boatbod / op25

Fork of osmocom OP25 by boatbod
311 stars 97 forks source link

Motorola Type II SmartZone decoding improvements #207

Open ilyacodes opened 3 months ago

ilyacodes commented 3 months ago

Is your feature request related to a problem? Please describe. Motorola Type II SmartZone functionality currently decodes only a small subset of control channel messages. This is sufficient for basic trunk tracking, but it could be much better, both for debugging live systems and for potential future features that require a deeper understanding of system state (e.g. patches, etc).

Describe the solution you'd like I am currently working on setting up my own Type II IntelliRepeater "site" on the bench, and will be using it to identify opcodes and add parsing for them. At a minimum, this will enable them to be logged for debugging and manual inspection.

I plan to contribute the findings back to the project, but have the following question: what is the most efficient way for me to contribute?

I would definitely like to make this the least headache for everyone involved, so I'm asking before I get started.

Describe alternatives you've considered This isn't really applicable, I just want to know the most efficient way to contribute.

Additional context To be clear, I'm not asking you to implement anything, just asking how I can contribute to the project most efficiently.

boatbod commented 3 months ago

Ilya,Right now all development goes through the 'dev' branch,  then gets merged to 'master' and finally down to 'gr310'.My preference would be for you to clone from 'dev' and do your work there, then when a substantial block of work is tested and ready to publish, make a pull request and I can roll it up into the code base from there. Thanks, GrahamOn Mar 28, 2024 3:23 PM, ilyacodes @.***> wrote: Is your feature request related to a problem? Please describe. Motorola Type II SmartZone functionality currently decodes only a small subset of control channel messages. This is sufficient for basic trunk tracking, but it could be much better, both for debugging live systems and for potential future features that require a deeper understanding of system state (e.g. patches, etc). Describe the solution you'd like I am currently working on setting up my own Type II IntelliRepeater "site" on the bench, and will be using it to identify opcodes and add parsing for them. At a minimum, this will enable them to be logged for debugging and manual inspection. I plan to contribute the findings back to the project, but have the following question: what is the most efficient way for me to contribute? One PR per new message discovered? One large PR, but each message as its own commit? One giant PR when I'm all done? Describe alternatives you've considered This isn't really applicable, I just want to know the most efficient way to contribute. Additional context To be clear, I'm not asking you to implement anything, just asking how I can contribute to the project most efficiently.

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you are subscribed to this thread.Message ID: @.***>

ilyacodes commented 2 months ago

Hi Graham - thanks, I've sent #209 your way for review. Sorry it's so big, but I just waited for a substantial block of tested changes as requested. Future PRs should be more manageable as they will be building on the many refactorings that took place in this first PR.

EDIT: moved to #210 because I was cleaning up branches on my end.

boatbod commented 2 months ago

I have merged the smartnet and mi/algid/keyid logging changes into branch "dev". I'd appreciate if you could give it some exercise to make sure it's good before I propagate forward into "master" and "gr310" branches. My ability to test smartnet locally is severely limited because the only system we have basically runs with zero traffic (it's a hot standby for our P25 system, but sees no usage).

I'll be honest that I'm not sure I like the changes to the terminal yet. Let me run it for a while and see if I can get used to it. The "control" and "secondary" stuff is rather distracting.

ilyacodes commented 2 months ago

Perfect, thank you for reviewing and merging!

I have some wideband SDRs (hackrf and Pluto) on the way so I’ll get some more data on it too, especially P25 and SmartZone running at the same time. I’ve also been running it nearly continuously on SmartZone (in various iterations) for the last couple weeks.

The biggest risk I see currently is the IDLE messages – I’m still trying to make sense of how they get interleaved with other multi-OSW messages, though I think it may be a matter of just living with an infrequent unknown OSW. It happens more on some systems than others.

One question: I don’t know how familiar you are with DSD-FME, but one option it has is to use a pre-recorded file as input instead of an SDR. Does op25 have anything like this? If so I can get some recordings which we can use as test cases, as it gets merged into production branches.

Re: the terminal, perhaps we can have that be a flag in the config file? I find it handy to see more info even when not using the web interface, but I agree it can be clutter if you don’t care about it.

boatbod commented 2 months ago

op25 has the capability to take input from sdr devices, native symbol files, .IQ and .wav files.

The symbol files are the easiest, and utilize "raw_input" and "raw_output" parameters in the channel section of the .json. The benefit is you can start/stop the capture from the terminal very easily and they bypass the whole demodulator chain on playback. The limitation is you can't tune, and it really doesn't work well in an environment like smartzone where you expect voice on one channel and the control chan on another.

.IQ and .wav file handling are included for compatibility with DSD+FL/DSD-FME recordings. Depending how the recordings were made depends how you need to configure op25 for playback. Check the iq_example and wav_example Readme's for more info.

ilyacodes commented 2 months ago

Thank you, I will read up on that and try it.

boatbod commented 2 months ago

For .wav the main challenge is adjusting the "wav_gain" parameter to get a nice signal. Recommend looking at the Datascope plot (eye diagram) to tweak that adjustment.

For .IQ the problem is knowing/identifying the tuning offset in the .iq file. FMPP does things one way, while FMPP24 does it differently. Some iq files have a header signature while others don't...
Take a peek in lib/iqfile_source_impl.cc for more hints. I usually fire up the fft plot and/or mixer plot to try to verify if I've got the "offset" parameter correct. The "iq_seek" parameter allows you to skip ahead in the file as necessary.

boatbod commented 2 months ago

All changes have been pulled and integrated into dev, master & gr310 branches.

ilyacodes commented 2 months ago

Is it possible to replay raw_input symbol files at faster than real time - i.e. disable the self.throttle on the channels? I notice that's a difference from DSD-FME that is a little annoying when I've been doing iterative testing over the same (large) raw_output data set.

I'm also curious whether you have looked at ISWs at all? I have been looking at mottrunk.txt as well as US patents [1] [2] [3] (among others) and am finding that there is a little bit of information about the ISW format, but the details of deinterleaving and CRC are basically documented as "For some unknown reason you must [do x]. Don't ask us why.". Is it fair to say that's basically the state of the art for Type II at this time?

I was able to get a recording of some ISWs on the bench though, so I've demodulated that and am looking at how to make sense of the resulting bitstream now.

boatbod commented 2 months ago

You could probably speed up the throttle, but I think disabling it completely might lead to timing problems where channel signaling arrives at a faster rate than it can be passed to python and processed by the trunking code. Best thing would be to try and see what happens!

I've not done anything with ISWs. My local smartzone system is for the most part dead (i.e. just a control channel idling it's time away) so having any traffic to monitor and debug would be a rarity.

