Skip to content

Commit

Permalink
use new type AdvertismentDataElement for ManufacturerData also
Browse files Browse the repository at this point in the history
  • Loading branch information
dnlwgnd committed Feb 24, 2024
1 parent e357a2a commit f0fb62b
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 65 deletions.
18 changes: 9 additions & 9 deletions adapter_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,30 +141,30 @@ func makeScanResult(prph cbgo.Peripheral, advFields cbgo.AdvFields, rssi int) Sc
serviceUUIDs = append(serviceUUIDs, parsedUUID)
}

var manufacturerData []ManufacturerDataElement
var manufacturerData []AdvertismentDataElement
if len(advFields.ManufacturerData) > 2 {
// Note: CoreBluetooth seems to assume there can be only one
// manufacturer data fields in an advertisement packet, while the
// specification allows multiple such fields. See the Bluetooth Core
// Specification Supplement, table 1.1:
// https://www.bluetooth.com/specifications/css-11/
manufacturerID := uint16(advFields.ManufacturerData[0])
manufacturerID += uint16(advFields.ManufacturerData[1]) << 8
manufacturerData = append(manufacturerData, ManufacturerDataElement{
CompanyID: manufacturerID,
Data: advFields.ManufacturerData[2:],
manufacturerData = append(manufacturerData, AdvertismentDataElement{
UUID: New16BitUUID(uint16(advFields.ManufacturerData[0]) + uint16(advFields.ManufacturerData[1]) << 8),
Data: advFields.ManufacturerData[2:],
})
}

serviceData := make(map[uint16][]byte)
var serviceData []AdvertismentDataElement
for _, svcData := range advFields.ServiceData {
cbgoUUID := svcData.UUID
uuid, err := ParseUUID(cbgoUUID.String())
if err != nil || uuid.String() != cbgoUUID.String() {
continue
}
svcID := uuid.Get16Bit()
serviceData[svcID] = svcData.Data[:]
serviceData = append(serviceData, AdvertismentDataElement{
UUID: uuid,
Data: svcData.Data[:],
})
}

// Peripheral UUID is randomized on macOS, which means to
Expand Down
4 changes: 2 additions & 2 deletions examples/advertisement/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ func main() {
adv := adapter.DefaultAdvertisement()
must("config adv", adv.Configure(bluetooth.AdvertisementOptions{
LocalName: "Go Bluetooth",
ManufacturerData: []bluetooth.ManufacturerDataElement{
{CompanyID: 0xffff, Data: []byte{0x01, 0x02}},
ManufacturerData: []bluetooth.AdvertismentDataElement{
{UUID: bluetooth.New16BitUUID(0xFFFF), Data: []byte{0x01, 0x02}},
},
}))
must("start adv", adv.Start())
Expand Down
61 changes: 21 additions & 40 deletions gap.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,29 +55,19 @@ type AdvertisementOptions struct {
Interval Duration

// ManufacturerData stores Advertising Data.
ManufacturerData []ManufacturerDataElement
ManufacturerData []AdvertismentDataElement

// ServiceData stores Advertising Data.
ServiceData []AdvertismentDataElement
}

// Manufacturer data that's part of an advertisement packet.
type ManufacturerDataElement struct {
// AdvertismentDataElement strores a uuid/byte-array pair used as ServiceData or ManufacturerData advertisment elements
type AdvertismentDataElement struct {
// service uuid or company uuid
// The company ID, which must be one of the assigned company IDs.
// The full list is in here:
// https://www.bluetooth.com/specifications/assigned-numbers/
// The list can also be viewed here:
// https://bitbucket.org/bluetooth-SIG/public/src/main/assigned_numbers/company_identifiers/company_identifiers.yaml
// The value 0xffff can also be used for testing.
CompanyID uint16

// The value, which can be any value but can't be very large.
Data []byte
}

// AdvertismentDataElement strores a uuid/byte-array pair used as ServiceData or ManufacturerData advertisment elements
type AdvertismentDataElement struct {
// service uuid or company uuid
// The list can also be viewed here:
// https://bitbucket.org/bluetooth-SIG/public/src/main/assigned_numbers/company_identifiers/company_identifiers.yaml
// https://bitbucket.org/bluetooth-SIG/public/src/main/assigned_numbers/uuids/service_uuids.yaml
Expand Down Expand Up @@ -139,7 +129,7 @@ type AdvertisementPayload interface {

// ManufacturerData returns a slice with all the manufacturer data present in the
// advertising. It may be empty.
ManufacturerData() []ManufacturerDataElement
ManufacturerData() []AdvertismentDataElement

// ServiceData returns a slice with all the service data present in the
// advertising. It may be empty.
Expand All @@ -158,7 +148,7 @@ type AdvertisementFields struct {
ServiceUUIDs []UUID

// ManufacturerData is the manufacturer data of the advertisement.
ManufacturerData []ManufacturerDataElement
ManufacturerData []AdvertismentDataElement

// ServiceData is the service data of the advertisement.
ServiceData []AdvertismentDataElement
Expand Down Expand Up @@ -195,7 +185,7 @@ func (p *advertisementFields) Bytes() []byte {
}

// ManufacturerData returns the underlying ManufacturerData field.
func (p *advertisementFields) ManufacturerData() []ManufacturerDataElement {
func (p *advertisementFields) ManufacturerData() []AdvertismentDataElement {
return p.AdvertisementFields.ManufacturerData
}

Expand Down Expand Up @@ -315,21 +305,12 @@ func (buf *rawAdvertisementPayload) HasServiceUUID(uuid UUID) bool {
}

// ManufacturerData returns the manufacturer data in the advertisement payload.
func (buf *rawAdvertisementPayload) ManufacturerData() []ManufacturerDataElement {
var manufacturerData []ManufacturerDataElement
for index := 0; index < int(buf.len)+4; index += int(buf.data[index]) + 1 {
fieldLength := int(buf.data[index+0])
if fieldLength < 3 {
continue
}
fieldType := buf.data[index+1]
if fieldType != 0xff {
continue
}
key := uint16(buf.data[index+2]) | uint16(buf.data[index+3])<<8
manufacturerData = append(manufacturerData, ManufacturerDataElement{
CompanyID: key,
Data: buf.data[index+4 : index+fieldLength+1],
func (buf *rawAdvertisementPayload) ManufacturerData() []AdvertismentDataElement {
var manufacturerData []AdvertismentDataElement
for _, data := range buf.findAllFields(0xFF) {
manufacturerData = append(manufacturerData, AdvertismentDataElement{
UUID: New16BitUUID(uint16(data[0])+(uint16(data[1])<<8)),
Data: data[2:],
})
}
return manufacturerData
Expand Down Expand Up @@ -390,7 +371,7 @@ func (buf *rawAdvertisementPayload) addFromOptions(options AdvertisementOptions)
}

for _, element := range options.ManufacturerData {
if err := buf.addManufacturerData(element.CompanyID, element.Data); err != nil {
if err := buf.addManufacturerData(element.UUID, element.Data); err != nil {
return err
}
}
Expand All @@ -405,19 +386,19 @@ func (buf *rawAdvertisementPayload) addFromOptions(options AdvertisementOptions)
}

// addManufacturerData adds manufacturer data ([]byte) entries to the advertisement payload.
func (buf *rawAdvertisementPayload) addManufacturerData(key uint16, value []byte) (err error) {
func (buf *rawAdvertisementPayload) addManufacturerData(uuid UUID, data []byte) (err error) {
// Check whether the field can fit this manufacturer data.
fieldLength := len(value) + 4
fieldLength := 1 + 1 + 2 + len(data) // 1 byte length, 1 byte ad type, 2 bytes uuid, actual manufacturer data
if int(buf.len)+fieldLength > len(buf.data) {
return errAdvertisementPacketTooBig
}

// Add the data.
buf.data[buf.len+0] = uint8(fieldLength - 1)
buf.data[buf.len+1] = 0xff
buf.data[buf.len+2] = uint8(key)
buf.data[buf.len+3] = uint8(key >> 8)
copy(buf.data[buf.len+4:], value)
buf.data[buf.len+0] = byte(fieldLength - 1)
buf.data[buf.len+1] = 0xFF
buf.data[buf.len+2] = byte(uuid.Get16Bit())
buf.data[buf.len+3] = byte(uuid.Get16Bit() >> 8)
copy(buf.data[buf.len+4:], data)
buf.len += uint8(fieldLength)

return nil
Expand Down
10 changes: 5 additions & 5 deletions gap_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (a *Advertisement) Configure(options AdvertisementOptions) error {
// Convert map[uint16][]byte to map[uint16]any because that's what BlueZ needs.
manufacturerData := map[uint16]any{}
for _, element := range options.ManufacturerData {
manufacturerData[element.CompanyID] = element.Data
manufacturerData[element.UUID.Get16Bit()] = element.Data
}

// Build an org.bluez.LEAdvertisement1 object, to be exported over DBus.
Expand Down Expand Up @@ -279,12 +279,12 @@ func makeScanResult(props map[string]dbus.Variant) ScanResult {
a := Address{MACAddress{MAC: addr}}
a.SetRandom(props["AddressType"].Value().(string) == "random")

var manufacturerData []ManufacturerDataElement
var manufacturerData []AdvertismentDataElement
if mdata, ok := props["ManufacturerData"].Value().(map[uint16]dbus.Variant); ok {
for k, v := range mdata {
manufacturerData = append(manufacturerData, ManufacturerDataElement{
CompanyID: k,
Data: v.Value().([]byte),
manufacturerData = append(manufacturerData, AdvertismentDataElement{
UUID: New16BitUUID(k),
Data: v.Value().([]byte),
})
}
}
Expand Down
12 changes: 6 additions & 6 deletions gap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ func TestCreateAdvertisementPayload(t *testing.T) {
raw: "\x02\x01\x06" + // flags
"\a\xff\x34\x12asdf", // manufacturer data
parsed: AdvertisementOptions{
ManufacturerData: []ManufacturerDataElement{
{0x1234, []byte("asdf")},
ManufacturerData: []AdvertismentDataElement{
{New16BitUUID(0x1234), []byte("asdf")},
},
},
},
Expand All @@ -71,10 +71,10 @@ func TestCreateAdvertisementPayload(t *testing.T) {
"\x05\xff\xff\xff\x03\x07" + // manufacturer data 2
"\x03\xff\x11\x00", // manufacturer data 3
parsed: AdvertisementOptions{
ManufacturerData: []ManufacturerDataElement{
{0x1234, []byte{5}},
{0xffff, []byte{3, 7}},
{0x0011, []byte{}},
ManufacturerData: []AdvertismentDataElement{
{New16BitUUID(0x1234), []byte{5}},
{New16BitUUID(0xFFFF), []byte{3, 7}},
{New16BitUUID(0x0011), []byte{}},
},
},
},
Expand Down
6 changes: 3 additions & 3 deletions gap_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func getScanResultFromArgs(args *advertisement.BluetoothLEAdvertisementReceivedE
Address: adr,
}

var manufacturerData []ManufacturerDataElement
var manufacturerData []AdvertismentDataElement
if winAdv, err := args.GetAdvertisement(); err == nil && winAdv != nil {
vector, _ := winAdv.GetManufacturerData()
size, _ := vector.GetSize()
Expand All @@ -123,8 +123,8 @@ func getScanResultFromArgs(args *advertisement.BluetoothLEAdvertisementReceivedE
manData := (*advertisement.BluetoothLEManufacturerData)(element)
companyID, _ := manData.GetCompanyId()
buffer, _ := manData.GetData()
manufacturerData = append(manufacturerData, ManufacturerDataElement{
CompanyID: companyID,
manufacturerData = append(manufacturerData, AdvertismentDataElement{
UUID: New16BitUUID(companyID),
Data: bufferToSlice(buffer),
})
}
Expand Down

0 comments on commit f0fb62b

Please sign in to comment.