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,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