Category Archives: software

Home Assistant Matter Server with Podman

Yet more updates, turns out as of a few days ago, they now actually provide a container of the matter server _without_ all the home assistant OS cruft. so it’s even easier:

$ podman run -v /etc/localtime:/etc/localtime:ro -v /run/dbus:/run/dbus:ro  -d --network=host ghcr.io/home-assistant-libs/python-matter-server:stable

(Original below)

so, home assistant only formally supports matter via an home assistant “Addons” which are only supported by the Home Assistant “OS”. That’s… not a cool way of runnings for me, and all it really does is run a docker server wrapping an external service they made, python-matter-server

The Docker service they made is here: https://github.com/home-assistant/addons/tree/master/matter_server This… doesn’t run nicely with podman, but it can mostly be worked around pretty easily.

So, assuming you have home assistant already running on localhost, under podman:

$ podman run -v /etc/localtime:/etc/localtime:ro -v /run/dbus:/run/dbus:ro  -d --network=host -e SUPERVISOR_API=http://localhost docker.io/homeassistant/aarch64-addon-matter-server:latest

The -e SUPERVISOR_API call doesn’t actually do anything, because you don’t actually have the home assistant supervisor, but it might be helpful in some cases, and shows you how to do it anyway.

Originally there were more instructions, below, but they actually went and fixed my bug report eventually, so you no longer need anything other then “usual” podman invocations on their default image.


Unfortunately you will need to edit a few layers, as they seem pretty against letting this be run easily without their entire OS

# First make sure we're up to date
$ podman pull docker.io/homeassistant/aarch64-addon-matter-server
# now, run that, and get a shell in it, we need to edit...
$ podman run -d docker.io/homeassistant/aarch64-addon-matter-server
390841611cf49675741ec72ea91341aef628fd6865bba51eeee9d0f1533473b8
$ podman exec -it -l /bin/bash
root@390841611cf4:~#

Ok, now, what are we fixing? Well, the log line from that bug report linked first… Despite closing my issue, they actually fixed this later…

That… actually means you don’t need to do any image fuckery at all… Lets just do some magic podman to replicate the docker file sufficiently…

Podman and OpenCart

I have been doing some experiments with shopping cart systems, and was trying to run them on podman for some “quick” testing. (I’m not much of a container expert, but I don’t have a php setup on my workstation right now, so this seemed like a good time to become one)

Now, OpenCart installation instructions are super manual but that shouldn’t be too hard right?

Well, after a bit of faffing around, looking for an nginx+php-fpm container ready to go, I just fell back and tried:

$ podman run -p 8081:80 -d -v ./opencart-4.0.2.1/upload:/var/www/html php:8-apache

This runs ok, but you’ll instantly get problems trying to access it:

Warning: mkdir(): Permission denied in /var/www/html/system/storage/vendor/twig/twig/src/Cache/FilesystemCache.php on line 50
Warning: file_put_contents(/var/www/html/system/storage/logs/error.log): Failed to open stream: Permission denied in /var/www/html/system/library/log.php on line 34
Warning: file_put_contents(/var/www/html/system/storage/logs/error.log): Failed to open stream: Permission denied in /var/www/html/system/library/log.php on line 34RuntimeException: Unable to create the cache directory (/var/www/html/system/storage/cache/template/c3). in /var/www/html/system/storage/vendor/twig/twig/src/Cache/FilesystemCache.php on line 53

Ok… you are clever and wise, and have been around computers. You understand, in your bones, that podman’s rootless containers means that “apache” is really running as your normal user id, but thinks it has another id inside the container. You do a lot of reading about “podman unshare” but, you really don’t give a shit what fucking UID is being used inside the php apache container?! You finally find what sounds like the right solution, which sounds exactly right, but… not… quite?

$ podman run -p 8082:80 -d --userns=keep-id -v ./opencart-4.0.2.1/upload:/var/www/html php:8-apache
0e726377f1ecdf7120cdd74f9c9b89b424eba6602c01c167440da91e7069685a

