Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
jevois.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2017 Gautier Hattenberger <gautier.hattenberger@enac.fr>
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  */
27 
28 #include "std.h"
29 #include "mcu_periph/uart.h"
30 #include "modules/core/abi.h"
33 #include <string.h>
34 #include <stdio.h>
35 
38 
39 // max string length
40 #define JEVOIS_MAX_LEN 32
41 // max number of coordinates
42 #define JEVOIS_MAX_COORD 18
43 // check delimiter
44 #define JEVOIS_CHECK_DELIM(_c) (_c == ' ' || _c == '\n' || _c == '\r' || _c == '\0')
45 
46 // generic JEVOIS message structure
47 struct jevois_msg_t {
49  char id[JEVOIS_MAX_LEN];
53  struct FloatQuat quat;
55 };
56 
57 // decoder state
59  JV_SYNC = 0,
66  JV_EXTRA
67 };
68 
69 // jevois struct
70 struct jevois_t {
71  enum jevois_state state; // decoder state
72  char buf[JEVOIS_MAX_LEN]; // temp buffer
73  uint8_t idx; // temp buffer index
74  uint8_t n; // temp coordinates/dimension index
75  struct jevois_msg_t msg; // last decoded message
76  bool data_available; // new data to report
77 };
78 
79 struct jevois_t jevois;
80 
81 // reporting function, send telemetry message
82 void jevois_report(void)
83 {
84  if (jevois.data_available == false) {
85  // no new data, return
86  return;
87  }
88 
89  float quat[4] = {
90  jevois.msg.quat.qi,
91  jevois.msg.quat.qx,
92  jevois.msg.quat.qy,
94  };
95  uint8_t len = strlen(jevois.msg.id);
96  char none[] = "None";
97  char *id = jevois.msg.id;
98  if (len == 0) {
99  id = none;
100  len = 4;
101  }
102  DOWNLINK_SEND_JEVOIS(DefaultChannel, DefaultDevice,
103  &jevois.msg.type,
104  len, id,
105  &jevois.msg.nb,
106  Max(jevois.msg.nb,1), jevois.msg.coord,
107  jevois.msg.dim,
108  quat);
109  jevois.data_available = false;
110 }
111 
112 // initialization
113 void jevois_init(void)
114 {
115  // dummy settings
117  jevois_stream_setting = false;
118 
119  jevois.state = JV_SYNC;
120  jevois.idx = 0;
121  jevois.n = 0;
122  jevois.data_available = false;
123  memset(jevois.buf, 0, JEVOIS_MAX_LEN);
124 }
125 
126 // extrat a number (int) from an idea string
127 // this might be needed as jevois ID can start with a letter
128 // this will extract the first substring with a number
129 // and return the result of atoi function
130 int jevois_extract_nb(char *in) {
131  unsigned int i, j = 0;
132  bool first = false;
133  char out[JEVOIS_MAX_LEN];
134  for (i = 0; i < strlen(in)+1; i++) {
135  if ((in[i] >= '0' && in[i] < '9') || in[i] == '-') {
136  out[j++] = in[i];
137  first = true;
138  } else if (first || in[i] == '\0') {
139  out[j] = '\0';
140  break;
141  }
142  }
143  return atoi(out);
144 }
145 
146 // send specific message if requested
147 static void jevois_send_message(void)
148 {
149 #if JEVOIS_SEND_MSG
150  // send pprzlink JEVOIS message
151  jevois_report();
152 #endif
153 #if JEVOIS_SEND_FOLLOW_TARGET
154  float cam_heading = (JEVOIS_HFOV / (2.f * JEVOIS_NORM)) * (float)(jevois.msg.coord[0]);
155  float cam_height = (JEVOIS_VFOV / (2.f * JEVOIS_NORM)) * (float)(jevois.msg.coord[1]);
156  // send a FOLLOW_TARGET message in camera frame
157  AbiSendMsgFOLLOW_TARGET(CAM_JEVOIS_ID, 0, 0, cam_heading, cam_height, 0.f);
158 #endif
159 #if JEVOIS_SEND_VISUAL_DETECTION
160  AbiSendMsgVISUAL_DETECTION(CAM_JEVOIS_ID,
161  jevois.msg.coord[0],
162  jevois.msg.coord[1],
163  jevois.msg.dim[0],
164  jevois.msg.dim[1],
165  0,
167 #endif
168 }
169 
170 static void jevois_handle_msg(struct jevois_t *jv) {
171  // send ABI message
172  AbiSendMsgJEVOIS_MSG(CAM_JEVOIS_ID,
173  jv->msg.type,
174  jv->msg.id,
175  jv->msg.nb,
176  jv->msg.coord,
177  jv->msg.dim,
178  jv->msg.quat,
179  jv->msg.extra);
180  // also send specific messages if needed
182  jv->data_available = true;
183  jv->idx = 0;
184  jv->n = 0;
185 }
186 
187 // raw message parsing function
188 static void jevois_parse(struct jevois_t *jv, char c)
189 {
190  switch (jv->state) {
191  case JV_SYNC:
192  // wait for sync (newline character)
193  if (c == '\n') {
194  jv->state = JV_TYPE;
195  jv->idx = 0;
196  jv->n = 0;
197  }
198  break;
199  case JV_TYPE:
200  jv->buf[jv->idx++] = c; // fill buffer
201  // parse type
202  if (jv->idx > 2) { // msg type + white space
203  if (jv->buf[0] == 'T' && jv->buf[1] == '1') {
204  jv->state = JV_COORD;
205  jv->msg.type = JEVOIS_MSG_T1;
206  jv->msg.nb = 1;
207  } else if (jv->buf[0] == 'N' && jv->buf[1] == '1') {
208  jv->state = JV_ID;
209  jv->msg.type = JEVOIS_MSG_N1;
210  jv->msg.nb = 1;
211  } else if (jv->buf[0] == 'D' && jv->buf[1] == '1') {
212  jv->state = JV_ID;
213  jv->msg.type = JEVOIS_MSG_D1;
214  jv->msg.nb = 2;
215  } else if (jv->buf[0] == 'T' && jv->buf[1] == '2') {
216  jv->state = JV_COORD;
217  jv->msg.type = JEVOIS_MSG_T2;
218  jv->msg.nb = 2;
219  } else if (jv->buf[0] == 'N' && jv->buf[1] == '2') {
220  jv->state = JV_ID;
221  jv->msg.type = JEVOIS_MSG_N2;
222  jv->msg.nb = 2;
223  } else if (jv->buf[0] == 'D' && jv->buf[1] == '2') {
224  jv->state = JV_ID;
225  jv->msg.type = JEVOIS_MSG_D2;
226  jv->msg.nb = 8;
227  } else if (jv->buf[0] == 'F' && jv->buf[1] == '2') {
228  jv->state = JV_ID;
229  jv->msg.type = JEVOIS_MSG_F2;
230  jv->msg.nb = 0;
231  } else if (jv->buf[0] == 'T' && jv->buf[1] == '3') {
232  jv->state = JV_COORD;
233  jv->msg.type = JEVOIS_MSG_T3;
234  jv->msg.nb = 3;
235  } else if (jv->buf[0] == 'N' && jv->buf[1] == '3') {
236  jv->state = JV_ID;
237  jv->msg.type = JEVOIS_MSG_N3;
238  jv->msg.nb = 3;
239  } else if (jv->buf[0] == 'D' && jv->buf[1] == '3') {
240  jv->state = JV_ID;
241  jv->msg.type = JEVOIS_MSG_D3;
242  jv->msg.nb = 3;
243  } else if (jv->buf[0] == 'F' && jv->buf[1] == '3') {
244  jv->state = JV_ID;
245  jv->msg.type = JEVOIS_MSG_F3;
246  jv->msg.nb = 0;
247  } else {
248  jv->state = JV_SYNC; // error
249  }
250  jv->idx = 0;
251  }
252  break;
253  case JV_ID:
254  if (JEVOIS_CHECK_DELIM(c)) {
255  jv->msg.id[jv->idx] = '\0'; // end string
256  if (jv->msg.type == JEVOIS_MSG_F2 ||
257  jv->msg.type == JEVOIS_MSG_F3) {
258  jv->state = JV_SIZE; // parse n before coordinates
259  } else {
260  jv->state = JV_COORD; // parse directly coordinates
261  }
262  jv->idx = 0;
263  break;
264  }
265  else {
266  jv->msg.id[jv->idx++] = c;
267  if (jv->idx > JEVOIS_MAX_LEN - 1) {
268  jv->state = JV_SYNC; // too long, return to sync
269  }
270  }
271  break;
272  case JV_SIZE:
273  if (JEVOIS_CHECK_DELIM(c)) {
274  jv->buf[jv->idx] = '\0'; // end string
275  jv->msg.nb = (uint8_t)atoi(jv->buf); // store size
276  jv->state = JV_COORD;
277  jv->idx = 0;
278  }
279  else {
280  jv->buf[jv->idx++] = c; // fill buffer
281  }
282  break;
283  case JV_COORD:
284  if (JEVOIS_CHECK_DELIM(c)) {
285  jv->buf[jv->idx] = '\0'; // end string
286  jv->msg.coord[jv->n++] = (int16_t)atoi(jv->buf); // store value
287  if (jv->n == jv->msg.nb) {
288  // got all coordinates, go to next state
289  jv->n = 0; // reset number of received elements
290  jv->idx = 0; // reset index
291  switch (jv->msg.type) {
292  case JEVOIS_MSG_T1:
293  case JEVOIS_MSG_T2:
294  case JEVOIS_MSG_T3:
295  jevois_handle_msg(jv);
296  jv->state = JV_TYPE;
297  break;
298  case JEVOIS_MSG_N1:
299  case JEVOIS_MSG_N2:
300  case JEVOIS_MSG_N3:
301  case JEVOIS_MSG_D3:
302  jv->state = JV_DIM;
303  break;
304  case JEVOIS_MSG_D1:
305  case JEVOIS_MSG_D2:
306  case JEVOIS_MSG_F2:
307  case JEVOIS_MSG_F3:
308  jv->state = JV_EXTRA;
309  break;
310  default:
311  jv->state = JV_SYNC; // error
312  break;
313  }
314  }
315  jv->idx = 0; // reset index
316  }
317  else {
318  jv->buf[jv->idx++] = c; // fill buffer
319  }
320  break;
321  case JV_DIM:
322  if (JEVOIS_CHECK_DELIM(c)) {
323  jv->buf[jv->idx] = '\0'; // end string
324  jv->msg.dim[jv->n++] = (uint16_t)atoi(jv->buf); // store dimension
325  if (jv->n == jv->msg.nb) {
326  // got all dimensions, go to next state
327  jv->n = 0; // reset number of received elements
328  jv->idx = 0; // reset index
329  if (jv->msg.type == JEVOIS_MSG_D3) {
330  jv->state = JV_QUAT;
331  } else {
332  jevois_handle_msg(jv);
333  jv->state = JV_TYPE;
334  }
335  break;
336  }
337  jv->idx = 0; // reset index
338  }
339  else {
340  jv->buf[jv->idx++] = c; // fill buffer
341  }
342  break;
343  case JV_QUAT:
344  if (JEVOIS_CHECK_DELIM(c)) {
345  jv->buf[jv->idx] = '\0';
346  float q = (float)atof(jv->buf);
347  switch (jv->n) {
348  case 0:
349  jv->msg.quat.qi = q;
350  break;
351  case 1:
352  jv->msg.quat.qx = q;
353  break;
354  case 2:
355  jv->msg.quat.qy = q;
356  break;
357  case 3:
358  jv->msg.quat.qz = q;
359  jv->state = JV_EXTRA;
360  break;
361  default:
362  jv->state = JV_SYNC; // error
363  break;
364  }
365  jv->n++;
366  jv->idx = 0; // reset index
367  }
368  else {
369  jv->buf[jv->idx++] = c; // fill buffer
370  }
371  break;
372  case JV_EXTRA:
373  if (JEVOIS_CHECK_DELIM(c)) {
374  jv->msg.extra[jv->idx] = '\0'; // end string
375 
376  if (c == '\n') {
377  jevois_handle_msg(jv);
378  jv->state = JV_TYPE;
379  } else if( c=='\r') {
380  // do nothing, just to consume '\r'
381  }
382  else {
383  jv->state = JV_SYNC;
384  }
385  }
386  else {
387  jv->msg.extra[jv->idx++] = c; // store extra string
388  if (jv->idx > JEVOIS_MAX_LEN - 1) {
389  jv->state = JV_SYNC; // too long, return to sync
390  }
391  }
392  break;
393  default:
394  // error, back to SYNC
395  jv->state = JV_SYNC;
396  break;
397  }
398 }
399 
400 
401 // UART polling function
402 void jevois_event(void)
403 {
404  // Look for data on serial link and send to parser
405  while (uart_char_available(&(JEVOIS_DEV))) {
406  uint8_t ch = uart_getch(&(JEVOIS_DEV));
407  jevois_parse(&jevois, ch);
408  }
409 }
410 
411 // utility function to send a string
413 {
414  uint8_t i = 0;
415  while (s[i]) {
416  uart_put_byte(&(JEVOIS_DEV), 0, (uint8_t)(s[i]));
417  i++;
418  }
419 }
420 
421 void jevois_stream(bool activate)
422 {
423  jevois_stream_setting = activate;
424  if (activate) {
425  jevois_send_string("streamon\r\n");
426  } else {
427  jevois_send_string("streamoff\r\n");
428  }
429 }
430 
431 void jevois_setmapping(int number)
432 {
433  jevois_mapping_setting = number;
434  jevois_stream(false);
435  jevois_send_string("setmapping ");
436  char s[4];
437 #ifndef SITL
438  itoa(number, s, 10);
439 #endif
441  jevois_send_string("\r\n");
442  jevois_stream(true);
443 }
444 
446 {
447  char str[32] __attribute__((unused));
448 #if JEVOIS_SEND_ALT
449  // send current altitude in millimeter
450  int alt_mm = (int)(stateGetPositionEnu_f()->z * 1000.f);
451  Bound(alt_mm, -999999, 999999);
452  sprintf(str, "alt %d\r\n", alt_mm);
453  jevois_send_string(str);
454 #endif
455 #if JEVOIS_SEND_POS
456  // send current position in millimeter
457  struct EnuCoor_f pos = *stateGetPositionEnu_f();
458  int x_mm = (int)(pos.x * 1000.f);
459  int y_mm = (int)(pos.y * 1000.f);
460  int z_mm = (int)(pos.z * 1000.f);
461  Bound(x_mm, -999999, 999999);
462  Bound(y_mm, -999999, 999999);
463  Bound(z_mm, -999999, 999999);
464  sprintf(str, "pos %d %d %d\r\n", x_mm, y_mm, z_mm);
465  jevois_send_string(str);
466 #endif
467 #if JEVOIS_SEND_QUAT
468  // send quaternion
469  struct FloatQuat quat = *stateGetNedToBodyQuat_f();
470  int qi = (int)(quat.qi * 1000.f);
471  int qx = (int)(quat.qx * 1000.f);
472  int qy = (int)(quat.qy * 1000.f);
473  int qz = (int)(quat.qz * 1000.f);
474  Bound(qi, -9999, 9999);
475  Bound(qx, -9999, 9999);
476  Bound(qy, -9999, 9999);
477  Bound(qz, -9999, 9999);
478  sprintf(str, "quat %d %d %d %d\r\n", qi, qx, qy, qz);
479  jevois_send_string(str);
480 #endif
481 }
Main include for ABI (AirBorneInterface).
#define CAM_JEVOIS_ID
volatile int32_t alt_mm
Definition: exif_module.c:33
Roation quaternion.
static struct FloatQuat * stateGetNedToBodyQuat_f(void)
Get vehicle body attitude quaternion (float).
Definition: state.h:1294
static struct EnuCoor_f * stateGetPositionEnu_f(void)
Get position in local ENU coordinates (float).
Definition: state.h:848
bool jevois_stream_setting
Definition: jevois.c:37
static void jevois_parse(struct jevois_t *jv, char c)
Definition: jevois.c:188
void jevois_setmapping(int number)
Set video mapping.
Definition: jevois.c:431
char id[JEVOIS_MAX_LEN]
Definition: jevois.c:49
static void jevois_handle_msg(struct jevois_t *jv)
Definition: jevois.c:170
uint8_t idx
Definition: jevois.c:73
uint8_t type
Definition: jevois.c:48
char buf[JEVOIS_MAX_LEN]
Definition: jevois.c:72
char extra[JEVOIS_MAX_LEN]
Definition: jevois.c:54
void jevois_stream(bool activate)
Start and stop streaming.
Definition: jevois.c:421
static void jevois_send_message(void)
Definition: jevois.c:147
uint8_t nb
Definition: jevois.c:50
struct jevois_t jevois
Definition: jevois.c:79
void jevois_report(void)
Definition: jevois.c:82
int jevois_mapping_setting
Definition: jevois.c:36
void jevois_event(void)
Definition: jevois.c:402
int16_t coord[JEVOIS_MAX_COORD]
Definition: jevois.c:51
int jevois_extract_nb(char *in)
Extract a number from jevoid ID field.
Definition: jevois.c:130
uint16_t dim[3]
Definition: jevois.c:52
#define JEVOIS_CHECK_DELIM(_c)
Definition: jevois.c:44
void jevois_send_string(char *s)
Generic function to send a string command to Jevois.
Definition: jevois.c:412
struct jevois_msg_t msg
Definition: jevois.c:75
void jevois_send_state(void)
Send state to camera.
Definition: jevois.c:445
struct FloatQuat quat
Definition: jevois.c:53
uint8_t n
Definition: jevois.c:74
#define JEVOIS_MAX_COORD
Definition: jevois.c:42
#define JEVOIS_MAX_LEN
Definition: jevois.c:40
bool data_available
Definition: jevois.c:76
void jevois_init(void)
Definition: jevois.c:113
jevois_state
Definition: jevois.c:58
@ JV_QUAT
Definition: jevois.c:65
@ JV_DIM
Definition: jevois.c:64
@ JV_SIZE
Definition: jevois.c:62
@ JV_EXTRA
Definition: jevois.c:66
@ JV_TYPE
Definition: jevois.c:60
@ JV_COORD
Definition: jevois.c:63
@ JV_ID
Definition: jevois.c:61
@ JV_SYNC
Definition: jevois.c:59
enum jevois_state state
Definition: jevois.c:71
#define JEVOIS_MSG_D2
Definition: jevois.h:37
#define JEVOIS_MSG_T3
Definition: jevois.h:39
#define JEVOIS_MSG_F3
Definition: jevois.h:42
#define JEVOIS_HFOV
Camera horizontal FOV From datasheet it should be 65deg, but it seems that better results are acheive...
Definition: jevois.h:52
#define JEVOIS_VFOV
Camera vertical FOV Camera has a 4/3 ratio.
Definition: jevois.h:59
#define JEVOIS_MSG_F2
Definition: jevois.h:38
#define JEVOIS_MSG_N1
Definition: jevois.h:33
#define JEVOIS_MSG_D1
Definition: jevois.h:34
#define JEVOIS_NORM
Normalized data from JEVOIS are between -1000 and 1000.
Definition: jevois.h:45
#define JEVOIS_MSG_N3
Definition: jevois.h:40
#define JEVOIS_MSG_N2
Definition: jevois.h:36
#define JEVOIS_MSG_D3
Definition: jevois.h:41
#define JEVOIS_MSG_T1
JEVOIS messages types.
Definition: jevois.h:32
#define JEVOIS_MSG_T2
Definition: jevois.h:35
static uint32_t s
void uart_put_byte(struct uart_periph *periph, long fd, uint8_t data)
Definition: uart_arch.c:306
int uart_char_available(struct uart_periph *p)
Check UART for available chars in receive buffer.
Definition: uart_arch.c:357
uint8_t uart_getch(struct uart_periph *p)
Definition: uart_arch.c:348
Paparazzi floating point algebra.
float y
in meters
float x
in meters
float z
in meters
vector in East North Up coordinates Units: meters
arch independent UART (Universal Asynchronous Receiver/Transmitter) API
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
Definition: vl53l1_types.h:88
short int16_t
Typedef defining 16 bit short type.
Definition: vl53l1_types.h:93
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98