Skip to content

Commit fa824f7

Browse files
committed
Started working on SerialOTA implementation
1 parent fe3ba3a commit fa824f7

File tree

6 files changed

+192
-7
lines changed

6 files changed

+192
-7
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ mbed_config.h
1313
*.hex
1414
*.pem
1515
signing_keys.c
16-
mbed-os/*
16+
mbed-os/*
17+
mcuboot/*

SerialOTA.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* SerialOTA.cpp
3+
*
4+
* Created on: Jul 31, 2020
5+
* Author: gdbeckstein
6+
*/
7+
8+
#include "SerialOTA.h"
9+
#include "drivers/MbedCRC.h"
10+
11+
#define OTA_DONE_SEQ_NUM 0xFFFF
12+
13+
SerialOTA::SerialOTA(mbed::FileHandle& serial, mbed::BlockDevice& update_bd) : _serial(serial),
14+
_update_bd(update_bd), _current_seq(0) {
15+
}
16+
17+
SerialOTA::ota_error_t SerialOTA::begin(void) {
18+
19+
mbed::MbedCRC<POLY_16BIT_CCITT, 16> ct;
20+
uint32_t bytes_collected = 0;
21+
packet_header_t header = { 0 };
22+
uint32_t crc;
23+
24+
// Initialize the secondary block device
25+
_update_bd.init();
26+
27+
// Erase the entire secondary block device
28+
_update_bd.erase(0x0, _update_bd.size());
29+
30+
_serial.set_blocking(true);
31+
32+
// Tell the serial bootloader host application to begin :)
33+
_serial.write("GO", 2);
34+
35+
while(true) {
36+
37+
// Read a packet from the FileHandle
38+
_serial.read(_payload_buffer, OTA_PAYLOAD_BUFFER_SIZE);
39+
40+
// The first bytes will be the header
41+
memcpy(&header, _payload_buffer, sizeof(packet_header_t));
42+
43+
// If the sequence number is OTA_DONE_SEQ_NUM we're done!
44+
if(header.sequence_num == OTA_DONE_SEQ_NUM) {
45+
return OTA_SUCCESS;
46+
}
47+
48+
// Check the sequence number
49+
if(_current_seq != header.sequence_num) {
50+
return OTA_OUT_OF_SYNC;
51+
}
52+
53+
// Check the make sure the update_bd can fit the bytes
54+
if((bytes_collected + header.payload_size) > _update_bd.size()) {
55+
return OTA_OUT_OF_SPACE;
56+
}
57+
58+
// Check the CRC16 to make sure the data is not corrupt
59+
ct.compute(&_payload_buffer[2],
60+
(header.payload_size+sizeof(packet_header_t)-sizeof(uint16_t)),
61+
&crc);
62+
63+
if(crc != header.crc16) {
64+
return OTA_CRC_ERROR;
65+
}
66+
67+
// Everything checks out, proceed to writing the bytes to the update_bd
68+
_update_bd.program(&_payload_buffer[sizeof(packet_header_t)],
69+
bytes_collected,
70+
header.payload_size);
71+
72+
// Update sequence number and bytes_collected
73+
_current_seq++;
74+
bytes_collected += header.payload_size;
75+
76+
}
77+
}

SerialOTA.h

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,58 @@
88
#ifndef SERIALOTA_H_
99
#define SERIALOTA_H_
1010

11-
#include "Stream.h"
11+
#include "platform/FileHandle.h"
12+
#include "BlockDevice.h"
13+
14+
#define OTA_PAYLOAD_BUFFER_SIZE 384
1215

1316
class SerialOTA
1417
{
18+
19+
public:
20+
21+
typedef struct {
22+
uint16_t crc16; /** CRC16 of entire packet */
23+
uint16_t sequence_num; /** Sequence number of the OTA update, the special value 0xFFFF means the transfer is over. Wraps at 0xFFFE */
24+
uint16_t payload_size; /** Payload size of this packet in bytes */
25+
} packet_header_t;
26+
27+
typedef enum {
28+
OTA_SUCCESS = 0x0, /** success */
29+
OTA_OUT_OF_SPACE = 0x1, /** update_bd has run out of space for the update */
30+
OTA_CRC_ERROR = 0x2, /** CRC error on last packet */
31+
OTA_OUT_OF_SYNC = 0x3, /** Sequence number received out of sync */
32+
} ota_error_t;
33+
1534
public:
1635

17-
SerialOTA();
36+
/**
37+
* Instantiate a SerialOTA interface
38+
*
39+
* @param[in] serial Serial FileHandle reference to use
40+
* @param[in] update_bd BlockDevice to store the update in
41+
*/
42+
SerialOTA(mbed::FileHandle& serial, mbed::BlockDevice& update_bd);
43+
44+
/**
45+
* Begins the SerialOTA update process
46+
*
47+
* This is a blocking function call and will only
48+
* exit upon error or completion
49+
*
50+
* @retval error
51+
*/
52+
ota_error_t begin(void);
53+
54+
protected:
55+
56+
mbed::FileHandle& _serial;
57+
58+
mbed::BlockDevice& _update_bd;
59+
60+
uint16_t _current_seq;
61+
62+
uint8_t _payload_buffer[OTA_PAYLOAD_BUFFER_SIZE];
1863

1964
};
2065