$ podman logs -l
AH00558: apache2: Could not reliably determine the server's fully qualified domain name, using 10.0.2.100. Set the 'ServerName' directive globally to suppress this message
(13)Permission denied: AH00072: make_sock: could not bind to address [::]:80
(13)Permission denied: AH00072: make_sock: could not bind to address 0.0.0.0:80
no listening sockets available, shutting down
AH00015: Unable to open logs

Ok, this is because apache runs as root to bind port 80 inside the container, even though you’re always going to map it from the outside anyway, that sucks. Ok, one more bit of magic right? We can just tell the container that it’s allowed to bind to low ports!

podman run -p 8083:80 -d --userns=keep-id --sysctl net.ipv4.ip_unprivileged_port_start=0 -v ./opencart-4.0.2.1/upload:/var/www/html php:8-apache

And you finally get the OpenCart installation page at http://localhost:8083 None of this addresses the rest of the installation, like “removing the install folder once you’re done” and “configure mysql…”

Silabs Silicon Labs Configurator (SLC) command line

Wow, this is clearly not used much! but, it does seem to work so far? I’ve only taken a few steps, so this is note taking for me and the rest of the internet!

Installation

It talks about pip install -r requirements.txt, but even if you run it in a venv, somewhere it … escapes? and relies on system libraries, or something. You’ll get failures about unable to find jinja2 anyway. (I already had python3-jinja2 installed system wide, but it failed anyway. I had to remake the virtual env with

$ python3 -m venv --system-site-packages .env33
$ . .env33/bin/activate
(.env33) $ pip install -r requirements.txt

Generate a project

Ok, this is described (poorly, IMO) in their UG520: Software Project Generation and Configuration with SLC-CLI, (also linked from the bottom of the readme of the Gecko SDK) which at least is trying to document this process, so props for getting there I guess.

slc generate ~/SimplicityStudio/SDKs/gecko_sdk/app/bluetooth/example/soc_thermometer/soc_thermometer_freertos.slcp -d ~/src/slc-test1-soc-thermo -np --with brd4184a

Ok, that wasn’t so bad. You can use parts instead of brd ids, but that went ok. You’ll need to use “slc configuration …” to set your sdk path separately. I got a failure about “untrusted sdk” first, which was not described in UG520, but it at least gave me the command line to “trust” the sdk. I don’t know what the goals here are, I presume it’s important for secure boot stuff one day?

You can now simply “make” in the output directory. Not bad. Lots of files, lots of files but hey, command line ready to go…

Adding bluetooth configuration

Ok, but what about the UI for GATT config and things? Components I’m not covering (yet), I _think_ you just edit your .slcp in the output directory?) but I needed to know how to generate the bluetooth stuff again.

Bad news, you’re editing xml. Good news, it’s not terribly sucky, as long as you have a decent grasp of how bluetooth works. There’s online “help” for the syntax inside simplicity studio, if you click the “Manual” button

Click “View manual” to get the syntax for the XML

You can even, while you’re playing, do it in simplicity studio, and then rip it out again. Save in the UI, then right click the “gatt_configuration.btconf” and choose edit in text editor and view it as the plain old XML it is underneath. (What’s a namespace? What’s a QName? aintnobodygottime.gif)

Ok, so you edited your project_path/config/btconf/gatt_configuration.btconf and want to regenerate all the things that need regenerating, filling that sweet “autogen” folder right? slc has a temptingly named “btConfig” that sounds like it might do the right thing. So you run it and give it arguments until it’s happy right?

TL;DR:

$ slc btConfig generate -contentFolder $(realpath config/btconf) -generationOutput $(realpath autogen)

But how did we get there? Really?

$ slc btConfig generate -contentFolder config/btconfg -generationOutput autogen
Error: No 'gatt' node found in xml!
Error running command. Exit code: 1

Hrm. what? Maybe it wants the full path to the file, even though it says folder?

$ slc btConfig generate -contentFolder config/btconf/gatt_configuration.btconf -generationOutput autogen
Traceback (most recent call last):
  File "bgbuild.py", line 167, in <module>
    od = xml_to_dict(args.inputs)
  File "bgbuild.py", line 124, in xml_to_dict
    od[x] = GattXmlParser().to_string(x)
  File "/home/karlp/SimplicityStudio/SDKs/gecko_sdk/protocol/bluetooth/bin/gatt/gattxml.py", line 33, in to_string
    tree = ET.parse(xml)
  File "/home/karlp/tools/Silabs_slc_cli/bin/slc-cli/developer/adapter_packs/python/lib/python3.6/xml/etree/ElementTree.py", line 1196, in parse
    tree.parse(source, parser)
  File "/home/karlp/tools/Silabs_slc_cli/bin/slc-cli/developer/adapter_packs/python/lib/python3.6/xml/etree/ElementTree.py", line 586, in parse
    source = open(source, "rb")
FileNotFoundError: [Errno 2] No such file or directory: 'config/btconf/gatt_configuration.btconf'
Error running command. Exit code: 1

Well, progress, What? that smells like relative path brain damage….

$ slc btConfig generate -contentFolder $(realpath config/btconf/gatt_configuration.btconf) -generationOutput $(realpath autogen)

That… looks ok then? If you were clever, and had already committed the default state to revision control, you could check what it had done. And you’d see that you just lost the SiLabs OTA and health thermometer characteristics that were in the demo originally. If you look in the gatt_configuration.btconf, you also see that they’re not mentioned there! they’re just extra files dropped in the config/btconf directory. Ahhhh, so we don’t want to use the full path to the file, but we need to use our relative path workarounds we learnt later!

And that builds at least. Command line flashing/debugging/etc is for another day at least…. (We’re going to use SSv5 a bit more, we need to _work_ but at least we need to know how some of this might be possible

Simplicity Studio 5 on Fedora 34

UPDATE: You can do the steps below, and it will…. mostly work, but you’ll still run into broken things like, unable to enter text on the project config wizards or the bluetoot gatt configuration. The only _viable_ solution I’ve found really, is just to log out, and log in again choosing “Gnome on Xorg” and just not making wayland part of your daily headaches.


You still need the export GDK_BACKEND=x11 trick, and you still need the ./studio -Djxbrowser.chromium.dir=/home/$USER/.jxbrowser trick.

You also need to make sure you have git-lfs installed, or you will get fun errors like

/home/karlp/Downloads/SimplicityStudio_v5/developer/toolchains/gnu_arm/10.2_2020q4/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/bin/ld:/home/karlp/SimplicityStudio/SDKs/gecko_sdk//protocol/bluetooth/lib/EFR32BG22/GCC/binapploader.o:1: syntax error

$ cat /home/karlp/SimplicityStudio/SDKs/gecko_sdk//protocol/bluetooth/lib/EFR32BG22/GCC/binapploader.o
version https://git-lfs.github.com/spec/v1
oid sha256:59b50942a2f0085fe2c87d0d038b13b8af279c742f0d3013b1d1ad6929070a3f
size 66088

Oops, that doesn’t look like a bootloader binary! This is actually mentioned on https://docs.silabs.com/simplicity-studio-5-users-guide/latest/ss-5-users-guide-overview/known-issues as issue 76584, but you wouldn’t find that til later. The tips are to reinstall, but you can also

cd ~/SimplicityStudio/SDKs/gecko_sdk && git lfs fetch && git lfs pull && echo "whew, that took aaaages"

You can _probably_ do tricks with git lfs to just pull the single files you need, and avoid pulling the 800meg or something at 1meg/sec that it took, but this got me a building and functional simplicity studio! wheee…..

Restoring a Kicad 6.99 PCB to Kicad 6.x

Yah, I was using the 5.99 nightlies via a “kicad-nightly” package on fedora, and after Kicad 6.0 came out, this moved (correctly) to the 6.99 branch, which brought in a whole slew of new changes to the project files, which are… not backward compatible. (Which I also understand… but…)

So, what to do? First, edit the “version” in the top of the file to something like 20211014.

Then try and open the file, see how far along you were and how much got munched….

Try and remove strokes

The following VIM regex will strip all the line settings out. :%s/(stroke.*type solid))// If you had customized lines, sorry, you can’t have that in 6.0 anyway. Try re-opening the file again…

Try also :%s/(stroke.*type default))//

Try and remove thermal angles

more vim regexping…. :%s/(thermal_bridge_angle \d*)//g

That was enough for my file. Hopefully this helps someone…

Xiaomi Miijia LYWSD03MMC with pure bluetoothctl

Because software is software, it all gets thrown out every now and again for….. reasons. BlueZ, on linux, has moved away from hciconfig and hcitool and gattttool and so on, and it’s all “bluetoothctl” and “btmgmt” See https://wiki.archlinux.org/title/Bluetooth#Deprecated_BlueZ_tools for some more on that.

Anyway, I got some of these really cheap Xiaomi BTLE temperature+humidity meters. Turns out there’s a custom firmware you can flash to them and all sorts, but really, I was just interested in some basic usage, and also, as I’m getting my toes wet in bluetooth development, working out how to just plain use them as intended! (well, mostly, I’ve no intention of using any Xiaomi cloud apps)

This application claims to use the standard interface, and it’s “documentation” of this interface is https://github.com/JsBergbau/MiTemperature2#more-info and the little bit of code at

def connect():
	#print("Interface: " + str(args.interface))
	p = btle.Peripheral(adress,iface=args.interface)	
	val=b'\x01\x00'
	p.writeCharacteristic(0x0038,val,True) #enable notifications of Temperature, Humidity and Battery voltage
	p.writeCharacteristic(0x0046,b'\xf4\x01\x00',True)
	p.withDelegate(MyDelegate("abc"))
	return p

Well, that wasn’t very helpful. Using tools like NrfConnect, I’m expecting things like a service UUID and a characteristic UUID and things. Also, I don’t have gatttool to even try it like this :)

So, how to do it in “modern” bluetoothctl? Here’s the cheatsheet. First, find our meters…

$ bluetoothctl
# menu scan
# clear
# transport le
# back
# scan on
SetDiscoveryFilter success
Discovery started
[CHG] Controller <your hci mac> Discovering: yes
[NEW] Device <a meter mac> LYWSD03MMC
[NEW] Device <other devices> <other ids>
# scan off

Now, we need to connect to it. According to https://github.com/custom-components/ble_monitor#supported-sensors it actually does broadcast the details about once every 10 minutes, which is neat, but you need a key for it, and aintnobodygottimeforthat.gif.

# connect <mac address>
lots and lots of spam like
[NEW] Descriptor (Handle 0x9f94)
	/org/bluez/hci0/dev_MAC_ADDRESS/service0060/char0061/desc0063
	00002901-0000-1000-8000-00805f9b34fb
	Characteristic User Description
[NEW] Descriptor (Handle 0xa434)
	/org/bluez/hci0/dev_MAC_ADDRESS/service0060/char0061/desc0064
	00002902-0000-1000-8000-00805f9b34fb
	Client Characteristic Configuration
[NEW] Characteristic (Handle 0xa904)
	/org/bluez/hci0/dev_MAC_ADDRESS/service0060/char0065
	00000102-0065-6c62-2e74-6f696d2e696d
	Vendor specific
[NEW] Descriptor (Handle 0xb1d4)
	/org/bluez/hci0/dev_MAC_ADDRESS/service0060/char0065/desc0067
	00002901-0000-1000-8000-00805f9b34fb
	Characteristic User Description
....more lines like this.
[CHG] Device MAC_ADDRESS UUIDs: 00000100-0065-6c62-2e74-6f696d2e696d
[CHG] Device MAC_ADDRESS UUIDs: 00001800-0000-1000-8000-00805f9b34fb
[CHG] Device MAC_ADDRESS UUIDs: 00001801-0000-1000-8000-00805f9b34fb
[CHG] Device MAC_ADDRESS UUIDs: 0000180a-0000-1000-8000-00805f9b34fb
[CHG] Device MAC_ADDRESS UUIDs: 0000180f-0000-1000-8000-00805f9b34fb
[CHG] Device MAC_ADDRESS UUIDs: 0000fe95-0000-1000-8000-00805f9b34fb
[CHG] Device MAC_ADDRESS UUIDs: 00010203-0405-0607-0809-0a0b0c0d1912
[CHG] Device MAC_ADDRESS UUIDs: ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6
[CHG] Device MAC_ADDRESS ServicesResolved: yes

