The xplane_io (X-Plane I/O) program is used to establish network communications, via UDP, with the X-Plane flight simulator running on a computer. The code consists of class libraries that abstract the lower-level UDP packet encoding and decoding details, according to the UDP protocol specifications in X-Plane version 9. Any X-Plane DATA packets can be sent and received, and any X-Plane DataRefs can be set by sending DREF packets to X-Plane.

Dependencies:   EthernetNetIf mbed ConfigFile

Committer:
bapowell
Date:
Wed Dec 21 22:29:59 2011 +0000
Revision:
0:a5d13af495af

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
bapowell 0:a5d13af495af 1 #include "EthernetNetIf.h"
bapowell 0:a5d13af495af 2 #include "UDPSocket.h"
bapowell 0:a5d13af495af 3 #include "LocalConfigFile.h"
bapowell 0:a5d13af495af 4 #include "Scaler.h"
bapowell 0:a5d13af495af 5 #include "XPlaneUdp.h"
bapowell 0:a5d13af495af 6 #include "XPlaneUdpDATA.h"
bapowell 0:a5d13af495af 7 #include "XPlaneUdpDecoder.h"
bapowell 0:a5d13af495af 8 #include "XPlaneUdpEncoder.h"
bapowell 0:a5d13af495af 9 #include "XPlaneIO.h"
bapowell 0:a5d13af495af 10
bapowell 0:a5d13af495af 11 XPlaneIO::~XPlaneIO() {
bapowell 0:a5d13af495af 12 if (_eth != NULL) {
bapowell 0:a5d13af495af 13 free(_eth);
bapowell 0:a5d13af495af 14 _eth = NULL;
bapowell 0:a5d13af495af 15 }
bapowell 0:a5d13af495af 16
bapowell 0:a5d13af495af 17 for (int i = 0; i < _xpAnalogInCount; i++) {
bapowell 0:a5d13af495af 18 if (_xpAnalogIn[i] != NULL) {
bapowell 0:a5d13af495af 19 free(_xpAnalogIn[i]);
bapowell 0:a5d13af495af 20 }
bapowell 0:a5d13af495af 21 }
bapowell 0:a5d13af495af 22
bapowell 0:a5d13af495af 23 for (XPlaneUdpDATAMap::iterator it = _recvDATAMap.begin(); it != _recvDATAMap.end(); it++) {
bapowell 0:a5d13af495af 24 if ((it->second) != NULL) {
bapowell 0:a5d13af495af 25 free(it->second);
bapowell 0:a5d13af495af 26 }
bapowell 0:a5d13af495af 27 }
bapowell 0:a5d13af495af 28 _recvDATAMap.clear();
bapowell 0:a5d13af495af 29
bapowell 0:a5d13af495af 30 }
bapowell 0:a5d13af495af 31
bapowell 0:a5d13af495af 32 bool XPlaneIO::setup(char * configFilename, Ethernet * ethernet) {
bapowell 0:a5d13af495af 33
bapowell 0:a5d13af495af 34 printf("X-Plane I/O ... initializing \n");
bapowell 0:a5d13af495af 35
bapowell 0:a5d13af495af 36 bool returnStatus = true;
bapowell 0:a5d13af495af 37
bapowell 0:a5d13af495af 38 LocalConfigFile cfg(configFilename);
bapowell 0:a5d13af495af 39
bapowell 0:a5d13af495af 40 _debug = cfg.getBool("debug", false);
bapowell 0:a5d13af495af 41 printf("debug: %d \n", _debug);
bapowell 0:a5d13af495af 42
bapowell 0:a5d13af495af 43 _debugVerbose = cfg.getBool("debugVerbose", false);
bapowell 0:a5d13af495af 44 printf("debugVerbose: %d \n", _debugVerbose);
bapowell 0:a5d13af495af 45
bapowell 0:a5d13af495af 46 IpAddr ipAddr;
bapowell 0:a5d13af495af 47 int intIp[4];
bapowell 0:a5d13af495af 48
bapowell 0:a5d13af495af 49 bool dhcp = true;
bapowell 0:a5d13af495af 50 if (cfg.fillIntArray4("mbed_ip_address", intIp)) {
bapowell 0:a5d13af495af 51 ipAddr = IpAddr(intIp[0], intIp[1], intIp[2], intIp[3]);
bapowell 0:a5d13af495af 52 // Continue gathering IP configuration.
bapowell 0:a5d13af495af 53 if (cfg.fillIntArray4("mbed_ip_netmask", intIp)) {
bapowell 0:a5d13af495af 54 IpAddr ipMask = IpAddr(intIp[0], intIp[1], intIp[2], intIp[3]);
bapowell 0:a5d13af495af 55 if (cfg.fillIntArray4("mbed_ip_gateway", intIp)) {
bapowell 0:a5d13af495af 56 IpAddr ipGtwy = IpAddr(intIp[0], intIp[1], intIp[2], intIp[3]);
bapowell 0:a5d13af495af 57 if (cfg.fillIntArray4("mbed_ip_dnssrvr", intIp)) {
bapowell 0:a5d13af495af 58 IpAddr ipDns = IpAddr(intIp[0], intIp[1], intIp[2], intIp[3]);
bapowell 0:a5d13af495af 59
bapowell 0:a5d13af495af 60 _eth = new EthernetNetIf(ipAddr, ipMask, ipGtwy, ipDns);
bapowell 0:a5d13af495af 61 dhcp = false;
bapowell 0:a5d13af495af 62 }
bapowell 0:a5d13af495af 63 }
bapowell 0:a5d13af495af 64 }
bapowell 0:a5d13af495af 65 }
bapowell 0:a5d13af495af 66 if (dhcp) {
bapowell 0:a5d13af495af 67 if (_debug) printf("mbed_ip_* address config not found or invalid, so defaulting to DHCP \n");
bapowell 0:a5d13af495af 68 _eth = new EthernetNetIf;
bapowell 0:a5d13af495af 69 }
bapowell 0:a5d13af495af 70
bapowell 0:a5d13af495af 71 // Set up the mbed ethernet interface.
bapowell 0:a5d13af495af 72 EthernetErr ethErr = _eth->setup();
bapowell 0:a5d13af495af 73 if (ethErr != ETH_OK) {
bapowell 0:a5d13af495af 74 printf("Ethernet setup failed (error = %d) \n", ethErr);
bapowell 0:a5d13af495af 75 returnStatus = false;
bapowell 0:a5d13af495af 76 }
bapowell 0:a5d13af495af 77
bapowell 0:a5d13af495af 78 if (_debug) {
bapowell 0:a5d13af495af 79 ipAddr = _eth->getIp();
bapowell 0:a5d13af495af 80 printf("mbed IP address is %d.%d.%d.%d \n", ipAddr[0], ipAddr[1], ipAddr[2], ipAddr[3]);
bapowell 0:a5d13af495af 81 }
bapowell 0:a5d13af495af 82
bapowell 0:a5d13af495af 83 const Ethernet::Mode linkModes[] = {Ethernet::AutoNegotiate, Ethernet::HalfDuplex10, Ethernet::FullDuplex10, Ethernet::HalfDuplex100, Ethernet::FullDuplex100};
bapowell 0:a5d13af495af 84 int linkMode = cfg.getInt("ethernet_link_mode", 0);
bapowell 0:a5d13af495af 85 ethernet->set_link(linkModes[linkMode]);
bapowell 0:a5d13af495af 86 if (_debug) printf("ethernet_link_mode set to %d \n", linkMode);
bapowell 0:a5d13af495af 87
bapowell 0:a5d13af495af 88 if (_debug) printf("Setting recvHost and sendHost \n");
bapowell 0:a5d13af495af 89 _recvHost.setIp(ipAddr);
bapowell 0:a5d13af495af 90 _recvHost.setPort(cfg.getInt("recv_port", 49000));
bapowell 0:a5d13af495af 91 if (cfg.fillIntArray4("xplane_ip_address", intIp)) {
bapowell 0:a5d13af495af 92 _sendHost.setIp(IpAddr(intIp[0], intIp[1], intIp[2], intIp[3]));
bapowell 0:a5d13af495af 93 }
bapowell 0:a5d13af495af 94 _sendHost.setPort(cfg.getInt("xplane_ip_port", 49000));
bapowell 0:a5d13af495af 95
bapowell 0:a5d13af495af 96 if (_debug) printf("Setting event callback handler \n");
bapowell 0:a5d13af495af 97 _udpSocket.setOnEvent(this, &XPlaneIO::onUDPSocketEvent);
bapowell 0:a5d13af495af 98
bapowell 0:a5d13af495af 99 if (_debug) printf("Binding to recvHost \n");
bapowell 0:a5d13af495af 100 UDPSocketErr udpErr = _udpSocket.bind(_recvHost);
bapowell 0:a5d13af495af 101 if (udpErr != UDPSOCKET_OK) {
bapowell 0:a5d13af495af 102 printf("Failure in binding to recvHost (error = %d) \n", udpErr);
bapowell 0:a5d13af495af 103 returnStatus = false;
bapowell 0:a5d13af495af 104 }
bapowell 0:a5d13af495af 105
bapowell 0:a5d13af495af 106 _sendInterval = cfg.getInt("send_interval", 200);
bapowell 0:a5d13af495af 107 printf("send_interval: %d ms \n", _sendInterval);
bapowell 0:a5d13af495af 108
bapowell 0:a5d13af495af 109 _reverseByteOrder = cfg.getBool("reverse_byte_order", false);
bapowell 0:a5d13af495af 110 printf("reverse_byte_order: %d \n", _reverseByteOrder);
bapowell 0:a5d13af495af 111
bapowell 0:a5d13af495af 112 char key[33];
bapowell 0:a5d13af495af 113 float f4[4];
bapowell 0:a5d13af495af 114
bapowell 0:a5d13af495af 115 // Scan for Analog Inputs (up to 6).
bapowell 0:a5d13af495af 116 _xpAnalogInCount = 0;
bapowell 0:a5d13af495af 117 for (int a = 1; a <= 6; a++) {
bapowell 0:a5d13af495af 118 sprintf(key, "ain_%d_pin", a);
bapowell 0:a5d13af495af 119 PinName pin = cfg.getPin(key, NC);
bapowell 0:a5d13af495af 120 if (pin != NC) {
bapowell 0:a5d13af495af 121 sprintf(key, "ain_%d_scale1", a);
bapowell 0:a5d13af495af 122 if (cfg.fillFloatArray4(key, f4)) {
bapowell 0:a5d13af495af 123 Scaler<float> scale1(f4[0], f4[1], f4[2], f4[3]);
bapowell 0:a5d13af495af 124 sprintf(key, "ain_%d_scale2", a);
bapowell 0:a5d13af495af 125 if (cfg.fillFloatArray4(key, f4)) {
bapowell 0:a5d13af495af 126 Scaler<float> scale2(f4[0], f4[1], f4[2], f4[3]);
bapowell 0:a5d13af495af 127 sprintf(key, "ain_%d_msg_idx", a);
bapowell 0:a5d13af495af 128 int msgIdx = cfg.getInt(key, -1);
bapowell 0:a5d13af495af 129 if (msgIdx >= 0) {
bapowell 0:a5d13af495af 130 sprintf(key, "ain_%d_float_idx", a);
bapowell 0:a5d13af495af 131 int floatIdx = cfg.getInt(key, -1);
bapowell 0:a5d13af495af 132 if (floatIdx >= 0) {
bapowell 0:a5d13af495af 133 // found all valid config items
bapowell 0:a5d13af495af 134 printf("Setting Analog Input # %d \n", a);
bapowell 0:a5d13af495af 135 _xpAnalogIn[_xpAnalogInCount] = new XPlaneAnalogIn(pin, scale1, scale2, msgIdx, floatIdx);
bapowell 0:a5d13af495af 136 _xpAnalogInCount++;
bapowell 0:a5d13af495af 137
bapowell 0:a5d13af495af 138 addDATAToSend(msgIdx);
bapowell 0:a5d13af495af 139 }
bapowell 0:a5d13af495af 140 }
bapowell 0:a5d13af495af 141 }
bapowell 0:a5d13af495af 142 }
bapowell 0:a5d13af495af 143 }
bapowell 0:a5d13af495af 144 }
bapowell 0:a5d13af495af 145 for (int i = _xpAnalogInCount; i < 6; i++) {
bapowell 0:a5d13af495af 146 _xpAnalogIn[i] = NULL;
bapowell 0:a5d13af495af 147 }
bapowell 0:a5d13af495af 148
bapowell 0:a5d13af495af 149 _udpDecoder.setDebug(_debugVerbose);
bapowell 0:a5d13af495af 150 _udpDecoder.setReverseByteOrder(_reverseByteOrder);
bapowell 0:a5d13af495af 151
bapowell 0:a5d13af495af 152 _udpEncoder.setDebug(_debugVerbose);
bapowell 0:a5d13af495af 153
bapowell 0:a5d13af495af 154 return returnStatus;
bapowell 0:a5d13af495af 155 }
bapowell 0:a5d13af495af 156
bapowell 0:a5d13af495af 157
bapowell 0:a5d13af495af 158 bool XPlaneIO::addDATAToReceive(int msgIndex) {
bapowell 0:a5d13af495af 159 return addXPlaneUdpDATAToMap(_recvDATAMap, msgIndex, _reverseByteOrder);
bapowell 0:a5d13af495af 160 }
bapowell 0:a5d13af495af 161
bapowell 0:a5d13af495af 162 bool XPlaneIO::addDATAToSend(int msgIndex) {
bapowell 0:a5d13af495af 163 return addXPlaneUdpDATAToMap(_sendDATAMap, msgIndex, _reverseByteOrder);
bapowell 0:a5d13af495af 164 }
bapowell 0:a5d13af495af 165
bapowell 0:a5d13af495af 166 XPlaneUdpDATA * XPlaneIO::getReceiveDATA(int msgIndex) const {
bapowell 0:a5d13af495af 167 return getXPlaneUdpDATA(_recvDATAMap, msgIndex);
bapowell 0:a5d13af495af 168 }
bapowell 0:a5d13af495af 169
bapowell 0:a5d13af495af 170 XPlaneUdpDATA * XPlaneIO::getSendDATA(int msgIndex) const {
bapowell 0:a5d13af495af 171 return getXPlaneUdpDATA(_sendDATAMap, msgIndex);
bapowell 0:a5d13af495af 172 }
bapowell 0:a5d13af495af 173
bapowell 0:a5d13af495af 174 float XPlaneIO::getReceiveDATAValue(int msgIndex, int floatIndex) const {
bapowell 0:a5d13af495af 175 XPlaneUdpDATA *DATAmsg = getReceiveDATA(msgIndex);
bapowell 0:a5d13af495af 176 if (DATAmsg != NULL) {
bapowell 0:a5d13af495af 177 return DATAmsg->getData(floatIndex);
bapowell 0:a5d13af495af 178 }
bapowell 0:a5d13af495af 179 else {
bapowell 0:a5d13af495af 180 return -999.999f;
bapowell 0:a5d13af495af 181 }
bapowell 0:a5d13af495af 182 }
bapowell 0:a5d13af495af 183
bapowell 0:a5d13af495af 184 void XPlaneIO::setSendDATAValue(int msgIndex, int floatIndex, float f) {
bapowell 0:a5d13af495af 185 XPlaneUdpDATA *DATAmsg = getSendDATA(msgIndex);
bapowell 0:a5d13af495af 186 if (DATAmsg != NULL) {
bapowell 0:a5d13af495af 187 DATAmsg->setData(floatIndex, f);
bapowell 0:a5d13af495af 188 }
bapowell 0:a5d13af495af 189 }
bapowell 0:a5d13af495af 190
bapowell 0:a5d13af495af 191
bapowell 0:a5d13af495af 192 void XPlaneIO::pollAnalogIn() {
bapowell 0:a5d13af495af 193 int scaleRange;
bapowell 0:a5d13af495af 194 bool noChange;
bapowell 0:a5d13af495af 195 for (int i = 0; i < _xpAnalogInCount; i++) {
bapowell 0:a5d13af495af 196 XPlaneAnalogIn * xpAIn = _xpAnalogIn[i];
bapowell 0:a5d13af495af 197 float aout = xpAIn->read_scaled(scaleRange, noChange);
bapowell 0:a5d13af495af 198 if (! noChange) {
bapowell 0:a5d13af495af 199 setSendDATAValue(xpAIn->xplaneDATAMsgIdx(), xpAIn->xplaneDATAMsgFloatIdx(), aout);
bapowell 0:a5d13af495af 200 }
bapowell 0:a5d13af495af 201 }
bapowell 0:a5d13af495af 202 }
bapowell 0:a5d13af495af 203
bapowell 0:a5d13af495af 204
bapowell 0:a5d13af495af 205 void XPlaneIO::sendDREF(XPlaneUdpDREF & dref) {
bapowell 0:a5d13af495af 206 _sendDREFQueue.push(dref);
bapowell 0:a5d13af495af 207 }
bapowell 0:a5d13af495af 208
bapowell 0:a5d13af495af 209
bapowell 0:a5d13af495af 210 void XPlaneIO::startSendingUdp() {
bapowell 0:a5d13af495af 211 _sendTicker.attach_us(this, &XPlaneIO::sendUdp, _sendInterval * 1000);
bapowell 0:a5d13af495af 212 }
bapowell 0:a5d13af495af 213
bapowell 0:a5d13af495af 214 void XPlaneIO::stopSendingUdp() {
bapowell 0:a5d13af495af 215 _sendTicker.detach();
bapowell 0:a5d13af495af 216 }
bapowell 0:a5d13af495af 217
bapowell 0:a5d13af495af 218 void XPlaneIO::sendUdp() {
bapowell 0:a5d13af495af 219 if (_debugVerbose) printf("sendUdp() called \n");
bapowell 0:a5d13af495af 220
bapowell 0:a5d13af495af 221 pollAnalogIn();
bapowell 0:a5d13af495af 222
bapowell 0:a5d13af495af 223 int len = _udpEncoder.encodeFromDATAMap(_udpSendBuffer, UDP_SEND_BUFFER_SIZE, _sendDATAMap, true);
bapowell 0:a5d13af495af 224 if (len > 5) {
bapowell 0:a5d13af495af 225 udpSocketSend(_udpSendBuffer, len);
bapowell 0:a5d13af495af 226 resetDataChangedInMap(_sendDATAMap);
bapowell 0:a5d13af495af 227 }
bapowell 0:a5d13af495af 228
bapowell 0:a5d13af495af 229 while (_sendDREFQueue.size() > 0) {
bapowell 0:a5d13af495af 230 len = _udpEncoder.encodeDataRef(_udpSendBuffer, UDP_SEND_BUFFER_SIZE, _sendDREFQueue.front());
bapowell 0:a5d13af495af 231 if (len > 0) {
bapowell 0:a5d13af495af 232 udpSocketSend(_udpSendBuffer, len);
bapowell 0:a5d13af495af 233 }
bapowell 0:a5d13af495af 234 _sendDREFQueue.pop();
bapowell 0:a5d13af495af 235 }
bapowell 0:a5d13af495af 236 }
bapowell 0:a5d13af495af 237
bapowell 0:a5d13af495af 238
bapowell 0:a5d13af495af 239 /**
bapowell 0:a5d13af495af 240 * Callback handler for received UDP data.
bapowell 0:a5d13af495af 241 */
bapowell 0:a5d13af495af 242 void XPlaneIO::onUDPSocketEvent(UDPSocketEvent e) {
bapowell 0:a5d13af495af 243 if (_debugVerbose) printf("onUDPSocketEvent() called \n");
bapowell 0:a5d13af495af 244
bapowell 0:a5d13af495af 245 if (e == UDPSOCKET_READABLE) {
bapowell 0:a5d13af495af 246 if (_debugVerbose) printf("onUDPSocketEvent() : event=UDPSOCKET_READABLE \n");
bapowell 0:a5d13af495af 247
bapowell 0:a5d13af495af 248 Host host;
bapowell 0:a5d13af495af 249 while (int len = _udpSocket.recvfrom(_udpRecvBuffer, UDP_RECV_BUFFER_SIZE, &host)) {
bapowell 0:a5d13af495af 250 if (len <= 0) {
bapowell 0:a5d13af495af 251 break;
bapowell 0:a5d13af495af 252 }
bapowell 0:a5d13af495af 253
bapowell 0:a5d13af495af 254 if (_debugVerbose) {
bapowell 0:a5d13af495af 255 IpAddr hostIp = host.getIp();
bapowell 0:a5d13af495af 256 //printf("From %d.%d.%d.%d: len=%d: %s\n", hostIp[0], hostIp[1], hostIp[2], hostIp[3], len, buf);
bapowell 0:a5d13af495af 257 printf("From %d.%d.%d.%d: len=%d \n", hostIp[0], hostIp[1], hostIp[2], hostIp[3], len);
bapowell 0:a5d13af495af 258 }
bapowell 0:a5d13af495af 259
bapowell 0:a5d13af495af 260 XPlaneUdpMessageType pktMsgType = _udpDecoder.setUdpBuffer(_udpRecvBuffer, len);
bapowell 0:a5d13af495af 261 if (pktMsgType == DATA) {
bapowell 0:a5d13af495af 262 _udpDecoder.putIntoDATAMap(_recvDATAMap, true);
bapowell 0:a5d13af495af 263 }
bapowell 0:a5d13af495af 264 }
bapowell 0:a5d13af495af 265 }
bapowell 0:a5d13af495af 266 }
bapowell 0:a5d13af495af 267
bapowell 0:a5d13af495af 268
bapowell 0:a5d13af495af 269 int XPlaneIO::udpSocketSend(char * buf, int len) {
bapowell 0:a5d13af495af 270 if (_debugVerbose) printf("udpSocketSend(): sending %d bytes \n", len);
bapowell 0:a5d13af495af 271
bapowell 0:a5d13af495af 272 int nSent = _udpSocket.sendto(buf, len, &_sendHost);
bapowell 0:a5d13af495af 273
bapowell 0:a5d13af495af 274 if ( nSent < 0 ) {
bapowell 0:a5d13af495af 275 if (_debug) printf("PROBLEM SENDING UDP DATA (error = %d) \n", (UDPSocketErr)nSent);
bapowell 0:a5d13af495af 276 }
bapowell 0:a5d13af495af 277 else if ( nSent != len ) {
bapowell 0:a5d13af495af 278 if (_debug) printf("WARNING: %d bytes were sent \n", nSent);
bapowell 0:a5d13af495af 279 }
bapowell 0:a5d13af495af 280
bapowell 0:a5d13af495af 281 return nSent;
bapowell 0:a5d13af495af 282 }
bapowell 0:a5d13af495af 283
bapowell 0:a5d13af495af 284
bapowell 0:a5d13af495af 285
bapowell 0:a5d13af495af 286 bool XPlaneIO::debug() const {
bapowell 0:a5d13af495af 287 return _debug;
bapowell 0:a5d13af495af 288 }
bapowell 0:a5d13af495af 289
bapowell 0:a5d13af495af 290 bool XPlaneIO::reverseByteOrder() const {
bapowell 0:a5d13af495af 291 return _reverseByteOrder;
bapowell 0:a5d13af495af 292 }
bapowell 0:a5d13af495af 293
bapowell 0:a5d13af495af 294 XPlaneUdpDATAMap & XPlaneIO::recvDATAMap() {
bapowell 0:a5d13af495af 295 return _recvDATAMap;
bapowell 0:a5d13af495af 296 }
bapowell 0:a5d13af495af 297
bapowell 0:a5d13af495af 298 XPlaneUdpDATAMap & XPlaneIO::sendDATAMap() {
bapowell 0:a5d13af495af 299 return _sendDATAMap;
bapowell 0:a5d13af495af 300 }