PROTOTYPE(discovery):gatt: add ReadCharacteristicBlob and SetMTU

   * Add ReadCharacteristicBlob and SetMTU to gatt library
   * This works only for linux.

Change-Id: Iab12c5a74d383ad265b128fe7f57ca9b779bf071
diff --git a/go/src/github.com/paypal/gatt/examples/explorer.go b/go/src/github.com/paypal/gatt/examples/explorer.go
index 3861cd9..4ec4d4d 100644
--- a/go/src/github.com/paypal/gatt/examples/explorer.go
+++ b/go/src/github.com/paypal/gatt/examples/explorer.go
@@ -50,6 +50,11 @@
 	fmt.Println("Connected")
 	defer p.Device().CancelConnection(p)
 
+	if err := p.SetMTU(500); err != nil {
+		fmt.Printf("Failed to set MTU, err: %s\n", err)
+		return
+	}
+
 	// Discovery services
 	ss, err := p.DiscoverServices(nil)
 	if err != nil {
@@ -81,7 +86,7 @@
 
 			// Read the characteristic, if possible.
 			if (c.Properties() & gatt.CharRead) != 0 {
-				b, err := p.ReadCharacteristic(c)
+				b, err := p.ReadCharacteristicBlob(c)
 				if err != nil {
 					fmt.Printf("Failed to read characteristic, err: %s\n", err)
 					continue
diff --git a/go/src/github.com/paypal/gatt/peripheral.go b/go/src/github.com/paypal/gatt/peripheral.go
index 3aa61f8..bc69ddc 100644
--- a/go/src/github.com/paypal/gatt/peripheral.go
+++ b/go/src/github.com/paypal/gatt/peripheral.go
@@ -39,6 +39,9 @@
 	// ReadCharacteristic retrieves the value of a specified characteristic.
 	ReadCharacteristic(c *Characteristic) ([]byte, error)
 
+	// ReadCharacteristicBlob retrieves the value of a specified characteristic by ReadBlob.
+	ReadCharacteristicBlob(c *Characteristic) ([]byte, error)
+
 	// ReadDescriptor retrieves the value of a specified characteristic descriptor.
 	ReadDescriptor(d *Descriptor) ([]byte, error)
 
@@ -56,6 +59,9 @@
 
 	// 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 {
diff --git a/go/src/github.com/paypal/gatt/peripheral_darwin.go b/go/src/github.com/paypal/gatt/peripheral_darwin.go
index 434e65e..643b97d 100644
--- a/go/src/github.com/paypal/gatt/peripheral_darwin.go
+++ b/go/src/github.com/paypal/gatt/peripheral_darwin.go
@@ -1,6 +1,7 @@
 package gatt
 
 import (
+	"errors"
 	"log"
 
 	"github.com/paypal/gatt/xpc"
@@ -120,6 +121,10 @@
 	return b, nil
 }
 
+func (p *peripheral) ReadCharacteristicBlob(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,
@@ -200,6 +205,10 @@
 	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 {
diff --git a/go/src/github.com/paypal/gatt/peripheral_linux.go b/go/src/github.com/paypal/gatt/peripheral_linux.go
index 3cd9abc..277228a 100644
--- a/go/src/github.com/paypal/gatt/peripheral_linux.go
+++ b/go/src/github.com/paypal/gatt/peripheral_linux.go
@@ -1,6 +1,7 @@
 package gatt
 
 import (
+	"bytes"
 	"encoding/binary"
 	"errors"
 	"fmt"
@@ -215,6 +216,30 @@
 	return b, nil
 }
 
+func (p *peripheral) ReadCharacteristicBlob(c *Characteristic) ([]byte, error) {
+	var buf bytes.Buffer
+	var off uint16
+	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)
@@ -295,7 +320,6 @@
 	return p.setNotifyValue(c, gattCCCIndicateFlag, f)
 }
 
-
 func (p *peripheral) ReadRSSI() int {
 	// TODO: implement
 	return -1
@@ -391,3 +415,18 @@
 
 	}
 }
+
+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
+}