A dairy runs on a Data Processing Unit that weighs milk, reads fat and SNF, computes a rate and pays the farmer. The firmware is encrypted, the vendor is gone, and nobody can say what the device actually calculates — which matters, because the number it prints is somebody's income. The operator owns the units and commissioned this work on their own hardware.
What I did about it
Decrypted the 117,936-byte image and walked the ARM Cortex-M vector table from the reset handler, recovering 2,116 ASCII strings to map the menu tree and the operator-facing screens.
Identified the display as a 3-chip JHD12864E on a KS0108/NT7108 controller — and proved it was **not** an ST7920, which several earlier attempts had assumed — then mapped all 20 pins to MCU ports, finding DB0–DB7 wired sequentially to PC0–PC7, which makes bit operations cheap.
Reconstructed the three pricing modes the firmware supports: FAT-SNF, FAT-only, and FAT-CLR where SNF is derived first as SNF = (CLR/4) + (Fat × 0.2) + 0.7, cross-checked against the device's own cow and buffalo rate charts.
Wrote the findings up as seven documents — including FAILED_APPROACHES.md, which records the dead ends, because on this kind of work the failed hypotheses are most of the value to whoever picks it up next.
What I rejected, and why
Cleanroom-rewriting the unit's software from a specification would have been safer legally and cleaner technically. It was not possible: there is no specification, and the rate charts baked into the firmware are the only remaining record of what farmers have actually been paid. Recovering the existing behaviour first is the only way to know whether a replacement would change anyone's income.
The work was authorised by the operator on hardware they own, which is the right footing — but I documented the scope only in the commit history rather than in a signed statement of work. On anything touching a third party's firmware I would put the authorisation in writing before the first byte is read, not after.