August 2018

Solar Cluster: Kernel driver now up on Github

So, I’m happy enough with the driver now that I’ll collapse down the commits and throw it up onto the Github repository.  I might take another look at kernel 4.18, but for now, you’ll find them on the ts7670-4.14.67 branch.

Two things I observe about this voltage monitor:

  1. The voltage output is not what you’d call, accurate.  I think it’s only a 10-bit ADC, which is still plenty good enough for this application, but the reading I think is “high” by about 50mV.
  2. There’s significant noise on the reading, with noticeable quantisation steps.

Owing to these, and to thwart the possibility of using this data in side-channel attacks using power analysis, I’ve put a 40-sample moving-average filter on the “public” data.

Never the less, it’s a handy party trick, and not one I expected these devices to be able to do.  My workplace manages a big fleet of these single-board computers in the residential towers at Barangaroo where they spend all day polling Modbus and M-Bus meters.  In the event we’re at all suspicious about DC power supplies though, it’s a simple matter to load this kernel tree (they already run U-Boot) and configure collectd (which is also installed).

I also tried briefly switching off the mains power to see that I was indeed reading the battery voltage and not just a random number that looked like the voltage.  That yielded an interesting effect:

You can see where I switched the mains supply off, and back on again.  From about 8:19PM the battery voltage predictably fell until about 8:28PM where it was at around 12.6V.

Then it did something strange, it rose about 100mV before settling at 12.7V.  I suspect if I kept it off all night it’d steadily decrease: the sun has long set.  I’ve turned the mains charger back on now, as you can see by the step-rise shortly after 8:44PM.

The bands on the above chart are the alert zones.  I’ll get an email if the battery voltage strays outside of that safe region of 12-14.6V.  Below 12V, and I run the risk of deep-cycling the batteries.  Above 14.6V, and I’ll cook them!

The IPMI BMCs on the nodes already sent me angry emails when the battery got low, so in that sense, Grafana duplicates that, but does so with pretty charts.  The BMCs don’t see when the battery gets too high though, for the simple matter that what they see is regulated by LDOs.

Solar Cluster: Getting the battery voltage into Grafana

I’ve succeeded in getting a working battery monitor kernel module. This is basically taking the application note by Technologic Systems and spinning that into a power supply class driver that reports the voltage via sysfs.

As it happens, the battery module in collectd does not see this as a “battery”, something I’ll look at later. For now the exec plug-in works well enough. This feeds through eventually to an InfluxDB database with Grafana sitting on top.

https://netmon.longlandclan.id.au/d/IyZP-V2mk/battery-voltage?orgId=1

Solar Cluster: Kernel driver debugging

So, I successfully last night, parted the core bits out of ts_wdt.c and make ts-mcu-core.c.  This is a multi-function device, and serves to provide a shared channel for the two drivers that’ll use it.

Tonight, I took a stab at writing the PSU part of it.  Suffice to say, I’ve got work to do:

