commit
9cc117d30c
@ -0,0 +1 @@
|
||||
* text=auto
|
||||
@ -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,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);
|
||||
}
|
||||
}
|
||||
@ -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,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…
Reference in new issue