2 ******************************************************************************
5 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2018.
6 * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
7 * @brief In Application Programming module to support firmware upgrades by
8 * providing a means to enter the bootloader.
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
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 #include <openpilot.h>
31 #include <pios_board_info.h>
33 #include "firmwareiap.h"
34 #include "firmwareiapobj.h"
35 #include "flightstatus.h"
38 #define IAP_CMD_STEP_1 1122
39 #define IAP_CMD_STEP_2 2233
40 #define IAP_CMD_STEP_3 3344
42 #define IAP_CMD_CRC 100
43 #define IAP_CMD_VERIFY 101
44 #define IAP_CMD_VERSION 102
46 #define IAP_STATE_READY 0
47 #define IAP_STATE_STEP_1 1
48 #define IAP_STATE_STEP_2 2
49 #define IAP_STATE_RESETTING 3
51 #define RESET_DELAY 500
53 #define TICKS2MS(t) ((t) / portTICK_RATE_MS)
54 #define MS2TICKS(m) ((m) * portTICK_RATE_MS)
56 const uint32_t iap_time_2_low_end
= 500;
57 const uint32_t iap_time_2_high_end
= 5000;
58 const uint32_t iap_time_3_low_end
= 500;
59 const uint32_t iap_time_3_high_end
= 5000;
64 static uint8_t reset_count
= 0;
65 static portTickType lastResetSysTime
;
68 static void FirmwareIAPCallback(UAVObjEvent
*ev
);
70 static uint32_t get_time(void);
75 static void resetTask(UAVObjEvent
*);
78 * Initialise the module, called on startup.
79 * \returns 0 on success or -1 if initialisation failed
83 * \brief Performs object initialization functions.
85 * \return 0 - under all cases
90 MODULE_INITCALL(FirmwareIAPInitialize
, 0);
91 int32_t FirmwareIAPInitialize()
93 FirmwareIAPObjInitialize();
95 const struct pios_board_info
*bdinfo
= &pios_board_info_blob
;
97 FirmwareIAPObjData data
;
98 FirmwareIAPObjGet(&data
);
100 PIOS_BL_HELPER_FLASH_Read_Description(data
.Description
, FIRMWAREIAPOBJ_DESCRIPTION_NUMELEM
);
101 PIOS_SYS_SerialNumberGetBinary(data
.CPUSerial
);
102 if (data
.BoardType
== 0) {
103 data
.BoardRevision
= bdinfo
->board_rev
;
104 data
.BoardType
= bdinfo
->board_type
;
106 data
.BootloaderRevision
= bdinfo
->bl_rev
;
108 data
.crc
= PIOS_BL_HELPER_CRC_Memory_Calc();
109 FirmwareIAPObjSet(&data
);
110 if (bdinfo
->magic
== PIOS_BOARD_INFO_BLOB_MAGIC
) {
111 FirmwareIAPObjConnectCallback(&FirmwareIAPCallback
);
116 int32_t FirmwareIAPStart()
122 * \brief FirmwareIAPCallback - callback function for firmware IAP requests
123 * \param[in] ev - pointer objevent
129 static uint8_t iap_state
= IAP_STATE_READY
;
130 static void FirmwareIAPCallback(UAVObjEvent
*ev
)
132 static uint32_t last_time
= 0;
136 if (iap_state
== IAP_STATE_RESETTING
) {
140 FirmwareIAPObjData data
;
142 if (ev
->obj
== FirmwareIAPObjHandle()) {
143 // Get the input object data
144 FirmwareIAPObjGet(&data
);
145 this_time
= get_time();
146 delta
= this_time
- last_time
;
147 last_time
= this_time
;
149 case IAP_STATE_READY
:
150 if (data
.Command
== IAP_CMD_STEP_1
) {
151 iap_state
= IAP_STATE_STEP_1
;
154 case IAP_STATE_STEP_1
:
155 if (data
.Command
== IAP_CMD_STEP_2
) {
156 if (delta
> iap_time_2_low_end
&& delta
< iap_time_2_high_end
) {
157 iap_state
= IAP_STATE_STEP_2
;
159 iap_state
= IAP_STATE_READY
;
162 iap_state
= IAP_STATE_READY
;
165 case IAP_STATE_STEP_2
:
166 if (data
.Command
== IAP_CMD_STEP_3
) {
167 if (delta
> iap_time_3_low_end
&& delta
< iap_time_3_high_end
) {
168 #ifndef PIOS_APPS_MINIMAL
169 FlightStatusData flightStatus
;
170 FlightStatusGet(&flightStatus
);
172 if (flightStatus
.Armed
!= FLIGHTSTATUS_ARMED_DISARMED
) {
173 // Abort any attempts if not disarmed
174 iap_state
= IAP_STATE_READY
;
178 // we've met the three sequence of command numbers
179 // we've met the time requirements.
180 PIOS_IAP_SetRequest1();
181 PIOS_IAP_SetRequest2();
183 /* Note: Cant just wait timeout value, because first time is randomized */
185 lastResetSysTime
= xTaskGetTickCount();
186 UAVObjEvent
*event
= pios_malloc(sizeof(UAVObjEvent
));
187 memset(event
, 0, sizeof(UAVObjEvent
));
188 EventPeriodicCallbackCreate(event
, resetTask
, 100);
189 iap_state
= IAP_STATE_RESETTING
;
191 iap_state
= IAP_STATE_READY
;
194 iap_state
= IAP_STATE_READY
;
197 case IAP_STATE_RESETTING
:
198 // stay here permanentally, should reboot
201 iap_state
= IAP_STATE_READY
;
202 last_time
= 0; // Reset the time counter, as we are not doing a IAP reset
209 // Returns number of milliseconds from the start of the kernel.
212 * \brief Returns number of milliseconds from the start of the kernel
214 * \return number of milliseconds from the start of the kernel.
220 static uint32_t get_time(void)
224 ticks
= xTaskGetTickCount();
226 return TICKS2MS(ticks
);
230 * Executed by event dispatcher callback to reset Board
232 static void resetTask(__attribute__((unused
)) UAVObjEvent
*ev
)
234 #if defined(PIOS_LED_HEARTBEAT)
235 PIOS_LED_Toggle(PIOS_LED_HEARTBEAT
);
236 #endif /* PIOS_LED_HEARTBEAT */
238 #if defined(PIOS_LED_ALARM)
239 PIOS_LED_Toggle(PIOS_LED_ALARM
);
240 #endif /* PIOS_LED_ALARM */
242 if ((portTickType
)(xTaskGetTickCount() - lastResetSysTime
) > RESET_DELAY
/ portTICK_RATE_MS
) {
243 lastResetSysTime
= xTaskGetTickCount();