163 lines
4.1 KiB
C++
163 lines
4.1 KiB
C++
/*
|
|
* Copyright (C) EdgeTX
|
|
*
|
|
* Based on code named
|
|
* opentx - https://github.com/opentx/opentx
|
|
* th9x - http://code.google.com/p/th9x
|
|
* er9x - http://code.google.com/p/er9x
|
|
* gruvin9x - http://code.google.com/p/gruvin9x
|
|
*
|
|
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include "edgetx.h"
|
|
#include "io/frsky_firmware_update.h"
|
|
#include "os/sleep.h"
|
|
#include "tasks/mixer_task.h"
|
|
#include "lib_file.h"
|
|
|
|
#include "pxx2_ota.h"
|
|
#include "pxx2_transport.h"
|
|
|
|
bool Pxx2OtaUpdate::waitStep(uint8_t step, uint8_t timeout)
|
|
{
|
|
OtaUpdateInformation * destination = moduleState[module].otaUpdateInformation;
|
|
uint8_t elapsed = 0;
|
|
|
|
watchdogSuspend(100 /*1s*/);
|
|
|
|
while (step != destination->step) {
|
|
if (elapsed++ > timeout) {
|
|
return false;
|
|
}
|
|
sleep_ms(1);
|
|
telemetryWakeup();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
const char* Pxx2OtaUpdate::nextStep(uint8_t step, const char* rxName,
|
|
uint32_t address, const uint8_t* buffer)
|
|
{
|
|
OtaUpdateInformation * destination = moduleState[module].otaUpdateInformation;
|
|
|
|
destination->step = step;
|
|
destination->address = address;
|
|
|
|
for (uint8_t retry = 0;; retry++) {
|
|
uint8_t* module_buffer = pulsesGetModuleBuffer(module);
|
|
Pxx2Pulses pxx2(module_buffer);
|
|
pxx2.sendOtaUpdate(module, rxName, address, (const char *) buffer);
|
|
|
|
// send the frame immediately
|
|
auto mod = pulsesGetModuleDriver(module);
|
|
auto mod_st = (etx_module_state_t*)mod->ctx;
|
|
|
|
auto drv = modulePortGetSerialDrv(mod_st->tx);
|
|
auto ctx = modulePortGetCtx(mod_st->tx);
|
|
drv->sendBuffer(ctx, module_buffer, pxx2.getSize());
|
|
|
|
if (waitStep(step + 1, 20)) {
|
|
return nullptr;
|
|
}
|
|
else if (retry == 100) {
|
|
return "Transfer failed";
|
|
}
|
|
}
|
|
}
|
|
|
|
const char* Pxx2OtaUpdate::doFlashFirmware(const char* filename,
|
|
ProgressHandler progressHandler)
|
|
{
|
|
FIL file;
|
|
uint8_t buffer[32];
|
|
UINT count;
|
|
const char * result;
|
|
|
|
result = nextStep(OTA_UPDATE_START, rxName, 0, nullptr);
|
|
if (result) {
|
|
return result;
|
|
}
|
|
|
|
if (f_open(&file, filename, FA_READ) != FR_OK) {
|
|
return "Open file failed";
|
|
}
|
|
|
|
uint32_t size;
|
|
const char * ext = getFileExtension(filename);
|
|
if (ext && !strcasecmp(ext, FRSKY_FIRMWARE_EXT)) {
|
|
FrSkyFirmwareInformation * information = (FrSkyFirmwareInformation *) buffer;
|
|
if (f_read(&file, buffer, sizeof(FrSkyFirmwareInformation), &count) != FR_OK ||
|
|
count != sizeof(FrSkyFirmwareInformation)) {
|
|
f_close(&file);
|
|
return "Format error";
|
|
}
|
|
size = information->size;
|
|
}
|
|
else {
|
|
size = f_size(&file);
|
|
}
|
|
|
|
uint32_t done = 0;
|
|
while (1) {
|
|
progressHandler(getBasename(filename), STR_OTA_UPDATE, done, size);
|
|
if (f_read(&file, buffer, sizeof(buffer), &count) != FR_OK) {
|
|
f_close(&file);
|
|
return "Read file failed";
|
|
}
|
|
|
|
result = nextStep(OTA_UPDATE_TRANSFER, nullptr, done, buffer);
|
|
if (result) {
|
|
return result;
|
|
}
|
|
|
|
if (count < sizeof(buffer)) {
|
|
f_close(&file);
|
|
break;
|
|
}
|
|
|
|
done += count;
|
|
}
|
|
|
|
return nextStep(OTA_UPDATE_EOF, nullptr, done, nullptr);
|
|
}
|
|
|
|
void Pxx2OtaUpdate::flashFirmware(const char * filename, ProgressHandler progressHandler)
|
|
{
|
|
mixerTaskStop();
|
|
|
|
watchdogSuspend(100 /*1s*/);
|
|
sleep_ms(100);
|
|
|
|
moduleState[module].mode = MODULE_MODE_OTA_UPDATE;
|
|
const char * result = doFlashFirmware(filename, progressHandler);
|
|
moduleState[module].mode = MODULE_MODE_NORMAL;
|
|
|
|
AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1 );
|
|
BACKLIGHT_ENABLE();
|
|
|
|
if (result) {
|
|
POPUP_WARNING(STR_FIRMWARE_UPDATE_ERROR, result);
|
|
}
|
|
else {
|
|
POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS);
|
|
}
|
|
|
|
watchdogSuspend(100);
|
|
sleep_ms(100);
|
|
|
|
mixerTaskStart();
|
|
}
|
|
|
|
|