Sunday, April 26, 2026

FreeDV Sunday net - moving to an hour earlier

A good net this morning from 10:30 on 7.177.

It was proposed that we move to an hour earlier for improved propagation and with a few exceptions this was fine with everyone. I'll update the list on the freedv.org site to reflect this change.

Two of us were running an early build of version 2.3 which has the C port. It seems solid to me and Leighton, VK3FC, and I look forward to it being released as it's smaller and faster.


Stations included VK1RF (Running the Flex AppImage!), VK2KNC, VK2BLQ, VK3CCR (welcome to the net Brian), VK3FC, VK3GTP, VK3JCO, VK3KEZ, VK3ZD, VK4EV (not heard), VK5AG, VK5KVA, VK5RA, VK5ST, VK2AWJ and me VK3TPM.

Saturday, April 25, 2026

macOS disk full? - move home to an external drive

It's amazing to me that a 500GB disk can get full but that happened to me on the Mac Mini yesterday. I have a lot of large developer tools including Xcode and Android Studio. Like any unix system, macOS doesn't do well when disk space is low. I've long had an external drive and store source code there but a lot of space was taken up inside my Home directory in ~/Library so I thought I'd try putting home on the external drive.

Doing this is pretty easy:
  • Go to Settings > Users & Groups
  • Control Click on your username and you see an "Advanced Options..." menu item
  • Scroll down to Home directory and Choose.. the disk you want to use

You'll be prompted to reboot and when the machine comes up it will be like a new user setup with all the Apple ID login etc. Once all that is done you can copy over files from the old home directory, things like Documents, Developer, Movies, etc.

I left it to iCloud to sync over my music and pictures.

Perhaps there's a way to move over the old home but I decided not to risk it.

All is working well now but the external disk is noticably slower than the fast internal SSD but Applications, which are still on the boot disk, still launch quickly.

Friday, April 24, 2026

FreeDV client for iPhone?

Was chatting with FreeDV regular Joe, VK3SRC, who's been pushing for an appliance like implementation of FreeDV RADE V1 for Raspberry Pi, mainly for portable operation. It occurred to me that a better way would be to have a client app for the phone - we all carry phones and they are powerful enough these days.

The project noted recently an effort by talented developer Lee, BX4ACP, who has started work, open source, on both iOS and Android clients.  

I forked the iOS code and started looking around. Lee commented that there would be problems with the iPhone audio system but his app looked quite polished so I tried to get it going.

It turns out that while you can attach other audio devices to an iPhone including bluetooth or USB audio devices, the phone basically takes the device as an input and output pair. My use case is to have the phone connected to both a transceiver and probably a headset or some sort.

Audio must come from the transceiver, be decoded and play into the headset. For transmit we'd sample audio from the headset's mic and send encoded audio to the transciever.

I fought the OS for a few days and finally gave up. It seems that Apple doesn't want developers changing audio devices programmatically. They want the user to be in control. 

Talking with Mooneer this morning, he raised the idea of special USB audio hardware, rather like what was done in the EzDV box which even uses the separate channels of a stereo pair.

I dialled back what I was trying to do and now have a RADE V1 decoder that takes audio from the input of a USB sound dongle and sends decoded audio out to the same device.


This works well. The phone easily handles the load. It's a pity 3.5mm patch cords are needed but I think a portable decoder like this might have some applications.

Another problem on the iPhone is that Apple don't let you talk to USB serial devices unless they've been specifically approved by them. A friend suggested that a bluetooth to serial adapter would be a work-around.

In the end though, I think an Android app might be the solution for portable RADE operation - until we get it built in to a radio.

Wednesday, April 22, 2026

Tech Talk on ABC Radio - A new CEO for Apple

This week on ABC Nightlife we discussed the stepping aside of arguably the most successful CEO of any company in history with the move of Apple's Tim Cook to Executive Chair of the Board. The AI model so powerful it's too dangerous to release and the boom in electric vehicle sales around the world due to fuel prices - and what needs to be done to make them practical in Australia.  https://www.abc.net.au/listen/programs/nightlife/ai-revolution-arrives-in-software-development/106589944 

Sunday, April 19, 2026

FreeDV Sunday net - good conditions

Good conditions for the Sunday morning 10:30am net but a smaller group probably because I've been away for the past two weeks. I had reports that I could be heard directly in VK4 and another person who listened via Web SDR.


There were deep fades on the OFDM waterfall but all signals could be decoded well enough. I was particularly pleased to hear that David, VK3KQT, was talking with my C port client on a Raspberry Pi and Peter, VK3PCC was using a pre-release build of the FreeDV client using my library.

Participating were: VK2AWJ, VK2DWG, VK2KNC, VK2BLQ (once he got the audio working!), VK3KEZ, VK2UMZ, VK3KQT, VK3PCC, VK3UBK, VK3ZTR, VK5ABE, VK5AG, VK5FD, VK3JF, and me VK3TPM.

