DSheirer / sdrtrunk

A cross-platform java application for decoding, monitoring, recording and streaming trunked mobile and related radio protocols using Software Defined Radios (SDR). Website:
GNU General Public License v3.0
1.6k stars 256 forks source link

Add DMR Decoder #6

Closed GoogleCodeExporter closed 4 years ago

GoogleCodeExporter commented 9 years ago
Add decoder support for Digital Mobile Radio/Moto-TRBO decoder.

Original issue reported on code.google.com by dennis.s...@gmail.com on 6 May 2014 at 11:31

GoogleCodeExporter commented 9 years ago

Original comment by dennis.s...@gmail.com on 6 May 2014 at 11:33

spartancain commented 9 years ago

Due to the exceptional breakdown you provide in SDRTrunk of the data stream itself and the specific messages received, SDRTrunk has a very useful professional application as a makeshift test set for digital functionality (as used by a tech stuck without a digital service monitor).

That usage would be greatly enhanced by the ability to view the data stream from a TRBO radio. For that reason, I respectfully request that this enhancement be completed as soon as reasonable possible as you continue to develop this outstanding software.

Thank you for all your hard work. I have only recently begun using SDRTrunk, and I am absolutely bowled over by the quantity of features and the clear dedication, persistence, and skill you have put into developing it. My life as a radio technician with hi-tech hardware to fix and low-tech test hardware to use has been measurably improved by this application. I hope you understand that I ask out of professional eagerness rather than impatience - thanks again.

DSheirer commented 9 years ago

I'm glad it's proving useful for you. Once I get build 0.2.0 finalized, I'll be starting on the DMR decoder next.

truedaystar commented 8 years ago

I have one local dept that user DRM that I would love to decode.. So Add the vote in for me.. I love the software,, I have a little to learn, like calibrating my tuners, but I will get there when I get time to set down and do it.

DrekiDegga commented 5 years ago

I have had my eye on this feature request for some time now and I would just like to say that I would love to be able to use sdrtrunk to decode DMR/mototrbo/capacityplus. Currently there is no good way to do this with available software So if DMR was added to sdrtrunk it would be the only decent option for trunking DMR.

Thanks for the work you do for sdrtrunk.

maozhenyu123 commented 4 years ago

@DSheirer I've been trying to add DMR functionality to sdrtrunk these days, and if possible, I will do TETRA after that.

Basically, I copied part of codes from the P25 phase I because P25 and DMR are similar on modulation level? But with no luck, the DiBits I got did not match with the DMR SYNC.

Since DMR is 4FSK(+/-648HZ, +/-1944HZ) modulated, and P25 is C4FM(+/-600HZ and +/-1800HZ). Does that mean the current DQPSK Demodulator is not going to work with DMR?(If the phase change of 4FSK is not 45°)?

Just wanna get a place to start.

DSheirer commented 4 years ago

Since the deviation of the signal is a little bit wider than P25 C4FM, expand the baseband filter cutoff frequency to ensure the signal isn't being distored.

You may have to change the symbol gain value being passed to the InterpolatingSampleBuffer. Phase 1 decoder uses a value of 0.3 and Phase 2 uses a value of .01

I normally add support for new decoders to the DemodulatorViewerFX application first so that I can visually monitor the performance of the decoder against a real-world signal and I adjust the filter and gain values until I'm happy with the symbol lock-on and tracking performance. The viewer application allows you to manually step through a recording. Warning: the viewer's coding has a lot of warts and is just a dev utility that I use.

maozhenyu123 commented 4 years ago

Since the deviation of the signal is a little bit wider than P25 C4FM, expand the baseband filter cutoff frequency to ensure the signal isn't being distored.

You may have to change the symbol gain value being passed to the InterpolatingSampleBuffer. Phase 1 decoder uses a value of 0.3 and Phase 2 uses a value of .01

I normally add support for new decoders to the DemodulatorViewerFX application first so that I can visually monitor the performance of the decoder against a real-world signal and I adjust the filter and gain values until I'm happy with the symbol lock-on and tracking performance. The viewer application allows you to manually step through a recording. Warning: the viewer's coding has a lot of warts and is just a dev utility that I use.

Awesome, it works!! I set the baseband filter cutoff to be 6100 instead of 5100, now DMR SYNC can be detected. BTW, is the phase change still gonna be 45 degrees(since modulation index is now 0.27 rather than 0.25)

DSheirer commented 4 years ago

The phase change detector(s) work by detecting the sync patterns that will be transmitted when the PLL locks at +/- 90 degrees and 180 degrees. You'll have to create these 3 sync patterns as derivatives from the normal sync pattern.

