Skip to content

Commit 724bd7b

Browse files
implemented stm32h7 ota class
1 parent 02f5ab6 commit 724bd7b

File tree

3 files changed

+293
-44
lines changed

3 files changed

+293
-44
lines changed

src/ota/implementation/OTASTM32H7.cpp

+215
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
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

src/ota/implementation/OTASTM32H7.h

+78-12
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,89 @@
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+
111
#pragma once
12+
#include "ota/interface/OTAInterfaceDefault.h"
13+
14+
#include <QSPIFBlockDevice.h>
15+
16+
#include <BlockDevice.h>
17+
#include <MBRBlockDevice.h>
18+
#include <FATFileSystem.h>
19+
#include <LittleFileSystem.h>
220

3-
#include "src/ota/interface/OTAInterface.h"
21+
#include "WiFi.h" /* WiFi from ArduinoCore-mbed */
22+
#include <SocketHelpers.h>
423

5-
class STM32H7OTACloudProcess: public OTACloudProcessInterface {
24+
#define APOTA_QSPI_FLASH_FLAG (1 << 2)
25+
#define APOTA_SDCARD_FLAG (1 << 3)
26+
#define APOTA_RAW_FLAG (1 << 4)
27+
#define APOTA_FATFS_FLAG (1 << 5)
28+
#define APOTA_LITTLEFS_FLAG (1 << 6)
29+
#define APOTA_MBR_FLAG (1 << 7)
30+
31+
namespace portenta {
32+
enum StorageType {
33+
QSPI_FLASH_FATFS = APOTA_QSPI_FLASH_FLAG | APOTA_FATFS_FLAG,
34+
QSPI_FLASH_FATFS_MBR = APOTA_QSPI_FLASH_FLAG | APOTA_FATFS_FLAG | APOTA_MBR_FLAG,
35+
SD_FATFS = APOTA_SDCARD_FLAG | APOTA_FATFS_FLAG,
36+
SD_FATFS_MBR = APOTA_SDCARD_FLAG | APOTA_FATFS_FLAG | APOTA_MBR_FLAG,
37+
};
38+
}
39+
40+
class STM32H7OTACloudProcess: public OTADefaultCloudProcessInterface {
641
public:
7-
STM32H7OTACloudProcess();
8-
void update();
42+
STM32H7OTACloudProcess(MessageStream *ms, Client* client=nullptr);
43+
~STM32H7OTACloudProcess();
44+
void update() override;
945

10-
// retrocompatibility functions used in old ota prtotocol based on properties
11-
int otaRequest(char const * ota_url, NetworkAdapter iface);
12-
String getOTAImageSHA256();
13-
bool isOTACapable();
46+
virtual bool isOtaCapable() override;
1447
protected:
15-
// we start the download and decompress process
16-
virtual State fetch(Message* msg=nullptr);
48+
virtual OTACloudProcessInterface::State resume(Message* msg=nullptr) override;
49+
50+
// we are overriding the method of startOTA in order to open the destination file for the ota download
51+
virtual OTACloudProcessInterface::State startOTA() override;
1752

1853
// whene the download is correctly finished we set the mcu to use the newly downloaded binary
19-
virtual State flashOTA(Message* msg=nullptr);
54+
virtual OTACloudProcessInterface::State flashOTA() override;
2055

2156
// we reboot the device
22-
virtual State reboot(Message* msg=nullptr);
57+
virtual OTACloudProcessInterface::State reboot() override;
58+
59+
// write the decompressed char buffer of the incoming ota
60+
virtual int writeFlash(uint8_t* const buffer, size_t len) override;
61+
62+
virtual void reset() override;
63+
64+
void* appStartAddress();
65+
uint32_t appSize();
66+
bool appFlashOpen() { return true; };
67+
bool appFlashClose() { return true; };
68+
private:
69+
bool storageInit();
70+
bool storageOpen();
71+
72+
void storageClean();
73+
74+
FILE* decompressed;
75+
// static const char UPDATE_FILE_NAME[];
76+
mbed::BlockDevice* _bd_raw_qspi;
77+
uint32_t _program_length;
78+
79+
mbed::BlockDevice* _bd;
80+
mbed::FATFileSystem* _fs;
81+
82+
mbed::MBRBlockDevice* cert_bd_qspi;
83+
mbed::FATFileSystem* cert_fs_qspi;
84+
85+
const portenta::StorageType storage=portenta::QSPI_FLASH_FATFS_MBR;
86+
const uint32_t data_offset=2;
87+
88+
static const char UPDATE_FILE_NAME[];
2389
};

src/ota/implementation/OTASTM32H7.ipp

-32
This file was deleted.

0 commit comments

Comments
 (0)