Saturday, April 11, 2026

Redfest conference on digital communications

Today I had the pleasure of speaking at Redfest north of Brisbane. I spoke about how AI is being used in FreeDV and the exciting development (with the assistance of AI coding) of the port to C of the existing Python code in the Radio Autoencoder.


I attended a fascinating talk about Allstar.


There were several commercial vendors displaying their gear in the main hall plus an outdoor area with lots of great second hand equipment at good prices.



My thanks for the invitation and congratulations to the organisers for their hard work and professionalism.


Thursday, April 09, 2026

The pair of mystery strong FSK signals on 40m

There's been a bit of discussion at our radio club about the origin of the pair of FSK signals on the 40m band in recent months. Here's how they look and sound:


They sounds a bit like morse code but as you listen you soon notice that they aren't. One of our members was convinced, due to the strength, that they come from Australia. I did some internet sleuthing and the conclusion seems to be that they come from the hotspots on this map:


From Google’s AI overview:

These mystery FSK signals on the 40m ham band (approx. 7.061–7.068 MHz and 7.100+ MHz) are persistent, paired, non-amateur, wide-shift (~7 kHz) FSK signals likely originating from Eastern Europe/Russia, potentially related to regional conflicts. They resemble slow, garbled CW (20 baud) but are actually digital, military-style 5N1 encrypted data. 

Key Details of 40m Mystery FSK Signals:

·         Location & Characteristics: Usually found as a two-channel, high-power system with a 7 kHz separation (e.g., pairs near 7.0615/7.0685 MHz or higher in the band).

·         What they sound like: They sound like slow, rhythmic, or "gibberish" Morse code to the ear, but common CW decoders will not read them properly.

·         Likely Origin: The signals are believed to be related to military, government, or state-level monitoring, possibly coming from the Sevastopol/Crimea region or near the Russia/Ukraine conflict area.

·         Modulation: They are 20-baud FSK (Frequency Shift Keying) with a 7,000 Hz shift, often characterized by a constant, repeating 255-bit, 17-bit frame, 15-frame superframe, designed to appear like noise or to be jamming-resistant.

·         Timing: They appear as "key-down/key-up" pairs, meaning when one frequency is transmitting, the other is silent, suggesting a 2-channel diversity system.

·         Distinction from Amateur Activity: While some users initially suspected Winlink (a, b) or heavy traffic, these signals are widely considered "intruders" and not standard amateur digital modes like FT8 or RTTY. 

These signals are a well-documented annoyance to amateur operators in Europe and North America and have been appearing in bursts, especially between 2023 and 2026. 

On Facebook: https://www.facebook.com/groups/hfunderground/posts/1377589986956733/

What is this random strong CW signals appearing in 40m band simultaneously in three frequencies like 7050 7065 7070. We believe it may be from Russia.

These are two fsk transmissions with 7 kHz shift and 20 baud. They change frequency after about 10 minute transmission with 1.5 kHz. 

It is Iranian.. encrypted message system built by the Russians. been tracking it for weeks. It is used for sleeper cells to give them instructions. And you can take that to the bank. Jack 

Also on Facebook: https://www.facebook.com/groups/22212809595/posts/10163697406274596/

For the past week+ there has been some intruder on the 40M CW band easily heard on both coasts of North America. 

It is occasionally QSY'ing anywhere from 7.04MHz to 7.07MHz and may be outside that range goo. It is often on a whole multiple of 500Hz.

Although we are most often hearing one CW frequency with our rigs set at a normal bandwidth, I can often find an "evil twin" which is key-down while the other one is key-up, so I think it's more likely to be super-wide shift FSK. Below for example is me putting receiver 1 on 7.063MHz and the other on 7.070MHz circa 0400Z on Jan 30 2026. You see when one is key up the other is key down.

The basic signal rate seems to 0.05seconds (20 Baud). Our CW-seeking brains seem to try to interpret it as CW because if we here one element at 0.05seconds we think it's a dit and another at 0.15 seconds our brains.

I do not recognize 7kHz shift 20 baud FSK as a standard encoding anywhere but someone might know better than me.

I'm gonna record some longer patches and see if I can recognize any framing.

Tim N3QE

From SOTA Reflector: https://reflector.sota.org.uk/t/some-weird-cw-found-on-40m/38289

While trying to impove my indoor loop on 40-80m (coil added in a middle makes a noticeable difference on both TX/RX!) I’ve came across those strange CW signals. Perhaps they are trying to emulate a mechanical key with no audio control (although a vertical wouldn’t sound like that) But what could be a purpose? Another weird thing is that those sigs are present on four frequencies simultaneously with S9+:

7041.50 kHz

7048.50 kHz

7063.00 kHz

7070.00 kHz

Weird CW on 40m 

Is that something known or a new thing? There is plenty of strange stuff on air now, but I haven’t heard such lovely Morse yet :slight_smile: 

Also