mbed_app.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"requires": ["bare-metal", "mbedtls", "mcuboot", "flashiap-block-device", "spif-driver", "qspif", "mbed-trace"],
2+
"requires": ["bare-metal", "mbedtls", "mcuboot", "flashiap-block-device", "spif-driver", "qspif", "mbed-trace", "serialcobs"],
33
"target_overrides": {
44
"*": {
55
"target.restrict_size": "0x20000",

tinycbor.lib

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
https://github.com/EmbeddedPlanet/tinycbor/#c49bb8f5f158c9f37b7cef5bb9eb7ee0a9eb6707
1+
https://github.com/EmbeddedPlanet/tinycbor/#6f4953e3c00afe6cb1677b9dd28bd0c4ad43b6ab

user_main.cpp

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,91 @@
55
* Author: gdbeckstein
66
*/
77

8-
#include "BlockDevice.h"
8+
#include "PinNames.h"
99

1010
/** Enable serial bootloader feature by default */
1111
#ifndef MBED_CONF_APP_SERIAL_BOOTLOADER_ENABLE
1212
#define MBED_CONF_APP_SERIAL_BOOTLOADER_ENABLE 1
1313
#endif
1414

15+
#ifndef MBED_CONF_APP_SERIAL_BOOTLOADER_BAUD
16+
#define MBED_CONF_APP_SERIAL_BOOTLOADER_BAUD 115200
17+
#endif
18+
1519
#if MBED_CONF_APP_SERIAL_BOOTLOADER_ENABLE
1620

21+
#include "secondary_bd.h"
22+
23+
#include "SerialOTA.h"
24+
1725
#include "rtos/ThisThread.h"
26+
#include "rtos/Kernel.h"
1827
#include <chrono>
1928

29+
#include "drivers/BufferedSerial.h"
30+
#include "drivers/DigitalIn.h"
31+
#include "SerialCOBS.h"
32+
2033
#define BOOT_WAIT_TIMEOUT 5s
2134

2235
using namespace std::chrono;
2336

37+
mbed::DigitalIn button(BUTTON1);
38+
39+
// TODO - add led status indicator?
40+
2441
#endif // MBED_CONF_APP_SERIAL_BOOTLOADER_ENABLE
2542

2643
void mbed_mcuboot_user_init(void) {
2744

2845
#if MBED_CONF_APP_SERIAL_BOOTLOADER_ENABLE
2946

30-
// Set up the serial bootloader
47+
// If the button is held down upon bootup, start the serial bootloader
48+
if(button) {
49+
return;
50+
}
51+
52+
// Set up the serial interface
53+
mbed::BufferedSerial pc(STDIO_UART_TX, STDIO_UART_RX, MBED_CONF_APP_SERIAL_BOOTLOADER_BAUD);
54+
55+
// Wait for a specified timeout until just booting
56+
rtos::Kernel::Clock::duration time_waited = 0ms;
57+
bool timed_out = true;
58+
uint8_t c = 1;
59+
while(time_waited < BOOT_WAIT_TIMEOUT) {
60+
// The serial bootloader should send 0-bytes until we respond we're ready, look for that
61+
if(pc.readable()) {
62+
if(pc.read(&c, 1)) {
63+
if(c == 0) {
64+
timed_out = false;
65+
break;
66+
}
67+
}
68+
}
69+
70+
// Otherwise, keep waiting
71+
rtos::ThisThread::sleep_for(100ms);
72+
time_waited += 100ms;
73+
}
74+
75+
// Serial bootloader timed out, boot the main application
76+
if(timed_out) {
77+
return;
78+
}
79+
80+
// Serial bootloader connected, send an acknowledgement
81+
c = 1;
82+
pc.write(&c, 1);
83+
84+
// Wrap it with COBS-R encoding (0-byte delimeters)
85+
SerialCOBS serial_cobs(pc);
86+
87+
// Create the SerialOTA object and let it do its thing
88+
SerialOTA ota(serial_cobs, *get_secondary_bd());
89+
90+
SerialOTA::ota_error_t error = ota.begin();
91+
92+
// TODO - check error?
3193

3294
#endif // MBED_CONF_APP_SERIAL_BOOTLOADER_ENABLE
3395

0 commit comments

Comments
 (0)