The characteristic you need is ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6, under the similar service UUID. So now, we just “subscribe” to notifications from it.

# menu gatt
[LYWSD03MMC]# select-attribute ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6
[LYWSD03MMC:/service0021/char0035]# notify on
[CHG] Attribute /org/bluez/hci0/dev_MAC_ADDRESS/service0021/char0035 Notifying: yes
Notify started
[CHG] Attribute /org/bluez/hci0/dev_MAC_ADDRESS/service0021/char0035 Value:
  36 09 2a f6 0b                                   6.*..           
[CHG] Attribute /org/bluez/hci0/dev_MAC_ADDRRESS/service0021/char0035 Value:
  35 09 2a f6 0b                                   5.*..           
[CHG] Attribute /org/bluez/hci0/dev_MAC_ADDRESS/service0021/char0035 Value:
  33 09 2a f6 0b                                   3.*..           
[LYWSD03MMC:/service0021/char0035]# notify off

And…. now we can go back to https://github.com/JsBergbau/MiTemperature2#more-info and decode these readings.

>>> x = "2a 09 2a 4e 0c"
>>> struct.unpack("<HbH",binascii.unhexlify((x).replace(" ","")))
(2346, 42, 3150)

With Python, that gives us a temperature of 23.46°C, humidity of 42%, and a battery level of 3.150V.

Yay.


Originally, I was blind to the subtle differences in the characteristic UUIDs, and thought I had to hand iterate them. The below text at least shows how you can do that, but it’s unnecessary.

Ok, now the nasty bit. We want to get notifications from one of the characteristics on service UUID ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6. But you can’t just “select” this, because, at least as far as I can tell, there’s no way of saying _which_ descriptor you want.

So, first you need to use scroll that big dump of descriptors (or view it again with list-attributes in the gatt menu) to work out the “locally assigned service handle” In my case it’s 0021, but I’ve got zero faith that’s a stable number. You figure it from a line like this…

[NEW] Characteristic (Handle 0xd944)
	/org/bluez/hci0/dev_MAC_ADDRESS/service0021/char0048
	ebe0ccd9-7a0a-4b0c-8a1a-6ff2997da3a6
	Vendor specific

Now, which characteristic is which? Well, thankfully, Xiaomi uses the lovely Characteristic User Description in their descriptors, so you just go through them one by one, “read”ing them, until you get to the right one…

[LYWSD03MMC:]# select-attribute /org/bluez/hci0/dev_MAC_ADDRESS/service0021/char0035/desc0037 
[LYWSD03MMC:/service0021/char0035/desc0037]# read
Attempting to read /org/bluez/hci0/dev_MAC_ADDRESS/service0021/char0035/desc0037
[CHG] Attribute /org/bluez/hci0/dev_MAC_ADDRESS/service0021/char0035/desc0037 Value:
  54 65 6d 70 65 72 61 74 75 72 65 20 61 6e 64 20  Temperature and 
  48 75 6d 69 64 69 74 79 00                       Humidity.       
  54 65 6d 70 65 72 61 74 75 72 65 20 61 6e 64 20  Temperature and 
  48 75 6d 69 64 69 74 79 00                       Humidity.       
[LYWSD03MMC:/service0021/char0035/desc0037]#

The sucky bit, is you need to manually select _each_ of the “descNNNN” underneath _each_ of the “charNNNN” under this service. (On my devices, it’s the second characteristic with dual descriptors…)

now, select the characteristic itself. (you can’t get notifications on the descriptor…)

[LYWSD03MMC:/service0021/char0035/desc0037]# select-attribute /org/bluez/hci0/dev_MAC_ADDRESS/service0021/char0035
[LYWSD03MMC:/service0021/char0035]# notify on
[CHG] Attribute /org/bluez/hci0/dev_MAC_ADDRESS/service0021/char0035 Notifying: yes
Notify started
[CHG] Attribute /org/bluez/hci0/dev_MAC_ADDRESS/service0021/char0035 Value:
  2b 09 2a 4e 0c                                   +.*N.           