If you look at the dibit/symbol plots for a normal PLL lock, then imagine rotating the entire constellation of dibits/symbols + or - 90 degrees and 180 degrees to formulate what the derivative sync patterns will be.

maozhenyu123 commented 4 years ago

I've finished a startup at https://github.com/maozhenyu123/sdrtrunk/commit/c88fb9d46207544b490a5d4fadd6c30ae1e8c72e. Now it can recognize different frame and message.

I think I have to do a little bit adjustment to the filter because sometimes it will miss some sync.

DSheirer commented 4 years ago

@maozhenyu123 Wow! You've made a great bit of progress. If I remember correctly, some of the DMR voice frames (b-f) do not have a sync pattern and that might be causing some of the sync loss.

maozhenyu123 commented 4 years ago

@DSheirer Yes, voice frame b-e does not come with a SYNC pattern. But there is still 50%+ chance of missing a VOICE_FRAME_A, which should have a VOICE_SYNC. But it only happened when I am using a mobile radio. I think there might be something wrong with the filter.

DSheirer commented 4 years ago

There's a FilterViewer where you can visualize the parameters that you're using for your filter. Modifiy the getFilter() method and copy your FIRFilterSpecification into that method and it will pop up a graphical display of the filter that's being used.

maozhenyu123 commented 4 years ago

@DSheirer Unfortunately, I am not good at doing things like filter and demodulation (not sure what is the ideal situation even I have a visualization of current filter). If possible, could you plz help me with this.

I am still working at higher level and now it supports CSBK/VLC/TLC parsing/validation and voice frame parsing as well. (I have added ReedSolomon_12_9 and BPTC_196_96 to the edac toolkits for block validation) New commit: https://github.com/maozhenyu123/sdrtrunk/commit/c6d8012b96a28a4d7c2f0f9622daad7cddf7dbc7

DSheirer commented 4 years ago

I should have some time this weekend ... I'll see what I can do.

By the way ... there's already a DMR 3/4 rate Trellis decoder in the code base: ViterbiDecoder_3_4_DMR.

maozhenyu123 commented 4 years ago

Nice. I realized sometime the program lost sync(when there was no transmission) and never got back when there was a new one. But once I restart the channel by clicking "STOP" then "START", it will be able to decode then. Also, I can definitely see some repeating pattern(but just not match with DMR sync), with a period of 288bits(the length of a DMR message). Is that because of the phase error(90 CW, CCW, 180)?

DSheirer commented 4 years ago

You're probably right about the PLL locking on with a phase error. Calculating each of the 3 phase error patterns for each sync pattern is going to produce 27 variants to check.

I had an idea to update the MultiSyncPatternMatcher so that it would only check the sync variants when it was in a lost sync state. That would minimize the overhead of checking all patterns all the time.

maozhenyu123 commented 4 years ago

I am not sure how to calculate a phase error.

DSheirer commented 4 years ago

No worries. I was going to do it and send but ran out of time. I'll try to work on those this weekend and send to you.

DSheirer commented 4 years ago

@maozhenyu123 Here's the phase inversion symbols. I included code and explanations so that you can see how the derived phase inverted sync symbols are calculated.

cheers, Denny Phase Inversion Sync Symbols.txt

maozhenyu123 commented 4 years ago

@DSheirer Unfortunately, none of those sync was detected when there was sync-lost then re-sync. I am trying to figure out why.

ah1102 commented 4 years ago

I would like to see a DMR decoder. On github there is a DSD repository with source codes. You can see how it is implemented there.

maozhenyu123 commented 4 years ago

I would like to see a DMR decoder. On github there is a DSD repository with source codes. You can see how it is implemented there.

Try my branch on https://github.com/maozhenyu123/sdrtrunk/tree/dmr-function

ah1102 commented 4 years ago

Give thanks! But I would like to see DMR in the main branch of the project. Here are all the latest changes.

ah1102 commented 4 years ago

Some errors at the end of the package Снимок экрана 2020-05-07 в 14 12 15

After a short time, the terminal stops displaying the received packet and "CONTROL" stops displaying yellow. Снимок экрана 2020-05-07 в 14 13 02

In the window "Messages" such errors Снимок экрана 2020-05-07 в 14 15 56

My settings Снимок экрана 2020-05-07 в 14 13 18

Such errors still appear if the "messages" window is active Снимок экрана 2020-05-07 в 14 20 08 Снимок экрана 2020-05-07 в 14 21 44

I have never heard voices. Does your decoder support voice? Can you tell me how to configure?

maozhenyu123 commented 4 years ago

