Wednesday, June 5, 2024

[Tech] LimeSDR on ARM64 Windows (almost)

I recently got a LimeSDR Mini v2.0, a software-defined radio receiver-transmitter that's open-source, open-hardware, and generally awesome. (OK, that last bit is an opinion--I did back the CrowdSupply project, so I definitely thought it was Neat.)

Since ARM64 Windows is, shall we say, an intrinsic part of my day job, I naturally tried using the LimeSDR on the Lenovo ThinkPad X13s I use. It didn't work.

So, what's a software developer to do when an open-source project doesn't work?

Make it work and contribute back the changes, of course!

Thursday, November 23, 2023

[Technical] Using rtl_433 with Salter temperature probe

 So, you bought a Salter brand oven thermometer, FCC ID 2ATK8-BS201, and it has a nice removable remote that listens to radio chirps from the base to report the temperature. Great! It's a nice, functional product, even if the FCC ID doesn't seem to exist. (!)

If you want to use it with rtl_433 and an SDR, though, you'll find that it reuses the ThermoPro TP12 protocol under the hood.

Well, that's easy enough--except it reports two temperatures, and neither of them seem remotely correct. If you watch closely, though, you'll find that "temperature_1_C" is exactly 30 degrees C over the temperature reported on the remote.

I haven't figured out what temperature_2_C is yet, but it does seem to track with temp 1 at least a little.

Thursday, September 28, 2023

[Tech] GPS reception on Raspberry Pi 2 with RTL-SDR

(Nope, still not working yet.)

 

I have an RTL-SDR dongle and an active GPS antenna, so I'd like to attach them to my wee little Raspberry Pi 2 and try and catch some signals with them.

Since I have an RTL SDR Blog v3 dongle, the hardware isn't really that interesting.

What is interesting is the software. My little Pi is not running x64 Windows; in fact, it's running Ubuntu 22.04 Server. I'd like this data reception to be self-contained if possible, so rtl-tcp is out this round.

The RTL SDR Blog has a post about this:

https://www.rtl-sdr.com/rtl-sdr-tutorial-gps-decoding-plotting/

This is from 2017 and points to a neat project:

https://www.github.com/taroz/GNSS-SDRLIB

This repo contains a set of Windows tools and a single Linux CLI tool that doesn't build out of the box.

  1. Per `cli/linux/readme.md`, you need to edit the makefile to select your radio.
  2. You also need to remove -DSSE2_ENABLE, since that won't work on Arm.
  3. Next you need to install libfftw3-dev: `sudo apt install libfftw3-dev`
  4. There's a bug in stereo.h, where STEREO_globalDataBuffer is defined in a header, leading to extra conflicting definitions at link time. I marked it extern in the header and added it to stereo.c, which probably isn't the best place for it.
  5. There are checked-in library binaries that need to be provided for the new platform.
    1. libfec appears to live on at https://github.com/quiet/libfec and is handily installed via `sudo apt install libfec-dev`. Switch the .a file on the LIBS line out for `-lfec`.
    2. libnslstereo is not related to libnsl. I haven't yet been able to track it down, but stereo.h suggests it's just another RF front-end. Since I'm using an RTL-SDR instead, I dropped it from the OPTIONS, LIBS, and OBS lines.
    3. librtlsdr: from your local RTL-SDR build based on https://github.com/rtlsdrblog/rtl-sdr-blog, copy build/src/librtlsdr.a over src/rcv/rtlsdr/rtlsdr.lib and change LIBS+=-lrtlsdr to LIBS+=../../src/rcv/rtlsdr/rtlsdr.lib
      1. FCIB has earned it's 'F' in this repo. Holy cow.

A quick `make -j4` and now we have a binary that, when copied into the `bin` folder next to its INI file, prints:

$ ./gnss-sdrcli
GNSS-SDRLIB start!
error: rcvinit 

Yay!

Editing bin/gnss-sdrcli.ini to point to frontend/rtlsdr_L1.ini seems to be a good start. The RTL-SDR fires up, but then the program crashes. Adding some tracing shows that it's during RTL-SDR init, so maybe the headers and static lib don't match and that's breaking things.

