A Minimal ASL Node Without Asterisk Dependency (R&D)

I was doing some audio testing and noticed something very interesting, and highly relevant to the question of the necessity for 16K sample rates on AllStar / ROIP / VOIP.

Usually when you do an audio test with AllStar, you just do a parrot test, your audio is played back, and if it resembles your transmission closely enough and levels are in range then you assume all is good and move on. What people do not tend to do with AllStar however when doing an audio test is monitor the audio from an independent RF receiver, which will capture both your original RF signal and the parroted audio, making it very easy to then compare the two and see what exact coloration, distortion, level changes, etc. are being introduced.

Here is just a quick graph of the frequency response of a ~10 second test message that I transmitted from one HT (KG-Q10H), into a node with an RT85 HT, and then had another Retevis HT receiving from both and recording into a Win PC audio editor. If I were to do this with white noise the graph would then be of the actual frequency response but even just with a normal voice test signal it’s very clear that the output from the node (red curve) drops to zero by 3.3KHz whereas the input signal from my HT on RF (green curve) has frequency content out to 5KHz.

I had noticed before that audio direct from one radio to another definitely sounds clearer than audio echoed back from ASL, but previously just assumed oh well that’s “just how it works”. This is a tendency of users and developers of any large system - there is inertia in the ways that things are in legacy systems and it takes a somewhat significant exogenous force sometimes for people to see that something in a system they are used to could actually be highly non-optimal.

20 years ago, 8K sample rates for VOIP/ROIP were “good enough” for the CPU power and network bandwidth limitations of the era, people became accustomed to that sound, and only a few audiophile / pro-audio types like Patrick and I ever thought anything of it.

After having now more carefully compared the differences in actual audio over RF from the radio going into a node vs. the audio transmitted from a node, I have to say that 8K sample rates no longer make sense in 2026, and should be obsoleted at the earliest opportunity.

As is clear in the above graph there is very significant frequency content and information out to at least 4.8 KHz, that is completely lost by ASL. The difference in clarity between the input and output signals really is pretty major when you listen to it. I could post example audio clips here but I think it’s better if people try it for themselves. Just take any HT or radio, run the speaker out jack into an audio interface / URI and record into a PC audio recording program (at 48KHz 16-bit). (Any of my URIs work great for this as they are fully functional Win/Mac/Linux audio interfaces).

There seems to be a belief that FM transmitters do very sharp filtering that limits audio bandwidth to ~3.5KHz but in reality that filtering is not overly sharp and there is quite a lot of detail on FM audio out to 5KHz. And it seems to be a common belief that anything above ~3.5KHz isn’t important, but that is also not true, and I would encourage everyone to listen for yourself to the difference in the actual audio going into your node or repeater system etc. vs. what it then plays back or sends out over the network.

Presumably 16Ksps audio is not going to happen soon in ASL3, so once &-ASL supports the basic functions used in AllScan nodes ie. DTMF commands, text-to-speech, easy updates, web dashboard with WiFi management support, etc. I will start offering &-ASL as an option in my node builds.

Could this be used on a T-Twr (T-TWR REV2.1 – LILYGO®) to turn it into an ASL hotspot?

Hi Jeff: I’m not familiar with the T-TWR. I found a schematic but it’s pretty hard to follow so I’m not completely sure how the ESP32 and radio module are interconnected. If someone has a schematic that shows the connections to the ESP32 (page 1, upper left) I’d be interested in taking a look.

Given the capabilities that are claimed on the datasheet, I think it’s very likely that you could build an ASL hotspot using this hardware. Whether the RF/audio performance is any good would need to be tested. Those NiceRF modules are targeted at mass-market walkie-talkies. That said, I’ve been amazed by how many people run their ASL nodes on the NiceRF SA818 module (SHARI and derivatives). I’m no connoisseur so do what makes you happy.

I’ve been doing a lot of work to get the Ampersand kernel running on a microcontroller. My development target is ARM (RP2350/Pico). However, the capabilities of the ESP32-S3 chip used in the T-TWR are pretty similar so I suspect it’s doable. I want to get RP2350 and the STM32 working well before I start spending time on the ESP32. It’s a completely different development platform. Stay tuned.

This week I did some more work on the Ampersand microcontroller implementation which I call Microamp. This short video shows the first working test of a call into an AllStar parrot node. The production quality of the video leaves something to be desired - I’ll try to make a better one.

This demo shows something I’ve been hoping to achieve since I started this project in October: an AllStarLink node running with no dependency on Asterisk or Linux.

The node runs on the green Pico W board in the foreground of the video. That board has an RP2040 (150 MHz ARM Cortex-M0) and an Infineon CYW43 WIFI radio. Audio output is produced by a MAX98357A I2S IC that can drive about 2.5 watts into a speaker. Audio input is captured using an INMP441 digital MEMS I2S microphone. The entire system runs from a 3.3V power supply.

The code is a subset of what is used in the Linux/Windows implementation, except for a bare-metal UDP sockets library that obviously isn’t needed on Linux. The node can’t accept inbound calls yet because it can’t register itself - that requires TCP capability that I don’t have yet. There is a UDP way of registering that is used by HamVOIP nodes that I might try first just to get things going, but the plan is to use HTTP registration.

There are some other computers on the bench in the video (Pi5, desktop PC) but those are just to support the flash process and the debug probe.

Next I’m going to switch to the 16K CODEC and setup some better quality audio components to show that audio quality doesn’t need to be compromised.

The Pico W is $6.00, the MAX98357A + speaker is $6.25 and the INMP441 is $2.60.

I did some work on SA818/SHARI-like devices this week. I started off with an AURSINC Shari device that, uhhh, a friend bought. But then Marshall KE6PCV was kind enough to send me two devices from the HotSpot Radio product line. Given how many hams I’ve encountered who are using AllStar with some form of SA818 radio it seemed like a worthwhile thing to experiment with.

I’m sure plenty of people have done product reviews of these devices so I don’t need to get into that. The two Hotspot Radio devices Marshall sent (HotSpotRadio USB and the USB Duplex Repeater) have a much better build quality than the AURSINK Shari and I’m sure the nice folks who operate on the 880 MHz band appreciate the 5th order harmonic filter on those boards. Unless I’m missing something the AURSICK device seems to jump right to the antenna connector. The noise floor is also lower on the HotSpot Radio devices from my rudimentary test.

I did some work to allow the SA818 serial programming to happen directly from my node configuration screen. Actually, the HotSpot Radio duplex repeater has two SA818 modules so I created the ability to save/load two independent radio configurations (see below). Having a duplex hotspot is really nice.

One thing I noticed about the SA818 is that there is a slight delay on key-down. From what I’ve read, this is a known problem with the module and is possibly related to power-saving modes. It’s not a huge deal, but it can cut off the very beginning of a transmission in certain cases. I did some work to address this which I’ll describe in a separate post about TX/RX delay. The SA818 firmware version was different between the AURSNIC and HotSpot Radio units but that didn’t seem to make much of a difference as far as key-down speed.

I needed to make a few other changes to my code to support these hot-spots, but overall they provide a decent way to get a radio link to AllStar. I’m no connoisseur, but the audio quality sounded fine to me.

One thing that helps a little with the duplex board is to set the squelch to 0 on the transmit radio, no CTCSS decoding. BTW, is he running version 1.2 firmware on those radios yet? If so, are you programming those radios flat, i.e. with emphasis and HPF/LPF disabled, and compensating for that in your code? That's the way to get the best audio out of a version 1.2 SA818 radio. You can even do software based CTCSS encode and decode, which works a lot better than the deck on the SA818, at least in my opinion using the DSP stuff from ASL three’s usbradio channel.

Thanks Patrick, this is interesting.

The HotSpot Radio units that I have report V1.1 on the NiceRF firmware. I am programming the radios with emphasis/deemphasis enabled and the HPF/LPF disabled. I am using the on-module CTCSS encode/decode.

Given what you are saying, I’m going to add the filter settings to my screen so that they are user-settable and reconfigure and repeat all of the tests with the setup you’ve recommended. This will provide a good chance to test my DSP stuff. And since I have all of these units on the bench I should probably do a real passband analysis to see how the whole system behaves.

There is a bug with V1.1 where you can’t actually disable the HPF in the radio for more than one receive or transmit cycle, so you can’t get discriminator audio out of it, but those settings will still be useful for testing your DSP, since that is still more optimal even with the HPF in-place on the radio. This was fixed with V1.2 for generic sa818’s. If you have a genuine Kits4Hams SHARI, that’s version 5.5 of the custom firmware for those radios which has that fix. There are probably other variations with clones or whatever, but who knows?

