Skip to main content

Protocol Overview

The MSP protocol supports multiple versions designed for different use cases and hardware capabilities. This page covers the fundamentals of MSP communication.

Protocol Versions Comparison​

FeatureMSPv1MSPv1 JUMBOMSPv2 NativeMSPv2 over V1
Header$M$M$X$M
Command ID Size8-bit8-bit16-bit16-bit
Max Payload255 bytes65535 bytes65535 bytes65535 bytes
ChecksumXORXORCRC8-DVB-S2Dual (CRC8 + XOR)
Backward CompatibleN/AYesNoYes

Direction Indicators​

MSP uses direction bytes to distinguish between requests and responses:

DirectionCharacterHex ValueDescription
Request<0x3CMessage FROM host TO flight controller
Response>0x3EMessage FROM flight controller TO host
Error!0x21Error response (command failed or unknown)
/// MSP direction indicators
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MspDirection {
Request = b'<', // 0x3C - Host to FC
Response = b'>', // 0x3E - FC to Host
Error = b'!', // 0x21 - Error response
}

impl MspDirection {
pub fn from_byte(b: u8) -> Option<Self> {
match b {
b'<' => Some(MspDirection::Request),
b'>' => Some(MspDirection::Response),
b'!' => Some(MspDirection::Error),
_ => None,
}
}
}

Magic Bytes​

The protocol version is identified by the first two bytes (magic header):

VersionByte 0Byte 1Pattern
MSPv1$ (0x24)M (0x4D)$M
MSPv2$ (0x24)X (0x58)$X
/// MSP protocol version
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MspVersion {
V1,
V2,
}

impl MspVersion {
pub fn from_header(header: &[u8; 2]) -> Option<Self> {
match header {
[b'$', b'M'] => Some(MspVersion::V1),
[b'$', b'X'] => Some(MspVersion::V2),
_ => None,
}
}

pub fn header_bytes(&self) -> [u8; 2] {
match self {
MspVersion::V1 => [b'$', b'M'],
MspVersion::V2 => [b'$', b'X'],
}
}
}

API Version​

The current Betaflight API version is 1.48. The API version can be queried using MSP_API_VERSION (command 1).

/// API version information
#[derive(Debug, Clone, Copy)]
pub struct ApiVersion {
pub protocol_version: u8, // MSP protocol version (0 = v1, 2 = v2)
pub api_major: u8, // API major version
pub api_minor: u8, // API minor version
}

impl ApiVersion {
pub fn from_payload(data: &[u8]) -> Option<Self> {
if data.len() < 3 {
return None;
}
Some(ApiVersion {
protocol_version: data[0],
api_major: data[1],
api_minor: data[2],
})
}
}

Message Flow​

Request-Response Pattern​

MSP follows a simple request-response pattern:

Host                          Flight Controller
| |
| ---- MSP Request ($M<) ----> |
| |
| <--- MSP Response ($M>) ---- |
| |

Unsolicited Messages​

Some MSP implementations support push-based telemetry, but the standard pattern is poll-based (host initiates all communication).

Command Categories​

Commands are organized into functional groups:

RangeCategoryDescription
0-10System InfoProtocol/API version, board info
32-62ConfigurationSettings (battery, modes, features)
64-99Data & StorageEEPROM, dataflash, blackbox
101-150TelemetryStatus, sensors, RC inputs
150-199Extended StatusAdditional status and OSD
200-229Control/WriteSET commands for configuration
230-255UtilityDebug, EEPROM write, reboot

GET vs SET Commands​

Most configuration items have paired commands:

  • GET (read): Query current value
  • SET (write): Modify value

By convention:

  • SET commands are typically GET command + 1
  • GET commands have empty request payloads
  • SET commands include the new values in the request payload
// Example: PID commands
const MSP_PID: u8 = 112; // GET - read PID values
const MSP_SET_PID: u8 = 202; // SET - write PID values

Error Handling​

When a command fails or is unknown, the flight controller responds with:

  • Direction byte: ! (0x21) instead of >
  • Empty payload or error code
/// Check if response indicates an error
fn is_error_response(direction: u8) -> bool {
direction == b'!'
}

Result Codes​

Internal result codes used by MSP handlers:

CodeNameDescription
1MSP_RESULT_ACKCommand executed successfully
0MSP_RESULT_NO_REPLYNo response generated
-1MSP_RESULT_ERRORCommand failed
-2MSP_RESULT_CMD_UNKNOWNCommand not recognized

Timing Considerations​

  • Response Time: Typically 1-10ms for simple queries
  • Serial Baud Rate: Common rates are 115200, 230400, 420000, 921600
  • Polling Rate: 10-100 Hz is typical for telemetry
  • Timeout: Recommended 100-500ms timeout for responses
/// Recommended MSP timing constants
pub const MSP_DEFAULT_TIMEOUT_MS: u64 = 500;
pub const MSP_TELEMETRY_RATE_HZ: u32 = 50;
pub const MSP_SERIAL_BAUD: u32 = 115200;

Next Steps​