Repository: incubator-mynewt-newtmgr
Updated Branches:
  refs/heads/master fc22b9fa5 -> 822cea97d


nmxact - Device discovery.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/commit/822cea97
Tree: 
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/tree/822cea97
Diff: 
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/diff/822cea97

Branch: refs/heads/master
Commit: 822cea97dd33b02255269392be0ea7aa9472d709
Parents: fc22b9f
Author: Christopher Collins <ccoll...@apache.org>
Authored: Mon May 1 14:21:54 2017 -0700
Committer: Christopher Collins <ccoll...@apache.org>
Committed: Tue May 16 14:49:35 2017 -0700

----------------------------------------------------------------------
 nmxact/bledefs/bledefs.go           |  17 ++++
 nmxact/example/ble_dual/ble_dual.go |  35 +++++++-
 nmxact/example/ble_scan/ble_scan.go | 144 +++++++++++++++++++++++++++++
 nmxact/nmble/ble_act.go             |  55 ++++++++++--
 nmxact/nmble/ble_fsm.go             | 150 +++++++++++++++++++++----------
 nmxact/nmble/ble_oic_sesn.go        |   5 ++
 nmxact/nmble/ble_plain_sesn.go      |   4 +
 nmxact/nmble/ble_proto.go           |  39 +++++++-
 nmxact/nmble/ble_scanner.go         | 127 ++++++++++++++++++++++++++
 nmxact/nmble/ble_util.go            |  14 +--
 nmxact/nmble/ble_xport.go           |  18 +++-
 nmxact/nmble/dispatch.go            |  38 ++++----
 nmxact/nmserial/serial_xport.go     |   5 ++
 nmxact/nmxutil/nmxutil.go           |  77 +++++++++++++---
 nmxact/scan/scan.go                 |  48 ++++++++++
 nmxact/sesn/sesn_cfg.go             |   2 +
 nmxact/xport/xport.go               |   3 +
 17 files changed, 685 insertions(+), 96 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/822cea97/nmxact/bledefs/bledefs.go