After many in-depth discussions over the past few months with numerous people on the above and related topics I just thought I would add a few additional notes.

  • Re. ASL3, which is indirectly a topic of this thread, I wanted to summarize what I would see as the top priorities - in order - for ASL3 if it is to not become obsolete in the next couple years.
  1. IPV6 support, to address CGNAT issues that are becoming more common.
  2. Full support for node metadata over IAX such that it is possible to know what nodes are connected and what nodes are keyed up at any point in time - regardless of how many intermediary nodes they may be connected through.
  3. 16Ksps codec support, and cleaning up the channel driver filtering code accordingly.
  • Re. SA818 modules, to sum it up, the SA818 is a consumer-grade module with low audio SNR (40dB stated), low power output and a number of issues. Similarly, in my experience all Japanese brands of HTs are pretty much consumer-grade toys. Yes even the fancy $600+ DSTAR HTs. This stuff is all going to be obsolete within a couple years.

  • Re. simplex nodes, these conceptually are also consumer-grade toys. The idea that people are using nodes on a repeater linking system, that cannot be keyed up after the repeater’s courtesy tone, instead requiring a full carrier drop, just seems silly.

There are fortunately better options, such as my ANF101 cross-band full-duplex design (for which a URI and mounting plate are only $89 or a complete node radio module only $149), and the Wouxun KG-9 and KG-10 series of HTs. Demo of these in action - https://youtu.be/Qy_7CWG2Dvs

Not to drift off the original topic, but I am also playing with a few HSR duplex nodes here as well, and had a few observations to mention, and a few resulting questions.

When I run the sa818 version command, the modules report SA818s ver 1.1.
Is version 1.1 of the SA818s actually newer and improved over the original SA818 modules? Another words, do the "s" version 1.1 modules have some of the fixes the later non "s" module firmware versions addressed?

Do the SA818s modules exhibit the same issue with the HPF re-enabling itself?

Can the firmware be updated in the modules via the normal programming mechanism, or does it require the modules to be accessed another way?

One thing I noticed is that the decode timing of the internal CTCSS decoder is very slow. To the point where it is causing the first 100-200ms of a transmission to be missed. If the put the module in carrier squelch there is a noticeable improvement.

The overall audio quality is pretty good for what it is. Listening to the audio out of the HSR and comparing it to a newer generation Motorola SLR repeater exciter, while both are connected to the same source (node), the HSR sounds pretty close. Maybe not as good as an old Micor FM exciter, but good enough by today's standards.

Eric
K2CB

#1 on your list is already in progress.

#2 There's a forthcoming discussion on this. There's been a lot of developer discussion on the this and if the value for the implementation, the potential for incompatability, and the network traffic generated is going to be worth it.

#3 IIRC, the biggest limitation to 16k codec support was using DAHDI correct? That's removed in the next major release. If you have any code for changes to chan_usbradio or chan_simpleuse please open a PR.

sa818 V1.1 firmware has the high pass filter bug, and you can’t update the firmware yourself, because Nice RF doesn’t give firmware to anyone. Even if you could, it would require soldering a J-Tag interface to the module.

I have a couple of V1.2 radios. The slow decoding problem is mitigated by putting the radio in carrier squelch, setting squelch to 0, and using usbradio to do the CTCSS encoding and decoding, but you can’t do that with a V1.1 radios because of the high pass problem.

It’s also worth noting that falsing is a pretty big problem with the sa818’s implementation of CTCSS as well, and the logic is terrible. Once it opens, it won’t close again even if the tone disappears until the signal drops under a certain threshold. All things that usbradio’s DSP can fix, assuming you have a V1.2 radio.

OK, this is good timing because I’ve been doing a lot of work on my timing/state machines stuff lately. This is tedious, but the recent conversations have helped me to understand the requirements a bit better. Not saying I’m 100% there, which is the point of this message.

I’m not trying to do formal software requirements analysis here because I’m sure nobody wants to be bothered by that. However, I have tried to write down a clear statement of how my code is built at the moment. I provide this so that the repeater aficionados can comment/criticize and help to get this right. I’m particularly interested in what Patrick N2DYI has to say on this since he’s given me a lot of input already, but anyone who has experience with repeater behavior should jump in.

I know there is a related set of requirements related to duplex modes - that’s for a different thread. Here I’m just trying to get the transmit/receive timers right. This message is split into two parts: one for the transmit path and one for the receive path. I hope that helps to keep things straight.

If you have the patience to think about this, thank you! If not, I totally understand - this is repeater nerd stuff.

Transmit Path

