|
| 1 | +// Copyright 2026 Blues Inc. All rights reserved. |
| 2 | +// |
| 3 | +// Use of this source code is governed by licenses granted by the |
| 4 | +// copyright holder including that found in the LICENSE file. |
| 5 | +// |
| 6 | +// This example demonstrates Notecard Outboard Firmware Update, which lets you |
| 7 | +// update this host MCU's firmware over-the-air from Notehub, with no host code |
| 8 | +// required to perform the download. The Notecard receives the new firmware |
| 9 | +// image and reprograms the host over the DFU signals on a Notecarrier F. |
| 10 | +// |
| 11 | +// The sketch does two things: |
| 12 | +// |
| 13 | +// 1. In setup(), it configures the Notecard to enable Outboard Firmware |
| 14 | +// Update (see the `card.dfu`, `card.aux` and `dfu.status` requests below). |
| 15 | +// 2. In loop(), it blinks the built-in LED with a recognizable pattern and |
| 16 | +// reports a firmware version. This is the "payload" you will update: build |
| 17 | +// and upload a new version of this sketch to Notehub, apply it to the |
| 18 | +// host, and watch the blink pattern (and reported version) change. |
| 19 | +// |
| 20 | +// This example targets STM32-based Blues hosts on a Notecarrier F, such as the |
| 21 | +// Swan and Cygnet Feathers and the STM32F405 Feather. See DFU_MCU_TYPE below |
| 22 | +// for hosts (like the SparkFun MicroMod STM32) whose boot pin is inverted. |
| 23 | +// |
| 24 | +// For the full walkthrough, see: |
| 25 | +// https://dev.blues.io/notehub/host-firmware-updates/notecard-outboard-firmware-update/ |
| 26 | + |
| 27 | +// Include the Arduino library for the Notecard |
| 28 | +#include <Notecard.h> |
| 29 | + |
| 30 | +// If the Notecard is connected to a serial port, define it here. For example, |
| 31 | +// if you are using the Adafruit Feather NRF52840 Express, the RX/TX pins (and |
| 32 | +// thus the Notecard) are on Serial1. However, if you are using an M5Stack Basic |
| 33 | +// Core IoT Development Kit, you would connect the R2 pin to the Notecard's TX |
| 34 | +// pin, and the M5Stack's T2 pin to the Notecard's RX pin, and then would use |
| 35 | +// Serial2. |
| 36 | +// |
| 37 | +// Also, you may define a debug output port where you can watch transactions as |
| 38 | +// they are sent to and from the Notecard. When using the Arduino IDE this is |
| 39 | +// typically "Serial", but you can use any available port. |
| 40 | +// |
| 41 | +// Note that both of these definitions are optional; just prefix either line |
| 42 | +// with `//` to remove it. |
| 43 | +// |
| 44 | +// - Remove `txRxPinsSerial` if you wired your Notecard using I2C SDA/SCL pins, |
| 45 | +// instead of serial RX/TX. |
| 46 | +// - Remove `usbSerial` if you don't want the Notecard library to output debug |
| 47 | +// information. |
| 48 | + |
| 49 | +// #define txRxPinsSerial Serial1 |
| 50 | +#define usbSerial Serial |
| 51 | + |
| 52 | +// This is the unique Product Identifier for your device |
| 53 | +#ifndef PRODUCT_UID |
| 54 | +#define PRODUCT_UID "" // "com.my-company.my-name:my-project" |
| 55 | +#pragma message "PRODUCT_UID is not defined in this example. Please ensure your Notecard has a product identifier set before running this example or define it in code here. More details at https://dev.blues.io/tools-and-sdks/samples/product-uid" |
| 56 | +#endif |
| 57 | + |
| 58 | +#define myProductID PRODUCT_UID |
| 59 | + |
| 60 | +// The host MCU type reported to the Notecard via `card.dfu`. Use "stm32" for |
| 61 | +// most STM32 hosts (Swan, Cygnet, STM32F405 Feather). Use "stm32-bi" for hosts |
| 62 | +// whose boot pin is active LOW / inverted, such as the SparkFun MicroMod STM32. |
| 63 | +#ifndef DFU_MCU_TYPE |
| 64 | +#define DFU_MCU_TYPE "stm32" |
| 65 | +#endif |
| 66 | + |
| 67 | +// The firmware version reported to Notehub via `dfu.status`. Bump this (and |
| 68 | +// change the blink pattern below) when you build a new image to update to. |
| 69 | +#define FIRMWARE_VERSION "1.0.0" |
| 70 | + |
| 71 | +Notecard notecard; |
| 72 | + |
| 73 | +// One-time Arduino initialization |
| 74 | +void setup() |
| 75 | +{ |
| 76 | + // Set up the built-in LED so loop() can show a recognizable running pattern. |
| 77 | + pinMode(LED_BUILTIN, OUTPUT); |
| 78 | + |
| 79 | + // Set up for debug output (if available). |
| 80 | +#ifdef usbSerial |
| 81 | + // If you open Arduino's serial terminal window, you'll be able to watch |
| 82 | + // JSON objects being transferred to and from the Notecard for each request. |
| 83 | + usbSerial.begin(115200); |
| 84 | + const size_t usb_timeout_ms = 3000; |
| 85 | + for (const size_t start_ms = millis(); !usbSerial && (millis() - start_ms) < usb_timeout_ms;) |
| 86 | + ; |
| 87 | + |
| 88 | + // For low-memory platforms, don't turn on internal Notecard logs. |
| 89 | +#ifndef NOTE_C_LOW_MEM |
| 90 | + notecard.setDebugOutputStream(usbSerial); |
| 91 | +#else |
| 92 | +#pragma message("INFO: Notecard debug logs disabled. (non-fatal)") |
| 93 | +#endif // !NOTE_C_LOW_MEM |
| 94 | +#endif // usbSerial |
| 95 | + |
| 96 | + // Initialize the physical I/O channel to the Notecard |
| 97 | +#ifdef txRxPinsSerial |
| 98 | + notecard.begin(txRxPinsSerial, 9600); |
| 99 | +#else |
| 100 | + notecard.begin(); |
| 101 | +#endif |
| 102 | + |
| 103 | + // Put the Notecard in continuous mode so it maintains a live session with |
| 104 | + // Notehub. Outboard Firmware Update requires the Notecard to be in |
| 105 | + // "continuous" or "periodic" mode. `sendRequestWithRetry()` is important on |
| 106 | + // the first message after a cold boot, to handle the hardware race |
| 107 | + // condition while the Notecard becomes ready. |
| 108 | + J *req = notecard.newRequest("hub.set"); |
| 109 | + if (myProductID[0]) |
| 110 | + { |
| 111 | + JAddStringToObject(req, "product", myProductID); |
| 112 | + } |
| 113 | + JAddStringToObject(req, "mode", "continuous"); |
| 114 | + notecard.sendRequestWithRetry(req, 5); // 5 seconds |
| 115 | + |
| 116 | + // Enable Outboard Firmware Update for this host and tell the Notecard which |
| 117 | + // MCU type it is driving. On a Notecarrier F the DFU signals are routed over |
| 118 | + // the Notecard's shared AUX pins, so we set `mode` to "aux" here. |
| 119 | + req = notecard.newRequest("card.dfu"); |
| 120 | + JAddStringToObject(req, "name", DFU_MCU_TYPE); |
| 121 | + JAddBoolToObject(req, "on", true); |
| 122 | + JAddStringToObject(req, "mode", "aux"); |
| 123 | + notecard.sendRequest(req); |
| 124 | + |
| 125 | + // Free the AUX pins so they can be used for Outboard Firmware Update. |
| 126 | + req = notecard.newRequest("card.aux"); |
| 127 | + JAddStringToObject(req, "mode", "off"); |
| 128 | + notecard.sendRequest(req); |
| 129 | + |
| 130 | + // Enable host DFU and report the running firmware version to Notehub. |
| 131 | + req = notecard.newRequest("dfu.status"); |
| 132 | + JAddBoolToObject(req, "on", true); |
| 133 | + JAddStringToObject(req, "version", FIRMWARE_VERSION); |
| 134 | + notecard.sendRequest(req); |
| 135 | +} |
| 136 | + |
| 137 | +// In the Arduino main loop, blink the built-in LED with a recognizable pattern. |
| 138 | +// After an Outboard Firmware Update, change this pattern (and bump |
| 139 | +// FIRMWARE_VERSION above) so you can visually confirm the update was applied. |
| 140 | +void loop() |
| 141 | +{ |
| 142 | + digitalWrite(LED_BUILTIN, HIGH); |
| 143 | + delay(500); |
| 144 | + digitalWrite(LED_BUILTIN, LOW); |
| 145 | + delay(500); |
| 146 | +} |
0 commit comments