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