1
0
Fork 0
mirror of https://github.com/opentx/opentx.git synced 2025-07-25 01:05:10 +03:00

OTA Update added

This commit is contained in:
Bertrand Songis 2019-05-07 11:18:39 +02:00
parent daba1ffcb1
commit ad9d8001b2
6 changed files with 243 additions and 43 deletions

View file

@ -88,7 +88,9 @@ void onSdFormatConfirm(const char * result)
void onUpdateConfirmation(const char * result) void onUpdateConfirmation(const char * result)
{ {
if (result == STR_OK) { if (result == STR_OK) {
// TODO OTA Update OtaUpdateInformation * destination = moduleState[EXTERNAL_MODULE].otaUpdateInformation;
Pxx2OtaUpdate otaUpdate(EXTERNAL_MODULE, destination->candidateReceiversNames[destination->selectedReceiverIndex]);
otaUpdate.flashFirmware(destination->filename);
} }
else { else {
moduleState[EXTERNAL_MODULE].mode = MODULE_MODE_NORMAL; moduleState[EXTERNAL_MODULE].mode = MODULE_MODE_NORMAL;
@ -97,14 +99,14 @@ void onUpdateConfirmation(const char * result)
void onUpdateStateChanged() void onUpdateStateChanged()
{ {
if (reusableBuffer.sdManager.otaInformation.step == BIND_INFO_REQUEST) { if (reusableBuffer.sdManager.otaUpdateInformation.step == BIND_INFO_REQUEST) {
POPUP_CONFIRMATION(PXX2receiversModels[reusableBuffer.sdManager.otaInformation.receiverInformation.modelID], onUpdateConfirmation); POPUP_CONFIRMATION(PXX2receiversModels[reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.modelID], onUpdateConfirmation);
char * tmp = strAppend(reusableBuffer.sdManager.otaReceiverVersion, TR_CURRENT_VERSION); char * tmp = strAppend(reusableBuffer.sdManager.otaReceiverVersion, TR_CURRENT_VERSION);
tmp = strAppendUnsigned(tmp, 1 + reusableBuffer.sdManager.otaInformation.receiverInformation.swVersion.major); tmp = strAppendUnsigned(tmp, 1 + reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.major);
*tmp++ = '.'; *tmp++ = '.';
tmp = strAppendUnsigned(tmp, reusableBuffer.sdManager.otaInformation.receiverInformation.swVersion.minor); tmp = strAppendUnsigned(tmp, reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.minor);
*tmp++ = '.'; *tmp++ = '.';
tmp = strAppendUnsigned(tmp, reusableBuffer.sdManager.otaInformation.receiverInformation.swVersion.revision); tmp = strAppendUnsigned(tmp, reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.revision);
SET_WARNING_INFO(reusableBuffer.sdManager.otaReceiverVersion, tmp - reusableBuffer.sdManager.otaReceiverVersion, 0); SET_WARNING_INFO(reusableBuffer.sdManager.otaReceiverVersion, tmp - reusableBuffer.sdManager.otaReceiverVersion, 0);
} }
} }
@ -203,9 +205,9 @@ void onSdManagerMenu(const char * result)
} }
#endif #endif
else if (result == STR_FLASH_RECEIVER_OTA) { else if (result == STR_FLASH_RECEIVER_OTA) {
getSelectionFullPath(lfn); memclear(&reusableBuffer.sdManager.otaUpdateInformation, sizeof(OtaUpdateInformation));
memclear(&reusableBuffer.sdManager.otaInformation, sizeof(BindInformation)); getSelectionFullPath(reusableBuffer.sdManager.otaUpdateInformation.filename);
moduleState[EXTERNAL_MODULE].startBind(&reusableBuffer.sdManager.otaInformation, onUpdateStateChanged); moduleState[EXTERNAL_MODULE].startBind(&reusableBuffer.sdManager.otaUpdateInformation, onUpdateStateChanged);
} }
#endif #endif
#if defined(LUA) #if defined(LUA)
@ -219,10 +221,10 @@ void onSdManagerMenu(const char * result)
void onUpdateReceiverSelection(const char * result) void onUpdateReceiverSelection(const char * result)
{ {
if (result != STR_EXIT) { if (result != STR_EXIT) {
reusableBuffer.sdManager.otaInformation.selectedReceiverIndex = (result - reusableBuffer.sdManager.otaInformation.candidateReceiversNames[0]) / sizeof(reusableBuffer.sdManager.otaInformation.candidateReceiversNames[0]); reusableBuffer.sdManager.otaUpdateInformation.selectedReceiverIndex = (result - reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversNames[0]) / sizeof(reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversNames[0]);
reusableBuffer.sdManager.otaInformation.step = BIND_INFO_REQUEST; reusableBuffer.sdManager.otaUpdateInformation.step = BIND_INFO_REQUEST;
#if defined(SIMU) #if defined(SIMU)
reusableBuffer.sdManager.otaInformation.receiverInformation.modelID = 0x01; reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.modelID = 0x01;
onUpdateStateChanged(); onUpdateStateChanged();
#endif #endif
} }
@ -483,11 +485,11 @@ void menuRadioSdManager(event_t _event)
} }
if (moduleState[EXTERNAL_MODULE].mode == MODULE_MODE_BIND) { if (moduleState[EXTERNAL_MODULE].mode == MODULE_MODE_BIND) {
if (reusableBuffer.sdManager.otaInformation.step == BIND_INIT) { if (reusableBuffer.sdManager.otaUpdateInformation.step == BIND_INIT) {
if (reusableBuffer.sdManager.otaInformation.candidateReceiversCount > 0) { if (reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversCount > 0) {
popupMenuItemsCount = min<uint8_t>(reusableBuffer.sdManager.otaInformation.candidateReceiversCount, PXX2_MAX_RECEIVERS_PER_MODULE); popupMenuItemsCount = min<uint8_t>(reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversCount, PXX2_MAX_RECEIVERS_PER_MODULE);
for (uint8_t i=0; i<popupMenuItemsCount; i++) { for (uint8_t i=0; i<popupMenuItemsCount; i++) {
popupMenuItems[i] = reusableBuffer.sdManager.otaInformation.candidateReceiversNames[i]; popupMenuItems[i] = reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversNames[i];
} }
popupMenuTitle = STR_PXX2_SELECT_RX; popupMenuTitle = STR_PXX2_SELECT_RX;
CLEAR_POPUP(); CLEAR_POPUP();

View file

@ -1164,7 +1164,7 @@ union ReusableBuffer
uint16_t offset; uint16_t offset;
uint16_t count; uint16_t count;
char originalName[SD_SCREEN_FILE_LENGTH+1]; char originalName[SD_SCREEN_FILE_LENGTH+1];
BindInformation otaInformation; OtaUpdateInformation otaUpdateInformation;
char otaReceiverVersion[sizeof(TR_CURRENT_VERSION) + 12]; char otaReceiverVersion[sizeof(TR_CURRENT_VERSION) + 12];
} sdManager; } sdManager;
#endif #endif

View file

@ -27,6 +27,7 @@
#include "pulses/pxx1.h" #include "pulses/pxx1.h"
#include "pulses/pxx2.h" #include "pulses/pxx2.h"
#include "modules.h" #include "modules.h"
#include "ff.h"
#if NUM_MODULES > 1 #if NUM_MODULES > 1
#define IS_RANGECHECK_ENABLE() (moduleState[0].mode == MODULE_MODE_RANGECHECK || moduleState[1].mode == MODULE_MODE_RANGECHECK) #define IS_RANGECHECK_ENABLE() (moduleState[0].mode == MODULE_MODE_RANGECHECK || moduleState[1].mode == MODULE_MODE_RANGECHECK)
@ -77,7 +78,8 @@ enum ModuleSettingsMode
MODULE_MODE_BIND, MODULE_MODE_BIND,
MODULE_MODE_SHARE, MODULE_MODE_SHARE,
MODULE_MODE_RANGECHECK, MODULE_MODE_RANGECHECK,
MODULE_MODE_RESET MODULE_MODE_RESET,
MODULE_MODE_OTA_UPDATE,
}; };
@ -104,35 +106,44 @@ PACK(struct ModuleInformation {
} receivers[PXX2_MAX_RECEIVERS_PER_MODULE]; } receivers[PXX2_MAX_RECEIVERS_PER_MODULE];
}); });
struct ModuleSettings { class ModuleSettings {
uint8_t state; // 0x00 = READ 0x40 = WRITE public:
tmr10ms_t retryTime; uint8_t state; // 0x00 = READ 0x40 = WRITE
uint8_t rfProtocol; tmr10ms_t retryTime;
uint8_t externalAntenna; uint8_t rfProtocol;
int8_t txPower; uint8_t externalAntenna;
int8_t txPower;
}; };
struct ReceiverSettings { class ReceiverSettings {
uint8_t state; // 0x00 = READ 0x40 = WRITE public:
tmr10ms_t timeout; uint8_t state; // 0x00 = READ 0x40 = WRITE
uint8_t receiverId; tmr10ms_t timeout;
uint8_t dirty; uint8_t receiverId;
uint8_t telemetryDisabled; uint8_t dirty;
uint8_t pwmRate; uint8_t telemetryDisabled;
uint8_t outputsCount; uint8_t pwmRate;
uint8_t outputsMapping[24]; uint8_t outputsCount;
uint8_t outputsMapping[24];
}; };
struct BindInformation { class BindInformation {
uint8_t step; public:
uint32_t timeout; uint8_t step;
char candidateReceiversNames[PXX2_MAX_RECEIVERS_PER_MODULE][PXX2_LEN_RX_NAME + 1]; uint32_t timeout;
uint8_t candidateReceiversCount; char candidateReceiversNames[PXX2_MAX_RECEIVERS_PER_MODULE][PXX2_LEN_RX_NAME + 1];
uint8_t selectedReceiverIndex; uint8_t candidateReceiversCount;
uint8_t rxUid; uint8_t selectedReceiverIndex;
uint8_t lbtMode; uint8_t rxUid;
uint8_t flexMode; uint8_t lbtMode;
PXX2HardwareInformation receiverInformation; uint8_t flexMode;
PXX2HardwareInformation receiverInformation;
};
class OtaUpdateInformation: public BindInformation {
public:
char filename[_MAX_LFN+1];
uint32_t address;
}; };
typedef void (* ModuleCallback)(); typedef void (* ModuleCallback)();
@ -156,6 +167,7 @@ PACK(struct ModuleState {
ModuleInformation * moduleInformation; ModuleInformation * moduleInformation;
ModuleSettings * moduleSettings; ModuleSettings * moduleSettings;
BindInformation * bindInformation; BindInformation * bindInformation;
OtaUpdateInformation * otaUpdateInformation;
}; };
ModuleCallback callback; ModuleCallback callback;

