2 ******************************************************************************
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * @brief In Application Programming module to support firmware upgrades by
7 * providing a means to enter the bootloader.
9 * @see The GNU Public License (GPL) Version 3
11 *****************************************************************************/
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include <openpilot.h>
30 #include <pios_board_info.h>
32 #include "firmwareiap.h"
33 #include "firmwareiapobj.h"
34 #include "flightstatus.h"
37 #define IAP_CMD_STEP_1 1122
38 #define IAP_CMD_STEP_2 2233
39 #define IAP_CMD_STEP_3 3344
41 #define IAP_CMD_CRC 100
42 #define IAP_CMD_VERIFY 101
43 #define IAP_CMD_VERSION 102
45 #define IAP_STATE_READY 0
46 #define IAP_STATE_STEP_1 1
47 #define IAP_STATE_STEP_2 2
48 #define IAP_STATE_RESETTING 3
50 #define RESET_DELAY 500 /* delay between sending reset ot INS */
52 #define TICKS2MS(t) ((t) / portTICK_RATE_MS)
53 #define MS2TICKS(m) ((m) * portTICK_RATE_MS)
55 const uint32_t iap_time_2_low_end
= 500;
56 const uint32_t iap_time_2_high_end
= 5000;
57 const uint32_t iap_time_3_low_end
= 500;
58 const uint32_t iap_time_3_high_end
= 5000;
63 static uint8_t reset_count
= 0;
64 static portTickType lastResetSysTime
;
67 static void FirmwareIAPCallback(UAVObjEvent
*ev
);
69 static uint32_t get_time(void);
74 static void resetTask(UAVObjEvent
*);
77 * Initialise the module, called on startup.
78 * \returns 0 on success or -1 if initialisation failed
82 * \brief Performs object initialization functions.
84 * \return 0 - under all cases
89 MODULE_INITCALL(FirmwareIAPInitialize
, 0);
90 int32_t FirmwareIAPInitialize()
92 FirmwareIAPObjInitialize();
94 const struct pios_board_info
*bdinfo
= &pios_board_info_blob
;
96 FirmwareIAPObjData data
;
97 FirmwareIAPObjGet(&data
);
99 data
.BoardType
= bdinfo
->board_type
;
100 PIOS_BL_HELPER_FLASH_Read_Description(data
.Description
, FIRMWAREIAPOBJ_DESCRIPTION_NUMELEM
);
101 PIOS_SYS_SerialNumberGetBinary(data
.CPUSerial
);
102 data
.BoardRevision
= bdinfo
->board_rev
;
103 data
.BootloaderRevision
= bdinfo
->bl_rev
;
106 FirmwareIAPObjSet(&data
);
107 if (bdinfo
->magic
== PIOS_BOARD_INFO_BLOB_MAGIC
) {
108 FirmwareIAPObjConnectCallback(&FirmwareIAPCallback
);
113 int32_t FirmwareIAPStart()
119 * \brief FirmwareIAPCallback - callback function for firmware IAP requests
120 * \param[in] ev - pointer objevent
126 static uint8_t iap_state
= IAP_STATE_READY
;
127 static void FirmwareIAPCallback(UAVObjEvent
*ev
)
129 const struct pios_board_info
*bdinfo
= &pios_board_info_blob
;
130 static uint32_t last_time
= 0;
134 if (iap_state
== IAP_STATE_RESETTING
) {
138 FirmwareIAPObjData data
;
139 FirmwareIAPObjGet(&data
);
141 if (ev
->obj
== FirmwareIAPObjHandle()) {
142 // Get the input object data
143 FirmwareIAPObjGet(&data
);
144 this_time
= get_time();
145 delta
= this_time
- last_time
;
146 last_time
= this_time
;
147 if ((data
.BoardType
== bdinfo
->board_type
) && (data
.crc
!= PIOS_BL_HELPER_CRC_Memory_Calc())) {
148 PIOS_BL_HELPER_FLASH_Read_Description(data
.Description
, FIRMWAREIAPOBJ_DESCRIPTION_NUMELEM
);
149 PIOS_SYS_SerialNumberGetBinary(data
.CPUSerial
);
150 data
.BoardRevision
= bdinfo
->board_rev
;
151 data
.BootloaderRevision
= bdinfo
->bl_rev
;
152 data
.crc
= PIOS_BL_HELPER_CRC_Memory_Calc();
153 FirmwareIAPObjSet(&data
);
155 if ((data
.ArmReset
== 1) && (iap_state
!= IAP_STATE_RESETTING
)) {
157 FirmwareIAPObjSet(&data
);
160 case IAP_STATE_READY
:
161 if (data
.Command
== IAP_CMD_STEP_1
) {
162 iap_state
= IAP_STATE_STEP_1
;
165 case IAP_STATE_STEP_1
:
166 if (data
.Command
== IAP_CMD_STEP_2
) {
167 if (delta
> iap_time_2_low_end
&& delta
< iap_time_2_high_end
) {
168 iap_state
= IAP_STATE_STEP_2
;
170 iap_state
= IAP_STATE_READY
;
173 iap_state
= IAP_STATE_READY
;
176 case IAP_STATE_STEP_2
:
177 if (data
.Command
== IAP_CMD_STEP_3
) {
178 if (delta
> iap_time_3_low_end
&& delta
< iap_time_3_high_end
) {
179 #ifndef PIOS_APPS_MINIMAL
180 FlightStatusData flightStatus
;
181 FlightStatusGet(&flightStatus
);
183 if (flightStatus
.Armed
!= FLIGHTSTATUS_ARMED_DISARMED
) {
184 // Abort any attempts if not disarmed
185 iap_state
= IAP_STATE_READY
;
189 // we've met the three sequence of command numbers
190 // we've met the time requirements.
191 PIOS_IAP_SetRequest1();
192 PIOS_IAP_SetRequest2();
194 /* Note: Cant just wait timeout value, because first time is randomized */
196 lastResetSysTime
= xTaskGetTickCount();
197 UAVObjEvent
*event
= pios_malloc(sizeof(UAVObjEvent
));
198 memset(event
, 0, sizeof(UAVObjEvent
));
199 EventPeriodicCallbackCreate(event
, resetTask
, 100);
200 iap_state
= IAP_STATE_RESETTING
;
202 iap_state
= IAP_STATE_READY
;
205 iap_state
= IAP_STATE_READY
;
208 case IAP_STATE_RESETTING
:
209 // stay here permanentally, should reboot
212 iap_state
= IAP_STATE_READY
;
213 last_time
= 0; // Reset the time counter, as we are not doing a IAP reset
220 // Returns number of milliseconds from the start of the kernel.
223 * \brief Returns number of milliseconds from the start of the kernel
225 * \return number of milliseconds from the start of the kernel.
231 static uint32_t get_time(void)
235 ticks
= xTaskGetTickCount();
237 return TICKS2MS(ticks
);
241 * Executed by event dispatcher callback to reset INS before resetting OP
243 static void resetTask(__attribute__((unused
)) UAVObjEvent
*ev
)
245 #if defined(PIOS_LED_HEARTBEAT)
246 PIOS_LED_Toggle(PIOS_LED_HEARTBEAT
);
247 #endif /* PIOS_LED_HEARTBEAT */
249 #if defined(PIOS_LED_ALARM)
250 PIOS_LED_Toggle(PIOS_LED_ALARM
);
251 #endif /* PIOS_LED_ALARM */
253 FirmwareIAPObjData data
;
254 FirmwareIAPObjGet(&data
);
256 if ((portTickType
)(xTaskGetTickCount() - lastResetSysTime
) > RESET_DELAY
/ portTICK_RATE_MS
) {
257 lastResetSysTime
= xTaskGetTickCount();
258 data
.BoardType
= 0xFF;
260 data
.crc
= reset_count
; /* Must change a value for this to get to INS */
261 FirmwareIAPObjSet(&data
);
263 if (reset_count
> 3) {