initial commit
This commit is contained in:
Vendored
+123
@@ -0,0 +1,123 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Glucose profile sensor.
|
||||
*
|
||||
* Copyright (c) 2012-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef GLPS_API_H
|
||||
#define GLPS_API_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup GLUCOSE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief All supported features of the glucose profile */
|
||||
#define GLP_ALL_SUPPORTED_FEATURES 0x000F
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the Glucose profile sensor.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by the application when a message that requires
|
||||
* processing by the glucose profile sensor is received.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsProcMsg(wsfMsgHdr_t *pMsg);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a button press.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param btn Button press.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsBtn(dmConnId_t connId, uint8_t btn);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS write callback for glucose service record access control point. Use this
|
||||
* function as a parameter to SvcGlsCbackRegister().
|
||||
*
|
||||
* \param connId DM connection identifier.
|
||||
* \param handle ATT handle.
|
||||
* \param operation ATT operation.
|
||||
* \param offset Write offset.
|
||||
* \param len Write length.
|
||||
* \param pValue Value to write.
|
||||
* \param pAttr Attribute to write.
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t GlpsRacpWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the supported features of the glucose sensor.
|
||||
*
|
||||
* \param feature Feature bitmask.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsSetFeature(uint16_t feature);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the CCCD index used by the application for glucose service characteristics.
|
||||
*
|
||||
* \param glmCccIdx Glucose measurement CCCD index.
|
||||
* \param glmcCccIdx Glucose measurement context CCCD index.
|
||||
* \param racpCccIdx Record access control point CCCD index.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsSetCccIdx(uint8_t glmCccIdx, uint8_t glmcCccIdx, uint8_t racpCccIdx);
|
||||
|
||||
/*! \} */ /* GLUCOSE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* GLPS_API_H */
|
||||
Vendored
+430
@@ -0,0 +1,430 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Glucose profile example record database and access functions.
|
||||
*
|
||||
* Copyright (c) 2012-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "svc_ch.h"
|
||||
#include "svc_gls.h"
|
||||
#include "app_api.h"
|
||||
#include "glps_api.h"
|
||||
#include "glps_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Number of records in example database */
|
||||
#define GLPS_DB_NUM_RECORDS 3
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! Control block */
|
||||
static struct
|
||||
{
|
||||
uint8_t numRec;
|
||||
} glpsDbCb;
|
||||
|
||||
/*! Example record database */
|
||||
static glpsRec_t glpsDb[GLPS_DB_NUM_RECORDS] =
|
||||
{
|
||||
/* record 1 */
|
||||
{
|
||||
/* measurement */
|
||||
{
|
||||
CH_GLM_FLAG_TIME_OFFSET | CH_GLM_FLAG_CONC_TYPE_LOC | /* Flags */
|
||||
CH_GLM_FLAG_UNITS_MOL_L | CH_GLM_FLAG_SENSOR_STATUS,
|
||||
0x0001, /* Sequence number */
|
||||
{2012, 6, 15, 20, 52, 36}, /* Base time */
|
||||
60, /* Time offset */
|
||||
SFLT_TO_UINT16(50, -3), /* Glucose concentration (SFLOAT) */
|
||||
CH_GLM_LOC_FINGER | (CH_GLM_TYPE_ART_BLOOD << 4), /* Sample type and sample location */
|
||||
CH_GLM_STATUS_BATT_LOW /* Sensor status annunciation */
|
||||
},
|
||||
|
||||
/* context */
|
||||
{
|
||||
CH_GLMC_FLAG_CARB | CH_GLMC_FLAG_MEAL | /* Flags */
|
||||
CH_GLMC_FLAG_TESTER | CH_GLMC_FLAG_EXERCISE |
|
||||
CH_GLMC_FLAG_MED | CH_GLMC_FLAG_MED_KG |
|
||||
CH_GLMC_FLAG_HBA1C,
|
||||
0x0001, /* Sequence number */
|
||||
0, /* Extended Flags */
|
||||
CH_GLMC_CARB_DINNER, /* Carbohydrate ID */
|
||||
SFLT_TO_UINT16(12, -3), /* Carbohydrate (SFLOAT) */
|
||||
CH_GLMC_MEAL_POSTPRANDIAL, /* Meal */
|
||||
CH_GLMC_HEALTH_NONE | (CH_GLMC_TESTER_SELF << 4), /* Tester and health */
|
||||
300, /* Exercise Duration */
|
||||
99, /* Exercise Intensity */
|
||||
CH_GLMC_MED_LONG, /* Medication ID */
|
||||
SFLT_TO_UINT16(50, -6), /* Medication (SFLOAT) */
|
||||
SFLT_TO_UINT16(10, 0) /* HbA1c */
|
||||
},
|
||||
},
|
||||
|
||||
/* record 2 */
|
||||
{
|
||||
/* measurement */
|
||||
{
|
||||
CH_GLM_FLAG_CONC_TYPE_LOC | CH_GLM_FLAG_UNITS_KG_L | /* Flags */
|
||||
CH_GLM_FLAG_CONTEXT_INFO,
|
||||
0x0002, /* Sequence number */
|
||||
{2012, 6, 16, 6, 45, 20}, /* Base time */
|
||||
0, /* Time offset */
|
||||
SFLT_TO_UINT16(20, -5), /* Glucose concentration (SFLOAT) */
|
||||
CH_GLM_LOC_FINGER | (CH_GLM_TYPE_ART_BLOOD << 4), /* Sample type and sample location */
|
||||
0 /* Sensor status annunciation */
|
||||
},
|
||||
|
||||
/* context */
|
||||
{
|
||||
CH_GLMC_FLAG_CARB | CH_GLMC_FLAG_MEAL | /* Flags */
|
||||
CH_GLMC_FLAG_TESTER | CH_GLMC_FLAG_EXERCISE |
|
||||
CH_GLMC_FLAG_MED | CH_GLMC_FLAG_MED_L |
|
||||
CH_GLMC_FLAG_HBA1C,
|
||||
0x0002, /* Sequence number */
|
||||
0, /* Extended Flags */
|
||||
CH_GLMC_CARB_BREAKFAST, /* Carbohydrate ID */
|
||||
SFLT_TO_UINT16(3, -3), /* Carbohydrate (SFLOAT) */
|
||||
CH_GLMC_MEAL_PREPRANDIAL, /* Meal */
|
||||
CH_GLMC_HEALTH_NONE | (CH_GLMC_TESTER_SELF << 4), /* Tester and health */
|
||||
1000, /* Exercise Duration */
|
||||
25, /* Exercise Intensity */
|
||||
CH_GLMC_MED_LONG, /* Medication ID */
|
||||
SFLT_TO_UINT16(10, -3), /* Medication (SFLOAT) */
|
||||
SFLT_TO_UINT16(11, 0) /* HbA1c */
|
||||
},
|
||||
},
|
||||
|
||||
/* record 3 */
|
||||
{
|
||||
/* measurement */
|
||||
{
|
||||
CH_GLM_FLAG_CONC_TYPE_LOC | CH_GLM_FLAG_UNITS_KG_L, /* Flags */
|
||||
0x0003, /* Sequence number */
|
||||
{2012, 6, 16, 18, 45, 20}, /* Base time */
|
||||
0, /* Time offset */
|
||||
SFLT_TO_UINT16(20, -5), /* Glucose concentration (SFLOAT) */
|
||||
CH_GLM_LOC_FINGER | (CH_GLM_TYPE_ART_BLOOD << 4), /* Sample type and sample location */
|
||||
0 /* Sensor status annunciation */
|
||||
},
|
||||
|
||||
/* context */
|
||||
{
|
||||
CH_GLMC_FLAG_TESTER | CH_GLMC_FLAG_EXERCISE | /* Flags */
|
||||
CH_GLMC_FLAG_MED | CH_GLMC_FLAG_MED_L |
|
||||
CH_GLMC_FLAG_HBA1C,
|
||||
0x0003, /* Sequence number */
|
||||
0, /* Extended Flags */
|
||||
0, /* Carbohydrate ID */
|
||||
SFLT_TO_UINT16(0, 0), /* Carbohydrate (SFLOAT) */
|
||||
0, /* Meal */
|
||||
CH_GLMC_HEALTH_NONE | (CH_GLMC_TESTER_SELF << 4), /* Tester and health */
|
||||
1001, /* Exercise Duration */
|
||||
26, /* Exercise Intensity */
|
||||
CH_GLMC_MED_LONG, /* Medication ID */
|
||||
SFLT_TO_UINT16(15, -3), /* Medication (SFLOAT) */
|
||||
SFLT_TO_UINT16(12, 0) /* HbA1c */
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get last database record.
|
||||
*
|
||||
* \return Pointer to record or NULL if no record.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static glpsRec_t *glpsDbGetEnd(void)
|
||||
{
|
||||
if (glpsDbCb.numRec == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (glpsRec_t *) &glpsDb[glpsDbCb.numRec - 1];
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next database record after the given current record.
|
||||
*
|
||||
* \param pCurrRec Pointer to current record.
|
||||
*
|
||||
* \return Pointer to record or NULL if no record.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static glpsRec_t *glpsDbGetNext(glpsRec_t *pCurrRec)
|
||||
{
|
||||
if (glpsDbCb.numRec == 0 || pCurrRec == glpsDbGetEnd())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else if (pCurrRec == NULL)
|
||||
{
|
||||
return (glpsRec_t *) glpsDb;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (pCurrRec + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next record filtered for "all".
|
||||
*
|
||||
* \param pCurrRec Pointer to current record.
|
||||
* \param pRec Return pointer to next record, if found.
|
||||
*
|
||||
* \return CH_RACP_RSP_SUCCESS if a record is found, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t glpsDbOpAll(glpsRec_t *pCurrRec, glpsRec_t **pRec)
|
||||
{
|
||||
*pRec = glpsDbGetNext(pCurrRec);
|
||||
return (*pRec != NULL) ? CH_RACP_RSP_SUCCESS : CH_RACP_RSP_NO_RECORDS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next record filtered for "greater than or equal to sequence number".
|
||||
*
|
||||
* \param pFilter Glucose service RACP filter parameters.
|
||||
* \param pCurrRec Pointer to current record.
|
||||
* \param pRec Return pointer to next record, if found.
|
||||
*
|
||||
* \return CH_RACP_RSP_SUCCESS if a record is found, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t glpsDbOpGteqSeqNum(uint8_t *pFilter, glpsRec_t *pCurrRec, glpsRec_t **pRec)
|
||||
{
|
||||
uint16_t seqNum;
|
||||
|
||||
/* parse seq number */
|
||||
pFilter++;
|
||||
BYTES_TO_UINT16(seqNum, pFilter);
|
||||
|
||||
/* find record */
|
||||
while ((*pRec = glpsDbGetNext(pCurrRec)) != NULL)
|
||||
{
|
||||
if ((*pRec)->meas.seqNum >= seqNum)
|
||||
{
|
||||
return CH_RACP_RSP_SUCCESS;
|
||||
}
|
||||
pCurrRec = *pRec;
|
||||
}
|
||||
|
||||
return CH_RACP_RSP_NO_RECORDS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next record filtered for "last".
|
||||
*
|
||||
* \param pCurrRec Pointer to current record.
|
||||
* \param pRec Return pointer to next record, if found.
|
||||
*
|
||||
* \return CH_RACP_RSP_SUCCESS if a record is found, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t glpsDbOpLast(glpsRec_t *pCurrRec, glpsRec_t **pRec)
|
||||
{
|
||||
/* if current record is already last return failure */
|
||||
*pRec = glpsDbGetEnd();
|
||||
if (*pRec != NULL && *pRec != pCurrRec)
|
||||
{
|
||||
return CH_RACP_RSP_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CH_RACP_RSP_NO_RECORDS;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the glucose record database.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsDbInit(void)
|
||||
{
|
||||
glpsDbCb.numRec = GLPS_DB_NUM_RECORDS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next record that matches the given filter parameters that follows
|
||||
* the given current record.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param pFilter Glucose service RACP filter parameters.
|
||||
* \param pCurrRec Pointer to current record.
|
||||
* \param pRec Return pointer to next record, if found.
|
||||
*
|
||||
* \return CH_RACP_RSP_SUCCESS if a record is found, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t glpsDbGetNextRecord(uint8_t oper, uint8_t *pFilter, glpsRec_t *pCurrRec, glpsRec_t **pRec)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
switch (oper)
|
||||
{
|
||||
case CH_RACP_OPERATOR_ALL:
|
||||
status = glpsDbOpAll(pCurrRec, pRec);
|
||||
break;
|
||||
|
||||
case CH_RACP_OPERATOR_GTEQ:
|
||||
/* check filter type */
|
||||
if (*pFilter == CH_RACP_GLS_FILTER_SEQ)
|
||||
{
|
||||
status = glpsDbOpGteqSeqNum(pFilter, pCurrRec, pRec);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = CH_RACP_RSP_OPERAND_NOT_SUP;
|
||||
}
|
||||
break;
|
||||
|
||||
case CH_RACP_OPERATOR_LAST:
|
||||
status = glpsDbOpLast(pCurrRec, pRec);
|
||||
break;
|
||||
|
||||
case CH_RACP_OPERATOR_NULL:
|
||||
status = CH_RACP_RSP_INV_OPERATOR;
|
||||
break;
|
||||
|
||||
default:
|
||||
status = CH_RACP_RSP_OPERATOR_NOT_SUP;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Delete records that match the given filter parameters.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param pFilter Glucose service RACP filter parameters.
|
||||
*
|
||||
* \return CH_RACP_RSP_SUCCESS if records deleted, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t glpsDbDeleteRecords(uint8_t oper, uint8_t *pFilter)
|
||||
{
|
||||
/* only 'all records' is supported */
|
||||
if (oper == CH_RACP_OPERATOR_ALL)
|
||||
{
|
||||
glpsDbCb.numRec = 0;
|
||||
|
||||
return CH_RACP_RSP_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CH_RACP_RSP_OPERATOR_NOT_SUP;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the number of records matching the filter parameters.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param pFilter Glucose service RACP filter parameters.
|
||||
* \param pNumRec Returns number of records which match filter parameters.
|
||||
|
||||
*
|
||||
* \return RACP status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t glpsDbGetNumRecords(uint8_t oper, uint8_t *pFilter, uint8_t *pNumRec)
|
||||
{
|
||||
glpsRec_t *pCurrRec = NULL;
|
||||
uint8_t status;
|
||||
|
||||
*pNumRec = 0;
|
||||
while ((status = glpsDbGetNextRecord(oper, pFilter, pCurrRec, &pCurrRec)) == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
(*pNumRec)++;
|
||||
}
|
||||
|
||||
if (status == CH_RACP_RSP_NO_RECORDS)
|
||||
{
|
||||
status = CH_RACP_RSP_SUCCESS;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate a new record.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsDbGenerateRecord(void)
|
||||
{
|
||||
if (glpsDbCb.numRec < GLPS_DB_NUM_RECORDS)
|
||||
{
|
||||
glpsDbCb.numRec++;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For conformance testing only. Toggle the sample data record number 2's medication
|
||||
* quantity unit flag between Kilograms and Liters. Also modifies quantity.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsDbToggleMedicationUnits(void)
|
||||
{
|
||||
if (glpsDb[1].context.flags & CH_GLMC_FLAG_MED_L)
|
||||
{
|
||||
/* Change medication quantity to Kilograms. */
|
||||
glpsDb[1].context.flags &= ~CH_GLMC_FLAG_MED_L;
|
||||
glpsDb[1].context.flags |= CH_GLMC_FLAG_MED_KG;
|
||||
glpsDb[1].context.medication = SFLT_TO_UINT16(50, -6);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Change medication quantiy to Liters. */
|
||||
glpsDb[1].context.flags &= ~CH_GLMC_FLAG_MED_KG;
|
||||
glpsDb[1].context.flags |= CH_GLMC_FLAG_MED_L;
|
||||
glpsDb[1].context.medication = SFLT_TO_UINT16(10, -3);
|
||||
}
|
||||
}
|
||||
Vendored
+822
@@ -0,0 +1,822 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Glucose profile sensor.
|
||||
*
|
||||
* Copyright (c) 2012-2019 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include "wsf_types.h"
|
||||
#include "wsf_assert.h"
|
||||
#include "wsf_trace.h"
|
||||
#include "util/bstream.h"
|
||||
#include "att_api.h"
|
||||
#include "svc_ch.h"
|
||||
#include "svc_gls.h"
|
||||
#include "app_api.h"
|
||||
#include "app_ui.h"
|
||||
#include "glps_api.h"
|
||||
#include "glps_main.h"
|
||||
|
||||
/**************************************************************************************************
|
||||
Local Variables
|
||||
**************************************************************************************************/
|
||||
|
||||
/* Control block */
|
||||
static struct
|
||||
{
|
||||
uint8_t operand[GLPS_OPERAND_MAX]; /* Stored operand filter data */
|
||||
glpsRec_t *pCurrRec; /* Pointer to current measurement record */
|
||||
bool_t inProgress; /* TRUE if RACP procedure in progress */
|
||||
bool_t txReady; /* TRUE if ready to send next notification or indication */
|
||||
bool_t aborting; /* TRUE if abort procedure in progress */
|
||||
uint8_t glmCccIdx; /* Glucose measurement CCCD index */
|
||||
uint8_t glmcCccIdx; /* Glucose measurement context CCCD index */
|
||||
uint8_t racpCccIdx; /* Record access control point CCCD index */
|
||||
uint8_t oper; /* Stored operator */
|
||||
} glpsCb;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Build a glucose measurement characteristic.
|
||||
*
|
||||
* \param pBuf Pointer to buffer to hold the built glucose measurement.
|
||||
* \param pGlm Glucose measurement values.
|
||||
*
|
||||
* \return Length of pBuf in bytes.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t glpsBuildGlm(uint8_t *pBuf, glpsGlm_t *pGlm)
|
||||
{
|
||||
uint8_t *p = pBuf;
|
||||
uint8_t flags = pGlm->flags;
|
||||
|
||||
/* flags */
|
||||
UINT8_TO_BSTREAM(p, flags);
|
||||
|
||||
/* sequence number */
|
||||
UINT16_TO_BSTREAM(p, pGlm->seqNum);
|
||||
|
||||
/* base time */
|
||||
UINT16_TO_BSTREAM(p, pGlm->baseTime.year);
|
||||
UINT8_TO_BSTREAM(p, pGlm->baseTime.month);
|
||||
UINT8_TO_BSTREAM(p, pGlm->baseTime.day);
|
||||
UINT8_TO_BSTREAM(p, pGlm->baseTime.hour);
|
||||
UINT8_TO_BSTREAM(p, pGlm->baseTime.min);
|
||||
UINT8_TO_BSTREAM(p, pGlm->baseTime.sec);
|
||||
|
||||
/* time offset */
|
||||
if (flags & CH_GLM_FLAG_TIME_OFFSET)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pGlm->timeOffset);
|
||||
}
|
||||
|
||||
/* glucose concentration, type, and sample location */
|
||||
if (flags & CH_GLM_FLAG_CONC_TYPE_LOC)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pGlm->concentration);
|
||||
UINT8_TO_BSTREAM(p, pGlm->typeSampleLoc);
|
||||
}
|
||||
|
||||
/* sensor status annunciation */
|
||||
if (flags & CH_GLM_FLAG_SENSOR_STATUS)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pGlm->sensorStatus);
|
||||
}
|
||||
|
||||
/* return length */
|
||||
return (uint8_t) (p - pBuf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Build a glucose measurement context characteristic.
|
||||
*
|
||||
* \param pBuf Pointer to buffer to hold the built glucose measurement context.
|
||||
* \param pGlmc Glucose measurement context values.
|
||||
*
|
||||
* \return Length of pBuf in bytes.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t glpsBuildGlmc(uint8_t *pBuf, glpsGlmc_t *pGlmc)
|
||||
{
|
||||
uint8_t *p = pBuf;
|
||||
uint8_t flags = pGlmc->flags;
|
||||
|
||||
/* flags */
|
||||
UINT8_TO_BSTREAM(p, flags);
|
||||
|
||||
/* sequence number */
|
||||
UINT16_TO_BSTREAM(p, pGlmc->seqNum);
|
||||
|
||||
/* extended flags present */
|
||||
if (flags & CH_GLMC_FLAG_EXT)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, pGlmc->extFlags);
|
||||
}
|
||||
|
||||
/* carbohydrate id and carbohydrate present */
|
||||
if (flags & CH_GLMC_FLAG_CARB)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, pGlmc->carbId);
|
||||
UINT16_TO_BSTREAM(p, pGlmc->carb);
|
||||
}
|
||||
|
||||
/* meal present */
|
||||
if (flags & CH_GLMC_FLAG_MEAL)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, pGlmc->meal);
|
||||
}
|
||||
|
||||
/* tester-health present */
|
||||
if (flags & CH_GLMC_FLAG_TESTER)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, pGlmc->testerHealth);
|
||||
}
|
||||
|
||||
/* exercise duration and exercise intensity present */
|
||||
if (flags & CH_GLMC_FLAG_EXERCISE)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pGlmc->exerDuration);
|
||||
UINT8_TO_BSTREAM(p, pGlmc->exerIntensity);
|
||||
}
|
||||
|
||||
/* medication ID and medication present */
|
||||
if (flags & CH_GLMC_FLAG_MED)
|
||||
{
|
||||
UINT8_TO_BSTREAM(p, pGlmc->medicationId);
|
||||
UINT16_TO_BSTREAM(p, pGlmc->medication);
|
||||
}
|
||||
|
||||
/* hba1c present */
|
||||
if (flags & CH_GLMC_FLAG_HBA1C)
|
||||
{
|
||||
UINT16_TO_BSTREAM(p, pGlmc->hba1c);
|
||||
}
|
||||
|
||||
/* return length */
|
||||
return (uint8_t) (p - pBuf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a glucose measurement context notification.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param pRec Return pointer to glucose record.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsSendMeasContext(dmConnId_t connId, glpsRec_t *pRec)
|
||||
{
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t len;
|
||||
|
||||
/* build glucose measurement context characteristic */
|
||||
len = glpsBuildGlmc(buf, &glpsCb.pCurrRec->context);
|
||||
|
||||
/* send notification */
|
||||
AttsHandleValueNtf(connId, GLS_GLMC_HDL, len, buf);
|
||||
glpsCb.txReady = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a glucose measurement notification.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param pRec Return pointer to glucose record.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsSendMeas(dmConnId_t connId, glpsRec_t *pRec)
|
||||
{
|
||||
uint8_t buf[ATT_DEFAULT_PAYLOAD_LEN];
|
||||
uint8_t len;
|
||||
|
||||
/* build glucose measurement characteristic */
|
||||
len = glpsBuildGlm(buf, &glpsCb.pCurrRec->meas);
|
||||
|
||||
/* send notification */
|
||||
AttsHandleValueNtf(connId, GLS_GLM_HDL, len, buf);
|
||||
glpsCb.txReady = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a RACP response indication.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param opcode RACP opcode.
|
||||
* \param status RACP status.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsRacpSendRsp(dmConnId_t connId, uint8_t opcode, uint8_t status)
|
||||
{
|
||||
uint8_t buf[GLPS_RACP_RSP_LEN];
|
||||
|
||||
/* build response */
|
||||
buf[0] = CH_RACP_OPCODE_RSP;
|
||||
buf[1] = CH_RACP_OPERATOR_NULL;
|
||||
buf[2] = opcode;
|
||||
buf[3] = status;
|
||||
|
||||
/* send indication */
|
||||
AttsHandleValueInd(connId, GLS_RACP_HDL, GLPS_RACP_RSP_LEN, buf);
|
||||
glpsCb.txReady = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Send a RACP number of records response indication.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param numRec Number of records.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsRacpSendNumRecRsp(dmConnId_t connId, uint16_t numRec)
|
||||
{
|
||||
uint8_t buf[GLPS_RACP_NUM_REC_RSP_LEN];
|
||||
|
||||
/* build response */
|
||||
buf[0] = CH_RACP_OPCODE_NUM_RSP;
|
||||
buf[1] = CH_RACP_OPERATOR_NULL;
|
||||
buf[2] = UINT16_TO_BYTE0(numRec);
|
||||
buf[3] = UINT16_TO_BYTE1(numRec);
|
||||
|
||||
/* send indication */
|
||||
AttsHandleValueInd(connId, GLS_RACP_HDL, GLPS_RACP_RSP_LEN, buf);
|
||||
glpsCb.txReady = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle connection open.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void glpsConnOpen(dmEvt_t *pMsg)
|
||||
{
|
||||
/* initialize */
|
||||
glpsCb.pCurrRec = NULL;
|
||||
glpsCb.aborting = FALSE;
|
||||
glpsCb.inProgress = FALSE;
|
||||
glpsCb.txReady = FALSE;
|
||||
glpsCb.oper = CH_RACP_OPERATOR_NULL;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle connection close.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void glpsConnClose(dmEvt_t *pMsg)
|
||||
{
|
||||
glpsCb.pCurrRec = NULL;
|
||||
glpsCb.aborting = FALSE;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle an ATT handle value confirm.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void glpsHandleValueCnf(attEvt_t *pMsg)
|
||||
{
|
||||
dmConnId_t connId = (dmConnId_t) pMsg->hdr.param;
|
||||
glpsCb.txReady = TRUE;
|
||||
|
||||
/* if aborting finish that up */
|
||||
if (glpsCb.aborting)
|
||||
{
|
||||
glpsCb.aborting = FALSE;
|
||||
glpsRacpSendRsp(connId, CH_RACP_OPCODE_ABORT, CH_RACP_RSP_SUCCESS);
|
||||
}
|
||||
|
||||
/* if this is for RACP indication */
|
||||
if (pMsg->handle == GLS_RACP_HDL)
|
||||
{
|
||||
/* procedure no longer in progress */
|
||||
glpsCb.inProgress = FALSE;
|
||||
}
|
||||
/* if this is for measurement or context notification */
|
||||
else if (pMsg->handle == GLS_GLM_HDL || pMsg->handle == GLS_GLMC_HDL)
|
||||
{
|
||||
if (glpsCb.pCurrRec != NULL)
|
||||
{
|
||||
/* if measurement was sent and there is context to send */
|
||||
if (pMsg->handle == GLS_GLM_HDL && AttsCccEnabled(connId, glpsCb.glmcCccIdx) &&
|
||||
(glpsCb.pCurrRec->meas.flags & CH_GLM_FLAG_CONTEXT_INFO))
|
||||
{
|
||||
/* send context */
|
||||
glpsSendMeasContext(connId, glpsCb.pCurrRec);
|
||||
}
|
||||
/* else if there is another record */
|
||||
else if (glpsDbGetNextRecord(glpsCb.oper, glpsCb.operand,
|
||||
glpsCb.pCurrRec, &glpsCb.pCurrRec) == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
/* send measurement */
|
||||
glpsSendMeas(connId, glpsCb.pCurrRec);
|
||||
}
|
||||
/* else all records sent; send RACP response */
|
||||
else
|
||||
{
|
||||
glpsRacpSendRsp(connId, CH_RACP_OPCODE_REPORT, CH_RACP_RSP_SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Verify validity of operand data. If valid, store the data.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param len Operand length.
|
||||
* \param pOperand Operand data.
|
||||
|
||||
*
|
||||
* \return RACP status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static uint8_t glpsRacpOperCheck(uint8_t oper, uint16_t len, uint8_t *pOperand)
|
||||
{
|
||||
uint8_t status = CH_RACP_RSP_SUCCESS;
|
||||
uint8_t filterType;
|
||||
uint8_t filterLen = 0;
|
||||
|
||||
/* these operators have no operands */
|
||||
if (oper == CH_RACP_OPERATOR_ALL || oper == CH_RACP_OPERATOR_FIRST ||
|
||||
oper == CH_RACP_OPERATOR_LAST || oper == CH_RACP_OPERATOR_NULL)
|
||||
{
|
||||
if (len != 0)
|
||||
{
|
||||
status = CH_RACP_RSP_INV_OPERAND;
|
||||
}
|
||||
}
|
||||
/* remaining operators must have operands */
|
||||
else if (oper == CH_RACP_OPERATOR_LTEQ || oper == CH_RACP_OPERATOR_GTEQ ||
|
||||
oper == CH_RACP_OPERATOR_RANGE)
|
||||
{
|
||||
if (len == 0)
|
||||
{
|
||||
status = CH_RACP_RSP_INV_OPERAND;
|
||||
}
|
||||
else
|
||||
{
|
||||
filterType = *pOperand;
|
||||
len--;
|
||||
|
||||
/* operand length depends on filter type */
|
||||
if (filterType == CH_RACP_GLS_FILTER_SEQ)
|
||||
{
|
||||
filterLen = CH_RACP_GLS_FILTER_SEQ_LEN;
|
||||
}
|
||||
else if (filterType == CH_RACP_GLS_FILTER_TIME)
|
||||
{
|
||||
filterLen = CH_RACP_GLS_FILTER_TIME_LEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
status = CH_RACP_RSP_OPERAND_NOT_SUP;
|
||||
}
|
||||
|
||||
if (status == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
/* range operator has two filters, others have one */
|
||||
if (oper == CH_RACP_OPERATOR_RANGE)
|
||||
{
|
||||
filterLen *= 2;
|
||||
}
|
||||
|
||||
/* verify length */
|
||||
if (len != filterLen)
|
||||
{
|
||||
status = CH_RACP_RSP_INV_OPERAND;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* unknown operator */
|
||||
else
|
||||
{
|
||||
status = CH_RACP_RSP_OPERATOR_NOT_SUP;
|
||||
}
|
||||
|
||||
/* store operator and operand */
|
||||
if (status == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
glpsCb.oper = oper;
|
||||
memcpy(glpsCb.operand, pOperand, len);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a RACP report stored records operation.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param oper Operator.
|
||||
* \param pOperand Operand data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void glpsRacpReport(dmConnId_t connId, uint8_t oper, uint8_t *pOperand)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
/* if record found */
|
||||
if ((status = glpsDbGetNextRecord(oper, pOperand, NULL, &glpsCb.pCurrRec)) == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
/* send measurement */
|
||||
glpsSendMeas(connId, glpsCb.pCurrRec);
|
||||
}
|
||||
/* if not successful send response */
|
||||
else
|
||||
{
|
||||
glpsRacpSendRsp(connId, CH_RACP_OPCODE_REPORT, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a RACP delete records operation.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param oper Operator.
|
||||
* \param pOperand Operand data.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void glpsRacpDelete(dmConnId_t connId, uint8_t oper, uint8_t *pOperand)
|
||||
{
|
||||
uint8_t status;
|
||||
|
||||
/* delete records */
|
||||
status = glpsDbDeleteRecords(oper, pOperand);
|
||||
|
||||
/* send response */
|
||||
glpsRacpSendRsp(connId, CH_RACP_OPCODE_DELETE, status);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a RACP abort operation.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void glpsRacpAbort(dmConnId_t connId)
|
||||
{
|
||||
/* if operation in progress */
|
||||
if (glpsCb.inProgress)
|
||||
{
|
||||
/* abort operation and clean up */
|
||||
glpsCb.pCurrRec = NULL;
|
||||
}
|
||||
|
||||
/* send response */
|
||||
if (glpsCb.txReady)
|
||||
{
|
||||
glpsRacpSendRsp(connId, CH_RACP_OPCODE_ABORT, CH_RACP_RSP_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
glpsCb.aborting = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a RACP report number of stored records operation.
|
||||
*
|
||||
* \param connId Connection ID.
|
||||
* \param oper Operator.
|
||||
* \param pOperand Operand data.
|
||||
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void glpsRacpReportNum(dmConnId_t connId, uint8_t oper, uint8_t *pOperand)
|
||||
{
|
||||
uint8_t status;
|
||||
uint8_t numRec;
|
||||
|
||||
/* get number of records */
|
||||
status = glpsDbGetNumRecords(oper, pOperand, &numRec);
|
||||
|
||||
if (status == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
/* send response */
|
||||
/* note: status check guarantees numRec has been initialized */
|
||||
/* coverity[uninit_use_in_call] */
|
||||
glpsRacpSendNumRecRsp(connId, numRec);
|
||||
}
|
||||
else
|
||||
{
|
||||
glpsRacpSendRsp(connId, CH_RACP_OPCODE_REPORT_NUM, status);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
*
|
||||
* \brief Toggle bonding flag in Glucose Feature Characteristic.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
static void glpsToggleBondingFlag(void)
|
||||
{
|
||||
uint8_t *pGlpsFlagsValue;
|
||||
uint16_t len;
|
||||
|
||||
/* Get flags */
|
||||
if (AttsGetAttr(GLS_GLF_HDL, &len, &pGlpsFlagsValue) == ATT_SUCCESS)
|
||||
{
|
||||
uint16_t glpsFlags;
|
||||
|
||||
BYTES_TO_UINT16(glpsFlags, pGlpsFlagsValue);
|
||||
|
||||
if (glpsFlags & CH_GLF_MULTI_BOND)
|
||||
{
|
||||
glpsFlags &= ~CH_GLF_MULTI_BOND;
|
||||
}
|
||||
else
|
||||
{
|
||||
glpsFlags |= CH_GLF_MULTI_BOND;
|
||||
}
|
||||
|
||||
GlpsSetFeature(glpsFlags);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \fn GlpsInit
|
||||
*
|
||||
* \brief Initialize the Glucose profile sensor.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsInit(void)
|
||||
{
|
||||
glpsDbInit();
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief This function is called by the application when a message that requires
|
||||
* processing by the glucose profile sensor is received.
|
||||
*
|
||||
* \param pMsg Event message.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsProcMsg(wsfMsgHdr_t *pMsg)
|
||||
{
|
||||
switch(pMsg->event)
|
||||
{
|
||||
case DM_CONN_OPEN_IND:
|
||||
glpsConnOpen((dmEvt_t *) pMsg);
|
||||
break;
|
||||
|
||||
case DM_CONN_CLOSE_IND:
|
||||
glpsConnClose((dmEvt_t *) pMsg);
|
||||
break;
|
||||
|
||||
case ATTS_HANDLE_VALUE_CNF:
|
||||
glpsHandleValueCnf((attEvt_t *) pMsg);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Handle a button press.
|
||||
*
|
||||
* \param connId Connection identifier.
|
||||
* \param btn Button press.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsBtn(dmConnId_t connId, uint8_t btn)
|
||||
{
|
||||
/* button actions when connected */
|
||||
if (connId != DM_CONN_ID_NONE)
|
||||
{
|
||||
switch (btn)
|
||||
{
|
||||
case APP_UI_BTN_2_MED:
|
||||
/* Toggle medication quantity, for test purposes only */
|
||||
glpsDbToggleMedicationUnits();
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_2_LONG:
|
||||
/* generate a new record */
|
||||
glpsDbGenerateRecord();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* button actions when not connected */
|
||||
else
|
||||
{
|
||||
switch (btn)
|
||||
{
|
||||
case APP_UI_BTN_2_SHORT:
|
||||
/* Toggle bonding flag */
|
||||
glpsToggleBondingFlag();
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_2_MED:
|
||||
/* Toggle medication quantity, for test purposes only */
|
||||
glpsDbToggleMedicationUnits();
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_2_LONG:
|
||||
/* generate a new record */
|
||||
glpsDbGenerateRecord();
|
||||
break;
|
||||
|
||||
case APP_UI_BTN_2_EX_LONG:
|
||||
/* delete all records */
|
||||
glpsDbDeleteRecords(CH_RACP_OPERATOR_ALL, NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief ATTS write callback for glucose service record access control point. Use this
|
||||
* function as a parameter to SvcGlsCbackRegister().
|
||||
*
|
||||
* \return ATT status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t GlpsRacpWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
|
||||
uint16_t offset, uint16_t len, uint8_t *pValue, attsAttr_t *pAttr)
|
||||
{
|
||||
uint8_t opcode;
|
||||
uint8_t oper;
|
||||
uint8_t status;
|
||||
|
||||
/* sanity check on length */
|
||||
if (len < GLPS_RACP_MIN_WRITE_LEN)
|
||||
{
|
||||
return ATT_ERR_LENGTH;
|
||||
}
|
||||
|
||||
/* if control point not configured for indication */
|
||||
if (!AttsCccEnabled(connId, glpsCb.racpCccIdx))
|
||||
{
|
||||
return GLS_ERR_CCCD;
|
||||
}
|
||||
|
||||
/* parse opcode and operator and adjust remaining parameter length */
|
||||
BSTREAM_TO_UINT8(opcode, pValue);
|
||||
BSTREAM_TO_UINT8(oper, pValue);
|
||||
len -= 2;
|
||||
|
||||
/* handle a procedure in progress */
|
||||
if (opcode != CH_RACP_OPCODE_ABORT && glpsCb.inProgress)
|
||||
{
|
||||
return GLS_ERR_IN_PROGRESS;
|
||||
}
|
||||
|
||||
/* handle record request when notifications not enabled */
|
||||
if (opcode == CH_RACP_OPCODE_REPORT && !AttsCccEnabled(connId, glpsCb.glmCccIdx))
|
||||
{
|
||||
return GLS_ERR_CCCD;
|
||||
}
|
||||
|
||||
/* verify operands */
|
||||
if ((status = glpsRacpOperCheck(oper, len, pValue)) == CH_RACP_RSP_SUCCESS)
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
/* report records */
|
||||
case CH_RACP_OPCODE_REPORT:
|
||||
glpsRacpReport(connId, oper, pValue);
|
||||
break;
|
||||
|
||||
/* delete records */
|
||||
case CH_RACP_OPCODE_DELETE:
|
||||
glpsRacpDelete(connId, oper, pValue);
|
||||
break;
|
||||
|
||||
/* abort current operation */
|
||||
case CH_RACP_OPCODE_ABORT:
|
||||
glpsRacpAbort(connId);
|
||||
break;
|
||||
|
||||
/* report number of records */
|
||||
case CH_RACP_OPCODE_REPORT_NUM:
|
||||
glpsRacpReportNum(connId, oper, pValue);
|
||||
break;
|
||||
|
||||
/* unsupported opcode */
|
||||
default:
|
||||
glpsRacpSendRsp(connId, opcode, CH_RACP_RSP_OPCODE_NOT_SUP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* else invalid operands; send response with failure status */
|
||||
else
|
||||
{
|
||||
glpsRacpSendRsp(connId, opcode, status);
|
||||
}
|
||||
|
||||
/* procedure now in progress */
|
||||
glpsCb.inProgress = TRUE;
|
||||
|
||||
return ATT_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the supported features of the glucose sensor.
|
||||
*
|
||||
* \param feature Feature bitmask.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsSetFeature(uint16_t feature)
|
||||
{
|
||||
uint8_t buf[2] = {UINT16_TO_BYTES(feature)};
|
||||
|
||||
AttsSetAttr(GLS_GLF_HDL, sizeof(buf), buf);
|
||||
}
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Set the CCCD index used by the application for glucose service characteristics.
|
||||
*
|
||||
* \param glmCccIdx Glucose measurement CCCD index.
|
||||
* \param glmcCccIdx Glucose measurement context CCCD index.
|
||||
* \param racpCccIdx Record access control point CCCD index.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void GlpsSetCccIdx(uint8_t glmCccIdx, uint8_t glmcCccIdx, uint8_t racpCccIdx)
|
||||
{
|
||||
glpsCb.glmCccIdx = glmCccIdx;
|
||||
glpsCb.glmcCccIdx = glmCccIdx;
|
||||
glpsCb.racpCccIdx = racpCccIdx;
|
||||
}
|
||||
|
||||
Vendored
+167
@@ -0,0 +1,167 @@
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief Glucose profile sensor internal interfaces.
|
||||
*
|
||||
* Copyright (c) 2012-2018 Arm Ltd.
|
||||
*
|
||||
* Copyright (c) 2019 Packetcraft, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
#ifndef GLPS_MAIN_H
|
||||
#define GLPS_MAIN_H
|
||||
|
||||
#include "app_hw.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*! \addtogroup GLUCOSE_PROFILE
|
||||
* \{ */
|
||||
|
||||
/**************************************************************************************************
|
||||
Macros
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Minimum RACP write length */
|
||||
#define GLPS_RACP_MIN_WRITE_LEN 2
|
||||
|
||||
/*! \brief RACP response length */
|
||||
#define GLPS_RACP_RSP_LEN 4
|
||||
|
||||
/*! \brief Glucose RACP number of stored records response length */
|
||||
#define GLPS_RACP_NUM_REC_RSP_LEN 4
|
||||
|
||||
/*! \brief RACP operand maximum length */
|
||||
#define GLPS_OPERAND_MAX ((CH_RACP_GLS_FILTER_TIME_LEN * 2) + 1)
|
||||
|
||||
/**************************************************************************************************
|
||||
Data Types
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \brief Glucose measurement structure */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t flags; /*!< \brief Flags */
|
||||
uint16_t seqNum; /*!< \brief Sequence number */
|
||||
appDateTime_t baseTime; /*!< \brief Base time */
|
||||
int16_t timeOffset; /*!< \brief Time offset */
|
||||
uint16_t concentration; /*!< \brief Glucose concentration (SFLOAT) */
|
||||
uint8_t typeSampleLoc; /*!< \brief Sample type and sample location */
|
||||
uint16_t sensorStatus; /*!< \brief Sensor status annunciation */
|
||||
} glpsGlm_t;
|
||||
|
||||
/*! \brief Glucose measurement context structure */
|
||||
typedef struct
|
||||
{
|
||||
uint8_t flags; /*!< \brief Flags */
|
||||
uint16_t seqNum; /*!< \brief Sequence number */
|
||||
uint8_t extFlags; /*!< \brief Extended Flags */
|
||||
uint8_t carbId; /*!< \brief Carbohydrate ID */
|
||||
uint16_t carb; /*!< \brief Carbohydrate (SFLOAT) */
|
||||
uint8_t meal; /*!< \brief Meal */
|
||||
uint8_t testerHealth; /*!< \brief Tester and health */
|
||||
uint16_t exerDuration; /*!< \brief Exercise Duration */
|
||||
uint8_t exerIntensity; /*!< \brief Exercise Intensity */
|
||||
uint8_t medicationId; /*!< \brief Medication ID */
|
||||
uint16_t medication; /*!< \brief Medication (SFLOAT) */
|
||||
uint16_t hba1c; /*!< \brief HbA1c */
|
||||
} glpsGlmc_t;
|
||||
|
||||
/*! \brief Glucose measurement record */
|
||||
typedef struct
|
||||
{
|
||||
glpsGlm_t meas; /*!< \brief Glucose measurement */
|
||||
glpsGlmc_t context; /*!< \brief Glucose measurement context */
|
||||
} glpsRec_t;
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Initialize the glucose record database.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsDbInit(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the next record that matches the given filter parameters that follows
|
||||
* the given current record.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param pFilter Glucose service RACP filter parameters.
|
||||
* \param pCurrRec Pointer to current record.
|
||||
* \param pRec Return pointer to next record, if found.
|
||||
*
|
||||
* \return \ref CH_RACP_RSP_SUCCESS if a record is found, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t glpsDbGetNextRecord(uint8_t oper, uint8_t *pFilter, glpsRec_t *pCurrRec, glpsRec_t **pRec);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Delete records that match the given filter parameters.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param pFilter Glucose service RACP filter parameters.
|
||||
*
|
||||
* \return \ref CH_RACP_RSP_SUCCESS if records deleted, otherwise an error status is returned.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t glpsDbDeleteRecords(uint8_t oper, uint8_t *pFilter);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Get the number of records matching the filter parameters.
|
||||
*
|
||||
* \param oper Operator.
|
||||
* \param pFilter Glucose service RACP filter parameters.
|
||||
* \param pNumRec Returns number of records which match filter parameters.
|
||||
|
||||
*
|
||||
* \return RACP status.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
uint8_t glpsDbGetNumRecords(uint8_t oper, uint8_t *pFilter, uint8_t *pNumRec);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief Generate a new record.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsDbGenerateRecord(void);
|
||||
|
||||
/*************************************************************************************************/
|
||||
/*!
|
||||
* \brief For conformance testing only. Toggle the sample data record number 2's medication
|
||||
* quantity unit flag between Kilograms and Liters. Also modifies quantity.
|
||||
*
|
||||
* \return None.
|
||||
*/
|
||||
/*************************************************************************************************/
|
||||
void glpsDbToggleMedicationUnits(void);
|
||||
|
||||
/*! \} */ /* GLUCOSE_PROFILE */
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* GLPS_MAIN_H */
|
||||
Reference in New Issue
Block a user