update credits
[librepilot.git] / flight / libraries / op_dfu.c
blob3cfb03a5b109be943272d658a2e0543b966b67a7
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 || (DeviceState == failed_jump)) {
162 if (Data0 > 0) {
163 OPDfuIni(true);
165 DeviceState = DFUidle;
166 currentProgrammingDestination = devicesTable[Data0].programmingType;
167 currentDeviceCanRead = devicesTable[Data0].readWriteFlags & 0x01;
168 currentDeviceCanWrite = devicesTable[Data0].readWriteFlags >> 1
169 & 0x01;
170 currentDevice = devicesTable[Data0];
171 uint8_t result = 0;
172 switch (currentProgrammingDestination) {
173 case Self_flash:
174 result = PIOS_BL_HELPER_FLASH_Ini();
175 break;
176 case Remote_flash_via_spi:
177 result = true;
178 break;
179 default:
180 DeviceState = Last_operation_failed;
181 Aditionals = (uint16_t)Command;
183 if (result != 1) {
184 DeviceState = Last_operation_failed;
185 Aditionals = (uint32_t)Command;
188 break;
189 case Upload:
190 if ((DeviceState == DFUidle) || (DeviceState == uploading)) {
191 if ((StartFlag == 1) && (Next_Packet == 0)) {
192 TransferType = Data0;
193 SizeOfTransfer = Count;
194 Next_Packet = 1;
195 Expected_CRC = unpack_uint32(&xReceive_Buffer[DATA + 2]);
196 SizeOfLastPacket = Data1;
198 if (isBiggerThanAvailable(TransferType, (SizeOfTransfer - 1)
199 * 14 * 4 + SizeOfLastPacket * 4) == true) {
200 DeviceState = outsideDevCapabilities;
201 Aditionals = (uint32_t)Command;
202 } else {
203 uint8_t result = 1;
204 if (TransferType == FW) {
205 switch (currentProgrammingDestination) {
206 case Self_flash:
207 result = PIOS_BL_HELPER_FLASH_Start();
208 break;
209 case Remote_flash_via_spi:
210 result = false;
211 break;
212 default:
213 break;
216 if (result != 1) {
217 DeviceState = Last_operation_failed;
218 Aditionals = (uint32_t)Command;
219 } else {
220 DeviceState = uploading;
223 } else if ((StartFlag != 1) && (Next_Packet != 0)) {
224 if (Count > SizeOfTransfer) {
225 DeviceState = too_many_packets;
226 Aditionals = Count;
227 } else if (Count == Next_Packet - 1) {
228 uint8_t numberOfWords = 14;
229 if (Count == SizeOfTransfer - 1) { // is this the last packet?
230 numberOfWords = SizeOfLastPacket;
232 uint8_t result = 0;
233 uint32_t offset;
234 uint32_t aux;;
235 switch (currentProgrammingDestination) {
236 case Self_flash:
237 for (uint8_t x = 0; x < numberOfWords; ++x) {
238 offset = 4 * x;
239 Data = unpack_uint32(&xReceive_Buffer[DATA + offset]);
240 aux = baseOfAdressType(TransferType) + (uint32_t)(
241 Count * 14 * 4 + x * 4);
242 result = 0;
243 for (int retry = 0; retry < MAX_WRI_RETRYS; ++retry) {
244 if (result == 0) {
245 result = (FLASH_ProgramWord(aux, Data)
246 == FLASH_COMPLETE) ? 1 : 0;
250 break;
251 case Remote_flash_via_spi:
252 result = false; // No support for this for the OPLink Mini
253 break;
254 default:
255 result = 0;
256 break;
258 if (result != 1) {
259 DeviceState = Last_operation_failed;
260 Aditionals = (uint32_t)Command;
263 ++Next_Packet;
264 } else {
265 DeviceState = wrong_packet_received;
266 Aditionals = Count;
268 } else {
269 DeviceState = Last_operation_failed;
270 Aditionals = (uint32_t)Command;
273 break;
274 case Req_Capabilities:
275 OPDfuIni(true);
276 Buffer[0] = 0x01;
277 Buffer[1] = Rep_Capabilities;
278 if (Data0 == 0) {
279 Buffer[2] = 0;
280 Buffer[3] = 0;
281 Buffer[4] = 0;
282 Buffer[5] = 0;
283 Buffer[6] = 0;
284 Buffer[7] = numberOfDevices;
285 uint16_t WRFlags = 0;
286 for (int x = 0; x < numberOfDevices; ++x) {
287 WRFlags = ((devicesTable[x].readWriteFlags << (x * 2))
288 | WRFlags);
290 Buffer[8] = WRFlags >> 8;
291 Buffer[9] = WRFlags;
292 } else {
293 pack_uint32(devicesTable[Data0 - 1].sizeOfCode, &Buffer[2]);
294 Buffer[6] = Data0;
295 Buffer[7] = devicesTable[Data0 - 1].BL_Version;
296 Buffer[8] = devicesTable[Data0 - 1].sizeOfDescription;
297 Buffer[9] = devicesTable[Data0 - 1].devID;
298 pack_uint32(devicesTable[Data0 - 1].FW_Crc, &Buffer[10]);
299 Buffer[14] = devicesTable[Data0 - 1].devID >> 8;
300 Buffer[15] = devicesTable[Data0 - 1].devID;
302 sendData(Buffer + 1, 63);
303 break;
304 case JumpFW:
305 if (Data == 0x5AFE) {
306 /* Force board into safe mode */
307 PIOS_IAP_WriteBootCount(0xFFFF);
309 // pass any Opt value to the firmware
310 PIOS_IAP_WriteBootCmd(0, Opt[0]);
311 PIOS_IAP_WriteBootCmd(1, Opt[1]);
312 PIOS_IAP_WriteBootCmd(2, Opt[2]);
314 FLASH_Lock();
315 JumpToApp = 1;
316 break;
317 case Reset:
318 PIOS_SYS_Reset();
319 break;
320 case Abort_Operation:
321 Next_Packet = 0;
322 DeviceState = DFUidle;
323 break;
325 case Op_END:
326 if (DeviceState == uploading) {
327 if (Next_Packet - 1 == SizeOfTransfer) {
328 Next_Packet = 0;
329 if ((TransferType != FW) || (Expected_CRC == CalcFirmCRC())) {
330 DeviceState = Last_operation_Success;
331 } else {
332 DeviceState = CRC_Fail;
335 if (Next_Packet - 1 < SizeOfTransfer) {
336 Next_Packet = 0;
337 DeviceState = too_few_packets;
340 break;
341 case Download_Req:
342 if (DeviceState == DFUidle) {
343 downType = Data0;
344 downPacketTotal = Count;
345 downSizeOfLastPacket = Data1;
346 if (isBiggerThanAvailable(downType, (downPacketTotal - 1) * 14
347 + downSizeOfLastPacket) == 1) {
348 DeviceState = outsideDevCapabilities;
349 Aditionals = (uint32_t)Command;
350 } else {
351 downPacketCurrent = 0;
352 DeviceState = downloading;
354 } else {
355 DeviceState = Last_operation_failed;
356 Aditionals = (uint32_t)Command;
358 break;
360 case Status_Request:
361 Buffer[0] = 0x01;
362 Buffer[1] = Status_Rep;
363 if (DeviceState == wrong_packet_received) {
364 pack_uint32(Aditionals, &Buffer[2]);
365 } else {
366 Buffer[2] = 0;
367 Buffer[3] = ((uint16_t)Aditionals) >> 8;
368 Buffer[4] = ((uint16_t)Aditionals);
369 Buffer[5] = 0;
371 Buffer[6] = DeviceState;
372 Buffer[7] = 0;
373 Buffer[8] = 0;
374 Buffer[9] = 0;
375 sendData(Buffer + 1, 63);
376 if (DeviceState == Last_operation_Success) {
377 DeviceState = DFUidle;
379 break;
380 case Status_Rep:
382 break;
384 if (EchoReqFlag == 1) {
385 echoBuffer[1] = echoBuffer[1] | EchoAnsFlag;
386 sendData(echoBuffer + 1, 63);
389 void OPDfuIni(uint8_t discover)
391 const struct pios_board_info *bdinfo = &pios_board_info_blob;
392 Device dev;
394 dev.programmingType = Self_flash;
395 dev.readWriteFlags = (BOARD_READABLE | (BOARD_WRITABLE << 1));
396 dev.startOfUserCode = bdinfo->fw_base;
397 dev.sizeOfCode = bdinfo->fw_size;
398 dev.sizeOfDescription = bdinfo->desc_size;
399 dev.BL_Version = bdinfo->bl_rev;
400 dev.FW_Crc = CalcFirmCRC();
401 dev.devID = (bdinfo->board_type << 8) | (bdinfo->board_rev);
402 dev.devType = bdinfo->hw_type;
403 numberOfDevices = 1;
404 devicesTable[0] = dev;
405 if (discover) {
406 // TODO check other devices trough spi or whatever
409 uint32_t baseOfAdressType(DFUTransfer type)
411 switch (type) {
412 case FW:
413 return currentDevice.startOfUserCode;
415 break;
416 case Descript:
417 return currentDevice.startOfUserCode + currentDevice.sizeOfCode;
419 break;
420 default:
422 return 0;
425 uint8_t isBiggerThanAvailable(DFUTransfer type, uint32_t size)
427 switch (type) {
428 case FW:
429 return (size > currentDevice.sizeOfCode) ? 1 : 0;
431 break;
432 case Descript:
433 return (size > currentDevice.sizeOfDescription) ? 1 : 0;
435 break;
436 default:
437 return true;
441 uint32_t CalcFirmCRC()
443 switch (currentProgrammingDestination) {
444 case Self_flash:
445 return PIOS_BL_HELPER_CRC_Memory_Calc();
447 break;
448 case Remote_flash_via_spi:
449 return 0;
451 break;
452 default:
453 return 0;
455 break;
458 void sendData(uint8_t *buf, uint16_t size)
460 platform_senddata(buf, size);
463 bool flash_read(uint8_t *buffer, uint32_t adr, DFUProgType type)
465 switch (type) {
466 case Remote_flash_via_spi:
467 return false; // We should not get this for the OPLink Mini
469 break;
470 case Self_flash:
471 for (uint8_t x = 0; x < 4; ++x) {
472 buffer[x] = *PIOS_BL_HELPER_FLASH_If_Read(adr + x);
474 return true;
476 break;
477 default:
478 return false;