View file

@ -287,8 +287,40 @@ void Pxx2Pulses::setupShareMode(uint8_t module)
Pxx2Transport::addByte(reusableBuffer.moduleSetup.pxx2.shareReceiverIndex); Pxx2Transport::addByte(reusableBuffer.moduleSetup.pxx2.shareReceiverIndex);
} }
void Pxx2Pulses::sendOtaUpdate(uint8_t module, const char * rxName, uint32_t address, const char * data)
{
initFrame();
addFrameType(PXX2_TYPE_C_OTA, PXX2_TYPE_ID_OTA);
if (rxName) {
Pxx2Transport::addByte(0x00);
for (uint8_t i=0; i<PXX2_LEN_RX_NAME; i++) {
Pxx2Transport::addByte(rxName[i]);
}
}
else if (data) {
Pxx2Transport::addByte(0x01);
Pxx2Transport::addWord(address);
for (uint8_t i=0; i<32; i++) {
Pxx2Transport::addByte(data[i]);
}
}
else {
Pxx2Transport::addByte(0x02);
}
endFrame();
if (module == EXTERNAL_MODULE)
extmoduleSendNextFrame();
}
void Pxx2Pulses::setupFrame(uint8_t module) void Pxx2Pulses::setupFrame(uint8_t module)
{ {
if (moduleState[module].mode == MODULE_MODE_OTA_UPDATE)
return;
initFrame(); initFrame();
switch (moduleState[module].mode) { switch (moduleState[module].mode) {
@ -336,3 +368,95 @@ void Pxx2Pulses::setupFrame(uint8_t module)
endFrame(); endFrame();
} }
bool Pxx2OtaUpdate::waitStep(uint8_t step, uint8_t timeout)
{
OtaUpdateInformation * destination = moduleState[module].otaUpdateInformation;
uint8_t elapsed = 0;
watchdogSuspend(100);
while (step != destination->step) {
if (elapsed++ > timeout) {
return false;
}
RTOS_WAIT_MS(1);
telemetryWakeup();
}
return true;
}
const char * Pxx2OtaUpdate::doFlashFirmware(const char * filename)
{
FIL file;
uint8_t buffer[32];
UINT count = 0;
OtaUpdateInformation * destination = moduleState[module].otaUpdateInformation;
destination->step = OTA_UPDATE_START;
extmodulePulsesData.pxx2.sendOtaUpdate(module, rxName, 0, nullptr);
if (!waitStep(OTA_UPDATE_START_ACK, 10)) {
return "OTA start failed";
}
if (f_open(&file, filename, FA_READ) != FR_OK) {
return "Opening file failed";
}
uint32_t size = f_size(&file);
uint32_t done = 0;
while (1) {
done += count;
drawProgressScreen(getBasename(filename), "OTA update...", done, size);
if (f_read(&file, buffer, sizeof(buffer), &count) != FR_OK) {
f_close(&file);
return "Reading file failed";
}
destination->step = OTA_UPDATE_TRANSFER;
extmodulePulsesData.pxx2.sendOtaUpdate(module, nullptr, done, (char *)buffer);
if (!waitStep(OTA_UPDATE_TRANSFER_ACK, 10)) {
return "OTA transfer failed";
}
if (count < sizeof(buffer)) {
f_close(&file);
break;
}
}
destination->step = OTA_UPDATE_EOF;
extmodulePulsesData.pxx2.sendOtaUpdate(module, nullptr, done, nullptr);
if (!waitStep(OTA_UPDATE_END, 10)) {
return "OTA end failed";
}
return nullptr;
}
void Pxx2OtaUpdate::flashFirmware(const char * filename)
{
pausePulses();
watchdogSuspend(100);
RTOS_WAIT_MS(100);
moduleState[module].mode = MODULE_MODE_OTA_UPDATE;
const char * result = doFlashFirmware(filename);
moduleState[module].mode = MODULE_MODE_NORMAL;
AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1 );
BACKLIGHT_ENABLE();
if (result) {
POPUP_WARNING(STR_FIRMWARE_UPDATE_ERROR);
SET_WARNING_INFO(result, strlen(result), 0);
}
else {
POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS);
}
watchdogSuspend(100);
RTOS_WAIT_MS(100);
resumePulses();
}

View file

@ -41,6 +41,7 @@
#define PXX2_TYPE_ID_SPECTRUM 0x02 #define PXX2_TYPE_ID_SPECTRUM 0x02
#define PXX2_TYPE_C_OTA 0xFE #define PXX2_TYPE_C_OTA 0xFE
#define PXX2_TYPE_ID_OTA 0x02
#define PXX2_CHANNELS_FLAG0_FAILSAFE (1 << 6) #define PXX2_CHANNELS_FLAG0_FAILSAFE (1 << 6)
#define PXX2_CHANNELS_FLAG0_RANGECHECK (1 << 7) #define PXX2_CHANNELS_FLAG0_RANGECHECK (1 << 7)
@ -130,6 +131,15 @@ enum PXX2BindSteps {
BIND_OK BIND_OK
}; };
enum PXX2OtaUpdateSteps {
OTA_UPDATE_START = BIND_OK + 1,
OTA_UPDATE_START_ACK,
OTA_UPDATE_TRANSFER,
OTA_UPDATE_TRANSFER_ACK,
OTA_UPDATE_EOF,
OTA_UPDATE_END
};
enum PXX2ReceiverStatus { enum PXX2ReceiverStatus {
PXX2_HARDWARE_INFO, PXX2_HARDWARE_INFO,
PXX2_SETTINGS_READ, PXX2_SETTINGS_READ,
@ -178,6 +188,8 @@ class Pxx2Transport: public DataBuffer<uint8_t, 64>, public Pxx2CrcMixin {
}; };
class Pxx2Pulses: public Pxx2Transport { class Pxx2Pulses: public Pxx2Transport {
friend class Pxx2OtaUpdate;
public: public:
void setupFrame(uint8_t module); void setupFrame(uint8_t module);
@ -204,6 +216,8 @@ class Pxx2Pulses: public Pxx2Transport {
void setupPowerMeter(uint8_t module); void setupPowerMeter(uint8_t module);
void sendOtaUpdate(uint8_t module, const char * rxName, uint32_t address, const char * data);
void addHead() void addHead()
{ {
// send 7E, do not CRC // send 7E, do not CRC
@ -265,4 +279,22 @@ class Pxx2Pulses: public Pxx2Transport {
} }
}; };
class Pxx2OtaUpdate {
public:
Pxx2OtaUpdate(uint8_t module, const char * rxName):
module(module),
rxName(rxName)
{
}
void flashFirmware(const char * filename);
protected:
uint8_t module;
const char * rxName;
const char * doFlashFirmware(const char * filename);
bool waitStep(uint8_t step, uint8_t timeout);
};
#endif #endif

View file

@ -239,6 +239,32 @@ void processPowerMeterFrame(uint8_t module, uint8_t * frame)
} }
} }
void processOtaUpdateFrame(uint8_t module, uint8_t * frame)
{
if (moduleState[module].mode != MODULE_MODE_OTA_UPDATE) {
return;
}
OtaUpdateInformation * destination = moduleState[module].otaUpdateInformation;
if (destination->step == OTA_UPDATE_START) {
if (frame[3] == 0x00 && memcmp(&destination->candidateReceiversNames[destination->selectedReceiverIndex], &frame[4], PXX2_LEN_RX_NAME) == 0) {
destination->step = OTA_UPDATE_START_ACK;
}
}
else if (destination->step == OTA_UPDATE_TRANSFER) {
uint32_t address = *((uint32_t *)&frame[4]);
if (frame[3] == 0x01 && destination->address == address) {
destination->step = OTA_UPDATE_TRANSFER_ACK;
}
}
else if (destination->step == OTA_UPDATE_EOF) {
if (frame[3] == 0x02) {
destination->step = OTA_UPDATE_END;
}
}
}
void processModuleFrame(uint8_t module, uint8_t *frame) void processModuleFrame(uint8_t module, uint8_t *frame)
{ {
switch (frame[2]) { switch (frame[2]) {
@ -296,6 +322,10 @@ void processPXX2Frame(uint8_t module, uint8_t *frame)
processToolsFrame(module, frame); processToolsFrame(module, frame);
break; break;
case PXX2_TYPE_C_OTA:
processOtaUpdateFrame(module, frame);
break;
default: default:
break; break;
} }