OK-DMR / ok-dmrlib

DMR PDUs, elements, FEC and CRC library, including proprietary DMR protocols of Hytera and Motorola
GNU Affero General Public License v3.0
39 stars 8 forks source link

Help with embedded outbound Reverse Channel information #8

Open kantooon opened 10 months ago

kantooon commented 10 months ago

Hi, I'm trying to implement in MMDVMHost the DMR tier III reverse channel commands for MS de-key and MS power control. I use ok-dmrlib to generate the 32 bit PDUs, but the radios do not respond to the commands so there seems to be some issue with my code. I figured out by myself that in VBPTC3211 I have to invert the parity bits row to odd in the set_parity() method and changed it accordingly. I'm not so sure about CRC7 configuration. I wonder if you could help me troubleshoot my ok-dmrlib code below. Otherwise, the EMB fields are set with LCSS 0, PI 1 and correct colour code. The PDU is only transmitted in voice burst F so that seems fine as well.

 ba = bitarray('0100')
 CRC7_conf = BitCrcConfiguration(
        width_bits=7,
        polynomial=0x27,
        init_value=0x00,
        final_xor_value=0x7A,
        reverse_input_bytes=False,
        reverse_output_bytes=False,
    )
    crc7_calc = BitCrcCalculator(CRC7_conf, True)
    crc7_nm = crc7_calc.calculate_checksum(ba)
    print(crc7_nm)
    ba = ba + crc7_nm
    out = VBPTC3211.encode(ba)
    print(out)
    pad = bitarray('0000')
    padl = bitarray('0000')
    pad.extend(out)
    pad.extend(padl)
    all_bytes = bits_to_bytes(pad)
    readable = all_bytes.hex(',').split(',')
    x = str()
    for i in readable:
        x += "0x" + i + ', '
    print(x)
smarek commented 10 months ago

Hey @kantooon