[CHG] Attribute /org/bluez/hci0/dev_MAC_ADDRESS/service0021/char0035 Value:
  2a 09 2a 4e 0c                                   *.*N.           
[CHG] Attribute /org/bluez/hci0/dev_MAC_ADDRESS/service0021/char0035 Value:
  2b 09 2a 4e 0c                                   +.*N.           
[CHG] Attribute /org/bluez/hci0/dev_MAC_ADDRESS/service0021/char0035 Value:
  2b 09 2a 4e 0c                                   +.*N.           
[CHG] Attribute /org/bluez/hci0/dev_MAC_ADDRESS/service0021/char0035 Value:
  29 09 2a 4e 0c                                   ).*N.           
[LYWSD03MMC:/service0021/char0035]# notify off

Autofailing autotools are autohell, as always

“Needed” a new version of something, so build from source. Configure not available, because… autohell, so run “autogen.sh” instead.

karlp@nanopiduo2:~/src/libgpiod$ ./autogen.sh 
autoreconf: Entering directory `.'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force -I m4
aclocal: warning: couldn't open directory 'm4': No such file or directory
autoreconf: configure.ac: tracing
autoreconf: configure.ac: creating directory autostuff
autoreconf: configure.ac: not using Libtool
autoreconf: running: /usr/bin/autoconf --force
configure.ac:92: error: possibly undefined macro: AC_CHECK_HEADERS
      If this token and others are legitimate, please use m4_pattern_allow.
      See the Autoconf documentation.
configure.ac:172: error: possibly undefined macro: AC_LIBTOOL_CXX
configure.ac:174: error: Unexpanded AX_ macro found. Please install GNU autoconf-archive.
configure.ac:179: error: possibly undefined macro: AC_LANG_PUSH
configure.ac:181: error: possibly undefined macro: AC_LANG_POP
configure.ac:188: error: Unexpanded AX_ macro found. Please install GNU autoconf-archive.
autoreconf: /usr/bin/autoconf failed with exit status: 1
karlp@nanopiduo2:~/src/libgpiod$

Whatever, this is “traditional” that you can’t actually use autohell without adding more autohell from somewhere else, but ok, bend the knee, install autoconf-archive and continue….

karlp@nanopiduo2:~/src/libgpiod$ ./autogen.sh 
autoreconf: Entering directory `.'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force -I m4
aclocal: warning: couldn't open directory 'm4': No such file or directory
autoreconf: configure.ac: tracing
autoreconf: configure.ac: not using Libtool
autoreconf: running: /usr/bin/autoconf --force
configure.ac:92: error: possibly undefined macro: AC_CHECK_HEADERS
      If this token and others are legitimate, please use m4_pattern_allow.
      See the Autoconf documentation.
configure.ac:172: error: possibly undefined macro: AC_LIBTOOL_CXX
configure.ac:179: error: possibly undefined macro: AC_LANG_PUSH
configure.ac:181: error: possibly undefined macro: AC_LANG_POP
autoreconf: /usr/bin/autoconf failed with exit status: 1
karlp@nanopiduo2:~/src/libgpiod$

wat? really? that’s it? Thanks for nothing. Google and the accumulated wisdom of years of hate suggest that, as this is a “new” machine, I might not have installed pkg-config. (Given that the whole thing with autohell is finding things, you might think it could give you a better error?) ok, Install that, try again

