merge
This commit is contained in:
commit
6dcfbd012f
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
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>
|
||||
1
.idea/vcs.xml
generated
1
.idea/vcs.xml
generated
@ -2,6 +2,5 @@
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/serial/SparkFun_Ublox_Arduino_Library" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
27
.idea/workspace.xml
generated
27
.idea/workspace.xml
generated
@ -22,7 +22,32 @@
|
||||
</select>
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="99c957e4-aa42-481d-843d-3fbc901e0f79" name="Default Changelist" comment="" />
|
||||
<list default="true" id="99c957e4-aa42-481d-843d-3fbc901e0f79" name="Default Changelist" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/.idea/.gitignore" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/cmd/tcp_only/tcp_only.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/core/collectors.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/core/dispatcher.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/core/format.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/core/http.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/core/pipeline.go" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/static/iphone.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/vcs.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/cmd/serial_only/serial_only.go" beforeDir="false" afterPath="$PROJECT_DIR$/cmd/serial_only/serial_only.go" 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" />
|
||||
<change beforePath="$PROJECT_DIR$/dispatcher/dispatcher.go" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/ex_websocketMessage.json" beforeDir="false" afterPath="$PROJECT_DIR$/static/ex_websocketMessage.json" 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$/static/hyperimu.json" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/index.html" beforeDir="false" afterPath="$PROJECT_DIR$/static/index.html" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/net/net.go" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/serial_ubx/serial.go" beforeDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/ublox/decode.go" beforeDir="false" afterPath="$PROJECT_DIR$/ublox/decode.go" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/ublox/messages.go" beforeDir="false" afterPath="$PROJECT_DIR$/ublox/messages.go" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
|
||||
@ -1,14 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"git.timovolkmann.de/gyrogpsc/serial_ubx"
|
||||
"log"
|
||||
"fmt"
|
||||
"git.timovolkmann.de/gyrogpsc/core"
|
||||
)
|
||||
|
||||
const (
|
||||
SERIAL_PORT = "/dev/tty.usbmodem14201"
|
||||
)
|
||||
|
||||
func main() {
|
||||
r, err := serial_ubx.Setup("/dev/tty.usbmodem14201")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
r.Printloop()
|
||||
core.SerialCollector(&printer{}, SERIAL_PORT)
|
||||
}
|
||||
|
||||
type printer struct{}
|
||||
|
||||
func (p *printer) Process(data *core.Sensordata) error {
|
||||
fmt.Println(data)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"git.timovolkmann.de/gyrogpsc/dispatcher"
|
||||
gnet "git.timovolkmann.de/gyrogpsc/net"
|
||||
"git.timovolkmann.de/gyrogpsc/core"
|
||||
"log"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -12,14 +12,19 @@ const (
|
||||
)
|
||||
|
||||
func main() {
|
||||
d := dispatcher.New()
|
||||
collectRoutines(d)
|
||||
gnet.NewHttpServer(d, HTTP_PORT)
|
||||
log.Println("setup dispatcher")
|
||||
dispatcher := core.NewDispatcher()
|
||||
log.Println("initialize processing pipeline")
|
||||
processor := core.NewPipeline(dispatcher, 50, 494)
|
||||
processor.Run()
|
||||
collectRoutines(processor)
|
||||
log.Println("start http server")
|
||||
core.HttpListenAndServe(dispatcher, 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)
|
||||
func collectRoutines(proc core.Processor) {
|
||||
// collect Sensor data from Serial UBX in Goroutine
|
||||
go core.SerialCollector(proc, SERIAL_PORT)
|
||||
// collect Sensor data from JSON over TCP in Goroutine
|
||||
go core.TcpCollector(proc, TCP_PORT)
|
||||
}
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
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)
|
||||
}
|
||||
22
cmd/tcp_only/tcp_only.go
Normal file
22
cmd/tcp_only/tcp_only.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"git.timovolkmann.de/gyrogpsc/core"
|
||||
)
|
||||
|
||||
const (
|
||||
TCP_PORT = ":3010"
|
||||
HTTP_PORT = ":3011"
|
||||
)
|
||||
|
||||
func main() {
|
||||
dispatcher := core.NewDispatcher()
|
||||
processor := core.NewPipeline(dispatcher, 20, 10000)
|
||||
collectRoutines(processor)
|
||||
core.HttpListenAndServe(dispatcher, HTTP_PORT)
|
||||
}
|
||||
|
||||
func collectRoutines(proc core.Processor) {
|
||||
// collect Sensor data from JSON over TCP in Goroutine
|
||||
go core.TcpCollector(proc, TCP_PORT)
|
||||
}
|
||||
105
core/collectors.go
Normal file
105
core/collectors.go
Normal file
@ -0,0 +1,105 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"git.timovolkmann.de/gyrogpsc/ublox"
|
||||
"go.bug.st/serial"
|
||||
)
|
||||
|
||||
func TcpCollector(proc Processor, tcpPort string) {
|
||||
log.Println("start tcp collectors")
|
||||
|
||||
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)
|
||||
}
|
||||
log.Println("...new incoming tcp connection...")
|
||||
|
||||
// Handle connections in a new goroutine.
|
||||
go jsonHandler(conn, proc)
|
||||
}
|
||||
}
|
||||
|
||||
// handles incoming tcp connections with json payload.
|
||||
func jsonHandler(conn net.Conn, proc Processor) {
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
// TRY reader := bufio.NewReader(conn) OR NewScanner(conn)
|
||||
buf := make([]byte, 2048)
|
||||
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
|
||||
}
|
||||
//json := pretty.Pretty(buf[:n])
|
||||
//fmt.Println(string(json))
|
||||
//fmt.Println(string(buf[:n]))
|
||||
sd, err := ConvertSensorDataPhone(buf[:n])
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
|
||||
err = proc.Process(sd)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func SerialCollector(proc Processor, serialPort string) {
|
||||
log.Println("start serial collectors")
|
||||
mode := &serial.Mode{
|
||||
BaudRate: 115200,
|
||||
}
|
||||
port, err := serial.Open(serialPort, mode)
|
||||
if err != nil {
|
||||
log.Fatalln(err.Error())
|
||||
}
|
||||
|
||||
decoder := ublox.NewDecoder(port)
|
||||
|
||||
for {
|
||||
meas, err := decoder.Decode()
|
||||
if err != nil {
|
||||
if err.Error() == "NMEA not implemented" {
|
||||
continue
|
||||
}
|
||||
log.Println(err)
|
||||
continue
|
||||
}
|
||||
sd, err := ConvertUbxToSensorData(meas)
|
||||
if err != nil {
|
||||
log.Println("convert err:", err, meas)
|
||||
continue
|
||||
}
|
||||
if sd == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
err = proc.Process(sd)
|
||||
if err != nil {
|
||||
log.Println("process err:", err, *sd)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
52
core/dispatcher.go
Normal file
52
core/dispatcher.go
Normal file
@ -0,0 +1,52 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
)
|
||||
|
||||
type Subscriber interface {
|
||||
Subscribe() (int16, <-chan string)
|
||||
Unsubscribe(id int16) error
|
||||
}
|
||||
|
||||
type Publisher interface {
|
||||
Publish(message string)
|
||||
}
|
||||
|
||||
type dispatcher struct {
|
||||
listeners map[int16]chan string
|
||||
counter int16
|
||||
}
|
||||
|
||||
func NewDispatcher() *dispatcher {
|
||||
return &dispatcher{
|
||||
listeners: make(map[int16]chan string),
|
||||
counter: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dispatcher) Publish(message string) {
|
||||
log.Printf("publish to %v listeners:\n%v\n", len(d.listeners), message)
|
||||
for _, ch := range d.listeners {
|
||||
ch <- message
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
178
core/format.go
Normal file
178
core/format.go
Normal file
@ -0,0 +1,178 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.timovolkmann.de/gyrogpsc/ublox"
|
||||
"github.com/tidwall/gjson"
|
||||
"log"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/m7shapan/njson"
|
||||
)
|
||||
|
||||
/*{
|
||||
"smartphone": {
|
||||
// hier daten von hyperimu
|
||||
},
|
||||
"serial": {
|
||||
// hier Daten von M8U:
|
||||
"timestamp": 37539672354
|
||||
"position": [0, 0, 0],
|
||||
"orientation": [0, 0, 0]
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
type sourceId string
|
||||
|
||||
const (
|
||||
SOURCE_TCP sourceId = "SOURCE_TCP"
|
||||
SOURCE_SERIAL sourceId = "SOURCE_SERIAL"
|
||||
)
|
||||
|
||||
type Sensordata struct {
|
||||
itow uint32
|
||||
SourceId sourceId
|
||||
Timestamp int64
|
||||
Position [3]float64
|
||||
Orientation [3]float64
|
||||
}
|
||||
|
||||
func (s Sensordata) isSameEpoch(n Sensordata) bool {
|
||||
if n.itow == 0 {
|
||||
return false
|
||||
}
|
||||
return s.itow == n.itow
|
||||
}
|
||||
|
||||
func (s Sensordata) Consolidate(n Sensordata) Sensordata {
|
||||
if (s.SourceId != n.SourceId && s != Sensordata{}) {
|
||||
log.Println(s)
|
||||
log.Println(n)
|
||||
log.Fatalln("Do not consolidate Sensordata from different Sources")
|
||||
}
|
||||
if s.isSameEpoch(n) {
|
||||
null := Sensordata{}
|
||||
//if s.Timestamp == null.Timestamp { s.Timestamp = n.Timestamp }
|
||||
//if s.Position == null.Position { s.Position = n.Position }
|
||||
//if s.Orientation == null.Orientation { s.Orientation = n.Orientation }
|
||||
if n.Timestamp != null.Timestamp && s.Timestamp != n.Timestamp {
|
||||
s.Timestamp = n.Timestamp
|
||||
}
|
||||
if n.Position != null.Position && s.Position != n.Position {
|
||||
s.Position = n.Position
|
||||
}
|
||||
if n.Orientation != null.Orientation && s.Orientation != n.Orientation {
|
||||
s.Orientation = n.Orientation
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func (s Sensordata) Consolidate2(n Sensordata) Sensordata {
|
||||
null := Sensordata{}
|
||||
//if s.Timestamp == null.Timestamp { s.Timestamp = n.Timestamp }
|
||||
//if s.Position == null.Position { s.Position = n.Position }
|
||||
//if s.Orientation == null.Orientation { s.Orientation = n.Orientation }
|
||||
//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
|
||||
}
|
||||
|
||||
var (
|
||||
errNotImplemented = errors.New("message not implemented")
|
||||
errRawMessage = errors.New("raw message")
|
||||
)
|
||||
|
||||
func ConvertUbxToSensorData(msg interface{}) (*Sensordata, error) {
|
||||
sd := &Sensordata{
|
||||
SourceId: SOURCE_SERIAL,
|
||||
}
|
||||
switch v := msg.(type) {
|
||||
case *ublox.NavPvt:
|
||||
//log.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).UnixNano()
|
||||
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
|
||||
case *ublox.HnrPvt:
|
||||
//log.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).UnixNano()
|
||||
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
|
||||
case *ublox.NavAtt:
|
||||
//log.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:
|
||||
//class := make([]byte, 2)
|
||||
//binary.LittleEndian.PutUint16(class, v.ClassID())
|
||||
//log.Printf("%#v, %#v", class[0],class[1])
|
||||
return nil, nil
|
||||
default:
|
||||
return nil, errNotImplemented
|
||||
}
|
||||
return sd, nil
|
||||
}
|
||||
|
||||
func ConvertSensorDataPhone(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
|
||||
sd := &Sensordata{
|
||||
SourceId: SOURCE_TCP,
|
||||
Timestamp: int64(timestamp * float64(time.Second)),
|
||||
//Timestamp: time.Unix(0, prep.Timestamp * int64(time.Millisecond)),
|
||||
Position: [3]float64{lat, lon, alt},
|
||||
Orientation: [3]float64{pitch, roll, yaw},
|
||||
}
|
||||
//log.Println(string(pretty.Pretty(jsonData)))
|
||||
//log.Println(sd)
|
||||
return sd, nil
|
||||
}
|
||||
|
||||
|
||||
func convertAndroidHyperImu(jsonData []byte) (*Sensordata, error) {
|
||||
prep := struct {
|
||||
Timestamp int64 `njson:"Timestamp"`
|
||||
Position [3]float64 `njson:"GPS"`
|
||||
Orientation [3]float64 `njson:"orientation"`
|
||||
}{}
|
||||
err := njson.Unmarshal(jsonData, &prep)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sd := &Sensordata{
|
||||
Timestamp: prep.Timestamp * int64(time.Millisecond),
|
||||
//Timestamp: time.Unix(0, prep.Timestamp * int64(time.Millisecond)),
|
||||
Position: prep.Position,
|
||||
Orientation: prep.Orientation,
|
||||
}
|
||||
return sd, nil
|
||||
}
|
||||
71
core/http.go
Normal file
71
core/http.go
Normal file
@ -0,0 +1,71 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gorilla/websocket"
|
||||
"html/template"
|
||||
"log"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func echo(sub Subscriber) 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 := sub.Subscribe()
|
||||
defer sub.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.NewDispatcher("").ParseFiles("index.html"))
|
||||
tpl, err := template.ParseFiles("static/index.html")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
err = tpl.Execute(w, "ws://"+r.Host+"/echo")
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
|
||||
func HttpListenAndServe(sub Subscriber, httpPort string) {
|
||||
log.Println("register websocket handler")
|
||||
http.HandleFunc("/echo", echo(sub))
|
||||
log.Println("register index handler")
|
||||
http.HandleFunc("/", home)
|
||||
log.Println("register static file handler")
|
||||
http.Handle("/static/", http.FileServer(http.Dir(".")))
|
||||
|
||||
log.Println("start server")
|
||||
log.Fatal(http.ListenAndServe(httpPort, nil))
|
||||
}
|
||||
169
core/pipeline.go
Normal file
169
core/pipeline.go
Normal file
@ -0,0 +1,169 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TODO: adapt HNR-INS data to continue orientation stream
|
||||
|
||||
type Processor interface {
|
||||
Process(data *Sensordata) error
|
||||
}
|
||||
|
||||
type pipeline struct {
|
||||
syn synchronizer
|
||||
agr aggregator
|
||||
pub Publisher
|
||||
publishTicker *time.Ticker
|
||||
}
|
||||
|
||||
func NewPipeline(d Publisher, publishIntervalMs int, delayUpdateIntervalMs int) *pipeline {
|
||||
return &pipeline{
|
||||
synchronizer{
|
||||
//bufferSize: 100,
|
||||
mutex: &sync.Mutex{},
|
||||
updateTicker: time.NewTicker(time.Duration(delayUpdateIntervalMs) * time.Millisecond),
|
||||
},
|
||||
aggregator{
|
||||
tcpMutex: &sync.Mutex{},
|
||||
serialMutex: &sync.Mutex{},
|
||||
},
|
||||
d,
|
||||
time.NewTicker(time.Duration(publishIntervalMs) * time.Millisecond),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pipeline) Run() {
|
||||
go p.scheduleSynchronizer()
|
||||
go func() {
|
||||
for {
|
||||
<-p.publishTicker.C
|
||||
err := p.Publish()
|
||||
if err != nil && err.Error() != "no data available" {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
log.Println("pipeline: processing service started")
|
||||
}
|
||||
|
||||
func (p *pipeline) Publish() error {
|
||||
p.agr.tcpMutex.Lock()
|
||||
p.agr.serialMutex.Lock()
|
||||
//log.Println(pub.tcpSensorData)
|
||||
//log.Println(pub.serialSensorData)
|
||||
if (p.agr.tcpSensorData == Sensordata{} && p.agr.serialSensorData == Sensordata{}) {
|
||||
p.agr.tcpMutex.Unlock()
|
||||
p.agr.serialMutex.Unlock()
|
||||
return errors.New("no data available")
|
||||
}
|
||||
data := map[string]Sensordata{
|
||||
string(SOURCE_TCP): p.agr.tcpSensorData,
|
||||
string(SOURCE_SERIAL): p.agr.serialSensorData,
|
||||
}
|
||||
//p.agr.tcpSensorData = Sensordata{}
|
||||
//p.agr.serialSensorData = Sensordata{}
|
||||
p.agr.tcpMutex.Unlock()
|
||||
p.agr.serialMutex.Unlock()
|
||||
|
||||
jdata, err := json.Marshal(data)
|
||||
//log.Println(string(pretty.Pretty(jdata)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.pub.Publish(string(jdata))
|
||||
return nil
|
||||
}
|
||||
|
||||
type aggregator struct {
|
||||
tcpSensorData Sensordata
|
||||
serialSensorData Sensordata
|
||||
tcpMutex *sync.Mutex
|
||||
serialMutex *sync.Mutex
|
||||
}
|
||||
|
||||
type UnixNanoTime int64
|
||||
|
||||
type synchronizer struct {
|
||||
tcpSerialDelayMs int64
|
||||
//tcpBuffer map[UnixNanoTime]Sensordata
|
||||
//serialBuffer map[UnixNanoTime]Sensordata
|
||||
//bufferSize int
|
||||
mutex *sync.Mutex
|
||||
updateTicker *time.Ticker
|
||||
// should run concurrently
|
||||
//
|
||||
// Methods:
|
||||
// pushSensordata(Sensordata), remove oldest if larger than bufferSize
|
||||
// refreshDelay()
|
||||
// Schedule()
|
||||
}
|
||||
|
||||
func (p *pipeline) scheduleSynchronizer() {
|
||||
log.Println("synchronizer: started")
|
||||
for {
|
||||
<-p.syn.updateTicker.C
|
||||
err := p.refreshDelay()
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pipeline) refreshDelay() error {
|
||||
log.Println("refreshing delay....")
|
||||
fmt.Println("Delay TCP/SERIAL", p.syn.tcpSerialDelayMs)
|
||||
p.agr.serialMutex.Lock()
|
||||
p.agr.tcpMutex.Lock()
|
||||
tcpTime := time.Unix(0, p.agr.tcpSensorData.Timestamp)
|
||||
serTime := time.Unix(0, p.agr.serialSensorData.Timestamp)
|
||||
p.agr.serialMutex.Unlock()
|
||||
p.agr.tcpMutex.Unlock()
|
||||
if tcpTime.UnixNano() == 0 || serTime.UnixNano() == 0 {
|
||||
return errors.New("no sync possible. no data to compare")
|
||||
}
|
||||
log.Println("TCP", tcpTime.String())
|
||||
log.Println("SER", serTime.String())
|
||||
log.Println("Difference", tcpTime.Sub(serTime).Milliseconds())
|
||||
delay := tcpTime.Sub(serTime).Milliseconds()
|
||||
p.syn.tcpSerialDelayMs += delay
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *pipeline) Process(data *Sensordata) error {
|
||||
if data == nil {
|
||||
return errors.New("nil processing not allowed")
|
||||
}
|
||||
//log.Println(string(data.SourceId))
|
||||
switch data.SourceId {
|
||||
case SOURCE_TCP:
|
||||
go p.pushTcpDataToBuffer(*data)
|
||||
case SOURCE_SERIAL:
|
||||
go p.pushSerialDataToBuffer(*data)
|
||||
default:
|
||||
return errors.New("invalid data source")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *pipeline) pushTcpDataToBuffer(data Sensordata) {
|
||||
if p.syn.tcpSerialDelayMs > 0 {
|
||||
time.Sleep(time.Duration(p.syn.tcpSerialDelayMs) * time.Millisecond)
|
||||
}
|
||||
p.agr.tcpMutex.Lock()
|
||||
p.agr.tcpSensorData = p.agr.tcpSensorData.Consolidate2(data)
|
||||
p.agr.tcpMutex.Unlock()
|
||||
}
|
||||
func (p *pipeline) pushSerialDataToBuffer(data Sensordata) {
|
||||
if p.syn.tcpSerialDelayMs < 0 {
|
||||
time.Sleep(time.Duration(-p.syn.tcpSerialDelayMs) * time.Millisecond)
|
||||
}
|
||||
p.agr.serialMutex.Lock()
|
||||
p.agr.serialSensorData = p.agr.serialSensorData.Consolidate2(data)
|
||||
p.agr.serialMutex.Unlock()
|
||||
}
|
||||
@ -1,46 +0,0 @@
|
||||
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
|
||||
}
|
||||
5
go.mod
5
go.mod
@ -3,11 +3,10 @@ module git.timovolkmann.de/gyrogpsc
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
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/m7shapan/njson v1.0.1
|
||||
github.com/tidwall/gjson v1.6.0
|
||||
github.com/tidwall/pretty v1.0.2
|
||||
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
|
||||
)
|
||||
|
||||
39
go.sum
39
go.sum
@ -1,50 +1,33 @@
|
||||
github.com/creack/goselect v0.1.1 h1:tiSSgKE1eJtxs1h/VgGQWuXUP0YS4CDIFMp6vaI1ls0=
|
||||
github.com/creack/goselect v0.1.1/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||
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/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/m7shapan/njson v1.0.1 h1:s+odQrPkzcCCGRTp46cD0XCVYN3pvdoaVwbFVmjAvys=
|
||||
github.com/m7shapan/njson v1.0.1/go.mod h1:4sidL3oRZO1KV5FkclRBPI7nqFzlIq3BwdxHRMlOa9U=
|
||||
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/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/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
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/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/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=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
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/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-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
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-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-20190412213103-97732733099d/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-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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
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-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
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/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.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
132
net/net.go
132
net/net.go
@ -1,132 +0,0 @@
|
||||
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)
|
||||
http.Handle("/static/", http.StripPrefix("/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.
|
||||
}
|
||||
}
|
||||
@ -1,124 +0,0 @@
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
||||
@ -63,4 +63,4 @@
|
||||
-0.006618400104343891
|
||||
],
|
||||
"tmd3702_proximity proximity sensor": [5, 0, 0]
|
||||
}
|
||||
}
|
||||
869
static/iphone.json
Normal file
869
static/iphone.json
Normal file
@ -0,0 +1,869 @@
|
||||
[
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.037598",
|
||||
"accelerometerAccelerationY" : "-0.007950",
|
||||
"accelerometerAccelerationZ" : "-1.003952",
|
||||
"accelerometerTimestamp_sinceReboot" : "77700.804899",
|
||||
"avAudioRecorderAveragePower" : "-34.990307",
|
||||
"avAudioRecorderPeakPower" : "-30.574509",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"gyroRotationX" : "0.008506",
|
||||
"gyroRotationY" : "-0.076335",
|
||||
"gyroRotationZ" : "0.000154",
|
||||
"gyroTimestamp_sinceReboot" : "77700.794635",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationHeadingAccuracy" : "14.876174",
|
||||
"locationHeadingTimestamp_since1970" : "1607291137.949005",
|
||||
"locationHeadingX" : "-36.616150",
|
||||
"locationHeadingY" : "-2.895218",
|
||||
"locationHeadingZ" : "-25.625000",
|
||||
"locationMagneticHeading" : "85.920738",
|
||||
"locationTrueHeading" : "89.001564",
|
||||
"loggingTime" : "2020-12-06 22:45:37.964 +0100",
|
||||
"logSampleNr" : "765",
|
||||
"magnetometerTimestamp_sinceReboot" : "77700.802641",
|
||||
"magnetometerX" : "187.223969",
|
||||
"magnetometerY" : "188.439392",
|
||||
"magnetometerZ" : "-710.010864"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.036438",
|
||||
"accelerometerAccelerationY" : "-0.008789",
|
||||
"accelerometerAccelerationZ" : "-1.003464",
|
||||
"accelerometerTimestamp_sinceReboot" : "77700.821012",
|
||||
"avAudioRecorderAveragePower" : "-35.768673",
|
||||
"avAudioRecorderPeakPower" : "-30.574509",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationHeadingAccuracy" : "14.876176",
|
||||
"locationHeadingTimestamp_since1970" : "1607291137.968956",
|
||||
"locationHeadingX" : "-36.500809",
|
||||
"locationHeadingY" : "-2.983276",
|
||||
"locationHeadingZ" : "-25.554626",
|
||||
"locationMagneticHeading" : "85.920799",
|
||||
"locationTrueHeading" : "89.001625",
|
||||
"loggingTime" : "2020-12-06 22:45:37.989 +0100",
|
||||
"logSampleNr" : "766",
|
||||
"motionAttitudeReferenceFrame" : "XTrueNorthZVertical",
|
||||
"motionGravityX" : "0.034999",
|
||||
"motionGravityY" : "-0.009051",
|
||||
"motionGravityZ" : "-0.999346",
|
||||
"motionMagneticFieldCalibrationAccuracy" : "2.000000",
|
||||
"motionMagneticFieldX" : "-36.500809",
|
||||
"motionMagneticFieldY" : "-2.983276",
|
||||
"motionMagneticFieldZ" : "-25.554626",
|
||||
"motionPitch" : "0.009051",
|
||||
"motionQuaternionW" : "-0.008792",
|
||||
"motionQuaternionX" : "-0.017541",
|
||||
"motionQuaternionY" : "0.004372",
|
||||
"motionQuaternionZ" : "0.999798",
|
||||
"motionRoll" : "0.035007",
|
||||
"motionRotationRateX" : "0.002088",
|
||||
"motionRotationRateY" : "-0.004357",
|
||||
"motionRotationRateZ" : "-0.000906",
|
||||
"motionTimestamp_sinceReboot" : "77700.804614",
|
||||
"motionUserAccelerationX" : "0.002599",
|
||||
"motionUserAccelerationY" : "0.001101",
|
||||
"motionUserAccelerationZ" : "-0.004606",
|
||||
"motionYaw" : "-3.124165"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.033234",
|
||||
"accelerometerAccelerationY" : "-0.008926",
|
||||
"accelerometerAccelerationZ" : "-1.002014",
|
||||
"accelerometerTimestamp_sinceReboot" : "77700.837125",
|
||||
"avAudioRecorderAveragePower" : "-35.768673",
|
||||
"avAudioRecorderPeakPower" : "-30.574509",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"gyroRotationX" : "0.008186",
|
||||
"gyroRotationY" : "-0.076672",
|
||||
"gyroRotationZ" : "0.000862",
|
||||
"gyroTimestamp_sinceReboot" : "77700.824603",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationHeadingAccuracy" : "14.876178",
|
||||
"locationHeadingTimestamp_since1970" : "1607291137.989421",
|
||||
"locationHeadingX" : "-36.537552",
|
||||
"locationHeadingY" : "-2.889069",
|
||||
"locationHeadingZ" : "-25.606628",
|
||||
"locationMagneticHeading" : "85.920822",
|
||||
"locationTrueHeading" : "89.001648",
|
||||
"loggingTime" : "2020-12-06 22:45:37.996 +0100",
|
||||
"logSampleNr" : "767"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.034439",
|
||||
"accelerometerAccelerationY" : "-0.009415",
|
||||
"accelerometerAccelerationZ" : "-1.006668",
|
||||
"accelerometerTimestamp_sinceReboot" : "77700.853239",
|
||||
"avAudioRecorderAveragePower" : "-31.989109",
|
||||
"avAudioRecorderPeakPower" : "-30.574509",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationHeadingAccuracy" : "14.876178",
|
||||
"locationHeadingTimestamp_since1970" : "1607291138.008792",
|
||||
"locationHeadingX" : "-36.428513",
|
||||
"locationHeadingY" : "-2.911438",
|
||||
"locationHeadingZ" : "-25.462769",
|
||||
"locationMagneticHeading" : "85.921715",
|
||||
"locationTrueHeading" : "89.002541",
|
||||
"loggingTime" : "2020-12-06 22:45:38.012 +0100",
|
||||
"logSampleNr" : "768",
|
||||
"motionAttitudeReferenceFrame" : "XTrueNorthZVertical",
|
||||
"motionGravityX" : "0.034996",
|
||||
"motionGravityY" : "-0.009039",
|
||||
"motionGravityZ" : "-0.999347",
|
||||
"motionMagneticFieldCalibrationAccuracy" : "2.000000",
|
||||
"motionMagneticFieldX" : "-36.537552",
|
||||
"motionMagneticFieldY" : "-2.889069",
|
||||
"motionMagneticFieldZ" : "-25.606628",
|
||||
"motionPitch" : "0.009039",
|
||||
"motionQuaternionW" : "-0.008788",
|
||||
"motionQuaternionX" : "-0.017540",
|
||||
"motionQuaternionY" : "0.004366",
|
||||
"motionQuaternionZ" : "0.999798",
|
||||
"motionRoll" : "0.035005",
|
||||
"motionRotationRateX" : "0.000459",
|
||||
"motionRotationRateY" : "-0.000712",
|
||||
"motionRotationRateZ" : "-0.001314",
|
||||
"motionTimestamp_sinceReboot" : "77700.834613",
|
||||
"motionUserAccelerationX" : "-0.000923",
|
||||
"motionUserAccelerationY" : "0.000250",
|
||||
"motionUserAccelerationZ" : "-0.003110",
|
||||
"motionYaw" : "-3.124172"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.035385",
|
||||
"accelerometerAccelerationY" : "-0.012100",
|
||||
"accelerometerAccelerationZ" : "-1.011292",
|
||||
"accelerometerTimestamp_sinceReboot" : "77700.869321",
|
||||
"avAudioRecorderAveragePower" : "-31.288141",
|
||||
"avAudioRecorderPeakPower" : "-30.269579",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"gyroRotationX" : "0.010996",
|
||||
"gyroRotationY" : "-0.081939",
|
||||
"gyroRotationZ" : "0.002051",
|
||||
"gyroTimestamp_sinceReboot" : "77700.854571",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"loggingTime" : "2020-12-06 22:45:38.029 +0100",
|
||||
"logSampleNr" : "769",
|
||||
"magnetometerTimestamp_sinceReboot" : "77700.860777",
|
||||
"magnetometerX" : "187.028076",
|
||||
"magnetometerY" : "188.409332",
|
||||
"magnetometerZ" : "-709.159546"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.035950",
|
||||
"accelerometerAccelerationY" : "-0.011780",
|
||||
"accelerometerAccelerationZ" : "-1.006134",
|
||||
"accelerometerTimestamp_sinceReboot" : "77700.885435",
|
||||
"avAudioRecorderAveragePower" : "-32.153595",
|
||||
"avAudioRecorderPeakPower" : "-29.939217",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationHeadingAccuracy" : "14.876180",
|
||||
"locationHeadingTimestamp_since1970" : "1607291138.029312",
|
||||
"locationHeadingX" : "-36.654816",
|
||||
"locationHeadingY" : "-3.019150",
|
||||
"locationHeadingZ" : "-24.858765",
|
||||
"locationMagneticHeading" : "85.921791",
|
||||
"locationTrueHeading" : "89.002617",
|
||||
"loggingTime" : "2020-12-06 22:45:38.047 +0100",
|
||||
"logSampleNr" : "770",
|
||||
"motionAttitudeReferenceFrame" : "XTrueNorthZVertical",
|
||||
"motionGravityX" : "0.034864",
|
||||
"motionGravityY" : "-0.009091",
|
||||
"motionGravityZ" : "-0.999351",
|
||||
"motionMagneticFieldCalibrationAccuracy" : "2.000000",
|
||||
"motionMagneticFieldX" : "-36.654816",
|
||||
"motionMagneticFieldY" : "-3.019150",
|
||||
"motionMagneticFieldZ" : "-24.858765",
|
||||
"motionPitch" : "0.009091",
|
||||
"motionQuaternionW" : "-0.008783",
|
||||
"motionQuaternionX" : "-0.017474",
|
||||
"motionQuaternionY" : "0.004393",
|
||||
"motionQuaternionZ" : "0.999799",
|
||||
"motionRoll" : "0.034872",
|
||||
"motionRotationRateX" : "0.000922",
|
||||
"motionRotationRateY" : "-0.000872",
|
||||
"motionRotationRateZ" : "-0.000288",
|
||||
"motionTimestamp_sinceReboot" : "77700.864581",
|
||||
"motionUserAccelerationX" : "0.001284",
|
||||
"motionUserAccelerationY" : "-0.001514",
|
||||
"motionUserAccelerationZ" : "-0.011895",
|
||||
"motionYaw" : "-3.124182"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.035431",
|
||||
"accelerometerAccelerationY" : "-0.008698",
|
||||
"accelerometerAccelerationZ" : "-1.001877",
|
||||
"accelerometerTimestamp_sinceReboot" : "77700.901548",
|
||||
"avAudioRecorderAveragePower" : "-32.153595",
|
||||
"avAudioRecorderPeakPower" : "-29.939217",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"gyroRotationX" : "0.005874",
|
||||
"gyroRotationY" : "-0.076437",
|
||||
"gyroRotationZ" : "0.000249",
|
||||
"gyroTimestamp_sinceReboot" : "77700.884570",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationAltitude" : "187.182343",
|
||||
"locationCourse" : "-1.000000",
|
||||
"locationFloor" : "-9999",
|
||||
"locationHeadingAccuracy" : "14.876182",
|
||||
"locationHeadingTimestamp_since1970" : "1607291138.049074",
|
||||
"locationHeadingX" : "-36.686508",
|
||||
"locationHeadingY" : "-3.035675",
|
||||
"locationHeadingZ" : "-24.890198",
|
||||
"locationHorizontalAccuracy" : "30.000000",
|
||||
"locationLatitude" : "49.066370",
|
||||
"locationLongitude" : "9.135756",
|
||||
"locationMagneticHeading" : "85.922256",
|
||||
"locationSpeed" : "0.000000",
|
||||
"locationTimestamp_since1970" : "1607291137.995236",
|
||||
"locationTrueHeading" : "89.003082",
|
||||
"locationVerticalAccuracy" : "4.000000",
|
||||
"loggingTime" : "2020-12-06 22:45:38.061 +0100",
|
||||
"logSampleNr" : "771",
|
||||
"motionAttitudeReferenceFrame" : "XTrueNorthZVertical",
|
||||
"motionGravityX" : "0.034944",
|
||||
"motionGravityY" : "-0.009061",
|
||||
"motionGravityZ" : "-0.999348",
|
||||
"motionMagneticFieldCalibrationAccuracy" : "2.000000",
|
||||
"motionMagneticFieldX" : "-36.686508",
|
||||
"motionMagneticFieldY" : "-3.035675",
|
||||
"motionMagneticFieldZ" : "-24.890198",
|
||||
"motionPitch" : "0.009061",
|
||||
"motionQuaternionW" : "-0.008780",
|
||||
"motionQuaternionX" : "-0.017514",
|
||||
"motionQuaternionY" : "0.004377",
|
||||
"motionQuaternionZ" : "0.999799",
|
||||
"motionRoll" : "0.034952",
|
||||
"motionRotationRateX" : "-0.001064",
|
||||
"motionRotationRateY" : "-0.001599",
|
||||
"motionRotationRateZ" : "0.000173",
|
||||
"motionTimestamp_sinceReboot" : "77700.894549",
|
||||
"motionUserAccelerationX" : "-0.000566",
|
||||
"motionUserAccelerationY" : "-0.000552",
|
||||
"motionUserAccelerationZ" : "-0.007701",
|
||||
"motionYaw" : "-3.124187"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.033325",
|
||||
"accelerometerAccelerationY" : "-0.009155",
|
||||
"accelerometerAccelerationZ" : "-1.004761",
|
||||
"accelerometerTimestamp_sinceReboot" : "77700.917661",
|
||||
"avAudioRecorderAveragePower" : "-32.501255",
|
||||
"avAudioRecorderPeakPower" : "-29.852339",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationHeadingAccuracy" : "14.876183",
|
||||
"locationHeadingTimestamp_since1970" : "1607291138.068919",
|
||||
"locationHeadingX" : "-36.387695",
|
||||
"locationHeadingY" : "-2.955109",
|
||||
"locationHeadingZ" : "-25.351074",
|
||||
"locationMagneticHeading" : "85.922218",
|
||||
"locationTrueHeading" : "89.003044",
|
||||
"loggingTime" : "2020-12-06 22:45:38.077 +0100",
|
||||
"logSampleNr" : "772"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.035431",
|
||||
"accelerometerAccelerationY" : "-0.008286",
|
||||
"accelerometerAccelerationZ" : "-1.005096",
|
||||
"accelerometerTimestamp_sinceReboot" : "77700.933775",
|
||||
"avAudioRecorderAveragePower" : "-33.457474",
|
||||
"avAudioRecorderPeakPower" : "-29.852339",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"gyroRotationX" : "0.004643",
|
||||
"gyroRotationY" : "-0.075107",
|
||||
"gyroRotationZ" : "0.001784",
|
||||
"gyroTimestamp_sinceReboot" : "77700.914538",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationHeadingAccuracy" : "14.876183",
|
||||
"locationHeadingTimestamp_since1970" : "1607291138.088690",
|
||||
"locationHeadingX" : "-36.463043",
|
||||
"locationHeadingY" : "-2.722488",
|
||||
"locationHeadingZ" : "-25.380981",
|
||||
"locationMagneticHeading" : "85.921844",
|
||||
"locationTrueHeading" : "89.002670",
|
||||
"loggingTime" : "2020-12-06 22:45:38.094 +0100",
|
||||
"logSampleNr" : "773",
|
||||
"magnetometerTimestamp_sinceReboot" : "77700.918913",
|
||||
"magnetometerX" : "187.101776",
|
||||
"magnetometerY" : "188.768005",
|
||||
"magnetometerZ" : "-709.771484",
|
||||
"motionAttitudeReferenceFrame" : "XTrueNorthZVertical",
|
||||
"motionGravityX" : "0.034961",
|
||||
"motionGravityY" : "-0.009001",
|
||||
"motionGravityZ" : "-0.999348",
|
||||
"motionMagneticFieldCalibrationAccuracy" : "2.000000",
|
||||
"motionMagneticFieldX" : "-36.463043",
|
||||
"motionMagneticFieldY" : "-2.722488",
|
||||
"motionMagneticFieldZ" : "-25.380981",
|
||||
"motionPitch" : "0.009001",
|
||||
"motionQuaternionW" : "-0.008782",
|
||||
"motionQuaternionX" : "-0.017522",
|
||||
"motionQuaternionY" : "0.004348",
|
||||
"motionQuaternionZ" : "0.999798",
|
||||
"motionRoll" : "0.034970",
|
||||
"motionRotationRateX" : "-0.003020",
|
||||
"motionRotationRateY" : "0.004743",
|
||||
"motionRotationRateZ" : "0.000997",
|
||||
"motionTimestamp_sinceReboot" : "77700.924548",
|
||||
"motionUserAccelerationX" : "0.001217",
|
||||
"motionUserAccelerationY" : "-0.000520",
|
||||
"motionUserAccelerationZ" : "-0.003139",
|
||||
"motionYaw" : "-3.124183"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.035904",
|
||||
"accelerometerAccelerationY" : "-0.009094",
|
||||
"accelerometerAccelerationZ" : "-1.001312",
|
||||
"accelerometerTimestamp_sinceReboot" : "77700.949857",
|
||||
"avAudioRecorderAveragePower" : "-33.457474",
|
||||
"avAudioRecorderPeakPower" : "-29.852339",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"gyroRotationX" : "0.006907",
|
||||
"gyroRotationY" : "-0.079628",
|
||||
"gyroRotationZ" : "0.000950",
|
||||
"gyroTimestamp_sinceReboot" : "77700.944507",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"loggingTime" : "2020-12-06 22:45:38.109 +0100",
|
||||
"logSampleNr" : "774"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.036209",
|
||||
"accelerometerAccelerationY" : "-0.010406",
|
||||
"accelerometerAccelerationZ" : "-1.005539",
|
||||
"accelerometerTimestamp_sinceReboot" : "77700.965971",
|
||||
"avAudioRecorderAveragePower" : "-33.588783",
|
||||
"avAudioRecorderPeakPower" : "-29.852339",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationHeadingAccuracy" : "14.876184",
|
||||
"locationHeadingTimestamp_since1970" : "1607291138.108779",
|
||||
"locationHeadingX" : "-36.467972",
|
||||
"locationHeadingY" : "-2.907425",
|
||||
"locationHeadingZ" : "-25.277100",
|
||||
"locationMagneticHeading" : "85.922852",
|
||||
"locationTrueHeading" : "89.003677",
|
||||
"loggingTime" : "2020-12-06 22:45:38.125 +0100",
|
||||
"logSampleNr" : "775",
|
||||
"motionAttitudeReferenceFrame" : "XTrueNorthZVertical",
|
||||
"motionGravityX" : "0.034963",
|
||||
"motionGravityY" : "-0.009011",
|
||||
"motionGravityZ" : "-0.999348",
|
||||
"motionMagneticFieldCalibrationAccuracy" : "2.000000",
|
||||
"motionMagneticFieldX" : "-36.392593",
|
||||
"motionMagneticFieldY" : "-3.084808",
|
||||
"motionMagneticFieldZ" : "-25.575867",
|
||||
"motionPitch" : "0.009012",
|
||||
"motionQuaternionW" : "-0.008775",
|
||||
"motionQuaternionX" : "-0.017523",
|
||||
"motionQuaternionY" : "0.004353",
|
||||
"motionQuaternionZ" : "0.999799",
|
||||
"motionRoll" : "0.034972",
|
||||
"motionRotationRateX" : "-0.000240",
|
||||
"motionRotationRateY" : "-0.000722",
|
||||
"motionRotationRateZ" : "0.001070",
|
||||
"motionTimestamp_sinceReboot" : "77700.954516",
|
||||
"motionUserAccelerationX" : "0.000376",
|
||||
"motionUserAccelerationY" : "-0.001273",
|
||||
"motionUserAccelerationZ" : "-0.004177",
|
||||
"motionYaw" : "-3.124197"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.037720",
|
||||
"accelerometerAccelerationY" : "-0.010132",
|
||||
"accelerometerAccelerationZ" : "-1.008987",
|
||||
"accelerometerTimestamp_sinceReboot" : "77700.982084",
|
||||
"avAudioRecorderAveragePower" : "-34.231152",
|
||||
"avAudioRecorderPeakPower" : "-29.852339",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"gyroRotationX" : "0.004129",
|
||||
"gyroRotationY" : "-0.077557",
|
||||
"gyroRotationZ" : "-0.000793",
|
||||
"gyroTimestamp_sinceReboot" : "77700.974505",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationHeadingAccuracy" : "14.876186",
|
||||
"locationHeadingTimestamp_since1970" : "1607291138.128763",
|
||||
"locationHeadingX" : "-36.392593",
|
||||
"locationHeadingY" : "-3.084808",
|
||||
"locationHeadingZ" : "-25.575867",
|
||||
"locationMagneticHeading" : "85.922737",
|
||||
"locationTrueHeading" : "89.003563",
|
||||
"loggingTime" : "2020-12-06 22:45:38.141 +0100",
|
||||
"logSampleNr" : "776",
|
||||
"magnetometerTimestamp_sinceReboot" : "77700.977079",
|
||||
"magnetometerX" : "186.895142",
|
||||
"magnetometerY" : "188.252991",
|
||||
"magnetometerZ" : "-710.194702"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.036057",
|
||||
"accelerometerAccelerationY" : "-0.008194",
|
||||
"accelerometerAccelerationZ" : "-1.002792",
|
||||
"accelerometerTimestamp_sinceReboot" : "77700.998197",
|
||||
"avAudioRecorderAveragePower" : "-34.738995",
|
||||
"avAudioRecorderPeakPower" : "-29.852339",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationHeadingAccuracy" : "14.876188",
|
||||
"locationHeadingTimestamp_since1970" : "1607291138.148931",
|
||||
"locationHeadingX" : "-36.706497",
|
||||
"locationHeadingY" : "-3.118759",
|
||||
"locationHeadingZ" : "-25.621033",
|
||||
"locationMagneticHeading" : "85.923042",
|
||||
"locationTrueHeading" : "89.003868",
|
||||
"loggingTime" : "2020-12-06 22:45:38.168 +0100",
|
||||
"logSampleNr" : "777",
|
||||
"motionAttitudeReferenceFrame" : "XTrueNorthZVertical",
|
||||
"motionGravityX" : "0.034977",
|
||||
"motionGravityY" : "-0.009047",
|
||||
"motionGravityZ" : "-0.999347",
|
||||
"motionMagneticFieldCalibrationAccuracy" : "2.000000",
|
||||
"motionMagneticFieldX" : "-36.706497",
|
||||
"motionMagneticFieldY" : "-3.118759",
|
||||
"motionMagneticFieldZ" : "-25.621033",
|
||||
"motionPitch" : "0.009047",
|
||||
"motionQuaternionW" : "-0.008772",
|
||||
"motionQuaternionX" : "-0.017530",
|
||||
"motionQuaternionY" : "0.004370",
|
||||
"motionQuaternionZ" : "0.999798",
|
||||
"motionRoll" : "0.034985",
|
||||
"motionRotationRateX" : "0.000625",
|
||||
"motionRotationRateY" : "-0.000442",
|
||||
"motionRotationRateZ" : "0.000817",
|
||||
"motionTimestamp_sinceReboot" : "77700.984485",
|
||||
"motionUserAccelerationX" : "0.001827",
|
||||
"motionUserAccelerationY" : "-0.000368",
|
||||
"motionUserAccelerationZ" : "-0.007046",
|
||||
"motionYaw" : "-3.124204"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.034225",
|
||||
"accelerometerAccelerationY" : "-0.008728",
|
||||
"accelerometerAccelerationZ" : "-1.000931",
|
||||
"accelerometerTimestamp_sinceReboot" : "77701.014310",
|
||||
"avAudioRecorderAveragePower" : "-34.738995",
|
||||
"avAudioRecorderPeakPower" : "-29.852339",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"gyroRotationX" : "0.003781",
|
||||
"gyroRotationY" : "-0.076643",
|
||||
"gyroRotationZ" : "0.000894",
|
||||
"gyroTimestamp_sinceReboot" : "77701.004474",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationHeadingAccuracy" : "14.876190",
|
||||
"locationHeadingTimestamp_since1970" : "1607291138.168952",
|
||||
"locationHeadingX" : "-36.616852",
|
||||
"locationHeadingY" : "-2.912506",
|
||||
"locationHeadingZ" : "-25.239990",
|
||||
"locationMagneticHeading" : "85.923080",
|
||||
"locationTrueHeading" : "89.003906",
|
||||
"loggingTime" : "2020-12-06 22:45:38.173 +0100",
|
||||
"logSampleNr" : "778"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.033676",
|
||||
"accelerometerAccelerationY" : "-0.007309",
|
||||
"accelerometerAccelerationZ" : "-1.001099",
|
||||
"accelerometerTimestamp_sinceReboot" : "77701.030424",
|
||||
"avAudioRecorderAveragePower" : "-35.218269",
|
||||
"avAudioRecorderPeakPower" : "-29.852339",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"loggingTime" : "2020-12-06 22:45:38.189 +0100",
|
||||
"logSampleNr" : "779",
|
||||
"motionAttitudeReferenceFrame" : "XTrueNorthZVertical",
|
||||
"motionGravityX" : "0.035004",
|
||||
"motionGravityY" : "-0.008995",
|
||||
"motionGravityZ" : "-0.999347",
|
||||
"motionMagneticFieldCalibrationAccuracy" : "2.000000",
|
||||
"motionMagneticFieldX" : "-36.715759",
|
||||
"motionMagneticFieldY" : "-2.925949",
|
||||
"motionMagneticFieldZ" : "-25.069214",
|
||||
"motionPitch" : "0.008995",
|
||||
"motionQuaternionW" : "-0.008769",
|
||||
"motionQuaternionX" : "-0.017544",
|
||||
"motionQuaternionY" : "0.004344",
|
||||
"motionQuaternionZ" : "0.999798",
|
||||
"motionRoll" : "0.035013",
|
||||
"motionRotationRateX" : "-0.003867",
|
||||
"motionRotationRateY" : "0.001772",
|
||||
"motionRotationRateZ" : "0.000104",
|
||||
"motionTimestamp_sinceReboot" : "77701.014453",
|
||||
"motionUserAccelerationX" : "-0.000825",
|
||||
"motionUserAccelerationY" : "0.000175",
|
||||
"motionUserAccelerationZ" : "-0.000272",
|
||||
"motionYaw" : "-3.124209"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.037369",
|
||||
"accelerometerAccelerationY" : "-0.007599",
|
||||
"accelerometerAccelerationZ" : "-1.002563",
|
||||
"accelerometerTimestamp_sinceReboot" : "77701.046537",
|
||||
"avAudioRecorderAveragePower" : "-35.218269",
|
||||
"avAudioRecorderPeakPower" : "-29.852339",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"gyroRotationX" : "0.006077",
|
||||
"gyroRotationY" : "-0.077056",
|
||||
"gyroRotationZ" : "0.001649",
|
||||
"gyroTimestamp_sinceReboot" : "77701.034442",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationHeadingAccuracy" : "14.876190",
|
||||
"locationHeadingTimestamp_since1970" : "1607291138.188685",
|
||||
"locationHeadingX" : "-36.715759",
|
||||
"locationHeadingY" : "-2.925949",
|
||||
"locationHeadingZ" : "-25.069214",
|
||||
"locationMagneticHeading" : "85.923744",
|
||||
"locationTrueHeading" : "89.004570",
|
||||
"loggingTime" : "2020-12-06 22:45:38.206 +0100",
|
||||
"logSampleNr" : "780",
|
||||
"magnetometerTimestamp_sinceReboot" : "77701.035215",
|
||||
"magnetometerX" : "187.234955",
|
||||
"magnetometerY" : "188.355042",
|
||||
"magnetometerZ" : "-709.823547"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.035263",
|
||||
"accelerometerAccelerationY" : "-0.011368",
|
||||
"accelerometerAccelerationZ" : "-1.005341",
|
||||
"accelerometerTimestamp_sinceReboot" : "77701.062620",
|
||||
"avAudioRecorderAveragePower" : "-35.783520",
|
||||
"avAudioRecorderPeakPower" : "-29.852339",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationHeadingAccuracy" : "14.876191",
|
||||
"locationHeadingTimestamp_since1970" : "1607291138.208948",
|
||||
"locationHeadingX" : "-36.388031",
|
||||
"locationHeadingY" : "-3.009003",
|
||||
"locationHeadingZ" : "-25.307068",
|
||||
"locationMagneticHeading" : "85.924210",
|
||||
"locationTrueHeading" : "89.005035",
|
||||
"loggingTime" : "2020-12-06 22:45:38.228 +0100",
|
||||
"logSampleNr" : "781",
|
||||
"motionAttitudeReferenceFrame" : "XTrueNorthZVertical",
|
||||
"motionGravityX" : "0.035031",
|
||||
"motionGravityY" : "-0.009005",
|
||||
"motionGravityZ" : "-0.999346",
|
||||
"motionMagneticFieldCalibrationAccuracy" : "2.000000",
|
||||
"motionMagneticFieldX" : "-36.388031",
|
||||
"motionMagneticFieldY" : "-3.009003",
|
||||
"motionMagneticFieldZ" : "-25.307068",
|
||||
"motionPitch" : "0.009005",
|
||||
"motionQuaternionW" : "-0.008762",
|
||||
"motionQuaternionX" : "-0.017557",
|
||||
"motionQuaternionY" : "0.004350",
|
||||
"motionQuaternionZ" : "0.999798",
|
||||
"motionRoll" : "0.035040",
|
||||
"motionRotationRateX" : "-0.002688",
|
||||
"motionRotationRateY" : "0.001089",
|
||||
"motionRotationRateZ" : "0.000186",
|
||||
"motionTimestamp_sinceReboot" : "77701.044452",
|
||||
"motionUserAccelerationX" : "0.002337",
|
||||
"motionUserAccelerationY" : "0.001406",
|
||||
"motionUserAccelerationZ" : "-0.003218",
|
||||
"motionYaw" : "-3.124224"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.033936",
|
||||
"accelerometerAccelerationY" : "-0.008270",
|
||||
"accelerometerAccelerationZ" : "-1.008591",
|
||||
"accelerometerTimestamp_sinceReboot" : "77701.078733",
|
||||
"avAudioRecorderAveragePower" : "-35.894341",
|
||||
"avAudioRecorderPeakPower" : "-29.852339",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"gyroRotationX" : "0.006742",
|
||||
"gyroRotationY" : "-0.078071",
|
||||
"gyroRotationZ" : "0.000371",
|
||||
"gyroTimestamp_sinceReboot" : "77701.064441",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationHeadingAccuracy" : "14.876193",
|
||||
"locationHeadingTimestamp_since1970" : "1607291138.229093",
|
||||
"locationHeadingX" : "-36.477371",
|
||||
"locationHeadingY" : "-3.081924",
|
||||
"locationHeadingZ" : "-25.343933",
|
||||
"locationMagneticHeading" : "85.924126",
|
||||
"locationTrueHeading" : "89.004951",
|
||||
"loggingTime" : "2020-12-06 22:45:38.238 +0100",
|
||||
"logSampleNr" : "782"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.034683",
|
||||
"accelerometerAccelerationY" : "-0.010590",
|
||||
"accelerometerAccelerationZ" : "-1.008743",
|
||||
"accelerometerTimestamp_sinceReboot" : "77701.094846",
|
||||
"avAudioRecorderAveragePower" : "-36.771626",
|
||||
"avAudioRecorderPeakPower" : "-29.852339",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationHeadingAccuracy" : "14.876195",
|
||||
"locationHeadingTimestamp_since1970" : "1607291138.248836",
|
||||
"locationHeadingX" : "-36.430481",
|
||||
"locationHeadingY" : "-2.969254",
|
||||
"locationHeadingZ" : "-25.259521",
|
||||
"locationMagneticHeading" : "85.924248",
|
||||
"locationTrueHeading" : "89.005074",
|
||||
"loggingTime" : "2020-12-06 22:45:38.254 +0100",
|
||||
"logSampleNr" : "783",
|
||||
"magnetometerTimestamp_sinceReboot" : "77701.093351",
|
||||
"magnetometerX" : "186.871170",
|
||||
"magnetometerY" : "188.533890",
|
||||
"magnetometerZ" : "-709.817078",
|
||||
"motionAttitudeReferenceFrame" : "XTrueNorthZVertical",
|
||||
"motionGravityX" : "0.035061",
|
||||
"motionGravityY" : "-0.009031",
|
||||
"motionGravityZ" : "-0.999344",
|
||||
"motionMagneticFieldCalibrationAccuracy" : "2.000000",
|
||||
"motionMagneticFieldX" : "-36.430481",
|
||||
"motionMagneticFieldY" : "-2.969254",
|
||||
"motionMagneticFieldZ" : "-25.259521",
|
||||
"motionPitch" : "0.009031",
|
||||
"motionQuaternionW" : "-0.008761",
|
||||
"motionQuaternionX" : "-0.017572",
|
||||
"motionQuaternionY" : "0.004362",
|
||||
"motionQuaternionZ" : "0.999798",
|
||||
"motionRoll" : "0.035070",
|
||||
"motionRotationRateX" : "0.002348",
|
||||
"motionRotationRateY" : "0.000247",
|
||||
"motionRotationRateZ" : "0.000621",
|
||||
"motionTimestamp_sinceReboot" : "77701.074420",
|
||||
"motionUserAccelerationX" : "-0.000393",
|
||||
"motionUserAccelerationY" : "-0.000308",
|
||||
"motionUserAccelerationZ" : "-0.008239",
|
||||
"motionYaw" : "-3.124226"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.033768",
|
||||
"accelerometerAccelerationY" : "-0.008774",
|
||||
"accelerometerAccelerationZ" : "-1.005692",
|
||||
"accelerometerTimestamp_sinceReboot" : "77701.110960",
|
||||
"avAudioRecorderAveragePower" : "-36.771626",
|
||||
"avAudioRecorderPeakPower" : "-29.852339",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"gyroRotationX" : "0.002831",
|
||||
"gyroRotationY" : "-0.076265",
|
||||
"gyroRotationZ" : "0.001715",
|
||||
"gyroTimestamp_sinceReboot" : "77701.094409",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationHeadingAccuracy" : "14.876197",
|
||||
"locationHeadingTimestamp_since1970" : "1607291138.268665",
|
||||
"locationHeadingX" : "-36.766403",
|
||||
"locationHeadingY" : "-2.885361",
|
||||
"locationHeadingZ" : "-25.336365",
|
||||
"locationMagneticHeading" : "85.924141",
|
||||
"locationTrueHeading" : "89.004967",
|
||||
"loggingTime" : "2020-12-06 22:45:38.270 +0100",
|
||||
"logSampleNr" : "784",
|
||||
"motionAttitudeReferenceFrame" : "XTrueNorthZVertical",
|
||||
"motionGravityX" : "0.035022",
|
||||
"motionGravityY" : "-0.008936",
|
||||
"motionGravityZ" : "-0.999347",
|
||||
"motionMagneticFieldCalibrationAccuracy" : "2.000000",
|
||||
"motionMagneticFieldX" : "-36.766403",
|
||||
"motionMagneticFieldY" : "-2.885361",
|
||||
"motionMagneticFieldZ" : "-25.336365",
|
||||
"motionPitch" : "0.008936",
|
||||
"motionQuaternionW" : "-0.008761",
|
||||
"motionQuaternionX" : "-0.017552",
|
||||
"motionQuaternionY" : "0.004315",
|
||||
"motionQuaternionZ" : "0.999798",
|
||||
"motionRoll" : "0.035031",
|
||||
"motionRotationRateX" : "-0.001589",
|
||||
"motionRotationRateY" : "-0.001877",
|
||||
"motionRotationRateZ" : "-0.000561",
|
||||
"motionTimestamp_sinceReboot" : "77701.104388",
|
||||
"motionUserAccelerationX" : "0.000745",
|
||||
"motionUserAccelerationY" : "0.000620",
|
||||
"motionUserAccelerationZ" : "-0.007642",
|
||||
"motionYaw" : "-3.124223"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.035889",
|
||||
"accelerometerAccelerationY" : "-0.009491",
|
||||
"accelerometerAccelerationZ" : "-1.000381",
|
||||
"accelerometerTimestamp_sinceReboot" : "77701.127073",
|
||||
"avAudioRecorderAveragePower" : "-37.050854",
|
||||
"avAudioRecorderPeakPower" : "-29.852339",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"loggingTime" : "2020-12-06 22:45:38.290 +0100",
|
||||
"logSampleNr" : "785"
|
||||
},
|
||||
{
|
||||
"accelerometerAccelerationX" : "0.035278",
|
||||
"accelerometerAccelerationY" : "-0.008865",
|
||||
"accelerometerAccelerationZ" : "-1.004211",
|
||||
"accelerometerTimestamp_sinceReboot" : "77701.143186",
|
||||
"avAudioRecorderAveragePower" : "-37.257305",
|
||||
"avAudioRecorderPeakPower" : "-29.852339",
|
||||
"batteryLevel" : "0.660000",
|
||||
"batteryState" : "1",
|
||||
"deviceID" : "my_iOS_device",
|
||||
"deviceOrientation" : "5",
|
||||
"gyroRotationX" : "0.001609",
|
||||
"gyroRotationY" : "-0.076717",
|
||||
"gyroRotationZ" : "0.001673",
|
||||
"gyroTimestamp_sinceReboot" : "77701.124377",
|
||||
"identifierForVendor" : "1B07EE58-F14E-4E47-ABF8-7E919F119960",
|
||||
"IP_en0" : "10.41.8.38",
|
||||
"IP_pdp_ip0" : "100.78.225.228",
|
||||
"label" : "0",
|
||||
"locationHeadingAccuracy" : "14.876198",
|
||||
"locationHeadingTimestamp_since1970" : "1607291138.288638",
|
||||
"locationHeadingX" : "-36.884933",
|
||||
"locationHeadingY" : "-3.087875",
|
||||
"locationHeadingZ" : "-25.284058",
|
||||
"locationMagneticHeading" : "85.924454",
|
||||
"locationTrueHeading" : "89.005280",
|
||||
"loggingTime" : "2020-12-06 22:45:38.302 +0100",
|
||||
"logSampleNr" : "786",
|
||||
"motionAttitudeReferenceFrame" : "XTrueNorthZVertical",
|
||||
"motionGravityX" : "0.035028",
|
||||
"motionGravityY" : "-0.008846",
|
||||
"motionGravityZ" : "-0.999347",
|
||||
"motionMagneticFieldCalibrationAccuracy" : "2.000000",
|
||||
"motionMagneticFieldX" : "-36.644531",
|
||||
"motionMagneticFieldY" : "-2.917130",
|
||||
"motionMagneticFieldZ" : "-25.302368",
|
||||
"motionPitch" : "0.008846",
|
||||
"motionQuaternionW" : "-0.008759",
|
||||
"motionQuaternionX" : "-0.017555",
|
||||
"motionQuaternionY" : "0.004270",
|
||||
"motionQuaternionZ" : "0.999798",
|
||||
"motionRoll" : "0.035037",
|
||||
"motionRotationRateX" : "-0.003860",
|
||||
"motionRotationRateY" : "-0.000956",
|
||||
"motionRotationRateZ" : "-0.001445",
|
||||
"motionTimestamp_sinceReboot" : "77701.134387",
|
||||
"motionUserAccelerationX" : "0.002051",
|
||||
"motionUserAccelerationY" : "0.000881",
|
||||
"motionUserAccelerationZ" : "-0.002896",
|
||||
"motionYaw" : "-3.124227"
|
||||
}
|
||||
]
|
||||
@ -14,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
|
||||
@ -74,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. Skips NMEA.
|
||||
func (d *Decoder) Decode() (msg Message, err error) {
|
||||
// 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) {
|
||||
if !d.s.Scan() {
|
||||
if err = d.s.Err(); err == nil {
|
||||
err = io.EOF
|
||||
@ -85,11 +85,10 @@ func (d *Decoder) Decode() (msg Message, err error) {
|
||||
|
||||
switch d.s.Bytes()[0] {
|
||||
case '$':
|
||||
//fmt.Println("NMEA message: skipping!")
|
||||
return nil, err
|
||||
return nil, errors.New("NMEA not implemented")
|
||||
//return nmea.Decode(d.s.Bytes())
|
||||
case 0xB5:
|
||||
return DecodeUbx(d.s.Bytes())
|
||||
return decodeUbx(d.s.Bytes())
|
||||
}
|
||||
panic("impossible frame")
|
||||
}
|
||||
@ -99,7 +98,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)
|
||||
|
||||
@ -149,7 +148,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,21 @@
|
||||
package ublox
|
||||
|
||||
type Message interface {
|
||||
classID() uint16
|
||||
ClassID() uint16
|
||||
}
|
||||
|
||||
//type UbxMessage interface {
|
||||
// Timestamp() (time.Time, error)
|
||||
// Position() ([3]float64, error)
|
||||
// Orientation() ([3]float64, error)
|
||||
//}
|
||||
|
||||
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 +53,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 +83,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 +97,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
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user