Skip to content

Commit ddb5b00

Browse files
authored
Merge pull request #376 from pennam/unor4-ota
Uno R4 WiFi OTA update
2 parents 2597cdb + 98e4201 commit ddb5b00

File tree

7 files changed

+213
-5
lines changed

7 files changed

+213
-5
lines changed

extras/tools/bin2ota.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
if len(sys.argv) != 4:
77
print ("Usage: bin2ota.py BOARD sketch.bin sketch.ota")
8-
print (" BOARD = [ MKR_WIFI_1010 | NANO_33_IOT | PORTENTA_H7_M7 | NANO_RP2040_CONNECT | NICLA_VISION | OPTA | GIGA | NANO_ESP32 ]")
8+
print (" BOARD = [ MKR_WIFI_1010 | NANO_33_IOT | PORTENTA_H7_M7 | NANO_RP2040_CONNECT | NICLA_VISION | OPTA | GIGA | NANO_ESP32 | ESP32 | UNOR4WIFI]")
99
sys.exit()
1010

1111
board = sys.argv[1]
@@ -37,6 +37,8 @@
3737
# Magic number for all ESP32 boards not related to (VID/PID)
3838
elif board == "ESP32":
3939
magic_number = 0x45535033.to_bytes(4,byteorder='little')
40+
elif board == "UNOR4WIFI":
41+
magic_number = 0x23411002.to_bytes(4,byteorder='little')
4042
else:
4143
print ("Error,", board, "is not a supported board type")
4244
sys.exit()

src/AIoTC_Config.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@
108108
#define OTA_STORAGE_PORTENTA_QSPI (0)
109109
#endif
110110

111-
#if defined(ARDUINO_ARCH_ESP32)
111+
#if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_UNOR4_WIFI)
112112
#define OTA_STORAGE_ESP (1)
113113
#endif
114114

src/tls/bearssl/dec32be.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
*/
2424

2525
#include <AIoTC_Config.h>
26-
#if defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_OFFLOADED_ECCX08) || defined(BOARD_HAS_SE050) || defined(ARDUINO_ARCH_ESP32)
26+
#if defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_OFFLOADED_ECCX08) || \
27+
defined(BOARD_HAS_SE050) || defined(ARDUINO_ARCH_ESP32) || \
28+
defined(ARDUINO_UNOR4_WIFI)
2729

2830
#include "inner.h"
2931

src/tls/bearssl/enc32be.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
*/
2424

2525
#include <AIoTC_Config.h>
26-
#if defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_OFFLOADED_ECCX08) || defined(BOARD_HAS_SE050) || defined(ARDUINO_ARCH_ESP32)
26+
#if defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_OFFLOADED_ECCX08) || \
27+
defined(BOARD_HAS_SE050) || defined(ARDUINO_ARCH_ESP32) || \
28+
defined(ARDUINO_UNOR4_WIFI)
2729

2830
#include "inner.h"
2931

src/tls/bearssl/sha2small.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
*/
2424

2525
#include <AIoTC_Config.h>
26-
#if defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_OFFLOADED_ECCX08) || defined(BOARD_HAS_SE050) || defined(ARDUINO_ARCH_ESP32)
26+
#if defined(BOARD_HAS_ECCX08) || defined(BOARD_HAS_OFFLOADED_ECCX08) || \
27+
defined(BOARD_HAS_SE050) || defined(ARDUINO_ARCH_ESP32) || \
28+
defined(ARDUINO_UNOR4_WIFI)
2729

2830
#include "inner.h"
2931

