hotfix: allow arming in Stabilized 4,5,6
[librepilot.git] / flight / libraries / op_dfu.c
blobe952a886c623d8f04f0ce25929af438e759d424d
1 /**
2 ******************************************************************************
3 * @addtogroup CopterControlBL CopterControl BootLoader
4 * @brief These files contain the code to the CopterControl Bootloader.
6 * @{
7 * @file op_dfu.c
8 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
9 * @brief This file contains the DFU commands handling code
10 * @see The GNU Public License (GPL) Version 3
12 *****************************************************************************/
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * for more details.
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 /* Includes ------------------------------------------------------------------*/
30 #include "pios.h"
31 #include <stdbool.h>
32 #include "op_dfu.h"
33 #include "pios_bl_helper.h"
34 #include "pios_com_msg.h"
35 #include <pios_board_info.h>
36 // programmable devices
37 Device devicesTable[10];
38 uint8_t numberOfDevices = 0;
40 DFUProgType currentProgrammingDestination; // flash, flash_trough spi
41 uint8_t currentDeviceCanRead;
42 uint8_t currentDeviceCanWrite;
43 Device currentDevice;
45 uint8_t Buffer[64];
46 uint8_t echoBuffer[64];
47 uint8_t SendBuffer[64];
48 uint8_t Command = 0;
49 uint8_t EchoReqFlag = 0;
50 uint8_t EchoAnsFlag = 0;
51 uint8_t StartFlag = 0;
52 uint32_t Aditionals = 0;
53 uint32_t SizeOfTransfer = 0;
54 uint32_t Expected_CRC = 0;
55 uint8_t SizeOfLastPacket = 0;
56 uint32_t Next_Packet = 0;
57 uint8_t TransferType;
58 uint32_t Count = 0;
59 uint32_t Data;
60 uint8_t Data0;
61 uint8_t Data1;
62 uint8_t Data2;
63 uint8_t Data3;
64 uint32_t Opt[3];
66 // Download vars
67 uint32_t downSizeOfLastPacket = 0;
68 uint32_t downPacketTotal = 0;
69 uint32_t downPacketCurrent = 0;
70 DFUTransfer downType = 0;
71 /* Extern variables ----------------------------------------------------------*/
72 extern DFUStates DeviceState;
73 extern uint8_t JumpToApp;
74 /* Private function prototypes -----------------------------------------------*/
75 /* Private functions ---------------------------------------------------------*/
76 void sendData(uint8_t *buf, uint16_t size);
77 uint32_t CalcFirmCRC(void);
79 void DataDownload(__attribute__((unused)) DownloadAction action)
81 if ((DeviceState == downloading)) {
82 uint8_t packetSize;
83 uint32_t offset;
84 uint32_t partoffset;
85 SendBuffer[0] = 0x01;
86 SendBuffer[1] = Download;
87 SendBuffer[2] = downPacketCurrent >> 24;
88 SendBuffer[3] = downPacketCurrent >> 16;
89 SendBuffer[4] = downPacketCurrent >> 8;
90 SendBuffer[5] = downPacketCurrent;
91 if (downPacketCurrent == downPacketTotal - 1) {
92 packetSize = downSizeOfLastPacket;
93 } else {
94 packetSize = 14;
96 for (uint8_t x = 0; x < packetSize; ++x) {
97 partoffset = (downPacketCurrent * 14 * 4) + (x * 4);
98 offset = baseOfAdressType(downType) + partoffset;
99 if (!flash_read(SendBuffer + (6 + x * 4), offset,
100 currentProgrammingDestination)) {
101 DeviceState = Last_operation_failed;
104 downPacketCurrent = downPacketCurrent + 1;
105 if (downPacketCurrent > downPacketTotal - 1) {
106 DeviceState = Last_operation_Success;
107 Aditionals = (uint32_t)Download;
109 sendData(SendBuffer + 1, 63);
112 void processComand(uint8_t *xReceive_Buffer)
114 Command = xReceive_Buffer[COMMAND];
115 #ifdef DEBUG_SSP
116 char str[63] = { 0 };
117 sprintf(str, "Received COMMAND:%d|", Command);
118 PIOS_COM_SendString(PIOS_COM_TELEM_USB, str);
119 #endif
120 EchoReqFlag = (Command >> 7);
121 EchoAnsFlag = (Command >> 6) & 0x01;
122 StartFlag = (Command >> 5) & 0x01;
123 Count = xReceive_Buffer[COUNT] << 24;
124 Count += xReceive_Buffer[COUNT + 1] << 16;
125 Count += xReceive_Buffer[COUNT + 2] << 8;
126 Count += xReceive_Buffer[COUNT + 3];
128 Data = xReceive_Buffer[DATA] << 24;
129 Data += xReceive_Buffer[DATA + 1] << 16;
130 Data += xReceive_Buffer[DATA + 2] << 8;
131 Data += xReceive_Buffer[DATA + 3];
132 Data0 = xReceive_Buffer[DATA];
133 Data1 = xReceive_Buffer[DATA + 1];
134 Data2 = xReceive_Buffer[DATA + 2];
135 Data3 = xReceive_Buffer[DATA + 3];
136 for (uint32_t i = 0; i < 3; i++) {
137 Opt[i] = xReceive_Buffer[DATA + 4 * (i + 1)] << 24 |
138 xReceive_Buffer[DATA + 4 * (i + 1) + 1] << 16 |
139 xReceive_Buffer[DATA + 4 * (i + 1) + 2] << 8 |
140 xReceive_Buffer[DATA + 4 * (i + 1) + 3];
143 Command = Command & 0b00011111;
145 if (EchoReqFlag == 1) {
146 memcpy(echoBuffer, xReceive_Buffer, 64);
148 switch (Command) {
149 case EnterDFU:
150 if (((DeviceState == BLidle) && (Data0 < numberOfDevices))
151 || (DeviceState == DFUidle)) {
152 if (Data0 > 0) {
153 OPDfuIni(true);
155 DeviceState = DFUidle;
156 currentProgrammingDestination = devicesTable[Data0].programmingType;
157 currentDeviceCanRead = devicesTable[Data0].readWriteFlags & 0x01;
158 currentDeviceCanWrite = devicesTable[Data0].readWriteFlags >> 1
159 & 0x01;
160 currentDevice = devicesTable[Data0];
161 uint8_t result = 0;
162 switch (currentProgrammingDestination) {
163 case Self_flash:
164 result = PIOS_BL_HELPER_FLASH_Ini();
165 break;
166 case Remote_flash_via_spi:
167 result = true;
168 break;
169 default:
170 DeviceState = Last_operation_failed;
171 Aditionals = (uint16_t)Command;
173 if (result != 1) {
174 DeviceState = Last_operation_failed;
175 Aditionals = (uint32_t)Command;
178 break;
179 case Upload:
180 if ((DeviceState == DFUidle) || (DeviceState == uploading)) {
181 if ((StartFlag == 1) && (Next_Packet == 0)) {
182 TransferType = Data0;
183 SizeOfTransfer = Count;
184 Next_Packet = 1;
185 Expected_CRC = Data2 << 24;
186 Expected_CRC += Data3 << 16;
187 Expected_CRC += xReceive_Buffer[DATA + 4] << 8;
188 Expected_CRC += xReceive_Buffer[DATA + 5];
189 SizeOfLastPacket = Data1;
191 if (isBiggerThanAvailable(TransferType, (SizeOfTransfer - 1)
192 * 14 * 4 + SizeOfLastPacket * 4) == true) {
193 DeviceState = outsideDevCapabilities;
194 Aditionals = (uint32_t)Command;
195 } else {
196 uint8_t result = 1;
197 if (TransferType == FW) {
198 switch (currentProgrammingDestination) {
199 case Self_flash:
200 result = PIOS_BL_HELPER_FLASH_Start();
201 break;
202 case Remote_flash_via_spi:
203 result = false;
204 break;
205 default:
206 break;
209 if (result != 1) {
210 DeviceState = Last_operation_failed;
211 Aditionals = (uint32_t)Command;
212 } else {
213 DeviceState = uploading;
216 } else if ((StartFlag != 1) && (Next_Packet != 0)) {
217 if (Count > SizeOfTransfer) {
218 DeviceState = too_many_packets;
219 Aditionals = Count;
220 } else if (Count == Next_Packet - 1) {
221 uint8_t numberOfWords = 14;
222 if (Count == SizeOfTransfer - 1) { // is this the last packet?
223 numberOfWords = SizeOfLastPacket;
225 uint8_t result = 0;
226 uint32_t offset;
227 uint32_t aux;;
228 switch (currentProgrammingDestination) {
229 case Self_flash:
230 for (uint8_t x = 0; x < numberOfWords; ++x) {
231 offset = 4 * x;
232 Data = xReceive_Buffer[DATA + offset] << 24;
233 Data += xReceive_Buffer[DATA + 1 + offset] << 16;
234 Data += xReceive_Buffer[DATA + 2 + offset] << 8;
235 Data += xReceive_Buffer[DATA + 3 + offset];
236 aux = baseOfAdressType(TransferType) + (uint32_t)(
237 Count * 14 * 4 + x * 4);
238 result = 0;
239 for (int retry = 0; retry < MAX_WRI_RETRYS; ++retry) {
240 if (result == 0) {
241 result = (FLASH_ProgramWord(aux, Data)
242 == FLASH_COMPLETE) ? 1 : 0;
246 break;
247 case Remote_flash_via_spi:
248 result = false; // No support for this for the OPLink Mini
249 break;
250 default:
251 result = 0;
252 break;
254 if (result != 1) {
255 DeviceState = Last_operation_failed;
256 Aditionals = (uint32_t)Command;
259 ++Next_Packet;
260 } else {
261 DeviceState = wrong_packet_received;
262 Aditionals = Count;
264 } else {
265 DeviceState = Last_operation_failed;
266 Aditionals = (uint32_t)Command;
269 break;
270 case Req_Capabilities:
271 OPDfuIni(true);
272 Buffer[0] = 0x01;
273 Buffer[1] = Rep_Capabilities;
274 if (Data0 == 0) {
275 Buffer[2] = 0;
276 Buffer[3] = 0;
277 Buffer[4] = 0;
278 Buffer[5] = 0;
279 Buffer[6] = 0;
280 Buffer[7] = numberOfDevices;
281 uint16_t WRFlags = 0;
282 for (int x = 0; x < numberOfDevices; ++x) {
283 WRFlags = ((devicesTable[x].readWriteFlags << (x * 2))
284 | WRFlags);
286 Buffer[8] = WRFlags >> 8;
287 Buffer[9] = WRFlags;
288 } else {
289 Buffer[2] = devicesTable[Data0 - 1].sizeOfCode >> 24;
290 Buffer[3] = devicesTable[Data0 - 1].sizeOfCode >> 16;
291 Buffer[4] = devicesTable[Data0 - 1].sizeOfCode >> 8;
292 Buffer[5] = devicesTable[Data0 - 1].sizeOfCode;
293 Buffer[6] = Data0;
294 Buffer[7] = devicesTable[Data0 - 1].BL_Version;
295 Buffer[8] = devicesTable[Data0 - 1].sizeOfDescription;
296 Buffer[9] = devicesTable[Data0 - 1].devID;
297 Buffer[10] = devicesTable[Data0 - 1].FW_Crc >> 24;
298 Buffer[11] = devicesTable[Data0 - 1].FW_Crc >> 16;
299 Buffer[12] = devicesTable[Data0 - 1].FW_Crc >> 8;
300 Buffer[13] = devicesTable[Data0 - 1].FW_Crc;
301 Buffer[14] = devicesTable[Data0 - 1].devID >> 8;
302 Buffer[15] = devicesTable[Data0 - 1].devID;
304 sendData(Buffer + 1, 63);
305 break;
306 case JumpFW:
307 if (Data == 0x5AFE) {
308 /* Force board into safe mode */
309 PIOS_IAP_WriteBootCount(0xFFFF);
311 // pass any Opt value to the firmware
312 PIOS_IAP_WriteBootCmd(0, Opt[0]);
313 PIOS_IAP_WriteBootCmd(1, Opt[1]);
314 PIOS_IAP_WriteBootCmd(2, Opt[2]);
316 FLASH_Lock();
317 JumpToApp = 1;
318 break;
319 case Reset:
320 PIOS_SYS_Reset();
321 break;
322 case Abort_Operation:
323 Next_Packet = 0;
324 DeviceState = DFUidle;
325 break;
327 case Op_END:
328 if (DeviceState == uploading) {
329 if (Next_Packet - 1 == SizeOfTransfer) {
330 Next_Packet = 0;
331 if ((TransferType != FW) || (Expected_CRC == CalcFirmCRC())) {
332 DeviceState = Last_operation_Success;
333 } else {
334 DeviceState = CRC_Fail;
337 if (Next_Packet - 1 < SizeOfTransfer) {
338 Next_Packet = 0;
339 DeviceState = too_few_packets;
342 break;
343 case Download_Req:
344 #ifdef DEBUG_SSP
345 sprintf(str, "COMMAND:DOWNLOAD_REQ 1 Status=%d|", DeviceState);
346 PIOS_COM_SendString(PIOS_COM_TELEM_USB, str);
347 #endif
348 if (DeviceState == DFUidle) {
349 #ifdef DEBUG_SSP
350 PIOS_COM_SendString(PIOS_COM_TELEM_USB, "COMMAND:DOWNLOAD_REQ 1|");
351 #endif
352 downType = Data0;
353 downPacketTotal = Count;
354 downSizeOfLastPacket = Data1;
355 if (isBiggerThanAvailable(downType, (downPacketTotal - 1) * 14
356 + downSizeOfLastPacket) == 1) {
357 DeviceState = outsideDevCapabilities;
358 Aditionals = (uint32_t)Command;
359 } else {
360 downPacketCurrent = 0;
361 DeviceState = downloading;
363 } else {
364 DeviceState = Last_operation_failed;
365 Aditionals = (uint32_t)Command;
367 break;
369 case Status_Request:
370 Buffer[0] = 0x01;
371 Buffer[1] = Status_Rep;
372 if (DeviceState == wrong_packet_received) {
373 Buffer[2] = Aditionals >> 24;
374 Buffer[3] = Aditionals >> 16;
375 Buffer[4] = Aditionals >> 8;
376 Buffer[5] = Aditionals;
377 } else {
378 Buffer[2] = 0;
379 Buffer[3] = ((uint16_t)Aditionals) >> 8;
380 Buffer[4] = ((uint16_t)Aditionals);
381 Buffer[5] = 0;
383 Buffer[6] = DeviceState;
384 Buffer[7] = 0;
385 Buffer[8] = 0;
386 Buffer[9] = 0;
387 sendData(Buffer + 1, 63);
388 if (DeviceState == Last_operation_Success) {
389 DeviceState = DFUidle;
391 break;
392 case Status_Rep:
394 break;
396 if (EchoReqFlag == 1) {
397 echoBuffer[1] = echoBuffer[1] | EchoAnsFlag;
398 sendData(echoBuffer + 1, 63);
401 void OPDfuIni(uint8_t discover)
403 const struct pios_board_info *bdinfo = &pios_board_info_blob;
404 Device dev;
406 dev.programmingType = Self_flash;
407 dev.readWriteFlags = (BOARD_READABLE | (BOARD_WRITABLE << 1));
408 dev.startOfUserCode = bdinfo->fw_base;
409 dev.sizeOfCode = bdinfo->fw_size;
410 dev.sizeOfDescription = bdinfo->desc_size;
411 dev.BL_Version = bdinfo->bl_rev;
412 dev.FW_Crc = CalcFirmCRC();
413 dev.devID = (bdinfo->board_type << 8) | (bdinfo->board_rev);
414 dev.devType = bdinfo->hw_type;
415 numberOfDevices = 1;
416 devicesTable[0] = dev;
417 if (discover) {
418 // TODO check other devices trough spi or whatever
421 uint32_t baseOfAdressType(DFUTransfer type)
423 switch (type) {
424 case FW:
425 return currentDevice.startOfUserCode;
427 break;
428 case Descript:
429 return currentDevice.startOfUserCode + currentDevice.sizeOfCode;
431 break;
432 default:
434 return 0;
437 uint8_t isBiggerThanAvailable(DFUTransfer type, uint32_t size)
439 switch (type) {
440 case FW:
441 return (size > currentDevice.sizeOfCode) ? 1 : 0;
443 break;
444 case Descript:
445 return (size > currentDevice.sizeOfDescription) ? 1 : 0;
447 break;
448 default:
449 return true;
453 uint32_t CalcFirmCRC()
455 switch (currentProgrammingDestination) {
456 case Self_flash:
457 return PIOS_BL_HELPER_CRC_Memory_Calc();
459 break;
460 case Remote_flash_via_spi:
461 return 0;
463 break;
464 default:
465 return 0;
467 break;
470 void sendData(uint8_t *buf, uint16_t size)
472 PIOS_COM_MSG_Send(PIOS_COM_TELEM_USB, buf, size);
475 bool flash_read(uint8_t *buffer, uint32_t adr, DFUProgType type)
477 switch (type) {
478 case Remote_flash_via_spi:
479 return false; // We should not get this for the OPLink Mini
481 break;
482 case Self_flash:
483 for (uint8_t x = 0; x < 4; ++x) {
484 buffer[x] = *PIOS_BL_HELPER_FLASH_If_Read(adr + x);
486 return true;
488 break;
489 default:
490 return false;