Galaxis Codebase  1.0.0
Team Galaxis software stack for the Carolo Cup 2023 - ROS2 based software
marvelmind.c
Go to the documentation of this file.
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #ifdef WIN32
5 #include <windows.h>
6 #include <process.h>
7 #else
8 #include <unistd.h>
9 #include <termios.h>
10 #include <fcntl.h>
11 #include <pthread.h>
12 #include <sys/poll.h>
13 #endif // WIN32
14 #include "marvelmind.h"
15 
17 // Calculate CRC (Modbus) for array of bytes
18 // buf: input buffer
19 // len: size of buffer
20 // returncode: CRC value
22 uint16_t CalcCrcModbus_(uint8_t* buf, int len) {
23  uint16_t crc = 0xFFFF;
24  int pos;
25  for(pos = 0; pos < len; pos++) {
26  crc ^= (uint16_t)buf[pos]; // XOR byte into least sig. byte of crc
27  int i;
28  for(i = 8; i != 0; i--) // Loop over each bit
29  {
30  if((crc & 0x0001) != 0) // If the LSB is set
31  {
32  crc >>= 1; // Shift right and XOR 0xA001
33  crc ^= 0xA001;
34  } else // Else LSB is not set
35  crc >>= 1; // Just shift right
36  }
37  }
38  return crc;
39 }
40 
41 #ifdef WIN32
42 #define SERIAL_PORT_HANDLE HANDLE
43 #define PORT_NOT_OPENED INVALID_HANDLE_VALUE
44 // Open Serial Port (Windows only)
46 // portFileName: alias of port (e.g. "COM3"). Add prefix "\\\\.\\" before alias
47 // to open higher ports (e.g. COM12)
48 // baudrate: baudRate rate (e.g. 19200)
49 // verbose: print errors
50 // returncode: valid handle if port is successfully opened or
51 // INVALID_HANDLE_VALUE on error
53 HANDLE OpenSerialPort_(const char* portFileName, uint32_t baudrate, bool verbose) {
54  HANDLE ttyHandle = CreateFile(TEXT(portFileName), GENERIC_READ, 0,
55  NULL, OPEN_EXISTING, 0 /*FILE_FLAG_OVERLAPPED*/, NULL);
56  if(ttyHandle == INVALID_HANDLE_VALUE) {
57  if(verbose)
58  puts("Error: unable to open serial connection "
59  "(possibly serial port is not available)");
60  return INVALID_HANDLE_VALUE;
61  }
62  COMMTIMEOUTS timeouts = { 3000, 3000, 3000, 3000, 3000 };
63  bool returnCode = SetCommTimeouts(ttyHandle, &timeouts);
64  if(!returnCode) {
65  if(verbose)
66  puts("Error: unable to set serial port timeouts");
67  CloseHandle(ttyHandle);
68  return INVALID_HANDLE_VALUE;
69  }
70  DCB dcb = { 0 };
71  returnCode = GetCommState(ttyHandle, &dcb);
72  if(!returnCode) {
73  if(verbose)
74  puts("Error: unable to get serial port parameters");
75  CloseHandle(ttyHandle);
76  return INVALID_HANDLE_VALUE;
77  }
78  dcb.BaudRate = baudrate;
79  dcb.fAbortOnError = true;
80  returnCode = SetCommState(ttyHandle, &dcb);
81  if(!returnCode) {
82  if(verbose)
83  puts("Error: unable to set serial port parameters");
84  CloseHandle(ttyHandle);
85  return INVALID_HANDLE_VALUE;
86  }
87  return ttyHandle;
88 }
89 #else
90 // Converts baudrate value to baudRate code (Linux only)
92 // baudrate: value of baudRate rate (e.g. 19200)
93 // verbose: show errors
94 // returncode: code of baudRate rate (e.g. B19200)
96 uint32_t _GetBaudCode(uint32_t baudrate, bool verbose) {
97  switch(baudrate) {
98  case 50:
99  return B50;
100  case 75:
101  return B75;
102  case 110:
103  return B110;
104  case 134:
105  return B134;
106  case 150:
107  return B150;
108  case 200:
109  return B200;
110  case 300:
111  return B300;
112  case 600:
113  return B600;
114  case 1200:
115  return B1200;
116  case 1800:
117  return B1800;
118  case 2400:
119  return B2400;
120  case 4800:
121  return B4800;
122  case 9600:
123  return B9600;
124  case 19200:
125  return B19200;
126  case 38400:
127  return B38400;
128  case 57600:
129  return B57600;
130  case 115200:
131  return B115200;
132  case 230400:
133  return B230400;
134  case 460800:
135  return B460800;
136  case 500000:
137  return B500000;
138  case 576000:
139  return B576000;
140  case 921600:
141  return B921600;
142  case 1000000:
143  return B1000000;
144  case 1152000:
145  return B1152000;
146  default:
147  if(verbose)
148  printf("Warning: unsupported baudrate %u. Using 9600.\n",
149  baudrate);
150  return B9600;
151  }
152 }
153 
154 #define SERIAL_PORT_HANDLE int
155 #define PORT_NOT_OPENED -1
156 // Open Serial Port (Linux only)
158 // portFileName: alias of port (e.g. "/dev/ttyACM0")
159 // baudrate: baudRate rate (e.g. 19200)
160 // verbose: show errors
161 // returncode: valid handle if port is successfully opened or -1 on error
163 int OpenSerialPort_(const char* portFileName, uint32_t baudrate, bool verbose) {
164  int ttyHandle = open(portFileName, O_RDWR | O_NONBLOCK | O_NDELAY);
165  if(ttyHandle < 0) {
166  if(verbose)
167  puts("Error: unable to open serial connection "
168  "(possibly serial port is not available)");
169  return -1;
170  }
171  struct termios ttyCtrl;
172  memset(&ttyCtrl, 0, sizeof ttyCtrl);
173  if(tcgetattr(ttyHandle, &ttyCtrl) != 0) {
174  if(verbose)
175  puts("Error: unable to get serial port parameters");
176  return -1;
177  }
178 
179  uint32_t baudCode = _GetBaudCode(baudrate, verbose);
180  cfsetospeed(&ttyCtrl, baudCode);
181  cfsetispeed(&ttyCtrl, baudCode);
182  // 8N1, no flow control
183  ttyCtrl.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS);
184  ttyCtrl.c_cflag |= CS8;
185  // no signaling chars, no echo, no canonical processing
186  ttyCtrl.c_lflag = 0;
187  ttyCtrl.c_oflag = 0; // no remapping, no delays
188  ttyCtrl.c_cc[VMIN] = 0; // read doesn't block
189  ttyCtrl.c_cc[VTIME] = 30; // 3 seconds read timeout
190  ttyCtrl.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
191  ttyCtrl.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
192  ttyCtrl.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // make raw
193  ttyCtrl.c_oflag &= ~OPOST; // make raw
194  tcflush(ttyHandle, TCIFLUSH); // Flush port
195  if(tcsetattr(ttyHandle, TCSANOW, &ttyCtrl) != 0) {
196  if(verbose)
197  puts("Error: unable to set serial port parameters");
198  return -1;
199  }
200  return ttyHandle;
201 }
202 #endif
203 
204 enum {
207 };
208 
210 
211 static int16_t get_int16(uint8_t* buffer) {
212  int16_t res = buffer[0] |
213  (((uint16_t)buffer[1]) << 8);
214 
215  return res;
216 }
217 
218 static uint32_t get_uint32(uint8_t* buffer) {
219  uint32_t res = buffer[0] |
220  (((uint32_t)buffer[1]) << 8) |
221  (((uint32_t)buffer[2]) << 16) |
222  (((uint32_t)buffer[3]) << 24);
223 
224  return res;
225 }
226 
227 static int32_t get_int32(uint8_t* buffer) {
228  int32_t res = buffer[0] |
229  (((uint32_t)buffer[1]) << 8) |
230  (((uint32_t)buffer[2]) << 16) |
231  (((uint32_t)buffer[3]) << 24);
232 
233  return res;
234 }
235 
237 // Thread function started by MarvelmindHedge_start
239 
240 static uint8_t markPositionReady(struct MarvelmindHedge* hedge) {
241  uint8_t ind = hedge->lastValues_next;
242  uint8_t indCur = ind;
243 
244  hedge->positionBuffer[ind].ready =
245  true;
246  hedge->positionBuffer[ind].processed =
247  false;
248  ind++;
249  if(ind >= MAX_BUFFERED_POSITIONS)
250  ind = 0;
252  hedge->lastValuesCount_++;
253  hedge->haveNewValues_ = true;
254 
255  hedge->lastValues_next = ind;
256 
257  return indCur;
258 }
259 
260 static struct PositionValue process_position_datagram(struct MarvelmindHedge* hedge, uint8_t* buffer) {
261  uint8_t ind = hedge->lastValues_next;
262 
263  hedge->positionBuffer[ind].address =
264  buffer[16];
265  hedge->positionBuffer[ind].timestamp =
266  buffer[5] |
267  (((uint32_t)buffer[6]) << 8) |
268  (((uint32_t)buffer[7]) << 16) |
269  (((uint32_t)buffer[8]) << 24);
270 
271  int16_t vx = buffer[9] |
272  (((uint16_t)buffer[10]) << 8);
273  hedge->positionBuffer[ind].x = vx * 10; // millimeters
274 
275  int16_t vy = buffer[11] |
276  (((uint16_t)buffer[12]) << 8);
277  hedge->positionBuffer[ind].y = vy * 10; // millimeters
278 
279  int16_t vz = buffer[13] |
280  (((uint16_t)buffer[14]) << 8);
281  hedge->positionBuffer[ind].z = vz * 10; // millimeters
282 
283  uint16_t vang = buffer[17] |
284  (((uint16_t)buffer[18]) << 8);
285  hedge->positionBuffer[ind].angle = ((float)(vang & 0x0fff)) / 10.0f;
286 
287  hedge->positionBuffer[ind].highResolution = false;
288 
289  ind = markPositionReady(hedge);
290 
291  return hedge->positionBuffer[ind];
292 }
293 
294 static struct PositionValue process_position_highres_datagram(struct MarvelmindHedge* hedge, uint8_t* buffer) {
295  uint8_t ind = hedge->lastValues_next;
296 
297  hedge->positionBuffer[ind].address =
298  buffer[22];
299  hedge->positionBuffer[ind].timestamp =
300  buffer[5] |
301  (((uint32_t)buffer[6]) << 8) |
302  (((uint32_t)buffer[7]) << 16) |
303  (((uint32_t)buffer[8]) << 24);
304 
305  int32_t vx = buffer[9] |
306  (((uint32_t)buffer[10]) << 8) |
307  (((uint32_t)buffer[11]) << 16) |
308  (((uint32_t)buffer[12]) << 24);
309  hedge->positionBuffer[ind].x = vx;
310 
311  int32_t vy = buffer[13] |
312  (((uint32_t)buffer[14]) << 8) |
313  (((uint32_t)buffer[15]) << 16) |
314  (((uint32_t)buffer[16]) << 24);
315  hedge->positionBuffer[ind].y = vy;
316 
317  int32_t vz = buffer[17] |
318  (((uint32_t)buffer[18]) << 8) |
319  (((uint32_t)buffer[19]) << 16) |
320  (((uint32_t)buffer[20]) << 24);
321  hedge->positionBuffer[ind].z = vz;
322 
323  uint16_t vang = buffer[23] |
324  (((uint16_t)buffer[24]) << 8);
325  hedge->positionBuffer[ind].angle = ((float)(vang & 0x0fff)) / 10.0f;
326 
327  hedge->positionBuffer[ind].highResolution = true;
328 
329  ind = markPositionReady(hedge);
330 
331  return hedge->positionBuffer[ind];
332 }
333 
334 static struct StationaryBeaconPosition* getOrAllocBeacon(struct MarvelmindHedge* hedge, uint8_t address) {
335  uint8_t i;
336  uint8_t n_used = hedge->positionsBeacons.numBeacons;
337 
338  if(n_used != 0)
339  for(i = 0; i < n_used; i++) {
340  if(hedge->positionsBeacons.beacons[i].address == address) {
341  return &hedge->positionsBeacons.beacons[i];
342  }
343  }
344 
345  if(n_used >= (MAX_STATIONARY_BEACONS - 1))
346  return NULL;
347 
348  hedge->positionsBeacons.numBeacons = (n_used + 1);
349  return &hedge->positionsBeacons.beacons[n_used];
350 }
351 
352 static void process_beacons_positions_datagram(struct MarvelmindHedge* hedge, uint8_t* buffer) {
353  uint8_t n = buffer[5]; // number of beacons in packet
354  uint8_t i, ofs;
355  uint8_t address;
356  int16_t x, y, z;
357  struct StationaryBeaconPosition* b;
358 
359  if((1 + n * 8) != buffer[4])
360  return; // incorrect size
361 
362  for(i = 0; i < n; i++) {
363  ofs = 6 + i * 8;
364 
365  address = buffer[ofs + 0];
366  x = buffer[ofs + 1] |
367  (((uint16_t)buffer[ofs + 2]) << 8);
368  y = buffer[ofs + 3] |
369  (((uint16_t)buffer[ofs + 4]) << 8);
370  z = buffer[ofs + 5] |
371  (((uint16_t)buffer[ofs + 6]) << 8);
372 
373  b = getOrAllocBeacon(hedge, address);
374  if(b != NULL) {
375  b->address = address;
376  b->x = x * 10; // millimeters
377  b->y = y * 10; // millimeters
378  b->z = z * 10; // millimeters
379 
380  b->highResolution = false;
381 
382  hedge->positionsBeacons.updated = true;
383  }
384  }
385 }
386 
387 static void process_beacons_positions_highres_datagram(struct MarvelmindHedge* hedge, uint8_t* buffer) {
388  uint8_t n = buffer[5]; // number of beacons in packet
389  uint8_t i, ofs;
390  uint8_t address;
391  int32_t x, y, z;
392  struct StationaryBeaconPosition* b;
393 
394  if((1 + n * 14) != buffer[4])
395  return; // incorrect size
396 
397  for(i = 0; i < n; i++) {
398  ofs = 6 + i * 14;
399 
400  address = buffer[ofs + 0];
401  x = buffer[ofs + 1] |
402  (((uint32_t)buffer[ofs + 2]) << 8) |
403  (((uint32_t)buffer[ofs + 3]) << 16) |
404  (((uint32_t)buffer[ofs + 4]) << 24);
405  y = buffer[ofs + 5] |
406  (((uint32_t)buffer[ofs + 6]) << 8) |
407  (((uint32_t)buffer[ofs + 7]) << 16) |
408  (((uint32_t)buffer[ofs + 8]) << 24);
409  z = buffer[ofs + 9] |
410  (((uint32_t)buffer[ofs + 10]) << 8) |
411  (((uint32_t)buffer[ofs + 11]) << 16) |
412  (((uint32_t)buffer[ofs + 12]) << 24);
413 
414  b = getOrAllocBeacon(hedge, address);
415  if(b != NULL) {
416  b->address = address;
417  b->x = x;
418  b->y = y;
419  b->z = z;
420 
421  b->highResolution = true;
422 
423  hedge->positionsBeacons.updated = true;
424  }
425  }
426 }
427 
428 static void process_imu_raw_datagram(struct MarvelmindHedge* hedge, uint8_t* buffer) {
429  uint8_t* dataBuf = &buffer[5];
430 
431  hedge->rawIMU.acc_x = get_int16(&dataBuf[0]);
432  hedge->rawIMU.acc_y = get_int16(&dataBuf[2]);
433  hedge->rawIMU.acc_z = get_int16(&dataBuf[4]);
434 
435  //
436  hedge->rawIMU.gyro_x = get_int16(&dataBuf[6]);
437  hedge->rawIMU.gyro_y = get_int16(&dataBuf[8]);
438  hedge->rawIMU.gyro_z = get_int16(&dataBuf[10]);
439 
440  //
441  hedge->rawIMU.compass_x = get_int16(&dataBuf[12]);
442  hedge->rawIMU.compass_y = get_int16(&dataBuf[14]);
443  hedge->rawIMU.compass_z = get_int16(&dataBuf[16]);
444 
445  hedge->rawIMU.timestamp = get_uint32(&dataBuf[24]);
446 
447  hedge->rawIMU.updated = true;
448 }
449 
450 static void process_imu_fusion_datagram(struct MarvelmindHedge* hedge, uint8_t* buffer) {
451  uint8_t* dataBuf = &buffer[5];
452 
453  hedge->fusionIMU.x = get_int32(&dataBuf[0]);
454  hedge->fusionIMU.y = get_int16(&dataBuf[4]);
455  hedge->fusionIMU.z = get_int16(&dataBuf[8]);
456 
457  hedge->fusionIMU.qw = get_int16(&dataBuf[12]);
458  hedge->fusionIMU.qx = get_int16(&dataBuf[14]);
459  hedge->fusionIMU.qy = get_int16(&dataBuf[16]);
460  hedge->fusionIMU.qz = get_int16(&dataBuf[18]);
461 
462  hedge->fusionIMU.vx = get_int16(&dataBuf[20]);
463  hedge->fusionIMU.vy = get_int16(&dataBuf[22]);
464  hedge->fusionIMU.vz = get_int16(&dataBuf[24]);
465 
466  hedge->fusionIMU.ax = get_int16(&dataBuf[26]);
467  hedge->fusionIMU.ay = get_int16(&dataBuf[28]);
468  hedge->fusionIMU.az = get_int16(&dataBuf[30]);
469 
470  hedge->fusionIMU.timestamp = get_uint32(&dataBuf[34]);
471 
472  hedge->fusionIMU.updated = true;
473 }
474 
475 static void process_raw_distances_datagram(struct MarvelmindHedge* hedge, uint8_t* buffer) {
476  uint8_t* dataBuf = &buffer[5];
477  uint8_t ofs, i;
478 
479  hedge->rawDistances.address_hedge = dataBuf[0];
480 
481  ofs = 1;
482  for(i = 0; i < 4; i++) {
483  hedge->rawDistances.distances[i].address_beacon = dataBuf[ofs + 0];
484  hedge->rawDistances.distances[i].distance = get_uint32(&dataBuf[ofs + 1]);
485  ofs += 6;
486  }
487 
488  hedge->rawDistances.updated = true;
489 }
490 
492 
493 void
494 #ifndef WIN32
495  *
496 #endif // WIN32
497  Marvelmind_Thread_(void* param) {
498  struct MarvelmindHedge* hedge = (struct MarvelmindHedge*)param;
499  struct PositionValue curPosition;
500  uint8_t input_buffer[256];
501  uint8_t recvState = RECV_HDR; // current state of receive data
502  uint8_t nBytesInBlockReceived = 0; // bytes received
503  uint16_t dataId;
504 #ifndef WIN32
505  struct pollfd fds[1];
506  int pollrc;
507 #endif
508 
510  hedge->baudRate, hedge->verbose);
511  if(ttyHandle == PORT_NOT_OPENED)
512  hedge->terminationRequired = true;
513  else if(hedge->verbose)
514  printf("Opened serial port %s with baudrate %u\n",
515  hedge->ttyFileName, hedge->baudRate);
516 
517  while(hedge->terminationRequired == false) {
518  uint8_t receivedChar;
519  bool readSuccessed = true;
520 #ifdef WIN32
521  DWORD nBytesRead;
522  OVERLAPPED osReader = { 0 };
523 
524  osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
525  if(osReader.hEvent == NULL) {
526  printf("Failed create event\n");
527  hedge->terminationRequired = true;
528  continue;
529  }
530 
531  readSuccessed = ReadFile(ttyHandle, &receivedChar, 1, &nBytesRead, NULL); //&osReader);
532  /* if (!readSuccessed)
533  {
534  dwRes = WaitForSingleObject(osReader.hEvent, 1000);
535  if (dwRes == WAIT_OBJECT_0)
536  {
537  if (GetOverlappedResult(ttyHandle, &osReader, &nBytesRead, FALSE))
538  {
539  readSuccessed= true;
540  }
541  }
542  }
543 */
544  CloseHandle(osReader.hEvent);
545 #else
546  int32_t nBytesRead;
547  fds[0].fd = ttyHandle;
548  fds[0].events = POLLIN;
549  pollrc = poll(fds, 1, 1000);
550  if(pollrc <= 0)
551  continue;
552  if((fds[0].revents & POLLIN) == 0)
553  continue;
554 
555  nBytesRead = read(ttyHandle, &receivedChar, 1);
556  if(nBytesRead < 0)
557  readSuccessed = false;
558 #endif
559  if(nBytesRead && readSuccessed) {
560  bool goodByte = false;
561  input_buffer[nBytesInBlockReceived] = receivedChar;
562  switch(recvState) {
563  case RECV_HDR:
564  switch(nBytesInBlockReceived) {
565  case 0:
566  goodByte = (receivedChar == 0xff);
567  break;
568  case 1:
569  goodByte = (receivedChar == 0x47);
570  break;
571  case 2:
572  goodByte = true;
573  break;
574  case 3:
575  dataId = (((uint16_t)receivedChar) << 8) + input_buffer[2];
576  goodByte = (dataId == POSITION_DATAGRAM_ID) ||
577  (dataId == BEACONS_POSITIONS_DATAGRAM_ID) ||
578  (dataId == POSITION_DATAGRAM_HIGHRES_ID) ||
580  (dataId == IMU_RAW_DATAGRAM_ID) ||
581  (dataId == IMU_FUSION_DATAGRAM_ID) ||
583  break;
584  case 4:
585  switch(dataId) {
587  goodByte = (receivedChar == 0x10);
588  break;
591  goodByte = true;
592  break;
594  goodByte = (receivedChar == 0x16);
595  break;
596  case IMU_RAW_DATAGRAM_ID:
597  goodByte = (receivedChar == 0x20);
598  break;
600  goodByte = (receivedChar == 0x2a);
601  break;
603  goodByte = (receivedChar == 0x20);
604  break;
605  }
606  if(goodByte)
607  recvState = RECV_DGRAM;
608  break;
609  }
610  if(goodByte) {
611  // correct header byte
612  nBytesInBlockReceived++;
613  } else {
614  // ...or incorrect
615  recvState = RECV_HDR;
616  nBytesInBlockReceived = 0;
617  }
618  break;
619  case RECV_DGRAM:
620  nBytesInBlockReceived++;
621  if(nBytesInBlockReceived >= 7 + input_buffer[4]) {
622  // parse dgram
623  uint16_t blockCrc =
624  CalcCrcModbus_(input_buffer, nBytesInBlockReceived);
625  if(blockCrc == 0) {
626 #ifdef WIN32
627  EnterCriticalSection(&hedge->lock_);
628 #else
629  pthread_mutex_lock(&hedge->lock_);
630 #endif
631  switch(dataId) {
633  // add to positionBuffer
634  curPosition = process_position_datagram(hedge, input_buffer);
635  break;
637  process_beacons_positions_datagram(hedge, input_buffer);
638  break;
640  // add to positionBuffer
641  curPosition = process_position_highres_datagram(hedge, input_buffer);
642  break;
644  process_beacons_positions_highres_datagram(hedge, input_buffer);
645  break;
646  case IMU_RAW_DATAGRAM_ID:
647  process_imu_raw_datagram(hedge, input_buffer);
648  break;
650  process_imu_fusion_datagram(hedge, input_buffer);
651  break;
653  process_raw_distances_datagram(hedge, input_buffer);
654  break;
655  }
656 #ifdef WIN32
657  LeaveCriticalSection(&hedge->lock_);
658 #else
659  pthread_mutex_unlock(&hedge->lock_);
660 #endif
661  // callback
662  if(hedge->anyInputPacketCallback) {
663  hedge->anyInputPacketCallback();
664  }
665 
666  if(hedge->receiveDataCallback) {
667  if(dataId == POSITION_DATAGRAM_ID) {
668  hedge->receiveDataCallback(curPosition);
669  }
670  }
671  }
672  // and repeat
673  recvState = RECV_HDR;
674  nBytesInBlockReceived = 0;
675  }
676  }
677  }
678  }
679 #ifndef WIN32
680  return NULL;
681 #endif
682 }
683 
685 // Create an initialize MarvelmindHedge structure
686 // returncode: pointer to structure on success or NULL on error
689  struct MarvelmindHedge* hedge = malloc(sizeof(struct MarvelmindHedge));
690  if(hedge) {
692  hedge->baudRate = 9600;
693  hedge->positionBuffer = NULL;
694  hedge->verbose = false;
695  hedge->receiveDataCallback = NULL;
696  hedge->anyInputPacketCallback = NULL;
697  hedge->lastValuesCount_ = 0;
698  hedge->lastValues_next = 0;
699  hedge->haveNewValues_ = false;
700  hedge->terminationRequired = false;
701 
702  hedge->rawIMU.updated = false;
703  hedge->fusionIMU.updated = false;
704  hedge->rawDistances.updated = false;
705 #ifdef WIN32
706  InitializeCriticalSection(&hedge->lock_);
707 #else
708  pthread_mutex_init(&hedge->lock_, NULL);
709 #endif
710  } else
711  puts("Not enough memory");
712  return hedge;
713 }
714 
716 // Initialize and start work thread
719  uint8_t i;
720 
721  hedge->positionBuffer =
722  malloc(sizeof(struct PositionValue) * MAX_BUFFERED_POSITIONS);
723  if(hedge->positionBuffer == NULL) {
724  if(hedge->verbose)
725  puts("Not enough memory");
726  hedge->terminationRequired = true;
727  return;
728  }
729  for(i = 0; i < MAX_BUFFERED_POSITIONS; i++) {
730  hedge->positionBuffer[i].ready = false;
731  hedge->positionBuffer[i].processed = false;
732  }
733  hedge->positionsBeacons.numBeacons = 0;
734  hedge->positionsBeacons.updated = false;
735 
736 #ifdef WIN32
737  _beginthread(Marvelmind_Thread_, 0, hedge);
738 #else
739  pthread_create(&hedge->thread_, NULL, Marvelmind_Thread_, hedge);
740 #endif
741 }
742 
744 // Write average position coordinates
745 // hedge: MarvelmindHedge structure
746 // position: pointer to PositionValue for write coordinates
747 // returncode: true if position is valid
750  struct PositionValue* position,
751  uint8_t address) {
752  uint8_t i;
753  int32_t avg_x = 0, avg_y = 0, avg_z = 0;
754  double avg_ang = 0.0;
755  uint32_t max_timestamp = 0;
756  bool position_valid;
757  bool highRes = false;
758 #ifdef WIN32
759  EnterCriticalSection(&hedge->lock_);
760 #else
761  pthread_mutex_lock(&hedge->lock_);
762 #endif
763  if(hedge->lastValuesCount_) {
764  uint8_t real_values_count = MAX_BUFFERED_POSITIONS;
765  uint8_t nFound = 0;
766  if(hedge->lastValuesCount_ < real_values_count)
767  real_values_count = hedge->lastValuesCount_;
768  for(i = 0; i < real_values_count; i++) {
769  if(address != 0)
770  if(hedge->positionBuffer[i].address != address)
771  continue;
772  if(!hedge->positionBuffer[i].ready)
773  continue;
774  if(hedge->positionBuffer[i].processed)
775  continue;
776  if(address == 0)
777  address = hedge->positionBuffer[i].address;
778  nFound++;
779  avg_x += hedge->positionBuffer[i].x;
780  avg_y += hedge->positionBuffer[i].y;
781  avg_z += hedge->positionBuffer[i].z;
782  avg_ang += hedge->positionBuffer[i].angle;
783  if(hedge->positionBuffer[i].highResolution)
784  highRes = true;
785  hedge->positionBuffer[i].processed = true;
786  if(hedge->positionBuffer[i].timestamp > max_timestamp)
787  max_timestamp = hedge->positionBuffer[i].timestamp;
788  }
789  if(nFound != 0) {
790  avg_x /= nFound;
791  avg_y /= nFound;
792  avg_z /= nFound;
793  avg_ang /= nFound;
794  position_valid = true;
795  } else {
796  position_valid = false;
797  }
798  } else
799  position_valid = false;
800 #ifdef WIN32
801  LeaveCriticalSection(&hedge->lock_);
802 #else
803  pthread_mutex_unlock(&hedge->lock_);
804 #endif
805  position->address = address;
806  position->x = avg_x;
807  position->y = avg_y;
808  position->z = avg_z;
809  position->angle = avg_ang;
810  position->timestamp = max_timestamp;
811  position->ready = position_valid;
812  position->highResolution = highRes;
813  return position_valid;
814 }
815 
817  struct PositionValue* position) {
818  return getPositionFromMarvelmindHedgeByAddress(hedge, position, 0);
819 }
820 
822 // Print average position coordinates
823 // onlyNew: print only new positions
826  bool onlyNew) {
827  uint8_t i, j;
828  double xm, ym, zm;
829 
830  if(hedge->haveNewValues_ || (!onlyNew)) {
831  struct PositionValue position;
832  uint8_t addresses[MAX_BUFFERED_POSITIONS];
833  uint8_t addressesNum = 0;
834 
835  for(i = 0; i < MAX_BUFFERED_POSITIONS; i++) {
836  uint8_t address = hedge->positionBuffer[i].address;
837  bool alreadyProcessed = false;
838  if(addressesNum != 0)
839  for(j = 0; j < addressesNum; j++) {
840  if(address == addresses[j]) {
841  alreadyProcessed = true;
842  break;
843  }
844  }
845  if(alreadyProcessed)
846  continue;
847  addresses[addressesNum++] = address;
848 
850  xm = ((double)position.x) / 1000.0;
851  ym = ((double)position.y) / 1000.0;
852  zm = ((double)position.z) / 1000.0;
853  if(position.ready) {
854  if(position.highResolution) {
855  printf("Address: %d, X: %.3f, Y: %.3f, Z: %.3f, Angle: %.1f at time T: %u\n",
856  position.address, xm, ym, zm, position.angle, position.timestamp);
857  } else {
858  printf("Address: %d, X: %.2f, Y: %.2f, Z: %.2f, Angle: %.1f at time T: %u\n",
859  position.address, xm, ym, zm, position.angle, position.timestamp);
860  }
861  }
862  hedge->haveNewValues_ = false;
863  }
864  }
865 }
866 
868 
870  struct StationaryBeaconsPositions* positions) {
871 #ifdef WIN32
872  EnterCriticalSection(&hedge->lock_);
873 #else
874  pthread_mutex_lock(&hedge->lock_);
875 #endif
876 
877  *positions = hedge->positionsBeacons;
878 
879 #ifdef WIN32
880  LeaveCriticalSection(&hedge->lock_);
881 #else
882  pthread_mutex_unlock(&hedge->lock_);
883 #endif
884 
885  return true;
886 }
887 
889  bool onlyNew) {
890  struct StationaryBeaconsPositions positions;
891  double xm, ym, zm;
892 
894 
895  if(positions.updated || (!onlyNew)) {
896  uint8_t i;
897  uint8_t n = hedge->positionsBeacons.numBeacons;
898  struct StationaryBeaconPosition* b;
899 
900  for(i = 0; i < n; i++) {
901  b = &positions.beacons[i];
902  xm = ((double)b->x) / 1000.0;
903  ym = ((double)b->y) / 1000.0;
904  zm = ((double)b->z) / 1000.0;
905  if(positions.beacons[i].highResolution) {
906  printf("Stationary beacon: address: %d, X: %.3f, Y: %.3f, Z: %.3f \n",
907  b->address, xm, ym, zm);
908  } else {
909  printf("Stationary beacon: address: %d, X: %.2f, Y: %.2f, Z: %.2f \n",
910  b->address, xm, ym, zm);
911  }
912  }
913 
914  hedge->positionsBeacons.updated = false;
915  }
916 }
917 
919 
921  struct RawDistances* rawDistances) {
922 #ifdef WIN32
923  EnterCriticalSection(&hedge->lock_);
924 #else
925  pthread_mutex_lock(&hedge->lock_);
926 #endif
927 
928  *rawDistances = hedge->rawDistances;
929 
930 #ifdef WIN32
931  LeaveCriticalSection(&hedge->lock_);
932 #else
933  pthread_mutex_unlock(&hedge->lock_);
934 #endif
935 
936  return true;
937 }
938 
940  bool onlyNew) {
941  struct RawDistances rawDistances;
942  uint8_t i;
943  float d_m;
944 
945  getRawDistancesFromMarvelmindHedge(hedge, &rawDistances);
946 
947  if(rawDistances.updated || (!onlyNew)) {
948  for(i = 0; i < 4; i++) {
949  if(rawDistances.distances[i].address_beacon != 0) {
950  d_m = rawDistances.distances[i].distance / 1000.0;
951  printf("Raw distance: %02d ==> %02d, Distance= %.3f \n",
952  (int)rawDistances.address_hedge,
953  (int)rawDistances.distances[i].address_beacon,
954  (float)d_m);
955  }
956  }
957 
958  hedge->rawDistances.updated = false;
959  }
960 }
961 
963 
965  struct RawIMUValue* rawIMU) {
966 #ifdef WIN32
967  EnterCriticalSection(&hedge->lock_);
968 #else
969  pthread_mutex_lock(&hedge->lock_);
970 #endif
971 
972  *rawIMU = hedge->rawIMU;
973 
974 #ifdef WIN32
975  LeaveCriticalSection(&hedge->lock_);
976 #else
977  pthread_mutex_unlock(&hedge->lock_);
978 #endif
979 
980  return true;
981 }
982 
984  bool onlyNew) {
985  struct RawIMUValue rawIMU;
986 
987  getRawIMUFromMarvelmindHedge(hedge, &rawIMU);
988 
989  if(rawIMU.updated || (!onlyNew)) {
990  printf("Raw IMU: Timestamp: %08d, aX=%05d aY=%05d aZ=%05d gX=%05d gY=%05d gZ=%05d cX=%05d cY=%05d cZ=%05d \n",
991  (int)rawIMU.timestamp,
992  (int)rawIMU.acc_x, (int)rawIMU.acc_y, (int)rawIMU.acc_z,
993  (int)rawIMU.gyro_x, (int)rawIMU.gyro_y, (int)rawIMU.gyro_z,
994  (int)rawIMU.compass_x, (int)rawIMU.compass_y, (int)rawIMU.compass_z);
995 
996  hedge->rawIMU.updated = false;
997  }
998 }
999 
1001 
1003  struct FusionIMUValue* fusionIMU) {
1004 #ifdef WIN32
1005  EnterCriticalSection(&hedge->lock_);
1006 #else
1007  pthread_mutex_lock(&hedge->lock_);
1008 #endif
1009 
1010  *fusionIMU = hedge->fusionIMU;
1011 
1012 #ifdef WIN32
1013  LeaveCriticalSection(&hedge->lock_);
1014 #else
1015  pthread_mutex_unlock(&hedge->lock_);
1016 #endif
1017 
1018  return true;
1019 }
1020 
1022  bool onlyNew) {
1023  struct FusionIMUValue fusionIMU;
1024  float x_m, y_m, z_m;
1025  float qw, qx, qy, qz;
1026  float vx, vy, vz, ax, ay, az;
1027 
1028  getFusionIMUFromMarvelmindHedge(hedge, &fusionIMU);
1029 
1030  if(fusionIMU.updated || (!onlyNew)) {
1031  x_m = fusionIMU.x / 1000.0;
1032  y_m = fusionIMU.y / 1000.0;
1033  z_m = fusionIMU.z / 1000.0;
1034 
1035  qw = fusionIMU.qw / 10000.0;
1036  qx = fusionIMU.qx / 10000.0;
1037  qy = fusionIMU.qy / 10000.0;
1038  qz = fusionIMU.qz / 10000.0;
1039 
1040  vx = fusionIMU.vx / 1000.0;
1041  vy = fusionIMU.vy / 1000.0;
1042  vz = fusionIMU.vz / 1000.0;
1043 
1044  ax = fusionIMU.ax / 1000.0;
1045  ay = fusionIMU.ay / 1000.0;
1046  az = fusionIMU.az / 1000.0;
1047 
1048  printf("IMU fusion: Timestamp: %08d, X=%.3f Y= %.3f Z=%.3f q=%.3f,%.3f,%.3f,%.3f v=%.3f,%.3f,%.3f a=%.3f,%.3f,%.3f \n",
1049  (int)fusionIMU.timestamp,
1050  (float)x_m, (float)y_m, (float)z_m,
1051  (float)qw, (float)qx, (float)qy, (float)qz,
1052  (float)vx, (float)vy, (float)vz,
1053  (float)ax, (float)ay, (float)az);
1054 
1055  hedge->fusionIMU.updated = false;
1056  }
1057 }
1058 
1060 // Stop work thread
1063  hedge->terminationRequired = true;
1064  if(hedge->verbose)
1065  puts("stopping");
1066 #ifdef WIN32
1067  WaitForSingleObject(hedge->thread_, INFINITE);
1068 #else
1069  pthread_join(hedge->thread_, NULL);
1070 #endif
1071 }
1072 
1074 // Destroy structures to free memory (You must call stopMarvelmindHedge
1075 // first)
1078  if(hedge->positionBuffer)
1079  free(hedge->positionBuffer);
1080  free(hedge);
1081 }
StationaryBeaconPosition::x
int32_t x
Definition: marvelmind.h:76
MarvelmindHedge::positionsBeacons
struct StationaryBeaconsPositions positionsBeacons
Definition: marvelmind.h:103
RawIMUValue
Definition: marvelmind.h:22
MarvelmindHedge::anyInputPacketCallback
void(* anyInputPacketCallback)()
Definition: marvelmind.h:122
PositionValue::z
int32_t z
Definition: marvelmind.h:12
getFusionIMUFromMarvelmindHedge
bool getFusionIMUFromMarvelmindHedge(struct MarvelmindHedge *hedge, struct FusionIMUValue *fusionIMU)
Definition: marvelmind.c:1002
marvelmind.h
FusionIMUValue::y
int32_t y
Definition: marvelmind.h:42
MarvelmindHedge::fusionIMU
struct FusionIMUValue fusionIMU
Definition: marvelmind.h:106
MarvelmindHedge::terminationRequired
bool terminationRequired
Definition: marvelmind.h:118
MarvelmindHedge::lastValuesCount_
uint8_t lastValuesCount_
Definition: marvelmind.h:125
FusionIMUValue::z
int32_t z
Definition: marvelmind.h:43
FusionIMUValue::qx
int16_t qx
Definition: marvelmind.h:46
getPositionFromMarvelmindHedgeByAddress
static bool getPositionFromMarvelmindHedgeByAddress(struct MarvelmindHedge *hedge, struct PositionValue *position, uint8_t address)
Definition: marvelmind.c:749
getRawIMUFromMarvelmindHedge
bool getRawIMUFromMarvelmindHedge(struct MarvelmindHedge *hedge, struct RawIMUValue *rawIMU)
Definition: marvelmind.c:964
MarvelmindHedge::verbose
bool verbose
Definition: marvelmind.h:112
StationaryBeaconPosition::y
int32_t y
Definition: marvelmind.h:76
MarvelmindHedge
Definition: marvelmind.h:89
FusionIMUValue::qw
int16_t qw
Definition: marvelmind.h:45
RawIMUValue::acc_y
int16_t acc_y
Definition: marvelmind.h:24
createMarvelmindHedge
struct MarvelmindHedge * createMarvelmindHedge()
Definition: marvelmind.c:688
destroyMarvelmindHedge
void destroyMarvelmindHedge(struct MarvelmindHedge *hedge)
Definition: marvelmind.c:1077
BEACONS_POSITIONS_DATAGRAM_ID
#define BEACONS_POSITIONS_DATAGRAM_ID
Definition: marvelmind.h:138
FusionIMUValue::az
int16_t az
Definition: marvelmind.h:56
getStationaryBeaconsPositionsFromMarvelmindHedge
bool getStationaryBeaconsPositionsFromMarvelmindHedge(struct MarvelmindHedge *hedge, struct StationaryBeaconsPositions *positions)
Definition: marvelmind.c:869
RawIMUValue::gyro_x
int16_t gyro_x
Definition: marvelmind.h:27
MarvelmindHedge::thread_
pthread_t thread_
Definition: marvelmind.h:132
RawDistances::address_hedge
uint8_t address_hedge
Definition: marvelmind.h:68
MAX_STATIONARY_BEACONS
#define MAX_STATIONARY_BEACONS
Definition: marvelmind.h:80
get_int32
static int32_t get_int32(uint8_t *buffer)
Definition: marvelmind.c:227
StationaryBeaconsPositions::updated
bool updated
Definition: marvelmind.h:85
FusionIMUValue::x
int32_t x
Definition: marvelmind.h:41
FusionIMUValue::qy
int16_t qy
Definition: marvelmind.h:47
SERIAL_PORT_HANDLE
#define SERIAL_PORT_HANDLE
Definition: marvelmind.c:154
RawIMUValue::gyro_z
int16_t gyro_z
Definition: marvelmind.h:29
MarvelmindHedge::rawDistances
struct RawDistances rawDistances
Definition: marvelmind.h:108
getOrAllocBeacon
static struct StationaryBeaconPosition * getOrAllocBeacon(struct MarvelmindHedge *hedge, uint8_t address)
Definition: marvelmind.c:334
MarvelmindHedge::baudRate
uint32_t baudRate
Definition: marvelmind.h:98
FusionIMUValue
Definition: marvelmind.h:40
PositionValue::y
int32_t y
Definition: marvelmind.h:12
process_imu_fusion_datagram
static void process_imu_fusion_datagram(struct MarvelmindHedge *hedge, uint8_t *buffer)
Definition: marvelmind.c:450
RawDistanceItem::address_beacon
uint8_t address_beacon
Definition: marvelmind.h:64
getPositionFromMarvelmindHedge
bool getPositionFromMarvelmindHedge(struct MarvelmindHedge *hedge, struct PositionValue *position)
Definition: marvelmind.c:816
RawDistanceItem::distance
uint32_t distance
Definition: marvelmind.h:65
PositionValue
Definition: marvelmind.h:9
POSITION_DATAGRAM_HIGHRES_ID
#define POSITION_DATAGRAM_HIGHRES_ID
Definition: marvelmind.h:139
FusionIMUValue::qz
int16_t qz
Definition: marvelmind.h:48
StationaryBeaconPosition
Definition: marvelmind.h:74
RawIMUValue::updated
bool updated
Definition: marvelmind.h:37
CalcCrcModbus_
uint16_t CalcCrcModbus_(uint8_t *buf, int len)
Definition: marvelmind.c:22
IMU_FUSION_DATAGRAM_ID
#define IMU_FUSION_DATAGRAM_ID
Definition: marvelmind.h:143
RawIMUValue::compass_x
int16_t compass_x
Definition: marvelmind.h:31
PositionValue::address
uint8_t address
Definition: marvelmind.h:10
getRawDistancesFromMarvelmindHedge
bool getRawDistancesFromMarvelmindHedge(struct MarvelmindHedge *hedge, struct RawDistances *rawDistances)
Definition: marvelmind.c:920
MarvelmindHedge::positionBuffer
struct PositionValue * positionBuffer
Definition: marvelmind.h:101
MarvelmindHedge::ttyFileName
const char * ttyFileName
Definition: marvelmind.h:94
BEACON_RAW_DISTANCE_DATAGRAM_ID
#define BEACON_RAW_DISTANCE_DATAGRAM_ID
Definition: marvelmind.h:142
RawDistances::updated
bool updated
Definition: marvelmind.h:71
process_beacons_positions_highres_datagram
static void process_beacons_positions_highres_datagram(struct MarvelmindHedge *hedge, uint8_t *buffer)
Definition: marvelmind.c:387
StationaryBeaconPosition::highResolution
bool highResolution
Definition: marvelmind.h:78
MarvelmindHedge::haveNewValues_
bool haveNewValues_
Definition: marvelmind.h:127
printStationaryBeaconsPositionsFromMarvelmindHedge
void printStationaryBeaconsPositionsFromMarvelmindHedge(struct MarvelmindHedge *hedge, bool onlyNew)
Definition: marvelmind.c:888
printRawDistancesFromMarvelmindHedge
void printRawDistancesFromMarvelmindHedge(struct MarvelmindHedge *hedge, bool onlyNew)
Definition: marvelmind.c:939
RawIMUValue::acc_x
int16_t acc_x
Definition: marvelmind.h:23
markPositionReady
static uint8_t markPositionReady(struct MarvelmindHedge *hedge)
Definition: marvelmind.c:240
printRawIMUFromMarvelmindHedge
void printRawIMUFromMarvelmindHedge(struct MarvelmindHedge *hedge, bool onlyNew)
Definition: marvelmind.c:983
process_raw_distances_datagram
static void process_raw_distances_datagram(struct MarvelmindHedge *hedge, uint8_t *buffer)
Definition: marvelmind.c:475
RawIMUValue::compass_y
int16_t compass_y
Definition: marvelmind.h:32
process_imu_raw_datagram
static void process_imu_raw_datagram(struct MarvelmindHedge *hedge, uint8_t *buffer)
Definition: marvelmind.c:428
PositionValue::processed
bool processed
Definition: marvelmind.h:19
RawIMUValue::acc_z
int16_t acc_z
Definition: marvelmind.h:25
PositionValue::timestamp
uint32_t timestamp
Definition: marvelmind.h:11
printPositionFromMarvelmindHedge
void printPositionFromMarvelmindHedge(struct MarvelmindHedge *hedge, bool onlyNew)
Definition: marvelmind.c:825
MAX_BUFFERED_POSITIONS
#define MAX_BUFFERED_POSITIONS
Definition: marvelmind.h:88
PORT_NOT_OPENED
#define PORT_NOT_OPENED
Definition: marvelmind.c:155
get_int16
static int16_t get_int16(uint8_t *buffer)
Definition: marvelmind.c:211
DEFAULT_TTY_FILENAME
#define DEFAULT_TTY_FILENAME
Definition: marvelmind.h:179
StationaryBeaconsPositions::beacons
struct StationaryBeaconPosition beacons[MAX_STATIONARY_BEACONS]
Definition: marvelmind.h:83
IMU_RAW_DATAGRAM_ID
#define IMU_RAW_DATAGRAM_ID
Definition: marvelmind.h:141
RawDistances::distances
struct RawDistanceItem distances[4]
Definition: marvelmind.h:69
FusionIMUValue::updated
bool updated
Definition: marvelmind.h:60
process_beacons_positions_datagram
static void process_beacons_positions_datagram(struct MarvelmindHedge *hedge, uint8_t *buffer)
Definition: marvelmind.c:352
process_position_highres_datagram
static struct PositionValue process_position_highres_datagram(struct MarvelmindHedge *hedge, uint8_t *buffer)
Definition: marvelmind.c:294
FusionIMUValue::vy
int16_t vy
Definition: marvelmind.h:51
PositionValue::angle
double angle
Definition: marvelmind.h:14
RawDistances
Definition: marvelmind.h:67
StationaryBeaconsPositions
Definition: marvelmind.h:81
BEACONS_POSITIONS_DATAGRAM_HIGHRES_ID
#define BEACONS_POSITIONS_DATAGRAM_HIGHRES_ID
Definition: marvelmind.h:140
printFusionIMUFromMarvelmindHedge
void printFusionIMUFromMarvelmindHedge(struct MarvelmindHedge *hedge, bool onlyNew)
Definition: marvelmind.c:1021
FusionIMUValue::ax
int16_t ax
Definition: marvelmind.h:54
RawIMUValue::gyro_y
int16_t gyro_y
Definition: marvelmind.h:28
FusionIMUValue::ay
int16_t ay
Definition: marvelmind.h:55
get_uint32
static uint32_t get_uint32(uint8_t *buffer)
Definition: marvelmind.c:218
OpenSerialPort_
int OpenSerialPort_(const char *portFileName, uint32_t baudrate, bool verbose)
Definition: marvelmind.c:163
StationaryBeaconsPositions::numBeacons
uint8_t numBeacons
Definition: marvelmind.h:82
_GetBaudCode
uint32_t _GetBaudCode(uint32_t baudrate, bool verbose)
Definition: marvelmind.c:96
MarvelmindHedge::rawIMU
struct RawIMUValue rawIMU
Definition: marvelmind.h:105
StationaryBeaconPosition::z
int32_t z
Definition: marvelmind.h:76
MarvelmindHedge::lastValues_next
uint8_t lastValues_next
Definition: marvelmind.h:126
MarvelmindHedge::lock_
pthread_mutex_t lock_
Definition: marvelmind.h:133
FusionIMUValue::vz
int16_t vz
Definition: marvelmind.h:52
PositionValue::ready
bool ready
Definition: marvelmind.h:18
PositionValue::highResolution
bool highResolution
Definition: marvelmind.h:16
Marvelmind_Thread_
void * Marvelmind_Thread_(void *param)
Definition: marvelmind.c:497
StationaryBeaconPosition::address
uint8_t address
Definition: marvelmind.h:75
RECV_HDR
@ RECV_HDR
Definition: marvelmind.c:205
startMarvelmindHedge
void startMarvelmindHedge(struct MarvelmindHedge *hedge)
Definition: marvelmind.c:718
FusionIMUValue::timestamp
uint32_t timestamp
Definition: marvelmind.h:58
PositionValue::x
int32_t x
Definition: marvelmind.h:12
MarvelmindHedge::receiveDataCallback
void(* receiveDataCallback)(struct PositionValue position)
Definition: marvelmind.h:121
process_position_datagram
static struct PositionValue process_position_datagram(struct MarvelmindHedge *hedge, uint8_t *buffer)
Definition: marvelmind.c:260
FusionIMUValue::vx
int16_t vx
Definition: marvelmind.h:50
stopMarvelmindHedge
void stopMarvelmindHedge(struct MarvelmindHedge *hedge)
Definition: marvelmind.c:1062
RECV_DGRAM
@ RECV_DGRAM
Definition: marvelmind.c:206
POSITION_DATAGRAM_ID
#define POSITION_DATAGRAM_ID
Definition: marvelmind.h:137
RawIMUValue::compass_z
int16_t compass_z
Definition: marvelmind.h:33
RawIMUValue::timestamp
uint32_t timestamp
Definition: marvelmind.h:35