ninafw: this PR contains several fixes and improvements for the NINAFW implementation including:
- correctly return from read requests instead of returning spurious error - move some steps previously being done during Configure() into Start() where they more correctly belonged. - use advertising display name as the correct default value for the generic access characteristic. - speed up the polling for new notifications for Centrals Signed-off-by: deadprogram <ron@hybridgroup.com>
This commit is contained in:
parent
564b0ba58f
commit
bf647ecd57
4 changed files with 71 additions and 44 deletions
|
@ -171,7 +171,7 @@ func (a *Adapter) startNotifications() {
|
|||
}
|
||||
}
|
||||
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
|
@ -925,6 +925,8 @@ func (a *att) handleReadReq(handle, attrHandle uint16) error {
|
|||
if err := a.hci.sendAclPkt(handle, attCID, response[:pos]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
case attributeTypeDescriptor:
|
||||
|
@ -945,6 +947,8 @@ func (a *att) handleReadReq(handle, attrHandle uint16) error {
|
|||
if err := a.hci.sendAclPkt(handle, attCID, response[:pos]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -269,6 +269,10 @@ var defaultAdvertisement Advertisement
|
|||
// Advertisement encapsulates a single advertisement instance.
|
||||
type Advertisement struct {
|
||||
adapter *Adapter
|
||||
|
||||
localName []byte
|
||||
serviceUUIDs []UUID
|
||||
interval uint16
|
||||
}
|
||||
|
||||
// DefaultAdvertisement returns the default advertisement instance but does not
|
||||
|
@ -276,14 +280,31 @@ type Advertisement struct {
|
|||
func (a *Adapter) DefaultAdvertisement() *Advertisement {
|
||||
if defaultAdvertisement.adapter == nil {
|
||||
defaultAdvertisement.adapter = a
|
||||
}
|
||||
|
||||
a.AddService(
|
||||
return &defaultAdvertisement
|
||||
}
|
||||
|
||||
// Configure this advertisement.
|
||||
func (a *Advertisement) Configure(options AdvertisementOptions) error {
|
||||
switch {
|
||||
case options.LocalName != "":
|
||||
a.localName = []byte(options.LocalName)
|
||||
default:
|
||||
a.localName = []byte("TinyGo")
|
||||
}
|
||||
|
||||
a.serviceUUIDs = append([]UUID{}, options.ServiceUUIDs...)
|
||||
a.interval = uint16(options.Interval)
|
||||
|
||||
a.adapter.AddService(
|
||||
&Service{
|
||||
UUID: ServiceUUIDGenericAccess,
|
||||
Characteristics: []CharacteristicConfig{
|
||||
{
|
||||
UUID: CharacteristicUUIDDeviceName,
|
||||
Flags: CharacteristicReadPermission,
|
||||
Value: a.localName,
|
||||
},
|
||||
{
|
||||
UUID: CharacteristicUUIDAppearance,
|
||||
|
@ -291,7 +312,7 @@ func (a *Adapter) DefaultAdvertisement() *Advertisement {
|
|||
},
|
||||
},
|
||||
})
|
||||
a.AddService(
|
||||
a.adapter.AddService(
|
||||
&Service{
|
||||
UUID: ServiceUUIDGenericAttribute,
|
||||
Characteristics: []CharacteristicConfig{
|
||||
|
@ -301,17 +322,16 @@ func (a *Adapter) DefaultAdvertisement() *Advertisement {
|
|||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
return &defaultAdvertisement
|
||||
return nil
|
||||
}
|
||||
|
||||
// Configure this advertisement.
|
||||
func (a *Advertisement) Configure(options AdvertisementOptions) error {
|
||||
// Start advertisement. May only be called after it has been configured.
|
||||
func (a *Advertisement) Start() error {
|
||||
// uint8_t type = (_connectable) ? 0x00 : (_localName ? 0x02 : 0x03);
|
||||
typ := uint8(0x00)
|
||||
|
||||
if err := a.adapter.hci.leSetAdvertisingParameters(uint16(options.Interval), uint16(options.Interval),
|
||||
if err := a.adapter.hci.leSetAdvertisingParameters(a.interval, a.interval,
|
||||
typ, 0x00, 0x00, [6]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0x07, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -325,8 +345,8 @@ func (a *Advertisement) Configure(options AdvertisementOptions) error {
|
|||
advertisingDataLen += 3
|
||||
|
||||
// TODO: handle multiple service UUIDs
|
||||
if len(options.ServiceUUIDs) > 0 {
|
||||
uuid := options.ServiceUUIDs[0]
|
||||
if len(a.serviceUUIDs) > 0 {
|
||||
uuid := a.serviceUUIDs[0]
|
||||
var sz uint8
|
||||
|
||||
switch {
|
||||
|
@ -355,23 +375,22 @@ func (a *Advertisement) Configure(options AdvertisementOptions) error {
|
|||
scanResponseDataLen := uint8(0)
|
||||
|
||||
switch {
|
||||
case len(options.LocalName) > 29:
|
||||
case len(a.localName) > 29:
|
||||
scanResponseData[1] = 0x08
|
||||
scanResponseData[0] = 1 + 29
|
||||
copy(scanResponseData[2:], options.LocalName[:29])
|
||||
copy(scanResponseData[2:], a.localName[:29])
|
||||
scanResponseDataLen = 31
|
||||
case len(options.LocalName) > 0:
|
||||
case len(a.localName) > 0:
|
||||
scanResponseData[1] = 0x09
|
||||
scanResponseData[0] = uint8(1 + len(options.LocalName))
|
||||
copy(scanResponseData[2:], options.LocalName)
|
||||
scanResponseDataLen = uint8(2 + len(options.LocalName))
|
||||
scanResponseData[0] = uint8(1 + len(a.localName))
|
||||
copy(scanResponseData[2:], a.localName)
|
||||
scanResponseDataLen = uint8(2 + len(a.localName))
|
||||
}
|
||||
|
||||
return a.adapter.hci.leSetScanResponseData(scanResponseData[:scanResponseDataLen])
|
||||
}
|
||||
if err := a.adapter.hci.leSetScanResponseData(scanResponseData[:scanResponseDataLen]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Start advertisement. May only be called after it has been configured.
|
||||
func (a *Advertisement) Start() error {
|
||||
if err := a.adapter.hci.leSetAdvertiseEnable(true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -42,10 +42,14 @@ func (a *Adapter) AddService(service *Service) error {
|
|||
endHandle = a.att.addLocalAttribute(attributeTypeDescriptor, charHandle, shortUUID(gattClientCharacteristicConfigUUID).UUID(), CharacteristicReadPermission|CharacteristicWritePermission, []byte{0, 0})
|
||||
}
|
||||
|
||||
if service.Characteristics[i].Handle != nil {
|
||||
if service.Characteristics[i].Handle == nil {
|
||||
service.Characteristics[i].Handle = &Characteristic{}
|
||||
}
|
||||
|
||||
service.Characteristics[i].Handle.adapter = a
|
||||
service.Characteristics[i].Handle.handle = valueHandle
|
||||
service.Characteristics[i].Handle.permissions = service.Characteristics[i].Flags
|
||||
if len(service.Characteristics[i].Value) > 0 {
|
||||
service.Characteristics[i].Handle.value = service.Characteristics[i].Value
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue