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"
61 #include "telemetry/telemetry.h"
63 #include "sensors/boardalignment.h"
64 #include "sensors/sensors.h"
65 #include "sensors/battery.h"
66 #include "sensors/sonar.h"
67 #include "sensors/acceleration.h"
68 #include "sensors/barometer.h"
69 #include "sensors/compass.h"
70 #include "sensors/gyro.h"
72 #include "flight/mixer.h"
73 #include "flight/pid.h"
74 #include "flight/imu.h"
75 #include "flight/failsafe.h"
76 #include "flight/navigation.h"
77 #include "flight/altitudehold.h"
79 #include "blackbox/blackbox.h"
83 #include "config/runtime_config.h"
84 #include "config/config.h"
85 #include "config/config_profile.h"
86 #include "config/config_master.h"
89 #ifdef USE_HARDWARE_REVISION_DETECTION
90 #include "hardware_revision.h"
93 #include "serial_msp.h"
95 #ifdef USE_SERIAL_1WIRE
96 #include "io/serial_1wire.h"
99 #include "drivers/serial_escserial.h"
101 static serialPort_t
*mspSerialPort
;
103 extern uint16_t cycleTime
; // FIXME dependency on mw.c
104 extern uint16_t rssi
; // FIXME dependency on mw.c
105 extern void resetPidProfile(pidProfile_t
*pidProfile
);
108 void setGyroSamplingSpeed(uint16_t looptime
) {
109 uint16_t gyroSampleRate
= 1000;
110 uint8_t maxDivider
= 1;
112 if (looptime
!= targetLooptime
|| looptime
== 0) {
113 if (looptime
== 0) looptime
= targetLooptime
; // needed for pid controller changes
115 if (looptime
< 1000) {
116 masterConfig
.gyro_lpf
= 0;
117 gyroSampleRate
= 125;
119 masterConfig
.pid_process_denom
= 1;
120 masterConfig
.acc_hardware
= 0;
121 masterConfig
.baro_hardware
= 0;
122 masterConfig
.mag_hardware
= 0;
123 if (looptime
< 250) {
124 masterConfig
.acc_hardware
= 1;
125 masterConfig
.baro_hardware
= 1;
126 masterConfig
.mag_hardware
= 1;
127 masterConfig
.pid_process_denom
= 2;
128 } else if (looptime
< 375) {
129 #if defined(LUX_RACE) || defined(COLIBRI_RACE) || defined(MOTOLAB) || defined(ALIENFLIGHTF3)
130 masterConfig
.acc_hardware
= 0;
132 masterConfig
.acc_hardware
= 1;
134 masterConfig
.baro_hardware
= 1;
135 masterConfig
.mag_hardware
= 1;
136 masterConfig
.pid_process_denom
= 2;
138 masterConfig
.gyro_sync_denom
= constrain(looptime
/ gyroSampleRate
, 1, maxDivider
);
140 masterConfig
.gyro_lpf
= 0;
141 masterConfig
.gyro_sync_denom
= 8;
142 masterConfig
.acc_hardware
= 0;
143 masterConfig
.baro_hardware
= 0;
144 masterConfig
.mag_hardware
= 0;
147 if (looptime
< 1000) {
148 masterConfig
.gyro_lpf
= 0;
149 masterConfig
.acc_hardware
= 1;
150 masterConfig
.baro_hardware
= 1;
151 masterConfig
.mag_hardware
= 1;
152 gyroSampleRate
= 125;
154 masterConfig
.pid_process_denom
= 1;
155 if (currentProfile
->pidProfile
.pidController
== 2) masterConfig
.pid_process_denom
= 2;
156 if (looptime
< 250) {
157 masterConfig
.pid_process_denom
= 3;
158 } else if (looptime
< 375) {
159 if (currentProfile
->pidProfile
.pidController
== 2) {
160 masterConfig
.pid_process_denom
= 3;
162 masterConfig
.pid_process_denom
= 2;
165 masterConfig
.gyro_sync_denom
= constrain(looptime
/ gyroSampleRate
, 1, maxDivider
);
167 masterConfig
.gyro_lpf
= 0;
169 masterConfig
.gyro_sync_denom
= 8;
170 masterConfig
.acc_hardware
= 0;
171 masterConfig
.baro_hardware
= 0;
172 masterConfig
.mag_hardware
= 0;
173 masterConfig
.pid_process_denom
= 1;
177 if (!(masterConfig
.use_multiShot
|| masterConfig
.use_oneshot42
) && ((masterConfig
.gyro_sync_denom
* gyroSampleRate
) == 125)) masterConfig
.pid_process_denom
= 3;
181 void useRcControlsConfig(modeActivationCondition_t
*modeActivationConditions
, escAndServoConfig_t
*escAndServoConfigToUse
, pidProfile_t
*pidProfileToUse
);
183 const char * const flightControllerIdentifier
= BETAFLIGHT_IDENTIFIER
; // 4 UPPER CASE alpha numeric characters that identify the flight controller.
185 typedef struct box_e
{
186 const uint8_t boxId
; // see boxId_e
187 const char *boxName
; // GUI-readable box name
188 const uint8_t permanentId
; //
192 static const box_t boxes
[CHECKBOX_ITEM_COUNT
+ 1] = {
193 { BOXARM
, "ARM;", 0 },
194 { BOXANGLE
, "ANGLE;", 1 },
195 { BOXHORIZON
, "HORIZON;", 2 },
196 { BOXBARO
, "BARO;", 3 },
197 //{ BOXVARIO, "VARIO;", 4 },
198 { BOXMAG
, "MAG;", 5 },
199 { BOXHEADFREE
, "HEADFREE;", 6 },
200 { BOXHEADADJ
, "HEADADJ;", 7 },
201 { BOXCAMSTAB
, "CAMSTAB;", 8 },
202 { BOXCAMTRIG
, "CAMTRIG;", 9 },
203 { BOXGPSHOME
, "GPS HOME;", 10 },
204 { BOXGPSHOLD
, "GPS HOLD;", 11 },
205 { BOXPASSTHRU
, "PASSTHRU;", 12 },
206 { BOXBEEPERON
, "BEEPER;", 13 },
207 { BOXLEDMAX
, "LEDMAX;", 14 },
208 { BOXLEDLOW
, "LEDLOW;", 15 },
209 { BOXLLIGHTS
, "LLIGHTS;", 16 },
210 { BOXCALIB
, "CALIB;", 17 },
211 { BOXGOV
, "GOVERNOR;", 18 },
212 { BOXOSD
, "OSD SW;", 19 },
213 { BOXTELEMETRY
, "TELEMETRY;", 20 },
214 { BOXGTUNE
, "GTUNE;", 21 },
215 { BOXSONAR
, "SONAR;", 22 },
216 { BOXSERVO1
, "SERVO1;", 23 },
217 { BOXSERVO2
, "SERVO2;", 24 },
218 { BOXSERVO3
, "SERVO3;", 25 },
219 { BOXBLACKBOX
, "BLACKBOX;", 26 },
220 { BOXFAILSAFE
, "FAILSAFE;", 27 },
221 { BOXAIRMODE
, "AIR MODE;", 28 },
222 { BOXACROPLUS
, "ACRO PLUS;", 29 },
223 { BOX3DDISABLESWITCH
, "DISABLE 3D SWITCH;", 30},
224 { CHECKBOX_ITEM_COUNT
, NULL
, 0xFF }
227 // this is calculated at startup based on enabled features.
228 static uint8_t activeBoxIds
[CHECKBOX_ITEM_COUNT
];
229 // this is the number of filled indexes in above array
230 static uint8_t activeBoxIdCount
= 0;
232 extern int16_t motor_disarmed
[MAX_SUPPORTED_MOTORS
];
234 // cause reboot after MSP processing complete
235 static bool isRebootScheduled
= false;
237 static const char pidnames
[] =
250 MSP_SDCARD_STATE_NOT_PRESENT
= 0,
251 MSP_SDCARD_STATE_FATAL
= 1,
252 MSP_SDCARD_STATE_CARD_INIT
= 2,
253 MSP_SDCARD_STATE_FS_INIT
= 3,
254 MSP_SDCARD_STATE_READY
= 4
258 STATIC_UNIT_TESTED mspPort_t mspPorts
[MAX_MSP_PORT_COUNT
];
260 STATIC_UNIT_TESTED mspPort_t
*currentPort
;
261 STATIC_UNIT_TESTED bufWriter_t
*writer
;
263 static void serialize8(uint8_t a
)
265 bufWriterAppend(writer
, a
);
266 currentPort
->checksum
^= a
;
269 static void serialize16(uint16_t a
)
271 serialize8((uint8_t)(a
>> 0));
272 serialize8((uint8_t)(a
>> 8));
275 static void serialize32(uint32_t a
)
277 serialize16((uint16_t)(a
>> 0));
278 serialize16((uint16_t)(a
>> 16));
281 static uint8_t read8(void)
283 return currentPort
->inBuf
[currentPort
->indRX
++] & 0xff;
286 static uint16_t read16(void)
288 uint16_t t
= read8();
289 t
+= (uint16_t)read8() << 8;
293 static uint32_t read32(void)
295 uint32_t t
= read16();
296 t
+= (uint32_t)read16() << 16;
300 static void headSerialResponse(uint8_t err
, uint8_t responseBodySize
)
302 serialBeginWrite(mspSerialPort
);
306 serialize8(err
? '!' : '>');
307 currentPort
->checksum
= 0; // start calculating a new checksum
308 serialize8(responseBodySize
);
309 serialize8(currentPort
->cmdMSP
);
312 static void headSerialReply(uint8_t responseBodySize
)
314 headSerialResponse(0, responseBodySize
);
317 static void headSerialError(uint8_t responseBodySize
)
319 headSerialResponse(1, responseBodySize
);
322 static void tailSerialReply(void)
324 serialize8(currentPort
->checksum
);
325 serialEndWrite(mspSerialPort
);
328 static void s_struct(uint8_t *cb
, uint8_t siz
)
330 headSerialReply(siz
);
335 static void serializeNames(const char *s
)
342 static const box_t
*findBoxByActiveBoxId(uint8_t activeBoxId
)
345 const box_t
*candidate
;
346 for (boxIndex
= 0; boxIndex
< sizeof(boxes
) / sizeof(box_t
); boxIndex
++) {
347 candidate
= &boxes
[boxIndex
];
348 if (candidate
->boxId
== activeBoxId
) {
355 static const box_t
*findBoxByPermenantId(uint8_t permenantId
)
358 const box_t
*candidate
;
359 for (boxIndex
= 0; boxIndex
< sizeof(boxes
) / sizeof(box_t
); boxIndex
++) {
360 candidate
= &boxes
[boxIndex
];
361 if (candidate
->permanentId
== permenantId
) {
368 static void serializeBoxNamesReply(void)
370 int i
, activeBoxId
, j
, flag
= 1, count
= 0, len
;
374 // in first run of the loop, we grab total size of junk to be sent
375 // then come back and actually send it
376 for (i
= 0; i
< activeBoxIdCount
; i
++) {
377 activeBoxId
= activeBoxIds
[i
];
379 box
= findBoxByActiveBoxId(activeBoxId
);
384 len
= strlen(box
->boxName
);
388 for (j
= 0; j
< len
; j
++)
389 serialize8(box
->boxName
[j
]);
394 headSerialReply(count
);
400 static void serializeSDCardSummaryReply(void)
402 headSerialReply(3 + 4 + 4);
405 uint8_t flags
= 1 /* SD card supported */ ;
410 // Merge the card and filesystem states together
411 if (!sdcard_isInserted()) {
412 state
= MSP_SDCARD_STATE_NOT_PRESENT
;
413 } else if (!sdcard_isFunctional()) {
414 state
= MSP_SDCARD_STATE_FATAL
;
416 switch (afatfs_getFilesystemState()) {
417 case AFATFS_FILESYSTEM_STATE_READY
:
418 state
= MSP_SDCARD_STATE_READY
;
420 case AFATFS_FILESYSTEM_STATE_INITIALIZATION
:
421 if (sdcard_isInitialized()) {
422 state
= MSP_SDCARD_STATE_FS_INIT
;
424 state
= MSP_SDCARD_STATE_CARD_INIT
;
427 case AFATFS_FILESYSTEM_STATE_FATAL
:
428 case AFATFS_FILESYSTEM_STATE_UNKNOWN
:
429 state
= MSP_SDCARD_STATE_FATAL
;
435 serialize8(afatfs_getLastError());
436 // Write free space and total space in kilobytes
437 serialize32(afatfs_getContiguousFreeSpace() / 1024);
438 serialize32(sdcard_getMetadata()->numBlocks
/ 2); // Block size is half a kilobyte
448 static void serializeDataflashSummaryReply(void)
450 headSerialReply(1 + 3 * 4);
452 const flashGeometry_t
*geometry
= flashfsGetGeometry();
453 uint8_t flags
= (flashfsIsReady() ? 1 : 0) | 2 /* FlashFS is supported */;
456 serialize32(geometry
->sectors
);
457 serialize32(geometry
->totalSize
);
458 serialize32(flashfsGetOffset()); // Effectively the current number of bytes stored on the volume
460 serialize8(0); // FlashFS is neither ready nor supported
468 static void serializeDataflashReadReply(uint32_t address
, uint8_t size
)
473 if (size
> sizeof(buffer
)) {
474 size
= sizeof(buffer
);
477 headSerialReply(4 + size
);
479 serialize32(address
);
481 // bytesRead will be lower than that requested if we reach end of volume
482 bytesRead
= flashfsReadAbs(address
, buffer
, size
);
484 for (int i
= 0; i
< bytesRead
; i
++) {
485 serialize8(buffer
[i
]);
490 static void resetMspPort(mspPort_t
*mspPortToReset
, serialPort_t
*serialPort
)
492 memset(mspPortToReset
, 0, sizeof(mspPort_t
));
494 mspPortToReset
->port
= serialPort
;
497 void mspAllocateSerialPorts(serialConfig_t
*serialConfig
)
499 UNUSED(serialConfig
);
501 serialPort_t
*serialPort
;
503 uint8_t portIndex
= 0;
505 serialPortConfig_t
*portConfig
= findSerialPortConfig(FUNCTION_MSP
);
507 while (portConfig
&& portIndex
< MAX_MSP_PORT_COUNT
) {
508 mspPort_t
*mspPort
= &mspPorts
[portIndex
];
514 serialPort
= openSerialPort(portConfig
->identifier
, FUNCTION_MSP
, NULL
, baudRates
[portConfig
->msp_baudrateIndex
], MODE_RXTX
, SERIAL_NOT_INVERTED
);
516 resetMspPort(mspPort
, serialPort
);
520 portConfig
= findNextSerialPortConfig(FUNCTION_MSP
);
524 void mspReleasePortIfAllocated(serialPort_t
*serialPort
)
527 for (portIndex
= 0; portIndex
< MAX_MSP_PORT_COUNT
; portIndex
++) {
528 mspPort_t
*candidateMspPort
= &mspPorts
[portIndex
];
529 if (candidateMspPort
->port
== serialPort
) {
530 closeSerialPort(serialPort
);
531 memset(candidateMspPort
, 0, sizeof(mspPort_t
));
536 void mspInit(serialConfig_t
*serialConfig
)
538 // calculate used boxes based on features and fill availableBoxes[] array
539 memset(activeBoxIds
, 0xFF, sizeof(activeBoxIds
));
541 activeBoxIdCount
= 0;
542 activeBoxIds
[activeBoxIdCount
++] = BOXARM
;
544 if (sensors(SENSOR_ACC
)) {
545 activeBoxIds
[activeBoxIdCount
++] = BOXANGLE
;
546 activeBoxIds
[activeBoxIdCount
++] = BOXHORIZON
;
549 activeBoxIds
[activeBoxIdCount
++] = BOXAIRMODE
;
550 activeBoxIds
[activeBoxIdCount
++] = BOXACROPLUS
;
551 activeBoxIds
[activeBoxIdCount
++] = BOX3DDISABLESWITCH
;
553 if (sensors(SENSOR_BARO
)) {
554 activeBoxIds
[activeBoxIdCount
++] = BOXBARO
;
557 if (sensors(SENSOR_ACC
) || sensors(SENSOR_MAG
)) {
558 activeBoxIds
[activeBoxIdCount
++] = BOXMAG
;
559 activeBoxIds
[activeBoxIdCount
++] = BOXHEADFREE
;
560 activeBoxIds
[activeBoxIdCount
++] = BOXHEADADJ
;
563 if (feature(FEATURE_SERVO_TILT
))
564 activeBoxIds
[activeBoxIdCount
++] = BOXCAMSTAB
;
567 if (feature(FEATURE_GPS
)) {
568 activeBoxIds
[activeBoxIdCount
++] = BOXGPSHOME
;
569 activeBoxIds
[activeBoxIdCount
++] = BOXGPSHOLD
;
573 if (masterConfig
.mixerMode
== MIXER_FLYING_WING
|| masterConfig
.mixerMode
== MIXER_AIRPLANE
)
574 activeBoxIds
[activeBoxIdCount
++] = BOXPASSTHRU
;
576 activeBoxIds
[activeBoxIdCount
++] = BOXBEEPERON
;
579 if (feature(FEATURE_LED_STRIP
)) {
580 activeBoxIds
[activeBoxIdCount
++] = BOXLEDLOW
;
584 if (feature(FEATURE_INFLIGHT_ACC_CAL
))
585 activeBoxIds
[activeBoxIdCount
++] = BOXCALIB
;
587 activeBoxIds
[activeBoxIdCount
++] = BOXOSD
;
589 if (feature(FEATURE_TELEMETRY
) && masterConfig
.telemetryConfig
.telemetry_switch
)
590 activeBoxIds
[activeBoxIdCount
++] = BOXTELEMETRY
;
592 if (feature(FEATURE_SONAR
)){
593 activeBoxIds
[activeBoxIdCount
++] = BOXSONAR
;
597 if (masterConfig
.mixerMode
== MIXER_CUSTOM_AIRPLANE
) {
598 activeBoxIds
[activeBoxIdCount
++] = BOXSERVO1
;
599 activeBoxIds
[activeBoxIdCount
++] = BOXSERVO2
;
600 activeBoxIds
[activeBoxIdCount
++] = BOXSERVO3
;
605 if (feature(FEATURE_BLACKBOX
)){
606 activeBoxIds
[activeBoxIdCount
++] = BOXBLACKBOX
;
610 if (feature(FEATURE_FAILSAFE
)){
611 activeBoxIds
[activeBoxIdCount
++] = BOXFAILSAFE
;
615 activeBoxIds
[activeBoxIdCount
++] = BOXGTUNE
;
618 memset(mspPorts
, 0x00, sizeof(mspPorts
));
619 mspAllocateSerialPorts(serialConfig
);
622 #define IS_ENABLED(mask) (mask == 0 ? 0 : 1)
624 static uint32_t packFlightModeFlags(void)
626 uint32_t i
, junk
, tmp
;
628 // Serialize the flags in the order we delivered them, ignoring BOXNAMES and BOXINDEXES
629 // Requires new Multiwii protocol version to fix
630 // It would be preferable to setting the enabled bits based on BOXINDEX.
632 tmp
= IS_ENABLED(FLIGHT_MODE(ANGLE_MODE
)) << BOXANGLE
|
633 IS_ENABLED(FLIGHT_MODE(HORIZON_MODE
)) << BOXHORIZON
|
634 IS_ENABLED(FLIGHT_MODE(BARO_MODE
)) << BOXBARO
|
635 IS_ENABLED(FLIGHT_MODE(MAG_MODE
)) << BOXMAG
|
636 IS_ENABLED(FLIGHT_MODE(HEADFREE_MODE
)) << BOXHEADFREE
|
637 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXHEADADJ
)) << BOXHEADADJ
|
638 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXCAMSTAB
)) << BOXCAMSTAB
|
639 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXCAMTRIG
)) << BOXCAMTRIG
|
640 IS_ENABLED(FLIGHT_MODE(GPS_HOME_MODE
)) << BOXGPSHOME
|
641 IS_ENABLED(FLIGHT_MODE(GPS_HOLD_MODE
)) << BOXGPSHOLD
|
642 IS_ENABLED(FLIGHT_MODE(PASSTHRU_MODE
)) << BOXPASSTHRU
|
643 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXBEEPERON
)) << BOXBEEPERON
|
644 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXLEDMAX
)) << BOXLEDMAX
|
645 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXLEDLOW
)) << BOXLEDLOW
|
646 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXLLIGHTS
)) << BOXLLIGHTS
|
647 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXCALIB
)) << BOXCALIB
|
648 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXGOV
)) << BOXGOV
|
649 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXOSD
)) << BOXOSD
|
650 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXTELEMETRY
)) << BOXTELEMETRY
|
651 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXGTUNE
)) << BOXGTUNE
|
652 IS_ENABLED(FLIGHT_MODE(SONAR_MODE
)) << BOXSONAR
|
653 IS_ENABLED(ARMING_FLAG(ARMED
)) << BOXARM
|
654 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXBLACKBOX
)) << BOXBLACKBOX
|
655 IS_ENABLED(FLIGHT_MODE(FAILSAFE_MODE
)) << BOXFAILSAFE
|
656 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXAIRMODE
)) << BOXAIRMODE
|
657 IS_ENABLED(IS_RC_MODE_ACTIVE(BOXACROPLUS
)) << BOXACROPLUS
;
659 for (i
= 0; i
< activeBoxIdCount
; i
++) {
660 int flag
= (tmp
& (1 << activeBoxIds
[i
]));
668 static bool processOutCommand(uint8_t cmdMSP
)
674 int32_t lat
= 0, lon
= 0;
678 case MSP_API_VERSION
:
680 1 + // protocol version length
683 serialize8(MSP_PROTOCOL_VERSION
);
685 serialize8(API_VERSION_MAJOR
);
686 serialize8(API_VERSION_MINOR
);
690 headSerialReply(FLIGHT_CONTROLLER_IDENTIFIER_LENGTH
);
692 for (i
= 0; i
< FLIGHT_CONTROLLER_IDENTIFIER_LENGTH
; i
++) {
693 serialize8(flightControllerIdentifier
[i
]);
698 headSerialReply(FLIGHT_CONTROLLER_VERSION_LENGTH
);
700 serialize8(FC_VERSION_MAJOR
);
701 serialize8(FC_VERSION_MINOR
);
702 serialize8(FC_VERSION_PATCH_LEVEL
);
707 BOARD_IDENTIFIER_LENGTH
+
708 BOARD_HARDWARE_REVISION_LENGTH
710 for (i
= 0; i
< BOARD_IDENTIFIER_LENGTH
; i
++) {
711 serialize8(boardIdentifier
[i
]);
713 #ifdef USE_HARDWARE_REVISION_DETECTION
714 serialize16(hardwareRevision
);
716 serialize16(0); // No other build targets currently have hardware revision detection.
724 GIT_SHORT_REVISION_LENGTH
727 for (i
= 0; i
< BUILD_DATE_LENGTH
; i
++) {
728 serialize8(buildDate
[i
]);
730 for (i
= 0; i
< BUILD_TIME_LENGTH
; i
++) {
731 serialize8(buildTime
[i
]);
734 for (i
= 0; i
< GIT_SHORT_REVISION_LENGTH
; i
++) {
735 serialize8(shortGitRevision
[i
]);
739 // DEPRECATED - Use MSP_API_VERSION
742 serialize8(MW_VERSION
);
743 serialize8(masterConfig
.mixerMode
);
744 serialize8(MSP_PROTOCOL_VERSION
);
745 serialize32(CAP_DYNBALANCE
); // "capability"
750 serialize16(cycleTime
);
752 serialize16(i2cGetErrorCounter());
756 serialize16(sensors(SENSOR_ACC
) | sensors(SENSOR_BARO
) << 1 | sensors(SENSOR_MAG
) << 2 | sensors(SENSOR_GPS
) << 3 | sensors(SENSOR_SONAR
) << 4);
757 serialize32(packFlightModeFlags());
758 serialize8(masterConfig
.current_profile_index
);
759 //serialize16(averageSystemLoadPercent);
764 serialize16(cycleTime
);
766 serialize16(i2cGetErrorCounter());
770 serialize16(sensors(SENSOR_ACC
) | sensors(SENSOR_BARO
) << 1 | sensors(SENSOR_MAG
) << 2 | sensors(SENSOR_GPS
) << 3 | sensors(SENSOR_SONAR
) << 4);
771 serialize32(packFlightModeFlags());
772 serialize8(masterConfig
.current_profile_index
);
777 // Hack scale due to choice of units for sensor data in multiwii
778 uint8_t scale
= (acc_1G
> 1024) ? 8 : 1;
780 for (i
= 0; i
< 3; i
++)
781 serialize16(accSmooth
[i
] / scale
);
782 for (i
= 0; i
< 3; i
++)
783 serialize16(gyroADC
[i
]);
784 for (i
= 0; i
< 3; i
++)
785 serialize16(magADC
[i
]);
789 s_struct((uint8_t *)&servo
, MAX_SUPPORTED_SERVOS
* 2);
791 case MSP_SERVO_CONFIGURATIONS
:
792 headSerialReply(MAX_SUPPORTED_SERVOS
* sizeof(servoParam_t
));
793 for (i
= 0; i
< MAX_SUPPORTED_SERVOS
; i
++) {
794 serialize16(masterConfig
.servoConf
[i
].min
);
795 serialize16(masterConfig
.servoConf
[i
].max
);
796 serialize16(masterConfig
.servoConf
[i
].middle
);
797 serialize8(masterConfig
.servoConf
[i
].rate
);
798 serialize8(masterConfig
.servoConf
[i
].angleAtMin
);
799 serialize8(masterConfig
.servoConf
[i
].angleAtMax
);
800 serialize8(masterConfig
.servoConf
[i
].forwardFromChannel
);
801 serialize32(masterConfig
.servoConf
[i
].reversedSources
);
804 case MSP_SERVO_MIX_RULES
:
805 headSerialReply(MAX_SERVO_RULES
* sizeof(servoMixer_t
));
806 for (i
= 0; i
< MAX_SERVO_RULES
; i
++) {
807 serialize8(masterConfig
.customServoMixer
[i
].targetChannel
);
808 serialize8(masterConfig
.customServoMixer
[i
].inputSource
);
809 serialize8(masterConfig
.customServoMixer
[i
].rate
);
810 serialize8(masterConfig
.customServoMixer
[i
].speed
);
811 serialize8(masterConfig
.customServoMixer
[i
].min
);
812 serialize8(masterConfig
.customServoMixer
[i
].max
);
813 serialize8(masterConfig
.customServoMixer
[i
].box
);
818 s_struct((uint8_t *)motor
, 16);
821 headSerialReply(2 * rxRuntimeConfig
.channelCount
);
822 for (i
= 0; i
< rxRuntimeConfig
.channelCount
; i
++)
823 serialize16(rcData
[i
]);
827 serialize16(attitude
.values
.roll
);
828 serialize16(attitude
.values
.pitch
);
829 serialize16(DECIDEGREES_TO_DEGREES(attitude
.values
.yaw
));
833 #if defined(BARO) || defined(SONAR)
834 serialize32(altitudeHoldGetEstimatedAltitude());
840 case MSP_SONAR_ALTITUDE
:
843 serialize32(sonarGetLatestAltitude());
850 serialize8((uint8_t)constrain(vbat
, 0, 255));
851 serialize16((uint16_t)constrain(mAhDrawn
, 0, 0xFFFF)); // milliamp hours drawn from battery
853 if(masterConfig
.batteryConfig
.multiwiiCurrentMeterOutput
) {
854 serialize16((uint16_t)constrain(amperage
* 10, 0, 0xFFFF)); // send amperage in 0.001 A steps. Negative range is truncated to zero
856 serialize16((int16_t)constrain(amperage
, -0x8000, 0x7FFF)); // send amperage in 0.01 A steps, range is -320A to 320A
858 case MSP_ARMING_CONFIG
:
860 serialize8(masterConfig
.auto_disarm_delay
);
861 serialize8(masterConfig
.disarm_kill_switch
);
865 serialize16((uint16_t)targetLooptime
);
869 serialize8(currentControlRateProfile
->rcRate8
);
870 serialize8(currentControlRateProfile
->rcExpo8
);
871 for (i
= 0 ; i
< 3; i
++) {
872 serialize8(currentControlRateProfile
->rates
[i
]); // R,P,Y see flight_dynamics_index_t
874 serialize8(currentControlRateProfile
->dynThrPID
);
875 serialize8(currentControlRateProfile
->thrMid8
);
876 serialize8(currentControlRateProfile
->thrExpo8
);
877 serialize16(currentControlRateProfile
->tpa_breakpoint
);
878 serialize8(currentControlRateProfile
->rcYawExpo8
);
881 headSerialReply(3 * PID_ITEM_COUNT
);
882 for (i
= 0; i
< PID_ITEM_COUNT
; i
++) {
883 serialize8(currentProfile
->pidProfile
.P8
[i
]);
884 serialize8(currentProfile
->pidProfile
.I8
[i
]);
885 serialize8(currentProfile
->pidProfile
.D8
[i
]);
889 headSerialReply(sizeof(pidnames
) - 1);
890 serializeNames(pidnames
);
892 case MSP_PID_CONTROLLER
:
894 serialize8(currentProfile
->pidProfile
.pidController
);
896 case MSP_MODE_RANGES
:
897 headSerialReply(4 * MAX_MODE_ACTIVATION_CONDITION_COUNT
);
898 for (i
= 0; i
< MAX_MODE_ACTIVATION_CONDITION_COUNT
; i
++) {
899 modeActivationCondition_t
*mac
= &masterConfig
.modeActivationConditions
[i
];
900 const box_t
*box
= &boxes
[mac
->modeId
];
901 serialize8(box
->permanentId
);
902 serialize8(mac
->auxChannelIndex
);
903 serialize8(mac
->range
.startStep
);
904 serialize8(mac
->range
.endStep
);
907 case MSP_ADJUSTMENT_RANGES
:
908 headSerialReply(MAX_ADJUSTMENT_RANGE_COUNT
* (
909 1 + // adjustment index/slot
910 1 + // aux channel index
913 1 + // adjustment function
914 1 // aux switch channel index
916 for (i
= 0; i
< MAX_ADJUSTMENT_RANGE_COUNT
; i
++) {
917 adjustmentRange_t
*adjRange
= &masterConfig
.adjustmentRanges
[i
];
918 serialize8(adjRange
->adjustmentIndex
);
919 serialize8(adjRange
->auxChannelIndex
);
920 serialize8(adjRange
->range
.startStep
);
921 serialize8(adjRange
->range
.endStep
);
922 serialize8(adjRange
->adjustmentFunction
);
923 serialize8(adjRange
->auxSwitchChannelIndex
);
927 serializeBoxNamesReply();
930 headSerialReply(activeBoxIdCount
);
931 for (i
= 0; i
< activeBoxIdCount
; i
++) {
932 const box_t
*box
= findBoxByActiveBoxId(activeBoxIds
[i
]);
936 serialize8(box
->permanentId
);
940 headSerialReply(2 * 5 + 3 + 3 + 2 + 4);
941 serialize16(masterConfig
.rxConfig
.midrc
);
943 serialize16(masterConfig
.escAndServoConfig
.minthrottle
);
944 serialize16(masterConfig
.escAndServoConfig
.maxthrottle
);
945 serialize16(masterConfig
.escAndServoConfig
.mincommand
);
947 serialize16(masterConfig
.failsafeConfig
.failsafe_throttle
);
950 serialize8(masterConfig
.gpsConfig
.provider
); // gps_type
951 serialize8(0); // TODO gps_baudrate (an index, cleanflight uses a uint32_t
952 serialize8(masterConfig
.gpsConfig
.sbasMode
); // gps_ubx_sbas
954 serialize8(0); // gps_type
955 serialize8(0); // TODO gps_baudrate (an index, cleanflight uses a uint32_t
956 serialize8(0); // gps_ubx_sbas
958 serialize8(masterConfig
.batteryConfig
.multiwiiCurrentMeterOutput
);
959 serialize8(masterConfig
.rxConfig
.rssi_channel
);
962 serialize16(masterConfig
.mag_declination
/ 10);
964 serialize8(masterConfig
.batteryConfig
.vbatscale
);
965 serialize8(masterConfig
.batteryConfig
.vbatmincellvoltage
);
966 serialize8(masterConfig
.batteryConfig
.vbatmaxcellvoltage
);
967 serialize8(masterConfig
.batteryConfig
.vbatwarningcellvoltage
);
971 // FIXME This is hardcoded and should not be.
973 for (i
= 0; i
< 8; i
++)
979 serialize8(STATE(GPS_FIX
));
980 serialize8(GPS_numSat
);
981 serialize32(GPS_coord
[LAT
]);
982 serialize32(GPS_coord
[LON
]);
983 serialize16(GPS_altitude
);
984 serialize16(GPS_speed
);
985 serialize16(GPS_ground_course
);
989 serialize16(GPS_distanceToHome
);
990 serialize16(GPS_directionToHome
);
991 serialize8(GPS_update
& 1);
994 wp_no
= read8(); // get the wp number
999 } else if (wp_no
== 16) {
1000 lat
= GPS_hold
[LAT
];
1001 lon
= GPS_hold
[LON
];
1006 serialize32(AltHold
); // altitude (cm) will come here -- temporary implementation to test feature with apps
1007 serialize16(0); // heading will come here (deg)
1008 serialize16(0); // time to stay (ms) will come here
1009 serialize8(0); // nav flag will come here
1012 headSerialReply(1 + (GPS_numCh
* 4));
1013 serialize8(GPS_numCh
);
1014 for (i
= 0; i
< GPS_numCh
; i
++){
1015 serialize8(GPS_svinfo_chn
[i
]);
1016 serialize8(GPS_svinfo_svid
[i
]);
1017 serialize8(GPS_svinfo_quality
[i
]);
1018 serialize8(GPS_svinfo_cno
[i
]);
1023 headSerialReply(DEBUG16_VALUE_COUNT
* sizeof(debug
[0]));
1025 // output some useful QA statistics
1026 // debug[x] = ((hse_value / 1000000) * 1000) + (SystemCoreClock / 1000000); // XX0YY [crystal clock : core clock]
1028 for (i
= 0; i
< DEBUG16_VALUE_COUNT
; i
++)
1029 serialize16(debug
[i
]); // 4 variables are here for general monitoring purpose
1032 // Additional commands that are not compatible with MultiWii
1035 serialize16(masterConfig
.accelerometerTrims
.values
.pitch
);
1036 serialize16(masterConfig
.accelerometerTrims
.values
.roll
);
1040 headSerialReply(12);
1041 serialize32(U_ID_0
);
1042 serialize32(U_ID_1
);
1043 serialize32(U_ID_2
);
1048 serialize32(featureMask());
1051 case MSP_BOARD_ALIGNMENT
:
1053 serialize16(masterConfig
.boardAlignment
.rollDegrees
);
1054 serialize16(masterConfig
.boardAlignment
.pitchDegrees
);
1055 serialize16(masterConfig
.boardAlignment
.yawDegrees
);
1058 case MSP_VOLTAGE_METER_CONFIG
:
1060 serialize8(masterConfig
.batteryConfig
.vbatscale
);
1061 serialize8(masterConfig
.batteryConfig
.vbatmincellvoltage
);
1062 serialize8(masterConfig
.batteryConfig
.vbatmaxcellvoltage
);
1063 serialize8(masterConfig
.batteryConfig
.vbatwarningcellvoltage
);
1066 case MSP_CURRENT_METER_CONFIG
:
1068 serialize16(masterConfig
.batteryConfig
.currentMeterScale
);
1069 serialize16(masterConfig
.batteryConfig
.currentMeterOffset
);
1070 serialize8(masterConfig
.batteryConfig
.currentMeterType
);
1071 serialize16(masterConfig
.batteryConfig
.batteryCapacity
);
1076 serialize8(masterConfig
.mixerMode
);
1080 headSerialReply(12);
1081 serialize8(masterConfig
.rxConfig
.serialrx_provider
);
1082 serialize16(masterConfig
.rxConfig
.maxcheck
);
1083 serialize16(masterConfig
.rxConfig
.midrc
);
1084 serialize16(masterConfig
.rxConfig
.mincheck
);
1085 serialize8(masterConfig
.rxConfig
.spektrum_sat_bind
);
1086 serialize16(masterConfig
.rxConfig
.rx_min_usec
);
1087 serialize16(masterConfig
.rxConfig
.rx_max_usec
);
1090 case MSP_FAILSAFE_CONFIG
:
1092 serialize8(masterConfig
.failsafeConfig
.failsafe_delay
);
1093 serialize8(masterConfig
.failsafeConfig
.failsafe_off_delay
);
1094 serialize16(masterConfig
.failsafeConfig
.failsafe_throttle
);
1095 serialize8(masterConfig
.failsafeConfig
.failsafe_kill_switch
);
1096 serialize16(masterConfig
.failsafeConfig
.failsafe_throttle_low_delay
);
1097 serialize8(masterConfig
.failsafeConfig
.failsafe_procedure
);
1100 case MSP_RXFAIL_CONFIG
:
1101 headSerialReply(3 * (rxRuntimeConfig
.channelCount
));
1102 for (i
= 0; i
< rxRuntimeConfig
.channelCount
; i
++) {
1103 serialize8(masterConfig
.rxConfig
.failsafe_channel_configurations
[i
].mode
);
1104 serialize16(RXFAIL_STEP_TO_CHANNEL_VALUE(masterConfig
.rxConfig
.failsafe_channel_configurations
[i
].step
));
1108 case MSP_RSSI_CONFIG
:
1110 serialize8(masterConfig
.rxConfig
.rssi_channel
);
1114 headSerialReply(MAX_MAPPABLE_RX_INPUTS
);
1115 for (i
= 0; i
< MAX_MAPPABLE_RX_INPUTS
; i
++)
1116 serialize8(masterConfig
.rxConfig
.rcmap
[i
]);
1120 headSerialReply(1 + 4 + 1 + 2 + 2 + 2 + 2 + 2);
1121 serialize8(masterConfig
.mixerMode
);
1123 serialize32(featureMask());
1125 serialize8(masterConfig
.rxConfig
.serialrx_provider
);
1127 serialize16(masterConfig
.boardAlignment
.rollDegrees
);
1128 serialize16(masterConfig
.boardAlignment
.pitchDegrees
);
1129 serialize16(masterConfig
.boardAlignment
.yawDegrees
);
1131 serialize16(masterConfig
.batteryConfig
.currentMeterScale
);
1132 serialize16(masterConfig
.batteryConfig
.currentMeterOffset
);
1135 case MSP_CF_SERIAL_CONFIG
:
1137 ((sizeof(uint8_t) + sizeof(uint16_t) + (sizeof(uint8_t) * 4)) * serialGetAvailablePortCount())
1139 for (i
= 0; i
< SERIAL_PORT_COUNT
; i
++) {
1140 if (!serialIsPortAvailable(masterConfig
.serialConfig
.portConfigs
[i
].identifier
)) {
1143 serialize8(masterConfig
.serialConfig
.portConfigs
[i
].identifier
);
1144 serialize16(masterConfig
.serialConfig
.portConfigs
[i
].functionMask
);
1145 serialize8(masterConfig
.serialConfig
.portConfigs
[i
].msp_baudrateIndex
);
1146 serialize8(masterConfig
.serialConfig
.portConfigs
[i
].gps_baudrateIndex
);
1147 serialize8(masterConfig
.serialConfig
.portConfigs
[i
].telemetry_baudrateIndex
);
1148 serialize8(masterConfig
.serialConfig
.portConfigs
[i
].blackbox_baudrateIndex
);
1153 case MSP_LED_COLORS
:
1154 headSerialReply(CONFIGURABLE_COLOR_COUNT
* 4);
1155 for (i
= 0; i
< CONFIGURABLE_COLOR_COUNT
; i
++) {
1156 hsvColor_t
*color
= &masterConfig
.colors
[i
];
1157 serialize16(color
->h
);
1158 serialize8(color
->s
);
1159 serialize8(color
->v
);
1163 case MSP_LED_STRIP_CONFIG
:
1164 headSerialReply(MAX_LED_STRIP_LENGTH
* 7);
1165 for (i
= 0; i
< MAX_LED_STRIP_LENGTH
; i
++) {
1166 ledConfig_t
*ledConfig
= &masterConfig
.ledConfigs
[i
];
1167 serialize16((ledConfig
->flags
& LED_DIRECTION_MASK
) >> LED_DIRECTION_BIT_OFFSET
);
1168 serialize16((ledConfig
->flags
& LED_FUNCTION_MASK
) >> LED_FUNCTION_BIT_OFFSET
);
1169 serialize8(GET_LED_X(ledConfig
));
1170 serialize8(GET_LED_Y(ledConfig
));
1171 serialize8(ledConfig
->color
);
1176 case MSP_DATAFLASH_SUMMARY
:
1177 serializeDataflashSummaryReply();
1181 case MSP_DATAFLASH_READ
:
1183 uint32_t readAddress
= read32();
1185 serializeDataflashReadReply(readAddress
, 128);
1190 case MSP_BLACKBOX_CONFIG
:
1194 serialize8(1); //Blackbox supported
1195 serialize8(masterConfig
.blackbox_device
);
1196 serialize8(masterConfig
.blackbox_rate_num
);
1197 serialize8(masterConfig
.blackbox_rate_denom
);
1199 serialize8(0); // Blackbox not supported
1206 case MSP_SDCARD_SUMMARY
:
1207 serializeSDCardSummaryReply();
1210 case MSP_TRANSPONDER_CONFIG
:
1212 headSerialReply(1 + sizeof(masterConfig
.transponderData
));
1214 serialize8(1); //Transponder supported
1216 for (i
= 0; i
< sizeof(masterConfig
.transponderData
); i
++) {
1217 serialize8(masterConfig
.transponderData
[i
]);
1221 serialize8(0); // Transponder not supported
1225 case MSP_BF_BUILD_INFO
:
1226 headSerialReply(11 + 4 + 4);
1227 for (i
= 0; i
< 11; i
++)
1228 serialize8(buildDate
[i
]); // MMM DD YYYY as ascii, MMM = Jan/Feb... etc
1229 serialize32(0); // future exp
1230 serialize32(0); // future exp
1234 headSerialReply(2 * 4);
1235 serialize16(masterConfig
.flight3DConfig
.deadband3d_low
);
1236 serialize16(masterConfig
.flight3DConfig
.deadband3d_high
);
1237 serialize16(masterConfig
.flight3DConfig
.neutral3d
);
1238 serialize16(masterConfig
.flight3DConfig
.deadband3d_throttle
);
1241 case MSP_RC_DEADBAND
:
1243 serialize8(masterConfig
.rcControlsConfig
.deadband
);
1244 serialize8(masterConfig
.rcControlsConfig
.yaw_deadband
);
1245 serialize8(masterConfig
.rcControlsConfig
.alt_hold_deadband
);
1247 case MSP_SENSOR_ALIGNMENT
:
1249 serialize8(masterConfig
.sensorAlignmentConfig
.gyro_align
);
1250 serialize8(masterConfig
.sensorAlignmentConfig
.acc_align
);
1251 serialize8(masterConfig
.sensorAlignmentConfig
.mag_align
);
1260 static bool processInCommand(void)
1268 int32_t lat
= 0, lon
= 0, alt
= 0;
1271 switch (currentPort
->cmdMSP
) {
1272 case MSP_SELECT_SETTING
:
1273 if (!ARMING_FLAG(ARMED
)) {
1274 masterConfig
.current_profile_index
= read8();
1275 if (masterConfig
.current_profile_index
> 1) {
1276 masterConfig
.current_profile_index
= 0;
1285 case MSP_SET_RAW_RC
:
1287 uint8_t channelCount
= currentPort
->dataSize
/ sizeof(uint16_t);
1288 if (channelCount
> MAX_SUPPORTED_RC_CHANNEL_COUNT
) {
1291 uint16_t frame
[MAX_SUPPORTED_RC_CHANNEL_COUNT
];
1293 for (i
= 0; i
< channelCount
; i
++) {
1294 frame
[i
] = read16();
1297 rxMspFrameReceive(frame
, channelCount
);
1301 case MSP_SET_ACC_TRIM
:
1302 masterConfig
.accelerometerTrims
.values
.pitch
= read16();
1303 masterConfig
.accelerometerTrims
.values
.roll
= read16();
1305 case MSP_SET_ARMING_CONFIG
:
1306 masterConfig
.auto_disarm_delay
= read8();
1307 masterConfig
.disarm_kill_switch
= read8();
1309 case MSP_SET_LOOP_TIME
:
1310 setGyroSamplingSpeed(read16());
1312 case MSP_SET_PID_CONTROLLER
:
1313 oldPid
= currentProfile
->pidProfile
.pidController
;
1314 currentProfile
->pidProfile
.pidController
= read8();
1315 pidSetController(currentProfile
->pidProfile
.pidController
);
1316 if (oldPid
!= currentProfile
->pidProfile
.pidController
) setGyroSamplingSpeed(0); // recalculate looptimes for new PID
1319 for (i
= 0; i
< PID_ITEM_COUNT
; i
++) {
1320 currentProfile
->pidProfile
.P8
[i
] = read8();
1321 currentProfile
->pidProfile
.I8
[i
] = read8();
1322 currentProfile
->pidProfile
.D8
[i
] = read8();
1325 case MSP_SET_MODE_RANGE
:
1327 if (i
< MAX_MODE_ACTIVATION_CONDITION_COUNT
) {
1328 modeActivationCondition_t
*mac
= &masterConfig
.modeActivationConditions
[i
];
1330 const box_t
*box
= findBoxByPermenantId(i
);
1332 mac
->modeId
= box
->boxId
;
1333 mac
->auxChannelIndex
= read8();
1334 mac
->range
.startStep
= read8();
1335 mac
->range
.endStep
= read8();
1337 useRcControlsConfig(masterConfig
.modeActivationConditions
, &masterConfig
.escAndServoConfig
, ¤tProfile
->pidProfile
);
1345 case MSP_SET_ADJUSTMENT_RANGE
:
1347 if (i
< MAX_ADJUSTMENT_RANGE_COUNT
) {
1348 adjustmentRange_t
*adjRange
= &masterConfig
.adjustmentRanges
[i
];
1350 if (i
< MAX_SIMULTANEOUS_ADJUSTMENT_COUNT
) {
1351 adjRange
->adjustmentIndex
= i
;
1352 adjRange
->auxChannelIndex
= read8();
1353 adjRange
->range
.startStep
= read8();
1354 adjRange
->range
.endStep
= read8();
1355 adjRange
->adjustmentFunction
= read8();
1356 adjRange
->auxSwitchChannelIndex
= read8();
1365 case MSP_SET_RC_TUNING
:
1366 if (currentPort
->dataSize
>= 10) {
1367 currentControlRateProfile
->rcRate8
= read8();
1368 currentControlRateProfile
->rcExpo8
= read8();
1369 for (i
= 0; i
< 3; i
++) {
1371 currentControlRateProfile
->rates
[i
] = MIN(rate
, i
== FD_YAW
? CONTROL_RATE_CONFIG_YAW_RATE_MAX
: CONTROL_RATE_CONFIG_ROLL_PITCH_RATE_MAX
);
1374 currentControlRateProfile
->dynThrPID
= MIN(rate
, CONTROL_RATE_CONFIG_TPA_MAX
);
1375 currentControlRateProfile
->thrMid8
= read8();
1376 currentControlRateProfile
->thrExpo8
= read8();
1377 currentControlRateProfile
->tpa_breakpoint
= read16();
1378 if (currentPort
->dataSize
>= 11) {
1379 currentControlRateProfile
->rcYawExpo8
= read8();
1387 if (tmp
< 1600 && tmp
> 1400)
1388 masterConfig
.rxConfig
.midrc
= tmp
;
1390 masterConfig
.escAndServoConfig
.minthrottle
= read16();
1391 masterConfig
.escAndServoConfig
.maxthrottle
= read16();
1392 masterConfig
.escAndServoConfig
.mincommand
= read16();
1394 masterConfig
.failsafeConfig
.failsafe_throttle
= read16();
1397 masterConfig
.gpsConfig
.provider
= read8(); // gps_type
1398 read8(); // gps_baudrate
1399 masterConfig
.gpsConfig
.sbasMode
= read8(); // gps_ubx_sbas
1401 read8(); // gps_type
1402 read8(); // gps_baudrate
1403 read8(); // gps_ubx_sbas
1405 masterConfig
.batteryConfig
.multiwiiCurrentMeterOutput
= read8();
1406 masterConfig
.rxConfig
.rssi_channel
= read8();
1409 masterConfig
.mag_declination
= read16() * 10;
1411 masterConfig
.batteryConfig
.vbatscale
= read8(); // actual vbatscale as intended
1412 masterConfig
.batteryConfig
.vbatmincellvoltage
= read8(); // vbatlevel_warn1 in MWC2.3 GUI
1413 masterConfig
.batteryConfig
.vbatmaxcellvoltage
= read8(); // vbatlevel_warn2 in MWC2.3 GUI
1414 masterConfig
.batteryConfig
.vbatwarningcellvoltage
= read8(); // vbatlevel when buzzer starts to alert
1417 for (i
= 0; i
< 8; i
++) // FIXME should this use MAX_MOTORS or MAX_SUPPORTED_MOTORS instead of 8
1418 motor_disarmed
[i
] = read16();
1420 case MSP_SET_SERVO_CONFIGURATION
:
1422 if (currentPort
->dataSize
!= 1 + sizeof(servoParam_t
)) {
1427 if (i
>= MAX_SUPPORTED_SERVOS
) {
1430 masterConfig
.servoConf
[i
].min
= read16();
1431 masterConfig
.servoConf
[i
].max
= read16();
1432 masterConfig
.servoConf
[i
].middle
= read16();
1433 masterConfig
.servoConf
[i
].rate
= read8();
1434 masterConfig
.servoConf
[i
].angleAtMin
= read8();
1435 masterConfig
.servoConf
[i
].angleAtMax
= read8();
1436 masterConfig
.servoConf
[i
].forwardFromChannel
= read8();
1437 masterConfig
.servoConf
[i
].reversedSources
= read32();
1442 case MSP_SET_SERVO_MIX_RULE
:
1445 if (i
>= MAX_SERVO_RULES
) {
1448 masterConfig
.customServoMixer
[i
].targetChannel
= read8();
1449 masterConfig
.customServoMixer
[i
].inputSource
= read8();
1450 masterConfig
.customServoMixer
[i
].rate
= read8();
1451 masterConfig
.customServoMixer
[i
].speed
= read8();
1452 masterConfig
.customServoMixer
[i
].min
= read8();
1453 masterConfig
.customServoMixer
[i
].max
= read8();
1454 masterConfig
.customServoMixer
[i
].box
= read8();
1455 loadCustomServoMixer();
1461 masterConfig
.flight3DConfig
.deadband3d_low
= read16();
1462 masterConfig
.flight3DConfig
.deadband3d_high
= read16();
1463 masterConfig
.flight3DConfig
.neutral3d
= read16();
1464 masterConfig
.flight3DConfig
.deadband3d_throttle
= read16();
1467 case MSP_SET_RC_DEADBAND
:
1468 masterConfig
.rcControlsConfig
.deadband
= read8();
1469 masterConfig
.rcControlsConfig
.yaw_deadband
= read8();
1470 masterConfig
.rcControlsConfig
.alt_hold_deadband
= read8();
1473 case MSP_SET_RESET_CURR_PID
:
1474 //resetPidProfile(¤tProfile->pidProfile);
1477 case MSP_SET_SENSOR_ALIGNMENT
:
1478 masterConfig
.sensorAlignmentConfig
.gyro_align
= read8();
1479 masterConfig
.sensorAlignmentConfig
.acc_align
= read8();
1480 masterConfig
.sensorAlignmentConfig
.mag_align
= read8();
1483 case MSP_RESET_CONF
:
1484 if (!ARMING_FLAG(ARMED
)) {
1489 case MSP_ACC_CALIBRATION
:
1490 if (!ARMING_FLAG(ARMED
))
1491 accSetCalibrationCycles(CALIBRATING_ACC_CYCLES
);
1493 case MSP_MAG_CALIBRATION
:
1494 if (!ARMING_FLAG(ARMED
))
1495 ENABLE_STATE(CALIBRATE_MAG
);
1497 case MSP_EEPROM_WRITE
:
1498 if (ARMING_FLAG(ARMED
)) {
1507 case MSP_SET_BLACKBOX_CONFIG
:
1508 // Don't allow config to be updated while Blackbox is logging
1509 if (blackboxMayEditConfig()) {
1510 masterConfig
.blackbox_device
= read8();
1511 masterConfig
.blackbox_rate_num
= read8();
1512 masterConfig
.blackbox_rate_denom
= read8();
1518 case MSP_SET_TRANSPONDER_CONFIG
:
1519 if (currentPort
->dataSize
!= sizeof(masterConfig
.transponderData
)) {
1524 for (i
= 0; i
< sizeof(masterConfig
.transponderData
); i
++) {
1525 masterConfig
.transponderData
[i
] = read8();
1528 transponderUpdateData(masterConfig
.transponderData
);
1533 case MSP_DATAFLASH_ERASE
:
1534 flashfsEraseCompletely();
1539 case MSP_SET_RAW_GPS
:
1541 ENABLE_STATE(GPS_FIX
);
1543 DISABLE_STATE(GPS_FIX
);
1545 GPS_numSat
= read8();
1546 GPS_coord
[LAT
] = read32();
1547 GPS_coord
[LON
] = read32();
1548 GPS_altitude
= read16();
1549 GPS_speed
= read16();
1550 GPS_update
|= 2; // New data signalisation to GPS functions // FIXME Magic Numbers
1553 wp_no
= read8(); //get the wp number
1556 alt
= read32(); // to set altitude (cm)
1557 read16(); // future: to set heading (deg)
1558 read16(); // future: to set time to stay (ms)
1559 read8(); // future: to set nav flag
1561 GPS_home
[LAT
] = lat
;
1562 GPS_home
[LON
] = lon
;
1563 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
1564 ENABLE_STATE(GPS_FIX_HOME
);
1566 AltHold
= alt
; // temporary implementation to test feature with apps
1567 } 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
1568 GPS_hold
[LAT
] = lat
;
1569 GPS_hold
[LON
] = lon
;
1571 AltHold
= alt
; // temporary implementation to test feature with apps
1572 nav_mode
= NAV_MODE_WP
;
1573 GPS_set_next_wp(&GPS_hold
[LAT
], &GPS_hold
[LON
]);
1577 case MSP_SET_FEATURE
:
1579 featureSet(read32()); // features bitmap
1582 case MSP_SET_BOARD_ALIGNMENT
:
1583 masterConfig
.boardAlignment
.rollDegrees
= read16();
1584 masterConfig
.boardAlignment
.pitchDegrees
= read16();
1585 masterConfig
.boardAlignment
.yawDegrees
= read16();
1588 case MSP_SET_VOLTAGE_METER_CONFIG
:
1589 masterConfig
.batteryConfig
.vbatscale
= read8(); // actual vbatscale as intended
1590 masterConfig
.batteryConfig
.vbatmincellvoltage
= read8(); // vbatlevel_warn1 in MWC2.3 GUI
1591 masterConfig
.batteryConfig
.vbatmaxcellvoltage
= read8(); // vbatlevel_warn2 in MWC2.3 GUI
1592 masterConfig
.batteryConfig
.vbatwarningcellvoltage
= read8(); // vbatlevel when buzzer starts to alert
1595 case MSP_SET_CURRENT_METER_CONFIG
:
1596 masterConfig
.batteryConfig
.currentMeterScale
= read16();
1597 masterConfig
.batteryConfig
.currentMeterOffset
= read16();
1598 masterConfig
.batteryConfig
.currentMeterType
= read8();
1599 masterConfig
.batteryConfig
.batteryCapacity
= read16();
1602 #ifndef USE_QUAD_MIXER_ONLY
1604 masterConfig
.mixerMode
= read8();
1608 case MSP_SET_RX_CONFIG
:
1609 masterConfig
.rxConfig
.serialrx_provider
= read8();
1610 masterConfig
.rxConfig
.maxcheck
= read16();
1611 masterConfig
.rxConfig
.midrc
= read16();
1612 masterConfig
.rxConfig
.mincheck
= read16();
1613 masterConfig
.rxConfig
.spektrum_sat_bind
= read8();
1614 if (currentPort
->dataSize
> 8) {
1615 masterConfig
.rxConfig
.rx_min_usec
= read16();
1616 masterConfig
.rxConfig
.rx_max_usec
= read16();
1620 case MSP_SET_FAILSAFE_CONFIG
:
1621 masterConfig
.failsafeConfig
.failsafe_delay
= read8();
1622 masterConfig
.failsafeConfig
.failsafe_off_delay
= read8();
1623 masterConfig
.failsafeConfig
.failsafe_throttle
= read16();
1624 masterConfig
.failsafeConfig
.failsafe_kill_switch
= read8();
1625 masterConfig
.failsafeConfig
.failsafe_throttle_low_delay
= read16();
1626 masterConfig
.failsafeConfig
.failsafe_procedure
= read8();
1629 case MSP_SET_RXFAIL_CONFIG
:
1631 if (i
< MAX_SUPPORTED_RC_CHANNEL_COUNT
) {
1632 masterConfig
.rxConfig
.failsafe_channel_configurations
[i
].mode
= read8();
1633 masterConfig
.rxConfig
.failsafe_channel_configurations
[i
].step
= CHANNEL_VALUE_TO_RXFAIL_STEP(read16());
1639 case MSP_SET_RSSI_CONFIG
:
1640 masterConfig
.rxConfig
.rssi_channel
= read8();
1643 case MSP_SET_RX_MAP
:
1644 for (i
= 0; i
< MAX_MAPPABLE_RX_INPUTS
; i
++) {
1645 masterConfig
.rxConfig
.rcmap
[i
] = read8();
1649 case MSP_SET_BF_CONFIG
:
1651 #ifdef USE_QUAD_MIXER_ONLY
1652 read8(); // mixerMode ignored
1654 masterConfig
.mixerMode
= read8(); // mixerMode
1658 featureSet(read32()); // features bitmap
1660 masterConfig
.rxConfig
.serialrx_provider
= read8(); // serialrx_type
1662 masterConfig
.boardAlignment
.rollDegrees
= read16(); // board_align_roll
1663 masterConfig
.boardAlignment
.pitchDegrees
= read16(); // board_align_pitch
1664 masterConfig
.boardAlignment
.yawDegrees
= read16(); // board_align_yaw
1666 masterConfig
.batteryConfig
.currentMeterScale
= read16();
1667 masterConfig
.batteryConfig
.currentMeterOffset
= read16();
1670 case MSP_SET_CF_SERIAL_CONFIG
:
1672 uint8_t portConfigSize
= sizeof(uint8_t) + sizeof(uint16_t) + (sizeof(uint8_t) * 4);
1674 if (currentPort
->dataSize
% portConfigSize
!= 0) {
1679 uint8_t remainingPortsInPacket
= currentPort
->dataSize
/ portConfigSize
;
1681 while (remainingPortsInPacket
--) {
1682 uint8_t identifier
= read8();
1684 serialPortConfig_t
*portConfig
= serialFindPortConfiguration(identifier
);
1690 portConfig
->identifier
= identifier
;
1691 portConfig
->functionMask
= read16();
1692 portConfig
->msp_baudrateIndex
= read8();
1693 portConfig
->gps_baudrateIndex
= read8();
1694 portConfig
->telemetry_baudrateIndex
= read8();
1695 portConfig
->blackbox_baudrateIndex
= read8();
1701 case MSP_SET_LED_COLORS
:
1702 for (i
= 0; i
< CONFIGURABLE_COLOR_COUNT
; i
++) {
1703 hsvColor_t
*color
= &masterConfig
.colors
[i
];
1704 color
->h
= read16();
1710 case MSP_SET_LED_STRIP_CONFIG
:
1713 if (i
>= MAX_LED_STRIP_LENGTH
|| currentPort
->dataSize
!= (1 + 7)) {
1717 ledConfig_t
*ledConfig
= &masterConfig
.ledConfigs
[i
];
1719 // currently we're storing directions and functions in a uint16 (flags)
1720 // the msp uses 2 x uint16_t to cater for future expansion
1722 ledConfig
->flags
= (mask
<< LED_DIRECTION_BIT_OFFSET
) & LED_DIRECTION_MASK
;
1725 ledConfig
->flags
|= (mask
<< LED_FUNCTION_BIT_OFFSET
) & LED_FUNCTION_MASK
;
1728 ledConfig
->xy
= CALCULATE_LED_X(mask
);
1731 ledConfig
->xy
|= CALCULATE_LED_Y(mask
);
1733 ledConfig
->color
= read8();
1735 reevalulateLedConfig();
1740 isRebootScheduled
= true;
1743 #ifdef USE_SERIAL_1WIRE
1745 // get channel number
1747 // we do not give any data back, assume channel number is transmitted OK
1749 // 0xFF -> preinitialize the Passthrough
1750 // switch all motor lines HI
1751 usb1WireInitialize();
1752 // reply the count of ESC found
1754 serialize8(escCount
);
1756 // and come back right afterwards
1757 // rem: App: Wait at least appx. 500 ms for BLHeli to jump into
1758 // bootloader mode before try to connect any ESC
1763 // Check for channel number 0..ESC_COUNT-1
1765 // because we do not come back after calling usb1WirePassthrough
1766 // proceed with a success reply first
1769 // flush the transmit buffer
1770 bufWriterFlush(writer
);
1771 // wait for all data to send
1772 waitForSerialPortToFinishTransmitting(currentPort
->port
);
1773 // Start to activate here
1774 // motor 1 => index 0
1776 // search currentPort portIndex
1777 /* next lines seems to be unnecessary, because the currentPort always point to the same mspPorts[portIndex]
1779 for (portIndex = 0; portIndex < MAX_MSP_PORT_COUNT; portIndex++) {
1780 if (currentPort == &mspPorts[portIndex]) {
1785 mspReleasePortIfAllocated(mspSerialPort
); // CloseSerialPort also marks currentPort as UNUSED_PORT
1786 usb1WirePassthrough(i
);
1787 // Wait a bit more to let App read the 0 byte and switch baudrate
1788 // 2ms will most likely do the job, but give some grace time
1790 // rebuild/refill currentPort structure, does openSerialPort if marked UNUSED_PORT - used ports are skiped
1791 mspAllocateSerialPorts(&masterConfig
.serialConfig
);
1792 /* restore currentPort and mspSerialPort
1793 setCurrentPort(&mspPorts[portIndex]); // not needed same index will be restored
1795 // former used MSP uart is active again
1796 // restore MSP_SET_1WIRE as current command for correct headSerialReply(0)
1797 currentPort
->cmdMSP
= MSP_SET_1WIRE
;
1799 // ESC channel higher than max. allowed
1800 // rem: BLHeliSuite will not support more than 8
1803 // proceed as usual with MSP commands
1804 // and wait to switch to next channel
1805 // rem: App needs to call MSP_BOOT to deinitialize Passthrough
1810 #ifdef USE_ESCSERIAL
1811 case MSP_SET_ESCSERIAL
:
1812 // get channel number
1814 // we do not give any data back, assume channel number is transmitted OK
1816 // 0xFF -> preinitialize the Passthrough
1817 // switch all motor lines HI
1818 escSerialInitialize();
1820 // and come back right afterwards
1821 // rem: App: Wait at least appx. 500 ms for BLHeli to jump into
1822 // bootloader mode before try to connect any ESC
1825 // Check for channel number 1..USABLE_TIMER_CHANNEL_COUNT-1
1826 if ((i
> 0) && (i
< USABLE_TIMER_CHANNEL_COUNT
)) {
1827 // because we do not come back after calling escEnablePassthrough
1828 // proceed with a success reply first
1831 // flush the transmit buffer
1832 bufWriterFlush(writer
);
1833 // wait for all data to send
1834 while (!isSerialTransmitBufferEmpty(mspSerialPort
)) {
1837 // Start to activate here
1838 // motor 1 => index 0
1839 escEnablePassthrough(mspSerialPort
,i
,0); //sk blmode
1840 // MPS uart is active again
1842 // ESC channel higher than max. allowed
1843 // rem: BLHeliSuite will not support more than 8
1846 // proceed as usual with MSP commands
1847 // and wait to switch to next channel
1848 // rem: App needs to call MSP_BOOT to deinitialize Passthrough
1854 // we do not know how to handle the (valid) message, indicate error MSP $M!
1861 STATIC_UNIT_TESTED
void mspProcessReceivedCommand() {
1862 if (!(processOutCommand(currentPort
->cmdMSP
) || processInCommand())) {
1866 currentPort
->c_state
= IDLE
;
1869 static bool mspProcessReceivedData(uint8_t c
)
1871 if (currentPort
->c_state
== IDLE
) {
1873 currentPort
->c_state
= HEADER_START
;
1877 } else if (currentPort
->c_state
== HEADER_START
) {
1878 currentPort
->c_state
= (c
== 'M') ? HEADER_M
: IDLE
;
1879 } else if (currentPort
->c_state
== HEADER_M
) {
1880 currentPort
->c_state
= (c
== '<') ? HEADER_ARROW
: IDLE
;
1881 } else if (currentPort
->c_state
== HEADER_ARROW
) {
1882 if (c
> MSP_PORT_INBUF_SIZE
) {
1883 currentPort
->c_state
= IDLE
;
1886 currentPort
->dataSize
= c
;
1887 currentPort
->offset
= 0;
1888 currentPort
->checksum
= 0;
1889 currentPort
->indRX
= 0;
1890 currentPort
->checksum
^= c
;
1891 currentPort
->c_state
= HEADER_SIZE
;
1893 } else if (currentPort
->c_state
== HEADER_SIZE
) {
1894 currentPort
->cmdMSP
= c
;
1895 currentPort
->checksum
^= c
;
1896 currentPort
->c_state
= HEADER_CMD
;
1897 } else if (currentPort
->c_state
== HEADER_CMD
&& currentPort
->offset
< currentPort
->dataSize
) {
1898 currentPort
->checksum
^= c
;
1899 currentPort
->inBuf
[currentPort
->offset
++] = c
;
1900 } else if (currentPort
->c_state
== HEADER_CMD
&& currentPort
->offset
>= currentPort
->dataSize
) {
1901 if (currentPort
->checksum
== c
) {
1902 currentPort
->c_state
= COMMAND_RECEIVED
;
1904 currentPort
->c_state
= IDLE
;
1910 STATIC_UNIT_TESTED
void setCurrentPort(mspPort_t
*port
)
1913 mspSerialPort
= currentPort
->port
;
1916 void mspProcess(void)
1919 mspPort_t
*candidatePort
;
1921 for (portIndex
= 0; portIndex
< MAX_MSP_PORT_COUNT
; portIndex
++) {
1922 candidatePort
= &mspPorts
[portIndex
];
1923 if (!candidatePort
->port
) {
1927 setCurrentPort(candidatePort
);
1928 // Big enough to fit a MSP_STATUS in one write.
1929 uint8_t buf
[sizeof(bufWriter_t
) + 20];
1930 writer
= bufWriterInit(buf
, sizeof(buf
),
1931 (bufWrite_t
)serialWriteBufShim
, currentPort
->port
);
1933 while (serialRxBytesWaiting(mspSerialPort
)) {
1935 uint8_t c
= serialRead(mspSerialPort
);
1936 bool consumed
= mspProcessReceivedData(c
);
1938 if (!consumed
&& !ARMING_FLAG(ARMED
)) {
1939 evaluateOtherData(mspSerialPort
, c
);
1942 if (currentPort
->c_state
== COMMAND_RECEIVED
) {
1943 mspProcessReceivedCommand();
1944 break; // process one command at a time so as not to block.
1948 bufWriterFlush(writer
);
1950 if (isRebootScheduled
) {
1951 waitForSerialPortToFinishTransmitting(candidatePort
->port
);
1953 handleOneshotFeatureChangeOnRestart();