From 1f5301f5de9c2e8d67cb4049b6dbaa6c963ce3e1 Mon Sep 17 00:00:00 2001 From: yannickulrich Date: Thu, 3 Nov 2022 19:09:06 +0000 Subject: [PATCH] Added Navigation service (#5) InfiniTime implements a [Navigation Service](https://github.com/InfiniTimeOrg/InfiniTime/blob/develop/doc/NavigationService.md). This pull request will add it to the go library by defining a function ```go func (i *Device) Navigation(flag string, narrative string, dist string, progress uint8) error { ... } ``` From the InfiniTime manual * `flag`: the graphic instruction as provided by [Pure Maps](https://github.com/rinigus/pure-maps/tree/master/qml/icons/navigation). A list of valid instruction icons can be found [here](https://github.com/rinigus/pure-maps/tree/master/qml/icons/navigation) * `narrative`: the instruction in words, eg. "At the roundabout take the first exit". * `dist`: a short string describing the distance to the upcoming instruction such as "50 m". * `progress`: the percent complete in a `uint8` Adding this to the `itd` daemon is straightforward ```patch diff --git a/api/types.go b/api/types.go index 281a85b..14c84de 100644 --- a/api/types.go +++ b/api/types.go @@ -22,6 +22,13 @@ type FwUpgradeData struct { Files []string } +type NavigationData struct { + Flag string + Narrative string + Dist string + Progress uint8 +} + type NotifyData struct { Title string Body string diff --git a/socket.go b/socket.go index 6fcba5c..91b37c0 100644 --- a/socket.go +++ b/socket.go @@ -204,6 +204,10 @@ func (i *ITD) Address(_ *server.Context) string { return i.dev.Address() } +func (i *ITD) Navigation(_ *server.Context, data api.NavigationData) error { + return i.dev.Navigation(data.Flag, data.Narrative, data.Dist, data.Progress) +} + func (i *ITD) Notify(_ *server.Context, data api.NotifyData) error { return i.dev.Notify(data.Title, data.Body) } ``` Co-authored-by: Yannick Ulrich Reviewed-on: https://gitea.arsenm.dev/Arsen6331/infinitime/pulls/5 Co-authored-by: yannickulrich Co-committed-by: yannickulrich --- README.md | 1 + infinitime.go | 16 +++++ navigation.go | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 navigation.go diff --git a/README.md b/README.md index 9a7c7fa..37210a7 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,7 @@ This library currently supports the following features: - Battery level - Music control - OTA firmware upgrades +- Navigation --- diff --git a/infinitime.go b/infinitime.go index d48e902..e234949 100644 --- a/infinitime.go +++ b/infinitime.go @@ -52,6 +52,10 @@ var charNames = map[string]string{ FSTransferChar: "Filesystem Transfer", FSVersionChar: "Filesystem Version", WeatherDataChar: "Weather Data", + NavFlagsChar: "Navigation Icon", + NavNarrativeChar:"Navigation Instruction", + NavManDistChar: "Navigation Distance to next event", + NavProgressChar: "Navigation Progress", } type Device struct { @@ -67,10 +71,13 @@ type Device struct { fsVersionChar *gatt.GattCharacteristic1 fsTransferChar *gatt.GattCharacteristic1 weatherDataChar *gatt.GattCharacteristic1 + weatherdataChar *gatt.GattCharacteristic1 notifEventCh chan uint8 notifEventDone bool Music MusicCtrl + Navigation NavigationCtrl DFU DFU + navigationEv NavigationEvent } var ( @@ -394,6 +401,14 @@ func (i *Device) resolveChars() error { charResolved := true // Set correct characteristics switch char.Properties.UUID { + case NavFlagsChar: + i.Navigation.flagsChar = char + case NavNarrativeChar: + i.Navigation.narrativeChar = char + case NavManDistChar: + i.Navigation.mandistChar = char + case NavProgressChar: + i.Navigation.progressChar = char case NewAlertChar: i.newAlertChar = char case NotifEventChar: @@ -723,6 +738,7 @@ func (i *Device) Notify(title, body string) error { ) } + // These constants represent the possible call statuses selected by the user const ( CallStatusDeclined uint8 = iota diff --git a/navigation.go b/navigation.go new file mode 100644 index 0000000..16e7da4 --- /dev/null +++ b/navigation.go @@ -0,0 +1,188 @@ +package infinitime + +import ( + "bytes" + "encoding/binary" + "errors" + "github.com/muka/go-bluetooth/bluez/profile/gatt" +) + +const ( + NavFlagsChar = "00010001-78fc-48fe-8e23-433b3a1942d0" + NavNarrativeChar= "00010002-78fc-48fe-8e23-433b3a1942d0" + NavManDistChar = "00010003-78fc-48fe-8e23-433b3a1942d0" + NavProgressChar = "00010004-78fc-48fe-8e23-433b3a1942d0" +) + +type NavigationCtrl struct { + flagsChar *gatt.GattCharacteristic1 + narrativeChar*gatt.GattCharacteristic1 + mandistChar *gatt.GattCharacteristic1 + progressChar *gatt.GattCharacteristic1 +} + +type NavFlag string +const ( + NavFlagArrive NavFlag = "arrive" + NavFlagArriveLeft NavFlag = "arrive-left" + NavFlagArriveRight NavFlag = "arrive-right" + NavFlagArriveStraight NavFlag = "arrive-straight" + NavFlagClose NavFlag = "close" + NavFlagContinue NavFlag = "continue" + NavFlagContinueLeft NavFlag = "continue-left" + NavFlagContinueRight NavFlag = "continue-right" + NavFlagContinueSlightLeft NavFlag = "continue-slight-left" + NavFlagContinueSlightRight NavFlag = "continue-slight-right" + NavFlagContinueStraight NavFlag = "continue-straight" + NavFlagContinueUturn NavFlag = "continue-uturn" + NavFlagDepart NavFlag = "depart" + NavFlagDepartLeft NavFlag = "depart-left" + NavFlagDepartRight NavFlag = "depart-right" + NavFlagDepartStraight NavFlag = "depart-straight" + NavFlagEndOfRoadLeft NavFlag = "end-of-road-left" + NavFlagEndOfRoadRight NavFlag = "end-of-road-right" + NavFlagFerry NavFlag = "ferry" + NavFlagFlag NavFlag = "flag" + NavFlagFork NavFlag = "fork" + NavFlagForkLeft NavFlag = "fork-left" + NavFlagForkRight NavFlag = "fork-right" + NavFlagForkSlightLeft NavFlag = "fork-slight-left" + NavFlagForkSlightRight NavFlag = "fork-slight-right" + NavFlagForkStraight NavFlag = "fork-straight" + NavFlagInvalid NavFlag = "invalid" + NavFlagInvalidLeft NavFlag = "invalid-left" + NavFlagInvalidRight NavFlag = "invalid-right" + NavFlagInvalidSlightLeft NavFlag = "invalid-slight-left" + NavFlagInvalidSlightRight NavFlag = "invalid-slight-right" + NavFlagInvalidStraight NavFlag = "invalid-straight" + NavFlagInvalidUturn NavFlag = "invalid-uturn" + NavFlagMergeLeft NavFlag = "merge-left" + NavFlagMergeRight NavFlag = "merge-right" + NavFlagMergeSlightLeft NavFlag = "merge-slight-left" + NavFlagMergeSlightRight NavFlag = "merge-slight-right" + NavFlagMergeStraight NavFlag = "merge-straight" + NavFlagNewNameLeft NavFlag = "new-name-left" + NavFlagNewNameRight NavFlag = "new-name-right" + NavFlagNewNameSharpLeft NavFlag = "new-name-sharp-left" + NavFlagNewNameSharpRight NavFlag = "new-name-sharp-right" + NavFlagNewNameSlightLeft NavFlag = "new-name-slight-left" + NavFlagNewNameSlightRight NavFlag = "new-name-slight-right" + NavFlagNewNameStraight NavFlag = "new-name-straight" + NavFlagNotificationLeft NavFlag = "notification-left" + NavFlagNotificationRight NavFlag = "notification-right" + NavFlagNotificationSharpLeft NavFlag = "notification-sharp-left" + NavFlagNotificationSharpRight NavFlag = "notification-sharp-right" + NavFlagNotificationSlightLeft NavFlag = "notification-slight-left" + NavFlagNotificationSlightRight NavFlag = "notification-slight-right" + NavFlagNotificationStraight NavFlag = "notification-straight" + NavFlagOffRampLeft NavFlag = "off-ramp-left" + NavFlagOffRampRight NavFlag = "off-ramp-right" + NavFlagOffRampSharpLeft NavFlag = "off-ramp-sharp-left" + NavFlagOffRampSharpRight NavFlag = "off-ramp-sharp-right" + NavFlagOffRampSlightLeft NavFlag = "off-ramp-slight-left" + NavFlagOffRampSlightRight NavFlag = "off-ramp-slight-right" + NavFlagOffRampStraight NavFlag = "off-ramp-straight" + NavFlagOnRampLeft NavFlag = "on-ramp-left" + NavFlagOnRampRight NavFlag = "on-ramp-right" + NavFlagOnRampSharpLeft NavFlag = "on-ramp-sharp-left" + NavFlagOnRampSharpRight NavFlag = "on-ramp-sharp-right" + NavFlagOnRampSlightLeft NavFlag = "on-ramp-slight-left" + NavFlagOnRampSlightRight NavFlag = "on-ramp-slight-right" + NavFlagOnRampStraight NavFlag = "on-ramp-straight" + NavFlagRotary NavFlag = "rotary" + NavFlagRotaryLeft NavFlag = "rotary-left" + NavFlagRotaryRight NavFlag = "rotary-right" + NavFlagRotarySharpLeft NavFlag = "rotary-sharp-left" + NavFlagRotarySharpRight NavFlag = "rotary-sharp-right" + NavFlagRotarySlightLeft NavFlag = "rotary-slight-left" + NavFlagRotarySlightRight NavFlag = "rotary-slight-right" + NavFlagRotaryStraight NavFlag = "rotary-straight" + NavFlagRoundabout NavFlag = "roundabout" + NavFlagRoundaboutLeft NavFlag = "roundabout-left" + NavFlagRoundaboutRight NavFlag = "roundabout-right" + NavFlagRoundaboutSharpLeft NavFlag = "roundabout-sharp-left" + NavFlagRoundaboutSharpRight NavFlag = "roundabout-sharp-right" + NavFlagRoundaboutSlightLeft NavFlag = "roundabout-slight-left" + NavFlagRoundaboutSlightRight NavFlag = "roundabout-slight-right" + NavFlagRoundaboutStraight NavFlag = "roundabout-straight" + NavFlagTurnLeft NavFlag = "turn-left" + NavFlagTurnRight NavFlag = "turn-right" + NavFlagTurnSharpLeft NavFlag = "turn-sharp-left" + NavFlagTurnSharpRight NavFlag = "turn-sharp-right" + NavFlagTurnSlightLeft NavFlag = "turn-slight-left" + NavFlagTurnSlightRight NavFlag = "turn-slight-right" + NavFlagTurnStright NavFlag = "turn-stright" + NavFlagUpdown NavFlag = "updown" + NavFlagUturn NavFlag = "uturn" +) + +type NavigationEvent struct { + Flag NavFlag + Narrative string + Dist string + Progress uint8 +} + +var ( + ErrNavProgress = errors.New("progress needs to between 0 and 100") + ErrNavInvalidFlag = errors.New("this flag is invalid") +) + +// Navigation sends a NavigationEvent to the watch +func (i *Device) SetNavigation(ev NavigationEvent) error { + if ev.Progress > 100 { + return ErrNavProgress + } + + if ev.Flag != i.navigationEv.Flag { + log.Debug().Str("func", "Navigation"). + Msg("Sending flag") + if err := i.checkStatus(i.Navigation.flagsChar, NavFlagsChar); err != nil { + return err + } + if err := i.Navigation.flagsChar.WriteValue([]byte(ev.Flag), nil); err != nil { + return err + } + i.navigationEv.Flag = ev.Flag + } + + if ev.Narrative != i.navigationEv.Narrative { + log.Debug().Str("func", "Navigation"). + Msg("Sending narrative") + if err := i.checkStatus(i.Navigation.narrativeChar, NavNarrativeChar); err != nil { + return err + } + if err := i.Navigation.narrativeChar.WriteValue([]byte(ev.Narrative), nil); err != nil { + return err + } + i.navigationEv.Narrative = ev.Narrative + } + + if ev.Dist != i.navigationEv.Dist { + log.Debug().Str("func", "Navigation"). + Msg("Sending mandist") + if err := i.checkStatus(i.Navigation.mandistChar, NavManDistChar); err != nil { + return err + } + if err := i.Navigation.mandistChar.WriteValue([]byte(ev.Dist), nil); err != nil { + return err + } + i.navigationEv.Dist = ev.Dist + } + + if ev.Progress != i.navigationEv.Progress { + log.Debug().Str("func", "Navigation"). + Msg("Sending progress") + if err := i.checkStatus(i.Navigation.progressChar, NavProgressChar); err != nil { + return err + } + buf := &bytes.Buffer{} + binary.Write(buf, binary.LittleEndian, ev.Progress) + if err := i.Navigation.progressChar.WriteValue(buf.Bytes(), nil); err != nil { + return err + } + i.navigationEv.Progress = ev.Progress + } + + return nil +}