B&W LCD receiver ID improvement (#5018)
[opentx.git] / radio / src / io / frsky_sport.cpp
blob593570e2436a529c7cdb044a532b1230b1ca5e21
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"
23 #if defined(STM32)
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 enum SportUpdateState {
37 SPORT_IDLE,
38 SPORT_POWERUP_REQ,
39 SPORT_POWERUP_ACK,
40 SPORT_VERSION_REQ,
41 SPORT_VERSION_ACK,
42 SPORT_DATA_TRANSFER,
43 SPORT_DATA_REQ,
44 SPORT_COMPLETE,
45 SPORT_FAIL
48 uint8_t sportUpdateState = SPORT_IDLE;
49 uint32_t sportUpdateAddr = 0;
51 void sportOutputPushByte(uint8_t byte)
53 if (byte == 0x7E || byte == 0x7D) {
54 telemetryOutputPushByte(0x7D);
55 telemetryOutputPushByte(0x20 ^ byte);
57 else {
58 telemetryOutputPushByte(byte);
62 bool isSportOutputBufferAvailable()
64 return (outputTelemetryBufferSize == 0 && outputTelemetryBufferTrigger == 0x7E);
67 // TODO merge it with S.PORT update function when finished
68 void sportOutputPushPacket(SportTelemetryPacket * packet)
70 uint16_t crc = 0;
72 for (uint8_t i=1; i<sizeof(SportTelemetryPacket); i++) {
73 uint8_t byte = packet->raw[i];
74 sportOutputPushByte(byte);
75 crc += byte; // 0-1FF
76 crc += crc >> 8; // 0-100
77 crc &= 0x00ff;
80 telemetryOutputPushByte(0xFF-crc);
81 telemetryOutputSetTrigger(packet->raw[0]); // physicalId
84 void sportProcessUpdatePacket(uint8_t * packet)
86 if (packet[0]==0x5E && packet[1]==0x50) {
87 switch (packet[2]) {
88 case PRIM_ACK_POWERUP :
89 if (sportUpdateState == SPORT_POWERUP_REQ) {
90 sportUpdateState = SPORT_POWERUP_ACK;
92 break;
94 case PRIM_ACK_VERSION:
95 if (sportUpdateState == SPORT_VERSION_REQ) {
96 sportUpdateState = SPORT_VERSION_ACK;
97 // SportVersion[0] = packet[3] ;
98 // SportVersion[1] = packet[4] ;
99 // SportVersion[2] = packet[5] ;
100 // SportVersion[3] = packet[6] ;
101 // SportVerValid = 1 ;
103 break;
105 case PRIM_REQ_DATA_ADDR :
106 if (sportUpdateState == SPORT_DATA_TRANSFER) {
107 sportUpdateAddr = *((uint32_t *)(&packet[3]));
108 sportUpdateState = SPORT_DATA_REQ;
110 break;
112 case PRIM_END_DOWNLOAD :
113 sportUpdateState = SPORT_COMPLETE ;
114 break;
116 case PRIM_DATA_CRC_ERR :
117 sportUpdateState = SPORT_FAIL ;
118 break;
123 bool sportWaitState(SportUpdateState state, int timeout)
125 #if defined(SIMU)
126 SIMU_SLEEP_NORET(1);
127 return true;
128 #else
129 watchdogSuspend(timeout / 10);
130 for (int i=timeout/2; i>=0; i--) {
131 uint8_t byte ;
132 while (telemetryGetByte(&byte)) {
133 processFrskyTelemetryData(byte);
135 if (sportUpdateState == state) {
136 return true;
138 else if (sportUpdateState == SPORT_FAIL) {
139 return false;
141 CoTickDelay(1);
143 return false;
144 #endif
147 void sportClearPacket(uint8_t * packet)
149 memset(packet+2, 0, 6);
152 // TODO merge this function
153 void sportWritePacket(uint8_t * packet)
155 uint8_t * ptr = outputTelemetryBuffer;
156 *ptr++ = 0x7E;
157 *ptr++ = 0xFF;
158 packet[7] = crc16(packet, 7);
159 for (int i=0; i<8; i++) {
160 if (packet[i] == 0x7E || packet[i] == 0x7D) {
161 *ptr++ = 0x7D;
162 *ptr++ = 0x20 ^ packet[i];
164 else {
165 *ptr++ = packet[i];
168 sportSendBuffer(outputTelemetryBuffer, ptr-outputTelemetryBuffer);
171 const char * sportUpdatePowerOn(ModuleIndex module)
173 uint8_t packet[8];
175 sportUpdateState = SPORT_POWERUP_REQ;
176 sportWaitState(SPORT_IDLE, 500); // Clear the fifo
178 telemetryInit(PROTOCOL_FRSKY_SPORT);
180 #if defined(PCBTARANIS) || defined(PCBHORUS)
181 if (module == INTERNAL_MODULE)
182 INTERNAL_MODULE_ON();
183 else
184 SPORT_UPDATE_POWER_ON();
185 #endif
187 sportWaitState(SPORT_IDLE, 50); // Clear the fifo
189 for (int i=0; i<10; i++) {
190 // max 10 attempts
191 sportClearPacket(packet);
192 packet[0] = 0x50 ;
193 packet[1] = PRIM_REQ_POWERUP;
194 sportWritePacket(packet);
195 if (sportWaitState(SPORT_POWERUP_ACK, 100))
196 return NULL;
199 if (telemetryProtocol != PROTOCOL_FRSKY_SPORT) {
200 return TR("Not responding", "Not S.Port 1");
203 if (!IS_FRSKY_SPORT_PROTOCOL()) {
204 return TR("Not responding", "Not S.Port 2");
206 #if defined(PCBX7)
207 if (IS_PCBREV_40()) {
208 return TR("Bottom pin no resp", "Bottom pin not responding");
210 else {
211 return TR("Module pin no resp", "Module pin not responding");
213 #else
214 return TR("Not responding", "Module not responding");
215 #endif
218 const char * sportUpdateReqVersion()
220 uint8_t packet[8];
221 sportWaitState(SPORT_IDLE, 20); // Clear the fifo
222 sportUpdateState = SPORT_VERSION_REQ;
223 for (int i=0; i<10; i++) {
224 // max 10 attempts
225 sportClearPacket(packet) ;
226 packet[0] = 0x50 ;
227 packet[1] = PRIM_REQ_VERSION ;
228 sportWritePacket(packet);
229 if (sportWaitState(SPORT_VERSION_ACK, 200))
230 return NULL;
232 return "Version request failed";
235 const char * sportUpdateUploadFile(const char *filename)
237 FIL file;
238 uint32_t buffer[1024/4];
239 UINT count;
240 uint8_t packet[8];
242 if (f_open(&file, filename, FA_READ) != FR_OK) {
243 return "Error opening file";
246 sportWaitState(SPORT_IDLE, 200); // Clear the fifo
247 sportUpdateState = SPORT_DATA_TRANSFER;
248 sportClearPacket(packet) ;
249 packet[0] = 0x50 ;
250 packet[1] = PRIM_CMD_DOWNLOAD ;
251 // Stop here for testing
252 sportWritePacket(packet);
254 while(1) {
255 if (f_read(&file, buffer, 1024, &count) != FR_OK) {
256 f_close(&file);
257 return "Error reading file";
260 count >>= 2;
262 for (UINT i=0; i<count; i++) {
263 if (!sportWaitState(SPORT_DATA_REQ, 2000)) {
264 return "Module refused data";
266 packet[0] = 0x50 ;
267 packet[1] = PRIM_DATA_WORD ;
268 packet[6] = sportUpdateAddr & 0x000000FF;
269 uint32_t offset = ( sportUpdateAddr & 1023 ) >> 2; // 32 bit word offset into buffer
270 uint32_t *data = (uint32_t *)(&packet[2]);
271 *data = buffer[offset];
272 sportUpdateState = SPORT_DATA_TRANSFER,
273 sportWritePacket(packet);
274 if (i==0) {
275 drawProgressBar(STR_WRITING, file.fptr, file.obj.objsize);
279 if (count < 256) {
280 f_close(&file);
281 return NULL;
286 const char * sportUpdateEnd()
288 uint8_t packet[8];
289 if (!sportWaitState(SPORT_DATA_REQ, 2000))
290 return "Module refused data";
291 sportClearPacket(packet);
292 packet[0] = 0x50 ;
293 packet[1] = PRIM_DATA_EOF;
294 sportWritePacket(packet);
295 if (!sportWaitState(SPORT_COMPLETE, 2000)) {
296 return "Module rejected firmware";
298 return NULL;
301 void sportFlashDevice(ModuleIndex module, const char * filename)
303 pausePulses();
305 #if defined(PCBTARANIS) || defined(PCBHORUS)
306 uint8_t intPwr = IS_INTERNAL_MODULE_ON();
307 uint8_t extPwr = IS_EXTERNAL_MODULE_ON();
308 INTERNAL_MODULE_OFF();
309 EXTERNAL_MODULE_OFF();
311 /* wait 2s off */
312 watchdogSuspend(2000);
313 CoTickDelay(1000);
314 #endif
316 const char * result = sportUpdatePowerOn(module);
317 if (!result) result = sportUpdateReqVersion();
318 if (!result) result = sportUpdateUploadFile(filename);
319 if (!result) result = sportUpdateEnd();
321 if (result) {
322 POPUP_WARNING(STR_FIRMWARE_UPDATE_ERROR);
323 SET_WARNING_INFO(result, strlen(result), 0);
326 #if defined(PCBTARANIS) || defined(PCBHORUS)
327 INTERNAL_MODULE_OFF();
328 SPORT_UPDATE_POWER_OFF();
329 #endif
331 sportWaitState(SPORT_IDLE, 500); // Clear the fifo
333 #if defined(PCBTARANIS) || defined(PCBHORUS)
334 if (intPwr)
335 INTERNAL_MODULE_ON();
336 if (extPwr)
337 EXTERNAL_MODULE_ON();
338 #endif
340 sportUpdateState = SPORT_IDLE;
342 resumePulses();
344 #endif
346 void sportProcessPacket(uint8_t * packet)
348 #if defined(STM32)
349 if (sportUpdateState != SPORT_IDLE) {
350 sportProcessUpdatePacket(packet); // Uses different chksum
351 return;
353 #endif
355 sportProcessTelemetryPacket(packet);