Continuous Integration of Firmware¶
Note
The AWS implementation of Bifravst provides resources to continuously test the firmware using real hardware.
Overview¶
Every commit to the firmware repo will trigger a CI run. The CI run will
create a new device and credentials on AWS IoT
build a firmware that has the device ID hardcoded for the MQTT client ID
create an AWS IoT job with the firmware and the credentials, which is picked up by a the Firmware CI runner (see below)
observe the firmware CI run until it finishes
download the log result from S3
run assertions against the log result
The Firmware CI runner is running on a Raspberry Pi connected to AWS IoT where it receives jobs to execute:
it flashes the firmware and optional credentials using the connected debugger to the connected nRF9160 DK or Thingy:91
it then collects all log output until a. a timeout is reached b. or a stop condition is reached (wait for a log output to match a string)
it uploads the logs to S3
Note
These devices connect to the existing instance of Bifravst, so the firmware tests will not set up a new blank Bifravst AWS environment for every test, but be run against the production environment. This is to ensure that firmware release will work against the existing, working solution. This approach is designed for trunk-based development.
Preparation¶
Enable the Firmware CI resources of Bifravst that allow GitHub Actions to create test devices, and the the Firmware CI runner to connect by enabling the context switch firmware-ci
when deploying the stack (see Getting Started).
echo "firmware-ci=1" >> context.cfg
npx cdk deploy '*'
Print the AWS Key for the CI runner on GitHub Actions using this command:
node cli firmware-ci -s
Region: "<Region>"
Bucket name: "<Bucket name>"
Access Key ID: "<AWS Access Key ID>"
Secret Access Key: "<AWS Secret Access Key>"
Now you can create a new IoT Thing to be used for a Firmware CI runner (see below):
node cli firmware-ci -c
You can delete a device using this command:
node cli firmware-ci -r "<deviceId>"
Configure these as secrets on the firmware GitHub repository:
AWS_ACCESS_KEY_ID
(as printed above)
AWS_SECRET_ACCESS_KEY
(as printed above)
AWS_REGION
(as printed above)
STACK_NAME
(the stack name of your production environment, usuallybifravst
)
DEVICE_ID
(the created Firmwer CI runner device, e.g.firmware-ci-3c431c57-e524-4010-b269-371cb53538b6
)
Firmware CI runner setup¶
Download JLink for your platform. Use the path to the folder (e.g.
~/JLink_Linux_V686_arm64/
) further down.Install firmware-ci-runner-aws:
git clone https://github.com/bifravst/firmware-ci-runner-aws.git cd firmware-ci-runner-aws npm ci npx tsc
Now provide these environment variables:
export AWS_ACCESS_KEY_ID="<AWS Access Key ID printed above>" export AWS_SECRET_ACCESS_KEY="<AWS Secret Access Key printed above>" export REGION="<Region printed above>" export BUCKET_NAME="<Bucket name printed above>" export PATH="<Path to JLINK>":$PATH
The recommended workflow is to use a direnv plugin for your shell which will automatically export the environment variables it finds in a
.envrc
file in the project folder: Create a new file.envrc
in the project folder and add the credentials that are presented to you after you have created the new user.Copy over the JSON file containing the certificate
Run:
node cli run "<device>" "<path to certificate.json>"
<device>
is the Linux file where the device is connected to, e.g./dev/ttyACM0
.
The Firmware CI will now process all schedule jobs one after another.