Cheers David, using that “wide-band FSK” hint I’ve found another Youtube sample and also some explanation, which I quote here for reference:

https://youtu.be/zRho2iFfBCE?si=d6cvedzhd65ZZoJs 

“Sevastopol; Extremely powerful two channel 20b/7000 Hz FSK paired signals re-appear from Apr 23rd on 40m band ~ 7045cf and 7065.5cf, each channel seems to be 7 kHz from mark and space, chosen for it’s immunity from being easily jammed, at times the pair will shift frequency; originating from Eastern EU / Western RU region, now Crimea with transmitters near Sevastopol. The modulation rate of 20b with a shift of 7000 Hz. -The signal frame is 17 bits, the first of which is a 0. -The superframe is 15 frames (255 bits) and is constantly repeated so it does not appear to carry any useful information Military encryption 5N1 use in related signal connection to the conflict between Ukraine and Russia is likely. Contributor ANgazu thank you for your analysis! Recorded 12 June 2025 by Tyler Stampfli, KA0KA …”

Wednesday, April 08, 2026

Tech talk on ABC Radio - in space you still need IT to fix Outlook

As Artemis II makes its lap around the moon, astronauts on board keep in touch with their control room and their loved ones using a different type of internet on NASA's Deep Space Network.

ACMA announces new rules for telco companies surrounding their mobile coverage maps ensuring clearer and more accurate results.

Peter Marks, mobile software developer and technology commentator from Access Informatics, joins Suzanne Hill with the latest tech news. Listen here: https://www.abc.net.au/listen/programs/nightlife/tech-talk-peter-marks/106539970 

Saturday, April 04, 2026

3D printed callsign banner for backpack in OpenSCAD

Recently I purchased a rather nice backpack which features an area that can hold velcro patches. I thought it would be nice to have one with my callsign on it and went hunting for one off emboydered patches. An idea occurred to me that a 3D printed banner could work. Here's the result:


Close up you can see that I've coloured in the engraved letters with a permanent marker. Some sort of paint would be better.


I'm able to write OpenSCAD code but it turns out so can Claude Code. This is what we came up with:

// Rectangular plate with embossed text

// Dimensions

plate_length = 90;   // mm

plate_width  = 20;   // mm (adjust to taste)

plate_height =  2;   // mm plate thickness

text_depth   =  0.8; // mm how proud the text stands

rim_width    =  1.5; // mm wall thickness of raised edge

rim_height   =  1.0; // mm how tall the rim stands above the plate


// Base plate

difference() {

    cube([plate_length, plate_width, plate_height]);

    // Embossed text on top surface

    translate([plate_length/2, plate_width/2, plate_height-0.6])

        linear_extrude(height = text_depth)

        text(

            "VK3TPM",

            size    = 15,

            font    = "Liberation Sans:style=Bold",

            halign  = "center",

            valign  = "center"

        );

}

Rolls of hook and loop self adhesive strips are available in stationary stores which is 20mm wide.

Wednesday, April 01, 2026

Experiment with live noise removal from an HF SSB signal

Today at the Macedon Ranges Amateur Radio Club coffee morning, Eric, VK3EJD, brought along a new gadget that he hopes will remove noise he experiences from a neighbour's solar system.


I used to have a noise reducing speaker from BHI but was never terribly happy with it. He reminded me that I'd started building a live noise reduction application for macOS using RNNoise so when I got home I did some tinkering and got it working. Here's a demo - although the noise is not terribly bad. (I switch it in and out during the video.


Here's an example of removing solar panel noise from an AM transmission:


It's promising but needs to be trained for your specific noise. In this I'm using the default model. This runs easily on an Apple M4. I wonder when we'll start to see this built in to amateur radio gear?

Tuesday, March 31, 2026

Convert HackRF Mayhem Portapack capture to a format playable with hackrf_transfer

I had a nice capture of a busy 40m band done using a HackRF Mayhem portapack and I wanted to play it back using a HackRF connected to a computer using hackrf_transfer.

Even though the native format of the hackrf IQ is 8 bit signed interleaved samples, for some reason the portapack pads these out to 16bit so conversion is needed.

A utility to do this is here.

Here's how it looks being played back:


These captures are excellent for demonstrating receivers and playing with decoders for digital modes. Note that the files can get rather large.

I play the output file back like this: hackrf_transfer -t 40mssb.iq8 -f 7100000 -x 1 -R


Sunday, March 29, 2026

FreeDV Sunday net - good rollup

Conditions were so bad last week that I didn't bother writing up the net. Virtually no NVIS. This week was much better. 


Stations on frequency included: VK5KHZ, VK5KVA, VK5AG, VK5ABE, VK3ZD, VK3MS, VK3KEZ, VK3JCO, VK3GTP, VK3FC, VK3DQ (welcome), VK2UMZ (rx only), VK2KNC, VK2AWJ, VK5RA, VK3XCI and me, VK3TPM.

Thanks everyone for coming up. The net is held on Sunday mornings from 10:30am eastern time on 7177 unless the frequency is in use.

Friday, March 27, 2026

My experiences of using AI for ham radio projects

At this week's Radio Old Timers Club lunch in Melbourne I presented a talk outlining the good success I've had recently using Claude Code for ham radio applications. Also there's a bit of an overview of how FreeDV RADEV1 uses machine learning already.


A few AV hitches and the crowd was finishing lunch but feedback was pretty good.

Wednesday, March 25, 2026

Tech Talk on ABC Radio - Microsoft sorry about Windows 11

This week on ABC Radio's Nightlife program we discuss a recent post by Microsoft acknowledging a list of things that users complain about. They promise to address these in the year ahead. The complaints about Windows comes at a time when Apple CEO Tim Cook reports that, with the launch of the low cost MacBook Neo, Apple has seen the highest number of new users to macOS in the company's history. 

Continuing a trend in recent months, layoffs in tech firms are being blamed on AI being used to replace workers - but is that really the case or just an excuse to downsize?

Finally there are rumours that Amazon is having another go at a product in the mobile space. Code named "Transformer" it's likely to be an AI driven portable device. Inevitably something will replace the mobile phone but is this it?

https://www.abc.net.au/listen/programs/nightlife/microsoft-makes-a-slight-apology-for-windows-11/106492726

Wednesday, March 11, 2026

Tech Talk on ABC Radio - Apple goes low

This week on ABC Nightlife I spoke with Rod Quinn about Apple's new MacBook Neo, a sub-$1000 laptop that competes very well with Windows laptops in that price range. Apple has made some compromises but kept their quality standards up.

We discussed the US AI controversy where Antrhopic, makers of Claude, asked the Department of Defence to not use its products for widespread domestic suveillance or autonomous weapons. DOD would not agree to those limitations and has done a deal with OpenAI, who presumably are ok with that.

Finally, the ban on social media for Australians under 16 introduced in December seems to be spreading with Indonesia announcing they'll introduce it gradually from March. They join Denmark, France, Germany, Malaysia, Spain, the UK and Greece in either announcing or at least considering a ban.

Too early to know how effective it's been in Australia but we do see that VPNs are booming...

https://www.abc.net.au/listen/programs/nightlife/nightlife-tech-talk-with-peter-marks/106439260

Sunday, March 08, 2026

FreeDV Sunday net - Good rollup, four states

The Russian FSK transmissions were very strong this morning which ruled out using 7045 so I parked the net on 7177 and didn't expect too many stations to find me but there was no problem. 

Stations heard: VK2AGU, VK2AWJ, VK2KNC, VK3GTP, VK3KEZ, VK3PCC, VK3PTR, VK3ZD, VK5AG, VK5KVA, VK7DMH, VK5ST, VK3CDH, VK2KO, VK5ST, VK2BLQ and me, VK3TPM.


A warm shout out to Joe VK3SRC who several stations credited with helping them with various aspects of getting FreeDV going nicely. Thanks Joe!

Also a shout out to Dave who's OpenWebRX+ is now decoding FreeDV RADEV1 over at Normanville.

Sunday, March 01, 2026

FreeDV Sunday net - conducted with C client

I've been working on my C port of the FreeDV app's main functionality over recent weeks. It's really just a proof of concept but yesterday I got reporting to qso.freedv.org working which made it practical to run today's net. That feature, combined with a minimal implementation of Hamlib, just enough to read transceiver status and turn transmit on and off, has made the app quite usable.


The app worked smoothly and the following stations were seen: VK5RT, VK5LN, VK5LO, VK5KVA, VK5AG, VK5ABE, VK3ZUM, VK3XCI, VK3UBK, VK3PCC, VK3KEZ, VK3GTP, VK3CDH, VK3BAL, VK2KO, VK2DWG, VK2CJB, VK2BLQ, VK2AWY, VK2TTL and me, VK3TPM.


Wednesday, February 25, 2026

Tech Talk on ABC Radio - Software that kills and AI boom crashes tech stocks

This week on ABC Nightlife, I discuss the final removal of the truly evil UK Post Office Horizon software system that led to 13 suicides among innocent sub postmasters, job offers for the OpenClaw developer, and the latest video creation models that are rocking movie producers - or is it just an evolution of the Computer Generated Images we've had for decades. https://www.abc.net.au/listen/programs/nightlife/actors-to-be-sacked-for-ai/106382876

Sunday, February 22, 2026

FreeDV Sunday net - a new record

A very well attended Sunday FreeDV net on 7045 this morning from 10:30 eastern time. Stations on frequency were: VK2AWJ, VK2BX, VK2UMZ, VK3BAL, VK3CDH, VK3DJB, VK3FC, VK3GTP, VK3ID, VK3KEZ, VK3PCC, VK3PTR, VK3SRC, VK5ABE, VK5AG, VK5KHZ, VK5KVA, VK5MH, VK7DMH, VK2KO, VK2KNC, VK2YW, VK2CJB and me VK3TPM. 24 stations!


 

Monday, February 16, 2026

Generating sideband to transmit on a HackRF

While working on my C port of FreeDV RADE1 I wanted a reliable radio signal to test with. While I have off air recordings from the FreeDV GUI app I thought it would be nice to generate my own files to transmit with the HackRF Portapack Mayhem which can record to C16 files and play them back. There's a TXT file with each recording that specifies the sample rate and output frequency.

I've made a python utility that can read a WAV file recording and produce C16 sideband. Here's how it sounds.


The code is pretty short so I've published it as a gist on GitHub.

The HackRF is a wonderful tool for radio experimentation. I'm using the standalone Mayhem but it works just as well from a computer via USB with hackrf_transfer.

Sunday, February 15, 2026

FreeDV Sunday net - 23 stations

An excellent FreeDV RADE1 net here in South East Australia with 23 stations on frequency. Some for the first time. Stations: VK5KHZ, VK5KFG, VK5AG, VK3ZUM, VK5KVA, VK3UBK, VK3SRC, VK3KEZ, VK3JCO, VK3GTP, VK3FC, VK3DJB, VK3CDH, VK3BQO, VK3BAL, VK2YW, VK2XOR, VK2UMZ, VK2KNC, VK2DWG, VK2AWJ, VK5HM and me VK3TPM. 


Normally I call in stations in alphabetical order but today I thought I'd trick Jack VK5KVA, by going in reverse.

 

Wednesday, February 11, 2026

C port of FreeDV RADE going well - transmit working today

Today marked a milestone in my investigation into using Claude Code with a complex codebase. I had a FreeDV RADE contact with another station using code it wrote under my instruction in just one week - very much part time. Here's a receive demo:


My thanks as always to Joe, VK3SRC, for assistance in testing and feedback. Also thanks to Britt, VK3AOB who responded to my first call which I really expected to not be decodable.

Here's how Claude Code looks while working on a bug in the code (click to enlarge):


 I'm developing on Linux Mint. The app is C++ using GTK and Claude seems very knowledgable in this scenario. I suspect that the large amount of open source software around is a great advantage for this sort of thing.

The code is here: https://github.com/peterbmarks/radae_decoder As you can see the name of the project is no longer correct as it encodes as well.

Tech talk on ABC Radio - Is OpenClaw the future?

Have you heard of a tool called OpenClaw? Apparently, you install it on your computer and it acts like your personal assistant. it's generating a lot of buzz and users are saying it's like they're 'finally getting a glimpse of the future'. 

Tech Talk takes a look at this and how the big four tech companies are faring after they've spent big on AI. 

Peter Marks, mobile software developer and technology commentator from Access Informatics, joined Philip Clark and listeners to Nightlife with the latest tech news. Listen here: https://www.abc.net.au/listen/programs/nightlife/nightlife-tech-talk-with-peter-marks/106328266 

Sunday, February 08, 2026

FreeDV Sunday net - excellent conditions

An excellent Sunday FreeDV net this morning with VK2, VK3 and VK5 stations all with good SNRs. 


Some interest was expressed in the C port of the RADAE python code which is encouraging. On the frequency, (not everyone transmitted), VK2AMF, VK2AWJ, VK2DWG, VK2GMH, VK2YE, VK3DJB, VK3FC, VK3GTP, VK3JCO, VK3KEZ, VK3XCI, VK3YV, VK3ZUM, VK4TEW, VK5ABE, VK5KHZ, VK5KVA, VK5LN, VK5ST, VK6YR, VK3BAL (running three copies of FreeDV!), VK3AOB, and me VK3TPM.


Saturday, February 07, 2026

Experimental C port of the FreeDV RADEV1

One of the objectives of the work on RADEV2 is to replace the currently required Python runtime from the distributed FreeDV app. This would make it easier to install, smaller, and hopefully more efficient. (Other objectives are improvements in how it works). Python is an important part of the project and is used for prototyping and testing - that won't change.

Re-writing all the python in C is a daunting, tedious, expert task, estimated to take many months that would result in an app that works pretty much the same as it does today.

I've been experimenting with Anthropic's Claude Code recently and it occurred to me that one of the things LLMs are particularly good at is translating between languages, human or programming. The result of just a few days of guiding Claude Code is an experimental RADEV1 decoder app.


The intial work, which includes command line tools to decode and encode from and to WAV files is on github here.

The proof of concept Linux application shown above is in a Github repo here

While it seems to work and does pass important tests, this is not code supported by the project at this time.

Claude Code enabled me to attempt something I wouldn't dream of until now. It was quite a big job for it (I hit my quota on two separate days and had to wait to resume).

Working with an LLM to write software does still require enough knowledge to know what to ask for and to guide the work.

I hope this work will encourage others to develop innovative FreeDV RADE software along side the official FreeDV App which remains the reference release. My sincere thanks to Dr David Rowe for his fantastic work and his help and encouragement with this little experiment.

Friday, February 06, 2026

A well used laptop keyboard

Many years ago I handed down a MacBook air to our youngest daughter. She used it until I handed down a later machine. Last week she returned it and I'm amazed to see how heavily she had used it over the years without complaint.


It still works although the battery is dead now. 

Some people complain that Apple is expensive but I think it's value for money.

This kind of keyboard wear reminds me of an HP25C calculator I had many years ago. It was also a piece of quality engineering and, as I recall, one feature was that the symbol on the buttons was plastic that extended right through the key so it would never wear off. 


Thursday, February 05, 2026

Xiegu X6200 review

Keen to do more field operating (and overnight camping). My rig of choice has been the Elecraft KX3 with it's excellent antenna tuner and easy to read LCD display. Since using rigs with a waterfall display of the band I find it hard to going back to tuning up and down trying to find stations. 

I purchased a Xiegu X6200 from AliExpress for AU$1200. 


It has some terrific features for portable operation:

  • Decent flat battery pack that clips on the back
  • Wonderful sharp and bright display
  • Excellent built-in antenna tuner
  • USB-C socket with interfaces for CAT control and audio
  • Handles to protect the knobs
The front facing speaker is small but quite effective. Surprisingly it is NOT a touch screen (although if you connect a mouse you get a mouse pointer). This means that to go through menus you must spin the outer lower left knob to move between settings and spin the inner knob to change a setting.

A waterfall with a touch screen is a wonderful thing and on a 7300 being able to tap a signal to tune there is missing here. Tuning with the knob is a little laggy and seems to have some inertia for some reason. (Unfortunately clicking on the waterfall with a mouse isn't supported).

The rig is certainly a quality build. All the controls feel excellent and the battery pack, sadly proprietary, clips on to the back. It's remarkably compact and solid feeling. The microphone has a full set of buttons including three configurable buttons for things like NR or NB. You can also direct enter frequencies. There is also a built-in microphone and PTT button so you could use it like a hand-held.

Because of my focus on digital modes, I wouldn't buy a radio without a direct USB connection and this radio does it all. I have found that it's rather sensitive to the cable being used and I've experienced the serial devices not appearing even though I was using a USB-C to USB-C cable that clearly carries data as it works with hard disks. The supplied USB-C to USB-A cable.

When plugged into a computer two serial devices appear. The second one is the CAT port (the other is a serial terminal).

Here's the settings that work with fldigi:


Here's the settings that work with FreeDV:


Rig: Xiegu X6200
Serial Port: /dev/ttyACM1
Baud Rate: 19200
Data bits, stop bits, handshake: Default
PTT Method: CAT
Mode: Data/Pkt
Split Operation: None.
Audio Input: alsa_input.usb-C-Media_Electronics_inc.USB_Audio_Device-00.mono-fallback
Audio Output: also_output.usb-C-Media_Electronics_inc._USB_Audio_Device-00.analog-stereo

The radio should switch to mode: U-DIG or L-DIG depending on band with FreeDV

I note that the audio level to WSJT-X is too high, 88dB. I needed to reduce "mic" gain in Linux sound settings.

Bugs

Xiegu has a history of software bugs in their radios. It seems some never get fixed. The most disappointing one for me is that I'm on the latest firmware 1.0.7 and I cannot get it to connect to Wifi which is a pity as there's a WFView server (Icom radio networking server) built in and it would be great to remote access the radio.

There is a discussion group at https://xiegu-x6200.groups.io/g/main/topics that looks to be a great resource.

Conclusion

I think this is quality radio for the money. I joined our club 80m net this week and got good reports from other stations. The radio puts out about 4W on the attached battery and about 9W with external power.

Wednesday, February 04, 2026

Tuesday, February 03, 2026

Very good morse decoder from 101 things

Prolific ham radio hacker Jonathan P Dawson has just shared a remarkable project he calls Hamfist that is a morse decode device running in the Arduino runtime for Pi PICO processors (including the original). 

Go and read his description but it's quite a sophisticated decoder, rather like a CW skimmer it can decode several morse signals in the audio passband. The PICO does the audio sampling with one of its A/D pins with just a simple circuit on the input.

"It combines adaptive signal processing, automatic speed estimation, probabilistic decoding, dictionary-based correction, and multi-channel decoding, all while keeping memory and CPU usage firmly under control."

I grabbed the source and built it in the Arduino IDE targeting the PICO. All very smooth. Unfortunately I don't have the display he uses, the ili9341, so I've ordered some. The code seems to run but of course I can't see the morse.

Update: A display board arrived.


So. I pointed Claude Code at the Arduino files and simply asked it to create a C++ command line program that could read a WAV file with morse audio in it and print out the decoded morse. It wrote wav_decoder.cpp and a Makefile. Jonathan includes some sample WAV files so I tried some of these. Here's how that goes:

cw_decoder % ./cw_wav_decoder examples/cw2.wav

WAV file: examples/cw2.wav

  Sample rate: 12000 Hz

  Channels: 1

  Bits per sample: 16

  Target sample rate: 15000 Hz

CQ SP3VT SP3VT TEST E4EQ SP3VE E3VT TEST PA3A IN PA3AT 5NN E 27 MIKEEE EAT/ HI TU S E3VT CQ SP3VT SE 3VT TEST CZ G3VT SPSE UT TEST CQ SW3VT SP EVE TEST CQ SP3VT SAME3VT TEST DK3T DA3T 5NT 

I would add that the decode all happens in a fraction of a second.

I'm not sure if I'm more impressed with Jonathan's contribution or Claude Code's capabilities. Here's the file it produced and the Makefile.

#include <cstdio>
#include <cstdlib>
#include <cstdint>
#include <cstring>
#include <string>

#include "cw_dsp.h"
#include "fft.h"

// WAV file header structure
struct WavHeader {
char riff[4]; // "RIFF"
uint32_t file_size; // File size - 8
char wave[4]; // "WAVE"
char fmt[4]; // "fmt "
uint32_t fmt_size; // Format chunk size
uint16_t audio_format; // 1 = PCM
uint16_t num_channels; // Number of channels
uint32_t sample_rate; // Sample rate
uint32_t byte_rate; // Bytes per second
uint16_t block_align; // Bytes per sample * channels
uint16_t bits_per_sample; // Bits per sample
};

// Derived DSP class that outputs decoded text to stdout
class c_wav_decoder : public c_cw_dsp {
private:
std::string last_text[NUM_CHANNELS];

protected:
void decode(uint16_t channel, std::string text, std::string partial) override {
if (!text.empty() && text != last_text[channel]) {
printf("%s", text.c_str());
fflush(stdout);
last_text[channel] = text;
}
}

public:
void print_final() {
// Flush any remaining text
flush();
printf("\n");
}
};

// Simple linear interpolation resampler
class Resampler {
private:
double ratio;
double position;
int16_t last_sample;
bool first_sample;

public:
Resampler(uint32_t input_rate, uint32_t output_rate)
: ratio((double)input_rate / output_rate)
, position(0.0)
, last_sample(0)
, first_sample(true) {}

// Process one input sample, may produce 0 or more output samples
// Returns number of output samples produced
int process(int16_t input, int16_t* output, int max_output) {
int count = 0;

if (first_sample) {
last_sample = input;
first_sample = false;
}

while (position < 1.0 && count < max_output) {
// Linear interpolation
double frac = position;
int32_t interpolated = (int32_t)((1.0 - frac) * last_sample + frac * input);
output[count++] = (int16_t)interpolated;
position += ratio;
}

position -= 1.0;
last_sample = input;

return count;
}
};

void print_usage(const char* program_name) {
fprintf(stderr, "Usage: %s <wav_file> [channel]\n", program_name);
fprintf(stderr, "\n");
fprintf(stderr, "Decodes Morse code (CW) from a WAV audio file.\n");
fprintf(stderr, "\n");
fprintf(stderr, "Arguments:\n");
fprintf(stderr, " wav_file Path to the input WAV file (mono or stereo, any sample rate)\n");
fprintf(stderr, " channel Optional: frequency channel 0-%d (default: all channels)\n", NUM_CHANNELS - 1);
fprintf(stderr, "\n");
fprintf(stderr, "The decoder uses %d frequency channels spanning 0-%.0f Hz.\n",
NUM_CHANNELS, NUM_CHANNELS * CHANNEL_SIZE * (SAMPLE_FREQUENCY / 2.0) / (FRAME_SIZE / 2));
}

int main(int argc, char* argv[]) {
if (argc < 2 || argc > 3) {
print_usage(argv[0]);
return 1;
}

const char* filename = argv[1];
int selected_channel = -1; // -1 means all channels

if (argc == 3) {
selected_channel = atoi(argv[2]);
if (selected_channel < 0 || selected_channel >= NUM_CHANNELS) {
fprintf(stderr, "Error: channel must be between 0 and %d\n", NUM_CHANNELS - 1);
return 1;
}
}

// Open the WAV file
FILE* file = fopen(filename, "rb");
if (!file) {
fprintf(stderr, "Error: Cannot open file '%s'\n", filename);
return 1;
}

// Read WAV header
WavHeader header;
if (fread(&header, sizeof(WavHeader), 1, file) != 1) {
fprintf(stderr, "Error: Cannot read WAV header\n");
fclose(file);
return 1;
}

// Validate WAV format
if (strncmp(header.riff, "RIFF", 4) != 0 || strncmp(header.wave, "WAVE", 4) != 0) {
fprintf(stderr, "Error: Not a valid WAV file\n");
fclose(file);
return 1;
}

if (header.audio_format != 1) {
fprintf(stderr, "Error: Only PCM WAV files are supported (format=%d)\n", header.audio_format);
fclose(file);
return 1;
}

if (header.bits_per_sample != 16 && header.bits_per_sample != 8) {
fprintf(stderr, "Error: Only 8-bit or 16-bit WAV files are supported\n");
fclose(file);
return 1;
}

fprintf(stderr, "WAV file: %s\n", filename);
fprintf(stderr, " Sample rate: %u Hz\n", header.sample_rate);
fprintf(stderr, " Channels: %u\n", header.num_channels);
fprintf(stderr, " Bits per sample: %u\n", header.bits_per_sample);
fprintf(stderr, " Target sample rate: %.0f Hz\n", SAMPLE_FREQUENCY);
fprintf(stderr, "\n");

// Skip to data chunk
// The fmt chunk might be larger than our struct, and there might be other chunks
fseek(file, 12, SEEK_SET); // Skip RIFF header

char chunk_id[4];
uint32_t chunk_size;

while (fread(chunk_id, 4, 1, file) == 1) {
if (fread(&chunk_size, 4, 1, file) != 1) {
fprintf(stderr, "Error: Malformed WAV file\n");
fclose(file);
return 1;
}

if (strncmp(chunk_id, "data", 4) == 0) {
break; // Found data chunk
}

// Skip this chunk
fseek(file, chunk_size, SEEK_CUR);
}

if (strncmp(chunk_id, "data", 4) != 0) {
fprintf(stderr, "Error: Cannot find data chunk in WAV file\n");
fclose(file);
return 1;
}

// Initialize FFT and DSP
fft_initialise();
c_wav_decoder decoder;

// Create resampler
Resampler resampler(header.sample_rate, (uint32_t)SAMPLE_FREQUENCY);

// Process audio data
const int BUFFER_SIZE = 1024;
uint8_t buffer[BUFFER_SIZE * 4]; // Max size for stereo 16-bit
int16_t output_buffer[16]; // Resampler output buffer

int bytes_per_sample = header.bits_per_sample / 8;
int bytes_per_frame = bytes_per_sample * header.num_channels;
int samples_per_read = BUFFER_SIZE;

uint32_t total_samples = chunk_size / bytes_per_frame;
uint32_t samples_processed = 0;

while (samples_processed < total_samples) {
int samples_to_read = samples_per_read;
if (samples_processed + samples_to_read > total_samples) {
samples_to_read = total_samples - samples_processed;
}

size_t bytes_read = fread(buffer, bytes_per_frame, samples_to_read, file);
if (bytes_read == 0) break;

for (size_t i = 0; i < bytes_read; i++) {
int16_t sample;

if (header.bits_per_sample == 16) {
// 16-bit sample
int16_t* samples = (int16_t*)(buffer + i * bytes_per_frame);
if (header.num_channels == 1) {
sample = samples[0];
} else {
// Mix stereo to mono
sample = (samples[0] + samples[1]) / 2;
}
} else {
// 8-bit sample (unsigned)
uint8_t* samples = buffer + i * bytes_per_frame;
if (header.num_channels == 1) {
sample = ((int16_t)samples[0] - 128) * 256;
} else {
// Mix stereo to mono
sample = (((int16_t)samples[0] - 128) + ((int16_t)samples[1] - 128)) * 128;
}
}

// Resample to target rate
int num_outputs = resampler.process(sample, output_buffer, 16);

// Feed resampled samples to decoder
for (int j = 0; j < num_outputs; j++) {
decoder.process_sample(output_buffer[j]);
}
}

samples_processed += bytes_read;
}

// Flush remaining decoded text
decoder.print_final();

fclose(file);

return 0;
}

Makefile:

CXX = g++
CXXFLAGS = -std=c++17 -O2 -Wall

# Source files
SOURCES = wav_decoder.cpp \
cw_dsp.cpp \
cw_decode.cpp \
cw_classifier.cpp \
cw_data.cpp \
dictionary.cpp \
fft.cpp \
utils.cpp

# Object files
OBJECTS = $(SOURCES:.cpp=.o)

# Output binary
TARGET = cw_wav_decoder

.PHONY: all clean

all: $(TARGET)

$(TARGET): $(OBJECTS)
$(CXX) $(CXXFLAGS) -o $@ $^

%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<

clean:
rm -f $(OBJECTS) $(TARGET)

# Dependencies
wav_decoder.o: wav_decoder.cpp cw_dsp.h fft.h
cw_dsp.o: cw_dsp.cpp cw_dsp.h cw_decode.h fft.h utils.h
cw_decode.o: cw_decode.cpp cw_decode.h cw_classifier.h cw_data.h dictionary.h
cw_classifier.o: cw_classifier.cpp cw_classifier.h
cw_data.o: cw_data.cpp cw_data.h
dictionary.o: dictionary.cpp cw_data.h
fft.o: fft.cpp fft.h
utils.o: utils.cpp utils.h