src/utility/ota/OTA-unor4.cpp

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
/*
2+
This file is part of ArduinoIoTCloud.
3+
4+
Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
5+
6+
This software is released under the GNU General Public License version 3,
7+
which covers the main part of arduino-cli.
8+
The terms of this license can be found at:
9+
https://www.gnu.org/licenses/gpl-3.0.en.html
10+
11+
You can be released from the requirements of the above licenses by purchasing
12+
a commercial license. Buying such a license is mandatory if you want to modify or
13+
otherwise use the software for commercial activities involving the Arduino
14+
software without disclosing the source code of your own applications. To purchase
15+
a commercial license, send an email to [email protected].
16+
*/
17+
18+
/******************************************************************************
19+
* INCLUDE
20+
******************************************************************************/
21+
22+
#include <AIoTC_Config.h>
23+
24+
#if defined ARDUINO_UNOR4_WIFI && OTA_ENABLED
25+
26+
#include "OTAUpdate.h"
27+
#include <Arduino_DebugUtils.h>
28+
#include "tls/utility/SHA256.h"
29+
#include "fsp_common_api.h"
30+
#include "r_flash_lp.h"
31+
#include "WiFiS3.h"
32+
33+
/******************************************************************************
34+
* DEFINES
35+
******************************************************************************/
36+
37+
/* Key code for writing PRCR register. */
38+
#define BSP_PRV_PRCR_KEY (0xA500U)
39+
#define BSP_PRV_PRCR_PRC1_UNLOCK ((BSP_PRV_PRCR_KEY) | 0x2U)
40+
#define BSP_PRV_PRCR_LOCK ((BSP_PRV_PRCR_KEY) | 0x0U)
41+
42+
#define OTA_MAGIC (*((volatile uint16_t *) &R_SYSTEM->VBTBKR[4]))
43+
#define OTA_SIZE (*((volatile uint32_t *) &R_SYSTEM->VBTBKR[6]))
44+
45+
/******************************************************************************
46+
* FUNCTION DEFINITION
47+
******************************************************************************/
48+
49+
static void unor4_setOTASize(uint32_t size)
50+
{
51+
R_SYSTEM->PRCR = (uint16_t) BSP_PRV_PRCR_PRC1_UNLOCK;
52+
OTA_MAGIC = 0x07AA;
53+
OTA_SIZE = size;
54+
R_SYSTEM->PRCR = (uint16_t) BSP_PRV_PRCR_LOCK;
55+
}
56+
57+
static uint32_t unor4_getOTASize()
58+
{
59+
if (OTA_MAGIC == 0x07AA)
60+
{
61+
return OTA_SIZE;
62+
}
63+
return 0;
64+
}
65+
66+
static int unor4_codeFlashOpen(flash_lp_instance_ctrl_t * ctrl)
67+
{
68+
flash_cfg_t cfg;
69+
70+
cfg.data_flash_bgo = false;
71+
cfg.p_callback = nullptr;
72+
cfg.p_context = nullptr;
73+
cfg.p_extend = nullptr;
74+
cfg.ipl = (BSP_IRQ_DISABLED);
75+
cfg.irq = FSP_INVALID_VECTOR;
76+
cfg.err_ipl = (BSP_IRQ_DISABLED);
77+
cfg.err_irq = FSP_INVALID_VECTOR;
78+
79+
fsp_err_t rv = FSP_ERR_UNSUPPORTED;
80+
81+
rv = R_FLASH_LP_Open(ctrl,&cfg);
82+
return rv;
83+
}
84+
85+
static int unor4_codeFlashClose(flash_lp_instance_ctrl_t * ctrl)
86+
{
87+
fsp_err_t rv = FSP_ERR_UNSUPPORTED;
88+
89+
rv = R_FLASH_LP_Close(ctrl);
90+
return rv;
91+
}
92+
93+
int unor4_onOTARequest(char const * ota_url)
94+
{
95+
OTAUpdate::Error ota_err = OTAUpdate::Error::None;
96+
OTAUpdate ota;
97+
98+
/* Initialize the board for OTA handling. */
99+
if ((ota_err = ota.begin("/update.bin")) != OTAUpdate::Error::None)
100+
{
101+
DEBUG_ERROR("OTAUpdate::begin() failed with %d", static_cast<int>(ota_err));
102+
return static_cast<int>(ota_err);
103+
}
104+
105+
/* Download the OTA file from the web storage location. */
106+
int const ota_download = ota.download(ota_url,"/update.bin");
107+
if (ota_download <= 0)
108+
{
109+
DEBUG_ERROR("OTAUpdate::download() failed with %d", ota_download);
110+
return ota_download;
111+
}
112+
DEBUG_VERBOSE("OTAUpdate::download() %d bytes downloaded", static_cast<int>(ota_download));
113+
114+
/* Verify update integrity */
115+
if ((ota_err = ota.verify()) != OTAUpdate::Error::None)
116+
{
117+
DEBUG_ERROR("OTAUpdate::verify() failed with %d", static_cast<int>(ota_err));
118+
return static_cast<int>(ota_err);
119+
}
120+
121+
/* Store update size and write OTA magin number */
122+
unor4_setOTASize(ota_download);
123+
124+
/* Flash new firmware */
125+
if ((ota_err = ota.update("/update.bin")) != OTAUpdate::Error::None)
126+
{
127+
DEBUG_ERROR("OTAUpdate::update() failed with %d", static_cast<int>(ota_err));
128+
return static_cast<int>(ota_err);
129+
}
130+
131+
return static_cast<int>(OTAUpdate::Error::None);
132+
}
133+
134+
String unor4_getOTAImageSHA256()
135+
{
136+
/* The length of the application can be retrieved the same way it was
137+
* communicated to the bootloader, that is by writing to the non-volatile
138+
* storage registers of the RTC.
139+
*/
140+
SHA256 sha256;
141+
uint32_t const app_start = 0x4000;
142+
uint32_t const app_size = unor4_getOTASize();
143+
144+
flash_lp_instance_ctrl_t ctrl;
145+
unor4_codeFlashOpen(&ctrl);
146+
147+
sha256.begin();
148+
uint32_t b = 0;
149+
uint32_t bytes_read = 0; for(uint32_t a = app_start;
150+
bytes_read < app_size;
151+
bytes_read += sizeof(b), a += sizeof(b))
152+
{
153+
/* Read the next chunk of memory. */
154+
memcpy(&b, reinterpret_cast<const void *>(a), sizeof(b));
155+
/* Feed it to SHA256. */
156+
sha256.update(reinterpret_cast<uint8_t *>(&b), sizeof(b));
157+
}
158+
159+
unor4_codeFlashClose(&ctrl);
160+
161+
/* Retrieve the final hash string. */
162+
uint8_t sha256_hash[SHA256::HASH_SIZE] = {0};
163+
sha256.finalize(sha256_hash);
164+
String sha256_str;
165+
std::for_each(sha256_hash,
166+
sha256_hash + SHA256::HASH_SIZE,
167+
[&sha256_str](uint8_t const elem)
168+
{
169+
char buf[4];
170+
snprintf(buf, 4, "%02X", elem);
171+
sha256_str += buf;
172+
});
173+
DEBUG_ERROR("SHA256: %d bytes (of %d) read", bytes_read, app_size);
174+
return sha256_str;
175+
}
176+
177+
bool unor4_isOTACapable()
178+
{
179+
/* check firmware version */
180+
String const fv = WiFi.firmwareVersion();
181+
if (fv < String("0.3.0")) {
182+
return false;
183+
}
184+
return true;
185+
}
186+
187+
#endif /* ARDUINO_UNOR4_WIFI */

