You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ma...@apache.org on 2017/03/06 21:17:12 UTC
[38/50] [abbrv] incubator-mynewt-newt git commit: MYNEWT-653 Use
runtimeco gatt fork.
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/linux/hci.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/linux/hci.go b/newtmgr/vendor/github.com/runtimeco/gatt/linux/hci.go
new file mode 100644
index 0000000..967680d
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/linux/hci.go
@@ -0,0 +1,400 @@
+package linux
+
+import (
+ "fmt"
+ "io"
+ "log"
+ "sync"
+
+ "github.com/runtimeco/gatt/linux/cmd"
+ "github.com/runtimeco/gatt/linux/evt"
+)
+
+type HCI struct {
+ AcceptMasterHandler func(pd *PlatData)
+ AcceptSlaveHandler func(pd *PlatData)
+ AdvertisementHandler func(pd *PlatData)
+
+ d io.ReadWriteCloser
+ c *cmd.Cmd
+ e *evt.Evt
+
+ plist map[bdaddr]*PlatData
+ plistmu *sync.Mutex
+
+ bufCnt chan struct{}
+ bufSize int
+
+ maxConn int
+ connsmu *sync.Mutex
+ conns map[uint16]*conn
+
+ adv bool
+ advmu *sync.Mutex
+}
+
+type bdaddr [6]byte
+
+type PlatData struct {
+ Name string
+ AddressType uint8
+ Address [6]byte
+ Data []byte
+ Connectable bool
+ RSSI int8
+
+ Conn io.ReadWriteCloser
+}
+
+func NewHCI(devID int, chk bool, maxConn int) (*HCI, error) {
+ d, err := newDevice(devID, chk)
+ if err != nil {
+ return nil, err
+ }
+ c := cmd.NewCmd(d)
+ e := evt.NewEvt()
+
+ h := &HCI{
+ d: d,
+ c: c,
+ e: e,
+
+ plist: make(map[bdaddr]*PlatData),
+ plistmu: &sync.Mutex{},
+
+ bufCnt: make(chan struct{}, 15-1),
+ bufSize: 27,
+
+ maxConn: maxConn,
+ connsmu: &sync.Mutex{},
+ conns: map[uint16]*conn{},
+
+ advmu: &sync.Mutex{},
+ }
+
+ e.HandleEvent(evt.LEMeta, evt.HandlerFunc(h.handleLEMeta))
+ e.HandleEvent(evt.DisconnectionComplete, evt.HandlerFunc(h.handleDisconnectionComplete))
+ e.HandleEvent(evt.NumberOfCompletedPkts, evt.HandlerFunc(h.handleNumberOfCompletedPkts))
+ e.HandleEvent(evt.CommandComplete, evt.HandlerFunc(c.HandleComplete))
+ e.HandleEvent(evt.CommandStatus, evt.HandlerFunc(c.HandleStatus))
+
+ go h.mainLoop()
+ h.resetDevice()
+ return h, nil
+}
+
+func (h *HCI) Close() error {
+ for _, c := range h.conns {
+ c.Close()
+ }
+ return h.d.Close()
+}
+
+func (h *HCI) SetAdvertiseEnable(en bool) error {
+ h.advmu.Lock()
+ h.adv = en
+ h.advmu.Unlock()
+ return h.setAdvertiseEnable(en)
+}
+
+func (h *HCI) setAdvertiseEnable(en bool) error {
+ h.advmu.Lock()
+ defer h.advmu.Unlock()
+ if en && h.adv && (len(h.conns) == h.maxConn) {
+ return nil
+ }
+ return h.c.SendAndCheckResp(
+ cmd.LESetAdvertiseEnable{
+ AdvertisingEnable: btoi(en),
+ }, []byte{0x00})
+}
+
+func (h *HCI) SendCmdWithAdvOff(c cmd.CmdParam) error {
+ h.setAdvertiseEnable(false)
+ err := h.c.SendAndCheckResp(c, nil)
+ if h.adv {
+ h.setAdvertiseEnable(true)
+ }
+ return err
+}
+
+func (h *HCI) SetScanEnable(en bool, dup bool) error {
+ return h.c.SendAndCheckResp(
+ cmd.LESetScanEnable{
+ LEScanEnable: btoi(en),
+ FilterDuplicates: btoi(!dup),
+ }, []byte{0x00})
+}
+
+func (h *HCI) Connect(pd *PlatData) error {
+ h.c.Send(
+ cmd.LECreateConn{
+ LEScanInterval: 0x0004, // N x 0.625ms
+ LEScanWindow: 0x0004, // N x 0.625ms
+ InitiatorFilterPolicy: 0x00, // white list not used
+ PeerAddressType: pd.AddressType, // public or random
+ PeerAddress: pd.Address, //
+ OwnAddressType: 0x00, // public
+ ConnIntervalMin: 6, // N x 0.125ms
+ ConnIntervalMax: 7, // N x 0.125ms
+ ConnLatency: 0x0000, //
+ SupervisionTimeout: 0x00100, // N x 10ms
+ MinimumCELength: 0x0000, // N x 0.625ms
+ MaximumCELength: 0x0000, // N x 0.625ms
+ })
+ return nil
+}
+
+func (h *HCI) CancelConnection(pd *PlatData) error {
+ return pd.Conn.Close()
+}
+
+func (h *HCI) SendRawCommand(c cmd.CmdParam) ([]byte, error) {
+ return h.c.Send(c)
+}
+
+func btoi(b bool) uint8 {
+ if b {
+ return 1
+ }
+ return 0
+}
+
+func (h *HCI) mainLoop() {
+ b := make([]byte, 4096)
+ for {
+ n, err := h.d.Read(b)
+ if err != nil {
+ return
+ }
+ if n == 0 {
+ return
+ }
+ p := make([]byte, n)
+ copy(p, b)
+ h.handlePacket(p)
+ }
+}
+
+func (h *HCI) handlePacket(b []byte) {
+ t, b := packetType(b[0]), b[1:]
+ var err error
+ switch t {
+ case typCommandPkt:
+ op := uint16(b[0]) | uint16(b[1])<<8
+ log.Printf("unmanaged cmd: opcode (%04x) [ % X ]\n", op, b)
+ case typACLDataPkt:
+ err = h.handleL2CAP(b)
+ case typSCODataPkt:
+ err = fmt.Errorf("SCO packet not supported")
+ case typEventPkt:
+ go func() {
+ err := h.e.Dispatch(b)
+ if err != nil {
+ log.Printf("hci: %s, [ % X]", err, b)
+ }
+ }()
+ case typVendorPkt:
+ err = fmt.Errorf("Vendor packet not supported")
+ default:
+ log.Fatalf("Unknown event: 0x%02X [ % X ]\n", t, b)
+ }
+ if err != nil {
+ log.Printf("hci: %s, [ % X]", err, b)
+ }
+}
+
+func (h *HCI) resetDevice() error {
+ seq := []cmd.CmdParam{
+ cmd.Reset{},
+ cmd.SetEventMask{EventMask: 0x3dbff807fffbffff},
+ cmd.LESetEventMask{LEEventMask: 0x000000000000001F},
+ cmd.WriteSimplePairingMode{SimplePairingMode: 1},
+ cmd.WriteLEHostSupported{LESupportedHost: 1, SimultaneousLEHost: 0},
+ cmd.WriteInquiryMode{InquiryMode: 2},
+ cmd.WritePageScanType{PageScanType: 1},
+ cmd.WriteInquiryScanType{ScanType: 1},
+ cmd.WriteClassOfDevice{ClassOfDevice: [3]byte{0x40, 0x02, 0x04}},
+ cmd.WritePageTimeout{PageTimeout: 0x2000},
+ cmd.WriteDefaultLinkPolicy{DefaultLinkPolicySettings: 0x5},
+ cmd.HostBufferSize{
+ HostACLDataPacketLength: 0x1000,
+ HostSynchronousDataPacketLength: 0xff,
+ HostTotalNumACLDataPackets: 0x0014,
+ HostTotalNumSynchronousDataPackets: 0x000a},
+ cmd.LESetScanParameters{
+ LEScanType: 0x01, // [0x00]: passive, 0x01: active
+ LEScanInterval: 0x0010, // [0x10]: 0.625ms * 16
+ LEScanWindow: 0x0010, // [0x10]: 0.625ms * 16
+ OwnAddressType: 0x00, // [0x00]: public, 0x01: random
+ ScanningFilterPolicy: 0x00, // [0x00]: accept all, 0x01: ignore non-white-listed.
+ },
+ }
+ for _, s := range seq {
+ if err := h.c.SendAndCheckResp(s, []byte{0x00}); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (h *HCI) handleAdvertisement(b []byte) {
+ // If no one is interested, don't bother.
+ if h.AdvertisementHandler == nil {
+ return
+ }
+ ep := &evt.LEAdvertisingReportEP{}
+ if err := ep.Unmarshal(b); err != nil {
+ return
+ }
+ for i := 0; i < int(ep.NumReports); i++ {
+ addr := bdaddr(ep.Address[i])
+ et := ep.EventType[i]
+ connectable := et == advInd || et == advDirectInd
+ scannable := et == advInd || et == advScanInd
+
+ if et == scanRsp {
+ h.plistmu.Lock()
+ pd, ok := h.plist[addr]
+ h.plistmu.Unlock()
+ if ok {
+ pd.Data = append(pd.Data, ep.Data[i]...)
+ h.AdvertisementHandler(pd)
+ }
+ continue
+ }
+
+ pd := &PlatData{
+ AddressType: ep.AddressType[i],
+ Address: ep.Address[i],
+ Data: ep.Data[i],
+ Connectable: connectable,
+ RSSI: ep.RSSI[i],
+ }
+ h.plistmu.Lock()
+ h.plist[addr] = pd
+ h.plistmu.Unlock()
+ if scannable {
+ continue
+ }
+ h.AdvertisementHandler(pd)
+ }
+}
+
+func (h *HCI) handleNumberOfCompletedPkts(b []byte) error {
+ ep := &evt.NumberOfCompletedPktsEP{}
+ if err := ep.Unmarshal(b); err != nil {
+ return err
+ }
+ for _, r := range ep.Packets {
+ for i := 0; i < int(r.NumOfCompletedPkts); i++ {
+ <-h.bufCnt
+ }
+ }
+ return nil
+}
+
+func (h *HCI) handleConnection(b []byte) {
+ ep := &evt.LEConnectionCompleteEP{}
+ if err := ep.Unmarshal(b); err != nil {
+ return // FIXME
+ }
+ hh := ep.ConnectionHandle
+ c := newConn(h, hh)
+ h.connsmu.Lock()
+ h.conns[hh] = c
+ h.connsmu.Unlock()
+ h.setAdvertiseEnable(true)
+
+ // FIXME: sloppiness. This call should be called by the package user once we
+ // flesh out the support of l2cap signaling packets (CID:0x0001,0x0005)
+ if ep.ConnLatency != 0 || ep.ConnInterval > 0x18 {
+ c.updateConnection()
+ }
+
+ // master connection
+ if ep.Role == 0x01 {
+ pd := &PlatData{
+ Address: ep.PeerAddress,
+ Conn: c,
+ }
+ h.AcceptMasterHandler(pd)
+ return
+ }
+ h.plistmu.Lock()
+ pd := h.plist[ep.PeerAddress]
+ h.plistmu.Unlock()
+ pd.Conn = c
+ h.AcceptSlaveHandler(pd)
+}
+
+func (h *HCI) handleDisconnectionComplete(b []byte) error {
+ ep := &evt.DisconnectionCompleteEP{}
+ if err := ep.Unmarshal(b); err != nil {
+ return err
+ }
+ hh := ep.ConnectionHandle
+ h.connsmu.Lock()
+ defer h.connsmu.Unlock()
+ c, found := h.conns[hh]
+ if !found {
+ // should not happen, just be cautious for now.
+ log.Printf("l2conn: disconnecting a disconnected 0x%04X connection", hh)
+ return nil
+ }
+ delete(h.conns, hh)
+ close(c.aclc)
+ h.setAdvertiseEnable(true)
+ return nil
+}
+
+func (h *HCI) handleLEMeta(b []byte) error {
+ code := evt.LEEventCode(b[0])
+ switch code {
+ case evt.LEConnectionComplete:
+ go h.handleConnection(b)
+ case evt.LEConnectionUpdateComplete:
+ // anything to do here?
+ case evt.LEAdvertisingReport:
+ go h.handleAdvertisement(b)
+ // case evt.LEReadRemoteUsedFeaturesComplete:
+ // case evt.LELTKRequest:
+ // case evt.LERemoteConnectionParameterRequest:
+ default:
+ return fmt.Errorf("Unhandled LE event: %s, [ % X ]", code, b)
+ }
+ return nil
+}
+
+func (h *HCI) handleL2CAP(b []byte) error {
+ a := &aclData{}
+ if err := a.unmarshal(b); err != nil {
+ return err
+ }
+ h.connsmu.Lock()
+ defer h.connsmu.Unlock()
+ c, found := h.conns[a.attr]
+
+ if a.flags != 0x002 {
+ if !found {
+ // should not happen, just be cautious for now.
+ log.Printf("l2conn: got data for disconnected handle: 0x%04x", a.attr)
+ return nil
+ if len(a.b) < 4 {
+ log.Printf("l2conn: l2cap packet is too short/corrupt, length is %d", len(a.b))
+ return nil
+ }
+ cid := uint16(a.b[2]) | (uint16(a.b[3]) << 8)
+ if cid == 5 {
+ c.handleSignal(a)
+ return nil
+ }
+ }
+ }
+ c.aclc <- a
+ return nil
+}
+
+func (h *HCI) trace(fmt string, v ...interface{}) {
+ log.Printf(fmt, v)
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/linux/l2cap.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/linux/l2cap.go b/newtmgr/vendor/github.com/runtimeco/gatt/linux/l2cap.go
new file mode 100644
index 0000000..daca82f
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/linux/l2cap.go
@@ -0,0 +1,174 @@
+package linux
+
+import (
+ "fmt"
+ "io"
+ "log"
+
+ "github.com/runtimeco/gatt/linux/cmd"
+)
+
+type aclData struct {
+ attr uint16
+ flags uint8
+ dlen uint16
+ b []byte
+}
+
+func (a *aclData) unmarshal(b []byte) error {
+ if len(b) < 4 {
+ return fmt.Errorf("malformed acl packet")
+ }
+ attr := uint16(b[0]) | (uint16(b[1]&0x0f) << 8)
+ flags := b[1] >> 4
+ dlen := uint16(b[2]) | (uint16(b[3]) << 8)
+ if len(b) != 4+int(dlen) {
+ return fmt.Errorf("malformed acl packet")
+ }
+
+ *a = aclData{attr: attr, flags: flags, dlen: dlen, b: b[4:]}
+ return nil
+}
+
+type conn struct {
+ hci *HCI
+ attr uint16
+ aclc chan *aclData
+}
+
+func newConn(hci *HCI, hh uint16) *conn {
+ return &conn{
+ hci: hci,
+ attr: hh,
+ aclc: make(chan *aclData),
+ }
+}
+
+func (c *conn) updateConnection() (int, error) {
+ b := []byte{
+ 0x12, // Code (Connection Param Update)
+ 0x02, // ID
+ 0x08, 0x00, // DataLength
+ 0x08, 0x00, // IntervalMin
+ 0x18, 0x00, // IntervalMax
+ 0x00, 0x00, // SlaveLatency
+ 0xC8, 0x00} // TimeoutMultiplier
+ return c.write(0x05, b)
+}
+
+// write writes the l2cap payload to the controller.
+// It first prepend the l2cap header (4-bytes), and diassemble the payload
+// if it is larger than the HCI LE buffer size that the conntroller can support.
+func (c *conn) write(cid int, b []byte) (int, error) {
+ flag := uint8(0) // ACL data continuation flag
+ tlen := len(b) // Total length of the l2cap payload
+
+ // log.Printf("W: [ % X ]", b)
+ w := append(
+ []byte{
+ 0, // packet type
+ 0, 0, // attr
+ 0, 0, // dlen
+ uint8(tlen), uint8(tlen >> 8), // l2cap header
+ uint8(cid), uint8(cid >> 8), // l2cap header
+ }, b...)
+
+ n := 4 + tlen // l2cap header + l2cap payload
+ for n > 0 {
+ dlen := n
+ if dlen > c.hci.bufSize {
+ dlen = c.hci.bufSize
+ }
+ w[0] = 0x02 // packetTypeACL
+ w[1] = uint8(c.attr)
+ w[2] = uint8(c.attr>>8) | flag
+ w[3] = uint8(dlen)
+ w[4] = uint8(dlen >> 8)
+
+ // make sure we don't send more buffers than the controller can handdle
+ c.hci.bufCnt <- struct{}{}
+
+ c.hci.d.Write(w[:5+dlen])
+ w = w[dlen:] // advance the pointer to the next segment, if any.
+ flag = 0x10 // the rest of iterations attr continued segments, if any.
+ n -= dlen
+ }
+
+ return len(b), nil
+}
+
+func (c *conn) Read(b []byte) (int, error) {
+ a, ok := <-c.aclc
+ if !ok {
+ return 0, io.EOF
+ }
+ tlen := int(uint16(a.b[0]) | uint16(a.b[1])<<8)
+ if tlen > len(b) {
+ return 0, io.ErrShortBuffer
+ }
+ d := a.b[4:] // skip l2cap header
+ copy(b, d)
+ n := len(d)
+
+ // Keep receiving and reassemble continued l2cap segments
+ for n != tlen {
+ if a, ok = <-c.aclc; !ok || (a.flags&0x1) == 0 {
+ return n, io.ErrUnexpectedEOF
+ }
+ copy(b[n:], a.b)
+ n += len(a.b)
+ }
+ // log.Printf("R: [ % X ]", b[:n])
+ return n, nil
+}
+
+func (c *conn) Write(b []byte) (int, error) {
+ return c.write(0x04, b)
+}
+
+// Close disconnects the connection by sending HCI disconnect command to the device.
+func (c *conn) Close() error {
+ h := c.hci
+ hh := c.attr
+ h.connsmu.Lock()
+ defer h.connsmu.Unlock()
+ _, found := h.conns[hh]
+ if !found {
+ // log.Printf("l2conn: 0x%04x already disconnected", hh)
+ return nil
+ }
+ if err, _ := h.c.Send(cmd.Disconnect{ConnectionHandle: hh, Reason: 0x13}); err != nil {
+ return fmt.Errorf("l2conn: failed to disconnect, %s", err)
+ }
+ return nil
+}
+
+// Signal Packets
+// 0x00 Reserved Any
+// 0x01 Command reject 0x0001 and 0x0005
+// 0x02 Connection request 0x0001
+// 0x03 Connection response 0x0001
+// 0x04 Configure request 0x0001
+// 0x05 Configure response 0x0001
+// 0x06 Disconnection request 0x0001 and 0x0005
+// 0x07 Disconnection response 0x0001 and 0x0005
+// 0x08 Echo request 0x0001
+// 0x09 Echo response 0x0001
+// 0x0A Information request 0x0001
+// 0x0B Information response 0x0001
+// 0x0C Create Channel request 0x0001
+// 0x0D Create Channel response 0x0001
+// 0x0E Move Channel request 0x0001
+// 0x0F Move Channel response 0x0001
+// 0x10 Move Channel Confirmation 0x0001
+// 0x11 Move Channel Confirmation response 0x0001
+// 0x12 Connection Parameter Update request 0x0005
+// 0x13 Connection Parameter Update response 0x0005
+// 0x14 LE Credit Based Connection request 0x0005
+// 0x15 LE Credit Based Connection response 0x0005
+// 0x16 LE Flow Control Credit 0x0005
+func (c *conn) handleSignal(a *aclData) error {
+ log.Printf("ignore l2cap signal:[ % X ]", a.b)
+ // FIXME: handle LE signaling channel (CID: 5)
+ return nil
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/asm.s
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/asm.s b/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/asm.s
new file mode 100644
index 0000000..d4ca868
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/asm.s
@@ -0,0 +1,8 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+TEXT �use(SB),NOSPLIT,$0
+ RET
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/asm_linux_386.s
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/asm_linux_386.s b/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/asm_linux_386.s
new file mode 100644
index 0000000..5d3ad9a
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/asm_linux_386.s
@@ -0,0 +1,33 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+//
+// System calls for 386, Linux
+//
+
+// Just jump to package syscall's implementation for all these functions.
+// The runtime may know about them.
+
+TEXT �Syscall(SB),NOSPLIT,$0-28
+ JMP syscall�Syscall(SB)
+
+TEXT �Syscall6(SB),NOSPLIT,$0-40
+ JMP syscall�Syscall6(SB)
+
+TEXT �RawSyscall(SB),NOSPLIT,$0-28
+ JMP syscall�RawSyscall(SB)
+
+TEXT �RawSyscall6(SB),NOSPLIT,$0-40
+ JMP syscall�RawSyscall6(SB)
+
+TEXT �socketcall(SB),NOSPLIT,$0-36
+ JMP syscall�socketcall(SB)
+
+TEXT �rawsocketcall(SB),NOSPLIT,$0-36
+ JMP syscall�rawsocketcall(SB)
+
+TEXT �seek(SB),NOSPLIT,$0-28
+ JMP syscall�seek(SB)
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket.go b/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket.go
new file mode 100644
index 0000000..ffc49a6
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket.go
@@ -0,0 +1,121 @@
+// Package socket implements a minimal set of function of the HCI Socket,
+// which is not yet supported by the Go standard library. Most of the code
+// follow suit the existing code in the standard library. Once it gets
+// supported officially, we can get rid of this package entirely.
+
+package socket
+
+import (
+ "errors"
+ "syscall"
+ "time"
+ "unsafe"
+)
+
+// Bluetooth Protocols
+const (
+ BTPROTO_L2CAP = 0
+ BTPROTO_HCI = 1
+ BTPROTO_SCO = 2
+ BTPROTO_RFCOMM = 3
+ BTPROTO_BNEP = 4
+ BTPROTO_CMTP = 5
+ BTPROTO_HIDP = 6
+ BTPROTO_AVDTP = 7
+)
+
+const (
+ HCI_CHANNEL_RAW = 0
+ HCI_CHANNEL_USER = 1
+ HCI_CHANNEL_MONITOR = 2
+ HCI_CHANNEL_CONTROL = 3
+)
+
+var (
+ ErrSocketOpenFailed = errors.New("unable to open bluetooth socket to device")
+ ErrSocketBindTimeout = errors.New("timeout occured binding to bluetooth device")
+)
+
+type _Socklen uint32
+
+type Sockaddr interface {
+ sockaddr() (ptr unsafe.Pointer, len _Socklen, err error) // lowercase; only we can define Sockaddrs
+}
+
+type rawSockaddrHCI struct {
+ Family uint16
+ Dev uint16
+ Channel uint16
+}
+
+type SockaddrHCI struct {
+ Dev int
+ Channel uint16
+ raw rawSockaddrHCI
+}
+
+const sizeofSockaddrHCI = unsafe.Sizeof(rawSockaddrHCI{})
+
+func (sa *SockaddrHCI) sockaddr() (unsafe.Pointer, _Socklen, error) {
+ if sa.Dev < 0 || sa.Dev > 0xFFFF {
+ return nil, 0, syscall.EINVAL
+ }
+ if sa.Channel < 0 || sa.Channel > 0xFFFF {
+ return nil, 0, syscall.EINVAL
+ }
+ sa.raw.Family = AF_BLUETOOTH
+ sa.raw.Dev = uint16(sa.Dev)
+ sa.raw.Channel = sa.Channel
+ return unsafe.Pointer(&sa.raw), _Socklen(sizeofSockaddrHCI), nil
+}
+
+func Socket(domain, typ, proto int) (int, error) {
+ for i := 0; i < 5; i++ {
+ if fd, err := syscall.Socket(domain, typ, proto); err == nil || err != syscall.EBUSY {
+ return fd, err
+ }
+ time.Sleep(time.Second)
+ }
+ return 0, ErrSocketOpenFailed
+}
+
+func Bind(fd int, sa Sockaddr) (err error) {
+ ptr, n, err := sa.sockaddr()
+ if err != nil {
+ return err
+ }
+ for i := 0; i < 5; i++ {
+ if err = bind(fd, ptr, n); err == nil || err != syscall.EBUSY {
+ return err
+ }
+ time.Sleep(time.Second)
+ }
+ return ErrSocketBindTimeout
+}
+
+// Socket Level
+const (
+ SOL_HCI = 0
+ SOL_L2CAP = 6
+ SOL_SCO = 17
+ SOL_RFCOMM = 18
+
+ SOL_BLUETOOTH = 274
+)
+
+// HCI Socket options
+const (
+ HCI_DATA_DIR = 1
+ HCI_FILTER = 2
+ HCI_TIME_STAMP = 3
+)
+
+type HCIFilter struct {
+ TypeMask uint32
+ EventMask [2]uint32
+ opcode uint16
+}
+
+func SetsockoptFilter(fd int, f *HCIFilter) (err error) {
+ return setsockopt(fd, SOL_HCI, HCI_FILTER, unsafe.Pointer(f), unsafe.Sizeof(*f))
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket_common.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket_common.go b/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket_common.go
new file mode 100644
index 0000000..b01ceeb
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket_common.go
@@ -0,0 +1,24 @@
+// +build !386
+
+package socket
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, _, e1 := syscall.Syscall(syscall.SYS_BIND, uintptr(s), uintptr(addr), uintptr(addrlen))
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
+ _, _, e1 := syscall.Syscall6(syscall.SYS_SETSOCKOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket_darwin.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket_darwin.go b/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket_darwin.go
new file mode 100644
index 0000000..abb96a5
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket_darwin.go
@@ -0,0 +1,6 @@
+// +build darwin
+
+package socket
+
+// For compile time compatibility
+const AF_BLUETOOTH = 0
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket_linux.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket_linux.go b/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket_linux.go
new file mode 100644
index 0000000..4793915
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket_linux.go
@@ -0,0 +1,7 @@
+// +build linux
+
+package socket
+
+import "syscall"
+
+const AF_BLUETOOTH = syscall.AF_BLUETOOTH
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket_linux_386.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket_linux_386.go b/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket_linux_386.go
new file mode 100644
index 0000000..05ca65c
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/linux/socket/socket_linux_386.go
@@ -0,0 +1,31 @@
+// +build linux,386
+
+package socket
+
+import (
+ "syscall"
+ "unsafe"
+)
+
+const (
+ BIND = 2
+ SETSOCKETOPT = 14
+)
+
+func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
+ _, e1 := socketcall(BIND, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) {
+ _, e1 := socketcall(SETSOCKETOPT, uintptr(s), uintptr(level), uintptr(name), uintptr(val), vallen, 0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err syscall.Errno)
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/linux/util/util.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/linux/util/util.go b/newtmgr/vendor/github.com/runtimeco/gatt/linux/util/util.go
new file mode 100644
index 0000000..4933008
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/linux/util/util.go
@@ -0,0 +1,16 @@
+package util
+
+import "encoding/binary"
+
+type order struct{ binary.ByteOrder }
+
+var Order = order{binary.LittleEndian}
+
+func (o order) Int8(b []byte) int8 { return int8(b[0]) }
+func (o order) Uint8(b []byte) uint8 { return b[0] }
+func (o order) MAC(b []byte) [6]byte { return [6]byte{b[5], b[4], b[3], b[2], b[1], b[0]} }
+
+func (o order) PutUint8(b []byte, v uint8) { b[0] = v }
+func (o order) PutMAC(b []byte, m [6]byte) {
+ b[0], b[1], b[2], b[3], b[4], b[5] = m[5], m[4], m[3], m[2], m[1], m[0]
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/option_darwin.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/option_darwin.go b/newtmgr/vendor/github.com/runtimeco/gatt/option_darwin.go
new file mode 100644
index 0000000..617db21
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/option_darwin.go
@@ -0,0 +1,15 @@
+package gatt
+
+const (
+ CentralManager = 0 // Client functions (default)
+ PeripheralManager = 1 // Server functions
+)
+
+// MacDeviceRole specify the XPC connection type to connect blued.
+// THis option can only be used with NewDevice on OS X implementation.
+func MacDeviceRole(r int) Option {
+ return func(d Device) error {
+ d.(*device).role = r
+ return nil
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/option_linux.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/option_linux.go b/newtmgr/vendor/github.com/runtimeco/gatt/option_linux.go
new file mode 100644
index 0000000..bf2360c
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/option_linux.go
@@ -0,0 +1,87 @@
+package gatt
+
+import (
+ "errors"
+ "io"
+
+ "github.com/runtimeco/gatt/linux/cmd"
+)
+
+// LnxDeviceID specifies which HCI device to use.
+// If n is set to -1, all the available HCI devices will be probed.
+// If chk is set to true, LnxDeviceID checks the LE support in the feature list of the HCI device.
+// This is to filter devices that does not support LE. In case some LE driver that doesn't correctly
+// set the LE support in its feature list, user can turn off the check.
+// This option can only be used with NewDevice on Linux implementation.
+func LnxDeviceID(n int, chk bool) Option {
+ return func(d Device) error {
+ d.(*device).devID = n
+ d.(*device).chkLE = chk
+ return nil
+ }
+}
+
+// LnxMaxConnections is an optional parameter.
+// If set, it overrides the default max connections supported.
+// This option can only be used with NewDevice on Linux implementation.
+func LnxMaxConnections(n int) Option {
+ return func(d Device) error {
+ d.(*device).maxConn = n
+ return nil
+ }
+}
+
+// LnxSetAdvertisingEnable sets the advertising data to the HCI device.
+// This option can be used with Option on Linux implementation.
+func LnxSetAdvertisingEnable(en bool) Option {
+ return func(d Device) error {
+ dd := d.(*device)
+ if dd == nil {
+ return errors.New("device is not initialized")
+ }
+ if err := dd.update(); err != nil {
+ return err
+ }
+ return dd.hci.SetAdvertiseEnable(en)
+ }
+}
+
+// LnxSetAdvertisingData sets the advertising data to the HCI device.
+// This option can be used with NewDevice or Option on Linux implementation.
+func LnxSetAdvertisingData(c *cmd.LESetAdvertisingData) Option {
+ return func(d Device) error {
+ d.(*device).advData = c
+ return nil
+ }
+}
+
+// LnxSetScanResponseData sets the scan response data to the HXI device.
+// This option can be used with NewDevice or Option on Linux implementation.
+func LnxSetScanResponseData(c *cmd.LESetScanResponseData) Option {
+ return func(d Device) error {
+ d.(*device).scanResp = c
+ return nil
+ }
+}
+
+// LnxSetAdvertisingParameters sets the advertising parameters to the HCI device.
+// This option can be used with NewDevice or Option on Linux implementation.
+func LnxSetAdvertisingParameters(c *cmd.LESetAdvertisingParameters) Option {
+ return func(d Device) error {
+ d.(*device).advParam = c
+ return nil
+ }
+}
+
+// LnxSendHCIRawCommand sends a raw command to the HCI device
+// This option can be used with NewDevice or Option on Linux implementation.
+func LnxSendHCIRawCommand(c cmd.CmdParam, rsp io.Writer) Option {
+ return func(d Device) error {
+ b, err := d.(*device).SendHCIRawCommand(c)
+ if rsp == nil {
+ return err
+ }
+ rsp.Write(b)
+ return err
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/peripheral.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/peripheral.go b/newtmgr/vendor/github.com/runtimeco/gatt/peripheral.go
new file mode 100644
index 0000000..36ad578
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/peripheral.go
@@ -0,0 +1,102 @@
+package gatt
+
+import (
+ "errors"
+ "sync"
+)
+
+// Peripheral is the interface that represent a remote peripheral device.
+type Peripheral interface {
+ // Device returns the underlying device.
+ Device() Device
+
+ // ID is the platform specific unique ID of the remote peripheral, e.g. MAC for Linux, Peripheral UUID for MacOS.
+ ID() string
+
+ // Name returns the name of the remote peripheral.
+ // This can be the advertised name, if exists, or the GAP device name, which takes priority
+ Name() string
+
+ // Services returnns the services of the remote peripheral which has been discovered.
+ Services() []*Service
+
+ // DiscoverServices discover the specified services of the remote peripheral.
+ // If the specified services is set to nil, all the available services of the remote peripheral are returned.
+ DiscoverServices(s []UUID) ([]*Service, error)
+
+ // DiscoverIncludedServices discovers the specified included services of a service.
+ // If the specified services is set to nil, all the included services of the service are returned.
+ DiscoverIncludedServices(ss []UUID, s *Service) ([]*Service, error)
+
+ // DiscoverCharacteristics discovers the specified characteristics of a service.
+ // If the specified characterstics is set to nil, all the characteristic of the service are returned.
+ DiscoverCharacteristics(c []UUID, s *Service) ([]*Characteristic, error)
+
+ // DiscoverDescriptors discovers the descriptors of a characteristic.
+ // If the specified descriptors is set to nil, all the descriptors of the characteristic are returned.
+ DiscoverDescriptors(d []UUID, c *Characteristic) ([]*Descriptor, error)
+
+ // ReadCharacteristic retrieves the value of a specified characteristic.
+ ReadCharacteristic(c *Characteristic) ([]byte, error)
+
+ // ReadLongCharacteristic retrieves the value of a specified characteristic that is longer than the
+ // MTU.
+ ReadLongCharacteristic(c *Characteristic) ([]byte, error)
+
+ // ReadDescriptor retrieves the value of a specified characteristic descriptor.
+ ReadDescriptor(d *Descriptor) ([]byte, error)
+
+ // WriteCharacteristic writes the value of a characteristic.
+ WriteCharacteristic(c *Characteristic, b []byte, noRsp bool) error
+
+ // WriteDescriptor writes the value of a characteristic descriptor.
+ WriteDescriptor(d *Descriptor, b []byte) error
+
+ // SetNotifyValue sets notifications for the value of a specified characteristic.
+ SetNotifyValue(c *Characteristic, f func(*Characteristic, []byte, error)) error
+
+ // SetIndicateValue sets indications for the value of a specified characteristic.
+ SetIndicateValue(c *Characteristic, f func(*Characteristic, []byte, error)) error
+
+ // ReadRSSI retrieves the current RSSI value for the remote peripheral.
+ ReadRSSI() int
+
+ // SetMTU sets the mtu for the remote peripheral.
+ SetMTU(mtu uint16) error
+}
+
+type subscriber struct {
+ sub map[uint16]subscribefn
+ mu *sync.Mutex
+}
+
+type subscribefn func([]byte, error)
+
+func newSubscriber() *subscriber {
+ return &subscriber{
+ sub: make(map[uint16]subscribefn),
+ mu: &sync.Mutex{},
+ }
+}
+
+func (s *subscriber) subscribe(h uint16, f subscribefn) {
+ s.mu.Lock()
+ s.sub[h] = f
+ s.mu.Unlock()
+}
+
+func (s *subscriber) unsubscribe(h uint16) {
+ s.mu.Lock()
+ delete(s.sub, h)
+ s.mu.Unlock()
+}
+
+func (s *subscriber) fn(h uint16) subscribefn {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ return s.sub[h]
+}
+
+var (
+ ErrInvalidLength = errors.New("invalid length")
+)
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/peripheral_darwin.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/peripheral_darwin.go b/newtmgr/vendor/github.com/runtimeco/gatt/peripheral_darwin.go
new file mode 100644
index 0000000..9174e61
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/peripheral_darwin.go
@@ -0,0 +1,277 @@
+package gatt
+
+import (
+ "errors"
+ "log"
+
+ "github.com/runtimeco/gatt/xpc"
+)
+
+type peripheral struct {
+ // NameChanged is called whenever the peripheral GAP Device name has changed.
+ NameChanged func(Peripheral)
+
+ // ServicesModified is called when one or more service of a peripheral have changed.
+ // A list of invalid service is provided in the parameter.
+ ServicesModified func(Peripheral, []*Service)
+
+ d *device
+ svcs []*Service
+
+ sub *subscriber
+
+ id xpc.UUID
+ name string
+
+ reqc chan message
+ rspc chan message
+ quitc chan struct{}
+}
+
+func NewPeripheral(u UUID) Peripheral { return &peripheral{id: xpc.UUID(u.b)} }
+
+func (p *peripheral) Device() Device { return p.d }
+func (p *peripheral) ID() string { return p.id.String() }
+func (p *peripheral) Name() string { return p.name }
+func (p *peripheral) Services() []*Service { return p.svcs }
+
+func (p *peripheral) DiscoverServices(ss []UUID) ([]*Service, error) {
+ rsp := p.sendReq(45, xpc.Dict{
+ "kCBMsgArgDeviceUUID": p.id,
+ "kCBMsgArgUUIDs": uuidSlice(ss),
+ })
+ if res := rsp.MustGetInt("kCBMsgArgResult"); res != 0 {
+ return nil, attEcode(res)
+ }
+ svcs := []*Service{}
+ for _, xss := range rsp["kCBMsgArgServices"].(xpc.Array) {
+ xs := xss.(xpc.Dict)
+ u := MustParseUUID(xs.MustGetHexBytes("kCBMsgArgUUID"))
+ h := uint16(xs.MustGetInt("kCBMsgArgServiceStartHandle"))
+ endh := uint16(xs.MustGetInt("kCBMsgArgServiceEndHandle"))
+ svcs = append(svcs, &Service{uuid: u, h: h, endh: endh})
+ }
+ p.svcs = svcs
+ return svcs, nil
+}
+
+func (p *peripheral) DiscoverIncludedServices(ss []UUID, s *Service) ([]*Service, error) {
+ rsp := p.sendReq(60, xpc.Dict{
+ "kCBMsgArgDeviceUUID": p.id,
+ "kCBMsgArgServiceStartHandle": s.h,
+ "kCBMsgArgServiceEndHandle": s.endh,
+ "kCBMsgArgUUIDs": uuidSlice(ss),
+ })
+ if res := rsp.MustGetInt("kCBMsgArgResult"); res != 0 {
+ return nil, attEcode(res)
+ }
+ // TODO
+ return nil, notImplemented
+}
+
+func (p *peripheral) DiscoverCharacteristics(cs []UUID, s *Service) ([]*Characteristic, error) {
+ rsp := p.sendReq(62, xpc.Dict{
+ "kCBMsgArgDeviceUUID": p.id,
+ "kCBMsgArgServiceStartHandle": s.h,
+ "kCBMsgArgServiceEndHandle": s.endh,
+ "kCBMsgArgUUIDs": uuidSlice(cs),
+ })
+ if res := rsp.MustGetInt("kCBMsgArgResult"); res != 0 {
+ return nil, attEcode(res)
+ }
+ for _, xcs := range rsp.MustGetArray("kCBMsgArgCharacteristics") {
+ xc := xcs.(xpc.Dict)
+ u := MustParseUUID(xc.MustGetHexBytes("kCBMsgArgUUID"))
+ ch := uint16(xc.MustGetInt("kCBMsgArgCharacteristicHandle"))
+ vh := uint16(xc.MustGetInt("kCBMsgArgCharacteristicValueHandle"))
+ props := Property(xc.MustGetInt("kCBMsgArgCharacteristicProperties"))
+ c := &Characteristic{uuid: u, svc: s, props: props, h: ch, vh: vh}
+ s.chars = append(s.chars, c)
+ }
+ return s.chars, nil
+}
+
+func (p *peripheral) DiscoverDescriptors(ds []UUID, c *Characteristic) ([]*Descriptor, error) {
+ rsp := p.sendReq(70, xpc.Dict{
+ "kCBMsgArgDeviceUUID": p.id,
+ "kCBMsgArgCharacteristicHandle": c.h,
+ "kCBMsgArgCharacteristicValueHandle": c.vh,
+ "kCBMsgArgUUIDs": uuidSlice(ds),
+ })
+ for _, xds := range rsp.MustGetArray("kCBMsgArgDescriptors") {
+ xd := xds.(xpc.Dict)
+ u := MustParseUUID(xd.MustGetHexBytes("kCBMsgArgUUID"))
+ h := uint16(xd.MustGetInt("kCBMsgArgDescriptorHandle"))
+ d := &Descriptor{uuid: u, char: c, h: h}
+ c.descs = append(c.descs, d)
+ }
+ return c.descs, nil
+}
+
+func (p *peripheral) ReadCharacteristic(c *Characteristic) ([]byte, error) {
+ rsp := p.sendReq(65, xpc.Dict{
+ "kCBMsgArgDeviceUUID": p.id,
+ "kCBMsgArgCharacteristicHandle": c.h,
+ "kCBMsgArgCharacteristicValueHandle": c.vh,
+ })
+ if res := rsp.MustGetInt("kCBMsgArgResult"); res != 0 {
+ return nil, attEcode(res)
+ }
+ b := rsp.MustGetBytes("kCBMsgArgData")
+ return b, nil
+}
+
+func (p *peripheral) ReadLongCharacteristic(c *Characteristic) ([]byte, error) {
+ return nil, errors.New("Not implemented")
+}
+
+func (p *peripheral) WriteCharacteristic(c *Characteristic, b []byte, noRsp bool) error {
+ args := xpc.Dict{
+ "kCBMsgArgDeviceUUID": p.id,
+ "kCBMsgArgCharacteristicHandle": c.h,
+ "kCBMsgArgCharacteristicValueHandle": c.vh,
+ "kCBMsgArgData": b,
+ "kCBMsgArgType": map[bool]int{false: 0, true: 1}[noRsp],
+ }
+ if noRsp {
+ p.sendCmd(66, args)
+ return nil
+ }
+ rsp := p.sendReq(65, args)
+ if res := rsp.MustGetInt("kCBMsgArgResult"); res != 0 {
+ return attEcode(res)
+ }
+ return nil
+}
+
+func (p *peripheral) ReadDescriptor(d *Descriptor) ([]byte, error) {
+ rsp := p.sendReq(77, xpc.Dict{
+ "kCBMsgArgDeviceUUID": p.id,
+ "kCBMsgArgDescriptorHandle": d.h,
+ })
+ if res := rsp.MustGetInt("kCBMsgArgResult"); res != 0 {
+ return nil, attEcode(res)
+ }
+ b := rsp.MustGetBytes("kCBMsgArgData")
+ return b, nil
+}
+
+func (p *peripheral) WriteDescriptor(d *Descriptor, b []byte) error {
+ rsp := p.sendReq(78, xpc.Dict{
+ "kCBMsgArgDeviceUUID": p.id,
+ "kCBMsgArgDescriptorHandle": d.h,
+ "kCBMsgArgData": b,
+ })
+ if res := rsp.MustGetInt("kCBMsgArgResult"); res != 0 {
+ return attEcode(res)
+ }
+ return nil
+}
+
+func (p *peripheral) SetNotifyValue(c *Characteristic, f func(*Characteristic, []byte, error)) error {
+ set := 1
+ if f == nil {
+ set = 0
+ }
+ // To avoid race condition, registeration is handled before requesting the server.
+ if f != nil {
+ // Note: when notified, core bluetooth reports characteristic handle, not value's handle.
+ p.sub.subscribe(c.h, func(b []byte, err error) { f(c, b, err) })
+ }
+ rsp := p.sendReq(68, xpc.Dict{
+ "kCBMsgArgDeviceUUID": p.id,
+ "kCBMsgArgCharacteristicHandle": c.h,
+ "kCBMsgArgCharacteristicValueHandle": c.vh,
+ "kCBMsgArgState": set,
+ })
+ if res := rsp.MustGetInt("kCBMsgArgResult"); res != 0 {
+ return attEcode(res)
+ }
+ // To avoid race condition, unregisteration is handled after server responses.
+ if f == nil {
+ p.sub.unsubscribe(c.h)
+ }
+ return nil
+}
+
+func (p *peripheral) SetIndicateValue(c *Characteristic,
+ f func(*Characteristic, []byte, error)) error {
+ // TODO: Implement set indications logic for darwin (https://github.com/runtimeco/gatt/issues/32)
+ return nil
+}
+
+func (p *peripheral) ReadRSSI() int {
+ rsp := p.sendReq(43, xpc.Dict{"kCBMsgArgDeviceUUID": p.id})
+ return rsp.MustGetInt("kCBMsgArgData")
+}
+
+func (p *peripheral) SetMTU(mtu uint16) error {
+ return errors.New("Not implemented")
+}
+
+func uuidSlice(uu []UUID) [][]byte {
+ us := [][]byte{}
+ for _, u := range uu {
+ us = append(us, reverse(u.b))
+ }
+ return us
+}
+
+type message struct {
+ id int
+ args xpc.Dict
+ rspc chan xpc.Dict
+}
+
+func (p *peripheral) sendCmd(id int, args xpc.Dict) {
+ p.reqc <- message{id: id, args: args}
+}
+
+func (p *peripheral) sendReq(id int, args xpc.Dict) xpc.Dict {
+ m := message{id: id, args: args, rspc: make(chan xpc.Dict)}
+ p.reqc <- m
+ return <-m.rspc
+}
+
+func (p *peripheral) loop() {
+ rspc := make(chan message)
+
+ go func() {
+ for {
+ select {
+ case req := <-p.reqc:
+ p.d.sendCBMsg(req.id, req.args)
+ if req.rspc == nil {
+ break
+ }
+ m := <-rspc
+ req.rspc <- m.args
+ case <-p.quitc:
+ return
+ }
+ }
+ }()
+
+ for {
+ select {
+ case rsp := <-p.rspc:
+ // Notification
+ if rsp.id == 71 && rsp.args.GetInt("kCBMsgArgIsNotification", 0) != 0 {
+ // While we're notified with the value's handle, blued reports the characteristic handle.
+ ch := uint16(rsp.args.MustGetInt("kCBMsgArgCharacteristicHandle"))
+ b := rsp.args.MustGetBytes("kCBMsgArgData")
+ f := p.sub.fn(ch)
+ if f == nil {
+ log.Printf("notified by unsubscribed handle")
+ // FIXME: should terminate the connection?
+ } else {
+ go f(b, nil)
+ }
+ break
+ }
+ rspc <- rsp
+ case <-p.quitc:
+ return
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/peripheral_linux.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/peripheral_linux.go b/newtmgr/vendor/github.com/runtimeco/gatt/peripheral_linux.go
new file mode 100644
index 0000000..43ec067
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/peripheral_linux.go
@@ -0,0 +1,448 @@
+package gatt
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "log"
+ "net"
+ "strings"
+
+ "github.com/runtimeco/gatt/linux"
+)
+
+type peripheral struct {
+ // NameChanged is called whenever the peripheral GAP device name has changed.
+ NameChanged func(*peripheral)
+
+ // ServicedModified is called when one or more service of a peripheral have changed.
+ // A list of invalid service is provided in the parameter.
+ ServicesModified func(*peripheral, []*Service)
+
+ d *device
+ svcs []*Service
+
+ sub *subscriber
+
+ mtu uint16
+ l2c io.ReadWriteCloser
+
+ reqc chan message
+ quitc chan struct{}
+
+ pd *linux.PlatData // platform specific data
+}
+
+func (p *peripheral) Device() Device { return p.d }
+func (p *peripheral) ID() string { return strings.ToUpper(net.HardwareAddr(p.pd.Address[:]).String()) }
+func (p *peripheral) Name() string { return p.pd.Name }
+func (p *peripheral) Services() []*Service { return p.svcs }
+
+func finish(op byte, h uint16, b []byte) bool {
+ done := b[0] == attOpError && b[1] == op && b[2] == byte(h) && b[3] == byte(h>>8)
+ e := attEcode(b[4])
+ if e != attEcodeAttrNotFound {
+ // log.Printf("unexpected protocol error: %s", e)
+ // FIXME: terminate the connection
+ }
+ return done
+}
+
+func (p *peripheral) DiscoverServices(s []UUID) ([]*Service, error) {
+ // TODO: implement the UUID filters
+ // p.pd.Conn.Write([]byte{0x02, 0x87, 0x00}) // MTU
+ done := false
+ start := uint16(0x0001)
+ for !done {
+ op := byte(attOpReadByGroupReq)
+ b := make([]byte, 7)
+ b[0] = op
+ binary.LittleEndian.PutUint16(b[1:3], start)
+ binary.LittleEndian.PutUint16(b[3:5], 0xFFFF)
+ binary.LittleEndian.PutUint16(b[5:7], 0x2800)
+
+ b = p.sendReq(op, b)
+ if finish(op, start, b) {
+ break
+ }
+ b = b[1:]
+ l, b := int(b[0]), b[1:]
+ switch {
+ case l == 6 && (len(b)%6 == 0):
+ case l == 20 && (len(b)%20 == 0):
+ default:
+ return nil, ErrInvalidLength
+ }
+
+ for len(b) != 0 {
+ h := binary.LittleEndian.Uint16(b[:2])
+ endh := binary.LittleEndian.Uint16(b[2:4])
+ s := &Service{
+ uuid: UUID{b[4:l]},
+ h: h,
+ endh: endh,
+ }
+ p.svcs = append(p.svcs, s)
+ b = b[l:]
+ done = endh == 0xFFFF
+ start = endh + 1
+ }
+ }
+ return p.svcs, nil
+}
+
+func (p *peripheral) DiscoverIncludedServices(ss []UUID, s *Service) ([]*Service, error) {
+ // TODO
+ return nil, nil
+}
+
+func (p *peripheral) DiscoverCharacteristics(cs []UUID, s *Service) ([]*Characteristic, error) {
+ // TODO: implement the UUID filters
+ done := false
+ start := s.h
+ var prev *Characteristic
+ for !done {
+ op := byte(attOpReadByTypeReq)
+ b := make([]byte, 7)
+ b[0] = op
+ binary.LittleEndian.PutUint16(b[1:3], start)
+ binary.LittleEndian.PutUint16(b[3:5], s.endh)
+ binary.LittleEndian.PutUint16(b[5:7], 0x2803)
+
+ b = p.sendReq(op, b)
+ if finish(op, start, b) {
+ break
+ }
+ b = b[1:]
+
+ l, b := int(b[0]), b[1:]
+ switch {
+ case l == 7 && (len(b)%7 == 0):
+ case l == 21 && (len(b)%21 == 0):
+ default:
+ return nil, ErrInvalidLength
+ }
+
+ for len(b) != 0 {
+ h := binary.LittleEndian.Uint16(b[:2])
+ props := Property(b[2])
+ vh := binary.LittleEndian.Uint16(b[3:5])
+ u := UUID{b[5:l]}
+ s := searchService(p.svcs, h, vh)
+ if s == nil {
+ log.Printf("Can't find service range that contains 0x%04X - 0x%04X", h, vh)
+ return nil, fmt.Errorf("Can't find service range that contains 0x%04X - 0x%04X", h, vh)
+ }
+ c := &Characteristic{
+ uuid: u,
+ svc: s,
+ props: props,
+ h: h,
+ vh: vh,
+ }
+ s.chars = append(s.chars, c)
+ b = b[l:]
+ done = vh == s.endh
+ start = vh + 1
+ if prev != nil {
+ prev.endh = c.h - 1
+ }
+ prev = c
+ }
+ }
+ if len(s.chars) > 1 {
+ s.chars[len(s.chars)-1].endh = s.endh
+ }
+ return s.chars, nil
+}
+
+func (p *peripheral) DiscoverDescriptors(ds []UUID, c *Characteristic) ([]*Descriptor, error) {
+ // TODO: implement the UUID filters
+ done := false
+ start := c.vh + 1
+ for !done {
+ if c.endh == 0 {
+ c.endh = c.svc.endh
+ }
+ op := byte(attOpFindInfoReq)
+ b := make([]byte, 5)
+ b[0] = op
+ binary.LittleEndian.PutUint16(b[1:3], start)
+ binary.LittleEndian.PutUint16(b[3:5], c.endh)
+
+ b = p.sendReq(op, b)
+ if finish(attOpFindInfoReq, start, b) {
+ break
+ }
+ b = b[1:]
+
+ var l int
+ f, b := int(b[0]), b[1:]
+ switch {
+ case f == 1 && (len(b)%4 == 0):
+ l = 4
+ case f == 2 && (len(b)%18 == 0):
+ l = 18
+ default:
+ return nil, ErrInvalidLength
+ }
+
+ for len(b) != 0 {
+ h := binary.LittleEndian.Uint16(b[:2])
+ u := UUID{b[2:l]}
+ d := &Descriptor{uuid: u, h: h, char: c}
+ c.descs = append(c.descs, d)
+ if u.Equal(attrClientCharacteristicConfigUUID) {
+ c.cccd = d
+ }
+ b = b[l:]
+ done = h == c.endh
+ start = h + 1
+ }
+ }
+ return c.descs, nil
+}
+
+func (p *peripheral) ReadCharacteristic(c *Characteristic) ([]byte, error) {
+ b := make([]byte, 3)
+ op := byte(attOpReadReq)
+ b[0] = op
+ binary.LittleEndian.PutUint16(b[1:3], c.vh)
+
+ b = p.sendReq(op, b)
+ b = b[1:]
+ return b, nil
+}
+
+func (p *peripheral) ReadLongCharacteristic(c *Characteristic) ([]byte, error) {
+ // The spec says that a read blob request should fail if the characteristic
+ // is smaller than mtu - 1. To simplify the API, the first read is done
+ // with a regular read request. If the buffer received is equal to mtu -1,
+ // then we read the rest of the data using read blob.
+ firstRead, err := p.ReadCharacteristic(c)
+ if err != nil {
+ return nil, err
+ }
+ if len(firstRead) < int(p.mtu)-1 {
+ return firstRead, nil
+ }
+
+ var buf bytes.Buffer
+ buf.Write(firstRead)
+ off := uint16(len(firstRead))
+ for {
+ b := make([]byte, 5)
+ op := byte(attOpReadBlobReq)
+ b[0] = op
+ binary.LittleEndian.PutUint16(b[1:3], c.vh)
+ binary.LittleEndian.PutUint16(b[3:5], off)
+
+ b = p.sendReq(op, b)
+ b = b[1:]
+ if len(b) == 0 {
+ break
+ }
+ buf.Write(b)
+ off += uint16(len(b))
+ if len(b) < int(p.mtu)-1 {
+ break
+ }
+ }
+ return buf.Bytes(), nil
+}
+
+func (p *peripheral) WriteCharacteristic(c *Characteristic, value []byte, noRsp bool) error {
+ b := make([]byte, 3+len(value))
+ op := byte(attOpWriteReq)
+ b[0] = op
+ if noRsp {
+ b[0] = attOpWriteCmd
+ }
+ binary.LittleEndian.PutUint16(b[1:3], c.vh)
+ copy(b[3:], value)
+
+ if noRsp {
+ p.sendCmd(op, b)
+ return nil
+ }
+ b = p.sendReq(op, b)
+ // TODO: error handling
+ b = b[1:]
+ return nil
+}
+
+func (p *peripheral) ReadDescriptor(d *Descriptor) ([]byte, error) {
+ b := make([]byte, 3)
+ op := byte(attOpReadReq)
+ b[0] = op
+ binary.LittleEndian.PutUint16(b[1:3], d.h)
+
+ b = p.sendReq(op, b)
+ b = b[1:]
+ // TODO: error handling
+ return b, nil
+}
+
+func (p *peripheral) WriteDescriptor(d *Descriptor, value []byte) error {
+ b := make([]byte, 3+len(value))
+ op := byte(attOpWriteReq)
+ b[0] = op
+ binary.LittleEndian.PutUint16(b[1:3], d.h)
+ copy(b[3:], value)
+
+ b = p.sendReq(op, b)
+ b = b[1:]
+ // TODO: error handling
+ return nil
+}
+
+func (p *peripheral) setNotifyValue(c *Characteristic, flag uint16,
+ f func(*Characteristic, []byte, error)) error {
+/*
+ if c.cccd == nil {
+ return errors.New("no cccd") // FIXME
+ }
+ ccc := uint16(0)
+ if f != nil {
+ ccc = flag
+*/
+ p.sub.subscribe(c.vh, func(b []byte, err error) { f(c, b, err) })
+/*
+ }
+ b := make([]byte, 5)
+ op := byte(attOpWriteReq)
+ b[0] = op
+ binary.LittleEndian.PutUint16(b[1:3], c.cccd.h)
+ binary.LittleEndian.PutUint16(b[3:5], ccc)
+
+ b = p.sendReq(op, b)
+ b = b[1:]
+ // TODO: error handling
+ if f == nil {
+ p.sub.unsubscribe(c.vh)
+ }
+*/
+ return nil
+}
+
+func (p *peripheral) SetNotifyValue(c *Characteristic,
+ f func(*Characteristic, []byte, error)) error {
+ return p.setNotifyValue(c, gattCCCNotifyFlag, f)
+}
+
+func (p *peripheral) SetIndicateValue(c *Characteristic,
+ f func(*Characteristic, []byte, error)) error {
+ return p.setNotifyValue(c, gattCCCIndicateFlag, f)
+}
+
+func (p *peripheral) ReadRSSI() int {
+ // TODO: implement
+ return -1
+}
+
+func searchService(ss []*Service, start, end uint16) *Service {
+ for _, s := range ss {
+ if s.h < start && s.endh >= end {
+ return s
+ }
+ }
+ return nil
+}
+
+// TODO: unifiy the message with OS X pots and refactor
+type message struct {
+ op byte
+ b []byte
+ rspc chan []byte
+}
+
+func (p *peripheral) sendCmd(op byte, b []byte) {
+ p.reqc <- message{op: op, b: b}
+}
+
+func (p *peripheral) sendReq(op byte, b []byte) []byte {
+ m := message{op: op, b: b, rspc: make(chan []byte)}
+ p.reqc <- m
+ return <-m.rspc
+}
+
+func (p *peripheral) loop() {
+ // Serialize the request.
+ rspc := make(chan []byte)
+
+ // Dequeue request loop
+ go func() {
+ for {
+ select {
+ case req := <-p.reqc:
+ p.l2c.Write(req.b)
+ if req.rspc == nil {
+ break
+ }
+ r := <-rspc
+ switch reqOp, rspOp := req.b[0], r[0]; {
+ case rspOp == attRspFor[reqOp]:
+ case rspOp == attOpError && r[1] == reqOp:
+ default:
+ log.Printf("Request 0x%02x got a mismatched response: 0x%02x", reqOp, rspOp)
+ // FIXME: terminate the connection?
+ }
+ req.rspc <- r
+ case <-p.quitc:
+ return
+ }
+ }
+ }()
+
+ // L2CAP implementations shall support a minimum MTU size of 48 bytes.
+ // The default value is 672 bytes
+ buf := make([]byte, 672)
+
+ // Handling response or notification/indication
+ for {
+ n, err := p.l2c.Read(buf)
+ if n == 0 || err != nil {
+ close(p.quitc)
+ return
+ }
+
+ b := make([]byte, n)
+ copy(b, buf)
+
+ if (b[0] != attOpHandleNotify) && (b[0] != attOpHandleInd) {
+ rspc <- b
+ continue
+ }
+
+ h := binary.LittleEndian.Uint16(b[1:3])
+ f := p.sub.fn(h)
+ if f == nil {
+ log.Printf("notified by unsubscribed handle")
+ // FIXME: terminate the connection?
+ } else {
+ go f(b[3:], nil)
+ }
+
+ if b[0] == attOpHandleInd {
+ // write aknowledgement for indication
+ p.l2c.Write([]byte{attOpHandleCnf})
+ }
+
+ }
+}
+
+func (p *peripheral) SetMTU(mtu uint16) error {
+ b := make([]byte, 3)
+ op := byte(attOpMtuReq)
+ b[0] = op
+ binary.LittleEndian.PutUint16(b[1:3], uint16(mtu))
+
+ b = p.sendReq(op, b)
+ serverMTU := binary.LittleEndian.Uint16(b[1:3])
+ if serverMTU < mtu {
+ mtu = serverMTU
+ }
+ p.mtu = mtu
+ return nil
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/readme.md
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/readme.md b/newtmgr/vendor/github.com/runtimeco/gatt/readme.md
new file mode 100644
index 0000000..ea3a957
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/readme.md
@@ -0,0 +1,115 @@
+# Package gatt provides a Bluetooth Low Energy GATT implementation.
+
+Gatt (Generic Attribute Profile) is the protocol used to write BLE peripherals (servers) and centrals (clients).
+
+As a peripheral, you can create services, characteristics, and descriptors,
+advertise, accept connections, and handle requests.
+
+As a central, you can scan, connect, discover services, and make requests.
+
+## SETUP
+
+### gatt supports both Linux and OS X.
+
+### On Linux:
+To gain complete and exclusive control of the HCI device, gatt uses
+HCI_CHANNEL_USER (introduced in Linux v3.14) instead of HCI_CHANNEL_RAW.
+Those who must use an older kernel may patch in these relevant commits
+from Marcel Holtmann:
+
+ Bluetooth: Introduce new HCI socket channel for user operation
+ Bluetooth: Introduce user channel flag for HCI devices
+ Bluetooth: Refactor raw socket filter into more readable code
+
+Note that because gatt uses HCI_CHANNEL_USER, once gatt has opened the
+device no other program may access it.
+
+Before starting a gatt program, make sure that your BLE device is down:
+
+ sudo hciconfig
+ sudo hciconfig hci0 down # or whatever hci device you want to use
+
+If you have BlueZ 5.14+ (or aren't sure), stop the built-in
+bluetooth server, which interferes with gatt, e.g.:
+
+ sudo service bluetooth stop
+
+Because gatt programs administer network devices, they must
+either be run as root, or be granted appropriate capabilities:
+
+ sudo <executable>
+ # OR
+ sudo setcap 'cap_net_raw,cap_net_admin=eip' <executable>
+ <executable>
+
+## Usage
+Please see [godoc.org](http://godoc.org/github.com/paypal/gatt) for documentation.
+
+## Examples
+
+### Build and run the examples on a native environment (Linux or OS X)
+
+Go is a compiled language, which means to run the examples you need to build them first.
+
+ # Build the sample server.
+ go build examples/server.go
+ # Start the sample server.
+ sudo ./server
+
+Alternatively, you can use "go run" to build and run the examples in a single step:
+
+ # Build and run the sample server.
+ sudo go run examples/server.go
+
+Discoverer and explorer demonstrates central (client) functions:
+
+ # Discover surrounding peripherals.
+ sudo go run examples/discoverer.go
+
+ # Connect to and explorer a peripheral device.
+ sudo go run examples/explorer.go <peripheral ID>
+
+### Cross-compile and deploy to a target device
+
+ # Build and run the server example on a ARMv5 target device.
+ GOARCH=arm GOARM=5 GOOS=linux go build examples/server.go
+ cp server <target device>
+ # Start the server on the target device
+ sudo ./server
+
+See the server.go, discoverer.go, and explorer.go in the examples/
+directory for writing server or client programs that run on Linux
+and OS X.
+
+Users, especially on Linux platforms, seeking finer-grained control
+over the devices can see the examples/server_lnx.go for the usage
+of Option, which are platform specific.
+
+See the rest of the docs for other options and finer-grained control.
+
+## Note
+Note that some BLE central devices, particularly iOS, may aggressively
+cache results from previous connections. If you change your services or
+characteristics, you may need to reboot the other device to pick up the
+changes. This is a common source of confusion and apparent bugs. For an
+OS X central, see http://stackoverflow.com/questions/20553957.
+
+## Known Issues
+
+Currently OS X vesion does not support subscribing to indications.
+Please check [#32](https://github.com/paypal/gatt/issues/32) for the status of this issue.
+
+## REFERENCES
+
+gatt started life as a port of bleno, to which it is indebted:
+https://github.com/sandeepmistry/bleno. If you are having
+problems with gatt, particularly around installation, issues
+filed with bleno might also be helpful references.
+
+To try out your GATT server, it is useful to experiment with a
+generic BLE client. LightBlue is a good choice. It is available
+free for both iOS and OS X.
+
+gatt is similar to [bleno](https://github.com/sandeepmistry/bleno) and [noble](https://github.com/sandeepmistry/noble), which offer BLE GATT implementations for node.js.
+
+Gatt is released under a [BSD-style license](./LICENSE.md).
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/uuid.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/uuid.go b/newtmgr/vendor/github.com/runtimeco/gatt/uuid.go
new file mode 100644
index 0000000..393e548
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/uuid.go
@@ -0,0 +1,86 @@
+package gatt
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/hex"
+ "fmt"
+ "strings"
+)
+
+// A UUID is a BLE UUID.
+type UUID struct {
+ // Hide the bytes, so that we can enforce that they have length 2 or 16,
+ // and that they are immutable. This simplifies the code and API.
+ b []byte
+}
+
+// UUID16 converts a uint16 (such as 0x1800) to a UUID.
+func UUID16(i uint16) UUID {
+ b := make([]byte, 2)
+ binary.LittleEndian.PutUint16(b, i)
+ return UUID{b}
+}
+
+// ParseUUID parses a standard-format UUID string, such
+// as "1800" or "34DA3AD1-7110-41A1-B1EF-4430F509CDE7".
+func ParseUUID(s string) (UUID, error) {
+ s = strings.Replace(s, "-", "", -1)
+ b, err := hex.DecodeString(s)
+ if err != nil {
+ return UUID{}, err
+ }
+ if err := lenErr(len(b)); err != nil {
+ return UUID{}, err
+ }
+ return UUID{reverse(b)}, nil
+}
+
+// MustParseUUID parses a standard-format UUID string,
+// like ParseUUID, but panics in case of error.
+func MustParseUUID(s string) UUID {
+ u, err := ParseUUID(s)
+ if err != nil {
+ panic(err)
+ }
+ return u
+}
+
+// lenErr returns an error if n is an invalid UUID length.
+func lenErr(n int) error {
+ switch n {
+ case 2, 16:
+ return nil
+ }
+ return fmt.Errorf("UUIDs must have length 2 or 16, got %d", n)
+}
+
+// Len returns the length of the UUID, in bytes.
+// BLE UUIDs are either 2 or 16 bytes.
+func (u UUID) Len() int {
+ return len(u.b)
+}
+
+// String hex-encodes a UUID.
+func (u UUID) String() string {
+ return fmt.Sprintf("%x", reverse(u.b))
+}
+
+// Equal returns a boolean reporting whether v represent the same UUID as u.
+func (u UUID) Equal(v UUID) bool {
+ return bytes.Equal(u.b, v.b)
+}
+
+// reverse returns a reversed copy of u.
+func reverse(u []byte) []byte {
+ // Special-case 16 bit UUIDS for speed.
+ l := len(u)
+ if l == 2 {
+ return []byte{u[1], u[0]}
+ }
+ b := make([]byte, l)
+ for i := 0; i < l/2+1; i++ {
+ b[i], b[l-i-1] = u[l-i-1], u[i]
+ }
+ return b
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/xpc/LICENSE
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/xpc/LICENSE b/newtmgr/vendor/github.com/runtimeco/gatt/xpc/LICENSE
new file mode 100644
index 0000000..766a0a5
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/xpc/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) {{{year}}} {{{fullname}}}
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/xpc/doc.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/xpc/doc.go b/newtmgr/vendor/github.com/runtimeco/gatt/xpc/doc.go
new file mode 100644
index 0000000..d292249
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/xpc/doc.go
@@ -0,0 +1,8 @@
+// Package xpc provides minimal OS X XPC support required for gatt
+//
+// This is adapted from [goble], by Raffaele Sena.
+//
+// http://godoc.org/github.com/raff/goble
+// https://github.com/raff/goble
+
+package xpc
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/xpc/xpc_darwin.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/xpc/xpc_darwin.go b/newtmgr/vendor/github.com/runtimeco/gatt/xpc/xpc_darwin.go
new file mode 100644
index 0000000..2a85a99
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/xpc/xpc_darwin.go
@@ -0,0 +1,350 @@
+package xpc
+
+/*
+#include "xpc_wrapper_darwin.h"
+#include "sys/utsname.h"
+*/
+import "C"
+
+import (
+ "errors"
+ "fmt"
+ "log"
+ r "reflect"
+ "unsafe"
+)
+
+type XPC struct {
+ conn C.xpc_connection_t
+}
+
+func (x *XPC) Send(msg interface{}, verbose bool) {
+ // verbose == true converts the type from bool to C._Bool
+ C.XpcSendMessage(x.conn, goToXpc(msg), true, verbose == true)
+}
+
+//
+// minimal XPC support required for BLE
+//
+
+// a dictionary of things
+type Dict map[string]interface{}
+
+func (d Dict) Contains(k string) bool {
+ _, ok := d[k]
+ return ok
+}
+
+func (d Dict) MustGetDict(k string) Dict {
+ return d[k].(Dict)
+}
+
+func (d Dict) MustGetArray(k string) Array {
+ return d[k].(Array)
+}
+
+func (d Dict) MustGetBytes(k string) []byte {
+ return d[k].([]byte)
+}
+
+func (d Dict) MustGetHexBytes(k string) string {
+ return fmt.Sprintf("%x", d[k].([]byte))
+}
+
+func (d Dict) MustGetInt(k string) int {
+ return int(d[k].(int64))
+}
+
+func (d Dict) MustGetUUID(k string) []byte {
+ u := d[k].(UUID)
+ return u[:]
+}
+
+func (d Dict) GetString(k, defv string) string {
+ if v := d[k]; v != nil {
+ //log.Printf("GetString %s %#v\n", k, v)
+ return v.(string)
+ } else {
+ //log.Printf("GetString %s default %#v\n", k, defv)
+ return defv
+ }
+}
+
+func (d Dict) GetBytes(k string, defv []byte) []byte {
+ if v := d[k]; v != nil {
+ //log.Printf("GetBytes %s %#v\n", k, v)
+ return v.([]byte)
+ } else {
+ //log.Printf("GetBytes %s default %#v\n", k, defv)
+ return defv
+ }
+}
+
+func (d Dict) GetInt(k string, defv int) int {
+ if v := d[k]; v != nil {
+ //log.Printf("GetString %s %#v\n", k, v)
+ return int(v.(int64))
+ } else {
+ //log.Printf("GetString %s default %#v\n", k, defv)
+ return defv
+ }
+}
+
+func (d Dict) GetUUID(k string) UUID {
+ return GetUUID(d[k])
+}
+
+// an array of things
+type Array []interface{}
+
+func (a Array) GetUUID(k int) UUID {
+ return GetUUID(a[k])
+}
+
+// a UUID
+type UUID []byte
+
+func MakeUUID(s string) UUID {
+ var sl []byte
+ fmt.Sscanf(s, "%32x", &sl)
+
+ var uuid [16]byte
+ copy(uuid[:], sl)
+ return UUID(uuid[:])
+}
+
+func (uuid UUID) String() string {
+ return fmt.Sprintf("%x", []byte(uuid))
+}
+
+func GetUUID(v interface{}) UUID {
+ if v == nil {
+ return UUID{}
+ }
+
+ if uuid, ok := v.(UUID); ok {
+ return uuid
+ }
+
+ if bytes, ok := v.([]byte); ok {
+ uuid := UUID{}
+
+ for i, b := range bytes {
+ uuid[i] = b
+ }
+
+ return uuid
+ }
+
+ if bytes, ok := v.([]uint8); ok {
+ uuid := UUID{}
+
+ for i, b := range bytes {
+ uuid[i] = b
+ }
+
+ return uuid
+ }
+
+ log.Fatalf("invalid type for UUID: %#v", v)
+ return UUID{}
+}
+
+var (
+ CONNECTION_INVALID = errors.New("connection invalid")
+ CONNECTION_INTERRUPTED = errors.New("connection interrupted")
+ CONNECTION_TERMINATED = errors.New("connection terminated")
+
+ TYPE_OF_UUID = r.TypeOf(UUID{})
+ TYPE_OF_BYTES = r.TypeOf([]byte{})
+)
+
+type XpcEventHandler interface {
+ HandleXpcEvent(event Dict, err error)
+}
+
+func XpcConnect(service string, eh XpcEventHandler) XPC {
+ cservice := C.CString(service)
+ defer C.free(unsafe.Pointer(cservice))
+ return XPC{conn: C.XpcConnect(cservice, unsafe.Pointer(&eh))}
+}
+
+//export handleXpcEvent
+func handleXpcEvent(event C.xpc_object_t, p unsafe.Pointer) {
+ //log.Printf("handleXpcEvent %#v %#v\n", event, p)
+
+ t := C.xpc_get_type(event)
+ eh := *((*XpcEventHandler)(p))
+
+ if t == C.TYPE_ERROR {
+ if event == C.ERROR_CONNECTION_INVALID {
+ // The client process on the other end of the connection has either
+ // crashed or cancelled the connection. After receiving this error,
+ // the connection is in an invalid state, and you do not need to
+ // call xpc_connection_cancel(). Just tear down any associated state
+ // here.
+ //log.Println("connection invalid")
+ eh.HandleXpcEvent(nil, CONNECTION_INVALID)
+ } else if event == C.ERROR_CONNECTION_INTERRUPTED {
+ //log.Println("connection interrupted")
+ eh.HandleXpcEvent(nil, CONNECTION_INTERRUPTED)
+ } else if event == C.ERROR_CONNECTION_TERMINATED {
+ // Handle per-connection termination cleanup.
+ //log.Println("connection terminated")
+ eh.HandleXpcEvent(nil, CONNECTION_TERMINATED)
+ } else {
+ //log.Println("got some error", event)
+ eh.HandleXpcEvent(nil, fmt.Errorf("%v", event))
+ }
+ } else {
+ eh.HandleXpcEvent(xpcToGo(event).(Dict), nil)
+ }
+}
+
+// goToXpc converts a go object to an xpc object
+func goToXpc(o interface{}) C.xpc_object_t {
+ return valueToXpc(r.ValueOf(o))
+}
+
+// valueToXpc converts a go Value to an xpc object
+//
+// note that not all the types are supported, but only the subset required for Blued
+func valueToXpc(val r.Value) C.xpc_object_t {
+ if !val.IsValid() {
+ return nil
+ }
+
+ var xv C.xpc_object_t
+
+ switch val.Kind() {
+ case r.Int, r.Int8, r.Int16, r.Int32, r.Int64:
+ xv = C.xpc_int64_create(C.int64_t(val.Int()))
+
+ case r.Uint, r.Uint8, r.Uint16, r.Uint32:
+ xv = C.xpc_int64_create(C.int64_t(val.Uint()))
+
+ case r.String:
+ xv = C.xpc_string_create(C.CString(val.String()))
+
+ case r.Map:
+ xv = C.xpc_dictionary_create(nil, nil, 0)
+ for _, k := range val.MapKeys() {
+ v := valueToXpc(val.MapIndex(k))
+ C.xpc_dictionary_set_value(xv, C.CString(k.String()), v)
+ if v != nil {
+ C.xpc_release(v)
+ }
+ }
+
+ case r.Array, r.Slice:
+ if val.Type() == TYPE_OF_UUID {
+ // array of bytes
+ var uuid [16]byte
+ r.Copy(r.ValueOf(uuid[:]), val)
+ xv = C.xpc_uuid_create(C.ptr_to_uuid(unsafe.Pointer(&uuid[0])))
+ } else if val.Type() == TYPE_OF_BYTES {
+ // slice of bytes
+ xv = C.xpc_data_create(unsafe.Pointer(val.Pointer()), C.size_t(val.Len()))
+ } else {
+ xv = C.xpc_array_create(nil, 0)
+ l := val.Len()
+
+ for i := 0; i < l; i++ {
+ v := valueToXpc(val.Index(i))
+ C.xpc_array_append_value(xv, v)
+ if v != nil {
+ C.xpc_release(v)
+ }
+ }
+ }
+
+ case r.Interface, r.Ptr:
+ xv = valueToXpc(val.Elem())
+
+ default:
+ log.Fatalf("unsupported %#v", val.String())
+ }
+
+ return xv
+}
+
+//export arraySet
+func arraySet(u unsafe.Pointer, i C.int, v C.xpc_object_t) {
+ a := *(*Array)(u)
+ a[i] = xpcToGo(v)
+}
+
+//export dictSet
+func dictSet(u unsafe.Pointer, k *C.char, v C.xpc_object_t) {
+ d := *(*Dict)(u)
+ d[C.GoString(k)] = xpcToGo(v)
+}
+
+// xpcToGo converts an xpc object to a go object
+//
+// note that not all the types are supported, but only the subset required for Blued
+func xpcToGo(v C.xpc_object_t) interface{} {
+ t := C.xpc_get_type(v)
+
+ switch t {
+ case C.TYPE_ARRAY:
+ a := make(Array, C.int(C.xpc_array_get_count(v)))
+ C.XpcArrayApply(unsafe.Pointer(&a), v)
+ return a
+
+ case C.TYPE_DATA:
+ return C.GoBytes(C.xpc_data_get_bytes_ptr(v), C.int(C.xpc_data_get_length(v)))
+
+ case C.TYPE_DICT:
+ d := make(Dict)
+ C.XpcDictApply(unsafe.Pointer(&d), v)
+ return d
+
+ case C.TYPE_INT64:
+ return int64(C.xpc_int64_get_value(v))
+
+ case C.TYPE_STRING:
+ return C.GoString(C.xpc_string_get_string_ptr(v))
+
+ case C.TYPE_UUID:
+ a := [16]byte{}
+ C.XpcUUIDGetBytes(unsafe.Pointer(&a), v)
+ return UUID(a[:])
+
+ default:
+ log.Fatalf("unexpected type %#v, value %#v", t, v)
+ }
+
+ return nil
+}
+
+// xpc_release is needed by tests, since they can't use CGO
+func xpc_release(xv C.xpc_object_t) {
+ C.xpc_release(xv)
+}
+
+// this is used to check the OS version
+
+type Utsname struct {
+ Sysname string
+ Nodename string
+ Release string
+ Version string
+ Machine string
+}
+
+func Uname(utsname *Utsname) error {
+ var cstruct C.struct_utsname
+ if err := C.uname(&cstruct); err != 0 {
+ return errors.New("utsname error")
+ }
+
+ // XXX: this may crash if any value is exactly 256 characters (no 0 terminator)
+ utsname.Sysname = C.GoString(&cstruct.sysname[0])
+ utsname.Nodename = C.GoString(&cstruct.nodename[0])
+ utsname.Release = C.GoString(&cstruct.release[0])
+ utsname.Version = C.GoString(&cstruct.version[0])
+ utsname.Machine = C.GoString(&cstruct.machine[0])
+
+ return nil
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/xpc/xpc_wrapper_darwin.c
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/xpc/xpc_wrapper_darwin.c b/newtmgr/vendor/github.com/runtimeco/gatt/xpc/xpc_wrapper_darwin.c
new file mode 100644
index 0000000..7bcb83d
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/xpc/xpc_wrapper_darwin.c
@@ -0,0 +1,85 @@
+#include <dispatch/dispatch.h>
+#include <xpc/xpc.h>
+#include <xpc/connection.h>
+#include <Block.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "_cgo_export.h"
+
+//
+// types and errors are implemented as macros
+// create some real objects to make them accessible to Go
+//
+xpc_type_t TYPE_ERROR = XPC_TYPE_ERROR;
+
+xpc_type_t TYPE_ARRAY = XPC_TYPE_ARRAY;
+xpc_type_t TYPE_DATA = XPC_TYPE_DATA;
+xpc_type_t TYPE_DICT = XPC_TYPE_DICTIONARY;
+xpc_type_t TYPE_INT64 = XPC_TYPE_INT64;
+xpc_type_t TYPE_STRING = XPC_TYPE_STRING;
+xpc_type_t TYPE_UUID = XPC_TYPE_UUID;
+
+xpc_object_t ERROR_CONNECTION_INVALID = (xpc_object_t) XPC_ERROR_CONNECTION_INVALID;
+xpc_object_t ERROR_CONNECTION_INTERRUPTED = (xpc_object_t) XPC_ERROR_CONNECTION_INTERRUPTED;
+xpc_object_t ERROR_CONNECTION_TERMINATED = (xpc_object_t) XPC_ERROR_TERMINATION_IMMINENT;
+
+const ptr_to_uuid_t ptr_to_uuid(void *p) { return (ptr_to_uuid_t)p; }
+
+
+//
+// connect to XPC service
+//
+xpc_connection_t XpcConnect(char *service, void *ctx) {
+ dispatch_queue_t queue = dispatch_queue_create(service, 0);
+ xpc_connection_t conn = xpc_connection_create_mach_service(service, queue, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
+
+ // making a local copy, that should be made "persistent" with the following Block_copy
+ GoInterface ictx = *((GoInterface*)ctx);
+
+ xpc_connection_set_event_handler(conn,
+ Block_copy(^(xpc_object_t event) {
+ handleXpcEvent(event, (void *)&ictx);
+ })
+ );
+
+ xpc_connection_resume(conn);
+ return conn;
+}
+
+void XpcSendMessage(xpc_connection_t conn, xpc_object_t message, bool release, bool reportDelivery) {
+ xpc_connection_send_message(conn, message);
+ xpc_connection_send_barrier(conn, ^{
+ // Block is invoked on connection's target queue
+ // when 'message' has been sent.
+ if (reportDelivery) { // maybe this could be a callback
+ puts("message delivered");
+ }
+ });
+ if (release) {
+ xpc_release(message);
+ }
+}
+
+void XpcArrayApply(void *v, xpc_object_t arr) {
+ xpc_array_apply(arr, ^bool(size_t index, xpc_object_t value) {
+ arraySet(v, index, value);
+ return true;
+ });
+}
+
+void XpcDictApply(void *v, xpc_object_t dict) {
+ xpc_dictionary_apply(dict, ^bool(const char *key, xpc_object_t value) {
+ dictSet(v, (char *)key, value);
+ return true;
+ });
+}
+
+void XpcUUIDGetBytes(void *v, xpc_object_t uuid) {
+ const uint8_t *src = xpc_uuid_get_bytes(uuid);
+ uint8_t *dest = (uint8_t *)v;
+
+ for (int i=0; i < sizeof(uuid_t); i++) {
+ dest[i] = src[i];
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/xpc/xpc_wrapper_darwin.h
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/xpc/xpc_wrapper_darwin.h b/newtmgr/vendor/github.com/runtimeco/gatt/xpc/xpc_wrapper_darwin.h
new file mode 100644
index 0000000..e2cfb5c
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/xpc/xpc_wrapper_darwin.h
@@ -0,0 +1,32 @@
+#ifndef _XPC_WRAPPER_H_
+#define _XPC_WRAPPER_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <xpc/xpc.h>
+
+extern xpc_type_t TYPE_ERROR;
+
+extern xpc_type_t TYPE_ARRAY;
+extern xpc_type_t TYPE_DATA;
+extern xpc_type_t TYPE_DICT;
+extern xpc_type_t TYPE_INT64;
+extern xpc_type_t TYPE_STRING;
+extern xpc_type_t TYPE_UUID;
+
+extern xpc_object_t ERROR_CONNECTION_INVALID;
+extern xpc_object_t ERROR_CONNECTION_INTERRUPTED;
+extern xpc_object_t ERROR_CONNECTION_TERMINATED;
+
+extern xpc_connection_t XpcConnect(char *, void *);
+extern void XpcSendMessage(xpc_connection_t, xpc_object_t, bool, bool);
+extern void XpcArrayApply(void *, xpc_object_t);
+extern void XpcDictApply(void *, xpc_object_t);
+extern void XpcUUIDGetBytes(void *, xpc_object_t);
+
+// the input type for xpc_uuid_create should be uuid_t but CGO instists on unsigned char *
+// typedef uuid_t * ptr_to_uuid_t;
+typedef unsigned char * ptr_to_uuid_t;
+extern const ptr_to_uuid_t ptr_to_uuid(void *p);
+
+#endif
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeinc/gatt/.gitignore
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeinc/gatt/.gitignore b/newtmgr/vendor/github.com/runtimeinc/gatt/.gitignore
deleted file mode 100644
index 7ab0687..0000000
--- a/newtmgr/vendor/github.com/runtimeinc/gatt/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-c.out
-c/*-ble
-sample
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeinc/gatt/LICENSE.md
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeinc/gatt/LICENSE.md b/newtmgr/vendor/github.com/runtimeinc/gatt/LICENSE.md
deleted file mode 100644
index 51c07a6..0000000
--- a/newtmgr/vendor/github.com/runtimeinc/gatt/LICENSE.md
+++ /dev/null
@@ -1,27 +0,0 @@
-Copyright (c) 2014 PayPal Inc. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
- * Neither the name of PayPal Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeinc/gatt/adv.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeinc/gatt/adv.go b/newtmgr/vendor/github.com/runtimeinc/gatt/adv.go
deleted file mode 100644
index 3b8a747..0000000
--- a/newtmgr/vendor/github.com/runtimeinc/gatt/adv.go
+++ /dev/null
@@ -1,234 +0,0 @@
-package gatt
-
-import (
- "errors"
- "log"
-)
-
-// MaxEIRPacketLength is the maximum allowed AdvertisingPacket
-// and ScanResponsePacket length.
-const MaxEIRPacketLength = 31
-
-// ErrEIRPacketTooLong is the error returned when an AdvertisingPacket
-// or ScanResponsePacket is too long.
-var ErrEIRPacketTooLong = errors.New("max packet length is 31")
-
-// Advertising data field types
-const (
- typeFlags = 0x01 // Flags
- typeSomeUUID16 = 0x02 // Incomplete List of 16-bit Service Class UUIDs
- typeAllUUID16 = 0x03 // Complete List of 16-bit Service Class UUIDs
- typeSomeUUID32 = 0x04 // Incomplete List of 32-bit Service Class UUIDs
- typeAllUUID32 = 0x05 // Complete List of 32-bit Service Class UUIDs
- typeSomeUUID128 = 0x06 // Incomplete List of 128-bit Service Class UUIDs
- typeAllUUID128 = 0x07 // Complete List of 128-bit Service Class UUIDs
- typeShortName = 0x08 // Shortened Local Name
- typeCompleteName = 0x09 // Complete Local Name
- typeTxPower = 0x0A // Tx Power Level
- typeClassOfDevice = 0x0D // Class of Device
- typeSimplePairingC192 = 0x0E // Simple Pairing Hash C-192
- typeSimplePairingR192 = 0x0F // Simple Pairing Randomizer R-192
- typeSecManagerTK = 0x10 // Security Manager TK Value
- typeSecManagerOOB = 0x11 // Security Manager Out of Band Flags
- typeSlaveConnInt = 0x12 // Slave Connection Interval Range
- typeServiceSol16 = 0x14 // List of 16-bit Service Solicitation UUIDs
- typeServiceSol128 = 0x15 // List of 128-bit Service Solicitation UUIDs
- typeServiceData16 = 0x16 // Service Data - 16-bit UUID
- typePubTargetAddr = 0x17 // Public Target Address
- typeRandTargetAddr = 0x18 // Random Target Address
- typeAppearance = 0x19 // Appearance
- typeAdvInterval = 0x1A // Advertising Interval
- typeLEDeviceAddr = 0x1B // LE Bluetooth Device Address
- typeLERole = 0x1C // LE Role
- typeServiceSol32 = 0x1F // List of 32-bit Service Solicitation UUIDs
- typeServiceData32 = 0x20 // Service Data - 32-bit UUID
- typeServiceData128 = 0x21 // Service Data - 128-bit UUID
- typeLESecConfirm = 0x22 // LE Secure Connections Confirmation Value
- typeLESecRandom = 0x23 // LE Secure Connections Random Value
- typeManufacturerData = 0xFF // Manufacturer Specific Data
-)
-
-// Advertising type flags
-const (
- flagLimitedDiscoverable = 0x01 // LE Limited Discoverable Mode
- flagGeneralDiscoverable = 0x02 // LE General Discoverable Mode
- flagLEOnly = 0x04 // BR/EDR Not Supported. Bit 37 of LMP Feature Mask Definitions (Page 0)
- flagBothController = 0x08 // Simultaneous LE and BR/EDR to Same Device Capable (Controller).
- flagBothHost = 0x10 // Simultaneous LE and BR/EDR to Same Device Capable (Host).
-)
-
-// FIXME: check the unmarshalling of this data structure.
-type ServiceData struct {
- UUID UUID
- Data []byte
-}
-
-// This is borrowed from core bluetooth.
-// Embedded/Linux folks might be interested in more details.
-type Advertisement struct {
- LocalName string
- ManufacturerData []byte
- ServiceData []ServiceData
- Services []UUID
- OverflowService []UUID
- TxPowerLevel int
- Connectable bool
- SolicitedService []UUID
- AddressType uint8
- Address [6]byte
-}
-
-// This is only used in Linux port.
-func (a *Advertisement) unmarshall(b []byte) error {
-
- // Utility function for creating a list of uuids.
- uuidList := func(u []UUID, d []byte, w int) []UUID {
- for len(d) > 0 {
- u = append(u, UUID{d[:w]})
- d = d[w:]
- }
- return u
- }
-
- for len(b) > 0 {
- if len(b) < 2 {
- return errors.New("invalid advertise data")
- }
- l, t := b[0], b[1]
- if len(b) < int(1+l) {
- return errors.New("invalid advertise data")
- }
- d := b[2 : 1+l]
- switch t {
- case typeFlags:
- // TODO: should we do anything about the discoverability here?
- case typeSomeUUID16:
- a.Services = uuidList(a.Services, d, 2)
- case typeAllUUID16:
- a.Services = uuidList(a.Services, d, 2)
- case typeSomeUUID32:
- a.Services = uuidList(a.Services, d, 4)
- case typeAllUUID32:
- a.Services = uuidList(a.Services, d, 4)
- case typeSomeUUID128:
- a.Services = uuidList(a.Services, d, 16)
- case typeAllUUID128:
- a.Services = uuidList(a.Services, d, 16)
- case typeShortName:
- a.LocalName = string(d)
- case typeCompleteName:
- a.LocalName = string(d)
- case typeTxPower:
- a.TxPowerLevel = int(d[0])
- case typeServiceSol16:
- a.SolicitedService = uuidList(a.SolicitedService, d, 2)
- case typeServiceSol128:
- a.SolicitedService = uuidList(a.SolicitedService, d, 16)
- case typeServiceSol32:
- a.SolicitedService = uuidList(a.SolicitedService, d, 4)
- case typeManufacturerData:
- a.ManufacturerData = make([]byte, len(d))
- copy(a.ManufacturerData, d)
- // case typeServiceData16,
- // case typeServiceData32,
- // case typeServiceData128:
- default:
- log.Printf("DATA: [ % X ]", d)
- }
- b = b[1+l:]
- }
- return nil
-}
-
-// AdvPacket is an utility to help crafting advertisment or scan response data.
-type AdvPacket struct {
- b []byte
-}
-
-// Bytes returns an 31-byte array, which contains up to 31 bytes of the packet.
-func (a *AdvPacket) Bytes() [31]byte {
- b := [31]byte{}
- copy(b[:], a.b)
- return b
-}
-
-// Len returns the length of the packets with a maximum of 31.
-func (a *AdvPacket) Len() int {
- if len(a.b) > 31 {
- return 31
- }
- return len(a.b)
-}
-
-// AppendField appends a BLE advertising packet field.
-// TODO: refuse to append field if it'd make the packet too long.
-func (a *AdvPacket) AppendField(typ byte, b []byte) *AdvPacket {
- // A field consists of len, typ, b.
- // Len is 1 byte for typ plus len(b).
- if len(a.b)+2+len(b) > MaxEIRPacketLength {
- b = b[:MaxEIRPacketLength-len(a.b)-2]
- }
- a.b = append(a.b, byte(len(b)+1))
- a.b = append(a.b, typ)
- a.b = append(a.b, b...)
- return a
-}
-
-// AppendFlags appends a flag field to the packet.
-func (a *AdvPacket) AppendFlags(f byte) *AdvPacket {
- return a.AppendField(typeFlags, []byte{f})
-}
-
-// AppendFlags appends a name field to the packet.
-// If the name fits in the space, it will be append as a complete name field, otherwise a short name field.
-func (a *AdvPacket) AppendName(n string) *AdvPacket {
- typ := byte(typeCompleteName)
- if len(a.b)+2+len(n) > MaxEIRPacketLength {
- typ = byte(typeShortName)
- }
- return a.AppendField(typ, []byte(n))
-}
-
-// AppendManufacturerData appends a manufacturer data field to the packet.
-func (a *AdvPacket) AppendManufacturerData(id uint16, b []byte) *AdvPacket {
- d := append([]byte{uint8(id), uint8(id >> 8)}, b...)
- return a.AppendField(typeManufacturerData, d)
-}
-
-// AppendUUIDFit appends a BLE advertised service UUID
-// packet field if it fits in the packet, and reports whether the UUID fit.
-func (a *AdvPacket) AppendUUIDFit(uu []UUID) bool {
- // Iterate all UUIDs to see if they fit in the packet or not.
- fit, l := true, len(a.b)
- for _, u := range uu {
- if u.Equal(attrGAPUUID) || u.Equal(attrGATTUUID) {
- continue
- }
- l += 2 + u.Len()
- if l > MaxEIRPacketLength {
- fit = false
- break
- }
- }
-
- // Append the UUIDs until they no longer fit.
- for _, u := range uu {
- if u.Equal(attrGAPUUID) || u.Equal(attrGATTUUID) {
- continue
- }
- if len(a.b)+2+u.Len() > MaxEIRPacketLength {
- break
- }
- switch l = u.Len(); {
- case l == 2 && fit:
- a.AppendField(typeAllUUID16, u.b)
- case l == 16 && fit:
- a.AppendField(typeAllUUID128, u.b)
- case l == 2 && !fit:
- a.AppendField(typeSomeUUID16, u.b)
- case l == 16 && !fit:
- a.AppendField(typeSomeUUID128, u.b)
- }
- }
- return fit
-}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeinc/gatt/attr.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeinc/gatt/attr.go b/newtmgr/vendor/github.com/runtimeinc/gatt/attr.go
deleted file mode 100644
index d1ae09d..0000000
--- a/newtmgr/vendor/github.com/runtimeinc/gatt/attr.go
+++ /dev/null
@@ -1,160 +0,0 @@
-package gatt
-
-import "log"
-
-// attr is a BLE attribute. It is not exported;
-// managing attributes is an implementation detail.
-type attr struct {
- h uint16 // attribute handle
- typ UUID // attribute type in UUID
- props Property // attripute property
- secure Property // attribute secure (implementation specific usage)
- value []byte // attribute value
-
- pvt interface{} // point to the corresponsing Serveice/Characteristic/Descriptor
-}
-
-// A attrRange is a contiguous range of attributes.
-type attrRange struct {
- aa []attr
- base uint16 // handle for first attr in aa
-}
-
-const (
- tooSmall = -1
- tooLarge = -2
-)
-
-// idx returns the index into aa corresponding to attr a.
-// If h is too small, idx returns tooSmall (-1).
-// If h is too large, idx returns tooLarge (-2).
-func (r *attrRange) idx(h int) int {
- if h < int(r.base) {
- return tooSmall
- }
- if int(h) >= int(r.base)+len(r.aa) {
- return tooLarge
- }
- return h - int(r.base)
-}
-
-// At returns attr a.
-func (r *attrRange) At(h uint16) (a attr, ok bool) {
- i := r.idx(int(h))
- if i < 0 {
- return attr{}, false
- }
- return r.aa[i], true
-}
-
-// Subrange returns attributes in range [start, end]; it may
-// return an empty slice. Subrange does not panic for
-// out-of-range start or end.
-func (r *attrRange) Subrange(start, end uint16) []attr {
- startidx := r.idx(int(start))
- switch startidx {
- case tooSmall:
- startidx = 0
- case tooLarge:
- return []attr{}
- }
-
- endidx := r.idx(int(end) + 1) // [start, end] includes its upper bound!
- switch endidx {
- case tooSmall:
- return []attr{}
- case tooLarge:
- endidx = len(r.aa)
- }
- return r.aa[startidx:endidx]
-}
-
-func dumpAttributes(aa []attr) {
- log.Printf("Generating attribute table:")
- log.Printf("handle\ttype\tprops\tsecure\tpvt\tvalue")
- for _, a := range aa {
- log.Printf("0x%04X\t0x%s\t0x%02X\t0x%02x\t%T\t[ % X ]",
- a.h, a.typ, int(a.props), int(a.secure), a.pvt, a.value)
- }
-}
-
-func generateAttributes(ss []*Service, base uint16) *attrRange {
- var aa []attr
- h := base
- last := len(ss) - 1
- for i, s := range ss {
- var a []attr
- h, a = generateServiceAttributes(s, h, i == last)
- aa = append(aa, a...)
- }
- dumpAttributes(aa)
- return &attrRange{aa: aa, base: base}
-}
-
-func generateServiceAttributes(s *Service, h uint16, last bool) (uint16, []attr) {
- s.h = h
- // endh set later
- a := attr{
- h: h,
- typ: attrPrimaryServiceUUID,
- value: s.uuid.b,
- props: CharRead,
- pvt: s,
- }
- aa := []attr{a}
- h++
-
- for _, c := range s.Characteristics() {
- var a []attr
- h, a = generateCharAttributes(c, h)
- aa = append(aa, a...)
- }
-
- s.endh = h - 1
- if last {
- h = 0xFFFF
- s.endh = h
- }
-
- return h, aa
-}
-
-func generateCharAttributes(c *Characteristic, h uint16) (uint16, []attr) {
- c.h = h
- c.vh = h + 1
- ca := attr{
- h: c.h,
- typ: attrCharacteristicUUID,
- value: append([]byte{byte(c.props), byte(c.vh), byte((c.vh) >> 8)}, c.uuid.b...),
- props: c.props,
- pvt: c,
- }
- va := attr{
- h: c.vh,
- typ: c.uuid,
- value: c.value,
- props: c.props,
- pvt: c,
- }
- h += 2
-
- aa := []attr{ca, va}
- for _, d := range c.descs {
- aa = append(aa, generateDescAttributes(d, h))
- h++
- }
-
- return h, aa
-}
-
-func generateDescAttributes(d *Descriptor, h uint16) attr {
- d.h = h
- a := attr{
- h: h,
- typ: d.uuid,
- value: d.value,
- props: d.props,
- pvt: d,
- }
- return a
-}