-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmsp_library.cpp
151 lines (127 loc) · 3.75 KB
/
msp_library.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
MSP.cpp
Copyright (c) 2017, Fabrizio Di Vittorio ([email protected])
This file originally was distributed under LGPL 2.1 and was transferred to
GNU GPL under the section 3 of LGPL 2.1 License
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Arduino.h>
#include "msp_library.h"
void MSPLibrary::begin(Stream &stream, uint32_t timeout)
{
_stream = &stream;
_timeout = timeout;
}
void MSPLibrary::reset()
{
_stream->flush();
while (_stream->available() > 0)
_stream->read();
}
void MSPLibrary::send(uint8_t messageID, void *payload, uint8_t size)
{
_stream->write('$');
_stream->write('M');
_stream->write('<');
_stream->write(size);
_stream->write(messageID);
uint8_t checksum = size ^ messageID;
uint8_t *payloadPtr = (uint8_t *)payload;
for (uint8_t i = 0; i < size; ++i)
{
uint8_t b = *(payloadPtr++);
checksum ^= b;
_stream->write(b);
}
_stream->write(checksum);
}
// timeout in milliseconds
bool MSPLibrary::recv(uint8_t *messageID, void *payload, uint8_t maxSize, uint8_t *recvSize)
{
uint32_t t0 = millis();
while (1)
{
// read header
while (_stream->available() < 6)
if (millis() - t0 >= _timeout)
return false;
char header[3];
_stream->readBytes((char *)header, 3);
// check header
if (header[0] == '$' && header[1] == 'M' && header[2] == '>')
{
// header ok, read payload size
*recvSize = _stream->read();
// read message ID (type)
*messageID = _stream->read();
uint8_t checksumCalc = *recvSize ^ *messageID;
// read payload
uint8_t *payloadPtr = (uint8_t *)payload;
uint8_t idx = 0;
while (idx < *recvSize)
{
if (millis() - t0 >= _timeout)
return false;
if (_stream->available() > 0)
{
uint8_t b = _stream->read();
checksumCalc ^= b;
if (idx < maxSize)
*(payloadPtr++) = b;
++idx;
}
}
// zero remaining bytes if *size < maxSize
for (; idx < maxSize; ++idx)
*(payloadPtr++) = 0;
// read and check checksum
while (_stream->available() == 0)
if (millis() - t0 >= _timeout)
return false;
uint8_t checksum = _stream->read();
if (checksumCalc == checksum)
{
return true;
}
}
}
}
// wait for messageID
// recvSize can be NULL
bool MSPLibrary::waitFor(uint8_t messageID, void *payload, uint8_t maxSize, uint8_t *recvSize)
{
uint8_t recvMessageID;
uint8_t recvSizeValue;
uint32_t t0 = millis();
while (millis() - t0 < _timeout)
if (recv(&recvMessageID, payload, maxSize, (recvSize ? recvSize : &recvSizeValue)) && messageID == recvMessageID)
return true;
// timeout
return false;
}
// send a message and wait for the reply
// recvSize can be NULL
bool MSPLibrary::request(uint8_t messageID, void *payload, uint8_t maxSize, uint8_t *recvSize)
{
send(messageID, NULL, 0);
return waitFor(messageID, payload, maxSize, recvSize);
}
// send message and wait for ack
bool MSPLibrary::command(uint8_t messageID, void *payload, uint8_t size, bool waitACK)
{
send(messageID, payload, size);
// ack required
if (waitACK)
return waitFor(messageID, NULL, 0);
return true;
}