2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
24 #include "build_config.h"
27 #include "scheduler.h"
29 #include "common/axis.h"
30 #include "common/color.h"
31 #include "common/maths.h"
33 #include "drivers/system.h"
35 #include "drivers/sensor.h"
36 #include "drivers/accgyro.h"
37 #include "drivers/compass.h"
39 #include "drivers/serial.h"
40 #include "drivers/bus_i2c.h"
41 #include "drivers/gpio.h"
42 #include "drivers/timer.h"
43 #include "drivers/pwm_rx.h"
44 #include "drivers/gyro_sync.h"
45 #include "drivers/sdcard.h"
46 #include "drivers/buf_writer.h"
50 #include "io/beeper.h"
51 #include "io/escservo.h"
52 #include "io/rc_controls.h"
54 #include "io/gimbal.h"
55 #include "io/serial.h"
56 #include "io/ledstrip.h"
57 #include "io/flashfs.h"
58 #include "io/transponder_ir.h"
59 #include "io/asyncfatfs/asyncfatfs.h"
62 #include "telemetry/telemetry.h"
64 #include "sensors/boardalignment.h"
65 #include "sensors/sensors.h"
66 #include "sensors/battery.h"
67 #include "sensors/sonar.h"
68 #include "sensors/acceleration.h"
69 #include "sensors/barometer.h"
70 #include "sensors/compass.h"
71 #include "sensors/gyro.h"
73 #include "flight/mixer.h"
74 #include "flight/pid.h"
75 #include "flight/imu.h"
76 #include "flight/failsafe.h"
77 #include "flight/navigation.h"
78 #include "flight/altitudehold.h"
80 #include "blackbox/blackbox.h"
84 #include "config/runtime_config.h"
85 #include "config/config.h"
86 #include "config/config_profile.h"
87 #include "config/config_master.h"
90 #ifdef USE_HARDWARE_REVISION_DETECTION
91 #include "hardware_revision.h"
94 #include "serial_msp.h"
96 #ifdef USE_SERIAL_4WAY_BLHELI_INTERFACE
97 #include "io/serial_4way.h"
100 static serialPort_t
*mspSerialPort
;
102 extern uint16_t cycleTime
; // FIXME dependency on mw.c
103 extern uint16_t rssi
; // FIXME dependency on mw.c
104 extern void resetPidProfile(pidProfile_t
*pidProfile
);
107 void setGyroSamplingSpeed(uint16_t looptime
) {
108 uint16_t gyroSampleRate
= 1000;
109 uint8_t maxDivider
= 1;
111 if (looptime
!= targetLooptime
|| looptime
== 0) {
112 if (looptime
== 0) looptime
= targetLooptime
; // needed for pid controller changes
114 if (looptime
< 1000) {
115 masterConfig
.gyro_lpf
= 0;
116 gyroSampleRate
= 125;
118 masterConfig
.pid_process_denom
= 1;
119 masterConfig
.acc_hardware
= 0;
120 masterConfig
.baro_hardware
= 0;
121 masterConfig
.mag_hardware
= 0;
122 if (looptime
< 250) {
123 masterConfig
.acc_hardware
= 1;
124 masterConfig
.baro_hardware
= 1;
125 masterConfig
.mag_hardware
= 1;
126 masterConfig
.pid_process_denom
= 2;
127 } else if (looptime
< 375) {
128 #if defined(LUX_RACE) || defined(COLIBRI_RACE) || defined(MOTOLAB) || defined(ALIENFLIGHTF3) || defined(SPRACINGF3EVO) || defined(DOGE)
129 masterConfig
.acc_hardware
= 0;
131 masterConfig
.acc_hardware
= 1;
133 masterConfig
.baro_hardware
= 1;
134 masterConfig
.mag_hardware
= 1;
135 masterConfig
.pid_process_denom
= 2;
137 masterConfig
.gyro_sync_denom
= constrain(looptime
/ gyroSampleRate
, 1, maxDivider
);
139 masterConfig
.gyro_lpf
= 0;
140 masterConfig
.gyro_sync_denom
= 8;
141 masterConfig
.acc_hardware
= 0;
142 masterConfig
.baro_hardware
= 0;
143 masterConfig
.mag_hardware
= 0;
146 if (looptime
< 1000) {
147 masterConfig
.gyro_lpf
= 0;
148 masterConfig
.acc_hardware
= 1;
149 masterConfig
.baro_hardware
= 1;
150 masterConfig
.mag_hardware
= 1;
151 gyroSampleRate
= 125;
153 masterConfig
.pid_process_denom
= 1;
154 if (currentProfile
->pidProfile
.pidController
== 2) masterConfig
.pid_process_denom
= 2;
155 if (looptime
< 250) {
156 masterConfig
.pid_process_denom
= 4;
157 } else if (looptime
< 375) {
158 if (currentProfile
->pidProfile
.pidController
== 2) {
159 masterConfig
.pid_process_denom
= 3;
161 masterConfig
.pid_process_denom
= 2;
164 masterConfig
.gyro_sync_denom
= constrain(looptime
/ gyroSampleRate
, 1, maxDivider
);
166 masterConfig
.gyro_lpf
= 0;
168 masterConfig
.gyro_sync_denom
= 8;
169 masterConfig
.acc_hardware
= 0;
170 masterConfig
.baro_hardware
= 0;
171 masterConfig
.mag_hardware
= 0;
172 masterConfig
.pid_process_denom
= 1;
178 void useRcControlsConfig(modeActivationCondition_t
*modeActivationConditions
, escAndServoConfig_t
*escAndServoConfigToUse
, pidProfile_t
*pidProfileToUse
);
180 const char * const flightControllerIdentifier
= BETAFLIGHT_IDENTIFIER
; // 4 UPPER CASE alpha numeric characters that identify the flight controller.
182 typedef struct box_e
{
183 const uint8_t boxId
; // see boxId_e
184 const char *boxName
; // GUI-readable box name
185 const uint8_t permanentId
; //
189 static const box_t boxes
[CHECKBOX_ITEM_COUNT
+ 1] = {
190 { BOXARM
, "ARM;", 0 },
191 { BOXANGLE
, "ANGLE;", 1 },
192 { BOXHORIZON
, "HORIZON;", 2 },
193 { BOXBARO
, "BARO;", 3 },
194 //{ BOXVARIO, "VARIO;", 4 },
195 { BOXMAG
, "MAG;", 5 },
196 { BOXHEADFREE
, "HEADFREE;", 6 },
197 { BOXHEADADJ
, "HEADADJ;", 7 },
198 { BOXCAMSTAB
, "CAMSTAB;", 8 },
199 { BOXCAMTRIG
, "CAMTRIG;", 9 },
200 { BOXGPSHOME
, "GPS HOME;", 10 },
201 { BOXGPSHOLD
, "GPS HOLD;", 11 },
202 { BOXPASSTHRU
, "PASSTHRU;", 12 },
203 { BOXBEEPERON
, "BEEPER;", 13 },
204 { BOXLEDMAX
, "LEDMAX;", 14 },
205 { BOXLEDLOW
, "LEDLOW;", 15 },
206 { BOXLLIGHTS
, "LLIGHTS;", 16 },
207 { BOXCALIB
, "CALIB;", 17 },
208 { BOXGOV
, "GOVERNOR;", 18 },
209 { BOXOSD
, "OSD SW;", 19 },
210 { BOXTELEMETRY
, "TELEMETRY;", 20 },
211 { BOXGTUNE
, "GTUNE;", 21 },
212 { BOXSONAR
, "SONAR;", 22 },
213 { BOXSERVO1
, "SERVO1;", 23 },
214 { BOXSERVO2
, "SERVO2;", 24 },
215 { BOXSERVO3
, "SERVO3;", 25 },
216 { BOXBLACKBOX
, "BLACKBOX;", 26 },
217 { BOXFAILSAFE
, "FAILSAFE;", 27 },
218 { BOXAIRMODE
, "AIR MODE;", 28 },
219 //{ BOXSUPEREXPO, "SUPER EXPO;", 29 },
220 { BOX3DDISABLESWITCH
, "DISABLE 3D SWITCH;", 30},
221 { CHECKBOX_ITEM_COUNT
, NULL
, 0xFF }
224 // this is calculated at startup based on enabled features.
225 static uint8_t activeBoxIds
[CHECKBOX_ITEM_COUNT
];
226 // this is the number of filled indexes in above array
227 static uint8_t activeBoxIdCount
= 0;
229 extern int16_t motor_disarmed
[MAX_SUPPORTED_MOTORS
];
231 // cause reboot after MSP processing complete
232 static bool isRebootScheduled
= false;
234 static const char pidnames
[] =
247 MSP_SDCARD_STATE_NOT_PRESENT
= 0,
248 MSP_SDCARD_STATE_FATAL
= 1,
249 MSP_SDCARD_STATE_CARD_INIT
= 2,
250 MSP_SDCARD_STATE_FS_INIT
= 3,
251 MSP_SDCARD_STATE_READY
= 4
255 STATIC_UNIT_TESTED mspPort_t mspPorts
[MAX_MSP_PORT_COUNT
];
257 STATIC_UNIT_TESTED mspPort_t
*currentPort
;
258 STATIC_UNIT_TESTED bufWriter_t
*writer
;
260 static void serialize8(uint8_t a
)
262 bufWriterAppend(writer
, a
);
263 currentPort
->checksum
^= a
;
266 static void serialize16(uint16_t a
)
268 serialize8((uint8_t)(a
>> 0));
269 serialize8((uint8_t)(a
>> 8));
272 static void serialize32(uint32_t a
)
274 serialize16((uint16_t)(a
>> 0));
275 serialize16((uint16_t)(a
>> 16));
278 static uint8_t read8(void)
280 return currentPort
->inBuf
[currentPort
->indRX
++] & 0xff;
283 static uint16_t read16(void)
285 uint16_t t
= read8();
286 t
+= (uint16_t)read8() << 8;
290 static uint32_t read32(void)
292 uint32_t t
= read16();
293 t
+= (uint32_t)read16() << 16;
297 static void headSerialResponse(uint8_t err
, uint8_t responseBodySize
)
299 serialBeginWrite(mspSerialPort
);
303 serialize8(err
? '!' : '>');
304 currentPort
->checksum
= 0; // start calculating a new checksum
305 serialize8(responseBodySize
);
306 serialize8(currentPort
->cmdMSP
);
309 static void headSerialReply(uint8_t responseBodySize
)
311 headSerialResponse(0, responseBodySize
);
314 static void headSerialError(uint8_t responseBodySize
)
316 headSerialResponse(1, responseBodySize
);
319 static void tailSerialReply(void)
321 serialize8(currentPort
->checksum
);
322 serialEndWrite(mspSerialPort
);
325 static void s_struct(uint8_t *cb
, uint8_t siz
)
327 headSerialReply(siz
);
332 static void serializeNames(const char *s
)
339 static const box_t
*findBoxByActiveBoxId(uint8_t activeBoxId
)
342 const box_t
*candidate
;
343 for (boxIndex
= 0; boxIndex
< sizeof(boxes
) / sizeof(box_t
); boxIndex
++) {
344 candidate
= &boxes
[boxIndex
];
345 if (candidate
->boxId
== activeBoxId
) {
352 static const box_t
*findBoxByPermenantId(uint8_t permenantId
)
355 const box_t
*candidate
;
356 for (boxIndex
= 0; boxIndex
< sizeof(boxes
) / sizeof(box_t
); boxIndex
++) {
357 candidate
= &boxes
[boxIndex
];
358 if (candidate
->permanentId
== permenantId
) {
365 static void serializeBoxNamesReply(void)
367 int i
, activeBoxId
, j
, flag
= 1, count
= 0, len
;
371 // in first run of the loop, we grab total size of junk to be sent
372 // then come back and actually send it
373 for (i
= 0; i
< activeBoxIdCount
; i
++) {
374 activeBoxId
= activeBoxIds
[i
];
376 box
= findBoxByActiveBoxId(activeBoxId
);
381 len
= strlen(box
->boxName
);
385 for (j
= 0; j
< len
; j
++)
386 serialize8(box
->boxName
[j
]);
391 headSerialReply(count
);
397 static void serializeSDCardSummaryReply(void)
399 headSerialReply(3 + 4 + 4);
402 uint8_t flags
= 1 /* SD card supported */ ;
407 // Merge the card and filesystem states together
408 if (!sdcard_isInserted()) {
409 state
= MSP_SDCARD_STATE_NOT_PRESENT
;
410 } else if (!sdcard_isFunctional()) {
411 state
= MSP_SDCARD_STATE_FATAL
;
413 switch (afatfs_getFilesystemState()) {
414 case AFATFS_FILESYSTEM_STATE_READY
:
415 state
= MSP_SDCARD_STATE_READY
;
417 case AFATFS_FILESYSTEM_STATE_INITIALIZATION
:
418 if (sdcard_isInitialized()) {
419 state
= MSP_SDCARD_STATE_FS_INIT
;
421 state
= MSP_SDCARD_STATE_CARD_INIT
;
424 case AFATFS_FILESYSTEM_STATE_FATAL
:
425 case AFATFS_FILESYSTEM_STATE_UNKNOWN
:
426 state
= MSP_SDCARD_STATE_FATAL
;
432 serialize8(afatfs_getLastError());
433 // Write free space and total space in kilobytes
434 serialize32(afatfs_getContiguousFreeSpace() / 1024);
435 serialize32(sdcard_getMetadata()->numBlocks
/ 2); // Block size is half a kilobyte
445 static void serializeDataflashSummaryReply(void)
447 headSerialReply(1 + 3 * 4);
449 const flashGeometry_t
*geometry
= flashfsGetGeometry();
450 uint8_t flags
= (flashfsIsReady() ? 1 : 0) | 2 /* FlashFS is supported */;
453 serialize32(geometry
->sectors
);
454 serialize32(geometry
->totalSize
);
455 serialize32(flashfsGetOffset()); // Effectively the current number of bytes stored on the volume
457 serialize8(0); // FlashFS is neither ready nor supported
465 static void serializeDataflashReadReply(uint32_t address
, uint8_t size
)
470 if (size
> sizeof(buffer
)) {
471 size
= sizeof(buffer
);
474 headSerialReply(4 + size
);
476 serialize32(address
);
478 // bytesRead will be lower than that requested if we reach end of volume
479 bytesRead
= flashfsReadAbs(address
, buffer
, size
);
481 for (int i
= 0; i
< bytesRead
; i
++) {
482 serialize8(buffer
[i
]);
487 static void resetMspPort(mspPort_t
*mspPortToReset
, serialPort_t
*serialPort
)
489 memset(mspPortToReset
, 0, sizeof(mspPort_t
));
491 mspPortToReset
->port
= serialPort
;
494 void mspAllocateSerialPorts(serialConfig_t
*serialConfig
)
496 UNUSED(serialConfig
);
498 serialPort_t
*serialPort
;
500 uint8_t portIndex
= 0;
502 serialPortConfig_t
*portConfig
= findSerialPortConfig(FUNCTION_MSP
);
504 while (portConfig
&& portIndex
< MAX_MSP_PORT_COUNT
) {
505 mspPort_t
*mspPort
= &mspPorts
[portIndex
];
511 serialPort
= openSerialPort(portConfig
->identifier
, FUNCTION_MSP
, NULL
, baudRates
[portConfig
->msp_baudrateIndex
], MODE_RXTX
, SERIAL_NOT_INVERTED
);
513 resetMspPort(mspPort
, serialPort
);
517 portConfig
= findNextSerialPortConfig(FUNCTION_MSP
);
521 void mspReleasePortIfAllocated(serialPort_t
*serialPort
)
524 for (portIndex
= 0; portIndex
< MAX_MSP_PORT_COUNT
; portIndex
++) {
525 mspPort_t
*candidateMspPort
= &mspPorts
[portIndex
];
526 if (candidateMspPort
->port
== serialPort
) {
527 closeSerialPort(serialPort
);
528 memset(candidateMspPort
, 0, sizeof(mspPort_t
));
533 void mspInit(serialConfig_t
*serialConfig
)
535 // calculate used boxes based on features and fill availableBoxes[] array
536 memset(activeBoxIds
, 0xFF, sizeof(activeBoxIds
));
538 activeBoxIdCount
= 0;
539 activeBoxIds
[activeBoxIdCount
++] = BOXARM
;
541 if (sensors(SENSOR_ACC
)) {
542 activeBoxIds
[activeBoxIdCount
++] = BOXANGLE
;
543 activeBoxIds
[activeBoxIdCount
++] = BOXHORIZON
;
546 if (!feature(FEATURE_AIRMODE
)) activeBoxIds
[activeBoxIdCount
++] = BOXAIRMODE
;
547 activeBoxIds
[activeBoxIdCount
++] = BOX3DDISABLESWITCH
;
549 if (sensors(SENSOR_BARO
)) {
550 activeBoxIds
[activeBoxIdCount
++] = BOXBARO
;
553 if (sensors(SENSOR_ACC
) || sensors(SENSOR_MAG
)) {
554 activeBoxIds
[activeBoxIdCount
++] = BOXMAG
;
555 activeBoxIds
[activeBoxIdCount
++] = BOXHEADFREE
;
556 activeBoxIds
[activeBoxIdCount
++] = BOXHEADADJ
;
559 if (feature(FEATURE_SERVO_TILT
))
560 activeBoxIds
[activeBoxIdCount
++] = BOXCAMSTAB
;
563 if (feature(FEATURE_GPS
)) {
564 activeBoxIds
[activeBoxIdCount
++] = BOXGPSHOME
;
565 activeBoxIds
[activeBoxIdCount
++] = BOXGPSHOLD
;
569 if (masterConfig
.mixerMode
== MIXER_FLYING_WING
|| masterConfig
.mixerMode
== MIXER_AIRPLANE
)
570 activeBoxIds
[activeBoxIdCount
++] = BOXPASSTHRU
;
572 activeBoxIds
[activeBoxIdCount
++] = BOXBEEPERON
;
575 if (feature(FEATURE_LED_STRIP
)) {
576 activeBoxIds
[activeBoxIdCount
++] = BOXLEDLOW
;
580 if (feature(FEATURE_INFLIGHT_ACC_CAL
))
581 activeBoxIds
[activeBoxIdCount
++] = BOXCALIB
;
583 activeBoxIds
[activeBoxIdCount
++] = BOXOSD
;
585 if (feature(FEATURE_TELEMETRY
) && masterConfig
.telemetryConfig
.telemetry_switch
)
586 activeBoxIds
[activeBoxIdCount
++] = BOXTELEMETRY
;
588 if (feature(FEATURE_SONAR
)){
589 activeBoxIds
[activeBoxIdCount
++] = BOXSONAR
;
593 if (masterConfig
.mixerMode
== MIXER_CUSTOM_AIRPLANE
) {
594 activeBoxIds
[activeBoxIdCount
++] = BOXSERVO1
;
595 activeBoxIds
[activeBoxIdCount
++] = BOXSERVO2
;
596 activeBoxIds
[activeBoxIdCount
++] = BOXSERVO3
;
601 if (feature(FEATURE_BLACKBOX
)){
602 activeBoxIds
[activeBoxIdCount
++] = BOXBLACKBOX
;
606 if (feature(FEATURE_FAILSAFE
)){
607 activeBoxIds
[activeBoxIdCount
++] = BOXFAILSAFE
;
611 activeBoxIds
[activeBoxIdCount
++] = BOXGTUNE
;
614 memset(mspPorts
, 0x00, sizeof(mspPorts
));
615 mspAllocateSerialPorts(serialConfig
);
618 #define IS_ENABLED(mask) (mask == 0 ? 0 : 1)
620 static uint32_t packFlightModeFlags(void)
622 uint32_t i
, junk
, tmp
;
624 // Serialize the flags in the order we delivered them, ignoring BOXNAMES and BOXINDEXES
625 // Requires new Multiwii protocol version to fix
626 // It would be preferable to setting the enabled bits based on BOXINDEX.
628 tmp
= IS_ENABLED(FLIGHT_MODE(ANGLE_MODE
)) << BOXANGLE
|
629 IS_ENABLED(FLIGHT_MODE(HORIZON_MODE
)) << BOXHORIZON
|
630 IS_ENABLED(FLIGHT_MODE(BARO_MODE
)) << BOXBARO
|
631 IS_ENABLED(FLIGHT_MODE(MAG_MODE
)) << BOXMAG
|
632 IS_ENABLED(FLIGHT_MODE(HEADFREE_MODE
)) << BOXHEADFREE
|
633 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXHEADADJ
)) << BOXHEADADJ
|
634 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXCAMSTAB
)) << BOXCAMSTAB
|
635 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXCAMTRIG
)) << BOXCAMTRIG
|
636 IS_ENABLED(FLIGHT_MODE(GPS_HOME_MODE
)) << BOXGPSHOME
|
637 IS_ENABLED(FLIGHT_MODE(GPS_HOLD_MODE
)) << BOXGPSHOLD
|
638 IS_ENABLED(FLIGHT_MODE(PASSTHRU_MODE
)) << BOXPASSTHRU
|
639 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXBEEPERON
)) << BOXBEEPERON
|
640 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXLEDMAX
)) << BOXLEDMAX
|
641 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXLEDLOW
)) << BOXLEDLOW
|
642 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXLLIGHTS
)) << BOXLLIGHTS
|
643 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXCALIB
)) << BOXCALIB
|
644 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXGOV
)) << BOXGOV
|
645 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXOSD
)) << BOXOSD
|
646 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXTELEMETRY
)) << BOXTELEMETRY
|
647 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXGTUNE
)) << BOXGTUNE
|
648 IS_ENABLED(FLIGHT_MODE(SONAR_MODE
)) << BOXSONAR
|
649 IS_ENABLED(ARMING_FLAG(ARMED
)) << BOXARM
|
650 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXBLACKBOX
)) << BOXBLACKBOX
|
651 IS_ENABLED(FLIGHT_MODE(FAILSAFE_MODE
)) << BOXFAILSAFE
|
652 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXAIRMODE
)) << BOXAIRMODE
;
654 for (i
= 0; i
< activeBoxIdCount
; i
++) {
655 int flag
= (tmp
& (1 << activeBoxIds
[i
]));
663 static bool processOutCommand(uint8_t cmdMSP
)
669 int32_t lat
= 0, lon
= 0;
673 case MSP_API_VERSION
:
675 1 + // protocol version length
678 serialize8(MSP_PROTOCOL_VERSION
);
680 serialize8(API_VERSION_MAJOR
);
681 serialize8(API_VERSION_MINOR
);
685 headSerialReply(FLIGHT_CONTROLLER_IDENTIFIER_LENGTH
);
687 for (i
= 0; i
< FLIGHT_CONTROLLER_IDENTIFIER_LENGTH
; i
++) {
688 serialize8(flightControllerIdentifier
[i
]);
693 headSerialReply(FLIGHT_CONTROLLER_VERSION_LENGTH
);
695 serialize8(FC_VERSION_MAJOR
);
696 serialize8(FC_VERSION_MINOR
);
697 serialize8(FC_VERSION_PATCH_LEVEL
);
702 BOARD_IDENTIFIER_LENGTH
+
703 BOARD_HARDWARE_REVISION_LENGTH
705 for (i
= 0; i
< BOARD_IDENTIFIER_LENGTH
; i
++) {
706 serialize8(boardIdentifier
[i
]);
708 #ifdef USE_HARDWARE_REVISION_DETECTION
709 serialize16(hardwareRevision
);
711 serialize16(0); // No other build targets currently have hardware revision detection.
719 GIT_SHORT_REVISION_LENGTH
722 for (i
= 0; i
< BUILD_DATE_LENGTH
; i
++) {
723 serialize8(buildDate
[i
]);
725 for (i
= 0; i
< BUILD_TIME_LENGTH
; i
++) {
726 serialize8(buildTime
[i
]);
729 for (i
= 0; i
< GIT_SHORT_REVISION_LENGTH
; i
++) {
730 serialize8(shortGitRevision
[i
]);
734 // DEPRECATED - Use MSP_API_VERSION
737 serialize8(MW_VERSION
);
738 serialize8(masterConfig
.mixerMode
);
739 serialize8(MSP_PROTOCOL_VERSION
);
740 serialize32(CAP_DYNBALANCE
); // "capability"
745 serialize16(cycleTime
);
747 serialize16(i2cGetErrorCounter());
751 serialize16(sensors(SENSOR_ACC
) | sensors(SENSOR_BARO
) << 1 | sensors(SENSOR_MAG
) << 2 | sensors(SENSOR_GPS
) << 3 | sensors(SENSOR_SONAR
) << 4);
752 serialize32(packFlightModeFlags());
753 serialize8(masterConfig
.current_profile_index
);
754 //serialize16(averageSystemLoadPercent);
759 serialize16(cycleTime
);
761 serialize16(i2cGetErrorCounter());
765 serialize16(sensors(SENSOR_ACC
) | sensors(SENSOR_BARO
) << 1 | sensors(SENSOR_MAG
) << 2 | sensors(SENSOR_GPS
) << 3 | sensors(SENSOR_SONAR
) << 4);
766 serialize32(packFlightModeFlags());
767 serialize8(masterConfig
.current_profile_index
);
772 // Hack scale due to choice of units for sensor data in multiwii
773 uint8_t scale
= (acc_1G
> 1024) ? 8 : 1;
775 for (i
= 0; i
< 3; i
++)
776 serialize16(accSmooth
[i
] / scale
);
777 for (i
= 0; i
< 3; i
++)
778 serialize16(gyroADC
[i
]);
779 for (i
= 0; i
< 3; i
++)
780 serialize16(magADC
[i
]);
784 s_struct((uint8_t *)&servo
, MAX_SUPPORTED_SERVOS
* 2);
786 case MSP_SERVO_CONFIGURATIONS
:
787 headSerialReply(MAX_SUPPORTED_SERVOS
* sizeof(servoParam_t
));
788 for (i
= 0; i
< MAX_SUPPORTED_SERVOS
; i
++) {
789 serialize16(masterConfig
.servoConf
[i
].min
);
790 serialize16(masterConfig
.servoConf
[i
].max
);
791 serialize16(masterConfig
.servoConf
[i
].middle
);
792 serialize8(masterConfig
.servoConf
[i
].rate
);
793 serialize8(masterConfig
.servoConf
[i
].angleAtMin
);
794 serialize8(masterConfig
.servoConf
[i
].angleAtMax
);
795 serialize8(masterConfig
.servoConf
[i
].forwardFromChannel
);
796 serialize32(masterConfig
.servoConf
[i
].reversedSources
);
799 case MSP_SERVO_MIX_RULES
:
800 headSerialReply(MAX_SERVO_RULES
* sizeof(servoMixer_t
));
801 for (i
= 0; i
< MAX_SERVO_RULES
; i
++) {
802 serialize8(masterConfig
.customServoMixer
[i
].targetChannel
);
803 serialize8(masterConfig
.customServoMixer
[i
].inputSource
);
804 serialize8(masterConfig
.customServoMixer
[i
].rate
);
805 serialize8(masterConfig
.customServoMixer
[i
].speed
);
806 serialize8(masterConfig
.customServoMixer
[i
].min
);
807 serialize8(masterConfig
.customServoMixer
[i
].max
);
808 serialize8(masterConfig
.customServoMixer
[i
].box
);
813 s_struct((uint8_t *)motor
, 16);
816 headSerialReply(2 * rxRuntimeConfig
.channelCount
);
817 for (i
= 0; i
< rxRuntimeConfig
.channelCount
; i
++)
818 serialize16(rcData
[i
]);
822 serialize16(attitude
.values
.roll
);
823 serialize16(attitude
.values
.pitch
);
824 serialize16(DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
));
828 #if defined(BARO) || defined(SONAR)
829 serialize32(altitudeHoldGetEstimatedAltitude());
835 case MSP_SONAR_ALTITUDE
:
838 serialize32(sonarGetLatestAltitude());
845 serialize8((uint8_t)constrain(vbat
, 0, 255));
846 serialize16((uint16_t)constrain(mAhDrawn
, 0, 0xFFFF)); // milliamp hours drawn from battery
848 if(masterConfig
.batteryConfig
.multiwiiCurrentMeterOutput
) {
849 serialize16((uint16_t)constrain(amperage
* 10, 0, 0xFFFF)); // send amperage in 0.001 A steps. Negative range is truncated to zero
851 serialize16((int16_t)constrain(amperage
, -0x8000, 0x7FFF)); // send amperage in 0.01 A steps, range is -320A to 320A
853 case MSP_ARMING_CONFIG
:
855 serialize8(masterConfig
.auto_disarm_delay
);
856 serialize8(masterConfig
.disarm_kill_switch
);
860 serialize16((uint16_t)targetLooptime
);
864 serialize8(currentControlRateProfile
->rcRate8
);
865 serialize8(currentControlRateProfile
->rcExpo8
);
866 for (i
= 0 ; i
< 3; i
++) {
867 serialize8(currentControlRateProfile
->rates
[i
]); // R,P,Y see flight_dynamics_index_t
869 serialize8(currentControlRateProfile
->dynThrPID
);
870 serialize8(currentControlRateProfile
->thrMid8
);
871 serialize8(currentControlRateProfile
->thrExpo8
);
872 serialize16(currentControlRateProfile
->tpa_breakpoint
);
873 serialize8(currentControlRateProfile
->rcYawExpo8
);
876 headSerialReply(3 * PID_ITEM_COUNT
);
877 for (i
= 0; i
< PID_ITEM_COUNT
; i
++) {
878 serialize8(currentProfile
->pidProfile
.P8
[i
]);
879 serialize8(currentProfile
->pidProfile
.I8
[i
]);
880 serialize8(currentProfile
->pidProfile
.D8
[i
]);
884 headSerialReply(sizeof(pidnames
) - 1);
885 serializeNames(pidnames
);
887 case MSP_PID_CONTROLLER
:
889 serialize8(currentProfile
->pidProfile
.pidController
);
891 case MSP_MODE_RANGES
:
892 headSerialReply(4 * MAX_MODE_ACTIVATION_CONDITION_COUNT
);
893 for (i
= 0; i
< MAX_MODE_ACTIVATION_CONDITION_COUNT
; i
++) {
894 modeActivationCondition_t
*mac
= &masterConfig
.modeActivationConditions
[i
];
895 const box_t
*box
= &boxes
[mac
->modeId
];
896 serialize8(box
->permanentId
);
897 serialize8(mac
->auxChannelIndex
);
898 serialize8(mac
->range
.startStep
);
899 serialize8(mac
->range
.endStep
);
902 case MSP_ADJUSTMENT_RANGES
:
903 headSerialReply(MAX_ADJUSTMENT_RANGE_COUNT
* (
904 1 + // adjustment index/slot
905 1 + // aux channel index
908 1 + // adjustment function
909 1 // aux switch channel index
911 for (i
= 0; i
< MAX_ADJUSTMENT_RANGE_COUNT
; i
++) {
912 adjustmentRange_t
*adjRange
= &masterConfig
.adjustmentRanges
[i
];
913 serialize8(adjRange
->adjustmentIndex
);
914 serialize8(adjRange
->auxChannelIndex
);
915 serialize8(adjRange
->range
.startStep
);
916 serialize8(adjRange
->range
.endStep
);
917 serialize8(adjRange
->adjustmentFunction
);
918 serialize8(adjRange
->auxSwitchChannelIndex
);
922 serializeBoxNamesReply();
925 headSerialReply(activeBoxIdCount
);
926 for (i
= 0; i
< activeBoxIdCount
; i
++) {
927 const box_t
*box
= findBoxByActiveBoxId(activeBoxIds
[i
]);
931 serialize8(box
->permanentId
);
935 headSerialReply(2 * 5 + 3 + 3 + 2 + 4);
936 serialize16(masterConfig
.rxConfig
.midrc
);
938 serialize16(masterConfig
.escAndServoConfig
.minthrottle
);
939 serialize16(masterConfig
.escAndServoConfig
.maxthrottle
);
940 serialize16(masterConfig
.escAndServoConfig
.mincommand
);
942 serialize16(masterConfig
.failsafeConfig
.failsafe_throttle
);
945 serialize8(masterConfig
.gpsConfig
.provider
); // gps_type
946 serialize8(0); // TODO gps_baudrate (an index, cleanflight uses a uint32_t
947 serialize8(masterConfig
.gpsConfig
.sbasMode
); // gps_ubx_sbas
949 serialize8(0); // gps_type
950 serialize8(0); // TODO gps_baudrate (an index, cleanflight uses a uint32_t
951 serialize8(0); // gps_ubx_sbas
953 serialize8(masterConfig
.batteryConfig
.multiwiiCurrentMeterOutput
);
954 serialize8(masterConfig
.rxConfig
.rssi_channel
);
957 serialize16(masterConfig
.mag_declination
/ 10);
959 serialize8(masterConfig
.batteryConfig
.vbatscale
);
960 serialize8(masterConfig
.batteryConfig
.vbatmincellvoltage
);
961 serialize8(masterConfig
.batteryConfig
.vbatmaxcellvoltage
);
962 serialize8(masterConfig
.batteryConfig
.vbatwarningcellvoltage
);
966 // FIXME This is hardcoded and should not be.
968 for (i
= 0; i
< 8; i
++)
974 serialize8(STATE(GPS_FIX
));
975 serialize8(GPS_numSat
);
976 serialize32(GPS_coord
[LAT
]);
977 serialize32(GPS_coord
[LON
]);
978 serialize16(GPS_altitude
);
979 serialize16(GPS_speed
);
980 serialize16(GPS_ground_course
);
984 serialize16(GPS_distanceToHome
);
985 serialize16(GPS_directionToHome
);
986 serialize8(GPS_update
& 1);
989 wp_no
= read8(); // get the wp number
994 } else if (wp_no
== 16) {
1001 serialize32(AltHold
); // altitude (cm) will come here -- temporary implementation to test feature with apps
1002 serialize16(0); // heading will come here (deg)
1003 serialize16(0); // time to stay (ms) will come here
1004 serialize8(0); // nav flag will come here
1007 headSerialReply(1 + (GPS_numCh
* 4));
1008 serialize8(GPS_numCh
);
1009 for (i
= 0; i
< GPS_numCh
; i
++){
1010 serialize8(GPS_svinfo_chn
[i
]);
1011 serialize8(GPS_svinfo_svid
[i
]);
1012 serialize8(GPS_svinfo_quality
[i
]);
1013 serialize8(GPS_svinfo_cno
[i
]);
1018 headSerialReply(DEBUG16_VALUE_COUNT
* sizeof(debug
[0]));
1020 // output some useful QA statistics
1021 // debug[x] = ((hse_value / 1000000) * 1000) + (SystemCoreClock / 1000000); // XX0YY [crystal clock : core clock]
1023 for (i
= 0; i
< DEBUG16_VALUE_COUNT
; i
++)
1024 serialize16(debug
[i
]); // 4 variables are here for general monitoring purpose
1027 // Additional commands that are not compatible with MultiWii
1030 serialize16(masterConfig
.accelerometerTrims
.values
.pitch
);
1031 serialize16(masterConfig
.accelerometerTrims
.values
.roll
);
1035 headSerialReply(12);
1036 serialize32(U_ID_0
);
1037 serialize32(U_ID_1
);
1038 serialize32(U_ID_2
);
1043 serialize32(featureMask());
1046 case MSP_BOARD_ALIGNMENT
:
1048 serialize16(masterConfig
.boardAlignment
.rollDegrees
);
1049 serialize16(masterConfig
.boardAlignment
.pitchDegrees
);
1050 serialize16(masterConfig
.boardAlignment
.yawDegrees
);
1053 case MSP_VOLTAGE_METER_CONFIG
:
1055 serialize8(masterConfig
.batteryConfig
.vbatscale
);
1056 serialize8(masterConfig
.batteryConfig
.vbatmincellvoltage
);
1057 serialize8(masterConfig
.batteryConfig
.vbatmaxcellvoltage
);
1058 serialize8(masterConfig
.batteryConfig
.vbatwarningcellvoltage
);
1061 case MSP_CURRENT_METER_CONFIG
:
1063 serialize16(masterConfig
.batteryConfig
.currentMeterScale
);
1064 serialize16(masterConfig
.batteryConfig
.currentMeterOffset
);
1065 serialize8(masterConfig
.batteryConfig
.currentMeterType
);
1066 serialize16(masterConfig
.batteryConfig
.batteryCapacity
);
1071 serialize8(masterConfig
.mixerMode
);
1075 headSerialReply(12);
1076 serialize8(masterConfig
.rxConfig
.serialrx_provider
);
1077 serialize16(masterConfig
.rxConfig
.maxcheck
);
1078 serialize16(masterConfig
.rxConfig
.midrc
);
1079 serialize16(masterConfig
.rxConfig
.mincheck
);
1080 serialize8(masterConfig
.rxConfig
.spektrum_sat_bind
);
1081 serialize16(masterConfig
.rxConfig
.rx_min_usec
);
1082 serialize16(masterConfig
.rxConfig
.rx_max_usec
);
1085 case MSP_FAILSAFE_CONFIG
:
1087 serialize8(masterConfig
.failsafeConfig
.failsafe_delay
);
1088 serialize8(masterConfig
.failsafeConfig
.failsafe_off_delay
);
1089 serialize16(masterConfig
.failsafeConfig
.failsafe_throttle
);
1090 serialize8(masterConfig
.failsafeConfig
.failsafe_kill_switch
);
1091 serialize16(masterConfig
.failsafeConfig
.failsafe_throttle_low_delay
);
1092 serialize8(masterConfig
.failsafeConfig
.failsafe_procedure
);
1095 case MSP_RXFAIL_CONFIG
:
1096 headSerialReply(3 * (rxRuntimeConfig
.channelCount
));
1097 for (i
= 0; i
< rxRuntimeConfig
.channelCount
; i
++) {
1098 serialize8(masterConfig
.rxConfig
.failsafe_channel_configurations
[i
].mode
);
1099 serialize16(RXFAIL_STEP_TO_CHANNEL_VALUE(masterConfig
.rxConfig
.failsafe_channel_configurations
[i
].step
));
1103 case MSP_RSSI_CONFIG
:
1105 serialize8(masterConfig
.rxConfig
.rssi_channel
);
1109 headSerialReply(MAX_MAPPABLE_RX_INPUTS
);
1110 for (i
= 0; i
< MAX_MAPPABLE_RX_INPUTS
; i
++)
1111 serialize8(masterConfig
.rxConfig
.rcmap
[i
]);
1115 headSerialReply(1 + 4 + 1 + 2 + 2 + 2 + 2 + 2);
1116 serialize8(masterConfig
.mixerMode
);
1118 serialize32(featureMask());
1120 serialize8(masterConfig
.rxConfig
.serialrx_provider
);
1122 serialize16(masterConfig
.boardAlignment
.rollDegrees
);
1123 serialize16(masterConfig
.boardAlignment
.pitchDegrees
);
1124 serialize16(masterConfig
.boardAlignment
.yawDegrees
);
1126 serialize16(masterConfig
.batteryConfig
.currentMeterScale
);
1127 serialize16(masterConfig
.batteryConfig
.currentMeterOffset
);
1130 case MSP_CF_SERIAL_CONFIG
:
1132 ((sizeof(uint8_t) + sizeof(uint16_t) + (sizeof(uint8_t) * 4)) * serialGetAvailablePortCount())
1134 for (i
= 0; i
< SERIAL_PORT_COUNT
; i
++) {
1135 if (!serialIsPortAvailable(masterConfig
.serialConfig
.portConfigs
[i
].identifier
)) {
1138 serialize8(masterConfig
.serialConfig
.portConfigs
[i
].identifier
);
1139 serialize16(masterConfig
.serialConfig
.portConfigs
[i
].functionMask
);
1140 serialize8(masterConfig
.serialConfig
.portConfigs
[i
].msp_baudrateIndex
);
1141 serialize8(masterConfig
.serialConfig
.portConfigs
[i
].gps_baudrateIndex
);
1142 serialize8(masterConfig
.serialConfig
.portConfigs
[i
].telemetry_baudrateIndex
);
1143 serialize8(masterConfig
.serialConfig
.portConfigs
[i
].blackbox_baudrateIndex
);
1148 case MSP_LED_COLORS
:
1149 headSerialReply(CONFIGURABLE_COLOR_COUNT
* 4);
1150 for (i
= 0; i
< CONFIGURABLE_COLOR_COUNT
; i
++) {
1151 hsvColor_t
*color
= &masterConfig
.colors
[i
];
1152 serialize16(color
->h
);
1153 serialize8(color
->s
);
1154 serialize8(color
->v
);
1158 case MSP_LED_STRIP_CONFIG
:
1159 headSerialReply(MAX_LED_STRIP_LENGTH
* 7);
1160 for (i
= 0; i
< MAX_LED_STRIP_LENGTH
; i
++) {
1161 ledConfig_t
*ledConfig
= &masterConfig
.ledConfigs
[i
];
1162 serialize16((ledConfig
->flags
& LED_DIRECTION_MASK
) >> LED_DIRECTION_BIT_OFFSET
);
1163 serialize16((ledConfig
->flags
& LED_FUNCTION_MASK
) >> LED_FUNCTION_BIT_OFFSET
);
1164 serialize8(GET_LED_X(ledConfig
));
1165 serialize8(GET_LED_Y(ledConfig
));
1166 serialize8(ledConfig
->color
);
1171 case MSP_DATAFLASH_SUMMARY
:
1172 serializeDataflashSummaryReply();
1176 case MSP_DATAFLASH_READ
:
1178 uint32_t readAddress
= read32();
1180 serializeDataflashReadReply(readAddress
, 128);
1185 case MSP_BLACKBOX_CONFIG
:
1189 serialize8(1); //Blackbox supported
1190 serialize8(masterConfig
.blackbox_device
);
1191 serialize8(masterConfig
.blackbox_rate_num
);
1192 serialize8(masterConfig
.blackbox_rate_denom
);
1194 serialize8(0); // Blackbox not supported
1201 case MSP_SDCARD_SUMMARY
:
1202 serializeSDCardSummaryReply();
1205 case MSP_TRANSPONDER_CONFIG
:
1207 headSerialReply(1 + sizeof(masterConfig
.transponderData
));
1209 serialize8(1); //Transponder supported
1211 for (i
= 0; i
< sizeof(masterConfig
.transponderData
); i
++) {
1212 serialize8(masterConfig
.transponderData
[i
]);
1216 serialize8(0); // Transponder not supported
1220 case MSP_BF_BUILD_INFO
:
1221 headSerialReply(11 + 4 + 4);
1222 for (i
= 0; i
< 11; i
++)
1223 serialize8(buildDate
[i
]); // MMM DD YYYY as ascii, MMM = Jan/Feb... etc
1224 serialize32(0); // future exp
1225 serialize32(0); // future exp
1229 headSerialReply(2 * 4);
1230 serialize16(masterConfig
.flight3DConfig
.deadband3d_low
);
1231 serialize16(masterConfig
.flight3DConfig
.deadband3d_high
);
1232 serialize16(masterConfig
.flight3DConfig
.neutral3d
);
1233 serialize16(masterConfig
.flight3DConfig
.deadband3d_throttle
);
1236 case MSP_RC_DEADBAND
:
1238 serialize8(masterConfig
.rcControlsConfig
.deadband
);
1239 serialize8(masterConfig
.rcControlsConfig
.yaw_deadband
);
1240 serialize8(masterConfig
.rcControlsConfig
.alt_hold_deadband
);
1242 case MSP_SENSOR_ALIGNMENT
:
1244 serialize8(masterConfig
.sensorAlignmentConfig
.gyro_align
);
1245 serialize8(masterConfig
.sensorAlignmentConfig
.acc_align
);
1246 serialize8(masterConfig
.sensorAlignmentConfig
.mag_align
);
1255 static bool processInCommand(void)
1263 int32_t lat
= 0, lon
= 0, alt
= 0;
1266 switch (currentPort
->cmdMSP
) {
1267 case MSP_SELECT_SETTING
:
1268 if (!ARMING_FLAG(ARMED
)) {
1269 masterConfig
.current_profile_index
= read8();
1270 if (masterConfig
.current_profile_index
> 1) {
1271 masterConfig
.current_profile_index
= 0;
1280 case MSP_SET_RAW_RC
:
1282 uint8_t channelCount
= currentPort
->dataSize
/ sizeof(uint16_t);
1283 if (channelCount
> MAX_SUPPORTED_RC_CHANNEL_COUNT
) {
1286 uint16_t frame
[MAX_SUPPORTED_RC_CHANNEL_COUNT
];
1288 for (i
= 0; i
< channelCount
; i
++) {
1289 frame
[i
] = read16();
1292 rxMspFrameReceive(frame
, channelCount
);
1296 case MSP_SET_ACC_TRIM
:
1297 masterConfig
.accelerometerTrims
.values
.pitch
= read16();
1298 masterConfig
.accelerometerTrims
.values
.roll
= read16();
1300 case MSP_SET_ARMING_CONFIG
:
1301 masterConfig
.auto_disarm_delay
= read8();
1302 masterConfig
.disarm_kill_switch
= read8();
1304 case MSP_SET_LOOP_TIME
:
1305 setGyroSamplingSpeed(read16());
1307 case MSP_SET_PID_CONTROLLER
:
1308 oldPid
= currentProfile
->pidProfile
.pidController
;
1309 currentProfile
->pidProfile
.pidController
= constrain(read8(), 1, 2);
1310 pidSetController(currentProfile
->pidProfile
.pidController
);
1311 if (oldPid
!= currentProfile
->pidProfile
.pidController
) setGyroSamplingSpeed(0); // recalculate looptimes for new PID
1314 for (i
= 0; i
< PID_ITEM_COUNT
; i
++) {
1315 currentProfile
->pidProfile
.P8
[i
] = read8();
1316 currentProfile
->pidProfile
.I8
[i
] = read8();
1317 currentProfile
->pidProfile
.D8
[i
] = read8();
1320 case MSP_SET_MODE_RANGE
:
1322 if (i
< MAX_MODE_ACTIVATION_CONDITION_COUNT
) {
1323 modeActivationCondition_t
*mac
= &masterConfig
.modeActivationConditions
[i
];
1325 const box_t
*box
= findBoxByPermenantId(i
);
1327 mac
->modeId
= box
->boxId
;
1328 mac
->auxChannelIndex
= read8();
1329 mac
->range
.startStep
= read8();
1330 mac
->range
.endStep
= read8();
1332 useRcControlsConfig(masterConfig
.modeActivationConditions
, &masterConfig
.escAndServoConfig
, ¤tProfile
->pidProfile
);
1340 case MSP_SET_ADJUSTMENT_RANGE
:
1342 if (i
< MAX_ADJUSTMENT_RANGE_COUNT
) {
1343 adjustmentRange_t
*adjRange
= &masterConfig
.adjustmentRanges
[i
];
1345 if (i
< MAX_SIMULTANEOUS_ADJUSTMENT_COUNT
) {
1346 adjRange
->adjustmentIndex
= i
;
1347 adjRange
->auxChannelIndex
= read8();
1348 adjRange
->range
.startStep
= read8();
1349 adjRange
->range
.endStep
= read8();
1350 adjRange
->adjustmentFunction
= read8();
1351 adjRange
->auxSwitchChannelIndex
= read8();
1360 case MSP_SET_RC_TUNING
:
1361 if (currentPort
->dataSize
>= 10) {
1362 currentControlRateProfile
->rcRate8
= read8();
1363 currentControlRateProfile
->rcExpo8
= read8();
1364 for (i
= 0; i
< 3; i
++) {
1366 currentControlRateProfile
->rates
[i
] = MIN(rate
, i
== FD_YAW
? CONTROL_RATE_CONFIG_YAW_RATE_MAX
: CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MAX
);
1369 currentControlRateProfile
->dynThrPID
= MIN(rate
, CONTROL_RATE_CONFIG_TPA_MAX
);
1370 currentControlRateProfile
->thrMid8
= read8();
1371 currentControlRateProfile
->thrExpo8
= read8();
1372 currentControlRateProfile
->tpa_breakpoint
= read16();
1373 if (currentPort
->dataSize
>= 11) {
1374 currentControlRateProfile
->rcYawExpo8
= read8();
1382 if (tmp
< 1600 && tmp
> 1400)
1383 masterConfig
.rxConfig
.midrc
= tmp
;
1385 masterConfig
.escAndServoConfig
.minthrottle
= read16();
1386 masterConfig
.escAndServoConfig
.maxthrottle
= read16();
1387 masterConfig
.escAndServoConfig
.mincommand
= read16();
1389 masterConfig
.failsafeConfig
.failsafe_throttle
= read16();
1392 masterConfig
.gpsConfig
.provider
= read8(); // gps_type
1393 read8(); // gps_baudrate
1394 masterConfig
.gpsConfig
.sbasMode
= read8(); // gps_ubx_sbas
1396 read8(); // gps_type
1397 read8(); // gps_baudrate
1398 read8(); // gps_ubx_sbas
1400 masterConfig
.batteryConfig
.multiwiiCurrentMeterOutput
= read8();
1401 masterConfig
.rxConfig
.rssi_channel
= read8();
1404 masterConfig
.mag_declination
= read16() * 10;
1406 masterConfig
.batteryConfig
.vbatscale
= read8(); // actual vbatscale as intended
1407 masterConfig
.batteryConfig
.vbatmincellvoltage
= read8(); // vbatlevel_warn1 in MWC2.3 GUI
1408 masterConfig
.batteryConfig
.vbatmaxcellvoltage
= read8(); // vbatlevel_warn2 in MWC2.3 GUI
1409 masterConfig
.batteryConfig
.vbatwarningcellvoltage
= read8(); // vbatlevel when buzzer starts to alert
1412 for (i
= 0; i
< 8; i
++) // FIXME should this use MAX_MOTORS or MAX_SUPPORTED_MOTORS instead of 8
1413 motor_disarmed
[i
] = read16();
1415 case MSP_SET_SERVO_CONFIGURATION
:
1417 if (currentPort
->dataSize
!= 1 + sizeof(servoParam_t
)) {
1422 if (i
>= MAX_SUPPORTED_SERVOS
) {
1425 masterConfig
.servoConf
[i
].min
= read16();
1426 masterConfig
.servoConf
[i
].max
= read16();
1427 masterConfig
.servoConf
[i
].middle
= read16();
1428 masterConfig
.servoConf
[i
].rate
= read8();
1429 masterConfig
.servoConf
[i
].angleAtMin
= read8();
1430 masterConfig
.servoConf
[i
].angleAtMax
= read8();
1431 masterConfig
.servoConf
[i
].forwardFromChannel
= read8();
1432 masterConfig
.servoConf
[i
].reversedSources
= read32();
1437 case MSP_SET_SERVO_MIX_RULE
:
1440 if (i
>= MAX_SERVO_RULES
) {
1443 masterConfig
.customServoMixer
[i
].targetChannel
= read8();
1444 masterConfig
.customServoMixer
[i
].inputSource
= read8();
1445 masterConfig
.customServoMixer
[i
].rate
= read8();
1446 masterConfig
.customServoMixer
[i
].speed
= read8();
1447 masterConfig
.customServoMixer
[i
].min
= read8();
1448 masterConfig
.customServoMixer
[i
].max
= read8();
1449 masterConfig
.customServoMixer
[i
].box
= read8();
1450 loadCustomServoMixer();
1456 masterConfig
.flight3DConfig
.deadband3d_low
= read16();
1457 masterConfig
.flight3DConfig
.deadband3d_high
= read16();
1458 masterConfig
.flight3DConfig
.neutral3d
= read16();
1459 masterConfig
.flight3DConfig
.deadband3d_throttle
= read16();
1462 case MSP_SET_RC_DEADBAND
:
1463 masterConfig
.rcControlsConfig
.deadband
= read8();
1464 masterConfig
.rcControlsConfig
.yaw_deadband
= read8();
1465 masterConfig
.rcControlsConfig
.alt_hold_deadband
= read8();
1468 case MSP_SET_RESET_CURR_PID
:
1469 //resetPidProfile(¤tProfile->pidProfile);
1472 case MSP_SET_SENSOR_ALIGNMENT
:
1473 masterConfig
.sensorAlignmentConfig
.gyro_align
= read8();
1474 masterConfig
.sensorAlignmentConfig
.acc_align
= read8();
1475 masterConfig
.sensorAlignmentConfig
.mag_align
= read8();
1478 case MSP_RESET_CONF
:
1479 if (!ARMING_FLAG(ARMED
)) {
1484 case MSP_ACC_CALIBRATION
:
1485 if (!ARMING_FLAG(ARMED
))
1486 accSetCalibrationCycles(CALIBRATING_ACC_CYCLES
);
1488 case MSP_MAG_CALIBRATION
:
1489 if (!ARMING_FLAG(ARMED
))
1490 ENABLE_STATE(CALIBRATE_MAG
);
1492 case MSP_EEPROM_WRITE
:
1493 if (ARMING_FLAG(ARMED
)) {
1502 case MSP_SET_BLACKBOX_CONFIG
:
1503 // Don't allow config to be updated while Blackbox is logging
1504 if (blackboxMayEditConfig()) {
1505 masterConfig
.blackbox_device
= read8();
1506 masterConfig
.blackbox_rate_num
= read8();
1507 masterConfig
.blackbox_rate_denom
= read8();
1513 case MSP_SET_TRANSPONDER_CONFIG
:
1514 if (currentPort
->dataSize
!= sizeof(masterConfig
.transponderData
)) {
1519 for (i
= 0; i
< sizeof(masterConfig
.transponderData
); i
++) {
1520 masterConfig
.transponderData
[i
] = read8();
1523 transponderUpdateData(masterConfig
.transponderData
);
1528 case MSP_DATAFLASH_ERASE
:
1529 flashfsEraseCompletely();
1534 case MSP_SET_RAW_GPS
:
1536 ENABLE_STATE(GPS_FIX
);
1538 DISABLE_STATE(GPS_FIX
);
1540 GPS_numSat
= read8();
1541 GPS_coord
[LAT
] = read32();
1542 GPS_coord
[LON
] = read32();
1543 GPS_altitude
= read16();
1544 GPS_speed
= read16();
1545 GPS_update
|= 2; // New data signalisation to GPS functions // FIXME Magic Numbers
1548 wp_no
= read8(); //get the wp number
1551 alt
= read32(); // to set altitude (cm)
1552 read16(); // future: to set heading (deg)
1553 read16(); // future: to set time to stay (ms)
1554 read8(); // future: to set nav flag
1556 GPS_home
[LAT
] = lat
;
1557 GPS_home
[LON
] = lon
;
1558 DISABLE_FLIGHT_MODE(GPS_HOME_MODE
); // with this flag, GPS_set_next_wp will be called in the next loop -- OK with SERIAL GPS / OK with I2C GPS
1559 ENABLE_STATE(GPS_FIX_HOME
);
1561 AltHold
= alt
; // temporary implementation to test feature with apps
1562 } else if (wp_no
== 16) { // OK with SERIAL GPS -- NOK for I2C GPS / needs more code dev in order to inject GPS coord inside I2C GPS
1563 GPS_hold
[LAT
] = lat
;
1564 GPS_hold
[LON
] = lon
;
1566 AltHold
= alt
; // temporary implementation to test feature with apps
1567 nav_mode
= NAV_MODE_WP
;
1568 GPS_set_next_wp(&GPS_hold
[LAT
], &GPS_hold
[LON
]);
1572 case MSP_SET_FEATURE
:
1574 featureSet(read32()); // features bitmap
1577 case MSP_SET_BOARD_ALIGNMENT
:
1578 masterConfig
.boardAlignment
.rollDegrees
= read16();
1579 masterConfig
.boardAlignment
.pitchDegrees
= read16();
1580 masterConfig
.boardAlignment
.yawDegrees
= read16();
1583 case MSP_SET_VOLTAGE_METER_CONFIG
:
1584 masterConfig
.batteryConfig
.vbatscale
= read8(); // actual vbatscale as intended
1585 masterConfig
.batteryConfig
.vbatmincellvoltage
= read8(); // vbatlevel_warn1 in MWC2.3 GUI
1586 masterConfig
.batteryConfig
.vbatmaxcellvoltage
= read8(); // vbatlevel_warn2 in MWC2.3 GUI
1587 masterConfig
.batteryConfig
.vbatwarningcellvoltage
= read8(); // vbatlevel when buzzer starts to alert
1590 case MSP_SET_CURRENT_METER_CONFIG
:
1591 masterConfig
.batteryConfig
.currentMeterScale
= read16();
1592 masterConfig
.batteryConfig
.currentMeterOffset
= read16();
1593 masterConfig
.batteryConfig
.currentMeterType
= read8();
1594 masterConfig
.batteryConfig
.batteryCapacity
= read16();
1597 #ifndef USE_QUAD_MIXER_ONLY
1599 masterConfig
.mixerMode
= read8();
1603 case MSP_SET_RX_CONFIG
:
1604 masterConfig
.rxConfig
.serialrx_provider
= read8();
1605 masterConfig
.rxConfig
.maxcheck
= read16();
1606 masterConfig
.rxConfig
.midrc
= read16();
1607 masterConfig
.rxConfig
.mincheck
= read16();
1608 masterConfig
.rxConfig
.spektrum_sat_bind
= read8();
1609 if (currentPort
->dataSize
> 8) {
1610 masterConfig
.rxConfig
.rx_min_usec
= read16();
1611 masterConfig
.rxConfig
.rx_max_usec
= read16();
1615 case MSP_SET_FAILSAFE_CONFIG
:
1616 masterConfig
.failsafeConfig
.failsafe_delay
= read8();
1617 masterConfig
.failsafeConfig
.failsafe_off_delay
= read8();
1618 masterConfig
.failsafeConfig
.failsafe_throttle
= read16();
1619 masterConfig
.failsafeConfig
.failsafe_kill_switch
= read8();
1620 masterConfig
.failsafeConfig
.failsafe_throttle_low_delay
= read16();
1621 masterConfig
.failsafeConfig
.failsafe_procedure
= read8();
1624 case MSP_SET_RXFAIL_CONFIG
:
1626 if (i
< MAX_SUPPORTED_RC_CHANNEL_COUNT
) {
1627 masterConfig
.rxConfig
.failsafe_channel_configurations
[i
].mode
= read8();
1628 masterConfig
.rxConfig
.failsafe_channel_configurations
[i
].step
= CHANNEL_VALUE_TO_RXFAIL_STEP(read16());
1634 case MSP_SET_RSSI_CONFIG
:
1635 masterConfig
.rxConfig
.rssi_channel
= read8();
1638 case MSP_SET_RX_MAP
:
1639 for (i
= 0; i
< MAX_MAPPABLE_RX_INPUTS
; i
++) {
1640 masterConfig
.rxConfig
.rcmap
[i
] = read8();
1644 case MSP_SET_BF_CONFIG
:
1646 #ifdef USE_QUAD_MIXER_ONLY
1647 read8(); // mixerMode ignored
1649 masterConfig
.mixerMode
= read8(); // mixerMode
1653 featureSet(read32()); // features bitmap
1655 masterConfig
.rxConfig
.serialrx_provider
= read8(); // serialrx_type
1657 masterConfig
.boardAlignment
.rollDegrees
= read16(); // board_align_roll
1658 masterConfig
.boardAlignment
.pitchDegrees
= read16(); // board_align_pitch
1659 masterConfig
.boardAlignment
.yawDegrees
= read16(); // board_align_yaw
1661 masterConfig
.batteryConfig
.currentMeterScale
= read16();
1662 masterConfig
.batteryConfig
.currentMeterOffset
= read16();
1665 case MSP_SET_CF_SERIAL_CONFIG
:
1667 uint8_t portConfigSize
= sizeof(uint8_t) + sizeof(uint16_t) + (sizeof(uint8_t) * 4);
1669 if (currentPort
->dataSize
% portConfigSize
!= 0) {
1674 uint8_t remainingPortsInPacket
= currentPort
->dataSize
/ portConfigSize
;
1676 while (remainingPortsInPacket
--) {
1677 uint8_t identifier
= read8();
1679 serialPortConfig_t
*portConfig
= serialFindPortConfiguration(identifier
);
1685 portConfig
->identifier
= identifier
;
1686 portConfig
->functionMask
= read16();
1687 portConfig
->msp_baudrateIndex
= read8();
1688 portConfig
->gps_baudrateIndex
= read8();
1689 portConfig
->telemetry_baudrateIndex
= read8();
1690 portConfig
->blackbox_baudrateIndex
= read8();
1696 case MSP_SET_LED_COLORS
:
1697 for (i
= 0; i
< CONFIGURABLE_COLOR_COUNT
; i
++) {
1698 hsvColor_t
*color
= &masterConfig
.colors
[i
];
1699 color
->h
= read16();
1705 case MSP_SET_LED_STRIP_CONFIG
:
1708 if (i
>= MAX_LED_STRIP_LENGTH
|| currentPort
->dataSize
!= (1 + 7)) {
1712 ledConfig_t
*ledConfig
= &masterConfig
.ledConfigs
[i
];
1714 // currently we're storing directions and functions in a uint16 (flags)
1715 // the msp uses 2 x uint16_t to cater for future expansion
1717 ledConfig
->flags
= (mask
<< LED_DIRECTION_BIT_OFFSET
) & LED_DIRECTION_MASK
;
1720 ledConfig
->flags
|= (mask
<< LED_FUNCTION_BIT_OFFSET
) & LED_FUNCTION_MASK
;
1723 ledConfig
->xy
= CALCULATE_LED_X(mask
);
1726 ledConfig
->xy
|= CALCULATE_LED_Y(mask
);
1728 ledConfig
->color
= read8();
1730 reevalulateLedConfig();
1735 isRebootScheduled
= true;
1738 #ifdef USE_SERIAL_4WAY_BLHELI_INTERFACE
1739 case MSP_SET_4WAY_IF
:
1740 // get channel number
1741 // switch all motor lines HI
1742 // reply the count of ESC found
1744 serialize8(Initialize4WayInterface());
1745 // because we do not come back after calling Process4WayInterface
1746 // proceed with a success reply first
1748 // flush the transmit buffer
1749 bufWriterFlush(writer
);
1750 // wait for all data to send
1751 waitForSerialPortToFinishTransmitting(currentPort
->port
);
1752 // rem: App: Wait at least appx. 500 ms for BLHeli to jump into
1753 // bootloader mode before try to connect any ESC
1754 // Start to activate here
1755 Process4WayInterface(currentPort
, writer
);
1756 // former used MSP uart is still active
1757 // proceed as usual with MSP commands
1761 // we do not know how to handle the (valid) message, indicate error MSP $M!
1768 STATIC_UNIT_TESTED
void mspProcessReceivedCommand() {
1769 if (!(processOutCommand(currentPort
->cmdMSP
) || processInCommand())) {
1773 currentPort
->c_state
= IDLE
;
1776 static bool mspProcessReceivedData(uint8_t c
)
1778 if (currentPort
->c_state
== IDLE
) {
1780 currentPort
->c_state
= HEADER_START
;
1784 } else if (currentPort
->c_state
== HEADER_START
) {
1785 currentPort
->c_state
= (c
== 'M') ? HEADER_M
: IDLE
;
1786 } else if (currentPort
->c_state
== HEADER_M
) {
1787 currentPort
->c_state
= (c
== '<') ? HEADER_ARROW
: IDLE
;
1788 } else if (currentPort
->c_state
== HEADER_ARROW
) {
1789 if (c
> MSP_PORT_INBUF_SIZE
) {
1790 currentPort
->c_state
= IDLE
;
1793 currentPort
->dataSize
= c
;
1794 currentPort
->offset
= 0;
1795 currentPort
->checksum
= 0;
1796 currentPort
->indRX
= 0;
1797 currentPort
->checksum
^= c
;
1798 currentPort
->c_state
= HEADER_SIZE
;
1800 } else if (currentPort
->c_state
== HEADER_SIZE
) {
1801 currentPort
->cmdMSP
= c
;
1802 currentPort
->checksum
^= c
;
1803 currentPort
->c_state
= HEADER_CMD
;
1804 } else if (currentPort
->c_state
== HEADER_CMD
&& currentPort
->offset
< currentPort
->dataSize
) {
1805 currentPort
->checksum
^= c
;
1806 currentPort
->inBuf
[currentPort
->offset
++] = c
;
1807 } else if (currentPort
->c_state
== HEADER_CMD
&& currentPort
->offset
>= currentPort
->dataSize
) {
1808 if (currentPort
->checksum
== c
) {
1809 currentPort
->c_state
= COMMAND_RECEIVED
;
1811 currentPort
->c_state
= IDLE
;
1817 STATIC_UNIT_TESTED
void setCurrentPort(mspPort_t
*port
)
1820 mspSerialPort
= currentPort
->port
;
1823 void mspProcess(void)
1826 mspPort_t
*candidatePort
;
1828 for (portIndex
= 0; portIndex
< MAX_MSP_PORT_COUNT
; portIndex
++) {
1829 candidatePort
= &mspPorts
[portIndex
];
1830 if (!candidatePort
->port
) {
1834 setCurrentPort(candidatePort
);
1835 // Big enough to fit a MSP_STATUS in one write.
1836 uint8_t buf
[sizeof(bufWriter_t
) + 20];
1837 writer
= bufWriterInit(buf
, sizeof(buf
),
1838 (bufWrite_t
)serialWriteBufShim
, currentPort
->port
);
1840 while (serialRxBytesWaiting(mspSerialPort
)) {
1842 uint8_t c
= serialRead(mspSerialPort
);
1843 bool consumed
= mspProcessReceivedData(c
);
1845 if (!consumed
&& !ARMING_FLAG(ARMED
)) {
1846 evaluateOtherData(mspSerialPort
, c
);
1849 if (currentPort
->c_state
== COMMAND_RECEIVED
) {
1850 mspProcessReceivedCommand();
1851 break; // process one command at a time so as not to block.
1855 bufWriterFlush(writer
);
1857 if (isRebootScheduled
) {
1858 waitForSerialPortToFinishTransmitting(candidatePort
->port
);
1860 handleOneshotFeatureChangeOnRestart();
1861 // On real flight controllers, systemReset() will do a soft reset of the device,
1862 // reloading the program. But to support offline testing this flag needs to be
1863 // cleared so that the software doesn't continuously attempt to reboot itself.
1864 isRebootScheduled
= false;