5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
22 #include "frsky_firmware_update.h"
24 #define PRIM_REQ_POWERUP 0
25 #define PRIM_REQ_VERSION 1
26 #define PRIM_CMD_DOWNLOAD 3
27 #define PRIM_DATA_WORD 4
28 #define PRIM_DATA_EOF 5
30 #define PRIM_ACK_POWERUP 0x80
31 #define PRIM_ACK_VERSION 0x81
32 #define PRIM_REQ_DATA_ADDR 0x82
33 #define PRIM_END_DOWNLOAD 0x83
34 #define PRIM_DATA_CRC_ERR 0x84
36 const char * readFrSkyFirmwareInformation(const char * filename
, FrSkyFirmwareInformation
& data
)
41 if (f_open(&file
, filename
, FA_READ
) != FR_OK
) {
42 return "Error opening file";
45 if (f_read(&file
, &data
, sizeof(data
), &count
) != FR_OK
|| count
!= sizeof(data
)) {
47 return "Error reading file";
50 uint32_t size
= f_size(&file
);
53 if (data
.headerVersion
!= 1 && data
.fourcc
!= 0x4B535246) {
54 return "Wrong format";
57 if (size
!= sizeof(data
) + data
.size
) {
64 void FrskyDeviceFirmwareUpdate::processFrame(const uint8_t * frame
)
66 if (frame
[0] == 0x5E && frame
[1] == 0x50) {
68 case PRIM_ACK_POWERUP
:
69 if (state
== SPORT_POWERUP_REQ
) {
70 state
= SPORT_POWERUP_ACK
;
74 case PRIM_ACK_VERSION
:
75 if (state
== SPORT_VERSION_REQ
) {
76 state
= SPORT_VERSION_ACK
;
77 // here we could display the version
81 case PRIM_REQ_DATA_ADDR
:
82 if (state
== SPORT_DATA_TRANSFER
) {
83 address
= *((uint32_t *)(&frame
[3]));
84 state
= SPORT_DATA_REQ
;
88 case PRIM_END_DOWNLOAD
:
89 state
= SPORT_COMPLETE
;
92 case PRIM_DATA_CRC_ERR
:
100 bool FrskyDeviceFirmwareUpdate::readBuffer(uint8_t * buffer
, uint8_t count
, uint32_t timeout
)
102 watchdogSuspend(timeout
);
105 case INTERNAL_MODULE
:
107 uint32_t elapsed
= 0;
109 while (index
< count
&& elapsed
< timeout
) {
110 if (intmoduleFifo
.pop(buffer
[index
])) {
115 if (++elapsed
== timeout
)
130 const uint8_t * FrskyDeviceFirmwareUpdate::readFullDuplexFrame(ModuleFifo
& fifo
, uint32_t timeout
)
133 bool bytestuff
= false;
135 uint32_t elapsed
= 0;
137 while (!fifo
.pop(byte
)) {
139 if (elapsed
++ >= timeout
) {
148 frame
[len
] = 0x20 ^ byte
;
154 if (len
> 0 || byte
== 0x7E) {
161 const uint8_t * FrskyDeviceFirmwareUpdate::readHalfDuplexFrame(uint32_t timeout
)
163 for (int i
=timeout
; i
>=0; i
--) {
165 while (telemetryGetByte(&byte
)) {
166 if (pushFrskyTelemetryData(byte
)) {
167 return telemetryRxBuffer
;
175 const uint8_t * FrskyDeviceFirmwareUpdate::readFrame(uint32_t timeout
)
180 #if defined(INTERNAL_MODULE_PXX2)
181 case INTERNAL_MODULE
:
182 return readFullDuplexFrame(intmoduleFifo
, timeout
);
186 return readHalfDuplexFrame(timeout
);
190 bool FrskyDeviceFirmwareUpdate::waitState(State newState
, uint32_t timeout
)
195 static uint8_t pass
= 0;
202 watchdogSuspend(timeout
/ 10);
204 const uint8_t * frame
= readFrame(timeout
);
210 return state
== newState
;
214 void FrskyDeviceFirmwareUpdate::startFrame(uint8_t command
)
218 memset(&frame
[2], 0, 6);
221 // TODO merge this function
222 void FrskyDeviceFirmwareUpdate::sendFrame()
224 uint8_t * ptr
= outputTelemetryBuffer
.data
;
227 frame
[7] = crc16(CRC_1021
, frame
, 7);
228 for (int i
=0; i
<8; i
++) {
229 if (frame
[i
] == 0x7E || frame
[i
] == 0x7D) {
231 *ptr
++ = 0x20 ^ frame
[i
];
239 #if defined(INTERNAL_MODULE_PXX2)
240 case INTERNAL_MODULE
:
241 return intmoduleSendBuffer(outputTelemetryBuffer
.data
, ptr
- outputTelemetryBuffer
.data
);
245 return sportSendBuffer(outputTelemetryBuffer
.data
, ptr
- outputTelemetryBuffer
.data
);
249 const char * FrskyDeviceFirmwareUpdate::sendPowerOn()
251 state
= SPORT_POWERUP_REQ
;
254 telemetryClearFifo();
256 for (int i
=0; i
<10; i
++) {
258 startFrame(PRIM_REQ_POWERUP
);
260 if (waitState(SPORT_POWERUP_ACK
, 100))
264 if (telemetryProtocol
!= PROTOCOL_TELEMETRY_FRSKY_SPORT
) {
265 return TR("Not responding", "Not S.Port 1");
268 if (!IS_FRSKY_SPORT_PROTOCOL()) {
269 return TR("Not responding", "Not S.Port 2");
272 return TR("Not responding", "Device not responding");
275 const char * FrskyDeviceFirmwareUpdate::sendReqVersion()
278 telemetryClearFifo();
280 state
= SPORT_VERSION_REQ
;
281 for (int i
=0; i
<10; i
++) {
283 startFrame(PRIM_REQ_VERSION
) ;
285 if (waitState(SPORT_VERSION_ACK
, 100))
288 return "Version request failed";
291 // X12S / X10 IXJT = use TX + RX @ 38400 bauds with BOOTCMD pin inverted
292 // X10 / X10 ISRM = use TX + RX @ 57600 bauds (no BOOTCMD)
293 // X9D / X9D+ / X9E / XLite IXJT = use S.PORT @ 57600 bauds
294 // XLite PRO / X9Lite / X9D+ 2019 ISRM = use TX + RX @ 57600 bauds
296 const char * FrskyDeviceFirmwareUpdate::doFlashFirmware(const char * filename
)
300 FrSkyFirmwareInformation information
;
303 if (f_open(&file
, filename
, FA_READ
) != FR_OK
) {
304 return "Error opening file";
307 const char * ext
= getFileExtension(filename
);
308 if (ext
&& !strcasecmp(ext
, FRSKY_FIRMWARE_EXT
)) {
309 if (f_read(&file
, &information
, sizeof(FrSkyFirmwareInformation
), &count
) != FR_OK
|| count
!= sizeof(FrSkyFirmwareInformation
)) {
311 return "Format error";
315 #if defined(PCBHORUS)
316 information
.productId
= FIRMWARE_ID_XJT
;
320 #if defined(PCBHORUS)
321 if (module
== INTERNAL_MODULE
&& information
.productId
== FIRMWARE_ID_XJT
) {
322 INTERNAL_MODULE_ON();
324 intmoduleSerialStart(38400, true, USART_Parity_No
, USART_StopBits_1
, USART_WordLength_8b
);
325 GPIO_SetBits(INTMODULE_BOOTCMD_GPIO
, INTMODULE_BOOTCMD_GPIO_PIN
);
326 result
= uploadFileToHorusXJT(filename
, &file
);
327 GPIO_ResetBits(INTMODULE_BOOTCMD_GPIO
, INTMODULE_BOOTCMD_GPIO_PIN
);
334 #if defined(INTERNAL_MODULE_PXX2)
335 case INTERNAL_MODULE
:
336 intmoduleSerialStart(57600, true, USART_Parity_No
, USART_StopBits_1
, USART_WordLength_8b
);
341 telemetryInit(PROTOCOL_TELEMETRY_FRSKY_SPORT
);
345 if (module
== INTERNAL_MODULE
)
346 INTERNAL_MODULE_ON();
347 else if (module
== EXTERNAL_MODULE
)
348 EXTERNAL_MODULE_ON();
350 SPORT_UPDATE_POWER_ON();
352 result
= uploadFileNormal(filename
, &file
);
357 #if defined(PCBHORUS)
358 const char * FrskyDeviceFirmwareUpdate::uploadFileToHorusXJT(const char * filename
, FIL
* file
)
360 uint32_t buffer
[1024 / sizeof(uint32_t)];
364 if (!readBuffer(frame
, 8, 100) || frame
[0] != 0x01) {
365 return TR("Not responding", "Device not responding");
368 intmoduleSendByte(0x81);
369 readBuffer(frame
, 1, 100);
371 if (!readBuffer(frame
, 8, 100) || frame
[0] != 0x02) {
372 return TR("Not responding", "Device not responding");
375 intmoduleSendByte(0x82);
376 readBuffer(frame
, 1, 100);
380 drawProgressScreen(getBasename(filename
), STR_WRITING
, file
->fptr
, file
->obj
.objsize
);
382 if (f_read(file
, buffer
, 1024, &count
) != FR_OK
) {
383 return "Error reading file";
386 if (!readBuffer(frame
, 2, 100))
387 return "Data refused";
389 if (frame
[0] != 0x11 || frame
[1] != index
)
390 return "Wrong request";
393 intmoduleSendByte(0xA1);
399 memset(((uint8_t *)buffer
) + count
, 0, 1024 - count
);
401 intmoduleSendByte(frame
[0] + 0x80);
402 intmoduleSendByte(frame
[1]);
404 uint16_t crc_16
= crc16(CRC_1189
, (uint8_t *)buffer
, 1024, crc16(CRC_1189
, &frame
[1], 1));
405 for (size_t i
= 0; i
< sizeof(buffer
); i
++) {
406 intmoduleSendByte(((uint8_t *)buffer
)[i
]);
408 intmoduleSendByte(crc_16
>> 8);
409 intmoduleSendByte(crc_16
);
416 const char * FrskyDeviceFirmwareUpdate::uploadFileNormal(const char * filename
, FIL
* file
)
418 uint32_t buffer
[1024 / sizeof(uint32_t)];
421 const char * result
= sendPowerOn();
425 result
= sendReqVersion();
430 telemetryClearFifo();
432 state
= SPORT_DATA_TRANSFER
;
433 startFrame(PRIM_CMD_DOWNLOAD
);
437 if (f_read(file
, buffer
, 1024, &count
) != FR_OK
) {
438 return "Error reading file";
443 for (uint32_t i
=0; i
<count
; i
++) {
444 if (!waitState(SPORT_DATA_REQ
, 2000)) {
445 return "Data refused";
447 startFrame(PRIM_DATA_WORD
);
448 uint32_t offset
= (address
& 1023) >> 2; // 32 bit word offset into buffer
449 *((uint32_t *)(frame
+ 2)) = buffer
[offset
];
450 frame
[6] = address
& 0x000000FF;
451 state
= SPORT_DATA_TRANSFER
,
454 drawProgressScreen(getBasename(filename
), STR_WRITING
, file
->fptr
, file
->obj
.objsize
);
463 return endTransfer();
466 const char * FrskyDeviceFirmwareUpdate::endTransfer()
468 if (!waitState(SPORT_DATA_REQ
, 2000))
469 return "Data refused";
470 startFrame(PRIM_DATA_EOF
);
472 if (!waitState(SPORT_COMPLETE
, 2000)) {
473 return "Firmware rejected";
478 const char * FrskyDeviceFirmwareUpdate::flashFirmware(const char * filename
)
482 #if defined(HARDWARE_INTERNAL_MODULE)
483 uint8_t intPwr
= IS_INTERNAL_MODULE_ON();
484 INTERNAL_MODULE_OFF();
487 uint8_t extPwr
= IS_EXTERNAL_MODULE_ON();
488 EXTERNAL_MODULE_OFF();
490 SPORT_UPDATE_POWER_OFF();
492 drawProgressScreen(getBasename(filename
), STR_DEVICE_RESET
, 0, 0);
495 watchdogSuspend(1000 /*10s*/);
498 const char * result
= doFlashFirmware(filename
);
500 AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1
);
504 POPUP_WARNING(STR_FIRMWARE_UPDATE_ERROR
);
505 SET_WARNING_INFO(result
, strlen(result
), 0);
508 POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS
);
511 #if defined(HARDWARE_INTERNAL_MODULE)
512 INTERNAL_MODULE_OFF();
514 EXTERNAL_MODULE_OFF();
515 SPORT_UPDATE_POWER_OFF();
518 watchdogSuspend(500 /*5s*/);
520 telemetryClearFifo();
522 #if defined(HARDWARE_INTERNAL_MODULE)
524 INTERNAL_MODULE_ON();
525 setupPulsesInternalModule();
530 EXTERNAL_MODULE_ON();
531 setupPulsesExternalModule();
540 #define CHIP_FIRMWARE_UPDATE_TIMEOUT 20000 /* 20s */
542 const char * FrskyChipFirmwareUpdate::waitAnswer(uint8_t & status
)
544 watchdogSuspend(CHIP_FIRMWARE_UPDATE_TIMEOUT
);
546 telemetryPortSetDirectionInput();
549 for (uint8_t i
= 0; i
< sizeof(buffer
); i
++) {
552 if (telemetryGetByte(&buffer
[i
])) {
553 if ((i
== 0 && buffer
[0] != 0x7F) ||
554 (i
== 1 && buffer
[1] != 0xFE) ||
555 (i
== 10 && buffer
[10] != 0x0D) ||
556 (i
== 11 && buffer
[11] != 0x0A)) {
562 if (++retry
== CHIP_FIRMWARE_UPDATE_TIMEOUT
) {
572 const char * FrskyChipFirmwareUpdate::startBootloader()
580 for (uint8_t i
= 0; i
< 30; i
++)
583 for (uint32_t i
= 0; i
< 100; i
++) {
591 /*for (uint8_t i=0; i < 30; i++)
593 for (uint8_t i=0; i < 50; i++)
594 sportSendByte(0x7F);*/
597 const char * result
= waitAnswer(status
);
601 return status
== 0x08 ? nullptr : "Bootloader failed";
604 void FrskyChipFirmwareUpdate::sendByte(uint8_t byte
, bool crcFlag
)
612 const char * FrskyChipFirmwareUpdate::sendUpgradeCommand(char command
, uint32_t packetsCount
)
617 sendByte(0x7F, false);
618 sendByte(0xFE, false);
627 sendByte(packetsCount
>> 8);
628 sendByte(packetsCount
);
631 sendByte('E' == command
? 0x00 : 0x0C);
635 for (uint8_t i
=0; i
< 0x40; i
++)
636 sendByte('E' == command
? 0xF7 : 0x7F);
639 sendByte(crc
, false);
642 sendByte(0x0D, false);
643 sendByte(0x0A, false);
646 const char * result
= waitAnswer(status
);
650 return status
== 0x00 ? nullptr : "Upgrade failed";
653 const char * FrskyChipFirmwareUpdate::sendUpgradeData(uint32_t index
, uint8_t * data
)
658 sendByte(0x7F, false);
659 sendByte(0xFE, false);
668 sendByte(index
>> 8);
676 for (uint8_t i
= 0; i
< 0x40; i
++)
680 sendByte(crc
, false);
683 sendByte(0x0D, false);
684 sendByte(0x0A, false);
687 const char * result
= waitAnswer(status
);
691 return status
== 0x00 ? nullptr : "Upgrade failed";
694 const char * FrskyChipFirmwareUpdate::doFlashFirmware(const char * filename
)
701 result
= startBootloader();
705 if (f_open(&file
, filename
, FA_READ
) != FR_OK
) {
706 return "Error opening file";
709 FrSkyFirmwareInformation
* information
= (FrSkyFirmwareInformation
*)buffer
;
710 if (f_read(&file
, buffer
, sizeof(FrSkyFirmwareInformation
), &count
) != FR_OK
|| count
!= sizeof(FrSkyFirmwareInformation
)) {
712 return "Format error";
715 uint32_t packetsCount
= (information
->size
+ sizeof(buffer
) - 1) / sizeof(buffer
);
716 drawProgressScreen(getBasename(filename
), STR_FLASH_WRITE
, 0, packetsCount
);
718 result
= sendUpgradeCommand('A', packetsCount
);
724 drawProgressScreen(getBasename(filename
), STR_FLASH_WRITE
, index
, packetsCount
);
725 if (f_read(&file
, buffer
, sizeof(buffer
), &count
) != FR_OK
) {
727 return "Error reading file";
729 result
= sendUpgradeData(index
+ 1, buffer
);
732 if (++index
== packetsCount
)
738 return sendUpgradeCommand('E', packetsCount
);
741 const char * FrskyChipFirmwareUpdate::flashFirmware(const char * filename
, bool wait
)
743 drawProgressScreen(getBasename(filename
), STR_DEVICE_RESET
, 0, 0);
747 #if defined(HARDWARE_INTERNAL_MODULE)
748 uint8_t intPwr
= IS_INTERNAL_MODULE_ON();
749 INTERNAL_MODULE_OFF();
752 uint8_t extPwr
= IS_EXTERNAL_MODULE_ON();
753 EXTERNAL_MODULE_OFF();
755 SPORT_UPDATE_POWER_OFF();
759 watchdogSuspend(1000 /*10s*/);
763 telemetryInit(PROTOCOL_TELEMETRY_FRSKY_SPORT
);
765 const char * result
= doFlashFirmware(filename
);
767 AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1
);
771 POPUP_WARNING(STR_FIRMWARE_UPDATE_ERROR
);
772 SET_WARNING_INFO(result
, strlen(result
), 0);
775 POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS
);
779 watchdogSuspend(1000 /*10s*/);
782 #if defined(HARDWARE_INTERNAL_MODULE)
784 INTERNAL_MODULE_ON();
785 setupPulsesInternalModule();
790 EXTERNAL_MODULE_ON();
791 setupPulsesExternalModule();