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,113 @@
// ****************************************************************************
//
// amdtp_api.h
//! @file
//!
//! @brief Ambiq Micro's demonstration of AMDTP client.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef AMDTP_API_H
#define AMDTP_API_H
#include "wsf_os.h"
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \fn AmdtpcStart
*
* \brief Start the application.
*
* \return None.
*/
/*************************************************************************************************/
void AmdtpcStart(void);
/*************************************************************************************************/
/*!
* \fn AmdtpcHandlerInit
*
* \brief Application handler init function called during system initialization.
*
* \param handlerID WSF handler ID for App.
*
* \return None.
*/
/*************************************************************************************************/
void AmdtpcHandlerInit(wsfHandlerId_t handlerId);
/*************************************************************************************************/
/*!
* \fn AmdtpcHandler
*
* \brief WSF event handler for the application.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void AmdtpcHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
void AmdtpcScanStart(void);
void AmdtpcScanStop(void);
void AmdtpcConnOpen(uint8_t idx);
void AmdtpcSendTestData(void);
void AmdtpcSendTestDataStop(void);
void AmdtpcRequestServerSend(void);
void AmdtpcRequestServerSendStop(void);
#ifdef __cplusplus
};
#endif
#endif /* AMDTP_API_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,113 @@
// ****************************************************************************
//
// amdtp_api.h
//! @file
//!
//! @brief Ambiq Micro's demonstration of AMDTP service.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef AMDTP_API_H
#define AMDTP_API_H
#include "wsf_os.h"
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Macros
**************************************************************************************************/
#ifndef AMDTP_CONN_MAX
#define AMDTP_CONN_MAX 1
#endif
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \fn AmdtpStart
*
* \brief Start the application.
*
* \return None.
*/
/*************************************************************************************************/
void AmdtpStart(void);
/*************************************************************************************************/
/*!
* \fn AmdtpHandlerInit
*
* \brief Application handler init function called during system initialization.
*
* \param handlerID WSF handler ID for App.
*
* \return None.
*/
/*************************************************************************************************/
void AmdtpHandlerInit(wsfHandlerId_t handlerId);
/*************************************************************************************************/
/*!
* \fn AmdtpHandler
*
* \brief WSF event handler for the application.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void AmdtpHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
#ifdef __cplusplus
};
#endif
#endif /* AMDTP_API_H */
@@ -0,0 +1,845 @@
// ****************************************************************************
//
// amdtp_main.c
//! @file
//!
//! @brief Ambiq Micro's demonstration of AMDTP service.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include <string.h>
#include "wsf_types.h"
#include "bstream.h"
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "hci_api.h"
#include "dm_api.h"
#include "att_api.h"
#include "smp_api.h"
#include "app_api.h"
#include "app_db.h"
#include "app_ui.h"
#include "app_hw.h"
#include "svc_ch.h"
#include "svc_core.h"
#include "svc_dis.h"
#include "amdtp_api.h"
#include "amdtps_api.h"
#include "svc_amdtp.h"
#include "am_util.h"
#include "gatt_api.h"
/**************************************************************************************************
Macros
**************************************************************************************************/
#define MEASURE_THROUGHPUT
/*! WSF message event starting value */
#define AMDTP_MSG_START 0xA0
/*! WSF message event enumeration */
enum
{
AMDTP_TIMER_IND = AMDTP_MSG_START, /*! AMDTP tx timeout timer expired */
#ifdef MEASURE_THROUGHPUT
AMDTP_MEAS_TP_TIMER_IND,
#endif
};
/**************************************************************************************************
Data Types
**************************************************************************************************/
/*! Application message type */
typedef union
{
wsfMsgHdr_t hdr;
dmEvt_t dm;
attsCccEvt_t ccc;
attEvt_t att;
} amdtpMsg_t;
static void amdtpClose(amdtpMsg_t *pMsg);
/**************************************************************************************************
Configurable Parameters
**************************************************************************************************/
/*! configurable parameters for advertising */
static const appAdvCfg_t amdtpAdvCfg =
{
{60000, 0, 0}, /*! Advertising durations in ms */
{ 800, 800, 0} /*! Advertising intervals in 0.625 ms units */
};
/*! configurable parameters for slave */
static const appSlaveCfg_t amdtpSlaveCfg =
{
AMDTP_CONN_MAX, /*! Maximum connections */
};
/*! configurable parameters for security */
static const appSecCfg_t amdtpSecCfg =
{
DM_AUTH_BOND_FLAG | DM_AUTH_SC_FLAG, /*! Authentication and bonding flags */
0, /*! Initiator key distribution flags */
DM_KEY_DIST_LTK, /*! Responder key distribution flags */
FALSE, /*! TRUE if Out-of-band pairing data is present */
FALSE /*! TRUE to initiate security upon connection */
};
/*! configurable parameters for AMDTP connection parameter update */
static const appUpdateCfg_t amdtpUpdateCfg =
{
3000, /*! Connection idle period in ms before attempting
connection parameter update; set to zero to disable */
/* W/A: Apollo2-Blue has issues with interval 7.5ms */
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
6, /*! 7.5ms */
15, /*! 18.75ms */
#else
8,
18,
#endif
0, /*! Connection latency */
600, /*! Supervision timeout in 10ms units */
5 /*! Number of update attempts before giving up */
};
/*! SMP security parameter configuration */
static const smpCfg_t amdtpSmpCfg =
{
3000, /*! 'Repeated attempts' timeout in msec */
SMP_IO_NO_IN_NO_OUT, /*! I/O Capability */
7, /*! Minimum encryption key length */
16, /*! Maximum encryption key length */
3, /*! Attempts to trigger 'repeated attempts' timeout */
0, /*! Device authentication requirements */
};
/*! AMDTPS configuration */
static const AmdtpsCfg_t amdtpAmdtpsCfg =
{
0
};
/**************************************************************************************************
Advertising Data
**************************************************************************************************/
/*! advertising data, discoverable mode */
static const uint8_t amdtpAdvDataDisc[] =
{
/*! flags */
2, /*! length */
DM_ADV_TYPE_FLAGS, /*! AD type */
DM_FLAG_LE_GENERAL_DISC | /*! flags */
DM_FLAG_LE_BREDR_NOT_SUP,
/*! tx power */
2, /*! length */
DM_ADV_TYPE_TX_POWER, /*! AD type */
0, /*! tx power */
/*! service UUID list */
3, /*! length */
DM_ADV_TYPE_16_UUID, /*! AD type */
UINT16_TO_BYTES(ATT_UUID_DEVICE_INFO_SERVICE),
17, /*! length */
DM_ADV_TYPE_128_UUID, /*! AD type */
ATT_UUID_AMDTP_SERVICE
};
/*! scan data, discoverable mode */
static const uint8_t amdtpScanDataDisc[] =
{
/*! device name */
6, /*! length */
DM_ADV_TYPE_LOCAL_NAME, /*! AD type */
'A',
'm',
'd',
't',
'p'
};
/**************************************************************************************************
Client Characteristic Configuration Descriptors
**************************************************************************************************/
/*! enumeration of client characteristic configuration descriptors */
enum
{
AMDTP_GATT_SC_CCC_IDX, /*! GATT service, service changed characteristic */
AMDTP_AMDTPS_TX_CCC_IDX, /*! AMDTP service, tx characteristic */
AMDTP_AMDTPS_RX_ACK_CCC_IDX, /*! AMDTP service, rx ack characteristic */
AMDTP_NUM_CCC_IDX
};
/*! client characteristic configuration descriptors settings, indexed by above enumeration */
static const attsCccSet_t amdtpCccSet[AMDTP_NUM_CCC_IDX] =
{
/* cccd handle value range security level */
{GATT_SC_CH_CCC_HDL, ATT_CLIENT_CFG_INDICATE, DM_SEC_LEVEL_NONE}, /* AMDTP_GATT_SC_CCC_IDX */
{AMDTPS_TX_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE}, /* AMDTP_AMDTPS_TX_CCC_IDX */
{AMDTPS_ACK_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE} /* AMDTP_AMDTPS_RX_ACK_CCC_IDX */
};
/**************************************************************************************************
Global Variables
**************************************************************************************************/
/*! WSF handler ID */
wsfHandlerId_t amdtpHandlerId;
#ifdef MEASURE_THROUGHPUT
wsfTimer_t measTpTimer;
int gTotalDataBytesRecev = 0;
#endif
/*************************************************************************************************/
/*!
* \fn amdtpDmCback
*
* \brief Application DM callback.
*
* \param pDmEvt DM callback event
*
* \return None.
*/
/*************************************************************************************************/
static void amdtpDmCback(dmEvt_t *pDmEvt)
{
dmEvt_t *pMsg;
uint16_t len;
len = DmSizeOfEvt(pDmEvt);
if ((pMsg = WsfMsgAlloc(len)) != NULL)
{
memcpy(pMsg, pDmEvt, len);
WsfMsgSend(amdtpHandlerId, pMsg);
}
}
/*************************************************************************************************/
/*!
* \fn amdtpAttCback
*
* \brief Application ATT callback.
*
* \param pEvt ATT callback event
*
* \return None.
*/
/*************************************************************************************************/
static void amdtpAttCback(attEvt_t *pEvt)
{
attEvt_t *pMsg;
if ((pMsg = WsfMsgAlloc(sizeof(attEvt_t) + pEvt->valueLen)) != NULL)
{
memcpy(pMsg, pEvt, sizeof(attEvt_t));
pMsg->pValue = (uint8_t *) (pMsg + 1);
memcpy(pMsg->pValue, pEvt->pValue, pEvt->valueLen);
WsfMsgSend(amdtpHandlerId, pMsg);
}
}
/*************************************************************************************************/
/*!
* \fn amdtpCccCback
*
* \brief Application ATTS client characteristic configuration callback.
*
* \param pDmEvt DM callback event
*
* \return None.
*/
/*************************************************************************************************/
static void amdtpCccCback(attsCccEvt_t *pEvt)
{
attsCccEvt_t *pMsg;
appDbHdl_t dbHdl;
/* if CCC not set from initialization and there's a device record */
if ((pEvt->handle != ATT_HANDLE_NONE) &&
((dbHdl = AppDbGetHdl((dmConnId_t) pEvt->hdr.param)) != APP_DB_HDL_NONE))
{
/* store value in device database */
AppDbSetCccTblValue(dbHdl, pEvt->idx, pEvt->value);
}
if ((pMsg = WsfMsgAlloc(sizeof(attsCccEvt_t))) != NULL)
{
memcpy(pMsg, pEvt, sizeof(attsCccEvt_t));
WsfMsgSend(amdtpHandlerId, pMsg);
}
}
static bool sendDataContinuously = false;
static uint32_t counter = 0;
static void AmdtpsSendTestData(void)
{
uint8_t data[1024] = {0};
eAmdtpStatus_t status;
sendDataContinuously = true;
*((uint32_t*)&(data[0])) = counter;
// status = AmdtpsSendPacket(AMDTP_PKT_TYPE_DATA, false, true, data, sizeof(data));
status = AmdtpsSendPacket(AMDTP_PKT_TYPE_DATA, false, false, data, AttGetMtu(1) - 11); //fixme
if (status != AMDTP_STATUS_SUCCESS)
{
APP_TRACE_INFO1("AmdtpsSendTestData() failed, status = %d\n", status);
}
else
{
counter++;
}
}
/*************************************************************************************************/
/*!
* \fn amdtpProcCccState
*
* \brief Process CCC state change.
*
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
bool bPairingCompleted = false;
static void amdtpProcCccState(amdtpMsg_t *pMsg)
{
APP_TRACE_INFO3("ccc state ind value:%d handle:%d idx:%d", pMsg->ccc.value, pMsg->ccc.handle, pMsg->ccc.idx);
/* AMDTPS TX CCC */
if (pMsg->ccc.idx == AMDTP_AMDTPS_TX_CCC_IDX)
{
if (pMsg->ccc.value == ATT_CLIENT_CFG_NOTIFY)
{
// notify enabled
amdtps_start((dmConnId_t)pMsg->ccc.hdr.param, AMDTP_TIMER_IND, AMDTP_AMDTPS_TX_CCC_IDX);
// AppSlaveSecurityeq(1);
// if(bPairingCompleted == true)
{
#if defined(AMDTPS_TXTEST)
counter = 0;
AmdtpsSendTestData(); //fixme
#endif
}
}
else
{
// notify disabled
amdtpClose(pMsg);
amdtps_stop((dmConnId_t)pMsg->ccc.hdr.param);
}
return;
}
}
/*************************************************************************************************/
/*!
* \fn amdtpClose
*
* \brief Perform UI actions on connection close.
*
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
static void amdtpClose(amdtpMsg_t *pMsg)
{
}
/*************************************************************************************************/
/*!
* \fn amdtpSetup
*
* \brief Set up advertising and other procedures that need to be performed after
* device reset.
*
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
static void amdtpSetup(amdtpMsg_t *pMsg)
{
/* set advertising and scan response data for discoverable mode */
AppAdvSetData(APP_ADV_DATA_DISCOVERABLE, sizeof(amdtpAdvDataDisc), (uint8_t *) amdtpAdvDataDisc);
AppAdvSetData(APP_SCAN_DATA_DISCOVERABLE, sizeof(amdtpScanDataDisc), (uint8_t *) amdtpScanDataDisc);
/* set advertising and scan response data for connectable mode */
AppAdvSetData(APP_ADV_DATA_CONNECTABLE, sizeof(amdtpAdvDataDisc), (uint8_t *) amdtpAdvDataDisc);
AppAdvSetData(APP_SCAN_DATA_CONNECTABLE, sizeof(amdtpScanDataDisc), (uint8_t *) amdtpScanDataDisc);
/* start advertising; automatically set connectable/discoverable mode and bondable mode */
AppAdvStart(APP_MODE_AUTO_INIT);
}
/*************************************************************************************************/
/*!
* \fn amdtpBtnCback
*
* \brief Button press callback.
*
* \param btn Button press.
*
* \return None.
*/
/*************************************************************************************************/
static void amdtpBtnCback(uint8_t btn)
{
dmConnId_t connId;
/* button actions when connected */
if ((connId = AppConnIsOpen()) != DM_CONN_ID_NONE)
{
switch (btn)
{
case APP_UI_BTN_1_SHORT:
break;
case APP_UI_BTN_1_MED:
break;
case APP_UI_BTN_1_LONG:
AppConnClose(connId);
break;
case APP_UI_BTN_2_SHORT:
break;
default:
break;
}
}
/* button actions when not connected */
else
{
switch (btn)
{
case APP_UI_BTN_1_SHORT:
/* start or restart advertising */
AppAdvStart(APP_MODE_AUTO_INIT);
break;
case APP_UI_BTN_1_MED:
/* enter discoverable and bondable mode mode */
AppSetBondable(TRUE);
AppAdvStart(APP_MODE_DISCOVERABLE);
break;
case APP_UI_BTN_1_LONG:
/* clear bonded device info and restart advertising */
AppDbDeleteAllRecords();
AppAdvStart(APP_MODE_AUTO_INIT);
break;
default:
break;
}
}
}
#ifdef MEASURE_THROUGHPUT
static void showThroughput(void)
{
APP_TRACE_INFO1("throughput : %d Bytes/s\n", gTotalDataBytesRecev);
gTotalDataBytesRecev = 0;
WsfTimerStartSec(&measTpTimer, 1);
}
#endif
/*************************************************************************************************/
/*!
* \fn amdtpProcMsg
*
* \brief Process messages from the event handler.
*
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
static void amdtpProcMsg(amdtpMsg_t *pMsg)
{
uint8_t uiEvent = APP_UI_NONE;
switch(pMsg->hdr.event)
{
case AMDTP_TIMER_IND:
amdtps_proc_msg(&pMsg->hdr);
break;
#ifdef MEASURE_THROUGHPUT
case AMDTP_MEAS_TP_TIMER_IND:
showThroughput();
break;
#endif
case ATTS_HANDLE_VALUE_CNF:
//APP_TRACE_INFO1("ATTS_HANDLE_VALUE_CNF, status = %d", pMsg->att.hdr.status);
amdtps_proc_msg(&pMsg->hdr);
break;
case ATTS_CCC_STATE_IND:
amdtpProcCccState(pMsg);
break;
case ATT_MTU_UPDATE_IND:
APP_TRACE_INFO1("Negotiated MTU %d", ((attEvt_t *)pMsg)->mtu);
break;
case DM_CONN_DATA_LEN_CHANGE_IND:
APP_TRACE_INFO2("DM_CONN_DATA_LEN_CHANGE_IND, Tx=%d, Rx=%d", ((hciLeDataLenChangeEvt_t*)pMsg)->maxTxOctets, ((hciLeDataLenChangeEvt_t*)pMsg)->maxRxOctets);
//AttcMtuReq((dmConnId_t)(pMsg->hdr.param), 480);//ATT_MAX_MTU);//83); //fixme
break;
case DM_RESET_CMPL_IND:
AttsCalculateDbHash();
DmSecGenerateEccKeyReq();
amdtpSetup(pMsg);
uiEvent = APP_UI_RESET_CMPL;
break;
case DM_ADV_START_IND:
uiEvent = APP_UI_ADV_START;
break;
case DM_ADV_STOP_IND:
uiEvent = APP_UI_ADV_STOP;
break;
case DM_CONN_OPEN_IND:
amdtps_proc_msg(&pMsg->hdr);
// AttcMtuReq((dmConnId_t)(pMsg->hdr.param), ATT_MAX_MTU);//83); //fixme
// hciConnSpec_t connSpec;
// connSpec.connIntervalMin = (7.5/1.25);
// connSpec.connIntervalMax = (15/1.25);
// connSpec.connLatency = 0;
// connSpec.supTimeout = 200;
// connSpec.minCeLen = 4;//0;
// connSpec.maxCeLen = 8;//0xffff; //fixme
// DmConnUpdate(1, &connSpec);
// PDU length, TX interval (0x148 ~ 0x848)
//DmConnSetDataLen(1, 27, 0x148);
DmConnSetDataLen(1, 251, 0x848);
// AppSlaveSecurityReq(1);
uiEvent = APP_UI_CONN_OPEN;
break;
case DM_CONN_CLOSE_IND:
amdtpClose(pMsg);
amdtps_proc_msg(&pMsg->hdr);
APP_TRACE_INFO1("DM_CONN_CLOSE_IND, reason = 0x%x", pMsg->dm.connClose.reason);
uiEvent = APP_UI_CONN_CLOSE;
break;
case DM_CONN_UPDATE_IND:
amdtps_proc_msg(&pMsg->hdr);
break;
case DM_SEC_PAIR_CMPL_IND:
DmSecGenerateEccKeyReq();
uiEvent = APP_UI_SEC_PAIR_CMPL;
bPairingCompleted = true;
break;
case DM_SEC_PAIR_FAIL_IND:
DmSecGenerateEccKeyReq();
APP_TRACE_INFO1("DM_SEC_PAIR_FAIL_IND, status = 0x%x", pMsg->dm.pairCmpl.hdr.status);
bPairingCompleted = false;
uiEvent = APP_UI_SEC_PAIR_FAIL;
break;
case DM_SEC_ENCRYPT_IND:
uiEvent = APP_UI_SEC_ENCRYPT;
break;
case DM_SEC_ENCRYPT_FAIL_IND:
uiEvent = APP_UI_SEC_ENCRYPT_FAIL;
break;
case DM_SEC_AUTH_REQ_IND:
AppHandlePasskey(&pMsg->dm.authReq);
break;
case DM_SEC_ECC_KEY_IND:
DmSecSetEccKey(&pMsg->dm.eccMsg.data.key);
break;
case DM_SEC_COMPARE_IND:
AppHandleNumericComparison(&pMsg->dm.cnfInd);
break;
case DM_HW_ERROR_IND:
uiEvent = APP_UI_HW_ERROR;
break;
case DM_VENDOR_SPEC_CMD_CMPL_IND:
{
#if defined(AM_PART_APOLLO) || defined(AM_PART_APOLLO2)
uint8_t *param_ptr = &pMsg->dm.vendorSpecCmdCmpl.param[0];
switch (pMsg->dm.vendorSpecCmdCmpl.opcode)
{
case 0xFC20: //read at address
{
uint32_t read_value;
BSTREAM_TO_UINT32(read_value, param_ptr);
APP_TRACE_INFO3("VSC 0x%0x complete status %x param %x",
pMsg->dm.vendorSpecCmdCmpl.opcode,
pMsg->hdr.status,
read_value);
}
break;
default:
APP_TRACE_INFO2("VSC 0x%0x complete status %x",
pMsg->dm.vendorSpecCmdCmpl.opcode,
pMsg->hdr.status);
break;
}
#endif
}
break;
default:
break;
}
if (uiEvent != APP_UI_NONE)
{
AppUiAction(uiEvent);
}
}
//
//static void AmdtpsSendTestData(void)
//{
// static uint8_t counter = 0;
// uint8_t data[236] = {0};
// eAmdtpStatus_t status;
//
// sendDataContinuously = true;
// data[1] = counter;
// status = AmdtpsSendPacket(AMDTP_PKT_TYPE_DATA, false, true, data, sizeof(data));
// if (status != AMDTP_STATUS_SUCCESS)
// {
// APP_TRACE_INFO1("AmdtpsSendTestData() failed, status = %d\n", status);
// }
// else
// {
// counter++;
// }
//}
void amdtpDtpRecvCback(uint8_t * buf, uint16_t len)
{
#ifdef MEASURE_THROUGHPUT
static bool measTpStarted = false;
#endif
#if 0
// reception callback
// print the received data
APP_TRACE_INFO0("-----------AMDTP Received data--------------\n");
APP_TRACE_INFO3("len = %d, buf[0] = %d, buf[1] = %d\n", len, buf[0], buf[1]);
#endif
if (buf[0] == 1)
{
APP_TRACE_INFO0("send test data\n");
AmdtpsSendTestData();
}
else if (buf[0] == 2)
{
APP_TRACE_INFO0("send test data stop\n");
sendDataContinuously = false;
}
#ifdef MEASURE_THROUGHPUT
gTotalDataBytesRecev += len;
if (!measTpStarted)
{
measTpStarted = true;
WsfTimerStartSec(&measTpTimer, 1);
}
#endif
}
void amdtpDtpTransCback(eAmdtpStatus_t status)
{
// APP_TRACE_INFO1("amdtpDtpTransCback status = %d\n", status);
if (status == AMDTP_STATUS_SUCCESS && sendDataContinuously)
{
AmdtpsSendTestData();
}
}
/*************************************************************************************************/
/*!
* \fn AmdtpHandlerInit
*
* \brief Application handler init function called during system initialization.
*
* \param handlerID WSF handler ID.
*
* \return None.
*/
/*************************************************************************************************/
void AmdtpHandlerInit(wsfHandlerId_t handlerId)
{
APP_TRACE_INFO0("AmdtpHandlerInit");
/* store handler ID */
amdtpHandlerId = handlerId;
/* Set configuration pointers */
pAppAdvCfg = (appAdvCfg_t *) &amdtpAdvCfg;
pAppSlaveCfg = (appSlaveCfg_t *) &amdtpSlaveCfg;
pAppSecCfg = (appSecCfg_t *) &amdtpSecCfg;
pAppUpdateCfg = (appUpdateCfg_t *) &amdtpUpdateCfg;
/* Initialize application framework */
AppSlaveInit();
AppServerInit();
/* Set stack configuration pointers */
pSmpCfg = (smpCfg_t *) &amdtpSmpCfg;
/* initialize amdtp service server */
amdtps_init(handlerId, (AmdtpsCfg_t *) &amdtpAmdtpsCfg, amdtpDtpRecvCback, amdtpDtpTransCback);
#ifdef MEASURE_THROUGHPUT
measTpTimer.handlerId = handlerId;
measTpTimer.msg.event = AMDTP_MEAS_TP_TIMER_IND;
#endif
}
/*************************************************************************************************/
/*!
* \fn AmdtpHandler
*
* \brief WSF event handler for application.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void AmdtpHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
{
if (pMsg != NULL)
{
// APP_TRACE_INFO1("Amdtp got evt %d", pMsg->event);
/* process ATT messages */
if (pMsg->event >= ATT_CBACK_START && pMsg->event <= ATT_CBACK_END)
{
/* process server-related ATT messages */
AppServerProcAttMsg(pMsg);
}
/* process DM messages */
else if (pMsg->event >= DM_CBACK_START && pMsg->event <= DM_CBACK_END)
{
/* process advertising and connection-related messages */
AppSlaveProcDmMsg((dmEvt_t *) pMsg);
/* process security-related messages */
AppSlaveSecProcDmMsg((dmEvt_t *) pMsg);
}
/* perform profile and user interface-related operations */
amdtpProcMsg((amdtpMsg_t *) pMsg);
}
}
/*************************************************************************************************/
/*!
* \fn AmdtpStart
*
* \brief Start the application.
*
* \return None.
*/
/*************************************************************************************************/
void AmdtpStart(void)
{
/* Register for stack callbacks */
DmRegister(amdtpDmCback);
DmConnRegister(DM_CLIENT_ID_APP, amdtpDmCback);
AttRegister(amdtpAttCback);
AttConnRegister(AppServerConnCback);
AttsCccRegister(AMDTP_NUM_CCC_IDX, (attsCccSet_t *) amdtpCccSet, amdtpCccCback);
/* Register for app framework callbacks */
AppUiBtnRegister(amdtpBtnCback);
/* Initialize attribute server database */
SvcCoreGattCbackRegister(GattReadCback, GattWriteCback);
SvcCoreAddGroup();
SvcDisAddGroup();
SvcAmdtpsCbackRegister(NULL, amdtps_write_cback);
SvcAmdtpsAddGroup();
/* Set Service Changed CCCD index. */
GattSetSvcChangedIdx(AMDTP_GATT_SC_CCC_IDX);
/* Reset the device */
DmDevReset();
}
@@ -0,0 +1,113 @@
// ****************************************************************************
//
// amota_api.h
//! @file
//!
//! @brief Ambiq Micro's demonstration of AMOTA service.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef AMOTA_API_H
#define AMOTA_API_H
#include "wsf_os.h"
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Macros
**************************************************************************************************/
#ifndef AMOTA_CONN_MAX
#define AMOTA_CONN_MAX 1
#endif
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \fn AmotaStart
*
* \brief Start the application.
*
* \return None.
*/
/*************************************************************************************************/
void AmotaStart(void);
/*************************************************************************************************/
/*!
* \fn AmotaHandlerInit
*
* \brief Application handler init function called during system initialization.
*
* \param handlerID WSF handler ID for App.
*
* \return None.
*/
/*************************************************************************************************/
void AmotaHandlerInit(wsfHandlerId_t handlerId);
/*************************************************************************************************/
/*!
* \fn AmotaHandler
*
* \brief WSF event handler for the application.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void AmotaHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
#ifdef __cplusplus
};
#endif
#endif /* AMOTA_API_H */
@@ -0,0 +1,693 @@
// ****************************************************************************
//
// amota_main.c
//! @file
//!
//! @brief Ambiq Micro's demonstration of AMOTA service.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include <string.h>
#include "wsf_types.h"
#include "bstream.h"
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "hci_api.h"
#include "dm_api.h"
#include "att_api.h"
#include "app_api.h"
#include "app_db.h"
#include "app_ui.h"
#include "app_hw.h"
#include "svc_ch.h"
#include "svc_core.h"
#include "svc_dis.h"
#include "amota_api.h"
#include "amotas_api.h"
#include "svc_amotas.h"
#include "gatt_api.h"
/**************************************************************************************************
Macros
**************************************************************************************************/
/*! WSF message event starting value */
#define AMOTA_MSG_START 0xA0
/*! WSF message event enumeration */
enum
{
AMOTA_RESET_TIMER_IND = AMOTA_MSG_START, /*! AMOTA reset timer expired */
AMOTA_DISCONNECT_TIMER_IND, /*! AMOTA disconnect timer expired */
};
/**************************************************************************************************
Data Types
**************************************************************************************************/
/*! Application message type */
typedef union
{
wsfMsgHdr_t hdr;
dmEvt_t dm;
attsCccEvt_t ccc;
attEvt_t att;
} amotaMsg_t;
/**************************************************************************************************
Configurable Parameters
**************************************************************************************************/
/*! configurable parameters for advertising */
static const appAdvCfg_t amotaAdvCfg =
{
{ 0, 0, 0}, /*! Advertising durations in ms */
{ 800, 800, 0} /*! Advertising intervals in 0.625 ms units */
};
/*! configurable parameters for slave */
static const appSlaveCfg_t amotaSlaveCfg =
{
AMOTA_CONN_MAX, /*! Maximum connections */
};
/*! configurable parameters for security */
static const appSecCfg_t amotaSecCfg =
{
DM_AUTH_BOND_FLAG, /*! Authentication and bonding flags */
0, /*! Initiator key distribution flags */
DM_KEY_DIST_LTK, /*! Responder key distribution flags */
FALSE, /*! TRUE if Out-of-band pairing data is present */
FALSE /*! TRUE to initiate security upon connection */
};
/*! configurable parameters for AMOTA connection parameter update */
static appUpdateCfg_t otaUpdateCfg =
{
0, /*! Connection idle period in ms before attempting
connection parameter update; set to zero to disable */
(15 / 1.25), /*! 15 ms */
(30 / 1.25), /*! 30 ms */
0, /*! Connection latency */
(6000 / 10), /*! Supervision timeout in 10ms units */
5 /*! Number of update attempts before giving up */
};
/*! AMOTAS configuration */
static const AmotasCfg_t amotasCfg =
{
0
};
/**************************************************************************************************
Advertising Data
**************************************************************************************************/
/*! advertising data, discoverable mode */
static const uint8_t amotaAdvDataDisc[] =
{
/*! flags */
2, /*! length */
DM_ADV_TYPE_FLAGS, /*! AD type */
DM_FLAG_LE_GENERAL_DISC | /*! flags */
DM_FLAG_LE_BREDR_NOT_SUP,
/*! tx power */
2, /*! length */
DM_ADV_TYPE_TX_POWER, /*! AD type */
0, /*! tx power */
/*! service UUID list */
3, /*! length */
DM_ADV_TYPE_16_UUID, /*! AD type */
UINT16_TO_BYTES(ATT_UUID_DEVICE_INFO_SERVICE)
};
/*! scan data, discoverable mode */
static const uint8_t amotaScanDataDisc[] =
{
/*! device name */
15, /*! length */
DM_ADV_TYPE_LOCAL_NAME, /*! AD type */
'a',
'm',
'b',
'i',
'q',
'm',
'i',
'c',
'r',
'o',
' ',
'o',
't',
'a'
};
/**************************************************************************************************
Client Characteristic Configuration Descriptors
**************************************************************************************************/
/*! enumeration of client characteristic configuration descriptors */
enum
{
AMOTA_GATT_SC_CCC_IDX, /*! GATT service, service changed characteristic */
AMOTA_AMOTAS_TX_CCC_IDX, /*! AMOTA service, tx characteristic */
AMOTA_NUM_CCC_IDX
};
/*! client characteristic configuration descriptors settings, indexed by above enumeration */
static const attsCccSet_t amotaCccSet[AMOTA_NUM_CCC_IDX] =
{
/* cccd handle value range security level */
{GATT_SC_CH_CCC_HDL, ATT_CLIENT_CFG_INDICATE, DM_SEC_LEVEL_NONE}, /* AMOTA_GATT_SC_CCC_IDX */
{AMOTAS_TX_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE} /* AMOTA_AMOTAS_TX_CCC_IDX */
};
/**************************************************************************************************
Global Variables
**************************************************************************************************/
/*! WSF handler ID */
wsfHandlerId_t amotaHandlerId;
/*************************************************************************************************/
/*!
* \fn amotaDmCback
*
* \brief Application DM callback.
*
* \param pDmEvt DM callback event
*
* \return None.
*/
/*************************************************************************************************/
static void amotaDmCback(dmEvt_t *pDmEvt)
{
dmEvt_t *pMsg;
if ((pMsg = WsfMsgAlloc(sizeof(dmEvt_t))) != NULL)
{
memcpy(pMsg, pDmEvt, sizeof(dmEvt_t));
WsfMsgSend(amotaHandlerId, pMsg);
}
}
/*************************************************************************************************/
/*!
* \fn amotaAttCback
*
* \brief Application ATT callback.
*
* \param pEvt ATT callback event
*
* \return None.
*/
/*************************************************************************************************/
static void amotaAttCback(attEvt_t *pEvt)
{
attEvt_t *pMsg;
if ((pMsg = WsfMsgAlloc(sizeof(attEvt_t) + pEvt->valueLen)) != NULL)
{
memcpy(pMsg, pEvt, sizeof(attEvt_t));
pMsg->pValue = (uint8_t *) (pMsg + 1);
memcpy(pMsg->pValue, pEvt->pValue, pEvt->valueLen);
WsfMsgSend(amotaHandlerId, pMsg);
}
}
/*************************************************************************************************/
/*!
* \fn amotaCccCback
*
* \brief Application ATTS client characteristic configuration callback.
*
* \param pDmEvt DM callback event
*
* \return None.
*/
/*************************************************************************************************/
static void amotaCccCback(attsCccEvt_t *pEvt)
{
attsCccEvt_t *pMsg;
appDbHdl_t dbHdl;
/* if CCC not set from initialization and there's a device record */
if ((pEvt->handle != ATT_HANDLE_NONE) &&
((dbHdl = AppDbGetHdl((dmConnId_t) pEvt->hdr.param)) != APP_DB_HDL_NONE))
{
/* store value in device database */
AppDbSetCccTblValue(dbHdl, pEvt->idx, pEvt->value);
}
if ((pMsg = WsfMsgAlloc(sizeof(attsCccEvt_t))) != NULL)
{
memcpy(pMsg, pEvt, sizeof(attsCccEvt_t));
WsfMsgSend(amotaHandlerId, pMsg);
}
}
/*************************************************************************************************/
/*!
* \fn amotaProcCccState
*
* \brief Process CCC state change.
*
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
static void amotaProcCccState(amotaMsg_t *pMsg)
{
APP_TRACE_INFO3("ccc state ind value:%d handle:%d idx:%d", pMsg->ccc.value, pMsg->ccc.handle, pMsg->ccc.idx);
/* handle heart rate measurement CCC */
/* AMOTAS TX CCC */
if (pMsg->ccc.idx == AMOTA_AMOTAS_TX_CCC_IDX)
{
if (pMsg->ccc.value == ATT_CLIENT_CFG_NOTIFY)
{
// notify enabled
amotas_start((dmConnId_t) pMsg->ccc.hdr.param,
AMOTA_RESET_TIMER_IND, AMOTA_DISCONNECT_TIMER_IND,
AMOTA_AMOTAS_TX_CCC_IDX);
}
else
{
// notify disabled
amotas_stop((dmConnId_t) pMsg->ccc.hdr.param);
}
return;
}
}
/*************************************************************************************************/
/*!
* \fn amotaClose
*
* \brief Perform UI actions on connection close.
*
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
static void amotaClose(amotaMsg_t *pMsg)
{
/* stop amotas */
amotas_conn_close((dmConnId_t) pMsg->hdr.param);
}
/*************************************************************************************************/
/*!
* \fn amotaSetup
*
* \brief Set up advertising and other procedures that need to be performed after
* device reset.
*
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
static void amotaSetup(amotaMsg_t *pMsg)
{
/* set advertising and scan response data for discoverable mode */
AppAdvSetData(APP_ADV_DATA_DISCOVERABLE, sizeof(amotaAdvDataDisc), (uint8_t *) amotaAdvDataDisc);
AppAdvSetData(APP_SCAN_DATA_DISCOVERABLE, sizeof(amotaScanDataDisc), (uint8_t *) amotaScanDataDisc);
/* set advertising and scan response data for connectable mode */
AppAdvSetData(APP_ADV_DATA_CONNECTABLE, 0, NULL);
AppAdvSetData(APP_SCAN_DATA_CONNECTABLE, 0, NULL);
/* start advertising; automatically set connectable/discoverable mode and bondable mode */
AppAdvStart(APP_MODE_AUTO_INIT);
}
/*************************************************************************************************/
/*!
* \fn amotaBtnCback
*
* \brief Button press callback.
*
* \param btn Button press.
*
* \return None.
*/
/*************************************************************************************************/
static void amotaBtnCback(uint8_t btn)
{
dmConnId_t connId;
/* button actions when connected */
if ((connId = AppConnIsOpen()) != DM_CONN_ID_NONE)
{
switch (btn)
{
case APP_UI_BTN_1_SHORT:
break;
case APP_UI_BTN_1_MED:
break;
case APP_UI_BTN_1_LONG:
AppConnClose(connId);
break;
case APP_UI_BTN_2_SHORT:
break;
default:
break;
}
}
/* button actions when not connected */
else
{
switch (btn)
{
case APP_UI_BTN_1_SHORT:
/* start or restart advertising */
AppAdvStart(APP_MODE_AUTO_INIT);
break;
case APP_UI_BTN_1_MED:
/* enter discoverable and bondable mode mode */
AppSetBondable(TRUE);
AppAdvStart(APP_MODE_DISCOVERABLE);
break;
case APP_UI_BTN_1_LONG:
/* clear bonded device info and restart advertising */
AppDbDeleteAllRecords();
AppAdvStart(APP_MODE_AUTO_INIT);
break;
default:
break;
}
}
}
/*************************************************************************************************/
/*!
* \fn amotaProcMsg
*
* \brief Process messages from the event handler.
*
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
static void amotaProcMsg(amotaMsg_t *pMsg)
{
uint8_t uiEvent = APP_UI_NONE;
switch(pMsg->hdr.event)
{
case AMOTA_RESET_TIMER_IND:
case AMOTA_DISCONNECT_TIMER_IND:
amotas_proc_msg(&pMsg->hdr);
break;
case ATTS_HANDLE_VALUE_CNF:
break;
case ATTS_CCC_STATE_IND:
amotaProcCccState(pMsg);
break;
case ATT_MTU_UPDATE_IND:
APP_TRACE_INFO1("Negotiated MTU %d", ((attEvt_t *)pMsg)->mtu);
break;
case DM_RESET_CMPL_IND:
AttsCalculateDbHash();
DmSecGenerateEccKeyReq();
amotaSetup(pMsg);
uiEvent = APP_UI_RESET_CMPL;
break;
case DM_ADV_SET_START_IND:
uiEvent = APP_UI_ADV_SET_START_IND;
break;
case DM_ADV_SET_STOP_IND:
uiEvent = APP_UI_ADV_SET_STOP_IND;
break;
case DM_ADV_START_IND:
uiEvent = APP_UI_ADV_START;
break;
case DM_ADV_STOP_IND:
uiEvent = APP_UI_ADV_STOP;
break;
case DM_CONN_OPEN_IND:
amotas_proc_msg(&pMsg->hdr);
uiEvent = APP_UI_CONN_OPEN;
break;
case DM_CONN_CLOSE_IND:
{
hciDisconnectCmplEvt_t *evt = (hciDisconnectCmplEvt_t*) pMsg;
// uiEvent = APP_UI_CONN_CLOSE;
APP_TRACE_INFO1(">>> Connection closed reason 0x%x <<<",
evt->reason);
amotaClose(pMsg);
}
break;
case DM_CONN_UPDATE_IND:
amotas_proc_msg(&pMsg->hdr);
break;
case DM_SEC_PAIR_CMPL_IND:
DmSecGenerateEccKeyReq();
uiEvent = APP_UI_SEC_PAIR_CMPL;
break;
case DM_SEC_PAIR_FAIL_IND:
DmSecGenerateEccKeyReq();
uiEvent = APP_UI_SEC_PAIR_FAIL;
break;
case DM_SEC_ENCRYPT_IND:
uiEvent = APP_UI_SEC_ENCRYPT;
break;
case DM_SEC_ENCRYPT_FAIL_IND:
uiEvent = APP_UI_SEC_ENCRYPT_FAIL;
break;
case DM_SEC_AUTH_REQ_IND:
AppHandlePasskey(&pMsg->dm.authReq);
break;
case DM_SEC_ECC_KEY_IND:
DmSecSetEccKey(&pMsg->dm.eccMsg.data.key);
break;
case DM_SEC_COMPARE_IND:
AppHandleNumericComparison(&pMsg->dm.cnfInd);
break;
case DM_PRIV_CLEAR_RES_LIST_IND:
APP_TRACE_INFO1("Clear resolving list status 0x%02x", pMsg->hdr.status);
break;
case DM_HW_ERROR_IND:
uiEvent = APP_UI_HW_ERROR;
break;
case DM_VENDOR_SPEC_CMD_CMPL_IND:
{
#if defined(AM_PART_APOLLO) || defined(AM_PART_APOLLO2)
uint8_t *param_ptr = &pMsg->dm.vendorSpecCmdCmpl.param[0];
switch (pMsg->dm.vendorSpecCmdCmpl.opcode)
{
case 0xFC20: //read at address
{
uint32_t read_value;
BSTREAM_TO_UINT32(read_value, param_ptr);
APP_TRACE_INFO3("VSC 0x%0x complete status %x param %x",
pMsg->dm.vendorSpecCmdCmpl.opcode,
pMsg->hdr.status,
read_value);
}
break;
default:
APP_TRACE_INFO2("VSC 0x%0x complete status %x",
pMsg->dm.vendorSpecCmdCmpl.opcode,
pMsg->hdr.status);
break;
}
#endif
}
break;
default:
break;
}
if (uiEvent != APP_UI_NONE)
{
AppUiAction(uiEvent);
}
}
/*************************************************************************************************/
/*!
* \fn AmotaHandlerInit
*
* \brief Application handler init function called during system initialization.
*
* \param handlerID WSF handler ID.
*
* \return None.
*/
/*************************************************************************************************/
void AmotaHandlerInit(wsfHandlerId_t handlerId)
{
APP_TRACE_INFO0("AmotaHandlerInit");
/* store handler ID */
amotaHandlerId = handlerId;
/* Set configuration pointers */
pAppAdvCfg = (appAdvCfg_t *) &amotaAdvCfg;
pAppSlaveCfg = (appSlaveCfg_t *) &amotaSlaveCfg;
pAppSecCfg = (appSecCfg_t *) &amotaSecCfg;
pAppUpdateCfg = (appUpdateCfg_t *) &otaUpdateCfg;
/* Initialize application framework */
AppSlaveInit();
AppServerInit();
/* initialize amota service server */
amotas_init(handlerId, (AmotasCfg_t *) &amotasCfg);
}
/*************************************************************************************************/
/*!
* \fn AmotaHandler
*
* \brief WSF event handler for application.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void AmotaHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
{
if (pMsg != NULL)
{
// APP_TRACE_INFO1("Amota got evt %d", pMsg->event);
/* process ATT messages */
if (pMsg->event >= ATT_CBACK_START && pMsg->event <= ATT_CBACK_END)
{
/* process server-related ATT messages */
AppServerProcAttMsg(pMsg);
}
/* process DM messages */
else if (pMsg->event >= DM_CBACK_START && pMsg->event <= DM_CBACK_END)
{
/* process advertising and connection-related messages */
AppSlaveProcDmMsg((dmEvt_t *) pMsg);
/* process security-related messages */
AppSlaveSecProcDmMsg((dmEvt_t *) pMsg);
}
/* perform profile and user interface-related operations */
amotaProcMsg((amotaMsg_t *) pMsg);
}
}
/*************************************************************************************************/
/*!
* \fn AmotaStart
*
* \brief Start the application.
*
* \return None.
*/
/*************************************************************************************************/
void AmotaStart(void)
{
/* Register for stack callbacks */
DmRegister(amotaDmCback);
DmConnRegister(DM_CLIENT_ID_APP, amotaDmCback);
AttRegister(amotaAttCback);
AttConnRegister(AppServerConnCback);
AttsCccRegister(AMOTA_NUM_CCC_IDX, (attsCccSet_t *) amotaCccSet, amotaCccCback);
/* Register for app framework callbacks */
AppUiBtnRegister(amotaBtnCback);
/* Initialize attribute server database */
SvcCoreGattCbackRegister(GattReadCback, GattWriteCback);
SvcCoreAddGroup();
SvcDisAddGroup();
SvcAmotasCbackRegister(NULL, amotas_write_cback);
SvcAmotasAddGroup();
/* Set Service Changed CCCD index. */
GattSetSvcChangedIdx(AMOTA_GATT_SC_CCC_IDX);
/* Reset the device */
DmDevReset();
}
@@ -0,0 +1,112 @@
// ****************************************************************************
//
// ancs_api.h
//! @file
//!
//! @brief Ambiq Micro's demonstration of ANCSC.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef ANCS_API_H
#define ANCS_API_H
#include "wsf_os.h"
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Macros
**************************************************************************************************/
#ifndef ANCS_CONN_MAX
#define ANCS_CONN_MAX 1
#endif
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \fn AncsStart
*
* \brief Start the application.
*
* \return None.
*/
/*************************************************************************************************/
void AncsStart(void);
/*************************************************************************************************/
/*!
* \fn AncsHandlerInit
*
* \brief Application handler init function called during system initialization.
*
* \param handlerID WSF handler ID for App.
*
* \return None.
*/
/*************************************************************************************************/
void AncsHandlerInit(wsfHandlerId_t handlerId);
/*************************************************************************************************/
/*!
* \fn AncsHandler
*
* \brief WSF event handler for the application.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void AncsHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
#ifdef __cplusplus
};
#endif
#endif /* ANCS_API_H */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,106 @@
// ****************************************************************************
//
// beaconscanner_api.h
//! @file
//!
//! @brief Beacon Scanner sample application interface
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef BEACONSCANNER_API_H
#define BEACONSCANNER_API_H
#include "wsf_os.h"
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \fn BeaconScannerStart
*
* \brief Start Beacon Scan application.
*
* \return None.
*/
/*************************************************************************************************/
void BeaconScannerStart(void);
/*************************************************************************************************/
/*!
* \fn BeaconScannerHandlerInit
*
* \brief Beacon Scan handler init function called during system initialization.
*
* \param handlerID WSF handler ID for App.
*
* \return None.
*/
/*************************************************************************************************/
void BeaconScannerHandlerInit(wsfHandlerId_t handlerId);
/*************************************************************************************************/
/*!
* \fn BeaconScannerHandler
*
* \brief WSF event handler for Beacon Scan application.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void BeaconScannerHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
#ifdef __cplusplus
};
#endif
#endif /* BEACONSCANNER_API_H */
@@ -0,0 +1,109 @@
// ****************************************************************************
//
// ibeacon_api.h
//! @file
//!
//! @brief Ambiq Micro iBeacon example
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef IBEACON_API_H
#define IBEACON_API_H
#include "wsf_os.h"
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Macros
**************************************************************************************************/
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \fn iBeaconStart
*
* \brief Start the application.
*
* \return None.
*/
/*************************************************************************************************/
void iBeaconStart(void);
/*************************************************************************************************/
/*!
* \fn iBeaconHandlerInit
*
* \brief Application handler init function called during system initialization.
*
* \param handlerID WSF handler ID for App.
*
* \return None.
*/
/*************************************************************************************************/
void iBeaconHandlerInit(wsfHandlerId_t handlerId);
/*************************************************************************************************/
/*!
* \fn iBeaconHandler
*
* \brief WSF event handler for the application.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void iBeaconHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
#ifdef __cplusplus
};
#endif
#endif /* IBEACON_API_H */
@@ -0,0 +1,331 @@
// ****************************************************************************
//
// ibeacon_main.c
//! @file
//!
//! @brief Ambiq Micro's demonstration of iBeacon.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include <string.h>
#include "wsf_types.h"
#include "bstream.h"
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "hci_api.h"
#include "dm_api.h"
#include "att_api.h"
#include "app_api.h"
#include "app_db.h"
#include "app_ui.h"
#include "app_hw.h"
#include "svc_ch.h"
#include "svc_core.h"
#include "svc_dis.h"
#include "ibeacon_api.h"
#include "gatt_api.h"
/**************************************************************************************************
Macros
**************************************************************************************************/
/*! WSF message event starting value */
#define IBEACON_MSG_START 0xA0
/*! WSF message event enumeration */
enum
{
IBEACON_TIMER_IND = IBEACON_MSG_START, /*! iBeacon reset timer expired */
};
/**************************************************************************************************
Data Types
**************************************************************************************************/
/*! Application message type */
typedef union
{
wsfMsgHdr_t hdr;
dmEvt_t dm;
} ibeaconMsg_t;
/**************************************************************************************************
Configurable Parameters
**************************************************************************************************/
/*! configurable parameters for advertising */
static const appAdvCfg_t ibeaconAdvCfg =
{
{60000, 0, 0}, /*! Advertising durations in ms */
{ 800, 800, 0} /*! Advertising intervals in 0.625 ms units */
};
/*! configurable parameters for slave */
static const appSlaveCfg_t ibeaconSlaveCfg =
{
1, /*! Maximum connections */
};
/*! configurable parameters for security */
static const appSecCfg_t ibeaconSecCfg =
{
DM_AUTH_BOND_FLAG, /*! Authentication and bonding flags */
0, /*! Initiator key distribution flags */
DM_KEY_DIST_LTK, /*! Responder key distribution flags */
FALSE, /*! TRUE if Out-of-band pairing data is present */
FALSE /*! TRUE to initiate security upon connection */
};
/**************************************************************************************************
Advertising Data
**************************************************************************************************/
/*! advertising data, discoverable mode */
static const uint8_t ibeaconAdvDataDisc[] =
{
/*! flags */
2, /*! length */
DM_ADV_TYPE_FLAGS, /*! AD type */
DM_FLAG_LE_GENERAL_DISC | /*! flags */
DM_FLAG_LE_BREDR_NOT_SUP,
/*! Manufacturer specific data AD type */
0x1A, /*! length */
DM_ADV_TYPE_MANUFACTURER, /*! AD type */
0x4C, /*! Company ID[0] */
0x00, /*! Company ID[1] */
0x02, /*! Device type, this has to be 0x02*/
0x15, /*! Length of vendor advertising data. */
/*! Proximity UUID 16 bytes */
0xe2, 0xc5, 0x6d, 0xb5,
0xdf, 0xfb, 0x48, 0xd2,
0xb0, 0x60, 0xd0, 0xf5,
0xa7, 0x10, 0x96, 0xe0,
/*! Major 0xnnnn */
0x00, 0x00,
/*! Minor 0xnnnn */
0x00, 0x00,
/*! Measured Power */
0xc5
};
/**************************************************************************************************
Global Variables
**************************************************************************************************/
/*! WSF handler ID */
wsfHandlerId_t iBeaconHandlerId;
/*************************************************************************************************/
/*!
* \fn iBeaconDmCback
*
* \brief Application DM callback.
*
* \param pDmEvt DM callback event
*
* \return None.
*/
/*************************************************************************************************/
static void iBeaconDmCback(dmEvt_t *pDmEvt)
{
dmEvt_t *pMsg;
if ((pMsg = WsfMsgAlloc(sizeof(dmEvt_t))) != NULL)
{
memcpy(pMsg, pDmEvt, sizeof(dmEvt_t));
WsfMsgSend(iBeaconHandlerId, pMsg);
}
}
/*************************************************************************************************/
/*!
* \fn iBeacon Setup
*
* \brief Set up advertising and other procedures that need to be performed after
* device reset.
*
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
static void iBeaconSetup(ibeaconMsg_t *pMsg)
{
/* set advertising and scan response data for discoverable mode */
AppAdvSetData(APP_ADV_DATA_DISCOVERABLE, sizeof(ibeaconAdvDataDisc), (uint8_t *) ibeaconAdvDataDisc);
/* set advertising and scan response data for connectable mode */
AppAdvSetData(APP_ADV_DATA_CONNECTABLE, 0, NULL);
// non-connectable advertising
AppSetAdvType(DM_ADV_NONCONN_UNDIRECT);
/* start advertising; automatically set connectable/discoverable mode and bondable mode */
AppAdvStart(APP_MODE_DISCOVERABLE);
}
/*************************************************************************************************/
/*!
* \fn iBeaconProcMsg
*
* \brief Process messages from the event handler.
*
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
static void iBeaconProcMsg(ibeaconMsg_t *pMsg)
{
uint8_t uiEvent = APP_UI_NONE;
switch(pMsg->hdr.event)
{
case DM_RESET_CMPL_IND:
AttsCalculateDbHash();
DmSecGenerateEccKeyReq();
iBeaconSetup(pMsg);
uiEvent = APP_UI_RESET_CMPL;
break;
case DM_ADV_START_IND:
uiEvent = APP_UI_ADV_START;
break;
case DM_ADV_STOP_IND:
uiEvent = APP_UI_ADV_STOP;
break;
default:
break;
}
if (uiEvent != APP_UI_NONE)
{
AppUiAction(uiEvent);
}
}
/*************************************************************************************************/
/*!
* \fn iBeaconHandlerInit
*
* \brief Application handler init function called during system initialization.
*
* \param handlerID WSF handler ID.
*
* \return None.
*/
/*************************************************************************************************/
void iBeaconHandlerInit(wsfHandlerId_t handlerId)
{
APP_TRACE_INFO0("iBeaconHandlerInit");
/* store handler ID */
iBeaconHandlerId = handlerId;
/* Set configuration pointers */
pAppAdvCfg = (appAdvCfg_t *) &ibeaconAdvCfg;
pAppSlaveCfg = (appSlaveCfg_t *) &ibeaconSlaveCfg;
pAppSecCfg = (appSecCfg_t *) &ibeaconSecCfg;
/* Initialize application framework */
AppSlaveInit();
}
/*************************************************************************************************/
/*!
* \fn iBeaconHandler
*
* \brief WSF event handler for application.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void iBeaconHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
{
if (pMsg != NULL)
{
APP_TRACE_INFO1("iBeacon got evt %d", pMsg->event);
if (pMsg->event >= DM_CBACK_START && pMsg->event <= DM_CBACK_END)
{
/* process advertising and connection-related messages */
AppSlaveProcDmMsg((dmEvt_t *) pMsg);
/* process security-related messages */
AppSlaveSecProcDmMsg((dmEvt_t *) pMsg);
}
/* perform profile and user interface-related operations */
iBeaconProcMsg((ibeaconMsg_t *) pMsg);
}
}
/*************************************************************************************************/
/*!
* \fn iBeaconStart
*
* \brief Start the application.
*
* \return None.
*/
/*************************************************************************************************/
void iBeaconStart(void)
{
/* Register for stack callbacks */
DmRegister(iBeaconDmCback);
DmConnRegister(DM_CLIENT_ID_APP, iBeaconDmCback);
/* Reset the device */
DmDevReset();
}
@@ -0,0 +1,127 @@
// ****************************************************************************
//
// prodtest_datc_api.h
//! @file
//!
//! @brief Proprietary data transfer client sample application.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/*************************************************************************************************/
/*!
* \file prodtest_datc_api.h
*
* \brief Proprietary data transfer client sample application.
*
* $Date: 2016-12-28 16:12:14 -0600 (Wed, 28 Dec 2016) $
* $Revision: 10805 $
*
* Copyright (c) 2012-2017 ARM Ltd., all rights reserved.
* ARM Ltd. confidential and proprietary.
*
* IMPORTANT. Your use of this file is governed by a Software License Agreement
* ("Agreement") that must be accepted in order to download or otherwise receive a
* copy of this file. You may not use or copy this file for any purpose other than
* as described in the Agreement. If you do not agree to all of the terms of the
* Agreement do not use this file and delete all copies in your possession or control;
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
* to any use, copying or further distribution of this software.
*/
/*************************************************************************************************/
#ifndef DATC_API_H
#define DATC_API_H
#include "wsf_os.h"
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \fn DatcStart
*
* \brief Start the application.
*
* \return None.
*/
/*************************************************************************************************/
void DatcStart(void);
/*************************************************************************************************/
/*!
* \fn DatcHandlerInit
*
* \brief Application handler init function called during system initialization.
*
* \param handlerID WSF handler ID for App.
*
* \return None.
*/
/*************************************************************************************************/
void DatcHandlerInit(wsfHandlerId_t handlerId);
/*************************************************************************************************/
/*!
* \fn DatcHandler
*
* \brief WSF event handler for the application.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void DatcHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
#ifdef __cplusplus
};
#endif
#endif /* DATC_API_H */
@@ -0,0 +1,130 @@
// ****************************************************************************
//
// prodtest_dats_api.h
//! @file
//!
//! @brief Proprietary data transfer server sample application.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/*************************************************************************************************/
/*!
* file prodtest_dats_api.h
*
* brief Proprietary data transfer server sample application.
*
* $Date: 2016-12-28 16:12:14 -0600 (Wed, 28 Dec 2016) $
* $Revision: 10805 $
*
* Copyright (c) 2012-2017 ARM Ltd., all rights reserved.
* ARM Ltd. confidential and proprietary.
*
* IMPORTANT. Your use of this file is governed by a Software License Agreement
* ("Agreement") that must be accepted in order to download or otherwise receive a
* copy of this file. You may not use or copy this file for any purpose other than
* as described in the Agreement. If you do not agree to all of the terms of the
* Agreement do not use this file and delete all copies in your possession or control;
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
* to any use, copying or further distribution of this software.
*/
/*************************************************************************************************/
#ifndef DATS_API_H
#define DATS_API_H
#include "wsf_os.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef WDXS_INCLUDED
#define WDXS_INCLUDED FALSE
#endif
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \fn DatsStart
*
* \brief Start the application.
*
* \return None.
*/
/*************************************************************************************************/
void DatsStart(void);
/*************************************************************************************************/
/*!
* \fn DatsHandlerInit
*
* \brief Application handler init function called during system initialization.
*
* \param handlerID WSF handler ID for App.
*
* \return None.
*/
/*************************************************************************************************/
void DatsHandlerInit(wsfHandlerId_t handlerId);
/*************************************************************************************************/
/*!
* \fn DatsHandler
*
* \brief WSF event handler for the application.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void DatsHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
#ifdef __cplusplus
};
#endif
#endif /* DATS_API_H */
@@ -0,0 +1,802 @@
// ****************************************************************************
//
// prodtest_dats_main.c
//! @file
//!
//! @brief Data transmitter sample application.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/*************************************************************************************************/
/*!
* file dats_main.c
*
* brief Data transmitter sample application.
*
* $Date: 2017-03-09 12:18:38 -0600 (Thu, 09 Mar 2017) $
* $Revision: 11460 $
*
* Copyright (c) 2012-2017 ARM Ltd., all rights reserved.
* ARM Ltd. confidential and proprietary.
*
* IMPORTANT. Your use of this file is governed by a Software License Agreement
* ("Agreement") that must be accepted in order to download or otherwise receive a
* copy of this file. You may not use or copy this file for any purpose other than
* as described in the Agreement. If you do not agree to all of the terms of the
* Agreement do not use this file and delete all copies in your possession or control;
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
* to any use, copying or further distribution of this software.
*/
/*************************************************************************************************/
#include <string.h>
#include "wsf_types.h"
#include "bstream.h"
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "wsf_buf.h"
#include "hci_api.h"
#include "sec_api.h"
#include "dm_api.h"
#include "smp_api.h"
#include "att_api.h"
#include "app_api.h"
#include "app_db.h"
#include "app_ui.h"
#include "svc_ch.h"
#include "svc_core.h"
#include "svc_wp.h"
#include "calc128.h"
#include "prodtest_dats_api.h"
#if WDXS_INCLUDED == TRUE
#include "wsf_efs.h"
#include "svc_wdxs.h"
#include "wdxs_api.h"
#include "wdxs_main.h"
#include "wdxs_stream.h"
#endif
#include "hci_apollo_config.h"
#include "hci_drv_em9304.h"
#include "gatt_api.h"
/**************************************************************************************************
Macros
**************************************************************************************************/
#if CS50_INCLUDED == TRUE
/* PHY Test Modes */
#define DATS_PHY_1M 1
#define DATS_PHY_2M 2
#define DATS_PHY_CODED 3
#endif /* CS50_INCLUDED */
/*! Enumeration of client characteristic configuration descriptors */
enum
{
#if WDXS_INCLUDED == TRUE
WDXS_DC_CH_CCC_IDX, /*! WDXS DC service, service changed characteristic */
WDXS_FTC_CH_CCC_IDX, /*! WDXS FTC service, service changed characteristic */
WDXS_FTD_CH_CCC_IDX, /*! WDXS FTD service, service changed characteristic */
WDXS_AU_CH_CCC_IDX, /*! WDXS AU service, service changed characteristic */
#endif /* WDXS_INCLUDED */
DATS_GATT_SC_CCC_IDX, /*! GATT service, service changed characteristic */
DATS_WP_DAT_CCC_IDX, /*! ARM Ltd. proprietary service, data transfer characteristic */
DATS_NUM_CCC_IDX
};
/**************************************************************************************************
Configurable Parameters
**************************************************************************************************/
/*! configurable parameters for advertising */
static const appAdvCfg_t datsAdvCfg =
{
{30000, 0, 0}, /*! Advertising durations in ms */
{ 32, 32, 0} /*! Advertising intervals in 0.625 ms units */
};
/*! configurable parameters for slave */
static const appSlaveCfg_t datsSlaveCfg =
{
1, /*! Maximum connections */
};
/*! configurable parameters for security */
static const appSecCfg_t datsSecCfg =
{
0, /*! Authentication and bonding flags */
DM_KEY_DIST_IRK, /*! Initiator key distribution flags */
DM_KEY_DIST_LTK | DM_KEY_DIST_IRK, /*! Responder key distribution flags */
FALSE, /*! TRUE if Out-of-band pairing data is present */
FALSE /*! TRUE to initiate security upon connection */
};
/*! SMP security parameter configuration */
static const smpCfg_t datsSmpCfg =
{
3000, /*! 'Repeated attempts' timeout in msec */
SMP_IO_NO_IN_NO_OUT, /*! I/O Capability */
7, /*! Minimum encryption key length */
16, /*! Maximum encryption key length */
1, /*! Attempts to trigger 'repeated attempts' timeout */
0, /*! Device authentication requirements */
64000, /*! Maximum repeated attempts timeout in msec */
64000, /*! Time msec before attemptExp decreases */
2 /*! Repeated attempts multiplier exponent */
};
/*! configurable parameters for connection parameter update */
static const appUpdateCfg_t datsUpdateCfg =
{
0, /*! Connection idle period in ms before attempting
connection parameter update; set to zero to disable */
640, /*! Minimum connection interval in 1.25ms units */
800, /*! Maximum connection interval in 1.25ms units */
3, /*! Connection latency */
600, /*! Supervision timeout in 10ms units */
5 /*! Number of update attempts before giving up */
};
/*! ATT configurable parameters (increase MTU) */
static const attCfg_t datsAttCfg =
{
15, /* ATT server service discovery connection idle timeout in seconds */
241, /* desired ATT MTU */
ATT_MAX_TRANS_TIMEOUT, /* transcation timeout in seconds */
4 /* number of queued prepare writes supported by server */
};
/*! local IRK */
static uint8_t localIrk[] =
{
0x95, 0xC8, 0xEE, 0x6F, 0xC5, 0x0D, 0xEF, 0x93, 0x35, 0x4E, 0x7C, 0x57, 0x08, 0xE2, 0xA3, 0x85
};
/**************************************************************************************************
Advertising Data
**************************************************************************************************/
/*! advertising data, discoverable mode */
static const uint8_t datsAdvDataDisc[] =
{
/*! flags */
2, /*! length */
DM_ADV_TYPE_FLAGS, /*! AD type */
DM_FLAG_LE_GENERAL_DISC | /*! flags */
DM_FLAG_LE_BREDR_NOT_SUP,
/*! manufacturer specific data */
3, /*! length */
DM_ADV_TYPE_MANUFACTURER, /*! AD type */
UINT16_TO_BYTES(HCI_ID_ARM) /*! company ID */
};
/*! scan data, discoverable mode */
static const uint8_t datsScanDataDisc[] =
{
/*! device name */
8, /*! length */
DM_ADV_TYPE_LOCAL_NAME, /*! AD type */
'D',
'a',
't',
'a',
' ',
'T',
'X'
};
/**************************************************************************************************
Client Characteristic Configuration Descriptors
**************************************************************************************************/
/*! client characteristic configuration descriptors settings, indexed by above enumeration */
static const attsCccSet_t datsCccSet[DATS_NUM_CCC_IDX] =
{
/* cccd handle value range security level */
#if WDXS_INCLUDED == TRUE
{WDXS_DC_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE}, /* WDXS_DC_CH_CCC_IDX */
{WDXS_FTC_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE}, /* WDXS_FTC_CH_CCC_IDX */
{WDXS_FTD_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE}, /* WDXS_FTD_CH_CCC_IDX */
{WDXS_AU_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE}, /* WDXS_AU_CH_CCC_IDX */
#endif /* WDXS_INCLUDED */
{GATT_SC_CH_CCC_HDL, ATT_CLIENT_CFG_INDICATE, DM_SEC_LEVEL_NONE}, /* DATS_GATT_SC_CCC_IDX */
{WP_DAT_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE} /* DATS_WP_DAT_CCC_IDX */
};
/**************************************************************************************************
Local Variables
**************************************************************************************************/
/*! application control block */
static struct
{
wsfHandlerId_t handlerId; /* WSF handler ID */
#if CS50_INCLUDED == TRUE
uint8_t phyMode; /*! PHY Test Mode */
#endif /* CS50_INCLUDED */
} datsCb;
/* LESC OOB configuration */
static dmSecLescOobCfg_t *datsOobCfg;
/*************************************************************************************************/
/*!
* \fn datsSendData
*
* \brief Send notification containing data.
*
* \param connId DM connection ID.
*
* \return None.
*/
/*************************************************************************************************/
static void datsSendData(dmConnId_t connId)
{
uint8_t str[] = "hello.....from dats";
if (AttsCccEnabled(connId, DATS_WP_DAT_CCC_IDX))
{
/* send notification */
AttsHandleValueNtf(connId, WP_DAT_HDL, sizeof(str), str);
AttsHandleValueNtf(connId, WP_DAT_HDL, sizeof(str), str);
AttsHandleValueNtf(connId, WP_DAT_HDL, sizeof(str), str);
AttsHandleValueNtf(connId, WP_DAT_HDL, sizeof(str), str);
AttsHandleValueNtf(connId, WP_DAT_HDL, sizeof(str), str);
}
}
static void datsSetup(dmEvt_t *pMsg);
/*************************************************************************************************/
/*!
* \fn datsDmCback
*
* \brief Application DM callback.
*
* \param pDmEvt DM callback event
*
* \return None.
*/
/*************************************************************************************************/
static void datsDmCback(dmEvt_t *pDmEvt)
{
dmEvt_t *pMsg;
uint16_t len;
if (pDmEvt->hdr.event == DM_SEC_ECC_KEY_IND)
{
DmSecSetEccKey(&pDmEvt->eccMsg.data.key);
/* If the local device sends OOB data. */
if (datsSecCfg.oob)
{
uint8_t oobLocalRandom[SMP_RAND_LEN];
SecRand(oobLocalRandom, SMP_RAND_LEN);
DmSecCalcOobReq(oobLocalRandom, pDmEvt->eccMsg.data.key.pubKey_x);
}
}
else if (pDmEvt->hdr.event == DM_SEC_CALC_OOB_IND)
{
if (datsOobCfg == NULL)
{
datsOobCfg = WsfBufAlloc(sizeof(dmSecLescOobCfg_t));
}
if (datsOobCfg)
{
Calc128Cpy(datsOobCfg->localConfirm, pDmEvt->oobCalcInd.confirm);
Calc128Cpy(datsOobCfg->localRandom, pDmEvt->oobCalcInd.random);
}
}
else
{
len = DmSizeOfEvt(pDmEvt);
if ((pMsg = WsfMsgAlloc(len)) != NULL)
{
memcpy(pMsg, pDmEvt, len);
WsfMsgSend(datsCb.handlerId, pMsg);
}
}
}
/*************************************************************************************************/
/*!
* \fn datsAttCback
*
* \brief Application ATT callback.
*
* \param pEvt ATT callback event
*
* \return None.
*/
/*************************************************************************************************/
static void datsAttCback(attEvt_t *pEvt)
{
#if WDXS_INCLUDED == TRUE
WdxsAttCback(pEvt);
#endif /* WDXS_INCLUDED */
}
/*************************************************************************************************/
/*!
* \fn datsCccCback
*
* \brief Application ATTS client characteristic configuration callback.
*
* \param pDmEvt DM callback event
*
* \return None.
*/
/*************************************************************************************************/
static void datsCccCback(attsCccEvt_t *pEvt)
{
appDbHdl_t dbHdl;
/* If CCC not set from initialization and there's a device record and currently bonded */
if ((pEvt->handle != ATT_HANDLE_NONE) &&
((dbHdl = AppDbGetHdl((dmConnId_t) pEvt->hdr.param)) != APP_DB_HDL_NONE) &&
AppCheckBonded((dmConnId_t)pEvt->hdr.param))
{
/* Store value in device database. */
AppDbSetCccTblValue(dbHdl, pEvt->idx, pEvt->value);
}
}
/*************************************************************************************************/
/*!
* \fn datsWpWriteCback
*
* \brief ATTS write callback for proprietary data service.
*
* \return ATT status.
*/
/*************************************************************************************************/
uint8_t datsWpWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr)
{
/* print received data */
APP_TRACE_INFO0((const char*) pValue);
/* send back some data */
datsSendData(connId);
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \fn datsSetup
*
* \brief Set up advertising and other procedures that need to be performed after
* device reset.
*
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
static void datsSetup(dmEvt_t *pMsg)
{
/* set advertising and scan response data for discoverable mode */
AppAdvSetData(APP_ADV_DATA_DISCOVERABLE, sizeof(datsAdvDataDisc), (uint8_t *) datsAdvDataDisc);
AppAdvSetData(APP_SCAN_DATA_DISCOVERABLE, sizeof(datsScanDataDisc), (uint8_t *) datsScanDataDisc);
/* set advertising and scan response data for connectable mode */
AppAdvSetData(APP_ADV_DATA_CONNECTABLE, sizeof(datsAdvDataDisc), (uint8_t *) datsAdvDataDisc);
AppAdvSetData(APP_SCAN_DATA_CONNECTABLE, sizeof(datsScanDataDisc), (uint8_t *) datsScanDataDisc);
/* start advertising; automatically set connectable/discoverable mode and bondable mode */
AppAdvStart(APP_MODE_AUTO_INIT);
}
/*************************************************************************************************/
/*!
* \fn datsProcMsg
*
* \brief Process messages from the event handler.
*
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
static void datsProcMsg(dmEvt_t *pMsg)
{
uint8_t uiEvent = APP_UI_NONE;
switch(pMsg->hdr.event)
{
case ATT_MTU_UPDATE_IND:
APP_TRACE_INFO1("Negotiated MTU %d", ((attEvt_t *)pMsg)->mtu);
break;
case DM_RESET_CMPL_IND:
AttsCalculateDbHash();
DmSecGenerateEccKeyReq();
datsSetup(NULL);
uiEvent = APP_UI_RESET_CMPL;
HciVsEM_SetRfPowerLevelEx(TX_POWER_LEVEL_PLUS_0P4_dBm);
break;
case DM_ADV_SET_START_IND:
uiEvent = APP_UI_ADV_SET_START_IND;
break;
case DM_ADV_SET_STOP_IND:
uiEvent = APP_UI_ADV_SET_STOP_IND;
break;
case DM_ADV_START_IND:
uiEvent = APP_UI_ADV_START;
break;
case DM_ADV_STOP_IND:
uiEvent = APP_UI_ADV_STOP;
break;
case DM_CONN_OPEN_IND:
uiEvent = APP_UI_CONN_OPEN;
#if CS50_INCLUDED == TRUE
datsCb.phyMode = DATS_PHY_1M;
#endif /* CS50_INCLUDED */
break;
case DM_CONN_CLOSE_IND:
uiEvent = APP_UI_CONN_CLOSE;
break;
case DM_SEC_PAIR_CMPL_IND:
DmSecGenerateEccKeyReq();
uiEvent = APP_UI_SEC_PAIR_CMPL;
break;
case DM_SEC_PAIR_FAIL_IND:
DmSecGenerateEccKeyReq();
uiEvent = APP_UI_SEC_PAIR_FAIL;
break;
case DM_SEC_ENCRYPT_IND:
uiEvent = APP_UI_SEC_ENCRYPT;
break;
case DM_SEC_ENCRYPT_FAIL_IND:
uiEvent = APP_UI_SEC_ENCRYPT_FAIL;
break;
case DM_SEC_AUTH_REQ_IND:
if (pMsg->authReq.oob)
{
dmConnId_t connId = (dmConnId_t) pMsg->hdr.param;
/* TODO: Perform OOB Exchange with the peer. */
/* TODO: Fill datsOobCfg peerConfirm and peerRandom with value passed out of band */
if (datsOobCfg != NULL)
{
DmSecSetOob(connId, datsOobCfg);
}
DmSecAuthRsp(connId, 0, NULL);
}
else
{
AppHandlePasskey(&pMsg->authReq);
}
break;
case DM_SEC_ECC_KEY_IND:
DmSecSetEccKey(&pMsg->eccMsg.data.key);
break;
case DM_SEC_COMPARE_IND:
AppHandleNumericComparison(&pMsg->cnfInd);
break;
case DM_PRIV_CLEAR_RES_LIST_IND:
APP_TRACE_INFO1("Clear resolving list status 0x%02x", pMsg->hdr.status);
break;
case DM_HW_ERROR_IND:
uiEvent = APP_UI_HW_ERROR;
break;
case DM_VENDOR_SPEC_CMD_CMPL_IND:
{
#if defined(AM_PART_APOLLO) || defined(AM_PART_APOLLO2)
uint8_t *param_ptr = &pMsg->vendorSpecCmdCmpl.param[0];
switch (pMsg->vendorSpecCmdCmpl.opcode)
{
case 0xFC20: //read at address
{
uint32_t read_value;
BSTREAM_TO_UINT32(read_value, param_ptr);
APP_TRACE_INFO3("VSC 0x%0x complete status %x param %x",
pMsg->vendorSpecCmdCmpl.opcode,
pMsg->hdr.status,
read_value);
}
break;
default:
APP_TRACE_INFO2("VSC 0x%0x complete status %x",
pMsg->vendorSpecCmdCmpl.opcode,
pMsg->hdr.status);
break;
}
#endif
}
break;
default:
break;
}
if (uiEvent != APP_UI_NONE)
{
AppUiAction(uiEvent);
}
}
/*************************************************************************************************/
/*!
* \fn DatsHandlerInit
*
* \brief Application handler init function called during system initialization.
*
* \param handlerID WSF handler ID.
*
* \return None.
*/
/*************************************************************************************************/
void DatsHandlerInit(wsfHandlerId_t handlerId)
{
APP_TRACE_INFO0("DatsHandlerInit");
/* store handler ID */
datsCb.handlerId = handlerId;
/* Set configuration pointers */
pAppSlaveCfg = (appSlaveCfg_t *) &datsSlaveCfg;
pAppAdvCfg = (appAdvCfg_t *) &datsAdvCfg;
pAppSecCfg = (appSecCfg_t *) &datsSecCfg;
pAppUpdateCfg = (appUpdateCfg_t *) &datsUpdateCfg;
pSmpCfg = (smpCfg_t *) &datsSmpCfg;
/* Initialize application framework */
AppSlaveInit();
/* Set IRK for the local device */
DmSecSetLocalIrk(localIrk);
}
/*************************************************************************************************/
/*!
* \fn datsBtnCback
*
* \brief Button press callback.
*
* \param btn Button press.
*
* \return None.
*/
/*************************************************************************************************/
static void datsBtnCback(uint8_t btn)
{
#if WDXS_INCLUDED == TRUE
static uint8_t waveform = WDXS_STREAM_WAVEFORM_SINE;
#endif /* WDXS_INCLUDED */
#if CS50_INCLUDED == TRUE
dmConnId_t connId;
if ((connId = AppConnIsOpen()) != DM_CONN_ID_NONE)
#else
if (AppConnIsOpen() != DM_CONN_ID_NONE)
#endif /* CS50_INCLUDED */
{
switch (btn)
{
#if CS50_INCLUDED == TRUE
case APP_UI_BTN_2_SHORT:
/* Toggle PHY Test Mode */
if (datsCb.phyMode == DATS_PHY_1M)
{
APP_TRACE_INFO0("2 MBit TX and RX PHY Requested");
DmSetPhy(connId, HCI_ALL_PHY_ALL_PREFERENCES, HCI_PHY_LE_2M_BIT, HCI_PHY_LE_2M_BIT, HCI_PHY_OPTIONS_NONE);
}
else if (datsCb.phyMode == DATS_PHY_2M)
{
APP_TRACE_INFO0("LE Coded TX and RX PHY Requested");
DmSetPhy(connId, HCI_ALL_PHY_ALL_PREFERENCES, HCI_PHY_LE_CODED_BIT, HCI_PHY_LE_CODED_BIT, HCI_PHY_OPTIONS_NONE);
}
else
{
APP_TRACE_INFO0("1 MBit TX and RX PHY Requested");
DmSetPhy(connId, HCI_ALL_PHY_ALL_PREFERENCES, HCI_PHY_LE_1M_BIT, HCI_PHY_LE_1M_BIT, HCI_PHY_OPTIONS_NONE);
}
break;
#endif /* CS50_INCLUDED */
#if WDXS_INCLUDED == TRUE
case APP_UI_BTN_1_SHORT:
/* Change stream waveform */
waveform++;
if ( waveform > WDXS_STREAM_WAVEFORM_SAWTOOTH )
{
waveform = WDXS_STREAM_WAVEFORM_SINE;
}
wdxsSetStreamWaveform(waveform);
break;
#endif /* WDXS_INCLUDED */
default:
break;
}
}
}
/*************************************************************************************************/
/*!
* \fn datsWsfBufDiagnostics
*
* \brief Callback for WSF buffer diagnostic messages.
*
* \param pInfo Diagnostics message
*
* \return None.
*/
/*************************************************************************************************/
static void datsWsfBufDiagnostics(WsfBufDiag_t *pInfo)
{
if (pInfo->type == WSF_BUF_ALLOC_FAILED)
{
APP_TRACE_INFO2("Dats got WSF Buffer Allocation Failure - Task: %d Len: %d",
pInfo->param.alloc.taskId, pInfo->param.alloc.len);
}
}
/*************************************************************************************************/
/*!
* \fn DatsHandler
*
* \brief WSF event handler for application.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void DatsHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
{
if (pMsg != NULL)
{
APP_TRACE_INFO1("Dats got evt %d", pMsg->event);
/* process ATT messages */
if (pMsg->event >= ATT_CBACK_START && pMsg->event <= ATT_CBACK_END)
{
/* process server-related ATT messages */
AppServerProcAttMsg(pMsg);
}
/* process DM messages */
else if (pMsg->event >= DM_CBACK_START && pMsg->event <= DM_CBACK_END)
{
/* process advertising and connection-related messages */
AppSlaveProcDmMsg((dmEvt_t *) pMsg);
/* process security-related messages */
AppSlaveSecProcDmMsg((dmEvt_t *) pMsg);
#if WDXS_INCLUDED == TRUE
/* process WDXS-related messages */
WdxsProcDmMsg((dmEvt_t*) pMsg);
#endif /* WDXS_INCLUDED */
}
/* perform profile and user interface-related operations */
datsProcMsg((dmEvt_t *) pMsg);
}
}
/*************************************************************************************************/
/*!
* \fn DatsStart
*
* \brief Start the application.
*
* \return None.
*/
/*************************************************************************************************/
void DatsStart(void)
{
/* Register for stack callbacks */
DmRegister(datsDmCback);
DmConnRegister(DM_CLIENT_ID_APP, datsDmCback);
AttRegister(datsAttCback);
AttConnRegister(AppServerConnCback);
AttsCccRegister(DATS_NUM_CCC_IDX, (attsCccSet_t *) datsCccSet, datsCccCback);
/* Initialize attribute server database */
SvcCoreGattCbackRegister(GattReadCback, GattWriteCback);
SvcCoreAddGroup();
SvcWpCbackRegister(NULL, datsWpWriteCback);
SvcWpAddGroup();
/* Register for app framework button callbacks */
AppUiBtnRegister(datsBtnCback);
#if WDXS_INCLUDED == TRUE
/* Initialize the OTA File Media */
WdxsOtaMediaInit();
/* Initialize the WDXS Stream */
wdxsStreamInit();
/* Set the WDXS CCC Identifiers */
WdxsSetCccIdx(WDXS_DC_CH_CCC_IDX, WDXS_AU_CH_CCC_IDX, WDXS_FTC_CH_CCC_IDX, WDXS_FTD_CH_CCC_IDX);
#endif /* WDXS_INCLUDED */
WsfBufDiagRegister(datsWsfBufDiagnostics);
/* Set Service Changed CCCD index. */
GattSetSvcChangedIdx(DATS_GATT_SC_CCC_IDX);
/* Reset the device */
DmDevReset();
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,126 @@
// ****************************************************************************
//
// vole_api.h
//! @file
//!
//! @brief Ambiq Micro's demonstration of AMDTP service.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2018, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 1.2.12 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef VOLE_API_H
#define VOLE_API_H
#include "wsf_os.h"
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Macros
**************************************************************************************************/
#ifndef VOLE_CONN_MAX
#define VOLE_CONN_MAX 1
#endif
/*! WSF message event starting value */
#define VOLE_MSG_START 0xA0
/*! WSF message event enumeration */
enum
{
AMOTA_TIMER_IND = VOLE_MSG_START,
};
extern dmConnId_t g_AmaConnId;
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \fn AmvosStart
*
* \brief Start the application.
*
* \return None.
*/
/*************************************************************************************************/
void VoleStart(void);
/*************************************************************************************************/
/*!
* \fn VoleHandlerInit
*
* \brief Application handler init function called during system initialization.
*
* \param handlerID WSF handler ID for App.
*
* \return None.
*/
/*************************************************************************************************/
void VoleHandlerInit(wsfHandlerId_t handlerId);
/*************************************************************************************************/
/*!
* \fn VoleHandler
*
* \brief WSF event handler for the application.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void VoleHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg);
void VoleBleSend(uint8_t * buf, uint32_t len);
#ifdef __cplusplus
};
#endif
#endif /* VOLE_API_H */
@@ -0,0 +1,867 @@
// ****************************************************************************
//
// vole_main.c
//! @file
//!
//! @brief Ambiq Micro's demonstration of Voice Over LE service.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include "usr_include.h"
#include <string.h>
#include "wsf_types.h"
#include "bstream.h"
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "hci_api.h"
#include "dm_api.h"
#include "att_api.h"
#include "smp_api.h"
#include "app_api.h"
#include "app_db.h"
#include "app_ui.h"
#include "app_hw.h"
#include "svc_ch.h"
#include "svc_core.h"
#include "svc_dis.h"
#include "vole_api.h"
#include "svc_amvole.h"
#include "vole_common.h"
#include "vole_board_config.h"
#include "am_util.h"
#include "crc32.h"
#include "am_app_KWD_AMA.h"
#include "FreeRTOS.h"
#include "task.h"
#include "voles_api.h"
#include "gatt_api.h"
/**************************************************************************************************
Macros
**************************************************************************************************/
/**************************************************************************************************
Data Types
**************************************************************************************************/
/*! Application message type */
typedef union
{
wsfMsgHdr_t hdr;
dmEvt_t dm;
attsCccEvt_t ccc;
attEvt_t att;
} amvoleMsg_t;
/**************************************************************************************************
Configurable Parameters
**************************************************************************************************/
/*! configurable parameters for advertising */
static const appAdvCfg_t amvoleAdvCfg =
{
{60000, 0, 0}, /*! Advertising durations in ms */
{ 800, 800, 0} /*! Advertising intervals in 0.625 ms units */
};
/*! configurable parameters for slave */
static const appSlaveCfg_t amvoleSlaveCfg =
{
VOLE_CONN_MAX, /*! Maximum connections */
};
/*! configurable parameters for security */
static const appSecCfg_t amvoleSecCfg =
{
DM_AUTH_BOND_FLAG | DM_AUTH_SC_FLAG, /*! Authentication and bonding flags */
0, /*! Initiator key distribution flags */
DM_KEY_DIST_LTK, /*! Responder key distribution flags */
FALSE, /*! TRUE if Out-of-band pairing data is present */
FALSE /*! TRUE to initiate security upon connection */
};
static const appUpdateCfg_t amvoleUpdateCfg =
{
1000, //3000, /*! Connection idle period in ms before attempting
//connection parameter update; set to zero to disable */
6, //6, /*! 7.5ms */
12, //15, /*! 30ms */
0, /*! Connection latency */
400, //2000, //600, /*! Supervision timeout in 10ms units */
5 /*! Number of update attempts before giving up */
};
/*! SMP security parameter configuration */
static const smpCfg_t amvoleSmpCfg =
{
3000, /*! 'Repeated attempts' timeout in msec */
SMP_IO_NO_IN_NO_OUT, /*! I/O Capability */
7, /*! Minimum encryption key length */
16, /*! Maximum encryption key length */
3, /*! Attempts to trigger 'repeated attempts' timeout */
0, /*! Device authentication requirements */
};
/**************************************************************************************************
Advertising Data
**************************************************************************************************/
// RAM buffers to be used
uint8_t amvoleAdvDataDisc[31];
uint8_t amvoleScanDataDisc[31];
/*! advertising data, discoverable mode */
static const uint8_t amvoleAdvDataDiscDefault[] =
{
/*! flags */
2, /*! length */
DM_ADV_TYPE_FLAGS, /*! AD type */
DM_FLAG_LE_GENERAL_DISC | /*! flags */
DM_FLAG_LE_BREDR_NOT_SUP,
/*! tx power */
2, /*! length */
DM_ADV_TYPE_TX_POWER, /*! AD type */
0, /*! tx power */
/*! service UUID list */
17, /*! length */
DM_ADV_TYPE_128_UUID, /*! AD type */
ATT_UUID_VOLES_SERVICE
};
/*! scan data, discoverable mode */
static const uint8_t amvoleScanDataDiscDefault[] =
{
/*! device name */
5, /*! length */
DM_ADV_TYPE_LOCAL_NAME, /*! AD type */
'V',
'o',
'L',
'E'
};
dmConnId_t g_AmaConnId = DM_CONN_ID_NONE;
bool_t g_start_voice_send = FALSE;
extern bool am_app_KWD_AMA_tx_ver_exchange_send(void);
// index is the starting point of the local name, local name only in advData
static bool amvoleSetLocalName(uint8_t* pAdvData, uint8_t* pLocalName, uint8_t len, uint8_t index)
{
if (index + len + 1 > 31)
{
// max adv data is 31 byte long
return false;
}
// set parameter length
pAdvData[index] = len + 1;
// set parameter type
pAdvData[index + 1] = DM_ADV_TYPE_LOCAL_NAME;
// set local name
for ( uint8_t i = 0; i < len; i++ )
{
pAdvData[i + 2 + index] = pLocalName[i];
}
return true;
}
void amvoleKwdSetDemoName(void)
{
uint8_t test_bdaddress[6];
uint8_t ble_device_name[20] = "VOLES-"; //local name = device name
uint8_t *pBda;
uint8_t index = 6;
//fixme: read bd address and print out
pBda = HciGetBdAddr();
BdaCpy(test_bdaddress, pBda);
pBda = (uint8_t*)Bda2Str(test_bdaddress);
APP_TRACE_INFO0("Local Device BD Address: ");
APP_TRACE_INFO0(Bda2Str(test_bdaddress));
APP_TRACE_INFO0("\n");
// build demo name here
// 1st letter is board variant
#if USE_MAYA
ble_device_name[index++] = 'M';
#elif USE_APOLLO2_QT
ble_device_name[index++] = 'Q';
#else
ble_device_name[index++] = 'E';
#endif
// 3rd letter is wake-on-sound variant
#if USE_WAKE_ON_SOUND
ble_device_name[index++] = 'W';
#else
ble_device_name[index++] = 'A'; // A for always listening...
#endif
ble_device_name[index++] = '-';
ble_device_name[index++] = 'A';
ble_device_name[index++] = 'M';
ble_device_name[index++] = 'A';
// a hyphen...
ble_device_name[index++] = '-';
// take the last 4 hex digit
ble_device_name[index++] = pBda[8];
ble_device_name[index++] = pBda[9];
ble_device_name[index++] = pBda[10];
ble_device_name[index++] = pBda[11];
// set local name here:
amvoleSetLocalName(amvoleScanDataDisc, ble_device_name, index, 0);
//SvcCoreSetDevName(ble_device_name, index);
}
/**************************************************************************************************
Client Characteristic Configuration Descriptors
**************************************************************************************************/
/*! enumeration of client characteristic configuration descriptors */
enum
{
VOLES_GATT_SC_CCC_IDX, /*! GATT service, service changed characteristic */
VOLES_TX_CCC_IDX, /*! AMDTP service, tx characteristic */
VOLES_NUM_CCC_IDX
};
/*! client characteristic configuration descriptors settings, indexed by above enumeration */
static const attsCccSet_t amvoleCccSet[VOLES_NUM_CCC_IDX] =
{
/* cccd handle value range security level */
{GATT_SC_CH_CCC_HDL, ATT_CLIENT_CFG_INDICATE, DM_SEC_LEVEL_NONE}, /* VOLES_GATT_SC_CCC_IDX */
{VOLES_TX_CH_CCC_HDL, ATT_CLIENT_CFG_NOTIFY, DM_SEC_LEVEL_NONE}, /* VOLES_TX_CCC_IDX */
};
/**************************************************************************************************
Global Variables
**************************************************************************************************/
/*! WSF handler ID */
wsfHandlerId_t amvoleHandlerId;
/*************************************************************************************************/
/*!
* \fn amvoleDmCback
*
* \brief Application DM callback.
*
* \param pDmEvt DM callback event
*
* \return None.
*/
/*************************************************************************************************/
static void amvoleDmCback(dmEvt_t *pDmEvt)
{
dmEvt_t *pMsg;
uint16_t len;
len = DmSizeOfEvt(pDmEvt);
if ((pMsg = WsfMsgAlloc(len)) != NULL)
{
memcpy(pMsg, pDmEvt, len);
WsfMsgSend(amvoleHandlerId, pMsg);
}
}
bool amvoleTxChannelIsAvailable(void)
{
return(DM_CONN_ID_NONE != AppConnIsOpen());
}
void VoleBleSend(uint8_t * buf, uint32_t len)
{
if (amvoleTxChannelIsAvailable())
{
// simply tries to send notification
AttsHandleValueNtf(g_AmaConnId, VOLES_TX_HDL, len, buf); // connId always group 0 since support only 1 connection.
}
}
/*************************************************************************************************/
/*!
* \fn amvoleAttCback
*
* \brief Application ATT callback.
*
* \param pEvt ATT callback event
*
* \return None.
*/
/*************************************************************************************************/
static void amvoleAttCback(attEvt_t *pEvt)
{
attEvt_t *pMsg;
if ((pMsg = WsfMsgAlloc(sizeof(attEvt_t) + pEvt->valueLen)) != NULL)
{
memcpy(pMsg, pEvt, sizeof(attEvt_t));
pMsg->pValue = (uint8_t *) (pMsg + 1);
memcpy(pMsg->pValue, pEvt->pValue, pEvt->valueLen);
WsfMsgSend(amvoleHandlerId, pMsg);
}
}
/*************************************************************************************************/
/*!
* \fn amvoleCccCback
*
* \brief Application ATTS client characteristic configuration callback.
*
* \param pDmEvt DM callback event
*
* \return None.
*/
/*************************************************************************************************/
static void amvoleCccCback(attsCccEvt_t *pEvt)
{
attsCccEvt_t *pMsg;
appDbHdl_t dbHdl;
/* if CCC not set from initialization and there's a device record */
if ((pEvt->handle != ATT_HANDLE_NONE) &&
((dbHdl = AppDbGetHdl((dmConnId_t) pEvt->hdr.param)) != APP_DB_HDL_NONE))
{
/* store value in device database */
AppDbSetCccTblValue(dbHdl, pEvt->idx, pEvt->value);
}
if ((pMsg = WsfMsgAlloc(sizeof(attsCccEvt_t))) != NULL)
{
memcpy(pMsg, pEvt, sizeof(attsCccEvt_t));
WsfMsgSend(amvoleHandlerId, pMsg);
}
}
/*************************************************************************************************/
/*!
* \fn amvoleProcCccState
*
* \brief Process CCC state change.
*
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
static void amvoleProcCccState(amvoleMsg_t *pMsg)
{
APP_TRACE_INFO3("ccc state ind value:%d handle:%d idx:%d\n", pMsg->ccc.value, pMsg->ccc.handle, pMsg->ccc.idx);
/* VOLES TX CCC */
if (pMsg->ccc.idx == VOLES_TX_CCC_IDX)
{
if (pMsg->ccc.value == ATT_CLIENT_CFG_NOTIFY)
{
// notify enabled
g_AmaConnId = (dmConnId_t) pMsg->ccc.hdr.param;
APP_TRACE_INFO1("connId : %d\r\n", pMsg->ccc.hdr.param);
}
else
{
g_AmaConnId = DM_CONN_ID_NONE;
}
return;
}
}
/*************************************************************************************************/
/*!
* \fn amvoleClose
*
* \brief Perform UI actions on connection close.
*
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
static void amvoleClose(amvoleMsg_t *pMsg)
{
}
/*************************************************************************************************/
/*!
* \fn amvoleSetup
*
* \brief Set up advertising and other procedures that need to be performed after
* device reset.
*
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
static void amvoleSetup(amvoleMsg_t *pMsg)
{
/* set advertising and scan response data for discoverable mode */
AppAdvSetData(APP_ADV_DATA_DISCOVERABLE, sizeof(amvoleAdvDataDisc), (uint8_t *) amvoleAdvDataDisc);
AppAdvSetData(APP_SCAN_DATA_DISCOVERABLE, sizeof(amvoleScanDataDisc), (uint8_t *) amvoleScanDataDisc);
/* set advertising and scan response data for connectable mode */
AppAdvSetData(APP_ADV_DATA_CONNECTABLE, sizeof(amvoleAdvDataDisc), (uint8_t *) amvoleAdvDataDisc);
AppAdvSetData(APP_SCAN_DATA_CONNECTABLE, sizeof(amvoleScanDataDisc), (uint8_t *) amvoleScanDataDisc);
AppSetBondable(TRUE);
/* start advertising; automatically set connectable/discoverable mode and bondable mode */
AppAdvStart(APP_MODE_AUTO_INIT);
}
//*****************************************************************************
//
// LED task to indicate external events, such as heart beat and key word detected.
//
//*****************************************************************************
void am_app_led_on(void)
{
#if defined(AM_PART_APOLLO2)
am_hal_gpio_out_bit_toggle(LED_D6);
am_hal_gpio_out_bit_toggle(LED_D7);
am_hal_gpio_out_bit_toggle(LED_D8);
#endif // #if defined(AM_PART_APOLLO2)
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
#if USE_APOLLO3_BLUE_EVB
am_hal_gpio_state_write(LED_D5, AM_HAL_GPIO_OUTPUT_TOGGLE);
am_hal_gpio_state_write(LED_D6, AM_HAL_GPIO_OUTPUT_TOGGLE);
am_hal_gpio_state_write(LED_D7, AM_HAL_GPIO_OUTPUT_TOGGLE);
am_hal_gpio_state_write(LED_D8, AM_HAL_GPIO_OUTPUT_TOGGLE);
#endif // #if USE_APOLLO3_BLUE_EVB
#endif //#if defined(AM_PART_APOLLO3)
}
void am_app_led_off(void)
{
#if defined(AM_PART_APOLLO2)
am_hal_gpio_out_bit_clear(LED_D6);
am_hal_gpio_out_bit_clear(LED_D7);
am_hal_gpio_out_bit_clear(LED_D8);
#endif
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
#if USE_APOLLO3_BLUE_EVB
am_hal_gpio_state_write(LED_D5, AM_HAL_GPIO_OUTPUT_CLEAR);
am_hal_gpio_state_write(LED_D6, AM_HAL_GPIO_OUTPUT_CLEAR);
am_hal_gpio_state_write(LED_D7, AM_HAL_GPIO_OUTPUT_CLEAR);
am_hal_gpio_state_write(LED_D8, AM_HAL_GPIO_OUTPUT_CLEAR);
#endif
#endif
}
/*************************************************************************************************/
/*!
* \fn amvoleBtnCback
*
* \brief Button press callback.
*
* \param btn Button press.
*
* \return None.
*/
/*************************************************************************************************/
static void amvoleBtnCback(uint8_t btn)
{
dmConnId_t connId = AppConnIsOpen();
APP_TRACE_INFO2("button %d pressed, connection open:%d", btn, connId);
/* button actions when connected */
if (connId != DM_CONN_ID_NONE)
{
APP_TRACE_INFO1("btn:%d", btn);
switch (btn)
{
// transmit voice data using mSBC encode
case APP_UI_BTN_1_SHORT:
APP_TRACE_INFO0("start speech data send...");
voles_set_codec_type(MSBC_CODEC_IN_USE);
voles_init(amvoleHandlerId, MSBC_CODEC_IN_USE);
am_app_KWD_AMA_start_speech_send();
break;
case APP_UI_BTN_2_SHORT:
voles_set_codec_type(OPUS_CODEC_IN_USE);
voles_init(amvoleHandlerId, OPUS_CODEC_IN_USE);
am_app_KWD_AMA_start_speech_send();
break;
default:
break;
}
}
}
uint8_t
amvole_write_cback(dmConnId_t connId, uint16_t handle, uint8_t operation,
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr)
{
if (handle == VOLES_RX_HDL)
{
am_app_KWD_AMA_rx_handler(pValue, len);
}
return ATT_SUCCESS;
}
/*************************************************************************************************/
/*!
* \fn amvoleProcMsg
*
* \brief Process messages from the event handler.
*
* \param pMsg Pointer to message.
*
* \return None.
*/
/*************************************************************************************************/
static void amvoleProcMsg(amvoleMsg_t *pMsg)
{
uint8_t uiEvent = APP_UI_NONE;
static uint8_t retry_cnt = 0;
switch(pMsg->hdr.event)
{
case ATTS_HANDLE_VALUE_CNF:
voles_proc_msg(&pMsg->hdr);
break;
case ATTS_CCC_STATE_IND:
amvoleProcCccState(pMsg);
if (pMsg->ccc.handle == VOLES_TX_CH_CCC_HDL)
{
am_app_KWD_AMA_tx_ver_exchange_send();
}
break;
case DM_RESET_CMPL_IND:
AttsCalculateDbHash();
DmSecGenerateEccKeyReq();
amvoleSetup(pMsg);
#if USE_BLE_TX_POWER_SET
HciVsEM_SetRfPowerLevelEx(TX_POWER_LEVEL_PLUS_6P2_dBm);
#endif
uiEvent = APP_UI_RESET_CMPL;
break;
case DM_ADV_SET_START_IND:
uiEvent = APP_UI_ADV_SET_START_IND;
break;
case DM_ADV_SET_STOP_IND:
uiEvent = APP_UI_ADV_SET_STOP_IND;
break;
case DM_ADV_START_IND:
uiEvent = APP_UI_ADV_START;
break;
case DM_ADV_STOP_IND:
uiEvent = APP_UI_ADV_STOP;
break;
case DM_CONN_OPEN_IND:
voles_proc_msg(&pMsg->hdr);
DmConnSetDataLen(1, 251, 0x848);
uiEvent = APP_UI_CONN_OPEN;
retry_cnt = 0;
break;
case ATT_MTU_UPDATE_IND:
if ( AttGetMtu(1) < BLE_MSBC_DATA_BUFFER_SIZE )
{
if (retry_cnt < 5)
{
retry_cnt++;
AttcMtuReq(1, 247);
}
}
APP_TRACE_INFO2("ATT_MTU_UPDATE_IND AttGetMtu(), return = %d pMsg->att.mtu = %d\n", AttGetMtu(1), pMsg->att.mtu);
break;
case DM_CONN_DATA_LEN_CHANGE_IND:
am_util_debug_printf("DM_CONN_DATA_LEN_CHANGE_IND: status = %d, max RX len = %d, max TX len = %d \n", pMsg->dm.dataLenChange.hdr.status, pMsg->dm.dataLenChange.maxRxOctets, pMsg->dm.dataLenChange.maxTxOctets);
break;
case DM_CONN_CLOSE_IND:
APP_TRACE_INFO1("DM_CONN_CLOSE_IND reason = 0x%02x\n", pMsg->dm.connClose.reason);
amvoleClose(pMsg);
uiEvent = APP_UI_CONN_CLOSE;
// AppAdvStart(APP_MODE_DISCOVERABLE);
g_AmaConnId = DM_CONN_ID_NONE;
//g_eAmaStatus = VOS_AMA_INIT;
break;
case DM_CONN_UPDATE_IND:
voles_proc_msg(&pMsg->hdr);
break;
case DM_SEC_PAIR_CMPL_IND:
DmSecGenerateEccKeyReq();
uiEvent = APP_UI_SEC_PAIR_CMPL;
break;
case DM_SEC_PAIR_FAIL_IND:
DmSecGenerateEccKeyReq();
uiEvent = APP_UI_SEC_PAIR_FAIL;
break;
case DM_SEC_ENCRYPT_IND:
uiEvent = APP_UI_SEC_ENCRYPT;
break;
case DM_SEC_ENCRYPT_FAIL_IND:
uiEvent = APP_UI_SEC_ENCRYPT_FAIL;
break;
case DM_SEC_AUTH_REQ_IND:
AppHandlePasskey(&pMsg->dm.authReq);
break;
case DM_SEC_ECC_KEY_IND:
DmSecSetEccKey(&pMsg->dm.eccMsg.data.key);
break;
case DM_SEC_COMPARE_IND:
AppHandleNumericComparison(&pMsg->dm.cnfInd);
break;
case DM_PRIV_CLEAR_RES_LIST_IND:
APP_TRACE_INFO1("Clear resolving list status 0x%02x", pMsg->hdr.status);
break;
case DM_HW_ERROR_IND:
uiEvent = APP_UI_HW_ERROR;
break;
case DM_VENDOR_SPEC_CMD_CMPL_IND:
{
#if defined(AM_PART_APOLLO) || defined(AM_PART_APOLLO2)
uint8_t *param_ptr = &pMsg->dm.vendorSpecCmdCmpl.param[0];
switch (pMsg->dm.vendorSpecCmdCmpl.opcode)
{
case 0xFC20: //read at address
{
uint32_t read_value;
BSTREAM_TO_UINT32(read_value, param_ptr);
APP_TRACE_INFO3("VSC 0x%0x complete status %x param %x",
pMsg->dm.vendorSpecCmdCmpl.opcode,
pMsg->hdr.status,
read_value);
}
break;
default:
APP_TRACE_INFO2("VSC 0x%0x complete status %x",
pMsg->dm.vendorSpecCmdCmpl.opcode,
pMsg->hdr.status);
break;
}
#endif
}
break;
default:
break;
}
if (uiEvent != APP_UI_NONE)
{
AppUiAction(uiEvent);
}
}
void amvoleStartSendVoiceData()
{
g_start_voice_send = TRUE;
am_app_led_on();
voles_transmit_voice_data();
}
/*************************************************************************************************/
/*!
* \fn VoleHandlerInit
*
* \brief Application handler init function called during system initialization.
*
* \param handlerID WSF handler ID.
*
* \return None.
*/
/*************************************************************************************************/
void VoleHandlerInit(wsfHandlerId_t handlerId)
{
APP_TRACE_INFO0("VoleHandlerInit");
/* store handler ID */
amvoleHandlerId = handlerId;
/* Set configuration pointers */
pAppAdvCfg = (appAdvCfg_t *) &amvoleAdvCfg;
pAppSlaveCfg = (appSlaveCfg_t *) &amvoleSlaveCfg;
pAppSecCfg = (appSecCfg_t *) &amvoleSecCfg;
pAppUpdateCfg = (appUpdateCfg_t *) &amvoleUpdateCfg;
/* Initialize application framework */
AppSlaveInit();
AppServerInit();
/* Set stack configuration pointers */
pSmpCfg = (smpCfg_t *) &amvoleSmpCfg;
//voles_init(handlerId);
}
/*************************************************************************************************/
/*!
* \fn VoleHandler
*
* \brief WSF event handler for application.
*
* \param event WSF event mask.
* \param pMsg WSF message.
*
* \return None.
*/
/*************************************************************************************************/
void VoleHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
{
if (pMsg != NULL)
{
APP_TRACE_INFO1("vole got evt 0x%x", pMsg->event);
/* process ATT messages */
if (pMsg->event >= ATT_CBACK_START && pMsg->event <= ATT_CBACK_END)
{
/* process server-related ATT messages */
AppServerProcAttMsg(pMsg);
}
/* process DM messages */
else if (pMsg->event >= DM_CBACK_START && pMsg->event <= DM_CBACK_END)
{
/* process advertising and connection-related messages */
AppSlaveProcDmMsg((dmEvt_t *) pMsg);
/* process security-related messages */
AppSlaveSecProcDmMsg((dmEvt_t *) pMsg);
}
/* perform profile and user interface-related operations */
amvoleProcMsg((amvoleMsg_t *) pMsg);
}
}
/*************************************************************************************************/
/*!
* \fn VoleStart
*
* \brief Start the application.
*
* \return None.
*/
/*************************************************************************************************/
void VoleStart(void)
{
/* Register for stack callbacks */
DmRegister(amvoleDmCback);
DmConnRegister(DM_CLIENT_ID_APP, amvoleDmCback);
AttRegister(amvoleAttCback);
AttConnRegister(AppServerConnCback);
AttsCccRegister(VOLES_NUM_CCC_IDX, (attsCccSet_t *) amvoleCccSet, amvoleCccCback);
/* Register for app framework callbacks */
AppUiBtnRegister(amvoleBtnCback);
// set up adv data
memcpy(amvoleAdvDataDisc, amvoleAdvDataDiscDefault, sizeof(amvoleAdvDataDiscDefault));
memcpy(amvoleScanDataDisc, amvoleScanDataDiscDefault, sizeof(amvoleScanDataDiscDefault));
/* Initialize attribute server database */
SvcCoreGattCbackRegister(GattReadCback, GattWriteCback);
SvcCoreAddGroup();
SvcDisAddGroup();
SvcVolesCbackRegister(NULL, amvole_write_cback);
SvcVolesAddGroup();
/* Set Service Changed CCCD index. */
GattSetSvcChangedIdx(VOLES_GATT_SC_CCC_IDX);
/* Reset the device */
DmDevReset();
}
@@ -0,0 +1,824 @@
//*****************************************************************************
//
//! @file hci_drv.c
//!
//! @brief HCI driver interface.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "am_mcu_apollo.h"
#include "am_util.h"
#include "am_devices_em9304.h"
#include "em9304_init.h"
#include "em9304_patches.h"
#include "hci_apollo_config.h"
#define INVALIDATE_UNKNOWN_PATCHES
#define ENABLE_32K_CLK_FROM_APOLLO
#define SLEEP_CLK_PATCH_CONTAINER_ID (0x16)
// if a product is designed with step-up DCDC mode for EM9304
// and was programmed HCI v6 patch on OTP, it's required
// to define INVALIDATE_HCI_V6_PATCH_ON_OTP to do a special
// handling to invalidate the v6 patch on OTP and program
// v8 or later HCI patch.
#define INVALIDATE_HCI_V6_PATCH_ON_OTP
#ifdef INVALIDATE_HCI_V6_PATCH_ON_OTP
#define HCI_V6_PATCH_CONTAINER_ID 53
#endif
// This should be defined as the currently included HCI code patch
// e.g. currently v8 is latest, which has container ID 77.
#define HCI_CURRENT_CODE_PATCH_CONTAINER_ID 77
// Define the HCI Command Type locally.
#define HCI_CMD_TYPE 1
// EM_PatchQuery field offsets
#define PATCH_INDEX_OFFSET 3
// EM_PatchQuery response field offsets
#define CONTAINER_COUNT_INDEX 7
#define CONTAINER_ADDR_INDEX 15
#define CONTAINER_SIZE_INDEX 19
#define BUILD_NUMBER_INDEX 27
#define USER_BUILD_NUMBER_INDEX 29
#define CONTAINER_VERSION_INDEX 32
#define CONTAINER_TYPE_INDEX 33
#define CONTAINER_ID_INDEX 34
// EM_PatchQuery response values
#define CONTAINER_TYPE_CONFIG_DATA_WORD 1
#define CONTAINER_TYPE_RANDOM_DATA_WORD 2
#define CONTAINER_TYPE_RANDOM_DATA_BYTE 3
#define CONTAINER_TYPE_CONFIG_DATA_BYTE 11
// EM_PatchWrite and EM_PatchContine field offsets
#define PATCH_LENGTH_OFFSET 2
// EM_PatchWrite destination memory field offsets
#define PATCH_DEST_MEMORY_OFFSET 3
// EM_PatchWrite and EM_PatchContinue response field offsets
#define HCI_STATUS_OFFSET 6
#define EM_PATCH_STATUS_OFFSET 7
// EM_PatchWrite and EM_PatchContinue Patch Status values
#define EM_PATCH_APPLIED 1
#define EM_PATCH_CONTINUE 2
// Maximum number of attempts to wait for a response from EM9304.
#define EM9304_MAX_ATTEMPTS 100
#define EM9304_ATTEMPT_DELAY_MS 1
#define EM9304_IRAM1_START_ADDRESS 0x20000
// Initialization function error return status.
enum
{
EM9304_INIT_STATUS_SUCCESS,
EM9304_INIT_STATUS_ERROR
} e_em9304_init_status;
//*****************************************************************************
//
// HCI Commands for EM9304
//
//*****************************************************************************
uint8_t g_pui8EM_SleepDisable[] = {0x2D, 0xFC, 0x01, 0x00};
uint8_t g_pui8EM_SetOTPOn[] = {0x2B, 0xFC, 0x01, 0x01};
uint8_t g_pui8EM_SetOTPOff[] = {0x2B, 0xFC, 0x01, 0x00};
uint8_t g_pui8EM_SetIRAMOn[] = {0x2B, 0xFC, 0x01, 0x07};
uint8_t g_pui8EM_PatchQuery[] = {0x34, 0xFC, 0x02, 0x00, 0x00};
uint8_t g_pui8EM_SleepEnable[] = {0x2D, 0xFC, 0x01, 0x01};
uint8_t g_pui8EM_CpuReset[] = {0x32, 0xFC, 0x00};
uint32_t
applyEM9304Patches(uint32_t target_memory, uint32_t containerID);
//*****************************************************************************
//
// HCI RX packet buffer for EM9304 Driver.
//
//*****************************************************************************
static uint32_t g_pui32HCIRXBuffer[64];
//*****************************************************************************
//
// Static record of the EM9304 patch errors
//
//*****************************************************************************
uint32_t g_EMPatchErrors = 0;
//*****************************************************************************
//
//! @brief Patch Response helper functions for the EM9304 patches. This
//! routine blocks on a response from the EM9304 and filters the
//! vendor specific events.
//!
//! @return none.
//
//*****************************************************************************
uint32_t
waitEM9304Response(void)
{
uint32_t numBytesRx;
// HCI Respone should return in 1-2 messages at most, but driver returns
// 0 bytes when nothing is available, so wait up to 10msec.
for (uint32_t attempts = 0; attempts < EM9304_MAX_ATTEMPTS; attempts++)
{
numBytesRx = am_devices_em9304_block_read(&g_sEm9304, g_pui32HCIRXBuffer, 0);
// Look for "no message" return while filtering out the EM9304 vendor specific events.
if ((numBytesRx != 0) && (!((numBytesRx == 4) && (0x0000FF04 == (g_pui32HCIRXBuffer[0] & 0x0000FFFF)))))
{
return EM9304_INIT_STATUS_SUCCESS;
}
am_util_delay_ms(EM9304_ATTEMPT_DELAY_MS);
}
return EM9304_INIT_STATUS_ERROR;
}
//*****************************************************************************
//
//! @brief Function to check for valid patches in the em9304_patches.* files.
//! Invalid patches means that the scripts to generate the patch files
//! were run without valid *.emp files as input.
//!
//! @return bool (TRUE = patches are valid).
//
//*****************************************************************************
bool validEM9304Patches(void)
{
//
// Check to see if we have valid patches.
// NULL patch has a specific signature.
//
if ((1 == EM9304_PATCHES_NUM_PATCHES) &&
(0xFFFF == g_pEm9304Patches[0].buildNumber) &&
(0xFFFF == g_pEm9304Patches[0].userBuildNumber) &&
(0xFF == g_pEm9304Patches[0].containerVersion) &&
(0xFF == g_pEm9304Patches[0].containerType) &&
(0xFF == g_pEm9304Patches[0].containerID) &&
(0x00 == g_pEm9304Patches[0].applyPatch) &&
(0x00 == g_pEm9304Patches[0].startingPatch) &&
(0x00 == g_pEm9304Patches[0].endingPatch))
{
am_util_debug_printf("em9304_patches.c contains NULL patch only\n");
return false;
}
else
{
am_util_debug_printf("Valid em9304_patches.c file found\n");
return true;
}
}
//*****************************************************************************
//
//! @brief Function to invalidate a patch at a given address. The size field
//! is changed to corrupt the patch in OTP.
//!
//! @return status.
//
//*****************************************************************************
#ifdef INVALIDATE_UNKNOWN_PATCHES
static uint32_t invalidateEM9304Patch(uint32_t addr, uint32_t size)
{
uint8_t *bytePtr = (uint8_t *)&g_pui32HCIRXBuffer;
uint8_t payload[] =
{
0x22, 0xFC, //WriteAtAddr command
0x0C, //HCI param length
0, 0, 0, 0, // container address placeholder
0x33, 0x39, 0x6D, 0x65, //signature
0, 0, 0, 0 //size placeholder
};
payload[3] = (uint8_t)(addr & 0xFF);
payload[4] = (uint8_t)((addr & 0xFF00) >> 8);
payload[5] = (uint8_t)((addr & 0xFF0000) >> 16);
payload[6] = (uint8_t)((addr & 0xFF000000) >> 24);
size |= 0x36000000; // mask the size to change the patch (invalidate it).
payload[11] = (uint8_t)(size & 0xFF);
payload[12] = (uint8_t)((size & 0xFF00) >> 8);
payload[13] = (uint8_t)((size & 0xFF0000) >> 16);
payload[14] = (uint8_t)((size & 0xFF000000) >> 24);
am_devices_em9304_block_write(&g_sEm9304, HCI_CMD_TYPE, payload, sizeof(payload));
if ((EM9304_INIT_STATUS_SUCCESS != waitEM9304Response()) || (bytePtr[HCI_STATUS_OFFSET] != 0))
{
am_util_debug_printf("Invalidating patch at %x status %d\n", addr, bytePtr[HCI_STATUS_OFFSET]);
return EM9304_INIT_STATUS_ERROR;
}
am_util_debug_printf("Invalidating patch at %x status OK\n", addr);
return EM9304_INIT_STATUS_SUCCESS;
}
#endif
//*****************************************************************************
//
//! @brief Query the EM9304 patches. This routine uses the EM_PatchQuery HCI
//! command to interogate the connected EM9304 about its current patch
//! state and then update the patch Container Info data structure.
//!
//! @return status.
//
//*****************************************************************************
uint32_t
queryEM9304Patches(void)
{
uint32_t containerCount;
uint32_t buildNumber, userBuildNumber, containerVersion, containerType, containerID;
#ifdef INVALIDATE_UNKNOWN_PATCHES
uint32_t containerAddr, containerSize;
bool invalidatePatch = false;
#endif
uint8_t *pBuf = (uint8_t *)g_pui32HCIRXBuffer;
// Initialize the container info patch status
for (uint32_t patch = 0; patch < EM9304_PATCHES_NUM_PATCHES; patch++)
{
// Check patch for enabling 32Khz clck from Apollo MCU
if ((g_pEm9304Patches[patch].userBuildNumber == 2) && (g_pEm9304Patches[patch].containerID == SLEEP_CLK_PATCH_CONTAINER_ID))
{
uint32_t ui32PN;
//
// Device identification
//
ui32PN = AM_REG(MCUCTRL, CHIP_INFO) &
AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_PN_M;
#ifdef ENABLE_32K_CLK_FROM_APOLLO
// Currently only enable this for Apollo2-Blue
if (ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLOBL)
{
g_pEm9304Patches[patch].applyPatch = true;
// GPIO 24 in Apollo2-blue connected to LFCLK in EM9304
am_hal_gpio_pin_config(24, AM_HAL_PIN_24_CLKOUT);
am_hal_clkgen_osc_start(AM_HAL_CLKGEN_OSC_XT);
am_util_delay_ms(500);
am_hal_clkgen_clkout_enable(AM_HAL_CLKGEN_CLKOUT_CKSEL_XT);
}
#endif
}
else
{
g_pEm9304Patches[patch].applyPatch = true;
}
}
// Send the EM_SetSleepOptions command to disable sleep and check the response.
am_devices_em9304_block_write(&g_sEm9304, HCI_CMD_TYPE, g_pui8EM_SleepDisable, sizeof(g_pui8EM_SleepDisable));
if (EM9304_INIT_STATUS_SUCCESS != waitEM9304Response())
{
am_util_debug_printf("No Response to EM9304 Sleep Disable\n");
return EM9304_INIT_STATUS_ERROR;
}
// Check that the response is to the Sleep Disable.
if ((0x01040E04 != g_pui32HCIRXBuffer[0]) || (0x0000FC2D != (g_pui32HCIRXBuffer[1] & 0x0000FFFF)))
{
am_util_debug_printf("Invalid Response to EM9304 Sleep Disable\n");
return EM9304_INIT_STATUS_ERROR;
}
// Send the EM_SetMemoryMode command to turn on OTP and check the response.
am_devices_em9304_block_write(&g_sEm9304, HCI_CMD_TYPE, g_pui8EM_SetOTPOn, sizeof(g_pui8EM_SetOTPOn));
if (EM9304_INIT_STATUS_SUCCESS != waitEM9304Response())
{
am_util_debug_printf("No Response to EM9304 OTP Enable\n");
return EM9304_INIT_STATUS_ERROR;
}
// Check that the response is to the OTP enable.
if ((0x01040E04 != g_pui32HCIRXBuffer[0]) || (0x0000FC2B != (g_pui32HCIRXBuffer[1] & 0x0000FFFF)))
{
am_util_debug_printf("Invalid Response to EM9304 OTP Enable\n");
return EM9304_INIT_STATUS_ERROR;
}
// Query the EM9304 with the EM_PatchQuery and Patch Index = 0. This will return the Container Count.
am_devices_em9304_block_write(&g_sEm9304, HCI_CMD_TYPE, g_pui8EM_PatchQuery, sizeof(g_pui8EM_PatchQuery));
if (EM9304_INIT_STATUS_SUCCESS != waitEM9304Response())
{
am_util_debug_printf("No Response to EM9304 Patch Query\n");
return EM9304_INIT_STATUS_ERROR;
}
// Check that the response is to the Patch Query.
if ((0x01200E04 != g_pui32HCIRXBuffer[0]) || (0x0000FC34 != (g_pui32HCIRXBuffer[1] & 0x0000FFFF)))
{
am_util_debug_printf("Invalid Response to EM9304 Patch Query\n");
return EM9304_INIT_STATUS_ERROR;
}
// Extract the container information from the query response.
containerCount = (uint32_t)pBuf[CONTAINER_COUNT_INDEX] +
((uint32_t)pBuf[CONTAINER_COUNT_INDEX + 1] << 8);
// Assume the first patch is the manufacturing trim patch.
// This is the only patch that never should be invalidated.
am_util_debug_printf("Number of patch containers on EM9304 excluding Patch#0: %d\n", containerCount - 1);
#ifdef INVALIDATE_UNKNOWN_PATCHES
#ifdef INVALIDATE_HCI_V6_PATCH_ON_OTP
bool old_patch_invalidated = false;
bool hci_v6_patch_present_on_otp = false;
// For each container in Container Count to see if HCI meta patch v6 patch
// is present
for (uint32_t container = 1; container < containerCount; container++)
{
// Send the EM_PatchQuery for the Container.
g_pui8EM_PatchQuery[PATCH_INDEX_OFFSET] = container;
am_devices_em9304_block_write(&g_sEm9304, HCI_CMD_TYPE, g_pui8EM_PatchQuery, sizeof(g_pui8EM_PatchQuery));
if (EM9304_INIT_STATUS_SUCCESS != waitEM9304Response())
{
am_util_debug_printf("No Response to EM9304 Patch Query\n");
return EM9304_INIT_STATUS_ERROR;
}
containerID = pBuf[CONTAINER_ID_INDEX];
// v6 patch's container ID is 53 in decimal.
if (containerID == HCI_V6_PATCH_CONTAINER_ID)
{
hci_v6_patch_present_on_otp = true;
am_util_debug_printf("HCI v6 patch found in OTP\n");
break;
}
}
if (hci_v6_patch_present_on_otp)
{
// here we have to do code-reset to EM9304
am_hal_gpio_pin_config(HCI_APOLLO_RESET_PIN, AM_HAL_GPIO_OUTPUT);
am_hal_gpio_out_bit_clear(HCI_APOLLO_RESET_PIN);
am_util_delay_ms(10);
am_hal_gpio_out_bit_set(HCI_APOLLO_RESET_PIN);
am_util_delay_ms(20);
// Apply the latest code patch into IRAM in order to invalidate v6 patch in otp
// properly.
applyEM9304Patches(DEST_MEMORY_IRAM, HCI_CURRENT_CODE_PATCH_CONTAINER_ID);
// Send EM_CpuReset HCI command.
am_devices_em9304_block_write(&g_sEm9304, HCI_CMD_TYPE, g_pui8EM_CpuReset, sizeof(g_pui8EM_CpuReset));
// HCI Respone should return in 1-2 messages at most, but driver returns
// 0 bytes when nothing is available, so wait up to 10msec.
for (uint32_t attempts = 0; attempts < EM9304_MAX_ATTEMPTS; attempts++)
{
uint32_t numBytesRx;
numBytesRx = am_devices_em9304_block_read(&g_sEm9304, g_pui32HCIRXBuffer, 0);
if ((numBytesRx == 7) && (0x0000FC32 == (g_pui32HCIRXBuffer[1] & 0x0000FFFF)))
{
am_util_debug_printf("EM9304 CPU Reset Successfully\n");
break;
}
am_util_delay_ms(EM9304_ATTEMPT_DELAY_MS);
}
// Send the EM_SetSleepOptions command to disable sleep and check the response.
am_devices_em9304_block_write(&g_sEm9304, HCI_CMD_TYPE, g_pui8EM_SleepDisable, sizeof(g_pui8EM_SleepDisable));
if (EM9304_INIT_STATUS_SUCCESS != waitEM9304Response())
{
am_util_debug_printf("No Response to EM9304 Sleep Disable\n");
return EM9304_INIT_STATUS_ERROR;
}
// Check that the response is to the Sleep Disable.
if ((0x01040E04 != g_pui32HCIRXBuffer[0]) || (0x0000FC2D != (g_pui32HCIRXBuffer[1] & 0x0000FFFF)))
{
am_util_debug_printf("Invalid Response to EM9304 Sleep Disable\n");
return EM9304_INIT_STATUS_ERROR;
}
// Send the EM_SetMemoryMode command to turn on OTP and check the response.
am_devices_em9304_block_write(&g_sEm9304, HCI_CMD_TYPE, g_pui8EM_SetOTPOn, sizeof(g_pui8EM_SetOTPOn));
if (EM9304_INIT_STATUS_SUCCESS != waitEM9304Response())
{
am_util_debug_printf("No Response to EM9304 OTP Enable\n");
return EM9304_INIT_STATUS_ERROR;
}
// Check that the response is to the OTP enable.
if ((0x01040E04 != g_pui32HCIRXBuffer[0]) || (0x0000FC2B != (g_pui32HCIRXBuffer[1] & 0x0000FFFF)))
{
am_util_debug_printf("Invalid Response to EM9304 OTP Enable\n");
return EM9304_INIT_STATUS_ERROR;
}
// Query the EM9304 with the EM_PatchQuery and Patch Index = 0. This will return the Container Count.
am_devices_em9304_block_write(&g_sEm9304, HCI_CMD_TYPE, g_pui8EM_PatchQuery, sizeof(g_pui8EM_PatchQuery));
if (EM9304_INIT_STATUS_SUCCESS != waitEM9304Response())
{
am_util_debug_printf("No Response to EM9304 Patch Query\n");
return EM9304_INIT_STATUS_ERROR;
}
// Check that the response is to the Patch Query.
if ((0x01200E04 != g_pui32HCIRXBuffer[0]) || (0x0000FC34 != (g_pui32HCIRXBuffer[1] & 0x0000FFFF)))
{
am_util_debug_printf("Invalid Response to EM9304 Patch Query\n");
return EM9304_INIT_STATUS_ERROR;
}
// Extract the container information from the query response.
containerCount = (uint32_t)pBuf[CONTAINER_COUNT_INDEX] +
((uint32_t)pBuf[CONTAINER_COUNT_INDEX + 1] << 8);
// Assume the first patch is the manufacturing trim patch.
// This is the only patch that never should be invalidated.
am_util_debug_printf("Number of patch containers on EM9304 excluding Patch#0: %d\n", containerCount - 1);
}
#endif
#endif
// For each container in Container Count
for (uint32_t container = 1; container < containerCount; container++)
{
// Send the EM_PatchQuery for the Container.
g_pui8EM_PatchQuery[PATCH_INDEX_OFFSET] = container;
am_devices_em9304_block_write(&g_sEm9304, HCI_CMD_TYPE, g_pui8EM_PatchQuery, sizeof(g_pui8EM_PatchQuery));
if (EM9304_INIT_STATUS_SUCCESS != waitEM9304Response())
{
am_util_debug_printf("No Response to EM9304 Patch Query\n");
return EM9304_INIT_STATUS_ERROR;
}
// Extract the container information from the query response.
containerCount = (uint32_t)pBuf[CONTAINER_COUNT_INDEX] +
((uint32_t)pBuf[CONTAINER_COUNT_INDEX + 1] << 8);
buildNumber = (uint32_t)pBuf[BUILD_NUMBER_INDEX] +
((uint32_t)(pBuf[BUILD_NUMBER_INDEX + 1] << 8));
userBuildNumber = (uint32_t)pBuf[USER_BUILD_NUMBER_INDEX] +
((uint32_t)(pBuf[USER_BUILD_NUMBER_INDEX + 1] << 8));
containerVersion = pBuf[CONTAINER_VERSION_INDEX];
containerType = pBuf[CONTAINER_TYPE_INDEX];
containerID = pBuf[CONTAINER_ID_INDEX];
#ifdef INVALIDATE_UNKNOWN_PATCHES
containerAddr = (uint32_t)((pBuf[CONTAINER_ADDR_INDEX + 3] << 24) +
(pBuf[CONTAINER_ADDR_INDEX + 2] << 16) +
(pBuf[CONTAINER_ADDR_INDEX + 1] << 8) +
pBuf[CONTAINER_ADDR_INDEX]);
containerSize = (uint32_t)((pBuf[CONTAINER_SIZE_INDEX + 3] << 24) +
(pBuf[CONTAINER_SIZE_INDEX + 2] << 16) +
(pBuf[CONTAINER_SIZE_INDEX + 1] << 8) +
pBuf[CONTAINER_SIZE_INDEX]);
am_util_debug_printf("Patch #%d: Container Address = %8.8X Container Size = %4.4d Container Type=%d Container ID=%d Container Version=%d Build Number=%d User Build Number=%d\n",
container, containerAddr, containerSize, containerType, containerID, containerVersion, buildNumber, userBuildNumber);
// if patch is on IRAM, we wont' do anything to it.
if (containerAddr & EM9304_IRAM1_START_ADDRESS)
{
continue;
}
// Check for patches that are likely not configuration managed by the customer.
// Avoid invalidating these patches.
if (((CONTAINER_TYPE_CONFIG_DATA_WORD == containerType) ||
(CONTAINER_TYPE_RANDOM_DATA_WORD == containerType) ||
(CONTAINER_TYPE_CONFIG_DATA_BYTE == containerType) ||
(CONTAINER_TYPE_RANDOM_DATA_BYTE == containerType)) &&
((0 == buildNumber) || (3089 == buildNumber)) &&
(0 == userBuildNumber))
{
invalidatePatch = false;
}
else
{
// Initialize the invalidate flag.
invalidatePatch = true;
}
#endif
// For each local patch, compare the Container Version, Container Type, and Container ID to the container info.
for (uint32_t patch = 0; patch < EM9304_PATCHES_NUM_PATCHES; patch++)
{
if ((g_pEm9304Patches[patch].buildNumber == buildNumber) &&
(g_pEm9304Patches[patch].userBuildNumber == userBuildNumber) &&
(g_pEm9304Patches[patch].containerVersion == containerVersion) &&
(g_pEm9304Patches[patch].containerType == containerType) &&
(g_pEm9304Patches[patch].containerID == containerID))
{
g_pEm9304Patches[patch].applyPatch = false; // Patch is already installed, so don't apply.
#ifdef INVALIDATE_UNKNOWN_PATCHES
// Note that we will "re-enable" patches here even if they met the criteria above (which can happen!)
invalidatePatch = false;
#endif
break;
}
}
#ifdef INVALIDATE_UNKNOWN_PATCHES
// Check to see if we need to invalidate the patch.
if (invalidatePatch)
{
invalidateEM9304Patch(containerAddr, containerSize);
// if any old patch on OTP got invalidated, we need to hard-reset em9304
// for the patch not to take effect so that subsequent patch applying can
// work reliably.
old_patch_invalidated = true;
}
#endif
}
#ifdef INVALIDATE_UNKNOWN_PATCHES
#ifdef INVALIDATE_HCI_V6_PATCH_ON_OTP
if (hci_v6_patch_present_on_otp || old_patch_invalidated)
{
// If we has invalidate v6 or other unknown patch on OTP
// we should do a cold reset to em9304 in order to clean
// the previously programmed patch in IRAM.
// here we have to do code-reset to EM9304
am_hal_gpio_pin_config(HCI_APOLLO_RESET_PIN, AM_HAL_GPIO_OUTPUT);
am_hal_gpio_out_bit_clear(HCI_APOLLO_RESET_PIN);
am_util_delay_ms(10);
am_hal_gpio_out_bit_set(HCI_APOLLO_RESET_PIN);
am_util_delay_ms(20);
}
#endif
#endif
// if (DEST_MEMORY_IRAM == EM9304_PATCHES_DEST_MEMORY)
// {
// // Send the EM_SetMemoryMode command to turn off OTP and check the response.
// am_devices_em9304_block_write(&g_sEm9304, HCI_CMD_TYPE, g_pui8EM_SetOTPOff, sizeof(g_pui8EM_SetOTPOff) );
// if (EM9304_INIT_STATUS_SUCCESS != waitEM9304Response())
// {
// am_util_debug_printf("No Response to EM9304 OTP Disable\n");
// return EM9304_INIT_STATUS_ERROR;
// }
// // Check that the response is to the OTP Disable.
// if ((0x01040E04 != g_pui32HCIRXBuffer[0]) || (0x0000FC2B != (g_pui32HCIRXBuffer[1] & 0x0000FFFF)))
// {
// am_util_debug_printf("Invalid Response to EM9304 OTP Disable\n");
// return EM9304_INIT_STATUS_ERROR;
// }
// }
// Send the EM_SetSleepOptions command to disable sleep and check the response.
am_devices_em9304_block_write(&g_sEm9304, HCI_CMD_TYPE, g_pui8EM_SleepEnable, sizeof(g_pui8EM_SleepEnable));
if (EM9304_INIT_STATUS_SUCCESS != waitEM9304Response())
{
am_util_debug_printf("No Response to EM9304 Sleep Enable\n");
return EM9304_INIT_STATUS_ERROR;
}
// Check that the response is to the Sleep Enable.
if ((0x01040E04 != g_pui32HCIRXBuffer[0]) || (0x0000FC2D != (g_pui32HCIRXBuffer[1] & 0x0000FFFF)))
{
am_util_debug_printf("Invalid Response to EM9304 Sleep Enable\n");
return EM9304_INIT_STATUS_ERROR;
}
return EM9304_INIT_STATUS_SUCCESS;
}
//*****************************************************************************
//
//! @brief Apply the EM9304 patches. This routine uses the EM_PatchQuery HCI
//! command to interogate the connected EM9304 about its current patch
//! state and then update the patch Container Info data structure.
//!
//!
//! @return Returns the status of the patch application (< 0 is an error).
//
//*****************************************************************************
uint32_t
applyEM9304Patches(uint32_t target_memory, uint32_t containerID)
{
uint8_t *bytePtr = (uint8_t *)&g_pui32HCIRXBuffer;
uint32_t ui32PN;
g_EMPatchErrors = 0;
//
// Device identification
//
ui32PN = AM_REG(MCUCTRL, CHIP_INFO) &
AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_PN_M;
// only enable clock for Apollo2-blue (maybe later Apollo3 as well)
if (ui32PN == AM_UTIL_MCUCTRL_CHIP_INFO_PARTNUM_APOLLOBL)
{
}
if (DEST_MEMORY_IRAM == target_memory)
{
// Send the EM_SetMemoryMode command to turn on IRAM and check the response.
am_devices_em9304_block_write(&g_sEm9304, HCI_CMD_TYPE, g_pui8EM_SetIRAMOn, sizeof(g_pui8EM_SetIRAMOn));
if (EM9304_INIT_STATUS_SUCCESS != waitEM9304Response())
{
am_util_debug_printf("No Response to EM9304 IRAM Enable\n");
return EM9304_INIT_STATUS_ERROR;
}
// Check that the response is to the IRAM enable.
if ((0x01040E04 != g_pui32HCIRXBuffer[0]) || (0x0000FC2B != (g_pui32HCIRXBuffer[1] & 0x0000FFFF)))
{
am_util_debug_printf("Invalid Response to EM9304 IRAM Enable\n");
return EM9304_INIT_STATUS_ERROR;
}
}
// Loop through the patches and apply those that are not already there.
// For each local patch, compare the Container Version, Container Type, and Container ID to the container info.
for (uint32_t patch = 0; patch < EM9304_PATCHES_NUM_PATCHES; patch++)
{
if ((containerID != 0) && (containerID != (uint32_t)g_pEm9304Patches[patch].containerID))
{
continue;
}
if (g_pEm9304Patches[patch].applyPatch)
{
am_util_debug_printf("Applying Patch #%d: Container Type=%d Container ID=%d Container Version=%d Build Number=%d User Build Number=%d\n",
patch, g_pEm9304Patches[patch].containerType, g_pEm9304Patches[patch].containerID, g_pEm9304Patches[patch].containerVersion,
g_pEm9304Patches[patch].buildNumber, g_pEm9304Patches[patch].userBuildNumber);
for (uint32_t index = g_pEm9304Patches[patch].startingPatch; index < g_pEm9304Patches[patch].endingPatch; index++)
{
if ((index == g_pEm9304Patches[patch].startingPatch) &&
(target_memory != g_pEm9304PatchesHCICmd[index][PATCH_DEST_MEMORY_OFFSET]))
{
// max payload is 64 bytes for patch writing
uint8_t g_pEm9304PatchesHCICmd_temp[80];
memcpy(g_pEm9304PatchesHCICmd_temp, g_pEm9304PatchesHCICmd[index],
g_pEm9304PatchesHCICmd[index][PATCH_LENGTH_OFFSET] + 3);
// change destination memory type
g_pEm9304PatchesHCICmd_temp[PATCH_DEST_MEMORY_OFFSET] = target_memory;
am_devices_em9304_block_write(&g_sEm9304, HCI_CMD_TYPE, (uint8_t *)g_pEm9304PatchesHCICmd_temp,
g_pEm9304PatchesHCICmd_temp[PATCH_LENGTH_OFFSET] + 3);
}
else
{
am_devices_em9304_block_write(&g_sEm9304, HCI_CMD_TYPE, (uint8_t *)g_pEm9304PatchesHCICmd[index],
g_pEm9304PatchesHCICmd[index][PATCH_LENGTH_OFFSET] + 3);
}
if (EM9304_INIT_STATUS_SUCCESS != waitEM9304Response())
{
am_util_debug_printf("No Response to EM9304 Patch Write\n");
return EM9304_INIT_STATUS_ERROR;
}
if ((g_pEm9304PatchesHCICmd[index][0] == 0x27) &&
((bytePtr[EM_PATCH_STATUS_OFFSET] != EM_PATCH_CONTINUE) &&
(bytePtr[EM_PATCH_STATUS_OFFSET] != EM_PATCH_APPLIED)))
{
am_util_debug_printf("Error Response (%d)to EM9304 Patch Write\n", bytePtr[EM_PATCH_STATUS_OFFSET]);
return EM9304_INIT_STATUS_ERROR;
}
else if (g_pEm9304PatchesHCICmd[index][0] == 0x28)
{
if (((index + 1) == g_pEm9304Patches[patch].endingPatch) && (bytePtr[EM_PATCH_STATUS_OFFSET] != EM_PATCH_APPLIED))
{
am_util_debug_printf("Error Response to EM9304 Patch Continue (next to last patch segment)\n");
return EM9304_INIT_STATUS_ERROR;
}
else if (((index + 1) < g_pEm9304Patches[patch].endingPatch) && (bytePtr[EM_PATCH_STATUS_OFFSET] != EM_PATCH_CONTINUE))
{
am_util_debug_printf("Error Response to EM9304 Patch Continue (last patch segment)\n");
return EM9304_INIT_STATUS_ERROR;
}
}
}
}
}
return EM9304_INIT_STATUS_SUCCESS;
}
//*****************************************************************************
//
// Configure the necessary pins and start the EM9304 radio.
//
//*****************************************************************************
uint32_t
initEM9304(void)
{
if (validEM9304Patches())
{
//
// Query the EM9304 for patches
//
if (EM9304_INIT_STATUS_SUCCESS == queryEM9304Patches())
{
//
// Apply the patches not already in the EM9304
//
if (EM9304_INIT_STATUS_SUCCESS != applyEM9304Patches(EM9304_PATCHES_DEST_MEMORY, 0))
{
am_util_debug_printf("EM9304 Patch Application Failed\n");
}
}
else
{
am_util_debug_printf("EM9304 Patching Query Failed. Patch update not applied\n");
}
}
// Send EM_CpuReset HCI command.
am_devices_em9304_block_write(&g_sEm9304, HCI_CMD_TYPE, g_pui8EM_CpuReset, sizeof(g_pui8EM_CpuReset));
// HCI Respone should return in 1-2 messages at most, but driver returns
// 0 bytes when nothing is available, so wait up to 10msec.
for (uint32_t attempts = 0; attempts < EM9304_MAX_ATTEMPTS; attempts++)
{
uint32_t numBytesRx;
numBytesRx = am_devices_em9304_block_read(&g_sEm9304, g_pui32HCIRXBuffer, 0);
if ((numBytesRx == 7) && (0x0000FC32 == (g_pui32HCIRXBuffer[1] & 0x0000FFFF)))
{
am_util_debug_printf("EM9304 CPU Reset Successfully\n");
break;
}
am_util_delay_ms(EM9304_ATTEMPT_DELAY_MS);
}
return EM9304_PATCHES_DEST_MEMORY;
}
@@ -0,0 +1,51 @@
//*****************************************************************************
//
//! @file em9304_init.h
//!
//! @brief Initialization functions for the EM Micro EM9304 BLE radio.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef EM9304_INIT_H
#define EM9304_INIT_H
uint32_t initEM9304(void);
#endif // EM9304_INIT_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,95 @@
//*****************************************************************************
//
//! @file em9304_patches.h
//!
//! @brief This is a generated file.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include <stdint.h>
#include <stdbool.h>
#ifndef EM9304_PATCHES_H
#define EM9304_PATCHES_H
//*****************************************************************************
//
// Length of the binary array in bytes.
//
//*****************************************************************************
#define EM9304_PATCHES_NUM_PATCHES 8
// EM patch destination memory:
// 1 means EM patch will be programmed into OTP if emp file
// was not programmed before.
// 0 means EM patch will be programmed into IRAM each time when
// EM9304 is cold boot.
#define DEST_MEMORY_IRAM 0
#define DEST_MEMORY_OTP 1
#define EM9304_PATCHES_DEST_MEMORY 0
//*****************************************************************************
//
// EM9304 Container Info type
//
//*****************************************************************************
typedef struct
{
uint16_t buildNumber; // Firmware Build Number
uint16_t userBuildNumber; // User defined Build Number (determines patch precedence)
uint8_t containerVersion; // Container Version
uint8_t containerType; // Container Type
uint8_t containerID; // Container ID
bool applyPatch; // Flag to apply this patch.
uint8_t startingPatch; // Starting patch index.
uint8_t endingPatch; // Ending patch index + 1.
} em9304_container_info_t;
//*****************************************************************************
//
// Extracted binary array.
//
//*****************************************************************************
extern em9304_container_info_t g_pEm9304Patches[8];
extern const uint8_t g_pEm9304PatchesHCICmd[131][68];
#endif // EM9304_PATCHES_H
@@ -0,0 +1,321 @@
// ****************************************************************************
//
// ble_menu.c
//! @file
//!
//! @brief Functions for BLE control menu.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include "ble_menu.h"
#include "wsf_types.h"
#include "amdtp_api.h"
#include "app_api.h"
char menuRxData[20];
uint32_t menuRxDataLen = 0;
sBleMenuCb bleMenuCb;
char mainMenuContent[BLE_MENU_ID_MAX][32] = {
"1. BLE_MENU_ID_GAP",
"2. BLE_MENU_ID_GATT",
"3. BLE_MENU_ID_AMDTP",
};
char gapMenuContent[GAP_MENU_ID_MAX][32] = {
"1. Start Scan",
"2. Stop Scan",
"3. Show Scan Results",
"4. Create Connection"
};
char gattMenuContent[GATT_MENU_ID_MAX][32] = {
"1. TBD",
};
char amdtpMenuContent[AMDTP_MENU_ID_MAX][64] = {
"1. Send test data continuously",
"2. Stop sending test data",
"3. Request Server to send",
"4. Request Server to stop sending"
};
static void BleMenuShowMenu(void);
//*****************************************************************************
//
// Transmit delay waits for busy bit to clear to allow
// for a transmission to fully complete before proceeding.
//
//*****************************************************************************
void
uart_transmit_delay(uint32_t ui32Module)
{
//
// Wait until busy bit clears to make sure UART fully transmitted last byte
//
//while ( am_hal_uart_flags_get(ui32Module) & AM_HAL_UART_FR_BUSY );
}
static bool isSelectionHome(void)
{
if (menuRxData[0] == 'h')
{
bleMenuCb.menuId = BLE_MENU_ID_MAIN;
bleMenuCb.prevMenuId = BLE_MENU_ID_MAIN;
bleMenuCb.gapMenuSelected = GAP_MENU_ID_NONE;
return true;
}
return false;
}
static void showScanResults(void)
{
appDevInfo_t *devInfo;
uint8_t num = AppScanGetNumResults();
am_menu_printf("--------------------Scan Results--------------------\r\n");
for (int i = 0; i < num; i++)
{
devInfo = AppScanGetResult(i);
if (devInfo)
{
am_menu_printf("%d : %d %02x%02x%02x%02x%02x%02x \r\n", i, devInfo->addrType,
devInfo->addr[0], devInfo->addr[1], devInfo->addr[2], devInfo->addr[3], devInfo->addr[4], devInfo->addr[5]);
}
}
am_menu_printf("-----------------------------------------------------\r\n");
}
static void handleGAPSlection(void)
{
eGapMenuId id;
if (bleMenuCb.gapMenuSelected == GAP_MENU_ID_NONE)
{
id = (eGapMenuId)(menuRxData[0] - '0');
}
else
{
id = bleMenuCb.gapMenuSelected;
}
switch (id)
{
case GAP_MENU_ID_SCAN_START:
am_menu_printf("scan start\r\n");
AmdtpcScanStart();
break;
case GAP_MENU_ID_SCAN_STOP:
AmdtpcScanStop();
break;
case GAP_MENU_ID_SCAN_RESULTS:
showScanResults();
break;
case GAP_MENU_ID_CONNECT:
if (bleMenuCb.gapMenuSelected == GAP_MENU_ID_NONE)
{
am_menu_printf("choose an idx from scan results to connect:\r\n");
showScanResults();
bleMenuCb.gapMenuSelected = GAP_MENU_ID_CONNECT;
}
else
{
uint8_t idx = menuRxData[0] - '0';
bleMenuCb.gapMenuSelected = GAP_MENU_ID_NONE;
AmdtpcConnOpen(idx);
}
break;
default:
break;
}
}
static void handleAMDTPSlection(void)
{
eAmdtpMenuId id;
id = (eAmdtpMenuId)(menuRxData[0] - '0');
switch (id)
{
case AMDTP_MENU_ID_SEND:
am_menu_printf("send data to server\r\n");
AmdtpcSendTestData();
break;
case AMDTP_MENU_ID_SEND_STOP:
am_menu_printf("send data to server stop\r\n");
AmdtpcSendTestDataStop();
break;
case AMDTP_MENU_ID_SERVER_SEND:
am_menu_printf("request server to send\r\n");
AmdtpcRequestServerSend();
break;
case AMDTP_MENU_ID_SERVER_SEND_STOP:
am_menu_printf("request server to stop\r\n");
AmdtpcRequestServerSendStop();
break;
default:
break;
}
}
static void handleSelection(void)
{
if (isSelectionHome())
{
BleMenuShowMenu();
return;
}
switch (bleMenuCb.menuId)
{
case BLE_MENU_ID_MAIN:
bleMenuCb.menuId = (eBleMenuId)(menuRxData[0] - '0');
BleMenuShowMenu();
break;
case BLE_MENU_ID_GAP:
handleGAPSlection();
break;
case BLE_MENU_ID_GATT:
break;
case BLE_MENU_ID_AMDTP:
handleAMDTPSlection();
break;
default:
am_util_debug_printf("handleSelection() unknown input\n");
break;
}
}
void
BleMenuRx(void)
{
if (menuRxDataLen == 0)
{
return;
}
menuRxData[menuRxDataLen] = '\0';
am_util_debug_printf("BleMenuRx data = %s\n", menuRxData);
handleSelection();
// clear UART rx buffer
memset(menuRxData, 0, sizeof(menuRxData));
menuRxDataLen = 0;
}
static void
BLEMenuShowMainMenu(void)
{
am_menu_printf("--------------------BLE main menu--------------------\r\n");
for (int i = 0; i < BLE_MENU_ID_MAX; i++)
{
am_menu_printf("%s\r\n", mainMenuContent[i]);
uart_transmit_delay(AM_BSP_UART_PRINT_INST);
}
am_menu_printf("hint: use 'h' to do main menu\r\n");
am_menu_printf("-----------------------------------------------------\r\n");
}
static void
BLEMenuShowGAPMenu(void)
{
for (int i = 0; i < GAP_MENU_ID_MAX; i++)
{
am_menu_printf("%s\r\n", gapMenuContent[i]);
uart_transmit_delay(AM_BSP_UART_PRINT_INST);
}
}
static void
BLEMenuShowGATTMenu(void)
{
for (int i = 0; i < GATT_MENU_ID_MAX; i++)
{
am_menu_printf("%s\r\n", gattMenuContent[i]);
uart_transmit_delay(AM_BSP_UART_PRINT_INST);
}
}
static void
BLEMenuShowAMDTPMenu(void)
{
for (int i = 0; i < AMDTP_MENU_ID_MAX; i++)
{
am_menu_printf("%s\r\n", amdtpMenuContent[i]);
uart_transmit_delay(AM_BSP_UART_PRINT_INST);
}
}
static void
BleMenuShowMenu(void)
{
switch (bleMenuCb.menuId)
{
case BLE_MENU_ID_MAIN:
BLEMenuShowMainMenu();
break;
case BLE_MENU_ID_GAP:
BLEMenuShowGAPMenu();
break;
case BLE_MENU_ID_GATT:
BLEMenuShowGATTMenu();
break;
case BLE_MENU_ID_AMDTP:
BLEMenuShowAMDTPMenu();
break;
default:
break;
}
}
void
BleMenuInit(void)
{
bleMenuCb.prevMenuId = BLE_MENU_ID_MAIN;
bleMenuCb.menuId = BLE_MENU_ID_MAIN;
bleMenuCb.gapMenuSelected = GAP_MENU_ID_NONE;
bleMenuCb.gattMenuSelected = GATT_MENU_ID_NONE;
BleMenuShowMenu();
}
@@ -0,0 +1,125 @@
// ****************************************************************************
//
// ble_menu.h
//! @file
//!
//! @brief Functions for BLE control menu.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef BLE_MENU_H
#define BLE_MENU_H
#include "am_util.h"
#include "am_util_stdio.h"
#include "am_bsp.h"
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#ifdef __cplusplus
extern "C"
{
#endif
typedef enum
{
BLE_MENU_ID_MAIN = 0,
BLE_MENU_ID_GAP,
BLE_MENU_ID_GATT,
BLE_MENU_ID_AMDTP,
BLE_MENU_ID_MAX
}eBleMenuId;
typedef enum
{
GAP_MENU_ID_NONE = 0,
GAP_MENU_ID_SCAN_START,
GAP_MENU_ID_SCAN_STOP,
GAP_MENU_ID_SCAN_RESULTS,
GAP_MENU_ID_CONNECT,
GAP_MENU_ID_MAX
}eGapMenuId;
typedef enum
{
GATT_MENU_ID_NONE = 0,
GATT_MENU_ID_TBD,
GATT_MENU_ID_MAX
}eGattMenuId;
typedef enum
{
AMDTP_MENU_ID_NONE = 0,
AMDTP_MENU_ID_SEND,
AMDTP_MENU_ID_SEND_STOP,
AMDTP_MENU_ID_SERVER_SEND,
AMDTP_MENU_ID_SERVER_SEND_STOP,
AMDTP_MENU_ID_MAX
}eAmdtpMenuId;
typedef struct
{
eBleMenuId prevMenuId;
eBleMenuId menuId;
eGapMenuId gapMenuSelected;
eGattMenuId gattMenuSelected;
}sBleMenuCb;
extern char menuRxData[20];
extern uint32_t menuRxDataLen;
extern uint32_t am_menu_printf(const char *pcFmt, ...);
void
BleMenuRx(void);
void
BleMenuInit(void);
#ifdef __cplusplus
}
#endif
#endif // BLE_MENU_H
@@ -0,0 +1,423 @@
//*****************************************************************************
//
//! @file amdtp_common.c
//!
//! @brief This file provides the shared functions for the AMDTP service.
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#include "amdtp_common.h"
#include "amota_crc32.h"
#include "am_util.h"
extern void amdtps_timeout_timer_expired(void *data, UINT16 datalen);
void
resetPkt(amdtpPacket_t *pkt)
{
pkt->offset = 0;
pkt->header.pktType = AMDTP_PKT_TYPE_UNKNOWN;
pkt->len = 0;
}
eAmdtpStatus_t
AmdtpReceivePkt(amdtpCb_t *amdtpCb, amdtpPacket_t *pkt, uint16_t len, uint8_t *pValue)
{
uint8_t dataIdx = 0;
uint32_t calDataCrc = 0;
uint16_t header = 0;
if (pkt->offset == 0 && len < AMDTP_PREFIX_SIZE_IN_PKT)
{
AMDTP_TRC("Invalid packet!!!\n");
AmdtpSendReply(amdtpCb, AMDTP_STATUS_INVALID_PKT_LENGTH, NULL, 0);
return AMDTP_STATUS_INVALID_PKT_LENGTH;
}
// new packet
if (pkt->offset == 0)
{
BT_UNPACK_LE_2_BYTE(&pkt->len, pValue);
BT_UNPACK_LE_2_BYTE(&header, &pValue[2]);
pkt->header.pktType = (header & PACKET_TYPE_BIT_MASK) >> PACKET_TYPE_BIT_OFFSET;
pkt->header.pktSn = (header & PACKET_SN_BIT_MASK) >> PACKET_SN_BIT_OFFSET;
pkt->header.encrypted = (header & PACKET_ENCRYPTION_BIT_MASK) >> PACKET_ENCRYPTION_BIT_OFFSET;
pkt->header.ackEnabled = (header & PACKET_ACK_BIT_MASK) >> PACKET_ACK_BIT_OFFSET;
dataIdx = AMDTP_PREFIX_SIZE_IN_PKT;
if (pkt->header.pktType == AMDTP_PKT_TYPE_DATA)
{
amdtpCb->rxState = AMDTP_STATE_GETTING_DATA;
}
#ifdef AMDTP_DEBUG_ON
AMDTP_TRC("pkt len = 0x%x\n", pkt->len);
AMDTP_TRC("pkt header = 0x%x\n", header);
#endif
AMDTP_TRC("type = %d, sn = %d\n", pkt->header.pktType, pkt->header.pktSn);
AMDTP_TRC("enc = %d, ackEnabled = %d\n", pkt->header.encrypted, pkt->header.ackEnabled);
}
// make sure we have enough space for new data
if (pkt->offset + len - dataIdx > AMDTP_PACKET_SIZE)
{
AMDTP_TRC("not enough buffer size!!!\n");
if (pkt->header.pktType == AMDTP_PKT_TYPE_DATA)
{
amdtpCb->rxState = AMDTP_STATE_RX_IDLE;
}
// reset pkt
resetPkt(pkt);
AmdtpSendReply(amdtpCb, AMDTP_STATUS_INSUFFICIENT_BUFFER, NULL, 0);
return AMDTP_STATUS_INSUFFICIENT_BUFFER;
}
// copy new data into buffer and also save crc into it if it's the last frame in a packet
// 4 bytes crc is included in pkt length
memcpy(pkt->data + pkt->offset, pValue + dataIdx, len - dataIdx);
pkt->offset += (len - dataIdx);
// whole packet received
if (pkt->offset >= pkt->len)
{
uint32_t peerCrc = 0;
//
// check CRC
//
BT_UNPACK_LE_4_BYTE(&peerCrc, pkt->data + pkt->len - AMDTP_CRC_SIZE_IN_PKT);
calDataCrc = AmotaCrc32(0xFFFFFFFFU, pkt->len - AMDTP_CRC_SIZE_IN_PKT, pkt->data);
#ifdef AMDTP_DEBUG_ON
AMDTP_TRC("calDataCrc = 0x%x\n", calDataCrc);
AMDTP_TRC("peerCrc = 0x%x\n", peerCrc);
AMDTP_TRC("len: %d\n", pkt->len);
#endif
if (peerCrc != calDataCrc)
{
AMDTP_TRC("crc error\n");
if (pkt->header.pktType == AMDTP_PKT_TYPE_DATA)
{
amdtpCb->rxState = AMDTP_STATE_RX_IDLE;
}
// reset pkt
resetPkt(pkt);
AmdtpSendReply(amdtpCb, AMDTP_STATUS_CRC_ERROR, NULL, 0);
return AMDTP_STATUS_CRC_ERROR;
}
return AMDTP_STATUS_RECEIVE_DONE;
}
return AMDTP_STATUS_RECEIVE_CONTINUE;
}
//*****************************************************************************
//
// AMDTP packet handler
//
//*****************************************************************************
void
AmdtpPacketHandler(amdtpCb_t *amdtpCb, eAmdtpPktType_t type, uint16_t len, uint8_t *buf)
{
#ifdef AMDTP_DEBUG_ON
AMDTP_TRC("received packet type = %d, len = %d\n", type, len);
#endif
switch(type)
{
case AMDTP_PKT_TYPE_DATA:
//
// data package recevied
//
// record packet serial number
amdtpCb->lastRxPktSn = amdtpCb->rxPkt.header.pktSn;
AmdtpSendReply(amdtpCb, AMDTP_STATUS_SUCCESS, NULL, 0);
if (amdtpCb->recvCback)
{
amdtpCb->recvCback(buf, len);
}
amdtpCb->rxState = AMDTP_STATE_RX_IDLE;
resetPkt(&amdtpCb->rxPkt);
break;
case AMDTP_PKT_TYPE_ACK:
{
eAmdtpStatus_t status = (eAmdtpStatus_t)buf[0];
// stop tx timeout timer
if (BT_TIMER_HANDLE_INIT_VAL != amdtpCb->timeoutTimer)
{
#ifdef AMDTP_DEBUG_ON
API_RESULT retval = API_SUCCESS;
retval = BT_stop_timer (amdtpCb->timeoutTimer);
AMDTP_TRC (
"[AMDTP]: Stopping Timer with result 0x%04X, timer handle %p\n",
retval, amdtpCb->timeoutTimer);
#else
BT_stop_timer (amdtpCb->timeoutTimer);
#endif
amdtpCb->timeoutTimer = BT_TIMER_HANDLE_INIT_VAL;
}
if (amdtpCb->txState != AMDTP_STATE_TX_IDLE)
{
#ifdef AMDTP_DEBUG_ON
AMDTP_TRC("set txState back to idle, state = %d\n", amdtpCb->txState);
#endif
amdtpCb->txState = AMDTP_STATE_TX_IDLE;
}
if (status == AMDTP_STATUS_CRC_ERROR || status == AMDTP_STATUS_RESEND_REPLY)
{
// resend packet
AmdtpSendPacketHandler(amdtpCb);
}
else
{
// increase packet serial number if send successfully
if (status == AMDTP_STATUS_SUCCESS)
{
amdtpCb->txPktSn++;
if (amdtpCb->txPktSn == 16)
{
amdtpCb->txPktSn = 0;
}
}
// packet transfer successful or other error
// reset packet
resetPkt(&amdtpCb->txPkt);
// notify application layer
if (amdtpCb->transCback)
{
amdtpCb->transCback(status);
}
}
resetPkt(&amdtpCb->ackPkt);
}
break;
case AMDTP_PKT_TYPE_CONTROL:
{
eAmdtpControl_t control = (eAmdtpControl_t)buf[0];
uint8_t resendPktSn = buf[1];
if (control == AMDTP_CONTROL_RESEND_REQ)
{
AMDTP_TRC("resendPktSn = %d, lastRxPktSn = %d\n", resendPktSn, amdtpCb->lastRxPktSn);
amdtpCb->rxState = AMDTP_STATE_RX_IDLE;
resetPkt(&amdtpCb->rxPkt);
if (resendPktSn > amdtpCb->lastRxPktSn)
{
AmdtpSendReply(amdtpCb, AMDTP_STATUS_RESEND_REPLY, NULL, 0);
}
else if (resendPktSn == amdtpCb->lastRxPktSn)
{
AmdtpSendReply(amdtpCb, AMDTP_STATUS_SUCCESS, NULL, 0);
}
else
{
AMDTP_ERR("resendPktSn = %d, lastRxPktSn = %d\n", resendPktSn, amdtpCb->lastRxPktSn);
}
}
else
{
AMDTP_TRC("unexpected contrl = %d\n", control);
}
resetPkt(&amdtpCb->ackPkt);
}
break;
default:
break;
}
}
void
AmdtpBuildPkt(amdtpCb_t *amdtpCb, eAmdtpPktType_t type, BOOLEAN encrypted, BOOLEAN enableACK, uint8_t *buf, uint16_t len)
{
uint16_t header = 0;
uint32_t calDataCrc;
amdtpPacket_t *pkt;
if (type == AMDTP_PKT_TYPE_DATA)
{
pkt = &amdtpCb->txPkt;
header = amdtpCb->txPktSn << PACKET_SN_BIT_OFFSET;
}
else
{
pkt = &amdtpCb->ackPkt;
}
//
// Prepare header frame to be sent first
//
// length
pkt->len = len + AMDTP_PREFIX_SIZE_IN_PKT + AMDTP_CRC_SIZE_IN_PKT;
pkt->data[0] = (len + AMDTP_CRC_SIZE_IN_PKT) & 0xff;
pkt->data[1] = ((len + AMDTP_CRC_SIZE_IN_PKT) >> 8) & 0xff;
// header
header = header | (type << PACKET_TYPE_BIT_OFFSET);
if (encrypted)
{
header = header | (1 << PACKET_ENCRYPTION_BIT_OFFSET);
}
if (enableACK)
{
header = header | (1 << PACKET_ACK_BIT_OFFSET);
}
pkt->data[2] = (header & 0xff);
pkt->data[3] = (header >> 8);
// copy data
memcpy(&(pkt->data[AMDTP_PREFIX_SIZE_IN_PKT]), buf, len);
calDataCrc = AmotaCrc32(0xFFFFFFFFU, len, buf);
// add checksum
pkt->data[AMDTP_PREFIX_SIZE_IN_PKT + len] = (calDataCrc & 0xff);
pkt->data[AMDTP_PREFIX_SIZE_IN_PKT + len + 1] = ((calDataCrc >> 8) & 0xff);
pkt->data[AMDTP_PREFIX_SIZE_IN_PKT + len + 2] = ((calDataCrc >> 16) & 0xff);
pkt->data[AMDTP_PREFIX_SIZE_IN_PKT + len + 3] = ((calDataCrc >> 24) & 0xff);
}
//*****************************************************************************
//
// Send Reply to Sender
//
//*****************************************************************************
void
AmdtpSendReply(amdtpCb_t *amdtpCb, eAmdtpStatus_t status, uint8_t *data, uint16_t len)
{
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN] = {0};
eAmdtpStatus_t st;
buf[0] = status;
if (len > 0)
{
memcpy(buf + 1, data, len);
}
st = amdtpCb->ack_sender_func(AMDTP_PKT_TYPE_ACK, false, false, buf, len + 1);
if (st != AMDTP_STATUS_SUCCESS)
{
AMDTP_ERR("AmdtpSendReply status = %d\n", status);
}
}
//*****************************************************************************
//
// Send control message to Receiver
//
//*****************************************************************************
void
AmdtpSendControl(amdtpCb_t *amdtpCb, eAmdtpControl_t control, uint8_t *data, uint16_t len)
{
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN] = {0};
eAmdtpStatus_t st;
buf[0] = control;
if (len > 0)
{
memcpy(buf + 1, data, len);
}
st = amdtpCb->ack_sender_func(AMDTP_PKT_TYPE_CONTROL, false, false, buf, len + 1);
if (st != AMDTP_STATUS_SUCCESS)
{
AMDTP_ERR("AmdtpSendControl status = %d\n", st);
}
}
void
AmdtpSendPacketHandler(amdtpCb_t *amdtpCb)
{
uint16_t transferSize = 0;
uint16_t remainingBytes = 0;
amdtpPacket_t *txPkt = &amdtpCb->txPkt;
API_RESULT retval = API_SUCCESS;
if ( amdtpCb->txState == AMDTP_STATE_TX_IDLE )
{
txPkt->offset = 0;
amdtpCb->txState = AMDTP_STATE_SENDING;
}
if ( txPkt->offset >= txPkt->len )
{
// done sent packet
amdtpCb->txState = AMDTP_STATE_WAITING_ACK;
// start tx timeout timer
if (BT_TIMER_HANDLE_INIT_VAL != amdtpCb->timeoutTimer)
{
retval = BT_stop_timer (amdtpCb->timeoutTimer);
AMDTP_TRC (
"[AMDTP]: Stopping Timer with result 0x%04X, timer handle %p\n",
retval, amdtpCb->timeoutTimer);
amdtpCb->timeoutTimer = BT_TIMER_HANDLE_INIT_VAL;
}
retval = BT_start_timer
(
&amdtpCb->timeoutTimer,
amdtpCb->txTimeout,
amdtps_timeout_timer_expired,
NULL,
0
);
}
else
{
remainingBytes = txPkt->len - txPkt->offset;
transferSize = ((amdtpCb->attMtuSize - 3) > remainingBytes)
? remainingBytes
: (amdtpCb->attMtuSize - 3);
// send packet
amdtpCb->data_sender_func(&txPkt->data[txPkt->offset], transferSize);
txPkt->offset += transferSize;
}
}
@@ -0,0 +1,217 @@
//*****************************************************************************
//
//! @file amdtp_common.h
//!
//! @brief This file provides the shared functions for the AMDTP service.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef AMDTP_COMMON_H
#define AMDTP_COMMON_H
#include "BT_api.h"
//*****************************************************************************
//
// Macro definitions
//
//*****************************************************************************
#define BT_MODULE_BIT_MASK_AMDTPS 0x00020000
#define BT_MODULE_ID_AMDTPS (BT_MODULE_PAGE_2 | BT_MODULE_BIT_MASK_AMDTPS)
#define AMDTP_ERR(...) BT_debug_error(BT_MODULE_ID_AMDTPS, __VA_ARGS__)
#define AMDTP_TRC(...) BT_debug_trace(BT_MODULE_ID_AMDTPS, __VA_ARGS__)
#define AMDTP_MAX_PAYLOAD_SIZE 2048 //512
#define AMDTP_PACKET_SIZE (AMDTP_MAX_PAYLOAD_SIZE + AMDTP_PREFIX_SIZE_IN_PKT + AMDTP_CRC_SIZE_IN_PKT) // Bytes
#define AMDTP_LENGTH_SIZE_IN_PKT 2
#define AMDTP_HEADER_SIZE_IN_PKT 2
#define AMDTP_CRC_SIZE_IN_PKT 4
#define AMDTP_PREFIX_SIZE_IN_PKT AMDTP_LENGTH_SIZE_IN_PKT + AMDTP_HEADER_SIZE_IN_PKT
#define PACKET_TYPE_BIT_OFFSET 12
#define PACKET_TYPE_BIT_MASK (0xf << PACKET_TYPE_BIT_OFFSET)
#define PACKET_SN_BIT_OFFSET 8
#define PACKET_SN_BIT_MASK (0xf << PACKET_SN_BIT_OFFSET)
#define PACKET_ENCRYPTION_BIT_OFFSET 7
#define PACKET_ENCRYPTION_BIT_MASK (0x1 << PACKET_ENCRYPTION_BIT_OFFSET)
#define PACKET_ACK_BIT_OFFSET 6
#define PACKET_ACK_BIT_MASK (0x1 << PACKET_ACK_BIT_OFFSET)
#define TX_TIMEOUT_DEFAULT 1 // 1 second
#define ATT_DEFAULT_PAYLOAD_LEN 20
//
// amdtp states
//
typedef enum eAmdtpState
{
AMDTP_STATE_INIT,
AMDTP_STATE_TX_IDLE,
AMDTP_STATE_RX_IDLE,
AMDTP_STATE_SENDING,
AMDTP_STATE_GETTING_DATA,
AMDTP_STATE_WAITING_ACK,
AMDTP_STATE_MAX
}eAmdtpState_t;
//
// amdtp packet type
//
typedef enum eAmdtpPktType
{
AMDTP_PKT_TYPE_UNKNOWN,
AMDTP_PKT_TYPE_DATA,
AMDTP_PKT_TYPE_ACK,
AMDTP_PKT_TYPE_CONTROL,
AMDTP_PKT_TYPE_MAX
}eAmdtpPktType_t;
typedef enum eAmdtpControl
{
AMDTP_CONTROL_RESEND_REQ,
AMDTP_CONTROL_MAX
}eAmdtpControl_t;
//
// amdtp status
//
typedef enum eAmdtpStatus
{
AMDTP_STATUS_SUCCESS,
AMDTP_STATUS_CRC_ERROR,
AMDTP_STATUS_INVALID_METADATA_INFO,
AMDTP_STATUS_INVALID_PKT_LENGTH,
AMDTP_STATUS_INSUFFICIENT_BUFFER,
AMDTP_STATUS_UNKNOWN_ERROR,
AMDTP_STATUS_BUSY,
AMDTP_STATUS_TX_NOT_READY, // no connection or tx busy
AMDTP_STATUS_RESEND_REPLY,
AMDTP_STATUS_RECEIVE_CONTINUE,
AMDTP_STATUS_RECEIVE_DONE,
AMDTP_STATUS_MAX
}eAmdtpStatus_t;
//
// packet prefix structure
//
typedef struct
{
uint8_t pktType : 4;
uint8_t pktSn : 4;
uint8_t encrypted : 1;
uint32_t ackEnabled : 1;
uint32_t reserved : 6; // Reserved for future usage
}
amdtpPktHeader_t;
//
// packet
//
typedef struct
{
uint16_t offset;
uint16_t len; // data plus checksum
amdtpPktHeader_t header;
uint8_t *data;
}
amdtpPacket_t;
/*! Application data reception callback */
typedef void (*amdtpRecvCback_t)(uint8_t *buf, uint16_t len);
/*! Application data transmission result callback */
typedef void (*amdtpTransCback_t)(eAmdtpStatus_t status);
typedef void (*amdtp_reply_func_t)(eAmdtpStatus_t status, uint8_t *data, uint16_t len);
typedef void (*amdtp_packet_handler_func_t)(eAmdtpPktType_t type, uint16_t len, uint8_t *buf);
typedef eAmdtpStatus_t (*amdtp_ack_sender_func_t)(eAmdtpPktType_t type, BOOLEAN encrypted, BOOLEAN enableACK, uint8_t *buf, uint16_t len);
typedef void (*amdtp_data_sender_func_t)(uint8_t *buf, uint16_t len);
typedef struct
{
eAmdtpState_t txState;
eAmdtpState_t rxState;
amdtpPacket_t rxPkt;
amdtpPacket_t txPkt;
amdtpPacket_t ackPkt;
uint8_t txPktSn; // data packet serial number for Tx
uint8_t lastRxPktSn; // last received data packet serial number
uint16_t attMtuSize;
BT_timer_handle timeoutTimer; // timeout timer after DTP update done
uint8_t txTimeout; // timeout in second unit
amdtpRecvCback_t recvCback; // application callback for data reception
amdtpTransCback_t transCback; // application callback for tx complete status
amdtp_data_sender_func_t data_sender_func;
amdtp_ack_sender_func_t ack_sender_func;
}
amdtpCb_t;
//*****************************************************************************
//
// function definitions
//
//*****************************************************************************
void
AmdtpBuildPkt(amdtpCb_t *amdtpCb, eAmdtpPktType_t type, BOOLEAN encrypted, BOOLEAN enableACK, uint8_t *buf, uint16_t len);
eAmdtpStatus_t
AmdtpReceivePkt(amdtpCb_t *amdtpCb, amdtpPacket_t *pkt, uint16_t len, uint8_t *pValue);
void
AmdtpSendReply(amdtpCb_t *amdtpCb, eAmdtpStatus_t status, uint8_t *data, uint16_t len);
void
AmdtpSendControl(amdtpCb_t *amdtpCb, eAmdtpControl_t control, uint8_t *data, uint16_t len);
void
AmdtpSendPacketHandler(amdtpCb_t *amdtpCb);
void
AmdtpPacketHandler(amdtpCb_t *amdtpCb, eAmdtpPktType_t type, uint16_t len, uint8_t *buf);
void
resetPkt(amdtpPacket_t *pkt);
#endif // AMDTP_COMMON_H
@@ -0,0 +1,554 @@
//*****************************************************************************
//
// appl_amdtps.c
//! @file
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file appl_amdtps.c
*
* This file contains the AMDTP application.
* Sample applications detailed below:
* a. The Sensor, as defined by the Sepcification plays the GAP Peripheral
* role.
* b. The Sensor application has following sevice records:
* - GAP
* - GATT
* - Battery
* - Device Information and
* - AMDTP
* [NOTE]: Please see gatt_db.c for more details of the record.
* c. appl_manage_transfer routine takes care of handling peer
* configuration. This handling would be needed:
* - When Peer Configures Measurement Transfer by writting to the
* Characteristic Client Configuration of AMOTA Tx.
* - Subsequent reconnection with bonded device that had already
* configured the device for transfer. Please note it is mandatory
* for GATT Servers to remember the configurations of bonded GATT
* clients.
* In order to ensure the above mentioned configurations are correctly
* handled, the routine, appl_manage_transfer, is therefore called from:
* - gatt_db_amotas_handler and
* - appl_amdtps_connect
* [NOTE]: If link does not have the needed secruity for the service,
* transfer will not be initiated.
*/
/* --------------------------------------------- Header File Inclusion */
#include "appl.h"
#include "am_mcu_apollo.h"
#include "am_bsp.h"
#include "am_util.h"
#ifdef AMDTPS
//*****************************************************************************
//
// Global variables
//
//*****************************************************************************
uint8_t rxPktBuf[AMDTP_PACKET_SIZE];
uint8_t txPktBuf[AMDTP_PACKET_SIZE];
uint8_t ackPktBuf[20];
#if defined(AMDTPS_RXONLY) || defined(AMDTPS_RX2TX)
static int totalLen = 0;
#endif
//*****************************************************************************
//
// Macro definitions
//
//*****************************************************************************
/* Control block */
static struct
{
BOOLEAN txReady; // TRUE if ready to send notifications
AmdtpsCfg_t cfg; // configurable parameters
amdtpCb_t core;
}
amdtpsCb;
/* --------------------------------------------- Static Global Variables */
static GATT_DB_HANDLE appl_amdtps_handle;
static ATT_ATTR_HANDLE appl_tx_hndl;
static ATT_ATTR_HANDLE appl_ack_hndl;
/* --------------------------------------------- Functions */
static bool sendDataContinuously = false;
static uint32_t counter = 0;
static void AmdtpsSendTestData(void)
{
uint8_t data[236] = {0};
eAmdtpStatus_t status;
sendDataContinuously = true;
*((uint32_t*)&(data[0])) = counter;
status = AmdtpsSendPacket(AMDTP_PKT_TYPE_DATA, false, true, data, sizeof(data));
if (status != AMDTP_STATUS_SUCCESS)
{
AMDTP_TRC("[AMDTP]: AmdtpsSendTestData() failed, status = %d\n", status);
}
else
{
counter++;
}
}
void amdtpsDtpRecvCback(uint8_t * buf, uint16_t len)
{
if (buf[0] == 1)
{
AMDTP_TRC("[AMDTP]: send test data\n");
AmdtpsSendTestData();
}
else if (buf[0] == 2)
{
AMDTP_TRC("[AMDTP]: send test data stop\n");
sendDataContinuously = false;
}
}
void amdtpsDtpTransCback(eAmdtpStatus_t status)
{
#ifdef AMDTP_DEBUG_ON
AMDTP_TRC("[AMDTP]: amdtpDtpTransCback =%d\n", status);
#endif
if (status == AMDTP_STATUS_SUCCESS && sendDataContinuously)
{
AmdtpsSendTestData();
}
}
void appl_amdtps_init(void)
{
appl_amdtp_server_reinitialize();
}
void appl_amdtps_connect(APPL_HANDLE * appl_handle)
{
ATT_VALUE value;
UINT16 cli_cnfg;
cli_cnfg = 0;
appl_amdtps_handle.device_id = APPL_GET_DEVICE_HANDLE((*appl_handle));
appl_amdtps_handle.char_id = GATT_CHAR_AMDTP_TX;
appl_amdtps_handle.service_id = GATT_SER_AMDTP_INST;
BT_gatt_db_get_char_val_hndl(&appl_amdtps_handle, &appl_tx_hndl);
BT_gatt_db_get_char_cli_cnfg(&appl_amdtps_handle, &value);
BT_UNPACK_LE_2_BYTE (&cli_cnfg, value.val);
appl_amdtps_handle.char_id = GATT_CHAR_AMDTP_ACK;
BT_gatt_db_get_char_val_hndl(&appl_amdtps_handle, &appl_ack_hndl);
BT_gatt_db_get_char_cli_cnfg(&appl_amdtps_handle, &value);
BT_UNPACK_LE_2_BYTE (&cli_cnfg, value.val);
AMDTP_TRC (
"[APPL]: Fetched Client Configuration (0x%04X) for Device (0x%02X)\n",
cli_cnfg, APPL_GET_DEVICE_HANDLE((*appl_handle)));
appl_manage_trasnfer(appl_amdtps_handle, cli_cnfg);
}
void appl_manage_trasnfer(GATT_DB_HANDLE handle, UINT16 config)
{
APPL_HANDLE appl_handle;
API_RESULT retval;
UCHAR security, ekey_size;
AMDTP_TRC("[AMDTP]: appl_manage_trasnfer+ \n");
/* Get required security for service */
/* Get required security level */
BT_gatt_db_get_service_security (&handle, &security);
/* Get required encryption key size */
BT_gatt_db_get_service_enc_key_size (&handle, &ekey_size);
/* Verify if security requirements are available with the link */
retval = appl_smp_assert_security
(
&handle.device_id,
security,
ekey_size
);
/* Security requirements satisfied? */
if (API_SUCCESS != retval)
{
/* No. Return */
return;
}
/* Security requirements satisfied, go ahead with data transfer */
retval = appl_get_handle_from_device_handle(handle.device_id, &appl_handle);
if (API_SUCCESS != retval)
{
return;
}
if (GATT_CLI_CNFG_NOTIFICATION == config)
{
amdtpsCb.txReady = true;
amdtpsCb.core.txState = AMDTP_STATE_TX_IDLE;
AMDTP_TRC("[AMDTP]: notify registered \n");
#if defined(AMDTPS_TXTEST)
counter = 0;
AmdtpsSendTestData(); //fixme
#endif
}
else if (GATT_CLI_CNFG_DEFAULT == config)
{
amdtpsCb.txReady = false;
AMDTP_TRC("[AMDTP]: notify unregistered \n");
}
else
{
/* Incorrect Configuration */
}
}
//*****************************************************************************
//
// Send Notification to Client
//
//*****************************************************************************
static void amdtpsSendData(uint8_t *buf, uint16_t len)
{
ATT_HANDLE_VALUE_PAIR hndl_val_param;
API_RESULT retval;
APPL_HANDLE appl_handle;
#ifdef AMDTP_DEBUG_ON
AMDTP_TRC("Sending Tx On Handle 0x%04X\n", appl_tx_hndl);
#endif
appl_get_handle_from_device_handle (appl_amdtps_handle.device_id, &appl_handle);
hndl_val_param.handle = appl_tx_hndl;
hndl_val_param.value.val = buf;
hndl_val_param.value.len = len;
retval = BT_att_send_hndl_val_ntf
(
&APPL_GET_ATT_INSTANCE(appl_handle),
&hndl_val_param
);
if (API_SUCCESS != retval)
{
AMDTP_ERR( "[** ERR **]: Failed to send, reason 0x%04X", retval);
}
}
static eAmdtpStatus_t
amdtpsSendAck(eAmdtpPktType_t type, BOOLEAN encrypted, BOOLEAN enableACK, uint8_t *buf, uint16_t len)
{
ATT_HANDLE_VALUE_PAIR hndl_val_param;
API_RESULT retval;
APPL_HANDLE appl_handle;
AmdtpBuildPkt(&amdtpsCb.core, type, encrypted, enableACK, buf, len);
#ifdef AMDTP_DEBUG_ON
AMDTP_TRC("Sending Ack On Handle 0x%04X\n", appl_ack_hndl);
#endif
/* send notification */
appl_get_handle_from_device_handle (appl_amdtps_handle.device_id, &appl_handle);
hndl_val_param.handle = appl_ack_hndl;
hndl_val_param.value.val = amdtpsCb.core.ackPkt.data;
hndl_val_param.value.len = amdtpsCb.core.ackPkt.len;
retval = BT_att_send_hndl_val_ntf
(
&APPL_GET_ATT_INSTANCE(appl_handle),
&hndl_val_param
);
if (API_SUCCESS != retval)
{
AMDTP_ERR( "[** ERR **]: Failed to send measurement, reason 0x%04X", retval);
return AMDTP_STATUS_TX_NOT_READY;
}
return AMDTP_STATUS_SUCCESS;
}
//*****************************************************************************
//
// Timer Expiration handler
//
//*****************************************************************************
void amdtps_timeout_timer_expired(void *data, UINT16 datalen)
{
API_RESULT retval = API_SUCCESS;
uint8_t ack[1];
ack[0] = amdtpsCb.core.txPktSn;
AMDTP_TRC("amdtps tx timeout, txPktSn = %d\n", amdtpsCb.core.txPktSn);
AmdtpSendControl(&amdtpsCb.core, AMDTP_CONTROL_RESEND_REQ, ack, 1);
// fire a timer for receiving an AMDTP_STATUS_RESEND_REPLY ACK
if (BT_TIMER_HANDLE_INIT_VAL != amdtpsCb.core.timeoutTimer)
{
retval = BT_stop_timer (amdtpsCb.core.timeoutTimer);
AMDTP_TRC (
"[AMDTP]: Stopping Timer with result 0x%04X, timer handle %p\n",
retval, amdtpsCb.core.timeoutTimer);
amdtpsCb.core.timeoutTimer = BT_TIMER_HANDLE_INIT_VAL;
}
retval = BT_start_timer
(
&amdtpsCb.core.timeoutTimer,
amdtpsCb.core.txTimeout,
amdtps_timeout_timer_expired,
NULL,
0
);
AMDTP_TRC (
"[AMDTP]: Started Timer with result 0x%04X, timer handle %p\n",
retval, amdtpsCb.core.timeoutTimer);
}
void amdtpsHandleValueCnf(
APPL_HANDLE * appl_handle,
UCHAR * event_data,
UINT16 event_datalen
)
{
ATT_ATTR_HANDLE attr_handle;
BT_UNPACK_LE_2_BYTE(&attr_handle, event_data);
#ifdef AMDTP_DEBUG_ON
AMDTP_TRC("appl_handle 0x%x attr_handle = 0x%x\n", *appl_handle, attr_handle);
#endif
#if !defined(AMDTPS_RXONLY) && !defined(AMDTPS_RX2TX)
if ( attr_handle == appl_tx_hndl )
{
amdtpsCb.txReady = true;
// process next data
AmdtpSendPacketHandler(&amdtpsCb.core);
#ifdef AMDTPS_TXTEST
// fixme when last packet, continue to send next one.
if (amdtpsCb.core.txState == AMDTP_STATE_WAITING_ACK)
{
uint8_t temp[3];
temp[0] = AMDTP_STATUS_SUCCESS;
AmdtpPacketHandler(&amdtpsCb.core, AMDTP_PKT_TYPE_ACK, 3, temp);
}
#endif
}
#endif
}
void amdtps_mtu_update(APPL_HANDLE * appl_handle, UINT16 t_mtu)
{
UINT16 mtu = 0;
BT_att_access_mtu(&APPL_GET_ATT_INSTANCE(*appl_handle),
&mtu);
AMDTP_TRC("appl_handle 0x%x t_mtu = %d %d\n", *appl_handle, t_mtu, mtu);
}
void appl_amdtp_server_reinitialize(void)
{
API_RESULT retval = API_SUCCESS;
memset(&amdtpsCb, 0, sizeof(amdtpsCb));
amdtpsCb.txReady = false;
amdtpsCb.core.txState = AMDTP_STATE_INIT;
amdtpsCb.core.rxState = AMDTP_STATE_RX_IDLE;
amdtpsCb.core.lastRxPktSn = 0;
amdtpsCb.core.txPktSn = 0;
resetPkt(&amdtpsCb.core.rxPkt);
amdtpsCb.core.rxPkt.data = rxPktBuf;
resetPkt(&amdtpsCb.core.txPkt);
amdtpsCb.core.txPkt.data = txPktBuf;
resetPkt(&amdtpsCb.core.ackPkt);
amdtpsCb.core.ackPkt.data = ackPktBuf;
amdtpsCb.core.recvCback = amdtpsDtpRecvCback;
amdtpsCb.core.transCback = amdtpsDtpTransCback;
amdtpsCb.core.data_sender_func = amdtpsSendData;
amdtpsCb.core.ack_sender_func = amdtpsSendAck;
amdtpsCb.core.txTimeout = TX_TIMEOUT_DEFAULT;
if (BT_TIMER_HANDLE_INIT_VAL != amdtpsCb.core.timeoutTimer)
{
retval = BT_stop_timer (amdtpsCb.core.timeoutTimer);
AMDTP_TRC (
"[AMDTP]: Stopping Timer with result 0x%04X, timer handle %p\n",
retval, amdtpsCb.core.timeoutTimer);
amdtpsCb.core.timeoutTimer = BT_TIMER_HANDLE_INIT_VAL;
}
#if defined(AMDTPS_RXONLY) || defined(AMDTPS_RX2TX)
AMDTP_TRC("*** RECEIVED TOTAL %d ***\n", totalLen);
totalLen = 0;
#endif
}
API_RESULT appl_amdtps_write_cback
(
GATT_DB_HANDLE * handle,
ATT_VALUE * value
)
{
API_RESULT retval = API_SUCCESS;
eAmdtpStatus_t status = AMDTP_STATUS_UNKNOWN_ERROR;
amdtpPacket_t *pkt = NULL;
#if 0
uint16_t i = 0;
AMDTP_TRC("============= data arrived start ===============\n");
for (i = 0; i < value->len; i++)
{
AMDTP_TRC("%x\t", value->val[i]);
}
AMDTP_TRC("============= data arrived end ===============\n");
#endif
if (GATT_CHAR_AMDTP_RX == handle->char_id)
{
#if defined(AMDTPS_RX2TX)
amdtpsSendData(value->val, value->len);
#endif
#if defined(AMDTPS_RXONLY) || defined(AMDTPS_RX2TX)
totalLen += value->len;
AMDTP_TRC("received data len %d, total %d\n", value->len, totalLen);
return API_SUCCESS;
#else /* RXONLY && RX2TX */
status = AmdtpReceivePkt(&amdtpsCb.core, &amdtpsCb.core.rxPkt, value->len, value->val);
#endif
}
else if (GATT_CHAR_AMDTP_ACK == handle->char_id)
{
status = AmdtpReceivePkt(&amdtpsCb.core, &amdtpsCb.core.ackPkt, value->len, value->val);
}
if (status == AMDTP_STATUS_RECEIVE_DONE)
{
if (GATT_CHAR_AMDTP_RX == handle->char_id)
{
pkt = &amdtpsCb.core.rxPkt;
}
else if (GATT_CHAR_AMDTP_ACK == handle->char_id)
{
pkt = &amdtpsCb.core.ackPkt;
}
AmdtpPacketHandler(&amdtpsCb.core, (eAmdtpPktType_t)pkt->header.pktType, pkt->len - AMDTP_CRC_SIZE_IN_PKT, pkt->data);
}
return retval;
}
//*****************************************************************************
//
//! @brief Send data to Client via notification
//!
//! @param type - packet type
//! @param encrypted - is packet encrypted
//! @param enableACK - does client need to response
//! @param buf - data
//! @param len - data length
//!
//! @return status
//
//*****************************************************************************
eAmdtpStatus_t
AmdtpsSendPacket(eAmdtpPktType_t type, BOOLEAN encrypted, BOOLEAN enableACK, uint8_t *buf, uint16_t len)
{
//
// Check if ready to send notification
//
if ( !amdtpsCb.txReady )
{
//set in callback amdtpsHandleValueCnf
AMDTP_TRC("data sending failed, not ready for notification.\n", NULL);
return AMDTP_STATUS_TX_NOT_READY;
}
//
// Check if the service is idle to send
//
if ( amdtpsCb.core.txState != AMDTP_STATE_TX_IDLE )
{
AMDTP_TRC("data sending failed, tx state = %d\n", amdtpsCb.core.txState);
return AMDTP_STATUS_BUSY;
}
//
// Check if data length is valid
//
if ( len > AMDTP_MAX_PAYLOAD_SIZE )
{
AMDTP_TRC("data sending failed, exceed maximum payload, len = %d.\n", len);
return AMDTP_STATUS_INVALID_PKT_LENGTH;
}
AmdtpBuildPkt(&amdtpsCb.core, type, encrypted, enableACK, buf, len);
// send packet
AmdtpSendPacketHandler(&amdtpsCb.core);
return AMDTP_STATUS_SUCCESS;
}
#endif /* AMDTPS */
@@ -0,0 +1,102 @@
//*****************************************************************************
//
// appl_amdtps.h
//! @file
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file appl_amdtps.h
*
* Application Header File for AMDTPS.
*/
#ifndef _H_APPL_AMDTPS_
#define _H_APPL_AMDTPS_
/* ----------------------------------------- Header File Inclusion */
#include "BT_api.h"
#include "BT_gatt_db_api.h"
#include "gatt_db.h"
#include "appl.h"
#include "amdtp_common.h"
//*****************************************************************************
//
// Macro definitions
//
//*****************************************************************************
/*! Configurable parameters */
typedef struct
{
//! Short description of each member should go here.
uint32_t reserved;
}
AmdtpsCfg_t;
/* --------------------------------------------- Functions */
void appl_amdtps_init(void);
void appl_manage_trasnfer(GATT_DB_HANDLE handle, UINT16 config);
void appl_amdtps_connect(DEVICE_HANDLE * dq_handle);
void appl_amdtp_server_reinitialize(void);
API_RESULT appl_amdtps_write_cback(GATT_DB_HANDLE *handle, ATT_VALUE *value);
eAmdtpStatus_t AmdtpsSendPacket(eAmdtpPktType_t type, BOOLEAN encrypted, BOOLEAN enableACK, uint8_t *buf, uint16_t len);
void amdtpsHandleValueCnf( APPL_HANDLE * appl_handle, UCHAR * event_data, UINT16 event_datalen);
void amdtps_mtu_update(APPL_HANDLE * appl_handle, UINT16 t_mtu);
/* Profile handling */
#define APPL_PROFILE_INIT(...) appl_amdtps_init()
#define APPL_PROFILE_CONNECT(x) appl_amdtps_connect(x)
#define APPL_SEND_MEASUREMENT(x)
#define APPL_PROFILE_DISCONNECT_HANDLER(x) appl_amdtp_server_reinitialize()
#define GATT_DB_PROFILE_HANDLER gatt_db_amdtps_handler
#define APPL_PROFILE_HVN_NTF_COMPLETE_HANDLER(x, y, z) amdtpsHandleValueCnf(x, y, z)
#define APPL_PROFILE_HVN_IND_COMPLETE_HANDLER(x, y, z) amdtpsHandleValueCnf(x, y, z)
#define APPL_PROFILE_MTU_UPDT_COMPLETE_HANDLER(x, y) amdtps_mtu_update(x, y)
#define APPL_USE_IDLE_TIMER
#define APPL_IDLE_TIMEOUT 30
#endif /* _H_APPL_AMDTPS_ */
@@ -0,0 +1,221 @@
//*****************************************************************************
//
// appl_gap_config_params.c
//! @file
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file appl_gap_config_params.c
*
* This file contains GAP Configuration Parameters used by the application.
*/
/* --------------------------------------------- Header File Inclusion */
#include "appl_gap.h"
#ifdef AMDTPS
/* --------------------------------------------- External Global Variables */
/* --------------------------------------------- Exported Global Variables */
/* --------------------------------------------- Static Global Variables */
#if ((defined APPL_GAP_BROADCASTER_SUPPORT) || (defined APPL_GAP_PERIPHERAL_SUPPORT))
/** Advertisement Data Options */
const APPL_GAP_ADV_DATA appl_gap_adv_data[APPL_GAP_MAX_ADV_DATA_OPTIONS] =
{
/* GAP Advertisement Parameters */
{
{
/**
* Flags:
* 0x01: LE Limited Discoverable Mode
* 0x02: LE General Discoverable Mode
* 0x04: BR/EDR Not Supported
* 0x08: Simultaneous LE and BR/EDR to Same Device
* Capable (Controller)
* 0x10: Simultaneous LE and BR/EDR to Same Device
* Capable (Host)
*/
0x02, 0x01,
(BT_AD_FLAGS_LE_GENERAL_DISC_MODE | BT_AD_FLAGS_LE_BR_EDR_SUPPORT),
/**
* Service UUID List:
* Battery Service (0x180F)
* DeviceInformation Service (0x180A)
* Heart Rate Service (0x180D)
*/
0x07, 0x03, 0x0F, 0x18, 0x0A, 0x18, 0x0D, 0x18,
/**
* Shortened Device Name: Mindtree
*/
0x09, 0x08, 0x4D, 0x69, 0x6E, 0x64, 0x74, 0x72, 0x65, 0x65
},
21
}
};
/* Advertisement parameters options */
const APPL_GAP_ADV_PARAM appl_gap_adv_param[APPL_GAP_MAX_ADV_PARAM_OPTIONS] =
{
/* 0 - Normal Advertising Params */
{
32,
32,
7,
0
},
/* 1 - Fast Connection Advertising Params */
{
32,
48,
7,
0
},
/* 2 - Low Power Advertising Params */
{
1600,
4000,
7,
0
}
};
/* Advertisement Table */
APPL_GAP_ADV_INFO appl_gap_adv_table =
{
appl_gap_adv_data,
appl_gap_adv_param,
APPL_GAP_ADV_IDLE
};
#endif /* APPL_GAP_BROADCASTER || APPL_GAP_PERIPHERAL_SUPPORT */
#if ((defined APPL_GAP_OBSERVER_SUPPORT) || (defined APPL_GAP_CENTRAL_SUPPORT))
/* Scan Parameters Option */
const APPL_GAP_SCAN_PARAM appl_gap_scan_param[APPL_GAP_MAX_SCAN_PARAM_OPTIONS] =
{
/* Normal Scan Params */
{
32,
7,
0
},
/* Fast Connection Scan Params */
{
48,
7,
0
},
/* Low Power Scan Params */
{
4000,
7,
0
}
};
/* Scan Table */
APPL_GAP_SCAN_INFO appl_gap_scan_table =
{
appl_gap_scan_param,
APPL_GAP_SCAN_IDLE
};
#endif /* APPL_GAP_OBSERVER_SUPPORT || APPL_GAP_CENTRAL_SUPPORT */
#ifdef APPL_GAP_CENTRAL_SUPPORT
/* Connection Parameters Options */
const APPL_GAP_CONN_PARAM appl_gap_conn_param[APPL_GAP_MAX_CONN_PARAM_OPTIONS] =
{
{
4,
4,
0,
40,
56,
0,
955,
32,
32
}
};
/* GAP Connection Table */
APPL_GAP_CONN_INFO appl_gap_conn_table =
{
appl_gap_conn_param,
APPL_GAP_CONN_IDLE
};
#endif /* APPL_GAP_CENTRAL_SUPPORT */
#endif /* AMDTPS */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,161 @@
//*****************************************************************************
//
// gatt_db.h
//! @file
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file gatt_db.h
*/
#ifndef _H_GATT_DB_
#define _H_GATT_DB_
/**
* addgroup gatt_db_module
*/
/**
* defgroup gatt_db_tuneable_param Tuneable Parameters
* {
* This section defines the Tuneable Constants of Data Base Module.
*/
/** Number of Characteristics in the data base */
#define GATT_CHARACTERISTIC_COUNT 16
/** Number of Services in the data base */
#define GATT_SERVICE_COUNT 5
/** Number of Characteristics that are configurable by the client */
#define GATT_DB_MAX_CONFIGUREABLE_CHAR 4
/** Maximum Length of any Characteristic Value/Descriptor */
#define GATT_DB_MAX_VAL_LENGTH 32
#define GATT_VALUE_ARRAY_SIZE 1
#define GATT_CONST_VALUE_ARRAY_SIZE 245
#define GATT_DB_PEER_VALUE_ARRAY_SIZE 8
#define GATT_DB_MAX_ATTRIBUTES 43
#define GATT_UUID_ARRAY_SIZE 118
#define GATT_DB_MAX_TYPE_COUNT 25
#define GATT_DB_MAX_PEER_CONFIGURATION \
(GATT_DB_PEER_VALUE_ARRAY_SIZE * BT_MAX_DEVICE_QUEUE_SIZE)
/** \} */
/** Service Instance Reference */
/** GAP Service */
#define GATT_SER_GAP_INST 0
/** GATT Service */
#define GATT_SER_GATT_INST 1
/** Battery Service */
#define GATT_SER_BATTERY_INST 2
/** DeviceInformation Service */
#define GATT_SER_DEV_INFO_INST 3
/** AMDTP Service */
#define GATT_SER_AMDTP_INST 4
/** Characteristic Instance Reference */
/** DeviceName */
#define GATT_CHAR_DEV_NAME_INST 0
/** Appearance */
#define GATT_CHAR_APPEARANCE_INST 1
/** Service Changed */
#define GATT_CHAR_SER_CHNGD_INST 2
/** BatteryLevel */
#define GATT_CHAR_BATTERY_LVL_INST 3
/** ManufacturerName */
#define GATT_CHAR_MAN_NAME_INST 4
/** ModelNumber */
#define GATT_CHAR_MODEL_NO_INST 5
/** SerialNumber */
#define GATT_CHAR_SL_NO_INST 6
/** FirmwareRevision */
#define GATT_CHAR_FW_REV_INST 7
/** HardwareRevision */
#define GATT_CHAR_HW_REV_INST 8
/** SoftwareRevision */
#define GATT_CHAR_SW_REV_INST 9
/** SystemId */
#define GATT_CHAR_SYS_ID_INST 10
/** RegCertDataList */
#define GATT_CHAR_REG_CERT_DATA_INST 11
/** PnPID */
#define GATT_CHAR_PNP_ID_INST 12
/** AMDTP Rx */
#define GATT_CHAR_AMDTP_RX 13
/** AMDTP Tx */
#define GATT_CHAR_AMDTP_TX 14
/** AMDTP Ack */
#define GATT_CHAR_AMDTP_ACK 15
#endif /* _H_GATT_DB_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,113 @@
//*****************************************************************************
//
// appl_amota.h
//! @file
//!
//! @brief Application Header File for AMOTA.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file appl_amota.h
*
* Application Header File for AMOTA.
*/
#ifndef _H_APPL_AMOTA_
#define _H_APPL_AMOTA_
/* ----------------------------------------- Header File Inclusion */
#include "BT_api.h"
#include "BT_gatt_db_api.h"
#include "gatt_db.h"
#include "appl.h"
// enable debug print for AMOTA profile
// #define AMOTA_DEBUG_ON
/* --------------------------------------------- Global Definitions */
#define AMOTA_PACKET_SIZE (512 + 16) // Bytes
#define AMOTA_LENGTH_SIZE_IN_PKT 2
#define AMOTA_CMD_SIZE_IN_PKT 1
#define AMOTA_CRC_SIZE_IN_PKT 4
#define AMOTA_HEADER_SIZE_IN_PKT AMOTA_LENGTH_SIZE_IN_PKT + AMOTA_CMD_SIZE_IN_PKT
#define AMOTA_FW_HEADER_SIZE 44
#define AMOTA_FW_STORAGE_INTERNAL 0
#define AMOTA_FW_STORAGE_EXTERNAL 1
/* ----------------------------------------- Data Types/ Structures */
/*! Configurable parameters */
typedef struct
{
//! Short description of each member should go here.
uint32_t reserved;
}
AmotasCfg_t;
/* --------------------------------------------- Functions */
void appl_amotas_init(void);
void appl_manage_trasnfer(GATT_DB_HANDLE handle, UINT16 config);
void appl_amotas_connect(DEVICE_HANDLE * dq_handle);
void appl_amotas_send_data(UCHAR *data, UINT16 len);
void appl_amotas_disconnect(void);
API_RESULT appl_amotas_write_cback(GATT_DB_HANDLE *handle, ATT_VALUE *value);
void amota_mtu_update(APPL_HANDLE * appl_handle, UINT16 t_mtu);
/* Profile handling */
#define APPL_PROFILE_INIT(...) appl_amotas_init()
#define APPL_PROFILE_CONNECT(x) appl_amotas_connect(x)
#define APPL_SEND_MEASUREMENT(x) //appl_send_amotas_measurement(x)
#define APPL_PROFILE_DISCONNECT_HANDLER(x) appl_amotas_disconnect()
#define GATT_DB_PROFILE_HANDLER gatt_db_amotas_handler
#define APPL_PROFILE_HVN_NTF_COMPLETE_HANDLER(x, y, z)
#define APPL_PROFILE_HVN_IND_COMPLETE_HANDLER(x, y, z)
#define APPL_PROFILE_MTU_UPDT_COMPLETE_HANDLER(x, y) amota_mtu_update(x, y)
#define APPL_USE_IDLE_TIMER
#define APPL_IDLE_TIMEOUT 30
#endif /* _H_APPL_AMOTA_ */
@@ -0,0 +1,223 @@
//*****************************************************************************
//
// appl_gap_config_params.c
//! @file
//!
//! @brief This file contains GAP Configuration Parameters used by the application.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file appl_gap_config_params.c
*
* This file contains GAP Configuration Parameters used by the application.
*/
/* --------------------------------------------- Header File Inclusion */
#include "appl_gap.h"
#ifdef AMOTAS
/* --------------------------------------------- External Global Variables */
/* --------------------------------------------- Exported Global Variables */
/* --------------------------------------------- Static Global Variables */
#if ((defined APPL_GAP_BROADCASTER_SUPPORT) || (defined APPL_GAP_PERIPHERAL_SUPPORT))
/** Advertisement Data Options */
const APPL_GAP_ADV_DATA appl_gap_adv_data[APPL_GAP_MAX_ADV_DATA_OPTIONS] =
{
/* GAP Advertisement Parameters */
{
{
/**
* Flags:
* 0x01: LE Limited Discoverable Mode
* 0x02: LE General Discoverable Mode
* 0x04: BR/EDR Not Supported
* 0x08: Simultaneous LE and BR/EDR to Same Device
* Capable (Controller)
* 0x10: Simultaneous LE and BR/EDR to Same Device
* Capable (Host)
*/
0x02, 0x01,
(BT_AD_FLAGS_LE_GENERAL_DISC_MODE | BT_AD_FLAGS_LE_BR_EDR_SUPPORT),
/**
* Service UUID List:
* Battery Service (0x180F)
* DeviceInformation Service (0x180A)
* Heart Rate Service (0x180D)
*/
0x07, 0x03, 0x0F, 0x18, 0x0A, 0x18, 0x0D, 0x18,
/**
* Shortened Device Name: Mindtree
*/
0x09, 0x08, 0x4D, 0x69, 0x6E, 0x64, 0x74, 0x72, 0x65, 0x65
},
21
}
};
/* Advertisement parameters options */
const APPL_GAP_ADV_PARAM appl_gap_adv_param[APPL_GAP_MAX_ADV_PARAM_OPTIONS] =
{
/* 0 - Normal Advertising Params */
{
32,
32,
7,
0
},
/* 1 - Fast Connection Advertising Params */
{
32,
48,
7,
0
},
/* 2 - Low Power Advertising Params */
{
32,
32,
7,
0
}
};
/* Advertisement Table */
APPL_GAP_ADV_INFO appl_gap_adv_table =
{
appl_gap_adv_data,
appl_gap_adv_param,
APPL_GAP_ADV_IDLE
};
#endif /* APPL_GAP_BROADCASTER || APPL_GAP_PERIPHERAL_SUPPORT */
#if ((defined APPL_GAP_OBSERVER_SUPPORT) || (defined APPL_GAP_CENTRAL_SUPPORT))
/* Scan Parameters Option */
const APPL_GAP_SCAN_PARAM appl_gap_scan_param[APPL_GAP_MAX_SCAN_PARAM_OPTIONS] =
{
/* Normal Scan Params */
{
32,
7,
0
},
/* Fast Connection Scan Params */
{
48,
7,
0
},
/* Low Power Scan Params */
{
4000,
7,
0
}
};
/* Scan Table */
APPL_GAP_SCAN_INFO appl_gap_scan_table =
{
appl_gap_scan_param,
APPL_GAP_SCAN_IDLE
};
#endif /* APPL_GAP_OBSERVER_SUPPORT || APPL_GAP_CENTRAL_SUPPORT */
#ifdef APPL_GAP_CENTRAL_SUPPORT
/* Connection Parameters Options */
const APPL_GAP_CONN_PARAM appl_gap_conn_param[APPL_GAP_MAX_CONN_PARAM_OPTIONS] =
{
{
4,
4,
0,
40,
56,
0,
955,
32,
32
}
};
/* GAP Connection Table */
APPL_GAP_CONN_INFO appl_gap_conn_table =
{
appl_gap_conn_param,
APPL_GAP_CONN_IDLE
};
#endif /* APPL_GAP_CENTRAL_SUPPORT */
#endif /* AMOTAS */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,161 @@
//*****************************************************************************
//
// gatt_db.h
//! @file
//!
//! @brief This section defines the Tuneable Constants of Data Base Module.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file gatt_db.h
*/
#ifndef _H_GATT_DB_
#define _H_GATT_DB_
/**
* addgroup gatt_db_module
*/
/**
* defgroup gatt_db_tuneable_param Tuneable Parameters
* {
* This section defines the Tuneable Constants of Data Base Module.
*/
/** Number of Characteristics in the data base */
#define GATT_CHARACTERISTIC_COUNT 15
/** Number of Services in the data base */
#define GATT_SERVICE_COUNT 5
/** Number of Characteristics that are configurable by the client */
#define GATT_DB_MAX_CONFIGUREABLE_CHAR 3
/** Maximum Length of any Characteristic Value/Descriptor */
#define GATT_DB_MAX_VAL_LENGTH 32
#define GATT_VALUE_ARRAY_SIZE 1
#define GATT_CONST_VALUE_ARRAY_SIZE 226
#define GATT_DB_PEER_VALUE_ARRAY_SIZE 6
#define GATT_DB_MAX_ATTRIBUTES 40
#define GATT_UUID_ARRAY_SIZE 102
#define GATT_DB_MAX_TYPE_COUNT 24
#define GATT_DB_MAX_PEER_CONFIGURATION \
(GATT_DB_PEER_VALUE_ARRAY_SIZE * BT_MAX_DEVICE_QUEUE_SIZE)
/** \} */
/** Service Instance Reference */
/** GAP Service */
#define GATT_SER_GAP_INST 0
/** GATT Service */
#define GATT_SER_GATT_INST 1
/** Battery Service */
#define GATT_SER_BATTERY_INST 2
/** DeviceInformation Service */
#define GATT_SER_DEV_INFO_INST 3
/** AMOTA Service */
#define GATT_SER_AMOTA_INST 4
/** Characteristic Instance Reference */
/** DeviceName */
#define GATT_CHAR_DEV_NAME_INST 0
/** Appearance */
#define GATT_CHAR_APPEARANCE_INST 1
/** Service Changed */
#define GATT_CHAR_SER_CHNGD_INST 2
/** BatteryLevel */
#define GATT_CHAR_BATTERY_LVL_INST 3
/** ManufacturerName */
#define GATT_CHAR_MAN_NAME_INST 4
/** ModelNumber */
#define GATT_CHAR_MODEL_NO_INST 5
/** SerialNumber */
#define GATT_CHAR_SL_NO_INST 6
/** FirmwareRevision */
#define GATT_CHAR_FW_REV_INST 7
/** HardwareRevision */
#define GATT_CHAR_HW_REV_INST 8
/** SoftwareRevision */
#define GATT_CHAR_SW_REV_INST 9
/** SystemId */
#define GATT_CHAR_SYS_ID_INST 10
/** RegCertDataList */
#define GATT_CHAR_REG_CERT_DATA_INST 11
/** PnPID */
#define GATT_CHAR_PNP_ID_INST 12
/** AMOTA Rx */
#define GATT_CHAR_AMOTA_RX 13
/** AMOTA Tx */
#define GATT_CHAR_AMOTA_TX 14
#endif /* _H_GATT_DB_ */
@@ -0,0 +1,604 @@
//*****************************************************************************
//
//! @file appl_ams.c
//!
//! @brief Provides functions for the AMS service.
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file appl_ams.c
*
*/
/* --------------------------------------------- Header File Inclusion */
#ifdef AMS
#include "appl.h"
#include "BT_common.h"
#include "BT_hci_api.h"
#include "BT_att_api.h"
#include "BT_smp_api.h"
#include "smp_pl.h"
#include "l2cap.h"
#include "fsm_defines.h"
#include "task.h"
/* ----------------------------------------- Configuration Defines */
extern uint32_t am_util_stdio_printf(const char *pcFmt, ...);
#undef APPL_TRC
#undef APPL_ERR
#define APPL_TRC am_util_stdio_printf
#define APPL_ERR am_util_stdio_printf
/* ----------------------------------------- Macro Defines */
/**@brief Entity IDs */
typedef enum
{
AMS_ENTITY_ID_PLAYER, /** The currently active media app. Attributes for this entity include values such as its name, playback state, and playback volume. */
AMS_ENTITY_ID_QUEUE, /** The currently loaded playback queue. Attributes for this entity include values such as its size and its shuffle and repeat modes. */
AMS_ENTITY_ID_TRACK, /** The currently loaded track. Attributes for this entity include values such as its artist, title, and duration. */
} ams_entity_id_values_t;
/**@brief Player AttributeID */
typedef enum
{
AMS_PLAYER_ATTRID_NAME, /** A string containing the localized name of the app */
AMS_PLAYER_ATTRID_PLAYBACKINFO, /** PlaybackState, PlaybackRate, ElapsedTime */
AMS_PLAYER_ATTRID_VOLUME, /** A string that represents the floating point value of the volume, ranging from 0 (silent) to 1 (full volume). */
} ams_player_attribute_id_values_t;
/**@brief Queue AttributeID */
typedef enum
{
AMS_QUEUE_ATTRID_INDEX, /** A string containing the integer value of the queue index, zero-based. */
AMS_QUEUE_ATTRID_COUNT, /** A string containing the integer value of the total number of items in the queue. */
AMS_QUEUE_ATTRID_SHUFFLE, /** A string containing the integer value of the shuffle mode. */
AMS_QUEUE_ATTRID_REPEAT, /** A string containing the integer value value of the repeat mode. */
} ams_queue_attribute_id_values_t;
/**@brief Track AttributeID */
typedef enum
{
AMS_TRACK_ATTRID_ARTIST, /** A string containing the name of the artist. */
AMS_TRACK_ATTRID_ALBUM, /** A string containing the name of the album. */
AMS_TRACK_ATTRID_TITLE, /** A string containing the title of the track. */
AMS_TRACK_ATTRID_DURATION, /** A string containing the floating point value of the total duration of the track in seconds. */
} ams_track_attribute_id_values_t;
typedef enum
{
AMS_DISCONNECTED,
AMS_CONNECTED,
AMS_BONDED,
AMS_DISCOVERED,
} ams_appl_state_t;
/* ----------------------------------------- External Global Variables */
void appl_profile_operations (void);
void appl_bond_with_peer(void);
void appl_discover_AMS(void);
extern BT_DEVICE_ADDR g_bd_addr;
/* ----------------------------------------- Exported Global Variables */
/* ----------------------------------------- Static Global Variables */
DECL_STATIC UCHAR write_response = 0;
DECL_STATIC API_RESULT gResult = 0;
DECL_STATIC ams_appl_state_t appl_ams_state = AMS_DISCONNECTED;
DECL_STATIC ATT_UUID ams_service_uuid128 = {.uuid_128.value = {0xDC, 0xF8, 0x55, 0xAD, 0x02, 0xC5, 0xF4, 0x8E, 0x3A, 0x43, 0x36, 0x0F, 0x2B, 0x50, 0xD3, 0x89}};
DECL_STATIC ATT_UUID AMS_RemoteCommand_UUID = {.uuid_128.value = {0xC2, 0x51, 0xCA, 0xF7, 0x56, 0x0E, 0xDF, 0xB8, 0x8A, 0x4A, 0xB1, 0x57, 0xD8, 0x81, 0x3C, 0x9B}};
DECL_STATIC ATT_UUID AMS_EntityUpdate_UUID = {.uuid_128.value = {0x02, 0xC1, 0x96, 0xBA, 0x92, 0xBB, 0x0C, 0x9A, 0x1F, 0x41, 0x8D, 0x80, 0xCE, 0xAB, 0x7C, 0x2F}};
DECL_STATIC ATT_UUID AMS_EntityAttribute_UUID = {.uuid_128.value = {0xD7, 0xD5, 0xBB, 0x70, 0xA8, 0xA3, 0xAB, 0xA6, 0xD8, 0x46, 0xAB, 0x23, 0x8C, 0xF3, 0xB2, 0xC6}};
/* BLE Connection Handle */
//DECL_STATIC UINT16 appl_ble_connection_handle;
/** AMS Characteristic related information */
typedef struct
{
/* AMS Service */
/* Remote Command */
ATT_ATTR_HANDLE ams_remote_command_hdl;
/* Remote Command - CCC */
ATT_ATTR_HANDLE ams_remote_command_ccc_hdl;
/* Entity Update */
ATT_ATTR_HANDLE ams_entity_update_hdl;
/* Entity Update - CCC */
ATT_ATTR_HANDLE ams_entity_update_ccc_hdl;
/* Entity Attribute */
ATT_ATTR_HANDLE ams_entity_attribute_hdl;
} AMS_CHAR_INFO;
#define APPL_CLI_CNFG_VAL_LENGTH 2
DECL_STATIC AMS_CHAR_INFO ams_char_info;
#ifdef APPL_MENU_OPS
BT_DEVICE_ADDR g_peer_bd_addr;
static UCHAR ams_client_menu[] =
"\n\
\r\n\
1. Bond with peer \r\n\
\r\n\
2. Discover AMS \r\n\
\r\n\
3. Subscribe to Entity Update \r\n\
\r\n\
4. Write to Entity Update \r\n\
\r\n\
5. Write to Remote Command \r\n\
\r\n\
6. Write to Entity Attribute \r\n\
\r\n\
7. Read Entity Attribute \r\n\
\r\n\
Your Option? \0";
#endif /* APPL_MENU_OPS */
/* --------------------------------------------- Constants */
/* --------------------------------------------- Static Global Variables */
/* --------------------------------------------- Functions */
void appl_bond_with_peer(void)
{
API_RESULT retval;
/* If connection is successful, initiate bonding [Step 2(c)] */
SMP_AUTH_INFO auth;
SMP_BD_ADDR smp_peer_bd_addr;
SMP_BD_HANDLE smp_bd_handle;
APPL_TRC("\n<<appl_bond_with_peer>>\n");
auth.param = 1;
auth.bonding = 1;
auth.ekey_size = 12;
auth.security = SMP_SEC_LEVEL_1;
BT_COPY_BD_ADDR(smp_peer_bd_addr.addr, g_bd_addr.addr);
BT_COPY_TYPE(smp_peer_bd_addr.type, g_bd_addr.type);
retval = BT_smp_get_bd_handle
(
&smp_peer_bd_addr,
&smp_bd_handle
);
if (API_SUCCESS == retval)
{
retval = BT_smp_authenticate (&smp_bd_handle, &auth);
}
if (API_SUCCESS != retval)
{
APPL_TRC (
"Initiation of Authentication Failed. Reason 0x%04X\n",
retval);
}
/**
* Application will receive authentication complete event,
* in SMP Callback.
*
* Look for 'SMP_AUTHENTICATION_COMPLETE' event handling in
* 'appl_smp_callback'.
*/
}
void appl_ams_init(void)
{
appl_ams_state = AMS_DISCONNECTED;
APPL_TRC("\n\n<<appl_ams_init>>\n\n");
}
void appl_ams_connect(APPL_HANDLE * appl_handle)
{
APPL_STATE_T state = GET_APPL_STATE(*appl_handle);
if ( state == SL_0_TRANSPORT_OPERATING && appl_ams_state == AMS_DISCONNECTED )
{
appl_ams_state = AMS_CONNECTED;
APPL_TRC("\n\n<<CONNECTED>>\n\n");
}
else if ( state == SL_0_TRANSPORT_OPERATING && appl_ams_state == AMS_DISCOVERED)
{
appl_ams_state = AMS_BONDED;
APPL_TRC("\n\n<<BONDED>>\n\n");
}
else
{
appl_ams_state = AMS_DISCONNECTED;
APPL_TRC("\n\n<<DISCONNECTED>>\n\n");
}
}
void appl_search_complete(void)
{
appl_ams_state = AMS_DISCOVERED;
APPL_TRC("\n\n<<DISCOVERED>>\n\n");
}
void appl_recvice_att_event(UCHAR att_event, API_RESULT event_result)
{
if ( att_event == ATT_WRITE_RSP )
{
write_response = 1;
gResult = 0;
}
else if ( att_event == ATT_ERROR_RSP )
{
gResult = event_result;
}
}
void appl_manage_trasnfer (GATT_DB_HANDLE handle, UINT16 config)
{
APPL_TRC("\n\n<<appl_manage_trasnfer>>\n\n");
}
void appl_send_ams_measurement (APPL_HANDLE * handle)
{
APPL_TRC("\n\n<<appl_send_ams_measurement>>\n\n");
}
void appl_timer_expiry_handler (void *data, UINT16 datalen)
{
APPL_TRC("\n\n<<appl_timer_expiry_handler>>\n\n");
}
void appl_ams_server_reinitialize (void)
{
appl_ams_state = AMS_DISCONNECTED;
APPL_TRC("\n\n<<appl_ams_server_reinitialize>>\n\n");
}
void ams_mtu_update(APPL_HANDLE * appl_handle, UINT16 t_mtu)
{
UINT16 mtu = 0;
BT_att_access_mtu(&APPL_GET_ATT_INSTANCE(*appl_handle),
&mtu);
APPL_TRC("appl_handle 0x%x t_mtu = %d %d\n", *appl_handle, t_mtu, mtu);
}
/* ------------------------------- ATT related Functions */
void appl_rcv_service_desc (UINT16 config, ATT_UUID uuid, UINT16 value_handle)
{
/* Populate Needed CCCDs here */
if (GATT_CLIENT_CONFIG == config)
{
if ( memcmp(&uuid, &AMS_RemoteCommand_UUID, ATT_128_BIT_UUID_SIZE) == 0 )
{
ams_char_info.ams_remote_command_ccc_hdl = value_handle;
}
else if ( memcmp(&uuid, &AMS_EntityUpdate_UUID, ATT_128_BIT_UUID_SIZE) == 0 )
{
ams_char_info.ams_entity_update_ccc_hdl = value_handle;
}
}
}
void appl_rcv_service_char (ATT_UUID uuid, UINT16 value_handle)
{
if ( memcmp(&uuid, &AMS_RemoteCommand_UUID, ATT_128_BIT_UUID_SIZE) == 0 )
{
ams_char_info.ams_remote_command_hdl = value_handle;
}
else if ( memcmp(&uuid, &AMS_EntityUpdate_UUID, ATT_128_BIT_UUID_SIZE) == 0 )
{
ams_char_info.ams_entity_update_hdl = value_handle;
}
else if ( memcmp(&uuid, &AMS_EntityAttribute_UUID, ATT_128_BIT_UUID_SIZE) == 0 )
{
ams_char_info.ams_entity_attribute_hdl = value_handle;
}
}
void Wait4WrtRsp(void)
{
const TickType_t xDelay = 10 / portTICK_PERIOD_MS;
UCHAR i = 0;
while ( !write_response )
{
vTaskDelay( xDelay );
if (i++ > 10 )
{
break;
}
}
write_response = 0;
}
void appl_discover_AMS(void)
{
APPL_TRC("\n<<appl discover AMS>>\n");
appl_discover_service
(
ams_service_uuid128,
ATT_128_BIT_UUID_FORMAT
);
return;
}
void AmsWrite2EnityUpdate(uint8_t entityID)
{
ATT_VALUE att_value;
uint8_t buf[5];
APPL_TRC("\n++<<AmsWrite2EnityUpdate %d>>\n", entityID);
if ( entityID == AMS_ENTITY_ID_PLAYER )
{
buf[0] = AMS_ENTITY_ID_PLAYER;
buf[1] = AMS_PLAYER_ATTRID_NAME;
buf[2] = AMS_PLAYER_ATTRID_PLAYBACKINFO;
buf[3] = AMS_PLAYER_ATTRID_VOLUME;
att_value.len = 4;
}
else if ( entityID == AMS_ENTITY_ID_QUEUE )
{
buf[0] = AMS_ENTITY_ID_QUEUE;
buf[1] = AMS_QUEUE_ATTRID_INDEX;
buf[2] = AMS_QUEUE_ATTRID_COUNT;
buf[3] = AMS_QUEUE_ATTRID_SHUFFLE;
buf[4] = AMS_QUEUE_ATTRID_REPEAT;
att_value.len = 5;
}
else if ( entityID == AMS_ENTITY_ID_TRACK )
{
buf[0] = AMS_ENTITY_ID_TRACK;
buf[1] = AMS_TRACK_ATTRID_ARTIST;
buf[2] = AMS_TRACK_ATTRID_ALBUM;
buf[3] = AMS_TRACK_ATTRID_TITLE;
buf[4] = AMS_TRACK_ATTRID_DURATION;
att_value.len = 5;
}
else
{
return;
}
att_value.val = buf;
appl_write_req (ams_char_info.ams_entity_update_hdl, &att_value);
Wait4WrtRsp();
APPL_TRC("\n--<<AmsWrite2EnityUpdate %d>>\n", entityID);
}
void AmsWrite2RemoteCommand(uint8_t cmd)
{
ATT_VALUE att_value;
uint8_t buf[1]; // retrieve the complete attribute list
buf[0] = cmd;
att_value.len = 1;
att_value.val = buf;
appl_write_req (ams_char_info.ams_remote_command_hdl, &att_value);
}
void AmsWrite2EntityAttribute(uint8_t entityID, uint8_t attrID)
{
ATT_VALUE att_value;
uint8_t buf[2]; // retrieve the complete attribute list
buf[0] = entityID;
buf[1] = attrID;
att_value.len = 2;
att_value.val = buf;
appl_write_req (ams_char_info.ams_entity_attribute_hdl, &att_value);
}
void AmsSubscribe2EnityUpdate(void)
{
ATT_VALUE att_value;
UINT16 cli_cfg;
UCHAR cfg_val[APPL_CLI_CNFG_VAL_LENGTH];
APPL_TRC("\n++<<AmsSubscribe2EnityUpdate>>\n");
cli_cfg = GATT_CLI_CNFG_NOTIFICATION;
BT_PACK_LE_2_BYTE(cfg_val, &cli_cfg);
att_value.len = APPL_CLI_CNFG_VAL_LENGTH;
att_value.val = cfg_val;
appl_write_req (ams_char_info.ams_entity_update_ccc_hdl, &att_value);
Wait4WrtRsp();
APPL_TRC("\n--<<AmsSubscribe2EnityUpdate(0x%04X)>>\n", gResult);
}
void appl_profile_operations (void)
{
const TickType_t xDelay = 100 / portTICK_PERIOD_MS;
write_response = 0;
fsm_post_event
(
APPL_FSM_ID,
ev_appl_device_init_req,
NULL
);
while ( appl_ams_state != AMS_CONNECTED )
{
vTaskDelay( xDelay );
}
appl_discover_AMS();
while ( appl_ams_state != AMS_DISCOVERED )
{
vTaskDelay( xDelay );
}
AmsSubscribe2EnityUpdate();
if (gResult == 0x0305 /* insufficient authentication */ ||
gResult == 0x030F /* insufficient Encryption */ )
{
appl_bond_with_peer();
while ( appl_ams_state != AMS_BONDED )
{
vTaskDelay( xDelay );
}
AmsSubscribe2EnityUpdate();
}
else
{
appl_ams_state = AMS_BONDED;
}
AmsWrite2EnityUpdate(AMS_ENTITY_ID_PLAYER);
AmsWrite2EnityUpdate(AMS_ENTITY_ID_QUEUE);
AmsWrite2EnityUpdate(AMS_ENTITY_ID_TRACK);
while ( appl_ams_state != AMS_DISCONNECTED )
{
vTaskDelay( xDelay );
}
}
void AmsDumpBytes (UCHAR *buffer, UINT16 length)
{
char hex_stream[49];
char char_stream[17];
UINT32 i;
UINT16 offset, count;
UCHAR c;
APPL_TRC("\n");
APPL_TRC (
"-------------------------------------------------------------------\n");
count = 0;
offset = 0;
for (i = 0; i < length; i ++ )
{
c = buffer[i];
sprintf(hex_stream + offset, "%02X ", c);
if ( (c >= 0x20) && (c <= 0x7E) )
{
char_stream[count] = c;
}
else
{
char_stream[count] = '.';
}
count ++;
offset += 3;
if ( 16 == count )
{
char_stream[count] = '\0';
count = 0;
offset = 0;
APPL_TRC ("%s %s\n",
hex_stream, char_stream);
BT_mem_set(hex_stream, 0, 49);
BT_mem_set(char_stream, 0, 17);
}
}
if ( offset != 0 )
{
char_stream[count] = '\0';
/* Maintain the alignment */
APPL_TRC ("%-48s %s\n",
hex_stream, char_stream);
}
APPL_TRC (
"-------------------------------------------------------------------\n");
APPL_TRC ("\n");
return;
}
void AmsNotificationCb(UCHAR *event_data, UINT16 event_datalen)
{
AmsDumpBytes(event_data + 2, (event_datalen - 2));
}
void AmsReadRSPCb(UCHAR *event_data, UINT16 event_datalen)
{
ATT_ATTR_HANDLE attr_handle;
BT_UNPACK_LE_2_BYTE(&attr_handle, event_data);
AmsDumpBytes(event_data + 2, (event_datalen - 2));
}
#endif /* AMS */
@@ -0,0 +1,117 @@
//*****************************************************************************
//
//! @file appl_ams.c
//!
//! @brief Application Header File for AMS.
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file appl_ams.h
*
* Application Header File for AMS.
*/
#ifndef _H_APPL_AMS_
#define _H_APPL_AMS_
/* ----------------------------------------- Header File Inclusion */
#include "BT_api.h"
#include "BT_gatt_db_api.h"
#include "gatt_db.h"
#include "appl.h"
#include "appl_ams_att_server.h"
/* ----------------------------------------- Data Types/ Structures */
typedef struct
{
UCHAR index;
UCHAR length;
}APPL_HRS_OBS_DATA_INFO;
/* --------------------------------------------- Global Definitions */
/** LSB of error code has to be spec defined */
#define APPL_HR_CNTRL_PNT_NOT_SUPPORTED (APPL_ERR_ID | 0x80)
/* --------------------------------------------- Functions */
void appl_ams_init(void);
void appl_manage_trasnfer (GATT_DB_HANDLE handle, UINT16 config);
void appl_timer_expiry_handler (void *data, UINT16 datalen);
void appl_ams_connect(DEVICE_HANDLE * dq_handle);
void appl_send_ams_measurement (APPL_HANDLE * handle);
void appl_ams_server_reinitialize (void);
void appl_rcv_service_desc (UINT16 config, ATT_UUID uuid, UINT16 value_handle);
void appl_rcv_service_char (ATT_UUID uuid, UINT16 value_handle);
API_RESULT appl_hr_control_point_handler
(
GATT_DB_HANDLE * handle,
ATT_VALUE * value
);
API_RESULT appl_att_callback
(
ATT_HANDLE * handle,
UCHAR event_type,
API_RESULT event_result,
UCHAR * event_data,
UINT16 event_datalen
);
void ams_mtu_update(APPL_HANDLE * appl_handle, UINT16 t_mtu);
/* Profile handling */
#define APPL_PROFILE_INIT(...) appl_ams_init()
#define APPL_PROFILE_CONNECT(x) appl_ams_connect(x)
#define APPL_SEND_MEASUREMENT(x)appl_send_ams_measurement(x)
#define APPL_PROFILE_DISCONNECT_HANDLER(x) appl_ams_server_reinitialize()
#define GATT_DB_PROFILE_HANDLER gatt_db_ams_handler
#define APPL_PROFILE_HVN_NTF_COMPLETE_HANDLER(x, y, z)
#define APPL_PROFILE_HVN_IND_COMPLETE_HANDLER(x, y, z)
#define APPL_PROFILE_MTU_UPDT_COMPLETE_HANDLER(x, y) ams_mtu_update(x, y)
#define APPL_USE_IDLE_TIMER
#define APPL_IDLE_TIMEOUT 30
#endif /* _H_APPL_AMS_ */
@@ -0,0 +1,158 @@
//*****************************************************************************
//
//! @file appl_ams_att_server.h
//!
//! @brief ATT Server Application Header File
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file appl_ams_att_server.h
*
* ATT Server Application Header File
*/
/*
* Copyright (C) 2013. Mindtree Ltd.
* All rights reserved.
*/
#ifndef _H_APPL_AMS_ATT_SERVER_
#define _H_APPL_AMS_ATT_SERVER_
/* ----------------------------------------- Header File Inclusion */
#include "BT_api.h"
#include "BT_gatt_db_api.h"
#define APPL_ATT_WRITE_QUEUE_SIZE 10
#define APPL_ATT_MAX_WRITE_BUFFER_SIZE 256 /* 255 */
#define APPL_ATT_MTU ATT_MAX_MTU
#define APPL_SERVER_BUFFER_SIZE 256 /* 256 */
#define APPL_MAX_GROUP_TYPE_QUERIED 5
#define APPL_MAX_HNDL_UUID_LIST_SIZE 5
#define APPL_MAX_HNDL_LIST_SIZE 11
#define APPL_MAX_HNDL_VALUE_SIZE 5
/* ATT PDU Request Length */
#define APPL_ATT_XCNHG_MTU_REQ_LEN 2
#define APPL_ATT_XCNHG_MTU_RSP_LEN 2
#define APPL_ATT_FIND_INFO_REQ_LEN 4
#define APPL_ATT_FIND_INFO_RSP_LEN_1 5
#define APPL_ATT_FIND_INFO_RSP_LEN_2 22
#define ATT_FIND_BY_TYPE_VAL_RSP_LEN1 4
#define ATT_FIND_BY_TYPE_VAL_RSP_LEN2 21
#define APPL_ATT_READ_BY_TYPE_REQ_LEN_1 6
#define APPL_ATT_READ_BY_TYPE_REQ_LEN_2 20
#define ATT_READ_BY_TYPE_RSP_LEN_1 3
#define ATT_READ_BY_TYPE_RSP_LEN_2 22
#define APPL_ATT_READ_REQ_LEN 2
#define APPL_ATT_READ_RSP_LEN_1 0
#define APPL_ATT_READ_RSP_LEN_2 22
#define APPL_ATT_READ_BLOB_REQ_LEN 4
#define APPL_ATT_READ_BLOB_RSP_LEN_1 0
#define APPL_ATT_READ_BLOB_RSP_LEN_2 22
#define APPL_ATT_READ_BY_GROUP_REQ_LEN_1 6
#define APPL_ATT_READ_BY_GROUP_REQ_LEN_2 20
#define APPL_ATT_READ_BY_GROUP_RSP_LEN_1 5
#define APPL_ATT_READ_BY_GROUP_RSP_LEN_2 22
#define APPL_ATT_EXECUTE_WRITE_REQ_LEN 1
#define APPL_ATT_INVALID_LEN 0xFF
#define APPL_MAX_VALID_ATT_PDU_LEN_CHK 7
/** Application Defined error */
#define APPL_ATT_INVALID_OFFSET 0xFFFF
#define ATT_INVALID_ATTR_HANDLE_VAL 0x0000
#define APPL_MAX_MULTIPLE_READ_COUNT 11
#define APPL_CHECK_IF_ATT_REQUEST(type)\
((((((type) > 0x13) && ((type) < 0x16)) ||\
(((type) > 0x1E) && (((type) != ATT_SIGNED_WRITE_CMD) &&\
((type) != ATT_WRITE_CMD)))) || (0x01 == ((type) & 0x01)))? BT_FALSE : BT_TRUE)
#define APPL_ATT_PREPARE_QUEUE_INIT(i)\
appl_att_write_queue[(i)].handle_value.handle = 0;\
appl_att_write_queue[(i)].offset = 0xFFFF;\
appl_att_write_queue[(i)].handle_value.value.len = 0;\
appl_att_write_queue[(i)].handle_value.value.val = NULL;
API_RESULT appl_discover_service
(
/* IN */ ATT_UUID uuid,
/* IN */ UCHAR uuid_frmt
);
API_RESULT appl_write_req
(
/* IN */ ATT_ATTR_HANDLE handle,
/* IN */ ATT_VALUE * value
);
API_RESULT appl_read_req
(
/* IN */ ATT_ATTR_HANDLE handle
);
API_RESULT appl_att_server_init(void);
API_RESULT appl_handle_unsupported_op_code (ATT_HANDLE *handle, UCHAR op_code);
API_RESULT appl_validate_att_pdu_req_len
(
UCHAR att_event,
UINT16 event_datalen
);
#ifdef SMP_DATA_SIGNING
void appl_gatt_signing_complete (API_RESULT status, UCHAR * data, UINT16 datalen);
void appl_gatt_signing_verification_complete
(
API_RESULT status,
UCHAR * data,
UINT16 datalen
);
#endif /* SMP_DATA_SIGNING */
#endif /* _H_APPL_AMS_ATT_SERVER_ */
@@ -0,0 +1,227 @@
//*****************************************************************************
//
//! @file appl_gap_config_params.c
//!
//! @brief This file contains GAP Configuration Parameters used by the application.
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file appl_gap_config_params.c
*
* This file contains GAP Configuration Parameters used by the application.
*/
/* --------------------------------------------- Header File Inclusion */
#include "appl_gap.h"
#ifdef AMS
/* --------------------------------------------- External Global Variables */
/* --------------------------------------------- Exported Global Variables */
/* --------------------------------------------- Static Global Variables */
#if ((defined APPL_GAP_BROADCASTER_SUPPORT) || (defined APPL_GAP_PERIPHERAL_SUPPORT))
/** Advertisement Data Options */
const APPL_GAP_ADV_DATA appl_gap_adv_data[APPL_GAP_MAX_ADV_DATA_OPTIONS] =
{
/* GAP Advertisement Parameters */
{
{
/**
* Flags:
* 0x01: LE Limited Discoverable Mode
* 0x02: LE General Discoverable Mode
* 0x04: BR/EDR Not Supported
* 0x08: Simultaneous LE and BR/EDR to Same Device
* Capable (Controller)
* 0x10: Simultaneous LE and BR/EDR to Same Device
* Capable (Host)
*/
0x02, 0x01,
(BT_AD_FLAGS_LE_GENERAL_DISC_MODE | BT_AD_FLAGS_LE_BR_EDR_SUPPORT),
/**
* Service UUID List:
* Battery Service (0x180F)
* DeviceInformation Service (0x180A)
*/
0x05, 0x03, 0x0F, 0x18, 0x0A, 0x18,
/**
* Shortened Device Name: AM
*/
0x03, 0x08, 0x41, 0x4d,
/**
* List of 16-bit Service Solicitation UUIDs(AMS UUID)
*/
0x11, 0x15, 0xDC, 0xF8, 0x55, 0xAD, 0x02, 0xC5, 0xF4, 0x8E, 0x3A, 0x43, 0x36, 0x0F, 0x2B, 0x50, 0xD3, 0x89
},
31
}
};
/* Advertisement parameters options */
const APPL_GAP_ADV_PARAM appl_gap_adv_param[APPL_GAP_MAX_ADV_PARAM_OPTIONS] =
{
/* 0 - Normal Advertising Params */
{
32,
32,
7,
0
},
/* 1 - Fast Connection Advertising Params */
{
32,
48,
7,
0
},
/* 2 - Low Power Advertising Params */
{
1600,
4000,
7,
0
}
};
/* Advertisement Table */
APPL_GAP_ADV_INFO appl_gap_adv_table =
{
appl_gap_adv_data,
appl_gap_adv_param,
APPL_GAP_ADV_IDLE
};
#endif /* APPL_GAP_BROADCASTER || APPL_GAP_PERIPHERAL_SUPPORT */
#if ((defined APPL_GAP_OBSERVER_SUPPORT) || (defined APPL_GAP_CENTRAL_SUPPORT))
/* Scan Parameters Option */
const APPL_GAP_SCAN_PARAM appl_gap_scan_param[APPL_GAP_MAX_SCAN_PARAM_OPTIONS] =
{
/* Normal Scan Params */
{
32,
7,
0
},
/* Fast Connection Scan Params */
{
48,
7,
0
},
/* Low Power Scan Params */
{
4000,
7,
0
}
};
/* Scan Table */
APPL_GAP_SCAN_INFO appl_gap_scan_table =
{
appl_gap_scan_param,
APPL_GAP_SCAN_IDLE
};
#endif /* APPL_GAP_OBSERVER_SUPPORT || APPL_GAP_CENTRAL_SUPPORT */
#ifdef APPL_GAP_CENTRAL_SUPPORT
/* Connection Parameters Options */
const APPL_GAP_CONN_PARAM appl_gap_conn_param[APPL_GAP_MAX_CONN_PARAM_OPTIONS] =
{
{
4,
4,
0,
40,
56,
0,
955,
32,
32
}
};
/* GAP Connection Table */
APPL_GAP_CONN_INFO appl_gap_conn_table =
{
appl_gap_conn_param,
APPL_GAP_CONN_IDLE
};
#endif /* APPL_GAP_CENTRAL_SUPPORT */
#endif /* AMS */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,157 @@
//*****************************************************************************
//
//! @file gatt_db.h
//!
//! @brief GATT Databse.
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file gatt_db.h
*/
/*
* Copyright (C) 2013. Mindtree Ltd.
* All rights reserved.
*/
#ifndef _H_GATT_DB_
#define _H_GATT_DB_
/**
* addgroup gatt_db_module
*/
/**
* defgroup gatt_db_tuneable_param Tuneable Parameters
* {
* This section defines the Tuneable Constants of Data Base Module.
*/
/** Number of Characteristics in the data base */
#define GATT_CHARACTERISTIC_COUNT 13
/** Number of Services in the data base */
#define GATT_SERVICE_COUNT 4
/** Number of Characteristics that are configurable by the client */
#define GATT_DB_MAX_CONFIGUREABLE_CHAR 3
/** Maximum Length of any Characteristic Value/Descriptor */
#define GATT_DB_MAX_VAL_LENGTH 32
#define GATT_VALUE_ARRAY_SIZE 1
#define GATT_CONST_VALUE_ARRAY_SIZE 180
#define GATT_DB_PEER_VALUE_ARRAY_SIZE 4
#define GATT_DB_MAX_ATTRIBUTES 34
#define GATT_UUID_ARRAY_SIZE 54
#define GATT_DB_MAX_TYPE_COUNT 21
#define GATT_DB_MAX_PEER_CONFIGURATION \
(GATT_DB_PEER_VALUE_ARRAY_SIZE * BT_MAX_DEVICE_QUEUE_SIZE)
/** \} */
/** Service Instance Reference */
/** GAP Service */
#define GATT_SER_GAP_INST 0
/** GATT Service */
#define GATT_SER_GATT_INST 1
/** Battery Service */
#define GATT_SER_BATTERY_INST 2
/** DeviceInformation Service */
#define GATT_SER_DEV_INFO_INST 3
/** Characteristic Instance Reference */
/** DeviceName */
#define GATT_CHAR_DEV_NAME_INST 0
/** Appearance */
#define GATT_CHAR_APPEARANCE_INST 1
/** Service Changed */
#define GATT_CHAR_SER_CHNGD_INST 2
/** BatteryLevel */
#define GATT_CHAR_BATTERY_LVL_INST 3
/** ManufacturerName */
#define GATT_CHAR_MAN_NAME_INST 4
/** ModelNumber */
#define GATT_CHAR_MODEL_NO_INST 5
/** SerialNumber */
#define GATT_CHAR_SL_NO_INST 6
/** FirmwareRevision */
#define GATT_CHAR_FW_REV_INST 7
/** HardwareRevision */
#define GATT_CHAR_HW_REV_INST 8
/** SoftwareRevision */
#define GATT_CHAR_SW_REV_INST 9
/** SystemId */
#define GATT_CHAR_SYS_ID_INST 10
/** RegCertDataList */
#define GATT_CHAR_REG_CERT_DATA_INST 11
/** PnPID */
#define GATT_CHAR_PNP_ID_INST 12
#endif /* _H_GATT_DB_ */
@@ -0,0 +1,666 @@
//*****************************************************************************
//
//! @file appl_ancs.c
//!
//! @brief ANCS service.
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file appl_ancs.c
*
*/
/* --------------------------------------------- Header File Inclusion */
#ifdef ANCS
#include "appl.h"
#include "BT_common.h"
#include "BT_hci_api.h"
#include "BT_att_api.h"
#include "BT_smp_api.h"
#include "smp_pl.h"
#include "l2cap.h"
#include "fsm_defines.h"
#include "task.h"
#include "queue.h"
/* ----------------------------------------- Configuration Defines */
extern uint32_t am_util_stdio_printf(const char *pcFmt, ...);
#undef APPL_TRC
#undef APPL_ERR
#define APPL_TRC am_util_stdio_printf
#define APPL_ERR am_util_stdio_printf
/* ----------------------------------------- Macro Defines */
/**@brief Category IDs for iOS notifications. */
typedef enum
{
BLE_ANCS_CATEGORY_ID_OTHER, /**< The iOS notification belongs to the "other" category. */
BLE_ANCS_CATEGORY_ID_INCOMING_CALL, /**< The iOS notification belongs to the "Incoming Call" category. */
BLE_ANCS_CATEGORY_ID_MISSED_CALL, /**< The iOS notification belongs to the "Missed Call" category. */
BLE_ANCS_CATEGORY_ID_VOICE_MAIL, /**< The iOS notification belongs to the "Voice Mail" category. */
BLE_ANCS_CATEGORY_ID_SOCIAL, /**< The iOS notification belongs to the "Social" category. */
BLE_ANCS_CATEGORY_ID_SCHEDULE, /**< The iOS notification belongs to the "Schedule" category. */
BLE_ANCS_CATEGORY_ID_EMAIL, /**< The iOS notification belongs to the "E-mail" category. */
BLE_ANCS_CATEGORY_ID_NEWS, /**< The iOS notification belongs to the "News" category. */
BLE_ANCS_CATEGORY_ID_HEALTH_AND_FITNESS, /**< The iOS notification belongs to the "Health and Fitness" category. */
BLE_ANCS_CATEGORY_ID_BUSINESS_AND_FINANCE, /**< The iOS notification belongs to the "Buisness and Finance" category. */
BLE_ANCS_CATEGORY_ID_LOCATION, /**< The iOS notification belongs to the "Location" category. */
BLE_ANCS_CATEGORY_ID_ENTERTAINMENT /**< The iOS notification belongs to the "Entertainment" category. */
} ancc_category_id_values_t;
/**@brief Event IDs for iOS notifications. */
typedef enum
{
BLE_ANCS_EVENT_ID_NOTIFICATION_ADDED, /**< The iOS notification was added. */
BLE_ANCS_EVENT_ID_NOTIFICATION_MODIFIED, /**< The iOS notification was modified. */
BLE_ANCS_EVENT_ID_NOTIFICATION_REMOVED /**< The iOS notification was removed. */
} ancc_evt_id_values_t;
/**@brief Control point command IDs that the Notification Consumer can send to the Notification Provider. */
typedef enum
{
BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES, /**< Requests attributes to be sent from the NP to the NC for a given notification. */
BLE_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES, /**< Requests attributes to be sent from the NP to the NC for a given iOS App. */
BLE_ANCS_COMMAND_ID_GET_PERFORM_NOTIF_ACTION, /**< Requests an action to be performed on a given notification, for example dismiss an alarm. */
} ancc_command_id_values_t;
/**@brief IDs for iOS notification attributes. */
typedef enum
{
BLE_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER, /**< Identifies that the attribute data is of an "App Identifier" type. */
BLE_ANCS_NOTIF_ATTR_ID_TITLE, /**< Identifies that the attribute data is a "Title". Needs to be followed by a 2-bytes max length parameter*/
BLE_ANCS_NOTIF_ATTR_ID_SUBTITLE, /**< Identifies that the attribute data is a "Subtitle". Needs to be followed by a 2-bytes max length parameter*/
BLE_ANCS_NOTIF_ATTR_ID_MESSAGE, /**< Identifies that the attribute data is a "Message". Needs to be followed by a 2-bytes max length parameter*/
BLE_ANCS_NOTIF_ATTR_ID_MESSAGE_SIZE, /**< Identifies that the attribute data is a "Message Size". */
BLE_ANCS_NOTIF_ATTR_ID_DATE, /**< Identifies that the attribute data is a "Date". */
BLE_ANCS_NOTIF_ATTR_ID_POSITIVE_ACTION_LABEL, /**< The notification has a "Positive action" that can be executed associated with it. */
BLE_ANCS_NOTIF_ATTR_ID_NEGATIVE_ACTION_LABEL, /**< The notification has a "Negative action" that can be executed associated with it. */
} ancc_notif_attr_id_values_t;
/**@brief Typedef for iOS notifications. */
typedef struct
{
uint8_t event_id; /**< This field informs the accessory whether the given iOS notification was added, modified, or removed. The enumerated values for this field are defined in EventID Values.. */
uint8_t event_flags; /**< A bitmask whose set bits inform an NC of specificities with the iOS notification. */
uint8_t category_id; /**< A numerical value providing a category in which the iOS notification can be classified. */
uint8_t category_count; /**< The current number of active iOS notifications in the given category. */
uint32_t notification_uid; /**< A 32-bit numerical value that is the unique identifier (UID) for the iOS notification. */
} ancc_notif_t;
typedef enum
{
ANCS_DISCONNECTED,
ANCS_CONNECTED,
ANCS_BONDED,
ANCS_DISCOVERED,
} ancs_appl_state_t;
/* ----------------------------------------- External Global Variables */
void appl_profile_operations (void);
void AncsGetNotificationAttribute(uint32_t notiUid);
extern BT_DEVICE_ADDR g_bd_addr;
/* ----------------------------------------- Exported Global Variables */
QueueHandle_t xNtfUIDQueue;
/* ----------------------------------------- Static Global Variables */
DECL_STATIC UCHAR write_response = 0;
DECL_STATIC API_RESULT gResult = 0;
DECL_STATIC ancs_appl_state_t appl_ancs_state = ANCS_DISCONNECTED;
DECL_STATIC ATT_UUID ancs_service_uuid128 = {.uuid_128.value = {0xD0, 0x00, 0x2D, 0x12, 0x1E, 0x4B, 0x0F, 0xA4, 0x99, 0x4E, 0xCE, 0xB5, 0x31, 0xF4, 0x05, 0x79}};
DECL_STATIC ATT_UUID ANCS_ControlPoint_UUID = {.uuid_128.value = {0xD9, 0xD9, 0xAA, 0xFD, 0xBD, 0x9B, 0x21, 0x98, 0xA8, 0x49, 0xE1, 0x45, 0xF3, 0xD8, 0xD1, 0x69}};
DECL_STATIC ATT_UUID ANCS_NotificationSource_UUID = {.uuid_128.value = {0xBD, 0x1D, 0xA2, 0x99, 0xE6, 0x25, 0x58, 0x8C, 0xD9, 0x42, 0x01, 0x63, 0x0D, 0x12, 0xBF, 0x9F}};
DECL_STATIC ATT_UUID ANCS_DataSource_UUID = {.uuid_128.value = {0xFB, 0x7B, 0x7C, 0xCE, 0x6A, 0xB3, 0x44, 0xBE, 0xB5, 0x4B, 0xD6, 0x24, 0xE9, 0xC6, 0xEA, 0x22}};
/* BLE Connection Handle */
//DECL_STATIC UINT16 appl_ble_connection_handle;
/** ANCS Characteristic related information */
typedef struct
{
/* ANCS Service */
/* Notification Source */
ATT_ATTR_HANDLE ancs_notification_source_hdl;
/* Notification Source - CCC */
ATT_ATTR_HANDLE ancs_notification_source_ccc_hdl;
/* Control Point */
ATT_ATTR_HANDLE ancs_control_point_hdl;
/* Data Source */
ATT_ATTR_HANDLE ancs_data_source_hdl;
/* Data Source - CCC */
ATT_ATTR_HANDLE ancs_data_source_ccc_hdl;
} ANCS_CHAR_INFO;
#define APPL_CLI_CNFG_VAL_LENGTH 2
DECL_STATIC ANCS_CHAR_INFO ancs_char_info;
#ifdef APPL_MENU_OPS
BT_DEVICE_ADDR g_peer_bd_addr;
static UCHAR ancs_client_menu[] =
"\n\
\r\n\
1. Bond with peer \r\n\
\r\n\
2. Discover ANCS \r\n\
\r\n\
3. Set Data Source CCCD \r\n\
\r\n\
4. Set Notification Source CCCD \r\n\
\r\n\
5. Get Notification Attribute by UID \r\n\
\r\n\
Your Option? \0";
#endif /* APPL_MENU_OPS */
/* --------------------------------------------- Constants */
/* --------------------------------------------- Static Global Variables */
/* --------------------------------------------- Functions */
void appl_bond_with_peer(void)
{
API_RESULT retval;
/* If connection is successful, initiate bonding [Step 2(c)] */
SMP_AUTH_INFO auth;
SMP_BD_ADDR smp_peer_bd_addr;
SMP_BD_HANDLE smp_bd_handle;
APPL_TRC("\n<<appl_bond_with_peer>>\n");
auth.param = 1;
auth.bonding = 1;
auth.ekey_size = 12;
auth.security = SMP_SEC_LEVEL_1;
BT_COPY_BD_ADDR(smp_peer_bd_addr.addr, g_bd_addr.addr);
BT_COPY_TYPE(smp_peer_bd_addr.type, g_bd_addr.type);
retval = BT_smp_get_bd_handle
(
&smp_peer_bd_addr,
&smp_bd_handle
);
if (API_SUCCESS == retval)
{
retval = BT_smp_authenticate (&smp_bd_handle, &auth);
}
if (API_SUCCESS != retval)
{
APPL_TRC (
"Initiation of Authentication Failed. Reason 0x%04X\n",
retval);
}
/**
* Application will receive authentication complete event,
* in SMP Callback.
*
* Look for 'SMP_AUTHENTICATION_COMPLETE' event handling in
* 'appl_smp_callback'.
*/
}
void appl_ancs_init(void)
{
appl_ancs_state = ANCS_DISCONNECTED;
APPL_TRC("\n\n<<appl_ancs_init>>\n\n");
}
void appl_ancs_connect(APPL_HANDLE * appl_handle)
{
APPL_STATE_T state = GET_APPL_STATE(*appl_handle);
if ( state == SL_0_TRANSPORT_OPERATING && appl_ancs_state == ANCS_DISCONNECTED )
{
appl_ancs_state = ANCS_CONNECTED;
APPL_TRC("\n\n<<CONNECTED>>\n\n");
}
else if ( state == SL_0_TRANSPORT_OPERATING && appl_ancs_state == ANCS_DISCOVERED )
{
appl_ancs_state = ANCS_BONDED;
APPL_TRC("\n\n<<BONDED>>\n\n");
}
else
{
appl_ancs_state = ANCS_DISCONNECTED;
APPL_TRC("\n\n<<DISCONNECTED>>\n\n");
}
}
void appl_search_complete(void)
{
appl_ancs_state = ANCS_DISCOVERED;
APPL_TRC("\n\n<<DISCOVERED>>\n\n");
}
void appl_recvice_att_event(UCHAR att_event, API_RESULT event_result)
{
if ( att_event == ATT_WRITE_RSP )
{
write_response = 1;
gResult = 0;
}
else if ( att_event == ATT_ERROR_RSP )
{
gResult = event_result;
}
}
void appl_manage_trasnfer (GATT_DB_HANDLE handle, UINT16 config)
{
APPL_TRC("\n\n<<appl_manage_trasnfer>>\n\n");
}
void appl_send_ancs_measurement (APPL_HANDLE * handle)
{
APPL_TRC("\n\n<<appl_send_ancs_measurement>>\n\n");
}
void appl_timer_expiry_handler (void *data, UINT16 datalen)
{
APPL_TRC("\n\n<<appl_timer_expiry_handler>>\n\n");
}
void appl_ancs_server_reinitialize (void)
{
appl_ancs_state = ANCS_DISCONNECTED;
APPL_TRC("\n\n<<appl_ancs_server_reinitialize>>\n\n");
}
void ancs_mtu_update(APPL_HANDLE * appl_handle, UINT16 t_mtu)
{
UINT16 mtu = 0;
BT_att_access_mtu(&APPL_GET_ATT_INSTANCE(*appl_handle),
&mtu);
APPL_TRC("appl_handle 0x%x t_mtu = %d %d\n", *appl_handle, t_mtu, mtu);
}
/* ------------------------------- ATT related Functions */
void appl_rcv_service_desc (UINT16 config, ATT_UUID uuid, UINT16 value_handle)
{
/* Populate Needed CCCDs here */
if (GATT_CLIENT_CONFIG == config)
{
if ( memcmp(&uuid, &ANCS_NotificationSource_UUID, ATT_128_BIT_UUID_SIZE) == 0 )
{
ancs_char_info.ancs_notification_source_ccc_hdl = value_handle;
}
else if ( memcmp(&uuid, &ANCS_DataSource_UUID, ATT_128_BIT_UUID_SIZE) == 0 )
{
ancs_char_info.ancs_data_source_ccc_hdl = value_handle;
}
}
}
void appl_rcv_service_char (ATT_UUID uuid, UINT16 value_handle)
{
if ( memcmp(&uuid, &ANCS_NotificationSource_UUID, ATT_128_BIT_UUID_SIZE) == 0 )
{
ancs_char_info.ancs_notification_source_hdl = value_handle;
}
else if ( memcmp(&uuid, &ANCS_ControlPoint_UUID, ATT_128_BIT_UUID_SIZE) == 0 )
{
ancs_char_info.ancs_control_point_hdl = value_handle;
}
else if ( memcmp(&uuid, &ANCS_DataSource_UUID, ATT_128_BIT_UUID_SIZE) == 0 )
{
ancs_char_info.ancs_data_source_hdl = value_handle;
}
}
void Wait4WrtRsp(void)
{
const TickType_t xDelay = 10 / portTICK_PERIOD_MS;
UCHAR i = 0;
while ( !write_response )
{
vTaskDelay( xDelay );
if (i++ > 10 )
{
break;
}
}
write_response = 0;
}
void appl_discover_ANCS(void)
{
APPL_TRC("\n<<appl_discover_ANCS>>\n");
appl_discover_service
(
ancs_service_uuid128,
ATT_128_BIT_UUID_FORMAT
);
return;
}
void AncsSubscribeNotifications(void)
{
ATT_VALUE att_value;
UINT16 cli_cfg;
UCHAR cfg_val[APPL_CLI_CNFG_VAL_LENGTH];
APPL_TRC("\n++<<AncsSubscribeNotifications>>\n");
cli_cfg = GATT_CLI_CNFG_NOTIFICATION;
BT_PACK_LE_2_BYTE(cfg_val, &cli_cfg);
att_value.len = APPL_CLI_CNFG_VAL_LENGTH;
att_value.val = cfg_val;
appl_write_req(ancs_char_info.ancs_data_source_ccc_hdl, &att_value);
Wait4WrtRsp();
cli_cfg = GATT_CLI_CNFG_NOTIFICATION;
BT_PACK_LE_2_BYTE(cfg_val, &cli_cfg);
att_value.len = APPL_CLI_CNFG_VAL_LENGTH;
att_value.val = cfg_val;
appl_write_req(ancs_char_info.ancs_notification_source_ccc_hdl, &att_value);
Wait4WrtRsp();
APPL_TRC("\n--<<AncsSubscribeNotifications(0x%04X)>>\n", gResult);
}
void appl_profile_operations (void)
{
const TickType_t xDelay = 100 / portTICK_PERIOD_MS;
UINT32 NtfUID;
write_response = 0;
xNtfUIDQueue = 0;
xNtfUIDQueue = xQueueCreate( 10, sizeof(UINT32) );
fsm_post_event
(
APPL_FSM_ID,
ev_appl_device_init_req,
NULL
);
while ( appl_ancs_state != ANCS_CONNECTED)
{
vTaskDelay( xDelay );
}
appl_discover_ANCS();
while ( appl_ancs_state != ANCS_DISCOVERED )
{
vTaskDelay( xDelay );
}
AncsSubscribeNotifications();
if ( gResult == 0x0305 /* insufficient authentication */ ||
gResult == 0x030F /* insufficient Encryption */ )
{
appl_bond_with_peer();
while ( appl_ancs_state != ANCS_BONDED )
{
vTaskDelay( xDelay );
}
AncsSubscribeNotifications();
}
else
{
appl_ancs_state = ANCS_BONDED;
}
while ( appl_ancs_state != ANCS_DISCONNECTED )
{
if ( xQueueReceive( xNtfUIDQueue, &( NtfUID ), ( TickType_t ) 10 ) )
{
AncsGetNotificationAttribute(NtfUID);
}
}
if ( xNtfUIDQueue != 0 )
{
vQueueDelete( xNtfUIDQueue);
}
}
void AncsDumpBytes (UCHAR *buffer, UINT16 length)
{
char hex_stream[49];
char char_stream[17];
UINT32 i;
UINT16 offset, count;
UCHAR c;
APPL_TRC (
"-------------------------------------------------------------------\n");
count = 0;
offset = 0;
for ( i = 0; i < length; i++ )
{
c = buffer[i];
sprintf(hex_stream + offset, "%02X ", c);
if ( (c >= 0x20) && (c <= 0x7E) )
{
char_stream[count] = c;
}
else
{
char_stream[count] = '.';
}
count ++;
offset += 3;
if ( 16 == count )
{
char_stream[count] = '\0';
count = 0;
offset = 0;
APPL_TRC ("%s %s\n",
hex_stream, char_stream);
BT_mem_set(hex_stream, 0, 49);
BT_mem_set(char_stream, 0, 17);
}
}
if ( offset != 0 )
{
char_stream[count] = '\0';
/* Maintain the alignment */
APPL_TRC ("%-48s %s\n",
hex_stream, char_stream);
}
APPL_TRC (
"-------------------------------------------------------------------\n\n");
return;
}
void AncsGetNotificationAttribute(uint32_t notiUid)
{
API_RESULT retval;
ATT_VALUE att_value;
// An example to get notification attributes
uint16_t max_len = 256;
uint8_t buf[19]; // retrieve the complete attribute list
APPL_TRC("++<<GetNtfUID:%X>>\n", notiUid);
buf[0] = BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES; // put command
uint8_t *p = &buf[1];
BT_UNPACK_LE_4_BYTE(p, (uint8_t*)(&notiUid)); // encode notification uid
// encode attribute IDs
buf[5] = BLE_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER;
buf[6] = BLE_ANCS_NOTIF_ATTR_ID_TITLE;
// 2 byte length
buf[7] = max_len;
buf[8] = max_len >> 8;
buf[9] = BLE_ANCS_NOTIF_ATTR_ID_SUBTITLE;
buf[10] = max_len;
buf[11] = max_len >> 8;
buf[12] = BLE_ANCS_NOTIF_ATTR_ID_MESSAGE;
buf[13] = max_len;
buf[14] = max_len >> 8;
buf[15] = BLE_ANCS_NOTIF_ATTR_ID_MESSAGE_SIZE;
buf[16] = BLE_ANCS_NOTIF_ATTR_ID_DATE;
buf[17] = BLE_ANCS_NOTIF_ATTR_ID_POSITIVE_ACTION_LABEL;
buf[18] = BLE_ANCS_NOTIF_ATTR_ID_NEGATIVE_ACTION_LABEL;
att_value.len = 19;
att_value.val = buf;
retval = appl_write_req(ancs_char_info.ancs_control_point_hdl, &att_value);
//APPL_TRC ("retval 0x%04X\n", retval);
if ( retval == API_SUCCESS )
{
Wait4WrtRsp();
}
APPL_TRC("--<<GetNtfUID:%X>>\n", notiUid);
}
void AncsNotificationCb(UCHAR *event_data, UINT16 event_datalen)
{
ATT_ATTR_HANDLE attr_handle;
ancc_notif_t *NotificationSource;
BT_UNPACK_LE_2_BYTE(&attr_handle, event_data);
if ( attr_handle == ancs_char_info.ancs_notification_source_hdl )
{
NotificationSource = (ancc_notif_t *)(event_data + 2);
switch(NotificationSource->category_id)
{
case(BLE_ANCS_CATEGORY_ID_OTHER):
APPL_TRC("OTHER(%X)\n", NotificationSource->notification_uid);
break;
case(BLE_ANCS_CATEGORY_ID_INCOMING_CALL):
APPL_TRC("INCOMING_CALL(%X)\n", NotificationSource->notification_uid);
break;
case(BLE_ANCS_CATEGORY_ID_MISSED_CALL):
APPL_TRC("MISSED_CALL(%X)\n", NotificationSource->notification_uid);
break;
case(BLE_ANCS_CATEGORY_ID_VOICE_MAIL):
APPL_TRC("VOICE_MAIL(%X)\n", NotificationSource->notification_uid);
break;
case(BLE_ANCS_CATEGORY_ID_SOCIAL):
APPL_TRC("SOCIAL(%X)\n", NotificationSource->notification_uid);
break;
case(BLE_ANCS_CATEGORY_ID_SCHEDULE):
APPL_TRC("SCHEDULE(%X)\n", NotificationSource->notification_uid);
break;
case(BLE_ANCS_CATEGORY_ID_EMAIL):
APPL_TRC("EMAIL(%X)\n", NotificationSource->notification_uid);
break;
case(BLE_ANCS_CATEGORY_ID_NEWS):
APPL_TRC("NEWS(%X)\n", NotificationSource->notification_uid);
break;
case(BLE_ANCS_CATEGORY_ID_HEALTH_AND_FITNESS):
APPL_TRC("HEALTH_AND_FITNESS(%X)\n", NotificationSource->notification_uid);
break;
case(BLE_ANCS_CATEGORY_ID_BUSINESS_AND_FINANCE):
APPL_TRC("BUSINESS_AND_FINANCE(%X)\n", NotificationSource->notification_uid);
break;
case(BLE_ANCS_CATEGORY_ID_LOCATION):
APPL_TRC("LOCATION(%X)\n", NotificationSource->notification_uid);
break;
case(BLE_ANCS_CATEGORY_ID_ENTERTAINMENT):
APPL_TRC("ENTERTAINMENT(%X)\n", NotificationSource->notification_uid);
break;
default:
break;
}
//APPL_TRC("Spaces %d\n", uxQueueSpacesAvailable(xNtfUIDQueue));
xQueueSend( xNtfUIDQueue, ( void * ) &(NotificationSource->notification_uid), ( TickType_t ) 0 );
}
#if 0
else if ( attr_handle == ancs_char_info.ancs_data_source_hdl )
{
APPL_TRC("data source\n");
}
#endif
AncsDumpBytes(event_data + 2, (event_datalen-2));
}
#endif /* ANCS */
@@ -0,0 +1,122 @@
//*****************************************************************************
//
//! @file appl_ancs.h
//!
//! @brief Application Header File for ANCS.
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file appl_ancs.h
*
* Application Header File for ANCS.
*/
/*
* Copyright (C) 2013. Mindtree Ltd.
* All rights reserved.
*/
#ifndef _H_APPL_ANCS_
#define _H_APPL_ANCS_
/* ----------------------------------------- Header File Inclusion */
#include "BT_api.h"
#include "BT_gatt_db_api.h"
#include "gatt_db.h"
#include "appl.h"
#include "appl_ancs_att_server.h"
/* ----------------------------------------- Data Types/ Structures */
typedef struct
{
UCHAR index;
UCHAR length;
}APPL_HRS_OBS_DATA_INFO;
/* --------------------------------------------- Global Definitions */
/** LSB of error code has to be spec defined */
#define APPL_HR_CNTRL_PNT_NOT_SUPPORTED (APPL_ERR_ID | 0x80)
/* --------------------------------------------- Functions */
void appl_ancs_init(void);
void appl_manage_trasnfer (GATT_DB_HANDLE handle, UINT16 config);
void appl_timer_expiry_handler (void *data, UINT16 datalen);
void appl_ancs_connect(DEVICE_HANDLE * dq_handle);
void appl_send_ancs_measurement (APPL_HANDLE * handle);
void appl_ancs_server_reinitialize (void);
void appl_rcv_service_desc (UINT16 config, ATT_UUID uuid, UINT16 value_handle);
void appl_rcv_service_char (ATT_UUID uuid, UINT16 value_handle);
API_RESULT appl_hr_control_point_handler
(
GATT_DB_HANDLE * handle,
ATT_VALUE * value
);
API_RESULT appl_att_callback
(
ATT_HANDLE * handle,
UCHAR event_type,
API_RESULT event_result,
UCHAR * event_data,
UINT16 event_datalen
);
void ancs_mtu_update(APPL_HANDLE * appl_handle, UINT16 t_mtu);
/* Profile handling */
#define APPL_PROFILE_INIT(...) appl_ancs_init()
#define APPL_PROFILE_CONNECT(x) appl_ancs_connect(x)
#define APPL_SEND_MEASUREMENT(x)appl_send_ancs_measurement(x)
#define APPL_PROFILE_DISCONNECT_HANDLER(x) appl_ancs_server_reinitialize()
#define GATT_DB_PROFILE_HANDLER gatt_db_ancs_handler
#define APPL_PROFILE_HVN_NTF_COMPLETE_HANDLER(x, y, z)
#define APPL_PROFILE_HVN_IND_COMPLETE_HANDLER(x, y, z)
#define APPL_PROFILE_MTU_UPDT_COMPLETE_HANDLER(x, y) ancs_mtu_update(x, y)
#define APPL_USE_IDLE_TIMER
#define APPL_IDLE_TIMEOUT 30
#endif /* _H_APPL_ANCS_ */
@@ -0,0 +1,158 @@
//*****************************************************************************
//
//! @file appl_ancs_att_server.h
//!
//! @brief ATT Server Application Header File
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file appl_ancs_att_server.h
*
* ATT Server Application Header File
*/
/*
* Copyright (C) 2013. Mindtree Ltd.
* All rights reserved.
*/
#ifndef _H_APPL_ANCS_ATT_SERVER_
#define _H_APPL_ANCS_ATT_SERVER_
/* ----------------------------------------- Header File Inclusion */
#include "BT_api.h"
#include "BT_gatt_db_api.h"
#define APPL_ATT_WRITE_QUEUE_SIZE 10
#define APPL_ATT_MAX_WRITE_BUFFER_SIZE 256 /* 255 */
#define APPL_ATT_MTU ATT_MAX_MTU
#define APPL_SERVER_BUFFER_SIZE 256 /* 256 */
#define APPL_MAX_GROUP_TYPE_QUERIED 5
#define APPL_MAX_HNDL_UUID_LIST_SIZE 5
#define APPL_MAX_HNDL_LIST_SIZE 11
#define APPL_MAX_HNDL_VALUE_SIZE 5
/* ATT PDU Request Length */
#define APPL_ATT_XCNHG_MTU_REQ_LEN 2
#define APPL_ATT_XCNHG_MTU_RSP_LEN 2
#define APPL_ATT_FIND_INFO_REQ_LEN 4
#define APPL_ATT_FIND_INFO_RSP_LEN_1 5
#define APPL_ATT_FIND_INFO_RSP_LEN_2 22
#define ATT_FIND_BY_TYPE_VAL_RSP_LEN1 4
#define ATT_FIND_BY_TYPE_VAL_RSP_LEN2 21
#define APPL_ATT_READ_BY_TYPE_REQ_LEN_1 6
#define APPL_ATT_READ_BY_TYPE_REQ_LEN_2 20
#define ATT_READ_BY_TYPE_RSP_LEN_1 3
#define ATT_READ_BY_TYPE_RSP_LEN_2 22
#define APPL_ATT_READ_REQ_LEN 2
#define APPL_ATT_READ_RSP_LEN_1 0
#define APPL_ATT_READ_RSP_LEN_2 22
#define APPL_ATT_READ_BLOB_REQ_LEN 4
#define APPL_ATT_READ_BLOB_RSP_LEN_1 0
#define APPL_ATT_READ_BLOB_RSP_LEN_2 22
#define APPL_ATT_READ_BY_GROUP_REQ_LEN_1 6
#define APPL_ATT_READ_BY_GROUP_REQ_LEN_2 20
#define APPL_ATT_READ_BY_GROUP_RSP_LEN_1 5
#define APPL_ATT_READ_BY_GROUP_RSP_LEN_2 22
#define APPL_ATT_EXECUTE_WRITE_REQ_LEN 1
#define APPL_ATT_INVALID_LEN 0xFF
#define APPL_MAX_VALID_ATT_PDU_LEN_CHK 7
/** Application Defined error */
#define APPL_ATT_INVALID_OFFSET 0xFFFF
#define ATT_INVALID_ATTR_HANDLE_VAL 0x0000
#define APPL_MAX_MULTIPLE_READ_COUNT 11
#define APPL_CHECK_IF_ATT_REQUEST(type)\
((((((type) > 0x13) && ((type) < 0x16)) ||\
(((type) > 0x1E) && (((type) != ATT_SIGNED_WRITE_CMD) &&\
((type) != ATT_WRITE_CMD)))) || (0x01 == ((type) & 0x01)))? BT_FALSE : BT_TRUE)
#define APPL_ATT_PREPARE_QUEUE_INIT(i)\
appl_att_write_queue[(i)].handle_value.handle = 0;\
appl_att_write_queue[(i)].offset = 0xFFFF;\
appl_att_write_queue[(i)].handle_value.value.len = 0;\
appl_att_write_queue[(i)].handle_value.value.val = NULL;
API_RESULT appl_discover_service
(
/* IN */ ATT_UUID uuid,
/* IN */ UCHAR uuid_frmt
);
API_RESULT appl_write_req
(
/* IN */ ATT_ATTR_HANDLE handle,
/* IN */ ATT_VALUE * value
);
API_RESULT appl_read_req
(
/* IN */ ATT_ATTR_HANDLE handle
);
API_RESULT appl_att_server_init(void);
API_RESULT appl_handle_unsupported_op_code (ATT_HANDLE *handle, UCHAR op_code);
API_RESULT appl_validate_att_pdu_req_len
(
UCHAR att_event,
UINT16 event_datalen
);
#ifdef SMP_DATA_SIGNING
void appl_gatt_signing_complete (API_RESULT status, UCHAR * data, UINT16 datalen);
void appl_gatt_signing_verification_complete
(
API_RESULT status,
UCHAR * data,
UINT16 datalen
);
#endif /* SMP_DATA_SIGNING */
#endif /* _H_APPL_ANCS_ATT_SERVER_ */
@@ -0,0 +1,231 @@
//*****************************************************************************
//
//! @file appl_gap_config_params.c
//!
//! @brief This file contains GAP Configuration Parameters used by the application.
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file appl_gap_config_params.c
*
* This file contains GAP Configuration Parameters used by the application.
*/
/*
* Copyright (C) 2013. Mindtree Ltd.
* All rights reserved.
*/
/* --------------------------------------------- Header File Inclusion */
#include "appl_gap.h"
#ifdef ANCS
/* --------------------------------------------- External Global Variables */
/* --------------------------------------------- Exported Global Variables */
/* --------------------------------------------- Static Global Variables */
#if ((defined APPL_GAP_BROADCASTER_SUPPORT) || (defined APPL_GAP_PERIPHERAL_SUPPORT))
/** Advertisement Data Options */
const APPL_GAP_ADV_DATA appl_gap_adv_data[APPL_GAP_MAX_ADV_DATA_OPTIONS] =
{
/* GAP Advertisement Parameters */
{
{
/**
* Flags:
* 0x01: LE Limited Discoverable Mode
* 0x02: LE General Discoverable Mode
* 0x04: BR/EDR Not Supported
* 0x08: Simultaneous LE and BR/EDR to Same Device
* Capable (Controller)
* 0x10: Simultaneous LE and BR/EDR to Same Device
* Capable (Host)
*/
0x02, 0x01,
(BT_AD_FLAGS_LE_GENERAL_DISC_MODE | BT_AD_FLAGS_LE_BR_EDR_SUPPORT),
/**
* Service UUID List:
* Battery Service (0x180F)
* DeviceInformation Service (0x180A)
*/
0x05, 0x03, 0x0F, 0x18, 0x0A, 0x18,
/**
* Shortened Device Name: AM
*/
0x03, 0x08, 0x41, 0x4d,
/**
* List of 16-bit Service Solicitation UUIDs(ANCS UUID)
*/
0x11, 0x15, 0xD0, 0x00, 0x2D, 0x12, 0x1E, 0x4B, 0x0F, 0xA4, 0x99, 0x4E, 0xCE, 0xB5, 0x31, 0xF4, 0x05, 0x79
},
31
}
};
/* Advertisement parameters options */
const APPL_GAP_ADV_PARAM appl_gap_adv_param[APPL_GAP_MAX_ADV_PARAM_OPTIONS] =
{
/* 0 - Normal Advertising Params */
{
32,
32,
7,
0
},
/* 1 - Fast Connection Advertising Params */
{
32,
48,
7,
0
},
/* 2 - Low Power Advertising Params */
{
1600,
4000,
7,
0
}
};
/* Advertisement Table */
APPL_GAP_ADV_INFO appl_gap_adv_table =
{
appl_gap_adv_data,
appl_gap_adv_param,
APPL_GAP_ADV_IDLE
};
#endif /* APPL_GAP_BROADCASTER || APPL_GAP_PERIPHERAL_SUPPORT */
#if ((defined APPL_GAP_OBSERVER_SUPPORT) || (defined APPL_GAP_CENTRAL_SUPPORT))
/* Scan Parameters Option */
const APPL_GAP_SCAN_PARAM appl_gap_scan_param[APPL_GAP_MAX_SCAN_PARAM_OPTIONS] =
{
/* Normal Scan Params */
{
32,
7,
0
},
/* Fast Connection Scan Params */
{
48,
7,
0
},
/* Low Power Scan Params */
{
4000,
7,
0
}
};
/* Scan Table */
APPL_GAP_SCAN_INFO appl_gap_scan_table =
{
appl_gap_scan_param,
APPL_GAP_SCAN_IDLE
};
#endif /* APPL_GAP_OBSERVER_SUPPORT || APPL_GAP_CENTRAL_SUPPORT */
#ifdef APPL_GAP_CENTRAL_SUPPORT
/* Connection Parameters Options */
const APPL_GAP_CONN_PARAM appl_gap_conn_param[APPL_GAP_MAX_CONN_PARAM_OPTIONS] =
{
{
4,
4,
0,
40,
56,
0,
955,
32,
32
}
};
/* GAP Connection Table */
APPL_GAP_CONN_INFO appl_gap_conn_table =
{
appl_gap_conn_param,
APPL_GAP_CONN_IDLE
};
#endif /* APPL_GAP_CENTRAL_SUPPORT */
#endif /* ANCS */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,157 @@
//*****************************************************************************
//
//! @file gatt_db.h
//!
//! @brief GATT Databse.
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file gatt_db.h
*/
/*
* Copyright (C) 2013. Mindtree Ltd.
* All rights reserved.
*/
#ifndef _H_GATT_DB_
#define _H_GATT_DB_
/**
* addgroup gatt_db_module
*/
/**
* defgroup gatt_db_tuneable_param Tuneable Parameters
* {
* This section defines the Tuneable Constants of Data Base Module.
*/
/** Number of Characteristics in the data base */
#define GATT_CHARACTERISTIC_COUNT 13
/** Number of Services in the data base */
#define GATT_SERVICE_COUNT 4
/** Number of Characteristics that are configurable by the client */
#define GATT_DB_MAX_CONFIGUREABLE_CHAR 3
/** Maximum Length of any Characteristic Value/Descriptor */
#define GATT_DB_MAX_VAL_LENGTH 32
#define GATT_VALUE_ARRAY_SIZE 1
#define GATT_CONST_VALUE_ARRAY_SIZE 182
#define GATT_DB_PEER_VALUE_ARRAY_SIZE 4
#define GATT_DB_MAX_ATTRIBUTES 34
#define GATT_UUID_ARRAY_SIZE 54
#define GATT_DB_MAX_TYPE_COUNT 21
#define GATT_DB_MAX_PEER_CONFIGURATION \
(GATT_DB_PEER_VALUE_ARRAY_SIZE * BT_MAX_DEVICE_QUEUE_SIZE)
/** \} */
/** Service Instance Reference */
/** GAP Service */
#define GATT_SER_GAP_INST 0
/** GATT Service */
#define GATT_SER_GATT_INST 1
/** Battery Service */
#define GATT_SER_BATTERY_INST 2
/** DeviceInformation Service */
#define GATT_SER_DEV_INFO_INST 3
/** Characteristic Instance Reference */
/** DeviceName */
#define GATT_CHAR_DEV_NAME_INST 0
/** Appearance */
#define GATT_CHAR_APPEARANCE_INST 1
/** Service Changed */
#define GATT_CHAR_SER_CHNGD_INST 2
/** BatteryLevel */
#define GATT_CHAR_BATTERY_LVL_INST 3
/** ManufacturerName */
#define GATT_CHAR_MAN_NAME_INST 4
/** ModelNumber */
#define GATT_CHAR_MODEL_NO_INST 5
/** SerialNumber */
#define GATT_CHAR_SL_NO_INST 6
/** FirmwareRevision */
#define GATT_CHAR_FW_REV_INST 7
/** HardwareRevision */
#define GATT_CHAR_HW_REV_INST 8
/** SoftwareRevision */
#define GATT_CHAR_SW_REV_INST 9
/** SystemId */
#define GATT_CHAR_SYS_ID_INST 10
/** RegCertDataList */
#define GATT_CHAR_REG_CERT_DATA_INST 11
/** PnPID */
#define GATT_CHAR_PNP_ID_INST 12
#endif /* _H_GATT_DB_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,234 @@
//*****************************************************************************
//
//! @file appl_gap_config_params.c
//!
//! @brief This file contains GAP Configuration Parameters used by the application.
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file appl_gap_config_params.c
*
* This file contains GAP Configuration Parameters used by the application.
*/
/*
* Copyright (C) 2013. Mindtree Ltd.
* All rights reserved.
*/
/* --------------------------------------------- Header File Inclusion */
#include "appl_gap.h"
/* --------------------------------------------- External Global Variables */
/* --------------------------------------------- Exported Global Variables */
/* --------------------------------------------- Static Global Variables */
#if ((defined APPL_GAP_BROADCASTER_SUPPORT) || (defined APPL_GAP_PERIPHERAL_SUPPORT))
/** Advertisement Data Options */
const APPL_GAP_ADV_DATA appl_gap_adv_data[APPL_GAP_MAX_ADV_DATA_OPTIONS] =
{
/* GAP Advertisement Parameters */
{
{
/**
* Flags:
* 0x01: LE Limited Discoverable Mode
* 0x02: LE General Discoverable Mode
* 0x04: BR/EDR Not Supported
* 0x08: Simultaneous LE and BR/EDR to Same Device
* Capable (Controller)
* 0x10: Simultaneous LE and BR/EDR to Same Device
* Capable (Host)
*/
0x02, 0x01,
(BT_AD_FLAGS_LE_GENERAL_DISC_MODE | BT_AD_FLAGS_LE_BR_EDR_SUPPORT),
/*! Manufacturer specific data AD type */
0x1A, /*! length */
HCI_AD_TYPE_MANUFACTURER_SPECIFIC_DATA, /*! AD type */
0x4C, /*! Company ID[0] */
0x00, /*! Company ID[1] */
0x02, /*! Device type, this has to be 0x02*/
0x15, /*! Length of vendor advertising data. */
/*! Proximity UUID 16 bytes */
0xe2, 0xc5, 0x6d, 0xb5,
0xdf, 0xfb, 0x48, 0xd2,
0xb0, 0x60, 0xd0, 0xf5,
0xa7, 0x10, 0x96, 0xe0,
/*! Major 0xnnnn */
0x00, 0x00,
/*! Minor 0xnnnn */
0x00, 0x00,
/*! Measured Power */
0xc5
},
30
}
};
/* Advertisement parameters options */
const APPL_GAP_ADV_PARAM appl_gap_adv_param[APPL_GAP_MAX_ADV_PARAM_OPTIONS] =
{
/* 0 - Normal Advertising Params */
{
32,
32,
7,
0
},
/* 1 - Fast Connection Advertising Params */
{
32,
48,
7,
0
},
/* 2 - Low Power Advertising Params */
{
1600,
4000,
7,
0
}
};
/* Advertisement Table */
APPL_GAP_ADV_INFO appl_gap_adv_table =
{
appl_gap_adv_data,
appl_gap_adv_param,
APPL_GAP_ADV_IDLE
};
#endif /* APPL_GAP_BROADCASTER || APPL_GAP_PERIPHERAL_SUPPORT */
#if ((defined APPL_GAP_OBSERVER_SUPPORT) || (defined APPL_GAP_CENTRAL_SUPPORT))
/* Scan Parameters Option */
const APPL_GAP_SCAN_PARAM appl_gap_scan_param[APPL_GAP_MAX_SCAN_PARAM_OPTIONS] =
{
/* Normal Scan Params */
{
32,
7,
0
},
/* Fast Connection Scan Params */
{
48,
7,
0
},
/* Low Power Scan Params */
{
4000,
7,
0
}
};
/* Scan Table */
APPL_GAP_SCAN_INFO appl_gap_scan_table =
{
appl_gap_scan_param,
APPL_GAP_SCAN_IDLE
};
#endif /* APPL_GAP_OBSERVER_SUPPORT || APPL_GAP_CENTRAL_SUPPORT */
#ifdef APPL_GAP_CENTRAL_SUPPORT
/* Connection Parameters Options */
const APPL_GAP_CONN_PARAM appl_gap_conn_param[APPL_GAP_MAX_CONN_PARAM_OPTIONS] =
{
{
4,
4,
0,
40,
56,
0,
955,
32,
32
}
};
/* GAP Connection Table */
APPL_GAP_CONN_INFO appl_gap_conn_table =
{
appl_gap_conn_param,
APPL_GAP_CONN_IDLE
};
#endif /* APPL_GAP_CENTRAL_SUPPORT */
@@ -0,0 +1,25 @@
/**
* \file appl_ibeacon.c
*
* This file contains ibeacon example
*
* Copyright (C) 2013. Mindtree Ltd.
* All rights reserved.
*/
/* --------------------------------------------- Header File Inclusion */
#include "appl.h"
/* --------------------------------------------- Constants */
/* --------------------------------------------- Static Global Variables */
/* --------------------------------------------- Functions */
void appl_ibeacon_init(void)
{
}
@@ -0,0 +1,87 @@
//*****************************************************************************
//
//! @file appl_ibeacon.h
//!
//! @brief Application Header File for iBeacon example.
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file appl_ibeacon.h
*
* Application Header File for iBeacon example.
*/
/*
* Copyright (C) 2013. Mindtree Ltd.
* All rights reserved.
*/
#ifndef _H_APPL_HRS_
#define _H_APPL_HRS_
/* ----------------------------------------- Header File Inclusion */
#include "BT_api.h"
#include "BT_gatt_db_api.h"
#include "gatt_db.h"
#include "appl.h"
/* ----------------------------------------- Data Types/ Structures */
/* --------------------------------------------- Functions */
void appl_ibeacon_init(void);
/* Profile handling */
#define APPL_PROFILE_INIT(...) appl_ibeacon_init()
#define APPL_PROFILE_CONNECT(x)
#define APPL_SEND_MEASUREMENT(x)
#define APPL_PROFILE_DISCONNECT_HANDLER(x)
#define GATT_DB_PROFILE_HANDLER
#define APPL_PROFILE_HVN_NTF_COMPLETE_HANDLER(x, y, z)
#define APPL_PROFILE_HVN_IND_COMPLETE_HANDLER(x, y, z)
#define APPL_PROFILE_MTU_UPDT_COMPLETE_HANDLER(x, y)
#define APPL_USE_IDLE_TIMER
#define APPL_IDLE_TIMEOUT 30
#endif /* _H_APPL_HRS_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,167 @@
//*****************************************************************************
//
//! @file gatt_db.h
//!
//! @brief GATT Databse.
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/**
* \file gatt_db.h
*/
/*
* Copyright (C) 2013. Mindtree Ltd.
* All rights reserved.
*/
#ifndef _H_GATT_DB_
#define _H_GATT_DB_
/**
* addgroup gatt_db_module
*/
/**
* defgroup gatt_db_tuneable_param Tuneable Parameters
* {
* This section defines the Tuneable Constants of Data Base Module.
*/
/** Number of Characteristics in the data base */
#define GATT_CHARACTERISTIC_COUNT 16
/** Number of Services in the data base */
#define GATT_SERVICE_COUNT 5
/** Number of Characteristics that are configurable by the client */
#define GATT_DB_MAX_CONFIGUREABLE_CHAR 3
/** Maximum Length of any Characteristic Value/Descriptor */
#define GATT_DB_MAX_VAL_LENGTH 32
#define GATT_VALUE_ARRAY_SIZE 3
#define GATT_CONST_VALUE_ARRAY_SIZE 203
#define GATT_DB_PEER_VALUE_ARRAY_SIZE 6
#define GATT_DB_MAX_ATTRIBUTES 42
#define GATT_UUID_ARRAY_SIZE 62
#define GATT_DB_MAX_TYPE_COUNT 25
#define GATT_DB_MAX_PEER_CONFIGURATION \
(GATT_DB_PEER_VALUE_ARRAY_SIZE * BT_MAX_DEVICE_QUEUE_SIZE)
/** \} */
/** Service Instance Reference */
/** GAP Service */
#define GATT_SER_GAP_INST 0
/** GATT Service */
#define GATT_SER_GATT_INST 1
/** Battery Service */
#define GATT_SER_BATTERY_INST 2
/** DeviceInformation Service */
#define GATT_SER_DEV_INFO_INST 3
/** Heart Rate Service */
#define GATT_SER_HEART_RATE_INST 4
/** Characteristic Instance Reference */
/** DeviceName */
#define GATT_CHAR_DEV_NAME_INST 0
/** Appearance */
#define GATT_CHAR_APPEARANCE_INST 1
/** Service Changed */
#define GATT_CHAR_SER_CHNGD_INST 2
/** BatteryLevel */
#define GATT_CHAR_BATTERY_LVL_INST 3
/** ManufacturerName */
#define GATT_CHAR_MAN_NAME_INST 4
/** ModelNumber */
#define GATT_CHAR_MODEL_NO_INST 5
/** SerialNumber */
#define GATT_CHAR_SL_NO_INST 6
/** FirmwareRevision */
#define GATT_CHAR_FW_REV_INST 7
/** HardwareRevision */
#define GATT_CHAR_HW_REV_INST 8
/** SoftwareRevision */
#define GATT_CHAR_SW_REV_INST 9
/** SystemId */
#define GATT_CHAR_SYS_ID_INST 10
/** RegCertDataList */
#define GATT_CHAR_REG_CERT_DATA_INST 11
/** PnPID */
#define GATT_CHAR_PNP_ID_INST 12
/** HeartRateMeasurement */
#define GATT_CHAR_HR_MSRMNT 13
/** BodySensorLocation */
#define GATT_CHAR_BODY_SNSR_LOC_INST 14
/** HeartRateControlPoint */
#define GATT_CHAR_HR_CNTRL_PNT_INST 15
#endif /* _H_GATT_DB_ */
@@ -0,0 +1,111 @@
// ****************************************************************************
//
// amdtpc_api.h
//! @file
//!
//! @brief Ambiq Micro AMDTP client.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef AMDTPC_API_H
#define AMDTPC_API_H
#include "att_api.h"
#include "amdtp_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Macros
**************************************************************************************************/
enum
{
AMDTP_RX_HDL_IDX, /*! Rx data */
AMDTP_TX_DATA_HDL_IDX, /*! Tx data */
AMDTP_TX_DATA_CCC_HDL_IDX, /*! Tx data client characteristic configuration descriptor */
AMDTP_ACK_HDL_IDX, /*! Ack */
AMDTP_ACK_CCC_HDL_IDX, /*! Ack client characteristic configuration descriptor */
AMDTP_HDL_LIST_LEN /*! Handle list length */
};
/**************************************************************************************************
Function Declarations
**************************************************************************************************/
/*************************************************************************************************/
/*!
* \fn AmdtpcDiscover
*
* \brief Perform service and characteristic discovery for AMDTP service.
* Parameter pHdlList must point to an array of length AMDTP_HDL_LIST_LEN.
* If discovery is successful the handles of discovered characteristics and
* descriptors will be set in pHdlList.
*
* \param connId Connection identifier.
* \param pHdlList Characteristic handle list.
*
* \return None.
*/
/*************************************************************************************************/
void AmdtpcDiscover(dmConnId_t connId, uint16_t *pHdlList);
void
amdtpc_init(wsfHandlerId_t handlerId, amdtpRecvCback_t recvCback, amdtpTransCback_t transCback);
void
amdtpc_start(uint16_t rxHdl, uint16_t ackHdl, uint8_t timerEvt);
void
amdtpc_proc_msg(wsfMsgHdr_t *pMsg);
eAmdtpStatus_t
AmdtpcSendPacket(eAmdtpPktType_t type, bool_t encrypted, bool_t enableACK, uint8_t *buf, uint16_t len);
#ifdef __cplusplus
};
#endif
#endif /* AMDTPC_API_H */
@@ -0,0 +1,438 @@
// ****************************************************************************
//
// amdtpc_main.c
//! @file
//!
//! @brief Ambiq Micro AMDTP client.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include <string.h>
#include <stdbool.h>
#include "wsf_types.h"
#include "wsf_assert.h"
#include "bstream.h"
#include "app_api.h"
#include "amdtpc_api.h"
#include "svc_amdtp.h"
#include "wsf_trace.h"
static void amdtpcHandleWriteResponse(attEvt_t *pMsg);
//*****************************************************************************
//
// Global variables
//
//*****************************************************************************
uint8_t rxPktBuf[AMDTP_PACKET_SIZE];
uint8_t txPktBuf[AMDTP_PACKET_SIZE];
uint8_t ackPktBuf[20];
/**************************************************************************************************
Local Variables
**************************************************************************************************/
/* UUIDs */
static const uint8_t amdtpSvcUuid[] = {ATT_UUID_AMDTP_SERVICE}; /*! AMDTP service */
static const uint8_t amdtpRxChUuid[] = {ATT_UUID_AMDTP_RX}; /*! AMDTP Rx */
static const uint8_t amdtpTxChUuid[] = {ATT_UUID_AMDTP_TX}; /*! AMDTP Tx */
static const uint8_t amdtpAckChUuid[] = {ATT_UUID_AMDTP_ACK}; /*! AMDTP Ack */
/* Characteristics for discovery */
/*! Proprietary data */
static const attcDiscChar_t amdtpRx =
{
amdtpRxChUuid,
ATTC_SET_REQUIRED | ATTC_SET_UUID_128
};
static const attcDiscChar_t amdtpTx =
{
amdtpTxChUuid,
ATTC_SET_REQUIRED | ATTC_SET_UUID_128
};
/*! AMDTP Tx CCC descriptor */
static const attcDiscChar_t amdtpTxCcc =
{
attCliChCfgUuid,
ATTC_SET_REQUIRED | ATTC_SET_DESCRIPTOR
};
static const attcDiscChar_t amdtpAck =
{
amdtpAckChUuid,
ATTC_SET_REQUIRED | ATTC_SET_UUID_128
};
/*! AMDTP Tx CCC descriptor */
static const attcDiscChar_t amdtpAckCcc =
{
attCliChCfgUuid,
ATTC_SET_REQUIRED | ATTC_SET_DESCRIPTOR
};
/*! List of characteristics to be discovered; order matches handle index enumeration */
static const attcDiscChar_t *amdtpDiscCharList[] =
{
&amdtpRx, /*! Rx */
&amdtpTx, /*! Tx */
&amdtpTxCcc, /*! Tx CCC descriptor */
&amdtpAck, /*! Ack */
&amdtpAckCcc /*! Ack CCC descriptor */
};
/* sanity check: make sure handle list length matches characteristic list length */
//WSF_ASSERT(AMDTP_HDL_LIST_LEN == ((sizeof(amdtpDiscCharList) / sizeof(attcDiscChar_t *))));
/* Control block */
static struct
{
bool_t txReady; // TRUE if ready to send notifications
uint16_t attRxHdl;
uint16_t attAckHdl;
amdtpCb_t core;
}
amdtpcCb;
/*************************************************************************************************/
/*!
* \fn AmdtpDiscover
*
* \brief Perform service and characteristic discovery for AMDTP service.
* Parameter pHdlList must point to an array of length AMDTP_HDL_LIST_LEN.
* If discovery is successful the handles of discovered characteristics and
* descriptors will be set in pHdlList.
*
* \param connId Connection identifier.
* \param pHdlList Characteristic handle list.
*
* \return None.
*/
/*************************************************************************************************/
void
AmdtpcDiscover(dmConnId_t connId, uint16_t *pHdlList)
{
AppDiscFindService(connId, ATT_128_UUID_LEN, (uint8_t *) amdtpSvcUuid,
AMDTP_HDL_LIST_LEN, (attcDiscChar_t **) amdtpDiscCharList, pHdlList);
}
//*****************************************************************************
//
// Send data to Server
//
//*****************************************************************************
static void
amdtpcSendData(uint8_t *buf, uint16_t len)
{
dmConnId_t connId;
if ((connId = AppConnIsOpen()) == DM_CONN_ID_NONE)
{
APP_TRACE_INFO0("AmdtpcSendData() no connection\n");
return;
}
if (amdtpcCb.attRxHdl != ATT_HANDLE_NONE)
{
AttcWriteCmd(connId, amdtpcCb.attRxHdl, len, buf);
amdtpcCb.txReady = false;
}
else
{
APP_TRACE_WARN1("Invalid attRxHdl = 0x%x\n", amdtpcCb.attRxHdl);
}
}
static eAmdtpStatus_t
amdtpcSendAck(eAmdtpPktType_t type, bool_t encrypted, bool_t enableACK, uint8_t *buf, uint16_t len)
{
dmConnId_t connId;
AmdtpBuildPkt(&amdtpcCb.core, type, encrypted, enableACK, buf, len);
if ((connId = AppConnIsOpen()) == DM_CONN_ID_NONE)
{
APP_TRACE_INFO0("AmdtpcSendAck() no connection\n");
return AMDTP_STATUS_TX_NOT_READY;
}
if (amdtpcCb.attAckHdl != ATT_HANDLE_NONE)
{
//APP_TRACE_INFO2("rxHdl = 0x%x, ackHdl = 0x%x\n", amdtpcCb.attRxHdl, amdtpcCb.attAckHdl);
AttcWriteCmd(connId, amdtpcCb.attAckHdl, amdtpcCb.core.ackPkt.len, amdtpcCb.core.ackPkt.data);
}
else
{
APP_TRACE_INFO1("Invalid attAckHdl = 0x%x\n", amdtpcCb.attAckHdl);
return AMDTP_STATUS_TX_NOT_READY;
}
return AMDTP_STATUS_SUCCESS;
}
void
amdtpc_init(wsfHandlerId_t handlerId, amdtpRecvCback_t recvCback, amdtpTransCback_t transCback)
{
memset(&amdtpcCb, 0, sizeof(amdtpcCb));
amdtpcCb.txReady = false;
amdtpcCb.core.txState = AMDTP_STATE_TX_IDLE;
amdtpcCb.core.rxState = AMDTP_STATE_INIT;
amdtpcCb.core.timeoutTimer.handlerId = handlerId;
amdtpcCb.core.lastRxPktSn = 0;
amdtpcCb.core.txPktSn = 0;
resetPkt(&amdtpcCb.core.rxPkt);
amdtpcCb.core.rxPkt.data = rxPktBuf;
resetPkt(&amdtpcCb.core.txPkt);
amdtpcCb.core.txPkt.data = txPktBuf;
resetPkt(&amdtpcCb.core.ackPkt);
amdtpcCb.core.ackPkt.data = ackPktBuf;
amdtpcCb.core.recvCback = recvCback;
amdtpcCb.core.transCback = transCback;
amdtpcCb.core.txTimeoutMs = TX_TIMEOUT_DEFAULT;
amdtpcCb.core.data_sender_func = amdtpcSendData;
amdtpcCb.core.ack_sender_func = amdtpcSendAck;
}
static void
amdtpc_conn_close(dmEvt_t *pMsg)
{
/* clear connection */
WsfTimerStop(&amdtpcCb.core.timeoutTimer);
amdtpcCb.txReady = false;
amdtpcCb.core.txState = AMDTP_STATE_TX_IDLE;
amdtpcCb.core.rxState = AMDTP_STATE_INIT;
amdtpcCb.core.lastRxPktSn = 0;
amdtpcCb.core.txPktSn = 0;
resetPkt(&amdtpcCb.core.rxPkt);
resetPkt(&amdtpcCb.core.txPkt);
resetPkt(&amdtpcCb.core.ackPkt);
}
void
amdtpc_start(uint16_t rxHdl, uint16_t ackHdl, uint8_t timerEvt)
{
amdtpcCb.txReady = true;
amdtpcCb.attRxHdl = rxHdl;
amdtpcCb.attAckHdl = ackHdl;
amdtpcCb.core.timeoutTimer.msg.event = timerEvt;
dmConnId_t connId;
if ((connId = AppConnIsOpen()) == DM_CONN_ID_NONE)
{
APP_TRACE_INFO0("amdtpc_start() no connection\n");
return;
}
amdtpcCb.core.attMtuSize = AttGetMtu(connId);
APP_TRACE_INFO1("MTU size = %d bytes", amdtpcCb.core.attMtuSize);
}
//*****************************************************************************
//
// Timer Expiration handler
//
//*****************************************************************************
void
amdtpc_timeout_timer_expired(wsfMsgHdr_t *pMsg)
{
uint8_t data[1];
data[0] = amdtpcCb.core.txPktSn;
APP_TRACE_INFO1("amdtpc tx timeout, txPktSn = %d", amdtpcCb.core.txPktSn);
AmdtpSendControl(&amdtpcCb.core, AMDTP_CONTROL_RESEND_REQ, data, 1);
// fire a timer for receiving an AMDTP_STATUS_RESEND_REPLY ACK
WsfTimerStartMs(&amdtpcCb.core.timeoutTimer, amdtpcCb.core.txTimeoutMs);
}
/*************************************************************************************************/
/*!
* \fn amdtpcValueNtf
*
* \brief Process a received ATT notification.
*
* \param pMsg Pointer to ATT callback event message.
*
* \return None.
*/
/*************************************************************************************************/
static uint8_t
amdtpcValueNtf(attEvt_t *pMsg)
{
eAmdtpStatus_t status = AMDTP_STATUS_UNKNOWN_ERROR;
amdtpPacket_t *pkt = NULL;
#if 0
APP_TRACE_INFO0("receive ntf data\n");
APP_TRACE_INFO1("handle = 0x%x\n", pMsg->handle);
for (int i = 0; i < pMsg->valueLen; i++)
{
APP_TRACE_INFO1("%02x ", pMsg->pValue[i]);
}
APP_TRACE_INFO0("\n");
#endif
if (pMsg->handle == amdtpcCb.attRxHdl)
{
status = AmdtpReceivePkt(&amdtpcCb.core, &amdtpcCb.core.rxPkt, pMsg->valueLen, pMsg->pValue);
}
else if ( pMsg->handle == amdtpcCb.attAckHdl )
{
status = AmdtpReceivePkt(&amdtpcCb.core, &amdtpcCb.core.ackPkt, pMsg->valueLen, pMsg->pValue);
}
if (status == AMDTP_STATUS_RECEIVE_DONE)
{
if (pMsg->handle == amdtpcCb.attRxHdl)
{
pkt = &amdtpcCb.core.rxPkt;
}
else if (pMsg->handle == amdtpcCb.attAckHdl)
{
pkt = &amdtpcCb.core.ackPkt;
}
AmdtpPacketHandler(&amdtpcCb.core, (eAmdtpPktType_t)pkt->header.pktType, pkt->len - AMDTP_CRC_SIZE_IN_PKT, pkt->data);
}
return ATT_SUCCESS;
}
static void
amdtpcHandleWriteResponse(attEvt_t *pMsg)
{
//APP_TRACE_INFO2("amdtpcHandleWriteResponse, status = %d, hdl = 0x%x\n", pMsg->hdr.status, pMsg->handle);
if (pMsg->hdr.status == ATT_SUCCESS && pMsg->handle == amdtpcCb.attRxHdl)
{
amdtpcCb.txReady = true;
// process next data
AmdtpSendPacketHandler(&amdtpcCb.core);
}
}
void
amdtpc_proc_msg(wsfMsgHdr_t *pMsg)
{
if (pMsg->event == DM_CONN_OPEN_IND)
{
}
else if (pMsg->event == DM_CONN_CLOSE_IND)
{
amdtpc_conn_close((dmEvt_t *) pMsg);
}
else if (pMsg->event == DM_CONN_UPDATE_IND)
{
}
else if (pMsg->event == amdtpcCb.core.timeoutTimer.msg.event)
{
amdtpc_timeout_timer_expired(pMsg);
}
else if (pMsg->event == ATTC_WRITE_CMD_RSP)
{
amdtpcHandleWriteResponse((attEvt_t *) pMsg);
}
else if (pMsg->event == ATTC_HANDLE_VALUE_NTF)
{
amdtpcValueNtf((attEvt_t *) pMsg);
}
}
//*****************************************************************************
//
//! @brief Send data to Server via write command
//!
//! @param type - packet type
//! @param encrypted - is packet encrypted
//! @param enableACK - does client need to response
//! @param buf - data
//! @param len - data length
//!
//! @return status
//
//*****************************************************************************
eAmdtpStatus_t
AmdtpcSendPacket(eAmdtpPktType_t type, bool_t encrypted, bool_t enableACK, uint8_t *buf, uint16_t len)
{
//
// Check if the service is idle to send
//
if ( amdtpcCb.core.txState != AMDTP_STATE_TX_IDLE )
{
APP_TRACE_INFO1("data sending failed, tx state = %d", amdtpcCb.core.txState);
return AMDTP_STATUS_BUSY;
}
//
// Check if data length is valid
//
if ( len > AMDTP_MAX_PAYLOAD_SIZE )
{
APP_TRACE_INFO1("data sending failed, exceed maximum payload, len = %d.", len);
return AMDTP_STATUS_INVALID_PKT_LENGTH;
}
//
// Check if ready to send notification
//
if ( !amdtpcCb.txReady )
{
//set in callback amdtpsHandleValueCnf
APP_TRACE_INFO1("data sending failed, not ready for notification.", NULL);
return AMDTP_STATUS_TX_NOT_READY;
}
AmdtpBuildPkt(&amdtpcCb.core, type, encrypted, enableACK, buf, len);
// send packet
AmdtpSendPacketHandler(&amdtpcCb.core);
return AMDTP_STATUS_SUCCESS;
}
@@ -0,0 +1,399 @@
// ****************************************************************************
//
// amdtp_common.c
//! @file
//!
//! @brief This file provides the shared functions for the AMDTP service.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include "amdtp_common.h"
#include "wsf_assert.h"
#include "wsf_trace.h"
#include "bstream.h"
#include "att_api.h"
#include "am_util_debug.h"
#include "crc32.h"
#include "am_util.h"
void
resetPkt(amdtpPacket_t *pkt)
{
pkt->offset = 0;
pkt->header.pktType = AMDTP_PKT_TYPE_UNKNOWN;
pkt->len = 0;
}
eAmdtpStatus_t
AmdtpReceivePkt(amdtpCb_t *amdtpCb, amdtpPacket_t *pkt, uint16_t len, uint8_t *pValue)
{
uint8_t dataIdx = 0;
uint32_t calDataCrc = 0;
uint16_t header = 0;
if (pkt->offset == 0 && len < AMDTP_PREFIX_SIZE_IN_PKT)
{
APP_TRACE_INFO0("Invalid packet!!!");
AmdtpSendReply(amdtpCb, AMDTP_STATUS_INVALID_PKT_LENGTH, NULL, 0);
return AMDTP_STATUS_INVALID_PKT_LENGTH;
}
// new packet
if (pkt->offset == 0)
{
BYTES_TO_UINT16(pkt->len, pValue);
BYTES_TO_UINT16(header, &pValue[2]);
pkt->header.pktType = (header & PACKET_TYPE_BIT_MASK) >> PACKET_TYPE_BIT_OFFSET;
pkt->header.pktSn = (header & PACKET_SN_BIT_MASK) >> PACKET_SN_BIT_OFFSET;
pkt->header.encrypted = (header & PACKET_ENCRYPTION_BIT_MASK) >> PACKET_ENCRYPTION_BIT_OFFSET;
pkt->header.ackEnabled = (header & PACKET_ACK_BIT_MASK) >> PACKET_ACK_BIT_OFFSET;
dataIdx = AMDTP_PREFIX_SIZE_IN_PKT;
if (pkt->header.pktType == AMDTP_PKT_TYPE_DATA)
{
amdtpCb->rxState = AMDTP_STATE_GETTING_DATA;
}
#ifdef AMDTP_DEBUG_ON
APP_TRACE_INFO1("pkt len = 0x%x", pkt->len);
APP_TRACE_INFO1("pkt header = 0x%x", header);
#endif
APP_TRACE_INFO2("type = %d, sn = %d", pkt->header.pktType, pkt->header.pktSn);
APP_TRACE_INFO2("enc = %d, ackEnabled = %d", pkt->header.encrypted, pkt->header.ackEnabled);
}
// make sure we have enough space for new data
if (pkt->offset + len - dataIdx > AMDTP_PACKET_SIZE)
{
APP_TRACE_INFO0("not enough buffer size!!!");
if (pkt->header.pktType == AMDTP_PKT_TYPE_DATA)
{
amdtpCb->rxState = AMDTP_STATE_RX_IDLE;
}
// reset pkt
resetPkt(pkt);
AmdtpSendReply(amdtpCb, AMDTP_STATUS_INSUFFICIENT_BUFFER, NULL, 0);
return AMDTP_STATUS_INSUFFICIENT_BUFFER;
}
// copy new data into buffer and also save crc into it if it's the last frame in a packet
// 4 bytes crc is included in pkt length
memcpy(pkt->data + pkt->offset, pValue + dataIdx, len - dataIdx);
pkt->offset += (len - dataIdx);
// whole packet received
if (pkt->offset >= pkt->len)
{
uint32_t peerCrc = 0;
//
// check CRC
//
BYTES_TO_UINT32(peerCrc, pkt->data + pkt->len - AMDTP_CRC_SIZE_IN_PKT);
calDataCrc = CalcCrc32(0xFFFFFFFFU, pkt->len - AMDTP_CRC_SIZE_IN_PKT, pkt->data);
#ifdef AMDTP_DEBUG_ON
APP_TRACE_INFO1("calDataCrc = 0x%x ", calDataCrc);
APP_TRACE_INFO1("peerCrc = 0x%x", peerCrc);
APP_TRACE_INFO1("len: %d", pkt->len);
#endif
if (peerCrc != calDataCrc)
{
APP_TRACE_INFO0("crc error\n");
if (pkt->header.pktType == AMDTP_PKT_TYPE_DATA)
{
amdtpCb->rxState = AMDTP_STATE_RX_IDLE;
}
// reset pkt
resetPkt(pkt);
AmdtpSendReply(amdtpCb, AMDTP_STATUS_CRC_ERROR, NULL, 0);
return AMDTP_STATUS_CRC_ERROR;
}
return AMDTP_STATUS_RECEIVE_DONE;
}
return AMDTP_STATUS_RECEIVE_CONTINUE;
}
//*****************************************************************************
//
// AMDTP packet handler
//
//*****************************************************************************
void
AmdtpPacketHandler(amdtpCb_t *amdtpCb, eAmdtpPktType_t type, uint16_t len, uint8_t *buf)
{
// APP_TRACE_INFO2("received packet type = %d, len = %d\n", type, len);
switch(type)
{
case AMDTP_PKT_TYPE_DATA:
//
// data package recevied
//
// record packet serial number
amdtpCb->lastRxPktSn = amdtpCb->rxPkt.header.pktSn;
AmdtpSendReply(amdtpCb, AMDTP_STATUS_SUCCESS, NULL, 0);
if (amdtpCb->recvCback)
{
amdtpCb->recvCback(buf, len);
}
amdtpCb->rxState = AMDTP_STATE_RX_IDLE;
resetPkt(&amdtpCb->rxPkt);
break;
case AMDTP_PKT_TYPE_ACK:
{
eAmdtpStatus_t status = (eAmdtpStatus_t)buf[0];
// stop tx timeout timer
WsfTimerStop(&amdtpCb->timeoutTimer);
if (amdtpCb->txState != AMDTP_STATE_TX_IDLE)
{
// APP_TRACE_INFO1("set txState back to idle, state = %d\n", amdtpCb->txState);
amdtpCb->txState = AMDTP_STATE_TX_IDLE;
}
if (status == AMDTP_STATUS_CRC_ERROR || status == AMDTP_STATUS_RESEND_REPLY)
{
// resend packet
AmdtpSendPacketHandler(amdtpCb);
}
else
{
// increase packet serial number if send successfully
if (status == AMDTP_STATUS_SUCCESS)
{
amdtpCb->txPktSn++;
if (amdtpCb->txPktSn == 16)
{
amdtpCb->txPktSn = 0;
}
}
// packet transfer successful or other error
// reset packet
resetPkt(&amdtpCb->txPkt);
// notify application layer
if (amdtpCb->transCback)
{
amdtpCb->transCback(status);
}
}
resetPkt(&amdtpCb->ackPkt);
}
break;
case AMDTP_PKT_TYPE_CONTROL:
{
eAmdtpControl_t control = (eAmdtpControl_t)buf[0];
uint8_t resendPktSn = buf[1];
if (control == AMDTP_CONTROL_RESEND_REQ)
{
APP_TRACE_INFO2("resendPktSn = %d, lastRxPktSn = %d", resendPktSn, amdtpCb->lastRxPktSn);
amdtpCb->rxState = AMDTP_STATE_RX_IDLE;
resetPkt(&amdtpCb->rxPkt);
if (resendPktSn > amdtpCb->lastRxPktSn)
{
AmdtpSendReply(amdtpCb, AMDTP_STATUS_RESEND_REPLY, NULL, 0);
}
else if (resendPktSn == amdtpCb->lastRxPktSn)
{
AmdtpSendReply(amdtpCb, AMDTP_STATUS_SUCCESS, NULL, 0);
}
else
{
APP_TRACE_WARN2("resendPktSn = %d, lastRxPktSn = %d", resendPktSn, amdtpCb->lastRxPktSn);
}
}
else
{
APP_TRACE_WARN1("unexpected contrl = %d\n", control);
}
resetPkt(&amdtpCb->ackPkt);
}
break;
default:
break;
}
}
void
AmdtpBuildPkt(amdtpCb_t *amdtpCb, eAmdtpPktType_t type, bool_t encrypted, bool_t enableACK, uint8_t *buf, uint16_t len)
{
uint16_t header = 0;
uint32_t calDataCrc;
amdtpPacket_t *pkt;
if (type == AMDTP_PKT_TYPE_DATA)
{
pkt = &amdtpCb->txPkt;
header = amdtpCb->txPktSn << PACKET_SN_BIT_OFFSET;
}
else
{
pkt = &amdtpCb->ackPkt;
}
//
// Prepare header frame to be sent first
//
// length
pkt->len = len + AMDTP_PREFIX_SIZE_IN_PKT + AMDTP_CRC_SIZE_IN_PKT;
pkt->data[0] = (len + AMDTP_CRC_SIZE_IN_PKT) & 0xff;
pkt->data[1] = ((len + AMDTP_CRC_SIZE_IN_PKT) >> 8) & 0xff;
// header
header = header | (type << PACKET_TYPE_BIT_OFFSET);
if (encrypted)
{
header = header | (1 << PACKET_ENCRYPTION_BIT_OFFSET);
}
if (enableACK)
{
header = header | (1 << PACKET_ACK_BIT_OFFSET);
}
pkt->data[2] = (header & 0xff);
pkt->data[3] = (header >> 8);
// copy data
memcpy(&(pkt->data[AMDTP_PREFIX_SIZE_IN_PKT]), buf, len);
calDataCrc = CalcCrc32(0xFFFFFFFFU, len, buf);
// add checksum
pkt->data[AMDTP_PREFIX_SIZE_IN_PKT + len] = (calDataCrc & 0xff);
pkt->data[AMDTP_PREFIX_SIZE_IN_PKT + len + 1] = ((calDataCrc >> 8) & 0xff);
pkt->data[AMDTP_PREFIX_SIZE_IN_PKT + len + 2] = ((calDataCrc >> 16) & 0xff);
pkt->data[AMDTP_PREFIX_SIZE_IN_PKT + len + 3] = ((calDataCrc >> 24) & 0xff);
}
//*****************************************************************************
//
// Send Reply to Sender
//
//*****************************************************************************
void
AmdtpSendReply(amdtpCb_t *amdtpCb, eAmdtpStatus_t status, uint8_t *data, uint16_t len)
{
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN] = {0};
eAmdtpStatus_t st;
WSF_ASSERT(len < ATT_DEFAULT_PAYLOAD_LEN);
buf[0] = status;
if (len > 0)
{
memcpy(buf + 1, data, len);
}
st = amdtpCb->ack_sender_func(AMDTP_PKT_TYPE_ACK, false, false, buf, len + 1);
if (st != AMDTP_STATUS_SUCCESS)
{
APP_TRACE_WARN1("AmdtpSendReply status = %d\n", status);
}
}
//*****************************************************************************
//
// Send control message to Receiver
//
//*****************************************************************************
void
AmdtpSendControl(amdtpCb_t *amdtpCb, eAmdtpControl_t control, uint8_t *data, uint16_t len)
{
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN] = {0};
eAmdtpStatus_t st;
WSF_ASSERT(len < ATT_DEFAULT_PAYLOAD_LEN);
buf[0] = control;
if (len > 0)
{
memcpy(buf + 1, data, len);
}
st = amdtpCb->ack_sender_func(AMDTP_PKT_TYPE_CONTROL, false, false, buf, len + 1);
if (st != AMDTP_STATUS_SUCCESS)
{
APP_TRACE_WARN1("AmdtpSendControl status = %d\n", st);
}
}
void
AmdtpSendPacketHandler(amdtpCb_t *amdtpCb)
{
uint16_t transferSize = 0;
uint16_t remainingBytes = 0;
amdtpPacket_t *txPkt = &amdtpCb->txPkt;
if ( amdtpCb->txState == AMDTP_STATE_TX_IDLE )
{
txPkt->offset = 0;
amdtpCb->txState = AMDTP_STATE_SENDING;
}
if ( txPkt->offset >= txPkt->len )
{
// done sent packet
amdtpCb->txState = AMDTP_STATE_WAITING_ACK;
// start tx timeout timer
WsfTimerStartMs(&amdtpCb->timeoutTimer, amdtpCb->txTimeoutMs);
}
else
{
remainingBytes = txPkt->len - txPkt->offset;
transferSize = ((amdtpCb->attMtuSize - 3) > remainingBytes)
? remainingBytes
: (amdtpCb->attMtuSize - 3);
// send packet
amdtpCb->data_sender_func(&txPkt->data[txPkt->offset], transferSize);
txPkt->offset += transferSize;
}
}
@@ -0,0 +1,224 @@
// ****************************************************************************
//
// amdtp_common.h
//! @file
//!
//! @brief This file provides the shared functions for the AMDTP service.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef AMDTP_COMMON_H
#define AMDTP_COMMON_H
#include "wsf_types.h"
#include "wsf_timer.h"
#ifdef __cplusplus
extern "C"
{
#endif
//*****************************************************************************
//
// Macro definitions
//
//*****************************************************************************
#define AMDTP_MAX_PAYLOAD_SIZE 2048//512
#define AMDTP_PACKET_SIZE (AMDTP_MAX_PAYLOAD_SIZE + AMDTP_PREFIX_SIZE_IN_PKT + AMDTP_CRC_SIZE_IN_PKT) // Bytes
#define AMDTP_LENGTH_SIZE_IN_PKT 2
#define AMDTP_HEADER_SIZE_IN_PKT 2
#define AMDTP_CRC_SIZE_IN_PKT 4
#define AMDTP_PREFIX_SIZE_IN_PKT AMDTP_LENGTH_SIZE_IN_PKT + AMDTP_HEADER_SIZE_IN_PKT
#define PACKET_TYPE_BIT_OFFSET 12
#define PACKET_TYPE_BIT_MASK (0xf << PACKET_TYPE_BIT_OFFSET)
#define PACKET_SN_BIT_OFFSET 8
#define PACKET_SN_BIT_MASK (0xf << PACKET_SN_BIT_OFFSET)
#define PACKET_ENCRYPTION_BIT_OFFSET 7
#define PACKET_ENCRYPTION_BIT_MASK (0x1 << PACKET_ENCRYPTION_BIT_OFFSET)
#define PACKET_ACK_BIT_OFFSET 6
#define PACKET_ACK_BIT_MASK (0x1 << PACKET_ACK_BIT_OFFSET)
#define TX_TIMEOUT_DEFAULT 1000
//
// amdtp states
//
typedef enum eAmdtpState
{
AMDTP_STATE_INIT,
AMDTP_STATE_TX_IDLE,
AMDTP_STATE_RX_IDLE,
AMDTP_STATE_SENDING,
AMDTP_STATE_GETTING_DATA,
AMDTP_STATE_WAITING_ACK,
AMDTP_STATE_MAX
}eAmdtpState_t;
//
// amdtp packet type
//
typedef enum eAmdtpPktType
{
AMDTP_PKT_TYPE_UNKNOWN,
AMDTP_PKT_TYPE_DATA,
AMDTP_PKT_TYPE_ACK,
AMDTP_PKT_TYPE_CONTROL,
AMDTP_PKT_TYPE_MAX
}eAmdtpPktType_t;
typedef enum eAmdtpControl
{
AMDTP_CONTROL_RESEND_REQ,
AMDTP_CONTROL_MAX
}eAmdtpControl_t;
//
// amdtp status
//
typedef enum eAmdtpStatus
{
AMDTP_STATUS_SUCCESS,
AMDTP_STATUS_CRC_ERROR,
AMDTP_STATUS_INVALID_METADATA_INFO,
AMDTP_STATUS_INVALID_PKT_LENGTH,
AMDTP_STATUS_INSUFFICIENT_BUFFER,
AMDTP_STATUS_UNKNOWN_ERROR,
AMDTP_STATUS_BUSY,
AMDTP_STATUS_TX_NOT_READY, // no connection or tx busy
AMDTP_STATUS_RESEND_REPLY,
AMDTP_STATUS_RECEIVE_CONTINUE,
AMDTP_STATUS_RECEIVE_DONE,
AMDTP_STATUS_MAX
}eAmdtpStatus_t;
//
// packet prefix structure
//
typedef struct
{
uint8_t pktType : 4;
uint8_t pktSn : 4;
uint8_t encrypted : 1;
uint32_t ackEnabled : 1;
uint32_t reserved : 6; // Reserved for future usage
}
amdtpPktHeader_t;
//
// packet
//
typedef struct
{
uint16_t offset;
uint16_t len; // data plus checksum
amdtpPktHeader_t header;
uint8_t *data;
}
amdtpPacket_t;
/*! Application data reception callback */
typedef void (*amdtpRecvCback_t)(uint8_t *buf, uint16_t len);
/*! Application data transmission result callback */
typedef void (*amdtpTransCback_t)(eAmdtpStatus_t status);
typedef void (*amdtp_reply_func_t)(eAmdtpStatus_t status, uint8_t *data, uint16_t len);
typedef void (*amdtp_packet_handler_func_t)(eAmdtpPktType_t type, uint16_t len, uint8_t *buf);
typedef eAmdtpStatus_t (*amdtp_ack_sender_func_t)(eAmdtpPktType_t type, bool_t encrypted, bool_t enableACK, uint8_t *buf, uint16_t len);
typedef void (*amdtp_data_sender_func_t)(uint8_t *buf, uint16_t len);
typedef struct
{
eAmdtpState_t txState;
eAmdtpState_t rxState;
amdtpPacket_t rxPkt;
amdtpPacket_t txPkt;
amdtpPacket_t ackPkt;
uint8_t txPktSn; // data packet serial number for Tx
uint8_t lastRxPktSn; // last received data packet serial number
uint16_t attMtuSize;
wsfTimer_t timeoutTimer; // timeout timer after DTP update done
wsfTimerTicks_t txTimeoutMs;
amdtpRecvCback_t recvCback; // application callback for data reception
amdtpTransCback_t transCback; // application callback for tx complete status
amdtp_data_sender_func_t data_sender_func;
amdtp_ack_sender_func_t ack_sender_func;
}
amdtpCb_t;
//*****************************************************************************
//
// function definitions
//
//*****************************************************************************
void
AmdtpBuildPkt(amdtpCb_t *amdtpCb, eAmdtpPktType_t type, bool_t encrypted, bool_t enableACK, uint8_t *buf, uint16_t len);
eAmdtpStatus_t
AmdtpReceivePkt(amdtpCb_t *amdtpCb, amdtpPacket_t *pkt, uint16_t len, uint8_t *pValue);
void
AmdtpSendReply(amdtpCb_t *amdtpCb, eAmdtpStatus_t status, uint8_t *data, uint16_t len);
void
AmdtpSendControl(amdtpCb_t *amdtpCb, eAmdtpControl_t control, uint8_t *data, uint16_t len);
void
AmdtpSendPacketHandler(amdtpCb_t *amdtpCb);
void
AmdtpPacketHandler(amdtpCb_t *amdtpCb, eAmdtpPktType_t type, uint16_t len, uint8_t *buf);
void
resetPkt(amdtpPacket_t *pkt);
#ifdef __cplusplus
}
#endif
#endif // AMDTP_COMMON_H
@@ -0,0 +1,109 @@
//*****************************************************************************
//
// amdtps_api.h
//! @file
//!
//! @brief Brief description of the header. No need to get fancy here.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef AMDTPS_API_H
#define AMDTPS_API_H
#include "wsf_timer.h"
#include "att_api.h"
#include "amdtp_common.h"
#ifdef __cplusplus
extern "C"
{
#endif
//*****************************************************************************
//
// Macro definitions
//
//*****************************************************************************
//
// Connection control block
//
typedef struct
{
dmConnId_t connId; // Connection ID
bool_t amdtpToSend; // AMDTP notify ready to be sent on this channel
}
amdtpsConn_t;
/*! Configurable parameters */
typedef struct
{
//! Short description of each member should go here.
uint32_t reserved;
}
AmdtpsCfg_t;
//*****************************************************************************
//
// function definitions
//
//*****************************************************************************
void amdtps_init(wsfHandlerId_t handlerId, AmdtpsCfg_t *pCfg, amdtpRecvCback_t recvCback, amdtpTransCback_t transCback);
void amdtps_proc_msg(wsfMsgHdr_t *pMsg);
uint8_t amdtps_write_cback(dmConnId_t connId, uint16_t handle, uint8_t operation,
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr);
void amdtps_start(dmConnId_t connId, uint8_t timerEvt, uint8_t amdtpCccIdx);
void amdtps_stop(dmConnId_t connId);
eAmdtpStatus_t
AmdtpsSendPacket(eAmdtpPktType_t type, bool_t encrypted, bool_t enableACK, uint8_t *buf, uint16_t len);
#ifdef __cplusplus
}
#endif
#endif // AMDTPS_API_H
@@ -0,0 +1,524 @@
//*****************************************************************************
//
// amdtps_main.c
//! @file
//!
//! @brief This file provides the main application for the AMDTP service.
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include "wsf_types.h"
#include "wsf_assert.h"
#include "wsf_trace.h"
#include "wsf_buf.h" //for WsfBufAlloc and WsfBufFree
#include "bstream.h"
#include "att_api.h"
#include "svc_ch.h"
#include "svc_amdtp.h"
#include "app_api.h"
#include "app_hw.h"
#include "amdtps_api.h"
#include "am_util_debug.h"
#include "crc32.h"
#include "am_mcu_apollo.h"
#include "am_bsp.h"
#include "am_util.h"
//*****************************************************************************
//
// Global variables
//
//*****************************************************************************
uint8_t rxPktBuf[AMDTP_PACKET_SIZE];
uint8_t txPktBuf[AMDTP_PACKET_SIZE];
uint8_t ackPktBuf[20];
#if defined(AMDTPS_RXONLY) || defined(AMDTPS_RX2TX)
static int totalLen = 0;
#endif
//*****************************************************************************
//
// Macro definitions
//
//*****************************************************************************
/* Control block */
static struct
{
amdtpsConn_t conn[DM_CONN_MAX]; // connection control block
bool_t txReady; // TRUE if ready to send notifications
wsfHandlerId_t appHandlerId;
AmdtpsCfg_t cfg; // configurable parameters
amdtpCb_t core;
}
amdtpsCb;
//*****************************************************************************
//
// Connection Open event
//
//*****************************************************************************
static void
amdtps_conn_open(dmEvt_t *pMsg)
{
hciLeConnCmplEvt_t *evt = (hciLeConnCmplEvt_t*) pMsg;
APP_TRACE_INFO0("connection opened\n");
APP_TRACE_INFO1("handle = 0x%x\n", evt->handle);
APP_TRACE_INFO1("role = 0x%x\n", evt->role);
APP_TRACE_INFO3("addrMSB = %02x%02x%02x%02x%02x%02x\n", evt->peerAddr[0], evt->peerAddr[1], evt->peerAddr[2]);
APP_TRACE_INFO3("addrLSB = %02x%02x%02x%02x%02x%02x\n", evt->peerAddr[3], evt->peerAddr[4], evt->peerAddr[5]);
APP_TRACE_INFO1("connInterval = 0x%x\n", evt->connInterval);
APP_TRACE_INFO1("connLatency = 0x%x\n", evt->connLatency);
APP_TRACE_INFO1("supTimeout = 0x%x\n", evt->supTimeout);
}
//*****************************************************************************
//
// Connection Update event
//
//*****************************************************************************
static void
amdtps_conn_update(dmEvt_t *pMsg)
{
hciLeConnUpdateCmplEvt_t *evt = (hciLeConnUpdateCmplEvt_t*) pMsg;
APP_TRACE_INFO1("connection update status = 0x%x", evt->status);
APP_TRACE_INFO1("handle = 0x%x", evt->handle);
APP_TRACE_INFO1("connInterval = 0x%x", evt->connInterval);
APP_TRACE_INFO1("connLatency = 0x%x", evt->connLatency);
APP_TRACE_INFO1("supTimeout = 0x%x", evt->supTimeout);
}
static void amdtpsSetupToSend(void)
{
amdtpsConn_t *pConn = amdtpsCb.conn;
uint8_t i;
for (i = 0; i < DM_CONN_MAX; i++, pConn++)
{
if (pConn->connId != DM_CONN_ID_NONE)
{
pConn->amdtpToSend = TRUE;
}
}
}
//*****************************************************************************
//
// Find Next Connection to Send on
//
//*****************************************************************************
static amdtpsConn_t*
amdtps_find_next2send(void)
{
amdtpsConn_t *pConn = amdtpsCb.conn;
return pConn;
}
//*****************************************************************************
//
// Send Notification to Client
//
//*****************************************************************************
static void
amdtpsSendData(uint8_t *buf, uint16_t len)
{
amdtpsSetupToSend();
amdtpsConn_t *pConn = amdtps_find_next2send();
/* send notification */
if (pConn)
{
#ifdef AMDTP_DEBUG_ON
APP_TRACE_INFO1("amdtpsSendData(), Send to connId = %d\n", pConn->connId);
#endif
AttsHandleValueNtf(pConn->connId, AMDTPS_TX_HDL, len, buf);
pConn->amdtpToSend = false;
amdtpsCb.txReady = false;
}
else
{
APP_TRACE_WARN1("Invalid Conn = %d\n", pConn->connId);
}
}
static eAmdtpStatus_t
amdtpsSendAck(eAmdtpPktType_t type, bool_t encrypted, bool_t enableACK, uint8_t *buf, uint16_t len)
{
AmdtpBuildPkt(&amdtpsCb.core, type, encrypted, enableACK, buf, len);
// send packet
amdtpsSetupToSend();
amdtpsConn_t *pConn = amdtps_find_next2send();
/* send notification */
if (pConn)
{
#ifdef AMDTP_DEBUG_ON
APP_TRACE_INFO1("amdtpsSendAck(), Send to connId = %d\n", pConn->connId);
#endif
AttsHandleValueNtf(pConn->connId, AMDTPS_ACK_HDL, amdtpsCb.core.ackPkt.len, amdtpsCb.core.ackPkt.data);
pConn->amdtpToSend = false;
}
else
{
APP_TRACE_WARN1("Invalid Conn = %d\n", pConn->connId);
return AMDTP_STATUS_TX_NOT_READY;
}
return AMDTP_STATUS_SUCCESS;
}
//*****************************************************************************
//
// Timer Expiration handler
//
//*****************************************************************************
static void
amdtps_timeout_timer_expired(wsfMsgHdr_t *pMsg)
{
uint8_t data[1];
data[0] = amdtpsCb.core.txPktSn;
APP_TRACE_INFO1("amdtps tx timeout, txPktSn = %d", amdtpsCb.core.txPktSn);
AmdtpSendControl(&amdtpsCb.core, AMDTP_CONTROL_RESEND_REQ, data, 1);
// fire a timer for receiving an AMDTP_STATUS_RESEND_REPLY ACK
WsfTimerStartMs(&amdtpsCb.core.timeoutTimer, amdtpsCb.core.txTimeoutMs);
}
/*************************************************************************************************/
/*!
* \fn amdtpsHandleValueCnf
*
* \brief Handle a received ATT handle value confirm.
*
* \param pMsg Event message.
*
* \return None.
*/
/*************************************************************************************************/
static void
amdtpsHandleValueCnf(attEvt_t *pMsg)
{
//APP_TRACE_INFO2("Cnf status = %d, handle = 0x%x\n", pMsg->hdr.status, pMsg->handle);
if (pMsg->hdr.status == ATT_SUCCESS)
{
#if !defined(AMDTPS_RXONLY) && !defined(AMDTPS_RX2TX)
if (pMsg->handle == AMDTPS_TX_HDL)
{
amdtpsCb.txReady = true;
// process next data
AmdtpSendPacketHandler(&amdtpsCb.core);
#ifdef AMDTPS_TXTEST
// fixme when last packet, continue to send next one.
if (amdtpsCb.core.txState == AMDTP_STATE_WAITING_ACK)
{
uint8_t temp[3];
temp[0] = AMDTP_STATUS_SUCCESS;
AmdtpPacketHandler(&amdtpsCb.core, AMDTP_PKT_TYPE_ACK, 3, temp);
}
#endif
}
#endif
}
else
{
#if 0 //def AMDTPS_TXTEST
// workround for ATT timeout issue
/* Connection control block */
typedef struct
{
wsfQueue_t prepWriteQueue; /* prepare write queue */
wsfTimer_t idleTimer; /* service discovery idle timer */
uint16_t handle; /* connection handle */
uint16_t mtu; /* connection mtu */
dmConnId_t connId; /* DM connection ID */
bool_t mtuSent; /* MTU req or rsp sent */
bool_t flowDisabled; /* Data flow disabled */
bool_t transTimedOut; /* ATT transaction timed out */
} attCcb_t;
extern attCcb_t *attCcbByConnId(dmConnId_t connId);
if (pMsg->hdr.status == 0x71)
{
attCcb_t *ccb = attCcbByConnId(1);
ccb->transTimedOut = FALSE;
}
#endif
APP_TRACE_WARN2("cnf status = %d, hdl = 0x%x\n", pMsg->hdr.status, pMsg->handle);
}
}
//*****************************************************************************
//
//! @brief initialize amdtp service
//!
//! @param handlerId - connection handle
//! @param pCfg - configuration parameters
//!
//! @return None
//
//*****************************************************************************
void
amdtps_init(wsfHandlerId_t handlerId, AmdtpsCfg_t *pCfg, amdtpRecvCback_t recvCback, amdtpTransCback_t transCback)
{
memset(&amdtpsCb, 0, sizeof(amdtpsCb));
amdtpsCb.appHandlerId = handlerId;
amdtpsCb.txReady = false;
amdtpsCb.core.txState = AMDTP_STATE_INIT;
amdtpsCb.core.rxState = AMDTP_STATE_RX_IDLE;
amdtpsCb.core.timeoutTimer.handlerId = handlerId;
for (int i = 0; i < DM_CONN_MAX; i++)
{
amdtpsCb.conn[i].connId = DM_CONN_ID_NONE;
}
amdtpsCb.core.lastRxPktSn = 0;
amdtpsCb.core.txPktSn = 0;
resetPkt(&amdtpsCb.core.rxPkt);
amdtpsCb.core.rxPkt.data = rxPktBuf;
resetPkt(&amdtpsCb.core.txPkt);
amdtpsCb.core.txPkt.data = txPktBuf;
resetPkt(&amdtpsCb.core.ackPkt);
amdtpsCb.core.ackPkt.data = ackPktBuf;
amdtpsCb.core.recvCback = recvCback;
amdtpsCb.core.transCback = transCback;
amdtpsCb.core.txTimeoutMs = TX_TIMEOUT_DEFAULT;
amdtpsCb.core.data_sender_func = amdtpsSendData;
amdtpsCb.core.ack_sender_func = amdtpsSendAck;
}
static void
amdtps_conn_close(dmEvt_t *pMsg)
{
hciDisconnectCmplEvt_t *evt = (hciDisconnectCmplEvt_t*) pMsg;
dmConnId_t connId = evt->hdr.param;
/* clear connection */
amdtpsCb.conn[connId - 1].connId = DM_CONN_ID_NONE;
amdtpsCb.conn[connId - 1].amdtpToSend = FALSE;
WsfTimerStop(&amdtpsCb.core.timeoutTimer);
amdtpsCb.core.txState = AMDTP_STATE_INIT;
amdtpsCb.core.rxState = AMDTP_STATE_RX_IDLE;
amdtpsCb.core.lastRxPktSn = 0;
amdtpsCb.core.txPktSn = 0;
resetPkt(&amdtpsCb.core.rxPkt);
resetPkt(&amdtpsCb.core.txPkt);
resetPkt(&amdtpsCb.core.ackPkt);
#if defined(AMDTPS_RXONLY) || defined(AMDTPS_RX2TX)
APP_TRACE_INFO1("*** RECEIVED TOTAL %d ***", totalLen);
totalLen = 0;
#endif
}
uint8_t
amdtps_write_cback(dmConnId_t connId, uint16_t handle, uint8_t operation,
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr)
{
eAmdtpStatus_t status = AMDTP_STATUS_UNKNOWN_ERROR;
amdtpPacket_t *pkt = NULL;
#if 0
uint16_t i = 0;
APP_TRACE_INFO0("============= data arrived start ===============");
for (i = 0; i < len; i++)
{
APP_TRACE_INFO1("%x\t", pValue[i]);
}
APP_TRACE_INFO0("");
APP_TRACE_INFO0("============= data arrived end ===============");
#endif
if (handle == AMDTPS_RX_HDL)
{
#if defined(AMDTPS_RX2TX)
amdtpsSendData(pValue, len);
#endif
#if defined(AMDTPS_RXONLY) || defined(AMDTPS_RX2TX)
totalLen += len;
APP_TRACE_INFO2("received data len %d, total %d", len, totalLen);
return ATT_SUCCESS;
#else /* RXONLY && RX2TX */
status = AmdtpReceivePkt(&amdtpsCb.core, &amdtpsCb.core.rxPkt, len, pValue);
#endif /* RXONLY && RX2TX */
}
else if (handle == AMDTPS_ACK_HDL)
{
status = AmdtpReceivePkt(&amdtpsCb.core, &amdtpsCb.core.ackPkt, len, pValue);
}
if (status == AMDTP_STATUS_RECEIVE_DONE)
{
if (handle == AMDTPS_RX_HDL)
{
pkt = &amdtpsCb.core.rxPkt;
}
else if (handle == AMDTPS_ACK_HDL)
{
pkt = &amdtpsCb.core.ackPkt;
}
AmdtpPacketHandler(&amdtpsCb.core, (eAmdtpPktType_t)pkt->header.pktType, pkt->len - AMDTP_CRC_SIZE_IN_PKT, pkt->data);
}
return ATT_SUCCESS;
}
void
amdtps_start(dmConnId_t connId, uint8_t timerEvt, uint8_t amdtpCccIdx)
{
//
// set conn id
//
amdtpsCb.conn[connId - 1].connId = connId;
amdtpsCb.conn[connId - 1].amdtpToSend = TRUE;
amdtpsCb.core.timeoutTimer.msg.event = timerEvt;
amdtpsCb.core.txState = AMDTP_STATE_TX_IDLE;
amdtpsCb.txReady = true;
amdtpsCb.core.attMtuSize = AttGetMtu(connId);
APP_TRACE_INFO1("MTU size = %d bytes", amdtpsCb.core.attMtuSize);
}
void
amdtps_stop(dmConnId_t connId)
{
//
// clear connection
//
amdtpsCb.conn[connId - 1].connId = DM_CONN_ID_NONE;
amdtpsCb.conn[connId - 1].amdtpToSend = FALSE;
amdtpsCb.core.txState = AMDTP_STATE_INIT;
amdtpsCb.txReady = false;
}
void
amdtps_proc_msg(wsfMsgHdr_t *pMsg)
{
if (pMsg->event == DM_CONN_OPEN_IND)
{
amdtps_conn_open((dmEvt_t *) pMsg);
}
else if (pMsg->event == DM_CONN_CLOSE_IND)
{
amdtps_conn_close((dmEvt_t *) pMsg);
}
else if (pMsg->event == DM_CONN_UPDATE_IND)
{
amdtps_conn_update((dmEvt_t *) pMsg);
}
else if (pMsg->event == amdtpsCb.core.timeoutTimer.msg.event)
{
amdtps_timeout_timer_expired(pMsg);
}
else if (pMsg->event == ATTS_HANDLE_VALUE_CNF)
{
amdtpsHandleValueCnf((attEvt_t *) pMsg);
}
}
//*****************************************************************************
//
//! @brief Send data to Client via notification
//!
//! @param type - packet type
//! @param encrypted - is packet encrypted
//! @param enableACK - does client need to response
//! @param buf - data
//! @param len - data length
//!
//! @return status
//
//*****************************************************************************
eAmdtpStatus_t
AmdtpsSendPacket(eAmdtpPktType_t type, bool_t encrypted, bool_t enableACK, uint8_t *buf, uint16_t len)
{
//
// Check if ready to send notification
//
if ( !amdtpsCb.txReady )
{
//set in callback amdtpsHandleValueCnf
APP_TRACE_INFO1("data sending failed, not ready for notification.", NULL);
return AMDTP_STATUS_TX_NOT_READY;
}
//
// Check if the service is idle to send
//
if ( amdtpsCb.core.txState != AMDTP_STATE_TX_IDLE )
{
APP_TRACE_INFO1("data sending failed, tx state = %d", amdtpsCb.core.txState);
return AMDTP_STATUS_BUSY;
}
//
// Check if data length is valid
//
if ( len > AMDTP_MAX_PAYLOAD_SIZE )
{
APP_TRACE_INFO1("data sending failed, exceed maximum payload, len = %d.", len);
return AMDTP_STATUS_INVALID_PKT_LENGTH;
}
AmdtpBuildPkt(&amdtpsCb.core, type, encrypted, enableACK, buf, len);
// send packet
AmdtpSendPacketHandler(&amdtpsCb.core);
return AMDTP_STATUS_SUCCESS;
}
@@ -0,0 +1,120 @@
//*****************************************************************************
//
// amotas_api.h
//! @file
//!
//! @brief Brief description of the header. No need to get fancy here.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef AMOTAS_API_H
#define AMOTAS_API_H
#include "wsf_timer.h"
#include "att_api.h"
// enable debug print for AMOTA profile
// #define AMOTA_DEBUG_ON
#ifdef __cplusplus
extern "C"
{
#endif
//*****************************************************************************
//
// Macro definitions
//
//*****************************************************************************
#define AMOTA_PACKET_SIZE (512 + 16) // Bytes
#define AMOTA_LENGTH_SIZE_IN_PKT 2
#define AMOTA_CMD_SIZE_IN_PKT 1
#define AMOTA_CRC_SIZE_IN_PKT 4
#define AMOTA_HEADER_SIZE_IN_PKT AMOTA_LENGTH_SIZE_IN_PKT + AMOTA_CMD_SIZE_IN_PKT
#define AMOTA_FW_HEADER_SIZE 44
#define AMOTA_FW_STORAGE_INTERNAL 0
#define AMOTA_FW_STORAGE_EXTERNAL 1
/*! Configurable parameters */
typedef struct
{
//! Short description of each member should go here.
uint32_t reserved;
}
AmotasCfg_t;
//*****************************************************************************
//
// External variable definitions
//
//*****************************************************************************
//*****************************************************************************
//
// External function definitions.
//
//*****************************************************************************
//*****************************************************************************
//
// function definitions
//
//*****************************************************************************
void amotas_init(wsfHandlerId_t handlerId, AmotasCfg_t *pCfg);
void amotas_proc_msg(wsfMsgHdr_t *pMsg);
uint8_t amotas_write_cback(dmConnId_t connId, uint16_t handle, uint8_t operation,
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr);
void amotas_start(dmConnId_t connId, uint8_t resetTimerEvt, uint8_t disconnectTimerEvt, uint8_t amotaCccIdx);
void amotas_stop(dmConnId_t connId);
extern void amotas_conn_close(dmConnId_t connId);
#ifdef __cplusplus
}
#endif
#endif // AMOTAS_API_H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,232 @@
//*****************************************************************************
//
// ancc_api.h
//! @file
//!
//! @brief apple notification center service client.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef ANCC_API_H
#define ANCC_API_H
#include "att_api.h"
#ifdef __cplusplus
extern "C" {
#endif
/**************************************************************************************************
Macros
**************************************************************************************************/
/* ANCS Service */ // 7905F431-B5CE-4E99-A40F-4B1E122D00D0
#define ATT_UUID_ANCS_SERVICE 0xd0, 0x00, 0x2d, 0x12, 0x1e, 0x4b, 0x0f, 0xa4,\
0x99, 0x4e, 0xce, 0xb5, 0x31, 0xf4, 0x05, 0x79
/* ANCS characteristics */
// 9FBF120D-6301-42D9-8C58-25E699A21DBD
#define ATT_UUID_NOTIFICATION_SOURCE 0xbd, 0x1d, 0xa2, 0x99, 0xe6, 0x25, 0x58, 0x8c, \
0xd9, 0x42, 0x01, 0x63, 0x0d, 0x12, 0xbf, 0x9f
//69D1D8F3-45E1-49A8-9821-9BBDFDAAD9D9
#define ATT_UUID_CTRL_POINT 0xd9, 0xd9, 0xaa, 0xfd, 0xbd, 0x9b, 0x21, 0x98,\
0xa8, 0x49, 0xe1, 0x45, 0xf3, 0xd8, 0xd1, 0x69
// 22EAC6E9-24D6-4BB5-BE44-B36ACE7C7BFB
#define ATT_UUID_DATA_SOURCE 0xfb, 0x7b, 0x7c, 0xce, 0x6a, 0xb3, 0x44, 0xbe,\
0xb5, 0x4b, 0xd6, 0x24, 0xe9, 0xc6, 0xea, 0x22
#define ANCC_LIST_ELEMENTS 64
#define ANCC_APP_IDENTIFIER_SIZE_BYTES 64
#define ANCC_ATTRI_BUFFER_SIZE_BYTES 512
/**@brief Category IDs for iOS notifications. */
typedef enum
{
BLE_ANCS_CATEGORY_ID_OTHER, /**< The iOS notification belongs to the "other" category. */
BLE_ANCS_CATEGORY_ID_INCOMING_CALL, /**< The iOS notification belongs to the "Incoming Call" category. */
BLE_ANCS_CATEGORY_ID_MISSED_CALL, /**< The iOS notification belongs to the "Missed Call" category. */
BLE_ANCS_CATEGORY_ID_VOICE_MAIL, /**< The iOS notification belongs to the "Voice Mail" category. */
BLE_ANCS_CATEGORY_ID_SOCIAL, /**< The iOS notification belongs to the "Social" category. */
BLE_ANCS_CATEGORY_ID_SCHEDULE, /**< The iOS notification belongs to the "Schedule" category. */
BLE_ANCS_CATEGORY_ID_EMAIL, /**< The iOS notification belongs to the "E-mail" category. */
BLE_ANCS_CATEGORY_ID_NEWS, /**< The iOS notification belongs to the "News" category. */
BLE_ANCS_CATEGORY_ID_HEALTH_AND_FITNESS, /**< The iOS notification belongs to the "Health and Fitness" category. */
BLE_ANCS_CATEGORY_ID_BUSINESS_AND_FINANCE, /**< The iOS notification belongs to the "Buisness and Finance" category. */
BLE_ANCS_CATEGORY_ID_LOCATION, /**< The iOS notification belongs to the "Location" category. */
BLE_ANCS_CATEGORY_ID_ENTERTAINMENT /**< The iOS notification belongs to the "Entertainment" category. */
} ancc_category_id_values_t;
/**@brief Event IDs for iOS notifications. */
typedef enum
{
BLE_ANCS_EVENT_ID_NOTIFICATION_ADDED, /**< The iOS notification was added. */
BLE_ANCS_EVENT_ID_NOTIFICATION_MODIFIED, /**< The iOS notification was modified. */
BLE_ANCS_EVENT_ID_NOTIFICATION_REMOVED /**< The iOS notification was removed. */
} ancc_evt_id_values_t;
/**@brief Control point command IDs that the Notification Consumer can send to the Notification Provider. */
typedef enum
{
BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES, /**< Requests attributes to be sent from the NP to the NC for a given notification. */
BLE_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES, /**< Requests attributes to be sent from the NP to the NC for a given iOS App. */
BLE_ANCS_COMMAND_ID_GET_PERFORM_NOTIF_ACTION, /**< Requests an action to be performed on a given notification, for example dismiss an alarm. */
} ancc_command_id_values_t;
/**@brief IDs for iOS notification attributes. */
typedef enum
{
BLE_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER, /**< Identifies that the attribute data is of an "App Identifier" type. */
BLE_ANCS_NOTIF_ATTR_ID_TITLE, /**< Identifies that the attribute data is a "Title". Needs to be followed by a 2-bytes max length parameter*/
BLE_ANCS_NOTIF_ATTR_ID_SUBTITLE, /**< Identifies that the attribute data is a "Subtitle". Needs to be followed by a 2-bytes max length parameter*/
BLE_ANCS_NOTIF_ATTR_ID_MESSAGE, /**< Identifies that the attribute data is a "Message". Needs to be followed by a 2-bytes max length parameter*/
BLE_ANCS_NOTIF_ATTR_ID_MESSAGE_SIZE, /**< Identifies that the attribute data is a "Message Size". */
BLE_ANCS_NOTIF_ATTR_ID_DATE, /**< Identifies that the attribute data is a "Date". */
BLE_ANCS_NOTIF_ATTR_ID_POSITIVE_ACTION_LABEL, /**< The notification has a "Positive action" that can be executed associated with it. */
BLE_ANCS_NOTIF_ATTR_ID_NEGATIVE_ACTION_LABEL, /**< The notification has a "Negative action" that can be executed associated with it. */
} ancc_notif_attr_id_values_t;
/**@brief ActionID values. */
typedef enum
{
BLE_ANCS_NOTIF_ACTION_ID_POSITIVE,
BLE_ANCS_NOTIF_ACTION_ID_NEGATIVE,
} ancc_notif_action_id_values_t;
/**@brief Typedef for iOS notifications. */
typedef struct
{
uint8_t event_id; /**< This field informs the accessory whether the given iOS notification was added, modified, or removed. The enumerated values for this field are defined in EventID Values.. */
uint8_t event_flags; /**< A bitmask whose set bits inform an NC of specificities with the iOS notification. */
uint8_t category_id; /**< A numerical value providing a category in which the iOS notification can be classified. */
uint8_t category_count; /**< The current number of active iOS notifications in the given category. */
uint32_t notification_uid; /**< A 32-bit numerical value that is the unique identifier (UID) for the iOS notification. */
bool_t noti_valid; /**< A flag to indicate whether the notification is still valid in the list. */
} ancc_notif_t;
/*! ancs client enumeration of handle indexes of characteristics to be discovered */
enum
{
ANCC_NOTIFICATION_SOURCE_HDL_IDX, // ANCC Notification Source Handle
ANCC_NOTIFICATION_SOURCE_CCC_HDL_IDX, // ANCC Notification Source CCC Handle
ANCC_CONTROL_POINT_HDL_IDX, // ANCC Control Point Handle
ANCC_DATA_SOURCE_HDL_IDX, // ANCC Data Source Handle
ANCC_DATA_SOURCE_CCC_HDL_IDX, // ANCC Data Source CCC Handle
ANCC_HDL_LIST_LEN /*! Handle list length */
};
/*! Configurable parameters */
typedef struct
{
wsfTimerTicks_t period; /*! action timer expiration period in ms */
} anccCfg_t;
typedef enum
{
NOTI_ATTR_NEW_NOTIFICATION = 0,
NOTI_ATTR_NEW_ATTRIBUTE,
NOTI_ATTR_RECEIVING_ATTRIBUTE
} enum_active_state_t;
typedef struct
{
uint16_t handle; // handle to indicate the current active notification in the list
enum_active_state_t attrState;
uint16_t bufIndex;
uint16_t parseIndex;
uint16_t attrLength;
uint8_t attrId;
uint16_t attrCount;
uint8_t commandId;
uint32_t notiUid;
uint8_t appId[ANCC_APP_IDENTIFIER_SIZE_BYTES];
uint8_t attrDataBuf[ANCC_ATTRI_BUFFER_SIZE_BYTES];
} active_notif_t;
/*! Application data reception callback */
typedef void (*anccAttrRecvCback_t)(active_notif_t* pAttr);
typedef void (*anccNotiCmplCback_t)(active_notif_t* pAttr, uint32_t notiUid);
/*! Application notify remove callback */
typedef void (*anccNotiRemoveCback_t)(ancc_notif_t* pAttr);
typedef struct
{
dmConnId_t connId;
uint16_t* hdlList;
anccCfg_t cfg;
wsfTimer_t actionTimer; // perform actions with proper delay
wsfTimer_t discoverTimer; // perform service discovery delay
ancc_notif_t anccList[ANCC_LIST_ELEMENTS]; // buffer size = MAX_LIST_ELEMENTS*sizeof(ancc_notif_t)
active_notif_t active;
anccAttrRecvCback_t attrCback;
anccNotiCmplCback_t notiCback;
anccNotiRemoveCback_t rmvCback;
} anccCb_t;
/**************************************************************************************************
Function Prototypes
**************************************************************************************************/
// operation interfaces
void AncsPerformNotiAction(uint16_t *pHdlList, uint32_t notiUid, ancc_notif_action_id_values_t actionId);
void AncsGetAppAttribute(uint16_t *pHdlList, uint8_t* appId);
void AnccGetNotificationAttribute(uint16_t *pHdlList, uint32_t notiUid);
// initialization interfaces
void AnccInit(wsfHandlerId_t handlerId, anccCfg_t* cfg, uint8_t disctimer_event);
void AnccCbackRegister(anccAttrRecvCback_t attrCback, anccNotiCmplCback_t notiCback, anccNotiRemoveCback_t rmvCback);
// app routines
void AnccNtfValueUpdate(uint16_t *pHdlList, attEvt_t * pMsg, uint8_t actionTimerEvt);
void AnccActionHandler(uint8_t actionTimerEvt);
void AnccActionStop(void);
void AnccActionStart(uint8_t timerEvt);
void AnccConnClose(void);
void AnccConnOpen(dmConnId_t connId, uint16_t* hdlList);
void AnccSvcDiscover(dmConnId_t connId, uint16_t *pHdlList);
bool_t AnccStartServiceDiscovery(void);
/* Global variable */
extern anccCb_t anccCb;
#ifdef __cplusplus
};
#endif
#endif /* ANCC_API_H */
@@ -0,0 +1,709 @@
//*****************************************************************************
//
// ancc_main.c
//! @file
//!
//! @brief apple notification center service client.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include <string.h>
#include "wsf_types.h"
#include "wsf_assert.h"
#include "bstream.h"
#include "app_api.h"
#include "ancc_api.h"
#include "am_util.h"
/**************************************************************************************************
Local Variables
**************************************************************************************************/
/*!
* Apple Notification Center Service Client (ANCC)
*/
/* UUIDs */
static const uint8_t anccAncsSvcUuid[] = {ATT_UUID_ANCS_SERVICE}; /*! ANCS Service UUID */
static const uint8_t anccNSChUuid[] = {ATT_UUID_NOTIFICATION_SOURCE}; /*! Notification Source UUID */
static const uint8_t anccCPChUuid[] = {ATT_UUID_CTRL_POINT}; /*! control point UUID*/
static const uint8_t anccDSChUuid[] = {ATT_UUID_DATA_SOURCE}; /*! data source UUID*/
/* Characteristics for discovery */
#define DISCOVER_TIMER_DELAY (3000) // ms
/*! Proprietary data */
static const attcDiscChar_t anccNSDat =
{
anccNSChUuid,
ATTC_SET_REQUIRED | ATTC_SET_UUID_128
};
/*! Proprietary data descriptor */ //notification source
static const attcDiscChar_t anccNSdatCcc =
{
attCliChCfgUuid,
ATTC_SET_REQUIRED | ATTC_SET_DESCRIPTOR
};
// control point
static const attcDiscChar_t anccCtrlPoint =
{
anccCPChUuid,
ATTC_SET_REQUIRED | ATTC_SET_UUID_128
};
// data source
static const attcDiscChar_t anccDataSrc =
{
anccDSChUuid,
ATTC_SET_REQUIRED | ATTC_SET_UUID_128
};
/*! Proprietary data descriptor */ //data source
static const attcDiscChar_t anccDataSrcCcc =
{
attCliChCfgUuid,
ATTC_SET_REQUIRED | ATTC_SET_DESCRIPTOR
};
/*! List of characteristics to be discovered; order matches handle index enumeration */
static const attcDiscChar_t *anccSvcDiscCharList[] =
{
&anccNSDat, /*! Proprietary data */
&anccNSdatCcc, /*! Proprietary data descriptor */
&anccCtrlPoint, /*! Control point */
&anccDataSrc, /*! data source */
&anccDataSrcCcc /*! data source descriptor */
};
/* sanity check: make sure handle list length matches characteristic list length */
WSF_CT_ASSERT(ANCC_HDL_LIST_LEN == ((sizeof(anccSvcDiscCharList) / sizeof(attcDiscChar_t *))));
/* Global variable */
anccCb_t anccCb;
/*************************************************************************************************/
/*!
* \fn AnccSvcDiscover
*
* \brief Perform service and characteristic discovery for ancs service.
* Parameter pHdlList must point to an array of length ANCC_HDL_LIST_LEN.
* If discovery is successful the handles of discovered characteristics and
* descriptors will be set in pHdlList.
*
* \param connId Connection identifier.
* \param pHdlList Characteristic handle list.
*
* \return None.
*/
/*************************************************************************************************/
void AnccSvcDiscover(dmConnId_t connId, uint16_t *pHdlList)
{
AppDiscFindService(connId, ATT_128_UUID_LEN, (uint8_t *) anccAncsSvcUuid,
ANCC_HDL_LIST_LEN, (attcDiscChar_t **) anccSvcDiscCharList, pHdlList);
}
/*************************************************************************************************/
/*!
* \fn AnccInit
*
* \brief Initialize the control variables of ancs client
*
* \param handlerId App handler id for timer operation.
* \param cfg config variable.
*
* \return None.
*/
/*************************************************************************************************/
void AnccInit(wsfHandlerId_t handlerId, anccCfg_t* cfg, uint8_t disctimer_event)
{
memset(anccCb.anccList, 0, ANCC_LIST_ELEMENTS * sizeof(ancc_notif_t));
anccCb.cfg.period = cfg->period;
anccCb.actionTimer.handlerId = handlerId;
anccCb.discoverTimer.handlerId = handlerId;
anccCb.discoverTimer.msg.event = disctimer_event;
}
/*************************************************************************************************/
/*!
* \fn AnccConnOpen
*
* \brief Update the key parameters for control variables when connection open.
*
* \param connId Connection identifier.
* \param hdlList Characteristic handle list.
*
* \return None.
*/
/*************************************************************************************************/
void AnccConnOpen(dmConnId_t connId, uint16_t* hdlList)
{
anccCb.connId = connId;
anccCb.hdlList = hdlList;
WsfTimerStop(&anccCb.discoverTimer);
WsfTimerStartMs(&anccCb.discoverTimer, DISCOVER_TIMER_DELAY);
}
/*************************************************************************************************/
/*!
* \fn AnccConnClose
*
* \brief Clear the key parameters for control variables when connection close.
*
* \param None.
*
* \return None.
*/
/*************************************************************************************************/
void AnccConnClose(void)
{
WsfTimerStop(&anccCb.discoverTimer);
anccCb.connId = DM_CONN_ID_NONE;
}
/*************************************************************************************************/
/*!
* \fn anccNoConnActive
*
* \brief Return TRUE if no connections with active measurements.
*
* \return TRUE if no connections active.
*/
/*************************************************************************************************/
static bool_t anccNoConnActive(void)
{
if (anccCb.connId != DM_CONN_ID_NONE)
{
return FALSE;
}
return TRUE;
}
/*************************************************************************************************/
/*!
* \fn anccActionListPush
*
* \brief Return TRUE if element is added/updated to the list.
*
* \return TRUE if element is added/updated to the list.
* FALSE if list is full.
*/
/*************************************************************************************************/
static bool_t anccActionListPush(ancc_notif_t* pElement)
{
uint16_t i;
for ( i = 0; i < ANCC_LIST_ELEMENTS; i++ )
{
if ( (anccCb.anccList[i].notification_uid == pElement->notification_uid ) && (anccCb.anccList[i].noti_valid == true) )
{
// same notification uid received, update the element
anccCb.anccList[i].notification_uid = pElement->notification_uid;
anccCb.anccList[i].event_id = pElement->event_id;
anccCb.anccList[i].event_flags = pElement->event_flags;
anccCb.anccList[i].category_id = pElement->category_id;
anccCb.anccList[i].category_count = pElement->category_count;
return true;
}
}
for ( i = 0; i < ANCC_LIST_ELEMENTS; i++ )
{
if ( anccCb.anccList[i].noti_valid == false )
{
// found an empty slot
anccCb.anccList[i].notification_uid = pElement->notification_uid;
anccCb.anccList[i].event_id = pElement->event_id;
anccCb.anccList[i].event_flags = pElement->event_flags;
anccCb.anccList[i].category_id = pElement->category_id;
anccCb.anccList[i].category_count = pElement->category_count;
anccCb.anccList[i].noti_valid = true;
return true;
}
}
return false; //no empty slot left
}
/*************************************************************************************************/
/*!
* \fn anccActionListPop
*
* \brief Return TRUE if element is popped out and removed from the list.
*
* \return TRUE if element is popped out and removed from the list.
* FALSE if list is already empty.
*/
/*************************************************************************************************/
static bool_t anccActionListPop(void)
{
uint16_t i;
for ( i = 0; i < ANCC_LIST_ELEMENTS; i++ )
{
if ( anccCb.anccList[ANCC_LIST_ELEMENTS - i - 1].noti_valid == true )
{
// found a valid element in the list
anccCb.anccList[ANCC_LIST_ELEMENTS - i - 1].noti_valid = false;
anccCb.active.handle = ANCC_LIST_ELEMENTS - i - 1;
return true;
}
}
return false; //no element left in the list
}
/*************************************************************************************************/
/*!
* \fn AnccActionStart
*
* \brief Start periodic ancc operation. This function starts a timer to perform
* periodic actions.
*
* \param timerEvt WSF event designated by the application for the timer.
*
* \return None.
*/
/*************************************************************************************************/
void AnccActionStart(uint8_t timerEvt)
{
/* if this is first connection */
if (anccNoConnActive() == FALSE)
{
/* initialize control block */
anccCb.actionTimer.msg.event = timerEvt;
/* (re-)start timer */
WsfTimerStop(&anccCb.actionTimer);
WsfTimerStartMs(&anccCb.actionTimer, anccCb.cfg.period);
}
}
/*************************************************************************************************/
/*!
* \fn AnccActionStop
*
* \brief Stop periodic ancc action.
*
* \param connId DM connection identifier.
*
* \return None.
*/
/*************************************************************************************************/
void AnccActionStop(void)
{
/* stop timer */
WsfTimerStop(&anccCb.actionTimer);
}
/*************************************************************************************************/
/*!
* \fn AnccGetNotificationAttribute
*
* \brief Send a command to the apple notification center service control point.
*
* \param pHdlList Characteristic handle list.
* \param notiUid NotificationUid.
*
* \return None.
*/
/*************************************************************************************************/
void AnccGetNotificationAttribute(uint16_t *pHdlList, uint32_t notiUid)
{
// An example to get notification attributes
uint16_t max_len = 256;
uint8_t buf[19]; // retrieve the complete attribute list
if (pHdlList[ANCC_CONTROL_POINT_HDL_IDX] != ATT_HANDLE_NONE)
{
buf[0] = BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES; // put command
uint8_t * p = &buf[1];
UINT32_TO_BSTREAM(p, notiUid); // encode notification uid
// encode attribute IDs
buf[5] = BLE_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER;
buf[6] = BLE_ANCS_NOTIF_ATTR_ID_TITLE;
// 2 byte length
buf[7] = max_len;
buf[8] = max_len >> 8;
buf[9] = BLE_ANCS_NOTIF_ATTR_ID_SUBTITLE;
buf[10] = max_len;
buf[11] = max_len >> 8;
buf[12] = BLE_ANCS_NOTIF_ATTR_ID_MESSAGE;
buf[13] = max_len;
buf[14] = max_len >> 8;
buf[15] = BLE_ANCS_NOTIF_ATTR_ID_MESSAGE_SIZE;
buf[16] = BLE_ANCS_NOTIF_ATTR_ID_DATE;
buf[17] = BLE_ANCS_NOTIF_ATTR_ID_POSITIVE_ACTION_LABEL;
buf[18] = BLE_ANCS_NOTIF_ATTR_ID_NEGATIVE_ACTION_LABEL;
AttcWriteReq(anccCb.connId, pHdlList[ANCC_CONTROL_POINT_HDL_IDX], sizeof(buf), buf);
}
}
/*************************************************************************************************/
/*!
* \fn AncsGetAppAttribute
*
* \brief Send a command to the apple notification center service control point.
*
* \param pHdlList Connection identifier.
* \param pAppId Attribute handle.
*
* \return None.
*/
/*************************************************************************************************/
void AncsGetAppAttribute(uint16_t *pHdlList, uint8_t *pAppId)
{
// An example to get app attributes
uint8_t buf[64]; // to hold the command, size of app identifier is unknown
uint8_t count = 0;
if (pHdlList[ANCC_CONTROL_POINT_HDL_IDX] != ATT_HANDLE_NONE)
{
buf[0] = BLE_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES; // put command
while (pAppId[count++] != 0); // NULL terminated string
if ( count > (64 - 2) )
{
// app identifier is too long
}
else
{
memcpy(&buf[1], pAppId, count);
}
buf[count + 1] = 0; // app attribute id
AttcWriteReq(anccCb.connId, pHdlList[ANCC_CONTROL_POINT_HDL_IDX], (count + 2), buf);
}
}
/*************************************************************************************************/
/*!
* \fn AncsPerformNotiAction
*
* \brief Send a command to the apple notification center service control point.
*
* \param pHdlList Characteristic handle list.
* \param actionId Notification action identifier.
* \param notiUid NotificationUid.
*
* \return None.
*/
/*************************************************************************************************/
void AncsPerformNotiAction(uint16_t *pHdlList, uint32_t notiUid, ancc_notif_action_id_values_t actionId)
{
// An example to performs notification action
uint8_t buf[6]; //to hold the command, size of app identifier is unknown
if (pHdlList[ANCC_CONTROL_POINT_HDL_IDX] != ATT_HANDLE_NONE)
{
buf[0] = BLE_ANCS_COMMAND_ID_GET_PERFORM_NOTIF_ACTION; // put command
uint8_t * p = &buf[1];
UINT32_TO_BSTREAM(p, notiUid); // encode notification uid
buf[5] = actionId; //action id
AttcWriteReq(anccCb.connId, pHdlList[ANCC_CONTROL_POINT_HDL_IDX], sizeof(buf), buf);
}
}
/*************************************************************************************************/
/*!
* \fn AnccActionHandler
*
* \brief Routine to handle ancc related actions.
*
* \param actionTimerEvt WsfTimer event indication.
*
* \return None.
*/
/*************************************************************************************************/
void AnccActionHandler(uint8_t actionTimerEvt)
{
// perform action
if ( anccActionListPop() )
{
AnccGetNotificationAttribute(anccCb.hdlList, anccCb.anccList[anccCb.active.handle].notification_uid);
AnccActionStart(actionTimerEvt);
}
else
{
//list empty
AnccActionStop();
}
}
/*************************************************************************************************/
/*!
* \fn anccAttrHandler
*
* \brief Static routine to handle attribute receiving and processing.
*
* \param pMsg pointer to ATT message.
*
* \return None.
*/
/*************************************************************************************************/
static bool anccAttrHandler(attEvt_t * pMsg)
{
uint8_t count = 0;
uint16_t bytesRemaining = 0;
switch(anccCb.active.attrState)
{
case NOTI_ATTR_NEW_NOTIFICATION:
// new notification
anccCb.active.commandId = pMsg->pValue[0];
if ( anccCb.active.commandId == BLE_ANCS_COMMAND_ID_GET_NOTIF_ATTRIBUTES )
{
BYTES_TO_UINT32(anccCb.active.notiUid, &(pMsg->pValue[1]));
count = 4;
}
else if ( anccCb.active.commandId == BLE_ANCS_COMMAND_ID_GET_APP_ATTRIBUTES )
{
while(pMsg->pValue[count + 1] != 0) // NULL terminated string
{
anccCb.active.appId[count] = pMsg->pValue[count + 1];
count++;
}
anccCb.active.appId[count + 1] = 0; // NULL terminated string
}
else
{
// BLE_ANCS_COMMAND_ID_GET_PERFORM_NOTIF_ACTION
return false;
}
anccCb.active.parseIndex += count + 1;
anccCb.active.attrState = NOTI_ATTR_NEW_ATTRIBUTE;
anccCb.active.attrId = 0;
anccCb.active.attrCount = 0;
if ( pMsg->valueLen > ANCC_ATTRI_BUFFER_SIZE_BYTES )
{
// notification size overflow
}
else
{
bytesRemaining = pMsg->valueLen;
}
// copy data
memset(anccCb.active.attrDataBuf, 0, ANCC_ATTRI_BUFFER_SIZE_BYTES);
anccCb.active.bufIndex = 0;
for (uint16_t i = 0; i < bytesRemaining; i++)
{
anccCb.active.attrDataBuf[anccCb.active.bufIndex++] = pMsg->pValue[i];
}
// no break here by intention
case NOTI_ATTR_NEW_ATTRIBUTE:
// new attribute
// check consistency of the attribute
if ( anccCb.active.bufIndex - anccCb.active.parseIndex < 3 ) // 1 byte attribute id + 2 bytes attribute length
{
// attribute header not received completely
anccCb.active.attrState = NOTI_ATTR_RECEIVING_ATTRIBUTE;
return false;
}
anccCb.active.attrId = anccCb.active.attrDataBuf[anccCb.active.parseIndex];
BYTES_TO_UINT16(anccCb.active.attrLength, &(anccCb.active.attrDataBuf[anccCb.active.parseIndex + 1]));
if ( anccCb.active.attrLength > (anccCb.active.bufIndex - anccCb.active.parseIndex - 3) ) // 1 byte attribute id + 2 bytes attribute length
{
// attribute body not received completely
anccCb.active.attrState = NOTI_ATTR_RECEIVING_ATTRIBUTE;
return false;
}
// parse attribute
anccCb.active.attrCount++;
anccCb.active.parseIndex += 3; // 1 byte attribute id + 2 bytes attribute length
if ( anccCb.active.attrId == BLE_ANCS_NOTIF_ATTR_ID_APP_IDENTIFIER )
{
uint8_t temp = 0;
while(anccCb.active.attrDataBuf[anccCb.active.parseIndex + temp] != 0) // NULL terminated string
{
anccCb.active.appId[temp] = anccCb.active.attrDataBuf[anccCb.active.parseIndex + temp];
temp++;
}
anccCb.active.appId[temp] = 0; // NULL terminated string
}
//
// attribute received
// execute callback function
//
(*anccCb.attrCback)(&anccCb.active);
anccCb.active.parseIndex += anccCb.active.attrLength;
if ( anccCb.active.attrCount >= 8 ) //custom criteria
{
//notification reception done
anccCb.active.attrState = NOTI_ATTR_NEW_NOTIFICATION;
anccCb.active.parseIndex = 0;
anccCb.active.bufIndex = 0;
//
// notification received
// execute callback function
//
(*anccCb.notiCback)(&anccCb.active, anccCb.active.notiUid);
return false;
}
return true; // continue parsing
// no need to break;
case NOTI_ATTR_RECEIVING_ATTRIBUTE:
// notification continuing
bytesRemaining = 0;
if ( anccCb.active.bufIndex + pMsg->valueLen > ANCC_ATTRI_BUFFER_SIZE_BYTES )
{
// notification size overflow
anccCb.active.attrState = NOTI_ATTR_NEW_NOTIFICATION;
anccCb.active.parseIndex = 0;
anccCb.active.bufIndex = 0;
return false;
}
else
{
bytesRemaining = pMsg->valueLen;
}
// copy data
for (uint16_t i = 0; i < bytesRemaining; i++)
{
anccCb.active.attrDataBuf[anccCb.active.bufIndex++] = pMsg->pValue[i];
}
anccCb.active.attrState = NOTI_ATTR_NEW_ATTRIBUTE;
return true;
// no need to break;
}
return false;
}
/*************************************************************************************************/
/*!
* \fn AnccNtfValueUpdate
*
* \brief Routine to handle any ancc related notify.
*
* \param pHdlList Characteristic handle list.
* \param actionTimerEvt WsfTimer event indication.
* \param pMsg pointer to ATT message.
*
* \return None.
*/
/*************************************************************************************************/
void AnccNtfValueUpdate(uint16_t *pHdlList, attEvt_t * pMsg, uint8_t actionTimerEvt)
{
ancc_notif_t ancs_notif;
uint8_t *p;
//notification received
if (pMsg->handle == pHdlList[ANCC_NOTIFICATION_SOURCE_HDL_IDX])
{
// process notificiation source (brief)
p = pMsg->pValue;
ancs_notif.event_id = p[0];
ancs_notif.event_flags = p[1];
ancs_notif.category_id = p[2];
ancs_notif.category_count = p[3];
BYTES_TO_UINT32(ancs_notif.notification_uid, &p[4]);
if (BLE_ANCS_EVENT_ID_NOTIFICATION_REMOVED == ancs_notif.event_id)
{
if (NULL != anccCb.rmvCback)
{
anccCb.rmvCback(&ancs_notif);
}
}
else if ( !anccActionListPush(&ancs_notif) )
{
// list full
// APP_TRACE_INFO0("action list full...");
}
else
{
//
// actions to be done with timer delays to avoid generating heavy traffic
//
AnccActionStart(actionTimerEvt);
// APP_TRACE_INFO0("added to action list");
}
}
else if ( pMsg->handle == pHdlList[ANCC_DATA_SOURCE_HDL_IDX] )
{
// process notificiation/app attributes
while(anccAttrHandler(pMsg));
}
}
/*************************************************************************************************/
/*!
* \fn AnccCbackRegister
*
* \brief Register the attribute received callback and notification completed callback.
*
* \param attrCback Pointer to attribute received callback function.
* \param notiCback Pointer to notification completed callback function.
*
* \return None.
*/
/*************************************************************************************************/
void AnccCbackRegister(anccAttrRecvCback_t attrCback, anccNotiCmplCback_t notiCback, anccNotiRemoveCback_t rmvCback)
{
anccCb.attrCback = attrCback;
anccCb.notiCback = notiCback;
anccCb.rmvCback = rmvCback;
}
/*************************************************************************************************/
/*!
* \fn AnccStartServiceDiscovery
*
* \brief Do service discovery on connected connection.
*
* \return Return TRUE if service discovery is initiated successfully.
*
*/
/*************************************************************************************************/
bool_t AnccStartServiceDiscovery(void)
{
if (anccCb.connId != DM_CONN_ID_NONE)
{
appDiscStart(anccCb.connId);
return TRUE;
}
return FALSE;
}
@@ -0,0 +1,109 @@
//*****************************************************************************
//
// voles_api.h
//! @file
//!
//! @brief Brief description of the header. No need to get fancy here.
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef VOLES_API_H
#define VOLES_API_H
#include "wsf_timer.h"
#include "att_api.h"
#include "vole_common.h"
#ifdef __cplusplus
extern "C"
{
#endif
//*****************************************************************************
//
// Macro definitions
//
//*****************************************************************************
//
// Connection control block
//
typedef struct
{
dmConnId_t connId; // Connection ID
bool_t voleToSend; // VOLE notify ready to be sent on this channel
}
volesConn_t;
/*! Configurable parameters */
typedef struct
{
//! Short description of each member should go here.
uint32_t reserved;
}
VolesCfg_t;
//*****************************************************************************
//
// function definitions
//
//*****************************************************************************
void voles_init(wsfHandlerId_t handlerId, eVoleCodecType codec_type);
void voles_proc_msg(wsfMsgHdr_t *pMsg);
void voles_transmit_voice_data(void);
int voles_set_codec_type(eVoleCodecType codec_type);
uint8_t voles_write_cback(dmConnId_t connId, uint16_t handle, uint8_t operation,
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr);
void voles_start(dmConnId_t connId, uint8_t timerEvt, uint8_t voleCccIdx);
void voles_stop(dmConnId_t connId);
#ifdef __cplusplus
}
#endif
#endif // VOLES_API_H
@@ -0,0 +1,465 @@
//*****************************************************************************
//
// voles_main.c
//! @file
//!
//! @brief This file provides the main application for the VOLE service.
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include "wsf_types.h"
#include "wsf_assert.h"
#include "wsf_trace.h"
#include "wsf_buf.h" //for WsfBufAlloc and WsfBufFree
#include "bstream.h"
#include "att_api.h"
#include "svc_ch.h"
#include "svc_amvole.h"
#include "app_api.h"
#include "app_hw.h"
#include "voles_api.h"
#include "am_util_debug.h"
#include "crc32.h"
#include "am_mcu_apollo.h"
#include "am_bsp.h"
#include "am_util.h"
#include "sbc.h"
#include "vole_common.h"
#include "att_defs.h"
#include "vole_board_config.h"
#include "voice_data.h"
#include "ae_api.h"
//*****************************************************************************
//
// Global variables
//
//*****************************************************************************
eVoleCodecType g_vole_codec_type;
uint8_t g_ble_data_buffer[ATT_MAX_MTU];
extern bool_t g_start_voice_send;
//*****************************************************************************
//
// Macro definitions
//
//*****************************************************************************
static sbc_t g_SBCInstance;
int g_opusErr;
uint32_t g_audioSampleRate = 16000;
int32_t g_audioChannel = 1;
/* Control block */
static struct
{
volesConn_t conn[DM_CONN_MAX]; // connection control block
bool_t txReady; // TRUE if ready to send notifications
wsfHandlerId_t appHandlerId;
VolesCfg_t cfg; // configurable parameters
voleCb_t core;
}
volesCb;
extern bool am_app_KWD_AMA_tx_ver_exchange_send(void);
extern uint16_t am_app_KWD_AMA_stream_send(uint8_t* buf, uint32_t len);
extern void am_app_led_off(void);
static void voles_conn_parameter_req(void)
{
hciConnSpec_t connSpec;
connSpec.connIntervalMin = 6; //(15/1.25);//(30/1.25);
connSpec.connIntervalMax = 12; //(15/1.25);//(30/1.25);
connSpec.connLatency = 0; //0;
connSpec.supTimeout = 400;
connSpec.minCeLen = 0;
connSpec.maxCeLen = 0xffff; //fixme
DmConnUpdate(1, &connSpec);
}
//*****************************************************************************
//
// Connection Open event
//
//*****************************************************************************
static void
voles_conn_open(dmEvt_t *pMsg)
{
hciLeConnCmplEvt_t *evt = (hciLeConnCmplEvt_t*) pMsg;
APP_TRACE_INFO0("connection opened\n");
APP_TRACE_INFO1("handle = 0x%x\n", evt->handle);
APP_TRACE_INFO1("role = 0x%x\n", evt->role);
APP_TRACE_INFO3("addrMSB = %02x%02x%02x%02x%02x%02x\n", evt->peerAddr[0], evt->peerAddr[1], evt->peerAddr[2]);
APP_TRACE_INFO3("addrLSB = %02x%02x%02x%02x%02x%02x\n", evt->peerAddr[3], evt->peerAddr[4], evt->peerAddr[5]);
APP_TRACE_INFO1("connInterval = %d x 1.25 ms\n", evt->connInterval);
APP_TRACE_INFO1("connLatency = %d\n", evt->connLatency);
APP_TRACE_INFO1("supTimeout = %d ms\n", evt->supTimeout * 10);
if ( evt->connInterval > 12 )
{
voles_conn_parameter_req();
}
}
//*****************************************************************************
//
// Connection Update event
//
//*****************************************************************************
static void
voles_conn_update(dmEvt_t *pMsg)
{
hciLeConnUpdateCmplEvt_t *evt = (hciLeConnUpdateCmplEvt_t*) pMsg;
APP_TRACE_INFO1("connection update status = 0x%x", evt->status);
APP_TRACE_INFO1("handle = 0x%x", evt->handle);
APP_TRACE_INFO1("connInterval = 0x%x", evt->connInterval);
APP_TRACE_INFO1("connLatency = 0x%x", evt->connLatency);
APP_TRACE_INFO1("supTimeout = 0x%x", evt->supTimeout);
if ( evt->connInterval > (15 / 1.25) )
{
// retry
voles_conn_parameter_req();
}
}
int32_t voles_msbc_encode_voice_data(uint8_t *input, uint8_t *output, uint16_t len)
{
int32_t i32CompressedLen = 0;
if ((input == NULL) || (output == NULL))
{
return 0;
}
sbc_encoder_encode(&g_SBCInstance, input, len,
output, CODEC_MSBC_OUTPUT_SIZE, (int *)&i32CompressedLen);
APP_TRACE_INFO2("voles encode, input len:%d, compressedLen:%d", len, i32CompressedLen);
return i32CompressedLen;
}
int voles_set_codec_type(eVoleCodecType codec_type)
{
APP_TRACE_INFO1("set codec type:%s", ((codec_type == 0) ? "MSBC code" : "OPUS codec"));
if (codec_type != VOLE_CODEC_TYPE_INVALID)
{
g_vole_codec_type = codec_type;
return codec_type;
}
else
{
return VOLE_CODEC_TYPE_INVALID;
}
}
eVoleCodecType voles_get_codec_type(void)
{
return g_vole_codec_type;
}
// get the size for each sending packet
int voles_ble_buffer_size(void)
{
eVoleCodecType codec_type = voles_get_codec_type();
int buffer_size = 0;
switch(codec_type)
{
case MSBC_CODEC_IN_USE:
buffer_size = BLE_MSBC_DATA_BUFFER_SIZE;
break;
case OPUS_CODEC_IN_USE:
buffer_size = BLE_OPUS_DATA_BUFFER_SIZE;
break;
default:
break;
}
return buffer_size;
}
void voles_transmit_voice_data(void)
{
volePacket_t *txPkt = &volesCb.core.txPkt;
uint32_t offset = txPkt->offset;
int remain_data_len = 0;
int enc_data_len = 0;
uint8_t output_data[100] = {0};
int output_len = 0;
static int index = 0;
eVoleCodecType codec_type = voles_get_codec_type();
txPkt->len = sizeof(voice_data);
remain_data_len = txPkt->len - offset;
if (codec_type == MSBC_CODEC_IN_USE)
{
enc_data_len = (remain_data_len>CODEC_MSBC_INPUT_SIZE)?CODEC_MSBC_INPUT_SIZE:remain_data_len;
}
else if (codec_type == OPUS_CODEC_IN_USE)
{
enc_data_len = (remain_data_len>CODEC_OPUS_INPUT_SIZE)?CODEC_OPUS_INPUT_SIZE:remain_data_len;
}
APP_TRACE_INFO3("send %s encode data, total len:%d, offset:%d", (codec_type == MSBC_CODEC_IN_USE) ? "mSBC" : "Opus",
txPkt->len, offset);
if (offset >= txPkt->len)
{
am_app_led_off();
g_start_voice_send = FALSE;
memset(output_data, 0x0, sizeof(output_data));
txPkt->offset = 0;
}
else
{
if (codec_type == MSBC_CODEC_IN_USE)
{
output_len = voles_msbc_encode_voice_data(&voice_data[offset + AUD_HEADER_LEN], output_data, enc_data_len);
txPkt->offset += enc_data_len;
}
else if (codec_type == OPUS_CODEC_IN_USE)
{
output_len = audio_enc_encode_frame((short *)&voice_data[offset + AUD_HEADER_LEN], enc_data_len, output_data);
APP_TRACE_INFO1("opus encode, output_len:%d", output_len);
if (output_len == (CODEC_OPUS_OUTPUT_SIZE))
{
txPkt->offset += (2*CODEC_OPUS_INPUT_SIZE);
//APP_TRACE_INFO1("opus_encode: ret:%d", output_len);
}
else
{
txPkt->offset += enc_data_len;
}
}
}
if ( output_len > 0 )
{
memcpy(&g_ble_data_buffer[index], output_data, output_len);
index += output_len;
}
if ( index >= voles_ble_buffer_size() || output_len <= 0 )
{
if (index >0)
{
am_app_KWD_AMA_stream_send(g_ble_data_buffer, index);
index = 0;
memset(g_ble_data_buffer, 0x0, sizeof(g_ble_data_buffer));
}
}
else
{
uint8_t output_size = ((voles_get_codec_type() == MSBC_CODEC_IN_USE) ? CODEC_MSBC_OUTPUT_SIZE : (CODEC_OPUS_OUTPUT_SIZE));
if (output_len == output_size)
{
voles_transmit_voice_data();
}
else if (output_len>0 && output_len<output_size)
{
am_app_KWD_AMA_stream_send(output_data, output_len);
index = 0;
}
}
}
//extern opus_encoder_t* octopus_encoder_create(int option);
/*************************************************************************************************/
/*!
* \fn volesHandleValueCnf
*
* \brief Handle a received ATT handle value confirm.
*
* \param pMsg Event message.
*
* \return None.
*/
/*************************************************************************************************/
static void
volesHandleValueCnf(attEvt_t *pMsg)
{
if (pMsg->hdr.status == ATT_SUCCESS)
{
if (g_start_voice_send)
{
voles_transmit_voice_data();
}
}
else
{
APP_TRACE_WARN2("cnf status = %d, hdl = 0x%x\n", pMsg->hdr.status, pMsg->handle);
}
}
void voles_opus_encoder_init(void)
{
//
// Opus codec init
//
audio_enc_init(0);
APP_TRACE_INFO0("Opus encoder initialization is finished!\r\n\n");
}
//*****************************************************************************
//6
//! @brief initialize vole service
//!
//! @param handlerId - connection handle
//! @param pCfg - configuration parameters
//!
//! @return None
//
//*****************************************************************************
void voles_init(wsfHandlerId_t handlerId, eVoleCodecType codec_type)
{
memset(&volesCb, 0, sizeof(volesCb));
volesCb.appHandlerId = handlerId;
volesCb.core.txPkt.data = voice_data;
if (codec_type == MSBC_CODEC_IN_USE)
{
sbc_encode_init(&g_SBCInstance, 1); //0: SBC
}
else if (codec_type == OPUS_CODEC_IN_USE)
{
voles_opus_encoder_init();
}
}
static void
voles_conn_close(dmEvt_t *pMsg)
{
hciDisconnectCmplEvt_t *evt = (hciDisconnectCmplEvt_t*) pMsg;
dmConnId_t connId = evt->hdr.param;
/* clear connection */
volesCb.conn[connId - 1].connId = DM_CONN_ID_NONE;
volesCb.conn[connId - 1].voleToSend = FALSE;
WsfTimerStop(&volesCb.core.timeoutTimer);
volesCb.core.txState = VOLE_STATE_INIT;
volesCb.core.rxState = VOLE_STATE_RX_IDLE;
volesCb.core.lastRxPktSn = 0;
volesCb.core.txPktSn = 0;
VoleResetPkt(&volesCb.core.rxPkt);
VoleResetPkt(&volesCb.core.txPkt);
VoleResetPkt(&volesCb.core.ackPkt);
}
uint8_t
voles_write_cback(dmConnId_t connId, uint16_t handle, uint8_t operation,
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr)
{
APP_TRACE_INFO3("write cb, len:%d, value %x %x", len, pValue[0], pValue[1]);
return ATT_SUCCESS;
}
void
voles_start(dmConnId_t connId, uint8_t timerEvt, uint8_t voleCccIdx)
{
//
// set conn id
//
volesCb.conn[connId - 1].connId = connId;
volesCb.conn[connId - 1].voleToSend = TRUE;
volesCb.core.timeoutTimer.msg.event = timerEvt;
volesCb.core.txState = VOLE_STATE_TX_IDLE;
volesCb.txReady = true;
volesCb.core.attMtuSize = AttGetMtu(connId);
APP_TRACE_INFO1("MTU size = %d bytes", volesCb.core.attMtuSize);
}
void
voles_stop(dmConnId_t connId)
{
//
// clear connection
//
volesCb.conn[connId - 1].connId = DM_CONN_ID_NONE;
volesCb.conn[connId - 1].voleToSend = FALSE;
volesCb.core.txState = VOLE_STATE_INIT;
volesCb.txReady = false;
}
void voles_proc_msg(wsfMsgHdr_t *pMsg)
{
if (pMsg->event == DM_CONN_OPEN_IND)
{
voles_conn_open((dmEvt_t *) pMsg);
}
else if (pMsg->event == DM_CONN_CLOSE_IND)
{
voles_conn_close((dmEvt_t *) pMsg);
}
else if (pMsg->event == DM_CONN_UPDATE_IND)
{
voles_conn_update((dmEvt_t *) pMsg);
}
else if (pMsg->event == ATTS_HANDLE_VALUE_CNF)
{
volesHandleValueCnf((attEvt_t *) pMsg);
}
}
@@ -0,0 +1,84 @@
//*****************************************************************************
//
//! @file am_app_KWD_AMA.h
//!
//! @brief header file of AMA protocol handler
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2017, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision v1.2.11 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef AM_APP_KWD_AMA_H
#define AM_APP_KWD_AMA_H
#include "accessories.pb.h"
#define AMA_TRANSPORT_HEADER_VERSION_MASK 0xF000
#define AMA_TRANSPORT_HEADER_STEAM_ID_MASK 0x0F80
#define AMA_TRANSPORT_HEADER_LENGTH_TYPE_MASK 0x01
typedef struct
{
#if USE_OUTPUT_AMVOS_AMA
uint8_t ama_buf[AMA_BUFFER_SIZE + 3];
#else
uint8_t* buf;
#endif
uint32_t len;
uint32_t reserved;
} sRadioQueue_t;
typedef enum
{
VOS_AMA_INIT = 0, // New state for disconnected time
VOS_AMA_IDLE,
VOS_AMA_LISTENING,
VOS_AMA_PROCESSING,
VOS_AMA_SPEAKING
} eVosAmaStatus_t;
//*****************************************************************************
// External function declaration
//*****************************************************************************
extern bool am_app_KWD_AMA_start_speech_send(void);
extern int am_app_KWD_AMA_rx_handler(uint8_t *data, uint16_t len);
extern bool am_app_KWD_AMA_keep_alive_send(void);
extern uint32_t g_ui32AmaDialogID;
extern eVosAmaStatus_t g_eAmaStatus;
#endif // #ifndef AM_APP_KWD_AMA_H
@@ -0,0 +1,239 @@
//*****************************************************************************
//
// accessories.pb.h
//! @file
//!
//! @brief Auto-generated (see below).
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/* Automatically generated nanopb header */
/* Generated by nanopb-0.3.9.1 at Fri Nov 09 16:58:28 2018. */
#ifndef PB_ACCESSORIES_PB_H_INCLUDED
#define PB_ACCESSORIES_PB_H_INCLUDED
#include <pb.h>
#include "common.pb.h"
#include "system.pb.h"
#include "transport.pb.h"
#include "speech.pb.h"
#include "calling.pb.h"
#include "central.pb.h"
#include "device.pb.h"
#include "media.pb.h"
#include "state.pb.h"
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Enum definitions */
typedef enum _Command
{
Command_NONE = 0,
Command_RESET_CONNECTION = 51,
Command_SYNCHRONIZE_SETTINGS = 50,
Command_KEEP_ALIVE = 55,
Command_REMOVE_DEVICE = 56,
Command_UPGRADE_TRANSPORT = 30,
Command_SWITCH_TRANSPORT = 31,
Command_START_SPEECH = 11,
Command_PROVIDE_SPEECH = 10,
Command_STOP_SPEECH = 12,
Command_ENDPOINT_SPEECH = 13,
Command_NOTIFY_SPEECH_STATE = 14,
Command_FORWARD_AT_COMMAND = 40,
Command_INCOMING_CALL = 41,
Command_GET_CENTRAL_INFORMATION = 103,
Command_GET_DEVICE_INFORMATION = 20,
Command_GET_DEVICE_CONFIGURATION = 21,
Command_OVERRIDE_ASSISTANT = 22,
Command_START_SETUP = 23,
Command_COMPLETE_SETUP = 24,
Command_NOTIFY_DEVICE_CONFIGURATION = 25,
Command_UPDATE_DEVICE_INFORMATION = 26,
Command_NOTIFY_DEVICE_INFORMATION = 27,
Command_ISSUE_MEDIA_CONTROL = 60,
Command_GET_STATE = 100,
Command_SET_STATE = 101,
Command_SYNCHRONIZE_STATE = 102
} Command;
#define _Command_MIN Command_NONE
#define _Command_MAX Command_SYNCHRONIZE_STATE
#define _Command_ARRAYSIZE ((Command)(Command_SYNCHRONIZE_STATE + 1))
/* Struct definitions */
typedef struct _Response
{
ErrorCode error_code;
pb_size_t which_payload;
union
{
DeviceInformation device_information;
State state;
ConnectionDetails connection_details;
DeviceConfiguration device_configuration;
CentralInformation central_information;
Dialog dialog;
SpeechProvider speech_provider;
} payload;
/* @@protoc_insertion_point(struct:Response) */
} Response;
typedef struct _ControlEnvelope
{
Command command;
pb_size_t which_payload;
union
{
Response response;
ProvideSpeech provide_speech;
StartSpeech start_speech;
StopSpeech stop_speech;
EndpointSpeech endpoint_speech;
NotifySpeechState notify_speech_state;
GetDeviceInformation get_device_information;
GetDeviceConfiguration get_device_configuration;
OverrideAssistant override_assistant;
StartSetup start_setup;
CompleteSetup complete_setup;
NotifyDeviceConfiguration notify_device_configuration;
UpdateDeviceInformation update_device_information;
NotifyDeviceInformation notify_device_information;
UpgradeTransport upgrade_transport;
SwitchTransport switch_transport;
ForwardATCommand forward_at_command;
IncomingCall incoming_call;
SynchronizeSettings synchronize_settings;
ResetConnection reset_connection;
KeepAlive keep_alive;
RemoveDevice remove_device;
IssueMediaControl issue_media_control;
GetState get_state;
SetState set_state;
SynchronizeState synchronize_state;
GetCentralInformation get_central_information;
} payload;
/* @@protoc_insertion_point(struct:ControlEnvelope) */
} ControlEnvelope;
/* Default values for struct fields */
/* Initializer values for message structs */
#define Response_init_default {_ErrorCode_MIN, 0, {DeviceInformation_init_default}}
#define ControlEnvelope_init_default {_Command_MIN, 0, {Response_init_default}}
#define Response_init_zero {_ErrorCode_MIN, 0, {DeviceInformation_init_zero}}
#define ControlEnvelope_init_zero {_Command_MIN, 0, {Response_init_zero}}
/* Field tags (for use in manual encoding/decoding) */
#define Response_device_information_tag 3
#define Response_state_tag 7
#define Response_connection_details_tag 8
#define Response_device_configuration_tag 10
#define Response_central_information_tag 13
#define Response_dialog_tag 14
#define Response_speech_provider_tag 15
#define Response_error_code_tag 1
#define ControlEnvelope_response_tag 9
#define ControlEnvelope_provide_speech_tag 10
#define ControlEnvelope_start_speech_tag 11
#define ControlEnvelope_stop_speech_tag 12
#define ControlEnvelope_endpoint_speech_tag 13
#define ControlEnvelope_notify_speech_state_tag 14
#define ControlEnvelope_get_device_information_tag 20
#define ControlEnvelope_get_device_configuration_tag 21
#define ControlEnvelope_override_assistant_tag 22
#define ControlEnvelope_start_setup_tag 23
#define ControlEnvelope_complete_setup_tag 24
#define ControlEnvelope_notify_device_configuration_tag 25
#define ControlEnvelope_update_device_information_tag 26
#define ControlEnvelope_notify_device_information_tag 27
#define ControlEnvelope_upgrade_transport_tag 30
#define ControlEnvelope_switch_transport_tag 31
#define ControlEnvelope_forward_at_command_tag 40
#define ControlEnvelope_incoming_call_tag 41
#define ControlEnvelope_synchronize_settings_tag 50
#define ControlEnvelope_reset_connection_tag 51
#define ControlEnvelope_keep_alive_tag 55
#define ControlEnvelope_remove_device_tag 56
#define ControlEnvelope_issue_media_control_tag 60
#define ControlEnvelope_get_state_tag 100
#define ControlEnvelope_set_state_tag 101
#define ControlEnvelope_synchronize_state_tag 102
#define ControlEnvelope_get_central_information_tag 103
#define ControlEnvelope_command_tag 1
/* Struct field encoding specification for nanopb */
extern const pb_field_t Response_fields[9];
extern const pb_field_t ControlEnvelope_fields[29];
/* Maximum encoded size of messages (where known) */
#define Response_size 104
#define ControlEnvelope_size (2 + (UpdateDeviceInformation_size > 302 ? UpdateDeviceInformation_size : 302))
/* Message IDs (where set with "msgid" option) */
#ifdef PB_MSGID
#define ACCESSORIES_MESSAGES \
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
/* @@protoc_insertion_point(eof) */
#endif
@@ -0,0 +1,110 @@
//*****************************************************************************
//
// calling.pb.h
//! @file
//!
//! @brief Auto-generated (see below).
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/* Automatically generated nanopb header */
/* Generated by nanopb-0.3.9.1 at Fri Nov 09 16:58:28 2018. */
#ifndef PB_CALLING_PB_H_INCLUDED
#define PB_CALLING_PB_H_INCLUDED
#include <pb.h>
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Struct definitions */
typedef struct _ForwardATCommand
{
char command[34];
/* @@protoc_insertion_point(struct:ForwardATCommand) */
} ForwardATCommand;
typedef struct _IncomingCall
{
char caller_number[34];
/* @@protoc_insertion_point(struct:IncomingCall) */
} IncomingCall;
/* Default values for struct fields */
/* Initializer values for message structs */
#define ForwardATCommand_init_default {""}
#define IncomingCall_init_default {""}
#define ForwardATCommand_init_zero {""}
#define IncomingCall_init_zero {""}
/* Field tags (for use in manual encoding/decoding) */
#define ForwardATCommand_command_tag 1
#define IncomingCall_caller_number_tag 1
/* Struct field encoding specification for nanopb */
extern const pb_field_t ForwardATCommand_fields[2];
extern const pb_field_t IncomingCall_fields[2];
/* Maximum encoded size of messages (where known) */
#define ForwardATCommand_size 36
#define IncomingCall_size 36
/* Message IDs (where set with "msgid" option) */
#ifdef PB_MSGID
#define CALLING_MESSAGES \
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
/* @@protoc_insertion_point(eof) */
#endif
@@ -0,0 +1,122 @@
//*****************************************************************************
//
// central.pb.h
//! @file
//!
//! @brief Auto-generated (see below).
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/* Automatically generated nanopb header */
/* Generated by nanopb-0.3.9.1 at Fri Nov 09 16:58:28 2018. */
#ifndef PB_CENTRAL_PB_H_INCLUDED
#define PB_CENTRAL_PB_H_INCLUDED
#include <pb.h>
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Enum definitions */
typedef enum _Platform
{
Platform_UNDEFINED = 0,
Platform_IOS = 1,
Platform_ANDROID = 2
} Platform;
#define _Platform_MIN Platform_UNDEFINED
#define _Platform_MAX Platform_ANDROID
#define _Platform_ARRAYSIZE ((Platform)(Platform_ANDROID + 1))
/* Struct definitions */
typedef struct _GetCentralInformation
{
char dummy_field;
/* @@protoc_insertion_point(struct:GetCentralInformation) */
} GetCentralInformation;
typedef struct _CentralInformation
{
char name[32];
Platform platform;
/* @@protoc_insertion_point(struct:CentralInformation) */
} CentralInformation;
/* Default values for struct fields */
/* Initializer values for message structs */
#define CentralInformation_init_default {"", _Platform_MIN}
#define GetCentralInformation_init_default {0}
#define CentralInformation_init_zero {"", _Platform_MIN}
#define GetCentralInformation_init_zero {0}
/* Field tags (for use in manual encoding/decoding) */
#define CentralInformation_name_tag 1
#define CentralInformation_platform_tag 2
/* Struct field encoding specification for nanopb */
extern const pb_field_t CentralInformation_fields[3];
extern const pb_field_t GetCentralInformation_fields[1];
/* Maximum encoded size of messages (where known) */
#define CentralInformation_size 36
#define GetCentralInformation_size 0
/* Message IDs (where set with "msgid" option) */
#ifdef PB_MSGID
#define CENTRAL_MESSAGES \
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
/* @@protoc_insertion_point(eof) */
#endif
@@ -0,0 +1,95 @@
//*****************************************************************************
//
// common.pb.h
//! @file
//!
//! @brief Auto-generated (see below).
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/* Automatically generated nanopb header */
/* Generated by nanopb-0.3.9.1 at Fri Nov 09 16:58:28 2018. */
#ifndef PB_COMMON_PB_H_INCLUDED
#define PB_COMMON_PB_H_INCLUDED
#include <pb.h>
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Enum definitions */
typedef enum _Transport
{
Transport_BLUETOOTH_LOW_ENERGY = 0,
Transport_BLUETOOTH_RFCOMM = 1,
Transport_BLUETOOTH_IAP = 2
} Transport;
#define _Transport_MIN Transport_BLUETOOTH_LOW_ENERGY
#define _Transport_MAX Transport_BLUETOOTH_IAP
#define _Transport_ARRAYSIZE ((Transport)(Transport_BLUETOOTH_IAP + 1))
typedef enum _ErrorCode
{
ErrorCode_SUCCESS = 0,
ErrorCode_UNKNOWN = 1,
ErrorCode_INTERNAL = 2,
ErrorCode_UNSUPPORTED = 3,
ErrorCode_USER_CANCELLED = 4,
ErrorCode_NOT_FOUND = 5,
ErrorCode_INVALID = 6,
ErrorCode_BUSY = 7
} ErrorCode;
#define _ErrorCode_MIN ErrorCode_SUCCESS
#define _ErrorCode_MAX ErrorCode_BUSY
#define _ErrorCode_ARRAYSIZE ((ErrorCode)(ErrorCode_BUSY + 1))
#ifdef __cplusplus
} /* extern "C" */
#endif
/* @@protoc_insertion_point(eof) */
#endif
@@ -0,0 +1,278 @@
//*****************************************************************************
//
// device.pb.h
//! @file
//!
//! @brief Auto-generated (see below).
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/* Automatically generated nanopb header */
/* Generated by nanopb-0.3.9.1 at Fri Nov 09 16:58:28 2018. */
#ifndef PB_DEVICE_PB_H_INCLUDED
#define PB_DEVICE_PB_H_INCLUDED
#include <pb.h>
#include "common.pb.h"
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Enum definitions */
typedef enum _ConnectionStatus
{
ConnectionStatus_CONNECTION_STATUS_UNKNOWN = 0,
ConnectionStatus_CONNECTION_STATUS_CONNECTED = 1,
ConnectionStatus_CONNECTION_STATUS_DISCONNECTED = 2
} ConnectionStatus;
#define _ConnectionStatus_MIN ConnectionStatus_CONNECTION_STATUS_UNKNOWN
#define _ConnectionStatus_MAX ConnectionStatus_CONNECTION_STATUS_DISCONNECTED
#define _ConnectionStatus_ARRAYSIZE ((ConnectionStatus)(ConnectionStatus_CONNECTION_STATUS_DISCONNECTED + 1))
typedef enum _DevicePresence
{
DevicePresence_DEVICE_PRESENCE_UNKNOWN = 0,
DevicePresence_DEVICE_PRESENCE_ACTIVE = 1,
DevicePresence_DEVICE_PRESENCE_INACTIVE = 2,
DevicePresence_DEVICE_PRESENCE_ACCESSIBLE = 3
} DevicePresence;
#define _DevicePresence_MIN DevicePresence_DEVICE_PRESENCE_UNKNOWN
#define _DevicePresence_MAX DevicePresence_DEVICE_PRESENCE_ACCESSIBLE
#define _DevicePresence_ARRAYSIZE ((DevicePresence)(DevicePresence_DEVICE_PRESENCE_ACCESSIBLE + 1))
typedef enum _DeviceBattery_Status
{
DeviceBattery_Status_UNKNOWN = 0,
DeviceBattery_Status_CHARGING = 1,
DeviceBattery_Status_DISCHARGING = 2,
DeviceBattery_Status_FULL = 3
} DeviceBattery_Status;
#define _DeviceBattery_Status_MIN DeviceBattery_Status_UNKNOWN
#define _DeviceBattery_Status_MAX DeviceBattery_Status_FULL
#define _DeviceBattery_Status_ARRAYSIZE ((DeviceBattery_Status)(DeviceBattery_Status_FULL + 1))
/* Struct definitions */
typedef struct _GetDeviceConfiguration
{
char dummy_field;
/* @@protoc_insertion_point(struct:GetDeviceConfiguration) */
} GetDeviceConfiguration;
typedef struct _StartSetup
{
char dummy_field;
/* @@protoc_insertion_point(struct:StartSetup) */
} StartSetup;
typedef struct _UpdateDeviceInformation
{
pb_callback_t name;
/* @@protoc_insertion_point(struct:UpdateDeviceInformation) */
} UpdateDeviceInformation;
typedef struct _CompleteSetup
{
ErrorCode error_code;
/* @@protoc_insertion_point(struct:CompleteSetup) */
} CompleteSetup;
typedef struct _DeviceBattery
{
uint32_t level;
uint32_t scale;
DeviceBattery_Status status;
/* @@protoc_insertion_point(struct:DeviceBattery) */
} DeviceBattery;
typedef struct _DeviceConfiguration
{
bool needs_assistant_override;
bool needs_setup;
/* @@protoc_insertion_point(struct:DeviceConfiguration) */
} DeviceConfiguration;
typedef struct _DeviceStatus
{
ConnectionStatus link;
ConnectionStatus nfmi;
DevicePresence presence;
/* @@protoc_insertion_point(struct:DeviceStatus) */
} DeviceStatus;
typedef struct _GetDeviceInformation
{
uint32_t device_id;
/* @@protoc_insertion_point(struct:GetDeviceInformation) */
} GetDeviceInformation;
typedef struct _OverrideAssistant
{
ErrorCode error_code;
/* @@protoc_insertion_point(struct:OverrideAssistant) */
} OverrideAssistant;
typedef struct _DeviceInformation
{
char serial_number[20];
char name[16];
pb_size_t supported_transports_count;
Transport supported_transports[4];
char device_type[14];
uint32_t device_id;
DeviceBattery battery;
DeviceStatus status;
uint32_t product_color;
/* @@protoc_insertion_point(struct:DeviceInformation) */
} DeviceInformation;
typedef struct _NotifyDeviceConfiguration
{
DeviceConfiguration device_configuration;
/* @@protoc_insertion_point(struct:NotifyDeviceConfiguration) */
} NotifyDeviceConfiguration;
typedef struct _NotifyDeviceInformation
{
DeviceInformation device_information;
/* @@protoc_insertion_point(struct:NotifyDeviceInformation) */
} NotifyDeviceInformation;
/* Default values for struct fields */
/* Initializer values for message structs */
#define DeviceBattery_init_default {0, 0, _DeviceBattery_Status_MIN}
#define DeviceStatus_init_default {_ConnectionStatus_MIN, _ConnectionStatus_MIN, _DevicePresence_MIN}
#define DeviceInformation_init_default {"", "", 0, {_Transport_MIN, _Transport_MIN, _Transport_MIN, _Transport_MIN}, "", 0, DeviceBattery_init_default, DeviceStatus_init_default, 0}
#define GetDeviceInformation_init_default {0}
#define DeviceConfiguration_init_default {0, 0}
#define GetDeviceConfiguration_init_default {0}
#define OverrideAssistant_init_default {_ErrorCode_MIN}
#define StartSetup_init_default {0}
#define CompleteSetup_init_default {_ErrorCode_MIN}
#define NotifyDeviceConfiguration_init_default {DeviceConfiguration_init_default}
#define UpdateDeviceInformation_init_default {{{NULL}, NULL}}
#define NotifyDeviceInformation_init_default {DeviceInformation_init_default}
#define DeviceBattery_init_zero {0, 0, _DeviceBattery_Status_MIN}
#define DeviceStatus_init_zero {_ConnectionStatus_MIN, _ConnectionStatus_MIN, _DevicePresence_MIN}
#define DeviceInformation_init_zero {"", "", 0, {_Transport_MIN, _Transport_MIN, _Transport_MIN, _Transport_MIN}, "", 0, DeviceBattery_init_zero, DeviceStatus_init_zero, 0}
#define GetDeviceInformation_init_zero {0}
#define DeviceConfiguration_init_zero {0, 0}
#define GetDeviceConfiguration_init_zero {0}
#define OverrideAssistant_init_zero {_ErrorCode_MIN}
#define StartSetup_init_zero {0}
#define CompleteSetup_init_zero {_ErrorCode_MIN}
#define NotifyDeviceConfiguration_init_zero {DeviceConfiguration_init_zero}
#define UpdateDeviceInformation_init_zero {{{NULL}, NULL}}
#define NotifyDeviceInformation_init_zero {DeviceInformation_init_zero}
/* Field tags (for use in manual encoding/decoding) */
#define UpdateDeviceInformation_name_tag 1
#define CompleteSetup_error_code_tag 1
#define DeviceBattery_level_tag 1
#define DeviceBattery_scale_tag 2
#define DeviceBattery_status_tag 3
#define DeviceConfiguration_needs_assistant_override_tag 1
#define DeviceConfiguration_needs_setup_tag 2
#define DeviceStatus_link_tag 1
#define DeviceStatus_nfmi_tag 2
#define DeviceStatus_presence_tag 3
#define GetDeviceInformation_device_id_tag 1
#define OverrideAssistant_error_code_tag 1
#define DeviceInformation_serial_number_tag 1
#define DeviceInformation_name_tag 2
#define DeviceInformation_supported_transports_tag 3
#define DeviceInformation_device_type_tag 4
#define DeviceInformation_device_id_tag 5
#define DeviceInformation_battery_tag 6
#define DeviceInformation_status_tag 7
#define DeviceInformation_product_color_tag 8
#define NotifyDeviceConfiguration_device_configuration_tag 1
#define NotifyDeviceInformation_device_information_tag 1
/* Struct field encoding specification for nanopb */
extern const pb_field_t DeviceBattery_fields[4];
extern const pb_field_t DeviceStatus_fields[4];
extern const pb_field_t DeviceInformation_fields[9];
extern const pb_field_t GetDeviceInformation_fields[2];
extern const pb_field_t DeviceConfiguration_fields[3];
extern const pb_field_t GetDeviceConfiguration_fields[1];
extern const pb_field_t OverrideAssistant_fields[2];
extern const pb_field_t StartSetup_fields[1];
extern const pb_field_t CompleteSetup_fields[2];
extern const pb_field_t NotifyDeviceConfiguration_fields[2];
extern const pb_field_t UpdateDeviceInformation_fields[2];
extern const pb_field_t NotifyDeviceInformation_fields[2];
/* Maximum encoded size of messages (where known) */
#define DeviceBattery_size 14
#define DeviceStatus_size 6
#define DeviceInformation_size 100
#define GetDeviceInformation_size 6
#define DeviceConfiguration_size 4
#define GetDeviceConfiguration_size 0
#define OverrideAssistant_size 2
#define StartSetup_size 0
#define CompleteSetup_size 2
#define NotifyDeviceConfiguration_size 6
/* UpdateDeviceInformation_size depends on runtime parameters */
#define NotifyDeviceInformation_size 102
/* Message IDs (where set with "msgid" option) */
#ifdef PB_MSGID
#define DEVICE_MESSAGES \
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
/* @@protoc_insertion_point(eof) */
#endif
@@ -0,0 +1,112 @@
//*****************************************************************************
//
// media.pb.h
//! @file
//!
//! @brief Auto-generated (see below).
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/* Automatically generated nanopb header */
/* Generated by nanopb-0.3.9.1 at Fri Nov 09 16:58:28 2018. */
#ifndef PB_MEDIA_PB_H_INCLUDED
#define PB_MEDIA_PB_H_INCLUDED
#include <pb.h>
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Enum definitions */
typedef enum _MediaControl
{
MediaControl_PLAY = 0,
MediaControl_PAUSE = 1,
MediaControl_NEXT = 2,
MediaControl_PREVIOUS = 3,
MediaControl_PLAY_PAUSE = 4
} MediaControl;
#define _MediaControl_MIN MediaControl_PLAY
#define _MediaControl_MAX MediaControl_PLAY_PAUSE
#define _MediaControl_ARRAYSIZE ((MediaControl)(MediaControl_PLAY_PAUSE + 1))
/* Struct definitions */
typedef struct _IssueMediaControl
{
MediaControl control;
/* @@protoc_insertion_point(struct:IssueMediaControl) */
} IssueMediaControl;
/* Default values for struct fields */
/* Initializer values for message structs */
#define IssueMediaControl_init_default {_MediaControl_MIN}
#define IssueMediaControl_init_zero {_MediaControl_MIN}
/* Field tags (for use in manual encoding/decoding) */
#define IssueMediaControl_control_tag 1
/* Struct field encoding specification for nanopb */
extern const pb_field_t IssueMediaControl_fields[2];
/* Maximum encoded size of messages (where known) */
#define IssueMediaControl_size 2
/* Message IDs (where set with "msgid" option) */
#ifdef PB_MSGID
#define MEDIA_MESSAGES \
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
/* @@protoc_insertion_point(eof) */
#endif
@@ -0,0 +1,649 @@
//*****************************************************************************
//
// pb.h
//! @file
//!
//! @brief Auto-generated (see below).
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/* Common parts of the nanopb library. Most of these are quite low-level
* stuff. For the high-level interface, see pb_encode.h and pb_decode.h.
*/
#ifndef PB_H_INCLUDED
#define PB_H_INCLUDED
/*****************************************************************
* Nanopb compilation time options. You can change these here by *
* uncommenting the lines, or on the compiler command line. *
*****************************************************************/
/* Enable support for dynamically allocated fields */
/* #define PB_ENABLE_MALLOC 1 */
/* Define this if your CPU / compiler combination does not support
* unaligned memory access to packed structures. */
/* #define PB_NO_PACKED_STRUCTS 1 */
/* Increase the number of required fields that are tracked.
* A compiler warning will tell if you need this. */
/* #define PB_MAX_REQUIRED_FIELDS 256 */
/* Add support for tag numbers > 255 and fields larger than 255 bytes. */
/* #define PB_FIELD_16BIT 1 */
#define PB_FIELD_16BIT 1
/* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */
/* #define PB_FIELD_32BIT 1 */
/* Disable support for error messages in order to save some code space. */
/* #define PB_NO_ERRMSG 1 */
/* Disable support for custom streams (support only memory buffers). */
/* #define PB_BUFFER_ONLY 1 */
/* Switch back to the old-style callback function signature.
* This was the default until nanopb-0.2.1. */
/* #define PB_OLD_CALLBACK_STYLE */
/******************************************************************
* You usually don't need to change anything below this line. *
* Feel free to look around and use the defined macros, though. *
******************************************************************/
/* Version of the nanopb library. Just in case you want to check it in
* your own program. */
#define NANOPB_VERSION nanopb-0.3.9.1
/* Include all the system headers needed by nanopb. You will need the
* definitions of the following:
* - strlen, memcpy, memset functions
* - [u]int_least8_t, uint_fast8_t, [u]int_least16_t, [u]int32_t, [u]int64_t
* - size_t
* - bool
*
* If you don't have the standard header files, you can instead provide
* a custom header that defines or includes all this. In that case,
* define PB_SYSTEM_HEADER to the path of this file.
*/
#ifdef PB_SYSTEM_HEADER
#include PB_SYSTEM_HEADER
#else
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#ifdef PB_ENABLE_MALLOC
#include <stdlib.h>
#endif
#endif
/* Macro for defining packed structures (compiler dependent).
* This just reduces memory requirements, but is not required.
*/
#if defined(PB_NO_PACKED_STRUCTS)
/* Disable struct packing */
# define PB_PACKED_STRUCT_START
# define PB_PACKED_STRUCT_END
# define pb_packed
#elif defined(__GNUC__) || defined(__clang__)
/* For GCC and clang */
# define PB_PACKED_STRUCT_START
# define PB_PACKED_STRUCT_END
# define pb_packed __attribute__((packed))
#elif defined(__ICCARM__) || defined(__CC_ARM)
/* For IAR ARM and Keil MDK-ARM compilers */
# define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)")
# define PB_PACKED_STRUCT_END _Pragma("pack(pop)")
# define pb_packed
#elif defined(_MSC_VER) && (_MSC_VER >= 1500)
/* For Microsoft Visual C++ */
# define PB_PACKED_STRUCT_START __pragma(pack(push, 1))
# define PB_PACKED_STRUCT_END __pragma(pack(pop))
# define pb_packed
#else
/* Unknown compiler */
# define PB_PACKED_STRUCT_START
# define PB_PACKED_STRUCT_END
# define pb_packed
#endif
/* Handly macro for suppressing unreferenced-parameter compiler warnings. */
#ifndef PB_UNUSED
#define PB_UNUSED(x) (void)(x)
#endif
/* Compile-time assertion, used for checking compatible compilation options.
* If this does not work properly on your compiler, use
* #define PB_NO_STATIC_ASSERT to disable it.
*
* But before doing that, check carefully the error message / place where it
* comes from to see if the error has a real cause. Unfortunately the error
* message is not always very clear to read, but you can see the reason better
* in the place where the PB_STATIC_ASSERT macro was called.
*/
#ifndef PB_NO_STATIC_ASSERT
#ifndef PB_STATIC_ASSERT
#define PB_STATIC_ASSERT(COND, MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND) ? 1 : -1];
#define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER)
#define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##LINE##COUNTER
#endif
#else
#define PB_STATIC_ASSERT(COND, MSG)
#endif
/* Number of required fields to keep track of. */
#ifndef PB_MAX_REQUIRED_FIELDS
#define PB_MAX_REQUIRED_FIELDS 64
#endif
#if PB_MAX_REQUIRED_FIELDS < 64
#error You should not lower PB_MAX_REQUIRED_FIELDS from the default value (64).
#endif
/* List of possible field types. These are used in the autogenerated code.
* Least-significant 4 bits tell the scalar type
* Most-significant 4 bits specify repeated/required/packed etc.
*/
typedef uint_least8_t pb_type_t;
/**** Field data types ****/
/* Numeric types */
#define PB_LTYPE_VARINT 0x00 /* int32, int64, enum, bool */
#define PB_LTYPE_UVARINT 0x01 /* uint32, uint64 */
#define PB_LTYPE_SVARINT 0x02 /* sint32, sint64 */
#define PB_LTYPE_FIXED32 0x03 /* fixed32, sfixed32, float */
#define PB_LTYPE_FIXED64 0x04 /* fixed64, sfixed64, double */
/* Marker for last packable field type. */
#define PB_LTYPE_LAST_PACKABLE 0x04
/* Byte array with pre-allocated buffer.
* data_size is the length of the allocated PB_BYTES_ARRAY structure. */
#define PB_LTYPE_BYTES 0x05
/* String with pre-allocated buffer.
* data_size is the maximum length. */
#define PB_LTYPE_STRING 0x06
/* Submessage
* submsg_fields is pointer to field descriptions */
#define PB_LTYPE_SUBMESSAGE 0x07
/* Extension pseudo-field
* The field contains a pointer to pb_extension_t */
#define PB_LTYPE_EXTENSION 0x08
/* Byte array with inline, pre-allocated byffer.
* data_size is the length of the inline, allocated buffer.
* This differs from PB_LTYPE_BYTES by defining the element as
* pb_byte_t[data_size] rather than pb_bytes_array_t. */
#define PB_LTYPE_FIXED_LENGTH_BYTES 0x09
/* Number of declared LTYPES */
#define PB_LTYPES_COUNT 0x0A
#define PB_LTYPE_MASK 0x0F
/**** Field repetition rules ****/
#define PB_HTYPE_REQUIRED 0x00
#define PB_HTYPE_OPTIONAL 0x10
#define PB_HTYPE_REPEATED 0x20
#define PB_HTYPE_ONEOF 0x30
#define PB_HTYPE_MASK 0x30
/**** Field allocation types ****/
#define PB_ATYPE_STATIC 0x00
#define PB_ATYPE_POINTER 0x80
#define PB_ATYPE_CALLBACK 0x40
#define PB_ATYPE_MASK 0xC0
#define PB_ATYPE(x) ((x) & PB_ATYPE_MASK)
#define PB_HTYPE(x) ((x) & PB_HTYPE_MASK)
#define PB_LTYPE(x) ((x) & PB_LTYPE_MASK)
/* Data type used for storing sizes of struct fields
* and array counts.
*/
#if defined(PB_FIELD_32BIT)
typedef uint32_t pb_size_t;
typedef int32_t pb_ssize_t;
#elif defined(PB_FIELD_16BIT)
typedef uint_least16_t pb_size_t;
typedef int_least16_t pb_ssize_t;
#else
typedef uint_least8_t pb_size_t;
typedef int_least8_t pb_ssize_t;
#endif
#define PB_SIZE_MAX ((pb_size_t)-1)
/* Data type for storing encoded data and other byte streams.
* This typedef exists to support platforms where uint8_t does not exist.
* You can regard it as equivalent on uint8_t on other platforms.
*/
typedef uint_least8_t pb_byte_t;
/* This structure is used in auto-generated constants
* to specify struct fields.
* You can change field sizes if you need structures
* larger than 256 bytes or field tags larger than 256.
* The compiler should complain if your .proto has such
* structures. Fix that by defining PB_FIELD_16BIT or
* PB_FIELD_32BIT.
*/
PB_PACKED_STRUCT_START
typedef struct pb_field_s pb_field_t;
struct pb_field_s
{
pb_size_t tag;
pb_type_t type;
pb_size_t data_offset; /* Offset of field data, relative to previous field. */
pb_ssize_t size_offset; /* Offset of array size or has-boolean, relative to data */
pb_size_t data_size; /* Data size in bytes for a single item */
pb_size_t array_size; /* Maximum number of entries in array */
/* Field definitions for submessage
* OR default value for all other non-array, non-callback types
* If null, then field will zeroed. */
const void *ptr;
} pb_packed;
PB_PACKED_STRUCT_END
/* Make sure that the standard integer types are of the expected sizes.
* Otherwise fixed32/fixed64 fields can break.
*
* If you get errors here, it probably means that your stdint.h is not
* correct for your platform.
*/
#ifndef PB_WITHOUT_64BIT
PB_STATIC_ASSERT(sizeof(int64_t) == 2 * sizeof(int32_t), INT64_T_WRONG_SIZE)
PB_STATIC_ASSERT(sizeof(uint64_t) == 2 * sizeof(uint32_t), UINT64_T_WRONG_SIZE)
#endif
/* This structure is used for 'bytes' arrays.
* It has the number of bytes in the beginning, and after that an array.
* Note that actual structs used will have a different length of bytes array.
*/
#define PB_BYTES_ARRAY_T(n) struct { pb_size_t size; pb_byte_t bytes[n]; }
#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes))
struct pb_bytes_array_s
{
pb_size_t size;
pb_byte_t bytes[1];
};
typedef struct pb_bytes_array_s pb_bytes_array_t;
/* This structure is used for giving the callback function.
* It is stored in the message structure and filled in by the method that
* calls pb_decode.
*
* The decoding callback will be given a limited-length stream
* If the wire type was string, the length is the length of the string.
* If the wire type was a varint/fixed32/fixed64, the length is the length
* of the actual value.
* The function may be called multiple times (especially for repeated types,
* but also otherwise if the message happens to contain the field multiple
* times.)
*
* The encoding callback will receive the actual output stream.
* It should write all the data in one call, including the field tag and
* wire type. It can write multiple fields.
*
* The callback can be null if you want to skip a field.
*/
typedef struct pb_istream_s pb_istream_t;
typedef struct pb_ostream_s pb_ostream_t;
typedef struct pb_callback_s pb_callback_t;
struct pb_callback_s
{
#ifdef PB_OLD_CALLBACK_STYLE
/* Deprecated since nanopb-0.2.1 */
union
{
bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void *arg);
bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, const void *arg);
} funcs;
#else
/* New function signature, which allows modifying arg contents in callback. */
union
{
bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg);
bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg);
} funcs;
#endif
/* Free arg for use by callback */
void *arg;
};
/* Wire types. Library user needs these only in encoder callbacks. */
typedef enum
{
PB_WT_VARINT = 0,
PB_WT_64BIT = 1,
PB_WT_STRING = 2,
PB_WT_32BIT = 5
} pb_wire_type_t;
/* Structure for defining the handling of unknown/extension fields.
* Usually the pb_extension_type_t structure is automatically generated,
* while the pb_extension_t structure is created by the user. However,
* if you want to catch all unknown fields, you can also create a custom
* pb_extension_type_t with your own callback.
*/
typedef struct pb_extension_type_s pb_extension_type_t;
typedef struct pb_extension_s pb_extension_t;
struct pb_extension_type_s
{
/* Called for each unknown field in the message.
* If you handle the field, read off all of its data and return true.
* If you do not handle the field, do not read anything and return true.
* If you run into an error, return false.
* Set to NULL for default handler.
*/
bool (*decode)(pb_istream_t *stream, pb_extension_t *extension,
uint32_t tag, pb_wire_type_t wire_type);
/* Called once after all regular fields have been encoded.
* If you have something to write, do so and return true.
* If you do not have anything to write, just return true.
* If you run into an error, return false.
* Set to NULL for default handler.
*/
bool (*encode)(pb_ostream_t *stream, const pb_extension_t *extension);
/* Free field for use by the callback. */
const void *arg;
};
struct pb_extension_s
{
/* Type describing the extension field. Usually you'll initialize
* this to a pointer to the automatically generated structure. */
const pb_extension_type_t *type;
/* Destination for the decoded data. This must match the datatype
* of the extension field. */
void *dest;
/* Pointer to the next extension handler, or NULL.
* If this extension does not match a field, the next handler is
* automatically called. */
pb_extension_t *next;
/* The decoder sets this to true if the extension was found.
* Ignored for encoding. */
bool found;
};
/* Memory allocation functions to use. You can define pb_realloc and
* pb_free to custom functions if you want. */
#ifdef PB_ENABLE_MALLOC
# ifndef pb_realloc
# define pb_realloc(ptr, size) realloc(ptr, size)
# endif
# ifndef pb_free
# define pb_free(ptr) free(ptr)
# endif
#endif
/* This is used to inform about need to regenerate .pb.h/.pb.c files. */
#define PB_PROTO_HEADER_VERSION 30
/* These macros are used to declare pb_field_t's in the constant array. */
/* Size of a structure member, in bytes. */
#define pb_membersize(st, m) (sizeof ((st*)0)->m)
/* Number of entries in an array. */
#define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0]))
/* Delta from start of one member to the start of another member. */
#define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2))
/* Marks the end of the field list */
#define PB_LAST_FIELD {0, (pb_type_t)0, 0, 0, 0, 0, 0}
/* Macros for filling in the data_offset field */
/* data_offset for first field in a message */
#define PB_DATAOFFSET_FIRST(st, m1, m2) (offsetof(st, m1))
/* data_offset for subsequent fields */
#define PB_DATAOFFSET_OTHER(st, m1, m2) (offsetof(st, m1) - offsetof(st, m2) - pb_membersize(st, m2))
/* data offset for subsequent fields inside an union (oneof) */
#define PB_DATAOFFSET_UNION(st, m1, m2) (PB_SIZE_MAX)
/* Choose first/other based on m1 == m2 (deprecated, remains for backwards compatibility) */
#define PB_DATAOFFSET_CHOOSE(st, m1, m2) (int)(offsetof(st, m1) == offsetof(st, m2) \
? PB_DATAOFFSET_FIRST(st, m1, m2) \
: PB_DATAOFFSET_OTHER(st, m1, m2))
/* Required fields are the simplest. They just have delta (padding) from
* previous field end, and the size of the field. Pointer is used for
* submessages and default values.
*/
#define PB_REQUIRED_STATIC(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \
fd, 0, pb_membersize(st, m), 0, ptr}
/* Optional fields add the delta to the has_ variable. */
#define PB_OPTIONAL_STATIC(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \
fd, \
pb_delta(st, has_ ## m, m), \
pb_membersize(st, m), 0, ptr}
#define PB_SINGULAR_STATIC(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \
fd, 0, pb_membersize(st, m), 0, ptr}
/* Repeated fields have a _count field and also the maximum number of entries. */
#define PB_REPEATED_STATIC(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | ltype, \
fd, \
pb_delta(st, m ## _count, m), \
pb_membersize(st, m[0]), \
pb_arraysize(st, m), ptr}
/* Allocated fields carry the size of the actual data, not the pointer */
#define PB_REQUIRED_POINTER(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_POINTER | PB_HTYPE_REQUIRED | ltype, \
fd, 0, pb_membersize(st, m[0]), 0, ptr}
/* Optional fields don't need a has_ variable, as information would be redundant */
#define PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \
fd, 0, pb_membersize(st, m[0]), 0, ptr}
/* Same as optional fields*/
#define PB_SINGULAR_POINTER(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \
fd, 0, pb_membersize(st, m[0]), 0, ptr}
/* Repeated fields have a _count field and a pointer to array of pointers */
#define PB_REPEATED_POINTER(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_POINTER | PB_HTYPE_REPEATED | ltype, \
fd, pb_delta(st, m ## _count, m), \
pb_membersize(st, m[0]), 0, ptr}
/* Callbacks are much like required fields except with special datatype. */
#define PB_REQUIRED_CALLBACK(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_CALLBACK | PB_HTYPE_REQUIRED | ltype, \
fd, 0, pb_membersize(st, m), 0, ptr}
#define PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \
fd, 0, pb_membersize(st, m), 0, ptr}
#define PB_SINGULAR_CALLBACK(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \
fd, 0, pb_membersize(st, m), 0, ptr}
#define PB_REPEATED_CALLBACK(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_CALLBACK | PB_HTYPE_REPEATED | ltype, \
fd, 0, pb_membersize(st, m), 0, ptr}
/* Optional extensions don't have the has_ field, as that would be redundant.
* Furthermore, the combination of OPTIONAL without has_ field is used
* for indicating proto3 style fields. Extensions exist in proto2 mode only,
* so they should be encoded according to proto2 rules. To avoid the conflict,
* extensions are marked as REQUIRED instead.
*/
#define PB_OPTEXT_STATIC(tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \
0, \
0, \
pb_membersize(st, m), 0, ptr}
#define PB_OPTEXT_POINTER(tag, st, m, fd, ltype, ptr) \
PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr)
#define PB_OPTEXT_CALLBACK(tag, st, m, fd, ltype, ptr) \
PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr)
/* The mapping from protobuf types to LTYPEs is done using these macros. */
#define PB_LTYPE_MAP_BOOL PB_LTYPE_VARINT
#define PB_LTYPE_MAP_BYTES PB_LTYPE_BYTES
#define PB_LTYPE_MAP_DOUBLE PB_LTYPE_FIXED64
#define PB_LTYPE_MAP_ENUM PB_LTYPE_VARINT
#define PB_LTYPE_MAP_UENUM PB_LTYPE_UVARINT
#define PB_LTYPE_MAP_FIXED32 PB_LTYPE_FIXED32
#define PB_LTYPE_MAP_FIXED64 PB_LTYPE_FIXED64
#define PB_LTYPE_MAP_FLOAT PB_LTYPE_FIXED32
#define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT
#define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT
#define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE
#define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32
#define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64
#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT
#define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT
#define PB_LTYPE_MAP_STRING PB_LTYPE_STRING
#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT
#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT
#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION
#define PB_LTYPE_MAP_FIXED_LENGTH_BYTES PB_LTYPE_FIXED_LENGTH_BYTES
/* This is the actual macro used in field descriptions.
* It takes these arguments:
* - Field tag number
* - Field type: BOOL, BYTES, DOUBLE, ENUM, UENUM, FIXED32, FIXED64,
* FLOAT, INT32, INT64, MESSAGE, SFIXED32, SFIXED64
* SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION
* - Field rules: REQUIRED, OPTIONAL or REPEATED
* - Allocation: STATIC, CALLBACK or POINTER
* - Placement: FIRST or OTHER, depending on if this is the first field in structure.
* - Message name
* - Field name
* - Previous field name (or field name again for first field)
* - Pointer to default value or submsg fields.
*/
#define PB_FIELD(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \
PB_ ## rules ## _ ## allocation(tag, message, field, \
PB_DATAOFFSET_ ## placement(message, field, prevfield), \
PB_LTYPE_MAP_ ## type, ptr)
/* Field description for repeated static fixed count fields.*/
#define PB_REPEATED_FIXED_COUNT(tag, type, placement, message, field, prevfield, ptr) \
{tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | PB_LTYPE_MAP_ ## type, \
PB_DATAOFFSET_ ## placement(message, field, prevfield), \
0, \
pb_membersize(message, field[0]), \
pb_arraysize(message, field), ptr}
/* Field description for oneof fields. This requires taking into account the
* union name also, that's why a separate set of macros is needed.
*/
#define PB_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \
fd, pb_delta(st, which_ ## u, u.m), \
pb_membersize(st, u.m), 0, ptr}
#define PB_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \
fd, pb_delta(st, which_ ## u, u.m), \
pb_membersize(st, u.m[0]), 0, ptr}
#define PB_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \
PB_ONEOF_ ## allocation(union_name, tag, message, field, \
PB_DATAOFFSET_ ## placement(message, union_name.field, prevfield), \
PB_LTYPE_MAP_ ## type, ptr)
#define PB_ANONYMOUS_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \
fd, pb_delta(st, which_ ## u, m), \
pb_membersize(st, m), 0, ptr}
#define PB_ANONYMOUS_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \
{tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \
fd, pb_delta(st, which_ ## u, m), \
pb_membersize(st, m[0]), 0, ptr}
#define PB_ANONYMOUS_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \
PB_ANONYMOUS_ONEOF_ ## allocation(union_name, tag, message, field, \
PB_DATAOFFSET_ ## placement(message, field, prevfield), \
PB_LTYPE_MAP_ ## type, ptr)
/* These macros are used for giving out error messages.
* They are mostly a debugging aid; the main error information
* is the true/false return value from functions.
* Some code space can be saved by disabling the error
* messages if not used.
*
* PB_SET_ERROR() sets the error message if none has been set yet.
* msg must be a constant string literal.
* PB_GET_ERROR() always returns a pointer to a string.
* PB_RETURN_ERROR() sets the error and returns false from current
* function.
*/
#ifdef PB_NO_ERRMSG
#define PB_SET_ERROR(stream, msg) PB_UNUSED(stream)
#define PB_GET_ERROR(stream) "(errmsg disabled)"
#else
#define PB_SET_ERROR(stream, msg) (stream->errmsg = (stream)->errmsg ? (stream)->errmsg : (msg))
#define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)")
#endif
#define PB_RETURN_ERROR(stream, msg) return PB_SET_ERROR(stream, msg), false
#endif
@@ -0,0 +1,90 @@
//*****************************************************************************
//
// bp_common.h
//! @file
//!
//! @brief Auto-generated (see below).
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/* pb_common.h: Common support functions for pb_encode.c and pb_decode.c.
* These functions are rarely needed by applications directly.
*/
#ifndef PB_COMMON_H_INCLUDED
#define PB_COMMON_H_INCLUDED
#include "pb.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Iterator for pb_field_t list */
struct pb_field_iter_s
{
const pb_field_t *start; /* Start of the pb_field_t array */
const pb_field_t *pos; /* Current position of the iterator */
unsigned required_field_index; /* Zero-based index that counts only the required fields */
void *dest_struct; /* Pointer to start of the structure */
void *pData; /* Pointer to current field value */
void *pSize; /* Pointer to count/has field */
};
typedef struct pb_field_iter_s pb_field_iter_t;
/* Initialize the field iterator structure to beginning.
* Returns false if the message type is empty. */
bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct);
/* Advance the iterator to the next field.
* Returns false when the iterator wraps back to the first field. */
bool pb_field_iter_next(pb_field_iter_t *iter);
/* Advance the iterator until it points at a field with the given tag.
* Returns false if no such field exists. */
bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
@@ -0,0 +1,222 @@
//*****************************************************************************
//
// pb_decode.h
//! @file
//!
//! @brief Auto-generated (see below).
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/* pb_decode.h: Functions to decode protocol buffers. Depends on pb_decode.c.
* The main function is pb_decode. You also need an input stream, and the
* field descriptions created by nanopb_generator.py.
*/
#ifndef PB_DECODE_H_INCLUDED
#define PB_DECODE_H_INCLUDED
#include "pb.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Structure for defining custom input streams. You will need to provide
* a callback function to read the bytes from your storage, which can be
* for example a file or a network socket.
*
* The callback must conform to these rules:
*
* 1) Return false on IO errors. This will cause decoding to abort.
* 2) You can use state to store your own data (e.g. buffer pointer),
* and rely on pb_read to verify that no-body reads past bytes_left.
* 3) Your callback may be used with substreams, in which case bytes_left
* is different than from the main stream. Don't use bytes_left to compute
* any pointers.
*/
struct pb_istream_s
{
#ifdef PB_BUFFER_ONLY
/* Callback pointer is not used in buffer-only configuration.
* Having an int pointer here allows binary compatibility but
* gives an error if someone tries to assign callback function.
*/
int *callback;
#else
bool (*callback)(pb_istream_t *stream, pb_byte_t *buf, size_t count);
#endif
void *state; /* Free field for use by callback implementation */
size_t bytes_left;
#ifndef PB_NO_ERRMSG
const char *errmsg;
#endif
};
/***************************
* Main decoding functions *
***************************/
/* Decode a single protocol buffers message from input stream into a C structure.
* Returns true on success, false on any failure.
* The actual struct pointed to by dest must match the description in fields.
* Callback fields of the destination structure must be initialized by caller.
* All other fields will be initialized by this function.
*
* Example usage:
* MyMessage msg = {};
* uint8_t buffer[64];
* pb_istream_t stream;
*
* // ... read some data into buffer ...
*
* stream = pb_istream_from_buffer(buffer, count);
* pb_decode(&stream, MyMessage_fields, &msg);
*/
bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
/* Same as pb_decode, except does not initialize the destination structure
* to default values. This is slightly faster if you need no default values
* and just do memset(struct, 0, sizeof(struct)) yourself.
*
* This can also be used for 'merging' two messages, i.e. update only the
* fields that exist in the new message.
*
* Note: If this function returns with an error, it will not release any
* dynamically allocated fields. You will need to call pb_release() yourself.
*/
bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
/* Same as pb_decode, except expects the stream to start with the message size
* encoded as varint. Corresponds to parseDelimitedFrom() in Google's
* protobuf API.
*/
bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
/* Same as pb_decode_delimited, except that it does not initialize the destination structure.
* See pb_decode_noinit
*/
bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
/* Same as pb_decode, except allows the message to be terminated with a null byte.
* NOTE: Until nanopb-0.4.0, pb_decode() also allows null-termination. This behaviour
* is not supported in most other protobuf implementations, so pb_decode_delimited()
* is a better option for compatibility.
*/
bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct);
#ifdef PB_ENABLE_MALLOC
/* Release any allocated pointer fields. If you use dynamic allocation, you should
* call this for any successfully decoded message when you are done with it. If
* pb_decode() returns with an error, the message is already released.
*/
void pb_release(const pb_field_t fields[], void *dest_struct);
#endif
/**************************************
* Functions for manipulating streams *
**************************************/
/* Create an input stream for reading from a memory buffer.
*
* Alternatively, you can use a custom stream that reads directly from e.g.
* a file or a network socket.
*/
pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize);
/* Function to read from a pb_istream_t. You can use this if you need to
* read some custom header data, or to read data in field callbacks.
*/
bool pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);
/************************************************
* Helper functions for writing field callbacks *
************************************************/
/* Decode the tag for the next field in the stream. Gives the wire type and
* field tag. At end of the message, returns false and sets eof to true. */
bool pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof);
/* Skip the field payload data, given the wire type. */
bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type);
/* Decode an integer in the varint format. This works for bool, enum, int32,
* int64, uint32 and uint64 field types. */
#ifndef PB_WITHOUT_64BIT
bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest);
#else
#define pb_decode_varint pb_decode_varint32
#endif
/* Decode an integer in the varint format. This works for bool, enum, int32,
* and uint32 field types. */
bool pb_decode_varint32(pb_istream_t *stream, uint32_t *dest);
/* Decode an integer in the zig-zagged svarint format. This works for sint32
* and sint64. */
#ifndef PB_WITHOUT_64BIT
bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest);
#else
bool pb_decode_svarint(pb_istream_t *stream, int32_t *dest);
#endif
/* Decode a fixed32, sfixed32 or float value. You need to pass a pointer to
* a 4-byte wide C variable. */
bool pb_decode_fixed32(pb_istream_t *stream, void *dest);
#ifndef PB_WITHOUT_64BIT
/* Decode a fixed64, sfixed64 or double value. You need to pass a pointer to
* a 8-byte wide C variable. */
bool pb_decode_fixed64(pb_istream_t *stream, void *dest);
#endif
/* Make a limited-length substream for reading a PB_WT_STRING field. */
bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream);
bool pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
@@ -0,0 +1,217 @@
//*****************************************************************************
//
// pb_encode.h
//! @file
//!
//! @brief Auto-generated (see below).
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/* pb_encode.h: Functions to encode protocol buffers. Depends on pb_encode.c.
* The main function is pb_encode. You also need an output stream, and the
* field descriptions created by nanopb_generator.py.
*/
#ifndef PB_ENCODE_H_INCLUDED
#define PB_ENCODE_H_INCLUDED
#include "pb.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Structure for defining custom output streams. You will need to provide
* a callback function to write the bytes to your storage, which can be
* for example a file or a network socket.
*
* The callback must conform to these rules:
*
* 1) Return false on IO errors. This will cause encoding to abort.
* 2) You can use state to store your own data (e.g. buffer pointer).
* 3) pb_write will update bytes_written after your callback runs.
* 4) Substreams will modify max_size and bytes_written. Don't use them
* to calculate any pointers.
*/
struct pb_ostream_s
{
#ifdef PB_BUFFER_ONLY
/* Callback pointer is not used in buffer-only configuration.
* Having an int pointer here allows binary compatibility but
* gives an error if someone tries to assign callback function.
* Also, NULL pointer marks a 'sizing stream' that does not
* write anything.
*/
int *callback;
#else
bool (*callback)(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
#endif
void *state; /* Free field for use by callback implementation. */
size_t max_size; /* Limit number of output bytes written (or use SIZE_MAX). */
size_t bytes_written; /* Number of bytes written so far. */
#ifndef PB_NO_ERRMSG
const char *errmsg;
#endif
};
/***************************
* Main encoding functions *
***************************/
/* Encode a single protocol buffers message from C structure into a stream.
* Returns true on success, false on any failure.
* The actual struct pointed to by src_struct must match the description in fields.
* All required fields in the struct are assumed to have been filled in.
*
* Example usage:
* MyMessage msg = {};
* uint8_t buffer[64];
* pb_ostream_t stream;
*
* msg.field1 = 42;
* stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
* pb_encode(&stream, MyMessage_fields, &msg);
*/
bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct);
/* Same as pb_encode, but prepends the length of the message as a varint.
* Corresponds to writeDelimitedTo() in Google's protobuf API.
*/
bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct);
/* Same as pb_encode, but appends a null byte to the message for termination.
* NOTE: This behaviour is not supported in most other protobuf implementations, so pb_encode_delimited()
* is a better option for compatibility.
*/
bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct);
/* Encode the message to get the size of the encoded data, but do not store
* the data. */
bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct);
/**************************************
* Functions for manipulating streams *
**************************************/
/* Create an output stream for writing into a memory buffer.
* The number of bytes written can be found in stream.bytes_written after
* encoding the message.
*
* Alternatively, you can use a custom stream that writes directly to e.g.
* a file or a network socket.
*/
pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize);
/* Pseudo-stream for measuring the size of a message without actually storing
* the encoded data.
*
* Example usage:
* MyMessage msg = {};
* pb_ostream_t stream = PB_OSTREAM_SIZING;
* pb_encode(&stream, MyMessage_fields, &msg);
* printf("Message size is %d\n", stream.bytes_written);
*/
#ifndef PB_NO_ERRMSG
#define PB_OSTREAM_SIZING {0, 0, 0, 0, 0}
#else
#define PB_OSTREAM_SIZING {0, 0, 0, 0}
#endif
/* Function to write into a pb_ostream_t stream. You can use this if you need
* to append or prepend some custom headers to the message.
*/
bool pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
/************************************************
* Helper functions for writing field callbacks *
************************************************/
/* Encode field header based on type and field number defined in the field
* structure. Call this from the callback before writing out field contents. */
bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field);
/* Encode field header by manually specifing wire type. You need to use this
* if you want to write out packed arrays from a callback field. */
bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number);
/* Encode an integer in the varint format.
* This works for bool, enum, int32, int64, uint32 and uint64 field types. */
#ifndef PB_WITHOUT_64BIT
bool pb_encode_varint(pb_ostream_t *stream, uint64_t value);
#else
bool pb_encode_varint(pb_ostream_t *stream, uint32_t value);
#endif
/* Encode an integer in the zig-zagged svarint format.
* This works for sint32 and sint64. */
#ifndef PB_WITHOUT_64BIT
bool pb_encode_svarint(pb_ostream_t *stream, int64_t value);
#else
bool pb_encode_svarint(pb_ostream_t *stream, int32_t value);
#endif
/* Encode a string or bytes type field. For strings, pass strlen(s) as size. */
bool pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size);
/* Encode a fixed32, sfixed32 or float value.
* You need to pass a pointer to a 4-byte wide C variable. */
bool pb_encode_fixed32(pb_ostream_t *stream, const void *value);
#ifndef PB_WITHOUT_64BIT
/* Encode a fixed64, sfixed64 or double value.
* You need to pass a pointer to a 8-byte wide C variable. */
bool pb_encode_fixed64(pb_ostream_t *stream, const void *value);
#endif
/* Encode a submessage field.
* You need to pass the pb_field_t array and pointer to struct, just like
* with pb_encode(). This internally encodes the submessage twice, first to
* calculate message size and then to actually write it out.
*/
bool pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif
@@ -0,0 +1,276 @@
//*****************************************************************************
//
// speech.pb.h
//! @file
//!
//! @brief Auto-generated (see below).
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/* Automatically generated nanopb header */
/* Generated by nanopb-0.3.9.1 at Fri Nov 09 16:58:28 2018. */
#ifndef PB_SPEECH_PB_H_INCLUDED
#define PB_SPEECH_PB_H_INCLUDED
#include <pb.h>
#include "common.pb.h"
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Enum definitions */
typedef enum _AudioProfile
{
AudioProfile_CLOSE_TALK = 0,
AudioProfile_NEAR_FIELD = 1,
AudioProfile_FAR_FIELD = 2
} AudioProfile;
#define _AudioProfile_MIN AudioProfile_CLOSE_TALK
#define _AudioProfile_MAX AudioProfile_FAR_FIELD
#define _AudioProfile_ARRAYSIZE ((AudioProfile)(AudioProfile_FAR_FIELD + 1))
typedef enum _AudioFormat
{
AudioFormat_PCM_L16_16KHZ_MONO = 0,
AudioFormat_OPUS_16KHZ_32KBPS_CBR_0_20MS = 1,
AudioFormat_OPUS_16KHZ_16KBPS_CBR_0_20MS = 2,
AudioFormat_MSBC = 3
} AudioFormat;
#define _AudioFormat_MIN AudioFormat_PCM_L16_16KHZ_MONO
#define _AudioFormat_MAX AudioFormat_MSBC
#define _AudioFormat_ARRAYSIZE ((AudioFormat)(AudioFormat_MSBC + 1))
typedef enum _AudioSource
{
AudioSource_STREAM = 0,
AudioSource_BLUETOOTH_SCO = 1
} AudioSource;
#define _AudioSource_MIN AudioSource_STREAM
#define _AudioSource_MAX AudioSource_BLUETOOTH_SCO
#define _AudioSource_ARRAYSIZE ((AudioSource)(AudioSource_BLUETOOTH_SCO + 1))
typedef enum _SpeechState
{
SpeechState_IDLE = 0,
SpeechState_LISTENING = 1,
SpeechState_PROCESSING = 2,
SpeechState_SPEAKING = 3
} SpeechState;
#define _SpeechState_MIN SpeechState_IDLE
#define _SpeechState_MAX SpeechState_SPEAKING
#define _SpeechState_ARRAYSIZE ((SpeechState)(SpeechState_SPEAKING + 1))
typedef enum _SpeechInitiator_Type
{
SpeechInitiator_Type_NONE = 0,
SpeechInitiator_Type_PRESS_AND_HOLD = 1,
SpeechInitiator_Type_TAP = 3,
SpeechInitiator_Type_WAKEWORD = 4
} SpeechInitiator_Type;
#define _SpeechInitiator_Type_MIN SpeechInitiator_Type_NONE
#define _SpeechInitiator_Type_MAX SpeechInitiator_Type_WAKEWORD
#define _SpeechInitiator_Type_ARRAYSIZE ((SpeechInitiator_Type)(SpeechInitiator_Type_WAKEWORD + 1))
/* Struct definitions */
typedef struct _Dialog
{
uint32_t id;
/* @@protoc_insertion_point(struct:Dialog) */
} Dialog;
typedef struct _NotifySpeechState
{
SpeechState state;
/* @@protoc_insertion_point(struct:NotifySpeechState) */
} NotifySpeechState;
typedef PB_BYTES_ARRAY_T(256) SpeechInitiator_WakeWord_metadata_t;
typedef struct _SpeechInitiator_WakeWord
{
uint32_t start_index_in_samples;
uint32_t end_index_in_samples;
bool near_miss;
SpeechInitiator_WakeWord_metadata_t metadata;
/* @@protoc_insertion_point(struct:SpeechInitiator_WakeWord) */
} SpeechInitiator_WakeWord;
typedef struct _SpeechSettings
{
AudioProfile audio_profile;
AudioFormat audio_format;
AudioSource audio_source;
/* @@protoc_insertion_point(struct:SpeechSettings) */
} SpeechSettings;
typedef struct _EndpointSpeech
{
Dialog dialog;
/* @@protoc_insertion_point(struct:EndpointSpeech) */
} EndpointSpeech;
typedef struct _ProvideSpeech
{
Dialog dialog;
/* @@protoc_insertion_point(struct:ProvideSpeech) */
} ProvideSpeech;
typedef struct _SpeechInitiator
{
SpeechInitiator_Type type;
SpeechInitiator_WakeWord wake_word;
/* @@protoc_insertion_point(struct:SpeechInitiator) */
} SpeechInitiator;
typedef struct _SpeechProvider
{
SpeechSettings speech_settings;
Dialog dialog;
/* @@protoc_insertion_point(struct:SpeechProvider) */
} SpeechProvider;
typedef struct _StopSpeech
{
ErrorCode error_code;
Dialog dialog;
/* @@protoc_insertion_point(struct:StopSpeech) */
} StopSpeech;
typedef struct _StartSpeech
{
SpeechSettings settings;
SpeechInitiator initiator;
Dialog dialog;
bool suppressEarcon;
/* @@protoc_insertion_point(struct:StartSpeech) */
} StartSpeech;
/* Default values for struct fields */
/* Initializer values for message structs */
#define Dialog_init_default {0}
#define SpeechSettings_init_default {_AudioProfile_MIN, _AudioFormat_MIN, _AudioSource_MIN}
#define SpeechInitiator_init_default {_SpeechInitiator_Type_MIN, SpeechInitiator_WakeWord_init_default}
#define SpeechInitiator_WakeWord_init_default {0, 0, 0, {0, {0}}}
#define StartSpeech_init_default {SpeechSettings_init_default, SpeechInitiator_init_default, Dialog_init_default, 0}
#define SpeechProvider_init_default {SpeechSettings_init_default, Dialog_init_default}
#define ProvideSpeech_init_default {Dialog_init_default}
#define StopSpeech_init_default {_ErrorCode_MIN, Dialog_init_default}
#define EndpointSpeech_init_default {Dialog_init_default}
#define NotifySpeechState_init_default {_SpeechState_MIN}
#define Dialog_init_zero {0}
#define SpeechSettings_init_zero {_AudioProfile_MIN, _AudioFormat_MIN, _AudioSource_MIN}
#define SpeechInitiator_init_zero {_SpeechInitiator_Type_MIN, SpeechInitiator_WakeWord_init_zero}
#define SpeechInitiator_WakeWord_init_zero {0, 0, 0, {0, {0}}}
#define StartSpeech_init_zero {SpeechSettings_init_zero, SpeechInitiator_init_zero, Dialog_init_zero, 0}
#define SpeechProvider_init_zero {SpeechSettings_init_zero, Dialog_init_zero}
#define ProvideSpeech_init_zero {Dialog_init_zero}
#define StopSpeech_init_zero {_ErrorCode_MIN, Dialog_init_zero}
#define EndpointSpeech_init_zero {Dialog_init_zero}
#define NotifySpeechState_init_zero {_SpeechState_MIN}
/* Field tags (for use in manual encoding/decoding) */
#define Dialog_id_tag 1
#define NotifySpeechState_state_tag 1
#define SpeechInitiator_WakeWord_start_index_in_samples_tag 1
#define SpeechInitiator_WakeWord_end_index_in_samples_tag 2
#define SpeechInitiator_WakeWord_near_miss_tag 3
#define SpeechInitiator_WakeWord_metadata_tag 4
#define SpeechSettings_audio_profile_tag 1
#define SpeechSettings_audio_format_tag 2
#define SpeechSettings_audio_source_tag 3
#define EndpointSpeech_dialog_tag 1
#define ProvideSpeech_dialog_tag 1
#define SpeechInitiator_type_tag 1
#define SpeechInitiator_wake_word_tag 2
#define SpeechProvider_speech_settings_tag 1
#define SpeechProvider_dialog_tag 2
#define StopSpeech_error_code_tag 1
#define StopSpeech_dialog_tag 2
#define StartSpeech_settings_tag 1
#define StartSpeech_initiator_tag 2
#define StartSpeech_dialog_tag 3
#define StartSpeech_suppressEarcon_tag 4
/* Struct field encoding specification for nanopb */
extern const pb_field_t Dialog_fields[2];
extern const pb_field_t SpeechSettings_fields[4];
extern const pb_field_t SpeechInitiator_fields[3];
extern const pb_field_t SpeechInitiator_WakeWord_fields[5];
extern const pb_field_t StartSpeech_fields[5];
extern const pb_field_t SpeechProvider_fields[3];
extern const pb_field_t ProvideSpeech_fields[2];
extern const pb_field_t StopSpeech_fields[3];
extern const pb_field_t EndpointSpeech_fields[2];
extern const pb_field_t NotifySpeechState_fields[2];
/* Maximum encoded size of messages (where known) */
#define Dialog_size 6
#define SpeechSettings_size 6
#define SpeechInitiator_size 278
#define SpeechInitiator_WakeWord_size 273
#define StartSpeech_size 299
#define SpeechProvider_size 16
#define ProvideSpeech_size 8
#define StopSpeech_size 10
#define EndpointSpeech_size 8
#define NotifySpeechState_size 2
/* Message IDs (where set with "msgid" option) */
#ifdef PB_MSGID
#define SPEECH_MESSAGES \
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
/* @@protoc_insertion_point(eof) */
#endif
@@ -0,0 +1,140 @@
//*****************************************************************************
//
// state.pb.h
//! @file
//!
//! @brief Auto-generated (see below).
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/* Automatically generated nanopb header */
/* Generated by nanopb-0.3.9.1 at Fri Nov 09 16:58:28 2018. */
#ifndef PB_STATE_PB_H_INCLUDED
#define PB_STATE_PB_H_INCLUDED
#include <pb.h>
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Struct definitions */
typedef struct _GetState
{
uint32_t feature;
/* @@protoc_insertion_point(struct:GetState) */
} GetState;
typedef struct _State
{
uint32_t feature;
pb_size_t which_value;
union
{
bool boolean;
uint32_t integer;
} value;
/* @@protoc_insertion_point(struct:State) */
} State;
typedef struct _SetState
{
State state;
/* @@protoc_insertion_point(struct:SetState) */
} SetState;
typedef struct _SynchronizeState
{
State state;
/* @@protoc_insertion_point(struct:SynchronizeState) */
} SynchronizeState;
/* Default values for struct fields */
/* Initializer values for message structs */
#define State_init_default {0, 0, {0}}
#define GetState_init_default {0}
#define SetState_init_default {State_init_default}
#define SynchronizeState_init_default {State_init_default}
#define State_init_zero {0, 0, {0}}
#define GetState_init_zero {0}
#define SetState_init_zero {State_init_zero}
#define SynchronizeState_init_zero {State_init_zero}
/* Field tags (for use in manual encoding/decoding) */
#define GetState_feature_tag 1
#define State_boolean_tag 2
#define State_integer_tag 3
#define State_feature_tag 1
#define SetState_state_tag 1
#define SynchronizeState_state_tag 1
/* Struct field encoding specification for nanopb */
extern const pb_field_t State_fields[4];
extern const pb_field_t GetState_fields[2];
extern const pb_field_t SetState_fields[2];
extern const pb_field_t SynchronizeState_fields[2];
/* Maximum encoded size of messages (where known) */
#define State_size 12
#define GetState_size 6
#define SetState_size 14
#define SynchronizeState_size 14
/* Message IDs (where set with "msgid" option) */
#ifdef PB_MSGID
#define STATE_MESSAGES \
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
/* @@protoc_insertion_point(eof) */
#endif
@@ -0,0 +1,134 @@
//*****************************************************************************
//
// system.pb.h
//! @file
//!
//! @brief Auto-generated (see below).
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/* Automatically generated nanopb header */
/* Generated by nanopb-0.3.9.1 at Fri Nov 09 16:58:28 2018. */
#ifndef PB_SYSTEM_PB_H_INCLUDED
#define PB_SYSTEM_PB_H_INCLUDED
#include <pb.h>
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Struct definitions */
typedef struct _KeepAlive
{
char dummy_field;
/* @@protoc_insertion_point(struct:KeepAlive) */
} KeepAlive;
typedef struct _RemoveDevice
{
char dummy_field;
/* @@protoc_insertion_point(struct:RemoveDevice) */
} RemoveDevice;
typedef struct _ResetConnection
{
uint32_t timeout;
bool force_disconnect;
/* @@protoc_insertion_point(struct:ResetConnection) */
} ResetConnection;
typedef struct _SynchronizeSettings
{
uint32_t timestamp_hi;
uint32_t timestamp_lo;
/* @@protoc_insertion_point(struct:SynchronizeSettings) */
} SynchronizeSettings;
/* Default values for struct fields */
/* Initializer values for message structs */
#define ResetConnection_init_default {0, 0}
#define SynchronizeSettings_init_default {0, 0}
#define KeepAlive_init_default {0}
#define RemoveDevice_init_default {0}
#define ResetConnection_init_zero {0, 0}
#define SynchronizeSettings_init_zero {0, 0}
#define KeepAlive_init_zero {0}
#define RemoveDevice_init_zero {0}
/* Field tags (for use in manual encoding/decoding) */
#define ResetConnection_timeout_tag 1
#define ResetConnection_force_disconnect_tag 2
#define SynchronizeSettings_timestamp_hi_tag 1
#define SynchronizeSettings_timestamp_lo_tag 2
/* Struct field encoding specification for nanopb */
extern const pb_field_t ResetConnection_fields[3];
extern const pb_field_t SynchronizeSettings_fields[3];
extern const pb_field_t KeepAlive_fields[1];
extern const pb_field_t RemoveDevice_fields[1];
/* Maximum encoded size of messages (where known) */
#define ResetConnection_size 8
#define SynchronizeSettings_size 12
#define KeepAlive_size 0
#define RemoveDevice_size 0
/* Message IDs (where set with "msgid" option) */
#ifdef PB_MSGID
#define SYSTEM_MESSAGES \
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
/* @@protoc_insertion_point(eof) */
#endif
@@ -0,0 +1,124 @@
//*****************************************************************************
//
// transport.pb.h
//! @file
//!
//! @brief Auto-generated (see below).
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
/* Automatically generated nanopb header */
/* Generated by nanopb-0.3.9.1 at Fri Nov 09 16:58:28 2018. */
#ifndef PB_TRANSPORT_PB_H_INCLUDED
#define PB_TRANSPORT_PB_H_INCLUDED
#include <pb.h>
#include "common.pb.h"
/* @@protoc_insertion_point(includes) */
#if PB_PROTO_HEADER_VERSION != 30
#error Regenerate this file with the current version of nanopb generator.
#endif
#ifdef __cplusplus
extern "C" {
#endif
/* Struct definitions */
typedef PB_BYTES_ARRAY_T(64) ConnectionDetails_identifier_t;
typedef struct _ConnectionDetails
{
ConnectionDetails_identifier_t identifier;
/* @@protoc_insertion_point(struct:ConnectionDetails) */
} ConnectionDetails;
typedef struct _SwitchTransport
{
Transport new_transport;
/* @@protoc_insertion_point(struct:SwitchTransport) */
} SwitchTransport;
typedef struct _UpgradeTransport
{
Transport transport;
/* @@protoc_insertion_point(struct:UpgradeTransport) */
} UpgradeTransport;
/* Default values for struct fields */
/* Initializer values for message structs */
#define ConnectionDetails_init_default {{0, {0}}}
#define UpgradeTransport_init_default {_Transport_MIN}
#define SwitchTransport_init_default {_Transport_MIN}
#define ConnectionDetails_init_zero {{0, {0}}}
#define UpgradeTransport_init_zero {_Transport_MIN}
#define SwitchTransport_init_zero {_Transport_MIN}
/* Field tags (for use in manual encoding/decoding) */
#define ConnectionDetails_identifier_tag 1
#define SwitchTransport_new_transport_tag 1
#define UpgradeTransport_transport_tag 1
/* Struct field encoding specification for nanopb */
extern const pb_field_t ConnectionDetails_fields[2];
extern const pb_field_t UpgradeTransport_fields[2];
extern const pb_field_t SwitchTransport_fields[2];
/* Maximum encoded size of messages (where known) */
#define ConnectionDetails_size 66
#define UpgradeTransport_size 2
#define SwitchTransport_size 2
/* Message IDs (where set with "msgid" option) */
#ifdef PB_MSGID
#define TRANSPORT_MESSAGES \
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif
/* @@protoc_insertion_point(eof) */
#endif
@@ -0,0 +1,124 @@
//*****************************************************************************
//
// ae.api.h
//! @file
//!
//! @brief Functions for interfacing with the encoder library
//!
//! @addtogroup
//! @ingroup
//! @{
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef AE_API__H
#define AE_API__H
//*****************************************************************************
//
// External Function Calls
//
//*****************************************************************************
//*****************************************************************************
//
//! @brief Initialization of the library
//!
//! Run the initialization function before any operation with the encoder.
//! @param option - option to select whether to include 8-byte header into output.
//! 0 for no header.
//! other value for with header.
//! @return numBytes - number of bytes of the data output, including header length.
//!
//! @{
//
//*****************************************************************************
int audio_enc_init(int option);
//*****************************************************************************
//
//! @brief Encodes a frame of audio
//!
//! @param p_pcm_buffer - pointer to the input buffer.
//! @param n_pcm_samples - input length in samples.
//! @param p_encoded_buffer - pointer to the output buffer.
//!
//! This is the major function of the encoder, the encoder encodes a fixed length
//! of audio (20ms) in a fixed input format (16KHz, 16bit, mono, 640 bytes in length),
//! with a fixed output format: CBR, 32000bps output rate (8:1 compression),
//! complexity 4.
//! When output header is selected, each output frame will have a 8 byte header in
//! the beginning of the output data: 4 bytes of length (fixed to 80) followed by
//! 4 bytes of range code.
//!
//! @return numBytes - number of bytes of the data output, including header length.
//!
//! @{
//
//*****************************************************************************
int audio_enc_encode_frame(short *p_pcm_buffer, int n_pcm_samples, unsigned char *p_encoded_buffer);
//*****************************************************************************
//
//! @brief Get version information of the libary
//!
//! @return version_string - pointer to the libary version string.
//!
//! @{
//
//*****************************************************************************
char* audio_get_lib_version(void);
//*****************************************************************************
//
//! @brief Get version information of the base package
//!
//! @return version_string - pointer to the base package version string.
//! version information is 7 byte long without line break
//! @{
//
//*****************************************************************************
char* audio_get_package_version(void);
#endif // AE_API__H
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,848 @@
/*
*
* Bluetooth low-complexity, subband codec (SBC) library
*
* Copyright (C) 2008-2010 Nokia Corporation
* Copyright (C) 2012-2014 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2004-2005 Henryk Ploetz <henryk@ploetzli.ch>
* Copyright (C) 2005-2006 Brad Midgley <bmidgley@xmission.com>
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef __SBC_H
#define __SBC_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
//#include <sys/types.h>
#include <limits.h>
/* sampling frequency */
#define SBC_FREQ_16000 0x00
#define SBC_FREQ_32000 0x01
#define SBC_FREQ_44100 0x02
#define SBC_FREQ_48000 0x03
/* blocks */
#define SBC_BLK_4 0x00
#define SBC_BLK_8 0x01
#define SBC_BLK_12 0x02
#define SBC_BLK_16 0x03
/* channel mode */
#define SBC_MODE_MONO 0x00
#define SBC_MODE_DUAL_CHANNEL 0x01
#define SBC_MODE_STEREO 0x02
#define SBC_MODE_JOINT_STEREO 0x03
/* allocation method */
#define SBC_AM_LOUDNESS 0x00
#define SBC_AM_SNR 0x01
/* subbands */
#define SBC_SB_4 0x00
#define SBC_SB_8 0x01
/* data endianess */
#define SBC_LE 0x00
#define SBC_BE 0x01
#ifndef _SSIZE_T_DEFINED
#ifdef _WIN64
typedef __int64 ssize_t;
#else
typedef int ssize_t;
#endif
#define _SSIZE_T_DEFINED
#endif
#define SBC_EXPORT
#define SBC_X_BUFFER_SIZE 328
#define SCALE_OUT_BITS 15
//#define SBC_ALIGNED
#define SBC_ALWAYS_INLINE inline
#define SBCDEC_FIXED_EXTRA_BITS 2
#define SBC_ALIGN_BITS 4
#define SBC_ALIGN_MASK ((1 << (SBC_ALIGN_BITS)) - 1)
#define fabs(x) ((x) < 0 ? -(x) : (x))
/* C does not provide an explicit arithmetic shift right but this will
always be correct and every compiler *should* generate optimal code */
#define ASR(val, bits) ((-2 >> 1 == -1) ? \
((int32_t)(val)) >> (bits) : ((int32_t) (val)) / (1 << (bits)))
#define SCALE_SPROTO4_TBL 12
#define SCALE_SPROTO8_TBL 14
#define SCALE_NPROTO4_TBL 11
#define SCALE_NPROTO8_TBL 11
#define SCALE4_STAGED1_BITS 15
#define SCALE4_STAGED2_BITS 16
#define SCALE8_STAGED1_BITS 15
#define SCALE8_STAGED2_BITS 16
typedef int32_t sbc_fixed_t;
#define SCALE4_STAGED1(src) ASR(src, SCALE4_STAGED1_BITS)
#define SCALE4_STAGED2(src) ASR(src, SCALE4_STAGED2_BITS)
#define SCALE8_STAGED1(src) ASR(src, SCALE8_STAGED1_BITS)
#define SCALE8_STAGED2(src) ASR(src, SCALE8_STAGED2_BITS)
#define MULA(a, b, res) ((a) * (b) + (res))
#define MUL(a, b) ((a) * (b))
#define SBC_FIXED_0(val) { val = 0; }
#define FIXED_A int32_t /* data type for fixed point accumulator */
#define FIXED_T int16_t /* data type for fixed point constants */
#define SBC_FIXED_EXTRA_BITS 0
#define SS4(val) ASR(val, SCALE_SPROTO4_TBL)
#define SS8(val) ASR(val, SCALE_SPROTO8_TBL)
#define SN4(val) ASR(val, SCALE_NPROTO4_TBL + 1 + SBCDEC_FIXED_EXTRA_BITS)
#define SN8(val) ASR(val, SCALE_NPROTO8_TBL + 1 + SBCDEC_FIXED_EXTRA_BITS)
#define SBC_PROTO_FIXED4_SCALE \
((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 1)
#define F_PROTO4(x) (FIXED_A) ((x * 2) * \
((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5)
#define F(x) F_PROTO4(x)
static const FIXED_T _sbc_proto_fixed4[40] =
{
F(0.00000000E+00), F(5.36548976E-04),
-F(1.49188357E-03), F(2.73370904E-03),
F(3.83720193E-03), F(3.89205149E-03),
F(1.86581691E-03), F(3.06012286E-03),
F(1.09137620E-02), F(2.04385087E-02),
-F(2.88757392E-02), F(3.21939290E-02),
F(2.58767811E-02), F(6.13245186E-03),
-F(2.88217274E-02), F(7.76463494E-02),
F(1.35593274E-01), F(1.94987841E-01),
-F(2.46636662E-01), F(2.81828203E-01),
F(2.94315332E-01), F(2.81828203E-01),
F(2.46636662E-01), -F(1.94987841E-01),
-F(1.35593274E-01), -F(7.76463494E-02),
F(2.88217274E-02), F(6.13245186E-03),
F(2.58767811E-02), F(3.21939290E-02),
F(2.88757392E-02), -F(2.04385087E-02),
-F(1.09137620E-02), -F(3.06012286E-03),
-F(1.86581691E-03), F(3.89205149E-03),
F(3.83720193E-03), F(2.73370904E-03),
F(1.49188357E-03), -F(5.36548976E-04),
};
#undef F
/*
* To produce this cosine matrix in Octave:
*
* b = zeros(4, 8);
* for i = 0:3
* for j = 0:7 b(i+1, j+1) = cos((i + 0.5) * (j - 2) * (pi/4))
* endfor
* endfor;
* printf("%.10f, ", b');
*
* Note: in each block of 8 numbers sign was changed for elements 2 and 7
*
* Change of sign for element 2 allows to replace constant 1.0 (not
* representable in Q15 format) with -1.0 (fine with Q15).
* Changed sign for element 7 allows to have more similar constants
* and simplify subband filter function code.
*/
#define SBC_COS_TABLE_FIXED4_SCALE \
((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS)
#define F_COS4(x) (FIXED_A) ((x) * \
((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5)
#define F(x) F_COS4(x)
static const FIXED_T cos_table_fixed_4[32] =
{
F(0.7071067812), F(0.9238795325), -F(1.0000000000), F(0.9238795325),
F(0.7071067812), F(0.3826834324), F(0.0000000000), F(0.3826834324),
-F(0.7071067812), F(0.3826834324), -F(1.0000000000), F(0.3826834324),
-F(0.7071067812), -F(0.9238795325), -F(0.0000000000), -F(0.9238795325),
-F(0.7071067812), -F(0.3826834324), -F(1.0000000000), -F(0.3826834324),
-F(0.7071067812), F(0.9238795325), F(0.0000000000), F(0.9238795325),
F(0.7071067812), -F(0.9238795325), -F(1.0000000000), -F(0.9238795325),
F(0.7071067812), -F(0.3826834324), -F(0.0000000000), -F(0.3826834324),
};
#undef F
/* A2DP specification: Section 12.8 Tables
*
* Original values are premultiplied by 4 for better precision (that is the
* maximum which is possible without overflows)
*
* Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15
* in order to compensate the same change applied to cos_table_fixed_8
*/
#define SBC_PROTO_FIXED8_SCALE \
((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 1)
#define F_PROTO8(x) (FIXED_A) ((x * 2) * \
((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5)
#define F(x) F_PROTO8(x)
static const FIXED_T _sbc_proto_fixed8[80] =
{
F(0.00000000E+00), F(1.56575398E-04),
F(3.43256425E-04), F(5.54620202E-04),
-F(8.23919506E-04), F(1.13992507E-03),
F(1.47640169E-03), F(1.78371725E-03),
F(2.01182542E-03), F(2.10371989E-03),
F(1.99454554E-03), F(1.61656283E-03),
F(9.02154502E-04), F(1.78805361E-04),
F(1.64973098E-03), F(3.49717454E-03),
F(5.65949473E-03), F(8.02941163E-03),
F(1.04584443E-02), F(1.27472335E-02),
-F(1.46525263E-02), F(1.59045603E-02),
F(1.62208471E-02), F(1.53184106E-02),
F(1.29371806E-02), F(8.85757540E-03),
F(2.92408442E-03), -F(4.91578024E-03),
-F(1.46404076E-02), F(2.61098752E-02),
F(3.90751381E-02), F(5.31873032E-02),
F(6.79989431E-02), F(8.29847578E-02),
F(9.75753918E-02), F(1.11196689E-01),
-F(1.23264548E-01), F(1.33264415E-01),
F(1.40753505E-01), F(1.45389847E-01),
F(1.46955068E-01), F(1.45389847E-01),
F(1.40753505E-01), F(1.33264415E-01),
F(1.23264548E-01), -F(1.11196689E-01),
-F(9.75753918E-02), -F(8.29847578E-02),
-F(6.79989431E-02), -F(5.31873032E-02),
-F(3.90751381E-02), -F(2.61098752E-02),
F(1.46404076E-02), -F(4.91578024E-03),
F(2.92408442E-03), F(8.85757540E-03),
F(1.29371806E-02), F(1.53184106E-02),
F(1.62208471E-02), F(1.59045603E-02),
F(1.46525263E-02), -F(1.27472335E-02),
-F(1.04584443E-02), -F(8.02941163E-03),
-F(5.65949473E-03), -F(3.49717454E-03),
-F(1.64973098E-03), -F(1.78805361E-04),
-F(9.02154502E-04), F(1.61656283E-03),
F(1.99454554E-03), F(2.10371989E-03),
F(2.01182542E-03), F(1.78371725E-03),
F(1.47640169E-03), F(1.13992507E-03),
F(8.23919506E-04), -F(5.54620202E-04),
-F(3.43256425E-04), -F(1.56575398E-04),
};
#undef F
/*
* To produce this cosine matrix in Octave:
*
* b = zeros(8, 16);
* for i = 0:7
* for j = 0:15 b(i+1, j+1) = cos((i + 0.5) * (j - 4) * (pi/8))
* endfor endfor;
* printf("%.10f, ", b');
*
* Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15
*
* Change of sign for element 4 allows to replace constant 1.0 (not
* representable in Q15 format) with -1.0 (fine with Q15).
* Changed signs for elements 13, 14, 15 allow to have more similar constants
* and simplify subband filter function code.
*/
#define SBC_COS_TABLE_FIXED8_SCALE \
((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS)
#define F_COS8(x) (FIXED_A) ((x) * \
((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5)
#define F(x) F_COS8(x)
static const FIXED_T cos_table_fixed_8[128] =
{
F(0.7071067812), F(0.8314696123), F(0.9238795325), F(0.9807852804),
-F(1.0000000000), F(0.9807852804), F(0.9238795325), F(0.8314696123),
F(0.7071067812), F(0.5555702330), F(0.3826834324), F(0.1950903220),
F(0.0000000000), F(0.1950903220), F(0.3826834324), F(0.5555702330),
-F(0.7071067812), -F(0.1950903220), F(0.3826834324), F(0.8314696123),
-F(1.0000000000), F(0.8314696123), F(0.3826834324), -F(0.1950903220),
-F(0.7071067812), -F(0.9807852804), -F(0.9238795325), -F(0.5555702330),
-F(0.0000000000), -F(0.5555702330), -F(0.9238795325), -F(0.9807852804),
-F(0.7071067812), -F(0.9807852804), -F(0.3826834324), F(0.5555702330),
-F(1.0000000000), F(0.5555702330), -F(0.3826834324), -F(0.9807852804),
-F(0.7071067812), F(0.1950903220), F(0.9238795325), F(0.8314696123),
F(0.0000000000), F(0.8314696123), F(0.9238795325), F(0.1950903220),
F(0.7071067812), -F(0.5555702330), -F(0.9238795325), F(0.1950903220),
-F(1.0000000000), F(0.1950903220), -F(0.9238795325), -F(0.5555702330),
F(0.7071067812), F(0.8314696123), -F(0.3826834324), -F(0.9807852804),
-F(0.0000000000), -F(0.9807852804), -F(0.3826834324), F(0.8314696123),
F(0.7071067812), F(0.5555702330), -F(0.9238795325), -F(0.1950903220),
-F(1.0000000000), -F(0.1950903220), -F(0.9238795325), F(0.5555702330),
F(0.7071067812), -F(0.8314696123), -F(0.3826834324), F(0.9807852804),
F(0.0000000000), F(0.9807852804), -F(0.3826834324), -F(0.8314696123),
-F(0.7071067812), F(0.9807852804), -F(0.3826834324), -F(0.5555702330),
-F(1.0000000000), -F(0.5555702330), -F(0.3826834324), F(0.9807852804),
-F(0.7071067812), -F(0.1950903220), F(0.9238795325), -F(0.8314696123),
-F(0.0000000000), -F(0.8314696123), F(0.9238795325), -F(0.1950903220),
-F(0.7071067812), F(0.1950903220), F(0.3826834324), -F(0.8314696123),
-F(1.0000000000), -F(0.8314696123), F(0.3826834324), F(0.1950903220),
-F(0.7071067812), F(0.9807852804), -F(0.9238795325), F(0.5555702330),
-F(0.0000000000), F(0.5555702330), -F(0.9238795325), F(0.9807852804),
F(0.7071067812), -F(0.8314696123), F(0.9238795325), -F(0.9807852804),
-F(1.0000000000), -F(0.9807852804), F(0.9238795325), -F(0.8314696123),
F(0.7071067812), -F(0.5555702330), F(0.3826834324), -F(0.1950903220),
-F(0.0000000000), -F(0.1950903220), F(0.3826834324), -F(0.5555702330),
};
#undef F
/*
* Enforce 16 byte alignment for the data, which is supposed to be used
* with SIMD optimized code.
*/
#define SBC_ALIGN_BITS 4
#define SBC_ALIGN_MASK ((1 << (SBC_ALIGN_BITS)) - 1)
#ifdef __GNUC__
#define SBC_ALIGNED __attribute__((aligned(1 << (SBC_ALIGN_BITS))))
#else
#define SBC_ALIGNED
#endif
/*
* Constant tables for the use in SIMD optimized analysis filters
* Each table consists of two parts:
* 1. reordered "proto" table
* 2. reordered "cos" table
*
* Due to non-symmetrical reordering, separate tables for "even"
* and "odd" cases are needed
*/
static const FIXED_T SBC_ALIGNED analysis_consts_fixed4_simd_even[40 + 16] =
{
#define C0 1.0932568993
#define C1 1.3056875580
#define C2 1.3056875580
#define C3 1.6772280856
#define F(x) F_PROTO4(x)
F(0.00000000E+00 * C0), F(3.83720193E-03 * C0),
F(5.36548976E-04 * C1), F(2.73370904E-03 * C1),
F(3.06012286E-03 * C2), F(3.89205149E-03 * C2),
F(0.00000000E+00 * C3), -F(1.49188357E-03 * C3),
F(1.09137620E-02 * C0), F(2.58767811E-02 * C0),
F(2.04385087E-02 * C1), F(3.21939290E-02 * C1),
F(7.76463494E-02 * C2), F(6.13245186E-03 * C2),
F(0.00000000E+00 * C3), -F(2.88757392E-02 * C3),
F(1.35593274E-01 * C0), F(2.94315332E-01 * C0),
F(1.94987841E-01 * C1), F(2.81828203E-01 * C1),
-F(1.94987841E-01 * C2), F(2.81828203E-01 * C2),
F(0.00000000E+00 * C3), -F(2.46636662E-01 * C3),
-F(1.35593274E-01 * C0), F(2.58767811E-02 * C0),
-F(7.76463494E-02 * C1), F(6.13245186E-03 * C1),
-F(2.04385087E-02 * C2), F(3.21939290E-02 * C2),
F(0.00000000E+00 * C3), F(2.88217274E-02 * C3),
-F(1.09137620E-02 * C0), F(3.83720193E-03 * C0),
-F(3.06012286E-03 * C1), F(3.89205149E-03 * C1),
-F(5.36548976E-04 * C2), F(2.73370904E-03 * C2),
F(0.00000000E+00 * C3), -F(1.86581691E-03 * C3),
#undef F
#define F(x) F_COS4(x)
F(0.7071067812 / C0), F(0.9238795325 / C1),
-F(0.7071067812 / C0), F(0.3826834324 / C1),
-F(0.7071067812 / C0), -F(0.3826834324 / C1),
F(0.7071067812 / C0), -F(0.9238795325 / C1),
F(0.3826834324 / C2), -F(1.0000000000 / C3),
-F(0.9238795325 / C2), -F(1.0000000000 / C3),
F(0.9238795325 / C2), -F(1.0000000000 / C3),
-F(0.3826834324 / C2), -F(1.0000000000 / C3),
#undef F
#undef C0
#undef C1
#undef C2
#undef C3
};
static const FIXED_T SBC_ALIGNED analysis_consts_fixed4_simd_odd[40 + 16] =
{
#define C0 1.3056875580
#define C1 1.6772280856
#define C2 1.0932568993
#define C3 1.3056875580
#define F(x) F_PROTO4(x)
F(2.73370904E-03 * C0), F(5.36548976E-04 * C0),
-F(1.49188357E-03 * C1), F(0.00000000E+00 * C1),
F(3.83720193E-03 * C2), F(1.09137620E-02 * C2),
F(3.89205149E-03 * C3), F(3.06012286E-03 * C3),
F(3.21939290E-02 * C0), F(2.04385087E-02 * C0),
-F(2.88757392E-02 * C1), F(0.00000000E+00 * C1),
F(2.58767811E-02 * C2), F(1.35593274E-01 * C2),
F(6.13245186E-03 * C3), F(7.76463494E-02 * C3),
F(2.81828203E-01 * C0), F(1.94987841E-01 * C0),
-F(2.46636662E-01 * C1), F(0.00000000E+00 * C1),
F(2.94315332E-01 * C2), -F(1.35593274E-01 * C2),
F(2.81828203E-01 * C3), -F(1.94987841E-01 * C3),
F(6.13245186E-03 * C0), -F(7.76463494E-02 * C0),
F(2.88217274E-02 * C1), F(0.00000000E+00 * C1),
F(2.58767811E-02 * C2), -F(1.09137620E-02 * C2),
F(3.21939290E-02 * C3), -F(2.04385087E-02 * C3),
F(3.89205149E-03 * C0), -F(3.06012286E-03 * C0),
-F(1.86581691E-03 * C1), F(0.00000000E+00 * C1),
F(3.83720193E-03 * C2), F(0.00000000E+00 * C2),
F(2.73370904E-03 * C3), -F(5.36548976E-04 * C3),
#undef F
#define F(x) F_COS4(x)
F(0.9238795325 / C0), -F(1.0000000000 / C1),
F(0.3826834324 / C0), -F(1.0000000000 / C1),
-F(0.3826834324 / C0), -F(1.0000000000 / C1),
-F(0.9238795325 / C0), -F(1.0000000000 / C1),
F(0.7071067812 / C2), F(0.3826834324 / C3),
-F(0.7071067812 / C2), -F(0.9238795325 / C3),
-F(0.7071067812 / C2), F(0.9238795325 / C3),
F(0.7071067812 / C2), -F(0.3826834324 / C3),
#undef F
#undef C0
#undef C1
#undef C2
#undef C3
};
static const FIXED_T SBC_ALIGNED analysis_consts_fixed8_simd_even[80 + 64] =
{
#define C0 2.7906148894
#define C1 2.4270044280
#define C2 2.8015616024
#define C3 3.1710363741
#define C4 2.5377944043
#define C5 2.4270044280
#define C6 2.8015616024
#define C7 3.1710363741
#define F(x) F_PROTO8(x)
F(0.00000000E+00 * C0), F(2.01182542E-03 * C0),
F(1.56575398E-04 * C1), F(1.78371725E-03 * C1),
F(3.43256425E-04 * C2), F(1.47640169E-03 * C2),
F(5.54620202E-04 * C3), F(1.13992507E-03 * C3),
-F(8.23919506E-04 * C4), F(0.00000000E+00 * C4),
F(2.10371989E-03 * C5), F(3.49717454E-03 * C5),
F(1.99454554E-03 * C6), F(1.64973098E-03 * C6),
F(1.61656283E-03 * C7), F(1.78805361E-04 * C7),
F(5.65949473E-03 * C0), F(1.29371806E-02 * C0),
F(8.02941163E-03 * C1), F(1.53184106E-02 * C1),
F(1.04584443E-02 * C2), F(1.62208471E-02 * C2),
F(1.27472335E-02 * C3), F(1.59045603E-02 * C3),
-F(1.46525263E-02 * C4), F(0.00000000E+00 * C4),
F(8.85757540E-03 * C5), F(5.31873032E-02 * C5),
F(2.92408442E-03 * C6), F(3.90751381E-02 * C6),
-F(4.91578024E-03 * C7), F(2.61098752E-02 * C7),
F(6.79989431E-02 * C0), F(1.46955068E-01 * C0),
F(8.29847578E-02 * C1), F(1.45389847E-01 * C1),
F(9.75753918E-02 * C2), F(1.40753505E-01 * C2),
F(1.11196689E-01 * C3), F(1.33264415E-01 * C3),
-F(1.23264548E-01 * C4), F(0.00000000E+00 * C4),
F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5),
F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6),
F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7),
-F(6.79989431E-02 * C0), F(1.29371806E-02 * C0),
-F(5.31873032E-02 * C1), F(8.85757540E-03 * C1),
-F(3.90751381E-02 * C2), F(2.92408442E-03 * C2),
-F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3),
F(1.46404076E-02 * C4), F(0.00000000E+00 * C4),
F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5),
F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6),
F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7),
-F(5.65949473E-03 * C0), F(2.01182542E-03 * C0),
-F(3.49717454E-03 * C1), F(2.10371989E-03 * C1),
-F(1.64973098E-03 * C2), F(1.99454554E-03 * C2),
-F(1.78805361E-04 * C3), F(1.61656283E-03 * C3),
-F(9.02154502E-04 * C4), F(0.00000000E+00 * C4),
F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5),
F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6),
F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7),
#undef F
#define F(x) F_COS8(x)
F(0.7071067812 / C0), F(0.8314696123 / C1),
-F(0.7071067812 / C0), -F(0.1950903220 / C1),
-F(0.7071067812 / C0), -F(0.9807852804 / C1),
F(0.7071067812 / C0), -F(0.5555702330 / C1),
F(0.7071067812 / C0), F(0.5555702330 / C1),
-F(0.7071067812 / C0), F(0.9807852804 / C1),
-F(0.7071067812 / C0), F(0.1950903220 / C1),
F(0.7071067812 / C0), -F(0.8314696123 / C1),
F(0.9238795325 / C2), F(0.9807852804 / C3),
F(0.3826834324 / C2), F(0.8314696123 / C3),
-F(0.3826834324 / C2), F(0.5555702330 / C3),
-F(0.9238795325 / C2), F(0.1950903220 / C3),
-F(0.9238795325 / C2), -F(0.1950903220 / C3),
-F(0.3826834324 / C2), -F(0.5555702330 / C3),
F(0.3826834324 / C2), -F(0.8314696123 / C3),
F(0.9238795325 / C2), -F(0.9807852804 / C3),
-F(1.0000000000 / C4), F(0.5555702330 / C5),
-F(1.0000000000 / C4), -F(0.9807852804 / C5),
-F(1.0000000000 / C4), F(0.1950903220 / C5),
-F(1.0000000000 / C4), F(0.8314696123 / C5),
-F(1.0000000000 / C4), -F(0.8314696123 / C5),
-F(1.0000000000 / C4), -F(0.1950903220 / C5),
-F(1.0000000000 / C4), F(0.9807852804 / C5),
-F(1.0000000000 / C4), -F(0.5555702330 / C5),
F(0.3826834324 / C6), F(0.1950903220 / C7),
-F(0.9238795325 / C6), -F(0.5555702330 / C7),
F(0.9238795325 / C6), F(0.8314696123 / C7),
-F(0.3826834324 / C6), -F(0.9807852804 / C7),
-F(0.3826834324 / C6), F(0.9807852804 / C7),
F(0.9238795325 / C6), -F(0.8314696123 / C7),
-F(0.9238795325 / C6), F(0.5555702330 / C7),
F(0.3826834324 / C6), -F(0.1950903220 / C7),
#undef F
#undef C0
#undef C1
#undef C2
#undef C3
#undef C4
#undef C5
#undef C6
#undef C7
};
static const FIXED_T SBC_ALIGNED analysis_consts_fixed8_simd_odd[80 + 64] =
{
#define C0 2.5377944043
#define C1 2.4270044280
#define C2 2.8015616024
#define C3 3.1710363741
#define C4 2.7906148894
#define C5 2.4270044280
#define C6 2.8015616024
#define C7 3.1710363741
#define F(x) F_PROTO8(x)
F(0.00000000E+00 * C0), -F(8.23919506E-04 * C0),
F(1.56575398E-04 * C1), F(1.78371725E-03 * C1),
F(3.43256425E-04 * C2), F(1.47640169E-03 * C2),
F(5.54620202E-04 * C3), F(1.13992507E-03 * C3),
F(2.01182542E-03 * C4), F(5.65949473E-03 * C4),
F(2.10371989E-03 * C5), F(3.49717454E-03 * C5),
F(1.99454554E-03 * C6), F(1.64973098E-03 * C6),
F(1.61656283E-03 * C7), F(1.78805361E-04 * C7),
F(0.00000000E+00 * C0), -F(1.46525263E-02 * C0),
F(8.02941163E-03 * C1), F(1.53184106E-02 * C1),
F(1.04584443E-02 * C2), F(1.62208471E-02 * C2),
F(1.27472335E-02 * C3), F(1.59045603E-02 * C3),
F(1.29371806E-02 * C4), F(6.79989431E-02 * C4),
F(8.85757540E-03 * C5), F(5.31873032E-02 * C5),
F(2.92408442E-03 * C6), F(3.90751381E-02 * C6),
-F(4.91578024E-03 * C7), F(2.61098752E-02 * C7),
F(0.00000000E+00 * C0), -F(1.23264548E-01 * C0),
F(8.29847578E-02 * C1), F(1.45389847E-01 * C1),
F(9.75753918E-02 * C2), F(1.40753505E-01 * C2),
F(1.11196689E-01 * C3), F(1.33264415E-01 * C3),
F(1.46955068E-01 * C4), -F(6.79989431E-02 * C4),
F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5),
F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6),
F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7),
F(0.00000000E+00 * C0), F(1.46404076E-02 * C0),
-F(5.31873032E-02 * C1), F(8.85757540E-03 * C1),
-F(3.90751381E-02 * C2), F(2.92408442E-03 * C2),
-F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3),
F(1.29371806E-02 * C4), -F(5.65949473E-03 * C4),
F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5),
F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6),
F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7),
F(0.00000000E+00 * C0), -F(9.02154502E-04 * C0),
-F(3.49717454E-03 * C1), F(2.10371989E-03 * C1),
-F(1.64973098E-03 * C2), F(1.99454554E-03 * C2),
-F(1.78805361E-04 * C3), F(1.61656283E-03 * C3),
F(2.01182542E-03 * C4), F(0.00000000E+00 * C4),
F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5),
F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6),
F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7),
#undef F
#define F(x) F_COS8(x)
-F(1.0000000000 / C0), F(0.8314696123 / C1),
-F(1.0000000000 / C0), -F(0.1950903220 / C1),
-F(1.0000000000 / C0), -F(0.9807852804 / C1),
-F(1.0000000000 / C0), -F(0.5555702330 / C1),
-F(1.0000000000 / C0), F(0.5555702330 / C1),
-F(1.0000000000 / C0), F(0.9807852804 / C1),
-F(1.0000000000 / C0), F(0.1950903220 / C1),
-F(1.0000000000 / C0), -F(0.8314696123 / C1),
F(0.9238795325 / C2), F(0.9807852804 / C3),
F(0.3826834324 / C2), F(0.8314696123 / C3),
-F(0.3826834324 / C2), F(0.5555702330 / C3),
-F(0.9238795325 / C2), F(0.1950903220 / C3),
-F(0.9238795325 / C2), -F(0.1950903220 / C3),
-F(0.3826834324 / C2), -F(0.5555702330 / C3),
F(0.3826834324 / C2), -F(0.8314696123 / C3),
F(0.9238795325 / C2), -F(0.9807852804 / C3),
F(0.7071067812 / C4), F(0.5555702330 / C5),
-F(0.7071067812 / C4), -F(0.9807852804 / C5),
-F(0.7071067812 / C4), F(0.1950903220 / C5),
F(0.7071067812 / C4), F(0.8314696123 / C5),
F(0.7071067812 / C4), -F(0.8314696123 / C5),
-F(0.7071067812 / C4), -F(0.1950903220 / C5),
-F(0.7071067812 / C4), F(0.9807852804 / C5),
F(0.7071067812 / C4), -F(0.5555702330 / C5),
F(0.3826834324 / C6), F(0.1950903220 / C7),
-F(0.9238795325 / C6), -F(0.5555702330 / C7),
F(0.9238795325 / C6), F(0.8314696123 / C7),
-F(0.3826834324 / C6), -F(0.9807852804 / C7),
-F(0.3826834324 / C6), F(0.9807852804 / C7),
F(0.9238795325 / C6), -F(0.8314696123 / C7),
-F(0.9238795325 / C6), F(0.5555702330 / C7),
F(0.3826834324 / C6), -F(0.1950903220 / C7),
#undef F
#undef C0
#undef C1
#undef C2
#undef C3
#undef C4
#undef C5
#undef C6
#undef C7
};
static const int32_t sbc_proto_4_40m0[] =
{
SS4(0x00000000), SS4(0xffa6982f), SS4(0xfba93848), SS4(0x0456c7b8),
SS4(0x005967d1), SS4(0xfffb9ac7), SS4(0xff589157), SS4(0xf9c2a8d8),
SS4(0x027c1434), SS4(0x0019118b), SS4(0xfff3c74c), SS4(0xff137330),
SS4(0xf81b8d70), SS4(0x00ec1b8b), SS4(0xfff0b71a), SS4(0xffe99b00),
SS4(0xfef84470), SS4(0xf6fb4370), SS4(0xffcdc351), SS4(0xffe01dc7)
};
static const int32_t sbc_proto_4_40m1[] =
{
SS4(0xffe090ce), SS4(0xff2c0475), SS4(0xf694f800), SS4(0xff2c0475),
SS4(0xffe090ce), SS4(0xffe01dc7), SS4(0xffcdc351), SS4(0xf6fb4370),
SS4(0xfef84470), SS4(0xffe99b00), SS4(0xfff0b71a), SS4(0x00ec1b8b),
SS4(0xf81b8d70), SS4(0xff137330), SS4(0xfff3c74c), SS4(0x0019118b),
SS4(0x027c1434), SS4(0xf9c2a8d8), SS4(0xff589157), SS4(0xfffb9ac7)
};
static const int32_t sbc_proto_8_80m0[] =
{
SS8(0x00000000), SS8(0xfe8d1970), SS8(0xee979f00), SS8(0x11686100),
SS8(0x0172e690), SS8(0xfff5bd1a), SS8(0xfdf1c8d4), SS8(0xeac182c0),
SS8(0x0d9daee0), SS8(0x00e530da), SS8(0xffe9811d), SS8(0xfd52986c),
SS8(0xe7054ca0), SS8(0x0a00d410), SS8(0x006c1de4), SS8(0xffdba705),
SS8(0xfcbc98e8), SS8(0xe3889d20), SS8(0x06af2308), SS8(0x000bb7db),
SS8(0xffca00ed), SS8(0xfc3fbb68), SS8(0xe071bc00), SS8(0x03bf7948),
SS8(0xffc4e05c), SS8(0xffb54b3b), SS8(0xfbedadc0), SS8(0xdde26200),
SS8(0x0142291c), SS8(0xff960e94), SS8(0xff9f3e17), SS8(0xfbd8f358),
SS8(0xdbf79400), SS8(0xff405e01), SS8(0xff7d4914), SS8(0xff8b1a31),
SS8(0xfc1417b8), SS8(0xdac7bb40), SS8(0xfdbb828c), SS8(0xff762170)
};
static const int32_t sbc_proto_8_80m1[] =
{
SS8(0xff7c272c), SS8(0xfcb02620), SS8(0xda612700), SS8(0xfcb02620),
SS8(0xff7c272c), SS8(0xff762170), SS8(0xfdbb828c), SS8(0xdac7bb40),
SS8(0xfc1417b8), SS8(0xff8b1a31), SS8(0xff7d4914), SS8(0xff405e01),
SS8(0xdbf79400), SS8(0xfbd8f358), SS8(0xff9f3e17), SS8(0xff960e94),
SS8(0x0142291c), SS8(0xdde26200), SS8(0xfbedadc0), SS8(0xffb54b3b),
SS8(0xffc4e05c), SS8(0x03bf7948), SS8(0xe071bc00), SS8(0xfc3fbb68),
SS8(0xffca00ed), SS8(0x000bb7db), SS8(0x06af2308), SS8(0xe3889d20),
SS8(0xfcbc98e8), SS8(0xffdba705), SS8(0x006c1de4), SS8(0x0a00d410),
SS8(0xe7054ca0), SS8(0xfd52986c), SS8(0xffe9811d), SS8(0x00e530da),
SS8(0x0d9daee0), SS8(0xeac182c0), SS8(0xfdf1c8d4), SS8(0xfff5bd1a)
};
static const int32_t synmatrix4[8][4] =
{
{ SN4(0x05a82798), SN4(0xfa57d868), SN4(0xfa57d868), SN4(0x05a82798) },
{ SN4(0x030fbc54), SN4(0xf89be510), SN4(0x07641af0), SN4(0xfcf043ac) },
{ SN4(0x00000000), SN4(0x00000000), SN4(0x00000000), SN4(0x00000000) },
{ SN4(0xfcf043ac), SN4(0x07641af0), SN4(0xf89be510), SN4(0x030fbc54) },
{ SN4(0xfa57d868), SN4(0x05a82798), SN4(0x05a82798), SN4(0xfa57d868) },
{ SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) },
{ SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000) },
{ SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) }
};
static const int32_t synmatrix8[16][8] =
{
{ SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798),
SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798) },
{ SN8(0x0471ced0), SN8(0xf8275a10), SN8(0x018f8b84), SN8(0x06a6d988),
SN8(0xf9592678), SN8(0xfe70747c), SN8(0x07d8a5f0), SN8(0xfb8e3130) },
{ SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac),
SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54) },
{ SN8(0x018f8b84), SN8(0xfb8e3130), SN8(0x06a6d988), SN8(0xf8275a10),
SN8(0x07d8a5f0), SN8(0xf9592678), SN8(0x0471ced0), SN8(0xfe70747c) },
{ SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000),
SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000) },
{ SN8(0xfe70747c), SN8(0x0471ced0), SN8(0xf9592678), SN8(0x07d8a5f0),
SN8(0xf8275a10), SN8(0x06a6d988), SN8(0xfb8e3130), SN8(0x018f8b84) },
{ SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54),
SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac) },
{ SN8(0xfb8e3130), SN8(0x07d8a5f0), SN8(0xfe70747c), SN8(0xf9592678),
SN8(0x06a6d988), SN8(0x018f8b84), SN8(0xf8275a10), SN8(0x0471ced0) },
{ SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868),
SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868) },
{ SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0),
SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) },
{ SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0),
SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) },
{ SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c),
SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) },
{ SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000),
SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000) },
{ SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c),
SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) },
{ SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0),
SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) },
{ SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0),
SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) }
};
struct sbc_encoder_state
{
int position;
/* Number of consecutive blocks handled by the encoder */
uint8_t increment;
int16_t SBC_ALIGNED X[2][SBC_X_BUFFER_SIZE];
/* Polyphase analysis filter for 4 subbands configuration,
* it handles "increment" blocks at once */
void (*sbc_analyze_4s)(struct sbc_encoder_state *state,
int16_t *x, int32_t *out, int out_stride);
/* Polyphase analysis filter for 8 subbands configuration,
* it handles "increment" blocks at once */
void (*sbc_analyze_8s)(struct sbc_encoder_state *state,
int16_t *x, int32_t *out, int out_stride);
/* Process input data (deinterleave, endian conversion, reordering),
* depending on the number of subbands and input data byte order */
int (*sbc_enc_process_input_4s_le)(int position,
const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
int nsamples, int nchannels);
int (*sbc_enc_process_input_4s_be)(int position,
const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
int nsamples, int nchannels);
int (*sbc_enc_process_input_8s_le)(int position,
const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
int nsamples, int nchannels);
int (*sbc_enc_process_input_8s_be)(int position,
const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
int nsamples, int nchannels);
/* Scale factors calculation */
void (*sbc_calc_scalefactors)(int32_t sb_sample_f[16][2][8],
uint32_t scale_factor[2][8],
int blocks, int channels, int subbands);
/* Scale factors calculation with joint stereo support */
int (*sbc_calc_scalefactors_j)(int32_t sb_sample_f[16][2][8],
uint32_t scale_factor[2][8],
int blocks, int subbands);
const char *implementation_info;
};
/* A2DP specification: Appendix B, page 69 */
static const int sbc_offset4[4][4] =
{
{ -1, 0, 0, 0 },
{ -2, 0, 0, 1 },
{ -2, 0, 0, 1 },
{ -2, 0, 0, 1 }
};
/* A2DP specification: Appendix B, page 69 */
static const int sbc_offset8[4][8] =
{
{ -2, 0, 0, 0, 0, 0, 0, 1 },
{ -3, 0, 0, 0, 0, 0, 1, 2 },
{ -4, 0, 0, 0, 0, 0, 1, 2 },
{ -4, 0, 0, 0, 0, 0, 1, 2 }
};
struct sbc_struct
{
unsigned long flags;
uint8_t frequency;
uint8_t blocks;
uint8_t subbands;
uint8_t mode;
uint8_t allocation;
uint8_t bitpool;
uint8_t endian;
void *priv;
void *priv_alloc_base;
};
typedef struct sbc_struct sbc_t;
int sbc_init(sbc_t *sbc, unsigned long flags);
int sbc_reinit(sbc_t *sbc, unsigned long flags);
int sbc_init_msbc(sbc_t *sbc, unsigned long flags);
int sbc_init_a2dp(sbc_t *sbc, unsigned long flags,
const void *conf, size_t conf_len);
int sbc_reinit_a2dp(sbc_t *sbc, unsigned long flags,
const void *conf, size_t conf_len);
ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len);
/* Decodes ONE input block into ONE output block */
ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len,
void *output, size_t output_len, size_t *written);
/* Encodes ONE input block into ONE output block */
ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
void *output, size_t output_len, ssize_t *written);
/* Returns the output block size in bytes */
size_t sbc_get_frame_length(sbc_t *sbc);
/* Returns the time one input/output block takes to play in msec*/
unsigned sbc_get_frame_duration(sbc_t *sbc);
/* Returns the input block size in bytes */
size_t sbc_get_codesize(sbc_t *sbc);
const char *sbc_get_implementation_info(sbc_t *sbc);
void sbc_finish(sbc_t *sbc);
void pcm_to_sbc(char *filename, char *output, int msbc);
void sbc_to_pcm(char *filename, char *output, int msbc);
void sbc_init_primitives(struct sbc_encoder_state *state);
void sbc_decode_init(sbc_t *sbc, int msbc);
ssize_t sbc_decoder_decode(sbc_t *sbc, const void *input, size_t input_len,
void *output, size_t output_len, size_t *written);
void sbc_decoder_uninit(sbc_t *sbc);
void sbc_encode_init(sbc_t *sbc, int msbc);
ssize_t sbc_encoder_encode(sbc_t *sbc, const void *input, size_t input_len,
void *output, size_t output_len, ssize_t *written);
void sbc_encoder_uninit(sbc_t *sbc);
#ifdef __cplusplus
}
#endif
#endif /* __SBC_H */
@@ -0,0 +1,400 @@
// ****************************************************************************
//
// vole_common.c
//! @file
//!
//! @brief This file provides the shared functions for the Vole service.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include "vole_common.h"
#include "wsf_assert.h"
#include "wsf_trace.h"
#include "bstream.h"
#include "att_api.h"
#include "am_util_debug.h"
#include "crc32.h"
#include "am_util.h"
void
VoleResetPkt(volePacket_t *pkt)
{
// pkt->offset = 0;
// pkt->header.pktType = VOLE_PKT_TYPE_UNKNOWN;
// pkt->len = 0;
}
eVoleStatus_t
VoleReceivePkt(voleCb_t *voleCb, volePacket_t *pkt, uint16_t len, uint8_t *pValue)
{
uint8_t dataIdx = 0;
uint32_t calDataCrc = 0;
uint16_t header = 0;
if (pkt->offset == 0 && len < VOLE_PREFIX_SIZE_IN_PKT)
{
APP_TRACE_INFO0("Invalid packet!!!");
VoleSendReply(voleCb, VOLE_STATUS_INVALID_PKT_LENGTH, NULL, 0);
return VOLE_STATUS_INVALID_PKT_LENGTH;
}
// new packet
if (pkt->offset == 0)
{
BYTES_TO_UINT16(pkt->len, pValue);
BYTES_TO_UINT16(header, &pValue[2]);
pkt->header.pktType = (header & PACKET_TYPE_BIT_MASK) >> PACKET_TYPE_BIT_OFFSET;
pkt->header.pktSn = (header & PACKET_SN_BIT_MASK) >> PACKET_SN_BIT_OFFSET;
pkt->header.encrypted = (header & PACKET_ENCRYPTION_BIT_MASK) >> PACKET_ENCRYPTION_BIT_OFFSET;
pkt->header.ackEnabled = (header & PACKET_ACK_BIT_MASK) >> PACKET_ACK_BIT_OFFSET;
dataIdx = VOLE_PREFIX_SIZE_IN_PKT;
if (pkt->header.pktType == VOLE_PKT_TYPE_DATA)
{
voleCb->rxState = VOLE_STATE_GETTING_DATA;
}
#ifdef VOLE_DEBUG_ON
APP_TRACE_INFO1("pkt len = 0x%x", pkt->len);
APP_TRACE_INFO1("pkt header = 0x%x", header);
#endif
APP_TRACE_INFO2("type = %d, sn = %d", pkt->header.pktType, pkt->header.pktSn);
APP_TRACE_INFO2("enc = %d, ackEnabled = %d", pkt->header.encrypted, pkt->header.ackEnabled);
}
// make sure we have enough space for new data
if (pkt->offset + len - dataIdx > VOLE_PACKET_SIZE)
{
APP_TRACE_INFO0("not enough buffer size!!!");
if (pkt->header.pktType == VOLE_PKT_TYPE_DATA)
{
voleCb->rxState = VOLE_STATE_RX_IDLE;
}
// reset pkt
VoleResetPkt(pkt);
VoleSendReply(voleCb, VOLE_STATUS_INSUFFICIENT_BUFFER, NULL, 0);
return VOLE_STATUS_INSUFFICIENT_BUFFER;
}
// copy new data into buffer and also save crc into it if it's the last frame in a packet
// 4 bytes crc is included in pkt length
memcpy(pkt->data + pkt->offset, pValue + dataIdx, len - dataIdx);
pkt->offset += (len - dataIdx);
// whole packet received
if (pkt->offset >= pkt->len)
{
uint32_t peerCrc = 0;
//
// check CRC
//
BYTES_TO_UINT32(peerCrc, pkt->data + pkt->len - VOLE_CRC_SIZE_IN_PKT);
calDataCrc = CalcCrc32(0xFFFFFFFFU, pkt->len - VOLE_CRC_SIZE_IN_PKT, pkt->data);
#ifdef VOLE_DEBUG_ON
APP_TRACE_INFO1("calDataCrc = 0x%x ", calDataCrc);
APP_TRACE_INFO1("peerCrc = 0x%x", peerCrc);
APP_TRACE_INFO1("len: %d", pkt->len);
#endif
if (peerCrc != calDataCrc)
{
APP_TRACE_INFO0("crc error\n");
if (pkt->header.pktType == VOLE_PKT_TYPE_DATA)
{
voleCb->rxState = VOLE_STATE_RX_IDLE;
}
// reset pkt
VoleResetPkt(pkt);
VoleSendReply(voleCb, VOLE_STATUS_CRC_ERROR, NULL, 0);
return VOLE_STATUS_CRC_ERROR;
}
return VOLE_STATUS_RECEIVE_DONE;
}
return VOLE_STATUS_RECEIVE_CONTINUE;
}
//*****************************************************************************
//
// Vole packet handler
//
//*****************************************************************************
void
VolePacketHandler(voleCb_t *voleCb, eVolePktType_t type, uint16_t len, uint8_t *buf)
{
// APP_TRACE_INFO2("received packet type = %d, len = %d\n", type, len);
switch(type)
{
case VOLE_PKT_TYPE_DATA:
//
// data package recevied
//
// record packet serial number
voleCb->lastRxPktSn = voleCb->rxPkt.header.pktSn;
VoleSendReply(voleCb, VOLE_STATUS_SUCCESS, NULL, 0);
if (voleCb->recvCback)
{
voleCb->recvCback(buf, len);
}
voleCb->rxState = VOLE_STATE_RX_IDLE;
VoleResetPkt(&voleCb->rxPkt);
break;
case VOLE_PKT_TYPE_ACK:
{
eVoleStatus_t status = (eVoleStatus_t)buf[0];
// stop tx timeout timer
WsfTimerStop(&voleCb->timeoutTimer);
if (voleCb->txState != VOLE_STATE_TX_IDLE)
{
// APP_TRACE_INFO1("set txState back to idle, state = %d\n", voleCb->txState);
voleCb->txState = VOLE_STATE_TX_IDLE;
}
if (status == VOLE_STATUS_CRC_ERROR || status == VOLE_STATUS_RESEND_REPLY)
{
// resend packet
VoleSendPacketHandler(voleCb);
}
else
{
// increase packet serial number if send successfully
if (status == VOLE_STATUS_SUCCESS)
{
voleCb->txPktSn++;
if (voleCb->txPktSn == 16)
{
voleCb->txPktSn = 0;
}
}
// packet transfer successful or other error
// reset packet
VoleResetPkt(&voleCb->txPkt);
// notify application layer
if (voleCb->transCback)
{
voleCb->transCback(status);
}
}
VoleResetPkt(&voleCb->ackPkt);
}
break;
case VOLE_PKT_TYPE_CONTROL:
{
eVoleControl_t control = (eVoleControl_t)buf[0];
uint8_t resendPktSn = buf[1];
if (control == VOLE_CONTROL_RESEND_REQ)
{
APP_TRACE_INFO2("resendPktSn = %d, lastRxPktSn = %d", resendPktSn, voleCb->lastRxPktSn);
voleCb->rxState = VOLE_STATE_RX_IDLE;
VoleResetPkt(&voleCb->rxPkt);
if (resendPktSn > voleCb->lastRxPktSn)
{
VoleSendReply(voleCb, VOLE_STATUS_RESEND_REPLY, NULL, 0);
}
else if (resendPktSn == voleCb->lastRxPktSn)
{
VoleSendReply(voleCb, VOLE_STATUS_SUCCESS, NULL, 0);
}
else
{
APP_TRACE_WARN2("resendPktSn = %d, lastRxPktSn = %d", resendPktSn, voleCb->lastRxPktSn);
}
}
else
{
APP_TRACE_WARN1("unexpected contrl = %d\n", control);
}
VoleResetPkt(&voleCb->ackPkt);
}
break;
default:
break;
}
}
void
VoleBuildPkt(voleCb_t *voleCb, eVolePktType_t type, bool_t encrypted, bool_t enableACK, uint8_t *buf, uint16_t len)
{
uint16_t header = 0;
uint32_t calDataCrc;
volePacket_t *pkt;
if (type == VOLE_PKT_TYPE_DATA)
{
pkt = &voleCb->txPkt;
header = voleCb->txPktSn << PACKET_SN_BIT_OFFSET;
}
else
{
pkt = &voleCb->ackPkt;
}
//
// Prepare header frame to be sent first
//
// length
pkt->len = len + VOLE_PREFIX_SIZE_IN_PKT + VOLE_CRC_SIZE_IN_PKT;
pkt->data[0] = (len + VOLE_CRC_SIZE_IN_PKT) & 0xff;
pkt->data[1] = ((len + VOLE_CRC_SIZE_IN_PKT) >> 8) & 0xff;
// header
header = header | (type << PACKET_TYPE_BIT_OFFSET);
if (encrypted)
{
header = header | (1 << PACKET_ENCRYPTION_BIT_OFFSET);
}
if (enableACK)
{
header = header | (1 << PACKET_ACK_BIT_OFFSET);
}
pkt->data[2] = (header & 0xff);
pkt->data[3] = (header >> 8);
// copy data
memcpy(&(pkt->data[VOLE_PREFIX_SIZE_IN_PKT]), buf, len);
calDataCrc = CalcCrc32(0xFFFFFFFFU, len, buf);
// add checksum
pkt->data[VOLE_PREFIX_SIZE_IN_PKT + len] = (calDataCrc & 0xff);
pkt->data[VOLE_PREFIX_SIZE_IN_PKT + len + 1] = ((calDataCrc >> 8) & 0xff);
pkt->data[VOLE_PREFIX_SIZE_IN_PKT + len + 2] = ((calDataCrc >> 16) & 0xff);
pkt->data[VOLE_PREFIX_SIZE_IN_PKT + len + 3] = ((calDataCrc >> 24) & 0xff);
}
//*****************************************************************************
//
// Send Reply to Sender
//
//*****************************************************************************
void
VoleSendReply(voleCb_t *voleCb, eVoleStatus_t status, uint8_t *data, uint16_t len)
{
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN] = {0};
eVoleStatus_t st;
WSF_ASSERT(len < ATT_DEFAULT_PAYLOAD_LEN);
buf[0] = status;
if (len > 0)
{
memcpy(buf + 1, data, len);
}
st = voleCb->ack_sender_func(VOLE_PKT_TYPE_ACK, false, false, buf, len + 1);
if (st != VOLE_STATUS_SUCCESS)
{
APP_TRACE_WARN1("VoleSendReply status = %d\n", status);
}
}
//*****************************************************************************
//
// Send control message to Receiver
//
//*****************************************************************************
void
VoleSendControl(voleCb_t *voleCb, eVoleControl_t control, uint8_t *data, uint16_t len)
{
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN] = {0};
eVoleStatus_t st;
WSF_ASSERT(len < ATT_DEFAULT_PAYLOAD_LEN);
buf[0] = control;
if (len > 0)
{
memcpy(buf + 1, data, len);
}
st = voleCb->ack_sender_func(VOLE_PKT_TYPE_CONTROL, false, false, buf, len + 1);
if (st != VOLE_STATUS_SUCCESS)
{
APP_TRACE_WARN1("VoleSendControl status = %d\n", st);
}
}
void
VoleSendPacketHandler(voleCb_t *voleCb)
{
uint16_t transferSize = 0;
uint16_t remainingBytes = 0;
volePacket_t *txPkt = &voleCb->txPkt;
if ( voleCb->txState == VOLE_STATE_TX_IDLE )
{
txPkt->offset = 0;
voleCb->txState = VOLE_STATE_SENDING;
}
if ( txPkt->offset >= txPkt->len )
{
// done sent packet
voleCb->txState = VOLE_STATE_WAITING_ACK;
// start tx timeout timer
WsfTimerStartMs(&voleCb->timeoutTimer, voleCb->txTimeoutMs);
}
else
{
remainingBytes = txPkt->len - txPkt->offset;
transferSize = ((voleCb->attMtuSize - 3) > remainingBytes)
? remainingBytes
: (voleCb->attMtuSize - 3);
// send packet
APP_TRACE_INFO1("VoleSendPacketHandler, send len:%d", transferSize);
voleCb->data_sender_func(&txPkt->data[txPkt->offset], transferSize);
txPkt->offset += transferSize;
}
}
@@ -0,0 +1,247 @@
// ****************************************************************************
//
// vole_common.h
//! @file
//!
//! @brief This file provides the shared functions for the Vole service.
//!
//! @{
//
// ****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef VOLE_COMMON_H
#define VOLE_COMMON_H
#include "wsf_types.h"
#include "wsf_timer.h"
#ifdef __cplusplus
extern "C"
{
#endif
//*****************************************************************************
//
// Macro definitions
//
//*****************************************************************************
#define VOLE_MAX_PAYLOAD_SIZE 10//2048//512
#define VOLE_PACKET_SIZE (VOLE_MAX_PAYLOAD_SIZE + VOLE_PREFIX_SIZE_IN_PKT + VOLE_CRC_SIZE_IN_PKT) // Bytes
#define VOLE_LENGTH_SIZE_IN_PKT 2
#define VOLE_HEADER_SIZE_IN_PKT 2
#define VOLE_CRC_SIZE_IN_PKT 4
#define VOLE_PREFIX_SIZE_IN_PKT VOLE_LENGTH_SIZE_IN_PKT + VOLE_HEADER_SIZE_IN_PKT
#define PACKET_TYPE_BIT_OFFSET 12
#define PACKET_TYPE_BIT_MASK (0xf << PACKET_TYPE_BIT_OFFSET)
#define PACKET_SN_BIT_OFFSET 8
#define PACKET_SN_BIT_MASK (0xf << PACKET_SN_BIT_OFFSET)
#define PACKET_ENCRYPTION_BIT_OFFSET 7
#define PACKET_ENCRYPTION_BIT_MASK (0x1 << PACKET_ENCRYPTION_BIT_OFFSET)
#define PACKET_ACK_BIT_OFFSET 6
#define PACKET_ACK_BIT_MASK (0x1 << PACKET_ACK_BIT_OFFSET)
#define TX_TIMEOUT_DEFAULT 1000
#define MANUFACT_ADV 0x1234
#define AUD_HEADER_LEN 44
struct au_header
{
uint32_t magic; /* '.snd' */
uint32_t hdr_size; /* size of header (min 24) */
uint32_t data_size; /* size of data */
uint32_t encoding; /* see to AU_FMT_XXXX */
uint32_t sample_rate; /* sample rate */
uint32_t channels; /* number of channels (voices) */
};
typedef enum codecType
{
MSBC_CODEC_IN_USE = 0,
OPUS_CODEC_IN_USE = 1,
VOLE_CODEC_TYPE_INVALID = 0xFF
}eVoleCodecType;
//
// Vole states
//
typedef enum eVoleState
{
VOLE_STATE_INIT,
VOLE_STATE_TX_IDLE,
VOLE_STATE_RX_IDLE,
VOLE_STATE_SENDING,
VOLE_STATE_GETTING_DATA,
VOLE_STATE_WAITING_ACK,
VOLE_STATE_MAX
}eVoleState_t;
//
// Vole packet type
//
typedef enum eVolePktType
{
VOLE_PKT_TYPE_UNKNOWN,
VOLE_PKT_TYPE_DATA,
VOLE_PKT_TYPE_ACK,
VOLE_PKT_TYPE_CONTROL,
VOLE_PKT_TYPE_MAX
}eVolePktType_t;
typedef enum eVoleControl
{
VOLE_CONTROL_RESEND_REQ,
VOLE_CONTROL_MAX
}eVoleControl_t;
//
// Vole status
//
typedef enum eVoleStatus
{
VOLE_STATUS_SUCCESS,
VOLE_STATUS_CRC_ERROR,
VOLE_STATUS_INVALID_METADATA_INFO,
VOLE_STATUS_INVALID_PKT_LENGTH,
VOLE_STATUS_INSUFFICIENT_BUFFER,
VOLE_STATUS_UNKNOWN_ERROR,
VOLE_STATUS_BUSY,
VOLE_STATUS_TX_NOT_READY, // no connection or tx busy
VOLE_STATUS_RESEND_REPLY,
VOLE_STATUS_RECEIVE_CONTINUE,
VOLE_STATUS_RECEIVE_DONE,
VOLE_STATUS_MAX
}eVoleStatus_t;
//
// packet prefix structure
//
typedef struct
{
uint8_t pktType : 4;
uint8_t pktSn : 4;
uint8_t encrypted : 1;
uint32_t ackEnabled : 1;
uint32_t reserved : 6; // Reserved for future usage
}
volePktHeader_t;
//
// packet
//
typedef struct
{
uint32_t offset;
uint32_t len; // data plus checksum
volePktHeader_t header;
uint8_t *data;
}
volePacket_t;
/*! Application data reception callback */
typedef void (*voleRecvCback_t)(uint8_t *buf, uint16_t len);
/*! Application data transmission result callback */
typedef void (*voleTransCback_t)(eVoleStatus_t status);
typedef void (*vole_reply_func_t)(eVoleStatus_t status, uint8_t *data, uint16_t len);
typedef void (*vole_packet_handler_func_t)(eVolePktType_t type, uint16_t len, uint8_t *buf);
typedef eVoleStatus_t (*vole_ack_sender_func_t)(eVolePktType_t type, bool_t encrypted, bool_t enableACK, uint8_t *buf, uint16_t len);
typedef void (*vole_data_sender_func_t)(uint8_t *buf, uint16_t len);
typedef struct
{
eVoleState_t txState;
eVoleState_t rxState;
volePacket_t rxPkt;
volePacket_t txPkt;
volePacket_t ackPkt;
uint8_t txPktSn; // data packet serial number for Tx
uint8_t lastRxPktSn; // last received data packet serial number
uint16_t attMtuSize;
// int total_tx_len;
wsfTimer_t timeoutTimer; // timeout timer after DTP update done
wsfTimerTicks_t txTimeoutMs;
voleRecvCback_t recvCback; // application callback for data reception
voleTransCback_t transCback; // application callback for tx complete status
vole_data_sender_func_t data_sender_func;
vole_ack_sender_func_t ack_sender_func;
}
voleCb_t;
//*****************************************************************************
//
// function definitions
//
//*****************************************************************************
void
VoleBuildPkt(voleCb_t *voleCb, eVolePktType_t type, bool_t encrypted, bool_t enableACK, uint8_t *buf, uint16_t len);
eVoleStatus_t
VoleReceivePkt(voleCb_t *voleCb, volePacket_t *pkt, uint16_t len, uint8_t *pValue);
void
VoleSendReply(voleCb_t *voleCb, eVoleStatus_t status, uint8_t *data, uint16_t len);
void
VoleSendControl(voleCb_t *voleCb, eVoleControl_t control, uint8_t *data, uint16_t len);
void
VoleSendPacketHandler(voleCb_t *voleCb);
void
VolePacketHandler(voleCb_t *voleCb, eVolePktType_t type, uint16_t len, uint8_t *buf);
void
VoleResetPkt(volePacket_t *pkt);
#ifdef __cplusplus
}
#endif
#endif // VOLE_COMMON_H
@@ -0,0 +1,253 @@
//*****************************************************************************
//
//! @file svc_amdtp.c
//!
//! @brief AM data transfer protocol service implementation
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include "wsf_types.h"
#include "att_api.h"
#include "wsf_trace.h"
#include "bstream.h"
#include "svc_ch.h"
#include "svc_amdtp.h"
#include "svc_cfg.h"
//*****************************************************************************
//
// Macro definitions
//
//*****************************************************************************
//#define SOME_MACRO 42 //!< This is the answer
//*****************************************************************************
//
// Global Variables
//
//*****************************************************************************
//uint32_t g_ui32Stuff;
/**************************************************************************************************
Static Variables
**************************************************************************************************/
/* UUIDs */
static const uint8_t svcRxUuid[] = {ATT_UUID_AMDTP_RX};
static const uint8_t svcTxUuid[] = {ATT_UUID_AMDTP_TX};
static const uint8_t svcAckUuid[] = {ATT_UUID_AMDTP_ACK};
/**************************************************************************************************
Service variables
**************************************************************************************************/
/* AMDTP service declaration */
static const uint8_t amdtpSvc[] = {ATT_UUID_AMDTP_SERVICE};
static const uint16_t amdtpLenSvc = sizeof(amdtpSvc);
/* AMDTP RX characteristic */
static const uint8_t amdtpRxCh[] = {ATT_PROP_WRITE_NO_RSP, UINT16_TO_BYTES(AMDTPS_RX_HDL), ATT_UUID_AMDTP_RX};
static const uint16_t amdtpLenRxCh = sizeof(amdtpRxCh);
/* AMDTP TX characteristic */
static const uint8_t amdtpTxCh[] = {ATT_PROP_NOTIFY, UINT16_TO_BYTES(AMDTPS_TX_HDL), ATT_UUID_AMDTP_TX};
static const uint16_t amdtpLenTxCh = sizeof(amdtpTxCh);
/* AMDTP RX ack characteristic */
static const uint8_t amdtpAckCh[] = {(ATT_PROP_WRITE_NO_RSP | ATT_PROP_NOTIFY), UINT16_TO_BYTES(AMDTPS_ACK_HDL), ATT_UUID_AMDTP_ACK};
static const uint16_t amdtpLenAckCh = sizeof(amdtpAckCh);
/* AMDTP RX data */
/* Note these are dummy values */
static const uint8_t amdtpRx[] = {0};
static const uint16_t amdtpLenRx = sizeof(amdtpRx);
/* AMDTP TX data */
/* Note these are dummy values */
static const uint8_t amdtpTx[] = {0};
static const uint16_t amdtpLenTx = sizeof(amdtpTx);
/* Proprietary data client characteristic configuration */
static uint8_t amdtpTxChCcc[] = {UINT16_TO_BYTES(0x0000)};
static const uint16_t amdtpLenTxChCcc = sizeof(amdtpTxChCcc);
/* AMDTP RX ack data */
/* Note these are dummy values */
static const uint8_t amdtpAck[] = {0};
static const uint16_t amdtpLenAck = sizeof(amdtpAck);
/* Proprietary data client characteristic configuration */
static uint8_t amdtpAckChCcc[] = {UINT16_TO_BYTES(0x0000)};
static const uint16_t amdtpLenAckChCcc = sizeof(amdtpAckChCcc);
/* Attribute list for AMDTP group */
static const attsAttr_t amdtpList[] =
{
{
attPrimSvcUuid,
(uint8_t *) amdtpSvc,
(uint16_t *) &amdtpLenSvc,
sizeof(amdtpSvc),
0,
ATTS_PERMIT_READ
},
{
attChUuid,
(uint8_t *) amdtpRxCh,
(uint16_t *) &amdtpLenRxCh,
sizeof(amdtpRxCh),
0,
ATTS_PERMIT_READ
},
{
svcRxUuid,
(uint8_t *) amdtpRx,
(uint16_t *) &amdtpLenRx,
ATT_VALUE_MAX_LEN,
(ATTS_SET_UUID_128 | ATTS_SET_VARIABLE_LEN | ATTS_SET_WRITE_CBACK),
ATTS_PERMIT_WRITE
},
{
attChUuid,
(uint8_t *) amdtpTxCh,
(uint16_t *) &amdtpLenTxCh,
sizeof(amdtpTxCh),
0,
ATTS_PERMIT_READ
},
{
svcTxUuid,
(uint8_t *) amdtpTx,
(uint16_t *) &amdtpLenTx,
sizeof(amdtpTx), //ATT_VALUE_MAX_LEN,
0, //(ATTS_SET_UUID_128 | ATTS_SET_VARIABLE_LEN),
0, //ATTS_PERMIT_READ
},
{
attCliChCfgUuid,
(uint8_t *) amdtpTxChCcc,
(uint16_t *) &amdtpLenTxChCcc,
sizeof(amdtpTxChCcc),
ATTS_SET_CCC,
(ATTS_PERMIT_READ | ATTS_PERMIT_WRITE)
},
{
attChUuid,
(uint8_t *) amdtpAckCh,
(uint16_t *) &amdtpLenAckCh,
sizeof(amdtpAckCh),
0,
ATTS_PERMIT_READ
},
{
svcAckUuid,
(uint8_t *) amdtpAck,
(uint16_t *) &amdtpLenAck,
ATT_VALUE_MAX_LEN,
(ATTS_SET_UUID_128 | ATTS_SET_VARIABLE_LEN | ATTS_SET_WRITE_CBACK),
ATTS_PERMIT_WRITE,
},
{
attCliChCfgUuid,
(uint8_t *) amdtpAckChCcc,
(uint16_t *) &amdtpLenAckChCcc,
sizeof(amdtpAckChCcc),
ATTS_SET_CCC,
(ATTS_PERMIT_READ | ATTS_PERMIT_WRITE)
}
};
/* AMDTP group structure */
static attsGroup_t svcAmdtpGroup =
{
NULL,
(attsAttr_t *) amdtpList,
NULL,
NULL,
AMDTPS_START_HDL,
AMDTPS_END_HDL
};
/*************************************************************************************************/
/*!
* \fn SvcAmdtpsAddGroup
*
* \brief Add the services to the attribute server.
*
* \return None.
*/
/*************************************************************************************************/
void SvcAmdtpsAddGroup(void)
{
AttsAddGroup(&svcAmdtpGroup);
}
/*************************************************************************************************/
/*!
* \fn SvcAmdtpRemoveGroup
*
* \brief Remove the services from the attribute server.
*
* \return None.
*/
/*************************************************************************************************/
void SvcAmdtpsRemoveGroup(void)
{
AttsRemoveGroup(AMDTPS_START_HDL);
}
/*************************************************************************************************/
/*!
* \fn SvcAmdtpsCbackRegister
*
* \brief Register callbacks for the service.
*
* \param readCback Read callback function.
* \param writeCback Write callback function.
*
* \return None.
*/
/*************************************************************************************************/
void SvcAmdtpsCbackRegister(attsReadCback_t readCback, attsWriteCback_t writeCback)
{
svcAmdtpGroup.readCback = readCback;
svcAmdtpGroup.writeCback = writeCback;
}
@@ -0,0 +1,131 @@
//*****************************************************************************
//
//! @file svc_amdtps.h
//!
//! @brief AmbiqMicro Data Transfer Protocol service definition
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef SVC_AMDTPS_H
#define SVC_AMDTPS_H
//
// Put additional includes here if necessary.
//
#ifdef __cplusplus
extern "C"
{
#endif
//*****************************************************************************
//
// Macro definitions
//
//*****************************************************************************
/*! Base UUID: 00002760-08C2-11E1-9073-0E8AC72EXXXX */
#define ATT_UUID_AMBIQ_BASE 0x2E, 0xC7, 0x8A, 0x0E, 0x73, 0x90, \
0xE1, 0x11, 0xC2, 0x08, 0x60, 0x27, 0x00, 0x00
/*! Macro for building Ambiq UUIDs */
#define ATT_UUID_AMBIQ_BUILD(part) UINT16_TO_BYTES(part), ATT_UUID_AMBIQ_BASE
/*! Partial amdtp service UUIDs */
#define ATT_UUID_AMDTP_SERVICE_PART 0x1011
/*! Partial amdtp rx characteristic UUIDs */
#define ATT_UUID_AMDTP_RX_PART 0x0011
/*! Partial amdtp tx characteristic UUIDs */
#define ATT_UUID_AMDTP_TX_PART 0x0012
/*! Partial amdtp ack characteristic UUIDs */
#define ATT_UUID_AMDTP_ACK_PART 0x0013
/* Amdtp services */
#define ATT_UUID_AMDTP_SERVICE ATT_UUID_AMBIQ_BUILD(ATT_UUID_AMDTP_SERVICE_PART)
/* Amdtp characteristics */
#define ATT_UUID_AMDTP_RX ATT_UUID_AMBIQ_BUILD(ATT_UUID_AMDTP_RX_PART)
#define ATT_UUID_AMDTP_TX ATT_UUID_AMBIQ_BUILD(ATT_UUID_AMDTP_TX_PART)
#define ATT_UUID_AMDTP_ACK ATT_UUID_AMBIQ_BUILD(ATT_UUID_AMDTP_ACK_PART)
// AM DTP Service
#define AMDTPS_START_HDL 0x0800//0x300
#define AMDTPS_END_HDL (AMDTPS_MAX_HDL - 1)
/* AMDTP Service Handles */
enum
{
AMDTP_SVC_HDL = AMDTPS_START_HDL, /* AMDTP service declaration */
AMDTPS_RX_CH_HDL, /* AMDTP write command characteristic */
AMDTPS_RX_HDL, /* AMDTP write command data */
AMDTPS_TX_CH_HDL, /* AMDTP notify characteristic */
AMDTPS_TX_HDL, /* AMDTP notify data */
AMDTPS_TX_CH_CCC_HDL, /* AMDTP notify client characteristic configuration */
AMDTPS_ACK_CH_HDL, /* AMDTP rx ack characteristic */
AMDTPS_ACK_HDL, /* AMDTP rx ack data */
AMDTPS_ACK_CH_CCC_HDL, /* AMDTP rx ack client characteristic configuration */
AMDTPS_MAX_HDL
};
//*****************************************************************************
//
// External variable definitions
//
//*****************************************************************************
//extern uint32_t g_ui32Stuff;
//*****************************************************************************
//
// Function definitions.
//
//*****************************************************************************
void SvcAmdtpsAddGroup(void);
void SvcAmdtpsRemoveGroup(void);
void SvcAmdtpsCbackRegister(attsReadCback_t readCback, attsWriteCback_t writeCback);
#ifdef __cplusplus
}
#endif
#endif // SVC_AMDTPS_H
@@ -0,0 +1,215 @@
//*****************************************************************************
//
//! @file svc_amotas.c
//!
//! @brief AM OTA service implementation
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include "wsf_types.h"
#include "att_api.h"
#include "wsf_trace.h"
#include "bstream.h"
#include "svc_ch.h"
#include "svc_amotas.h"
#include "svc_cfg.h"
//*****************************************************************************
//
// Macro definitions
//
//*****************************************************************************
//#define SOME_MACRO 42 //!< This is the answer
//*****************************************************************************
//
// Global Variables
//
//*****************************************************************************
//uint32_t g_ui32Stuff;
/**************************************************************************************************
Static Variables
**************************************************************************************************/
/* UUIDs */
static const uint8_t svcRxUuid[] = {ATT_UUID_AMOTA_RX};
static const uint8_t svcTxUuid[] = {ATT_UUID_AMOTA_TX};
/**************************************************************************************************
Service variables
**************************************************************************************************/
/* AMOTA service declaration */
static const uint8_t amotaSvc[] = {ATT_UUID_AMOTA_SERVICE};
static const uint16_t amotaLenSvc = sizeof(amotaSvc);
/* AMOTA RX characteristic */
static const uint8_t amotaRxCh[] = {ATT_PROP_WRITE_NO_RSP, UINT16_TO_BYTES(AMOTAS_RX_HDL), ATT_UUID_AMOTA_RX};
static const uint16_t amotaLenRxCh = sizeof(amotaRxCh);
/* AMOTA TX characteristic */
static const uint8_t amotaTxCh[] = {ATT_PROP_NOTIFY, UINT16_TO_BYTES(AMOTAS_TX_HDL), ATT_UUID_AMOTA_TX};
static const uint16_t amotaLenTxCh = sizeof(amotaTxCh);
/* AMOTA RX data */
/* Note these are dummy values */
static const uint8_t amotaRx[] = {0};
static const uint16_t amotaLenRx = sizeof(amotaRx);
/* AMOTA TX data */
/* Note these are dummy values */
static const uint8_t amotaTx[] = {0};
static const uint16_t amotaLenTx = sizeof(amotaTx);
/* Proprietary data client characteristic configuration */
static uint8_t amotaTxChCcc[] = {UINT16_TO_BYTES(0x0000)};
static const uint16_t amotaLenTxChCcc = sizeof(amotaTxChCcc);
/* Attribute list for AMOTA group */
static const attsAttr_t amotaList[] =
{
{
attPrimSvcUuid,
(uint8_t *) amotaSvc,
(uint16_t *) &amotaLenSvc,
sizeof(amotaSvc),
0,
ATTS_PERMIT_READ
},
{
attChUuid,
(uint8_t *) amotaRxCh,
(uint16_t *) &amotaLenRxCh,
sizeof(amotaRxCh),
0,
ATTS_PERMIT_READ
},
{
svcRxUuid,
(uint8_t *) amotaRx,
(uint16_t *) &amotaLenRx,
ATT_VALUE_MAX_LEN,
(ATTS_SET_UUID_128 | ATTS_SET_VARIABLE_LEN | ATTS_SET_WRITE_CBACK),
ATTS_PERMIT_WRITE
},
{
attChUuid,
(uint8_t *) amotaTxCh,
(uint16_t *) &amotaLenTxCh,
sizeof(amotaTxCh),
0,
ATTS_PERMIT_READ
},
{
svcTxUuid,
(uint8_t *) amotaTx,
(uint16_t *) &amotaLenTx,
ATT_VALUE_MAX_LEN,
(ATTS_SET_UUID_128 | ATTS_SET_VARIABLE_LEN),
ATTS_PERMIT_READ
},
{
attCliChCfgUuid,
(uint8_t *) amotaTxChCcc,
(uint16_t *) &amotaLenTxChCcc,
sizeof(amotaTxChCcc),
ATTS_SET_CCC,
(ATTS_PERMIT_READ | ATTS_PERMIT_WRITE)
}
};
/* AMOTA group structure */
static attsGroup_t svcAmotaGroup =
{
NULL,
(attsAttr_t *) amotaList,
NULL,
NULL,
AMOTAS_START_HDL,
AMOTAS_END_HDL
};
/*************************************************************************************************/
/*!
* \fn SvcAmotasAddGroup
*
* \brief Add the services to the attribute server.
*
* \return None.
*/
/*************************************************************************************************/
void SvcAmotasAddGroup(void)
{
AttsAddGroup(&svcAmotaGroup);
}
/*************************************************************************************************/
/*!
* \fn SvcAmotaRemoveGroup
*
* \brief Remove the services from the attribute server.
*
* \return None.
*/
/*************************************************************************************************/
void SvcAmotasRemoveGroup(void)
{
AttsRemoveGroup(AMOTAS_START_HDL);
}
/*************************************************************************************************/
/*!
* \fn SvcAmotasCbackRegister
*
* \brief Register callbacks for the service.
*
* \param readCback Read callback function.
* \param writeCback Write callback function.
*
* \return None.
*/
/*************************************************************************************************/
void SvcAmotasCbackRegister(attsReadCback_t readCback, attsWriteCback_t writeCback)
{
svcAmotaGroup.readCback = readCback;
svcAmotaGroup.writeCback = writeCback;
}
@@ -0,0 +1,124 @@
//*****************************************************************************
//
//! @file svc_amotas.h
//!
//! @brief AmbiqMicro OTA service definition
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2020, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.4.2 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef SVC_AMOTAS_H
#define SVC_AMOTAS_H
//
// Put additional includes here if necessary.
//
#ifdef __cplusplus
extern "C"
{
#endif
//*****************************************************************************
//
// Macro definitions
//
//*****************************************************************************
/*! Base UUID: 00002760-08C2-11E1-9073-0E8AC72EXXXX */
#define ATT_UUID_AMBIQ_BASE 0x2E, 0xC7, 0x8A, 0x0E, 0x73, 0x90, \
0xE1, 0x11, 0xC2, 0x08, 0x60, 0x27, 0x00, 0x00
/*! Macro for building Ambiq UUIDs */
#define ATT_UUID_AMBIQ_BUILD(part) UINT16_TO_BYTES(part), ATT_UUID_AMBIQ_BASE
/*! Partial amota service UUIDs */
#define ATT_UUID_AMOTA_SERVICE_PART 0x1001
/*! Partial amota rx characteristic UUIDs */
#define ATT_UUID_AMOTA_RX_PART 0x0001
/*! Partial amota tx characteristic UUIDs */
#define ATT_UUID_AMOTA_TX_PART 0x0002
/* Amota services */
#define ATT_UUID_AMOTA_SERVICE ATT_UUID_AMBIQ_BUILD(ATT_UUID_AMOTA_SERVICE_PART)
/* Amota characteristics */
#define ATT_UUID_AMOTA_RX ATT_UUID_AMBIQ_BUILD(ATT_UUID_AMOTA_RX_PART)
#define ATT_UUID_AMOTA_TX ATT_UUID_AMBIQ_BUILD(ATT_UUID_AMOTA_TX_PART)
// AM OTA Service
#define AMOTAS_START_HDL 0x300
#define AMOTAS_END_HDL (AMOTAS_MAX_HDL - 1)
/* AMOTA Service Handles */
enum
{
AMOTA_SVC_HDL = AMOTAS_START_HDL, /* AMOTA service declaration */
AMOTAS_RX_CH_HDL, /* AMOTA write command characteristic */
AMOTAS_RX_HDL, /* AMOTA write command data */
AMOTAS_TX_CH_HDL, /* AMOTA notify characteristic */
AMOTAS_TX_HDL, /* AMOTA notify data */
AMOTAS_TX_CH_CCC_HDL, /* AMOTA notify client characteristic configuration */
AMOTAS_MAX_HDL
};
//*****************************************************************************
//
// External variable definitions
//
//*****************************************************************************
//extern uint32_t g_ui32Stuff;
//*****************************************************************************
//
// Function definitions.
//
//*****************************************************************************
void SvcAmotasAddGroup(void);
void SvcAmotasRemoveGroup(void);
void SvcAmotasCbackRegister(attsReadCback_t readCback, attsWriteCback_t writeCback);
#ifdef __cplusplus
}
#endif
#endif // SVC_AMOTAS_H
@@ -0,0 +1,224 @@
//*****************************************************************************
//
//! @file svc_amvole.c
//!
//! @brief AM Voice Over LE service implementation
//!
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2018, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 1.2.12 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#include "wsf_types.h"
#include "att_api.h"
#include "wsf_trace.h"
#include "bstream.h"
#include "svc_ch.h"
#include "svc_amvole.h"
#include "svc_cfg.h"
//*****************************************************************************
//
// Macro definitions
//
//*****************************************************************************
//#define SOME_MACRO 42 //!< This is the answer
//*****************************************************************************
//
// Global Variables
//
//*****************************************************************************
/**************************************************************************************************
Static Variables
**************************************************************************************************/
/* UUIDs */
static const uint8_t svcRxUuid[] = {ATT_UUID_VOLES_RX};
static const uint8_t svcTxUuid[] = {ATT_UUID_VOLES_TX};
/**************************************************************************************************
Service variables
**************************************************************************************************/
/* VOLES service declaration */
static const uint8_t amvoleSvc[] = {ATT_UUID_VOLES_SERVICE};
static const uint16_t amvoleLenSvc = sizeof(amvoleSvc);
/* VOLES RX characteristic */
static const uint8_t amvoleRxCh[] = {ATT_PROP_WRITE, UINT16_TO_BYTES(VOLES_RX_HDL), ATT_UUID_VOLES_RX};
static const uint16_t amvoleLenRxCh = sizeof(amvoleRxCh);
/* VOLES TX characteristic */
static const uint8_t amvoleTxCh[] = {ATT_PROP_NOTIFY | ATT_PROP_READ, UINT16_TO_BYTES(VOLES_TX_HDL), ATT_UUID_VOLES_TX};
static const uint16_t amvoleLenTxCh = sizeof(amvoleTxCh);
/* VOLES RX data */
/* Note these are dummy values */
static const uint8_t amvoleRx[] = {0};
static const uint16_t amvoleLenRx = sizeof(amvoleRx);
/* VOLES TX data */
/* Note these are dummy values */
static const uint8_t amvoleTx[] = {0};
static const uint16_t amvoleLenTx = sizeof(amvoleTx);
/* Proprietary data client characteristic configuration */
static uint8_t amvoleTxChCcc[] = {UINT16_TO_BYTES(0x0000)};
static const uint16_t amvoleLenTxChCcc = sizeof(amvoleTxChCcc);
/* Attribute list for VOLES group */
static const attsAttr_t amvoleList[] =
{
{
attPrimSvcUuid,
(uint8_t *) amvoleSvc,
(uint16_t *) &amvoleLenSvc,
sizeof(amvoleSvc),
0,
ATTS_PERMIT_READ
},
{
attChUuid,
(uint8_t *) amvoleRxCh,
(uint16_t *) &amvoleLenRxCh,
sizeof(amvoleRxCh),
0,
ATTS_PERMIT_READ
},
{
svcRxUuid,
(uint8_t *) amvoleRx,
(uint16_t *) &amvoleLenRx,
ATT_VALUE_MAX_LEN,
(ATTS_SET_UUID_128 | ATTS_SET_VARIABLE_LEN | ATTS_SET_WRITE_CBACK),
ATTS_PERMIT_WRITE
//ATTS_PERMIT_WRITE_ENC
},
{
attChUuid,
(uint8_t *) amvoleTxCh,
(uint16_t *) &amvoleLenTxCh,
sizeof(amvoleTxCh),
0,
ATTS_PERMIT_READ
},
{
svcTxUuid,
(uint8_t *) amvoleTx,
(uint16_t *) &amvoleLenTx,
sizeof(amvoleTx), //ATT_VALUE_MAX_LEN,
#if 0
#if USE_OUTPUT_VOLES_AMA
(ATTS_SET_UUID_128 | ATTS_SET_VARIABLE_LEN),
ATTS_PERMIT_READ
#else
0, //(ATTS_SET_UUID_128 | ATTS_SET_VARIABLE_LEN),
0 //ATTS_PERMIT_READ
#endif
#endif
(ATTS_SET_UUID_128),
ATTS_PERMIT_READ
},
{
attCliChCfgUuid,
(uint8_t *) amvoleTxChCcc,
(uint16_t *) &amvoleLenTxChCcc,
sizeof(amvoleTxChCcc),
ATTS_SET_CCC,
(ATTS_PERMIT_READ | ATTS_PERMIT_WRITE)
}
};
/* VOLES group structure */
static attsGroup_t svcVolesGroup =
{
NULL,
(attsAttr_t *) amvoleList,
NULL,
NULL,
VOLES_START_HDL,
VOLES_END_HDL
};
/*************************************************************************************************/
/*!
* \fn SvcVolesAddGroup
*
* \brief Add the services to the attribute server.
*
* \return None.
*/
/*************************************************************************************************/
void SvcVolesAddGroup(void)
{
AttsAddGroup(&svcVolesGroup);
}
/*************************************************************************************************/
/*!
* \fn SvcVolesRemoveGroup
*
* \brief Remove the services from the attribute server.
*
* \return None.
*/
/*************************************************************************************************/
void SvcVolesRemoveGroup(void)
{
AttsRemoveGroup(VOLES_START_HDL);
}
/*************************************************************************************************/
/*!
* \fn SvcVolesCbackRegister
*
* \brief Register callbacks for the service.
*
* \param readCback Read callback function.
* \param writeCback Write callback function.
*
* \return None.
*/
/*************************************************************************************************/
void SvcVolesCbackRegister(attsReadCback_t readCback, attsWriteCback_t writeCback)
{
svcVolesGroup.readCback = readCback;
svcVolesGroup.writeCback = writeCback;
}
@@ -0,0 +1,107 @@
//*****************************************************************************
//
//! @file svc_amvole.h
//!
//! @brief AmbiqMicro Voice Over LE service definition
//
//*****************************************************************************
//*****************************************************************************
//
// Copyright (c) 2018, Ambiq Micro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// Third party software included in this distribution is subject to the
// additional license terms as defined in the /docs/licenses directory.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 1.2.12 of the AmbiqSuite Development Package.
//
//*****************************************************************************
#ifndef SVC_VOLES_H
#define SVC_VOLES_H
//
// Put additional includes here if necessary.
//
#ifdef __cplusplus
extern "C"
{
#endif
//*****************************************************************************
//
// Macro definitions
//
//*****************************************************************************
/* AMA services */
#define ATT_UUID_VOLES_SERVICE 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x03, 0xFE, 0x00, 0x00
/* VOLE characteristics */
#define ATT_UUID_VOLES_RX 0x76, 0x30, 0xF8, 0xDD, 0x90, 0xA3, 0x61, 0xAC, 0xA7, 0x43, 0x05, 0x30, 0x77, 0xB1, 0x4E, 0xF0
#define ATT_UUID_VOLES_TX 0x0B, 0x42, 0x82, 0x1F, 0x64, 0x72, 0x2F, 0x8A, 0xB4, 0x4B, 0x79, 0x18, 0x5B, 0xA0, 0xEE, 0x2B
#define VOLES_START_HDL 0x0800//0x300
#define VOLES_END_HDL (VOLES_MAX_HDL - 1)
/* VOLE Service Handles */
enum
{
VOLES_SVC_HDL = VOLES_START_HDL, /* VOLE service declaration */
VOLES_RX_CH_HDL, /* VOLE write command characteristic */
VOLES_RX_HDL, /* VOLE write command data */
VOLES_TX_CH_HDL, /* VOLE notify characteristic */
VOLES_TX_HDL, /* VOLE notify data */
VOLES_TX_CH_CCC_HDL, /* VOLE notify client characteristic configuration */
VOLES_MAX_HDL
};
//*****************************************************************************
//
// External variable definitions
//
//*****************************************************************************
//*****************************************************************************
//
// Function definitions.
//
//*****************************************************************************
void SvcVolesAddGroup(void);
void SvcVolesRemoveGroup(void);
void SvcVolesCbackRegister(attsReadCback_t readCback, attsWriteCback_t writeCback);
#ifdef __cplusplus
}
#endif
#endif // SVC_VOLES_H