diff options
author | Stanley Huang <stanleyhuangyc@gmail.com> | 2013-12-15 22:34:46 +1100 |
---|---|---|
committer | Stanley Huang <stanleyhuangyc@gmail.com> | 2013-12-15 22:34:46 +1100 |
commit | 2e009a031d1fe4aff95da3bc1b981d9ace697dd3 (patch) | |
tree | 4f01eb3fd1fd9c89f221b0e1afa211e0b439edc6 | |
parent | 5837da971a01b8853b3f04809844c898eb79d5a3 (diff) | |
download | 2021-arduino-obd-2e009a031d1fe4aff95da3bc1b981d9ace697dd3.tar.gz 2021-arduino-obd-2e009a031d1fe4aff95da3bc1b981d9ace697dd3.tar.bz2 2021-arduino-obd-2e009a031d1fe4aff95da3bc1b981d9ace697dd3.zip |
add Data2KML source code
-rw-r--r-- | megalogger/megalogger.ino | 2 | ||||
-rw-r--r-- | utilities/data2kml/README.txt | 2 | ||||
-rw-r--r-- | utilities/data2kml/data2kml.cpp | 361 | ||||
-rw-r--r-- | utilities/data2kml/data2kml.sln | 20 | ||||
-rw-r--r-- | utilities/data2kml/data2kml.vcxproj | 93 | ||||
-rw-r--r-- | utilities/data2kml/data2kml.vcxproj.filters | 30 | ||||
-rw-r--r-- | utilities/data2kml/kmlhead.txt | 159 | ||||
-rw-r--r-- | utilities/data2kml/logdata.h | 100 |
8 files changed, 766 insertions, 1 deletions
diff --git a/megalogger/megalogger.ino b/megalogger/megalogger.ino index 43d1f5a..15da969 100644 --- a/megalogger/megalogger.ino +++ b/megalogger/megalogger.ino @@ -332,7 +332,7 @@ private: gps.get_datetime(&date, &time, 0); logData(PID_GPS_TIME, time, date); - int speed = gps.speed() * 1852 / 100 / 1000; + float speed = gps.speed() * 1852 / 100000; logData(PID_GPS_SPEED, speed); // no need to log GPS data when vehicle has not been moving diff --git a/utilities/data2kml/README.txt b/utilities/data2kml/README.txt new file mode 100644 index 0000000..8114da1 --- /dev/null +++ b/utilities/data2kml/README.txt @@ -0,0 +1,2 @@ +Data2KML is an open-source command line utility written by Stanley Huang for Arduino OBD-II Data Logger (http://arduinodev.com/hardware). +Simply drag and drop a data log CSV file to the data2kml.exe and a KML file will be generated.
\ No newline at end of file diff --git a/utilities/data2kml/data2kml.cpp b/utilities/data2kml/data2kml.cpp new file mode 100644 index 0000000..0875503 --- /dev/null +++ b/utilities/data2kml/data2kml.cpp @@ -0,0 +1,361 @@ +/************************************************************************* +* Data2Kml - Converting OBD-II/GPS logger data to KML (Google Earth) +* Distributed under GPL v2.0 +* (c)2013 Written by Stanley Huang <stanleyhuangyc@gmail.com> +*************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdlib.h> +#include <time.h> +#include "logdata.h" + +typedef struct { + uint32_t timestamp; + float lat; + float lon; + uint16_t speed; + uint16_t speedgps; + uint16_t rpm; + uint16_t throttle; + uint16_t coolant; + uint16_t intake; + uint16_t load; + uint16_t absload; + uint16_t alt; + int16_t acc[3]; +} DATASET; + +typedef struct { + int state; + FILE* fp; + HEADER hdr; + char buffer[256]; + int bufbytes; + DATASET* dataset; + int datacount; + float startLat; + float startLon; + uint32_t curDate; + uint32_t curTime; + uint32_t ts; + uint32_t lastts; + float lastLat; + float lastLon; + uint32_t lastTime; + DATASET datas; +} KML_DATA; + +void WriteKMLData(KML_DATA* kd, uint32_t timestamp, uint16_t pid, float value[]) +{ + kd->ts = timestamp; + switch (pid) { + case PID_GPS_COORDINATES: + kd->datas.lat = value[0]; + kd->datas.lon = value[1]; + if (!kd->startLat) { + kd->startLat = kd->datas.lat; + kd->startLon = kd->datas.lon; + } + break; + case PID_GPS_ALTITUDE: + kd->datas.alt = (uint16_t)value[0]; + break; + case PID_SPEED: + kd->datas.speed = (uint16_t)value[0]; + break; + case PID_RPM: + kd->datas.rpm = (uint16_t)value[0]; + break; + case PID_THROTTLE: + kd->datas.throttle = (uint16_t)value[0]; + break; + case PID_COOLANT_TEMP: + kd->datas.coolant = (uint16_t)value[0]; + break; + case PID_INTAKE_TEMP: + kd->datas.intake = (uint16_t)value[0]; + break; + case PID_ENGINE_LOAD: + kd->datas.load = (uint16_t)value[0]; + break; + case PID_ABS_ENGINE_LOAD: + kd->datas.absload = (uint16_t)value[0]; + break; + case PID_GPS_SPEED: + kd->datas.speedgps = (uint16_t)value[0]; + break; + case PID_ACC: + kd->datas.acc[0] = (int16_t)value[0]; + kd->datas.acc[1] = (int16_t)value[1]; + kd->datas.acc[2] = (int16_t)value[2]; + break; + case PID_GPS_TIME: { + uint32_t date = (uint32_t)value[1]; + if (date > 10000 && (kd->curDate == 0 || (date % 100) <= (kd->curDate % 100) + 1)) { + kd->curDate = date; + kd->curTime = (uint32_t)value[0]; + } + } break; + } + if (kd->curTime != kd->lastTime && kd->datas.lat && kd->datas.lon) { + fprintf(kd->fp, "<when>"); + if (kd->curDate) { + fprintf(kd->fp, "%04u-%02u-%02u", 2000 + (kd->curDate % 100), (kd->curDate / 100) % 100, kd->curDate / 10000); + } else { + time_t yesterday = time(0) - 86400; + struct tm *btm = localtime(&yesterday); + fprintf(kd->fp, "%04d-%02d-%02d", 1900+btm->tm_year, btm->tm_mon + 1, btm->tm_mday); + } + + if (kd->curTime) { + fprintf(kd->fp, "T%02u:%02u:%02u.%03uZ", kd->curTime / 10000000, (kd->curTime / 100000) % 100, (kd->curTime / 1000) % 100, kd->curTime % 1000); + } + fprintf(kd->fp, "</when>"); + fprintf(kd->fp, "<gx:coord>%f %f %f</gx:coord>", kd->datas.lon, kd->datas.lat, kd->datas.alt); + + kd->datas.timestamp = timestamp; + kd->dataset = (DATASET*)realloc(kd->dataset, sizeof(DATASET) * (kd->datacount + 1)); + memcpy(kd->dataset + kd->datacount, &kd->datas, sizeof(DATASET)); + kd->datacount++; + + kd->lastLat = kd->datas.lat; + kd->lastLon = kd->datas.lon; + kd->lastTime = kd->curTime; + } +} + +void AppendFile(FILE* fp, char* filename) +{ + int uint8_ts; + char buffer[256]; + FILE* fpHeader = fopen(filename, "rb"); + if (!fpHeader) return; + while ((uint8_ts = fread(buffer, 1, sizeof(buffer), fpHeader)) > 0) { + fwrite(buffer, 1, uint8_ts, fp); + } + fclose(fpHeader); +} + +void WriteKMLTail(KML_DATA* kd) +{ + int i; + int lowThrottle = 50; + printf("Generating extended data\n"); + + fprintf(kd->fp, "<ExtendedData><SchemaData schemaUrl=\"#schema\">"); + fprintf(kd->fp, "<gx:SimpleArrayData name=\"speed\">"); + for (i = 0; i < kd->datacount; i++) { + fprintf(kd->fp, "<gx:value>%d</gx:value>", kd->dataset[i].speed); + } + fprintf(kd->fp, "</gx:SimpleArrayData>"); + /* + fprintf(kd->fp, "<gx:SimpleArrayData name=\"speedgps\">"); + for (i = 0; i < kd->datacount; i++) { + fprintf(kd->fp, "<gx:value>%d</gx:value>", kd->dataset[i].speedgps); + } + fprintf(kd->fp, "</gx:SimpleArrayData>"); + */ + fprintf(kd->fp, "<gx:SimpleArrayData name=\"rpm\">"); + for (i = 0; i < kd->datacount; i++) { + fprintf(kd->fp, "<gx:value>%d</gx:value>", kd->dataset[i].rpm); + } + fprintf(kd->fp, "</gx:SimpleArrayData>"); + + fprintf(kd->fp, "<gx:SimpleArrayData name=\"gear\">"); + for (i = 0; i < kd->datacount; i++) { + fprintf(kd->fp, "<gx:value>%d</gx:value>", kd->dataset[i].speed ? kd->dataset[i].rpm / kd->dataset[i].speed : 1); + } + fprintf(kd->fp, "</gx:SimpleArrayData>"); + + fprintf(kd->fp, "<gx:SimpleArrayData name=\"coolant\">"); + for (i = 0; i < kd->datacount; i++) { + fprintf(kd->fp, "<gx:value>%d</gx:value>", kd->dataset[i].coolant); + } + fprintf(kd->fp, "</gx:SimpleArrayData>"); + + fprintf(kd->fp, "<gx:SimpleArrayData name=\"intake\">"); + for (i = 0; i < kd->datacount; i++) { + fprintf(kd->fp, "<gx:value>%d</gx:value>", kd->dataset[i].intake); + } + fprintf(kd->fp, "</gx:SimpleArrayData>"); + + fprintf(kd->fp, "<gx:SimpleArrayData name=\"load\">"); + for (i = 0; i < kd->datacount; i++) { + fprintf(kd->fp, "<gx:value>%d</gx:value>", kd->dataset[i].load); + } + fprintf(kd->fp, "</gx:SimpleArrayData>"); + + /* + fprintf(kd->fp, "<gx:SimpleArrayData name=\"abs\">"); + for (i = 0; i < kd->datacount; i++) { + fprintf(kd->fp, "<gx:value>%d</gx:value>", kd->dataset[i].absload); + } + fprintf(kd->fp, "</gx:SimpleArrayData>"); + */ + + fprintf(kd->fp, "<gx:SimpleArrayData name=\"thr\">"); + for (i = 0; i < kd->datacount; i++) { + fprintf(kd->fp, "<gx:value>%d</gx:value>", kd->dataset[i].throttle); + if (kd->dataset[i].speed == 0) + lowThrottle = kd->dataset[i].throttle; + } + fprintf(kd->fp, "</gx:SimpleArrayData>"); + + fprintf(kd->fp, "<gx:SimpleArrayData name=\"alt\">"); + for (i = 0; i < kd->datacount; i++) { + fprintf(kd->fp, "<gx:value>%.2f</gx:value>", (float)kd->dataset[i].alt / 100); + } + fprintf(kd->fp, "</gx:SimpleArrayData>"); + + /* + fprintf(kd->fp, "<gx:SimpleArrayData name=\"sats\">"); + for (i = 0; i < kd->datacount; i++) { + fprintf(kd->fp, "<gx:value>%d</gx:value>", kd->dataset[i].sats); + } + fprintf(kd->fp, "</gx:SimpleArrayData>"); + */ + + fprintf(kd->fp, "<gx:SimpleArrayData name=\"acc\">"); + for (i = 0; i < kd->datacount; i++) { + fprintf(kd->fp, "<gx:value>X:%d Y:%d Z:%d</gx:value>", kd->dataset[i].acc[0] / 64, kd->dataset[i].acc[1] / 64, kd->dataset[i].acc[2] / 64); + } + fprintf(kd->fp, "</gx:SimpleArrayData>"); + fprintf(kd->fp, "<gx:SimpleArrayData name=\"ts\">"); + for (i = 0; i < kd->datacount; i++) { + fprintf(kd->fp, "<gx:value>%u</gx:value>", kd->dataset[i].timestamp); + } + fprintf(kd->fp, "</gx:SimpleArrayData>"); + fprintf(kd->fp, "</SchemaData></ExtendedData>\r\n</gx:Track></Placemark>"); + + int n = 0; + for (i = 0; i < kd->datacount - 1; i++) { + if (kd->dataset[i].speed < 25) { + continue; + } + if (kd->dataset[i].throttle > lowThrottle + 2) { + // throttle pedal is still down + continue; + } + float g = 0; + if (kd->dataset[i + 1].speed < kd->dataset[i].speed) + g = (((float)kd->dataset[i + 1].speed - kd->dataset[i].speed) * 1000 / (kd->dataset[i + 1].timestamp - kd->dataset[i].timestamp) / 3.6) / 9.8f; + else if (kd->dataset[i].speed < kd->dataset[i - 1].speed) + g = (((float)kd->dataset[i].speed - kd->dataset[i - 1].speed) * 1000 / (kd->dataset[i].timestamp - kd->dataset[i - 1].timestamp) / 3.6) / 9.8f; + else + continue; + + if (g <= -0.15f) { + n++; + fprintf(kd->fp, "<Placemark><name>#%d %u:%02u</name>", n, kd->dataset[i].timestamp / 60000, (kd->dataset[i].timestamp / 1000) % 60); + fprintf(kd->fp, "<styleUrl>#brakepoint</styleUrl><Point><coordinates>%f,%f</coordinates></Point>", kd->dataset[i].lon, kd->dataset[i].lat); + fprintf(kd->fp, "<ExtendedData>"); + fprintf(kd->fp, "<Data name=\"Speed\"><value>%d</value></Data>", kd->dataset[i].speed); + fprintf(kd->fp, "<Data name=\"RPM\"><value>%d</value></Data>", kd->dataset[i].rpm); + fprintf(kd->fp, "<Data name=\"ACC\"><value>%.2fG</value></Data>", g); + fprintf(kd->fp, "</ExtendedData>"); + fprintf(kd->fp, "</Placemark>\r\n"); + uint32_t t = kd->dataset[i].timestamp + 500; + while (kd->dataset[++i].timestamp < t); + } + } + fprintf(kd->fp, "</Folder></Document></kml>"); + +} + +void Cleanup(KML_DATA* kd) +{ + if (kd->dataset) free(kd->dataset); + if (kd->fp) fclose(kd->fp); + free(kd); +} + +int ConvertToKML(const char* logfile, const char* kmlfile, uint32_t startpos, uint32_t endpos) +{ + FILE* fp = fopen(logfile, "r"); + if (!fp) { + printf("Error opening file - %s\n", logfile); + return -1; + } + + uint32_t ts = 0; + KML_DATA* kd = (KML_DATA*)calloc(1, sizeof(KML_DATA)); + kd->fp = fopen(kmlfile, "w"); + + AppendFile(kd->fp, "kmlhead.txt"); + + int elapsed; + int pid; + + while (fscanf(fp, "%d,%X,", &elapsed, &pid) > 0) { + char c; + char data[32]; + int i = 0; + int index = 0; + float value[3] = {0}; + while ((c = fgetc(fp)) != '\n') { + if (i == sizeof(data)) continue; + data[i++] = c; + if (c == ' ') { + if (index < 2) { + data[i] = 0; + value[index++] = atof(data); + i = 0; + } + } + } + data[i] = 0; + value[index] = atof(data); + ts += elapsed; + if (ts < startpos) + continue; + + printf("Time=%.1f PID=%X", (float)ts / 1000, pid); + for (int n = 0; n <= index; n++) { + if (value[n] == (int)value[n]) + printf(" D%d=%d", n, (int)value[n]); + else + printf(" D%d=%f", n, value[n]); + } + putchar('\n'); + WriteKMLData(kd, ts, pid, value); + + if (endpos && ts > endpos) + break; + } + + WriteKMLTail(kd); + Cleanup(kd); + return 0; +} + +int main(int argc, const char* argv[]) +{ + int startpos = 0; + int endpos = 0; + char outfile[256]; + + printf("Data2KML (C)2013 ArduinoDev.com Written by Stanley Huang\n\n"); + if (argc <= 1) { + printf("Usage: %s [Input file] [Output file] [Start Pos] [End Pos]\n\n", argv[0]); + printf("Description about the arguments:\n\n\ +Input file: path to logged CSV file\n\ +Output file: path to KML file (output in the input directory if unspecified)\n\ +Start Pos: start time (seconds) for processing\n\ +End Pos: end time (seconds) for processing\n"); + return -1; + } + + if (argc > 3) + startpos = (uint32_t)atoi(argv[3]) * 1000; + if (argc > 4) + endpos = (uint32_t)atoi(argv[4]) * 1000; + + _snprintf(outfile, sizeof(outfile), "%s.kml", argv[1]); + + ConvertToKML(argv[1], argc > 2 ? argv[2] : outfile, startpos, endpos); + + return 0; +} diff --git a/utilities/data2kml/data2kml.sln b/utilities/data2kml/data2kml.sln new file mode 100644 index 0000000..2738d93 --- /dev/null +++ b/utilities/data2kml/data2kml.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "data2kml", "data2kml.vcxproj", "{E4ED3BCD-0D31-4960-BD22-399FB53D760F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E4ED3BCD-0D31-4960-BD22-399FB53D760F}.Debug|Win32.ActiveCfg = Debug|Win32 + {E4ED3BCD-0D31-4960-BD22-399FB53D760F}.Debug|Win32.Build.0 = Debug|Win32 + {E4ED3BCD-0D31-4960-BD22-399FB53D760F}.Release|Win32.ActiveCfg = Release|Win32 + {E4ED3BCD-0D31-4960-BD22-399FB53D760F}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/utilities/data2kml/data2kml.vcxproj b/utilities/data2kml/data2kml.vcxproj new file mode 100644 index 0000000..6911892 --- /dev/null +++ b/utilities/data2kml/data2kml.vcxproj @@ -0,0 +1,93 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{E4ED3BCD-0D31-4960-BD22-399FB53D760F}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>data2kmz</RootNamespace> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v110</PlatformToolset> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v110_xp</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>MultiByte</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + <OutDir>$(ProjectDir)\</OutDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <OutDir>$(ProjectDir)\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader> + </PrecompiledHeader> + <WarningLevel>Level3</WarningLevel> + <Optimization>Disabled</Optimization> + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <WarningLevel>Level3</WarningLevel> + <PrecompiledHeader> + </PrecompiledHeader> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <RuntimeLibrary>MultiThreaded</RuntimeLibrary> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + </Link> + </ItemDefinitionGroup> + <ItemGroup> + <ClCompile Include="data2kml.cpp" /> + </ItemGroup> + <ItemGroup> + <Text Include="kmlhead.txt" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="logdata.h" /> + </ItemGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/utilities/data2kml/data2kml.vcxproj.filters b/utilities/data2kml/data2kml.vcxproj.filters new file mode 100644 index 0000000..6ee7fbb --- /dev/null +++ b/utilities/data2kml/data2kml.vcxproj.filters @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <Filter Include="Source Files"> + <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier> + <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions> + </Filter> + <Filter Include="Header Files"> + <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier> + <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions> + </Filter> + <Filter Include="Resource Files"> + <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier> + <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions> + </Filter> + </ItemGroup> + <ItemGroup> + <ClCompile Include="data2kml.cpp"> + <Filter>Source Files</Filter> + </ClCompile> + </ItemGroup> + <ItemGroup> + <Text Include="kmlhead.txt" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="logdata.h"> + <Filter>Header Files</Filter> + </ClInclude> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/utilities/data2kml/kmlhead.txt b/utilities/data2kml/kmlhead.txt new file mode 100644 index 0000000..93334b1 --- /dev/null +++ b/utilities/data2kml/kmlhead.txt @@ -0,0 +1,159 @@ +<?xml version="1.0" encoding="UTF-8"?> +<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2"> +<Document> +<name>OBD-II/GPS Data Logger</name> +<Style id="brakepoint"> +<BalloonStyle> + <text><strong>Brakepoint</strong><br/> + <![CDATA[ + Speed: $[Speed] km/h<br/> + RPM: $[RPM]<br/> + ACC: $[ACC] + ]]> + </text> +</BalloonStyle> +</Style> +<!-- Normal track style --> +<Style id="track_n"> + <IconStyle> + <scale>.5</scale> + <Icon> + <href>http://earth.google.com/images/kml-icons/track-directional/track-none.png</href> + </Icon> + </IconStyle> + <LabelStyle> + <scale>0</scale> + </LabelStyle> +</Style> +<!-- Highlighted track style --> +<Style id="track_h"> + <IconStyle> + <scale>1.2</scale> + <Icon> + <href>http://earth.google.com/images/kml-icons/track-directional/track-none.png</href> + </Icon> + </IconStyle> +</Style> +<StyleMap id="track"> + <Pair> + <key>normal</key> + <styleUrl>#track_n</styleUrl> + </Pair> + <Pair> + <key>highlight</key> + <styleUrl>#track_h</styleUrl> + </Pair> +</StyleMap> +<!-- Normal multiTrack style --> +<Style id="multiTrack_n"> + <IconStyle> + <Icon> + <href>http://earth.google.com/images/kml-icons/track-directional/track-0.png</href> + </Icon> + </IconStyle> + <LineStyle> + <color>99ffac59</color> + <width>6</width> + </LineStyle> + +</Style> +<!-- Highlighted multiTrack style --> +<Style id="multiTrack_h"> + <IconStyle> + <scale>1.2</scale> + <Icon> + <href>http://earth.google.com/images/kml-icons/track-directional/track-0.png</href> + </Icon> + </IconStyle> + <LineStyle> + <color>99ffac59</color> + <width>8</width> + </LineStyle> +</Style> +<StyleMap id="multiTrack"> + <Pair> + <key>normal</key> + <styleUrl>#multiTrack_n</styleUrl> + </Pair> + <Pair> + <key>highlight</key> + <styleUrl>#multiTrack_h</styleUrl> + </Pair> +</StyleMap> +<!-- Normal waypoint style --> +<Style id="waypoint_n"> + <IconStyle> + <Icon> + <href>http://maps.google.com/mapfiles/kml/pal4/icon61.png</href> + </Icon> + </IconStyle> +</Style> +<!-- Highlighted waypoint style --> +<Style id="waypoint_h"> + <IconStyle> + <scale>1.2</scale> + <Icon> + <href>http://maps.google.com/mapfiles/kml/pal4/icon61.png</href> + </Icon> + </IconStyle> +</Style> +<StyleMap id="waypoint"> + <Pair> + <key>normal</key> + <styleUrl>#waypoint_n</styleUrl> + </Pair> + <Pair> + <key>highlight</key> + <styleUrl>#waypoint_h</styleUrl> + </Pair> +</StyleMap> +<Style id="lineStyle"> + <LineStyle> + <color>99ffac29</color> + <width>3</width> + </LineStyle> +</Style> +<Schema id="schema"> + <gx:SimpleArrayField name="speed" type="int"> + <displayName>Speed (km/h)</displayName> + </gx:SimpleArrayField> + <!--gx:SimpleArrayField name="speedgps" type="int"> + <displayName>GPS Speed (km/h)</displayName> + </gx:SimpleArrayField--> + <gx:SimpleArrayField name="rpm" type="int"> + <displayName>Engine RPM</displayName> + </gx:SimpleArrayField> + <gx:SimpleArrayField name="acc" type="string"> + <displayName>Acceleration</displayName> + </gx:SimpleArrayField> + <gx:SimpleArrayField name="gear" type="int"> + <displayName>Gear Ratio</displayName> + </gx:SimpleArrayField> + <gx:SimpleArrayField name="coolant" type="int"> + <displayName>Coolant Temperature (°C)</displayName> + </gx:SimpleArrayField> + <gx:SimpleArrayField name="intake" type="int"> + <displayName>Intake Temperature (°C)</displayName> + </gx:SimpleArrayField> + <gx:SimpleArrayField name="load" type="int"> + <displayName>Engine Load (%)</displayName> + </gx:SimpleArrayField> + <!--gx:SimpleArrayField name="abs" type="int"> + <displayName>Abs. Engine Load (%)</displayName> + </gx:SimpleArrayField--> + <gx:SimpleArrayField name="thr" type="int"> + <displayName>Throttle Position (%)</displayName> + </gx:SimpleArrayField> + <gx:SimpleArrayField name="alt" type="float"> + <displayName>Altitude (m)</displayName> + </gx:SimpleArrayField> + <gx:SimpleArrayField name="ts" type="int"> + <displayName>Timestamp (ms)</displayName> + </gx:SimpleArrayField> +</Schema> +<Folder> + <name>Tracks</name> + <Placemark> + <name>Main Track</name> + <styleUrl>#multiTrack</styleUrl> + <gx:Track> diff --git a/utilities/data2kml/logdata.h b/utilities/data2kml/logdata.h new file mode 100644 index 0000000..68eb36f --- /dev/null +++ b/utilities/data2kml/logdata.h @@ -0,0 +1,100 @@ +#define PID_RPM 0x10C +#define PID_SPEED 0x10D +#define PID_THROTTLE 0x111 +#define PID_ENGINE_LOAD 0x104 +#define PID_COOLANT_TEMP 0x105 +#define PID_INTAKE_TEMP 0x10F +#define PID_MAF_FLOW 0x110 +#define PID_ABS_ENGINE_LOAD 0x143 +#define PID_AMBIENT_TEMP 0x146 +#define PID_FUEL_PRESSURE 0x10A +#define PID_INTAKE_PRESSURE 0x10B +#define PID_BAROMETRIC 0x133 +#define PID_TIMING_ADVANCE 0x10E +#define PID_FUEL_LEVEL 0x12F +#define PID_RUNTIME 0x11F +#define PID_DISTANCE 0x131 + +#define PID_TIME_DATE 0xF001 +#define PID_TIME_TIME 0xF002 +#define PID_TIME_PLAY_SPEED 0xF003 + +#define PID_TURBO_BOOST 0xF108 + +#define PID_STAT_0_60 0xF100 +#define PID_STAT_0_100 0xF101 +#define PID_STAT_0_160 0xF102 +#define PID_STAT_0_400 0xF103 +#define PID_STAT_CUR_LAP 0xF110 +#define PID_STAT_LAST_LAP 0xF111 +#define PID_STAT_BEST_LAP 0xF112 +#define PID_STAT_LAP_PROGRESS 0xF113 + +#define PID_COMMAND 0xFFFE +#define PID_SYNC 0xFFFF + +enum { + PID_STAT_DISTANCE = 0xF200, + PID_STAT_TRIP_TIME, + PID_STAT_WAIT_TIME, + PID_STAT_SPEED_MAX, + PID_STAT_SPEED_AVG, + PID_STAT_RPM_MAX, + PID_STAT_RPM_MIN, + PID_STAT_RPM_AVG, + PID_STAT_INTAKE_MAX, + PID_STAT_INTAKE_MIN, + PID_STAT_INTAKE_SUM, + PID_STAT_ACC_FORWARD, + PID_STAT_ACC_BACKWARD, +}; + +enum { + PID_LOCAL_DATA = 0xF300, + PID_LOCAL_RATE, + PID_REMOTE_DATA, + PID_REMOTE_RATE, + PID_TIME_REMAIN, + PID_BATTERY, + PID_DEVICE_TEMP, +}; + +#define PID_GPS_COORDINATES 0xF00A +#define PID_GPS_ALTITUDE 0xF00C +#define PID_GPS_SPEED 0xF00D +#define PID_GPS_HEADING 0xF00E +#define PID_GPS_SAT_COUNT 0xF00F +#define PID_GPS_TIME 0xF010 + +#define PID_ACC 0xF020 +#define PID_GYRO 0xF021 + +#define PID_VIDEO_FRAME 0xFF00 + +#define HEADER_ID ('S' << 24 | 'U' << 16 | 'D' << 8 | 'U') + +typedef struct { + uint32_t time; + uint16_t pid; + uint16_t flags; + uint32_t value; +} LOG_DATA; + +typedef struct { + uint32_t id; //4 + uint32_t dataOffset; //4 + uint8_t ver; //1 + uint8_t ununsed; //1 + uint16_t flags; //2 + uint32_t date; + uint32_t time; + uint32_t startTick; + uint32_t unused[2]; + uint64_t devid; //8 + uint8_t ununsed2[20]; + uint8_t vin[32]; //32 + int32_t videoOffset; //4 + uint8_t stats[84]; //84 + uint8_t reserved[72]; //72 + uint32_t tail; //4 +} HEADER; //256 |