1) for formatting, put ``` (three backticks) on empty line before and after your code, docs: https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks

  my formatted code

2) Can you let me know if you have RC Info payload with valid CRC7 ? I can add the CRC7 with tests here

3) From "ETSI TS 102 361-1 V2.5.1 (2017-10)" section B.3.13 (7-bit CRC calculation) I'd guess this is correct config

https://github.com/OK-DMR/ok-dmrlib/blob/master/okdmr/dmrlib/etsi/crc/crc.py#L291

    BitCrcConfiguration(
        width_bits=7,
        polynomial=0x27,
        init_value=0x00,
        final_xor_value=0x00,
        reverse_input_bytes=False,
        reverse_output_bytes=False,
    )

Not sure why you have final_xor_value=0x7A

kantooon commented 10 months ago

Hi, thanks for responding, answers below:

2. Can you let me know if you have RC Info payload with valid CRC7 ? I can add the CRC7 with tests here

Unfortunately I don't. I'm writing this blind, and the only way of testing it is with my radios (Hytera HP785, manual says it supports transmit interrupt and power control).

Not sure why you have final_xor_value=0x7A

ETSI TS 102 361-1, section B.3.12 Data Type CRC Mask, table B.21, reverse channel has a CRC mask of 0x7A. Isn't that the purpose of final_xor_value?

Also, if you can, is it possible to add odd parity option to VBTC3211 as in B.2.2.2 Reverse Channel Single Burst BPTC?

smarek commented 10 months ago

Ok, data type mask, i handle those differently since the CRC impl is typically not data-type-specific, indeed I think that's where your problem might be

If you take a look for example in CRC9 https://github.com/OK-DMR/ok-dmrlib/blob/fdb3fa7037a40cd397101e3e13e618c2c9ecbd0a/okdmr/dmrlib/etsi/crc/crc9.py#L51

I apply the mask to calculated and two-complement value of CRC, you can try similar flow, coding the crc's was the most tricky part for me as well :))

And last, how did you figure your payload is not taking effect because of invalid CRC ? Working with Hytera radios sometimes the reason is codeplug settings or licensing or just straight firmware bug. If you're able to capture full traffic with your MS as PCAP, we could maybe see more? I guess you're already aware of pcap tooling we have

kantooon commented 10 months ago

Ok, data type mask, i handle those differently since the CRC impl is typically not data-type-specific, indeed I think that's where your problem might be

If you take a look for example in CRC9

https://github.com/OK-DMR/ok-dmrlib/blob/fdb3fa7037a40cd397101e3e13e618c2c9ecbd0a/okdmr/dmrlib/etsi/crc/crc9.py#L51

I apply the mask to calculated and two-complement value of CRC, you can try similar flow, coding the crc's was the most tricky part for me as well :))

Thanks for the advice, I'll try this method as well, but for CRC9 the standard specifies an inversion polynomial, whereas for CRC7 it explicitly says there's no inversion polynomial.

And last, how did you figure your payload is not taking effect because of invalid CRC ? Working with Hytera radios sometimes the reason is codeplug settings or licensing or just straight firmware bug. If you're able to capture full traffic with your MS as PCAP, we could maybe see more? I guess you're already aware of pcap tooling we have

I guess I will need to double check the codeplug, power control is explicitly enabled, but there's no setting for receiving TX interrupt, only for transmitting. As far as licenses, I'm covered, the tier III license has everything. I'll need to check what I can do with pcap since I don't see how to get the data from MMDVM to pcap...

smarek commented 10 months ago

Regarding the network, suffices to capture network traffic between mmdvmhost (i assume you have some rpi hotspot or similar) and your computer (hblink maybe?), pcap can then be filtered and data extracted using dmrlib-pcap-tool, usually simply running "dmrlib-pcap-tool PATH_TO_YOUR_CAPTURE.pcapng" shows you data and stats, then you can fiddle with cli switches, see help

> dmrlib-pcap-tool --help
usage: dmrlib-pcap-tool [-h] [--ports WHITELIST_PORTS [WHITELIST_PORTS ...]] [--filter BLACKLIST_PORTS [BLACKLIST_PORTS ...]] [--no-statistics]
                        [--print-raw] [--extract-embedded-lc] [--observe-transmissions] [--debug-vocoder-bytes] [--verbose] [--ipsc]
                        [--filter-ip FILTER_IP [FILTER_IP ...]]
                        files [files ...]

Read and debug UDP packets in PCAP/PCAPNG file

positional arguments:
  files                 PCAP or PCAPNG file to be read

options:
  -h, --help            show this help message and exit
  --ports WHITELIST_PORTS [WHITELIST_PORTS ...], -p WHITELIST_PORTS [WHITELIST_PORTS ...]
                        Whitelist UDP ports to inspect (source or destination or both) (default: [])
  --filter BLACKLIST_PORTS [BLACKLIST_PORTS ...], -f BLACKLIST_PORTS [BLACKLIST_PORTS ...]
                        Blacklist UDP ports to exclude from inspection (source or destination or both) (default: [67, 68, 53, 161, 162, 123, 137, 138, 443,
                        80, 1900, 5353, 5355, 30052, 30061])
  --no-statistics, -q   Suppress statistics at the end of output (default: False)
  --print-raw, -r       Print raw UDP Data before parsing the payload (default: False)
  --extract-embedded-lc, -e
                        Extract only Embedded LinkControl data and print these (default: False)
  --observe-transmissions, -o
                        Feed bursts to Transmission and debug the data and how the state of terminals changed (default: False)
  --debug-vocoder-bytes
                        Effective only with --observe-transmissions, will print voice bytes in format ready for vocoder decode (default: False)
  --verbose, -v         Verbose logging (default: False)
  --ipsc                Analyze IPSC traffic (map between slot-type, frame-type and data-type) (default: False)
  --filter-ip FILTER_IP [FILTER_IP ...]
                        Filter traffic by "ORIGIN" IP address(es) (default: [])
kantooon commented 10 months ago

Oh I see what you meant with pcap. The RC PDU is only trnsmitted via RF currently, but I can also add it to the network transmisssion so I can wireshark it. I don't have a classic hotspot, my setup is all SDR-based and running on x86_64 Linux.

If you're curious, my test tier III system consists of a LimeSDR family device, qradiolink as lower PHY with 7 RF channels multiplexed in GNU radio flowgraphs, and some custom forks of MMDVM and MMDVMHost called MMDVM-SDR and MMDVMHost-SDR. The setup is partly described here: https://qradiolink.org/multicarrier-transceiver-DMR-YSF-M17-with-MMDVM-and-LimeSDR.html but there's like zero docs for tier III since it's WIP.

The RC PDU transmit is initiated from the trunking controller (dmrtc) and sent on the alternate logical channel (it only works with aligned timing and not offset timing).

smarek commented 10 months ago

very impressive, i've yet to work more with downlink and Tier-III PDUs, and the reason is i don't have them captured (i have SDR but it wasn't my priority so far to get it), if you could supply me with the on-air data, i would add a support for all these PDUs and routines to handle them.

Regarding form of the data, you can take inspiration from our and lwvmobile's last-years adventure with dsd-fme "DSP structured output" https://github.com/lwvmobile/dsd-fme/issues/94#issuecomment-1399266023

And last I guess your note about aligned/offset timing is just the current state of implementation, not actual AI protocol limitation?

kantooon commented 10 months ago

Yes sure, I use dsd-fme as well to test PDUs. Let me know what PDU captures you need, I already asked lwvmobile for a few changes in the DMR decoder and supplied him with some captures off the air.

The aligned timing limitation is specified in the standard at 5.1.1 Channel timing relationship. Reverse channel only works in this mode, basically the MS transmits its own timeslot, then switches to RX for the duration of the other timeslot and hears its own transmission repeated back (maybe with RC signalling). In offset timing, on the other hand it supports full duplex calls instead since the MS receives the other logical channel during that time.

kantooon commented 10 months ago

I'm going to close this now, as I haven't been able to find the solution yet, but I'm busy with other stuff. I'll come back to this later with a fresh perspective and if I find the right solution I'll also let you know. Thanks for your informative answers and your help in this topic!

smarek commented 10 months ago

Keep it open, its bookmark for my brain as well, thanks and good luck 🤞

smarek commented 3 days ago

@kantooon just heads up, odd parity for B.2.2.2 is now included per https://github.com/OK-DMR/ok-dmrlib/commit/8e3c84d97b15b18494da81ffdd2979d12d449ef8

smarek commented 3 days ago

@kantooon and because I became interested, i made some progress, you can check it https://github.com/OK-DMR/ok-dmrlib/commit/1a00ff4e71bb14735aa6741120411ac8e3f4e017

However yes, currently CRC7 does not seem to match the data (which was extracted from Hytera IPSC protocol, so it might not be valid in the original IPSC payload as well)

Before the Single Burst RC BPTC encoder, the appropriate CRC Mask as defined in clause B.3.12 of the present document shall be applied to the 7 bit CRC. I think this means, you should not apply "Reverse Channel Crc Mask", but apply whatever mask matches the rest of surrounding data/voice burst

Few records from log

c3520050d1f6000001000501010000001111cccc1111000040b80022040220024460220002000104808f6460b252602000650022040220024440b8020000000006010000ce432800 178.238.234.72:50002 -> 192.168.1.110:50001 IPSC TS:1 SEQ: 209 [EmbeddedSignalling] [RC Info bitarray('11111000000001100000011001000101')][LCSS.SingleFragmentLCorCSBK] [PreemptionPowerIndicator.CarriesReverseChannelInformation] [CC: 1]

c3520050d7f6000001000501010000001111cccc1111000040b81d8ed769d5d5c5371f08b0c04113f9865321b58254a58012d5d5425f515188acb8c00000000006010000ce432800 178.238.234.72:50002 -> 192.168.1.110:50001 IPSC TS:1 SEQ: 215 [EmbeddedSignalling] [RC Info bitarray('01101111100100100001010100111000')][LCSS.SingleFragmentLCorCSBK] [PreemptionPowerIndicator.CarriesReverseChannelInformation] [CC: 1]

kantooon commented 2 days ago

I think this is great news, I'll go generate the RC PDU again and compare it with the previously generated one. I can test the channel pre-emption over RF as well, but it's a little more convoluted, requires some changes in the trunking controller as well.

kantooon commented 2 days ago

I just ran the new reverse_channel code on the PDU's I had already computed months ago. They are a a match bit for bit, so either the code is correct, or we both made the same mistake somewhere. These are also recognized by dsd-fme as such. From my previous testing, my Hytera radios don't respond to these reverse channel commands. It may be a CPS setting that I haven't found, or they might use some proprietary, non-ETSI PDU, not sure which.

smarek commented 2 days ago

Ok, i'm truly sorry, this has been a rabbit hole for me, turns out the initial test data are not correct, and I wasted few more hours trying to get it working

I need to get at least a single RC PDU (embedded or standalone) , which is verified to be complete and with valid CRC, please help me out if you can, @lwvmobile might have data maybe

Thanks

smarek commented 1 day ago

I cannot get it out of my head, few sanity checks, i think i'm going crazy if you could take a look @kantooon please

1a) Parity - odd (zeroes==ones), even = (both counters should be (%2==0)), right?

odd parity 01000000001101011 <- RC(10 - 0) + H(4 - 0) 10111111110010100 <- PC(15 - 0) ZEROES 17 ONES 17 LEN 34 ZEROES==ONES

even parity 01000000010010000 <- RC(10 - 0) + H(4 - 0) 01000000010010000 <- PC(15 - 0) ZEROES 28 ONES 6 LEN 34 ZEROES%2==0, ONES%2==0

1b) Parity for all RC signalling should be "odd", so "even" should indicate "transmission bit-flip error", right?

1c) Parity should match, regardless of CRC Mask used, right?

2a) Distinguish embedded RC PDU (32bit) from LC fragment, these two conditions must be met, otherwise it's definitely not RC PDU, right?

3a) i've found https://github.com/lwvmobile/dsd-fme/issues/187 which seems my and lwvmobile implementations now match, which is unfortunate

4a) All RC embedded pdus I have have "even parity", which means they are not suitable for implementation/testing,


Also i found voice encryption by Chowdhary which places encryption params in the same places, but that should not be what i'm seeing in data captures, https://patentimages.storage.googleapis.com/df/89/8c/2b85c61f329b5b/US8422679.pdf

kantooon commented 14 hours ago

lwvmobile's implementation was independent, and it decodes my PDUs which are based on your code, it seems unlikely we all made the same error. It's more likely Hytera uses some other proprietary signalling I think.