inital commit from private repo to public;

pull/1/head
Bryan Biedenkapp 6 years ago
commit 9cc117d30c

1
.gitattributes vendored

@ -0,0 +1 @@
* text=auto

64
.gitignore vendored

@ -0,0 +1,64 @@
# Ignore thumbnails created by windows
Thumbs.db
# Ignore files build by Visual Studio
*.obj
*.pdb
*.mdb # Mono debug file
*.user
*.aps
*.pch
*.vspscc
*_i.c
*_p.c
*.ncb
*.suo
*.tlb
*.tlh
*.bak
*.cache
*.ilk
*.log
[Bb]in
[Dd]ebug*/
*.lib
*.sbr
[Oo]bj*/
[Rr]elease*/
[R]elease*/
_ReSharper*/
[Tt]est[Rr]esult*
*.sdf
*.opensdf
*.userprefs
build.mk
*.prv.xml
*.pub.xml
build/
.vscode/
package/
*.ini
# Compiled binary files
*.exe
*.dll
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Visual Studio
.vs

@ -0,0 +1,38 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.28729.10
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dvmhost", "DVMHost.vcxproj", "{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Debug|Any CPU.ActiveCfg = Debug|Win32
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Debug|Any CPU.Build.0 = Debug|Win32
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Debug|x64.ActiveCfg = Debug|x64
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Debug|x64.Build.0 = Debug|x64
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Debug|x86.ActiveCfg = Debug|Win32
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Debug|x86.Build.0 = Debug|Win32
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Release|Any CPU.ActiveCfg = Release|Win32
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Release|Any CPU.Build.0 = Release|Win32
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Release|x64.ActiveCfg = Release|x64
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Release|x64.Build.0 = Release|x64
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Release|x86.ActiveCfg = Release|Win32
{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
EndGlobal

@ -0,0 +1,320 @@
<?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>{1D34E8C1-CFA5-4D60-B509-9DB58DC4AE92}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>DVMHost</RootNamespace>
<ProjectName>dvmhost</ProjectName>
<WindowsTargetPlatformVersion>10.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>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</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>
<IncludePath>$(ProjectDir);$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(ProjectDir);$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>$(ProjectDir);$(IncludePath)</IncludePath>
</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>
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;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>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent />
<PreBuildEvent />
</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>
<ObjectFileName>$(IntDir)%(RelativeDir)</ObjectFileName>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;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>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="dmr\acl\AccessControl.h" />
<ClInclude Include="dmr\data\Data.h" />
<ClInclude Include="dmr\data\DataHeader.h" />
<ClInclude Include="dmr\data\EMB.h" />
<ClInclude Include="dmr\data\EmbeddedData.h" />
<ClInclude Include="dmr\Control.h" />
<ClInclude Include="dmr\DataPacket.h" />
<ClInclude Include="dmr\DMRDefines.h" />
<ClInclude Include="dmr\Slot.h" />
<ClInclude Include="dmr\SlotType.h" />
<ClInclude Include="dmr\Sync.h" />
<ClInclude Include="dmr\VoicePacket.h" />
<ClInclude Include="dmr\edac\Trellis.h" />
<ClInclude Include="dmr\lc\CSBK.h" />
<ClInclude Include="dmr\lc\FullLC.h" />
<ClInclude Include="dmr\lc\LC.h" />
<ClInclude Include="dmr\lc\ShortLC.h" />
<ClInclude Include="edac\AMBEFEC.h" />
<ClInclude Include="edac\BCH.h" />
<ClInclude Include="edac\BPTC19696.h" />
<ClInclude Include="edac\CRC.h" />
<ClInclude Include="edac\Golay2087.h" />
<ClInclude Include="edac\Golay24128.h" />
<ClInclude Include="edac\Hamming.h" />
<ClInclude Include="edac\QR1676.h" />
<ClInclude Include="edac\RS129.h" />
<ClInclude Include="edac\RS634717.h" />
<ClInclude Include="edac\SHA256.h" />
<ClInclude Include="Defines.h" />
<ClInclude Include="HostMain.h" />
<ClInclude Include="host\calibrate\Console.h" />
<ClInclude Include="host\calibrate\HostCal.h" />
<ClInclude Include="host\Host.h" />
<ClInclude Include="lookups\IdenTableLookup.h" />
<ClInclude Include="lookups\LookupTable.h" />
<ClInclude Include="lookups\RadioIdLookup.h" />
<ClInclude Include="lookups\RSSIInterpolator.h" />
<ClInclude Include="lookups\TalkgroupIdLookup.h" />
<ClInclude Include="modem\Modem.h" />
<ClInclude Include="modem\NullModem.h" />
<ClInclude Include="modem\SerialController.h" />
<ClInclude Include="network\BaseNetwork.h" />
<ClInclude Include="network\Network.h" />
<ClInclude Include="network\RemoteControl.h" />
<ClInclude Include="network\UDPSocket.h" />
<ClInclude Include="p25\acl\AccessControl.h" />
<ClInclude Include="p25\data\DataBlock.h" />
<ClInclude Include="p25\data\DataHeader.h" />
<ClInclude Include="p25\data\LowSpeedData.h" />
<ClInclude Include="p25\edac\Trellis.h" />
<ClInclude Include="p25\lc\LC.h" />
<ClInclude Include="p25\lc\TDULC.h" />
<ClInclude Include="p25\lc\TSBK.h" />
<ClInclude Include="p25\Audio.h" />
<ClInclude Include="p25\Control.h" />
<ClInclude Include="p25\DataPacket.h" />
<ClInclude Include="p25\VoicePacket.h" />
<ClInclude Include="p25\TrunkPacket.h" />
<ClInclude Include="p25\P25Defines.h" />
<ClInclude Include="p25\NID.h" />
<ClInclude Include="p25\SiteData.h" />
<ClInclude Include="p25\P25Utils.h" />
<ClInclude Include="p25\Sync.h" />
<ClInclude Include="Log.h" />
<ClInclude Include="Mutex.h" />
<ClInclude Include="RingBuffer.h" />
<ClInclude Include="StopWatch.h" />
<ClInclude Include="Thread.h" />
<ClInclude Include="Timer.h" />
<ClInclude Include="Utils.h" />
<ClInclude Include="yaml\Yaml.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="dmr\acl\AccessControl.cpp" />
<ClCompile Include="dmr\data\Data.cpp" />
<ClCompile Include="dmr\data\DataHeader.cpp" />
<ClCompile Include="dmr\data\EMB.cpp" />
<ClCompile Include="dmr\data\EmbeddedData.cpp" />
<ClCompile Include="dmr\Control.cpp" />
<ClCompile Include="dmr\DataPacket.cpp" />
<ClCompile Include="dmr\Slot.cpp" />
<ClCompile Include="dmr\SlotType.cpp" />
<ClCompile Include="dmr\Sync.cpp" />
<ClCompile Include="dmr\VoicePacket.cpp" />
<ClCompile Include="dmr\edac\Trellis.cpp" />
<ClCompile Include="dmr\lc\CSBK.cpp" />
<ClCompile Include="dmr\lc\FullLC.cpp" />
<ClCompile Include="dmr\lc\LC.cpp" />
<ClCompile Include="dmr\lc\ShortLC.cpp" />
<ClCompile Include="edac\AMBEFEC.cpp" />
<ClCompile Include="edac\BCH.cpp" />
<ClCompile Include="edac\BPTC19696.cpp" />
<ClCompile Include="edac\CRC.cpp" />
<ClCompile Include="edac\Golay2087.cpp" />
<ClCompile Include="edac\Golay24128.cpp" />
<ClCompile Include="edac\Hamming.cpp" />
<ClCompile Include="edac\QR1676.cpp" />
<ClCompile Include="edac\RS129.cpp" />
<ClCompile Include="edac\RS634717.cpp" />
<ClCompile Include="edac\SHA256.cpp" />
<ClCompile Include="HostMain.cpp" />
<ClCompile Include="host\calibrate\Console.cpp" />
<ClCompile Include="host\calibrate\HostCal.cpp" />
<ClCompile Include="host\Host.cpp" />
<ClCompile Include="lookups\IdenTableLookup.cpp" />
<ClCompile Include="lookups\RadioIdLookup.cpp" />
<ClCompile Include="lookups\RSSIInterpolator.cpp" />
<ClCompile Include="lookups\TalkgroupIdLookup.cpp" />
<ClCompile Include="modem\Modem.cpp" />
<ClCompile Include="modem\NullModem.cpp" />
<ClCompile Include="modem\SerialController.cpp" />
<ClCompile Include="network\BaseNetwork.cpp" />
<ClCompile Include="network\Network.cpp" />
<ClCompile Include="network\RemoteControl.cpp" />
<ClCompile Include="network\UDPSocket.cpp" />
<ClCompile Include="p25\acl\AccessControl.cpp" />
<ClCompile Include="p25\data\DataBlock.cpp" />
<ClCompile Include="p25\data\DataHeader.cpp" />
<ClCompile Include="p25\data\LowSpeedData.cpp" />
<ClCompile Include="p25\edac\Trellis.cpp" />
<ClCompile Include="p25\lc\LC.cpp" />
<ClCompile Include="p25\lc\TDULC.cpp" />
<ClCompile Include="p25\lc\TSBK.cpp" />
<ClCompile Include="p25\Audio.cpp" />
<ClCompile Include="p25\Control.cpp" />
<ClCompile Include="p25\DataPacket.cpp" />
<ClCompile Include="p25\TrunkPacket.cpp" />
<ClCompile Include="p25\VoicePacket.cpp" />
<ClCompile Include="p25\NID.cpp" />
<ClCompile Include="p25\P25Utils.cpp" />
<ClCompile Include="p25\Sync.cpp" />
<ClCompile Include="Log.cpp" />
<ClCompile Include="Mutex.cpp" />
<ClCompile Include="StopWatch.cpp" />
<ClCompile Include="Thread.cpp" />
<ClCompile Include="Timer.cpp" />
<ClCompile Include="Utils.cpp" />
<ClCompile Include="yaml\Yaml.cpp" />
</ItemGroup>
<ItemGroup>
<CopyFileToFolders Include="iden_table.dat">
<FileType>Document</FileType>
</CopyFileToFolders>
<CopyFileToFolders Include="config.yml">
<FileType>Document</FileType>
</CopyFileToFolders>
<None Include="cpp.hint" />
<None Include="Makefile" />
<None Include="Makefile.arm" />
<None Include="Makefile.rpi-arm" />
<CopyFileToFolders Include="rid_acl.dat">
<FileType>Document</FileType>
</CopyFileToFolders>
<CopyFileToFolders Include="RSSI.dat">
<FileType>Document</FileType>
</CopyFileToFolders>
<CopyFileToFolders Include="tg_acl.dat">
<FileType>Document</FileType>
</CopyFileToFolders>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

@ -0,0 +1,540 @@
<?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>
<Filter Include="Header Files\p25">
<UniqueIdentifier>{d76c896d-81a1-4571-a979-85bbe05f6ff2}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\dmr">
<UniqueIdentifier>{b48c6e95-0721-492e-b1ea-7ec159b0ad47}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\edac">
<UniqueIdentifier>{6af8b815-9965-4986-b628-1dc3f551ec6a}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\p25">
<UniqueIdentifier>{9cbfad41-aaef-4b33-bfa5-1c6dd6c245c9}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\dmr">
<UniqueIdentifier>{0db9bf97-4035-4390-8e6e-2aac5d51dbc4}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\edac">
<UniqueIdentifier>{8e26b0a3-a3ad-4d67-bc50-c725212e96a1}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\modem">
<UniqueIdentifier>{1e5fc186-1e05-48e3-a775-dc2b28e6b554}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\network">
<UniqueIdentifier>{916a1400-af49-4141-912a-eb51ee88e24a}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\modem">
<UniqueIdentifier>{11b92d52-caf4-4a9e-86dc-6188084d91d4}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\network">
<UniqueIdentifier>{364613af-689a-40ff-9eb0-9ed75ec264d0}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\dmr\acl">
<UniqueIdentifier>{7c629c3c-e84b-48f4-9dde-061d737bf36d}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\dmr\lc">
<UniqueIdentifier>{4ea80282-86d8-4253-8fe1-ea332ba13e09}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\dmr\data">
<UniqueIdentifier>{9e7cd2a6-f295-456f-aa3a-4328994acad2}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\dmr\acl">
<UniqueIdentifier>{0405cae8-d22a-4120-b228-3c2250948346}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\dmr\lc">
<UniqueIdentifier>{f490b092-2827-4999-b3ee-bf978975894a}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\dmr\data">
<UniqueIdentifier>{87267b26-6d3b-4b44-9c34-93860af6bff2}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\dmr\edac">
<UniqueIdentifier>{ac49360e-4207-433b-a3db-1974710de8b8}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\dmr\edac">
<UniqueIdentifier>{6de4c69f-fa55-405e-a92f-3fdec05414c5}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\p25\acl">
<UniqueIdentifier>{ee5bbcfb-d1bf-47fb-88b4-1b76100d1c0f}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\p25\lc">
<UniqueIdentifier>{77d81332-702f-487a-b155-dcc38f2831f0}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\p25\data">
<UniqueIdentifier>{ac8d97b8-a9bd-48e3-9fb9-08e997d055d4}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\p25\edac">
<UniqueIdentifier>{94f78cbc-78b5-454e-972d-89ff595eca17}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\p25\acl">
<UniqueIdentifier>{bae82c0a-4986-4f77-a85e-e865b77993b3}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\p25\lc">
<UniqueIdentifier>{453ece82-3382-481b-b8a6-560f085e1d0d}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\p25\data">
<UniqueIdentifier>{d742b2cf-71b2-45a1-afbd-753128c38f66}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\p25\edac">
<UniqueIdentifier>{07a6e6a8-699e-41a9-9e0f-0a8a064b2331}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\lookups">
<UniqueIdentifier>{d602c3e6-4a28-4d6f-a0f6-49b54978ce71}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\lookups">
<UniqueIdentifier>{89dd7bc2-bdf5-4ae8-ba5b-f44abdaba5e8}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\yaml">
<UniqueIdentifier>{a085e2ea-d75f-4eef-b7f1-1cb100cd6323}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\yaml">
<UniqueIdentifier>{3f236928-1cc8-405c-a085-8a22404b5887}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\host">
<UniqueIdentifier>{5a6c9478-41b0-41e3-8511-4d58e7edc38f}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\host">
<UniqueIdentifier>{f4690a68-efe2-4d42-a449-3b25d20d18a1}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files\host\calibrate">
<UniqueIdentifier>{f8c0460a-c82a-430c-8ad7-eac5ad528ca7}</UniqueIdentifier>
</Filter>
<Filter Include="Source Files\host\calibrate">
<UniqueIdentifier>{3a6ae793-a482-46fe-9fd3-93476ccb591d}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Defines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Log.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="Utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Thread.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Mutex.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="edac\AMBEFEC.h">
<Filter>Header Files\edac</Filter>
</ClInclude>
<ClInclude Include="edac\BCH.h">
<Filter>Header Files\edac</Filter>
</ClInclude>
<ClInclude Include="edac\BPTC19696.h">
<Filter>Header Files\edac</Filter>
</ClInclude>
<ClInclude Include="edac\CRC.h">
<Filter>Header Files\edac</Filter>
</ClInclude>
<ClInclude Include="edac\Golay2087.h">
<Filter>Header Files\edac</Filter>
</ClInclude>
<ClInclude Include="edac\Golay24128.h">
<Filter>Header Files\edac</Filter>
</ClInclude>
<ClInclude Include="edac\Hamming.h">
<Filter>Header Files\edac</Filter>
</ClInclude>
<ClInclude Include="edac\QR1676.h">
<Filter>Header Files\edac</Filter>
</ClInclude>
<ClInclude Include="edac\RS129.h">
<Filter>Header Files\edac</Filter>
</ClInclude>
<ClInclude Include="edac\SHA256.h">
<Filter>Header Files\edac</Filter>
</ClInclude>
<ClInclude Include="modem\Modem.h">
<Filter>Header Files\modem</Filter>
</ClInclude>
<ClInclude Include="modem\SerialController.h">
<Filter>Header Files\modem</Filter>
</ClInclude>
<ClInclude Include="network\Network.h">
<Filter>Header Files\network</Filter>
</ClInclude>
<ClInclude Include="network\UDPSocket.h">
<Filter>Header Files\network</Filter>
</ClInclude>
<ClInclude Include="edac\RS634717.h">
<Filter>Header Files\edac</Filter>
</ClInclude>
<ClInclude Include="modem\NullModem.h">
<Filter>Header Files\modem</Filter>
</ClInclude>
<ClInclude Include="network\RemoteControl.h">
<Filter>Header Files\network</Filter>
</ClInclude>
<ClInclude Include="lookups\IdenTableLookup.h">
<Filter>Header Files\lookups</Filter>
</ClInclude>
<ClInclude Include="lookups\LookupTable.h">
<Filter>Header Files\lookups</Filter>
</ClInclude>
<ClInclude Include="lookups\RadioIdLookup.h">
<Filter>Header Files\lookups</Filter>
</ClInclude>
<ClInclude Include="lookups\RSSIInterpolator.h">
<Filter>Header Files\lookups</Filter>
</ClInclude>
<ClInclude Include="lookups\TalkgroupIdLookup.h">
<Filter>Header Files\lookups</Filter>
</ClInclude>
<ClInclude Include="p25\P25Defines.h">
<Filter>Header Files\p25</Filter>
</ClInclude>
<ClInclude Include="p25\P25Utils.h">
<Filter>Header Files\p25</Filter>
</ClInclude>
<ClInclude Include="dmr\acl\AccessControl.h">
<Filter>Header Files\dmr\acl</Filter>
</ClInclude>
<ClInclude Include="dmr\data\Data.h">
<Filter>Header Files\dmr\data</Filter>
</ClInclude>
<ClInclude Include="dmr\data\DataHeader.h">
<Filter>Header Files\dmr\data</Filter>
</ClInclude>
<ClInclude Include="dmr\data\EMB.h">
<Filter>Header Files\dmr\data</Filter>
</ClInclude>
<ClInclude Include="dmr\data\EmbeddedData.h">
<Filter>Header Files\dmr\data</Filter>
</ClInclude>
<ClInclude Include="dmr\edac\Trellis.h">
<Filter>Header Files\dmr\edac</Filter>
</ClInclude>
<ClInclude Include="dmr\lc\CSBK.h">
<Filter>Header Files\dmr\lc</Filter>
</ClInclude>
<ClInclude Include="dmr\lc\FullLC.h">
<Filter>Header Files\dmr\lc</Filter>
</ClInclude>
<ClInclude Include="dmr\lc\LC.h">
<Filter>Header Files\dmr\lc</Filter>
</ClInclude>
<ClInclude Include="dmr\lc\ShortLC.h">
<Filter>Header Files\dmr\lc</Filter>
</ClInclude>
<ClInclude Include="dmr\Control.h">
<Filter>Header Files\dmr</Filter>
</ClInclude>
<ClInclude Include="dmr\DataPacket.h">
<Filter>Header Files\dmr</Filter>
</ClInclude>
<ClInclude Include="dmr\DMRDefines.h">
<Filter>Header Files\dmr</Filter>
</ClInclude>
<ClInclude Include="dmr\Slot.h">
<Filter>Header Files\dmr</Filter>
</ClInclude>
<ClInclude Include="dmr\SlotType.h">
<Filter>Header Files\dmr</Filter>
</ClInclude>
<ClInclude Include="dmr\Sync.h">
<Filter>Header Files\dmr</Filter>
</ClInclude>
<ClInclude Include="dmr\VoicePacket.h">
<Filter>Header Files\dmr</Filter>
</ClInclude>
<ClInclude Include="p25\acl\AccessControl.h">
<Filter>Header Files\p25\acl</Filter>
</ClInclude>
<ClInclude Include="p25\data\DataBlock.h">
<Filter>Header Files\p25\data</Filter>
</ClInclude>
<ClInclude Include="p25\data\DataHeader.h">
<Filter>Header Files\p25\data</Filter>
</ClInclude>
<ClInclude Include="p25\data\LowSpeedData.h">
<Filter>Header Files\p25\data</Filter>
</ClInclude>
<ClInclude Include="p25\edac\Trellis.h">
<Filter>Header Files\p25\edac</Filter>
</ClInclude>
<ClInclude Include="p25\lc\LC.h">
<Filter>Header Files\p25\lc</Filter>
</ClInclude>
<ClInclude Include="p25\lc\TDULC.h">
<Filter>Header Files\p25\lc</Filter>
</ClInclude>
<ClInclude Include="p25\lc\TSBK.h">
<Filter>Header Files\p25\lc</Filter>
</ClInclude>
<ClInclude Include="p25\Audio.h">
<Filter>Header Files\p25</Filter>
</ClInclude>
<ClInclude Include="p25\Control.h">
<Filter>Header Files\p25</Filter>
</ClInclude>
<ClInclude Include="p25\DataPacket.h">
<Filter>Header Files\p25</Filter>
</ClInclude>
<ClInclude Include="p25\NID.h">
<Filter>Header Files\p25</Filter>
</ClInclude>
<ClInclude Include="p25\SiteData.h">
<Filter>Header Files\p25</Filter>
</ClInclude>
<ClInclude Include="p25\Sync.h">
<Filter>Header Files\p25</Filter>
</ClInclude>
<ClInclude Include="p25\TrunkPacket.h">
<Filter>Header Files\p25</Filter>
</ClInclude>
<ClInclude Include="p25\VoicePacket.h">
<Filter>Header Files\p25</Filter>
</ClInclude>
<ClInclude Include="yaml\Yaml.h">
<Filter>Header Files\yaml</Filter>
</ClInclude>
<ClInclude Include="host\calibrate\Console.h">
<Filter>Header Files\host\calibrate</Filter>
</ClInclude>
<ClInclude Include="host\calibrate\HostCal.h">
<Filter>Header Files\host\calibrate</Filter>
</ClInclude>
<ClInclude Include="host\Host.h">
<Filter>Header Files\host</Filter>
</ClInclude>
<ClInclude Include="HostMain.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="network\BaseNetwork.h">
<Filter>Header Files\network</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Log.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="Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Thread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Mutex.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="edac\AMBEFEC.cpp">
<Filter>Source Files\edac</Filter>
</ClCompile>
<ClCompile Include="edac\BCH.cpp">
<Filter>Source Files\edac</Filter>
</ClCompile>
<ClCompile Include="edac\BPTC19696.cpp">
<Filter>Source Files\edac</Filter>
</ClCompile>
<ClCompile Include="edac\CRC.cpp">
<Filter>Source Files\edac</Filter>
</ClCompile>
<ClCompile Include="edac\Golay2087.cpp">
<Filter>Source Files\edac</Filter>
</ClCompile>
<ClCompile Include="edac\Golay24128.cpp">
<Filter>Source Files\edac</Filter>
</ClCompile>
<ClCompile Include="edac\Hamming.cpp">
<Filter>Source Files\edac</Filter>
</ClCompile>
<ClCompile Include="edac\QR1676.cpp">
<Filter>Source Files\edac</Filter>
</ClCompile>
<ClCompile Include="edac\RS129.cpp">
<Filter>Source Files\edac</Filter>
</ClCompile>
<ClCompile Include="edac\SHA256.cpp">
<Filter>Source Files\edac</Filter>
</ClCompile>
<ClCompile Include="network\Network.cpp">
<Filter>Source Files\network</Filter>
</ClCompile>
<ClCompile Include="network\UDPSocket.cpp">
<Filter>Source Files\network</Filter>
</ClCompile>
<ClCompile Include="modem\Modem.cpp">
<Filter>Source Files\modem</Filter>
</ClCompile>
<ClCompile Include="modem\SerialController.cpp">
<Filter>Source Files\modem</Filter>
</ClCompile>
<ClCompile Include="edac\RS634717.cpp">
<Filter>Source Files\edac</Filter>
</ClCompile>
<ClCompile Include="modem\NullModem.cpp">
<Filter>Source Files\modem</Filter>
</ClCompile>
<ClCompile Include="network\RemoteControl.cpp">
<Filter>Source Files\network</Filter>
</ClCompile>
<ClCompile Include="lookups\IdenTableLookup.cpp">
<Filter>Source Files\lookups</Filter>
</ClCompile>
<ClCompile Include="lookups\RadioIdLookup.cpp">
<Filter>Source Files\lookups</Filter>
</ClCompile>
<ClCompile Include="lookups\RSSIInterpolator.cpp">
<Filter>Source Files\lookups</Filter>
</ClCompile>
<ClCompile Include="lookups\TalkgroupIdLookup.cpp">
<Filter>Source Files\lookups</Filter>
</ClCompile>
<ClCompile Include="dmr\acl\AccessControl.cpp">
<Filter>Source Files\dmr\acl</Filter>
</ClCompile>
<ClCompile Include="dmr\data\Data.cpp">
<Filter>Source Files\dmr\data</Filter>
</ClCompile>
<ClCompile Include="dmr\data\DataHeader.cpp">
<Filter>Source Files\dmr\data</Filter>
</ClCompile>
<ClCompile Include="dmr\data\EMB.cpp">
<Filter>Source Files\dmr\data</Filter>
</ClCompile>
<ClCompile Include="dmr\data\EmbeddedData.cpp">
<Filter>Source Files\dmr\data</Filter>
</ClCompile>
<ClCompile Include="dmr\edac\Trellis.cpp">
<Filter>Source Files\dmr\edac</Filter>
</ClCompile>
<ClCompile Include="dmr\lc\CSBK.cpp">
<Filter>Source Files\dmr\lc</Filter>
</ClCompile>
<ClCompile Include="dmr\lc\FullLC.cpp">
<Filter>Source Files\dmr\lc</Filter>
</ClCompile>
<ClCompile Include="dmr\lc\LC.cpp">
<Filter>Source Files\dmr\lc</Filter>
</ClCompile>
<ClCompile Include="dmr\lc\ShortLC.cpp">
<Filter>Source Files\dmr\lc</Filter>
</ClCompile>
<ClCompile Include="dmr\Control.cpp">
<Filter>Source Files\dmr</Filter>
</ClCompile>
<ClCompile Include="dmr\DataPacket.cpp">
<Filter>Source Files\dmr</Filter>
</ClCompile>
<ClCompile Include="dmr\Slot.cpp">
<Filter>Source Files\dmr</Filter>
</ClCompile>
<ClCompile Include="dmr\SlotType.cpp">
<Filter>Source Files\dmr</Filter>
</ClCompile>
<ClCompile Include="dmr\Sync.cpp">
<Filter>Source Files\dmr</Filter>
</ClCompile>
<ClCompile Include="dmr\VoicePacket.cpp">
<Filter>Source Files\dmr</Filter>
</ClCompile>
<ClCompile Include="p25\acl\AccessControl.cpp">
<Filter>Source Files\p25\acl</Filter>
</ClCompile>
<ClCompile Include="p25\data\DataBlock.cpp">
<Filter>Source Files\p25\data</Filter>
</ClCompile>
<ClCompile Include="p25\data\DataHeader.cpp">
<Filter>Source Files\p25\data</Filter>
</ClCompile>
<ClCompile Include="p25\data\LowSpeedData.cpp">
<Filter>Source Files\p25\data</Filter>
</ClCompile>
<ClCompile Include="p25\edac\Trellis.cpp">
<Filter>Source Files\p25\edac</Filter>
</ClCompile>
<ClCompile Include="p25\lc\LC.cpp">
<Filter>Source Files\p25\lc</Filter>
</ClCompile>
<ClCompile Include="p25\lc\TDULC.cpp">
<Filter>Source Files\p25\lc</Filter>
</ClCompile>
<ClCompile Include="p25\lc\TSBK.cpp">
<Filter>Source Files\p25\lc</Filter>
</ClCompile>
<ClCompile Include="p25\Audio.cpp">
<Filter>Source Files\p25</Filter>
</ClCompile>
<ClCompile Include="p25\Control.cpp">
<Filter>Source Files\p25</Filter>
</ClCompile>
<ClCompile Include="p25\DataPacket.cpp">
<Filter>Source Files\p25</Filter>
</ClCompile>
<ClCompile Include="p25\NID.cpp">
<Filter>Source Files\p25</Filter>
</ClCompile>
<ClCompile Include="p25\P25Utils.cpp">
<Filter>Source Files\p25</Filter>
</ClCompile>
<ClCompile Include="p25\Sync.cpp">
<Filter>Source Files\p25</Filter>
</ClCompile>
<ClCompile Include="p25\TrunkPacket.cpp">
<Filter>Source Files\p25</Filter>
</ClCompile>
<ClCompile Include="p25\VoicePacket.cpp">
<Filter>Source Files\p25</Filter>
</ClCompile>
<ClCompile Include="yaml\Yaml.cpp">
<Filter>Source Files\yaml</Filter>
</ClCompile>
<ClCompile Include="host\Host.cpp">
<Filter>Source Files\host</Filter>
</ClCompile>
<ClCompile Include="host\calibrate\Console.cpp">
<Filter>Source Files\host\calibrate</Filter>
</ClCompile>
<ClCompile Include="host\calibrate\HostCal.cpp">
<Filter>Source Files\host\calibrate</Filter>
</ClCompile>
<ClCompile Include="HostMain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="network\BaseNetwork.cpp">
<Filter>Source Files\network</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="Makefile" />
<None Include="Makefile.arm" />
<None Include="Makefile.rpi-arm" />
<None Include="cpp.hint" />
</ItemGroup>
<ItemGroup>
<CopyFileToFolders Include="iden_table.dat" />
<CopyFileToFolders Include="rid_acl.dat" />
<CopyFileToFolders Include="RSSI.dat" />
<CopyFileToFolders Include="tg_acl.dat" />
<CopyFileToFolders Include="config.yml" />
</ItemGroup>
</Project>

@ -0,0 +1,239 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2018-2020 by Bryan Biedenkapp N2PLL
*
* 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(__DEFINES_H__)
#define __DEFINES_H__
#include <stdint.h>
#include <string>
#include <sstream>
#include <ios>
// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------
#ifndef _INT8_T_DECLARED
#ifndef __INT8_TYPE__
typedef signed char int8_t;
#endif // __INT8_TYPE__
#endif // _INT8_T_DECLARED
#ifndef _INT16_T_DECLARED
#ifndef __INT16_TYPE__
typedef short int16_t;
#endif // __INT16_TYPE__
#endif // _INT16_T_DECLARED
#ifndef _INT32_T_DECLARED
#ifndef __INT32_TYPE__
typedef int int32_t;
#endif // __INT32_TYPE__
#endif // _INT32_T_DECLARED
#ifndef _INT64_T_DECLARED
#ifndef __INT64_TYPE__
typedef long long int64_t;
#endif // __INT64_TYPE__
#endif // _INT64_T_DECLARED
#ifndef _UINT8_T_DECLARED
#ifndef __UINT8_TYPE__
typedef unsigned char uint8_t;
#endif // __UINT8_TYPE__
#endif // _UINT8_T_DECLARED
#ifndef _UINT16_T_DECLARED
#ifndef __UINT16_TYPE__
typedef unsigned short uint16_t;
#endif // __UINT16_TYPE__
#endif // _UINT16_T_DECLARED
#ifndef _UINT32_T_DECLARED
#ifndef __UINT32_TYPE__
typedef unsigned int uint32_t;
#endif // __UINT32_TYPE__
#endif // _UINT32_T_DECLARED
#ifndef _UINT64_T_DECLARED
#ifndef __UINT64_TYPE__
typedef unsigned long long uint64_t;
#endif // __UINT64_TYPE__
#endif // _UINT64_T_DECLARED
#ifndef __LONG64_TYPE__
typedef long long long64_t;
#endif // __LONG64_TYPE__
#ifndef __ULONG64_TYPE__
typedef unsigned long long ulong64_t;
#endif // __ULONG64_TYPE__
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
#define __PROG_NAME__ "Digital Voice Modem Host"
#define __EXE_NAME__ "dvmhost"
#define __VER__ "R01.00.00"
#define __BUILD__ __DATE__ " " __TIME__
#define HOST_SW_API
#if defined(_WIN32) || defined(_WIN64)
#define DEFAULT_CONF_FILE "config.yml"
#else
#define DEFAULT_CONF_FILE "/opt/DVM/bin/config.yml"
#endif // defined(_WIN32) || defined(_WIN64)
#if defined(_WIN32) || defined(_WIN64)
#define DEFAULT_LOCK_FILE "dvm.lock"
#else
#define DEFAULT_LOCK_FILE "/tmp/dvm.lock"
#endif // defined(_WIN32) || defined(_WIN64)
#if defined(__GNUC__) || defined(__GNUG__)
#define __forceinline __attribute__((always_inline))
#endif
const uint32_t TRAFFIC_DEFAULT_PORT = 62031;
const uint32_t RCON_DEFAULT_PORT = 9990;
const uint8_t BIT_MASK_TABLE[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
enum HOST_STATE {
HOST_STATE_LOCKOUT = 250U,
HOST_STATE_ERROR = 254U,
HOST_STATE_QUIT = 255U,
};
const uint8_t TAG_HEADER = 0x00U;
const uint8_t TAG_DATA = 0x01U;
const uint8_t TAG_LOST = 0x02U;
const uint8_t TAG_EOT = 0x03U;
enum RPT_RF_STATE {
RS_RF_LISTENING,
RS_RF_LATE_ENTRY,
RS_RF_AUDIO,
RS_RF_DATA,
RS_RF_REJECTED,
RS_RF_INVALID
};
enum RPT_NET_STATE {
RS_NET_IDLE,
RS_NET_AUDIO,
RS_NET_DATA
};
const uint8_t UDP_COMPRESS_NONE = 0x00U;
const uint8_t IP_COMPRESS_NONE = 0x00U;
const uint8_t IP_COMPRESS_RFC1144_COMPRESS = 0x01U;
const uint8_t IP_COMPRESS_RFC1144_UNCOMPRESS = 0x02U;
// ---------------------------------------------------------------------------
// Inlines
// ---------------------------------------------------------------------------
inline std::string __BOOL_STR(const bool& value) {
std::stringstream ss;
ss << std::boolalpha << value;
return ss.str();
}
inline std::string __INT_STR(const int& value) {
std::stringstream ss;
ss << value;
return ss.str();
}
inline std::string __FLOAT_STR(const float& value) {
std::stringstream ss;
ss << value;
return ss.str();
}
// ---------------------------------------------------------------------------
// Macros
// ---------------------------------------------------------------------------
#define __FLOAT_ADDR(x) (*(uint32_t*)& x)
#define __DOUBLE_ADDR(x) (*(uint64_t*)& x)
#define WRITE_BIT(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_BIT(p, i) (p[(i) >> 3] & BIT_MASK_TABLE[(i) & 7])
#define __SET_UINT32(val, buffer, offset) \
buffer[0U + offset] = val >> 24; \
buffer[1U + offset] = val >> 16; \
buffer[2U + offset] = val >> 8; \
buffer[3U + offset] = val >> 0;
#define __GET_UINT32(buffer, offset) \
(buffer[offset + 0U] << 24) | \
(buffer[offset + 1U] << 16) | \
(buffer[offset + 2U] << 8) | \
(buffer[offset + 3U] << 0);
#define __SET_UINT16(val, buffer, offset) \
buffer[0U + offset] = val >> 16; \
buffer[1U + offset] = val >> 8; \
buffer[2U + offset] = val >> 0;
#define __GET_UINT16(buffer, offset) \
(buffer[offset + 0U] << 16) | \
(buffer[offset + 1U] << 8) | \
(buffer[offset + 2U] << 0);
/**
* Property Creation
* These macros should always be used LAST in the "public" section of a class definition.
*/
/// <summary>Creates a read-only get property.</summary>
#define __READONLY_PROPERTY(type, variableName, propName) \
private: type m_##variableName; \
public: __forceinline type get##propName(void) const { return m_##variableName; }
/// <summary>Creates a read-only get property, does not use "get".</summary>
#define __READONLY_PROPERTY_PLAIN(type, variableName, propName) \
private: type m_##variableName; \
public: __forceinline type propName(void) const { return m_##variableName; }
/// <summary>Creates a read-only get property by reference.</summary>
#define __READONLY_PROPERTY_BYREF(type, variableName, propName) \
private: type m_##variableName; \
public: __forceinline type& get##propName(void) const { return m_##variableName; }
/// <summary>Creates a get and set property.</summary>
#define __PROPERTY(type, variableName, propName) \
private: type m_##variableName; \
public: __forceinline type get##propName(void) const { return m_##variableName; } \
__forceinline void set##propName(type val) { m_##variableName = val; }
/// <summary>Creates a get and set property, does not use "get"/"set".</summary>
#define __PROPERTY_PLAIN(type, variableName, propName) \
private: type m_##variableName; \
public: __forceinline type propName(void) const { return m_##variableName; } \
__forceinline void propName(type val) { m_##variableName = val; }
/// <summary>Creates a get and set property by reference.</summary>
#define __PROPERTY_BYREF(type, variableName, propName) \
private: type m_##variableName; \
public: __forceinline type& get##propName(void) const { return m_##variableName; } \
__forceinline void set##propName(type& val) { m_##variableName = val; }
#endif // __DEFINES_H__

@ -0,0 +1,236 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2020 by Bryan Biedenkapp N2PLL
*
* 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 "Defines.h"
#include "HostMain.h"
#include "host/Host.h"
#include "host/calibrate/HostCal.h"
#include "Log.h"
using namespace network;
using namespace modem;
using namespace lookups;
#include <cstdio>
#include <cstdarg>
#include <vector>
#if !defined(_WIN32) && !defined(_WIN64)
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <pwd.h>
#endif
// ---------------------------------------------------------------------------
// Macros
// ---------------------------------------------------------------------------
#define IS(s) (::strcmp(argv[i], s) == 0)
// ---------------------------------------------------------------------------
// Global Variables
// ---------------------------------------------------------------------------
int g_signal = 0;
bool g_calibrate = false;
std::string g_progExe = std::string(__EXE_NAME__);
std::string g_iniFile = std::string(DEFAULT_CONF_FILE);
std::string g_lockFile = std::string(DEFAULT_LOCK_FILE);
bool g_foreground = false;
bool g_killed = false;
bool g_fireDMRBeacon = false;
bool g_fireP25Control = false;
bool g_interruptP25Control = false;
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
#if !defined(_WIN32) && !defined(_WIN64)
static void sigHandler(int signum)
{
g_killed = true;
g_signal = signum;
}
#endif
void fatal(const char* msg, ...)
{
char buffer[400U];
va_list vl;
va_start(vl, msg);
::vsprintf(buffer + ::strlen(buffer), msg, vl);
va_end(vl);
::fprintf(stderr, "%s: %s\n", g_progExe.c_str(), buffer);
exit(EXIT_FAILURE);
}
void usage(const char* message, const char* arg)
{
::fprintf(stdout, __PROG_NAME__ " %s (built %s)\r\n", __VER__, __BUILD__);
if (message != NULL) {
::fprintf(stderr, "%s: ", g_progExe.c_str());
::fprintf(stderr, message, arg);
::fprintf(stderr, "\n\n");
}
::fprintf(stdout, "usage: %s [-v] [-f] [--cal] [-c <configuration file>]\n\n"
" -f foreground mode\n"
" --cal calibration mode\n"
"\n"
" -v show version information\n"
" -h show this screen\n"
" -- stop handling options\n",
g_progExe.c_str());
exit(EXIT_FAILURE);
}
int checkArgs(int argc, char* argv[])
{
int i, p = 0;
// iterate through arguments
for (i = 1; i <= argc; i++)
{
if (argv[i] == NULL) {
break;
}
if (*argv[i] != '-') {
continue;
}
else if (IS("--")) {
++p;
break;
}
else if (IS("-f")) {
g_foreground = true;
}
else if (IS("--cal")) {
g_calibrate = true;
}
else if (IS("-c")) {
if (argc-- <= 0)
usage("error: %s", "must specify the configuration file to use");
g_iniFile = std::string(argv[++i]);
if (g_iniFile == "")
usage("error: %s", "configuration file cannot be blank!");
p += 2;
}
else if (IS("-v")) {
::fprintf(stdout, __PROG_NAME__ " %s (built %s)\r\n", __VER__, __BUILD__);
if (argc == 2)
exit(EXIT_SUCCESS);
}
else if (IS("-h")) {
usage(NULL, NULL);
if (argc == 2)
exit(EXIT_SUCCESS);
}
else {
usage("unrecognized option `%s'", argv[i]);
}
}
if (p < 0 || p > argc) {
p = 0;
}
return ++p;
}
// ---------------------------------------------------------------------------
// Program Entry Point
// ---------------------------------------------------------------------------
int main(int argc, char** argv)
{
if (argv[0] != NULL && *argv[0] != 0)
g_progExe = std::string(argv[0]);
if (argc > 1) {
// check arguments
int i = checkArgs(argc, argv);
if (i < argc) {
argc -= i;
argv += i;
}
else {
argc--;
argv++;
}
}
#if !defined(_WIN32) && !defined(_WIN64)
::signal(SIGINT, sigHandler);
::signal(SIGTERM, sigHandler);
::signal(SIGHUP, sigHandler);
#endif
int ret = 0;
do {
g_signal = 0;
if (g_calibrate) {
HostCal* cal = new HostCal(g_iniFile);
ret = cal->run();
delete cal;
}
else {
Host* host = new Host(g_iniFile);
ret = host->run();
delete host;
}
if (g_signal == 2)
::LogInfoEx(LOG_HOST, "Exited on receipt of SIGINT");
if (g_signal == 15)
::LogInfoEx(LOG_HOST, "Exited on receipt of SIGTERM");
if (g_signal == 1)
::LogInfoEx(LOG_HOST, "Restarting on receipt of SIGHUP");
} while (g_signal == 1);
::LogFinalise();
::ActivityLogFinalise();
return ret;
}

@ -0,0 +1,56 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2020 by Bryan Biedenkapp N2PLL
*
* 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(__HOST_MAIN_H__)
#define __HOST_MAIN_H__
#include "Defines.h"
#include <string>
// ---------------------------------------------------------------------------
// Externs
// ---------------------------------------------------------------------------
extern int g_signal;
extern std::string g_progExe;
extern std::string g_iniFile;
extern std::string g_lockFile;
extern bool g_foreground;
extern bool g_killed;
extern bool g_fireDMRBeacon;
extern bool g_fireP25Control;
extern bool g_interruptP25Control;
extern HOST_SW_API void fatal(const char* msg, ...);
#endif // __HOST_MAIN_H__

@ -0,0 +1,264 @@
The GNU General Public License, Version 2, June 1991 (GPLv2)
============================================================
> Copyright (C) 1989, 1991 Free Software Foundation, Inc.
> 51 Franklin Street, 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 Lesser 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.
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.

@ -0,0 +1,327 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2018-2019 by Bryan Biedenkapp N2PLL
*
* 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"
#include "network/Network.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>
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
#if defined(_WIN32) || defined(_WIN64)
#define EOL "\n"
#else
#define EOL "\r\n"
#endif
// ---------------------------------------------------------------------------
// Global Variables
// ---------------------------------------------------------------------------
static uint32_t m_fileLevel = 0U;
static std::string m_filePath;
static std::string m_actFilePath;
static std::string m_fileRoot;
static std::string m_actFileRoot;
static network::Network* m_network;
static FILE* m_fpLog = NULL;
static FILE* m_actFpLog = NULL;
static uint32_t m_displayLevel = 2U;
static struct tm m_tm;
static struct tm m_actTm;
static char LEVELS[] = " DMIWEF";
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
/// <summary>
/// Helper to open the detailed log file, file handle.
/// </summary>
/// <returns>True, if log file is opened, otherwise false.
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;
}
/// <summary>
/// Helper to open the activity log file, file handle.
/// </summary>
/// <returns>True, if log file is opened, otherwise false.
static bool ActivityLogOpen()
{
time_t now;
::time(&now);
struct tm* tm = ::gmtime(&now);
if (tm->tm_mday == m_actTm.tm_mday && tm->tm_mon == m_actTm.tm_mon && tm->tm_year == m_actTm.tm_year) {
if (m_actFpLog != NULL)
return true;
}
else {
if (m_actFpLog != NULL)
::fclose(m_actFpLog);
}
char filename[100U];
#if defined(_WIN32) || defined(_WIN64)
::sprintf(filename, "%s\\%s-%04d-%02d-%02d.activity.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.activity.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
#endif
m_actFpLog = ::fopen(filename, "a+t");
m_actTm = *tm;
return m_actFpLog != NULL;
}
/// <summary>
/// Initializes the activity log.
/// </summary>
/// <param name="filePath">Full-path to the activity log file.</param>
/// <param name="fileRoot">Prefix of the activity log file name.</param>
bool ActivityLogInitialise(const std::string& filePath, const std::string& fileRoot)
{
m_actFilePath = filePath;
m_actFileRoot = fileRoot;
m_network = NULL;
return ::ActivityLogOpen();
}
/// <summary>
/// Finalizes the activity log.
/// </summary>
void ActivityLogFinalise()
{
if (m_actFpLog != NULL)
::fclose(m_actFpLog);
}
/// <summary>
/// Writes a new entry to the activity log.
/// </summary>
/// <param name="mode">Digital mode (usually P25 or DMR).</param>
/// <param name="sourceRf">Flag indicating that the entry was generated from an RF event.</param>
/// <param name="msg">Formatted string to write to activity log.</param>
void ActivityLog(const char *mode, const bool sourceRf, const char* msg, ...)
{
assert(mode != NULL);
assert(msg != NULL);
char buffer[400U];
#if defined(_WIN32) || defined(_WIN64)
SYSTEMTIME st;
::GetSystemTime(&st);
::sprintf(buffer, "A: %04u-%02u-%02u %02u:%02u:%02u.%03u %s %s ", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, mode, (sourceRf) ? "RF" : "Net");
#else
struct timeval now;
::gettimeofday(&now, NULL);
struct tm* tm = ::gmtime(&now.tv_sec);
::sprintf(buffer, "A: %04d-%02d-%02d %02d:%02d:%02d.%03lu %s %s ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000U, mode, (sourceRf) ? "RF" : "Net");
#endif
va_list vl;
va_start(vl, msg);
::vsprintf(buffer + ::strlen(buffer), msg, vl);
va_end(vl);
bool ret = ::ActivityLogOpen();
if (!ret)
return;
::fprintf(m_actFpLog, "%s\n", buffer);
::fflush(m_actFpLog);
if (m_network != NULL) {
m_network->writeActLog(buffer);
}
if (2U >= m_fileLevel && m_fileLevel != 0U) {
bool ret = ::LogOpen();
if (!ret)
return;
::fprintf(m_fpLog, "%s\n", buffer);
::fflush(m_fpLog);
}
if (2U >= m_displayLevel && m_displayLevel != 0U) {
::fprintf(stdout, "%s" EOL, buffer);
::fflush(stdout);
}
}
/// <summary>
/// Sets the instance of the Network class to transfer the activity log with.
/// </summary>
/// <param name="network">Instance of the Network class.</param>
void ActivityLogSetNetwork(void* network)
{
// Note: The Network class is passed here as a void so we can avoid including the Network.h
// header in Log.h. This is dirty and probably terrible...
m_network = (network::Network*)network;
}
/// <summary>
/// Initializes the detailed log.
/// </summary>
/// <param name="filePath">Full-path to the detailed log file.</param>
/// <param name="fileRoot">Prefix of the detailed log file name.</param>
/// <param name="fileLevel">File logging level.</param>
/// <param name="displayLevel">Console logging level.</param>
bool LogInitialise(const std::string& filePath, const std::string& fileRoot, uint32_t fileLevel, uint32_t displayLevel)
{
m_filePath = filePath;
m_fileRoot = fileRoot;
m_fileLevel = fileLevel;
m_displayLevel = displayLevel;
return ::LogOpen();
}
/// <summary>
/// Finalizes the detailed log.
/// </summary>
void LogFinalise()
{
if (m_fpLog != NULL)
::fclose(m_fpLog);
}
/// <summary>
/// Writes a new entry to the detailed log.
/// </summary>
/// <param name="level">Log level.</param>
/// <param name="module">Module name the log entry was genearted from.</param>
/// <param name="msg">Formatted string to write to activity log.</param>
void Log(uint32_t level, const char *module, const char* fmt, ...)
{
assert(fmt != NULL);
char buffer[300U];
#if defined(_WIN32) || defined(_WIN64)
SYSTEMTIME st;
::GetSystemTime(&st);
if (module != NULL) {
::sprintf(buffer, "%c: %04u-%02u-%02u %02u:%02u:%02u.%03u (%s) ", LEVELS[level], st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, module);
}
else {
::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);
if (module != NULL) {
::sprintf(buffer, "%c: %04d-%02d-%02d %02d:%02d:%02d.%03lu (%s) ", 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, module);
}
else {
::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" EOL, buffer);
::fflush(stdout);
}
if (level >= 6U) { // Fatal
::fclose(m_fpLog);
exit(1);
}
}

82
Log.h

@ -0,0 +1,82 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2018-2019 by Bryan Biedenkapp N2PLL
*
* 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 "Defines.h"
#include <string>
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
#define LOG_HOST "HOST"
#define LOG_RCON "RCON"
#define LOG_MODEM "MODEM"
#define LOG_RF "RF"
#define LOG_NET "NET"
#define LOG_P25 "P25"
#define LOG_DMR "DMR"
#define LOG_CAL "CAL"
// ---------------------------------------------------------------------------
// Macros
// ---------------------------------------------------------------------------
#define LogDebug(_module, fmt, ...) Log(1U, _module, fmt, ##__VA_ARGS__)
#define LogMessage(_module, fmt, ...) Log(2U, _module, fmt, ##__VA_ARGS__)
#define LogInfo(fmt, ...) Log(3U, NULL, fmt, ##__VA_ARGS__)
#define LogInfoEx(_module, fmt, ...) Log(3U, _module, fmt, ##__VA_ARGS__)
#define LogWarning(_module, fmt, ...) Log(4U, _module, fmt, ##__VA_ARGS__)
#define LogError(_module, fmt, ...) Log(5U, _module, fmt, ##__VA_ARGS__)
#define LogFatal(_module, fmt, ...) Log(6U, _module, fmt, ##__VA_ARGS__)
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
/// <summary>Initializes the activity log.</summary>
extern HOST_SW_API bool ActivityLogInitialise(const std::string& filePath, const std::string& fileRoot);
/// <summary>Finalizes the activity log.</summary>
extern HOST_SW_API void ActivityLogFinalise();
/// <summary>Writes a new entry to the activity log.</summary>
extern HOST_SW_API void ActivityLog(const char* mode, const bool sourceRf, const char* msg, ...);
/// <summary>Sets the instance of the Network class to transfer the activity log with.</summary>
extern HOST_SW_API void ActivityLogSetNetwork(void* network);
/// <summary>Initializes the detailed log.</summary>
extern HOST_SW_API bool LogInitialise(const std::string& filePath, const std::string& fileRoot, uint32_t fileLevel, uint32_t displayLevel);
/// <summary>Finalizes the detailed log.</summary>
extern HOST_SW_API void LogFinalise();
/// <summary>Writes a new entry to the detailed log.</summary>
extern HOST_SW_API void Log(uint32_t level, const char* module, const char* fmt, ...);
#endif // __LOG_H__

@ -0,0 +1,91 @@
CC = gcc
CXX = g++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -I.
LIBS = -lpthread
LDFLAGS = -g
OBJECTS = \
edac/AMBEFEC.o \
edac/BCH.o \
edac/BPTC19696.o \
edac/CRC.o \
edac/Golay2087.o \
edac/Golay24128.o \
edac/Hamming.o \
edac/QR1676.o \
edac/RS129.o \
edac/RS634717.o \
edac/SHA256.o \
dmr/acl/AccessControl.o \
dmr/data/Data.o \
dmr/data/DataHeader.o \
dmr/data/EMB.o \
dmr/data/EmbeddedData.o \
dmr/edac/Trellis.o \
dmr/lc/CSBK.o \
dmr/lc/FullLC.o \
dmr/lc/LC.o \
dmr/lc/ShortLC.o \
dmr/Control.o \
dmr/DataPacket.o \
dmr/Slot.o \
dmr/SlotType.o \
dmr/Sync.o \
dmr/VoicePacket.o \
lookups/IdenTableLookup.o \
lookups/RadioIdLookup.o \
lookups/RSSIInterpolator.o \
lookups/TalkgroupIdLookup.o \
p25/acl/AccessControl.o \
p25/data/DataBlock.o \
p25/data/DataHeader.o \
p25/data/LowSpeedData.o \
p25/edac/Trellis.o \
p25/lc/LC.o \
p25/lc/TDULC.o \
p25/lc/TSBK.o \
p25/Audio.o \
p25/Control.o \
p25/DataPacket.o \
p25/NID.o \
p25/Sync.o \
p25/TrunkPacket.o \
p25/P25Utils.o \
p25/VoicePacket.o \
modem/SerialController.o \
modem/Modem.o \
modem/NullModem.o \
network/UDPSocket.o \
network/RemoteControl.o \
network/BaseNetwork.o \
network/Network.o \
yaml/Yaml.o \
host/calibrate/Console.o \
host/calibrate/HostCal.o \
host/Host.o \
Log.o \
Mutex.o \
Thread.o \
Timer.o \
StopWatch.o \
Utils.o \
HostMain.o
BIN = ../bin
all: dvmhost
-cp -f dvmhost $(BIN)
if [ ! -e $(BIN)/config.yml ]; then cp -f config.yml $(BIN); fi
if [ ! -e $(BIN)/rid_acl.dat ]; then cp -f rid_acl.dat $(BIN); fi
if [ ! -e $(BIN)/tg_acl.dat ]; then cp -f tg_acl.dat $(BIN); fi
if [ ! -e $(BIN)/iden_table.dat ]; then cp -f iden_table.dat $(BIN); fi
if [ ! -e $(BIN)/RSSI.dat ]; then cp -f RSSI.dat $(BIN); fi
dvmhost: $(OBJECTS)
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o dvmhost
%.o: %.cpp
$(CXX) $(CFLAGS) -c -o $@ $<
clean:
$(RM) dvmhost *.o *.d *.bak *~ edac/*.o dmr/*.o dmr/acl/*.o dmr/data/*.o dmr/edac/*.o dmr/lc/*.o p25/*.o p25/acl/*.o p25/data/*.o p25/edac/*.o p25/lc/*.o lookups/*.o modem/*.o network/*.o yaml/*.o host/*.o host/calibrate/*.o

@ -0,0 +1,91 @@
CC = arm-linux-gnueabihf-gcc-4.9
CXX = arm-linux-gnueabihf-g++-4.9
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -I.
LIBS = -lpthread
LDFLAGS = -g
OBJECTS = \
edac/AMBEFEC.o \
edac/BCH.o \
edac/BPTC19696.o \
edac/CRC.o \
edac/Golay2087.o \
edac/Golay24128.o \
edac/Hamming.o \
edac/QR1676.o \
edac/RS129.o \
edac/RS634717.o \
edac/SHA256.o \
dmr/acl/AccessControl.o \
dmr/data/Data.o \
dmr/data/DataHeader.o \
dmr/data/EMB.o \
dmr/data/EmbeddedData.o \
dmr/edac/Trellis.o \
dmr/lc/CSBK.o \
dmr/lc/FullLC.o \
dmr/lc/LC.o \
dmr/lc/ShortLC.o \
dmr/Control.o \
dmr/DataPacket.o \
dmr/Slot.o \
dmr/SlotType.o \
dmr/Sync.o \
dmr/VoicePacket.o \
lookups/IdenTableLookup.o \
lookups/RadioIdLookup.o \
lookups/RSSIInterpolator.o \
lookups/TalkgroupIdLookup.o \
p25/acl/AccessControl.o \
p25/data/DataBlock.o \
p25/data/DataHeader.o \
p25/data/LowSpeedData.o \
p25/edac/Trellis.o \
p25/lc/LC.o \
p25/lc/TDULC.o \
p25/lc/TSBK.o \
p25/Audio.o \
p25/Control.o \
p25/DataPacket.o \
p25/NID.o \
p25/Sync.o \
p25/TrunkPacket.o \
p25/P25Utils.o \
p25/VoicePacket.o \
modem/SerialController.o \
modem/Modem.o \
modem/NullModem.o \
network/UDPSocket.o \
network/RemoteControl.o \
network/BaseNetwork.o \
network/Network.o \
yaml/Yaml.o \
host/calibrate/Console.o \
host/calibrate/HostCal.o \
host/Host.o \
Log.o \
Mutex.o \
Thread.o \
Timer.o \
StopWatch.o \
Utils.o \
HostMain.o
BIN = ../bin
all: dvmhost
-cp -f dvmhost $(BIN)
if [ ! -e $(BIN)/config.yml ]; then cp -f config.yml $(BIN); fi
if [ ! -e $(BIN)/rid_acl.dat ]; then cp -f rid_acl.dat $(BIN); fi
if [ ! -e $(BIN)/tg_acl.dat ]; then cp -f tg_acl.dat $(BIN); fi
if [ ! -e $(BIN)/iden_table.dat ]; then cp -f iden_table.dat $(BIN); fi
if [ ! -e $(BIN)/RSSI.dat ]; then cp -f RSSI.dat $(BIN); fi
dvmhost: $(OBJECTS)
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o dvmhost
%.o: %.cpp
$(CXX) $(CFLAGS) -c -o $@ $<
clean:
$(RM) dvmhost *.o *.d *.bak *~ edac/*.o dmr/*.o dmr/acl/*.o dmr/data/*.o dmr/edac/*.o dmr/lc/*.o p25/*.o p25/acl/*.o p25/data/*.o p25/edac/*.o p25/lc/*.o lookups/*.o modem/*.o network/*.o yaml/*.o host/*.o host/calibrate/*.o

@ -0,0 +1,91 @@
CC = /opt/tools/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc
CXX = /opt/tools/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -I.
LIBS = -lpthread
LDFLAGS = -g
OBJECTS = \
edac/AMBEFEC.o \
edac/BCH.o \
edac/BPTC19696.o \
edac/CRC.o \
edac/Golay2087.o \
edac/Golay24128.o \
edac/Hamming.o \
edac/QR1676.o \
edac/RS129.o \
edac/RS634717.o \
edac/SHA256.o \
dmr/acl/AccessControl.o \
dmr/data/Data.o \
dmr/data/DataHeader.o \
dmr/data/EMB.o \
dmr/data/EmbeddedData.o \
dmr/edac/Trellis.o \
dmr/lc/CSBK.o \
dmr/lc/FullLC.o \
dmr/lc/LC.o \
dmr/lc/ShortLC.o \
dmr/Control.o \
dmr/DataPacket.o \
dmr/Slot.o \
dmr/SlotType.o \
dmr/Sync.o \
dmr/VoicePacket.o \
lookups/IdenTableLookup.o \
lookups/RadioIdLookup.o \
lookups/RSSIInterpolator.o \
lookups/TalkgroupIdLookup.o \
p25/acl/AccessControl.o \
p25/data/DataBlock.o \
p25/data/DataHeader.o \
p25/data/LowSpeedData.o \
p25/edac/Trellis.o \
p25/lc/LC.o \
p25/lc/TDULC.o \
p25/lc/TSBK.o \
p25/Audio.o \
p25/Control.o \
p25/DataPacket.o \
p25/NID.o \
p25/Sync.o \
p25/TrunkPacket.o \
p25/P25Utils.o \
p25/VoicePacket.o \
modem/SerialController.o \
modem/Modem.o \
modem/NullModem.o \
network/UDPSocket.o \
network/RemoteControl.o \
network/BaseNetwork.o \
network/Network.o \
yaml/Yaml.o \
host/calibrate/Console.o \
host/calibrate/HostCal.o \
host/Host.o \
Log.o \
Mutex.o \
Thread.o \
Timer.o \
StopWatch.o \
Utils.o \
HostMain.o
BIN = ../bin
all: dvmhost
-cp -f dvmhost $(BIN)
if [ ! -e $(BIN)/config.yml ]; then cp -f config.yml $(BIN); fi
if [ ! -e $(BIN)/rid_acl.dat ]; then cp -f rid_acl.dat $(BIN); fi
if [ ! -e $(BIN)/tg_acl.dat ]; then cp -f tg_acl.dat $(BIN); fi
if [ ! -e $(BIN)/iden_table.dat ]; then cp -f iden_table.dat $(BIN); fi
if [ ! -e $(BIN)/RSSI.dat ]; then cp -f RSSI.dat $(BIN); fi
dvmhost: $(OBJECTS)
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o dvmhost
%.o: %.cpp
$(CXX) $(CFLAGS) -c -o $@ $<
clean:
$(RM) dvmhost *.o *.d *.bak *~ edac/*.o dmr/*.o dmr/acl/*.o dmr/data/*.o dmr/edac/*.o dmr/lc/*.o p25/*.o p25/acl/*.o p25/data/*.o p25/edac/*.o p25/lc/*.o lookups/*.o modem/*.o network/*.o yaml/*.o host/*.o host/calibrate/*.o

@ -0,0 +1,102 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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"
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
#if defined(_WIN32) || defined(_WIN64)
/// <summary>
/// Initializes a new instance of the Mutex class.
/// </summary>
Mutex::Mutex() :
m_handle()
{
m_handle = ::CreateMutex(NULL, FALSE, NULL);
}
/// <summary>
/// Finalizes a instance of the Mutex class.
/// </summary>
Mutex::~Mutex()
{
::CloseHandle(m_handle);
}
/// <summary>
/// Locks the mutex.
/// </summary>
void Mutex::lock()
{
::WaitForSingleObject(m_handle, INFINITE);
}
/// <summary>
/// Unlocks the mutex.
/// </summary>
void Mutex::unlock()
{
::ReleaseMutex(m_handle);
}
#else
/// <summary>
/// Initializes a new instance of the Mutex class.
/// </summary>
Mutex::Mutex() :
m_mutex(PTHREAD_MUTEX_INITIALIZER)
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the Mutex class.
/// </summary>
Mutex::~Mutex()
{
/* stub */
}
/// <summary>
/// Locks the mutex.
/// </summary>
void Mutex::lock()
{
::pthread_mutex_lock(&m_mutex);
}
/// <summary>
/// Unlocks the mutex.
/// </summary>
void Mutex::unlock()
{
::pthread_mutex_unlock(&m_mutex);
}
#endif

@ -0,0 +1,66 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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__
#include "Defines.h"
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <pthread.h>
#endif
// ---------------------------------------------------------------------------
// Class Declaration
// Implements a simple mutual exclusion locking mechanism.
// ---------------------------------------------------------------------------
class HOST_SW_API Mutex {
public:
/// <summary>Initializes a new instance of the Mutex class.</summary>
Mutex();
/// <summary>Finalizes a instance of the Mutex class.</summary>
~Mutex();
/// <summary>Locks the mutex.</summary>
void lock();
/// <summary>Unlocks the mutex.</summary>
void unlock();
private:
#if defined(_WIN32) || defined(_WIN64)
HANDLE m_handle;
#else
pthread_mutex_t m_mutex;
#endif
};
#endif // __MUTEX_H__

@ -0,0 +1,21 @@
# Digital Voice Modem Host
The DVM Host software provides the host computer implementation of a mixed-mode DMR/P25 or dedicated-mode DMR or P25 repeater system that talks to the actual modem hardware. The host software; is the portion of a complete Over-The-Air modem implementation that performs the data processing, decision making and FEC correction for a digital repeater.
This project is a direct fork of the MMDVMHost (https://github.com/g4klx/MMDVMHost) project, and combines the MMDVMCal (https://github.com/g4klx/MMDVMCal) project into a single package.
## Building
Please see the various Makefile included in the project for more information. (All following information assumes familiarity with the standard Linux make system.)
The DVM Host software does not have any specific library dependancies and is written to be as library-free as possible. A basic GCC install is usually all thats needed to compile.
* Makefile - This makefile is used for building binaries for the native installed GCC.
* Makefile.arm - This makefile is used for cross-compiling for a ARM platform.
Use the ```make``` command to build the software.
## License
This project is licensed under the GPLv2 License - see the [LICENSE.md](LICENSE.md) file for details

@ -0,0 +1,11 @@
# This file maps the raw RSSI values to dBm values to send to the DMR network. A number of data
# points should be entered and the software will use those to work out the in-between values.
#
# The format of the file is:
# Raw RSSI Value dBm Value
#
# For example
# 1134 -90
# 1123 -100
# 1000 -109
#

@ -0,0 +1,223 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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.
*/
#if !defined(__RING_BUFFER_H__)
#define __RING_BUFFER_H__
#include "Defines.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
// ---------------------------------------------------------------------------
// Class Declaration
// Implements a circular buffer for storing data.
// ---------------------------------------------------------------------------
template<class T>
class HOST_SW_API RingBuffer {
public:
/// <summary>Initializes a new instance of the RingBuffer class.</summary>
/// <param name="length">Length of ring buffer.</param>
/// <param name="name">Name of buffer.</param>
RingBuffer(uint32_t 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));
}
/// <summary>Finalizes a instance of the RingBuffer class.</summary>
~RingBuffer()
{
delete[] m_buffer;
}
/// <summary>Adds data to the end of the ring buffer.</summary>
/// <param name="buffer">Data buffer.</param>
/// <param name="length">Length of data in buffer.</param>
/// <returns>True, if data is added to ring buffer, otherwise false.</returns>
bool addData(const T* buffer, uint32_t length)
{
if (length >= freeSpace()) {
LogError(LOG_HOST, "%s buffer overflow, clearing the buffer. (%u >= %u)", m_name, length, freeSpace());
clear();
return false;
}
for (uint32_t i = 0U; i < length; i++) {
m_buffer[m_iPtr++] = buffer[i];
if (m_iPtr == m_length)
m_iPtr = 0U;
}
return true;
}
/// <summary>Gets data from the ring buffer.</summary>
/// <param name="buffer">Buffer to write data to be retrieved.</param>
/// <param name="length">Length of data to retrieve.</param>
/// <returns>True, if data is read from ring buffer, otherwise false.</returns>
bool getData(T* buffer, uint32_t length)
{
if (dataSize() < length) {
LogError(LOG_HOST, "**** Underflow in %s ring buffer, %u < %u", m_name, dataSize(), length);
return false;
}
for (uint32_t i = 0U; i < length; i++) {
buffer[i] = m_buffer[m_oPtr++];
if (m_oPtr == m_length)
m_oPtr = 0U;
}
return true;
}
/// <summary>Gets data from ring buffer without moving buffer pointers.</summary>
/// <param name="buffer">Buffer to write data to be retrieved.</param>
/// <param name="length">Length of data to retrieve.</param>
/// <returns>True, if data is read from ring buffer, otherwise false.</returns>
bool peek(T* buffer, uint32_t length)
{
if (dataSize() < length) {
LogError(LOG_HOST, "**** Underflow peek in %s ring buffer, %u < %u", m_name, dataSize(), length);
return false;
}
uint32_t ptr = m_oPtr;
for (uint32_t i = 0U; i < length; i++) {
buffer[i] = m_buffer[ptr++];
if (ptr == m_length)
ptr = 0U;
}
return true;
}
/// <summary>Clears ring buffer and resets data pointers.</summary>
void clear()
{
m_iPtr = 0U;
m_oPtr = 0U;
::memset(m_buffer, 0x00, m_length * sizeof(T));
}
/// <summary>Resizes the ring buffer to the specified length.</summary>
/// <param name="length">New length of the ring buffer.</param>
void resize(uint32_t length)
{
clear();
delete[] m_buffer;
m_length = length;
m_buffer = new T[length];
clear();
}
/// <summary>Returns the currently available space in the ring buffer.</summary>
/// <returns>Space free in the ring buffer.</returns>
uint32_t freeSpace() const
{
uint32_t len = m_length;
if (m_oPtr > m_iPtr)
len = m_oPtr - m_iPtr;
else if (m_iPtr > m_oPtr)
len = m_length - (m_iPtr - m_oPtr);
if (len > m_length)
len = 0U;
return len;
}
/// <summary>Returns the size of the data currently stored in the ring buffer.</summary>
/// <returns>Size of data stored in the ring buffer.</returns>
uint32_t dataSize() const
{
return m_length - freeSpace();
}
/// <summary>Gets the length of the ring buffer.</summary>
/// <returns>Length of ring buffer.</returns>
uint32_t length() const
{
return m_length;
}
/// <summary>Helper to test if the given length of data would fit in the ring buffer.</summary>
/// <returns>True, if specified length will fit in buffer, otherwise false.</returns>
bool hasSpace(uint32_t length) const
{
return freeSpace() > length;
}
/// <summary>Helper to return whether the ring buffer contains data.</summary>
/// <returns>True, if ring buffer contains data, otherwise false.</returns>
bool hasData() const
{
return m_oPtr != m_iPtr;
}
/// <summary>Helper to return whether the ring buffer is empty or not.</summary>
/// <returns>True, if the ring buffer is empty, otherwise false.</returns>
bool isEmpty() const
{
return m_oPtr == m_iPtr;
}
private:
uint32_t m_length;
const char* m_name;
T* m_buffer;
uint32_t m_iPtr;
uint32_t m_oPtr;
};
#endif // __RING_BUFFER_H__

@ -0,0 +1,157 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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)
#include <cstdio>
#include <ctime>
#endif
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
#if defined(_WIN32) || defined(_WIN64)
/// <summary>
/// Initializes a new instance of the StopWatch class.
/// </summary>
StopWatch::StopWatch() :
m_frequencyS(),
m_frequencyMS(),
m_start()
{
::QueryPerformanceFrequency(&m_frequencyS);
m_frequencyMS.QuadPart = m_frequencyS.QuadPart / 1000ULL;
}
/// <summary>
/// Finalizes a instance of the StopWatch class.
/// </summary>
StopWatch::~StopWatch()
{
/* stub */
}
/// <summary>
/// Gets the current running time.
/// </summary>
/// <returns></returns>
ulong64_t StopWatch::time() const
{
LARGE_INTEGER now;
::QueryPerformanceCounter(&now);
return (ulong64_t)(now.QuadPart / m_frequencyMS.QuadPart);
}
/// <summary>
/// Starts the stopwatch.
/// </summary>
/// <returns></returns>
ulong64_t StopWatch::start()
{
::QueryPerformanceCounter(&m_start);
return (ulong64_t)(m_start.QuadPart / m_frequencyS.QuadPart);
}
/// <summary>
/// Gets the elpased time since the stopwatch started.
/// </summary>
/// <returns></returns>
uint32_t StopWatch::elapsed()
{
LARGE_INTEGER now;
::QueryPerformanceCounter(&now);
LARGE_INTEGER temp;
temp.QuadPart = (now.QuadPart - m_start.QuadPart) * 1000;
return (uint32_t)(temp.QuadPart / m_frequencyS.QuadPart);
}
#else
/// <summary>
/// Initializes a new instance of the StopWatch class.
/// </summary>
StopWatch::StopWatch() :
m_startMS(0ULL)
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the StopWatch class.
/// </summary>
StopWatch::~StopWatch()
{
/* stub */
}
/// <summary>
/// Gets the current running time.
/// </summary>
/// <returns></returns>
ulong64_t StopWatch::time() const
{
struct timeval now;
::gettimeofday(&now, NULL);
return now.tv_sec * 1000ULL + now.tv_usec / 1000ULL;
}
/// <summary>
/// Starts the stopwatch.
/// </summary>
/// <returns></returns>
ulong64_t StopWatch::start()
{
struct timespec now;
::clock_gettime(CLOCK_MONOTONIC, &now);
m_startMS = now.tv_sec * 1000ULL + now.tv_nsec / 1000000ULL;
return m_startMS;
}
/// <summary>
/// Gets the elpased time since the stopwatch started.
/// </summary>
/// <returns></returns>
uint32_t StopWatch::elapsed()
{
struct timespec now;
::clock_gettime(CLOCK_MONOTONIC, &now);
ulong64_t nowMS = now.tv_sec * 1000ULL + now.tv_nsec / 1000000ULL;
return nowMS - m_startMS;
}
#endif

@ -0,0 +1,71 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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__
#include "Defines.h"
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <sys/time.h>
#endif
// ---------------------------------------------------------------------------
// Class Declaration
// Implements a stopwatch.
// ---------------------------------------------------------------------------
class HOST_SW_API StopWatch {
public:
/// <summary>Initializes a new instance of the StopWatch class.</summary>
StopWatch();
/// <summary>Finalizes a instance of the StopWatch class.</summary>
~StopWatch();
/// <summary>Gets the current running time.</summary>
ulong64_t time() const;
/// <summary>Starts the stopwatch.</summary>
ulong64_t start();
/// <summary>Gets the elpased time since the stopwatch started.</summary>
uint32_t elapsed();
private:
#if defined(_WIN32) || defined(_WIN64)
LARGE_INTEGER m_frequencyS;
LARGE_INTEGER m_frequencyMS;
LARGE_INTEGER m_start;
#else
ulong64_t m_startMS;
#endif
};
#endif // __STOPWATCH_H__

@ -0,0 +1,164 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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)
#include <unistd.h>
#endif
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
#if defined(_WIN32) || defined(_WIN64)
/// <summary>
/// Initializes a new instance of the Thread class.
/// </summary>
Thread::Thread() :
m_handle()
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the Thread class.
/// </summary>
Thread::~Thread()
{
/* stub */
}
/// <summary>
/// Starts the thread execution.
/// </summary>
/// <returns>True, if thread started, otherwise false.</returns>
bool Thread::run()
{
m_handle = ::CreateThread(NULL, 0, &helper, this, 0, NULL);
return m_handle != NULL;
}
/// <summary>
///
/// </summary>
void Thread::wait()
{
::WaitForSingleObject(m_handle, INFINITE);
::CloseHandle(m_handle);
}
/// <summary>
///
/// </summary>
/// <param name="ms"></param>
void Thread::sleep(uint32_t ms)
{
::Sleep(ms);
}
#else
/// <summary>
/// Initializes a new instance of the Thread class.
/// </summary>
Thread::Thread() :
m_thread()
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the Thread class.
/// </summary>
Thread::~Thread()
{
/* stub */
}
/// <summary>
/// Starts the thread execution.
/// </summary>
/// <returns>True, if thread started, otherwise false.</returns>
bool Thread::run()
{
return ::pthread_create(&m_thread, NULL, helper, this) == 0;
}
/// <summary>
///
/// </summary>
void Thread::wait()
{
::pthread_join(m_thread, NULL);
}
/// <summary>
///
/// </summary>
/// <param name="ms"></param>
void Thread::sleep(uint32_t ms)
{
::usleep(ms * 1000);
}
#endif
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
#if defined(_WIN32) || defined(_WIN64)
/// <summary>
///
/// </summary>
/// <param name="arg"></param>
/// <returns></returns>
DWORD Thread::helper(LPVOID arg)
{
Thread* p = (Thread*)arg;
p->entry();
return 0UL;
}
#else
/// <summary>
///
/// </summary>
/// <param name="arg"></param>
/// <returns></returns>
void* Thread::helper(void* arg)
{
Thread* p = (Thread*)arg;
p->entry();
return NULL;
}
#endif

@ -0,0 +1,81 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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__
#include "Defines.h"
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <pthread.h>
#endif
// ---------------------------------------------------------------------------
// Class Declaration
// Implements a simple threading mechanism.
// ---------------------------------------------------------------------------
class HOST_SW_API Thread {
public:
/// <summary>Initializes a new instance of the Thread class.</summary>
Thread();
/// <summary>Finalizes a instance of the Thread class.</summary>
virtual ~Thread();
/// <summary>Starts the thread execution.</summary>
virtual bool run();
/// <summary>User-defined function to run for the thread main.</summary>
virtual void entry() = 0;
/// <summary></summary>
virtual void wait();
/// <summary></summary>
static void sleep(uint32_t ms);
private:
#if defined(_WIN32) || defined(_WIN64)
HANDLE m_handle;
#else
pthread_t m_thread;
#endif
#if defined(_WIN32) || defined(_WIN64)
/// <summary></summary>
static DWORD __stdcall helper(LPVOID arg);
#else
/// <summary></summary>
static void* helper(void* arg);
#endif
};
#endif // __THREAD_H__

@ -0,0 +1,121 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2009,2010,2015 by Jonathan Naylor G4KLX
* Copyright (C) 2017-2019 by Bryan Biedenkapp N2PLL
*
* 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 "Defines.h"
#include "Timer.h"
#include <cstdio>
#include <cassert>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the Timer class.
/// </summary>
Timer::Timer() :
m_ticksPerSec(1000U),
m_timeout(0U),
m_timer(0U),
m_paused(false)
{
/* stub */
}
/// <summary>
/// Initializes a new instance of the Timer class.
/// </summary>
/// <param name="ticksPerSec"></param>
/// <param name="secs"></param>
/// <param name="msecs"></param>
Timer::Timer(uint32_t ticksPerSec, uint32_t secs, uint32_t msecs) :
m_ticksPerSec(ticksPerSec),
m_timeout(0U),
m_timer(0U),
m_paused(false)
{
assert(ticksPerSec > 0U);
if (secs > 0U || msecs > 0U) {
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
ulong64_t temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
m_timeout = (uint32_t)(temp / 1000ULL + 1ULL);
}
}
/// <summary>
/// Finalizes a instance of the Timer class.
/// </summary>
Timer::~Timer()
{
/* stub */
}
/// <summary>
/// Sets the timeout for the timer.
/// </summary>
/// <param name="secs"></param>
/// <param name="msecs"></param>
void Timer::setTimeout(uint32_t secs, uint32_t msecs)
{
if (secs > 0U || msecs > 0U) {
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
ulong64_t temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
m_timeout = (uint32_t)(temp / 1000ULL + 1ULL);
}
else {
m_timeout = 0U;
m_timer = 0U;
}
}
/// <summary>
/// Gets the timeout for the timer.
/// </summary>
/// <returns></returns>
uint32_t Timer::getTimeout() const
{
if (m_timeout == 0U)
return 0U;
return (m_timeout - 1U) / m_ticksPerSec;
}
/// <summary>
/// Gets the current time for the timer.
/// </summary>
/// <returns></returns>
uint32_t Timer::getTimer() const
{
if (m_timer == 0U)
return 0U;
return (m_timer - 1U) / m_ticksPerSec;
}

@ -0,0 +1,153 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2009,2010,2011,2014 by Jonathan Naylor G4KLX
* Copyright (C) 2017-2019 by Bryan Biedenkapp N2PLL
*
* 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(__TIMER_H__)
#define __TIMER_H__
#include "Defines.h"
// ---------------------------------------------------------------------------
// Class Declaration
// Implements a timer.
// ---------------------------------------------------------------------------
class HOST_SW_API Timer {
public:
/// <summary>Initializes a new instance of the Timer class.</summary>
Timer();
/// <summary>Initializes a new instance of the Timer class.</summary>
Timer(uint32_t ticksPerSec, uint32_t secs = 0U, uint32_t msecs = 0U);
/// <summary>Finalizes a instance of the Timer class.</summary>
~Timer();
/// <summary>Sets the timeout for the timer.</summary>
void setTimeout(uint32_t secs, uint32_t msecs = 0U);
/// <summary>Gets the timeout for the timer.</summary>
uint32_t getTimeout() const;
/// <summary>Gets the current time for the timer.</summary>
uint32_t getTimer() const;
/// <summary>Gets the currently remaining time for the timer.</summary>
/// <returns>Amount of time remaining before the timeout.</returns>
uint32_t getRemaining()
{
if (m_timeout == 0U || m_timer == 0U)
return 0U;
if (m_timer >= m_timeout)
return 0U;
return (m_timeout - m_timer) / m_ticksPerSec;
}
/// <summary>Flag indicating whether the timer is running.</summary>
/// <returns>True, if the timer is still running, otherwise false.</returns>
bool isRunning()
{
return m_timer > 0U;
}
/// <summary>Flag indicating whether the timer is paused.</summary>
/// <returns>True, if the timer is paused, otherwise false.</returns>
bool isPaused()
{
return m_paused;
}
/// <summary>Starts the timer.</summary>
/// <param name="secs"></param>
/// <param name="msecs"></param>
void start(uint32_t secs, uint32_t msecs = 0U)
{
setTimeout(secs, msecs);
start();
}
/// <summary>Starts the timer.</summary>
void start()
{
if (m_timeout > 0U)
m_timer = 1U;
m_paused = false;
}
/// <summary>Stops the timer.</summary>
void stop()
{
m_timer = 0U;
m_paused = false;
}
/// <summary>Pauses the timer.</summary>
void pause()
{
m_paused = true;
}
/// <summary>Resumes the timer.</summary>
void resume()
{
m_paused = false;
}
/// <summary>Flag indicating whether or not the timer has reached timeout and expired.</summary>
/// <returns>True, if the timer is expired, otherwise false.</returns>
bool hasExpired()
{
if (m_timeout == 0U || m_timer == 0U)
return false;
if (m_timer >= m_timeout)
return true;
return false;
}
/// <summary>Updates the timer by the passed number of ticks.</summary>
/// <param name="ticks"></param>
void clock(uint32_t ticks = 1U)
{
if (m_paused)
return;
if (m_timer > 0U && m_timeout > 0U)
m_timer += ticks;
}
private:
uint32_t m_ticksPerSec;
uint32_t m_timeout;
uint32_t m_timer;
bool m_paused;
};
#endif // __TIMER_H__

@ -0,0 +1,341 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2009,2014,2015,2016 Jonathan Naylor, G4KLX
* Copyright (C) 2018-2020 Bryan Biedenkapp N2PLL
*
* 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>
// ---------------------------------------------------------------------------
// Constants/Macros
// ---------------------------------------------------------------------------
const uint8_t BITS_TABLE[] = {
# define B2(n) n, n+1, n+1, n+2
# define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2)
# define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2)
B6(0), B6(1), B6(1), B6(2)
};
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
/// <summary>
/// Displays the host version.
/// </summary>
void getHostVersion()
{
LogInfo(__PROG_NAME__ " %s (built %s)", __VER__, __BUILD__);
}
// ---------------------------------------------------------------------------
// Static Class Members
// ---------------------------------------------------------------------------
/// <summary>
///
/// <summary>
/// <param name="title"></param>
/// <param name="data"></param>
/// <param name="length"></param>
void Utils::dump(const std::string& title, const uint8_t* data, uint32_t length)
{
assert(data != NULL);
dump(2U, title, data, length);
}
/// <summary>
///
/// <summary>
/// <param name="level"></param>
/// <param name="title"></param>
/// <param name="data"></param>
/// <param name="length"></param>
void Utils::dump(int level, const std::string& title, const uint8_t* data, uint32_t length)
{
assert(data != NULL);
::Log(level, "DUMP", "%s", title.c_str());
uint32_t offset = 0U;
while (length > 0U) {
std::string output;
uint32_t bytes = (length > 16U) ? 16U : length;
for (unsigned i = 0U; i < bytes; i++) {
char temp[10U];
::sprintf(temp, "%02X ", data[offset + i]);
output += temp;
}
for (uint32_t i = bytes; i < 16U; i++)
output += " ";
output += " *";
for (unsigned i = 0U; i < bytes; i++) {
uint8_t c = data[offset + i];
if (::isprint(c))
output += c;
else
output += '.';
}
output += '*';
::Log(level, "DUMP", "%04X: %s", offset, output.c_str());
offset += 16U;
if (length >= 16U)
length -= 16U;
else
length = 0U;
}
}
/// <summary>
///
/// <summary>
/// <param name="title"></param>
/// <param name="bits"></param>
/// <param name="length"></param>
void Utils::dump(const std::string& title, const bool* bits, uint32_t length)
{
assert(bits != NULL);
dump(2U, title, bits, length);
}
/// <summary>
///
/// <summary>
/// <param name="level"></param>
/// <param name="title"></param>
/// <param name="bits"></param>
/// <param name="length"></param>
void Utils::dump(int level, const std::string& title, const bool* bits, uint32_t length)
{
assert(bits != NULL);
uint8_t bytes[100U];
uint32_t nBytes = 0U;
for (uint32_t n = 0U; n < length; n += 8U, nBytes++)
bitsToByteBE(bits + n, bytes[nBytes]);
dump(level, title, bytes, nBytes);
}
/// <summary>
///
/// <summary>
/// <param name="byte"></param>
/// <param name="bits"></param>
void Utils::byteToBitsBE(uint8_t 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;
}
/// <summary>
///
/// <summary>
/// <param name="byte"></param>
/// <param name="bits"></param>
void Utils::byteToBitsLE(uint8_t 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;
}
/// <summary>
///
/// <summary>
/// <param name="bits"></param>
/// <param name="byte"></param>
void Utils::bitsToByteBE(const bool* bits, uint8_t& 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;
}
/// <summary>
///
/// <summary>
/// <param name="bits"></param>
/// <param name="byte"></param>
void Utils::bitsToByteLE(const bool* bits, uint8_t& 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;
}
/// <summary>
///
/// </summary>
/// <param name="in"></param>
/// <param name="out"></param>
/// <param name="start"></param>
/// <param name="stop"></param>
uint32_t Utils::getBits(const uint8_t* in, uint8_t* out, uint32_t start, uint32_t stop)
{
assert(in != NULL);
assert(out != NULL);
uint32_t n = 0U;
for (uint32_t i = start; i < stop; i++, n++) {
bool b = READ_BIT(in, i);
WRITE_BIT(out, n, b);
}
return n;
}
/// <summary>
///
/// </summary>
/// <param name="in"></param>
/// <param name="out"></param>
/// <param name="start"></param>
/// <param name="length"></param>
uint32_t Utils::getBitRange(const uint8_t* in, uint8_t* out, uint32_t start, uint32_t length)
{
return getBits(in, out, start, start + length);
}
/// <summary>
///
/// </summary>
/// <param name="in"></param>
/// <param name="out"></param>
/// <param name="start"></param>
/// <param name="stop"></param>
uint32_t Utils::setBits(const uint8_t* in, uint8_t* out, uint32_t start, uint32_t stop)
{
assert(in != NULL);
assert(out != NULL);
uint32_t n = 0U;
for (uint32_t i = start; i < stop; i++, n++) {
bool b = READ_BIT(in, n);
WRITE_BIT(out, i, b);
}
return n;
}
/// <summary>
///
/// </summary>
/// <param name="in"></param>
/// <param name="out"></param>
/// <param name="start"></param>
/// <param name="length"></param>
uint32_t Utils::setBitRange(const uint8_t* in, uint8_t* out, uint32_t start, uint32_t length)
{
return setBits(in, out, start, start + length);
}
/// <summary>
/// Returns the count of bits in the passed 8 byte value.
/// </summary>
/// <param name="bits"></param>
/// <returns></returns>
uint8_t Utils::countBits8(uint8_t bits)
{
return BITS_TABLE[bits];
}
/// <summary>
/// Returns the count of bits in the passed 32 byte value.
/// </summary>
/// <param name="bits"></param>
/// <returns></returns>
uint8_t Utils::countBits32(uint32_t bits)
{
uint8_t* p = (uint8_t*)&bits;
uint8_t n = 0U;
n += BITS_TABLE[p[0U]];
n += BITS_TABLE[p[1U]];
n += BITS_TABLE[p[2U]];
n += BITS_TABLE[p[3U]];
return n;
}
/// <summary>
/// Returns the count of bits in the passed 64 byte value.
/// </summary>
/// <param name="bits"></param>
/// <returns></returns>
uint8_t Utils::countBits64(ulong64_t bits)
{
uint8_t* p = (uint8_t*)&bits;
uint8_t n = 0U;
n += BITS_TABLE[p[0U]];
n += BITS_TABLE[p[1U]];
n += BITS_TABLE[p[2U]];
n += BITS_TABLE[p[3U]];
n += BITS_TABLE[p[4U]];
n += BITS_TABLE[p[5U]];
n += BITS_TABLE[p[6U]];
n += BITS_TABLE[p[7U]];
return n;
}

@ -0,0 +1,86 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2009,2014,2015 by Jonathan Naylor, G4KLX
* Copyright (C) 2018-2019 Bryan Biedenkapp N2PLL
*
* 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.
*/
#if !defined(__UTILS_H__)
#define __UTILS_H__
#include "Defines.h"
#include <string>
// ---------------------------------------------------------------------------
// Externs
// ---------------------------------------------------------------------------
extern "C" {
/// <summary>Displays the host version.</summary>
HOST_SW_API void getHostVersion();
}
// ---------------------------------------------------------------------------
// Class Declaration
// Implements various helper utilities.
// ---------------------------------------------------------------------------
class HOST_SW_API Utils {
public:
/// <summary></summary>
static void dump(const std::string& title, const uint8_t* data, uint32_t length);
/// <summary></summary>
static void dump(int level, const std::string& title, const uint8_t* data, uint32_t length);
/// <summary></summary>
static void dump(const std::string& title, const bool* bits, uint32_t length);
/// <summary></summary>
static void dump(int level, const std::string& title, const bool* bits, uint32_t length);
/// <summary></summary>
static void byteToBitsBE(uint8_t byte, bool* bits);
/// <summary></summary>
static void byteToBitsLE(uint8_t byte, bool* bits);
/// <summary></summary>
static void bitsToByteBE(const bool* bits, uint8_t& byte);
/// <summary></summary>
static void bitsToByteLE(const bool* bits, uint8_t& byte);
/// <summary></summary>
static uint32_t getBits(const uint8_t* in, uint8_t* out, uint32_t start, uint32_t stop);
/// <summary></summary>
static uint32_t getBitRange(const uint8_t* in, uint8_t* out, uint32_t start, uint32_t length);
/// <summary></summary>
static uint32_t setBits(const uint8_t* in, uint8_t* out, uint32_t start, uint32_t stop);
/// <summary></summary>
static uint32_t setBitRange(const uint8_t* in, uint8_t* out, uint32_t start, uint32_t length);
/// <summary>Returns the count of bits in the passed 8 byte value.</summary>
static uint8_t countBits8(uint8_t bits);
/// <summary>Returns the count of bits in the passed 32 byte value.</summary>
static uint8_t countBits32(uint32_t bits);
/// <summary>Returns the count of bits in the passed 64 byte value.</summary>
static uint8_t countBits64(ulong64_t bits);
};
#endif // __UTILS_H__

@ -0,0 +1,128 @@
daemon: true
log:
displayLevel: 1
fileLevel: 1
filePath: .
activityFilePath: .
fileRoot: DVM
network:
enable: true
id: 100000
address: 127.0.0.1
port: 62031
rconAddress: 127.0.0.1
rconPort: 9990
jitter: 360
talkgroupHang: 10
password: "PASSWORD"
slot1: true
slot2: true
transferActivityLog: false
updateLookups: false
debug: false
protocols:
dmr:
enable: true
beacons:
enable: false
interval: 60
duration: 3
embeddedLCOnly: false
dumpTAData: true
dumpDataPacket: false
repeatDataPacket: true
callHang: 5
txHang: 8
queueSize: 10000
verbose: true
debug: false
p25:
enable: true
preambleCount: 4
control:
enable: false
continuous: false
interval: 60
duration: 1
voiceOnControl: false
inhibitIllegal: false
legacyGroupGrnt: true
verifyAff: false
verifyReg: false
dumpDataPacket: false
repeatDataPacket: true
callHang: 5
noStatusAck: false
noMessageAck: true
statusCmd:
enable: true
radioCheck: 1
radioInhibit: 0
radioUninhibit: 0
radioForceReg: 0
radioForceDereg: 0
silenceThreshold: 124
queueSize: 16000
verbose: true
debug: false
system:
identity: ABCD123
timeout: 180
duplex: true
modeHang: 10
# rfModeHang: 10
# netModeHang: 10
# fixedMode: false
info:
latitude: 0.0
longitude: 0.0
height: 0
power: 10
location: "Repeater Site, USA"
config:
channelId: 2
channelNo: 1
voiceChNo:
- 1
colorCode: 5
nac: 293
pSuperGroup: FFFF
netId: BB800
sysId: 001
rfssId: 1
siteId: 1
modem:
port: null
rxInvert: false
txInvert: false
pttInvert: false
dcBlocker: true
cosLockout: false
txDelay: 1
dmrDelay: 7
rxDCOffset: 0
txDCOffset: 0
rxLevel: 50
txLevel: 50
# cwIdTxLevel: 50
# dmrTxLevel: 50
# p25TxLevel: 50
rssiMappingFile: RSSI.dat
disableOFlowReset: false
trace: false
debug: false
cwId:
enable: true
time: 15
callsign: ABCD123
iden_table:
file: iden_table.dat
time: 30
radio_id:
file: rid_acl.dat
time: 2
acl: false
talkgroup_id:
file: tg_acl.dat
time: 2
acl: false

@ -0,0 +1,13 @@
// Creates a read-only get property.
#define __READONLY_PROPERTY(type, variableName, propName)
// Creates a read-only get property, does not use "get".
#define __READONLY_PROPERTY_PLAIN(type, variableName, propName)
// Creates a read-only get property by reference.
#define __READONLY_PROPERTY_BYREF(type, variableName, propName)
// Creates a get and set property.
#define __PROPERTY(type, variableName, propName)
// Creates a get and set property, does not use "get"/"set".
#define __PROPERTY_PLAIN(type, variableName, propName)
// Creates a get and set property by reference.
#define __PROPERTY_BYREF(type, variableName, propName)

@ -0,0 +1,254 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2017 Jonathan Naylor, G4KLX
* Copyright (C) 2017,2020 by Bryan Biedenkapp <gatekeep@jmp.cx>
*
* 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 "Defines.h"
#include "dmr/Control.h"
#include "dmr/acl/AccessControl.h"
#include "dmr/lc/CSBK.h"
#include "Log.h"
using namespace dmr;
#include <cstdio>
#include <cassert>
#include <algorithm>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the Control class.
/// </summary>
/// <param name="colorCode">DMR access color code.</param>
/// <param name="callHang">Amount of hangtime for a DMR call.</param>
/// <param name="queueSize">Size of DMR data frame ring buffer.</param>
/// <param name="embeddedLCOnly"></param>
/// <param name="dumpTAData"></param>
/// <param name="timeout">Transmit timeout.</param>
/// <param name="tgHang">Amount of time to hang on the last talkgroup mode from RF.</param>
/// <param name="modem">Instance of the Modem class.</param>
/// <param name="network">Instance of the BaseNetwork class.</param>
/// <param name="duplex">Flag indicating full-duplex operation.</param>
/// <param name="ridLookup">Instance of the RadioIdLookup class.</param>
/// <param name="tidLookup">Instance of the TalkgroupIdLookup class.</param>
/// <param name="rssi">Instance of the CRSSIInterpolator class.</param>
/// <param name="jitter"></param>
/// <param name="dumpDataPacket"></param>
/// <param name="repeatDataPacket"></param>
/// <param name="debug">Flag indicating whether DMR debug is enabled.</param>
/// <param name="verbose">Flag indicating whether DMR verbose logging is enabled.</param>
Control::Control(uint32_t colorCode, uint32_t callHang, uint32_t queueSize, bool embeddedLCOnly,
bool dumpTAData, uint32_t timeout, uint32_t tgHang, modem::Modem* modem, network::BaseNetwork* network, bool duplex,
lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup, lookups::RSSIInterpolator* rssi,
uint32_t jitter, bool dumpDataPacket, bool repeatDataPacket, bool debug, bool verbose) :
m_colorCode(colorCode),
m_modem(modem),
m_network(network),
m_slot1(NULL),
m_slot2(NULL),
m_ridLookup(ridLookup),
m_tidLookup(tidLookup),
m_verbose(verbose),
m_debug(debug)
{
assert(modem != NULL);
assert(ridLookup != NULL);
assert(tidLookup != NULL);
assert(rssi != NULL);
acl::AccessControl::init(m_ridLookup, m_tidLookup);
Slot::init(colorCode, embeddedLCOnly, dumpTAData, callHang, modem, network, duplex, m_ridLookup, m_tidLookup, rssi, jitter);
m_slot1 = new Slot(1U, timeout, tgHang, queueSize, dumpDataPacket, repeatDataPacket, debug, verbose);
m_slot2 = new Slot(2U, timeout, tgHang, queueSize, dumpDataPacket, repeatDataPacket, debug, verbose);
}
/// <summary>
/// Finalizes a instance of the Control class.
/// </summary>
Control::~Control()
{
delete m_slot2;
delete m_slot1;
}
/// <summary>
/// Helper to process wakeup frames from the RF interface.
/// </summary>
/// <param name="data">DMR wakeup frame data.</param>
/// <returns>True, if wakeup frames were processed, otherwise false.</returns>
bool Control::processWakeup(const uint8_t* data)
{
assert(data != NULL);
// wakeups always come in on slot 1
if (data[0U] != TAG_DATA || data[1U] != (DMR_IDLE_RX | DMR_SYNC_DATA | DT_CSBK))
return false;
// generate a new CSBK and check validity
lc::CSBK csbk = lc::CSBK(m_debug);
bool valid = csbk.decode(data + 2U);
if (!valid)
return false;
uint8_t csbko = csbk.getCSBKO();
if (csbko != CSBKO_BSDWNACT)
return false;
uint32_t srcId = csbk.getSrcId();
// check the srcId against the ACL control
bool ret = acl::AccessControl::validateSrcId(srcId);
if (!ret) {
LogError(LOG_RF, "DMR, invalid CSBKO_BSDWNACT, srcId = %u", srcId);
return false;
}
if (m_verbose) {
LogMessage(LOG_RF, "DMR, CSBKO_BSDWNACT, srcId = %u", srcId);
}
return true;
}
/// <summary>
/// Process a data frame for slot 1, from the RF interface.
/// </summary>
/// <param name="data">DMR data frame buffer.</param>
/// <param name="len">Length of data frame buffer.</param>
/// <returns>True, if data frame was processed, otherwise false.</returns>
bool Control::processFrame1(uint8_t *data, uint32_t len)
{
assert(data != NULL);
return m_slot1->processFrame(data, len);
}
/// <summary>
/// Get a frame data for slot 1, from data ring buffer.
/// </summary>
/// <param name="data">Buffer to put retrieved DMR data frame data.</param>
/// <returns>Length of data retrieved from DMR ring buffer.</returns>
uint32_t Control::getFrame1(uint8_t* data)
{
assert(data != NULL);
return m_slot1->getFrame(data);
}
/// <summary>
/// Process a data frame for slot 2, from the RF interface.
/// </summary>
/// <param name="data">DMR data frame buffer.</param>
/// <param name="len">Length of data frame buffer.</param>
/// <returns>True, if data frame was processed, otherwise false.</returns>
bool Control::processFrame2(uint8_t *data, uint32_t len)
{
assert(data != NULL);
return m_slot2->processFrame(data, len);
}
/// <summary>
/// Get a frame data for slot 2, from data ring buffer.
/// </summary>
/// <param name="data">Buffer to put retrieved DMR data frame data.</param>
/// <returns>Length of data retrieved from DMR ring buffer.</returns>
uint32_t Control::getFrame2(uint8_t *data)
{
assert(data != NULL);
return m_slot2->getFrame(data);
}
/// <summary>
/// Updates the processor.
/// </summary>
void Control::clock()
{
if (m_network != NULL) {
data::Data data;
bool ret = m_network->readDMR(data);
if (ret) {
uint32_t slotNo = data.getSlotNo();
switch (slotNo) {
case 1U:
m_slot1->processNetwork(data);
break;
case 2U:
m_slot2->processNetwork(data);
break;
default:
LogError(LOG_NET, "DMR, invalid slot, slotNo = %u", slotNo);
break;
}
}
}
m_slot1->clock();
m_slot2->clock();
}
/// <summary>
/// Helper to write a DMR extended function packet on the RF interface.
/// </summary>
/// <param name="slotNo">DMR slot number.</param>
/// <param name="func">Extended function opcode.</param>
/// <param name="arg">Extended function argument.</param>
/// <param name="dstId">Destination radio ID.</param>
void Control::writeRF_Ext_Func(uint32_t slotNo, uint32_t func, uint32_t arg, uint32_t dstId)
{
switch (slotNo) {
case 1U:
m_slot1->writeRF_Ext_Func(func, arg, dstId);
break;
case 2U:
m_slot2->writeRF_Ext_Func(func, arg, dstId);
break;
default:
LogError(LOG_NET, "DMR, invalid slot, slotNo = %u", slotNo);
break;
}
}
/// <summary>
/// Helper to write a DMR call alert packet on the RF interface.
/// </summary>
/// <param name="slotNo">DMR slot number.</param>
/// <param name="srcId">Source radio ID.</param>
/// <param name="dstId">Destination radio ID.</param>
void Control::writeRF_Call_Alrt(uint32_t slotNo, uint32_t srcId, uint32_t dstId)
{
switch (slotNo) {
case 1U:
m_slot1->writeRF_Call_Alrt(srcId, dstId);
break;
case 2U:
m_slot2->writeRF_Call_Alrt(srcId, dstId);
break;
default:
LogError(LOG_NET, "DMR, invalid slot, slotNo = %u", slotNo);
break;
}
}

@ -0,0 +1,103 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017,2020 by Bryan Biedenkapp N2PLL
*
* 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(__DMR_CONTROL_H__)
#define __DMR_CONTROL_H__
#include "Defines.h"
#include "dmr/data/Data.h"
#include "dmr/Slot.h"
#include "modem/Modem.h"
#include "network/BaseNetwork.h"
#include "network/RemoteControl.h"
#include "lookups/RSSIInterpolator.h"
#include "lookups/RadioIdLookup.h"
#include "lookups/TalkgroupIdLookup.h"
namespace dmr
{
// ---------------------------------------------------------------------------
// Class Prototypes
// ---------------------------------------------------------------------------
class HOST_SW_API Slot;
// ---------------------------------------------------------------------------
// Class Declaration
// This class implements core logic for handling DMR.
// ---------------------------------------------------------------------------
class HOST_SW_API Control {
public:
/// <summary>Initializes a new instance of the Control class.</summary>
Control(uint32_t colorCode, uint32_t callHang, uint32_t queueSize, bool embeddedLCOnly,
bool dumpTAData, uint32_t timeout, uint32_t tgHang, modem::Modem* modem, network::BaseNetwork* network, bool duplex,
lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup, lookups::RSSIInterpolator* rssi,
uint32_t jitter, bool dumpDataPacket, bool repeatDataPacket, bool debug, bool verbose);
/// <summary>Finalizes a instance of the Control class.</summary>
~Control();
/// <summary>Helper to process wakeup frames from the RF interface.</summary>
bool processWakeup(const uint8_t* data);
/// <summary>Process a data frame for slot 1, from the RF interface.</summary>
bool processFrame1(uint8_t* data, uint32_t len);
/// <summary>Get a frame data for slot 1, from data ring buffer.</summary>
uint32_t getFrame1(uint8_t* data);
/// <summary>Process a data frame for slot 2, from the RF interface.</summary>
bool processFrame2(uint8_t* data, uint32_t len);
/// <summary>Get a frame data for slot 2, from data ring buffer.</summary>
uint32_t getFrame2(uint8_t* data);
/// <summary>Updates the processor.</summary>
void clock();
/// <summary>Helper to write a DMR extended function packet on the RF interface.</summary>
void writeRF_Ext_Func(uint32_t slotNo, uint32_t func, uint32_t arg, uint32_t dstId);
/// <summary>Helper to write a DMR call alert packet on the RF interface.</summary>
void writeRF_Call_Alrt(uint32_t slotNo, uint32_t srcId, uint32_t dstId);
private:
uint32_t m_colorCode;
modem::Modem* m_modem;
network::BaseNetwork* m_network;
Slot* m_slot1;
Slot* m_slot2;
lookups::RadioIdLookup* m_ridLookup;
lookups::TalkgroupIdLookup* m_tidLookup;
bool m_verbose;
bool m_debug;
};
} // namespace dmr
#endif // __DMR_CONTROL_H__

@ -0,0 +1,192 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2019 by Bryan Biedenkapp N2PLL
*
* 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(__DMR_DEFINES_H__)
#define __DMR_DEFINES_H__
#include "Defines.h"
namespace dmr
{
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const uint32_t DMR_FRAME_LENGTH_BITS = 264U;
const uint32_t DMR_FRAME_LENGTH_BYTES = 33U;
const uint32_t DMR_SYNC_LENGTH_BITS = 48U;
const uint32_t DMR_SYNC_LENGTH_BYTES = 6U;
const uint32_t DMR_EMB_LENGTH_BITS = 8U;
const uint32_t DMR_EMB_LENGTH_BYTES = 1U;
const uint32_t DMR_SLOT_TYPE_LENGTH_BITS = 8U;
const uint32_t DMR_SLOT_TYPE_LENGTH_BYTES = 1U;
const uint32_t DMR_EMBEDDED_SIGNALLING_LENGTH_BITS = 32U;
const uint32_t DMR_EMBEDDED_SIGNALLING_LENGTH_BYTES = 4U;
const uint32_t DMR_AMBE_LENGTH_BITS = 108U * 2U;
const uint32_t DMR_AMBE_LENGTH_BYTES = 27U;
const uint32_t DMR_LC_HEADER_LENGTH_BYTES = 12U;
const uint8_t BS_SOURCED_AUDIO_SYNC[] = { 0x07U, 0x55U, 0xFDU, 0x7DU, 0xF7U, 0x5FU, 0x70U };
const uint8_t BS_SOURCED_DATA_SYNC[] = { 0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U };
const uint8_t MS_SOURCED_AUDIO_SYNC[] = { 0x07U, 0xF7U, 0xD5U, 0xDDU, 0x57U, 0xDFU, 0xD0U };
const uint8_t MS_SOURCED_DATA_SYNC[] = { 0x0DU, 0x5DU, 0x7FU, 0x77U, 0xFDU, 0x75U, 0x70U };
const uint8_t DIRECT_SLOT1_AUDIO_SYNC[] = { 0x05U, 0xD5U, 0x77U, 0xF7U, 0x75U, 0x7FU, 0xF0U };
const uint8_t DIRECT_SLOT1_DATA_SYNC[] = { 0x0FU, 0x7FU, 0xDDU, 0x5DU, 0xDFU, 0xD5U, 0x50U };
const uint8_t DIRECT_SLOT2_AUDIO_SYNC[] = { 0x07U, 0xDFU, 0xFDU, 0x5FU, 0x55U, 0xD5U, 0xF0U };
const uint8_t DIRECT_SLOT2_DATA_SYNC[] = { 0x0DU, 0x75U, 0x57U, 0xF5U, 0xFFU, 0x7FU, 0x50U };
const uint8_t DMR_MS_DATA_SYNC_BYTES[] = { 0x0DU, 0x5DU, 0x7FU, 0x77U, 0xFDU, 0x75U, 0x70U };
const uint8_t DMR_MS_VOICE_SYNC_BYTES[] = { 0x07U, 0xF7U, 0xD5U, 0xDDU, 0x57U, 0xDFU, 0xD0U };
const uint8_t SYNC_MASK[] = { 0x0FU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xF0U };
// The PR FILL and Data Sync pattern.
const uint8_t DMR_IDLE_DATA[] = { TAG_DATA, 0x00U,
0x53U, 0xC2U, 0x5EU, 0xABU, 0xA8U, 0x67U, 0x1DU, 0xC7U, 0x38U, 0x3BU, 0xD9U,
0x36U, 0x00U, 0x0DU, 0xFFU, 0x57U, 0xD7U, 0x5DU, 0xF5U, 0xD0U, 0x03U, 0xF6U,
0xE4U, 0x65U, 0x17U, 0x1BU, 0x48U, 0xCAU, 0x6DU, 0x4FU, 0xC6U, 0x10U, 0xB4U };
// A silence frame only
const uint8_t DMR_SILENCE_DATA[] = { TAG_DATA, 0x00U,
0xB9U, 0xE8U, 0x81U, 0x52U, 0x61U, 0x73U, 0x00U, 0x2AU, 0x6BU, 0xB9U, 0xE8U,
0x81U, 0x52U, 0x60U, 0x00U, 0x00U, 0x00U, 0x00U, 0x00U, 0x01U, 0x73U, 0x00U,
0x2AU, 0x6BU, 0xB9U, 0xE8U, 0x81U, 0x52U, 0x61U, 0x73U, 0x00U, 0x2AU, 0x6BU };
const uint8_t PAYLOAD_LEFT_MASK[] = { 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xF0U };
const uint8_t PAYLOAD_RIGHT_MASK[] = { 0x0FU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU };
const uint8_t VOICE_LC_HEADER_CRC_MASK[] = { 0x96U, 0x96U, 0x96U };
const uint8_t TERMINATOR_WITH_LC_CRC_MASK[] = { 0x99U, 0x99U, 0x99U };
const uint8_t PI_HEADER_CRC_MASK[] = { 0x69U, 0x69U };
const uint8_t DATA_HEADER_CRC_MASK[] = { 0xCCU, 0xCCU };
const uint8_t CSBK_CRC_MASK[] = { 0xA5U, 0xA5U };
const uint32_t DMR_SLOT_TIME = 60U;
const uint32_t AMBE_PER_SLOT = 3U;
const uint8_t DT_MASK = 0x0FU;
const uint8_t DMR_IDLE_RX = 0x80U;
const uint8_t DMR_SYNC_DATA = 0x40U;
const uint8_t DMR_SYNC_VOICE = 0x20U;
const uint8_t DMR_SLOT1 = 0x00U;
const uint8_t DMR_SLOT2 = 0x80U;
const uint8_t DPF_UDT = 0x00U;
const uint8_t DPF_RESPONSE = 0x01U;
const uint8_t DPF_UNCONFIRMED_DATA = 0x02U;
const uint8_t DPF_CONFIRMED_DATA = 0x03U;
const uint8_t DPF_DEFINED_SHORT = 0x0DU;
const uint8_t DPF_DEFINED_RAW = 0x0EU;
const uint8_t DPF_PROPRIETARY = 0x0FU;
const uint32_t DMR_MAX_PDU_COUNT = 32U;
const uint32_t DMR_MAX_PDU_LENGTH = 512U;
const uint8_t FID_ETSI = 0x00U; // ETSI Standard Feature Set
const uint8_t FID_DMRA = 0x10U; //
const uint32_t DMR_EXT_FNCT_CHECK = 0x0000U; // Radio Check
const uint32_t DMR_EXT_FNCT_UNINHIBIT = 0x007EU; // Radio Uninhibit
const uint32_t DMR_EXT_FNCT_INHIBIT = 0x007FU; // Radio Inhibit
const uint32_t DMR_EXT_FNCT_CHECK_ACK = 0x0080U; // Radio Check Ack
const uint32_t DMR_EXT_FNCT_UNINHIBIT_ACK = 0x00FEU; // Radio Uninhibit Ack
const uint32_t DMR_EXT_FNCT_INHIBIT_ACK = 0x00FFU; // Radio Inhibit Ack
// Data Type(s)
const uint8_t DT_VOICE_PI_HEADER = 0x00U;
const uint8_t DT_VOICE_LC_HEADER = 0x01U;
const uint8_t DT_TERMINATOR_WITH_LC = 0x02U;
const uint8_t DT_CSBK = 0x03U;
const uint8_t DT_DATA_HEADER = 0x06U;
const uint8_t DT_RATE_12_DATA = 0x07U;
const uint8_t DT_RATE_34_DATA = 0x08U;
const uint8_t DT_IDLE = 0x09U;
const uint8_t DT_RATE_1_DATA = 0x0AU;
// Dummy values
const uint8_t DT_VOICE_SYNC = 0xF0U;
const uint8_t DT_VOICE = 0xF1U;
// Full-Link Control Opcode(s)
const uint8_t FLCO_GROUP = 0x00U; // GRP VCH USER - Group Voice Channel User
const uint8_t FLCO_PRIVATE = 0x03U; // UU VCH USER - Unit-to-Unit Voice Channel User
const uint8_t FLCO_TALKER_ALIAS_HEADER = 0x04U; //
const uint8_t FLCO_TALKER_ALIAS_BLOCK1 = 0x05U; //
const uint8_t FLCO_TALKER_ALIAS_BLOCK2 = 0x06U; //
const uint8_t FLCO_TALKER_ALIAS_BLOCK3 = 0x07U; //
const uint8_t FLCO_GPS_INFO = 0x08U; //
// Control Signalling Block Opcode(s)
const uint8_t CSBKO_NONE = 0x00U; //
const uint8_t CSBKO_UU_V_REQ = 0x04U; // UU VCH REQ - Unit-to-Unit Voice Channel Request
const uint8_t CSBKO_UU_ANS_RSP = 0x05U; // UU ANS RSP - Unit to Unit Answer Response
const uint8_t CSBKO_CTCSBK = 0x07U; // CT CSBK - Channel Timing CSBK
const uint8_t CSBKO_CALL_ALRT = 0x1FU; // CALL ALRT - Call Alert
const uint8_t CSBKO_ACK_RSP = 0x20U; // ACK RSP - Acknowledge Response
const uint8_t CSBKO_EXT_FNCT = 0x24U; // EXT FNCT - Extended Function
const uint8_t CSBKO_NACK_RSP = 0x26U; // NACK RSP - Negative Acknowledgement Response
const uint8_t CSBKO_BSDWNACT = 0x38U; // BS DWN ACT - BS Outbound Activation
const uint8_t CSBKO_PRECCSBK = 0x3DU; // PRE CSBK - Preamble CSBK
const uint8_t TALKER_ID_NONE = 0x00U;
const uint8_t TALKER_ID_HEADER = 0x01U;
const uint8_t TALKER_ID_BLOCK1 = 0x02U;
const uint8_t TALKER_ID_BLOCK2 = 0x04U;
const uint8_t TALKER_ID_BLOCK3 = 0x08U;
const uint32_t NO_HEADERS_SIMPLEX = 8U;
const uint32_t NO_HEADERS_DUPLEX = 3U;
const uint32_t NO_PREAMBLE_CSBK = 15U;
} // namespace dmr
// ---------------------------------------------------------------------------
// Namespace Prototypes
// ---------------------------------------------------------------------------
namespace edac { }
namespace dmr
{
namespace edac
{
using namespace ::edac;
} // namespace edac
} // namespace dmr
#endif // __DMR_DEFINES_H__

File diff suppressed because it is too large Load Diff

@ -0,0 +1,99 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017-2020 by Bryan Biedenkapp N2PLL
*
* 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(__DMR_DATA_PACKET_H__)
#define __DMR_DATA_PACKET_H__
#include "Defines.h"
#include "dmr/data/Data.h"
#include "dmr/data/EmbeddedData.h"
#include "dmr/lc/LC.h"
#include "dmr/Slot.h"
#include "edac/AMBEFEC.h"
#include "modem/Modem.h"
#include "network/BaseNetwork.h"
#include "RingBuffer.h"
#include "lookups/RadioIdLookup.h"
#include "lookups/TalkgroupIdLookup.h"
#include "StopWatch.h"
#include "Timer.h"
#include <vector>
namespace dmr
{
// ---------------------------------------------------------------------------
// Class Prototypes
// ---------------------------------------------------------------------------
class HOST_SW_API VoicePacket;
class HOST_SW_API Slot;
// ---------------------------------------------------------------------------
// Class Declaration
// This class implements core logic for handling DMR data packets.
// ---------------------------------------------------------------------------
class HOST_SW_API DataPacket {
public:
/// <summary>Process a data frame from the RF interface.</summary>
bool process(uint8_t* data, uint32_t len);
/// <summary>Process a data frame from the network.</summary>
void processNetwork(const data::Data& dmrData);
private:
friend class VoicePacket;
friend class Slot;
Slot* m_slot;
lc::LC* m_rfLC;
lc::LC* m_netLC;
uint8_t* m_pduUserData;
uint32_t m_pduDataOffset;
bool m_dumpDataPacket;
bool m_repeatDataPacket;
bool m_verbose;
bool m_debug;
/// <summary>Initializes a new instance of the DataPacket class.</summary>
DataPacket(Slot* slot, network::BaseNetwork* network, bool dumpDataPacket, bool repeatDataPacket, bool debug, bool verbose);
/// <summary>Finalizes a instance of the DataPacket class.</summary>
~DataPacket();
/// <summary>Helper to write RF end of frame data.</summary>
void writeEndRF(bool writeEnd = false);
/// <summary>Helper to write network end of frame data.</summary>
void writeEndNet(bool writeEnd = false);
};
} // namespace dmr
#endif // __DMR_DATA_PACKET_H__

@ -0,0 +1,715 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2017,2018 Jonathan Naylor, G4KLX
* Copyright (C) 2017-2020 by Bryan Biedenkapp N2PLL
*
* 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 "Defines.h"
#include "dmr/Slot.h"
#include "dmr/acl/AccessControl.h"
#include "dmr/lc/FullLC.h"
#include "dmr/lc/ShortLC.h"
#include "dmr/lc/CSBK.h"
#include "dmr/SlotType.h"
#include "dmr/Sync.h"
#include "edac/BPTC19696.h"
#include "edac/CRC.h"
#include "Log.h"
#include "Utils.h"
using namespace dmr;
#include <cassert>
#include <ctime>
#include <algorithm>
#include <cmath>
// ---------------------------------------------------------------------------
// Static Class Members
// ---------------------------------------------------------------------------
uint32_t Slot::m_colorCode = 0U;
bool Slot::m_embeddedLCOnly = false;
bool Slot::m_dumpTAData = true;
modem::Modem* Slot::m_modem = NULL;
network::BaseNetwork* Slot::m_network = NULL;
bool Slot::m_duplex = true;
lookups::RadioIdLookup* Slot::m_ridLookup = NULL;
lookups::TalkgroupIdLookup* Slot::m_tidLookup = NULL;
uint32_t Slot::m_hangCount = 3U * 17U;
lookups::RSSIInterpolator* Slot::m_rssiMapper = NULL;
uint32_t Slot::m_jitterTime = 360U;
uint32_t Slot::m_jitterSlots = 6U;
uint8_t* Slot::m_idle = NULL;
uint8_t Slot::m_flco1;
uint8_t Slot::m_id1 = 0U;
bool Slot::m_voice1 = true;
uint8_t Slot::m_flco2;
uint8_t Slot::m_id2 = 0U;
bool Slot::m_voice2 = true;
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the Slot class.
/// </summary>
/// <param name="slotNo">DMR slot number.</param>
/// <param name="queueSize">Modem frame buffer queue size (bytes).</param>
/// <param name="timeout">Transmit timeout.</param>
/// <param name="tgHang">Amount of time to hang on the last talkgroup mode from RF.</param>
/// <param name="dumpDataPacket"></param>
/// <param name="repeatDataPacket"></param>
/// <param name="debug">Flag indicating whether DMR debug is enabled.</param>
/// <param name="verbose">Flag indicating whether DMR verbose logging is enabled.</param>
Slot::Slot(uint32_t slotNo, uint32_t timeout, uint32_t tgHang, uint32_t queueSize, bool dumpDataPacket, bool repeatDataPacket,
bool debug, bool verbose) :
m_slotNo(slotNo),
m_queue(queueSize, "DMR Slot"),
m_rfState(RS_RF_LISTENING),
m_rfLastDstId(0U),
m_netState(RS_NET_IDLE),
m_netLastDstId(0U),
m_rfSeqNo(0U),
m_networkWatchdog(1000U, 0U, 1500U),
m_rfTimeoutTimer(1000U, timeout),
m_netTimeoutTimer(1000U, timeout),
m_packetTimer(1000U, 0U, 50U),
m_networkTGHang(1000U, tgHang),
m_interval(),
m_elapsed(),
m_rfFrames(0U),
m_netFrames(0U),
m_netLost(0U),
m_netMissed(0U),
m_rfBits(1U),
m_netBits(1U),
m_rfErrs(0U),
m_netErrs(0U),
m_rfTimeout(false),
m_netTimeout(false),
m_rssi(0U),
m_maxRSSI(0U),
m_minRSSI(0U),
m_aveRSSI(0U),
m_rssiCount(0U),
m_verbose(verbose),
m_debug(debug)
{
m_interval.start();
m_voice = new VoicePacket(this, m_network, m_embeddedLCOnly, m_dumpTAData, debug, verbose);
m_data = new DataPacket(this, m_network, dumpDataPacket, repeatDataPacket, debug, verbose);
}
/// <summary>
/// Finalizes a instance of the Slot class.
/// </summary>
Slot::~Slot()
{
delete m_voice;
delete m_data;
}
/// <summary>
/// Process DMR data frame from the RF interface.
/// </summary>
/// <param name="data">Buffer containing data frame.</param>
/// <param name="len">Length of data frame.</param>
/// <returns></returns>
bool Slot::processFrame(uint8_t *data, uint32_t len)
{
assert(data != NULL);
// Utils::dump(2U, "!!! *RX DMR Raw", data, len);
if (data[0U] == TAG_LOST && m_rfState == RS_RF_AUDIO) {
if (m_rssi != 0U) {
::ActivityLog("DMR", true, "Slot %u, RF voice transmission lost, %.1f seconds, BER: %.1f%%, RSSI: -%u/-%u/-%u dBm",
m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits), m_minRSSI, m_maxRSSI, m_aveRSSI / m_rssiCount);
}
else {
::ActivityLog("DMR", true, "Slot %u, RF voice transmission lost, %.1f seconds, BER: %.1f%%",
m_slotNo, float(m_rfFrames) / 16.667F, float(m_rfErrs * 100U) / float(m_rfBits));
}
LogMessage(LOG_RF, "DMR Slot %u, total frames: %d, total bits: %d, errors: %d, BER: %.4f%%",
m_slotNo, m_rfFrames, m_rfBits, m_rfErrs, float(m_rfErrs * 100U) / float(m_rfBits));
if (m_rfTimeout) {
m_data->writeEndRF();
return false;
}
else {
m_data->writeEndRF(true);
return true;
}
}
if (data[0U] == TAG_LOST && m_rfState == RS_RF_DATA) {
::ActivityLog("DMR", true, "Slot %u, RF data transmission lost", m_slotNo);
m_data->writeEndRF();
return false;
}
if (data[0U] == TAG_LOST) {
m_rfState = RS_RF_LISTENING;
m_rfLastDstId = 0U;
return false;
}
// Have we got RSSI bytes on the end?
if (len == (DMR_FRAME_LENGTH_BYTES + 4U)) {
uint16_t raw = 0U;
raw |= (data[35U] << 8) & 0xFF00U;
raw |= (data[36U] << 0) & 0x00FFU;
// Convert the raw RSSI to dBm
int rssi = m_rssiMapper->interpolate(raw);
if (m_verbose) {
LogMessage(LOG_RF, "DMR Slot %u, raw RSSI = %u, reported RSSI = %d dBm", m_slotNo, raw, rssi);
}
// RSSI is always reported as positive
m_rssi = (rssi >= 0) ? rssi : -rssi;
if (m_rssi > m_minRSSI)
m_minRSSI = m_rssi;
if (m_rssi < m_maxRSSI)
m_maxRSSI = m_rssi;
m_aveRSSI += m_rssi;
m_rssiCount++;
}
bool dataSync = (data[1U] & DMR_SYNC_DATA) == DMR_SYNC_DATA;
bool voiceSync = (data[1U] & DMR_SYNC_VOICE) == DMR_SYNC_VOICE;
if (!(dataSync || voiceSync) && m_rfState == RS_RF_LISTENING) {
if (m_verbose) {
uint8_t sync[DMR_SYNC_LENGTH_BYTES];
::memcpy(sync, data + 2U, DMR_SYNC_LENGTH_BYTES);
// count data sync errors
uint8_t dataErrs = 0U;
for (uint8_t i = 0U; i < DMR_SYNC_LENGTH_BYTES; i++)
dataErrs += Utils::countBits8(sync[i] ^ DMR_MS_DATA_SYNC_BYTES[i]);
// count voice sync errors
uint8_t voiceErrs = 0U;
for (uint8_t i = 0U; i < DMR_SYNC_LENGTH_BYTES; i++)
voiceErrs += Utils::countBits8(sync[i] ^ DMR_MS_VOICE_SYNC_BYTES[i]);
LogDebug(LOG_RF, "DMR, sync word rejected, dataErrs = %u, voiceErrs = %u", dataErrs, voiceErrs);
}
}
if ((dataSync || voiceSync) && m_debug) {
Utils::dump(1U, "!!! *RX DMR Modem Frame", data, len);
}
if ((dataSync || voiceSync) && m_rfState != RS_RF_LISTENING)
m_networkTGHang.start();
if (dataSync) {
return m_data->process(data, len);
}
return m_voice->process(data, len);
}
/// <summary>
/// Get frame data from data ring buffer.
/// </summary>
/// <param name="data">Buffer to store frame data.</param>
/// <returns>Length of frame data retreived.</returns>
uint32_t Slot::getFrame(uint8_t* data)
{
assert(data != NULL);
if (m_queue.isEmpty())
return 0U;
uint8_t len = 0U;
m_queue.getData(&len, 1U);
m_queue.getData(data, len);
return len;
}
/// <summary>
/// Process a data frame from the network.
/// </summary>
/// <param name="dmrData"></param>
void Slot::processNetwork(const data::Data& dmrData)
{
// don't process network frames if the RF modem isn't in a listening state
if (m_rfState != RS_RF_LISTENING) {
LogWarning(LOG_NET, "Traffic collision detect, preempting new network traffic to existing RF traffic!");
return;
}
m_networkWatchdog.start();
uint8_t dataType = dmrData.getDataType();
switch (dataType)
{
case DT_VOICE_LC_HEADER:
case DT_VOICE_PI_HEADER:
case DT_TERMINATOR_WITH_LC:
case DT_DATA_HEADER:
case DT_CSBK:
case DT_RATE_12_DATA:
case DT_RATE_34_DATA:
case DT_RATE_1_DATA:
m_data->processNetwork(dmrData);
break;
case DT_VOICE_SYNC:
case DT_VOICE:
default:
m_voice->processNetwork(dmrData);
}
}
/// <summary>
/// Updates the DMR slot processor.
/// </summary>
void Slot::clock()
{
uint32_t ms = m_interval.elapsed();
m_interval.start();
m_rfTimeoutTimer.clock(ms);
if (m_rfTimeoutTimer.isRunning() && m_rfTimeoutTimer.hasExpired()) {
if (!m_rfTimeout) {
LogMessage(LOG_RF, "DMR Slot %u, user has timed out", m_slotNo);
m_rfTimeout = true;
}
}
m_netTimeoutTimer.clock(ms);
if (m_netTimeoutTimer.isRunning() && m_netTimeoutTimer.hasExpired()) {
if (!m_netTimeout) {
LogMessage(LOG_NET, "DMR Slot %u, user has timed out", m_slotNo);
m_netTimeout = true;
}
}
if (m_networkTGHang.isRunning()) {
m_networkTGHang.clock(ms);
if (m_networkTGHang.hasExpired()) {
m_networkTGHang.stop();
m_rfLastDstId = 0U;
}
}
if (m_netState == RS_NET_AUDIO || m_netState == RS_NET_DATA) {
m_networkWatchdog.clock(ms);
if (m_networkWatchdog.hasExpired()) {
if (m_netState == RS_NET_AUDIO) {
// We've received the voice header haven't we?
m_netFrames += 1U;
::ActivityLog("DMR", false, "Slot %u, network watchdog has expired, %.1f seconds, %u%% packet loss, BER: %.1f%%",
m_slotNo, float(m_netFrames) / 16.667F, (m_netLost * 100U) / m_netFrames, float(m_netErrs * 100U) / float(m_netBits));
m_data->writeEndNet(true);
}
else {
::ActivityLog("DMR", false, "Slot %u, network watchdog has expired", m_slotNo);
m_data->writeEndNet();
}
}
}
if (m_netState == RS_NET_AUDIO) {
m_packetTimer.clock(ms);
if (m_packetTimer.isRunning() && m_packetTimer.hasExpired()) {
uint32_t elapsed = m_elapsed.elapsed();
if (elapsed >= m_jitterTime) {
LogWarning(LOG_NET, "DMR Slot %u, lost audio for %ums filling in", m_slotNo, elapsed);
m_voice->insertSilence(m_jitterSlots);
m_elapsed.start();
}
m_packetTimer.start();
}
}
}
/// <summary>
/// Helper to initialize the DMR slot processor.
/// </summary>
/// <param name="colorCode">DMR access color code.</param>
/// <param name="embeddedLCOnly"></param>
/// <param name="dumpTAData"></param>
/// <param name="callHang">Amount of hangtime for a DMR call.</param>
/// <param name="modem">Instance of the Modem class.</param>
/// <param name="network">Instance of the BaseNetwork class.</param>
/// <param name="duplex">Flag indicating full-duplex operation.</param>
/// <param name="ridLookup">Instance of the RadioIdLookup class.</param>
/// <param name="tidLookup">Instance of the TalkgroupIdLookup class.</param>
/// <param name="rssi">Instance of the CRSSIInterpolator class.</param>
/// <param name="jitter"></param>
void Slot::init(uint32_t colorCode, bool embeddedLCOnly, bool dumpTAData, uint32_t callHang, modem::Modem* modem,
network::BaseNetwork* network, bool duplex, lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup,
lookups::RSSIInterpolator* rssiMapper, uint32_t jitter)
{
assert(modem != NULL);
assert(ridLookup != NULL);
assert(tidLookup != NULL);
assert(rssiMapper != NULL);
m_colorCode = colorCode;
m_embeddedLCOnly = embeddedLCOnly;
m_dumpTAData = dumpTAData;
m_modem = modem;
m_network = network;
m_duplex = duplex;
m_ridLookup = ridLookup;
m_tidLookup = tidLookup;
m_hangCount = callHang * 17U;
m_rssiMapper = rssiMapper;
m_jitterTime = jitter;
float jitter_tmp = float(jitter) / 360.0F;
m_jitterSlots = (uint32_t)(std::ceil(jitter_tmp) * 6.0F);
m_idle = new uint8_t[DMR_FRAME_LENGTH_BYTES + 2U];
::memcpy(m_idle, DMR_IDLE_DATA, DMR_FRAME_LENGTH_BYTES + 2U);
// Generate the Slot Type for the Idle frame
SlotType slotType;
slotType.setColorCode(colorCode);
slotType.setDataType(DT_IDLE);
slotType.encode(m_idle + 2U);
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Write data processed from RF to the data ring buffer.
/// </summary>
/// <param name="data"></param>
void Slot::writeQueueRF(const uint8_t *data)
{
assert(data != NULL);
if (m_netState != RS_NET_IDLE)
return;
uint8_t len = DMR_FRAME_LENGTH_BYTES + 2U;
uint32_t space = m_queue.freeSpace();
if (space < (len + 1U)) {
uint32_t queueLen = m_queue.length();
m_queue.resize(queueLen + 2500);
LogError(LOG_DMR, "Slot %u, overflow in the DMR slot RF queue; queue resized was %u is %u", m_slotNo, queueLen, m_queue.length());
return;
}
m_queue.addData(&len, 1U);
m_queue.addData(data, len);
}
/// <summary>
/// Write data processed from the network to the data ring buffer.
/// </summary>
/// <param name="data"></param>
void Slot::writeQueueNet(const uint8_t *data)
{
assert(data != NULL);
uint8_t len = DMR_FRAME_LENGTH_BYTES + 2U;
uint32_t space = m_queue.freeSpace();
if (space < (len + 1U)) {
LogError(LOG_DMR, "Slot %u, overflow in the DMR slot RF queue", m_slotNo);
return;
}
m_queue.addData(&len, 1U);
m_queue.addData(data, len);
}
/// <summary>
/// Write data processed from RF to the network.
/// </summary>
/// <param name="data"></param>
/// <param name="dataType"></param>
/// <param name="errors"></param>
void Slot::writeNetworkRF(const uint8_t* data, uint8_t dataType, uint8_t errors)
{
assert(data != NULL);
assert(m_data->m_rfLC != NULL);
writeNetworkRF(data, dataType, m_data->m_rfLC->getFLCO(), m_data->m_rfLC->getSrcId(), m_data->m_rfLC->getDstId(), errors);
}
/// <summary>
/// Write data processed from RF to the network.
/// </summary>
/// <param name="data"></param>
/// <param name="dataType"></param>
/// <param name="flco"></param>
/// <param name="srcId"></param>
/// <param name="dstId"></param>
/// <param name="errors"></param>
void Slot::writeNetworkRF(const uint8_t* data, uint8_t dataType, uint8_t flco, uint32_t srcId,
uint32_t dstId, uint8_t errors)
{
assert(data != NULL);
if (m_netState != RS_NET_IDLE)
return;
if (m_network == NULL)
return;
data::Data dmrData;
dmrData.setSlotNo(m_slotNo);
dmrData.setDataType(dataType);
dmrData.setSrcId(srcId);
dmrData.setDstId(dstId);
dmrData.setFLCO(flco);
dmrData.setN(m_voice->m_rfN);
dmrData.setSeqNo(m_rfSeqNo);
dmrData.setBER(errors);
dmrData.setRSSI(m_rssi);
m_rfSeqNo++;
dmrData.setData(data + 2U);
m_network->writeDMR(dmrData);
}
/// <summary>
/// Helper to write a extended function packet on the RF interface.
/// </summary>
/// <param name="func">Extended function opcode.</param>
/// <param name="arg">Extended function argument.</param>
/// <param name="dstId">Destination radio ID.</param>
void Slot::writeRF_Ext_Func(uint32_t func, uint32_t arg, uint32_t dstId)
{
if (m_verbose) {
LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_EXT_FNCT (Extended Function), op = $%02X, arg = %u, tgt = %u",
m_slotNo, func, arg, dstId);
}
// generate activity log entry
if (func == DMR_EXT_FNCT_CHECK) {
::ActivityLog("DMR", true, "Slot %u received radio check request from %u to %u", m_slotNo, arg, dstId);
}
else if (func == DMR_EXT_FNCT_INHIBIT) {
::ActivityLog("DMR", true, "Slot %u received radio inhibit request from %u to %u", m_slotNo, arg, dstId);
}
else if (func == DMR_EXT_FNCT_UNINHIBIT) {
::ActivityLog("DMR", true, "Slot %u received radio uninhibit request from %u to %u", m_slotNo, arg, dstId);
}
uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U];
::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES);
SlotType slotType;
slotType.setColorCode(m_colorCode);
slotType.setDataType(DT_CSBK);
lc::CSBK csbk = lc::CSBK(false);
csbk.setCSBKO(CSBKO_EXT_FNCT);
csbk.setFID(FID_DMRA);
csbk.setGI(false);
csbk.setCBF(func);
csbk.setSrcId(arg);
csbk.setDstId(dstId);
// Regenerate the CSBK data
csbk.encode(data + 2U);
// Regenerate the Slot Type
slotType.encode(data + 2U);
// Convert the Data Sync to be from the BS or MS as needed
Sync::addDMRDataSync(data + 2U, m_duplex);
m_rfSeqNo = 0U;
data[0U] = TAG_DATA;
data[1U] = 0x00U;
if (m_duplex)
writeQueueRF(data);
}
/// <summary>
/// Helper to write a call alert packet on the RF interface.
/// </summary>
/// <param name="srcId">Source radio ID.</param>
/// <param name="dstId">Destination radio ID.</param>
void Slot::writeRF_Call_Alrt(uint32_t srcId, uint32_t dstId)
{
if (m_verbose) {
LogMessage(LOG_RF, "DMR Slot %u, DT_CSBK, CSBKO_CALL_ALRT (Call Alert), src = %u, dst = %u",
m_slotNo, srcId, dstId);
}
::ActivityLog("DMR", true, "Slot %u received call alert request from %u to %u", m_slotNo, srcId, dstId);
uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U];
::memset(data + 2U, 0x00U, DMR_FRAME_LENGTH_BYTES);
SlotType slotType;
slotType.setColorCode(m_colorCode);
slotType.setDataType(DT_CSBK);
lc::CSBK csbk = lc::CSBK(false);
csbk.setCSBKO(CSBKO_CALL_ALRT);
csbk.setFID(FID_DMRA);
csbk.setGI(false);
csbk.setSrcId(srcId);
csbk.setDstId(dstId);
// Regenerate the CSBK data
csbk.encode(data + 2U);
// Regenerate the Slot Type
slotType.encode(data + 2U);
// Convert the Data Sync to be from the BS or MS as needed
Sync::addDMRDataSync(data + 2U, m_duplex);
m_rfSeqNo = 0U;
data[0U] = TAG_DATA;
data[1U] = 0x00U;
if (m_duplex)
writeQueueRF(data);
}
/// <summary>
///
/// </summary>
/// <param name="slotNo"></param>
/// <param name="id"></param>
/// <param name="flco"></param>
/// <param name="voice"></param>
void Slot::setShortLC(uint32_t slotNo, uint32_t id, uint8_t flco, bool voice)
{
assert(m_modem != NULL);
switch (slotNo) {
case 1U:
m_id1 = 0U;
m_flco1 = flco;
m_voice1 = voice;
if (id != 0U) {
uint8_t buffer[3U];
buffer[0U] = (id << 16) & 0xFFU;
buffer[1U] = (id << 8) & 0xFFU;
buffer[2U] = (id << 0) & 0xFFU;
m_id1 = edac::CRC::crc8(buffer, 3U);
}
break;
case 2U:
m_id2 = 0U;
m_flco2 = flco;
m_voice2 = voice;
if (id != 0U) {
uint8_t buffer[3U];
buffer[0U] = (id << 16) & 0xFFU;
buffer[1U] = (id << 8) & 0xFFU;
buffer[2U] = (id << 0) & 0xFFU;
m_id2 = edac::CRC::crc8(buffer, 3U);
}
break;
default:
LogError(LOG_DMR, "invalid slot number passed to setShortLC, slotNo = %u", slotNo);
return;
}
// If we have no activity to report, let the modem send the null Short LC when it's ready
if (m_id1 == 0U && m_id2 == 0U)
return;
uint8_t lc[5U];
lc[0U] = 0x01U;
lc[1U] = 0x00U;
lc[2U] = 0x00U;
lc[3U] = 0x00U;
if (m_id1 != 0U) {
lc[2U] = m_id1;
if (m_voice1) {
if (m_flco1 == FLCO_GROUP)
lc[1U] |= 0x80U;
else
lc[1U] |= 0x90U;
}
else {
if (m_flco1 == FLCO_GROUP)
lc[1U] |= 0xB0U;
else
lc[1U] |= 0xA0U;
}
}
if (m_id2 != 0U) {
lc[3U] = m_id2;
if (m_voice2) {
if (m_flco2 == FLCO_GROUP)
lc[1U] |= 0x08U;
else
lc[1U] |= 0x09U;
}
else {
if (m_flco2 == FLCO_GROUP)
lc[1U] |= 0x0BU;
else
lc[1U] |= 0x0AU;
}
}
lc[4U] = edac::CRC::crc8(lc, 4U);
uint8_t sLC[9U];
lc::ShortLC shortLC;
shortLC.encode(lc, sLC);
m_modem->writeDMRShortLC(sLC);
}

@ -0,0 +1,186 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017-2020 by Bryan Biedenkapp N2PLL
*
* 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(__DMR_SLOT_H__)
#define __DMR_SLOT_H__
#include "Defines.h"
#include "dmr/Control.h"
#include "dmr/DataPacket.h"
#include "dmr/VoicePacket.h"
#include "modem/Modem.h"
#include "network/BaseNetwork.h"
#include "lookups/RSSIInterpolator.h"
#include "lookups/RadioIdLookup.h"
#include "lookups/TalkgroupIdLookup.h"
#include "RingBuffer.h"
#include "StopWatch.h"
#include "Timer.h"
#include <vector>
namespace dmr
{
// ---------------------------------------------------------------------------
// Class Prototypes
// ---------------------------------------------------------------------------
class HOST_SW_API Control;
class HOST_SW_API VoicePacket;
class HOST_SW_API DataPacket;
// ---------------------------------------------------------------------------
// Class Declaration
// This class implements core logic for handling DMR slots.
// ---------------------------------------------------------------------------
class HOST_SW_API Slot {
public:
/// <summary>Initializes a new instance of the Slot class.</summary>
Slot(uint32_t slotNo, uint32_t timeout, uint32_t tgHang, uint32_t queueSize, bool dumpDataPacket, bool repeatDataPacket,
bool debug, bool verbose);
/// <summary>Finalizes a instance of the Slot class.</summary>
~Slot();
/// <summary>Process a data frame from the RF interface.</summary>
bool processFrame(uint8_t* data, uint32_t len);
/// <summary>Get frame data from data ring buffer.</summary>
uint32_t getFrame(uint8_t* data);
/// <summary>Process a data frames from the network.</summary>
void processNetwork(const data::Data& data);
/// <summary>Updates the slot processor.</summary>
void clock();
/// <summary>Helper to initialize the slot processor.</summary>
static void init(uint32_t colorCode, bool embeddedLCOnly, bool dumpTAData, uint32_t callHang, modem::Modem* modem,
network::BaseNetwork* network, bool duplex, lookups::RadioIdLookup* ridLookup, lookups::TalkgroupIdLookup* tidLookup,
lookups::RSSIInterpolator* rssiMapper, uint32_t jitter);
private:
friend class Control;
friend class VoicePacket;
VoicePacket* m_voice;
friend class DataPacket;
DataPacket* m_data;
uint32_t m_slotNo;
RingBuffer<uint8_t> m_queue;
RPT_RF_STATE m_rfState;
uint32_t m_rfLastDstId;
RPT_NET_STATE m_netState;
uint32_t m_netLastDstId;
uint8_t m_rfSeqNo;
Timer m_networkWatchdog;
Timer m_rfTimeoutTimer;
Timer m_netTimeoutTimer;
Timer m_packetTimer;
Timer m_networkTGHang;
StopWatch m_interval;
StopWatch m_elapsed;
uint32_t m_rfFrames;
uint32_t m_netFrames;
uint32_t m_netLost;
uint32_t m_netMissed;
uint32_t m_rfBits;
uint32_t m_netBits;
uint32_t m_rfErrs;
uint32_t m_netErrs;
bool m_rfTimeout;
bool m_netTimeout;
uint8_t m_rssi;
uint8_t m_maxRSSI;
uint8_t m_minRSSI;
uint32_t m_aveRSSI;
uint32_t m_rssiCount;
bool m_verbose;
bool m_debug;
static uint32_t m_colorCode;
static bool m_embeddedLCOnly;
static bool m_dumpTAData;
static modem::Modem* m_modem;
static network::BaseNetwork* m_network;
static bool m_duplex;
static lookups::RadioIdLookup* m_ridLookup;
static lookups::TalkgroupIdLookup* m_tidLookup;
static uint32_t m_hangCount;
static lookups::RSSIInterpolator* m_rssiMapper;
static uint32_t m_jitterTime;
static uint32_t m_jitterSlots;
static uint8_t* m_idle;
static uint8_t m_flco1;
static uint8_t m_id1;
static bool m_voice1;
static uint8_t m_flco2;
static uint8_t m_id2;
static bool m_voice2;
/// <summary>Write data processed from RF to the data ring buffer.</summary>
void writeQueueRF(const uint8_t* data);
/// <summary>Write data processed from the network to the data ring buffer.</summary>
void writeQueueNet(const uint8_t* data);
/// <summary>Write data processed from RF to the network.</summary>
void writeNetworkRF(const uint8_t* data, uint8_t dataType, uint8_t errors = 0U);
/// <summary>Write data processed from RF to the network.</summary>
void writeNetworkRF(const uint8_t* data, uint8_t dataType, uint8_t flco, uint32_t srcId,
uint32_t dstId, uint8_t errors = 0U);
/// <summary>Helper to write a extended function packet on the RF interface.</summary>
void writeRF_Ext_Func(uint32_t func, uint32_t arg, uint32_t dstId);
/// <summary>Helper to write a call alert packet on the RF interface.</summary>
void writeRF_Call_Alrt(uint32_t srcId, uint32_t dstId);
/// <summary></summary>
static void setShortLC(uint32_t slotNo, uint32_t id, uint8_t flco = FLCO_GROUP, bool voice = true);
};
} // namespace dmr
#endif // __DMR_SLOT_H__

@ -0,0 +1,104 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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 "Defines.h"
#include "dmr/SlotType.h"
#include "edac/Golay2087.h"
using namespace dmr;
#include <cstdio>
#include <cassert>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the SlotType class.
/// </summary>
SlotType::SlotType() :
m_colorCode(0U),
m_dataType(0U)
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the SlotType class.
/// </summary>
SlotType::~SlotType()
{
/* stub */
}
/// <summary>
/// Decodes DMR slot type.
/// </summary>
/// <param name="data"></param>
void SlotType::decode(const uint8_t* data)
{
assert(data != NULL);
uint8_t DMRSlotType[3U];
DMRSlotType[0U] = (data[12U] << 2) & 0xFCU;
DMRSlotType[0U] |= (data[13U] >> 6) & 0x03U;
DMRSlotType[1U] = (data[13U] << 2) & 0xC0U;
DMRSlotType[1U] |= (data[19U] << 2) & 0x3CU;
DMRSlotType[1U] |= (data[20U] >> 6) & 0x03U;
DMRSlotType[2U] = (data[20U] << 2) & 0xF0U;
uint8_t code = edac::Golay2087::decode(DMRSlotType);
m_colorCode = (code >> 4) & 0x0FU;
m_dataType = (code >> 0) & 0x0FU;
}
/// <summary>
/// Encodes DMR slot type.
/// </summary>
/// <param name="data"></param>
void SlotType::encode(uint8_t* data) const
{
assert(data != NULL);
uint8_t DMRSlotType[3U];
DMRSlotType[0U] = (m_colorCode << 4) & 0xF0U;
DMRSlotType[0U] |= (m_dataType << 0) & 0x0FU;
DMRSlotType[1U] = 0x00U;
DMRSlotType[2U] = 0x00U;
edac::Golay2087::encode(DMRSlotType);
data[12U] = (data[12U] & 0xC0U) | ((DMRSlotType[0U] >> 2) & 0x3FU);
data[13U] = (data[13U] & 0x0FU) | ((DMRSlotType[0U] << 6) & 0xC0U) | ((DMRSlotType[1U] >> 2) & 0x30U);
data[19U] = (data[19U] & 0xF0U) | ((DMRSlotType[1U] >> 2) & 0x0FU);
data[20U] = (data[20U] & 0x03U) | ((DMRSlotType[1U] << 6) & 0xC0U) | ((DMRSlotType[2U] >> 2) & 0x3CU);
}

@ -0,0 +1,63 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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(__DMR_SLOT_TYPE_H__)
#define __DMR_SLOT_TYPE_H__
#include "Defines.h"
namespace dmr
{
// ---------------------------------------------------------------------------
// Class Declaration
// Represents DMR slot type.
// ---------------------------------------------------------------------------
class HOST_SW_API SlotType {
public:
/// <summary>Initializes a new instance of the SlotType class.</summary>
SlotType();
/// <summary>Finalizes a instance of the SlotType class.</summary>
~SlotType();
/// <summary>Decodes DMR slot type.</summary>
void decode(const uint8_t* data);
/// <summary>Encodes DMR slot type.</summary>
void encode(uint8_t* data) const;
public:
/// <summary>DMR access color code.</summary>
__PROPERTY(uint8_t, colorCode, ColorCode);
/// <summary></summary>
__PROPERTY(uint8_t, dataType, DataType);
};
} // namespace dmr
#endif // __DMR_SLOT_TYPE_H__

@ -0,0 +1,79 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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 "Defines.h"
#include "dmr/DMRDefines.h"
#include "dmr/Sync.h"
using namespace dmr;
#include <cstdio>
#include <cassert>
#include <cstring>
// ---------------------------------------------------------------------------
// Static Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Helper to append DMR data sync bytes to the passed buffer.
/// </summary>
/// <param name="data">Buffer to append sync bytes to.</param>
/// <param name="duplex">Flag indicating whether this is duplex operation.</param>
void Sync::addDMRDataSync(uint8_t* data, bool duplex)
{
assert(data != NULL);
if (duplex) {
for (uint32_t i = 0U; i < 7U; i++)
data[i + 13U] = (data[i + 13U] & ~SYNC_MASK[i]) | BS_SOURCED_DATA_SYNC[i];
}
else {
for (uint32_t i = 0U; i < 7U; i++)
data[i + 13U] = (data[i + 13U] & ~SYNC_MASK[i]) | MS_SOURCED_DATA_SYNC[i];
}
}
/// <summary>
/// Helper to append DMR voice sync bytes to the passed buffer.
/// </summary>
/// <param name="data">Buffer to append sync bytes to.</param>
/// <param name="duplex">Flag indicating whether this is duplex operation.</param>
void Sync::addDMRAudioSync(uint8_t* data, bool duplex)
{
assert(data != NULL);
if (duplex) {
for (uint32_t i = 0U; i < 7U; i++)
data[i + 13U] = (data[i + 13U] & ~SYNC_MASK[i]) | BS_SOURCED_AUDIO_SYNC[i];
}
else {
for (uint32_t i = 0U; i < 7U; i++)
data[i + 13U] = (data[i + 13U] & ~SYNC_MASK[i]) | MS_SOURCED_AUDIO_SYNC[i];
}
}

@ -0,0 +1,51 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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(__DMR_SYNC_H__)
#define __DMR_SYNC_H__
#include "Defines.h"
namespace dmr
{
// ---------------------------------------------------------------------------
// Class Declaration
// Helper class for generating DMR sync data.
// ---------------------------------------------------------------------------
class HOST_SW_API Sync {
public:
/// <summary>Helper to append DMR data sync bytes to the passed buffer.</summary>
static void addDMRDataSync(uint8_t* data, bool duplex);
/// <summary>Helper to append DMR voice sync bytes to the passed buffer.</summary>
static void addDMRAudioSync(uint8_t* data, bool duplex);
};
} // namespace dmr
#endif // __DMR_SYNC_H__

@ -0,0 +1,849 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2017,2018 Jonathan Naylor, G4KLX
* Copyright (C) 2017-2019 by Bryan Biedenkapp N2PLL
*
* 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 "Defines.h"
#include "dmr/VoicePacket.h"
#include "dmr/acl/AccessControl.h"
#include "dmr/data/DataHeader.h"
#include "dmr/data/EMB.h"
#include "dmr/edac/Trellis.h"
#include "dmr/lc/CSBK.h"
#include "dmr/lc/ShortLC.h"
#include "dmr/lc/FullLC.h"
#include "dmr/SlotType.h"
#include "dmr/Sync.h"
#include "edac/BPTC19696.h"
#include "edac/CRC.h"
#include "Log.h"
#include "Utils.h"
using namespace dmr;
#include <cassert>
#include <ctime>
#include <algorithm>
#include <cmath>
// ---------------------------------------------------------------------------
// Macros
// ---------------------------------------------------------------------------
#define CHECK_TRAFFIC_COLLISION_DELLC(_DST_ID) \
if (m_slot->m_netState != RS_NET_IDLE && _DST_ID == m_slot->m_netLastDstId) { \
LogWarning(LOG_RF, "DMR Slot %u, Traffic collision detect, preempting new RF traffic to existing network traffic!", m_slot->m_slotNo); \
delete lc; \
return false; \
}
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Process DMR voice frame from the RF interface.
/// </summary>
/// <param name="data">Buffer containing data frame.</param>
/// <param name="len">Length of data frame.</param>
/// <returns></returns>
bool VoicePacket::process(uint8_t* data, uint32_t len)
{
assert(data != NULL);
bool voiceSync = (data[1U] & DMR_SYNC_VOICE) == DMR_SYNC_VOICE;
if (voiceSync) {
if (m_slot->m_rfState == RS_RF_AUDIO) {
m_lastRfN = 0U;
// Convert the Audio Sync to be from the BS or MS as needed
Sync::addDMRAudioSync(data + 2U, m_slot->m_duplex);
uint32_t errors = 0U;
uint8_t fid = m_slot->m_data->m_rfLC->getFID();
if (fid == FID_ETSI || fid == FID_DMRA) {
errors = m_fec.regenerateDMR(data + 2U);
if (m_verbose) {
LogMessage(LOG_RF, "DMR Slot %u, DMR_SYNC_VOICE audio, sequence no = 0, errs = %u/141 (%.1f%%)",
m_slot->m_slotNo, errors, float(errors) / 1.41F);
}
m_slot->m_rfErrs += errors;
}
m_slot->m_rfBits += 141U;
m_slot->m_rfFrames++;
m_rfEmbeddedReadN = (m_rfEmbeddedReadN + 1U) % 2U;
m_rfEmbeddedWriteN = (m_rfEmbeddedWriteN + 1U) % 2U;
m_rfEmbeddedData[m_rfEmbeddedWriteN].reset();
if (!m_slot->m_rfTimeout) {
data[0U] = TAG_DATA;
data[1U] = 0x00U;
if (m_slot->m_duplex)
m_slot->writeQueueRF(data);
m_slot->writeNetworkRF(data, DT_VOICE_SYNC, errors);
return true;
}
return false;
}
else if (m_slot->m_rfState == RS_RF_LISTENING) {
m_rfEmbeddedLC.reset();
m_slot->m_rfState = RS_RF_LATE_ENTRY;
return false;
}
}
else {
if (m_slot->m_rfState == RS_RF_AUDIO) {
m_rfN = data[1U] & 0x0FU;
if (m_rfN > 5U)
return false;
if (m_rfN == m_lastRfN)
return false;
if (m_rfN != (m_lastRfN + 1U))
return false;
m_lastRfN = m_rfN;
uint32_t errors = 0U;
uint8_t fid = m_slot->m_data->m_rfLC->getFID();
if (fid == FID_ETSI || fid == FID_DMRA) {
errors = m_fec.regenerateDMR(data + 2U);
if (m_verbose) {
LogMessage(LOG_RF, "DMR Slot %u, DMR_SYNC_VOICE audio, sequence no = %u, errs = %u/141 (%.1f%%)",
m_slot->m_slotNo, m_rfN, errors, float(errors) / 1.41F);
}
m_slot->m_rfErrs += errors;
}
m_slot->m_rfBits += 141U;
m_slot->m_rfFrames++;
// Get the LCSS from the EMB
data::EMB emb;
emb.decode(data + 2U);
uint8_t lcss = emb.getLCSS();
// Dump any interesting Embedded Data
bool ret = m_rfEmbeddedData[m_rfEmbeddedWriteN].addData(data + 2U, lcss);
if (ret) {
uint8_t flco = m_rfEmbeddedData[m_rfEmbeddedWriteN].getFLCO();
uint8_t data[9U];
m_rfEmbeddedData[m_rfEmbeddedWriteN].getRawData(data);
char text[80U];
switch (flco) {
case FLCO_GROUP:
case FLCO_PRIVATE:
// ::sprintf(text, "DMR Slot %u, Embedded LC", m_slotNo);
// Utils::dump(1U, text, data, 9U);
break;
case FLCO_GPS_INFO:
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, FLCO_GPS_INFO (Embedded GPS Info)", m_slot->m_slotNo);
Utils::dump(2U, text, data, 9U);
}
if (m_verbose) {
logGPSPosition(m_slot->m_data->m_rfLC->getSrcId(), data);
}
break;
case FLCO_TALKER_ALIAS_HEADER:
if (!(m_rfTalkerId & TALKER_ID_HEADER)) {
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, FLCO_TALKER_ALIAS_HEADER (Embedded Talker Alias Header)", m_slot->m_slotNo);
Utils::dump(2U, text, data, 9U);
}
m_rfTalkerId |= TALKER_ID_HEADER;
}
break;
case FLCO_TALKER_ALIAS_BLOCK1:
if (!(m_rfTalkerId & TALKER_ID_BLOCK1)) {
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, FLCO_TALKER_ALIAS_BLOCK1 (Embedded Talker Alias Block 1)", m_slot->m_slotNo);
Utils::dump(2U, text, data, 9U);
}
m_rfTalkerId |= TALKER_ID_BLOCK1;
}
break;
case FLCO_TALKER_ALIAS_BLOCK2:
if (!(m_rfTalkerId & TALKER_ID_BLOCK2)) {
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, FLCO_TALKER_ALIAS_BLOCK2 (Embedded Talker Alias Block 2)", m_slot->m_slotNo);
Utils::dump(2U, text, data, 9U);
}
m_rfTalkerId |= TALKER_ID_BLOCK2;
}
break;
case FLCO_TALKER_ALIAS_BLOCK3:
if (!(m_rfTalkerId & TALKER_ID_BLOCK3)) {
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, FLCO_TALKER_ALIAS_BLOCK3 (Embedded Talker Alias Block 3)", m_slot->m_slotNo);
Utils::dump(2U, text, data, 9U);
}
m_rfTalkerId |= TALKER_ID_BLOCK3;
}
break;
default:
::sprintf(text, "DMR Slot %u, Unknown Embedded Data", m_slot->m_slotNo);
Utils::dump(1U, text, data, 9U);
break;
}
}
// Regenerate the previous super blocks Embedded Data or substitude the LC for it
if (m_rfEmbeddedData[m_rfEmbeddedReadN].isValid())
lcss = m_rfEmbeddedData[m_rfEmbeddedReadN].getData(data + 2U, m_rfN);
else
lcss = m_rfEmbeddedLC.getData(data + 2U, m_rfN);
// Regenerate the EMB
emb.setColorCode(m_slot->m_colorCode);
emb.setLCSS(lcss);
emb.encode(data + 2U);
if (!m_slot->m_rfTimeout) {
data[0U] = TAG_DATA;
data[1U] = 0x00U;
m_slot->writeNetworkRF(data, DT_VOICE, errors);
if (m_embeddedLCOnly) {
// Only send the previously received LC
lcss = m_rfEmbeddedLC.getData(data + 2U, m_rfN);
// Regenerate the EMB
emb.setColorCode(m_slot->m_colorCode);
emb.setLCSS(lcss);
emb.encode(data + 2U);
}
if (m_slot->m_duplex)
m_slot->writeQueueRF(data);
return true;
}
return false;
}
else if (m_slot->m_rfState == RS_RF_LATE_ENTRY) {
data::EMB emb;
emb.decode(data + 2U);
// If we haven't received an LC yet, then be strict on the color code
uint8_t colorCode = emb.getColorCode();
if (colorCode != m_slot->m_colorCode)
return false;
m_rfEmbeddedLC.addData(data + 2U, emb.getLCSS());
lc::LC* lc = m_rfEmbeddedLC.getLC();
if (lc != NULL) {
uint32_t srcId = lc->getSrcId();
uint32_t dstId = lc->getDstId();
uint8_t flco = lc->getFLCO();
CHECK_TRAFFIC_COLLISION_DELLC(dstId);
// validate the source RID
if (!acl::AccessControl::validateSrcId(srcId)) {
LogWarning(LOG_RF, "DMR Slot %u, DMR_DATA_SYNC denial, RID rejection, srcId = %u", m_slot->m_slotNo, srcId);
delete lc;
return false;
}
// validate the target ID, if the target is a talkgroup
if (flco == FLCO_GROUP) {
if (!acl::AccessControl::validateTGId(m_slot->m_slotNo, dstId)) {
LogWarning(LOG_RF, "DMR Slot %u, DMR_DATA_SYNC denial, TGID rejection, srcId = %u, dstId = %u", m_slot->m_slotNo, srcId, dstId);
delete lc;
return false;
}
}
m_slot->m_data->m_rfLC = lc;
// The standby LC data
m_rfEmbeddedLC.setLC(*m_slot->m_data->m_rfLC);
m_rfEmbeddedData[0U].setLC(*m_slot->m_data->m_rfLC);
m_rfEmbeddedData[1U].setLC(*m_slot->m_data->m_rfLC);
// Create a dummy start frame to replace the received frame
uint8_t start[DMR_FRAME_LENGTH_BYTES + 2U];
Sync::addDMRDataSync(start + 2U, m_slot->m_duplex);
lc::FullLC fullLC;
fullLC.encode(*m_slot->m_data->m_rfLC, start + 2U, DT_VOICE_LC_HEADER);
SlotType slotType;
slotType.setColorCode(m_slot->m_colorCode);
slotType.setDataType(DT_VOICE_LC_HEADER);
slotType.encode(start + 2U);
start[0U] = TAG_DATA;
start[1U] = 0x00U;
m_slot->m_rfTimeoutTimer.start();
m_slot->m_rfTimeout = false;
m_slot->m_rfFrames = 0U;
m_slot->m_rfSeqNo = 0U;
m_slot->m_rfBits = 1U;
m_slot->m_rfErrs = 0U;
m_rfEmbeddedReadN = 0U;
m_rfEmbeddedWriteN = 1U;
m_rfTalkerId = TALKER_ID_NONE;
m_slot->m_minRSSI = m_slot->m_rssi;
m_slot->m_maxRSSI = m_slot->m_rssi;
m_slot->m_aveRSSI = m_slot->m_rssi;
m_slot->m_rssiCount = 1U;
if (m_slot->m_duplex) {
m_slot->m_queue.clear();
m_slot->m_modem->writeDMRAbort(m_slot->m_slotNo);
for (uint32_t i = 0U; i < NO_HEADERS_DUPLEX; i++)
m_slot->writeQueueRF(start);
}
m_slot->writeNetworkRF(start, DT_VOICE_LC_HEADER);
m_rfN = data[1U] & 0x0FU;
if (m_rfN > 5U)
return false;
if (m_rfN == m_lastRfN)
return false;
m_lastRfN = m_rfN;
// Regenerate the EMB
emb.encode(data + 2U);
// Send the original audio frame out
uint32_t errors = 0U;
uint8_t fid = m_slot->m_data->m_rfLC->getFID();
if (fid == FID_ETSI || fid == FID_DMRA) {
errors = m_fec.regenerateDMR(data + 2U);
if (m_verbose) {
LogMessage(LOG_RF, "DMR Slot %u, DMR_AUDIO_SYNC audio, sequence no = %u, errs = %u/141 (%.1f%%)",
m_slot->m_slotNo, m_rfN, errors, float(errors) / 1.41F);
}
m_slot->m_rfErrs += errors;
}
m_slot->m_rfBits += 141U;
m_slot->m_rfFrames++;
data[0U] = TAG_DATA;
data[1U] = 0x00U;
if (m_slot->m_duplex)
m_slot->writeQueueRF(data);
m_slot->writeNetworkRF(data, DT_VOICE, errors);
m_slot->m_rfState = RS_RF_AUDIO;
m_slot->m_rfLastDstId = dstId;
if (m_slot->m_netState == RS_NET_IDLE) {
m_slot->setShortLC(m_slot->m_slotNo, dstId, flco, true);
}
::ActivityLog("DMR", true, "Slot %u, received RF late entry from %u to %s%u", m_slot->m_slotNo, srcId, flco == FLCO_GROUP ? "TG " : "", dstId);
return true;
}
}
}
return false;
}
/// <summary>
/// Process a voice frame from the network.
/// </summary>
/// <param name="dmrData"></param>
void VoicePacket::processNetwork(const data::Data& dmrData)
{
uint8_t dataType = dmrData.getDataType();
uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U];
dmrData.getData(data + 2U);
if (dataType == DT_VOICE_SYNC) {
if (m_slot->m_netState == RS_NET_IDLE) {
lc::LC* lc = new lc::LC(dmrData.getFLCO(), dmrData.getSrcId(), dmrData.getDstId());
uint32_t dstId = lc->getDstId();
uint32_t srcId = lc->getSrcId();
m_slot->m_data->m_netLC = lc;
// The standby LC data
m_netEmbeddedLC.setLC(*m_slot->m_data->m_netLC);
m_netEmbeddedData[0U].setLC(*m_slot->m_data->m_netLC);
m_netEmbeddedData[1U].setLC(*m_slot->m_data->m_netLC);
m_lastFrameValid = false;
m_slot->m_netTimeoutTimer.start();
m_slot->m_netTimeout = false;
if (m_slot->m_duplex) {
m_slot->m_queue.clear();
m_slot->m_modem->writeDMRAbort(m_slot->m_slotNo);
}
for (uint32_t i = 0U; i < m_slot->m_jitterSlots; i++)
m_slot->writeQueueNet(m_slot->m_idle);
// Create a dummy start frame
uint8_t start[DMR_FRAME_LENGTH_BYTES + 2U];
Sync::addDMRDataSync(start + 2U, m_slot->m_duplex);
lc::FullLC fullLC;
fullLC.encode(*m_slot->m_data->m_netLC, start + 2U, DT_VOICE_LC_HEADER);
SlotType slotType;
slotType.setColorCode(m_slot->m_colorCode);
slotType.setDataType(DT_VOICE_LC_HEADER);
slotType.encode(start + 2U);
start[0U] = TAG_DATA;
start[1U] = 0x00U;
if (m_slot->m_duplex) {
for (uint32_t i = 0U; i < NO_HEADERS_DUPLEX; i++)
m_slot->writeQueueRF(start);
}
else {
for (uint32_t i = 0U; i < NO_HEADERS_SIMPLEX; i++)
m_slot->writeQueueRF(start);
}
m_slot->m_netFrames = 0U;
m_slot->m_netLost = 0U;
m_slot->m_netBits = 1U;
m_slot->m_netErrs = 0U;
m_netEmbeddedReadN = 0U;
m_netEmbeddedWriteN = 1U;
m_netTalkerId = TALKER_ID_NONE;
m_slot->m_netState = RS_NET_AUDIO;
m_slot->m_netLastDstId = dstId;
m_slot->setShortLC(m_slot->m_slotNo, dstId, m_slot->m_data->m_netLC->getFLCO(), true);
::ActivityLog("DMR", false, "Slot %u, received network late entry from %u to %s%u",
m_slot->m_slotNo, srcId, m_slot->m_data->m_netLC->getFLCO() == FLCO_GROUP ? "TG " : "", dstId);
}
if (m_slot->m_netState == RS_NET_AUDIO) {
uint8_t fid = m_slot->m_data->m_netLC->getFID();
if (fid == FID_ETSI || fid == FID_DMRA) {
m_slot->m_netErrs += m_fec.regenerateDMR(data + 2U);
if (m_verbose) {
LogMessage(LOG_NET, "DMR Slot %u, DMR_SYNC_VOICE audio, sequence no = %u, errs = %u/141 (%.1f%%)",
m_slot->m_slotNo, m_netN, m_slot->m_netErrs, float(m_slot->m_netErrs) / 1.41F);
}
}
m_slot->m_netBits += 141U;
data[0U] = TAG_DATA;
data[1U] = 0x00U;
// Convert the Audio Sync to be from the BS or MS as needed
Sync::addDMRAudioSync(data + 2U, m_slot->m_duplex);
// Initialise the lost packet data
if (m_slot->m_netFrames == 0U) {
::memcpy(m_lastFrame, data, DMR_FRAME_LENGTH_BYTES + 2U);
m_lastFrameValid = true;
m_netN = 5U;
m_slot->m_netLost = 0U;
}
if (!m_slot->m_netTimeout)
m_slot->writeQueueNet(data);
m_netEmbeddedReadN = (m_netEmbeddedReadN + 1U) % 2U;
m_netEmbeddedWriteN = (m_netEmbeddedWriteN + 1U) % 2U;
m_netEmbeddedData[m_netEmbeddedWriteN].reset();
m_slot->m_packetTimer.start();
m_slot->m_elapsed.start();
m_slot->m_netFrames++;
// Save details in case we need to infill data
m_netN = dmrData.getN();
}
}
else if (dataType == DT_VOICE) {
if (m_slot->m_netState != RS_NET_AUDIO)
return;
uint8_t fid = m_slot->m_data->m_netLC->getFID();
if (fid == FID_ETSI || fid == FID_DMRA) {
m_slot->m_netErrs += m_fec.regenerateDMR(data + 2U);
if (m_verbose) {
LogMessage(LOG_NET, "DMR Slot %u, DMR_SYNC_VOICE audio, sequence no = %u, errs = %u/141 (%.1f%%)",
m_slot->m_slotNo, m_netN, m_slot->m_netErrs, float(m_slot->m_netErrs) / 1.41F);
}
}
m_slot->m_netBits += 141U;
// Get the LCSS from the EMB
data::EMB emb;
emb.decode(data + 2U);
uint8_t lcss = emb.getLCSS();
// Dump any interesting Embedded Data
bool ret = m_netEmbeddedData[m_netEmbeddedWriteN].addData(data + 2U, lcss);
if (ret) {
uint8_t flco = m_netEmbeddedData[m_netEmbeddedWriteN].getFLCO();
uint8_t data[9U];
m_netEmbeddedData[m_netEmbeddedWriteN].getRawData(data);
char text[80U];
switch (flco) {
case FLCO_GROUP:
case FLCO_PRIVATE:
// ::sprintf(text, "DMR Slot %u, Embedded LC", m_slotNo);
// Utils::dump(1U, text, data, 9U);
break;
case FLCO_GPS_INFO:
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, FLCO_GPS_INFO (Embedded GPS Info)", m_slot->m_slotNo);
Utils::dump(2U, text, data, 9U);
}
logGPSPosition(m_slot->m_data->m_netLC->getSrcId(), data);
break;
case FLCO_TALKER_ALIAS_HEADER:
if (!(m_netTalkerId & TALKER_ID_HEADER)) {
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, FLCO_TALKER_ALIAS_HEADER (Embedded Talker Alias Header)", m_slot->m_slotNo);
Utils::dump(2U, text, data, 9U);
}
m_netTalkerId |= TALKER_ID_HEADER;
}
break;
case FLCO_TALKER_ALIAS_BLOCK1:
if (!(m_netTalkerId & TALKER_ID_BLOCK1)) {
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, FLCO_TALKER_ALIAS_BLOCK1 (Embedded Talker Alias Block 1)", m_slot->m_slotNo);
Utils::dump(2U, text, data, 9U);
}
m_netTalkerId |= TALKER_ID_BLOCK1;
}
break;
case FLCO_TALKER_ALIAS_BLOCK2:
if (!(m_netTalkerId & TALKER_ID_BLOCK2)) {
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, FLCO_TALKER_ALIAS_BLOCK2 (Embedded Talker Alias Block 2)", m_slot->m_slotNo);
Utils::dump(2U, text, data, 9U);
}
m_netTalkerId |= TALKER_ID_BLOCK2;
}
break;
case FLCO_TALKER_ALIAS_BLOCK3:
if (!(m_netTalkerId & TALKER_ID_BLOCK3)) {
if (m_dumpTAData) {
::sprintf(text, "DMR Slot %u, FLCO_TALKER_ALIAS_BLOCK3 (Embedded Talker Alias Block 3)", m_slot->m_slotNo);
Utils::dump(2U, text, data, 9U);
}
m_netTalkerId |= TALKER_ID_BLOCK3;
}
break;
default:
::sprintf(text, "DMR Slot %u, Unknown Embedded Data", m_slot->m_slotNo);
Utils::dump(1U, text, data, 9U);
break;
}
}
if (m_embeddedLCOnly) {
// Only send the previously received LC
lcss = m_netEmbeddedLC.getData(data + 2U, dmrData.getN());
}
else {
// Regenerate the previous super blocks Embedded Data or substitude the LC for it
if (m_netEmbeddedData[m_netEmbeddedReadN].isValid())
lcss = m_netEmbeddedData[m_netEmbeddedReadN].getData(data + 2U, dmrData.getN());
else
lcss = m_netEmbeddedLC.getData(data + 2U, dmrData.getN());
}
// Regenerate the EMB
emb.setColorCode(m_slot->m_colorCode);
emb.setLCSS(lcss);
emb.encode(data + 2U);
data[0U] = TAG_DATA;
data[1U] = 0x00U;
// Initialise the lost packet data
if (m_slot->m_netFrames == 0U) {
::memcpy(m_lastFrame, data, DMR_FRAME_LENGTH_BYTES + 2U);
m_lastFrameValid = true;
m_netN = 5U;
m_slot->m_netLost = 0U;
}
if (insertSilence(data, dmrData.getN())) {
if (!m_slot->m_netTimeout)
m_slot->writeQueueNet(data);
}
m_slot->m_packetTimer.start();
m_slot->m_elapsed.start();
m_slot->m_netFrames++;
// Save details in case we need to infill data
m_netN = dmrData.getN();
}
else {
// Unhandled data type
LogWarning(LOG_NET, "DMR Slot %u, unhandled network data, type = $%02X", m_slot->m_slotNo, dataType);
}
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the VoicePacket class.
/// </summary>
/// <param name="slot">DMR slot.</param>
/// <param name="network">Instance of the BaseNetwork class.</param>
/// <param name="embeddedLCOnly"></param>
/// <param name="dumpTAData"></param>
/// <param name="debug">Flag indicating whether DMR debug is enabled.</param>
/// <param name="verbose">Flag indicating whether DMR verbose logging is enabled.</param>
VoicePacket::VoicePacket(Slot* slot, network::BaseNetwork* network, bool embeddedLCOnly, bool dumpTAData, bool debug, bool verbose) :
m_slot(slot),
m_lastFrame(NULL),
m_lastFrameValid(false),
m_rfN(0U),
m_lastRfN(0U),
m_netN(0U),
m_rfEmbeddedLC(),
m_rfEmbeddedData(NULL),
m_rfEmbeddedReadN(0U),
m_rfEmbeddedWriteN(1U),
m_netEmbeddedLC(),
m_netEmbeddedData(NULL),
m_netEmbeddedReadN(0U),
m_netEmbeddedWriteN(1U),
m_rfTalkerId(TALKER_ID_NONE),
m_netTalkerId(TALKER_ID_NONE),
m_fec(),
m_embeddedLCOnly(embeddedLCOnly),
m_dumpTAData(dumpTAData),
m_verbose(verbose),
m_debug(debug)
{
m_lastFrame = new uint8_t[DMR_FRAME_LENGTH_BYTES + 2U];
m_rfEmbeddedData = new data::EmbeddedData[2U];
m_netEmbeddedData = new data::EmbeddedData[2U];
}
/// <summary>
/// Finalizes a instance of the VoicePacket class.
/// </summary>
VoicePacket::~VoicePacket()
{
delete[] m_lastFrame;
delete[] m_rfEmbeddedData;
delete[] m_netEmbeddedData;
}
/// <summary>
///
/// </summary>
/// <param name="srcId">Source radio ID.</param>
/// <param name="data"></param>
void VoicePacket::logGPSPosition(const uint32_t srcId, const uint8_t* data)
{
uint32_t errorVal = (data[2U] & 0x0E) >> 1U;
const char* error;
switch (errorVal) {
case 0U:
error = "< 2m";
break;
case 1U:
error = "< 20m";
break;
case 2U:
error = "< 200m";
break;
case 3U:
error = "< 2km";
break;
case 4U:
error = "< 20km";
break;
case 5U:
error = "< 200km";
break;
case 6U:
error = "> 200km";
break;
default:
error = "not known";
break;
}
int longitudeVal = ((data[2U] & 0x01U) << 31) | (data[3U] << 23) | (data[4U] << 15) | (data[5U] << 7);
longitudeVal >>= 7;
int latitudeVal = (data[6U] << 24) | (data[7U] << 16) | (data[8U] << 8);
latitudeVal >>= 8;
float longitude = 360.0F / 33554432.0F; // 360/2^25 steps
float latitude = 180.0F / 16777216.0F; // 180/2^24 steps
longitude *= float(longitudeVal);
latitude *= float(latitudeVal);
LogMessage(LOG_DMR, "GPS position for %u [lat %f, long %f] (Position error %s)", srcId, latitude, longitude, error);
}
/// <summary>
/// Helper to insert DMR AMBE silence frames.
/// </summary>
/// <param name="data"></param>
/// <param name="seqNo"></param>
/// <returns></returns>
bool VoicePacket::insertSilence(const uint8_t* data, uint8_t seqNo)
{
assert(data != NULL);
// Do not send duplicate
if (seqNo == m_netN)
return false;
// Check to see if we have any spaces to fill?
uint8_t seq = (m_netN + 1U) % 6U;
if (seq == seqNo) {
// Just copy the data, nothing else to do here
::memcpy(m_lastFrame, data, DMR_FRAME_LENGTH_BYTES + 2U);
m_lastFrameValid = true;
return true;
}
uint32_t count = (seqNo - seq + 6U) % 6U;
insertSilence(count);
::memcpy(m_lastFrame, data, DMR_FRAME_LENGTH_BYTES + 2U);
m_lastFrameValid = true;
return true;
}
/// <summary>
/// Helper to insert DMR AMBE silence frames.
/// </summary>
/// <param name="count"></param>
void VoicePacket::insertSilence(uint32_t count)
{
uint8_t data[DMR_FRAME_LENGTH_BYTES + 2U];
if (m_lastFrameValid) {
::memcpy(data, m_lastFrame, 2U); // The control data
::memcpy(data + 2U, m_lastFrame + 24U + 2U, 9U); // Copy the last audio block to the first
::memcpy(data + 24U + 2U, data + 2U, 9U); // Copy the last audio block to the last
::memcpy(data + 9U + 2U, data + 2U, 5U); // Copy the last audio block to the middle (1/2)
::memcpy(data + 19U + 2U, data + 4U + 2U, 5U); // Copy the last audio block to the middle (2/2)
}
else {
// Not sure what to do if this isn't AMBE audio
::memcpy(data, DMR_SILENCE_DATA, DMR_FRAME_LENGTH_BYTES + 2U);
}
uint8_t n = (m_netN + 1U) % 6U;
uint8_t fid = m_slot->m_data->m_netLC->getFID();
data::EMB emb;
emb.setColorCode(m_slot->m_colorCode);
for (uint32_t i = 0U; i < count; i++) {
// Only use our silence frame if its AMBE audio data
if (fid == FID_ETSI || fid == FID_DMRA) {
if (i > 0U) {
::memcpy(data, DMR_SILENCE_DATA, DMR_FRAME_LENGTH_BYTES + 2U);
m_lastFrameValid = false;
}
}
if (n == 0U) {
Sync::addDMRAudioSync(data + 2U, m_slot->m_duplex);
}
else {
uint8_t lcss = m_netEmbeddedLC.getData(data + 2U, n);
emb.setLCSS(lcss);
emb.encode(data + 2U);
}
m_slot->writeQueueNet(data);
m_netN = n;
m_slot->m_netFrames++;
m_slot->m_netLost++;
n = (n + 1U) % 6U;
}
}

@ -0,0 +1,114 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017-2019 by Bryan Biedenkapp N2PLL
*
* 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(__DMR_VOICE_PACKET_H__)
#define __DMR_VOICE_PACKET_H__
#include "Defines.h"
#include "dmr/data/Data.h"
#include "dmr/data/EmbeddedData.h"
#include "dmr/lc/LC.h"
#include "dmr/Slot.h"
#include "edac/AMBEFEC.h"
#include "network/BaseNetwork.h"
#include "lookups/RadioIdLookup.h"
#include "lookups/TalkgroupIdLookup.h"
#include <vector>
namespace dmr
{
// ---------------------------------------------------------------------------
// Class Prototypes
// ---------------------------------------------------------------------------
class HOST_SW_API DataPacket;
class HOST_SW_API Slot;
// ---------------------------------------------------------------------------
// Class Declaration
// This class implements core logic for handling DMR voice packets.
// ---------------------------------------------------------------------------
class HOST_SW_API VoicePacket {
public:
/// <summary>Process a voice frame from the RF interface.</summary>
bool process(uint8_t* data, uint32_t len);
/// <summary>Process a voice frame from the network.</summary>
void processNetwork(const data::Data& dmrData);
private:
friend class DataPacket;
friend class Slot;
Slot* m_slot;
uint8_t* m_lastFrame;
bool m_lastFrameValid;
uint8_t m_rfN;
uint8_t m_lastRfN;
uint8_t m_netN;
data::EmbeddedData m_rfEmbeddedLC;
data::EmbeddedData* m_rfEmbeddedData;
uint32_t m_rfEmbeddedReadN;
uint32_t m_rfEmbeddedWriteN;
data::EmbeddedData m_netEmbeddedLC;
data::EmbeddedData* m_netEmbeddedData;
uint32_t m_netEmbeddedReadN;
uint32_t m_netEmbeddedWriteN;
uint8_t m_rfTalkerId;
uint8_t m_netTalkerId;
edac::AMBEFEC m_fec;
bool m_embeddedLCOnly;
bool m_dumpTAData;
bool m_verbose;
bool m_debug;
/// <summary>Initializes a new instance of the VoicePacket class.</summary>
VoicePacket(Slot* slot, network::BaseNetwork* network, bool embeddedLCOnly, bool dumpTAData, bool debug, bool verbose);
/// <summary>Finalizes a instance of the VoicePacket class.</summary>
~VoicePacket();
/// <summary></summary>
void logGPSPosition(const uint32_t srcId, const uint8_t* data);
/// <summary>Helper to insert DMR AMBE silence frames.</summary>
bool insertSilence(const uint8_t* data, uint8_t seqNo);
/// <summary>Helper to insert DMR AMBE silence frames.</summary>
void insertSilence(uint32_t count);
};
} // namespace dmr
#endif // __DMR_VOICE_PACKET_H__

@ -0,0 +1,108 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2016 by Simon Rune G7RZU
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017,2019 by Bryan Biedenkapp N2PLL
*
* 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
*/
#include "Defines.h"
#include "dmr/acl/AccessControl.h"
#include "Log.h"
using namespace dmr::acl;
#include <algorithm>
#include <vector>
#include <cstring>
// ---------------------------------------------------------------------------
// Static Class Members
// ---------------------------------------------------------------------------
RadioIdLookup* AccessControl::m_ridLookup;
TalkgroupIdLookup* AccessControl::m_tidLookup;
/// <summary>
/// Initializes the DMR access control.
/// </summary>
/// <param name="ridLookup">Instance of the RadioIdLookup class.</param>
/// <param name="tidLookup">Instance of the TalkgroupIdLookup class.</param>
void AccessControl::init(RadioIdLookup* ridLookup, TalkgroupIdLookup* tidLookup)
{
m_ridLookup = ridLookup;
m_tidLookup = tidLookup;
}
/// <summary>
/// Helper to validate a source radio ID.
/// </summary>
/// <param name="id">Source Radio ID.</param>
/// <returns>True, if source radio ID is valid, otherwise false.</returns>
bool AccessControl::validateSrcId(uint32_t id)
{
// check if RID ACLs are enabled
if (m_ridLookup->getACL() == false) {
return true;
}
// lookup RID and perform test for validity
RadioId rid = m_ridLookup->find(id);
if (!rid.radioEnabled())
return false;
return true;
}
/// <summary>
/// Helper to validate a talkgroup ID.
/// </summary>
/// <param name="slotNo">DMR slot number.</param>
/// <param name="id">Talkgroup ID.</param>
/// <returns>True, if talkgroup ID is valid, otherwise false.</returns>
bool AccessControl::validateTGId(uint32_t slotNo, uint32_t id)
{
// TG0 is never valid
if (id == 0U)
return false;
// check if TID ACLs are enabled
if (m_tidLookup->getACL() == false) {
return true;
}
// lookup TID and perform test for validity
TalkgroupId tid = m_tidLookup->find(id);
if (!tid.tgEnabled())
return false;
if (tid.tgSlot() == 0)
return true; // TG Slot of 0 for the talkgroup entry means both
if (tid.tgSlot() != slotNo)
return false;
return true;
}

@ -0,0 +1,66 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2016 by Simon Rune G7RZU
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017,2019 by Bryan Biedenkapp N2PLL
*
* 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
*/
#if !defined(__DMR_ACL__ACCESS_CONTROL_H__)
#define __DMR_ACL__ACCESS_CONTROL_H__
#include "Defines.h"
#include "lookups/RadioIdLookup.h"
#include "lookups/TalkgroupIdLookup.h"
namespace dmr
{
namespace acl
{
using namespace ::lookups;
// ---------------------------------------------------------------------------
// Class Declaration
// This class implements radio and talkgroup ID access control checking.
// ---------------------------------------------------------------------------
class HOST_SW_API AccessControl {
public:
/// <summary>Initializes the DMR access control.</summary>
static void init(RadioIdLookup* ridLookup, TalkgroupIdLookup* tidLookup);
/// <summary>Helper to validate a source radio ID.</summary>
static bool validateSrcId(uint32_t id);
/// <summary>Helper to validate a talkgroup ID.</summary>
static bool validateTGId(uint32_t slotNo, uint32_t id);
private:
static RadioIdLookup* m_ridLookup;
static TalkgroupIdLookup* m_tidLookup;
};
} // namespace acl
} // namespace dmr
#endif // __DMR_ACL__ACCESS_CONTROL_H__

@ -0,0 +1,128 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 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 "Defines.h"
#include "dmr/DMRDefines.h"
#include "dmr/data/Data.h"
#include "Utils.h"
using namespace dmr::data;
using namespace dmr;
#include <cstdio>
#include <cstring>
#include <cassert>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the Data class.
/// </summary>
/// <param name="data"></param>
Data::Data(const Data& data) :
m_slotNo(data.m_slotNo),
m_srcId(data.m_srcId),
m_dstId(data.m_dstId),
m_flco(data.m_flco),
m_n(data.m_n),
m_seqNo(data.m_seqNo),
m_dataType(data.m_dataType),
m_ber(data.m_ber),
m_rssi(data.m_rssi),
m_data(NULL)
{
m_data = new uint8_t[2U * DMR_FRAME_LENGTH_BYTES];
::memcpy(m_data, data.m_data, 2U * DMR_FRAME_LENGTH_BYTES);
}
/// <summary>
/// Initializes a new instance of the Data class.
/// </summary>
Data::Data() :
m_slotNo(1U),
m_srcId(0U),
m_dstId(0U),
m_flco(FLCO_GROUP),
m_n(0U),
m_seqNo(0U),
m_dataType(0U),
m_ber(0U),
m_rssi(0U),
m_data(NULL)
{
m_data = new uint8_t[2U * DMR_FRAME_LENGTH_BYTES];
}
/// <summary>
/// Finalizes a instance of the Data class.
/// </summary>
Data::~Data()
{
delete[] m_data;
}
/// <summary>
/// Equals operator.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
Data& Data::operator=(const Data& data)
{
if (this != &data) {
::memcpy(m_data, data.m_data, DMR_FRAME_LENGTH_BYTES);
m_slotNo = data.m_slotNo;
m_srcId = data.m_srcId;
m_dstId = data.m_dstId;
m_flco = data.m_flco;
m_dataType = data.m_dataType;
m_seqNo = data.m_seqNo;
m_n = data.m_n;
m_ber = data.m_ber;
m_rssi = data.m_rssi;
}
return *this;
}
/// <summary></summary>
/// <param name="buffer"></param>
void Data::setData(const uint8_t* buffer)
{
assert(buffer != NULL);
::memcpy(m_data, buffer, DMR_FRAME_LENGTH_BYTES);
}
/// <summary></summary>
/// <param name="buffer"></param>
uint32_t Data::getData(uint8_t* buffer) const
{
assert(buffer != NULL);
::memcpy(buffer, m_data, DMR_FRAME_LENGTH_BYTES);
return DMR_FRAME_LENGTH_BYTES;
}

@ -0,0 +1,90 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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; 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.
*/
#if !defined(__DMR_DATA__DATA_H__)
#define __DMR_DATA__DATA_H__
#include "Defines.h"
#include "dmr/DMRDefines.h"
namespace dmr
{
namespace data
{
// ---------------------------------------------------------------------------
// Class Declaration
// Represents general DMR data.
// ---------------------------------------------------------------------------
class HOST_SW_API Data {
public:
/// <summary>Initializes a new instance of the Data class.</summary>
Data(const Data& data);
/// <summary>Initializes a new instance of the Data class.</summary>
Data();
/// <summary>Finalizes a instance of the Data class.</summary>
~Data();
/// <summary>Equals operator.</summary>
Data& operator=(const Data& data);
/// <summary></summary>
void setData(const uint8_t* buffer);
/// <summary></summary>
uint32_t getData(uint8_t* buffer) const;
public:
/// <summary>DMR slot number.</summary>
__PROPERTY(uint32_t, slotNo, SlotNo);
/// <summary>Source ID.</summary>
__PROPERTY(uint32_t, srcId, SrcId);
/// <summary>Destination ID.</summary>
__PROPERTY(uint32_t, dstId, DstId);
/// <summary>Sets the full-link control opcode.</summary>
__PROPERTY(uint8_t, flco, FLCO);
/// <summary></summary>
__PROPERTY(uint8_t, n, N);
/// <summary>Sequence number.</summary>
__PROPERTY(uint8_t, seqNo, SeqNo);
/// <summary></summary>
__PROPERTY(uint8_t, dataType, DataType);
/// <summary></summary>
__PROPERTY(uint8_t, ber, BER);
/// <summary></summary>
__PROPERTY(uint8_t, rssi, RSSI);
private:
uint8_t* m_data;
};
} // namespace data
} // namespace dmr
#endif // __DMR_DATA__DATA_H__

@ -0,0 +1,199 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2012 by Ian Wraith
* 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.
*/
#include "Defines.h"
#include "dmr/DMRDefines.h"
#include "dmr/data/DataHeader.h"
#include "edac/BPTC19696.h"
#include "edac/RS129.h"
#include "edac/CRC.h"
#include "Utils.h"
using namespace dmr::data;
using namespace dmr;
#include <cstdio>
#include <cassert>
#include <cstring>
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const uint8_t UDTF_NMEA = 0x05U;
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the DataHeader class.
/// </summary>
DataHeader::DataHeader() :
m_GI(false),
m_srcId(0U),
m_dstId(0U),
m_blocks(0U),
m_data(NULL),
m_A(false),
m_F(false),
m_S(false),
m_Ns(0U)
{
m_data = new uint8_t[12U];
}
/// <summary>
/// Finalizes a instance of the DataHeader class.
/// </summary>
DataHeader::~DataHeader()
{
delete[] m_data;
}
/// <summary>
/// Equals operator.
/// </summary>
/// <param name="header"></param>
/// <returns></returns>
DataHeader& DataHeader::operator=(const DataHeader& header)
{
if (&header != this) {
::memcpy(m_data, header.m_data, 12U);
m_GI = header.m_GI;
m_A = header.m_A;
m_srcId = header.m_srcId;
m_dstId = header.m_dstId;
m_blocks = header.m_blocks;
m_F = header.m_F;
m_S = header.m_S;
m_Ns = header.m_Ns;
}
return *this;
}
/// <summary>
/// Decodes a DMR data header.
/// </summary>
/// <param name="bytes"></param>
/// <returns>True, if DMR data header was decoded, otherwise false.</returns>
bool DataHeader::decode(const uint8_t* bytes)
{
assert(bytes != NULL);
// decode BPTC (196,96) FEC
edac::BPTC19696 bptc;
bptc.decode(bytes, m_data);
// validate the CRC-CCITT 16
m_data[10U] ^= DATA_HEADER_CRC_MASK[0U];
m_data[11U] ^= DATA_HEADER_CRC_MASK[1U];
bool valid = edac::CRC::checkCCITT162(m_data, DMR_LC_HEADER_LENGTH_BYTES);
if (!valid)
return false;
// restore the checksum
m_data[10U] ^= DATA_HEADER_CRC_MASK[0U];
m_data[11U] ^= DATA_HEADER_CRC_MASK[1U];
m_GI = (m_data[0U] & 0x80U) == 0x80U;
m_A = (m_data[0U] & 0x40U) == 0x40U;
uint8_t dpf = m_data[0U] & 0x0FU;
if (dpf == DPF_PROPRIETARY)
return true;
m_dstId = m_data[2U] << 16 | m_data[3U] << 8 | m_data[4U];
m_srcId = m_data[5U] << 16 | m_data[6U] << 8 | m_data[7U];
switch (dpf) {
case DPF_UNCONFIRMED_DATA:
Utils::dump(1U, "DMR, Unconfirmed Data Header", m_data, DMR_LC_HEADER_LENGTH_BYTES);
m_F = (m_data[8U] & 0x80U) == 0x80U;
m_blocks = m_data[8U] & 0x7FU;
break;
case DPF_CONFIRMED_DATA:
Utils::dump(1U, "DMR, Confirmed Data Header", m_data, DMR_LC_HEADER_LENGTH_BYTES);
m_F = (m_data[8U] & 0x80U) == 0x80U;
m_blocks = m_data[8U] & 0x7FU;
m_S = (m_data[9U] & 0x80U) == 0x80U;
m_Ns = (m_data[9U] >> 4) & 0x07U;
break;
case DPF_RESPONSE:
Utils::dump(1U, "DMR, Response Data Header", m_data, DMR_LC_HEADER_LENGTH_BYTES);
m_blocks = m_data[8U] & 0x7FU;
break;
case DPF_PROPRIETARY:
Utils::dump(1U, "DMR, Proprietary Data Header", m_data, DMR_LC_HEADER_LENGTH_BYTES);
break;
case DPF_DEFINED_RAW:
Utils::dump(1U, "DMR, Raw or Status/Precoded Short Data Header", m_data, DMR_LC_HEADER_LENGTH_BYTES);
m_blocks = (m_data[0U] & 0x30U) + (m_data[1U] & 0x0FU);
m_F = (m_data[8U] & 0x01U) == 0x01U;
m_S = (m_data[8U] & 0x02U) == 0x02U;
break;
case DPF_DEFINED_SHORT:
Utils::dump(1U, "DMR, Defined Short Data Header", m_data, DMR_LC_HEADER_LENGTH_BYTES);
m_blocks = (m_data[0U] & 0x30U) + (m_data[1U] & 0x0FU);
m_F = (m_data[8U] & 0x01U) == 0x01U;
m_S = (m_data[8U] & 0x02U) == 0x02U;
break;
case DPF_UDT:
Utils::dump(1U, "DMR, Unified Data Transport Header", m_data, DMR_LC_HEADER_LENGTH_BYTES);
m_blocks = (m_data[8U] & 0x03U) + 1U;
break;
default:
Utils::dump("DMR, Unknown Data Header", m_data, DMR_LC_HEADER_LENGTH_BYTES);
break;
}
return true;
}
/// <summary>
/// Encodes a DMR data header.
/// </summary>
/// <param name="bytes"></param>
void DataHeader::encode(uint8_t* bytes) const
{
assert(bytes != NULL);
// encode BPTC (196,96) FEC
edac::BPTC19696 bptc;
bptc.encode(m_data, bytes);
}

@ -0,0 +1,83 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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(__DMR_DATA__DATA_HEADER_H__)
#define __DMR_DATA__DATA_HEADER_H__
#include "Defines.h"
namespace dmr
{
namespace data
{
// ---------------------------------------------------------------------------
// Class Declaration
// Represents a DMR data header.
// ---------------------------------------------------------------------------
class HOST_SW_API DataHeader {
public:
/// <summary>Initializes a new instance of the DataHeader class.</summary>
DataHeader();
/// <summary>Finalizes a instance of the DataHeader class.</summary>
~DataHeader();
/// <summary>Equals operator.</summary>
DataHeader& operator=(const DataHeader& header);
/// <summary>Decodes a DMR data header.</summary>
bool decode(const uint8_t* bytes);
/// <summary>Encodes a DMR data header.</summary>
void encode(uint8_t* bytes) const;
public:
/// <summary>Flag indicating whether the CSBK is group or individual.</summary>
__READONLY_PROPERTY(bool, GI, GI);
/// <summary>Source ID.</summary>
__READONLY_PROPERTY(uint32_t, srcId, SrcId);
/// <summary>Destination ID.</summary>
__READONLY_PROPERTY(uint32_t, dstId, DstId);
/// <summary>Gets the number of data blocks following the header.</summary>
__READONLY_PROPERTY(uint32_t, blocks, Blocks);
private:
uint8_t* m_data;
bool m_A;
bool m_F;
bool m_S;
uint8_t m_Ns;
};
} // namespace data
} // namespace dmr
#endif // __DMR_DATA__DATA_HEADER_H__

@ -0,0 +1,105 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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 "Defines.h"
#include "dmr/data/EMB.h"
#include "edac/QR1676.h"
using namespace dmr::data;
using namespace dmr;
#include <cstdio>
#include <cassert>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the EMB class.
/// </summary>
EMB::EMB() :
m_colorCode(0U),
m_PI(false),
m_LCSS(0U)
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the EMB class.
/// </summary>
EMB::~EMB()
{
/* stub */
}
/// <summary>
/// Decodes DMR embedded signalling data.
/// </summary>
/// <param name="data"></param>
void EMB::decode(const uint8_t* data)
{
assert(data != NULL);
uint8_t DMREMB[2U];
DMREMB[0U] = (data[13U] << 4) & 0xF0U;
DMREMB[0U] |= (data[14U] >> 4) & 0x0FU;
DMREMB[1U] = (data[18U] << 4) & 0xF0U;
DMREMB[1U] |= (data[19U] >> 4) & 0x0FU;
// decode QR (16,7,6) FEC
edac::QR1676::decode(DMREMB);
m_colorCode = (DMREMB[0U] >> 4) & 0x0FU;
m_PI = (DMREMB[0U] & 0x08U) == 0x08U;
m_LCSS = (DMREMB[0U] >> 1) & 0x03U;
}
/// <summary>
/// Encodes DMR embedded signalling data.
/// </summary>
/// <param name="data"></param>
void EMB::encode(uint8_t* data) const
{
assert(data != NULL);
uint8_t DMREMB[2U];
DMREMB[0U] = (m_colorCode << 4) & 0xF0U;
DMREMB[0U] |= m_PI ? 0x08U : 0x00U;
DMREMB[0U] |= (m_LCSS << 1) & 0x06U;
DMREMB[1U] = 0x00U;
// encode QR (16,7,6) FEC
edac::QR1676::encode(DMREMB);
data[13U] = (data[13U] & 0xF0U) | ((DMREMB[0U] >> 4U) & 0x0FU);
data[14U] = (data[14U] & 0x0FU) | ((DMREMB[0U] << 4U) & 0xF0U);
data[18U] = (data[18U] & 0xF0U) | ((DMREMB[1U] >> 4U) & 0x0FU);
data[19U] = (data[19U] & 0x0FU) | ((DMREMB[1U] << 4U) & 0xF0U);
}

@ -0,0 +1,69 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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(__DMR_DATA__EMB_H__)
#define __DMR_DATA__EMB_H__
#include "Defines.h"
namespace dmr
{
namespace data
{
// ---------------------------------------------------------------------------
// Class Declaration
// Represents a DMR embedded signalling data.
// ---------------------------------------------------------------------------
class HOST_SW_API EMB {
public:
/// <summary>Initializes a new instance of the EMB class.</summary>
EMB();
/// <summary>Finalizes a instance of the EMB class.</summary>
~EMB();
/// <summary>Decodes DMR embedded signalling data.</summary>
void decode(const uint8_t* data);
/// <summary>Encodes DMR embedded signalling data.</summary>
void encode(uint8_t* data) const;
public:
/// <summary>DMR access color code.</summary>
__PROPERTY(uint8_t, colorCode, ColorCode);
/// <summary>Flag indicating whether the privacy indicator is set or not.</summary>
__PROPERTY(bool, PI, PI);
/// <summary>Link control start/stop.</summary>
__PROPERTY(uint8_t, LCSS, LCSS);
};
} // namespace data
} // namespace dmr
#endif // __DMR_DATA__EMB_H__

@ -0,0 +1,367 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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.
*/
#include "Defines.h"
#include "dmr/data/EmbeddedData.h"
#include "edac/Hamming.h"
#include "edac/CRC.h"
#include "Utils.h"
using namespace dmr::data;
using namespace dmr;
#include <cstdio>
#include <cassert>
#include <cstring>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the EmbeddedData class.
/// </summary>
EmbeddedData::EmbeddedData() :
m_valid(false),
m_FLCO(FLCO_GROUP),
m_state(LCS_NONE),
m_data(NULL),
m_raw(NULL)
{
m_raw = new bool[128U];
m_data = new bool[72U];
}
/// <summary>
/// Finalizes a instance of the EmbeddedData class.
/// </summary>
EmbeddedData::~EmbeddedData()
{
delete[] m_raw;
delete[] m_data;
}
/// <summary>
/// Add LC data (which may consist of 4 blocks) to the data store.
/// </summary>
/// <param name="data"></param>
/// <param name="lcss"></param>
/// <returns></returns>
bool EmbeddedData::addData(const uint8_t* data, uint8_t lcss)
{
assert(data != NULL);
bool rawData[40U];
Utils::byteToBitsBE(data[14U], rawData + 0U);
Utils::byteToBitsBE(data[15U], rawData + 8U);
Utils::byteToBitsBE(data[16U], rawData + 16U);
Utils::byteToBitsBE(data[17U], rawData + 24U);
Utils::byteToBitsBE(data[18U], rawData + 32U);
// Is this the first block of a 4 block embedded LC ?
if (lcss == 1U) {
for (uint32_t a = 0U; a < 32U; a++)
m_raw[a] = rawData[a + 4U];
// Show we are ready for the next LC block
m_state = LCS_FIRST;
m_valid = false;
return false;
}
// Is this the 2nd block of a 4 block embedded LC ?
if (lcss == 3U && m_state == LCS_FIRST) {
for (uint32_t a = 0U; a < 32U; a++)
m_raw[a + 32U] = rawData[a + 4U];
// Show we are ready for the next LC block
m_state = LCS_SECOND;
return false;
}
// Is this the 3rd block of a 4 block embedded LC ?
if (lcss == 3U && m_state == LCS_SECOND) {
for (uint32_t a = 0U; a < 32U; a++)
m_raw[a + 64U] = rawData[a + 4U];
// Show we are ready for the final LC block
m_state = LCS_THIRD;
return false;
}
// Is this the final block of a 4 block embedded LC ?
if (lcss == 2U && m_state == LCS_THIRD) {
for (uint32_t a = 0U; a < 32U; a++)
m_raw[a + 96U] = rawData[a + 4U];
// Show that we're not ready for any more data
m_state = LCS_NONE;
// Process the complete data block
decodeEmbeddedData();
if (m_valid)
encodeEmbeddedData();
return m_valid;
}
return false;
}
/// <summary>
///
/// </summary>
/// <param name="data"></param>
/// <param name="n"></param>
/// <returns></returns>
uint8_t EmbeddedData::getData(uint8_t* data, uint8_t n) const
{
assert(data != NULL);
if (n >= 1U && n < 5U) {
n--;
bool bits[40U];
::memset(bits, 0x00U, 40U * sizeof(bool));
::memcpy(bits + 4U, m_raw + n * 32U, 32U * sizeof(bool));
uint8_t bytes[5U];
Utils::bitsToByteBE(bits + 0U, bytes[0U]);
Utils::bitsToByteBE(bits + 8U, bytes[1U]);
Utils::bitsToByteBE(bits + 16U, bytes[2U]);
Utils::bitsToByteBE(bits + 24U, bytes[3U]);
Utils::bitsToByteBE(bits + 32U, bytes[4U]);
data[14U] = (data[14U] & 0xF0U) | (bytes[0U] & 0x0FU);
data[15U] = bytes[1U];
data[16U] = bytes[2U];
data[17U] = bytes[3U];
data[18U] = (data[18U] & 0x0FU) | (bytes[4U] & 0xF0U);
switch (n) {
case 0U:
return 1U;
case 3U:
return 2U;
default:
return 3U;
}
}
else {
data[14U] &= 0xF0U;
data[15U] = 0x00U;
data[16U] = 0x00U;
data[17U] = 0x00U;
data[18U] &= 0x0FU;
return 0U;
}
}
/// <summary>Sets link control data.</summary>
/// <param name="lc"></param>
void EmbeddedData::setLC(const lc::LC& lc)
{
lc.getData(m_data);
m_FLCO = lc.getFLCO();
m_valid = true;
encodeEmbeddedData();
}
/// <summary>Gets link control data.</summary>
/// <returns></returns>
lc::LC* EmbeddedData::getLC() const
{
if (!m_valid)
return NULL;
if (m_FLCO != FLCO_GROUP && m_FLCO != FLCO_PRIVATE)
return NULL;
return new lc::LC(m_data);
}
/// <summary>
///
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
bool EmbeddedData::getRawData(uint8_t* data) const
{
assert(data != NULL);
if (!m_valid)
return false;
Utils::bitsToByteBE(m_data + 0U, data[0U]);
Utils::bitsToByteBE(m_data + 8U, data[1U]);
Utils::bitsToByteBE(m_data + 16U, data[2U]);
Utils::bitsToByteBE(m_data + 24U, data[3U]);
Utils::bitsToByteBE(m_data + 32U, data[4U]);
Utils::bitsToByteBE(m_data + 40U, data[5U]);
Utils::bitsToByteBE(m_data + 48U, data[6U]);
Utils::bitsToByteBE(m_data + 56U, data[7U]);
Utils::bitsToByteBE(m_data + 64U, data[8U]);
return true;
}
/// <summary>
/// Helper to reset data values to defaults.
/// </summary>
void EmbeddedData::reset()
{
m_state = LCS_NONE;
m_valid = false;
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Unpack and error check an embedded LC.
/// </summary>
void EmbeddedData::decodeEmbeddedData()
{
// The data is unpacked downwards in columns
bool data[128U];
::memset(data, 0x00U, 128U * sizeof(bool));
uint32_t b = 0U;
for (uint32_t a = 0U; a < 128U; a++) {
data[b] = m_raw[a];
b += 16U;
if (b > 127U)
b -= 127U;
}
// Hamming (16,11,4) check each row except the last one
for (uint32_t a = 0U; a < 112U; a += 16U) {
if (!edac::Hamming::decode16114(data + a))
return;
}
// Check the parity bits
for (uint32_t a = 0U; a < 16U; a++) {
bool parity = data[a + 0U] ^ data[a + 16U] ^ data[a + 32U] ^ data[a + 48U] ^ data[a + 64U] ^ data[a + 80U] ^ data[a + 96U] ^ data[a + 112U];
if (parity)
return;
}
// We have passed the Hamming check so extract the actual payload
b = 0U;
for (uint32_t a = 0U; a < 11U; a++, b++)
m_data[b] = data[a];
for (uint32_t a = 16U; a < 27U; a++, b++)
m_data[b] = data[a];
for (uint32_t a = 32U; a < 42U; a++, b++)
m_data[b] = data[a];
for (uint32_t a = 48U; a < 58U; a++, b++)
m_data[b] = data[a];
for (uint32_t a = 64U; a < 74U; a++, b++)
m_data[b] = data[a];
for (uint32_t a = 80U; a < 90U; a++, b++)
m_data[b] = data[a];
for (uint32_t a = 96U; a < 106U; a++, b++)
m_data[b] = data[a];
// Extract the 5 bit CRC
uint32_t crc = 0U;
if (data[42]) crc += 16U;
if (data[58]) crc += 8U;
if (data[74]) crc += 4U;
if (data[90]) crc += 2U;
if (data[106]) crc += 1U;
// Now CRC check this
if (!edac::CRC::checkFiveBit(m_data, crc))
return;
m_valid = true;
// Extract the FLCO
uint8_t flco;
Utils::bitsToByteBE(m_data + 0U, flco);
m_FLCO = flco & 0x3FU;
}
/// <summary>
/// Pack and FEC for an embedded LC.
/// </summary>
void EmbeddedData::encodeEmbeddedData()
{
uint32_t crc;
edac::CRC::encodeFiveBit(m_data, crc);
bool data[128U];
::memset(data, 0x00U, 128U * sizeof(bool));
data[106U] = (crc & 0x01U) == 0x01U;
data[90U] = (crc & 0x02U) == 0x02U;
data[74U] = (crc & 0x04U) == 0x04U;
data[58U] = (crc & 0x08U) == 0x08U;
data[42U] = (crc & 0x10U) == 0x10U;
uint32_t b = 0U;
for (uint32_t a = 0U; a < 11U; a++, b++)
data[a] = m_data[b];
for (uint32_t a = 16U; a < 27U; a++, b++)
data[a] = m_data[b];
for (uint32_t a = 32U; a < 42U; a++, b++)
data[a] = m_data[b];
for (uint32_t a = 48U; a < 58U; a++, b++)
data[a] = m_data[b];
for (uint32_t a = 64U; a < 74U; a++, b++)
data[a] = m_data[b];
for (uint32_t a = 80U; a < 90U; a++, b++)
data[a] = m_data[b];
for (uint32_t a = 96U; a < 106U; a++, b++)
data[a] = m_data[b];
// Hamming (16,11,4) check each row except the last one
for (uint32_t a = 0U; a < 112U; a += 16U)
edac::Hamming::encode16114(data + a);
// Add the parity bits for each column
for (uint32_t a = 0U; a < 16U; a++)
data[a + 112U] = data[a + 0U] ^ data[a + 16U] ^ data[a + 32U] ^ data[a + 48U] ^ data[a + 64U] ^ data[a + 80U] ^ data[a + 96U];
// The data is packed downwards in columns
b = 0U;
for (uint32_t a = 0U; a < 128U; a++) {
m_raw[a] = data[b];
b += 16U;
if (b > 127U)
b -= 127U;
}
}

@ -0,0 +1,100 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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(__DMR_DATA__EMBEDDED_DATA_H__)
#define __DMR_DATA__EMBEDDED_DATA_H__
#include "Defines.h"
#include "dmr/DMRDefines.h"
#include "dmr/lc/LC.h"
namespace dmr
{
namespace data
{
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
enum LC_STATE {
LCS_NONE,
LCS_FIRST,
LCS_SECOND,
LCS_THIRD
};
// ---------------------------------------------------------------------------
// Class Declaration
// Represents a DMR embedded data.
// ---------------------------------------------------------------------------
class HOST_SW_API EmbeddedData {
public:
/// <summary>Initializes a new instance of the EmbeddedData class.</summary>
EmbeddedData();
/// <summary>Finalizes a instance of the EmbeddedData class.</summary>
~EmbeddedData();
/// <summary>Add LC data (which may consist of 4 blocks) to the data store.</summary>
bool addData(const uint8_t* data, uint8_t lcss);
/// <summary></summary>
uint8_t getData(uint8_t* data, uint8_t n) const;
/// <summary>Sets link control data.</summary>
void setLC(const lc::LC& lc);
/// <summary>Gets link control data.</summary>
lc::LC* getLC() const;
/// <summary></summary>
bool getRawData(uint8_t* data) const;
/// <summary>Helper to reset data values to defaults.</summary>
void reset();
public:
/// <summary>Flag indicating whether or not the embedded data is valid.</summary>
__READONLY_PROPERTY_PLAIN(bool, valid, isValid);
/// <summary>Full-link control opcode.</summary>
__READONLY_PROPERTY(uint8_t, FLCO, FLCO);
private:
LC_STATE m_state;
bool* m_data;
bool* m_raw;
/// <summary>Unpack and error check an embedded LC.</summary>
void decodeEmbeddedData();
/// <summary>Pack and FEC for an embedded LC.</summary>
void encodeEmbeddedData();
};
} // namespace data
} // namespace dmr
#endif // __DMR_DATA__EMBEDDED_DATA_H__

@ -0,0 +1,453 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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; 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 "Defines.h"
#include "dmr/edac/Trellis.h"
using namespace dmr::edac;
#include <cstdio>
#include <cassert>
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const uint32_t INTERLEAVE_TABLE[] = {
0U, 1U, 8U, 9U, 16U, 17U, 24U, 25U, 32U, 33U, 40U, 41U, 48U, 49U, 56U, 57U, 64U, 65U, 72U, 73U, 80U, 81U, 88U, 89U, 96U, 97U,
2U, 3U, 10U, 11U, 18U, 19U, 26U, 27U, 34U, 35U, 42U, 43U, 50U, 51U, 58U, 59U, 66U, 67U, 74U, 75U, 82U, 83U, 90U, 91U,
4U, 5U, 12U, 13U, 20U, 21U, 28U, 29U, 36U, 37U, 44U, 45U, 52U, 53U, 60U, 61U, 68U, 69U, 76U, 77U, 84U, 85U, 92U, 93U,
6U, 7U, 14U, 15U, 22U, 23U, 30U, 31U, 38U, 39U, 46U, 47U, 54U, 55U, 62U, 63U, 70U, 71U, 78U, 79U, 86U, 87U, 94U, 95U };
const uint8_t ENCODE_TABLE[] = {
0U, 8U, 4U, 12U, 2U, 10U, 6U, 14U,
4U, 12U, 2U, 10U, 6U, 14U, 0U, 8U,
1U, 9U, 5U, 13U, 3U, 11U, 7U, 15U,
5U, 13U, 3U, 11U, 7U, 15U, 1U, 9U,
3U, 11U, 7U, 15U, 1U, 9U, 5U, 13U,
7U, 15U, 1U, 9U, 5U, 13U, 3U, 11U,
2U, 10U, 6U, 14U, 0U, 8U, 4U, 12U,
6U, 14U, 0U, 8U, 4U, 12U, 2U, 10U };
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the Trellis class.
/// </summary>
Trellis::Trellis()
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the Trellis class.
/// </summary>
Trellis::~Trellis()
{
/* stub */
}
/// <summary>
/// Decodes 3/4 rate Trellis.
/// </summary>
/// <param name="data"></param>
/// <param name="payload"></param>
/// <returns></returns>
bool Trellis::decode(const uint8_t* data, uint8_t* payload)
{
assert(data != NULL);
assert(payload != NULL);
int8_t dibits[98U];
deinterleave(data, dibits);
uint8_t points[49U];
dibitsToPoints(dibits, points);
// Check the original code
uint8_t tribits[49U];
uint32_t failPos = checkCode(points, tribits);
if (failPos == 999U) {
tribitsToBits(tribits, payload);
return true;
}
uint8_t savePoints[49U];
for (uint32_t i = 0U; i < 49U; i++)
savePoints[i] = points[i];
bool ret = fixCode(points, failPos, payload);
if (ret)
return true;
if (failPos == 0U)
return false;
// Backtrack one place for a last go
return fixCode(savePoints, failPos - 1U, payload);
}
/// <summary>
/// Encodes 3/4 rate Trellis.
/// </summary>
/// <param name="payload"></param>
/// <param name="data"></param>
void Trellis::encode(const uint8_t* payload, uint8_t* data)
{
assert(payload != NULL);
assert(data != NULL);
uint8_t tribits[49U];
bitsToTribits(payload, tribits);
uint8_t points[49U];
uint8_t state = 0U;
for (uint32_t i = 0U; i < 49U; i++) {
uint8_t tribit = tribits[i];
points[i] = ENCODE_TABLE[state * 8U + tribit];
state = tribit;
}
int8_t dibits[98U];
pointsToDibits(points, dibits);
interleave(dibits, data);
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
///
/// </summary>
/// <param name="data"></param>
/// <param name="dibits"></param>
void Trellis::deinterleave(const uint8_t* data, int8_t* dibits) const
{
for (uint32_t i = 0U; i < 98U; i++) {
uint32_t n = i * 2U + 0U;
if (n >= 98U) n += 68U;
bool b1 = READ_BIT(data, n) != 0x00U;
n = i * 2U + 1U;
if (n >= 98U) n += 68U;
bool b2 = READ_BIT(data, n) != 0x00U;
int8_t dibit;
if (!b1 && b2)
dibit = +3;
else if (!b1 && !b2)
dibit = +1;
else if (b1 && !b2)
dibit = -1;
else
dibit = -3;
n = INTERLEAVE_TABLE[i];
dibits[n] = dibit;
}
}
/// <summary>
///
/// </summary>
/// <param name="dibits"></param>
/// <param name="data"></param>
void Trellis::interleave(const int8_t* dibits, uint8_t* data) const
{
for (uint32_t i = 0U; i < 98U; i++) {
uint32_t n = INTERLEAVE_TABLE[i];
bool b1, b2;
switch (dibits[n]) {
case +3:
b1 = false;
b2 = true;
break;
case +1:
b1 = false;
b2 = false;
break;
case -1:
b1 = true;
b2 = false;
break;
default:
b1 = true;
b2 = true;
break;
}
n = i * 2U + 0U;
if (n >= 98U) n += 68U;
WRITE_BIT(data, n, b1);
n = i * 2U + 1U;
if (n >= 98U) n += 68U;
WRITE_BIT(data, n, b2);
}
}
/// <summary>
///
/// </summary>
/// <param name="dibits"></param>
/// <param name="points"></param>
void Trellis::dibitsToPoints(const int8_t* dibits, uint8_t* points) const
{
for (uint32_t i = 0U; i < 49U; i++) {
if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == -1)
points[i] = 0U;
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == -1)
points[i] = 1U;
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == -3)
points[i] = 2U;
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == -3)
points[i] = 3U;
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == -1)
points[i] = 4U;
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == -1)
points[i] = 5U;
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == -3)
points[i] = 6U;
else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == -3)
points[i] = 7U;
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == +3)
points[i] = 8U;
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == +3)
points[i] = 9U;
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == +1)
points[i] = 10U;
else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == +1)
points[i] = 11U;
else if (dibits[i * 2U + 0U] == +1 && dibits[i * 2U + 1U] == +3)
points[i] = 12U;
else if (dibits[i * 2U + 0U] == -1 && dibits[i * 2U + 1U] == +3)
points[i] = 13U;
else if (dibits[i * 2U + 0U] == +3 && dibits[i * 2U + 1U] == +1)
points[i] = 14U;
else if (dibits[i * 2U + 0U] == -3 && dibits[i * 2U + 1U] == +1)
points[i] = 15U;
}
}
/// <summary>
///
/// </summary>
/// <param name="points"></param>
/// <param name="dibits"></param>
void Trellis::pointsToDibits(const uint8_t* points, int8_t* dibits) const
{
for (uint32_t i = 0U; i < 49U; i++) {
switch (points[i]) {
case 0U:
dibits[i * 2U + 0U] = +1;
dibits[i * 2U + 1U] = -1;
break;
case 1U:
dibits[i * 2U + 0U] = -1;
dibits[i * 2U + 1U] = -1;
break;
case 2U:
dibits[i * 2U + 0U] = +3;
dibits[i * 2U + 1U] = -3;
break;
case 3U:
dibits[i * 2U + 0U] = -3;
dibits[i * 2U + 1U] = -3;
break;
case 4U:
dibits[i * 2U + 0U] = -3;
dibits[i * 2U + 1U] = -1;
break;
case 5U:
dibits[i * 2U + 0U] = +3;
dibits[i * 2U + 1U] = -1;
break;
case 6U:
dibits[i * 2U + 0U] = -1;
dibits[i * 2U + 1U] = -3;
break;
case 7U:
dibits[i * 2U + 0U] = +1;
dibits[i * 2U + 1U] = -3;
break;
case 8U:
dibits[i * 2U + 0U] = -3;
dibits[i * 2U + 1U] = +3;
break;
case 9U:
dibits[i * 2U + 0U] = +3;
dibits[i * 2U + 1U] = +3;
break;
case 10U:
dibits[i * 2U + 0U] = -1;
dibits[i * 2U + 1U] = +1;
break;
case 11U:
dibits[i * 2U + 0U] = +1;
dibits[i * 2U + 1U] = +1;
break;
case 12U:
dibits[i * 2U + 0U] = +1;
dibits[i * 2U + 1U] = +3;
break;
case 13U:
dibits[i * 2U + 0U] = -1;
dibits[i * 2U + 1U] = +3;
break;
case 14U:
dibits[i * 2U + 0U] = +3;
dibits[i * 2U + 1U] = +1;
break;
default:
dibits[i * 2U + 0U] = -3;
dibits[i * 2U + 1U] = +1;
break;
}
}
}
/// <summary>
///
/// </summary>
/// <param name="payload"></param>
/// <param name="tribits"></param>
void Trellis::bitsToTribits(const uint8_t* payload, uint8_t* tribits) const
{
for (uint32_t i = 0U; i < 48U; i++) {
uint32_t n = 143U - i * 3U;
bool b1 = READ_BIT(payload, n) != 0x00U;
n--;
bool b2 = READ_BIT(payload, n) != 0x00U;
n--;
bool b3 = READ_BIT(payload, n) != 0x00U;
uint8_t tribit = 0U;
tribit |= b1 ? 4U : 0U;
tribit |= b2 ? 2U : 0U;
tribit |= b3 ? 1U : 0U;
tribits[i] = tribit;
}
tribits[48U] = 0U;
}
/// <summary>
///
/// </summary>
/// <param name="tribits"></param>
/// <param name="payload"></param>
void Trellis::tribitsToBits(const uint8_t* tribits, uint8_t* payload) const
{
for (uint32_t i = 0U; i < 48U; i++) {
uint8_t tribit = tribits[i];
bool b1 = (tribit & 0x04U) == 0x04U;
bool b2 = (tribit & 0x02U) == 0x02U;
bool b3 = (tribit & 0x01U) == 0x01U;
uint32_t n = 143U - i * 3U;
WRITE_BIT(payload, n, b1);
n--;
WRITE_BIT(payload, n, b2);
n--;
WRITE_BIT(payload, n, b3);
}
}
/// <summary>
///
/// </summary>
/// <param name="points"></param>
/// <param name="failPos"></param>
/// <param name="payload"></param>
/// <returns></returns>
bool Trellis::fixCode(uint8_t* points, uint32_t failPos, uint8_t* payload) const
{
for (unsigned j = 0U; j < 20U; j++) {
uint32_t bestPos = 0U;
uint32_t bestVal = 0U;
for (uint32_t i = 0U; i < 16U; i++) {
points[failPos] = i;
uint8_t tribits[49U];
uint32_t pos = checkCode(points, tribits);
if (pos == 999U) {
tribitsToBits(tribits, payload);
return true;
}
if (pos > bestPos) {
bestPos = pos;
bestVal = i;
}
}
points[failPos] = bestVal;
failPos = bestPos;
}
return false;
}
/// <summary>
///
/// </summary>
/// <param name="points"></param>
/// <param name="tribits"></param>
/// <returns></returns>
uint32_t Trellis::checkCode(const uint8_t* points, uint8_t* tribits) const
{
uint8_t state = 0U;
for (uint32_t i = 0U; i < 49U; i++) {
tribits[i] = 9U;
for (uint32_t j = 0U; j < 8U; j++) {
if (points[i] == ENCODE_TABLE[state * 8U + j]) {
tribits[i] = j;
break;
}
}
if (tribits[i] == 9U)
return i;
state = tribits[i];
}
if (tribits[48U] != 0U)
return 48U;
return 999U;
}

@ -0,0 +1,73 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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; 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.
*/
#if !defined(__DMR_EDAC__TRELLIS_H__)
#define __DMR_EDAC__TRELLIS_H__
#include "Defines.h"
namespace dmr
{
namespace edac
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements 3/4 rate Trellis for DMR.
// ---------------------------------------------------------------------------
class HOST_SW_API Trellis {
public:
/// <summary>Initializes a new instance of the Trellis class.</summary>
Trellis();
/// <summary>Finalizes a instance of the Trellis class.</summary>
~Trellis();
/// <summary>Decodes 3/4 rate Trellis.</summary>
bool decode(const uint8_t* data, uint8_t* payload);
/// <summary>Encodes 3/4 rate Trellis.</summary>
void encode(const uint8_t* payload, uint8_t* data);
private:
/// <summary></summary>
void deinterleave(const uint8_t* in, int8_t* dibits) const;
/// <summary></summary>
void interleave(const int8_t* dibits, uint8_t* out) const;
/// <summary></summary>
void dibitsToPoints(const int8_t* dibits, uint8_t* points) const;
/// <summary></summary>
void pointsToDibits(const uint8_t* points, int8_t* dibits) const;
/// <summary></summary>
void bitsToTribits(const uint8_t* payload, uint8_t* tribits) const;
/// <summary></summary>
void tribitsToBits(const uint8_t* tribits, uint8_t* payload) const;
/// <summary></summary>
bool fixCode(uint8_t* points, uint32_t failPos, uint8_t* payload) const;
/// <summary></summary>
uint32_t checkCode(const uint8_t* points, uint8_t* tribits) const;
};
} // namespace edac
} // namespace dmr
#endif // __DMR_EDAC__TRELLIS_H__

@ -0,0 +1,247 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2019 by Bryan Biedenkapp N2PLL
*
* 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 "Defines.h"
#include "dmr/lc/CSBK.h"
#include "edac/BPTC19696.h"
#include "edac/CRC.h"
#include "Utils.h"
using namespace dmr::lc;
using namespace dmr;
#include <cstdio>
#include <cassert>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the CSBK class.
/// </summary>
/// <param name="debug"></param>
CSBK::CSBK(bool debug) :
m_CSBKO(CSBKO_NONE),
m_FID(0x00U),
m_bsId(0U),
m_GI(false),
m_srcId(0U),
m_dstId(0U),
m_dataContent(false),
m_CBF(0U),
m_data(NULL),
m_debug(debug)
{
m_data = new uint8_t[12U];
}
/// <summary>
/// Finalizes a instance of the CSBK class.
/// </summary>
CSBK::~CSBK()
{
delete[] m_data;
}
/// <summary>
/// Decodes a DMR CSBK.
/// </summary>
/// <param name="bytes"></param>
/// <returns>True, if DMR CSBK was decoded, otherwise false.</returns>
bool CSBK::decode(const uint8_t* bytes)
{
assert(bytes != NULL);
// decode BPTC (196,96) FEC
edac::BPTC19696 bptc;
bptc.decode(bytes, m_data);
// validate the CRC-CCITT 16
m_data[10U] ^= CSBK_CRC_MASK[0U];
m_data[11U] ^= CSBK_CRC_MASK[1U];
bool valid = edac::CRC::checkCCITT162(m_data, DMR_LC_HEADER_LENGTH_BYTES);
if (!valid)
return false;
// restore the checksum
m_data[10U] ^= CSBK_CRC_MASK[0U];
m_data[11U] ^= CSBK_CRC_MASK[1U];
m_CSBKO = m_data[0U] & 0x3FU;
m_FID = m_data[1U];
switch (m_CSBKO) {
case CSBKO_BSDWNACT:
m_GI = false;
m_bsId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U];
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
m_dataContent = false;
m_CBF = 0U;
if (m_debug)
Utils::dump(1U, "Downlink Activate CSBK", m_data, DMR_LC_HEADER_LENGTH_BYTES);
break;
case CSBKO_UU_V_REQ:
m_GI = false;
m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U];
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
m_dataContent = false;
m_CBF = 0U;
if (m_debug)
Utils::dump(1U, "Unit to Unit Service Request CSBK", m_data, DMR_LC_HEADER_LENGTH_BYTES);
break;
case CSBKO_UU_ANS_RSP:
m_GI = false;
m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U];
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
m_dataContent = false;
m_CBF = 0U;
if (m_debug)
Utils::dump(1U, "Unit to Unit Service Answer Response CSBK", m_data, DMR_LC_HEADER_LENGTH_BYTES);
break;
case CSBKO_PRECCSBK:
m_GI = (m_data[2U] & 0x40U) == 0x40U;
m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U];
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
m_dataContent = (m_data[2U] & 0x80U) == 0x80U;
m_CBF = m_data[3U];
if (m_debug)
Utils::dump(1U, "Preamble CSBK", m_data, DMR_LC_HEADER_LENGTH_BYTES);
break;
case CSBKO_CALL_ALRT:
m_GI = (m_data[2U] & 0x40U) == 0x40U;
m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U];
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
m_dataContent = (m_data[2U] & 0x80U) == 0x80U;
m_CBF = m_data[3U];
if (m_debug)
Utils::dump(1U, "Call Alert CSBK", m_data, DMR_LC_HEADER_LENGTH_BYTES);
break;
case CSBKO_ACK_RSP:
m_GI = (m_data[2U] & 0x40U) == 0x40U;
m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U];
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
m_dataContent = (m_data[2U] & 0x80U) == 0x80U;
m_CBF = m_data[3U];
if (m_debug)
Utils::dump(1U, "ACK Response CSBK", m_data, DMR_LC_HEADER_LENGTH_BYTES);
break;
case CSBKO_EXT_FNCT:
m_GI = false;
m_dstId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U];
m_srcId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
m_dataContent = (m_data[2U] & 0x80U) == 0x80U;
m_CBF = m_data[3U];
if (m_debug)
Utils::dump(1U, "Extended Function CSBK", m_data, DMR_LC_HEADER_LENGTH_BYTES);
break;
case CSBKO_NACK_RSP:
m_GI = false;
m_srcId = m_data[4U] << 16 | m_data[5U] << 8 | m_data[6U];
m_dstId = m_data[7U] << 16 | m_data[8U] << 8 | m_data[9U];
m_dataContent = false;
m_CBF = 0U;
if (m_debug)
Utils::dump(1U, "Negative Acknowledge Response CSBK", m_data, DMR_LC_HEADER_LENGTH_BYTES);
break;
default:
m_GI = false;
m_srcId = 0U;
m_dstId = 0U;
m_dataContent = false;
m_CBF = 0U;
if (m_debug)
Utils::dump("Unhandled CSBK type", m_data, DMR_LC_HEADER_LENGTH_BYTES);
return true;
}
return true;
}
/// <summary>
/// Encodes a DMR CSBK.
/// </summary>
/// <param name="bytes"></param>
void CSBK::encode(uint8_t* bytes) const
{
assert(bytes != NULL);
m_data[0U] = m_CSBKO;
m_data[1U] = m_FID;
if (m_GI) {
m_data[2U] |= 0x40U;
}
if (m_dataContent) {
m_data[2U] |= 0x80U;
}
m_data[3U] = m_CBF;
if (m_CSBKO == CSBKO_EXT_FNCT) {
m_data[4U] = (m_srcId >> 16) & 0xFFU;
m_data[5U] = (m_srcId >> 8) & 0xFFU;
m_data[6U] = (m_srcId >> 0) & 0xFFU;
m_data[7U] = (m_dstId >> 16) & 0xFFU;
m_data[8U] = (m_dstId >> 8) & 0xFFU;
m_data[9U] = (m_dstId >> 0) & 0xFFU;
}
else {
m_data[4U] = (m_dstId >> 16) & 0xFFU;
m_data[5U] = (m_dstId >> 8) & 0xFFU;
m_data[6U] = (m_dstId >> 0) & 0xFFU;
m_data[7U] = (m_srcId >> 16) & 0xFFU;
m_data[8U] = (m_srcId >> 8) & 0xFFU;
m_data[9U] = (m_srcId >> 0) & 0xFFU;
}
m_data[10U] ^= CSBK_CRC_MASK[0U];
m_data[11U] ^= CSBK_CRC_MASK[1U];
edac::CRC::addCCITT162(m_data, 12U);
m_data[10U] ^= CSBK_CRC_MASK[0U];
m_data[11U] ^= CSBK_CRC_MASK[1U];
// encode BPTC (196,96) FEC
edac::BPTC19696 bptc;
bptc.encode(m_data, bytes);
}

@ -0,0 +1,90 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2019 by Bryan Biedenkapp N2PLL
*
* 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(__DMR_LC__CSBK_H__)
#define __DMR_LC__CSBK_H__
#include "Defines.h"
#include "dmr/DMRDefines.h"
namespace dmr
{
namespace lc
{
// ---------------------------------------------------------------------------
// Class Declaration
// Represents DMR control signalling block data.
// ---------------------------------------------------------------------------
class HOST_SW_API CSBK {
public:
/// <summary>Initializes a new instance of the CSBK class.</summary>
CSBK(bool debug);
/// <summary>Finalizes a instance of the CSBK class.</summary>
~CSBK();
/// <summary>Decodes a DMR CSBK.</summary>
bool decode(const uint8_t* bytes);
/// <summary>Encodes a DMR CSBK.</summary>
void encode(uint8_t* bytes) const;
public:
// Generic fields
/// <summary>CSBK opcode.</summary>
__PROPERTY(uint8_t, CSBKO, CSBKO);
/// <summary>CSBK feature ID.</summayr>
__PROPERTY(uint8_t, FID, FID);
// For BS Dwn Act
__READONLY_PROPERTY(uint32_t, bsId, BSId);
// For Pre
/// <summary>Flag indicating whether the CSBK is group or individual.</summary>
__PROPERTY(bool, GI, GI);
/// <summary>Source ID.</summary>
__PROPERTY(uint32_t, srcId, SrcId);
/// <summary>Destination ID.</summary>
__PROPERTY(uint32_t, dstId, DstId);
/// <summary></summary>
__READONLY_PROPERTY(bool, dataContent, DataContent);
/// <summary>Sets the number of blocks to follow.</summary>
__PROPERTY(uint8_t, CBF, CBF);
private:
uint8_t* m_data;
bool m_debug;
};
} // namespace lc
} // namespace dmr
#endif // __DMR_LC__CSBK_H__

@ -0,0 +1,140 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2012 by Ian Wraith
* 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 "Defines.h"
#include "dmr/DMRDefines.h"
#include "dmr/lc/FullLC.h"
#include "edac/RS129.h"
#include "Log.h"
#include "Utils.h"
using namespace dmr::lc;
using namespace dmr;
#include <cstdio>
#include <cassert>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initialize a new instance of the FullLC class.
/// </summary>
FullLC::FullLC() :
m_bptc()
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the FullLC class.
/// </summary>
FullLC::~FullLC()
{
/* stub */
}
/// <summary>
/// Decode DMR full-link control data.
/// </summary>
/// <param name="data"></param>
/// <param name="type"></param>
/// <returns></returns>
LC* FullLC::decode(const uint8_t* data, uint8_t type)
{
assert(data != NULL);
// decode BPTC (196,96) FEC
uint8_t lcData[DMR_LC_HEADER_LENGTH_BYTES];
m_bptc.decode(data, lcData);
switch (type) {
case DT_VOICE_LC_HEADER:
lcData[9U] ^= VOICE_LC_HEADER_CRC_MASK[0U];
lcData[10U] ^= VOICE_LC_HEADER_CRC_MASK[1U];
lcData[11U] ^= VOICE_LC_HEADER_CRC_MASK[2U];
break;
case DT_TERMINATOR_WITH_LC:
lcData[9U] ^= TERMINATOR_WITH_LC_CRC_MASK[0U];
lcData[10U] ^= TERMINATOR_WITH_LC_CRC_MASK[1U];
lcData[11U] ^= TERMINATOR_WITH_LC_CRC_MASK[2U];
break;
default:
LogError(LOG_DMR, "Unsupported LC type, type = %d", int(type));
return NULL;
}
// check RS (12,9) FEC
if (!edac::RS129::check(lcData))
return NULL;
return new LC(lcData);
}
/// <summary>
/// Encode DMR full-link control data.
/// </summary>
/// <param name="lc"></param>
/// <param name="data"></param>
/// <param name="type"></param>
void FullLC::encode(const LC& lc, uint8_t* data, uint8_t type)
{
assert(data != NULL);
uint8_t lcData[DMR_LC_HEADER_LENGTH_BYTES];
lc.getData(lcData);
// encode RS (12,9) FEC
uint8_t parity[4U];
edac::RS129::encode(lcData, 9U, parity);
switch (type) {
case DT_VOICE_LC_HEADER:
lcData[9U] = parity[2U] ^ VOICE_LC_HEADER_CRC_MASK[0U];
lcData[10U] = parity[1U] ^ VOICE_LC_HEADER_CRC_MASK[1U];
lcData[11U] = parity[0U] ^ VOICE_LC_HEADER_CRC_MASK[2U];
break;
case DT_TERMINATOR_WITH_LC:
lcData[9U] = parity[2U] ^ TERMINATOR_WITH_LC_CRC_MASK[0U];
lcData[10U] = parity[1U] ^ TERMINATOR_WITH_LC_CRC_MASK[1U];
lcData[11U] = parity[0U] ^ TERMINATOR_WITH_LC_CRC_MASK[2U];
break;
default:
LogError(LOG_DMR, "Unsupported LC type, type = %d", int(type));
return;
}
// encode BPTC (196,96) FEC
m_bptc.encode(lcData, data);
}

@ -0,0 +1,65 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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(__DMR_LC__FULL_LC_H__)
#define __DMR_LC__FULL_LC_H__
#include "Defines.h"
#include "dmr/lc/LC.h"
#include "dmr/SlotType.h"
#include "edac/BPTC19696.h"
namespace dmr
{
namespace lc
{
// ---------------------------------------------------------------------------
// Class Declaration
// Represents full DMR link control.
// ---------------------------------------------------------------------------
class HOST_SW_API FullLC {
public:
/// <summary>Initializes a new instance of the FullLC class.</summary>
FullLC();
/// <summary>Finalizes a instance of the FullLC class.</summary>
~FullLC();
/// <summary>Decode DMR full-link control data.</summary>
LC* decode(const uint8_t* data, uint8_t type);
/// <summary>Encode DMR full-link control data.</summary>
void encode(const LC& lc, uint8_t* data, uint8_t type);
private:
edac::BPTC19696 m_bptc;
};
} // namespace lc
} // namespace dmr
#endif // __DMR_LC__FULL_LC_H__

@ -0,0 +1,221 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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 "Defines.h"
#include "dmr/lc/LC.h"
#include "Utils.h"
using namespace dmr::lc;
using namespace dmr;
#include <cstdio>
#include <cassert>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the LC class.
/// </summary>
/// <param name="flco">Full-link Control Opcode.</param>
/// <param name="srcId">Source ID.</param>
/// <param name="dstId">Destination ID.</param>
LC::LC(uint8_t flco, uint32_t srcId, uint32_t dstId) :
m_PF(false),
m_FLCO(flco),
m_FID(0U),
m_srcId(srcId),
m_dstId(dstId),
m_R(false),
m_options(0U)
{
/* stub */
}
/// <summary>
/// Initializes a new instance of the LC class.
/// </summary>
/// <param name="bytes"></param>
LC::LC(const uint8_t* bytes) :
m_PF(false),
m_FLCO(FLCO_GROUP),
m_FID(0U),
m_srcId(0U),
m_dstId(0U),
m_R(false),
m_options(0U)
{
assert(bytes != NULL);
m_PF = (bytes[0U] & 0x80U) == 0x80U;
m_R = (bytes[0U] & 0x40U) == 0x40U;
m_FLCO = bytes[0U] & 0x3FU;
m_FID = bytes[1U];
m_options = bytes[2U];
m_dstId = bytes[3U] << 16 | bytes[4U] << 8 | bytes[5U];
m_srcId = bytes[6U] << 16 | bytes[7U] << 8 | bytes[8U];
}
/// <summary>
/// Initializes a new instance of the LC class.
/// </summary>
/// <param name="bits"></param>
LC::LC(const bool* bits) :
m_PF(false),
m_FLCO(FLCO_GROUP),
m_FID(0U),
m_srcId(0U),
m_dstId(0U),
m_R(false),
m_options(0U)
{
assert(bits != NULL);
m_PF = bits[0U];
m_R = bits[1U];
uint8_t temp1, temp2, temp3;
Utils::bitsToByteBE(bits + 0U, temp1);
m_FLCO = temp1 & 0x3FU;
Utils::bitsToByteBE(bits + 8U, temp2);
m_FID = temp2;
Utils::bitsToByteBE(bits + 16U, temp3);
m_options = temp3;
uint8_t d1, d2, d3;
Utils::bitsToByteBE(bits + 24U, d1);
Utils::bitsToByteBE(bits + 32U, d2);
Utils::bitsToByteBE(bits + 40U, d3);
uint8_t s1, s2, s3;
Utils::bitsToByteBE(bits + 48U, s1);
Utils::bitsToByteBE(bits + 56U, s2);
Utils::bitsToByteBE(bits + 64U, s3);
m_srcId = s1 << 16 | s2 << 8 | s3;
m_dstId = d1 << 16 | d2 << 8 | d3;
}
/// <summary>
/// Initializes a new instance of the LC class.
/// </summary>
LC::LC() :
m_PF(false),
m_FLCO(FLCO_GROUP),
m_FID(0U),
m_srcId(0U),
m_dstId(0U),
m_R(false),
m_options(0U)
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the LC class.
/// </summary>
LC::~LC()
{
/* stub */
}
/// <summary>
///
/// </summary>
/// <param name="bytes"></param>
void LC::getData(uint8_t* bytes) const
{
assert(bytes != NULL);
bytes[0U] = (uint8_t)m_FLCO;
if (m_PF)
bytes[0U] |= 0x80U;
if (m_R)
bytes[0U] |= 0x40U;
bytes[1U] = m_FID;
bytes[2U] = m_options;
bytes[3U] = m_dstId >> 16;
bytes[4U] = m_dstId >> 8;
bytes[5U] = m_dstId >> 0;
bytes[6U] = m_srcId >> 16;
bytes[7U] = m_srcId >> 8;
bytes[8U] = m_srcId >> 0;
}
/// <summary>
///
/// </summary>
/// <param name="bits"></param>
void LC::getData(bool* bits) const
{
assert(bits != NULL);
uint8_t bytes[9U];
getData(bytes);
Utils::byteToBitsBE(bytes[0U], bits + 0U);
Utils::byteToBitsBE(bytes[1U], bits + 8U);
Utils::byteToBitsBE(bytes[2U], bits + 16U);
Utils::byteToBitsBE(bytes[3U], bits + 24U);
Utils::byteToBitsBE(bytes[4U], bits + 32U);
Utils::byteToBitsBE(bytes[5U], bits + 40U);
Utils::byteToBitsBE(bytes[6U], bits + 48U);
Utils::byteToBitsBE(bytes[7U], bits + 56U);
Utils::byteToBitsBE(bytes[8U], bits + 64U);
}
/// <summary>
///
/// </summary>
/// <returns></returns>
bool LC::getOVCM() const
{
return (m_options & 0x04U) == 0x04U;
}
/// <summary>
///
/// </summary>
/// <param name="ovcm"></param>
void LC::setOVCM(bool ovcm)
{
if (ovcm)
m_options |= 0x04U;
else
m_options &= 0xFBU;
}

@ -0,0 +1,90 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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(__DMR_LC__LC_H__)
#define __DMR_LC__LC_H__
#include "Defines.h"
#include "dmr/DMRDefines.h"
namespace dmr
{
namespace lc
{
// ---------------------------------------------------------------------------
// Class Declaration
// Represents DMR link control data.
// ---------------------------------------------------------------------------
class HOST_SW_API LC {
public:
/// <summary>Initializes a new instance of the LC class.</summary>
LC(uint8_t flco, uint32_t srcId, uint32_t dstId);
/// <summary>Initializes a new instance of the LC class.</summary>
LC(const uint8_t* bytes);
/// <summary>Initializes a new instance of the LC class.</summary>
LC(const bool* bits);
/// <summary>Initializes a new instance of the LC class.</summary>
LC();
/// <summary>Finalizes a instance of the LC class.</summary>
~LC();
/// <summary></summary>
void getData(uint8_t* bytes) const;
/// <summary></summary>
void getData(bool* bits) const;
/// <summary></summary>
bool getOVCM() const;
/// <summary></summary>
void setOVCM(bool ovcm);
public:
/// <summary>Flag indicating whether link protection is enabled.</summary>
__PROPERTY(bool, PF, PF);
/// <summary>Full-link control opcode.</summary>
__PROPERTY(uint8_t, FLCO, FLCO);
/// <summary>CSBK feature ID.</summayr>
__PROPERTY(uint8_t, FID, FID);
/// <summary>Sets the source ID.</summary>
__PROPERTY(uint32_t, srcId, SrcId);
/// <summary>Sets the destination ID.</summary>
__PROPERTY(uint32_t, dstId, DstId);
private:
bool m_R;
uint8_t m_options;
};
} // namespace lc
} // namespace dmr
#endif // __DMR_LC__LC_H__

@ -0,0 +1,287 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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 "Defines.h"
#include "dmr/lc/ShortLC.h"
#include "edac/Hamming.h"
#include "Utils.h"
using namespace dmr::lc;
using namespace dmr;
#include <cstdio>
#include <cassert>
#include <cstring>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the ShortLC class.
/// </summary>
ShortLC::ShortLC() :
m_rawData(NULL),
m_deInterData(NULL)
{
m_rawData = new bool[72U];
m_deInterData = new bool[68U];
}
/// <summary>
/// Finalizes a instance of the ShortLC class.
/// </summary>
ShortLC::~ShortLC()
{
delete[] m_rawData;
delete[] m_deInterData;
}
/// <summary>
/// Decode DMR short-link control data.
/// </summary>
/// <param name="in"></param>
/// <param name="out"></param>
/// <returns></returns>
bool ShortLC::decode(const uint8_t* in, uint8_t* out)
{
assert(in != NULL);
assert(out != NULL);
// Get the raw binary
decodeExtractBinary(in);
// Deinterleave
decodeDeInterleave();
// Error check
bool ret = decodeErrorCheck();
if (!ret)
return false;
// Extract Data
decodeExtractData(out);
return true;
}
/// <summary>
/// Encode DMR short-link control data.
/// </summary>
/// <param name="in"></param>
/// <param name="out"></param>
void ShortLC::encode(const uint8_t* in, uint8_t* out)
{
assert(in != NULL);
assert(out != NULL);
// Extract Data
encodeExtractData(in);
// Error check
encodeErrorCheck();
// Deinterleave
encodeInterleave();
// Get the raw binary
encodeExtractBinary(out);
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
///
/// </summary>
/// <param name="in"></param>
void ShortLC::decodeExtractBinary(const uint8_t* in)
{
assert(in != NULL);
Utils::byteToBitsBE(in[0U], m_rawData + 0U);
Utils::byteToBitsBE(in[1U], m_rawData + 8U);
Utils::byteToBitsBE(in[2U], m_rawData + 16U);
Utils::byteToBitsBE(in[3U], m_rawData + 24U);
Utils::byteToBitsBE(in[4U], m_rawData + 32U);
Utils::byteToBitsBE(in[5U], m_rawData + 40U);
Utils::byteToBitsBE(in[6U], m_rawData + 48U);
Utils::byteToBitsBE(in[7U], m_rawData + 56U);
Utils::byteToBitsBE(in[8U], m_rawData + 64U);
}
/// <summary>
///
/// </summary>
void ShortLC::decodeDeInterleave()
{
for (uint32_t i = 0U; i < 68U; i++)
m_deInterData[i] = false;
for (uint32_t a = 0U; a < 67U; a++) {
// Calculate the interleave sequence
uint32_t interleaveSequence = (a * 4U) % 67U;
// Shuffle the data
m_deInterData[a] = m_rawData[interleaveSequence];
}
m_deInterData[67U] = m_rawData[67U];
}
/// <summary>
///
/// </summary>
/// <returns></returns>
bool ShortLC::decodeErrorCheck()
{
// Run through each of the 3 rows containing data
edac::Hamming::decode17123(m_deInterData + 0U);
edac::Hamming::decode17123(m_deInterData + 17U);
edac::Hamming::decode17123(m_deInterData + 34U);
// Run through each of the 17 columns
for (uint32_t c = 0U; c < 17U; c++) {
bool bit = m_deInterData[c + 0U] ^ m_deInterData[c + 17U] ^ m_deInterData[c + 34U];
if (bit != m_deInterData[c + 51U])
return false;
}
return true;
}
/// <summary>
///
/// </summary>
/// <param name="data"></param>
void ShortLC::decodeExtractData(uint8_t* data) const
{
assert(data != NULL);
bool bData[40U];
for (uint32_t i = 0U; i < 40U; i++)
bData[i] = false;
uint32_t pos = 4U;
for (uint32_t a = 0U; a < 12U; a++, pos++)
bData[pos] = m_deInterData[a];
for (uint32_t a = 17U; a < 29U; a++, pos++)
bData[pos] = m_deInterData[a];
for (uint32_t a = 34U; a < 46U; a++, pos++)
bData[pos] = m_deInterData[a];
Utils::bitsToByteBE(bData + 0U, data[0U]);
Utils::bitsToByteBE(bData + 8U, data[1U]);
Utils::bitsToByteBE(bData + 16U, data[2U]);
Utils::bitsToByteBE(bData + 24U, data[3U]);
Utils::bitsToByteBE(bData + 32U, data[4U]);
}
/// <summary>
///
/// </summary>
/// <param name="in"></param>
void ShortLC::encodeExtractData(const uint8_t* in) const
{
assert(in != NULL);
bool bData[40U];
Utils::byteToBitsBE(in[0U], bData + 0U);
Utils::byteToBitsBE(in[1U], bData + 8U);
Utils::byteToBitsBE(in[2U], bData + 16U);
Utils::byteToBitsBE(in[3U], bData + 24U);
Utils::byteToBitsBE(in[4U], bData + 32U);
for (uint32_t i = 0U; i < 68U; i++)
m_deInterData[i] = false;
uint32_t pos = 4U;
for (uint32_t a = 0U; a < 12U; a++, pos++)
m_deInterData[a] = bData[pos];
for (uint32_t a = 17U; a < 29U; a++, pos++)
m_deInterData[a] = bData[pos];
for (uint32_t a = 34U; a < 46U; a++, pos++)
m_deInterData[a] = bData[pos];
}
/// <summary>
///
/// </summary>
void ShortLC::encodeErrorCheck()
{
// Run through each of the 3 rows containing data
edac::Hamming::encode17123(m_deInterData + 0U);
edac::Hamming::encode17123(m_deInterData + 17U);
edac::Hamming::encode17123(m_deInterData + 34U);
// Run through each of the 17 columns
for (uint32_t c = 0U; c < 17U; c++)
m_deInterData[c + 51U] = m_deInterData[c + 0U] ^ m_deInterData[c + 17U] ^ m_deInterData[c + 34U];
}
/// <summary>
///
/// </summary>
void ShortLC::encodeInterleave()
{
for (uint32_t i = 0U; i < 72U; i++)
m_rawData[i] = false;
for (uint32_t a = 0U; a < 67U; a++) {
// Calculate the interleave sequence
uint32_t interleaveSequence = (a * 4U) % 67U;
// Unshuffle the data
m_rawData[interleaveSequence] = m_deInterData[a];
}
m_rawData[67U] = m_deInterData[67U];
}
/// <summary>
///
/// </summary>
/// <param name="data"></param>
void ShortLC::encodeExtractBinary(uint8_t* data)
{
assert(data != NULL);
Utils::bitsToByteBE(m_rawData + 0U, data[0U]);
Utils::bitsToByteBE(m_rawData + 8U, data[1U]);
Utils::bitsToByteBE(m_rawData + 16U, data[2U]);
Utils::bitsToByteBE(m_rawData + 24U, data[3U]);
Utils::bitsToByteBE(m_rawData + 32U, data[4U]);
Utils::bitsToByteBE(m_rawData + 40U, data[5U]);
Utils::bitsToByteBE(m_rawData + 48U, data[6U]);
Utils::bitsToByteBE(m_rawData + 56U, data[7U]);
Utils::bitsToByteBE(m_rawData + 64U, data[8U]);
}

@ -0,0 +1,81 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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(__DMR_LC__SHORT_LC_H__)
#define __DMR_LC__SHORT_LC_H__
#include "Defines.h"
namespace dmr
{
namespace lc
{
// ---------------------------------------------------------------------------
// Class Declaration
// Represents short DMR link control.
// ---------------------------------------------------------------------------
class HOST_SW_API ShortLC {
public:
/// <summary>Initializes a new instance of the ShortLC class.</summary>
ShortLC();
/// <summary>Finalizes a instance of the ShortLC class.</summary>
~ShortLC();
/// <summary>Decode DMR short-link control data.</summary>
bool decode(const uint8_t* in, uint8_t* out);
/// <summary>Encode DMR short-link control data.</summary>
void encode(const uint8_t* in, uint8_t* out);
private:
bool* m_rawData;
bool* m_deInterData;
/// <summary></summary>
void decodeExtractBinary(const uint8_t* in);
/// <summary></summary>
void decodeDeInterleave();
/// <summary></summary>
bool decodeErrorCheck();
/// <summary></summary>
void decodeExtractData(uint8_t* data) const;
/// <summary></summary>
void encodeExtractData(const uint8_t* in) const;
/// <summary></summary>
void encodeErrorCheck();
/// <summary></summary>
void encodeInterleave();
/// <summary></summary>
void encodeExtractBinary(uint8_t* data);
};
} // namespace lc
} // namespace dmr
#endif // __DMR_LC__SHORT_LC_H__

@ -0,0 +1,554 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2010,2014,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2016 Mathias Weyland, HB9FRV
*
* 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 "Defines.h"
#include "edac/AMBEFEC.h"
#include "edac/Golay24128.h"
#include "edac/Hamming.h"
using namespace edac;
#include <cstdio>
#include <cassert>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the AMBEFEC class.
/// </summary>
AMBEFEC::AMBEFEC()
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the AMBEFEC class.
/// </summary>
AMBEFEC::~AMBEFEC()
{
/* stub */
}
/// <summary>
/// Regnerates the DMR AMBE FEC for the input bytes.
/// </summary>
/// <param name="bytes"></param>
/// <returns>Count of errors.</returns>
uint32_t AMBEFEC::regenerateDMR(uint8_t* bytes) const
{
assert(bytes != NULL);
uint32_t a1 = 0U, a2 = 0U, a3 = 0U;
uint32_t b1 = 0U, b2 = 0U, b3 = 0U;
uint32_t c1 = 0U, c2 = 0U, c3 = 0U;
uint32_t MASK = 0x800000U;
for (uint32_t i = 0U; i < 24U; i++) {
uint32_t a1Pos = DMR_A_TABLE[i];
uint32_t b1Pos = DMR_B_TABLE[i];
uint32_t c1Pos = DMR_C_TABLE[i];
uint32_t a2Pos = a1Pos + 72U;
if (a2Pos >= 108U)
a2Pos += 48U;
uint32_t b2Pos = b1Pos + 72U;
if (b2Pos >= 108U)
b2Pos += 48U;
uint32_t c2Pos = c1Pos + 72U;
if (c2Pos >= 108U)
c2Pos += 48U;
uint32_t a3Pos = a1Pos + 192U;
uint32_t b3Pos = b1Pos + 192U;
uint32_t c3Pos = c1Pos + 192U;
if (READ_BIT(bytes, a1Pos))
a1 |= MASK;
if (READ_BIT(bytes, a2Pos))
a2 |= MASK;
if (READ_BIT(bytes, a3Pos))
a3 |= MASK;
if (READ_BIT(bytes, b1Pos))
b1 |= MASK;
if (READ_BIT(bytes, b2Pos))
b2 |= MASK;
if (READ_BIT(bytes, b3Pos))
b3 |= MASK;
if (READ_BIT(bytes, c1Pos))
c1 |= MASK;
if (READ_BIT(bytes, c2Pos))
c2 |= MASK;
if (READ_BIT(bytes, c3Pos))
c3 |= MASK;
MASK >>= 1;
}
uint32_t errors = regenerate(a1, b1, c1, true);
errors += regenerate(a2, b2, c2, true);
errors += regenerate(a3, b3, c3, true);
MASK = 0x800000U;
for (uint32_t i = 0U; i < 24U; i++) {
uint32_t a1Pos = DMR_A_TABLE[i];
uint32_t b1Pos = DMR_B_TABLE[i];
uint32_t c1Pos = DMR_C_TABLE[i];
uint32_t a2Pos = a1Pos + 72U;
if (a2Pos >= 108U)
a2Pos += 48U;
uint32_t b2Pos = b1Pos + 72U;
if (b2Pos >= 108U)
b2Pos += 48U;
uint32_t c2Pos = c1Pos + 72U;
if (c2Pos >= 108U)
c2Pos += 48U;
uint32_t a3Pos = a1Pos + 192U;
uint32_t b3Pos = b1Pos + 192U;
uint32_t c3Pos = c1Pos + 192U;
WRITE_BIT(bytes, a1Pos, a1 & MASK);
WRITE_BIT(bytes, a2Pos, a2 & MASK);
WRITE_BIT(bytes, a3Pos, a3 & MASK);
WRITE_BIT(bytes, b1Pos, b1 & MASK);
WRITE_BIT(bytes, b2Pos, b2 & MASK);
WRITE_BIT(bytes, b3Pos, b3 & MASK);
WRITE_BIT(bytes, c1Pos, c1 & MASK);
WRITE_BIT(bytes, c2Pos, c2 & MASK);
WRITE_BIT(bytes, c3Pos, c3 & MASK);
MASK >>= 1;
}
return errors;
}
/// <summary>
/// Returns the number of errors on the DMR BER input bytes.
/// </summary>
/// <param name="bytes"></param>
/// <returns>Count of errors.</returns>
uint32_t AMBEFEC::measureDMRBER(const uint8_t* bytes) const
{
assert(bytes != NULL);
uint32_t a1 = 0U, a2 = 0U, a3 = 0U;
uint32_t b1 = 0U, b2 = 0U, b3 = 0U;
uint32_t c1 = 0U, c2 = 0U, c3 = 0U;
uint32_t MASK = 0x800000U;
for (uint32_t i = 0U; i < 24U; i++) {
uint32_t a1Pos = DMR_A_TABLE[i];
uint32_t b1Pos = DMR_B_TABLE[i];
uint32_t c1Pos = DMR_C_TABLE[i];
uint32_t a2Pos = a1Pos + 72U;
if (a2Pos >= 108U)
a2Pos += 48U;
uint32_t b2Pos = b1Pos + 72U;
if (b2Pos >= 108U)
b2Pos += 48U;
uint32_t c2Pos = c1Pos + 72U;
if (c2Pos >= 108U)
c2Pos += 48U;
uint32_t a3Pos = a1Pos + 192U;
uint32_t b3Pos = b1Pos + 192U;
uint32_t c3Pos = c1Pos + 192U;
if (READ_BIT(bytes, a1Pos))
a1 |= MASK;
if (READ_BIT(bytes, a2Pos))
a2 |= MASK;
if (READ_BIT(bytes, a3Pos))
a3 |= MASK;
if (READ_BIT(bytes, b1Pos))
b1 |= MASK;
if (READ_BIT(bytes, b2Pos))
b2 |= MASK;
if (READ_BIT(bytes, b3Pos))
b3 |= MASK;
if (READ_BIT(bytes, c1Pos))
c1 |= MASK;
if (READ_BIT(bytes, c2Pos))
c2 |= MASK;
if (READ_BIT(bytes, c3Pos))
c3 |= MASK;
MASK >>= 1;
}
uint32_t errors = regenerate(a1, b1, c1, true);
errors += regenerate(a2, b2, c2, true);
errors += regenerate(a3, b3, c3, true);
return errors;
}
/// <summary>
/// Regenerates the P25 IMBE FEC for the input bytes.
/// </summary>
/// <param name="bytes"></param>
/// <returns>Count of errors.</returns>
uint32_t AMBEFEC::regenerateIMBE(uint8_t* bytes) const
{
assert(bytes != NULL);
bool orig[144U];
bool temp[144U];
// De-interleave
for (uint32_t i = 0U; i < 144U; i++) {
uint32_t n = IMBE_INTERLEAVE[i];
orig[i] = temp[i] = READ_BIT(bytes, n);
}
// now ..
// 12 voice bits 0
// 11 golay bits 12
//
// 12 voice bits 23
// 11 golay bits 35
//
// 12 voice bits 46
// 11 golay bits 58
//
// 12 voice bits 69
// 11 golay bits 81
//
// 11 voice bits 92
// 4 hamming bits 103
//
// 11 voice bits 107
// 4 hamming bits 118
//
// 11 voice bits 122
// 4 hamming bits 133
//
// 7 voice bits 137
// Process the c0 section first to allow the de-whitening to be accurate
// Check/Fix FEC
bool* bit = temp;
// c0
uint32_t g1 = 0U;
for (uint32_t i = 0U; i < 23U; i++)
g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U);
uint32_t c0data = Golay24128::decode23127(g1);
uint32_t g2 = Golay24128::encode23127(c0data);
for (int i = 23; i >= 0; i--) {
bit[i] = (g2 & 0x01U) == 0x01U;
g2 >>= 1;
}
bit += 23U;
bool prn[114U];
// Create the whitening vector and save it for future use
uint32_t p = 16U * c0data;
for (uint32_t i = 0U; i < 114U; i++) {
p = (173U * p + 13849U) % 65536U;
prn[i] = p >= 32768U;
}
// De-whiten some bits
for (uint32_t i = 0U; i < 114U; i++)
temp[i + 23U] ^= prn[i];
// c1
g1 = 0U;
for (uint32_t i = 0U; i < 23U; i++)
g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U);
uint32_t c1data = Golay24128::decode23127(g1);
g2 = Golay24128::encode23127(c1data);
for (int i = 23; i >= 0; i--) {
bit[i] = (g2 & 0x01U) == 0x01U;
g2 >>= 1;
}
bit += 23U;
// c2
g1 = 0;
for (uint32_t i = 0U; i < 23U; i++)
g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U);
uint32_t c2data = Golay24128::decode23127(g1);
g2 = Golay24128::encode23127(c2data);
for (int i = 23; i >= 0; i--) {
bit[i] = (g2 & 0x01U) == 0x01U;
g2 >>= 1;
}
bit += 23U;
// c3
g1 = 0U;
for (uint32_t i = 0U; i < 23U; i++)
g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U);
uint32_t c3data = Golay24128::decode23127(g1);
g2 = Golay24128::encode23127(c3data);
for (int i = 23; i >= 0; i--) {
bit[i] = (g2 & 0x01U) == 0x01U;
g2 >>= 1;
}
bit += 23U;
// c4
Hamming::decode15113_1(bit);
bit += 15U;
// c5
Hamming::decode15113_1(bit);
bit += 15U;
// c6
Hamming::decode15113_1(bit);
// Whiten some bits
for (uint32_t i = 0U; i < 114U; i++)
temp[i + 23U] ^= prn[i];
uint32_t errors = 0U;
for (uint32_t i = 0U; i < 144U; i++) {
if (orig[i] != temp[i])
errors++;
}
// Interleave
for (uint32_t i = 0U; i < 144U; i++) {
uint32_t n = IMBE_INTERLEAVE[i];
WRITE_BIT(bytes, n, temp[i]);
}
return errors;
}
/// <summary>
/// Returns the number of errors on the P25 BER input bytes.
/// </summary>
/// <param name="bytes"></param>
/// <returns>Count of errors.</returns>
uint32_t AMBEFEC::measureP25BER(const uint8_t* bytes) const
{
assert(bytes != NULL);
bool orig[144U];
bool temp[144U];
// De-interleave
for (uint32_t i = 0U; i < 144U; i++) {
uint32_t n = IMBE_INTERLEAVE[i];
orig[i] = temp[i] = READ_BIT(bytes, n);
}
// now ..
// 12 voice bits 0
// 11 golay bits 12
//
// 12 voice bits 23
// 11 golay bits 35
//
// 12 voice bits 46
// 11 golay bits 58
//
// 12 voice bits 69
// 11 golay bits 81
//
// 11 voice bits 92
// 4 hamming bits 103
//
// 11 voice bits 107
// 4 hamming bits 118
//
// 11 voice bits 122
// 4 hamming bits 133
//
// 7 voice bits 137
// Process the c0 section first to allow the de-whitening to be accurate
// Check/Fix FEC
bool* bit = temp;
// c0
uint32_t g1 = 0U;
for (uint32_t i = 0U; i < 23U; i++)
g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U);
uint32_t c0data = Golay24128::decode23127(g1);
uint32_t g2 = Golay24128::encode23127(c0data);
for (int i = 23; i >= 0; i--) {
bit[i] = (g2 & 0x01U) == 0x01U;
g2 >>= 1;
}
bit += 23U;
bool prn[114U];
// Create the whitening vector and save it for future use
uint32_t p = 16U * c0data;
for (uint32_t i = 0U; i < 114U; i++) {
p = (173U * p + 13849U) % 65536U;
prn[i] = p >= 32768U;
}
// De-whiten some bits
for (uint32_t i = 0U; i < 114U; i++)
temp[i + 23U] ^= prn[i];
// c1
g1 = 0U;
for (uint32_t i = 0U; i < 23U; i++)
g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U);
uint32_t c1data = Golay24128::decode23127(g1);
g2 = Golay24128::encode23127(c1data);
for (int i = 23; i >= 0; i--) {
bit[i] = (g2 & 0x01U) == 0x01U;
g2 >>= 1;
}
bit += 23U;
// c2
g1 = 0;
for (uint32_t i = 0U; i < 23U; i++)
g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U);
uint32_t c2data = Golay24128::decode23127(g1);
g2 = Golay24128::encode23127(c2data);
for (int i = 23; i >= 0; i--) {
bit[i] = (g2 & 0x01U) == 0x01U;
g2 >>= 1;
}
bit += 23U;
// c3
g1 = 0U;
for (uint32_t i = 0U; i < 23U; i++)
g1 = (g1 << 1) | (bit[i] ? 0x01U : 0x00U);
uint32_t c3data = Golay24128::decode23127(g1);
g2 = Golay24128::encode23127(c3data);
for (int i = 23; i >= 0; i--) {
bit[i] = (g2 & 0x01U) == 0x01U;
g2 >>= 1;
}
bit += 23U;
// c4
Hamming::decode15113_1(bit);
bit += 15U;
// c5
Hamming::decode15113_1(bit);
bit += 15U;
// c6
Hamming::decode15113_1(bit);
// Whiten some bits
for (uint32_t i = 0U; i < 114U; i++)
temp[i + 23U] ^= prn[i];
uint32_t errors = 0U;
for (uint32_t i = 0U; i < 144U; i++) {
if (orig[i] != temp[i])
errors++;
}
return errors;
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
///
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="c"></param>
/// <param name="b23"></param>
/// <returns></returns>
uint32_t AMBEFEC::regenerate(uint32_t& a, uint32_t& b, uint32_t& c, bool b23) const
{
uint32_t old_a = a;
uint32_t old_b = b;
// For the b23 bypass
bool b24 = (b & 0x01U) == 0x01U;
uint32_t data = Golay24128::decode24128(a);
uint32_t new_a = Golay24128::encode24128(data);
// The PRNG
uint32_t p = PRNG_TABLE[data];
b ^= p;
uint32_t datb = Golay24128::decode24128(b);
uint32_t new_b = Golay24128::encode24128(datb);
new_b ^= p;
if (b23) {
new_b &= 0xFFFFFEU;
new_b |= b24 ? 0x01U : 0x00U;
}
uint32_t errsA = 0U, errsB = 0U;
uint32_t v = new_a ^ old_a;
while (v != 0U) {
v &= v - 1U;
errsA++;
}
v = new_b ^ old_b;
while (v != 0U) {
v &= v - 1U;
errsB++;
}
if (b23) {
if (errsA >= 4U || ((errsA + errsB) >= 6U && errsA >= 2U)) {
a = 0xF00292U;
b = 0x0E0B20U;
c = 0x000000U;
}
}
a = new_a;
b = new_b;
return errsA + errsB;
}

@ -0,0 +1,500 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2010,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.
*/
#if !defined(__AMBE_FEC_H__)
#define __AMBE_FEC_H__
#include "Defines.h"
namespace edac
{
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const uint32_t PRNG_TABLE[] = {
0x42CC47U, 0x19D6FEU, 0x304729U, 0x6B2CD0U, 0x60BF47U, 0x39650EU, 0x7354F1U, 0xEACF60U, 0x819C9FU, 0xDE25CEU,
0xD7B745U, 0x8CC8B8U, 0x8D592BU, 0xF71257U, 0xBCA084U, 0xA5B329U, 0xEE6AFAU, 0xF7D9A7U, 0xBCC21CU, 0x4712D9U,
0x4F2922U, 0x14FA37U, 0x5D43ECU, 0x564115U, 0x299A92U, 0x20A9EBU, 0x7B707DU, 0x3BE3A4U, 0x20D95BU, 0x6B085AU,
0x5233A5U, 0x99A474U, 0xC0EDCBU, 0xCB5F12U, 0x918455U, 0xF897ECU, 0xE32E3BU, 0xAA7CC2U, 0xB1E7C9U, 0xFC561DU,
0xA70DE6U, 0x8DBE73U, 0xD4F608U, 0x57658DU, 0x0E5E56U, 0x458DABU, 0x7E15B8U, 0x376645U, 0x2DFD86U, 0x64EC3BU,
0x3F1F60U, 0x3481B4U, 0x4DA00FU, 0x067BCEU, 0x1B68B1U, 0xD19328U, 0xCA03FFU, 0xA31856U, 0xF8EB81U, 0xF9F2F8U,
0xA26067U, 0xA91BB6U, 0xF19A59U, 0x9A6148U, 0x8372B6U, 0xC8E86FU, 0x9399DCU, 0x1A0291U, 0x619142U, 0x6DE9FFU,
0x367A2CU, 0x7D2511U, 0x6484DAU, 0x2F1F0FU, 0x1E6DB4U, 0x55F6E1U, 0x0EA70AU, 0x061C96U, 0xDD0E45U, 0xB4D738U,
0xAF64ABU, 0xE47F42U, 0xFDBE9DU, 0xB684ACU, 0xFE5773U, 0xC1E4A2U, 0x8AFD0DU, 0x932ED4U, 0xD814E3U, 0x81853AU,
0x225EECU, 0x7A6945U, 0x31A112U, 0x2AB2EBU, 0x630974U, 0x785AB5U, 0x11E3CEU, 0x4A715BU, 0x402AA0U, 0x199B7DU,
0x16C05EU, 0x6F5283U, 0xA4FB10U, 0xBFA8ECU, 0xF633B7U, 0xEC4012U, 0xADD8C9U, 0xD6EB1CU, 0xDD3027U, 0x84A1FAU,
0xCF9E19U, 0xD64C80U, 0xBC4557U, 0xA7B62EU, 0x6E2DA1U, 0x311F50U, 0x38C68EU, 0x63D5BFU, 0x486E60U, 0x10BFE1U,
0x5BAD1EU, 0x4A4647U, 0x0157F0U, 0x7ACC29U, 0x73BEEAU, 0x2825D7U, 0xA0940CU, 0xFBCFF9U, 0xB05C62U, 0x892426U,
0xC6B3DDU, 0xDF3840U, 0x9449B3U, 0xCED3BEU, 0xE7804DU, 0xBC3B90U, 0xF5AA0BU, 0xE6D17EU, 0x2D43B5U, 0x345A04U,
0x5EA9DBU, 0x07A202U, 0x0C7134U, 0x45C9FDU, 0x5EDA0AU, 0x310193U, 0x6830C4U, 0x62AA3DU, 0x3B59B2U, 0xB04043U,
0xEB975CU, 0x82BCADU, 0x912E62U, 0xD8F7FBU, 0x82C489U, 0x895F54U, 0xF00FE7U, 0xFBBC2AU, 0xA2E771U, 0xE956C4U,
0xF6CD1FU, 0x3F8FEAU, 0x0534E1U, 0x4C653CU, 0x17FE8FU, 0x1C4C52U, 0x4515A1U, 0x2E86A9U, 0x3FBD56U, 0x756C87U,
0x6ED218U, 0x279179U, 0x7C0AA6U, 0xD53B17U, 0x8EE0C8U, 0x85F291U, 0xD94B36U, 0x9298EFU, 0xAB8318U, 0xE07301U,
0xBB68DFU, 0xB2CB7CU, 0xE910A5U, 0xE101D2U, 0x92BB4BU, 0x59E8B4U, 0x407175U, 0x0B026AU, 0x12989BU, 0x792944U,
0x2376EDU, 0x2EF5BAU, 0x758663U, 0x7C1ED5U, 0x078D0CU, 0x4EF6ABU, 0x5567F2U, 0x9F7C29U, 0xC68E9CU, 0xC51747U,
0xBC6422U, 0xB7EFB9U, 0xECFD44U, 0xA50497U, 0xAF178AU, 0xD68C69U, 0xD97DB5U, 0x82670EU, 0xCBB45BU, 0x508D90U,
0x190A25U, 0x63F0FEU, 0x68E3C7U, 0x317A10U, 0x3A09D9U, 0x6B926EU, 0x004237U, 0x1B79C8U, 0x53EA59U, 0x48B3B7U,
0x811166U, 0xDE4A79U, 0xF5F988U, 0xAC6057U, 0xE733FEU, 0xFF89ADU, 0xB49830U, 0x8F4BC3U, 0xC6F00EU, 0x9DA135U,
0x942FE0U, 0xC71C3BU, 0x4DC78FU, 0x3476C4U, 0x7F6C39U, 0x66BFAAU, 0x298657U, 0x725504U, 0x5B4E89U, 0x01FE72U,
0x0835A3U, 0x53269CU, 0x189D4DU, 0x01CDC2U, 0xEA763BU, 0xF3A56DU, 0xB0BCD4U, 0xE80F13U, 0xE355CAU, 0x98C47DU,
0x91AB24U, 0xCE38DBU, 0x87A35AU, 0x9CD3A5U, 0xD648F4U, 0xAF7B6FU, 0x24A292U, 0x7D3011U, 0x764B6DU, 0x2DDABEU,
0x44D123U, 0x5E22D8U, 0x1FB09DU, 0x04A926U, 0x4F5AF3U, 0x064128U, 0x3DB105U, 0x70AAD6U, 0xAA392FU, 0xA1C4B8U,
0xF8C7C0U, 0xD35D0FU, 0x8A2E9EU, 0xC1B761U, 0xDA44F0U, 0x925E8FU, 0x89CF4EU, 0xE8B4D1U, 0xB32728U, 0xB8FE7FU,
0x61DCC6U, 0x2A4701U, 0x1614D8U, 0x5DADE2U, 0x46BE37U, 0x0F44DCU, 0x54D549U, 0x5D8E32U, 0x263DAFU, 0x2C237CU,
0x75E291U, 0xBE5982U, 0xA74A7FU, 0xC493A4U, 0xDFA131U, 0x967A5AU, 0xCCCB8EU, 0xC1D835U, 0x9A02ECU, 0xF331BBU,
0xE8B812U, 0xA3EBC5U, 0xBA507CU, 0x7080ABU, 0x099BC2U, 0x02285DU, 0x59718CU, 0x50C273U, 0x0B1862U, 0x4A1F8CU,
0x70A655U, 0x3BF5C2U, 0x666FBBU, 0x6DDE68U, 0x3485C5U, 0x9F161EU, 0xC46F4BU, 0x8CFDF0U, 0x97C625U, 0xDE058EU,
0xC59CD3U, 0xAEAE20U, 0xF775BCU, 0xFC647FU, 0xBD9F02U, 0xE70C91U, 0xCC1468U, 0x11E7B7U, 0x1AFC36U, 0x435B49U,
0x080398U, 0x139027U, 0x7B63FEU, 0x607AF9U, 0x29E900U, 0x7293D6U, 0x79026FU, 0x00D930U, 0x0BEAF1U, 0xD3614EU,
0x90119FU, 0x8B8AE4U, 0xC61969U, 0xBD609AU, 0xB4F247U, 0xEFA954U, 0xE518A9U, 0xBC0362U, 0xD7D0D6U, 0xCE7E8DU,
0x856F18U, 0x1C94E3U, 0x578726U, 0x0D5F1DU, 0x24ECC0U, 0x7FF713U, 0x3E26AAU, 0x251D6DU, 0x6A8F14U, 0x53648BU,
0x19757AU, 0x40AEB4U, 0xCB9CA5U, 0x90055AU, 0x9956C3U, 0xE2ED34U, 0xAB3C7DU, 0xB126EAU, 0xFA9513U, 0xA3D2C8U,
0x886BFDU, 0xD9F836U, 0xD2A2E3U, 0x8D1359U, 0x454804U, 0x5EDBF7U, 0x37637AU, 0x2C3089U, 0x67ABD4U, 0x3E8847U,
0x3551BAU, 0x4D6331U, 0x46B8C4U, 0x1D299FU, 0x54120EU, 0x5FC0E1U, 0x86D93BU, 0xE56A0EU, 0xFBB1D5U, 0xB2B600U,
0xA94EABU, 0xE05DF6U, 0x9BE605U, 0x90B798U, 0xC92C6BU, 0xC3DE66U, 0x9AC7BDU, 0xD15448U, 0x6A3FD3U, 0x23ADA3U,
0x78346CU, 0x7147F5U, 0x2BDC02U, 0x0EAD5BU, 0x553FFCU, 0x1EA425U, 0x07D5F2U, 0x4C4ECBU, 0x554C14U, 0x3EB3F5U,
0xE4A26AU, 0xED799BU, 0xB6CA85U, 0xFFD25CU, 0xC421BFU, 0x8F3A22U, 0x96AB51U, 0xDC518CU, 0x895217U, 0x8289F2U,
0xF9B8A9U, 0xF0231CU, 0x2BF1C7U, 0x62C80AU, 0x781B39U, 0x1320E5U, 0x4AB156U, 0x41EB8FU, 0x1848E0U, 0x13D771U,
0x4886AEU, 0x203C5FU, 0x3B6F40U, 0x76F6A1U, 0xE5457EU, 0xAE1EE7U, 0xD7AC10U, 0xDCB549U, 0x8476EFU, 0x8FC536U,
0xD49DE9U, 0x9D0ED8U, 0xA63513U, 0xEFE4A6U, 0xB4DF7DU, 0x3E0D00U, 0x779693U, 0x4CA75EU, 0x0568ADU, 0x527BB0U,
0x59C34BU, 0x00109FU, 0x0A0B14U, 0x73FA61U, 0x38E0BAU, 0x23530FU, 0x6A88D4U, 0xB199DDU, 0x98322AU, 0xC260F3U,
0xCBF944U, 0x908A0DU, 0xDB11F2U, 0xC28163U, 0xADFABDU, 0xBC694CU, 0xF65243U, 0xAD83BAU, 0xA40D6DU, 0x5F7EF4U,
0x16E787U, 0x0DF44AU, 0x460EF1U, 0x5E1F24U, 0x15CC3FU, 0x6C77CAU, 0x676401U, 0x3C9CBDU, 0x359FEEU, 0x6A0413U,
0x02F590U, 0x91EE4DU, 0xDA3C3EU, 0xC305A3U, 0x889658U, 0xF14D99U, 0xFA7F86U, 0xA1E677U, 0xE981E8U, 0xF21A10U,
0xBB4BD7U, 0x80F1CEU, 0xCB6239U, 0x123BE0U, 0x1D885FU, 0x45921EU, 0x6641E1U, 0x3DE870U, 0x74BBAFU, 0x6F00C6U,
0x261055U, 0x7DCBA8U, 0x57787AU, 0x0E2167U, 0x05B28CU, 0xCC8819U, 0x975BE2U, 0xBC52B7U, 0xE5E52CU, 0xEB37C9U,
0xB20E12U, 0xF9DD2FU, 0xE8C6FCU, 0x837701U, 0xD8AD82U, 0xD1BE5AU, 0x0B0525U, 0x0244B4U, 0x79FE5BU, 0x322DCAU,
0x2B3495U, 0x60876CU, 0x79DCFBU, 0x334C12U, 0x4C7745U, 0x45A4DCU, 0x1E3F23U, 0x175FF2U, 0xC4C0D8U, 0xAFF30DU,
0xB72AF6U, 0xFCB96BU, 0xA5C338U, 0xAE5295U, 0xF54946U, 0xDCBABBU, 0x87A1A8U, 0xCF2165U, 0xD4DA9EU, 0x9FC90BU,
0x223070U, 0x6922A4U, 0x30B92FU, 0x3348D6U, 0x695B01U, 0x20C038U, 0x1BB2EFU, 0x523B06U, 0x49EC99U, 0x02D7C8U,
0x5B4777U, 0x713CA6U, 0xA8AF49U, 0xA3B650U, 0xF84586U, 0xB5DF7FU, 0xAE8CF8U, 0xC72581U, 0x9D3652U, 0x9EEDCFU,
0xC75D34U, 0xCC0671U, 0xB5B5CAU, 0xFEAC1FU, 0x677EA4U, 0x2DC5F9U, 0x26D63AU, 0x7F1F86U, 0x142855U, 0x0DF2A8U,
0x42E3B3U, 0x195872U, 0x108B8DU, 0x6AB31CU, 0x632063U, 0x307BAAU, 0xFBC83DU, 0xE201C4U, 0xA91393U, 0x90A82AU,
0xDAF9E4U, 0x816A55U, 0x88D00AU, 0xD383DBU, 0xFA3A64U, 0xA569A5U, 0xEEE2DEU, 0x76D243U, 0x3D0D90U, 0x649E6DU,
0x47E76EU, 0x1C7491U, 0x156E49U, 0x4E9DDEU, 0x0604B7U, 0x3D3720U, 0x76FDD9U, 0x6FEC06U, 0x2417B7U, 0xFD04F8U,
0xF29D29U, 0x886F92U, 0xC1744FU, 0xDAC73CU, 0x939EB1U, 0x880C63U, 0xEBE79EU, 0xB2F285U, 0xB86970U, 0xE11ABBU,
0xEA822EU, 0x311155U, 0x586AC0U, 0x43F92BU, 0x0A81F6U, 0x5412C5U, 0x5D111CU, 0x26E8CBU, 0x2D7B63U, 0x74213CU,
0x3F90CDU, 0x2E8B52U, 0x645883U, 0xDFE36CU, 0x96F375U, 0xDD0882U, 0xC40B1BU, 0x8FD6CCU, 0xB464A5U, 0xFC7F3EU,
0xA7AECBU, 0xAA9511U, 0xF10634U, 0xBA5CEFU, 0x83ED32U, 0x483681U, 0x5015DCU, 0x138D3FU, 0x48DEA2U, 0x616571U,
0x3AF40CU, 0x33AF97U, 0x681D72U, 0x2246E9U, 0x3BD7B9U, 0x506C46U, 0x0D2FDFU, 0x869338U, 0xDDC061U, 0xD45BD6U,
0xAF6A0FU, 0xE7B8C0U, 0xFC2371U, 0xBF102EU, 0xA6C9DFU, 0xEDDA40U, 0x943089U, 0x9FA1BFU, 0x459A66U, 0x0C4995U,
0x175108U, 0x7AE243U, 0x6139B6U, 0x2A2A2DU, 0x73D3D8U, 0x79C183U, 0x204A26U, 0x0B3FFDU, 0x5AA420U, 0x111613U,
0x8A4FDFU, 0xC3DC2CU, 0xF9A7B5U, 0xB034EAU, 0xEBAC5BU, 0xE0CF94U, 0xBD5465U, 0xF605FAU, 0xCFBEA3U, 0x85AC54U,
0x9E55DDU, 0xD7C62AU, 0x0CDD73U, 0x252FCDU, 0x76361CU, 0x7DF5D3U, 0x3546E2U, 0x6E5B39U, 0x67A98CU, 0x1CB247U,
0x57231AU, 0x4AD8A9U, 0x01CA74U, 0x191187U, 0xF2208AU, 0xA9AB50U, 0xA0F8A5U, 0xFB403EU, 0xF2D34BU, 0xA9A880U,
0xCB393DU, 0xD262EEU, 0x99D0B7U, 0xC04B00U, 0xCB1AC9U, 0xB0B176U, 0x39E3A7U, 0x677EF8U, 0x2ECD58U, 0x359687U,
0x7E277EU, 0x473D69U, 0x0CEEB0U, 0x55D557U, 0x5F04CEU, 0x0C8EBDU, 0x25BD60U, 0x7E64DBU, 0xB7771EU, 0xACCC05U,
0xE51CF0U, 0xBF2F2AU, 0x90F497U, 0xC9E7D4U, 0xC25F09U, 0x9B9CBAU, 0xD08767U, 0xEB320CU, 0xA36999U, 0x38FB42U,
0x7180B3U, 0x22112CU, 0x29AA45U, 0x50F9D2U, 0x1B610AU, 0x0202FDU, 0x4899E4U, 0x57080BU, 0x3E72DAU, 0x65E165U,
0x6CFA34U, 0xB70BEBU, 0xBC104AU, 0xE4E295U, 0x8F7BECU, 0x96787FU, 0xD583B2U, 0x9E9740U, 0x870C5DU, 0xECFFA6U,
0xF4E433U, 0xBF35F8U, 0xE00F8DU, 0x699C16U, 0x3265EBU, 0x1B6638U, 0x40F515U, 0x0A8DC6U, 0x131E1BU, 0x5845A0U,
0x21F670U, 0x2A6E1FU, 0x791D8EU, 0x708651U, 0x2AD7E8U, 0xE37CAFU, 0xD8EE56U, 0x97B3C1U, 0x8E0018U, 0xC51B6FU,
0x9CC9E6U, 0xB67019U, 0xEF23C8U, 0xE498F2U, 0xBF9927U, 0xF643ECU, 0xCD7051U, 0x04E902U, 0x563AFFU, 0x5D006CU,
0x04D3A1U, 0x0FCA9AU, 0x72794FU, 0x39A2B4U, 0x228231U, 0x6A19EAU, 0x714E96U, 0x18F705U, 0x4324FCU, 0xC83E3BU,
0x918D02U, 0xDADCD5U, 0xC2470CU, 0xA135B3U, 0xBABCF2U, 0xF30F4DU, 0xA8549EU, 0xA1C543U, 0xDEFF78U, 0xD42CBCU,
0x0DB747U, 0x46C6D2U, 0x5F5C89U, 0x144F60U, 0x6FA6F7U, 0x66350EU, 0x2C0A59U, 0x35DAE0U, 0x7EC12FU, 0x0D32FEU,
0x0429C1U, 0x5FB911U, 0xD642AEU, 0x895167U, 0xC3D8B0U, 0xFAAB89U, 0xB1315AU, 0xA8C0A7U, 0xE3DB24U, 0xB84879U,
0x913382U, 0xCBA317U, 0x82F8FCU, 0x994BA9U, 0x50C213U, 0x4390CEU, 0x282F5DU, 0x713E30U, 0x7FCDE3U, 0x26565EU,
0x2D0485U, 0x56BDD4U, 0x1FAE7BU, 0x0475AAU, 0x4DD555U, 0x17CE4CU, 0x9C1D9BU, 0xE52473U, 0xEEF7E4U, 0xB7CD1DU,
0xF45E42U, 0xEF87E3U, 0x87B43CU, 0x986FADU, 0xD16FD2U, 0x8AD403U, 0x8103A8U, 0xD83A75U, 0x33A826U, 0x2BF39BU,
0x604049U, 0x7B99A4U, 0x328ABFU, 0x49306AU, 0x407191U, 0x1BEA04U, 0x19D96FU, 0x4001F2U, 0x0FB201U, 0x36E9DCU,
0xFD7ADFU, 0xE64326U, 0xAF91F9U, 0xF51249U, 0xDC2B16U, 0x87F8D7U, 0xCCE668U, 0xC517B1U, 0x9E8C46U, 0x97BF5FU,
0xED6498U, 0xA67461U, 0x378FF6U, 0x788C8FU, 0x611514U, 0x0AE6F1U, 0x53FC2BU, 0x596F3EU, 0x0216C5U, 0x4B8508U,
0x507FBBU, 0x396EE6U, 0x22F535U, 0xE99688U, 0xB10F43U, 0xBA1D36U, 0xC3E2ADU, 0xC07178U, 0x9B28C3U, 0xD69A8BU,
0xCD817CU, 0x8570E5U, 0xFEEB12U, 0xF5E8CBU, 0xAC10C4U, 0x270335U, 0x7ED8EAU, 0x156B5BU, 0x0E7A14U, 0x46A0C5U,
0x5D937AU, 0x144AA3U, 0x4F79D5U, 0x6CF35CU, 0x31228FU, 0x7A1932U, 0x628E69U, 0xA9D59CU, 0x926517U, 0xDBBEE2U,
0x80ADB9U, 0x891424U, 0xD246D7U, 0xD8ED1AU, 0xA17C28U, 0xEA27F5U, 0xF3942EU, 0xB8CE8FU, 0xAB5FD0U, 0x466461U,
0x1CB7BEU, 0x152F6FU, 0x4E1CC0U, 0x05D799U, 0x1CE66EU, 0x773DF7U, 0x7EAB00U, 0x249048U, 0x6D41D7U, 0x765A26U,
0x1DA9F9U, 0x8431C8U, 0xCF0203U, 0x96C1DEU, 0x90D86DU, 0xCB6A30U, 0xA23193U, 0xB9A24EU, 0xF05B95U, 0xEB48A0U,
0xA0D27AU, 0xD8A39FU, 0xD33804U, 0x0A9B79U, 0x01C3AAU, 0x5A5437U, 0x132FD4U, 0x28BC0DU, 0x60253AU, 0x3F57E3U,
0x3CCC7CU, 0x65DD9DU, 0x4E26C2U, 0x172572U, 0xDCDDADU, 0xC64E64U, 0x8F5553U, 0x94A68AU, 0xFDBE7DU, 0xA66DE4U,
0xADD68BU, 0xF4C75AU, 0xFE0CC1U, 0x873E34U, 0xC8A72FU, 0xDBD0C2U, 0x124B10U, 0x49998DU, 0x40A8FEU, 0x3A3323U,
0x316088U, 0x68D95DU, 0x235B06U, 0x3A00B3U, 0x51B178U, 0x4AEA89U, 0x025816U, 0x59C36FU, 0xD092B8U, 0x8B2930U,
0xE43AC7U, 0xF5E2DEU, 0xBEC121U, 0xA71AF0U, 0xED8B7FU, 0x94B40EU, 0x9F66D1U, 0xD45D68U, 0xCD8CBFU, 0x8617F6U,
0x5F2545U, 0x75FC98U, 0x2EFF62U, 0x674467U, 0x7C959CU, 0x318F09U, 0x0A7CD2U, 0x4967AFU, 0x11D62CU, 0x1A8CD1U,
0x431F02U, 0x48A69DU, 0xB3E5ECU, 0xFA7623U, 0xE10E9AU, 0xA99948U, 0xB20215U, 0xD971A6U, 0x80E86BU, 0x8BDA90U,
0xD60185U, 0x9D907EU, 0x8FFBFBU, 0xE66920U, 0x7D705DU, 0x3483CEU, 0x6F9833U, 0x646BF1U, 0x1DF3E8U, 0x17E017U,
0x4E1BC6U, 0x050A79U, 0x1E8038U, 0x5773E7U, 0x2C685EU, 0xA1BD89U, 0xFB86B0U, 0xF01477U, 0xA16D8EU, 0xCAFE19U,
0xD365C1U, 0x9815AEU, 0x839E3FU, 0xCBCDC4U, 0x907611U, 0xB9E70AU, 0xE2BDE7U, 0x2B0E34U, 0x301789U, 0x7BE4DAU,
0x477707U, 0x0C2FACU, 0x558C79U, 0x5E9743U, 0x0D4496U, 0x04786DU, 0x7FABE0U, 0x3730B3U, 0x3C014AU, 0xE7DADDU,
0xEEE834U, 0x956163U, 0xDCB2FAU, 0xC78905U, 0x8D5BD4U, 0xD0427BU, 0xDBF12BU, 0xA22AB4U, 0xA93B4DU, 0xFA819AU,
0xB3D2B3U, 0x287B64U, 0x40289DU, 0x5BB206U, 0x100153U, 0x495CB8U, 0x42CF2DU, 0x3BF4D6U, 0x70248BU, 0x6ABF19U,
0x23CCF4U, 0x3C4527U, 0x75761AU, 0x8EACC1U, 0x853F44U, 0xD44EBFU, 0xDED5EEU, 0x87C751U, 0xEC3E80U, 0xF72D6FU,
0xBEB676U, 0xE557A1U, 0xEC4D59U, 0xB6BECEU, 0x9DA527U, 0x443078U, 0x0BCAE9U, 0x12D916U, 0x594087U, 0x6033E8U,
0x22A831U, 0x7948A2U, 0x70535FU, 0x2BC01CU, 0x62BBA1U, 0x592A7BU, 0x92308EU, 0x8AC395U, 0xC15A50U, 0x9809ABU,
0xB3B336U, 0xECB245U, 0xE54998U, 0xBEDA1BU, 0xF681E6U, 0xED35F5U, 0x8E2E0CU, 0x87FDD3U, 0x5CC453U, 0x1556ACU,
0x0E85FDU, 0x64AC42U, 0x3D7F8BU, 0x36447CU, 0x6FD665U, 0x640FB2U, 0x3B3C4BU, 0x52A7C4U, 0x48F7B5U, 0x014C2EU,
0x9A9FFBU, 0xD19601U, 0xA0250CU, 0xAB7FFFU, 0xF2C822U, 0xB8D1B1U, 0xA302CCU, 0xEAB907U, 0xD1E9B2U, 0x987269U,
0xC3411CU, 0xCC8897U, 0x141A42U, 0x3F61B8U, 0x66F2A1U, 0x2DCB56U, 0x3618DFU, 0x778208U, 0x2CB3F1U, 0x0468EEU,
0x5F7B1FU, 0x5693D0U, 0x0D8041U, 0x461B3EU, 0xFFECE7U, 0xB4FD50U, 0xA94798U, 0xE314CFU, 0xB88D76U, 0xB17EADU,
0xCA7508U, 0xC3E553U, 0x989EA6U, 0xDB0D3DU, 0xC396E8U, 0xA8E683U, 0x717D1EU, 0x7A0EEDU, 0x219730U, 0x288422U,
0x736ECFU, 0x1BFF14U, 0x04A4A1U, 0x4F177AU, 0x56092BU, 0x1DD884U, 0x64635DU, 0xEF70EAU, 0xA589B3U, 0xF49B54U,
0xFF50CDU, 0xA66312U, 0x8DFA62U, 0xD628FDU, 0x9F131CU, 0x8582C3U, 0xCCF9DAU, 0xF36A29U, 0xB8B2F4U, 0x618157U,
0x6A020AU, 0x335999U, 0x79E864U, 0x4272BFU, 0x03259AU, 0x189C40U, 0x51CFB5U, 0x0A752EU, 0x216463U, 0x79BF90U,
0x721C0DU, 0xAB47FEU, 0xE4D727U, 0xFDEC28U, 0x963FD9U, 0x8DA646U, 0xC594B7U, 0x9E4FE8U, 0x977E60U, 0xECA597U,
0xAF264EU, 0xB61C79U, 0xFDCDA0U, 0x65D64FU, 0x2E61DCU, 0x553881U, 0x5CAA72U, 0x0351FBU, 0x0A400CU, 0x51FB55U,
0x3BB9CAU, 0x22223AU, 0x6993B5U, 0x30C8C4U, 0x3B5B1BU, 0xE02B82U, 0xC1B075U, 0x9B23BCU, 0xD25A8BU, 0xC9C852U,
0x82A3A9U, 0xBB303CU, 0xF42977U, 0xADDA82U, 0xA64418U, 0xFC55E5U, 0xB5AEE6U, 0x0EBD3BU, 0x4765C8U, 0x4CD655U,
0x17DD2EU, 0x562EEBU, 0x6C3770U, 0x25A585U, 0x3E5EDEU, 0x754F6FU, 0x2C94A1U, 0x23A758U, 0x5A3F4FU, 0xD07C96U,
0x8BC761U, 0xC254E8U, 0xD92C97U, 0xB0BF06U, 0xEBE0D9U, 0xE25138U, 0xB8CAA7U, 0xBB98DEU, 0xE22109U, 0x896291U,
0x10F172U, 0x5BCB2FU, 0x401A94U, 0x0CA141U, 0x77B2BAU, 0x7E6BBFU, 0x255964U, 0x6E82D9U, 0x77130AU, 0x3C3877U,
0x04EAF4U, 0x4FD129U, 0x9C40DBU, 0x959BC6U, 0xCEAC2DU, 0xE774FCU, 0xBC6763U, 0xF6DC12U, 0xEB8DCDU, 0xA00664U,
0xF9F4B3U, 0xD2EF4AU, 0x895E5DU, 0x800584U, 0x5A972BU, 0x132EFBU, 0x287D84U, 0x63E615U, 0x7297CEU, 0x391D23U,
0x608E30U, 0x6AF5CDU, 0x11641EU, 0x5C5E93U, 0x4789E0U, 0x0E903DU, 0x956386U, 0xFEF053U, 0xB6E879U, 0xAD0BACU,
0xE41077U, 0xFF83CAU, 0xB47A99U, 0xCD6870U, 0xCE93E7U, 0x96823EU, 0x9D1941U, 0xC4EBD0U, 0x2BF23FU, 0x3031EEU,
0x790A71U, 0x229909U, 0x2AC1CEU, 0x717677U, 0x5AEDA0U, 0x039C99U, 0x480646U, 0x515587U, 0x1AEC3CU, 0x296F69U,
0xE13492U, 0xBA8607U, 0xB39FCCU, 0xEC4CB1U, 0xA77723U, 0x9EA7DEU, 0xD51C0DU, 0xCD0F00U, 0x86D4FBU, 0xDDF56EU,
0xF46F95U, 0x2FBCD4U, 0x268D6BU, 0x7D52B2U, 0x374165U, 0x26F9DCU, 0x4D2A9BU, 0x141163U, 0x1FD2FCU, 0x40CA2DU,
0x497952U, 0x3322D3U, 0x7AB32CU, 0xE108F5U, 0xAA5AE2U, 0xB3E31BU, 0xF8B098U, 0x812B65U, 0x8B8936U, 0xD0D08AU,
0xD94341U, 0x8A7894U, 0xE3A9AFU, 0xF8377AU, 0xB74481U, 0x6FDD0CU, 0x64EE5FU, 0x3D35A2U, 0x163731U, 0x5F8ECCU,
0x045DC7U, 0x0F4616U, 0x57B6E8U, 0x7CAD79U, 0x253E86U, 0x6EC7CFU, 0x7DD478U, 0xB426A1U, 0xCF2D76U, 0xC3BC5FU,
0x984780U, 0x935571U, 0xCACCEEU, 0x81BBBFU, 0xB82054U, 0xF371C0U, 0xE9CB3BU, 0xA05826U, 0xFB33F5U, 0x52A218U,
0x09B88BU, 0x424BF6U, 0x53D22DU, 0x198198U, 0x043A53U, 0x6F2A06U, 0x34F1BDU, 0x3DC260U, 0x664982U, 0x6FB81BU,
0x15A24CU, 0xDE71F5U, 0xC7482AU, 0x8CDFCBU, 0x9505D4U, 0xDE3405U, 0xA5EFFAU, 0xA4FC63U, 0xFE5704U, 0xB387DDU,
0xA8BC6AU, 0xC32FB2U, 0x5A7EE5U, 0x11C44CU, 0x489797U, 0x420E62U, 0x19BD79U, 0x30E6BCU, 0x6B6407U, 0x225DDAU,
0x398EA9U, 0x703534U, 0x0A64F7U, 0x09FA0AU, 0xD4C910U, 0xDF10E5U, 0x86833EU, 0xCDB99BU, 0xE67A40U, 0xBE631BU,
0xB590AEU, 0xEC8B75U, 0xA73BD0U, 0x9CE08BU, 0xD5F35EU, 0x8E0AE5U, 0x061828U, 0x5D835AU, 0x5660C7U, 0x277914U,
0x68CAE9U, 0x7190E2U, 0x3A0113U, 0x20FECCU, 0x49ED7DU, 0x127522U, 0x1B06ABU, 0x40855CU, 0x8B9E85U, 0x926FB2U,
0xF8F56AU, 0xE186A5U, 0xAA1F14U, 0xF10CCBU, 0xF0F7BAU, 0x8F6735U, 0x867CECU, 0xDC9F1FU, 0x978402U, 0x8E54F1U,
0x45EF3CU, 0x7CFC8FU, 0x3705D2U, 0x6C1248U, 0x64C8BDU, 0x3FF976U, 0x566243U, 0x4DA198U, 0x069B45U, 0x1F0AF6U,
0x5851BBU, 0x00E248U, 0xAB3BD1U, 0xF2090EU, 0xF9926FU, 0xA2C3F1U, 0xEB7800U, 0xD07B9FU, 0x98A1E6U, 0xC31021U,
0xC84BB8U, 0x91D84FU, 0x9AEC96U, 0x6337A9U, 0x288468U, 0x369FB3U, 0x774E06U, 0x6C645DU, 0x05B7A9U, 0x4E2E22U,
0x551DFFU, 0x1CC78CU, 0x47D611U, 0x4F2DF2U, 0x343E6FU, 0xBF8514U, 0xE655C1U, 0xAD5E5AU, 0xB4EDBFU, 0xDFB4E4U,
0xC1265DU, 0x80DD8BU, 0xDBC852U, 0xD25375U, 0x8920ACU, 0xA2BA53U, 0xFB0BC2U, 0x31401DU, 0x28D33CU, 0x63AAE3U,
0x18381AU, 0x11238DU, 0x4AD2E4U, 0x434933U, 0x195BABU, 0x56A058U, 0x6FB105U, 0x2C5AAEU, 0x35C97BU, 0xFED9A0U,
0xA52295U, 0x8D314EU, 0xD6ECA3U, 0x9F5E30U, 0x84456DU, 0xCFB6DEU, 0xD6AF03U, 0xBD2CE9U, 0xE556FCU, 0xEEC707U,
0xB71CD6U, 0x382F59U, 0x43B720U, 0x02E4F7U, 0x195F4EU, 0x51CC99U, 0x0AA550U, 0x013767U, 0x786CBEU, 0x73DD01U,
0x2AC6D1U, 0x61159EU, 0x7BA92FU, 0x92BAF4U, 0x896109U, 0xC0521AU, 0x9F9AF7U, 0x942924U, 0xC532B9U, 0xEFE3C2U,
0xA6D807U, 0xFD0ABCU, 0xF69369U, 0xAFA033U, 0x44738EU, 0x5D694DU, 0x17C8F0U, 0x0C93A3U, 0x45207AU, 0x1EF9C5U,
0x37EB04U, 0x6850FBU, 0x6305EAU, 0x3B9E15U, 0x782DC4U, 0x41774BU, 0x8AF633U, 0xD18DE4U, 0xD81E5DU, 0x83A69AU,
0x8AF583U, 0xF06E7CU, 0xBB5FADU, 0xA28416U, 0xE99653U, 0xF06D88U, 0x9FEC35U, 0xC4F7E6U, 0x4C059AU, 0x1F1C19U,
0x56EFC4U, 0x4D743FU, 0x24612AU, 0x3F9BD1U, 0x748814U, 0x2C13AFU, 0x27F276U, 0x5EE861U, 0x553B88U, 0x0E0A5FU,
0xC791E6U, 0xD8E2B0U, 0x907A69U, 0xABE9C6U, 0xE09217U, 0xB10168U, 0xBA48F9U, 0xE3FA26U, 0x8861CFU, 0x9230D8U,
0xDB8B21U, 0xC099B2U, 0x09644FU, 0x52F704U, 0x79AC90U, 0x201F6BU, 0x2E17BEU, 0x77C495U, 0x3CFF48U, 0x172E9BU,
0x4E9426U, 0x0D8775U, 0x145E98U, 0x5E6D03U, 0xC5F6D6U, 0xAC242DU, 0xF70D3CU, 0xFEDED2U, 0xA5C543U, 0xAE74BCU,
0xD62EE5U, 0x9D9D72U, 0x80029BU, 0xCB534CU, 0x90E175U, 0x19BAAAU, 0x6A3B6BU, 0x6280D4U, 0x39D385U, 0x724B7AU,
0x6B78E2U, 0x00A321U, 0x19101CU, 0x5248CFU, 0x0ADB30U, 0x01F0A9U, 0x5A21CEU, 0xB73A17U, 0xACC880U, 0xE55179U,
0xFE42A6U, 0xB4B987U, 0xC5AF58U, 0xCE1688U, 0x97C533U, 0x9CCE76U, 0xC73F8DU, 0x8E2510U, 0xB4B6C3U, 0x7D4FFEU,
0x665C3DU, 0x2DC7C0U, 0x70B55BU, 0x5B2C2EU, 0x025FF5U, 0x49D470U, 0x53448AU, 0x1A3FD7U, 0x09AC64U, 0x60BDBDU,
0x3B467AU, 0xB0D043U, 0xE98B9CU, 0xE33A2DU, 0x9A21E2U, 0xD1C3B3U, 0xCA5A0CU, 0x8709DDU, 0xDCB222U, 0xF5A3AAU,
0xBF79DDU, 0xA44A04U, 0xEDD193U, 0x3E006AU, 0x373B21U, 0x4CF994U, 0x47C04FU, 0x1F53DAU, 0x5488A1U, 0x4DB86CU,
0x2623DFU, 0x7D7402U, 0x70CF50U, 0x2B9EFDU, 0x232426U, 0xF8A7D3U, 0x91FEC8U, 0x8A4D39U, 0xC117F6U, 0xD0866FU,
0x9B3D18U, 0xE36EC1U, 0xE8F576U, 0xB3C5BFU, 0xBA1629U, 0xE1BD50U, 0xA8EC8FU, 0x17763EU, 0x5D45F1U, 0x049CA0U,
0x0F8F1FU, 0x5630C6U, 0x7DE225U, 0x26FB38U, 0x6F08CBU, 0x7D0316U, 0x34B28DU, 0x2F68E9U, 0xC47B72U, 0x9DC287U,
0x96915CU, 0xCF0B41U, 0x85F8A2U, 0xBAE17FU, 0xF372CCU, 0xE81991U, 0xA1894AU, 0xFAF2EBU, 0xF16134U, 0x89F845U,
0x0A8ADBU, 0x53153AU, 0x1806E5U, 0x03FF7CU, 0x6A7C0BU, 0x312692U, 0x399775U, 0x628CACU, 0x6D7FB3U, 0x34EE42U,
0x5FF49DU, 0x56073CU, 0x8D1C67U, 0x87CDBBU, 0xDEE708U, 0xB574D5U, 0xA4ADB6U, 0xEF9E2BU, 0xF605D0U, 0xBD7545U,
0xE6EE0EU, 0xCE39FBU, 0x950260U, 0xD8929DU, 0x43D9CEU, 0x086A47U, 0x31B3B1U, 0x7AA068U, 0x221ADFU, 0x294B86U,
0x72F049U, 0x73E3F8U, 0x083927U, 0x418856U, 0x5AC3C9U, 0x105020U, 0xC969B7U, 0xE2BBEEU, 0xBF2019U, 0xB41181U,
0xEFCA6AU, 0xA6FD3FU, 0xBC27A4U, 0xD53651U, 0xCE9D9AU, 0x854EA7U, 0xDC5E74U, 0xDFE5A9U, 0x26B61AU, 0x6C0D57U,
0x77DCECU, 0x3EC639U, 0x2575C3U, 0x682CD6U, 0x13AF1DU, 0x1855ECU, 0x404473U, 0x4BDF8AU, 0x12ACDDU, 0xF93754U,
0xE207A3U, 0xABD87AU, 0xF04B45U, 0xF03284U, 0xABB05BU, 0x80ABEBU, 0xD95AB4U, 0x92C10DU, 0x8FD2CEU, 0xC42833U,
0xEC3920U, 0x37C2FDU, 0x7C5106U, 0x654883U, 0x2EAAF8U, 0x37B12DU, 0x5C20B6U, 0x065B42U, 0x07C909U, 0x5C12B4U,
0x152367U, 0x2EB4FAU, 0x65CF19U, 0xFC5F40U, 0xB294FFU, 0xEBA72EU, 0xE03ED1U, 0x9B6CD0U, 0x92D70FU, 0xC944F6U,
0x801D60U, 0x9AAE19U, 0xF1F4DEU, 0xA85547U, 0xAB4EB8U, 0x729DE9U, 0x792456U, 0x223697U, 0x4BED0CU, 0x55DE71U,
0x1C03A2U, 0x07910FU, 0x4CAADCU, 0x356BA0U, 0x3E5033U, 0x67C3EEU, 0x2D9B05U, 0xB62810U, 0xFFF3EBU, 0xC4E03EU,
0x8558A5U, 0xDE0B48U, 0xD5905BU, 0x8D71A2U, 0xA26A75U, 0xFBD8ECU, 0xB08982U, 0xAB1253U, 0xE2A1ECU, 0x79FB3FU,
0x116E52U, 0x4A15C9U, 0x43861CU, 0x188FE7U, 0x537DF2U, 0x62E619U, 0x29D7C0U, 0x310C57U, 0x7A1F2EU, 0x25E5B8U,
0xAC7451U, 0xC76F86U, 0xDE9C9FU, 0x959460U, 0xCF27B1U, 0xC6FC1EU, 0xBDEDCFU, 0xF416B0U, 0xEF0429U, 0xA49FEEU,
0xBDEA17U, 0xFF7104U, 0x06A3F8U, 0x0D8A63U, 0x5219A6U, 0x5B62DDU, 0x00F348U, 0x6969B3U, 0x731A6EU, 0x38816DU,
0x61D090U, 0x6A6343U, 0x33F9FEU, 0x18B8A5U, 0xC30340U, 0x8B10DAU, 0x98E80BU, 0xD1FB74U, 0xEA20F5U, 0xA5930AU,
0xFC8E93U, 0xF75CC4U, 0xAF673DU, 0xA4E6BAU, 0xDF3D43U, 0x960F9CU, 0x0DD68DU, 0x44E572U, 0x1F7EB2U, 0x35AD09U,
0x6C9554U, 0x6746A7U, 0x365D3AU, 0x7DFCF9U, 0x64A6C4U, 0x0B351FU, 0x118CEAU, 0x58DF61U, 0x836434U, 0x8A36CFU,
0xF1AB5BU, 0xBA18A0U, 0xA343EDU, 0xE8C27EU, 0xF0F887U, 0xBB2B50U, 0xC03A69U, 0xC9C1A6U, 0x9A5317U, 0x9368C8U,
0x5CB919U, 0x26A226U, 0x2F01EFU, 0x74D919U, 0x3DCA80U, 0x2631D7U, 0x6D223EU, 0x54BAA1U, 0x1E4950U, 0x47520BU,
0x4CA79EU, 0x97BC75U, 0xBE3EA8U, 0xED479BU, 0xA4D446U, 0xBA4FF5U, 0xF13C39U, 0xE8A46AU, 0x83D7D7U, 0xDA4C0CU,
0xD1DDF9U, 0x8AA7F2U, 0xC22427U, 0x793DDCU, 0x30CE45U, 0x2B5522U, 0x6007FBU, 0x39BE6CU, 0x32AD95U, 0x42560BU,
0x4D426AU, 0x16D1B5U, 0x5F3A04U, 0x442BDBU, 0x2DF082U, 0xF6C225U, 0xFE59FCU, 0xA5880FU, 0xAEB312U, 0xF761C9U,
0x9C582CU, 0x85CBB7U, 0xCE00C3U, 0xD43118U, 0x9DAB9DU, 0xEAF866U, 0xE3437BU, 0x381288U, 0x738955U, 0x6A3BF6U,
0x2066ABU, 0x19D570U, 0x52DEC1U, 0x090E1EU, 0x00B5FFU, 0x5BE6E1U, 0x727D38U, 0x284CCFU, 0x639656U, 0xFA8531U,
0xBD3CA8U, 0xD4EF77U, 0xCFC586U, 0x841489U, 0x9C0F78U, 0xD7BCA7U, 0x8E671EU, 0xA5774DU, 0xFE8481U, 0xF79F32U,
0xAC0AEFU, 0x65F09CU, 0x5FF301U, 0x144ACAU, 0x0D193FU, 0x468224U, 0x13F0D1U, 0x18694AU, 0x63FA87U, 0x2B81F4U,
0x30106DU, 0x790A9BU, 0xE2E952U, 0x8970CDU, 0xD003BCU, 0xDB9963U, 0x838AD2U, 0x88731DU, 0xD1E064U, 0xBAFFF3U,
0xA10F2AU, 0xEC049DU, 0xBFD7D4U, 0xB7EE2BU, 0x4C7CBBU, 0x478760U, 0x1E9415U, 0x554D9EU, 0x4C7E6BU, 0x07E4B0U,
0x3D35ADU, 0x741E4EU, 0x2F8D93U, 0x26FC20U, 0x7D667DU, 0x16B586U, 0x8B8E02U, 0xC91FD9U, 0xD0456CU, 0x9BF237U,
0xC0EBCEU, 0xE92849U, 0xB29390U, 0xBBC3E7U, 0xE1787EU, 0xAA6B81U, 0x93B040U, 0xD8005FU, 0x411BAEU, 0x0AC870U,
0x51F1D1U, 0x5D328EU, 0x362837U, 0x6799E0U, 0x6C4239U, 0x37711AU, 0x3EABC7U, 0x45BA3CU, 0x0D01A9U, 0x16D6F2U,
0xDDCF17U, 0xC46D8CU, 0x8F3670U, 0xF6A723U, 0xFD5CBCU, 0xA74F5DU, 0xEAF582U, 0xF1A43BU, 0x903768U, 0x8B0CC5U,
0xC0DC16U, 0x9957CBU, 0x1324F0U, 0x4ABD25U, 0x61AECEU, 0x38545AU, 0x73C701U, 0x68FEF4U, 0x212D6FU, 0x5B3382U,
0x52C2D1U, 0x09494CU, 0x065ABFU, 0xDFA126U, 0x9CB149U, 0xA56A98U, 0xEE5927U, 0xF4C0F6U, 0xBD33B8U, 0xE62901U,
0xCFB8D6U, 0x94D32FU, 0x9F40B8U, 0xC69AF1U, 0x8CAB0EU, 0x15309FU, 0x7E6360U, 0x21DA31U, 0x2848BAU, 0x733747U,
0x72A6D4U, 0x08EDA8U, 0x435F7BU, 0x5A4CD6U, 0x119505U, 0x082658U, 0x433DE3U, 0xB8ED26U, 0xB0D6DDU, 0xEB05C8U,
0xA2BC13U, 0xA9BEEAU, 0xD6656DU, 0xDF5614U, 0x848F82U, 0xC41C5BU, 0xDF26A4U, 0x94F7A5U, 0xADCC5AU, 0x665B8BU,
0x3F1234U, 0x34A0EDU, 0x6E7BAAU, 0x076813U, 0x1CD1C4U, 0x55833DU, 0x4E1836U, 0x03A9E2U, 0x58F219U, 0x72418CU,
0x2B09F7U, 0xA89A72U, 0xF1A1A9U, 0xBA7254U, 0x81EA47U, 0xC899BAU, 0xD20279U, 0x9B13C4U, 0xC0E09FU, 0xCB7E4BU,
0xB25FF0U, 0xF98431U, 0xE4974EU, 0x2E6CD7U, 0x35FC00U, 0x5CE7A9U, 0x07147EU, 0x060D07U, 0x5D9F98U, 0x56E449U,
0x0E65A6U, 0x659EB7U, 0x7C8D49U, 0x371790U, 0x6C6623U, 0xE5FD6EU, 0x9E6EBDU, 0x921600U, 0xC985D3U, 0x82DAEEU,
0x9B7B25U, 0xD0E0F0U, 0xE1924BU, 0xAA091EU, 0xF158F5U, 0xF9E369U, 0x22F1BAU, 0x4B28C7U, 0x509B54U, 0x1B80BDU,
0x024162U, 0x497B53U, 0x01A88CU, 0x3E1B5DU, 0x7502F2U, 0x6CD12BU, 0x27EB1CU, 0x7E7AC5U, 0xDDA113U, 0x8596BAU,
0xCE5EEDU, 0xD54D14U, 0x9CF68BU, 0x87A54AU, 0xEE1C31U, 0xB58EA4U, 0xBFD55FU, 0xE66482U, 0xE93FA1U, 0x90AD7CU,
0x5B04EFU, 0x405713U, 0x09CC48U, 0x13BFEDU, 0x522736U, 0x2914E3U, 0x22CFD8U, 0x7B5E05U, 0x3061E6U, 0x29B37FU,
0x43BAA8U, 0x5849D1U, 0x91D25EU, 0xCEE0AFU, 0xC73971U, 0x9C2A40U, 0xB7919FU, 0xEF401EU, 0xA452E1U, 0xB5B9B8U,
0xFEA80FU, 0x8533D6U, 0x8C4115U, 0xD7DA28U, 0x5F6BF3U, 0x043006U, 0x4FA39DU, 0x76DBD9U, 0x394C22U, 0x20C7BFU,
0x6BB64CU, 0x312C41U, 0x187FB2U, 0x43C46FU, 0x0A55F4U, 0x192E81U, 0xD2BC4AU, 0xCBA5FBU, 0xA15624U, 0xF85DFDU,
0xF38ECBU, 0xBA3602U, 0xA125F5U, 0xCEFE6CU, 0x97CF3BU, 0x9D55C2U, 0xC4A64DU, 0x4FBFBCU, 0x1468A3U, 0x7D4352U,
0x6ED19DU, 0x270804U, 0x7D3B76U, 0x76A0ABU, 0x0FF018U, 0x0443D5U, 0x5D188EU, 0x16A93BU, 0x0932E0U, 0xC07015U,
0xFACB1EU, 0xB39AC3U, 0xE80170U, 0xE3B3ADU, 0xBAEA5EU, 0xD17956U, 0xC042A9U, 0x8A9378U, 0x912DE7U, 0xD86E86U,
0x83F559U, 0x2AC4E8U, 0x711F37U, 0x7A0D6EU, 0x26B4C9U, 0x6D6710U, 0x547CE7U, 0x1F8CFEU, 0x449720U, 0x4D3483U,
0x16EF5AU, 0x1EFE2DU, 0x6D44B4U, 0xA6174BU, 0xBF8E8AU, 0xF4FD95U, 0xED6764U, 0x86D6BBU, 0xDC8912U, 0xD10A45U,
0x8A799CU, 0x83E12AU, 0xF872F3U, 0xB10954U, 0xAA980DU, 0x6083D6U, 0x397163U, 0x3AE8B8U, 0x439BDDU, 0x481046U,
0x1302BBU, 0x5AFB68U, 0x50E875U, 0x297396U, 0x26824AU, 0x7D98F1U, 0x344BA4U, 0xAF726FU, 0xE6F5DAU, 0x9C0F01U,
0x971C38U, 0xCE85EFU, 0xC5F626U, 0x946D91U, 0xFFBDC8U, 0xE48637U, 0xAC15A6U, 0xB74C48U, 0x7EEE99U, 0x21B586U,
0x0A0677U, 0x539FA8U, 0x18CC01U, 0x007652U, 0x4B67CFU, 0x70B43CU, 0x390FF1U, 0x625ECAU, 0x6BD01FU, 0x38E3C4U,
0xB23870U, 0xCB893BU, 0x8093C6U, 0x994055U, 0xD679A8U, 0x8DAAFBU, 0xA4B176U, 0xFE018DU, 0xF7CA5CU, 0xACD963U,
0xE762B2U, 0xFE323DU, 0x1589C4U, 0x0C5A92U, 0x4F432BU, 0x17F0ECU, 0x1CAA35U, 0x673B82U, 0x6E54DBU, 0x31C724U,
0x785CA5U, 0x632C5AU, 0x29B70BU, 0x508490U, 0xDB5D6DU, 0x82CFEEU, 0x89B492U, 0xD22541U, 0xBB2EDCU, 0xA1DD27U,
0xE04F62U, 0xFB56D9U, 0xB0A50CU, 0xF9BED7U, 0xC24EFAU, 0x8F5529U, 0x55C6D0U, 0x5E3B47U, 0x07383FU, 0x2CA2F0U,
0x75D161U, 0x3E489EU, 0x25BB0FU, 0x6DA170U, 0x7630B1U, 0x174B2EU, 0x4CD8D7U, 0x470180U, 0x9E2339U, 0xD5B8FEU,
0xE9EB27U, 0xA2521DU, 0xB941C8U, 0xF0BB23U, 0xAB2AB6U, 0xA271CDU, 0xD9C250U, 0xD3DC83U, 0x8A1D6EU, 0x41A67DU,
0x58B580U, 0x3B6C5BU, 0x205ECEU, 0x6985A5U, 0x333471U, 0x3E27CAU, 0x65FD13U, 0x0CCE44U, 0x1747EDU, 0x5C143AU,
0x45AF83U, 0x8F7F54U, 0xF6643DU, 0xFDD7A2U, 0xA68E73U, 0xAF3D8CU, 0xF4E79DU, 0xB5E073U, 0x8F59AAU, 0xC40A3DU,
0x999044U, 0x922197U, 0xCB7A3AU, 0x60E9E1U, 0x3B90B4U, 0x73020FU, 0x6839DAU, 0x21FA71U, 0x3A632CU, 0x5151DFU,
0x088A43U, 0x039B80U, 0x4260FDU, 0x18F36EU, 0x33EB97U, 0xEE1848U, 0xE503C9U, 0xBCA4B6U, 0xF7FC67U, 0xEC6FD8U,
0x849C01U, 0x9F8506U, 0xD616FFU, 0x8D6C29U, 0x86FD90U, 0xFF26CFU, 0xF4150EU, 0x2C9EB1U, 0x6FEE60U, 0x74751BU,
0x39E696U, 0x429F65U, 0x4B0DB8U, 0x1056ABU, 0x1AE756U, 0x43FC9DU, 0x282F29U, 0x318172U, 0x7A90E7U, 0xE36B1CU,
0xA878D9U, 0xF2A0E2U, 0xDB133FU, 0x8008ECU, 0xC1D955U, 0xDAE292U, 0x9570EBU, 0xAC9B74U, 0xE68A85U, 0xBF514BU,
0x34635AU, 0x6FFAA5U, 0x66A93CU, 0x1D12CBU, 0x54C382U, 0x4ED915U, 0x056AECU, 0x5C2D37U, 0x779402U, 0x2607C9U,
0x2D5D1CU, 0x72ECA6U, 0xBAB7FBU, 0xA12408U, 0xC89C85U, 0xD3CF76U, 0x98542BU, 0xC177B8U, 0xCAAE45U, 0xB29CCEU,
0xB9473BU, 0xE2D660U, 0xABEDF1U, 0xA03F1EU, 0x7926C4U, 0x1A95F1U, 0x044E2AU, 0x4D49FFU, 0x56B154U, 0x1FA209U,
0x6419FAU, 0x6F4867U, 0x36D394U, 0x3C2199U, 0x653842U, 0x2EABB7U, 0x95C02CU, 0xDC525CU, 0x87CB93U, 0x8EB80AU,
0xD423FDU, 0xF152A4U, 0xAAC003U, 0xE15BDAU, 0xF82A0DU, 0xB3B134U, 0xAAB3EBU, 0xC14C0AU, 0x1B5D95U, 0x128664U,
0x49357AU, 0x002DA3U, 0x3BDE40U, 0x70C5DDU, 0x6954AEU, 0x23AE73U, 0x76ADE8U, 0x7D760DU, 0x064756U, 0x0FDCE3U,
0xD40E38U, 0x9D37F5U, 0x87E4C6U, 0xECDF1AU, 0xB54EA9U, 0xBE1470U, 0xE7B71FU, 0xEC288EU, 0xB77951U, 0xDFC3A0U,
0xC490BFU, 0x89095EU, 0x1ABA81U, 0x51E118U, 0x2853EFU, 0x234AB6U, 0x7B8910U, 0x703AC9U, 0x2B6216U, 0x62F127U,
0x59CAECU, 0x101B59U, 0x4B2082U, 0xC1F2FFU, 0x88696CU, 0xB358A1U, 0xFA9752U, 0xAD844FU, 0xA63CB4U, 0xFFEF60U,
0xF5F4EBU, 0x8C059EU, 0xC71F45U, 0xDCACF0U, 0x95772BU, 0x4E6622U, 0x67CDD5U, 0x3D9F0CU, 0x3406BBU, 0x6F75F2U,
0x24EE0DU, 0x3D7E9CU, 0x520542U, 0x4396B3U, 0x09ADBCU, 0x527C45U, 0x5BF292U, 0xA0810BU, 0xE91878U, 0xF20BB5U,
0xB9F10EU, 0xA1E0DBU, 0xEA33C0U, 0x938835U, 0x989BFEU, 0xC36342U, 0xCA6011U, 0x95FBECU, 0xFD0A6FU, 0x6E11B2U,
0x25C3C1U, 0x3CFA5CU, 0x7769A7U, 0x0EB266U, 0x058079U, 0x5E1988U, 0x167E17U, 0x0DE5EFU, 0x44B428U, 0x7F0E31U,
0x349DC6U, 0xEDC41FU, 0xE277A0U, 0xBA6DE1U, 0x99BE1EU, 0xC2178FU, 0x8B4450U, 0x90FF39U, 0xD9EFAAU, 0x823457U,
0xA88785U, 0xF1DE98U, 0xFA4D73U, 0x3377E6U, 0x68A41DU, 0x43AD48U, 0x1A1AD3U, 0x14C836U, 0x4DF1EDU, 0x0622D0U,
0x173903U, 0x7C88FEU, 0x27527DU, 0x2E41A5U, 0xF4FADAU, 0xFDBB4BU, 0x8601A4U, 0xCDD235U, 0xD4CB6AU, 0x9F7893U,
0x862304U, 0xCCB3EDU, 0xB388BAU, 0xBA5B23U, 0xE1C0DCU, 0xE8A00DU, 0x3B3F27U, 0x500CF2U, 0x48D509U, 0x034694U,
0x5A3CC7U, 0x51AD6AU, 0x0AB6B9U, 0x234544U, 0x785E57U, 0x30DE9AU, 0x2B2561U, 0x6036F4U, 0xDDCF8FU, 0x96DD5BU,
0xCF46D0U, 0xCCB729U, 0x96A4FEU, 0xDF3FC7U, 0xE44D10U, 0xADC4F9U, 0xB61366U, 0xFD2837U, 0xA4B888U, 0x8EC359U,
0x5750B6U, 0x5C49AFU, 0x07BA79U, 0x4A2080U, 0x517307U, 0x38DA7EU, 0x62C9ADU, 0x611230U, 0x38A2CBU, 0x33F98EU,
0x4A4A35U, 0x0153E0U, 0x98815BU, 0xD23A06U, 0xD929C5U, 0x80E079U, 0xEBD7AAU, 0xF20D57U, 0xBD1C4CU, 0xE6A78DU,
0xEF7472U, 0x954CE3U, 0x9CDF9CU, 0xCF8455U, 0x0437C2U, 0x1DFE3BU, 0x56EC6CU, 0x6F57D5U, 0x25061BU, 0x7E95AAU,
0x772FF5U, 0x2C7C24U, 0x05C59BU, 0x5A965AU, 0x111D21U, 0x892DBCU, 0xC2F26FU, 0x9B6192U, 0xB81891U, 0xE38B6EU,
0xEA91B6U, 0xB16221U, 0xF9FB48U, 0xC2C8DFU, 0x890226U, 0x9013F9U, 0xDBE848U, 0x02FB07U, 0x0D62D6U, 0x77906DU,
0x3E8BB0U, 0x2538C3U, 0x6C614EU, 0x77F39CU, 0x141861U, 0x4D0D7AU, 0x47968FU, 0x1EE544U, 0x157DD1U, 0xCEEEAAU,
0xA7953FU, 0xBC06D4U, 0xF57E09U, 0xABED3AU, 0xA2EEE3U, 0xD91734U, 0xD2849CU, 0x8BDEC3U, 0xC06F32U, 0xD174ADU,
0x9BA77CU, 0x201C93U, 0x690C8AU, 0x22F77DU, 0x3BF4E4U, 0x702933U, 0x4B9B5AU, 0x0380C1U, 0x585134U, 0x556AEEU,
0x0EF9CBU, 0x45A310U, 0x7C12CDU, 0xB7C97EU, 0xAFEA23U, 0xEC72C0U, 0xB7215DU, 0x9E9A8EU, 0xC50BF3U, 0xCC5068U,
0x97E28DU, 0xDDB916U, 0xC42846U, 0xAF93B9U, 0xF2D020U, 0x796CC7U, 0x223F9EU, 0x2BA429U, 0x5095F0U, 0x18473FU,
0x03DC8EU, 0x40EFD1U, 0x593620U, 0x1225BFU, 0x6BCF76U, 0x605E40U, 0xBA6599U, 0xF3B66AU, 0xE8AEF7U, 0x851DBCU,
0x9EC649U, 0xD5D5D2U, 0x8C2C27U, 0x863E7CU, 0xDFB5D9U, 0xF4C002U, 0xA55BDFU, 0xEEE9ECU, 0x75B020U, 0x3C23D3U,
0x06584AU, 0x4FCB15U, 0x1453A4U, 0x1F306BU, 0x42AB9AU, 0x09FA05U, 0x30415CU, 0x7A53ABU, 0x61AA22U, 0x2839D5U,
0xF3228CU, 0xDAD032U, 0x89C9E3U, 0x820A2CU, 0xCAB91DU, 0x91A4C6U, 0x985673U, 0xE34DB8U, 0xA8DCE5U, 0xB52756U,
0xFE358BU, 0xE6EE78U, 0x0DDF75U, 0x5654AFU, 0x5F075AU, 0x04BFC1U, 0x0D2CB4U, 0x56577FU, 0x34C6C2U, 0x2D9D11U,
0x662F48U, 0x3FB4FFU, 0x34E536U, 0x4F4E89U, 0xC61C58U, 0x988107U, 0xD132A7U, 0xCA6978U, 0x81D881U, 0xB8C296U,
0xF3114FU, 0xAA2AA8U, 0xA0FB31U, 0xF37142U, 0xDA429FU, 0x819B24U, 0x4888E1U, 0x5333FAU, 0x1AE30FU, 0x40D0D5U,
0x6F0B68U, 0x36182BU, 0x3DA0F6U, 0x646345U, 0x2F7898U, 0x14CDF3U, 0x5C9666U, 0xC704BDU, 0x8E7F4CU, 0xDDEED3U,
0xD655BAU, 0xAF062DU, 0xE49EF5U, 0xFDFD02U, 0xB7661BU, 0xA8F7F4U, 0xC18D25U, 0x9A1E9AU, 0x9305CBU, 0x48F414U,
0x43EFB5U, 0x1B1D6AU, 0x708413U, 0x698780U, 0x2A7C4DU, 0x6168BFU, 0x78F3A2U, 0x130059U, 0x0B1BCCU, 0x40CA07U,
0x1FF072U, 0x9663E9U, 0xCD9A14U, 0xE499C7U, 0xBF0AEAU, 0xF57239U, 0xECE1E4U, 0xA7BA5FU, 0xDE098FU, 0xD591E0U,
0x86E271U, 0x8F79AEU, 0xD52817U, 0x1C8350U, 0x2711A9U, 0x684C3EU, 0x71FFE7U, 0x3AE490U, 0x633619U, 0x498FE6U,
0x10DC37U, 0x1B670DU, 0x4066D8U, 0x09BC13U, 0x328FAEU, 0xFB16FDU, 0xA9C500U, 0xA2FF93U, 0xFB2C5EU, 0xF03565U,
0x8D86B0U, 0xC65D4BU, 0xDD7DCEU, 0x95E615U, 0x8EB169U, 0xE708FAU, 0xBCDB03U, 0x37C1C4U, 0x6E72FDU, 0x25232AU,
0x3DB8F3U, 0x5ECA4CU, 0x45430DU, 0x0CF0B2U, 0x57AB61U, 0x5E3ABCU, 0x210087U, 0x2BD343U, 0xF248B8U, 0xB9392DU,
0xA0A376U, 0xEBB09FU, 0x905908U, 0x99CAF1U, 0xD3F5A6U, 0xCA251FU, 0x813ED0U, 0xF2CD01U, 0xFBD63EU, 0xA046EEU,
0x29BD51U, 0x76AE98U, 0x3C274FU, 0x055476U, 0x4ECEA5U, 0x573F58U, 0x1C24DBU, 0x47B786U, 0x6ECC7DU, 0x345CE8U,
0x7D0703U, 0x66B456U, 0xAF3DECU, 0xBC6F31U, 0xD7D0A2U, 0x8EC1CFU, 0x80321CU, 0xD9A9A1U, 0xD2FB7AU, 0xA9422BU,
0xE05184U, 0xFB8A55U, 0xB22AAAU, 0xE831B3U, 0x63E264U, 0x1ADB8CU, 0x11081BU, 0x4832E2U, 0x0BA1BDU, 0x10781CU,
0x784BC3U, 0x679052U, 0x2E902DU, 0x752BFCU, 0x7EFC57U, 0x27C58AU, 0xCC57D9U, 0xD40C64U, 0x9FBFB6U, 0x84665BU,
0xCD7540U, 0xB6CF95U, 0xBF8E6EU, 0xE415FBU, 0xE62690U, 0xBFFE0DU, 0xF04DFEU, 0xC91623U, 0x028520U, 0x19BCD9U,
0x506E06U, 0x0AEDB6U, 0x23D4E9U, 0x780728U, 0x331997U, 0x3AE84EU, 0x6173B9U, 0x6840A0U, 0x129B67U, 0x598B9EU,
0xC87009U, 0x877370U, 0x9EEAEBU, 0xF5190EU, 0xAC03D4U, 0xA690C1U, 0xFDE93AU, 0xB47AF7U, 0xAF8044U, 0xC69119U,
0xDD0ACAU, 0x166977U, 0x4EF0BCU, 0x45E2C9U, 0x3C1D52U, 0x3F8E87U, 0x64D73CU, 0x296574U, 0x327E83U, 0x7A8F1AU,
0x0114EDU, 0x0A1734U, 0x53EF3BU, 0xD8FCCAU, 0x812715U, 0xEA94A4U, 0xF185EBU, 0xB95F3AU, 0xA26C85U, 0xEBB55CU,
0xB0862AU, 0x930CA3U, 0xCEDD70U, 0x85E6CDU, 0x9D7196U, 0x562A63U, 0x6D9AE8U, 0x24411DU, 0x7F5246U, 0x76EBDBU,
0x2DB928U, 0x2712E5U, 0x5E83D7U, 0x15D80AU, 0x0C6BD1U, 0x473170U, 0x54A02FU, 0xB99B9EU, 0xE34841U, 0xEAD090U,
0xB1E33FU, 0xFA2866U, 0xE31991U, 0x88C208U, 0x8154FFU, 0xDB6FB7U, 0x92BE28U, 0x89A5D9U, 0xE25606U, 0x7BCE37U,
0x30FDFCU, 0x693E21U, 0x6F2792U, 0x3495CFU, 0x5DCE6CU, 0x465DB1U, 0x0FA46AU, 0x14B75FU, 0x5F2D85U, 0x275C60U,
0x2CC7FBU, 0xF56486U, 0xFE3C55U, 0xA5ABC8U, 0xECD02BU, 0xD743F2U, 0x9FDAC5U, 0xC0A81CU, 0xC33383U, 0x9A2262U,
0xB1D93DU, 0xE8DA8DU, 0x232252U, 0x39B19BU, 0x70AAACU, 0x6B5975U, 0x024182U, 0x59921BU, 0x522974U, 0x0B38A5U,
0x01F33EU, 0x78C1CBU, 0x3758D0U, 0x242F3DU, 0xEDB4EFU, 0xB66672U, 0xBF5701U, 0xC5CCDCU, 0xCE9F77U, 0x9726A2U,
0xDCA4F9U, 0xC5FF4CU, 0xAE4E87U, 0xB51576U, 0xFDA7E9U, 0xA63C90U, 0x2F6D47U, 0x74D6CFU, 0x1BC538U, 0x0A1D21U,
0x413EDEU, 0x58E50FU, 0x127480U, 0x6B4BF1U, 0x60992EU, 0x2BA297U, 0x327340U, 0x79E809U, 0xA0DABAU, 0x8A0367U,
0xD1009DU, 0x98BB98U, 0x836A63U, 0xCE70F6U, 0xF5832DU, 0xB69850U, 0xEE29D3U, 0xE5732EU, 0xBCE0FDU, 0xB75962U,
0x4C1A13U, 0x0589DCU, 0x1EF165U, 0x5666B7U, 0x4DFDEAU, 0x268E59U, 0x7F1794U, 0x74256FU, 0x29FE7AU, 0x626F81U,
0x700404U, 0x1996DFU, 0x828FA2U, 0xCB7C31U, 0x9067CCU, 0x9B940EU, 0xE20C17U, 0xE81FE8U, 0xB1E439U, 0xFAF586U,
0xE17FC7U, 0xA88C18U, 0xD397A1U, 0x5E4276U, 0x04794FU, 0x0FEB88U, 0x5E9271U, 0x3501E6U, 0x2C9A3EU, 0x67EA51U,
0x7C61C0U, 0x34323BU, 0x6F89EEU, 0x4618F5U, 0x1D4218U, 0xD4F1CBU, 0xCFE876U, 0x841B25U, 0xB888F8U, 0xF3D053U,
0xAA7386U, 0xA168BCU, 0xF2BB69U, 0xFB8792U, 0x80541FU, 0xC8CF4CU, 0xC3FEB5U, 0x182522U, 0x1117CBU, 0x6A9E9CU,
0x234D05U, 0x3876FAU, 0x72A42BU, 0x2FBD84U, 0x240ED4U, 0x5DD54BU, 0x56C4B2U, 0x057E65U, 0x4C2D4CU, 0xD7849BU,
0xBFD762U, 0xA44DF9U, 0xEFFEACU, 0xB6A347U, 0xBD30D2U, 0xC40B29U, 0x8FDB74U, 0x9540E6U, 0xDC330BU, 0xC3BAD8U,
0x8A89E5U, 0x71533EU, 0x7AC0BBU, 0x2BB140U, 0x212A11U, 0x7838AEU, 0x13C17FU, 0x08D290U, 0x414989U, 0x1AA85EU,
0x13B2A6U, 0x494131U, 0x625AD8U, 0xBBCF87U, 0xF43516U, 0xED26E9U, 0xA6BF78U, 0x9FCC17U, 0xDD57CEU, 0x86B75DU,
0x8FACA0U, 0xD43FE3U, 0x9D445EU, 0xA6D584U, 0x6DCF71U, 0x753C6AU, 0x3EA5AFU, 0x67F654U, 0x4C4CC9U, 0x134DBAU,
0x1AB667U, 0x4125E4U, 0x097E19U, 0x12CA0AU, 0x71D1F3U, 0x78022CU, 0xA33BACU, 0xEAA953U, 0xF17A02U, 0x9B53BDU,
0xC28074U, 0xC9BB83U, 0x90299AU, 0x9BF04DU, 0xC4C3B4U, 0xAD583BU, 0xB7084AU, 0xFEB3D1U, 0x656004U, 0x2E69FEU,
0x5FDAF3U, 0x548000U, 0x0D37DDU, 0x472E4EU, 0x5CFD33U, 0x1546F8U, 0x2E164DU, 0x678D96U, 0x3CBEE3U, 0x337768U,
0xEBE5BDU, 0xC09E47U, 0x990D5EU, 0xD234A9U, 0xC9E720U, 0x887DF7U, 0xD34C0EU, 0xFB9711U, 0xA084E0U, 0xA96C2FU,
0xF27FBEU, 0xB9E4C1U, 0x001318U, 0x4B02AFU, 0x56B867U, 0x1CEB30U, 0x477289U, 0x4E8152U, 0x358AF7U, 0x3C1AACU,
0x676159U, 0x24F2C2U, 0x3C6917U, 0x57197CU, 0x8E82E1U, 0x85F112U, 0xDE68CFU, 0xD77BDDU, 0x8C9130U, 0xE400EBU,
0xFB5B5EU, 0xB0E885U, 0xA9F6D4U, 0xE2277BU, 0x9B9CA2U, 0x108F15U, 0x5A764CU, 0x0B64ABU, 0x00AF32U, 0x599CEDU,
0x72059DU, 0x29D702U, 0x60ECE3U, 0x7A7D3CU, 0x330625U, 0x0C95D6U, 0x474D0BU, 0x9E7EA8U, 0x95FDF5U, 0xCCA666U,
0x86179BU, 0xBD8D40U, 0xFCDA65U, 0xE763BFU, 0xAE304AU, 0xF58AD1U, 0xDE9B9CU, 0x86406FU, 0x8DE3F2U, 0x54B801U,
0x1B28D8U, 0x0213D7U, 0x69C026U, 0x7259B9U, 0x3A6B48U, 0x61B017U, 0x68819FU, 0x135A68U, 0x50D9B1U, 0x49E386U,
0x02325FU, 0x9A29B0U, 0xD19E23U, 0xAAC77EU, 0xA3558DU, 0xFCAE04U, 0xF5BFF3U, 0xAE04AAU, 0xC44635U, 0xDDDDC5U,
0x966C4AU, 0xCF373BU, 0xC4A4E4U, 0x1FD47DU, 0x3E4F8AU, 0x64DC43U, 0x2DA574U, 0x3637ADU, 0x7D5C56U, 0x44CFC3U,
0x0BD688U, 0x52257DU, 0x59BBE7U, 0x03AA1AU, 0x4A5119U, 0xF142C4U, 0xB89A37U, 0xB329AAU, 0xE822D1U, 0xA9D114U,
0x93C88FU, 0xDA5A7AU, 0xC1A121U, 0x8AB090U, 0xD36B5EU, 0xDC58A7U, 0xA5C0B0U, 0x2F8369U, 0x74389EU, 0x3DAB17U,
0x26D368U, 0x4F40F9U, 0x141F26U, 0x1DAEC7U, 0x473558U, 0x446721U, 0x1DDEF6U, 0x769D6EU, 0xEF0E8DU, 0xA434D0U,
0xBFE56BU, 0xF35EBEU, 0x884D45U, 0x819440U, 0xDAA69BU, 0x917D26U, 0x88ECF5U, 0xC3C788U, 0xFB150BU, 0xB02ED6U,
0x63BF24U, 0x6A6439U, 0x3153D2U, 0x188B03U, 0x43989CU, 0x0923EDU, 0x147232U, 0x5FF99BU, 0x060B4CU, 0x2D10B5U,
0x76A1A2U, 0x7FFA7BU, 0xA568D4U, 0xECD104U, 0xD7827BU, 0x9C19EAU, 0x8D6831U, 0xC6E2DCU, 0x9F71CFU, 0x950A32U,
0xEE9BE1U, 0xA3A16CU, 0xB8761FU, 0xF16FC2U, 0x6A9C79U, 0x010FACU, 0x491786U, 0x52F453U, 0x1BEF88U, 0x007C35U,
0x4B8566U, 0x32978FU, 0x316C18U, 0x697DC1U, 0x62E6BEU, 0x3B142FU, 0xD40DC0U, 0xCFCE11U, 0x86F58EU, 0xDD66F6U,
0xD53E31U, 0x8E8988U, 0xA5125FU, 0xFC6366U, 0xB7F9B9U, 0xAEAA78U, 0xE513C3U, 0xD69096U, 0x1ECB6DU, 0x4579F8U,
0x4C6033U, 0x13B34EU, 0x5888DCU, 0x615821U, 0x2AE3F2U, 0x32F0FFU, 0x792B04U, 0x220A91U, 0x0B906AU, 0xD0432BU,
0xD97294U, 0x82AD4DU, 0xC8BE9AU, 0xD90623U, 0xB2D564U, 0xEBEE9CU, 0xE02D03U, 0xBF35D2U, 0xB686ADU, 0xCCDD2CU,
0x854CD3U, 0x1EF70AU, 0x55A51DU, 0x4C1CE4U, 0x074F67U, 0x7ED49AU, 0x7476C9U, 0x2F2F75U, 0x26BCBEU, 0x75876BU,
0x1C5650U, 0x07C885U, 0x48BB7EU, 0x9022F3U, 0x9B11A0U, 0xC2CA5DU, 0xE9C8CEU, 0xA07133U, 0xFBA238U, 0xF0B9E9U,
0xA84917U, 0x835286U, 0xDAC179U, 0x913830U, 0x822B87U, 0x4BD95EU, 0x30D289U, 0x3C43A0U, 0x67B87FU, 0x6CAA8EU,
0x353311U, 0x7E4440U, 0x47DFABU, 0x0C8E3FU, 0x1634C4U, 0x5FA7D9U, 0x04CC0AU, 0xAD5DE7U, 0xF64774U, 0xBDB409U,
0xAC2DD2U, 0xE67E67U, 0xFBC5ACU, 0x90D5F9U, 0xCB0E42U, 0xC23D9FU, 0x99B67DU, 0x9047E4U, 0xEA5DB3U, 0x218E0AU,
0x38B7D5U, 0x732034U, 0x6AFA2BU, 0x21CBFAU, 0x5A1005U, 0x5B039CU, 0x01A8FBU, 0x4C7822U, 0x574395U, 0x3CD04DU,
0xA5811AU, 0xEE3BB3U, 0xB76868U, 0xBDF19DU, 0xE64286U, 0xCF1943U, 0x949BF8U, 0xDDA225U, 0xC67156U, 0x8FCACBU,
0xF59B08U, 0xF605F5U, 0x2B36EFU, 0x20EF1AU, 0x797CC1U, 0x324664U, 0x1985BFU, 0x419CE4U, 0x4A6F51U, 0x13748AU,
0x58C42FU, 0x631F74U, 0x2A0CA1U, 0x71F51AU, 0xF9E7D7U, 0xA27CA5U, 0xA99F38U, 0xD886EBU, 0x973516U, 0x8E6F1DU,
0xC5FEECU, 0xDF0133U, 0xB61282U, 0xED8ADDU, 0xE4F954U, 0xBF7AA3U, 0x74617AU, 0x6D904DU, 0x070A95U, 0x1E795AU,
0x55E0EBU, 0x0EF334U, 0x0F0845U, 0x7098CAU, 0x798313U, 0x2360E0U, 0x687BFDU, 0x71AB0EU, 0xBA10C3U, 0x830370U,
0xC8FA2DU, 0x93EDB7U, 0x9B3742U, 0xC00689U, 0xA99DBCU, 0xB25E67U, 0xF964BAU, 0xE0F509U, 0xA7AE44U, 0xFF1DB7U,
0x54C42EU, 0x0DF6F1U, 0x066D90U, 0x5D3C0EU, 0x1487FFU, 0x2F8460U, 0x675E19U, 0x3CEFDEU, 0x37B447U, 0x6E27B0U,
0x651369U, 0x9CC856U, 0xD77B97U, 0xC9604CU, 0x88B1F9U, 0x939BA2U, 0xFA4856U, 0xB1D1DDU, 0xAAE200U, 0xE33873U,
0xB829EEU, 0xB0D20DU, 0xCBC190U, 0x407AEBU, 0x19AA3EU, 0x52A1A5U, 0x4B1240U, 0x204B1BU, 0x3ED9A2U, 0x7F2274U,
0x2437ADU, 0x2DAC8AU, 0x76DF53U, 0x5D45ACU, 0x04F43DU, 0xCEBFE2U, 0xD72CC3U, 0x9C551CU, 0xE7C7E5U, 0xEEDC72U,
0xB52D1BU, 0xBCB6CCU, 0xE6A454U, 0xA95FA7U, 0x904EFAU, 0xD3A551U, 0xCA3684U, 0x01265FU, 0x5ADD6AU, 0x72CEB1U,
0x29135CU, 0x60A1CFU, 0x7BBA92U, 0x304921U, 0x2950FCU, 0x42D316U, 0x1AA903U, 0x1138F8U, 0x48E329U, 0xC7D0A6U,
0xBC48DFU, 0xFD1B08U, 0xE6A0B1U, 0xAE3366U, 0xF55AAFU, 0xFEC898U, 0x879341U, 0x8C22FEU, 0xD5392EU, 0x9EEA61U,
0x8456D0U, 0x6D450BU, 0x769EF6U, 0x3FADE5U, 0x606508U, 0x6BD6DBU, 0x3ACD46U, 0x101C3DU, 0x5927F8U, 0x02F543U,
0x096C96U, 0x505FCCU, 0xBB8C71U, 0xA296B2U, 0xE8370FU, 0xF36C5CU, 0xBADF85U, 0xE1063AU, 0xC814FBU, 0x97AF04U,
0x9CFA15U, 0xC461EAU, 0x87D23BU, 0xBE88B4U, 0x7509CCU, 0x2E721BU, 0x27E1A2U, 0x7C5965U, 0x750A7CU, 0x0F9183U,
0x44A052U, 0x5D7BE9U, 0x1669ACU, 0x0F9277U, 0x6013CAU, 0x3B0819U, 0xB3FA65U, 0xE0E3E6U, 0xA9103BU, 0xB28BC0U,
0xDB9ED5U, 0xC0642EU, 0x8B77EBU, 0xD3EC50U, 0xD80D89U, 0xA1179EU, 0xAAC477U, 0xF1F5A0U, 0x386E19U, 0x271D4FU,
0x6F8596U, 0x541639U, 0x1F6DE8U, 0x4EFE97U, 0x45B706U, 0x1C05D9U, 0x779E30U, 0x6DCF27U, 0x2474DEU, 0x3F664DU,
0xF69BB0U, 0xAD08FBU, 0x86536FU, 0xDFE094U, 0xD1E841U, 0x883B6AU, 0xC300B7U, 0xE8D164U, 0xB16BD9U, 0xF2788AU,
0xEBA167U, 0xA192FCU, 0x3A0929U, 0x53DBD2U, 0x08F2C3U, 0x01212DU, 0x5A3ABCU, 0x518B43U, 0x29D11AU, 0x62628DU,
0x7FFD64U, 0x34ACB3U, 0x6F1E8AU, 0xE64555U, 0x95C494U, 0x9D7F2BU, 0xC62C7AU, 0x8DB485U, 0x94871DU, 0xFF5CDEU,
0xE6EFE3U, 0xADB730U, 0xF524CFU, 0xFE0F56U, 0xA5DE31U, 0x48C5E8U, 0x53377FU, 0x1AAE86U, 0x01BD59U, 0x4B4678U,
0x3A50A7U, 0x31E977U, 0x683ACCU, 0x633189U, 0x38C072U, 0x71DAEFU, 0x4B493CU, 0x82B001U, 0x99A3C2U, 0xD2383FU,
0x8F4AA4U, 0xA4D3D1U, 0xFDA00AU, 0xB62B8FU, 0xACBB75U, 0xE5C028U, 0xF6539BU, 0x9F4242U, 0xC4B985U, 0x4F2FBCU,
0x167463U, 0x1CC5D2U, 0x65DE1DU, 0x2E3C4CU, 0x35A5F3U, 0x78F622U, 0x234DDDU, 0x0A5C55U, 0x408622U, 0x5BB5FBU,
0x122E6CU, 0xC1FF95U, 0xC8C4DEU, 0xB3066BU, 0xB83FB0U, 0xE0AC25U, 0xAB775EU, 0xB24793U, 0xD9DC20U, 0x828BFDU,
0x8F30AFU, 0xD46102U, 0xDCDBD9U, 0x07582CU, 0x6E0137U, 0x75B2C6U, 0x3EE809U, 0x2F7990U, 0x64C2E7U, 0x1C913EU,
0x170A89U, 0x4C3A40U, 0x45E9D6U, 0x1E42AFU, 0x571370U, 0xE889C1U, 0xA2BA0EU, 0xFB635FU, 0xF070E0U, 0xA9CF39U,
0x821DDAU, 0xD904C7U, 0x90F734U, 0x82FCE9U, 0xCB4D72U, 0xD09716U, 0x3B848DU, 0x623D78U, 0x696EA3U, 0x30F4BEU,
0x7A075DU, 0x451E80U, 0x0C8D33U, 0x17E66EU, 0x5E76B5U, 0x050D14U, 0x0E9ECBU, 0x7607BAU, 0xF57524U, 0xACEAC5U,
0xE7F91AU, 0xFC0083U, 0x9583F4U, 0xCED96DU, 0xC6688AU, 0x9D7353U, 0x92804CU, 0xCB11BDU, 0xA00B62U, 0xA9F8C3U,
0x72E398U, 0x783244U, 0x2118F7U, 0x4A8B2AU, 0x5B5249U, 0x1061D4U, 0x09FA2FU, 0x428ABAU, 0x1911F1U, 0x31C604U,
0x6AFD9FU, 0x276D62U, 0xBC2631U, 0xF795B8U, 0xCE4C4EU, 0x855F97U, 0xDDE520U, 0xD6B479U, 0x8D0FB6U, 0x8C1C07U,
0xF7C6D8U, 0xBE77A9U, 0xA53C36U, 0xEFAFDFU, 0x369648U, 0x1D4411U, 0x40DFE6U, 0x4BEE7EU, 0x103595U, 0x5902C0U,
0x43D85BU, 0x2AC9AEU, 0x316265U, 0x7AB158U, 0x23A18BU, 0x201A56U, 0xD949E5U, 0x93F2A8U, 0x882313U, 0xC139C6U,
0xDA8A3CU, 0x97D329U, 0xEC50E2U, 0xE7AA13U, 0xBFBB8CU, 0xB42075U, 0xED5322U, 0x06C8ABU, 0x1DF85CU, 0x542785U,
0x0FB4BAU, 0x0FCD7BU, 0x544FA4U, 0x7F5414U, 0x26A54BU, 0x6D3EF2U, 0x702D31U, 0x3BD7CCU, 0x13C6DFU, 0xC83D02U,
0x83AEF9U, 0x9AB77CU, 0xD15507U, 0xC84ED2U, 0xA3DF49U, 0xF9A4BDU, 0xF836F6U, 0xA3ED4BU, 0xEADC98U, 0xD14B05U,
0x9A30E6U, 0x03A0BFU, 0x4D6B00U, 0x1458D1U, 0x1FC12EU, 0x64932FU, 0x6D28F0U, 0x36BB09U, 0x7FE29FU, 0x6551E6U,
0x0E0B21U, 0x57AAB8U, 0x54B147U, 0x8D6216U, 0x86DBA9U, 0xDDC968U, 0xB412F3U, 0xAA218EU, 0xE3FC5DU, 0xF86EF0U,
0xB35523U, 0xCA945FU, 0xC1AFCCU, 0x983C11U, 0xD264FAU, 0x49D7EFU, 0x000C14U, 0x3B1FC1U, 0x7AA75AU, 0x21F4B7U,
0x2A6FA4U, 0x728E5DU, 0x5D958AU, 0x042713U, 0x4F767DU, 0x54EDACU, 0x1D5E13U, 0x8604C0U, 0xEE91ADU, 0xB5EA36U,
0xBC79E3U, 0xE77018U, 0xAC820DU, 0x9D19E6U, 0xD6283FU, 0xCEF3A8U, 0x85E0D1U, 0xDA1A47U, 0x538BAEU, 0x389079U,
0x216360U, 0x6A6B9FU, 0x30D84EU, 0x3903E1U, 0x421230U, 0x0BE94FU, 0x10FBD6U, 0x5B6011U, 0x4215E8U, 0x008EFBU,
0xF95C07U, 0xF2759CU, 0xADE659U, 0xA49D22U, 0xFF0CB7U, 0x96964CU, 0x8CE591U, 0xC77E92U, 0x9E2F6FU, 0x959CBCU,
0xCC0601U, 0xE7475AU, 0x3CFCBFU, 0x74EF25U, 0x6717F4U, 0x2E048BU, 0x15DF0AU, 0x5A6CF5U, 0x03716CU, 0x08A33BU,
0x5098C2U, 0x5B1945U, 0x20C2BCU, 0x69F063U, 0xF22972U, 0xBB1A8DU, 0xE0814DU, 0xCA52F6U, 0x936AABU, 0x98B958U,
0xC9A2C5U, 0x820306U, 0x9B593BU, 0xF4CAE0U, 0xEE7315U, 0xA7209EU, 0x7C9BCBU, 0x75C930U, 0x0E54A4U, 0x45E75FU,
0x5CBC12U, 0x173D81U, 0x0F0778U, 0x44D4AFU, 0x3FC596U, 0x363E59U, 0x65ACE8U, 0x6C9737U, 0xA346E6U, 0xD95DD9U,
0xD0FE10U, 0x8B26E6U, 0xC2357FU, 0xD9CE28U, 0x92DDC1U, 0xAB455EU, 0xE1B6AFU, 0xB8ADF4U, 0xB35861U, 0x68438AU,
0x41C157U, 0x12B864U, 0x5B2BB9U, 0x45B00AU, 0x0EC3C6U, 0x175B95U, 0x7C2828U, 0x25B3F3U, 0x2E2206U, 0x75580DU,
0x3DDBD8U, 0x86C223U, 0xCF31BAU, 0xD4AADDU, 0x9FF804U, 0xC64193U, 0xCD526AU, 0xBDA9F4U, 0xB2BD95U, 0xE92E4AU,
0xA0C5FBU, 0xBBD424U, 0xD20F7DU, 0x093DDAU, 0x01A603U, 0x5A77F0U, 0x514CEDU, 0x089E36U, 0x63A7D3U, 0x7A3448U,
0x31FF3CU, 0x2BCEE7U, 0x625462U, 0x150799U, 0x1CBC84U, 0xC7ED77U, 0x8C76AAU, 0x95C409U, 0xDF9954U, 0xE62A8FU,
0xAD213EU, 0xF6F1E1U, 0xFF4A00U, 0xA4191EU, 0x8D82C7U, 0xD7B330U, 0x9C69A9U, 0x057ACEU, 0x42C357U, 0x2B1088U,
0x303A79U, 0x7BEB76U, 0x63F087U, 0x284358U, 0x7198E1U, 0x5A88B2U, 0x017B7EU, 0x0860CDU, 0x53F510U, 0x9A0F63U,
0xA00CFEU, 0xEBB535U, 0xF2E6C0U, 0xB97DDBU, 0xEC0F2EU, 0xE796B5U, 0x9C0578U, 0xD47E0BU, 0xCFEF92U, 0x86F564U,
0x1D16ADU, 0x768F32U, 0x2FFC43U, 0x24669CU, 0x7C752DU, 0x778CE2U, 0x2E1F9BU, 0x45000CU, 0x5EF0D5U, 0x13FB62U,
0x40282BU, 0x4811D4U, 0xB38344U, 0xB8789FU, 0xE16BEAU, 0xAAB261U, 0xB38194U, 0xF81B4FU, 0xC2CA52U, 0x8BE1B1U,
0xD0726CU, 0xD903DFU, 0x829982U, 0xE94A79U, 0x7471FDU, 0x36E026U, 0x2FBA93U, 0x640DC8U, 0x3F1431U, 0x16D7B6U,
0x4D6C6FU, 0x443C18U, 0x1E8781U, 0x55947EU, 0x6C4FBFU, 0x27FFA0U, 0xBEE451U, 0xF5378FU, 0xAE0E2EU, 0xA2CD71U,
0xC9D7C8U, 0x98661FU, 0x93BDC6U, 0xC88EE5U, 0xC15438U, 0xBA45C3U, 0xF2FE56U, 0xE9290DU, 0x2230E8U, 0x3B9273U,
0x70C98FU, 0x0958DCU, 0x02A343U, 0x58B0A2U, 0x150A7DU, 0x0E5BC4U, 0x6FC897U, 0x74F33AU, 0x3F23E9U, 0x66A834U,
0xECDB0FU, 0xB542DAU, 0x9E5131U, 0xC7ABA5U, 0x8C38FEU, 0x97010BU, 0xDED290U, 0xA4CC7DU, 0xAD3D2EU, 0xF6B6B3U,
0xF9A540U, 0x205ED9U, 0x634EB6U, 0x5A9567U, 0x11A6D8U, 0x0B3F09U };
const uint32_t DMR_A_TABLE[] = {
0U, 4U, 8U, 12U, 16U, 20U, 24U, 28U, 32U, 36U, 40U, 44U,
48U, 52U, 56U, 60U, 64U, 68U, 1U, 5U, 9U, 13U, 17U, 21U };
const uint32_t DMR_B_TABLE[] = {
25U, 29U, 33U, 37U, 41U, 45U, 49U, 53U, 57U, 61U, 65U, 69U,
2U, 6U, 10U, 14U, 18U, 22U, 26U, 30U, 34U, 38U, 42U, 46U };
const uint32_t DMR_C_TABLE[] = {
50U, 54U, 58U, 62U, 66U, 70U, 3U, 7U, 11U, 15U, 19U, 23U,
27U, 31U, 35U, 39U, 43U, 47U, 51U, 55U, 59U, 63U, 67U, 71U };
const uint32_t IMBE_INTERLEAVE[] = {
0, 7, 12, 19, 24, 31, 36, 43, 48, 55, 60, 67, 72, 79, 84, 91, 96, 103, 108, 115, 120, 127, 132, 139,
1, 6, 13, 18, 25, 30, 37, 42, 49, 54, 61, 66, 73, 78, 85, 90, 97, 102, 109, 114, 121, 126, 133, 138,
2, 9, 14, 21, 26, 33, 38, 45, 50, 57, 62, 69, 74, 81, 86, 93, 98, 105, 110, 117, 122, 129, 134, 141,
3, 8, 15, 20, 27, 32, 39, 44, 51, 56, 63, 68, 75, 80, 87, 92, 99, 104, 111, 116, 123, 128, 135, 140,
4, 11, 16, 23, 28, 35, 40, 47, 52, 59, 64, 71, 76, 83, 88, 95, 100, 107, 112, 119, 124, 131, 136, 143,
5, 10, 17, 22, 29, 34, 41, 46, 53, 58, 65, 70, 77, 82, 89, 94, 101, 106, 113, 118, 125, 130, 137, 142 };
// ---------------------------------------------------------------------------
// Class Declaration
// Implements routines to regenerate DMR/IMBE data using forward error
// correction.
// ---------------------------------------------------------------------------
class HOST_SW_API AMBEFEC {
public:
/// <summary>Initializes a new instance of the AMBEFEC class.</summary>
AMBEFEC();
/// <summary>Finalizes a instance of the AMBEFEC class.</summary>
~AMBEFEC();
/// <summary>Regenerates the DMR AMBE FEC for the input bytes.</summary>
uint32_t regenerateDMR(uint8_t* bytes) const;
/// <summary>Returns the number of errors on the DMR BER input bytes.</summary>
uint32_t measureDMRBER(const uint8_t* bytes) const;
/// <summary>Regenerates the P25 IMBE FEC for the input bytes.</summary>
uint32_t regenerateIMBE(uint8_t* bytes) const;
/// <summary>Returns the number of errors on the P25 BER input bytes.</summary>
uint32_t measureP25BER(const uint8_t* bytes) const;
private:
/// <summary></summary>
uint32_t regenerate(uint32_t& a, uint32_t& b, uint32_t& c, bool b23) const;
};
} // namespace edac
#endif // __AMBE_FEC_H__

@ -0,0 +1,178 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* File: bch3.c
* Title: Encoder/decoder for binary BCH codes in C (Version 3.1)
* Author: Robert Morelos-Zaragoza
* Date: August 1994
* Revised: June 13, 1997
*
* =============== Encoder/Decoder for binary BCH codes in C =================
*
* Version 1: Original program. The user provides the generator polynomial
* of the code (cumbersome!).
* Version 2: Computes the generator polynomial of the code.
* Version 3: No need to input the coefficients of a primitive polynomial of
* degree m, used to construct the Galois Field GF(2**m). The
* program now works for any binary BCH code of length such that:
* 2**(m-1) - 1 < length <= 2**m - 1
*
* Note: You may have to change the size of the arrays to make it work.
*
* The encoding and decoding methods used in this program are based on the
* book "Error Control Coding: Fundamentals and Applications", by Lin and
* Costello, Prentice Hall, 1983.
*
* Thanks to Patrick Boyle (pboyle@era.com) for his observation that 'bch2.c'
* did not work for lengths other than 2**m-1 which led to this new version.
* Portions of this program are from 'rs.c', a Reed-Solomon encoder/decoder
* in C, written by Simon Rockliff (simon@augean.ua.oz.au) on 21/9/89. The
* previous version of the BCH encoder/decoder in C, 'bch2.c', was written by
* Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) on 5/19/92.
*
* NOTE:
* The author is not responsible for any malfunctioning of
* this program, nor for any damage caused by it. Please include the
* original program along with these comments in any redistribution.
*
* For more information, suggestions, or other ideas on implementing error
* correcting codes, please contact me at:
*
* Robert Morelos-Zaragoza
* 5120 Woodway, Suite 7036
* Houston, Texas 77056
*
* email: r.morelos-zaragoza@ieee.org
*
* COPYRIGHT NOTICE: This computer program is free for non-commercial purposes.
* You may implement this program for any non-commercial application. You may
* also implement this program for commercial purposes, provided that you
* obtain my written permission. Any modification of this program is covered
* by this copyright.
*
* == Copyright (c) 1994-7, Robert Morelos-Zaragoza. All rights reserved. ==
*
* m = order of the Galois field GF(2**m)
* n = 2**m - 1 = size of the multiplicative group of GF(2**m)
* length = length of the BCH code
* t = error correcting capability (max. no. of errors the code corrects)
* d = 2*t + 1 = designed min. distance = no. of consecutive roots of g(x) + 1
* k = n - deg(g(x)) = dimension (no. of information bits/codeword) of the code
* p[] = coefficients of a primitive polynomial used to generate GF(2**m)
* g[] = coefficients of the generator polynomial, g(x)
* alpha_to [] = log table of GF(2**m)
* index_of[] = antilog table of GF(2**m)
* data[] = information bits = coefficients of data polynomial, i(x)
* bb[] = coefficients of redundancy polynomial x^(length-k) i(x) modulo g(x)
* numerr = number of errors
* errpos[] = error positions
* recd[] = coefficients of the received polynomial
* decerror = number of decoding errors (in _message_ positions)
*
*/
#include "Defines.h"
#include "edac/BCH.h"
using namespace edac;
#include <cmath>
#include <cstdio>
#include <cassert>
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const int length = 63;
const int k = 16;
const int g[] = {
1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1,
1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1
};
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the BCH class.
/// </summary>
BCH::BCH()
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the BCH class.
/// </summary>
BCH::~BCH()
{
/* stub */
}
/// <summary>
/// Encodes input data with BCH.
/// </summary>
/// <param name="nid">P25 NID data to encode with BCH.</param>
void BCH::encode(uint8_t* nid)
{
assert(nid != NULL);
int data[16];
for (int i = 0; i < 16; i++)
data[i] = READ_BIT(nid, i) ? 1 : 0;
int bb[63];
encode(data, bb);
for (int i = 0; i < (length - k); i++) {
bool b = bb[i] == 1;
WRITE_BIT(nid, i + 16U, b);
}
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
///
/// </summary>
/// <remarks>
/// Compute redundacy bb[], the coefficients of b(x). The redundancy
/// polynomial b(x) is the remainder after dividing x^(length-k)*data(x)
/// by the generator polynomial g(x).
/// </remarks>
/// <param name="data"></param>
/// <param name="bb"></param>
void BCH::encode(const int* data, int* bb)
{
for (int i = 0; i < length - k; i++)
bb[i] = 0;
for (int i = k - 1; i >= 0; i--) {
int feedback = data[i] ^ bb[length - k - 1];
if (feedback != 0) {
for (int j = length - k - 1; j > 0; j--)
if (g[j] != 0)
bb[j] = bb[j - 1] ^ feedback;
else
bb[j] = bb[j - 1];
bb[0] = g[0] && feedback;
}
else {
for (int j = length - k - 1; j > 0; j--)
bb[j] = bb[j - 1];
bb[0] = 0;
}
}
}

@ -0,0 +1,59 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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(__BCH_H__)
#define __BCH_H__
#include "Defines.h"
namespace edac
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements BoseChaudhuriHocquenghem codes for protecting P25 NID
// data.
// ---------------------------------------------------------------------------
class HOST_SW_API BCH {
public:
/// <summary>Initializes a new instance of the BCH class.</summary>
BCH();
/// <summary>Finalizes a instance of the BCH class.</summary>
~BCH();
/// <summary>Encodes input data with BCH.</summary>
void encode(uint8_t* data);
private:
/// <summary></summary>
void encode(const int* data, int* bb);
};
} // namespace edac
#endif // __BCH_H__

@ -0,0 +1,401 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2012 by Ian Wraith
* Copyright (C) 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 "Defines.h"
#include "edac/BPTC19696.h"
#include "edac/Hamming.h"
#include "Utils.h"
using namespace edac;
#include <cstdio>
#include <cassert>
#include <cstring>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the BPTC19696 class.
/// </summary>
BPTC19696::BPTC19696() :
m_rawData(NULL),
m_deInterData(NULL)
{
m_rawData = new bool[196];
m_deInterData = new bool[196];
}
/// <summary>
/// Finalizes a instance of the BPTC19696 class.
/// </summary>
BPTC19696::~BPTC19696()
{
delete[] m_rawData;
delete[] m_deInterData;
}
/// <summary>
/// Decode BPTC (196,96) FEC.
/// </summary>
/// <param name="in">Input data to decode.</param>
/// <param name="out">Decoded data.</param>
void BPTC19696::decode(const uint8_t* in, uint8_t* out)
{
assert(in != NULL);
assert(out != NULL);
// Get the raw binary
decodeExtractBinary(in);
// Deinterleave
decodeDeInterleave();
// Error check
decodeErrorCheck();
// Extract Data
decodeExtractData(out);
}
/// <summary>
/// Encode BPTC (196,96) FEC.
/// </summary>
/// <param name="in">Input data to encode.</param>
/// <param name="out">Encoded data.</param>
void BPTC19696::encode(const uint8_t* in, uint8_t* out)
{
assert(in != NULL);
assert(out != NULL);
// Extract Data
encodeExtractData(in);
// Error check
encodeErrorCheck();
// Deinterleave
encodeInterleave();
// Get the raw binary
encodeExtractBinary(out);
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
///
/// </summary>
/// <param name="in"></param>
void BPTC19696::decodeExtractBinary(const uint8_t* in)
{
// First block
Utils::byteToBitsBE(in[0U], m_rawData + 0U);
Utils::byteToBitsBE(in[1U], m_rawData + 8U);
Utils::byteToBitsBE(in[2U], m_rawData + 16U);
Utils::byteToBitsBE(in[3U], m_rawData + 24U);
Utils::byteToBitsBE(in[4U], m_rawData + 32U);
Utils::byteToBitsBE(in[5U], m_rawData + 40U);
Utils::byteToBitsBE(in[6U], m_rawData + 48U);
Utils::byteToBitsBE(in[7U], m_rawData + 56U);
Utils::byteToBitsBE(in[8U], m_rawData + 64U);
Utils::byteToBitsBE(in[9U], m_rawData + 72U);
Utils::byteToBitsBE(in[10U], m_rawData + 80U);
Utils::byteToBitsBE(in[11U], m_rawData + 88U);
Utils::byteToBitsBE(in[12U], m_rawData + 96U);
// Handle the two bits
bool bits[8U];
Utils::byteToBitsBE(in[20U], bits);
m_rawData[98U] = bits[6U];
m_rawData[99U] = bits[7U];
// Second block
Utils::byteToBitsBE(in[21U], m_rawData + 100U);
Utils::byteToBitsBE(in[22U], m_rawData + 108U);
Utils::byteToBitsBE(in[23U], m_rawData + 116U);
Utils::byteToBitsBE(in[24U], m_rawData + 124U);
Utils::byteToBitsBE(in[25U], m_rawData + 132U);
Utils::byteToBitsBE(in[26U], m_rawData + 140U);
Utils::byteToBitsBE(in[27U], m_rawData + 148U);
Utils::byteToBitsBE(in[28U], m_rawData + 156U);
Utils::byteToBitsBE(in[29U], m_rawData + 164U);
Utils::byteToBitsBE(in[30U], m_rawData + 172U);
Utils::byteToBitsBE(in[31U], m_rawData + 180U);
Utils::byteToBitsBE(in[32U], m_rawData + 188U);
}
/// <summary>
///
/// </summary>
void BPTC19696::decodeDeInterleave()
{
for (uint32_t i = 0U; i < 196U; i++)
m_deInterData[i] = false;
// The first bit is R(3) which is not used so can be ignored
for (uint32_t a = 0U; a < 196U; a++) {
// Calculate the interleave sequence
uint32_t interleaveSequence = (a * 181U) % 196U;
// Shuffle the data
m_deInterData[a] = m_rawData[interleaveSequence];
}
}
/// <summary>
///
/// </summary>
void BPTC19696::decodeErrorCheck()
{
bool fixing;
uint32_t count = 0U;
do {
fixing = false;
// Run through each of the 15 columns
bool col[13U];
for (uint32_t c = 0U; c < 15U; c++) {
uint32_t pos = c + 1U;
for (uint32_t a = 0U; a < 13U; a++) {
col[a] = m_deInterData[pos];
pos = pos + 15U;
}
if (Hamming::decode1393(col)) {
uint32_t pos = c + 1U;
for (uint32_t a = 0U; a < 13U; a++) {
m_deInterData[pos] = col[a];
pos = pos + 15U;
}
fixing = true;
}
}
// Run through each of the 9 rows containing data
for (uint32_t r = 0U; r < 9U; r++) {
uint32_t pos = (r * 15U) + 1U;
if (Hamming::decode15113_2(m_deInterData + pos))
fixing = true;
}
count++;
} while (fixing && count < 5U);
}
/// <summary>
///
/// </summary>
/// <param name="data"></param>
void BPTC19696::decodeExtractData(uint8_t* data) const
{
bool bData[96U];
uint32_t pos = 0U;
for (uint32_t a = 4U; a <= 11U; a++, pos++)
bData[pos] = m_deInterData[a];
for (uint32_t a = 16U; a <= 26U; a++, pos++)
bData[pos] = m_deInterData[a];
for (uint32_t a = 31U; a <= 41U; a++, pos++)
bData[pos] = m_deInterData[a];
for (uint32_t a = 46U; a <= 56U; a++, pos++)
bData[pos] = m_deInterData[a];
for (uint32_t a = 61U; a <= 71U; a++, pos++)
bData[pos] = m_deInterData[a];
for (uint32_t a = 76U; a <= 86U; a++, pos++)
bData[pos] = m_deInterData[a];
for (uint32_t a = 91U; a <= 101U; a++, pos++)
bData[pos] = m_deInterData[a];
for (uint32_t a = 106U; a <= 116U; a++, pos++)
bData[pos] = m_deInterData[a];
for (uint32_t a = 121U; a <= 131U; a++, pos++)
bData[pos] = m_deInterData[a];
Utils::bitsToByteBE(bData + 0U, data[0U]);
Utils::bitsToByteBE(bData + 8U, data[1U]);
Utils::bitsToByteBE(bData + 16U, data[2U]);
Utils::bitsToByteBE(bData + 24U, data[3U]);
Utils::bitsToByteBE(bData + 32U, data[4U]);
Utils::bitsToByteBE(bData + 40U, data[5U]);
Utils::bitsToByteBE(bData + 48U, data[6U]);
Utils::bitsToByteBE(bData + 56U, data[7U]);
Utils::bitsToByteBE(bData + 64U, data[8U]);
Utils::bitsToByteBE(bData + 72U, data[9U]);
Utils::bitsToByteBE(bData + 80U, data[10U]);
Utils::bitsToByteBE(bData + 88U, data[11U]);
}
/// <summary>
///
/// </summary>
/// <param name="in"></param>
void BPTC19696::encodeExtractData(const uint8_t* in) const
{
bool bData[96U];
Utils::byteToBitsBE(in[0U], bData + 0U);
Utils::byteToBitsBE(in[1U], bData + 8U);
Utils::byteToBitsBE(in[2U], bData + 16U);
Utils::byteToBitsBE(in[3U], bData + 24U);
Utils::byteToBitsBE(in[4U], bData + 32U);
Utils::byteToBitsBE(in[5U], bData + 40U);
Utils::byteToBitsBE(in[6U], bData + 48U);
Utils::byteToBitsBE(in[7U], bData + 56U);
Utils::byteToBitsBE(in[8U], bData + 64U);
Utils::byteToBitsBE(in[9U], bData + 72U);
Utils::byteToBitsBE(in[10U], bData + 80U);
Utils::byteToBitsBE(in[11U], bData + 88U);
for (uint32_t i = 0U; i < 196U; i++)
m_deInterData[i] = false;
uint32_t pos = 0U;
for (uint32_t a = 4U; a <= 11U; a++, pos++)
m_deInterData[a] = bData[pos];
for (uint32_t a = 16U; a <= 26U; a++, pos++)
m_deInterData[a] = bData[pos];
for (uint32_t a = 31U; a <= 41U; a++, pos++)
m_deInterData[a] = bData[pos];
for (uint32_t a = 46U; a <= 56U; a++, pos++)
m_deInterData[a] = bData[pos];
for (uint32_t a = 61U; a <= 71U; a++, pos++)
m_deInterData[a] = bData[pos];
for (uint32_t a = 76U; a <= 86U; a++, pos++)
m_deInterData[a] = bData[pos];
for (uint32_t a = 91U; a <= 101U; a++, pos++)
m_deInterData[a] = bData[pos];
for (uint32_t a = 106U; a <= 116U; a++, pos++)
m_deInterData[a] = bData[pos];
for (uint32_t a = 121U; a <= 131U; a++, pos++)
m_deInterData[a] = bData[pos];
}
/// <summary>
///
/// </summary>
void BPTC19696::encodeErrorCheck()
{
// Run through each of the 9 rows containing data
for (uint32_t r = 0U; r < 9U; r++) {
uint32_t pos = (r * 15U) + 1U;
Hamming::encode15113_2(m_deInterData + pos);
}
// Run through each of the 15 columns
bool col[13U];
for (uint32_t c = 0U; c < 15U; c++) {
uint32_t pos = c + 1U;
for (uint32_t a = 0U; a < 13U; a++) {
col[a] = m_deInterData[pos];
pos = pos + 15U;
}
Hamming::encode1393(col);
pos = c + 1U;
for (uint32_t a = 0U; a < 13U; a++) {
m_deInterData[pos] = col[a];
pos = pos + 15U;
}
}
}
/// <summary>
///
/// </summary>
void BPTC19696::encodeInterleave()
{
for (uint32_t i = 0U; i < 196U; i++)
m_rawData[i] = false;
// The first bit is R(3) which is not used so can be ignored
for (uint32_t a = 0U; a < 196U; a++) {
// Calculate the interleave sequence
uint32_t interleaveSequence = (a * 181U) % 196U;
// Unshuffle the data
m_rawData[interleaveSequence] = m_deInterData[a];
}
}
/// <summary>
///
/// </summary>
/// <param name="data"></param>
void BPTC19696::encodeExtractBinary(uint8_t* data)
{
// First block
Utils::bitsToByteBE(m_rawData + 0U, data[0U]);
Utils::bitsToByteBE(m_rawData + 8U, data[1U]);
Utils::bitsToByteBE(m_rawData + 16U, data[2U]);
Utils::bitsToByteBE(m_rawData + 24U, data[3U]);
Utils::bitsToByteBE(m_rawData + 32U, data[4U]);
Utils::bitsToByteBE(m_rawData + 40U, data[5U]);
Utils::bitsToByteBE(m_rawData + 48U, data[6U]);
Utils::bitsToByteBE(m_rawData + 56U, data[7U]);
Utils::bitsToByteBE(m_rawData + 64U, data[8U]);
Utils::bitsToByteBE(m_rawData + 72U, data[9U]);
Utils::bitsToByteBE(m_rawData + 80U, data[10U]);
Utils::bitsToByteBE(m_rawData + 88U, data[11U]);
// Handle the two bits
uint8_t byte;
Utils::bitsToByteBE(m_rawData + 96U, byte);
data[12U] = (data[12U] & 0x3FU) | ((byte >> 0) & 0xC0U);
data[20U] = (data[20U] & 0xFCU) | ((byte >> 4) & 0x03U);
// Second block
Utils::bitsToByteBE(m_rawData + 100U, data[21U]);
Utils::bitsToByteBE(m_rawData + 108U, data[22U]);
Utils::bitsToByteBE(m_rawData + 116U, data[23U]);
Utils::bitsToByteBE(m_rawData + 124U, data[24U]);
Utils::bitsToByteBE(m_rawData + 132U, data[25U]);
Utils::bitsToByteBE(m_rawData + 140U, data[26U]);
Utils::bitsToByteBE(m_rawData + 148U, data[27U]);
Utils::bitsToByteBE(m_rawData + 156U, data[28U]);
Utils::bitsToByteBE(m_rawData + 164U, data[29U]);
Utils::bitsToByteBE(m_rawData + 172U, data[30U]);
Utils::bitsToByteBE(m_rawData + 180U, data[31U]);
Utils::bitsToByteBE(m_rawData + 188U, data[32U]);
}

@ -0,0 +1,78 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 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.
*/
#if !defined(__BPTC19696_H__)
#define __BPTC19696_H__
#include "Defines.h"
namespace edac
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements Block Product Turbo Code (196,96) FEC.
// ---------------------------------------------------------------------------
class HOST_SW_API BPTC19696 {
public:
/// <summary>Initializes a new instance of the BPTC19696 class.</summary>
BPTC19696();
/// <summary>Finalizes a instance of the BPTC19696 class.</summary>
~BPTC19696();
/// <summary>Decode BPTC (196,96) FEC.</summary>
void decode(const uint8_t* in, uint8_t* out);
/// <summary>Encode BPTC (196,96) FEC.</summary>
void encode(const uint8_t* in, uint8_t* out);
private:
bool* m_rawData;
bool* m_deInterData;
/// <summary></summary>
void decodeExtractBinary(const uint8_t* in);
/// <summary></summary>
void decodeErrorCheck();
/// <summary></summary>
void decodeDeInterleave();
/// <summary></summary>
void decodeExtractData(uint8_t* data) const;
/// <summary></summary>
void encodeExtractData(const uint8_t* in) const;
/// <summary></summary>
void encodeInterleave();
/// <summary></summary>
void encodeErrorCheck();
/// <summary></summary>
void encodeExtractBinary(uint8_t* data);
};
} // namespace edac
#endif // __BPTC19696_H__

@ -0,0 +1,442 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2018 by Bryan Biedenkapp N2PLL
*
* 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 "Defines.h"
#include "edac/CRC.h"
#include "Utils.h"
using namespace edac;
#include <cstdint>
#include <cstdio>
#include <cassert>
#include <cmath>
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const uint8_t CRC8_TABLE[] = {
0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31,
0x24, 0x23, 0x2A, 0x2D, 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, 0xE0, 0xE7, 0xEE, 0xE9,
0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1,
0xB4, 0xB3, 0xBA, 0xBD, 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, 0xB7, 0xB0, 0xB9, 0xBE,
0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16,
0x03, 0x04, 0x0D, 0x0A, 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, 0x89, 0x8E, 0x87, 0x80,
0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8,
0xDD, 0xDA, 0xD3, 0xD4, 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, 0x19, 0x1E, 0x17, 0x10,
0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F,
0x6A, 0x6D, 0x64, 0x63, 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, 0xAE, 0xA9, 0xA0, 0xA7,
0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF,
0xFA, 0xFD, 0xF4, 0xF3, 0x01 };
const uint16_t CRC9_TABLE[] = {
0x000, 0x259, 0x2B2, 0x0EB, 0x23D, 0x064, 0x08F, 0x2D6,
0x27A, 0x023, 0x0C8, 0x291, 0x047, 0x21E, 0x2F5, 0x0AC,
0x0F4, 0x2AD, 0x246, 0x01F, 0x2C9, 0x090, 0x07B, 0x222,
0x28E, 0x0D7, 0x03C, 0x265, 0x0B3, 0x2EA, 0x201, 0x058,
0x2B1, 0x0E8, 0x003, 0x25A, 0x08C, 0x2D5, 0x23E, 0x067,
0x0CB, 0x292, 0x279, 0x020, 0x2F6, 0x0AF, 0x044, 0x21D,
0x245, 0x01C, 0x0F7, 0x2AE, 0x078, 0x221, 0x2CA, 0x093,
0x03F, 0x266, 0x28D, 0x0D4, 0x202, 0x05B, 0x0B0, 0x2E9,
0x03B, 0x262, 0x289, 0x0D0, 0x206, 0x05F, 0x0B4, 0x2ED,
0x241, 0x018, 0x0F3, 0x2AA, 0x07C, 0x225, 0x2CE, 0x097,
0x0CF, 0x296, 0x27D, 0x024, 0x2F2, 0x0AB, 0x040, 0x219,
0x2B5, 0x0EC, 0x007, 0x25E, 0x088, 0x2D1, 0x23A, 0x063,
0x28A, 0x0D3, 0x038, 0x261, 0x0B7, 0x2EE, 0x205, 0x05C,
0x0F0, 0x2A9, 0x242, 0x01B, 0x2CD, 0x094, 0x07F, 0x226,
0x27E, 0x027, 0x0CC, 0x295, 0x043, 0x21A, 0x2F1, 0x0A8,
0x004, 0x25D, 0x2B6, 0x0EF, 0x239, 0x060, 0x08B, 0x2D2,
0x276, 0x02F, 0x0C4, 0x29D, 0x04B, 0x212, 0x2F9, 0x0A0,
0x00C, 0x255, 0x2BE, 0x0E7, 0x231, 0x068, 0x083, 0x2DA,
0x282, 0x0DB, 0x030, 0x269, 0x0BF, 0x2E6, 0x20D, 0x054,
0x0F8, 0x2A1, 0x24A, 0x013, 0x2C5, 0x09C, 0x077, 0x22E,
0x0C7, 0x29E, 0x275, 0x02C, 0x2FA, 0x0A3, 0x048, 0x211,
0x2BD, 0x0E4, 0x00F, 0x256, 0x080, 0x2D9, 0x232, 0x06B,
0x033, 0x26A, 0x281, 0x0D8, 0x20E, 0x057, 0x0BC, 0x2E5,
0x249, 0x010, 0x0FB, 0x2A2, 0x074, 0x22D, 0x2C6, 0x09F,
0x24D, 0x014, 0x0FF, 0x2A6, 0x070, 0x229, 0x2C2, 0x09B,
0x037, 0x26E, 0x285, 0x0DC, 0x20A, 0x053, 0x0B8, 0x2E1,
0x2B9, 0x0E0, 0x00B, 0x252, 0x084, 0x2DD, 0x236, 0x06F,
0x0C3, 0x29A, 0x271, 0x028, 0x2FE, 0x0A7, 0x04C, 0x215,
0x0FC, 0x2A5, 0x24E, 0x017, 0x2C1, 0x098, 0x073, 0x22A,
0x286, 0x0DF, 0x034, 0x26D, 0x0BB, 0x2E2, 0x209, 0x050,
0x008, 0x251, 0x2BA, 0x0E3, 0x235, 0x06C, 0x087, 0x2DE,
0x272, 0x02B, 0x0C0, 0x299, 0x04F, 0x216, 0x2FD, 0x0A4 };
const uint16_t CCITT16_TABLE1[] = {
0x0000U, 0x1189U, 0x2312U, 0x329bU, 0x4624U, 0x57adU, 0x6536U, 0x74bfU,
0x8c48U, 0x9dc1U, 0xaf5aU, 0xbed3U, 0xca6cU, 0xdbe5U, 0xe97eU, 0xf8f7U,
0x1081U, 0x0108U, 0x3393U, 0x221aU, 0x56a5U, 0x472cU, 0x75b7U, 0x643eU,
0x9cc9U, 0x8d40U, 0xbfdbU, 0xae52U, 0xdaedU, 0xcb64U, 0xf9ffU, 0xe876U,
0x2102U, 0x308bU, 0x0210U, 0x1399U, 0x6726U, 0x76afU, 0x4434U, 0x55bdU,
0xad4aU, 0xbcc3U, 0x8e58U, 0x9fd1U, 0xeb6eU, 0xfae7U, 0xc87cU, 0xd9f5U,
0x3183U, 0x200aU, 0x1291U, 0x0318U, 0x77a7U, 0x662eU, 0x54b5U, 0x453cU,
0xbdcbU, 0xac42U, 0x9ed9U, 0x8f50U, 0xfbefU, 0xea66U, 0xd8fdU, 0xc974U,
0x4204U, 0x538dU, 0x6116U, 0x709fU, 0x0420U, 0x15a9U, 0x2732U, 0x36bbU,
0xce4cU, 0xdfc5U, 0xed5eU, 0xfcd7U, 0x8868U, 0x99e1U, 0xab7aU, 0xbaf3U,
0x5285U, 0x430cU, 0x7197U, 0x601eU, 0x14a1U, 0x0528U, 0x37b3U, 0x263aU,
0xdecdU, 0xcf44U, 0xfddfU, 0xec56U, 0x98e9U, 0x8960U, 0xbbfbU, 0xaa72U,
0x6306U, 0x728fU, 0x4014U, 0x519dU, 0x2522U, 0x34abU, 0x0630U, 0x17b9U,
0xef4eU, 0xfec7U, 0xcc5cU, 0xddd5U, 0xa96aU, 0xb8e3U, 0x8a78U, 0x9bf1U,
0x7387U, 0x620eU, 0x5095U, 0x411cU, 0x35a3U, 0x242aU, 0x16b1U, 0x0738U,
0xffcfU, 0xee46U, 0xdcddU, 0xcd54U, 0xb9ebU, 0xa862U, 0x9af9U, 0x8b70U,
0x8408U, 0x9581U, 0xa71aU, 0xb693U, 0xc22cU, 0xd3a5U, 0xe13eU, 0xf0b7U,
0x0840U, 0x19c9U, 0x2b52U, 0x3adbU, 0x4e64U, 0x5fedU, 0x6d76U, 0x7cffU,
0x9489U, 0x8500U, 0xb79bU, 0xa612U, 0xd2adU, 0xc324U, 0xf1bfU, 0xe036U,
0x18c1U, 0x0948U, 0x3bd3U, 0x2a5aU, 0x5ee5U, 0x4f6cU, 0x7df7U, 0x6c7eU,
0xa50aU, 0xb483U, 0x8618U, 0x9791U, 0xe32eU, 0xf2a7U, 0xc03cU, 0xd1b5U,
0x2942U, 0x38cbU, 0x0a50U, 0x1bd9U, 0x6f66U, 0x7eefU, 0x4c74U, 0x5dfdU,
0xb58bU, 0xa402U, 0x9699U, 0x8710U, 0xf3afU, 0xe226U, 0xd0bdU, 0xc134U,
0x39c3U, 0x284aU, 0x1ad1U, 0x0b58U, 0x7fe7U, 0x6e6eU, 0x5cf5U, 0x4d7cU,
0xc60cU, 0xd785U, 0xe51eU, 0xf497U, 0x8028U, 0x91a1U, 0xa33aU, 0xb2b3U,
0x4a44U, 0x5bcdU, 0x6956U, 0x78dfU, 0x0c60U, 0x1de9U, 0x2f72U, 0x3efbU,
0xd68dU, 0xc704U, 0xf59fU, 0xe416U, 0x90a9U, 0x8120U, 0xb3bbU, 0xa232U,
0x5ac5U, 0x4b4cU, 0x79d7U, 0x685eU, 0x1ce1U, 0x0d68U, 0x3ff3U, 0x2e7aU,
0xe70eU, 0xf687U, 0xc41cU, 0xd595U, 0xa12aU, 0xb0a3U, 0x8238U, 0x93b1U,
0x6b46U, 0x7acfU, 0x4854U, 0x59ddU, 0x2d62U, 0x3cebU, 0x0e70U, 0x1ff9U,
0xf78fU, 0xe606U, 0xd49dU, 0xc514U, 0xb1abU, 0xa022U, 0x92b9U, 0x8330U,
0x7bc7U, 0x6a4eU, 0x58d5U, 0x495cU, 0x3de3U, 0x2c6aU, 0x1ef1U, 0x0f78U };
const uint16_t CCITT16_TABLE2[] = {
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 };
const uint32_t CRC32_TABLE[] = {
0x00000000, 0x04C11DB5, 0x09823B6A, 0x0D4326DF, 0x130476D4, 0x17C56B61, 0x1A864DBE, 0x1E47500B,
0x2608EDA8, 0x22C9F01D, 0x2F8AD6C2, 0x2B4BCB77, 0x350C9B7C, 0x31CD86C9, 0x3C8EA016, 0x384FBDA3,
0x4C11DB50, 0x48D0C6E5, 0x4593E03A, 0x4152FD8F, 0x5F15AD84, 0x5BD4B031, 0x569796EE, 0x52568B5B,
0x6A1936F8, 0x6ED82B4D, 0x639B0D92, 0x675A1027, 0x791D402C, 0x7DDC5D99, 0x709F7B46, 0x745E66F3,
0x9823B6A0, 0x9CE2AB15, 0x91A18DCA, 0x9560907F, 0x8B27C074, 0x8FE6DDC1, 0x82A5FB1E, 0x8664E6AB,
0xBE2B5B08, 0xBAEA46BD, 0xB7A96062, 0xB3687DD7, 0xAD2F2DDC, 0xA9EE3069, 0xA4AD16B6, 0xA06C0B03,
0xD4326DF0, 0xD0F37045, 0xDDB0569A, 0xD9714B2F, 0xC7361B24, 0xC3F70691, 0xCEB4204E, 0xCA753DFB,
0xF23A8058, 0xF6FB9DED, 0xFBB8BB32, 0xFF79A687, 0xE13EF68C, 0xE5FFEB39, 0xE8BCCDE6, 0xEC7DD053,
0x348670F5, 0x30476D40, 0x3D044B9F, 0x39C5562A, 0x27820621, 0x23431B94, 0x2E003D4B, 0x2AC120FE,
0x128E9D5D, 0x164F80E8, 0x1B0CA637, 0x1FCDBB82, 0x018AEB89, 0x054BF63C, 0x0808D0E3, 0x0CC9CD56,
0x7897ABA5, 0x7C56B610, 0x711590CF, 0x75D48D7A, 0x6B93DD71, 0x6F52C0C4, 0x6211E61B, 0x66D0FBAE,
0x5E9F460D, 0x5A5E5BB8, 0x571D7D67, 0x53DC60D2, 0x4D9B30D9, 0x495A2D6C, 0x44190BB3, 0x40D81606,
0xACA5C655, 0xA864DBE0, 0xA527FD3F, 0xA1E6E08A, 0xBFA1B081, 0xBB60AD34, 0xB6238BEB, 0xB2E2965E,
0x8AAD2BFD, 0x8E6C3648, 0x832F1097, 0x87EE0D22, 0x99A95D29, 0x9D68409C, 0x902B6643, 0x94EA7BF6,
0xE0B41D05, 0xE47500B0, 0xE936266F, 0xEDF73BDA, 0xF3B06BD1, 0xF7717664, 0xFA3250BB, 0xFEF34D0E,
0xC6BCF0AD, 0xC27DED18, 0xCF3ECBC7, 0xCBFFD672, 0xD5B88679, 0xD1799BCC, 0xDC3ABD13, 0xD8FBA0A6,
0x690CE1EA, 0x6DCDFC5F, 0x608EDA80, 0x644FC735, 0x7A08973E, 0x7EC98A8B, 0x738AAC54, 0x774BB1E1,
0x4F040C42, 0x4BC511F7, 0x46863728, 0x42472A9D, 0x5C007A96, 0x58C16723, 0x558241FC, 0x51435C49,
0x251D3ABA, 0x21DC270F, 0x2C9F01D0, 0x285E1C65, 0x36194C6E, 0x32D851DB, 0x3F9B7704, 0x3B5A6AB1,
0x0315D712, 0x07D4CAA7, 0x0A97EC78, 0x0E56F1CD, 0x1011A1C6, 0x14D0BC73, 0x19939AAC, 0x1D528719,
0xF12F574A, 0xF5EE4AFF, 0xF8AD6C20, 0xFC6C7195, 0xE22B219E, 0xE6EA3C2B, 0xEBA91AF4, 0xEF680741,
0xD727BAE2, 0xD3E6A757, 0xDEA58188, 0xDA649C3D, 0xC423CC36, 0xC0E2D183, 0xCDA1F75C, 0xC960EAE9,
0xBD3E8C1A, 0xB9FF91AF, 0xB4BCB770, 0xB07DAAC5, 0xAE3AFACE, 0xAAFBE77B, 0xA7B8C1A4, 0xA379DC11,
0x9B3661B2, 0x9FF77C07, 0x92B45AD8, 0x9675476D, 0x88321766, 0x8CF30AD3, 0x81B02C0C, 0x857131B9,
0x5D8A911F, 0x594B8CAA, 0x5408AA75, 0x50C9B7C0, 0x4E8EE7CB, 0x4A4FFA7E, 0x470CDCA1, 0x43CDC114,
0x7B827CB7, 0x7F436102, 0x720047DD, 0x76C15A68, 0x68860A63, 0x6C4717D6, 0x61043109, 0x65C52CBC,
0x119B4A4F, 0x155A57FA, 0x18197125, 0x1CD86C90, 0x029F3C9B, 0x065E212E, 0x0B1D07F1, 0x0FDC1A44,
0x3793A7E7, 0x3352BA52, 0x3E119C8D, 0x3AD08138, 0x2497D133, 0x2056CC86, 0x2D15EA59, 0x29D4F7EC,
0xC5A927BF, 0xC1683A0A, 0xCC2B1CD5, 0xC8EA0160, 0xD6AD516B, 0xD26C4CDE, 0xDF2F6A01, 0xDBEE77B4,
0xE3A1CA17, 0xE760D7A2, 0xEA23F17D, 0xEEE2ECC8, 0xF0A5BCC3, 0xF464A176, 0xF92787A9, 0xFDE69A1C,
0x89B8FCEF, 0x8D79E15A, 0x803AC785, 0x84FBDA30, 0x9ABC8A3B, 0x9E7D978E, 0x933EB151, 0x97FFACE4,
0xAFB01147, 0xAB710CF2, 0xA6322A2D, 0xA2F33798, 0xBCB46793, 0xB8757A26, 0xB5365CF9, 0xB1F7414C };
// ---------------------------------------------------------------------------
// Static Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Check 5-bit CRC.
/// </summary>
/// <param name="in">Boolean bit array.</param>
/// <param name="tcrc">Computed CRC to check.</param>
/// <returns>True, if CRC is valid, otherwise false.</returns>
bool CRC::checkFiveBit(bool* in, uint32_t tcrc)
{
assert(in != NULL);
uint32_t crc;
encodeFiveBit(in, crc);
return crc == tcrc;
}
/// <summary>
/// Encode 5-bit CRC.
/// </summary>
/// <param name="in">Boolean bit array.</param>
/// <param name="tcrc">Computed CRC.</param>
void CRC::encodeFiveBit(const bool* in, uint32_t& tcrc)
{
assert(in != NULL);
unsigned short total = 0U;
for (uint32_t i = 0U; i < 72U; i += 8U) {
uint8_t c;
Utils::bitsToByteBE(in + i, c);
total += c;
}
total %= 31U;
tcrc = total;
}
/// <summary>
/// Check 16-bit CRC-CCITT.
/// </summary>
/// <remarks>This uses polynomial 0x1021.</remarks>
/// <param name="in">Input byte array.</param>
/// <param name="length">Length of byte array.</param>
/// <returns>True, if CRC is valid, otherwise false.</returns>
bool CRC::checkCCITT162(const uint8_t *in, uint32_t length)
{
assert(in != NULL);
assert(length > 2U);
union {
uint16_t crc16;
uint8_t crc8[2U];
};
crc16 = 0U;
for (unsigned i = 0U; i < (length - 2U); i++)
crc16 = (uint16_t(crc8[0U]) << 8) ^ CCITT16_TABLE2[crc8[1U] ^ in[i]];
crc16 = ~crc16;
return crc8[0U] == in[length - 1U] && crc8[1U] == in[length - 2U];
}
/// <summary>
/// Encode 16-bit CRC-CCITT.
/// </summary>
/// <remarks>This uses polynomial 0x1021.</remarks>
/// <param name="in">Input byte array.</param>
/// <param name="length">Length of byte array.</param>
void CRC::addCCITT162(uint8_t* in, uint32_t length)
{
assert(in != NULL);
assert(length > 2U);
union {
uint16_t crc16;
uint8_t crc8[2U];
};
crc16 = 0U;
for (unsigned i = 0U; i < (length - 2U); i++)
crc16 = (uint16_t(crc8[0U]) << 8) ^ CCITT16_TABLE2[crc8[1U] ^ in[i]];
crc16 = ~crc16;
in[length - 1U] = crc8[0U];
in[length - 2U] = crc8[1U];
}
/// <summary>
/// Check 16-bit CRC-CCITT.
/// </summary>
/// <remarks>This uses polynomial 0x1189.</remarks>
/// <param name="in">Input byte array.</param>
/// <param name="length">Length of byte array.</param>
/// <returns>True, if CRC is valid, otherwise false.</returns>
bool CRC::checkCCITT161(const uint8_t *in, uint32_t length)
{
assert(in != NULL);
assert(length > 2U);
union {
uint16_t crc16;
uint8_t crc8[2U];
};
crc16 = 0xFFFFU;
for (uint32_t i = 0U; i < (length - 2U); i++)
crc16 = uint16_t(crc8[1U]) ^ CCITT16_TABLE1[crc8[0U] ^ in[i]];
crc16 = ~crc16;
return crc8[0U] == in[length - 2U] && crc8[1U] == in[length - 1U];
}
/// <summary>
/// Encode 16-bit CRC-CCITT.
/// </summary>
/// <remarks>This uses polynomial 0x1189.</remarks>
/// <param name="in">Input byte array.</param>
/// <param name="length">Length of byte array.</param>
void CRC::addCCITT161(uint8_t* in, uint32_t length)
{
assert(in != NULL);
assert(length > 2U);
union {
uint16_t crc16;
uint8_t crc8[2U];
};
crc16 = 0xFFFFU;
for (uint32_t i = 0U; i < (length - 2U); i++)
crc16 = uint16_t(crc8[1U]) ^ CCITT16_TABLE1[crc8[0U] ^ in[i]];
crc16 = ~crc16;
in[length - 2U] = crc8[0U];
in[length - 1U] = crc8[1U];
}
/// <summary>
/// Check 32-bit CRC.
/// </summary>
/// <param name="in">Input byte array.</param>
/// <param name="length">Length of byte array.</param>
/// <returns>True, if CRC is valid, otherwise false.</returns>
bool CRC::checkCRC32(const uint8_t *in, uint32_t length)
{
assert(in != NULL);
assert(length > 4U);
union {
uint32_t crc32;
uint8_t crc8[4U];
};
crc32 = 0xFFFFFFFFU;
for (uint32_t i = 0U; i < (length - 4U); i++)
crc32 = (crc32 << 8) ^ CRC32_TABLE[((crc32 >> 24) ^ in[i]) & 0xFF];
crc32 = ~crc32;
return crc8[0U] == in[length - 4U] && crc8[1U] == in[length - 3U] && crc8[2U] == in[length - 2U] && crc8[3U] == in[length - 1U];
}
/// <summary>
/// Encode 32-bit CRC.
/// </summary>
/// <param name="in">Input byte array.</param>
/// <param name="length">Length of byte array.</param>
void CRC::addCRC32(uint8_t* in, uint32_t length)
{
assert(in != NULL);
assert(length > 4U);
union {
uint32_t crc32;
uint8_t crc8[4U];
};
crc32 = 0xFFFFFFFFU;
for (uint32_t i = 0U; i < (length - 4U); i++)
crc32 = (crc32 << 8) ^ CRC32_TABLE[((crc32 >> 24) ^ in[i]) & 0xFF];
crc32 = ~crc32;
in[length - 4U] = crc8[0U];
in[length - 3U] = crc8[1U];
in[length - 2U] = crc8[2U];
in[length - 1U] = crc8[3U];
}
/// <summary>
/// Generate 8-bit CRC.
/// </summary>
/// <param name="in">Input byte array.</param>
/// <param name="length">Length of byte array.</param>
/// <returns>Calculated 8-bit CRC value.</returns>
uint8_t CRC::crc8(const uint8_t *in, uint32_t length)
{
assert(in != NULL);
uint8_t crc = 0U;
for (uint32_t i = 0U; i < length; i++)
crc = CRC8_TABLE[crc ^ in[i]];
return crc;
}
/// <summary>
/// Generate 9-bit CRC.
/// </summary>
/// <param name="in">Input byte array.</param>
/// <param name="length">Length of byte array.</param>
/// <returns>Calculated 9-bit CRC value.</returns>
uint16_t CRC::crc9(const uint8_t* in, uint32_t length)
{
assert(in != NULL);
uint16_t crc = 0U;
for (uint32_t i = 0U; i < length; i++)
crc = CRC9_TABLE[(crc ^ in[i]) & 0xFF];
return crc;
}

@ -0,0 +1,72 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2018 by Bryan Biedenkapp N2PLL
*
* 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(__CRC_H__)
#define __CRC_H__
#include "Defines.h"
namespace edac
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements various Cyclic Redundancy Check routines.
// ---------------------------------------------------------------------------
class HOST_SW_API CRC {
public:
/// <summary>Check 5-bit CRC.</summary>
static bool checkFiveBit(bool* in, uint32_t tcrc);
/// <summary>Encode 5-bit CRC.</summary>
static void encodeFiveBit(const bool* in, uint32_t& tcrc);
/// <summary>Check 16-bit CRC-CCITT.</summary>
static bool checkCCITT162(const uint8_t* in, uint32_t length);
/// <summary>Encode 16-bit CRC-CCITT.</summary>
static void addCCITT162(uint8_t* in, uint32_t length);
/// <summary>Check 16-bit CRC-CCITT.</summary>
static bool checkCCITT161(const uint8_t* in, uint32_t length);
/// <summary>Encode 16-bit CRC-CCITT.</summary>
static void addCCITT161(uint8_t* in, uint32_t length);
/// <summary>Check 32-bit CRC.</summary>
static bool checkCRC32(const uint8_t* in, uint32_t length);
/// <summary>Encode 32-bit CRC.</summary>
static void addCRC32(uint8_t* in, uint32_t length);
/// <summary>Generate 8-bit CRC.</summary>
static uint8_t crc8(const uint8_t* in, uint32_t length);
/// <summary>Generate 9-bit CRC.</summary>
static uint16_t crc9(const uint8_t* in, uint32_t length);
};
} // namespace edac
#endif // __CRC_H__

@ -0,0 +1,300 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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 "Defines.h"
#include "edac/Golay2087.h"
using namespace edac;
#include <cstdio>
#include <cassert>
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const uint32_t ENCODING_TABLE_2087[] = {
0x0000U, 0xB08EU, 0xE093U, 0x501DU, 0x70A9U, 0xC027U, 0x903AU, 0x20B4U, 0x60DCU, 0xD052U, 0x804FU, 0x30C1U,
0x1075U, 0xA0FBU, 0xF0E6U, 0x4068U, 0x7036U, 0xC0B8U, 0x90A5U, 0x202BU, 0x009FU, 0xB011U, 0xE00CU, 0x5082U,
0x10EAU, 0xA064U, 0xF079U, 0x40F7U, 0x6043U, 0xD0CDU, 0x80D0U, 0x305EU, 0xD06CU, 0x60E2U, 0x30FFU, 0x8071U,
0xA0C5U, 0x104BU, 0x4056U, 0xF0D8U, 0xB0B0U, 0x003EU, 0x5023U, 0xE0ADU, 0xC019U, 0x7097U, 0x208AU, 0x9004U,
0xA05AU, 0x10D4U, 0x40C9U, 0xF047U, 0xD0F3U, 0x607DU, 0x3060U, 0x80EEU, 0xC086U, 0x7008U, 0x2015U, 0x909BU,
0xB02FU, 0x00A1U, 0x50BCU, 0xE032U, 0x90D9U, 0x2057U, 0x704AU, 0xC0C4U, 0xE070U, 0x50FEU, 0x00E3U, 0xB06DU,
0xF005U, 0x408BU, 0x1096U, 0xA018U, 0x80ACU, 0x3022U, 0x603FU, 0xD0B1U, 0xE0EFU, 0x5061U, 0x007CU, 0xB0F2U,
0x9046U, 0x20C8U, 0x70D5U, 0xC05BU, 0x8033U, 0x30BDU, 0x60A0U, 0xD02EU, 0xF09AU, 0x4014U, 0x1009U, 0xA087U,
0x40B5U, 0xF03BU, 0xA026U, 0x10A8U, 0x301CU, 0x8092U, 0xD08FU, 0x6001U, 0x2069U, 0x90E7U, 0xC0FAU, 0x7074U,
0x50C0U, 0xE04EU, 0xB053U, 0x00DDU, 0x3083U, 0x800DU, 0xD010U, 0x609EU, 0x402AU, 0xF0A4U, 0xA0B9U, 0x1037U,
0x505FU, 0xE0D1U, 0xB0CCU, 0x0042U, 0x20F6U, 0x9078U, 0xC065U, 0x70EBU, 0xA03DU, 0x10B3U, 0x40AEU, 0xF020U,
0xD094U, 0x601AU, 0x3007U, 0x8089U, 0xC0E1U, 0x706FU, 0x2072U, 0x90FCU, 0xB048U, 0x00C6U, 0x50DBU, 0xE055U,
0xD00BU, 0x6085U, 0x3098U, 0x8016U, 0xA0A2U, 0x102CU, 0x4031U, 0xF0BFU, 0xB0D7U, 0x0059U, 0x5044U, 0xE0CAU,
0xC07EU, 0x70F0U, 0x20EDU, 0x9063U, 0x7051U, 0xC0DFU, 0x90C2U, 0x204CU, 0x00F8U, 0xB076U, 0xE06BU, 0x50E5U,
0x108DU, 0xA003U, 0xF01EU, 0x4090U, 0x6024U, 0xD0AAU, 0x80B7U, 0x3039U, 0x0067U, 0xB0E9U, 0xE0F4U, 0x507AU,
0x70CEU, 0xC040U, 0x905DU, 0x20D3U, 0x60BBU, 0xD035U, 0x8028U, 0x30A6U, 0x1012U, 0xA09CU, 0xF081U, 0x400FU,
0x30E4U, 0x806AU, 0xD077U, 0x60F9U, 0x404DU, 0xF0C3U, 0xA0DEU, 0x1050U, 0x5038U, 0xE0B6U, 0xB0ABU, 0x0025U,
0x2091U, 0x901FU, 0xC002U, 0x708CU, 0x40D2U, 0xF05CU, 0xA041U, 0x10CFU, 0x307BU, 0x80F5U, 0xD0E8U, 0x6066U,
0x200EU, 0x9080U, 0xC09DU, 0x7013U, 0x50A7U, 0xE029U, 0xB034U, 0x00BAU, 0xE088U, 0x5006U, 0x001BU, 0xB095U,
0x9021U, 0x20AFU, 0x70B2U, 0xC03CU, 0x8054U, 0x30DAU, 0x60C7U, 0xD049U, 0xF0FDU, 0x4073U, 0x106EU, 0xA0E0U,
0x90BEU, 0x2030U, 0x702DU, 0xC0A3U, 0xE017U, 0x5099U, 0x0084U, 0xB00AU, 0xF062U, 0x40ECU, 0x10F1U, 0xA07FU,
0x80CBU, 0x3045U, 0x6058U, 0xD0D6U };
const uint32_t DECODING_TABLE_1987[] = {
0x00000U, 0x00001U, 0x00002U, 0x00003U, 0x00004U, 0x00005U, 0x00006U, 0x00007U, 0x00008U, 0x00009U, 0x0000AU, 0x0000BU, 0x0000CU,
0x0000DU, 0x0000EU, 0x24020U, 0x00010U, 0x00011U, 0x00012U, 0x00013U, 0x00014U, 0x00015U, 0x00016U, 0x00017U, 0x00018U, 0x00019U,
0x0001AU, 0x0001BU, 0x0001CU, 0x0001DU, 0x48040U, 0x01480U, 0x00020U, 0x00021U, 0x00022U, 0x00023U, 0x00024U, 0x00025U, 0x00026U,
0x24008U, 0x00028U, 0x00029U, 0x0002AU, 0x24004U, 0x0002CU, 0x24002U, 0x24001U, 0x24000U, 0x00030U, 0x00031U, 0x00032U, 0x08180U,
0x00034U, 0x00C40U, 0x00036U, 0x00C42U, 0x00038U, 0x43000U, 0x0003AU, 0x43002U, 0x02902U, 0x24012U, 0x02900U, 0x24010U, 0x00040U,
0x00041U, 0x00042U, 0x00043U, 0x00044U, 0x00045U, 0x00046U, 0x00047U, 0x00048U, 0x00049U, 0x0004AU, 0x02500U, 0x0004CU, 0x0004DU,
0x48010U, 0x48011U, 0x00050U, 0x00051U, 0x00052U, 0x21200U, 0x00054U, 0x00C20U, 0x48008U, 0x48009U, 0x00058U, 0x00059U, 0x48004U,
0x48005U, 0x48002U, 0x48003U, 0x48000U, 0x48001U, 0x00060U, 0x00061U, 0x00062U, 0x00063U, 0x00064U, 0x00C10U, 0x10300U, 0x0B000U,
0x00068U, 0x00069U, 0x01880U, 0x01881U, 0x40181U, 0x40180U, 0x24041U, 0x24040U, 0x00070U, 0x00C04U, 0x00072U, 0x00C06U, 0x00C01U,
0x00C00U, 0x00C03U, 0x00C02U, 0x05204U, 0x00C0CU, 0x48024U, 0x48025U, 0x05200U, 0x00C08U, 0x48020U, 0x48021U, 0x00080U, 0x00081U,
0x00082U, 0x00083U, 0x00084U, 0x00085U, 0x00086U, 0x00087U, 0x00088U, 0x00089U, 0x0008AU, 0x50200U, 0x0008CU, 0x0A800U, 0x01411U,
0x01410U, 0x00090U, 0x00091U, 0x00092U, 0x08120U, 0x00094U, 0x00095U, 0x04A00U, 0x01408U, 0x00098U, 0x00099U, 0x01405U, 0x01404U,
0x01403U, 0x01402U, 0x01401U, 0x01400U, 0x000A0U, 0x000A1U, 0x000A2U, 0x08110U, 0x000A4U, 0x000A5U, 0x42400U, 0x42401U, 0x000A8U,
0x000A9U, 0x01840U, 0x01841U, 0x40141U, 0x40140U, 0x24081U, 0x24080U, 0x000B0U, 0x08102U, 0x08101U, 0x08100U, 0x000B4U, 0x08106U,
0x08105U, 0x08104U, 0x20A01U, 0x20A00U, 0x08109U, 0x08108U, 0x01423U, 0x01422U, 0x01421U, 0x01420U, 0x000C0U, 0x000C1U, 0x000C2U,
0x000C3U, 0x000C4U, 0x000C5U, 0x000C6U, 0x000C7U, 0x000C8U, 0x000C9U, 0x01820U, 0x01821U, 0x20600U, 0x40120U, 0x16000U, 0x16001U,
0x000D0U, 0x000D1U, 0x42801U, 0x42800U, 0x03100U, 0x18200U, 0x03102U, 0x18202U, 0x000D8U, 0x000D9U, 0x48084U, 0x01444U, 0x48082U,
0x01442U, 0x48080U, 0x01440U, 0x000E0U, 0x32000U, 0x01808U, 0x04600U, 0x40109U, 0x40108U, 0x0180CU, 0x4010AU, 0x01802U, 0x40104U,
0x01800U, 0x01801U, 0x40101U, 0x40100U, 0x01804U, 0x40102U, 0x0A408U, 0x08142U, 0x08141U, 0x08140U, 0x00C81U, 0x00C80U, 0x00C83U,
0x00C82U, 0x0A400U, 0x0A401U, 0x01810U, 0x01811U, 0x40111U, 0x40110U, 0x01814U, 0x40112U, 0x00100U, 0x00101U, 0x00102U, 0x00103U,
0x00104U, 0x00105U, 0x00106U, 0x41800U, 0x00108U, 0x00109U, 0x0010AU, 0x02440U, 0x0010CU, 0x0010DU, 0x0010EU, 0x02444U, 0x00110U,
0x00111U, 0x00112U, 0x080A0U, 0x00114U, 0x00115U, 0x00116U, 0x080A4U, 0x00118U, 0x00119U, 0x15000U, 0x15001U, 0x02822U, 0x02823U,
0x02820U, 0x02821U, 0x00120U, 0x00121U, 0x00122U, 0x08090U, 0x00124U, 0x00125U, 0x10240U, 0x10241U, 0x00128U, 0x00129U, 0x0012AU,
0x24104U, 0x09400U, 0x400C0U, 0x02810U, 0x24100U, 0x00130U, 0x08082U, 0x08081U, 0x08080U, 0x31001U, 0x31000U, 0x02808U, 0x08084U,
0x02806U, 0x0808AU, 0x02804U, 0x08088U, 0x02802U, 0x02803U, 0x02800U, 0x02801U, 0x00140U, 0x00141U, 0x00142U, 0x02408U, 0x00144U,
0x00145U, 0x10220U, 0x10221U, 0x00148U, 0x02402U, 0x02401U, 0x02400U, 0x400A1U, 0x400A0U, 0x02405U, 0x02404U, 0x00150U, 0x00151U,
0x00152U, 0x02418U, 0x03080U, 0x03081U, 0x03082U, 0x03083U, 0x09801U, 0x09800U, 0x02411U, 0x02410U, 0x48102U, 0x09804U, 0x48100U,
0x48101U, 0x00160U, 0x00161U, 0x10204U, 0x10205U, 0x10202U, 0x40088U, 0x10200U, 0x10201U, 0x40085U, 0x40084U, 0x02421U, 0x02420U,
0x40081U, 0x40080U, 0x10208U, 0x40082U, 0x41402U, 0x080C2U, 0x41400U, 0x080C0U, 0x00D01U, 0x00D00U, 0x10210U, 0x10211U, 0x40095U,
0x40094U, 0x02844U, 0x080C8U, 0x40091U, 0x40090U, 0x02840U, 0x02841U, 0x00180U, 0x00181U, 0x00182U, 0x08030U, 0x00184U, 0x14400U,
0x22201U, 0x22200U, 0x00188U, 0x00189U, 0x0018AU, 0x08038U, 0x40061U, 0x40060U, 0x40063U, 0x40062U, 0x00190U, 0x08022U, 0x08021U,
0x08020U, 0x03040U, 0x03041U, 0x08025U, 0x08024U, 0x40C00U, 0x40C01U, 0x08029U, 0x08028U, 0x2C000U, 0x2C001U, 0x01501U, 0x01500U,
0x001A0U, 0x08012U, 0x08011U, 0x08010U, 0x40049U, 0x40048U, 0x08015U, 0x08014U, 0x06200U, 0x40044U, 0x30400U, 0x08018U, 0x40041U,
0x40040U, 0x40043U, 0x40042U, 0x08003U, 0x08002U, 0x08001U, 0x08000U, 0x08007U, 0x08006U, 0x08005U, 0x08004U, 0x0800BU, 0x0800AU,
0x08009U, 0x08008U, 0x40051U, 0x40050U, 0x02880U, 0x0800CU, 0x001C0U, 0x001C1U, 0x64000U, 0x64001U, 0x03010U, 0x40028U, 0x08C00U,
0x08C01U, 0x40025U, 0x40024U, 0x02481U, 0x02480U, 0x40021U, 0x40020U, 0x40023U, 0x40022U, 0x03004U, 0x03005U, 0x08061U, 0x08060U,
0x03000U, 0x03001U, 0x03002U, 0x03003U, 0x0300CU, 0x40034U, 0x30805U, 0x30804U, 0x03008U, 0x40030U, 0x30801U, 0x30800U, 0x4000DU,
0x4000CU, 0x08051U, 0x08050U, 0x40009U, 0x40008U, 0x10280U, 0x4000AU, 0x40005U, 0x40004U, 0x01900U, 0x40006U, 0x40001U, 0x40000U,
0x40003U, 0x40002U, 0x14800U, 0x08042U, 0x08041U, 0x08040U, 0x03020U, 0x40018U, 0x08045U, 0x08044U, 0x40015U, 0x40014U, 0x08049U,
0x08048U, 0x40011U, 0x40010U, 0x40013U, 0x40012U, 0x00200U, 0x00201U, 0x00202U, 0x00203U, 0x00204U, 0x00205U, 0x00206U, 0x00207U,
0x00208U, 0x00209U, 0x0020AU, 0x50080U, 0x0020CU, 0x0020DU, 0x0020EU, 0x50084U, 0x00210U, 0x00211U, 0x00212U, 0x21040U, 0x00214U,
0x00215U, 0x04880U, 0x04881U, 0x00218U, 0x00219U, 0x0E001U, 0x0E000U, 0x0021CU, 0x0021DU, 0x04888U, 0x0E004U, 0x00220U, 0x00221U,
0x00222U, 0x00223U, 0x00224U, 0x00225U, 0x10140U, 0x10141U, 0x00228U, 0x00229U, 0x0022AU, 0x24204U, 0x12401U, 0x12400U, 0x24201U,
0x24200U, 0x00230U, 0x00231U, 0x00232U, 0x21060U, 0x2A000U, 0x2A001U, 0x2A002U, 0x2A003U, 0x20881U, 0x20880U, 0x20883U, 0x20882U,
0x05040U, 0x05041U, 0x05042U, 0x24210U, 0x00240U, 0x00241U, 0x00242U, 0x21010U, 0x00244U, 0x46000U, 0x10120U, 0x10121U, 0x00248U,
0x00249U, 0x0024AU, 0x21018U, 0x20480U, 0x20481U, 0x20482U, 0x20483U, 0x00250U, 0x21002U, 0x21001U, 0x21000U, 0x18081U, 0x18080U,
0x21005U, 0x21004U, 0x12800U, 0x12801U, 0x21009U, 0x21008U, 0x05020U, 0x05021U, 0x48200U, 0x48201U, 0x00260U, 0x00261U, 0x10104U,
0x04480U, 0x10102U, 0x10103U, 0x10100U, 0x10101U, 0x62002U, 0x62003U, 0x62000U, 0x62001U, 0x05010U, 0x05011U, 0x10108U, 0x10109U,
0x0500CU, 0x21022U, 0x21021U, 0x21020U, 0x05008U, 0x00E00U, 0x10110U, 0x10111U, 0x05004U, 0x05005U, 0x05006U, 0x21028U, 0x05000U,
0x05001U, 0x05002U, 0x05003U, 0x00280U, 0x00281U, 0x00282U, 0x50008U, 0x00284U, 0x00285U, 0x04810U, 0x22100U, 0x00288U, 0x50002U,
0x50001U, 0x50000U, 0x20440U, 0x20441U, 0x50005U, 0x50004U, 0x00290U, 0x00291U, 0x04804U, 0x04805U, 0x04802U, 0x18040U, 0x04800U,
0x04801U, 0x20821U, 0x20820U, 0x50011U, 0x50010U, 0x0480AU, 0x01602U, 0x04808U, 0x01600U, 0x002A0U, 0x002A1U, 0x04441U, 0x04440U,
0x002A4U, 0x002A5U, 0x04830U, 0x04444U, 0x06100U, 0x20810U, 0x50021U, 0x50020U, 0x06104U, 0x20814U, 0x50025U, 0x50024U, 0x20809U,
0x20808U, 0x13000U, 0x08300U, 0x04822U, 0x2080CU, 0x04820U, 0x04821U, 0x20801U, 0x20800U, 0x20803U, 0x20802U, 0x20805U, 0x20804U,
0x04828U, 0x20806U, 0x002C0U, 0x002C1U, 0x04421U, 0x04420U, 0x20408U, 0x18010U, 0x2040AU, 0x18012U, 0x20404U, 0x20405U, 0x50041U,
0x50040U, 0x20400U, 0x20401U, 0x20402U, 0x20403U, 0x18005U, 0x18004U, 0x21081U, 0x21080U, 0x18001U, 0x18000U, 0x04840U, 0x18002U,
0x20414U, 0x1800CU, 0x21089U, 0x21088U, 0x20410U, 0x18008U, 0x20412U, 0x1800AU, 0x04403U, 0x04402U, 0x04401U, 0x04400U, 0x10182U,
0x04406U, 0x10180U, 0x04404U, 0x01A02U, 0x0440AU, 0x01A00U, 0x04408U, 0x20420U, 0x40300U, 0x20422U, 0x40302U, 0x04413U, 0x04412U,
0x04411U, 0x04410U, 0x18021U, 0x18020U, 0x10190U, 0x18022U, 0x20841U, 0x20840U, 0x01A10U, 0x20842U, 0x05080U, 0x05081U, 0x05082U,
0x05083U, 0x00300U, 0x00301U, 0x00302U, 0x00303U, 0x00304U, 0x00305U, 0x10060U, 0x22080U, 0x00308U, 0x00309U, 0x28800U, 0x28801U,
0x44402U, 0x44403U, 0x44400U, 0x44401U, 0x00310U, 0x00311U, 0x10C01U, 0x10C00U, 0x00314U, 0x00315U, 0x10070U, 0x10C04U, 0x00318U,
0x00319U, 0x28810U, 0x10C08U, 0x44412U, 0x00000U, 0x44410U, 0x44411U, 0x00320U, 0x60400U, 0x10044U, 0x10045U, 0x10042U, 0x0C800U,
0x10040U, 0x10041U, 0x06080U, 0x06081U, 0x06082U, 0x06083U, 0x1004AU, 0x0C808U, 0x10048U, 0x10049U, 0x58008U, 0x08282U, 0x08281U,
0x08280U, 0x10052U, 0x0C810U, 0x10050U, 0x10051U, 0x58000U, 0x58001U, 0x58002U, 0x08288U, 0x02A02U, 0x02A03U, 0x02A00U, 0x02A01U,
0x00340U, 0x00341U, 0x10024U, 0x10025U, 0x10022U, 0x10023U, 0x10020U, 0x10021U, 0x34001U, 0x34000U, 0x02601U, 0x02600U, 0x1002AU,
0x34004U, 0x10028U, 0x10029U, 0x0C400U, 0x0C401U, 0x21101U, 0x21100U, 0x60800U, 0x60801U, 0x10030U, 0x10031U, 0x0C408U, 0x34010U,
0x21109U, 0x21108U, 0x60808U, 0x60809U, 0x10038U, 0x28420U, 0x10006U, 0x10007U, 0x10004U, 0x10005U, 0x10002U, 0x10003U, 0x10000U,
0x10001U, 0x1000EU, 0x40284U, 0x1000CU, 0x1000DU, 0x1000AU, 0x40280U, 0x10008U, 0x10009U, 0x10016U, 0x10017U, 0x10014U, 0x10015U,
0x10012U, 0x10013U, 0x10010U, 0x10011U, 0x05104U, 0x44802U, 0x44801U, 0x44800U, 0x05100U, 0x05101U, 0x10018U, 0x28400U, 0x00380U,
0x00381U, 0x22005U, 0x22004U, 0x22003U, 0x22002U, 0x22001U, 0x22000U, 0x06020U, 0x06021U, 0x50101U, 0x50100U, 0x11800U, 0x11801U,
0x22009U, 0x22008U, 0x45001U, 0x45000U, 0x08221U, 0x08220U, 0x04902U, 0x22012U, 0x04900U, 0x22010U, 0x06030U, 0x45008U, 0x08229U,
0x08228U, 0x11810U, 0x11811U, 0x04908U, 0x22018U, 0x06008U, 0x06009U, 0x08211U, 0x08210U, 0x100C2U, 0x22022U, 0x100C0U, 0x22020U,
0x06000U, 0x06001U, 0x06002U, 0x06003U, 0x06004U, 0x40240U, 0x06006U, 0x40242U, 0x08203U, 0x08202U, 0x08201U, 0x08200U, 0x08207U,
0x08206U, 0x08205U, 0x08204U, 0x06010U, 0x20900U, 0x08209U, 0x08208U, 0x61002U, 0x20904U, 0x61000U, 0x61001U, 0x29020U, 0x29021U,
0x100A4U, 0x22044U, 0x100A2U, 0x22042U, 0x100A0U, 0x22040U, 0x20504U, 0x40224U, 0x0D005U, 0x0D004U, 0x20500U, 0x40220U, 0x0D001U,
0x0D000U, 0x03204U, 0x18104U, 0x08261U, 0x08260U, 0x03200U, 0x18100U, 0x03202U, 0x18102U, 0x11421U, 0x11420U, 0x00000U, 0x11422U,
0x03208U, 0x18108U, 0x0D011U, 0x0D010U, 0x29000U, 0x29001U, 0x10084U, 0x04500U, 0x10082U, 0x40208U, 0x10080U, 0x10081U, 0x06040U,
0x40204U, 0x06042U, 0x40206U, 0x40201U, 0x40200U, 0x10088U, 0x40202U, 0x29010U, 0x08242U, 0x08241U, 0x08240U, 0x10092U, 0x40218U,
0x10090U, 0x10091U, 0x11401U, 0x11400U, 0x11403U, 0x11402U, 0x40211U, 0x40210U, 0x10098U, 0x40212U, 0x00400U, 0x00401U, 0x00402U,
0x00403U, 0x00404U, 0x00405U, 0x00406U, 0x00407U, 0x00408U, 0x00409U, 0x0040AU, 0x02140U, 0x0040CU, 0x0040DU, 0x01091U, 0x01090U,
0x00410U, 0x00411U, 0x00412U, 0x00413U, 0x00414U, 0x00860U, 0x01089U, 0x01088U, 0x00418U, 0x38000U, 0x01085U, 0x01084U, 0x01083U,
0x01082U, 0x01081U, 0x01080U, 0x00420U, 0x00421U, 0x00422U, 0x00423U, 0x00424U, 0x00850U, 0x42080U, 0x42081U, 0x00428U, 0x00429U,
0x48801U, 0x48800U, 0x09100U, 0x12200U, 0x24401U, 0x24400U, 0x00430U, 0x00844U, 0x00432U, 0x00846U, 0x00841U, 0x00840U, 0x1C000U,
0x00842U, 0x00438U, 0x0084CU, 0x010A5U, 0x010A4U, 0x00849U, 0x00848U, 0x010A1U, 0x010A0U, 0x00440U, 0x00441U, 0x00442U, 0x02108U,
0x00444U, 0x00830U, 0x70001U, 0x70000U, 0x00448U, 0x02102U, 0x02101U, 0x02100U, 0x20280U, 0x20281U, 0x02105U, 0x02104U, 0x00450U,
0x00824U, 0x00452U, 0x00826U, 0x00821U, 0x00820U, 0x00823U, 0x00822U, 0x24802U, 0x02112U, 0x24800U, 0x02110U, 0x00829U, 0x00828U,
0x48400U, 0x010C0U, 0x00460U, 0x00814U, 0x04281U, 0x04280U, 0x00811U, 0x00810U, 0x00813U, 0x00812U, 0x54000U, 0x54001U, 0x02121U,
0x02120U, 0x00819U, 0x00818U, 0x0081BU, 0x0081AU, 0x00805U, 0x00804U, 0x41100U, 0x00806U, 0x00801U, 0x00800U, 0x00803U, 0x00802U,
0x0A080U, 0x0080CU, 0x0A082U, 0x0080EU, 0x00809U, 0x00808U, 0x0080BU, 0x0080AU, 0x00480U, 0x00481U, 0x00482U, 0x00483U, 0x00484U,
0x14100U, 0x42020U, 0x01018U, 0x00488U, 0x00489U, 0x01015U, 0x01014U, 0x20240U, 0x01012U, 0x01011U, 0x01010U, 0x00490U, 0x00491U,
0x0100DU, 0x0100CU, 0x0100BU, 0x0100AU, 0x01009U, 0x01008U, 0x40900U, 0x01006U, 0x01005U, 0x01004U, 0x01003U, 0x01002U, 0x01001U,
0x01000U, 0x004A0U, 0x004A1U, 0x42004U, 0x04240U, 0x42002U, 0x42003U, 0x42000U, 0x42001U, 0x30102U, 0x30103U, 0x30100U, 0x30101U,
0x4200AU, 0x01032U, 0x42008U, 0x01030U, 0x25000U, 0x25001U, 0x08501U, 0x08500U, 0x008C1U, 0x008C0U, 0x42010U, 0x01028U, 0x0A040U,
0x0A041U, 0x01025U, 0x01024U, 0x01023U, 0x01022U, 0x01021U, 0x01020U, 0x004C0U, 0x49000U, 0x04221U, 0x04220U, 0x20208U, 0x20209U,
0x08900U, 0x08901U, 0x20204U, 0x20205U, 0x02181U, 0x02180U, 0x20200U, 0x20201U, 0x20202U, 0x01050U, 0x0A028U, 0x008A4U, 0x0104DU,
0x0104CU, 0x008A1U, 0x008A0U, 0x01049U, 0x01048U, 0x0A020U, 0x0A021U, 0x01045U, 0x01044U, 0x20210U, 0x01042U, 0x01041U, 0x01040U,
0x04203U, 0x04202U, 0x04201U, 0x04200U, 0x00891U, 0x00890U, 0x42040U, 0x04204U, 0x0A010U, 0x0A011U, 0x01C00U, 0x04208U, 0x20220U,
0x40500U, 0x20222U, 0x40502U, 0x0A008U, 0x00884U, 0x04211U, 0x04210U, 0x00881U, 0x00880U, 0x00883U, 0x00882U, 0x0A000U, 0x0A001U,
0x0A002U, 0x0A003U, 0x0A004U, 0x00888U, 0x01061U, 0x01060U, 0x00500U, 0x00501U, 0x00502U, 0x02048U, 0x00504U, 0x14080U, 0x00506U,
0x14082U, 0x00508U, 0x02042U, 0x02041U, 0x02040U, 0x09020U, 0x09021U, 0x44200U, 0x02044U, 0x00510U, 0x00511U, 0x10A01U, 0x10A00U,
0x4A001U, 0x4A000U, 0x4A003U, 0x4A002U, 0x40880U, 0x40881U, 0x02051U, 0x02050U, 0x40884U, 0x01182U, 0x01181U, 0x01180U, 0x00520U,
0x60200U, 0x00522U, 0x60202U, 0x09008U, 0x09009U, 0x0900AU, 0x0900BU, 0x09004U, 0x09005U, 0x30080U, 0x02060U, 0x09000U, 0x09001U,
0x09002U, 0x09003U, 0x41042U, 0x08482U, 0x41040U, 0x08480U, 0x00941U, 0x00940U, 0x41044U, 0x00942U, 0x09014U, 0x09015U, 0x02C04U,
0x08488U, 0x09010U, 0x09011U, 0x02C00U, 0x02C01U, 0x00540U, 0x0200AU, 0x02009U, 0x02008U, 0x08882U, 0x0200EU, 0x08880U, 0x0200CU,
0x02003U, 0x02002U, 0x02001U, 0x02000U, 0x02007U, 0x02006U, 0x02005U, 0x02004U, 0x0C200U, 0x0C201U, 0x41020U, 0x02018U, 0x00921U,
0x00920U, 0x41024U, 0x00922U, 0x02013U, 0x02012U, 0x02011U, 0x02010U, 0x02017U, 0x02016U, 0x02015U, 0x02014U, 0x41012U, 0x0202AU,
0x41010U, 0x02028U, 0x26000U, 0x00910U, 0x10600U, 0x10601U, 0x02023U, 0x02022U, 0x02021U, 0x02020U, 0x09040U, 0x40480U, 0x02025U,
0x02024U, 0x41002U, 0x00904U, 0x41000U, 0x41001U, 0x00901U, 0x00900U, 0x41004U, 0x00902U, 0x4100AU, 0x02032U, 0x41008U, 0x02030U,
0x00909U, 0x00908U, 0x28201U, 0x28200U, 0x00580U, 0x14004U, 0x00582U, 0x14006U, 0x14001U, 0x14000U, 0x08840U, 0x14002U, 0x40810U,
0x40811U, 0x30020U, 0x020C0U, 0x14009U, 0x14008U, 0x01111U, 0x01110U, 0x40808U, 0x40809U, 0x08421U, 0x08420U, 0x14011U, 0x14010U,
0x01109U, 0x01108U, 0x40800U, 0x40801U, 0x40802U, 0x01104U, 0x40804U, 0x01102U, 0x01101U, 0x01100U, 0x03801U, 0x03800U, 0x30008U,
0x08410U, 0x14021U, 0x14020U, 0x42100U, 0x42101U, 0x30002U, 0x30003U, 0x30000U, 0x30001U, 0x09080U, 0x40440U, 0x30004U, 0x30005U,
0x08403U, 0x08402U, 0x08401U, 0x08400U, 0x08407U, 0x08406U, 0x08405U, 0x08404U, 0x40820U, 0x40821U, 0x30010U, 0x08408U, 0x40824U,
0x01122U, 0x01121U, 0x01120U, 0x08806U, 0x0208AU, 0x08804U, 0x02088U, 0x08802U, 0x14040U, 0x08800U, 0x08801U, 0x02083U, 0x02082U,
0x02081U, 0x02080U, 0x20300U, 0x40420U, 0x08808U, 0x02084U, 0x03404U, 0x03405U, 0x08814U, 0x02098U, 0x03400U, 0x03401U, 0x08810U,
0x08811U, 0x40840U, 0x40841U, 0x02091U, 0x02090U, 0x40844U, 0x01142U, 0x01141U, 0x01140U, 0x04303U, 0x04302U, 0x04301U, 0x04300U,
0x40409U, 0x40408U, 0x08820U, 0x08821U, 0x40405U, 0x40404U, 0x30040U, 0x020A0U, 0x40401U, 0x40400U, 0x40403U, 0x40402U, 0x41082U,
0x08442U, 0x41080U, 0x08440U, 0x00981U, 0x00980U, 0x41084U, 0x00982U, 0x0A100U, 0x11200U, 0x0A102U, 0x11202U, 0x40411U, 0x40410U,
0x40413U, 0x40412U, 0x00600U, 0x00601U, 0x00602U, 0x00603U, 0x00604U, 0x00605U, 0x00606U, 0x00607U, 0x00608U, 0x05800U, 0x0060AU,
0x05802U, 0x200C0U, 0x12020U, 0x44100U, 0x44101U, 0x00610U, 0x00611U, 0x10901U, 0x10900U, 0x51000U, 0x51001U, 0x51002U, 0x10904U,
0x00618U, 0x05810U, 0x01285U, 0x01284U, 0x51008U, 0x01282U, 0x01281U, 0x01280U, 0x00620U, 0x60100U, 0x040C1U, 0x040C0U, 0x12009U,
0x12008U, 0x21800U, 0x21801U, 0x12005U, 0x12004U, 0x12007U, 0x12006U, 0x12001U, 0x12000U, 0x12003U, 0x12002U, 0x00630U, 0x00A44U,
0x040D1U, 0x040D0U, 0x00A41U, 0x00A40U, 0x21810U, 0x00A42U, 0x12015U, 0x12014U, 0x00000U, 0x12016U, 0x12011U, 0x12010U, 0x12013U,
0x12012U, 0x00640U, 0x00641U, 0x040A1U, 0x040A0U, 0x20088U, 0x20089U, 0x2008AU, 0x040A4U, 0x20084U, 0x20085U, 0x19000U, 0x02300U,
0x20080U, 0x20081U, 0x20082U, 0x20083U, 0x0C100U, 0x0C101U, 0x21401U, 0x21400U, 0x00A21U, 0x00A20U, 0x00A23U, 0x00A22U, 0x20094U,
0x20095U, 0x19010U, 0x21408U, 0x20090U, 0x20091U, 0x20092U, 0x28120U, 0x04083U, 0x04082U, 0x04081U, 0x04080U, 0x00A11U, 0x00A10U,
0x10500U, 0x04084U, 0x200A4U, 0x0408AU, 0x04089U, 0x04088U, 0x200A0U, 0x12040U, 0x200A2U, 0x12042U, 0x00A05U, 0x00A04U, 0x04091U,
0x04090U, 0x00A01U, 0x00A00U, 0x00A03U, 0x00A02U, 0x05404U, 0x00A0CU, 0x28105U, 0x28104U, 0x05400U, 0x00A08U, 0x28101U, 0x28100U,
0x00680U, 0x00681U, 0x04061U, 0x04060U, 0x20048U, 0x20049U, 0x2004AU, 0x04064U, 0x20044U, 0x20045U, 0x50401U, 0x50400U, 0x20040U,
0x20041U, 0x20042U, 0x01210U, 0x68002U, 0x68003U, 0x68000U, 0x68001U, 0x04C02U, 0x0120AU, 0x04C00U, 0x01208U, 0x20054U, 0x01206U,
0x01205U, 0x01204U, 0x20050U, 0x01202U, 0x01201U, 0x01200U, 0x18800U, 0x04042U, 0x04041U, 0x04040U, 0x42202U, 0x04046U, 0x42200U,
0x04044U, 0x20064U, 0x0404AU, 0x04049U, 0x04048U, 0x20060U, 0x12080U, 0x20062U, 0x12082U, 0x18810U, 0x04052U, 0x04051U, 0x04050U,
0x4C009U, 0x4C008U, 0x42210U, 0x04054U, 0x20C01U, 0x20C00U, 0x20C03U, 0x20C02U, 0x4C001U, 0x4C000U, 0x01221U, 0x01220U, 0x2000CU,
0x04022U, 0x04021U, 0x04020U, 0x20008U, 0x20009U, 0x2000AU, 0x04024U, 0x20004U, 0x20005U, 0x20006U, 0x04028U, 0x20000U, 0x20001U,
0x20002U, 0x20003U, 0x2001CU, 0x04032U, 0x04031U, 0x04030U, 0x20018U, 0x18400U, 0x2001AU, 0x18402U, 0x20014U, 0x20015U, 0x20016U,
0x01244U, 0x20010U, 0x20011U, 0x20012U, 0x01240U, 0x04003U, 0x04002U, 0x04001U, 0x04000U, 0x20028U, 0x04006U, 0x04005U, 0x04004U,
0x20024U, 0x0400AU, 0x04009U, 0x04008U, 0x20020U, 0x20021U, 0x20022U, 0x0400CU, 0x04013U, 0x04012U, 0x04011U, 0x04010U, 0x00A81U,
0x00A80U, 0x04015U, 0x04014U, 0x0A200U, 0x11100U, 0x04019U, 0x04018U, 0x20030U, 0x20031U, 0x50800U, 0x50801U, 0x00700U, 0x60020U,
0x10811U, 0x10810U, 0x4400AU, 0x60024U, 0x44008U, 0x44009U, 0x44006U, 0x02242U, 0x44004U, 0x02240U, 0x44002U, 0x44003U, 0x44000U,
0x44001U, 0x0C040U, 0x10802U, 0x10801U, 0x10800U, 0x0C044U, 0x10806U, 0x10805U, 0x10804U, 0x23000U, 0x23001U, 0x10809U, 0x10808U,
0x44012U, 0x44013U, 0x44010U, 0x44011U, 0x60001U, 0x60000U, 0x60003U, 0x60002U, 0x60005U, 0x60004U, 0x10440U, 0x10441U, 0x60009U,
0x60008U, 0x44024U, 0x6000AU, 0x09200U, 0x12100U, 0x44020U, 0x44021U, 0x60011U, 0x60010U, 0x10821U, 0x10820U, 0x07003U, 0x07002U,
0x07001U, 0x07000U, 0x23020U, 0x60018U, 0x28045U, 0x28044U, 0x09210U, 0x28042U, 0x28041U, 0x28040U, 0x0C010U, 0x0C011U, 0x02209U,
0x02208U, 0x10422U, 0x10423U, 0x10420U, 0x10421U, 0x02203U, 0x02202U, 0x02201U, 0x02200U, 0x20180U, 0x20181U, 0x44040U, 0x02204U,
0x0C000U, 0x0C001U, 0x0C002U, 0x10840U, 0x0C004U, 0x0C005U, 0x0C006U, 0x10844U, 0x0C008U, 0x0C009U, 0x02211U, 0x02210U, 0x0C00CU,
0x28022U, 0x28021U, 0x28020U, 0x60041U, 0x60040U, 0x10404U, 0x04180U, 0x10402U, 0x10403U, 0x10400U, 0x10401U, 0x02223U, 0x02222U,
0x02221U, 0x02220U, 0x1040AU, 0x28012U, 0x10408U, 0x28010U, 0x0C020U, 0x0C021U, 0x41200U, 0x41201U, 0x00B01U, 0x00B00U, 0x10410U,
0x28008U, 0x11081U, 0x11080U, 0x28005U, 0x28004U, 0x28003U, 0x28002U, 0x28001U, 0x28000U, 0x52040U, 0x14204U, 0x22405U, 0x22404U,
0x14201U, 0x14200U, 0x22401U, 0x22400U, 0x20144U, 0x20145U, 0x44084U, 0x022C0U, 0x20140U, 0x20141U, 0x44080U, 0x44081U, 0x40A08U,
0x10882U, 0x10881U, 0x10880U, 0x14211U, 0x14210U, 0x1A008U, 0x10884U, 0x40A00U, 0x40A01U, 0x40A02U, 0x01304U, 0x1A002U, 0x01302U,
0x1A000U, 0x01300U, 0x60081U, 0x60080U, 0x04141U, 0x04140U, 0x60085U, 0x60084U, 0x104C0U, 0x04144U, 0x06400U, 0x06401U, 0x30200U,
0x30201U, 0x06404U, 0x40640U, 0x30204U, 0x30205U, 0x08603U, 0x08602U, 0x08601U, 0x08600U, 0x00000U, 0x08606U, 0x08605U, 0x08604U,
0x11041U, 0x11040U, 0x30210U, 0x11042U, 0x11045U, 0x11044U, 0x1A020U, 0x01320U, 0x52000U, 0x52001U, 0x04121U, 0x04120U, 0x20108U,
0x20109U, 0x08A00U, 0x08A01U, 0x20104U, 0x20105U, 0x02281U, 0x02280U, 0x20100U, 0x20101U, 0x20102U, 0x20103U, 0x0C080U, 0x0C081U,
0x0C082U, 0x04130U, 0x0C084U, 0x06808U, 0x08A10U, 0x08A11U, 0x11021U, 0x11020U, 0x11023U, 0x11022U, 0x20110U, 0x06800U, 0x20112U,
0x06802U, 0x04103U, 0x04102U, 0x04101U, 0x04100U, 0x10482U, 0x04106U, 0x10480U, 0x04104U, 0x11011U, 0x11010U, 0x04109U, 0x04108U,
0x20120U, 0x40600U, 0x20122U, 0x40602U, 0x11009U, 0x11008U, 0x22800U, 0x04110U, 0x1100DU, 0x1100CU, 0x22804U, 0x04114U, 0x11001U,
0x11000U, 0x11003U, 0x11002U, 0x11005U, 0x11004U, 0x28081U, 0x28080U };
#define X18 0x00040000 /* vector representation of X^{18} */
#define X11 0x00000800 /* vector representation of X^{11} */
#define MASK8 0xfffff800 /* auxiliary vector for testing */
#define GENPOL 0x00000c75 /* generator polinomial, g(x) */
// ---------------------------------------------------------------------------
// Static Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Decode Golay (20,8,7) FEC.
/// </summary>
/// <param name="data">Golay FEC encoded data byte array</param>
/// <returns></returns>
uint8_t Golay2087::decode(const uint8_t* data)
{
assert(data != NULL);
uint32_t code = (data[0U] << 11) + (data[1U] << 3) + (data[2U] >> 5);
uint32_t syndrome = getSyndrome1987(code);
uint32_t error_pattern = DECODING_TABLE_1987[syndrome];
if (error_pattern != 0x00U)
code ^= error_pattern;
return code >> 11;
}
/// <summary>
/// Encode Golay (20,8,7) FEC.
/// </summary>
/// <param name="data">Data to encode with Golay FEC.</param>
void Golay2087::encode(uint8_t* data)
{
assert(data != NULL);
uint32_t value = data[0U];
uint32_t cksum = ENCODING_TABLE_2087[value];
data[1U] = cksum & 0xFFU;
data[2U] = cksum >> 8;
}
// ---------------------------------------------------------------------------
// Private Static Class Members
// ---------------------------------------------------------------------------
/// <summary>
///
/// </summary>
/// <remarks>
/// Compute the syndrome corresponding to the given pattern, i.e., the
/// remainder after dividing the pattern (when considering it as the vector
/// representation of a polynomial) by the generator polynomial, GENPOL.
/// In the program this pattern has several meanings: (1) pattern = infomation
/// bits, when constructing the encoding table; (2) pattern = error pattern,
/// when constructing the decoding table; and (3) pattern = received vector, to
/// obtain its syndrome in decoding.
/// </remarks>
/// <param name="pattern"></param>
/// <returns></returns>
uint32_t Golay2087::getSyndrome1987(uint32_t pattern)
{
uint32_t aux = X18;
if (pattern >= X11) {
while (pattern & MASK8) {
while (!(aux & pattern))
aux = aux >> 1;
pattern ^= (aux / X11) * GENPOL;
}
}
return pattern;
}

@ -0,0 +1,55 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 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.
*/
#if !defined(__GOLAY2087_H__)
#define __GOLAY2087_H__
#include "Defines.h"
namespace edac
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements Golay (20,8,7) forward error correction.
// ---------------------------------------------------------------------------
class HOST_SW_API Golay2087 {
public:
/// <summary>Decode Golay (20,8,7) FEC.</summary>
static uint8_t decode(const uint8_t* data);
/// <summary>Encode Golay (20,8,7) FEC.</summary>
static void encode(uint8_t* data);
private:
/// <summary></summary>
static uint32_t getSyndrome1987(uint32_t pattern);
};
} // namespace edac
#endif // __GOLAY2087_H__

File diff suppressed because it is too large Load Diff

@ -0,0 +1,68 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2010,2016 by Jonathan Naylor G4KLX
* Copyright (C) 2017 by Bryan Biedenkapp N2PLL
*
* 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(__GOLAY24128_H__)
#define __GOLAY24128_H__
#include "Defines.h"
namespace edac
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements Golay (23,12,7) and Golay (24,12,8) forward error
// correction.
// ---------------------------------------------------------------------------
class HOST_SW_API Golay24128 {
public:
/// <summary>Decode Golay (23,12,7) FEC.</summary>
static uint32_t decode23127(uint32_t code);
/// <summary>Decode Golay (24,12,8) FEC.</summary>
static uint32_t decode24128(uint32_t code);
/// <summary>Decode Golay (24,12,8) FEC.</summary>
static uint32_t decode24128(uint8_t* bytes);
/// <summary>Decode Golay (24,12,8) FEC.</summary>
static void decode24128(uint8_t* data, const uint8_t* raw, uint32_t msglen);
/// <summary>Encode Golay (23,12,7) FEC.</summary>
static uint32_t encode23127(uint32_t data);
/// <summary>Encode Golay (24,12,8) FEC.</summary>
static uint32_t encode24128(uint32_t data);
/// <summary>Encode Golay (24,12,8) FEC.</summary>
static void encode24128(uint8_t* data, const uint8_t* raw, uint32_t msglen);
private:
/// <summary></summary>
static uint32_t getSyndrome23127(uint32_t pattern);
};
} // namespace edac
#endif // __GOLAY24128_H__

@ -0,0 +1,412 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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 "edac/Hamming.h"
using namespace edac;
#include <cstdio>
#include <cassert>
// ---------------------------------------------------------------------------
// Static Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Decode Hamming (15,11,3).
/// </summary>
/// <param name="d">Boolean bit array.</param>
/// <returns>True, if bit errors are detected, otherwise false.</returns>
bool Hamming::decode15113_1(bool* d)
{
assert(d != NULL);
// Calculate the parity it should have
bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6];
bool c1 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[7] ^ d[8] ^ d[9];
bool c2 = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[8] ^ d[10];
bool c3 = d[0] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[9] ^ d[10];
unsigned char n = 0U;
n |= (c0 != d[11]) ? 0x01U : 0x00U;
n |= (c1 != d[12]) ? 0x02U : 0x00U;
n |= (c2 != d[13]) ? 0x04U : 0x00U;
n |= (c3 != d[14]) ? 0x08U : 0x00U;
switch (n) {
// Parity bit errors
case 0x01U: d[11] = !d[11]; return true;
case 0x02U: d[12] = !d[12]; return true;
case 0x04U: d[13] = !d[13]; return true;
case 0x08U: d[14] = !d[14]; return true;
// Data bit errors
case 0x0FU: d[0] = !d[0]; return true;
case 0x07U: d[1] = !d[1]; return true;
case 0x0BU: d[2] = !d[2]; return true;
case 0x03U: d[3] = !d[3]; return true;
case 0x0DU: d[4] = !d[4]; return true;
case 0x05U: d[5] = !d[5]; return true;
case 0x09U: d[6] = !d[6]; return true;
case 0x0EU: d[7] = !d[7]; return true;
case 0x06U: d[8] = !d[8]; return true;
case 0x0AU: d[9] = !d[9]; return true;
case 0x0CU: d[10] = !d[10]; return true;
// No bit errors
default: return false;
}
}
/// <summary>
/// Encode Hamming (15,11,3).
/// </summary>
/// <param name="d">Boolean bit array.</param>
void Hamming::encode15113_1(bool* d)
{
assert(d != NULL);
// Calculate the checksum this row should have
d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6];
d[12] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[7] ^ d[8] ^ d[9];
d[13] = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[8] ^ d[10];
d[14] = d[0] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[9] ^ d[10];
}
/// <summary>
/// Decode Hamming (15,11,3).
/// </summary>
/// <param name="d">Boolean bit array.</param>
/// <returns>True, if bit errors are detected, otherwise false.</returns>
bool Hamming::decode15113_2(bool* d)
{
assert(d != NULL);
// Calculate the checksum this row should have
bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8];
bool c1 = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9];
bool c2 = d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[7] ^ d[9] ^ d[10];
bool c3 = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[10];
unsigned char n = 0x00U;
n |= (c0 != d[11]) ? 0x01U : 0x00U;
n |= (c1 != d[12]) ? 0x02U : 0x00U;
n |= (c2 != d[13]) ? 0x04U : 0x00U;
n |= (c3 != d[14]) ? 0x08U : 0x00U;
switch (n) {
// Parity bit errors
case 0x01U: d[11] = !d[11]; return true;
case 0x02U: d[12] = !d[12]; return true;
case 0x04U: d[13] = !d[13]; return true;
case 0x08U: d[14] = !d[14]; return true;
// Data bit errors
case 0x09U: d[0] = !d[0]; return true;
case 0x0BU: d[1] = !d[1]; return true;
case 0x0FU: d[2] = !d[2]; return true;
case 0x07U: d[3] = !d[3]; return true;
case 0x0EU: d[4] = !d[4]; return true;
case 0x05U: d[5] = !d[5]; return true;
case 0x0AU: d[6] = !d[6]; return true;
case 0x0DU: d[7] = !d[7]; return true;
case 0x03U: d[8] = !d[8]; return true;
case 0x06U: d[9] = !d[9]; return true;
case 0x0CU: d[10] = !d[10]; return true;
// No bit errors
default: return false;
}
}
/// <summary>
/// Encode Hamming (15,11,3).
/// </summary>
/// <param name="d">Boolean bit array.</param>
void Hamming::encode15113_2(bool* d)
{
assert(d != NULL);
// Calculate the checksum this row should have
d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8];
d[12] = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9];
d[13] = d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[7] ^ d[9] ^ d[10];
d[14] = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[10];
}
/// <summary>
/// Decode Hamming (13,9,3).
/// </summary>
/// <param name="d">Boolean bit array.</param>
/// <returns>True, if bit errors are detected, otherwise false.</returns>
bool Hamming::decode1393(bool* d)
{
assert(d != NULL);
// Calculate the checksum this column should have
bool c0 = d[0] ^ d[1] ^ d[3] ^ d[5] ^ d[6];
bool c1 = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7];
bool c2 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8];
bool c3 = d[0] ^ d[2] ^ d[4] ^ d[5] ^ d[8];
unsigned char n = 0x00U;
n |= (c0 != d[9]) ? 0x01U : 0x00U;
n |= (c1 != d[10]) ? 0x02U : 0x00U;
n |= (c2 != d[11]) ? 0x04U : 0x00U;
n |= (c3 != d[12]) ? 0x08U : 0x00U;
switch (n) {
// Parity bit errors
case 0x01U: d[9] = !d[9]; return true;
case 0x02U: d[10] = !d[10]; return true;
case 0x04U: d[11] = !d[11]; return true;
case 0x08U: d[12] = !d[12]; return true;
// Data bit erros
case 0x0FU: d[0] = !d[0]; return true;
case 0x07U: d[1] = !d[1]; return true;
case 0x0EU: d[2] = !d[2]; return true;
case 0x05U: d[3] = !d[3]; return true;
case 0x0AU: d[4] = !d[4]; return true;
case 0x0DU: d[5] = !d[5]; return true;
case 0x03U: d[6] = !d[6]; return true;
case 0x06U: d[7] = !d[7]; return true;
case 0x0CU: d[8] = !d[8]; return true;
// No bit errors
default: return false;
}
}
/// <summary>
/// Encode Hamming (13,9,3).
/// </summary>
/// <param name="d">Boolean bit array.</param>
void Hamming::encode1393(bool* d)
{
assert(d != NULL);
// Calculate the checksum this column should have
d[9] = d[0] ^ d[1] ^ d[3] ^ d[5] ^ d[6];
d[10] = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7];
d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8];
d[12] = d[0] ^ d[2] ^ d[4] ^ d[5] ^ d[8];
}
/// <summary>
/// Decode Hamming (10,6,3).
/// </summary>
/// <param name="d">Boolean bit array.</param>
/// <returns>True, if bit errors are detected, otherwise false.</returns>
bool Hamming::decode1063(bool* d)
{
assert(d != NULL);
// Calculate the checksum this column should have
bool c0 = d[0] ^ d[1] ^ d[2] ^ d[5];
bool c1 = d[0] ^ d[1] ^ d[3] ^ d[5];
bool c2 = d[0] ^ d[2] ^ d[3] ^ d[4];
bool c3 = d[1] ^ d[2] ^ d[3] ^ d[4];
unsigned char n = 0x00U;
n |= (c0 != d[6]) ? 0x01U : 0x00U;
n |= (c1 != d[7]) ? 0x02U : 0x00U;
n |= (c2 != d[8]) ? 0x04U : 0x00U;
n |= (c3 != d[9]) ? 0x08U : 0x00U;
switch (n) {
// Parity bit errors
case 0x01U: d[6] = !d[6]; return true;
case 0x02U: d[7] = !d[7]; return true;
case 0x04U: d[8] = !d[8]; return true;
case 0x08U: d[9] = !d[9]; return true;
// Data bit erros
case 0x07U: d[0] = !d[0]; return true;
case 0x0BU: d[1] = !d[1]; return true;
case 0x0DU: d[2] = !d[2]; return true;
case 0x0EU: d[3] = !d[3]; return true;
case 0x0CU: d[4] = !d[4]; return true;
case 0x03U: d[5] = !d[5]; return true;
// No bit errors
default: return false;
}
}
/// <summary>
/// Encode Hamming (10,6,3).
/// </summary>
/// <param name="d">Boolean bit array.</param>
void Hamming::encode1063(bool* d)
{
assert(d != NULL);
// Calculate the checksum this column should have
d[6] = d[0] ^ d[1] ^ d[2] ^ d[5];
d[7] = d[0] ^ d[1] ^ d[3] ^ d[5];
d[8] = d[0] ^ d[2] ^ d[3] ^ d[4];
d[9] = d[1] ^ d[2] ^ d[3] ^ d[4];
}
/// <summary>
/// Decode Hamming (16,11,4).
/// </summary>
/// <param name="d">Boolean bit array.</param>
/// <returns>True, if bit errors are detected or no bit errors, otherwise false if unrecoverable errors are detected.</returns>
bool Hamming::decode16114(bool* d)
{
assert(d != NULL);
// Calculate the checksum this column should have
bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8];
bool c1 = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9];
bool c2 = d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[7] ^ d[9] ^ d[10];
bool c3 = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[10];
bool c4 = d[0] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[9] ^ d[10];
// Compare these with the actual bits
unsigned char n = 0x00U;
n |= (c0 != d[11]) ? 0x01U : 0x00U;
n |= (c1 != d[12]) ? 0x02U : 0x00U;
n |= (c2 != d[13]) ? 0x04U : 0x00U;
n |= (c3 != d[14]) ? 0x08U : 0x00U;
n |= (c4 != d[15]) ? 0x10U : 0x00U;
switch (n) {
// Parity bit errors
case 0x01U: d[11] = !d[11]; return true;
case 0x02U: d[12] = !d[12]; return true;
case 0x04U: d[13] = !d[13]; return true;
case 0x08U: d[14] = !d[14]; return true;
case 0x10U: d[15] = !d[15]; return true;
// Data bit errors
case 0x19U: d[0] = !d[0]; return true;
case 0x0BU: d[1] = !d[1]; return true;
case 0x1FU: d[2] = !d[2]; return true;
case 0x07U: d[3] = !d[3]; return true;
case 0x0EU: d[4] = !d[4]; return true;
case 0x15U: d[5] = !d[5]; return true;
case 0x1AU: d[6] = !d[6]; return true;
case 0x0DU: d[7] = !d[7]; return true;
case 0x13U: d[8] = !d[8]; return true;
case 0x16U: d[9] = !d[9]; return true;
case 0x1CU: d[10] = !d[10]; return true;
// No bit errors
case 0x00U: return true;
// Unrecoverable errors
default: return false;
}
}
/// <summary>
/// Encode Hamming (10,6,3).
/// </summary>
/// <param name="d">Boolean bit array.</param>
void Hamming::encode16114(bool* d)
{
assert(d != NULL);
d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8];
d[12] = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9];
d[13] = d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[7] ^ d[9] ^ d[10];
d[14] = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[10];
d[15] = d[0] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[9] ^ d[10];
}
/// <summary>
/// Decode Hamming (17,12,3).
/// </summary>
/// <param name="d">Boolean bit array.</param>
/// <returns>True, if bit errors are detected or no bit errors, otherwise false if unrecoverable errors are detected.</returns>
bool Hamming::decode17123(bool* d)
{
assert(d != NULL);
// Calculate the checksum this column should have
bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[6] ^ d[7] ^ d[9];
bool c1 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[7] ^ d[8] ^ d[10];
bool c2 = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[8] ^ d[9] ^ d[11];
bool c3 = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[10];
bool c4 = d[0] ^ d[1] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[11];
// Compare these with the actual bits
unsigned char n = 0x00U;
n |= (c0 != d[12]) ? 0x01U : 0x00U;
n |= (c1 != d[13]) ? 0x02U : 0x00U;
n |= (c2 != d[14]) ? 0x04U : 0x00U;
n |= (c3 != d[15]) ? 0x08U : 0x00U;
n |= (c4 != d[16]) ? 0x10U : 0x00U;
switch (n) {
// Parity bit errors
case 0x01U: d[12] = !d[12]; return true;
case 0x02U: d[13] = !d[13]; return true;
case 0x04U: d[14] = !d[14]; return true;
case 0x08U: d[15] = !d[15]; return true;
case 0x10U: d[16] = !d[16]; return true;
// Data bit errors
case 0x1BU: d[0] = !d[0]; return true;
case 0x1FU: d[1] = !d[1]; return true;
case 0x17U: d[2] = !d[2]; return true;
case 0x07U: d[3] = !d[3]; return true;
case 0x0EU: d[4] = !d[4]; return true;
case 0x1CU: d[5] = !d[5]; return true;
case 0x11U: d[6] = !d[6]; return true;
case 0x0BU: d[7] = !d[7]; return true;
case 0x16U: d[8] = !d[8]; return true;
case 0x05U: d[9] = !d[9]; return true;
case 0x0AU: d[10] = !d[10]; return true;
case 0x14U: d[11] = !d[11]; return true;
// No bit errors
case 0x00U: return true;
// Unrecoverable errors
default: return false;
}
}
/// <summary>
/// Encode Hamming (17,12,3).
/// </summary>
/// <param name="d">Boolean bit array.</param>
void Hamming::encode17123(bool* d)
{
assert(d != NULL);
d[12] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[6] ^ d[7] ^ d[9];
d[13] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[7] ^ d[8] ^ d[10];
d[14] = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[8] ^ d[9] ^ d[11];
d[15] = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[10];
d[16] = d[0] ^ d[1] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[11];
}

@ -0,0 +1,77 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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(__HAMMING_H__)
#define __HAMMING_H__
#include "Defines.h"
namespace edac
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements Hamming (15,11,3), (13,9,3), (10,6,3), (16,11,4) and
// (17, 12, 3) forward error correction.
// ---------------------------------------------------------------------------
class HOST_SW_API Hamming {
public:
/// <summary>Decode Hamming (15,11,3).</summary>
static bool decode15113_1(bool* d);
/// <summary>Encode Hamming (15,11,3).</summary>
static void encode15113_1(bool* d);
/// <summary>Decode Hamming (15,11,3).</summary>
static bool decode15113_2(bool* d);
/// <summary>Encode Hamming (15,11,3).</summary>
static void encode15113_2(bool* d);
/// <summary>Decode Hamming (13,9,3).</summary>
static bool decode1393(bool* d);
/// <summary>Encode Hamming (13,9,3).</summary>
static void encode1393(bool* d);
/// <summary>Decode Hamming (10,6,3).</summary>
static bool decode1063(bool* d);
/// <summary>Encode Hamming (10,6,3).</summary>
static void encode1063(bool* d);
/// <summary>Decode Hamming (16,11,4).</summary>
static bool decode16114(bool* d);
/// <summary>Encode Hamming (16,11,4).</summary>
static void encode16114(bool* d);
/// <summary>Decode Hamming (17,12,3).</summary>
static bool decode17123(bool* d);
/// <summary>Encode Hamming (17,12,3).</summary>
static void encode17123(bool* d);
};
} // namespace edac
#endif // __HAMMING_H__

@ -0,0 +1,152 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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 "Defines.h"
#include "edac/QR1676.h"
using namespace edac;
#include <cstdio>
#include <cassert>
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const uint32_t ENCODING_TABLE_1676[] = {
0x0000U, 0x0273U, 0x04E5U, 0x0696U, 0x09C9U, 0x0BBAU, 0x0D2CU, 0x0F5FU, 0x11E2U, 0x1391U, 0x1507U, 0x1774U,
0x182BU, 0x1A58U, 0x1CCEU, 0x1EBDU, 0x21B7U, 0x23C4U, 0x2552U, 0x2721U, 0x287EU, 0x2A0DU, 0x2C9BU, 0x2EE8U,
0x3055U, 0x3226U, 0x34B0U, 0x36C3U, 0x399CU, 0x3BEFU, 0x3D79U, 0x3F0AU, 0x411EU, 0x436DU, 0x45FBU, 0x4788U,
0x48D7U, 0x4AA4U, 0x4C32U, 0x4E41U, 0x50FCU, 0x528FU, 0x5419U, 0x566AU, 0x5935U, 0x5B46U, 0x5DD0U, 0x5FA3U,
0x60A9U, 0x62DAU, 0x644CU, 0x663FU, 0x6960U, 0x6B13U, 0x6D85U, 0x6FF6U, 0x714BU, 0x7338U, 0x75AEU, 0x77DDU,
0x7882U, 0x7AF1U, 0x7C67U, 0x7E14U, 0x804FU, 0x823CU, 0x84AAU, 0x86D9U, 0x8986U, 0x8BF5U, 0x8D63U, 0x8F10U,
0x91ADU, 0x93DEU, 0x9548U, 0x973BU, 0x9864U, 0x9A17U, 0x9C81U, 0x9EF2U, 0xA1F8U, 0xA38BU, 0xA51DU, 0xA76EU,
0xA831U, 0xAA42U, 0xACD4U, 0xAEA7U, 0xB01AU, 0xB269U, 0xB4FFU, 0xB68CU, 0xB9D3U, 0xBBA0U, 0xBD36U, 0xBF45U,
0xC151U, 0xC322U, 0xC5B4U, 0xC7C7U, 0xC898U, 0xCAEBU, 0xCC7DU, 0xCE0EU, 0xD0B3U, 0xD2C0U, 0xD456U, 0xD625U,
0xD97AU, 0xDB09U, 0xDD9FU, 0xDFECU, 0xE0E6U, 0xE295U, 0xE403U, 0xE670U, 0xE92FU, 0xEB5CU, 0xEDCAU, 0xEFB9U,
0xF104U, 0xF377U, 0xF5E1U, 0xF792U, 0xF8CDU, 0xFABEU, 0xFC28U, 0xFE5BU };
const uint32_t DECODING_TABLE_1576[] = {
0x0000U, 0x0001U, 0x0002U, 0x0003U, 0x0004U, 0x0005U, 0x0006U, 0x4020U, 0x0008U, 0x0009U, 0x000AU, 0x000BU,
0x000CU, 0x000DU, 0x2081U, 0x2080U, 0x0010U, 0x0011U, 0x0012U, 0x0013U, 0x0014U, 0x0C00U, 0x0016U, 0x0C02U,
0x0018U, 0x0120U, 0x001AU, 0x0122U, 0x4102U, 0x0124U, 0x4100U, 0x4101U, 0x0020U, 0x0021U, 0x0022U, 0x4004U,
0x0024U, 0x4002U, 0x4001U, 0x4000U, 0x0028U, 0x0110U, 0x1800U, 0x1801U, 0x002CU, 0x400AU, 0x4009U, 0x4008U,
0x0030U, 0x0108U, 0x0240U, 0x0241U, 0x0034U, 0x4012U, 0x4011U, 0x4010U, 0x0101U, 0x0100U, 0x0103U, 0x0102U,
0x0105U, 0x0104U, 0x1401U, 0x1400U, 0x0040U, 0x0041U, 0x0042U, 0x0043U, 0x0044U, 0x0045U, 0x0046U, 0x4060U,
0x0048U, 0x0049U, 0x0301U, 0x0300U, 0x004CU, 0x1600U, 0x0305U, 0x0304U, 0x0050U, 0x0051U, 0x0220U, 0x0221U,
0x3000U, 0x4200U, 0x3002U, 0x4202U, 0x0058U, 0x1082U, 0x1081U, 0x1080U, 0x3008U, 0x4208U, 0x2820U, 0x1084U,
0x0060U, 0x0061U, 0x0210U, 0x0211U, 0x0480U, 0x0481U, 0x4041U, 0x4040U, 0x0068U, 0x2402U, 0x2401U, 0x2400U,
0x0488U, 0x3100U, 0x2810U, 0x2404U, 0x0202U, 0x0880U, 0x0200U, 0x0201U, 0x0206U, 0x0884U, 0x0204U, 0x0205U,
0x0141U, 0x0140U, 0x0208U, 0x0209U, 0x2802U, 0x0144U, 0x2800U, 0x2801U, 0x0080U, 0x0081U, 0x0082U, 0x0A00U,
0x0084U, 0x0085U, 0x2009U, 0x2008U, 0x0088U, 0x0089U, 0x2005U, 0x2004U, 0x2003U, 0x2002U, 0x2001U, 0x2000U,
0x0090U, 0x0091U, 0x0092U, 0x1048U, 0x0602U, 0x0C80U, 0x0600U, 0x0601U, 0x0098U, 0x1042U, 0x1041U, 0x1040U,
0x2013U, 0x2012U, 0x2011U, 0x2010U, 0x00A0U, 0x00A1U, 0x00A2U, 0x4084U, 0x0440U, 0x0441U, 0x4081U, 0x4080U,
0x6000U, 0x1200U, 0x6002U, 0x1202U, 0x6004U, 0x2022U, 0x2021U, 0x2020U, 0x0841U, 0x0840U, 0x2104U, 0x0842U,
0x2102U, 0x0844U, 0x2100U, 0x2101U, 0x0181U, 0x0180U, 0x0B00U, 0x0182U, 0x5040U, 0x0184U, 0x2108U, 0x2030U,
0x00C0U, 0x00C1U, 0x4401U, 0x4400U, 0x0420U, 0x0421U, 0x0422U, 0x4404U, 0x0900U, 0x0901U, 0x1011U, 0x1010U,
0x0904U, 0x2042U, 0x2041U, 0x2040U, 0x0821U, 0x0820U, 0x1009U, 0x1008U, 0x4802U, 0x0824U, 0x4800U, 0x4801U,
0x1003U, 0x1002U, 0x1001U, 0x1000U, 0x0501U, 0x0500U, 0x1005U, 0x1004U, 0x0404U, 0x0810U, 0x1100U, 0x1101U,
0x0400U, 0x0401U, 0x0402U, 0x0403U, 0x040CU, 0x0818U, 0x1108U, 0x1030U, 0x0408U, 0x0409U, 0x040AU, 0x2060U,
0x0801U, 0x0800U, 0x0280U, 0x0802U, 0x0410U, 0x0804U, 0x0412U, 0x0806U, 0x0809U, 0x0808U, 0x1021U, 0x1020U,
0x5000U, 0x2200U, 0x5002U, 0x2202U };
#define X14 0x00004000 /* vector representation of X^{14} */
#define X8 0x00000100 /* vector representation of X^{8} */
#define MASK7 0xffffff00 /* auxiliary vector for testing */
#define GENPOL 0x00000139 /* generator polinomial, g(x) */
// ---------------------------------------------------------------------------
// Static Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Decode QR (16,7,6) FEC.
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
uint8_t QR1676::decode(const uint8_t* data)
{
assert(data != NULL);
uint32_t code = (data[0U] << 7) + (data[1U] >> 1);
uint32_t syndrome = getSyndrome1576(code);
uint32_t error_pattern = DECODING_TABLE_1576[syndrome];
code ^= error_pattern;
return code >> 7;
}
/// <summary>
/// Encode QR (16,7,6) FEC.
/// </summary>
/// <remarks>Compute the EMB against a precomputed list of correct words.</remarks>
/// <param name="data"></param>
void QR1676::encode(uint8_t* data)
{
assert(data != NULL);
uint32_t value = (data[0U] >> 1) & 0x7FU;
uint32_t cksum = ENCODING_TABLE_1676[value];
data[0U] = cksum >> 8;
data[1U] = cksum & 0xFFU;
}
// ---------------------------------------------------------------------------
// Private Static Class Members
// ---------------------------------------------------------------------------
/// <summary>
///
/// </summary>
/// <remarks>
/// Compute the syndrome corresponding to the given pattern, i.e., the
/// remainder after dividing the pattern (when considering it as the vector
/// representation of a polynomial) by the generator polynomial, GENPOL.
/// In the program this pattern has several meanings: (1) pattern = infomation
/// bits, when constructing the encoding table; (2) pattern = error pattern,
/// when constructing the decoding table; and (3) pattern = received vector, to
/// obtain its syndrome in decoding.
/// </remarks>
/// <param name="pattern"></param>
/// <returns></returns>
uint32_t QR1676::getSyndrome1576(uint32_t pattern)
{
uint32_t aux = X14;
if (pattern >= X8) {
while (pattern & MASK7) {
while (!(aux & pattern))
aux = aux >> 1;
pattern ^= (aux / X8) * GENPOL;
}
}
return pattern;
}

@ -0,0 +1,55 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 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.
*/
#if !defined(__QR1676_H__)
#define __QR1676_H__
#include "Defines.h"
namespace edac
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements Quadratic residue (16,7,6) forward error correction.
// ---------------------------------------------------------------------------
class HOST_SW_API QR1676 {
public:
/// <summary>Decode QR (16,7,6) FEC.</summary>
static uint8_t decode(const uint8_t* data);
/// <summary>Encode QR (16,7,6) FEC.</summary>
static void encode(uint8_t* data);
private:
/// <summary></summary>
static uint32_t getSyndrome1576(uint32_t pattern);
};
} // namespace edac
#endif // __QR1676_H__

@ -0,0 +1,170 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 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 "Defines.h"
#include "edac/RS129.h"
using namespace edac;
#include <cstdio>
#include <cassert>
#include <cstring>
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const uint32_t NPAR = 3U;
/* Maximum degree of various polynomials. */
const uint32_t MAXDEG = NPAR * 2U;
/* Generator Polynomial */
const uint8_t POLY[] = { 64U, 56U, 14U, 1U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U };
const uint8_t EXP_TABLE[] = {
0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U, 0x1DU, 0x3AU, 0x74U, 0xE8U, 0xCDU, 0x87U, 0x13U, 0x26U,
0x4CU, 0x98U, 0x2DU, 0x5AU, 0xB4U, 0x75U, 0xEAU, 0xC9U, 0x8FU, 0x03U, 0x06U, 0x0CU, 0x18U, 0x30U, 0x60U, 0xC0U,
0x9DU, 0x27U, 0x4EU, 0x9CU, 0x25U, 0x4AU, 0x94U, 0x35U, 0x6AU, 0xD4U, 0xB5U, 0x77U, 0xEEU, 0xC1U, 0x9FU, 0x23U,
0x46U, 0x8CU, 0x05U, 0x0AU, 0x14U, 0x28U, 0x50U, 0xA0U, 0x5DU, 0xBAU, 0x69U, 0xD2U, 0xB9U, 0x6FU, 0xDEU, 0xA1U,
0x5FU, 0xBEU, 0x61U, 0xC2U, 0x99U, 0x2FU, 0x5EU, 0xBCU, 0x65U, 0xCAU, 0x89U, 0x0FU, 0x1EU, 0x3CU, 0x78U, 0xF0U,
0xFDU, 0xE7U, 0xD3U, 0xBBU, 0x6BU, 0xD6U, 0xB1U, 0x7FU, 0xFEU, 0xE1U, 0xDFU, 0xA3U, 0x5BU, 0xB6U, 0x71U, 0xE2U,
0xD9U, 0xAFU, 0x43U, 0x86U, 0x11U, 0x22U, 0x44U, 0x88U, 0x0DU, 0x1AU, 0x34U, 0x68U, 0xD0U, 0xBDU, 0x67U, 0xCEU,
0x81U, 0x1FU, 0x3EU, 0x7CU, 0xF8U, 0xEDU, 0xC7U, 0x93U, 0x3BU, 0x76U, 0xECU, 0xC5U, 0x97U, 0x33U, 0x66U, 0xCCU,
0x85U, 0x17U, 0x2EU, 0x5CU, 0xB8U, 0x6DU, 0xDAU, 0xA9U, 0x4FU, 0x9EU, 0x21U, 0x42U, 0x84U, 0x15U, 0x2AU, 0x54U,
0xA8U, 0x4DU, 0x9AU, 0x29U, 0x52U, 0xA4U, 0x55U, 0xAAU, 0x49U, 0x92U, 0x39U, 0x72U, 0xE4U, 0xD5U, 0xB7U, 0x73U,
0xE6U, 0xD1U, 0xBFU, 0x63U, 0xC6U, 0x91U, 0x3FU, 0x7EU, 0xFCU, 0xE5U, 0xD7U, 0xB3U, 0x7BU, 0xF6U, 0xF1U, 0xFFU,
0xE3U, 0xDBU, 0xABU, 0x4BU, 0x96U, 0x31U, 0x62U, 0xC4U, 0x95U, 0x37U, 0x6EU, 0xDCU, 0xA5U, 0x57U, 0xAEU, 0x41U,
0x82U, 0x19U, 0x32U, 0x64U, 0xC8U, 0x8DU, 0x07U, 0x0EU, 0x1CU, 0x38U, 0x70U, 0xE0U, 0xDDU, 0xA7U, 0x53U, 0xA6U,
0x51U, 0xA2U, 0x59U, 0xB2U, 0x79U, 0xF2U, 0xF9U, 0xEFU, 0xC3U, 0x9BU, 0x2BU, 0x56U, 0xACU, 0x45U, 0x8AU, 0x09U,
0x12U, 0x24U, 0x48U, 0x90U, 0x3DU, 0x7AU, 0xF4U, 0xF5U, 0xF7U, 0xF3U, 0xFBU, 0xEBU, 0xCBU, 0x8BU, 0x0BU, 0x16U,
0x2CU, 0x58U, 0xB0U, 0x7DU, 0xFAU, 0xE9U, 0xCFU, 0x83U, 0x1BU, 0x36U, 0x6CU, 0xD8U, 0xADU, 0x47U, 0x8EU, 0x01U,
0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U, 0x1DU, 0x3AU, 0x74U, 0xE8U, 0xCDU, 0x87U, 0x13U, 0x26U, 0x4CU,
0x98U, 0x2DU, 0x5AU, 0xB4U, 0x75U, 0xEAU, 0xC9U, 0x8FU, 0x03U, 0x06U, 0x0CU, 0x18U, 0x30U, 0x60U, 0xC0U, 0x9DU,
0x27U, 0x4EU, 0x9CU, 0x25U, 0x4AU, 0x94U, 0x35U, 0x6AU, 0xD4U, 0xB5U, 0x77U, 0xEEU, 0xC1U, 0x9FU, 0x23U, 0x46U,
0x8CU, 0x05U, 0x0AU, 0x14U, 0x28U, 0x50U, 0xA0U, 0x5DU, 0xBAU, 0x69U, 0xD2U, 0xB9U, 0x6FU, 0xDEU, 0xA1U, 0x5FU,
0xBEU, 0x61U, 0xC2U, 0x99U, 0x2FU, 0x5EU, 0xBCU, 0x65U, 0xCAU, 0x89U, 0x0FU, 0x1EU, 0x3CU, 0x78U, 0xF0U, 0xFDU,
0xE7U, 0xD3U, 0xBBU, 0x6BU, 0xD6U, 0xB1U, 0x7FU, 0xFEU, 0xE1U, 0xDFU, 0xA3U, 0x5BU, 0xB6U, 0x71U, 0xE2U, 0xD9U,
0xAFU, 0x43U, 0x86U, 0x11U, 0x22U, 0x44U, 0x88U, 0x0DU, 0x1AU, 0x34U, 0x68U, 0xD0U, 0xBDU, 0x67U, 0xCEU, 0x81U,
0x1FU, 0x3EU, 0x7CU, 0xF8U, 0xEDU, 0xC7U, 0x93U, 0x3BU, 0x76U, 0xECU, 0xC5U, 0x97U, 0x33U, 0x66U, 0xCCU, 0x85U,
0x17U, 0x2EU, 0x5CU, 0xB8U, 0x6DU, 0xDAU, 0xA9U, 0x4FU, 0x9EU, 0x21U, 0x42U, 0x84U, 0x15U, 0x2AU, 0x54U, 0xA8U,
0x4DU, 0x9AU, 0x29U, 0x52U, 0xA4U, 0x55U, 0xAAU, 0x49U, 0x92U, 0x39U, 0x72U, 0xE4U, 0xD5U, 0xB7U, 0x73U, 0xE6U,
0xD1U, 0xBFU, 0x63U, 0xC6U, 0x91U, 0x3FU, 0x7EU, 0xFCU, 0xE5U, 0xD7U, 0xB3U, 0x7BU, 0xF6U, 0xF1U, 0xFFU, 0xE3U,
0xDBU, 0xABU, 0x4BU, 0x96U, 0x31U, 0x62U, 0xC4U, 0x95U, 0x37U, 0x6EU, 0xDCU, 0xA5U, 0x57U, 0xAEU, 0x41U, 0x82U,
0x19U, 0x32U, 0x64U, 0xC8U, 0x8DU, 0x07U, 0x0EU, 0x1CU, 0x38U, 0x70U, 0xE0U, 0xDDU, 0xA7U, 0x53U, 0xA6U, 0x51U,
0xA2U, 0x59U, 0xB2U, 0x79U, 0xF2U, 0xF9U, 0xEFU, 0xC3U, 0x9BU, 0x2BU, 0x56U, 0xACU, 0x45U, 0x8AU, 0x09U, 0x12U,
0x24U, 0x48U, 0x90U, 0x3DU, 0x7AU, 0xF4U, 0xF5U, 0xF7U, 0xF3U, 0xFBU, 0xEBU, 0xCBU, 0x8BU, 0x0BU, 0x16U, 0x2CU,
0x58U, 0xB0U, 0x7DU, 0xFAU, 0xE9U, 0xCFU, 0x83U, 0x1BU, 0x36U, 0x6CU, 0xD8U, 0xADU, 0x47U, 0x8EU, 0x01U, 0x00U };
const uint8_t LOG_TABLE[] = {
0x00U, 0x00U, 0x01U, 0x19U, 0x02U, 0x32U, 0x1AU, 0xC6U, 0x03U, 0xDFU, 0x33U, 0xEEU, 0x1BU, 0x68U, 0xC7U, 0x4BU,
0x04U, 0x64U, 0xE0U, 0x0EU, 0x34U, 0x8DU, 0xEFU, 0x81U, 0x1CU, 0xC1U, 0x69U, 0xF8U, 0xC8U, 0x08U, 0x4CU, 0x71U,
0x05U, 0x8AU, 0x65U, 0x2FU, 0xE1U, 0x24U, 0x0FU, 0x21U, 0x35U, 0x93U, 0x8EU, 0xDAU, 0xF0U, 0x12U, 0x82U, 0x45U,
0x1DU, 0xB5U, 0xC2U, 0x7DU, 0x6AU, 0x27U, 0xF9U, 0xB9U, 0xC9U, 0x9AU, 0x09U, 0x78U, 0x4DU, 0xE4U, 0x72U, 0xA6U,
0x06U, 0xBFU, 0x8BU, 0x62U, 0x66U, 0xDDU, 0x30U, 0xFDU, 0xE2U, 0x98U, 0x25U, 0xB3U, 0x10U, 0x91U, 0x22U, 0x88U,
0x36U, 0xD0U, 0x94U, 0xCEU, 0x8FU, 0x96U, 0xDBU, 0xBDU, 0xF1U, 0xD2U, 0x13U, 0x5CU, 0x83U, 0x38U, 0x46U, 0x40U,
0x1EU, 0x42U, 0xB6U, 0xA3U, 0xC3U, 0x48U, 0x7EU, 0x6EU, 0x6BU, 0x3AU, 0x28U, 0x54U, 0xFAU, 0x85U, 0xBAU, 0x3DU,
0xCAU, 0x5EU, 0x9BU, 0x9FU, 0x0AU, 0x15U, 0x79U, 0x2BU, 0x4EU, 0xD4U, 0xE5U, 0xACU, 0x73U, 0xF3U, 0xA7U, 0x57U,
0x07U, 0x70U, 0xC0U, 0xF7U, 0x8CU, 0x80U, 0x63U, 0x0DU, 0x67U, 0x4AU, 0xDEU, 0xEDU, 0x31U, 0xC5U, 0xFEU, 0x18U,
0xE3U, 0xA5U, 0x99U, 0x77U, 0x26U, 0xB8U, 0xB4U, 0x7CU, 0x11U, 0x44U, 0x92U, 0xD9U, 0x23U, 0x20U, 0x89U, 0x2EU,
0x37U, 0x3FU, 0xD1U, 0x5BU, 0x95U, 0xBCU, 0xCFU, 0xCDU, 0x90U, 0x87U, 0x97U, 0xB2U, 0xDCU, 0xFCU, 0xBEU, 0x61U,
0xF2U, 0x56U, 0xD3U, 0xABU, 0x14U, 0x2AU, 0x5DU, 0x9EU, 0x84U, 0x3CU, 0x39U, 0x53U, 0x47U, 0x6DU, 0x41U, 0xA2U,
0x1FU, 0x2DU, 0x43U, 0xD8U, 0xB7U, 0x7BU, 0xA4U, 0x76U, 0xC4U, 0x17U, 0x49U, 0xECU, 0x7FU, 0x0CU, 0x6FU, 0xF6U,
0x6CU, 0xA1U, 0x3BU, 0x52U, 0x29U, 0x9DU, 0x55U, 0xAAU, 0xFBU, 0x60U, 0x86U, 0xB1U, 0xBBU, 0xCCU, 0x3EU, 0x5AU,
0xCBU, 0x59U, 0x5FU, 0xB0U, 0x9CU, 0xA9U, 0xA0U, 0x51U, 0x0BU, 0xF5U, 0x16U, 0xEBU, 0x7AU, 0x75U, 0x2CU, 0xD7U,
0x4FU, 0xAEU, 0xD5U, 0xE9U, 0xE6U, 0xE7U, 0xADU, 0xE8U, 0x74U, 0xD6U, 0xF4U, 0xEAU, 0xA8U, 0x50U, 0x58U, 0xAFU };
// ---------------------------------------------------------------------------
// Static Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Check RS (12,9) FEC.
/// </summary>
/// <param name="in"></param>
/// <returns></returns>
bool RS129::check(const uint8_t* in)
{
assert(in != NULL);
uint8_t parity[4U];
encode(in, 9U, parity);
return in[9U] == parity[2U] && in[10U] == parity[1U] && in[11U] == parity[0U];
}
/// <summary>
/// Encode RS (12,9) FEC.
/// </summary>
/// <remarks>
/// Simulate a LFSR with generator polynomial for n byte RS code.
/// Pass in a pointer to the data array, and amount of data.
///
/// The parity bytes are deposited into parity.
/// </remarks>
/// <param name="msg"></param>
/// <param name="nbytes"></param>
/// <param name="parity"></param>
void RS129::encode(const uint8_t* msg, uint32_t nbytes, uint8_t* parity)
{
assert(msg != NULL);
assert(parity != NULL);
for (uint32_t i = 0U; i < NPAR + 1U; i++)
parity[i] = 0x00U;
for (uint32_t i = 0U; i < nbytes; i++) {
uint8_t dbyte = msg[i] ^ parity[NPAR - 1U];
for (int j = NPAR - 1; j > 0; j--)
parity[j] = parity[j - 1] ^ gmult(POLY[j], dbyte);
parity[0] = gmult(POLY[0], dbyte);
}
}
// ---------------------------------------------------------------------------
// Private Static Class Members
// ---------------------------------------------------------------------------
/// <summary>
///
/// </summary>
/// <remarks>Multiplication using logarithms.</remarks>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
uint8_t RS129::gmult(uint8_t a, uint8_t b)
{
if (a == 0U || b == 0U)
return 0U;
uint32_t i = LOG_TABLE[a];
uint32_t j = LOG_TABLE[b];
return EXP_TABLE[i + j];
}

@ -0,0 +1,56 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 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.
*/
#if !defined(__RS129_H__)
#define __RS129_H__
#include "Defines.h"
namespace edac
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements Reed-Solomon (12,9) forward error correction.
// ---------------------------------------------------------------------------
class HOST_SW_API RS129 {
public:
/// <summary>Check RS (12,9) FEC.</summary>
static bool check(const uint8_t* in);
/// <summary>Encode RS (12,9) FEC.</summary>
static void encode(const uint8_t* msg, uint32_t nbytes, uint8_t* parity);
private:
/// <summary></summary>
static uint8_t gmult(uint8_t a, uint8_t b);
};
} // namespace edac
#endif // __RS129_H__

@ -0,0 +1,576 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2017-2018 by Bryan Biedenkapp N2PLL
*
* 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 "Defines.h"
#include "edac/RS634717.h"
using namespace edac;
#include <cstdio>
#include <cassert>
#include <cstring>
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
const uint8_t ENCODE_MATRIX[12U][24U] = {
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 062, 044, 003, 025, 014, 016, 027, 003, 053, 004, 036, 047 },
{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 011, 012, 011, 011, 016, 064, 067, 055, 001, 076, 026, 073 },
{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 003, 001, 005, 075, 014, 006, 020, 044, 066, 006, 070, 066 },
{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 021, 070, 027, 045, 016, 067, 023, 064, 073, 033, 044, 021 },
{ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 030, 022, 003, 075, 015, 015, 033, 015, 051, 003, 053, 050 },
{ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 001, 041, 027, 056, 076, 064, 021, 053, 004, 025, 001, 012 },
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 061, 076, 021, 055, 076, 001, 063, 035, 030, 013, 064, 070 },
{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 024, 022, 071, 056, 021, 035, 073, 042, 057, 074, 043, 076 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 072, 042, 005, 020, 043, 047, 033, 056, 001, 016, 013, 076 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 072, 014, 065, 054, 035, 025, 041, 016, 015, 040, 071, 026 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 073, 065, 036, 061, 042, 022, 017, 004, 044, 020, 025, 005 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 071, 005, 055, 003, 071, 034, 060, 011, 074, 002, 041, 050 } };
const uint8_t ENCODE_MATRIX_24169[16U][24U] = {
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 051, 045, 067, 015, 064, 067, 052, 012 },
{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 057, 025, 063, 073, 071, 022, 040, 015 },
{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 005, 001, 031, 004, 016, 054, 025, 076 },
{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 073, 007, 047, 014, 041, 077, 047, 011 },
{ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 075, 015, 051, 051, 017, 067, 017, 057 },
{ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 020, 032, 014, 042, 075, 042, 070, 054 },
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 002, 075, 043, 005, 001, 040, 012, 064 },
{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 024, 074, 015, 072, 024, 026, 074, 061 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 042, 064, 007, 022, 061, 020, 040, 065 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 032, 032, 055, 041, 057, 066, 021, 077 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 065, 036, 025, 007, 050, 016, 040, 051 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 064, 006, 054, 032, 076, 046, 014, 036 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 062, 063, 074, 070, 005, 027, 037, 046 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 055, 043, 034, 071, 057, 076, 050, 064 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 024, 023, 023, 005, 050, 070, 042, 023 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 067, 075, 045, 060, 057, 024, 006, 026 } };
const uint8_t ENCODE_MATRIX_362017[20U][36U] = {
{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 074, 037, 034, 006, 002, 007, 044, 064, 026, 014, 026, 044, 054, 013, 077, 005 },
{ 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 004, 017, 050, 024, 011, 005, 030, 057, 033, 003, 002, 002, 015, 016, 025, 026 },
{ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 007, 023, 037, 046, 056, 075, 043, 045, 055, 021, 050, 031, 045, 027, 071, 062 },
{ 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 026, 005, 007, 063, 063, 027, 063, 040, 006, 004, 040, 045, 047, 030, 075, 007 },
{ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 023, 073, 073, 041, 072, 034, 021, 051, 067, 016, 031, 074, 011, 021, 012, 021 },
{ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 024, 051, 025, 023, 022, 041, 074, 066, 074, 065, 070, 036, 067, 045, 064, 001 },
{ 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 052, 033, 014, 002, 020, 006, 014, 025, 052, 023, 035, 074, 075, 075, 043, 027 },
{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 055, 062, 056, 025, 073, 060, 015, 030, 013, 017, 020, 002, 070, 055, 014, 047 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 054, 051, 032, 065, 077, 012, 054, 013, 035, 032, 056, 012, 075, 001, 072, 063 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 074, 041, 030, 041, 043, 022, 051, 006, 064, 033, 003, 047, 027, 012, 055, 047 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 054, 070, 011, 003, 013, 022, 016, 057, 003, 045, 072, 031, 030, 056, 035, 022 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 051, 007, 072, 030, 065, 054, 006, 021, 036, 063, 050, 061, 064, 052, 001, 060 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 001, 065, 032, 070, 013, 044, 073, 024, 012, 052, 021, 055, 012, 035, 014, 072 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 011, 070, 005, 010, 065, 024, 015, 077, 022, 024, 024, 074, 007, 044, 007, 046 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 006, 002, 065, 011, 041, 020, 045, 042, 046, 054, 035, 012, 040, 064, 065, 033 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 034, 031, 001, 015, 044, 064, 016, 024, 052, 016, 006, 062, 020, 013, 055, 057 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 063, 043, 025, 044, 077, 063, 017, 017, 064, 014, 040, 074, 031, 072, 054, 006 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 071, 021, 070, 044, 056, 004, 030, 074, 004, 023, 071, 070, 063, 045, 056, 043 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 002, 001, 053, 074, 002, 014, 052, 074, 012, 057, 024, 063, 015, 042, 052, 033 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 034, 035, 002, 023, 021, 027, 022, 033, 064, 042, 005, 073, 051, 046, 073, 060 } };
const uint32_t rsGFexp[64] = {
1, 2, 4, 8, 16, 32, 3, 6,
12, 24, 48, 35, 5, 10, 20, 40,
19, 38, 15, 30, 60, 59, 53, 41,
17, 34, 7, 14, 28, 56, 51, 37,
9, 18, 36, 11, 22, 44, 27, 54,
47, 29, 58, 55, 45, 25, 50, 39,
13, 26, 52, 43, 21, 42, 23, 46,
31, 62, 63, 61, 57, 49, 33, 0
};
const uint32_t rsGFlog[64] = {
63, 0, 1, 6, 2, 12, 7, 26,
3, 32, 13, 35, 8, 48, 27, 18,
4, 24, 33, 16, 14, 52, 36, 54,
9, 45, 49, 38, 28, 41, 19, 56,
5, 62, 25, 11, 34, 31, 17, 47,
15, 23, 53, 51, 37, 44, 55, 40,
10, 61, 46, 30, 50, 22, 39, 43,
29, 60, 42, 21, 20, 59, 57, 58
};
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the RS634717 class.
/// </summary>
RS634717::RS634717()
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the RS634717 class.
/// </summary>
RS634717::~RS634717()
{
/* stub */
}
/// <summary>
/// Decode RS (24,12,13) FEC.
/// </summary>
/// <param name="data">Reed-Solomon FEC encoded data to decode.</param>
/// <returns>True, if data was decoded, otherwise false.</returns>
bool RS634717::decode241213(uint8_t* data)
{
return decode(data, 24U, 39, 12);
}
/// <summary>
/// Encode RS (24,12,13) FEC.
/// </summary>
/// <param name="data">Raw data to encode with Reed-Solomon FEC.</param>
void RS634717::encode241213(uint8_t* data)
{
assert(data != NULL);
uint8_t codeword[24U];
for (uint32_t i = 0U; i < 24U; i++) {
codeword[i] = 0x00U;
uint32_t offset = 0U;
for (uint32_t j = 0U; j < 12U; j++, offset += 6U) {
uint8_t hexbit = bin2Hex(data, offset);
codeword[i] ^= gf6Mult(hexbit, ENCODE_MATRIX[j][i]);
}
}
uint32_t offset = 0U;
for (uint32_t i = 0U; i < 24U; i++, offset += 6U)
hex2Bin(codeword[i], data, offset);
}
/// <summary>
/// Decode RS (24,16,9) FEC.
/// </summary>
/// <param name="data">Reed-Solomon FEC encoded data to decode.</param>
/// <returns>True, if data was decoded, otherwise false.</returns>
bool RS634717::decode24169(uint8_t* data)
{
return decode(data, 24U, 39, 8);
}
/// <summary>
/// Encode RS (24,16,9) FEC.
/// </summary>
/// <param name="data">Raw data to encode with Reed-Solomon FEC.</param>
void RS634717::encode24169(uint8_t* data)
{
assert(data != NULL);
uint8_t codeword[24U];
for (uint32_t i = 0U; i < 24U; i++) {
codeword[i] = 0x00U;
uint32_t offset = 0U;
for (uint32_t j = 0U; j < 16U; j++, offset += 6U) {
uint8_t hexbit = bin2Hex(data, offset);
codeword[i] ^= gf6Mult(hexbit, ENCODE_MATRIX_24169[j][i]);
}
}
uint32_t offset = 0U;
for (uint32_t i = 0U; i < 24U; i++, offset += 6U)
hex2Bin(codeword[i], data, offset);
}
/// <summary>
/// Decode RS (36,20,17) FEC.
/// </summary>
/// <param name="data">Reed-Solomon FEC encoded data to decode.</param>
/// <returns>True, if data was decoded, otherwise false.</returns>
bool RS634717::decode362017(uint8_t* data)
{
return decode(data, 36U, 27, 16);
}
/// <summary>
/// Encode RS (36,20,17) FEC.
/// </summary>
/// <param name="data">Raw data to encode with Reed-Solomon FEC.</param>
void RS634717::encode362017(uint8_t* data)
{
assert(data != NULL);
uint8_t codeword[36U];
for (uint32_t i = 0U; i < 36U; i++) {
codeword[i] = 0x00U;
uint32_t offset = 0U;
for (uint32_t j = 0U; j < 20U; j++, offset += 6U) {
uint8_t hexbit = bin2Hex(data, offset);
codeword[i] ^= gf6Mult(hexbit, ENCODE_MATRIX_362017[j][i]);
}
}
uint32_t offset = 0U;
for (uint32_t i = 0U; i < 36U; i++, offset += 6U)
hex2Bin(codeword[i], data, offset);
}
// ---------------------------------------------------------------------------
// Private Static Class Members
// ---------------------------------------------------------------------------
/// <summary>
///
/// </summary>
/// <param name="input"></param>
/// <param name="offset"></param>
/// <returns></returns>
uint8_t RS634717::bin2Hex(const uint8_t* input, uint32_t offset)
{
uint8_t output = 0x00U;
output |= READ_BIT(input, offset + 0U) ? 0x20U : 0x00U;
output |= READ_BIT(input, offset + 1U) ? 0x10U : 0x00U;
output |= READ_BIT(input, offset + 2U) ? 0x08U : 0x00U;
output |= READ_BIT(input, offset + 3U) ? 0x04U : 0x00U;
output |= READ_BIT(input, offset + 4U) ? 0x02U : 0x00U;
output |= READ_BIT(input, offset + 5U) ? 0x01U : 0x00U;
return output;
}
/// <summary>
///
/// </summary>
/// <param name="input"></param>
/// <param name="output"></param>
/// <param name="offset"></param>
/// <returns></returns>
void RS634717::hex2Bin(uint8_t input, uint8_t* output, uint32_t offset)
{
WRITE_BIT(output, offset + 0U, input & 0x20U);
WRITE_BIT(output, offset + 1U, input & 0x10U);
WRITE_BIT(output, offset + 2U, input & 0x08U);
WRITE_BIT(output, offset + 3U, input & 0x04U);
WRITE_BIT(output, offset + 4U, input & 0x02U);
WRITE_BIT(output, offset + 5U, input & 0x01U);
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
///
/// </summary>
/// <remarks>GF(2 ^ 6) multiply (for Reed-Solomon encoder).</remarks>
/// <param name="a"></param>
/// <param name="b"></param>
/// <returns></returns>
uint8_t RS634717::gf6Mult(uint8_t a, uint8_t b) const
{
uint8_t p = 0x00U;
for (uint32_t i = 0U; i < 6U; i++) {
if ((b & 0x01U) == 0x01U)
p ^= a;
a <<= 1;
if ((a & 0x40U) == 0x40U)
a ^= 0x43U; // primitive polynomial : x ^ 6 + x + 1
b >>= 1;
}
return p;
}
/// <summary>
/// Decode variable length Reed-Solomon FEC.
/// </summary>
/// <param name="data"></param>
/// <param name="bitLength"></param>
/// <param name="firstData"></param>
/// <param name="roots"></param>
/// <returns></returns>
bool RS634717::decode(uint8_t* data, const uint32_t bitLength, const int firstData, const int roots)
{
assert(data != NULL);
uint8_t HB[63U];
::memset(HB, 0x00U, 63U);
uint32_t offset = 0U;
for (uint32_t i = 0U; i < bitLength; i++, offset += 6)
HB[i] = bin2Hex(data, offset);
// RS (63,63-nroots,nroots+1) decoder where nroots = number of parity bits
// rsDec(8, 39) rsDec(16, 27) rsDec(12, 39)
const int nroots = roots;
int lambda[18]; // Err+Eras Locator poly
int S[17]; // syndrome poly
int b[18];
int t[18];
int omega[18];
int root[17];
int reg[18];
int locn[17];
int i, j, count, r, el, SynError, DiscrR, q, DegOmega, tmp, num1, num2, den, DegLambda;
// form the syndromes; i.e., evaluate HB(x) at roots of g(x)
for (i = 0; i <= nroots - 1; i++) {
S[i] = HB[0];
}
for (j = 1; j <= 62; j++) {
for (i = 0; i <= nroots - 1; i++) {
if (S[i] == 0) {
S[i] = HB[j];
}
else {
S[i] = HB[j] ^ rsGFexp[(rsGFlog[S[i]] + i + 1) % 63];
}
}
}
// convert syndromes to index form, checking for nonzero condition
SynError = 0;
for (i = 0; i <= nroots - 1; i++) {
SynError = SynError | S[i];
S[i] = rsGFlog[S[i]];
}
if (SynError == 0) {
// if syndrome is zero, rsData[] is a codeword and there are
// no errors to correct. So return rsData[] unmodified
count = 0;
return true;
}
for (i = 1; i <= nroots; i++) {
lambda[i] = 0;
}
lambda[0] = 1;
for (i = 0; i <= nroots; i++) {
b[i] = rsGFlog[lambda[i]];
}
// begin Berlekamp-Massey algorithm to determine error+erasure
// locator polynomial
r = 0;
el = 0;
while (++r <= nroots) {
// r is the step number
//r = r + 1;
// compute discrepancy at the r-th step in poly-form
DiscrR = 0;
for (i = 0; i <= r - 1; i++) {
if ((lambda[i] != 0) && (S[r - i - 1] != 63)) {
DiscrR = DiscrR ^ rsGFexp[(rsGFlog[lambda[i]] + S[r - i - 1]) % 63];
}
}
DiscrR = rsGFlog[DiscrR]; // index form
if (DiscrR == 63) {
// shift elements upward one step
for (i = nroots; i >= 1; i += -1) {
b[i] = b[i - 1];
}
b[0] = 63;
}
else {
// t(x) <-- lambda(x) - DiscrR*x*b(x)
t[0] = lambda[0];
for (i = 0; i <= nroots - 1; i++) {
if (b[i] != 63) {
t[i + 1] = lambda[i + 1] ^ rsGFexp[(DiscrR + b[i]) % 63];
}
else {
t[i + 1] = lambda[i + 1];
}
}
if (2 * el <= r - 1) {
el = r - el;
// b(x) <-- inv(DiscrR) * lambda(x)
for (i = 0; i <= nroots; i++) {
if (lambda[i]) {
b[i] = (rsGFlog[lambda[i]] - DiscrR + 63) % 63;
}
else {
b[i] = 63;
}
}
}
else {
// shift elements upward one step
for (i = nroots; i >= 1; i += -1) {
b[i] = b[i - 1];
}
b[0] = 63;
}
for (i = 0; i <= nroots; i++) {
lambda[i] = t[i];
}
}
} /* end while() */
// convert lambda to index form and compute deg(lambda(x))
DegLambda = 0;
for (i = 0; i <= nroots; i++) {
lambda[i] = rsGFlog[lambda[i]];
if (lambda[i] != 63) {
DegLambda = i;
}
}
// find roots of the error+erasure locator polynomial by Chien search
for (i = 1; i <= nroots; i++) {
reg[i] = lambda[i];
}
count = 0; // number of roots of lambda(x)
for (i = 1; i <= 63; i++) {
q = 1; // lambda[0] is always 0
for (j = DegLambda; j >= 1; j += -1) {
if (reg[j] != 63) {
reg[j] = (reg[j] + j) % 63;
q = q ^ rsGFexp[reg[j]];
}
}
// it is a root
if (q == 0) {
// store root (index-form) and error location number
root[count] = i;
locn[count] = i - 40;
// if we have max possible roots, abort search to save time
count = count + 1;
if (count == DegLambda) {
break;
}
}
}
if (DegLambda != count) {
// deg(lambda) unequal to number of roots => uncorrectable error detected
return false;
}
// compute err+eras evaluator poly omega(x)
// = s(x) * lambda(x) (modulo x**nroots). in index form. Also find deg(omega).
DegOmega = 0;
for (i = 0; i <= nroots - 1; i++) {
tmp = 0;
if (DegLambda < i) {
j = DegLambda;
}
else {
j = i;
}
for (/* j = j */; j >= 0; j += -1) {
if ((S[i - j] != 63) && (lambda[j] != 63)) {
tmp = tmp ^ rsGFexp[(S[i - j] + lambda[j]) % 63];
}
}
if (tmp) {
DegOmega = i;
}
omega[i] = rsGFlog[tmp];
}
omega[nroots] = 63;
// compute error values in poly-form:
// num1 = omega(inv(X(l)))
// num2 = inv(X(l))**(FCR - 1)
// den = lambda_pr(inv(X(l)))
for (j = count - 1; j >= 0; j += -1) {
num1 = 0;
for (i = DegOmega; i >= 0; i += -1) {
if (omega[i] != 63) {
num1 = num1 ^ rsGFexp[(omega[i] + i * root[j]) % 63];
}
}
num2 = rsGFexp[0];
den = 0;
// lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i]
if (DegLambda < nroots) {
i = DegLambda;
}
else {
i = nroots;
}
for (i = i & ~1; i >= 0; i += -2) {
if (lambda[i + 1] != 63) {
den = den ^ rsGFexp[(lambda[i + 1] + i * root[j]) % 63];
}
}
if (den == 0) {
return false;
}
// apply error to data
if (num1 != 0) {
if (locn[j] < firstData)
return false;
HB[locn[j]] = HB[locn[j]] ^ (rsGFexp[(rsGFlog[num1] + rsGFlog[num2] + 63 - rsGFlog[den]) % 63]);
}
}
offset = 0U;
for (uint32_t i = 0U; i < (uint32_t)nroots; i++, offset += 6)
hex2Bin(HB[i], data, offset);
return true;
}

@ -0,0 +1,80 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2017 by Bryan Biedenkapp N2PLL
*
* 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(__RS634717_H__)
#define __RS634717_H__
#include "Defines.h"
namespace edac
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements Reed-Solomon (63,47,17). Which is also used to implement
// Reed-Solomon (24,12,13), (24,16,9) and (36,20,17) forward
// error correction.
// ---------------------------------------------------------------------------
class HOST_SW_API RS634717 {
public:
/// <summary>Initializes a new instance of the RS634717 class.</summary>
RS634717();
/// <summary>Finalizes a instance of the RS634717 class.</summary>
~RS634717();
/// <summary>Decode RS (24,12,13) FEC.</summary>
bool decode241213(uint8_t* data);
/// <summary>Encode RS (24,12,13) FEC.</summary>
void encode241213(uint8_t* data);
/// <summary>Decode RS (24,16,9) FEC.</summary>
bool decode24169(uint8_t* data);
/// <summary>Encode RS (24,16,9) FEC.</summary>
void encode24169(uint8_t* data);
/// <summary>Decode RS (36,20,17) FEC.</summary>
bool decode362017(uint8_t* data);
/// <summary>Encode RS (36,20,17) FEC.</summary>
void encode362017(uint8_t* data);
private:
/// <summary></summary>
static uint8_t bin2Hex(const uint8_t* input, uint32_t offset);
/// <summary></summary>
static void hex2Bin(uint8_t input, uint8_t* output, uint32_t offset);
/// <summary></summary>
uint8_t gf6Mult(uint8_t a, uint8_t b) const;
/// <summary>Decode variable length Reed-Solomon FEC.</summary>
bool decode(uint8_t* data, const uint32_t bitLength, const int firstData, const int roots);
};
} // namespace edac
#endif // __RS634717_H__

@ -0,0 +1,438 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2005, 2006, 2008 Free Software Foundation, Inc.
* Copyright (C) 2011,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 "Defines.h"
#include "edac/SHA256.h"
using namespace edac;
#include <cstdio>
#include <cstring>
#include <cassert>
// ---------------------------------------------------------------------------
// Macros
// ---------------------------------------------------------------------------
#ifdef WORDS_BIGENDIAN
# define SWAP(n) (n)
#else
# define SWAP(n) \
(((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
#endif
#define BLOCKSIZE 4096
#if BLOCKSIZE % 64 != 0
# error "invalid BLOCKSIZE"
#endif
// Round functions.
#define F2(A,B,C) ( ( A & B ) | ( C & ( A | B ) ) )
#define F1(E,F,G) ( G ^ ( E & ( F ^ G ) ) )
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
/*
* This array contains the bytes used to pad the buffer to the next 64-byte
* boundary.
*/
static const uint8_t fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
/*
* SHA256 round constants
*/
#define K(I) roundConstants[I]
static const uint32_t roundConstants[64] = {
0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL,
0x3956c25bUL, 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL,
0xd807aa98UL, 0x12835b01UL, 0x243185beUL, 0x550c7dc3UL,
0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL, 0xc19bf174UL,
0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL,
0x983e5152UL, 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL,
0xc6e00bf3UL, 0xd5a79147UL, 0x06ca6351UL, 0x14292967UL,
0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL, 0x53380d13UL,
0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL,
0xd192e819UL, 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL,
0x19a4c116UL, 0x1e376c08UL, 0x2748774cUL, 0x34b0bcb5UL,
0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL, 0x682e6ff3UL,
0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL,
};
// ---------------------------------------------------------------------------
// Global Functions
// ---------------------------------------------------------------------------
/*
* Copy the value from v into the memory location pointed to by *cp,
* If your architecture allows unaligned access this is equivalent to
* (uint32_t *) cp = v
*/
static inline void set_uint32(uint8_t* cp, uint32_t v)
{
assert(cp != NULL);
::memcpy(cp, &v, sizeof v);
}
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the SHA256 class.
/// </summary>
/// <remarks>
/// Takes a pointer to a 256 bit block of data (eight 32 bit ints) and
/// intializes it to the start constants of the SHA256 algorithm. This
/// must be called before using hash in the call to sha256_hash
/// </remarks>
SHA256::SHA256() :
m_state(NULL),
m_total(NULL),
m_buflen(0U),
m_buffer(NULL)
{
m_state = new uint32_t[8U];
m_total = new uint32_t[2U];
m_buffer = new uint32_t[32U];
init();
}
/// <summary>
/// Finalizes a instance of the SHA256 class.
/// </summary>
SHA256::~SHA256()
{
delete[] m_state;
delete[] m_total;
delete[] m_buffer;
}
/// <summary>
/// Starting with the result of former calls of this function (or the initialization
/// function update the context for the next LEN bytes starting at BUFFER. It is
/// necessary that LEN is a multiple of 64!!!
/// </summary>
/// <remarks>
/// Process LEN bytes of BUFFER, accumulating context into CTX.
/// It is assumed that LEN % 64 == 0.
/// Most of this code comes from GnuPG's cipher/sha1.c.
/// </remarks>
/// <param name="buffer"></param>
/// <param name="len"></param>
void SHA256::processBlock(const uint8_t* buffer, uint32_t len)
{
assert(buffer != NULL);
const uint32_t *words = (uint32_t *)buffer;
uint32_t nwords = len / sizeof(uint32_t);
const uint32_t *endp = words + nwords;
uint32_t x[16];
uint32_t a = m_state[0];
uint32_t b = m_state[1];
uint32_t c = m_state[2];
uint32_t d = m_state[3];
uint32_t e = m_state[4];
uint32_t f = m_state[5];
uint32_t g = m_state[6];
uint32_t h = m_state[7];
// First increment the byte count. FIPS PUB 180-2 specifies the possible
// length of the file up to 2^64 bits. Here we only compute the
// number of bytes. Do a double word increment.
m_total[0] += len;
if (m_total[0] < len)
++m_total[1];
#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
#define S0(x) (rol(x, 25) ^ rol(x, 14) ^ (x >> 3))
#define S1(x) (rol(x, 15) ^ rol(x, 13) ^ (x >> 10))
#define SS0(x) (rol(x, 30) ^ rol(x, 19) ^ rol(x, 10))
#define SS1(x) (rol(x, 26) ^ rol(x, 21) ^ rol(x, 7))
#define M(I) (tm = S1(x[(I - 2) & 0x0f]) + x[(I - 7) & 0x0f] + S0(x[(I - 15) & 0x0f]) + x[I & 0x0f], x[I & 0x0f] = tm)
#define R(A,B,C,D,E,F,G,H,K,M) do { t0 = SS0(A) + F2(A,B,C); \
t1 = H + SS1(E) + F1(E,F,G) + K + M; \
D += t1; H = t0 + t1; \
} while(0)
while (words < endp) {
uint32_t tm;
uint32_t t0, t1;
// FIXME: see sha1.c for a better implementation.
for (uint32_t t = 0U; t < 16U; t++) {
x[t] = SWAP(*words);
words++;
}
R(a, b, c, d, e, f, g, h, K(0), x[0]);
R(h, a, b, c, d, e, f, g, K(1), x[1]);
R(g, h, a, b, c, d, e, f, K(2), x[2]);
R(f, g, h, a, b, c, d, e, K(3), x[3]);
R(e, f, g, h, a, b, c, d, K(4), x[4]);
R(d, e, f, g, h, a, b, c, K(5), x[5]);
R(c, d, e, f, g, h, a, b, K(6), x[6]);
R(b, c, d, e, f, g, h, a, K(7), x[7]);
R(a, b, c, d, e, f, g, h, K(8), x[8]);
R(h, a, b, c, d, e, f, g, K(9), x[9]);
R(g, h, a, b, c, d, e, f, K(10), x[10]);
R(f, g, h, a, b, c, d, e, K(11), x[11]);
R(e, f, g, h, a, b, c, d, K(12), x[12]);
R(d, e, f, g, h, a, b, c, K(13), x[13]);
R(c, d, e, f, g, h, a, b, K(14), x[14]);
R(b, c, d, e, f, g, h, a, K(15), x[15]);
R(a, b, c, d, e, f, g, h, K(16), M(16));
R(h, a, b, c, d, e, f, g, K(17), M(17));
R(g, h, a, b, c, d, e, f, K(18), M(18));
R(f, g, h, a, b, c, d, e, K(19), M(19));
R(e, f, g, h, a, b, c, d, K(20), M(20));
R(d, e, f, g, h, a, b, c, K(21), M(21));
R(c, d, e, f, g, h, a, b, K(22), M(22));
R(b, c, d, e, f, g, h, a, K(23), M(23));
R(a, b, c, d, e, f, g, h, K(24), M(24));
R(h, a, b, c, d, e, f, g, K(25), M(25));
R(g, h, a, b, c, d, e, f, K(26), M(26));
R(f, g, h, a, b, c, d, e, K(27), M(27));
R(e, f, g, h, a, b, c, d, K(28), M(28));
R(d, e, f, g, h, a, b, c, K(29), M(29));
R(c, d, e, f, g, h, a, b, K(30), M(30));
R(b, c, d, e, f, g, h, a, K(31), M(31));
R(a, b, c, d, e, f, g, h, K(32), M(32));
R(h, a, b, c, d, e, f, g, K(33), M(33));
R(g, h, a, b, c, d, e, f, K(34), M(34));
R(f, g, h, a, b, c, d, e, K(35), M(35));
R(e, f, g, h, a, b, c, d, K(36), M(36));
R(d, e, f, g, h, a, b, c, K(37), M(37));
R(c, d, e, f, g, h, a, b, K(38), M(38));
R(b, c, d, e, f, g, h, a, K(39), M(39));
R(a, b, c, d, e, f, g, h, K(40), M(40));
R(h, a, b, c, d, e, f, g, K(41), M(41));
R(g, h, a, b, c, d, e, f, K(42), M(42));
R(f, g, h, a, b, c, d, e, K(43), M(43));
R(e, f, g, h, a, b, c, d, K(44), M(44));
R(d, e, f, g, h, a, b, c, K(45), M(45));
R(c, d, e, f, g, h, a, b, K(46), M(46));
R(b, c, d, e, f, g, h, a, K(47), M(47));
R(a, b, c, d, e, f, g, h, K(48), M(48));
R(h, a, b, c, d, e, f, g, K(49), M(49));
R(g, h, a, b, c, d, e, f, K(50), M(50));
R(f, g, h, a, b, c, d, e, K(51), M(51));
R(e, f, g, h, a, b, c, d, K(52), M(52));
R(d, e, f, g, h, a, b, c, K(53), M(53));
R(c, d, e, f, g, h, a, b, K(54), M(54));
R(b, c, d, e, f, g, h, a, K(55), M(55));
R(a, b, c, d, e, f, g, h, K(56), M(56));
R(h, a, b, c, d, e, f, g, K(57), M(57));
R(g, h, a, b, c, d, e, f, K(58), M(58));
R(f, g, h, a, b, c, d, e, K(59), M(59));
R(e, f, g, h, a, b, c, d, K(60), M(60));
R(d, e, f, g, h, a, b, c, K(61), M(61));
R(c, d, e, f, g, h, a, b, K(62), M(62));
R(b, c, d, e, f, g, h, a, K(63), M(63));
a = m_state[0] += a;
b = m_state[1] += b;
c = m_state[2] += c;
d = m_state[3] += d;
e = m_state[4] += e;
f = m_state[5] += f;
g = m_state[6] += g;
h = m_state[7] += h;
}
}
/// <summary>
/// Starting with the result of former calls of this function (or the initialization
/// function update the context for the next LEN bytes starting at BUFFER. It is NOT
/// required that LEN is a multiple of 64.
/// </summary>
/// <param name="buffer"></param>
/// <param name="len"></param>
void SHA256::processBytes(const uint8_t* buffer, uint32_t len)
{
assert(buffer != NULL);
// When we already have some bits in our internal buffer concatenate
// both inputs first.
if (m_buflen != 0U) {
uint32_t left_over = m_buflen;
uint32_t add = 128U - left_over > len ? len : 128U - left_over;
::memcpy(&((char*)m_buffer)[left_over], buffer, add);
m_buflen += add;
if (m_buflen > 64U) {
processBlock((uint8_t*)m_buffer, m_buflen & ~63U);
m_buflen &= 63U;
// The regions in the following copy operation cannot overlap.
::memcpy(m_buffer, &((char*)m_buffer)[(left_over + add) & ~63U], m_buflen);
}
buffer += add;
len -= add;
}
// Process available complete blocks.
if (len >= 64U) {
processBlock(buffer, len & ~63U);
buffer += (len & ~63U);
len &= 63U;
}
// Move remaining bytes in internal buffer.
if (len > 0U) {
uint32_t left_over = m_buflen;
::memcpy(&((char*)m_buffer)[left_over], buffer, len);
left_over += len;
if (left_over >= 64U) {
processBlock((uint8_t*)m_buffer, 64U);
left_over -= 64U;
::memcpy(m_buffer, &m_buffer[16], left_over);
}
m_buflen = left_over;
}
}
/// <summary>
/// Process the remaining bytes in the bufferand put result from context
/// in first 32 bytes following buffer. The result is always in little
/// endian byte order, so that a byte - wise output yields to the wanted
/// ASCII representation of the message digest.
/// </summary>
/// <param name="buffer"></param>
/// <returns></returns>
uint8_t* SHA256::finish(uint8_t* buffer)
{
assert(buffer != NULL);
conclude();
return read(buffer);
}
/// <summary>
/// Put result from context in first 32 bytes following buffer. The result is
/// always in little endian byte order, so that a byte - wise output yields
/// to the wanted ASCII representation of the message digest.
/// </summary>
/// <param name="buffer"></param>
/// <returns></returns>
uint8_t* SHA256::read(uint8_t* buffer)
{
assert(buffer != NULL);
for (uint32_t i = 0U; i < 8U; i++)
set_uint32(buffer + i * sizeof(m_state[0]), SWAP(m_state[i]));
return buffer;
}
/// <summary>
/// Compute SHA256 message digest for the length bytes beginning at buffer. The
/// result is always in little endian byte order, so that a byte-wise
/// output yields to the wanted ASCII representation of the message
/// digest.
/// </summary>
/// <param name="buffer"></param>
/// <param name="len"></param>
/// <param name="resblock"></param>
/// <returns></returns>
uint8_t* SHA256::buffer(const uint8_t* buffer, uint32_t len, uint8_t* resblock)
{
assert(buffer != NULL);
assert(resblock != NULL);
// Initialize the computation context.
init();
// Process whole buffer but last len % 64 bytes.
processBytes(buffer, len);
// Put result in desired memory area.
return finish(resblock);
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
///
/// </summary>
void SHA256::init()
{
m_state[0] = 0x6a09e667UL;
m_state[1] = 0xbb67ae85UL;
m_state[2] = 0x3c6ef372UL;
m_state[3] = 0xa54ff53aUL;
m_state[4] = 0x510e527fUL;
m_state[5] = 0x9b05688cUL;
m_state[6] = 0x1f83d9abUL;
m_state[7] = 0x5be0cd19UL;
m_total[0] = m_total[1] = 0;
m_buflen = 0;
}
/// <summary>
/// Process the remaining bytes in the internal buffer and the usual
/// prolog according to the standard and write the result to the buffer.
/// </summary>
void SHA256::conclude()
{
// Take yet unprocessed bytes into account.
uint32_t bytes = m_buflen;
uint32_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4;
// Now count remaining bytes.
m_total[0] += bytes;
if (m_total[0] < bytes)
++m_total[1];
// Put the 64-bit file length in *bits* at the end of the buffer.
// Use set_uint32 rather than a simple assignment, to avoid risk of
// unaligned access.
set_uint32((uint8_t*)& m_buffer[size - 2], SWAP((m_total[1] << 3) | (m_total[0] >> 29)));
set_uint32((uint8_t*)& m_buffer[size - 1], SWAP(m_total[0] << 3));
::memcpy(&((char*)m_buffer)[bytes], fillbuf, (size - 2) * 4 - bytes);
// Process last bytes.
processBlock((uint8_t*)m_buffer, size * 4);
}

@ -0,0 +1,99 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2005, 2006, 2008, 2009 Free Software Foundation, Inc.
* Copyright (C) 2011,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(__SHA256_H__)
#define __SHA256_H__
#include "Defines.h"
#include <cstdint>
namespace edac
{
// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------
enum {
SHA256_DIGEST_SIZE = 256 / 8
};
// ---------------------------------------------------------------------------
// Class Declaration
// Implements SHA-256 hashing.
// ---------------------------------------------------------------------------
class HOST_SW_API SHA256 {
public:
/// <summary>Initializes a new instance of the SHA256 class.</summary>
SHA256();
/// <summary>Finalizes a instance of the SHA256 class.</summary>
~SHA256();
/// <summary>Starting with the result of former calls of this function (or the initialization
/// function update the context for the next LEN bytes starting at BUFFER. It is necessary
/// that LEN is a multiple of 64!!!</summary>
void processBlock(const uint8_t* buffer, uint32_t len);
/// <summary>Starting with the result of former calls of this function (or the initialization
/// function update the context for the next LEN bytes starting at BUFFER. It is NOT required
/// that LEN is a multiple of 64.</summary>
void processBytes(const uint8_t* buffer, uint32_t len);
/// <summary>Process the remaining bytes in the bufferand put result from context in first 32
/// bytes following buffer. The result is always in little endian byte order, so that a byte-wise
/// output yields to the wanted ASCII representation of the message digest.</summary>
uint8_t* finish(uint8_t* buffer);
/// <summary>Put result from context in first 32 bytes following buffer. The result is always
/// in little endian byte order, so that a byte - wise output yields to the wanted ASCII
/// representation of the message digest.</summary>
uint8_t* read(uint8_t* buffer);
/// <summary>Compute SHA256 message digest for the length bytes beginning at buffer. The result
/// is always in little endian byte order, so that a byte-wise output yields to the wanted ASCII
/// representation of the message digest.</summary>
uint8_t* buffer(const uint8_t* buffer, uint32_t len, uint8_t* resblock);
private:
uint32_t* m_state;
uint32_t* m_total;
uint32_t m_buflen;
uint32_t* m_buffer;
/// <summary></summary>
void init();
/// <summary>Process the remaining bytes in the internal buffer and the usual prolog according to
/// the standard and write the result to the buffer.</summary>
void conclude();
};
} // namespace edac
#endif // __SHA256_H__

File diff suppressed because it is too large Load Diff

@ -0,0 +1,142 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017-2020 by Bryan Biedenkapp N2PLL
*
* 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(__HOST_H__)
#define __HOST_H__
#include "Defines.h"
#include "network/Network.h"
#include "network/RemoteControl.h"
#include "modem/Modem.h"
#include "Timer.h"
#include "lookups/IdenTableLookup.h"
#include "lookups/RadioIdLookup.h"
#include "lookups/TalkgroupIdLookup.h"
#include "yaml/Yaml.h"
#include <string>
// ---------------------------------------------------------------------------
// Class Prototypes
// ---------------------------------------------------------------------------
class HOST_SW_API RemoteControl;
// ---------------------------------------------------------------------------
// Class Declaration
// This class implements the core host service logic.
// ---------------------------------------------------------------------------
class HOST_SW_API Host {
public:
/// <summary>Initializes a new instance of the Host class.</summary>
Host(const std::string& confFile);
/// <summary>Finalizes a instance of the Host class.</summary>
~Host();
/// <summary>Executes the main modem host processing loop.</summary>
int run();
private:
const std::string& m_confFile;
yaml::Node m_conf;
modem::Modem* m_modem;
network::Network* m_network;
uint8_t m_mode;
Timer m_modeTimer;
Timer m_dmrTXTimer;
Timer m_cwIdTimer;
bool m_dmrEnabled;
bool m_p25Enabled;
bool m_p25CtrlBcstContinuous;
bool m_duplex;
bool m_fixedMode;
uint32_t m_timeout;
uint32_t m_rfModeHang;
uint32_t m_netModeHang;
uint32_t m_netTalkgroupHang;
std::string m_identity;
std::string m_cwCallsign;
uint32_t m_cwIdTime;
float m_latitude;
float m_longitude;
int m_height;
uint32_t m_power;
std::string m_location;
uint32_t m_rxFrequency;
uint32_t m_txFrequency;
uint8_t m_channelId;
uint32_t m_channelNo;
std::vector<uint32_t> m_voiceChNo;
lookups::IdenTableLookup* m_idenTable;
lookups::RadioIdLookup* m_ridLookup;
lookups::TalkgroupIdLookup* m_tidLookup;
bool m_dmrBeacons;
bool m_controlData;
uint32_t m_dmrColorCode;
uint32_t m_p25NAC;
uint32_t m_p25PatchSuperGroup;
uint32_t m_p25NetId;
uint32_t m_p25SysId;
uint8_t m_p25RfssId;
uint8_t m_p25SiteId;
friend class RemoteControl;
RemoteControl* m_remoteControl;
/// <summary>Reads basic configuration parameters from the INI.</summary>
bool readParams();
/// <summary>Initializes the modem DSP.</summary>
bool createModem();
/// <summary>Initializes network connectivity.</summary>
bool createNetwork();
/// <summary>Helper to set the host/modem running state.</summary>
void setMode(uint8_t mode);
/// <summary></summary>
void createLockFile(const char* mode) const;
/// <summary></summary>
void removeLockFile() const;
};
#endif // __HOST_H__

@ -0,0 +1,176 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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 "host/calibrate/Console.h"
#include <cstdio>
#if defined(_WIN32) || defined(_WIN64)
#include <conio.h>
#else
#include <cstring>
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
#endif
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
#if defined(_WIN32) || defined(_WIN64)
/// <summary>
/// Initializes a new instance of the Console class.
/// </summary>
Console::Console()
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the Console class.
/// </summary>
Console::~Console()
{
/* stub */
}
/// <summary>
/// Opens the terminal console.
/// </summary>
bool Console::open()
{
return true;
}
/// <summary>
/// Retrieves a character input on the keyboard.
/// </summary>
/// <returns></returns>
int Console::getChar()
{
if (::_kbhit() == 0)
return -1;
return ::_getch();
}
/// <summary>
/// Closes the terminal console.
/// </summary>
void Console::close()
{
/* stub */
}
#else
/// <summary>
/// Initializes a new instance of the Console class.
/// </summary>
Console::Console() :
m_termios()
{
::memset(&m_termios, 0x00U, sizeof(termios));
}
/// <summary>
/// Finalizes a instance of the Console class.
/// </summary>
Console::~Console()
{
/* stub */
}
/// <summary>
/// Opens the terminal console.
/// </summary>
bool Console::open()
{
termios tios;
int n = ::tcgetattr(STDIN_FILENO, &tios);
if (n != 0) {
::fprintf(stderr, "tcgetattr: returned %d\r\n", n);
return -1;
}
m_termios = tios;
::cfmakeraw(&tios);
n = ::tcsetattr(STDIN_FILENO, TCSANOW, &tios);
if (n != 0) {
::fprintf(stderr, "tcsetattr: returned %d\r\n", n);
return -1;
}
return true;
}
/// <summary>
/// Retrieves a character input on the keyboard.
/// </summary>
/// <returns></returns>
int Console::getChar()
{
fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
int n = ::select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv);
if (n <= 0) {
if (n < 0)
::fprintf(stderr, "select: returned %d\r\n", n);
return -1;
}
char c;
n = ::read(STDIN_FILENO, &c, 1);
if (n <= 0) {
if (n < 0)
::fprintf(stderr, "read: returned %d\r\n", n);
return -1;
}
return c;
}
/// <summary>
/// Closes the terminal console.
/// </summary>
void Console::close()
{
int n = ::tcsetattr(STDIN_FILENO, TCSANOW, &m_termios);
if (n != 0)
::fprintf(stderr, "tcsetattr: returned %d\r\n", n);
}
#endif

@ -0,0 +1,67 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMCal project. (https://github.com/g4klx/MMDVMCal)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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(__CONSOLE_H__)
#define __CONSOLE_H__
#include "Defines.h"
#if !defined(_WIN32) && !defined(_WIN64)
#include <termios.h>
#endif
// ---------------------------------------------------------------------------
// Class Declaration
// Implements cross-platform handling of the terminal console. This is
// mainly used for the calibration mode.
// ---------------------------------------------------------------------------
class HOST_SW_API Console {
public:
/// <summary>Initializes a new instance of the Console class.</summary>
Console();
/// <summary>Finalizes a instance of the Console class.</summary>
~Console();
/// <summary>Opens the terminal console.</summary>
bool open();
/// <summary>Retrieves a character input on the keyboard.</summary>
int getChar();
/// <summary>Closes the terminal console.</summary>
void close();
private:
#if !defined(_WIN32) && !defined(_WIN64)
termios m_termios;
#endif
};
#endif // __CONSOLE_H__

File diff suppressed because it is too large Load Diff

@ -0,0 +1,157 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMCal project. (https://github.com/g4klx/MMDVMCal)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
* Copyright (C) 2017,2018 by Andy Uribe CA6JAU
* Copyright (C) 2017-2020 by Bryan Biedenkapp N2PLL
*
* 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(__HOST_CAL_H__)
#define __HOST_CAL_H__
#include "Defines.h"
#include "edac/AMBEFEC.h"
#include "modem/Modem.h"
#include "modem/SerialController.h"
#include "host/calibrate/Console.h"
#include "host/Host.h"
#include "yaml/Yaml.h"
#include <string>
// ---------------------------------------------------------------------------
// Class Declaration
// This class implements the interactive calibration mode.
// ---------------------------------------------------------------------------
class HOST_SW_API HostCal {
public:
/// <summary>Initializes a new instance of the HostCal class.</summary>
HostCal(const std::string& confFile);
/// <summary>Finalizes a instance of the HostCal class.</summary>
~HostCal();
/// <summary>Executes the calibration processing loop.</summary>
int run();
private:
const std::string& m_confFile;
yaml::Node m_conf;
std::string m_port;
modem::CSerialController m_serial;
Console m_console;
edac::AMBEFEC m_fec;
bool m_transmit;
bool m_duplex;
bool m_txInvert;
bool m_rxInvert;
bool m_pttInvert;
bool m_dcBlocker;
float m_txLevel;
float m_rxLevel;
bool m_dmrEnabled;
bool m_dmrRx1K;
bool m_p25Enabled;
bool m_p25Rx1K;
int m_txDCOffset;
int m_rxDCOffset;
uint32_t m_txDelay;
uint32_t m_dmrDelay;
bool m_debug;
uint8_t m_mode;
std::string m_modeStr;
uint32_t m_berFrames;
uint32_t m_berBits;
uint32_t m_berErrs;
uint32_t m_berUndecodableLC;
uint32_t m_berUncorrectable;
uint32_t m_timeout;
uint32_t m_timer;
/// <summary>Helper to print the calibration help to the console.</summary>
void displayHelp();
/// <summary>Helper to change the Tx level.</summary>
bool setTXLevel(int incr);
/// <summary>Helper to change the Rx level.</summary>
bool setRXLevel(int incr);
/// <summary>Helper to change the Tx DC offset.</summary>
bool setTXDCOffset(int incr);
/// <summary>Helper to change the Rx DC offset.</summary>
bool setRXDCOffset(int incr);
/// <summary>Helper to toggle modem transmit mode.</summary>
bool setTransmit();
/// <summary>Initializes the modem DSP.</summary>
bool initModem();
/// <summary>Read data frames from the modem DSP.</summary>
int readModem(uint8_t* buffer, uint32_t length);
/// <summary>Process DMR Rx BER.</summary>
void processDMRBER(const uint8_t* buffer, uint8_t seq);
/// <summary>Process DMR Tx 1011hz BER.</summary>
void processDMR1KBER(const uint8_t* buffer, uint8_t seq);
/// <summary>Process P25 Rx BER.</summary>
void processP25BER(const uint8_t* buffer);
/// <summary>Process P25 Tx 1011hz BER.</summary>
void processP251KBER(const uint8_t* buffer);
/// <summary>Retrieve the modem DSP version.</summary>
bool getFirmwareVersion();
/// <summary>Write configuration to the modem DSP.</summary>
bool writeConfig();
/// <summary>Write configuration to the modem DSP.</summary>
bool writeConfig(uint8_t modeOverride);
/// <summary></summary>
void sleep(uint32_t ms);
/// <summary></summary>
void timerClock();
/// <summary></summary>
void timerStart();
/// <summary></summary>
void timerStop();
/// <summary>Prints the current status of the calibration.</summary>
void printStatus();
/// <summary></summary>
void printDebug(const uint8_t* buffer, uint32_t length);
/// <summary></summary>
unsigned char countErrs(unsigned char a, unsigned char b);
};
#endif // __HOST_CAL_H__

@ -0,0 +1,8 @@
#
# This file sets the valid P25 bandplan identity table.
#
# ChId,Base Freq,Spacing (khz),Input Offset (mhz),Bandwidth (khz),<newline>
0,851006250,6.25,-45.000,12.5,
1,762006250,6.25,30.000,12.5,
15,935001250,6.25,-39.00000,12.5,
2,450000000,6.25,5.000,12.5,

@ -0,0 +1,157 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2018-2019 by Bryan Biedenkapp N2PLL
*
* 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 "lookups/IdenTableLookup.h"
#include "Log.h"
#include "Timer.h"
using namespace lookups;
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <vector>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the IdenTableLookup class.
/// </summary>
/// <param name="filename">Full-path to the channel identity table file.</param>
/// <param name="reloadTime">Interval of time to reload the channel identity table.</param>
IdenTableLookup::IdenTableLookup(const std::string& filename, uint32_t reloadTime) : LookupTable(filename, reloadTime)
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the IdenTableLookup class.
/// </summary>
IdenTableLookup::~IdenTableLookup()
{
/* stub */
}
/// <summary>
/// Finds a table entry in this lookup table.
/// </summary>
/// <param name="id">Unique identifier for table entry.</param>
/// <returns>Table entry.</returns>
IdenTable IdenTableLookup::find(uint32_t id)
{
IdenTable entry;
m_mutex.lock();
{
try {
entry = m_table.at(id);
} catch (...) {
/* stub */
}
}
m_mutex.unlock();
float chBandwidthKhz = entry.chBandwidthKhz();
if (chBandwidthKhz == 0.0F)
chBandwidthKhz = 12.5F;
float chSpaceKhz = entry.chSpaceKhz();
if (chSpaceKhz < 2.5F) // clamp to 2.5
chSpaceKhz = 2.5F;
if (chSpaceKhz > 6.25F) // clamp to 6.25
chSpaceKhz = 6.25F;
return IdenTable(entry.channelId(), entry.baseFrequency(), chSpaceKhz, entry.txOffsetMhz(), chBandwidthKhz);
}
/// <summary>
/// Returns the list of entries in this lookup table.
/// </summary>
/// <returns>List of all entries in the lookup table.</returns>
std::vector<IdenTable> IdenTableLookup::list()
{
std::vector<IdenTable> list = std::vector<IdenTable>();
if (m_table.size() > 0) {
for (auto it = m_table.begin(); it != m_table.end(); ++it) {
IdenTable entry = it->second;
list.push_back(entry);
}
}
return list;
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Parses a table entry from the passed comma delimited string.
/// </summary>
/// <param name="tableEntry">Comma delimited string to process into table entry.</param>
/// <returns>Table entry.</returns>
IdenTable IdenTableLookup::parse(std::string tableEntry)
{
std::string next;
std::vector<std::string> parsed;
char delim = ',';
for (auto it = tableEntry.begin(); it != tableEntry.end(); it++) {
if (*it == delim) {
if (!next.empty()) {
parsed.push_back(next);
next.clear();
}
}
else
next += *it;
}
if (!next.empty())
parsed.push_back(next);
uint8_t channelId = (uint8_t)::atoi(parsed[0].c_str());
uint32_t baseFrequency = (uint32_t)::atoi(parsed[1].c_str());
float chSpaceKhz = float(::atof(parsed[2].c_str()));
float txOffsetMhz = float(::atof(parsed[3].c_str()));
float chBandwidthKhz = float(::atof(parsed[4].c_str()));
if (chSpaceKhz == 0.0F)
chSpaceKhz = chBandwidthKhz / 2;
if (chSpaceKhz < 2.5F) // clamp to 2.5
chSpaceKhz = 2.5F;
if (chSpaceKhz > 6.25F) // clamp to 6.25
chSpaceKhz = 6.25F;
IdenTable entry = IdenTable(channelId, baseFrequency, chSpaceKhz, txOffsetMhz, chBandwidthKhz);
LogMessage(LOG_HOST, "Channel Id %u: BaseFrequency = %uHz, TXOffsetMhz = %fMHz, BandwidthKhz = %fKHz, SpaceKhz = %fKHz",
entry.channelId(), entry.baseFrequency(), entry.txOffsetMhz(), entry.chBandwidthKhz(), entry.chSpaceKhz());
return entry;
}

@ -0,0 +1,130 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2018-2019 by Bryan Biedenkapp N2PLL
*
* 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(__IDEN_TABLE_LOOKUP_H__)
#define __IDEN_TABLE_LOOKUP_H__
#include "Defines.h"
#include "lookups/LookupTable.h"
#include "Thread.h"
#include "Mutex.h"
#include <string>
#include <unordered_map>
#include <vector>
namespace lookups
{
// ---------------------------------------------------------------------------
// Class Declaration
// Represents an individual entry in the bandplan identity table.
// ---------------------------------------------------------------------------
class HOST_SW_API IdenTable {
public:
/// <summary>Initializes a new insatnce of the IdenTable class.</summary>
IdenTable() :
m_channelId(0U),
m_baseFrequency(0U),
m_chSpaceKhz(0.0F),
m_txOffsetMhz(0.0F),
m_chBandwidthKhz(0.0F)
{
/* stub */
}
/// <summary>Initializes a new insatnce of the IdenTable class.</summary>
/// <param name="channelId"></param>
/// <param name="baseFrequency"></param>
/// <param name="chSpaceKhz"></param>
/// <param name="txOffsetMhz"></param>
/// <param name="chBandwidthKhz"></param>
IdenTable(uint8_t channelId, uint32_t baseFrequency, float chSpaceKhz, float txOffsetMhz, float chBandwidthKhz) :
m_channelId(channelId),
m_baseFrequency(baseFrequency),
m_chSpaceKhz(chSpaceKhz),
m_txOffsetMhz(txOffsetMhz),
m_chBandwidthKhz(chBandwidthKhz)
{
/* stub */
}
/// <summary>Equals operator.</summary>
/// <param name="data"></param>
/// <returns></returns>
IdenTable& operator=(const IdenTable& data)
{
if (this != &data) {
m_channelId = data.m_channelId;
m_baseFrequency = data.m_baseFrequency;
m_chSpaceKhz = data.m_chSpaceKhz;
m_txOffsetMhz = data.m_txOffsetMhz;
m_chBandwidthKhz = data.m_chBandwidthKhz;
}
return *this;
}
public:
/// <summary>Channel ID for this entry.</summary>
__READONLY_PROPERTY_PLAIN(uint8_t, channelId, channelId);
/// <summary>Base frequency for this entry.</summary>
__READONLY_PROPERTY_PLAIN(uint32_t, baseFrequency, baseFrequency);
/// <summary>Channel spacing in kHz for this entry.</summary>
__READONLY_PROPERTY_PLAIN(float, chSpaceKhz, chSpaceKhz);
/// <summary>Channel transmit offset in MHz for this entry.</summary>
__READONLY_PROPERTY_PLAIN(float, txOffsetMhz, txOffsetMhz);
/// <summary>Channel bandwith in kHz for this entry.</summary>
__READONLY_PROPERTY_PLAIN(float, chBandwidthKhz, chBandwidthKhz);
};
// ---------------------------------------------------------------------------
// Class Declaration
// Implements a threading lookup table class that contains the bandplan
// identity table.
// ---------------------------------------------------------------------------
class HOST_SW_API IdenTableLookup : public LookupTable<IdenTable> {
public:
/// <summary>Initializes a new instance of the IdenTableLookup class.</summary>
IdenTableLookup(const std::string& filename, uint32_t reloadTime);
/// <summary>Finalizes a instance of the IdenTableLookup class.</summary>
virtual ~IdenTableLookup();
/// <summary>Finds a table entry in this lookup table.</summary>
virtual IdenTable find(uint32_t id);
/// <summary>Returns the list of entries in this lookup table.</summary>
std::vector<IdenTable> list();
private:
/// <summary>Parses a table entry from the passed comma delimited string.</summary>
IdenTable parse(std::string tableEntry);
};
} // namespace lookups
#endif // __IDEN_TABLE_LOOKUP_H__

@ -0,0 +1,212 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2018-2019 by Bryan Biedenkapp N2PLL
*
* 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(__LOOKUP_TABLE_H__)
#define __LOOKUP_TABLE_H__
#include "Defines.h"
#include "Log.h"
#include "Thread.h"
#include "Timer.h"
#include "Mutex.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <string>
#include <unordered_map>
namespace lookups
{
// ---------------------------------------------------------------------------
// Class Declaration
// Implements a abstract threading class that contains base logic for
// building tables of data.
// ---------------------------------------------------------------------------
template <class T>
class HOST_SW_API LookupTable : public Thread {
public:
/// <summary>Initializes a new instance of the LookupTable class.</summary>
/// <param name="filename">Full-path to the lookup table file.</param>
/// <param name="reloadTime">Interval of time to reload the channel identity table.</param>
LookupTable(const std::string& filename, uint32_t reloadTime) :
Thread(),
m_filename(filename),
m_reloadTime(reloadTime)
{
/* stub */
}
/// <summary>Finalizes a instance of the LookupTable class.</summary>
virtual ~LookupTable()
{
/* stub */
}
/// <summary></summary>
virtual void entry()
{
Timer timer(1U, 60U * m_reloadTime);
timer.start();
while (!m_stop) {
sleep(1000U);
timer.clock();
if (timer.hasExpired()) {
load();
timer.start();
}
}
}
/// <summary>Stops and unloads this lookup table.</summary>
virtual void stop()
{
if (m_reloadTime == 0U) {
delete this;
return;
}
m_stop = true;
wait();
}
/// <summary>Reads the lookup table from the specified lookup table file.</summary>
/// <returns>True, if lookup table was read, otherwise false.</returns>
virtual bool read()
{
bool ret = load();
if (m_reloadTime > 0U)
run();
return ret;
}
/// <summary>Clears all entries from the lookup table.</summary>
virtual void clear()
{
m_mutex.lock();
{
m_table.clear();
}
m_mutex.unlock();
}
/// <summary>Helper to check if this lookup table has the specified unique ID.</summary>
/// <param name="id">Unique ID to check for.</param>
/// <returns>True, if the lookup table has an entry by the specified unique ID, otherwise false.</returns>
virtual bool hasEntry(uint32_t id)
{
m_mutex.lock();
{
try {
m_table.at(id);
return true;
}
catch (...) {
return false;
}
}
m_mutex.unlock();
return false;
}
/// <summary>Finds a table entry in this lookup table.</summary>
/// <param name="id">Unique identifier for table entry.</param>
/// <returns>Table entry.</returns>
virtual T find(uint32_t id) = 0;
protected:
std::string m_filename;
uint32_t m_reloadTime;
std::unordered_map<uint32_t, T> m_table;
Mutex m_mutex;
bool m_stop;
bool m_acl;
/// <summary>Parses a table entry from the passed comma delimited string.</summary>
/// <param name="tableEntry">Comma delimited string to process into table entry.</param>
/// <returns>Table entry.</returns>
virtual T parse(std::string tableEntry) = 0;
/// <summary>Loads the table from the passed lookup table file.</summary>
/// <returns>True, if lookup table was loaded, otherwise false.</returns>
virtual bool load()
{
if (strlen(m_filename.c_str()) <= 0) {
return false;
}
FILE* fp = ::fopen(m_filename.c_str(), "rt");
if (fp == NULL) {
LogError(LOG_HOST, "Cannot open the lookup file - %s", m_filename.c_str());
return false;
}
// clear table
clear();
m_mutex.lock();
{
char buffer[100U];
while (::fgets(buffer, 100U, fp) != NULL) {
if (buffer[0U] == '#')
continue;
std::string strbuf = buffer;
char* p1 = ::strtok(buffer, ",\r\n");
if (p1 != NULL) {
uint32_t id = (uint32_t)::atoi(p1);
m_table[id] = parse(strbuf);
}
}
}
m_mutex.unlock();
::fclose(fp);
size_t size = m_table.size();
if (size == 0U)
return false;
LogInfoEx(LOG_HOST, "Loaded %u entries into lookup table", size);
return true;
}
};
} // namespace lookups
#endif // __LOOKUP_TABLE_H__

@ -0,0 +1,123 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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 "lookups/RSSIInterpolator.h"
#include "Log.h"
using namespace lookups;
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the RSSIInterpolator class.
/// </summary>
RSSIInterpolator::RSSIInterpolator() :
m_map()
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the RSSIInterpolator class.
/// </summary>
RSSIInterpolator::~RSSIInterpolator()
{
m_map.clear();
}
/// <summary>
/// Loads the table from the passed RSSI mapping file.
/// </summary>
/// <param name="filename">Full-path to the RSSI mapping file.</param>
/// <returns>True, if RSSI mapping was loaded, otherwise false.</returns>
bool RSSIInterpolator::load(const std::string& filename)
{
FILE* fp = ::fopen(filename.c_str(), "rt");
if (fp == NULL) {
LogError(LOG_HOST, "Cannot open the RSSI data file - %s", filename.c_str());
return false;
}
char buffer[100U];
while (::fgets(buffer, 100, 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) {
uint16_t raw = uint16_t(::atoi(p1));
int rssi = ::atoi(p2);
m_map.insert(std::pair<uint16_t, int>(raw, rssi));
}
}
::fclose(fp);
LogInfoEx(LOG_HOST, "Loaded %u RSSI data mapping points from %s", m_map.size(), filename.c_str());
return true;
}
/// <summary>
/// Interoplates the given raw RSSI value with the lookup map.
/// </summary>
/// <param name="val">Raw RSSI value from modem DSP.</param>
/// <returns>Interpolated RSSI value.</returns>
int RSSIInterpolator::interpolate(uint16_t val) const
{
if (m_map.empty())
return 0;
std::map<uint16_t, int>::const_iterator it = m_map.lower_bound(val);
if (it == m_map.end())
return m_map.rbegin()->second;
if (it == m_map.begin())
return it->second;
uint16_t x2 = it->first;
int y2 = it->second;
--it;
uint16_t x1 = it->first;
int y1 = it->second;
float p = float(val - x1) / float(x2 - x1);
return int((1.0F - p) * float(y1) + p * float(y2));
}

@ -0,0 +1,64 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* 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(__RSSI_INTERPOLATOR_H__)
#define __RSSI_INTERPOLATOR_H__
#include "Defines.h"
#include <cstdint>
#include <string>
#include <map>
namespace lookups
{
// ---------------------------------------------------------------------------
// Class Declaration
//
// ---------------------------------------------------------------------------
class HOST_SW_API RSSIInterpolator {
public:
/// <summary>Initializes a new instance of the RSSIInterpolator class.</summary>
RSSIInterpolator();
/// <summary>Finalizes a instance of the RSSIInterpolator class.</summary>
~RSSIInterpolator();
/// <summary>Loads the table from the passed RSSI mapping file.</summary>
bool load(const std::string& filename);
/// <summary>Interoplates the given raw RSSI value with the lookup map.</summary>
int interpolate(uint16_t raw) const;
private:
std::map<uint16_t, int> m_map;
};
} // namespace lookups
#endif // __RSSI_INTERPOLATOR_H__

@ -0,0 +1,192 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2017-2019 by Bryan Biedenkapp N2PLL
*
* 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 "lookups/RadioIdLookup.h"
#include "p25/P25Defines.h"
#include "Log.h"
#include "Timer.h"
using namespace lookups;
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <vector>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the RadioIdLookup class.
/// </summary>
/// <param name="filename">Full-path to the radio ID table file.</param>
/// <param name="reloadTime">Interval of time to reload the radio ID table.</param>
/// <param name="ridAcl">Flag indicating whether radio ID access control is enabled.</param>
RadioIdLookup::RadioIdLookup(const std::string& filename, uint32_t reloadTime, bool ridAcl) : LookupTable(filename, reloadTime),
m_acl(ridAcl)
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the RadioIdLookup class.
/// </summary>
RadioIdLookup::~RadioIdLookup()
{
/* stub */
}
/// <summary>
/// Toggles the specified radio ID enabled or disabled.
/// </summary>
/// <param name="id">Unique ID to toggle.</param>
/// <param name="enabled">Flag indicating if radio ID is enabled or not.</param>
void RadioIdLookup::toggleEntry(uint32_t id, bool enabled)
{
RadioId rid = find(id);
if (rid.radioEnabled() == false && rid.radioDefault() == true) {
if (enabled) {
LogMessage(LOG_HOST, "Added enabled RID %u to RID ACL table", id);
}
else {
LogMessage(LOG_HOST, "Added disabled RID %u to RID ACL table", id);
}
}
if (rid.radioEnabled() == false && rid.radioDefault() == false) {
if (enabled) {
LogMessage(LOG_HOST, "Enabled RID %u in RID ACL table", id);
}
else {
LogMessage(LOG_HOST, "Disabled RID %u in RID ACL table", id);
}
}
addEntry(id, enabled);
}
/// <summary>
/// Adds a new entry to the lookup table by the specified unique ID.
/// </summary>
/// <param name="id">Unique ID to add.</param>
/// <param name="enabled">Flag indicating if radio ID is enabled or not.</param>
void RadioIdLookup::addEntry(uint32_t id, bool enabled)
{
if ((id == p25::P25_WUID_ALL) || (id == p25::P25_WUID_SYS) || (id == p25::P25_WUID_FNE)) {
return;
}
RadioId entry = RadioId(enabled, false);
m_mutex.lock();
{
try {
RadioId _entry = m_table.at(id);
// if the enabled value doesn't match -- override with the intended
if (_entry.radioEnabled() != enabled) {
_entry = RadioId(enabled, false);
m_table[id] = _entry;
}
} catch (...) {
m_table[id] = entry;
}
}
m_mutex.unlock();
}
/// <summary>
/// Finds a table entry in this lookup table.
/// </summary>
/// <param name="id">Unique identifier for table entry.</param>
/// <returns>Table entry.</returns>
RadioId RadioIdLookup::find(uint32_t id)
{
RadioId entry;
if (id == p25::P25_WUID_ALL || id == p25::P25_WUID_SYS || id == p25::P25_WUID_FNE) {
return RadioId(true, false);
}
m_mutex.lock();
{
try {
entry = m_table.at(id);
} catch (...) {
entry = RadioId(false, true);
}
}
m_mutex.unlock();
return entry;
}
/// <summary>
/// Flag indicating whether radio ID access control is enabled or not.
/// </summary>
/// <returns>True, if radio ID access control is enabled, otherwise false.</returns>
bool RadioIdLookup::getACL()
{
return m_acl;
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Parses a table entry from the passed comma delimited string.
/// </summary>
/// <param name="tableEntry">Comma delimited string to process into table entry.</param>
/// <returns>Table entry.</returns>
RadioId RadioIdLookup::parse(std::string tableEntry)
{
std::string next;
std::vector<std::string> parsed;
char delim = ',';
for (auto it = tableEntry.begin(); it != tableEntry.end(); it++) {
if (*it == delim) {
if (!next.empty()) {
parsed.push_back(next);
next.clear();
}
}
else
next += *it;
}
if (!next.empty())
parsed.push_back(next);
bool radioEnabled = ::atoi(parsed[1].c_str()) == 1;
bool radioDefault = false;
return RadioId(radioEnabled, radioDefault);
}

@ -0,0 +1,127 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2017-2019 by Bryan Biedenkapp N2PLL
*
* 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(__RADIO_ID_LOOKUP_H__)
#define __RADIO_ID_LOOKUP_H__
#include "Defines.h"
#include "lookups/LookupTable.h"
#include "Thread.h"
#include "Mutex.h"
#include <string>
#include <unordered_map>
namespace lookups
{
// ---------------------------------------------------------------------------
// Class Declaration
// Represents an individual entry in the radio ID table.
// ---------------------------------------------------------------------------
class HOST_SW_API RadioId {
public:
/// <summary>Initializes a new insatnce of the RadioId class.</summary>
RadioId() :
m_radioEnabled(false),
m_radioDefault(false)
{
/* stub */
}
/// <summary>Initializes a new insatnce of the RadioId class.</summary>
/// <param name="radioEnabled"></param>
/// <param name="radioDefault"></param>
RadioId(bool radioEnabled, bool radioDefault) :
m_radioEnabled(radioEnabled),
m_radioDefault(radioDefault)
{
/* stub */
}
/// <summary>Equals operator. Copies this RadioId to another RadioId.</summary>
RadioId& operator=(const RadioId& data)
{
if (this != &data) {
m_radioEnabled = data.m_radioEnabled;
m_radioDefault = data.m_radioDefault;
}
return *this;
}
/// <summary></summary>
/// <param name="radioEnabled"></param>
/// <param name="radioDefault"></param>
void set(bool radioEnabled, bool radioDefault)
{
m_radioEnabled = radioEnabled;
m_radioDefault = radioDefault;
}
public:
/// <summary></summary>
__READONLY_PROPERTY_PLAIN(bool, radioEnabled, radioEnabled);
/// <summary></summary>
__READONLY_PROPERTY_PLAIN(bool, radioDefault, radioDefault);
};
// ---------------------------------------------------------------------------
// Class Declaration
// Implements a threading lookup table class that contains a radio ID
// lookup table.
// ---------------------------------------------------------------------------
class HOST_SW_API RadioIdLookup : public LookupTable<RadioId> {
public:
/// <summary>Initializes a new instance of the RadioIdLookup class.</summary>
RadioIdLookup(const std::string& filename, uint32_t reloadTime, bool ridAcl);
/// <summary>Finalizes a instance of the RadioIdLookup class.</summary>
virtual ~RadioIdLookup();
/// <summary>Toggles the specified radio ID enabled or disabled.</summary>
void toggleEntry(uint32_t id, bool enabled);
/// <summary>Adds a new entry to the lookup table by the specified unique ID.</summary>
void addEntry(uint32_t id, bool enabled);
/// <summary>Finds a table entry in this lookup table.</summary>
virtual RadioId find(uint32_t id);
/// <summary>Flag indicating whether radio ID access control is enabled or not.</summary>
bool getACL();
private:
bool m_acl;
/// <summary>Parses a table entry from the passed comma delimited string.</summary>
virtual RadioId parse(std::string tableEntry);
};
} // namespace lookups
#endif // __RADIO_ID_LOOKUP_H__

@ -0,0 +1,156 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2017-2019 by Bryan Biedenkapp N2PLL
*
* 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 "lookups/TalkgroupIdLookup.h"
#include "Log.h"
#include "Timer.h"
using namespace lookups;
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <vector>
// ---------------------------------------------------------------------------
// Public Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Initializes a new instance of the TalkgroupIdLookup class.
/// </summary>
/// <param name="filename">Full-path to the talkgroup ID table file.</param>
/// <param name="reloadTime">Interval of time to reload the talkgroup ID table.</param>
/// <param name="tidAcl">Flag indicating whether talkgroup ID access control is enabled.</param>
TalkgroupIdLookup::TalkgroupIdLookup(const std::string& filename, uint32_t reloadTime, bool tidAcl) : LookupTable(filename, reloadTime),
m_acl(tidAcl)
{
/* stub */
}
/// <summary>
/// Finalizes a instance of the TalkgroupIdLookup class.
/// </summary>
TalkgroupIdLookup::~TalkgroupIdLookup()
{
/* stub */
}
/// <summary>
/// Adds a new entry to the lookup table by the specified unique ID.
/// </summary>
/// <param name="id">Unique ID to add.</param>
/// <param name="slot">DMR slot this talkgroup is valid on.</param>
/// <param name="enabled">Flag indicating if talkgroup ID is enabled or not.</param>
void TalkgroupIdLookup::addEntry(uint32_t id, unsigned char slot, bool enabled)
{
TalkgroupId entry = TalkgroupId(enabled, slot, false);
m_mutex.lock();
{
try {
TalkgroupId _entry = m_table.at(id);
// if the enabled value doesn't match -- override with the intended
if (_entry.tgEnabled() != enabled) {
_entry = TalkgroupId(enabled, _entry.tgSlot(), false);
m_table[id] = _entry;
}
} catch (...) {
m_table[id] = entry;
}
}
m_mutex.unlock();
}
/// <summary>
/// Finds a table entry in this lookup table.
/// </summary>
/// <param name="id">Unique identifier for table entry.</param>
/// <returns>Table entry.</returns>
TalkgroupId TalkgroupIdLookup::find(uint32_t id)
{
TalkgroupId entry;
m_mutex.lock();
{
try {
entry = m_table.at(id);
} catch (...) {
entry = TalkgroupId(false, 0U, true);
}
}
m_mutex.unlock();
return entry;
}
/// <summary>
/// Flag indicating whether talkgroup ID access control is enabled or not.
/// </summary>
/// <returns>True, if talkgroup ID access control is enabled, otherwise false.</returns>
bool TalkgroupIdLookup::getACL()
{
return m_acl;
}
// ---------------------------------------------------------------------------
// Private Class Members
// ---------------------------------------------------------------------------
/// <summary>
/// Parses a table entry from the passed comma delimited string.
/// </summary>
/// <param name="tableEntry">Comma delimited string to process into table entry.</param>
/// <returns>Table entry.</returns>
TalkgroupId TalkgroupIdLookup::parse(std::string tableEntry)
{
std::string next;
std::vector<std::string> parsed;
char delim = ',';
for (auto it = tableEntry.begin(); it != tableEntry.end(); it++) {
if (*it == delim) {
if (!next.empty()) {
parsed.push_back(next);
next.clear();
}
}
else
next += *it;
}
if (!next.empty())
parsed.push_back(next);
bool tgEnabled = ::atoi(parsed[1].c_str()) == 1;
uint8_t tgSlot = (uint8_t)::atoi(parsed[2].c_str());
bool tgDefault = false;
return TalkgroupId(tgEnabled, tgSlot, tgDefault);
}

@ -0,0 +1,132 @@
/**
* Digital Voice Modem - Host Software
* GPLv2 Open Source. Use is subject to license terms.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* @package DVM / Host Software
*
*/
//
// Based on code from the MMDVMHost project. (https://github.com/g4klx/MMDVMHost)
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0)
//
/*
* Copyright (C) 2016 by Jonathan Naylor G4KLX
* Copyright (C) 2017-2019 by Bryan Biedenkapp N2PLL
*
* 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(__TALKGROUP_ID_LOOKUP_H__)
#define __TALKGROUP_ID_LOOKUP_H__
#include "Defines.h"
#include "lookups/LookupTable.h"
#include "Thread.h"
#include "Mutex.h"
#include <string>
#include <unordered_map>
namespace lookups
{
// ---------------------------------------------------------------------------
// Class Declaration
// Represents an individual entry in the talkgroup ID table.
// ---------------------------------------------------------------------------
class HOST_SW_API TalkgroupId {
public:
/// <summary>Initializes a new insatnce of the TalkgroupId class.</summary>
TalkgroupId() :
m_tgEnabled(false),
m_tgSlot(0U),
m_tgDefault(false)
{
/* stub */
}
/// <summary>Initializes a new insatnce of the TalkgroupId class.</summary>
/// <param name="tgEnabled"></param>
/// <param name="tgSlot"></param>
/// <param name="tgDefault"></param>
TalkgroupId(bool tgEnabled, uint8_t tgSlot, bool tgDefault) :
m_tgEnabled(tgEnabled),
m_tgSlot(tgSlot),
m_tgDefault(tgDefault)
{
/* stub */
}
/// <summary>Equals operator. Copies this TalkgroupId to another TalkgroupId.</summary>
TalkgroupId& operator=(const TalkgroupId& data)
{
if (this != &data) {
m_tgEnabled = data.m_tgEnabled;
m_tgSlot = data.m_tgSlot;
m_tgDefault = data.m_tgDefault;
}
return *this;
}
/// <summary></summary>
/// <param name="tgEnabled"></param>
/// <param name="tgSlot"></param>
/// <param name="tgDefault"></param>
void set(bool tgEnabled, uint8_t tgSlot, bool tgDefault)
{
m_tgEnabled = tgEnabled;
m_tgSlot = tgSlot;
m_tgDefault = tgDefault;
}
public:
/// <summary></summary>
__READONLY_PROPERTY_PLAIN(bool, tgEnabled, tgEnabled);
/// <summary></summary>
__READONLY_PROPERTY_PLAIN(uint8_t, tgSlot, tgSlot);
/// <summary></summary>
__READONLY_PROPERTY_PLAIN(bool, tgDefault, tgDefault);
};
// ---------------------------------------------------------------------------
// Class Declaration
// Implements a threading lookup table class that contains a talkgroup
// ID lookup table.
// ---------------------------------------------------------------------------
class HOST_SW_API TalkgroupIdLookup : public LookupTable<TalkgroupId> {
public:
/// <summary>Initializes a new instance of the TalkgroupIdLookup class.</summary>
TalkgroupIdLookup(const std::string& filename, uint32_t reloadTime, bool tidAcl);
/// <summary>Finalizes a instance of the TalkgroupIdLookup class.</summary>
virtual ~TalkgroupIdLookup();
/// <summary>Adds a new entry to the lookup table by the specified unique ID.</summary>
void addEntry(uint32_t id, unsigned char slot, bool enabled);
/// <summary>Finds a table entry in this lookup table.</summary>
virtual TalkgroupId find(uint32_t id);
/// <summary>Flag indicating whether talkgroup ID access control is enabled or not.</summary>
bool getACL();
private:
bool m_acl;
/// <summary>Parses a table entry from the passed comma delimited string.</summary>
virtual TalkgroupId parse(std::string tableEntry);
};
} // namespace lookups
#endif // __TALKGROUP_ID_LOOKUP_H__

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

Loading…
Cancel
Save

Powered by TurnKey Linux.