Initial commit.

This commit is contained in:
Jonathan Naylor 2018-03-13 22:16:48 +00:00
commit e3abbaa85f
94 changed files with 9980 additions and 0 deletions

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
Debug
Release
x64
*.o
*.opendb
*.bak
*.obj
*~
*.sdf
*.log
*.zip
*.exe
*.user
*.VC.db
.vs

340
LICENCE Normal file
View File

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

51
NXDNClients.sln Normal file
View File

@ -0,0 +1,51 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2010
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NXDNParrot", "NXDNParrot\NXDNParrot.vcxproj", "{2AE94EAA-FD57-45C9-8555-6425CFA777A3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NXDNGateway", "NXDNGateway\NXDNGateway.vcxproj", "{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NXDNReflector", "NXDNReflector\NXDNReflector.vcxproj", "{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2AE94EAA-FD57-45C9-8555-6425CFA777A3}.Debug|x64.ActiveCfg = Debug|x64
{2AE94EAA-FD57-45C9-8555-6425CFA777A3}.Debug|x64.Build.0 = Debug|x64
{2AE94EAA-FD57-45C9-8555-6425CFA777A3}.Debug|x86.ActiveCfg = Debug|Win32
{2AE94EAA-FD57-45C9-8555-6425CFA777A3}.Debug|x86.Build.0 = Debug|Win32
{2AE94EAA-FD57-45C9-8555-6425CFA777A3}.Release|x64.ActiveCfg = Release|x64
{2AE94EAA-FD57-45C9-8555-6425CFA777A3}.Release|x64.Build.0 = Release|x64
{2AE94EAA-FD57-45C9-8555-6425CFA777A3}.Release|x86.ActiveCfg = Release|Win32
{2AE94EAA-FD57-45C9-8555-6425CFA777A3}.Release|x86.Build.0 = Release|Win32
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Debug|x64.ActiveCfg = Debug|x64
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Debug|x64.Build.0 = Debug|x64
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Debug|x86.ActiveCfg = Debug|Win32
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Debug|x86.Build.0 = Debug|Win32
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Release|x64.ActiveCfg = Release|x64
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Release|x64.Build.0 = Release|x64
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Release|x86.ActiveCfg = Release|Win32
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Release|x86.Build.0 = Release|Win32
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Debug|x64.ActiveCfg = Debug|x64
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Debug|x64.Build.0 = Debug|x64
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Debug|x86.ActiveCfg = Debug|Win32
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Debug|x86.Build.0 = Debug|Win32
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Release|x64.ActiveCfg = Release|x64
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Release|x64.Build.0 = Release|x64
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Release|x86.ActiveCfg = Release|Win32
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {02935C01-6975-4CA6-81D3-505FFB8A432C}
EndGlobalSection
EndGlobal

282
NXDNGateway/Conf.cpp Normal file
View File

@ -0,0 +1,282 @@
/*
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Conf.h"
#include "Log.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
const int BUFFER_SIZE = 500;
enum SECTION {
SECTION_NONE,
SECTION_GENERAL,
SECTION_ID_LOOKUP,
SECTION_VOICE,
SECTION_LOG,
SECTION_NETWORK
};
CConf::CConf(const std::string& file) :
m_file(file),
m_callsign(),
m_rptAddress(),
m_rptPort(0U),
m_myAddress(),
m_myPort(0U),
m_announcements(true),
m_daemon(false),
m_lookupName(),
m_lookupTime(0U),
m_voiceEnabled(true),
m_voiceLanguage("en_GB"),
m_voiceDirectory(),
m_logFilePath(),
m_logFileRoot(),
m_networkPort(0U),
m_networkHosts1(),
m_networkHosts2(),
m_networkReloadTime(0U),
m_networkParrotAddress("127.0.0.1"),
m_networkParrotPort(0U),
m_networkStartup(9999U),
m_networkInactivityTimeout(0U),
m_networkDebug(false)
{
}
CConf::~CConf()
{
}
bool CConf::read()
{
FILE* fp = ::fopen(m_file.c_str(), "rt");
if (fp == NULL) {
::fprintf(stderr, "Couldn't open the .ini file - %s\n", m_file.c_str());
return false;
}
SECTION section = SECTION_NONE;
char buffer[BUFFER_SIZE];
while (::fgets(buffer, BUFFER_SIZE, fp) != NULL) {
if (buffer[0U] == '#')
continue;
if (buffer[0U] == '[') {
if (::strncmp(buffer, "[General]", 9U) == 0)
section = SECTION_GENERAL;
else if (::strncmp(buffer, "[Id Lookup]", 11U) == 0)
section = SECTION_ID_LOOKUP;
else if (::strncmp(buffer, "[Voice]", 7U) == 0)
section = SECTION_VOICE;
else if (::strncmp(buffer, "[Log]", 5U) == 0)
section = SECTION_LOG;
else if (::strncmp(buffer, "[Network]", 9U) == 0)
section = SECTION_NETWORK;
else
section = SECTION_NONE;
continue;
}
char* key = ::strtok(buffer, " \t=\r\n");
if (key == NULL)
continue;
char* value = ::strtok(NULL, "\r\n");
if (section == SECTION_GENERAL) {
if (::strcmp(key, "Callsign") == 0) {
// Convert the callsign to upper case
for (unsigned int i = 0U; value[i] != 0; i++)
value[i] = ::toupper(value[i]);
m_callsign = value;
} else if (::strcmp(key, "RptAddress") == 0)
m_rptAddress = value;
else if (::strcmp(key, "RptPort") == 0)
m_rptPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "LocalAddress") == 0)
m_myAddress = value;
else if (::strcmp(key, "LocalPort") == 0)
m_myPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "Announcements") == 0)
m_announcements = ::atoi(value) == 1;
else if (::strcmp(key, "Daemon") == 0)
m_daemon = ::atoi(value) == 1;
} else if (section == SECTION_ID_LOOKUP) {
if (::strcmp(key, "Name") == 0)
m_lookupName = value;
else if (::strcmp(key, "Time") == 0)
m_lookupTime = (unsigned int)::atoi(value);
} else if (section == SECTION_VOICE) {
if (::strcmp(key, "Enabled") == 0)
m_voiceEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Language") == 0)
m_voiceLanguage = value;
else if (::strcmp(key, "Directory") == 0)
m_voiceDirectory = value;
} else if (section == SECTION_LOG) {
if (::strcmp(key, "FilePath") == 0)
m_logFilePath = value;
else if (::strcmp(key, "FileRoot") == 0)
m_logFileRoot = value;
} else if (section == SECTION_NETWORK) {
if (::strcmp(key, "Port") == 0)
m_networkPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "HostsFile1") == 0)
m_networkHosts1 = value;
else if (::strcmp(key, "HostsFile2") == 0)
m_networkHosts2 = value;
else if (::strcmp(key, "ReloadTime") == 0)
m_networkReloadTime = (unsigned int)::atoi(value);
else if (::strcmp(key, "ParrotAddress") == 0)
m_networkParrotAddress = value;
else if (::strcmp(key, "ParrotPort") == 0)
m_networkParrotPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "Startup") == 0)
m_networkStartup = (unsigned int)::atoi(value);
else if (::strcmp(key, "InactivityTimeout") == 0)
m_networkInactivityTimeout = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_networkDebug = ::atoi(value) == 1;
}
}
::fclose(fp);
return true;
}
std::string CConf::getCallsign() const
{
return m_callsign;
}
std::string CConf::getRptAddress() const
{
return m_rptAddress;
}
unsigned int CConf::getRptPort() const
{
return m_rptPort;
}
std::string CConf::getMyAddress() const
{
return m_myAddress;
}
unsigned int CConf::getMyPort() const
{
return m_myPort;
}
bool CConf::getAnnouncements() const
{
return m_announcements;
}
bool CConf::getDaemon() const
{
return m_daemon;
}
std::string CConf::getLookupName() const
{
return m_lookupName;
}
unsigned int CConf::getLookupTime() const
{
return m_lookupTime;
}
bool CConf::getVoiceEnabled() const
{
return m_voiceEnabled;
}
std::string CConf::getVoiceLanguage() const
{
return m_voiceLanguage;
}
std::string CConf::getVoiceDirectory() const
{
return m_voiceDirectory;
}
std::string CConf::getLogFilePath() const
{
return m_logFilePath;
}
std::string CConf::getLogFileRoot() const
{
return m_logFileRoot;
}
unsigned int CConf::getNetworkPort() const
{
return m_networkPort;
}
std::string CConf::getNetworkHosts1() const
{
return m_networkHosts1;
}
std::string CConf::getNetworkHosts2() const
{
return m_networkHosts2;
}
unsigned int CConf::getNetworkReloadTime() const
{
return m_networkReloadTime;
}
std::string CConf::getNetworkParrotAddress() const
{
return m_networkParrotAddress;
}
unsigned int CConf::getNetworkParrotPort() const
{
return m_networkParrotPort;
}
unsigned int CConf::getNetworkStartup() const
{
return m_networkStartup;
}
unsigned int CConf::getNetworkInactivityTimeout() const
{
return m_networkInactivityTimeout;
}
bool CConf::getNetworkDebug() const
{
return m_networkDebug;
}

97
NXDNGateway/Conf.h Normal file
View File

@ -0,0 +1,97 @@
/*
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(CONF_H)
#define CONF_H
#include <string>
#include <vector>
class CConf
{
public:
CConf(const std::string& file);
~CConf();
bool read();
// The General section
std::string getCallsign() const;
std::string getRptAddress() const;
unsigned int getRptPort() const;
std::string getMyAddress() const;
unsigned int getMyPort() const;
bool getAnnouncements() const;
bool getDaemon() const;
// The Id Lookup section
std::string getLookupName() const;
unsigned int getLookupTime() const;
// The Voice section
bool getVoiceEnabled() const;
std::string getVoiceLanguage() const;
std::string getVoiceDirectory() const;
// The Log section
std::string getLogFilePath() const;
std::string getLogFileRoot() const;
// The Network section
unsigned int getNetworkPort() const;
std::string getNetworkHosts1() const;
std::string getNetworkHosts2() const;
unsigned int getNetworkReloadTime() const;
std::string getNetworkParrotAddress() const;
unsigned int getNetworkParrotPort() const;
unsigned int getNetworkStartup() const;
unsigned int getNetworkInactivityTimeout() const;
bool getNetworkDebug() const;
private:
std::string m_file;
std::string m_callsign;
std::string m_rptAddress;
unsigned int m_rptPort;
std::string m_myAddress;
unsigned int m_myPort;
bool m_announcements;
bool m_daemon;
std::string m_lookupName;
unsigned int m_lookupTime;
bool m_voiceEnabled;
std::string m_voiceLanguage;
std::string m_voiceDirectory;
std::string m_logFilePath;
std::string m_logFileRoot;
unsigned int m_networkPort;
std::string m_networkHosts1;
std::string m_networkHosts2;
unsigned int m_networkReloadTime;
std::string m_networkParrotAddress;
unsigned int m_networkParrotPort;
unsigned int m_networkStartup;
unsigned int m_networkInactivityTimeout;
bool m_networkDebug;
};
#endif

140
NXDNGateway/IcomNetwork.cpp Normal file
View File

@ -0,0 +1,140 @@
/*
* Copyright (C) 2009-2014,2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "IcomNetwork.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
const unsigned int BUFFER_LENGTH = 200U;
CIcomNetwork::CIcomNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug) :
m_socket(localAddress, localPort),
m_address(),
m_port(gatewayPort),
m_debug(debug),
m_buffer(1000U, "Icom")
{
assert(gatewayPort > 0U);
assert(!gatewayAddress.empty());
m_address = CUDPSocket::lookup(gatewayAddress);
}
CIcomNetwork::~CIcomNetwork()
{
}
bool CIcomNetwork::open()
{
LogMessage("Opening Icom connection");
if (m_address.s_addr == INADDR_NONE)
return false;
return m_socket.open();
}
bool CIcomNetwork::write(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
unsigned char buffer[110U];
::memset(buffer, 0x00U, 110U);
buffer[0U] = 'I';
buffer[1U] = 'C';
buffer[2U] = 'O';
buffer[3U] = 'M';
buffer[4U] = 0x01U;
buffer[5U] = 0x01U;
buffer[6U] = 0x08U;
buffer[7U] = 0xE0U;
buffer[37U] = 0x23U;
buffer[38U] = (data[0U] == 0x81U || data[0U] == 0x83U) ? 0x1CU : 0x10U;
buffer[39U] = 0x21U;
::memcpy(buffer + 40U, data, length);
if (m_debug)
CUtils::dump(1U, "Icom Data Sent", buffer, 102U);
return m_socket.write(buffer, 102U, m_address, m_port);
}
void CIcomNetwork::clock(unsigned int ms)
{
unsigned char buffer[BUFFER_LENGTH];
in_addr address;
unsigned int port;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port);
if (length <= 0)
return;
// Check if the data is for us
if (m_address.s_addr != address.s_addr || port != m_port) {
LogMessage("Icom packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, m_port, port);
return;
}
// Invalid packet type?
if (::memcmp(buffer, "ICOM", 4U) != 0)
return;
// An Icom repeater connect request
if (buffer[4U] == 0x01U && buffer[5U] == 0x61U) {
buffer[5U] = 0x62U;
buffer[37U] = 0x02U;
buffer[38U] = 0x4FU;
buffer[39U] = 0x4BU;
m_socket.write(buffer, length, m_address, m_port);
return;
}
if (length != 102)
return;
if (m_debug)
CUtils::dump(1U, "Icom Data Received", buffer, length);
m_buffer.addData(buffer + 40U, 33U);
}
bool CIcomNetwork::read(unsigned char* data)
{
assert(data != NULL);
if (m_buffer.isEmpty())
return false;
m_buffer.getData(data, 33U);
return true;
}
void CIcomNetwork::close()
{
m_socket.close();
LogMessage("Closing Icom connection");
}

52
NXDNGateway/IcomNetwork.h Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2009-2014,2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef IcomNetwork_H
#define IcomNetwork_H
#include "RingBuffer.h"
#include "UDPSocket.h"
#include "Timer.h"
#include <cstdint>
#include <string>
class CIcomNetwork {
public:
CIcomNetwork(const std::string& localAddress, unsigned int localPort, const std::string& gatewayAddress, unsigned int gatewayPort, bool debug);
~CIcomNetwork();
bool open();
bool write(const unsigned char* data, unsigned int length);
bool read(unsigned char* data);
void close();
void clock(unsigned int ms);
private:
CUDPSocket m_socket;
in_addr m_address;
unsigned int m_port;
bool m_debug;
CRingBuffer<unsigned char> m_buffer;
};
#endif

136
NXDNGateway/Log.cpp Normal file
View File

@ -0,0 +1,136 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Log.h"
#if defined(_WIN32) || defined(_WIN64)
#include <Windows.h>
#else
#include <sys/time.h>
#endif
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <ctime>
#include <cassert>
#include <cstring>
static unsigned int m_fileLevel = 2U;
static std::string m_filePath;
static std::string m_fileRoot;
static FILE* m_fpLog = NULL;
static unsigned int m_displayLevel = 2U;
static struct tm m_tm;
static char LEVELS[] = " DMIWEF";
static bool LogOpen()
{
if (m_fileLevel == 0U)
return true;
time_t now;
::time(&now);
struct tm* tm = ::gmtime(&now);
if (tm->tm_mday == m_tm.tm_mday && tm->tm_mon == m_tm.tm_mon && tm->tm_year == m_tm.tm_year) {
if (m_fpLog != NULL)
return true;
} else {
if (m_fpLog != NULL)
::fclose(m_fpLog);
}
char filename[100U];
#if defined(_WIN32) || defined(_WIN64)
::sprintf(filename, "%s\\%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
#else
::sprintf(filename, "%s/%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
#endif
m_fpLog = ::fopen(filename, "a+t");
m_tm = *tm;
return m_fpLog != NULL;
}
bool LogInitialise(const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel)
{
m_filePath = filePath;
m_fileRoot = fileRoot;
m_fileLevel = fileLevel;
m_displayLevel = displayLevel;
return ::LogOpen();
}
void LogFinalise()
{
if (m_fpLog != NULL)
::fclose(m_fpLog);
}
void Log(unsigned int level, const char* fmt, ...)
{
assert(fmt != NULL);
char buffer[300U];
#if defined(_WIN32) || defined(_WIN64)
SYSTEMTIME st;
::GetSystemTime(&st);
::sprintf(buffer, "%c: %04u-%02u-%02u %02u:%02u:%02u.%03u ", LEVELS[level], st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
#else
struct timeval now;
::gettimeofday(&now, NULL);
struct tm* tm = ::gmtime(&now.tv_sec);
::sprintf(buffer, "%c: %04d-%02d-%02d %02d:%02d:%02d.%03lu ", LEVELS[level], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000U);
#endif
va_list vl;
va_start(vl, fmt);
::vsprintf(buffer + ::strlen(buffer), fmt, vl);
va_end(vl);
if (level >= m_fileLevel && m_fileLevel != 0U) {
bool ret = ::LogOpen();
if (!ret)
return;
::fprintf(m_fpLog, "%s\n", buffer);
::fflush(m_fpLog);
}
if (level >= m_displayLevel && m_displayLevel != 0U) {
::fprintf(stdout, "%s\n", buffer);
::fflush(stdout);
}
if (level == 6U) { // Fatal
::fclose(m_fpLog);
exit(1);
}
}

36
NXDNGateway/Log.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(LOG_H)
#define LOG_H
#include <string>
#define LogDebug(fmt, ...) Log(1U, fmt, ##__VA_ARGS__)
#define LogMessage(fmt, ...) Log(2U, fmt, ##__VA_ARGS__)
#define LogInfo(fmt, ...) Log(3U, fmt, ##__VA_ARGS__)
#define LogWarning(fmt, ...) Log(4U, fmt, ##__VA_ARGS__)
#define LogError(fmt, ...) Log(5U, fmt, ##__VA_ARGS__)
#define LogFatal(fmt, ...) Log(6U, fmt, ##__VA_ARGS__)
extern void Log(unsigned int level, const char* fmt, ...);
extern bool LogInitialise(const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel);
extern void LogFinalise();
#endif

19
NXDNGateway/Makefile Normal file
View File

@ -0,0 +1,19 @@
CC = gcc
CXX = g++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread
LIBS = -lpthread
LDFLAGS = -g
OBJECTS = Conf.o IcomNetwork.o Log.o Mutex.o NXDNCRC.o NXDNGateway.o NXDNLookup.o NXDNNetwork.o Reflectors.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o Voice.o
all: NXDNGateway
NXDNGateway: $(OBJECTS)
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o NXDNGateway
%.o: %.cpp
$(CXX) $(CFLAGS) -c -o $@ $<
clean:
$(RM) NXDNGateway *.o *.d *.bak *~

65
NXDNGateway/Mutex.cpp Normal file
View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Mutex.h"
#if defined(_WIN32) || defined(_WIN64)
CMutex::CMutex() :
m_handle()
{
m_handle = ::CreateMutex(NULL, FALSE, NULL);
}
CMutex::~CMutex()
{
::CloseHandle(m_handle);
}
void CMutex::lock()
{
::WaitForSingleObject(m_handle, INFINITE);
}
void CMutex::unlock()
{
::ReleaseMutex(m_handle);
}
#else
CMutex::CMutex() :
m_mutex(PTHREAD_MUTEX_INITIALIZER)
{
}
CMutex::~CMutex()
{
}
void CMutex::lock()
{
::pthread_mutex_lock(&m_mutex);
}
void CMutex::unlock()
{
::pthread_mutex_unlock(&m_mutex);
}
#endif

45
NXDNGateway/Mutex.h Normal file
View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(MUTEX_H)
#define MUTEX_H
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <pthread.h>
#endif
class CMutex
{
public:
CMutex();
~CMutex();
void lock();
void unlock();
private:
#if defined(_WIN32) || defined(_WIN64)
HANDLE m_handle;
#else
pthread_mutex_t m_mutex;
#endif
};
#endif

405
NXDNGateway/NXDN.csv Normal file
View File

@ -0,0 +1,405 @@
UID,Call,Name,Location,Notes
2,W2FLY/M,Harry,Southern NJ,UHF NX-800 mobile
3,WB2OOM/M,Tina,Southern NJ,UHF NX-800 Mobile
4,W2FLY/M,Harry,Southern NJ,UHF NX-800 Van
7,F1PRY,Emmanuel,BEAUVAIS FR,
8,W2FLY/P,Harry,Southern NJ,UHF NX-820 Port 2
9,KE8BGA,Lowell Katz,"Cleveland, Ohio","on the north shore, NX-800"
17,KC2SNI,Jim Hannon,"West Berlin, New Jersey",My Radio is an Icom IC-3161DT
25,WB2RUH/P,Bruce,Southern NJ,UHF NX-320
26,WB2RUH/M,Bruce,Southern NJ,UHF NX-800 mobile
30,KD4MOJ,Doug,,Doug
74,N2IXC,Ed,Chatsworth NJ,
76,W2FLY/P,Harry,Southern NJ,UFH NX5300 Port 1
77,W2FLY/P,Harry,"Somers Point, NJ",UHF NX-800 Shore Base
78,W2FLY,Harry,"Mullica Hill, NJ",UHF NX-800
79,W2FLY/M,Harry,Southern NJ,UHF NX-5800
80,W2FLY/M,Harry,Southern NJ,VHF NX-5700 mobile
82,W2FLY/P,Harry,"Somers Point, NJ",VHF NX-700 Shore Base
85,W2FLY/M,Harry,Southern NJ,VHF NX_700 van
86,W2FLY,Harry,"Mullica Hill, NJ",VHF NX-700 base
87,W2FLY/M,Harry,Southern NJ,VHF NX-700 mobile
88,W2FLY/P,Harry,Southern NJ,VHF NX-220 portable
89,WB2RUH,Bruce,Vineland NJ,VHF NX-700 base
99,K1ZSG,Don,,Mobile
134,N2SRO,Mike,Pitman,Mobile Radio
134,N2SRO,Mike,NJ,
141,KF2M,Greg Popovich,"Mt Laurel, NJ",IC-F4161DT
401,W1KFR,Bill,,Bill
901,K1IFF,Cliff,CT,Cliff NX320
902,K1IFF,Cliff,CT,Cliff NX320 - demo
903,K1IFF,Cliff,CT,Cliff NX800H
905,WA1LMV,Rick,,Rick NX320
906,K1IFF,Cliff,CT,Cliff NX200
907,K1IFF,Cliff,CT,Future
908,W4CLL,Chuck,,CHUCK
909,AB1UB V,Woody,"Bristol, CT",
909,AB1UB,Woody,"Bristol, CT",
909,AB1UB,Woody,,Woody NX300
909,W4CCL,Chuck,,CHUCK
910,W4CLL,Chuck,,CHUCK
911,W4CLL,Chuck,,CHUCK
912,W4CCL,Chuck,,CHUCK
920,N1XDN,Bob,CT,Bob P1 UHF NX300
921,N1XDN,Bob,CT,Bob P1 VHF NX220
922,N1XDN,Bob,CT,Bob P2 UHF NX300
923,N1XDN,Bob,CT,Bob M1 VHF NX700
924,N1XDN,Bob,CT,Bob P3 UHF NX-5300
925,N1XDN,Bob,CT,Bob P2 VHF NX-5200
926,N1XDN,Bob,CT,Bob M1 UHF NX-5800
928,N1XDN,Bob,CT,Icom portable
930,K1IFF,Cliff,CT,NX300
931,K1IFF,Cliff,CT,NX300
936,W1GPO,John,,NX300
951,K1KGQ,Joel,,Joel NX800H
952,K1KGQ,Joel,CT,Truck radio
952,K1GML,Gail,,Gail NX800H
953,K1KGQ,Joel,,Joel NX320-1
954,K1KGQ,Joel,,
955,K1KGQ,Joel,,
956,K1KGQ,Joel,,
957,K1KGQ,Joel,,
958,K1KGQ,Joel,,Joel F4161
959,K1KGQ,Joel,,Future
960,K1ZXX,Gary,,Gary - Icom All radios
961,WA1SSB,Joe,,Joe NX800H
962,N1MAT,Dennis,,Dennis F4161
963,N1MAT,Dennis,,Dennis F4161
970,KB1VRI,Nick,CT,
970,KB1VRI,Nick,,Nick
971,N1ELE,Paul,CT,
972,N1ODJ,Kenny Schmitz,Middletown,
973,W1VLF,Paul,CT,
980,W1RHS,Rick,Connecticut,
995,K1IFF/Base,Cliff,"Brsitol, CT",NXR710 link radio
1001,KE4GWW,James,AL,NX200 Portable #1
1002,KE4GWW,James,AL,NX200 Portable #2
1003,KE4GWW,James,AL,NX300 Portable #1
1004,KE4GWW,James,AL,NX300 Portable #2
1005,KE4GWW,James,AL,NX700 Base
1006,KE4GWW,James,AL,NX800 Base
1007,KE4GWW,James M. Nelson,"Dothan, AL",NX700 Mobile#1
1008,DK6PX,Stefan,Germany nr Bad Toelz,Coming up FR6000
1008,KE4GWW,James,AL,NX700 Mobile#2
1009,KE4GWW,James,AL,NX800 Mobile#1
1010,KE4GWW,James,AL,NX800 Mobile#2
1066,KM4JXP,Peter Tasker,Longboat Key,NX5300
1954,W4BPT,BILLY TAYLOR,"RINGGOLD,GA.",
1956,KC7SDD,Dana Hanford,"Bainbridge Island, WA","Member BARC, W7NPC.org"
1963,N5JRN,David Barts,"Bainbridge Island, WA","Handheld, Icom 4161"
1966,ZS6IIX,Henry,Petit South Africa,
1997,KC1AJR,Giovanni,East Hampton CT,kenwood NX800 K2
3070,W4ORL,Ralph,,Ralph - Mobile
3071,W4LOV,Mike,,Mike - NX800
3072,N4JTK,John,,John - NX800
3074,W4MCA,Michael,,Michael - NX300
3075,W4LOV,Mike,,Mike - NX800
3079,NN4TT,Dave,Orlando,NX300
3079,W4ORL,Ralph,,Ralph - Portable
3081,W4MCA,Michael,,Michael - NX800
3082,W4LOV,Mike,,Mike - Portable
3083,KD4TWJ,Dean,,Dean - Mobile NX800
3271,N4KEG,Richard,,RICHARD - Mobile and or ht's N4KEG (UHF)
3274,KD4EFM,Evans,FL,
3275,KD4EFM,Evans,FL,
3278,KD4EFM,Evans,FL,
3279,N4KEG,Richard,,
3280,KD4EFM,Evans,"Lakeland, Florida",work radio
3280,KD4EFM,Evans,FL,Evans Mobile(s)
3280,KD4EFM,Evans,FL,
3281,N4KEG,Richard,,
3450,K0KAD,CHAD TAYLOR,"SPOKANE VALLEY, WA",My Portable
3451,K0KAD,CHAD TAYLOR,"SPOKANE VALLEY, WA",My Base Station
3452,K0KAD,CHAD TAYLOR,"SPOKANE VALLEY, WA",Mobile Radio
4020,K4XXX,Ed,"London, KY",NX820 Base
4802,hb3yrb,Alex,Verbier,nx5300
4804,hb9fmf,Didier,Rougemont,NX5300
5001,N5QZ,Ryan,AR,"N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-820"
5002,N5QZ,Ryan,AR,"N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-720"
5003,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-820"
5004,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-720"
5005,AC5AV,Larry,AR,"AC5AV, Larry Sicks, Searcy, AR"
5006,AC5AV,Larry,AR,"AC5AV, Larry Sicks, Searcy, AR"
5007,N5LKE,James,AR,"N5LKE, James Ferguson, Searcy, AR - Kenwood NX-800"
5008,AF5WN,Mason,AR,"AF5WN, Mason Creager, Cabot, AR - Kenwood NX-700H"
5009,KJ5SF,Stan,AR,"KJ5SF, Stan Rongey, Searcy, AR - Kenwood NX-800"
5100,K5SRS,Michael Smith,"Fayetteville, AR",NX-5800 Mobile
5101,KC5YQB,Paul Blair,"Fayetteville, AR",
5125,AE5OQ,Armstead,"Higden, AR",
5125,AE5OQ,Armstead,AR,entered by k1iff
5134,AE5OQ,Armstead,AR,"AE5OQ, Armstead M Feland, IV, Higdon, AR - Kenwood NX-200"
5150,WY6NN,Doug,"Los Angeles, CA",NX-300/5300
5151,KC6HFJ,Tamara,"Los Angeles, CA",NX-300
5170,K5WMZ,Gary,AR,"K5WMZ, Gary D Partlow, Ward, AR - Kenwood NX-700"
5599,W1ZM,Ryan,,"W1ZM, Ryan Nelson, NX-5300"
5987,W5ZN,Joel,AR,"W5ZN, Joel Harrison, Judsonia, AR - Kenwood NX-800"
6430,K4GFD,Norm,FL,Norm Greensboro Fla
6431,K4GFD,Norm,,
6432,K4GFD,Norm,,
6439,N4NKV,George,,George
6801,hb9vsd,relais de verbier,verbier,
6802,HB9YRB,Alex,Verbier,
6804,HB9FMF,Didier,Rougemont,
7737,N4NKV,George,,George
9834,VA7NY,PJ,,PJ
12002,W4KJP,Kevin,,KEVIN
12005,KD4TWJ,Dean,,Dean - Portable IC-F4161
12006,W4MO,Stewart,,STEWART NX300 / 320
12007,W4MO,Stewart,,STEWART NX800
12010,kd4dwp,Ben,Orlando,
12013,K4NBC,Miguel Orama,"Palm Bay, Florida",Icom F4146DS UHF Portable
12014,K4NBC,Miguel Orama,"Palm Bay, Florida",Kenwood NX200 VHF HT
12015,K4NBC,K4NBC-Miguel UHF Mobile,"Palm Bay, Florida",Future UHF Mobile
12016,K4NBC,Miguel,"Palm Bay, Florida",M2 Icom F6061D
12017,N4JFZ,,,
12021,W4PJT,Paul,,Paul
12023,KD4NWL,John,,JOHN
12127,W4KDM,Rick,,Rick - Portable NX300
12136,WA4KWK,John,,John F6121
12200,NB9X,Paul,FL,
12201,NB9X,Paul,FL,PAUL
12202,NB9X,Paul,FL,
12203,NB9X,Paul,FL,
12204,WX3C,Juan Arias,Florida,Orlando metro
12204,NB9X,Paul,FL,
12210,N4APG,Bill,,Bill Pfost
12211,N4APG,Bill,,Bill Pfost
12212,N4APG,Bill,,Bill Pfost
12213,N4APG,Bill,,Bill Pfost
12214,N4APG,Bill,,Bill Pfost
12215,WA4ISB,Ed,,ED Mobile
12216,WA4ISB,Ed,,
12220,N4PK,Paul,,PAUK K.
12221,N4PK,Paul,,
12222,W4PJT,Paul,,
12223,W4PJT,Paul,,
12226,KI4SWY,William,,
12230,KQ4KX,Richard,,Richard Sharp
12231,KQ4KX,Richard,,
12234,KD4TWJ,Dean,EL98,
12235,N1IC,Nick,,Nic
12236,N1IC,Nick,,
12240,KR4X,Larry,,
12241,KR4X,Larry,,
12245,KD4ACG,Jason,"Hudson, FL",Icom Mobile
12245,KD4ACG,Jason,,JASON
12246,KD4ACG,Jason,"Hudson, FL",Icom Portable
12246,KD4ACG,Jason,,JASON
12247,K2MCI,,,
12250,KE4GYX,,,
12272,KE4OSL,,,
12273,KE4OSL,,,
12374,KF4I,Thom,,Thom Base
12375,KF4I,Thom,,Thom Mobile
12523,KM4JVE,Ana,,Ana - IC-F4161
12577,N2DLX,Richard,,Rich Dunajewski NX-5800
12604,K4CBN,Greg,,GREG
12605,K4CBN,Greg,,
12606,K4CBN,Greg,,
12607,K4CBN,Greg,,
12608,K4CBN,Greg,,
12666,KI4SWY,William,,William Stillwel ( All Radios )
12691,KE3WDW,Sam,,Sam
12780,KC4YUA,Brett,,BRETT
13105,W7QO,Alan,,
13106,W7QO,Alan,,
13107,W7QO,Alan,,
13121,W4CML,Chuck,,
13122,W4CML,Chuck,,
13125,KD4APP,Don,,Don - NX300
13126,KD4APP,Don,,Don - F6061D
13127,KD4APP,Don,,Don - NX200
13131,W5JR,Mike,,
13132,W5JR,Mike,,
13401,W1KFR,Bill,,Bill
13815,KG4BKO,Bill,GA,nx320
14020,K4XXX,Ed,"London, KY",NX5300
14021,K4XXX,Ed,"London, KY",NX5200
15001,N5QZ,Ryan,AR,"N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-800H (Vehicle 1)"
15002,N5QZ,Ryan,AR,"N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-700 (Vehicle 1)"
15003,N5QZ,Ryan,AR,"N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-800 (Vehicle 2)"
15004,N5QZ,Ryan,AR,"N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-700 (Vehicle 2)"
15005,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-800 (Vehicle 1)"
15006,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-700 (Vehicle 1)"
15007,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-800 (Vehicle 2)"
15008,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-700 (Vehicle 2)"
15009,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-800 (Vehicle 3)"
15010,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-700 (Vehicle 3)"
15011,N5QT,Dawn,AR,"N5QT, Dawn Gray, Searcy, AR - Kenwood NX-800"
15012,AC5AV,Larry,AR,"AC5AV, Larry Sicks, Searcy, AR - Kenwood NX-800"
15013,AC5AV,Larry,AR,"AC5AV, Larry Sicks, Searcy, AR - Kenwood NX-700"
15014,N5QT,Dawn,AR,"N5QT, Dawn Gray, Searcy, AR - Kenwood NX-700"
15015,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR Motorcycle Mobile"
15016,KG5KS,Kenny,,"KG5KS, Kenny Thompson - Kenwood NX-700HK"
15017,KG5KS,Kenny,,"KG5KS, Kenny Thompson - Kenwood NX-800HK"
15018,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR ATV Mobile"
15019,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR ATV Mobile"
15020,WA8UBL,Allen,AR,"WA8UBL, Allen Herrick, Beebe, AR, Kenwood NX-700"
15021,KD5HRT,Heath,AR,"KD5HRT, Heath Taylor, McRae, AR, Kenwood NX-800"
15022,WA8UBL,Allen,AR,"WA8UBL, Allen Herrick, Beebe, AR - Kenwood NX-800"
15023,N5ZA,Joel,AR,"N5ZA, Joe Belew, Beebe, AR - Kenwood NX-700"
15024,KF5TPF,Ryan,AR,"KF5TPF, Ryan Nelson, Edgemont, AR NX-700"
15025,KE5YZP,Ryan,AR,"KE5YZP, Ryan Schwarck, Batesville, AR NX-700"
15026,AF5OD,Landon,AR,"AF5OD, Landon McCord, Searcy, AR"
15027,KB5RFF,Scott,AR,"KB5RFF, Scott Gray, Searcy, AR - Kenwood NX-800"
17002,KC9GMX,Stephen,,Stephen - Base F6121D
17004,KC9GMX,Stephen,,Stephen - F6061D
17005,KC9NPJ,Jarrett,,Jarrett F6121D
17006,KC9GMX,Stephen,,Stephen - F4161DS
17007,KC9NPJ,Jarrett,,Jarrett F4231DS
17008,KC9RHH,Jesse,,F4101D
17009,KC9PHK,Michael,,F4061DS
17011,N9BRG,Dan,,Dan kenwood nx800k2
17855,AG6RN,Demian,CA,NX-210
21007,WA1LMV,Rick,,Rick
21014,K2BUI,Eric,,Eric
24020,K4XXX,Ed,"London, KY",NX5800
24021,K4XXX,Ed,"London, KY",NX5700
25001,N5QZ,Ryan,AR,"N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-300"
25002,N5QZ,Ryan,AR,"N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-200"
25003,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-300"
25004,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-200"
25005,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-320"
25006,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-340U"
25007,N5QT,Dawn,AR,"N5QT, Dawn Gray, Searcy, AR - Kenwood NX-300"
25008,N5QT,Dawn,AR,"N5QT, Dawn Gray, Searcy, AR - Kenwood NX-200"
25009,AC5AV,Larry,AR,"AC5AV, Larry Sicks, Searcy, AR - Kenwood NX-300"
25010,KD5OOW,Tom,AR,"KD5OOW, Tom McGee, Searcy, AR - Kenwood NX-300"
25011,W5ZN,Joel,AR,"W5ZN, Joel Harrison, Judsonia, AR - Kenwood NX-300"
25012,KD5HRT,Heath,AR,"KD5HRT, Heath Taylor, McRae, AR - Kenwood NX-300"
25013,KK5WA,Darin,AR,"KK5WA, Darin Dykes, Beebe, AR - Kenwood NX-320"
25014,N5LKE,James,AR,"N5LKE, James Ferguson, Searcy, AR - Kenwood NX-5300"
25015,KJ5ORD,John,AR,"KJ5ORD, John Ord, Searcy, AR - Kenwood NX-300"
25016,KB5RFF,Scott,AR,"KB5RFF, Scott Gray, Searcy, AR - Kenwood NX-300"
25017,KB5ZUH,Todd,AR,"KB5ZUH, Todd Williams, Searcy, AR - Kenwood NX-320"
25018,KB5ZUH,Todd,AR,"KB5ZUH, Todd Williams, Searcy, AR - Kenwood NX-340"
25019,KB5ZUH,Todd,AR,"KB5ZUH, Todd Williams, Searcy, AR - Kenwood NX-340"
25020,KB5ZUH,Todd,AR,"KB5ZUH, Todd Williams, Searcy, AR - Kenwood NX-320"
25021,KE5UZU,Raymond Prince,"England, AR",Kenwood Handheld
25021,AF5OD,Landon,AR,"AF5OD, Landon McCord, Searcy, AR"
25022,KE5UZU,Raymond Prince,"England, AR",Icom Handheld
25022,KE5YZP,Ryan,AR,"KE5YZP, Ryan A Schwarck, Batesville, AR - Icom"
25023,KE5YZP,Ryan,AR,"KE5YZP, Ryan A Schwarck, Batesville, AR - Icom"
25024,KG5CHM,Colt,AR,"KG5CHM, Colt Boyd, Searcy, AR - Kenwood NX-300"
25025,KJ5ORD,John,AR,"KJ5ORD, John Ord, Searcy, AR - Kenwood NX-xxx VHF"
25026,WA8UBL,Allen,AR,"WA8UBL, Allen Herrick, Beebe, AR - Kenwood NX-320"
25027,KF5TPF,Ryan,AR,"KF5TPF, Ryan Nelson, Edgemont, AR - Kenwood NX-200"
25028,WA8UBL,Allen,AR,"WA8UBL, Allen Herrick, Beebe, AR - Kenwood NX-220"
25029,KF5WHX,Trey,AR,"KF5WHX, Trey Ferguson, Searcy, AR - Kenwood NX-320"
25030,AC5AV,Larry,AR,"AC5AV, Larry Sicks, Searcy, AR"
25031,KJ5SF,Stan,AR,"KJ5SF, Stan Rongey, Searcy, AR - Kenwood NX-340"
25032,KC5DFH,Kirk,AR,"KC5DFH, Kirk Williams, Searcy, AR - Kenwood NX-340"
25033,AF5OD,Landon,AR,"AF5OD, Landon McCord, Searcy, AR, Icom F4161DS"
25034,KF5TPF,Ryan,AR,"KF5TPF, Ryan Nelson, Edgemont, AR - ICOM 4161"
25035,KG5BMB,Glenda,AR,"KG5BMB, Glenda McCord, Searcy, AR, Icom F4161DS"
25039,KC1JET,Jim,,JIM (BASE)
25068,N1QD,Joe,,
25069,N1COP,Bob,,Bob
25070,WD1L,John,,John
25125,N1TI,Tim,"Mattapoisett, MA",
25125,N1TI,Tim,"Mattapoisett, MA",
25144,W1WCF,Walter,,Walter
25221,N0XIA,James,,James - Kenwood Mobile and Portable
25222,KE4SDC,Ron,,Ron - Portable NX300
25246,WG1U,Ken,"Assonet, MA",
25333,W1AKN,Jack,,Jack Mobile
25390,KC1JET,Jim,,JIM (MOBILE)
25390,KC1JET,Jim,,JIM
25444,W1TAV,Steve,,Steve
25555,WA1MNQ,Mike,,Mike
25582,N1KXJ,Ray,"E. Bridgewater, MA.",Port.
25582,N1KXJ,Ray Wall,East Bridgewater,
25585,N1AVA,Ken Howland,"DARTMOUTH,MA",
25700,NN1D,Tony Souza,"Swansea, MA",
25740,WG1U,Kenny,,KEN
25743,WG1U,Kenny,,KEN
25746,N1OTY,John,,JOHN
25777,W1BON,Bump,,Bump
25830,KB1CHU,Steve,MA,
25863,N1ZZN,Jeff,,JEFF
25874,KB1KVD,Jason,,Jason - Icom Mob & Port
25888,K1WGU,Bob,,Bob
25889,AB1CQ,Gary,,Gary
25900,N1ZZR,Matt,,Matt - mobile
25901,N1MRC,Matt,"Bridgewater, MA",N1MRC P-1
25901,N1ZZR,Matt,,Matt
25957,KC1HO,Steve,,STEVE
27101,KI4SWB,Mark,"Melbourne Beach, FL",Icom Portable
27102,KP4OO,Carlos,"Palm Bay, FL",Icom Portable
27201,KI4SWB,Mark,"Melbourne Beach, FL",Icom Mobile
27202,KP4OO,Carlos,"Palm Bay, FL",Icom Mobile
28001,K3KRS,rYAN,CLEVLAND,OHIO
30505,KG6MQE,Jim,MT,
30571,WX4RCF,Ryan F.,"Tampa, FL",
31117,K4QHR,Pete,,Pete
31124,KM4JXP,Peter,,NX5300
31146,KD2KWD,Michael Santamaria,"Brandon, FL",Kenwood
33000,N1PA-R,Paul,NH,PAUL - NEW HAMPSHIRE REPEATER
33001,N1PA,Paul,NH,PAUL - NEW HAMPSHIRE
33002,N1PA,Paul,NH,PAUL - NEW HAMPSHIRE
34001,N2WNS,Bill,NJ,N2WNS Portable
34002,N2WNS,Bill,NJ,N2WNS Base
36001,W2CCR,Chris,NY,"Chris, Galway, NY NX300"
36002,KC2VOB,Asad,NY,"Asad, NYC, NX-5800"
36003,KC2VOB,Asad,NY,"Asad, NYC, NX-300GK"
36134,N2SRO,Mike,"Pitman, NJ",Portable
37001,KA4YMY,Steve,NC,"Steve, Charlotte, NC NX320"
37009,KA4YMY,Steve,"Charlotte, NC",
37010,KA4YMY,Steve,"Charlotte, NC",
37010,KA4YMY,Steve,"Charlotte, NC",
40024,N5YEI,Jeff Dalrymple,"Jay, Oklahoma",NX-5800 Mobile
40124,N5YEI,Jeff Dalrymple,"Jay, Oklahoma",NX-5300 Portable
43751,N4IRS,Steve,,Steve
44001,K2BUI,Eric,RI,
44002,K2BUI,Eric,"Providence, RI",
44007,W2DAN,Dave,,Dave - NX700
44298,N1JBC,Jed,,JED
49101,WX7Y-1,Bret Mills,Castle Dale Utah,WX7y-1 Hand Held 1
49102,WX7Y-2,Bret Mills,"Caslte Dale, Utah",WX7Y-2 Hand held
49104,WX7Y-4,Bret Mills,"Castle Dale, Utah",WX7Y-4 Mobile
49106,WX7Y-6,Bret Mills,Castle Dale,WX7Y-6 Mobile
55700,WB9HKE,Rick,WI,
55704,WB9HKE,Rick,WI,
57000,VE3SP,Andre,"Toronto, ON",mobile
57001,VE3SP,Andre,"Toronto, ON",handheld
57001,VE3EI,Eric,,Eric - Portable
57002,VE3OKZ,Janusz,"Toronto, ON",mobile
57002,VE3EI,Eric,,Eric - Dongle
57003,VE3OKZ,Janusz,"Toronto, ON",handheld
57004,VE3CCD,Curtis,"Scarborough, ON",handheld
57005,VE3NBI,Anoop,"Scarborough, ON",handheld
57006,VE3JLU,Sherwin,"Scarborough, ON",handheld
57007,va3rq,Jon,"Oakville, ON",handheld
57008,ve3ogb,Randy,"Toronto, ON",handheld
57009,va3mk,Mark,"Oakville, ON",handheld
57010,va3mk,Mark,"Oakville, ON",mobile
57011,VA3WZW,Andre,"Durham, ON",mobile
57012,VA3WZW,Andre,"Durham, ON",mobile
57013,VA3AGV,cottage,"Toronto, ON",mobile
57014,VE3BWP,Brian,"Caledon, ON",handheld
57015,VE3HY,Frank,"Caledon, ON",handheld
57016,VE3UBI,Paul,"Scarborough, ON",mobile
57017,VE3UBI,Paul,"Scarborough, ON",handheld
57018,VE3RZR,Richard,"Toronto, ON",handheld
57019,VE3AEP,Dom,"Toronto, ON",mobile
57020,VA3PEO,Adrian,"Toronto, ON",handheld
57021,va3wjo,Walter,"Toronto, ON",handheld
57022,ve3fkn,Tom,"Stoney Creek, ON",handheld
57023,ve3ips,John,"Toronto, ON",handheld
57024,VA3CQA,Brian,"Scarborough, ON",handheld
57025,VA3PAD,Andrew,"Scarborough, ON",mobile
57026,VA3PAD,Andrew,"Scarborough, ON",handheld
57027,VA3VAD,Arpad,"Hamilton, ON",handheld
57028,VA3KY,Shelly,"Thornhill, ON",mobile
57029,VA3KY,Shelly,"Thornhill, ON",handheld
57030,VE3KFQ,Doug,"Toronto, ON",mobile
57031,VE3KFQ,Doug,"Toronto, ON",handheld
57032,VE3AEP,Dom 2,"Toronto, ON",handheld
57033,VE3DJZ,Huey,"Hamilton, ON",mobile
57034,VE3DJZ,Huey,"Hamilton, ON",handheld
57035,VA3RQ,Jon,Oakville ON,Mobile
3106418,N5ICK,Nicholas Nixon,"Rialto, Ca",
3112205,N2HUC,Phil Roberts,"Port St. Lucie, FL",DV4MINI AMBE voice
3118365,NA9VY,Chris Gilbert,"New Palestine, IN",
3118366,N9UMJ,Rick Nicholson,Buddha Indiana,
3142058,N3BAH,L. Abraham Smith,Southwestern Pennsylvania,
1 UID Call Name Location Notes
2 2 W2FLY/M Harry Southern NJ UHF NX-800 mobile
3 3 WB2OOM/M Tina Southern NJ UHF NX-800 Mobile
4 4 W2FLY/M Harry Southern NJ UHF NX-800 Van
5 7 F1PRY Emmanuel BEAUVAIS FR
6 8 W2FLY/P Harry Southern NJ UHF NX-820 Port 2
7 9 KE8BGA Lowell Katz Cleveland, Ohio on the north shore, NX-800
8 17 KC2SNI Jim Hannon West Berlin, New Jersey My Radio is an Icom IC-3161DT
9 25 WB2RUH/P Bruce Southern NJ UHF NX-320
10 26 WB2RUH/M Bruce Southern NJ UHF NX-800 mobile
11 30 KD4MOJ Doug Doug
12 74 N2IXC Ed Chatsworth NJ
13 76 W2FLY/P Harry Southern NJ UFH NX5300 Port 1
14 77 W2FLY/P Harry Somers Point, NJ UHF NX-800 Shore Base
15 78 W2FLY Harry Mullica Hill, NJ UHF NX-800
16 79 W2FLY/M Harry Southern NJ UHF NX-5800
17 80 W2FLY/M Harry Southern NJ VHF NX-5700 mobile
18 82 W2FLY/P Harry Somers Point, NJ VHF NX-700 Shore Base
19 85 W2FLY/M Harry Southern NJ VHF NX_700 van
20 86 W2FLY Harry Mullica Hill, NJ VHF NX-700 base
21 87 W2FLY/M Harry Southern NJ VHF NX-700 mobile
22 88 W2FLY/P Harry Southern NJ VHF NX-220 portable
23 89 WB2RUH Bruce Vineland NJ VHF NX-700 base
24 99 K1ZSG Don Mobile
25 134 N2SRO Mike Pitman Mobile Radio
26 134 N2SRO Mike NJ
27 141 KF2M Greg Popovich Mt Laurel, NJ IC-F4161DT
28 401 W1KFR Bill Bill
29 901 K1IFF Cliff CT Cliff NX320
30 902 K1IFF Cliff CT Cliff NX320 - demo
31 903 K1IFF Cliff CT Cliff NX800H
32 905 WA1LMV Rick Rick NX320
33 906 K1IFF Cliff CT Cliff NX200
34 907 K1IFF Cliff CT Future
35 908 W4CLL Chuck CHUCK
36 909 AB1UB V Woody Bristol, CT
37 909 AB1UB Woody Bristol, CT
38 909 AB1UB Woody Woody NX300
39 909 W4CCL Chuck CHUCK
40 910 W4CLL Chuck CHUCK
41 911 W4CLL Chuck CHUCK
42 912 W4CCL Chuck CHUCK
43 920 N1XDN Bob CT Bob P1 UHF NX300
44 921 N1XDN Bob CT Bob P1 VHF NX220
45 922 N1XDN Bob CT Bob P2 UHF NX300
46 923 N1XDN Bob CT Bob M1 VHF NX700
47 924 N1XDN Bob CT Bob P3 UHF NX-5300
48 925 N1XDN Bob CT Bob P2 VHF NX-5200
49 926 N1XDN Bob CT Bob M1 UHF NX-5800
50 928 N1XDN Bob CT Icom portable
51 930 K1IFF Cliff CT NX300
52 931 K1IFF Cliff CT NX300
53 936 W1GPO John NX300
54 951 K1KGQ Joel Joel NX800H
55 952 K1KGQ Joel CT Truck radio
56 952 K1GML Gail Gail NX800H
57 953 K1KGQ Joel Joel NX320-1
58 954 K1KGQ Joel
59 955 K1KGQ Joel
60 956 K1KGQ Joel
61 957 K1KGQ Joel
62 958 K1KGQ Joel Joel F4161
63 959 K1KGQ Joel Future
64 960 K1ZXX Gary Gary - Icom All radios
65 961 WA1SSB Joe Joe NX800H
66 962 N1MAT Dennis Dennis F4161
67 963 N1MAT Dennis Dennis F4161
68 970 KB1VRI Nick CT
69 970 KB1VRI Nick Nick
70 971 N1ELE Paul CT
71 972 N1ODJ Kenny Schmitz Middletown
72 973 W1VLF Paul CT
73 980 W1RHS Rick Connecticut
74 995 K1IFF/Base Cliff Brsitol, CT NXR710 link radio
75 1001 KE4GWW James AL NX200 Portable #1
76 1002 KE4GWW James AL NX200 Portable #2
77 1003 KE4GWW James AL NX300 Portable #1
78 1004 KE4GWW James AL NX300 Portable #2
79 1005 KE4GWW James AL NX700 Base
80 1006 KE4GWW James AL NX800 Base
81 1007 KE4GWW James M. Nelson Dothan, AL NX700 Mobile#1
82 1008 DK6PX Stefan Germany nr Bad Toelz Coming up FR6000
83 1008 KE4GWW James AL NX700 Mobile#2
84 1009 KE4GWW James AL NX800 Mobile#1
85 1010 KE4GWW James AL NX800 Mobile#2
86 1066 KM4JXP Peter Tasker Longboat Key NX5300
87 1954 W4BPT BILLY TAYLOR RINGGOLD,GA.
88 1956 KC7SDD Dana Hanford Bainbridge Island, WA Member BARC, W7NPC.org
89 1963 N5JRN David Barts Bainbridge Island, WA Handheld, Icom 4161
90 1966 ZS6IIX Henry Petit South Africa
91 1997 KC1AJR Giovanni East Hampton CT kenwood NX800 K2
92 3070 W4ORL Ralph Ralph - Mobile
93 3071 W4LOV Mike Mike - NX800
94 3072 N4JTK John John - NX800
95 3074 W4MCA Michael Michael - NX300
96 3075 W4LOV Mike Mike - NX800
97 3079 NN4TT Dave Orlando NX300
98 3079 W4ORL Ralph Ralph - Portable
99 3081 W4MCA Michael Michael - NX800
100 3082 W4LOV Mike Mike - Portable
101 3083 KD4TWJ Dean Dean - Mobile NX800
102 3271 N4KEG Richard RICHARD - Mobile and or ht's N4KEG (UHF)
103 3274 KD4EFM Evans FL
104 3275 KD4EFM Evans FL
105 3278 KD4EFM Evans FL
106 3279 N4KEG Richard
107 3280 KD4EFM Evans Lakeland, Florida work radio
108 3280 KD4EFM Evans FL Evans Mobile(s)
109 3280 KD4EFM Evans FL
110 3281 N4KEG Richard
111 3450 K0KAD CHAD TAYLOR SPOKANE VALLEY, WA My Portable
112 3451 K0KAD CHAD TAYLOR SPOKANE VALLEY, WA My Base Station
113 3452 K0KAD CHAD TAYLOR SPOKANE VALLEY, WA Mobile Radio
114 4020 K4XXX Ed London, KY NX820 Base
115 4802 hb3yrb Alex Verbier nx5300
116 4804 hb9fmf Didier Rougemont NX5300
117 5001 N5QZ Ryan AR N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-820
118 5002 N5QZ Ryan AR N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-720
119 5003 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-820
120 5004 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-720
121 5005 AC5AV Larry AR AC5AV, Larry Sicks, Searcy, AR
122 5006 AC5AV Larry AR AC5AV, Larry Sicks, Searcy, AR
123 5007 N5LKE James AR N5LKE, James Ferguson, Searcy, AR - Kenwood NX-800
124 5008 AF5WN Mason AR AF5WN, Mason Creager, Cabot, AR - Kenwood NX-700H
125 5009 KJ5SF Stan AR KJ5SF, Stan Rongey, Searcy, AR - Kenwood NX-800
126 5100 K5SRS Michael Smith Fayetteville, AR NX-5800 Mobile
127 5101 KC5YQB Paul Blair Fayetteville, AR
128 5125 AE5OQ Armstead Higden, AR
129 5125 AE5OQ Armstead AR entered by k1iff
130 5134 AE5OQ Armstead AR AE5OQ, Armstead M Feland, IV, Higdon, AR - Kenwood NX-200
131 5150 WY6NN Doug Los Angeles, CA NX-300/5300
132 5151 KC6HFJ Tamara Los Angeles, CA NX-300
133 5170 K5WMZ Gary AR K5WMZ, Gary D Partlow, Ward, AR - Kenwood NX-700
134 5599 W1ZM Ryan W1ZM, Ryan Nelson, NX-5300
135 5987 W5ZN Joel AR W5ZN, Joel Harrison, Judsonia, AR - Kenwood NX-800
136 6430 K4GFD Norm FL Norm Greensboro Fla
137 6431 K4GFD Norm
138 6432 K4GFD Norm
139 6439 N4NKV George George
140 6801 hb9vsd relais de verbier verbier
141 6802 HB9YRB Alex Verbier
142 6804 HB9FMF Didier Rougemont
143 7737 N4NKV George George
144 9834 VA7NY PJ PJ
145 12002 W4KJP Kevin KEVIN
146 12005 KD4TWJ Dean Dean - Portable IC-F4161
147 12006 W4MO Stewart STEWART NX300 / 320
148 12007 W4MO Stewart STEWART NX800
149 12010 kd4dwp Ben Orlando
150 12013 K4NBC Miguel Orama Palm Bay, Florida Icom F4146DS UHF Portable
151 12014 K4NBC Miguel Orama Palm Bay, Florida Kenwood NX200 VHF HT
152 12015 K4NBC K4NBC-Miguel UHF Mobile Palm Bay, Florida Future UHF Mobile
153 12016 K4NBC Miguel Palm Bay, Florida M2 Icom F6061D
154 12017 N4JFZ
155 12021 W4PJT Paul Paul
156 12023 KD4NWL John JOHN
157 12127 W4KDM Rick Rick - Portable NX300
158 12136 WA4KWK John John F6121
159 12200 NB9X Paul FL
160 12201 NB9X Paul FL PAUL
161 12202 NB9X Paul FL
162 12203 NB9X Paul FL
163 12204 WX3C Juan Arias Florida Orlando metro
164 12204 NB9X Paul FL
165 12210 N4APG Bill Bill Pfost
166 12211 N4APG Bill Bill Pfost
167 12212 N4APG Bill Bill Pfost
168 12213 N4APG Bill Bill Pfost
169 12214 N4APG Bill Bill Pfost
170 12215 WA4ISB Ed ED Mobile
171 12216 WA4ISB Ed
172 12220 N4PK Paul PAUK K.
173 12221 N4PK Paul
174 12222 W4PJT Paul
175 12223 W4PJT Paul
176 12226 KI4SWY William
177 12230 KQ4KX Richard Richard Sharp
178 12231 KQ4KX Richard
179 12234 KD4TWJ Dean EL98
180 12235 N1IC Nick Nic
181 12236 N1IC Nick
182 12240 KR4X Larry
183 12241 KR4X Larry
184 12245 KD4ACG Jason Hudson, FL Icom Mobile
185 12245 KD4ACG Jason JASON
186 12246 KD4ACG Jason Hudson, FL Icom Portable
187 12246 KD4ACG Jason JASON
188 12247 K2MCI
189 12250 KE4GYX
190 12272 KE4OSL
191 12273 KE4OSL
192 12374 KF4I Thom Thom Base
193 12375 KF4I Thom Thom Mobile
194 12523 KM4JVE Ana Ana - IC-F4161
195 12577 N2DLX Richard Rich Dunajewski NX-5800
196 12604 K4CBN Greg GREG
197 12605 K4CBN Greg
198 12606 K4CBN Greg
199 12607 K4CBN Greg
200 12608 K4CBN Greg
201 12666 KI4SWY William William Stillwel ( All Radios )
202 12691 KE3WDW Sam Sam
203 12780 KC4YUA Brett BRETT
204 13105 W7QO Alan
205 13106 W7QO Alan
206 13107 W7QO Alan
207 13121 W4CML Chuck
208 13122 W4CML Chuck
209 13125 KD4APP Don Don - NX300
210 13126 KD4APP Don Don - F6061D
211 13127 KD4APP Don Don - NX200
212 13131 W5JR Mike
213 13132 W5JR Mike
214 13401 W1KFR Bill Bill
215 13815 KG4BKO Bill GA nx320
216 14020 K4XXX Ed London, KY NX5300
217 14021 K4XXX Ed London, KY NX5200
218 15001 N5QZ Ryan AR N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-800H (Vehicle 1)
219 15002 N5QZ Ryan AR N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-700 (Vehicle 1)
220 15003 N5QZ Ryan AR N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-800 (Vehicle 2)
221 15004 N5QZ Ryan AR N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-700 (Vehicle 2)
222 15005 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-800 (Vehicle 1)
223 15006 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-700 (Vehicle 1)
224 15007 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-800 (Vehicle 2)
225 15008 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-700 (Vehicle 2)
226 15009 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-800 (Vehicle 3)
227 15010 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-700 (Vehicle 3)
228 15011 N5QT Dawn AR N5QT, Dawn Gray, Searcy, AR - Kenwood NX-800
229 15012 AC5AV Larry AR AC5AV, Larry Sicks, Searcy, AR - Kenwood NX-800
230 15013 AC5AV Larry AR AC5AV, Larry Sicks, Searcy, AR - Kenwood NX-700
231 15014 N5QT Dawn AR N5QT, Dawn Gray, Searcy, AR - Kenwood NX-700
232 15015 N5QS Roger AR N5QS, Roger Gray, Searcy, AR Motorcycle Mobile
233 15016 KG5KS Kenny KG5KS, Kenny Thompson - Kenwood NX-700HK
234 15017 KG5KS Kenny KG5KS, Kenny Thompson - Kenwood NX-800HK
235 15018 N5QS Roger AR N5QS, Roger Gray, Searcy, AR ATV Mobile
236 15019 N5QS Roger AR N5QS, Roger Gray, Searcy, AR ATV Mobile
237 15020 WA8UBL Allen AR WA8UBL, Allen Herrick, Beebe, AR, Kenwood NX-700
238 15021 KD5HRT Heath AR KD5HRT, Heath Taylor, McRae, AR, Kenwood NX-800
239 15022 WA8UBL Allen AR WA8UBL, Allen Herrick, Beebe, AR - Kenwood NX-800
240 15023 N5ZA Joel AR N5ZA, Joe Belew, Beebe, AR - Kenwood NX-700
241 15024 KF5TPF Ryan AR KF5TPF, Ryan Nelson, Edgemont, AR NX-700
242 15025 KE5YZP Ryan AR KE5YZP, Ryan Schwarck, Batesville, AR NX-700
243 15026 AF5OD Landon AR AF5OD, Landon McCord, Searcy, AR
244 15027 KB5RFF Scott AR KB5RFF, Scott Gray, Searcy, AR - Kenwood NX-800
245 17002 KC9GMX Stephen Stephen - Base F6121D
246 17004 KC9GMX Stephen Stephen - F6061D
247 17005 KC9NPJ Jarrett Jarrett F6121D
248 17006 KC9GMX Stephen Stephen - F4161DS
249 17007 KC9NPJ Jarrett Jarrett F4231DS
250 17008 KC9RHH Jesse F4101D
251 17009 KC9PHK Michael F4061DS
252 17011 N9BRG Dan Dan kenwood nx800k2
253 17855 AG6RN Demian CA NX-210
254 21007 WA1LMV Rick Rick
255 21014 K2BUI Eric Eric
256 24020 K4XXX Ed London, KY NX5800
257 24021 K4XXX Ed London, KY NX5700
258 25001 N5QZ Ryan AR N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-300
259 25002 N5QZ Ryan AR N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-200
260 25003 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-300
261 25004 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-200
262 25005 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-320
263 25006 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-340U
264 25007 N5QT Dawn AR N5QT, Dawn Gray, Searcy, AR - Kenwood NX-300
265 25008 N5QT Dawn AR N5QT, Dawn Gray, Searcy, AR - Kenwood NX-200
266 25009 AC5AV Larry AR AC5AV, Larry Sicks, Searcy, AR - Kenwood NX-300
267 25010 KD5OOW Tom AR KD5OOW, Tom McGee, Searcy, AR - Kenwood NX-300
268 25011 W5ZN Joel AR W5ZN, Joel Harrison, Judsonia, AR - Kenwood NX-300
269 25012 KD5HRT Heath AR KD5HRT, Heath Taylor, McRae, AR - Kenwood NX-300
270 25013 KK5WA Darin AR KK5WA, Darin Dykes, Beebe, AR - Kenwood NX-320
271 25014 N5LKE James AR N5LKE, James Ferguson, Searcy, AR - Kenwood NX-5300
272 25015 KJ5ORD John AR KJ5ORD, John Ord, Searcy, AR - Kenwood NX-300
273 25016 KB5RFF Scott AR KB5RFF, Scott Gray, Searcy, AR - Kenwood NX-300
274 25017 KB5ZUH Todd AR KB5ZUH, Todd Williams, Searcy, AR - Kenwood NX-320
275 25018 KB5ZUH Todd AR KB5ZUH, Todd Williams, Searcy, AR - Kenwood NX-340
276 25019 KB5ZUH Todd AR KB5ZUH, Todd Williams, Searcy, AR - Kenwood NX-340
277 25020 KB5ZUH Todd AR KB5ZUH, Todd Williams, Searcy, AR - Kenwood NX-320
278 25021 KE5UZU Raymond Prince England, AR Kenwood Handheld
279 25021 AF5OD Landon AR AF5OD, Landon McCord, Searcy, AR
280 25022 KE5UZU Raymond Prince England, AR Icom Handheld
281 25022 KE5YZP Ryan AR KE5YZP, Ryan A Schwarck, Batesville, AR - Icom
282 25023 KE5YZP Ryan AR KE5YZP, Ryan A Schwarck, Batesville, AR - Icom
283 25024 KG5CHM Colt AR KG5CHM, Colt Boyd, Searcy, AR - Kenwood NX-300
284 25025 KJ5ORD John AR KJ5ORD, John Ord, Searcy, AR - Kenwood NX-xxx VHF
285 25026 WA8UBL Allen AR WA8UBL, Allen Herrick, Beebe, AR - Kenwood NX-320
286 25027 KF5TPF Ryan AR KF5TPF, Ryan Nelson, Edgemont, AR - Kenwood NX-200
287 25028 WA8UBL Allen AR WA8UBL, Allen Herrick, Beebe, AR - Kenwood NX-220
288 25029 KF5WHX Trey AR KF5WHX, Trey Ferguson, Searcy, AR - Kenwood NX-320
289 25030 AC5AV Larry AR AC5AV, Larry Sicks, Searcy, AR
290 25031 KJ5SF Stan AR KJ5SF, Stan Rongey, Searcy, AR - Kenwood NX-340
291 25032 KC5DFH Kirk AR KC5DFH, Kirk Williams, Searcy, AR - Kenwood NX-340
292 25033 AF5OD Landon AR AF5OD, Landon McCord, Searcy, AR, Icom F4161DS
293 25034 KF5TPF Ryan AR KF5TPF, Ryan Nelson, Edgemont, AR - ICOM 4161
294 25035 KG5BMB Glenda AR KG5BMB, Glenda McCord, Searcy, AR, Icom F4161DS
295 25039 KC1JET Jim JIM (BASE)
296 25068 N1QD Joe
297 25069 N1COP Bob Bob
298 25070 WD1L John John
299 25125 N1TI Tim Mattapoisett, MA
300 25125 N1TI Tim Mattapoisett, MA
301 25144 W1WCF Walter Walter
302 25221 N0XIA James James - Kenwood Mobile and Portable
303 25222 KE4SDC Ron Ron - Portable NX300
304 25246 WG1U Ken Assonet, MA
305 25333 W1AKN Jack Jack Mobile
306 25390 KC1JET Jim JIM (MOBILE)
307 25390 KC1JET Jim JIM
308 25444 W1TAV Steve Steve
309 25555 WA1MNQ Mike Mike
310 25582 N1KXJ Ray E. Bridgewater, MA. Port.
311 25582 N1KXJ Ray Wall East Bridgewater
312 25585 N1AVA Ken Howland DARTMOUTH,MA
313 25700 NN1D Tony Souza Swansea, MA
314 25740 WG1U Kenny KEN
315 25743 WG1U Kenny KEN
316 25746 N1OTY John JOHN
317 25777 W1BON Bump Bump
318 25830 KB1CHU Steve MA
319 25863 N1ZZN Jeff JEFF
320 25874 KB1KVD Jason Jason - Icom Mob & Port
321 25888 K1WGU Bob Bob
322 25889 AB1CQ Gary Gary
323 25900 N1ZZR Matt Matt - mobile
324 25901 N1MRC Matt Bridgewater, MA N1MRC P-1
325 25901 N1ZZR Matt Matt
326 25957 KC1HO Steve STEVE
327 27101 KI4SWB Mark Melbourne Beach, FL Icom Portable
328 27102 KP4OO Carlos Palm Bay, FL Icom Portable
329 27201 KI4SWB Mark Melbourne Beach, FL Icom Mobile
330 27202 KP4OO Carlos Palm Bay, FL Icom Mobile
331 28001 K3KRS rYAN CLEVLAND OHIO
332 30505 KG6MQE Jim MT
333 30571 WX4RCF Ryan F. Tampa, FL
334 31117 K4QHR Pete Pete
335 31124 KM4JXP Peter NX5300
336 31146 KD2KWD Michael Santamaria Brandon, FL Kenwood
337 33000 N1PA-R Paul NH PAUL - NEW HAMPSHIRE REPEATER
338 33001 N1PA Paul NH PAUL - NEW HAMPSHIRE
339 33002 N1PA Paul NH PAUL - NEW HAMPSHIRE
340 34001 N2WNS Bill NJ N2WNS Portable
341 34002 N2WNS Bill NJ N2WNS Base
342 36001 W2CCR Chris NY Chris, Galway, NY NX300
343 36002 KC2VOB Asad NY Asad, NYC, NX-5800
344 36003 KC2VOB Asad NY Asad, NYC, NX-300GK
345 36134 N2SRO Mike Pitman, NJ Portable
346 37001 KA4YMY Steve NC Steve, Charlotte, NC NX320
347 37009 KA4YMY Steve Charlotte, NC
348 37010 KA4YMY Steve Charlotte, NC
349 37010 KA4YMY Steve Charlotte, NC
350 40024 N5YEI Jeff Dalrymple Jay, Oklahoma NX-5800 Mobile
351 40124 N5YEI Jeff Dalrymple Jay, Oklahoma NX-5300 Portable
352 43751 N4IRS Steve Steve
353 44001 K2BUI Eric RI
354 44002 K2BUI Eric Providence, RI
355 44007 W2DAN Dave Dave - NX700
356 44298 N1JBC Jed JED
357 49101 WX7Y-1 Bret Mills Castle Dale Utah WX7y-1 Hand Held 1
358 49102 WX7Y-2 Bret Mills Caslte Dale, Utah WX7Y-2 Hand held
359 49104 WX7Y-4 Bret Mills Castle Dale, Utah WX7Y-4 Mobile
360 49106 WX7Y-6 Bret Mills Castle Dale WX7Y-6 Mobile
361 55700 WB9HKE Rick WI
362 55704 WB9HKE Rick WI
363 57000 VE3SP Andre Toronto, ON mobile
364 57001 VE3SP Andre Toronto, ON handheld
365 57001 VE3EI Eric Eric - Portable
366 57002 VE3OKZ Janusz Toronto, ON mobile
367 57002 VE3EI Eric Eric - Dongle
368 57003 VE3OKZ Janusz Toronto, ON handheld
369 57004 VE3CCD Curtis Scarborough, ON handheld
370 57005 VE3NBI Anoop Scarborough, ON handheld
371 57006 VE3JLU Sherwin Scarborough, ON handheld
372 57007 va3rq Jon Oakville, ON handheld
373 57008 ve3ogb Randy Toronto, ON handheld
374 57009 va3mk Mark Oakville, ON handheld
375 57010 va3mk Mark Oakville, ON mobile
376 57011 VA3WZW Andre Durham, ON mobile
377 57012 VA3WZW Andre Durham, ON mobile
378 57013 VA3AGV cottage Toronto, ON mobile
379 57014 VE3BWP Brian Caledon, ON handheld
380 57015 VE3HY Frank Caledon, ON handheld
381 57016 VE3UBI Paul Scarborough, ON mobile
382 57017 VE3UBI Paul Scarborough, ON handheld
383 57018 VE3RZR Richard Toronto, ON handheld
384 57019 VE3AEP Dom Toronto, ON mobile
385 57020 VA3PEO Adrian Toronto, ON handheld
386 57021 va3wjo Walter Toronto, ON handheld
387 57022 ve3fkn Tom Stoney Creek, ON handheld
388 57023 ve3ips John Toronto, ON handheld
389 57024 VA3CQA Brian Scarborough, ON handheld
390 57025 VA3PAD Andrew Scarborough, ON mobile
391 57026 VA3PAD Andrew Scarborough, ON handheld
392 57027 VA3VAD Arpad Hamilton, ON handheld
393 57028 VA3KY Shelly Thornhill, ON mobile
394 57029 VA3KY Shelly Thornhill, ON handheld
395 57030 VE3KFQ Doug Toronto, ON mobile
396 57031 VE3KFQ Doug Toronto, ON handheld
397 57032 VE3AEP Dom 2 Toronto, ON handheld
398 57033 VE3DJZ Huey Hamilton, ON mobile
399 57034 VE3DJZ Huey Hamilton, ON handheld
400 57035 VA3RQ Jon Oakville ON Mobile
401 3106418 N5ICK Nicholas Nixon Rialto, Ca
402 3112205 N2HUC Phil Roberts Port St. Lucie, FL DV4MINI AMBE voice
403 3118365 NA9VY Chris Gilbert New Palestine, IN
404 3118366 N9UMJ Rick Nicholson Buddha Indiana
405 3142058 N3BAH L. Abraham Smith Southwestern Pennsylvania

185
NXDNGateway/NXDNCRC.cpp Normal file
View File

@ -0,0 +1,185 @@
/*
* Copyright (C) 2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "NXDNCRC.h"
#include <cstdio>
#include <cassert>
const uint8_t BIT_MASK_TABLE1[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE1[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE1[(i)&7])
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE1[(i)&7])
bool CNXDNCRC::checkCRC6(const unsigned char* in, unsigned int length)
{
assert(in != NULL);
uint8_t crc = createCRC6(in, length);
uint8_t temp[1U];
temp[0U] = 0x00U;
unsigned int j = length;
for (unsigned int i = 2U; i < 8U; i++, j++) {
bool b = READ_BIT1(in, j);
WRITE_BIT1(temp, i, b);
}
return crc == temp[0U];
}
void CNXDNCRC::encodeCRC6(unsigned char* in, unsigned int length)
{
assert(in != NULL);
uint8_t crc[1U];
crc[0U] = createCRC6(in, length);
unsigned int n = length;
for (unsigned int i = 2U; i < 8U; i++, n++) {
bool b = READ_BIT1(crc, i);
WRITE_BIT1(in, n, b);
}
}
bool CNXDNCRC::checkCRC12(const unsigned char* in, unsigned int length)
{
assert(in != NULL);
uint16_t crc = createCRC12(in, length);
uint8_t temp1[2U];
temp1[0U] = (crc >> 8) & 0xFFU;
temp1[1U] = (crc >> 0) & 0xFFU;
uint8_t temp2[2U];
temp2[0U] = 0x00U;
temp2[1U] = 0x00U;
unsigned int j = length;
for (unsigned int i = 4U; i < 16U; i++, j++) {
bool b = READ_BIT1(in, j);
WRITE_BIT1(temp2, i, b);
}
return temp1[0U] == temp2[0U] && temp1[1U] == temp2[1U];
}
void CNXDNCRC::encodeCRC12(unsigned char* in, unsigned int length)
{
assert(in != NULL);
uint16_t crc = createCRC12(in, length);
uint8_t temp[2U];
temp[0U] = (crc >> 8) & 0xFFU;
temp[1U] = (crc >> 0) & 0xFFU;
unsigned int n = length;
for (unsigned int i = 4U; i < 16U; i++, n++) {
bool b = READ_BIT1(temp, i);
WRITE_BIT1(in, n, b);
}
}
bool CNXDNCRC::checkCRC15(const unsigned char* in, unsigned int length)
{
assert(in != NULL);
uint16_t crc = createCRC15(in, length);
uint8_t temp1[2U];
temp1[0U] = (crc >> 8) & 0xFFU;
temp1[1U] = (crc >> 0) & 0xFFU;
uint8_t temp2[2U];
temp2[0U] = 0x00U;
temp2[1U] = 0x00U;
unsigned int j = length;
for (unsigned int i = 1U; i < 16U; i++, j++) {
bool b = READ_BIT1(in, j);
WRITE_BIT1(temp2, i, b);
}
return temp1[0U] == temp2[0U] && temp1[1U] == temp2[1U];
}
void CNXDNCRC::encodeCRC15(unsigned char* in, unsigned int length)
{
assert(in != NULL);
uint16_t crc = createCRC15(in, length);
uint8_t temp[2U];
temp[0U] = (crc >> 8) & 0xFFU;
temp[1U] = (crc >> 0) & 0xFFU;
unsigned int n = length;
for (unsigned int i = 1U; i < 16U; i++, n++) {
bool b = READ_BIT1(temp, i);
WRITE_BIT1(in, n, b);
}
}
uint8_t CNXDNCRC::createCRC6(const unsigned char* in, unsigned int length)
{
uint8_t crc = 0x3FU;
for (unsigned int i = 0U; i < length; i++) {
bool bit1 = READ_BIT1(in, i) != 0x00U;
bool bit2 = (crc & 0x20U) == 0x20U;
crc <<= 1;
if (bit1 ^ bit2)
crc ^= 0x27U;
}
return crc & 0x3FU;
}
uint16_t CNXDNCRC::createCRC12(const unsigned char* in, unsigned int length)
{
uint16_t crc = 0x0FFFU;
for (unsigned int i = 0U; i < length; i++) {
bool bit1 = READ_BIT1(in, i) != 0x00U;
bool bit2 = (crc & 0x0800U) == 0x0800U;
crc <<= 1;
if (bit1 ^ bit2)
crc ^= 0x080FU;
}
return crc & 0x0FFFU;
}
uint16_t CNXDNCRC::createCRC15(const unsigned char* in, unsigned int length)
{
uint16_t crc = 0x7FFFU;
for (unsigned int i = 0U; i < length; i++) {
bool bit1 = READ_BIT1(in, i) != 0x00U;
bool bit2 = (crc & 0x4000U) == 0x4000U;
crc <<= 1;
if (bit1 ^ bit2)
crc ^= 0x4CC5U;
}
return crc & 0x7FFFU;
}

42
NXDNGateway/NXDNCRC.h Normal file
View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(NXDNCRC_H)
#define NXDNCRC_H
#include <cstdint>
class CNXDNCRC
{
public:
static bool checkCRC6(const unsigned char* in, unsigned int length);
static void encodeCRC6(unsigned char* in, unsigned int length);
static bool checkCRC12(const unsigned char* in, unsigned int length);
static void encodeCRC12(unsigned char* in, unsigned int length);
static bool checkCRC15(const unsigned char* in, unsigned int length);
static void encodeCRC15(unsigned char* in, unsigned int length);
private:
static uint8_t createCRC6(const unsigned char* in, unsigned int length);
static uint16_t createCRC12(const unsigned char* in, unsigned int length);
static uint16_t createCRC15(const unsigned char* in, unsigned int length);
};
#endif

380
NXDNGateway/NXDNGateway.cpp Normal file
View File

@ -0,0 +1,380 @@
/*
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "IcomNetwork.h"
#include "NXDNNetwork.h"
#include "NXDNGateway.h"
#include "NXDNLookup.h"
#include "Reflectors.h"
#include "StopWatch.h"
#include "Version.h"
#include "Thread.h"
#include "Voice.h"
#include "Timer.h"
#include "Log.h"
#if defined(_WIN32) || defined(_WIN64)
#include <Windows.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <pwd.h>
#endif
#if defined(_WIN32) || defined(_WIN64)
const char* DEFAULT_INI_FILE = "NXDNGateway.ini";
#else
const char* DEFAULT_INI_FILE = "/etc/NXDNGateway.ini";
#endif
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <ctime>
#include <cstring>
int main(int argc, char** argv)
{
const char* iniFile = DEFAULT_INI_FILE;
if (argc > 1) {
for (int currentArg = 1; currentArg < argc; ++currentArg) {
std::string arg = argv[currentArg];
if ((arg == "-v") || (arg == "--version")) {
::fprintf(stdout, "NXDNGateway version %s\n", VERSION);
return 0;
} else if (arg.substr(0, 1) == "-") {
::fprintf(stderr, "Usage: NXDNGateway [-v|--version] [filename]\n");
return 1;
} else {
iniFile = argv[currentArg];
}
}
}
CNXDNGateway* gateway = new CNXDNGateway(std::string(iniFile));
gateway->run();
delete gateway;
return 0;
}
CNXDNGateway::CNXDNGateway(const std::string& file) :
m_conf(file)
{
}
CNXDNGateway::~CNXDNGateway()
{
}
void CNXDNGateway::run()
{
bool ret = m_conf.read();
if (!ret) {
::fprintf(stderr, "NXDNGateway: cannot read the .ini file\n");
return;
}
ret = ::LogInitialise(m_conf.getLogFilePath(), m_conf.getLogFileRoot(), 1U, 1U);
if (!ret) {
::fprintf(stderr, "NXDNGateway: unable to open the log file\n");
return;
}
#if !defined(_WIN32) && !defined(_WIN64)
bool m_daemon = m_conf.getDaemon();
if (m_daemon) {
// Create new process
pid_t pid = ::fork();
if (pid == -1) {
::LogWarning("Couldn't fork() , exiting");
return;
}
else if (pid != 0)
exit(EXIT_SUCCESS);
// Create new session and process group
if (::setsid() == -1) {
::LogWarning("Couldn't setsid(), exiting");
return;
}
// Set the working directory to the root directory
if (::chdir("/") == -1) {
::LogWarning("Couldn't cd /, exiting");
return;
}
::close(STDIN_FILENO);
::close(STDOUT_FILENO);
::close(STDERR_FILENO);
//If we are currently root...
if (getuid() == 0) {
struct passwd* user = ::getpwnam("mmdvm");
if (user == NULL) {
::LogError("Could not get the mmdvm user, exiting");
return;
}
uid_t mmdvm_uid = user->pw_uid;
gid_t mmdvm_gid = user->pw_gid;
//Set user and group ID's to mmdvm:mmdvm
if (setgid(mmdvm_gid) != 0) {
::LogWarning("Could not set mmdvm GID, exiting");
return;
}
if (setuid(mmdvm_uid) != 0) {
::LogWarning("Could not set mmdvm UID, exiting");
return;
}
//Double check it worked (AKA Paranoia)
if (setuid(0) != -1) {
::LogWarning("It's possible to regain root - something is wrong!, exiting");
return;
}
}
}
#endif
CIcomNetwork localNetwork(m_conf.getMyAddress(), m_conf.getMyPort(), m_conf.getRptAddress(), m_conf.getRptPort(), false);
ret = localNetwork.open();
if (!ret) {
::LogFinalise();
return;
}
CNXDNNetwork remoteNetwork(m_conf.getNetworkPort(), m_conf.getCallsign(), m_conf.getNetworkDebug());
ret = remoteNetwork.open();
if (!ret) {
localNetwork.close();
::LogFinalise();
return;
}
CReflectors reflectors(m_conf.getNetworkHosts1(), m_conf.getNetworkHosts2(), m_conf.getNetworkReloadTime());
if (m_conf.getNetworkParrotPort() > 0U)
reflectors.setParrot(m_conf.getNetworkParrotAddress(), m_conf.getNetworkParrotPort());
reflectors.load();
CNXDNLookup* lookup = new CNXDNLookup(m_conf.getLookupName(), m_conf.getLookupTime());
lookup->read();
CTimer inactivityTimer(1000U, m_conf.getNetworkInactivityTimeout() * 60U);
CTimer lostTimer(1000U, 120U);
CTimer pollTimer(1000U, 5U);
CStopWatch stopWatch;
stopWatch.start();
CVoice* voice = NULL;
if (m_conf.getVoiceEnabled())
voice = new CVoice(m_conf.getVoiceDirectory(), m_conf.getVoiceLanguage(), 1U);
LogMessage("Starting NXDNGateway-%s", VERSION);
unsigned short srcId = 0U;
unsigned short dstId = 0U;
bool grp = false;
unsigned int currentId = 9999U;
in_addr currentAddr;
unsigned int currentPort = 0U;
unsigned int id = m_conf.getNetworkStartup();
if (id != 9999U) {
CNXDNReflector* reflector = reflectors.find(id);
if (reflector != NULL) {
currentId = id;
currentAddr = reflector->m_address;
currentPort = reflector->m_port;
inactivityTimer.start();
pollTimer.start();
lostTimer.start();
remoteNetwork.writePoll(currentAddr, currentPort);
remoteNetwork.writePoll(currentAddr, currentPort);
remoteNetwork.writePoll(currentAddr, currentPort);
LogMessage("Linked at startup to reflector %u", currentId);
}
}
for (;;) {
unsigned char buffer[200U];
in_addr address;
unsigned int port;
// From the reflector to the MMDVM
unsigned int len = remoteNetwork.readData(buffer, 200U, address, port);
if (len > 0U) {
// If we're linked and it's from the right place, send it on
if (currentId != 9999U && currentAddr.s_addr == address.s_addr && currentPort == port) {
// Don't pass reflector control data through to the MMDVM
if (::memcmp(buffer, "NXDND", 5U) == 0)
localNetwork.write(buffer + 10U, len - 10U);
// Any network activity is proof that the reflector is alive
lostTimer.start();
}
}
// From the MMDVM to the reflector or control data
len = localNetwork.read(buffer);
if (len > 0U) {
if (buffer[0U] == 0x81U || buffer[0U] == 0x83U) {
grp = (buffer[7U] & 0x20U) == 0x20U;
srcId = (buffer[8U] << 8) & 0xFF00U;
srcId |= (buffer[9U] << 0) & 0x00FFU;
dstId = (buffer[10U] << 8) & 0xFF00U;
dstId |= (buffer[11U] << 0) & 0x00FFU;
if (dstId != currentId) {
CNXDNReflector* reflector = NULL;
if (dstId != 9999U)
reflector = reflectors.find(dstId);
// If we're unlinking or changing reflectors, unlink from the current one
if (dstId == 9999U || reflector != NULL) {
std::string callsign = lookup->find(srcId);
if (currentId != 9999U) {
LogMessage("Unlinked from reflector %u by %s", currentId, callsign.c_str());
remoteNetwork.writeUnlink(currentAddr, currentPort);
remoteNetwork.writeUnlink(currentAddr, currentPort);
remoteNetwork.writeUnlink(currentAddr, currentPort);
inactivityTimer.stop();
pollTimer.stop();
lostTimer.stop();
}
if (voice != NULL)
voice->linkedTo(dstId);
currentId = dstId;
}
// Link to the new reflector
if (reflector != NULL) {
currentId = dstId;
currentAddr = reflector->m_address;
currentPort = reflector->m_port;
std::string callsign = lookup->find(srcId);
LogMessage("Linked to reflector %u by %s", currentId, callsign.c_str());
remoteNetwork.writePoll(currentAddr, currentPort);
remoteNetwork.writePoll(currentAddr, currentPort);
remoteNetwork.writePoll(currentAddr, currentPort);
inactivityTimer.start();
pollTimer.start();
lostTimer.start();
}
}
}
// If we're linked and we have a network, send it on
if (currentId != 9999U) {
remoteNetwork.writeData(buffer, len, srcId, dstId, grp, currentAddr, currentPort);
inactivityTimer.start();
}
}
if (voice != NULL) {
unsigned int length = voice->read(buffer);
if (length > 0U)
localNetwork.write(buffer, length);
}
unsigned int ms = stopWatch.elapsed();
stopWatch.start();
reflectors.clock(ms);
if (voice != NULL)
voice->clock(ms);
inactivityTimer.clock(ms);
if (inactivityTimer.isRunning() && inactivityTimer.hasExpired()) {
if (currentId != 9999U) {
LogMessage("Unlinking from %u due to inactivity", currentId);
remoteNetwork.writeUnlink(currentAddr, currentPort);
remoteNetwork.writeUnlink(currentAddr, currentPort);
remoteNetwork.writeUnlink(currentAddr, currentPort);
if (voice != NULL)
voice->unlinked();
currentId = 9999U;
pollTimer.stop();
lostTimer.stop();
}
inactivityTimer.stop();
}
pollTimer.clock(ms);
if (pollTimer.isRunning() && pollTimer.hasExpired()) {
if (currentId != 9999U)
remoteNetwork.writePoll(currentAddr, currentPort);
pollTimer.start();
}
lostTimer.clock(ms);
if (lostTimer.isRunning() && lostTimer.hasExpired()) {
if (currentId != 9999U) {
LogWarning("No response from %u, unlinking", currentId);
currentId = 9999U;
}
inactivityTimer.stop();
lostTimer.stop();
}
localNetwork.clock(ms);
if (ms < 5U)
CThread::sleep(5U);
}
delete voice;
localNetwork.close();
remoteNetwork.close();
lookup->stop();
::LogFinalise();
}

53
NXDNGateway/NXDNGateway.h Normal file
View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(NXDNGateway_H)
#define NXDNGateway_H
#include "Timer.h"
#include "Conf.h"
#include <cstdio>
#include <string>
#include <vector>
#if !defined(_WIN32) && !defined(_WIN64)
#include <netdb.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#include <winsock.h>
#endif
class CNXDNGateway
{
public:
CNXDNGateway(const std::string& file);
~CNXDNGateway();
void run();
private:
CConf m_conf;
};
#endif

View File

@ -0,0 +1,31 @@
[General]
Callsign=G4KLX
RptAddress=127.0.0.1
RptPort=14021
LocalAddress=127.0.0.1
LocalPort=14020
Daemon=1
[Voice]
Enabled=1
Language=en_GB
Directory=./Audio
[Id Lookup]
Name=NXDN.csv
Time=24
[Log]
FilePath=.
FileRoot=NXDNGateway
[Network]
Port=14050
HostsFile1=./NXDNHosts.txt
HostsFile2=./private/NXDNHosts.txt
ReloadTime=60
ParrotAddress=127.0.0.1
ParrotPort=42011
Startup=10200
InactivityTimeout=10
Debug=0

View File

@ -0,0 +1,187 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>NXDNGateway</RootNamespace>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Conf.h" />
<ClInclude Include="IcomNetwork.h" />
<ClInclude Include="Log.h" />
<ClInclude Include="Mutex.h" />
<ClInclude Include="NXDNCRC.h" />
<ClInclude Include="NXDNGateway.h" />
<ClInclude Include="NXDNLookup.h" />
<ClInclude Include="NXDNNetwork.h" />
<ClInclude Include="Reflectors.h" />
<ClInclude Include="RingBuffer.h" />
<ClInclude Include="StopWatch.h" />
<ClInclude Include="Thread.h" />
<ClInclude Include="Timer.h" />
<ClInclude Include="UDPSocket.h" />
<ClInclude Include="Utils.h" />
<ClInclude Include="Version.h" />
<ClInclude Include="Voice.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Conf.cpp" />
<ClCompile Include="IcomNetwork.cpp" />
<ClCompile Include="Log.cpp" />
<ClCompile Include="Mutex.cpp" />
<ClCompile Include="NXDNCRC.cpp" />
<ClCompile Include="NXDNGateway.cpp" />
<ClCompile Include="NXDNLookup.cpp" />
<ClCompile Include="NXDNNetwork.cpp" />
<ClCompile Include="Reflectors.cpp" />
<ClCompile Include="StopWatch.cpp" />
<ClCompile Include="Thread.cpp" />
<ClCompile Include="Timer.cpp" />
<ClCompile Include="UDPSocket.cpp" />
<ClCompile Include="Utils.cpp" />
<ClCompile Include="Voice.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Conf.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Log.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Mutex.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNGateway.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="StopWatch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Thread.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Timer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UDPSocket.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Version.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Reflectors.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNLookup.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IcomNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RingBuffer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Voice.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNCRC.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Conf.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Log.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Mutex.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNGateway.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="StopWatch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Thread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Timer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UDPSocket.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Reflectors.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNLookup.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="IcomNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Voice.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNCRC.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -0,0 +1,7 @@
# NXDNHosts.txt
#
# The format of this file is the number of the Talk Group followed by the host name or address and port
#
# World Wide, 65000
65000 176.9.1.168 41008

160
NXDNGateway/NXDNLookup.cpp Normal file
View File

@ -0,0 +1,160 @@
/*
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "NXDNLookup.h"
#include "Timer.h"
#include "Log.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
CNXDNLookup::CNXDNLookup(const std::string& filename, unsigned int reloadTime) :
CThread(),
m_filename(filename),
m_reloadTime(reloadTime),
m_table(),
m_mutex(),
m_stop(false)
{
}
CNXDNLookup::~CNXDNLookup()
{
}
bool CNXDNLookup::read()
{
bool ret = load();
if (m_reloadTime > 0U)
run();
return ret;
}
void CNXDNLookup::entry()
{
LogInfo("Started the NXDN Id lookup reload thread");
CTimer timer(1U, 3600U * m_reloadTime);
timer.start();
while (!m_stop) {
sleep(1000U);
timer.clock();
if (timer.hasExpired()) {
load();
timer.start();
}
}
LogInfo("Stopped the NXDN Id lookup reload thread");
}
void CNXDNLookup::stop()
{
if (m_reloadTime == 0U) {
delete this;
return;
}
m_stop = true;
wait();
}
std::string CNXDNLookup::find(unsigned int id)
{
std::string callsign;
if (id == 0xFFFFU)
return std::string("ALL");
m_mutex.lock();
try {
callsign = m_table.at(id);
} catch (...) {
char text[10U];
::sprintf(text, "%u", id);
callsign = std::string(text);
}
m_mutex.unlock();
return callsign;
}
bool CNXDNLookup::exists(unsigned int id)
{
m_mutex.lock();
bool found = m_table.count(id) == 1U;
m_mutex.unlock();
return found;
}
bool CNXDNLookup::load()
{
FILE* fp = ::fopen(m_filename.c_str(), "rt");
if (fp == NULL) {
LogWarning("Cannot open the NXDN Id lookup file - %s", m_filename.c_str());
return false;
}
m_mutex.lock();
// Remove the old entries
m_table.clear();
char buffer[100U];
while (::fgets(buffer, 100U, fp) != NULL) {
if (buffer[0U] == '#')
continue;
char* p1 = ::strtok(buffer, ",\t\r\n");
char* p2 = ::strtok(NULL, ",\t\r\n");
if (p1 != NULL && p2 != NULL) {
unsigned int id = (unsigned int)::atoi(p1);
if (id > 0U) {
for (char* p = p2; *p != 0x00U; p++)
*p = ::toupper(*p);
m_table[id] = std::string(p2);
}
}
}
m_mutex.unlock();
::fclose(fp);
size_t size = m_table.size();
if (size == 0U)
return false;
LogInfo("Loaded %u Ids to the NXDN callsign lookup table", size);
return true;
}

53
NXDNGateway/NXDNLookup.h Normal file
View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef NXDNLookup_H
#define NXDNLookup_H
#include "Thread.h"
#include "Mutex.h"
#include <string>
#include <unordered_map>
class CNXDNLookup : public CThread {
public:
CNXDNLookup(const std::string& filename, unsigned int reloadTime);
virtual ~CNXDNLookup();
bool read();
virtual void entry();
std::string find(unsigned int id);
bool exists(unsigned int id);
void stop();
private:
std::string m_filename;
unsigned int m_reloadTime;
std::unordered_map<unsigned int, std::string> m_table;
CMutex m_mutex;
bool m_stop;
bool load();
};
#endif

144
NXDNGateway/NXDNNetwork.cpp Normal file
View File

@ -0,0 +1,144 @@
/*
* Copyright (C) 2009-2014,2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "NXDNNetwork.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
CNXDNNetwork::CNXDNNetwork(unsigned int port, const std::string& callsign, bool debug) :
m_callsign(callsign),
m_socket(port),
m_debug(debug)
{
m_callsign.resize(10U, ' ');
}
CNXDNNetwork::~CNXDNNetwork()
{
}
bool CNXDNNetwork::open()
{
LogInfo("Opening NXDN network connection");
return m_socket.open();
}
bool CNXDNNetwork::writeData(const unsigned char* data, unsigned int length, unsigned short srcId, unsigned short dstId, bool grp, const in_addr& address, unsigned int port)
{
assert(data != NULL);
assert(length > 0U);
assert(port > 0U);
unsigned char buffer[20U];
buffer[0U] = 'N';
buffer[1U] = 'X';
buffer[2U] = 'D';
buffer[3U] = 'N';
buffer[4U] = 'D';
buffer[5U] = (srcId >> 8) & 0xFFU;
buffer[6U] = (srcId >> 0) & 0xFFU;
buffer[7U] = (dstId >> 8) & 0xFFU;
buffer[8U] = (dstId >> 0) & 0xFFU;
buffer[9U] = 0x00U;
buffer[9U] |= grp ? 0x01U : 0x00U;
if (data[0U] == 0x81U || data[0U] == 0x83U) {
buffer[9U] |= buffer[5U] == 0x01U ? 0x04U : 0x00U;
buffer[9U] |= buffer[5U] == 0x08U ? 0x08U : 0x00U;
}
::memcpy(buffer + 10U, data, 33U);
if (m_debug)
CUtils::dump(1U, "NXDN Network Data Sent", buffer, 43U);
return m_socket.write(buffer, 43U, address, port);
}
bool CNXDNNetwork::writePoll(const in_addr& address, unsigned int port)
{
assert(port > 0U);
unsigned char data[20U];
data[0U] = 'N';
data[1U] = 'X';
data[2U] = 'D';
data[3U] = 'N';
data[4U] = 'P';
for (unsigned int i = 0U; i < 10U; i++)
data[i + 5U] = m_callsign.at(i);
if (m_debug)
CUtils::dump(1U, "NXDN Network Poll Sent", data, 15U);
return m_socket.write(data, 15U, address, port);
}
bool CNXDNNetwork::writeUnlink(const in_addr& address, unsigned int port)
{
assert(port > 0U);
unsigned char data[20U];
data[0U] = 'N';
data[1U] = 'X';
data[2U] = 'D';
data[3U] = 'N';
data[4U] = 'U';
for (unsigned int i = 0U; i < 10U; i++)
data[i + 5U] = m_callsign.at(i);
if (m_debug)
CUtils::dump(1U, "NXDN Network Unlink Sent", data, 15U);
return m_socket.write(data, 15U, address, port);
}
unsigned int CNXDNNetwork::readData(unsigned char* data, unsigned int length, in_addr& address, unsigned int& port)
{
assert(data != NULL);
assert(length > 0U);
int len = m_socket.read(data, length, address, port);
if (len <= 0)
return 0U;
if (m_debug)
CUtils::dump(1U, "NXDN Network Data Received", data, len);
return len;
}
void CNXDNNetwork::close()
{
m_socket.close();
LogInfo("Closing NXDN network connection");
}

50
NXDNGateway/NXDNNetwork.h Normal file
View File

@ -0,0 +1,50 @@
/*
* Copyright (C) 2009-2014,2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef NXDNNetwork_H
#define NXDNNetwork_H
#include "UDPSocket.h"
#include <cstdint>
#include <string>
class CNXDNNetwork {
public:
CNXDNNetwork(unsigned int port, const std::string& callsign, bool debug);
~CNXDNNetwork();
bool open();
bool writeData(const unsigned char* data, unsigned int length, unsigned short srcId, unsigned short dstId, bool grp, const in_addr& address, unsigned int port);
bool writePoll(const in_addr& address, unsigned int port);
bool writeUnlink(const in_addr& address, unsigned int port);
unsigned int readData(unsigned char* data, unsigned int length, in_addr& address, unsigned int& port);
void close();
private:
std::string m_callsign;
CUDPSocket m_socket;
bool m_debug;
};
#endif

159
NXDNGateway/Reflectors.cpp Normal file
View File

@ -0,0 +1,159 @@
/*
* Copyright (C) 2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Reflectors.h"
#include "Log.h"
#include <algorithm>
#include <functional>
#include <cstdio>
#include <cassert>
#include <cstring>
#include <cctype>
CReflectors::CReflectors(const std::string& hostsFile1, const std::string& hostsFile2, unsigned int reloadTime) :
m_hostsFile1(hostsFile1),
m_hostsFile2(hostsFile2),
m_parrotAddress(),
m_parrotPort(0U),
m_reflectors(),
m_timer(1000U, reloadTime * 60U)
{
if (reloadTime > 0U)
m_timer.start();
}
CReflectors::~CReflectors()
{
for (std::vector<CNXDNReflector*>::iterator it = m_reflectors.begin(); it != m_reflectors.end(); ++it)
delete *it;
m_reflectors.clear();
}
void CReflectors::setParrot(const std::string& address, unsigned int port)
{
m_parrotAddress = address;
m_parrotPort = port;
}
bool CReflectors::load()
{
// Clear out the old reflector list
for (std::vector<CNXDNReflector*>::iterator it = m_reflectors.begin(); it != m_reflectors.end(); ++it)
delete *it;
m_reflectors.clear();
FILE* fp = ::fopen(m_hostsFile1.c_str(), "rt");
if (fp != NULL) {
char buffer[100U];
while (::fgets(buffer, 100U, fp) != NULL) {
if (buffer[0U] == '#')
continue;
char* p1 = ::strtok(buffer, " \t\r\n");
char* p2 = ::strtok(NULL, " \t\r\n");
char* p3 = ::strtok(NULL, " \t\r\n");
if (p1 != NULL && p2 != NULL && p3 != NULL) {
std::string host = std::string(p2);
in_addr address = CUDPSocket::lookup(host);
if (address.s_addr != INADDR_NONE) {
CNXDNReflector* refl = new CNXDNReflector;
refl->m_id = (unsigned int)::atoi(p1);
refl->m_address = address;
refl->m_port = (unsigned int)::atoi(p3);
m_reflectors.push_back(refl);
}
}
}
::fclose(fp);
}
fp = ::fopen(m_hostsFile2.c_str(), "rt");
if (fp != NULL) {
char buffer[100U];
while (::fgets(buffer, 100U, fp) != NULL) {
if (buffer[0U] == '#')
continue;
char* p1 = ::strtok(buffer, " \t\r\n");
char* p2 = ::strtok(NULL, " \t\r\n");
char* p3 = ::strtok(NULL, " \t\r\n");
if (p1 != NULL && p2 != NULL && p3 != NULL) {
std::string host = std::string(p2);
in_addr address = CUDPSocket::lookup(host);
if (address.s_addr != INADDR_NONE) {
CNXDNReflector* refl = new CNXDNReflector;
refl->m_id = (unsigned int)::atoi(p1);
refl->m_address = address;
refl->m_port = (unsigned int)::atoi(p3);
m_reflectors.push_back(refl);
}
}
}
::fclose(fp);
}
size_t size = m_reflectors.size();
LogInfo("Loaded %u NXDN reflectors", size);
// Add the Parrot entry
if (m_parrotPort > 0U) {
CNXDNReflector* refl = new CNXDNReflector;
refl->m_id = 10U;
refl->m_address = CUDPSocket::lookup(m_parrotAddress);
refl->m_port = m_parrotPort;
m_reflectors.push_back(refl);
LogInfo("Loaded NXDN parrot (TG%u)", refl->m_id);
}
size = m_reflectors.size();
if (size == 0U)
return false;
return true;
}
CNXDNReflector* CReflectors::find(unsigned int id)
{
for (std::vector<CNXDNReflector*>::iterator it = m_reflectors.begin(); it != m_reflectors.end(); ++it) {
if (id == (*it)->m_id)
return *it;
}
return NULL;
}
void CReflectors::clock(unsigned int ms)
{
m_timer.clock(ms);
if (m_timer.isRunning() && m_timer.hasExpired()) {
load();
m_timer.start();
}
}

64
NXDNGateway/Reflectors.h Normal file
View File

@ -0,0 +1,64 @@
/*
* Copyright (C) 2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(Reflectors_H)
#define Reflectors_H
#include "UDPSocket.h"
#include "Timer.h"
#include <vector>
#include <string>
class CNXDNReflector {
public:
CNXDNReflector() :
m_id(),
m_address(),
m_port(0U)
{
}
unsigned int m_id;
in_addr m_address;
unsigned int m_port;
};
class CReflectors {
public:
CReflectors(const std::string& hostsFile1, const std::string& hostsFile2, unsigned int reloadTime);
~CReflectors();
void setParrot(const std::string& address, unsigned int port);
bool load();
CNXDNReflector* find(unsigned int id);
void clock(unsigned int ms);
private:
std::string m_hostsFile1;
std::string m_hostsFile2;
std::string m_parrotAddress;
unsigned int m_parrotPort;
std::vector<CNXDNReflector*> m_reflectors;
CTimer m_timer;
};
#endif

147
NXDNGateway/RingBuffer.h Normal file
View File

@ -0,0 +1,147 @@
/*
* Copyright (C) 2006-2009,2012,2013,2015,2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef RingBuffer_H
#define RingBuffer_H
#include <cstdio>
#include <cassert>
#include <cstring>
template<class T> class CRingBuffer {
public:
CRingBuffer(unsigned int length, const char* name) :
m_length(length),
m_name(name),
m_buffer(NULL),
m_iPtr(0U),
m_oPtr(0U)
{
assert(length > 0U);
assert(name != NULL);
m_buffer = new T[length];
::memset(m_buffer, 0x00, m_length * sizeof(T));
}
~CRingBuffer()
{
delete[] m_buffer;
}
bool addData(const T* buffer, unsigned int nSamples)
{
if (nSamples >= freeSpace()) {
::fprintf(stderr, "**** Overflow in %s ring buffer, %u >= %u\n", m_name, nSamples, freeSpace());
return false;
}
for (unsigned int i = 0U; i < nSamples; i++) {
m_buffer[m_iPtr++] = buffer[i];
if (m_iPtr == m_length)
m_iPtr = 0U;
}
return true;
}
bool getData(T* buffer, unsigned int nSamples)
{
if (dataSize() < nSamples) {
::fprintf(stderr, "**** Underflow in %s ring buffer, %u < %u\n", m_name, dataSize(), nSamples);
return false;
}
for (unsigned int i = 0U; i < nSamples; i++) {
buffer[i] = m_buffer[m_oPtr++];
if (m_oPtr == m_length)
m_oPtr = 0U;
}
return true;
}
bool peek(T* buffer, unsigned int nSamples)
{
if (dataSize() < nSamples) {
::fprintf(stderr, "**** Underflow peek in %s ring buffer, %u < %u\n", m_name, dataSize(), nSamples);
return false;
}
unsigned int ptr = m_oPtr;
for (unsigned int i = 0U; i < nSamples; i++) {
buffer[i] = m_buffer[ptr++];
if (ptr == m_length)
ptr = 0U;
}
return true;
}
void clear()
{
m_iPtr = 0U;
m_oPtr = 0U;
::memset(m_buffer, 0x00, m_length * sizeof(T));
}
unsigned int freeSpace() const
{
if (m_oPtr == m_iPtr)
return m_length;
if (m_oPtr > m_iPtr)
return m_oPtr - m_iPtr;
return (m_length + m_oPtr) - m_iPtr;
}
unsigned int dataSize() const
{
return m_length - freeSpace();
}
bool hasSpace(unsigned int length) const
{
return freeSpace() > length;
}
bool hasData() const
{
return m_oPtr != m_iPtr;
}
bool isEmpty() const
{
return m_oPtr == m_iPtr;
}
private:
unsigned int m_length;
const char* m_name;
T* m_buffer;
unsigned int m_iPtr;
unsigned int m_oPtr;
};
#endif

84
NXDNGateway/StopWatch.cpp Normal file
View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "StopWatch.h"
#if defined(_WIN32) || defined(_WIN64)
CStopWatch::CStopWatch() :
m_frequency(),
m_start()
{
::QueryPerformanceFrequency(&m_frequency);
}
CStopWatch::~CStopWatch()
{
}
unsigned long CStopWatch::start()
{
::QueryPerformanceCounter(&m_start);
return (unsigned long)(m_start.QuadPart / m_frequency.QuadPart);
}
unsigned int CStopWatch::elapsed()
{
LARGE_INTEGER now;
::QueryPerformanceCounter(&now);
LARGE_INTEGER temp;
temp.QuadPart = (now.QuadPart - m_start.QuadPart) * 1000;
return (unsigned int)(temp.QuadPart / m_frequency.QuadPart);
}
#else
#include <cstdio>
CStopWatch::CStopWatch() :
m_start()
{
}
CStopWatch::~CStopWatch()
{
}
unsigned long CStopWatch::start()
{
::gettimeofday(&m_start, NULL);
return m_start.tv_usec;
}
unsigned int CStopWatch::elapsed()
{
struct timeval now;
::gettimeofday(&now, NULL);
unsigned int elapsed = (now.tv_sec - m_start.tv_sec) * 1000U;
elapsed += now.tv_usec / 1000U;
elapsed -= m_start.tv_usec / 1000U;
return elapsed;
}
#endif

46
NXDNGateway/StopWatch.h Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(STOPWATCH_H)
#define STOPWATCH_H
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <sys/time.h>
#endif
class CStopWatch
{
public:
CStopWatch();
~CStopWatch();
unsigned long start();
unsigned int elapsed();
private:
#if defined(_WIN32) || defined(_WIN64)
LARGE_INTEGER m_frequency;
LARGE_INTEGER m_start;
#else
struct timeval m_start;
#endif
};
#endif

101
NXDNGateway/Thread.cpp Normal file
View File

@ -0,0 +1,101 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Thread.h"
#if defined(_WIN32) || defined(_WIN64)
CThread::CThread() :
m_handle()
{
}
CThread::~CThread()
{
}
bool CThread::run()
{
m_handle = ::CreateThread(NULL, 0, &helper, this, 0, NULL);
return m_handle != NULL;
}
void CThread::wait()
{
::WaitForSingleObject(m_handle, INFINITE);
::CloseHandle(m_handle);
}
DWORD CThread::helper(LPVOID arg)
{
CThread* p = (CThread*)arg;
p->entry();
return 0UL;
}
void CThread::sleep(unsigned int ms)
{
::Sleep(ms);
}
#else
#include <unistd.h>
CThread::CThread() :
m_thread()
{
}
CThread::~CThread()
{
}
bool CThread::run()
{
return ::pthread_create(&m_thread, NULL, helper, this) == 0;
}
void CThread::wait()
{
::pthread_join(m_thread, NULL);
}
void* CThread::helper(void* arg)
{
CThread* p = (CThread*)arg;
p->entry();
return NULL;
}
void CThread::sleep(unsigned int ms)
{
::usleep(ms * 1000);
}
#endif

56
NXDNGateway/Thread.h Normal file
View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(THREAD_H)
#define THREAD_H
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <pthread.h>
#endif
class CThread
{
public:
CThread();
virtual ~CThread();
virtual bool run();
virtual void entry() = 0;
virtual void wait();
static void sleep(unsigned int ms);
private:
#if defined(_WIN32) || defined(_WIN64)
HANDLE m_handle;
#else
pthread_t m_thread;
#endif
#if defined(_WIN32) || defined(_WIN64)
static DWORD __stdcall helper(LPVOID arg);
#else
static void* helper(void* arg);
#endif
};
#endif

68
NXDNGateway/Timer.cpp Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2009,2010,2015 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Timer.h"
#include <cstdio>
#include <cassert>
CTimer::CTimer(unsigned int ticksPerSec, unsigned int secs, unsigned int msecs) :
m_ticksPerSec(ticksPerSec),
m_timeout(0U),
m_timer(0U)
{
assert(ticksPerSec > 0U);
if (secs > 0U || msecs > 0U) {
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
}
}
CTimer::~CTimer()
{
}
void CTimer::setTimeout(unsigned int secs, unsigned int msecs)
{
if (secs > 0U || msecs > 0U) {
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
} else {
m_timeout = 0U;
m_timer = 0U;
}
}
unsigned int CTimer::getTimeout() const
{
if (m_timeout == 0U)
return 0U;
return (m_timeout - 1U) / m_ticksPerSec;
}
unsigned int CTimer::getTimer() const
{
if (m_timer == 0U)
return 0U;
return (m_timer - 1U) / m_ticksPerSec;
}

89
NXDNGateway/Timer.h Normal file
View File

@ -0,0 +1,89 @@
/*
* Copyright (C) 2009,2010,2011,2014 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef Timer_H
#define Timer_H
class CTimer {
public:
CTimer(unsigned int ticksPerSec, unsigned int secs = 0U, unsigned int msecs = 0U);
~CTimer();
void setTimeout(unsigned int secs, unsigned int msecs = 0U);
unsigned int getTimeout() const;
unsigned int getTimer() const;
unsigned int getRemaining()
{
if (m_timeout == 0U || m_timer == 0U)
return 0U;
if (m_timer >= m_timeout)
return 0U;
return (m_timeout - m_timer) / m_ticksPerSec;
}
bool isRunning()
{
return m_timer > 0U;
}
void start(unsigned int secs, unsigned int msecs = 0U)
{
setTimeout(secs, msecs);
start();
}
void start()
{
if (m_timeout > 0U)
m_timer = 1U;
}
void stop()
{
m_timer = 0U;
}
bool hasExpired()
{
if (m_timeout == 0U || m_timer == 0U)
return false;
if (m_timer >= m_timeout)
return true;
return false;
}
void clock(unsigned int ticks = 1U)
{
if (m_timer > 0U && m_timeout > 0U)
m_timer += ticks;
}
private:
unsigned int m_ticksPerSec;
unsigned int m_timeout;
unsigned int m_timer;
};
#endif

262
NXDNGateway/UDPSocket.cpp Normal file
View File

@ -0,0 +1,262 @@
/*
* Copyright (C) 2006-2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "UDPSocket.h"
#include "Log.h"
#include <cassert>
#if !defined(_WIN32) && !defined(_WIN64)
#include <cerrno>
#include <cstring>
#endif
CUDPSocket::CUDPSocket(const std::string& address, unsigned int port) :
m_address(address),
m_port(port),
m_fd(-1)
{
assert(!address.empty());
#if defined(_WIN32) || defined(_WIN64)
WSAData data;
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
if (wsaRet != 0)
LogError("Error from WSAStartup");
#endif
}
CUDPSocket::CUDPSocket(unsigned int port) :
m_address(),
m_port(port),
m_fd(-1)
{
#if defined(_WIN32) || defined(_WIN64)
WSAData data;
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
if (wsaRet != 0)
LogError("Error from WSAStartup");
#endif
}
CUDPSocket::~CUDPSocket()
{
#if defined(_WIN32) || defined(_WIN64)
::WSACleanup();
#endif
}
in_addr CUDPSocket::lookup(const std::string& hostname)
{
in_addr addr;
#if defined(_WIN32) || defined(_WIN64)
unsigned long address = ::inet_addr(hostname.c_str());
if (address != INADDR_NONE && address != INADDR_ANY) {
addr.s_addr = address;
return addr;
}
struct hostent* hp = ::gethostbyname(hostname.c_str());
if (hp != NULL) {
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr));
return addr;
}
LogError("Cannot find address for host %s", hostname.c_str());
addr.s_addr = INADDR_NONE;
return addr;
#else
in_addr_t address = ::inet_addr(hostname.c_str());
if (address != in_addr_t(-1)) {
addr.s_addr = address;
return addr;
}
struct hostent* hp = ::gethostbyname(hostname.c_str());
if (hp != NULL) {
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr));
return addr;
}
LogError("Cannot find address for host %s", hostname.c_str());
addr.s_addr = INADDR_NONE;
return addr;
#endif
}
bool CUDPSocket::open()
{
m_fd = ::socket(PF_INET, SOCK_DGRAM, 0);
if (m_fd < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot create the UDP socket, err: %lu", ::GetLastError());
#else
LogError("Cannot create the UDP socket, err: %d", errno);
#endif
return false;
}
if (m_port > 0U) {
sockaddr_in addr;
::memset(&addr, 0x00, sizeof(sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(m_port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (!m_address.empty()) {
#if defined(_WIN32) || defined(_WIN64)
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str());
#else
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str());
#endif
if (addr.sin_addr.s_addr == INADDR_NONE) {
LogError("The local address is invalid - %s", m_address.c_str());
return false;
}
}
int reuse = 1;
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot set the UDP socket option, err: %lu", ::GetLastError());
#else
LogError("Cannot set the UDP socket option, err: %d", errno);
#endif
return false;
}
if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot bind the UDP address, err: %lu", ::GetLastError());
#else
LogError("Cannot bind the UDP address, err: %d", errno);
#endif
return false;
}
}
return true;
}
int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port)
{
assert(buffer != NULL);
assert(length > 0U);
// Check that the readfrom() won't block
fd_set readFds;
FD_ZERO(&readFds);
#if defined(_WIN32) || defined(_WIN64)
FD_SET((unsigned int)m_fd, &readFds);
#else
FD_SET(m_fd, &readFds);
#endif
// Return immediately
timeval tv;
tv.tv_sec = 0L;
tv.tv_usec = 0L;
int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv);
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from UDP select, err: %lu", ::GetLastError());
#else
LogError("Error returned from UDP select, err: %d", errno);
#endif
return -1;
}
if (ret == 0)
return 0;
sockaddr_in addr;
#if defined(_WIN32) || defined(_WIN64)
int size = sizeof(sockaddr_in);
#else
socklen_t size = sizeof(sockaddr_in);
#endif
#if defined(_WIN32) || defined(_WIN64)
int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size);
#else
ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size);
#endif
if (len <= 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from recvfrom, err: %lu", ::GetLastError());
#else
LogError("Error returned from recvfrom, err: %d", errno);
#endif
return -1;
}
address = addr.sin_addr;
port = ntohs(addr.sin_port);
return len;
}
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port)
{
assert(buffer != NULL);
assert(length > 0U);
sockaddr_in addr;
::memset(&addr, 0x00, sizeof(sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr = address;
addr.sin_port = htons(port);
#if defined(_WIN32) || defined(_WIN64)
int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in));
#else
ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in));
#endif
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from sendto, err: %lu", ::GetLastError());
#else
LogError("Error returned from sendto, err: %d", errno);
#endif
return false;
}
#if defined(_WIN32) || defined(_WIN64)
if (ret != int(length))
return false;
#else
if (ret != ssize_t(length))
return false;
#endif
return true;
}
void CUDPSocket::close()
{
#if defined(_WIN32) || defined(_WIN64)
::closesocket(m_fd);
#else
::close(m_fd);
#endif
}

58
NXDNGateway/UDPSocket.h Normal file
View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2009-2011,2013,2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef UDPSocket_H
#define UDPSocket_H
#include <string>
#if !defined(_WIN32) && !defined(_WIN64)
#include <netdb.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#else
#include <winsock.h>
#endif
class CUDPSocket {
public:
CUDPSocket(const std::string& address, unsigned int port = 0U);
CUDPSocket(unsigned int port = 0U);
~CUDPSocket();
bool open();
int read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port);
bool write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port);
void close();
static in_addr lookup(const std::string& hostName);
private:
std::string m_address;
unsigned short m_port;
int m_fd;
};
#endif

146
NXDNGateway/Utils.cpp Normal file
View File

@ -0,0 +1,146 @@
/*
* Copyright (C) 2009,2014,2015,2016 Jonathan Naylor, G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
void CUtils::dump(const std::string& title, const unsigned char* data, unsigned int length)
{
assert(data != NULL);
dump(2U, title, data, length);
}
void CUtils::dump(int level, const std::string& title, const unsigned char* data, unsigned int length)
{
assert(data != NULL);
::Log(level, "%s", title.c_str());
unsigned int offset = 0U;
while (length > 0U) {
std::string output;
unsigned int bytes = (length > 16U) ? 16U : length;
for (unsigned i = 0U; i < bytes; i++) {
char temp[10U];
::sprintf(temp, "%02X ", data[offset + i]);
output += temp;
}
for (unsigned int i = bytes; i < 16U; i++)
output += " ";
output += " *";
for (unsigned i = 0U; i < bytes; i++) {
unsigned char c = data[offset + i];
if (::isprint(c))
output += c;
else
output += '.';
}
output += '*';
::Log(level, "%04X: %s", offset, output.c_str());
offset += 16U;
if (length >= 16U)
length -= 16U;
else
length = 0U;
}
}
void CUtils::dump(const std::string& title, const bool* bits, unsigned int length)
{
assert(bits != NULL);
dump(2U, title, bits, length);
}
void CUtils::dump(int level, const std::string& title, const bool* bits, unsigned int length)
{
assert(bits != NULL);
unsigned char bytes[100U];
unsigned int nBytes = 0U;
for (unsigned int n = 0U; n < length; n += 8U, nBytes++)
bitsToByteBE(bits + n, bytes[nBytes]);
dump(level, title, bytes, nBytes);
}
void CUtils::byteToBitsBE(unsigned char byte, bool* bits)
{
assert(bits != NULL);
bits[0U] = (byte & 0x80U) == 0x80U;
bits[1U] = (byte & 0x40U) == 0x40U;
bits[2U] = (byte & 0x20U) == 0x20U;
bits[3U] = (byte & 0x10U) == 0x10U;
bits[4U] = (byte & 0x08U) == 0x08U;
bits[5U] = (byte & 0x04U) == 0x04U;
bits[6U] = (byte & 0x02U) == 0x02U;
bits[7U] = (byte & 0x01U) == 0x01U;
}
void CUtils::byteToBitsLE(unsigned char byte, bool* bits)
{
assert(bits != NULL);
bits[0U] = (byte & 0x01U) == 0x01U;
bits[1U] = (byte & 0x02U) == 0x02U;
bits[2U] = (byte & 0x04U) == 0x04U;
bits[3U] = (byte & 0x08U) == 0x08U;
bits[4U] = (byte & 0x10U) == 0x10U;
bits[5U] = (byte & 0x20U) == 0x20U;
bits[6U] = (byte & 0x40U) == 0x40U;
bits[7U] = (byte & 0x80U) == 0x80U;
}
void CUtils::bitsToByteBE(const bool* bits, unsigned char& byte)
{
assert(bits != NULL);
byte = bits[0U] ? 0x80U : 0x00U;
byte |= bits[1U] ? 0x40U : 0x00U;
byte |= bits[2U] ? 0x20U : 0x00U;
byte |= bits[3U] ? 0x10U : 0x00U;
byte |= bits[4U] ? 0x08U : 0x00U;
byte |= bits[5U] ? 0x04U : 0x00U;
byte |= bits[6U] ? 0x02U : 0x00U;
byte |= bits[7U] ? 0x01U : 0x00U;
}
void CUtils::bitsToByteLE(const bool* bits, unsigned char& byte)
{
assert(bits != NULL);
byte = bits[0U] ? 0x01U : 0x00U;
byte |= bits[1U] ? 0x02U : 0x00U;
byte |= bits[2U] ? 0x04U : 0x00U;
byte |= bits[3U] ? 0x08U : 0x00U;
byte |= bits[4U] ? 0x10U : 0x00U;
byte |= bits[5U] ? 0x20U : 0x00U;
byte |= bits[6U] ? 0x40U : 0x00U;
byte |= bits[7U] ? 0x80U : 0x00U;
}

36
NXDNGateway/Utils.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2009,2014,2015 by Jonathan Naylor, G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef Utils_H
#define Utils_H
#include <string>
class CUtils {
public:
static void dump(const std::string& title, const unsigned char* data, unsigned int length);
static void dump(int level, const std::string& title, const unsigned char* data, unsigned int length);
static void dump(const std::string& title, const bool* bits, unsigned int length);
static void dump(int level, const std::string& title, const bool* bits, unsigned int length);
static void byteToBitsBE(unsigned char byte, bool* bits);
static void byteToBitsLE(unsigned char byte, bool* bits);
static void bitsToByteBE(const bool* bits, unsigned char& byte);
static void bitsToByteLE(const bool* bits, unsigned char& byte);
private:
};
#endif

24
NXDNGateway/Version.h Normal file
View File

@ -0,0 +1,24 @@
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20170719";
#endif

343
NXDNGateway/Voice.cpp Normal file
View File

@ -0,0 +1,343 @@
/*
* Copyright (C) 2017,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "NXDNCRC.h"
#include "Voice.h"
#include "Log.h"
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cassert>
#include <sys/stat.h>
const unsigned char HEADER[] = { 0x83U, 0x01U, 0x10U, 0x00U, 0x0FU, 0x01U, 0x00U, 0x20U };
const unsigned char TRAILER[] = { 0x83U, 0x01U, 0x10U, 0x00U, 0x0FU, 0x08U, 0x00U, 0x20U };
const unsigned char SILENCE[] = {0xACU, 0xAAU, 0x40U, 0x20U, 0x00U, 0x44U, 0x40U, 0x80U, 0x80U};
const unsigned char NXDN_FRAME_LENGTH = 33U;
const unsigned int NXDN_FRAME_TIME = 80U;
const unsigned int SILENCE_LENGTH = 9U;
const unsigned int AMBE_LENGTH = 9U;
const unsigned char BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
CVoice::CVoice(const std::string& directory, const std::string& language, unsigned int srcId) :
m_indxFile(),
m_ambeFile(),
m_srcId(srcId),
m_status(VS_NONE),
m_timer(1000U, 1U),
m_stopWatch(),
m_sent(0U),
m_ambe(NULL),
m_positions(),
m_voiceData(NULL),
m_voiceLength(0U)
{
#if defined(_WIN32) || defined(_WIN64)
m_indxFile = directory + "\\" + language + ".indx";
m_ambeFile = directory + "\\" + language + ".ambe";
#else
m_indxFile = directory + "/" + language + ".indx";
m_ambeFile = directory + "/" + language + ".ambe";
#endif
// Approximately 10 seconds worth
m_voiceData = new unsigned char[120U * NXDN_FRAME_LENGTH];
}
CVoice::~CVoice()
{
for (std::unordered_map<std::string, CPositions*>::iterator it = m_positions.begin(); it != m_positions.end(); ++it)
delete it->second;
m_positions.clear();
delete[] m_ambe;
delete[] m_voiceData;
}
bool CVoice::open()
{
FILE* fpindx = ::fopen(m_indxFile.c_str(), "rt");
if (fpindx == NULL) {
LogError("Unable to open the index file - %s", m_indxFile.c_str());
return false;
}
struct stat statStruct;
int ret = ::stat(m_ambeFile.c_str(), &statStruct);
if (ret != 0) {
LogError("Unable to stat the AMBE file - %s", m_ambeFile.c_str());
::fclose(fpindx);
return false;
}
FILE* fpambe = ::fopen(m_ambeFile.c_str(), "rb");
if (fpambe == NULL) {
LogError("Unable to open the AMBE file - %s", m_ambeFile.c_str());
::fclose(fpindx);
return false;
}
m_ambe = new unsigned char[statStruct.st_size];
size_t sizeRead = ::fread(m_ambe, 1U, statStruct.st_size, fpambe);
if (sizeRead != 0U) {
char buffer[80U];
while (::fgets(buffer, 80, fpindx) != NULL) {
char* p1 = ::strtok(buffer, "\t\r\n");
char* p2 = ::strtok(NULL, "\t\r\n");
char* p3 = ::strtok(NULL, "\t\r\n");
if (p1 != NULL && p2 != NULL && p3 != NULL) {
std::string symbol = std::string(p1);
unsigned int start = ::atoi(p2) * AMBE_LENGTH;
unsigned int length = ::atoi(p3) * AMBE_LENGTH;
CPositions* pos = new CPositions;
pos->m_start = start;
pos->m_length = length;
m_positions[symbol] = pos;
}
}
}
::fclose(fpindx);
::fclose(fpambe);
return true;
}
void CVoice::linkedTo(unsigned int tg)
{
char letters[10U];
::sprintf(letters, "%u", tg);
std::vector<std::string> words;
if (m_positions.count("linkedto") == 0U) {
words.push_back("linked");
words.push_back("2");
} else {
words.push_back("linkedto");
}
for (unsigned int i = 0U; letters[i] != 0x00U; i++)
words.push_back(std::string(1U, letters[i]));
createVoice(tg, words);
}
void CVoice::unlinked()
{
std::vector<std::string> words;
words.push_back("notlinked");
createVoice(9999U, words);
}
void CVoice::createVoice(unsigned int tg, const std::vector<std::string>& words)
{
unsigned int ambeLength = 0U;
for (std::vector<std::string>::const_iterator it = words.begin(); it != words.end(); ++it) {
if (m_positions.count(*it) > 0U) {
CPositions* position = m_positions.at(*it);
ambeLength += position->m_length;
} else {
LogWarning("Unable to find character/phrase \"%s\" in the index", (*it).c_str());
}
}
// Ensure that the AMBE is an integer number of DMR frames
if ((ambeLength % (4U * AMBE_LENGTH)) != 0U) {
unsigned int frames = ambeLength / (4U * AMBE_LENGTH);
frames++;
ambeLength = frames * (4U * AMBE_LENGTH);
}
// Add space for silence before and after the voice
ambeLength += SILENCE_LENGTH * AMBE_LENGTH;
ambeLength += SILENCE_LENGTH * AMBE_LENGTH;
unsigned char* ambeData = new unsigned char[ambeLength];
// Fill the AMBE data with silence
for (unsigned int i = 0U; i < ambeLength; i += AMBE_LENGTH)
::memcpy(ambeData + i, SILENCE, AMBE_LENGTH);
// Put offset in for silence at the beginning
unsigned int pos = SILENCE_LENGTH * AMBE_LENGTH;
for (std::vector<std::string>::const_iterator it = words.begin(); it != words.end(); ++it) {
if (m_positions.count(*it) > 0U) {
CPositions* position = m_positions.at(*it);
unsigned int start = position->m_start;
unsigned int length = position->m_length;
::memcpy(ambeData + pos, m_ambe + start, length);
pos += length;
}
}
m_voiceLength = 0U;
createHeader(true, tg);
unsigned char sacch[12U];
::memset(sacch, 0x00U, 12U);
sacch[2U] = 0x20U;
sacch[3U] = (m_srcId >> 8) & 0xFFU;
sacch[4U] = (m_srcId >> 0) & 0xFFU;
sacch[5U] = (tg >> 8) & 0xFFU;
sacch[6U] = (tg >> 0) & 0xFFU;
unsigned int n = 0U;
for (unsigned int i = 0U; i < ambeLength; i += (4U * AMBE_LENGTH)) {
unsigned char* p = ambeData + i;
unsigned char buffer[NXDN_FRAME_LENGTH];
::memset(buffer, 0x00U, NXDN_FRAME_LENGTH);
buffer[0U] = 0xAEU;
switch (n) {
case 0U: buffer[1U] = 0xC1U; break;
case 1U: buffer[1U] = 0x81U; break;
case 2U: buffer[1U] = 0x41U; break;
default: buffer[1U] = 0x01U; break;
}
for (unsigned int j = 0U; j < 18U; j++) {
bool b = READ_BIT1(sacch, j + n * 18U);
WRITE_BIT1(buffer, j + 16U, b);
}
CNXDNCRC::encodeCRC6(buffer + 1U, 26U);
::memcpy(buffer + 5U + 0U, p + 0U, 13U);
::memcpy(buffer + 5U + 14U, p + 13U, 13U);
n = (n + 1U) % 4U;
::memcpy(m_voiceData + m_voiceLength, buffer, NXDN_FRAME_LENGTH);
m_voiceLength += NXDN_FRAME_LENGTH;
}
createTrailer(true, tg);
delete[] ambeData;
m_status = VS_WAITING;
m_timer.start();
}
bool CVoice::read(unsigned char* data)
{
assert(data != NULL);
if (m_status != VS_SENDING)
return false;
unsigned int count = m_stopWatch.elapsed() / NXDN_FRAME_TIME;
if (m_sent < count) {
unsigned int offset = m_sent * NXDN_FRAME_LENGTH;
::memcpy(data, m_voiceData + offset, NXDN_FRAME_LENGTH);
m_sent++;
if (offset >= m_voiceLength) {
m_timer.stop();
m_voiceLength = 0U;
m_status = VS_NONE;
}
return true;
}
return false;
}
void CVoice::clock(unsigned int ms)
{
m_timer.clock(ms);
if (m_timer.isRunning() && m_timer.hasExpired()) {
if (m_status == VS_WAITING) {
m_stopWatch.start();
m_status = VS_SENDING;
m_sent = 0U;
}
}
}
void CVoice::createHeader(bool grp, unsigned int dstId)
{
unsigned char buffer[NXDN_FRAME_LENGTH];
::memset(buffer, 0x00U, NXDN_FRAME_LENGTH);
::memcpy(buffer, HEADER, 8U);
if (grp)
buffer[7U] = 0x20U;
buffer[8U] = (m_srcId >> 8) & 0xFFU;
buffer[9U] = (m_srcId >> 0) & 0xFFU;
buffer[10U] = (dstId >> 8) & 0xFFU;
buffer[11U] = (dstId >> 0) & 0xFFU;
CNXDNCRC::encodeCRC12(buffer + 5U, 80U);
::memcpy(buffer + 19U, buffer + 5U, 12U);
::memcpy(m_voiceData + m_voiceLength, buffer, NXDN_FRAME_LENGTH);
m_voiceLength += NXDN_FRAME_LENGTH;
}
void CVoice::createTrailer(bool grp, unsigned int dstId)
{
unsigned char buffer[NXDN_FRAME_LENGTH];
::memset(buffer, 0x00U, NXDN_FRAME_LENGTH);
::memcpy(buffer, TRAILER, 8U);
if (grp)
buffer[7U] = 0x20U;
buffer[8U] = (m_srcId >> 8) & 0xFFU;
buffer[9U] = (m_srcId >> 0) & 0xFFU;
buffer[10U] = (dstId >> 8) & 0xFFU;
buffer[11U] = (dstId >> 0) & 0xFFU;
CNXDNCRC::encodeCRC12(buffer + 5U, 80U);
::memcpy(buffer + 19U, buffer + 5U, 12U);
::memcpy(m_voiceData + m_voiceLength, buffer, NXDN_FRAME_LENGTH);
m_voiceLength += NXDN_FRAME_LENGTH;
}

72
NXDNGateway/Voice.h Normal file
View File

@ -0,0 +1,72 @@
/*
* Copyright (C) 2017 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(Voice_H)
#define Voice_H
#include "StopWatch.h"
#include "Timer.h"
#include <string>
#include <vector>
#include <unordered_map>
enum VOICE_STATUS {
VS_NONE,
VS_WAITING,
VS_SENDING
};
struct CPositions {
unsigned int m_start;
unsigned int m_length;
};
class CVoice {
public:
CVoice(const std::string& directory, const std::string& language, unsigned int srcId);
~CVoice();
bool open();
void linkedTo(unsigned int tg);
void unlinked();
bool read(unsigned char* data);
void clock(unsigned int ms);
private:
std::string m_indxFile;
std::string m_ambeFile;
unsigned int m_srcId;
VOICE_STATUS m_status;
CTimer m_timer;
CStopWatch m_stopWatch;
unsigned int m_sent;
unsigned char* m_ambe;
unsigned char* m_voiceData;
unsigned int m_voiceLength;
std::unordered_map<std::string, CPositions*> m_positions;
void createHeader(bool grp, unsigned int dstId);
void createTrailer(bool grp, unsigned int dstId);
void createVoice(unsigned int tg, const std::vector<std::string>& words);
};
#endif

18
NXDNParrot/Makefile Normal file
View File

@ -0,0 +1,18 @@
CC = gcc
CXX = g++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread
LIBS = -lpthread
LDFLAGS = -g
OBJECTS = Network.o NXDNParrot.o Parrot.o StopWatch.o Thread.o Timer.o UDPSocket.o
all: NXDNParrot
NXDNParrot: $(OBJECTS)
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o NXDNParrot
%.o: %.cpp
$(CXX) $(CFLAGS) -c -o $@ $<
clean:
$(RM) NXDNParrot *.o *.d *.bak *~

138
NXDNParrot/NXDNParrot.cpp Normal file
View File

@ -0,0 +1,138 @@
/*
* Copyright (C) 2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "StopWatch.h"
#include "NXDNParrot.h"
#include "Parrot.h"
#include "Network.h"
#include "Version.h"
#include "Thread.h"
#include "Timer.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
int main(int argc, char** argv)
{
if (argc == 1) {
::fprintf(stderr, "Usage: NXDNParrot <port>\n");
return 1;
}
unsigned int port = ::atoi(argv[1U]);
if (port == 0U) {
::fprintf(stderr, "NXDNParrot: invalid port number - %s\n", argv[1U]);
return 1;
}
CNXDNParrot parrot(port);
parrot.run();
return 0;
}
CNXDNParrot::CNXDNParrot(unsigned int port) :
m_port(port)
{
}
CNXDNParrot::~CNXDNParrot()
{
}
void CNXDNParrot::run()
{
CParrot parrot(180U);
CNetwork network(m_port);
bool ret = network.open();
if (!ret)
return;
CStopWatch stopWatch;
stopWatch.start();
CTimer watchdogTimer(1000U, 0U, 1500U);
CTimer turnaroundTimer(1000U, 2U);
CStopWatch playoutTimer;
unsigned int count = 0U;
bool playing = false;
::fprintf(stdout, "Starting NXDNParrot-%s\n", VERSION);
for (;;) {
unsigned char buffer[200U];
unsigned int len = network.read(buffer);
if (len > 0U) {
parrot.write(buffer, len);
watchdogTimer.start();
if ((buffer[9U] & 0x04U) == 0x04U) {
::fprintf(stdout, "Received end of transmission\n");
turnaroundTimer.start();
watchdogTimer.stop();
parrot.end();
}
}
if (turnaroundTimer.isRunning() && turnaroundTimer.hasExpired()) {
if (!playing) {
playoutTimer.start();
playing = true;
count = 0U;
}
// A frame every 80ms
unsigned int wanted = playoutTimer.elapsed() / 80U;
while (count < wanted) {
len = parrot.read(buffer);
if (len > 0U) {
network.write(buffer, len);
count++;
} else {
parrot.clear();
network.end();
turnaroundTimer.stop();
playing = false;
count = wanted;
}
}
}
unsigned int ms = stopWatch.elapsed();
stopWatch.start();
network.clock(ms);
watchdogTimer.clock(ms);
turnaroundTimer.clock(ms);
if (watchdogTimer.isRunning() && watchdogTimer.hasExpired()) {
turnaroundTimer.start();
watchdogTimer.stop();
parrot.end();
}
if (ms < 5U)
CThread::sleep(5U);
}
network.close();
}

34
NXDNParrot/NXDNParrot.h Normal file
View File

@ -0,0 +1,34 @@
/*
* Copyright (C) 2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(NXDNParrot_H)
#define NXDNParrot_H
class CNXDNParrot
{
public:
CNXDNParrot(unsigned int port);
~CNXDNParrot();
void run();
private:
unsigned int m_port;
};
#endif

View File

@ -0,0 +1,171 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{2AE94EAA-FD57-45C9-8555-6425CFA777A3}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>NXDNParrot</RootNamespace>
<WindowsTargetPlatformVersion>10.0.15063.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Network.h" />
<ClInclude Include="NXDNParrot.h" />
<ClInclude Include="Parrot.h" />
<ClInclude Include="RingBuffer.h" />
<ClInclude Include="StopWatch.h" />
<ClInclude Include="Thread.h" />
<ClInclude Include="Timer.h" />
<ClInclude Include="UDPSocket.h" />
<ClInclude Include="Version.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Network.cpp" />
<ClCompile Include="NXDNParrot.cpp" />
<ClCompile Include="Parrot.cpp" />
<ClCompile Include="StopWatch.cpp" />
<ClCompile Include="Thread.cpp" />
<ClCompile Include="Timer.cpp" />
<ClCompile Include="UDPSocket.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Network.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNParrot.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Parrot.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RingBuffer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="StopWatch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Timer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UDPSocket.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Version.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Thread.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Network.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNParrot.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Parrot.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="StopWatch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Timer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UDPSocket.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Thread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

103
NXDNParrot/Network.cpp Normal file
View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2009-2014,2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Network.h"
#include <cstdio>
#include <cassert>
#include <cstring>
const unsigned int BUFFER_LENGTH = 200U;
CNetwork::CNetwork(unsigned int port) :
m_socket(port),
m_address(),
m_port(0U),
m_buffer(1000U, "NXDN Network")
{
}
CNetwork::~CNetwork()
{
}
bool CNetwork::open()
{
::fprintf(stdout, "Opening NXDN network connection\n");
return m_socket.open();
}
bool CNetwork::write(const unsigned char* data, unsigned int length)
{
if (m_port == 0U)
return true;
assert(data != NULL);
return m_socket.write(data, length, m_address, m_port);
}
void CNetwork::clock(unsigned int ms)
{
unsigned char buffer[BUFFER_LENGTH];
in_addr address;
unsigned int port;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port);
if (length <= 0)
return;
m_address.s_addr = address.s_addr;
m_port = port;
if (::memcmp(buffer, "NXDNP", 5U) == 0) { // A poll
write(buffer, length);
} else if (::memcmp(buffer, "NXDND", 5U) == 0) {
unsigned char l = length;
m_buffer.addData(&l, 1U);
m_buffer.addData(buffer, length);
}
}
unsigned int CNetwork::read(unsigned char* data)
{
assert(data != NULL);
if (m_buffer.isEmpty())
return 0U;
unsigned char len = 0U;
m_buffer.getData(&len, 1U);
m_buffer.getData(data, len);
return len;
}
void CNetwork::end()
{
m_port = 0U;
}
void CNetwork::close()
{
m_socket.close();
::fprintf(stdout, "Closing NXDN network connection\n");
}

52
NXDNParrot/Network.h Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2009-2014,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef Network_H
#define Network_H
#include "RingBuffer.h"
#include "UDPSocket.h"
#include <cstdint>
#include <string>
class CNetwork {
public:
CNetwork(unsigned int port);
~CNetwork();
bool open();
bool write(const unsigned char* data, unsigned int length);
unsigned int read(unsigned char* data);
void end();
void close();
void clock(unsigned int ms);
private:
CUDPSocket m_socket;
in_addr m_address;
unsigned int m_port;
CRingBuffer<unsigned char> m_buffer;
};
#endif

81
NXDNParrot/Parrot.cpp Normal file
View File

@ -0,0 +1,81 @@
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Parrot.h"
#include <cstdio>
#include <cassert>
#include <cstring>
CParrot::CParrot(unsigned int timeout) :
m_data(NULL),
m_length(timeout * 1000U + 1000U),
m_used(0U),
m_ptr(0U)
{
assert(timeout > 0U);
m_data = new unsigned char[m_length];
}
CParrot::~CParrot()
{
delete[] m_data;
}
bool CParrot::write(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
if ((m_length - m_used) < (length + 2U))
return false;
m_data[m_used] = length;
::memcpy(m_data + m_used + 1U, data, length);
m_used += length + 1U;
return true;
}
void CParrot::end()
{
m_ptr = 0U;
}
void CParrot::clear()
{
m_used = 0U;
m_ptr = 0U;
}
unsigned int CParrot::read(unsigned char* data)
{
assert(data != NULL);
if (m_used == 0U)
return 0U;
unsigned int length = m_data[m_ptr];
::memcpy(data, m_data + m_ptr + 1U, length);
m_ptr += length + 1U;
if (m_ptr >= m_used)
m_used = 0U;
return length;
}

43
NXDNParrot/Parrot.h Normal file
View File

@ -0,0 +1,43 @@
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(Parrot_H)
#define Parrot_H
class CParrot
{
public:
CParrot(unsigned int timeout);
~CParrot();
bool write(const unsigned char* data, unsigned int length);
unsigned int read(unsigned char* data);
void end();
void clear();
private:
unsigned char* m_data;
unsigned int m_length;
unsigned int m_used;
unsigned int m_ptr;
};
#endif

147
NXDNParrot/RingBuffer.h Normal file
View File

@ -0,0 +1,147 @@
/*
* Copyright (C) 2006-2009,2012,2013,2015,2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef RingBuffer_H
#define RingBuffer_H
#include <cstdio>
#include <cassert>
#include <cstring>
template<class T> class CRingBuffer {
public:
CRingBuffer(unsigned int length, const char* name) :
m_length(length),
m_name(name),
m_buffer(NULL),
m_iPtr(0U),
m_oPtr(0U)
{
assert(length > 0U);
assert(name != NULL);
m_buffer = new T[length];
::memset(m_buffer, 0x00, m_length * sizeof(T));
}
~CRingBuffer()
{
delete[] m_buffer;
}
bool addData(const T* buffer, unsigned int nSamples)
{
if (nSamples >= freeSpace()) {
::fprintf(stderr, "**** Overflow in %s ring buffer, %u >= %u\n", m_name, nSamples, freeSpace());
return false;
}
for (unsigned int i = 0U; i < nSamples; i++) {
m_buffer[m_iPtr++] = buffer[i];
if (m_iPtr == m_length)
m_iPtr = 0U;
}
return true;
}
bool getData(T* buffer, unsigned int nSamples)
{
if (dataSize() < nSamples) {
::fprintf(stderr, "**** Underflow in %s ring buffer, %u < %u\n", m_name, dataSize(), nSamples);
return false;
}
for (unsigned int i = 0U; i < nSamples; i++) {
buffer[i] = m_buffer[m_oPtr++];
if (m_oPtr == m_length)
m_oPtr = 0U;
}
return true;
}
bool peek(T* buffer, unsigned int nSamples)
{
if (dataSize() < nSamples) {
::fprintf(stderr, "**** Underflow peek in %s ring buffer, %u < %u\n", m_name, dataSize(), nSamples);
return false;
}
unsigned int ptr = m_oPtr;
for (unsigned int i = 0U; i < nSamples; i++) {
buffer[i] = m_buffer[ptr++];
if (ptr == m_length)
ptr = 0U;
}
return true;
}
void clear()
{
m_iPtr = 0U;
m_oPtr = 0U;
::memset(m_buffer, 0x00, m_length * sizeof(T));
}
unsigned int freeSpace() const
{
if (m_oPtr == m_iPtr)
return m_length;
if (m_oPtr > m_iPtr)
return m_oPtr - m_iPtr;
return (m_length + m_oPtr) - m_iPtr;
}
unsigned int dataSize() const
{
return m_length - freeSpace();
}
bool hasSpace(unsigned int length) const
{
return freeSpace() > length;
}
bool hasData() const
{
return m_oPtr != m_iPtr;
}
bool isEmpty() const
{
return m_oPtr == m_iPtr;
}
private:
unsigned int m_length;
const char* m_name;
T* m_buffer;
unsigned int m_iPtr;
unsigned int m_oPtr;
};
#endif

84
NXDNParrot/StopWatch.cpp Normal file
View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "StopWatch.h"
#if defined(_WIN32) || defined(_WIN64)
CStopWatch::CStopWatch() :
m_frequency(),
m_start()
{
::QueryPerformanceFrequency(&m_frequency);
}
CStopWatch::~CStopWatch()
{
}
unsigned long CStopWatch::start()
{
::QueryPerformanceCounter(&m_start);
return (unsigned long)(m_start.QuadPart / m_frequency.QuadPart);
}
unsigned int CStopWatch::elapsed()
{
LARGE_INTEGER now;
::QueryPerformanceCounter(&now);
LARGE_INTEGER temp;
temp.QuadPart = (now.QuadPart - m_start.QuadPart) * 1000;
return (unsigned int)(temp.QuadPart / m_frequency.QuadPart);
}
#else
#include <cstdio>
CStopWatch::CStopWatch() :
m_start()
{
}
CStopWatch::~CStopWatch()
{
}
unsigned long CStopWatch::start()
{
::gettimeofday(&m_start, NULL);
return m_start.tv_usec;
}
unsigned int CStopWatch::elapsed()
{
struct timeval now;
::gettimeofday(&now, NULL);
unsigned int elapsed = (now.tv_sec - m_start.tv_sec) * 1000U;
elapsed += now.tv_usec / 1000U;
elapsed -= m_start.tv_usec / 1000U;
return elapsed;
}
#endif

46
NXDNParrot/StopWatch.h Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(STOPWATCH_H)
#define STOPWATCH_H
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <sys/time.h>
#endif
class CStopWatch
{
public:
CStopWatch();
~CStopWatch();
unsigned long start();
unsigned int elapsed();
private:
#if defined(_WIN32) || defined(_WIN64)
LARGE_INTEGER m_frequency;
LARGE_INTEGER m_start;
#else
struct timeval m_start;
#endif
};
#endif

101
NXDNParrot/Thread.cpp Normal file
View File

@ -0,0 +1,101 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Thread.h"
#if defined(_WIN32) || defined(_WIN64)
CThread::CThread() :
m_handle()
{
}
CThread::~CThread()
{
}
bool CThread::run()
{
m_handle = ::CreateThread(NULL, 0, &helper, this, 0, NULL);
return m_handle != NULL;
}
void CThread::wait()
{
::WaitForSingleObject(m_handle, INFINITE);
::CloseHandle(m_handle);
}
DWORD CThread::helper(LPVOID arg)
{
CThread* p = (CThread*)arg;
p->entry();
return 0UL;
}
void CThread::sleep(unsigned int ms)
{
::Sleep(ms);
}
#else
#include <unistd.h>
CThread::CThread() :
m_thread()
{
}
CThread::~CThread()
{
}
bool CThread::run()
{
return ::pthread_create(&m_thread, NULL, helper, this) == 0;
}
void CThread::wait()
{
::pthread_join(m_thread, NULL);
}
void* CThread::helper(void* arg)
{
CThread* p = (CThread*)arg;
p->entry();
return NULL;
}
void CThread::sleep(unsigned int ms)
{
::usleep(ms * 1000);
}
#endif

56
NXDNParrot/Thread.h Normal file
View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(THREAD_H)
#define THREAD_H
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <pthread.h>
#endif
class CThread
{
public:
CThread();
virtual ~CThread();
virtual bool run();
virtual void entry() = 0;
virtual void wait();
static void sleep(unsigned int ms);
private:
#if defined(_WIN32) || defined(_WIN64)
HANDLE m_handle;
#else
pthread_t m_thread;
#endif
#if defined(_WIN32) || defined(_WIN64)
static DWORD __stdcall helper(LPVOID arg);
#else
static void* helper(void* arg);
#endif
};
#endif

68
NXDNParrot/Timer.cpp Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2009,2010,2015 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Timer.h"
#include <cstdio>
#include <cassert>
CTimer::CTimer(unsigned int ticksPerSec, unsigned int secs, unsigned int msecs) :
m_ticksPerSec(ticksPerSec),
m_timeout(0U),
m_timer(0U)
{
assert(ticksPerSec > 0U);
if (secs > 0U || msecs > 0U) {
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
}
}
CTimer::~CTimer()
{
}
void CTimer::setTimeout(unsigned int secs, unsigned int msecs)
{
if (secs > 0U || msecs > 0U) {
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
} else {
m_timeout = 0U;
m_timer = 0U;
}
}
unsigned int CTimer::getTimeout() const
{
if (m_timeout == 0U)
return 0U;
return (m_timeout - 1U) / m_ticksPerSec;
}
unsigned int CTimer::getTimer() const
{
if (m_timer == 0U)
return 0U;
return (m_timer - 1U) / m_ticksPerSec;
}

89
NXDNParrot/Timer.h Normal file
View File

@ -0,0 +1,89 @@
/*
* Copyright (C) 2009,2010,2011,2014 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef Timer_H
#define Timer_H
class CTimer {
public:
CTimer(unsigned int ticksPerSec, unsigned int secs = 0U, unsigned int msecs = 0U);
~CTimer();
void setTimeout(unsigned int secs, unsigned int msecs = 0U);
unsigned int getTimeout() const;
unsigned int getTimer() const;
unsigned int getRemaining()
{
if (m_timeout == 0U || m_timer == 0U)
return 0U;
if (m_timer >= m_timeout)
return 0U;
return (m_timeout - m_timer) / m_ticksPerSec;
}
bool isRunning()
{
return m_timer > 0U;
}
void start(unsigned int secs, unsigned int msecs = 0U)
{
setTimeout(secs, msecs);
start();
}
void start()
{
if (m_timeout > 0U)
m_timer = 1U;
}
void stop()
{
m_timer = 0U;
}
bool hasExpired()
{
if (m_timeout == 0U || m_timer == 0U)
return false;
if (m_timer >= m_timeout)
return true;
return false;
}
void clock(unsigned int ticks = 1U)
{
if (m_timer > 0U && m_timeout > 0U)
m_timer += ticks;
}
private:
unsigned int m_ticksPerSec;
unsigned int m_timeout;
unsigned int m_timer;
};
#endif

263
NXDNParrot/UDPSocket.cpp Normal file
View File

@ -0,0 +1,263 @@
/*
* Copyright (C) 2006-2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "UDPSocket.h"
#include <cassert>
#if !defined(_WIN32) && !defined(_WIN64)
#include <cerrno>
#include <cstring>
#endif
CUDPSocket::CUDPSocket(const std::string& address, unsigned int port) :
m_address(address),
m_port(port),
m_fd(-1)
{
assert(!address.empty());
#if defined(_WIN32) || defined(_WIN64)
WSAData data;
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
if (wsaRet != 0)
::fprintf(stderr, "Error from WSAStartup\n");
#endif
}
CUDPSocket::CUDPSocket(unsigned int port) :
m_address(),
m_port(port),
m_fd(-1)
{
#if defined(_WIN32) || defined(_WIN64)
WSAData data;
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
if (wsaRet != 0)
::fprintf(stderr, "Error from WSAStartup\n");
#endif
}
CUDPSocket::~CUDPSocket()
{
#if defined(_WIN32) || defined(_WIN64)
::WSACleanup();
#endif
}
in_addr CUDPSocket::lookup(const std::string& hostname)
{
in_addr addr;
#if defined(_WIN32) || defined(_WIN64)
unsigned long address = ::inet_addr(hostname.c_str());
if (address != INADDR_NONE && address != INADDR_ANY) {
addr.s_addr = address;
return addr;
}
struct hostent* hp = ::gethostbyname(hostname.c_str());
if (hp != NULL) {
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr));
return addr;
}
::fprintf(stderr, "Cannot find address for host %s\n", hostname.c_str());
addr.s_addr = INADDR_NONE;
return addr;
#else
in_addr_t address = ::inet_addr(hostname.c_str());
if (address != in_addr_t(-1)) {
addr.s_addr = address;
return addr;
}
struct hostent* hp = ::gethostbyname(hostname.c_str());
if (hp != NULL) {
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr));
return addr;
}
::fprintf(stderr, "Cannot find address for host %s\n", hostname.c_str());
addr.s_addr = INADDR_NONE;
return addr;
#endif
}
bool CUDPSocket::open()
{
m_fd = ::socket(PF_INET, SOCK_DGRAM, 0);
if (m_fd < 0) {
#if defined(_WIN32) || defined(_WIN64)
::fprintf(stderr, "Cannot create the UDP socket, err: %lu\n", ::GetLastError());
#else
::fprintf(stderr, "Cannot create the UDP socket, err: %d\n", errno);
#endif
return false;
}
if (m_port > 0U) {
sockaddr_in addr;
::memset(&addr, 0x00, sizeof(sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(m_port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (!m_address.empty()) {
#if defined(_WIN32) || defined(_WIN64)
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str());
#else
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str());
#endif
if (addr.sin_addr.s_addr == INADDR_NONE) {
::fprintf(stderr, "The local address is invalid - %s\n", m_address.c_str());
return false;
}
}
int reuse = 1;
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
#if defined(_WIN32) || defined(_WIN64)
::fprintf(stderr, "Cannot set the UDP socket option, err: %lu\n", ::GetLastError());
#else
::fprintf(stderr, "Cannot set the UDP socket option, err: %d\n", errno);
#endif
return false;
}
if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) {
#if defined(_WIN32) || defined(_WIN64)
::fprintf(stderr, "Cannot bind the UDP address, err: %lu\n", ::GetLastError());
#else
::fprintf(stderr, "Cannot bind the UDP address, err: %d\n", errno);
#endif
return false;
}
::fprintf(stdout, "Opening UDP port on %u\n", m_port);
}
return true;
}
int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port)
{
assert(buffer != NULL);
assert(length > 0U);
// Check that the readfrom() won't block
fd_set readFds;
FD_ZERO(&readFds);
#if defined(_WIN32) || defined(_WIN64)
FD_SET((unsigned int)m_fd, &readFds);
#else
FD_SET(m_fd, &readFds);
#endif
// Return immediately
timeval tv;
tv.tv_sec = 0L;
tv.tv_usec = 0L;
int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv);
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
::fprintf(stderr, "Error returned from UDP select, err: %lu\n", ::GetLastError());
#else
::fprintf(stderr, "Error returned from UDP select, err: %d\n", errno);
#endif
return -1;
}
if (ret == 0)
return 0;
sockaddr_in addr;
#if defined(_WIN32) || defined(_WIN64)
int size = sizeof(sockaddr_in);
#else
socklen_t size = sizeof(sockaddr_in);
#endif
#if defined(_WIN32) || defined(_WIN64)
int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size);
#else
ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size);
#endif
if (len <= 0) {
#if defined(_WIN32) || defined(_WIN64)
::fprintf(stderr, "Error returned from recvfrom, err: %lu\n", ::GetLastError());
#else
::fprintf(stderr, "Error returned from recvfrom, err: %d\n", errno);
#endif
return -1;
}
address = addr.sin_addr;
port = ntohs(addr.sin_port);
return len;
}
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port)
{
assert(buffer != NULL);
assert(length > 0U);
sockaddr_in addr;
::memset(&addr, 0x00, sizeof(sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr = address;
addr.sin_port = htons(port);
#if defined(_WIN32) || defined(_WIN64)
int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in));
#else
ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in));
#endif
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
::fprintf(stderr, "Error returned from sendto, err: %lu\n", ::GetLastError());
#else
::fprintf(stderr, "Error returned from sendto, err: %d\n", errno);
#endif
return false;
}
#if defined(_WIN32) || defined(_WIN64)
if (ret != int(length))
return false;
#else
if (ret != ssize_t(length))
return false;
#endif
return true;
}
void CUDPSocket::close()
{
#if defined(_WIN32) || defined(_WIN64)
::closesocket(m_fd);
#else
::close(m_fd);
#endif
}

58
NXDNParrot/UDPSocket.h Normal file
View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2009-2011,2013,2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef UDPSocket_H
#define UDPSocket_H
#include <string>
#if !defined(_WIN32) && !defined(_WIN64)
#include <netdb.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#else
#include <winsock.h>
#endif
class CUDPSocket {
public:
CUDPSocket(const std::string& address, unsigned int port = 0U);
CUDPSocket(unsigned int port = 0U);
~CUDPSocket();
bool open();
int read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port);
bool write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port);
void close();
static in_addr lookup(const std::string& hostName);
private:
std::string m_address;
unsigned short m_port;
int m_fd;
};
#endif

24
NXDNParrot/Version.h Normal file
View File

@ -0,0 +1,24 @@
/*
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20180206";
#endif

191
NXDNReflector/Conf.cpp Normal file
View File

@ -0,0 +1,191 @@
/*
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Conf.h"
#include "Log.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
const int BUFFER_SIZE = 500;
enum SECTION {
SECTION_NONE,
SECTION_GENERAL,
SECTION_ID_LOOKUP,
SECTION_LOG,
SECTION_NETWORK,
SECTION_NXCORE
};
CConf::CConf(const std::string& file) :
m_file(file),
m_daemon(false),
m_lookupName(),
m_lookupTime(0U),
m_logDisplayLevel(0U),
m_logFileLevel(0U),
m_logFilePath(),
m_logFileRoot(),
m_networkPort(0U),
m_networkDebug(false),
m_nxCoreEnabled(false),
m_nxCoreAddress(),
m_nxCoreDebug(false)
{
}
CConf::~CConf()
{
}
bool CConf::read()
{
FILE* fp = ::fopen(m_file.c_str(), "rt");
if (fp == NULL) {
::fprintf(stderr, "Couldn't open the .ini file - %s\n", m_file.c_str());
return false;
}
SECTION section = SECTION_NONE;
char buffer[BUFFER_SIZE];
while (::fgets(buffer, BUFFER_SIZE, fp) != NULL) {
if (buffer[0U] == '#')
continue;
if (buffer[0U] == '[') {
if (::strncmp(buffer, "[General]", 9U) == 0)
section = SECTION_GENERAL;
else if (::strncmp(buffer, "[Id Lookup]", 11U) == 0)
section = SECTION_ID_LOOKUP;
else if (::strncmp(buffer, "[Log]", 5U) == 0)
section = SECTION_LOG;
else if (::strncmp(buffer, "[Network]", 9U) == 0)
section = SECTION_NETWORK;
else if (::strncmp(buffer, "[NXCore]", 8U) == 0)
section = SECTION_NXCORE;
else
section = SECTION_NONE;
continue;
}
char* key = ::strtok(buffer, " \t=\r\n");
if (key == NULL)
continue;
char* value = ::strtok(NULL, "\r\n");
if (section == SECTION_GENERAL) {
if (::strcmp(key, "Daemon") == 0)
m_daemon = ::atoi(value) == 1;
} else if (section == SECTION_ID_LOOKUP) {
if (::strcmp(key, "Name") == 0)
m_lookupName = value;
else if (::strcmp(key, "Time") == 0)
m_lookupTime = (unsigned int)::atoi(value);
} else if (section == SECTION_LOG) {
if (::strcmp(key, "FilePath") == 0)
m_logFilePath = value;
else if (::strcmp(key, "FileRoot") == 0)
m_logFileRoot = value;
else if (::strcmp(key, "FileLevel") == 0)
m_logFileLevel = (unsigned int)::atoi(value);
else if (::strcmp(key, "DisplayLevel") == 0)
m_logDisplayLevel = (unsigned int)::atoi(value);
} else if (section == SECTION_NETWORK) {
if (::strcmp(key, "Port") == 0)
m_networkPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_networkDebug = ::atoi(value) == 1;
} else if (section == SECTION_NXCORE) {
if (::strcmp(key, "Enabled") == 0)
m_nxCoreEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Address") == 0)
m_nxCoreAddress = value;
else if (::strcmp(key, "Debug") == 0)
m_nxCoreDebug = ::atoi(value) == 1;
}
}
::fclose(fp);
return true;
}
bool CConf::getDaemon() const
{
return m_daemon;
}
std::string CConf::getLookupName() const
{
return m_lookupName;
}
unsigned int CConf::getLookupTime() const
{
return m_lookupTime;
}
unsigned int CConf::getLogDisplayLevel() const
{
return m_logDisplayLevel;
}
unsigned int CConf::getLogFileLevel() const
{
return m_logFileLevel;
}
std::string CConf::getLogFilePath() const
{
return m_logFilePath;
}
std::string CConf::getLogFileRoot() const
{
return m_logFileRoot;
}
unsigned int CConf::getNetworkPort() const
{
return m_networkPort;
}
bool CConf::getNetworkDebug() const
{
return m_networkDebug;
}
bool CConf::getNXCoreEnabled() const
{
return m_nxCoreEnabled;
}
std::string CConf::getNXCoreAddress() const
{
return m_nxCoreAddress;
}
bool CConf::getNXCoreDebug() const
{
return m_nxCoreDebug;
}

75
NXDNReflector/Conf.h Normal file
View File

@ -0,0 +1,75 @@
/*
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(CONF_H)
#define CONF_H
#include <string>
#include <vector>
class CConf
{
public:
CConf(const std::string& file);
~CConf();
bool read();
// The General section
bool getDaemon() const;
// The Id Lookup section
std::string getLookupName() const;
unsigned int getLookupTime() const;
// The Log section
unsigned int getLogDisplayLevel() const;
unsigned int getLogFileLevel() const;
std::string getLogFilePath() const;
std::string getLogFileRoot() const;
// The Network section
unsigned int getNetworkPort() const;
bool getNetworkDebug() const;
// The NXCore section
bool getNXCoreEnabled() const;
std::string getNXCoreAddress() const;
bool getNXCoreDebug() const;
private:
std::string m_file;
bool m_daemon;
std::string m_lookupName;
unsigned int m_lookupTime;
unsigned int m_logDisplayLevel;
unsigned int m_logFileLevel;
std::string m_logFilePath;
std::string m_logFileRoot;
unsigned int m_networkPort;
bool m_networkDebug;
bool m_nxCoreEnabled;
std::string m_nxCoreAddress;
bool m_nxCoreDebug;
};
#endif

136
NXDNReflector/Log.cpp Normal file
View File

@ -0,0 +1,136 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Log.h"
#if defined(_WIN32) || defined(_WIN64)
#include <Windows.h>
#else
#include <sys/time.h>
#endif
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <ctime>
#include <cassert>
#include <cstring>
static unsigned int m_fileLevel = 2U;
static std::string m_filePath;
static std::string m_fileRoot;
static FILE* m_fpLog = NULL;
static unsigned int m_displayLevel = 2U;
static struct tm m_tm;
static char LEVELS[] = " DMIWEF";
static bool LogOpen()
{
if (m_fileLevel == 0U)
return true;
time_t now;
::time(&now);
struct tm* tm = ::gmtime(&now);
if (tm->tm_mday == m_tm.tm_mday && tm->tm_mon == m_tm.tm_mon && tm->tm_year == m_tm.tm_year) {
if (m_fpLog != NULL)
return true;
} else {
if (m_fpLog != NULL)
::fclose(m_fpLog);
}
char filename[100U];
#if defined(_WIN32) || defined(_WIN64)
::sprintf(filename, "%s\\%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
#else
::sprintf(filename, "%s/%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
#endif
m_fpLog = ::fopen(filename, "a+t");
m_tm = *tm;
return m_fpLog != NULL;
}
bool LogInitialise(const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel)
{
m_filePath = filePath;
m_fileRoot = fileRoot;
m_fileLevel = fileLevel;
m_displayLevel = displayLevel;
return ::LogOpen();
}
void LogFinalise()
{
if (m_fpLog != NULL)
::fclose(m_fpLog);
}
void Log(unsigned int level, const char* fmt, ...)
{
assert(fmt != NULL);
char buffer[300U];
#if defined(_WIN32) || defined(_WIN64)
SYSTEMTIME st;
::GetSystemTime(&st);
::sprintf(buffer, "%c: %04u-%02u-%02u %02u:%02u:%02u.%03u ", LEVELS[level], st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
#else
struct timeval now;
::gettimeofday(&now, NULL);
struct tm* tm = ::gmtime(&now.tv_sec);
::sprintf(buffer, "%c: %04d-%02d-%02d %02d:%02d:%02d.%03lu ", LEVELS[level], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000U);
#endif
va_list vl;
va_start(vl, fmt);
::vsprintf(buffer + ::strlen(buffer), fmt, vl);
va_end(vl);
if (level >= m_fileLevel && m_fileLevel != 0U) {
bool ret = ::LogOpen();
if (!ret)
return;
::fprintf(m_fpLog, "%s\n", buffer);
::fflush(m_fpLog);
}
if (level >= m_displayLevel && m_displayLevel != 0U) {
::fprintf(stdout, "%s\n", buffer);
::fflush(stdout);
}
if (level == 6U) { // Fatal
::fclose(m_fpLog);
exit(1);
}
}

36
NXDNReflector/Log.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(LOG_H)
#define LOG_H
#include <string>
#define LogDebug(fmt, ...) Log(1U, fmt, ##__VA_ARGS__)
#define LogMessage(fmt, ...) Log(2U, fmt, ##__VA_ARGS__)
#define LogInfo(fmt, ...) Log(3U, fmt, ##__VA_ARGS__)
#define LogWarning(fmt, ...) Log(4U, fmt, ##__VA_ARGS__)
#define LogError(fmt, ...) Log(5U, fmt, ##__VA_ARGS__)
#define LogFatal(fmt, ...) Log(6U, fmt, ##__VA_ARGS__)
extern void Log(unsigned int level, const char* fmt, ...);
extern bool LogInitialise(const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel);
extern void LogFinalise();
#endif

19
NXDNReflector/Makefile Normal file
View File

@ -0,0 +1,19 @@
CC = gcc
CXX = g++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread
LIBS = -lpthread
LDFLAGS = -g
OBJECTS = Conf.o Log.o Mutex.o NXCoreNetwork.o NXDNLookup.o NXDNNetwork.o NXDNReflector.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o
all: NXDNReflector
NXDNReflector: $(OBJECTS)
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o NXDNReflector
%.o: %.cpp
$(CXX) $(CFLAGS) -c -o $@ $<
clean:
$(RM) NXDNReflector *.o *.d *.bak *~

65
NXDNReflector/Mutex.cpp Normal file
View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Mutex.h"
#if defined(_WIN32) || defined(_WIN64)
CMutex::CMutex() :
m_handle()
{
m_handle = ::CreateMutex(NULL, FALSE, NULL);
}
CMutex::~CMutex()
{
::CloseHandle(m_handle);
}
void CMutex::lock()
{
::WaitForSingleObject(m_handle, INFINITE);
}
void CMutex::unlock()
{
::ReleaseMutex(m_handle);
}
#else
CMutex::CMutex() :
m_mutex(PTHREAD_MUTEX_INITIALIZER)
{
}
CMutex::~CMutex()
{
}
void CMutex::lock()
{
::pthread_mutex_lock(&m_mutex);
}
void CMutex::unlock()
{
::pthread_mutex_unlock(&m_mutex);
}
#endif

45
NXDNReflector/Mutex.h Normal file
View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(MUTEX_H)
#define MUTEX_H
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <pthread.h>
#endif
class CMutex
{
public:
CMutex();
~CMutex();
void lock();
void unlock();
private:
#if defined(_WIN32) || defined(_WIN64)
HANDLE m_handle;
#else
pthread_mutex_t m_mutex;
#endif
};
#endif

View File

@ -0,0 +1,130 @@
/*
* Copyright (C) 2009-2014,2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "NXCoreNetwork.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
const unsigned int BUFFER_LENGTH = 200U;
const unsigned int NXCORE_PORT = 41300U;
CNXCoreNetwork::CNXCoreNetwork(const std::string& address, bool debug) :
m_socket("", NXCORE_PORT),
m_address(),
m_debug(debug),
m_buffer(1000U, "NXCore Network")
{
assert(!address.empty());
m_address = CUDPSocket::lookup(address);
}
CNXCoreNetwork::~CNXCoreNetwork()
{
}
bool CNXCoreNetwork::open()
{
LogMessage("Opening NXCore network connection");
if (m_address.s_addr == INADDR_NONE)
return false;
return m_socket.open();
}
bool CNXCoreNetwork::write(const unsigned char* data, unsigned int len)
{
assert(data != NULL);
unsigned char buffer[110U];
::memset(buffer, 0x00U, 110U);
buffer[0U] = 'I';
buffer[1U] = 'C';
buffer[2U] = 'O';
buffer[3U] = 'M';
buffer[4U] = 0x01U;
buffer[5U] = 0x01U;
buffer[6U] = 0x08U;
buffer[7U] = 0xE0U;
buffer[37U] = 0x23U;
buffer[38U] = (data[9U] & 0x0CU) != 0x00U ? 0x1CU : 0x10U;
buffer[39U] = 0x21U;
::memcpy(buffer + 40U, data + 10U, 33U);
if (m_debug)
CUtils::dump(1U, "NXCore Network Data Sent", buffer, 102U);
return m_socket.write(buffer, 102U, m_address, NXCORE_PORT);
}
void CNXCoreNetwork::clock(unsigned int ms)
{
unsigned char buffer[BUFFER_LENGTH];
in_addr address;
unsigned int port;
int length = m_socket.read(buffer, BUFFER_LENGTH, address, port);
if (length <= 0)
return;
// Check if the data is for us
if (m_address.s_addr != address.s_addr || port != NXCORE_PORT) {
LogMessage("NXCore packet received from an invalid source, %08X != %08X and/or %u != %u", m_address.s_addr, address.s_addr, NXCORE_PORT, port);
return;
}
// Invalid packet type?
if (::memcmp(buffer, "ICOM", 4U) != 0)
return;
if (length != 102)
return;
if (m_debug)
CUtils::dump(1U, "NXCore Network Data Received", buffer, length);
m_buffer.addData(buffer + 40U, 33U);
}
bool CNXCoreNetwork::read(unsigned char* data, unsigned int len)
{
assert(data != NULL);
if (m_buffer.isEmpty())
return false;
m_buffer.getData(data, 33U);
return true;
}
void CNXCoreNetwork::close()
{
m_socket.close();
LogMessage("Closing NXCore network connection");
}

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2009-2014,2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef NXCoreNetwork_H
#define NXCoreNetwork_H
#include "RingBuffer.h"
#include "UDPSocket.h"
#include "Timer.h"
#include <cstdint>
#include <string>
class CNXCoreNetwork {
public:
CNXCoreNetwork(const std::string& address, bool debug);
~CNXCoreNetwork();
bool open();
bool write(const unsigned char* data, unsigned int len);
bool read(unsigned char* data, unsigned int len);
void close();
void clock(unsigned int ms);
private:
CUDPSocket m_socket;
in_addr m_address;
bool m_debug;
CRingBuffer<unsigned char> m_buffer;
};
#endif

405
NXDNReflector/NXDN.csv Normal file
View File

@ -0,0 +1,405 @@
UID,Call,Name,Location,Notes
2,W2FLY/M,Harry,Southern NJ,UHF NX-800 mobile
3,WB2OOM/M,Tina,Southern NJ,UHF NX-800 Mobile
4,W2FLY/M,Harry,Southern NJ,UHF NX-800 Van
7,F1PRY,Emmanuel,BEAUVAIS FR,
8,W2FLY/P,Harry,Southern NJ,UHF NX-820 Port 2
9,KE8BGA,Lowell Katz,"Cleveland, Ohio","on the north shore, NX-800"
17,KC2SNI,Jim Hannon,"West Berlin, New Jersey",My Radio is an Icom IC-3161DT
25,WB2RUH/P,Bruce,Southern NJ,UHF NX-320
26,WB2RUH/M,Bruce,Southern NJ,UHF NX-800 mobile
30,KD4MOJ,Doug,,Doug
74,N2IXC,Ed,Chatsworth NJ,
76,W2FLY/P,Harry,Southern NJ,UFH NX5300 Port 1
77,W2FLY/P,Harry,"Somers Point, NJ",UHF NX-800 Shore Base
78,W2FLY,Harry,"Mullica Hill, NJ",UHF NX-800
79,W2FLY/M,Harry,Southern NJ,UHF NX-5800
80,W2FLY/M,Harry,Southern NJ,VHF NX-5700 mobile
82,W2FLY/P,Harry,"Somers Point, NJ",VHF NX-700 Shore Base
85,W2FLY/M,Harry,Southern NJ,VHF NX_700 van
86,W2FLY,Harry,"Mullica Hill, NJ",VHF NX-700 base
87,W2FLY/M,Harry,Southern NJ,VHF NX-700 mobile
88,W2FLY/P,Harry,Southern NJ,VHF NX-220 portable
89,WB2RUH,Bruce,Vineland NJ,VHF NX-700 base
99,K1ZSG,Don,,Mobile
134,N2SRO,Mike,Pitman,Mobile Radio
134,N2SRO,Mike,NJ,
141,KF2M,Greg Popovich,"Mt Laurel, NJ",IC-F4161DT
401,W1KFR,Bill,,Bill
901,K1IFF,Cliff,CT,Cliff NX320
902,K1IFF,Cliff,CT,Cliff NX320 - demo
903,K1IFF,Cliff,CT,Cliff NX800H
905,WA1LMV,Rick,,Rick NX320
906,K1IFF,Cliff,CT,Cliff NX200
907,K1IFF,Cliff,CT,Future
908,W4CLL,Chuck,,CHUCK
909,AB1UB V,Woody,"Bristol, CT",
909,AB1UB,Woody,"Bristol, CT",
909,AB1UB,Woody,,Woody NX300
909,W4CCL,Chuck,,CHUCK
910,W4CLL,Chuck,,CHUCK
911,W4CLL,Chuck,,CHUCK
912,W4CCL,Chuck,,CHUCK
920,N1XDN,Bob,CT,Bob P1 UHF NX300
921,N1XDN,Bob,CT,Bob P1 VHF NX220
922,N1XDN,Bob,CT,Bob P2 UHF NX300
923,N1XDN,Bob,CT,Bob M1 VHF NX700
924,N1XDN,Bob,CT,Bob P3 UHF NX-5300
925,N1XDN,Bob,CT,Bob P2 VHF NX-5200
926,N1XDN,Bob,CT,Bob M1 UHF NX-5800
928,N1XDN,Bob,CT,Icom portable
930,K1IFF,Cliff,CT,NX300
931,K1IFF,Cliff,CT,NX300
936,W1GPO,John,,NX300
951,K1KGQ,Joel,,Joel NX800H
952,K1KGQ,Joel,CT,Truck radio
952,K1GML,Gail,,Gail NX800H
953,K1KGQ,Joel,,Joel NX320-1
954,K1KGQ,Joel,,
955,K1KGQ,Joel,,
956,K1KGQ,Joel,,
957,K1KGQ,Joel,,
958,K1KGQ,Joel,,Joel F4161
959,K1KGQ,Joel,,Future
960,K1ZXX,Gary,,Gary - Icom All radios
961,WA1SSB,Joe,,Joe NX800H
962,N1MAT,Dennis,,Dennis F4161
963,N1MAT,Dennis,,Dennis F4161
970,KB1VRI,Nick,CT,
970,KB1VRI,Nick,,Nick
971,N1ELE,Paul,CT,
972,N1ODJ,Kenny Schmitz,Middletown,
973,W1VLF,Paul,CT,
980,W1RHS,Rick,Connecticut,
995,K1IFF/Base,Cliff,"Brsitol, CT",NXR710 link radio
1001,KE4GWW,James,AL,NX200 Portable #1
1002,KE4GWW,James,AL,NX200 Portable #2
1003,KE4GWW,James,AL,NX300 Portable #1
1004,KE4GWW,James,AL,NX300 Portable #2
1005,KE4GWW,James,AL,NX700 Base
1006,KE4GWW,James,AL,NX800 Base
1007,KE4GWW,James M. Nelson,"Dothan, AL",NX700 Mobile#1
1008,DK6PX,Stefan,Germany nr Bad Toelz,Coming up FR6000
1008,KE4GWW,James,AL,NX700 Mobile#2
1009,KE4GWW,James,AL,NX800 Mobile#1
1010,KE4GWW,James,AL,NX800 Mobile#2
1066,KM4JXP,Peter Tasker,Longboat Key,NX5300
1954,W4BPT,BILLY TAYLOR,"RINGGOLD,GA.",
1956,KC7SDD,Dana Hanford,"Bainbridge Island, WA","Member BARC, W7NPC.org"
1963,N5JRN,David Barts,"Bainbridge Island, WA","Handheld, Icom 4161"
1966,ZS6IIX,Henry,Petit South Africa,
1997,KC1AJR,Giovanni,East Hampton CT,kenwood NX800 K2
3070,W4ORL,Ralph,,Ralph - Mobile
3071,W4LOV,Mike,,Mike - NX800
3072,N4JTK,John,,John - NX800
3074,W4MCA,Michael,,Michael - NX300
3075,W4LOV,Mike,,Mike - NX800
3079,NN4TT,Dave,Orlando,NX300
3079,W4ORL,Ralph,,Ralph - Portable
3081,W4MCA,Michael,,Michael - NX800
3082,W4LOV,Mike,,Mike - Portable
3083,KD4TWJ,Dean,,Dean - Mobile NX800
3271,N4KEG,Richard,,RICHARD - Mobile and or ht's N4KEG (UHF)
3274,KD4EFM,Evans,FL,
3275,KD4EFM,Evans,FL,
3278,KD4EFM,Evans,FL,
3279,N4KEG,Richard,,
3280,KD4EFM,Evans,"Lakeland, Florida",work radio
3280,KD4EFM,Evans,FL,Evans Mobile(s)
3280,KD4EFM,Evans,FL,
3281,N4KEG,Richard,,
3450,K0KAD,CHAD TAYLOR,"SPOKANE VALLEY, WA",My Portable
3451,K0KAD,CHAD TAYLOR,"SPOKANE VALLEY, WA",My Base Station
3452,K0KAD,CHAD TAYLOR,"SPOKANE VALLEY, WA",Mobile Radio
4020,K4XXX,Ed,"London, KY",NX820 Base
4802,hb3yrb,Alex,Verbier,nx5300
4804,hb9fmf,Didier,Rougemont,NX5300
5001,N5QZ,Ryan,AR,"N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-820"
5002,N5QZ,Ryan,AR,"N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-720"
5003,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-820"
5004,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-720"
5005,AC5AV,Larry,AR,"AC5AV, Larry Sicks, Searcy, AR"
5006,AC5AV,Larry,AR,"AC5AV, Larry Sicks, Searcy, AR"
5007,N5LKE,James,AR,"N5LKE, James Ferguson, Searcy, AR - Kenwood NX-800"
5008,AF5WN,Mason,AR,"AF5WN, Mason Creager, Cabot, AR - Kenwood NX-700H"
5009,KJ5SF,Stan,AR,"KJ5SF, Stan Rongey, Searcy, AR - Kenwood NX-800"
5100,K5SRS,Michael Smith,"Fayetteville, AR",NX-5800 Mobile
5101,KC5YQB,Paul Blair,"Fayetteville, AR",
5125,AE5OQ,Armstead,"Higden, AR",
5125,AE5OQ,Armstead,AR,entered by k1iff
5134,AE5OQ,Armstead,AR,"AE5OQ, Armstead M Feland, IV, Higdon, AR - Kenwood NX-200"
5150,WY6NN,Doug,"Los Angeles, CA",NX-300/5300
5151,KC6HFJ,Tamara,"Los Angeles, CA",NX-300
5170,K5WMZ,Gary,AR,"K5WMZ, Gary D Partlow, Ward, AR - Kenwood NX-700"
5599,W1ZM,Ryan,,"W1ZM, Ryan Nelson, NX-5300"
5987,W5ZN,Joel,AR,"W5ZN, Joel Harrison, Judsonia, AR - Kenwood NX-800"
6430,K4GFD,Norm,FL,Norm Greensboro Fla
6431,K4GFD,Norm,,
6432,K4GFD,Norm,,
6439,N4NKV,George,,George
6801,hb9vsd,relais de verbier,verbier,
6802,HB9YRB,Alex,Verbier,
6804,HB9FMF,Didier,Rougemont,
7737,N4NKV,George,,George
9834,VA7NY,PJ,,PJ
12002,W4KJP,Kevin,,KEVIN
12005,KD4TWJ,Dean,,Dean - Portable IC-F4161
12006,W4MO,Stewart,,STEWART NX300 / 320
12007,W4MO,Stewart,,STEWART NX800
12010,kd4dwp,Ben,Orlando,
12013,K4NBC,Miguel Orama,"Palm Bay, Florida",Icom F4146DS UHF Portable
12014,K4NBC,Miguel Orama,"Palm Bay, Florida",Kenwood NX200 VHF HT
12015,K4NBC,K4NBC-Miguel UHF Mobile,"Palm Bay, Florida",Future UHF Mobile
12016,K4NBC,Miguel,"Palm Bay, Florida",M2 Icom F6061D
12017,N4JFZ,,,
12021,W4PJT,Paul,,Paul
12023,KD4NWL,John,,JOHN
12127,W4KDM,Rick,,Rick - Portable NX300
12136,WA4KWK,John,,John F6121
12200,NB9X,Paul,FL,
12201,NB9X,Paul,FL,PAUL
12202,NB9X,Paul,FL,
12203,NB9X,Paul,FL,
12204,WX3C,Juan Arias,Florida,Orlando metro
12204,NB9X,Paul,FL,
12210,N4APG,Bill,,Bill Pfost
12211,N4APG,Bill,,Bill Pfost
12212,N4APG,Bill,,Bill Pfost
12213,N4APG,Bill,,Bill Pfost
12214,N4APG,Bill,,Bill Pfost
12215,WA4ISB,Ed,,ED Mobile
12216,WA4ISB,Ed,,
12220,N4PK,Paul,,PAUK K.
12221,N4PK,Paul,,
12222,W4PJT,Paul,,
12223,W4PJT,Paul,,
12226,KI4SWY,William,,
12230,KQ4KX,Richard,,Richard Sharp
12231,KQ4KX,Richard,,
12234,KD4TWJ,Dean,EL98,
12235,N1IC,Nick,,Nic
12236,N1IC,Nick,,
12240,KR4X,Larry,,
12241,KR4X,Larry,,
12245,KD4ACG,Jason,"Hudson, FL",Icom Mobile
12245,KD4ACG,Jason,,JASON
12246,KD4ACG,Jason,"Hudson, FL",Icom Portable
12246,KD4ACG,Jason,,JASON
12247,K2MCI,,,
12250,KE4GYX,,,
12272,KE4OSL,,,
12273,KE4OSL,,,
12374,KF4I,Thom,,Thom Base
12375,KF4I,Thom,,Thom Mobile
12523,KM4JVE,Ana,,Ana - IC-F4161
12577,N2DLX,Richard,,Rich Dunajewski NX-5800
12604,K4CBN,Greg,,GREG
12605,K4CBN,Greg,,
12606,K4CBN,Greg,,
12607,K4CBN,Greg,,
12608,K4CBN,Greg,,
12666,KI4SWY,William,,William Stillwel ( All Radios )
12691,KE3WDW,Sam,,Sam
12780,KC4YUA,Brett,,BRETT
13105,W7QO,Alan,,
13106,W7QO,Alan,,
13107,W7QO,Alan,,
13121,W4CML,Chuck,,
13122,W4CML,Chuck,,
13125,KD4APP,Don,,Don - NX300
13126,KD4APP,Don,,Don - F6061D
13127,KD4APP,Don,,Don - NX200
13131,W5JR,Mike,,
13132,W5JR,Mike,,
13401,W1KFR,Bill,,Bill
13815,KG4BKO,Bill,GA,nx320
14020,K4XXX,Ed,"London, KY",NX5300
14021,K4XXX,Ed,"London, KY",NX5200
15001,N5QZ,Ryan,AR,"N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-800H (Vehicle 1)"
15002,N5QZ,Ryan,AR,"N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-700 (Vehicle 1)"
15003,N5QZ,Ryan,AR,"N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-800 (Vehicle 2)"
15004,N5QZ,Ryan,AR,"N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-700 (Vehicle 2)"
15005,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-800 (Vehicle 1)"
15006,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-700 (Vehicle 1)"
15007,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-800 (Vehicle 2)"
15008,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-700 (Vehicle 2)"
15009,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-800 (Vehicle 3)"
15010,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-700 (Vehicle 3)"
15011,N5QT,Dawn,AR,"N5QT, Dawn Gray, Searcy, AR - Kenwood NX-800"
15012,AC5AV,Larry,AR,"AC5AV, Larry Sicks, Searcy, AR - Kenwood NX-800"
15013,AC5AV,Larry,AR,"AC5AV, Larry Sicks, Searcy, AR - Kenwood NX-700"
15014,N5QT,Dawn,AR,"N5QT, Dawn Gray, Searcy, AR - Kenwood NX-700"
15015,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR Motorcycle Mobile"
15016,KG5KS,Kenny,,"KG5KS, Kenny Thompson - Kenwood NX-700HK"
15017,KG5KS,Kenny,,"KG5KS, Kenny Thompson - Kenwood NX-800HK"
15018,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR ATV Mobile"
15019,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR ATV Mobile"
15020,WA8UBL,Allen,AR,"WA8UBL, Allen Herrick, Beebe, AR, Kenwood NX-700"
15021,KD5HRT,Heath,AR,"KD5HRT, Heath Taylor, McRae, AR, Kenwood NX-800"
15022,WA8UBL,Allen,AR,"WA8UBL, Allen Herrick, Beebe, AR - Kenwood NX-800"
15023,N5ZA,Joel,AR,"N5ZA, Joe Belew, Beebe, AR - Kenwood NX-700"
15024,KF5TPF,Ryan,AR,"KF5TPF, Ryan Nelson, Edgemont, AR NX-700"
15025,KE5YZP,Ryan,AR,"KE5YZP, Ryan Schwarck, Batesville, AR NX-700"
15026,AF5OD,Landon,AR,"AF5OD, Landon McCord, Searcy, AR"
15027,KB5RFF,Scott,AR,"KB5RFF, Scott Gray, Searcy, AR - Kenwood NX-800"
17002,KC9GMX,Stephen,,Stephen - Base F6121D
17004,KC9GMX,Stephen,,Stephen - F6061D
17005,KC9NPJ,Jarrett,,Jarrett F6121D
17006,KC9GMX,Stephen,,Stephen - F4161DS
17007,KC9NPJ,Jarrett,,Jarrett F4231DS
17008,KC9RHH,Jesse,,F4101D
17009,KC9PHK,Michael,,F4061DS
17011,N9BRG,Dan,,Dan kenwood nx800k2
17855,AG6RN,Demian,CA,NX-210
21007,WA1LMV,Rick,,Rick
21014,K2BUI,Eric,,Eric
24020,K4XXX,Ed,"London, KY",NX5800
24021,K4XXX,Ed,"London, KY",NX5700
25001,N5QZ,Ryan,AR,"N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-300"
25002,N5QZ,Ryan,AR,"N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-200"
25003,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-300"
25004,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-200"
25005,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-320"
25006,N5QS,Roger,AR,"N5QS, Roger Gray, Searcy, AR - Kenwood NX-340U"
25007,N5QT,Dawn,AR,"N5QT, Dawn Gray, Searcy, AR - Kenwood NX-300"
25008,N5QT,Dawn,AR,"N5QT, Dawn Gray, Searcy, AR - Kenwood NX-200"
25009,AC5AV,Larry,AR,"AC5AV, Larry Sicks, Searcy, AR - Kenwood NX-300"
25010,KD5OOW,Tom,AR,"KD5OOW, Tom McGee, Searcy, AR - Kenwood NX-300"
25011,W5ZN,Joel,AR,"W5ZN, Joel Harrison, Judsonia, AR - Kenwood NX-300"
25012,KD5HRT,Heath,AR,"KD5HRT, Heath Taylor, McRae, AR - Kenwood NX-300"
25013,KK5WA,Darin,AR,"KK5WA, Darin Dykes, Beebe, AR - Kenwood NX-320"
25014,N5LKE,James,AR,"N5LKE, James Ferguson, Searcy, AR - Kenwood NX-5300"
25015,KJ5ORD,John,AR,"KJ5ORD, John Ord, Searcy, AR - Kenwood NX-300"
25016,KB5RFF,Scott,AR,"KB5RFF, Scott Gray, Searcy, AR - Kenwood NX-300"
25017,KB5ZUH,Todd,AR,"KB5ZUH, Todd Williams, Searcy, AR - Kenwood NX-320"
25018,KB5ZUH,Todd,AR,"KB5ZUH, Todd Williams, Searcy, AR - Kenwood NX-340"
25019,KB5ZUH,Todd,AR,"KB5ZUH, Todd Williams, Searcy, AR - Kenwood NX-340"
25020,KB5ZUH,Todd,AR,"KB5ZUH, Todd Williams, Searcy, AR - Kenwood NX-320"
25021,KE5UZU,Raymond Prince,"England, AR",Kenwood Handheld
25021,AF5OD,Landon,AR,"AF5OD, Landon McCord, Searcy, AR"
25022,KE5UZU,Raymond Prince,"England, AR",Icom Handheld
25022,KE5YZP,Ryan,AR,"KE5YZP, Ryan A Schwarck, Batesville, AR - Icom"
25023,KE5YZP,Ryan,AR,"KE5YZP, Ryan A Schwarck, Batesville, AR - Icom"
25024,KG5CHM,Colt,AR,"KG5CHM, Colt Boyd, Searcy, AR - Kenwood NX-300"
25025,KJ5ORD,John,AR,"KJ5ORD, John Ord, Searcy, AR - Kenwood NX-xxx VHF"
25026,WA8UBL,Allen,AR,"WA8UBL, Allen Herrick, Beebe, AR - Kenwood NX-320"
25027,KF5TPF,Ryan,AR,"KF5TPF, Ryan Nelson, Edgemont, AR - Kenwood NX-200"
25028,WA8UBL,Allen,AR,"WA8UBL, Allen Herrick, Beebe, AR - Kenwood NX-220"
25029,KF5WHX,Trey,AR,"KF5WHX, Trey Ferguson, Searcy, AR - Kenwood NX-320"
25030,AC5AV,Larry,AR,"AC5AV, Larry Sicks, Searcy, AR"
25031,KJ5SF,Stan,AR,"KJ5SF, Stan Rongey, Searcy, AR - Kenwood NX-340"
25032,KC5DFH,Kirk,AR,"KC5DFH, Kirk Williams, Searcy, AR - Kenwood NX-340"
25033,AF5OD,Landon,AR,"AF5OD, Landon McCord, Searcy, AR, Icom F4161DS"
25034,KF5TPF,Ryan,AR,"KF5TPF, Ryan Nelson, Edgemont, AR - ICOM 4161"
25035,KG5BMB,Glenda,AR,"KG5BMB, Glenda McCord, Searcy, AR, Icom F4161DS"
25039,KC1JET,Jim,,JIM (BASE)
25068,N1QD,Joe,,
25069,N1COP,Bob,,Bob
25070,WD1L,John,,John
25125,N1TI,Tim,"Mattapoisett, MA",
25125,N1TI,Tim,"Mattapoisett, MA",
25144,W1WCF,Walter,,Walter
25221,N0XIA,James,,James - Kenwood Mobile and Portable
25222,KE4SDC,Ron,,Ron - Portable NX300
25246,WG1U,Ken,"Assonet, MA",
25333,W1AKN,Jack,,Jack Mobile
25390,KC1JET,Jim,,JIM (MOBILE)
25390,KC1JET,Jim,,JIM
25444,W1TAV,Steve,,Steve
25555,WA1MNQ,Mike,,Mike
25582,N1KXJ,Ray,"E. Bridgewater, MA.",Port.
25582,N1KXJ,Ray Wall,East Bridgewater,
25585,N1AVA,Ken Howland,"DARTMOUTH,MA",
25700,NN1D,Tony Souza,"Swansea, MA",
25740,WG1U,Kenny,,KEN
25743,WG1U,Kenny,,KEN
25746,N1OTY,John,,JOHN
25777,W1BON,Bump,,Bump
25830,KB1CHU,Steve,MA,
25863,N1ZZN,Jeff,,JEFF
25874,KB1KVD,Jason,,Jason - Icom Mob & Port
25888,K1WGU,Bob,,Bob
25889,AB1CQ,Gary,,Gary
25900,N1ZZR,Matt,,Matt - mobile
25901,N1MRC,Matt,"Bridgewater, MA",N1MRC P-1
25901,N1ZZR,Matt,,Matt
25957,KC1HO,Steve,,STEVE
27101,KI4SWB,Mark,"Melbourne Beach, FL",Icom Portable
27102,KP4OO,Carlos,"Palm Bay, FL",Icom Portable
27201,KI4SWB,Mark,"Melbourne Beach, FL",Icom Mobile
27202,KP4OO,Carlos,"Palm Bay, FL",Icom Mobile
28001,K3KRS,rYAN,CLEVLAND,OHIO
30505,KG6MQE,Jim,MT,
30571,WX4RCF,Ryan F.,"Tampa, FL",
31117,K4QHR,Pete,,Pete
31124,KM4JXP,Peter,,NX5300
31146,KD2KWD,Michael Santamaria,"Brandon, FL",Kenwood
33000,N1PA-R,Paul,NH,PAUL - NEW HAMPSHIRE REPEATER
33001,N1PA,Paul,NH,PAUL - NEW HAMPSHIRE
33002,N1PA,Paul,NH,PAUL - NEW HAMPSHIRE
34001,N2WNS,Bill,NJ,N2WNS Portable
34002,N2WNS,Bill,NJ,N2WNS Base
36001,W2CCR,Chris,NY,"Chris, Galway, NY NX300"
36002,KC2VOB,Asad,NY,"Asad, NYC, NX-5800"
36003,KC2VOB,Asad,NY,"Asad, NYC, NX-300GK"
36134,N2SRO,Mike,"Pitman, NJ",Portable
37001,KA4YMY,Steve,NC,"Steve, Charlotte, NC NX320"
37009,KA4YMY,Steve,"Charlotte, NC",
37010,KA4YMY,Steve,"Charlotte, NC",
37010,KA4YMY,Steve,"Charlotte, NC",
40024,N5YEI,Jeff Dalrymple,"Jay, Oklahoma",NX-5800 Mobile
40124,N5YEI,Jeff Dalrymple,"Jay, Oklahoma",NX-5300 Portable
43751,N4IRS,Steve,,Steve
44001,K2BUI,Eric,RI,
44002,K2BUI,Eric,"Providence, RI",
44007,W2DAN,Dave,,Dave - NX700
44298,N1JBC,Jed,,JED
49101,WX7Y-1,Bret Mills,Castle Dale Utah,WX7y-1 Hand Held 1
49102,WX7Y-2,Bret Mills,"Caslte Dale, Utah",WX7Y-2 Hand held
49104,WX7Y-4,Bret Mills,"Castle Dale, Utah",WX7Y-4 Mobile
49106,WX7Y-6,Bret Mills,Castle Dale,WX7Y-6 Mobile
55700,WB9HKE,Rick,WI,
55704,WB9HKE,Rick,WI,
57000,VE3SP,Andre,"Toronto, ON",mobile
57001,VE3SP,Andre,"Toronto, ON",handheld
57001,VE3EI,Eric,,Eric - Portable
57002,VE3OKZ,Janusz,"Toronto, ON",mobile
57002,VE3EI,Eric,,Eric - Dongle
57003,VE3OKZ,Janusz,"Toronto, ON",handheld
57004,VE3CCD,Curtis,"Scarborough, ON",handheld
57005,VE3NBI,Anoop,"Scarborough, ON",handheld
57006,VE3JLU,Sherwin,"Scarborough, ON",handheld
57007,va3rq,Jon,"Oakville, ON",handheld
57008,ve3ogb,Randy,"Toronto, ON",handheld
57009,va3mk,Mark,"Oakville, ON",handheld
57010,va3mk,Mark,"Oakville, ON",mobile
57011,VA3WZW,Andre,"Durham, ON",mobile
57012,VA3WZW,Andre,"Durham, ON",mobile
57013,VA3AGV,cottage,"Toronto, ON",mobile
57014,VE3BWP,Brian,"Caledon, ON",handheld
57015,VE3HY,Frank,"Caledon, ON",handheld
57016,VE3UBI,Paul,"Scarborough, ON",mobile
57017,VE3UBI,Paul,"Scarborough, ON",handheld
57018,VE3RZR,Richard,"Toronto, ON",handheld
57019,VE3AEP,Dom,"Toronto, ON",mobile
57020,VA3PEO,Adrian,"Toronto, ON",handheld
57021,va3wjo,Walter,"Toronto, ON",handheld
57022,ve3fkn,Tom,"Stoney Creek, ON",handheld
57023,ve3ips,John,"Toronto, ON",handheld
57024,VA3CQA,Brian,"Scarborough, ON",handheld
57025,VA3PAD,Andrew,"Scarborough, ON",mobile
57026,VA3PAD,Andrew,"Scarborough, ON",handheld
57027,VA3VAD,Arpad,"Hamilton, ON",handheld
57028,VA3KY,Shelly,"Thornhill, ON",mobile
57029,VA3KY,Shelly,"Thornhill, ON",handheld
57030,VE3KFQ,Doug,"Toronto, ON",mobile
57031,VE3KFQ,Doug,"Toronto, ON",handheld
57032,VE3AEP,Dom 2,"Toronto, ON",handheld
57033,VE3DJZ,Huey,"Hamilton, ON",mobile
57034,VE3DJZ,Huey,"Hamilton, ON",handheld
57035,VA3RQ,Jon,Oakville ON,Mobile
3106418,N5ICK,Nicholas Nixon,"Rialto, Ca",
3112205,N2HUC,Phil Roberts,"Port St. Lucie, FL",DV4MINI AMBE voice
3118365,NA9VY,Chris Gilbert,"New Palestine, IN",
3118366,N9UMJ,Rick Nicholson,Buddha Indiana,
3142058,N3BAH,L. Abraham Smith,Southwestern Pennsylvania,
1 UID Call Name Location Notes
2 2 W2FLY/M Harry Southern NJ UHF NX-800 mobile
3 3 WB2OOM/M Tina Southern NJ UHF NX-800 Mobile
4 4 W2FLY/M Harry Southern NJ UHF NX-800 Van
5 7 F1PRY Emmanuel BEAUVAIS FR
6 8 W2FLY/P Harry Southern NJ UHF NX-820 Port 2
7 9 KE8BGA Lowell Katz Cleveland, Ohio on the north shore, NX-800
8 17 KC2SNI Jim Hannon West Berlin, New Jersey My Radio is an Icom IC-3161DT
9 25 WB2RUH/P Bruce Southern NJ UHF NX-320
10 26 WB2RUH/M Bruce Southern NJ UHF NX-800 mobile
11 30 KD4MOJ Doug Doug
12 74 N2IXC Ed Chatsworth NJ
13 76 W2FLY/P Harry Southern NJ UFH NX5300 Port 1
14 77 W2FLY/P Harry Somers Point, NJ UHF NX-800 Shore Base
15 78 W2FLY Harry Mullica Hill, NJ UHF NX-800
16 79 W2FLY/M Harry Southern NJ UHF NX-5800
17 80 W2FLY/M Harry Southern NJ VHF NX-5700 mobile
18 82 W2FLY/P Harry Somers Point, NJ VHF NX-700 Shore Base
19 85 W2FLY/M Harry Southern NJ VHF NX_700 van
20 86 W2FLY Harry Mullica Hill, NJ VHF NX-700 base
21 87 W2FLY/M Harry Southern NJ VHF NX-700 mobile
22 88 W2FLY/P Harry Southern NJ VHF NX-220 portable
23 89 WB2RUH Bruce Vineland NJ VHF NX-700 base
24 99 K1ZSG Don Mobile
25 134 N2SRO Mike Pitman Mobile Radio
26 134 N2SRO Mike NJ
27 141 KF2M Greg Popovich Mt Laurel, NJ IC-F4161DT
28 401 W1KFR Bill Bill
29 901 K1IFF Cliff CT Cliff NX320
30 902 K1IFF Cliff CT Cliff NX320 - demo
31 903 K1IFF Cliff CT Cliff NX800H
32 905 WA1LMV Rick Rick NX320
33 906 K1IFF Cliff CT Cliff NX200
34 907 K1IFF Cliff CT Future
35 908 W4CLL Chuck CHUCK
36 909 AB1UB V Woody Bristol, CT
37 909 AB1UB Woody Bristol, CT
38 909 AB1UB Woody Woody NX300
39 909 W4CCL Chuck CHUCK
40 910 W4CLL Chuck CHUCK
41 911 W4CLL Chuck CHUCK
42 912 W4CCL Chuck CHUCK
43 920 N1XDN Bob CT Bob P1 UHF NX300
44 921 N1XDN Bob CT Bob P1 VHF NX220
45 922 N1XDN Bob CT Bob P2 UHF NX300
46 923 N1XDN Bob CT Bob M1 VHF NX700
47 924 N1XDN Bob CT Bob P3 UHF NX-5300
48 925 N1XDN Bob CT Bob P2 VHF NX-5200
49 926 N1XDN Bob CT Bob M1 UHF NX-5800
50 928 N1XDN Bob CT Icom portable
51 930 K1IFF Cliff CT NX300
52 931 K1IFF Cliff CT NX300
53 936 W1GPO John NX300
54 951 K1KGQ Joel Joel NX800H
55 952 K1KGQ Joel CT Truck radio
56 952 K1GML Gail Gail NX800H
57 953 K1KGQ Joel Joel NX320-1
58 954 K1KGQ Joel
59 955 K1KGQ Joel
60 956 K1KGQ Joel
61 957 K1KGQ Joel
62 958 K1KGQ Joel Joel F4161
63 959 K1KGQ Joel Future
64 960 K1ZXX Gary Gary - Icom All radios
65 961 WA1SSB Joe Joe NX800H
66 962 N1MAT Dennis Dennis F4161
67 963 N1MAT Dennis Dennis F4161
68 970 KB1VRI Nick CT
69 970 KB1VRI Nick Nick
70 971 N1ELE Paul CT
71 972 N1ODJ Kenny Schmitz Middletown
72 973 W1VLF Paul CT
73 980 W1RHS Rick Connecticut
74 995 K1IFF/Base Cliff Brsitol, CT NXR710 link radio
75 1001 KE4GWW James AL NX200 Portable #1
76 1002 KE4GWW James AL NX200 Portable #2
77 1003 KE4GWW James AL NX300 Portable #1
78 1004 KE4GWW James AL NX300 Portable #2
79 1005 KE4GWW James AL NX700 Base
80 1006 KE4GWW James AL NX800 Base
81 1007 KE4GWW James M. Nelson Dothan, AL NX700 Mobile#1
82 1008 DK6PX Stefan Germany nr Bad Toelz Coming up FR6000
83 1008 KE4GWW James AL NX700 Mobile#2
84 1009 KE4GWW James AL NX800 Mobile#1
85 1010 KE4GWW James AL NX800 Mobile#2
86 1066 KM4JXP Peter Tasker Longboat Key NX5300
87 1954 W4BPT BILLY TAYLOR RINGGOLD,GA.
88 1956 KC7SDD Dana Hanford Bainbridge Island, WA Member BARC, W7NPC.org
89 1963 N5JRN David Barts Bainbridge Island, WA Handheld, Icom 4161
90 1966 ZS6IIX Henry Petit South Africa
91 1997 KC1AJR Giovanni East Hampton CT kenwood NX800 K2
92 3070 W4ORL Ralph Ralph - Mobile
93 3071 W4LOV Mike Mike - NX800
94 3072 N4JTK John John - NX800
95 3074 W4MCA Michael Michael - NX300
96 3075 W4LOV Mike Mike - NX800
97 3079 NN4TT Dave Orlando NX300
98 3079 W4ORL Ralph Ralph - Portable
99 3081 W4MCA Michael Michael - NX800
100 3082 W4LOV Mike Mike - Portable
101 3083 KD4TWJ Dean Dean - Mobile NX800
102 3271 N4KEG Richard RICHARD - Mobile and or ht's N4KEG (UHF)
103 3274 KD4EFM Evans FL
104 3275 KD4EFM Evans FL
105 3278 KD4EFM Evans FL
106 3279 N4KEG Richard
107 3280 KD4EFM Evans Lakeland, Florida work radio
108 3280 KD4EFM Evans FL Evans Mobile(s)
109 3280 KD4EFM Evans FL
110 3281 N4KEG Richard
111 3450 K0KAD CHAD TAYLOR SPOKANE VALLEY, WA My Portable
112 3451 K0KAD CHAD TAYLOR SPOKANE VALLEY, WA My Base Station
113 3452 K0KAD CHAD TAYLOR SPOKANE VALLEY, WA Mobile Radio
114 4020 K4XXX Ed London, KY NX820 Base
115 4802 hb3yrb Alex Verbier nx5300
116 4804 hb9fmf Didier Rougemont NX5300
117 5001 N5QZ Ryan AR N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-820
118 5002 N5QZ Ryan AR N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-720
119 5003 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-820
120 5004 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-720
121 5005 AC5AV Larry AR AC5AV, Larry Sicks, Searcy, AR
122 5006 AC5AV Larry AR AC5AV, Larry Sicks, Searcy, AR
123 5007 N5LKE James AR N5LKE, James Ferguson, Searcy, AR - Kenwood NX-800
124 5008 AF5WN Mason AR AF5WN, Mason Creager, Cabot, AR - Kenwood NX-700H
125 5009 KJ5SF Stan AR KJ5SF, Stan Rongey, Searcy, AR - Kenwood NX-800
126 5100 K5SRS Michael Smith Fayetteville, AR NX-5800 Mobile
127 5101 KC5YQB Paul Blair Fayetteville, AR
128 5125 AE5OQ Armstead Higden, AR
129 5125 AE5OQ Armstead AR entered by k1iff
130 5134 AE5OQ Armstead AR AE5OQ, Armstead M Feland, IV, Higdon, AR - Kenwood NX-200
131 5150 WY6NN Doug Los Angeles, CA NX-300/5300
132 5151 KC6HFJ Tamara Los Angeles, CA NX-300
133 5170 K5WMZ Gary AR K5WMZ, Gary D Partlow, Ward, AR - Kenwood NX-700
134 5599 W1ZM Ryan W1ZM, Ryan Nelson, NX-5300
135 5987 W5ZN Joel AR W5ZN, Joel Harrison, Judsonia, AR - Kenwood NX-800
136 6430 K4GFD Norm FL Norm Greensboro Fla
137 6431 K4GFD Norm
138 6432 K4GFD Norm
139 6439 N4NKV George George
140 6801 hb9vsd relais de verbier verbier
141 6802 HB9YRB Alex Verbier
142 6804 HB9FMF Didier Rougemont
143 7737 N4NKV George George
144 9834 VA7NY PJ PJ
145 12002 W4KJP Kevin KEVIN
146 12005 KD4TWJ Dean Dean - Portable IC-F4161
147 12006 W4MO Stewart STEWART NX300 / 320
148 12007 W4MO Stewart STEWART NX800
149 12010 kd4dwp Ben Orlando
150 12013 K4NBC Miguel Orama Palm Bay, Florida Icom F4146DS UHF Portable
151 12014 K4NBC Miguel Orama Palm Bay, Florida Kenwood NX200 VHF HT
152 12015 K4NBC K4NBC-Miguel UHF Mobile Palm Bay, Florida Future UHF Mobile
153 12016 K4NBC Miguel Palm Bay, Florida M2 Icom F6061D
154 12017 N4JFZ
155 12021 W4PJT Paul Paul
156 12023 KD4NWL John JOHN
157 12127 W4KDM Rick Rick - Portable NX300
158 12136 WA4KWK John John F6121
159 12200 NB9X Paul FL
160 12201 NB9X Paul FL PAUL
161 12202 NB9X Paul FL
162 12203 NB9X Paul FL
163 12204 WX3C Juan Arias Florida Orlando metro
164 12204 NB9X Paul FL
165 12210 N4APG Bill Bill Pfost
166 12211 N4APG Bill Bill Pfost
167 12212 N4APG Bill Bill Pfost
168 12213 N4APG Bill Bill Pfost
169 12214 N4APG Bill Bill Pfost
170 12215 WA4ISB Ed ED Mobile
171 12216 WA4ISB Ed
172 12220 N4PK Paul PAUK K.
173 12221 N4PK Paul
174 12222 W4PJT Paul
175 12223 W4PJT Paul
176 12226 KI4SWY William
177 12230 KQ4KX Richard Richard Sharp
178 12231 KQ4KX Richard
179 12234 KD4TWJ Dean EL98
180 12235 N1IC Nick Nic
181 12236 N1IC Nick
182 12240 KR4X Larry
183 12241 KR4X Larry
184 12245 KD4ACG Jason Hudson, FL Icom Mobile
185 12245 KD4ACG Jason JASON
186 12246 KD4ACG Jason Hudson, FL Icom Portable
187 12246 KD4ACG Jason JASON
188 12247 K2MCI
189 12250 KE4GYX
190 12272 KE4OSL
191 12273 KE4OSL
192 12374 KF4I Thom Thom Base
193 12375 KF4I Thom Thom Mobile
194 12523 KM4JVE Ana Ana - IC-F4161
195 12577 N2DLX Richard Rich Dunajewski NX-5800
196 12604 K4CBN Greg GREG
197 12605 K4CBN Greg
198 12606 K4CBN Greg
199 12607 K4CBN Greg
200 12608 K4CBN Greg
201 12666 KI4SWY William William Stillwel ( All Radios )
202 12691 KE3WDW Sam Sam
203 12780 KC4YUA Brett BRETT
204 13105 W7QO Alan
205 13106 W7QO Alan
206 13107 W7QO Alan
207 13121 W4CML Chuck
208 13122 W4CML Chuck
209 13125 KD4APP Don Don - NX300
210 13126 KD4APP Don Don - F6061D
211 13127 KD4APP Don Don - NX200
212 13131 W5JR Mike
213 13132 W5JR Mike
214 13401 W1KFR Bill Bill
215 13815 KG4BKO Bill GA nx320
216 14020 K4XXX Ed London, KY NX5300
217 14021 K4XXX Ed London, KY NX5200
218 15001 N5QZ Ryan AR N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-800H (Vehicle 1)
219 15002 N5QZ Ryan AR N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-700 (Vehicle 1)
220 15003 N5QZ Ryan AR N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-800 (Vehicle 2)
221 15004 N5QZ Ryan AR N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-700 (Vehicle 2)
222 15005 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-800 (Vehicle 1)
223 15006 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-700 (Vehicle 1)
224 15007 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-800 (Vehicle 2)
225 15008 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-700 (Vehicle 2)
226 15009 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-800 (Vehicle 3)
227 15010 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-700 (Vehicle 3)
228 15011 N5QT Dawn AR N5QT, Dawn Gray, Searcy, AR - Kenwood NX-800
229 15012 AC5AV Larry AR AC5AV, Larry Sicks, Searcy, AR - Kenwood NX-800
230 15013 AC5AV Larry AR AC5AV, Larry Sicks, Searcy, AR - Kenwood NX-700
231 15014 N5QT Dawn AR N5QT, Dawn Gray, Searcy, AR - Kenwood NX-700
232 15015 N5QS Roger AR N5QS, Roger Gray, Searcy, AR Motorcycle Mobile
233 15016 KG5KS Kenny KG5KS, Kenny Thompson - Kenwood NX-700HK
234 15017 KG5KS Kenny KG5KS, Kenny Thompson - Kenwood NX-800HK
235 15018 N5QS Roger AR N5QS, Roger Gray, Searcy, AR ATV Mobile
236 15019 N5QS Roger AR N5QS, Roger Gray, Searcy, AR ATV Mobile
237 15020 WA8UBL Allen AR WA8UBL, Allen Herrick, Beebe, AR, Kenwood NX-700
238 15021 KD5HRT Heath AR KD5HRT, Heath Taylor, McRae, AR, Kenwood NX-800
239 15022 WA8UBL Allen AR WA8UBL, Allen Herrick, Beebe, AR - Kenwood NX-800
240 15023 N5ZA Joel AR N5ZA, Joe Belew, Beebe, AR - Kenwood NX-700
241 15024 KF5TPF Ryan AR KF5TPF, Ryan Nelson, Edgemont, AR NX-700
242 15025 KE5YZP Ryan AR KE5YZP, Ryan Schwarck, Batesville, AR NX-700
243 15026 AF5OD Landon AR AF5OD, Landon McCord, Searcy, AR
244 15027 KB5RFF Scott AR KB5RFF, Scott Gray, Searcy, AR - Kenwood NX-800
245 17002 KC9GMX Stephen Stephen - Base F6121D
246 17004 KC9GMX Stephen Stephen - F6061D
247 17005 KC9NPJ Jarrett Jarrett F6121D
248 17006 KC9GMX Stephen Stephen - F4161DS
249 17007 KC9NPJ Jarrett Jarrett F4231DS
250 17008 KC9RHH Jesse F4101D
251 17009 KC9PHK Michael F4061DS
252 17011 N9BRG Dan Dan kenwood nx800k2
253 17855 AG6RN Demian CA NX-210
254 21007 WA1LMV Rick Rick
255 21014 K2BUI Eric Eric
256 24020 K4XXX Ed London, KY NX5800
257 24021 K4XXX Ed London, KY NX5700
258 25001 N5QZ Ryan AR N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-300
259 25002 N5QZ Ryan AR N5QZ, Ryan McAfee, Searcy, AR - Kenwood NX-200
260 25003 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-300
261 25004 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-200
262 25005 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-320
263 25006 N5QS Roger AR N5QS, Roger Gray, Searcy, AR - Kenwood NX-340U
264 25007 N5QT Dawn AR N5QT, Dawn Gray, Searcy, AR - Kenwood NX-300
265 25008 N5QT Dawn AR N5QT, Dawn Gray, Searcy, AR - Kenwood NX-200
266 25009 AC5AV Larry AR AC5AV, Larry Sicks, Searcy, AR - Kenwood NX-300
267 25010 KD5OOW Tom AR KD5OOW, Tom McGee, Searcy, AR - Kenwood NX-300
268 25011 W5ZN Joel AR W5ZN, Joel Harrison, Judsonia, AR - Kenwood NX-300
269 25012 KD5HRT Heath AR KD5HRT, Heath Taylor, McRae, AR - Kenwood NX-300
270 25013 KK5WA Darin AR KK5WA, Darin Dykes, Beebe, AR - Kenwood NX-320
271 25014 N5LKE James AR N5LKE, James Ferguson, Searcy, AR - Kenwood NX-5300
272 25015 KJ5ORD John AR KJ5ORD, John Ord, Searcy, AR - Kenwood NX-300
273 25016 KB5RFF Scott AR KB5RFF, Scott Gray, Searcy, AR - Kenwood NX-300
274 25017 KB5ZUH Todd AR KB5ZUH, Todd Williams, Searcy, AR - Kenwood NX-320
275 25018 KB5ZUH Todd AR KB5ZUH, Todd Williams, Searcy, AR - Kenwood NX-340
276 25019 KB5ZUH Todd AR KB5ZUH, Todd Williams, Searcy, AR - Kenwood NX-340
277 25020 KB5ZUH Todd AR KB5ZUH, Todd Williams, Searcy, AR - Kenwood NX-320
278 25021 KE5UZU Raymond Prince England, AR Kenwood Handheld
279 25021 AF5OD Landon AR AF5OD, Landon McCord, Searcy, AR
280 25022 KE5UZU Raymond Prince England, AR Icom Handheld
281 25022 KE5YZP Ryan AR KE5YZP, Ryan A Schwarck, Batesville, AR - Icom
282 25023 KE5YZP Ryan AR KE5YZP, Ryan A Schwarck, Batesville, AR - Icom
283 25024 KG5CHM Colt AR KG5CHM, Colt Boyd, Searcy, AR - Kenwood NX-300
284 25025 KJ5ORD John AR KJ5ORD, John Ord, Searcy, AR - Kenwood NX-xxx VHF
285 25026 WA8UBL Allen AR WA8UBL, Allen Herrick, Beebe, AR - Kenwood NX-320
286 25027 KF5TPF Ryan AR KF5TPF, Ryan Nelson, Edgemont, AR - Kenwood NX-200
287 25028 WA8UBL Allen AR WA8UBL, Allen Herrick, Beebe, AR - Kenwood NX-220
288 25029 KF5WHX Trey AR KF5WHX, Trey Ferguson, Searcy, AR - Kenwood NX-320
289 25030 AC5AV Larry AR AC5AV, Larry Sicks, Searcy, AR
290 25031 KJ5SF Stan AR KJ5SF, Stan Rongey, Searcy, AR - Kenwood NX-340
291 25032 KC5DFH Kirk AR KC5DFH, Kirk Williams, Searcy, AR - Kenwood NX-340
292 25033 AF5OD Landon AR AF5OD, Landon McCord, Searcy, AR, Icom F4161DS
293 25034 KF5TPF Ryan AR KF5TPF, Ryan Nelson, Edgemont, AR - ICOM 4161
294 25035 KG5BMB Glenda AR KG5BMB, Glenda McCord, Searcy, AR, Icom F4161DS
295 25039 KC1JET Jim JIM (BASE)
296 25068 N1QD Joe
297 25069 N1COP Bob Bob
298 25070 WD1L John John
299 25125 N1TI Tim Mattapoisett, MA
300 25125 N1TI Tim Mattapoisett, MA
301 25144 W1WCF Walter Walter
302 25221 N0XIA James James - Kenwood Mobile and Portable
303 25222 KE4SDC Ron Ron - Portable NX300
304 25246 WG1U Ken Assonet, MA
305 25333 W1AKN Jack Jack Mobile
306 25390 KC1JET Jim JIM (MOBILE)
307 25390 KC1JET Jim JIM
308 25444 W1TAV Steve Steve
309 25555 WA1MNQ Mike Mike
310 25582 N1KXJ Ray E. Bridgewater, MA. Port.
311 25582 N1KXJ Ray Wall East Bridgewater
312 25585 N1AVA Ken Howland DARTMOUTH,MA
313 25700 NN1D Tony Souza Swansea, MA
314 25740 WG1U Kenny KEN
315 25743 WG1U Kenny KEN
316 25746 N1OTY John JOHN
317 25777 W1BON Bump Bump
318 25830 KB1CHU Steve MA
319 25863 N1ZZN Jeff JEFF
320 25874 KB1KVD Jason Jason - Icom Mob & Port
321 25888 K1WGU Bob Bob
322 25889 AB1CQ Gary Gary
323 25900 N1ZZR Matt Matt - mobile
324 25901 N1MRC Matt Bridgewater, MA N1MRC P-1
325 25901 N1ZZR Matt Matt
326 25957 KC1HO Steve STEVE
327 27101 KI4SWB Mark Melbourne Beach, FL Icom Portable
328 27102 KP4OO Carlos Palm Bay, FL Icom Portable
329 27201 KI4SWB Mark Melbourne Beach, FL Icom Mobile
330 27202 KP4OO Carlos Palm Bay, FL Icom Mobile
331 28001 K3KRS rYAN CLEVLAND OHIO
332 30505 KG6MQE Jim MT
333 30571 WX4RCF Ryan F. Tampa, FL
334 31117 K4QHR Pete Pete
335 31124 KM4JXP Peter NX5300
336 31146 KD2KWD Michael Santamaria Brandon, FL Kenwood
337 33000 N1PA-R Paul NH PAUL - NEW HAMPSHIRE REPEATER
338 33001 N1PA Paul NH PAUL - NEW HAMPSHIRE
339 33002 N1PA Paul NH PAUL - NEW HAMPSHIRE
340 34001 N2WNS Bill NJ N2WNS Portable
341 34002 N2WNS Bill NJ N2WNS Base
342 36001 W2CCR Chris NY Chris, Galway, NY NX300
343 36002 KC2VOB Asad NY Asad, NYC, NX-5800
344 36003 KC2VOB Asad NY Asad, NYC, NX-300GK
345 36134 N2SRO Mike Pitman, NJ Portable
346 37001 KA4YMY Steve NC Steve, Charlotte, NC NX320
347 37009 KA4YMY Steve Charlotte, NC
348 37010 KA4YMY Steve Charlotte, NC
349 37010 KA4YMY Steve Charlotte, NC
350 40024 N5YEI Jeff Dalrymple Jay, Oklahoma NX-5800 Mobile
351 40124 N5YEI Jeff Dalrymple Jay, Oklahoma NX-5300 Portable
352 43751 N4IRS Steve Steve
353 44001 K2BUI Eric RI
354 44002 K2BUI Eric Providence, RI
355 44007 W2DAN Dave Dave - NX700
356 44298 N1JBC Jed JED
357 49101 WX7Y-1 Bret Mills Castle Dale Utah WX7y-1 Hand Held 1
358 49102 WX7Y-2 Bret Mills Caslte Dale, Utah WX7Y-2 Hand held
359 49104 WX7Y-4 Bret Mills Castle Dale, Utah WX7Y-4 Mobile
360 49106 WX7Y-6 Bret Mills Castle Dale WX7Y-6 Mobile
361 55700 WB9HKE Rick WI
362 55704 WB9HKE Rick WI
363 57000 VE3SP Andre Toronto, ON mobile
364 57001 VE3SP Andre Toronto, ON handheld
365 57001 VE3EI Eric Eric - Portable
366 57002 VE3OKZ Janusz Toronto, ON mobile
367 57002 VE3EI Eric Eric - Dongle
368 57003 VE3OKZ Janusz Toronto, ON handheld
369 57004 VE3CCD Curtis Scarborough, ON handheld
370 57005 VE3NBI Anoop Scarborough, ON handheld
371 57006 VE3JLU Sherwin Scarborough, ON handheld
372 57007 va3rq Jon Oakville, ON handheld
373 57008 ve3ogb Randy Toronto, ON handheld
374 57009 va3mk Mark Oakville, ON handheld
375 57010 va3mk Mark Oakville, ON mobile
376 57011 VA3WZW Andre Durham, ON mobile
377 57012 VA3WZW Andre Durham, ON mobile
378 57013 VA3AGV cottage Toronto, ON mobile
379 57014 VE3BWP Brian Caledon, ON handheld
380 57015 VE3HY Frank Caledon, ON handheld
381 57016 VE3UBI Paul Scarborough, ON mobile
382 57017 VE3UBI Paul Scarborough, ON handheld
383 57018 VE3RZR Richard Toronto, ON handheld
384 57019 VE3AEP Dom Toronto, ON mobile
385 57020 VA3PEO Adrian Toronto, ON handheld
386 57021 va3wjo Walter Toronto, ON handheld
387 57022 ve3fkn Tom Stoney Creek, ON handheld
388 57023 ve3ips John Toronto, ON handheld
389 57024 VA3CQA Brian Scarborough, ON handheld
390 57025 VA3PAD Andrew Scarborough, ON mobile
391 57026 VA3PAD Andrew Scarborough, ON handheld
392 57027 VA3VAD Arpad Hamilton, ON handheld
393 57028 VA3KY Shelly Thornhill, ON mobile
394 57029 VA3KY Shelly Thornhill, ON handheld
395 57030 VE3KFQ Doug Toronto, ON mobile
396 57031 VE3KFQ Doug Toronto, ON handheld
397 57032 VE3AEP Dom 2 Toronto, ON handheld
398 57033 VE3DJZ Huey Hamilton, ON mobile
399 57034 VE3DJZ Huey Hamilton, ON handheld
400 57035 VA3RQ Jon Oakville ON Mobile
401 3106418 N5ICK Nicholas Nixon Rialto, Ca
402 3112205 N2HUC Phil Roberts Port St. Lucie, FL DV4MINI AMBE voice
403 3118365 NA9VY Chris Gilbert New Palestine, IN
404 3118366 N9UMJ Rick Nicholson Buddha Indiana
405 3142058 N3BAH L. Abraham Smith Southwestern Pennsylvania

View File

@ -0,0 +1,160 @@
/*
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "NXDNLookup.h"
#include "Timer.h"
#include "Log.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
CNXDNLookup::CNXDNLookup(const std::string& filename, unsigned int reloadTime) :
CThread(),
m_filename(filename),
m_reloadTime(reloadTime),
m_table(),
m_mutex(),
m_stop(false)
{
}
CNXDNLookup::~CNXDNLookup()
{
}
bool CNXDNLookup::read()
{
bool ret = load();
if (m_reloadTime > 0U)
run();
return ret;
}
void CNXDNLookup::entry()
{
LogInfo("Started the NXDN Id lookup reload thread");
CTimer timer(1U, 3600U * m_reloadTime);
timer.start();
while (!m_stop) {
sleep(1000U);
timer.clock();
if (timer.hasExpired()) {
load();
timer.start();
}
}
LogInfo("Stopped the NXDN Id lookup reload thread");
}
void CNXDNLookup::stop()
{
if (m_reloadTime == 0U) {
delete this;
return;
}
m_stop = true;
wait();
}
std::string CNXDNLookup::find(unsigned int id)
{
std::string callsign;
if (id == 0xFFFFU)
return std::string("ALL");
m_mutex.lock();
try {
callsign = m_table.at(id);
} catch (...) {
char text[10U];
::sprintf(text, "%u", id);
callsign = std::string(text);
}
m_mutex.unlock();
return callsign;
}
bool CNXDNLookup::exists(unsigned int id)
{
m_mutex.lock();
bool found = m_table.count(id) == 1U;
m_mutex.unlock();
return found;
}
bool CNXDNLookup::load()
{
FILE* fp = ::fopen(m_filename.c_str(), "rt");
if (fp == NULL) {
LogWarning("Cannot open the NXDN Id lookup file - %s", m_filename.c_str());
return false;
}
m_mutex.lock();
// Remove the old entries
m_table.clear();
char buffer[100U];
while (::fgets(buffer, 100U, fp) != NULL) {
if (buffer[0U] == '#')
continue;
char* p1 = ::strtok(buffer, ",\t\r\n");
char* p2 = ::strtok(NULL, ",\t\r\n");
if (p1 != NULL && p2 != NULL) {
unsigned int id = (unsigned int)::atoi(p1);
if (id > 0U) {
for (char* p = p2; *p != 0x00U; p++)
*p = ::toupper(*p);
m_table[id] = std::string(p2);
}
}
}
m_mutex.unlock();
::fclose(fp);
size_t size = m_table.size();
if (size == 0U)
return false;
LogInfo("Loaded %u Ids to the NXDN callsign lookup table", size);
return true;
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef NXDNLookup_H
#define NXDNLookup_H
#include "Thread.h"
#include "Mutex.h"
#include <string>
#include <unordered_map>
class CNXDNLookup : public CThread {
public:
CNXDNLookup(const std::string& filename, unsigned int reloadTime);
virtual ~CNXDNLookup();
bool read();
virtual void entry();
std::string find(unsigned int id);
bool exists(unsigned int id);
void stop();
private:
std::string m_filename;
unsigned int m_reloadTime;
std::unordered_map<unsigned int, std::string> m_table;
CMutex m_mutex;
bool m_stop;
bool load();
};
#endif

View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2009-2014,2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "NXDNNetwork.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
CNXDNNetwork::CNXDNNetwork(unsigned int port, bool debug) :
m_socket(port),
m_debug(debug)
{
}
CNXDNNetwork::~CNXDNNetwork()
{
}
bool CNXDNNetwork::open()
{
LogInfo("Opening NXDN network connection");
return m_socket.open();
}
bool CNXDNNetwork::write(const unsigned char* data, unsigned int length, const in_addr& address, unsigned int port)
{
assert(data != NULL);
assert(length > 0U);
assert(port > 0U);
if (m_debug)
CUtils::dump(1U, "NXDN Network Data Sent", data, length);
return m_socket.write(data, length, address, port);
}
unsigned int CNXDNNetwork::read(unsigned char* data, unsigned int length, in_addr& address, unsigned int& port)
{
assert(data != NULL);
assert(length > 0U);
int len = m_socket.read(data, length, address, port);
if (len <= 0)
return 0U;
if (m_debug)
CUtils::dump(1U, "NXDN Network Data Received", data, len);
return len;
}
void CNXDNNetwork::close()
{
m_socket.close();
LogInfo("Closing NXDN network connection");
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2009-2014,2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef NXDNNetwork_H
#define NXDNNetwork_H
#include "UDPSocket.h"
#include <cstdint>
#include <string>
class CNXDNNetwork {
public:
CNXDNNetwork(unsigned int port, bool debug);
~CNXDNNetwork();
bool open();
bool write(const unsigned char* data, unsigned int length, const in_addr& address, unsigned int port);
unsigned int read(unsigned char* data, unsigned int length, in_addr& address, unsigned int& port);
void close();
private:
CUDPSocket m_socket;
bool m_debug;
};
#endif

View File

@ -0,0 +1,396 @@
/*
* Copyright (C) 2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "NXCoreNetwork.h"
#include "NXDNReflector.h"
#include "NXDNNetwork.h"
#include "NXDNLookup.h"
#include "StopWatch.h"
#include "Version.h"
#include "Thread.h"
#include "Utils.h"
#include "Log.h"
#if defined(_WIN32) || defined(_WIN64)
#include <Windows.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <pwd.h>
#endif
#if defined(_WIN32) || defined(_WIN64)
const char* DEFAULT_INI_FILE = "NXDNReflector.ini";
#else
const char* DEFAULT_INI_FILE = "/etc/NXDNReflector.ini";
#endif
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <ctime>
#include <cstring>
#include <algorithm>
int main(int argc, char** argv)
{
const char* iniFile = DEFAULT_INI_FILE;
if (argc > 1) {
for (int currentArg = 1; currentArg < argc; ++currentArg) {
std::string arg = argv[currentArg];
if ((arg == "-v") || (arg == "--version")) {
::fprintf(stdout, "NXDNReflector version %s\n", VERSION);
return 0;
} else if (arg.substr(0, 1) == "-") {
::fprintf(stderr, "Usage: NXDNReflector [-v|--version] [filename]\n");
return 1;
} else {
iniFile = argv[currentArg];
}
}
}
CNXDNReflector* reflector = new CNXDNReflector(std::string(iniFile));
reflector->run();
delete reflector;
return 0;
}
CNXDNReflector::CNXDNReflector(const std::string& file) :
m_conf(file),
m_repeaters()
{
}
CNXDNReflector::~CNXDNReflector()
{
}
void CNXDNReflector::run()
{
bool ret = m_conf.read();
if (!ret) {
::fprintf(stderr, "NXDNReflector: cannot read the .ini file\n");
return;
}
ret = ::LogInitialise(m_conf.getLogFilePath(), m_conf.getLogFileRoot(), m_conf.getLogFileLevel(), m_conf.getLogDisplayLevel());
if (!ret) {
::fprintf(stderr, "NXDNReflector: unable to open the log file\n");
return;
}
#if !defined(_WIN32) && !defined(_WIN64)
bool m_daemon = m_conf.getDaemon();
if (m_daemon) {
// Create new process
pid_t pid = ::fork();
if (pid == -1) {
::LogWarning("Couldn't fork() , exiting");
return;
}
else if (pid != 0)
exit(EXIT_SUCCESS);
// Create new session and process group
if (::setsid() == -1) {
::LogWarning("Couldn't setsid(), exiting");
return;
}
// Set the working directory to the root directory
if (::chdir("/") == -1) {
::LogWarning("Couldn't cd /, exiting");
return;
}
::close(STDIN_FILENO);
::close(STDOUT_FILENO);
::close(STDERR_FILENO);
//If we are currently root...
if (getuid() == 0) {
struct passwd* user = ::getpwnam("mmdvm");
if (user == NULL) {
::LogError("Could not get the mmdvm user, exiting");
return;
}
uid_t mmdvm_uid = user->pw_uid;
gid_t mmdvm_gid = user->pw_gid;
//Set user and group ID's to mmdvm:mmdvm
if (setgid(mmdvm_gid) != 0) {
::LogWarning("Could not set mmdvm GID, exiting");
return;
}
if (setuid(mmdvm_uid) != 0) {
::LogWarning("Could not set mmdvm UID, exiting");
return;
}
//Double check it worked (AKA Paranoia)
if (setuid(0) != -1) {
::LogWarning("It's possible to regain root - something is wrong!, exiting");
return;
}
}
}
#endif
CNXDNNetwork nxdnNetwork(m_conf.getNetworkPort(), m_conf.getNetworkDebug());
ret = nxdnNetwork.open();
if (!ret) {
::LogFinalise();
return;
}
CNXCoreNetwork* nxCoreNetwork = NULL;
if (m_conf.getNXCoreEnabled()) {
nxCoreNetwork = new CNXCoreNetwork(m_conf.getNXCoreAddress(), m_conf.getNXCoreDebug());
ret = nxCoreNetwork->open();
if (!ret) {
nxdnNetwork.close();
delete nxCoreNetwork;
::LogFinalise();
return;
}
}
CNXDNLookup* lookup = new CNXDNLookup(m_conf.getLookupName(), m_conf.getLookupTime());
lookup->read();
CStopWatch stopWatch;
stopWatch.start();
CTimer dumpTimer(1000U, 120U);
dumpTimer.start();
LogMessage("Starting NXDNReflector-%s", VERSION);
CNXDNRepeater* current = NULL;
bool nxCore = false;
CTimer watchdogTimer(1000U, 0U, 1500U);
for (;;) {
unsigned char buffer[200U];
in_addr address;
unsigned int port;
unsigned int len = nxdnNetwork.read(buffer, 200U, address, port);
if (len > 0U) {
CNXDNRepeater* rpt = findRepeater(address, port);
if (::memcmp(buffer, "NXDNP", 5U) == 0) {
if (rpt == NULL) {
rpt = new CNXDNRepeater;
rpt->m_timer.start();
rpt->m_address = address;
rpt->m_port = port;
rpt->m_callsign = std::string((char*)(buffer + 5U), 10U);
m_repeaters.push_back(rpt);
LogMessage("Adding %s (%s:%u)", rpt->m_callsign.c_str(), ::inet_ntoa(address), port);
}
else {
rpt->m_timer.start();
}
// Return the poll
nxdnNetwork.write(buffer, len, address, port);
} else if (::memcmp(buffer, "NXDNU", 5U) == 0) {
if (rpt != NULL) {
std::string callsign = std::string((char*)(buffer + 5U), 10U);
LogMessage("Removing %s (%s:%u)", callsign.c_str(), ::inet_ntoa(address), port);
for (std::vector<CNXDNRepeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
if (*it == rpt) {
m_repeaters.erase(it);
break;
}
}
delete rpt;
}
} else if (::memcmp(buffer, "NXDND", 5U) == 0) {
if (rpt != NULL) {
rpt->m_timer.start();
if (current == NULL && !nxCore) {
current = rpt;
unsigned short srcId = (buffer[5U] << 8) | buffer[6U];
unsigned short dstId = (buffer[7U] << 8) | buffer[8U];
bool grp = (buffer[9U] & 0x01U) == 0x01U;
std::string callsign = lookup->find(srcId);
LogMessage("Transmission from %s at %s to %s%u", callsign.c_str(), current->m_callsign.c_str(), grp ? "TG " : "", dstId);
}
if (current == rpt) {
watchdogTimer.start();
for (std::vector<CNXDNRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
in_addr addr = (*it)->m_address;
unsigned int prt = (*it)->m_port;
if (addr.s_addr != address.s_addr || prt != port)
nxdnNetwork.write(buffer, len, addr, prt);
if (nxCoreNetwork != NULL)
nxCoreNetwork->write(buffer, len);
}
if ((buffer[9U] & 0x04U) == 0x04U) {
LogMessage("Received end of transmission");
watchdogTimer.stop();
current = NULL;
}
}
} else {
LogMessage("Data received from an unknown source - %s:%u", ::inet_ntoa(address), port);
CUtils::dump(2U, "Data", buffer, len);
}
}
}
if (nxCoreNetwork != NULL) {
len = nxCoreNetwork->read(buffer, 200U);
if (len > 0U) {
if (current == NULL) {
if (!nxCore) {
if ((buffer[0U] == 0x81U || buffer[0U] == 0x83U) && buffer[5U] == 0x01U) {
bool grp = (buffer[7U] & 0x20U) == 0x20U;
unsigned short srcId = (buffer[8U] << 8) | buffer[9U];
unsigned short dstId = (buffer[10U] << 8) | buffer[11U];
std::string callsign = lookup->find(srcId);
LogMessage("Transmission from %s at NXCore to %s%u", callsign.c_str(), grp ? "TG " : "", dstId);
nxCore = true;
}
}
if (nxCore) {
watchdogTimer.start();
for (std::vector<CNXDNRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
in_addr addr = (*it)->m_address;
unsigned int prt = (*it)->m_port;
nxdnNetwork.write(buffer, len, addr, prt);
}
if ((buffer[0U] == 0x81U || buffer[0U] == 0x83U) && buffer[5U] == 0x08U) {
LogMessage("Received end of transmission");
nxCore = false;
watchdogTimer.stop();
}
}
}
}
}
unsigned int ms = stopWatch.elapsed();
stopWatch.start();
// Remove any repeaters that haven't reported for a while
for (std::vector<CNXDNRepeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it)
(*it)->m_timer.clock(ms);
for (std::vector<CNXDNRepeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
CNXDNRepeater* itRpt = *it;
if (itRpt->m_timer.hasExpired()) {
in_addr address = itRpt->m_address;
unsigned int port = itRpt->m_port;
std::string callsign = itRpt->m_callsign;
LogMessage("Removing %s (%s:%u) disappeared", callsign.c_str(), ::inet_ntoa(address), port);
m_repeaters.erase(it);
delete itRpt;
break;
}
}
watchdogTimer.clock(ms);
if (watchdogTimer.isRunning() && watchdogTimer.hasExpired()) {
LogMessage("Network watchdog has expired");
watchdogTimer.stop();
current = NULL;
nxCore = false;
}
dumpTimer.clock(ms);
if (dumpTimer.hasExpired()) {
dumpRepeaters();
dumpTimer.start();
}
if (nxCoreNetwork != NULL)
nxCoreNetwork->clock(ms);
if (ms < 5U)
CThread::sleep(5U);
}
nxdnNetwork.close();
if (nxCoreNetwork != NULL) {
nxCoreNetwork->close();
delete nxCoreNetwork;
}
lookup->stop();
::LogFinalise();
}
CNXDNRepeater* CNXDNReflector::findRepeater(const in_addr& address, unsigned int port) const
{
for (std::vector<CNXDNRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
if (address.s_addr == (*it)->m_address.s_addr && (*it)->m_port == port)
return *it;
}
return NULL;
}
void CNXDNReflector::dumpRepeaters() const
{
if (m_repeaters.size() == 0U) {
LogMessage("No repeaters linked");
return;
}
LogMessage("Currently linked repeaters:");
for (std::vector<CNXDNRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
in_addr address = (*it)->m_address;
unsigned int port = (*it)->m_port;
std::string callsign = (*it)->m_callsign;
unsigned int timer = (*it)->m_timer.getTimer();
unsigned int timeout = (*it)->m_timer.getTimeout();
LogMessage(" %s (%s:%u) %u/%u", callsign.c_str(), ::inet_ntoa(address), port, timer, timeout);
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright (C) 2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(NXDNReflector_H)
#define NXDNReflector_H
#include "Timer.h"
#include "Conf.h"
#include <cstdio>
#include <string>
#include <vector>
#if !defined(_WIN32) && !defined(_WIN64)
#include <netdb.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#include <winsock.h>
#endif
class CNXDNRepeater {
public:
CNXDNRepeater() :
m_address(),
m_port(0U),
m_callsign(),
m_timer(1000U, 120U)
{
}
in_addr m_address;
unsigned int m_port;
std::string m_callsign;
CTimer m_timer;
};
class CNXDNReflector
{
public:
CNXDNReflector(const std::string& file);
~CNXDNReflector();
void run();
private:
CConf m_conf;
std::vector<CNXDNRepeater*> m_repeaters;
CNXDNRepeater* findRepeater(const in_addr& address, unsigned int port) const;
void dumpRepeaters() const;
};
#endif

View File

@ -0,0 +1,22 @@
[General]
Daemon=1
[Id Lookup]
Name=NXDN.csv
Time=24
[Log]
# Logging levels, 0=No logging
DisplayLevel=1
FileLevel=1
FilePath=.
FileRoot=NXDNReflector
[Network]
Port=41007
Debug=0
[NXCore]
Enabled=0
Address=127.0.0.1
Debug=0

View File

@ -0,0 +1,76 @@
#!/bin/bash
### BEGIN INIT INFO
#
# Provides: NXDNReflector
# Required-Start: $all
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Example startscript NXDNReflector
#
### END INIT INFO
## Fill in name of program here.
PROG="NXDNReflector"
PROG_PATH="/usr/local/bin/"
PROG_ARGS="/etc/NXDNReflector.ini"
PIDFILE="/var/run/NXDNReflector.pid"
USER="root"
start() {
if [ -e $PIDFILE ]; then
## Program is running, exit with error.
echo "Error! $PROG is currently running!" 1>&2
exit 1
else
cd $PROG_PATH
./$PROG $PROG_ARGS
echo "$PROG started"
touch $PIDFILE
fi
}
stop() {
if [ -e $PIDFILE ]; then
## Program is running, so stop it
echo "$PROG is running"
rm -f $PIDFILE
killall $PROG
echo "$PROG stopped"
else
## Program is not running, exit with error.
echo "Error! $PROG not started!" 1>&2
exit 1
fi
}
## Check to see if we are running as root first.
## Found at
## http://www.cyberciti.biz/tips/shell-root-user-check-script.html
if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root" 1>&2
exit 1
fi
case "$1" in
start)
start
exit 0
;;
stop)
stop
exit 0
;;
reload|restart|force-reload)
stop
sleep 5
start
exit 0
;;
**)
echo "Usage: $0 {start|stop|reload}" 1>&2
exit 1
;;
esac
exit 0
### END

View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2026
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NXDNReflector", "NXDNReflector.vcxproj", "{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Debug|x64.ActiveCfg = Debug|x64
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Debug|x64.Build.0 = Debug|x64
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Debug|x86.ActiveCfg = Debug|Win32
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Debug|x86.Build.0 = Debug|Win32
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Release|x64.ActiveCfg = Release|x64
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Release|x64.Build.0 = Release|x64
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Release|x86.ActiveCfg = Release|Win32
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {32F19C39-C6E7-44AB-BE4C-EA8DD3C57231}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,186 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Conf.h" />
<ClInclude Include="NXCoreNetwork.h" />
<ClInclude Include="NXDNLookup.h" />
<ClInclude Include="Log.h" />
<ClInclude Include="Mutex.h" />
<ClInclude Include="NXDNNetwork.h" />
<ClInclude Include="NXDNReflector.h" />
<ClInclude Include="RingBuffer.h" />
<ClInclude Include="StopWatch.h" />
<ClInclude Include="Thread.h" />
<ClInclude Include="Timer.h" />
<ClInclude Include="UDPSocket.h" />
<ClInclude Include="Utils.h" />
<ClInclude Include="Version.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Conf.cpp" />
<ClCompile Include="NXCoreNetwork.cpp" />
<ClCompile Include="NXDNLookup.cpp" />
<ClCompile Include="Log.cpp" />
<ClCompile Include="Mutex.cpp" />
<ClCompile Include="NXDNNetwork.cpp" />
<ClCompile Include="NXDNReflector.cpp" />
<ClCompile Include="StopWatch.cpp" />
<ClCompile Include="Thread.cpp" />
<ClCompile Include="Timer.cpp" />
<ClCompile Include="UDPSocket.cpp" />
<ClCompile Include="Utils.cpp" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>NXDNReflector</RootNamespace>
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Conf.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNLookup.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Log.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Mutex.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNReflector.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RingBuffer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="StopWatch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Thread.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Timer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UDPSocket.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Version.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXDNNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="NXCoreNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Conf.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNLookup.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Log.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Mutex.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNReflector.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="StopWatch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Thread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Timer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UDPSocket.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXDNNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="NXCoreNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

147
NXDNReflector/RingBuffer.h Normal file
View File

@ -0,0 +1,147 @@
/*
* Copyright (C) 2006-2009,2012,2013,2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef RingBuffer_H
#define RingBuffer_H
#include <cstdio>
#include <cassert>
#include <cstring>
template<class T> class CRingBuffer {
public:
CRingBuffer(unsigned int length, const char* name) :
m_length(length),
m_name(name),
m_buffer(NULL),
m_iPtr(0U),
m_oPtr(0U)
{
assert(length > 0U);
assert(name != NULL);
m_buffer = new T[length];
::memset(m_buffer, 0x00, m_length * sizeof(T));
}
~CRingBuffer()
{
delete[] m_buffer;
}
bool addData(const T* buffer, unsigned int nSamples)
{
if (nSamples >= freeSpace()) {
::fprintf(stderr, "**** Overflow in %s ring buffer, %u >= %u\n", m_name, nSamples, freeSpace());
return false;
}
for (unsigned int i = 0U; i < nSamples; i++) {
m_buffer[m_iPtr++] = buffer[i];
if (m_iPtr == m_length)
m_iPtr = 0U;
}
return true;
}
bool getData(T* buffer, unsigned int nSamples)
{
if (dataSize() < nSamples) {
::fprintf(stderr, "**** Underflow in %s ring buffer, %u < %u\n", m_name, dataSize(), nSamples);
return false;
}
for (unsigned int i = 0U; i < nSamples; i++) {
buffer[i] = m_buffer[m_oPtr++];
if (m_oPtr == m_length)
m_oPtr = 0U;
}
return true;
}
bool peek(T* buffer, unsigned int nSamples)
{
if (dataSize() < nSamples) {
::fprintf(stderr, "**** Underflow peek in %s ring buffer, %u < %u\n", m_name, dataSize(), nSamples);
return false;
}
unsigned int ptr = m_oPtr;
for (unsigned int i = 0U; i < nSamples; i++) {
buffer[i] = m_buffer[ptr++];
if (ptr == m_length)
ptr = 0U;
}
return true;
}
void clear()
{
m_iPtr = 0U;
m_oPtr = 0U;
::memset(m_buffer, 0x00, m_length * sizeof(T));
}
unsigned int freeSpace() const
{
if (m_oPtr == m_iPtr)
return m_length;
if (m_oPtr > m_iPtr)
return m_oPtr - m_iPtr;
return (m_length + m_oPtr) - m_iPtr;
}
unsigned int dataSize() const
{
return m_length - freeSpace();
}
bool hasSpace(unsigned int length) const
{
return freeSpace() > length;
}
bool hasData() const
{
return m_oPtr != m_iPtr;
}
bool isEmpty() const
{
return m_oPtr == m_iPtr;
}
private:
unsigned int m_length;
const char* m_name;
T* m_buffer;
unsigned int m_iPtr;
unsigned int m_oPtr;
};
#endif

View File

@ -0,0 +1,84 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "StopWatch.h"
#if defined(_WIN32) || defined(_WIN64)
CStopWatch::CStopWatch() :
m_frequency(),
m_start()
{
::QueryPerformanceFrequency(&m_frequency);
}
CStopWatch::~CStopWatch()
{
}
unsigned long CStopWatch::start()
{
::QueryPerformanceCounter(&m_start);
return (unsigned long)(m_start.QuadPart / m_frequency.QuadPart);
}
unsigned int CStopWatch::elapsed()
{
LARGE_INTEGER now;
::QueryPerformanceCounter(&now);
LARGE_INTEGER temp;
temp.QuadPart = (now.QuadPart - m_start.QuadPart) * 1000;
return (unsigned int)(temp.QuadPart / m_frequency.QuadPart);
}
#else
#include <cstdio>
CStopWatch::CStopWatch() :
m_start()
{
}
CStopWatch::~CStopWatch()
{
}
unsigned long CStopWatch::start()
{
::gettimeofday(&m_start, NULL);
return m_start.tv_usec;
}
unsigned int CStopWatch::elapsed()
{
struct timeval now;
::gettimeofday(&now, NULL);
unsigned int elapsed = (now.tv_sec - m_start.tv_sec) * 1000U;
elapsed += now.tv_usec / 1000U;
elapsed -= m_start.tv_usec / 1000U;
return elapsed;
}
#endif

46
NXDNReflector/StopWatch.h Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(STOPWATCH_H)
#define STOPWATCH_H
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <sys/time.h>
#endif
class CStopWatch
{
public:
CStopWatch();
~CStopWatch();
unsigned long start();
unsigned int elapsed();
private:
#if defined(_WIN32) || defined(_WIN64)
LARGE_INTEGER m_frequency;
LARGE_INTEGER m_start;
#else
struct timeval m_start;
#endif
};
#endif

101
NXDNReflector/Thread.cpp Normal file
View File

@ -0,0 +1,101 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Thread.h"
#if defined(_WIN32) || defined(_WIN64)
CThread::CThread() :
m_handle()
{
}
CThread::~CThread()
{
}
bool CThread::run()
{
m_handle = ::CreateThread(NULL, 0, &helper, this, 0, NULL);
return m_handle != NULL;
}
void CThread::wait()
{
::WaitForSingleObject(m_handle, INFINITE);
::CloseHandle(m_handle);
}
DWORD CThread::helper(LPVOID arg)
{
CThread* p = (CThread*)arg;
p->entry();
return 0UL;
}
void CThread::sleep(unsigned int ms)
{
::Sleep(ms);
}
#else
#include <unistd.h>
CThread::CThread() :
m_thread()
{
}
CThread::~CThread()
{
}
bool CThread::run()
{
return ::pthread_create(&m_thread, NULL, helper, this) == 0;
}
void CThread::wait()
{
::pthread_join(m_thread, NULL);
}
void* CThread::helper(void* arg)
{
CThread* p = (CThread*)arg;
p->entry();
return NULL;
}
void CThread::sleep(unsigned int ms)
{
::usleep(ms * 1000);
}
#endif

56
NXDNReflector/Thread.h Normal file
View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(THREAD_H)
#define THREAD_H
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <pthread.h>
#endif
class CThread
{
public:
CThread();
virtual ~CThread();
virtual bool run();
virtual void entry() = 0;
virtual void wait();
static void sleep(unsigned int ms);
private:
#if defined(_WIN32) || defined(_WIN64)
HANDLE m_handle;
#else
pthread_t m_thread;
#endif
#if defined(_WIN32) || defined(_WIN64)
static DWORD __stdcall helper(LPVOID arg);
#else
static void* helper(void* arg);
#endif
};
#endif

68
NXDNReflector/Timer.cpp Normal file
View File

@ -0,0 +1,68 @@
/*
* Copyright (C) 2009,2010,2015 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Timer.h"
#include <cstdio>
#include <cassert>
CTimer::CTimer(unsigned int ticksPerSec, unsigned int secs, unsigned int msecs) :
m_ticksPerSec(ticksPerSec),
m_timeout(0U),
m_timer(0U)
{
assert(ticksPerSec > 0U);
if (secs > 0U || msecs > 0U) {
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
}
}
CTimer::~CTimer()
{
}
void CTimer::setTimeout(unsigned int secs, unsigned int msecs)
{
if (secs > 0U || msecs > 0U) {
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
} else {
m_timeout = 0U;
m_timer = 0U;
}
}
unsigned int CTimer::getTimeout() const
{
if (m_timeout == 0U)
return 0U;
return (m_timeout - 1U) / m_ticksPerSec;
}
unsigned int CTimer::getTimer() const
{
if (m_timer == 0U)
return 0U;
return (m_timer - 1U) / m_ticksPerSec;
}

89
NXDNReflector/Timer.h Normal file
View File

@ -0,0 +1,89 @@
/*
* Copyright (C) 2009,2010,2011,2014 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef Timer_H
#define Timer_H
class CTimer {
public:
CTimer(unsigned int ticksPerSec, unsigned int secs = 0U, unsigned int msecs = 0U);
~CTimer();
void setTimeout(unsigned int secs, unsigned int msecs = 0U);
unsigned int getTimeout() const;
unsigned int getTimer() const;
unsigned int getRemaining()
{
if (m_timeout == 0U || m_timer == 0U)
return 0U;
if (m_timer >= m_timeout)
return 0U;
return (m_timeout - m_timer) / m_ticksPerSec;
}
bool isRunning()
{
return m_timer > 0U;
}
void start(unsigned int secs, unsigned int msecs = 0U)
{
setTimeout(secs, msecs);
start();
}
void start()
{
if (m_timeout > 0U)
m_timer = 1U;
}
void stop()
{
m_timer = 0U;
}
bool hasExpired()
{
if (m_timeout == 0U || m_timer == 0U)
return false;
if (m_timer >= m_timeout)
return true;
return false;
}
void clock(unsigned int ticks = 1U)
{
if (m_timer > 0U && m_timeout > 0U)
m_timer += ticks;
}
private:
unsigned int m_ticksPerSec;
unsigned int m_timeout;
unsigned int m_timer;
};
#endif

262
NXDNReflector/UDPSocket.cpp Normal file
View File

@ -0,0 +1,262 @@
/*
* Copyright (C) 2006-2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "UDPSocket.h"
#include "Log.h"
#include <cassert>
#if !defined(_WIN32) && !defined(_WIN64)
#include <cerrno>
#include <cstring>
#endif
CUDPSocket::CUDPSocket(const std::string& address, unsigned int port) :
m_address(address),
m_port(port),
m_fd(-1)
{
assert(!address.empty());
#if defined(_WIN32) || defined(_WIN64)
WSAData data;
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
if (wsaRet != 0)
LogError("Error from WSAStartup");
#endif
}
CUDPSocket::CUDPSocket(unsigned int port) :
m_address(),
m_port(port),
m_fd(-1)
{
#if defined(_WIN32) || defined(_WIN64)
WSAData data;
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
if (wsaRet != 0)
LogError("Error from WSAStartup");
#endif
}
CUDPSocket::~CUDPSocket()
{
#if defined(_WIN32) || defined(_WIN64)
::WSACleanup();
#endif
}
in_addr CUDPSocket::lookup(const std::string& hostname)
{
in_addr addr;
#if defined(_WIN32) || defined(_WIN64)
unsigned long address = ::inet_addr(hostname.c_str());
if (address != INADDR_NONE && address != INADDR_ANY) {
addr.s_addr = address;
return addr;
}
struct hostent* hp = ::gethostbyname(hostname.c_str());
if (hp != NULL) {
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr));
return addr;
}
LogError("Cannot find address for host %s", hostname.c_str());
addr.s_addr = INADDR_NONE;
return addr;
#else
in_addr_t address = ::inet_addr(hostname.c_str());
if (address != in_addr_t(-1)) {
addr.s_addr = address;
return addr;
}
struct hostent* hp = ::gethostbyname(hostname.c_str());
if (hp != NULL) {
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr));
return addr;
}
LogError("Cannot find address for host %s", hostname.c_str());
addr.s_addr = INADDR_NONE;
return addr;
#endif
}
bool CUDPSocket::open()
{
m_fd = ::socket(PF_INET, SOCK_DGRAM, 0);
if (m_fd < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot create the UDP socket, err: %lu", ::GetLastError());
#else
LogError("Cannot create the UDP socket, err: %d", errno);
#endif
return false;
}
if (m_port > 0U) {
sockaddr_in addr;
::memset(&addr, 0x00, sizeof(sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(m_port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (!m_address.empty()) {
#if defined(_WIN32) || defined(_WIN64)
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str());
#else
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str());
#endif
if (addr.sin_addr.s_addr == INADDR_NONE) {
LogError("The local address is invalid - %s", m_address.c_str());
return false;
}
}
int reuse = 1;
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot set the UDP socket option, err: %lu", ::GetLastError());
#else
LogError("Cannot set the UDP socket option, err: %d", errno);
#endif
return false;
}
if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot bind the UDP address, err: %lu", ::GetLastError());
#else
LogError("Cannot bind the UDP address, err: %d", errno);
#endif
return false;
}
}
return true;
}
int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port)
{
assert(buffer != NULL);
assert(length > 0U);
// Check that the readfrom() won't block
fd_set readFds;
FD_ZERO(&readFds);
#if defined(_WIN32) || defined(_WIN64)
FD_SET((unsigned int)m_fd, &readFds);
#else
FD_SET(m_fd, &readFds);
#endif
// Return immediately
timeval tv;
tv.tv_sec = 0L;
tv.tv_usec = 0L;
int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv);
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from UDP select, err: %lu", ::GetLastError());
#else
LogError("Error returned from UDP select, err: %d", errno);
#endif
return -1;
}
if (ret == 0)
return 0;
sockaddr_in addr;
#if defined(_WIN32) || defined(_WIN64)
int size = sizeof(sockaddr_in);
#else
socklen_t size = sizeof(sockaddr_in);
#endif
#if defined(_WIN32) || defined(_WIN64)
int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size);
#else
ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size);
#endif
if (len <= 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from recvfrom, err: %lu", ::GetLastError());
#else
LogError("Error returned from recvfrom, err: %d", errno);
#endif
return -1;
}
address = addr.sin_addr;
port = ntohs(addr.sin_port);
return len;
}
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port)
{
assert(buffer != NULL);
assert(length > 0U);
sockaddr_in addr;
::memset(&addr, 0x00, sizeof(sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_addr = address;
addr.sin_port = htons(port);
#if defined(_WIN32) || defined(_WIN64)
int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in));
#else
ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in));
#endif
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from sendto, err: %lu", ::GetLastError());
#else
LogError("Error returned from sendto, err: %d", errno);
#endif
return false;
}
#if defined(_WIN32) || defined(_WIN64)
if (ret != int(length))
return false;
#else
if (ret != ssize_t(length))
return false;
#endif
return true;
}
void CUDPSocket::close()
{
#if defined(_WIN32) || defined(_WIN64)
::closesocket(m_fd);
#else
::close(m_fd);
#endif
}

58
NXDNReflector/UDPSocket.h Normal file
View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2009-2011,2013,2015,2016 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef UDPSocket_H
#define UDPSocket_H
#include <string>
#if !defined(_WIN32) && !defined(_WIN64)
#include <netdb.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#else
#include <winsock.h>
#endif
class CUDPSocket {
public:
CUDPSocket(const std::string& address, unsigned int port = 0U);
CUDPSocket(unsigned int port = 0U);
~CUDPSocket();
bool open();
int read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port);
bool write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port);
void close();
static in_addr lookup(const std::string& hostName);
private:
std::string m_address;
unsigned short m_port;
int m_fd;
};
#endif

146
NXDNReflector/Utils.cpp Normal file
View File

@ -0,0 +1,146 @@
/*
* Copyright (C) 2009,2014,2015,2016 Jonathan Naylor, G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
void CUtils::dump(const std::string& title, const unsigned char* data, unsigned int length)
{
assert(data != NULL);
dump(2U, title, data, length);
}
void CUtils::dump(int level, const std::string& title, const unsigned char* data, unsigned int length)
{
assert(data != NULL);
::Log(level, "%s", title.c_str());
unsigned int offset = 0U;
while (length > 0U) {
std::string output;
unsigned int bytes = (length > 16U) ? 16U : length;
for (unsigned i = 0U; i < bytes; i++) {
char temp[10U];
::sprintf(temp, "%02X ", data[offset + i]);
output += temp;
}
for (unsigned int i = bytes; i < 16U; i++)
output += " ";
output += " *";
for (unsigned i = 0U; i < bytes; i++) {
unsigned char c = data[offset + i];
if (::isprint(c))
output += c;
else
output += '.';
}
output += '*';
::Log(level, "%04X: %s", offset, output.c_str());
offset += 16U;
if (length >= 16U)
length -= 16U;
else
length = 0U;
}
}
void CUtils::dump(const std::string& title, const bool* bits, unsigned int length)
{
assert(bits != NULL);
dump(2U, title, bits, length);
}
void CUtils::dump(int level, const std::string& title, const bool* bits, unsigned int length)
{
assert(bits != NULL);
unsigned char bytes[100U];
unsigned int nBytes = 0U;
for (unsigned int n = 0U; n < length; n += 8U, nBytes++)
bitsToByteBE(bits + n, bytes[nBytes]);
dump(level, title, bytes, nBytes);
}
void CUtils::byteToBitsBE(unsigned char byte, bool* bits)
{
assert(bits != NULL);
bits[0U] = (byte & 0x80U) == 0x80U;
bits[1U] = (byte & 0x40U) == 0x40U;
bits[2U] = (byte & 0x20U) == 0x20U;
bits[3U] = (byte & 0x10U) == 0x10U;
bits[4U] = (byte & 0x08U) == 0x08U;
bits[5U] = (byte & 0x04U) == 0x04U;
bits[6U] = (byte & 0x02U) == 0x02U;
bits[7U] = (byte & 0x01U) == 0x01U;
}
void CUtils::byteToBitsLE(unsigned char byte, bool* bits)
{
assert(bits != NULL);
bits[0U] = (byte & 0x01U) == 0x01U;
bits[1U] = (byte & 0x02U) == 0x02U;
bits[2U] = (byte & 0x04U) == 0x04U;
bits[3U] = (byte & 0x08U) == 0x08U;
bits[4U] = (byte & 0x10U) == 0x10U;
bits[5U] = (byte & 0x20U) == 0x20U;
bits[6U] = (byte & 0x40U) == 0x40U;
bits[7U] = (byte & 0x80U) == 0x80U;
}
void CUtils::bitsToByteBE(const bool* bits, unsigned char& byte)
{
assert(bits != NULL);
byte = bits[0U] ? 0x80U : 0x00U;
byte |= bits[1U] ? 0x40U : 0x00U;
byte |= bits[2U] ? 0x20U : 0x00U;
byte |= bits[3U] ? 0x10U : 0x00U;
byte |= bits[4U] ? 0x08U : 0x00U;
byte |= bits[5U] ? 0x04U : 0x00U;
byte |= bits[6U] ? 0x02U : 0x00U;
byte |= bits[7U] ? 0x01U : 0x00U;
}
void CUtils::bitsToByteLE(const bool* bits, unsigned char& byte)
{
assert(bits != NULL);
byte = bits[0U] ? 0x01U : 0x00U;
byte |= bits[1U] ? 0x02U : 0x00U;
byte |= bits[2U] ? 0x04U : 0x00U;
byte |= bits[3U] ? 0x08U : 0x00U;
byte |= bits[4U] ? 0x10U : 0x00U;
byte |= bits[5U] ? 0x20U : 0x00U;
byte |= bits[6U] ? 0x40U : 0x00U;
byte |= bits[7U] ? 0x80U : 0x00U;
}

36
NXDNReflector/Utils.h Normal file
View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2009,2014,2015 by Jonathan Naylor, G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef Utils_H
#define Utils_H
#include <string>
class CUtils {
public:
static void dump(const std::string& title, const unsigned char* data, unsigned int length);
static void dump(int level, const std::string& title, const unsigned char* data, unsigned int length);
static void dump(const std::string& title, const bool* bits, unsigned int length);
static void dump(int level, const std::string& title, const bool* bits, unsigned int length);
static void byteToBitsBE(unsigned char byte, bool* bits);
static void byteToBitsLE(unsigned char byte, bool* bits);
static void bitsToByteBE(const bool* bits, unsigned char& byte);
static void bitsToByteLE(const bool* bits, unsigned char& byte);
private:
};
#endif

24
NXDNReflector/Version.h Normal file
View File

@ -0,0 +1,24 @@
/*
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20180206";
#endif

13
README.md Normal file
View File

@ -0,0 +1,13 @@
These programs are clients for the NXDN networking now built into the MMDVM Host.
The Parrot is very simple minded and can only handle one client at a time and is therefore not suitable for use as a shared resource via the Internet.
The Gateway allows for use of NXDN Talk Groups to control the access to the various NXDN reflectors.
The Gateway has an ini file that contain the parameters for running the software. The filename of the ini file is passed as a parameter on the command line. The Parrot takes the UDP port number to listen on as an argument.
The MMDVM .ini file should have the IP address and port number of the client in the [NXDN Network] settings.
They build on 32-bit and 64-bit Linux as well as on Windows using Visual Studio 2017 on x86 and x64.
This software is licenced under the GPL v2 and is intended for amateur and educational use only. Use of this software for commercial purposes is strictly forbidden.