nmxact - Scan to determine peer address.
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/2c153c28 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/tree/2c153c28 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/diff/2c153c28 Branch: refs/heads/master Commit: 2c153c283bfb17ae9b8f0bfc5916cd11cf0a5247 Parents: d24f040 Author: Christopher Collins <[email protected]> Authored: Thu Mar 16 19:15:08 2017 -0700 Committer: Christopher Collins <[email protected]> Committed: Tue Mar 28 15:38:36 2017 -0700 ---------------------------------------------------------------------- nmxact/bledefs/bledefs.go | 145 +++++++++++++++++++++++++++++++----- nmxact/nmble/ble_act.go | 75 +++++++++++++++++++ nmxact/nmble/ble_fsm.go | 108 ++++++++++++++++++++++----- nmxact/nmble/ble_oic_sesn.go | 2 +- nmxact/nmble/ble_plain_sesn.go | 2 +- nmxact/nmble/ble_proto.go | 69 +++++++++++++++++ nmxact/nmble/ble_util.go | 16 ++++ nmxact/nmble/dispatch.go | 6 ++ nmxact/sesn/sesn_cfg.go | 2 +- 9 files changed, 385 insertions(+), 40 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/2c153c28/nmxact/bledefs/bledefs.go ---------------------------------------------------------------------- diff --git a/nmxact/bledefs/bledefs.go b/nmxact/bledefs/bledefs.go index 314cbec..5b12d0a 100644 --- a/nmxact/bledefs/bledefs.go +++ b/nmxact/bledefs/bledefs.go @@ -27,10 +27,10 @@ import ( "strings" ) -type BleAddrType int - const BLE_ATT_ATTR_MAX_LEN = 512 +type BleAddrType int + const ( BLE_ADDR_TYPE_PUBLIC BleAddrType = 0 BLE_ADDR_TYPE_RANDOM = 1 @@ -45,21 +45,6 @@ var BleAddrTypeStringMap = map[BleAddrType]string{ BLE_ADDR_TYPE_RPA_RND: "rpa_rnd", } -type BleAddr struct { - Bytes [6]byte -} - -type BleDev struct { - AddrType BleAddrType - Addr BleAddr -} - -func (bd *BleDev) String() string { - return fmt.Sprintf("%s,%s", - BleAddrTypeToString(bd.AddrType), - bd.Addr.String()) -} - func BleAddrTypeToString(addrType BleAddrType) string { s := BleAddrTypeStringMap[addrType] if s == "" { @@ -95,6 +80,10 @@ func (a *BleAddrType) UnmarshalJSON(data []byte) error { return err } +type BleAddr struct { + Bytes [6]byte +} + func ParseBleAddr(s string) (BleAddr, error) { ba := BleAddr{} @@ -146,3 +135,125 @@ func (ba *BleAddr) UnmarshalJSON(data []byte) error { return nil } + +type BleDev struct { + AddrType BleAddrType + Addr BleAddr +} + +func (bd *BleDev) String() string { + return fmt.Sprintf("%s,%s", + BleAddrTypeToString(bd.AddrType), + bd.Addr.String()) +} + +type BlePeerSpec struct { + Name string + Dev BleDev // Only used if name not present. +} + +type BleScanFilterPolicy int + +const ( + BLE_SCAN_FILT_NO_WL BleScanFilterPolicy = 0 + BLE_SCAN_FILT_USE_WL = 1 + BLE_SCAN_FILT_NO_WL_INITA = 2 + BLE_SCAN_FILT_USE_WL_INITA = 3 +) + +var BleScanFilterPolicyStringMap = map[BleScanFilterPolicy]string{ + BLE_SCAN_FILT_NO_WL: "no_wl", + BLE_SCAN_FILT_USE_WL: "use_wl", + BLE_SCAN_FILT_NO_WL_INITA: "no_wl_inita", + BLE_SCAN_FILT_USE_WL_INITA: "use_wl_inita", +} + +func BleScanFilterPolicyToString(filtPolicy BleScanFilterPolicy) string { + s := BleScanFilterPolicyStringMap[filtPolicy] + if s == "" { + panic(fmt.Sprintf("Invalid BleScanFilterPolicy: %d", int(filtPolicy))) + } + + return s +} + +func BleScanFilterPolicyFromString(s string) (BleScanFilterPolicy, error) { + for filtPolicy, name := range BleScanFilterPolicyStringMap { + if s == name { + return filtPolicy, nil + } + } + + return BleScanFilterPolicy(0), + fmt.Errorf("Invalid BleScanFilterPolicy string: %s", s) +} + +func (a BleScanFilterPolicy) MarshalJSON() ([]byte, error) { + return json.Marshal(BleScanFilterPolicyToString(a)) +} + +func (a *BleScanFilterPolicy) UnmarshalJSON(data []byte) error { + var err error + + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + + *a, err = BleScanFilterPolicyFromString(s) + return err +} + +type BleAdvEventType int + +const ( + BLE_ADV_EVENT_IND BleAdvEventType = 0 + BLE_ADV_EVENT_DIRECT_IND_HD = 1 + BLE_ADV_EVENT_SCAN_IND = 2 + BLE_ADV_EVENT_NONCONN_IND = 3 + BLE_ADV_EVENT_DIRECT_IND_LD = 4 +) + +var BleAdvEventTypeStringMap = map[BleAdvEventType]string{ + BLE_ADV_EVENT_IND: "ind", + BLE_ADV_EVENT_DIRECT_IND_HD: "direct_ind_hd", + BLE_ADV_EVENT_SCAN_IND: "scan_ind", + BLE_ADV_EVENT_NONCONN_IND: "nonconn_ind", + BLE_ADV_EVENT_DIRECT_IND_LD: "direct_ind_ld", +} + +func BleAdvEventTypeToString(advEventType BleAdvEventType) string { + s := BleAdvEventTypeStringMap[advEventType] + if s == "" { + panic(fmt.Sprintf("Invalid BleAdvEventType: %d", int(advEventType))) + } + + return s +} + +func BleAdvEventTypeFromString(s string) (BleAdvEventType, error) { + for advEventType, name := range BleAdvEventTypeStringMap { + if s == name { + return advEventType, nil + } + } + + return BleAdvEventType(0), + fmt.Errorf("Invalid BleAdvEventType string: %s", s) +} + +func (a BleAdvEventType) MarshalJSON() ([]byte, error) { + return json.Marshal(BleAdvEventTypeToString(a)) +} + +func (a *BleAdvEventType) UnmarshalJSON(data []byte) error { + var err error + + var s string + if err := json.Unmarshal(data, &s); err != nil { + return err + } + + *a, err = BleAdvEventTypeFromString(s) + return err +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/2c153c28/nmxact/nmble/ble_act.go ---------------------------------------------------------------------- diff --git a/nmxact/nmble/ble_act.go b/nmxact/nmble/ble_act.go index 673010c..08c396f 100644 --- a/nmxact/nmble/ble_act.go +++ b/nmxact/nmble/ble_act.go @@ -286,3 +286,78 @@ func exchangeMtu(x *BleXport, bl *BleListener, r *BleExchangeMtuReq) ( } } } + +type scanFn func(evt *BleScanEvt) + +func scan(x *BleXport, bl *BleListener, r *BleScanReq, + abortChan chan struct{}, scanCb scanFn) error { + + 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 *BleScanRsp: + bl.Acked = true + if msg.Status != 0 { + return StatusError(MSG_OP_RSP, MSG_TYPE_SCAN, msg.Status) + } + + case *BleScanEvt: + scanCb(msg) + + default: + } + + case <-bl.AfterTimeout(x.rspTimeout): + return BhdTimeoutError(MSG_TYPE_EXCHANGE_MTU) + + case <-abortChan: + return nil + } + } +} + +func scanCancel(x *BleXport, bl *BleListener, r *BleScanCancelReq) error { + 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 *BleScanCancelRsp: + bl.Acked = true + if msg.Status != 0 { + return StatusError(MSG_OP_RSP, MSG_TYPE_SCAN, msg.Status) + } + return nil + + default: + } + + case <-bl.AfterTimeout(x.rspTimeout): + return BhdTimeoutError(MSG_TYPE_EXCHANGE_MTU) + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/2c153c28/nmxact/nmble/ble_fsm.go ---------------------------------------------------------------------- diff --git a/nmxact/nmble/ble_fsm.go b/nmxact/nmble/ble_fsm.go index a9ce890..88ce90e 100644 --- a/nmxact/nmble/ble_fsm.go +++ b/nmxact/nmble/ble_fsm.go @@ -19,16 +19,17 @@ const DFLT_ATT_MTU = 23 const ( SESN_STATE_UNCONNECTED BleSesnState = 0 - SESN_STATE_CONNECTING = 1 - SESN_STATE_CONNECTED = 2 - SESN_STATE_EXCHANGING_MTU = 3 - SESN_STATE_EXCHANGED_MTU = 4 - SESN_STATE_DISCOVERING_SVC = 5 - SESN_STATE_DISCOVERED_SVC = 6 - SESN_STATE_DISCOVERING_CHR = 7 - SESN_STATE_DISCOVERED_CHR = 8 - SESN_STATE_TERMINATING = 9 - SESN_STATE_CONN_CANCELLING = 10 + SESN_STATE_SCANNING = 1 + SESN_STATE_CONNECTING = 2 + SESN_STATE_CONNECTED = 3 + SESN_STATE_EXCHANGING_MTU = 4 + SESN_STATE_EXCHANGED_MTU = 5 + SESN_STATE_DISCOVERING_SVC = 6 + SESN_STATE_DISCOVERED_SVC = 7 + SESN_STATE_DISCOVERING_CHR = 8 + SESN_STATE_DISCOVERED_CHR = 9 + SESN_STATE_TERMINATING = 10 + SESN_STATE_CONN_CANCELLING = 11 ) type BleRxNmpFn func(data []byte) @@ -37,7 +38,7 @@ type BleDisconnectFn func(err error) type BleFsmParams struct { Bx *BleXport OwnAddrType BleAddrType - Peer BleDev + PeerSpec BlePeerSpec SvcUuid BleUuid ReqChrUuid BleUuid RspChrUuid BleUuid @@ -47,8 +48,9 @@ type BleFsmParams struct { type BleFsm struct { bx *BleXport + peerSpec BlePeerSpec ownAddrType BleAddrType - peer BleDev + peer *BleDev svcUuid BleUuid reqChrUuid BleUuid rspChrUuid BleUuid @@ -71,10 +73,10 @@ type BleFsm struct { } func NewBleFsm(p BleFsmParams) *BleFsm { - return &BleFsm{ + bf := &BleFsm{ bx: p.Bx, + peerSpec: p.PeerSpec, ownAddrType: p.OwnAddrType, - peer: p.Peer, svcUuid: p.SvcUuid, reqChrUuid: p.ReqChrUuid, rspChrUuid: p.RspChrUuid, @@ -84,6 +86,12 @@ func NewBleFsm(p BleFsmParams) *BleFsm { bls: map[*BleListener]struct{}{}, attMtu: DFLT_ATT_MTU, } + + if bf.peerSpec.Name == "" { + bf.peer = &bf.peerSpec.Dev + } + + return bf } func (bf *BleFsm) disconnectError(reason int) error { @@ -347,6 +355,56 @@ func (bf *BleFsm) connect() error { return nil } +func (bf *BleFsm) scan() error { + r := NewBleScanReq() + r.OwnAddrType = bf.ownAddrType + r.DurationMs = 15000 + r.FilterPolicy = BLE_SCAN_FILT_NO_WL + r.Limited = false + r.Passive = false + r.FilterDuplicates = true + + bl, err := bf.addBleSeqListener(r.Seq) + if err != nil { + return err + } + defer bf.removeBleSeqListener(r.Seq) + + abortChan := make(chan struct{}, 1) + + scanCb := func(evt *BleScanEvt) { + if evt.DataName == bf.peerSpec.Name { + bf.peer = &BleDev{ + AddrType: evt.AddrType, + Addr: evt.Addr, + } + abortChan <- struct{}{} + } + } + if err := scan(bf.bx, bl, r, abortChan, scanCb); err != nil { + return err + } + + // Scanning still in progress; cancel the operation. + return bf.scanCancel() +} + +func (bf *BleFsm) scanCancel() error { + r := NewBleScanCancelReq() + + bl, err := bf.addBleSeqListener(r.Seq) + if err != nil { + return err + } + defer bf.removeBleSeqListener(r.Seq) + + if err := scanCancel(bf.bx, bl, r); err != nil { + return err + } + + return nil +} + func (bf *BleFsm) terminateSetState() error { bf.mtx.Lock() defer bf.mtx.Unlock() @@ -537,12 +595,22 @@ func (bf *BleFsm) Start() error { state := bf.getState() switch state { case SESN_STATE_UNCONNECTED: - cb := func() error { return bf.connect() } - err := bf.action( - SESN_STATE_UNCONNECTED, - SESN_STATE_CONNECTING, - SESN_STATE_CONNECTED, - cb) + var err error + if bf.peer == nil { + cb := func() error { return bf.scan() } + err = bf.action( + SESN_STATE_UNCONNECTED, + SESN_STATE_SCANNING, + SESN_STATE_UNCONNECTED, + cb) + } else { + cb := func() error { return bf.connect() } + err = bf.action( + SESN_STATE_UNCONNECTED, + SESN_STATE_CONNECTING, + SESN_STATE_CONNECTED, + cb) + } if err != nil { return err http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/2c153c28/nmxact/nmble/ble_oic_sesn.go ---------------------------------------------------------------------- diff --git a/nmxact/nmble/ble_oic_sesn.go b/nmxact/nmble/ble_oic_sesn.go index 6c6de2f..f0dead2 100644 --- a/nmxact/nmble/ble_oic_sesn.go +++ b/nmxact/nmble/ble_oic_sesn.go @@ -49,7 +49,7 @@ func NewBleOicSesn(bx *BleXport, cfg sesn.SesnCfg) *BleOicSesn { bos.bf = NewBleFsm(BleFsmParams{ Bx: bx, OwnAddrType: cfg.Ble.OwnAddrType, - Peer: cfg.Ble.Peer, + PeerSpec: cfg.Ble.Peer, SvcUuid: svcUuid, ReqChrUuid: reqChrUuid, RspChrUuid: rspChrUuid, http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/2c153c28/nmxact/nmble/ble_plain_sesn.go ---------------------------------------------------------------------- diff --git a/nmxact/nmble/ble_plain_sesn.go b/nmxact/nmble/ble_plain_sesn.go index 967e320..c4b24c6 100644 --- a/nmxact/nmble/ble_plain_sesn.go +++ b/nmxact/nmble/ble_plain_sesn.go @@ -43,7 +43,7 @@ func NewBlePlainSesn(bx *BleXport, cfg sesn.SesnCfg) *BlePlainSesn { bps.bf = NewBleFsm(BleFsmParams{ Bx: bx, OwnAddrType: cfg.Ble.OwnAddrType, - Peer: cfg.Ble.Peer, + PeerSpec: cfg.Ble.Peer, SvcUuid: svcUuid, ReqChrUuid: chrUuid, RspChrUuid: chrUuid, http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/2c153c28/nmxact/nmble/ble_proto.go ---------------------------------------------------------------------- diff --git a/nmxact/nmble/ble_proto.go b/nmxact/nmble/ble_proto.go index f8f936b..80ef2a0 100644 --- a/nmxact/nmble/ble_proto.go +++ b/nmxact/nmble/ble_proto.go @@ -227,6 +227,8 @@ const ( MSG_TYPE_GEN_RAND_ADDR = 12 MSG_TYPE_SET_RAND_ADDR = 13 MSG_TYPE_CONN_CANCEL = 14 + MSG_TYPE_SCAN = 15 + MSG_TYPE_SCAN_CANCEL = 16 MSG_TYPE_SYNC_EVT = 2049 MSG_TYPE_CONNECT_EVT = 2050 @@ -236,6 +238,7 @@ const ( MSG_TYPE_WRITE_ACK_EVT = 2054 MSG_TYPE_NOTIFY_RX_EVT = 2055 MSG_TYPE_MTU_CHANGE_EVT = 2056 + MSG_TYPE_SCAN_EVT = 2057 ) var MsgOpStringMap = map[MsgOp]string{ @@ -255,6 +258,8 @@ var MsgTypeStringMap = map[MsgType]string{ MSG_TYPE_WRITE_CMD: "write_cmd", MSG_TYPE_EXCHANGE_MTU: "exchange_mtu", MSG_TYPE_CONN_CANCEL: "conn_cancel", + MSG_TYPE_SCAN: "scan", + MSG_TYPE_SCAN_CANCEL: "scan_cancel", MSG_TYPE_SYNC_EVT: "sync_evt", MSG_TYPE_CONNECT_EVT: "connect_evt", @@ -263,6 +268,7 @@ var MsgTypeStringMap = map[MsgType]string{ MSG_TYPE_DISC_CHR_EVT: "disc_chr_evt", MSG_TYPE_NOTIFY_RX_EVT: "notify_rx_evt", MSG_TYPE_MTU_CHANGE_EVT: "mtu_change_evt", + MSG_TYPE_SCAN_EVT: "scan_evt", } type BleHdr struct { @@ -579,6 +585,69 @@ type BleMtuChangeEvt struct { Mtu int `json:"mtu"` } +type BleScanReq struct { + // Header + Op MsgOp `json:"op"` + Type MsgType `json:"type"` + Seq int `json:"seq"` + + // Mandatory + OwnAddrType BleAddrType `json:"own_addr_type"` + DurationMs int `json:"duration_ms"` + Itvl int `json:"itvl"` + Window int `json:"window"` + FilterPolicy BleScanFilterPolicy `json:"filter_policy"` + Limited bool `json:"limited"` + Passive bool `json:"passive"` + FilterDuplicates bool `json:"filter_duplicates"` +} + +type BleScanRsp struct { + // Header + Op MsgOp `json:"op"` + Type MsgType `json:"type"` + Seq int `json:"seq"` + + // Mandatory + Status int `json:"status"` +} + +type BleScanEvt struct { + // Header + Op MsgOp `json:"op"` + Type MsgType `json:"type"` + Seq int `json:"seq"` + + // Mandatory + EventType BleAdvEventType `json:"event_type"` + AddrType BleAddrType `json:"addr_type"` + Addr BleAddr `json:"addr"` + Rssi int8 `json:"rssi"` + Data BleBytes `json:"data"` + + // Optional + DataFlags uint8 `json:"data_flags"` + DataName string `json:"data_name"` + DataNameIsComplete bool `json:"data_name_is_complete"` +} + +type BleScanCancelReq struct { + // Header + Op MsgOp `json:"op"` + Type MsgType `json:"type"` + Seq int `json:"seq"` +} + +type BleScanCancelRsp struct { + // Header + Op MsgOp `json:"op"` + Type MsgType `json:"type"` + Seq int `json:"seq"` + + // Mandatory + Status int `json:"status"` +} + func ErrCodeToString(e int) string { var s string http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/2c153c28/nmxact/nmble/ble_util.go ---------------------------------------------------------------------- diff --git a/nmxact/nmble/ble_util.go b/nmxact/nmble/ble_util.go index a202186..08eb8d9 100644 --- a/nmxact/nmble/ble_util.go +++ b/nmxact/nmble/ble_util.go @@ -156,3 +156,19 @@ func NewBleWriteCmdReq() *BleWriteCmdReq { Data: BleBytes{}, } } + +func NewBleScanReq() *BleScanReq { + return &BleScanReq{ + Op: MSG_OP_REQ, + Type: MSG_TYPE_SCAN, + Seq: NextSeq(), + } +} + +func NewBleScanCancelReq() *BleScanCancelReq { + return &BleScanCancelReq{ + Op: MSG_OP_REQ, + Type: MSG_TYPE_SCAN_CANCEL, + Seq: NextSeq(), + } +} http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/2c153c28/nmxact/nmble/dispatch.go ---------------------------------------------------------------------- diff --git a/nmxact/nmble/dispatch.go b/nmxact/nmble/dispatch.go index cb1f864..546fc11 100644 --- a/nmxact/nmble/dispatch.go +++ b/nmxact/nmble/dispatch.go @@ -94,6 +94,8 @@ func discChrUuidRspCtor() BleMsg { return &BleDiscChrUuidRsp{} } func writeCmdRspCtor() BleMsg { return &BleWriteCmdRsp{} } func exchangeMtuRspCtor() BleMsg { return &BleExchangeMtuRsp{} } func connCancelRspCtor() BleMsg { return &BleConnCancelRsp{} } +func scanRspCtor() BleMsg { return &BleScanRsp{} } +func scanCancelRspCtor() BleMsg { return &BleScanCancelRsp{} } func syncEvtCtor() BleMsg { return &BleSyncEvt{} } func connectEvtCtor() BleMsg { return &BleConnectEvt{} } @@ -102,6 +104,7 @@ func discSvcEvtCtor() BleMsg { return &BleDiscSvcEvt{} } func discChrEvtCtor() BleMsg { return &BleDiscChrEvt{} } func notifyRxEvtCtor() BleMsg { return &BleNotifyRxEvt{} } func mtuChangeEvtCtor() BleMsg { return &BleMtuChangeEvt{} } +func scanEvtCtor() BleMsg { return &BleScanEvt{} } var msgCtorMap = map[OpTypePair]msgCtor{ {MSG_OP_RSP, MSG_TYPE_ERR}: errRspCtor, @@ -114,6 +117,8 @@ var msgCtorMap = map[OpTypePair]msgCtor{ {MSG_OP_RSP, MSG_TYPE_WRITE_CMD}: writeCmdRspCtor, {MSG_OP_RSP, MSG_TYPE_EXCHANGE_MTU}: exchangeMtuRspCtor, {MSG_OP_RSP, MSG_TYPE_CONN_CANCEL}: connCancelRspCtor, + {MSG_OP_RSP, MSG_TYPE_SCAN}: scanRspCtor, + {MSG_OP_RSP, MSG_TYPE_SCAN_CANCEL}: scanCancelRspCtor, {MSG_OP_EVT, MSG_TYPE_SYNC_EVT}: syncEvtCtor, {MSG_OP_EVT, MSG_TYPE_CONNECT_EVT}: connectEvtCtor, @@ -122,6 +127,7 @@ var msgCtorMap = map[OpTypePair]msgCtor{ {MSG_OP_EVT, MSG_TYPE_DISC_CHR_EVT}: discChrEvtCtor, {MSG_OP_EVT, MSG_TYPE_NOTIFY_RX_EVT}: notifyRxEvtCtor, {MSG_OP_EVT, MSG_TYPE_MTU_CHANGE_EVT}: mtuChangeEvtCtor, + {MSG_OP_EVT, MSG_TYPE_SCAN_EVT}: scanEvtCtor, } func NewBleDispatcher() *BleDispatcher { http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newtmgr/blob/2c153c28/nmxact/sesn/sesn_cfg.go ---------------------------------------------------------------------- diff --git a/nmxact/sesn/sesn_cfg.go b/nmxact/sesn/sesn_cfg.go index 21def4b..cb6dce6 100644 --- a/nmxact/sesn/sesn_cfg.go +++ b/nmxact/sesn/sesn_cfg.go @@ -17,7 +17,7 @@ type OnCloseFn func(s Sesn, err error) type SesnCfgBle struct { OwnAddrType bledefs.BleAddrType - Peer bledefs.BleDev + Peer bledefs.BlePeerSpec CloseTimeout time.Duration }
