LP-89 - Port OP_15.05.01 fixes. Release notes:
[librepilot.git] / flight / libraries / op_dfu.c
blobd10b351e615f0868abefa290235cc4c31a2ed3cf
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_board_info.h>
35 // programmable devices
36 Device devicesTable[10];
37 uint8_t numberOfDevices = 0;
39 DFUProgType currentProgrammingDestination; // flash, flash_trough spi
40 uint8_t currentDeviceCanRead;
41 uint8_t currentDeviceCanWrite;
42 Device currentDevice;
44 uint8_t Buffer[64];
45 uint8_t echoBuffer[64];
46 uint8_t SendBuffer[64];
47 uint8_t Command = 0;
48 uint8_t EchoReqFlag = 0;
49 uint8_t EchoAnsFlag = 0;
50 uint8_t StartFlag = 0;
51 uint32_t Aditionals = 0;
52 uint32_t SizeOfTransfer = 0;
53 uint32_t Expected_CRC = 0;
54 uint8_t SizeOfLastPacket = 0;
55 uint32_t Next_Packet = 0;
56 uint8_t TransferType;
57 uint32_t Count = 0;
58 uint32_t Data;
59 uint8_t Data0;
60 uint8_t Data1;
61 uint8_t Data2;
62 uint8_t Data3;
63 uint32_t Opt[3];
65 // Download vars
66 uint32_t downSizeOfLastPacket = 0;
67 uint32_t downPacketTotal = 0;
68 uint32_t downPacketCurrent = 0;
69 DFUTransfer downType = 0;
70 /* Extern variables ----------------------------------------------------------*/
71 extern DFUStates DeviceState;
72 extern uint8_t JumpToApp;
73 extern int32_t platform_senddata(const uint8_t *msg, uint16_t msg_len);
74 /* Private function prototypes -----------------------------------------------*/
75 static uint32_t baseOfAdressType(uint8_t type);
76 static uint8_t isBiggerThanAvailable(uint8_t type, uint32_t size);
77 static void OPDfuIni(uint8_t discover);
78 bool flash_read(uint8_t *buffer, uint32_t adr, DFUProgType type);
79 /* Private functions ---------------------------------------------------------*/
80 void sendData(uint8_t *buf, uint16_t size);
81 uint32_t CalcFirmCRC(void);
83 void DataDownload(__attribute__((unused)) DownloadAction action)
85 if ((DeviceState == downloading)) {
86 uint8_t packetSize;
87 uint32_t offset;
88 uint32_t partoffset;
89 SendBuffer[0] = 0x01;
90 SendBuffer[1] = Download;
91 SendBuffer[2] = downPacketCurrent >> 24;
92 SendBuffer[3] = downPacketCurrent >> 16;
93 SendBuffer[4] = downPacketCurrent >> 8;
94 SendBuffer[5] = downPacketCurrent;
95 if (downPacketCurrent == downPacketTotal - 1) {
96 packetSize = downSizeOfLastPacket;
97 } else {
98 packetSize = 14;
100 for (uint8_t x = 0; x < packetSize; ++x) {
101 partoffset = (downPacketCurrent * 14 * 4) + (x * 4);
102 offset = baseOfAdressType(downType) + partoffset;
103 if (!flash_read(SendBuffer + (6 + x * 4), offset,
104 currentProgrammingDestination)) {
105 DeviceState = Last_operation_failed;
108 downPacketCurrent = downPacketCurrent + 1;
109 if (downPacketCurrent > downPacketTotal - 1) {
110 DeviceState = Last_operation_Success;
111 Aditionals = (uint32_t)Download;
113 sendData(SendBuffer + 1, 63);
117 static uint32_t unpack_uint32(uint8_t *buffer)
119 uint32_t ret = buffer[0] << 24;
121 ret += buffer[1] << 16;
122 ret += buffer[2] << 8;
123 ret += buffer[3];
124 return ret;
127 static void pack_uint32(uint32_t value, uint8_t *buffer)
129 buffer[0] = value >> 24;
130 buffer[1] = value >> 16;
131 buffer[2] = value >> 8;
132 buffer[3] = value;
136 void processComand(uint8_t *xReceive_Buffer)
138 Command = xReceive_Buffer[COMMAND];
139 EchoReqFlag = (Command >> 7);
140 EchoAnsFlag = (Command >> 6) & 0x01;
141 StartFlag = (Command >> 5) & 0x01;
142 Count = unpack_uint32(&xReceive_Buffer[COUNT]);
143 Data = unpack_uint32(&xReceive_Buffer[DATA]);
144 Data0 = xReceive_Buffer[DATA];
145 Data1 = xReceive_Buffer[DATA + 1];
146 Data2 = xReceive_Buffer[DATA + 2];
147 Data3 = xReceive_Buffer[DATA + 3];
148 for (uint32_t i = 0; i < 3; i++) {
149 Opt[i] = unpack_uint32(&xReceive_Buffer[DATA + 4 * (i + 1)]);
152 Command = Command & 0b00011111;
154 if (EchoReqFlag == 1) {
155 memcpy(echoBuffer, xReceive_Buffer, 64);
157 switch (Command) {
158 case EnterDFU:
159 if (((DeviceState == BLidle) && (Data0 < numberOfDevices))
160 || (DeviceState == DFUidle)) {
161 if (Data0 > 0) {
162 OPDfuIni(true);
164 DeviceState = DFUidle;
165 currentProgrammingDestination = devicesTable[Data0].programmingType;
166 currentDeviceCanRead = devicesTable[Data0].readWriteFlags & 0x01;
167 currentDeviceCanWrite = devicesTable[Data0].readWriteFlags >> 1
168 & 0x01;
169 currentDevice = devicesTable[Data0];
170 uint8_t result = 0;
171 switch (currentProgrammingDestination) {
172 case Self_flash:
173 result = PIOS_BL_HELPER_FLASH_Ini();
174 break;
175 case Remote_flash_via_spi:
176 result = true;
177 break;
178 default:
179 DeviceState = Last_operation_failed;
180 Aditionals = (uint16_t)Command;
182 if (result != 1) {
183 DeviceState = Last_operation_failed;
184 Aditionals = (uint32_t)Command;
187 break;
188 case Upload:
189 if ((DeviceState == DFUidle) || (DeviceState == uploading)) {
190 if ((StartFlag == 1) && (Next_Packet == 0)) {
191 TransferType = Data0;
192 SizeOfTransfer = Count;
193 Next_Packet = 1;
194 Expected_CRC = unpack_uint32(&xReceive_Buffer[DATA + 2]);
195 SizeOfLastPacket = Data1;
197 if (isBiggerThanAvailable(TransferType, (SizeOfTransfer - 1)
198 * 14 * 4 + SizeOfLastPacket * 4) == true) {
199 DeviceState = outsideDevCapabilities;
200 Aditionals = (uint32_t)Command;
201 } else {
202 uint8_t result = 1;
203 if (TransferType == FW) {
204 switch (currentProgrammingDestination) {
205 case Self_flash:
206 result = PIOS_BL_HELPER_FLASH_Start();
207 break;
208 case Remote_flash_via_spi:
209 result = false;
210 break;
211 default:
212 break;
215 if (result != 1) {
216 DeviceState = Last_operation_failed;
217 Aditionals = (uint32_t)Command;
218 } else {
219 DeviceState = uploading;
222 } else if ((StartFlag != 1) && (Next_Packet != 0)) {
223 if (Count > SizeOfTransfer) {
224 DeviceState = too_many_packets;
225 Aditionals = Count;
226 } else if (Count == Next_Packet - 1) {
227 uint8_t numberOfWords = 14;
228 if (Count == SizeOfTransfer - 1) { // is this the last packet?
229 numberOfWords = SizeOfLastPacket;
231 uint8_t result = 0;
232 uint32_t offset;
233 uint32_t aux;;
234 switch (currentProgrammingDestination) {
235 case Self_flash:
236 for (uint8_t x = 0; x < numberOfWords; ++x) {
237 offset = 4 * x;
238 Data = unpack_uint32(&xReceive_Buffer[DATA + offset]);
239 aux = baseOfAdressType(TransferType) + (uint32_t)(
240 Count * 14 * 4 + x * 4);
241 result = 0;
242 for (int retry = 0; retry < MAX_WRI_RETRYS; ++retry) {
243 if (result == 0) {
244 result = (FLASH_ProgramWord(aux, Data)
245 == FLASH_COMPLETE) ? 1 : 0;
249 break;
250 case Remote_flash_via_spi:
251 result = false; // No support for this for the OPLink Mini
252 break;
253 default:
254 result = 0;
255 break;
257 if (result != 1) {
258 DeviceState = Last_operation_failed;
259 Aditionals = (uint32_t)Command;
262 ++Next_Packet;
263 } else {
264 DeviceState = wrong_packet_received;
265 Aditionals = Count;
267 } else {
268 DeviceState = Last_operation_failed;
269 Aditionals = (uint32_t)Command;
272 break;
273 case Req_Capabilities:
274 OPDfuIni(true);
275 Buffer[0] = 0x01;
276 Buffer[1] = Rep_Capabilities;
277 if (Data0 == 0) {
278 Buffer[2] = 0;
279 Buffer[3] = 0;
280 Buffer[4] = 0;
281 Buffer[5] = 0;
282 Buffer[6] = 0;
283 Buffer[7] = numberOfDevices;
284 uint16_t WRFlags = 0;
285 for (int x = 0; x < numberOfDevices; ++x) {
286 WRFlags = ((devicesTable[x].readWriteFlags << (x * 2))
287 | WRFlags);
289 Buffer[8] = WRFlags >> 8;
290 Buffer[9] = WRFlags;
291 } else {
292 pack_uint32(devicesTable[Data0 - 1].sizeOfCode, &Buffer[2]);
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 pack_uint32(devicesTable[Data0 - 1].FW_Crc, &Buffer[10]);
298 Buffer[14] = devicesTable[Data0 - 1].devID >> 8;
299 Buffer[15] = devicesTable[Data0 - 1].devID;
301 sendData(Buffer + 1, 63);
302 break;
303 case JumpFW:
304 if (Data == 0x5AFE) {
305 /* Force board into safe mode */
306 PIOS_IAP_WriteBootCount(0xFFFF);
308 // pass any Opt value to the firmware
309 PIOS_IAP_WriteBootCmd(0, Opt[0]);
310 PIOS_IAP_WriteBootCmd(1, Opt[1]);
311 PIOS_IAP_WriteBootCmd(2, Opt[2]);
313 FLASH_Lock();
314 JumpToApp = 1;
315 break;
316 case Reset:
317 PIOS_SYS_Reset();
318 break;
319 case Abort_Operation:
320 Next_Packet = 0;
321 DeviceState = DFUidle;
322 break;
324 case Op_END:
325 if (DeviceState == uploading) {
326 if (Next_Packet - 1 == SizeOfTransfer) {
327 Next_Packet = 0;
328 if ((TransferType != FW) || (Expected_CRC == CalcFirmCRC())) {
329 DeviceState = Last_operation_Success;
330 } else {
331 DeviceState = CRC_Fail;
334 if (Next_Packet - 1 < SizeOfTransfer) {
335 Next_Packet = 0;
336 DeviceState = too_few_packets;
339 break;
340 case Download_Req:
341 if (DeviceState == DFUidle) {
342 downType = Data0;
343 downPacketTotal = Count;
344 downSizeOfLastPacket = Data1;
345 if (isBiggerThanAvailable(downType, (downPacketTotal - 1) * 14
346 + downSizeOfLastPacket) == 1) {
347 DeviceState = outsideDevCapabilities;
348 Aditionals = (uint32_t)Command;
349 } else {
350 downPacketCurrent = 0;
351 DeviceState = downloading;
353 } else {
354 DeviceState = Last_operation_failed;
355 Aditionals = (uint32_t)Command;
357 break;
359 case Status_Request:
360 Buffer[0] = 0x01;
361 Buffer[1] = Status_Rep;
362 if (DeviceState == wrong_packet_received) {
363 pack_uint32(Aditionals, &Buffer[2]);
364 } else {
365 Buffer[2] = 0;
366 Buffer[3] = ((uint16_t)Aditionals) >> 8;
367 Buffer[4] = ((uint16_t)Aditionals);
368 Buffer[5] = 0;
370 Buffer[6] = DeviceState;
371 Buffer[7] = 0;
372 Buffer[8] = 0;
373 Buffer[9] = 0;
374 sendData(Buffer + 1, 63);
375 if (DeviceState == Last_operation_Success) {
376 DeviceState = DFUidle;
378 break;
379 case Status_Rep:
381 break;
383 if (EchoReqFlag == 1) {
384 echoBuffer[1] = echoBuffer[1] | EchoAnsFlag;
385 sendData(echoBuffer + 1, 63);
388 void OPDfuIni(uint8_t discover)
390 const struct pios_board_info *bdinfo = &pios_board_info_blob;
391 Device dev;
393 dev.programmingType = Self_flash;
394 dev.readWriteFlags = (BOARD_READABLE | (BOARD_WRITABLE << 1));
395 dev.startOfUserCode = bdinfo->fw_base;
396 dev.sizeOfCode = bdinfo->fw_size;
397 dev.sizeOfDescription = bdinfo->desc_size;
398 dev.BL_Version = bdinfo->bl_rev;
399 dev.FW_Crc = CalcFirmCRC();
400 dev.devID = (bdinfo->board_type << 8) | (bdinfo->board_rev);
401 dev.devType = bdinfo->hw_type;
402 numberOfDevices = 1;
403 devicesTable[0] = dev;
404 if (discover) {
405 // TODO check other devices trough spi or whatever
408 uint32_t baseOfAdressType(DFUTransfer type)
410 switch (type) {
411 case FW:
412 return currentDevice.startOfUserCode;
414 break;
415 case Descript:
416 return currentDevice.startOfUserCode + currentDevice.sizeOfCode;
418 break;
419 default:
421 return 0;
424 uint8_t isBiggerThanAvailable(DFUTransfer type, uint32_t size)
426 switch (type) {
427 case FW:
428 return (size > currentDevice.sizeOfCode) ? 1 : 0;
430 break;
431 case Descript:
432 return (size > currentDevice.sizeOfDescription) ? 1 : 0;
434 break;
435 default:
436 return true;
440 uint32_t CalcFirmCRC()
442 switch (currentProgrammingDestination) {
443 case Self_flash:
444 return PIOS_BL_HELPER_CRC_Memory_Calc();
446 break;
447 case Remote_flash_via_spi:
448 return 0;
450 break;
451 default:
452 return 0;
454 break;
457 void sendData(uint8_t *buf, uint16_t size)
459 platform_senddata(buf, size);
462 bool flash_read(uint8_t *buffer, uint32_t adr, DFUProgType type)
464 switch (type) {
465 case Remote_flash_via_spi:
466 return false; // We should not get this for the OPLink Mini
468 break;
469 case Self_flash:
470 for (uint8_t x = 0; x < 4; ++x) {
471 buffer[x] = *PIOS_BL_HELPER_FLASH_If_Read(adr + x);
473 return true;
475 break;
476 default:
477 return false;