Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d39f8e758b | |||
| 487dabbbf6 | |||
| 15fa35f0fa | |||
| 3c1800d9a5 | |||
| 2e65f3d38b | |||
| 60d0076d98 | |||
| 7f7af3ebac | |||
| fc1998976f | |||
| f485846d75 |
166
.gitignore
vendored
166
.gitignore
vendored
@ -1,165 +1 @@
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/macos,go,intellij
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=macos,go,intellij
|
||||
|
||||
### Go ###
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
### Go Patch ###
|
||||
/vendor/
|
||||
/Godeps/
|
||||
|
||||
### Intellij ###
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/usage.statistics.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# Generated files
|
||||
.idea/**/contentModel.xml
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
.idea/**/dbnavigator.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
|
||||
# Gradle and Maven with auto-import
|
||||
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||
# since they will be recreated, and may cause churn. Uncomment if using
|
||||
# auto-import.
|
||||
# .idea/artifacts
|
||||
# .idea/compiler.xml
|
||||
# .idea/jarRepositories.xml
|
||||
# .idea/modules.xml
|
||||
# .idea/*.iml
|
||||
# .idea/modules
|
||||
# *.iml
|
||||
# *.ipr
|
||||
|
||||
# CMake
|
||||
cmake-build-*/
|
||||
|
||||
# Mongo Explorer plugin
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
# File-based project format
|
||||
*.iws
|
||||
|
||||
# IntelliJ
|
||||
out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Cursive Clojure plugin
|
||||
.idea/replstate.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
fabric.properties
|
||||
|
||||
# Editor-based Rest Client
|
||||
.idea/httpRequests
|
||||
|
||||
# Android studio 3.1+ serialized cache file
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
### Intellij Patch ###
|
||||
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
|
||||
|
||||
# *.iml
|
||||
# modules.xml
|
||||
# .idea/misc.xml
|
||||
# *.ipr
|
||||
|
||||
# Sonarlint plugin
|
||||
# https://plugins.jetbrains.com/plugin/7973-sonarlint
|
||||
.idea/**/sonarlint/
|
||||
|
||||
# SonarQube Plugin
|
||||
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
|
||||
.idea/**/sonarIssues.xml
|
||||
|
||||
# Markdown Navigator plugin
|
||||
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
|
||||
.idea/**/markdown-navigator.xml
|
||||
.idea/**/markdown-navigator-enh.xml
|
||||
.idea/**/markdown-navigator/
|
||||
|
||||
# Cache file creation bug
|
||||
# See https://youtrack.jetbrains.com/issue/JBR-2257
|
||||
.idea/$CACHE_FILE$
|
||||
|
||||
# CodeStream plugin
|
||||
# https://plugins.jetbrains.com/plugin/12206-codestream
|
||||
.idea/codestream.xml
|
||||
|
||||
### macOS ###
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/macos,go,intellij
|
||||
|
||||
# CUSTOM
|
||||
.env
|
||||
gpsconfig.yml
|
||||
config.yml
|
||||
_db
|
||||
/build
|
||||
.idea/
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -1,3 +0,0 @@
|
||||
[submodule "static/indicators"]
|
||||
path = static/indicators
|
||||
url = https://github.com/sebmatton/jQuery-Flight-Indicators.git
|
||||
2
.idea/.gitignore
generated
vendored
2
.idea/.gitignore
generated
vendored
@ -2,7 +2,7 @@
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/../../../../../../:\Users\Frank\Desktop\gyrogpsc\.idea/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
|
||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
5
.idea/codeStyles/codeStyleConfig.xml
generated
@ -1,5 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
||||
4
.idea/jsLibraryMappings.xml
generated
4
.idea/jsLibraryMappings.xml
generated
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="JavaScriptLibraryMappings">
|
||||
<file url="PROJECT" libraries="{Chart, Chart.js, mapbox-gl, three.js}" />
|
||||
<file url="PROJECT" libraries="{Chart, Chart.js}" />
|
||||
</component>
|
||||
</project>
|
||||
</project>
|
||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager">
|
||||
<output url="file://$PROJECT_DIR$/out"/>
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
2
.idea/vcs.xml
generated
2
.idea/vcs.xml
generated
@ -2,6 +2,6 @@
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/static/indicators" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library" vcs="" />
|
||||
</component>
|
||||
</project>
|
||||
118
.idea/workspace.xml
generated
Normal file
118
.idea/workspace.xml
generated
Normal file
@ -0,0 +1,118 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="70ae6a46-b58b-4192-b69d-37293bd6e2cf" name="Default Changelist" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cmd/server/server.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/server/server.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cmd/server_only/server_only.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/server_only/server_only.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/net/net.go" beforeDir="false" afterPath="$PROJECT_DIR$/net/net.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/static/scripts/map.js" beforeDir="false" afterPath="$PROJECT_DIR$/static/scripts/map.js" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/static/scripts/websocket.js" beforeDir="false" afterPath="$PROJECT_DIR$/static/scripts/websocket.js" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="GOROOT" path="C:\Go" />
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="GoLibraries">
|
||||
<option name="indexEntireGoPath" value="false" />
|
||||
</component>
|
||||
<component name="ProjectId" id="1l4NBsO3Y7UF6i7T6TL4EsARWQm" />
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||
<property name="aspect.path.notification.shown" value="true" />
|
||||
<property name="go.import.settings.migrated" value="true" />
|
||||
<property name="go.tried.to.enable.integration.vgo.integrator" value="true" />
|
||||
<property name="nodejs_package_manager_path" value="npm" />
|
||||
<property name="settings.editor.selected.configurable" value="preferences.pluginManager" />
|
||||
</component>
|
||||
<component name="RunManager" selected="Go Build.go build git.timovolkmann.de/gyrogpsc/cmd/server">
|
||||
<configuration name="go build git.timovolkmann.de/gyrogpsc/cmd/server" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true" nameIsGenerated="true">
|
||||
<module name="gyrogpsc" />
|
||||
<working_directory value="$PROJECT_DIR$" />
|
||||
<kind value="PACKAGE" />
|
||||
<filePath value="$PROJECT_DIR$/cmd/server/server.go" />
|
||||
<package value="git.timovolkmann.de/gyrogpsc/cmd/server" />
|
||||
<directory value="$PROJECT_DIR$" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="index.html" type="JavascriptDebugType" temporary="true" nameIsGenerated="true" uri="http://localhost:63342/gyrogpsc/index.html" useBuiltInWebServerPort="true">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="Go Build.go build git.timovolkmann.de/gyrogpsc/cmd/server" />
|
||||
<item itemvalue="JavaScript Debug.index.html" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="70ae6a46-b58b-4192-b69d-37293bd6e2cf" name="Default Changelist" comment="" />
|
||||
<created>1606852272847</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1606852272847</updated>
|
||||
<workItem from="1606852274006" duration="9755000" />
|
||||
<workItem from="1606894728295" duration="599000" />
|
||||
<workItem from="1607244448990" duration="217000" />
|
||||
<workItem from="1607244781024" duration="2248000" />
|
||||
<workItem from="1607419204431" duration="595000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
<option name="oldMeFiltersMigrated" value="true" />
|
||||
</component>
|
||||
<component name="VgoProject">
|
||||
<integration-enabled>true</integration-enabled>
|
||||
</component>
|
||||
<component name="WindowStateProjectService">
|
||||
<state x="752" y="451" key="#GOROOT" timestamp="1606385156675">
|
||||
<screen x="0" y="0" width="1920" height="1040" />
|
||||
</state>
|
||||
<state x="752" y="451" key="#GOROOT/0.0.1920.1040/-1440.113.1440.860@0.0.1920.1040" timestamp="1606385156675" />
|
||||
<state x="640" y="256" key="#com.intellij.openapi.updateSettings.impl.PluginUpdateInfoDialog" timestamp="1607244535893">
|
||||
<screen x="0" y="0" width="1920" height="1040" />
|
||||
</state>
|
||||
<state x="640" y="256" key="#com.intellij.openapi.updateSettings.impl.PluginUpdateInfoDialog/0.0.1920.1040/-1440.113.1440.860@0.0.1920.1040" timestamp="1607244535893" />
|
||||
<state width="1877" height="282" key="GridCell.Tab.0.bottom" timestamp="1606865976622">
|
||||
<screen x="0" y="0" width="1920" height="1040" />
|
||||
</state>
|
||||
<state width="1877" height="282" key="GridCell.Tab.0.bottom/0.0.1920.1040/-1440.113.1440.860@0.0.1920.1040" timestamp="1606865976622" />
|
||||
<state width="1877" height="282" key="GridCell.Tab.0.center" timestamp="1606865976622">
|
||||
<screen x="0" y="0" width="1920" height="1040" />
|
||||
</state>
|
||||
<state width="1877" height="282" key="GridCell.Tab.0.center/0.0.1920.1040/-1440.113.1440.860@0.0.1920.1040" timestamp="1606865976622" />
|
||||
<state width="1877" height="282" key="GridCell.Tab.0.left" timestamp="1606865976622">
|
||||
<screen x="0" y="0" width="1920" height="1040" />
|
||||
</state>
|
||||
<state width="1877" height="282" key="GridCell.Tab.0.left/0.0.1920.1040/-1440.113.1440.860@0.0.1920.1040" timestamp="1606865976622" />
|
||||
<state width="1877" height="282" key="GridCell.Tab.0.right" timestamp="1606865976622">
|
||||
<screen x="0" y="0" width="1920" height="1040" />
|
||||
</state>
|
||||
<state width="1877" height="282" key="GridCell.Tab.0.right/0.0.1920.1040/-1440.113.1440.860@0.0.1920.1040" timestamp="1606865976622" />
|
||||
<state x="540" y="263" key="IDE.errors.dialog" timestamp="1606385007112">
|
||||
<screen x="0" y="0" width="1920" height="1040" />
|
||||
</state>
|
||||
<state x="540" y="263" key="IDE.errors.dialog/0.0.1920.1040/-1440.113.1440.860@0.0.1920.1040" timestamp="1606385007112" />
|
||||
<state x="461" y="165" key="SettingsEditor" timestamp="1606563366122">
|
||||
<screen x="0" y="0" width="1920" height="1040" />
|
||||
</state>
|
||||
<state x="461" y="165" key="SettingsEditor/0.0.1920.1040/-1440.113.1440.860@0.0.1920.1040" timestamp="1606563366122" />
|
||||
</component>
|
||||
</project>
|
||||
378
.idea/workspace.xml~develop
generated
Normal file
378
.idea/workspace.xml~develop
generated
Normal file
@ -0,0 +1,378 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="BranchesTreeState">
|
||||
<expand>
|
||||
<path>
|
||||
<item name="ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
||||
<item name="LOCAL_ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
||||
<item name="LOCAL_ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
||||
<item name="GROUP_NODE:sensor" type="e8cecc67:BranchNodeDescriptor" />
|
||||
</path>
|
||||
</expand>
|
||||
<select>
|
||||
<path>
|
||||
<item name="ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
||||
<item name="LOCAL_ROOT" type="e8cecc67:BranchNodeDescriptor" />
|
||||
<item name="GROUP_NODE:sensor" type="e8cecc67:BranchNodeDescriptor" />
|
||||
<item name="BRANCH:sensor/relative" type="e8cecc67:BranchNodeDescriptor" />
|
||||
</path>
|
||||
</select>
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="99c957e4-aa42-481d-843d-3fbc901e0f79" name="Default Changelist" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/cmd/serial_only/serial_only.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/serial_ubx/serial.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ublox/decode.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ublox/messages.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/ublox/strings_navpvt.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/go.mod" beforeDir="false" afterPath="$PROJECT_DIR$/go.mod" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/go.sum" beforeDir="false" afterPath="$PROJECT_DIR$/go.sum" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/hyperimu.json" beforeDir="false" afterPath="$PROJECT_DIR$/hyperimu.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/.gitattributes" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/.gitignore" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/CONTRIBUTING.md" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/ISSUE_TEMPLATE.md" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/LICENSE.md" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/README.md" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/Theory.md" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Dead Reckoning/Example1_calibrateSensor/Example1_calibrateSensor.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Dead Reckoning/Example2_getIMUData/Example2_getIMUData.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Dead Reckoning/Example3_getSensorStatus/Example3_getSensorStatus.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Dead Reckoning/Example4_vehicleDynamics/Example4_vehicleDynamics.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example10_AltitudeMSL/Example10_AltitudeMSL.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example11_ResetModule/Example1_FactoryDefaultviaI2C/Example1_FactoryDefaultviaI2C.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example11_ResetModule/Example2_FactoryDefaultsviaSerial/Example2_FactoryDefaultsviaSerial.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example12_UseUart/Example12_UseUart.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example13_PVT/Example1_AutoPVT/Example1_AutoPVT.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example13_PVT/Example2_AutoPVT_ExplicitUpdate/Example2_AutoPVT_ExplicitUpdate.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example13_PVT/Example3_AssumeAutoPVTviaUart/Example3_AssumeAutoPVTviaUart.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example14_DebugOutput/Example14_DebugOutput.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example15_GetDateTime/Example15_GetDateTime.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example16_Nanosecond_MaxOutput/Example16_Nanosecond_MaxOutput.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example16_PartialSecond_MaxOutput/Example16_PartialSecond_MaxOutput.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example17_Geofence/Example17_Geofence.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example18_PowerSaveMode/Example18_PowerSaveMode.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example19_DynamicModel/Example19_DynamicModel.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example1_BasicNMEARead/Example1_BasicNMEARead.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example20_SendCustomCommand/Example20_SendCustomCommand.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example21_ModuleInfo/Example21_ModuleInfo.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example22_PowerOff/Example22_PowerOff.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example2_NMEAParsing/Example2_NMEAParsing.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example3_GetPosition/Example3_GetPosition.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example4_FixType/Example4_FixType.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example5_SpeedHeadingPrecision/Example5_SpeedHeadingPrecision.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example6_EnableNMEASentences/Example6_EnableNMEASentences.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example7_OutputRate/Example7_OutputRate.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example8_GetProtocolVersion/Example8_GetProtocolVersion.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Example9_ChangeI2CAddress/Example9_ChangeI2CAddress.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/NEO-M8P-2/Example1_EnableRTCM/Example1_EnableRTCM.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/NEO-M8P-2/Example2_StartRTCMBase/Example2_StartRTCMBase.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/NEO-M8P-2/Example3_BaseWithLCD/Example3_BaseWithLCD.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Series_6_7/Example1_GetPositionAndTime_Series_6_7/Example1_GetPositionAndTime_Series_6_7.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Series_6_7/Example1_GetPositionAndTime_Series_6_7/SparkFun_Ublox_Arduino_Library_Series_6_7.cpp" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/Series_6_7/Example1_GetPositionAndTime_Series_6_7/SparkFun_Ublox_Arduino_Library_Series_6_7.h" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/ZED-F9P/Example10_GetHighPrecisionPositionAndAccuracy/Example10_GetHighPrecisionPositionAndAccuracy.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/ZED-F9P/Example11_GetHighPrecisionPositionUsingDouble/Example11_GetHighPrecisionPositionUsingDouble.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/ZED-F9P/Example11_autoHPPOSLLH/Example11_autoHPPOSLLH.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/ZED-F9P/Example11_setStaticPosition/Example11_setStaticPosition.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/ZED-F9P/Example1_GetPositionAccuracy/Example1_GetPositionAccuracy.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/ZED-F9P/Example2_ValConfigurationMethod/Example2_ValConfigurationMethod.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/ZED-F9P/Example3_StartRTCMBase/Example3_StartRTCMBase.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/ZED-F9P/Example4_BaseWithLCD/Example4_BaseWithLCD.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/ZED-F9P/Example5_RelativePositioningInformation/Example5_RelativePositioningInformation.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/ZED-F9P/Example6_GetVal/Example6_GetVal.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/ZED-F9P/Example7_SetVal/Example7_SetVal.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/ZED-F9P/Example8_GetSetPortSettings/Example8_GetSetPortSettings.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/examples/ZED-F9P/Example9_multiSetVal/Example9_multiSetVal.ino" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/keywords.txt" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/library.properties" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/src/SparkFun_Ublox_Arduino_Library.cpp" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/src/SparkFun_Ublox_Arduino_Library.h" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library/src/u-blox_config_keys.h" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial/serial.go" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/server.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/server/server.go" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="Go Application" />
|
||||
<option value="Go File" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="GOROOT" path="/usr/local/Cellar/go/1.15.2/libexec" />
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_BRANCH_BY_REPOSITORY">
|
||||
<map>
|
||||
<entry key="$PROJECT_DIR$" value="master" />
|
||||
</map>
|
||||
</option>
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectId" id="1jq0r5aMzeueG8kqyThltUQyqCa" />
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="DefaultGoTemplateProperty" value="Go File" />
|
||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||
<property name="configurable.Global.GOPATH.is.expanded" value="true" />
|
||||
<property name="configurable.Module.GOPATH.is.expanded" value="true" />
|
||||
<property name="configurable.Project.GOPATH.is.expanded" value="true" />
|
||||
<property name="go.import.settings.migrated" value="true" />
|
||||
<property name="go.sdk.automatically.set" value="true" />
|
||||
<property name="go.tried.to.enable.integration.vgo.integrator" value="true" />
|
||||
<property name="last_opened_file_path" value="$USER_HOME$" />
|
||||
<property name="settings.editor.selected.configurable" value="preferences.pluginManager" />
|
||||
</component>
|
||||
<component name="RecentsManager">
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="$PROJECT_DIR$/cmd/server" />
|
||||
<recent name="$PROJECT_DIR$/serial_ubx" />
|
||||
<recent name="$PROJECT_DIR$" />
|
||||
<recent name="$PROJECT_DIR$/ublox" />
|
||||
<recent name="$PROJECT_DIR$/serial" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager" selected="Go Build.go build git.timovolkmann.de/gyrogpsc/cmd/serial_only">
|
||||
<configuration name="go build git.timovolkmann.de/gyrogpsc/cmd/serial_only" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true" nameIsGenerated="true">
|
||||
<module name="gyrogpsc" />
|
||||
<working_directory value="$PROJECT_DIR$" />
|
||||
<kind value="PACKAGE" />
|
||||
<filePath value="$PROJECT_DIR$/cmd/serial_only/serial_only.go" />
|
||||
<package value="git.timovolkmann.de/gyrogpsc/cmd/serial_only" />
|
||||
<directory value="$PROJECT_DIR$" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="go build git.timovolkmann.de/gyrogpsc/serial" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true" nameIsGenerated="true">
|
||||
<module name="gyrogpsc" />
|
||||
<working_directory value="$PROJECT_DIR$" />
|
||||
<kind value="PACKAGE" />
|
||||
<filePath value="$PROJECT_DIR$/serial/serial.go" />
|
||||
<package value="git.timovolkmann.de/gyrogpsc/serial" />
|
||||
<directory value="$PROJECT_DIR$" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="go build server.go" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true" nameIsGenerated="true">
|
||||
<module name="gyrogpsc" />
|
||||
<working_directory value="$PROJECT_DIR$" />
|
||||
<kind value="FILE" />
|
||||
<filePath value="$PROJECT_DIR$/server.go" />
|
||||
<directory value="$PROJECT_DIR$" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="Go Build.go build git.timovolkmann.de/gyrogpsc/cmd/serial_only" />
|
||||
<item itemvalue="Go Build.go build git.timovolkmann.de/gyrogpsc/serial" />
|
||||
<item itemvalue="Go Build.go build server.go" />
|
||||
<item itemvalue="Go Build.go build server.go" />
|
||||
<item itemvalue="Go Build.go build git.timovolkmann.de/gyrogpsc/serial" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="99c957e4-aa42-481d-843d-3fbc901e0f79" name="Default Changelist" comment="" />
|
||||
<created>1604516509922</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1604516509922</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00001" summary="initial working version">
|
||||
<created>1604747925521</created>
|
||||
<option name="number" value="00001" />
|
||||
<option name="presentableId" value="LOCAL-00001" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1604747925521</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00002" summary="added dispatcher.go">
|
||||
<created>1604747940729</created>
|
||||
<option name="number" value="00002" />
|
||||
<option name="presentableId" value="LOCAL-00002" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1604747940729</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00003" summary="3d orientation visualization html/css">
|
||||
<created>1604768327573</created>
|
||||
<option name="number" value="00003" />
|
||||
<option name="presentableId" value="LOCAL-00003" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1604768327573</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00004" summary="switched to relative sensor data (gyroscope)">
|
||||
<created>1604777752387</created>
|
||||
<option name="number" value="00004" />
|
||||
<option name="presentableId" value="LOCAL-00004" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1604777752387</updated>
|
||||
</task>
|
||||
<task id="LOCAL-00005" summary="changed orientation">
|
||||
<created>1605444355479</created>
|
||||
<option name="number" value="00005" />
|
||||
<option name="presentableId" value="LOCAL-00005" />
|
||||
<option name="project" value="LOCAL" />
|
||||
<updated>1605444355479</updated>
|
||||
</task>
|
||||
<option name="localTasksCounter" value="6" />
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
<option name="TAB_STATES">
|
||||
<map>
|
||||
<entry key="MAIN">
|
||||
<value>
|
||||
<State>
|
||||
<option name="FILTERS">
|
||||
<map>
|
||||
<entry key="branch">
|
||||
<value>
|
||||
<list>
|
||||
<option value="sensor/relative" />
|
||||
</list>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</State>
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
<option name="oldMeFiltersMigrated" value="true" />
|
||||
</component>
|
||||
<component name="VcsManagerConfiguration">
|
||||
<MESSAGE value="initial working version" />
|
||||
<MESSAGE value="added dispatcher.go" />
|
||||
<MESSAGE value="3d orientation visualization html/css" />
|
||||
<MESSAGE value="switched to relative sensor data (gyroscope)" />
|
||||
<MESSAGE value="changed orientation" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="changed orientation" />
|
||||
</component>
|
||||
<component name="VgoProject">
|
||||
<integration-enabled>true</integration-enabled>
|
||||
</component>
|
||||
<component name="WindowStateProjectService">
|
||||
<state x="640" y="377" key="#Go_Modules" timestamp="1604584628285">
|
||||
<screen x="0" y="23" width="1680" height="1027" />
|
||||
</state>
|
||||
<state x="640" y="377" key="#Go_Modules/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604584628285" />
|
||||
<state x="603" y="247" key="#xdebugger.evaluate" timestamp="1604750409547">
|
||||
<screen x="0" y="23" width="1680" height="1027" />
|
||||
</state>
|
||||
<state x="603" y="247" key="#xdebugger.evaluate/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604750409547" />
|
||||
<state x="100" y="123" width="1480" height="827" key="DiffContextDialog" timestamp="1604517986662">
|
||||
<screen x="0" y="23" width="1680" height="1027" />
|
||||
</state>
|
||||
<state x="100" y="123" width="1480" height="827" key="DiffContextDialog/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604517986662" />
|
||||
<state x="739" y="405" key="EnvironmentVariablesDialog" timestamp="1604585759907">
|
||||
<screen x="0" y="23" width="1680" height="1027" />
|
||||
</state>
|
||||
<state x="739" y="405" key="EnvironmentVariablesDialog/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604585759907" />
|
||||
<state width="1638" height="346" key="GridCell.Tab.-1.bottom" timestamp="1604750445987">
|
||||
<screen x="0" y="23" width="1680" height="1027" />
|
||||
</state>
|
||||
<state width="1638" height="346" key="GridCell.Tab.-1.bottom/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604750445987" />
|
||||
<state width="1638" height="346" key="GridCell.Tab.-1.center" timestamp="1604750445987">
|
||||
<screen x="0" y="23" width="1680" height="1027" />
|
||||
</state>
|
||||
<state width="1638" height="346" key="GridCell.Tab.-1.center/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604750445987" />
|
||||
<state width="1638" height="346" key="GridCell.Tab.-1.left" timestamp="1604750445987">
|
||||
<screen x="0" y="23" width="1680" height="1027" />
|
||||
</state>
|
||||
<state width="1638" height="346" key="GridCell.Tab.-1.left/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604750445987" />
|
||||
<state width="1638" height="346" key="GridCell.Tab.-1.right" timestamp="1604750445987">
|
||||
<screen x="0" y="23" width="1680" height="1027" />
|
||||
</state>
|
||||
<state width="1638" height="346" key="GridCell.Tab.-1.right/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604750445987" />
|
||||
<state width="1878" height="249" key="GridCell.Tab.0.bottom" timestamp="1606326600270">
|
||||
<screen x="0" y="23" width="1920" height="1177" />
|
||||
</state>
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.bottom/0.-1417.2560.1417/0.23.1680.1027@0.-1417.2560.1417" timestamp="1604948042531" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.bottom/0.23.1680.1027/0.-1417.2560.1417@0.-1417.2560.1417" timestamp="1604913985770" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.bottom/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604760252890" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.bottom/0.23.1680.1027@0.23.1680.1027" timestamp="1604933111805" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.bottom/0.23.1920.1116@0.23.1920.1116" timestamp="1605380018474" />
|
||||
<state width="1878" height="249" key="GridCell.Tab.0.bottom/0.23.1920.1177/0.-1417.2560.1417@0.23.1920.1177" timestamp="1606326600270" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.bottom/0.23.1920.1177@0.23.1920.1177" timestamp="1605533225921" />
|
||||
<state width="1878" height="249" key="GridCell.Tab.0.center" timestamp="1606326600270">
|
||||
<screen x="0" y="23" width="1920" height="1177" />
|
||||
</state>
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.center/0.-1417.2560.1417/0.23.1680.1027@0.-1417.2560.1417" timestamp="1604948042530" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.center/0.23.1680.1027/0.-1417.2560.1417@0.-1417.2560.1417" timestamp="1604913985769" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.center/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604760252890" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.center/0.23.1680.1027@0.23.1680.1027" timestamp="1604933111805" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.center/0.23.1920.1116@0.23.1920.1116" timestamp="1605380018473" />
|
||||
<state width="1878" height="249" key="GridCell.Tab.0.center/0.23.1920.1177/0.-1417.2560.1417@0.23.1920.1177" timestamp="1606326600270" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.center/0.23.1920.1177@0.23.1920.1177" timestamp="1605533225920" />
|
||||
<state width="1878" height="249" key="GridCell.Tab.0.left" timestamp="1606326600269">
|
||||
<screen x="0" y="23" width="1920" height="1177" />
|
||||
</state>
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.left/0.-1417.2560.1417/0.23.1680.1027@0.-1417.2560.1417" timestamp="1604948042530" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.left/0.23.1680.1027/0.-1417.2560.1417@0.-1417.2560.1417" timestamp="1604913985768" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.left/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604760252889" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.left/0.23.1680.1027@0.23.1680.1027" timestamp="1604933111805" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.left/0.23.1920.1116@0.23.1920.1116" timestamp="1605380018472" />
|
||||
<state width="1878" height="249" key="GridCell.Tab.0.left/0.23.1920.1177/0.-1417.2560.1417@0.23.1920.1177" timestamp="1606326600269" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.left/0.23.1920.1177@0.23.1920.1177" timestamp="1605533225919" />
|
||||
<state width="1878" height="249" key="GridCell.Tab.0.right" timestamp="1606326600270">
|
||||
<screen x="0" y="23" width="1920" height="1177" />
|
||||
</state>
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.right/0.-1417.2560.1417/0.23.1680.1027@0.-1417.2560.1417" timestamp="1604948042531" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.right/0.23.1680.1027/0.-1417.2560.1417@0.-1417.2560.1417" timestamp="1604913985770" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.right/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604760252890" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.right/0.23.1680.1027@0.23.1680.1027" timestamp="1604933111805" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.right/0.23.1920.1116@0.23.1920.1116" timestamp="1605380018473" />
|
||||
<state width="1878" height="249" key="GridCell.Tab.0.right/0.23.1920.1177/0.-1417.2560.1417@0.23.1920.1177" timestamp="1606326600270" />
|
||||
<state width="1638" height="273" key="GridCell.Tab.0.right/0.23.1920.1177@0.23.1920.1177" timestamp="1605533225920" />
|
||||
<state width="1638" height="346" key="GridCell.Tab.1.bottom" timestamp="1604750442086">
|
||||
<screen x="0" y="23" width="1680" height="1027" />
|
||||
</state>
|
||||
<state width="1638" height="346" key="GridCell.Tab.1.bottom/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604750442086" />
|
||||
<state width="1638" height="346" key="GridCell.Tab.1.center" timestamp="1604750442085">
|
||||
<screen x="0" y="23" width="1680" height="1027" />
|
||||
</state>
|
||||
<state width="1638" height="346" key="GridCell.Tab.1.center/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604750442085" />
|
||||
<state width="1638" height="346" key="GridCell.Tab.1.left" timestamp="1604750442085">
|
||||
<screen x="0" y="23" width="1680" height="1027" />
|
||||
</state>
|
||||
<state width="1638" height="346" key="GridCell.Tab.1.left/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604750442085" />
|
||||
<state width="1638" height="346" key="GridCell.Tab.1.right" timestamp="1604750442085">
|
||||
<screen x="0" y="23" width="1680" height="1027" />
|
||||
</state>
|
||||
<state width="1638" height="346" key="GridCell.Tab.1.right/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604750442085" />
|
||||
<state x="204" y="155" width="1501" height="766" key="SettingsEditor" timestamp="1605609479939">
|
||||
<screen x="0" y="23" width="1920" height="1177" />
|
||||
</state>
|
||||
<state x="179" y="138" width="1501" height="766" key="SettingsEditor/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604757277174" />
|
||||
<state x="204" y="155" key="SettingsEditor/0.23.1920.1177/0.-1417.2560.1417@0.23.1920.1177" timestamp="1605609479939" />
|
||||
<state width="840" height="513" key="XDebugger.FullValuePopup" timestamp="1604750505120">
|
||||
<screen x="0" y="23" width="1680" height="1027" />
|
||||
</state>
|
||||
<state width="840" height="513" key="XDebugger.FullValuePopup/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604750505120" />
|
||||
<state x="505" y="250" width="670" height="676" key="search.everywhere.popup" timestamp="1604757918385">
|
||||
<screen x="0" y="23" width="1680" height="1027" />
|
||||
</state>
|
||||
<state x="505" y="250" width="670" height="676" key="search.everywhere.popup/0.23.1680.1027/0.-1417.2560.1417@0.23.1680.1027" timestamp="1604757918385" />
|
||||
<state x="596" y="393" key="vcs.readOnlyHandler.ReadOnlyStatusDialog" timestamp="1605566567276">
|
||||
<screen x="0" y="23" width="1920" height="1177" />
|
||||
</state>
|
||||
<state x="596" y="393" key="vcs.readOnlyHandler.ReadOnlyStatusDialog/0.23.1920.1177/0.-1417.2560.1417@0.23.1920.1177" timestamp="1605566567276" />
|
||||
</component>
|
||||
</project>
|
||||
Binary file not shown.
@ -1 +0,0 @@
|
||||
ˆ‰œœ+¥¶Îz {Hello Badger
|
||||
@ -1 +0,0 @@
|
||||
38895
|
||||
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
;µÐÕ0.Ñþý|uG…Hello Badger
|
||||
@ -1 +0,0 @@
|
||||
38895
|
||||
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
枯華虌𤥢崱v叐<76>Hello Badger
|
||||
@ -1 +0,0 @@
|
||||
27554
|
||||
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
ßÁuðÓJäe»|?^<5E>¢˜Hello Badger
|
||||
@ -1 +0,0 @@
|
||||
38895
|
||||
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
ˆ‰œœ+¥¶Îz {Hello Badger
|
||||
@ -1 +0,0 @@
|
||||
38895
|
||||
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
;µÐÕ0.Ñþý|uG…Hello Badger
|
||||
@ -1 +0,0 @@
|
||||
38895
|
||||
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
枯華虌𤥢崱v叐<76>Hello Badger
|
||||
@ -1 +0,0 @@
|
||||
6958
|
||||
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
ßÁuðÓJäe»|?^<5E>¢˜Hello Badger
|
||||
@ -1 +0,0 @@
|
||||
6958
|
||||
Binary file not shown.
@ -1,72 +0,0 @@
|
||||
/**
|
||||
only for testing purposes
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"git.timovolkmann.de/gyrogpsc/core"
|
||||
"git.timovolkmann.de/gyrogpsc/storage"
|
||||
"git.timovolkmann.de/gyrogpsc/web"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/viper"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
)
|
||||
|
||||
func main() {
|
||||
go func() {
|
||||
logrus.Println(http.ListenAndServe("localhost:6060", nil))
|
||||
}()
|
||||
|
||||
conf := configurationFromFile()
|
||||
|
||||
logrus.Debug(conf)
|
||||
|
||||
repo := storage.NewRepository(conf)
|
||||
disp := core.NewDispatcher()
|
||||
|
||||
service := core.NewTrackingService(conf, repo, disp)
|
||||
|
||||
go func() {
|
||||
// Long Run
|
||||
//service.LoadTracking(uuid.MustParse("06b05aa3-6a13-4ffb-8ac7-cd35dfc0f949"))
|
||||
// Tunnel
|
||||
service.LoadTracking(uuid.MustParse("c3dbee7c-512a-4cc8-9804-21f0f2cf3c22"), true)
|
||||
|
||||
//pprof.StopCPUProfile()
|
||||
//os.Exit(0)
|
||||
}()
|
||||
|
||||
web.CreateServer(service, disp, conf)
|
||||
}
|
||||
|
||||
func configurationFromFile() *core.Configuration {
|
||||
viper.SetDefault("collectors.porttcp", ":3010")
|
||||
viper.SetDefault("collectors.portserial", "/dev/tty.usbmodem14201")
|
||||
viper.SetDefault("webserver.port", ":3011")
|
||||
viper.SetDefault("pipeline.publishIntervalMs", 50)
|
||||
viper.SetDefault("pipeline.syncUpdateIntervalMs", 494)
|
||||
viper.SetDefault("debuglevel", "INFO")
|
||||
|
||||
viper.SetConfigName("gpsconfig") // name of config file (without extension)
|
||||
viper.SetConfigType("yaml")
|
||||
viper.AddConfigPath(".")
|
||||
viper.AddConfigPath("./../../")
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
logrus.Warn("couldn't find config file. using standard configuration")
|
||||
}
|
||||
|
||||
c := core.Configuration{}
|
||||
if err := viper.Unmarshal(&c); err != nil {
|
||||
logrus.Debug("couldn't load config...")
|
||||
logrus.Error(err)
|
||||
}
|
||||
lvl, err := logrus.ParseLevel(c.Debuglevel)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
logrus.SetLevel(lvl)
|
||||
return &c
|
||||
}
|
||||
14
cmd/serial_only/serial_only.go
Normal file
14
cmd/serial_only/serial_only.go
Normal file
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"git.timovolkmann.de/gyrogpsc/serial_ubx"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
r, err := serial_ubx.Setup("/dev/tty.usbmodem14201")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
r.Printloop()
|
||||
}
|
||||
@ -1,30 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"git.timovolkmann.de/gyrogpsc/core"
|
||||
"git.timovolkmann.de/gyrogpsc/storage"
|
||||
"git.timovolkmann.de/gyrogpsc/web"
|
||||
"github.com/sirupsen/logrus"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
"git.timovolkmann.de/gyrogpsc/dispatcher"
|
||||
gnet "git.timovolkmann.de/gyrogpsc/net"
|
||||
)
|
||||
|
||||
const (
|
||||
TCP_PORT = ":3010"
|
||||
HTTP_PORT = ":3011"
|
||||
//SERIAL_PORT = "/dev/tty.usbmodem14201"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// launch profiling server in goroutine to debug performance issues
|
||||
go func() {
|
||||
logrus.Println(http.ListenAndServe("localhost:6060", nil))
|
||||
}()
|
||||
|
||||
// load configuration from file
|
||||
conf := core.ConfigurationFromFile()
|
||||
// initialize persistence layer
|
||||
repo := storage.NewRepository(conf)
|
||||
// initialize message distribution layer
|
||||
disp := core.NewDispatcher()
|
||||
|
||||
// initialize core logic service and inject
|
||||
service := core.NewTrackingService(conf, repo, disp)
|
||||
|
||||
// launch webserver
|
||||
web.CreateServer(service, disp, conf)
|
||||
d := dispatcher.New()
|
||||
collectRoutines(d)
|
||||
gnet.NewHttpServer(d, HTTP_PORT)
|
||||
}
|
||||
|
||||
func collectRoutines(d *dispatcher.Dispatcher) {
|
||||
// collectRoutines Serial UBX Sensor Data
|
||||
//go gnet.SerialUbxCollector(d, SERIAL_PORT)
|
||||
// collectRoutines TCP JSON Sensor Data
|
||||
go gnet.TcpJsonCollector(d, TCP_PORT)
|
||||
}
|
||||
|
||||
25
cmd/server_only/server_only.go
Normal file
25
cmd/server_only/server_only.go
Normal file
@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"git.timovolkmann.de/gyrogpsc/dispatcher"
|
||||
gnet "git.timovolkmann.de/gyrogpsc/net"
|
||||
)
|
||||
|
||||
const (
|
||||
TCP_PORT = ":3010"
|
||||
HTTP_PORT = ":3011"
|
||||
SERIAL_PORT = "/dev/tty.usbmodem14201"
|
||||
)
|
||||
|
||||
func main() {
|
||||
d := dispatcher.New()
|
||||
collectRoutines(d)
|
||||
gnet.NewHttpServer(d, HTTP_PORT)
|
||||
}
|
||||
|
||||
func collectRoutines(d *dispatcher.Dispatcher) {
|
||||
// collectRoutines Serial UBX Sensor Data
|
||||
go gnet.SerialUbxCollector(d, SERIAL_PORT)
|
||||
// collectRoutines TCP JSON Sensor Data
|
||||
go gnet.TcpJsonCollector(d, TCP_PORT)
|
||||
}
|
||||
@ -1,235 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.timovolkmann.de/gyrogpsc/ublox"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.bug.st/serial"
|
||||
"net"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Collector interface {
|
||||
Collect()
|
||||
Stop()
|
||||
OutChannel() chan interface{}
|
||||
}
|
||||
|
||||
type CollectorType string
|
||||
|
||||
const (
|
||||
SERIAL CollectorType = "SERIAL_COLLECTOR"
|
||||
TCP CollectorType = "TCP_COLLECTOR"
|
||||
)
|
||||
|
||||
var tcpSingleton *tcpCollector
|
||||
|
||||
func NewCollector(config *Configuration, typ CollectorType) Collector {
|
||||
var coll Collector
|
||||
switch typ {
|
||||
case SERIAL:
|
||||
coll = newSerial(config)
|
||||
case TCP:
|
||||
if tcpSingleton == nil {
|
||||
tcpSingleton = newTcp(config)
|
||||
}
|
||||
coll = tcpSingleton
|
||||
default:
|
||||
panic("selected collector type not implemented")
|
||||
}
|
||||
return coll
|
||||
}
|
||||
|
||||
type serialCollector struct {
|
||||
out chan interface{}
|
||||
config *Configuration
|
||||
}
|
||||
|
||||
func (s *serialCollector) OutChannel() chan interface{} {
|
||||
return s.out
|
||||
}
|
||||
|
||||
func (s *serialCollector) Collect() {
|
||||
go func(ch chan interface{}) {
|
||||
logrus.Println("start serial collector")
|
||||
mode := &serial.Mode{
|
||||
BaudRate: 115200,
|
||||
}
|
||||
port, err := serial.Open(s.config.Collectors.SerialCollectorPort, mode)
|
||||
if err != nil {
|
||||
logrus.Warn("can't open serial port:", err)
|
||||
//if e, ok := err.(serial.PortError); ok && e.Code() == serial.PortBusy {
|
||||
for i := 3; i < 20; i = i + 2 {
|
||||
logrus.Warnf("try again in -> %vms", i*i)
|
||||
time.Sleep(time.Millisecond * time.Duration(i*i))
|
||||
port, err = serial.Open(s.config.Collectors.SerialCollectorPort, mode)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
logrus.Errorln(err)
|
||||
}
|
||||
//}
|
||||
}
|
||||
|
||||
decoder := ublox.NewDecoder(port)
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logrus.Infoln("stopped collecting channel: serial")
|
||||
}
|
||||
logrus.Infoln("close serial port")
|
||||
port.Close()
|
||||
}()
|
||||
maxSkip := 0
|
||||
loop:
|
||||
for {
|
||||
//logrus.Trace("serial collector running")
|
||||
meas, err2 := decoder.Decode()
|
||||
if err2 != nil {
|
||||
if err2.Error() == "NMEA not implemented" {
|
||||
continue
|
||||
}
|
||||
logrus.Println("serial read err:", err2)
|
||||
break
|
||||
}
|
||||
select {
|
||||
case ch <- meas:
|
||||
maxSkip = 0
|
||||
default:
|
||||
logrus.Traceln("skip collecting serial messages")
|
||||
if maxSkip >= 10 {
|
||||
break loop
|
||||
}
|
||||
maxSkip++
|
||||
}
|
||||
|
||||
}
|
||||
logrus.Println("serial collector stopped")
|
||||
}(s.out)
|
||||
}
|
||||
|
||||
func (s *serialCollector) Stop() {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
logrus.Debugln("channel already closed")
|
||||
}
|
||||
}()
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case <-s.out:
|
||||
logrus.Debugln("waiting")
|
||||
default:
|
||||
logrus.Debugln("breaking")
|
||||
break loop
|
||||
}
|
||||
}
|
||||
close(s.out)
|
||||
s.out = make(chan interface{}, 16)
|
||||
}
|
||||
|
||||
func newSerial(config *Configuration) *serialCollector {
|
||||
return &serialCollector{
|
||||
out: make(chan interface{}, 16),
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
type tcpCollector struct {
|
||||
out chan interface{}
|
||||
config *Configuration
|
||||
}
|
||||
|
||||
func (t *tcpCollector) OutChannel() chan interface{} {
|
||||
return t.out
|
||||
}
|
||||
|
||||
func (t *tcpCollector) Collect() {
|
||||
logrus.Info("starting tcp collector")
|
||||
}
|
||||
|
||||
func (t *tcpCollector) Stop() {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
logrus.Debugln("channel already closed")
|
||||
}
|
||||
}()
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case <-t.out:
|
||||
logrus.Debugln("waiting")
|
||||
default:
|
||||
logrus.Debugln("breaking")
|
||||
break loop
|
||||
}
|
||||
}
|
||||
close(t.out)
|
||||
t.out = make(chan interface{}, 16)
|
||||
}
|
||||
|
||||
func newTcp(config *Configuration) *tcpCollector {
|
||||
//func newTcp(proc Processor, config *Configuration) *tcpCollector {
|
||||
logrus.Println("listen for tcp connections on port", config.Collectors.TcpCollectorPort)
|
||||
|
||||
listener, err := net.Listen("tcp", config.Collectors.TcpCollectorPort)
|
||||
if err != nil {
|
||||
fmt.Println("Error listening:", err)
|
||||
//os.Exit(1)
|
||||
}
|
||||
c := &tcpCollector{
|
||||
out: make(chan interface{}, 16),
|
||||
config: config,
|
||||
}
|
||||
go func() {
|
||||
for {
|
||||
// Listen for an incoming connection.
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
logrus.Errorln("Error accepting: ", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
logrus.Infoln("new incoming tcp connection...")
|
||||
|
||||
// Handle connections in a new goroutine.
|
||||
go c.connectionHandler(conn)
|
||||
}
|
||||
}()
|
||||
return c
|
||||
}
|
||||
|
||||
// handles incoming tcp connections.
|
||||
func (t *tcpCollector) connectionHandler(conn net.Conn) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
logrus.Infoln("stopped collecting tcp: panic")
|
||||
}
|
||||
logrus.Infoln("close connection")
|
||||
conn.Close()
|
||||
}()
|
||||
|
||||
buf := make([]byte, 2048)
|
||||
skipped := 0
|
||||
//loop:
|
||||
for {
|
||||
// Read the incoming connection into the buffer.
|
||||
n, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
fmt.Println("TCP error - reading from connection:", n, err.Error())
|
||||
break
|
||||
}
|
||||
select {
|
||||
case t.out <- buf:
|
||||
skipped = 0
|
||||
default:
|
||||
logrus.Traceln("skip collecting tcp messages")
|
||||
//if skipped >= 10 {
|
||||
// break loop
|
||||
//}
|
||||
skipped++
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,52 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// This struct represents and holds all configurable parameters
|
||||
type Configuration struct {
|
||||
Collectors struct {
|
||||
TcpCollectorPort string `mapstructure:"porttcp"`
|
||||
SerialCollectorPort string `mapstructure:"portserial"`
|
||||
} `mapstructure:"Collectors"`
|
||||
Webserver struct {
|
||||
Port string `mapstructure:"port"`
|
||||
} `mapstructure:"webserver"`
|
||||
Pipeline struct {
|
||||
PublishIntervalMs int `mapstructure:"publishintervalms"`
|
||||
SyncUpdateIntervalMs int `mapstructure:"syncupdateintervalms"`
|
||||
} `mapstructure:"pipeline"`
|
||||
Debuglevel string `mapstructure:"debuglevel"`
|
||||
}
|
||||
|
||||
// Call this function to load configuration from gpsconfig.yml
|
||||
func ConfigurationFromFile() *Configuration {
|
||||
viper.SetDefault("collectors.porttcp", ":3010")
|
||||
viper.SetDefault("collectors.portserial", "/dev/tty.usbmodem14201")
|
||||
viper.SetDefault("webserver.port", ":3011")
|
||||
viper.SetDefault("pipeline.publishIntervalMs", 50)
|
||||
viper.SetDefault("pipeline.syncUpdateIntervalMs", 494)
|
||||
viper.SetDefault("debuglevel", "INFO")
|
||||
|
||||
viper.SetConfigName("gpsconfig") // name of config file (without extension)
|
||||
viper.SetConfigType("yaml")
|
||||
viper.AddConfigPath(".")
|
||||
viper.AddConfigPath("./../../")
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
logrus.Warn("couldn't find config file. using standard configuration")
|
||||
}
|
||||
|
||||
c := Configuration{}
|
||||
if err := viper.Unmarshal(&c); err != nil {
|
||||
logrus.Debug("couldn't load config...")
|
||||
logrus.Error(err)
|
||||
}
|
||||
lvl, err := logrus.ParseLevel(c.Debuglevel)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
logrus.SetLevel(lvl)
|
||||
return &c
|
||||
}
|
||||
@ -1,266 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.timovolkmann.de/gyrogpsc/ublox"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/tidwall/gjson"
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
// holds all sensor data and metadata for a specific recording
|
||||
type Tracking struct {
|
||||
TrackingMetadata
|
||||
Data []SensorData
|
||||
}
|
||||
|
||||
// holds all metadata for a specific recording
|
||||
type TrackingMetadata struct {
|
||||
UUID uuid.UUID
|
||||
TimeCreated time.Time
|
||||
Collectors []CollectorType
|
||||
Size int
|
||||
}
|
||||
|
||||
func newTracking() Tracking {
|
||||
return Tracking{
|
||||
TrackingMetadata: TrackingMetadata{
|
||||
UUID: uuid.New(),
|
||||
},
|
||||
Data: []SensorData{},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Tracking) isEmpty() bool {
|
||||
if len(s.Data) != s.Size {
|
||||
logrus.Errorln("data inconsistent...", len(s.Data), s.Size)
|
||||
}
|
||||
return len(s.Data) == 0
|
||||
}
|
||||
|
||||
// enumerate sources
|
||||
type SourceId string
|
||||
|
||||
const (
|
||||
SOURCE_TCP SourceId = "SOURCE_TCP"
|
||||
SOURCE_SERIAL SourceId = "SOURCE_SERIAL"
|
||||
)
|
||||
|
||||
// internal unified representation for smartphone and ublox sensor data
|
||||
type SensorData struct {
|
||||
//MsgClass string
|
||||
//FixType string
|
||||
itow uint32
|
||||
source SourceId
|
||||
latency int
|
||||
Servertime time.Time
|
||||
Timestamp time.Time
|
||||
Position [3]float64 //`json:",omitempty"`
|
||||
HAcc float64 //`json:",omitempty"`//[H,V]
|
||||
VAcc float64 //`json:",omitempty"`//[H,V]
|
||||
Orientation [3]float64 //`json:",omitempty"`
|
||||
Speed float64 //`json:",omitempty"`
|
||||
HeadDevice float64 //`json:",omitempty"` // Course / Heading of Motion
|
||||
HeadMotion float64 //`json:",omitempty"` // Course / Heading of Motion
|
||||
HeadingAcc float64 //`json:",omitempty"`
|
||||
Gyroscope [3]float64 //`json:",omitempty"`
|
||||
LinearAcc [3]float64 //`json:",omitempty"`
|
||||
|
||||
}
|
||||
|
||||
func (s *SensorData) Source() SourceId {
|
||||
return s.source
|
||||
}
|
||||
|
||||
func (s *SensorData) SetSource(si SourceId) {
|
||||
s.source = si
|
||||
}
|
||||
|
||||
func (s SensorData) isSameEpoch(n SensorData) bool {
|
||||
if n.itow == 0 {
|
||||
return false
|
||||
}
|
||||
return s.itow == n.itow
|
||||
}
|
||||
|
||||
// Consolidates two sensordata elements if they are in the same epoch
|
||||
func (s SensorData) ConsolidateEpochsOnly(n SensorData) SensorData {
|
||||
s.checkSources(&n)
|
||||
if s.isSameEpoch(n) {
|
||||
null := SensorData{}
|
||||
|
||||
if n.Timestamp == null.Timestamp {
|
||||
n.Timestamp = s.Timestamp
|
||||
}
|
||||
if n.Position == null.Position {
|
||||
n.Position = s.Position
|
||||
}
|
||||
if n.Orientation == null.Orientation {
|
||||
n.Orientation = s.Orientation
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Consolidates two sensordata elements but ignores timestamps
|
||||
func (s SensorData) ConsolidateExTime(n SensorData) SensorData {
|
||||
s.checkSources(&n)
|
||||
null := SensorData{}
|
||||
|
||||
if n.Position == null.Position {
|
||||
n.Position = s.Position
|
||||
}
|
||||
if n.Orientation == null.Orientation {
|
||||
n.Orientation = s.Orientation
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (s *SensorData) checkSources(n *SensorData) {
|
||||
if (s.source != n.source && *s != SensorData{}) {
|
||||
logrus.Println(s)
|
||||
logrus.Println(n)
|
||||
logrus.Fatalln("Do not consolidate SensorData from different Sources")
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
errNotImplemented = errors.New("message not implemented")
|
||||
errRawMessage = errors.New("raw message")
|
||||
)
|
||||
|
||||
var lastTimeOffsetIphone int64
|
||||
var lastTimeOffsetUblox int64
|
||||
|
||||
func ConvertUbxSensorData(msg interface{}) (*SensorData, error) {
|
||||
sd := &SensorData{
|
||||
//Servertime: time.Now().UTC(),
|
||||
source: SOURCE_SERIAL,
|
||||
}
|
||||
switch v := msg.(type) {
|
||||
case *ublox.NavPvt:
|
||||
//logrus.Println("NAV-PVT")
|
||||
sd.itow = v.ITOW_ms
|
||||
sd.Timestamp = time.Date(int(v.Year_y), time.Month(v.Month_month), int(v.Day_d), int(v.Hour_h), int(v.Min_min), int(v.Sec_s), int(v.Nano_ns), time.UTC)
|
||||
sd.Position[0] = float64(v.Lat_dege7) / 1e+7
|
||||
sd.Position[1] = float64(v.Lon_dege7) / 1e+7
|
||||
sd.Position[2] = float64(v.HMSL_mm) / 1e+3 // mm in m
|
||||
sd.HAcc = float64(v.HAcc_mm) / 1000
|
||||
sd.VAcc = float64(v.VAcc_mm) / 1000
|
||||
sd.HeadMotion = float64(v.HeadMot_dege5) / 1e+5
|
||||
sd.HeadDevice = float64(v.HeadVeh_dege5) / 1e+5
|
||||
sd.HeadingAcc = float64(v.HeadAcc_dege5) / 1e+5
|
||||
sd.Speed = float64(v.GSpeed_mm_s) * 1e-3
|
||||
case *ublox.HnrPvt:
|
||||
//logrus.Println("HNR-PVT")
|
||||
sd.itow = v.ITOW_ms
|
||||
sd.Timestamp = time.Date(int(v.Year_y), time.Month(v.Month_month), int(v.Day_d), int(v.Hour_h), int(v.Min_min), int(v.Sec_s), int(v.Nano_ns), time.UTC)
|
||||
sd.Position[0] = float64(v.Lat_dege7) / 1e+7
|
||||
sd.Position[1] = float64(v.Lon_dege7) / 1e+7
|
||||
sd.Position[2] = float64(v.HMSL_mm) / 1e+3 // mm in m
|
||||
sd.HAcc = float64(v.HAcc) / 1000
|
||||
sd.VAcc = float64(v.VAcc) / 1000
|
||||
sd.HeadMotion = float64(v.HeadMot_dege5) / 1e+5
|
||||
sd.HeadDevice = float64(v.HeadVeh_dege5) / 1e+5
|
||||
sd.HeadingAcc = float64(v.HeadAcc_dege5) / 1e+5
|
||||
sd.Speed = float64(v.GSpeed_mm_s) * 1e-3 // mm in m/s
|
||||
case *ublox.NavAtt:
|
||||
//logrus.Println("NAV-ATT")
|
||||
sd.itow = v.ITOW_ms
|
||||
sd.Orientation[0] = float64(v.Pitch_deg) * 1e-5
|
||||
sd.Orientation[1] = float64(v.Roll_deg) * 1e-5
|
||||
sd.Orientation[2] = float64(v.Heading_deg) * 1e-5
|
||||
case *ublox.RawMessage:
|
||||
return nil, nil
|
||||
default:
|
||||
return nil, errNotImplemented
|
||||
}
|
||||
|
||||
if !sd.Timestamp.IsZero() && sd.Timestamp.Nanosecond() != 0 {
|
||||
lastTimeOffsetUblox = time.Now().UnixNano() - sd.Timestamp.UnixNano()
|
||||
} else {
|
||||
sd.Timestamp = time.Now().UTC().Add(time.Duration(lastTimeOffsetUblox))
|
||||
}
|
||||
|
||||
return sd, nil
|
||||
}
|
||||
|
||||
func ConvertByteSensorData(jsonData []byte) (*SensorData, error) {
|
||||
if gjson.Get(string(jsonData), "os").String() == "hyperimu" {
|
||||
return convertAndroidHyperImu(jsonData)
|
||||
}
|
||||
return convertIPhoneSensorLog(jsonData)
|
||||
}
|
||||
|
||||
func convertIPhoneSensorLog(jsonData []byte) (*SensorData, error) {
|
||||
timestamp := gjson.Get(string(jsonData), "locationTimestamp_since1970").Float()
|
||||
lat := gjson.Get(string(jsonData), "locationLatitude").Float()
|
||||
lon := gjson.Get(string(jsonData), "locationLongitude").Float()
|
||||
alt := gjson.Get(string(jsonData), "locationAltitude").Float()
|
||||
pitch := gjson.Get(string(jsonData), "motionPitch").Float() * 180 / math.Pi
|
||||
roll := gjson.Get(string(jsonData), "motionRoll").Float() * 180 / math.Pi
|
||||
yaw := gjson.Get(string(jsonData), "motionYaw").Float() * 180 / math.Pi
|
||||
hAcc := gjson.Get(string(jsonData), "locationHorizontalAccuracy").Float()
|
||||
vAcc := gjson.Get(string(jsonData), "locationVerticalAccuracy").Float()
|
||||
headingAcc := gjson.Get(string(jsonData), "locationHeadingAccuracy").Float()
|
||||
headMotion := gjson.Get(string(jsonData), "locationCourse").Float()
|
||||
headDevice := gjson.Get(string(jsonData), "locationTrueHeading").Float()
|
||||
speed := gjson.Get(string(jsonData), "locationSpeed").Float()
|
||||
|
||||
var ts time.Time
|
||||
if timestamp != 0 {
|
||||
ts = time.Unix(0, int64(timestamp*float64(time.Second))).UTC()
|
||||
lastTimeOffsetIphone = time.Now().UnixNano() - ts.UnixNano()
|
||||
} else {
|
||||
ts = time.Now().UTC().Add(time.Duration(lastTimeOffsetIphone))
|
||||
}
|
||||
//if ts == time.Date()
|
||||
sd := &SensorData{
|
||||
//Servertime: time.Now().UTC(),
|
||||
source: SOURCE_TCP,
|
||||
Timestamp: ts,
|
||||
Position: [3]float64{lat, lon, alt},
|
||||
Orientation: [3]float64{pitch, roll, yaw},
|
||||
HAcc: hAcc,
|
||||
VAcc: vAcc,
|
||||
HeadingAcc: headingAcc,
|
||||
HeadMotion: headMotion,
|
||||
HeadDevice: headDevice,
|
||||
Speed: speed,
|
||||
}
|
||||
if (*sd == SensorData{}) {
|
||||
return nil, errors.New("iphone sensorlog: convert empty")
|
||||
}
|
||||
return sd, nil
|
||||
}
|
||||
|
||||
func convertAndroidHyperImu(jsonData []byte) (*SensorData, error) {
|
||||
timestamp := gjson.Get(string(jsonData), "Timestamp").Int()
|
||||
lat := gjson.Get(string(jsonData), "GPS.0").Float()
|
||||
lon := gjson.Get(string(jsonData), "GPS.1").Float()
|
||||
alt := gjson.Get(string(jsonData), "GPS.2").Float()
|
||||
pitch := gjson.Get(string(jsonData), "orientation.0").Float()
|
||||
roll := gjson.Get(string(jsonData), "orientation.1").Float()
|
||||
yaw := gjson.Get(string(jsonData), "orientation.2").Float()
|
||||
// following properties not available for HyperIMU
|
||||
//hAcc := gjson.Get(string(jsonData), "locationHorizontalAccuracy").Float()
|
||||
//vAcc := gjson.Get(string(jsonData), "locationVerticalAccuracy").Float()
|
||||
//headingAcc := gjson.Get(string(jsonData), "locationHeadingAccuracy").Float()
|
||||
//headMotion := gjson.Get(string(jsonData), "locationCourse").Float()
|
||||
//headDevice := gjson.Get(string(jsonData), "locationTrueHeading").Float()
|
||||
//speed := gjson.Get(string(jsonData), "locationSpeed").Float()
|
||||
|
||||
sd := &SensorData{
|
||||
//Servertime: time.Now().UTC(),
|
||||
source: SOURCE_TCP,
|
||||
Timestamp: time.Unix(0, timestamp*int64(time.Millisecond)).UTC(),
|
||||
Position: [3]float64{lat, lon, alt},
|
||||
Orientation: [3]float64{pitch, roll, yaw},
|
||||
}
|
||||
if (*sd == SensorData{}) {
|
||||
return nil, errors.New("android hyperimu: convert empty")
|
||||
}
|
||||
return sd, nil
|
||||
}
|
||||
@ -1,82 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/semaphore"
|
||||
)
|
||||
|
||||
// dispatcher is responsible to distribute messages to subscribed listeners
|
||||
type dispatcher struct {
|
||||
listeners map[int16]chan string
|
||||
counter int16
|
||||
sem *semaphore.Weighted
|
||||
}
|
||||
|
||||
// Returns initialized dispatcher.
|
||||
func NewDispatcher() *dispatcher {
|
||||
return &dispatcher{
|
||||
listeners: make(map[int16]chan string),
|
||||
counter: 0,
|
||||
sem: semaphore.NewWeighted(1),
|
||||
}
|
||||
}
|
||||
|
||||
// disable or enable streaming without removing all listeners from dispatcher
|
||||
func (d *dispatcher) SetStreaming(s bool) bool {
|
||||
if ok := d.sem.TryAcquire(1); s && ok {
|
||||
// if you want to turn on and can get semaphore then return success
|
||||
return true
|
||||
} else if !s && !ok {
|
||||
// if you want to turn off and cant get semaphore, you can safely turn off by releasing semaphore and return success
|
||||
d.sem.Release(1)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// if closed, dispatcher will not forward published messages and drops them.
|
||||
func (d *dispatcher) IsClosed() bool {
|
||||
if d.sem.TryAcquire(1) {
|
||||
d.sem.Release(1)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// publishes message to all subscribed listeners.
|
||||
// if dispatcher closed, dispatcher will not forward published messages and drops them.
|
||||
func (d *dispatcher) Publish(message string) {
|
||||
if d.IsClosed() {
|
||||
return
|
||||
}
|
||||
logrus.Tracef("publishing to %v listeners\n", len(d.listeners))
|
||||
for _, ch := range d.listeners {
|
||||
select {
|
||||
case ch <- message:
|
||||
default:
|
||||
logrus.Traceln("dispatcher: skip closed channel")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Registers new client as listener and returns his id and a channel which is used to receive all messages.
|
||||
func (d *dispatcher) Subscribe() (id int16, receiver <-chan string) {
|
||||
key := d.counter
|
||||
d.counter++
|
||||
rec := make(chan string)
|
||||
d.listeners[key] = rec
|
||||
return key, rec
|
||||
}
|
||||
|
||||
// Unsubscribes Listener with given ID.
|
||||
// if listener with given ID exists, it will be deleted and no error will be returned.
|
||||
func (d *dispatcher) Unsubscribe(id int16) error {
|
||||
receiver, ok := d.listeners[id]
|
||||
if !ok {
|
||||
return errors.New("no subscription with id")
|
||||
}
|
||||
delete(d.listeners, id)
|
||||
close(receiver)
|
||||
return nil
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
package core
|
||||
|
||||
import "github.com/google/uuid"
|
||||
|
||||
// abstraction for dispatcher to make it replaceable
|
||||
type Subscriber interface {
|
||||
Subscribe() (int16, <-chan string)
|
||||
Unsubscribe(id int16) error
|
||||
}
|
||||
|
||||
// abstraction for dispatcher to make it replaceable
|
||||
type Publisher interface {
|
||||
Publish(message string)
|
||||
Streamer
|
||||
}
|
||||
|
||||
// implementing struct should be responsible for message forwarding (to client)
|
||||
type Streamer interface {
|
||||
SetStreaming(s bool) (ok bool)
|
||||
IsClosed() bool
|
||||
}
|
||||
|
||||
// abstraction for persistance layer
|
||||
type Storer interface {
|
||||
Save(tracking Tracking) error
|
||||
LoadAll() ([]TrackingMetadata, error)
|
||||
Load(id uuid.UUID) (*Tracking, error)
|
||||
}
|
||||
@ -1,146 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
ext "github.com/reugn/go-streams/extension"
|
||||
"github.com/reugn/go-streams/flow"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/tidwall/pretty"
|
||||
"time"
|
||||
)
|
||||
|
||||
type pipelineRecord struct{}
|
||||
|
||||
func NewRecordPipeline(p Publisher, s Tracker, netChan chan interface{}, serialChan chan interface{}) *pipelineRecord {
|
||||
// set pipeline up and wire it together
|
||||
collNet := ext.NewChanSource(netChan)
|
||||
collSer := ext.NewChanSource(serialChan)
|
||||
transNet := flow.NewFlatMap(transformNetFunc, 1)
|
||||
transSer := flow.NewFlatMap(transformSerFunc, 1)
|
||||
flowStore := flow.NewMap(storeFunc(s), 1)
|
||||
|
||||
dataSanitizer := flow.NewMap(replaySanitizeFunc(), 1)
|
||||
|
||||
flowJson := flow.NewMap(jsonFunc, 1)
|
||||
sinkPub := newPublishSink(p)
|
||||
|
||||
// wire up and execute
|
||||
demux := flow.Merge(collNet.Via(transNet), collSer.Via(transSer))
|
||||
go demux.Via(flowStore).Via(dataSanitizer).Via(flowJson).To(sinkPub)
|
||||
|
||||
return &pipelineRecord{}
|
||||
}
|
||||
|
||||
func storeFunc(s Tracker) flow.MapFunc {
|
||||
return func(i interface{}) interface{} {
|
||||
var sd *SensorData
|
||||
if v, ok := i.(*SensorData); ok {
|
||||
sd = v
|
||||
} else {
|
||||
panic("unexpected data struct")
|
||||
}
|
||||
if (*sd == SensorData{} || sd == nil) {
|
||||
logrus.Info("empty data")
|
||||
} else {
|
||||
sd.Servertime = time.Now().UTC()
|
||||
s.Put(*sd)
|
||||
}
|
||||
|
||||
logrus.Debugf("%-14v %-40s %-40s %v %v", sd.Source(), sd.Timestamp.Format(time.RFC3339Nano), sd.Servertime.Format(time.RFC3339Nano), sd.Position, sd.Orientation)
|
||||
//runtime.Gosched()
|
||||
return sd
|
||||
}
|
||||
}
|
||||
|
||||
func jsonFunc(i interface{}) interface{} {
|
||||
var sd *SensorData
|
||||
switch v := i.(type) {
|
||||
case SensorData:
|
||||
sd = &v
|
||||
case *SensorData:
|
||||
sd = v
|
||||
default:
|
||||
panic("jsonFunc: wrong Type")
|
||||
}
|
||||
|
||||
data := map[string]interface{}{}
|
||||
if sd.Source() == SOURCE_TCP {
|
||||
data[string(SOURCE_TCP)] = *sd
|
||||
}
|
||||
if sd.Source() == SOURCE_SERIAL {
|
||||
data[string(SOURCE_SERIAL)] = *sd
|
||||
}
|
||||
|
||||
jdata, err := json.Marshal(data)
|
||||
logrus.Traceln(string(pretty.Pretty(jdata)))
|
||||
if err != nil {
|
||||
logrus.Fatalln(err)
|
||||
}
|
||||
return string(jdata)
|
||||
|
||||
}
|
||||
|
||||
func transformNetFunc(i interface{}) []interface{} {
|
||||
logrus.Traceln("transform TCP data...")
|
||||
|
||||
var returnSlice []interface{}
|
||||
if b, ok := i.([]byte); ok {
|
||||
sd, err := ConvertByteSensorData(b)
|
||||
if err != nil {
|
||||
logrus.Errorln("error converting byte message:", err)
|
||||
}
|
||||
if sd != nil {
|
||||
return append(returnSlice, sd)
|
||||
}
|
||||
}
|
||||
logrus.Errorln("wrong data type. expected []byte data")
|
||||
return nil
|
||||
}
|
||||
|
||||
func transformSerFunc(i interface{}) []interface{} {
|
||||
logrus.Traceln("transform SERIAL data...")
|
||||
|
||||
var returnSlice []interface{}
|
||||
sd, err := ConvertUbxSensorData(i)
|
||||
if err != nil {
|
||||
logrus.Errorln("error converting ubx message:", err)
|
||||
return nil
|
||||
}
|
||||
if sd == nil {
|
||||
return nil
|
||||
}
|
||||
return append(returnSlice, sd)
|
||||
}
|
||||
|
||||
// Publish sink will pass data to dispatcher after flowing through the stream processing
|
||||
// matches api to use it with github.com/reugn/go-streams/flow
|
||||
|
||||
type publishSink struct {
|
||||
in chan interface{}
|
||||
p Publisher
|
||||
}
|
||||
|
||||
func newPublishSink(p Publisher) *publishSink {
|
||||
sink := &publishSink{make(chan interface{}), p}
|
||||
sink.init()
|
||||
return sink
|
||||
}
|
||||
|
||||
func (ps *publishSink) In() chan<- interface{} {
|
||||
return ps.in
|
||||
}
|
||||
|
||||
func (ps *publishSink) init() {
|
||||
go func() {
|
||||
logrus.Trace("publish sink running")
|
||||
for elem := range ps.in {
|
||||
if v, ok := elem.(string); ok {
|
||||
ps.p.Publish(v)
|
||||
} else {
|
||||
logrus.Debugln("not publishing. wrong format", elem)
|
||||
//reflect.TypeOf(elem)
|
||||
}
|
||||
}
|
||||
logrus.Trace("publish sink stopped")
|
||||
}()
|
||||
}
|
||||
@ -1,216 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"container/heap"
|
||||
"github.com/reugn/go-streams"
|
||||
ext "github.com/reugn/go-streams/extension"
|
||||
"github.com/reugn/go-streams/flow"
|
||||
"github.com/sirupsen/logrus"
|
||||
"runtime"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type pipelineReplay struct {
|
||||
stopChan chan struct{}
|
||||
replayChan chan interface{}
|
||||
}
|
||||
|
||||
func (p *pipelineReplay) Stop() {
|
||||
defer func() {
|
||||
if recover() != nil {
|
||||
logrus.Debugln("replay channel already closed")
|
||||
}
|
||||
}()
|
||||
logrus.Debugln("send stop signal...")
|
||||
select {
|
||||
case p.stopChan <- struct{}{}:
|
||||
logrus.Debugln("stop signal sent")
|
||||
//default:
|
||||
// logrus.Debugln("stop signal skipped")
|
||||
}
|
||||
}
|
||||
|
||||
func NewReplayPipeline(p Publisher, t *Tracking) *pipelineReplay {
|
||||
r := &pipelineReplay{make(chan struct{}), nil}
|
||||
// set pipeline up and wire it together
|
||||
r.replayChan = r.channelFromTracking(t)
|
||||
collNet := ext.NewChanSource(r.replayChan)
|
||||
dataSanitizer := flow.NewMap(replaySanitizeFunc(), 1)
|
||||
//flowReorder := NewRearranger()
|
||||
|
||||
flowJson := flow.NewMap(jsonFunc, 1)
|
||||
sinkPub := newPublishSink(p)
|
||||
|
||||
// wire up and execute
|
||||
//go collNet.Via(dataSanitizer).Via(flowJson).To(sinkPub)
|
||||
go collNet.Via(dataSanitizer).Via(flowJson).To(sinkPub)
|
||||
return r
|
||||
}
|
||||
|
||||
func (p *pipelineReplay) channelFromTracking(t *Tracking) chan interface{} {
|
||||
ch := make(chan interface{})
|
||||
sort.Slice(t.Data, func(i, j int) bool { return t.Data[i].Servertime.Before(t.Data[j].Servertime) })
|
||||
go func() {
|
||||
lastTs := t.Data[0].Servertime.UnixNano()
|
||||
lastTsNow := time.Now().UTC().UnixNano()
|
||||
i := 0
|
||||
br:
|
||||
for i <= len(t.Data)-1 {
|
||||
durationSinceLastEvent := t.Data[i].Servertime.UnixNano() - lastTs
|
||||
timeCounter := time.Now().UTC().UnixNano() - lastTsNow
|
||||
if timeCounter >= durationSinceLastEvent {
|
||||
logrus.Traceln("replay tracking: ", t.Data[i])
|
||||
ch <- &(t.Data[i])
|
||||
lastTs = t.Data[i].Servertime.UnixNano()
|
||||
lastTsNow = time.Now().UTC().UnixNano()
|
||||
i++
|
||||
}
|
||||
select {
|
||||
case <-p.stopChan:
|
||||
logrus.Debugln("received stop signal: replay stopped")
|
||||
break br
|
||||
default:
|
||||
}
|
||||
}
|
||||
logrus.Infoln("replay: tracking replay finished")
|
||||
select {
|
||||
case <-p.stopChan:
|
||||
logrus.Debugln("received stop signal: replay pipeline closed")
|
||||
}
|
||||
close(p.replayChan)
|
||||
}()
|
||||
return ch
|
||||
}
|
||||
|
||||
func replaySanitizeFunc() flow.MapFunc {
|
||||
var lastTimeOffsetIphone int64
|
||||
var lastTimeOffsetUblox int64
|
||||
|
||||
return func(i interface{}) interface{} {
|
||||
sd := i.(*SensorData)
|
||||
|
||||
if !(sd.Timestamp.IsZero() || sd.Timestamp.Nanosecond() == 0) {
|
||||
lastOffset := sd.Servertime.UnixNano() - sd.Timestamp.UnixNano()
|
||||
if sd.Source() == SOURCE_TCP {
|
||||
lastTimeOffsetIphone = lastOffset
|
||||
}
|
||||
if sd.Source() == SOURCE_SERIAL {
|
||||
lastTimeOffsetUblox = lastOffset
|
||||
}
|
||||
} else {
|
||||
var lastOff int64
|
||||
if sd.Source() == SOURCE_TCP {
|
||||
lastOff = lastTimeOffsetIphone
|
||||
}
|
||||
if sd.Source() == SOURCE_SERIAL {
|
||||
lastOff = lastTimeOffsetUblox
|
||||
}
|
||||
sd.Timestamp = sd.Servertime.Add(time.Duration(lastOff))
|
||||
}
|
||||
//if sd.Servertime.Before(time.Unix(1608422400, 0)) && sd.Speed != 0 && sd.Source() == SOURCE_SERIAL {
|
||||
// sd.Speed = sd.Speed * 3.6
|
||||
//}
|
||||
return sd
|
||||
}
|
||||
}
|
||||
|
||||
// The Rearranger is not used but kept, for later experiments.
|
||||
|
||||
func NewRearranger() *rearranger {
|
||||
rearran := &rearranger{
|
||||
queue: &flow.PriorityQueue{},
|
||||
in: make(chan interface{}),
|
||||
out: make(chan interface{}),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
go rearran.receive()
|
||||
go rearran.emit()
|
||||
return rearran
|
||||
}
|
||||
|
||||
type rearranger struct {
|
||||
sync.RWMutex
|
||||
queue *flow.PriorityQueue
|
||||
in chan interface{}
|
||||
out chan interface{}
|
||||
done chan struct{}
|
||||
lastTimestamp int64
|
||||
lastTimeNanoNow int64
|
||||
}
|
||||
|
||||
// Verify rearranger satisfies the Flow interface.
|
||||
var _ streams.Flow = (*rearranger)(nil)
|
||||
|
||||
func (r *rearranger) In() chan<- interface{} {
|
||||
return r.in
|
||||
}
|
||||
|
||||
func (r *rearranger) Out() <-chan interface{} {
|
||||
return r.out
|
||||
}
|
||||
|
||||
func (r *rearranger) Via(flow streams.Flow) streams.Flow {
|
||||
go r.transmit(flow)
|
||||
return flow
|
||||
}
|
||||
|
||||
func (r *rearranger) To(sink streams.Sink) {
|
||||
r.transmit(sink)
|
||||
}
|
||||
|
||||
// submit emitted windows to the next Inlet
|
||||
func (r *rearranger) transmit(inlet streams.Inlet) {
|
||||
for elem := range r.Out() {
|
||||
inlet.In() <- elem
|
||||
}
|
||||
close(inlet.In())
|
||||
}
|
||||
|
||||
func (r *rearranger) receive() {
|
||||
for elem := range r.in {
|
||||
ts := r.timestamp(elem)
|
||||
//if r.lastTimestamp == 0 {
|
||||
// r.lastTimestamp = ts //- (500 * 1e+6) // Delay
|
||||
// r.lastTimeNanoNow = time.Now().UTC().UnixNano()
|
||||
//}
|
||||
item := flow.NewItem(elem, ts, 0)
|
||||
r.Lock()
|
||||
heap.Push(r.queue, item)
|
||||
r.Unlock()
|
||||
logrus.Debugln("item recieved.")
|
||||
runtime.Gosched()
|
||||
}
|
||||
close(r.done)
|
||||
close(r.out)
|
||||
}
|
||||
|
||||
// emit pops data from ordered priority queue
|
||||
func (r *rearranger) emit() {
|
||||
for {
|
||||
if r.queue.Len() <= 10 {
|
||||
continue
|
||||
}
|
||||
tnow := time.Now().UTC().UnixNano()
|
||||
logrus.Debugln("popping item: ")
|
||||
|
||||
r.Lock()
|
||||
item := heap.Pop(r.queue).(*flow.Item)
|
||||
r.Unlock()
|
||||
v := item.Msg.(*SensorData)
|
||||
r.out <- v
|
||||
r.lastTimestamp = v.Timestamp.UnixNano()
|
||||
r.lastTimeNanoNow = tnow
|
||||
select {
|
||||
case <-r.done:
|
||||
return
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *rearranger) timestamp(elem interface{}) int64 {
|
||||
v := elem.(*SensorData)
|
||||
return v.Timestamp.UnixNano()
|
||||
}
|
||||
279
core/service.go
279
core/service.go
@ -1,279 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sync/semaphore"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// indicates state of the TrackingService
|
||||
type OpMode uint8
|
||||
|
||||
const (
|
||||
STOPPED OpMode = iota
|
||||
LIVE
|
||||
RECORDING
|
||||
REPLAY
|
||||
)
|
||||
|
||||
// structs implementing this interface are expected to cache sensor data passed by Put(data) while recording and dropping data if not recording
|
||||
type Tracker interface {
|
||||
Put(data SensorData)
|
||||
Recorder
|
||||
}
|
||||
|
||||
type Recorder interface {
|
||||
SetRecording(s bool) (ok bool)
|
||||
IsRecording() bool
|
||||
}
|
||||
|
||||
// this struct holds all relevant references for the TrackingService
|
||||
type TrackingService struct {
|
||||
opMode OpMode
|
||||
tracking *Tracking
|
||||
//pipeline *pipelineRecord
|
||||
replaypipe *pipelineReplay
|
||||
collectors []Collector
|
||||
store Storer
|
||||
publisher Publisher
|
||||
config *Configuration
|
||||
recSem *semaphore.Weighted
|
||||
mu *sync.RWMutex
|
||||
}
|
||||
|
||||
// constructor
|
||||
func NewTrackingService(c *Configuration, s Storer, p Publisher) *TrackingService {
|
||||
t := &Tracking{}
|
||||
ts := &TrackingService{
|
||||
tracking: t,
|
||||
opMode: STOPPED,
|
||||
collectors: nil,
|
||||
recSem: semaphore.NewWeighted(1),
|
||||
mu: &sync.RWMutex{},
|
||||
config: c,
|
||||
store: s,
|
||||
publisher: p,
|
||||
}
|
||||
|
||||
// first call to to open tcp port. makes app ready to accept connections
|
||||
NewCollector(c, TCP)
|
||||
|
||||
return ts
|
||||
}
|
||||
|
||||
// caches sensordata while recording
|
||||
func (t *TrackingService) Put(data SensorData) {
|
||||
if !t.IsRecording() {
|
||||
return
|
||||
}
|
||||
t.mu.Lock()
|
||||
t.tracking.Data = append(t.tracking.Data, data)
|
||||
t.tracking.Size++
|
||||
logrus.Traceln("raw data points: len->", len(t.tracking.Data))
|
||||
t.mu.Unlock()
|
||||
}
|
||||
|
||||
// changes recording state of service
|
||||
func (t *TrackingService) SetRecording(s bool) (ok bool) {
|
||||
if okay := t.recSem.TryAcquire(1); okay && s {
|
||||
// if i want to turn on and can get semaphore then return success
|
||||
return true
|
||||
} else if !s && !okay {
|
||||
// if i want to turn off and cant get semaphore, i can safely turn off by releasing semaphore and return success
|
||||
t.recSem.Release(1)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t *TrackingService) IsRecording() bool {
|
||||
if t.recSem.TryAcquire(1) {
|
||||
t.recSem.Release(1)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// creates a new Pipeline with requested collectors
|
||||
func (t *TrackingService) StartLivetracking(cols ...CollectorType) (string, error) {
|
||||
logrus.Info("SERVICE: NEW PIPELINE")
|
||||
// check if state machine is in right state
|
||||
if t.opMode == RECORDING {
|
||||
txt := "trackingservice: please stop recording before resetting pipeline"
|
||||
logrus.Warn(txt)
|
||||
return "RECORDING", errors.New(txt)
|
||||
}
|
||||
if t.opMode == REPLAY {
|
||||
t.StopAll()
|
||||
}
|
||||
if t.opMode == LIVE {
|
||||
txt := "trackingservice: stop tracking running stream before creating new one"
|
||||
logrus.Warnln(txt)
|
||||
return "record already running since: " + t.tracking.TimeCreated.String(), errors.New(txt)
|
||||
}
|
||||
logrus.Debugln("new tracking:", cols)
|
||||
t.opMode = LIVE
|
||||
|
||||
// create and start collectors
|
||||
t.collectors = nil
|
||||
var tcp, ser chan interface{}
|
||||
for _, col := range cols {
|
||||
c := NewCollector(t.config, col)
|
||||
t.collectors = append(t.collectors, c)
|
||||
if col == TCP {
|
||||
tcp = c.OutChannel()
|
||||
}
|
||||
if col == SERIAL {
|
||||
ser = c.OutChannel()
|
||||
}
|
||||
c.Collect()
|
||||
}
|
||||
t.safelyReplaceTracking(newTracking())
|
||||
t.tracking.Collectors = cols
|
||||
|
||||
// finally create pipeline
|
||||
NewRecordPipeline(t.publisher, t, tcp, ser)
|
||||
t.publisher.SetStreaming(true)
|
||||
logrus.Debugln("current State:", t.opMode)
|
||||
|
||||
return "LIVE", nil
|
||||
}
|
||||
|
||||
// retrieves all trackings. metadata only.
|
||||
func (t *TrackingService) AllTrackings() ([]TrackingMetadata, error) {
|
||||
logrus.Info("SERVICE: GET ALL TRACKINGS")
|
||||
data, err := t.store.LoadAll()
|
||||
logrus.Debugln("current State:", t.opMode)
|
||||
return data, err
|
||||
}
|
||||
|
||||
// starts recording and returns state
|
||||
func (t *TrackingService) StartRecord() (string, error) {
|
||||
logrus.Info("SERVICE: START RECORD")
|
||||
if t.opMode != LIVE {
|
||||
if t.opMode == RECORDING {
|
||||
txt := "trackingservice: already recording"
|
||||
logrus.Warn(txt)
|
||||
return "record already running since: " + t.tracking.TimeCreated.String(), errors.New(txt)
|
||||
} else {
|
||||
txt := "trackingservice: start collector pipeline to record data"
|
||||
logrus.Warn(txt)
|
||||
return "record already running since: " + t.tracking.TimeCreated.String(), errors.New(txt)
|
||||
}
|
||||
}
|
||||
t.opMode = RECORDING
|
||||
t.tracking.TimeCreated = time.Now()
|
||||
t.SetRecording(true)
|
||||
logrus.Debugln("current State:", t.opMode)
|
||||
return "record started at: " + t.tracking.TimeCreated.String(), nil
|
||||
}
|
||||
|
||||
// stops recording and returns metadata of current tracking if successfully stopped
|
||||
func (t *TrackingService) StopRecord() (*TrackingMetadata, error) {
|
||||
logrus.Info("SERVICE: STOP RECORD")
|
||||
if t.opMode != RECORDING {
|
||||
txt := "trackingservice: couldn't stop. not recording"
|
||||
logrus.Info(txt)
|
||||
return nil, errors.New(txt)
|
||||
}
|
||||
t.SetRecording(false)
|
||||
|
||||
err := t.store.Save(*t.tracking)
|
||||
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
t.opMode = LIVE
|
||||
|
||||
tm := t.tracking.TrackingMetadata
|
||||
t.safelyReplaceTracking(newTracking())
|
||||
t.tracking.Collectors = tm.Collectors
|
||||
logrus.Debugln("current State:", t.opMode)
|
||||
return &tm, err
|
||||
}
|
||||
|
||||
// stops live tracking and recording. if theres no active recording, no metadata will be returned
|
||||
func (t *TrackingService) StopAll() (*TrackingMetadata, error) {
|
||||
logrus.Info("SERVICE: STOP ALL")
|
||||
var tm *TrackingMetadata = nil
|
||||
var err error
|
||||
for _, e := range t.collectors {
|
||||
e.Stop()
|
||||
}
|
||||
if t.replaypipe != nil {
|
||||
t.replaypipe.Stop()
|
||||
t.replaypipe = nil
|
||||
}
|
||||
// let buffer run empty after collectors stopped
|
||||
time.Sleep(time.Millisecond * 5)
|
||||
t.publisher.SetStreaming(false)
|
||||
if t.opMode == RECORDING {
|
||||
logrus.Info("trackingservice: gracefully stop recording ")
|
||||
tm, err = t.StopRecord()
|
||||
}
|
||||
t.opMode = STOPPED
|
||||
logrus.Debugln("current State:", t.opMode)
|
||||
return tm, err
|
||||
}
|
||||
|
||||
// retrieves tracking with all data and starts replay pipeline if desired.
|
||||
// in that case the application behaves like in live mode.
|
||||
func (t *TrackingService) LoadTracking(trackingId uuid.UUID, replay bool) (*Tracking, error) {
|
||||
logrus.Info("SERVICE: LOAD TRACKING")
|
||||
if t.opMode == RECORDING {
|
||||
txt := "trackingservice: please stop recording before load another tracking"
|
||||
logrus.Warn(txt)
|
||||
return nil, errors.New(txt)
|
||||
}
|
||||
if t.opMode == REPLAY || t.opMode == LIVE {
|
||||
t.StopAll()
|
||||
}
|
||||
logrus.Info("LOAD TRACKING from database")
|
||||
tracking, err := t.store.Load(trackingId)
|
||||
fixSpeedValues(tracking)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if replay == false {
|
||||
return tracking, nil
|
||||
}
|
||||
t.safelyReplaceTracking(*tracking)
|
||||
if t.replaypipe != nil {
|
||||
select {
|
||||
case <-t.replaypipe.stopChan:
|
||||
logrus.Warnln("blocking channel closed")
|
||||
default:
|
||||
}
|
||||
t.replaypipe = nil
|
||||
}
|
||||
t.replaypipe = NewReplayPipeline(t.publisher, t.tracking)
|
||||
t.publisher.SetStreaming(true)
|
||||
t.opMode = REPLAY
|
||||
logrus.Debugln("current State:", t.opMode)
|
||||
return t.tracking, nil
|
||||
}
|
||||
|
||||
func (t *TrackingService) DeleteTracking(trackingId uuid.UUID) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
// helper function to replace tracking held by service. makes sure to keep the pointer and change only underlying data.
|
||||
func (t *TrackingService) safelyReplaceTracking(tr Tracking) {
|
||||
t.recSem.Acquire(context.Background(), 1)
|
||||
*t.tracking = tr
|
||||
t.recSem.Release(1)
|
||||
}
|
||||
|
||||
// helper function to fixSpeedValues wrong values recorded before 12/20/2020
|
||||
func fixSpeedValues(tracking *Tracking) {
|
||||
logrus.Debugln("fixing speed values")
|
||||
for i := 0; i < len(tracking.Data); i++ {
|
||||
if tracking.Data[i].Servertime.Before(time.Unix(1608422400, 0)) && tracking.Data[i].Source() == SOURCE_SERIAL && tracking.Data[i].Speed != 0 {
|
||||
tracking.Data[i].Speed = tracking.Data[i].Speed * 3.6
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
devdocs.pdf
BIN
devdocs.pdf
Binary file not shown.
46
dispatcher/dispatcher.go
Normal file
46
dispatcher/dispatcher.go
Normal file
@ -0,0 +1,46 @@
|
||||
package dispatcher
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Dispatcher struct {
|
||||
listeners map[int16]chan string
|
||||
counter int16
|
||||
}
|
||||
|
||||
func New() *Dispatcher {
|
||||
fmt.Println("new dispatcher")
|
||||
return &Dispatcher{
|
||||
listeners: make(map[int16]chan string),
|
||||
counter: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dispatcher) Publish(message string) {
|
||||
fmt.Println("publish to listeners", len(d.listeners))
|
||||
for _, ch := range d.listeners {
|
||||
ch <- message
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Dispatcher) Subscribe() (id int16, receiver <-chan string) {
|
||||
fmt.Println("subscribe")
|
||||
key := d.counter
|
||||
d.counter++
|
||||
rec := make(chan string)
|
||||
d.listeners[key] = rec
|
||||
return key, rec
|
||||
}
|
||||
|
||||
func (d *Dispatcher) Unsubscribe(id int16) error {
|
||||
fmt.Println("unsubscribe")
|
||||
receiver, ok := d.listeners[id]
|
||||
if !ok {
|
||||
return errors.New("no subscription with id")
|
||||
}
|
||||
delete(d.listeners, id)
|
||||
close(receiver)
|
||||
return nil
|
||||
}
|
||||
9
ex_websocketMessage.json
Normal file
9
ex_websocketMessage.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"timestamp": 2938502375,
|
||||
"position": [490663054, 91358016],
|
||||
"altitude": 221,
|
||||
"altitude_msl": 221,
|
||||
"accuracy": [16.2, 20.3],
|
||||
"speed": [13, 9]
|
||||
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
# !!! copy this file and rename it to gpsconfig.yml !!!
|
||||
# !!! file must be located in working directory !!!
|
||||
|
||||
# server configurations
|
||||
webserver:
|
||||
port: ":3011"
|
||||
|
||||
# collector configurations
|
||||
collectors:
|
||||
porttcp: ":3010"
|
||||
portserial: "/dev/tty.usbmodem14201"
|
||||
|
||||
debuglevel: "INFO"
|
||||
|
||||
#// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
||||
#// Commonly used for hooks to send errors to an error tracking service.
|
||||
#ErrorLevel
|
||||
|
||||
#// WarnLevel level. Non-critical entries that deserve eyes.
|
||||
#WarnLevel
|
||||
|
||||
#// InfoLevel level. General operational entries about what's going on inside the
|
||||
#// application.
|
||||
#InfoLevel
|
||||
|
||||
#// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
||||
#DebugLevel
|
||||
25
go.mod
25
go.mod
@ -3,24 +3,11 @@ module git.timovolkmann.de/gyrogpsc
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/DataDog/zstd v1.4.6-0.20200617134701-89f69fb7df32 // indirect
|
||||
github.com/dgraph-io/badger/v2 v2.2007.2
|
||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||
github.com/gofiber/fiber/v2 v2.2.4
|
||||
github.com/gofiber/template v1.6.6
|
||||
github.com/gofiber/websocket/v2 v2.0.2
|
||||
github.com/golang/protobuf v1.4.2 // indirect
|
||||
github.com/google/go-cmp v0.5.2 // indirect
|
||||
github.com/google/uuid v1.1.2
|
||||
github.com/klauspost/compress v1.11.0 // indirect
|
||||
github.com/reugn/go-streams v0.6.3
|
||||
github.com/sirupsen/logrus v1.6.0
|
||||
github.com/spf13/viper v1.7.1
|
||||
github.com/tidwall/gjson v1.6.0
|
||||
github.com/daedaleanai/ublox v0.0.0-20201103121443-9befa131d32d
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/sparkfun/SparkFun_Ublox_Arduino_Library v1.8.7 // indirect
|
||||
github.com/tidwall/pretty v1.0.2
|
||||
go.bug.st/serial v1.1.3
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
|
||||
golang.org/x/sys v0.0.0-20201211090839-8ad439b19e0f // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect
|
||||
go.bug.st/serial v1.1.1
|
||||
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf // indirect
|
||||
golang.org/x/tools v0.0.0-20201121010211-780cb80bd7fb // indirect
|
||||
)
|
||||
|
||||
589
go.sum
589
go.sum
@ -1,605 +1,50 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
|
||||
github.com/CloudyKit/jet/v3 v3.0.1/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo=
|
||||
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||
github.com/DataDog/zstd v1.4.6-0.20200617134701-89f69fb7df32 h1:/gZKpgSMydtrih81nvUhlkXpZIUfthKShSCVbRzBt9Y=
|
||||
github.com/DataDog/zstd v1.4.6-0.20200617134701-89f69fb7df32/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||
github.com/Djarvur/go-err113 v0.0.0-20200511133814-5174e21577d5/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
|
||||
github.com/Joker/hpp v0.0.0-20180418125244-6893e659854a/go.mod h1:MzD2WMdSxvbHw5fM/OXOFily/lipJWRc9C1px0Mt0ZE=
|
||||
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
|
||||
github.com/Joker/jade v1.0.0/go.mod h1:efZIdO0py/LtcJRSa/j2WEklMSAw84WV0zZVMxNToB8=
|
||||
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/OpenPeeDeeP/depguard v1.0.1/go.mod h1:xsIw86fROiiwelg+jB2uM9PiKihMMmUx/1V+TNhjQvM=
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4=
|
||||
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/aymerick/raymond v2.0.2+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/bombsimon/wsl/v3 v3.1.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc=
|
||||
github.com/cbroglie/mustache v1.2.0/go.mod h1:gomHsVlF4zTcsY2H8d7U9SipCYbbrAks5breARbqAM0=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/goselect v0.1.1 h1:tiSSgKE1eJtxs1h/VgGQWuXUP0YS4CDIFMp6vaI1ls0=
|
||||
github.com/creack/goselect v0.1.1/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
|
||||
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/daedaleanai/ublox v0.0.0-20201103121443-9befa131d32d h1:WbFmX8L79E02PgDJYWINhWvceaMGUzgmrwdE5CuUBBk=
|
||||
github.com/daedaleanai/ublox v0.0.0-20201103121443-9befa131d32d/go.mod h1:pfcwlN8XUYXVYAkPU2LrFZnXIS4EvpZaXh+qRKCN9Sg=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denis-tingajkin/go-header v0.3.1/go.mod h1:sq/2IxMhaZX+RRcgHfCRx/m0M5na0fBt4/CRe7Lrji0=
|
||||
github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k=
|
||||
github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE=
|
||||
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA=
|
||||
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/eknkc/amber v0.0.0-20171010120322-cdade1c07385/go.mod h1:0vRUJqYpeSZifjYj7uP3BG/gKcuzL9xWVV/Y+cK33KM=
|
||||
github.com/fasthttp/websocket v1.4.3 h1:qjhRJ/rTy4KB8oBxljEC00SDt6HUY9jLRfM601SUdS4=
|
||||
github.com/fasthttp/websocket v1.4.3/go.mod h1:5r4oKssgS7W6Zn6mPWap3NWzNPJNzUUh3baWTOhcYQk=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/flosch/pongo2/v4 v4.0.1/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-critic/go-critic v0.5.0/go.mod h1:4jeRh3ZAVnRYhuWdOEvwzVqLUpxMSoAT0xZ74JsTPlo=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
|
||||
github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ=
|
||||
github.com/go-toolsmith/astequal v0.0.0-20180903214952-dcb477bfacd6/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
|
||||
github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
|
||||
github.com/go-toolsmith/astfmt v0.0.0-20180903215011-8f8ee99c3086/go.mod h1:mP93XdblcopXwlyN4X4uodxXQhldPGZbcEJIimQHrkg=
|
||||
github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw=
|
||||
github.com/go-toolsmith/astinfo v0.0.0-20180906194353-9809ff7efb21/go.mod h1:dDStQCHtmZpYOmjRP/8gHHnCCch3Zz3oEgCdZVdtweU=
|
||||
github.com/go-toolsmith/astp v0.0.0-20180903215135-0af7e3c24f30/go.mod h1:SV2ur98SGypH1UjcPpCatrV5hPazG6+IfNHbkDXBRrk=
|
||||
github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI=
|
||||
github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoMrjiy4zvdS+Bg6z9jZH82QXwkcgCBX6nOfnmdaHks=
|
||||
github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc=
|
||||
github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
|
||||
github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
|
||||
github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
|
||||
github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
|
||||
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||
github.com/gofiber/fiber/v2 v2.1.0/go.mod h1:aG+lMkwy3LyVit4CnmYUbUdgjpc3UYOltvlJZ78rgQ0=
|
||||
github.com/gofiber/fiber/v2 v2.2.2/go.mod h1:Aso7/M+EQOinVkWp4LUYjdlTpKTBoCk2Qo4djnMsyHE=
|
||||
github.com/gofiber/fiber/v2 v2.2.4 h1:t2V2SxlbQGdt8+SS/Mo+tQB0pDQn7OajKdA72qHcBVw=
|
||||
github.com/gofiber/fiber/v2 v2.2.4/go.mod h1:Aso7/M+EQOinVkWp4LUYjdlTpKTBoCk2Qo4djnMsyHE=
|
||||
github.com/gofiber/template v1.6.6 h1:mZ0sMRomxndpzVOSez6jKPaMO9UlUDfmBfHFmkFnb/A=
|
||||
github.com/gofiber/template v1.6.6/go.mod h1:WmzkzTh6QWwrGysWFU8bwNsmHmqRbxHmWZcApIT1ORo=
|
||||
github.com/gofiber/websocket/v2 v2.0.2 h1:UA/6NpyG+vmPGlvJvW8MJPJpRFuS7abinZ5HbLuV8u0=
|
||||
github.com/gofiber/websocket/v2 v2.0.2/go.mod h1:7VBnzEVRK0K0eTIVc5GbXPF1JWUFnllY0X4cRtG2v78=
|
||||
github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
|
||||
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a/go.mod h1:ryS0uhF+x9jgbj/N71xsEqODy9BN81/GonCZiOzirOk=
|
||||
github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6/go.mod h1:DbHgvLiFKX1Sh2T1w8Q/h4NAI8MHIpzCdnBUDTXU3I0=
|
||||
github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2NxV+sN8upjjeVYr5W7tyxaT1JVtvhKhOn2ii8=
|
||||
github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o=
|
||||
github.com/golangci/gocyclo v0.0.0-20180528144436-0a533e8fa43d/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU=
|
||||
github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU=
|
||||
github.com/golangci/golangci-lint v1.28.3/go.mod h1:JlLqleIwwgLVJtjKtrB37OKp3LGLrUhEx9tWY4VKWSY=
|
||||
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU=
|
||||
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
|
||||
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o=
|
||||
github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA=
|
||||
github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI=
|
||||
github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunEYvmd/TLamH+7LlVccLvUH5kZNhbCgTHoBbp4=
|
||||
github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gookit/color v1.2.4/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
|
||||
github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
|
||||
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
|
||||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a/go.mod h1:xRskid8CManxVta/ALEhJha/pweKBaVG6fWgc0yH25s=
|
||||
github.com/jirfag/go-printf-func-name v0.0.0-20191110105641-45db9963cdd3/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0=
|
||||
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||
github.com/jmoiron/sqlx v1.2.1-0.20190826204134-d7d95172beb5/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.10.5/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/klauspost/compress v1.11.0 h1:wJbzvpYMVGG9iTI9VxpnNZfd4DzMPoCWze3GgSqz8yg=
|
||||
github.com/klauspost/compress v1.11.0/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kyoh86/exportloopref v0.1.4/go.mod h1:h1rDl2Kdj97+Kwh4gdz3ujE7XHmH51Q0lUiZ1z4NLj8=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/logrusorgru/aurora v0.0.0-20181002194514-a7b3b318ed4e/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/maratori/testpackage v1.0.1/go.mod h1:ddKdw+XG0Phzhx8BFDTKgpWP4i7MpApTE5fXSKAqwDU=
|
||||
github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-slim v0.0.0-20200618151855-bde33eecb5ee/go.mod h1:ma9TUJeni8LGZMJvOwbAv/FOwiwqIMQN570LnpqCBSM=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/mozilla/tls-observatory v0.0.0-20200317151703-4fa42e1c2dee/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nakabonne/nestif v0.3.0/go.mod h1:dI314BppzXjJ4HsCnbo7XzrJHPszZsjnk5wEBSYHI2c=
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nishanths/exhaustive v0.0.0-20200525081945-8e46705b6132/go.mod h1:wBEpHwM2OdmeNpdCvRPUlkEbBuaFmcK4Wv8Q7FuGW3c=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.9.0/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
|
||||
github.com/quasilyte/go-ruleguard v0.1.2-0.20200318202121-b00d7a75d3d8/go.mod h1:CGFX09Ci3pq9QZdj86B+VGIdNj4VyCo2iPOGS9esB/k=
|
||||
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=
|
||||
github.com/reugn/go-streams v0.6.3 h1:b+RqXgcKyOKxU5aX1ddIXCia1UBGeNpO/+yzo0CBVuE=
|
||||
github.com/reugn/go-streams v0.6.3/go.mod h1:OsEa/+BuietQY5sJUCm5nrZujfWtuKIv7KQVCZCXYGg=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryancurrah/gomodguard v1.1.0/go.mod h1:4O8tr7hBODaGE6VIhfJDHcwzh5GUccKSJBU0UMXJFVM=
|
||||
github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/savsgio/gotils v0.0.0-20200608150037-a5f6f5aef16c h1:2nF5+FZ4/qp7pZVL7fR6DEaSTzuDmNaFTyqp92/hwF8=
|
||||
github.com/savsgio/gotils v0.0.0-20200608150037-a5f6f5aef16c/go.mod h1:TWNAOTaVzGOXq8RbEvHnhzA/A2sLZzgn0m6URjnukY8=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/securego/gosec/v2 v2.3.0/go.mod h1:UzeVyUXbxukhLeHKV3VVqo7HdoQR9MrRfFmZYotn8ME=
|
||||
github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc=
|
||||
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
|
||||
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
|
||||
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI=
|
||||
github.com/sourcegraph/go-diff v0.5.3/go.mod h1:v9JDtjCE4HHHCZGId75rg8gkKKa98RVjBcBGsVmMmak=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
|
||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk=
|
||||
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/sparkfun/SparkFun_Ublox_Arduino_Library v1.8.7 h1:T112CHmp+v1bh0W7sp49tZe8SUbw3viSGRTVLziZxfc=
|
||||
github.com/sparkfun/SparkFun_Ublox_Arduino_Library v1.8.7/go.mod h1:FVoZAzJFrR5D6P8qd2rgpJAV/qF5oODtIT9YjVV+xzY=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tdakkota/asciicheck v0.0.0-20200416190851-d7f85be797a2/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM=
|
||||
github.com/tetafro/godot v0.4.2/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0=
|
||||
github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc=
|
||||
github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
|
||||
github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
|
||||
github.com/tidwall/match v1.0.1/go.mod h1:LujAq0jyVjBy028G1WhWfIzbpQfMO8bBZ6Tyb0+pL9E=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU=
|
||||
github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/tommy-muehle/go-mnd v1.3.1-0.20200224220436-e6f9a994e8fa/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig=
|
||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
|
||||
github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA=
|
||||
github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.12.0/go.mod h1:229t1eWu9UXTPmoUkbpN/fctKPBY4IJoFXQnxHGXy6E=
|
||||
github.com/valyala/fasthttp v1.14.0/go.mod h1:ol1PCaL0dX20wC0htZ7sYCsvCYmrouYra0zHzaclZhE=
|
||||
github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA=
|
||||
github.com/valyala/fasthttp v1.17.0 h1:P8/koH4aSnJ4xbd0cUUFEGQs3jQqIxoDDyRQrUiAkqg=
|
||||
github.com/valyala/fasthttp v1.17.0/go.mod h1:jjraHZVbKOXftJfsOYoAjaeygpj5hr8ermTRJNroD7A=
|
||||
github.com/valyala/quicktemplate v1.5.0/go.mod h1:v7yYWpBEiutDyNfVaph6oC/yKwejzVyTX/2cwwHxyok=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a h1:0R4NLDRDZX6JcmhJgXi5E4b8Wg84ihbmUKp/GvSPEzc=
|
||||
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.bug.st/serial v1.1.1 h1:5J1DpaIaSIruBi7jVnKXnhRS+YQ9+2PLJMtIZKoIgnc=
|
||||
go.bug.st/serial v1.1.1/go.mod h1:VmYBeyJWp5BnJ0tw2NUJHZdJTGl2ecBGABHlzRK1knY=
|
||||
go.bug.st/serial v1.1.3 h1:YEBxJa9pKS9Wdg46B/jiaKbvvbUrjhZZZITfJHEJhaE=
|
||||
go.bug.st/serial v1.1.3/go.mod h1:8TT7u/SwwNIpJ8QaG4s+HTjFt9ReXs2cdOU7ZEk50Dk=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0 h1:5kGOVHlq0euqwzgTC9Vu15p6fV1Wi0ArVi8da2urnVg=
|
||||
golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201211090839-8ad439b19e0f h1:QdHQnPce6K4XQewki9WNbG5KOROuDzqO3NaYjI1cXJ0=
|
||||
golang.org/x/sys v0.0.0-20201211090839-8ad439b19e0f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf h1:kt3wY1Lu5MJAnKTfoMR52Cu4gwvna4VTzNOiT8tY73s=
|
||||
golang.org/x/sys v0.0.0-20201107080550-4d91cf3a1aaf/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190221204921-83362c3779f5/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200321224714-0d839f3cf2ed/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200331202046-9d5940d49312/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200414032229-332987a829c3/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200422022333-3d57cf2e726e/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200428185508-e9a00ec82136/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200519015757-0d0afa43d58a/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200702044944-0cc1aa72b347/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20201121010211-780cb80bd7fb h1:z5+u0pkAUPUWd3taoTialQ2JAMo4Wo1Z3L25U4ZV9r0=
|
||||
golang.org/x/tools v0.0.0-20201121010211-780cb80bd7fb/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
mvdan.cc/gofumpt v0.0.0-20200513141252-abc0db2c416a/go.mod h1:4q/PlrZKQLU5MowSvCKM3U4xJUPtJ8vKWx7vsWFJ3MI=
|
||||
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
|
||||
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
|
||||
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0=
|
||||
|
||||
15
hyperimu.json
Normal file
15
hyperimu.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"smartphone": {
|
||||
"os": "hyperimu",
|
||||
"Timestamp": 1606308915986,
|
||||
"orientation": [99.6939697265625, -36.261940002441406, 4.91012716293335],
|
||||
"lsm6ds3c gyroscope": [0.5955139398574829, -0.031028389930725098, 1.511426329612732],
|
||||
"GPS": [49.12283027, 9.19640999, 212.3125],
|
||||
"NMEA": [" ", " ", " "]
|
||||
},
|
||||
"serial": {
|
||||
"timestamp": 37539672354,
|
||||
"position": [0, 0, 0],
|
||||
"orientation": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
118
index.html
Normal file
118
index.html
Normal file
@ -0,0 +1,118 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.bundle.js"></script>
|
||||
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
|
||||
<script src="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
|
||||
<link href="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
|
||||
<style>
|
||||
body { margin: 0; padding: 0; }
|
||||
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
|
||||
</style>
|
||||
<script src="static/scripts/websocket.js"></script>
|
||||
<style>
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
background: #000;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.scene {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border: 0px solid #CCC;
|
||||
margin: 160px;
|
||||
perspective: 400px;
|
||||
}
|
||||
|
||||
.cube {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
position: relative;
|
||||
transform-style: preserve-3d;
|
||||
transform: translateZ(-100px);
|
||||
/*transition: transform 25ms;*/
|
||||
}
|
||||
|
||||
.cube.show-front { transform: translateZ(-100px) rotateY( 0deg); }
|
||||
.cube.show-right { transform: translateZ(-100px) rotateY( -90deg); }
|
||||
.cube.show-back { transform: translateZ(-100px) rotateY(-180deg); }
|
||||
.cube.show-left { transform: translateZ(-100px) rotateY( 90deg); }
|
||||
.cube.show-top { transform: translateZ(-100px) rotateX( -90deg); }
|
||||
.cube.show-bottom { transform: translateZ(-100px) rotateX( 90deg); }
|
||||
|
||||
.cube__face {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border: 1px solid white;
|
||||
line-height: 200px;
|
||||
font-size: 40px;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cube__face--front { background: hsla( 0, 100%, 50%, 0.7); }
|
||||
.cube__face--right { background: hsla( 60, 100%, 50%, 0.7); }
|
||||
.cube__face--back { background: hsla(120, 100%, 50%, 0.7); }
|
||||
.cube__face--left { background: hsla(180, 100%, 50%, 0.7); }
|
||||
.cube__face--top { background: hsla(240, 100%, 50%, 0.7); }
|
||||
.cube__face--bottom { background: hsla(300, 100%, 50%, 0.7); }
|
||||
|
||||
.cube__face--front { transform: rotateY( 0deg) translateZ(100px); }
|
||||
.cube__face--right { transform: rotateY( 90deg) translateZ(100px); }
|
||||
.cube__face--back { transform: rotateY(180deg) translateZ(100px); }
|
||||
.cube__face--left { transform: rotateY(-90deg) translateZ(100px); }
|
||||
.cube__face--top { transform: rotateX( 90deg) translateZ(100px); }
|
||||
.cube__face--bottom { transform: rotateX(-90deg) translateZ(100px); }
|
||||
|
||||
label { margin-right: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table style="font-size: x-small">
|
||||
<tr>
|
||||
<td valign="top" width="50%">
|
||||
<p>Click "Open" to create a connection to the server.
|
||||
</p>
|
||||
<form>
|
||||
<button id="open">Open</button>
|
||||
<button id="close">Close</button>
|
||||
<p style="display: none" >
|
||||
<input id="input" type="text" value="Hello world!">
|
||||
<button id="send">Send</button>
|
||||
</p>
|
||||
</form>
|
||||
<div class="scene" style='width: 600px; height: 400px;'>
|
||||
<div id="map" style='width: 600px; height: 400px;'></div>
|
||||
</div>
|
||||
|
||||
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
|
||||
<script src="static/scripts/map.js"></script>
|
||||
<div class="scene">
|
||||
<div id="gyroscope" class="cube">
|
||||
<div class="cube__face cube__face--front">front</div>
|
||||
<div class="cube__face cube__face--back">back</div>
|
||||
<div class="cube__face cube__face--right">right</div>
|
||||
<div class="cube__face cube__face--left">left</div>
|
||||
<div class="cube__face cube__face--top">top</div>
|
||||
<div class="cube__face cube__face--bottom">bottom</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="width: 600px; height: 400px;">
|
||||
<canvas id="myChart" width="400" height="200"></canvas>
|
||||
</div>
|
||||
<script src="static/scripts/chart.js"></script>
|
||||
|
||||
</td>
|
||||
<td valign="top" width="50%">
|
||||
<div id="output"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
135
net/net.go
Normal file
135
net/net.go
Normal file
@ -0,0 +1,135 @@
|
||||
package net
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"git.timovolkmann.de/gyrogpsc/dispatcher"
|
||||
"git.timovolkmann.de/gyrogpsc/serial_ubx"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/tidwall/pretty"
|
||||
"html/template"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
func echo(d *dispatcher.Dispatcher) func(w http.ResponseWriter, r *http.Request) {
|
||||
var upgrader = websocket.Upgrader{} // use default options
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Println("upgrading to ws")
|
||||
c, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
log.Print("upgrade:", err)
|
||||
return
|
||||
}
|
||||
//defer c.Close()
|
||||
go func() {
|
||||
for {
|
||||
if _, _, err := c.NextReader(); err != nil {
|
||||
c.Close()
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
dispatcherId, channel := d.Subscribe()
|
||||
defer d.Unsubscribe(dispatcherId)
|
||||
for {
|
||||
log.Println("")
|
||||
//if err != nil {
|
||||
// log.Println("read:", err)
|
||||
// break
|
||||
//}
|
||||
cmsg := <-channel
|
||||
err = c.WriteMessage(websocket.TextMessage, []byte(cmsg))
|
||||
if err != nil {
|
||||
log.Println("write:", err)
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func home(w http.ResponseWriter, r *http.Request) {
|
||||
//var homeTemplate = template.Must(template.New("").ParseFiles("index.html"))
|
||||
tpl, err := template.ParseFiles("index.html")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
err = tpl.Execute(w, "ws://"+r.Host+"/echo")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
|
||||
func NewHttpServer(d *dispatcher.Dispatcher, httpPort string) {
|
||||
http.HandleFunc("/echo", echo(d))
|
||||
http.HandleFunc("/", home)
|
||||
//<<<<<<< HEAD:server.go
|
||||
// http.Handle("/static/", http.FileServer(http.Dir(".")))
|
||||
// log.Fatal(http.ListenAndServe(":3011", nil))
|
||||
http.Handle("/static/", http.FileServer(http.Dir(".")))
|
||||
|
||||
log.Fatal(http.ListenAndServe(httpPort, nil))
|
||||
}
|
||||
|
||||
func SerialUbxCollector(d *dispatcher.Dispatcher, serialPort string) {
|
||||
r, err := serial_ubx.Setup(serialPort)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
for {
|
||||
meas, err := r.NextMeasurement()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
fmt.Println(meas)
|
||||
measjson, err := json.Marshal(meas)
|
||||
d.Publish(string(measjson))
|
||||
}
|
||||
}
|
||||
|
||||
func TcpJsonCollector(d *dispatcher.Dispatcher, tcpPort string) {
|
||||
listener, err := net.Listen("tcp", tcpPort)
|
||||
if err != nil {
|
||||
fmt.Println("Error listening:", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
// Close the listener when the application closes.
|
||||
defer listener.Close()
|
||||
|
||||
for {
|
||||
// Listen for an incoming connection.
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
fmt.Println("Error accepting: ", err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
// Handle connections in a new goroutine.
|
||||
go handleTcpJsonSensorData(conn, d)
|
||||
}
|
||||
}
|
||||
|
||||
// Handles incoming requests.
|
||||
func handleTcpJsonSensorData(conn net.Conn, d *dispatcher.Dispatcher) {
|
||||
defer conn.Close()
|
||||
// Make a buffer to hold incoming data.
|
||||
for {
|
||||
buf := make([]byte, 2048)
|
||||
// Read the incoming connection into the buffer.
|
||||
_, err := conn.Read(buf)
|
||||
if err != nil {
|
||||
fmt.Println("Error reading:", err.Error())
|
||||
break
|
||||
}
|
||||
json := pretty.Pretty(buf)
|
||||
fmt.Println(string(json))
|
||||
d.Publish(string(json))
|
||||
// Send a response back to person contacting us.
|
||||
//conn.Write([]byte("success"))
|
||||
// Close the connection when you're done with it.
|
||||
}
|
||||
}
|
||||
51
readme.md
51
readme.md
@ -1,51 +0,0 @@
|
||||
# gyropsc ⚡
|
||||
**Realtime Location Dashboard 🚀**
|
||||
|
||||
Comprehensive documentation can be found [here](/tvolkmann/gyrogpsc/src/branch/develop/devdocs.pdf).
|
||||
|
||||
# Quickstart
|
||||
First copy `example_config.yml` to `gpsconfig.yml` and adjust your parameters. if you intend to use this tool with ublox over USB or Serial, you need to set the name of your port in this config file. otherwise the program will panic.
|
||||
|
||||
## Requirements
|
||||
* Win, Linux or Mac Computer, ideally with serial port and WiFi
|
||||
* GPS device (Android or iOS smartphone and/or ublox 8/M8 series module)
|
||||
* download latest release and unzip it
|
||||
|
||||
## Preparation
|
||||
Make sure you prepared your GPS device like described in chapter 3.3 of the Documentation.
|
||||
Start gyrogpsc **before** connecting your smartphone via TCP. Make sure you updated the config file with the correct COM port for your ublox device, before starting the Serial Collector from the UI.
|
||||
|
||||
## Run
|
||||
Execute `gyropgsc-$OS`, according to your operating system. Make sure the containing folder is your working directory.
|
||||
|
||||
|
||||
# Build and run from source
|
||||
## Requirements
|
||||
* git
|
||||
* go >1.15
|
||||
|
||||
## Run
|
||||
1. `git clone --recursive https://git.timovolkmann.de/tvolkmann/gyrogpsc.git`
|
||||
2. run `go install` from project root
|
||||
3. run `go run cmd/server/server.go` from project root to start application or just `go build cmd/server/server.go` for building it only
|
||||
4. open `http://localhost:3011`
|
||||
|
||||
## Build
|
||||
For your platform only: `go build cmd/server/server.go`
|
||||
|
||||
**Cross-Platform Builds:**
|
||||
|
||||
For Windows 64-bit: `GOOS=windows GOARCH=amd64 go build -o gyrogpsc-win.exe cmd/server/server.go`
|
||||
|
||||
For MacOS: `GOOS=darwin GOARCH=amd64 go build -o gyrogpsc-mac cmd/server/server.go`
|
||||
|
||||
For Linux: `GOOS=linux GOARCH=arm64 go build -o gyrogpsc-linux cmd/server/server.go`
|
||||
|
||||
Make sure that binaries have execute permissions on Mac and Linux. Currently only working on 64-bit systems. Cross Platform commands only working on Mac & Linux.
|
||||
|
||||
## Static files and demo database
|
||||
### Demo database
|
||||
To use demo data, copy `backups/_db-210115-01/` to folder `_db/` in project root. The prebuilt binaries zip-file already contains demo data.
|
||||
|
||||
### Static files
|
||||
All static files (`static/` and `templates/`) must be in the root of working directory when running gyrogpsc. That's already the case if you follow "Run" instructions.
|
||||
124
serial_ubx/serial.go
Normal file
124
serial_ubx/serial.go
Normal file
@ -0,0 +1,124 @@
|
||||
package serial_ubx
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.timovolkmann.de/gyrogpsc/ublox"
|
||||
"go.bug.st/serial"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Measurement struct {
|
||||
//Timestamp int64 `json:"timestamp"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Position [3]int32 `json:"position"` // Latitude, Longitude, Height
|
||||
Orientation [3]int32 `json:"orientation"` // Pitch, Roll, Heading
|
||||
}
|
||||
|
||||
type ubxReceiver struct {
|
||||
decoder *ublox.Decoder
|
||||
currentMeas Measurement
|
||||
}
|
||||
|
||||
func Setup(portname string) (*ubxReceiver, error) {
|
||||
mode := &serial.Mode{
|
||||
BaudRate: 115200,
|
||||
}
|
||||
port, err := serial.Open(portname, mode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ubxReceiver{
|
||||
decoder: ublox.NewDecoder(port),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (u *ubxReceiver) Next() (ublox.Message, error) {
|
||||
return u.decoder.Decode()
|
||||
}
|
||||
|
||||
var (
|
||||
errNotImplemented = errors.New("message not implemented")
|
||||
)
|
||||
|
||||
// TODO: additional callback with adjustable timing
|
||||
func (u *ubxReceiver) NextMeasurement() (*Measurement, error) {
|
||||
|
||||
msg, err := u.decoder.Decode()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//t := time.Time{}
|
||||
switch v := msg.(type) {
|
||||
case *ublox.NavPvt:
|
||||
t, err := time.Parse(time.RFC3339Nano, formatTime(v.Year_y, v.Month_month, v.Day_d, v.Hour_h, v.Min_min, v.Sec_s, v.Nano_ns))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
//u.currentMeas.Timestamp = t.UnixNano()
|
||||
u.currentMeas.Timestamp = t
|
||||
u.currentMeas.Position[0] = v.Lat_dege7
|
||||
u.currentMeas.Position[1] = v.Lon_dege7
|
||||
u.currentMeas.Position[2] = v.Height_mm
|
||||
fmt.Printf("%T %v\n", *v, *v)
|
||||
case *ublox.HnrPvt:
|
||||
t, err := time.Parse(time.RFC3339Nano, formatTime(v.Year_y, v.Month_month, v.Day_d, v.Hour_h, v.Min_min, v.Sec_s, v.Nano_ns))
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
u.currentMeas.Timestamp = t
|
||||
u.currentMeas.Position[0] = v.Lat_dege7
|
||||
u.currentMeas.Position[1] = v.Lon_dege7
|
||||
u.currentMeas.Position[2] = v.Height_mm
|
||||
fmt.Printf("%T %v\n", *v, *v)
|
||||
case *ublox.NavAtt:
|
||||
u.currentMeas.Orientation[0] = v.Pitch_deg
|
||||
u.currentMeas.Orientation[1] = v.Roll_deg
|
||||
u.currentMeas.Orientation[2] = v.Heading_deg
|
||||
fmt.Printf("%T %v\n", *v, *v)
|
||||
|
||||
//case *ublox.RawMessage:
|
||||
// //fmt.Printf("%T %v\n\n", *v, *v)
|
||||
default:
|
||||
return nil, errNotImplemented
|
||||
}
|
||||
m := u.currentMeas
|
||||
return &m, nil
|
||||
}
|
||||
|
||||
func formatTime(Year_y uint16, Month_month byte, Day_d byte, Hour_h byte, Min_min byte, Sec_s byte, Nano_ns int32) string {
|
||||
//Nano_ns *= 1e+3
|
||||
if Nano_ns < 0 {
|
||||
Nano_ns += int32(time.Second)
|
||||
if Sec_s > 0 {
|
||||
Sec_s--
|
||||
} else if Min_min > 0 {
|
||||
Sec_s = 59
|
||||
Min_min--
|
||||
} else if Hour_h > 0 {
|
||||
Sec_s = 59
|
||||
Min_min = 59
|
||||
Hour_h--
|
||||
} else if Day_d > 1 {
|
||||
Sec_s = 59
|
||||
Min_min = 59
|
||||
Hour_h = 23
|
||||
Day_d--
|
||||
} // TODO: more cases for exact behavior! good for now...
|
||||
}
|
||||
//fmt.Printf("%04d-%02d-%02dT%02d:%02d:%02d.%09dZ00:00\n", Year_y, Month_month, Day_d, Hour_h, Min_min, Sec_s, Nano_ns )
|
||||
return fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d.%09dZ", Year_y, Month_month, Day_d, Hour_h, Min_min, Sec_s, Nano_ns)
|
||||
}
|
||||
|
||||
func (u *ubxReceiver) Printloop() {
|
||||
|
||||
for {
|
||||
meas, err := u.NextMeasurement()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
fmt.Println(meas)
|
||||
}
|
||||
|
||||
}
|
||||
230
static/index.html
Normal file
230
static/index.html
Normal file
@ -0,0 +1,230 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.bundle.js"></script>
|
||||
<script>
|
||||
const GRAPH_RES = 100;
|
||||
var dataSmartphone = [];
|
||||
window.addEventListener("load", function(evt) {
|
||||
var orientation = [0,0,0];
|
||||
var multiplier = 180/Math.PI/15
|
||||
var output = document.getElementById("output");
|
||||
var input = document.getElementById("input");
|
||||
var ws;
|
||||
var print = function(message) {
|
||||
var d = document.createElement("div");
|
||||
d.textContent = message;
|
||||
output.appendChild(d);
|
||||
};
|
||||
var print2 = function(message) {
|
||||
var d = document.createElement("p");
|
||||
d.innerText = message;
|
||||
oldNode = output.firstChild
|
||||
output.replaceChild(d, oldNode)
|
||||
};
|
||||
document.getElementById("open").onclick = function(evt) {
|
||||
if (ws && ws.OPEN) {
|
||||
print("Websocket already open")
|
||||
return false;
|
||||
}
|
||||
ws = new WebSocket("{{.}}");
|
||||
ws.onopen = function(evt) {
|
||||
print("OPEN");
|
||||
}
|
||||
ws.onclose = function(evt) {
|
||||
ws = null;
|
||||
print2("CLOSE");
|
||||
}
|
||||
ws.onmessage = function(evt) {
|
||||
//print2("RESPONSE: " + evt.data);
|
||||
dataSmartphone.push(evt.data)
|
||||
// let dat = JSON.parse(evt.data)["bmi26x gyroscope"]
|
||||
// let dat = JSON.parse(evt.data)["lsm6dsm gyroscope"]
|
||||
//let dat = JSON.parse(evt.data)["lsm6ds3c gyroscope"]
|
||||
let dat = JSON.parse(evt.data)
|
||||
//console.log(dat)
|
||||
//console.log(dat.orientation)
|
||||
document.getElementById("gyroscope").style.transform = `rotateX(${-((dat.orientation[1]+90)%360)}deg) rotateY(${dat.orientation[0]}deg) rotateZ(${-dat.orientation[2]}deg)`
|
||||
|
||||
|
||||
/*
|
||||
console.log(dat)
|
||||
orientation[0] += dat[0] * multiplier
|
||||
orientation[1] += dat[1] * multiplier
|
||||
orientation[2] += dat[2] * multiplier
|
||||
// dataset.push(orientation[0])
|
||||
// while (dataset.length >= 50) {
|
||||
// dataset.shift();
|
||||
// }
|
||||
// addData(orientation[0] / multiplier)
|
||||
*/
|
||||
addData(dat.orientation[0])
|
||||
// addData(dat[0])
|
||||
//document.getElementById("gyroscope").style.transform = `rotateX(${-orientation[0]}deg) rotateY(${orientation[1]}deg) rotateZ(${-orientation[2]}deg) translateZ(50px)`
|
||||
}
|
||||
ws.onerror = function(evt) {
|
||||
print("ERROR: " + evt.data);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
document.getElementById("send").onclick = function(evt) {
|
||||
if (!ws) {
|
||||
return false;
|
||||
}
|
||||
print("SEND: " + input.value);
|
||||
ws.send(input.value);
|
||||
return false;
|
||||
};
|
||||
document.getElementById("close").onclick = function(evt) {
|
||||
if (!ws) {
|
||||
return false;
|
||||
}
|
||||
ws.close();
|
||||
return false;
|
||||
};
|
||||
});
|
||||
|
||||
</script>
|
||||
<style>
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
background: #000;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.scene {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border: 0px solid #CCC;
|
||||
margin: 160px;
|
||||
perspective: 400px;
|
||||
}
|
||||
|
||||
.cube {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
position: relative;
|
||||
transform-style: preserve-3d;
|
||||
transform: translateZ(-100px);
|
||||
/*transition: transform 25ms;*/
|
||||
}
|
||||
|
||||
.cube.show-front { transform: translateZ(-100px) rotateY( 0deg); }
|
||||
.cube.show-right { transform: translateZ(-100px) rotateY( -90deg); }
|
||||
.cube.show-back { transform: translateZ(-100px) rotateY(-180deg); }
|
||||
.cube.show-left { transform: translateZ(-100px) rotateY( 90deg); }
|
||||
.cube.show-top { transform: translateZ(-100px) rotateX( -90deg); }
|
||||
.cube.show-bottom { transform: translateZ(-100px) rotateX( 90deg); }
|
||||
|
||||
.cube__face {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border: 1px solid white;
|
||||
line-height: 200px;
|
||||
font-size: 40px;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cube__face--front { background: hsla( 0, 100%, 50%, 0.7); }
|
||||
.cube__face--right { background: hsla( 60, 100%, 50%, 0.7); }
|
||||
.cube__face--back { background: hsla(120, 100%, 50%, 0.7); }
|
||||
.cube__face--left { background: hsla(180, 100%, 50%, 0.7); }
|
||||
.cube__face--top { background: hsla(240, 100%, 50%, 0.7); }
|
||||
.cube__face--bottom { background: hsla(300, 100%, 50%, 0.7); }
|
||||
|
||||
.cube__face--front { transform: rotateY( 0deg) translateZ(100px); }
|
||||
.cube__face--right { transform: rotateY( 90deg) translateZ(100px); }
|
||||
.cube__face--back { transform: rotateY(180deg) translateZ(100px); }
|
||||
.cube__face--left { transform: rotateY(-90deg) translateZ(100px); }
|
||||
.cube__face--top { transform: rotateX( 90deg) translateZ(100px); }
|
||||
.cube__face--bottom { transform: rotateX(-90deg) translateZ(100px); }
|
||||
|
||||
label { margin-right: 10px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<table style="font-size: x-small">
|
||||
<tr>
|
||||
<td valign="top" width="50%">
|
||||
<p>Click "Open" to create a connection to the server.
|
||||
</p>
|
||||
<form>
|
||||
<button id="open">Open</button>
|
||||
<button id="close">Close</button>
|
||||
<p style="display: none" >
|
||||
<input id="input" type="text" value="Hello world!">
|
||||
<button id="send">Send</button>
|
||||
</p>
|
||||
</form>
|
||||
<div class="scene">
|
||||
<div id="gyroscope" class="cube">
|
||||
<div class="cube__face cube__face--front">front</div>
|
||||
<div class="cube__face cube__face--back">back</div>
|
||||
<div class="cube__face cube__face--right">right</div>
|
||||
<div class="cube__face cube__face--left">left</div>
|
||||
<div class="cube__face cube__face--top">top</div>
|
||||
<div class="cube__face cube__face--bottom">bottom</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="width: 600px; height: 400px;">
|
||||
<canvas id="myChart" width="400" height="200"></canvas>
|
||||
</div>
|
||||
<script>
|
||||
var ctx = document.getElementById('myChart').getContext('2d');
|
||||
var myChart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: new Array(GRAPH_RES),
|
||||
datasets: [{
|
||||
label: 'Z',
|
||||
backgroundColor: 'rgba(255, 99, 132, 0.2)',
|
||||
borderColor: 'rgba(255, 99, 132, 1)',
|
||||
borderWidth: 1,
|
||||
pointRadius: 0,
|
||||
lineTension: 0.5,
|
||||
data: new Array(GRAPH_RES)
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
// beginAtZero: true
|
||||
min: -100,
|
||||
max: 100
|
||||
}
|
||||
}]
|
||||
},
|
||||
animation: {
|
||||
duration: 0
|
||||
}
|
||||
}
|
||||
});
|
||||
myChart.data.labels.fill("", 0, GRAPH_RES);
|
||||
myChart.data.datasets.forEach((dataset) => dataset.data.fill(0, 0, GRAPH_RES))
|
||||
function addData(data) {
|
||||
myChart.data.labels.push("");
|
||||
myChart.data.datasets.forEach((dataset) => {
|
||||
dataset.data.push(data);
|
||||
});
|
||||
while (myChart.data.labels.length >= GRAPH_RES) {
|
||||
myChart.data.labels.shift();
|
||||
myChart.data.datasets.forEach((dataset) => dataset.data.shift())
|
||||
}
|
||||
myChart.update();
|
||||
};
|
||||
</script>
|
||||
</td>
|
||||
<td valign="top" width="50%">
|
||||
<div id="output"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
@ -1 +0,0 @@
|
||||
Subproject commit 8e879d5461753b0f06e171847408e618d51c9838
|
||||
@ -1,56 +0,0 @@
|
||||
body { margin: 0; padding: 0; }
|
||||
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
|
||||
|
||||
.legend {
|
||||
background-color: #fff;
|
||||
border-radius: 3px;
|
||||
bottom: 30px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
|
||||
padding: 10px;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.legend h4 {
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
.legend div span {
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
height: 10px;
|
||||
margin-right: 5px;
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
body{margin:0; padding:0; font-size:13px; font-family:Georgia, "Times New Roman", Times, serif; color:#919191; background-color:#232323;}
|
||||
|
||||
.float-child {
|
||||
width: 45%;
|
||||
float: left;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
canvas {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.sceneMap {
|
||||
width: 1000px;
|
||||
height: 500px;
|
||||
border: 0px solid #CCC;
|
||||
margin: 20px;
|
||||
perspective: 400px;
|
||||
}
|
||||
|
||||
.scene {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border: 0px solid #CCC;
|
||||
margin: 70px;
|
||||
perspective: 400px;
|
||||
}
|
||||
|
||||
label { margin-right: 10px; }
|
||||
@ -1,114 +0,0 @@
|
||||
/**
|
||||
* This file defines a line chart used in the full replay page, showing Ublox horizontal accuracy,
|
||||
* smartphone horizontal accuracy and distance between the positions of the Ublox
|
||||
* and the Smartphone at a same time in meters, over time.
|
||||
*
|
||||
* @authors Timo Volkmann, Frank Herkommer.
|
||||
*/
|
||||
|
||||
//list of all horizontal accuracies sent in by the Ublox
|
||||
let allAccSerial = []
|
||||
//list of all coordinates sent in by the Ublox
|
||||
let allSerialCoords = []
|
||||
|
||||
//Defines the chart and its properties
|
||||
let ctx1 = document.getElementById('accChart').getContext('2d');
|
||||
let accChart = new Chart(ctx1, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [{
|
||||
label: 'Ublox Horizontal acc. (m)',
|
||||
backgroundColor: 'rgba(255, 255, 255, 1)',
|
||||
borderColor: 'rgba(255, 255, 255, 1)',
|
||||
borderWidth: 1,
|
||||
fill: false,
|
||||
pointRadius: 0.5,
|
||||
lineTension: 0.5,
|
||||
data: []
|
||||
},
|
||||
{
|
||||
label: 'Smartphone Horizontal acc. (m)',
|
||||
backgroundColor: 'rgb(185,190,45)',
|
||||
borderColor: 'rgb(185,190,45)',
|
||||
borderWidth: 1,
|
||||
fill: false,
|
||||
pointRadius: 0.5,
|
||||
lineTension: 0.5,
|
||||
data: []
|
||||
},
|
||||
{
|
||||
label: 'Distance Ublox - Smartphone (m)',
|
||||
backgroundColor: 'rgba(30, 130, 76, 1)',
|
||||
borderColor: 'rgba(30, 130, 76, 1)',
|
||||
borderWidth: 1,
|
||||
fill: false,
|
||||
pointRadius: 0.5,
|
||||
lineTension: 0.5,
|
||||
data: []
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
min: 0,
|
||||
max: 20,
|
||||
}
|
||||
}],
|
||||
xAxes: [{
|
||||
type: 'time',
|
||||
time: {
|
||||
unit: 'second'
|
||||
}
|
||||
}]
|
||||
},
|
||||
animation: {
|
||||
duration: 0
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Function to calculate the distance between to coordinates at a same time using the vincenty algorithm.
|
||||
*
|
||||
* @param data all collected data.
|
||||
*/
|
||||
function addDistances(data){
|
||||
//collect all horizontal accuracies from serial source and tcp source.
|
||||
let serialHAccs = data.filter(el => el.ser != null).map(el => {
|
||||
return el.ser.HAcc
|
||||
})
|
||||
let tcpHAccs = data.filter(el => el.tcp != null).map(el => {
|
||||
return el.tcp.HAcc
|
||||
})
|
||||
//apply vincenty algorithm on coordinates from serial and tcp source.
|
||||
let distances = data.filter(el => el.ser != null && el.tcp != null).map((el, i, arr) => {
|
||||
// return distVincenty(el.ser.Position, el.tcp.Position)
|
||||
const plaindist = distVincenty(el.ser.Position, el.tcp.Position)
|
||||
arr[i]['distance'] = plaindist
|
||||
|
||||
// if closest measurements not happening in the exact same millisecond,
|
||||
// calculate traveled distance for the time difference and substract it from result
|
||||
// bear in mind that this is not exact because the two measurements are not always exactly aligned with
|
||||
// the direction of motion. that's okay because we only need to estimate the accuracy
|
||||
arr[i]['distanceCleanAbs'] = plaindist - Math.abs(el.ser.Speed / 1000 * el.differenceMs)
|
||||
return arr[i].distanceCleanAbs // plaindist - Math.abs(el.ser.Speed / 1000 * el.differenceMs)
|
||||
})
|
||||
|
||||
let timelabels = data.filter(el => el.tcp != null).map(el => {
|
||||
return el.tcp.Timestamp
|
||||
})
|
||||
if (timelabels.length === 0) {
|
||||
timelabels = data.filter(el => el.ser != null).map(el => {
|
||||
return el.ser.Timestamp
|
||||
})
|
||||
}
|
||||
|
||||
//add the data to the chart and update the hart
|
||||
accChart.data.labels = timelabels
|
||||
accChart.data.datasets[0].data = serialHAccs
|
||||
accChart.data.datasets[1].data = tcpHAccs
|
||||
accChart.data.datasets[2].data = distances
|
||||
accChart.update()
|
||||
}
|
||||
@ -1,79 +0,0 @@
|
||||
/**
|
||||
* This file defines an horizontal bar chart used in the live tracking page, showing Ublox horizontal accuracy,
|
||||
* smartphone horizontal accuracy and distance between the positions of the Ublox
|
||||
* and the Smartphone at a same time in meters.
|
||||
*
|
||||
* @authors Timo Volkmann, Frank Herkommer.
|
||||
*/
|
||||
|
||||
//Defines the chart and its properties.
|
||||
let ctx = document.getElementById("accuracy").getContext('2d');
|
||||
let barChart = new Chart(ctx, {
|
||||
type: 'horizontalBar',
|
||||
data: {
|
||||
labels: ["Meters"],
|
||||
datasets: [{
|
||||
label: 'Ublox H. acc.',
|
||||
data: [0, 0],
|
||||
backgroundColor: "rgba(214, 69, 65, 1)"
|
||||
}, {
|
||||
label: 'Smartphone H. acc.',
|
||||
data: [0, 0],
|
||||
backgroundColor: "rgba(30, 139, 195, 1)"
|
||||
}, {
|
||||
label: 'Dist. Ublox-Smartphone',
|
||||
data: [0],
|
||||
backgroundColor: "rgba(30, 139, 0, 1)"
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
xAxes: [{
|
||||
ticks: {
|
||||
min: 0,
|
||||
max: 10
|
||||
}
|
||||
}]
|
||||
},
|
||||
legend: {
|
||||
display: true,
|
||||
enabled: true
|
||||
},
|
||||
tooltips: {
|
||||
enabled: false,
|
||||
display: false
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Function to add the Horizontal and Vertical accuracy sent by the Ublox to the chart.
|
||||
* Called every time a message is received over serial connection from the server.
|
||||
* @param hacc horizontal accuracy in meters.
|
||||
* @param vacc vertical accuracy in meters
|
||||
*/
|
||||
function addSerialAccuracy(hacc, vacc){
|
||||
barChart.data.datasets[0].data = [hacc, vacc];
|
||||
barChart.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to add the Horizontal and Vertical accuracy sent by the Smartphone to the chart.
|
||||
* Called every time a message is received over tcp connection from the server.
|
||||
* @param hacc horizontal accuracy in meters.
|
||||
* @param vacc vertical accuracy in meters
|
||||
*/
|
||||
function addTCPAccuracy(hacc, vacc){
|
||||
barChart.data.datasets[1].data = [hacc, vacc];
|
||||
barChart.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to add the calculated distance between coordinates sent by the Ublox and the coordinates
|
||||
* sent by the smartphone to the chart.
|
||||
* @param dist distance calculated in meters.
|
||||
*/
|
||||
function addDistanceToBarChart(dist){
|
||||
barChart.data.datasets[2].data = [dist];
|
||||
barChart.update();
|
||||
}
|
||||
43
static/scripts/chart.js
Normal file
43
static/scripts/chart.js
Normal file
@ -0,0 +1,43 @@
|
||||
var ctx = document.getElementById('myChart').getContext('2d');
|
||||
var myChart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: new Array(GRAPH_RES),
|
||||
datasets: [{
|
||||
label: 'Z',
|
||||
backgroundColor: 'rgba(255, 99, 132, 0.2)',
|
||||
borderColor: 'rgba(255, 99, 132, 1)',
|
||||
borderWidth: 1,
|
||||
pointRadius: 0,
|
||||
lineTension: 0.5,
|
||||
data: new Array(GRAPH_RES)
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
// beginAtZero: true
|
||||
min: -100,
|
||||
max: 100
|
||||
}
|
||||
}]
|
||||
},
|
||||
animation: {
|
||||
duration: 0
|
||||
}
|
||||
}
|
||||
});
|
||||
myChart.data.labels.fill("", 0, GRAPH_RES);
|
||||
myChart.data.datasets.forEach((dataset) => dataset.data.fill(0, 0, GRAPH_RES))
|
||||
function addData(data) {
|
||||
myChart.data.labels.push("");
|
||||
myChart.data.datasets.forEach((dataset) => {
|
||||
dataset.data.push(data);
|
||||
});
|
||||
while (myChart.data.labels.length >= GRAPH_RES) {
|
||||
myChart.data.labels.shift();
|
||||
myChart.data.datasets.forEach((dataset) => dataset.data.shift())
|
||||
}
|
||||
myChart.update();
|
||||
};
|
||||
@ -1,78 +0,0 @@
|
||||
/**
|
||||
* Function to calculate distance between two coordinates using the haversine algorithm (less precise).
|
||||
* @param coord1 first set of coordinates.
|
||||
* @param coord2 second set of coordinates.
|
||||
* @returns {number} distance between the two points in meters.
|
||||
*/
|
||||
function distanceInMetersBetweenEarthCoordinates(coord1, coord2) {
|
||||
let long1 = coord1[0]
|
||||
let lat1 = coord1[1]
|
||||
let long2 = coord2[0]
|
||||
let lat2 = coord2[1]
|
||||
|
||||
let earthRadiusM = 6371000
|
||||
|
||||
let phi1 = lat1 * Math.PI / 180
|
||||
let phi2 = lat2 * Math.PI / 180
|
||||
|
||||
let dlat = (lat2-lat1) * Math.PI / 180
|
||||
let dlong = (long2 - long1) * Math.PI / 180
|
||||
|
||||
let a = Math.sin(dlat/2) * Math.sin(dlat/2) +
|
||||
Math.cos(phi1) * Math.cos(phi2) *
|
||||
Math.sin(dlong/2) * Math.sin(dlong/2)
|
||||
let c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a))
|
||||
return earthRadiusM * c
|
||||
}
|
||||
|
||||
|
||||
Number.prototype.toRad = function () { return this * Math.PI / 180; }
|
||||
|
||||
/**
|
||||
* Function to calculate distance between two coordinates using the vincenty algorithm (more precise).
|
||||
* @param coord1 first set of coordinates.
|
||||
* @param coord2 second set of coordinates.
|
||||
* @returns {string|number} distance between the two point is meters.
|
||||
*/
|
||||
function distVincenty(coord1, coord2) {
|
||||
const lon1 = coord1[0]
|
||||
const lat1 = coord1[1]
|
||||
const lon2 = coord2[0]
|
||||
const lat2 = coord2[1]
|
||||
var a = 6378137, b = 6356752.314245, f = 1/298.257223563; // WGS-84 ellipsoid params
|
||||
var L = (lon2-lon1).toRad()
|
||||
var U1 = Math.atan((1-f) * Math.tan(lat1.toRad()));
|
||||
var U2 = Math.atan((1-f) * Math.tan(lat2.toRad()));
|
||||
var sinU1 = Math.sin(U1), cosU1 = Math.cos(U1);
|
||||
var sinU2 = Math.sin(U2), cosU2 = Math.cos(U2);
|
||||
|
||||
var lambda = L, lambdaP, iterLimit = 100;
|
||||
do {
|
||||
var sinLambda = Math.sin(lambda), cosLambda = Math.cos(lambda);
|
||||
var sinSigma = Math.sqrt((cosU2*sinLambda) * (cosU2*sinLambda) +
|
||||
(cosU1*sinU2-sinU1*cosU2*cosLambda) * (cosU1*sinU2-sinU1*cosU2*cosLambda));
|
||||
if (sinSigma===0) return 0; // co-incident points
|
||||
var cosSigma = sinU1*sinU2 + cosU1*cosU2*cosLambda;
|
||||
var sigma = Math.atan2(sinSigma, cosSigma);
|
||||
var sinAlpha = cosU1 * cosU2 * sinLambda / sinSigma;
|
||||
var cosSqAlpha = 1 - sinAlpha*sinAlpha;
|
||||
var cos2SigmaM = cosSigma - 2*sinU1*sinU2/cosSqAlpha;
|
||||
if (isNaN(cos2SigmaM)) cos2SigmaM = 0; // equatorial line: cosSqAlpha=0 (§6)
|
||||
var C = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha));
|
||||
lambdaP = lambda;
|
||||
lambda = L + (1-C) * f * sinAlpha *
|
||||
(sigma + C*sinSigma*(cos2SigmaM+C*cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)));
|
||||
} while (Math.abs(lambda-lambdaP) > 1e-12 && --iterLimit>0);
|
||||
|
||||
if (iterLimit===0) return NaN // formula failed to converge
|
||||
|
||||
var uSq = cosSqAlpha * (a*a - b*b) / (b*b);
|
||||
var A = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)));
|
||||
var B = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)));
|
||||
var deltaSigma = B*sinSigma*(cos2SigmaM+B/4*(cosSigma*(-1+2*cos2SigmaM*cos2SigmaM)-
|
||||
B/6*cos2SigmaM*(-3+4*sinSigma*sinSigma)*(-3+4*cos2SigmaM*cos2SigmaM)));
|
||||
var s = b*A*(sigma-deltaSigma);
|
||||
|
||||
s = s.toFixed(3); // round to 1mm precision
|
||||
return s;
|
||||
}
|
||||
737
static/scripts/hike.geo.json
Normal file
737
static/scripts/hike.geo.json
Normal file
@ -0,0 +1,737 @@
|
||||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "LineString",
|
||||
"coordinates": [
|
||||
[
|
||||
9.196275472640991,
|
||||
49.12280972701122
|
||||
],
|
||||
[
|
||||
9.19629693031311,
|
||||
49.122757066649065
|
||||
],
|
||||
[
|
||||
9.196267426013947,
|
||||
49.1227219597099
|
||||
],
|
||||
[
|
||||
9.196237921714783,
|
||||
49.12268685274588
|
||||
],
|
||||
[
|
||||
9.196205735206604,
|
||||
49.122642969005895
|
||||
],
|
||||
[
|
||||
9.196168184280396,
|
||||
49.12259908522708
|
||||
],
|
||||
[
|
||||
9.196090400218964,
|
||||
49.122556956762885
|
||||
],
|
||||
[
|
||||
9.196015298366547,
|
||||
49.12252536039125
|
||||
],
|
||||
[
|
||||
9.195816814899445,
|
||||
49.122421794365344
|
||||
],
|
||||
[
|
||||
9.19578731060028,
|
||||
49.12246041223081
|
||||
],
|
||||
[
|
||||
9.195752441883085,
|
||||
49.122495519355134
|
||||
],
|
||||
[
|
||||
9.195720255374908,
|
||||
49.1225306264546
|
||||
],
|
||||
[
|
||||
9.195685386657715,
|
||||
49.12257099958827
|
||||
],
|
||||
[
|
||||
9.195658564567566,
|
||||
49.122602595930815
|
||||
],
|
||||
[
|
||||
9.195634424686432,
|
||||
49.12263419225324
|
||||
],
|
||||
[
|
||||
9.195604920387268,
|
||||
49.12266052250654
|
||||
],
|
||||
[
|
||||
9.19557273387909,
|
||||
49.12268334204809
|
||||
],
|
||||
[
|
||||
9.195548593997955,
|
||||
49.12271318297122
|
||||
],
|
||||
[
|
||||
9.195532500743866,
|
||||
49.12273951318259
|
||||
],
|
||||
[
|
||||
9.195497632026672,
|
||||
49.12276057734161
|
||||
],
|
||||
[
|
||||
9.19557273387909,
|
||||
49.12281850373281
|
||||
],
|
||||
[
|
||||
9.195524454116821,
|
||||
49.12285712128936
|
||||
],
|
||||
[
|
||||
9.195497632026672,
|
||||
49.12287818539843
|
||||
],
|
||||
[
|
||||
9.195476174354553,
|
||||
49.122904515522194
|
||||
],
|
||||
[
|
||||
9.195586144924162,
|
||||
49.12300983587742
|
||||
],
|
||||
[
|
||||
9.195840954780579,
|
||||
49.1232152099268
|
||||
],
|
||||
[
|
||||
9.19605016708374,
|
||||
49.1233942532759
|
||||
],
|
||||
[
|
||||
9.196152091026306,
|
||||
49.1235346789797
|
||||
],
|
||||
[
|
||||
9.196280837059021,
|
||||
49.12368212554077
|
||||
],
|
||||
[
|
||||
9.196393489837646,
|
||||
49.12382606104651
|
||||
],
|
||||
[
|
||||
9.196511507034302,
|
||||
49.123924358225025
|
||||
],
|
||||
[
|
||||
9.196581244468689,
|
||||
49.12404371882266
|
||||
],
|
||||
[
|
||||
9.196720719337463,
|
||||
49.124173610911306
|
||||
],
|
||||
[
|
||||
9.196838736534119,
|
||||
49.12435967195905
|
||||
],
|
||||
[
|
||||
9.196951389312744,
|
||||
49.124501850213676
|
||||
],
|
||||
[
|
||||
9.197013080120087,
|
||||
49.1245896143649
|
||||
],
|
||||
[
|
||||
9.19705867767334,
|
||||
49.12465280445759
|
||||
],
|
||||
[
|
||||
9.19714719057083,
|
||||
49.12476865275172
|
||||
],
|
||||
[
|
||||
9.197292029857635,
|
||||
49.12495120102961
|
||||
],
|
||||
[
|
||||
9.197361767292023,
|
||||
49.12506529336202
|
||||
],
|
||||
[
|
||||
9.197455644607544,
|
||||
49.125175874910624
|
||||
],
|
||||
[
|
||||
9.197522699832916,
|
||||
49.12529347723932
|
||||
],
|
||||
[
|
||||
9.197605848312378,
|
||||
49.12543565281655
|
||||
],
|
||||
[
|
||||
9.197745323181152,
|
||||
49.125690163634275
|
||||
],
|
||||
[
|
||||
9.197841882705688,
|
||||
49.12584989044582
|
||||
],
|
||||
[
|
||||
9.19790893793106,
|
||||
49.12598328826778
|
||||
],
|
||||
[
|
||||
9.197978675365448,
|
||||
49.12612195141281
|
||||
],
|
||||
[
|
||||
9.198064506053925,
|
||||
49.12627290072483
|
||||
],
|
||||
[
|
||||
9.19819325208664,
|
||||
49.126525652032335
|
||||
],
|
||||
[
|
||||
9.198254942893982,
|
||||
49.12668011053043
|
||||
],
|
||||
[
|
||||
9.198305904865265,
|
||||
49.12679770929164
|
||||
],
|
||||
[
|
||||
9.198405146598816,
|
||||
49.12695743253551
|
||||
],
|
||||
[
|
||||
9.198488295078278,
|
||||
49.12716981099699
|
||||
],
|
||||
[
|
||||
9.198619723320007,
|
||||
49.12720315959838
|
||||
],
|
||||
[
|
||||
9.198799431324005,
|
||||
49.127229487425765
|
||||
],
|
||||
[
|
||||
9.199027419090271,
|
||||
49.12716630061657
|
||||
],
|
||||
[
|
||||
9.19931173324585,
|
||||
49.127129441607394
|
||||
],
|
||||
[
|
||||
9.199504852294922,
|
||||
49.12708556179883
|
||||
],
|
||||
[
|
||||
9.19965773820877,
|
||||
49.12704870272959
|
||||
],
|
||||
[
|
||||
9.199883043766022,
|
||||
49.12700482284956
|
||||
],
|
||||
[
|
||||
9.200116395950317,
|
||||
49.1269732293119
|
||||
],
|
||||
[
|
||||
9.200357794761658,
|
||||
49.12690653177737
|
||||
],
|
||||
[
|
||||
9.200548231601715,
|
||||
49.12688546937944
|
||||
],
|
||||
[
|
||||
9.20065551996231,
|
||||
49.126911797375485
|
||||
],
|
||||
[
|
||||
9.200770854949951,
|
||||
49.12695743253551
|
||||
],
|
||||
[
|
||||
9.200899600982666,
|
||||
49.12702061961085
|
||||
],
|
||||
[
|
||||
9.20103371143341,
|
||||
49.12706800986451
|
||||
],
|
||||
[
|
||||
9.201240241527557,
|
||||
49.12711891045688
|
||||
],
|
||||
[
|
||||
9.20141190290451,
|
||||
49.12714874871086
|
||||
],
|
||||
[
|
||||
9.2015540599823,
|
||||
49.127191750868846
|
||||
],
|
||||
[
|
||||
9.201587587594986,
|
||||
49.127187362895256
|
||||
],
|
||||
[
|
||||
9.201736450195312,
|
||||
49.1271601574503
|
||||
],
|
||||
[
|
||||
9.201810210943222,
|
||||
49.127157524664504
|
||||
],
|
||||
[
|
||||
9.201871901750565,
|
||||
49.12715313668789
|
||||
],
|
||||
[
|
||||
9.201933592557907,
|
||||
49.12710925690026
|
||||
],
|
||||
[
|
||||
9.202055633068085,
|
||||
49.12697498450896
|
||||
],
|
||||
[
|
||||
9.20224204659462,
|
||||
49.12691530777389
|
||||
],
|
||||
[
|
||||
9.20237347483635,
|
||||
49.126887224579605
|
||||
],
|
||||
[
|
||||
9.202480763196945,
|
||||
49.126842466955814
|
||||
],
|
||||
[
|
||||
9.20254647731781,
|
||||
49.12681613892294
|
||||
],
|
||||
[
|
||||
9.202671200037003,
|
||||
49.126769626030736
|
||||
],
|
||||
[
|
||||
9.202869683504105,
|
||||
49.126692396981234
|
||||
],
|
||||
[
|
||||
9.202970266342163,
|
||||
49.12665729282806
|
||||
],
|
||||
[
|
||||
9.203054755926132,
|
||||
49.12662218865002
|
||||
],
|
||||
[
|
||||
9.203156679868698,
|
||||
49.12659147247387
|
||||
],
|
||||
[
|
||||
9.203227758407593,
|
||||
49.126569532336404
|
||||
],
|
||||
[
|
||||
9.203289449214935,
|
||||
49.126551980219446
|
||||
],
|
||||
[
|
||||
9.203341752290726,
|
||||
49.12653179527724
|
||||
],
|
||||
[
|
||||
9.203158020973206,
|
||||
49.126483526903876
|
||||
],
|
||||
[
|
||||
9.203088283538818,
|
||||
49.12646334193381
|
||||
],
|
||||
[
|
||||
9.203002452850342,
|
||||
49.12644140173965
|
||||
],
|
||||
[
|
||||
9.202857613563538,
|
||||
49.12640278697433
|
||||
],
|
||||
[
|
||||
9.202712774276733,
|
||||
49.126357151303814
|
||||
],
|
||||
[
|
||||
9.202632308006287,
|
||||
49.126325557353475
|
||||
],
|
||||
[
|
||||
9.202412366867065,
|
||||
49.12626236939239
|
||||
],
|
||||
[
|
||||
9.202256798744202,
|
||||
49.126213223144774
|
||||
],
|
||||
[
|
||||
9.202122688293455,
|
||||
49.12616758729978
|
||||
],
|
||||
[
|
||||
9.201961755752563,
|
||||
49.12612546186714
|
||||
],
|
||||
[
|
||||
9.2018061876297,
|
||||
49.12607982594142
|
||||
],
|
||||
[
|
||||
9.201698899269104,
|
||||
49.126037700434225
|
||||
],
|
||||
[
|
||||
9.201596975326538,
|
||||
49.125999085354515
|
||||
],
|
||||
[
|
||||
9.20129120349884,
|
||||
49.125883239934964
|
||||
],
|
||||
[
|
||||
9.201119542121887,
|
||||
49.125827072361396
|
||||
],
|
||||
[
|
||||
9.200921058654785,
|
||||
49.12578143616102
|
||||
],
|
||||
[
|
||||
9.200685024261473,
|
||||
49.125676121692166
|
||||
],
|
||||
[
|
||||
9.200513362884521,
|
||||
49.12560591192202
|
||||
],
|
||||
[
|
||||
9.200336337089539,
|
||||
49.12554623353922
|
||||
],
|
||||
[
|
||||
9.199842810630798,
|
||||
49.125360176943595
|
||||
],
|
||||
[
|
||||
9.199681878089905,
|
||||
49.12527592467067
|
||||
],
|
||||
[
|
||||
9.1995370388031,
|
||||
49.12522677744532
|
||||
],
|
||||
[
|
||||
9.199456572532654,
|
||||
49.12518816173411
|
||||
],
|
||||
[
|
||||
9.19932246208191,
|
||||
49.12513199337321
|
||||
],
|
||||
[
|
||||
9.199220538139343,
|
||||
49.12508635653314
|
||||
],
|
||||
[
|
||||
9.199113249778748,
|
||||
49.125023166992925
|
||||
],
|
||||
[
|
||||
9.199016690254211,
|
||||
49.12496699844514
|
||||
],
|
||||
[
|
||||
9.198925495147705,
|
||||
49.1248932771296
|
||||
],
|
||||
[
|
||||
9.198732376098633,
|
||||
49.12480551351584
|
||||
],
|
||||
[
|
||||
9.198582172393799,
|
||||
49.124721260300475
|
||||
],
|
||||
[
|
||||
9.198474884033203,
|
||||
49.124647538619605
|
||||
],
|
||||
[
|
||||
9.198367595672607,
|
||||
49.12459839077146
|
||||
],
|
||||
[
|
||||
9.198265671730042,
|
||||
49.12455626400573
|
||||
],
|
||||
[
|
||||
9.198126196861267,
|
||||
49.124542221742516
|
||||
],
|
||||
[
|
||||
9.198099374771118,
|
||||
49.12450360549822
|
||||
],
|
||||
[
|
||||
9.198126196861267,
|
||||
49.12441584119478
|
||||
],
|
||||
[
|
||||
9.198174476623533,
|
||||
49.12433509789843
|
||||
],
|
||||
[
|
||||
9.19828176498413,
|
||||
49.12430701324279
|
||||
],
|
||||
[
|
||||
9.19831931591034,
|
||||
49.12427190740087
|
||||
],
|
||||
[
|
||||
9.198254942893982,
|
||||
49.12420871682283
|
||||
],
|
||||
[
|
||||
9.198115468025208,
|
||||
49.124149036758475
|
||||
],
|
||||
[
|
||||
9.197981357574463,
|
||||
49.124085846023824
|
||||
],
|
||||
[
|
||||
9.197836518287659,
|
||||
49.124026165811614
|
||||
],
|
||||
[
|
||||
9.197707772254944,
|
||||
49.12395595370529
|
||||
],
|
||||
[
|
||||
9.197557568550108,
|
||||
49.12386467781845
|
||||
],
|
||||
[
|
||||
9.197487831115723,
|
||||
49.12381201857656
|
||||
],
|
||||
[
|
||||
9.197385907173157,
|
||||
49.123717231800214
|
||||
],
|
||||
[
|
||||
9.197214245796204,
|
||||
49.12367510428589
|
||||
],
|
||||
[
|
||||
9.197010397911072,
|
||||
49.123566274708274
|
||||
],
|
||||
[
|
||||
9.196908473968506,
|
||||
49.123474998104186
|
||||
],
|
||||
[
|
||||
9.196704626083374,
|
||||
49.123401274570526
|
||||
],
|
||||
[
|
||||
9.196602702140808,
|
||||
49.123348614836544
|
||||
],
|
||||
[
|
||||
9.196484684944153,
|
||||
49.123260848488954
|
||||
],
|
||||
[
|
||||
9.196339845657349,
|
||||
49.12319414596088
|
||||
],
|
||||
[
|
||||
9.196216464042664,
|
||||
49.12313095400942
|
||||
],
|
||||
[
|
||||
9.196135997772217,
|
||||
49.12306776197748
|
||||
],
|
||||
[
|
||||
9.19607162475586,
|
||||
49.12299754851418
|
||||
],
|
||||
[
|
||||
9.195937514305115,
|
||||
49.12295893106699
|
||||
],
|
||||
[
|
||||
9.195835590362549,
|
||||
49.12289222813283
|
||||
],
|
||||
[
|
||||
9.195733666419983,
|
||||
49.12282903579667
|
||||
],
|
||||
[
|
||||
9.195638447999954,
|
||||
49.122754433629495
|
||||
],
|
||||
[
|
||||
9.195600226521492,
|
||||
49.12273293063105
|
||||
],
|
||||
[
|
||||
9.195574074983597,
|
||||
49.122708355764296
|
||||
],
|
||||
[
|
||||
9.195574074983597,
|
||||
49.12269431297779
|
||||
],
|
||||
[
|
||||
9.195623695850372,
|
||||
49.1226412136555
|
||||
],
|
||||
[
|
||||
9.195666611194609,
|
||||
49.12260961733753
|
||||
],
|
||||
[
|
||||
9.195688739418983,
|
||||
49.12258021519025
|
||||
],
|
||||
[
|
||||
9.195733666419983,
|
||||
49.12253106529318
|
||||
],
|
||||
[
|
||||
9.19575646519661,
|
||||
49.12250034658276
|
||||
],
|
||||
[
|
||||
9.195783287286758,
|
||||
49.12247269972715
|
||||
],
|
||||
[
|
||||
9.195801392197609,
|
||||
49.12244988008865
|
||||
],
|
||||
[
|
||||
9.195815473794937,
|
||||
49.122438470265486
|
||||
],
|
||||
[
|
||||
9.195830225944519,
|
||||
49.12242047784666
|
||||
],
|
||||
[
|
||||
9.195859730243683,
|
||||
49.122431887674
|
||||
],
|
||||
[
|
||||
9.195901304483414,
|
||||
49.122448563570735
|
||||
],
|
||||
[
|
||||
9.195931479334831,
|
||||
49.12246787249679
|
||||
],
|
||||
[
|
||||
9.195965006947517,
|
||||
49.12248367070343
|
||||
],
|
||||
[
|
||||
9.195998534560204,
|
||||
49.122498152388445
|
||||
],
|
||||
[
|
||||
9.19603407382965,
|
||||
49.12251307290797
|
||||
],
|
||||
[
|
||||
9.196063578128815,
|
||||
49.12253501484029
|
||||
],
|
||||
[
|
||||
9.196093752980232,
|
||||
49.122546424641236
|
||||
],
|
||||
[
|
||||
9.196127280592918,
|
||||
49.1225600286313
|
||||
],
|
||||
[
|
||||
9.19615812599659,
|
||||
49.12258109286655
|
||||
],
|
||||
[
|
||||
9.196201711893082,
|
||||
49.12261927177015
|
||||
],
|
||||
[
|
||||
9.196238592267036,
|
||||
49.12267237111598
|
||||
],
|
||||
[
|
||||
9.196262061595917,
|
||||
49.12270045669739
|
||||
],
|
||||
[
|
||||
9.196281507611275,
|
||||
49.122722837383684
|
||||
],
|
||||
[
|
||||
9.196305647492409,
|
||||
49.122746534569934
|
||||
],
|
||||
[
|
||||
9.196302965283394,
|
||||
49.1227693540719
|
||||
],
|
||||
[
|
||||
9.196292236447334,
|
||||
49.12279392890845
|
||||
],
|
||||
[
|
||||
9.196286201477049,
|
||||
49.122811482355665
|
||||
],
|
||||
[
|
||||
9.19628955423832,
|
||||
49.12282815812477
|
||||
],
|
||||
[
|
||||
9.196309000253677,
|
||||
49.1228479057388
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -1,211 +0,0 @@
|
||||
let width = document.getElementById("viewport").offsetWidth
|
||||
let height = 300;
|
||||
|
||||
let renderer = new THREE.WebGLRenderer({ antialias: true });
|
||||
renderer.setSize(width, height);
|
||||
document.getElementById("viewport").appendChild(renderer.domElement);
|
||||
|
||||
let scene = new THREE.Scene();
|
||||
|
||||
let cubeGeometry = new THREE.CubeGeometry(100, 100/2, 100*1.5);
|
||||
let cubeGeometry2 = new THREE.CubeGeometry(120, 120/2, 120*1.5);
|
||||
|
||||
const color = new THREE.Color("rgb(255, 0, 0)");
|
||||
let cubeMaterial = new THREE.MeshPhongMaterial({
|
||||
color: color,
|
||||
opacity: 1,
|
||||
transparent: true,
|
||||
});
|
||||
const color2 = new THREE.Color("rgb(48,117,255)");
|
||||
let cubeMaterial2 = new THREE.MeshPhongMaterial({
|
||||
color: color2,
|
||||
opacity: 0.5,
|
||||
transparent: true,
|
||||
});
|
||||
let cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
|
||||
let cube2 = new THREE.Mesh(cubeGeometry2, cubeMaterial2);
|
||||
scene.add(cube);
|
||||
scene.add(cube2);
|
||||
|
||||
let camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 6000);
|
||||
camera.position.y = 100;
|
||||
camera.position.z = 240;
|
||||
camera.lookAt(cube.position);
|
||||
|
||||
scene.add(camera);
|
||||
|
||||
let skyboxGeometry = new THREE.CubeGeometry(5000, 5000, 5000);
|
||||
let skyboxMaterial = new THREE.MeshBasicMaterial({ color: 0x232323, side: THREE.BackSide });
|
||||
let skybox = new THREE.Mesh(skyboxGeometry, skyboxMaterial);
|
||||
|
||||
scene.add(skybox);
|
||||
|
||||
const colorl = 0xFFFFFF;
|
||||
const intensity = 1;
|
||||
const light = new THREE.DirectionalLight(colorl, intensity);
|
||||
|
||||
let pointLight = new THREE.PointLight(0xffffff);
|
||||
pointLight.position.set(0, 300, 200);
|
||||
light.position.set(0, 300, 200);
|
||||
|
||||
scene.add(pointLight);
|
||||
|
||||
cube.position.x = 0
|
||||
cube2.position.x = 0
|
||||
|
||||
|
||||
|
||||
// calibration globals
|
||||
let manCalibration = new THREE.Euler( 0, 0, 0, 'XYZ' )
|
||||
let calibrationRot = new THREE.Quaternion()
|
||||
let calPitch = 0
|
||||
let calRoll = 0
|
||||
let calYaw = 0
|
||||
|
||||
let quaternionOffset = document.getElementById("quaternionOffset")
|
||||
|
||||
// function to set current cube rotation from sensor data with respect to calibration
|
||||
function renderTCP(x, y, z) {
|
||||
let calibration = new THREE.Quaternion().setFromEuler(manCalibration)
|
||||
let eul = new THREE.Euler( x, y, z, 'YXZ' );
|
||||
|
||||
cube2.quaternion.setFromEuler(eul).multiply(calibrationRot).multiply(calibration)
|
||||
|
||||
quaternionOffset.innerHTML = `Lage Abweichung: ${(cube2.quaternion.angleTo(cube.quaternion) * 180 / Math.PI).toFixed(2) }°`
|
||||
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
// function to set current cube rotation from sensor data
|
||||
function renderSerial(x, y, z) {
|
||||
let eul = new THREE.Euler( x, y, z, 'YXZ' ); // XYZ XZY YZX YXZ ZXY ZYX
|
||||
|
||||
cube.quaternion.setFromEuler(eul)
|
||||
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
renderTCP(0, 0, 0);
|
||||
renderSerial(0, 0, 0);
|
||||
|
||||
let pitchRange = document.getElementById("pitchRange");
|
||||
let yawRange = document.getElementById("yawRange");
|
||||
let rollRange = document.getElementById("rollRange");
|
||||
|
||||
pitchRange.oninput = () => {
|
||||
manCalibration.x = pitchRange.value * Math.PI / 180
|
||||
}
|
||||
yawRange.oninput = () => {
|
||||
manCalibration.y = yawRange.value * Math.PI / 180
|
||||
}
|
||||
rollRange.oninput = () => {
|
||||
manCalibration.z = rollRange.value * Math.PI / 180
|
||||
}
|
||||
|
||||
function delCalibration(evt) {
|
||||
calibrationRot = new THREE.Quaternion()
|
||||
manCalibration = new THREE.Euler( 0, 0, 0, 'XYZ' )
|
||||
pitchRange.value = 0
|
||||
yawRange.value = 0
|
||||
rollRange.value = 0
|
||||
calRoll = 0
|
||||
calPitch = 0
|
||||
}
|
||||
|
||||
let calState = false;
|
||||
function manualCalibration(evt) {
|
||||
let con = document.getElementById("manCalContainer")
|
||||
console.log("mancal", con.style.display)
|
||||
if (calState === false) {
|
||||
delCalibration()
|
||||
calState = !calState
|
||||
console.log("mancal ON")
|
||||
con.style.display = "block"
|
||||
} else {
|
||||
delCalibration()
|
||||
calState = !calState
|
||||
console.log("mancal OFF")
|
||||
con.style.display = "none"
|
||||
manCalibration = new THREE.Euler( 0, 0, 0, 'XYZ' )
|
||||
pitchRange.value = 0
|
||||
yawRange.value = 0
|
||||
rollRange.value = 0
|
||||
}
|
||||
}
|
||||
function calibrate(evt) {
|
||||
let serOrientation = cube.quaternion.clone()
|
||||
let tcpOrientation = cube2.quaternion.clone().multiply(calibrationRot.clone().invert())
|
||||
let diff = tcpOrientation.invert().multiply(serOrientation)
|
||||
|
||||
let old = new THREE.Euler().setFromQuaternion( cube2.quaternion, 'YXZ' )
|
||||
let dif = new THREE.Euler().setFromQuaternion( diff )
|
||||
console.log("OLD:","pitch", old.x * 180/Math.PI, "yaw", old.y * 180/Math.PI, "roll", old.z * 180/Math.PI)
|
||||
console.log("DIFF:","pitch", dif.x * 180/Math.PI, "yaw", dif.y * 180/Math.PI, "roll", dif.z * 180/Math.PI)
|
||||
calPitch = dif.x
|
||||
calYaw = dif.y
|
||||
calRoll = dif.z
|
||||
calibrationRot = diff
|
||||
}
|
||||
document.getElementById("deleteCalibration").onclick = delCalibration
|
||||
document.getElementById("manualCalibration").onclick = manualCalibration
|
||||
document.getElementById("calibrate").onclick = calibrate
|
||||
|
||||
|
||||
// indicators from https://github.com/sebmatton/jQuery-Flight-Indicators.git
|
||||
|
||||
let options = {
|
||||
size : 200, // Sets the size in pixels of the indicator (square)
|
||||
roll : 0, // Roll angle in degrees for an attitude indicator
|
||||
pitch : 0, // Pitch angle in degrees for an attitude indicator
|
||||
heading: 0, // Heading angle in degrees for an heading indicator
|
||||
vario: 0, // Variometer in 1000 feets/min for the variometer indicator
|
||||
airspeed: 0, // Air speed in knots for an air speed indicator
|
||||
altitude: 0, // Altitude in feets for an altimeter indicator
|
||||
pressure: 1000, // Pressure in hPa for an altimeter indicator
|
||||
showBox : true, // Sets if the outer squared box is visible or not (true or false)
|
||||
img_directory : 'static/indicators/img/' // The directory where the images are saved to
|
||||
}
|
||||
|
||||
let headingSer = $.flightIndicator('#headingSer', 'heading', options);
|
||||
let headingTcp = $.flightIndicator('#headingTcp', 'heading', options);
|
||||
let attitudeSer = $.flightIndicator('#attitudeSer', 'attitude', options);
|
||||
let attitudeTcp = $.flightIndicator('#attitudeTcp', 'attitude', options);
|
||||
let airspeed = $.flightIndicator('#airspeed', 'airspeed', options);
|
||||
let altimeter = $.flightIndicator('#altimeter', 'altimeter', options);
|
||||
|
||||
let airspeedLabel = document.getElementById("airspeedLabel")
|
||||
let altitudeLabel = document.getElementById("altitudeLabel")
|
||||
|
||||
// function to set analog indictors from current sensor data
|
||||
function setIndicatorsTcp(sensordata) {
|
||||
let q = new THREE.Euler().setFromQuaternion( cube2.quaternion, 'YXZ' ) // XYZ XZY YZX YXZ ZXY ZYX
|
||||
|
||||
if (sensordata.Orientation[0] !== 0 && sensordata.Orientation[1] !== 0) {
|
||||
attitudeTcp.setPitch(q.x * 180 / Math.PI)
|
||||
attitudeTcp.setRoll(q.z * 180 / Math.PI)
|
||||
}
|
||||
let heading = sensordata.HeadDevice
|
||||
if (heading !== 0) {
|
||||
headingTcp.setHeading(heading)
|
||||
}
|
||||
}
|
||||
|
||||
// function to set analog indictors from current sensor data
|
||||
function setIndicatorsSer(sensordata) {
|
||||
if (sensordata.Orientation[0] !== 0 && sensordata.Orientation[1] !== 0) {
|
||||
attitudeSer.setPitch(sensordata.Orientation[0])
|
||||
attitudeSer.setRoll(sensordata.Orientation[1])
|
||||
}
|
||||
let heading = sensordata.HeadMotion
|
||||
if (heading !== 0) {
|
||||
headingSer.setHeading(heading)
|
||||
}
|
||||
if (sensordata.Speed !== 0) {
|
||||
airspeed.setAirSpeed(sensordata.Speed * 3.6)
|
||||
airspeedLabel.innerHTML = `Ref. Speed: ${(sensordata.Speed * 3.6).toFixed(1)} km/h`
|
||||
}
|
||||
if (sensordata.Position[2] !== 0) {
|
||||
altimeter.setAltitude((sensordata.Position[2] * 10).toFixed())
|
||||
altitudeLabel.innerHTML = `HMSL: ${(sensordata.Position[2]).toFixed(2)} m`
|
||||
}
|
||||
}
|
||||
@ -1,30 +1,10 @@
|
||||
/**
|
||||
* This file defines the map in satellite style for the live tracking page, defines and updates its data sources.
|
||||
*
|
||||
* @authors Timo Volkmann, Frank Herkommer.
|
||||
*/
|
||||
|
||||
mapboxgl.accessToken = 'pk.eyJ1IjoiZmhlcmtvbW0iLCJhIjoiY2tobm81bXppMGVuNzMyazY3eDU0M2dyaSJ9.qWJrwtv7KitW60pzs6h3Gg';
|
||||
let map = new mapboxgl.Map({
|
||||
var map = new mapboxgl.Map({
|
||||
container: 'map',
|
||||
style: 'mapbox://styles/mapbox/satellite-v9',
|
||||
style: 'mapbox://styles/mapbox/streets-v11',
|
||||
zoom: 0
|
||||
});
|
||||
|
||||
//Empty geoJSON for coordinates from TCP input
|
||||
let emptyTCP = {
|
||||
type: "FeatureCollection",
|
||||
features: [
|
||||
{
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "LineString",
|
||||
coordinates: []
|
||||
}
|
||||
}]
|
||||
}
|
||||
//Empty geoJSON for coordinates from serial input
|
||||
let emptySERIAL = {
|
||||
var empty = {
|
||||
type: "FeatureCollection",
|
||||
features: [
|
||||
{
|
||||
@ -36,72 +16,42 @@ let emptySERIAL = {
|
||||
}]
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up the map with its data sources and its different layers.
|
||||
*/
|
||||
map.on('load', function () {
|
||||
// save full coordinate list for later
|
||||
//var coordinates = data.features[0].geometry.coordinates;
|
||||
|
||||
map.addSource('routeTCP', { 'type': 'geojson', 'data': emptyTCP })
|
||||
map.addSource('routeSERIAL', { 'type': 'geojson', 'data': emptySERIAL })
|
||||
// start by showing just the first coordinate
|
||||
//data.features[0].geometry.coordinates = [coordinates[0]];
|
||||
|
||||
// add it to the map
|
||||
//map.addSource('trace', { type: 'geojson', data: data });
|
||||
|
||||
map.addSource('route', { 'type': 'geojson', 'data': empty })
|
||||
|
||||
map.addLayer({
|
||||
'id': 'routeTCP',
|
||||
'id': 'route',
|
||||
'type': 'line',
|
||||
'source': 'routeTCP',
|
||||
'layout': {
|
||||
'visibility': 'visible'
|
||||
},
|
||||
'source': 'route',
|
||||
'paint': {
|
||||
'line-color': 'rgba(30, 139, 195, 1)',
|
||||
'line-opacity': 1,
|
||||
'line-color': 'yellow',
|
||||
'line-opacity': 0.75,
|
||||
'line-width': 5
|
||||
}
|
||||
});
|
||||
|
||||
map.addLayer({
|
||||
'id': 'routeSERIAL',
|
||||
'type': 'line',
|
||||
'source': 'routeSERIAL',
|
||||
'layout': {
|
||||
'visibility': 'visible'
|
||||
},
|
||||
'paint': {
|
||||
'line-color': 'rgba(214, 69, 65, 1)',
|
||||
'line-opacity': 1,
|
||||
'line-width': 5
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
map.jumpTo({ 'center': [9.19640999, 49.12283027], 'zoom': 16 });
|
||||
// setup the viewport
|
||||
map.jumpTo({ 'center': [9.19640999, 49.12283027], 'zoom': 15 });
|
||||
map.setPitch(30);
|
||||
|
||||
let stateLegendEl = document.getElementById('state-legend');
|
||||
stateLegendEl.style.display = 'block';
|
||||
// on a regular basis, add more coordinates from the saved list and update the map
|
||||
//var i = 0;
|
||||
//var timer = window.setInterval(, 10);
|
||||
|
||||
|
||||
})
|
||||
|
||||
/**
|
||||
* Function to push coordinates data coming from a TCP connection
|
||||
* into the emptyTCP geoJSON object.
|
||||
* Called every time a message is received over TCP from the server.
|
||||
*
|
||||
* @param TCPlong longitude coming in from device connected over TCP port.
|
||||
* @param TCPlat latitude coming in from device connected over TCP port.
|
||||
*/
|
||||
function updateMapTCP (TCPlong, TCPlat) {
|
||||
emptyTCP.features[0].geometry.coordinates.push([TCPlong, TCPlat]);
|
||||
map.getSource('routeTCP').setData(emptyTCP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to push coordinates data coming from a serial connection
|
||||
* into the emptySERIAL geoJSON object.
|
||||
* Called every time a message is received over serial connection from the server.
|
||||
*
|
||||
* @param SERIALlong longitude coming in from device connected over serial port.
|
||||
* @param SERIALlat latitude coming in from device connected over serial port.
|
||||
*/
|
||||
function updateMapSERIAL (SERIALlong, SERIALlat) {
|
||||
emptySERIAL.features[0].geometry.coordinates.push([SERIALlong, SERIALlat]);
|
||||
map.getSource('routeSERIAL').setData(emptySERIAL);
|
||||
}
|
||||
function updateMap (coordinates) {
|
||||
empty.features[0].geometry.coordinates.push(coordinates);
|
||||
map.getSource('route').setData(empty);
|
||||
map.panTo(coordinates);
|
||||
}
|
||||
@ -1,116 +0,0 @@
|
||||
/**
|
||||
* This file defines the map in satellite style for the full replay page.
|
||||
*
|
||||
* @authors Timo Volkmann, Frank Herkommer.
|
||||
*/
|
||||
|
||||
mapboxgl.accessToken = 'pk.eyJ1IjoiZmhlcmtvbW0iLCJhIjoiY2tobm81bXppMGVuNzMyazY3eDU0M2dyaSJ9.qWJrwtv7KitW60pzs6h3Gg';
|
||||
let map = new mapboxgl.Map({
|
||||
container: 'map',
|
||||
style: 'mapbox://styles/mapbox/satellite-v9',
|
||||
zoom: 0
|
||||
});
|
||||
|
||||
/**
|
||||
* Set up the map with its data sources and its different layers.
|
||||
*/
|
||||
map.on('load', function () {
|
||||
|
||||
map.addSource('routeTCP', { 'type': 'geojson', 'data': null })
|
||||
map.addSource('routeSERIAL', { 'type': 'geojson', 'data': null })
|
||||
|
||||
map.addLayer({
|
||||
'id': 'routeTCP',
|
||||
'type': 'line',
|
||||
'source': 'routeTCP',
|
||||
'layout': {
|
||||
'visibility': 'visible'
|
||||
},
|
||||
'paint': {
|
||||
'line-color': 'rgba(30, 139, 195, 1)',
|
||||
'line-opacity': 1,
|
||||
'line-width': 5
|
||||
}
|
||||
});
|
||||
|
||||
map.addLayer({
|
||||
'id': 'routeSERIAL',
|
||||
'type': 'line',
|
||||
'source': 'routeSERIAL',
|
||||
'layout': {
|
||||
'visibility': 'visible'
|
||||
},
|
||||
'paint': {
|
||||
'line-color': 'rgba(214, 69, 65, 1)',
|
||||
'line-opacity': 1,
|
||||
'line-width': 5
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
map.jumpTo({ 'center': [9.19640999, 49.12283027], 'zoom': 16 });
|
||||
map.setPitch(30);
|
||||
|
||||
let stateLegendEl = document.getElementById('state-legend');
|
||||
stateLegendEl.style.display = 'block';
|
||||
})
|
||||
|
||||
/**
|
||||
* Function to add all collected coordinates sent in by the Smartphone to the map.
|
||||
* @param sensordataList List of all received messages of the tcp source and their sensor data
|
||||
*/
|
||||
function updateMapTCPbulk(sensordataList) {
|
||||
console.log("add TCP data to map")
|
||||
let geoJsonTCP = {
|
||||
type: "FeatureCollection",
|
||||
features: [
|
||||
{
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "LineString",
|
||||
coordinates: []
|
||||
}
|
||||
}]
|
||||
}
|
||||
sensordataList.forEach(sensordata => {
|
||||
if (sensordata.Position[0] === 0 && sensordata.Position[1] === 0 && sensordata.Position[2] === 0) {
|
||||
return;
|
||||
}
|
||||
let lat = sensordata.Position[0]
|
||||
let lon = sensordata.Position[1]
|
||||
geoJsonTCP.features[0].geometry.coordinates.push([lon, lat]);
|
||||
|
||||
})
|
||||
map.getSource('routeTCP').setData(geoJsonTCP);
|
||||
map.panTo(geoJsonTCP.features[0].geometry.coordinates[geoJsonTCP.features[0].geometry.coordinates.length-1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to add all collected coordinates sent in by the Ublox to the map.
|
||||
* @param sensordataList List of all received messages of the serial source and their sensor data
|
||||
*/
|
||||
function updateMapSERIALbulk(sensordataList) {
|
||||
console.log("add SERIAL data to map")
|
||||
let geoJsonSerial = {
|
||||
type: "FeatureCollection",
|
||||
features: [
|
||||
{
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "LineString",
|
||||
coordinates: []
|
||||
}
|
||||
}]
|
||||
}
|
||||
sensordataList.forEach(sensordata => {
|
||||
if (sensordata.Position[0] === 0 && sensordata.Position[1] === 0 && sensordata.Position[2] === 0) {
|
||||
return;
|
||||
}
|
||||
let lat = sensordata.Position[0]
|
||||
let lon = sensordata.Position[1]
|
||||
geoJsonSerial.features[0].geometry.coordinates.push([lon, lat]);
|
||||
|
||||
})
|
||||
map.getSource('routeSERIAL').setData(geoJsonSerial);
|
||||
map.panTo(geoJsonSerial.features[0].geometry.coordinates[geoJsonSerial.features[0].geometry.coordinates.length-1]);
|
||||
}
|
||||
@ -1,188 +0,0 @@
|
||||
/**
|
||||
* This file contains all the controls for the full replay page.
|
||||
*
|
||||
* @authors Timo Volkmann, Frank Herkommer.
|
||||
*/
|
||||
|
||||
// indexes of a list of all collected Serial data where Timestamps matched with the smallest time
|
||||
//difference so they can be fitted on a chart with a smaller amount of tcp data
|
||||
let indexes
|
||||
|
||||
/**
|
||||
* function to parse a timestamp to a number
|
||||
* @param time Timestamp
|
||||
* @returns composed a number
|
||||
*/
|
||||
function composeTimestamp(time){
|
||||
let composed;
|
||||
composed = time.slice(11,25).split(':').join("").split('.').join("");
|
||||
return composed;
|
||||
}
|
||||
|
||||
/**
|
||||
* function to compare a Timestamp from tcp to all timestamps from serial to find a best match.
|
||||
* @param num tcp timestamp
|
||||
* @param arr list of serial timestamps
|
||||
* @returns {(*|number)[]} array with the index of the closest Serial timestamp match
|
||||
*/
|
||||
function findBestTimeMatch(num, arr) {
|
||||
let mid;
|
||||
let lo = 0;
|
||||
let hi = arr.length - 1;
|
||||
while (hi - lo > 1) {
|
||||
mid = Math.floor ((lo + hi) / 2);
|
||||
if (arr[mid] < num) {
|
||||
lo = mid;
|
||||
} else {
|
||||
hi = mid;
|
||||
}
|
||||
}
|
||||
if (num - arr[lo] <= arr[hi] - num) {
|
||||
return [arr[lo], lo];
|
||||
}
|
||||
return [arr[hi], hi];
|
||||
}
|
||||
|
||||
/**
|
||||
* function that calls find best match function and saves the indexes from a match into a list.
|
||||
* @param tcpdataList
|
||||
* @param serialdataList
|
||||
*/
|
||||
function findSerialDataIndex(tcpdataList, serialdataList) {
|
||||
let allSerialTimes = []
|
||||
|
||||
serialdataList.forEach(sensordata => {
|
||||
if (sensordata.Speed !== 0 && sensordata.HAcc !== 0) {
|
||||
allSpeedsSerial.push(sensordata.Speed)
|
||||
allAccSerial.push(sensordata.HAcc)
|
||||
if(sensordata.Position[1] !== 0 && sensordata.Position[0] !== 0){
|
||||
allSerialCoords.push([sensordata.Position[1], sensordata.Position[0]])
|
||||
}
|
||||
let serialTimestamp = composeTimestamp(sensordata.Timestamp)
|
||||
allSerialTimes.push(serialTimestamp)
|
||||
}
|
||||
})
|
||||
|
||||
tcpdataList.forEach(sensordata => {
|
||||
if (sensordata.Speed !== 0 && sensordata.HAcc !== 0) {
|
||||
let tcpTimestamp = composeTimestamp(sensordata.Timestamp)
|
||||
let index = findBestTimeMatch(tcpTimestamp, allSerialTimes)[1]
|
||||
|
||||
indexes.push(index)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
window.addEventListener("load", function(evt) {
|
||||
|
||||
//------------------------Buttons------------------------------
|
||||
|
||||
let trackings = null;
|
||||
document.getElementById("messungladen").onclick = function(evt) {
|
||||
fetch('http://localhost:3011/trackings/', { method: 'GET'}).then(results => {
|
||||
return results.json()
|
||||
}).then(r => {
|
||||
console.log(r)
|
||||
if (!'data' in r) {
|
||||
return
|
||||
}
|
||||
trackings = r.data
|
||||
let sel = document.getElementById("meas")
|
||||
sel.innerHTML = ''
|
||||
r.data.sort((a,b) => new Date(b.TimeCreated).getTime() - new Date(a.TimeCreated).getTime());
|
||||
r.data.forEach(tracking => {
|
||||
console.log(tracking)
|
||||
let option = document.createElement("option");
|
||||
option.text = tracking.TimeCreated + " Size: " + tracking.Size
|
||||
sel.add(option)
|
||||
})
|
||||
sel.disabled = false
|
||||
document.getElementById("replaystarten").disabled = false
|
||||
|
||||
})
|
||||
};
|
||||
|
||||
document.getElementById("replaystarten").onclick = function(evt) {
|
||||
indexes = []
|
||||
allSpeedsSerial = []
|
||||
allAccSerial = []
|
||||
allSerialCoords = []
|
||||
|
||||
let sel = document.getElementById("meas")
|
||||
console.log(trackings[sel.selectedIndex].UUID)
|
||||
fetch(`http://localhost:3011/trackings/${trackings[sel.selectedIndex].UUID}`, { method: 'GET'}).then(results => {
|
||||
return results.json()
|
||||
}).then(r => {
|
||||
// console.log(r.data.Data)
|
||||
// console.log(r.data)
|
||||
if('SOURCE_SERIAL' in r.data.Data && r.data.Data.SOURCE_SERIAL.length > 0 && 'SOURCE_TCP' in r.data.Data && r.data.Data.SOURCE_TCP.length > 0) {
|
||||
findSerialDataIndex(r.data.Data.SOURCE_TCP, r.data.Data.SOURCE_SERIAL)
|
||||
}
|
||||
if ('SOURCE_TCP' in r.data.Data && r.data.Data.SOURCE_TCP.length > 0) {
|
||||
updateMapTCPbulk(r.data.Data.SOURCE_TCP)
|
||||
addTCPSpeedData(r.data.Data.SOURCE_TCP)
|
||||
}
|
||||
if ('SOURCE_SERIAL' in r.data.Data && r.data.Data.SOURCE_SERIAL.length > 0) {
|
||||
updateMapSERIALbulk(r.data.Data.SOURCE_SERIAL)
|
||||
addSerialSpeedData(r.data.Data.SOURCE_SERIAL)
|
||||
}
|
||||
addDistances(prepareForDistanceCalc(r.data.Data))
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
function prepareForDistanceCalc(data) {
|
||||
if('SOURCE_TCP' in data && data.SOURCE_TCP.length > 0 && 'SOURCE_SERIAL' in data && data.SOURCE_SERIAL.length > 0) {
|
||||
let sensorPoints = [];
|
||||
data.SOURCE_TCP.forEach(element => {
|
||||
if (element.Position[0] !== 0 && element.Position[1] !== 0) {
|
||||
sensorPoints.push({
|
||||
differenceMs: Number.MAX_VALUE,
|
||||
tcp: element,
|
||||
ser: null,
|
||||
})
|
||||
}
|
||||
})
|
||||
sensorPoints.forEach((el, index, arr) => {
|
||||
let tcpTS = Date.parse(el.tcp.Timestamp)
|
||||
data.SOURCE_SERIAL.forEach(serElement => {
|
||||
let serTS = Date.parse(serElement.Timestamp)
|
||||
if (Math.abs(tcpTS - serTS) < el.differenceMs && serElement.Position[0] !== 0 && serElement.Position[1] !== 0) {
|
||||
el.differenceMs = tcpTS - serTS
|
||||
arr[index].ser = serElement
|
||||
}
|
||||
})
|
||||
})
|
||||
// filter differences with more than 50 ms
|
||||
let newSensorPoints = sensorPoints.filter(el => {
|
||||
return Math.abs(el.differenceMs) < 50
|
||||
})
|
||||
console.log("SENSORPOINTs", newSensorPoints)
|
||||
return newSensorPoints
|
||||
} else if ('SOURCE_SERIAL' in data && data.SOURCE_SERIAL.length > 0) {
|
||||
let sensorPoints = [];
|
||||
data.SOURCE_SERIAL.forEach(element => {
|
||||
if (element.Position[0] !== 0 && element.Position[1] !== 0) {
|
||||
sensorPoints.push({
|
||||
differenceMs: Number.MAX_VALUE,
|
||||
tcp: null,
|
||||
ser: element,
|
||||
})
|
||||
}
|
||||
})
|
||||
return sensorPoints
|
||||
} else if ('SOURCE_TCP' in data && data.SOURCE_TCP.length > 0) {
|
||||
let sensorPoints = [];
|
||||
data.SOURCE_TCP.forEach(element => {
|
||||
if (element.Position[0] !== 0 && element.Position[1] !== 0) {
|
||||
sensorPoints.push({
|
||||
differenceMs: Number.MAX_VALUE,
|
||||
tcp: element,
|
||||
ser: null,
|
||||
})
|
||||
}
|
||||
})
|
||||
return sensorPoints
|
||||
}
|
||||
return null
|
||||
}
|
||||
@ -1,115 +0,0 @@
|
||||
/**
|
||||
* This file defines a line chart used in the full replay page, showing Ublox speeds and
|
||||
* smartphone speeds at a same moment in time in km/h, over time.
|
||||
*
|
||||
* @authors Timo Volkmann, Frank Herkommer.
|
||||
*/
|
||||
|
||||
//List of all speeds sent in by the Ublox
|
||||
let allSpeedsSerial = []
|
||||
|
||||
//Define the line chart and its properties
|
||||
let ctx = document.getElementById('speedChart').getContext('2d');
|
||||
let speedChart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: new Array(),
|
||||
datasets: [{
|
||||
label: 'Ublox speed',
|
||||
backgroundColor: 'rgba(214, 69, 65, 1)',
|
||||
borderColor: 'rgba(214, 69, 65, 1)',
|
||||
borderWidth: 1,
|
||||
fill: false,
|
||||
pointRadius: 0.5,
|
||||
lineTension: 0.5,
|
||||
data: []
|
||||
},
|
||||
{
|
||||
label: 'Smartphone speed',
|
||||
backgroundColor: 'rgba(30, 139, 195, 1)',
|
||||
borderColor: 'rgba(30, 139, 195, 1)',
|
||||
borderWidth: 1,
|
||||
fill: false,
|
||||
pointRadius: 0.5,
|
||||
lineTension: 0.5,
|
||||
data: []
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
min: 0,
|
||||
max: 250,
|
||||
stepSize: 25
|
||||
}
|
||||
}],
|
||||
xAxes: [{
|
||||
type: 'time',
|
||||
time: {
|
||||
unit: 'second'
|
||||
}
|
||||
}]
|
||||
},
|
||||
animation: {
|
||||
duration: 0
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Function filtering out speed data sent in by the Ublox using only the given indexes calculated in the refull.js file,
|
||||
* and adding the data to the chart.
|
||||
* As there is less smartphone data collected, we only want the Ublox speeds that come in at the moment with the
|
||||
* smallest time difference between the TCP message and the Serial message.
|
||||
*/
|
||||
function addSerialSpeedData(sensordataList) {
|
||||
let speedsSerial = []
|
||||
let times = []
|
||||
|
||||
if(indexes.length > 0){
|
||||
indexes.forEach(index => {
|
||||
speedsSerial.push((allSpeedsSerial[index] * 3.6).toFixed(2))
|
||||
})
|
||||
speedChart.data.datasets[0].data = speedsSerial;
|
||||
speedChart.update();
|
||||
} else {
|
||||
sensordataList.forEach(sensordata => {
|
||||
if (sensordata.Speed === 0) {
|
||||
return;
|
||||
}
|
||||
let speed = sensordata.Speed
|
||||
speedsSerial.push((speed * 3.6).toFixed(2));
|
||||
let time = sensordata.Timestamp
|
||||
times.push(time)
|
||||
|
||||
})
|
||||
speedChart.data.labels = times;
|
||||
speedChart.data.datasets[0].data = speedsSerial;
|
||||
speedChart.update();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to extract only the speeds and Timestamps out of the messages received from the smartphone
|
||||
* and add tem to the chart.
|
||||
* @param sensordataList List of all received messages of the tcp source and their sensor data.
|
||||
*/
|
||||
function addTCPSpeedData(sensordataList) {
|
||||
let speedsTCP = []
|
||||
let times = []
|
||||
|
||||
sensordataList.forEach(sensordata => {
|
||||
if (sensordata.Speed === 0) {
|
||||
return;
|
||||
}
|
||||
let speed = sensordata.Speed
|
||||
speedsTCP.push((speed * 3.6).toFixed(2));
|
||||
let time = sensordata.Timestamp
|
||||
times.push(time)
|
||||
|
||||
})
|
||||
speedChart.data.labels = times;
|
||||
speedChart.data.datasets[1].data = speedsTCP;
|
||||
speedChart.update();
|
||||
}
|
||||
@ -1,183 +0,0 @@
|
||||
/**
|
||||
* This file defines a doughnut chart used in the live tracking page, representing a speedometer showing
|
||||
* Ublox speeds and smartphone speeds in km/h.
|
||||
*
|
||||
* @authors Timo Volkmann, Frank Herkommer.
|
||||
*/
|
||||
|
||||
let options1 = {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
datasets: [
|
||||
{
|
||||
label: 'speedTCP',
|
||||
data: [0,100],
|
||||
backgroundColor: [
|
||||
'rgba(30, 139, 195, 1)',
|
||||
'rgba(191, 191, 191, 1)'
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(255, 255, 255 ,1)',
|
||||
'rgba(255, 255, 255 ,1)'
|
||||
],
|
||||
borderWidth: 0
|
||||
},
|
||||
{
|
||||
label: 'speedSERIAl',
|
||||
data: [0, 100],
|
||||
backgroundColor: [
|
||||
'rgba(214, 69, 65, 1)',
|
||||
'rgba(191, 191, 191, 1)'
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(255, 255, 255 ,1)',
|
||||
'rgba(255, 255, 255 ,1)'
|
||||
],
|
||||
borderWidth: 0
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
rotation: Math.PI,
|
||||
circumference: Math.PI,
|
||||
legend: {
|
||||
display: false,
|
||||
enabled: false
|
||||
},
|
||||
tooltips: {
|
||||
enabled: false,
|
||||
display: false
|
||||
},
|
||||
cutoutPercentage: 40
|
||||
}
|
||||
}
|
||||
let options2 = {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
datasets: [
|
||||
{
|
||||
label: 'speedMarks',
|
||||
data: [50,50,50,50],
|
||||
backgroundColor: [
|
||||
'rgba(30, 130, 76, 1)',
|
||||
'rgba(244, 208, 63, 1)',
|
||||
'rgba(235, 151, 78, 1)',
|
||||
'rgba(217, 30, 24, 1)'
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(30, 130, 76, 1)',
|
||||
'rgba(244, 208, 63, 1)',
|
||||
'rgba(235, 151, 78, 1)',
|
||||
'rgba(217, 30, 24, 1)'
|
||||
],
|
||||
borderWidth: 0
|
||||
},
|
||||
{
|
||||
label: 'transparent',
|
||||
data: [100],
|
||||
backgroundColor: [
|
||||
'rgba(0, 0, 0, 0)'
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(0, 0, 0, 0)'
|
||||
],
|
||||
borderWidth: 2
|
||||
},
|
||||
{
|
||||
label: 'transparent1',
|
||||
data: [100],
|
||||
backgroundColor: [
|
||||
'rgba(0, 0, 0, 0)'
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(0, 0, 0, 0)'
|
||||
],
|
||||
borderWidth: 2
|
||||
},
|
||||
{
|
||||
label: 'transparent2',
|
||||
data: [100],
|
||||
backgroundColor: [
|
||||
'rgba(0, 0, 0, 0)'
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(0, 0, 0, 0)'
|
||||
],
|
||||
borderWidth: 2
|
||||
},
|
||||
{
|
||||
label: 'transparent3',
|
||||
data: [100],
|
||||
backgroundColor: [
|
||||
'rgba(0, 0, 0, 0)'
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(0, 0, 0, 0)'
|
||||
],
|
||||
borderWidth: 2
|
||||
},
|
||||
{
|
||||
label: 'speedMarks1',
|
||||
data: [50,50,50,50],
|
||||
backgroundColor: [
|
||||
'rgba(30, 130, 76, 1)',
|
||||
'rgba(244, 208, 63, 1)',
|
||||
'rgba(235, 151, 78, 1)',
|
||||
'rgba(217, 30, 24, 1)'
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(30, 130, 76, 1)',
|
||||
'rgba(244, 208, 63, 1)',
|
||||
'rgba(235, 151, 78, 1)',
|
||||
'rgba(217, 30, 24, 1)'
|
||||
],
|
||||
borderWidth: 0
|
||||
},
|
||||
]
|
||||
},
|
||||
options: {
|
||||
rotation: Math.PI,
|
||||
circumference: Math.PI,
|
||||
legend: {
|
||||
display: false,
|
||||
enabled: false
|
||||
},
|
||||
tooltips: {
|
||||
enabled: false,
|
||||
display: false
|
||||
},
|
||||
cutoutPercentage: 65
|
||||
}
|
||||
}
|
||||
//chart showing the actual speed of the two devices.
|
||||
let ctx1 = document.getElementById('speedometer').getContext('2d');
|
||||
let mySpeedometer = new Chart(ctx1, options1);
|
||||
//chart adding the different speed areas colored from green to red.
|
||||
let ctx2 = document.getElementById('speedometerSpeeds').getContext('2d');
|
||||
let mySpeedometer2 = new Chart(ctx2, options2);
|
||||
|
||||
/**
|
||||
* Function that adds speed data sent by the Ublox, converted to km/h, to the speedometer.
|
||||
* Called every time a message is received over serial connection from the server.
|
||||
* @param speedSERIAL speed of the Ublox in m/s
|
||||
*/
|
||||
function addSpeedSerial(speedSERIAL){
|
||||
let speedSERIALkmh = (speedSERIAL * 3.6)
|
||||
let speedSERIALpercent = (speedSERIALkmh/250)*100
|
||||
mySpeedometer.data.datasets[1].data = [speedSERIALpercent, 100-speedSERIALpercent];
|
||||
document.getElementById("speedSERIAL").innerHTML = `Ublox: ${speedSERIALkmh.toFixed(1)} km/h`
|
||||
mySpeedometer.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that adds speed data sent by the Smartphone, converted to km/h, to the speedometer.
|
||||
* Called every time a message is received over tcp connection from the server.
|
||||
* @param speedTCP speed of the Smartphone in m/s
|
||||
*/
|
||||
function addSpeedTcp(speedTCP){
|
||||
let speedTCPkmh = (speedTCP * 3.6)
|
||||
let speedTCPpercent = (speedTCPkmh/250)*100;
|
||||
mySpeedometer.data.datasets[0].data = [speedTCPpercent, 100-speedTCPpercent];
|
||||
document.getElementById("speedTCP").innerHTML = `Phone: ${speedTCPkmh.toFixed(1)} km/h`
|
||||
mySpeedometer.update();
|
||||
}
|
||||
@ -1,175 +1,75 @@
|
||||
// Temporary TCP and Serial data used to calculate vincenty distance between two coordinates in realtime.
|
||||
let tempTCPCoords = null;
|
||||
let tempSERIALCoords = null;
|
||||
|
||||
const GRAPH_RES = 100;
|
||||
var dataSmartphone = [];
|
||||
window.addEventListener("load", function(evt) {
|
||||
let output = document.getElementById("output");
|
||||
let checkBoxSmartphone = document.getElementById("checkbox1");
|
||||
let checkBoxUblox = document.getElementById("checkbox2");
|
||||
let ws;
|
||||
|
||||
const wsOnCloseF = function (evt) {
|
||||
ws = null;
|
||||
print2("CLOSED");
|
||||
let intervalId;
|
||||
intervalId = setInterval(() => {
|
||||
console.log("reconnect websocket...")
|
||||
if (ws !== null && ws.CONNECTING) {
|
||||
return
|
||||
}
|
||||
if (ws !== null && ws.OPEN) {
|
||||
clearInterval(intervalId)
|
||||
return
|
||||
}
|
||||
ws = new WebSocket("ws://localhost:3011/ws");
|
||||
ws.onopen = wsOnOpenF
|
||||
ws.onclose = wsOnCloseF
|
||||
ws.onmessage = wsOnMessageF
|
||||
ws.onerror = wsOnErrorF
|
||||
}, 1000)
|
||||
}
|
||||
// function called every time a message is received by the server.
|
||||
const wsOnMessageF = function (evt) {
|
||||
let dat = JSON.parse(evt.data)
|
||||
// If message comes from TCP source call functions to add TCP data != 0 to the charts
|
||||
if ('SOURCE_TCP' in dat) {
|
||||
setIndicatorsTcp(dat.SOURCE_TCP)
|
||||
if(dat.SOURCE_TCP.Orientation[0] !== 0 && dat.SOURCE_TCP.Orientation[1] !== 0 && dat.SOURCE_TCP.Orientation[2] !== 0){
|
||||
let heading = (dat.SOURCE_TCP.Orientation[2]+90)%360
|
||||
renderTCP((dat.SOURCE_TCP.Orientation[0]*Math.PI/180),heading*Math.PI/180,-(dat.SOURCE_TCP.Orientation[1]*Math.PI/180))
|
||||
}
|
||||
if(dat.SOURCE_TCP.Position[1] !== 0 && dat.SOURCE_TCP.Position[0] !== 0){
|
||||
document.getElementById("TCPlong").innerHTML = "Smartphone long: " + dat.SOURCE_TCP.Position[1]
|
||||
document.getElementById("TCPlat").innerHTML = "Smartphone lat: " + dat.SOURCE_TCP.Position[0]
|
||||
updateMapTCP(dat.SOURCE_TCP.Position[1], dat.SOURCE_TCP.Position[0])
|
||||
map.panTo([dat.SOURCE_TCP.Position[1], dat.SOURCE_TCP.Position[0]])
|
||||
tempTCPCoords = dat.SOURCE_TCP
|
||||
}
|
||||
if(dat.SOURCE_TCP.Speed !== 0){
|
||||
addSpeedTcp(dat.SOURCE_TCP.Speed);
|
||||
}
|
||||
if(dat.SOURCE_TCP.HeadDevice !== 0){
|
||||
document.getElementById("compassTCP").innerHTML = " Heading Device: " + dat.SOURCE_TCP.HeadDevice.toFixed(2) + "°"
|
||||
}
|
||||
if(dat.SOURCE_TCP.HeadMotion !== 0) {
|
||||
document.getElementById("compassTCPMot").innerHTML = "Heading Motion: " + dat.SOURCE_TCP.HeadMotion.toFixed(2) + "°"
|
||||
}
|
||||
if(dat.SOURCE_TCP.HAcc !== 0 && dat.SOURCE_TCP.VAcc !== 0){
|
||||
addTCPAccuracy(dat.SOURCE_TCP.HAcc, dat.SOURCE_TCP.VAcc)
|
||||
document.getElementById("tcpHAcc").innerHTML = "Phone HAcc: " + dat.SOURCE_TCP.HAcc.toFixed(2) + " m"
|
||||
document.getElementById("tcpVAcc").innerHTML = "Phone VAcc: " + dat.SOURCE_TCP.VAcc.toFixed(2) + " m"
|
||||
}
|
||||
}
|
||||
|
||||
// If message comes from Serial source call functions to add serial data != 0 to the charts
|
||||
if ('SOURCE_SERIAL' in dat) {
|
||||
setIndicatorsSer(dat.SOURCE_SERIAL)
|
||||
if(dat.SOURCE_SERIAL.Orientation[0] !== 0 && dat.SOURCE_SERIAL.Orientation[2] !== 0){
|
||||
renderSerial(dat.SOURCE_SERIAL.Orientation[0]*Math.PI/180,-dat.SOURCE_SERIAL.Orientation[2]*Math.PI/180,dat.SOURCE_SERIAL.Orientation[1]*Math.PI/180)
|
||||
}
|
||||
if(dat.SOURCE_SERIAL.Position[1] !== 0 && dat.SOURCE_SERIAL.Position[0] !== 0){
|
||||
document.getElementById("SERIALlong").innerHTML = "Ublox long: " + dat.SOURCE_SERIAL.Position[1]
|
||||
document.getElementById("SERIALlat").innerHTML = "Ublox lat: " + dat.SOURCE_SERIAL.Position[0]
|
||||
updateMapSERIAL(dat.SOURCE_SERIAL.Position[1], dat.SOURCE_SERIAL.Position[0])
|
||||
map.panTo([dat.SOURCE_SERIAL.Position[1], dat.SOURCE_SERIAL.Position[0]])
|
||||
tempSERIALCoords = dat.SOURCE_SERIAL
|
||||
if (tempTCPCoords !== null) {
|
||||
|
||||
// calculate distance between coordinates from phone and m8u
|
||||
let tempDist = distVincenty(tempTCPCoords.Position, tempSERIALCoords.Position)
|
||||
// calculate time difference between currently cached measurements from phone and m8u
|
||||
let timeDiff = Date.parse(tempTCPCoords.Timestamp) - Date.parse(tempSERIALCoords.Timestamp)
|
||||
// calculate error estimation: traveled distance in time difference
|
||||
let distError = Math.abs(dat.SOURCE_SERIAL.Speed / 1000 * timeDiff)
|
||||
// remove invalid negative values
|
||||
let distClean = Math.max(tempDist - distError, 0) // set to zero if error greater than diff as this is only an estimation
|
||||
|
||||
addDistanceToBarChart(distClean)
|
||||
document.getElementById("distance").innerHTML = "Distance 2D: " + distClean.toFixed(3) + " m"
|
||||
|
||||
if(distClean <= dat.SOURCE_SERIAL.HAcc){
|
||||
document.getElementById("greenlamp").style.backgroundColor = 'rgba(0, 230, 64, 1)'
|
||||
document.getElementById("yellow").style.backgroundColor = 'rgb(157,117,25)'
|
||||
document.getElementById("redlamp").style.backgroundColor = 'rgba(139, 0, 0, 1)'
|
||||
}
|
||||
else if(distClean <= tempTCPCoords.HAcc){
|
||||
document.getElementById("greenlamp").style.backgroundColor = 'rgba(0, 100, 0, 1)'
|
||||
document.getElementById("yellow").style.backgroundColor = 'rgb(255,199,66)'
|
||||
document.getElementById("redlamp").style.backgroundColor = 'rgba(139, 0, 0, 1)'
|
||||
}
|
||||
else{
|
||||
document.getElementById("greenlamp").style.backgroundColor = 'rgba(0, 100, 0, 1)'
|
||||
document.getElementById("yellow").style.backgroundColor = 'rgb(157,117,25)'
|
||||
document.getElementById("redlamp").style.backgroundColor = 'rgb(255,14,14)'
|
||||
}
|
||||
}
|
||||
tempTCPCoords = null
|
||||
}
|
||||
if(dat.SOURCE_SERIAL.Speed !== 0){
|
||||
addSpeedSerial(dat.SOURCE_SERIAL.Speed);
|
||||
}
|
||||
if(dat.SOURCE_SERIAL.HeadDevice !== 0){
|
||||
document.getElementById("compassSERIAL").innerHTML = "Heading Device: " + dat.SOURCE_SERIAL.HeadDevice.toFixed(2) + "°"
|
||||
}
|
||||
if(dat.SOURCE_SERIAL.HeadMotion !== 0) {
|
||||
document.getElementById("compassSERIALMot").innerHTML = "Heading Motion: " + dat.SOURCE_SERIAL.HeadMotion.toFixed(2) + "°"
|
||||
}
|
||||
if(dat.SOURCE_SERIAL.HAcc !== 0 && dat.SOURCE_SERIAL.VAcc !== 0){
|
||||
addSerialAccuracy(dat.SOURCE_SERIAL.HAcc, dat.SOURCE_SERIAL.VAcc)
|
||||
document.getElementById("serialHAcc").innerHTML = "Ublox HAcc: " + dat.SOURCE_SERIAL.HAcc.toFixed(3) + " m"
|
||||
document.getElementById("serialVAcc").innerHTML = "Ublox VAcc: " + dat.SOURCE_SERIAL.VAcc.toFixed(2) + " m"
|
||||
}
|
||||
}
|
||||
}
|
||||
const wsOnOpenF = function (evt) {
|
||||
print2("OPEN");
|
||||
}
|
||||
const wsOnErrorF = function(evt) {
|
||||
console.log(evt)
|
||||
print2("ERROR: " + evt);
|
||||
}
|
||||
|
||||
ws = new WebSocket("ws://localhost:3011/ws");
|
||||
ws.onopen = wsOnOpenF
|
||||
ws.onclose = wsOnCloseF
|
||||
ws.onmessage = wsOnMessageF
|
||||
ws.onerror = wsOnErrorF
|
||||
|
||||
const print2 = function(message) {
|
||||
let d = document.createElement("p");
|
||||
var orientation = [0,0,0];
|
||||
var multiplier = 180/Math.PI/15
|
||||
var output = document.getElementById("output");
|
||||
var input = document.getElementById("input");
|
||||
var ws;
|
||||
var print = function(message) {
|
||||
var d = document.createElement("div");
|
||||
d.textContent = message;
|
||||
output.appendChild(d);
|
||||
};
|
||||
var print2 = function(message) {
|
||||
var d = document.createElement("p");
|
||||
d.innerText = message;
|
||||
oldNode = output.firstChild
|
||||
output.replaceChild(d, oldNode)
|
||||
};
|
||||
|
||||
// On open send HTTP request corresponding to the chosen Source/s
|
||||
document.getElementById("open").onclick = function(evt) {
|
||||
if(checkBoxSmartphone.checked && checkBoxUblox.checked){
|
||||
fetch('http://localhost:3011/trackings?serial=true&tcp=true', { method: 'POST', body: 'some test data'})
|
||||
.then(results => results.json())
|
||||
.then(console.log);
|
||||
if (ws && ws.OPEN) {
|
||||
print("Websocket already open")
|
||||
return false;
|
||||
}
|
||||
else if(!checkBoxSmartphone.checked && checkBoxUblox.checked){
|
||||
fetch('http://localhost:3011/trackings?serial=true&tcp=false', { method: 'POST', body: 'some test data'})
|
||||
.then(results => results.json())
|
||||
.then(console.log);
|
||||
ws = new WebSocket("ws://localhost:3011/echo");
|
||||
ws.onopen = function(evt) {
|
||||
print("OPEN");
|
||||
}
|
||||
else if(checkBoxSmartphone.checked && !checkBoxUblox.checked){
|
||||
fetch('http://localhost:3011/trackings?serial=false&tcp=true', { method: 'POST', body: 'some test data'})
|
||||
.then(results => results.json())
|
||||
.then(console.log);
|
||||
}
|
||||
else if(!checkBoxSmartphone.checked && !checkBoxUblox.checked){
|
||||
fetch('http://localhost:3011/trackings?serial=false&tcp=false', { method: 'POST', body: 'some test data'})
|
||||
.then(results => results.json())
|
||||
.then(console.log);
|
||||
ws.onclose = function(evt) {
|
||||
ws = null;
|
||||
print2("CLOSE");
|
||||
}
|
||||
ws.onmessage = function(evt) {
|
||||
//print2("RESPONSE: " + evt.data);
|
||||
dataSmartphone.push(evt.data)
|
||||
// let dat = JSON.parse(evt.data)["bmi26x gyroscope"]
|
||||
// let dat = JSON.parse(evt.data)["lsm6dsm gyroscope"]
|
||||
//let dat = JSON.parse(evt.data)["lsm6ds3c gyroscope"]
|
||||
let dat = JSON.parse(evt.data)
|
||||
console.log(evt.data)
|
||||
console.log("JSON geparsed onmessage", dat)
|
||||
//console.log(dat.orientation)
|
||||
document.getElementById("gyroscope").style.transform = `rotateX(${-((dat.orientation[1]+90)%360)}deg) rotateY(${dat.orientation[0]}deg) rotateZ(${-dat.orientation[2]}deg)`
|
||||
|
||||
document.getElementById("tracking state").innerHTML = "Tracking state: LIVE"
|
||||
|
||||
checkBoxSmartphone.disabled = true;
|
||||
checkBoxUblox.disabled = true;
|
||||
|
||||
/*
|
||||
console.log(dat)
|
||||
orientation[0] += dat[0] * multiplier
|
||||
orientation[1] += dat[1] * multiplier
|
||||
orientation[2] += dat[2] * multiplier
|
||||
// dataset.push(orientation[0])
|
||||
// while (dataset.length >= 50) {
|
||||
// dataset.shift();
|
||||
// }
|
||||
// addData(orientation[0] / multiplier)
|
||||
*/
|
||||
addData(dat.orientation[0])
|
||||
setData(dat.GPS[0], dat.GPS[1])
|
||||
// addData(dat[0])
|
||||
//document.getElementById("gyroscope").style.transform = `rotateX(${-orientation[0]}deg) rotateY(${orientation[1]}deg) rotateZ(${-orientation[2]}deg) translateZ(50px)`
|
||||
}
|
||||
ws.onerror = function(evt) {
|
||||
print("ERROR: " + evt.data);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
document.getElementById("send").onclick = function(evt) {
|
||||
if (!ws) {
|
||||
return false;
|
||||
}
|
||||
print("SEND: " + input.value);
|
||||
ws.send(input.value);
|
||||
return false;
|
||||
};
|
||||
document.getElementById("close").onclick = function(evt) {
|
||||
@ -179,85 +79,4 @@ window.addEventListener("load", function(evt) {
|
||||
ws.close();
|
||||
return false;
|
||||
};
|
||||
|
||||
//------------------------Buttons------------------------------
|
||||
|
||||
/*
|
||||
Provides every Button with the corresponding HTTP request if the websocket is open.
|
||||
*/
|
||||
|
||||
document.getElementById("messungstarten").onclick = function(evt) {
|
||||
if (ws) {
|
||||
fetch('http://localhost:3011/trackings/', { method: 'PATCH', body: 'some data'})
|
||||
.then(results => results.json())
|
||||
.then(console.log);
|
||||
document.getElementById("tracking state").innerHTML = "Tracking state: RECORD"
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
document.getElementById("messungbeenden").onclick = function(evt) {
|
||||
if (ws) {
|
||||
fetch('http://localhost:3011/trackings/', { method: 'PUT', body: 'some data'})
|
||||
.then(results => results.json())
|
||||
.then(console.log);
|
||||
document.getElementById("tracking state").innerHTML = "Tracking state: LIVE"
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
document.getElementById("allesbeenden").onclick = function(evt) {
|
||||
if (ws) {
|
||||
fetch('http://localhost:3011/trackings/', { method: 'DELETE', body: 'some data'})
|
||||
.then(results => results.json())
|
||||
.then(console.log);
|
||||
checkBoxSmartphone.disabled = false;
|
||||
checkBoxUblox.disabled = false;
|
||||
document.getElementById("tracking state").innerHTML = "Tracking state: CLOSED"
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var trackings = null;
|
||||
document.getElementById("messungladen").onclick = function(evt) {
|
||||
fetch('http://localhost:3011/trackings/', { method: 'GET'}).then(results => {
|
||||
return results.json()
|
||||
}).then(r => {
|
||||
console.log(r)
|
||||
if (!'data' in r) {
|
||||
return
|
||||
}
|
||||
trackings = r.data
|
||||
let sel = document.getElementById("meas")
|
||||
r.data.sort((a,b) => new Date(b.TimeCreated).getTime() - new Date(a.TimeCreated).getTime());
|
||||
r.data.forEach(tracking => {
|
||||
console.log(tracking)
|
||||
let option = document.createElement("option");
|
||||
option.text = tracking.TimeCreated + " Size: " + tracking.Size
|
||||
sel.add(option)
|
||||
})
|
||||
sel.disabled = false
|
||||
document.getElementById("replaystarten").disabled = false
|
||||
|
||||
})
|
||||
};
|
||||
|
||||
document.getElementById("replaystarten").onclick = function(evt) {
|
||||
emptyTCP.features[0].geometry.coordinates = []
|
||||
emptySERIAL.features[0].geometry.coordinates = []
|
||||
|
||||
let sel = document.getElementById("meas")
|
||||
console.log(trackings[sel.selectedIndex].UUID)
|
||||
fetch(`http://localhost:3011/trackings/${trackings[sel.selectedIndex].UUID}?replay=true`, { method: 'GET'}).then(results => {
|
||||
return results.json()
|
||||
}).then(r => {
|
||||
console.log(r.data.Data)
|
||||
})
|
||||
document.getElementById("tracking state").innerHTML = "Tracking state: REPLAY"
|
||||
}
|
||||
|
||||
document.getElementById("fullReplay").onclick = function(evt) {
|
||||
window.open('http://localhost:3011/tracking')
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
476
static/style.css
476
static/style.css
@ -1,476 +0,0 @@
|
||||
body { margin: 0; padding: 0; }
|
||||
#map { position: absolute; top: 0; bottom: 0; width: 100%; }
|
||||
|
||||
.legend {
|
||||
background-color: #fff;
|
||||
border-radius: 3px;
|
||||
bottom: 30px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
||||
font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
|
||||
padding: 10px;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.legend h4 {
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
.legend div span {
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
height: 10px;
|
||||
margin-right: 5px;
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
body{margin:0; padding:0; font-size:13px; font-family:Georgia, "Times New Roman", Times, serif; color:#919191; background-color:#232323;}
|
||||
|
||||
.float-child {
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.sceneMap {
|
||||
width: 200px;
|
||||
height: 50vh;
|
||||
border: 0px solid #CCC;
|
||||
/*margin: 20px;*/
|
||||
perspective: 400px;
|
||||
}
|
||||
|
||||
|
||||
.sceneMap, #map {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.right-col {
|
||||
display: flex;
|
||||
flex-flow: wrap;
|
||||
width: 34%;
|
||||
max-width: 460px;
|
||||
}
|
||||
.left-col {
|
||||
display: flex;
|
||||
flex-flow: wrap;
|
||||
width: calc(66% - 20px);
|
||||
padding-right: 20px;
|
||||
|
||||
}
|
||||
|
||||
.compass-container {
|
||||
display: flex;
|
||||
flex-flow: wrap;
|
||||
}
|
||||
|
||||
.outer {
|
||||
position: relative;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
margin: 20px;
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
canvas {
|
||||
position: absolute;
|
||||
}
|
||||
.speedMin {
|
||||
position: absolute;
|
||||
left: 0%;
|
||||
transform: translate(-50%, 0);
|
||||
font-size: 30px;
|
||||
bottom: 0;
|
||||
margin-bottom: -50px;
|
||||
}
|
||||
.speed14 {
|
||||
position: absolute;
|
||||
left: 8%;
|
||||
transform: translate(-50%, 0);
|
||||
font-size: 20px;
|
||||
bottom: 0;
|
||||
margin-bottom: 90px;
|
||||
}
|
||||
.speedMed {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
font-size: 20px;
|
||||
bottom: 0;
|
||||
margin-bottom: 140px;
|
||||
}
|
||||
.speed34 {
|
||||
position: absolute;
|
||||
left: 92%;
|
||||
transform: translate(-50%, 0);
|
||||
font-size: 20px;
|
||||
bottom: 0;
|
||||
margin-bottom: 90px;
|
||||
}
|
||||
.speedMax {
|
||||
position: absolute;
|
||||
Left: 100%;
|
||||
transform: translate(-50%, 0);
|
||||
font-size: 30px;
|
||||
bottom: 0;
|
||||
margin-bottom: -50px;
|
||||
}
|
||||
|
||||
#compass {
|
||||
position: relative;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
/*margin: 20px;*/
|
||||
}
|
||||
#compass1 {
|
||||
position: relative;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
/*margin: 20px;*/
|
||||
}
|
||||
|
||||
.accuracy-container {
|
||||
display: flex;
|
||||
flex-flow: wrap;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.accuracy-values {
|
||||
margin: 28px 20px 0 20px;
|
||||
}
|
||||
|
||||
.led-container {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
#bezel {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-radius: 50%;
|
||||
}
|
||||
#bezelTCP {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
#axis {
|
||||
position: absolute;
|
||||
left: 88px;
|
||||
top: 88px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: #ffff;
|
||||
border: 6px solid #666;
|
||||
border-radius: 50%;
|
||||
}
|
||||
#axisTCP {
|
||||
position: absolute;
|
||||
left: 88px;
|
||||
top: 88px;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: #ffff;
|
||||
border: 6px solid #666;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
#needle {
|
||||
position: absolute;
|
||||
left: 96px;
|
||||
width: 4px;
|
||||
height: 160px;
|
||||
top: 16px;
|
||||
}
|
||||
#needleTCP {
|
||||
position: absolute;
|
||||
left: 96px;
|
||||
width: 4px;
|
||||
height: 160px;
|
||||
top: 16px;
|
||||
}
|
||||
|
||||
#needle:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -1px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 4px solid transparent;
|
||||
border-bottom: 80px solid #FF3600;
|
||||
}
|
||||
|
||||
#needle:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 80px;
|
||||
left: -1px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 4px solid transparent;
|
||||
border-top: 80px solid #666;
|
||||
}
|
||||
#needleTCP:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -1px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 4px solid transparent;
|
||||
border-bottom: 80px solid #FF3600;
|
||||
}
|
||||
|
||||
#needleTCP:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 80px;
|
||||
left: -1px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: 4px solid transparent;
|
||||
border-top: 80px solid #666;
|
||||
}
|
||||
|
||||
#N {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 88px;
|
||||
color: #FF3600;
|
||||
}
|
||||
|
||||
#E {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 80px;
|
||||
}
|
||||
|
||||
#S {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
left: 88px;
|
||||
}
|
||||
|
||||
#W {
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
top: 80px;
|
||||
}
|
||||
#NTCP {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 88px;
|
||||
color: #FF3600;
|
||||
}
|
||||
|
||||
#ETCP {
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 80px;
|
||||
}
|
||||
|
||||
#STCP {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
left: 88px;
|
||||
}
|
||||
|
||||
#WTCP {
|
||||
position: absolute;
|
||||
left: 5px;
|
||||
top: 80px;
|
||||
}
|
||||
|
||||
.dir {
|
||||
font-family: arial, sans-serif;
|
||||
color: #999;
|
||||
font-size: 20px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.quad {
|
||||
display: block;
|
||||
width: 2px;
|
||||
background: #ddd;
|
||||
height: 130px;
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
left: 98px;
|
||||
}
|
||||
|
||||
#NWSE {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
#NESW {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
#WE {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
#NWSETCP {
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
#NESWTCP {
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
#WETCP {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
|
||||
@-webkit-keyframes spin {
|
||||
100% {
|
||||
-webkit-transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.scene {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border: 0px solid #CCC;
|
||||
margin: 70px;
|
||||
perspective: 400px;
|
||||
}
|
||||
|
||||
.lamp {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
background-color: gray;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.lamps {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
}
|
||||
|
||||
.lampinner{
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
position: relative;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.cube {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
position: relative;
|
||||
transform-style: preserve-3d;
|
||||
/*transform: translateZ(-100px);*/
|
||||
transition: transform 25ms;
|
||||
}
|
||||
|
||||
.cube.show-front { transform:translateZ(-100px) rotateY( 0deg); }
|
||||
.cube.show-right { transform:translateZ(-100px) rotateY( -90deg); }
|
||||
.cube.show-back { transform:translateZ(-100px) rotateY(-180deg); }
|
||||
.cube.show-left { transform:translateZ(-100px) rotateY( 90deg); }
|
||||
.cube.show-top { transform:translateZ(-100px) rotateX( -90deg); }
|
||||
.cube.show-bottom { transform:translateZ(-100px) rotateX( 90deg); }
|
||||
|
||||
.cube__face {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border: 1px solid white;
|
||||
line-height: 200px;
|
||||
font-size: 40px;
|
||||
/*font-weight: bold;*/
|
||||
color: white;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cube__face--front { background: hsla( 0, 100%, 50%, 0.7); }
|
||||
.cube__face--right { background: hsla( 60, 100%, 50%, 0.7); }
|
||||
.cube__face--back { background: hsla(120, 100%, 50%, 0.7); }
|
||||
.cube__face--left { background: hsla(180, 100%, 50%, 0.7); }
|
||||
.cube__face--top { background: hsla(240, 100%, 50%, 0.7); }
|
||||
.cube__face--bottom { background: hsla(300, 100%, 50%, 0.7); }
|
||||
|
||||
.cube__face--front { transform: rotateY( 0deg) translateZ(100px) translateY(50px); height: 100px; line-height: 100px; }
|
||||
.cube__face--right { transform: rotateY( 90deg) translateZ(100px) translateY(50px); height: 100px; line-height: 100px; }
|
||||
.cube__face--back { transform: rotateY(180deg) translateZ(100px) translateY(50px); height: 100px; line-height: 100px; }
|
||||
.cube__face--left { transform: rotateY(-90deg) translateZ(100px) translateY(50px); height: 100px; line-height: 100px; }
|
||||
.cube__face--top { transform: rotateX( 90deg) translateZ(50px); }
|
||||
.cube__face--bottom { transform: rotateX(-90deg) translateZ(50px); }
|
||||
|
||||
label { margin-right: 10px; }
|
||||
|
||||
.slidecontainer {
|
||||
width: 100%;
|
||||
overflow: visible;
|
||||
padding: 10px 0px;
|
||||
}
|
||||
|
||||
#manCalContainer {
|
||||
display: none;
|
||||
}
|
||||
/*.slider {*/
|
||||
/* -webkit-appearance: none;*/
|
||||
/* width: 100%;*/
|
||||
/* height: 25px;*/
|
||||
/* background: #d3d3d3;*/
|
||||
/* outline: none;*/
|
||||
/* opacity: 0.7;*/
|
||||
/* -webkit-transition: .2s;*/
|
||||
/* transition: opacity .2s;*/
|
||||
/*}*/
|
||||
|
||||
.slider:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.slider::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: #4CAF50;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.slider::-moz-range-thumb {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: #4CAF50;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.slider {
|
||||
-webkit-appearance: none;
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
border-radius: 5px;
|
||||
background: #d3d3d3;
|
||||
outline: none;
|
||||
opacity: 0.7;
|
||||
-webkit-transition: opacity .15s ease-in-out;
|
||||
transition: opacity .15s ease-in-out;
|
||||
}
|
||||
|
||||
#viewport {
|
||||
width: 100%;
|
||||
height: 360px;
|
||||
}
|
||||
|
||||
.compass-digital {
|
||||
width: 400px;
|
||||
}
|
||||
@ -1,244 +0,0 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"git.timovolkmann.de/gyrogpsc/core"
|
||||
"github.com/dgraph-io/badger/v2"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sirupsen/logrus"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Must implement Storer
|
||||
type badgerStore struct {
|
||||
trackingsDb *badger.DB
|
||||
sensordatDb *badger.DB
|
||||
}
|
||||
|
||||
// Returns a badgerDB K/V Store instance. Opens database if exist or creates a new one in working directory
|
||||
func NewRepository(c *core.Configuration) *badgerStore {
|
||||
dir, _ := os.Getwd()
|
||||
logrus.Debug(dir)
|
||||
if _, err := os.Stat(filepath.Join(dir, "_db")); os.IsNotExist(err) {
|
||||
os.Mkdir(filepath.Join(dir, "_db"), os.ModePerm)
|
||||
}
|
||||
|
||||
bs := &badgerStore{}
|
||||
err := bs.openDBs()
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
return bs
|
||||
}
|
||||
|
||||
func (r *badgerStore) openDBs() error {
|
||||
var err error
|
||||
r.trackingsDb, err = badger.Open(badger.DefaultOptions("_db/trackings"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.sensordatDb, err = badger.Open(badger.DefaultOptions("_db/sensor"))
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *badgerStore) isDbClosed() bool {
|
||||
return r.trackingsDb.IsClosed() || r.sensordatDb.IsClosed()
|
||||
}
|
||||
|
||||
func (r *badgerStore) Save(tr core.Tracking) error {
|
||||
if ok := r.isDbClosed(); ok {
|
||||
logrus.Error("unable to write to database. database closed!")
|
||||
err := r.openDBs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//return badger.ErrDBClosed
|
||||
}
|
||||
uid, err := tr.UUID.MarshalText()
|
||||
if err != nil {
|
||||
logrus.Error(err, tr)
|
||||
}
|
||||
logrus.Infoln("save tracking:", tr.TimeCreated.Format(time.RFC3339Nano))
|
||||
meta, err := json.Marshal(tr.TrackingMetadata)
|
||||
if err != nil {
|
||||
logrus.Error(err, tr)
|
||||
return err
|
||||
}
|
||||
err = r.sensordatDb.Update(func(txn *badger.Txn) error {
|
||||
for _, v := range tr.Data {
|
||||
k := createRecordKey(tr.UUID, v.Source(), v.Timestamp)
|
||||
//logrus.Trace(v, " len key ->", len(k))
|
||||
j, err2 := json.Marshal(v)
|
||||
logrus.Traceln("save record k/v:\n", tr.UUID.String(), v.Timestamp.Format(time.RFC3339Nano))
|
||||
//logrus.Traceln(string(pretty.Pretty(j)))
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
err2 = txn.Set(k, j)
|
||||
|
||||
if err2 != nil {
|
||||
logrus.Warn(err2)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
logrus.Error(err, tr)
|
||||
}
|
||||
err = r.trackingsDb.Update(func(txn *badger.Txn) error {
|
||||
logrus.Debugln("save tracking metadata k/v:\n", string(uid), string(meta))
|
||||
err := txn.Set(uid, meta)
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
logrus.Error(err, tr)
|
||||
return err
|
||||
}
|
||||
|
||||
dr := 0.5
|
||||
_ = r.trackingsDb.RunValueLogGC(dr)
|
||||
_ = r.sensordatDb.RunValueLogGC(dr)
|
||||
logrus.Info("sucessfully saved tracking")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Retrieves all existing Trackings. Only Metadata. If you want actual data of tracking, load a specific one with Load(uuid)
|
||||
func (r *badgerStore) LoadAll() ([]core.TrackingMetadata, error) {
|
||||
var result []core.TrackingMetadata
|
||||
err := r.trackingsDb.View(func(txn *badger.Txn) error {
|
||||
opts := badger.DefaultIteratorOptions
|
||||
it := txn.NewIterator(opts)
|
||||
defer it.Close()
|
||||
for it.Rewind(); it.Valid(); it.Next() {
|
||||
item := it.Item()
|
||||
el := core.TrackingMetadata{}
|
||||
err2 := item.Value(func(val []byte) error {
|
||||
logrus.Debugln(string(val))
|
||||
err3 := json.Unmarshal(val, &el)
|
||||
return err3
|
||||
})
|
||||
if err2 != nil {
|
||||
logrus.Warn(err2)
|
||||
}
|
||||
|
||||
result = append(result, el)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Retrieves all data of a tracking from disk
|
||||
func (r *badgerStore) Load(id uuid.UUID) (*core.Tracking, error) {
|
||||
logrus.Debugln("try to load from db...", id)
|
||||
if ok := r.isDbClosed(); ok {
|
||||
logrus.Error("unable to read from database. database closed!")
|
||||
err := r.openDBs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
t := &core.Tracking{
|
||||
TrackingMetadata: core.TrackingMetadata{},
|
||||
//Records: []core.recordPair{},
|
||||
//Data: nil,
|
||||
}
|
||||
err := r.trackingsDb.View(func(txn *badger.Txn) error {
|
||||
item, err2 := txn.Get([]byte(id.String()))
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
err2 = item.Value(func(val []byte) error {
|
||||
err3 := json.Unmarshal(val, &t.TrackingMetadata)
|
||||
return err3
|
||||
})
|
||||
return err2
|
||||
})
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
err = r.sensordatDb.View(func(txn *badger.Txn) error {
|
||||
opts := badger.DefaultIteratorOptions
|
||||
opts.Prefix = []byte(id.String())
|
||||
it := txn.NewIterator(opts)
|
||||
defer it.Close()
|
||||
|
||||
for it.Rewind(); it.Valid(); it.Next() {
|
||||
item := it.Item()
|
||||
_, source, recTime := unmarshalDataKey(item.Key())
|
||||
el := core.SensorData{}
|
||||
el.Timestamp = recTime
|
||||
el.SetSource(source)
|
||||
err2 := item.Value(func(val []byte) error {
|
||||
//logrus.Traceln(string(val))
|
||||
err3 := json.Unmarshal(val, &el)
|
||||
//logrus.Traceln(err3, el)
|
||||
return err3
|
||||
})
|
||||
if err2 != nil {
|
||||
logrus.Warn(err2)
|
||||
}
|
||||
|
||||
t.Data = append(t.Data, el)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
}
|
||||
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// helper function to create []byte key from sensordata element
|
||||
func createRecordKey(uid uuid.UUID, source core.SourceId, timestamp time.Time) []byte {
|
||||
prefix := []byte(uid.String())
|
||||
var i string
|
||||
switch source {
|
||||
case core.SOURCE_TCP:
|
||||
i = "1"
|
||||
case core.SOURCE_SERIAL:
|
||||
i = "2"
|
||||
}
|
||||
middle := []byte(i)
|
||||
suffix := []byte(timestamp.Format(time.RFC3339Nano))
|
||||
if timestamp.IsZero() {
|
||||
err := errors.New("zero value detected")
|
||||
logrus.Errorln("unable to create key", err)
|
||||
}
|
||||
logrus.Traceln("save as:", string(prefix), string(middle), string(suffix))
|
||||
ret := append(prefix, middle...)
|
||||
return append(ret, suffix...)
|
||||
}
|
||||
|
||||
// helper function to split []byte key back to actual data
|
||||
func unmarshalDataKey(key []byte) (uuid.UUID, core.SourceId, time.Time) {
|
||||
|
||||
prefix := string(key[:36])
|
||||
suffix := string(key[37:])
|
||||
middle := string(key[36:37])
|
||||
|
||||
var source core.SourceId
|
||||
switch middle {
|
||||
case "1":
|
||||
source = core.SOURCE_TCP
|
||||
case "2":
|
||||
source = core.SOURCE_SERIAL
|
||||
}
|
||||
uid, err := uuid.Parse(prefix)
|
||||
if err != nil {
|
||||
logrus.Errorln("corrupted key", err)
|
||||
}
|
||||
timestamp, err := time.Parse(time.RFC3339Nano, suffix)
|
||||
if err != nil {
|
||||
logrus.Errorln("corrupted key", err)
|
||||
}
|
||||
|
||||
return uid, source, timestamp
|
||||
}
|
||||
@ -1,187 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.bundle.js"></script>
|
||||
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no"/>
|
||||
<script src="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
|
||||
<link href="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet"/>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r124/three.js"></script>
|
||||
<script src="static/scripts/distanceCalc.js"></script>
|
||||
<script src="static/scripts/websocket.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="static/indicators/css/flightindicators.css" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||
<script src="static/indicators/js/jquery.flightindicators.js"></script>
|
||||
<link rel="stylesheet" href="static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<table style="font-size: small">
|
||||
<tr>
|
||||
<td valign="top" width="100%">
|
||||
<div class="controls">
|
||||
<label><input type="checkbox" id="checkbox1" value="smartphone"> TCP</label><br>
|
||||
<label><input type="checkbox" id="checkbox2" value="ublox"> SERIAL</label><br>
|
||||
<button id="open">Livetracking starten</button>
|
||||
<button id="close" style="display: none">Trennen</button>
|
||||
|
||||
<button id="allesbeenden" style="margin-right: 16px;">Pipeline stoppen</button>
|
||||
<button id="messungstarten">Aufnahme starten</button>
|
||||
<button id="messungbeenden" style="margin-right: 16px;">Aufnahme beenden</button>
|
||||
<button id="messungladen" style="margin-right: 16px;">Aufnahmen laden</button>
|
||||
|
||||
<label>Aufnahmen:
|
||||
<select name="meas" id="meas" disabled>
|
||||
</select>
|
||||
</label>
|
||||
<button id="replaystarten" style="margin-right: 16px;" disabled>Wiedergabe starten</button>
|
||||
<button id="fullReplay">TRACKINGANALYSE</button>
|
||||
</div>
|
||||
<br>
|
||||
<label id="tracking state" style="font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif">Tracking
|
||||
state: </label><br>
|
||||
<label id="TCPlong" style="font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif">Smartphone
|
||||
long: </label>
|
||||
<label id="TCPlat" style="font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif">Smartphone lat: </label>
|
||||
<label id="SERIALlong" style="font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif">Ublox long: </label>
|
||||
<label id="SERIALlat" style="font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif">Ublox lat: </label>
|
||||
</td>
|
||||
<td valign="top">
|
||||
<div id="output"><p>CLOSED</p></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="float-container">
|
||||
<div class="float-child left-col">
|
||||
<div class="sceneMap">
|
||||
<div id="map"></div>
|
||||
<div id="state-legend" class="legend">
|
||||
<h4>Legende</h4>
|
||||
<div><span style="background-color: rgba(214, 69, 65, 1)"></span>Ublox</div>
|
||||
<div><span style="background-color: rgba(30, 139, 195, 1)"></span>Smartphone</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="outer">
|
||||
<div>
|
||||
<label id="speedTCP"
|
||||
style="color: rgba(30, 139, 195, 1); font: 15px 'Helvetica Neue', Arial, Helvetica, sans-serif">Speed
|
||||
Smartphone (km/h): </label><br>
|
||||
<label id="speedSERIAL"
|
||||
style="color: rgba(214, 69, 65, 1); font: 15px 'Helvetica Neue', Arial, Helvetica, sans-serif">Speed
|
||||
Ublox
|
||||
(km/h): </label><br>
|
||||
</div>
|
||||
<div>
|
||||
<canvas id="speedometer" width="320" height="230"></canvas>
|
||||
<canvas id="speedometerSpeeds" width="320" height="230"></canvas>
|
||||
<p class="speedMin">0</p>
|
||||
<p class="speed14">62</p>
|
||||
<p class="speedMed">125</p>
|
||||
<p class="speed34">188</p>
|
||||
<p class="speedMax">250</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="led-container">
|
||||
<div class="lamps">
|
||||
<div class="lamp">
|
||||
<div class="lampinner" id="greenlamp" style="background-color: darkgreen"></div>
|
||||
</div>
|
||||
<div class="lamp">
|
||||
<div class="lampinner" id="yellow" style="background-color: #9D7519"></div>
|
||||
</div>
|
||||
<div class="lamp">
|
||||
<div class="lampinner" id="redlamp" style="background-color: #8b0000"></div>
|
||||
</div>
|
||||
<label style="margin:auto; margin-left: 10px">Smartphone Genauigkeit</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="accuracy-container">
|
||||
<div style="width: 500px; height: 150px;">
|
||||
<canvas id="accuracy" width="500" height="150"></canvas>
|
||||
</div>
|
||||
<div class="accuracy-values">
|
||||
<div class="container" style="width: 150px; height: 70px">
|
||||
<label id="serialHAcc"
|
||||
style="color: rgba(214, 69, 65, 1); font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif">Ublox
|
||||
HAcc: </label><br>
|
||||
<label id="tcpHAcc"
|
||||
style="color: rgba(30, 139, 195, 1); font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif">Phone
|
||||
HAcc: </label><br>
|
||||
<label id="distance"
|
||||
style="color: rgba(30, 139, 0, 1); font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif">
|
||||
Distance: </label>
|
||||
|
||||
</div>
|
||||
<div class="container" style="width: 150px; height: 50px">
|
||||
<label id="serialVAcc"
|
||||
style="color: rgba(214, 69, 65, 1); font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif">Ublox
|
||||
VAcc: </label><br>
|
||||
<label id="tcpVAcc"
|
||||
style="color: rgba(30, 139, 195, 1); font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif">Phone
|
||||
VAcc: </label><br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="float-child right-col">
|
||||
<div class="compass-container">
|
||||
<label id="airspeedLabel"
|
||||
style="display:inline-block; width: 200px; margin-right: 0; color: rgba(214, 69, 65, 1); font: 15px 'Helvetica Neue', Arial, Helvetica, sans-serif">Ref. Speed:</label>
|
||||
<label id="altitudeLabel"
|
||||
style="color: rgba(214, 69, 65, 1); font: 15px 'Helvetica Neue', Arial, Helvetica, sans-serif">Altitude: </label><br>
|
||||
<span id="airspeed"></span>
|
||||
<span id="altimeter"></span>
|
||||
<div class="compass-digital">
|
||||
<label id="compassSERIAL"
|
||||
style="display:inline-block; width: 200px; margin-right: 0; color: rgba(214, 69, 65, 1); font: 15px 'Helvetica Neue', Arial, Helvetica, sans-serif"></label>
|
||||
<label id="compassTCP"
|
||||
style="color: rgba(30, 139, 195, 1); font: 15px 'Helvetica Neue', Arial, Helvetica, sans-serif"></label><br>
|
||||
<label id="compassSERIALMot"
|
||||
style="display:inline-block; width: 200px; margin-right: 0; color: rgba(214, 69, 65, 1); font: 15px 'Helvetica Neue', Arial, Helvetica, sans-serif"></label>
|
||||
<label id="compassTCPMot"
|
||||
style="color: rgba(30, 139, 195, 1); font: 15px 'Helvetica Neue', Arial, Helvetica, sans-serif"></label><br>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<span id="headingSer"></span>
|
||||
<span id="headingTcp"></span>
|
||||
<span id="attitudeSer"></span>
|
||||
<span id="attitudeTcp"></span>
|
||||
|
||||
<div>
|
||||
<div id="viewport">
|
||||
</div>
|
||||
<label id="quaternionOffset"
|
||||
style="color: grey; font: 15px 'Helvetica Neue', Arial, Helvetica, sans-serif">Lage Abweichung: </label><br>
|
||||
<div class="slidecontainer">
|
||||
<button id="calibrate">Smartphone Ausrichtung kalibrieren</button>
|
||||
<button id="deleteCalibration">Kalibrierung zurücksetzen</button>
|
||||
<button id="manualCalibration">Manuelle Kalibrierung</button>
|
||||
<div id="manCalContainer">
|
||||
<p><br>Manuelle Kalibrierung</p>
|
||||
<label>Pitch<input type="range" min="-180" max="180" value="0" class="slider" id="pitchRange"
|
||||
style="margin: 10px 0px"></label>
|
||||
<label>Yaw<input type="range" min="-180" max="180" value="0" class="slider" id="yawRange"
|
||||
style="margin: 10px 0px"></label>
|
||||
<label>Roll<input type="range" min="-180" max="180" value="0" class="slider" id="rollRange"
|
||||
style="margin: 10px 0px"></label>
|
||||
</div>
|
||||
</div>
|
||||
<script src="static/scripts/indicators.js"></script>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="static/scripts/map.js"></script>
|
||||
<script src="static/scripts/speedometer.js"></script>
|
||||
|
||||
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.4/Chart.min.js"></script>
|
||||
<script src="static/scripts/accuracy.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,47 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.bundle.js"></script>
|
||||
<script src="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.js"></script>
|
||||
<link href="https://api.mapbox.com/mapbox-gl-js/v1.12.0/mapbox-gl.css" rel="stylesheet" />
|
||||
<script src="static/scripts/distanceCalc.js"></script>
|
||||
<script src="static/scripts/refull.js"></script>
|
||||
<link rel="stylesheet" href="static/replayStyle.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="controls">
|
||||
<br>
|
||||
<button id="messungladen" style="margin-right: 16px;">Aufnahmen laden</button>
|
||||
|
||||
<label>Aufnahmen:
|
||||
<select name="meas" id="meas" disabled>
|
||||
</select>
|
||||
</label>
|
||||
<button id="replaystarten" style="margin-right: 16px;" disabled>Öffnen</button>
|
||||
</div>
|
||||
|
||||
<div class="sceneMap">
|
||||
<div id="map" style='width: 1000px; height: 500px;'></div>
|
||||
<div id="state-legend" class="legend">
|
||||
<h4>Legende</h4>
|
||||
<div><span style="background-color: rgba(214, 69, 65, 1)"></span>Ublox</div>
|
||||
<div><span style="background-color: rgba(30, 139, 195, 1)"></span>Smartphone</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="width: 1000px; height: 300px;">
|
||||
<canvas id="speedChart" width="1000" height="300"></canvas>
|
||||
</div>
|
||||
<div style="width: 1000px; height: 300px;">
|
||||
<canvas id="accChart" width="1000" height="300"></canvas>
|
||||
</div>
|
||||
|
||||
|
||||
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
|
||||
<script src="static/scripts/mapFull.js"></script>
|
||||
<script src="static/scripts/speedChart.js"></script>
|
||||
<script src="static/scripts/accChart.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -1,6 +1,3 @@
|
||||
// credits to https://github.com/daedaleanai/ublox for basic ubx parsing idea & code
|
||||
// missing ubx messages added and code modified by Timo Volkmann
|
||||
|
||||
// Package ublox provides methods to encode and decode u-Blox 8 / M8 NMEA and UBX messages
|
||||
// as documented in
|
||||
// UBX-13003221 - R20 u-blox 8 / u-blox M8 Receiver description Including protocol specification
|
||||
@ -17,17 +14,17 @@ import (
|
||||
"io"
|
||||
)
|
||||
|
||||
// A decoder scans an io stream into UBX (0xB5-0x62 separated) or NMEA ("$xxx,,,,*FF\r\n") frames.
|
||||
// A Decoder scans an io stream into UBX (0xB5-0x62 separated) or NMEA ("$xxx,,,,*FF\r\n") frames.
|
||||
// If you have an unmixed stream of NMEA-only data you can use nmea.Decode() on bufio.Scanner.Bytes() directly.
|
||||
type decoder struct {
|
||||
type Decoder struct {
|
||||
s *bufio.Scanner
|
||||
}
|
||||
|
||||
// NewDecoder creates a new bufio Scanner with a splitfunc that can handle both UBX and NMEA frames.
|
||||
func NewDecoder(r io.Reader) *decoder {
|
||||
func NewDecoder(r io.Reader) *Decoder {
|
||||
d := bufio.NewScanner(r)
|
||||
d.Split(splitFunc)
|
||||
return &decoder{s: d}
|
||||
return &Decoder{s: d}
|
||||
}
|
||||
|
||||
// Assume we're either at the start of an NMEA sentence or at the start of a UBX message
|
||||
@ -77,8 +74,8 @@ func splitFunc(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||
return 1 + i1, nil, nil
|
||||
}
|
||||
|
||||
// Decode reads on NMEA or UBX frame and calls decodeUbx accordingly to parse the message, while skipping NMEA.
|
||||
func (d *decoder) Decode() (msg interface{}, err error) {
|
||||
// Decode reads on NMEA or UBX frame and calls DecodeUbx accordingly to parse the message. Skips NMEA.
|
||||
func (d *Decoder) Decode() (msg Message, err error) {
|
||||
if !d.s.Scan() {
|
||||
if err = d.s.Err(); err == nil {
|
||||
err = io.EOF
|
||||
@ -88,10 +85,11 @@ func (d *decoder) Decode() (msg interface{}, err error) {
|
||||
|
||||
switch d.s.Bytes()[0] {
|
||||
case '$':
|
||||
return nil, errors.New("NMEA not implemented")
|
||||
//fmt.Println("NMEA message: skipping!")
|
||||
return nil, err
|
||||
//return nmea.Decode(d.s.Bytes())
|
||||
case 0xB5:
|
||||
return decodeUbx(d.s.Bytes())
|
||||
return DecodeUbx(d.s.Bytes())
|
||||
}
|
||||
panic("impossible frame")
|
||||
}
|
||||
@ -101,7 +99,7 @@ var (
|
||||
errInvalidChkSum = errors.New("invalid UBX checksum")
|
||||
)
|
||||
|
||||
func decodeUbx(frame []byte) (msg Message, err error) {
|
||||
func DecodeUbx(frame []byte) (msg Message, err error) {
|
||||
|
||||
buf := bytes.NewReader(frame)
|
||||
|
||||
@ -151,7 +149,7 @@ func decodeUbx(frame []byte) (msg Message, err error) {
|
||||
if msg != nil {
|
||||
err = binary.Read(buf, binary.LittleEndian, msg)
|
||||
} else {
|
||||
msg = &RawMessage{classID: header.ClassID, Data: append([]byte(nil), frame[6:len(frame)-2]...)}
|
||||
msg = &RawMessage{ClassID: header.ClassID, Data: append([]byte(nil), frame[6:len(frame)-2]...)}
|
||||
}
|
||||
//fmt.Println(msg)
|
||||
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
package ublox
|
||||
|
||||
type Message interface {
|
||||
ClassID() uint16
|
||||
classID() uint16
|
||||
}
|
||||
|
||||
type RawMessage struct {
|
||||
classID uint16
|
||||
ClassID uint16
|
||||
Data []byte
|
||||
}
|
||||
|
||||
func (msg *RawMessage) ClassID() uint16 { return msg.classID }
|
||||
func (msg *RawMessage) classID() uint16 { return msg.ClassID }
|
||||
|
||||
type NavPvt struct {
|
||||
ITOW_ms uint32 // - GPS time of week of the navigation epoch. See the description of iTOW for details.
|
||||
@ -47,7 +47,7 @@ type NavPvt struct {
|
||||
MagAcc_deg2e uint16 // 1e-2 Magnetic declination accuracy. Only supported in ADR 4.10 and later.
|
||||
}
|
||||
|
||||
func (NavPvt) ClassID() uint16 { return 0x0701 }
|
||||
func (NavPvt) classID() uint16 { return 0x0701 }
|
||||
|
||||
type HnrPvt struct {
|
||||
ITOW_ms uint32 // - GPS time of week of the navigation epoch. See the description of iTOW for details.
|
||||
@ -77,7 +77,7 @@ type HnrPvt struct {
|
||||
Reserved1 [4]byte // - Reserved
|
||||
}
|
||||
|
||||
func (HnrPvt) ClassID() uint16 { return 0x0028 }
|
||||
func (HnrPvt) classID() uint16 { return 0x0028 }
|
||||
|
||||
type NavAtt struct {
|
||||
ITOW_ms uint32 // - GPS time of week of the navigation epoch. See the description of iTOW for details.
|
||||
@ -91,7 +91,7 @@ type NavAtt struct {
|
||||
AccHeading_deg uint32
|
||||
}
|
||||
|
||||
func (NavAtt) ClassID() uint16 { return 0x0501 }
|
||||
func (NavAtt) classID() uint16 { return 0x0501 }
|
||||
|
||||
//go:generate stringer -output=strings_navpvt.go -trimprefix NavPVT -type=NavPVTFixType,NavPVTValid,NavPVTFlags,NavPVTFlags2,NavPVTFlags3
|
||||
|
||||
|
||||
260
web/http.go
260
web/http.go
@ -1,260 +0,0 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.timovolkmann.de/gyrogpsc/core"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||
"github.com/gofiber/template/html"
|
||||
"github.com/gofiber/websocket/v2"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func CreateServer(s *core.TrackingService, sub core.Subscriber, c *core.Configuration) {
|
||||
app := fiber.New(fiber.Config{
|
||||
Views: fiberTemplateEngine(c),
|
||||
})
|
||||
app.Use(logger.New())
|
||||
app.Static("/static", "./static")
|
||||
|
||||
// Application Main Page
|
||||
app.Get("/", fiberHomeHandler)
|
||||
app.Get("/tracking", fiberTrackingHandler)
|
||||
|
||||
// Websocket
|
||||
app.Get("/ws", websocket.New(createFiberWebsocketHandler(sub)))
|
||||
|
||||
// Tracking persistence controls HTTP JSON RPC API
|
||||
trackings := app.Group("/trackings")
|
||||
trackings.Get("/", allTrackingsHandler(s, c)) // Get all trackings Metadata
|
||||
trackings.Post("/", startPipelineHandler(s, c)) // Initialize new tracking, open websocket and prepare for automatic recording. Toggle ?serial=true and ?tcp=true. Returns trackingId
|
||||
trackings.Patch("/", startRecordingHandler(s, c)) // Starts recording
|
||||
trackings.Put("/", stopRecordingHandler(s, c)) // Stops current recording. Returns trackingId if record was successful
|
||||
trackings.Delete("/", stopAllHandler(s, c)) // Stops websocket connection, pipelines and collectors
|
||||
trackings.Get("/:trackingId", LoadTrackingHandler(s, c)) // Gets Tracking Metadata and loads sensorRecords from storage.
|
||||
|
||||
logrus.Fatal(app.Listen(c.Webserver.Port))
|
||||
}
|
||||
|
||||
func LoadTrackingHandler(s *core.TrackingService, c *core.Configuration) fiber.Handler {
|
||||
return func(ctx *fiber.Ctx) error {
|
||||
trackId := ctx.Params("trackingId")
|
||||
uid, err := uuid.Parse(trackId)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
ctx.Status(404).JSON(err)
|
||||
return err
|
||||
}
|
||||
var replay bool
|
||||
if ctx.Query("replay", "false") == "true" {
|
||||
replay = true
|
||||
} else {
|
||||
replay = false
|
||||
}
|
||||
tracking, err := s.LoadTracking(uid, replay)
|
||||
if err != nil {
|
||||
logrus.Error(err)
|
||||
ctx.Status(404).JSON(err)
|
||||
return err
|
||||
}
|
||||
st := struct {
|
||||
core.TrackingMetadata
|
||||
Data map[string][]core.SensorData
|
||||
}{}
|
||||
st.TrackingMetadata = tracking.TrackingMetadata
|
||||
st.Data = make(map[string][]core.SensorData)
|
||||
for _, el := range tracking.Data {
|
||||
st.Data[string(el.Source())] = append(st.Data[string(el.Source())], el)
|
||||
}
|
||||
prepres := make(map[string]interface{})
|
||||
prepres["data"] = st
|
||||
|
||||
err2 := ctx.JSON(prepres)
|
||||
if err2 != nil {
|
||||
ctx.Status(500).JSON(err2)
|
||||
return err2
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
func allTrackingsHandler(s *core.TrackingService, c *core.Configuration) fiber.Handler {
|
||||
return func(ctx *fiber.Ctx) error {
|
||||
trackings, err := s.AllTrackings()
|
||||
|
||||
prepres := make(map[string]interface{})
|
||||
prepres["data"] = trackings
|
||||
if err != nil {
|
||||
prepres["error"] = err.Error()
|
||||
}
|
||||
err2 := ctx.JSON(prepres)
|
||||
if err2 != nil {
|
||||
ctx.Status(500).JSON(err2)
|
||||
return err2
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func startPipelineHandler(s *core.TrackingService, c *core.Configuration) fiber.Handler {
|
||||
return func(ctx *fiber.Ctx) error {
|
||||
var collecs []core.CollectorType
|
||||
ser := ctx.Query("serial", "true")
|
||||
if ser == "true" {
|
||||
collecs = append(collecs, core.SERIAL)
|
||||
} else if ser != "false" && ser != "" {
|
||||
collecs = append(collecs, core.CollectorType(ser)) // TODO: allow passing serial port as url parameter
|
||||
}
|
||||
tcp := ctx.Query("tcp", "true")
|
||||
logrus.Debugln("query values: serial/tcp", ser, tcp)
|
||||
if tcp == "true" {
|
||||
collecs = append(collecs, core.TCP)
|
||||
}
|
||||
res, err := s.StartLivetracking(collecs...)
|
||||
|
||||
prepres := make(map[string]interface{})
|
||||
prepres["tracking_state"] = res
|
||||
prepres["data"] = collecs
|
||||
if err != nil {
|
||||
prepres["error"] = err.Error()
|
||||
}
|
||||
if len(collecs) == 0 {
|
||||
e := errors.New("attention! no collectors running. start a new pipeline")
|
||||
prepres["error"] = e.Error()
|
||||
}
|
||||
err2 := ctx.JSON(prepres)
|
||||
if err2 != nil {
|
||||
ctx.Status(500).JSON(err2)
|
||||
return err2
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func startRecordingHandler(s *core.TrackingService, c *core.Configuration) fiber.Handler {
|
||||
return func(ctx *fiber.Ctx) error {
|
||||
rec, err := s.StartRecord()
|
||||
|
||||
prepres := make(map[string]interface{})
|
||||
prepres["tracking_state"] = "RECORD"
|
||||
prepres["data"] = rec
|
||||
if err != nil {
|
||||
prepres["error"] = err.Error()
|
||||
|
||||
}
|
||||
err2 := ctx.JSON(prepres)
|
||||
if err2 != nil {
|
||||
ctx.Status(500).JSON(err2)
|
||||
return err2
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func stopRecordingHandler(s *core.TrackingService, c *core.Configuration) fiber.Handler {
|
||||
return func(ctx *fiber.Ctx) error {
|
||||
rec, err := s.StopRecord()
|
||||
|
||||
prepres := make(map[string]interface{})
|
||||
prepres["tracking_state"] = "LIVE"
|
||||
prepres["data"] = rec
|
||||
if err != nil {
|
||||
prepres["error"] = err.Error()
|
||||
|
||||
}
|
||||
err2 := ctx.JSON(prepres)
|
||||
if err2 != nil {
|
||||
ctx.Status(500).JSON(err2)
|
||||
return err2
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func stopAllHandler(s *core.TrackingService, c *core.Configuration) fiber.Handler {
|
||||
return func(ctx *fiber.Ctx) error {
|
||||
rec, err := s.StopAll()
|
||||
|
||||
prepres := make(map[string]interface{})
|
||||
prepres["tracking_state"] = "STOPPED"
|
||||
prepres["data"] = rec
|
||||
if err != nil {
|
||||
prepres["error"] = err.Error()
|
||||
|
||||
}
|
||||
err2 := ctx.JSON(prepres)
|
||||
if err2 != nil {
|
||||
ctx.Status(500).JSON(err2)
|
||||
return err2
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func createFiberWebsocketHandler(s core.Subscriber) func(conn *websocket.Conn) {
|
||||
return func(c *websocket.Conn) {
|
||||
logrus.Info("new websocket client")
|
||||
// Handle and discard inbound messages
|
||||
go func() {
|
||||
for {
|
||||
if _, _, err := c.NextReader(); err != nil {
|
||||
c.Close()
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
dispatcherId, channel := s.Subscribe()
|
||||
defer s.Unsubscribe(dispatcherId)
|
||||
for {
|
||||
cmsg := <-channel
|
||||
logrus.Traceln("write to ws:", cmsg)
|
||||
err := c.WriteMessage(websocket.TextMessage, []byte(cmsg))
|
||||
if err != nil {
|
||||
logrus.Infoln("close websocket connection", err)
|
||||
c.Close()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fiberTemplateEngine(c *core.Configuration) *html.Engine {
|
||||
// Create a new engine by passing the template folder
|
||||
// and template extension using <engine>.New(dir, ext string)
|
||||
engine := html.New("./templates", ".html")
|
||||
|
||||
// We also support the http.FileSystem interface
|
||||
// See examples below to load templates from embedded files
|
||||
// engine := html.NewFileSystem(http.Dir("./views"), ".html")
|
||||
|
||||
// Reload the templates on each render, good for development
|
||||
//engine.Reload(strings.ToLower(c.Debuglevel) == "debug") // Optional. Default: false
|
||||
engine.Reload(true) // Optional. Default: false
|
||||
|
||||
// Debug will print each template that is parsed, good for debugging
|
||||
//engine.Debug(strings.ToLower(c.Debuglevel) == "debug") // Optional. Default: false
|
||||
engine.Debug(true) // Optional. Default: false
|
||||
|
||||
// Layout defines the variable name that is used to yield templates within layouts
|
||||
//engine.Layout("embed") // Optional. Default: "embed"
|
||||
|
||||
// Delims sets the action delimiters to the specified strings
|
||||
//engine.Delims("{{", "}}") // Optional. Default: engine delimiters
|
||||
|
||||
// AddFunc adds a function to the template's global function map.
|
||||
//engine.AddFunc("greet", func(name string) string {
|
||||
// return "Hello, " + name + "!"
|
||||
//})
|
||||
return engine
|
||||
}
|
||||
|
||||
func fiberHomeHandler(c *fiber.Ctx) error {
|
||||
// Render index template
|
||||
return c.Render("index", "ws://"+c.Hostname()+"/ws")
|
||||
}
|
||||
|
||||
func fiberTrackingHandler(c *fiber.Ctx) error {
|
||||
// Render index template
|
||||
return c.Render("replayFull", nil)
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user