Paparazzi UAS  v5.12_stable-4-g9b43e9b
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
px4_flash.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) Kevin van Hecke
3  *
4  * This file is part of paparazzi
5  *
6  * paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with paparazzi; see the file COPYING. If not, see
18  * <http://www.gnu.org/licenses/>.
19  */
29 #include "mcu_periph/sys_time_arch.h"
31 
32 // Serial Port
33 #include "mcu_periph/uart.h"
34 #include "mcu_periph/usb_serial.h"
35 
36 #include "led.h"
37 
38 #include "libopencm3/cm3/scb.h"
39 
40 #include "mcu_periph/sys_time.h"
41 #ifdef INTER_MCU_AP
42 tid_t px4iobl_tid;
43 // define coms link for px4io f1
44 #define PX4IO_PORT (&((PX4IO_UART).device))
45 #endif
46 
47 #define FLASH_PORT (&((FLASH_UART).device))
48 
49 
50 // weird that these below are not in protocol.h, which is from the firmware px4 repo
51 // below is copied from qgroundcontrol:
52 #define PROTO_INSYNC 0x12
53 #define PROTO_EOC 0x20
54 // Reply bytes
55 #define PROTO_OK 0x10
56 #define PROTO_FAILED 0x11
57 #define PROTO_INVALID 0x13
58 // Command bytes
59 #define PROTO_GET_SYNC 0x21
60 #define PROTO_GET_DEVICE 0x22
61 #define PROTO_CHIP_ERASE 0x23
62 #define PROTO_LOAD_ADDRESS 0x24
63 #define PROTO_PROG_MULTI 0x27
64 #define PROTO_GET_CRC 0x29
65 #define PROTO_BOOT 0x30
66 
69 
70 void px4flash_init(void)
71 {
72  setToBootloaderMode = false;
73 #ifdef INTER_MCU_AP
74  px4ioRebootTimeout = false;
75  px4iobl_tid = sys_time_register_timer(12.0, NULL); //20 (fbw pprz bl timeout)-5 (px4 fmu bl timeout) - 3 (uncertainty and random delays)
76 #endif
77 }
78 
79 void px4flash_event(void)
80 {
81 #ifdef INTER_MCU_AP
82  if (sys_time_check_and_ack_timer(px4iobl_tid)) {
84  sys_time_cancel_timer(px4iobl_tid);
85  //for unknown reasons, 1500000 baud does not work reliably after prolonged times.
86  //I suspect a temperature related issue, combined with the fbw f1 crystal which is out of specs
87  //After a initial period on 1500000, revert to 230400
88  //We still start at 1500000 to remain compatible with original PX4 firmware. (which always runs at 1500000)
89  uart_periph_set_baudrate(PX4IO_PORT->periph, B230400);
90  }
91  if (PX4IO_PORT->char_available(PX4IO_PORT->periph)) {
92  if (!setToBootloaderMode) {
93  //ignore anything coming from IO if not in bootloader mode (which should be nothing)
94  } else {
95  //relay everything from IO to the laptop
96  while (PX4IO_PORT->char_available(PX4IO_PORT->periph)) {
97  unsigned char b = PX4IO_PORT->get_byte(PX4IO_PORT->periph);
98  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, b);
99  }
100  }
101  }
102 #endif
103 
104  //TODO: check if bootloader timeout was surpassed
105  if (FLASH_PORT->char_available(FLASH_PORT->periph) && !setToBootloaderMode) {
106  //check whether this is flash related communication, and for who (ap/fbw)
107  int state = 0;
108  while (state < 4 && FLASH_PORT->char_available(FLASH_PORT->periph)) {
109  unsigned char b = FLASH_PORT->get_byte(FLASH_PORT->periph);
110  switch (state) {
111  case (0) :
112  if (b == 'p') { state++; } else { return; }
113  break;
114  case (1) :
115  if (b == 'p') { state++; } else { return; }
116  break;
117  case (2) :
118  if (b == 'r') { state++; } else { return; }
119  break;
120  case (3) :
121  if (b == 'z') { state++; } else { return; }
122  break;
123  default :
124  break;
125  }
126  }
127 
128  if (state != 4) {return;}
129  //TODO: check if/how this interferes with flashing original PX4 firmware
130  unsigned char target = FLASH_PORT->get_byte(FLASH_PORT->periph);
131  if (target == '1') { //target ap
132  //the target is the ap, so reboot to PX4 bootloader
133  scb_reset_system();
134 
135  } else { // target fbw
136 #ifdef INTER_MCU_AP
137  //the target is the fbw, so reboot the fbw and switch to relay mode
138 
139  //first check if the bootloader has not timeout:
140  if (px4ioRebootTimeout) {
141  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'T');
142  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'I');
143  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'M');
144  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'E');
145  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'O');
146  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'U');
147  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'T'); // use 7 chars as answer
148  return;
149  } { // FBW OK OK hollay hollay :)
150  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'F');
151  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'B');
152  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'W');
153  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'O');
154  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'K');
155  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'O');
156  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'K'); // use 7 chars as answer
157  }
158 
159 
160  //stop all intermcu communication:
162 
163  px4iobl_tid = sys_time_register_timer(5.0, NULL); //10 (fbw pprz bl timeout)-5 (px4 fmu bl timeout)
164 
165  /*
166  * The forceprog define is very usefull, if for whatever reason the (normal, not bootloader) firmware on the IO chip became disfunct.
167  * In that case:
168  * 1. enable this define
169  * 2. build and upload the fmu f4 chip (ap target in pprz center)
170  * 3. build the io code, and convert the firmware using the following command:
171  * $(PAPARAZZI_SRC)/sw/tools/px4/px_mkfw.py --prototype $(PAPARAZZI_SRC)/sw/tools/px4/px4io-v2.prototype --image $(PAPARAZZI_HOME)/var/aircrafts/<AC_NAME>/fbw/fbw.bin > $(PAPARAZZI_HOME)/var/aircrafts/<AC_NAME>/fbw/fbw.px4
172  * 4. Start the following command:
173  * $(PAPARAZZI_SRC)/sw/tools/px4/px_uploader.py --port "/dev/ttyACM0" $(PAPARAZZI_SRC)/var/aircrafts/<AC_NAME>/fbw/fbw.px4
174  * Optional 5&6:
175  * 5a. Either, boot the Pixhawk (reconnect usb) holding the IO reset button until the FMU led stops blinking fast (i.e. exits its own bootloader)
176  * 5b Or, press the IO reset button on the pixhawk
177  * 6. Watch the output of the command of step 4, it should recognize the IO bootloader and start flashing. If not try repeating step 5a.
178  * 7. Don forget to disable the define and upload the ap again :)
179  */
180  //#define forceprog
181 
182 #ifndef forceprog
183  //send the reboot to bootloader command:
184  static struct IOPacket dma_packet;
185  dma_packet.count_code = 0x40 + 0x01;
186  dma_packet.crc = 0;
187  dma_packet.page = PX4IO_PAGE_SETUP;
188  dma_packet.offset = PX4IO_P_SETUP_REBOOT_BL;
189  dma_packet.regs[0] = PX4IO_REBOOT_BL_MAGIC;
190  dma_packet.crc = crc_packet(&dma_packet);
191  struct IOPacket *pkt = &dma_packet;
192  uint8_t *p = (uint8_t *)pkt;
193  PX4IO_PORT->put_byte(PX4IO_PORT->periph, 0, p[0]);
194  PX4IO_PORT->put_byte(PX4IO_PORT->periph, 0, p[1]);
195  PX4IO_PORT->put_byte(PX4IO_PORT->periph, 0, p[2]);
196  PX4IO_PORT->put_byte(PX4IO_PORT->periph, 0, p[3]);
197  PX4IO_PORT->put_byte(PX4IO_PORT->periph, 0, p[4]);
198  PX4IO_PORT->put_byte(PX4IO_PORT->periph, 0, p[5]);
199 
200  sys_time_usleep(5000); // this seems to be close to the minimum delay necessary to process this packet at the IO side
201  //the pixhawk IO chip should respond with:
202  // 0x00 ( PKT_CODE_SUCCESS )
203  // 0xe5
204  // 0x32
205  // 0x0a
206  //After that, the IO chips reboots into bootloader mode, in which it will stay for a short period
207  //The baudrate in bootloader mode ic changed to 115200 (normal operating baud is 1500000, at least for original pixhawk fmu firmware)
208 
209  //state machine
210  state = 0;
211  while (state < 4 && PX4IO_PORT->char_available(PX4IO_PORT->periph)) {
212 
213  unsigned char b = PX4IO_PORT->get_byte(PX4IO_PORT->periph);
214  switch (state) {
215  case (0) :
216  if (b == PKT_CODE_SUCCESS) { state++; } else { state = 0; }
217  break;
218  case (1) :
219  if (b == 0xe5) { state++; } else { state = 0; }
220  break;
221  case (2) :
222  if (b == 0x32) { state++; } else { state = 0; }
223  break;
224  case (3) :
225  if (b == 0x0a) { state++; } else { state = 0; }
226  break;
227  default :
228  break;
229  }
230  }
231 #else
232  int state = 4;
233 #endif
234  if (state == 4) {
235  uart_periph_set_baudrate(PX4IO_PORT->periph, B115200);
236  /* look for the bootloader for 150 ms */
237  int ret = 0;
238  for (int i = 0; i < 15 && !ret ; i++) {
239  sys_time_usleep(10000);
240 
241  //send a get_sync command in order to keep the io in bootloader mode
242  PX4IO_PORT->put_byte(PX4IO_PORT->periph, 0, PROTO_GET_SYNC);
243  PX4IO_PORT->put_byte(PX4IO_PORT->periph, 0, PROTO_EOC);
244 
245  //get_sync should be replied with, so check if that happens and
246  //all other bytes are discarded, hopefully those were not important
247  //(they may be caused by sending multiple syncs)
248  while (PX4IO_PORT->char_available(PX4IO_PORT->periph)) {
249  unsigned char b = PX4IO_PORT->get_byte(PX4IO_PORT->periph);
250 
251  if (b == PROTO_INSYNC) {
252  setToBootloaderMode = true;
253  ret = 1;
254  break;
255  }
256  }
257  }
258  if (setToBootloaderMode) {
259  //if successfully entered bootloader mode, clear any remaining bytes (which may have a function, but I did not check)
260  while (PX4IO_PORT->char_available(PX4IO_PORT->periph)) {PX4IO_PORT->get_byte(PX4IO_PORT->periph);}
261  }
262  } else {
263  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'E'); //TODO: find out what the PX4 protocol for error feedback is...
264  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'R');
265  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'R');
266  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'O');
267  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, 'R');
268  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, '!');
269  FLASH_PORT->put_byte(FLASH_PORT->periph, 0, ' '); // use 7 chars as answer
270 
271  }
272 #endif
273  }
274  } else if (FLASH_PORT->char_available(FLASH_PORT->periph)) {
275 #ifdef INTER_MCU_AP
276  //already in bootloader mode, just directly relay data
277  while (FLASH_PORT->char_available(FLASH_PORT->periph)) {
278  unsigned char b = FLASH_PORT->get_byte(FLASH_PORT->periph);
279  PX4IO_PORT->put_byte(PX4IO_PORT->periph, 0, b);
280  }
281 #endif
282  }
283 }
284 
#define PKT_CODE_SUCCESS
Definition: protocol.h:331
arch independent UART (Universal Asynchronous Receiver/Transmitter) API
#define PX4IO_P_SETUP_REBOOT_BL
Definition: protocol.h:224
void uart_periph_set_baudrate(struct uart_periph *p, uint32_t baud)
Set baudrate.
Definition: uart_arch.c:856
#define PROTO_GET_SYNC
NOP for re-establishing sync.
Definition: px4_flash.c:59
void intermcu_set_enabled(bool value)
Definition: intermcu_ap.c:105
#define PX4IO_PAGE_SETUP
Definition: protocol.h:177
void px4flash_init(void)
Definition: px4_flash.c:70
uint8_t count_code
Definition: protocol.h:321
#define FLASH_PORT
Definition: px4_flash.c:47
#define B115200
Definition: uart_arch.h:48
void sys_time_cancel_timer(tid_t id)
Cancel a system timer by id.
Definition: sys_time.c:60
uint8_t offset
Definition: protocol.h:324
#define PROTO_EOC
end of command
Definition: px4_flash.c:53
uint8_t page
Definition: protocol.h:323
#define FALSE
Definition: std.h:5
void px4flash_event(void)
Definition: px4_flash.c:79
#define B230400
Definition: uart_arch.h:49
#define PROTO_INSYNC
'in sync' byte sent before status
Definition: px4_flash.c:52
void sys_time_usleep(uint32_t us)
sys_time_usleep(uint32_t us)
Definition: sys_time_arch.c:95
static uint8_t crc_packet(struct IOPacket *pkt)
Definition: protocol.h:379
#define TRUE
Definition: std.h:4
Architecture independent timing functions.
int8_t tid_t
sys_time timer id type
Definition: sys_time.h:60
bool px4ioRebootTimeout
Definition: px4_flash.c:68
Rotorcraft Inter-MCU on the autopilot.
bool setToBootloaderMode
Definition: px4_flash.c:67
unsigned char uint8_t
Definition: types.h:14
static bool sys_time_check_and_ack_timer(tid_t id)
Check if timer has elapsed.
Definition: sys_time.h:114
uint8_t crc
Definition: protocol.h:322
uint16_t regs[PKT_MAX_REGS]
Definition: protocol.h:325
arch independent LED (Light Emitting Diodes) API
static float p[2][2]
struct FloatVect2 target
#define PX4IO_REBOOT_BL_MAGIC
Definition: protocol.h:225
struct State state
Definition: state.c:36
tid_t sys_time_register_timer(float duration, sys_time_cb cb)
Register a new system timer.
Definition: sys_time.c:43
arch independent USB API