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
@@ -0,0 +1,163 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Wireless Data Exchange profile application interface.
*
* Copyright (c) 2013-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 WDXS_API_H
#define WDXS_API_H
#include "att_api.h"
#include "wdx_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! \addtogroup WIRELESS_DATA_EXCHANGE_PROFILE
* \{ */
/**************************************************************************************************
Macros
**************************************************************************************************/
/*! \brief Size of RAM Media used by the application */
#define WDXS_APP_RAM_MEDIA_SIZE 256
/*! \brief Device Model Name */
#ifndef WDXS_DEVICE_MODEL
#define WDXS_DEVICE_MODEL "WDXS App"
#endif
/*************************************************************************************************/
/*!
* \brief Called at startup to configure WDXS authentication.
*
* \param reqLevel Level of authentication that is required for a client to use WDXS
* \param pKey Authentication key (set to NULL if no authentication is required)
*
* \return None.
*/
/*************************************************************************************************/
void WdxsAuthenticationCfg(bool_t reqLevel, uint8_t *pKey);
/*************************************************************************************************/
/*!
* \brief Handle WSF events for WDXS.
*
* \param event event
* \param pMsg message assiciated with event
*
* \return None.
*/
/*************************************************************************************************/
void WdxsHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
/*************************************************************************************************/
/*!
* \brief WSF Task Initialization for WDXS task.
*
* \param handlerId ID of the WDXS task
*
* \return None.
*/
/*************************************************************************************************/
void WdxsHandlerInit(wsfHandlerId_t handlerId);
/*************************************************************************************************/
/*!
* \brief Called by application to notify the WDXS of ATT Events.
*
* \param pEvt Pointer to the ATT Event
*
* \return TRUE if the application should ignore the event, else FALSE.
*/
/*************************************************************************************************/
uint8_t WdxsAttCback(attEvt_t *pEvt);
/*************************************************************************************************/
/*!
* \brief Called by application to notify the WDXS of DM Events.
*
* \param pEvt Pointer to the DM Event
*
* \return None.
*/
/*************************************************************************************************/
void WdxsProcDmMsg(dmEvt_t *pEvt);
/*************************************************************************************************/
/*!
* \brief Set the CCCD index used by the application for WDXS service characteristics.
*
* \param dcCccIdx Device Control CCCD index.
* \param auCccIdx Authentication CCCD index.
* \param ftcCccIdx File Transfer Control CCCD index.
* \param ftdCccIdx File Transfer Data CCCD index.
*
* \return None.
*/
/*************************************************************************************************/
void WdxsSetCccIdx(uint8_t dcCccIdx, uint8_t auCccIdx, uint8_t ftcCccIdx, uint8_t ftdCccIdx);
/*************************************************************************************************/
/*!
* \brief Registers the platform dependent Flash Media with the Embedded File System (EFS)
*
* \return None.
*/
/*************************************************************************************************/
void WdxsFlashMediaInit(void);
/*************************************************************************************************/
/*!
* \brief Registers the platform dependent OTA Media with the Embedded File System (EFS)
*
* \return None.
*/
/*************************************************************************************************/
void WdxsOtaMediaInit(void);
/*************************************************************************************************/
/*!
* \brief Resets the system.
*
* \return None.
*/
/*************************************************************************************************/
void WdxsResetSystem(void);
/*************************************************************************************************/
/*!
* \brief Initialize WDXS Device Configuration PHY.
*
* \return None.
*/
/*************************************************************************************************/
void WdxsPhyInit(void);
/*! \} */ /* WIRELESS_DATA_EXCHANGE_PROFILE */
#ifdef __cplusplus
}
#endif
#endif /* WDXS_API_H */
@@ -0,0 +1,218 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Wireless Data Exchange profile implementation - Authentication.
*
* Copyright (c) 2013-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 "util/bstream.h"
#include "wsf_trace.h"
#include "wsf_assert.h"
#include "wsf_efs.h"
#include "wsf_os.h"
#include "sec_api.h"
#include "svc_wdxs.h"
#include "wdxs_api.h"
#include "wdxs_main.h"
#include "dm_api.h"
#include "att_api.h"
#include "app_api.h"
#if WDXS_AU_ENABLED == TRUE
/* WDXS Authentication Control Block */
wdxsAuCb_t wdxsAuCb;
/*************************************************************************************************/
/*!
* \brief Transmit to authentication characteristic.
*
* \return ATT status.
*/
/*************************************************************************************************/
void wdxsAuSend(dmConnId_t connId)
{
APP_TRACE_INFO0("WDXS: AuSend");
/* if notification enabled */
if (AttsCccEnabled(connId, wdxsCb.auCccIdx))
{
/* send notification */
AttsHandleValueNtf(connId, WDXS_AU_HDL, wdxsAuCb.auMsgLen, wdxsAuCb.auMsgBuf);
wdxsCb.txReadyMask &= ~(WDXS_TX_MASK_AU_BIT | WDXS_TX_MASK_READY_BIT);
wdxsAuCb.authState = WDXS_AU_STATE_WAIT_REPLY;
}
}
/*************************************************************************************************/
/*!
* \brief Called by WDXS event handler when the WSF Sec operation is complete.
*
* \return None.
*/
/*************************************************************************************************/
void WdxsAuSecComplete(secAes_t *pAes)
{
uint8_t *p = wdxsAuCb.auMsgBuf;
/* Record the hash */
memcpy(wdxsAuCb.auHash, pAes->pCiphertext, WDX_AU_HASH_LEN);
/* Build challenge message */
UINT8_TO_BSTREAM(p, WDX_AU_OP_CHALLENGE);
memcpy(p, wdxsAuCb.auRand, WDX_AU_RAND_LEN);
wdxsAuCb.auMsgLen = WDX_AU_RAND_LEN + WDX_AU_HDR_LEN;
/* Update State */
wdxsAuCb.authState = WDXS_AU_STATE_WAIT_REPLY;
/* Indicate TX Ready */
wdxsCb.txReadyMask &= ~(WDXS_TX_MASK_AU_BIT | WDXS_TX_MASK_READY_BIT);
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
}
/*************************************************************************************************/
/*!
* \brief Process a request to start authentication.
*
* \return None.
*/
/*************************************************************************************************/
static uint8_t wdxsAuProcStart(dmConnId_t connId, uint8_t len, uint8_t *pValue)
{
/* Verify parameter length */
if (len != WDX_AU_PARAM_LEN_START)
{
return ATT_ERR_LENGTH;
}
/* Parse parameters */
BSTREAM_TO_UINT8(wdxsAuCb.authLevel, pValue);
BSTREAM_TO_UINT8(wdxsAuCb.authMode, pValue);
/* Generate random number */
SecRand(wdxsAuCb.auRand, WDX_AU_RAND_LEN);
/* Encrypt the random number to create the hash */
SecAes(wdxsAuCb.sessionKey, wdxsAuCb.auRand, wdxsCb.handlerId, connId, WDXS_EVT_AU_SEC_COMPLETE);
/* Update State */
wdxsAuCb.authState = WDXS_AU_STATE_WAIT_SEC;
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Process a reply to the authentication challenge.
*
* \return None.
*/
/*************************************************************************************************/
static uint8_t wdxsAuProcReply(uint8_t len, uint8_t *pValue)
{
/* Verify parameter length */
if (len != WDX_AU_PARAM_LEN_REPLY)
{
return ATT_ERR_LENGTH;
}
if (wdxsAuCb.authState == WDXS_AU_STATE_WAIT_REPLY)
{
/* Verify [0-7] bytes of cipher text against what was sent by client */
if (memcmp(wdxsAuCb.auHash, pValue, WDX_AU_HASH_LEN) == 0)
{
/* Successful challenge */
wdxsAuCb.authState = WDXS_AU_STATE_AUTHORIZED;
return ATT_SUCCESS;
}
return WDX_AU_ST_AUTH_FAILED;
}
return WDX_AU_ST_INVALID_STATE;
}
/*************************************************************************************************/
/*!
* \brief Process a write to the authentication characteristic.
*
* \return ATT status.
*/
/*************************************************************************************************/
uint8_t wdxsAuWrite(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
uint8_t op;
uint8_t status;
/* Sanity check message length */
if (len < WDX_AU_HDR_LEN)
{
return ATT_ERR_LENGTH;
}
/* Get Operation ID */
BSTREAM_TO_UINT8(op, pValue);
len -= WDX_AU_HDR_LEN;
APP_TRACE_INFO1("WDXS: AuWrite: op=%d", op);
switch (op)
{
case WDX_AU_OP_START:
status = wdxsAuProcStart(connId, (uint8_t) len, pValue);
break;
case WDX_AU_OP_REPLY:
status = wdxsAuProcReply((uint8_t) len, pValue);
break;
default:
status = ATT_ERR_RANGE;
break;
}
return status;
}
/*************************************************************************************************/
/*!
* \brief Called at startup to configure WDXS authentication.
*
* \param reqLevel Level of authentication that is required for a client to use WDXS
* \param key Authentication key (set to NULL if no authentication is required)
*
* \return None.
*/
/*************************************************************************************************/
void WdxsAuthenticationCfg(bool_t reqLevel, uint8_t *pKey)
{
wdxsAuCb.reqAuthLevel = reqLevel;
if (pKey)
{
memcpy(wdxsAuCb.sessionKey, pKey, WDX_AU_KEY_LEN);
}
}
#endif /* WDXS_AU_ENABLED */
@@ -0,0 +1,608 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Wireless Data Exchange profile implementation - Device Configuration.
*
* Copyright (c) 2013-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 "util/wstr.h"
#include "wsf_trace.h"
#include "wsf_assert.h"
#include "wsf_efs.h"
#include "util/bstream.h"
#include "svc_wdxs.h"
#include "wdxs_api.h"
#include "wdxs_main.h"
#include "dm_api.h"
#include "app_api.h"
#include "app_hw.h"
#if WDXS_DC_ENABLED == TRUE
/* WDXS Device Configuration Control Block */
wdxsDcCb_t wdxsDcCb;
/*************************************************************************************************/
/*!
* \brief Send device configuration notification
*
* \return None.
*/
/*************************************************************************************************/
void wdxsDcSend(dmConnId_t connId)
{
APP_TRACE_INFO0("WDXS: DcSend");
/* if notification enabled */
if (AttsCccEnabled(connId, wdxsCb.dcCccIdx))
{
/* send notification */
AttsHandleValueNtf(connId, WDXS_DC_HDL, wdxsDcCb.dcMsgLen, wdxsDcCb.dcMsgBuf);
wdxsCb.txReadyMask &= ~(WDXS_TX_MASK_DC_BIT | WDXS_TX_MASK_READY_BIT);
}
}
/*************************************************************************************************/
/*!
* \brief Send update message for connection parameters.
*
* \return ATT status.
*/
/*************************************************************************************************/
uint8_t wdxsDcUpdateConnParam(dmConnId_t connId, uint8_t status)
{
uint8_t *p;
/* if update already waiting to be sent */
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
{
return ATT_ERR_IN_PROGRESS;
}
/* build update to global buffer */
p = wdxsDcCb.dcMsgBuf;
UINT8_TO_BSTREAM(p, WDX_DC_OP_UPDATE);
UINT8_TO_BSTREAM(p, WDX_DC_ID_CONN_PARAM);
UINT8_TO_BSTREAM(p, status);
UINT16_TO_BSTREAM(p, wdxsCb.connInterval);
UINT16_TO_BSTREAM(p, wdxsCb.connLatency);
UINT16_TO_BSTREAM(p, wdxsCb.supTimeout);
wdxsDcCb.dcMsgLen = WDX_DC_LEN_CONN_PARAM + WDX_DC_HDR_LEN;
/* Indicate TX Ready */
wdxsCb.txReadyMask |= WDXS_TX_MASK_DC_BIT;
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Send update message for PHY.
*
* \return ATT status.
*/
/*************************************************************************************************/
uint8_t wdxsDcUpdatePhy(dmConnId_t connId, uint8_t status)
{
uint8_t *p;
/* if update already waiting to be sent */
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
{
return ATT_ERR_IN_PROGRESS;
}
/* build update to global buffer */
p = wdxsDcCb.dcMsgBuf;
UINT8_TO_BSTREAM(p, WDX_DC_OP_UPDATE);
UINT8_TO_BSTREAM(p, WDX_DC_ID_PHY);
UINT8_TO_BSTREAM(p, status);
UINT8_TO_BSTREAM(p, wdxsCb.txPhy);
UINT8_TO_BSTREAM(p, wdxsCb.rxPhy);
wdxsDcCb.dcMsgLen = WDX_DC_LEN_PHY + WDX_DC_HDR_LEN;
/* Indicate TX Ready */
wdxsCb.txReadyMask |= WDXS_TX_MASK_DC_BIT;
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Process Update Diagnostics Complete.
*
* \return ATT status.
*/
/*************************************************************************************************/
uint8_t wdxsDcUpdateDiagnosticsComplete(dmConnId_t connId)
{
uint8_t *p;
/* if update already waiting to be sent */
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
{
return ATT_ERR_IN_PROGRESS;
}
/* build update to global buffer */
p = wdxsDcCb.dcMsgBuf;
UINT8_TO_BSTREAM(p, WDX_DC_OP_UPDATE);
UINT8_TO_BSTREAM(p, WDX_DC_ID_DIAGNOSTICS_COMPLETE);
wdxsDcCb.dcMsgLen = WDX_DC_LEN_DIAG_COMPLETE + WDX_DC_HDR_LEN;
/* Indicate TX Ready */
wdxsCb.txReadyMask |= WDXS_TX_MASK_DC_BIT;
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Process set connection paramter request.
*
* \return ATT status.
*/
/*************************************************************************************************/
static uint8_t wdxsDcSetConnParamReq(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
hciConnSpec_t connSpec;
/* verify parameter length */
if (len != WDX_DC_LEN_CONN_PARAM_REQ)
{
return ATT_ERR_LENGTH;
}
/* parse parameters */
BSTREAM_TO_UINT16(connSpec.connIntervalMin, pValue);
BSTREAM_TO_UINT16(connSpec.connIntervalMax, pValue);
BSTREAM_TO_UINT16(connSpec.connLatency, pValue);
BSTREAM_TO_UINT16(connSpec.supTimeout, pValue);
/* request update to connection parameters */
DmConnUpdate(connId, &connSpec);
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Process set diagnostics.
*
* \return ATT status.
*/
/*************************************************************************************************/
static uint8_t wdxsDcSetEnterDiadnostics(dmConnId_t connId)
{
return wdxsDcUpdateDiagnosticsComplete(connId);
}
/*************************************************************************************************/
/*!
* \brief Process a Set Disconnect request.
*
* \return ATT status.
*/
/*************************************************************************************************/
static uint8_t wdxsDcSetDisconnectReq(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
AppConnClose(connId);
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Process a Set Security request.
*
* \return ATT status.
*/
/*************************************************************************************************/
static uint8_t wdxsDcSetSecurityReq(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
uint8_t secLevel;
/* verify parameter length */
if (len != WDX_DC_LEN_SEC_LEVEL)
{
return ATT_ERR_LENGTH;
}
/* parse parameters */
BSTREAM_TO_UINT8(secLevel, pValue);
/* Enable Security */
if (DmConnSecLevel(connId) != DM_SEC_LEVEL_NONE)
{
DmSecSlaveReq(connId, secLevel);
}
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Process a Set Service Changed request.
*
* \return ATT status.
*/
/*************************************************************************************************/
static uint8_t wdxsDcSetServiceChanged(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
/* TBD */
return ATT_ERR_NOT_SUP;
}
/*************************************************************************************************/
/*!
* \brief Process a Set Delete Bonds request.
*
* \return ATT status.
*/
/*************************************************************************************************/
static uint8_t wdxsDcSetDeleteBonds(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
/* TBD */
return ATT_ERR_NOT_SUP;
}
/*************************************************************************************************/
/*!
* \brief Process a Set Disconnect And Reset request.
*
* \return ATT status.
*/
/*************************************************************************************************/
static uint8_t wdxsDcSetDisconnectAndReset(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
wdxsDcCb.doReset = TRUE;
AppConnClose(connId);
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Process a Get Connection Parameter request.
*
* \return ATT status.
*/
/*************************************************************************************************/
static uint8_t wdxsDcGetConnParam(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
return wdxsDcUpdateConnParam(connId, HCI_SUCCESS);
}
/*************************************************************************************************/
/*!
* \brief Process a Get Security Level request.
*
* \return ATT status.
*/
/*************************************************************************************************/
static uint8_t wdxsDcGetSecurityLevel(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
uint8_t *p;
/* if update already waiting to be sent */
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
{
return ATT_ERR_IN_PROGRESS;
}
/* build update to global buffer */
p = wdxsDcCb.dcMsgBuf;
UINT8_TO_BSTREAM(p, WDX_DC_OP_UPDATE);
UINT8_TO_BSTREAM(p, WDX_DC_ID_CONN_SEC_LEVEL);
UINT8_TO_BSTREAM(p, DmConnSecLevel(connId));
wdxsDcCb.dcMsgLen = WDX_DC_LEN_SEC_LEVEL + WDX_DC_HDR_LEN;
/* Indicate TX Ready */
wdxsCb.txReadyMask |= WDXS_TX_MASK_DC_BIT;
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Process a Get Current ATT MTU request.
*
* \return ATT status.
*/
/*************************************************************************************************/
static uint8_t wdxsDcGetAttMtu(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
uint8_t *p;
/* if update already waiting to be sent */
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
{
return ATT_ERR_IN_PROGRESS;
}
/* build update to global buffer */
p = wdxsDcCb.dcMsgBuf;
UINT8_TO_BSTREAM(p, WDX_DC_OP_UPDATE);
UINT8_TO_BSTREAM(p, WDX_DC_ID_ATT_MTU);
UINT16_TO_BSTREAM(p, AttGetMtu(connId));
wdxsDcCb.dcMsgLen = WDX_DC_LEN_ATT_MTU + WDX_DC_HDR_LEN;
/* Indicate TX Ready */
wdxsCb.txReadyMask |= WDXS_TX_MASK_DC_BIT;
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Process a Get Battery Level request.
*
* \return ATT status.
*/
/*************************************************************************************************/
static uint8_t wdxsDcGetBatteryLevel(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
uint8_t *p;
/* if update already waiting to be sent */
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
{
return ATT_ERR_IN_PROGRESS;
}
/* build update to global buffer */
p = wdxsDcCb.dcMsgBuf;
UINT8_TO_BSTREAM(p, WDX_DC_OP_UPDATE);
UINT8_TO_BSTREAM(p, WDX_DC_ID_BATTERY_LEVEL);
/* add battery level */
AppHwBattRead(p);
wdxsDcCb.dcMsgLen = WDX_DC_LEN_BATTERY_LEVEL + WDX_DC_HDR_LEN;
/* Indicate TX Ready */
wdxsCb.txReadyMask |= WDXS_TX_MASK_DC_BIT;
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Process a Get Device Model Number request.
*
* \return ATT status.
*/
/*************************************************************************************************/
static uint8_t wdxsDcGetDeviceModel(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
uint8_t *p;
/* TODO: Add Device Model */
char *pModelTxt = WDXS_DEVICE_MODEL;
/* if update already waiting to be sent */
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
{
return ATT_ERR_IN_PROGRESS;
}
/* build update to global buffer */
p = wdxsDcCb.dcMsgBuf;
UINT8_TO_BSTREAM(p, WDX_DC_OP_UPDATE);
UINT8_TO_BSTREAM(p, WDX_DC_ID_MODEL_NUMBER);
/* Potential buffer overrun is intentional to zero out fixed length field */
/* coverity[overrun-buffer-arg] */
WstrnCpy((char *)p, pModelTxt, WDX_DC_LEN_DEVICE_MODEL);
wdxsDcCb.dcMsgLen = WDX_DC_LEN_DEVICE_MODEL + WDX_DC_HDR_LEN;
/* Indicate TX Ready */
wdxsCb.txReadyMask |= WDXS_TX_MASK_DC_BIT;
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Process a Get Firmware Revision request.
*
* \return ATT status.
*/
/*************************************************************************************************/
static uint8_t wdxsDcGetFirmwareRev(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
uint8_t *p;
/* TODO: Add Firmware Revision */
char *pFirmwareRev = "1.0";
/* if update already waiting to be sent */
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
{
return ATT_ERR_IN_PROGRESS;
}
/* build update to global buffer */
p = wdxsDcCb.dcMsgBuf;
UINT8_TO_BSTREAM(p, WDX_DC_OP_UPDATE);
UINT8_TO_BSTREAM(p, WDX_DC_ID_FIRMWARE_REV);
/* Potential buffer overrun is intentional to zero out fixed length field */
/* coverity[overrun-buffer-arg] */
WstrnCpy((char *)p, pFirmwareRev, WDX_DC_LEN_FIRMWARE_REV);
wdxsDcCb.dcMsgLen = WDX_DC_LEN_FIRMWARE_REV + WDX_DC_HDR_LEN;
/* Indicate TX Ready */
wdxsCb.txReadyMask |= WDXS_TX_MASK_DC_BIT;
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Process a write to the device configuration characteristic.
*
* \return ATT status.
*/
/*************************************************************************************************/
uint8_t wdxsDcWrite(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
uint8_t op;
uint8_t id;
uint8_t status = ATT_SUCCESS;
/* sanity check on message length */
if (len < WDX_DC_HDR_LEN)
{
return ATT_ERR_LENGTH;
}
/* verify notifications are enabled */
if (!AttsCccEnabled(connId, wdxsCb.dcCccIdx))
{
return ATT_ERR_CCCD;
}
/* get operation and parameter ID */
BSTREAM_TO_UINT8(op, pValue);
BSTREAM_TO_UINT8(id, pValue);
/* skip over header (note pValue was incremented above) */
len -= WDX_DC_HDR_LEN;
/* set operation */
if (op == WDX_DC_OP_SET)
{
switch (id)
{
case WDX_DC_ID_CONN_UPDATE_REQ:
status = wdxsDcSetConnParamReq(connId, len, pValue);
break;
case WDX_DC_ID_DISCONNECT_REQ:
status = wdxsDcSetDisconnectReq(connId, len, pValue);
break;
case WDX_DC_ID_SECURITY_REQ:
status = wdxsDcSetSecurityReq(connId, len, pValue);
break;
case WDX_DC_ID_SERVICE_CHANGED:
status = wdxsDcSetServiceChanged(connId, len, pValue);
break;
case WDX_DC_ID_DELETE_BONDS:
status = wdxsDcSetDeleteBonds(connId, len, pValue);
break;
case WDX_DC_ID_ENTER_DIAGNOSTICS:
status = wdxsDcSetEnterDiadnostics(connId);
break;
case WDX_DC_ID_DISCONNECT_AND_RESET:
status = wdxsDcSetDisconnectAndReset(connId, len, pValue);
break;
case WDX_DC_ID_PHY_UPDATE_REQ:
/* if device configuration phy callback registered */
if (wdxsDcCb.phyWriteCback != NULL)
{
status = (*wdxsDcCb.phyWriteCback)(connId, op, id, len, pValue);
break;
}
/* else fall through */
default:
status = ATT_ERR_RANGE;
break;
}
}
/* get operation */
else if (op == WDX_DC_OP_GET)
{
switch (id)
{
case WDX_DC_ID_CONN_PARAM:
status = wdxsDcGetConnParam(connId, len, pValue);
break;
case WDX_DC_ID_CONN_SEC_LEVEL:
status = wdxsDcGetSecurityLevel(connId, len, pValue);
break;
case WDX_DC_ID_ATT_MTU:
status = wdxsDcGetAttMtu(connId, len, pValue);
break;
case WDX_DC_ID_BATTERY_LEVEL:
status = wdxsDcGetBatteryLevel(connId, len, pValue);
break;
case WDX_DC_ID_MODEL_NUMBER:
status = wdxsDcGetDeviceModel(connId, len, pValue);
break;
case WDX_DC_ID_FIRMWARE_REV:
status = wdxsDcGetFirmwareRev(connId, len, pValue);
break;
case WDX_DC_ID_PHY:
/* if device configuration phy callback registered */
if (wdxsDcCb.phyWriteCback != NULL)
{
status = (*wdxsDcCb.phyWriteCback)(connId, op, id, len, pValue);
break;
}
/* else fall through */
default:
status = ATT_ERR_RANGE;
break;
}
}
else
{
status = ATT_ERR_RANGE;
}
return status;
}
/*************************************************************************************************/
/*!
* \brief Register a PHY write callback for the device configuration characteristic.
*
* \param cback PHY callback function.
*
* \return None.
*/
/*************************************************************************************************/
void wdxsDcPhyRegister(wdxsDcPhyWriteCback_t cback)
{
wdxsDcCb.phyWriteCback = cback;
}
#endif /* WDXS_DC_ENABLED */
@@ -0,0 +1,518 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Wireless Data Exchange profile implementation - File Transfer.
*
* Copyright (c) 2013-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 <stddef.h>
#include "wsf_types.h"
#include "wsf_trace.h"
#include "wsf_assert.h"
#include "wsf_efs.h"
#include "util/bstream.h"
#include "svc_wdxs.h"
#include "wdxs_api.h"
#include "wdxs_main.h"
#include "dm_api.h"
#include "app_api.h"
/**************************************************************************************************
Local Variables
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Read data from file.
*
* \return TRUE if EOF.
*/
/*************************************************************************************************/
static bool_t wdxsFileRead(uint16_t handle, uint32_t offset, uint32_t *pReadLen, uint8_t *pData)
{
bool_t eof = FALSE;
uint32_t fileSize = WsfEfsGetFileSize(handle);
if (fileSize && (offset + *pReadLen > fileSize))
{
*pReadLen = fileSize - offset;
eof = TRUE;
}
WsfEfsGet(handle, offset, pData, (uint16_t) *pReadLen);
return eof;
}
/*************************************************************************************************/
/*!
* \brief Prepare for FTD data.
*
* \return None.
*/
/*************************************************************************************************/
static uint8_t wdxsInitializeForPut(dmConnId_t connId, uint16_t handle)
{
uint32_t availableSize = WsfEfsGetFileMaxSize(handle);
/* verify file total length
* verify offset+length is not more than total length
*/
if ((wdxsCb.ftTotalLen > availableSize) ||
((wdxsCb.ftOffset + wdxsCb.ftLen) > wdxsCb.ftTotalLen))
{
return WDX_FTC_ST_INVALID_OP_DATA;
}
/* Erase on offset of zero */
if (wdxsCb.ftOffset == 0)
{
WsfEfsErase(handle);
}
/* set up file put operation */
wdxsCb.ftHandle = handle;
wdxsCb.ftInProgress = WDX_FTC_OP_PUT_REQ;
return WDX_FTC_ST_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Send a file transfer control characteristic notification.
*
* \return None.
*/
/*************************************************************************************************/
void wdxsFtcSend(dmConnId_t connId)
{
APP_TRACE_INFO0("WDXS: FTC Send");
/* if notification enabled */
if (AttsCccEnabled(connId, wdxsCb.ftcCccIdx))
{
/* send notification */
AttsHandleValueNtf(connId, WDXS_FTC_HDL, wdxsCb.ftcMsgLen, wdxsCb.ftcMsgBuf);
wdxsCb.txReadyMask &= ~(WDXS_TX_MASK_FTC_BIT | WDXS_TX_MASK_READY_BIT);
}
}
/*************************************************************************************************/
/*!
* \brief Send a file transfer response message.
*
* \return None.
*/
/*************************************************************************************************/
void wdxsFtcSendRsp(dmConnId_t connId, uint8_t op, uint16_t handle, uint8_t status)
{
uint8_t *p;
/* there should not be another response message set up */
if (wdxsCb.txReadyMask & WDXS_TX_MASK_FTC_BIT)
{
APP_TRACE_WARN0("WDXS: FTC message overflow");
return;
}
APP_TRACE_INFO3("WDXS: FTC SendRsp op=%d handle=%d status=%d", op, handle, status);
/* build message */
p = wdxsCb.ftcMsgBuf;
UINT8_TO_BSTREAM(p, op);
UINT16_TO_BSTREAM(p, handle);
if (op != WDX_FTC_OP_ABORT && op != WDX_FTC_OP_EOF)
{
UINT8_TO_BSTREAM(p, status);
}
if (op == WDX_FTC_OP_GET_RSP || op == WDX_FTC_OP_PUT_RSP)
{
UINT8_TO_BSTREAM(p, WDX_FTC_TRANSPORT_TYPE);
UINT16_TO_BSTREAM(p, WDX_FTC_TRANSPORT_ID);
}
wdxsCb.ftcMsgLen = (uint16_t) (p - wdxsCb.ftcMsgBuf);
/* Indicate TX Ready */
wdxsCb.txReadyMask |= WDXS_TX_MASK_FTC_BIT;
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
}
/*************************************************************************************************/
/*!
* \brief Process a file get request.
*
* \return None.
*/
/*************************************************************************************************/
static void wdxsFtcProcGetReq(dmConnId_t connId, uint16_t handle, uint16_t len, uint8_t *pValue)
{
uint8_t status;
APP_TRACE_INFO2("WDXS: FTC GetReq handle=%d len=%d", handle, len);
/* verify operation not already in progress */
if (wdxsCb.ftInProgress != WDX_FTC_OP_NONE)
{
status = WDX_FTC_ST_IN_PROGRESS;
}
else if ((WsfEfsGetFilePermissions(handle) & WSF_EFS_REMOTE_GET_PERMITTED) == 0)
{
status = WDX_FTC_ST_INVALID_OP_FILE;
}
else
{
if (handle == WDX_FLIST_HANDLE)
{
WdxsUpdateListing();
}
/* parse operation data */
BSTREAM_TO_UINT32(wdxsCb.ftOffset, pValue);
BSTREAM_TO_UINT32(wdxsCb.ftLen, pValue);
BSTREAM_TO_UINT8(wdxsCb.ftPrefXferType, pValue);
/* set up file get operation */
wdxsCb.ftHandle = handle;
wdxsCb.ftInProgress = WDX_FTC_OP_GET_REQ;
wdxsCb.txReadyMask |= WDXS_TX_MASK_FTD_BIT;
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
status = WDX_FTC_ST_SUCCESS;
}
/* send response */
wdxsFtcSendRsp(connId, WDX_FTC_OP_GET_RSP, handle, status);
}
/*************************************************************************************************/
/*!
* \brief Process a file put request.
*
* \return None.
*/
/*************************************************************************************************/
static void wdxsFtcProcPutReq(dmConnId_t connId, uint16_t handle, uint16_t len, uint8_t *pValue)
{
uint8_t status;
/* verify operation not already in progress */
if (wdxsCb.ftInProgress != WDX_FTC_OP_NONE)
{
status = WDX_FTC_ST_IN_PROGRESS;
}
/* verify permissions */
else if ((WsfEfsGetFilePermissions(handle) & WSF_EFS_REMOTE_PUT_PERMITTED) == 0)
{
status = WDX_FTC_ST_INVALID_HANDLE;
}
else
{
/* parse operation data */
wdxsCb.ftHandle = handle;
BSTREAM_TO_UINT32(wdxsCb.ftOffset, pValue);
BSTREAM_TO_UINT32(wdxsCb.ftLen, pValue);
BSTREAM_TO_UINT32(wdxsCb.ftTotalLen, pValue);
BSTREAM_TO_UINT8(wdxsCb.ftPrefXferType, pValue);
APP_TRACE_INFO3("WDXS: FTC PutReq handle=%d offset=%d, len=%d", handle, wdxsCb.ftOffset, wdxsCb.ftLen);
/* Initialize transfer*/
status = wdxsInitializeForPut(connId, handle);
}
APP_TRACE_INFO2("WDXS: FTC PutReq handle=%d status=%d", handle, status);
/* send response */
wdxsFtcSendRsp(connId, WDX_FTC_OP_PUT_RSP, handle, status);
}
/*************************************************************************************************/
/*!
* \brief Process a file verify request.
*
* \return None.
*/
/*************************************************************************************************/
static void wdxsFtcProcVerifyReq(dmConnId_t connId, uint16_t handle)
{
uint8_t status;
APP_TRACE_INFO1("WDXS: FTC VerifyReq: handle=%d", handle);
/* verify operation not already in progress */
if (wdxsCb.ftInProgress != WDX_FTC_OP_NONE)
{
status = WDX_FTC_ST_IN_PROGRESS;
}
else if ((WsfEfsGetFilePermissions(handle) & WSF_EFS_REMOTE_VERIFY_PERMITTED) == 0)
{
status = WDX_FTC_ST_INVALID_HANDLE;
}
else
{
/* Call the media specific validate command */
status = WsfEfsMediaSpecificCommand(handle, WSF_EFS_VALIDATE_CMD, 0);
}
/* send response */
wdxsFtcSendRsp(connId, WDX_FTC_OP_VERIFY_RSP, handle, status);
}
/*************************************************************************************************/
/*!
* \brief Process a file erase request.
*
* \return None.
*/
/*************************************************************************************************/
static void wdxsFtcProcEraseReq(dmConnId_t connId, uint16_t handle)
{
uint8_t status = WDX_FTC_ST_SUCCESS;
APP_TRACE_INFO1("WDXS: FTC EraseReq: handle=%d", handle);
/* verify operation not already in progress */
if (wdxsCb.ftInProgress != WDX_FTC_OP_NONE)
{
status = WDX_FTC_ST_IN_PROGRESS;
}
/* verify file handle */
else if ((WsfEfsGetFilePermissions(handle) & WSF_EFS_REMOTE_ERASE_PERMITTED) == 0)
{
status = WDX_FTC_ST_INVALID_OP_FILE;
}
else
{
/* do file erase */
WsfEfsErase(handle);
}
/* send response */
wdxsFtcSendRsp(connId, WDX_FTC_OP_ERASE_RSP, handle, status);
}
/*************************************************************************************************/
/*!
* \brief Process a file abort.
*
* \return None.
*/
/*************************************************************************************************/
static void wdxsFtcProcAbort(dmConnId_t connId, uint16_t handle)
{
APP_TRACE_INFO1("WDXS: FTC AbortReq: handle=%d", handle);
if (wdxsCb.ftInProgress != WDX_FTC_OP_NONE)
{
/* abort operation */
if (WsfEfsGetFileType(handle) == WSF_EFS_FILE_TYPE_STREAM)
{
wdxsCb.ftInProgress = WDX_FTC_OP_ABORT;
}
else
{
wdxsCb.ftInProgress = WDX_FTC_OP_NONE;
}
wdxsCb.ftLen = 0;
wdxsCb.ftOffset = 0;
}
}
/*************************************************************************************************/
/*!
* \brief Process a write to the file transfer data characteristic.
*
* \return ATT status.
*/
/*************************************************************************************************/
uint8_t wdxsFtdWrite(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
/* verify put operation in progress */
if (wdxsCb.ftInProgress != WDX_FTC_OP_PUT_REQ)
{
return ATT_ERR_UNLIKELY;
}
/* verify data length */
if (len <= WDX_FTD_HDR_LEN)
{
return ATT_ERR_LENGTH;
}
/* verify more data is expected */
if (wdxsCb.ftLen >= len)
{
WsfEfsPut(wdxsCb.ftHandle, wdxsCb.ftOffset, pValue, len);
/* update remaining length of put request */
wdxsCb.ftOffset += len;
wdxsCb.ftLen -= len;
/* if end of put req reached */
if (wdxsCb.ftLen == 0)
{
if (wdxsCb.ftOffset == wdxsCb.ftTotalLen)
{
/* Call the media specific WDXS Put Complete command */
WsfEfsMediaSpecificCommand(wdxsCb.ftHandle, WSF_EFS_WDXS_PUT_COMPLETE_CMD, wdxsCb.ftTotalLen);
}
/* put req done */
wdxsCb.ftInProgress = WDX_FTC_OP_NONE;
/* send eof */
wdxsFtcSendRsp(connId, WDX_FTC_OP_EOF, wdxsCb.ftHandle, 0);
}
}
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Process a write to the file transfer control characteristic.
*
* \return ATT status.
*/
/*************************************************************************************************/
uint8_t wdxsFtcWrite(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
uint8_t op;
uint16_t handle;
APP_TRACE_INFO1("WDXS: FTC Write: len=%d", len);
/* sanity check on message length */
if (len < WDX_FTC_HDR_LEN + WDX_FTC_HANDLE_LEN)
{
return ATT_ERR_LENGTH;
}
/* get operation and file handle */
BSTREAM_TO_UINT8(op, pValue);
BSTREAM_TO_UINT16(handle, pValue);
APP_TRACE_INFO2("WDXS: FTC Write: op=%d handle=%d", op, handle);
len -= WDX_FTC_HANDLE_LEN + WDX_FTC_HDR_LEN;
switch (op)
{
case WDX_FTC_OP_GET_REQ:
wdxsFtcProcGetReq(connId, handle, len, pValue);
break;
case WDX_FTC_OP_PUT_REQ:
wdxsFtcProcPutReq(connId, handle, len, pValue);
break;
case WDX_FTC_OP_VERIFY_REQ:
wdxsFtcProcVerifyReq(connId, handle);
break;
case WDX_FTC_OP_ERASE_REQ:
wdxsFtcProcEraseReq(connId, handle);
break;
case WDX_FTC_OP_ABORT:
wdxsFtcProcAbort(connId, handle);
break;
default:
break;
}
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Send a file transfer data characteristic notification.
*
* \return None.
*/
/*************************************************************************************************/
void wdxsFtdSend(dmConnId_t connId)
{
/* if notification enabled */
if (AttsCccEnabled(connId, wdxsCb.ftdCccIdx))
{
uint8_t *pBuf;
uint32_t readLen = AttGetMtu(connId) - ATT_VALUE_NTF_LEN;
bool_t eof;
uint8_t fileType = WsfEfsGetFileType(wdxsCb.ftHandle);
/* Check for abort when Streaming */
if ((fileType == WSF_EFS_FILE_TYPE_STREAM) && (wdxsCb.ftInProgress == WDX_FTC_OP_ABORT))
{
eof = TRUE;
readLen = 0;
}
else
{
eof = FALSE;
}
readLen = (readLen < wdxsCb.ftLen) ? readLen : wdxsCb.ftLen;
if (readLen && (pBuf = AttMsgAlloc((uint16_t)readLen, ATT_PDU_VALUE_NTF)) != NULL)
{
/* read data from file */
eof = wdxsFileRead(wdxsCb.ftHandle, wdxsCb.ftOffset, &readLen, pBuf);
if (readLen > 0)
{
/* update stored offset and length (non-streaming file) */
if (fileType == WSF_EFS_FILE_TYPE_BULK)
{
wdxsCb.ftLen -= readLen;
wdxsCb.ftOffset += readLen;
}
/* send notification */
AttsHandleValueNtfZeroCpy(connId, WDXS_FTD_HDL, (uint16_t)readLen, pBuf);
wdxsCb.txReadyMask &= ~(WDXS_TX_MASK_READY_BIT);
}
else
{
AttMsgFree(pBuf, ATT_PDU_VALUE_NTF);
}
}
/* check if end of transfer reached */
if (wdxsCb.ftLen == 0 || readLen == 0 || eof || wdxsCb.ftInProgress == WDX_FTC_OP_ABORT)
{
wdxsCb.ftInProgress = WDX_FTC_OP_NONE;
wdxsCb.txReadyMask &= ~(WDXS_TX_MASK_FTD_BIT);
}
if (eof)
{
/* send EOF */
wdxsFtcSendRsp(connId, WDX_FTC_OP_EOF, wdxsCb.ftHandle, 0);
}
}
}
@@ -0,0 +1,539 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Wireless Data Exchange profile implementation.
*
* Copyright (c) 2013-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 "util/wstr.h"
#include "wsf_trace.h"
#include "wsf_assert.h"
#include "wsf_efs.h"
#include "wsf_os.h"
#include "sec_api.h"
#include "util/bstream.h"
#include "svc_wdxs.h"
#include "wdxs_api.h"
#include "wdxs_main.h"
#include "dm_api.h"
#include "att_api.h"
#include "app_api.h"
/**************************************************************************************************
Global Variables
**************************************************************************************************/
/*! application control block */
wdxsCb_t wdxsCb;
/**************************************************************************************************
Macros
**************************************************************************************************/
/*! RAM File Media Configuration */
#define WDXS_RAM_LOCATION ((uint32_t)WdxsRamBlock)
#define WDXS_RAM_SIZE (WDX_FLIST_MAX_LEN + WDXS_APP_RAM_MEDIA_SIZE)
#define WDXS_RAM_END (WDXS_RAM_LOCATION + WDXS_RAM_SIZE)
/**************************************************************************************************
Local Function Prototypes
**************************************************************************************************/
static uint8_t WdxsRamErase(uint32_t address, uint32_t size);
static uint8_t WdxsRamRead(uint8_t *pBuf, uint32_t address, uint32_t size);
static uint8_t WdxsRamWrite(const uint8_t *pBuf, uint32_t address, uint32_t size);
/**************************************************************************************************
Function Prototypes
**************************************************************************************************/
void WdxsAuSecComplete(secAes_t *pAes);
/**************************************************************************************************
Local Variables
**************************************************************************************************/
/*! Reserve RAM for use by the RAM EFS Media */
static uint8_t WdxsRamBlock[WDXS_RAM_SIZE];
/*! EFS RAM Media Control Block */
static const wsfEfsMedia_t WDXS_RamMediaCtrl =
{
WDXS_RAM_LOCATION,
WDXS_RAM_LOCATION + WDXS_RAM_SIZE,
1,
NULL,
WdxsRamErase,
WdxsRamRead,
WdxsRamWrite,
NULL
};
/*************************************************************************************************/
/*!
* \brief Erase function for the EFS RAM media.
*
* \return none.
*
*/
/*************************************************************************************************/
static uint8_t WdxsRamErase(uint32_t address, uint32_t size)
{
uint8_t *pMem = (uint8_t *) address;
memset(pMem, 0xFF, size);
return TRUE;
}
/*************************************************************************************************/
/*!
* \brief Read function for the EFS RAM media.
*
* \return none.
*
*/
/*************************************************************************************************/
static uint8_t WdxsRamRead(uint8_t *pBuf, uint32_t address, uint32_t size)
{
uint8_t *pMem = (uint8_t *) address;
memcpy(pBuf, pMem, size);
return TRUE;
}
/*************************************************************************************************/
/*!
* \brief Write function for the EFS RAM media.
*
* \return none.
*
*/
/*************************************************************************************************/
static uint8_t WdxsRamWrite(const uint8_t *pBuf, uint32_t address, uint32_t size)
{
uint8_t *pMem = (uint8_t *) address;
memcpy(pMem, pBuf, size);
return TRUE;
}
/*************************************************************************************************/
/*!
* \brief Format file list information for the given file.
*
* \return none.
*/
/*************************************************************************************************/
static void wdxsFormatFileResource(uint8_t *pData, wsfEfsHandle_t handle)
{
UINT16_TO_BSTREAM(pData, handle);
UINT8_TO_BSTREAM(pData, WsfEfsGetFileType(handle));
UINT8_TO_BSTREAM(pData, WsfEfsGetFilePermissions(handle) & WSF_EFS_REMOTE_PERMISSIONS_MASK);
UINT32_TO_BSTREAM(pData, WsfEfsGetFileSize(handle));
WstrnCpy((char *)pData, WsfEfsGetFileName(handle), WSF_EFS_NAME_LEN);
WstrnCpy((char *)pData+WSF_EFS_NAME_LEN, WsfEfsGetFileVersion(handle), WSF_EFS_VERSION_LEN);
}
/*************************************************************************************************/
/*!
* \brief Create the file list.
*
* \return none.
*/
/*************************************************************************************************/
void WdxsUpdateListing(void)
{
uint8_t *pTmp;
uint8_t header[WDX_FLIST_HDR_SIZE];
uint8_t record[WDX_FLIST_RECORD_SIZE];
uint32_t position = 0, totalSize = 0;
uint32_t fileCount = 0;
uint8_t i;
position = WDX_FLIST_HDR_SIZE;
for (i=0; i<WSF_EFS_MAX_FILES; i++)
{
if (WsfEfsGetFileByHandle(i) && (WsfEfsGetFilePermissions(i) & WSF_EFS_REMOTE_VISIBLE))
{
/* Update the total size and file count */
totalSize += WsfEfsGetFileSize(i);
fileCount++;
wdxsFormatFileResource(record, i);
/* Write the record */
WsfEfsPut(WDX_FLIST_HANDLE, position, record, WDX_FLIST_RECORD_SIZE);
position += WDX_FLIST_RECORD_SIZE;
}
}
/* Add the header after calculating the total_size and file_count */
pTmp = header;
UINT8_TO_BSTREAM(pTmp, WDX_FLIST_FORMAT_VER);
UINT16_TO_BSTREAM(pTmp, fileCount);
UINT32_TO_BSTREAM(pTmp, totalSize);
/* Write the header */
WsfEfsPut(WDX_FLIST_HANDLE, 0, header, WDX_FLIST_HDR_SIZE);
}
/*************************************************************************************************/
/*!
* \brief Set the CCCD index used by the application for WDXS service characteristics.
*
* \param dcCccIdx Device Control CCCD index.
* \param auCccIdx Authentication CCCD index.
* \param ftcCccIdx File Transfer Control CCCD index.
* \param ftdCccIdx File Transfer Data CCCD index.
*
* \return None.
*/
/*************************************************************************************************/
void WdxsSetCccIdx(uint8_t dcCccIdx, uint8_t auCccIdx, uint8_t ftcCccIdx, uint8_t ftdCccIdx)
{
wdxsCb.dcCccIdx = dcCccIdx;
wdxsCb.auCccIdx = auCccIdx;
wdxsCb.ftcCccIdx = ftcCccIdx;
wdxsCb.ftdCccIdx = ftdCccIdx;
}
/*************************************************************************************************/
/*!
* \brief ATTS write callback for proprietary service.
*
* \return ATT status.
*/
/*************************************************************************************************/
uint8_t wdxsWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr)
{
uint8_t status;
#if WDXS_AU_ENABLED == TRUE
/* Require peer authentication before writing to any characteristic
(except for the authentication characteristic) */
if ((wdxsAuCb.reqAuthLevel != WDX_AU_LVL_NONE) && (handle != WDXS_AU_HDL))
{
if ((wdxsAuCb.authState != WDXS_AU_STATE_AUTHORIZED) || (wdxsAuCb.authLevel < wdxsAuCb.reqAuthLevel))
{
APP_TRACE_INFO1("WDXS: WriteCback unauthorized state=%d", wdxsAuCb.authState);
return WDX_APP_AUTH_REQUIRED;
}
}
#endif /* WDXS_AU_ENABLED */
switch (handle)
{
#if WDXS_DC_ENABLED == TRUE
/* Device configuration */
case WDXS_DC_HDL:
status = wdxsDcWrite(connId, len, pValue);
break;
#endif /* WDXS_DC_ENABLED */
/* File transfer control */
case WDXS_FTC_HDL:
status = wdxsFtcWrite(connId, len, pValue);
break;
/* File transfer data */
case WDXS_FTD_HDL:
status = wdxsFtdWrite(connId, len, pValue);
break;
#if WDXS_AU_ENABLED == TRUE
/* Authentication */
case WDXS_AU_HDL:
status = wdxsAuWrite(connId, len, pValue);
break;
#endif /* WDXS_AU_ENABLED */
default:
APP_TRACE_INFO1("WDXS: WriteCback unexpected handle=%d", handle);
status = ATT_ERR_HANDLE;
break;
}
return status;
}
/*************************************************************************************************/
/*!
* \brief Process TX data path
*
* \return None.
*/
/*************************************************************************************************/
static void wdxsProcTxPath(void)
{
dmConnId_t connId;
/* Check for a connection */
if ((connId = AppConnIsOpen()) != DM_CONN_ID_NONE)
{
/* Check if ready to transmit a message */
if (wdxsCb.txReadyMask & WDXS_TX_MASK_READY_BIT)
{
#if WDXS_DC_ENABLED == TRUE
/* Device configuration */
if (wdxsCb.txReadyMask & WDXS_TX_MASK_DC_BIT)
{
wdxsDcSend(connId);
return;
}
#endif /* WDXS_DC_ENABLED */
/* File Transfer Control */
if (wdxsCb.txReadyMask & WDXS_TX_MASK_FTC_BIT)
{
wdxsFtcSend(connId);
return;
}
#if WDXS_AU_ENABLED == TRUE
/* Authentication */
if (wdxsCb.txReadyMask & WDXS_TX_MASK_AU_BIT)
{
wdxsAuSend(connId);
return;
}
#endif /* WDXS_AU_ENABLED */
/* File Transfer Data */
if (wdxsCb.txReadyMask & WDXS_TX_MASK_FTD_BIT)
{
wdxsFtdSend(connId);
return;
}
}
}
}
/*************************************************************************************************/
/*!
* \brief WSF event handler for application.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void WdxsHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
{
APP_TRACE_INFO1("WDXS: Task Handler Evt=%d", event);
if (event & WDXS_EVT_TX_PATH)
{
wdxsProcTxPath();
}
#if WDXS_AU_ENABLED == TRUE
if (event & WDXS_EVT_AU_SEC_COMPLETE)
{
WdxsAuSecComplete((secAes_t*) pMsg);
}
#endif /* WDXS_AU_ENABLED */
}
/*************************************************************************************************/
/*!
* \brief Called by application to notify the WDXS of DM Events.
*
* \param pEvt Pointer to the DM Event
*
* \return None.
*/
/*************************************************************************************************/
void WdxsProcDmMsg(dmEvt_t *pEvt)
{
switch (pEvt->hdr.event)
{
case DM_CONN_CLOSE_IND:
if (wdxsDcCb.doReset)
{
WdxsResetSystem();
}
break;
case DM_CONN_OPEN_IND:
/* Initialize connection parameters */
wdxsCb.txReadyMask = WDXS_TX_MASK_READY_BIT;
wdxsCb.ftInProgress = WDX_FTC_OP_NONE;
wdxsCb.ftLen = 0;
wdxsCb.ftOffset = 0;
#if WDXS_AU_ENABLED == TRUE
wdxsAuCb.authLevel = WDX_AU_LVL_NONE;
wdxsAuCb.authState = WDXS_AU_STATE_UNAUTHORIZED;
#endif /* WDXS_AU_ENABLED */
wdxsCb.connInterval = pEvt->connOpen.connInterval;
wdxsCb.connLatency = pEvt->connOpen.connLatency;
wdxsCb.supTimeout = pEvt->connOpen.supTimeout;
wdxsCb.txPhy= HCI_PHY_LE_1M_BIT;
wdxsCb.rxPhy = HCI_PHY_LE_1M_BIT;
break;
case DM_CONN_UPDATE_IND:
if (pEvt->hdr.status == HCI_SUCCESS)
{
wdxsCb.connInterval = pEvt->connUpdate.connInterval;
wdxsCb.connLatency = pEvt->connUpdate.connLatency;
wdxsCb.supTimeout = pEvt->connUpdate.supTimeout;
}
wdxsDcUpdateConnParam((dmConnId_t) pEvt->hdr.param, pEvt->hdr.status);
break;
case DM_PHY_UPDATE_IND:
if (pEvt->hdr.status == HCI_SUCCESS)
{
wdxsCb.txPhy = pEvt->phyUpdate.txPhy;
wdxsCb.rxPhy = pEvt->phyUpdate.rxPhy;
}
wdxsDcUpdatePhy((dmConnId_t) pEvt->hdr.param, pEvt->hdr.status);
break;
default:
break;
}
}
/*************************************************************************************************/
/*!
* \brief Called by application to notify the WDXS of ATT Events.
*
* \param pEvt Pointer to the ATT Event
*
* \return None.
*/
/*************************************************************************************************/
uint8_t WdxsAttCback(attEvt_t *pEvt)
{
if (pEvt->handle < WDXS_START_HDL || pEvt->handle > WDXS_END_HDL)
{
return FALSE;
}
APP_TRACE_INFO2("WDXS: AttHook handle=%d event=%d", pEvt->handle, pEvt->hdr.event);
/* trigger tx data path on confirm */
if (pEvt->hdr.event == ATTS_HANDLE_VALUE_CNF &&
pEvt->hdr.status == ATT_SUCCESS)
{
wdxsCb.txReadyMask |= WDXS_TX_MASK_READY_BIT;
WsfSetEvent(wdxsCb.handlerId, WDXS_EVT_TX_PATH);
}
return TRUE;
}
/*************************************************************************************************/
/*!
* \brief Application handler init function called during system initialization.
*
* \param handlerID WSF handler ID.
*
* \return None.
*/
/*************************************************************************************************/
void WdxsHandlerInit(wsfHandlerId_t handlerId)
{
wsfEsfAttributes_t attr;
APP_TRACE_INFO0("WDXS: WdxsHandlerInit");
/* Initialize the control block */
memset(&wdxsCb, 0, sizeof(wdxsCb));
wdxsCb.txReadyMask = WDXS_TX_MASK_READY_BIT;
/* Store Handler ID */
wdxsCb.handlerId = handlerId;
/* Initialize the device configuration control block */
memset(&wdxsDcCb, 0, sizeof(wdxsDcCb));
/* Register the WDXS Service */
SvcWdxsRegister(wdxsWriteCback);
SvcWdxsAddGroup();
/* Initialize the embedded file system */
WsfEfsInit();
/* Register the RAM Media */
memset(WdxsRamBlock, 0xFF, sizeof(WdxsRamBlock));
WsfEfsRegisterMedia(&WDXS_RamMediaCtrl, WDX_RAM_MEDIA);
/* Set attributes for the WDXS File List */
attr.type = WSF_EFS_FILE_TYPE_BULK;
attr.permissions = WSF_EFS_LOCAL_PUT_PERMITTED | WSF_EFS_REMOTE_GET_PERMITTED;
WstrnCpy(attr.name, "Listing", WSF_EFS_NAME_LEN);
WstrnCpy(attr.version, "1.0", WSF_EFS_VERSION_LEN);
/* Create a file in RAM to contain the list WDXS File List */
WsfEfsAddFile(WDX_FLIST_MAX_LEN, WDX_RAM_MEDIA, &attr, WSF_EFS_FILE_OFFSET_ANY);
}
/*************************************************************************************************/
/*!
* \fn WdxsOtaMediaInit
*
* \brief Registers the platform dependent OTA Media with the Embedded File System (EFS)
*
* \param None
*
* \return None.
*/
/*************************************************************************************************/
void WdxsOtaMediaInit(void)
{
}
/*************************************************************************************************/
/*!
* \fn WdxsResetSystem
*
* \brief Resets the system.
*
* \param None
*
* \return None.
*/
/*************************************************************************************************/
void WdxsResetSystem(void)
{
}
/*************************************************************************************************/
/*!
* \fn WdxsFlashMediaInit
*
* \brief Registers the platform dependent Flash Media with the Embedded File System (EFS)
*
* \param None
*
* \return None.
*/
/*************************************************************************************************/
void WdxsFlashMediaInit(void)
{
}
@@ -0,0 +1,327 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Wireless Data Exchange profile implementation.
*
* Copyright (c) 2013-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 WDXS_MAIN_H
#define WDXS_MAIN_H
#ifdef __cplusplus
extern "C" {
#endif
/*! \addtogroup WIRELESS_DATA_EXCHANGE_PROFILE
* \{ */
/**************************************************************************************************
Macros
**************************************************************************************************/
/** \name WDXS Default Feature Set
*
*/
/**@{*/
#ifndef WDXS_DC_ENABLED
#define WDXS_DC_ENABLED TRUE
#endif
#ifndef WDXS_AU_ENABLED
#define WDXS_AU_ENABLED TRUE
#endif
#ifndef WDXS_OTA_ENABLED
#define WDXS_OTA_ENABLED TRUE
#endif
/**@}*/
/*! \brief Special length for streaming file */
#define WDXS_STREAM_FILE_LEN 0xFFFFFFFF
/** \name WSF event types for application event handler
*
*/
/**@{*/
#define WDXS_EVT_TX_PATH 0x01 /*!< \brief Trigger tx data path */
#define WDXS_EVT_AU_SEC_COMPLETE 0x02 /*!< \brief AU encryption of challenge ready */
/**@}*/
/** \name TX Ready Mask Bits
*
*/
/**@{*/
#define WDXS_TX_MASK_READY_BIT (1<<0) /*!< \brief Ready bit */
#define WDXS_TX_MASK_DC_BIT (1<<1) /*!< \brief DC bit */
#define WDXS_TX_MASK_FTC_BIT (1<<2) /*!< \brief FTC bit */
#define WDXS_TX_MASK_FTD_BIT (1<<3) /*!< \brief FTD bit */
#define WDXS_TX_MASK_AU_BIT (1<<4) /*!< \brief AU bit */
/**@}*/
/** \name Authentication states
*
*/
/**@{*/
#define WDXS_AU_STATE_UNAUTHORIZED 0x00 /*!< \brief Authentication has not started */
#define WDXS_AU_STATE_HASHING 0x01 /*!< \brief Authentication hash is being calculated */
#define WDXS_AU_STATE_WAIT_SEC 0x02 /*!< \brief Authentication challenge sent */
#define WDXS_AU_STATE_WAIT_REPLY 0x03 /*!< \brief Authentication waiting for challenge reply */
#define WDXS_AU_STATE_AUTHORIZED 0x04 /*!< \brief Authentication completed successfully */
/**@}*/
/**************************************************************************************************
Data Types
**************************************************************************************************/
/*! \brief WDXS Device Configuration PHY Write Callback */
typedef uint8_t (*wdxsDcPhyWriteCback_t)(dmConnId_t connId, uint8_t op, uint8_t id, uint16_t len,
uint8_t *pValue);
/**************************************************************************************************
Local Variables
**************************************************************************************************/
/*! \brief WDXS profile control block */
typedef struct
{
wsfHandlerId_t handlerId; /*!< \brief WSF handler ID */
uint8_t txReadyMask; /*!< \brief Bits indicate DC, FTC, FTD, and/or AU wish to transmit */
/* connection parameters */
uint16_t connInterval; /*!< \brief connection interval */
uint16_t connLatency; /*!< \brief connection latency */
uint16_t supTimeout; /*!< \brief supervision timeout */
/* Phy parameters */
uint8_t txPhy; /*!< \brief transmitter PHY */
uint8_t rxPhy; /*!< \brief receiver PHY */
/* for file transfer */
uint32_t ftOffset; /*!< \brief file data offset */
uint32_t ftLen; /*!< \brief remaining data length for current operation */
uint32_t ftTotalLen; /*!< \brief file total length */
uint16_t ftHandle; /*!< \brief file handle */
uint16_t ftcMsgLen; /*!< \brief message length */
uint8_t ftcMsgBuf[ATT_DEFAULT_PAYLOAD_LEN]; /*!< \brief message buffer */
uint8_t ftInProgress; /*!< \brief operation in progress */
uint8_t ftPrefXferType; /*!< \brief Preferred transport type */
/* ccc index */
uint8_t dcCccIdx; /*!< \brief device configuration ccc index */
uint8_t auCccIdx; /*!< \brief authentication ccc index */
uint8_t ftcCccIdx; /*!< \brief file transfer control ccc index */
uint8_t ftdCccIdx; /*!< \brief file transfer data ccc index */
} wdxsCb_t;
/*! \brief WDXS Device Configuration Control Block */
typedef struct
{
uint16_t dcMsgLen; /*!< \brief message length */
uint8_t dcMsgBuf[ATT_DEFAULT_PAYLOAD_LEN]; /*!< \brief message buffer */
bool_t doReset; /*!< \brief Reset device after disconnect */
wdxsDcPhyWriteCback_t phyWriteCback; /*!< \brief Device config PHY write callback */
} wdxsDcCb_t;
/*! \brief WDXS Authentication Control Block */
typedef struct
{
uint8_t auMsgBuf[ATT_DEFAULT_PAYLOAD_LEN]; /*!< \brief message buffer */
uint8_t auRand[WDX_AU_RAND_LEN]; /*!< \brief random challenge */
uint8_t sessionKey[WDX_AU_KEY_LEN]; /*!< \brief session key */
uint8_t auHash[WDX_AU_HASH_LEN]; /*!< \brief session key */
uint16_t auMsgLen; /*!< \brief message length */
uint8_t authLevel; /*!< \brief current authentication level */
uint8_t authMode; /*!< \brief current authentication mode */
uint8_t reqAuthLevel; /*!< \brief requested authentication level */
uint8_t authState; /*!< \brief authentication protocol state */
} wdxsAuCb_t;
/*! \brief WDXS event message union */
typedef union
{
wsfMsgHdr_t hdr; /*!< header */
dmEvt_t dm; /*!< DM event */
attsCccEvt_t ccc; /*!< ATT CCC event */
} wdxsMsg_t;
/**************************************************************************************************
Global Variables
**************************************************************************************************/
/** \name WDXS Control Block External Declaration
*
*/
/**@{*/
extern wdxsCb_t wdxsCb; /*!< \brief WDXS control block */
extern wdxsAuCb_t wdxsAuCb; /*!< \brief WDXS AU control block */
extern wdxsDcCb_t wdxsDcCb; /*!< \brief WDXS DC control block */
/**@}*/
/**************************************************************************************************
Global Function Prototypes
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Send device configuration notification
*
* \param connId DM connection identifier.
*
* \return None.
*/
/*************************************************************************************************/
void wdxsDcSend(dmConnId_t connId);
/*************************************************************************************************/
/*!
* \brief Send a file transfer control characteristic notification.
*
* \param connId DM connection identifier.
*
* \return None.
*/
/*************************************************************************************************/
void wdxsFtcSend(dmConnId_t connId);
/*************************************************************************************************/
/*!
* \brief Send a file transfer data characteristic notification.
*
* \param connId DM connection identifier.
*
* \return None.
*/
/*************************************************************************************************/
void wdxsFtdSend(dmConnId_t connId);
/*************************************************************************************************/
/*!
* \brief Transmit to authentication characteristic.
*
* \param connId DM connection identifier.
*
* \return ATT status.
*/
/*************************************************************************************************/
void wdxsAuSend(dmConnId_t connId);
/*************************************************************************************************/
/*!
* \brief Process a write to the device configuration characteristic.
*
* \param connId DM connection identifier.
* \param len Length to write.
* \param pValue value to write.
*
* \return ATT status.
*/
/*************************************************************************************************/
uint8_t wdxsDcWrite(dmConnId_t connId, uint16_t len, uint8_t *pValue);
/*************************************************************************************************/
/*!
* \brief Process a write to the file transfer control characteristic.
*
* \param connId DM connection identifier.
* \param len Length to write.
* \param pValue Value to write.
*
* \return ATT status.
*/
/*************************************************************************************************/
uint8_t wdxsFtcWrite(dmConnId_t connId, uint16_t len, uint8_t *pValue);
/*************************************************************************************************/
/*!
* \brief Process a write to the file transfer data characteristic.
*
* \param connId DM connection identifier.
* \param len Length to write.
* \param pValue Value to write.
*
* \return ATT status.
*/
/*************************************************************************************************/
uint8_t wdxsFtdWrite(dmConnId_t connId, uint16_t len, uint8_t *pValue);
/*************************************************************************************************/
/*!
* \brief Process a write to the authentication characteristic.
*
* \param connId DM connection identifier.
* \param len Length to write.
* \param pValue Value to write
*
* \return ATT status.
*/
/*************************************************************************************************/
uint8_t wdxsAuWrite(dmConnId_t connId, uint16_t len, uint8_t *pValue);
/*************************************************************************************************/
/*!
* \brief Send update message for connection parameters.
*
* \param connId DM connection identifier.
* \param status Update status.
*
* \return ATT status.
*/
/*************************************************************************************************/
uint8_t wdxsDcUpdateConnParam(dmConnId_t connId, uint8_t status);
/*************************************************************************************************/
/*!
* \brief Send update message for PHY.
*
* \param connId DM connection identifier.
* \param status Update status.
*
* \return ATT status.
*/
/*************************************************************************************************/
uint8_t wdxsDcUpdatePhy(dmConnId_t connId, uint8_t status);
/*************************************************************************************************/
/*!
* \brief Register a PHY write callback for the device configuration characteristic.
*
* \param cback PHY callback function.
*
* \return None.
*/
/*************************************************************************************************/
void wdxsDcPhyRegister(wdxsDcPhyWriteCback_t cback);
/*************************************************************************************************/
/*!
* \brief Create the file list.
*
* \return none.
*/
/*************************************************************************************************/
void WdxsUpdateListing(void);
/*! \} */ /* WIRELESS_DATA_EXCHANGE_PROFILE */
#ifdef __cplusplus
}
#endif
#endif /* WDXS_MAIN_H */
@@ -0,0 +1,147 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Wireless Data Exchange profile implementation - Device PHY Configuration.
*
* Copyright (c) 2013-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 "util/wstr.h"
#include "wsf_trace.h"
#include "wsf_assert.h"
#include "wsf_efs.h"
#include "util/bstream.h"
#include "svc_wdxs.h"
#include "wdxs_api.h"
#include "wdxs_main.h"
#include "dm_api.h"
#include "app_api.h"
#include "app_hw.h"
#if WDXS_DC_ENABLED == TRUE
/*************************************************************************************************/
/*!
* \brief Process set PHY request.
*
* \return ATT status.
*/
/*************************************************************************************************/
static uint8_t wdxsDcSetPhyReq(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
uint8_t allPhys;
uint8_t txPhys;
uint8_t rxPhys;
uint16_t phyOptions;
/* verify parameter length */
if (len != WDX_DC_LEN_PHY_UPDATE_REQ)
{
return ATT_ERR_LENGTH;
}
/* parse parameters */
BSTREAM_TO_UINT8(allPhys, pValue);
BSTREAM_TO_UINT8(txPhys, pValue);
BSTREAM_TO_UINT8(rxPhys, pValue);
BSTREAM_TO_UINT16(phyOptions, pValue);
/* request update to PHY */
DmSetPhy(connId, allPhys, txPhys, rxPhys, phyOptions);
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \brief Process a Get PHY request.
*
* \return ATT status.
*/
/*************************************************************************************************/
static uint8_t wdxsDcGetPhy(dmConnId_t connId, uint16_t len, uint8_t *pValue)
{
return wdxsDcUpdatePhy(connId, HCI_SUCCESS);
}
/*************************************************************************************************/
/*!
* \brief Process a PHY write to the device configuration characteristic.
*
* \return ATT status.
*/
/*************************************************************************************************/
static uint8_t wdxsDcPhyWrite(dmConnId_t connId, uint8_t op, uint8_t id, uint16_t len, uint8_t *pValue)
{
uint8_t status;
/* set operation */
if (op == WDX_DC_OP_SET)
{
switch (id)
{
case WDX_DC_ID_PHY_UPDATE_REQ:
status = wdxsDcSetPhyReq(connId, len, pValue);
break;
default:
status = ATT_ERR_RANGE;
break;
}
}
/* get operation */
else if (op == WDX_DC_OP_GET)
{
switch (id)
{
case WDX_DC_ID_PHY:
status = wdxsDcGetPhy(connId, len, pValue);
break;
default:
status = ATT_ERR_RANGE;
break;
}
}
else
{
status = ATT_ERR_RANGE;
}
return status;
}
/*************************************************************************************************/
/*!
* \brief Initialize WDXS Device Configuration PHY.
*
* \param None
*
* \return None.
*/
/*************************************************************************************************/
void WdxsPhyInit(void)
{
/* register device configuration phy write callback */
wdxsDcPhyRegister(wdxsDcPhyWrite);
}
#endif /* WDXS_DC_ENABLED */
@@ -0,0 +1,264 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Wireless Data Exchange profile implementation - Stream Example.
*
* Copyright (c) 2013-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 "util/wstr.h"
#include "wsf_trace.h"
#include "wsf_assert.h"
#include "wsf_efs.h"
#include "util/bstream.h"
#include "svc_wdxs.h"
#include "wdxs_api.h"
#include "wdxs_main.h"
#include "wdxs_stream.h"
#include "dm_api.h"
#include "att_api.h"
#include "app_api.h"
/*! Type of waveform to output from the Example Stream */
static uint8_t wdxsStreamWaveform = WDXS_STREAM_WAVEFORM_SINE;
/*************************************************************************************************/
/*
* Note: This file contains an example of creating Wireless Data Exchange
* (WDXS) Streams. WDXS Streams are implemented as virtual Physical Media in
* the Embedded File System (EFS). A Stream can be created in three steps:
*
* Step 1: Create a FileMedia_t (EFS Media Control structure) for the stream
* containing the read function created in step 2.
*
* Step 2: Implement a read function for the stream. The WDXS and EFS will
* call the read function to get data from the stream.
*
* Step 3: Register the media with the EFS, and add a file to the embedded
* file system that uses the media created in step 2.
*/
/*************************************************************************************************/
/*************************************************************************************************/
/* Step 1: Media Control Block */
/*************************************************************************************************/
/* Prototype of stream read function */
static uint8_t wdxsStreamRead(uint8_t *pBuf, uint32_t address, uint32_t len);
/* Example media control structure for a stream */
static const wsfEfsMedia_t WDXS_StreamMedia =
{
0,
0,
0,
NULL,
NULL,
wdxsStreamRead,
NULL,
NULL
};
/*************************************************************************************************/
/* Step 2: Read Function */
/*************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Example of a media read function that generates a Sine Wave.
*
* \param pBuf buffer to hold stream data.
* \param address unused in streams.
* \param len size of pBuf in bytes.
*
* \return None.
*/
/*************************************************************************************************/
static uint8_t wdxsSineRead(uint8_t *pBuf, uint32_t address, uint32_t len)
{
static int8_t incr = 1;
static uint8_t dataVal = 0;
/* Build data in sine waveform */
memset(pBuf, dataVal, len);
if (dataVal <= 127)
{
incr++;
}
else
{
incr--;
}
dataVal += (incr / 2);
return TRUE;
}
/*************************************************************************************************/
/*!
* \brief Example of a media read function that generates a Step Wave.
*
* \param pBuf buffer to hold stream data.
* \param address unused in streams.
* \param len size of pBuf in bytes.
*
* \return None.
*/
/*************************************************************************************************/
static uint8_t wdxsStepRead(uint8_t *pBuf, uint32_t address, uint32_t len)
{
static int8_t count = 0;
static int8_t incr = 25;
static uint8_t dataVal = 0;
/* Build data in step waveform */
memset(pBuf, dataVal, len);
if (count++ == 5)
{
count = 0;
dataVal += incr;
if (dataVal == 0)
incr = 25;
if (dataVal == 250)
incr = -25;
}
return TRUE;
}
/*************************************************************************************************/
/*!
* \brief Example of a media read function that generates a Sawtooth Wave.
*
* \param pBuf buffer to hold stream data.
* \param address unused in streams.
* \param len size of pBuf in bytes.
*
* \return None.
*/
/*************************************************************************************************/
static uint8_t wdxsSawtoothRead(uint8_t *pBuf, uint32_t address, uint32_t len)
{
static int8_t incr = 1;
static uint8_t dataVal = 0;
uint32_t i;
/* Build data in sawtooth waveform */
for (i=0; i<len; i++)
{
*pBuf++ = dataVal;
dataVal += incr;
if (dataVal == 0)
incr = 1;
else if (dataVal == 255)
incr = -1;
}
return TRUE;
}
/*************************************************************************************************/
/*!
* \brief Example of a media read function.
*
* \param pBuf buffer to hold stream data.
* \param address unused in streams.
* \param len size of pBuf in bytes.
*
* \return None.
*/
/*************************************************************************************************/
static uint8_t wdxsStreamRead(uint8_t *pBuf, uint32_t address, uint32_t len)
{
switch(wdxsStreamWaveform)
{
case WDXS_STREAM_WAVEFORM_SINE:
wdxsSineRead(pBuf, address, len);
break;
case WDXS_STREAM_WAVEFORM_STEP:
wdxsStepRead(pBuf, address, len);
break;
case WDXS_STREAM_WAVEFORM_SAWTOOTH:
wdxsSawtoothRead(pBuf, address, len);
break;
}
return TRUE;
}
/*************************************************************************************************/
/* Step 3: Register the stream media and adding the stream file. */
/*************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Example of creating a WDXS stream.
*
* \param none
*
* \return None.
*/
/*************************************************************************************************/
void wdxsStreamInit(void)
{
wsfEsfAttributes_t attr;
/* Register the media for the stream */
WsfEfsRegisterMedia(&WDXS_StreamMedia, WDX_STREAM_MEDIA);
/* Set the attributes for the stream */
attr.permissions = WSF_EFS_REMOTE_VISIBLE | WSF_EFS_REMOTE_GET_PERMITTED;
attr.type = WSF_EFS_FILE_TYPE_STREAM;
/* Potential buffer overrun is intentional to zero out fixed length field */
/* coverity[overrun-buffer-arg] */
WstrnCpy(attr.name, "Stream", WSF_EFS_NAME_LEN);
/* coverity[overrun-buffer-arg] */
WstrnCpy(attr.version, "1.0", WSF_EFS_VERSION_LEN);
/* Add a file for the stream */
WsfEfsAddFile(0, WDX_STREAM_MEDIA, &attr, 0);
}
/*************************************************************************************************/
/*!
* \brief Changes the type of waveform transmitted by the stream.
*
* \param type - Identifier of the waveform
*
* \return None.
*/
/*************************************************************************************************/
void wdxsSetStreamWaveform(uint8_t type)
{
if (type <= WDXS_STREAM_WAVEFORM_SAWTOOTH)
{
wdxsStreamWaveform = type;
}
}
@@ -0,0 +1,79 @@
/*************************************************************************************************/
/*!
* \file
*
* \brief Wireless Data Exchange profile implementation - Stream Example.
*
* Copyright (c) 2013-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 WDXS_STREAM_H
#define WDXS_STREAM_H
#ifdef __cplusplus
extern "C" {
#endif
/*! \addtogroup WIRELESS_DATA_EXCHANGE_PROFILE
* \{ */
/**************************************************************************************************
Constant Definitions
**************************************************************************************************/
/** \name WDXS Stream Waveform Types
* Type of waveform to output from the Example Stream
*/
/**@{*/
#define WDXS_STREAM_WAVEFORM_SINE 0
#define WDXS_STREAM_WAVEFORM_STEP 1
#define WDXS_STREAM_WAVEFORM_SAWTOOTH 2
/**@}*/
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \brief Example of creating a WDXS stream.
*
* \return None.
*/
/*************************************************************************************************/
void wdxsStreamInit(void);
/*************************************************************************************************/
/*!
* \brief Changes the type of waveform transmitted by the stream.
*
* \param type - Identifier of the waveform
*
* \return None.
*/
/*************************************************************************************************/
void wdxsSetStreamWaveform(uint8_t type);
/*! \} */ /* WIRELESS_DATA_EXCHANGE_PROFILE */
#ifdef __cplusplus
}
#endif
#endif /* WDXS_STREAM_H */