1
0
Fork 0
mirror of https://github.com/betaflight/betaflight.git synced 2025-07-16 04:45:24 +03:00

synced serial protocol to multiwii-dev 20120622

changed booleans to bitfield struct to match with 0622
no other functional changes, and not all enhancements (like boxlight) from 0622 are implemented yet
NOT flight tested, use at your own risk.

git-svn-id: https://afrodevices.googlecode.com/svn/trunk/baseflight@172 7c89a4a9-59b9-e629-4cfe-3a2d53b20e61
This commit is contained in:
timecop 2012-06-30 13:20:53 +00:00
parent 2fd5645dce
commit 9c2204c179
11 changed files with 5584 additions and 5472 deletions

View file

@ -1,6 +1,10 @@
#include "board.h"
#include "mw.h"
// Multiwii Serial Protocol 0
#define MSP_VERSION 0
#define PLATFORM_32BIT 0x80000000
#define MSP_IDENT 100 //out message multitype + version
#define MSP_STATUS 101 //out message cycletime & errors_count & sensor present & box activation
#define MSP_RAW_IMU 102 //out message 9 DOF
@ -17,6 +21,8 @@
#define MSP_BOX 113 //out message up to 16 checkbox (11 are used)
#define MSP_MISC 114 //out message powermeter trig + 8 free for future use
#define MSP_MOTOR_PINS 115 //out message which pins are in use for motors & servos, for GUI
#define MSP_BOXNAMES 116 //out message the aux switch names
#define MSP_PIDNAMES 117 //out message the PID names
#define MSP_SET_RAW_RC 200 //in message 8 rc chan
#define MSP_SET_RAW_GPS 201 //in message fix, numsat, lat, lon, alt, speed
@ -32,7 +38,38 @@
#define MSP_DEBUG 254 //out message debug1,debug2,debug3,debug4
static uint8_t checksum, stateMSP, indRX, inBuf[64];
#define INBUF_SIZE 64
static const char boxnames[] =
"ACC;"
"BARO;"
"MAG;"
"CAMSTAB;"
"CAMTRIG;"
"ARM;"
"GPS HOME;"
"GPS HOLD;"
"PASSTHRU;"
"HEADFREE;"
"BEEPER;"
"LEDMAX;"
"LLIGHTS;"
"HEADADJ;";
static const char pidnames[] =
"ROLL;"
"PITCH;"
"YAW;"
"ALT;"
"Pos;"
"PosR;"
"NavR;"
"LEVEL;"
"MAG;"
"VEL;";
static uint8_t checksum, indRX, inBuf[INBUF_SIZE];
static uint8_t cmdMSP;
void serialize32(uint32_t a)
{
@ -68,35 +105,43 @@ void serialize8(uint8_t a)
checksum ^= a;
}
uint32_t read32(void)
{
uint32_t t = inBuf[indRX++];
t += inBuf[indRX++] << 8;
t += (uint32_t) inBuf[indRX++] << 16;
t += (uint32_t) inBuf[indRX++] << 24;
return t;
}
uint16_t read16(void)
{
uint16_t t = inBuf[indRX++];
t += inBuf[indRX++] << 8;
return t;
}
uint8_t read8(void)
{
return inBuf[indRX++] & 0xff;
}
void headSerialReply(uint8_t c, uint8_t s)
uint16_t read16(void)
{
uint16_t t = read8();
t += (uint16_t) read8() << 8;
return t;
}
uint32_t read32(void)
{
uint32_t t = read16();
t += (uint32_t) read16() << 16;
return t;
}
void headSerialResponse(uint8_t err, uint8_t s)
{
serialize8('$');
serialize8('M');
serialize8('>');
serialize8(err ? '!' : '>');
checksum = 0; // start calculating a new checksum
serialize8(s);
serialize8(c);
checksum = 0;
serialize8(cmdMSP);
}
void headSerialReply(uint8_t s)
{
headSerialResponse(0, s);
}
void headSerialError(uint8_t s)
{
headSerialResponse(1, s);
}
void tailSerialReply(void)
@ -106,6 +151,13 @@ void tailSerialReply(void)
// UartSendData();
}
void serializeNames(const char *s)
{
const char *c;
for (c = s; *c; c++)
serialize8(*c);
}
// signal that we're in cli mode
uint8_t cliMode = 0;
@ -114,10 +166,203 @@ void serialInit(uint32_t baudrate)
uartInit(baudrate);
}
static void evaluateCommand(void)
{
uint8_t i;
switch (cmdMSP) {
case MSP_SET_RAW_RC:
for (i = 0; i < 8; i++)
rcData[i] = read16();
headSerialReply(0);
break;
case MSP_SET_RAW_GPS:
f.GPS_FIX = read8();
GPS_numSat = read8();
GPS_coord[LAT] = read32();
GPS_coord[LON] = read32();
GPS_altitude = read16();
GPS_speed = read16();
GPS_update |= 2; // New data signalisation to GPS functions
headSerialReply(0);
break;
case MSP_SET_PID:
for (i = 0; i < PIDITEMS; i++) {
cfg.P8[i] = read8();
cfg.I8[i] = read8();
cfg.D8[i] = read8();
}
headSerialReply(0);
break;
case MSP_SET_BOX:
for (i = 0; i < CHECKBOXITEMS; i++)
cfg.activate[i] = read16();
headSerialReply(0);
break;
case MSP_SET_RC_TUNING:
cfg.rcRate8 = read8();
cfg.rcExpo8 = read8();
cfg.rollPitchRate = read8();
cfg.yawRate = read8();
cfg.dynThrPID = read8();
cfg.thrMid8 = read8();
cfg.thrExpo8 = read8();
headSerialReply(0);
break;
case MSP_SET_MISC:
headSerialReply(0);
break;
case MSP_IDENT:
headSerialReply(7);
serialize8(VERSION); // multiwii version
serialize8(cfg.mixerConfiguration); // type of multicopter
serialize8(MSP_VERSION); // MultiWii Serial Protocol Version
serialize32(PLATFORM_32BIT); // "capability"
break;
case MSP_STATUS:
headSerialReply(10);
serialize16(cycleTime);
serialize16(i2cGetErrorCounter());
serialize16(sensors(SENSOR_ACC) | sensors(SENSOR_BARO) << 1 | sensors(SENSOR_MAG) << 2 | sensors(SENSOR_GPS) << 3 | sensors(SENSOR_SONAR) << 4);
serialize32(f.ACC_MODE << BOXACC | f.BARO_MODE << BOXBARO | f.MAG_MODE << BOXMAG | f.ARMED << BOXARM | rcOptions[BOXCAMSTAB] << BOXCAMSTAB | rcOptions[BOXCAMTRIG] << BOXCAMTRIG | f.GPS_HOME_MODE << BOXGPSHOME | f.GPS_HOLD_MODE << BOXGPSHOLD | f.HEADFREE_MODE << BOXHEADFREE | f.PASSTHRU_MODE << BOXPASSTHRU | rcOptions[BOXBEEPERON] << BOXBEEPERON | rcOptions[BOXLEDMAX] << BOXLEDMAX | rcOptions[BOXLLIGHTS] << BOXLLIGHTS | rcOptions[BOXHEADADJ] << BOXHEADADJ);
break;
case MSP_RAW_IMU:
headSerialReply(18);
for (i = 0; i < 3; i++)
serialize16(accSmooth[i]);
for (i = 0; i < 3; i++)
serialize16(gyroData[i]);
for (i = 0; i < 3; i++)
serialize16(magADC[i]);
break;
case MSP_SERVO:
headSerialReply(16);
for (i = 0; i < 8; i++)
serialize16(servo[i]);
break;
case MSP_MOTOR:
headSerialReply(16);
for (i = 0; i < 8; i++)
serialize16(motor[i]);
break;
case MSP_RC:
headSerialReply(16);
for (i = 0; i < 8; i++)
serialize16(rcData[i]);
break;
case MSP_RAW_GPS:
headSerialReply(14);
serialize8(f.GPS_FIX);
serialize8(GPS_numSat);
serialize32(GPS_coord[LAT]);
serialize32(GPS_coord[LON]);
serialize16(GPS_altitude);
serialize16(GPS_speed);
break;
case MSP_COMP_GPS:
headSerialReply(5);
serialize16(GPS_distanceToHome);
serialize16(GPS_directionToHome);
serialize8(GPS_update & 1);
break;
case MSP_ATTITUDE:
headSerialReply(8);
for (i = 0; i < 2; i++)
serialize16(angle[i]);
serialize16(heading);
serialize16(headFreeModeHold);
break;
case MSP_ALTITUDE:
headSerialReply(4);
serialize32(EstAlt);
break;
case MSP_BAT:
headSerialReply(3);
serialize8(vbat);
serialize16(0); // power meter trash
break;
case MSP_RC_TUNING:
headSerialReply(7);
serialize8(cfg.rcRate8);
serialize8(cfg.rcExpo8);
serialize8(cfg.rollPitchRate);
serialize8(cfg.yawRate);
serialize8(cfg.dynThrPID);
serialize8(cfg.thrMid8);
serialize8(cfg.thrExpo8);
break;
case MSP_PID:
headSerialReply(3 * PIDITEMS);
for (i = 0; i < PIDITEMS; i++) {
serialize8(cfg.P8[i]);
serialize8(cfg.I8[i]);
serialize8(cfg.D8[i]);
}
break;
case MSP_BOX:
headSerialReply(2 * CHECKBOXITEMS);
for (i = 0; i < CHECKBOXITEMS; i++)
serialize16(cfg.activate[i]);
break;
case MSP_BOXNAMES:
headSerialReply(sizeof(boxnames) - 1);
serializeNames(boxnames);
break;
case MSP_PIDNAMES:
headSerialReply(sizeof(pidnames) - 1);
serializeNames(pidnames);
break;
case MSP_MISC:
headSerialReply(2);
serialize16(0); // intPowerTrigger1
break;
case MSP_MOTOR_PINS:
headSerialReply(8);
for (i = 0; i < 8; i++)
serialize8(i + 1);
break;
case MSP_RESET_CONF:
checkFirstTime(true);
headSerialReply(0);
break;
case MSP_ACC_CALIBRATION:
calibratingA = 400;
headSerialReply(0);
break;
case MSP_MAG_CALIBRATION:
f.CALIBRATE_MAG = 1;
headSerialReply(0);
break;
case MSP_EEPROM_WRITE:
writeParams(0);
headSerialReply(0);
break;
case MSP_DEBUG:
headSerialReply(8);
for (i = 0; i < 4; i++)
serialize16(debug[i]); // 4 variables are here for general monitoring purpose
break;
default: // we do not know how to handle the (valid) message, indicate error MSP $M!
headSerialError(0);
break;
}
tailSerialReply();
}
void serialCom(void)
{
uint8_t i, c;
static uint8_t offset, dataSize;
uint8_t c;
static uint8_t offset;
static uint8_t dataSize;
static enum _serial_state {
IDLE,
HEADER_START,
HEADER_M,
HEADER_ARROW,
HEADER_SIZE,
HEADER_CMD,
} c_state = IDLE;
// in cli mode, all uart stuff goes to here. enter cli mode by sending #
if (cliMode) {
@ -128,238 +373,41 @@ void serialCom(void)
while (uartAvailable()) {
c = uartRead();
if (stateMSP > 99) { // a message with a length indication, indicating a non null payload
if (offset <= dataSize) { // there are still some octets to read (including checksum) to complete a full message
if (offset < dataSize)
checksum ^= c; // the checksum is computed, except for the last octet
inBuf[offset++] = c;
} else { // we have read all the payload
if (checksum == inBuf[dataSize]) { // we check is the computed checksum is ok
switch (stateMSP) { // if yes, then we execute different code depending on the message code. read8/16/32 will look into the inBuf buffer
case MSP_SET_RAW_RC:
for (i = 0; i < 8; i++) {
rcData[i] = read16();
}
break;
case MSP_SET_RAW_GPS:
GPS_fix = read8();
GPS_numSat = read8();
GPS_coord[LAT] = read32();
GPS_coord[LON] = read32();
GPS_altitude = read16();
GPS_speed = read16();
GPS_update = 1;
break;
case MSP_SET_PID:
for (i = 0; i < PIDITEMS; i++) {
cfg.P8[i] = read8();
cfg.I8[i] = read8();
cfg.D8[i] = read8();
}
break;
case MSP_SET_BOX:
for (i = 0; i < CHECKBOXITEMS; i++) {
cfg.activate[i] = read16();
}
break;
case MSP_SET_RC_TUNING:
cfg.rcRate8 = read8();
cfg.rcExpo8 = read8();
cfg.rollPitchRate = read8();
cfg.yawRate = read8();
cfg.dynThrPID = read8();
cfg.thrMid8 = read8();
cfg.thrExpo8 = read8();
break;
case MSP_SET_MISC:
break;
}
}
stateMSP = 0; // in any case we reset the MSP state
}
}
if (stateMSP < 5) {
if (stateMSP == 4) { // this protocol state indicates we have a message with a lenght indication, and we read here the message code (fifth octet)
if (c > 99) { // we check if it's a valid code (should be >99)
stateMSP = c; // the message code is then reuse to feed the protocol state
offset = 0;
checksum = 0;
indRX = 0; // and we init some values which will be used in the next loops to grasp the payload
} else {
stateMSP = 0; // the message code seems to be invalid. this should not happen => we reset the protocol state
}
}
if (stateMSP == 3) { // here, we need to check if the fourth octet indicates a code indication (>99) or a payload lenght indication (<100)
if (c < 100) { // a message with a length indication, indicating a non null payload
stateMSP++; // we update the protocol state to read the next octet
dataSize = c; // we store the payload lenght
if (dataSize > 63)
dataSize = 63; // in order to avoid overflow, we limit the size. this should not happen
} else {
switch (c) { // if we are here, the fourth octet indicates a code message
case MSP_IDENT: // and we check message code to execute the relative code
headSerialReply(c, 2); // we reply with an header indicating a payload lenght of 2 octets
serialize8(VERSION); // the first octet. serialize8/16/32 is used also to compute a checksum
serialize8(cfg.mixerConfiguration); // the second one
tailSerialReply();
break; // mainly to send the last octet which is the checksum
case MSP_STATUS:
headSerialReply(c, 8);
serialize16(cycleTime);
serialize16(i2cGetErrorCounter());
serialize16(sensors(SENSOR_ACC) | sensors(SENSOR_BARO) << 1 | sensors(SENSOR_MAG) << 2 | sensors(SENSOR_GPS) << 3 | sensors(SENSOR_SONAR) << 4);
serialize16(accMode << BOXACC | baroMode << BOXBARO | magMode << BOXMAG | armed << BOXARM | GPSModeHome << BOXGPSHOME | GPSModeHold << BOXGPSHOLD | headFreeMode << BOXHEADFREE);
tailSerialReply();
break;
case MSP_RAW_IMU:
headSerialReply(c, 18);
for (i = 0; i < 3; i++)
serialize16(accSmooth[i]);
for (i = 0; i < 3; i++)
serialize16(gyroData[i]);
for (i = 0; i < 3; i++)
serialize16(magADC[i]);
tailSerialReply();
break;
case MSP_SERVO:
headSerialReply(c, 16);
for (i = 0; i < 8; i++)
serialize16(servo[i]);
tailSerialReply();
break;
case MSP_MOTOR:
headSerialReply(c, 16);
for (i = 0; i < 8; i++)
serialize16(motor[i]);
tailSerialReply();
break;
case MSP_RC:
headSerialReply(c, 16);
for (i = 0; i < 8; i++)
serialize16(rcData[i]);
tailSerialReply();
break;
case MSP_RAW_GPS:
headSerialReply(c, 14);
serialize8(GPS_fix);
serialize8(GPS_numSat);
serialize32(GPS_coord[LAT]);
serialize32(GPS_coord[LON]);
serialize16(GPS_altitude);
serialize16(GPS_speed);
tailSerialReply();
break;
case MSP_COMP_GPS:
headSerialReply(c, 5);
serialize16(GPS_distanceToHome);
serialize16(GPS_directionToHome + 180);
serialize8(GPS_update);
tailSerialReply();
break;
case MSP_ATTITUDE:
headSerialReply(c, 6);
for (i = 0; i < 2; i++)
serialize16(angle[i]);
serialize16(heading);
tailSerialReply();
break;
case MSP_ALTITUDE:
headSerialReply(c, 4);
serialize32(EstAlt);
tailSerialReply();
break;
case MSP_BAT:
headSerialReply(c, 3);
serialize8(vbat);
serialize16(0);
tailSerialReply();
break;
case MSP_RC_TUNING:
headSerialReply(c, 7);
serialize8(cfg.rcRate8);
serialize8(cfg.rcExpo8);
serialize8(cfg.rollPitchRate);
serialize8(cfg.yawRate);
serialize8(cfg.dynThrPID);
serialize8(cfg.thrMid8);
serialize8(cfg.thrExpo8);
tailSerialReply();
break;
case MSP_PID:
headSerialReply(c, 3 * PIDITEMS);
for (i = 0; i < PIDITEMS; i++) {
serialize8(cfg.P8[i]);
serialize8(cfg.I8[i]);
serialize8(cfg.D8[i]);
}
tailSerialReply();
break;
case MSP_BOX:
headSerialReply(c, 2 * CHECKBOXITEMS);
for (i = 0; i < CHECKBOXITEMS; i++) {
serialize16(cfg.activate[i]);
}
tailSerialReply();
break;
case MSP_MISC:
headSerialReply(c, 2);
serialize16(0);
tailSerialReply();
break;
case MSP_MOTOR_PINS:
headSerialReply(c, 8);
for (i = 0; i < 8; i++)
serialize8(i + 1);
tailSerialReply();
break;
case MSP_RESET_CONF:
checkFirstTime(true);
break;
case MSP_ACC_CALIBRATION:
calibratingA = 400;
calibratingG = 1000; // hit gyro too
break;
case MSP_MAG_CALIBRATION:
calibratingM = 1;
break;
case MSP_EEPROM_WRITE:
writeParams(0);
break;
case MSP_DEBUG:
headSerialReply(c, 8);
serialize16(debug1); // 4 variables are here for general monitoring purpose
serialize16(debug2);
serialize16(debug3);
serialize16(debug4);
tailSerialReply();
break;
}
stateMSP = 0; // we reset the protocol state for the next loop
}
} else {
switch (c) { // header detection $MW<
case '$':
if (stateMSP == 0)
stateMSP++;
break; // first octet ok, no need to go further
case 'M':
if (stateMSP == 1)
stateMSP++;
break; // second octet ok, no need to go further
case '<':
if (stateMSP == 2)
stateMSP++;
break; // third octet ok, no need to go further
}
}
}
if (stateMSP == 0) { // still compliant with older single octet command
if (c_state == IDLE) {
// still compliant with older single octet command
// enable CLI
if (c == '#')
cliProcess();
else if (c == 'R')
systemReset(true); // reboot to bootloader
c_state = (c == '$') ? HEADER_START : IDLE;
} else if (c_state == HEADER_START) {
c_state = (c == 'M') ? HEADER_M : IDLE;
} else if (c_state == HEADER_M) {
c_state = (c == '<') ? HEADER_ARROW : IDLE;
} else if (c_state == HEADER_ARROW) {
if (c > INBUF_SIZE) { // now we are expecting the payload size
c_state = IDLE;
continue;
}
dataSize = c;
offset = 0;
checksum = 0;
indRX = 0;
checksum ^= c;
c_state = HEADER_SIZE; // the command is to follow
} else if (c_state == HEADER_SIZE) {
cmdMSP = c;
checksum ^= c;
c_state = HEADER_CMD;
} else if (c_state == HEADER_CMD && offset < dataSize) {
checksum ^= c;
inBuf[offset++] = c;
} else if (c_state == HEADER_CMD && offset >= dataSize) {
if (checksum == c) { // compare calculated and transferred checksum
evaluateCommand(); // we got a valid packet, evaluate it
}
c_state = IDLE;
}
}
}