📝 23 Jun 2024
Last week we upstreamed Milk-V Duo S SBC (pic below) to Apache NuttX RTOS. (Based on Sophgo SG2000 RISC-V SoC)
But NuttX Mainline changes every day. Will Milk-V Duo S suffer “Software Bit Rot”? And fail to boot NuttX someday?
Let’s do Daily Automated Testing for NuttX on a Milk-V Duo S. Yep on the Actual Physical SBC! Our script shall…
Download the Daily Automated Build
(To our TFTP Server)
Power on our SBC with an IKEA Smart Power Plug
(Via the Home Assistant API)
Which will boot NuttX Mainline on our SBC
(Thanks to TFTP)
And upload the NuttX Test Log as GitHub Release Notes
Toughest Thing about our Daily Exercise: Automagically Powering Up our SBC.
We hike to our neighbourhood IKEA Store and buy…
(Which talks Zigbee, not WiFi)
(Which talks Ethernet, not WiFi!)
(To power up our SBC)
We add the Smart Power Plug to the IKEA Home Smart App. And we name it “SG2000 Power”…
But IKEA doesn’t provide a Public API for their gadgets!
Yeah our script can’t directly control the power plug sigh. That’s why we…
Add the IKEA Smart Power Plug to Google Assistant
(On our Android Phone)
Eventually we control the IKEA Smart Power Plug via the Google Assistant SDK
(Which sounds kinda tedious)
So instead we control Google Assistant SDK thru Home Assistant
(Just point and click yay!)
For macOS: We run Home Assistant in a Docker Container
How will Home Assistant control Google Assistant to control our Smart Power Plug?
Assume we’ve added the Smart Power Plug to Google Assistant. And named the Smart Power Plug as “SG2000 Power”.
We create an Automation in Home Assistant…
Inside our Automation: Add an Action…
Select the Google Assistant SDK. Enter the command: “SG2000 Power On”…
Save it as an Automation named “SG2000 Power On”…
But how do we Power On our SBC from our Automated Test Script?
We call the Home Assistant REST API with a Long-Lived Access Token, to trigger our Automation: test.sh
## Long-Lived Access Token from
## http://localhost:8123/profile/security
token=xxxx
## Power Off our SBC:
## Trigger the Automation "sg2000_power_off"
curl \
-X POST \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
-d '{"entity_id": "automation.sg2000_power_off"}' \
http://localhost:8123/api/services/automation/trigger
## Power On our SBC:
## Trigger the Automation "sg2000_power_on"
curl \
-X POST \
-H "Authorization: Bearer $token" \
-H "Content-Type: application/json" \
-d '{"entity_id": "automation.sg2000_power_on"}' \
http://localhost:8123/api/services/automation/trigger
Doesn’t the USB UART Adapter supply a tiny bit of power to our SBC?
Yeah enough power to light up the SBC, but not enough to power up the SBC totally.
Thus our SBC will glow red (errily) at night, even though the power is off. (I drape a hand towel so it won’t haunt my sleep)
(Or maybe we power up Another SBC to test Our SBC)
What will we boot and test on our SBC?
We’ll download the Daily Build of NuttX Mainline (for Milk-V Duo S): test.sh
## Build Prefix is "nuttx-sg2000"
## Build Date is today (YYYY-MM-DD)
BUILD_PREFIX=nuttx-sg2000
BUILD_DATE=$(date +'%Y-%m-%d')
## Download the NuttX Build for today
wget -q \
https://github.com/lupyuen/nuttx-sg2000/releases/download/$BUILD_PREFIX-$BUILD_DATE/nuttx.zip \
-O /tmp/nuttx.zip
pushd /tmp
unzip -o nuttx.zip
popd
## Copy the NuttX Image to our TFTP Server.
## Rename as `Image-sg2000`
scp /tmp/Image \
tftpserver:/tftpfolder/Image-sg2000
## Run the Automated Test.
## For Linux: Change `nuttx.exp` to `-c nuttx.exp`
script /tmp/test.log \
nuttx.exp
We’re using a TFTP Server?
Yep our SBC will boot the NuttX Image that’s copied to our TFTP Server.
Our SBC needs a MicroSD Card with U-Boot Bootloader. And some special U-Boot Commands for TFTP.
(That will run automatically thanks to saveenv
)
See the nuttx.exp from above? Let’s talk about the Automated Test Script…
What’s inside our Automated Test Script: nuttx.exp?
This is an Expect Tcl Script that will send NuttX Commands over the USB Serial Port to our SBC: nuttx.exp
#!/usr/bin/expect
## Expect Script for Testing NuttX over a USB Serial Port
## Wait at most 300 seconds
set timeout 300
## For every 1 character sent, wait 0.001 milliseconds
set send_slow {1 0.001}
## Connect to SBC over USB Serial Port at 115.2 kbps
spawn screen /dev/tty.usbserial-0001 115200
## Wake up the NSH Shell
send -s "\r"
## Wait for the NSH Prompt and enter `uname -a`
expect "nsh> "
send -s "uname -a\r"
## Wait for the NSH Prompt and enter `ostest`
expect "nsh> "
send -s "ostest\r"
## Check the `ostest` response
expect {
## If we see this message, exit normally
"ostest_main: Exiting with status 0" {
## Terminate the session: Ctrl-A k y
send "\x01ky"
puts "===== Test OK\n"
exit 0
}
## If timeout, exit with an error
timeout {
## Terminate the session: Ctrl-A k y
send "\x01ky"
puts "===== Error: Test Failed\n"
exit 1
}
}
OSTest will run a whole bunch of NuttX Tests, thoroughly exercising everything and vetting our physical proficiency.
OK but where’s the evidence of our Daily Test?
Every day, everything gets meticulously recorded into the GitHub Release Notes. Looking like this…
== Download the latest NuttX Build for 2024-06-21
+ wget -q https://github.com/lupyuen/nuttx-sg2000/releases/download/nuttx-sg2000-2024-06-21/nuttx.zip -O /tmp/nuttx.zip
== Commit Hash for NuttX Kernel and NuttX Apps
NuttX Kernel:
https://github.com/apache/nuttx/tree/769e65ef8e9e5600c172b8579775164c201e532a
NuttX Apps:
https://github.com/apache/nuttx-apps/tree/bc68d954ad01ab28f57fab167a3f0c08cead24cc
== Copy NuttX Image to TFTP Server
+ scp /tmp/Image tftpserver:/tftpboot/Image-sg2000
== Start NuttX Kernel
NuttShell (NSH) NuttX-12.5.1
nsh> uname -a
NuttX 12.5.1 769e65ef8e Jun 21 2024 00:13:08 risc-v milkv_duos
== Run NuttX OSTest
nsh> ostest
...
user_main: Exiting
ostest_main: Exiting with status 0
== Test OK
Whoa that’s plenty of logs. How did they get there?
We ran a script to Upload the Test Log into the GitHub Release Notes: upload.sh
## Upload the Test Log to the
## GitHub Release Notes.
## `release.tag` looks like `nuttx-sg2000-2024-06-21`
gh release edit \
`cat /tmp/release.tag` \
--notes-file /tmp/release2.log \
--repo lupyuen/nuttx-sg2000
We run all these scripts every day?
Actually we run the scripts every 10 minutes, waiting for the Latest Daily Build.
Which triggers our Smart Power Plug and Automated Test Script.
## Run the Daily Automated Test
script /tmp/release.log \
scripts/test.sh
## Upload the Test Log to GitHub Release Notes
scripts/upload.sh
## OR: Do this to run the Automated Test automatically whenever there's a Daily Build
scripts/task.sh
(See the Automated Test Scripts)
OK thanks but why not run the Daily Automated Test on a Software Emulator? (Instead of Real Hardware)
Oh yes we’re doing that too! Please join me in the next article on SG2000 Emulator.
Many Thanks to my GitHub Sponsors (and the awesome NuttX Community) for supporting my work! This article wouldn’t have been possible without your support.
Got a question, comment or suggestion? Create an Issue or submit a Pull Request here…