ISSDK  1.7
IoT Sensing Software Development Kit
output_stream.c
Go to the documentation of this file.
1 /*
2  * The Clear BSD License
3  * Copyright (c) 2015 - 2016, Freescale Semiconductor, Inc.
4  * Copyright 2016-2017 NXP
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without modification,
8  * are permitted (subject to the limitations in the disclaimer below) provided
9  * that the following conditions are met:
10  *
11  * o Redistributions of source code must retain the above copyright notice, this list
12  * of conditions and the following disclaimer.
13  *
14  * o Redistributions in binary form must reproduce the above copyright notice, this
15  * list of conditions and the following disclaimer in the documentation and/or
16  * other materials provided with the distribution.
17  *
18  * o Neither the name of the copyright holder nor the names of its
19  * contributors may be used to endorse or promote products derived from this
20  * software without specific prior written permission.
21  *
22  * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
27  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 /*! \file output_stream.c
36  \brief Implements streaming function for the status subsystem. See status.h
37 */
38 
39 #include "sensor_fusion.h" // top level magCal and sensor fusion interfaces
40 #include "control.h" // Command/Streaming interface - application specific
41 #include "debug.h" // for test purposes
42 #define MAXPACKETRATEHZ 40
43 #define RATERESOLUTION 1000
44 
45 ///////////////////////////////////////////////////////////////////////////////////////////////////////
46 
47 // UART packet drivers
48 ///////////////////////////////////////////////////////////////////////////////////////////////////////
49 // function appends a variable number of source bytes to a destimation buffer
50 // for transmission as the bluetooth packet
51 // bluetooth packets are delimited by inserting the special byte 0x7E at the start
52 // and end of packets. this function must therefore handle the case of 0x7E appearing
53 // as general data. this is done here with the substitutions:
54 // a) replace 0x7E by 0x7D and 0x5E (one byte becomes two)
55 // b) replace 0x7D by 0x7D and 0x5D (one byte becomes two)
56 // the inverse mapping must be performed at the application receiving the bluetooth stream: ie:
57 // replace 0x7D and 0x5E with 0x7E
58 // replace 0x7D and 0x5D with 0x7D
59 // NOTE: do not use this function to append the start and end bytes 0x7E to the bluetooth
60 // buffer. instead add the start and end bytes 0x7E explicitly as in:
61 
62 // sUARTOutputBuffer[iByteCount++] = 0x7E;
63 void sBufAppendItem(uint8_t *pDest, uint16_t *pIndex, uint8_t *pSource,
64  uint16_t iBytesToCopy)
65 {
66  uint16_t i; // loop counter
67 
68  // loop over number of bytes to add to the destination buffer
69  for (i = 0; i < iBytesToCopy; i++)
70  {
71  switch (pSource[i])
72  {
73  case 0x7E:
74  // special case 1: replace 0x7E (start and end byte) with 0x7D and 0x5E
75  pDest[(*pIndex)++] = 0x7D;
76  pDest[(*pIndex)++] = 0x5E;
77  break;
78 
79  case 0x7D:
80  // special case 2: replace 0x7D with 0x7D and 0x5D
81  pDest[(*pIndex)++] = 0x7D;
82  pDest[(*pIndex)++] = 0x5D;
83  break;
84 
85  default:
86  // general case, simply add this byte without change
87  pDest[(*pIndex)++] = pSource[i];
88  break;
89  }
90  }
91 
92  return;
93 }
94 
95 // utility function for sending int16_t zeros
96 void sBufAppendZeros(uint8_t *pDest, uint16_t *pIndex, uint16_t numZeros) {
97  int16_t scratch16 = 0;
98  uint16_t i;
99  for (i=0; i<numZeros; i++) {
100  sBufAppendItem(pDest, pIndex, (uint8_t *) &scratch16, 2);
101  }
102 }
103 // utility function for reading common algorithm parameters
105  Quaternion *fq,
106  int16_t *iPhi,
107  int16_t *iThe,
108  int16_t *iRho,
109  int16_t iOmega[],
110  uint16_t *isystick) {
111  *fq = data->fq;
112  iOmega[CHX] = (int16_t) (data->fOmega[CHX] * 20.0F);
113  iOmega[CHY] = (int16_t) (data->fOmega[CHY] * 20.0F);
114  iOmega[CHZ] = (int16_t) (data->fOmega[CHZ] * 20.0F);
115  *iPhi = (int16_t) (10.0F * data->fPhi);
116  *iThe = (int16_t) (10.0F * data->fThe);
117  *iRho = (int16_t) (10.0F * data->fRho);
118  *isystick = (uint16_t) (data->systick / 20);
119 }
120 
121 // throttle back by fractional multiplier
122 /// (OVERSAMPLE_RATIO * MAXPACKETRATEHZ) / SENSORFS
123 uint16_t throttle()
124 {
125  static int32 iThrottle = 0;
126  uint8_t skip;
127  // The UART (serial over USB and over Bluetooth)
128  // is limited to 115kbps which is more than adequate for the 31kbps
129  // needed at the default 25Hz output rate but insufficient for 100Hz or
130  // 200Hz output rates. There is little point is providing output data
131  // faster than 25Hz video rates but since the UARTs can
132  // support a higher rate, the limit is set to MAXPACKETRATEHZ=40Hz.
133 
134  // the increment applied to iThrottle is in the range 0 to (RATERESOLUTION - 1)
135  iThrottle += ((int32) MAXPACKETRATEHZ * (int32) RATERESOLUTION) / (int32) FUSION_HZ;
136  if (iThrottle >= RATERESOLUTION) {
137  // update the throttle counter and transmit the packets over UART (USB and Bluetooth)
138  iThrottle -= RATERESOLUTION;
139  skip = false;
140  } else {
141  skip = true;
142  }
143  return(skip);
144 }
145 
146 // set packets out over UART_A to shield / Bluetooth module and over UART_B to OpenSDA / USB
147 //#pragma diag_suppress=Pe177,Pe550 // Suppress "never used" and "set but never used"
149 {
150  Quaternion fq; // quaternion to be transmitted
151  float ftmp; // scratch
152  static uint32_t iTimeStamp = 0; // 1MHz time stamp
153  uint16_t iIndex; // output buffer counter
154  int32_t scratch32; // scratch int32_t
155  int16_t scratch16; // scratch int16_t
156  int16_t iPhi,
157  iThe,
158  iRho; // integer angles to be transmitted
159  int16_t iDelta; // magnetic inclination angle if available
160  int16_t iOmega[3]; // scaled angular velocity vector
161  uint16_t isystick; // algorithm systick time
162  int16_t i, j, k; // general purpose
163  uint8_t tmpuint8_t; // scratch uint8_t
164  uint8_t flags; // byte of flags
165  uint8_t AngularVelocityPacketOn,
166  DebugPacketOn,
167  RPCPacketOn;
168  int8_t AccelCalPacketOn;
169  static uint8_t iPacketNumber = 0; // packet number
170 
171  // update the 1MHz time stamp counter expected by the PC GUI (independent of project clock rates)
172  iTimeStamp += 1000000 / FUSION_HZ;
173 
174 #if (MAXPACKETRATEHZ < FUSION_HZ)
175  uint8_t skip_packet = throttle(); // possible UART bandwidth problem
176  if (skip_packet) return; // need to skip packet transmission to avoid UART overrun
177 #endif
178 
179  // cache local copies of control flags so we don't have to keep dereferencing pointers below
180  quaternion_type quaternionPacketType;
181  quaternionPacketType = sfg->pControlSubsystem->QuaternionPacketType;
182  AngularVelocityPacketOn = sfg->pControlSubsystem->AngularVelocityPacketOn;
183  DebugPacketOn = sfg->pControlSubsystem->DebugPacketOn;
184  RPCPacketOn = sfg->pControlSubsystem->RPCPacketOn;
185  AccelCalPacketOn = sfg->pControlSubsystem->AccelCalPacketOn;
186 
187  // zero the counter for bytes accumulated into the transmit buffer
188  iIndex = 0;
189 
190  // ************************************************************************
191  // Main type 1: range 0 to 35 = 36 bytes
192  // Debug type 2: range 0 to 7 = 8 bytes
193  // Angular velocity type 3: range 0 to 13 = 14 bytes
194  // Euler angles type 4: range 0 to 13 = 14 bytes
195  // Altitude/Temp type 5: range 0 to 13 = 14 bytes
196  // Magnetic type 6: range 0 to 16 = 18 bytes
197  // Kalman packet 7: range 0 to 47 = 48 bytes
198  // Precision Accelerometer packet 8: range 0 to 46 = 47 bytes
199  //
200  // Total excluding intermittent packet 8 is:
201  // 152 bytes vs 256 bytes size of sUARTOutputBuffer
202  // at 25Hz, data rate is 25*152 = 3800 bytes/sec = 38.0kbaud = 33% of 115.2kbaud
203  // at 40Hz, data rate is 40*152 = 6080 bytes/sec = 60.8kbaud = 53% of 115.2kbaud
204  // at 50Hz, data rate is 50*152 = 7600 bytes/sec = 76.0kbaud = 66% of 115.2kbaud
205  // ************************************************************************
206  // ************************************************************************
207  // fixed length packet type 1
208  // this packet type is always transmitted
209  // total size is 0 to 35 equals 36 bytes
210  // ************************************************************************
211  // [0]: packet start byte (need a iIndex++ here since not using sBufAppendItem)
212  sUARTOutputBuffer[iIndex++] = 0x7E;
213 
214  // [1]: packet type 1 byte (iIndex is automatically updated in sBufAppendItem)
215  tmpuint8_t = 0x01;
216  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
217 
218  // [2]: packet number byte
219  sBufAppendItem(sUARTOutputBuffer, &iIndex, &iPacketNumber, 1);
220  iPacketNumber++;
221 
222  // [6-3]: 1MHz time stamp (4 bytes)
223  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iTimeStamp, 4);
224 
225  // [12-7]: integer accelerometer data words (scaled to 8192 counts per g for PC GUI)
226  // send non-zero data only if the accelerometer sensor is enabled and used by the selected quaternion
227  if (sfg->iFlags & F_USING_ACCEL) {
228  switch (quaternionPacketType)
229  {
230  case Q3:
231  case Q6MA:
232  case Q6AG:
233  case Q9:
234 #if F_USING_ACCEL
235  // accelerometer data is used for the selected quaternion so transmit but clip at 4g
236  scratch32 = (sfg->Accel.iGc[CHX] * 8192) / sfg->Accel.iCountsPerg;
237  if (scratch32 > 32767) scratch32 = 32767;
238  if (scratch32 < -32768) scratch32 = -32768;
239  scratch16 = (int16_t) (scratch32);
240  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
241 
242  scratch32 = (sfg->Accel.iGc[CHY] * 8192) / sfg->Accel.iCountsPerg;
243  if (scratch32 > 32767) scratch32 = 32767;
244  if (scratch32 < -32768) scratch32 = -32768;
245  scratch16 = (int16_t) (scratch32);
246  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
247 
248  scratch32 = (sfg->Accel.iGc[CHZ] * 8192) / sfg->Accel.iCountsPerg;
249  if (scratch32 > 32767) scratch32 = 32767;
250  if (scratch32 < -32768) scratch32 = -32768;
251  scratch16 = (int16_t) (scratch32);
252  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
253  break;
254 #endif // F_USING_ACCEL
255  case Q3M:
256  case Q3G:
257  default:
258  // accelerometer data is not used in currently selected algorithm so transmit zero
259  sBufAppendZeros(sUARTOutputBuffer, &iIndex, 3);
260  break;
261  }
262  } else {
263  // accelerometer structure is not defined so transmit zero
264  sBufAppendZeros(sUARTOutputBuffer, &iIndex, 3);
265  }
266  // [18-13]: integer calibrated magnetometer data words (already scaled to 10 count per uT for PC GUI)
267  // send non-zero data only if the magnetometer sensor is enabled and used by the selected quaternion
268  if (sfg->iFlags & F_USING_MAG)
269  switch (quaternionPacketType)
270  {
271  case Q3M:
272  case Q6MA:
273  case Q9:
274 #if F_USING_MAG
275  // magnetometer data is used for the selected quaternion so transmit
276  scratch16 = (int16_t) (sfg->Mag.iBc[CHX] * 10) / (sfg->Mag.iCountsPeruT);
277  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
278  scratch16 = (int16_t) ((sfg->Mag.iBc[CHY] * 10) / sfg->Mag.iCountsPeruT);
279  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
280  scratch16 = (int16_t) ((sfg->Mag.iBc[CHZ] * 10) / sfg->Mag.iCountsPeruT);
281  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
282  break;
283 #endif
284  // magnetometer data is not used in currently selected algorithm so transmit zero
285  case Q3:
286  case Q3G:
287  case Q6AG:
288  default:
289  sBufAppendZeros(sUARTOutputBuffer, &iIndex, 3);
290  break;
291  }
292  else
293  {
294  // magnetometer structure is not defined so transmit zero
295  sBufAppendZeros(sUARTOutputBuffer, &iIndex, 3);
296  }
297 
298  // [24-19]: uncalibrated gyro data words (scaled to 20 counts per deg/s for PC GUI)
299  // send non-zero data only if the gyro sensor is enabled and used by the selected quaternion
300  if (sfg->iFlags & F_USING_GYRO)
301  {
302  switch (quaternionPacketType)
303  {
304  case Q3G:
305  case Q6AG:
306 #if F_USING_GYRO
307  case Q9:
308 
309  // gyro data is used for the selected quaternion so transmit
310  scratch16 = (int16_t) ((sfg->Gyro.iYs[CHX] * 20) / sfg->Gyro.iCountsPerDegPerSec);
311  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
312  scratch16 = (int16_t) ((sfg->Gyro.iYs[CHY] * 20) / sfg->Gyro.iCountsPerDegPerSec);
313  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
314  scratch16 = (int16_t) ((sfg->Gyro.iYs[CHZ] * 20) / sfg->Gyro.iCountsPerDegPerSec);
315  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
316  break;
317 #endif
318  case Q3:
319  case Q3M:
320  case Q6MA:
321  default:
322  // gyro data is not used in currently selected algorithm so transmit zero
323  sBufAppendZeros(sUARTOutputBuffer, &iIndex, 3);
324  break;
325  }
326  }
327  else
328  {
329  // gyro structure is not defined so transmit zero
330  sBufAppendZeros(sUARTOutputBuffer, &iIndex, 3);
331  }
332 
333  // initialize default quaternion, flags byte, angular velocity and orientation
334  fq.q0 = 1.0F;
335  fq.q1 = fq.q2 = fq.q3 = 0.0F;
336  flags = 0x00;
337  iOmega[CHX] = iOmega[CHY] = iOmega[CHZ] = 0;
338  iPhi = iThe = iRho = iDelta = 0;
339  isystick = 0;
340 
341  // flags byte 33: quaternion type in least significant nibble
342  // Q3: coordinate nibble, 1
343  // Q3M: coordinate nibble, 6
344  // Q3G: coordinate nibble, 3
345  // Q6MA: coordinate nibble, 2
346  // Q6AG: coordinate nibble, 4
347  // Q9: coordinate nibble, 8
348  // flags byte 33: coordinate in most significant nibble
349  // Aerospace/NED: 0, quaternion nibble
350  // Android: 1, quaternion nibble
351  // Windows 8: 2, quaternion nibble
352  // set the quaternion, flags, angular velocity and Euler angles
353  switch (quaternionPacketType)
354  {
355 #if F_3DOF_G_BASIC
356  case Q3:
357  if (sfg->iFlags & F_3DOF_G_BASIC)
358  {
359  flags |= 0x01;
360  readCommon((SV_ptr)&sfg->SV_3DOF_G_BASIC, &fq, &iPhi, &iThe, &iRho, iOmega, &isystick);
361  }
362  break;
363 #endif
364 #if F_3DOF_B_BASIC
365  case Q3M:
366  if (sfg->iFlags & F_3DOF_B_BASIC)
367  {
368  flags |= 0x06;
369  readCommon((SV_ptr)&sfg->SV_3DOF_B_BASIC, &fq, &iPhi, &iThe, &iRho, iOmega, &isystick);
370  }
371  break;
372 #endif
373 #if F_3DOF_Y_BASIC
374  case Q3G:
375  if (sfg->iFlags & F_3DOF_Y_BASIC)
376  {
377  flags |= 0x03;
378  readCommon((SV_ptr)&sfg->SV_3DOF_Y_BASIC, &fq, &iPhi, &iThe, &iRho, iOmega, &isystick);
379  }
380  break;
381 #endif
382 #if F_6DOF_GB_BASIC
383  case Q6MA:
384  if (sfg->iFlags & F_6DOF_GB_BASIC)
385  {
386  flags |= 0x02;
387  iDelta = (int16_t) (10.0F * sfg->SV_6DOF_GB_BASIC.fLPDelta);
388  readCommon((SV_ptr)&sfg->SV_6DOF_GB_BASIC, &fq, &iPhi, &iThe, &iRho, iOmega, &isystick);
389  }
390  break;
391 #endif
392 #if F_6DOF_GY_KALMAN
393  case Q6AG:
394  if (sfg->iFlags & F_6DOF_GY_KALMAN)
395  {
396  flags |= 0x04;
397  readCommon((SV_ptr)&sfg->SV_6DOF_GY_KALMAN, &fq, &iPhi, &iThe, &iRho, iOmega, &isystick);
398  }
399  break;
400 #endif
401 #if F_9DOF_GBY_KALMAN
402  case Q9:
403  if (sfg->iFlags & F_9DOF_GBY_KALMAN)
404  {
405  flags |= 0x08;
406  iDelta = (int16_t) (10.0F * sfg->SV_9DOF_GBY_KALMAN.fDeltaPl);
407  readCommon((SV_ptr)&sfg->SV_9DOF_GBY_KALMAN, &fq, &iPhi, &iThe, &iRho, iOmega, &isystick);
408  }
409  break;
410 #endif
411  default:
412  // use the default data already initialized
413  break;
414  }
415 
416  // [32-25]: scale the quaternion (30K = 1.0F) and add to the buffer
417  scratch16 = (int16_t) (fq.q0 * 30000.0F);
418  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
419  scratch16 = (int16_t) (fq.q1 * 30000.0F);
420  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
421  scratch16 = (int16_t) (fq.q2 * 30000.0F);
422  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
423  scratch16 = (int16_t) (fq.q3 * 30000.0F);
424  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
425 
426  // set the coordinate system bits in flags from default NED (00)
427 #if THISCOORDSYSTEM == ANDROID
428  // set the Android flag bits
429  flags |= 0x10;
430 #elif THISCOORDSYSTEM == WIN8
431  // set the Win8 flag bits
432  flags |= 0x20;
433 #endif // THISCOORDSYSTEM
434 
435  // [33]: add the flags byte to the buffer
436  sBufAppendItem(sUARTOutputBuffer, &iIndex, &flags, 1);
437 
438  // [34]: add the shield (bits 7-5) and Kinetis (bits 4-0) byte
439  tmpuint8_t = ((THIS_SHIELD & 0x07) << 5) | (THIS_BOARD & 0x1F);
440  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
441 
442  // [35]: add the tail byte for the standard packet type 1
443  sUARTOutputBuffer[iIndex++] = 0x7E;
444 
445  // ************************************************************************
446  // Variable length debug packet type 2
447  // total size is 0 to 7 equals 8 bytes
448  // ************************************************************************
449  if (DebugPacketOn)
450  {
451  // [0]: packet start byte
452  sUARTOutputBuffer[iIndex++] = 0x7E;
453 
454  // [1]: packet type 2 byte
455  tmpuint8_t = 0x02;
456  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
457 
458  // [2]: packet number byte
459  sBufAppendItem(sUARTOutputBuffer, &iIndex, &iPacketNumber, 1);
460  iPacketNumber++;
461 
462  // [4-3] software version number
463  scratch16 = THISBUILD;
464  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
465 
466  // [6-5] systick count / 20
467  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &isystick, 2);
468 
469  // [7 in practice but can be variable]: add the tail byte for the debug packet type 2
470  sUARTOutputBuffer[iIndex++] = 0x7E;
471  }
472 
473  // ************************************************************************
474  // Angular Velocity packet type 3
475  // total bytes for packet type 2 is range 0 to 13 = 14 bytes
476  // ************************************************************************
477  if (AngularVelocityPacketOn)
478  {
479  // [0]: packet start byte
480  sUARTOutputBuffer[iIndex++] = 0x7E;
481 
482  // [1]: packet type 3 byte (angular velocity)
483  tmpuint8_t = 0x03;
484  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
485 
486  // [2]: packet number byte
487  sBufAppendItem(sUARTOutputBuffer, &iIndex, &iPacketNumber, 1);
488  iPacketNumber++;
489 
490  // [6-3]: time stamp (4 bytes)
491  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iTimeStamp, 4);
492 
493  // [12-7]: add the scaled angular velocity vector to the output buffer
494  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iOmega[CHX], 2);
495  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iOmega[CHY], 2);
496  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iOmega[CHZ], 2);
497 
498  // [13]: add the tail byte for the angular velocity packet type 3
499  sUARTOutputBuffer[iIndex++] = 0x7E;
500  }
501 
502  // ************************************************************************
503  // Roll, Pitch, Compass Euler angles packet type 4
504  // total bytes for packet type 4 is range 0 to 13 = 14 bytes
505  // ************************************************************************
506  if (RPCPacketOn)
507  {
508  // [0]: packet start byte
509  sUARTOutputBuffer[iIndex++] = 0x7E;
510 
511  // [1]: packet type 4 byte (Euler angles)
512  tmpuint8_t = 0x04;
513  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
514 
515  // [2]: packet number byte
516  sBufAppendItem(sUARTOutputBuffer, &iIndex, &iPacketNumber, 1);
517  iPacketNumber++;
518 
519  // [6-3]: time stamp (4 bytes)
520  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iTimeStamp, 4);
521 
522  // [12-7]: add the angles (resolution 0.1 deg per count) to the transmit buffer
523  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iPhi, 2);
524  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iThe, 2);
525  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iRho, 2);
526 
527  // [13]: add the tail byte for the roll, pitch, compass angle packet type 4
528  sUARTOutputBuffer[iIndex++] = 0x7E;
529  }
530 
531  // ************************************************************************
532  // Altitude / Temperature packet type 5
533  // total bytes for packet type 5 is range 0 to 13 = 14 bytes
534  // ************************************************************************
535 #if F_USING_PRESSURE
536  if (sfg->iFlags & F_1DOF_P_BASIC)
537  {
538  if (sfg->pControlSubsystem->AltPacketOn && sfg->Pressure.iWhoAmI)
539  {
540  // [0]: packet start byte
541  sUARTOutputBuffer[iIndex++] = 0x7E;
542 
543  // [1]: packet type 5 byte
544  tmpuint8_t = 0x05;
545  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
546 
547  // [2]: packet number byte
548  sBufAppendItem(sUARTOutputBuffer, &iIndex, &iPacketNumber, 1);
549  iPacketNumber++;
550 
551  // [6-3]: time stamp (4 bytes)
552  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &iTimeStamp,
553  4);
554 
555  // [10-7]: altitude (4 bytes, metres times 1000)
556  scratch32 = (int32_t) (sfg->SV_1DOF_P_BASIC.fLPH * 1000.0F);
557  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch32, 4);
558 
559  // [12-11]: temperature (2 bytes, deg C times 100)
560  scratch16 = (int16_t) (sfg->SV_1DOF_P_BASIC.fLPT * 100.0F);
561  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
562 
563  // [13]: add the tail byte for the altitude / temperature packet type 5
564  sUARTOutputBuffer[iIndex++] = 0x7E;
565  }
566  }
567 #endif
568 
569  // ************************************************************************
570  // magnetic buffer packet type 6
571  // currently total size is 0 to 17 equals 18 bytes
572  // this packet is only transmitted if a magnetic algorithm is computed
573  // ************************************************************************
574 #if F_USING_MAG
575  static int16_t MagneticPacketID = 0; // magnetic packet number
576  if (sfg->iFlags & F_USING_MAG)
577  {
578  // [0]: packet start byte
579  sUARTOutputBuffer[iIndex++] = 0x7E;
580 
581  // [1]: packet type 6 byte
582  tmpuint8_t = 0x06;
583  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
584 
585  // [2]: packet number byte
586  sBufAppendItem(sUARTOutputBuffer, &iIndex, &iPacketNumber, 1);
587  iPacketNumber++;
588 
589  // [4-3]: number of active measurements in the magnetic buffer
590  sBufAppendItem(sUARTOutputBuffer, &iIndex,
591  (uint8_t *) &(sfg->MagBuffer.iMagBufferCount), 2);
592 
593  // [6-5]: fit error (%) with resolution 0.01%
594  if (sfg->MagCal.fFitErrorpc > 327.67F)
595  scratch16 = 32767;
596  else
597  scratch16 = (int16_t) (sfg->MagCal.fFitErrorpc * 100.0F);
598  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
599 
600  // [8-7]: geomagnetic field strength with resolution 0.1uT
601  scratch16 = (int16_t) (sfg->MagCal.fB * 10.0F);
602  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
603 
604  // always calculate magnetic buffer row and column (low overhead and saves warnings)
605  k = MagneticPacketID - 10;
606  j = k / MAGBUFFSIZEX;
607  i = k - j * MAGBUFFSIZEX;
608 
609  // [10-9]: int16_t: ID of magnetic variable to be transmitted
610  // ID 0 to 4 inclusive are magnetic calibration coefficients
611  // ID 5 to 9 inclusive are for future expansion
612  // ID 10 to (MAGBUFFSIZEX=12) * (MAGBUFFSIZEY=24)-1 or 10 to 10+288-1 are magnetic buffer elements
613  // where the convention is used that a negative value indicates empty buffer element (index=-1)
614  if ((MagneticPacketID >= 10) && (sfg->MagBuffer.index[i][j] == -1))
615  {
616  // use negative ID to indicate inactive magnetic buffer element
617  scratch16 = -MagneticPacketID;
618  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
619  }
620  else
621  {
622  // use positive ID unchanged for variable or active magnetic buffer entry
623  scratch16 = MagneticPacketID;
624  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
625  }
626 
627  // [12-11]: int16_t: variable 1 to be transmitted this iteration
628  // [14-13]: int16_t: variable 2 to be transmitted this iteration
629  // [16-15]: int16_t: variable 3 to be transmitted this iteration
630  switch (MagneticPacketID)
631  {
632  case 0:
633  // item 1: currently unused
634  scratch16 = 0;
635  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
636 
637  // item 2: currently unused
638  scratch16 = 0;
639  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
640 
641  // item 3: magnetic inclination angle with resolution 0.1 deg
642  scratch16 = iDelta;
643  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
644  break;
645 
646  case 1:
647  // items 1 to 3: hard iron components range -3276uT to +3276uT encoded with 0.1uT resolution
648  scratch16 = (int16_t) (sfg->MagCal.fV[CHX] * 10.0F);
649  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
650  scratch16 = (int16_t) (sfg->MagCal.fV[CHY] * 10.0F);
651  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
652  scratch16 = (int16_t) (sfg->MagCal.fV[CHZ] * 10.0F);
653  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
654  break;
655 
656  case 2:
657  // items 1 to 3: diagonal soft iron range -32. to +32. encoded with 0.001 resolution
658  scratch16 = (int16_t) (sfg->MagCal.finvW[CHX][CHX] * 1000.0F);
659  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
660  scratch16 = (int16_t) (sfg->MagCal.finvW[CHY][CHY] * 1000.0F);
661  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
662  scratch16 = (int16_t) (sfg->MagCal.finvW[CHZ][CHZ] * 1000.0F);
663  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
664  break;
665 
666  case 3:
667  // items 1 to 3: off-diagonal soft iron range -32. to +32. encoded with 0.001 resolution
668  scratch16 = (int16_t) (sfg->MagCal.finvW[CHX][CHY] * 1000.0F);
669  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
670  scratch16 = (int16_t) (sfg->MagCal.finvW[CHX][CHZ] * 1000.0F);
671  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
672  scratch16 = (int16_t) (sfg->MagCal.finvW[CHY][CHZ] * 1000.0F);
673  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
674  break;
675 
676  case 4:
677  case 5:
678  case 6:
679  case 7:
680  case 8:
681  case 9:
682  // cases 4 to 9 inclusive are for future expansion so transmit zeroes for now
683  sBufAppendZeros(sUARTOutputBuffer, &iIndex, 3);
684  break;
685 
686  default:
687  // 10 and upwards: this handles the magnetic buffer elements
688  sBufAppendItem(sUARTOutputBuffer, &iIndex,
689  (uint8_t *) &(sfg->MagBuffer.iBs[CHX][i][j]), 2);
690  sBufAppendItem(sUARTOutputBuffer, &iIndex,
691  (uint8_t *) &(sfg->MagBuffer.iBs[CHY][i][j]), 2);
692  sBufAppendItem(sUARTOutputBuffer, &iIndex,
693  (uint8_t *) &(sfg->MagBuffer.iBs[CHZ][i][j]), 2);
694  break;
695  }
696 
697  // wrap the variable ID back to zero if necessary
698  MagneticPacketID++;
699  if (MagneticPacketID >= (10 + MAGBUFFSIZEX * MAGBUFFSIZEY))
700  MagneticPacketID = 0;
701 
702  // [17]: add the tail byte for the magnetic packet type 6
703  sUARTOutputBuffer[iIndex++] = 0x7E;
704  }
705 #endif
706 
707  // *******************************************************************************
708  // Kalman filter packet type 7
709  // total bytes for packet type 7 is range 0 to 41 inclusive = 42 bytes
710  // this packet is only transmitted when a Kalman algorithm is computed
711  // and then non-zero data is transmitted only when a Kalman quaternion is selected
712  // *******************************************************************************
713  bool kalman = false;
714 #if F_6DOF_GY_KALMAN
715  uint8_t six_axis_kalman = (sfg->iFlags & F_6DOF_GY_KALMAN) && (quaternionPacketType == Q6AG);
716  kalman = six_axis_kalman;
717 #endif
718 #if F_9DOF_GBY_KALMAN
719  uint8_t nine_axis_kalman = (sfg->iFlags & F_9DOF_GBY_KALMAN) && (quaternionPacketType == Q9);
720  kalman = kalman | nine_axis_kalman;
721 #endif
722 #if F_6DOF_GY_KALMAN || F_9DOF_GBY_KALMAN
723  if (kalman)
724  {
725  if ((quaternionPacketType == Q6AG) || (quaternionPacketType == Q9))
726  {
727  // [0]: packet start byte
728  sUARTOutputBuffer[iIndex++] = 0x7E;
729 
730  // [1]: packet type 7 byte
731  tmpuint8_t = 0x07;
732  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
733 
734  // [2]: packet number byte
735  sBufAppendItem(sUARTOutputBuffer, &iIndex, &iPacketNumber, 1);
736  iPacketNumber++;
737 
738  // [4-3]: fzgErr[CHX] resolution scaled by 30000
739  // [6-5]: fzgErr[CHY] resolution scaled by 30000
740  // [8-7]: fzgErr[CHZ] resolution scaled by 30000
741  for (i = CHX; i <= CHZ; i++)
742  {
743 #if F_6DOF_GY_KALMAN
744  if (six_axis_kalman) scratch16 = (int16_t) (sfg->SV_6DOF_GY_KALMAN.fZErr[i] * 30000.0F);
745 #endif
746 #if F_9DOF_GBY_KALMAN
747  if (nine_axis_kalman) scratch16 = (int16_t) (sfg->SV_9DOF_GBY_KALMAN.fZErr[i] * 30000.0F);
748 #endif
749  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16,2);
750  }
751 
752  // [10-9]: fgErrPl[CHX] resolution scaled by 30000
753  // [12-11]: fgErrPl[CHY] resolution scaled by 30000
754  // [14-13]: fgErrPl[CHZ] resolution scaled by 30000
755  for (i = CHX; i <= CHZ; i++)
756  {
757 #if F_6DOF_GY_KALMAN
758  if (six_axis_kalman) scratch16 = (int16_t) (sfg->SV_6DOF_GY_KALMAN.fqgErrPl[i] * 30000.0F);
759 #endif
760 #if F_9DOF_GBY_KALMAN
761  if (nine_axis_kalman) scratch16 = (int16_t) (sfg->SV_9DOF_GBY_KALMAN.fqgErrPl[i] * 30000.0F);
762 #endif
763  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16,2);
764  }
765 
766  // [16-15]: fzmErr[CHX] resolution scaled by 30000
767  // [18-17]: fzmErr[CHY] resolution scaled by 30000
768  // [20-19]: fzmErr[CHZ] resolution scaled by 30000
769  for (i = CHX; i <= CHZ; i++)
770  {
771 #if F_6DOF_GY_KALMAN
772  if (six_axis_kalman) scratch16 = 0;
773 #endif
774 #if F_9DOF_GBY_KALMAN
775  if (nine_axis_kalman) scratch16 = (int16_t) (sfg->SV_9DOF_GBY_KALMAN.fZErr[i + 3] * 30000.0F);
776 #endif
777  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
778  }
779 
780  // [22-21]: fmErrPl[CHX] resolution scaled by 30000
781  // [24-23]: fmErrPl[CHY] resolution scaled by 30000
782  // [26-25]: fmErrPl[CHZ] resolution scaled by 30000
783  for (i = CHX; i <= CHZ; i++)
784  {
785 #if F_6DOF_GY_KALMAN
786  if (six_axis_kalman) scratch16 = 0;
787 #endif
788 #if F_9DOF_GBY_KALMAN
789  if (nine_axis_kalman) scratch16 = (int16_t) (sfg->SV_9DOF_GBY_KALMAN.fqmErrPl[i] * 30000.0F);
790 #endif
791  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
792  }
793 
794  // [28-27]: fbPl[CHX] resolution 0.001 deg/sec
795  // [30-29]: fbPl[CHY] resolution 0.001 deg/sec
796  // [32-31]: fbPl[CHZ] resolution 0.001 deg/sec
797  for (i = CHX; i <= CHZ; i++)
798  {
799 #if F_6DOF_GY_KALMAN
800  if (six_axis_kalman) scratch16 = (int16_t) (sfg->SV_6DOF_GY_KALMAN.fbPl[i] * 1000.0F);
801 #endif
802 #if F_9DOF_GBY_KALMAN
803  if (nine_axis_kalman) scratch16 = (int16_t) (sfg->SV_9DOF_GBY_KALMAN.fbPl[i] * 1000.0F);
804 #endif
805  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
806  }
807 
808  // [34-33]: fDeltaPl resolution 0.01deg
809  scratch16 = 0;
810 #if F_9DOF_GBY_KALMAN
811  if (nine_axis_kalman) scratch16 = (int16_t) (sfg->SV_9DOF_GBY_KALMAN.fDeltaPl * 100.0F);
812 #endif
813  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
814 
815  // [36-35]: fAccGl[CHX] resolution 1/8192 g
816  // [38-37]: fAccGl[CHY] resolution 1/8192 g
817  // [40-39]: fAccGl[CHZ] resolution 1/8192 g
818  for (i = CHX; i <= CHZ; i++)
819  {
820  // default to zero data
821  ftmp = 0.0F;
822 #if F_6DOF_GY_KALMAN
823  if (six_axis_kalman) ftmp = sfg->SV_6DOF_GY_KALMAN.fAccGl[i] * 8192.0F;
824 #endif
825 #if F_9DOF_GBY_KALMAN
826  if (nine_axis_kalman) ftmp = sfg->SV_9DOF_GBY_KALMAN.fAccGl[i] * 8192.0F;
827 #endif
828 
829  // check for clipping
830  if (ftmp > 32767.0F) scratch16 = 32767;
831  else if (ftmp < -32768.0F) scratch16 = -32768;
832  else scratch16 = (int16_t) ftmp;
833  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
834  }
835 
836  // [42-41]: fDisGl[CHX] resolution 0.01m
837  // [44-43]: fDisGl[CHY] resolution 0.01m
838  // [46-45]: fDisGl[CHZ] resolution 0.01m
839  for (i = CHX; i <= CHZ; i++)
840  {
841  // default to zero data
842  ftmp = 0.0F;
843 #if F_9DOF_GBY_KALMAN
844  if (nine_axis_kalman) ftmp = sfg->SV_9DOF_GBY_KALMAN.fDisGl[i] * 100.0F;
845 #endif
846 
847  // check for clipping
848  if (ftmp > 32767.0F) scratch16 = 32767;
849  else if (ftmp < -32768.0F) scratch16 = -32768;
850  else scratch16 = (int16_t) ftmp;
851  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
852  }
853 
854  // [47]: add the tail byte for the Kalman packet type 7
855  sUARTOutputBuffer[iIndex++] = 0x7E;
856  }
857  } // end of check for Kalman packet
858 #endif
859 #if F_USING_ACCEL
860  // *************************************************************************
861  // fixed length packet type 8 transmitted whenever a precision accelerometer
862  // measurement has been stored.
863  // total size is 0 to 40 equals 41 bytes
864  // *************************************************************************
865  // check to see which packet (if any) is to be transmitted
866  if (AccelCalPacketOn != -1)
867  {
868  // [0]: packet start byte (need a iIndex++ here since not using sBufAppendItem)
869  sUARTOutputBuffer[iIndex++] = 0x7E;
870 
871  // [1]: packet type 8 byte (iIndex is automatically updated in sBufAppendItem)
872  tmpuint8_t = 0x08;
873  sBufAppendItem(sUARTOutputBuffer, &iIndex, &tmpuint8_t, 1);
874 
875  // [2]: packet number byte
876  sBufAppendItem(sUARTOutputBuffer, &iIndex, &iPacketNumber, 1);
877  iPacketNumber++;
878 
879  // [3]: AccelCalPacketOn in range 0-11 denotes stored location and MAXORIENTATIONS denotes transmit
880  // precision accelerometer calibration on power on before any measurements have been obtained.
881  sBufAppendItem(sUARTOutputBuffer, &iIndex,
882  (uint8_t *) &(AccelCalPacketOn), 1);
883 
884  // [9-4]: stored accelerometer measurement fGs (scaled to 8192 counts per g)
885  if ((AccelCalPacketOn >= 0) &&
886  (AccelCalPacketOn < MAX_ACCEL_CAL_ORIENTATIONS))
887  {
888  scratch16 = (int16_t) (sfg->AccelBuffer.fGsStored[AccelCalPacketOn][CHX] * 8192.0F);
889  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
890  scratch16 = (int16_t) (sfg->AccelBuffer.fGsStored[AccelCalPacketOn][CHY] * 8192.0F);
891  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
892  scratch16 = (int16_t) (sfg->AccelBuffer.fGsStored[AccelCalPacketOn][CHZ] * 8192.0F);
893  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
894  }
895  else
896  {
897  // transmit zero bytes since this is the power on or reset transmission of the precision calibration
898  sBufAppendZeros(sUARTOutputBuffer, &iIndex, 3);
899  }
900 
901  // [15-10]: precision accelerometer offset vector fV (g scaled by 32768.0)
902  scratch16 = (int16_t) (sfg->AccelCal.fV[CHX] * 32768.0F);
903  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
904  scratch16 = (int16_t) (sfg->AccelCal.fV[CHY] * 32768.0F);
905  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
906  scratch16 = (int16_t) (sfg->AccelCal.fV[CHZ] * 32768.0F);
907  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
908 
909  // [21-16]: precision accelerometer inverse gain matrix diagonal finvW - 1.0 (scaled by 10000.0)
910  scratch16 = (int16_t) ((sfg->AccelCal.finvW[CHX][CHX] - 1.0F) * 10000.0F);
911  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
912  scratch16 = (int16_t) ((sfg->AccelCal.finvW[CHY][CHY] - 1.0F) * 10000.0F);
913  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
914  scratch16 = (int16_t) ((sfg->AccelCal.finvW[CHZ][CHZ] - 1.0F) * 10000.0F);
915  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
916 
917  // [27-22]: precision accelerometer inverse gain matrix off-diagonal finvW (scaled by 10000)
918  scratch16 = (int16_t) (sfg->AccelCal.finvW[CHX][CHY] * 10000.0F);
919  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
920  scratch16 = (int16_t) (sfg->AccelCal.finvW[CHX][CHZ] * 10000.0F);
921  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
922  scratch16 = (int16_t) (sfg->AccelCal.finvW[CHY][CHZ] * 10000.0F);
923  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
924 
925  // [33-28]: precision accelerometer rotation matrix diagonal fR0 (scaled by 10000)
926  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHX][CHX] * 10000.0F);
927  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
928  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHY][CHY] * 10000.0F);
929  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
930  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHZ][CHZ] * 10000.0F);
931  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
932 
933  // [45-34]: precision accelerometer inverse rotation matrix off-diagonal fR0 (scaled by 10000)
934  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHX][CHY] * 10000.0F);
935  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
936  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHX][CHZ] * 10000.0F);
937  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
938  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHY][CHX] * 10000.0F);
939  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
940  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHY][CHZ] * 10000.0F);
941  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
942  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHZ][CHX] * 10000.0F);
943  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
944  scratch16 = (int16_t) (sfg->AccelCal.fR0[CHZ][CHY] * 10000.0F);
945  sBufAppendItem(sUARTOutputBuffer, &iIndex, (uint8_t *) &scratch16, 2);
946 
947  // [46]: add the tail byte for the packet type 8
948  sUARTOutputBuffer[iIndex++] = 0x7E;
949 
950  // disable future packets of this type until a new measurement has been obtained
952  }
953 #endif // F_USING_ACCEL
954  // ********************************************************************************
955  // all packets have now been constructed in the output buffer so now transmit.
956  // The final iIndex++ gives the number of bytes to transmit which is one more than
957  // the last index in the buffer. this function is non-blocking
958  // ********************************************************************************
959  sfg->pControlSubsystem->write(sfg->pControlSubsystem, sUARTOutputBuffer, iIndex);
960  return;
961 }
enum quaternion quaternion_type
the quaternion type to be transmitted
Quaternion derived from full 9-axis sensor fusion.
Definition: sensor_fusion.h:80
volatile quaternion_type QuaternionPacketType
quaternion type transmitted over UART
Definition: control.h:70
#define MAGBUFFSIZEX
x dimension in magnetometer buffer (12x24 equals 288 elements)
Definition: magnetic.h:53
#define F_USING_GYRO
nominally 0x0004 if a gyro is to be used, 0x0000 otherwise
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:87
void readCommon(SV_ptr data, Quaternion *fq, int16_t *iPhi, int16_t *iThe, int16_t *iRho, int16_t iOmega[], uint16_t *isystick)
float fV[3]
current hard iron offset x, y, z, (uT)
Definition: magnetic.h:84
ApplyPerturbation function used to analyze dynamic performance.
SensorFusionGlobals sfg
struct MagBuffer MagBuffer
mag cal constellation points
int32_t systick
systick timer;
Quaternion derived from 3-axis mag only (auto compass algorithm)
Definition: sensor_fusion.h:76
uint8_t data[FXLS8962_DATA_SIZE]
float fOmega[3]
average angular velocity (deg/s)
float q1
x vector component
Definition: orientation.h:49
writePort_t * write
low level function to write a char buffer to the serial stream
Definition: control.h:76
volatile uint8_t AltPacketOn
flag to enable altitude packet
Definition: control.h:74
int16_t iBc[3]
averaged calibrated measurement (counts)
Quaternion derived from 3-axis gyro only (rotation)
Definition: sensor_fusion.h:77
float fThe
pitch (deg)
Quaternion derived from 3-axis accel + 3 axis mag (eCompass)
Definition: sensor_fusion.h:78
int32_t int32
Definition: sensor_fusion.h:67
#define MAXPACKETRATEHZ
Definition: output_stream.c:42
Quaternion derived from 3-axis accel + 3-axis gyro (gaming)
Definition: sensor_fusion.h:79
volatile uint8_t AngularVelocityPacketOn
flag to enable angular velocity packet
Definition: control.h:71
uint16_t throttle()
(OVERSAMPLE_RATIO * MAXPACKETRATEHZ) / SENSORFS
#define THIS_BOARD
FRDM_K64F.
Definition: frdm_k64f.h:171
float fRho
compass (deg)
The top level fusion structure.
#define F_1DOF_P_BASIC
1DOF pressure (altitude) and temperature algorithm selector - 0x0100 to include, 0x0000 otherwise ...
#define F_9DOF_GBY_KALMAN
9DOF accel, mag and gyro algorithm selector - 0x4000 to include, 0x0000 otherwise ...
void sBufAppendItem(uint8_t *pDest, uint16_t *pIndex, uint8_t *pSource, uint16_t iBytesToCopy)
Utility function used to place data in output buffer about to be transmitted via UART.
Definition: output_stream.c:63
struct MagSensor Mag
magnetometer storage
#define THISBUILD
define build number sent in debug packet for display purposes only
#define F_6DOF_GY_KALMAN
6DOF accel and gyro (Kalman) algorithm selector - 0x2000 to include, 0x0000 otherwise ...
float fFitErrorpc
current fit error %
Definition: magnetic.h:88
The sensor_fusion.h file implements the top level programming interface.
volatile uint8_t RPCPacketOn
flag to enable roll, pitch, compass packet
Definition: control.h:73
#define F_3DOF_G_BASIC
3DOF accel tilt (accel) algorithm selector - 0x0200 to include, 0x0000 otherwise
#define CHZ
Used to access Z-channel entries in various data data structures.
Definition: sensor_fusion.h:88
int16_t iBs[3][MAGBUFFSIZEX][MAGBUFFSIZEY]
uncalibrated magnetometer readings
Definition: magnetic.h:74
uint8_t sUARTOutputBuffer[256]
main output buffer defined in control.c
Definition: control.c:63
Quaternion fq
orientation quaternion
void CreateAndSendPackets(SensorFusionGlobals *sfg, uint8_t *sUARTOutputBuffer)
float fB
current geomagnetic field magnitude (uT)
Definition: magnetic.h:86
int16_t iMagBufferCount
number of magnetometer readings
Definition: magnetic.h:77
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:86
uint32_t iFlags
a bit-field of sensors and algorithms used
int16_t iCountsPeruT
counts per uT
float q2
y vector component
Definition: orientation.h:50
float fPhi
roll (deg)
typedef int32_t(DATA_FORMAT_Append_t))(void *pData
The interface function to append the data on the formated stream.
quaternion structure definition
Definition: orientation.h:46
struct MagCalibration MagCal
mag cal storage
Quaternion derived from 3-axis accel (tilt)
Definition: sensor_fusion.h:75
#define F_3DOF_Y_BASIC
3DOF gyro integration algorithm selector - 0x0800 to include, 0x0000 otherwise
#define F_6DOF_GB_BASIC
6DOF accel and mag eCompass algorithm selector - 0x1000 to include, 0x0000 otherwise ...
#define MAX_ACCEL_CAL_ORIENTATIONS
number of stored precision accelerometer measurements
#define FUSION_HZ
(int) actual rate of fusion algorithm execution and sensor FIFO reads
Defines control sub-system.
struct ControlSubsystem * pControlSubsystem
void sBufAppendZeros(uint8_t *pDest, uint16_t *pIndex, uint16_t numZeros)
Definition: output_stream.c:96
#define F_USING_ACCEL
nominally 0x0001 if an accelerometer is to be used, 0x0000 otherwise
float q3
z vector component
Definition: orientation.h:51
float q0
scalar component
Definition: orientation.h:48
#define MAGBUFFSIZEY
y dimension in magnetometer buffer (12x24 equals 288 elements)
Definition: magnetic.h:54
#define THIS_SHIELD
#define F_3DOF_B_BASIC
3DOF mag eCompass (vehicle/mag) algorithm selector - 0x0400 to include, 0x0000 otherwise ...
int32_t index[MAGBUFFSIZEX][MAGBUFFSIZEY]
array of time indices
Definition: magnetic.h:75
#define F_USING_MAG
Definition: magnetic.h:47
float finvW[3][3]
current inverse soft iron matrix
Definition: magnetic.h:85
volatile int8_t AccelCalPacketOn
variable used to coordinate accelerometer calibration
Definition: control.h:75
#define RATERESOLUTION
Definition: output_stream.c:43
volatile uint8_t DebugPacketOn
flag to enable debug packet
Definition: control.h:72