2 * This file is part of INAV.
4 * INAV is free software. You can redistribute this software
5 * and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * INAV is distributed in the hope that they will be
11 * useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
27 #include "common/crc.h"
29 #include "drivers/flash.h"
30 #include "drivers/light_led.h"
31 #include "drivers/persistent.h"
32 #include "drivers/system.h"
34 #include "fc/firmware_update.h"
35 #include "fc/firmware_update_common.h"
36 #include "fc/runtime_config.h"
38 #include "io/asyncfatfs/asyncfatfs.h"
41 #ifdef MSP_FIRMWARE_UPDATE
43 #if !(defined(USE_FLASHFS) || defined(USE_SDCARD))
44 #error No storage backend available
47 static firmwareUpdateMetadata_t updateMetadata
;
48 static uint8_t updateFirmwareCalcCRC
= 0;
49 static uint32_t receivedSize
= 0;
50 static bool rollbackPrepared
= false;
52 #if defined(USE_SDCARD)
53 static uint32_t firmwareSize
;
54 static afatfsFilePtr_t updateFile
= NULL
;
55 static afatfsFilePtr_t backupFile
= NULL
;
57 static void updateFileOpenCallback(afatfsFilePtr_t file
)
62 static void backupFileOpenCallback(afatfsFilePtr_t file
)
67 #elif defined(USE_FLASHFS)
68 static uint32_t flashStartAddress
, flashOverflowAddress
;
72 static bool fullBackup(void)
74 const uint8_t *const backupSrcEnd
= (const uint8_t*)FLASH_END
;
75 uint8_t *backupSrcPtr
= (uint8_t*)&__firmware_start
;
77 updateMetadata
.backupCRC
= 0;
82 #if defined(USE_SDCARD)
83 if ((afatfs_getFilesystemState() != AFATFS_FILESYSTEM_STATE_READY
) || !afatfs_fopen(FIRMWARE_UPDATE_BACKUP_FILENAME
, "w+", backupFileOpenCallback
)) return false;
85 while (backupSrcPtr
< backupSrcEnd
) {
87 const uint16_t writeBlockSize
= 512;
88 uint32_t justWritten
= afatfs_fwriteSync(backupFile
, backupSrcPtr
, writeBlockSize
);
89 updateMetadata
.backupCRC
= crc8_dvb_s2_update(updateMetadata
.backupCRC
, backupSrcPtr
, justWritten
);
92 backupSrcPtr
+= justWritten
;
94 if (++counter
% (50*1024/512) == 0) {
101 afatfs_fcloseSync(backupFile
);
103 #elif defined(USE_FLASHFS)
104 flashPartition_t
*flashPartition
= flashPartitionFindByType(FLASH_PARTITION_TYPE_FULL_BACKUP
);
105 if (!flashPartition
) return false;
107 const flashGeometry_t
*flashGeometry
= flashGetGeometry();
108 const uint32_t flashSectorSize
= flashGeometry
->sectorSize
;
109 const uint32_t flashPartitionSize
= (flashPartition
->endSector
- flashPartition
->startSector
+ 1) * flashSectorSize
;
110 const uint32_t backupSize
= AVAILABLE_FIRMWARE_SPACE
;
111 if (backupSize
> flashPartitionSize
) return false;
113 uint32_t flashAddress
= flashPartition
->startSector
* flashSectorSize
;
115 const uint32_t flashPageSize
= flashGeometry
->pageSize
;
116 while (backupSrcPtr
< backupSrcEnd
) {
118 if (flashAddress
% flashSectorSize
== 0) {
119 flashEraseSector(flashAddress
);
120 flashWaitForReady(1000);
123 flashPageProgram(flashAddress
, backupSrcPtr
, flashPageSize
);
124 updateMetadata
.backupCRC
= crc8_dvb_s2_update(updateMetadata
.backupCRC
, backupSrcPtr
, flashPageSize
);
126 flashAddress
+= flashPageSize
;
127 backupSrcPtr
+= flashPageSize
;
129 if (++counter
% (10*1024/256) == 0) {
141 static bool backupIsValid(void)
143 if (!firmwareUpdateMetadataRead(&updateMetadata
) || (updateMetadata
.magic
!= FIRMWARE_UPDATE_METADATA_MAGIC
)) {
150 uint32_t counter
= 0;
153 #if defined(USE_SDCARD)
154 #define SD_BACKUP_FILE_BLOCK_READ_SIZE 512
155 if ((afatfs_getFilesystemState() != AFATFS_FILESYSTEM_STATE_READY
) || !afatfs_fopen(FIRMWARE_UPDATE_BACKUP_FILENAME
, "w+", backupFileOpenCallback
)) return false;
157 uint32_t totalRead
= 0;
159 uint8_t buffer
[SD_BACKUP_FILE_BLOCK_READ_SIZE
];
160 while (!afatfs_feof(backupFile
)) {
162 uint32_t readBytes
= afatfs_freadSync(backupFile
, buffer
, SD_BACKUP_FILE_BLOCK_READ_SIZE
);
163 calcCRC
= crc8_dvb_s2_update(calcCRC
, buffer
, readBytes
);
165 totalRead
+= readBytes
;
167 if (++counter
% (50*1024/SD_BACKUP_FILE_BLOCK_READ_SIZE
) == 0) {
174 afatfs_fcloseSync(backupFile
);
176 #elif defined(USE_FLASHFS)
177 flashPartition_t
*flashPartition
= flashPartitionFindByType(FLASH_PARTITION_TYPE_FULL_BACKUP
);
178 if (!flashPartition
) return false;
180 const flashGeometry_t
*flashGeometry
= flashGetGeometry();
181 const uint32_t flashSectorSize
= flashGeometry
->sectorSize
;
182 const uint32_t flashPartitionSize
= (flashPartition
->endSector
- flashPartition
->startSector
+ 1) * flashSectorSize
;
183 const uint32_t backupSize
= FLASH_END
- (uint32_t)&__firmware_start
;
184 if (backupSize
> flashPartitionSize
) return false;
186 uint32_t flashAddress
= flashPartition
->startSector
* flashSectorSize
;
187 const uint32_t flashEndAddress
= flashAddress
+ backupSize
;
190 while (flashAddress
< flashEndAddress
) {
192 flashReadBytes(flashAddress
, buffer
, sizeof(buffer
));
193 calcCRC
= crc8_dvb_s2_update(calcCRC
, buffer
, sizeof(buffer
));
195 flashAddress
+= sizeof(buffer
);
197 if (++counter
% (10*1024/256) == 0) {
206 return (calcCRC
== updateMetadata
.backupCRC
);
209 bool firmwareUpdatePrepare(uint32_t updateSize
)
211 if (ARMING_FLAG(ARMED
) || (updateSize
> AVAILABLE_FIRMWARE_SPACE
)) return false;
213 #if defined(USE_SDCARD)
214 if ((afatfs_getFilesystemState() != AFATFS_FILESYSTEM_STATE_READY
) || !afatfs_fopen(FIRMWARE_UPDATE_FIRMWARE_FILENAME
, "w+", updateFileOpenCallback
)) return false;
216 firmwareSize
= updateSize
;
218 #elif defined(USE_FLASHFS)
219 flashPartition_t
*flashUpdatePartition
= flashPartitionFindByType(FLASH_PARTITION_TYPE_UPDATE_FIRMWARE
);
220 if (!flashUpdatePartition
) return false;
222 const flashGeometry_t
*flashGeometry
= flashGetGeometry();
224 flashStartAddress
= flashUpdatePartition
->startSector
* flashGeometry
->sectorSize
;
225 flashOverflowAddress
= ((flashUpdatePartition
->endSector
+ 1) * flashGeometry
->sectorSize
);
228 uint32_t partitionSize
= (flashUpdatePartition
->endSector
- flashUpdatePartition
->startSector
+ 1) * (flashGeometry
->sectorSize
* flashGeometry
->pageSize
);
230 if (updateSize
> partitionSize
) {
234 updateMetadata
.firmwareSize
= updateSize
;
238 updateFirmwareCalcCRC
= 0;
243 bool firmwareUpdateStore(uint8_t *data
, uint16_t length
)
245 if (ARMING_FLAG(ARMED
)) {
249 #if defined(USE_SDCARD)
251 if (!updateFile
|| !firmwareSize
|| (receivedSize
+ length
> firmwareSize
)
252 || (afatfs_fwriteSync(updateFile
, data
, length
) != length
)) {
256 #elif defined(USE_FLASHFS)
257 if (!updateMetadata
.firmwareSize
|| (receivedSize
+ length
> updateMetadata
.firmwareSize
)) return false;
259 const uint32_t flashAddress
= flashStartAddress
+ receivedSize
;
261 if ((flashAddress
+ length
> flashOverflowAddress
) || (receivedSize
+ length
> updateMetadata
.firmwareSize
)) {
262 updateMetadata
.firmwareSize
= 0;
266 const flashGeometry_t
*flashGeometry
= flashGetGeometry();
267 const uint32_t flashSectorSize
= flashGeometry
->sectorSize
;
269 if (flashAddress
% flashSectorSize
== 0) {
270 flashEraseSector(flashAddress
);
271 flashWaitForReady(1000);
274 flashPageProgram(flashAddress
, data
, length
);
278 updateFirmwareCalcCRC
= crc8_dvb_s2_update(updateFirmwareCalcCRC
, data
, length
);
279 receivedSize
+= length
;
284 void firmwareUpdateExec(uint8_t expectCRC
)
286 if (ARMING_FLAG(ARMED
)) return;
288 #if defined(USE_SDCARD)
289 if (!afatfs_fclose(updateFile
, NULL
)) return;
290 if (firmwareSize
&& (receivedSize
== firmwareSize
) &&
291 (updateFirmwareCalcCRC
== expectCRC
) && fullBackup() && firmwareUpdateMetadataWrite(&updateMetadata
)) {
292 systemResetRequest(RESET_BOOTLOADER_FIRMWARE_UPDATE
);
294 #elif defined(USE_FLASHFS)
295 if (updateMetadata
.firmwareSize
&& (receivedSize
== updateMetadata
.firmwareSize
) &&
296 (updateFirmwareCalcCRC
== expectCRC
) && fullBackup() && firmwareUpdateMetadataWrite(&updateMetadata
)) {
297 systemResetRequest(RESET_BOOTLOADER_FIRMWARE_UPDATE
);
303 bool firmwareUpdateRollbackPrepare(void)
305 if (ARMING_FLAG(ARMED
) || !(rollbackPrepared
|| backupIsValid())) return false;
307 rollbackPrepared
= true;
311 void firmwareUpdateRollbackExec(void)
313 if (ARMING_FLAG(ARMED
) || !firmwareUpdateRollbackPrepare()) return;
315 systemResetRequest(RESET_BOOTLOADER_FIRMWARE_ROLLBACK
);