| /** |
| * 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 nmble |
| |
| import ( |
| "encoding/json" |
| "fmt" |
| "sync" |
| |
| "mynewt.apache.org/newtmgr/nmxact/nmxutil" |
| |
| log "github.com/Sirupsen/logrus" |
| ) |
| |
| type MsgBase struct { |
| // Header |
| Op MsgOp `json:"op"` |
| Type MsgType `json:"type"` |
| Seq BleSeq `json:"seq"` |
| |
| // Optional |
| ConnHandle int `json:"conn_handle" json:",omitempty"` |
| } |
| |
| type OpTypePair struct { |
| Op MsgOp |
| Type MsgType |
| } |
| |
| // The dispatcher is the owner of the listeners it points to. Only the |
| // dispatcher writes to these listeners. |
| type Dispatcher struct { |
| lm *ListenerMap |
| mtx sync.Mutex |
| } |
| |
| type msgCtor func() Msg |
| |
| func errRspCtor() Msg { return &BleErrRsp{} } |
| func syncRspCtor() Msg { return &BleSyncRsp{} } |
| func connectRspCtor() Msg { return &BleConnectRsp{} } |
| func terminateRspCtor() Msg { return &BleTerminateRsp{} } |
| func discAllSvcsRspCtor() Msg { return &BleDiscAllSvcsRsp{} } |
| func discSvcUuidRspCtor() Msg { return &BleDiscSvcUuidRsp{} } |
| func discAllChrsRspCtor() Msg { return &BleDiscAllChrsRsp{} } |
| func discChrUuidRspCtor() Msg { return &BleDiscChrUuidRsp{} } |
| func discAllDscsRspCtor() Msg { return &BleDiscAllDscsRsp{} } |
| func writeRspCtor() Msg { return &BleWriteRsp{} } |
| func writeCmdRspCtor() Msg { return &BleWriteCmdRsp{} } |
| func exchangeMtuRspCtor() Msg { return &BleExchangeMtuRsp{} } |
| func genRandAddrRspCtor() Msg { return &BleGenRandAddrRsp{} } |
| func setRandAddrRspCtor() Msg { return &BleSetRandAddrRsp{} } |
| func connCancelRspCtor() Msg { return &BleConnCancelRsp{} } |
| func scanRspCtor() Msg { return &BleScanRsp{} } |
| func scanCancelRspCtor() Msg { return &BleScanCancelRsp{} } |
| func setPreferredMtuRspCtor() Msg { return &BleSetPreferredMtuRsp{} } |
| func securityInitiateRspCtor() Msg { return &BleSecurityInitiateRsp{} } |
| func connFindRspCtor() Msg { return &BleConnFindRsp{} } |
| func resetRspCtor() Msg { return &BleResetRsp{} } |
| func advStartRspCtor() Msg { return &BleAdvStartRsp{} } |
| func advStopRspCtor() Msg { return &BleAdvStopRsp{} } |
| func advSetDataRspCtor() Msg { return &BleAdvSetDataRsp{} } |
| func advRspSetDataRspCtor() Msg { return &BleAdvRspSetDataRsp{} } |
| func advFieldsRspCtor() Msg { return &BleAdvFieldsRsp{} } |
| func clearSvcsRspCtor() Msg { return &BleClearSvcsRsp{} } |
| func addSvcsRspCtor() Msg { return &BleAddSvcsRsp{} } |
| func commitSvcsRspCtor() Msg { return &BleCommitSvcsRsp{} } |
| func accessStatusRspCtor() Msg { return &BleAccessStatusRsp{} } |
| func notifyRspCtor() Msg { return &BleNotifyRsp{} } |
| func findChrRspCtor() Msg { return &BleFindChrRsp{} } |
| func oobSecDataRspCtor() Msg { return &BleSmInjectIoRsp{} } |
| |
| func syncEvtCtor() Msg { return &BleSyncEvt{} } |
| func connectEvtCtor() Msg { return &BleConnectEvt{} } |
| func connCancelEvtCtor() Msg { return &BleConnCancelEvt{} } |
| func disconnectEvtCtor() Msg { return &BleDisconnectEvt{} } |
| func discSvcEvtCtor() Msg { return &BleDiscSvcEvt{} } |
| func discChrEvtCtor() Msg { return &BleDiscChrEvt{} } |
| func discDscEvtCtor() Msg { return &BleDiscDscEvt{} } |
| func writeAckEvtCtor() Msg { return &BleWriteAckEvt{} } |
| func notifyRxEvtCtor() Msg { return &BleNotifyRxEvt{} } |
| func mtuChangeEvtCtor() Msg { return &BleMtuChangeEvt{} } |
| func scanEvtCtor() Msg { return &BleScanEvt{} } |
| func scanTmoEvtCtor() Msg { return &BleScanCompleteEvt{} } |
| func advCompleteEvtCtor() Msg { return &BleAdvCompleteEvt{} } |
| func encChangeEvtCtor() Msg { return &BleEncChangeEvt{} } |
| func resetEvtCtor() Msg { return &BleResetEvt{} } |
| func accessEvtCtor() Msg { return &BleAccessEvt{} } |
| func passkeyEvtCtor() Msg { return &BlePasskeyEvt{} } |
| |
| var msgCtorMap = map[OpTypePair]msgCtor{ |
| {MSG_OP_RSP, MSG_TYPE_ERR}: errRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_SYNC}: syncRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_CONNECT}: connectRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_TERMINATE}: terminateRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_DISC_ALL_SVCS}: discAllSvcsRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_DISC_SVC_UUID}: discSvcUuidRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_DISC_ALL_CHRS}: discAllChrsRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_DISC_CHR_UUID}: discChrUuidRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_DISC_ALL_DSCS}: discAllDscsRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_WRITE}: writeRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_WRITE_CMD}: writeCmdRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_EXCHANGE_MTU}: exchangeMtuRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_GEN_RAND_ADDR}: genRandAddrRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_SET_RAND_ADDR}: setRandAddrRspCtor, |
| {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_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, |
| {MSG_OP_RSP, MSG_TYPE_ADV_START}: advStartRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_ADV_STOP}: advStopRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_ADV_SET_DATA}: advSetDataRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_ADV_RSP_SET_DATA}: advRspSetDataRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_ADV_FIELDS}: advFieldsRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_CLEAR_SVCS}: clearSvcsRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_ADD_SVCS}: addSvcsRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_COMMIT_SVCS}: commitSvcsRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_ACCESS_STATUS}: accessStatusRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_NOTIFY}: notifyRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_FIND_CHR}: findChrRspCtor, |
| {MSG_OP_RSP, MSG_TYPE_SM_INJECT_IO}: oobSecDataRspCtor, |
| |
| {MSG_OP_EVT, MSG_TYPE_SYNC_EVT}: syncEvtCtor, |
| {MSG_OP_EVT, MSG_TYPE_CONNECT_EVT}: connectEvtCtor, |
| {MSG_OP_EVT, MSG_TYPE_CONN_CANCEL_EVT}: connCancelEvtCtor, |
| {MSG_OP_EVT, MSG_TYPE_DISCONNECT_EVT}: disconnectEvtCtor, |
| {MSG_OP_EVT, MSG_TYPE_DISC_SVC_EVT}: discSvcEvtCtor, |
| {MSG_OP_EVT, MSG_TYPE_DISC_CHR_EVT}: discChrEvtCtor, |
| {MSG_OP_EVT, MSG_TYPE_DISC_DSC_EVT}: discDscEvtCtor, |
| {MSG_OP_EVT, MSG_TYPE_WRITE_ACK_EVT}: writeAckEvtCtor, |
| {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, |
| {MSG_OP_EVT, MSG_TYPE_SCAN_COMPLETE_EVT}: scanTmoEvtCtor, |
| {MSG_OP_EVT, MSG_TYPE_ADV_COMPLETE_EVT}: advCompleteEvtCtor, |
| {MSG_OP_EVT, MSG_TYPE_ENC_CHANGE_EVT}: encChangeEvtCtor, |
| {MSG_OP_EVT, MSG_TYPE_RESET_EVT}: resetEvtCtor, |
| {MSG_OP_EVT, MSG_TYPE_ACCESS_EVT}: accessEvtCtor, |
| {MSG_OP_EVT, MSG_TYPE_PASSKEY_EVT}: passkeyEvtCtor, |
| } |
| |
| func NewDispatcher() *Dispatcher { |
| return &Dispatcher{ |
| lm: NewListenerMap(), |
| } |
| } |
| |
| func (d *Dispatcher) AddListener(key ListenerKey, listener *Listener) error { |
| d.mtx.Lock() |
| defer d.mtx.Unlock() |
| |
| return d.lm.AddListener(key, listener) |
| } |
| |
| func (d *Dispatcher) RemoveListener(listener *Listener) *ListenerKey { |
| d.mtx.Lock() |
| defer d.mtx.Unlock() |
| |
| key := d.lm.RemoveListener(listener) |
| if key == nil { |
| return nil |
| } |
| |
| listener.Close() |
| return key |
| } |
| |
| func (d *Dispatcher) RemoveKey(key ListenerKey) *Listener { |
| d.mtx.Lock() |
| defer d.mtx.Unlock() |
| |
| listener := d.lm.RemoveKey(key) |
| if listener == nil { |
| return nil |
| } |
| |
| listener.Close() |
| return listener |
| } |
| |
| func (d *Dispatcher) ErrorAll(err error) { |
| nmxutil.Assert(err != nil) |
| |
| d.mtx.Lock() |
| listeners := d.lm.ExtractAll() |
| d.mtx.Unlock() |
| |
| for _, listener := range listeners { |
| listener.ErrChan <- err |
| listener.Close() |
| } |
| } |
| |
| func decodeBleBase(data []byte) (MsgBase, error) { |
| base := MsgBase{} |
| if err := json.Unmarshal(data, &base); err != nil { |
| return base, err |
| } |
| |
| return base, nil |
| } |
| |
| func decodeMsg(data []byte) (MsgBase, Msg, error) { |
| base, err := decodeBleBase(data) |
| if err != nil { |
| return base, nil, err |
| } |
| |
| opTypePair := OpTypePair{base.Op, base.Type} |
| cb := msgCtorMap[opTypePair] |
| if cb == nil { |
| return base, nil, fmt.Errorf( |
| "Unrecognized op+type pair: %s, %s", |
| MsgOpToString(base.Op), MsgTypeToString(base.Type)) |
| } |
| |
| msg := cb() |
| if err := json.Unmarshal(data, msg); err != nil { |
| return base, nil, err |
| } |
| |
| return base, msg, nil |
| } |
| |
| func (d *Dispatcher) Dispatch(data []byte) { |
| base, msg, err := decodeMsg(data) |
| if err != nil { |
| log.Warnf("BLE dispatch error: %s", err.Error()) |
| return |
| } |
| |
| d.mtx.Lock() |
| defer d.mtx.Unlock() |
| |
| _, listener := d.lm.FindListener(base.Seq, base.Type, base.ConnHandle) |
| |
| if listener == nil { |
| log.Debugf( |
| "No BLE listener for op=%d type=%d seq=%d connHandle=%d", |
| base.Op, base.Type, base.Seq, base.ConnHandle) |
| return |
| } |
| |
| listener.MsgChan <- msg |
| } |