diff --git a/FsTrack.jucer b/FsTrack.jucer index aea33e1..c122d35 100644 --- a/FsTrack.jucer +++ b/FsTrack.jucer @@ -4,7 +4,16 @@ bundleIdentifier="com.yourcompany.FsTrack" includeBinaryInAppConfig="1" jucerVersion="3.1.0"> + + + + + + + + + @@ -15,9 +24,9 @@ + isDebug="1" optimisation="1" targetName="FsTrack" headerPath="../../../../../extLib/FSUIPC"/> + isDebug="0" optimisation="2" targetName="FsTrack" headerPath="../../../../../extLib/FSUIPC"/> diff --git a/Source/FsLink.cpp b/Source/FsLink.cpp new file mode 100644 index 0000000..a1a0ef6 --- /dev/null +++ b/Source/FsLink.cpp @@ -0,0 +1,334 @@ +/* + * File: FsLink.cpp + * Author: jens + * + * Created on 9. Januar 2015, 20:14 + */ + +#include "FsLink.hpp" + +#define TWO_PWR_16 (65536.0) +#define TWO_PWR_32 (TWO_PWR_16*TWO_PWR_16) + +const char* FsLink::linkStateString[] = {"Init", "Disconnected", "Connected", "Paused", "Recording"}; +const char* FsLink::flightStateString[] = {"Init", "Suspend", "Ground", "Take off", "Enroute", "Touch down"}; + +FsLink::FsLink(const char *pDocRoot) +: m_docRoot(pDocRoot) +, m_pKml(nullptr) +, m_linkState(ls_init) +, m_linkStateNext(ls_disconnected) +, m_flightState(fs_init) +, m_flightStateNext(fs_suspend) +, m_kmlUpdateInterval(10) +, m_kmlUpdateCount(0) +{ + startTimer(100); +} + +FsLink::FsLink(const FsLink& orig) +{ + (void)orig; +} + +FsLink::~FsLink() +{ +} + +void FsLink::addListener(IFsLinkListener *pListener) +{ + m_listeners.add(pListener); +} + +void FsLink::setKml(IKml *pKml) +{ + m_pKml = pKml; +} + +bool FsLink::open() +{ + unsigned long result; + static char chOurKey[] = "CJM4KBNN1RLQ"; // As obtained from Pete Dowson + + memset(m_idStr, 0, sizeof(m_idStr)); + + if(FSUIPC_Open(SIM_ANY, &result)) + { + // Okay, we're linked, and already the FSUIPC_Open has had an initial + // exchange with FSUIPC to get its version number and to differentiate + // between FS's. + + // Now to auto-Register with FSUIPC, to save the user of an Unregistered FSUIPC + // having to Register UIPCHello for us: + + if (FSUIPC_Write(0x8001, 12, chOurKey, &result)) + FSUIPC_Process(&result); // Process the request(s) + + // I've not checked the reslut of the above -- if it didn't register us, + // and FSUIPC isn't fully user-Registered, the next request will not + // return the FS lock time + + FSUIPC_Read(0x24, sizeof(m_idStr), m_idStr, &result); + FSUIPC_Process(&result); + return true; + } + + return false; +} + +void FsLink::close() +{ + FSUIPC_Close(); // Closing when it wasn't open is okay, so this is safe here +} + +int FsLink::gatherData() +{ + DWORD result; + unsigned lat_lo, lon_lo, alt_lo; + char lat[8], lon[8], alt[8], FSRdy2Fly, FSDialog; + int lat_hi, lon_hi, alt_hi, radio_alt, bank, pitch, hdg_true, gs, tas, ias, bpa, vs, groundLevel, replay_active; + short mag_var, parking_brake, paused, framerate, plane_on_ground; + + FSUIPC_Read(0x600C, sizeof(m_flightData.timeZulu), &m_flightData.timeZulu, &result); + FSUIPC_Read(0x20, sizeof(groundLevel), &groundLevel, &result); + FSUIPC_Read(0x560, sizeof(lat), lat, &result); + FSUIPC_Read(0x568, sizeof(lon), lon, &result); + FSUIPC_Read(0x31E4, sizeof(radio_alt), &radio_alt, &result); + FSUIPC_Read(0x570, sizeof(alt), alt, &result); + FSUIPC_Read(0x578, sizeof(pitch), &pitch, &result); + FSUIPC_Read(0x57C, sizeof(bank), &bank, &result); + FSUIPC_Read(0x580, sizeof(hdg_true), &hdg_true, &result); + FSUIPC_Read(0x264, sizeof(paused), &paused, &result); + FSUIPC_Read(0x274, sizeof(framerate), &framerate, &result); + FSUIPC_Read(0x2A0, sizeof(mag_var), &mag_var, &result); + FSUIPC_Read(0x2B4, sizeof(gs), &gs, &result); + FSUIPC_Read(0x2B8, sizeof(tas), &tas, &result); + FSUIPC_Read(0x2BC, sizeof(ias), &ias, &result); + FSUIPC_Read(0x2C4, sizeof(bpa), &bpa, &result); + FSUIPC_Read(0x2C8, sizeof(vs), &vs, &result); + FSUIPC_Read(0x3364, sizeof(FSRdy2Fly), &FSRdy2Fly, &result); + FSUIPC_Read(0x3365, sizeof(FSDialog), &FSDialog, &result); + FSUIPC_Read(0x3D00, sizeof(m_flightData.aircraftTitle), m_flightData.aircraftTitle, &result); + FSUIPC_Read(0x3E00, sizeof(m_fsInstallPath), m_fsInstallPath, &result); + FSUIPC_Read(0x1F96, sizeof(m_flightData.tcasStr), m_flightData.tcasStr, &result); + FSUIPC_Read(0xF096, sizeof(m_flightData.tcasStr2), m_flightData.tcasStr2, &result); + FSUIPC_Read(0x3F04, sizeof(m_flightData.flightname), m_flightData.flightname, &result); + FSUIPC_Read(0x3130, sizeof(m_flightData.atcFlightNumStr), m_flightData.atcFlightNumStr, &result); + FSUIPC_Read(0x313C, sizeof(m_flightData.atcFlightIDStr), m_flightData.atcFlightIDStr, &result); + FSUIPC_Read(0x3148, sizeof(m_flightData.atcAirlineStr), m_flightData.atcAirlineStr, &result); + FSUIPC_Read(0x3160, sizeof(m_flightData.atcAircraftTypeStr), m_flightData.atcAircraftTypeStr, &result); + FSUIPC_Read(0x366, sizeof(plane_on_ground), &plane_on_ground, &result); + FSUIPC_Read(0xBC8, sizeof(parking_brake), &parking_brake, &result); + FSUIPC_Read(0x628, sizeof(replay_active), &replay_active, &result); + FSUIPC_Process(&result); + + if (result != FSUIPC_ERR_OK) + { + return -(int)result; + } + + memcpy(&lat_hi, &lat[4], sizeof(int)); + memcpy(&lat_lo, &lat[0], sizeof(int)); + m_flightData.lat = 90.0*((double)lat_hi + (double)lat_lo/TWO_PWR_32)/10001750; // degrees + + memcpy(&lon_hi, &lon[4], sizeof(int)); + memcpy(&lon_lo, &lon[0], sizeof(int)); + m_flightData.lon = 360.0*((double)lon_hi + (double)lon_lo/TWO_PWR_32)/TWO_PWR_32; // degrees + + memcpy(&alt_hi, &alt[4], sizeof(int)); + memcpy(&alt_lo, &alt[0], sizeof(int)); + m_flightData.gl_meter = groundLevel/256; // meter + m_flightData.alt_meter = (double)radio_alt/65536 + m_flightData.gl_meter; // meter + m_flightData.alt_feet = 3.28084*m_flightData.alt_meter; + + m_flightData.pitch_deg = 360.0*(double)pitch/TWO_PWR_32; // degrees + m_flightData.bank_deg = 360.0*(double)bank/TWO_PWR_32; // degrees + m_flightData.hdgTrue_deg = 360.0*(double)hdg_true/TWO_PWR_32; // degrees + if (m_flightData.hdgTrue_deg < 0.0) + m_flightData.hdgTrue_deg += 360.0; + if (m_flightData.hdgTrue_deg > 360.0) + m_flightData.hdgTrue_deg -= 360.0; + + m_flightData.magVar_deg = 360.0*(double)mag_var/TWO_PWR_16; // degrees + m_flightData.hdgMag_deg = m_flightData.hdgTrue_deg - m_flightData.magVar_deg; + if (m_flightData.hdgMag_deg < 0.0) + m_flightData.hdgMag_deg += 360.0; + if (m_flightData.hdgMag_deg > 360.0) + m_flightData.hdgMag_deg -= 360.0; + + m_flightData.gs_meterPerSec = (double)gs/TWO_PWR_16; // m/s + m_flightData.gs_knots = 1.946*m_flightData.gs_meterPerSec; // knots + m_flightData.tas_knots = (double)tas/128.0; // knots + m_flightData.ias_knots = (double)ias/128.0; // knots + m_flightData.bpa_knots = (double)bpa/128.0; // knots + m_flightData.vs_feetPerMin = 100*(double)vs/128.0; // ft/min + m_flightData.framerate = TWO_PWR_16/(2*framerate); + m_flightData.isFsReady = (FSRdy2Fly == 0); + m_flightData.isFsDialog = (FSDialog != 0); + m_flightData.isPaused = (paused != 0); + m_flightData.isReplay = (replay_active != 0); + m_flightData.isParked = (parking_brake != 0); + m_flightData.isOnGround = (plane_on_ground != 0); + + return 0; +} + +void FsLink::timerCallback() +{ + bool doUpdateState = false; + bool doUpdateData = false; + + if (m_linkState == ls_disconnected) + { + m_linkStateNext = ls_connected; + if (!open()) + { + close(); + m_linkStateNext = ls_disconnected; + } + } + else + { + if (gatherData() < 0) + { + close(); + m_linkStateNext = ls_disconnected; + } + } + + switch(m_linkState) + { + case ls_connected: + if (!m_flightData.isFsDialog && m_flightData.isFsReady) + { + if (m_pKml) + { + m_pKml->create(); + } + m_linkStateNext = ls_recording; + } + break; + + case ls_recording: + if (m_flightData.isFsDialog && !m_flightData.isFsReady) + { + m_pKml->destroy(); + m_linkStateNext = ls_connected; + break; + } + if (m_flightData.isPaused || m_flightData.isReplay) + { + m_linkStateNext = ls_paused; + break; + } + doUpdateData = true; + break; + + case ls_paused: + if (m_flightData.isFsDialog) + { + m_pKml->destroy(); + m_linkStateNext = ls_connected; + break; + } + if (!(m_flightData.isPaused || m_flightData.isReplay)) + { + m_linkStateNext = ls_recording; + break; + } + break; + + default: + break; + } + + switch(m_flightState) + { + case fs_suspend: + if (!m_flightData.isFsDialog && !m_flightData.isReplay) + { + m_flightStateNext = fs_ground; + if (!m_flightData.isOnGround) + { + m_flightStateNext = fs_enroute; + } + + } + break; + + case fs_ground: + if (!m_flightData.isOnGround) + { + m_flightStateNext = fs_takeoff; + } + break; + + case fs_takeoff: + m_flightStateNext = fs_enroute; + break; + + case fs_enroute: + if (m_flightData.isOnGround) + { + m_flightStateNext = fs_touchdown; + } + break; + + case fs_touchdown: + m_flightStateNext = fs_ground; + break; + + default: + break; + } + + // Override flight states + if (m_flightData.isFsDialog || m_flightData.isReplay) + { + m_flightStateNext = fs_suspend; + } + + doUpdateState = m_linkState != m_linkStateNext; + doUpdateState |= m_flightState != m_flightStateNext; + + m_linkState = m_linkStateNext; + m_flightState = m_flightStateNext; + + if (doUpdateState) + { + m_listeners.call(&IFsLinkListener::onStateChanged, *this); + } + + if (doUpdateData) + { + m_listeners.call(&IFsLinkListener::onDataChanged, *this); + + if (m_kmlUpdateCount > 0) + { + m_kmlUpdateCount--; + } + else + { + m_pKml->update(m_flightData); + m_pKml->export(m_pKml->getPath()); + m_kmlUpdateCount = m_kmlUpdateInterval; + } + + } + +} + +const char* FsLink::getLinkState() +{ + return linkStateString[m_linkState]; +} + +const char* FsLink::getFlightState() +{ + return flightStateString[m_flightState]; +} + +FlightData FsLink::getFlightData() +{ + return m_flightData; +} diff --git a/Source/FsLink.hpp b/Source/FsLink.hpp new file mode 100644 index 0000000..301bf53 --- /dev/null +++ b/Source/FsLink.hpp @@ -0,0 +1,75 @@ +/* + * File: FsLink.hpp + * Author: jens + * + * Created on 9. Januar 2015, 20:14 + */ + +#include "../JuceLibraryCode/JuceHeader.h" + +#include +#include +#include "IKml.hpp" +#include "IFsLink.hpp" + +#ifndef FSLINK_HPP +#define FSLINK_HPP + +class FsLink : public IFsLink, public juce::Timer +{ +public: + enum LinkState + { + ls_init = 0, + ls_disconnected, + ls_connected, + ls_paused, + ls_recording, + }; + + enum FlightState + { + fs_init = 0, + fs_suspend, + fs_ground, + fs_takeoff, + fs_enroute, + fs_touchdown, + }; + + FsLink(const char *pDocRoot); + FsLink(const FsLink& orig); + virtual ~FsLink(); + void addListener(IFsLinkListener *pListener); + void setKml(IKml *pKml); + +private: + ListenerList m_listeners; + const char *m_docRoot; + IKml *m_pKml; + const char *m_pCurrStateStr; + LinkState m_linkState; + LinkState m_linkStateNext; + FlightState m_flightState; + FlightState m_flightStateNext; + int m_kmlUpdateInterval; + int m_kmlUpdateCount; + char m_idStr[256]; + char m_fsInstallPath[256]; + FlightData m_flightData; + + static const char *linkStateString[]; + static const char *flightStateString[]; + + bool open(); + void close(); + int gatherData(); + + const char* getLinkState(); + const char* getFlightState(); + FlightData getFlightData(); + void timerCallback(); +}; + +#endif /* FSLINK_HPP */ + diff --git a/Source/HttpServer.cpp b/Source/HttpServer.cpp new file mode 100644 index 0000000..a738444 --- /dev/null +++ b/Source/HttpServer.cpp @@ -0,0 +1,113 @@ +#include "HttpServer.hpp" + + +HttpServer::HttpServer(const char *pDocDir) +: Thread("Http") +, m_docDir(pDocDir) +{ + startThread(); +} + + +HttpServer::~HttpServer(void) +{ + stopThread(10000); +} + +void HttpServer::addListener(IHttpListener *pListener) +{ + m_listeners.add(pListener); +} + +const char* HttpServer::getDocName(char *buffer, int buflen) +{ + static char docBuffer[1024]; + char *pDocname; + + strcpy(docBuffer, m_docDir); + pDocname = &docBuffer[strlen(docBuffer)]; + *pDocname = '\\'; + pDocname++; + + int i, off; + + if (!stricmp(buffer, "GET")) + { + return nullptr; + } + + off = 0; + while(buffer[3+off] == 0x20) + off++; + + while(buffer[3+off] == '/') + off++; + + i = 0; + while(buffer[3+off+i] != 0x20) + { + pDocname[i] = buffer[3+off+i]; + i++; + } + pDocname[i] = 0; + + return docBuffer; +} + +void HttpServer::run() +{ + char buffer[1024]; + + ScopedPointer listenSock = new StreamingSocket(); + listenSock->bindToPort(5001); + listenSock->createListener(5001); + + while(!threadShouldExit()) + { + const char *pDoc = nullptr; + if (listenSock->waitUntilReady(true, 100) > 0) + { + + ScopedPointer pSock = listenSock->waitForNextConnection(); + + int numRead = pSock->read(buffer, sizeof(buffer), false); + if (numRead > 0) + { + pDoc = getDocName(buffer, numRead); + if (!pDoc) + { + pSock->close(); + continue; + } + } + + m_listeners.call(&IHttpListener::onUpdate, pDoc); + + ScopedPointer file = new juce::File(pDoc); + if (!file) + continue; + + ScopedPointer pFileStream = file->createInputStream(); + if (!pFileStream) + continue; + + int64 remain = pFileStream->getTotalLength(); + int64 toRead; + + while(remain) + { + toRead = remain; + if (toRead > sizeof(buffer)) + { + toRead = sizeof(buffer); + } + pFileStream->read(buffer, toRead); + pSock->write(buffer, toRead); + remain -= toRead; + } + pFileStream = nullptr; + pSock = nullptr; + file = nullptr; + } + } +} diff --git a/Source/HttpServer.hpp b/Source/HttpServer.hpp new file mode 100644 index 0000000..28ad220 --- /dev/null +++ b/Source/HttpServer.hpp @@ -0,0 +1,23 @@ +#ifndef HTTPSERVER +#define HTTPSERVER + +#include "../JuceLibraryCode/JuceHeader.h" +#include "IHttp.hpp" + +class HttpServer : public juce::Thread +{ +public: + HttpServer(const char *pDocDir); + ~HttpServer(void); + void addListener(IHttpListener *pListener); + +private: + const char *m_docDir; + ListenerList m_listeners; + + const char* getDocName(char *buffer, int buflen); + void run(); + +}; + +#endif // HTTPSERVER diff --git a/Source/IFsLink.hpp b/Source/IFsLink.hpp new file mode 100644 index 0000000..59bae21 --- /dev/null +++ b/Source/IFsLink.hpp @@ -0,0 +1,48 @@ +/* + * File: FsLink.hpp + * Author: jens + * + * Created on 9. Januar 2015, 20:14 + */ + +#ifndef IFSLINK_HPP +#define IFSLINK_HPP + +struct FlightData +{ + bool isFsReady, isFsDialog, isPaused, isParked, isOnGround, isReplay; + unsigned long timeZulu; + double lat, lon, alt_meter, alt_feet, gl_meter, bank_deg, pitch_deg, hdgTrue_deg, hdgMag_deg, gs_meterPerSec, gs_knots, tas_knots, ias_knots, bpa_knots, vs_feetPerMin, magVar_deg; + double framerate; + char aircraftTitle[256]; + char tcasStr[15]; + char tcasStr2[15]; + char flightname[252]; + char atcFlightNumStr[12]; + char atcFlightIDStr[12]; + char atcAirlineStr[24]; + char atcAircraftTypeStr[24]; + +}; + +struct IFsLink +{ + IFsLink() {} + virtual ~IFsLink() {} + + virtual const char* getLinkState() = 0; + virtual const char* getFlightState() = 0; + virtual FlightData getFlightData() = 0; +}; + +struct IFsLinkListener +{ + IFsLinkListener() {} + virtual ~IFsLinkListener() {} + + virtual void onStateChanged(IFsLink &obj) = 0; + virtual void onDataChanged(IFsLink &obj) = 0; +}; + +#endif /* IFSLINK_HPP */ + diff --git a/Source/IHttp.hpp b/Source/IHttp.hpp new file mode 100644 index 0000000..6a1af6d --- /dev/null +++ b/Source/IHttp.hpp @@ -0,0 +1,20 @@ +/* + * File: IHttp.hpp + * Author: jens + * + * Created on 9. Januar 2015, 20:14 + */ + +#ifndef IHTTP_HPP +#define IHTTP_HPP + +struct IHttpListener +{ + IHttpListener() {} + virtual ~IHttpListener() {} + + virtual void onUpdate(const char *pPath) = 0; +}; + +#endif /* IHTTP_HPP */ + diff --git a/Source/IKml.hpp b/Source/IKml.hpp new file mode 100644 index 0000000..768fe44 --- /dev/null +++ b/Source/IKml.hpp @@ -0,0 +1,27 @@ +/* + * File: IKml.hpp + * Author: jens + * + * Created on 9. Januar 2015, 20:14 + */ + +#ifndef IKML_HPP +#define IKML_HPP + +#include "IFsLink.hpp" + +struct IKml +{ + IKml() {} + virtual ~IKml() {} + + virtual void create() = 0; + virtual void destroy() = 0; + virtual const char* getPath() = 0; + + virtual void update(FlightData const &flightData) = 0; + virtual void export(const char *pPath) = 0; +}; + +#endif /* IKML_HPP */ + diff --git a/Source/Kml.cpp b/Source/Kml.cpp new file mode 100644 index 0000000..9421123 --- /dev/null +++ b/Source/Kml.cpp @@ -0,0 +1,259 @@ +#include +#include +#include + +#include "Kml.hpp" + + +Kml::Kml(const char *pDocRoot) +: kml(nullptr) +, m_pPlanePlaceMark(nullptr) +, m_pPathPlaceMark(nullptr) +, m_docRoot(pDocRoot) +{ + memset(m_path, 0, sizeof(m_path)); +} + + +Kml::~Kml(void) +{ + kml = nullptr; +} + +const char* Kml::getPath() +{ + return m_path; +} + +void Kml::create() +{ + time_t time_departure; + struct tm *time_now; + + if (kml) + destroy(); + + kml = new XmlElement("kml"); + XmlElement *pDoc = kml->createNewChildElement("Document"); + XmlElement *pFile = kml->getChildByName("Document")->createNewChildElement("filename"); + XmlElement *pSnippet = kml->getChildByName("Document")->createNewChildElement("Snippet"); + + time(&time_departure); + time_now = localtime(&time_departure); + char time_str[256]; + + // Create an outer XML element.. + kml->setAttribute("xmlns", "http://www.opengis.net/kml/2.2"); + sprintf(m_path, "%s\\flight_%4.4d%2.2d%2.2d_%2.2d%2.2d%2.2d.kml", m_docRoot, 1900+time_now->tm_year, time_now->tm_mon+1, time_now->tm_mday, time_now->tm_hour, time_now->tm_min, time_now->tm_sec); + pFile->addTextElement(m_path); + pSnippet->setAttribute("maxLines", "2"); + + sprintf(time_str, "Created on %4.4d-%2.2d-%2.2d at %2.2d:%2.2d:%2.2d", 1900+time_now->tm_year, time_now->tm_mon+1, time_now->tm_mday, time_now->tm_hour, time_now->tm_min, time_now->tm_sec); + pSnippet->addTextElement(time_str); + +} + +void Kml::destroy() +{ + kml = nullptr; + m_pPlanePlaceMark = nullptr; + m_pPathPlaceMark = nullptr; +} + +void Kml::update(FlightData const &flightData) +{ + updatePlane(flightData); + updatePath(flightData); +} + +void Kml::updatePlane(FlightData const &flightData) +{ + const ScopedLock sl (m_lock); + char temp_str[1024]; + + XmlElement *pDoc = kml->getChildByName("Document"); + + XmlElement *pPlacemark = m_pPlanePlaceMark; + XmlElement *pName; + XmlElement *pStyle; + XmlElement *pIconStyle; + XmlElement *pIcon; + + XmlElement *pHref; + XmlElement *pHeading; + XmlElement *pY, *pW, *pH; + XmlElement *pDescr; + XmlElement *pPoint; + XmlElement *pExtrude; + XmlElement *pTesselate; + XmlElement *pAltitudeMode; + XmlElement *pCoords; + + if(pPlacemark == NULL) + { + // Placemark + pPlacemark = pDoc->createNewChildElement("Placemark"); + + // Name + sprintf(temp_str, "Unknown flight"); + if (strlen(flightData.atcFlightIDStr)) + { + if (strlen(flightData.atcFlightNumStr) == 0) + { + sprintf(temp_str, "%s", flightData.atcFlightIDStr); + } + else + { + sprintf(temp_str, "%s/%s", flightData.atcFlightIDStr, flightData.atcFlightNumStr); + } + } + pName = pPlacemark->createNewChildElement("name"); + pName->addTextElement(temp_str); + printf("%s\n", temp_str); + + // Description + pDescr = pPlacemark->createNewChildElement("description"); + sprintf(temp_str, "%s\nAltitude: %d ft, Speed: %d kts", flightData.atcFlightIDStr, (int)(flightData.alt_feet+0.5), (int)(flightData.gs_knots+0.5)); + pDescr->addTextElement(temp_str); + + // Style + pStyle = pPlacemark->createNewChildElement("Style"); + + // IconStyle + pIconStyle = pStyle->createNewChildElement("IconStyle"); + pHeading = pIconStyle->createNewChildElement("heading"); + sprintf(temp_str, "%d", (int)flightData.hdgTrue_deg); + pHeading->addTextElement(temp_str); + + // Icon + pIcon = pIconStyle->createNewChildElement("Icon"); + pHref = pIcon->createNewChildElement("href"); + pHref->addTextElement("root://icons/palette-2.png"); + pY = pIcon->createNewChildElement("y"); + pY->addTextElement("0"); + pW = pIcon->createNewChildElement("w"); + pW->addTextElement("32"); + pH = pIcon->createNewChildElement("h"); + pH->addTextElement("32"); + + // Point + pPoint = pPlacemark->createNewChildElement("Point"); + pExtrude = pPoint->createNewChildElement("extrude"); + pExtrude->addTextElement("1"); + pTesselate = pPoint->createNewChildElement("tesselate"); + pTesselate->addTextElement("1"); + pAltitudeMode = pPoint->createNewChildElement("altitudeMode"); + pAltitudeMode->addTextElement("absolute"); + pCoords = pPoint->createNewChildElement("coordinates"); + sprintf(temp_str, "%9.6f,%9.6f,%9.6f", flightData.lon, flightData.lat, flightData.alt_meter); + pCoords->addTextElement(temp_str); + + m_pPlanePlaceMark = pPlacemark; + } + else + { + // Description + sprintf(temp_str, "%s\nAltitude: %d ft, Speed: %d kts", flightData.atcFlightIDStr, (int)(flightData.alt_feet+0.5), (int)(flightData.gs_knots+0.5)); + pDescr = pPlacemark->getChildByName("description"); + pDescr->getFirstChildElement()->setText(temp_str); + + // Heading + sprintf(temp_str, "%d", (int)flightData.hdgTrue_deg); + pHeading = pPlacemark->getChildByName("Style")->getChildByName("IconStyle")->getChildByName("heading"); + pHeading->getFirstChildElement()->setText(temp_str); + + // Coordinates + sprintf(temp_str, "%9.6f,%9.6f,%9.6f", flightData.lon, flightData.lat, flightData.alt_meter); + pCoords = pPlacemark->getChildByName("Point")->getChildByName("coordinates"); + pCoords->getFirstChildElement()->setText(temp_str); + } + +} + +void Kml::updatePath(FlightData const &flightData) +{ + char temp_str[1024]; + + XmlElement *pDoc = kml->getChildByName("Document"); + + XmlElement *pPlacemark = m_pPathPlaceMark; + XmlElement *pName; + XmlElement *pStyle; + XmlElement *pLineStyle; + XmlElement *pLineColor; + XmlElement *pLineWidth; + XmlElement *pPolyStyle; + XmlElement *pPolyColor; + + XmlElement *pLineString; + XmlElement *pExtrude; + XmlElement *pTesselate; + XmlElement *pAltitudeMode; + XmlElement *pCoords; + + if(pPlacemark == NULL) + { + // Placemark + pPlacemark = pDoc->createNewChildElement("Placemark"); + + // Name + pName = pPlacemark->createNewChildElement("name"); + pName->addTextElement("Track"); + + // Style + pStyle = pPlacemark->createNewChildElement("Style"); + + // LineStyle + pLineStyle = pStyle->createNewChildElement("LineStyle"); + pLineColor = pLineStyle->createNewChildElement("color"); + sprintf(temp_str, "%4.4X\n", 0xff00ffff); + pLineColor->addTextElement(temp_str); + + pLineWidth = pLineStyle->createNewChildElement("width"); + pLineWidth->addTextElement("4"); + + // PolyStyle + pPolyStyle = pStyle->createNewChildElement("PolyStyle"); + pPolyColor = pPolyStyle->createNewChildElement("color"); + sprintf(temp_str, "%4.4X\n", 0x7f00ff00); + pPolyColor->addTextElement(temp_str); + + // LineString + pLineString = pPlacemark->createNewChildElement("LineString"); + pExtrude = pLineString->createNewChildElement("extrude"); + pExtrude->addTextElement("1"); + pTesselate = pLineString->createNewChildElement("tesselate"); + pTesselate->addTextElement("1"); + pAltitudeMode = pLineString->createNewChildElement("altitudeMode"); + pAltitudeMode->addTextElement("absolute"); + pCoords = pLineString->createNewChildElement("coordinates"); + sprintf(temp_str, "%9.6f,%9.6f,%9.6f", flightData.lon, flightData.lat, flightData.alt_meter); + pCoords->addTextElement(temp_str); + + m_pPathPlaceMark = pPlacemark; + } + else + { + // Coordinates + sprintf(temp_str, "\n%9.6f,%9.6f,%9.6f", flightData.lon, flightData.lat, flightData.alt_meter); + pCoords = pPlacemark->getChildByName("LineString")->getChildByName("coordinates"); + pCoords->addTextElement(temp_str); + } +} + +void Kml::export(const char *pPath) +{ + if (pPath && kml) + { + const ScopedLock sl (m_lock); + + File file(pPath); + kml->writeToFile(file, StringRef("")); + } +} + +void Kml::onUpdate(const char *pPath) +{ + export(pPath); +} + diff --git a/Source/Kml.hpp b/Source/Kml.hpp new file mode 100644 index 0000000..4c80a5a --- /dev/null +++ b/Source/Kml.hpp @@ -0,0 +1,32 @@ +#ifndef KML_HPP +#define KML_HPP + +#include "../JuceLibraryCode/JuceHeader.h" +#include "IHttp.hpp" +#include "IKml.hpp" + +class Kml : public IKml, public IHttpListener +{ +public: + Kml(const char *pDocRoot); + ~Kml(void); + +private: + CriticalSection m_lock; + ScopedPointer kml; + XmlElement *m_pPlanePlaceMark; + XmlElement *m_pPathPlaceMark; + char m_path[1024]; + const char *m_docRoot; + + void create(); + void destroy(); + const char* getPath(); + void update(FlightData const &flightData); + void export(const char *pPath); + void updatePlane(FlightData const &flightData); + void updatePath(FlightData const &flightData); + void onUpdate(const char *pPath); +}; + +#endif // !KML_HPP diff --git a/Source/Main.cpp b/Source/Main.cpp index 5cc0d31..edb648e 100644 --- a/Source/Main.cpp +++ b/Source/Main.cpp @@ -26,7 +26,9 @@ public: //============================================================================== void initialise (const String& commandLine) override { - // This method is where you should put your application's initialisation code.. + (void)commandLine; + + // This method is where you should put your application's initialisation code.. mainWindow = new MainWindow(); } @@ -48,6 +50,7 @@ public: void anotherInstanceStarted (const String& commandLine) override { + (void)commandLine; // When another instance of the app is launched while this one is running, // this method is invoked, and the commandLine parameter tells you what // the other instance's command-line arguments were. diff --git a/Source/MainComponent.cpp b/Source/MainComponent.cpp index 7a0abec..bb47346 100644 --- a/Source/MainComponent.cpp +++ b/Source/MainComponent.cpp @@ -37,6 +37,14 @@ MainComponent::MainComponent () m_fsuipcStatus->setColour (TextEditor::textColourId, Colours::black); m_fsuipcStatus->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + addAndMakeVisible (m_flightStatus = new Label ("Flight Status", + TRANS("Unknown"))); + m_flightStatus->setFont (Font (15.00f, Font::plain)); + m_flightStatus->setJustificationType (Justification::centredLeft); + m_flightStatus->setEditable (false, false, false); + m_flightStatus->setColour (TextEditor::textColourId, Colours::black); + m_flightStatus->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); + //[UserPreSize] //[/UserPreSize] @@ -45,6 +53,14 @@ MainComponent::MainComponent () //[Constructor] You can add your own custom stuff here.. + m_kml = new Kml("C:\\Users\\jens"); + + m_fsLink = new FsLink("C:\\Users\\jens"); + m_fsLink->addListener(this); + m_fsLink->setKml(m_kml); + + m_httpServer = new HttpServer("C:\\Users\\jens"); + m_httpServer->addListener(m_kml); //[/Constructor] } @@ -54,6 +70,7 @@ MainComponent::~MainComponent() //[/Destructor_pre] m_fsuipcStatus = nullptr; + m_flightStatus = nullptr; //[Destructor]. You can add your own custom destruction code here.. @@ -79,7 +96,8 @@ void MainComponent::paint (Graphics& g) void MainComponent::resized() { - m_fsuipcStatus->setBounds (32, 256, 150, 24); + m_fsuipcStatus->setBounds (16, 256, 150, 24); + m_flightStatus->setBounds (216, 256, 150, 24); //[UserResized] Add your own custom resize handling here.. //[/UserResized] } @@ -87,6 +105,16 @@ void MainComponent::resized() //[MiscUserCode] You can add your own definitions of your custom methods or any other code here... +void MainComponent::onStateChanged(IFsLink &obj) +{ + m_fsuipcStatus->setText(obj.getLinkState(), juce::sendNotification); + m_flightStatus->setText(obj.getFlightState(), juce::sendNotification); +} + +void MainComponent::onDataChanged(IFsLink &obj) +{ + (void)obj; +} //[/MiscUserCode] @@ -100,12 +128,17 @@ void MainComponent::resized() BEGIN_JUCER_METADATA + parentClasses="public Component, public IFsLinkListener" constructorParams="" + variableInitialisers="" snapPixels="8" snapActive="1" snapShown="1" + overlayOpacity="0.330" fixedSize="1" initialWidth="400" initialHeight="300">