Paparazzi UAS  v6.3_unstable
Paparazzi is a free software Unmanned Aircraft System.
mission_common.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Paparazzi Team
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, write to
18  * the Free Software Foundation, 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  */
22 
28 
29 #include <string.h>
30 #include "generated/flight_plan.h"
31 #include "generated/airframe.h"
34 
35 // Check for unique ID by default
36 #ifndef MISSION_CHECK_UNIQUE_ID
37 #define MISSION_CHECK_UNIQUE_ID TRUE
38 #endif
39 
40 struct _mission mission = { 0 };
41 
42 void mission_init(void)
43 {
44  mission.insert_idx = 0;
45  mission.current_idx = 0;
46  mission.element_time = 0.;
47 
48  for (int i = 0; i < MISSION_REGISTER_NB; i++) {
49  mission.registered[i].cb = NULL;
50  memset(mission.registered[i].type, '\0', MISSION_TYPE_SIZE);
51  }
52 }
53 
54 
55 // Insert element
56 bool mission_insert(enum MissionInsertMode insert, struct _mission_element *element)
57 {
58  uint8_t tmp;
59 
60 #if MISSION_CHECK_UNIQUE_ID
61  // check that the new element id is not already in the list
62  if (mission_get_from_index(element->index) != NULL) {
63  return false;
64  }
65 #endif
66 
67  switch (insert) {
68  case Append:
70  if (tmp == mission.current_idx) { return false; } // no room to insert element
71  mission.elements[mission.insert_idx] = *element; // add element
72  mission.insert_idx = tmp; // move insert index
73  break;
74  case Prepend:
75  if (mission.current_idx == 0) { tmp = MISSION_ELEMENT_NB - 1; }
76  else { tmp = mission.current_idx - 1; }
77  if (tmp == mission.insert_idx) { return false; } // no room to inser element
78  mission.elements[tmp] = *element; // add element
79  mission.current_idx = tmp; // move current index
80  mission.element_time = 0.; // reset timer
81  break;
82  case ReplaceCurrent:
83  // current element can always be modified, index are not changed
84  mission.elements[mission.current_idx] = *element;
85  mission.element_time = 0.; // reset timer
86  break;
87  case ReplaceAll:
88  // reset queue and index
89  mission.elements[0] = *element;
90  mission.current_idx = 0;
91  mission.insert_idx = 1;
92  mission.element_time = 0.; // reset timer
93  break;
94  case ReplaceNexts:
96  mission.elements[tmp] = *element;
98  break;
99  default:
100  // unknown insertion mode
101  return false;
102  }
103  return true;
104 
105 }
106 
107 // Register new callback
109 {
110  for (int i = 0; i < MISSION_REGISTER_NB; i++) {
111  if (str_equal(mission.registered[i].type, type)) {
112  return false; // identifier already registered
113  }
114  if (mission.registered[i].cb == NULL) {
115  strncpy(mission.registered[i].type, type, MISSION_TYPE_SIZE-1);
116  mission.registered[i].cb = cb;
117  return true;
118  }
119  }
120  return false; // no more room to register callbacks
121 }
122 
123 // Returns a pointer to a register struct with matching types, NULL if not found
125 {
126  for (int i = 0; i < MISSION_REGISTER_NB; i++) {
127  if (str_equal(mission.registered[i].type, type)) {
128  return &(mission.registered[i]);
129  }
130  }
131  return NULL; // not found
132 }
133 
134 // Returns a pointer to a mission element struct with matching index, NULL if not found
136 {
138  while (i != mission.insert_idx) {
139  if (mission.elements[i].index == index) {
140  return &mission.elements[i]; // return first next element with matching index
141  }
142  i++;
143  if (i == MISSION_ELEMENT_NB) {
144  i = 0;
145  }
146  }
147  return NULL; // not found
148 }
149 
150 // Get element
152 {
154  return NULL;
155  }
156  return &(mission.elements[mission.current_idx]);
157 }
158 
159 
160 // Report function
162 {
163  // build index list
164  uint8_t index_list[MISSION_ELEMENT_NB];
165  uint8_t i = mission.current_idx, j = 0;
166  while (i != mission.insert_idx) {
167  index_list[j++] = mission.elements[i].index;
168  i = (i + 1) % MISSION_ELEMENT_NB;
169  }
170  if (j == 0) { index_list[j++] = 0; } // Dummy value if index list is empty
171  //compute remaining time (or -1. if no time limit)
172  float remaining_time = -1.;
175  }
176 
177  // send status
178  DOWNLINK_SEND_MISSION_STATUS(DefaultChannel, DefaultDevice, &remaining_time, j, index_list);
179 }
180 
181 
183 // Parsing functions //
185 
187 {
188  if (DL_MISSION_GOTO_WP_ac_id(buf) != AC_ID) { return false; } // not for this aircraft
189 
190  struct _mission_element me;
191  me.type = MissionWP;
192  me.element.mission_wp.wp.x = DL_MISSION_GOTO_WP_wp_east(buf);
193  me.element.mission_wp.wp.y = DL_MISSION_GOTO_WP_wp_north(buf);
194  me.element.mission_wp.wp.z = DL_MISSION_GOTO_WP_wp_alt(buf);
195  me.duration = DL_MISSION_GOTO_WP_duration(buf);
196  me.index = DL_MISSION_GOTO_WP_index(buf);
197 
198  enum MissionInsertMode insert = (enum MissionInsertMode)(DL_MISSION_GOTO_WP_insert(buf));
199 
200  return mission_insert(insert, &me);
201 }
202 
204 {
205  if (DL_MISSION_GOTO_WP_LLA_ac_id(buf) != AC_ID) { return false; } // not for this aircraft
206 
207  struct LlaCoor_i lla;
208  lla.lat = DL_MISSION_GOTO_WP_LLA_wp_lat(buf);
209  lla.lon = DL_MISSION_GOTO_WP_LLA_wp_lon(buf);
210  lla.alt = DL_MISSION_GOTO_WP_LLA_wp_alt(buf);
211 
212  struct _mission_element me;
213  me.type = MissionWP;
214  // if there is no valid local coordinate, do not insert mission element
215  if (!mission_point_of_lla(&me.element.mission_wp.wp, &lla)) { return false; }
216  me.duration = DL_MISSION_GOTO_WP_LLA_duration(buf);
217  me.index = DL_MISSION_GOTO_WP_LLA_index(buf);
218 
219  enum MissionInsertMode insert = (enum MissionInsertMode)(DL_MISSION_GOTO_WP_LLA_insert(buf));
220 
221  return mission_insert(insert, &me);
222 }
223 
225 {
226  if (DL_MISSION_CIRCLE_ac_id(buf) != AC_ID) { return false; } // not for this aircraft
227 
228  struct _mission_element me;
229  me.type = MissionCircle;
230  me.element.mission_circle.center.x = DL_MISSION_CIRCLE_center_east(buf);
231  me.element.mission_circle.center.y = DL_MISSION_CIRCLE_center_north(buf);
232  me.element.mission_circle.center.z = DL_MISSION_CIRCLE_center_alt(buf);
233  me.element.mission_circle.radius = DL_MISSION_CIRCLE_radius(buf);
234  me.duration = DL_MISSION_CIRCLE_duration(buf);
235  me.index = DL_MISSION_CIRCLE_index(buf);
236 
237  enum MissionInsertMode insert = (enum MissionInsertMode)(DL_MISSION_CIRCLE_insert(buf));
238 
239  return mission_insert(insert, &me);
240 }
241 
243 {
244  if (DL_MISSION_CIRCLE_LLA_ac_id(buf) != AC_ID) { return false; } // not for this aircraft
245 
246  struct LlaCoor_i lla;
247  lla.lat = DL_MISSION_CIRCLE_LLA_center_lat(buf);
248  lla.lon = DL_MISSION_CIRCLE_LLA_center_lon(buf);
249  lla.alt = DL_MISSION_CIRCLE_LLA_center_alt(buf);
250 
251  struct _mission_element me;
252  me.type = MissionCircle;
253  // if there is no valid local coordinate, do not insert mission element
254  if (!mission_point_of_lla(&me.element.mission_circle.center, &lla)) { return false; }
255  me.element.mission_circle.radius = DL_MISSION_CIRCLE_LLA_radius(buf);
256  me.duration = DL_MISSION_CIRCLE_LLA_duration(buf);
257  me.index = DL_MISSION_CIRCLE_LLA_index(buf);
258 
259  enum MissionInsertMode insert = (enum MissionInsertMode)(DL_MISSION_CIRCLE_LLA_insert(buf));
260 
261  return mission_insert(insert, &me);
262 }
263 
265 {
266  if (DL_MISSION_SEGMENT_ac_id(buf) != AC_ID) { return false; } // not for this aircraft
267 
268  struct _mission_element me;
269  me.type = MissionSegment;
270  me.element.mission_segment.from.x = DL_MISSION_SEGMENT_segment_east_1(buf);
271  me.element.mission_segment.from.y = DL_MISSION_SEGMENT_segment_north_1(buf);
272  me.element.mission_segment.from.z = DL_MISSION_SEGMENT_segment_alt(buf);
273  me.element.mission_segment.to.x = DL_MISSION_SEGMENT_segment_east_2(buf);
274  me.element.mission_segment.to.y = DL_MISSION_SEGMENT_segment_north_2(buf);
275  me.element.mission_segment.to.z = DL_MISSION_SEGMENT_segment_alt(buf);
276  me.duration = DL_MISSION_SEGMENT_duration(buf);
277  me.index = DL_MISSION_SEGMENT_index(buf);
278 
279  enum MissionInsertMode insert = (enum MissionInsertMode)(DL_MISSION_SEGMENT_insert(buf));
280 
281  return mission_insert(insert, &me);
282 }
283 
285 {
286  if (DL_MISSION_SEGMENT_LLA_ac_id(buf) != AC_ID) { return false; } // not for this aircraft
287 
288  struct LlaCoor_i from_lla, to_lla;
289  from_lla.lat = DL_MISSION_SEGMENT_LLA_segment_lat_1(buf);
290  from_lla.lon = DL_MISSION_SEGMENT_LLA_segment_lon_1(buf);
291  from_lla.alt = DL_MISSION_SEGMENT_LLA_segment_alt(buf);
292  to_lla.lat = DL_MISSION_SEGMENT_LLA_segment_lat_2(buf);
293  to_lla.lon = DL_MISSION_SEGMENT_LLA_segment_lon_2(buf);
294  to_lla.alt = DL_MISSION_SEGMENT_LLA_segment_alt(buf);
295 
296  struct _mission_element me;
297  me.type = MissionSegment;
298  // if there is no valid local coordinate, do not insert mission element
299  if (!mission_point_of_lla(&me.element.mission_segment.from, &from_lla)) { return false; }
300  if (!mission_point_of_lla(&me.element.mission_segment.to, &to_lla)) { return false; }
301  me.duration = DL_MISSION_SEGMENT_LLA_duration(buf);
302  me.index = DL_MISSION_SEGMENT_LLA_index(buf);
303 
304  enum MissionInsertMode insert = (enum MissionInsertMode)(DL_MISSION_SEGMENT_LLA_insert(buf));
305 
306  return mission_insert(insert, &me);
307 }
308 
310 {
311  if (DL_MISSION_PATH_ac_id(buf) != AC_ID) { return false; } // not for this aircraft
312 
313  struct _mission_element me;
314  me.type = MissionPath;
315  me.element.mission_path.path[0].x = DL_MISSION_PATH_point_east_1(buf);
316  me.element.mission_path.path[0].y = DL_MISSION_PATH_point_north_1(buf);
317  me.element.mission_path.path[0].z = DL_MISSION_PATH_path_alt(buf);
318  me.element.mission_path.path[1].x = DL_MISSION_PATH_point_east_2(buf);
319  me.element.mission_path.path[1].y = DL_MISSION_PATH_point_north_2(buf);
320  me.element.mission_path.path[1].z = DL_MISSION_PATH_path_alt(buf);
321  me.element.mission_path.path[2].x = DL_MISSION_PATH_point_east_3(buf);
322  me.element.mission_path.path[2].y = DL_MISSION_PATH_point_north_3(buf);
323  me.element.mission_path.path[2].z = DL_MISSION_PATH_path_alt(buf);
324  me.element.mission_path.path[3].x = DL_MISSION_PATH_point_east_4(buf);
325  me.element.mission_path.path[3].y = DL_MISSION_PATH_point_north_4(buf);
326  me.element.mission_path.path[3].z = DL_MISSION_PATH_path_alt(buf);
327  me.element.mission_path.path[4].x = DL_MISSION_PATH_point_east_5(buf);
328  me.element.mission_path.path[4].y = DL_MISSION_PATH_point_north_5(buf);
329  me.element.mission_path.path[4].z = DL_MISSION_PATH_path_alt(buf);
330  me.element.mission_path.nb = DL_MISSION_PATH_nb(buf);
331  if (me.element.mission_path.nb > MISSION_PATH_NB) { me.element.mission_path.nb = MISSION_PATH_NB; }
332  me.element.mission_path.path_idx = 0;
333  me.duration = DL_MISSION_PATH_duration(buf);
334  me.index = DL_MISSION_PATH_index(buf);
335 
336  enum MissionInsertMode insert = (enum MissionInsertMode)(DL_MISSION_PATH_insert(buf));
337 
338  return mission_insert(insert, &me);
339 }
340 
342 {
343  if (DL_MISSION_PATH_LLA_ac_id(buf) != AC_ID) { return false; } // not for this aircraft
344 
345  struct LlaCoor_i lla[MISSION_PATH_NB];
346  lla[0].lat = DL_MISSION_PATH_LLA_point_lat_1(buf);
347  lla[0].lon = DL_MISSION_PATH_LLA_point_lon_1(buf);
348  lla[0].alt = DL_MISSION_PATH_LLA_path_alt(buf);
349  lla[1].lat = DL_MISSION_PATH_LLA_point_lat_2(buf);
350  lla[1].lon = DL_MISSION_PATH_LLA_point_lon_2(buf);
351  lla[1].alt = DL_MISSION_PATH_LLA_path_alt(buf);
352  lla[2].lat = DL_MISSION_PATH_LLA_point_lat_3(buf);
353  lla[2].lon = DL_MISSION_PATH_LLA_point_lon_3(buf);
354  lla[2].alt = DL_MISSION_PATH_LLA_path_alt(buf);
355  lla[3].lat = DL_MISSION_PATH_LLA_point_lat_4(buf);
356  lla[3].lon = DL_MISSION_PATH_LLA_point_lon_4(buf);
357  lla[3].alt = DL_MISSION_PATH_LLA_path_alt(buf);
358  lla[4].lat = DL_MISSION_PATH_LLA_point_lat_5(buf);
359  lla[4].lon = DL_MISSION_PATH_LLA_point_lon_5(buf);
360  lla[4].alt = DL_MISSION_PATH_LLA_path_alt(buf);
361 
362  struct _mission_element me;
363  me.type = MissionPath;
364  uint8_t i;
365  me.element.mission_path.nb = DL_MISSION_PATH_LLA_nb(buf);
366  if (me.element.mission_path.nb > MISSION_PATH_NB) { me.element.mission_path.nb = MISSION_PATH_NB; }
367  for (i = 0; i < me.element.mission_path.nb; i++) {
368  // if there is no valid local coordinate, do not insert mission element
369  if (!mission_point_of_lla(&me.element.mission_path.path[i], &lla[i])) { return false; }
370  }
371  me.element.mission_path.path_idx = 0;
372  me.duration = DL_MISSION_PATH_LLA_duration(buf);
373  me.index = DL_MISSION_PATH_LLA_index(buf);
374 
375  enum MissionInsertMode insert = (enum MissionInsertMode)(DL_MISSION_PATH_LLA_insert(buf));
376 
377  return mission_insert(insert, &me);
378 }
379 
381 {
382  if (DL_MISSION_CUSTOM_ac_id(buf) != AC_ID) { return false; } // not for this aircraft
383 
384  struct _mission_element me;
385  me.type = MissionCustom;
386  me.element.mission_custom.reg = mission_get_registered(DL_MISSION_CUSTOM_type(buf));
387  if (me.element.mission_custom.reg == NULL) {
388  return false; // unknown type
389  }
390  me.element.mission_custom.nb = DL_MISSION_CUSTOM_params_length(buf);
391  for (int i = 0; i < me.element.mission_custom.nb; i++) {
392  me.element.mission_custom.params[i] = DL_MISSION_CUSTOM_params(buf)[i];
393  }
394  me.duration = DL_MISSION_CUSTOM_duration(buf);
395  me.index = DL_MISSION_CUSTOM_index(buf);
396 
397  enum MissionInsertMode insert = (enum MissionInsertMode)(DL_MISSION_CUSTOM_insert(buf));
398 
399  return mission_insert(insert, &me);
400 }
401 
403 {
404  if (DL_MISSION_UPDATE_ac_id(buf) != AC_ID) { return false; } // not for this aircraft
405 
406  struct _mission_element *me = mission_get_from_index(DL_MISSION_UPDATE_index(buf));
407  if (me == NULL) {
408  return false; // unknown type
409  }
410 
411  float duration = DL_MISSION_UPDATE_duration(buf);
412  if (duration > -2.f) { // no update should in fact be -9
413  me->duration = duration; // update
414  }
415 
416  uint8_t nb = DL_MISSION_UPDATE_params_length(buf);
417  float params[MISSION_CUSTOM_MAX];
418  memcpy(params, DL_MISSION_UPDATE_params(buf), nb*sizeof(float));
419 
420  switch (me->type) {
421  case MissionCustom:
422  return me->element.mission_custom.reg->cb(nb, params, MissionUpdate);
423  case MissionWP:
424  case MissionCircle:
425  case MissionSegment:
426  case MissionPath:
427  default:
428  // TODO handle update param for standard patterns
429  break;
430  }
431  return true;
432 }
433 
435 {
436  if (DL_GOTO_MISSION_ac_id(buf) != AC_ID) { return false; } // not for this aircraft
437 
438  uint8_t mission_id = DL_GOTO_MISSION_mission_id(buf);
439  if (mission_id < MISSION_ELEMENT_NB) {
440  // reset timer
441  mission.element_time = 0.;
442  // set current index
443  mission.current_idx = mission_id;
444  } else { return false; }
445 
446  return true;
447 }
448 
450 {
451  if (DL_NEXT_MISSION_ac_id(buf) != AC_ID) { return false; } // not for this aircraft
452 
453  if (mission.current_idx == mission.insert_idx) { return false; } // already at the last position
454 
455  // reset timer
456  mission.element_time = 0.;
457  // increment current index
459  return true;
460 }
461 
463 {
464  if (DL_END_MISSION_ac_id(buf) != AC_ID) { return false; } // not for this aircraft
465 
466  // reset timer
467  mission.element_time = 0.;
468  // set current index to insert index (last position)
470  return true;
471 }
int32_t lat
in degrees*1e7
int32_t alt
in millimeters above WGS84 reference ellipsoid
int32_t lon
in degrees*1e7
vector in Latitude, Longitude and Altitude
struct _mission mission
int mission_parse_END_MISSION(uint8_t *buf)
int mission_parse_GOTO_WP_LLA(uint8_t *buf)
int mission_parse_CUSTOM(uint8_t *buf)
static struct _mission_registered * mission_get_registered(char *type)
void mission_init(void)
Init mission structure.
int mission_parse_NEXT_MISSION(uint8_t *buf)
int mission_parse_PATH_LLA(uint8_t *buf)
bool mission_insert(enum MissionInsertMode insert, struct _mission_element *element)
Insert a mission element according to the insertion mode.
void mission_status_report(void)
Report mission status.
int mission_parse_SEGMENT_LLA(uint8_t *buf)
int mission_parse_GOTO_WP(uint8_t *buf)
Parsing functions called when a mission message is received.
int mission_parse_CIRCLE(uint8_t *buf)
int mission_parse_UPDATE(uint8_t *buf)
struct _mission_element * mission_get_from_index(uint8_t index)
Get mission element by index.
int mission_parse_SEGMENT(uint8_t *buf)
int mission_parse_GOTO_MISSION(uint8_t *buf)
bool mission_register(mission_custom_cb cb, char *type)
Register a new navigation or action callback function.
struct _mission_element * mission_get(void)
Get current mission element.
int mission_parse_PATH(uint8_t *buf)
int mission_parse_CIRCLE_LLA(uint8_t *buf)
mission planner library
#define MISSION_TYPE_SIZE
bool(* mission_custom_cb)(uint8_t nb, float *params, enum MissionRunFlag flag)
custom mission element callback
char type[MISSION_TYPE_SIZE]
mission element identifier (5 char max + 1 \0)
mission_custom_cb cb
navigation/action function callback
@ MissionCustom
@ MissionCircle
@ MissionWP
@ MissionSegment
@ MissionPath
struct _mission_registered registered[MISSION_REGISTER_NB]
@ MissionUpdate
param update
struct _mission_element elements[MISSION_ELEMENT_NB]
float element_time
time in second spend in the current element
bool mission_point_of_lla(struct EnuCoor_f *point, struct LlaCoor_i *lla)
Get the ENU component of LLA mission point This function is firmware specific.
union _mission_element::@288 element
enum MissionType type
uint8_t index
index of mission element
#define MISSION_PATH_NB
#define MISSION_REGISTER_NB
Max number of registered nav/action callbacks can be redefined.
#define MISSION_ELEMENT_NB
Max number of elements in the tasks' list can be redefined.
uint8_t insert_idx
inserstion index
MissionInsertMode
@ ReplaceCurrent
replace current element
@ Append
add at the last position
@ ReplaceNexts
replace the next element and remove all the others
@ ReplaceAll
remove all elements and add the new one
@ Prepend
add before the current element
float duration
time to spend in the element (<= 0 to disable)
#define MISSION_CUSTOM_MAX
uint8_t current_idx
current mission element index
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98