[  158.712960] Unable to handle kernel NULL pointer dereference at virtual address 00000005
[  158.721328] pgd = c3854000
[  158.724089] [00000005] *pgd=4384f831, *pte=00000000, *ppte=00000000
[  158.730629] Internal error: Oops: 1 [#3] ARM
[  158.734947] Modules linked in: 8021q garp mrp stp llc nf_conntrack_ipv4 nf_defrag_ipv4 iptable_filter ip_tables xt_tcpudp nf_conntrack_ipv6 nf_defrag_ipv6 xt_conntrack nf_conntrack ip6table_filter ip6_tables x_tables flexcan can_dev
[  158.755812] CPU: 0 PID: 2059 Comm: cat Tainted: G      D         4.14.67-vrt-ts7670+ #3
[  158.763840] Hardware name: Freescale MXS (Device Tree)
[  158.769008] task: c68f3a20 task.stack: c3846000
[  158.773598] PC is at ts_mcu_transfer+0x1c/0x48
[  158.778073] LR is at 0x3
[  158.780630] pc : []    lr : [<00000003>]    psr: 60000013
[  158.786918] sp : c3847e44  ip : 00000000  fp : 014000c0
[  158.792165] r10: c5035000  r9 : c5305900  r8 : c777b428
[  158.797412] r7 : c0a7fa80  r6 : c777b400  r5 : c5035000  r4 : c3847e6c
[  158.803961] r3 : c3847e58  r2 : 00000001  r1 : c3847e4c  r0 : c07b8c68
[  158.810512] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
[  158.817671] Control: 0005317f  Table: 43854000  DAC: 00000051
[  158.823440] Process cat (pid: 2059, stack limit = 0xc3846190)
[  158.829212] Stack: (0xc3847e44 to 0xc3848000)
[  158.833611] 7e40:          c05bd150 00000001 00010000 00000004 c3847e48 00000150 c5035000
[  158.841833] 7e60: c777b420 c05bcaa4 c4f70c60 c777e070 c0a7fa80 c05bca20 00000fff c07ad4b0
[  158.850051] 7e80: c777b428 c04e46dc c4f52980 00001000 00000fff c01b1994 c4f52980 c4f70c60
[  158.858268] 7ea0: c3847ec8 ffffe000 00000000 c3847f88 00000001 c0164eac c3847fb0 c4f529b0
[  158.866487] 7ec0: 00020000 b6e3d000 00000000 00000000 c4f73f70 00000800 00000000 c01b0f60
[  158.874703] 7ee0: 00020000 c4f70c60 ffffe000 c3847f88 00000000 00000000 00000000 c013eb84
[  158.882918] 7f00: 000291ac 00000000 00000000 c0009344 00000077 b6e3c000 00000022 00000022
[  158.891135] 7f20: c686bdc0 c0117838 000b6e3c c3847f80 00022000 c686be14 b6e3c000 00000000
[  158.899354] 7f40: 00000000 00022000 b6e3d000 00020000 c4f70c60 ffffe000 c3847f88 c013ed0c
[  158.907571] 7f60: 00000022 00000000 000b6e3c c4f70c60 c4f70c60 b6e3d000 00020000 c000a9e4
[  158.915786] 7f80: c3846000 c013f2d8 00000000 00000000 00000000 00000000 00000000 00000000
[  158.924002] 7fa0: 00000003 c000a820 00000000 00000000 00000003 b6e3d000 00020000 00000000
[  158.932217] 7fc0: 00000000 00000000 00000000 00000003 00020000 00000000 00000001 00000000
[  158.940434] 7fe0: be8a62c0 be8a62ac b6eb77c4 b6eb6b9c 60000010 00000003 00000000 00000000
[  158.948691] [] (ts_mcu_transfer) from [] (ts_psu_get_prop+0x38/0xb0)
[  158.956847] [] (ts_psu_get_prop) from [] (power_supply_show_property+0x84/0x220)
[  158.966036] [] (power_supply_show_property) from [] (dev_attr_show+0x1c/0x48)
[  158.974974] [] (dev_attr_show) from [] (sysfs_kf_seq_show+0x84/0xf0)
[  158.983129] [] (sysfs_kf_seq_show) from [] (seq_read+0xcc/0x4f4)
[  158.990930] [] (seq_read) from [] (__vfs_read+0x1c/0x11c)
[  158.998117] [] (__vfs_read) from [] (vfs_read+0x88/0x158)
[  159.005304] [] (vfs_read) from [] (SyS_read+0x3c/0x90)
[  159.012232] [] (SyS_read) from [] (ret_fast_syscall+0x0/0x28)
[  159.019766] Code: e52de004 e281300c e590e004 e25cc001 (e1dee0b2) 
[  159.026278] ---[ end trace 2807dc313991fd87 ]---

The good news is the machine didn’t crash.c

Solar Cluster: Battery voltage kernel module

So, I had a brief look after getting kernel 4.18.5 booting… sure enough the problem was I had forgotten the watchdog, although I did see btrfs trigger a deadlock warning, so I may not be out of the woods yet.  I’ve posted the relevant kernel output to the linux-btrfs list.

Anyway, as it happens, that watchdog driver looks like it’ll need some re-factoring as a multi-function device.  At the moment, ts-wdt.c claims it based on this binding.

If I try to add a second driver, they’ll clash, and I expect the same if I try to access it via userspace.  So the sensible thing to do here, is to add a ts-companion.c MFD driver here, then re-factor ts-wdt.c to use it.  From there, I can write a ts-psu.c module which will go right here.

I think I’ll definitely be digging into those older sources to remind myself how that all worked.

Pondering a LED controller

So, a bit over 10 years ago, I made the Hat Lamp.  You can tell how long ago it was as it calls out Dick Smith part numbers for things like resistors.  (How long ago did they give that up?)

Anyway, the original still works, although my wiring is less than perfect.  I’ve thought about modernising it.  Back in 2007, addressable LEDs didn’t exist.  The project got by with nothing more than a 74HC14.  It used one gate as a pierce oscillator, a second to generate a 180° out-of-phase signal, and a third to perform “automatic” control based on the light that fell on a LDR mounted on the top of the hat.

I’ve thought about whether I modernise it.  I have access to 3D printing facilities at HSBNE, so destroying a hard hat is no longer of concern: the design I could come up with could be made to fit a hard hat without modification, meaning it would retain its safety standard qualifications.  LED technology has marched on, in 2007 a 1W LED was considered bright.  The Ay-up headlights I use when cycling are many times brighter than that.  These headlights do come with a headband accessory, which I have, but I find they’re a bit cumbersome.  They however work great on a hard hat or helmet.

That said, for WICEN activities, they’re often too bright, even on their lowest power setting.

MCUs are also cheaper today than they used to be.  And we have addressable LEDs.  Meaning that I could have the old alternating red “alien-abduction head first” pattern the old one, or any number of patterns to suit the occasion.

That said, I’m a little concerned about APA Electronic throwing their weight around.  I actually was considering the APA102s, as they use a SPI style interface which is less timing-sensitive than World Semi’s WS2812s, but really, I hadn’t made a firm choice.  Then, Pimoroni got that letter.  I have no idea whether that letter was (1) a hoax (as in, not actually sent from APA Electronic), (2) the matter settled or (3) the matter still in progress.

In any case, the patent referenced talks about synchronous interfaces.  One common gripe with the WS2812s is that the interface relies on strict timing, which is harder to do with higher-level MCUs and CPUs.  Arduinos can work them fine, but as it’s a somewhat custom serial link, you’ve got to be able to bit-bang it via GPIOs and not all systems are good at that.  Using SPI avoids that problem at the cost of an extra wire.  I wondered if there was another way.

This is what I came up with as a concept.  UARTs idle “high” when not transmitting, so the TX line can serve as a pull-up resistance when the master is not sending anything.  Some MCUs can also re-map their pins (e.g. NXP LPC81x, TI CC2538, Nordic NRF52840), others natively support half-duplex UART Rx/Tx on a single pin (e.g. Microchip ATTiny202).

That allows us to have a shared “bus” with 3 wires between each module: VDD, Data and VSS… the same as the WS2812s.  Unlike the WS2812s, this bus would be built on the UART standard, thus less sensitive to timing jitter.

The problem then is, how do you address each LED?  The WS2812 and APA102s solve this by making the whole bus function as one big shift register.  This makes the electronics simple, but has the cost that you can only communicate one way, from MCU to LED controller.  Thus, you have to maintain a framebuffer, and if you want to just change the colour of one LED, you’ve got to shift the entire framebuffer out.

Why can’t the LEDs have more brains?  How hard is it to DIY a LED controller?

The above arrangement uses the concept of “upstream” and “downstream” ports.  A bi-lateral switch is used to disconnect the “downstream” port under the control of the LED firmware.  If each slave on power up waited for some initialisation signal from the master, all could then disconnect their downstream ports, which then means the next command would only be received by the first LED module.

On telling it its assigned address, it could connect its downstream neighbour and you’d then be able to talk to those two LEDs, one of which would be at some unknown address, and the other, assigned.

This would repeat until you got to the end of the chain.  Given that the downstream LED can “hear” its upstream neighbour when it is connected, it’s not hard for the downstream LED to assume its address is one after its upstream neighbour.

Disconnection would be achieved via some sort of tri-state bi-directional buffer such as a bilateral switch.  I’ve used 4066s in the diagram, but in reality, I’d be using a single-unit version like a SN74LVC1G66.

It’s also common to consider these as matrices.  It’d be really neat, if you say had an array of say 320×240 pixels that the LEDs should use 4-byte addressing, where the lowest 9 bits was the X co-ordinate and the upper bits the Y co-ordinate.  Thus the addressing would count from 0x0000000 to 0x0000013f, then skip to 0x0000200.  That’s a simple arithmetic operation.  By connecting the next neighbour then announcing the address, this could trigger the neighbour to do the same automatically.  The master would then hear each and every pixel announce its address as it comes online.  When the messages stop, initialisation is complete.

A major problem with asynchronous communications is figuring out the baud rate.  Luckily, LIN has solved that problem.  No, I won’t actually use the LIN protocols, I’ll just use its sync frame, support for which is built into many MCU UART modules.  LIN uses a header which includes a BREAK followed by the 0x55 byte which helps the slave figure out the correct baud rate being used.  If I use that same sequence, I get autobauding for free.

So putting this together, how would this work?  Let’s assume everything has just been reset.  Each protocol frame would be bounded by a header and a trailer, the header being based on the LIN standard.  Not sure what the trailer will look like at this point, maybe a CRC.

  1. On power-on, the slaves all link their downstream ports.  (Thus if a controller crashes, you lose just that one pixel.  It also allows all slaves to receive the initial configuration commands.)
  2. The master then tells the slaves to commence a roll-call.  The instruction would be made up of:
    1. The “commence roll-call” op-code (1 byte)
    2. The length in bytes of the addresses to be used (1 byte; call its value L)
    3. The number of bits in the address representing a single row (1 byte; call this D)
    4. The number of pixels per row (L bytes, call this M)
  3. The slaves immediately disconnect their downstream ports then respond back with
    1. The “OK” op-code
  4. Since the head of the line would have disconnected every other slave, the master only hears one “OK” response.  The master performs the following computation:
    • Address = (2^(8L)) – 1
  5. The master starts the roll-call off by sending the following on the bus.
    1. The “Address announcement” op-code (1 byte)
    2. The address it calculated (L bytes)
  6. Since just the first slave is connected, it hears this.  It connects its downstream neighbour, then with the received address, it performs the following algorithm:
    • Address = UpstreamAddress + 1
    • If (Address & ((2^D)-1) > M:
      • Address = ((Address >> D) + 1) << D
  7. With its new address, and the immediate neighbour connected, it sends
    1. The “Address announcement” op-code (1 byte)
    2. The address it calculated (L bytes)

Ad infinite um, until the last in the chain announces its address.

The master of course hears all, including its own traffic.  As an example, if we considered a 320×200 pixel panel with 32-bit addressing; thus L=4, D=9 and M=320, it would hear this:

  • HEADER OP_ROLL_CALL L=4 D=9 M=320 TRAILER: Begin roll-call
  • HEADER RES_OK TRAILER: Slaves ready for roll-call
  • HEADER OP_ADDR_ANN ADDR=0xffffffff TRAILER: Master “my address is 0xffffffff”
  • HEADER OP_ADDR_ANN ADDR=0x00000000 TRAILER: First pixel “my address is 0x00000000”
  • HEADER OP_ADDR_ANN ADDR=0x00000001 TRAILER: Second pixel “my address is 0x00000001”
  • etc
  • HEADER OP_ADDR_ANN ADDR=0x0000013f TRAILER: 320th pixel “my address is 0x0000013f”
  • HEADER OP_ADDR_ANN ADDR=0x00000200 TRAILER: 321st pixel “my address is 0x00000200”
  • etc

At the end, everybody knows their address, including the master (which is derived from the address length; its address is “all ones”), and because each slave connected its neighbour, everyone can communicate together.

Operation codes could be implemented that allow a pixel to be set to a given colour, or to report its present colour.  Since they all know how to interpret the address to form co-ordinates, it’s possible for the master to send a command that says “fill rectangle (X1,Y1)-(X2,Y2) with colour C”, all pixels hear this simultaneously and the action is performed.

Or better yet, “pixels in area (X1,Y1)-(X2,Y2), copy the colour from the neighbour to your right”, which would allow for scrolling text displays.  The pixels would know immediately who to ask, and could have an “agreed upon” order in which to perform operations.  Thus (X1,Y1) would know to ask (X1+1,Y1) for its colour, copy that to its own output, then tell (X1,Y1+1) to perform its step.  (X1,Y2) would know that once it copied its colour from (X1+1,Y2), it needs to poke (X1+1,Y1).  Finally (X2,Y2) would know to tell the master that the operation is complete.

Blitting can also be done.  You know the operation, you know how to obtain the input data, the rest can be done independent of the master MCU.

The microcontrollers don’t need a lot of brains to do this, nor does the master for that matter, it’s distributed brains that get the job done.  The part I’m thinking of for this is the Microchip ATTiny202, which can be bought for under 60c a piece and features hardware UART and up to 4 PWM channels.

For sure, add in the bilateral switch, some passives, a PCB and a RGB LED and you’ve blown more money than the competition, but in this case, you’ve got a fully programmable LED controller with open-source firmware, that’s not patent encumbered.

It might be a little while before this MCU is available, Mouser reckon they’ll have them late October, which is fine I can wait.  Until then, plenty of time to research the problem.

Solar Cluster: Battery monitor PC now running Gentoo

So, after some argument, and a bit of sitting on a concrete floor with the netbook, I managed to get Gentoo loaded onto the TS-7670.  Right now it’s running off the MicroSD card, I’ll get things right, then shift it across to eMMC.

ts7670 ~ # emerge --info
Portage 2.3.40 (python 3.5.5-final-0, default/linux/musl/arm/armv7a, gcc-6.4.0, musl-1.1.19, 4.14.15-vrt-ts7670-00031-g1a006273f907-dirty armv5tejl)
=================================================================
System uname: Linux-4.14.15-vrt-ts7670-00031-g1a006273f907-dirty-armv5tejl-ARM926EJ-S_rev_5_-v5l-with-gentoo-2.4.1
KiB Mem:      111532 total,     13136 free
KiB Swap:    4194300 total,   4191228 free
Timestamp of repository gentoo: Fri, 17 Aug 2018 16:45:01 +0000
Head commit of repository gentoo: 563622899f514c21f5b7808cb50f6e88dbd7d7de
sh bash 4.4_p12
ld GNU ld (Gentoo 2.30 p2) 2.30.0
app-shells/bash:          4.4_p12::gentoo
dev-lang/perl:            5.24.3-r1::gentoo
dev-lang/python:          2.7.14-r1::gentoo, 3.5.5::gentoo
dev-util/pkgconfig:       0.29.2::gentoo
sys-apps/baselayout:      2.4.1-r2::gentoo
sys-apps/openrc:          0.34.11::gentoo
sys-apps/sandbox:         2.13::musl
sys-devel/autoconf:       2.69-r4::gentoo
sys-devel/automake:       1.15.1-r2::gentoo
sys-devel/binutils:       2.30-r2::gentoo
sys-devel/gcc:            6.4.0-r1::musl
sys-devel/gcc-config:     1.8-r1::gentoo
sys-devel/libtool:        2.4.6-r3::gentoo
sys-devel/make:           4.2.1::gentoo
sys-kernel/linux-headers: 4.13::musl (virtual/os-headers)
sys-libs/musl:            1.1.19::gentoo
Repositories:

gentoo
    location: /usr/portage
    sync-type: rsync
    sync-uri: rsync://virtatomos.longlandclan.id.au/gentoo-portage
    priority: -1000
    sync-rsync-verify-jobs: 1
    sync-rsync-extra-opts: 
    sync-rsync-verify-metamanifest: yes
    sync-rsync-verify-max-age: 24

ACCEPT_KEYWORDS="arm"
ACCEPT_LICENSE="* -@EULA"
CBUILD="arm-unknown-linux-musleabi"
CFLAGS="-Os -pipe -march=armv5te -mtune=arm926ej-s -mfloat-abi=soft"
CHOST="arm-unknown-linux-musleabi"
CONFIG_PROTECT="/etc /usr/share/gnupg/qualified.txt"
CONFIG_PROTECT_MASK="/etc/ca-certificates.conf /etc/env.d /etc/gconf /etc/gentoo-release /etc/sandbox.d /etc/terminfo"
CXXFLAGS="-Os -pipe -march=armv5te -mtune=arm926ej-s -mfloat-abi=soft"
DISTDIR="/home/portage/distfiles"
ENV_UNSET="DBUS_SESSION_BUS_ADDRESS DISPLAY PERL5LIB PERL5OPT PERLPREFIX PERL_CORE PERL_MB_OPT PERL_MM_OPT XAUTHORITY XDG_CACHE_HOME XDG_CONFIG_HOME XDG_DATA_HOME XDG_RUNTIME_DIR"
FCFLAGS="-O2 -pipe -march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=hard"
FEATURES="assume-digests binpkg-logs config-protect-if-modified distlocks ebuild-locks fixlafiles merge-sync multilib-strict news parallel-fetch preserve-libs protect-owned sandbox sfperms strict unknown-features-warn unmerge-logs unmerge-orphans userfetch userpriv usersandbox usersync xattr"
FFLAGS="-O2 -pipe -march=armv7-a -mfpu=vfpv3-d16 -mfloat-abi=hard"
GENTOO_MIRRORS=" http://virtatomos.longlandclan.id.au/portage http://mirror.internode.on.net/pub/gentoo http://ftp.swin.edu.au/gentoo http://mirror.aarnet.edu.au/pub/gentoo"
INSTALL_MASK="charset.alias"
LANG="en_AU.UTF-8"
LDFLAGS="-Wl,-O1 -Wl,--as-needed"
PKGDIR="/usr/portage/packages"
PORTAGE_CONFIGROOT="/"
PORTAGE_RSYNC_OPTS="--recursive --links --safe-links --perms --times --omit-dir-times --compress --force --whole-file --delete --stats --human-readable --timeout=180 --exclude=/distfiles --exclude=/local --exclude=/packages --exclude=/.git"
PORTAGE_TMPDIR="/var/tmp"
USE="arm bindist cli crypt cxx dri fortran iconv ipv6 modules ncurses nls nptl openmp pam pcre readline seccomp ssl tcpd unicode xattr zlib" APACHE2_MODULES="authn_core authz_core socache_shmcb unixd actions alias auth_basic authn_alias authn_anon authn_dbm authn_default authn_file authz_dbm authz_default authz_groupfile authz_host authz_owner authz_user autoindex cache cgi cgid dav dav_fs dav_lock deflate dir disk_cache env expires ext_filter file_cache filter headers include info log_config logio mem_cache mime mime_magic negotiation rewrite setenvif speling status unique_id userdir usertrack vhost_alias" CALLIGRA_FEATURES="karbon plan sheets stage words" COLLECTD_PLUGINS="df interface irq load memory rrdtool swap syslog" ELIBC="musl" GPSD_PROTOCOLS="ashtech aivdm earthmate evermore fv18 garmin garmintxt gpsclock isync itrax mtk3301 nmea ntrip navcom oceanserver oldstyle oncore rtcm104v2 rtcm104v3 sirf skytraq superstar2 timing tsip tripmate tnt ublox ubx" INPUT_DEVICES="libinput keyboard mouse" KERNEL="linux" LCD_DEVICES="bayrad cfontz cfontz633 glk hd44780 lb216 lcdm001 mtxorb ncurses text" LIBREOFFICE_EXTENSIONS="presenter-console presenter-minimizer" OFFICE_IMPLEMENTATION="libreoffice" PHP_TARGETS="php5-6 php7-0" POSTGRES_TARGETS="postgres9_5 postgres10" PYTHON_SINGLE_TARGET="python3_6" PYTHON_TARGETS="python2_7 python3_6" RUBY_TARGETS="ruby23" USERLAND="GNU" VIDEO_CARDS="dummy fbdev v4l" XTABLES_ADDONS="quota2 psd pknock lscan length2 ipv4options ipset ipp2p iface geoip fuzzy condition tee tarpit sysrq steal rawnat logmark ipmark dhcpmac delude chaos account"
Unset:  CC, CPPFLAGS, CTARGET, CXX, EMERGE_DEFAULT_OPTS, LC_ALL, LINGUAS, MAKEOPTS, PORTAGE_BINHOST, PORTAGE_BUNZIP2_COMMAND, PORTAGE_COMPRESS, PORTAGE_COMPRESS_FLAGS, PORTAGE_RSYNC_EXTRA_OPTS

I still have to update the kernel.  I actually did get kernel 4.18 to boot, but I forgot to add in support for the watchdog, so U-Boot tickled it, then the watchdog got hungry and kicked the reset half way through the boot sequence.

Rolling back to my older 4.14 kernel works.  I’ll try again with 4.18.5 in a moment.  Failing that, I have also brought the 4.14 patches up to 4.14.69 which is the latest LTS release of the kernel.

I’ve started looking at the power supply sysfs device class, with a view to exposing the supply voltage via sysfs.  The thinking here is that collectd supports reading this via the “battery” module (and realistically, it is a battery that is being measured: two 105Ah AGMs).

Worst case is I do something a little proprietary and deal with it in user space.  I’ll have to dig up the Linux kernel tree I did for Jacques Electronics all those years ago, as that had some examples of interfacing sysfs to a Cypress PSOC device that was acting as an I²C slave.  Rather than using an off-the-shelf solution, they programmed up a MCU that did power management, touchscreen sensing, keypad sensing, RGB LED control and others, all in one chip.  (Fun to try and interface that to the Linux kernel.)

Technologic Systems appear to have done something similar.  The device ID 0x78 implies a 10-bit device, but I think they’re just squatting on that 7-bit address.  They hail 0x78 then read out 4 bytes, which the last two bytes are the supply voltage ADC readings.  They do their own byte swapping before scaling the value to get mV.

Solar Cluster: Gentoo Linux MUSL for ARMv5 finally built

It’s taken several months and had a few false starts, but at long last I have some stage tarballs for Gentoo Linux MUSL for ARMv5 processors.  I’m not the only one wanting such a port, even looking for my earlier thread on the matter, I stumbled on this post.  (Google translate is hopeless with Russian, but I can get the gist of what’s being said.)

This was natively built on the TS-7670 using an external hard drive connected over USB 2.0 as both swap and the chroot.  It took two passes to clean everything up and get something that’s in a “release-able” state.

I think my next steps now will be:

  • Build an updated kernel … I might see if I can expose that I²C register via a sysfs file or something that collectd can pick up whilst I’m at it.  I have the kernel sources and bootloader sources.
  • Prepare the 32GB MicroSD card I bought a few weeks back with the needed partitions and load Gentoo onto that.
  • Install the MicroSD card and boot off it.
  • Back up the eMMC
  • Re-format the eMMC and copy the MicroSD card to it.

It’s supposed to be wet this weekend, so it sounds like a good project for indoors.

Progress reporting in Gentoo

I have a bad habit where it comes to updating systems, I tend to do it less frequently than I should, and that can sometimes snowball like it has for my mail server.  Even if it’s a fresh install, sometimes there’s a large number of packages that need installing.

Now Portage does report where it’s up to, but often that has long scrolled past the buffer on your terminal.  You can look at /var/log/emerge.log for this information, but sometimes it’s nice to just see a percentage progress and a pseudo graphical representation.

With this in mind, I cooked up a little script which just tails /var/log/emerge.log and displays a progress bar along with the last message reported. The script is quite short:

#!/bin/bash

shopt -s checkwinsize

stdbuf -o L tail -n 0 -F /var/log/emerge.log | while read line; do
	changed=0
	eval $( echo ${line} | \
		sed -ne '/[0-9]\+ of [0-9]\+/ { s:^.*(\([0-9]\+\) of \([0-9]\+\)).*$:done=\1 total=\2 changed=1:; p; }' )

	if [ "${changed}" = 1 ]; then
		case "${line}" in
			*"::: completed emerge"*)
				;;
			*)
				done=$(( ${done} - 1 ))
				;;
		esac

		percent=$(( ( ${done}*100 ) / ${total} ))
		width=$(( ${COLUMNS:-80} - 8 ))
		progress=$(( ( ${done}*${width} ) / ${total} ))
		remain=$(( ${width} - ${progress} ))

		progressbar="$( for n in $( seq 1 ${progress} ); do echo -n '#'; done )"
		remainbar="$( for n in $( seq 1 ${remain} ); do echo -n ':'; done )"

		printf '\033[2A\033[2K%s\n\033[2K\033[1G[\033[1m%s\033[0m%s] \033[1m%3d%%\033[0m\n' \
			"${line:0:${COLUMNS:-80}}" "$progressbar" "$remainbar" "$percent"
	else
		printf '\033[2A\033[2K%s\n\n' "${line:0:${COLUMNS:-80}}"
	fi

	if echo "${line}" | grep -q '*** terminating.'; then
		exit
	fi
done

What’s it look like?

It works well with GNU Screen as seen above.

Solar Cluster: Measuring the battery voltage

So, I was just updating the project details for this project, and I happened to see this blog post about reading the DC voltage input on the TS-7670v2.

I haven’t yet gotten around to finishing the power meters that I was building which would otherwise be reading these values directly, but they were basically going to connect via Modbus to the TS-7670v2 anyway.  One of its roles, aside from routing between the physical management network (IPMI and switch console access), was to monitor the battery.

I will have to explore this.  Collectd doesn’t have a general-purpose I²C module, but it does have one for barometer modules, so with a bit of work, I could make one to measure the voltage input which would tell me what the battery is doing.