Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: EthernetNetIf mbed ConfigFile
Revision 0:a5d13af495af, committed 2011-12-21
- Comitter:
- bapowell
- Date:
- Wed Dec 21 22:29:59 2011 +0000
- Commit message:
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EthernetNetIf.lib Wed Dec 21 22:29:59 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mamezu/code/EthernetNetIf/#0f6c82fcde82
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LocalConfigFile/ConfigFile.lib Wed Dec 21 22:29:59 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/shintamainjp/code/ConfigFile/#f6ceafabe9f8
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/LocalConfigFile/LocalConfigFile.cpp Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,114 @@
+#include <ctype.h>
+#include "LocalConfigFile.h"
+
+LocalConfigFile::LocalConfigFile(char *filename) {
+ LocalFileSystem localFileSys("local"); // create the local filesystem under the name "local"
+ sprintf(_buf, "/local/%s", filename); // set full file path into _buf
+ printf("Reading config file: %s ... ", _buf);
+ if (read(_buf)) {
+ printf("Success \n");
+ }
+ else {
+ printf("Problem \n");
+ }
+}
+
+char LocalConfigFile::getChar(char *key, char defaultVal) {
+ if (getValueIntoBuf(key)) {
+ if (strlen(_buf) > 0) {
+ return _buf[0];
+ }
+ else {
+ printf("getChar(key='%s'): Problem \n", key);
+ }
+ }
+ return defaultVal;
+}
+
+bool LocalConfigFile::getBool(char *key, bool defaultVal) {
+ char c = getChar(key, '.');
+ if (c != '.') {
+ c = toupper(c);
+ return (c == 'T' || c == 'Y' || c == '1');
+ }
+ else {
+ printf("getBool(key='%s'): Problem \n", key);
+ }
+ return defaultVal;
+}
+
+int LocalConfigFile::getInt(char *key, int defaultVal) {
+ if (getValueIntoBuf(key)) {
+ int val;
+ int cnt = sscanf(_buf, "%d", &val);
+ if (cnt == 1) {
+ return val;
+ }
+ else {
+ printf("getInt(key='%s'): Problem \n", key);
+ }
+ }
+ return defaultVal;
+}
+
+PinName LocalConfigFile::getPin(char *key, PinName defaultVal) {
+ const PinName pinName[] = {p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17, p18,
+ p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30};
+ int p = getInt(key, -1);
+ if (p == -1) {
+ printf("getPin(key='%s'): Problem \n", key);
+ }
+ else if (p < 5 || p > 30) {
+ printf("getPin(key='%s'): Invalid pin#: %d. Pin# must be between 5 and 30, inclusive.\n", key, p);
+ }
+ else {
+ return pinName[p - 5];
+ }
+ return defaultVal;
+}
+
+bool LocalConfigFile::fillIntArray4(char *key, int *intArray) {
+ if (getValueIntoBuf(key)) {
+ int a0, a1, a2, a3;
+ int cnt = sscanf(_buf, "%d %d %d %d", &a0, &a1, &a2, &a3);
+ if (cnt == 4) {
+ intArray[0] = a0;
+ intArray[1] = a1;
+ intArray[2] = a2;
+ intArray[3] = a3;
+ return true;
+ }
+ else {
+ printf("fillIntArray4(key='%s'): Problem \n", key);
+ }
+ }
+ return false;
+}
+
+bool LocalConfigFile::fillFloatArray4(char *key, float *floatArray) {
+ if (getValueIntoBuf(key)) {
+ float a0, a1, a2, a3;
+ int cnt = sscanf(_buf, "%f %f %f %f", &a0, &a1, &a2, &a3);
+ if (cnt == 4) {
+ floatArray[0] = a0;
+ floatArray[1] = a1;
+ floatArray[2] = a2;
+ floatArray[3] = a3;
+ return true;
+ }
+ else {
+ printf("fillFloatArray4(key='%s'): Problem \n", key);
+ }
+ }
+ return false;
+}
+
+bool LocalConfigFile::getValueIntoBuf(char *key) {
+ if (getValue(key, _buf, sizeof(_buf))) {
+ return true;
+ }
+ else {
+ printf("LocalConfigFile.getValueIntoBuf(key='%s'): Problem, or config key not found \n", key);
+ return false;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/LocalConfigFile/LocalConfigFile.h Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,25 @@
+#ifndef LOCALCONFIGFILE_H_INCLUDED
+#define LOCALCONFIGFILE_H_INCLUDED
+
+#include "mbed.h"
+#include "ConfigFile.h"
+
+class LocalConfigFile : public ConfigFile {
+public:
+
+ LocalConfigFile(char *filename);
+ char getChar(char *key, char defaultVal);
+ bool getBool(char *key, bool defaulVal);
+ int getInt(char *key, int defaultVal);
+ PinName getPin(char *key, PinName defaultVal);
+ bool fillIntArray4(char *key, int *intArray);
+ bool fillFloatArray4(char *key, float *floatArray);
+
+private:
+
+ char _buf[100];
+
+ bool getValueIntoBuf(char *key);
+};
+
+#endif // LOCALCONFIGFILE_H_INCLUDED
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Ranger/Ranger.h Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,159 @@
+#ifndef RANGER_H_INCLUDED
+#define RANGER_H_INCLUDED
+
+#include <vector>
+#include <stdarg.h>
+
+/**
+ * Perform range-type functions on a list of numbers.
+ * The numbers must be in ascending order.
+ *
+ * Example:
+ * @code
+ *
+ * #include "mbed.h"
+ * #include "Ranger.h"
+ *
+ * AnalogIn hatSwitch(p16);
+ *
+ * int main() {
+ *
+ * Ranger<float> hatSwitchInputRanger(4, 0.59, 0.68, 0.78, 0.92);
+ * int hatSwitchDegreesByRange[5] = {0, -90, 180, 90, 0};
+ *
+ * while(1) {
+ * int newRange = hatSwitchInputRanger.range(hatSwitch.read());
+ * if (hatSwitchInputRanger.rangeChanged()) {
+ * int degrees = hatSwitchDegreesByRange[newRange];
+ * }
+ * wait(0.1);
+ * }
+ * }
+ * @endcode
+ */
+
+template<typename N>
+class Ranger {
+public:
+
+ /**
+ * Create a Ranger object from the given set of passed-in numbers.
+ * The numbers in the variable argument list must be in ascending order.
+ *
+ * @param argCount number of arguments that follow
+ * @param ... numbers, in ascending order, which define the ranges
+ */
+ Ranger(int argCount, ... );
+
+ /**
+ * Create a Ranger object from the given vector.
+ * The numbers in the vector must be in ascending order.
+ *
+ * @param vect vector to copy from
+ */
+ Ranger(vector<N> vect);
+
+ /**
+ * Create a Ranger object from the given array.
+ * The numbers in the array must be in ascending order.
+ *
+ * @param count number of elements to copy from the array
+ * @param arr array to copy from
+ */
+ Ranger(int count, N arr[]);
+
+ /**
+ * Return the range that the given number falls in.
+ * The range is a slice index (zero-based), based on the Ranger's vector/array.
+ *
+ * @param input value to determine range from
+ */
+ int range(N input);
+
+ /**
+ * Check if the last call to range() resulted in a change of range from the previous call.
+ */
+ bool rangeChanged() const;
+
+ /**
+ * Print a representation of this instance to outputStream.
+ */
+ void toString(FILE * outputStream);
+
+private:
+
+ /**
+ * Common initialization, called from each constructor.
+ */
+ void init();
+
+ vector<N> _nbrVector;
+ N _lastInput;
+ int _lastRange;
+ bool _rangeChanged;
+};
+
+
+template<typename N>
+void Ranger<N>::init() {
+ _lastRange = -1;
+ _rangeChanged = false;
+}
+
+template<typename N>
+Ranger<N>::Ranger(int argCount, ... ) {
+ va_list argList;
+ va_start(argList, argCount);
+ for (int i = 0; i < argCount; i++) {
+ _nbrVector.push_back(va_arg(argList, N));
+ }
+ va_end(argList);
+
+ init();
+}
+
+template<typename N>
+Ranger<N>::Ranger(vector<N> vect) : _nbrVector(vect) {
+ init();
+}
+
+template<typename N>
+Ranger<N>::Ranger(int count, N arr[]) : _nbrVector(arr, arr + count) {
+ init();
+}
+
+template<typename N>
+int Ranger<N>::range(N input) {
+
+ int newRange = -1;
+
+ for (int i=0; i < _nbrVector.size(); i++) {
+ if (input < _nbrVector[i]) {
+ newRange = i;
+ break;
+ }
+ }
+
+ if (newRange == -1) {
+ newRange = _nbrVector.size();
+ }
+
+ _rangeChanged = (_lastRange != newRange);
+ _lastInput = input;
+ _lastRange = newRange;
+
+ return newRange;
+}
+
+template<typename N>
+bool Ranger<N>::rangeChanged() const {
+ return _rangeChanged;
+}
+
+template<typename N>
+void Ranger<N>::toString(FILE * outputStream) {
+ fprintf(outputStream, "Ranger: size=%d, lastRange=%d, changed=%d",
+ _nbrVector.size(), _lastRange, _rangeChanged);
+}
+
+#endif // RANGER_H_INCLUDED
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Scaler/Scaler.h Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,113 @@
+#ifndef SCALER_H_INCLUDED
+#define SCALER_H_INCLUDED
+
+/**
+ * Use linear projection (interpolation) to map/scale values from one range into another.
+ *
+ * Example:
+ * @code
+ *
+ * #include "mbed.h"
+ * #include "Scaler.h"
+ *
+ * AnalogIn pot(p20);
+ *
+ * Scaler<float> left(0.965, 0.653, -1, 0);
+ * Scaler<float> right(0.653, 0.491, 0, 1);
+ *
+ * int main() {
+ * while(1) {
+ * float scaledPotValue;
+ * float potValue = pot.read();
+ * printf("Pot value = %f, %d", potValue, pot.read_u16());
+ * if (potValue > 0.653) {
+ * scaledPotValue = left.scale(potValue);
+ * }
+ * else {
+ * scaledPotValue = right.scale(potValue);
+ * }
+ * printf("... scaled: %f \n", scaledPotValue);
+ * wait(0.1);
+ * }
+ * }
+ * @endcode
+ */
+
+template<typename N>
+class Scaler {
+public:
+
+ /**
+ * Create a Scaler object using the specified input and output ranges.
+ *
+ * @param inputFrom input range "from"
+ * @param inputTo input range "to"
+ * @param outputFrom output range "from"
+ * @param outputTo output range "to"
+ */
+ Scaler(N inputFrom, N inputTo, N outputFrom, N outputTo);
+
+ /**
+ * Map the input value, within the input range, to the output range.
+ *
+ * @param input value to project to the output range
+ */
+ N scale(N input) const;
+
+ // Accessors
+ N inputFrom() const;
+ N inputTo() const;
+ N outputFrom() const;
+ N outputTo() const;
+ N slope() const;
+
+private:
+
+ N _inputFrom;
+ N _inputTo;
+ N _outputFrom;
+ N _outputTo;
+ N _slope;
+};
+
+
+template<typename N>
+Scaler<N>::Scaler(N inputFrom, N inputTo, N outputFrom, N outputTo) {
+ _inputFrom = inputFrom;
+ _inputTo = inputTo;
+ _outputFrom = outputFrom;
+ _outputTo = outputTo;
+ _slope = (outputTo - outputFrom) / (inputTo - inputFrom);
+}
+
+template<typename N>
+N Scaler<N>::scale(N input) const {
+ return _slope * (input - _inputFrom) + _outputFrom;
+}
+
+template<typename N>
+N Scaler<N>::inputFrom() const {
+ return _inputFrom;
+}
+
+template<typename N>
+N Scaler<N>::inputTo() const {
+ return _inputTo;
+}
+
+template<typename N>
+N Scaler<N>::outputFrom() const {
+ return _outputFrom;
+}
+
+template<typename N>
+N Scaler<N>::outputTo() const {
+ return _outputTo;
+}
+
+template<typename N>
+N Scaler<N>::slope() const {
+ return _slope;
+}
+
+#endif // SCALER_H_INCLUDED
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/TimeoutPrompt/TimeoutPrompt.cpp Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,28 @@
+#include "TimeoutPrompt.h"
+
+TimeoutPrompt::TimeoutPrompt(Serial & serialInOut, int defaultTimeoutSeconds) :
+ _serialInOut(serialInOut), _defaultTimeoutSeconds(defaultTimeoutSeconds)
+{
+ _timer.reset();
+}
+
+char TimeoutPrompt::prompt(int timeoutSeconds, char *promptString, char* validChars) {
+ _serialInOut.printf("%s\n", promptString);
+ _timer.reset();
+ _timer.start();
+ while (_timer.read() < timeoutSeconds) {
+ if (_serialInOut.readable()) {
+ char c = _serialInOut.getc();
+ if (strchr(validChars, c) != NULL) {
+ _timer.stop();
+ return c;
+ }
+ }
+ }
+ _timer.stop();
+ return NULL;
+}
+
+char TimeoutPrompt::prompt(char *promptString, char* validChars) {
+ return prompt(_defaultTimeoutSeconds, promptString, validChars);
+}
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/TimeoutPrompt/TimeoutPrompt.h Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,30 @@
+#ifndef TIMEOUTPROMPT_H_INCLUDED
+#define TIMEOUTPROMPT_H_INCLUDED
+
+#include "mbed.h"
+
+class TimeoutPrompt {
+public:
+
+ TimeoutPrompt(Serial & serialInOut, int defaultTimeoutSeconds);
+
+ /**
+ * Output the given prompt for timeoutSeconds. If a character is input that matches
+ * one of the validChars, then return it. Otherwise, if no valid character is
+ * pressed within the timeout, then return NULL.
+ */
+ char prompt(int timeoutSeconds, char *promptString, char* validChars);
+
+ /**
+ * Overloaded method that uses defaultTimeoutSeconds.
+ */
+ char prompt(char *promptString, char* validChars);
+
+private:
+
+ Serial & _serialInOut;
+ int _defaultTimeoutSeconds;
+ Timer _timer;
+};
+
+#endif // TIMEOUTPROMPT_H_INCLUDED
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/XPlaneIO/XPlaneAnalogIn.cpp Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,85 @@
+#include "Scaler.h"
+#include "XPlaneAnalogIn.h"
+
+XPlaneAnalogIn::XPlaneAnalogIn(PinName pin, Scaler<float> scale1, Scaler<float> scale2, int msgIdx, int msgFloatIdx) :
+ _pin(pin), _scale1(scale1), _scale2(scale2), _xplaneDATAMsgIdx(msgIdx), _xplaneDATAMsgFloatIdx(msgFloatIdx),
+ _ain(pin)
+{
+ _lastUnscaledRead = -1.0;
+ _lastScaledRead = -999.0;
+ _lastScaleRange = -1;
+}
+
+float XPlaneAnalogIn::read_unscaled() {
+ _lastUnscaledRead = _ain.read();
+ return _lastUnscaledRead;
+}
+
+float XPlaneAnalogIn::read_scaled(int & range, bool & scaledOutputNoChange) {
+ float scaledOutput;
+ float rawInput = read_unscaled();
+
+ if (rawInput > _scale1.inputTo() && rawInput < _scale2.inputFrom()) {
+ range = 0;
+ scaledOutput = (_scale1.outputTo() + _scale2.outputFrom()) / 2.0f;
+ }
+ else if (rawInput <= _scale1.inputTo()) {
+ if (rawInput < _scale1.inputFrom()) {
+ range = 3;
+ scaledOutput = _scale1.outputFrom();
+ }
+ else {
+ range = 1;
+ scaledOutput = _scale1.scale(rawInput);
+ }
+ }
+ else { // rawInput >= _scale2.inputFrom
+ if (rawInput > _scale2.inputTo()) {
+ range = 4;
+ scaledOutput = _scale2.outputTo();
+ }
+ else {
+ range = 2;
+ scaledOutput = _scale2.scale(rawInput);
+ }
+ }
+
+ scaledOutputNoChange = ((scaledOutput == _lastScaledRead) ||
+ (range == _lastScaleRange && (range == 0 || range == 3 || range == 4)));
+
+ _lastScaledRead = scaledOutput;
+ _lastScaleRange = range;
+
+ return scaledOutput;
+}
+
+/*
+void XPlaneAnalogIn::scale1(Scaler<float> scale1) {
+ _scale1 = scale1;
+}
+
+void XPlaneAnalogIn::scale2(Scaler<float> scale2) {
+ _scale2 = scale2;
+}
+
+void XPlaneAnalogIn::xplaneDATAMsgIdx(int xplaneDATAMsgIdx) {
+ _xplaneDATAMsgIdx = xplaneDATAMsgIdx;
+}
+
+void XPlaneAnalogIn::xplaneDATAMsgFloatIdx(int xplaneDATAMsgFloatIdx) {
+ _xplaneDATAMsgFloatIdx = xplaneDATAMsgFloatIdx;
+}
+*/
+
+int XPlaneAnalogIn::xplaneDATAMsgIdx() {
+ return _xplaneDATAMsgIdx;
+}
+
+int XPlaneAnalogIn::xplaneDATAMsgFloatIdx() {
+ return _xplaneDATAMsgFloatIdx;
+}
+
+void XPlaneAnalogIn::toString(FILE * outputStream) {
+ fprintf(outputStream, "lastRawRead=%f lastScaledRead=%f lastScaleRange=%d",
+ _lastUnscaledRead, _lastScaledRead, _lastScaleRange);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/XPlaneIO/XPlaneAnalogIn.h Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,65 @@
+#ifndef XPLANEANALOGIN_H_INCLUDED
+#define XPLANEANALOGIN_H_INCLUDED
+
+#include "mbed.h"
+#include "Scaler.h"
+#include "XPlaneUdpDATA.h"
+
+class XPlaneAnalogIn {
+public:
+
+ XPlaneAnalogIn(PinName pin, Scaler<float> scale1, Scaler<float> scale2, int msgIdx, int msgFloatIdx);
+
+ /**
+ * Perform a read() on the AnalogIn pin, and return that value.
+ */
+ float read_unscaled();
+
+ /**
+ * Perform a read() on the AnalogIn pin, and return the value scaled by the scale1 and scale2 ranges.
+ * The range used for the scaling is returned via the reference parameter:
+ * 0 = input fell in between the ranges (i.e. deadband zone), so scaled output is midpoint between scale1 outputTo and scale2 outputFrom
+ * 1 = input fell in the scale1 range
+ * 2 = input fell in the scale2 range
+ * 3 = input was less than scale1 inputFrom, so scaled output is (bounded by) scale1 outputFrom
+ * 4 = input was greater than scale2 inputTo, so scaled output is (bounded by) scale2 outputTo
+ * The scaledOutputNoChange reference parameter will be set true if the scaled value didn't changed since the last read.
+ */
+ float read_scaled(int & range, bool & scaledOutputNoChange);
+
+
+ // Property accessors and mutators
+
+ //Scaler<float> scale1();
+ //void scale1(Scaler<float> scale1);
+
+ //Scaler<float> scale2();
+ //void scale2(Scaler<float> scale2);
+
+ int xplaneDATAMsgIdx();
+ //void xplaneDATAMsgIdx(int xplaneDATAMsgIdx);
+
+ int xplaneDATAMsgFloatIdx();
+ //void xplaneDATAMsgFloatIdx(int xplaneDATAMsgFloatIdx);
+
+ /**
+ * Print a representation of this instance to outputStream.
+ */
+ void toString(FILE * outputStream);
+
+private:
+
+ PinName _pin;
+ Scaler<float> _scale1;
+ Scaler<float> _scale2;
+ int _xplaneDATAMsgIdx;
+ int _xplaneDATAMsgFloatIdx;
+
+ AnalogIn _ain;
+
+ float _lastUnscaledRead;
+ float _lastScaledRead;
+ int _lastScaleRange;
+};
+
+#endif // XPLANEANALOGIN_H_INCLUDED
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/XPlaneIO/XPlaneIO.cpp Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,300 @@
+#include "EthernetNetIf.h"
+#include "UDPSocket.h"
+#include "LocalConfigFile.h"
+#include "Scaler.h"
+#include "XPlaneUdp.h"
+#include "XPlaneUdpDATA.h"
+#include "XPlaneUdpDecoder.h"
+#include "XPlaneUdpEncoder.h"
+#include "XPlaneIO.h"
+
+XPlaneIO::~XPlaneIO() {
+ if (_eth != NULL) {
+ free(_eth);
+ _eth = NULL;
+ }
+
+ for (int i = 0; i < _xpAnalogInCount; i++) {
+ if (_xpAnalogIn[i] != NULL) {
+ free(_xpAnalogIn[i]);
+ }
+ }
+
+ for (XPlaneUdpDATAMap::iterator it = _recvDATAMap.begin(); it != _recvDATAMap.end(); it++) {
+ if ((it->second) != NULL) {
+ free(it->second);
+ }
+ }
+ _recvDATAMap.clear();
+
+}
+
+bool XPlaneIO::setup(char * configFilename, Ethernet * ethernet) {
+
+ printf("X-Plane I/O ... initializing \n");
+
+ bool returnStatus = true;
+
+ LocalConfigFile cfg(configFilename);
+
+ _debug = cfg.getBool("debug", false);
+ printf("debug: %d \n", _debug);
+
+ _debugVerbose = cfg.getBool("debugVerbose", false);
+ printf("debugVerbose: %d \n", _debugVerbose);
+
+ IpAddr ipAddr;
+ int intIp[4];
+
+ bool dhcp = true;
+ if (cfg.fillIntArray4("mbed_ip_address", intIp)) {
+ ipAddr = IpAddr(intIp[0], intIp[1], intIp[2], intIp[3]);
+ // Continue gathering IP configuration.
+ if (cfg.fillIntArray4("mbed_ip_netmask", intIp)) {
+ IpAddr ipMask = IpAddr(intIp[0], intIp[1], intIp[2], intIp[3]);
+ if (cfg.fillIntArray4("mbed_ip_gateway", intIp)) {
+ IpAddr ipGtwy = IpAddr(intIp[0], intIp[1], intIp[2], intIp[3]);
+ if (cfg.fillIntArray4("mbed_ip_dnssrvr", intIp)) {
+ IpAddr ipDns = IpAddr(intIp[0], intIp[1], intIp[2], intIp[3]);
+
+ _eth = new EthernetNetIf(ipAddr, ipMask, ipGtwy, ipDns);
+ dhcp = false;
+ }
+ }
+ }
+ }
+ if (dhcp) {
+ if (_debug) printf("mbed_ip_* address config not found or invalid, so defaulting to DHCP \n");
+ _eth = new EthernetNetIf;
+ }
+
+ // Set up the mbed ethernet interface.
+ EthernetErr ethErr = _eth->setup();
+ if (ethErr != ETH_OK) {
+ printf("Ethernet setup failed (error = %d) \n", ethErr);
+ returnStatus = false;
+ }
+
+ if (_debug) {
+ ipAddr = _eth->getIp();
+ printf("mbed IP address is %d.%d.%d.%d \n", ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3]);
+ }
+
+ const Ethernet::Mode linkModes[] = {Ethernet::AutoNegotiate, Ethernet::HalfDuplex10, Ethernet::FullDuplex10, Ethernet::HalfDuplex100, Ethernet::FullDuplex100};
+ int linkMode = cfg.getInt("ethernet_link_mode", 0);
+ ethernet->set_link(linkModes[linkMode]);
+ if (_debug) printf("ethernet_link_mode set to %d \n", linkMode);
+
+ if (_debug) printf("Setting recvHost and sendHost \n");
+ _recvHost.setIp(ipAddr);
+ _recvHost.setPort(cfg.getInt("recv_port", 49000));
+ if (cfg.fillIntArray4("xplane_ip_address", intIp)) {
+ _sendHost.setIp(IpAddr(intIp[0], intIp[1], intIp[2], intIp[3]));
+ }
+ _sendHost.setPort(cfg.getInt("xplane_ip_port", 49000));
+
+ if (_debug) printf("Setting event callback handler \n");
+ _udpSocket.setOnEvent(this, &XPlaneIO::onUDPSocketEvent);
+
+ if (_debug) printf("Binding to recvHost \n");
+ UDPSocketErr udpErr = _udpSocket.bind(_recvHost);
+ if (udpErr != UDPSOCKET_OK) {
+ printf("Failure in binding to recvHost (error = %d) \n", udpErr);
+ returnStatus = false;
+ }
+
+ _sendInterval = cfg.getInt("send_interval", 200);
+ printf("send_interval: %d ms \n", _sendInterval);
+
+ _reverseByteOrder = cfg.getBool("reverse_byte_order", false);
+ printf("reverse_byte_order: %d \n", _reverseByteOrder);
+
+ char key[33];
+ float f4[4];
+
+ // Scan for Analog Inputs (up to 6).
+ _xpAnalogInCount = 0;
+ for (int a = 1; a <= 6; a++) {
+ sprintf(key, "ain_%d_pin", a);
+ PinName pin = cfg.getPin(key, NC);
+ if (pin != NC) {
+ sprintf(key, "ain_%d_scale1", a);
+ if (cfg.fillFloatArray4(key, f4)) {
+ Scaler<float> scale1(f4[0], f4[1], f4[2], f4[3]);
+ sprintf(key, "ain_%d_scale2", a);
+ if (cfg.fillFloatArray4(key, f4)) {
+ Scaler<float> scale2(f4[0], f4[1], f4[2], f4[3]);
+ sprintf(key, "ain_%d_msg_idx", a);
+ int msgIdx = cfg.getInt(key, -1);
+ if (msgIdx >= 0) {
+ sprintf(key, "ain_%d_float_idx", a);
+ int floatIdx = cfg.getInt(key, -1);
+ if (floatIdx >= 0) {
+ // found all valid config items
+ printf("Setting Analog Input # %d \n", a);
+ _xpAnalogIn[_xpAnalogInCount] = new XPlaneAnalogIn(pin, scale1, scale2, msgIdx, floatIdx);
+ _xpAnalogInCount++;
+
+ addDATAToSend(msgIdx);
+ }
+ }
+ }
+ }
+ }
+ }
+ for (int i = _xpAnalogInCount; i < 6; i++) {
+ _xpAnalogIn[i] = NULL;
+ }
+
+ _udpDecoder.setDebug(_debugVerbose);
+ _udpDecoder.setReverseByteOrder(_reverseByteOrder);
+
+ _udpEncoder.setDebug(_debugVerbose);
+
+ return returnStatus;
+}
+
+
+bool XPlaneIO::addDATAToReceive(int msgIndex) {
+ return addXPlaneUdpDATAToMap(_recvDATAMap, msgIndex, _reverseByteOrder);
+}
+
+bool XPlaneIO::addDATAToSend(int msgIndex) {
+ return addXPlaneUdpDATAToMap(_sendDATAMap, msgIndex, _reverseByteOrder);
+}
+
+XPlaneUdpDATA * XPlaneIO::getReceiveDATA(int msgIndex) const {
+ return getXPlaneUdpDATA(_recvDATAMap, msgIndex);
+}
+
+XPlaneUdpDATA * XPlaneIO::getSendDATA(int msgIndex) const {
+ return getXPlaneUdpDATA(_sendDATAMap, msgIndex);
+}
+
+float XPlaneIO::getReceiveDATAValue(int msgIndex, int floatIndex) const {
+ XPlaneUdpDATA *DATAmsg = getReceiveDATA(msgIndex);
+ if (DATAmsg != NULL) {
+ return DATAmsg->getData(floatIndex);
+ }
+ else {
+ return -999.999f;
+ }
+}
+
+void XPlaneIO::setSendDATAValue(int msgIndex, int floatIndex, float f) {
+ XPlaneUdpDATA *DATAmsg = getSendDATA(msgIndex);
+ if (DATAmsg != NULL) {
+ DATAmsg->setData(floatIndex, f);
+ }
+}
+
+
+void XPlaneIO::pollAnalogIn() {
+ int scaleRange;
+ bool noChange;
+ for (int i = 0; i < _xpAnalogInCount; i++) {
+ XPlaneAnalogIn * xpAIn = _xpAnalogIn[i];
+ float aout = xpAIn->read_scaled(scaleRange, noChange);
+ if (! noChange) {
+ setSendDATAValue(xpAIn->xplaneDATAMsgIdx(), xpAIn->xplaneDATAMsgFloatIdx(), aout);
+ }
+ }
+}
+
+
+void XPlaneIO::sendDREF(XPlaneUdpDREF & dref) {
+ _sendDREFQueue.push(dref);
+}
+
+
+void XPlaneIO::startSendingUdp() {
+ _sendTicker.attach_us(this, &XPlaneIO::sendUdp, _sendInterval * 1000);
+}
+
+void XPlaneIO::stopSendingUdp() {
+ _sendTicker.detach();
+}
+
+void XPlaneIO::sendUdp() {
+ if (_debugVerbose) printf("sendUdp() called \n");
+
+ pollAnalogIn();
+
+ int len = _udpEncoder.encodeFromDATAMap(_udpSendBuffer, UDP_SEND_BUFFER_SIZE, _sendDATAMap, true);
+ if (len > 5) {
+ udpSocketSend(_udpSendBuffer, len);
+ resetDataChangedInMap(_sendDATAMap);
+ }
+
+ while (_sendDREFQueue.size() > 0) {
+ len = _udpEncoder.encodeDataRef(_udpSendBuffer, UDP_SEND_BUFFER_SIZE, _sendDREFQueue.front());
+ if (len > 0) {
+ udpSocketSend(_udpSendBuffer, len);
+ }
+ _sendDREFQueue.pop();
+ }
+}
+
+
+/**
+ * Callback handler for received UDP data.
+ */
+void XPlaneIO::onUDPSocketEvent(UDPSocketEvent e) {
+ if (_debugVerbose) printf("onUDPSocketEvent() called \n");
+
+ if (e == UDPSOCKET_READABLE) {
+ if (_debugVerbose) printf("onUDPSocketEvent() : event=UDPSOCKET_READABLE \n");
+
+ Host host;
+ while (int len = _udpSocket.recvfrom(_udpRecvBuffer, UDP_RECV_BUFFER_SIZE, &host)) {
+ if (len <= 0) {
+ break;
+ }
+
+ if (_debugVerbose) {
+ IpAddr hostIp = host.getIp();
+ //printf("From %d.%d.%d.%d: len=%d: %s\n", hostIp[0], hostIp[1], hostIp[2], hostIp[3], len, buf);
+ printf("From %d.%d.%d.%d: len=%d \n", hostIp[0], hostIp[1], hostIp[2], hostIp[3], len);
+ }
+
+ XPlaneUdpMessageType pktMsgType = _udpDecoder.setUdpBuffer(_udpRecvBuffer, len);
+ if (pktMsgType == DATA) {
+ _udpDecoder.putIntoDATAMap(_recvDATAMap, true);
+ }
+ }
+ }
+}
+
+
+int XPlaneIO::udpSocketSend(char * buf, int len) {
+ if (_debugVerbose) printf("udpSocketSend(): sending %d bytes \n", len);
+
+ int nSent = _udpSocket.sendto(buf, len, &_sendHost);
+
+ if ( nSent < 0 ) {
+ if (_debug) printf("PROBLEM SENDING UDP DATA (error = %d) \n", (UDPSocketErr)nSent);
+ }
+ else if ( nSent != len ) {
+ if (_debug) printf("WARNING: %d bytes were sent \n", nSent);
+ }
+
+ return nSent;
+}
+
+
+
+bool XPlaneIO::debug() const {
+ return _debug;
+}
+
+bool XPlaneIO::reverseByteOrder() const {
+ return _reverseByteOrder;
+}
+
+XPlaneUdpDATAMap & XPlaneIO::recvDATAMap() {
+ return _recvDATAMap;
+}
+
+XPlaneUdpDATAMap & XPlaneIO::sendDATAMap() {
+ return _sendDATAMap;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/XPlaneIO/XPlaneIO.h Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,223 @@
+#ifndef XPLANEIO_H_INCLUDED
+#define XPLANEIO_H_INCLUDED
+
+#include <queue>
+#include "mbed.h"
+#include "EthernetNetIf.h"
+#include "UDPSocket.h"
+#include "XPlaneUdpDATA.h"
+#include "XPlaneUdpDecoder.h"
+#include "XPlaneUdpEncoder.h"
+#include "XPlaneAnalogIn.h"
+
+#define UDP_RECV_BUFFER_SIZE 512
+#define UDP_SEND_BUFFER_SIZE 512
+
+/**
+ * XPlaneIO is used to establish networked communication with X-Plane.
+ * Methods in this class allow the the client to send data to X-Plane as well as
+ * read data that has been sent from X-Plane.
+ */
+
+class XPlaneIO {
+public:
+
+ //XPlaneIO();
+ ~XPlaneIO();
+
+ /**
+ * Read configuration file and initialize.
+ */
+ bool setup(char * configFilename, Ethernet * ethernet);
+
+ /**
+ * Check if user wants to perform interactive XPlaneIO diagnostics. If so, enter diagnostics mode.
+ */
+ void diagnostics(Serial & serialInOut);
+
+ /**
+ * Include a DATA message, of the given index, in the UDP map -- for receiving from X-Plane.
+ * If a message of the given index already exists in the map, then do nothing.
+ * Returns true if a new DATA message was created and added to the map.
+ */
+ bool addDATAToReceive(int msgIndex);
+
+ /**
+ * Include a DATA message, of the given index, in the UDP map -- for sending to X-Plane.
+ * If a message of the given index already exists in the map, then do nothing.
+ * Returns true if a new DATA message was created and added to the map.
+ */
+ bool addDATAToSend(int msgIndex);
+
+ /**
+ * Return a pointer to the DATA message, of the given index, in the UDP receive map (data received from X-Plane).
+ * If a message of the given index does not exist in the map, then return NULL.
+ */
+ XPlaneUdpDATA * getReceiveDATA(int msgIndex) const;
+
+ /**
+ * Return a pointer to the DATA message, of the given index, in the UDP send map (data to send to X-Plane).
+ * If a message of the given index does not exist in the map, then return NULL.
+ */
+ XPlaneUdpDATA * getSendDATA(int msgIndex) const;
+
+ /**
+ * Return the float data value, of the given DATA message index, at the given float index (0-7), in the UDP receive map (data received from X-Plane).
+ * If a message of the given index does not exist in the map, then return -999.999f.
+ */
+ float getReceiveDATAValue(int msgIndex, int floatIndex) const;
+
+ /**
+ * Set the float data value, of the given DATA message index, at the given float index (0-7), in the UDP send map (data to send to X-Plane).
+ * If a message of the given index does not exist in the map, then do nothing.
+ */
+ void setSendDATAValue(int msgIndex, int floatIndex, float f);
+
+ /**
+ * Add an X-Plane DataRef to the queue -- to be sent the next time the
+ * sendUdp() ticker function is called.
+ */
+ void sendDREF(XPlaneUdpDREF & dref);
+
+ /**
+ * Start sending UDP data to X-Plane.
+ */
+ void startSendingUdp();
+
+ /**
+ * Stop sending UDP data to X-Plane.
+ */
+ void stopSendingUdp();
+
+ /**
+ * Utility method to send data via the UDPSocket to the sendHost.
+ */
+ int udpSocketSend(char * buf, int len);
+
+ // Accessors
+ bool debug() const;
+ bool reverseByteOrder() const;
+ XPlaneUdpDATAMap & recvDATAMap();
+ XPlaneUdpDATAMap & sendDATAMap();
+
+private:
+
+ bool _debug;
+ bool _debugVerbose;
+
+ //Serial & _serialInOut;
+
+ EthernetNetIf * _eth; // pointer, because don't want instantiated until gather config for it
+
+ // Set up local and remote hosts.
+ Host _recvHost; // mbed local host
+ Host _sendHost; // IP address and port to which UDP will be sent
+
+ // UDP socket to use for both binding to local address (to recv data) and to send data to remote host.
+ UDPSocket _udpSocket;
+
+ int _sendInterval; // milliseconds
+ Ticker _sendTicker;
+
+ bool _reverseByteOrder;
+
+ XPlaneUdpDATAMap _recvDATAMap; // keyed by DATA message index
+ XPlaneUdpDATAMap _sendDATAMap; // keyed by DATA message index
+
+ queue<XPlaneUdpDREF> _sendDREFQueue;
+
+ char _udpRecvBuffer[UDP_RECV_BUFFER_SIZE];
+ XPlaneUdpDecoder _udpDecoder;
+
+ char _udpSendBuffer[UDP_SEND_BUFFER_SIZE];
+ XPlaneUdpEncoder _udpEncoder;
+
+ XPlaneAnalogIn * _xpAnalogIn[6];
+ int _xpAnalogInCount;
+
+ /**
+ * Callback handler for when UDP data has been received.
+ * Note that this handler is assigned within the setup() method.
+ */
+ void onUDPSocketEvent(UDPSocketEvent e);
+
+ /**
+ * Ticker function for sending UDP data.
+ */
+ void sendUdp();
+
+ /**
+ * Poll analog inputs, and...
+ */
+ void pollAnalogIn();
+};
+
+#endif // XPLANEIO_H_INCLUDED
+
+
+
+/* Config file:
+
+debug=Y
+debugVerbose=N
+
+# If mbed_ip_address is not specified, then DHCP will be used.
+mbed_ip_address=192 168 10 202
+mbed_ip_netmask=255 255 255 0
+mbed_ip_gateway=192 168 10 99
+mbed_ip_dnssrvr=192 168 10 99
+
+# Ethernet link mode: 0 = AutoNegotiate, 1 = HalfDuplex10, 2 = FullDuplex10, 3 = HalfDuplex100, 4 = FullDuplex100
+# Note that AutoNegotiate does not work for 10 Mbit hub. e.g. Use 2 (FullDuplex10) for 10 Mbit hub that does not auto-detect speed.
+ethernet_link_mode=0
+
+# Local IP port to bind to. X-Plane should be configured to send data to the mbed_ip_address and this port.
+recv_port=49000
+
+# IP address and port to which UDP data will be sent.
+xplane_ip_address=192 168 10 106
+xplane_ip_port=49000
+
+# Interval (milliseconds) for sending UDP data to X-Plane.
+send_interval=250
+
+# Depending on X-Plane host computer (e.g Mac), byte order in UDP packets may need to be reversed.
+reverse_byte_order=N
+
+# Analog Inputs - for sending an analog value to X-Plane. Up to six are supported (# = 1-6).
+# ain_#_pin : AnalogIn pin number, 15-20 (p15-20)
+# ain_#_scale1 : Scale range 1: input_from input_to output_from output_to
+# Note: A gap between range1's input_to and range2's input_from will be seen as deadband; no data will be sent to X-Plane in that case.
+# ain_#_scale2 : Scale range 2: input_from input_to output_from output_to
+# ain_#_msg_idx : X-Plane DATA message: message index
+# ain_#_float_idx : X-Plane DATA message: float index (0-7) within the message
+
+# Analog Input #1:
+ain_1_pin=20
+ain_1_scale1=0.525 0.610 1.0 0.0
+ain_1_scale2=0.615 0.910 0.0 -1.0
+ain_1_msg_idx=8
+ain_1_float_idx=1
+
+# Analog Input #2:
+ain_2_pin=19
+ain_2_scale1=0.520 0.605 1.0 0.0
+ain_2_scale2=0.615 0.920 0.0 -1.0
+ain_2_msg_idx=8
+ain_2_float_idx=0
+
+# Analog Input #3:
+ain_3_pin=17
+ain_3_scale1=0.510 0.615 1.0 0.0
+ain_3_scale2=0.620 0.915 0.0 -1.0
+ain_3_msg_idx=8
+ain_3_float_idx=2
+
+
+# X-Plane DATA
+# MsgIdx 8 : 0=elev, 1=ailrn, 2=ruddr
+# MsgIdx 13 : 0=elev trim, 1=ailrn trim, 2=ruddr trim, 3=flap handl, 4=flap postn, 5=slat ratio, 6=sbrak handl, 7=sbrak postn
+# MsgIdx 25 : 0=throttle command
+# MsgIdx 26 : 0=throttle actual
+
+*/
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/XPlaneIO/XPlaneIO_diag.cpp Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,43 @@
+#include "XPlaneIO.h"
+#include "TimeoutPrompt.h"
+
+void XPlaneIO::diagnostics(Serial & serialInOut) {
+
+ TimeoutPrompt top(serialInOut, 2);
+
+ if (top.prompt("\nPress 'd' within 2 seconds for interactive diagnostics", "Dd") == NULL) {
+ return;
+ }
+
+ char c;
+
+ while ((c = top.prompt(30, "\n 1. Analog Input \n 2. \n 3. \n q. Quit \n Select within 30 seconds", "123Qq")) != NULL
+ && c != 'q' && c != 'Q')
+ {
+ serialInOut.printf("%c was typed \n\n", c);
+
+ switch (c) {
+ case '1':
+ for (int i = 0; i < _xpAnalogInCount; i++) {
+ pollAnalogIn();
+ serialInOut.printf("Analog Input #%d: ", i + 1);
+ _xpAnalogIn[i]->toString(serialInOut);
+ serialInOut.printf("\n");
+ }
+ break;
+ /*
+ case '2':
+ break;
+ case '3':
+ break;
+ case 'a':
+ case 'A':
+ break;
+ */
+ default:
+ serialInOut.printf("%c is not an option \n");
+ }
+ }
+
+ serialInOut.printf("Done \n");
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/XPlaneUdp/XPlaneUdp.h Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,14 @@
+#ifndef XPLANEUDP_H_INCLUDED
+#define XPLANEUDP_H_INCLUDED
+
+enum XPlaneUdpMessageType {
+ DATA,
+ UNKNOWN
+};
+
+/**
+ * Utility function to reverse the order of the four bytes at the given location.
+ */
+void reverse4Bytes(char* bytes);
+
+#endif // XPLANEUDP_H_INCLUDED
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/XPlaneUdp/XPlaneUdpDATA.cpp Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,71 @@
+#include "XPlaneUdpDATA.h"
+
+
+XPlaneUdpDATA::XPlaneUdpDATA(int messageIndex, bool reverseByteOrder) {
+
+ _messageIndex = messageIndex;
+ _reverseByteOrder = reverseByteOrder;
+ for (int i = 0; i < 8; i++) {
+ _data[i] = -999.0f;
+ }
+
+ _dataChanged = false;
+}
+
+int XPlaneUdpDATA::messageIndex() const {
+ return _messageIndex;
+}
+
+float XPlaneUdpDATA::getData(int i) const {
+ return _data[i];
+}
+
+void XPlaneUdpDATA::setData(int i, float f) {
+ _data[i] = f;
+ setDataChanged();
+}
+
+float& XPlaneUdpDATA::operator [] (int i) {
+ return _data[i];
+}
+
+void XPlaneUdpDATA::setAllData(char * DATAMessage) {
+ memcpy(_data, DATAMessage + 4, 32);
+ if (_reverseByteOrder) {
+ for (int d = 0; d < 8; d++) {
+ reverse4Bytes((char*) &(_data[d]));
+ }
+ }
+}
+
+void XPlaneUdpDATA::populateDATAMessage(char * bytes) {
+ memcpy(bytes, &_messageIndex, 4);
+ if (_reverseByteOrder) {
+ reverse4Bytes((char*) bytes);
+ }
+ memcpy(bytes + 4, _data, 32);
+ if (_reverseByteOrder) {
+ for (int d = 1; d < 9; d++) {
+ reverse4Bytes((char*) bytes + (d * 4));
+ }
+ }
+}
+
+bool XPlaneUdpDATA::isDataChanged() const {
+ return _dataChanged;
+}
+
+void XPlaneUdpDATA::setDataChanged() {
+ _dataChanged = true;
+}
+
+void XPlaneUdpDATA::resetDataChanged() {
+ _dataChanged = false;
+}
+
+void XPlaneUdpDATA::toString(FILE * outputStream) {
+ fprintf(outputStream, "idx=%d, 0:%f 1:%f 2:%f 3:%f 4:%f 5:%f 6:%f 7:%f, revBytes=%d",
+ _messageIndex,
+ _data[0], _data[1], _data[2], _data[3], _data[4], _data[5], _data[6], _data[7],
+ _reverseByteOrder);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/XPlaneUdp/XPlaneUdpDATA.h Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,68 @@
+#ifndef XPLANEUDPDATA_H_INCLUDED
+#define XPLANEUDPDATA_H_INCLUDED
+
+#include <map>
+#include "mbed.h"
+#include "XPlaneUdp.h"
+
+#define XPLANE_DATA_MSG_LENGTH 36 // 1 int + 8 floats
+
+class XPlaneUdpDATA {
+public:
+
+ XPlaneUdpDATA(int messageIndex, bool reverseByteOrder);
+
+ /**
+ * Accessor for the message index of this DATA message.
+ */
+ int messageIndex() const;
+
+ /**
+ * Accessor for the float data at the given float index (0-7).
+ */
+ float getData(int i) const;
+
+ /**
+ * Mutator for the float data at the given float index (0-7).
+ * The dataChanged flag will also be set.
+ */
+ void setData(int i, float f);
+
+ /**
+ * Overload the [] operator to return a reference to the float data at the given float index (0-7).
+ * NOTE: The dataChanged flag will not be set if this is used to modify the float data.
+ */
+ float& operator [] (int i);
+
+ /**
+ * Fill data[8] with 32 bytes starting at (DATAMessage + 4).
+ * Byte order will be reversed, according to the reverseByteOrder property.
+ */
+ void setAllData(char * DATAMessage);
+
+ /**
+ * Starting at the given pointer location, populate 36 bytes from values in index and data[8].
+ * Byte order will be reversed, according to the reverseByteOrder property.
+ */
+ void populateDATAMessage(char * bytes);
+
+ // Methods to read/write flag to track if data has been modified.
+ bool isDataChanged() const;
+ void setDataChanged();
+ void resetDataChanged();
+
+ /**
+ * Print a representation of this instance to outputStream.
+ */
+ void toString(FILE * outputStream);
+
+private:
+
+ int _messageIndex;
+ float _data[8];
+ bool _reverseByteOrder;
+ bool _dataChanged;
+};
+
+
+#endif // XPLANEUDPDATA_H_INCLUDED
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/XPlaneUdp/XPlaneUdpDATAMap.cpp Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,39 @@
+#include "XPlaneUdpDATAMap.h"
+
+XPlaneUdpDATA * getXPlaneUdpDATA(const XPlaneUdpDATAMap & DATAMap, int index) {
+ XPlaneUdpDATAMap::iterator iter = DATAMap.find(index);
+ if (iter != DATAMap.end()) {
+ return iter->second;
+ }
+ else {
+ return NULL;
+ }
+}
+
+bool addXPlaneUdpDATAToMap(XPlaneUdpDATAMap & DATAMap, int index, bool reverseByteOrder) {
+ XPlaneUdpDATA *DATAmsg = getXPlaneUdpDATA(DATAMap, index);
+ if (DATAmsg != NULL) {
+ return false;
+ }
+ else {
+ DATAmsg = new XPlaneUdpDATA(index, reverseByteOrder);
+ DATAMap[index] = DATAmsg;
+ return true;
+ }
+}
+
+void resetDataChangedInMap(XPlaneUdpDATAMap & DATAMap) {
+ for (XPlaneUdpDATAMap::iterator it = DATAMap.begin(); it != DATAMap.end(); it++) {
+ (it->second)->resetDataChanged();
+ }
+}
+
+void printXPlaneUdpDATAMap(FILE * outputStream, XPlaneUdpDATAMap & DATAMap) {
+ fprintf(outputStream, "Map:\n");
+ for (XPlaneUdpDATAMap::iterator it = DATAMap.begin(); it != DATAMap.end(); it++) {
+ //(it->second)->resetDataChanged();
+ fprintf(outputStream, " key: %d value: ", it->first);
+ (it->second)->toString(outputStream);
+ fprintf(outputStream, "\n");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/XPlaneUdp/XPlaneUdpDATAMap.h Wed Dec 21 22:29:59 2011 +0000 @@ -0,0 +1,35 @@ +#ifndef XPLANEUDPDATAMAP_H_INCLUDED +#define XPLANEUDPDATAMAP_H_INCLUDED + +#include <map> +#include "XPlaneUdpDATA.h" + +/** + * Map of XPlaneUdpDATA pointers, keyed by int (e.g. keyed by the DATA message index). + */ +typedef std::map<int, XPlaneUdpDATA *> XPlaneUdpDATAMap; + +/** + * Function to return the XPlaneUdpDATA pointer in the given map, keyed by the given int index. + * If no map entry exists for the given key index, then returns NULL. + */ +XPlaneUdpDATA * getXPlaneUdpDATA(const XPlaneUdpDATAMap & DATAMap, int index); + +/** + * Function to include a DATA message, of the given index, in the given map. + * If a message of the given index already exists in the map, then do nothing. + * Returns true if a new DATA message was created and added to the map. + */ +bool addXPlaneUdpDATAToMap(XPlaneUdpDATAMap & DATAMap, int index, bool reverseByteOrder); + +/** + * Function to reset the dataChanged flag in all DATA messages in the given map. + */ +void resetDataChangedInMap(XPlaneUdpDATAMap & DATAMap); + +/** + * Utility function to print the DATA messages in the given map. + */ +void printXPlaneUdpDATAMap(FILE * outputStream, XPlaneUdpDATAMap & DATAMap); + +#endif // XPLANEUDPDATAMAP_H_INCLUDED
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/XPlaneUdp/XPlaneUdpDREF.cpp Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,75 @@
+#include "XPlaneUdpDREF.h"
+
+
+XPlaneUdpDREF::XPlaneUdpDREF(char * drefName, bool reverseByteOrder) {
+
+ _drefName = drefName;
+ _reverseByteOrder = reverseByteOrder;
+
+ _dataChanged = false;
+ _drefFloat = DREF_VALUE_NA;
+ _drefInt = DREF_VALUE_NA;
+}
+
+
+char * XPlaneUdpDREF::drefName() const {
+ return _drefName;
+}
+
+float XPlaneUdpDREF::drefFloat() const {
+ return _drefFloat;
+}
+
+int XPlaneUdpDREF::drefInt() const {
+ return _drefInt;
+}
+
+void XPlaneUdpDREF::drefFloat(float floatVal) {
+ _drefFloat = floatVal;
+ _drefInt = DREF_VALUE_NA;
+ setDataChanged();
+}
+
+void XPlaneUdpDREF::drefInt(int intVal) {
+ _drefInt = intVal;
+ _drefFloat = DREF_VALUE_NA;
+ setDataChanged();
+}
+
+ /**
+ * Starting at the given pointer location, populate bytes from the dataRef value and name.
+ * Byte order will be reversed, according to the reverseBytes property.
+ */
+
+void XPlaneUdpDREF::populateDREFMessage(char * bytes) {
+
+ if (_drefInt != DREF_VALUE_NA) {
+ memcpy(bytes, &_drefInt, 4);
+ }
+ else {
+ memcpy(bytes, &_drefFloat, 4);
+ }
+
+ if (_reverseByteOrder) {
+ reverse4Bytes((char*) bytes);
+ }
+
+ strcpy(bytes + 4, _drefName);
+}
+
+bool XPlaneUdpDREF::isDataChanged() const {
+ return _dataChanged;
+}
+
+void XPlaneUdpDREF::setDataChanged() {
+ _dataChanged = true;
+}
+
+void XPlaneUdpDREF::resetDataChanged() {
+ _dataChanged = false;
+}
+
+void XPlaneUdpDREF::toString(FILE * outputStream) {
+ fprintf(outputStream, "DataRef: name=%s, intVal=%d, floatVal=%f, revBytes=%d",
+ _drefName, _drefInt, _drefFloat, _reverseByteOrder);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/XPlaneUdp/XPlaneUdpDREF.h Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,75 @@
+#ifndef XPLANEUDPDREF_H_INCLUDED
+#define XPLANEUDPDREF_H_INCLUDED
+
+#include <map>
+#include "mbed.h"
+#include "XPlaneUdp.h"
+
+#define DREF_VALUE_NA -999
+
+/**
+ * X-Plane DataRef
+ */
+class XPlaneUdpDREF {
+public:
+
+ XPlaneUdpDREF(char * drefName, bool reverseByteOrder);
+
+ /**
+ * Accessor for the DataRef name.
+ */
+ char * drefName() const;
+
+ /**
+ * Accessor for the DataRef float data value.
+ * Returns -999 if not applicable (this DataRef uses an int value).
+ */
+ float drefFloat() const;
+
+ /**
+ * Accessor for the DataRef int data value.
+ * Returns -999 if not applicable (this DataRef uses a float value).
+ */
+ int drefInt() const;
+
+ /**
+ * Mutator for the DataRef float data value.
+ * The DataRef int data will be set to -999.
+ * The dataChanged flag will also be set.
+ */
+ void drefFloat(float floatVal);
+
+ /**
+ * Mutator for the DataRef int data value.
+ * The DataRef float data will be set to -999.
+ * The dataChanged flag will also be set.
+ */
+ void drefInt(int intVal);
+
+ /**
+ * Starting at the given pointer location, populate bytes from the DataRef value and name.
+ * Byte order will be reversed, according to the reverseByteOrder property.
+ */
+ void populateDREFMessage(char * bytes);
+
+ // Methods to read/write flag to track if data has been modified.
+ bool isDataChanged() const;
+ void setDataChanged();
+ void resetDataChanged();
+
+ /**
+ * Print a representation of this instance to outputStream.
+ */
+ void toString(FILE * outputStream);
+
+private:
+
+ char * _drefName;
+ float _drefFloat;
+ int _drefInt;
+ bool _reverseByteOrder;
+ bool _dataChanged;
+};
+
+
+#endif // XPLANEUDPDREF_H_INCLUDED
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/XPlaneUdp/XPlaneUdpDecoder.cpp Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,69 @@
+#include <stdio.h>
+#include <string.h>
+#include "XPlaneUdp.h"
+#include "XPlaneUdpDecoder.h"
+#include "XPlaneUdpDATA.h"
+
+void XPlaneUdpDecoder::setDebug(bool debug) {
+ _debug = debug;
+}
+
+void XPlaneUdpDecoder::setReverseByteOrder(bool reverseByteOrder) {
+ _reverseByteOrder = reverseByteOrder;
+}
+
+XPlaneUdpMessageType XPlaneUdpDecoder::setUdpBuffer(char * buf, int bufLen) {
+ _udpPacketMsgType = UNKNOWN;
+ _udpBuffer = buf;
+ _udpBufferLen = bufLen;
+ //_udpBuffer[bufLen] = 0; // only need to do this if treating buffer like a string, e.g. printing it
+
+ if (_udpBufferLen >= 5) {
+ if (strncmp(_udpBuffer, "DATA", 4) == 0) {
+ if (_debug) printf("Got DATA pkt \n");
+ _udpPacketMsgType = DATA;
+ }
+ }
+
+ return _udpPacketMsgType;
+}
+
+int XPlaneUdpDecoder::putIntoDATAMap(XPlaneUdpDATAMap & DATAMap, bool filter) {
+ int updateCount = 0;
+
+ if (_udpPacketMsgType != DATA) {
+ return 0;
+ }
+
+ if (filter && (DATAMap.size() == 0)) {
+ return 0;
+ }
+
+ int dataMsgCount = (_udpBufferLen - 5) / XPLANE_DATA_MSG_LENGTH;
+ if (_debug) printf("%d msgs in pkt \n", dataMsgCount);
+ int bufOffset = 5;
+ for (int msgNbr = 0; msgNbr < dataMsgCount; msgNbr++) {
+
+ int index;
+ memcpy(&index, _udpBuffer + bufOffset, 4);
+ if (_reverseByteOrder) {
+ reverse4Bytes((char*) &index);
+ }
+
+ XPlaneUdpDATA *DATAmsg = getXPlaneUdpDATA(DATAMap, index);
+ if (DATAmsg != NULL) {
+ DATAmsg->setAllData(_udpBuffer + bufOffset);
+ updateCount++;
+ }
+ else if (! filter) {
+ DATAmsg = new XPlaneUdpDATA(index, _reverseByteOrder);
+ DATAmsg->setAllData(_udpBuffer + bufOffset);
+ DATAMap[index] = DATAmsg;
+ updateCount++;
+ }
+
+ bufOffset += XPLANE_DATA_MSG_LENGTH;
+ }
+
+ return updateCount;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/XPlaneUdp/XPlaneUdpDecoder.h Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,43 @@
+#ifndef XPLANEUDPDECODER_H_INCLUDED
+#define XPLANEUDPDECODER_H_INCLUDED
+
+#include "XPlaneUdp.h"
+#include "XPlaneUdpDATA.h"
+#include "XPlaneUdpDATAMap.h"
+
+class XPlaneUdpDecoder {
+public:
+
+ //XPlaneUdpDecoder();
+
+ void setDebug(bool debug);
+ void setReverseByteOrder(bool reverseByteOrder);
+
+ /**
+ * This must be called prior to other methods such as putIntoDATAMap().
+ * Point this decoder to the UDP data buffer, and read the first four bytes
+ * to determine the X-Plane UDP message type (e.g. DATA).
+ */
+ XPlaneUdpMessageType setUdpBuffer(char * buf, int bufLen);
+
+ /**
+ * Note: The setUdpBuffer() method must be called prior to calling this method.
+ * Decode the UDP packet. If it is a DATA packet from X-Plane, then populate
+ * XPlaneUdpDATA structure(s) in the map.
+ * If filter==true, then only existing structures in the map (keyed by message DATA msg index)
+ * will be populated, i.e. no new structures will be created in the map.
+ * Return the number of XPlaneUdpDATA structures populated/updated in the map.
+ */
+ int putIntoDATAMap(XPlaneUdpDATAMap & DATAMap, bool filter);
+
+private:
+
+ bool _debug;
+ bool _reverseByteOrder;
+ char *_udpBuffer;
+ int _udpBufferLen;
+ XPlaneUdpMessageType _udpPacketMsgType;
+};
+
+
+#endif // XPLANEUDPDECODER_H_INCLUDED
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/XPlaneUdp/XPlaneUdpEncoder.cpp Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,57 @@
+#include <stdio.h>
+#include <string.h>
+#include "XPlaneUdp.h"
+#include "XPlaneUdpEncoder.h"
+#include "XPlaneUdpDATA.h"
+
+void XPlaneUdpEncoder::setDebug(bool debug) {
+ _debug = debug;
+}
+
+int XPlaneUdpEncoder::encodeFromDATAMap(char * udpBuffer, int maxBufferLen, XPlaneUdpDATAMap & DATAMap, bool changedDataOnly) {
+ if (maxBufferLen < 5 || DATAMap.size() == 0) {
+ return 0;
+ }
+
+ strcpy(udpBuffer, "DATA");
+ int bufOffset = 5;
+
+ for (XPlaneUdpDATAMap::iterator it = DATAMap.begin(); it != DATAMap.end(); it++) {
+ if ((bufOffset + XPLANE_DATA_MSG_LENGTH) > maxBufferLen) {
+ break;
+ }
+ else {
+ XPlaneUdpDATA * DATAmsg = it->second;
+ if ((!changedDataOnly) || DATAmsg->isDataChanged()) {
+ DATAmsg->populateDATAMessage(udpBuffer + bufOffset);
+ bufOffset += XPLANE_DATA_MSG_LENGTH;
+ }
+ }
+ }
+
+ if (_debug) printf("encodeFromDATAMap(): Encoded %d bytes into UDP buffer \n", bufOffset);
+
+ return bufOffset;
+}
+
+
+int XPlaneUdpEncoder::encodeDataRef(char * udpBuffer, int maxBufferLen, XPlaneUdpDREF & dref) {
+ if (maxBufferLen < DATAREF_PACKET_SIZE) {
+ return 0;
+ }
+
+ memset(udpBuffer, '\0' , DATAREF_PACKET_SIZE); // zero out the buffer
+
+ strcpy(udpBuffer, "DREF");
+ int bufOffset = 5;
+
+ dref.populateDREFMessage(udpBuffer + bufOffset);
+
+ if (_debug) {
+ printf("encodeDataRef(): Encoded DREF packet into UDP buffer: ");
+ dref.toString(stdout);
+ printf("\n");
+ }
+
+ return DATAREF_PACKET_SIZE;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/XPlaneUdp/XPlaneUdpEncoder.h Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,41 @@
+#ifndef XPLANEUDPENCODER_H_INCLUDED
+#define XPLANEUDPENCODER_H_INCLUDED
+
+#include "XPlaneUdp.h"
+#include "XPlaneUdpDATA.h"
+#include "XPlaneUdpDATAMap.h"
+#include "XPlaneUdpDREF.h"
+
+#define DATAREF_PACKET_SIZE 509 // "DREF" + '\x00' + 4-byte_value + 500-char_name
+
+class XPlaneUdpEncoder {
+public:
+
+ //XPlaneUdpEncoder();
+
+ void setDebug(bool debug);
+
+ /**
+ * Encode a DATA packet from the messages in the given XPlaneUdpDATAMap.
+ * The encoded data will be placed at the location given by udpBuffer.
+ * If changedDataOnly is true, then only XPlaneUdpDATA messages with dataChanged will be encoded.
+ * Return number of bytes encoded into udpBuffer.
+ * Return -1 if there's more data in the map than what will fit in udpBuffer (> maxBufferLen).
+ */
+ int encodeFromDATAMap(char * udpBuffer, int maxBufferLen, XPlaneUdpDATAMap & DATAMap, bool changedDataOnly);
+
+ /**
+ * Encode a DataRef (DREF) packet, using the given DataRef.
+ * The encoded data will be placed at the location given by udpBuffer.
+ * Return number of bytes encoded into udpBuffer.
+ * Return -1 if there's more data in the map than what will fit in udpBuffer (> maxBufferLen).
+ */
+ int encodeDataRef(char * udpBuffer, int maxBufferLen, XPlaneUdpDREF & dref);
+
+private:
+
+ bool _debug;
+};
+
+
+#endif // XPLANEUDPENCODER_H_INCLUDED
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/XPlaneUdp/XPlaneUdp_util.cpp Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,11 @@
+
+void reverse4Bytes(char* bytes)
+{
+ char temp;
+ temp = bytes[0];
+ bytes[0] = bytes[3];
+ bytes[3] = temp;
+ temp = bytes[1];
+ bytes[1] = bytes[2];
+ bytes[2] = temp;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Wed Dec 21 22:29:59 2011 +0000
@@ -0,0 +1,74 @@
+#include "mbed.h"
+#include "EthernetNetIf.h"
+#include "Ranger.h"
+#include "XPlaneIO.h"
+
+Serial pc(USBTX, USBRX);
+
+int main() {
+
+ pc.baud(57600);
+
+ Ethernet ethernet;
+
+ XPlaneIO xpio;
+ if (! xpio.setup("XPlaneIO.cfg", ðernet)) {
+ printf("Config/setup failed \n");
+ return -1;
+ }
+
+ // Check if user wants to perform interactive XPlaneIO diagnostics.
+ xpio.diagnostics(pc);
+
+ AnalogOut throttleActual(p18);
+ xpio.addDATAToReceive(26); // "throttle actual" in msg 26, data[0]
+
+ AnalogIn hatSwitch(p16);
+ XPlaneUdpDREF pilotHeadHeading("sim/graphics/view/pilots_head_psi", xpio.reverseByteOrder());
+ Ranger<float> hatSwitchInputRanger(4, 0.59, 0.68, 0.78, 0.92);
+ float hatSwitchDegreesByRange[5] = {0, -90, 180, 90, 0};
+
+ Timer timerThrottle;
+ timerThrottle.start();
+
+ Timer timerHatSwitch;
+ timerHatSwitch.start();
+
+ Timer timerDebugPrint;
+ if (xpio.debug()) {
+ timerDebugPrint.start();
+ }
+
+ xpio.startSendingUdp();
+
+ while (1) {
+ Net::poll();
+
+ if (timerThrottle.read_ms() > 500) {
+ timerThrottle.reset();
+
+ throttleActual.write(xpio.getReceiveDATAValue(26, 0)); // throttle actual
+ }
+
+ if (timerHatSwitch.read_ms() > 250) {
+ timerHatSwitch.reset();
+
+ int newRange = hatSwitchInputRanger.range(hatSwitch.read());
+ if (hatSwitchInputRanger.rangeChanged()) {
+ pilotHeadHeading.drefFloat(hatSwitchDegreesByRange[newRange]);
+ xpio.sendDREF(pilotHeadHeading);
+ }
+ }
+
+ if (xpio.debug()) {
+ if (timerDebugPrint.read() > 2) {
+ timerDebugPrint.reset();
+
+ printf("Receive ");
+ printXPlaneUdpDATAMap(stdout, xpio.recvDATAMap());
+ printf("Send ");
+ printXPlaneUdpDATAMap(stdout, xpio.sendDATAMap());
+ }
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Wed Dec 21 22:29:59 2011 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912