QNAP NAS model TS-453 Pro has limited documentation on how to control its various peripherals, namely:
- the front LCD display, a 2 row, 16 column blue & white LCD display, and its two menu buttons ("ENTER", "SELECT")
- the front LEDs "STATUS" (red & green) & "USB" (blue)
- the 4 "disk error" LEDs (red)
- the front "USB COPY" button
- the main rear fan
I've spent some time toying with the stock firmware to figure that out.
Just FYI, to act of these peripherals (and a lot of other stuff such as flashing the firmware), the stock firmware uses a combination of a 1.3 MB shared library libuLinux_hal.so, a 364 KB hal_daemon service and a 176 KB hal_app command-line tool, plus some other libraries for parsing the specific INI-stored "HAL config" for each device model. For example, to produce a beep:
$ hal_app --se_buzzer enc_id=0,mode=1sends a message to hal_daemon which eventually writes to the relevant low-level I/O port through libuLinux_hal.
This can be controlled using standard hwmon tooling on Linux. Install lm-sensors/fancontrol. A sensible /etc/fancontrol is presented below:
INTERVAL=10
DEVPATH=hwmon1=devices/platform/coretemp.0 hwmon2=devices/platform/f71882fg.656
DEVNAME=hwmon1=coretemp hwmon2=f71869a
FCTEMPS=hwmon2/device/pwm1=hwmon1/temp2_input
FCFANS= hwmon2/device/pwm1=hwmon2/device/fan1_input
MINTEMP=hwmon2/device/pwm1=30
MAXTEMP=hwmon2/device/pwm1=65
MINSTART=hwmon2/device/pwm1=150
MINSTOP=hwmon2/device/pwm1=0
This is a well-documented A125 board. There are multiple scripts and programs on the web to read the buttons and control the LCD display. See eg. the implementation for qcontrol: a125.c.
The tl;dr is:
- serial port
/dev/ttyS1, baudrate 1200 (yes; that's 2 updates per second at best) - write
0x4D, 0x5E, 0x00to switch the backlight off, write0x4D, 0x5E, 0x01to switch the backlight on - write
0x4D, 0x0C, 0x00, 0x20, {16 chars}to write to the first line, write0x4D, 0x0C, 0x01, 0x20, {16 chars}to write to the second line (pad with spaces to clear the previous characters) - for each button press and release, the read buffer will receive 4 characters of the form
0x53, 0x05, 0x00, {BM}where{BM}is a bitmask of0x01→ ENTER (UP) and0x02→ SELECT (DOWN). Possible values are thus0x00,0x01,0x02,0x03. Pressing ENTER then pressing SELECT then releasing ENTER then releasing SELECT will send four 4-byte messages ending with0x01 → 0x03 → 0x02 → 0x00.
This is the funny, otherwise undocumented part.
The stock firmware contains model-specific config files, eg. model_QW370_QW550_16_10.conf, that describes on what low-level I/O ports should one read and write. Reproduced below are the interesting parts:
[System Enclosure]
VENDOR = QNAP
MODEL = TS-453 Pro
SIO_DEVICE = F71869A # The motherboard model.
# …
[System IO]
RESET_BUTTON = SIO:I92:B1
STATUS_GREEN_LED = SIO:I91:B2
STATUS_RED_LED = SIO:I91:B3
USB_COPY_BUTTON = SIO:IE2:B2
FRONT_USB_LED = SIO:IE1:B7
# …
[System Disk 1]
DEV_BUS = B00:D28:F0
DEV_PORT = 1
ERR_LED = SIO:I81:B0
# …
What I couldn't find in this file is the base port number. strace-ing the stock binary, I discovered it's 0xA05 (2565).
| Port | Purpose |
|---|---|
0xA05 |
Control "register" XX (:I{XX}) |
0xA06 |
Register value, using negative bitmask offset X (:B{X}) |
To change a LED state, write its control register to 0xA05 and the relevant bitmask to 0xA06.
For instance, to change STATUS_GREEN_LED = SIO:I91:B2:
- write to
0xA05:0x91(:I91) - write to
0xA06:0xFF ^ 0b100, as GREEN is 2nd bit (:B2)
To read a button status, write the control register to 0xA05, read 0xA06 and mask it to get the relevant bit. For instance, to poll for COPY button status USB_COPY_BUTTON = SIO:IE2:B2:
- write to
0xA05:0xE2(:IE2) - read
0xA06and get its 2nd bit (:B2)
There is a sample C program below to demo this feature.
Great work! Any hints as to how to control the buzzer?