You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2017/03/03 03:19:49 UTC
[7/7] incubator-mynewt-newt git commit: MYNEWT-653 Use runtimeco gatt
fork.
MYNEWT-653 Use runtimeco gatt fork.
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/commit/abf65d3a
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/tree/abf65d3a
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/diff/abf65d3a
Branch: refs/heads/develop
Commit: abf65d3a748ee8b1078ecd13adef096fb863e413
Parents: 671a154
Author: Christopher Collins <cc...@apache.org>
Authored: Thu Mar 2 19:12:27 2017 -0800
Committer: Christopher Collins <cc...@apache.org>
Committed: Thu Mar 2 19:18:41 2017 -0800
----------------------------------------------------------------------
newtmgr/Godeps/Godeps.json | 32 +-
.../vendor/github.com/runtimeco/gatt/.gitignore | 3 +
.../vendor/github.com/runtimeco/gatt/LICENSE.md | 27 +
newtmgr/vendor/github.com/runtimeco/gatt/adv.go | 234 +++++
.../vendor/github.com/runtimeco/gatt/attr.go | 160 +++
.../vendor/github.com/runtimeco/gatt/central.go | 152 +++
.../github.com/runtimeco/gatt/central_darwin.go | 70 ++
.../github.com/runtimeco/gatt/central_linux.go | 446 +++++++++
.../vendor/github.com/runtimeco/gatt/common.go | 399 ++++++++
.../vendor/github.com/runtimeco/gatt/const.go | 153 +++
.../vendor/github.com/runtimeco/gatt/device.go | 161 +++
.../github.com/runtimeco/gatt/device_darwin.go | 513 ++++++++++
.../github.com/runtimeco/gatt/device_linux.go | 240 +++++
newtmgr/vendor/github.com/runtimeco/gatt/doc.go | 88 ++
.../github.com/runtimeco/gatt/known_uuid.go | 122 +++
.../runtimeco/gatt/l2cap_writer_linux.go | 156 +++
.../github.com/runtimeco/gatt/linux/cmd/cmd.go | 995 +++++++++++++++++++
.../github.com/runtimeco/gatt/linux/const.go | 21 +
.../github.com/runtimeco/gatt/linux/device.go | 109 ++
.../github.com/runtimeco/gatt/linux/devices.go | 58 ++
.../github.com/runtimeco/gatt/linux/doc.go | 5 +
.../github.com/runtimeco/gatt/linux/evt/evt.go | 382 +++++++
.../runtimeco/gatt/linux/gioctl/LICENSE.md | 22 +
.../runtimeco/gatt/linux/gioctl/README.md | 12 +
.../runtimeco/gatt/linux/gioctl/ioctl.go | 57 ++
.../github.com/runtimeco/gatt/linux/hci.go | 400 ++++++++
.../github.com/runtimeco/gatt/linux/l2cap.go | 174 ++++
.../runtimeco/gatt/linux/socket/asm.s | 8 +
.../runtimeco/gatt/linux/socket/asm_linux_386.s | 33 +
.../runtimeco/gatt/linux/socket/socket.go | 121 +++
.../gatt/linux/socket/socket_common.go | 24 +
.../gatt/linux/socket/socket_darwin.go | 6 +
.../runtimeco/gatt/linux/socket/socket_linux.go | 7 +
.../gatt/linux/socket/socket_linux_386.go | 31 +
.../runtimeco/gatt/linux/util/util.go | 16 +
.../github.com/runtimeco/gatt/option_darwin.go | 15 +
.../github.com/runtimeco/gatt/option_linux.go | 87 ++
.../github.com/runtimeco/gatt/peripheral.go | 102 ++
.../runtimeco/gatt/peripheral_darwin.go | 277 ++++++
.../runtimeco/gatt/peripheral_linux.go | 448 +++++++++
.../vendor/github.com/runtimeco/gatt/readme.md | 115 +++
.../vendor/github.com/runtimeco/gatt/uuid.go | 86 ++
.../github.com/runtimeco/gatt/xpc/LICENSE | 21 +
.../vendor/github.com/runtimeco/gatt/xpc/doc.go | 8 +
.../github.com/runtimeco/gatt/xpc/xpc_darwin.go | 350 +++++++
.../runtimeco/gatt/xpc/xpc_wrapper_darwin.c | 85 ++
.../runtimeco/gatt/xpc/xpc_wrapper_darwin.h | 32 +
.../github.com/runtimeinc/gatt/.gitignore | 3 -
.../github.com/runtimeinc/gatt/LICENSE.md | 27 -
.../vendor/github.com/runtimeinc/gatt/adv.go | 234 -----
.../vendor/github.com/runtimeinc/gatt/attr.go | 160 ---
.../github.com/runtimeinc/gatt/central.go | 152 ---
.../runtimeinc/gatt/central_darwin.go | 70 --
.../github.com/runtimeinc/gatt/central_linux.go | 446 ---------
.../vendor/github.com/runtimeinc/gatt/common.go | 399 --------
.../vendor/github.com/runtimeinc/gatt/const.go | 153 ---
.../vendor/github.com/runtimeinc/gatt/device.go | 161 ---
.../github.com/runtimeinc/gatt/device_darwin.go | 513 ----------
.../github.com/runtimeinc/gatt/device_linux.go | 240 -----
.../vendor/github.com/runtimeinc/gatt/doc.go | 88 --
.../github.com/runtimeinc/gatt/known_uuid.go | 122 ---
.../runtimeinc/gatt/l2cap_writer_linux.go | 156 ---
.../github.com/runtimeinc/gatt/linux/cmd/cmd.go | 995 -------------------
.../github.com/runtimeinc/gatt/linux/const.go | 21 -
.../github.com/runtimeinc/gatt/linux/device.go | 109 --
.../github.com/runtimeinc/gatt/linux/devices.go | 58 --
.../github.com/runtimeinc/gatt/linux/doc.go | 5 -
.../github.com/runtimeinc/gatt/linux/evt/evt.go | 382 -------
.../runtimeinc/gatt/linux/gioctl/LICENSE.md | 22 -
.../runtimeinc/gatt/linux/gioctl/README.md | 12 -
.../runtimeinc/gatt/linux/gioctl/ioctl.go | 57 --
.../github.com/runtimeinc/gatt/linux/hci.go | 400 --------
.../github.com/runtimeinc/gatt/linux/l2cap.go | 174 ----
.../runtimeinc/gatt/linux/socket/asm.s | 8 -
.../gatt/linux/socket/asm_linux_386.s | 33 -
.../runtimeinc/gatt/linux/socket/socket.go | 121 ---
.../gatt/linux/socket/socket_common.go | 24 -
.../gatt/linux/socket/socket_darwin.go | 6 -
.../gatt/linux/socket/socket_linux.go | 7 -
.../gatt/linux/socket/socket_linux_386.go | 31 -
.../runtimeinc/gatt/linux/util/util.go | 16 -
.../github.com/runtimeinc/gatt/option_darwin.go | 15 -
.../github.com/runtimeinc/gatt/option_linux.go | 87 --
.../github.com/runtimeinc/gatt/peripheral.go | 102 --
.../runtimeinc/gatt/peripheral_darwin.go | 277 ------
.../runtimeinc/gatt/peripheral_linux.go | 448 ---------
.../vendor/github.com/runtimeinc/gatt/readme.md | 115 ---
.../vendor/github.com/runtimeinc/gatt/uuid.go | 86 --
.../github.com/runtimeinc/gatt/xpc/LICENSE | 21 -
.../github.com/runtimeinc/gatt/xpc/doc.go | 8 -
.../runtimeinc/gatt/xpc/xpc_darwin.go | 350 -------
.../runtimeinc/gatt/xpc/xpc_wrapper_darwin.c | 85 --
.../runtimeinc/gatt/xpc/xpc_wrapper_darwin.h | 32 -
93 files changed, 7061 insertions(+), 7033 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/Godeps/Godeps.json
----------------------------------------------------------------------
diff --git a/newtmgr/Godeps/Godeps.json b/newtmgr/Godeps/Godeps.json
index b2571e8..b486ebe 100644
--- a/newtmgr/Godeps/Godeps.json
+++ b/newtmgr/Godeps/Godeps.json
@@ -38,8 +38,8 @@
"Rev": "f3009df150dadf309fdee4a54ed65c124afad715"
},
{
- "ImportPath": "github.com/runtimeinc/gatt",
- "Rev": "a8b4c64987af1491ef629e5ec45d3fc47df29eb9"
+ "ImportPath": "github.com/runtimeco/gatt",
+ "Rev": "ceaca1e3d4b698ce4f610b8c71ebc5cde9ad40dd"
},
{
"ImportPath": "github.com/runtimeinc/gatt/linux",
@@ -116,6 +116,34 @@
"ImportPath": "mynewt.apache.org/newt/yaml",
"Comment": "pre_sterly_refactor-137-gfcecea4",
"Rev": "fcecea4b13ab467168e936a51ef01695833644d8"
+ },
+ {
+ "ImportPath": "github.com/runtimeco/gatt/linux",
+ "Rev": "ceaca1e3d4b698ce4f610b8c71ebc5cde9ad40dd"
+ },
+ {
+ "ImportPath": "github.com/runtimeco/gatt/linux/cmd",
+ "Rev": "ceaca1e3d4b698ce4f610b8c71ebc5cde9ad40dd"
+ },
+ {
+ "ImportPath": "github.com/runtimeco/gatt/xpc",
+ "Rev": "ceaca1e3d4b698ce4f610b8c71ebc5cde9ad40dd"
+ },
+ {
+ "ImportPath": "github.com/runtimeco/gatt/linux/evt",
+ "Rev": "ceaca1e3d4b698ce4f610b8c71ebc5cde9ad40dd"
+ },
+ {
+ "ImportPath": "github.com/runtimeco/gatt/linux/gioctl",
+ "Rev": "ceaca1e3d4b698ce4f610b8c71ebc5cde9ad40dd"
+ },
+ {
+ "ImportPath": "github.com/runtimeco/gatt/linux/socket",
+ "Rev": "ceaca1e3d4b698ce4f610b8c71ebc5cde9ad40dd"
+ },
+ {
+ "ImportPath": "github.com/runtimeco/gatt/linux/util",
+ "Rev": "ceaca1e3d4b698ce4f610b8c71ebc5cde9ad40dd"
}
]
}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/.gitignore
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/.gitignore b/newtmgr/vendor/github.com/runtimeco/gatt/.gitignore
new file mode 100644
index 0000000..7ab0687
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/.gitignore
@@ -0,0 +1,3 @@
+c.out
+c/*-ble
+sample
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/LICENSE.md
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/LICENSE.md b/newtmgr/vendor/github.com/runtimeco/gatt/LICENSE.md
new file mode 100644
index 0000000..51c07a6
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/LICENSE.md
@@ -0,0 +1,27 @@
+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/runtimeco/gatt/adv.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/adv.go b/newtmgr/vendor/github.com/runtimeco/gatt/adv.go
new file mode 100644
index 0000000..3b8a747
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/adv.go
@@ -0,0 +1,234 @@
+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/runtimeco/gatt/attr.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/attr.go b/newtmgr/vendor/github.com/runtimeco/gatt/attr.go
new file mode 100644
index 0000000..d1ae09d
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/attr.go
@@ -0,0 +1,160 @@
+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
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/central.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/central.go b/newtmgr/vendor/github.com/runtimeco/gatt/central.go
new file mode 100644
index 0000000..55bd2c1
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/central.go
@@ -0,0 +1,152 @@
+package gatt
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "sync"
+)
+
+// Central is the interface that represent a remote central device.
+type Central interface {
+ ID() string // ID returns platform specific ID of the remote central device.
+ Close() error // Close disconnects the connection.
+ MTU() int // MTU returns the current connection mtu.
+}
+
+type ResponseWriter interface {
+ // Write writes data to return as the characteristic value.
+ Write([]byte) (int, error)
+
+ // SetStatus reports the result of the read operation. See the Status* constants.
+ SetStatus(byte)
+}
+
+// responseWriter is the default implementation of ResponseWriter.
+type responseWriter struct {
+ capacity int
+ buf *bytes.Buffer
+ status byte
+}
+
+func newResponseWriter(c int) *responseWriter {
+ return &responseWriter{
+ capacity: c,
+ buf: new(bytes.Buffer),
+ status: StatusSuccess,
+ }
+}
+
+func (w *responseWriter) Write(b []byte) (int, error) {
+ if avail := w.capacity - w.buf.Len(); avail < len(b) {
+ return 0, fmt.Errorf("requested write %d bytes, %d available", len(b), avail)
+ }
+ return w.buf.Write(b)
+}
+
+func (w *responseWriter) SetStatus(status byte) { w.status = status }
+func (w *responseWriter) bytes() []byte { return w.buf.Bytes() }
+
+// A ReadHandler handles GATT read requests.
+type ReadHandler interface {
+ ServeRead(resp ResponseWriter, req *ReadRequest)
+}
+
+// ReadHandlerFunc is an adapter to allow the use of
+// ordinary functions as ReadHandlers. If f is a function
+// with the appropriate signature, ReadHandlerFunc(f) is a
+// ReadHandler that calls f.
+type ReadHandlerFunc func(resp ResponseWriter, req *ReadRequest)
+
+// ServeRead returns f(r, maxlen, offset).
+func (f ReadHandlerFunc) ServeRead(resp ResponseWriter, req *ReadRequest) {
+ f(resp, req)
+}
+
+// A WriteHandler handles GATT write requests.
+// Write and WriteNR requests are presented identically;
+// the server will ensure that a response is sent if appropriate.
+type WriteHandler interface {
+ ServeWrite(r Request, data []byte) (status byte)
+}
+
+// WriteHandlerFunc is an adapter to allow the use of
+// ordinary functions as WriteHandlers. If f is a function
+// with the appropriate signature, WriteHandlerFunc(f) is a
+// WriteHandler that calls f.
+type WriteHandlerFunc func(r Request, data []byte) byte
+
+// ServeWrite returns f(r, data).
+func (f WriteHandlerFunc) ServeWrite(r Request, data []byte) byte {
+ return f(r, data)
+}
+
+// A NotifyHandler handles GATT notification requests.
+// Notifications can be sent using the provided notifier.
+type NotifyHandler interface {
+ ServeNotify(r Request, n Notifier)
+}
+
+// NotifyHandlerFunc is an adapter to allow the use of
+// ordinary functions as NotifyHandlers. If f is a function
+// with the appropriate signature, NotifyHandlerFunc(f) is a
+// NotifyHandler that calls f.
+type NotifyHandlerFunc func(r Request, n Notifier)
+
+// ServeNotify calls f(r, n).
+func (f NotifyHandlerFunc) ServeNotify(r Request, n Notifier) {
+ f(r, n)
+}
+
+// A Notifier provides a means for a GATT server to send
+// notifications about value changes to a connected device.
+// Notifiers are provided by NotifyHandlers.
+type Notifier interface {
+ // Write sends data to the central.
+ Write(data []byte) (int, error)
+
+ // Done reports whether the central has requested not to
+ // receive any more notifications with this notifier.
+ Done() bool
+
+ // Cap returns the maximum number of bytes that may be sent
+ // in a single notification.
+ Cap() int
+}
+
+type notifier struct {
+ central *central
+ a *attr
+ maxlen int
+ donemu sync.RWMutex
+ done bool
+}
+
+func newNotifier(c *central, a *attr, maxlen int) *notifier {
+ return ¬ifier{central: c, a: a, maxlen: maxlen}
+}
+
+func (n *notifier) Write(b []byte) (int, error) {
+ n.donemu.RLock()
+ defer n.donemu.RUnlock()
+ if n.done {
+ return 0, errors.New("central stopped notifications")
+ }
+ return n.central.sendNotification(n.a, b)
+}
+
+func (n *notifier) Cap() int {
+ return n.maxlen
+}
+
+func (n *notifier) Done() bool {
+ n.donemu.RLock()
+ defer n.donemu.RUnlock()
+ return n.done
+}
+
+func (n *notifier) stop() {
+ n.donemu.Lock()
+ n.done = true
+ n.donemu.Unlock()
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/central_darwin.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/central_darwin.go b/newtmgr/vendor/github.com/runtimeco/gatt/central_darwin.go
new file mode 100644
index 0000000..47faa2e
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/central_darwin.go
@@ -0,0 +1,70 @@
+package gatt
+
+import (
+ "sync"
+
+ "github.com/runtimeco/gatt/xpc"
+)
+
+type central struct {
+ dev *device
+ uuid UUID
+ mtu int
+ notifiers map[uint16]*notifier
+ notifiersmu *sync.Mutex
+}
+
+func newCentral(d *device, u UUID) *central {
+ return ¢ral{
+ dev: d,
+ mtu: 23,
+ uuid: u,
+ notifiers: make(map[uint16]*notifier),
+ notifiersmu: &sync.Mutex{},
+ }
+}
+
+func (c *central) ID() string { return c.uuid.String() }
+func (c *central) Close() error { return nil }
+func (c *central) MTU() int { return c.mtu }
+
+func (c *central) sendNotification(a *attr, b []byte) (int, error) {
+ data := make([]byte, len(b))
+ copy(data, b) // have to make a copy, why?
+ c.dev.sendCmd(15, xpc.Dict{
+ // "kCBMsgArgUUIDs": [][]byte{reverse(c.uuid.b)}, // connection interrupted
+ // "kCBMsgArgUUIDs": [][]byte{c.uuid.b}, // connection interrupted
+ // "kCBMsgArgUUIDs": []xpc.UUID{xpc.UUID(reverse(c.uuid.b))},
+ // "kCBMsgArgUUIDs": []xpc.UUID{xpc.UUID(c.uuid.b)},
+ // "kCBMsgArgUUIDs": reverse(c.uuid.b),
+ //
+ // FIXME: Sigh... tried to targeting the central, but couldn't get work.
+ // So, broadcast to all subscribed centrals. Either of the following works.
+ // "kCBMsgArgUUIDs": []xpc.UUID{},
+ "kCBMsgArgUUIDs": [][]byte{},
+ "kCBMsgArgAttributeID": a.h,
+ "kCBMsgArgData": data,
+ })
+ return len(b), nil
+}
+
+func (c *central) startNotify(a *attr, maxlen int) {
+ c.notifiersmu.Lock()
+ defer c.notifiersmu.Unlock()
+ if _, found := c.notifiers[a.h]; found {
+ return
+ }
+ n := newNotifier(c, a, maxlen)
+ c.notifiers[a.h] = n
+ char := a.pvt.(*Characteristic)
+ go char.nhandler.ServeNotify(Request{Central: c}, n)
+}
+
+func (c *central) stopNotify(a *attr) {
+ c.notifiersmu.Lock()
+ defer c.notifiersmu.Unlock()
+ if n, found := c.notifiers[a.h]; found {
+ n.stop()
+ delete(c.notifiers, a.h)
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/central_linux.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/central_linux.go b/newtmgr/vendor/github.com/runtimeco/gatt/central_linux.go
new file mode 100644
index 0000000..3ae6994
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/central_linux.go
@@ -0,0 +1,446 @@
+package gatt
+
+import (
+ "encoding/binary"
+ "io"
+ "net"
+ "sync"
+)
+
+type security int
+
+const (
+ securityLow = iota
+ securityMed
+ securityHigh
+)
+
+type central struct {
+ attrs *attrRange
+ mtu uint16
+ addr net.HardwareAddr
+ security security
+ l2conn io.ReadWriteCloser
+ notifiers map[uint16]*notifier
+ notifiersmu *sync.Mutex
+}
+
+func newCentral(a *attrRange, addr net.HardwareAddr, l2conn io.ReadWriteCloser) *central {
+ return ¢ral{
+ attrs: a,
+ mtu: 23,
+ addr: addr,
+ security: securityLow,
+ l2conn: l2conn,
+ notifiers: make(map[uint16]*notifier),
+ notifiersmu: &sync.Mutex{},
+ }
+}
+
+func (c *central) ID() string {
+ return c.addr.String()
+}
+
+func (c *central) Close() error {
+ c.notifiersmu.Lock()
+ defer c.notifiersmu.Unlock()
+ for _, n := range c.notifiers {
+ n.stop()
+ }
+ return c.l2conn.Close()
+}
+
+func (c *central) MTU() int {
+ return int(c.mtu)
+}
+
+func (c *central) loop() {
+ for {
+ // L2CAP implementations shall support a minimum MTU size of 48 bytes.
+ // The default value is 672 bytes
+ b := make([]byte, 672)
+ n, err := c.l2conn.Read(b)
+ if n == 0 || err != nil {
+ c.Close()
+ break
+ }
+ if rsp := c.handleReq(b[:n]); rsp != nil {
+ c.l2conn.Write(rsp)
+ }
+ }
+}
+
+// handleReq dispatches a raw request from the central shim
+// to an appropriate handler, based on its type.
+// It panics if len(b) == 0.
+func (c *central) handleReq(b []byte) []byte {
+ var resp []byte
+ switch reqType, req := b[0], b[1:]; reqType {
+ case attOpMtuReq:
+ resp = c.handleMTU(req)
+ case attOpFindInfoReq:
+ resp = c.handleFindInfo(req)
+ case attOpFindByTypeValueReq:
+ resp = c.handleFindByTypeValue(req)
+ case attOpReadByTypeReq:
+ resp = c.handleReadByType(req)
+ case attOpReadReq:
+ resp = c.handleRead(req)
+ case attOpReadBlobReq:
+ resp = c.handleReadBlob(req)
+ case attOpReadByGroupReq:
+ resp = c.handleReadByGroup(req)
+ case attOpWriteReq, attOpWriteCmd:
+ resp = c.handleWrite(reqType, req)
+ case attOpReadMultiReq, attOpPrepWriteReq, attOpExecWriteReq, attOpSignedWriteCmd:
+ fallthrough
+ default:
+ resp = attErrorRsp(reqType, 0x0000, attEcodeReqNotSupp)
+ }
+ return resp
+}
+
+func (c *central) handleMTU(b []byte) []byte {
+ c.mtu = binary.LittleEndian.Uint16(b[:2])
+ if c.mtu < 23 {
+ c.mtu = 23
+ }
+ if c.mtu >= 256 {
+ c.mtu = 256
+ }
+ return []byte{attOpMtuRsp, uint8(c.mtu), uint8(c.mtu >> 8)}
+}
+
+// REQ: FindInfoReq(0x04), StartHandle, EndHandle
+// RSP: FindInfoRsp(0x05), UUIDFormat, Handle, UUID, Handle, UUID, ...
+func (c *central) handleFindInfo(b []byte) []byte {
+ start, end := readHandleRange(b[:4])
+
+ w := newL2capWriter(c.mtu)
+ w.WriteByteFit(attOpFindInfoRsp)
+
+ uuidLen := -1
+ for _, a := range c.attrs.Subrange(start, end) {
+ if uuidLen == -1 {
+ uuidLen = a.typ.Len()
+ if uuidLen == 2 {
+ w.WriteByteFit(0x01) // TODO: constants for 16bit vs 128bit uuid magic numbers here
+ } else {
+ w.WriteByteFit(0x02)
+ }
+ }
+ if a.typ.Len() != uuidLen {
+ break
+ }
+ w.Chunk()
+ w.WriteUint16Fit(a.h)
+ w.WriteUUIDFit(a.typ)
+ if ok := w.Commit(); !ok {
+ break
+ }
+ }
+
+ if uuidLen == -1 {
+ return attErrorRsp(attOpFindInfoReq, start, attEcodeAttrNotFound)
+ }
+ return w.Bytes()
+}
+
+// REQ: FindByTypeValueReq(0x06), StartHandle, EndHandle, Type(UUID), Value
+// RSP: FindByTypeValueRsp(0x07), AttrHandle, GroupEndHandle, AttrHandle, GroupEndHandle, ...
+func (c *central) handleFindByTypeValue(b []byte) []byte {
+ start, end := readHandleRange(b[:4])
+ t := UUID{b[4:6]}
+ u := UUID{b[6:]}
+
+ // Only support the ATT ReadByGroupReq for GATT Primary Service Discovery.
+ // More sepcifically, the "Discover Primary Services By Service UUID" sub-procedure
+ if !t.Equal(attrPrimaryServiceUUID) {
+ return attErrorRsp(attOpFindByTypeValueReq, start, attEcodeAttrNotFound)
+ }
+
+ w := newL2capWriter(c.mtu)
+ w.WriteByteFit(attOpFindByTypeValueRsp)
+
+ var wrote bool
+ for _, a := range c.attrs.Subrange(start, end) {
+ if !a.typ.Equal(attrPrimaryServiceUUID) {
+ continue
+ }
+ if !(UUID{a.value}.Equal(u)) {
+ continue
+ }
+ s := a.pvt.(*Service)
+ w.Chunk()
+ w.WriteUint16Fit(s.h)
+ w.WriteUint16Fit(s.endh)
+ if ok := w.Commit(); !ok {
+ break
+ }
+ wrote = true
+ }
+ if !wrote {
+ return attErrorRsp(attOpFindByTypeValueReq, start, attEcodeAttrNotFound)
+ }
+
+ return w.Bytes()
+}
+
+// REQ: ReadByType(0x08), StartHandle, EndHandle, Type(UUID)
+// RSP: ReadByType(0x09), LenOfEachDataField, DataField, DataField, ...
+func (c *central) handleReadByType(b []byte) []byte {
+ start, end := readHandleRange(b[:4])
+ t := UUID{b[4:]}
+
+ w := newL2capWriter(c.mtu)
+ w.WriteByteFit(attOpReadByTypeRsp)
+ uuidLen := -1
+ for _, a := range c.attrs.Subrange(start, end) {
+ if !a.typ.Equal(t) {
+ continue
+ }
+ if (a.secure&CharRead) != 0 && c.security > securityLow {
+ return attErrorRsp(attOpReadByTypeReq, start, attEcodeAuthentication)
+ }
+ v := a.value
+ if v == nil {
+ rsp := newResponseWriter(int(c.mtu - 1))
+ req := &ReadRequest{
+ Request: Request{Central: c},
+ Cap: int(c.mtu - 1),
+ Offset: 0,
+ }
+ if c, ok := a.pvt.(*Characteristic); ok {
+ c.rhandler.ServeRead(rsp, req)
+ } else if d, ok := a.pvt.(*Descriptor); ok {
+ d.rhandler.ServeRead(rsp, req)
+ }
+ v = rsp.bytes()
+ }
+ if uuidLen == -1 {
+ uuidLen = len(v)
+ w.WriteByteFit(byte(uuidLen) + 2)
+ }
+ if len(v) != uuidLen {
+ break
+ }
+ w.Chunk()
+ w.WriteUint16Fit(a.h)
+ w.WriteFit(v)
+ if ok := w.Commit(); !ok {
+ break
+ }
+ }
+ if uuidLen == -1 {
+ return attErrorRsp(attOpReadByTypeReq, start, attEcodeAttrNotFound)
+ }
+ return w.Bytes()
+}
+
+// REQ: ReadReq(0x0A), Handle
+// RSP: ReadRsp(0x0B), Value
+func (c *central) handleRead(b []byte) []byte {
+ h := binary.LittleEndian.Uint16(b)
+ a, ok := c.attrs.At(h)
+ if !ok {
+ return attErrorRsp(attOpReadReq, h, attEcodeInvalidHandle)
+ }
+ if a.props&CharRead == 0 {
+ return attErrorRsp(attOpReadReq, h, attEcodeReadNotPerm)
+ }
+ if a.secure&CharRead != 0 && c.security > securityLow {
+ return attErrorRsp(attOpReadReq, h, attEcodeAuthentication)
+ }
+ v := a.value
+ if v == nil {
+ req := &ReadRequest{
+ Request: Request{Central: c},
+ Cap: int(c.mtu - 1),
+ Offset: 0,
+ }
+ rsp := newResponseWriter(int(c.mtu - 1))
+ if c, ok := a.pvt.(*Characteristic); ok {
+ c.rhandler.ServeRead(rsp, req)
+ } else if d, ok := a.pvt.(*Descriptor); ok {
+ d.rhandler.ServeRead(rsp, req)
+ }
+ v = rsp.bytes()
+ }
+
+ w := newL2capWriter(c.mtu)
+ w.WriteByteFit(attOpReadRsp)
+ w.Chunk()
+ w.WriteFit(v)
+ w.CommitFit()
+ return w.Bytes()
+}
+
+// FIXME: check this, untested, might be broken
+func (c *central) handleReadBlob(b []byte) []byte {
+ h := binary.LittleEndian.Uint16(b)
+ offset := binary.LittleEndian.Uint16(b[2:])
+ a, ok := c.attrs.At(h)
+ if !ok {
+ return attErrorRsp(attOpReadBlobReq, h, attEcodeInvalidHandle)
+ }
+ if a.props&CharRead == 0 {
+ return attErrorRsp(attOpReadBlobReq, h, attEcodeReadNotPerm)
+ }
+ if a.secure&CharRead != 0 && c.security > securityLow {
+ return attErrorRsp(attOpReadBlobReq, h, attEcodeAuthentication)
+ }
+ v := a.value
+ if v == nil {
+ req := &ReadRequest{
+ Request: Request{Central: c},
+ Cap: int(c.mtu - 1),
+ Offset: int(offset),
+ }
+ rsp := newResponseWriter(int(c.mtu - 1))
+ if c, ok := a.pvt.(*Characteristic); ok {
+ c.rhandler.ServeRead(rsp, req)
+ } else if d, ok := a.pvt.(*Descriptor); ok {
+ d.rhandler.ServeRead(rsp, req)
+ }
+ v = rsp.bytes()
+ offset = 0 // the server has already adjusted for the offset
+ }
+ w := newL2capWriter(c.mtu)
+ w.WriteByteFit(attOpReadBlobRsp)
+ w.Chunk()
+ w.WriteFit(v)
+ if ok := w.ChunkSeek(offset); !ok {
+ return attErrorRsp(attOpReadBlobReq, h, attEcodeInvalidOffset)
+ }
+ w.CommitFit()
+ return w.Bytes()
+}
+
+func (c *central) handleReadByGroup(b []byte) []byte {
+ start, end := readHandleRange(b)
+ t := UUID{b[4:]}
+
+ // Only support the ATT ReadByGroupReq for GATT Primary Service Discovery.
+ // More specifically, the "Discover All Primary Services" sub-procedure.
+ if !t.Equal(attrPrimaryServiceUUID) {
+ return attErrorRsp(attOpReadByGroupReq, start, attEcodeUnsuppGrpType)
+ }
+
+ w := newL2capWriter(c.mtu)
+ w.WriteByteFit(attOpReadByGroupRsp)
+ uuidLen := -1
+ for _, a := range c.attrs.Subrange(start, end) {
+ if !a.typ.Equal(attrPrimaryServiceUUID) {
+ continue
+ }
+ if uuidLen == -1 {
+ uuidLen = len(a.value)
+ w.WriteByteFit(byte(uuidLen + 4))
+ }
+ if uuidLen != len(a.value) {
+ break
+ }
+ s := a.pvt.(*Service)
+ w.Chunk()
+ w.WriteUint16Fit(s.h)
+ w.WriteUint16Fit(s.endh)
+ w.WriteFit(a.value)
+ if ok := w.Commit(); !ok {
+ break
+ }
+ }
+ if uuidLen == -1 {
+ return attErrorRsp(attOpReadByGroupReq, start, attEcodeAttrNotFound)
+ }
+ return w.Bytes()
+}
+
+func (c *central) handleWrite(reqType byte, b []byte) []byte {
+ h := binary.LittleEndian.Uint16(b[:2])
+ value := b[2:]
+
+ a, ok := c.attrs.At(h)
+ if !ok {
+ return attErrorRsp(reqType, h, attEcodeInvalidHandle)
+ }
+
+ noRsp := reqType == attOpWriteCmd
+ charFlag := CharWrite
+ if noRsp {
+ charFlag = CharWriteNR
+ }
+ if a.props&charFlag == 0 {
+ return attErrorRsp(reqType, h, attEcodeWriteNotPerm)
+ }
+ if a.secure&charFlag == 0 && c.security > securityLow {
+ return attErrorRsp(reqType, h, attEcodeAuthentication)
+ }
+
+ // Props of Service and Characteristic declration are read only.
+ // So we only need deal with writable descriptors here.
+ // (Characteristic's value is implemented with descriptor)
+ if !a.typ.Equal(attrClientCharacteristicConfigUUID) {
+ // Regular write, not CCC
+ r := Request{Central: c}
+ if c, ok := a.pvt.(*Characteristic); ok {
+ c.whandler.ServeWrite(r, value)
+ } else if d, ok := a.pvt.(*Characteristic); ok {
+ d.whandler.ServeWrite(r, value)
+ }
+ if noRsp {
+ return nil
+ } else {
+ return []byte{attOpWriteRsp}
+ }
+ }
+
+ // CCC/descriptor write
+ if len(value) != 2 {
+ return attErrorRsp(reqType, h, attEcodeInvalAttrValueLen)
+ }
+ ccc := binary.LittleEndian.Uint16(value)
+ // char := a.pvt.(*Descriptor).char
+ if ccc&(gattCCCNotifyFlag|gattCCCIndicateFlag) != 0 {
+ c.startNotify(&a, int(c.mtu-3))
+ } else {
+ c.stopNotify(&a)
+ }
+ if noRsp {
+ return nil
+ }
+ return []byte{attOpWriteRsp}
+}
+
+func (c *central) sendNotification(a *attr, data []byte) (int, error) {
+ w := newL2capWriter(c.mtu)
+ w.WriteByteFit(attOpHandleNotify)
+ w.WriteUint16Fit(a.pvt.(*Descriptor).char.vh)
+ w.WriteFit(data)
+ return c.l2conn.Write(w.Bytes())
+}
+
+func readHandleRange(b []byte) (start, end uint16) {
+ return binary.LittleEndian.Uint16(b), binary.LittleEndian.Uint16(b[2:])
+}
+
+func (c *central) startNotify(a *attr, maxlen int) {
+ c.notifiersmu.Lock()
+ defer c.notifiersmu.Unlock()
+ if _, found := c.notifiers[a.h]; found {
+ return
+ }
+ char := a.pvt.(*Descriptor).char
+ n := newNotifier(c, a, maxlen)
+ c.notifiers[a.h] = n
+ go char.nhandler.ServeNotify(Request{Central: c}, n)
+}
+
+func (c *central) stopNotify(a *attr) {
+ c.notifiersmu.Lock()
+ defer c.notifiersmu.Unlock()
+ // char := a.pvt.(*Characteristic)
+ if n, found := c.notifiers[a.h]; found {
+ n.stop()
+ delete(c.notifiers, a.h)
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/common.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/common.go b/newtmgr/vendor/github.com/runtimeco/gatt/common.go
new file mode 100644
index 0000000..4fa2389
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/common.go
@@ -0,0 +1,399 @@
+package gatt
+
+// Supported statuses for GATT characteristic read/write operations.
+// These correspond to att constants in the BLE spec
+const (
+ StatusSuccess = 0
+ StatusInvalidOffset = 1
+ StatusUnexpectedError = 2
+)
+
+// A Request is the context for a request from a connected central device.
+// TODO: Replace this with more general context, such as:
+// http://godoc.org/golang.org/x/net/context
+type Request struct {
+ Central Central
+}
+
+// A ReadRequest is a characteristic read request from a connected device.
+type ReadRequest struct {
+ Request
+ Cap int // maximum allowed reply length
+ Offset int // request value offset
+}
+
+type Property int
+
+// Characteristic property flags (spec 3.3.3.1)
+const (
+ CharBroadcast Property = 0x01 // may be brocasted
+ CharRead Property = 0x02 // may be read
+ CharWriteNR Property = 0x04 // may be written to, with no reply
+ CharWrite Property = 0x08 // may be written to, with a reply
+ CharNotify Property = 0x10 // supports notifications
+ CharIndicate Property = 0x20 // supports Indications
+ CharSignedWrite Property = 0x40 // supports signed write
+ CharExtended Property = 0x80 // supports extended properties
+)
+
+func (p Property) String() (result string) {
+ if (p & CharBroadcast) != 0 {
+ result += "broadcast "
+ }
+ if (p & CharRead) != 0 {
+ result += "read "
+ }
+ if (p & CharWriteNR) != 0 {
+ result += "writeWithoutResponse "
+ }
+ if (p & CharWrite) != 0 {
+ result += "write "
+ }
+ if (p & CharNotify) != 0 {
+ result += "notify "
+ }
+ if (p & CharIndicate) != 0 {
+ result += "indicate "
+ }
+ if (p & CharSignedWrite) != 0 {
+ result += "authenticateSignedWrites "
+ }
+ if (p & CharExtended) != 0 {
+ result += "extendedProperties "
+ }
+ return
+}
+
+// A Service is a BLE service.
+type Service struct {
+ uuid UUID
+ chars []*Characteristic
+
+ h uint16
+ endh uint16
+}
+
+// NewService creates and initialize a new Service using u as it's UUID.
+func NewService(u UUID) *Service {
+ return &Service{uuid: u}
+}
+
+// AddCharacteristic adds a characteristic to a service.
+// AddCharacteristic panics if the service already contains another
+// characteristic with the same UUID.
+func (s *Service) AddCharacteristic(u UUID) *Characteristic {
+ for _, c := range s.chars {
+ if c.uuid.Equal(u) {
+ panic("service already contains a characteristic with uuid " + u.String())
+ }
+ }
+ c := &Characteristic{uuid: u, svc: s}
+ s.chars = append(s.chars, c)
+ return c
+}
+
+// UUID returns the UUID of the service.
+func (s *Service) UUID() UUID { return s.uuid }
+
+// Name returns the specificatin name of the service according to its UUID.
+// If the UUID is not assigne, Name returns an empty string.
+func (s *Service) Name() string {
+ return knownServices[s.uuid.String()].Name
+}
+
+// Handle returns the Handle of the service.
+func (s *Service) Handle() uint16 { return s.h }
+
+// EndHandle returns the End Handle of the service.
+func (s *Service) EndHandle() uint16 { return s.endh }
+
+// SetHandle sets the Handle of the service.
+func (s *Service) SetHandle(h uint16) { s.h = h }
+
+// SetEndHandle sets the End Handle of the service.
+func (s *Service) SetEndHandle(endh uint16) { s.endh = endh }
+
+// SetCharacteristics sets the Characteristics of the service.
+func (s *Service) SetCharacteristics(chars []*Characteristic) { s.chars = chars }
+
+// Characteristic returns the contained characteristic of this service.
+func (s *Service) Characteristics() []*Characteristic { return s.chars }
+
+// A Characteristic is a BLE characteristic.
+type Characteristic struct {
+ uuid UUID
+ props Property // enabled properties
+ secure Property // security enabled properties
+ svc *Service
+ cccd *Descriptor
+ descs []*Descriptor
+
+ value []byte
+
+ // All the following fields are only used in peripheral/server implementation.
+ rhandler ReadHandler
+ whandler WriteHandler
+ nhandler NotifyHandler
+
+ h uint16
+ vh uint16
+ endh uint16
+}
+
+// NewCharacteristic creates and returns a Characteristic.
+func NewCharacteristic(u UUID, s *Service, props Property, h uint16, vh uint16) *Characteristic {
+ c := &Characteristic{
+ uuid: u,
+ svc: s,
+ props: props,
+ h: h,
+ vh: vh,
+ }
+
+ return c
+}
+
+// Handle returns the Handle of the characteristic.
+func (c *Characteristic) Handle() uint16 { return c.h }
+
+// VHandle returns the Value Handle of the characteristic.
+func (c *Characteristic) VHandle() uint16 { return c.vh }
+
+// EndHandle returns the End Handle of the characteristic.
+func (c *Characteristic) EndHandle() uint16 { return c.endh }
+
+// Descriptor returns the Descriptor of the characteristic.
+func (c *Characteristic) Descriptor() *Descriptor { return c.cccd }
+
+// SetHandle sets the Handle of the characteristic.
+func (c *Characteristic) SetHandle(h uint16) { c.h = h }
+
+// SetVHandle sets the Value Handle of the characteristic.
+func (c *Characteristic) SetVHandle(vh uint16) { c.vh = vh }
+
+// SetEndHandle sets the End Handle of the characteristic.
+func (c *Characteristic) SetEndHandle(endh uint16) { c.endh = endh }
+
+// SetDescriptor sets the Descriptor of the characteristic.
+func (c *Characteristic) SetDescriptor(cccd *Descriptor) { c.cccd = cccd }
+
+// SetDescriptors sets the list of Descriptor of the characteristic.
+func (c *Characteristic) SetDescriptors(descs []*Descriptor) { c.descs = descs }
+
+// UUID returns the UUID of the characteristic.
+func (c *Characteristic) UUID() UUID {
+ return c.uuid
+}
+
+// Name returns the specificatin name of the characteristic.
+// If the UUID is not assigned, Name returns empty string.
+func (c *Characteristic) Name() string {
+ return knownCharacteristics[c.uuid.String()].Name
+}
+
+// Service returns the containing service of this characteristic.
+func (c *Characteristic) Service() *Service {
+ return c.svc
+}
+
+// Properties returns the properties of this characteristic.
+func (c *Characteristic) Properties() Property {
+ return c.props
+}
+
+// Descriptors returns the contained descriptors of this characteristic.
+func (c *Characteristic) Descriptors() []*Descriptor {
+ return c.descs
+}
+
+// AddDescriptor adds a descriptor to a characteristic.
+// AddDescriptor panics if the characteristic already contains another
+// descriptor with the same UUID.
+func (c *Characteristic) AddDescriptor(u UUID) *Descriptor {
+ for _, d := range c.descs {
+ if d.uuid.Equal(u) {
+ panic("service already contains a characteristic with uuid " + u.String())
+ }
+ }
+ d := &Descriptor{uuid: u, char: c}
+ c.descs = append(c.descs, d)
+ return d
+}
+
+// SetValue makes the characteristic support read requests, and returns a
+// static value. SetValue must be called before the containing service is
+// added to a server.
+// SetValue panics if the characteristic has been configured with a ReadHandler.
+func (c *Characteristic) SetValue(b []byte) {
+ if c.rhandler != nil {
+ panic("charactristic has been configured with a read handler")
+ }
+ c.props |= CharRead
+ // c.secure |= CharRead
+ c.value = make([]byte, len(b))
+ copy(c.value, b)
+}
+
+// HandleRead makes the characteristic support read requests, and routes read
+// requests to h. HandleRead must be called before the containing service is
+// added to a server.
+// HandleRead panics if the characteristic has been configured with a static value.
+func (c *Characteristic) HandleRead(h ReadHandler) {
+ if c.value != nil {
+ panic("charactristic has been configured with a static value")
+ }
+ c.props |= CharRead
+ // c.secure |= CharRead
+ c.rhandler = h
+}
+
+// HandleReadFunc calls HandleRead(ReadHandlerFunc(f)).
+func (c *Characteristic) HandleReadFunc(f func(rsp ResponseWriter, req *ReadRequest)) {
+ c.HandleRead(ReadHandlerFunc(f))
+}
+
+// HandleWrite makes the characteristic support write and write-no-response
+// requests, and routes write requests to h.
+// The WriteHandler does not differentiate between write and write-no-response
+// requests; it is handled automatically.
+// HandleWrite must be called before the containing service is added to a server.
+func (c *Characteristic) HandleWrite(h WriteHandler) {
+ c.props |= CharWrite | CharWriteNR
+ // c.secure |= CharWrite | CharWriteNR
+ c.whandler = h
+}
+
+// HandleWriteFunc calls HandleWrite(WriteHandlerFunc(f)).
+func (c *Characteristic) HandleWriteFunc(f func(r Request, data []byte) (status byte)) {
+ c.HandleWrite(WriteHandlerFunc(f))
+}
+
+// HandleNotify makes the characteristic support notify requests, and routes
+// notification requests to h. HandleNotify must be called before the
+// containing service is added to a server.
+func (c *Characteristic) HandleNotify(h NotifyHandler) {
+ if c.cccd != nil {
+ return
+ }
+ p := CharNotify | CharIndicate
+ c.props |= p
+ c.nhandler = h
+
+ // add ccc (client characteristic configuration) descriptor
+ secure := Property(0)
+ // If the characteristic requested secure notifications,
+ // then set ccc security to r/w.
+ if c.secure&p != 0 {
+ secure = CharRead | CharWrite
+ }
+ cd := &Descriptor{
+ uuid: attrClientCharacteristicConfigUUID,
+ props: CharRead | CharWrite | CharWriteNR,
+ secure: secure,
+ // FIXME: currently, we always return 0, which is inaccurate.
+ // Each connection should have it's own copy of this value.
+ value: []byte{0x00, 0x00},
+ char: c,
+ }
+ c.cccd = cd
+ c.descs = append(c.descs, cd)
+}
+
+// HandleNotifyFunc calls HandleNotify(NotifyHandlerFunc(f)).
+func (c *Characteristic) HandleNotifyFunc(f func(r Request, n Notifier)) {
+ c.HandleNotify(NotifyHandlerFunc(f))
+}
+
+// TODO
+// func (c *Characteristic) SubscribedCentrals() []Central{
+// }
+
+// Descriptor is a BLE descriptor
+type Descriptor struct {
+ uuid UUID
+ char *Characteristic
+ props Property // enabled properties
+ secure Property // security enabled properties
+
+ h uint16
+ value []byte
+
+ rhandler ReadHandler
+ whandler WriteHandler
+}
+
+// Handle returns the Handle of the descriptor.
+func (d *Descriptor) Handle() uint16 { return d.h }
+
+// SetHandle sets the Handle of the descriptor.
+func (d *Descriptor) SetHandle(h uint16) { d.h = h }
+
+// NewDescriptor creates and returns a Descriptor.
+func NewDescriptor(u UUID, h uint16, char *Characteristic) *Descriptor {
+ cd := &Descriptor{
+ uuid: u,
+ h: h,
+ char: char,
+ }
+ return cd
+}
+
+// UUID returns the UUID of the descriptor.
+func (d *Descriptor) UUID() UUID {
+ return d.uuid
+}
+
+// Name returns the specificatin name of the descriptor.
+// If the UUID is not assigned, returns an empty string.
+func (d *Descriptor) Name() string {
+ return knownDescriptors[d.uuid.String()].Name
+}
+
+// Characteristic returns the containing characteristic of the descriptor.
+func (d *Descriptor) Characteristic() *Characteristic {
+ return d.char
+}
+
+// SetValue makes the descriptor support read requests, and returns a static value.
+// SetValue must be called before the containing service is added to a server.
+// SetValue panics if the descriptor has already configured with a ReadHandler.
+func (d *Descriptor) SetValue(b []byte) {
+ if d.rhandler != nil {
+ panic("descriptor has been configured with a read handler")
+ }
+ d.props |= CharRead
+ // d.secure |= CharRead
+ d.value = make([]byte, len(b))
+ copy(d.value, b)
+}
+
+// HandleRead makes the descriptor support read requests, and routes read requests to h.
+// HandleRead must be called before the containing service is added to a server.
+// HandleRead panics if the descriptor has been configured with a static value.
+func (d *Descriptor) HandleRead(h ReadHandler) {
+ if d.value != nil {
+ panic("descriptor has been configured with a static value")
+ }
+ d.props |= CharRead
+ // d.secure |= CharRead
+ d.rhandler = h
+}
+
+// HandleReadFunc calls HandleRead(ReadHandlerFunc(f)).
+func (d *Descriptor) HandleReadFunc(f func(rsp ResponseWriter, req *ReadRequest)) {
+ d.HandleRead(ReadHandlerFunc(f))
+}
+
+// HandleWrite makes the descriptor support write and write-no-response requests, and routes write requests to h.
+// The WriteHandler does not differentiate between write and write-no-response requests; it is handled automatically.
+// HandleWrite must be called before the containing service is added to a server.
+func (d *Descriptor) HandleWrite(h WriteHandler) {
+ d.props |= CharWrite | CharWriteNR
+ // d.secure |= CharWrite | CharWriteNR
+ d.whandler = h
+}
+
+// HandleWriteFunc calls HandleWrite(WriteHandlerFunc(f)).
+func (d *Descriptor) HandleWriteFunc(f func(r Request, data []byte) (status byte)) {
+ d.HandleWrite(WriteHandlerFunc(f))
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/const.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/const.go b/newtmgr/vendor/github.com/runtimeco/gatt/const.go
new file mode 100644
index 0000000..4a04b04
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/const.go
@@ -0,0 +1,153 @@
+package gatt
+
+// This file includes constants from the BLE spec.
+
+var (
+ attrGAPUUID = UUID16(0x1800)
+ attrGATTUUID = UUID16(0x1801)
+
+ attrPrimaryServiceUUID = UUID16(0x2800)
+ attrSecondaryServiceUUID = UUID16(0x2801)
+ attrIncludeUUID = UUID16(0x2802)
+ attrCharacteristicUUID = UUID16(0x2803)
+
+ attrClientCharacteristicConfigUUID = UUID16(0x2902)
+ attrServerCharacteristicConfigUUID = UUID16(0x2903)
+
+ attrDeviceNameUUID = UUID16(0x2A00)
+ attrAppearanceUUID = UUID16(0x2A01)
+ attrPeripheralPrivacyUUID = UUID16(0x2A02)
+ attrReconnectionAddrUUID = UUID16(0x2A03)
+ attrPeferredParamsUUID = UUID16(0x2A04)
+ attrServiceChangedUUID = UUID16(0x2A05)
+)
+
+const (
+ gattCCCNotifyFlag = 0x0001
+ gattCCCIndicateFlag = 0x0002
+)
+
+const (
+ attOpError = 0x01
+ attOpMtuReq = 0x02
+ attOpMtuRsp = 0x03
+ attOpFindInfoReq = 0x04
+ attOpFindInfoRsp = 0x05
+ attOpFindByTypeValueReq = 0x06
+ attOpFindByTypeValueRsp = 0x07
+ attOpReadByTypeReq = 0x08
+ attOpReadByTypeRsp = 0x09
+ attOpReadReq = 0x0a
+ attOpReadRsp = 0x0b
+ attOpReadBlobReq = 0x0c
+ attOpReadBlobRsp = 0x0d
+ attOpReadMultiReq = 0x0e
+ attOpReadMultiRsp = 0x0f
+ attOpReadByGroupReq = 0x10
+ attOpReadByGroupRsp = 0x11
+ attOpWriteReq = 0x12
+ attOpWriteRsp = 0x13
+ attOpWriteCmd = 0x52
+ attOpPrepWriteReq = 0x16
+ attOpPrepWriteRsp = 0x17
+ attOpExecWriteReq = 0x18
+ attOpExecWriteRsp = 0x19
+ attOpHandleNotify = 0x1b
+ attOpHandleInd = 0x1d
+ attOpHandleCnf = 0x1e
+ attOpSignedWriteCmd = 0xd2
+)
+
+type attEcode byte
+
+const (
+ attEcodeSuccess attEcode = 0x00 // Success
+ attEcodeInvalidHandle attEcode = 0x01 // The attribute handle given was not valid on this server.
+ attEcodeReadNotPerm attEcode = 0x02 // The attribute cannot be read.
+ attEcodeWriteNotPerm attEcode = 0x03 // The attribute cannot be written.
+ attEcodeInvalidPDU attEcode = 0x04 // The attribute PDU was invalid.
+ attEcodeAuthentication attEcode = 0x05 // The attribute requires authentication before it can be read or written.
+ attEcodeReqNotSupp attEcode = 0x06 // Attribute server does not support the request received from the client.
+ attEcodeInvalidOffset attEcode = 0x07 // Offset specified was past the end of the attribute.
+ attEcodeAuthorization attEcode = 0x08 // The attribute requires authorization before it can be read or written.
+ attEcodePrepQueueFull attEcode = 0x09 // Too many prepare writes have been queued.
+ attEcodeAttrNotFound attEcode = 0x0a // No attribute found within the given attribute handle range.
+ attEcodeAttrNotLong attEcode = 0x0b // The attribute cannot be read or written using the Read Blob Request.
+ attEcodeInsuffEncrKeySize attEcode = 0x0c // The Encryption Key Size used for encrypting this link is insufficient.
+ attEcodeInvalAttrValueLen attEcode = 0x0d // The attribute value length is invalid for the operation.
+ attEcodeUnlikely attEcode = 0x0e // The attribute request that was requested has encountered an error that was unlikely, and therefore could not be completed as requested.
+ attEcodeInsuffEnc attEcode = 0x0f // The attribute requires encryption before it can be read or written.
+ attEcodeUnsuppGrpType attEcode = 0x10 // The attribute type is not a supported grouping attribute as defined by a higher layer specification.
+ attEcodeInsuffResources attEcode = 0x11 // Insufficient Resources to complete the request.
+)
+
+func (a attEcode) Error() string {
+ switch i := int(a); {
+ case i < 0x11:
+ return attEcodeName[a]
+ case i >= 0x12 && i <= 0x7F: // Reserved for future use
+ return "reserved error code"
+ case i >= 0x80 && i <= 0x9F: // Application Error, defined by higher level
+ return "reserved error code"
+ case i >= 0xA0 && i <= 0xDF: // Reserved for future use
+ return "reserved error code"
+ case i >= 0xE0 && i <= 0xFF: // Common profile and service error codes
+ return "profile or service error"
+ default: // can't happen, just make compiler happy
+ return "unkown error"
+ }
+}
+
+var attEcodeName = map[attEcode]string{
+ attEcodeSuccess: "success",
+ attEcodeInvalidHandle: "invalid handle",
+ attEcodeReadNotPerm: "read not permitted",
+ attEcodeWriteNotPerm: "write not permitted",
+ attEcodeInvalidPDU: "invalid PDU",
+ attEcodeAuthentication: "insufficient authentication",
+ attEcodeReqNotSupp: "request not supported",
+ attEcodeInvalidOffset: "invalid offset",
+ attEcodeAuthorization: "insufficient authorization",
+ attEcodePrepQueueFull: "prepare queue full",
+ attEcodeAttrNotFound: "attribute not found",
+ attEcodeAttrNotLong: "attribute not long",
+ attEcodeInsuffEncrKeySize: "insufficient encryption key size",
+ attEcodeInvalAttrValueLen: "invalid attribute value length",
+ attEcodeUnlikely: "unlikely error",
+ attEcodeInsuffEnc: "insufficient encryption",
+ attEcodeUnsuppGrpType: "unsupported group type",
+ attEcodeInsuffResources: "insufficient resources",
+}
+
+func attErrorRsp(op byte, h uint16, s attEcode) []byte {
+ return attErr{opcode: op, attr: h, status: s}.Marshal()
+}
+
+// attRspFor maps from att request
+// codes to att response codes.
+var attRspFor = map[byte]byte{
+ attOpMtuReq: attOpMtuRsp,
+ attOpFindInfoReq: attOpFindInfoRsp,
+ attOpFindByTypeValueReq: attOpFindByTypeValueRsp,
+ attOpReadByTypeReq: attOpReadByTypeRsp,
+ attOpReadReq: attOpReadRsp,
+ attOpReadBlobReq: attOpReadBlobRsp,
+ attOpReadMultiReq: attOpReadMultiRsp,
+ attOpReadByGroupReq: attOpReadByGroupRsp,
+ attOpWriteReq: attOpWriteRsp,
+ attOpPrepWriteReq: attOpPrepWriteRsp,
+ attOpExecWriteReq: attOpExecWriteRsp,
+}
+
+type attErr struct {
+ opcode uint8
+ attr uint16
+ status attEcode
+}
+
+// TODO: Reformulate in a way that lets the caller avoid allocs.
+// Accept a []byte? Write directly to an io.Writer?
+func (e attErr) Marshal() []byte {
+ // little-endian encoding for attr
+ return []byte{attOpError, e.opcode, byte(e.attr), byte(e.attr >> 8), byte(e.status)}
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/device.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/device.go b/newtmgr/vendor/github.com/runtimeco/gatt/device.go
new file mode 100644
index 0000000..eba96cf
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/device.go
@@ -0,0 +1,161 @@
+package gatt
+
+import "errors"
+
+var notImplemented = errors.New("not implemented")
+
+type State int
+
+const (
+ StateUnknown State = 0
+ StateResetting State = 1
+ StateUnsupported State = 2
+ StateUnauthorized State = 3
+ StatePoweredOff State = 4
+ StatePoweredOn State = 5
+)
+
+func (s State) String() string {
+ str := []string{
+ "Unknown",
+ "Resetting",
+ "Unsupported",
+ "Unauthorized",
+ "PoweredOff",
+ "PoweredOn",
+ }
+ return str[int(s)]
+}
+
+// Device defines the interface for a BLE device.
+// Since an interface can't define fields(properties). To implement the
+// callback support for cerntain events, deviceHandler is defined and
+// implementation of Device on different platforms should embed it in
+// order to keep have keep compatible in API level.
+// Package users can use the Handler to set these handlers.
+type Device interface {
+ Init(stateChanged func(Device, State)) error
+
+ // Advertise advertise AdvPacket
+ Advertise(a *AdvPacket) error
+
+ // AdvertiseNameAndServices advertises device name, and specified service UUIDs.
+ // It tres to fit the UUIDs in the advertising packet as much as possible.
+ // If name doesn't fit in the advertising packet, it will be put in scan response.
+ AdvertiseNameAndServices(name string, ss []UUID) error
+
+ // AdvertiseIBeaconData advertise iBeacon with given manufacturer data.
+ AdvertiseIBeaconData(b []byte) error
+
+ // AdvertisingIbeacon advertises iBeacon with specified parameters.
+ AdvertiseIBeacon(u UUID, major, minor uint16, pwr int8) error
+
+ // StopAdvertising stops advertising.
+ StopAdvertising() error
+
+ // RemoveAllServices removes all services that are currently in the database.
+ RemoveAllServices() error
+
+ // Add Service add a service to database.
+ AddService(s *Service) error
+
+ // SetServices set the specified service to the database.
+ // It removes all currently added services, if any.
+ SetServices(ss []*Service) error
+
+ // Scan discovers surounding remote peripherals that have the Service UUID specified in ss.
+ // If ss is set to nil, all devices scanned are reported.
+ // dup specifies weather duplicated advertisement should be reported or not.
+ // When a remote peripheral is discovered, the PeripheralDiscovered Handler is called.
+ Scan(ss []UUID, dup bool)
+
+ // StopScanning stops scanning.
+ StopScanning()
+
+ // Connect connects to a remote peripheral.
+ Connect(p Peripheral)
+
+ // CancelConnection disconnects a remote peripheral.
+ CancelConnection(p Peripheral)
+
+ // Handle registers the specified handlers.
+ Handle(h ...Handler)
+
+ // Stop HCI Connection
+ Stop() error
+
+ // Option sets the options specified.
+ Option(o ...Option) error
+}
+
+// deviceHandler is the handlers(callbacks) of the Device.
+type deviceHandler struct {
+ // stateChanged is called when the device states changes.
+ stateChanged func(d Device, s State)
+
+ // connect is called when a remote central device connects to the device.
+ centralConnected func(c Central)
+
+ // disconnect is called when a remote central device disconnects to the device.
+ centralDisconnected func(c Central)
+
+ // peripheralDiscovered is called when a remote peripheral device is found during scan procedure.
+ peripheralDiscovered func(p Peripheral, a *Advertisement, rssi int)
+
+ // peripheralConnected is called when a remote peripheral is conneted.
+ peripheralConnected func(p Peripheral, err error)
+
+ // peripheralConnected is called when a remote peripheral is disconneted.
+ peripheralDisconnected func(p Peripheral, err error)
+}
+
+// A Handler is a self-referential function, which registers the options specified.
+// See http://commandcenter.blogspot.com.au/2014/01/self-referential-functions-and-design.html for more discussion.
+type Handler func(Device)
+
+// Handle registers the specified handlers.
+func (d *device) Handle(hh ...Handler) {
+ for _, h := range hh {
+ h(d)
+ }
+}
+
+// CentralConnected returns a Handler, which sets the specified function to be called when a device connects to the server.
+func CentralConnected(f func(Central)) Handler {
+ return func(d Device) { d.(*device).centralConnected = f }
+}
+
+// CentralDisconnected returns a Handler, which sets the specified function to be called when a device disconnects from the server.
+func CentralDisconnected(f func(Central)) Handler {
+ return func(d Device) { d.(*device).centralDisconnected = f }
+}
+
+// PeripheralDiscovered returns a Handler, which sets the specified function to be called when a remote peripheral device is found during scan procedure.
+func PeripheralDiscovered(f func(Peripheral, *Advertisement, int)) Handler {
+ return func(d Device) { d.(*device).peripheralDiscovered = f }
+}
+
+// PeripheralConnected returns a Handler, which sets the specified function to be called when a remote peripheral device connects.
+func PeripheralConnected(f func(Peripheral, error)) Handler {
+ return func(d Device) { d.(*device).peripheralConnected = f }
+}
+
+// PeripheralDisconnected returns a Handler, which sets the specified function to be called when a remote peripheral device disconnects.
+func PeripheralDisconnected(f func(Peripheral, error)) Handler {
+ return func(d Device) { d.(*device).peripheralDisconnected = f }
+}
+
+// An Option is a self-referential function, which sets the option specified.
+// Most Options are platform-specific, which gives more fine-grained control over the device at a cost of losing portibility.
+// See http://commandcenter.blogspot.com.au/2014/01/self-referential-functions-and-design.html for more discussion.
+type Option func(Device) error
+
+// Option sets the options specified.
+// Some options can only be set before the device is initialized; they are best used with NewDevice instead of Option.
+func (d *device) Option(opts ...Option) error {
+ var err error
+ for _, opt := range opts {
+ err = opt(d)
+ }
+ return err
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/device_darwin.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/device_darwin.go b/newtmgr/vendor/github.com/runtimeco/gatt/device_darwin.go
new file mode 100644
index 0000000..acf4431
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/device_darwin.go
@@ -0,0 +1,513 @@
+package gatt
+
+import (
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "log"
+ "sync"
+ "time"
+
+ "github.com/runtimeco/gatt/xpc"
+)
+
+const (
+ peripheralDiscovered = 37
+ peripheralConnected = 38
+ peripheralDisconnected = 40
+ // below constants for Yosemite
+ rssiRead = 55
+ includedServicesDiscovered = 63
+ serviceDiscovered = 56
+ characteristicsDiscovered = 64
+ characteristicRead = 71
+ characteristicWritten = 72
+ notificationValueSet = 74
+ descriptorsDiscovered = 76
+ descriptorRead = 79
+ descriptorWritten = 80
+)
+
+type device struct {
+ deviceHandler
+
+ conn xpc.XPC
+
+ role int // 1: peripheralManager (server), 0: centralManager (client)
+
+ reqc chan message
+ rspc chan message
+
+ // Only used in client/centralManager implementation
+ plist map[string]*peripheral
+ plistmu *sync.Mutex
+
+ // Only used in server/peripheralManager implementation
+
+ attrN int
+ attrs map[int]*attr
+
+ subscribers map[string]*central
+}
+
+func NewDevice(opts ...Option) (Device, error) {
+ d := &device{
+ reqc: make(chan message),
+ rspc: make(chan message),
+ plist: map[string]*peripheral{},
+ plistmu: &sync.Mutex{},
+
+ attrN: 1,
+ attrs: make(map[int]*attr),
+
+ subscribers: make(map[string]*central),
+ }
+ d.Option(opts...)
+ d.conn = xpc.XpcConnect("com.apple.blued", d)
+ return d, nil
+}
+
+func (d *device) Init(f func(Device, State)) error {
+ go d.loop()
+ rsp := d.sendReq(1, xpc.Dict{
+ "kCBMsgArgName": fmt.Sprintf("gopher-%v", time.Now().Unix()),
+ "kCBMsgArgOptions": xpc.Dict{"kCBInitOptionShowPowerAlert": 1},
+ "kCBMsgArgType": d.role,
+ })
+ d.stateChanged = f
+ go d.stateChanged(d, State(rsp.MustGetInt("kCBMsgArgState")))
+ return nil
+}
+
+func (d *device) Advertise(a *AdvPacket) error {
+ rsp := d.sendReq(8, xpc.Dict{
+ "kCBAdvDataAppleMfgData": a.b, // not a.Bytes(). should be slice
+ })
+
+ if res := rsp.MustGetInt("kCBMsgArgResult"); res != 0 {
+ return errors.New("FIXME: Advertise error")
+ }
+ return nil
+}
+
+func (d *device) AdvertiseNameAndServices(name string, ss []UUID) error {
+ us := uuidSlice(ss)
+ rsp := d.sendReq(8, xpc.Dict{
+ "kCBAdvDataLocalName": name,
+ "kCBAdvDataServiceUUIDs": us},
+ )
+ if res := rsp.MustGetInt("kCBMsgArgResult"); res != 0 {
+ return errors.New("FIXME: Advertise error")
+ }
+ return nil
+}
+
+func (d *device) AdvertiseIBeaconData(data []byte) error {
+ var utsname xpc.Utsname
+ xpc.Uname(&utsname)
+
+ var rsp xpc.Dict
+
+ if utsname.Release >= "14." {
+ l := len(data)
+ buf := bytes.NewBuffer([]byte{byte(l + 5), 0xFF, 0x4C, 0x00, 0x02, byte(l)})
+ buf.Write(data)
+ rsp = d.sendReq(8, xpc.Dict{"kCBAdvDataAppleMfgData": buf.Bytes()})
+ } else {
+ rsp = d.sendReq(8, xpc.Dict{"kCBAdvDataAppleBeaconKey": data})
+ }
+
+ if res := rsp.MustGetInt("kCBMsgArgResult"); res != 0 {
+ return errors.New("FIXME: Advertise error")
+ }
+
+ return nil
+}
+
+func (d *device) AdvertiseIBeacon(u UUID, major, minor uint16, pwr int8) error {
+ b := make([]byte, 21)
+ copy(b, reverse(u.b)) // Big endian
+ binary.BigEndian.PutUint16(b[16:], major) // Big endian
+ binary.BigEndian.PutUint16(b[18:], minor) // Big endian
+ b[20] = uint8(pwr) // Measured Tx Power
+ return d.AdvertiseIBeaconData(b)
+}
+
+func (d *device) StopAdvertising() error {
+ rsp := d.sendReq(9, nil)
+ if res := rsp.MustGetInt("kCBMsgArgResult"); res != 0 {
+ return errors.New("FIXME: Stop Advertise error")
+ }
+ return nil
+}
+
+func (d *device) RemoveAllServices() error {
+ d.sendCmd(12, nil)
+ return nil
+}
+
+func (d *device) AddService(s *Service) error {
+ if s.uuid.Equal(attrGAPUUID) || s.uuid.Equal(attrGATTUUID) {
+ // skip GATT and GAP services
+ return nil
+ }
+
+ xs := xpc.Dict{
+ "kCBMsgArgAttributeID": d.attrN,
+ "kCBMsgArgAttributeIDs": []int{},
+ "kCBMsgArgCharacteristics": nil,
+ "kCBMsgArgType": 1, // 1 => primary, 0 => excluded
+ "kCBMsgArgUUID": reverse(s.uuid.b),
+ }
+ d.attrN++
+
+ xcs := xpc.Array{}
+ for _, c := range s.Characteristics() {
+ props := 0
+ perm := 0
+ if c.props&CharRead != 0 {
+ props |= 0x02
+ if CharRead&c.secure != 0 {
+ perm |= 0x04
+ } else {
+ perm |= 0x01
+ }
+ }
+ if c.props&CharWriteNR != 0 {
+ props |= 0x04
+ if c.secure&CharWriteNR != 0 {
+ perm |= 0x08
+ } else {
+ perm |= 0x02
+ }
+ }
+ if c.props&CharWrite != 0 {
+ props |= 0x08
+ if c.secure&CharWrite != 0 {
+ perm |= 0x08
+ } else {
+ perm |= 0x02
+ }
+ }
+ if c.props&CharNotify != 0 {
+ if c.secure&CharNotify != 0 {
+ props |= 0x100
+ } else {
+ props |= 0x10
+ }
+ }
+ if c.props&CharIndicate != 0 {
+ if c.secure&CharIndicate != 0 {
+ props |= 0x200
+ } else {
+ props |= 0x20
+ }
+ }
+
+ xc := xpc.Dict{
+ "kCBMsgArgAttributeID": d.attrN,
+ "kCBMsgArgUUID": reverse(c.uuid.b),
+ "kCBMsgArgAttributePermissions": perm,
+ "kCBMsgArgCharacteristicProperties": props,
+ "kCBMsgArgData": c.value,
+ }
+ d.attrs[d.attrN] = &attr{h: uint16(d.attrN), value: c.value, pvt: c}
+ d.attrN++
+
+ xds := xpc.Array{}
+ for _, d := range c.Descriptors() {
+ if d.uuid.Equal(attrClientCharacteristicConfigUUID) {
+ // skip CCCD
+ continue
+ }
+ xd := xpc.Dict{
+ "kCBMsgArgData": d.value,
+ "kCBMsgArgUUID": reverse(d.uuid.b),
+ }
+ xds = append(xds, xd)
+ }
+ xc["kCBMsgArgDescriptors"] = xds
+ xcs = append(xcs, xc)
+ }
+ xs["kCBMsgArgCharacteristics"] = xcs
+
+ rsp := d.sendReq(10, xs)
+ if res := rsp.MustGetInt("kCBMsgArgResult"); res != 0 {
+ return errors.New("FIXME: Add Srvice error")
+ }
+ return nil
+}
+
+func (d *device) SetServices(ss []*Service) error {
+ d.RemoveAllServices()
+ for _, s := range ss {
+ d.AddService(s)
+ }
+ return nil
+}
+
+func (d *device) Scan(ss []UUID, dup bool) {
+ args := xpc.Dict{
+ "kCBMsgArgUUIDs": uuidSlice(ss),
+ "kCBMsgArgOptions": xpc.Dict{
+ "kCBScanOptionAllowDuplicates": map[bool]int{true: 1, false: 0}[dup],
+ },
+ }
+ d.sendCmd(29, args)
+}
+
+func (d *device) StopScanning() {
+ d.sendCmd(30, nil)
+}
+
+func (d *device) Connect(p Peripheral) {
+ pp := p.(*peripheral)
+ d.plist[pp.id.String()] = pp
+ d.sendCmd(31,
+ xpc.Dict{
+ "kCBMsgArgDeviceUUID": pp.id,
+ "kCBMsgArgOptions": xpc.Dict{
+ "kCBConnectOptionNotifyOnDisconnection": 1,
+ },
+ })
+}
+
+func (d *device) respondToRequest(id int, args xpc.Dict) {
+
+ switch id {
+ case 19: // ReadRequest
+ u := UUID{args.MustGetUUID("kCBMsgArgDeviceUUID")}
+ t := args.MustGetInt("kCBMsgArgTransactionID")
+ a := args.MustGetInt("kCBMsgArgAttributeID")
+ o := args.MustGetInt("kCBMsgArgOffset")
+
+ attr := d.attrs[a]
+ v := attr.value
+ if v == nil {
+ c := newCentral(d, u)
+ req := &ReadRequest{
+ Request: Request{Central: c},
+ Cap: int(c.mtu - 1),
+ Offset: o,
+ }
+ rsp := newResponseWriter(int(c.mtu - 1))
+ if c, ok := attr.pvt.(*Characteristic); ok {
+ c.rhandler.ServeRead(rsp, req)
+ v = rsp.bytes()
+ }
+ }
+
+ d.sendCmd(13, xpc.Dict{
+ "kCBMsgArgAttributeID": a,
+ "kCBMsgArgData": v,
+ "kCBMsgArgTransactionID": t,
+ "kCBMsgArgResult": 0,
+ })
+
+ case 20: // WriteRequest
+ u := UUID{args.MustGetUUID("kCBMsgArgDeviceUUID")}
+ t := args.MustGetInt("kCBMsgArgTransactionID")
+ a := 0
+ noRsp := false
+ xxws := args.MustGetArray("kCBMsgArgATTWrites")
+ for _, xxw := range xxws {
+ xw := xxw.(xpc.Dict)
+ if a == 0 {
+ a = xw.MustGetInt("kCBMsgArgAttributeID")
+ }
+ o := xw.MustGetInt("kCBMsgArgOffset")
+ i := xw.MustGetInt("kCBMsgArgIgnoreResponse")
+ b := xw.MustGetBytes("kCBMsgArgData")
+ _ = o
+ attr := d.attrs[a]
+ c := newCentral(d, u)
+ r := Request{Central: c}
+ attr.pvt.(*Characteristic).whandler.ServeWrite(r, b)
+ if i == 1 {
+ noRsp = true
+ }
+
+ }
+ if noRsp {
+ break
+ }
+ d.sendCmd(13, xpc.Dict{
+ "kCBMsgArgAttributeID": a,
+ "kCBMsgArgData": nil,
+ "kCBMsgArgTransactionID": t,
+ "kCBMsgArgResult": 0,
+ })
+
+ case 21: // subscribed
+ u := UUID{args.MustGetUUID("kCBMsgArgDeviceUUID")}
+ a := args.MustGetInt("kCBMsgArgAttributeID")
+ attr := d.attrs[a]
+ c := newCentral(d, u)
+ d.subscribers[u.String()] = c
+ c.startNotify(attr, c.mtu)
+
+ case 22: // unubscribed
+ u := UUID{args.MustGetUUID("kCBMsgArgDeviceUUID")}
+ a := args.MustGetInt("kCBMsgArgAttributeID")
+ attr := d.attrs[a]
+ if c := d.subscribers[u.String()]; c != nil {
+ c.stopNotify(attr)
+ }
+
+ case 23: // notificationSent
+ }
+}
+
+/*
+ * OSX GATT library currently doesn't work for Mynewt, so adding this stub to keep
+ * it buildable for OSX.
+ */
+func (d *device) Stop() error {
+ return nil
+}
+
+func (d *device) CancelConnection(p Peripheral) {
+ d.sendCmd(32, xpc.Dict{"kCBMsgArgDeviceUUID": p.(*peripheral).id})
+}
+
+// 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 (d *device) sendReq(id int, args xpc.Dict) xpc.Dict {
+ m := message{id: id, args: args, rspc: make(chan xpc.Dict)}
+ d.reqc <- m
+ return <-m.rspc
+}
+
+func (d *device) sendCmd(id int, args xpc.Dict) {
+ d.reqc <- message{id: id, args: args}
+}
+
+func (d *device) loop() {
+ for req := range d.reqc {
+ d.sendCBMsg(req.id, req.args)
+ if req.rspc == nil {
+ continue
+ }
+ m := <-d.rspc
+ req.rspc <- m.args
+ }
+}
+
+func (d *device) sendCBMsg(id int, args xpc.Dict) {
+ // log.Printf("<< %d, %v", id, args)
+ d.conn.Send(xpc.Dict{"kCBMsgId": id, "kCBMsgArgs": args}, false)
+}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/abf65d3a/newtmgr/vendor/github.com/runtimeco/gatt/device_linux.go
----------------------------------------------------------------------
diff --git a/newtmgr/vendor/github.com/runtimeco/gatt/device_linux.go b/newtmgr/vendor/github.com/runtimeco/gatt/device_linux.go
new file mode 100644
index 0000000..4c989e1
--- /dev/null
+++ b/newtmgr/vendor/github.com/runtimeco/gatt/device_linux.go
@@ -0,0 +1,240 @@
+package gatt
+
+import (
+ "encoding/binary"
+ "net"
+
+ "github.com/runtimeco/gatt/linux"
+ "github.com/runtimeco/gatt/linux/cmd"
+)
+
+type device struct {
+ deviceHandler
+
+ hci *linux.HCI
+ state State
+
+ // All the following fields are only used peripheralManager (server) implementation.
+ svcs []*Service
+ attrs *attrRange
+
+ devID int
+ chkLE bool
+ maxConn int
+
+ advData *cmd.LESetAdvertisingData
+ scanResp *cmd.LESetScanResponseData
+ advParam *cmd.LESetAdvertisingParameters
+ scanParam *cmd.LESetScanParameters
+}
+
+func NewDevice(opts ...Option) (Device, error) {
+ d := &device{
+ maxConn: 1, // Support 1 connection at a time.
+ devID: -1, // Find an available HCI device.
+ chkLE: true, // Check if the device supports LE.
+
+ advParam: &cmd.LESetAdvertisingParameters{
+ AdvertisingIntervalMin: 0x800, // [0x0800]: 0.625 ms * 0x0800 = 1280.0 ms
+ AdvertisingIntervalMax: 0x800, // [0x0800]: 0.625 ms * 0x0800 = 1280.0 ms
+ AdvertisingType: 0x00, // [0x00]: ADV_IND, 0x01: DIRECT(HIGH), 0x02: SCAN, 0x03: NONCONN, 0x04: DIRECT(LOW)
+ OwnAddressType: 0x00, // [0x00]: public, 0x01: random
+ DirectAddressType: 0x00, // [0x00]: public, 0x01: random
+ DirectAddress: [6]byte{}, // Public or Random Address of the device to be connected
+ AdvertisingChannelMap: 0x7, // [0x07] 0x01: ch37, 0x2: ch38, 0x4: ch39
+ AdvertisingFilterPolicy: 0x00,
+ },
+ scanParam: &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.
+ },
+ }
+
+ d.Option(opts...)
+ h, err := linux.NewHCI(d.devID, d.chkLE, d.maxConn)
+ if err != nil {
+ return nil, err
+ }
+
+ d.hci = h
+ return d, nil
+}
+
+func (d *device) Init(f func(Device, State)) error {
+ d.hci.AcceptMasterHandler = func(pd *linux.PlatData) {
+ a := pd.Address
+ c := newCentral(d.attrs, net.HardwareAddr([]byte{a[5], a[4], a[3], a[2], a[1], a[0]}), pd.Conn)
+ if d.centralConnected != nil {
+ d.centralConnected(c)
+ }
+ c.loop()
+ if d.centralDisconnected != nil {
+ d.centralDisconnected(c)
+ }
+ }
+ d.hci.AcceptSlaveHandler = func(pd *linux.PlatData) {
+ p := &peripheral{
+ d: d,
+ pd: pd,
+ l2c: pd.Conn,
+ reqc: make(chan message),
+ quitc: make(chan struct{}),
+ sub: newSubscriber(),
+ }
+ if d.peripheralConnected != nil {
+ go d.peripheralConnected(p, nil)
+ }
+ p.loop()
+ if d.peripheralDisconnected != nil {
+ d.peripheralDisconnected(p, nil)
+ }
+ }
+ d.hci.AdvertisementHandler = func(pd *linux.PlatData) {
+ a := &Advertisement{}
+ a.unmarshall(pd.Data)
+ a.Connectable = pd.Connectable
+ a.Address = pd.Address
+ a.AddressType = pd.AddressType
+ p := &peripheral{pd: pd, d: d}
+ if d.peripheralDiscovered != nil {
+ pd.Name = a.LocalName
+ d.peripheralDiscovered(p, a, int(pd.RSSI))
+ }
+ }
+ d.state = StatePoweredOn
+ d.stateChanged = f
+ go d.stateChanged(d, d.state)
+ return nil
+}
+
+func (d *device) Stop() error {
+ d.state = StatePoweredOff
+ defer d.stateChanged(d, d.state)
+ return d.hci.Close()
+}
+
+func (d *device) AddService(s *Service) error {
+ d.svcs = append(d.svcs, s)
+ d.attrs = generateAttributes(d.svcs, uint16(1)) // ble attrs start at 1
+ return nil
+}
+
+func (d *device) RemoveAllServices() error {
+ d.svcs = nil
+ d.attrs = nil
+ return nil
+}
+
+func (d *device) SetServices(s []*Service) error {
+ d.RemoveAllServices()
+ d.svcs = append(d.svcs, s...)
+ d.attrs = generateAttributes(d.svcs, uint16(1)) // ble attrs start at 1
+ return nil
+}
+
+func (d *device) Advertise(a *AdvPacket) error {
+ d.advData = &cmd.LESetAdvertisingData{
+ AdvertisingDataLength: uint8(a.Len()),
+ AdvertisingData: a.Bytes(),
+ }
+
+ if err := d.update(); err != nil {
+ return err
+ }
+
+ return d.hci.SetAdvertiseEnable(true)
+}
+
+func (d *device) AdvertiseNameAndServices(name string, uu []UUID) error {
+ a := &AdvPacket{}
+ a.AppendFlags(flagGeneralDiscoverable | flagLEOnly)
+ a.AppendUUIDFit(uu)
+
+ if len(a.b)+len(name)+2 < MaxEIRPacketLength {
+ a.AppendName(name)
+ d.scanResp = nil
+ } else {
+ a := &AdvPacket{}
+ a.AppendName(name)
+ d.scanResp = &cmd.LESetScanResponseData{
+ ScanResponseDataLength: uint8(a.Len()),
+ ScanResponseData: a.Bytes(),
+ }
+ }
+
+ return d.Advertise(a)
+}
+
+func (d *device) AdvertiseIBeaconData(b []byte) error {
+ a := &AdvPacket{}
+ a.AppendFlags(flagGeneralDiscoverable | flagLEOnly)
+ a.AppendManufacturerData(0x004C, b)
+ d.advData = &cmd.LESetAdvertisingData{
+ AdvertisingDataLength: uint8(a.Len()),
+ AdvertisingData: a.Bytes(),
+ }
+
+ return d.Advertise(a)
+}
+
+func (d *device) AdvertiseIBeacon(u UUID, major, minor uint16, pwr int8) error {
+ b := make([]byte, 23)
+ b[0] = 0x02 // Data type: iBeacon
+ b[1] = 0x15 // Data length: 21 bytes
+ copy(b[2:], reverse(u.b)) // Big endian
+ binary.BigEndian.PutUint16(b[18:], major) // Big endian
+ binary.BigEndian.PutUint16(b[20:], minor) // Big endian
+ b[22] = uint8(pwr) // Measured Tx Power
+ return d.AdvertiseIBeaconData(b)
+}
+
+func (d *device) StopAdvertising() error {
+ return d.hci.SetAdvertiseEnable(false)
+}
+
+func (d *device) Scan(ss []UUID, dup bool) {
+ // TODO: filter
+ d.hci.SetScanEnable(true, dup)
+}
+
+func (d *device) StopScanning() {
+ d.hci.SetScanEnable(false, true)
+}
+
+func (d *device) Connect(p Peripheral) {
+ d.hci.Connect(p.(*peripheral).pd)
+}
+
+func (d *device) CancelConnection(p Peripheral) {
+ d.hci.CancelConnection(p.(*peripheral).pd)
+}
+
+func (d *device) SendHCIRawCommand(c cmd.CmdParam) ([]byte, error) {
+ return d.hci.SendRawCommand(c)
+}
+
+// Flush pending advertising settings to the device.
+func (d *device) update() error {
+ if d.advParam != nil {
+ if err := d.hci.SendCmdWithAdvOff(d.advParam); err != nil {
+ return err
+ }
+ d.advParam = nil
+ }
+ if d.scanResp != nil {
+ if err := d.hci.SendCmdWithAdvOff(d.scanResp); err != nil {
+ return err
+ }
+ d.scanResp = nil
+ }
+ if d.advData != nil {
+ if err := d.hci.SendCmdWithAdvOff(d.advData); err != nil {
+ return err
+ }
+ d.advData = nil
+ }
+ return nil
+}