From e21f41368e2a6be9a8d1134d0d3d895879760c10 Mon Sep 17 00:00:00 2001
From: schneider <schneider@blinkenlichts.net>
Date: Mon, 7 Dec 2020 04:08:23 +0100
Subject: [PATCH] feat(ess): Add card10 IAQ and CO2 measurements

---
 epicardium/ble/ble_main.c |  2 ++
 epicardium/ble/cccd.h     |  1 +
 epicardium/ble/ess.c      | 65 ++++++++++++++++++++++++++++++++++++++-
 epicardium/ble/ess.h      |  4 +++
 4 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/epicardium/ble/ble_main.c b/epicardium/ble/ble_main.c
index 2e7a5cef4..6e7e11227 100644
--- a/epicardium/ble/ble_main.c
+++ b/epicardium/ble/ble_main.c
@@ -263,6 +263,7 @@ static const attsCccSet_t bleCccSet[BLE_NUM_CCC_IDX] =
   {HID_INPUT_REPORT_1_CH_CCC_HDL,       ATT_CLIENT_CFG_NOTIFY,    DM_SEC_LEVEL_NONE},    /* HIDAPP_IN_KEYBOARD_CCC_HDL */
   {HID_INPUT_REPORT_2_CH_CCC_HDL,       ATT_CLIENT_CFG_NOTIFY,    DM_SEC_LEVEL_NONE},    /* HIDAPP_IN_MOUSE_CCC_HDL */
   {HID_INPUT_REPORT_3_CH_CCC_HDL,       ATT_CLIENT_CFG_NOTIFY,    DM_SEC_LEVEL_NONE},    /* HIDAPP_IN_CONSUMER_CCC_HDL */
+  {ESS_IAQ_CH_CCC_HDL,    ATT_CLIENT_CFG_NOTIFY,    DM_SEC_LEVEL_NONE},   /* BLE_ESS_IAQ_CCC_IDX */
 };
 
 /**************************************************************************************************
@@ -485,6 +486,7 @@ static void bleProcCccState(bleMsg_t *pMsg)
     case BLE_ESS_TEMP_CCC_IDX:
     case BLE_ESS_HUMI_CCC_IDX:
     case BLE_ESS_PRES_CCC_IDX:
+    case BLE_ESS_IAQ_CCC_IDX:
       bleESS_ccc_update();
     break;
   };
diff --git a/epicardium/ble/cccd.h b/epicardium/ble/cccd.h
index ea91c6306..5c3edf3cb 100644
--- a/epicardium/ble/cccd.h
+++ b/epicardium/ble/cccd.h
@@ -12,6 +12,7 @@ enum
   HIDAPP_IN_KEYBOARD_CCC_HDL,           /*! HID Input Report characteristic for keyboard inputs */
   HIDAPP_IN_MOUSE_CCC_HDL,              /*! HID Input Report characteristic for mouse inputs */
   HIDAPP_IN_CONSUMER_CCC_HDL,             /*! HID Input Report characteristic for consumer control inputs */
+  BLE_ESS_IAQ_CCC_IDX,                    /*! Environmental sensing service, IAQ characteristic */
   BLE_NUM_CCC_IDX
 };
 
diff --git a/epicardium/ble/ess.c b/epicardium/ble/ess.c
index f2e31bf1f..8b26a9f90 100644
--- a/epicardium/ble/ess.c
+++ b/epicardium/ble/ess.c
@@ -11,6 +11,8 @@
 #include "modules/log.h"
 #include "modules/modules.h"
 
+#include "ble/ble_api.h"
+
 #include "FreeRTOS.h"
 #include "timers.h"
 
@@ -46,7 +48,19 @@ static const uint8_t UUID_char_pressure[] = {
 	UINT16_TO_BYTES(ATT_UUID_PRESSURE)
 };
 
+/* BLE UUID for IAQ */
+static const uint8_t UUID_char_IAQ[] = {
+	ATT_PROP_READ | ATT_PROP_NOTIFY,
+	UINT16_TO_BYTES(ESS_IAQ_VAL_HDL),
+	CARD10_UUID_SUFFIX, 0xf1, CARD10_UUID_PREFIX
+};
+static const uint8_t UUID_attChar_IAQ[] = {
+	CARD10_UUID_SUFFIX, 0xf1, CARD10_UUID_PREFIX
+};
+
+
 static const uint16_t UUID_char_len = sizeof(UUID_char_temperature);
+static const uint16_t UUID_char_IAQ_len = sizeof(UUID_char_IAQ);
 
 static uint8_t initTemperatureValue[] = { UINT16_TO_BYTES(0) };
 static uint16_t initTemperatureLen = sizeof(initTemperatureValue);
@@ -57,6 +71,9 @@ static uint16_t initHumidityLen = sizeof(initHumidityValue);
 static uint8_t initPressureValue[] = { UINT32_TO_BYTES(0) };
 static uint16_t initPressureLen = sizeof(initPressureValue);
 
+static uint8_t initIAQValue[] = {0x00, UINT16_TO_BYTES(0), UINT16_TO_BYTES(0)};
+static uint16_t initIAQLen = sizeof(initIAQValue);
+
 /* Temperature client characteristic configuration */
 static uint8_t essValTempChCcc[] = {UINT16_TO_BYTES(0x0000)};
 static const uint16_t essLenTempChCcc = sizeof(essValTempChCcc);
