/* * FrSky Telemetry Protocol Host implementation. * Copyright 2016 by Thomas Buck * * Based on the FrSky Telemetry Protocol documentation: * http://www.frsky-rc.com/download/down.php?id=128 * * 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 2. */ #include "frsky.h" #define DEBUG_OUTPUT Serial FrSky::FrSky(Stream* s) : serial(s), dataHandler(0), alarmThresholdHandler(0), userDataHandler(0), bufferIndex(0) { for (uint8_t i = 0; i < userDataSize; i++) { userData[i] = 0; } for (uint8_t i = 0; i < bufferSize; i++) { buffer[i] = 0; } } void FrSky::poll() { if ((!serial) || (!serial->available())) { return; } uint8_t c = serial->read(); if (c == delimiter) { if (bufferIndex < minPacketSize) { bufferIndex = 0; } if (bufferIndex >= bufferSize) { bufferIndex = bufferSize - 1; } buffer[bufferIndex++] = c; if (bufferIndex > minPacketSize) { handleMessage(); bufferIndex = 0; } } else if ((bufferIndex > 0) && (bufferIndex < bufferSize)) { buffer[bufferIndex++] = c; } } void FrSky::pollAlarms() { serial->write(delimiter); writeEscaped(idGetAlarms); for (uint8_t i = 0; i < 8; i++) { writeEscaped(0); } serial->write(delimiter); } void FrSky::setAlarm(AlarmThreshold alarm) { uint8_t id = (alarm.id == analog1_1) ? idAlarm0 : ((alarm.id == analog1_2) ? idAlarm1 : ((alarm.id == analog2_1) ? idAlarm2 : idAlarm3)); serial->write(delimiter); writeEscaped(id); writeEscaped(alarm.value); writeEscaped(alarm.dir); writeEscaped(alarm.level); for (uint8_t i = 0; i < 5; i++) { writeEscaped(0); } serial->write(delimiter); } void FrSky::writeEscaped(uint8_t v) { if ((v == delimiter) || (v == escape)) { v ^= key; serial->write(escape); } serial->write(v); } void FrSky::handleMessage() { #ifdef DEBUG_OUTPUT DEBUG_OUTPUT.println("FrSky::handleMessage()"); for (uint8_t i = 0; i < bufferIndex; i++) { DEBUG_OUTPUT.print(buffer[i], HEX); } DEBUG_OUTPUT.println(); #endif if ((buffer[0] != delimiter) || (buffer[bufferIndex - 1] != delimiter)) { #ifdef DEBUG_OUTPUT DEBUG_OUTPUT.println("invalid packet begin/end!"); #endif return; } // Fix escaped bytes for (uint8_t i = 0; i < (bufferIndex - 1); i++) { if (buffer[i] == escape) { buffer[i] = buffer[i + 1] ^ key; for (uint8_t j = i + 1; j < (bufferIndex - 1); j++) { buffer[j] = buffer[j + 1]; } bufferIndex--; } } if (buffer[1] == idVoltageQuality) { if (dataHandler) { dataHandler(buffer[2], buffer[3], buffer[4], buffer[5]); } } else if (buffer[1] == idUserData) { uint8_t len = buffer[2]; if (len > userDataSize) { len = userDataSize; } for (uint8_t i = 0; i < len; i++) { userData[i] = buffer[i + 4]; } if ((len > 0) && (userDataHandler)) { userDataHandler(userData, len); } } else if ((buffer[1] == idAlarm0) || (buffer[1] == idAlarm1) || (buffer[1] == idAlarm2) || (buffer[1] == idAlarm3)) { AnalogValue v = (buffer[1] == idAlarm0) ? analog1_1 : ((buffer[1] == idAlarm1) ? analog1_2 : ((buffer[1] == idAlarm2) ? analog2_1 : analog2_2)); if (alarmThresholdHandler) { alarmThresholdHandler(AlarmThreshold(v, (GreaterLessThan)buffer[3], (AlarmLevel)buffer[4], buffer[2])); } } else { #ifdef DEBUG_OUTPUT DEBUG_OUTPUT.print("Unexpected ID: "); DEBUG_OUTPUT.println(buffer[1], HEX); #endif } }