From 6c41c7a3ddd54cc17001fe45a1a33ff7118e0c02 Mon Sep 17 00:00:00 2001
From: schneider <schneider@blinkenlichts.net>
Date: Sun, 14 Jul 2019 18:57:39 +0200
Subject: [PATCH] feat(epicardium): Add experimental BLE console

---
 epicardium/modules/ble.c     | 142 ++++++++++++++++++++++++++++++++++-
 epicardium/modules/modules.h |   6 +-
 epicardium/modules/serial.c  |   9 ++-
 3 files changed, 151 insertions(+), 6 deletions(-)

diff --git a/epicardium/modules/ble.c b/epicardium/modules/ble.c
index 7e0ab68c..dfb332e5 100644
--- a/epicardium/modules/ble.c
+++ b/epicardium/modules/ble.c
@@ -7,6 +7,12 @@
 #include "fit/fit_api.h"
 #include "hci_vs.h"
 
+#include "att_defs.h"
+#include "util/bstream.h"
+#include "att_api.h"
+
+#include "modules.h"
+
 #include "FreeRTOS.h"
 #include "timers.h"
 
@@ -26,7 +32,6 @@ 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] =
 {
@@ -164,6 +169,133 @@ static void scheduleTimer(void)
     }
 }
 
+#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),
+                   0, 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;
+
+#if 0
+uint8_t UARTReadCback(dmConnId_t connId, uint16_t handle, uint8_t operation,
+                     uint16_t offset, attsAttr_t *pAttr)
+{
+  //AppHwBattRead(pAttr->pValue);
+
+  return ATT_SUCCESS;
+}
+#endif
+
+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;
+
+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') {
+        if(ble_uart_buf_tx_fill > 0) {
+            AttsSetAttr(UART_TX_HDL, ble_uart_buf_tx_fill, ble_uart_tx_buf);
+            if(active_connection) {
+                AttsHandleValueNtf(active_connection, UART_TX_HDL, ble_uart_buf_tx_fill, ble_uart_tx_buf);
+            }
+            ble_uart_buf_tx_fill = 0;
+        }
+    }
+  }
+}
+
+
 static void ble_init(void)
 {
     WsfInit();
@@ -173,6 +305,14 @@ static void ble_init(void)
     NVIC_SetPriority(BTLE_RX_RCVD_IRQn, 2);
     FitStart();
 
+    /* Add the UART service dynamically */
+    AttsDynInit();
+    void *pSHdl;
+    pSHdl = SvcUARTAddGroupDyn();
+    //AttsDynRegister(pSHdl, UARTReadCback, UARTWriteCback);
+    AttsDynRegister(pSHdl, NULL, UARTWriteCback);
+
+
     /* Register a handler for Application events */
     AppUiActionRegister(SetAddress);
 
diff --git a/epicardium/modules/modules.h b/epicardium/modules/modules.h
index 182fdae7..ac6186ad 100644
--- a/epicardium/modules/modules.h
+++ b/epicardium/modules/modules.h
@@ -15,13 +15,17 @@ void fatfs_init(void);
 #define SERIAL_READ_BUFFER_SIZE 128
 void vSerialTask(void *pvParameters);
 
+void serial_enqueue_char(char chr);
+
 /* ---------- PMIC --------------------------------------------------------- */
 /* In 1/10s */
 #define PMIC_PRESS_SLEEP           20
 #define PMIC_PRESS_POWEROFF        40
 void vPmicTask(void *pvParameters);
 
+/* ---------- BLE ---------------------------------------------------------- */
+void ble_uart_write(uint8_t *pValue, uint8_t len);
+
 // Forces an unlock of the display. Only to be used in epicardium
 void disp_forcelock();
-
 #endif /* MODULES_H */
diff --git a/epicardium/modules/serial.c b/epicardium/modules/serial.c
index 8cffa3ac..db188ebe 100644
--- a/epicardium/modules/serial.c
+++ b/epicardium/modules/serial.c
@@ -29,6 +29,7 @@ void epic_uart_write_str(const char *str, intptr_t length)
 {
 	UART_Write(ConsoleUart, (uint8_t *)str, length);
 	cdcacm_write((uint8_t *)str, length);
+	ble_uart_write((uint8_t *)str, length);
 }
 
 /*
@@ -72,7 +73,7 @@ static void uart_callback(uart_req_t *req, int error)
 	portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
 }
 
-static void enqueue_char(char chr)
+void serial_enqueue_char(char chr)
 {
 	if (chr == 0x3) {
 		/* Control-C */
@@ -122,15 +123,15 @@ void vSerialTask(void *pvParameters)
 		ulTaskNotifyTake(pdTRUE, portTICK_PERIOD_MS * 1000);
 
 		if (read_req.num > 0) {
-			enqueue_char(*read_req.data);
+			serial_enqueue_char(*read_req.data);
 		}
 
 		while (UART_NumReadAvail(ConsoleUart) > 0) {
-			enqueue_char(UART_ReadByte(ConsoleUart));
+			serial_enqueue_char(UART_ReadByte(ConsoleUart));
 		}
 
 		while (cdcacm_num_read_avail() > 0) {
-			enqueue_char(cdcacm_read());
+			serial_enqueue_char(cdcacm_read());
 		}
 	}
 }
-- 
GitLab