ilyacodes commented 2 months ago

I've been able to successfully decode some ISWs!

Demodulation

Demodulation is fairly straightforward, I was able to do it in Universal Radio Hacker once I was able to get a decent recording [1].

Modulated data format

Bits Single-word Dual-word
10 1010101010 preamble 1010101010 preamble
78 ISW interleaved data ISW1 interleaved data
6 010101 sync [2: Fig 11b]
78 ISW2 interleaved data

Fortunately we can correlate this against the relevant patent [3: Fig 11a] to confirm relevant bit counts.

image

Once the data is demodulated, we can just follow this flow chart in reverse, from bottom to top, to get the original 21-bit ISW data.

Deinterleaving

The same deinterleaving function that is used for OSWs works for ISWs, with a minor change: use 4 groups of 20 elements rather than 4 groups of 19 elements.

Incoming 0 1 2 3 4 5 6 7 8 9 ...
Deinterleaved 0 20 40 60 1 21 41 61 2 22 ...

I'm still not sure what to do with the final few elements where 78 obviously doesn't divide cleanly into 20... right now I'm trying the following (non-standard emphasised).

Incoming ... 70 71 72 73 74 75 76 77
Deinterleaved ... 57 8 18 38 58 19 39 59

Error correction

Now we have 78 bits in their original order - we can now check parity bits and perform error correction. The same error correction function used for OSWs works here too.

One exception: bit 37 (0-indexed) always reports as bad for me, even though my signal is known to be basically perfect. This leads me to wonder whether my assumption of how to de-interleave the last few bits was correct.

Error-corrected data format

Once we have error-correction out of the way, the data is a fairly straightforward set of 38 bits:

Bits Meaning
16 Address
5 Command
17 CRC / error detection code

Auto-sync

Now we have 37 bits that have been error-corrected. At this point we face the auto-synchronization pattern that was added after the bits were encoded. My reading suggests that this is just an xor of the data with a pre-shared pattern known to both the transmitter and receiver [4].

Note: For this section, assume the data is left-aligned as shown below.

Based on known inputs and the helpful fact that the 5-bit command/opcode segment is known for ISW1 of a dual-word ISW [5: Fig 4b], I've determined the mask to be ACE328 for the 21-bit data segment. This is not quite a Barker-7 code [6] but shares similarities to combining several Barker codes in various orders and polarities:

Bits 0-15 16-20 21-37
Meaning Address Command CRC / error detection code
Layout AAAA_AAAA_AAAA_AAAA CCCC_C EEE_EEEE_EEEE_EEEE_EE
Mask 1010_1100_1110_0011 0010_1 Unknown

I've not yet experimented with extending the mask to apply to the 16-bit CRC portion of the ISW.

Error detection

Theoretically, once we finish applying the auto-sync mask, we can then do a CRC or CRC-like operation on the 21-bit data and compare it to the 17-bit error-detection value.

Since this is a different size from the CRC on the OSW, it is likely to be a different polynomial, and will require further research.

Adding automatic demodulation (op25 / DSD-FME)

I've dabbled at changing the SmartNet sync from AC to AA in both op25 and in DSD-FME, but so neither appears to sync and demodulate my actual ISWs. It does increase the noise of "sync" being "found" and getting garbage data though.

I'm hardly an expert in the demodulation logic - if there's something obvious you think I may be missing, please let me know!

Notes

[1] For future reference: this seems to be the sweet spot in SDR++ for recording signals that are usable for URH. Of course, adjust gain to match your setup.

image