Commit d8dd071a authored by schneider's avatar schneider
Browse files

Merge branch 'schneider/ble-time' into 'master'

Read date/time from iOS device

See merge request card10/firmware!406
parents f2d4062f 2293c62a
#pragma once
#include <stdint.h>
#include "wsf_types.h"
#include "att_api.h"
#include "dm_api.h"
#define CARD10_UUID_SUFFIX \
0x42, 0x23, 0x42, 0x23, 0x42, 0x23, 0x42, 0x23, 0x42, 0x23, 0x42, 0x23
#define CARD10_UUID_PREFIX 0x02, 0x23, 0x42
......@@ -16,3 +22,7 @@
/*************************************************************************************************/
void BleStart(void);
/* ATT client module interface. Used by main BLE module */
void bleValueUpdate(attEvt_t *pMsg);
void bleDiscCback(dmConnId_t connId, uint8_t status);
#include <stdint.h>
#include <stdbool.h>
#include "wsf_types.h"
#include "util/bstream.h"
#include "app_api.h"
#include "app_cfg.h"
#include "att_api.h"
#include "dm_api.h"
#include "gatt/gatt_api.h"
#include "gap/gap_api.h"
#include "tipc/tipc_api.h"
#include "modules/log.h"
/* card10:
* copied from lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/apps/tag/tag_main.c
* and lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/apps/watch/watch_main.c
*/
/* clang-format off */
/* clang-formet turned off for easier diffing against orginal file */
/**************************************************************************************************
ATT Client Discovery Data
**************************************************************************************************/
static uint16_t s_hdlList[APP_DB_HDL_LIST_LEN];
/*! the Client handle list, s_hdlList[], is set as follows:
*
* ------------------------------- <- BLE_DISC_GATT_START
* | GATT svc changed handle |
* -------------------------------
* | GATT svc changed ccc handle |
* ------------------------------- <- BLE_DISC_GAP_START
* | GAP central addr res handle |
* -------------------------------
* | GAP RPA Only handle |
* ------------------------------- <- BLE_DISC_CTS_START
* | TIPC_CTS_CT_HDL_IDX |
* -------------------------------
* | TIPC_CTS_CT_CCC_HDL_IDX |
* -------------------------------
* | TIPC_CTS_LTI_HDL_IDX |
* -------------------------------
* | TIPC_CTS_RTI_HDL_IDX |
* -------------------------------
*/
/*! Start of each service's handles in the the handle list */
#define BLE_DISC_GATT_START 0
#define BLE_DISC_GAP_START (BLE_DISC_GATT_START + GATT_HDL_LIST_LEN)
#define BLE_DISC_CTS_START (BLE_DISC_GAP_START + GAP_HDL_LIST_LEN)
#define BLE_DISC_HDL_LIST_LEN (BLE_DISC_CTS_START + TIPC_CTS_HDL_LIST_LEN)
/*! Pointers into handle list for each service's handles */
static uint16_t *pBleGattHdlList = &s_hdlList[BLE_DISC_GATT_START];
static uint16_t *pBleGapHdlList = &s_hdlList[BLE_DISC_GAP_START];
static uint16_t *pBleCtsHdlList = &s_hdlList[BLE_DISC_CTS_START];
/* sanity check: make sure handle list length is <= app db handle list length */
extern char wsf_ct_assert[(BLE_DISC_HDL_LIST_LEN <= APP_DB_HDL_LIST_LEN) ? 1 : -1];
/**************************************************************************************************
ATT Client Data
**************************************************************************************************/
/* Default value for GATT service changed ccc descriptor */
static const uint8_t bleGattScCccVal[] = {UINT16_TO_BYTES(ATT_CLIENT_CFG_INDICATE)};
/* List of characteristics to configure */
static const attcDiscCfg_t bleDiscCfgList[] =
{
/* Write: GATT service changed ccc descriptor */
{bleGattScCccVal, sizeof(bleGattScCccVal), (GATT_SC_CCC_HDL_IDX + BLE_DISC_GATT_START)},
/* Read: GAP central address resolution attribute */
{NULL, 0, (GAP_CAR_HDL_IDX + BLE_DISC_GAP_START)},
/* Read: CTS Current time */
{NULL, 0, (TIPC_CTS_CT_HDL_IDX + BLE_DISC_CTS_START)},
/* Read: CTS Local time information */
{NULL, 0, (TIPC_CTS_LTI_HDL_IDX + BLE_DISC_CTS_START)},
/* Read: CTS Reference time information */
{NULL, 0, (TIPC_CTS_RTI_HDL_IDX + BLE_DISC_CTS_START)},
};
/* Characteristic configuration list length */
#define BLE_DISC_CFG_LIST_LEN (sizeof(bleDiscCfgList) / sizeof(attcDiscCfg_t))
/* sanity check: make sure configuration list length is <= handle list length */
extern char wsf_ct_assert[(BLE_DISC_CFG_LIST_LEN <= BLE_DISC_HDL_LIST_LEN) ? 1 : -1];
/**************************************************************************************************
ATT Client Discovery Data
**************************************************************************************************/
/*! Discovery states: enumeration of services to be discovered */
enum
{
BLE_DISC_GATT_SVC, /* GATT service */
BLE_DISC_GAP_SVC, /* GAP service */
BLE_DISC_SLAVE_CTS_SVC,
BLE_DISC_SVC_MAX /* Discovery complete */
};
/*************************************************************************************************/
/*!
* \brief Process a received ATT indication.
*
* \param pMsg Pointer to ATT callback event message.
*
* \return None.
*/
/*************************************************************************************************/
void bleValueUpdate(attEvt_t *pMsg)
{
if (pMsg->hdr.status == ATT_SUCCESS)
{
/* determine which profile the handle belongs to */
/* GATT */
if (GattValueUpdate(pBleGattHdlList, pMsg) == ATT_SUCCESS)
{
return;
}
/* GAP */
if (GapValueUpdate(pBleGapHdlList, pMsg) == ATT_SUCCESS)
{
return;
}
/* current time */
if (TipcCtsValueUpdate(pBleCtsHdlList, pMsg) == ATT_SUCCESS)
{
return;
}
}
}
/*************************************************************************************************/
/*!
* \brief GAP service discovery has completed.
*
* \param connId Connection identifier.
*
* \return None.
*/
/*************************************************************************************************/
static void bleDiscGapCmpl(dmConnId_t connId)
{
appDbHdl_t dbHdl;
/* if RPA Only attribute found on peer device */
if ((pBleGapHdlList[GAP_RPAO_HDL_IDX] != ATT_HANDLE_NONE) &&
((dbHdl = AppDbGetHdl(connId)) != APP_DB_HDL_NONE))
{
/* update DB */
AppDbSetPeerRpao(dbHdl, TRUE);
}
}
/*************************************************************************************************/
/*!
* \brief Discovery callback.
*
* \param connId Connection identifier.
* \param status Service or configuration status.
*
* \return None.
*/
/*************************************************************************************************/
void bleDiscCback(dmConnId_t connId, uint8_t status)
{
static uint8_t discState;
static const char * const disc_status[] = {
"APP_DISC_INIT", /*!< \brief No discovery or configuration complete */
"APP_DISC_SEC_REQUIRED", /*!< \brief Security required to complete configuration */
"APP_DISC_START", /*!< \brief Service discovery started */
"APP_DISC_CMPL", /*!< \brief Service discovery complete */
"APP_DISC_FAILED", /*!< \brief Service discovery failed */
"APP_DISC_CFG_START", /*!< \brief Service configuration started */
"APP_DISC_CFG_CONN_START", /*!< \brief Configuration for connection setup started */
"APP_DISC_CFG_CMPL" /*!< \brief Service configuration complete */
};
LOG_INFO("ble", "bleDiscCback: %s (%d)", disc_status[status], status);
switch(status)
{
case APP_DISC_INIT:
/* set handle list when initialization requested */
AppDiscSetHdlList(connId, BLE_DISC_HDL_LIST_LEN, s_hdlList);
break;
case APP_DISC_SEC_REQUIRED:
/* request security */
AppSlaveSecurityReq(connId);
break;
case APP_DISC_START:
/* initialize discovery state */
discState = BLE_DISC_GATT_SVC;
GattDiscover(connId, pBleGattHdlList);
break;
case APP_DISC_FAILED:
case APP_DISC_CMPL:
if (status == APP_DISC_FAILED && pAppCfg->abortDisc)
{
if (discState == BLE_DISC_GATT_SVC)
{
/* discovery failed */
AppDiscComplete(connId, APP_DISC_FAILED);
break;
}
}
/* next discovery state */
discState++;
if (discState == BLE_DISC_GAP_SVC)
{
/* discover GAP service */
GapDiscover(connId, pBleGapHdlList);
}
else if (discState == BLE_DISC_SLAVE_CTS_SVC)
{
/* discover current time service */
TipcCtsDiscover(connId, pBleCtsHdlList);
}
else
{
/* discovery complete */
AppDiscComplete(connId, APP_DISC_CMPL);
/* GAP service discovery completed */
bleDiscGapCmpl(connId);
/* start configuration */
AppDiscConfigure(connId, APP_DISC_CFG_START, BLE_DISC_CFG_LIST_LEN,
(attcDiscCfg_t *) bleDiscCfgList, BLE_DISC_HDL_LIST_LEN, s_hdlList);
}
break;
case APP_DISC_CFG_START:
/* start configuration */
AppDiscConfigure(connId, APP_DISC_CFG_START, BLE_DISC_CFG_LIST_LEN,
(attcDiscCfg_t *) bleDiscCfgList, BLE_DISC_HDL_LIST_LEN, s_hdlList);
break;
case APP_DISC_CFG_CMPL:
AppDiscComplete(connId, APP_DISC_CFG_CMPL);
break;
case APP_DISC_CFG_CONN_START:
/* no connection setup configuration for this application */
break;
default:
break;
}
}
/* clang-format on */
......@@ -143,6 +143,12 @@ static const smpCfg_t bleSmpCfg =
.attemptExp = 2, /*! Exponent to raise attemptTimeout on maxAttempts */
};
/*! Configurable parameters for service and characteristic discovery */
static const appDiscCfg_t bleDiscCfg =
{
FALSE /*! TRUE to wait for a secure connection before initiating discovery */
};
/* Configuration structure */
static const attCfg_t bleAttCfg =
{
......@@ -172,7 +178,11 @@ static const uint8_t bleAdvDataDisc[] =
/*! service UUID list */
17,
DM_ADV_TYPE_128_UUID_PART,
CARD10_UUID_SUFFIX, 0x0, CARD10_UUID_PREFIX
CARD10_UUID_SUFFIX, 0x0, CARD10_UUID_PREFIX,
2, /*! length */
DM_ADV_TYPE_TX_POWER, /*! AD type */
0, /*! tx power */
};
/*! scan data, discoverable mode */
......@@ -181,7 +191,11 @@ uint8_t bleScanDataDisc[] =
/*! device name */
14, /*! length */
DM_ADV_TYPE_LOCAL_NAME, /*! AD type */
'c','a','r','d','1','0','-','0','0','0','0','0','0'
'c','a','r','d','1','0','-','0','0','0','0','0','0',
3, /*! length */
DM_ADV_TYPE_16_SOLICIT, /*! AD type */
UINT16_TO_BYTES(ATT_UUID_CURRENT_TIME_SERVICE),
};
/*! advertising data, connectable mode */
......@@ -676,7 +690,6 @@ static void scannerScanReport(dmEvt_t *pMsg)
}
}
/*************************************************************************************************/
/*!
* \brief Process messages from the event handler.
......@@ -696,6 +709,11 @@ static void bleProcMsg(bleMsg_t *pMsg)
BasProcMsg(&pMsg->hdr);
break;
case ATTC_READ_RSP:
case ATTC_HANDLE_VALUE_IND:
bleValueUpdate((attEvt_t *) pMsg);
break;
case ATTS_HANDLE_VALUE_CNF:
BasProcMsg(&pMsg->hdr);
break;
......@@ -861,10 +879,12 @@ static void BleHandlerInit(void)
pAppSlaveCfg = (appSlaveCfg_t *) &bleSlaveCfg;
pAppSecCfg = (appSecCfg_t *) &bleSecCfg;
pAppUpdateCfg = (appUpdateCfg_t *) &bleUpdateCfg;
pAppDiscCfg = (appDiscCfg_t *) &bleDiscCfg;
pAppMasterCfg = (appMasterCfg_t *) &scannerMasterCfg;
/* Initialize application framework */
AppSlaveInit();
AppDiscInit();
/* Set stack configuration pointers */
pSmpCfg = (smpCfg_t *) &bleSmpCfg;
......@@ -898,10 +918,15 @@ static void BleHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
/* process security-related messages */
AppSlaveSecProcDmMsg((dmEvt_t *) pMsg);
/* process discovery-related messages */
AppDiscProcDmMsg((dmEvt_t *) pMsg);
}
else if (pMsg->event >= ATT_CBACK_START && pMsg->event <= ATT_CBACK_END)
{
LOG_INFO("ble", "Ble got evt %d: %s", pMsg->event, att_events[pMsg->event - ATT_CBACK_START]);
/* process discovery-related ATT messages */
AppDiscProcAttMsg((attEvt_t *) pMsg);
}
else if (pMsg->event >= L2C_COC_CBACK_START && pMsg->event <= L2C_COC_CBACK_CBACK_END)
{
......@@ -936,6 +961,9 @@ void BleStart(void)
AttConnRegister(AppServerConnCback);
AttsCccRegister(BLE_NUM_CCC_IDX, (attsCccSet_t *) bleCccSet, bleCccCback);
/* Register for app framework discovery callbacks */
AppDiscRegister(bleDiscCback);
/* Initialize attribute server database */
SvcCoreAddGroup();
SvcDisAddGroup(); // Device Information Service
......
......@@ -2,6 +2,8 @@ ble_sources = files(
'ble.c',
'stack.c',
'ble_main.c',
'ble_attc.c',
'profiles/tipc_main.c',
'svc_dis.c',
'svc_core.c',
'bondings.c',
......
/*************************************************************************************************/
/*!
* \file
*
* \brief Time profile client.
*
* Copyright (c) 2011-2018 Arm Ltd. All Rights Reserved.
* ARM Ltd. confidential and proprietary.
*
* IMPORTANT. Your use of this file is governed by a Software License Agreement
* ("Agreement") that must be accepted in order to download or otherwise receive a
* copy of this file. You may not use or copy this file for any purpose other than
* as described in the Agreement. If you do not agree to all of the terms of the
* Agreement do not use this file and delete all copies in your possession or control;
* if you do not have a copy of the Agreement, you must contact ARM Ltd. prior
* to any use, copying or further distribution of this software.
*/
/*************************************************************************************************/
/* card10:
* copied from lib/sdk/Libraries/BTLE/stack/ble-profiles/sources/profiles/tipc/tipc_main.c
*/
/* clang-format off */
/* clang-formet turned off for easier diffing against orginal file */
#include "wsf_types.h"
#include "wsf_assert.h"
#include "wsf_trace.h"
#include "util/bstream.h"
#include "app_api.h"
#include "tipc/tipc_api.h"
#include "epicardium.h"
#include <time.h>
#include <stdio.h>
/**************************************************************************************************
Local Variables
**************************************************************************************************/
static time_t s_time;
/*!
* Current Time service
*/
/* Characteristics for discovery */
/*! Current time */
static const attcDiscChar_t tipcCtsCt =
{
attCtChUuid,
ATTC_SET_REQUIRED
};
/*! Current time client characteristic configuration descriptor */
static const attcDiscChar_t tipcCtsCtCcc =
{
attCliChCfgUuid,
ATTC_SET_REQUIRED | ATTC_SET_DESCRIPTOR
};
/*! Local time information */
static const attcDiscChar_t tipcCtsLti =
{
attLtiChUuid,
0
};
/*! Reference time information */
static const attcDiscChar_t tipcCtsRti =
{
attRtiChUuid,
0
};
/*! List of characteristics to be discovered; order matches handle index enumeration */
static const attcDiscChar_t *tipcCtsDiscCharList[] =
{
&tipcCtsCt, /* Current time */
&tipcCtsCtCcc, /* Current time client characteristic configuration descriptor */
&tipcCtsLti, /* Local time information */
&tipcCtsRti /* Reference time information */
};
/* sanity check: make sure handle list length matches characteristic list length */
WSF_CT_ASSERT(TIPC_CTS_HDL_LIST_LEN == ((sizeof(tipcCtsDiscCharList) / sizeof(attcDiscChar_t *))));
/*************************************************************************************************/
/*!
* \brief Perform service and characteristic discovery for Current Time service. Parameter
* pHdlList must point to an array of length TIPC_CTS_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 TipcCtsDiscover(dmConnId_t connId, uint16_t *pHdlList)
{
AppDiscFindService(connId, ATT_16_UUID_LEN, (uint8_t *) attCtsSvcUuid,
TIPC_CTS_HDL_LIST_LEN, (attcDiscChar_t **) tipcCtsDiscCharList, pHdlList);
}
/*************************************************************************************************/
/*!
* \brief Process a value received in an ATT read response, notification, or indication
* message. Parameter pHdlList must point to an array of length TIPC_CTS_HDL_LIST_LEN.
* If the attribute handle of the message matches a handle in the handle list the value
* is processed, otherwise it is ignored.
*
* \param pHdlList Characteristic handle list.
* \param pMsg ATT callback message.
*
* \return ATT_SUCCESS if handle is found, ATT_ERR_NOT_FOUND otherwise.
*/
/*************************************************************************************************/
uint8_t TipcCtsValueUpdate(uint16_t *pHdlList, attEvt_t *pMsg)
{
uint8_t status = ATT_SUCCESS;
uint8_t *p;
uint16_t year;
uint8_t month, day, hour, min, sec, dayOfWeek, adjustReason;
uint8_t sec256 = 0;
int8_t timeZone;
uint8_t dstOffset, source, accuracy;
/* Suppress unused variable compile warning */
(void)month; (void)day; (void)hour; (void)min; (void)sec; (void)dayOfWeek; (void)adjustReason;
(void)year; (void)sec256; (void)dstOffset; (void)accuracy; (void)timeZone; (void)source;
/* current time */
if (pMsg->handle == pHdlList[TIPC_CTS_CT_HDL_IDX])
{
/* parse value */
p = pMsg->pValue;
BSTREAM_TO_UINT16(year, p);
BSTREAM_TO_UINT8(month, p);
BSTREAM_TO_UINT8(day, p);
BSTREAM_TO_UINT8(hour, p);
BSTREAM_TO_UINT8(min, p);
BSTREAM_TO_UINT8(sec, p);
BSTREAM_TO_UINT8(dayOfWeek, p);
BSTREAM_TO_UINT8(sec256, p);
BSTREAM_TO_UINT8(adjustReason, p);
struct tm t;
t.tm_year = year - 1900;
t.tm_mon = month - 1;
t.tm_mday = day;
t.tm_hour = hour;
t.tm_min = min;
t.tm_sec = sec;
t.tm_isdst = -1; /* unknown */
s_time = mktime(&t);
APP_TRACE_INFO3("Date: %d/%d/%d", month, day, year);
APP_TRACE_INFO3("Time: %02d:%02d:%02d", hour, min, sec);
APP_TRACE_INFO3("dayOfWeek:%d sec256:%d adjustReason:%d", dayOfWeek, sec256, adjustReason);
}
/* local time information */
else if (pMsg->handle == pHdlList[TIPC_CTS_LTI_HDL_IDX])
{
/* parse value */
p = pMsg->pValue;
BSTREAM_TO_UINT8(timeZone, p);
BSTREAM_TO_UINT8(dstOffset, p);
APP_TRACE_INFO2("timeZone:%d dstOffset:%d", timeZone, dstOffset);
if(s_time) {
char buf[32];
snprintf(buf, sizeof(buf), "%+05d", (timeZone +dstOffset) / 4 * 100);
epic_config_set_string("timezone", buf);
epic_rtc_set_milliseconds(s_time * 1000 + (1000 * sec256) / 256 - (timeZone + dstOffset) * 15 * 60 * 1000);
}
}
/* reference time information */
else if (pMsg->handle == pHdlList[TIPC_CTS_RTI_HDL_IDX])
{
/* parse value */
p = pMsg->pValue;
BSTREAM_TO_UINT8(source, p);
BSTREAM_TO_UINT8(accuracy, p);
BSTREAM_TO_UINT8(day, p);
BSTREAM_TO_UINT8(hour, p);
APP_TRACE_INFO2("Ref. time source:%d accuracy:%d", source, accuracy);
APP_TRACE_INFO2("Last update days:%d hours:%d", day, hour);
}
/* handle not found in list */
else
{
status = ATT_ERR_NOT_FOUND;
}
return status;
}
/* clang-format on */
......@@ -184,6 +184,7 @@ void StackInit(void)
AttHandlerInit(handlerId);
AttsInit();
AttsIndInit();
AttcInit();
handlerId = WsfOsSetNextHandler(SmpHandler);
SmpHandlerInit(handlerId);
......
......@@ -507,11 +507,17 @@ int epic_config_set_string(const char *key, const char *value_in)
int fd2 = -1;
ret = epic_config_get_string(key, buf, sizeof(buf));
if (ret == 0 && strcmp(buf, value) == 0) {
/* Nothing to do: the values are the same. */
return 0;
}
size_t nread = read_config_offset(
slot->value_offset, buf, sizeof(buf)
);
if (nread == 0) {
LOG_DEBUG("card10.cfg", "could not read old value");
ret = -EIO;
goto complex_out;
}
......