| package gatt |
| |
| import ( |
| "log" |
| "sync" |
| |
| "github.com/go-ble/ble" |
| "github.com/go-ble/ble/linux/att" |
| ) |
| |
| // NewServerWithName creates a new Server with the specified name |
| func NewServerWithName(name string) (*Server, error) { |
| return NewServerWithNameAndHandler(name, nil) |
| } |
| |
| // NewServerWithNameAndHandler allow to specify a custom NotifyHandler |
| func NewServerWithNameAndHandler(name string, notifyHandler ble.NotifyHandler) (*Server, error) { |
| return &Server{ |
| name: name, |
| svcs: defaultServicesWithHandler(name, notifyHandler), |
| db: att.NewDB(defaultServices(name), uint16(1)), |
| }, nil |
| } |
| |
| // NewServer ... |
| func NewServer() (*Server, error) { |
| return NewServerWithName("Gopher") |
| } |
| |
| // Server ... |
| type Server struct { |
| sync.Mutex |
| name string |
| |
| svcs []*ble.Service |
| db *att.DB |
| } |
| |
| // AddService ... |
| func (s *Server) AddService(svc *ble.Service) error { |
| s.Lock() |
| defer s.Unlock() |
| s.svcs = append(s.svcs, svc) |
| s.db = att.NewDB(s.svcs, uint16(1)) // ble attrs start at 1 |
| return nil |
| } |
| |
| // RemoveAllServices ... |
| func (s *Server) RemoveAllServices() error { |
| s.Lock() |
| defer s.Unlock() |
| s.svcs = defaultServices(s.name) |
| s.db = att.NewDB(s.svcs, uint16(1)) // ble attrs start at 1 |
| return nil |
| } |
| |
| // SetServices ... |
| func (s *Server) SetServices(svcs []*ble.Service) error { |
| s.Lock() |
| defer s.Unlock() |
| s.svcs = append(defaultServices(s.name), svcs...) |
| s.db = att.NewDB(s.svcs, uint16(1)) // ble attrs start at 1 |
| return nil |
| } |
| |
| // DB ... |
| func (s *Server) DB() *att.DB { |
| return s.db |
| } |
| |
| func defaultServices(name string) []*ble.Service { |
| return defaultServicesWithHandler(name, nil) |
| } |
| func defaultServicesWithHandler(name string, handler ble.NotifyHandler) []*ble.Service { |
| // https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.ble.appearance.xml |
| var gapCharAppearanceGenericComputer = []byte{0x00, 0x80} |
| |
| gapSvc := ble.NewService(ble.GAPUUID) |
| gapSvc.NewCharacteristic(ble.DeviceNameUUID).SetValue([]byte(name)) |
| gapSvc.NewCharacteristic(ble.AppearanceUUID).SetValue(gapCharAppearanceGenericComputer) |
| gapSvc.NewCharacteristic(ble.PeripheralPrivacyUUID).SetValue([]byte{0x00}) |
| gapSvc.NewCharacteristic(ble.ReconnectionAddrUUID).SetValue([]byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}) |
| gapSvc.NewCharacteristic(ble.PeferredParamsUUID).SetValue([]byte{0x06, 0x00, 0x06, 0x00, 0x00, 0x00, 0xd0, 0x07}) |
| |
| gattSvc := ble.NewService(ble.GATTUUID) |
| var indicationHandler ble.NotifyHandlerFunc |
| indicationHandler = defaultHanderFunc |
| if handler != nil { |
| indicationHandler = handler.ServeNotify |
| } |
| gattSvc.NewCharacteristic(ble.ServiceChangedUUID).HandleIndicate(indicationHandler) |
| return []*ble.Service{gapSvc, gattSvc} |
| } |
| |
| func defaultHanderFunc(r ble.Request, n ble.Notifier) { |
| log.Printf("TODO: indicate client when the services are changed") |
| for { |
| select { |
| case <-n.Context().Done(): |
| log.Printf("count: Notification unsubscribed") |
| return |
| } |
| } |
| } |