5 /* ==========================================
6 MSP V2 Message Structure:
7 Offset: Usage: In CRC: Comment:
8 ======= ====== ======= ========
9 0 $ Framing magic start char
10 1 X 'X' in place of v1 'M'
11 2 type '<' / '>' / '!' Message Type (TODO find out what ! type is)
12 3 flag + uint8, flag, usage to be defined (set to zero)
13 4 function + uint16 (little endian). 0 - 255 is the same function as V1 for backwards compatibility
14 6 payload size + uint16 (little endian) payload size in bytes
15 8 payload + n (up to 65535 bytes) payload
16 n+8 checksum uint8, (n= payload size), crc8_dvb_s2 checksum
17 ========================================== */
19 // CRC helper function. External to MSP class
20 // TODO: Move all our CRC functions to a CRC lib
21 uint8_t crc8_dvb_s2(uint8_t crc
, unsigned char a
)
24 for (int ii
= 0; ii
< 8; ++ii
) {
26 crc
= (crc
<< 1) ^ 0xD5;
35 MSP::processReceivedByte(uint8_t c
)
37 switch (m_inputState
) {
40 // Wait for framing char
42 m_inputState
= MSP_HEADER_START
;
46 case MSP_HEADER_START
:
47 // Waiting for 'X' (MSPv2 native)
50 m_inputState
= MSP_HEADER_X
;
53 m_inputState
= MSP_IDLE
;
59 // Wait for the packet type (cmd or req)
60 m_inputState
= MSP_HEADER_V2_NATIVE
;
62 // Start of a new packet
63 // reset the packet, offset iterator, and CRC
70 m_packet
.type
= MSP_PACKET_COMMAND
;
73 m_packet
.type
= MSP_PACKET_RESPONSE
;
76 m_packet
.type
= MSP_PACKET_UNKNOWN
;
77 m_inputState
= MSP_IDLE
;
82 case MSP_HEADER_V2_NATIVE
:
83 // Read bytes until we have a full header
84 m_inputBuffer
[m_offset
++] = c
;
85 m_crc
= crc8_dvb_s2(m_crc
, c
);
87 // If we've received the correct amount of bytes for a full header
88 if (m_offset
== sizeof(mspHeaderV2_t
)) {
89 // Copy header values into packet
90 mspHeaderV2_t
* header
= (mspHeaderV2_t
*)&m_inputBuffer
[0];
91 m_packet
.payloadSize
= header
->payloadSize
;
92 m_packet
.function
= header
->function
;
93 m_packet
.flags
= header
->flags
;
94 // reset the offset iterator for re-use in payload below
96 if (m_packet
.payloadSize
== 0)
97 m_inputState
= MSP_CHECKSUM_V2_NATIVE
;
99 m_inputState
= MSP_PAYLOAD_V2_NATIVE
;
103 case MSP_PAYLOAD_V2_NATIVE
:
104 // Read bytes until we reach payloadSize
105 m_packet
.payload
[m_offset
++] = c
;
106 m_crc
= crc8_dvb_s2(m_crc
, c
);
108 // If we've received the correct amount of bytes for payload
109 if (m_offset
== m_packet
.payloadSize
) {
110 // Then we're up to the CRC
111 m_inputState
= MSP_CHECKSUM_V2_NATIVE
;
115 case MSP_CHECKSUM_V2_NATIVE
:
116 // Assert that the checksums match
118 m_inputState
= MSP_COMMAND_RECEIVED
;
121 DBGLN("CRC failure on MSP packet - Got %d expected %d", c
, m_crc
);
122 m_inputState
= MSP_IDLE
;
127 m_inputState
= MSP_IDLE
;
131 // If we've successfully parsed a complete packet
132 // return true so the calling function knows that
133 // a new packet is ready.
134 if (m_inputState
== MSP_COMMAND_RECEIVED
) {
141 MSP::getReceivedPacket()
147 MSP::markPacketReceived()
149 // Set input state to idle, ready to receive the next packet
150 // The current packet data will be discarded internally
151 m_inputState
= MSP_IDLE
;
155 MSP::sendPacket(mspPacket_t
* packet
, Stream
* port
)
157 // Sanity check the packet before sending
158 if (packet
->type
!= MSP_PACKET_COMMAND
&& packet
->type
!= MSP_PACKET_RESPONSE
) {
159 // Unsupported packet type (note: ignoring '!' until we know what it is)
163 if (packet
->type
== MSP_PACKET_RESPONSE
&& packet
->payloadSize
== 0) {
164 // Response packet with no payload
168 // Write out the framing chars
172 // Write out the packet type
173 if (packet
->type
== MSP_PACKET_COMMAND
) {
176 else if (packet
->type
== MSP_PACKET_RESPONSE
) {
180 // Subsequent bytes are contained in the crc
183 // Pack header struct into buffer
184 uint8_t headerBuffer
[5];
185 mspHeaderV2_t
* header
= (mspHeaderV2_t
*)&headerBuffer
[0];
186 header
->flags
= packet
->flags
;
187 header
->function
= packet
->function
;
188 header
->payloadSize
= packet
->payloadSize
;
190 // Write out the header buffer, adding each byte to the crc
191 for (uint8_t i
= 0; i
< sizeof(mspHeaderV2_t
); ++i
) {
192 port
->write(headerBuffer
[i
]);
193 crc
= crc8_dvb_s2(crc
, headerBuffer
[i
]);
196 // Write out the payload, adding each byte to the crc
197 for (uint16_t i
= 0; i
< packet
->payloadSize
; ++i
) {
198 port
->write(packet
->payload
[i
]);
199 crc
= crc8_dvb_s2(crc
, packet
->payload
[i
]);