LP-518 Only disable link for OPlink protocols, not OpenLRS.
[librepilot.git] / flight / modules / FirmwareIAP / firmwareiap.c
blob3164f3281dc25048afeddcb13e5d54bb25ebe731
1 /**
2 ******************************************************************************
4 * @file firmwareiap.c
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
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 #include <openpilot.h>
31 #include <pios_board_info.h>
33 #include "firmwareiap.h"
34 #include "firmwareiapobj.h"
35 #include "flightstatus.h"
37 // Private constants
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;
61 // Private types
63 // Private variables
64 static uint8_t reset_count = 0;
65 static portTickType lastResetSysTime;
67 // Private functions
68 static void FirmwareIAPCallback(UAVObjEvent *ev);
70 static uint32_t get_time(void);
72 // Private types
74 // Private functions
75 static void resetTask(UAVObjEvent *);
77 /**
78 * Initialise the module, called on startup.
79 * \returns 0 on success or -1 if initialisation failed
82 /*!
83 * \brief Performs object initialization functions.
84 * \param None.
85 * \return 0 - under all cases
87 * \note
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;
107 data.ArmReset = 0;
108 data.crc = PIOS_BL_HELPER_CRC_Memory_Calc();
109 FirmwareIAPObjSet(&data);
110 if (bdinfo->magic == PIOS_BOARD_INFO_BLOB_MAGIC) {
111 FirmwareIAPObjConnectCallback(&FirmwareIAPCallback);
113 return 0;
116 int32_t FirmwareIAPStart()
118 return 0;
122 * \brief FirmwareIAPCallback - callback function for firmware IAP requests
123 * \param[in] ev - pointer objevent
124 * \retval None.
126 * \note
129 static uint8_t iap_state = IAP_STATE_READY;
130 static void FirmwareIAPCallback(UAVObjEvent *ev)
132 static uint32_t last_time = 0;
133 uint32_t this_time;
134 uint32_t delta;
136 if (iap_state == IAP_STATE_RESETTING) {
137 return;
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;
148 switch (iap_state) {
149 case IAP_STATE_READY:
150 if (data.Command == IAP_CMD_STEP_1) {
151 iap_state = IAP_STATE_STEP_1;
153 break;
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;
158 } else {
159 iap_state = IAP_STATE_READY;
161 } else {
162 iap_state = IAP_STATE_READY;
164 break;
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;
175 break;
177 #endif
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 */
184 reset_count = 0;
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;
190 } else {
191 iap_state = IAP_STATE_READY;
193 } else {
194 iap_state = IAP_STATE_READY;
196 break;
197 case IAP_STATE_RESETTING:
198 // stay here permanentally, should reboot
199 break;
200 default:
201 iap_state = IAP_STATE_READY;
202 last_time = 0; // Reset the time counter, as we are not doing a IAP reset
203 break;
209 // Returns number of milliseconds from the start of the kernel.
212 * \brief Returns number of milliseconds from the start of the kernel
213 * \param None.
214 * \return number of milliseconds from the start of the kernel.
216 * \note
220 static uint32_t get_time(void)
222 portTickType ticks;
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();
244 PIOS_SYS_Reset();