Goals

  • Prevent the first part of a transmission from being clipped off, even in cases where the radio’s key-up behavior is slow (ex: SA818 modules, but maybe other radios). Try to move away from having to tell everyone to wait for a few seconds at the beginning of their transmissions to allow a transmitter to key up (this delay should be provided automatically if the hardware requires it).

  • Provide a hang time at the end of a transmission to prevent excessive key up/key down.

  • Provide support for a “chicken interval” at the end of a transmission during which the CTCSS tone is either turned off, phase-reversed, or changed to another arbitrary frequency in the brief interval before the transmitter is unkeyed.

  • Keep audio latency to a minimum.

  • Operate independently of the receive path to maintain flexibility with respect to duplex modes

Parameters

  • CTCSS encoder on/off

  • CTCSS break mode (chicken, reverse, secondary frequency)

  • Keyup interval

  • Hang interval

  • Chicken interval (Time between CTCSS break and unkeying)

All intervals are in milliseconds. Any of the intervals can be set to zero to disable the relevant feature.

Transmit System Logic/State Machine

We start in the idle state.

While in the Idle State:

  • The PTT signal is deasserted and the CTCSS encoder is off.
  • If audio is received from the conference it is pushed onto the back of the delay line and we enter pre-transmit mode.

While In Pre-Transmit Mode:

  • The PTT signal is asserted and the CTCSS encoder is in normal mode (if enabled).
  • Any audio received from the conference is pushed onto the back of the delay line.
  • Pre-transmit mode lasts for the time defined by the keyup interval. Once this interval expires we enter transmit mode.

While in Transmit Mode:

  • The PTT signal is asserted and the CTCSS encoder is in normal mode (if enabled).
  • Any audio received from the conference is pushed onto the back of the delay line.
  • Any audio on the delay line is popped from the front and sent to the radio.
  • Once the delay line is completely empty we enter the hang state.

While in Hang State:

  • The PTT signal is asserted and the CTCSS encoder is in normal mode (if enabled).
  • The hang state lasts as long as the hang interval. Once this interval expires we enter the chicken state.
  • Any audio received from the conference is pushed onto the back of the delay line and we re-enter the transmit state. It is important to note that we bypass the pre-transmit state in this case. No further audio delay is needed since the transmitter is already keyed up.

While in Chicken State:

  • The PTT signal is asserted and the CTCSS encoder is in off/reverse/alternate frequency mode according to the configuration.
  • If any audio is received from the conference it is pushed onto the back of the delay line.
  • The chicken state lasts for the chicken interval. Once this interval expires we enter the idle state.

Receive Path

Goals

  • Avoid losing the beginning part of any legit transmission.

  • Avoid contributing a crash into the conference at the tail of a transmission.

  • Debounce the COS/CTCSS signals to avoid false detects.

  • Provide optional kerchunk suppression to prevent short transmissions (<2 seconds) from being contributed to the conference. Note that a short transmission that closely follows other legit traffic is not considered to be a kerchunk.

  • Keep latency to a minimum.

  • Operate independently of the transmit path to maintain flexibility with respect to duplex modes

Configuration Parameters

  • Squelch type parameter that determines whether to use carrier squelch, tone squelch, or both.

  • Debounce Interval

  • Squelch Tail Interval

  • Kerchunk Interval

  • Idle Interval

All intervals are in milliseconds. Any of the intervals can be set to zero to disable the relevant feature.

Receive System Logic/State Machine

The system contains an audio delay line. Audio can be pushed onto the back of the delay line per the conditions below. Audio will be popped off the front of the delay line and sent to the conference whenever the audio gate is opened. If the audio gate is closed then audio just accumulates in the delay line.

We start in the idle state with the audio gate closed.

While in the Idle State:

  • Any audio received from the radio is ignored.
  • If the COS and/or CTCSS are asserted (according to the squelch type) we enter the assessment state.

While in the Assessment State:

  • Any audio received from the radio is pushed onto the back of the delay line. We don’t want to lose anything while we assess whether this is a legitimate transmission.
  • The assessment state lasts for the longer of the debounce interval or the kerchunk interval. If we have been in the receive state recently (where “recently” is defined by the idle interval), the kerchunk interval is ignored in this condition and we only consider the debounce interval. We do this because the kerchunk interval is probably fairly long (a few seconds) and we don’t want to carry this much latency once a legit QSO is up and running.
  • If the COS and/or CTCSS signals are deasserted (according to the squelch type) we enter the idle state and the delay line is flushed. The assumption in this case is that this was not a legit transmission and no audio was ever contributed to the conference.
  • Once the assessment state has expired we open the audio gate and enter the receive state.
  • Delayed audio now starts to flow into the conference.

