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
|
||||
fsVersionChar *gatt.GattCharacteristic1
|
||||
fsTransferChar *gatt.GattCharacteristic1
|
||||
notifEventCh chan uint8
|
||||
notifEventDone bool
|
||||
onReconnect func()
|
||||
Music MusicCtrl
|
||||
DFU DFU
|
||||
}
|
||||
|
||||
var ErrNoDevices = errors.New("no InfiniTime devices found")
|
||||
var ErrNotFound = errors.New("could not find any advertising InfiniTime devices")
|
||||
var (
|
||||
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 {
|
||||
AttemptReconnect bool
|
||||
@ -332,8 +338,8 @@ func (i *Device) Address() string {
|
||||
|
||||
// Version returns InfiniTime's reported firmware version string
|
||||
func (i *Device) Version() (string, error) {
|
||||
if !i.device.Properties.Connected {
|
||||
return "", nil
|
||||
if err := i.checkStatus(i.fwVersionChar); err != nil {
|
||||
return "", err
|
||||
}
|
||||
ver, err := i.fwVersionChar.ReadValue(nil)
|
||||
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
|
||||
func (i *Device) BatteryLevel() (uint8, error) {
|
||||
if !i.device.Properties.Connected {
|
||||
return 0, nil
|
||||
if err := i.checkStatus(i.battLevelChar); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
battLevel, err := i.battLevelChar.ReadValue(nil)
|
||||
if err != nil {
|
||||
@ -352,8 +358,8 @@ func (i *Device) BatteryLevel() (uint8, error) {
|
||||
}
|
||||
|
||||
func (i *Device) StepCount() (uint32, error) {
|
||||
if !i.device.Properties.Connected {
|
||||
return 0, nil
|
||||
if err := i.checkStatus(i.stepCountChar); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
stepCountData, err := i.stepCountChar.ReadValue(nil)
|
||||
if err != nil {
|
||||
@ -370,8 +376,8 @@ type MotionValues struct {
|
||||
|
||||
func (i *Device) Motion() (MotionValues, error) {
|
||||
out := MotionValues{}
|
||||
if !i.device.Properties.Connected {
|
||||
return out, nil
|
||||
if err := i.checkStatus(i.motionValChar); err != nil {
|
||||
return out, err
|
||||
}
|
||||
motionVals, err := i.motionValChar.ReadValue(nil)
|
||||
if err != nil {
|
||||
@ -386,8 +392,8 @@ func (i *Device) Motion() (MotionValues, error) {
|
||||
}
|
||||
|
||||
func (i *Device) HeartRate() (uint8, error) {
|
||||
if !i.device.Properties.Connected {
|
||||
return 0, nil
|
||||
if err := i.checkStatus(i.heartRateChar); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
heartRate, err := i.heartRateChar.ReadValue(nil)
|
||||
if err != nil {
|
||||
@ -397,8 +403,8 @@ func (i *Device) HeartRate() (uint8, error) {
|
||||
}
|
||||
|
||||
func (i *Device) WatchHeartRate() (<-chan uint8, func(), error) {
|
||||
if !i.device.Properties.Connected {
|
||||
return make(<-chan uint8), nil, nil
|
||||
if err := i.checkStatus(i.heartRateChar); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Start notifications on heart rate characteristic
|
||||
err := i.heartRateChar.StartNotify()
|
||||
@ -439,8 +445,8 @@ func (i *Device) WatchHeartRate() (<-chan uint8, func(), error) {
|
||||
}
|
||||
|
||||
func (i *Device) WatchBatteryLevel() (<-chan uint8, func(), error) {
|
||||
if !i.device.Properties.Connected {
|
||||
return make(<-chan uint8), nil, nil
|
||||
if err := i.checkStatus(i.battLevelChar); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Start notifications on heart rate characteristic
|
||||
err := i.battLevelChar.StartNotify()
|
||||
@ -481,8 +487,8 @@ func (i *Device) WatchBatteryLevel() (<-chan uint8, func(), error) {
|
||||
}
|
||||
|
||||
func (i *Device) WatchStepCount() (<-chan uint32, func(), error) {
|
||||
if !i.device.Properties.Connected {
|
||||
return make(<-chan uint32), nil, nil
|
||||
if err := i.checkStatus(i.stepCountChar); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Start notifications on step count characteristic
|
||||
err := i.stepCountChar.StartNotify()
|
||||
@ -523,8 +529,8 @@ func (i *Device) WatchStepCount() (<-chan uint32, func(), error) {
|
||||
}
|
||||
|
||||
func (i *Device) WatchMotion() (<-chan MotionValues, func(), error) {
|
||||
if !i.device.Properties.Connected {
|
||||
return make(<-chan MotionValues), nil, nil
|
||||
if err := i.checkStatus(i.motionValChar); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Start notifications on motion characteristic
|
||||
err := i.motionValChar.StartNotify()
|
||||
@ -576,8 +582,8 @@ func cancelFunc() (func(), chan struct{}) {
|
||||
|
||||
// SetTime sets the watch's time using the Current Time Service
|
||||
func (i *Device) SetTime(t time.Time) error {
|
||||
if !i.device.Properties.Connected {
|
||||
return nil
|
||||
if err := i.checkStatus(i.currentTimeChar); err != nil {
|
||||
return err
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
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
|
||||
// the Alert Notification Service (ANS)
|
||||
func (i *Device) Notify(title, body string) error {
|
||||
if !i.device.Properties.Connected {
|
||||
return nil
|
||||
if err := i.checkStatus(i.newAlertChar); err != nil {
|
||||
return err
|
||||
}
|
||||
return i.newAlertChar.WriteValue(
|
||||
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.
|
||||
// This channel will contain the user's response to the call notification. It
|
||||
// can only contain one value.
|
||||
// This channel will contain the user's response to the call notification.
|
||||
func (i *Device) NotifyCall(from string) (<-chan uint8, error) {
|
||||
if !i.device.Properties.Connected {
|
||||
return make(<-chan uint8), nil
|
||||
if err := i.checkStatus(i.newAlertChar); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Write call notification to new alert characteristic
|
||||
err := i.newAlertChar.WriteValue(
|
||||
@ -626,33 +631,59 @@ func (i *Device) NotifyCall(from string) (<-chan uint8, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Start notifications on notification event characteristic
|
||||
err = i.notifEventChar.StartNotify()
|
||||
|
||||
if !i.notifEventDone {
|
||||
err = i.initNotifEvent()
|
||||
if err != nil {
|
||||
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
|
||||
ch, err := i.notifEventChar.WatchProperties()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
// Create new output channel for status
|
||||
out := make(chan uint8, 1)
|
||||
i.notifEventCh = make(chan uint8, 1)
|
||||
go func() {
|
||||
// For every event
|
||||
for event := range ch {
|
||||
// If value changed
|
||||
if event.Name == "Value" {
|
||||
// Send status to channel
|
||||
out <- uint8(event.Value.([]byte)[0])
|
||||
return
|
||||
i.notifEventCh <- uint8(event.Value.([]byte)[0])
|
||||
}
|
||||
}
|
||||
}()
|
||||
return out, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// FS creates and returns a new filesystem from the device
|
||||
func (i *Device) FS() (*blefs.FS, error) {
|
||||
if err := i.checkStatus(i.currentTimeChar); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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