@@ -69,6 +86,10 @@ static const uint16_t essLenHumidityChCcc = sizeof(essValHumidityChCcc);
 static uint8_t essValPressureChCcc[] = {UINT16_TO_BYTES(0x0000)};
 static const uint16_t essLenPressureChCcc = sizeof(essValPressureChCcc);
 
+/* IAQ client characteristic configuration */
+static uint8_t essValIAQChCcc[] = {UINT16_TO_BYTES(0x0000)};
+static const uint16_t essLenIAQChCcc = sizeof(essValIAQChCcc);
+
 /* clang-format on */
 
 /*
@@ -171,6 +192,35 @@ static const attsAttr_t ESSSvcAttrList[] = {
 			 ATTS_PERMIT_WRITE) // How about security?
 	},
 
+	// IAQ
+	{
+		.pUuid       = attChUuid,
+		.pValue      = (uint8_t *)UUID_char_IAQ,
+		.pLen        = (uint16_t *)&UUID_char_IAQ_len,
+		.maxLen      = sizeof(UUID_char_IAQ),
+		.permissions = ATTS_PERMIT_READ,
+	},
+	{
+		.pUuid       = UUID_attChar_IAQ,
+		.pValue      = initIAQValue,
+		.pLen        = &initIAQLen,
+		.maxLen      = sizeof(initIAQValue),
+		.settings    = ATTS_SET_READ_CBACK,
+		.permissions = ATTS_PERMIT_READ | ATTS_PERMIT_READ_ENC |
+			       ATTS_PERMIT_READ_AUTH,
+	},
+	/* Characteristic CCC descriptor */
+	{
+		.pUuid    = attCliChCfgUuid,
+		.pValue   = essValIAQChCcc,
+		.pLen     = (uint16_t *)&essLenIAQChCcc,
+		.maxLen   = sizeof(essValIAQChCcc),
+		.settings = ATTS_SET_CCC,
+		.permissions =
+			(ATTS_PERMIT_READ |
+			 ATTS_PERMIT_WRITE) // How about security?
+	},
+
 };
 
 // validating that the service really has all charateristics
@@ -257,6 +307,15 @@ static void setAttrFromBME680(struct bme680_sensor_data *data)
 static void setAttrFromBSEC(struct bsec_sensor_data *data)
 {
 	setAttrFromBME680((struct bme680_sensor_data *)data);
+
+	uint16_t iaq            = data->indoor_air_quality;
+	uint8_t accuracy        = data->accuracy;
+	uint16_t co2_equivalent = data->co2_equivalent;
+	uint8_t IAQValue[]      = { accuracy,
+                               UINT16_TO_BYTES(iaq),
+                               UINT16_TO_BYTES(co2_equivalent) };
+
+	AttsSetAttr(ESS_IAQ_VAL_HDL, sizeof(IAQValue), IAQValue);
 }
 
 /*
@@ -306,6 +365,8 @@ static uint8_t readESSCB(
 		);
 		APP_TRACE_INFO1("ble-ess: read pressure: %u\n", pressure);
 		return ATT_SUCCESS;
+	case ESS_IAQ_VAL_HDL:
+		return ATT_SUCCESS;
 	default:
 		APP_TRACE_INFO0("ble-card10: read no handler found\n");
 		return ATT_ERR_HANDLE;
@@ -341,6 +402,7 @@ void bleESS_update_from_bsec_data(struct bsec_sensor_data *data)
 	sendNotification(connId, ESS_TEMPERATURE_VAL_HDL, BLE_ESS_TEMP_CCC_IDX);
 	sendNotification(connId, ESS_HUMIDITY_VAL_HDL, BLE_ESS_HUMI_CCC_IDX);
 	sendNotification(connId, ESS_PRESSURE_VAL_HDL, BLE_ESS_PRES_CCC_IDX);
+	sendNotification(connId, ESS_IAQ_VAL_HDL, BLE_ESS_IAQ_CCC_IDX);
 }
 
 /*
@@ -365,7 +427,8 @@ void bleESS_ccc_update(void)
 	if (connId != DM_CONN_ID_NONE &&
 	    (AttsCccEnabled(connId, BLE_ESS_TEMP_CCC_IDX) ||
 	     AttsCccEnabled(connId, BLE_ESS_HUMI_CCC_IDX) ||
-	     AttsCccEnabled(connId, BLE_ESS_PRES_CCC_IDX))) {
+	     AttsCccEnabled(connId, BLE_ESS_PRES_CCC_IDX) ||
+	     AttsCccEnabled(connId, BLE_ESS_IAQ_CCC_IDX))) {
 		LOG_INFO("ess", "enable periodic measurement");
 		periodic(3000);
 	} else {
diff --git a/epicardium/ble/ess.h b/epicardium/ble/ess.h
index f54d1328b..a58a0af1b 100644
--- a/epicardium/ble/ess.h
+++ b/epicardium/ble/ess.h
@@ -22,6 +22,10 @@ enum {
 	ESS_PRESSURE_CH_HDL,
 	ESS_PRESSURE_VAL_HDL,
 	ESS_PRES_CH_CCC_HDL,                  /*!< Pressure CCCD */
+	/*!< \brief IAQ/CO2 characteristic */
+	ESS_IAQ_CH_HDL,
+	ESS_IAQ_VAL_HDL,
+	ESS_IAQ_CH_CCC_HDL,                   /*!< IAQ CCCD */
 
 
 	/*!< \brief Maximum handle. */
-- 
GitLab