While in the Receive State:

  • Any audio received from the radio is pushed onto the back of the delay line.
  • If the COS and/or CTCSS signals are deasserted (according to the squelch type) we trim audio from the back of the delay line by the equivalent of the squelch tail interval. The assumption is that the last part of any received audio just prior to the COS/CTCSS drop is a crash. For example, if the squelch tail interval was set to 200ms, 10 20ms frames of audio will be trimmed from the back of the delay line.
  • After this trim has been performed we move to the drain state. Note that delayed audio is still flowing out to the conference since the gate is still opened.

While in the Drain State:

  • Any audio received from the radio is ignored.
  • Once the delay line is completely empty we close the audio gate and enter the idle state.
  • If the COS and/or CTCSS signals are asserted (according to the squelch type) we enter the assessment state.

Bruce:

This all looks pretty good to me, but, believe it or not, I don’t actually operate a repeater. I just observe things.

I do have one question though:

How do you use both carrier squelch and tone squelch at the same time? You indicated that could be a possibility, and that doesn’t really make sense to me in this context.

One thing that has always bugged me about how app_rpt works, regarding hang times, is in relation to ID’s and telemetry.

Let’s say you have a five second hang time. Someone has unkeyed the repeater, which now has to ID. In many cases, it will get all the way to the end of five seconds, ID, then hang for another five seconds.

Same goes for auto-ID’s that occur when the repeater hasn’t been keyed for a while. There is no real need for all that extra hang in that context.

I have never seen a hardware-based repeater controller behave like that. Generally, they either have an alternate hang time specifically for ID’s, or not at all.

So, in this way, I would probably also include specific timing logic for telemetry that is not local or remote voice transmission.

Also, make it optional to only send a tone when voice transmission is received, going to chicken state at the end of the delay, but before the hang, so that if you want your repeater to have courtesy tones and telemetry, but you want to have the ability for the end-user to not hear any of that, the gated tone will keep those sorts of things from opening the user’s squelch.

Great, thanks Patrick. I’m glad I’m somewhat close. A few things here:

You’re right, that doesn’t make sense. I’ll change it, assuming that tone squelch is a superset of carrier squelch.

I’ll make sure that there is no extra hang following an ID.

This one went over my head I think. Perhaps what you are talking about is having the option to have the machine-synthesized sounds in the node (TTS?) go out to the ASL network but not out the local radio transmitter?

Not quite. What I am suggesting is have the node transmit synthesized speech, tones, ID’s, etc. but with no tone. In other words, only send the tone when voice is present, not for anything else when this option is enabled.

Result:

A receiving radio will immediately close squelch when audio is no longer being received. If there is a courtesy tone, it will play, hang time, then the radio’s transmitter drops out, but during all that time, there is no tone, so the receiving radio doesn’t hear it unless decoding is turned off.

This is a pretty common setup for RF linking, where it isn’t desired for telemetry to go down the link, but is also useful when, for example, using cross-band repeat to access a local repeater from a mobile radio via an HT. It avoids the user having to wait for the repeater’s transmitter to drop before keying, even in a half duplex situation.

Thanks for that clarification Patrick, I understand your requirement now and I can build that option.

Would it be better to just add an option on each radio interface called something like “Transmit Conference Audio Only?” Or alternately “Suppress Telemetry Transmit?”

Doesn’t that achieve the goal in a more direct way?

I know that app_rpt has telemdefault=0 and nounkeyct=1 which may do similar things, but I think these might be node-wide settings (i.e. not at the level of a specific radio interface).

The goal in this case is not to stop the transmission of telemetry, or to change the behavior of telemetry in any way, only to stop the tone and only the tone from being transmitted when there is telemetry, in other words, when the repeater is doing anything other than repeating voice from a local radio or remote link while transmitting. Though I doubt many use it, ASL3 has this option as a cop command.

958 = cop,58 ; TX CTCSS On Input only Enable
; 959 = cop,59 ; TX CTCSS On Input only Disable

This behavior is also known as “gated PL”.

Can I suggest a possible option? The old MSF5000 repeater; ordinarily it would send the CW ID without PL but if someone keyed up during the transmission, PL would be added and everyone would hear it. I always liked that behavior.

TX CTCSS On Input only Enable

This is a somewhat confusing way to describe this function. If enabled, is CTCSS truly sent only when local COS is active?

If so, then any traffic received from a linked node would not have CTCSS and would not be heard by a user who was using coded squelch.