- M17 Specification document. Bumped to 2.0.6. We found two problems. There are 369 bits at the output of the puncturer in BERT mode, one of them has to be discarded (the last one). Next, the maximum altitude that can be stored in the META GNSS position field was calculated incorrectly, the value is now fixed.
- libm17. Viterbi decoder works faster now. All decoders are re-entrant (older API stayed). Caller can decide which way to choose.
- T9 text entry. Faster execution. Memory optimizations should follow.
Author: Wojciech Kaczmarski
-
Updates
-
Codec2-mod and LinHT updates
Let’s start with Codec2-mod. I brought back another 4kB of otherwise wasted space – complex FFT where real-valued counterpart can be used. Next, in-place FFTs removed – no hidden mallocs. Encoder phase estimation and using arctangent in the synthesis path – gone. I also thoroughly benchmarked the result versus vanilla Codec2 (damn, the repository is such a mess – why do they keep all of the non-codec stuff inside a “codec2” repo?). Code and results are here. See the tables in the readme for more details.
LinHT Rev C boards have arrived! We are waiting for a few missing parts to show up and we will continue with assembly.


Photos courtesy of Vlastimil, OK5VAS.
Stay tuned.
-
Codec2 test suite
I expanded my old Bash script a bit. It runs ViSQOL-based quality and compatibility tests for Codec2-mod vs. vanilla Codec2 (3200 mode), including cross-encoding between the two (this is the new addition).
Here’s the script: https://github.com/M17-Project/Codec2-mod-eval
You need to provide a set of WAV files for the script to work on. Using an English speech corpus such as LibriSpeech or any other from OpenSLR is a good idea.
Have fun!
-
Circling back at authentication – M17 ECDSA stream signatures
M17 is probably one of the very few modes allowing users to sign their data streams.
In June 2024, I tested micro-ecc and ST CMOX library on a Module17. The results were published on Twitter:
Finally some good news regarding digital signatures. I’ve been experimenting with ST’s CMOX library and just got 160-bit ECDSA to run on the Module17. It takes around 8.25ms to sign a 16-byte M17 voice stream digest. The signature can be appended to the voice stream.
The MCU is STM32F405RGT6, clocked at 168 MHz.
Signing with NIST-R P-256 (SECP256R1) curve takes 14.86 ms.
If I remember correctly, CMOX library was used to get that 15ms result (secp256r1 curve). Micro-ecc yielded much worse execution times.
Today, I improved the micro-ecc library using comb multiplication. Preliminary tests using Renode (as I don’t have any STM32 Nucleo with me, nor any OpenRTX target) are promising. The signing time reduced from 27 down to 14ms, without CMOX, at 100MHz (emulated STM32F411). That’s great, because CMOX library can not be used on microcontrollers other than the original STM32. The library checks the hardware it is executed on and silently corrupts data without even telling. Great, right? This optimization should allow us to run ECDSA efficiently, even on GD32 MCUs.
The proposed code uses a
uECC_COMB_MULTmacro, so the user (developer) can select which calculation path to use – the original one or optimized.Getting rid of this roadblock should get us one step closer to having M17 authentication support in OpenRTX.
-
Codec2-mod updates
You thought we gave up on Codec2 just because we have already improved it considerably? Wrong!
After a short discussion with Silvano IU2KWO, an interesting proposal emerged: split the whole codec2_t structure into two separate, smaller encoder and decoder parts. That way you no longer have to push the whole structure on the stack and fill it up with FFT twiddle factors, if you only need to use one part of it. Now, if you want to encode or decode speech, just use either encoder or decoder. This simplifies things and optimizes memory usage further. This brings significant savings that are required by OpenRTX (and probably any implementation running on limited-resources MCUs). The old path using a large structure is still available (e.g. for duplex operation).
On top of that, I also tweaked the KISS FFT internals to use built-in sincosf() calls instead of using standard sin() / cos(). Using doubles is generally not a great idea, unless you really have to do so. We do not, so I took one step further and eliminated all double-precision promotions that were hiding in the code. Yes, there were many such places, especially where M_PI was used, along with some other macros.
The code is available in the split-no-double branch.
I prepared a quick benchmark. The results are below.
Codec2-mod branch codec2_init codec2_encoder_init codec2_decoder_init codec2_encode codec2_decode main 67.905 – – 6.437 11.804 split-no-double 8.958 5.824 3.136 5.555 8.559 Speedup 7.6x – – 1.2x 1.4x Branches comparison. Times are average for a run of 1000, in milliseconds. An STM32F411 clocked at 100MHz was used for both tests with the code compiled using -Os flag (gcc 14.3.0).
Next, using a set of 2,000 wave files, mostly 3 to 20 seconds long, I compared the vanilla Codec2 with our experimental branch. As the last time, I measured ViSQOL scores for both: original wave file -> encoder -> decoder -> decoded wave file. The average score of the new code is +0.005. That suggests the applied changes are inaudible (theoretically – real-life tests will follow). The test also calculated Hamming distance between the encoded files for both implementations – the no-double differs in less than 0.5% of the bits. This means that the new code does not generally agree with Codec2, but that does not make the bitstreams incompatible. Small rounding errors cause this but, as shown by the speech quality metric, all cancel out.