src/utility/ota/OTA.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ String esp32_getOTAImageSHA256();
5555
bool esp32_isOTACapable();
5656
#endif
5757

58+
#ifdef ARDUINO_UNOR4_WIFI
59+
int unor4_onOTARequest(char const * url);
60+
String unor4_getOTAImageSHA256();
61+
bool unor4_isOTACapable();
62+
#endif
63+
5864
/******************************************************************************
5965
* PUBLIC MEMBER FUNCTIONS
6066
******************************************************************************/
@@ -74,6 +80,9 @@ int OTA::onRequest(String url, NetworkAdapter iface)
7480
#elif defined (ARDUINO_ARCH_ESP32)
7581
(void)iface;
7682
return esp32_onOTARequest(url.c_str());
83+
#elif defined (ARDUINO_UNOR4_WIFI)
84+
(void)iface;
85+
return unor4_onOTARequest(url.c_str());
7786
#else
7887
#error "OTA not supported for this architecture"
7988
#endif
@@ -89,6 +98,8 @@ String OTA::getImageSHA256()
8998
return portenta_h7_getOTAImageSHA256();
9099
#elif defined (ARDUINO_ARCH_ESP32)
91100
return esp32_getOTAImageSHA256();
101+
#elif defined (ARDUINO_UNOR4_WIFI)
102+
return unor4_getOTAImageSHA256();
92103
#else
93104
#error "No method for SHA256 checksum calculation over application image defined for this architecture."
94105
#endif
@@ -104,6 +115,8 @@ bool OTA::isCapable()
104115
return portenta_h7_isOTACapable();
105116
#elif defined (ARDUINO_ARCH_ESP32)
106117
return esp32_isOTACapable();
118+
#elif defined (ARDUINO_UNOR4_WIFI)
119+
return unor4_isOTACapable();
107120
#else
108121
#error "OTA not supported for this architecture"
109122
#endif

0 commit comments

Comments
 (0)