chore: New module/serial API (#3055)
* WiP: new module interface * WiP: softserial timer DMA * WiP: setup() and send() in one step and remove methods specific to internal or external module * fixes and extra port config * horus targets * module ports have moved * T8 support (only internal module) * fix nv14 * stupid GCC.... * disable BT * remove nv14 telem driver * remove old aux serial driver * Move module buffers out of pulses.h * Soft serial fixes and PXX1 support * Fixed PPM module output * Fixed CLI * compilation fixes * Ported bluetooth and flysky gimbal to new serial driver * Re-enable soft-serial RX * fixes and cleanup * nv14 fixes * Fix flysky gimbals * Ghost module * 16 bytes of RAM * Remove getByte from module API * Ghost cleanup * fix: _half_duplex_input() must be called after usart init * WiP * more cleanup * Remove board specific settings from PXX1 / PXX2 drivers * A bit of PXX2 header cleanup * Add support for OVER8 and ONEBIT * Add some support for inverters (NV14 / EL18) * Support NV14 power fixes in generic board * Fix polarity handling * Fix RX DMA * Fix mixer not running * Add soft-serial polarity control * Quick fix for telemetry polling while module port is changed * Fix bootloader DEBUG * Fix MPM telemetry * Fix pulse start * DSM2 soft-serial fallback * DSMP async module restart * Fix CRSF LUA upstream * Remove global variable telemetryProtocol * Use HAL/LL constants * Fix various issue with AFHDS3 and NV14/EL18 internal module * Fixed S.PORT unit tests * fix: update widx after writing at current index * fix: init error condition * Fix: possible infinite loop in _find_port() * Add support for bidir S.PORT init * Add support for "getLastByte" in HW serial driver * PXX1: Add support for S.PORT based on IDLE callback * Fix rebase error * Fix softserial _rx_fifo_push() * Add softserial support for waitForTxCompleted() * Fix MPM flashing (internal / external) * Fixed external MPM * Activate RX DMA on internal module Seems to work with serial passthrough without issues, at least on the L3R PRO. * Fix softserial DMA on stdlcd F4 targets * Add softserial support for 32bit timers (mostly TIM2) * More precise soft-serial * Fix MPM update using inverters & HW uart * Raise S.PORT DMA/USART IRQ prio to achieve faster switching to input * Remove useless delays * Fix flashing external ELRS module * Added a retry mechanism for FrSky S.PORT update * Remove useless enableRx() * External FrSky modules are all flashed via S.PORT * Remove power management unit update This was only used on the first batch of X-lite.
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
#include "frsky_firmware_update.h"
|
||||
#include "debug.h"
|
||||
#include "timers_driver.h"
|
||||
#include "tasks/mixer_task.h"
|
||||
|
||||
#if defined(LIBOPENUI)
|
||||
#include "libopenui.h"
|
||||
@@ -31,9 +32,7 @@
|
||||
#include "libopenui/src/libopenui_file.h"
|
||||
#endif
|
||||
|
||||
#if defined(INTMODULE_USART)
|
||||
#include "intmodule_serial_driver.h"
|
||||
#endif
|
||||
#include "hal/module_port.h"
|
||||
|
||||
#define PRIM_REQ_POWERUP 0
|
||||
#define PRIM_REQ_VERSION 1
|
||||
@@ -110,97 +109,65 @@ void FrskyDeviceFirmwareUpdate::processFrame(const uint8_t * frame)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(PCBHORUS)
|
||||
bool FrskyDeviceFirmwareUpdate::readBuffer(uint8_t * buffer, uint8_t count, uint32_t timeout)
|
||||
{
|
||||
watchdogSuspend(timeout);
|
||||
|
||||
switch (module) {
|
||||
case INTERNAL_MODULE:
|
||||
{
|
||||
uint32_t elapsed = 0;
|
||||
uint8_t index = 0;
|
||||
while (index < count && elapsed < timeout) {
|
||||
if (IntmoduleSerialDriver.getByte(uart_ctx, &(buffer[index]))) {
|
||||
++index;
|
||||
}
|
||||
else {
|
||||
RTOS_WAIT_MS(1);
|
||||
if (++elapsed == timeout)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
uint32_t elapsed = 0;
|
||||
uint8_t index = 0;
|
||||
while (index < count && elapsed < timeout) {
|
||||
if (uart_drv->getByte(uart_ctx, &(buffer[index]))) {
|
||||
++index;
|
||||
}
|
||||
else {
|
||||
RTOS_WAIT_MS(1);
|
||||
if (++elapsed == timeout)
|
||||
return false;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
const uint8_t * FrskyDeviceFirmwareUpdate::readFullDuplexFrame(uint32_t timeout)
|
||||
{
|
||||
#if defined(INTMODULE_USART)
|
||||
uint8_t len = 0;
|
||||
bool bytestuff = false;
|
||||
while (len < 10) {
|
||||
uint32_t elapsed = 0;
|
||||
uint8_t byte = 0;
|
||||
while (IntmoduleSerialDriver.getByte(uart_ctx, &byte) == 0) {
|
||||
RTOS_WAIT_MS(1);
|
||||
if (elapsed++ >= timeout) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
if (byte == 0x7D) {
|
||||
bytestuff = true;
|
||||
continue;
|
||||
}
|
||||
if (bytestuff) {
|
||||
frame[len] = 0x20 ^ byte;
|
||||
bytestuff = false;
|
||||
}
|
||||
else {
|
||||
frame[len] = byte;
|
||||
}
|
||||
if (len > 0 || byte == 0x7E) {
|
||||
++len;
|
||||
}
|
||||
}
|
||||
return &frame[1];
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
const uint8_t * FrskyDeviceFirmwareUpdate::readHalfDuplexFrame(uint32_t timeout)
|
||||
{
|
||||
for (int i = timeout; i >= 0; i--) {
|
||||
uint8_t byte ;
|
||||
while (sportGetByte(&byte)) {
|
||||
if (pushFrskyTelemetryData(byte)) {
|
||||
return telemetryRxBuffer;
|
||||
}
|
||||
}
|
||||
RTOS_WAIT_MS(1);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const uint8_t * FrskyDeviceFirmwareUpdate::readFrame(uint32_t timeout)
|
||||
{
|
||||
RTOS_WAIT_MS(1);
|
||||
|
||||
#if defined(INTERNAL_MODULE_PXX2)
|
||||
if ((module == INTERNAL_MODULE) &&
|
||||
(g_eeGeneral.internalModule = MODULE_TYPE_ISRM_PXX2)) {
|
||||
return readFullDuplexFrame(timeout);
|
||||
uint8_t len = 0;
|
||||
bool bytestuff = false;
|
||||
|
||||
while (len <= FRSKY_SPORT_PACKET_SIZE) {
|
||||
|
||||
uint32_t elapsed = 0;
|
||||
uint8_t byte = 0;
|
||||
|
||||
while (uart_drv->getByte(uart_ctx, &byte) == 0) {
|
||||
RTOS_WAIT_MS(1);
|
||||
if (elapsed++ >= timeout) {
|
||||
TRACE("timeout in frame (len=%d)",len);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (byte == BYTE_STUFF) {
|
||||
bytestuff = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bytestuff) {
|
||||
frame[len] = STUFF_MASK ^ byte;
|
||||
bytestuff = false;
|
||||
}
|
||||
else {
|
||||
frame[len] = byte;
|
||||
}
|
||||
|
||||
if (len > 0 || byte == START_STOP) {
|
||||
++len;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return readHalfDuplexFrame(timeout);
|
||||
|
||||
return &frame[1];
|
||||
}
|
||||
|
||||
bool FrskyDeviceFirmwareUpdate::waitState(State newState, uint32_t timeout)
|
||||
@@ -238,29 +205,20 @@ void FrskyDeviceFirmwareUpdate::startFrame(uint8_t command)
|
||||
void FrskyDeviceFirmwareUpdate::sendFrame()
|
||||
{
|
||||
uint8_t * ptr = outputTelemetryBuffer.data;
|
||||
*ptr++ = 0x7E;
|
||||
*ptr++ = START_STOP;
|
||||
*ptr++ = 0xFF;
|
||||
frame[7] = crc16(CRC_1021, frame, 7);
|
||||
for (int i=0; i<8; i++) {
|
||||
if (frame[i] == 0x7E || frame[i] == 0x7D) {
|
||||
*ptr++ = 0x7D;
|
||||
*ptr++ = 0x20 ^ frame[i];
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (frame[i] == START_STOP || frame[i] == BYTE_STUFF) {
|
||||
*ptr++ = BYTE_STUFF;
|
||||
*ptr++ = STUFF_MASK ^ frame[i];
|
||||
} else {
|
||||
*ptr++ = frame[i];
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(INTERNAL_MODULE_PXX2)
|
||||
if ((module == INTERNAL_MODULE) &&
|
||||
(g_eeGeneral.internalModule = MODULE_TYPE_ISRM_PXX2)) {
|
||||
IntmoduleSerialDriver.sendBuffer(uart_ctx, outputTelemetryBuffer.data,
|
||||
ptr - outputTelemetryBuffer.data);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
sportSendBuffer(outputTelemetryBuffer.data, ptr - outputTelemetryBuffer.data);
|
||||
uart_drv->sendBuffer(uart_ctx, outputTelemetryBuffer.data,
|
||||
ptr - outputTelemetryBuffer.data);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -269,7 +227,7 @@ const char * FrskyDeviceFirmwareUpdate::sendPowerOn()
|
||||
state = SPORT_POWERUP_REQ;
|
||||
|
||||
RTOS_WAIT_MS(50);
|
||||
telemetryClearFifo();
|
||||
uart_drv->clearRxBuffer(uart_ctx);
|
||||
|
||||
for (int i=0; i<10; i++) {
|
||||
// max 10 attempts
|
||||
@@ -279,21 +237,13 @@ const char * FrskyDeviceFirmwareUpdate::sendPowerOn()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (telemetryProtocol != PROTOCOL_TELEMETRY_FRSKY_SPORT) {
|
||||
return STR_DEVICE_NO_RESPONSE;
|
||||
}
|
||||
|
||||
if (!IS_FRSKY_SPORT_PROTOCOL()) {
|
||||
return STR_DEVICE_NO_RESPONSE;
|
||||
}
|
||||
|
||||
return STR_DEVICE_NO_RESPONSE;
|
||||
}
|
||||
|
||||
const char * FrskyDeviceFirmwareUpdate::sendReqVersion()
|
||||
{
|
||||
RTOS_WAIT_MS(20);
|
||||
telemetryClearFifo();
|
||||
uart_drv->clearRxBuffer(uart_ctx);
|
||||
|
||||
state = SPORT_VERSION_REQ;
|
||||
for (int i=0; i<10; i++) {
|
||||
@@ -311,20 +261,18 @@ const char * FrskyDeviceFirmwareUpdate::sendReqVersion()
|
||||
// X9D / X9D+ / X9E / XLite IXJT = use S.PORT @ 57600 bauds
|
||||
// XLite PRO / X9Lite / X9D+ 2019 ISRM = use TX + RX @ 57600 bauds
|
||||
|
||||
#if defined(INTMODULE_USART)
|
||||
static const etx_serial_init serialInitParams = {
|
||||
.baudrate = 0,
|
||||
.parity = ETX_Parity_None,
|
||||
.stop_bits = ETX_StopBits_One,
|
||||
.word_length = ETX_WordLength_8,
|
||||
.rx_enable = true,
|
||||
.encoding = ETX_Encoding_8N1,
|
||||
.direction = ETX_Dir_TX_RX,
|
||||
.polarity = ETX_Pol_Normal,
|
||||
};
|
||||
#endif
|
||||
|
||||
const char * FrskyDeviceFirmwareUpdate::doFlashFirmware(const char * filename, ProgressHandler progressHandler)
|
||||
const char *FrskyDeviceFirmwareUpdate::doFlashFirmware(
|
||||
const char *filename, ProgressHandler progressHandler)
|
||||
{
|
||||
FIL file;
|
||||
const char * result;
|
||||
const char *result;
|
||||
FrSkyFirmwareInformation information;
|
||||
UINT count;
|
||||
|
||||
@@ -332,64 +280,99 @@ const char * FrskyDeviceFirmwareUpdate::doFlashFirmware(const char * filename, P
|
||||
return STR_NEEDS_FILE;
|
||||
}
|
||||
|
||||
const char * ext = getFileExtension(filename);
|
||||
// Start with checking if we have a firmware description:
|
||||
// this mainly covers "newer" modules (ISRM, ACCESS based)
|
||||
|
||||
// default to S.PORT update...
|
||||
uint8_t port = ETX_MOD_PORT_SPORT;
|
||||
void (*set_pwr)(uint8_t) = nullptr;
|
||||
void (*set_bootcmd)(uint8_t) = nullptr;
|
||||
|
||||
// TODO: what about S.PORT update power control? (RX?)
|
||||
auto mod_desc = modulePortGetModuleDescription(module);
|
||||
set_pwr = mod_desc->set_pwr;
|
||||
|
||||
// ... and 57600 bps
|
||||
etx_serial_init cfg(serialInitParams);
|
||||
cfg.baudrate = 57600;
|
||||
|
||||
const char *ext = getFileExtension(filename);
|
||||
if (ext && !strcasecmp(ext, FRSKY_FIRMWARE_EXT)) {
|
||||
auto ret = f_read(&file, &information, sizeof(FrSkyFirmwareInformation), &count);
|
||||
auto ret =
|
||||
f_read(&file, &information, sizeof(FrSkyFirmwareInformation), &count);
|
||||
if (ret != FR_OK || count != sizeof(FrSkyFirmwareInformation)) {
|
||||
f_close(&file);
|
||||
return STR_DEVICE_FILE_ERROR;
|
||||
}
|
||||
|
||||
// probably some ISRM or ACCESS module...
|
||||
// TODO: what are we supposed to start with the firmware header file?
|
||||
if ((information.productFamily == FIRMWARE_FAMILY_INTERNAL_MODULE &&
|
||||
module != INTERNAL_MODULE) ||
|
||||
(information.productFamily == FIRMWARE_FAMILY_EXTERNAL_MODULE &&
|
||||
module != EXTERNAL_MODULE)) {
|
||||
|
||||
return STR_DEVICE_FILE_WRONG_SIG;
|
||||
}
|
||||
|
||||
if (information.productFamily == FIRMWARE_FAMILY_INTERNAL_MODULE &&
|
||||
information.productId == FIRMWARE_ID_MODULE_ISRM) {
|
||||
port = ETX_MOD_PORT_UART;
|
||||
}
|
||||
|
||||
} else if (module == INTERNAL_MODULE) {
|
||||
// For the older modules we need some guess work:
|
||||
//
|
||||
// - X12S / X10 IXJT = use TX + RX @ 38400 bauds with BOOTCMD pin
|
||||
// -> internal USART + boot pin
|
||||
//
|
||||
// - X9D / X9D+ / X9E / XLite IXJT = use S.PORT @ 57600 bauds
|
||||
// -> no internal USART OR no boot pin (XLite has an internal USART)
|
||||
|
||||
// X12S / X10 iXJT: TX + RX @ 38400 bauds with BOOTCMD pin inverted
|
||||
if (mod_desc->set_bootcmd) {
|
||||
cfg.baudrate = 38400;
|
||||
port = ETX_MOD_PORT_UART;
|
||||
set_bootcmd = mod_desc->set_bootcmd;
|
||||
} else {
|
||||
// keep the above defaults (S.PORT @ 57600 bps)
|
||||
}
|
||||
} else {
|
||||
#if defined(PCBHORUS)
|
||||
information.productId = FIRMWARE_ID_MODULE_XJT;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(PCBHORUS)
|
||||
if (module == INTERNAL_MODULE && information.productId == FIRMWARE_ID_MODULE_XJT) {
|
||||
INTERNAL_MODULE_ON();
|
||||
RTOS_WAIT_MS(1);
|
||||
// SPORT_MODULE is only defined for power control
|
||||
// but has not ports declared on it.
|
||||
//
|
||||
uint8_t serial_module = module != SPORT_MODULE ? module : EXTERNAL_MODULE;
|
||||
|
||||
etx_serial_init params(serialInitParams);
|
||||
params.baudrate = 38400;
|
||||
uart_ctx = IntmoduleSerialDriver.init(¶ms);
|
||||
mod_st = modulePortInitSerial(serial_module, port, &cfg);
|
||||
if (!mod_st) return "Communication port error";
|
||||
|
||||
GPIO_SetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN);
|
||||
// assume RX port is the same as TX
|
||||
uart_drv = modulePortGetSerialDrv(mod_st->tx);
|
||||
uart_ctx = modulePortGetCtx(mod_st->tx);
|
||||
|
||||
if (set_bootcmd) set_bootcmd(true);
|
||||
if (set_pwr) set_pwr(true);
|
||||
|
||||
// wait a bit for PWR to settle
|
||||
RTOS_WAIT_MS(1);
|
||||
|
||||
// Special update method for X12S / X10 iXJT
|
||||
if (module == INTERNAL_MODULE && port == ETX_MOD_PORT_UART && set_bootcmd != nullptr) {
|
||||
result = uploadFileToHorusXJT(filename, &file, progressHandler);
|
||||
GPIO_ResetBits(INTMODULE_BOOTCMD_GPIO, INTMODULE_BOOTCMD_GPIO_PIN);
|
||||
|
||||
f_close(&file);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(INTERNAL_MODULE_PXX2)
|
||||
if ((module == INTERNAL_MODULE) &&
|
||||
(g_eeGeneral.internalModule = MODULE_TYPE_ISRM_PXX2)) {
|
||||
etx_serial_init params(serialInitParams);
|
||||
params.baudrate = 57600;
|
||||
uart_ctx = IntmoduleSerialDriver.init(¶ms);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
telemetryInit(PROTOCOL_TELEMETRY_FRSKY_SPORT);
|
||||
} else {
|
||||
result = uploadFileNormal(filename, &file, progressHandler);
|
||||
}
|
||||
|
||||
if (module == INTERNAL_MODULE)
|
||||
INTERNAL_MODULE_ON();
|
||||
else if (module == EXTERNAL_MODULE)
|
||||
EXTERNAL_MODULE_ON();
|
||||
else
|
||||
SPORT_UPDATE_POWER_ON();
|
||||
if (set_pwr) set_pwr(false);
|
||||
if (set_bootcmd) set_bootcmd(false);
|
||||
|
||||
result = uploadFileNormal(filename, &file, progressHandler);
|
||||
f_close(&file);
|
||||
modulePortDeInit(mod_st);
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(PCBHORUS)
|
||||
const char * FrskyDeviceFirmwareUpdate::uploadFileToHorusXJT(const char * filename, FIL * file, ProgressHandler progressHandler)
|
||||
const char *FrskyDeviceFirmwareUpdate::uploadFileToHorusXJT(
|
||||
const char *filename, FIL *file, ProgressHandler progressHandler)
|
||||
{
|
||||
uint32_t buffer[1024 / sizeof(uint32_t)];
|
||||
UINT count;
|
||||
@@ -399,14 +382,14 @@ const char * FrskyDeviceFirmwareUpdate::uploadFileToHorusXJT(const char * filena
|
||||
return STR_DEVICE_NO_RESPONSE;
|
||||
}
|
||||
|
||||
IntmoduleSerialDriver.sendByte(uart_ctx, 0x81);
|
||||
uart_drv->sendByte(uart_ctx, 0x81);
|
||||
readBuffer(frame, 1, 100);
|
||||
|
||||
if (!readBuffer(frame, 8, 100) || frame[0] != 0x02) {
|
||||
return STR_DEVICE_NO_RESPONSE;
|
||||
}
|
||||
|
||||
IntmoduleSerialDriver.sendByte(uart_ctx, 0x82);
|
||||
uart_drv->sendByte(uart_ctx, 0x82);
|
||||
readBuffer(frame, 1, 100);
|
||||
|
||||
uint8_t index = 0;
|
||||
@@ -424,7 +407,7 @@ const char * FrskyDeviceFirmwareUpdate::uploadFileToHorusXJT(const char * filena
|
||||
return STR_DEVICE_WRONG_REQUEST;
|
||||
|
||||
if (count == 0) {
|
||||
IntmoduleSerialDriver.sendByte(uart_ctx, 0xA1);
|
||||
uart_drv->sendByte(uart_ctx, 0xA1);
|
||||
RTOS_WAIT_MS(50);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -432,22 +415,32 @@ const char * FrskyDeviceFirmwareUpdate::uploadFileToHorusXJT(const char * filena
|
||||
if (count < 1024)
|
||||
memset(((uint8_t *)buffer) + count, 0, 1024 - count);
|
||||
|
||||
IntmoduleSerialDriver.sendByte(uart_ctx, frame[0] + 0x80);
|
||||
IntmoduleSerialDriver.sendByte(uart_ctx, frame[1]);
|
||||
uart_drv->sendByte(uart_ctx, frame[0] + 0x80);
|
||||
uart_drv->sendByte(uart_ctx, frame[1]);
|
||||
|
||||
uint16_t crc_16 = crc16(CRC_1189, (uint8_t *)buffer, 1024, crc16(CRC_1189, &frame[1], 1));
|
||||
for (size_t i = 0; i < sizeof(buffer); i++) {
|
||||
IntmoduleSerialDriver.sendByte(uart_ctx, ((uint8_t *)buffer)[i]);
|
||||
uart_drv->sendByte(uart_ctx, ((uint8_t *)buffer)[i]);
|
||||
}
|
||||
IntmoduleSerialDriver.sendByte(uart_ctx, crc_16 >> 8);
|
||||
IntmoduleSerialDriver.sendByte(uart_ctx, crc_16);
|
||||
uart_drv->sendByte(uart_ctx, crc_16 >> 8);
|
||||
uart_drv->sendByte(uart_ctx, crc_16);
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const char * FrskyDeviceFirmwareUpdate::uploadFileNormal(const char * filename, FIL * file, ProgressHandler progressHandler)
|
||||
void FrskyDeviceFirmwareUpdate::sendDataTransfer(uint32_t* buffer)
|
||||
{
|
||||
startFrame(PRIM_DATA_WORD);
|
||||
uint32_t offset = (address & 1023) >> 2; // 32 bit word offset into buffer
|
||||
*((uint32_t *)(frame + 2)) = buffer[offset];
|
||||
frame[6] = address & 0x000000FF;
|
||||
state = SPORT_DATA_TRANSFER;
|
||||
sendFrame();
|
||||
}
|
||||
|
||||
const char *FrskyDeviceFirmwareUpdate::uploadFileNormal(
|
||||
const char *filename, FIL *file, ProgressHandler progressHandler)
|
||||
{
|
||||
uint32_t buffer[1024 / sizeof(uint32_t)];
|
||||
UINT count;
|
||||
@@ -461,12 +454,14 @@ const char * FrskyDeviceFirmwareUpdate::uploadFileNormal(const char * filename,
|
||||
return result;
|
||||
|
||||
RTOS_WAIT_MS(200);
|
||||
telemetryClearFifo();
|
||||
uart_drv->clearRxBuffer(uart_ctx);
|
||||
|
||||
state = SPORT_DATA_TRANSFER;
|
||||
startFrame(PRIM_CMD_DOWNLOAD);
|
||||
sendFrame();
|
||||
|
||||
uint8_t retries = 0;
|
||||
|
||||
while (true) {
|
||||
if (f_read(file, buffer, 1024, &count) != FR_OK) {
|
||||
return STR_DEVICE_FILE_ERROR;
|
||||
@@ -474,16 +469,19 @@ const char * FrskyDeviceFirmwareUpdate::uploadFileNormal(const char * filename,
|
||||
|
||||
count >>= 2;
|
||||
|
||||
for (uint32_t i=0; i<count; i++) {
|
||||
if (!waitState(SPORT_DATA_REQ, 2000)) {
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
|
||||
if (waitState(SPORT_DATA_REQ, 80)) {
|
||||
retries = 4; // reset retries
|
||||
} else if (retries > 0){
|
||||
--retries;
|
||||
TRACE("retrying last transfer (address=0x%04X)", address);
|
||||
} else {
|
||||
return STR_DEVICE_DATA_REFUSED;
|
||||
}
|
||||
startFrame(PRIM_DATA_WORD);
|
||||
uint32_t offset = (address & 1023) >> 2; // 32 bit word offset into buffer
|
||||
*((uint32_t *)(frame + 2)) = buffer[offset];
|
||||
frame[6] = address & 0x000000FF;
|
||||
state = SPORT_DATA_TRANSFER,
|
||||
sendFrame();
|
||||
|
||||
sendDataTransfer(buffer);
|
||||
|
||||
if (i == 0) {
|
||||
progressHandler(getBasename(filename), STR_WRITING, file->fptr, file->obj.objsize);
|
||||
}
|
||||
@@ -509,23 +507,13 @@ const char * FrskyDeviceFirmwareUpdate::endTransfer()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char * FrskyDeviceFirmwareUpdate::flashFirmware(const char * filename, ProgressHandler progressHandler)
|
||||
const char *FrskyDeviceFirmwareUpdate::flashFirmware(
|
||||
const char *filename, ProgressHandler progressHandler)
|
||||
{
|
||||
pauseMixerCalculations();
|
||||
pausePulses();
|
||||
pulsesStop();
|
||||
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
stopPulsesInternalModule();
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_EXTERNAL_MODULE)
|
||||
stopPulsesExternalModule();
|
||||
#endif
|
||||
|
||||
#if defined(SPORT_UPDATE_PWR_GPIO)
|
||||
uint8_t spuPwr = IS_SPORT_UPDATE_POWER_ON();
|
||||
SPORT_UPDATE_POWER_OFF();
|
||||
#endif
|
||||
// switch S.PORT power OFF if supported
|
||||
modulePortSetPower(SPORT_MODULE, false);
|
||||
|
||||
progressHandler(getBasename(filename), STR_DEVICE_RESET, 0, 0);
|
||||
|
||||
@@ -544,305 +532,18 @@ const char * FrskyDeviceFirmwareUpdate::flashFirmware(const char * filename, Pro
|
||||
POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS);
|
||||
}
|
||||
|
||||
#if defined(INTMODULE_USART)
|
||||
if (uart_ctx) {
|
||||
// If the UART is not deactivated, the module
|
||||
// will not properly reset
|
||||
IntmoduleSerialDriver.deinit(uart_ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
INTERNAL_MODULE_OFF();
|
||||
#endif
|
||||
EXTERNAL_MODULE_OFF();
|
||||
SPORT_UPDATE_POWER_OFF();
|
||||
watchdogSuspend(50 /*500ms*/);
|
||||
pulsesStart();
|
||||
|
||||
/* wait 2s off */
|
||||
watchdogSuspend(500 /*5s*/);
|
||||
RTOS_WAIT_MS(2000);
|
||||
telemetryClearFifo();
|
||||
|
||||
resumePulses();
|
||||
resumeMixerCalculations();
|
||||
|
||||
#if defined(SPORT_UPDATE_PWR_GPIO)
|
||||
if (spuPwr) {
|
||||
SPORT_UPDATE_POWER_ON();
|
||||
}
|
||||
#endif
|
||||
// TODO: S.PORT power control
|
||||
// -> where is it actually turned ON normally?
|
||||
//
|
||||
// #if defined(SPORT_UPDATE_PWR_GPIO)
|
||||
// if (spuPwr) {
|
||||
// SPORT_UPDATE_POWER_ON();
|
||||
// }
|
||||
// #endif
|
||||
|
||||
state = SPORT_IDLE;
|
||||
return result;
|
||||
}
|
||||
|
||||
#define CHIP_FIRMWARE_UPDATE_TIMEOUT 20000 /* 20s */
|
||||
|
||||
const char * FrskyChipFirmwareUpdate::waitAnswer(uint8_t & status)
|
||||
{
|
||||
watchdogSuspend(CHIP_FIRMWARE_UPDATE_TIMEOUT);
|
||||
|
||||
telemetryPortSetDirectionInput();
|
||||
|
||||
uint8_t buffer[12];
|
||||
for (uint8_t i = 0; i < sizeof(buffer); i++) {
|
||||
uint32_t retry = 0;
|
||||
while (true) {
|
||||
if (sportGetByte(&buffer[i])) {
|
||||
if ((i == 0 && buffer[0] != 0x7F) ||
|
||||
(i == 1 && buffer[1] != 0xFE) ||
|
||||
(i == 10 && buffer[10] != 0x0D) ||
|
||||
(i == 11 && buffer[11] != 0x0A)) {
|
||||
i = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (++retry == CHIP_FIRMWARE_UPDATE_TIMEOUT) {
|
||||
return STR_DEVICE_NO_RESPONSE;
|
||||
}
|
||||
RTOS_WAIT_MS(1);
|
||||
}
|
||||
}
|
||||
status = buffer[8];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char * FrskyChipFirmwareUpdate::startBootloader()
|
||||
{
|
||||
sportSendByte(0x03);
|
||||
RTOS_WAIT_MS(20);
|
||||
sportSendByte(0x02);
|
||||
RTOS_WAIT_MS(20);
|
||||
sportSendByte(0x01);
|
||||
|
||||
for (uint8_t i = 0; i < 30; i++)
|
||||
sportSendByte(0x7E);
|
||||
|
||||
for (uint32_t i = 0; i < 100; i++) {
|
||||
RTOS_WAIT_MS(20);
|
||||
sportSendByte(0x7F);
|
||||
}
|
||||
|
||||
RTOS_WAIT_MS(20);
|
||||
sportSendByte(0xFA);
|
||||
|
||||
/*for (uint8_t i=0; i < 30; i++)
|
||||
sportSendByte(0x7E);
|
||||
for (uint8_t i=0; i < 50; i++)
|
||||
sportSendByte(0x7F);*/
|
||||
|
||||
uint8_t status;
|
||||
const char * result = waitAnswer(status);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
return status == 0x08 ? nullptr : "Bootloader failed";
|
||||
}
|
||||
|
||||
void FrskyChipFirmwareUpdate::sendByte(uint8_t byte, bool crcFlag)
|
||||
{
|
||||
sportSendByte(byte);
|
||||
if (crcFlag) {
|
||||
crc ^= byte;
|
||||
}
|
||||
}
|
||||
|
||||
const char * FrskyChipFirmwareUpdate::sendUpgradeCommand(char command, uint32_t packetsCount)
|
||||
{
|
||||
crc = 0;
|
||||
|
||||
// Head
|
||||
sendByte(0x7F, false);
|
||||
sendByte(0xFE, false);
|
||||
|
||||
// Addr
|
||||
sendByte(0xFA);
|
||||
|
||||
// Cmd
|
||||
sendByte(command);
|
||||
|
||||
// Packets count
|
||||
sendByte(packetsCount >> 8);
|
||||
sendByte(packetsCount);
|
||||
|
||||
// Len
|
||||
sendByte('E' == command ? 0x00 : 0x0C);
|
||||
sendByte(0x40);
|
||||
|
||||
// Data
|
||||
for (uint8_t i=0; i < 0x40; i++)
|
||||
sendByte('E' == command ? 0xF7 : 0x7F);
|
||||
|
||||
// Checksum
|
||||
sendByte(crc, false);
|
||||
|
||||
// Tail
|
||||
sendByte(0x0D, false);
|
||||
sendByte(0x0A, false);
|
||||
|
||||
uint8_t status;
|
||||
const char * result = waitAnswer(status);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
return status == 0x00 ? nullptr : STR_FIRMWARE_UPDATE_ERROR;
|
||||
}
|
||||
|
||||
const char * FrskyChipFirmwareUpdate::sendUpgradeData(uint32_t index, uint8_t * data)
|
||||
{
|
||||
crc = 0;
|
||||
|
||||
// Head
|
||||
sendByte(0x7F, false);
|
||||
sendByte(0xFE, false);
|
||||
|
||||
// Addr
|
||||
sendByte(0xFA);
|
||||
|
||||
// Cmd
|
||||
sendByte('W');
|
||||
|
||||
// Packets count
|
||||
sendByte(index >> 8);
|
||||
sendByte(index);
|
||||
|
||||
// Len
|
||||
sendByte(0x00);
|
||||
sendByte(0x40);
|
||||
|
||||
// Data
|
||||
for (uint8_t i = 0; i < 0x40; i++)
|
||||
sendByte(*data++);
|
||||
|
||||
// Checksum
|
||||
sendByte(crc, false);
|
||||
|
||||
// Tail
|
||||
sendByte(0x0D, false);
|
||||
sendByte(0x0A, false);
|
||||
|
||||
uint8_t status;
|
||||
const char * result = waitAnswer(status);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
return status == 0x00 ? nullptr : STR_FIRMWARE_UPDATE_ERROR;
|
||||
}
|
||||
|
||||
const char * FrskyChipFirmwareUpdate::doFlashFirmware(const char * filename, ProgressHandler progressHandler)
|
||||
{
|
||||
const char * result;
|
||||
FIL file;
|
||||
uint8_t buffer[64];
|
||||
UINT count;
|
||||
|
||||
result = startBootloader();
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
if (f_open(&file, filename, FA_READ) != FR_OK) {
|
||||
return STR_NEEDS_FILE;
|
||||
}
|
||||
|
||||
FrSkyFirmwareInformation * information = (FrSkyFirmwareInformation *)buffer;
|
||||
if (f_read(&file, buffer, sizeof(FrSkyFirmwareInformation), &count) != FR_OK || count != sizeof(FrSkyFirmwareInformation)) {
|
||||
f_close(&file);
|
||||
return STR_DEVICE_FILE_ERROR;
|
||||
}
|
||||
|
||||
uint32_t packetsCount = (information->size + sizeof(buffer) - 1) / sizeof(buffer);
|
||||
progressHandler(getBasename(filename), STR_FLASH_WRITE, 0, packetsCount);
|
||||
|
||||
result = sendUpgradeCommand('A', packetsCount);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
uint32_t index = 0;
|
||||
while (1) {
|
||||
progressHandler(getBasename(filename), STR_FLASH_WRITE, index, packetsCount);
|
||||
if (f_read(&file, buffer, sizeof(buffer), &count) != FR_OK) {
|
||||
f_close(&file);
|
||||
return STR_DEVICE_FILE_ERROR;
|
||||
}
|
||||
result = sendUpgradeData(index + 1, buffer);
|
||||
if (result)
|
||||
return result;
|
||||
if (++index == packetsCount)
|
||||
break;
|
||||
}
|
||||
|
||||
f_close(&file);
|
||||
|
||||
return sendUpgradeCommand('E', packetsCount);
|
||||
}
|
||||
|
||||
const char * FrskyChipFirmwareUpdate::flashFirmware(const char * filename, ProgressHandler progressHandler, bool wait)
|
||||
{
|
||||
progressHandler(getBasename(filename), STR_DEVICE_RESET, 0, 0);
|
||||
|
||||
pausePulses();
|
||||
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
uint8_t intPwr = IS_INTERNAL_MODULE_ON();
|
||||
INTERNAL_MODULE_OFF();
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_EXTERNAL_MODULE)
|
||||
uint8_t extPwr = IS_EXTERNAL_MODULE_ON();
|
||||
EXTERNAL_MODULE_OFF();
|
||||
#endif
|
||||
|
||||
#if defined(SPORT_UPDATE_PWR_GPIO)
|
||||
uint8_t spuPwr = IS_SPORT_UPDATE_POWER_ON();
|
||||
SPORT_UPDATE_POWER_OFF();
|
||||
#endif
|
||||
|
||||
if (wait) {
|
||||
/* wait 2s off */
|
||||
watchdogSuspend(1000 /*10s*/);
|
||||
RTOS_WAIT_MS(2000);
|
||||
}
|
||||
|
||||
telemetryInit(PROTOCOL_TELEMETRY_FRSKY_SPORT);
|
||||
|
||||
const char * result = doFlashFirmware(filename, progressHandler);
|
||||
|
||||
AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1);
|
||||
BACKLIGHT_ENABLE();
|
||||
|
||||
if (result) {
|
||||
POPUP_WARNING(STR_FIRMWARE_UPDATE_ERROR, result);
|
||||
}
|
||||
else {
|
||||
POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS);
|
||||
}
|
||||
|
||||
/* wait 2s off */
|
||||
watchdogSuspend(1000 /*10s*/);
|
||||
RTOS_WAIT_MS(2000);
|
||||
|
||||
#if defined(HARDWARE_INTERNAL_MODULE)
|
||||
if (intPwr) {
|
||||
INTERNAL_MODULE_ON();
|
||||
setupPulsesInternalModule();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HARDWARE_EXTERNAL_MODULE)
|
||||
if (extPwr) {
|
||||
EXTERNAL_MODULE_ON();
|
||||
setupPulsesExternalModule();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SPORT_UPDATE_PWR_GPIO)
|
||||
if (spuPwr) {
|
||||
SPORT_UPDATE_POWER_ON();
|
||||
}
|
||||
#endif
|
||||
|
||||
resumePulses();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user