Sunday, July 23, 2023

ingots

 It was cleanup time again.

The plant operator was supposed to be good enough at his job to avoid this, but here I was again, shovelling lumps of waxy rage and slivers of regret and empty bubbles of crystallized disappointment into the crucible.

The heat would slowly soften them, then they would melt. I'd then stir the lumpy goo with a big glass rod until it was just thick goo, and then I'd squeeze it out into the molds. They'd cool there, wafting shimmers of heat into the room and across the ceiling, then solidify. The heat would get pretty awful, but at least they shrank away from the sides of the ingot molds. Stacking came next; the far wall had row upon row of these little ingots, stacked away. No one knew what to do with them; they were inert weight, bending space-time ever so slightly more than their surroundings, crying out to be used and refusing to even speak.

When the last bar was cast, set, and stacked, it was time to cool off and clean up. The bits that splashed, burbled, offgassed, or splattered on me as I worked needed to come off and go in the hopper for the next run--I wasn't allowed to leave the oppressively hot room with it on me, so I started working the intraplant signalling system. It was after hours; the break room only had a few people in it, screaming past each other in an attempt to, what, hear themselves scream? Make the pain stop? Make the pain multiply? Certainly not scrub or scrape someone else's protective gear. The control room was a skeleton crew with far too much to do; no spare cycles there. The engineering bay was noisy with the automatons left overnight to fill the silence, the few nocturnal engineers too engrossed to look up at the plant status lights.

And why should they? I'm a little cog cleaning up a mess that shouldn't, on the face of it, exist.

So I use the self-filtering shower to get most of it off, stopping every few minutes to let the solvent slip through the filters, then emptying the filters into the hopper. After a few cycles of painsstaking scrubbing and filtration, I would cast one last ingot, set the tongs down, and stare at it cooled. I had to wonder if some of it was my own, and not from the industrial processes the plant was charged with.

Still, it was done. I could go listen to the vain shrieking or wander, unseen, through the engineering department. At least the ingots were stacked. For now.

Monday, May 1, 2023

[Tech] FIRST Shuffleboard + PC-side Serial

 This is a collection of notes as I attempt to get the FRC 2023 software stack to communicate robot->Shuffleboard->PC serial, as would be useful when controlling driver station LEDs in response to robot state changes.

Empirically, at least, the Shuffleboard development environment is that year's WPILib VS Code installation. If you use the WPILib installer, you can use that installation of VS Code to work on Shuffleboard.

Shuffleboard code repo: https://github.com/wpilibsuite/shuffleboard

Just clone, open in VS Code, and the VS Code Terminal can run the Gradle commands described in the docs, like gradlew build.

Shuffleboard has docs around extending it: https://docs.wpilib.org/en/stable/docs/software/dashboards/shuffleboard/custom-widgets/creating-plugins.html

TL;DR: there are a couple of example plugins (/example-plugins/<plugin name>) you can duplicate, rename, and add to the build scripts. Bon appetit!

Shuffleboard's plugin folder is ~/Shuffleboard/plugins or %USERPROFILE%\Shuffleboard\plugins. You can copy the JAR there manually or use Shuffleboard's plugin loader to do it, sometimes using Clear Cache. There's even a nice build target for deploying: gradlew :example-plugins:PLUGIN-NAME:installPlugin

I needed a little more guidance than that. JavaFX is not my native tongue, and I need cross-plat serial interop on top of it all.

So...

Repo-scale build commands are documented in the repo root readme.

Build private version of the entire application (triggers dependency download): .\gradlew :app:shadowJar 

(:api:shadowJar does not seem to exist at the moment)

Building just the plugin jar (?): .\gradlew :example-plugins:xbox-controller-state:jar

Serial

https://stackoverflow.com/questions/900950/how-to-send-data-to-com-port-using-java

suggested

http://fazecast.github.io/jSerialComm/

Trying to figure out how to integrate them.

Gradle references say you can just slap in an 'implementation' clause under 'dependencies', but not only does that not seem to do anything, :example-plugins:PLUGIN-NAME:jar builds a JAR but doesn't register horrific syntax errors in my .java file!

