Forked from
card10 / firmware
1448 commits behind the upstream repository.
ble.c 10.23 KiB
#include "wsf_types.h"
#include "wsf_os.h"
#include "wsf_buf.h"
#include "wsf_timer.h"
#include "wsf_trace.h"
#include "app_ui.h"
#include "ble_api.h"
#include "hci_vs.h"
#include "att_defs.h"
#include "util/bstream.h"
#include "att_api.h"
#include "modules/modules.h"
#include "fs_util.h"
#include "FreeRTOS.h"
#include "timers.h"
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
/* Size of buffer for stdio functions */
#define WSF_BUF_POOLS 6
#define WSF_BUF_SIZE 0x1048
uint32_t SystemHeapSize=WSF_BUF_SIZE;
uint32_t SystemHeap[WSF_BUF_SIZE/4];
uint32_t SystemHeapStart;
/* Task ID for the ble handler */
static TaskHandle_t ble_task_id = NULL;
/*! Default pool descriptor. */
static wsfBufPoolDesc_t mainPoolDesc[WSF_BUF_POOLS] =
{
{ 16, 8 },
{ 32, 4 },
{ 64, 4 },
{ 128, 4 },
{ 256, 4 },
{ 512, 4 }
};
/*! \brief Stack initialization for app. */
extern void StackInit(void);
extern void AppInit(void);
/*************************************************************************************************/
void PalSysAssertTrap(void)
{
while(1) {}
}
/*************************************************************************************************/
static bool_t myTrace(const uint8_t *pBuf, uint32_t len)
{
extern uint8_t wsfCsNesting;
if (wsfCsNesting == 0)
{
fwrite(pBuf, len, 1, stdout);
return TRUE;
}
return FALSE;
}
/*************************************************************************************************/
/*!
* \brief Initialize WSF.
*
* \return None.
*/
/*************************************************************************************************/
static void WsfInit(void)
{
uint32_t bytesUsed;
WsfTimerInit();
SystemHeapStart = (uint32_t)&SystemHeap;
memset(SystemHeap, 0, sizeof(SystemHeap));
//printf("SystemHeapStart = 0x%x\n", SystemHeapStart);
//printf("SystemHeapSize = 0x%x\n", SystemHeapSize);
bytesUsed = WsfBufInit(WSF_BUF_POOLS, mainPoolDesc);
printf("bytesUsed = %u\n", (unsigned int)bytesUsed);
WsfTraceRegisterHandler(myTrace);
WsfTraceEnable(TRUE);
}
/* TODO: We need a source of MACs */
static void setAddress(void)
{
uint8_t bdAddr[6] = {0x02, 0x02, 0x44, 0x8B, 0x05, 0x00};
char buf[32];
fs_read_text_file("mac.txt", buf, sizeof(buf));
printf("mac file: %s\n", buf);
int a, b, c, d, e, f;
if(sscanf(buf, "%x:%x:%x:%x:%x:%x", &a, &b, &c, &d, &e, &f) == 6) {
bdAddr[0] = f;
bdAddr[1] = e;
bdAddr[2] = d;
bdAddr[3] = c;
bdAddr[4] = b;
bdAddr[5] = a;
}
printf("Setting address -- MAC %02X:%02X:%02X:%02X:%02X:%02X\n", bdAddr[5], bdAddr[4], bdAddr[3], bdAddr[2], bdAddr[1], bdAddr[0]);
HciVsSetBdAddr(bdAddr);
}
static StaticTimer_t x;
TimerHandle_t timerWakeup = NULL;
int lasttick = 0;
bool schedule_needed = false;
static void vTimerCallback(xTimerHandle pxTimer)
{
//printf("wake\n");
int tick = xTaskGetTickCount();
//printf("WsfTimerUpdate(%d)\n", tick - lasttick);
WsfTimerUpdate(tick - lasttick);
lasttick = tick;
//printf("done\n");
}
static void notify(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if(xPortIsInsideInterrupt()) {
vTaskNotifyGiveFromISR(ble_task_id, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
} else {
xTaskNotifyGive(ble_task_id);
}
}
void WsfTimerNotify(void)
{
//printf("WsfTimerNotify\n");
// TODO: Can we do this without waking up the task?
// xTimerChangePeriodFromISR exists
notify();
}
void wsf_ble_signal_event(void)
{
//printf("wsf_ble_signal_event\n");
notify();
}
static void scheduleTimer(void)
{
bool_t timerRunning;
wsfTimerTicks_t time_to_next_expire;
vTimerCallback(NULL);
time_to_next_expire = WsfTimerNextExpiration(&timerRunning);
if(timerRunning) {
//printf("time_to_next_expire = %d\n", time_to_next_expire);
//printf("change period\n");
if(timerWakeup != NULL) {
xTimerChangePeriod(timerWakeup, pdMS_TO_TICKS(time_to_next_expire), 0);
//printf("insert done\n");
} else {
printf("could not create timer\n");
}
} else {
printf("No timer running\n");
}
}
#define UART_START_HDL 0x800 /*!< \brief Service start handle. */
#define UART_END_HDL (BATT_MAX_HDL - 1) /*!< \brief Service end handle. */
/**************************************************************************************************
Handles
**************************************************************************************************/
/*! \brief UART Service Handles */
enum
{
UART_SVC_HDL = UART_START_HDL, /*!< \brief UART service declaration */
UART_RX_CH_HDL, /*!< \brief UART rx characteristic */
UART_RX_HDL, /*!< \brief UART rx value */
UART_TX_CH_HDL, /*!< \brief UART tx characteristic */
UART_TX_HDL, /*!< \brief UART tx value */
UART_TX_CH_CCC_HDL, /*!< \brief UART tx CCCD */
BATT_MAX_HDL /*!< \brief Maximum handle. */
};
/**@}*/
static const uint8_t UARTSvc[] = {0x9E,0xCA,0xDC,0x24,0x0E,0xE5,0xA9,0xE0,0x93,0xF3,0xA3,0xB5,0x01,0x00,0x40,0x6E};
static const uint8_t uartRxCh[] = {ATT_PROP_WRITE, UINT16_TO_BYTES(UART_RX_HDL), 0x9E,0xCA,0xDC,0x24,0x0E,0xE5,0xA9,0xE0,0x93,0xF3,0xA3,0xB5,0x02,0x00,0x40,0x6E};
const uint8_t attUartRxChUuid[] = {0x9E,0xCA,0xDC,0x24,0x0E,0xE5, 0xA9,0xE0,0x93,0xF3,0xA3,0xB5,0x02,0x00,0x40,0x6E};
static const uint8_t uartTxCh[] = {ATT_PROP_READ | ATT_PROP_NOTIFY, UINT16_TO_BYTES(UART_TX_HDL), 0x9E,0xCA,0xDC,0x24,0x0E,0xE5,0xA9,0xE0,0x93,0xF3,0xA3,0xB5,0x03,0x00,0x40,0x6E};
const uint8_t attUartTxChUuid[] = {0x9E,0xCA,0xDC,0x24,0x0E,0xE5, 0xA9,0xE0,0x93,0xF3,0xA3,0xB5,0x03,0x00,0x40,0x6E};
/* Battery level client characteristic configuration */
void *SvcUARTAddGroupDyn(void)
{
void *pSHdl;
uint8_t initCcc[] = {UINT16_TO_BYTES(0x0000)};
uint8_t initUARTVal[] = {0x20};
/* Create the service */
pSHdl = AttsDynCreateGroup(UART_START_HDL, UART_END_HDL);
if (pSHdl != NULL)
{
/* Primary service */
AttsDynAddAttrConst(pSHdl, attPrimSvcUuid, UARTSvc, sizeof(UARTSvc), 0, ATTS_PERMIT_READ);
/* UART rx characteristic */
AttsDynAddAttrConst(pSHdl, attChUuid, uartRxCh, sizeof(uartRxCh), 0, ATTS_PERMIT_READ);
// XXX: attUartRxChUuid is 16 bytes but nothing says so....
/* UART rx value */
// XXX: not sure if max value of 128 is fine...
AttsDynAddAttr(pSHdl, attUartRxChUuid, NULL, 0, 128,
ATTS_SET_WRITE_CBACK | ATTS_SET_VARIABLE_LEN, ATTS_PERMIT_WRITE);
/* UART tx characteristic */
AttsDynAddAttrConst(pSHdl, attChUuid, uartTxCh, sizeof(uartTxCh), 0, ATTS_PERMIT_READ);
/* UART tx value */
/* TODO: do we need ATTS_SET_READ_CBACK ? */
AttsDynAddAttr(pSHdl, attUartTxChUuid, initUARTVal, sizeof(uint8_t), sizeof(uint8_t),
ATTS_SET_READ_CBACK, ATTS_PERMIT_READ);
/* UART tx CCC descriptor */
AttsDynAddAttr(pSHdl, attCliChCfgUuid, initCcc, sizeof(uint16_t), sizeof(uint16_t),
ATTS_SET_CCC, ATTS_PERMIT_READ | ATTS_PERMIT_WRITE);
}
return pSHdl;
}
dmConnId_t active_connection = 0;
uint8_t UARTReadCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
uint16_t offset, attsAttr_t *pAttr)
{
//AppHwBattRead(pAttr->pValue);
printf("read callback\n");
return ATT_SUCCESS;
}
uint8_t UARTWriteCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
uint16_t offset, uint16_t len, uint8_t *pValue,
attsAttr_t *pAttr)
{
active_connection = connId;
//printf("UARTWriteCback %d: ", len);
int i;
for(i=0; i<len; i++) {
//printf("%c", pValue[i]);
serial_enqueue_char(pValue[i]);
}
serial_enqueue_char('\r');
//printf("\n");
#if 0
AttsSetAttr(UART_TX_HDL, len, pValue);
AttsHandleValueNtf(connId, UART_TX_HDL, len, pValue);
#endif
return ATT_SUCCESS;
}
uint8_t ble_uart_tx_buf[129];
uint8_t ble_uart_buf_tx_fill;
int ble_uart_lasttick = 0;
void ble_uart_write(uint8_t *pValue, uint8_t len)
{
int i;
for(i=0; i<len; i++) {
if(pValue[i] >= 0x20 && pValue[i] < 0x7f) {
ble_uart_tx_buf[ble_uart_buf_tx_fill] = pValue[i];
ble_uart_buf_tx_fill++;
} else if(pValue[i] == '\r' || pValue[i] == '\n') {
if(ble_uart_buf_tx_fill > 0) {
AttsSetAttr(UART_TX_HDL, ble_uart_buf_tx_fill, ble_uart_tx_buf);
if(active_connection) {
int x = xTaskGetTickCount() - ble_uart_lasttick;
if(x < 100) {
// Ugly hack if we already send something recently.
// TODO: figure out how these notifications are acknowledged
vTaskDelay(100 - x);
}
//printf("notify: ");
//int j;
//for(j=0;j<ble_uart_buf_tx_fill;j++) {
// printf("%02x ", ble_uart_tx_buf[j]);
//}
//printf("\n");
AttsHandleValueNtf(active_connection, UART_TX_HDL, ble_uart_buf_tx_fill, ble_uart_tx_buf);
ble_uart_lasttick = xTaskGetTickCount();
}
ble_uart_buf_tx_fill = 0;
}
}
}
}
static void ble_init(void)
{
WsfInit();
StackInit();
setAddress();
NVIC_SetPriority(BTLE_SFD_TO_IRQn, 2);
NVIC_SetPriority(BTLE_TX_DONE_IRQn, 2);
NVIC_SetPriority(BTLE_RX_RCVD_IRQn, 2);
AppInit();
BleStart();
/* Add the UART service dynamically */
AttsDynInit();
void *pSHdl;
pSHdl = SvcUARTAddGroupDyn();
AttsDynRegister(pSHdl, UARTReadCback, UARTWriteCback);
//AttsDynRegister(pSHdl, NULL, UARTWriteCback);
lasttick = xTaskGetTickCount();
timerWakeup = xTimerCreateStatic(
"timerWakeup", /* name */
pdMS_TO_TICKS(1), /* period/time */
pdFALSE, /* auto reload */
NULL, /* timer ID */
vTimerCallback, &x); /* callback */
}
void vBleTask(void*pvParameters)
{
ble_task_id = xTaskGetCurrentTaskHandle();
ble_init();
while (1){
ulTaskNotifyTake(pdTRUE, portTICK_PERIOD_MS * 1000);
wsfOsDispatcher();
scheduleTimer();
}
}