initial commit

This commit is contained in:
2022-10-23 23:45:43 -07:00
commit e190fa5193
6450 changed files with 8626944 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,349 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief L2CAP main module.
*
* Copyright (c) 2009-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed 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.
*/
/*************************************************************************************************/
#include "wsf_types.h"
#include "wsf_assert.h"
#include "wsf_trace.h"
#include "wsf_msg.h"
#include "util/bstream.h"
#include "l2c_api.h"
#include "l2c_main.h"
#include "dm_api.h"
/**************************************************************************************************
Macros
**************************************************************************************************/
/**************************************************************************************************
Global Variables
**************************************************************************************************/
/* Control block */
l2cCb_t l2cCb;
/*************************************************************************************************/
/*!
* \brief Default callback function for unregistered CID.
*
* \param handle The connection handle.
* \param len The length of the L2CAP payload data in pPacket.
* \param pPacket A buffer containing the packet.
*
* \return None.
*/
/*************************************************************************************************/
static void l2cDefaultDataCback(uint16_t handle, uint16_t len, uint8_t *pPacket)
{
L2C_TRACE_WARN0("rcvd data on uregistered cid");
}
/*************************************************************************************************/
/*!
* \brief Default callback function for unregistered CID.
*
* \param handle The connection handle.
* \param cid The L2CAP connection ID.
* \param len The length of the L2CAP payload data in pPacket.
* \param pPacket A buffer containing the packet.
*
* \return None.
*/
/*************************************************************************************************/
static void l2cDefaultDataCidCback(uint16_t handle, uint16_t cid, uint16_t len, uint8_t *pPacket)
{
L2C_TRACE_WARN1("unknown cid=0x%04x", cid);
}
/*************************************************************************************************/
/*!
* \brief Default L2CAP control callback function.
*
* \param pMsg Pointer to message structure.
*
* \return None.
*/
/*************************************************************************************************/
static void l2cDefaultCtrlCback(wsfMsgHdr_t *pMsg)
{
return;
}
/*************************************************************************************************/
/*!
* \brief Process received L2CAP signaling packets.
*
* \param handle The connection handle.
* \param len The length of the L2CAP payload data in pPacket.
* \param pPacket A buffer containing the packet.
*
* \return None.
*/
/*************************************************************************************************/
void l2cRxSignalingPkt(uint16_t handle, uint16_t len, uint8_t *pPacket)
{
uint8_t role;
dmConnId_t connId;
if ((connId = DmConnIdByHandle(handle)) == DM_CONN_ID_NONE)
{
return;
}
role = DmConnRole(connId);
if ((role == DM_ROLE_MASTER) && (l2cCb.masterRxSignalingPkt != NULL))
{
(*l2cCb.masterRxSignalingPkt)(handle, len, pPacket);
}
else if ((role == DM_ROLE_SLAVE) && (l2cCb.slaveRxSignalingPkt != NULL))
{
(*l2cCb.slaveRxSignalingPkt)(handle, len, pPacket);
}
else
{
L2C_TRACE_ERR1("Invalid role configuration: role=%d", role);
}
}
/*************************************************************************************************/
/*!
* \brief HCI ACL data callback function.
*
* \param pPacket A buffer containing an ACL packet.
*
* \return None.
*/
/*************************************************************************************************/
static void l2cHciAclCback(uint8_t *pPacket)
{
uint16_t handle;
uint16_t hciLen;
uint16_t cid;
uint16_t l2cLen;
uint8_t *p = pPacket;
/* parse HCI handle and length */
BSTREAM_TO_UINT16(handle, p);
handle &= HCI_HANDLE_MASK;
BSTREAM_TO_UINT16(hciLen, p);
/* parse L2CAP length */
if (hciLen >= L2C_HDR_LEN)
{
BSTREAM_TO_UINT16(l2cLen, p);
}
else
{
l2cLen = 0;
}
/* verify L2CAP length vs HCI length */
if (hciLen == (l2cLen + L2C_HDR_LEN))
{
/* parse CID */
BSTREAM_TO_UINT16(cid, p);
switch (cid)
{
case L2C_CID_LE_SIGNALING:
(*l2cCb.l2cSignalingCback)(handle, l2cLen, pPacket);
break;
case L2C_CID_ATT:
(*l2cCb.attDataCback)(handle, l2cLen, pPacket);
break;
case L2C_CID_SMP:
(*l2cCb.smpDataCback)(handle, l2cLen, pPacket);
break;
default:
(*l2cCb.l2cDataCidCback)(handle, cid, l2cLen, pPacket);
break;
}
}
/* else length mismatch */
else
{
L2C_TRACE_WARN2("length mismatch: l2c=%u hci=%u", l2cLen, hciLen);
}
/* deallocate buffer */
WsfMsgFree(pPacket);
}
/*************************************************************************************************/
/*!
* \brief HCI flow control callback function.
*
* \param handle The connection handle.
* \param flowDisabled TRUE if data flow is disabled.
*
* \return None.
*/
/*************************************************************************************************/
static void l2cHciFlowCback(uint16_t handle, bool_t flowDisabled)
{
wsfMsgHdr_t hdr;
/* get conn ID for handle */
if ((hdr.param = DmConnIdByHandle(handle)) != DM_CONN_ID_NONE)
{
/* execute higher layer flow control callbacks */
hdr.event = flowDisabled;
(*l2cCb.attCtrlCback)(&hdr);
hdr.event = flowDisabled;
(*l2cCb.smpCtrlCback)(&hdr);
/* execute connection oriented channel flow control callback */
hdr.event = flowDisabled;
(*l2cCb.l2cCocCtrlCback)(&hdr);
}
}
/*************************************************************************************************/
/*!
* \brief Send a command reject message with reason "not understood".
*
* \param handle The connection handle.
* \param identifier Identifier value in received message being rejected.
* \param reason Why request was rejected.
*
* \return None.
*/
/*************************************************************************************************/
void l2cSendCmdReject(uint16_t handle, uint8_t identifier, uint16_t reason)
{
uint8_t *pPacket;
uint8_t *p;
/* allocate msg buffer */
if ((pPacket = l2cMsgAlloc(L2C_SIG_PKT_BASE_LEN + L2C_SIG_CMD_REJ_LEN)) != NULL)
{
/* build message */
p = pPacket + L2C_PAYLOAD_START;
UINT8_TO_BSTREAM(p, L2C_SIG_CMD_REJ); /* command code */
UINT8_TO_BSTREAM(p, identifier); /* identifier */
UINT16_TO_BSTREAM(p, L2C_SIG_CMD_REJ_LEN); /* parameter length */
UINT16_TO_BSTREAM(p, reason); /* reason */
/* send packet */
L2cDataReq(L2C_CID_LE_SIGNALING, handle, (L2C_SIG_HDR_LEN + L2C_SIG_CMD_REJ_LEN), pPacket);
}
}
/*************************************************************************************************/
/*!
* \brief Allocate an L2CAP data message buffer to be used for the L2CAP protocol messages.
*
* \param len Message length in bytes.
*
* \return Pointer to data message buffer or NULL if allocation failed.
*/
/*************************************************************************************************/
void *l2cMsgAlloc(uint16_t len)
{
return WsfMsgDataAlloc(len, HCI_TX_DATA_TAILROOM);
}
/*************************************************************************************************/
/*!
* \brief Initialize L2C subsystem.
*
* \return None.
*/
/*************************************************************************************************/
void L2cInit(void)
{
/* Initialize control block */
l2cCb.attDataCback = l2cDefaultDataCback;
l2cCb.smpDataCback = l2cDefaultDataCback;
l2cCb.l2cSignalingCback = l2cRxSignalingPkt;
l2cCb.attCtrlCback = l2cDefaultCtrlCback;
l2cCb.smpCtrlCback = l2cDefaultCtrlCback;
l2cCb.l2cCocCtrlCback = l2cDefaultCtrlCback;
l2cCb.l2cDataCidCback = l2cDefaultDataCidCback;
l2cCb.identifier = 1;
/* Register with HCI */
HciAclRegister(l2cHciAclCback, l2cHciFlowCback);
}
/*************************************************************************************************/
/*!
* \brief called by the L2C client, such as ATT or SMP, to register for the given CID.
*
* \param cid channel identifier.
* \param dataCback Callback function for L2CAP data received for this CID.
* \param ctrlCback Callback function for control events for this CID.
*
* \return None.
*/
/*************************************************************************************************/
void L2cRegister(uint16_t cid, l2cDataCback_t dataCback, l2cCtrlCback_t ctrlCback)
{
WSF_ASSERT((cid == L2C_CID_ATT) || (cid == L2C_CID_SMP));
/* store the callbacks */
if (cid == L2C_CID_ATT)
{
/* registering for attribute protocol */
l2cCb.attDataCback = dataCback;
l2cCb.attCtrlCback = ctrlCback;
}
else
{
/* registering for security manager protocol */
l2cCb.smpDataCback = dataCback;
l2cCb.smpCtrlCback = ctrlCback;
}
}
/*************************************************************************************************/
/*!
* \brief Send an L2CAP data packet on the given CID.
*
* \param cid The channel identifier.
* \param handle The connection handle. The client receives this handle from DM.
* \param len The length of the payload data in pPacket.
* \param pPacket A buffer containing the packet.
*
* \return None.
*/
/*************************************************************************************************/
void L2cDataReq(uint16_t cid, uint16_t handle, uint16_t len, uint8_t *pPacket)
{
uint8_t *p = pPacket;
/* Set HCI header */
UINT16_TO_BSTREAM(p, handle);
UINT16_TO_BSTREAM(p, (len + L2C_HDR_LEN));
/* Set L2CAP header */
UINT16_TO_BSTREAM(p, len);
UINT16_TO_BSTREAM(p, cid);
/* Send to HCI */
HciSendAclData(pPacket);
}
@@ -0,0 +1,81 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief L2CAP main module.
*
* Copyright (c) 2009-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed 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.
*/
/*************************************************************************************************/
#ifndef L2C_MAIN_H
#define L2C_MAIN_H
#include "l2c_api.h"
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Macros
**************************************************************************************************/
/* Return the next L2CAP signaling req identifier. Cannot be zero. */
#define L2C_NEXT_ID(id) (((id) == 255) ? (1) : ((id) + 1))
/* L2C event handler message types */
#define L2C_MSG_REQ_TIMEOUT 1 /* L2CAP slave signaling request timeout */
#define L2C_MSG_TYPE_MAX 1
/**************************************************************************************************
Data Types
**************************************************************************************************/
/* Data callback with CID */
typedef void (*l2cDataCidCback_t)(uint16_t handle, uint16_t cid, uint16_t len, uint8_t *pPacket);
/* Main control block of the L2C subsystem */
typedef struct
{
l2cDataCback_t attDataCback; /* Data callback for ATT */
l2cDataCback_t smpDataCback; /* Data callback for SMP */
l2cDataCback_t l2cSignalingCback; /* Data callback for L2CAP signaling */
l2cCtrlCback_t attCtrlCback; /* Control callback for ATT */
l2cCtrlCback_t smpCtrlCback; /* Control callback for SMP */
l2cCtrlCback_t l2cCocCtrlCback; /* Control callback for L2CAP connection oriented channels */
l2cDataCback_t masterRxSignalingPkt; /* Master signaling packet processing function */
l2cDataCback_t slaveRxSignalingPkt; /* Slave signaling packet processing function */
l2cDataCidCback_t l2cDataCidCback; /* Data callback for L2CAP on other CIDs */
uint8_t identifier; /* Signaling request identifier */
} l2cCb_t;
/**************************************************************************************************
Function Prototypes
**************************************************************************************************/
void l2cSendCmdReject(uint16_t handle, uint8_t identifier, uint16_t reason);
void l2cRxSignalingPkt(uint16_t handle, uint16_t len, uint8_t *pPacket);
void *l2cMsgAlloc(uint16_t len);
/* Control block */
extern l2cCb_t l2cCb;
#ifdef __cplusplus
};
#endif
#endif /* L2C_MAIN_H */
@@ -0,0 +1,147 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief L2CAP module for master operations.
*
* Copyright (c) 2009-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed 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.
*/
/*************************************************************************************************/
#include "wsf_types.h"
#include "wsf_assert.h"
#include "wsf_trace.h"
#include "wsf_msg.h"
#include "util/bstream.h"
#include "l2c_api.h"
#include "l2c_main.h"
#include "dm_api.h"
/**************************************************************************************************
Macros
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Master processing of received L2CAP signaling packets.
*
* \param handle The connection handle.
* \param l2cLen The length of the L2CAP payload data in pPacket.
* \param pPacket A buffer containing the packet.
*
* \return None.
*/
/*************************************************************************************************/
static void l2cMasterRxSignalingPkt(uint16_t handle, uint16_t l2cLen, uint8_t *pPacket)
{
uint8_t code;
uint8_t id;
uint16_t len;
hciConnSpec_t connSpec;
/* parse code, len, and identifier */
pPacket += L2C_PAYLOAD_START;
BSTREAM_TO_UINT8(code, pPacket);
BSTREAM_TO_UINT8(id, pPacket);
BSTREAM_TO_UINT16(len, pPacket);
/* verify signaling length vs. l2c length
* verify this is a conn param update rsp
* verify parameter length
*/
if ((l2cLen != (len + L2C_SIG_HDR_LEN)) ||
(code != L2C_SIG_CONN_UPDATE_REQ) ||
(len != L2C_SIG_CONN_UPDATE_REQ_LEN))
{
L2C_TRACE_WARN3("invalid msg code:%d len:%d l2cLen:%d", code, len, l2cLen);
/* reject all unknown or invalid commands except command reject. */
if (code != L2C_SIG_CMD_REJ)
{
l2cSendCmdReject(handle, id, L2C_REJ_NOT_UNDERSTOOD);
}
return;
}
/* parse parameters */
BSTREAM_TO_UINT16(connSpec.connIntervalMin, pPacket);
BSTREAM_TO_UINT16(connSpec.connIntervalMax, pPacket);
BSTREAM_TO_UINT16(connSpec.connLatency, pPacket);
BSTREAM_TO_UINT16(connSpec.supTimeout, pPacket);
connSpec.minCeLen = 0;
connSpec.maxCeLen = 0;
/* check parameter range */
if ((connSpec.connIntervalMin < HCI_CONN_INTERVAL_MIN) ||
(connSpec.connIntervalMin > HCI_CONN_INTERVAL_MAX) ||
(connSpec.connIntervalMin > connSpec.connIntervalMax) ||
(connSpec.connIntervalMax < HCI_CONN_INTERVAL_MIN) ||
(connSpec.connIntervalMax > HCI_CONN_INTERVAL_MAX) ||
(connSpec.connLatency > HCI_CONN_LATENCY_MAX) ||
(connSpec.supTimeout < HCI_SUP_TIMEOUT_MIN) ||
(connSpec.supTimeout > HCI_SUP_TIMEOUT_MAX))
{
L2cDmConnUpdateRsp(id, handle, L2C_CONN_PARAM_REJECTED);
return;
}
DmL2cConnUpdateInd(id, handle, &connSpec);
}
/*************************************************************************************************/
/*!
* \brief Initialize L2C for operation as a Bluetooth LE master.
*
* \return None.
*/
/*************************************************************************************************/
void L2cMasterInit(void)
{
l2cCb.masterRxSignalingPkt = l2cMasterRxSignalingPkt;
}
/*************************************************************************************************/
/*!
* \brief This function is called by DM to send an L2CAP connection update response.
*
* \param identifier Identifier value previously passed from L2C to DM.
* \param handle The connection handle.
* \param result Connection update response result.
*
* \return None.
*/
/*************************************************************************************************/
void L2cDmConnUpdateRsp(uint8_t identifier, uint16_t handle, uint16_t result)
{
uint8_t *pPacket;
uint8_t *p;
/* allocate msg buffer */
if ((pPacket = l2cMsgAlloc(L2C_SIG_PKT_BASE_LEN + L2C_SIG_CONN_UPDATE_RSP_LEN)) != NULL)
{
/* build message */
p = pPacket + L2C_PAYLOAD_START;
UINT8_TO_BSTREAM(p, L2C_SIG_CONN_UPDATE_RSP); /* command code */
UINT8_TO_BSTREAM(p, identifier); /* identifier */
UINT16_TO_BSTREAM(p, L2C_SIG_CONN_UPDATE_RSP_LEN); /* parameter length */
UINT16_TO_BSTREAM(p, result); /* result */
/* send packet */
L2cDataReq(L2C_CID_LE_SIGNALING, handle, (L2C_SIG_HDR_LEN + L2C_SIG_CONN_UPDATE_RSP_LEN), pPacket);
}
}
@@ -0,0 +1,311 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief L2CAP module for slave operations.
*
* Copyright (c) 2009-2018 Arm Ltd.
*
* Copyright (c) 2019 Packetcraft, Inc.
*
* Licensed 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.
*/
/*************************************************************************************************/
#include <string.h>
#include "wsf_types.h"
#include "wsf_assert.h"
#include "wsf_trace.h"
#include "wsf_timer.h"
#include "wsf_msg.h"
#include "wsf_os.h"
#include "util/bstream.h"
#include "l2c_api.h"
#include "l2c_main.h"
#include "dm_api.h"
/**************************************************************************************************
Macros
**************************************************************************************************/
/* Signaling request timeout in seconds */
#define L2C_SIG_REQ_TIMEOUT 30
/**************************************************************************************************
Data Types
**************************************************************************************************/
/* Slave control block */
typedef struct
{
wsfTimer_t reqTimer; /* Signaling request timeout timer */
wsfHandlerId_t handlerId; /* ID for this event handler */
uint8_t lastCode[DM_CONN_MAX]; /* last code sent on each handle */
uint8_t signId[DM_CONN_MAX]; /* expected signaling identifier */
} l2cSlaveCb_t;
/**************************************************************************************************
Local Variables
**************************************************************************************************/
static l2cSlaveCb_t l2cSlaveCb;
/*************************************************************************************************/
/*!
* \brief Handle slave signaling request timeout.
*
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
static void l2cSlaveReqTimeout(wsfMsgHdr_t *pMsg)
{
L2C_TRACE_WARN0("conn update req timeout");
/* Notify DM that connection update has failed (handle is stored in param) */
DmL2cConnUpdateCnf(pMsg->param, L2C_CONN_PARAM_REJECTED);
}
/*************************************************************************************************/
/*!
* \brief Slave processing of received L2CAP signaling packets.
*
* \param handle The connection handle.
* \param l2cLen The length of the L2CAP payload data in pPacket.
* \param pPacket A buffer containing the packet.
*
* \return None.
*/
/*************************************************************************************************/
static void l2cSlaveRxSignalingPkt(uint16_t handle, uint16_t l2cLen, uint8_t *pPacket)
{
uint8_t code;
uint8_t id;
uint16_t len;
uint16_t result;
/* parse code, len, and identifier */
pPacket += L2C_PAYLOAD_START;
BSTREAM_TO_UINT8(code, pPacket);
BSTREAM_TO_UINT8(id, pPacket);
BSTREAM_TO_UINT16(len, pPacket);
/* verify signal identifier is valid */
if (id == L2C_SIGNAL_ID_INVALID)
{
/* not expected, ignore */
return;
}
/* verify signal identifier is expected
* verify signaling length vs. l2c length
* verify this is a conn param update rsp or command reject
* verify parameter length
*/
if ((id == l2cSlaveCb.signId[handle]) &&
(l2cLen == (len + L2C_SIG_HDR_LEN)) &&
(((code == L2C_SIG_CONN_UPDATE_RSP) && (len == L2C_SIG_CONN_UPDATE_RSP_LEN)) ||
(code == L2C_SIG_CMD_REJ)))
{
/* get last sent code */
uint8_t lastCode = l2cSlaveCb.lastCode[handle];
/* clear pending signal id */
l2cSlaveCb.signId[handle] = L2C_SIGNAL_ID_INVALID;
/* parse result parameter */
BSTREAM_TO_UINT16(result, pPacket);
/* stop req timer */
WsfTimerStop(&l2cSlaveCb.reqTimer);
if (lastCode == L2C_SIG_CONN_UPDATE_REQ)
{
if (code == L2C_SIG_CMD_REJ)
{
/* got command reject */
result = L2C_CONN_PARAM_REJECTED;
}
/* send to DM */
DmL2cConnUpdateCnf(handle, result);
}
else
{
/* send to DM */
DmL2cCmdRejInd(handle, result);
}
}
else
{
L2C_TRACE_WARN3("invalid msg code:%d len:%d l2cLen:%d", code, len, l2cLen);
/* reject all unknown, invalid or unidentified commands except command reject. */
if (code != L2C_SIG_CMD_REJ)
{
l2cSendCmdReject(handle, id, L2C_REJ_NOT_UNDERSTOOD);
}
return;
}
}
/*************************************************************************************************/
/*!
* \brief Initialize L2C for operation as a Bluetooth LE slave.
*
* \return None.
*/
/*************************************************************************************************/
void L2cSlaveInit(void)
{
l2cCb.slaveRxSignalingPkt = l2cSlaveRxSignalingPkt;
for (uint8_t i = 0; i < DM_CONN_MAX; i++)
{
l2cSlaveCb.signId[i] = L2C_SIGNAL_ID_INVALID;
}
}
/*************************************************************************************************/
/*!
* \brief Build and send a signaling packet.
*
* \param handle The connection handle.
* \param code Type of command.
* \param len Length of \ref pParam.
* \param pParam parameters of command to send.
*
* \return None.
*/
/*************************************************************************************************/
void L2cDmSigReq(uint16_t handle, uint8_t code, uint16_t len, uint8_t *pParam)
{
uint8_t *pPacket;
uint8_t *p;
WSF_ASSERT(handle < DM_CONN_MAX);
/* record code */
l2cSlaveCb.lastCode[handle] = code;
/* Start signaling request timer and store handle */
WsfTimerStartSec(&l2cSlaveCb.reqTimer, L2C_SIG_REQ_TIMEOUT);
l2cSlaveCb.reqTimer.msg.param = handle;
/* allocate msg buffer */
if ((pPacket = l2cMsgAlloc(L2C_SIG_PKT_BASE_LEN + len)) != NULL)
{
/* build message */
p = pPacket + L2C_PAYLOAD_START;
UINT8_TO_BSTREAM(p, code); /* command code */
l2cSlaveCb.signId[handle] = l2cCb.identifier;
UINT8_TO_BSTREAM(p, l2cCb.identifier); /* identifier */
l2cCb.identifier = L2C_NEXT_ID(l2cCb.identifier);
UINT16_TO_BSTREAM(p, len); /* parameter length */
memcpy(p, pParam, len); /* parameters */
/* send packet */
L2cDataReq(L2C_CID_LE_SIGNALING, handle, (L2C_SIG_HDR_LEN + len), pPacket);
}
}
/*************************************************************************************************/
/*!
* \brief This function is called by DM to send an L2CAP connection update request.
*
* \param handle The connection handle.
* \param pConnSpec Pointer to the connection specification structure.
*
* \return None.
*/
/*************************************************************************************************/
void L2cDmConnUpdateReq(uint16_t handle, hciConnSpec_t *pConnSpec)
{
uint8_t *pPacket;
uint8_t *p;
/* record code */
l2cSlaveCb.lastCode[handle] = L2C_SIG_CONN_UPDATE_REQ;
/* Start signaling request timer and store handle */
WsfTimerStartSec(&l2cSlaveCb.reqTimer, L2C_SIG_REQ_TIMEOUT);
l2cSlaveCb.reqTimer.msg.param = handle;
/* allocate msg buffer */
if ((pPacket = l2cMsgAlloc(L2C_SIG_PKT_BASE_LEN + L2C_SIG_CONN_UPDATE_REQ_LEN)) != NULL)
{
/* build message */
p = pPacket + L2C_PAYLOAD_START;
UINT8_TO_BSTREAM(p, L2C_SIG_CONN_UPDATE_REQ); /* command code */
UINT8_TO_BSTREAM(p, l2cCb.identifier); /* identifier */
l2cSlaveCb.signId[handle] = l2cCb.identifier;
l2cCb.identifier = L2C_NEXT_ID(l2cCb.identifier);
UINT16_TO_BSTREAM(p, L2C_SIG_CONN_UPDATE_REQ_LEN); /* parameter length */
UINT16_TO_BSTREAM(p, pConnSpec->connIntervalMin); /* interval min */
UINT16_TO_BSTREAM(p, pConnSpec->connIntervalMax); /* interval max */
UINT16_TO_BSTREAM(p, pConnSpec->connLatency); /* slave latency */
UINT16_TO_BSTREAM(p, pConnSpec->supTimeout); /* timeout multiplier */
/* send packet */
L2cDataReq(L2C_CID_LE_SIGNALING, handle, (L2C_SIG_HDR_LEN + L2C_SIG_CONN_UPDATE_REQ_LEN), pPacket);
}
}
/*************************************************************************************************/
/*!
* \brief Event handler initialization function for L2C when operating as a slave.
*
* \param handlerId ID for this event handler.
*
* \return None.
*/
/*************************************************************************************************/
void L2cSlaveHandlerInit(wsfHandlerId_t handlerId)
{
l2cSlaveCb.reqTimer.msg.event = L2C_MSG_REQ_TIMEOUT;
l2cSlaveCb.reqTimer.handlerId = handlerId;
l2cSlaveCb.handlerId = handlerId;
}
/*************************************************************************************************/
/*!
* \brief The WSF event handler for L2C when operating as a slave.
*
* \param event Event mask.
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
void L2cSlaveHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
{
/* Handle message */
if (pMsg != NULL)
{
WSF_ASSERT(pMsg->event > 0 && pMsg->event <= L2C_MSG_TYPE_MAX);
/* handle slave signaling request timeout */
if (pMsg->event == L2C_MSG_REQ_TIMEOUT)
{
l2cSlaveReqTimeout(pMsg);
}
}
/* Handle events */
else if (event)
{
}
}