Allow multiple call notification responses and improve error handling
This commit is contained in:
parent
9966880bc8
commit
58d5036f20
101
infinitime.go
101
infinitime.go
@ -42,13 +42,19 @@ type Device struct {
|
|||||||
heartRateChar *gatt.GattCharacteristic1
|
heartRateChar *gatt.GattCharacteristic1
|
||||||
fsVersionChar *gatt.GattCharacteristic1
|
fsVersionChar *gatt.GattCharacteristic1
|
||||||
fsTransferChar *gatt.GattCharacteristic1
|
fsTransferChar *gatt.GattCharacteristic1
|
||||||
|
notifEventCh chan uint8
|
||||||
|
notifEventDone bool
|
||||||
onReconnect func()
|
onReconnect func()
|
||||||
Music MusicCtrl
|
Music MusicCtrl
|
||||||
DFU DFU
|
DFU DFU
|
||||||
}
|
}
|
||||||
|
|
||||||
var ErrNoDevices = errors.New("no InfiniTime devices found")
|
var (
|
||||||
var ErrNotFound = errors.New("could not find any advertising InfiniTime devices")
|
ErrNoDevices = errors.New("no InfiniTime devices found")
|
||||||
|
ErrNotFound = errors.New("could not find any advertising InfiniTime devices")
|
||||||
|
ErrNotConnected = errors.New("not connected")
|
||||||
|
ErrCharNotAvail = errors.New("required characteristic is not available")
|
||||||
|
)
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
AttemptReconnect bool
|
AttemptReconnect bool
|
||||||
@ -332,8 +338,8 @@ func (i *Device) Address() string {
|
|||||||
|
|
||||||
// Version returns InfiniTime's reported firmware version string
|
// Version returns InfiniTime's reported firmware version string
|
||||||
func (i *Device) Version() (string, error) {
|
func (i *Device) Version() (string, error) {
|
||||||
if !i.device.Properties.Connected {
|
if err := i.checkStatus(i.fwVersionChar); err != nil {
|
||||||
return "", nil
|
return "", err
|
||||||
}
|
}
|
||||||
ver, err := i.fwVersionChar.ReadValue(nil)
|
ver, err := i.fwVersionChar.ReadValue(nil)
|
||||||
return string(ver), err
|
return string(ver), err
|
||||||
@ -341,8 +347,8 @@ func (i *Device) Version() (string, error) {
|
|||||||
|
|
||||||
// BatteryLevel gets the watch's battery level via the Battery Service
|
// BatteryLevel gets the watch's battery level via the Battery Service
|
||||||
func (i *Device) BatteryLevel() (uint8, error) {
|
func (i *Device) BatteryLevel() (uint8, error) {
|
||||||
if !i.device.Properties.Connected {
|
if err := i.checkStatus(i.battLevelChar); err != nil {
|
||||||
return 0, nil
|
return 0, err
|
||||||
}
|
}
|
||||||
battLevel, err := i.battLevelChar.ReadValue(nil)
|
battLevel, err := i.battLevelChar.ReadValue(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -352,8 +358,8 @@ func (i *Device) BatteryLevel() (uint8, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *Device) StepCount() (uint32, error) {
|
func (i *Device) StepCount() (uint32, error) {
|
||||||
if !i.device.Properties.Connected {
|
if err := i.checkStatus(i.stepCountChar); err != nil {
|
||||||
return 0, nil
|
return 0, err
|
||||||
}
|
}
|
||||||
stepCountData, err := i.stepCountChar.ReadValue(nil)
|
stepCountData, err := i.stepCountChar.ReadValue(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -370,8 +376,8 @@ type MotionValues struct {
|
|||||||
|
|
||||||
func (i *Device) Motion() (MotionValues, error) {
|
func (i *Device) Motion() (MotionValues, error) {
|
||||||
out := MotionValues{}
|
out := MotionValues{}
|
||||||
if !i.device.Properties.Connected {
|
if err := i.checkStatus(i.motionValChar); err != nil {
|
||||||
return out, nil
|
return out, err
|
||||||
}
|
}
|
||||||
motionVals, err := i.motionValChar.ReadValue(nil)
|
motionVals, err := i.motionValChar.ReadValue(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -386,8 +392,8 @@ func (i *Device) Motion() (MotionValues, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *Device) HeartRate() (uint8, error) {
|
func (i *Device) HeartRate() (uint8, error) {
|
||||||
if !i.device.Properties.Connected {
|
if err := i.checkStatus(i.heartRateChar); err != nil {
|
||||||
return 0, nil
|
return 0, err
|
||||||
}
|
}
|
||||||
heartRate, err := i.heartRateChar.ReadValue(nil)
|
heartRate, err := i.heartRateChar.ReadValue(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -397,8 +403,8 @@ func (i *Device) HeartRate() (uint8, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *Device) WatchHeartRate() (<-chan uint8, func(), error) {
|
func (i *Device) WatchHeartRate() (<-chan uint8, func(), error) {
|
||||||
if !i.device.Properties.Connected {
|
if err := i.checkStatus(i.heartRateChar); err != nil {
|
||||||
return make(<-chan uint8), nil, nil
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
// Start notifications on heart rate characteristic
|
// Start notifications on heart rate characteristic
|
||||||
err := i.heartRateChar.StartNotify()
|
err := i.heartRateChar.StartNotify()
|
||||||
@ -439,8 +445,8 @@ func (i *Device) WatchHeartRate() (<-chan uint8, func(), error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *Device) WatchBatteryLevel() (<-chan uint8, func(), error) {
|
func (i *Device) WatchBatteryLevel() (<-chan uint8, func(), error) {
|
||||||
if !i.device.Properties.Connected {
|
if err := i.checkStatus(i.battLevelChar); err != nil {
|
||||||
return make(<-chan uint8), nil, nil
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
// Start notifications on heart rate characteristic
|
// Start notifications on heart rate characteristic
|
||||||
err := i.battLevelChar.StartNotify()
|
err := i.battLevelChar.StartNotify()
|
||||||
@ -481,8 +487,8 @@ func (i *Device) WatchBatteryLevel() (<-chan uint8, func(), error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *Device) WatchStepCount() (<-chan uint32, func(), error) {
|
func (i *Device) WatchStepCount() (<-chan uint32, func(), error) {
|
||||||
if !i.device.Properties.Connected {
|
if err := i.checkStatus(i.stepCountChar); err != nil {
|
||||||
return make(<-chan uint32), nil, nil
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
// Start notifications on step count characteristic
|
// Start notifications on step count characteristic
|
||||||
err := i.stepCountChar.StartNotify()
|
err := i.stepCountChar.StartNotify()
|
||||||
@ -523,8 +529,8 @@ func (i *Device) WatchStepCount() (<-chan uint32, func(), error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *Device) WatchMotion() (<-chan MotionValues, func(), error) {
|
func (i *Device) WatchMotion() (<-chan MotionValues, func(), error) {
|
||||||
if !i.device.Properties.Connected {
|
if err := i.checkStatus(i.motionValChar); err != nil {
|
||||||
return make(<-chan MotionValues), nil, nil
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
// Start notifications on motion characteristic
|
// Start notifications on motion characteristic
|
||||||
err := i.motionValChar.StartNotify()
|
err := i.motionValChar.StartNotify()
|
||||||
@ -576,8 +582,8 @@ func cancelFunc() (func(), chan struct{}) {
|
|||||||
|
|
||||||
// SetTime sets the watch's time using the Current Time Service
|
// SetTime sets the watch's time using the Current Time Service
|
||||||
func (i *Device) SetTime(t time.Time) error {
|
func (i *Device) SetTime(t time.Time) error {
|
||||||
if !i.device.Properties.Connected {
|
if err := i.checkStatus(i.currentTimeChar); err != nil {
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
buf := &bytes.Buffer{}
|
buf := &bytes.Buffer{}
|
||||||
binary.Write(buf, binary.LittleEndian, uint16(t.Year()))
|
binary.Write(buf, binary.LittleEndian, uint16(t.Year()))
|
||||||
@ -595,8 +601,8 @@ func (i *Device) SetTime(t time.Time) error {
|
|||||||
// Notify sends a notification to InfiniTime via
|
// Notify sends a notification to InfiniTime via
|
||||||
// the Alert Notification Service (ANS)
|
// the Alert Notification Service (ANS)
|
||||||
func (i *Device) Notify(title, body string) error {
|
func (i *Device) Notify(title, body string) error {
|
||||||
if !i.device.Properties.Connected {
|
if err := i.checkStatus(i.newAlertChar); err != nil {
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
return i.newAlertChar.WriteValue(
|
return i.newAlertChar.WriteValue(
|
||||||
append([]byte{0x00, 0x01, 0x00}, []byte(title+"\x00"+body)...),
|
append([]byte{0x00, 0x01, 0x00}, []byte(title+"\x00"+body)...),
|
||||||
@ -612,11 +618,10 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NotifyCall sends a call notification to the PineTime and returns a channel.
|
// NotifyCall sends a call notification to the PineTime and returns a channel.
|
||||||
// This channel will contain the user's response to the call notification. It
|
// This channel will contain the user's response to the call notification.
|
||||||
// can only contain one value.
|
|
||||||
func (i *Device) NotifyCall(from string) (<-chan uint8, error) {
|
func (i *Device) NotifyCall(from string) (<-chan uint8, error) {
|
||||||
if !i.device.Properties.Connected {
|
if err := i.checkStatus(i.newAlertChar); err != nil {
|
||||||
return make(<-chan uint8), nil
|
return nil, err
|
||||||
}
|
}
|
||||||
// Write call notification to new alert characteristic
|
// Write call notification to new alert characteristic
|
||||||
err := i.newAlertChar.WriteValue(
|
err := i.newAlertChar.WriteValue(
|
||||||
@ -626,33 +631,59 @@ func (i *Device) NotifyCall(from string) (<-chan uint8, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// Start notifications on notification event characteristic
|
|
||||||
err = i.notifEventChar.StartNotify()
|
if !i.notifEventDone {
|
||||||
|
err = i.initNotifEvent()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
i.notifEventDone = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return i.notifEventCh, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// initNotifEvent initializes the notification event channel
|
||||||
|
func (i *Device) initNotifEvent() error {
|
||||||
|
// Start notifications on notification event characteristic
|
||||||
|
err := i.notifEventChar.StartNotify()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// Watch properties of notification event characteristic
|
// Watch properties of notification event characteristic
|
||||||
ch, err := i.notifEventChar.WatchProperties()
|
ch, err := i.notifEventChar.WatchProperties()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
// Create new output channel for status
|
// Create new output channel for status
|
||||||
out := make(chan uint8, 1)
|
i.notifEventCh = make(chan uint8, 1)
|
||||||
go func() {
|
go func() {
|
||||||
// For every event
|
// For every event
|
||||||
for event := range ch {
|
for event := range ch {
|
||||||
// If value changed
|
// If value changed
|
||||||
if event.Name == "Value" {
|
if event.Name == "Value" {
|
||||||
// Send status to channel
|
// Send status to channel
|
||||||
out <- uint8(event.Value.([]byte)[0])
|
i.notifEventCh <- uint8(event.Value.([]byte)[0])
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
return out, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// FS creates and returns a new filesystem from the device
|
// FS creates and returns a new filesystem from the device
|
||||||
func (i *Device) FS() (*blefs.FS, error) {
|
func (i *Device) FS() (*blefs.FS, error) {
|
||||||
|
if err := i.checkStatus(i.currentTimeChar); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return blefs.New(i.fsTransferChar)
|
return blefs.New(i.fsTransferChar)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *Device) checkStatus(char *gatt.GattCharacteristic1) error {
|
||||||
|
if !i.device.Properties.Connected {
|
||||||
|
return ErrNotConnected
|
||||||
|
}
|
||||||
|
if char == nil {
|
||||||
|
return ErrCharNotAvail
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user