Some errors at the end of the package Снимок экрана 2020-05-07 в 14 12 15

After a short time, the terminal stops displaying the received packet and "CONTROL" stops displaying yellow. Снимок экрана 2020-05-07 в 14 13 02

In the window "Messages" such errors Снимок экрана 2020-05-07 в 14 15 56

My settings Снимок экрана 2020-05-07 в 14 13 18

I have never heard voices. Does your decoder support voice? Can you tell me how to configure?

It does support voice. But it seems all data are CSBK-IDLE, which means there is no traffic. If a voice frame comes, it will show something like "Voice Frame A"

ah1102 commented 4 years ago

Are my settings correct? Do you also get these errors or not? Can I listen to two DMR sites at the same time?

maozhenyu123 commented 4 years ago

Are my settings correct? Do you also get these errors or not? Can I listen to two DMR sites at the same time?

My bad, should be fixed now.

ah1102 commented 4 years ago

Now I will rebuild

ah1102 commented 4 years ago

At first everything was fine, and then the output of packages in the linux terminal stopped, and in the sdrtrunk window this appeared Снимок экрана 2020-05-07 в 14 36 27

If I click "Stop" and then "Start", the output resumes and after a few seconds it stops again.

What could be the problem?

maozhenyu123 commented 4 years ago

Is there any transmission on the spectrum? I realized when the transmission stopped at first time, the decoder might not work after that if you do not restart it because it's not detecting SYNC anymore. That might be a PLL problem but I don't know how to fix it

ah1102 commented 4 years ago

Probably so, for clarity

Снимок экрана 2020-05-07 в 14 43 22

maozhenyu123 commented 4 years ago

BTW, this program does not decode the signal from my mobile station. The demodulation does not correctly worked as I expected. I think I will need to ask someone for help.

ah1102 commented 4 years ago

I am just learning programming. Tell me, does lsm or c4fm mode matter in your dmr decoder, what should I choose from the list?

maozhenyu123 commented 4 years ago

No, DMR use 4FSK.

ah1102 commented 4 years ago

Apparently, when a voice appears, such packets go, but I don’t hear anything. I have JMBE 1.0.4 and P25 is decoded.

Снимок экрана 2020-05-07 в 15 23 04

maozhenyu123 commented 4 years ago

This is not a voice frame but a control frame. The actual voice should be located at the channel assigned according to this control frame.

ah1102 commented 4 years ago

I don’t know, some mistakes are coming. What could it be? I tried to change the frequency +/-, but it did not bring any result.

Снимок экрана 2020-05-07 в 15 28 58

maozhenyu123 commented 4 years ago

Hmm, interesting. This is a voice frame but seems not valid(may be encrypted?). This release does not come with encryption detection.

Maybe not? I will check it out this afternoon.

ah1102 commented 4 years ago

I checked with dsd and there the voice is not encrypted. Снимок экрана 2020-05-07 в 15 47 43

ah1102 commented 4 years ago

And you have implemented the function: - non / inverted DMR / MOTOTRBO signal ?

Can you check how and compare how it is implemented in dsd https://github.com/szechyjs/dsd? There is a wiki where you can read

He can talk with the author of this project https://github.com/moneriomaa/openear He is actively responding.

ah1102 commented 4 years ago

It seems that the DMR, in which firefighters work in our city, does not demodulate your decoder. But he demodulates the ham radio in DMR. But in both cases, I see errors in java files in the terminal. It must be modified. Because DSD demodulates everyone in the DMR.

ah1102 commented 4 years ago

So I found another DMR decoder project - https://github.com/IanWraith/DMRDecode. This is the same DSD rewritten from "C" to "Java". DMR decoder program itself, the audio device does not switch, so I can’t even check it. Then, it is not clear where the program outputs the sound.

You can use an example of this code. As far as I know, this code has no copyright.

Снимок экрана 2020-05-09 в 09 02 28

cmartus commented 4 years ago

I've done some testing with the dmr-function-denny-edits2 branch and get errors along the line of encrypted voice. Using an AnyTone D868UV, Simplex TS1 TG99.

