// process device events and asynchronous errors // (implements XpcEventHandler) func (d *device) HandleXpcEvent(event xpc.Dict, err error) { if err != nil { log.Println("error:", err) return } id := event.MustGetInt("kCBMsgId") args := event.MustGetDict("kCBMsgArgs") //log.Printf(">> %d, %v", id, args) switch id { case // device event 6, // StateChanged 16, // AdvertisingStarted 17, // AdvertisingStopped 18: // ServiceAdded d.rspc <- message{id: id, args: args} case 19, // ReadRequest 20, // WriteRequest 21, // Subscribe 22, // Unubscribe 23: // Confirmation d.respondToRequest(id, args) case peripheralDiscovered: xa := args.MustGetDict("kCBMsgArgAdvertisementData") if len(xa) == 0 { return } u := UUID{args.MustGetUUID("kCBMsgArgDeviceUUID")} a := &Advertisement{ LocalName: xa.GetString("kCBAdvDataLocalName", args.GetString("kCBMsgArgName", "")), TxPowerLevel: xa.GetInt("kCBAdvDataTxPowerLevel", 0), ManufacturerData: xa.GetBytes("kCBAdvDataManufacturerData", nil), } rssi := args.MustGetInt("kCBMsgArgRssi") if xu, ok := xa["kCBAdvDataServiceUUIDs"]; ok { for _, xs := range xu.(xpc.Array) { s := UUID{reverse(xs.([]byte))} a.Services = append(a.Services, s) } } if xsds, ok := xa["kCBAdvDataServiceData"]; ok { xsd := xsds.(xpc.Array) for i := 0; i < len(xsd); i += 2 { sd := ServiceData{ UUID: UUID{xsd[i].([]byte)}, Data: xsd[i+1].([]byte), } a.ServiceData = append(a.ServiceData, sd) } } if d.peripheralDiscovered != nil { go d.peripheralDiscovered(&peripheral{id: xpc.UUID(u.b), d: d}, a, rssi) } case peripheralConnected: u := UUID{args.MustGetUUID("kCBMsgArgDeviceUUID")} p := &peripheral{ id: xpc.UUID(u.b), d: d, reqc: make(chan message), rspc: make(chan message), quitc: make(chan struct{}), sub: newSubscriber(), } d.plistmu.Lock() d.plist[u.String()] = p d.plistmu.Unlock() go p.loop() if d.peripheralConnected != nil { go d.peripheralConnected(p, nil) } case peripheralDisconnected: u := UUID{args.MustGetUUID("kCBMsgArgDeviceUUID")} d.plistmu.Lock() p := d.plist[u.String()] delete(d.plist, u.String()) d.plistmu.Unlock() if d.peripheralDisconnected != nil { d.peripheralDisconnected(p, nil) // TODO: Get Result as error? } close(p.quitc) case // Peripheral events rssiRead, serviceDiscovered, includedServicesDiscovered, characteristicsDiscovered, characteristicRead, characteristicWritten, notificationValueSet, descriptorsDiscovered, descriptorRead, descriptorWritten: u := UUID{args.MustGetUUID("kCBMsgArgDeviceUUID")} d.plistmu.Lock() p := d.plist[u.String()] d.plistmu.Unlock() p.rspc <- message{id: id, args: args} default: log.Printf("Unhandled event: %#v", event) } }
func NewPeripheral(u UUID) Peripheral { return &peripheral{id: xpc.UUID(u.b)} }