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 DecodeCommandBytes.c
10     \brief Command interpreter which interfaces to the Sensor Fusion Toolbox
11 */
12 
13 #include "sensor_fusion.h"
14 #include "control.h"
15 #include "fusion.h"
16 #include "calibration_storage.h"
17 // All commands for the command interpreter are exactly 4 characters long.
18 // The command interpeter converts the incoming packet to a 32-bit integer, which is then
19 // the index into a large switch statement for processing commands.
20 // The following block of #define statements are responsible for the conversion from 4-characters
21 // into an easier to use integer format.
22 #define cmd_VGplus      (((((('V' << 8) | 'G') << 8) | '+') << 8) | ' ') // "VG+ " = enable angular velocity packet transmission
23 #define cmd_VGminus     (((((('V' << 8) | 'G') << 8) | '-') << 8) | ' ') // "VG- " = disable angular velocity packet transmission
24 #define cmd_DBplus      (((((('D' << 8) | 'B') << 8) | '+') << 8) | ' ') // "DB+ " = enable debug packet transmission
25 #define cmd_DBminus     (((((('D' << 8) | 'B') << 8) | '-') << 8) | ' ') // "DB- " = disable debug packet transmission
26 #define cmd_Q3          (((((('Q' << 8) | '3') << 8) | ' ') << 8) | ' ') // "Q3  " = transmit 3-axis accelerometer quaternion in standard packet
27 #define cmd_Q3M         (((((('Q' << 8) | '3') << 8) | 'M') << 8) | ' ') // "Q3M " = transmit 3-axis magnetic quaternion in standard packet
28 #define cmd_Q3G         (((((('Q' << 8) | '3') << 8) | 'G') << 8) | ' ') // "Q3G " = transmit 3-axis gyro quaternion in standard packet
29 #define cmd_Q6MA        (((((('Q' << 8) | '6') << 8) | 'M') << 8) | 'A') // "Q6MA" = transmit 6-axis mag/accel quaternion in standard packet
30 #define cmd_Q6AG        (((((('Q' << 8) | '6') << 8) | 'A') << 8) | 'G') // "Q6AG" = transmit 6-axis accel/gyro quaternion in standard packet
31 #define cmd_Q9          (((((('Q' << 8) | '9') << 8) | ' ') << 8) | ' ') // "Q9  " = transmit 9-axis quaternion in standard packet (default)
32 #define cmd_RPCplus     (((((('R' << 8) | 'P') << 8) | 'C') << 8) | '+') // "RPC+" = Roll/Pitch/Compass on
33 #define cmd_RPCminus    (((((('R' << 8) | 'P') << 8) | 'C') << 8) | '-') // "RPC-" = Roll/Pitch/Compass off
34 #define cmd_ALTplus     (((((('A' << 8) | 'L') << 8) | 'T') << 8) | '+') // "ALT+" = Altitude packet on
35 #define cmd_ALTminus    (((((('A' << 8) | 'L') << 8) | 'T') << 8) | '-') // "ALT-" = Altitude packet off
36 #define cmd_RST         (((((('R' << 8) | 'S') << 8) | 'T') << 8) | ' ') // "RST " = Soft reset
37 #define cmd_RINS        (((((('R' << 8) | 'I') << 8) | 'N') << 8) | 'S') // "RINS" = Reset INS inertial navigation velocity and position
38 #define cmd_SVAC        (((((('S' << 8) | 'V') << 8) | 'A') << 8) | 'C') // "SVAC" = save all calibrations to Kinetis flash
39 #define cmd_SVMC        (((((('S' << 8) | 'V') << 8) | 'M') << 8) | 'C') // "SVMC" = save magnetic calibration to Kinetis flash
40 #define cmd_SVYC        (((((('S' << 8) | 'V') << 8) | 'Y') << 8) | 'C') // "SVYC" = save gyroscope calibration to Kinetis flash
41 #define cmd_SVGC        (((((('S' << 8) | 'V') << 8) | 'G') << 8) | 'C') // "SVGC" = save precision accelerometer calibration to Kinetis flash
42 #define cmd_ERAC        (((((('E' << 8) | 'R') << 8) | 'A') << 8) | 'C') // "ERAC" = erase all calibrations from Kinetis flash
43 #define cmd_ERMC        (((((('E' << 8) | 'R') << 8) | 'M') << 8) | 'C') // "ERMC" = erase magnetic calibration from Kinetis flash
44 #define cmd_ERYC        (((((('E' << 8) | 'R') << 8) | 'Y') << 8) | 'C') // "ERYC" = erase gyro offset calibration from Kinetis flash
45 #define cmd_ERGC        (((((('E' << 8) | 'R') << 8) | 'G') << 8) | 'C') // "ERGC" = erase precision accelerometer calibration from Kinetis flash
46 #define cmd_180X        (((((('1' << 8) | '8') << 8) | '0') << 8) | 'X') // "180X" perturbation
47 #define cmd_180Y        (((((('1' << 8) | '8') << 8) | '0') << 8) | 'Y') // "180Y" perturbation
48 #define cmd_180Z        (((((('1' << 8) | '8') << 8) | '0') << 8) | 'Z') // "180Z" perturbation
49 #define cmd_M90X        (((((('M' << 8) | '9') << 8) | '0') << 8) | 'X') // "M90X" perturbation
50 #define cmd_P90X        (((((('P' << 8) | '9') << 8) | '0') << 8) | 'X') // "P90X" perturbation
51 #define cmd_M90Y        (((((('M' << 8) | '9') << 8) | '0') << 8) | 'Y') // "M90Y" perturbation
52 #define cmd_P90Y        (((((('P' << 8) | '9') << 8) | '0') << 8) | 'Y') // "P90Y" perturbation
53 #define cmd_M90Z        (((((('M' << 8) | '9') << 8) | '0') << 8) | 'Z') // "M90Z" perturbation
54 #define cmd_P90Z        (((((('P' << 8) | '9') << 8) | '0') << 8) | 'Z') // "P90Z" perturbation
55 #define cmd_PA00        (((((('P' << 8) | 'A') << 8) | '0') << 8) | '0') // "PA00" average precision accelerometer location 0
56 #define cmd_PA01        (((((('P' << 8) | 'A') << 8) | '0') << 8) | '1') // "PA01" average precision accelerometer location 1
57 #define cmd_PA02        (((((('P' << 8) | 'A') << 8) | '0') << 8) | '2') // "PA02" average precision accelerometer location 2
58 #define cmd_PA03        (((((('P' << 8) | 'A') << 8) | '0') << 8) | '3') // "PA03" average precision accelerometer location 3
59 #define cmd_PA04        (((((('P' << 8) | 'A') << 8) | '0') << 8) | '4') // "PA04" average precision accelerometer location 4
60 #define cmd_PA05        (((((('P' << 8) | 'A') << 8) | '0') << 8) | '5') // "PA05" average precision accelerometer location 5
61 #define cmd_PA06        (((((('P' << 8) | 'A') << 8) | '0') << 8) | '6') // "PA06" average precision accelerometer location 6
62 #define cmd_PA07        (((((('P' << 8) | 'A') << 8) | '0') << 8) | '7') // "PA07" average precision accelerometer location 7
63 #define cmd_PA08        (((((('P' << 8) | 'A') << 8) | '0') << 8) | '8') // "PA08" average precision accelerometer location 8
64 #define cmd_PA09        (((((('P' << 8) | 'A') << 8) | '0') << 8) | '9') // "PA09" average precision accelerometer location 9
65 #define cmd_PA10        (((((('P' << 8) | 'A') << 8) | '1') << 8) | '0') // "PA10" average precision accelerometer location 10
66 #define cmd_PA11        (((((('P' << 8) | 'A') << 8) | '1') << 8) | '1') // "PA11" average precision accelerometer location 11
67 
DecodeCommandBytes(SensorFusionGlobals * sfg,char iCommandBuffer[],uint8 sUART_InputBuffer[],uint16 nbytes)68 void DecodeCommandBytes(SensorFusionGlobals *sfg, char iCommandBuffer[], uint8 sUART_InputBuffer[], uint16 nbytes)
69 {
70 	int32 isum;		// 32 bit command identifier
71 	int16 i, j;		// loop counters
72 
73 	// parse all received bytes in sUARTInputBuf into the iCommandBuffer delay line
74 	for (i = 0; i < nbytes; i++) {
75 		// shuffle the iCommandBuffer delay line and add the new command byte
76 		for (j = 0; j < 3; j++)
77 			iCommandBuffer[j] = iCommandBuffer[j + 1];
78 		iCommandBuffer[3] = sUART_InputBuffer[i];
79 
80 		// check if we have a valid command yet
81 		isum = ((((((int32)iCommandBuffer[0] << 8) | iCommandBuffer[1]) << 8) | iCommandBuffer[2]) << 8) | iCommandBuffer[3];
82 		switch (isum) 		{
83 		case cmd_VGplus: // "VG+ " = enable angular velocity packet transmission
84                     sfg->pControlSubsystem->AngularVelocityPacketOn = true;
85                     iCommandBuffer[3] = '~';
86 		break;
87 
88 		case cmd_VGminus: // "VG- " = disable angular velocity packet transmission
89                     sfg->pControlSubsystem->AngularVelocityPacketOn = false;
90                     iCommandBuffer[3] = '~';
91 		break;
92 
93 		case cmd_DBplus: // "DB+ " = enable debug packet transmission
94                     sfg->pControlSubsystem->DebugPacketOn = true;
95                     iCommandBuffer[3] = '~';
96 		break;
97 
98 		case cmd_DBminus: // "DB- " = disable debug packet transmission
99                     sfg->pControlSubsystem->DebugPacketOn = false;
100                     iCommandBuffer[3] = '~';
101 		break;
102 
103 		case cmd_Q3: // "Q3  " = transmit 3-axis accelerometer quaternion in standard packet
104 #if F_3DOF_G_BASIC
105                     sfg->pControlSubsystem->QuaternionPacketType = Q3;
106 #endif
107                     iCommandBuffer[3] = '~';
108 		break;
109 
110 		case cmd_Q3M:  // "Q3M " = transmit 3-axis magnetometer quaternion in standard packet
111 #if F_3DOF_B_BASIC
112                     sfg->pControlSubsystem->QuaternionPacketType = Q3M;
113 #endif
114                     iCommandBuffer[3] = '~';
115 		break;
116 
117 		case cmd_Q3G: // "Q3G " = transmit 3-axis gyro quaternion in standard packet
118 #if F_3DOF_Y_BASIC
119                     sfg->pControlSubsystem->QuaternionPacketType = Q3G;
120 #endif
121                     iCommandBuffer[3] = '~';
122 		break;
123 
124 		case cmd_Q6MA: // "Q6MA" = transmit 6-axis mag/accel quaternion in standard packet
125 #if F_6DOF_GB_BASIC
126                     sfg->pControlSubsystem->QuaternionPacketType = Q6MA;
127 #endif
128                     iCommandBuffer[3] = '~';
129 		break;
130 
131 		case cmd_Q6AG: // "Q6AG" = transmit 6-axis accel/gyro quaternion in standard packet
132 #if F_6DOF_GY_KALMAN
133                     sfg->pControlSubsystem->QuaternionPacketType = Q6AG;
134 #endif
135                     iCommandBuffer[3] = '~';
136 		break;
137 
138 		case cmd_Q9: // "Q9  " = transmit 9-axis quaternion in standard packet (default)
139 #if F_9DOF_GBY_KALMAN
140                     sfg->pControlSubsystem->QuaternionPacketType = Q9;
141 #endif
142                     iCommandBuffer[3] = '~';
143 		break;
144 
145 		case cmd_RPCplus: // "RPC+" = Roll/Pitch/Compass on
146                     sfg->pControlSubsystem->RPCPacketOn = true;
147                     iCommandBuffer[3] = '~';
148 		break;
149 
150 		case cmd_RPCminus: // "RPC-" = Roll/Pitch/Compass off
151                     sfg->pControlSubsystem->RPCPacketOn = false;
152                     iCommandBuffer[3] = '~';
153 		break;
154 
155 		case cmd_ALTplus: // "ALT+" = Altitude packet on
156                     sfg->pControlSubsystem->AltPacketOn = true;
157                     iCommandBuffer[3] = '~';
158 		break;
159 
160 		case cmd_ALTminus: // "ALT-" = Altitude packet off
161                     sfg->pControlSubsystem->AltPacketOn = false;
162                     iCommandBuffer[3] = '~';
163 		break;
164 
165 		case cmd_RST: // "RST " = Soft reset
166                     // reset sensor fusion
167                     fInitializeFusion(sfg);
168 
169                     // reset magnetic calibration and magnetometer data buffer
170 #if F_USING_MAG
171                     fInitializeMagCalibration(&sfg->MagCal, &sfg->MagBuffer);
172 #endif
173                     // reset precision accelerometer calibration and accelerometer measurements
174 #if F_USING_ACCEL
175                     fInitializeAccelCalibration(&sfg->AccelCal, &sfg->AccelBuffer, &(sfg->pControlSubsystem->AccelCalPacketOn)) ;
176 #endif
177                     iCommandBuffer[3] = '~';
178 		break;
179 
180 		case cmd_RINS: // "RINS" = Reset INS inertial navigation velocity and position
181 #if F_9DOF_GBY_KALMAN
182                     for (i = CHX; i <= CHZ; i++) {
183 			sfg->SV_9DOF_GBY_KALMAN.fVelGl[i] = 0.0F;
184 			sfg->SV_9DOF_GBY_KALMAN.fDisGl[i] = 0.0F;
185                     }
186 #endif
187 		iCommandBuffer[3] = '~';
188 		break;
189 
190 		case cmd_SVAC: // "SVAC" = save all calibrations to Kinetis flash
191                     SaveMagCalibrationToNVM(sfg);
192                     SaveGyroCalibrationToNVM(sfg);
193                     SaveAccelCalibrationToNVM(sfg);
194                     iCommandBuffer[3] = '~';
195 		break;
196 
197 		case cmd_SVMC: // "SVMC" = save magnetic calibration to Kinetis flash
198                     SaveMagCalibrationToNVM(sfg);
199                     iCommandBuffer[3] = '~';
200 		break;
201 
202 		case cmd_SVYC: // "SVYC" = save gyroscope calibration to Kinetis flash
203                     SaveGyroCalibrationToNVM(sfg);
204                     iCommandBuffer[3] = '~';
205 		break;
206 
207 		case cmd_SVGC: // "SVGC" = save precision accelerometer calibration to Kinetis flash
208                     SaveAccelCalibrationToNVM(sfg);
209                     iCommandBuffer[3] = '~';
210 		break;
211 
212 		case cmd_ERAC: // "ERAC" = erase all calibrations from Kinetis flash
213                     EraseMagCalibrationFromNVM();
214                     EraseGyroCalibrationFromNVM();
215                     EraseAccelCalibrationFromNVM();
216                     iCommandBuffer[3] = '~';
217 		break;
218 
219 		case cmd_ERMC: // "ERMC" = erase magnetic calibration offset 0 bytes from Kinetis flash
220                     EraseMagCalibrationFromNVM();
221                     iCommandBuffer[3] = '~';
222 		break;
223 
224 		case cmd_ERYC: // "ERYC" = erase gyro offset calibrationoffset 128 bytes from Kinetis flash
225                     EraseGyroCalibrationFromNVM();
226                     iCommandBuffer[3] = '~';
227 		break;
228 
229 		case cmd_ERGC: // "ERGC" = erase precision accelerometer calibration offset 192 bytesfrom Kinetis flash
230                     EraseAccelCalibrationFromNVM();
231                     iCommandBuffer[3] = '~';
232 		break;
233 
234 		case cmd_180X: // "180X" perturbation
235                     sfg->iPerturbation = 1;
236                     iCommandBuffer[3] = '~';
237 		break;
238 
239 		case cmd_180Y: // "180Y" perturbation
240                     sfg->iPerturbation = 2;
241                     iCommandBuffer[3] = '~';
242 		break;
243 
244 		case cmd_180Z: // "180Z" perturbation
245                     sfg->iPerturbation = 3;
246                   iCommandBuffer[3] = '~';
247 		break;
248 
249 		case cmd_M90X: // "M90X" perturbation
250                     sfg->iPerturbation = 4;
251                     iCommandBuffer[3] = '~';
252 		break;
253 
254 		case cmd_P90X: // "P90X" perturbation
255                     sfg->iPerturbation = 5;
256                     iCommandBuffer[3] = '~';
257 		break;
258 
259 		case cmd_M90Y: // "M90Y" perturbation
260                     sfg->iPerturbation = 6;
261                     iCommandBuffer[3] = '~';
262 		break;
263 
264 		case cmd_P90Y: // "P90Y" perturbation
265                     sfg->iPerturbation = 7;
266                     iCommandBuffer[3] = '~';
267 		break;
268 
269 		case cmd_M90Z: // "M90Z" perturbation
270                     sfg->iPerturbation = 8;
271                     iCommandBuffer[3] = '~';
272 		break;
273 
274 		case cmd_P90Z: // "P90Z" perturbation
275                     sfg->iPerturbation = 9;
276                     iCommandBuffer[3] = '~';
277 		break;
278 
279 #if F_USING_ACCEL
280 		case cmd_PA00: // "PA00" average precision accelerometer location 0
281                     sfg->AccelBuffer.iStoreLocation = 0;
282                     sfg->AccelBuffer.iStoreCounter = (ACCEL_CAL_AVERAGING_SECS * FUSION_HZ);
283                     iCommandBuffer[3] = '~';
284 		break;
285 
286 		case cmd_PA01: // "PA01" average precision accelerometer location 1
287                     sfg->AccelBuffer.iStoreLocation = 1;
288                     sfg->AccelBuffer.iStoreCounter = (ACCEL_CAL_AVERAGING_SECS * FUSION_HZ);
289                     iCommandBuffer[3] = '~';
290 		break;
291 
292 		case cmd_PA02: // "PA02" average precision accelerometer location 2
293                     sfg->AccelBuffer.iStoreLocation = 2;
294                     sfg->AccelBuffer.iStoreCounter = (ACCEL_CAL_AVERAGING_SECS * FUSION_HZ);
295                     iCommandBuffer[3] = '~';
296 		break;
297 
298 		case cmd_PA03: // "PA03" average precision accelerometer location 3
299                     sfg->AccelBuffer.iStoreLocation = 3;
300                     sfg->AccelBuffer.iStoreCounter = (ACCEL_CAL_AVERAGING_SECS * FUSION_HZ);
301                     iCommandBuffer[3] = '~';
302 		break;
303 
304 		case cmd_PA04: // "PA04" average precision accelerometer location 4
305                     sfg->AccelBuffer.iStoreLocation = 4;
306                     sfg->AccelBuffer.iStoreCounter = (ACCEL_CAL_AVERAGING_SECS * FUSION_HZ);
307                     iCommandBuffer[3] = '~';
308 		break;
309 
310 		case cmd_PA05: // "PA05" average precision accelerometer location 5
311                     sfg->AccelBuffer.iStoreLocation = 5;
312                     sfg->AccelBuffer.iStoreCounter = (ACCEL_CAL_AVERAGING_SECS * FUSION_HZ);
313                     iCommandBuffer[3] = '~';
314 		break;
315 
316 		case cmd_PA06: // "PA06" average precision accelerometer location 6
317                     sfg->AccelBuffer.iStoreLocation = 6;
318                     sfg->AccelBuffer.iStoreCounter = (ACCEL_CAL_AVERAGING_SECS * FUSION_HZ);
319                     iCommandBuffer[3] = '~';
320 		break;
321 
322 		case cmd_PA07: // "PA07" average precision accelerometer location 7
323                     sfg->AccelBuffer.iStoreLocation = 7;
324                     sfg->AccelBuffer.iStoreCounter = (ACCEL_CAL_AVERAGING_SECS * FUSION_HZ);
325                     iCommandBuffer[3] = '~';
326 		break;
327 
328 		case cmd_PA08: // "PA08" average precision accelerometer location 8
329                     sfg->AccelBuffer.iStoreLocation = 8;
330                     sfg->AccelBuffer.iStoreCounter = (ACCEL_CAL_AVERAGING_SECS * FUSION_HZ);
331                     iCommandBuffer[3] = '~';
332 		break;
333 
334 		case cmd_PA09: // "PA09" average precision accelerometer location 9
335                     sfg->AccelBuffer.iStoreLocation = 9;
336                     sfg->AccelBuffer.iStoreCounter = (ACCEL_CAL_AVERAGING_SECS * FUSION_HZ);
337                     iCommandBuffer[3] = '~';
338 		break;
339 
340 		case cmd_PA10: // "PA10" average precision accelerometer location 10
341                     sfg->AccelBuffer.iStoreLocation = 10;
342                     sfg->AccelBuffer.iStoreCounter = (ACCEL_CAL_AVERAGING_SECS * FUSION_HZ);
343                     iCommandBuffer[3] = '~';
344 		break;
345 
346 		case cmd_PA11: // "PA11" average precision accelerometer location 11
347                     sfg->AccelBuffer.iStoreLocation = 11;
348                     sfg->AccelBuffer.iStoreCounter = (ACCEL_CAL_AVERAGING_SECS * FUSION_HZ);
349                     iCommandBuffer[3] = '~';
350 		break;
351 #endif // precision accelerometer calibration
352 
353 		default:
354 			// no action
355 			break;
356 		}
357 	} // end of loop over received characters
358 
359 	return;
360 }
361