karlp@nanopiduo2:~/src/libgpiod$ ./autogen.sh 
autoreconf: Entering directory `.'
autoreconf: configure.ac: not using Gettext
autoreconf: running: aclocal --force -I m4
aclocal: warning: couldn't open directory 'm4': No such file or directory
autoreconf: configure.ac: tracing
autoreconf: configure.ac: not using Libtool
autoreconf: running: /usr/bin/autoconf --force
configure.ac:172: error: possibly undefined macro: AC_LIBTOOL_CXX
      If this token and others are legitimate, please use m4_pattern_allow.
      See the Autoconf documentation.
autoreconf: /usr/bin/autoconf failed with exit status: 1
karlp@nanopiduo2:~/src/libgpiod$

Progress, but… still not there. Still absolutely atrociously useless error messages. Now, I’ve read the README, it says to install autoconf-archive, and that’s about it. I have python3-dev and libstdc++-9-dev I’m not sure what else now…

Oh right. libtool, another gross piece of historic nonsense, that mostly just gets in the way, and leaves pretend files around the place.

Now autogen will ~finish, and run configure, happily checking whether I’m running on a 30 year old unpatched sparc solaris, so it applies the right workarounds, but don’t worry…

configure: error: "libgpiod needs linux headers version >= v5.10.0"

I mean, I’m super glad we included all that “portable” autohell bullshit when we’re explicitly tied to linux anyway. And not just any linux. At the time of writing, 5.10.0 was three days old.

At this point, there are now _other_ problems that autotools, but this is just another example of why you should NEVER be using autotools in 2020.

Jenkins agent systemd unit file

So, you try to setup an agent, and instead of getting a nice package or anything, you get told, “run this long java command line app” …. wat. Here’s a (very) basic system unit file to run your agent. You can copy the command lines from what jenkins provides itself.

$ cat /etc/systemd/system/jenkins-agent.service 
[Unit]
Description=My radical Jenkins agent
Wants=network-online.target
After=network-online.target

[Service]
ExecStart=/usr/bin/java -jar /var/opt/jenkins-agent/agent.jar -jnlpUrl https://radical.example.org/computer/blah/slave-agent.jnlp -secret @/var/opt/jenkins-agent/my.jenkins.secret-file -workDir /var/opt/jenkins-agent
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

(And remember, JDK8 for your agent, until https://issues.jenkins-ci.org/browse/JENKINS-63313 is fixed)

Then, just systemctl enable jenkins-agent and systemctl start jenkins-agent.

Actually using FEL to boot openwrt on friendlyarm nanopi duo2

Following on from where we left off, now let’s actually use FEL for the whole process, not just to get uboot loaded. In the last piece, once uboot was loaded, we used uboot+tftp to boot our openwrt ramdisk, but FEL can do it all in one hit, over usb, according to http://linux-sunxi.org/FEL/USBBoot#Booting_the_whole_system_over_USB_.28U-Boot_.2B_kernel_.2B_initramfs.29 and that’s way more useful on things that might not have an ethernet port onboard.

We basically just take our steps from the last one, and add them as options to the sunxi-fel tool.

First, we trim down our “my.env” file, as now it just needs to boot.


$ cat my-fel.cmd
setenv bootargs console=ttyS0,115200 earlyprintk
bootm $kernel_addr_r - $fdt_addr_r

Now, we convert that to the “scr” file that uboot will run magically.

$ tools/mkimage -C none -A arm -T script -d my-fel.cmd my-fel.scr

Now, use sunxi-fel with all the wonderful paths into the build guts of openwrt.

$ sunxi-fel uboot u-boot-sunxi-with-spl.bin write-with-progress 0x42000000 /home/karlp/src/openwrt-git/bin/targets/sunxi/cortexa7/openwrt-sunxi-cortexa7-sun8i-h3-nanopi-neo-initramfs-kernel.bin write 0x43000000 ~/src/openwrt-git/build_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/linux-sunxi_cortexa7/linux-4.14.82/arch/arm/boot/dts/sun8i-h3-nanopi-neo.dtb write 0x43100000 my-fel.scr
100% [================================================] 4013 kB, 770.4 kB/s

Because openwrt’s buildroot builds us a nice kernel+ramdisk image out of the box, (well, if you select “ramdisk” in the image settings) we don’t need to write the uImage and rootfs separately as indicated on the http://linux-sunxi.org/FEL/USBBoot page.

For reference, the openwrt diffconfig to build this is just

$ ./scripts/diffconfig.sh
CONFIG_TARGET_sunxi=y
CONFIG_TARGET_sunxi_cortexa7=y
CONFIG_TARGET_sunxi_cortexa7_DEVICE_sun8i-h3-nanopi-neo=y
CONFIG_DEVEL=y
CONFIG_TARGET_INITRAMFS_COMPRESSION_NONE=y
CONFIG_TARGET_ROOTFS_INITRAMFS=y

Booting openwrt on nanopi duo2 (or a nanopi neo) via FEL

Edit: See the next post to use just FEL via USB, (no cheating and using tftp afterwards like we do here)

(Very rough unformatted, just so I don’t lose it)

FriendlyARM NanoPi Duo2 is ~similar enough to a FriendlyARM NanoPi Neo to get started. Later, we’ll work on… later stuff.

I don’t want to go hacking around with sd cards and crap while I’m developing stuff, and FEL mode is great.

So… get a uboot built (2018.11 is what I tested) using “make nanopi_neo_defconfig” (You will almost definitely want to enable “Networking Support->Random ethaddr if unset”

Now, patch sunxi-fel: https://github.com/linux-sunxi/sunxi-tools/pull/117

Now, make an environment file with some helpers…. (you can do this by hand if you like)

#=uEnv
myvar=world
bootcmd=echo "Hello $myvar."
bootargs=console=ttyS0,115200 earlyprintk
serverip=192.168.3.6
resetserver=setenv serverip 192.168.3.6
loadkernel=tftp $kernel_addr_r build_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/linux-sunxi_cortexa7//sun8i-h3-nanopi-neo-kernel.bin
loaddtb=tftp $fdt_addr_r build_dir/target-arm_cortex-a7+neon-vfpv4_musl_eabi/u-boot-nanopi_neo/u-boot-2018.05/arch/arm/dts/sun8i-h3-nanopi-neo.dtb
loaddisk=tftp $ramdisk_addr_r
# Running dhcp will reset serverip....
winning=run resetserver && run loadkernel && run loaddtb && bootm $kernel_addr_r - $fdt_addr_r

(the magic variables are reffered to at http://linux-sunxi.org/FEL/USBBoot#Booting_the_whole_system_over_USB_.28U-Boot_.2B_kernel_.2B_initramfs.29)
The magic trick of bootm $kernel_addr_r – $fdt_addr_r I got from extracting the openwrt sdcard image file, and reading the “boot.scr” file in the first partition.

Now, go and build openwrt master

Now, setup a dhcp/tftp server as appropriate for your network.

Now, use (patched) sunxi-fel (fixing udev perms if necessary):

sunxi-fel uboot u-boot-sunxi-with-spl.bin write 0x43100000 my.env

Now, on serial console, use uboot to dhcp an address and run stuff…


dhcp
(ctrl-c to abort the dumb attempts at autofinding an image)
run resetserver
run winning

Now, enjoy the fruits of a whole lot of people’s labour…..


=> bootm $kernel_addr_r - $fdt_addr_r
## Booting kernel from Legacy Image at 42000000 ...
Image Name: ARM OpenWrt Linux-4.14.82
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 4013368 Bytes = 3.8 MiB
Load Address: 40008000
Entry Point: 40008000
Verifying Checksum ... OK
## Flattened Device Tree blob at 43000000
Booting using the fdt blob at 0x43000000
EHCI failed to shut down host controller.
Loading Kernel Image ... OK
Loading Device Tree to 49ff9000, end 49fff4b7 ... OK

Starting kernel ...

[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 4.14.82 (karlp@beros) (gcc version 7.3.0 (OpenWrt GCC 7.3.0 r8575-a734450d6f)) #0 SMP PREEMPT Mon Nov 26 20:27:17 2018
[ 0.000000] CPU: ARMv7 Processor [410fc075] revision 5 (ARMv7), cr=30c5387d
[ 0.000000] CPU: div instructions available: patching division code
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[ 0.000000] OF: fdt: Machine model: FriendlyARM NanoPi NEO

boring bootlog snipped, you know what they look like

From here, we need to move to a real separate device tree for the duo2, prepare to get the AP6212 module up and running, and handle how overlays/custom versions should be handled….