Various fixes around Companion trainer mode (#7116)
[opentx.git] / radio / src / io / frsky_firmware_update.cpp
blob1dca3b5a2290c77dd6888e5b120aee964a0833c6
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
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.
21 #include "opentx.h"
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)
38 FIL file;
39 UINT count;
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)) {
46 f_close(&file);
47 return "Error reading file";
50 uint32_t size = f_size(&file);
51 f_close(&file);
53 if (data.headerVersion != 1 && data.fourcc != 0x4B535246) {
54 return "Wrong format";
57 if (size != sizeof(data) + data.size) {
58 return "Wrong size";
61 return nullptr;
64 void FrskyDeviceFirmwareUpdate::processFrame(const uint8_t * frame)
66 if (frame[0] == 0x5E && frame[1] == 0x50) {
67 switch (frame[2]) {
68 case PRIM_ACK_POWERUP :
69 if (state == SPORT_POWERUP_REQ) {
70 state = SPORT_POWERUP_ACK;
72 break;
74 case PRIM_ACK_VERSION:
75 if (state == SPORT_VERSION_REQ) {
76 state = SPORT_VERSION_ACK;
77 // here we could display the version
79 break;
81 case PRIM_REQ_DATA_ADDR:
82 if (state == SPORT_DATA_TRANSFER) {
83 address = *((uint32_t *)(&frame[3]));
84 state = SPORT_DATA_REQ;
86 break;
88 case PRIM_END_DOWNLOAD :
89 state = SPORT_COMPLETE ;
90 break;
92 case PRIM_DATA_CRC_ERR :
93 state = SPORT_FAIL ;
94 break;
99 #if defined(PCBHORUS)
100 bool FrskyDeviceFirmwareUpdate::readBuffer(uint8_t * buffer, uint8_t count, uint32_t timeout)
102 watchdogSuspend(timeout);
104 switch (module) {
105 case INTERNAL_MODULE:
107 uint32_t elapsed = 0;
108 uint8_t index = 0;
109 while (index < count && elapsed < timeout) {
110 if (intmoduleFifo.pop(buffer[index])) {
111 ++index;
113 else {
114 RTOS_WAIT_MS(1);
115 if (++elapsed == timeout)
116 return false;
119 break;
122 default:
123 break;
126 return true;
128 #endif
130 const uint8_t * FrskyDeviceFirmwareUpdate::readFullDuplexFrame(ModuleFifo & fifo, uint32_t timeout)
132 uint8_t len = 0;
133 bool bytestuff = false;
134 while (len < 10) {
135 uint32_t elapsed = 0;
136 uint8_t byte;
137 while (!fifo.pop(byte)) {
138 RTOS_WAIT_MS(1);
139 if (elapsed++ >= timeout) {
140 return nullptr;
143 if (byte == 0x7D) {
144 bytestuff = true;
145 continue;
147 if (bytestuff) {
148 frame[len] = 0x20 ^ byte;
149 bytestuff = false;
151 else {
152 frame[len] = byte;
154 if (len > 0 || byte == 0x7E) {
155 ++len;
158 return &frame[1];
161 const uint8_t * FrskyDeviceFirmwareUpdate::readHalfDuplexFrame(uint32_t timeout)
163 for (int i=timeout; i>=0; i--) {
164 uint8_t byte ;
165 while (telemetryGetByte(&byte)) {
166 if (pushFrskyTelemetryData(byte)) {
167 return telemetryRxBuffer;
170 RTOS_WAIT_MS(1);
172 return nullptr;
175 const uint8_t * FrskyDeviceFirmwareUpdate::readFrame(uint32_t timeout)
177 RTOS_WAIT_MS(1);
179 switch (module) {
180 #if defined(INTERNAL_MODULE_PXX2)
181 case INTERNAL_MODULE:
182 return readFullDuplexFrame(intmoduleFifo, timeout);
183 #endif
185 default:
186 return readHalfDuplexFrame(timeout);
190 bool FrskyDeviceFirmwareUpdate::waitState(State newState, uint32_t timeout)
192 #if defined(SIMU)
193 UNUSED(state);
194 UNUSED(timeout);
195 static uint8_t pass = 0;
196 if (++pass == 10) {
197 pass = 0;
198 RTOS_WAIT_MS(1);
200 return true;
201 #else
202 watchdogSuspend(timeout / 10);
204 const uint8_t * frame = readFrame(timeout);
205 if (!frame) {
206 return false;
209 processFrame(frame);
210 return state == newState;
211 #endif
214 void FrskyDeviceFirmwareUpdate::startFrame(uint8_t command)
216 frame[0] = 0x50;
217 frame[1] = command;
218 memset(&frame[2], 0, 6);
221 // TODO merge this function
222 void FrskyDeviceFirmwareUpdate::sendFrame()
224 uint8_t * ptr = outputTelemetryBuffer.data;
225 *ptr++ = 0x7E;
226 *ptr++ = 0xFF;
227 frame[7] = crc16(CRC_1021, frame, 7);
228 for (int i=0; i<8; i++) {
229 if (frame[i] == 0x7E || frame[i] == 0x7D) {
230 *ptr++ = 0x7D;
231 *ptr++ = 0x20 ^ frame[i];
233 else {
234 *ptr++ = frame[i];
238 switch (module) {
239 #if defined(INTERNAL_MODULE_PXX2)
240 case INTERNAL_MODULE:
241 return intmoduleSendBuffer(outputTelemetryBuffer.data, ptr - outputTelemetryBuffer.data);
242 #endif
244 default:
245 return sportSendBuffer(outputTelemetryBuffer.data, ptr - outputTelemetryBuffer.data);
249 const char * FrskyDeviceFirmwareUpdate::sendPowerOn()
251 state = SPORT_POWERUP_REQ;
253 RTOS_WAIT_MS(50);
254 telemetryClearFifo();
256 for (int i=0; i<10; i++) {
257 // max 10 attempts
258 startFrame(PRIM_REQ_POWERUP);
259 sendFrame();
260 if (waitState(SPORT_POWERUP_ACK, 100))
261 return nullptr;
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()
277 RTOS_WAIT_MS(20);
278 telemetryClearFifo();
280 state = SPORT_VERSION_REQ;
281 for (int i=0; i<10; i++) {
282 // max 10 attempts
283 startFrame(PRIM_REQ_VERSION) ;
284 sendFrame();
285 if (waitState(SPORT_VERSION_ACK, 100))
286 return nullptr;
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)
298 FIL file;
299 const char * result;
300 FrSkyFirmwareInformation information;
301 UINT count;
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)) {
310 f_close(&file);
311 return "Format error";
314 else {
315 #if defined(PCBHORUS)
316 information.productId = FIRMWARE_ID_XJT;
317 #endif
320 #if defined(PCBHORUS)
321 if (module == INTERNAL_MODULE && information.productId == FIRMWARE_ID_XJT) {
322 INTERNAL_MODULE_ON();
323 RTOS_WAIT_MS(1);
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);
328 f_close(&file);
329 return result;
331 #endif
333 switch (module) {
334 #if defined(INTERNAL_MODULE_PXX2)
335 case INTERNAL_MODULE:
336 intmoduleSerialStart(57600, true, USART_Parity_No, USART_StopBits_1, USART_WordLength_8b);
337 break;
338 #endif
340 default:
341 telemetryInit(PROTOCOL_TELEMETRY_FRSKY_SPORT);
342 break;
345 if (module == INTERNAL_MODULE)
346 INTERNAL_MODULE_ON();
347 else if (module == EXTERNAL_MODULE)
348 EXTERNAL_MODULE_ON();
349 else
350 SPORT_UPDATE_POWER_ON();
352 result = uploadFileNormal(filename, &file);
353 f_close(&file);
354 return result;
357 #if defined(PCBHORUS)
358 const char * FrskyDeviceFirmwareUpdate::uploadFileToHorusXJT(const char * filename, FIL * file)
360 uint32_t buffer[1024 / sizeof(uint32_t)];
361 UINT count;
362 uint8_t frame[8];
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);
378 uint8_t index = 0;
379 while (true) {
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";
392 if (count == 0) {
393 intmoduleSendByte(0xA1);
394 RTOS_WAIT_MS(50);
395 return nullptr;
398 if (count < 1024)
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);
411 index++;
414 #endif
416 const char * FrskyDeviceFirmwareUpdate::uploadFileNormal(const char * filename, FIL * file)
418 uint32_t buffer[1024 / sizeof(uint32_t)];
419 UINT count;
421 const char * result = sendPowerOn();
422 if (result)
423 return result;
425 result = sendReqVersion();
426 if (result)
427 return result;
429 RTOS_WAIT_MS(200);
430 telemetryClearFifo();
432 state = SPORT_DATA_TRANSFER;
433 startFrame(PRIM_CMD_DOWNLOAD);
434 sendFrame();
436 while (true) {
437 if (f_read(file, buffer, 1024, &count) != FR_OK) {
438 return "Error reading file";
441 count >>= 2;
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,
452 sendFrame();
453 if (i == 0) {
454 drawProgressScreen(getBasename(filename), STR_WRITING, file->fptr, file->obj.objsize);
458 if (count < 256) {
459 break;
463 return endTransfer();
466 const char * FrskyDeviceFirmwareUpdate::endTransfer()
468 if (!waitState(SPORT_DATA_REQ, 2000))
469 return "Data refused";
470 startFrame(PRIM_DATA_EOF);
471 sendFrame();
472 if (!waitState(SPORT_COMPLETE, 2000)) {
473 return "Firmware rejected";
475 return nullptr;
478 const char * FrskyDeviceFirmwareUpdate::flashFirmware(const char * filename)
480 pausePulses();
482 #if defined(HARDWARE_INTERNAL_MODULE)
483 uint8_t intPwr = IS_INTERNAL_MODULE_ON();
484 INTERNAL_MODULE_OFF();
485 #endif
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);
494 /* wait 2s off */
495 watchdogSuspend(1000 /*10s*/);
496 RTOS_WAIT_MS(2000);
498 const char * result = doFlashFirmware(filename);
500 AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1 );
501 BACKLIGHT_ENABLE();
503 if (result) {
504 POPUP_WARNING(STR_FIRMWARE_UPDATE_ERROR);
505 SET_WARNING_INFO(result, strlen(result), 0);
507 else {
508 POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS);
511 #if defined(HARDWARE_INTERNAL_MODULE)
512 INTERNAL_MODULE_OFF();
513 #endif
514 EXTERNAL_MODULE_OFF();
515 SPORT_UPDATE_POWER_OFF();
517 /* wait 2s off */
518 watchdogSuspend(500 /*5s*/);
519 RTOS_WAIT_MS(2000);
520 telemetryClearFifo();
522 #if defined(HARDWARE_INTERNAL_MODULE)
523 if (intPwr) {
524 INTERNAL_MODULE_ON();
525 setupPulsesInternalModule();
527 #endif
529 if (extPwr) {
530 EXTERNAL_MODULE_ON();
531 setupPulsesExternalModule();
534 state = SPORT_IDLE;
535 resumePulses();
537 return result;
540 #define CHIP_FIRMWARE_UPDATE_TIMEOUT 20000 /* 20s */
542 const char * FrskyChipFirmwareUpdate::waitAnswer(uint8_t & status)
544 watchdogSuspend(CHIP_FIRMWARE_UPDATE_TIMEOUT);
546 telemetryPortSetDirectionInput();
548 uint8_t buffer[12];
549 for (uint8_t i = 0; i < sizeof(buffer); i++) {
550 uint32_t retry = 0;
551 while (true) {
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)) {
557 i = 0;
558 continue;
560 break;
562 if (++retry == CHIP_FIRMWARE_UPDATE_TIMEOUT) {
563 return "No answer";
565 RTOS_WAIT_MS(1);
568 status = buffer[8];
569 return nullptr;
572 const char * FrskyChipFirmwareUpdate::startBootloader()
574 sportSendByte(0x03);
575 RTOS_WAIT_MS(20);
576 sportSendByte(0x02);
577 RTOS_WAIT_MS(20);
578 sportSendByte(0x01);
580 for (uint8_t i = 0; i < 30; i++)
581 sportSendByte(0x7E);
583 for (uint32_t i = 0; i < 100; i++) {
584 RTOS_WAIT_MS(20);
585 sportSendByte(0x7F);
588 RTOS_WAIT_MS(20);
589 sportSendByte(0xFA);
591 /*for (uint8_t i=0; i < 30; i++)
592 sportSendByte(0x7E);
593 for (uint8_t i=0; i < 50; i++)
594 sportSendByte(0x7F);*/
596 uint8_t status;
597 const char * result = waitAnswer(status);
598 if (result)
599 return result;
601 return status == 0x08 ? nullptr : "Bootloader failed";
604 void FrskyChipFirmwareUpdate::sendByte(uint8_t byte, bool crcFlag)
606 sportSendByte(byte);
607 if (crcFlag) {
608 crc ^= byte;
612 const char * FrskyChipFirmwareUpdate::sendUpgradeCommand(char command, uint32_t packetsCount)
614 crc = 0;
616 // Head
617 sendByte(0x7F, false);
618 sendByte(0xFE, false);
620 // Addr
621 sendByte(0xFA);
623 // Cmd
624 sendByte(command);
626 // Packets count
627 sendByte(packetsCount >> 8);
628 sendByte(packetsCount);
630 // Len
631 sendByte('E' == command ? 0x00 : 0x0C);
632 sendByte(0x40);
634 // Data
635 for (uint8_t i=0; i < 0x40; i++)
636 sendByte('E' == command ? 0xF7 : 0x7F);
638 // Checksum
639 sendByte(crc, false);
641 // Tail
642 sendByte(0x0D, false);
643 sendByte(0x0A, false);
645 uint8_t status;
646 const char * result = waitAnswer(status);
647 if (result)
648 return result;
650 return status == 0x00 ? nullptr : "Upgrade failed";
653 const char * FrskyChipFirmwareUpdate::sendUpgradeData(uint32_t index, uint8_t * data)
655 crc = 0;
657 // Head
658 sendByte(0x7F, false);
659 sendByte(0xFE, false);
661 // Addr
662 sendByte(0xFA);
664 // Cmd
665 sendByte('W');
667 // Packets count
668 sendByte(index >> 8);
669 sendByte(index);
671 // Len
672 sendByte(0x00);
673 sendByte(0x40);
675 // Data
676 for (uint8_t i = 0; i < 0x40; i++)
677 sendByte(*data++);
679 // Checksum
680 sendByte(crc, false);
682 // Tail
683 sendByte(0x0D, false);
684 sendByte(0x0A, false);
686 uint8_t status;
687 const char * result = waitAnswer(status);
688 if (result)
689 return result;
691 return status == 0x00 ? nullptr : "Upgrade failed";
694 const char * FrskyChipFirmwareUpdate::doFlashFirmware(const char * filename)
696 const char * result;
697 FIL file;
698 uint8_t buffer[64];
699 UINT count;
701 result = startBootloader();
702 if (result)
703 return result;
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)) {
711 f_close(&file);
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);
719 if (result)
720 return result;
722 uint32_t index = 0;
723 while (1) {
724 drawProgressScreen(getBasename(filename), STR_FLASH_WRITE, index, packetsCount);
725 if (f_read(&file, buffer, sizeof(buffer), &count) != FR_OK) {
726 f_close(&file);
727 return "Error reading file";
729 result = sendUpgradeData(index + 1, buffer);
730 if (result)
731 return result;
732 if (++index == packetsCount)
733 break;
736 f_close(&file);
738 return sendUpgradeCommand('E', packetsCount);
741 const char * FrskyChipFirmwareUpdate::flashFirmware(const char * filename, bool wait)
743 drawProgressScreen(getBasename(filename), STR_DEVICE_RESET, 0, 0);
745 pausePulses();
747 #if defined(HARDWARE_INTERNAL_MODULE)
748 uint8_t intPwr = IS_INTERNAL_MODULE_ON();
749 INTERNAL_MODULE_OFF();
750 #endif
752 uint8_t extPwr = IS_EXTERNAL_MODULE_ON();
753 EXTERNAL_MODULE_OFF();
755 SPORT_UPDATE_POWER_OFF();
757 if (wait) {
758 /* wait 2s off */
759 watchdogSuspend(1000 /*10s*/);
760 RTOS_WAIT_MS(2000);
763 telemetryInit(PROTOCOL_TELEMETRY_FRSKY_SPORT);
765 const char * result = doFlashFirmware(filename);
767 AUDIO_PLAY(AU_SPECIAL_SOUND_BEEP1);
768 BACKLIGHT_ENABLE();
770 if (result) {
771 POPUP_WARNING(STR_FIRMWARE_UPDATE_ERROR);
772 SET_WARNING_INFO(result, strlen(result), 0);
774 else {
775 POPUP_INFORMATION(STR_FIRMWARE_UPDATE_SUCCESS);
778 /* wait 2s off */
779 watchdogSuspend(1000 /*10s*/);
780 RTOS_WAIT_MS(2000);
782 #if defined(HARDWARE_INTERNAL_MODULE)
783 if (intPwr) {
784 INTERNAL_MODULE_ON();
785 setupPulsesInternalModule();
787 #endif
789 if (extPwr) {
790 EXTERNAL_MODULE_ON();
791 setupPulsesExternalModule();
794 resumePulses();
796 return result;