mirror of
https://github.com/opentx/opentx.git
synced 2025-07-25 09:15:38 +03:00
OTA Update added
This commit is contained in:
parent
daba1ffcb1
commit
ad9d8001b2
6 changed files with 243 additions and 43 deletions
|
@ -88,7 +88,9 @@ void onSdFormatConfirm(const char * result)
|
|||
void onUpdateConfirmation(const char * result)
|
||||
{
|
||||
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 {
|
||||
moduleState[EXTERNAL_MODULE].mode = MODULE_MODE_NORMAL;
|
||||
|
@ -97,14 +99,14 @@ void onUpdateConfirmation(const char * result)
|
|||
|
||||
void onUpdateStateChanged()
|
||||
{
|
||||
if (reusableBuffer.sdManager.otaInformation.step == BIND_INFO_REQUEST) {
|
||||
POPUP_CONFIRMATION(PXX2receiversModels[reusableBuffer.sdManager.otaInformation.receiverInformation.modelID], onUpdateConfirmation);
|
||||
if (reusableBuffer.sdManager.otaUpdateInformation.step == BIND_INFO_REQUEST) {
|
||||
POPUP_CONFIRMATION(PXX2receiversModels[reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.modelID], onUpdateConfirmation);
|
||||
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 = strAppendUnsigned(tmp, reusableBuffer.sdManager.otaInformation.receiverInformation.swVersion.minor);
|
||||
tmp = strAppendUnsigned(tmp, reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.swVersion.minor);
|
||||
*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);
|
||||
}
|
||||
}
|
||||
|
@ -203,9 +205,9 @@ void onSdManagerMenu(const char * result)
|
|||
}
|
||||
#endif
|
||||
else if (result == STR_FLASH_RECEIVER_OTA) {
|
||||
getSelectionFullPath(lfn);
|
||||
memclear(&reusableBuffer.sdManager.otaInformation, sizeof(BindInformation));
|
||||
moduleState[EXTERNAL_MODULE].startBind(&reusableBuffer.sdManager.otaInformation, onUpdateStateChanged);
|
||||
memclear(&reusableBuffer.sdManager.otaUpdateInformation, sizeof(OtaUpdateInformation));
|
||||
getSelectionFullPath(reusableBuffer.sdManager.otaUpdateInformation.filename);
|
||||
moduleState[EXTERNAL_MODULE].startBind(&reusableBuffer.sdManager.otaUpdateInformation, onUpdateStateChanged);
|
||||
}
|
||||
#endif
|
||||
#if defined(LUA)
|
||||
|
@ -219,10 +221,10 @@ void onSdManagerMenu(const char * result)
|
|||
void onUpdateReceiverSelection(const char * result)
|
||||
{
|
||||
if (result != STR_EXIT) {
|
||||
reusableBuffer.sdManager.otaInformation.selectedReceiverIndex = (result - reusableBuffer.sdManager.otaInformation.candidateReceiversNames[0]) / sizeof(reusableBuffer.sdManager.otaInformation.candidateReceiversNames[0]);
|
||||
reusableBuffer.sdManager.otaInformation.step = BIND_INFO_REQUEST;
|
||||
reusableBuffer.sdManager.otaUpdateInformation.selectedReceiverIndex = (result - reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversNames[0]) / sizeof(reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversNames[0]);
|
||||
reusableBuffer.sdManager.otaUpdateInformation.step = BIND_INFO_REQUEST;
|
||||
#if defined(SIMU)
|
||||
reusableBuffer.sdManager.otaInformation.receiverInformation.modelID = 0x01;
|
||||
reusableBuffer.sdManager.otaUpdateInformation.receiverInformation.modelID = 0x01;
|
||||
onUpdateStateChanged();
|
||||
#endif
|
||||
}
|
||||
|
@ -483,11 +485,11 @@ void menuRadioSdManager(event_t _event)
|
|||
}
|
||||
|
||||
if (moduleState[EXTERNAL_MODULE].mode == MODULE_MODE_BIND) {
|
||||
if (reusableBuffer.sdManager.otaInformation.step == BIND_INIT) {
|
||||
if (reusableBuffer.sdManager.otaInformation.candidateReceiversCount > 0) {
|
||||
popupMenuItemsCount = min<uint8_t>(reusableBuffer.sdManager.otaInformation.candidateReceiversCount, PXX2_MAX_RECEIVERS_PER_MODULE);
|
||||
if (reusableBuffer.sdManager.otaUpdateInformation.step == BIND_INIT) {
|
||||
if (reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversCount > 0) {
|
||||
popupMenuItemsCount = min<uint8_t>(reusableBuffer.sdManager.otaUpdateInformation.candidateReceiversCount, PXX2_MAX_RECEIVERS_PER_MODULE);
|
||||
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;
|
||||
CLEAR_POPUP();
|
||||
|
|
|
@ -1164,7 +1164,7 @@ union ReusableBuffer
|
|||
uint16_t offset;
|
||||
uint16_t count;
|
||||
char originalName[SD_SCREEN_FILE_LENGTH+1];
|
||||
BindInformation otaInformation;
|
||||
OtaUpdateInformation otaUpdateInformation;
|
||||
char otaReceiverVersion[sizeof(TR_CURRENT_VERSION) + 12];
|
||||
} sdManager;
|
||||
#endif
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "pulses/pxx1.h"
|
||||
#include "pulses/pxx2.h"
|
||||
#include "modules.h"
|
||||
#include "ff.h"
|
||||
|
||||
#if NUM_MODULES > 1
|
||||
#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_SHARE,
|
||||
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];
|
||||
});
|
||||
|
||||
struct ModuleSettings {
|
||||
uint8_t state; // 0x00 = READ 0x40 = WRITE
|
||||
tmr10ms_t retryTime;
|
||||
uint8_t rfProtocol;
|
||||
uint8_t externalAntenna;
|
||||
int8_t txPower;
|
||||
class ModuleSettings {
|
||||
public:
|
||||
uint8_t state; // 0x00 = READ 0x40 = WRITE
|
||||
tmr10ms_t retryTime;
|
||||
uint8_t rfProtocol;
|
||||
uint8_t externalAntenna;
|
||||
int8_t txPower;
|
||||
};
|
||||
|
||||
struct ReceiverSettings {
|
||||
uint8_t state; // 0x00 = READ 0x40 = WRITE
|
||||
tmr10ms_t timeout;
|
||||
uint8_t receiverId;
|
||||
uint8_t dirty;
|
||||
uint8_t telemetryDisabled;
|
||||
uint8_t pwmRate;
|
||||
uint8_t outputsCount;
|
||||
uint8_t outputsMapping[24];
|
||||
class ReceiverSettings {
|
||||
public:
|
||||
uint8_t state; // 0x00 = READ 0x40 = WRITE
|
||||
tmr10ms_t timeout;
|
||||
uint8_t receiverId;
|
||||
uint8_t dirty;
|
||||
uint8_t telemetryDisabled;
|
||||
uint8_t pwmRate;
|
||||
uint8_t outputsCount;
|
||||
uint8_t outputsMapping[24];
|
||||
};
|
||||
|
||||
struct BindInformation {
|
||||
uint8_t step;
|
||||
uint32_t timeout;
|
||||
char candidateReceiversNames[PXX2_MAX_RECEIVERS_PER_MODULE][PXX2_LEN_RX_NAME + 1];
|
||||
uint8_t candidateReceiversCount;
|
||||
uint8_t selectedReceiverIndex;
|
||||
uint8_t rxUid;
|
||||
uint8_t lbtMode;
|
||||
uint8_t flexMode;
|
||||
PXX2HardwareInformation receiverInformation;
|
||||
class BindInformation {
|
||||
public:
|
||||
uint8_t step;
|
||||
uint32_t timeout;
|
||||
char candidateReceiversNames[PXX2_MAX_RECEIVERS_PER_MODULE][PXX2_LEN_RX_NAME + 1];
|
||||
uint8_t candidateReceiversCount;
|
||||
uint8_t selectedReceiverIndex;
|
||||
uint8_t rxUid;
|
||||
uint8_t lbtMode;
|
||||
uint8_t flexMode;
|
||||
PXX2HardwareInformation receiverInformation;
|
||||
};
|
||||
|
||||
class OtaUpdateInformation: public BindInformation {
|
||||
public:
|
||||
char filename[_MAX_LFN+1];
|
||||
uint32_t address;
|
||||
};
|
||||
|
||||
typedef void (* ModuleCallback)();
|
||||
|
@ -156,6 +167,7 @@ PACK(struct ModuleState {
|
|||
ModuleInformation * moduleInformation;
|
||||
ModuleSettings * moduleSettings;
|
||||
BindInformation * bindInformation;
|
||||
OtaUpdateInformation * otaUpdateInformation;
|
||||
};
|
||||
ModuleCallback callback;
|
||||
|
||||
|
|
|
@ -287,8 +287,40 @@ void Pxx2Pulses::setupShareMode(uint8_t module)
|
|||
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)
|
||||
{
|
||||
if (moduleState[module].mode == MODULE_MODE_OTA_UPDATE)
|
||||
return;
|
||||
|
||||
initFrame();
|
||||
|
||||
switch (moduleState[module].mode) {
|
||||
|
@ -336,3 +368,95 @@ void Pxx2Pulses::setupFrame(uint8_t module)
|
|||
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#define PXX2_TYPE_ID_SPECTRUM 0x02
|
||||
|
||||
#define PXX2_TYPE_C_OTA 0xFE
|
||||
#define PXX2_TYPE_ID_OTA 0x02
|
||||
|
||||
#define PXX2_CHANNELS_FLAG0_FAILSAFE (1 << 6)
|
||||
#define PXX2_CHANNELS_FLAG0_RANGECHECK (1 << 7)
|
||||
|
@ -130,6 +131,15 @@ enum PXX2BindSteps {
|
|||
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 {
|
||||
PXX2_HARDWARE_INFO,
|
||||
PXX2_SETTINGS_READ,
|
||||
|
@ -178,6 +188,8 @@ class Pxx2Transport: public DataBuffer<uint8_t, 64>, public Pxx2CrcMixin {
|
|||
};
|
||||
|
||||
class Pxx2Pulses: public Pxx2Transport {
|
||||
friend class Pxx2OtaUpdate;
|
||||
|
||||
public:
|
||||
void setupFrame(uint8_t module);
|
||||
|
||||
|
@ -204,6 +216,8 @@ class Pxx2Pulses: public Pxx2Transport {
|
|||
|
||||
void setupPowerMeter(uint8_t module);
|
||||
|
||||
void sendOtaUpdate(uint8_t module, const char * rxName, uint32_t address, const char * data);
|
||||
|
||||
void addHead()
|
||||
{
|
||||
// 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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
switch (frame[2]) {
|
||||
|
@ -296,6 +322,10 @@ void processPXX2Frame(uint8_t module, uint8_t *frame)
|
|||
processToolsFrame(module, frame);
|
||||
break;
|
||||
|
||||
case PXX2_TYPE_C_OTA:
|
||||
processOtaUpdateFrame(module, frame);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue