Skip to content
Snippets Groups Projects
ble.c 10.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include "wsf_types.h"
    #include "wsf_os.h"
    #include "wsf_buf.h"
    #include "wsf_timer.h"
    #include "wsf_trace.h"
    #include "app_ui.h"
    
    schneider's avatar
    schneider committed
    #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
    
    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();
    
    static void ble_init(void)
    {
        WsfInit();
    
        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();