My .java file ended up going in example-plugins\PLUGIN-NAME\src\main\java\com\SOMETHING before syntax errors would break the build.

In my plugin .gradle file, I added

implementation group: 'com.fazecast', name: 'jSerialComm', version: '2.9.3'

This lands it in the Gradle dependency cache, but the build error suggests it's not quite working.

Plugin.java:12: error: cannot find symbol
        var foo = new SerialPort.getCommPorts();
                                ^
  symbol:   class getCommPorts
  location: class SerialPort
1 error

Note the 'new' that is, in fact, utterly wrong here.

Now, how do I deploy this jar with my module?

Logging: Fun fact, Shuffleboard uses the bog-standard java.util.logging.Logger framework. One addHandler is to...%USERPROFILE%\Shuffleboard\*.log. Yeah. I've been flying blind with stack traces and logging *right there*. Whoops.

Talking to my brother, I can tweak the Gradle files to make a fat JAR, I can deploy the JAR, or leverage the standard plugin architecture if it's available.

For futher details, see my work-in-progress branch: https://github.com/jkunkee/shuffleboard/tree/jkunkee-stub-extension

Sunday, March 12, 2023

hey, don't cry -- recipe

 Expansion of https://www.tumblr.com/thesolarsurfer/710687700479508480

two cloves garlic
a dollop of olive oilve oil
1 can crushed tomatoes
a bit of balsamic vinegar
1/2 tbsp brown sugar
1/2 cup grated paremesan cheese
handful of fresh spinach
cooked pasta of your choice

1. don't cry
2. crush two cloves garlic into a (heated) pot with a dollop of olive oil
3. stir until golden
4. add one can of crushed tomatoes, a bit of balsamic vinegar, 1/2tbsp brown sugar, 1/2c grated parmesan cheese
5. stir for a few minutes
6. add a handful of fresh spinach until wilted
7. mix in pasta of your choice
8. ok?

Notes:

1 lb pasta is too much for this recipe

It is tasty, but the Tumblr post oversells it

Thursday, December 8, 2022

[Technical] WPILib installation on ARM64 Windows

[EDIT: WPILib's installer supports installation on ARM64 as of this PR. ARM64 Windows support is discussed in detail in that thread.]

If you find yourself on a FIRST Robotics team looking to compete in the 2023 season and you're working on the software for the robot, you will probably find yourself attempting to install WPILib.

The standard path is to go to the GitHub releases page, download the relevant ISO, mount it, and run the installer. I was last on a FIRST team in 2006, and I find this system refreshingly simple.

The documentation is clear that ARM64 Windows 10 and 11 are not supported. While I greatly appreciate this candor, ARM64 Windows 11 is easy to support by leveraging x64 emulation. (Disclaimer: I work on the team at Microsoft that implemented and maintains this emulation layer.)

Please note that this is stepping off the supported path, so there may be dragons.

Installation requires enlightening the installer to choose x64 when it sees ARM64.

  1. Install Visual Studio (2019 or 2022; I used 2022 17.5.0 Preview 1.0) with the .NET Desktop Development workload.
  2. Clone the installer repository. git clone https://github.com/wpilibsuite/WPILibInstaller-Avalonia.git
  3. Open the .sln file at the root of the repo with Visual Studio.
  4. Modify WPILibInstaller-Avalonia/Utils/PlatformUtils.cs to map ARM64 to x64.
    1. In commit e4f0039cb, I changed line 50 from
    2. if (currentArch == Architecture.X64)
    3. to
    4. if (currentArch == Architecture.X64 || currentArch == Architecture.Arm64)
  5. Start the Develop Command Prompt for your installation of Visual Studio.
  6. Change to the cloned source directory.
  7. Build the standalone EXE version of the project with dotnet publish. dotnet publish -r win10-x64 -p:PublishSingleFile=true
  8. Unpack the WPILib ISO.
  9. Find WPILibInstaller.exe in the unpacked folder and replace it with <repo root>\WPILibInstaller-Avalonia\bin\Debug\net7.0\win10-x64\publish\WPILibInstaller.exe.
  10. Run the new WPILibInstaller.exe from the unpacked folder.

So far, so good...we'll see how far I get with the rest.