1+ /*
2+ This file is part of the ArduinoIoTCloud library.
3+
4+ Copyright (c) 2024 Arduino SA
5+
6+ This Source Code Form is subject to the terms of the Mozilla Public
7+ License, v. 2.0. If a copy of the MPL was not distributed with this
8+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+ */
10+
11+ #include " AIoTC_Config.h"
12+ #if defined(BOARD_STM32H7) && OTA_ENABLED
13+ #include " OTASTM32H7.h"
14+
15+ #include " utility/watchdog/Watchdog.h"
16+ #include < STM32H747_System.h>
17+
18+ static bool findProgramLength (DIR * dir, uint32_t & program_length);
19+
20+ const char STM32H7OTACloudProcess::UPDATE_FILE_NAME[] = " /fs/UPDATE.BIN" ;
21+
22+ STM32H7OTACloudProcess::STM32H7OTACloudProcess (MessageStream *ms, Client* client)
23+ : OTADefaultCloudProcessInterface(ms, client)
24+ , decompressed(nullptr )
25+ , _bd_raw_qspi(nullptr )
26+ , _program_length(0 )
27+ , _bd(nullptr )
28+ , _fs(nullptr ) {
29+
30+ }
31+
32+ STM32H7OTACloudProcess::~STM32H7OTACloudProcess () {
33+ if (decompressed != nullptr ) {
34+ fclose (decompressed);
35+ decompressed = nullptr ;
36+ }
37+
38+ storageClean ();
39+ }
40+
41+ OTACloudProcessInterface::State STM32H7OTACloudProcess::resume (Message* msg) {
42+ return OtaBegin;
43+ }
44+
45+ void STM32H7OTACloudProcess::update () {
46+ OTADefaultCloudProcessInterface::update ();
47+ watchdog_reset (); // FIXME this should npot be performed here
48+ }
49+
50+ int STM32H7OTACloudProcess::writeFlash (uint8_t * const buffer, size_t len) {
51+ if (decompressed == nullptr ) {
52+ return -1 ;
53+ }
54+ return fwrite (buffer, sizeof (uint8_t ), len, decompressed);
55+ }
56+
57+ OTACloudProcessInterface::State STM32H7OTACloudProcess::startOTA () {
58+ if (!isOtaCapable ()) {
59+ return NoCapableBootloaderFail;
60+ }
61+
62+ /* Initialize the QSPI memory for OTA handling. */
63+ if (!storageInit ()) {
64+ return OtaStorageInitFail;
65+ }
66+
67+ // this could be useless, since we are writing over it
68+ remove (UPDATE_FILE_NAME);
69+
70+ decompressed = fopen (UPDATE_FILE_NAME, " wb" );
71+
72+ // start the download if the setup for ota storage is successful
73+ return OTADefaultCloudProcessInterface::startOTA ();
74+ }
75+
76+
77+ OTACloudProcessInterface::State STM32H7OTACloudProcess::flashOTA () {
78+ fclose (decompressed);
79+ decompressed = nullptr ;
80+
81+ /* Schedule the firmware update. */
82+ if (!storageOpen ()) {
83+ return OtaStorageOpenFail;
84+ }
85+
86+ // this sets the registries in RTC to load the firmware from the storage selected at the next reboot
87+ STM32H747::writeBackupRegister (RTCBackup::DR0, 0x07AA );
88+ STM32H747::writeBackupRegister (RTCBackup::DR1, storage);
89+ STM32H747::writeBackupRegister (RTCBackup::DR2, data_offset);
90+ STM32H747::writeBackupRegister (RTCBackup::DR3, _program_length);
91+
92+ return Reboot;
93+ }
94+
95+ OTACloudProcessInterface::State STM32H7OTACloudProcess::reboot () {
96+ // TODO save information about the progress reached in the ota
97+
98+ // This command reboots the mcu
99+ NVIC_SystemReset ();
100+
101+ return Resume; // This won't ever be reached
102+ }
103+
104+ void STM32H7OTACloudProcess::reset () {
105+ OTADefaultCloudProcessInterface::reset ();
106+
107+ remove (UPDATE_FILE_NAME);
108+
109+ storageClean ();
110+ }
111+
112+ void STM32H7OTACloudProcess::storageClean () {
113+ DEBUG_VERBOSE (F (" storage clean" ));
114+
115+ if (decompressed != nullptr ) {
116+ fclose (decompressed);
117+ decompressed = nullptr ;
118+ }
119+
120+ if (_fs != nullptr ) {
121+ _fs->unmount ();
122+ delete _fs;
123+ _fs = nullptr ;
124+ }
125+
126+ if (_bd != nullptr ) {
127+ delete _bd;
128+ _bd = nullptr ;
129+ }
130+ }
131+
132+ bool STM32H7OTACloudProcess::isOtaCapable () {
133+ #define BOOTLOADER_ADDR (0x8000000 )
134+ uint32_t bootloader_data_offset = 0x1F000 ;
135+ uint8_t * bootloader_data = (uint8_t *)(BOOTLOADER_ADDR + bootloader_data_offset);
136+ uint8_t currentBootloaderVersion = bootloader_data[1 ];
137+ if (currentBootloaderVersion < 22 )
138+ return false ;
139+ else
140+ return true ;
141+ }
142+
143+ bool STM32H7OTACloudProcess::storageInit () {
144+ int err_mount=1 ;
145+
146+ if (_bd_raw_qspi == nullptr ) {
147+ _bd_raw_qspi = mbed::BlockDevice::get_default_instance ();
148+
149+ if (_bd_raw_qspi->init () != QSPIF_BD_ERROR_OK) {
150+ DEBUG_VERBOSE (F (" Error: QSPI init failure." ));
151+ return false ;
152+ }
153+ }
154+
155+ if (storage == portenta::QSPI_FLASH_FATFS) {
156+ _fs = new mbed::FATFileSystem (" fs" );
157+ err_mount = _fs->mount (_bd_raw_qspi);
158+ } else if (storage == portenta::QSPI_FLASH_FATFS_MBR) {
159+ _bd = new mbed::MBRBlockDevice (_bd_raw_qspi, data_offset);
160+ _fs = new mbed::FATFileSystem (" fs" );
161+ err_mount = _fs->mount (_bd);
162+ }
163+
164+ if (!err_mount) {
165+ return true ;
166+ }
167+ DEBUG_VERBOSE (F (" Error while mounting the filesystem. Err = %d" ), err_mount);
168+ return false ;
169+ }
170+
171+ bool STM32H7OTACloudProcess::storageOpen () {
172+ DIR * dir = NULL ;
173+ if ((dir = opendir (" /fs" )) != NULL )
174+ {
175+ if (findProgramLength (dir, _program_length))
176+ {
177+ closedir (dir);
178+ return true ;
179+ }
180+ closedir (dir);
181+ }
182+
183+ return false ;
184+ }
185+
186+ bool findProgramLength (DIR * dir, uint32_t & program_length) {
187+ struct dirent * entry = NULL ;
188+ while ((entry = readdir (dir)) != NULL ) {
189+ if (strcmp (entry->d_name , " UPDATE.BIN" ) == 0 ) { // FIXME use constants
190+ struct stat stat_buf;
191+ stat (" /fs/UPDATE.BIN" , &stat_buf);
192+ program_length = stat_buf.st_size ;
193+ return true ;
194+ }
195+ }
196+
197+ return false ;
198+ }
199+
200+ // extern uint32_t __stext = ~0;
201+ extern uint32_t __etext;
202+ extern uint32_t _sdata;
203+ extern uint32_t _edata;
204+
205+ void * STM32H7OTACloudProcess::appStartAddress () {
206+ return (void *)0x8040000 ;
207+ // return &__stext;
208+ }
209+
210+ uint32_t STM32H7OTACloudProcess::appSize () {
211+ return ((&__etext - (uint32_t *)appStartAddress ()) + (&_edata - &_sdata))*sizeof (void *);
212+ }
213+
214+
215+ #endif // defined(BOARD_STM32H7) && OTA_ENABLED
0 commit comments