ERROR i.g.d.d.f.c.o.ChannelOutputProcessor - Error while processing polyphase channel samples [155MB/321MB 48%] java.lang.NullPointerException: null at io.github.dsheirer.edac.ReedSolomon_12_9.checkReedSolomon(ReedSolomon_12_9.java:320) at io.github.dsheirer.module.decode.dmr.message.data.lc.LCMessageFactory.createFull(LCMessageFactory.java:49) at io.github.dsheirer.module.decode.dmr.message.data.DataMessageWithLinkControl.getLCMessage(DataMessageWithLinkControl.java:61) at io.github.dsheirer.module.decode.dmr.message.data.DataMessageWithLinkControl.getIdentifiers(DataMessageWithLinkControl.java:79) at io.github.dsheirer.alias.action.AliasActionManager.receive(AliasActionManager.java:58) at io.github.dsheirer.alias.action.AliasActionManager.receive(AliasActionManager.java:43) at io.github.dsheirer.sample.Broadcaster.broadcast(Broadcaster.java:152) at io.github.dsheirer.sample.Broadcaster.receive(Broadcaster.java:59) at io.github.dsheirer.module.decode.Decoder$MessageDistributor.receive(Decoder.java:103) at io.github.dsheirer.module.decode.Decoder$MessageDistributor.receive(Decoder.java:96) at io.github.dsheirer.module.decode.dmr.DMRMessageProcessor.dispatch(DMRMessageProcessor.java:104) at io.github.dsheirer.module.decode.dmr.DMRMessageProcessor.receive(DMRMessageProcessor.java:61) at io.github.dsheirer.module.decode.dmr.DMRMessageProcessor.receive(DMRMessageProcessor.java:39) at io.github.dsheirer.module.decode.dmr.DMRMessageFramer.processDataBurst(DMRMessageFramer.java:316) at io.github.dsheirer.module.decode.dmr.DMRMessageFramer.burstDetectedWithSync(DMRMessageFramer.java:334) at io.github.dsheirer.module.decode.dmr.DMRBurstDetector.parseBurst(DMRBurstDetector.java:123) at io.github.dsheirer.module.decode.dmr.DMRBurstDetector.syncDetected(DMRBurstDetector.java:71) at io.github.dsheirer.bits.DMRSoftSyncDetector.checkSync(DMRSoftSyncDetector.java:59) at io.github.dsheirer.bits.MultiSyncPatternMatcher.receive(MultiSyncPatternMatcher.java:96) at io.github.dsheirer.module.decode.dmr.DMRSyncDetector.receive(DMRSyncDetector.java:128) at io.github.dsheirer.module.decode.dmr.DMRBurstDetector.receive(DMRBurstDetector.java:98) at io.github.dsheirer.module.decode.dmr.DMRMessageFramer.receive(DMRMessageFramer.java:180) at io.github.dsheirer.module.decode.dmr.DMRMessageFramer.receive(DMRMessageFramer.java:54) at io.github.dsheirer.sample.Broadcaster.broadcast(Broadcaster.java:152) at io.github.dsheirer.sample.Broadcaster.receive(Broadcaster.java:59) at io.github.dsheirer.dsp.psk.PSKDemodulator.broadcast(PSKDemodulator.java:58) at io.github.dsheirer.dsp.psk.DQPSKDecisionDirectedDemodulator.calculateSymbol(DQPSKDecisionDirectedDemodulator.java:88) at io.github.dsheirer.dsp.psk.PSKDemodulator.receive(PSKDemodulator.java:115) at io.github.dsheirer.dsp.psk.PSKDemodulator.receive(PSKDemodulator.java:89) at io.github.dsheirer.module.decode.dmr.DMRStandardDecoder.receive(DMRStandardDecoder.java:109) at io.github.dsheirer.module.decode.dmr.DMRStandardDecoder.receive(DMRStandardDecoder.java:43) at io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster.broadcast(ReusableBufferBroadcaster.java:42) at io.github.dsheirer.sample.buffer.ReusableBufferBroadcaster.broadcast(ReusableBufferBroadcaster.java:23) at io.github.dsheirer.sample.Broadcaster.receive(Broadcaster.java:59) at io.github.dsheirer.sample.buffer.ReusableComplexBufferAssembler.flush(ReusableComplexBufferAssembler.java:158) at io.github.dsheirer.sample.buffer.ReusableComplexBufferAssembler.receive(ReusableComplexBufferAssembler.java:132) at io.github.dsheirer.sample.buffer.ReusableComplexBufferAssembler.receive(ReusableComplexBufferAssembler.java:144) at io.github.dsheirer.dsp.filter.channelizer.output.OneChannelOutputProcessor.process(OneChannelOutputProcessor.java:97) at io.github.dsheirer.dsp.filter.channelizer.output.ChannelOutputProcessor.processChannelResults(ChannelOutputProcessor.java:124) at io.github.dsheirer.dsp.filter.channelizer.PolyphaseChannelSource.processSamples(PolyphaseChannelSource.java:248) at io.github.dsheirer.source.tuner.channel.TunerChannelSource$ScheduledIntervalProcessor.run(TunerChannelSource.java:321) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305) at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:830)