----------------------------------------------------------------------
diff --git a/nmxact/bledefs/bledefs.go b/nmxact/bledefs/bledefs.go
index b811dc0..3d7e85b 100644
--- a/nmxact/bledefs/bledefs.go
+++ b/nmxact/bledefs/bledefs.go
@@ -29,6 +29,15 @@ import (
 
 const BLE_ATT_ATTR_MAX_LEN = 512
 
+const NmpPlainSvcUuid = "8D53DC1D-1DB7-4CD3-868B-8A527460AA84"
+const NmpPlainChrUuid = "DA2E7828-FBCE-4E01-AE9E-261174997C48"
+const NmpOicSvcUuid = "ADE3D529-C784-4F63-A987-EB69F70EE816"
+const NmpOicReqChrUuid = "AD7B334F-4637-4B86-90B6-9D787F03D218"
+const NmpOicRspChrUuid = "E9241982-4580-42C4-8831-95048216B256"
+
+// This supersedes the 128-bit UUID above.
+const OmpSvcUuid = 0x9923
+
 type BleAddrType int
 
 const (
@@ -391,3 +400,11 @@ func (d *BleConnDesc) String() string {
                BleAddrTypeToString(d.PeerOtaAddrType),
                d.PeerOtaAddr.String())
 }
+
+type BleEncryptWhen int
+
+const (
+       BLE_ENCRYPT_NEVER BleEncryptWhen = iota
+       BLE_ENCRYPT_PRIV_ONLY
+       BLE_ENCRYPT_ALWAYS
+)

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/822cea97/nmxact/example/ble_dual/ble_dual.go
----------------------------------------------------------------------
diff --git a/nmxact/example/ble_dual/ble_dual.go 
b/nmxact/example/ble_dual/ble_dual.go
index 5be14e5..d446c3a 100644
--- a/nmxact/example/ble_dual/ble_dual.go
+++ b/nmxact/example/ble_dual/ble_dual.go
@@ -21,6 +21,7 @@ package main
 
 import (
        "fmt"
+       "io/ioutil"
        "os"
        "os/signal"
        "sync"
@@ -31,6 +32,7 @@ import (
        "mynewt.apache.org/newt/util"
        "mynewt.apache.org/newtmgr/nmxact/bledefs"
        "mynewt.apache.org/newtmgr/nmxact/nmble"
+       "mynewt.apache.org/newtmgr/nmxact/nmp"
        "mynewt.apache.org/newtmgr/nmxact/nmxutil"
        "mynewt.apache.org/newtmgr/nmxact/sesn"
        "mynewt.apache.org/newtmgr/nmxact/xact"
@@ -144,6 +146,37 @@ func sendTaskStat(s sesn.Sesn) error {
        return nil
 }
 
+func sendImageUpload(s sesn.Sesn) error {
+       data, err := 
ioutil.ReadFile("/Users/ccollins/Downloads/f17c9295bfbbf8f6b31ddcfa835be095090d0a875edcf88116bfaeec55f27e93/app.img")
+       if err != nil {
+               return err
+       }
+
+       c := xact.NewImageUploadCmd()
+       c.Data = data
+       c.ProgressCb = func(c *xact.ImageUploadCmd, r *nmp.ImageUploadRsp) {
+               fmt.Printf("Rxed upload rsp: %d\n", r.Off)
+       }
+
+       res, err := c.Run(s)
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "error executing image upload command: 
%s\n",
+                       err.Error())
+               panic(err.Error())
+       }
+
+       if res.Status() != 0 {
+               fmt.Printf("Peer responded negatively to image upload command; 
"+
+                       "status=%d\n", res.Status())
+               panic("ERROR")
+       }
+
+       fmt.Printf("[%p] Peer responded with image upload: rc=%#v\n",
+               s, res.Status())
+
+       return nil
+}
+
 func sendOne(s sesn.Sesn) {
        // Repeatedly:
        //     * Connect to peer if unconnected.
@@ -183,7 +216,7 @@ func sendOne(s sesn.Sesn) {
 }
 
 func main() {
-       nmxutil.SetLogLevel(log.InfoLevel)
+       nmxutil.SetLogLevel(log.DebugLevel)
 
        // Initialize the BLE transport.
        params := nmble.NewXportCfg()

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/822cea97/nmxact/example/ble_scan/ble_scan.go
----------------------------------------------------------------------
diff --git a/nmxact/example/ble_scan/ble_scan.go 
b/nmxact/example/ble_scan/ble_scan.go
new file mode 100644
index 0000000..d9f794c
--- /dev/null
+++ b/nmxact/example/ble_scan/ble_scan.go
@@ -0,0 +1,144 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package main
+
+import (
+       "fmt"
+       "os"
+       "os/signal"
+       "syscall"
+
+       log "github.com/Sirupsen/logrus"
+
+       "mynewt.apache.org/newt/util"
+       "mynewt.apache.org/newtmgr/nmxact/bledefs"
+       "mynewt.apache.org/newtmgr/nmxact/nmble"
+       "mynewt.apache.org/newtmgr/nmxact/nmxutil"
+       "mynewt.apache.org/newtmgr/nmxact/scan"
+       "mynewt.apache.org/newtmgr/nmxact/sesn"
+       "mynewt.apache.org/newtmgr/nmxact/xport"
+)
+
+func configExitHandler(x xport.Xport, s sesn.Sesn) {
+       onExit := func() {
+               if s != nil && s.IsOpen() {
+                       s.Close()
+               }
+
+               x.Stop()
+       }
+
+       sigChan := make(chan os.Signal, 1)
+       signal.Notify(sigChan)
+
+       go func() {
+               for {
+                       s := <-sigChan
+                       switch s {
+                       case os.Interrupt, syscall.SIGTERM:
+                               onExit()
+                               os.Exit(0)
+
+                       case syscall.SIGQUIT:
+                               util.PrintStacks()
+                       }
+               }
+       }()
+}
+
+func main() {
+       //nmxutil.SetLogLevel(log.DebugLevel)
+       nmxutil.SetLogLevel(log.InfoLevel)
+
+       // Initialize the BLE transport.
+       params := nmble.NewXportCfg()
+       params.SockPath = "/tmp/blehostd-uds"
+       params.BlehostdPath = "blehostd.elf"
+       params.DevPath = "/dev/cu.usbmodem14221"
+
+       x, err := nmble.NewBleXport(params)
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "error creating BLE transport: %s\n",
+                       err.Error())
+               os.Exit(1)
+       }
+
+       // Start the BLE transport.
+       if err := x.Start(); err != nil {
+               fmt.Fprintf(os.Stderr, "error starting BLE transport: %s\n",
+                       err.Error())
+               os.Exit(1)
+       }
+       defer x.Stop()
+
+       scanChan := make(chan scan.ScanPeer)
+       scanCb := func(peer scan.ScanPeer) {
+               fmt.Printf("discovered peer: %#v\n", peer)
+               scanChan <- peer
+       }
+
+       configExitHandler(x, nil)
+
+       scanner, err := x.BuildScanner()
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "error building BLE scanner: %s\n",
+                       err.Error())
+               os.Exit(1)
+       }
+
+       for {
+               sc := scan.BleOmpScanCfg(scanCb)
+               if err := scanner.Start(sc); err != nil {
+                       fmt.Fprintf(os.Stderr, "error starting scan: %s\n", 
err.Error())
+                       os.Exit(1)
+               }
+
+               p := <-scanChan
+
+               // Found a peer; stop scanning.
+               if err := scanner.Stop(); err != nil {
+                       fmt.Fprintf(os.Stderr, "Failed to stop scan: %s\n", 
err.Error())
+                       os.Exit(1)
+               }
+
+               fmt.Printf("Connecting to %#v\n", p)
+               c := sesn.NewSesnCfg()
+               c.MgmtProto = sesn.MGMT_PROTO_OMP
+               c.Ble.OwnAddrType = bledefs.BLE_ADDR_TYPE_RANDOM
+               c.Ble.PeerSpec = sesn.BlePeerSpecDev(p.Opaque.(bledefs.BleDev))
+
+               s, err := x.BuildSesn(c)
+               if err != nil {
+                       fmt.Fprintf(os.Stderr, "error creating BLE session: 
%s\n",
+                               err.Error())
+                       os.Exit(1)
+               }
+
+               if err := s.Open(); err != nil {
+                       fmt.Fprintf(os.Stderr, "error opening BLE session: 
%s\n",
+                               err.Error())
+                       os.Exit(1)
+               }
+
+               fmt.Printf("Connected\n")
+               fmt.Printf("Closing\n")
+               s.Close()
+       }
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/822cea97/nmxact/nmble/ble_act.go
----------------------------------------------------------------------
diff --git a/nmxact/nmble/ble_act.go b/nmxact/nmble/ble_act.go
index 4c5eef0..ed129cd 100644
--- a/nmxact/nmble/ble_act.go
+++ b/nmxact/nmble/ble_act.go
@@ -84,12 +84,12 @@ func connCancel(x *BleXport, bl *BleListener, r 
*BleConnCancelReq) error {
                        switch msg := bm.(type) {
                        case *BleConnCancelRsp:
                                bl.Acked = true
-                               if msg.Status != 0 {
+                               if msg.Status != 0 && msg.Status != 
ERR_CODE_EALREADY {
                                        return StatusError(MSG_OP_RSP, rspType, 
msg.Status)
-                               } else {
-                                       return nil
                                }
 
+                               return nil
+
                        default:
                        }
 
@@ -288,9 +288,8 @@ func exchangeMtu(x *BleXport, bl *BleListener, r 
*BleExchangeMtuReq) (
 type scanSuccessFn func()
 type advRptFn func(r BleAdvReport)
 
-func scan(x *BleXport, bl *BleListener, r *BleScanReq,
-       abortChan chan struct{},
-       scanSuccessCb scanSuccessFn, advRptCb advRptFn) error {
+func actScan(x *BleXport, bl *BleListener, r *BleScanReq,
+       abortChan chan struct{}, advRptCb advRptFn) error {
 
        const rspType = MSG_TYPE_SCAN
 
@@ -314,8 +313,6 @@ func scan(x *BleXport, bl *BleListener, r *BleScanReq,
                                bl.Acked = true
                                if msg.Status != 0 {
                                        return StatusError(MSG_OP_RSP, rspType, 
msg.Status)
-                               } else {
-                                       scanSuccessCb()
                                }
 
                        case *BleScanEvt:
@@ -358,7 +355,7 @@ func scanCancel(x *BleXport, bl *BleListener, r 
*BleScanCancelReq) error {
                        switch msg := bm.(type) {
                        case *BleScanCancelRsp:
                                bl.Acked = true
-                               if msg.Status != 0 {
+                               if msg.Status != 0 && msg.Status != 
ERR_CODE_EALREADY {
                                        return StatusError(MSG_OP_RSP, rspType, 
msg.Status)
                                }
                                return nil
@@ -443,6 +440,46 @@ func reset(x *BleXport, bl *BleListener,
        }
 }
 
+// Blocking
+func encInitiate(x *BleXport, bl *BleListener, encChan chan error,
+       r *BleSecurityInitiateReq) error {
+
+       const rspType = MSG_TYPE_SECURITY_INITIATE
+
+       j, err := json.Marshal(r)
+       if err != nil {
+               return err
+       }
+
+       if err := x.Tx(j); err != nil {
+               return err
+       }
+
+       for {
+               select {
+               case err := <-bl.ErrChan:
+                       return err
+
+               case bm := <-bl.BleChan:
+                       switch msg := bm.(type) {
+                       case *BleSecurityInitiateRsp:
+                               bl.Acked = true
+                               if msg.Status != 0 {
+                                       return StatusError(MSG_OP_RSP, rspType, 
msg.Status)
+                               }
+
+                       default:
+                       }
+
+               case err := <-encChan:
+                       return err
+
+               case <-bl.AfterTimeout(x.RspTimeout()):
+                       return BhdTimeoutError(rspType, r.Seq)
+               }
+       }
+}
+
 // Asks the controller to generate a random address.  This is done when the
 // transport is starting up, and therefore does not require the transport to be
 // synced.  Only the transport should call this function.

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/822cea97/nmxact/nmble/ble_fsm.go
----------------------------------------------------------------------
diff --git a/nmxact/nmble/ble_fsm.go b/nmxact/nmble/ble_fsm.go
index 828997a..ed7b90b 100644
--- a/nmxact/nmble/ble_fsm.go
+++ b/nmxact/nmble/ble_fsm.go
@@ -34,10 +34,11 @@ const (
        SESN_STATE_EXCHANGE_MTU                 = 3
        SESN_STATE_DISCOVER_SVC                 = 4
        SESN_STATE_DISCOVER_CHR                 = 5
-       SESN_STATE_SUBSCRIBE                    = 6
-       SESN_STATE_DONE                         = 7
-       SESN_STATE_TERMINATING                  = 8
-       SESN_STATE_CONN_CANCELLING              = 9
+       SESN_STATE_SECURITY                     = 6
+       SESN_STATE_SUBSCRIBE                    = 7
+       SESN_STATE_DONE                         = 8
+       SESN_STATE_TERMINATING                  = 9
+       SESN_STATE_CONN_CANCELLING              = 10
 )
 
 type BleFsmDisconnectType int
@@ -67,6 +68,7 @@ type BleFsmParams struct {
        RspChrUuid   BleUuid
        RxNmpCb      BleRxNmpFn
        DisconnectCb BleDisconnectFn
+       Encrypt      BleEncryptWhen
 }
 
 type BleFsm struct {
@@ -79,15 +81,13 @@ type BleFsm struct {
        nmpRspChr  *BleChr
        attMtu     int
        connChan   chan error
+       encChan    chan error
        bls        map[*BleListener]struct{}
        state      BleSesnState
        errFunnel  nmxutil.ErrFunnel
        id         uint32
        wg         sync.WaitGroup
 
-       // Gets notified when the FSM has stopped due to an error.
-       errChan chan error
-
        // Protects all accesses to the FSM state variable.
        stateMtx sync.Mutex
 
@@ -207,8 +207,12 @@ func (bf *BleFsm) removeBleSeqListener(name string, seq 
BleSeq) {
        bf.removeBleListener(name, base)
 }
 
+func (bf *BleFsm) connInfo() (BleConnDesc, error) {
+       return ConnFindXact(bf.params.Bx, bf.connHandle)
+}
+
 func (bf *BleFsm) logConnection() {
-       desc, err := ConnFindXact(bf.params.Bx, bf.connHandle)
+       desc, err := bf.connInfo()
        if err != nil {
                return
        }
@@ -263,19 +267,17 @@ func (bf *BleFsm) errorAll(err error) {
 
 func (bf *BleFsm) processErr(err error) {
        // Remember some fields before we clear them.
-       dt := calcDisconnectType(bf.state)
+       dt := calcDisconnectType(bf.getState())
 
        var peer BleDev
        if bf.peerDev != nil {
                peer = *bf.peerDev
        }
 
+       bf.params.Bx.StopWaitingForMaster(bf, err)
        bf.errorAll(err)
 
-       bf.stateMtx.Lock()
-       bf.state = SESN_STATE_UNCONNECTED
-       bf.stateMtx.Unlock()
-
+       bf.setState(SESN_STATE_UNCONNECTED)
        bf.peerDev = nil
 
        // Wait for all listeners to get removed.
@@ -283,8 +285,6 @@ func (bf *BleFsm) processErr(err error) {
 
        bf.errFunnel.Reset()
        bf.params.DisconnectCb(dt, peer, err)
-
-       bf.errChan <- err
 }
 
 func (bf *BleFsm) connectListen(seq BleSeq) error {
@@ -357,6 +357,21 @@ func (bf *BleFsm) connectListen(seq BleSeq) error {
                                                bf.attMtu = int(msg.Mtu)
                                        }
 
+                               case *BleEncChangeEvt:
+                                       var err error
+                                       if msg.Status != 0 {
+                                               err = StatusError(MSG_OP_EVT,
+                                                       MSG_TYPE_ENC_CHANGE_EVT,
+                                                       msg.Status)
+                                               log.Debugf(err.Error())
+                                       } else {
+                                               log.Debugf("Connection 
encrypted; conn_handle=%d",
+                                                       msg.ConnHandle)
+                                       }
+                                       if bf.encChan != nil {
+                                               bf.encChan <- err
+                                       }
+
                                case *BleDisconnectEvt:
                                        err := bf.disconnectError(msg.Reason)
                                        bf.errFunnel.Insert(err)
@@ -419,7 +434,7 @@ func (bf *BleFsm) connect() error {
        r.PeerAddr = bf.peerDev.Addr
 
        // Initiating a connection requires dedicated master privileges.
-       if err := bf.params.Bx.AcquireMaster(); err != nil {
+       if err := bf.params.Bx.AcquireMaster(bf); err != nil {
                return err
        }
        defer bf.params.Bx.ReleaseMaster()
@@ -439,7 +454,7 @@ func (bf *BleFsm) connect() error {
        }
 
        // Connection operation now in progress.
-       bf.state = SESN_STATE_CONNECTING
+       bf.setState(SESN_STATE_CONNECTING)
 
        err := <-bf.connChan
        if !nmxutil.IsXport(err) {
@@ -447,11 +462,8 @@ func (bf *BleFsm) connect() error {
                // operation.  In most cases, the host has already stopped 
connecting
                // and will respond with an "ealready" error that can be 
ignored.
                if err := bf.connCancel(); err != nil {
-                       bhe := nmxutil.ToBleHost(err)
-                       if bhe == nil || bhe.Status != ERR_CODE_EALREADY {
-                               log.Errorf("Failed to cancel connect in 
progress: %s",
-                                       err.Error())
-                       }
+                       log.Errorf("Failed to cancel connect in progress: %s",
+                               err.Error())
                }
        }
 
@@ -468,7 +480,7 @@ func (bf *BleFsm) scan() error {
        r.FilterDuplicates = true
 
        // Scanning requires dedicated master privileges.
-       if err := bf.params.Bx.AcquireMaster(); err != nil {
+       if err := bf.params.Bx.AcquireMaster(bf); err != nil {
                return err
        }
        defer bf.params.Bx.ReleaseMaster()
@@ -481,9 +493,6 @@ func (bf *BleFsm) scan() error {
 
        abortChan := make(chan struct{}, 1)
 
-       // This function gets called when scanning begins.
-       scanSuccessCb := func() { bf.state = SESN_STATE_SCANNING }
-
        // This function gets called for each incoming advertisement.
        advRptCb := func(r BleAdvReport) {
                // Ask client if we should connect to this advertiser.
@@ -493,17 +502,14 @@ func (bf *BleFsm) scan() error {
                }
        }
 
-       err = scan(bf.params.Bx, bl, r, abortChan, scanSuccessCb, advRptCb)
+       err = actScan(bf.params.Bx, bl, r, abortChan, advRptCb)
        if !nmxutil.IsXport(err) {
                // The transport did not restart; always attempt to cancel the 
scan
                // operation.  In most cases, the host has already stopped 
scanning
                // and will respond with an "ealready" error that can be 
ignored.
                if err := bf.scanCancel(); err != nil {
-                       bhe := nmxutil.ToBleHost(err)
-                       if bhe == nil || bhe.Status != ERR_CODE_EALREADY {
-                               log.Errorf("Failed to cancel scan in progress: 
%s",
-                                       err.Error())
-                       }
+                       log.Errorf("Failed to cancel scan in progress: %s",
+                               err.Error())
                }
        }
 
@@ -527,10 +533,7 @@ func (bf *BleFsm) scanCancel() error {
 }
 
 func (bf *BleFsm) terminateSetState() error {
-       bf.stateMtx.Lock()
-       defer bf.stateMtx.Unlock()
-
-       switch bf.state {
+       switch bf.getState() {
        case SESN_STATE_UNCONNECTED,
                SESN_STATE_CONNECTING,
                SESN_STATE_CONN_CANCELLING:
@@ -539,7 +542,7 @@ func (bf *BleFsm) terminateSetState() error {
                return fmt.Errorf(
                        "BLE terminate failed; session already being closed")
        default:
-               bf.state = SESN_STATE_TERMINATING
+               bf.setState(SESN_STATE_TERMINATING)
        }
 
        return nil
@@ -602,6 +605,26 @@ func (bf *BleFsm) discSvcUuid() error {
        return nil
 }
 
+func (bf *BleFsm) encInitiate() error {
+       r := NewBleSecurityInitiateReq()
+       r.ConnHandle = bf.connHandle
+
+       bl, err := bf.addBleSeqListener("enc-initiate", r.Seq)
+       if err != nil {
+               return err
+       }
+       defer bf.removeBleSeqListener("enc-initiate", r.Seq)
+
+       bf.encChan = make(chan error, 1)
+       defer func() { bf.encChan = nil }()
+
+       if err := encInitiate(bf.params.Bx, bl, bf.encChan, r); err != nil {
+               return err
+       }
+
+       return nil
+}
+
 func (bf *BleFsm) discAllChrs() error {
        r := NewBleDiscAllChrsReq()
        r.ConnHandle = bf.connHandle
@@ -700,6 +723,24 @@ func (bf *BleFsm) subscribe() error {
        return nil
 }
 
+func (bf *BleFsm) shouldEncrypt() bool {
+       switch bf.params.Encrypt {
+       case BLE_ENCRYPT_NEVER:
+               return false
+
+       case BLE_ENCRYPT_ALWAYS:
+               return true
+
+       case BLE_ENCRYPT_PRIV_ONLY:
+               return bf.peerDev.AddrType == BLE_ADDR_TYPE_RPA_PUB ||
+                       bf.peerDev.AddrType == BLE_ADDR_TYPE_RPA_RND
+
+       default:
+               panic(fmt.Sprintf("Invalid BleEncryptWhen value: %d",
+                       bf.params.Encrypt))
+       }
+}
+
 // Tries to populate the FSM's peerDev field.  This function succeeds if the
 // client specified the address of the peer to connect to.
 func (bf *BleFsm) tryFillPeerDev() bool {
@@ -718,10 +759,7 @@ func (bf *BleFsm) tryFillPeerDev() bool {
 }
 
 func (bf *BleFsm) executeState() (bool, error) {
-       bf.stateMtx.Lock()
-       defer bf.stateMtx.Unlock()
-
-       switch bf.state {
+       switch bf.getState() {
        case SESN_STATE_UNCONNECTED:
                // Determine if we can immediately initiate a connection, or if 
we
                // need to scan for a peer first.  If the client specified a 
peer
@@ -731,17 +769,18 @@ func (bf *BleFsm) executeState() (bool, error) {
                bf.tryFillPeerDev()
                if bf.peerDev == nil {
                        // Peer not inferred yet.  Initiate scan.
+                       bf.setState(SESN_STATE_SCANNING)
                        if err := bf.scan(); err != nil {
                                return false, err
                        }
-                       bf.state = SESN_STATE_UNCONNECTED
+                       bf.setState(SESN_STATE_UNCONNECTED)
                } else {
                        // We already know the address we want to connect to.  
Initiate
                        // a connection.
                        if err := bf.connect(); err != nil {
                                return false, err
                        }
-                       bf.state = SESN_STATE_EXCHANGE_MTU
+                       bf.setState(SESN_STATE_EXCHANGE_MTU)
                }
 
        case SESN_STATE_EXCHANGE_MTU:
@@ -750,25 +789,35 @@ func (bf *BleFsm) executeState() (bool, error) {
                        retry := bhe != nil && bhe.Status == ERR_CODE_ENOTCONN
                        return retry, err
                }
-               bf.state = SESN_STATE_DISCOVER_SVC
+               bf.setState(SESN_STATE_DISCOVER_SVC)
 
        case SESN_STATE_DISCOVER_SVC:
                if err := bf.discSvcUuid(); err != nil {
                        return false, err
                }
-               bf.state = SESN_STATE_DISCOVER_CHR
+               bf.setState(SESN_STATE_DISCOVER_CHR)
 
        case SESN_STATE_DISCOVER_CHR:
                if err := bf.discAllChrs(); err != nil {
                        return false, err
                }
-               bf.state = SESN_STATE_SUBSCRIBE
+               if bf.shouldEncrypt() {
+                       bf.setState(SESN_STATE_SECURITY)
+               } else {
+                       bf.setState(SESN_STATE_SUBSCRIBE)
+               }
+
+       case SESN_STATE_SECURITY:
+               if err := bf.encInitiate(); err != nil {
+                       return false, err
+               }
+               bf.setState(SESN_STATE_SUBSCRIBE)
 
        case SESN_STATE_SUBSCRIBE:
                if err := bf.subscribe(); err != nil {
                        return false, err
                }
-               bf.state = SESN_STATE_DONE
+               bf.setState(SESN_STATE_DONE)
 
        case SESN_STATE_DONE:
                /* Open complete. */
@@ -789,13 +838,12 @@ func (bf *BleFsm) startOnce() (bool, error) {
        }
 
        bf.errFunnel.Start()
-       bf.errChan = make(chan error, 1)
 
        for {
                retry, err := bf.executeState()
                if err != nil {
                        bf.errFunnel.Insert(err)
-                       err = <-bf.errChan
+                       err = bf.errFunnel.Wait()
                        return retry, err
                } else if bf.getState() == SESN_STATE_DONE {
                        return false, nil
@@ -837,6 +885,10 @@ func (bf *BleFsm) Stop() (bool, error) {
                bf.errFunnel.Insert(fmt.Errorf("Connection attempt cancelled"))
                return false, nil
 
+       case SESN_STATE_SCANNING:
+               bf.errFunnel.Insert(fmt.Errorf("Scan cancelled"))
+               return false, nil
+
        default:
                if err := bf.terminate(); err != nil {
                        return false, err

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/822cea97/nmxact/nmble/ble_oic_sesn.go
----------------------------------------------------------------------
diff --git a/nmxact/nmble/ble_oic_sesn.go b/nmxact/nmble/ble_oic_sesn.go
index 433ecb0..b390738 100644
--- a/nmxact/nmble/ble_oic_sesn.go
+++ b/nmxact/nmble/ble_oic_sesn.go
@@ -57,6 +57,7 @@ func NewBleOicSesn(bx *BleXport, cfg sesn.SesnCfg) 
*BleOicSesn {
                SvcUuid:     svcUuid,
                ReqChrUuid:  reqChrUuid,
                RspChrUuid:  rspChrUuid,
+               Encrypt:     cfg.Ble.Encrypt,
                RxNmpCb:     func(d []byte) { bos.onRxNmp(d) },
                DisconnectCb: func(dt BleFsmDisconnectType, p BleDev, e error) {
                        bos.onDisconnect(dt, p, e)
@@ -245,3 +246,7 @@ func (bos *BleOicSesn) MtuOut() int {
                nmp.NMP_HDR_SIZE
        return util.IntMin(mtu, BLE_ATT_ATTR_MAX_LEN)
 }
+
+func (bos *BleOicSesn) ConnInfo() (BleConnDesc, error) {
+       return bos.bf.connInfo()
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/822cea97/nmxact/nmble/ble_plain_sesn.go
----------------------------------------------------------------------
diff --git a/nmxact/nmble/ble_plain_sesn.go b/nmxact/nmble/ble_plain_sesn.go
index 2bcd950..f2048c3 100644
--- a/nmxact/nmble/ble_plain_sesn.go
+++ b/nmxact/nmble/ble_plain_sesn.go
@@ -217,3 +217,7 @@ func (bps *BlePlainSesn) MtuOut() int {
        mtu := bps.bf.attMtu - WRITE_CMD_BASE_SZ - nmp.NMP_HDR_SIZE
        return util.IntMin(mtu, BLE_ATT_ATTR_MAX_LEN)
 }
+
+func (bps *BlePlainSesn) ConnInfo() (BleConnDesc, error) {
+       return bps.bf.connInfo()
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/822cea97/nmxact/nmble/ble_proto.go
----------------------------------------------------------------------
diff --git a/nmxact/nmble/ble_proto.go b/nmxact/nmble/ble_proto.go
index 0bb4d01..24363c7 100644
--- a/nmxact/nmble/ble_proto.go
+++ b/nmxact/nmble/ble_proto.go
@@ -93,7 +93,7 @@ const (
        ERR_CODE_HCI_ACL_CONN_EXISTS         = 11
        ERR_CODE_HCI_CMD_DISALLOWED          = 12
        ERR_CODE_HCI_CONN_REJ_RESOURCES      = 13
-       ERR_CODE_HCI_CONN_REJ_SECURITY       = 14
+       ERR_CODE_HCI_CONN_REJ_ENC            = 14
        ERR_CODE_HCI_CONN_REJ_BD_ADDR        = 15
        ERR_CODE_HCI_CONN_ACCEPT_TMO         = 16
        ERR_CODE_HCI_UNSUPPORTED             = 17
@@ -157,7 +157,7 @@ var HciErrCodeStringMap = map[int]string{
        ERR_CODE_HCI_ACL_CONN_EXISTS:     "acl conn exists",
        ERR_CODE_HCI_CMD_DISALLOWED:      "cmd disallowed",
        ERR_CODE_HCI_CONN_REJ_RESOURCES:  "conn rej resources",
-       ERR_CODE_HCI_CONN_REJ_SECURITY:   "conn rej security",
+       ERR_CODE_HCI_CONN_REJ_ENC:        "conn rej security",
        ERR_CODE_HCI_CONN_REJ_BD_ADDR:    "conn rej bd addr",
        ERR_CODE_HCI_CONN_ACCEPT_TMO:     "conn accept tmo",
        ERR_CODE_HCI_UNSUPPORTED:         "unsupported",
@@ -270,6 +270,7 @@ var MsgTypeStringMap = map[MsgType]string{
        MSG_TYPE_SCAN:              "scan",
        MSG_TYPE_SCAN_CANCEL:       "scan_cancel",
        MSG_TYPE_SET_PREFERRED_MTU: "set_preferred_mtu",
+       MSG_TYPE_SECURITY_INITIATE: "security_initiate",
        MSG_TYPE_CONN_FIND:         "conn_find",
        MSG_TYPE_RESET:             "reset",
 
@@ -784,6 +785,40 @@ type BleResetRsp struct {
        Op   MsgOp   `json:"op"`
        Type MsgType `json:"type"`
        Seq  BleSeq  `json:"seq"`
+
+       // Mandatory
+       Status int `json:"status"`
+}
+
+type BleSecurityInitiateReq struct {
+       // Header
+       Op   MsgOp   `json:"op"`
+       Type MsgType `json:"type"`
+       Seq  BleSeq  `json:"seq"`
+
+       // Mandatory
+       ConnHandle uint16 `json:"conn_handle"`
+}
+
+type BleSecurityInitiateRsp struct {
+       // Header
+       Op   MsgOp   `json:"op"`
+       Type MsgType `json:"type"`
+       Seq  BleSeq  `json:"seq"`
+
+       // Mandatory
+       Status int `json:"status"`
+}
+
+type BleEncChangeEvt struct {
+       // Header
+       Op   MsgOp   `json:"op"`
+       Type MsgType `json:"type"`
+       Seq  BleSeq  `json:"seq"`
+
+       // Mandatory
+       Status     int    `json:"status"`
+       ConnHandle uint16 `json:"conn_handle"`
 }
 
 func ErrCodeToString(e int) string {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/822cea97/nmxact/nmble/ble_scanner.go
----------------------------------------------------------------------
diff --git a/nmxact/nmble/ble_scanner.go b/nmxact/nmble/ble_scanner.go
new file mode 100644
index 0000000..4cdcf07
--- /dev/null
+++ b/nmxact/nmble/ble_scanner.go
@@ -0,0 +1,127 @@
+package nmble
+
+import (
+       "encoding/base64"
+       "fmt"
+
+       log "github.com/Sirupsen/logrus"
+
+       . "mynewt.apache.org/newtmgr/nmxact/bledefs"
+       "mynewt.apache.org/newtmgr/nmxact/omp"
+       "mynewt.apache.org/newtmgr/nmxact/scan"
+       "mynewt.apache.org/newtmgr/nmxact/xact"
+)
+
+// Implements scan.Scanner.
+type BleScanner struct {
+       cfg scan.Cfg
+
+       bx           *BleXport
+       reportedDevs map[BleDev][]byte
+       bos          *BleOicSesn
+       od           *omp.OmpDispatcher
+       enabled      bool
+}
+
+func NewBleScanner(bx *BleXport) *BleScanner {
+       return &BleScanner{
+               bx:           bx,
+               reportedDevs: map[BleDev][]byte{},
+       }
+}
+
+func (s *BleScanner) scan() (scan.ScanPeer, error) {
+       if err := s.bos.Open(); err != nil {
+               return scan.ScanPeer{}, err
+       }
+       defer s.bos.Close()
+
+       // Now we are connected and paired.  Read the peer's hardware ID and 
report
+       // it upstream.
+
+       desc, err := s.bos.ConnInfo()
+       if err != nil {
+               return scan.ScanPeer{}, err
+       }
+
+       c := xact.NewConfigReadCmd()
+       c.Name = "id/hwid"
+
+       res, err := c.Run(s.bos)
+       if err != nil {
+               return scan.ScanPeer{}, err
+       }
+       if res.Status() != 0 {
+               return scan.ScanPeer{},
+                       fmt.Errorf("failed to read hardware ID; NMP status=%d",
+                               res.Status())
+       }
+       cres := res.(*xact.ConfigReadResult)
+
+       rawId, err := base64.StdEncoding.DecodeString(cres.Rsp.Val)
+       if err != nil {
+               return scan.ScanPeer{},
+                       fmt.Errorf("failed to decode hardware ID; undecoded=%s",
+                               cres.Rsp.Val)
+       }
+
+       peer := scan.ScanPeer{
+               HwId: rawId,
+               Opaque: BleDev{
+                       AddrType: desc.PeerIdAddrType,
+                       Addr:     desc.PeerIdAddr,
+               },
+       }
+
+       return peer, nil
+}
+
+func (s *BleScanner) Start(cfg scan.Cfg) error {
+       if s.enabled {
+               return fmt.Errorf("Attempt to start BLE scanner twice")
+       }
+
+       // Wrap predicate with logic that discards duplicates.
+       innerPred := cfg.SesnCfg.Ble.PeerSpec.ScanPred
+       cfg.SesnCfg.Ble.PeerSpec.ScanPred = func(adv BleAdvReport) bool {
+               // Filter devices that have already been reported.
+               if s.reportedDevs[adv.Sender] != nil {
+                       return false
+               }
+               return innerPred(adv)
+       }
+
+       session, err := s.bx.BuildSesn(cfg.SesnCfg)
+       if err != nil {
+               return err
+       }
+
+       s.enabled = true
+       s.cfg = cfg
+       s.bos = session.(*BleOicSesn)
+
+       // Start background scanning.
+       go func() {
+               for s.enabled {
+                       p, err := s.scan()
+                       if err != nil {
+                               log.Debugf("Scan error: %s", err.Error())
+                       } else {
+                               s.reportedDevs[p.Opaque.(BleDev)] = p.HwId
+                               s.cfg.ScanCb(p)
+                       }
+               }
+       }()
+
+       return nil
+}
+
+func (s *BleScanner) Stop() error {
+       if !s.enabled {
+               return fmt.Errorf("Attempt to stop BLE scanner twice")
+       }
+       s.enabled = false
+
+       s.bos.Close()
+       return nil
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/822cea97/nmxact/nmble/ble_util.go
----------------------------------------------------------------------
diff --git a/nmxact/nmble/ble_util.go b/nmxact/nmble/ble_util.go
index 13a2b8c..fc5fe27 100644
--- a/nmxact/nmble/ble_util.go
+++ b/nmxact/nmble/ble_util.go
@@ -11,12 +11,6 @@ import (
        "mynewt.apache.org/newtmgr/nmxact/nmxutil"
 )
 
-const NmpPlainSvcUuid = "8D53DC1D-1DB7-4CD3-868B-8A527460AA84"
-const NmpPlainChrUuid = "DA2E7828-FBCE-4E01-AE9E-261174997C48"
-const NmpOicSvcUuid = "ADE3D529-C784-4F63-A987-EB69F70EE816"
-const NmpOicReqChrUuid = "AD7B334F-4637-4B86-90B6-9D787F03D218"
-const NmpOicRspChrUuid = "E9241982-4580-42C4-8831-95048216B256"
-
 const WRITE_CMD_BASE_SZ = 3
 const NOTIFY_CMD_BASE_SZ = 3
 
@@ -251,6 +245,14 @@ func NewResetReq() *BleResetReq {
        }
 }
 
+func NewBleSecurityInitiateReq() *BleSecurityInitiateReq {
+       return &BleSecurityInitiateReq{
+               Op:   MSG_OP_REQ,
+               Type: MSG_TYPE_SECURITY_INITIATE,
+               Seq:  NextSeq(),
+       }
+}
+
 func ConnFindXact(x *BleXport, connHandle uint16) (BleConnDesc, error) {
        r := NewBleConnFindReq()
        r.ConnHandle = connHandle

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/822cea97/nmxact/nmble/ble_xport.go
----------------------------------------------------------------------
diff --git a/nmxact/nmble/ble_xport.go b/nmxact/nmble/ble_xport.go
index 0c2fe80..fdaf07c 100644
--- a/nmxact/nmble/ble_xport.go
+++ b/nmxact/nmble/ble_xport.go
@@ -12,6 +12,7 @@ import (
        "mynewt.apache.org/newt/util/unixchild"
        . "mynewt.apache.org/newtmgr/nmxact/bledefs"
        "mynewt.apache.org/newtmgr/nmxact/nmxutil"
+       "mynewt.apache.org/newtmgr/nmxact/scan"
        "mynewt.apache.org/newtmgr/nmxact/sesn"
 )
 
@@ -94,6 +95,7 @@ type BleXport struct {
        master            nmxutil.SingleResource
        randAddr          *BleAddr
        mtx               sync.Mutex
+       scanner           *BleScanner
 
        cfg XportCfg
 }
@@ -123,6 +125,14 @@ func (bx *BleXport) createUnixChild() {
        bx.client = unixchild.New(config)
 }
 
+func (bx *BleXport) BuildScanner() (scan.Scanner, error) {
+       if bx.scanner == nil {
+               bx.scanner = NewBleScanner(bx)
+       }
+
+       return bx.scanner, nil
+}
+
 func (bx *BleXport) BuildSesn(cfg sesn.SesnCfg) (sesn.Sesn, error) {
        switch cfg.MgmtProto {
        case sesn.MGMT_PROTO_NMP:
@@ -533,10 +543,14 @@ func (bx *BleXport) RspTimeout() time.Duration {
        return bx.cfg.BlehostdRspTimeout
 }
 
-func (bx *BleXport) AcquireMaster() error {
-       return bx.master.Acquire()
+func (bx *BleXport) AcquireMaster(token interface{}) error {
+       return bx.master.Acquire(token)
 }
 
 func (bx *BleXport) ReleaseMaster() {
        bx.master.Release()
 }
+
+func (bx *BleXport) StopWaitingForMaster(token interface{}, err error) {
+       bx.master.StopWaiting(token, err)
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/822cea97/nmxact/nmble/dispatch.go
----------------------------------------------------------------------
diff --git a/nmxact/nmble/dispatch.go b/nmxact/nmble/dispatch.go
index c9f17ec..9225292 100644
--- a/nmxact/nmble/dispatch.go
+++ b/nmxact/nmble/dispatch.go
@@ -84,23 +84,24 @@ type BleDispatcher struct {
 
 type msgCtor func() BleMsg
 
-func errRspCtor() BleMsg             { return &BleErrRsp{} }
-func syncRspCtor() BleMsg            { return &BleSyncRsp{} }
-func connectRspCtor() BleMsg         { return &BleConnectRsp{} }
-func terminateRspCtor() BleMsg       { return &BleTerminateRsp{} }
-func discSvcUuidRspCtor() BleMsg     { return &BleDiscSvcUuidRsp{} }
-func discAllChrsRspCtor() BleMsg     { return &BleDiscAllChrsRsp{} }
-func discChrUuidRspCtor() BleMsg     { return &BleDiscChrUuidRsp{} }
-func writeCmdRspCtor() BleMsg        { return &BleWriteCmdRsp{} }
-func exchangeMtuRspCtor() BleMsg     { return &BleExchangeMtuRsp{} }
-func genRandAddrRspCtor() BleMsg     { return &BleGenRandAddrRsp{} }
-func setRandAddrRspCtor() BleMsg     { return &BleSetRandAddrRsp{} }
-func connCancelRspCtor() BleMsg      { return &BleConnCancelRsp{} }
-func scanRspCtor() BleMsg            { return &BleScanRsp{} }
-func scanCancelRspCtor() BleMsg      { return &BleScanCancelRsp{} }
-func setPreferredMtuRspCtor() BleMsg { return &BleSetPreferredMtuRsp{} }
-func connFindRspCtor() BleMsg        { return &BleConnFindRsp{} }
-func resetRspCtor() BleMsg           { return &BleResetRsp{} }
+func errRspCtor() BleMsg              { return &BleErrRsp{} }
+func syncRspCtor() BleMsg             { return &BleSyncRsp{} }
+func connectRspCtor() BleMsg          { return &BleConnectRsp{} }
+func terminateRspCtor() BleMsg        { return &BleTerminateRsp{} }
+func discSvcUuidRspCtor() BleMsg      { return &BleDiscSvcUuidRsp{} }
+func discAllChrsRspCtor() BleMsg      { return &BleDiscAllChrsRsp{} }
+func discChrUuidRspCtor() BleMsg      { return &BleDiscChrUuidRsp{} }
+func writeCmdRspCtor() BleMsg         { return &BleWriteCmdRsp{} }
+func exchangeMtuRspCtor() BleMsg      { return &BleExchangeMtuRsp{} }
+func genRandAddrRspCtor() BleMsg      { return &BleGenRandAddrRsp{} }
+func setRandAddrRspCtor() BleMsg      { return &BleSetRandAddrRsp{} }
+func connCancelRspCtor() BleMsg       { return &BleConnCancelRsp{} }
+func scanRspCtor() BleMsg             { return &BleScanRsp{} }
+func scanCancelRspCtor() BleMsg       { return &BleScanCancelRsp{} }
+func setPreferredMtuRspCtor() BleMsg  { return &BleSetPreferredMtuRsp{} }
+func securityInitiateRspCtor() BleMsg { return &BleSecurityInitiateRsp{} }
+func connFindRspCtor() BleMsg         { return &BleConnFindRsp{} }
+func resetRspCtor() BleMsg            { return &BleResetRsp{} }
 
 func syncEvtCtor() BleMsg       { return &BleSyncEvt{} }
 func connectEvtCtor() BleMsg    { return &BleConnectEvt{} }
@@ -111,6 +112,7 @@ func notifyRxEvtCtor() BleMsg   { return &BleNotifyRxEvt{} }
 func mtuChangeEvtCtor() BleMsg  { return &BleMtuChangeEvt{} }
 func scanEvtCtor() BleMsg       { return &BleScanEvt{} }
 func scanTmoEvtCtor() BleMsg    { return &BleScanTmoEvt{} }
+func encChangeEvtCtor() BleMsg  { return &BleEncChangeEvt{} }
 
 var msgCtorMap = map[OpTypePair]msgCtor{
        {MSG_OP_RSP, MSG_TYPE_ERR}:               errRspCtor,
@@ -128,6 +130,7 @@ var msgCtorMap = map[OpTypePair]msgCtor{
        {MSG_OP_RSP, MSG_TYPE_SCAN}:              scanRspCtor,
        {MSG_OP_RSP, MSG_TYPE_SCAN_CANCEL}:       scanCancelRspCtor,
        {MSG_OP_RSP, MSG_TYPE_SET_PREFERRED_MTU}: setPreferredMtuRspCtor,
+       {MSG_OP_RSP, MSG_TYPE_SECURITY_INITIATE}: securityInitiateRspCtor,
        {MSG_OP_RSP, MSG_TYPE_CONN_FIND}:         connFindRspCtor,
        {MSG_OP_RSP, MSG_TYPE_RESET}:             resetRspCtor,
 
@@ -140,6 +143,7 @@ var msgCtorMap = map[OpTypePair]msgCtor{
        {MSG_OP_EVT, MSG_TYPE_MTU_CHANGE_EVT}: mtuChangeEvtCtor,
        {MSG_OP_EVT, MSG_TYPE_SCAN_EVT}:       scanEvtCtor,
        {MSG_OP_EVT, MSG_TYPE_SCAN_TMO_EVT}:   scanTmoEvtCtor,
+       {MSG_OP_EVT, MSG_TYPE_ENC_CHANGE_EVT}: encChangeEvtCtor,
 }
 
 func NewBleDispatcher() *BleDispatcher {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/822cea97/nmxact/nmserial/serial_xport.go
----------------------------------------------------------------------
diff --git a/nmxact/nmserial/serial_xport.go b/nmxact/nmserial/serial_xport.go
index 37f991f..a8c0c71 100644
--- a/nmxact/nmserial/serial_xport.go
+++ b/nmxact/nmserial/serial_xport.go
@@ -14,6 +14,7 @@ import (
 
        "mynewt.apache.org/newt/util"
        "mynewt.apache.org/newtmgr/nmxact/nmxutil"
+       "mynewt.apache.org/newtmgr/nmxact/scan"
        "mynewt.apache.org/newtmgr/nmxact/sesn"
 )
 
@@ -56,6 +57,10 @@ func (sx *SerialXport) BuildSesn(cfg sesn.SesnCfg) 
(sesn.Sesn, error) {
        }
 }
 
+func (sx *SerialXport) BuildScanner() (scan.Scanner, error) {
+       return nil, fmt.Errorf("Attempt to build serial scanner")
+}
+
 func (sx *SerialXport) Start() error {
        c := &serial.Config{
                Name:        sx.cfg.DevPath,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/822cea97/nmxact/nmxutil/nmxutil.go
----------------------------------------------------------------------
diff --git a/nmxact/nmxutil/nmxutil.go b/nmxact/nmxutil/nmxutil.go
index 707b1bc..257d6b5 100644
--- a/nmxact/nmxutil/nmxutil.go
+++ b/nmxact/nmxutil/nmxutil.go
@@ -1,6 +1,7 @@
 package nmxutil
 
 import (
+       "fmt"
        "math/rand"
        "os"
        "sync"
@@ -40,19 +41,22 @@ func NextNmpSeq() uint8 {
        return val
 }
 
+type SRWaiter struct {
+       c     chan error
+       token interface{}
+}
+
 type SingleResource struct {
        acquired  bool
-       waitQueue [](chan error)
+       waitQueue []SRWaiter
        mtx       sync.Mutex
 }
 
 func NewSingleResource() SingleResource {
-       return SingleResource{
-               waitQueue: [](chan error){},
-       }
+       return SingleResource{}
 }
 
-func (s *SingleResource) Acquire() error {
+func (s *SingleResource) Acquire(token interface{}) error {
        s.mtx.Lock()
 
        if !s.acquired {
@@ -61,12 +65,17 @@ func (s *SingleResource) Acquire() error {
                return nil
        }
 
-       w := make(chan error)
+       // XXX: Verify no duplicates.
+
+       w := SRWaiter{
+               c:     make(chan error),
+               token: token,
+       }
        s.waitQueue = append(s.waitQueue, w)
 
        s.mtx.Unlock()
 
-       err := <-w
+       err := <-w.c
        if err != nil {
                return err
        }
@@ -94,7 +103,19 @@ func (s *SingleResource) Release() {
 
        s.mtx.Unlock()
 
-       w <- nil
+       w.c <- nil
+}
+
+func (s *SingleResource) StopWaiting(token interface{}, err error) {
+       s.mtx.Lock()
+       defer s.mtx.Unlock()
+
+       for _, w := range s.waitQueue {
+               if w.token == token {
+                       w.c <- err
+                       return
+               }
+       }
 }
 
 func (s *SingleResource) Abort(err error) {
@@ -102,9 +123,9 @@ func (s *SingleResource) Abort(err error) {
        defer s.mtx.Unlock()
 
        for _, w := range s.waitQueue {
-               w <- err
+               w.c <- err
        }
-       s.waitQueue = [](chan error){}
+       s.waitQueue = nil
 }
 
 type ErrLessFn func(a error, b error) bool
@@ -122,6 +143,7 @@ type ErrFunnel struct {
        curErr   error
        errTimer *time.Timer
        started  bool
+       waiters  [](chan error)
 }
 
 func (f *ErrFunnel) Start() {
@@ -175,8 +197,13 @@ func (f *ErrFunnel) Reset() {
 
 func (f *ErrFunnel) timerExp() {
        f.mtx.Lock()
+
        err := f.curErr
        f.curErr = nil
+
+       waiters := f.waiters
+       f.waiters = nil
+
        f.mtx.Unlock()
 
        if err == nil {
@@ -184,4 +211,34 @@ func (f *ErrFunnel) timerExp() {
        }
 
        f.ProcCb(err)
+
+       for _, w := range waiters {
+               w <- err
+       }
+}
+
+func (f *ErrFunnel) Wait() error {
+       var err error
+       var c chan error
+
+       f.mtx.Lock()
+
+       if !f.started {
+               if f.curErr == nil {
+                       err = fmt.Errorf("Wait on unstarted ErrFunnel")
+               } else {
+                       err = f.curErr
+               }
+       } else {
+               c = make(chan error)
+               f.waiters = append(f.waiters, c)
+       }
+
+       f.mtx.Unlock()
+
+       if err != nil {
+               return err
+       } else {
+               return <-c
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/822cea97/nmxact/scan/scan.go
----------------------------------------------------------------------
diff --git a/nmxact/scan/scan.go b/nmxact/scan/scan.go
new file mode 100644
index 0000000..c90546e
--- /dev/null
+++ b/nmxact/scan/scan.go
@@ -0,0 +1,48 @@
+package scan
+
+import (
+       "mynewt.apache.org/newtmgr/nmxact/bledefs"
+       "mynewt.apache.org/newtmgr/nmxact/sesn"
+)
+
+type ScanPeer struct {
+       HwId   []byte
+       Opaque interface{}
+}
+
+type ScanFn func(peer ScanPeer)
+
+type Cfg struct {
+       ScanCb  ScanFn
+       SesnCfg sesn.SesnCfg
+}
+
+type Scanner interface {
+       Start(cfg Cfg) error
+       Stop() error
+}
+
+func BleOmpScanCfg(ScanCb ScanFn) Cfg {
+       sc := sesn.NewSesnCfg()
+       sc.MgmtProto = sesn.MGMT_PROTO_OMP
+       sc.Ble.OwnAddrType = bledefs.BLE_ADDR_TYPE_RANDOM
+       sc.Ble.Encrypt = bledefs.BLE_ENCRYPT_PRIV_ONLY
+       sc.Ble.PeerSpec = sesn.BlePeerSpec{
+               ScanPred: func(adv bledefs.BleAdvReport) bool {
+                       for _, u := range adv.Uuids16 {
+                               if u == bledefs.OmpSvcUuid {
+                                       return true
+                               }
+                       }
+
+                       return false
+               },
+       }
+
+       cfg := Cfg{
+               ScanCb:  ScanCb,
+               SesnCfg: sc,
+       }
+
+       return cfg
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/822cea97/nmxact/sesn/sesn_cfg.go
----------------------------------------------------------------------
diff --git a/nmxact/sesn/sesn_cfg.go b/nmxact/sesn/sesn_cfg.go
index 60cdc81..0022640 100644
--- a/nmxact/sesn/sesn_cfg.go
+++ b/nmxact/sesn/sesn_cfg.go
@@ -47,6 +47,8 @@ type SesnCfgBle struct {
        ConnTries    int
        CloseTimeout time.Duration
        OnCloseCb    BleOnCloseFn
+
+       Encrypt bledefs.BleEncryptWhen
 }
 
 type SesnCfg struct {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/822cea97/nmxact/xport/xport.go
----------------------------------------------------------------------
diff --git a/nmxact/xport/xport.go b/nmxact/xport/xport.go
index 85ef2b2..ec8a499 100644
--- a/nmxact/xport/xport.go
+++ b/nmxact/xport/xport.go
@@ -1,6 +1,7 @@
 package xport
 
 import (
+       "mynewt.apache.org/newtmgr/nmxact/scan"
        "mynewt.apache.org/newtmgr/nmxact/sesn"
 )
 
@@ -9,7 +10,9 @@ type RxFn func(data []byte)
 type Xport interface {
        Start() error
        Stop() error
+
        BuildSesn(cfg sesn.SesnCfg) (sesn.Sesn, error)
+       BuildScanner() (scan.Scanner, error)
 
        Tx(data []byte) error
 }


Reply via email to