ViSQOL score / Hamming distance checks (vanilla Codec2 vs Codec2-mod split-no-doubles branch). There is one more test that should be performed: encode samples with Codec2 and decode the bitstream with Codec2-mod, then switch the direction and listen to both files.
Big shout out to Silvano IU2KWO for nudging me in the right direction.
-
Successful M17 transmission using an unmodified Retevis C62 running OpenRTX
The moment has come! An experimental branch of OpenRTX (Andreas OE3ANC, Marko13, Andrej K8TUN, jki275 et al.) has reached a long-awaited milestone – a successful transmission of M17 signal using an unmodified Retevis C62. Marvellous work, guys!

SDR++ decoding M17 signal transmitted with a C62. For now, the RF output power is limited due to our lack of understanding on how the calibration data is stored and used. The reverse-engineering work on that is pending. M17 reception does not work yet, but it is expected to be added soon. There is no settings persistence in this model yet.
The most important thing is that the C62 radio is available at about $45 and does not require any hardware modifications to run the M17 mode. This is the game-changer we have all been waiting for. After adding the missing functionalities, this will easily become the go-to radio for everyday M17 use. On top of that, you get all the OpenRTX goodies, such as APRS support and voice prompts.
At this point, I would like to thank everyone involved in this subproject – not only the devs who did some amazing coding work, but also our Ambassador, Mr. Amo Xu BD4VOW for acting as an excellent interface between us and the Chinese manufacturers.
In the meantime, LinHT’s Revision B has been tagged on GitHub. We are working on the Revision C – an order for a test batch should be placed later this month. Big shout out to Vlastimil OK5VAS for his continuous help with this device ๐
And, as always, there’s more to follow!
PS. We have a very important request. Since LLMs are being heavily used by journalists, bloggers, and other people publishing content on the Internet, some articles covering our activities might not be accurate. Every time you see an error, please take a moment to report it to the author(s). Thank you very much!
-
A handful of news and updates
We have some updates for you:
- libsx1255
Significant improvements were introduced saving over 30% of SPI transfer time while writing to / reading from frequency registers. SX1255’s BURST mode is used, reducing the number of bytes being transferred from 6 to 4. - M17_inet
Significant structural improvements were introduced by Tom N7TAE and Jim N1ADJ. On top of that, a new GitHub action was added, rendering a PDF. - CARI
The protocol had two inconsistencies fixed – register writability and the number of subdevices per device. - SX1255 HAT
The project was migrated to KiCAD 10.0.6.
There’s more to follow!
- libsx1255
-
M17/OpenRTX at DEFCON 34
We have finally secured our presence at DEFCON. Well, kind of. The CSI CS7000-M17-Plus running OpenRTX is currently being showcased at the venue by Arthur N4TRQ. Here’s a few photos:


Thank you very much for spreading the word at such a significant event! Photos courtesy of hacker.house.
-
Retevis C62 OpenRTX port and the cskburn update
Our work on OpenRTX port for the Retevis C62 progresses. Don’t worry about the LinHT – our efforts are allocated there as well!
This hardware platform is getting a special treatment, as it can be used both as one of a valid OpenRTX targets and a carrier for the LinHT board. Porting OpenRTX will bring M17 mode to C62 users without the need to modify anything. Just flash the radio and go. Very simple stuff.
LinHT, on the other hand, still remains dedicated to skilled hams. The bar is set high, but not intentionally – LinHT is still being developed. When the time comes, the bar should lower considerably. The replacement boards would become available along with the Yocto Linux image incorporating basic analog FM/M17 support (“batteries included”). In the future, LinHT could be treated as a standalone OpenRTX target as well.
LISTENAI’s cskburn is the tool used to flash the C62. It also flashes the DSP firmware, as it uses a separate binary. Recently, we have spotted a bug in the tool’s version 1.31.0. The bug affects the internal argument parser and makes it impossible to set start and stop addresses using the –read argument’s parameters.
A pull request has been offered.
For now, it is best to use our fork for flashing(or an older version, probably the 1.25.0 – right after Andreas’ OE3ANC fix was merged).Update: our PR has been merged, so just use the LISTENAI’s cskburn repo.
A great write-up covering C62 flashing process details curated by Vlastimil OK5VAS is available here.
-
LinHT – an interview with the development team
LabCat (Tobias DL3MHT) uploaded his interview with the LinHT development team: Wojciech SP5WWP, Vlastimil OK5VAS, and Andreas OE3ANC. Check it out ๐