diff --git a/epicardium/ble/ble_main.c b/epicardium/ble/ble_main.c
index 431b4310a59cd2b811d1ec39670d8a08023423f4..12c62f2a9313abe28892f8a6ebc5d46259a8770a 100644
--- a/epicardium/ble/ble_main.c
+++ b/epicardium/ble/ble_main.c
@@ -34,6 +34,7 @@
 #include "svc_hrs.h"
 #include "svc_dis.h"
 #include "svc_batt.h"
+#include "svc_hid.h"
 #include "svc_rscs.h"
 #include "bas/bas_api.h"
 #include "hrps/hrps_api.h"
@@ -182,9 +183,9 @@ static const uint8_t bleAdvDataDisc[] =
   DM_ADV_TYPE_128_UUID_PART,
   CARD10_UUID_SUFFIX, 0x0, CARD10_UUID_PREFIX,
 
-  2,                                      /*! length */
-  DM_ADV_TYPE_TX_POWER,                   /*! AD type */
-  0,                                      /*! tx power */
+  3,                                      /*! length */
+  DM_ADV_TYPE_16_UUID_PART,               /*! AD type */
+  UINT16_TO_BYTES(ATT_UUID_HID_SERVICE)
 };
 
 /*! scan data, discoverable mode */
@@ -232,6 +233,11 @@ static const attsCccSet_t bleCccSet[BLE_NUM_CCC_IDX] =
   {ESS_TEMP_CH_CCC_HDL,   ATT_CLIENT_CFG_NOTIFY,    DM_SEC_LEVEL_NONE},   /* BLE_ESS_TEMP_CCC_IDX */
   {ESS_HUMI_CH_CCC_HDL,   ATT_CLIENT_CFG_NOTIFY,    DM_SEC_LEVEL_NONE},   /* BLE_ESS_HUMI_CCC_IDX */
   {ESS_PRES_CH_CCC_HDL,   ATT_CLIENT_CFG_NOTIFY,    DM_SEC_LEVEL_NONE},   /* BLE_ESS_PRES_CCC_IDX */
+  {HID_MOUSE_BOOT_IN_CH_CCC_HDL,        ATT_CLIENT_CFG_NOTIFY,    DM_SEC_LEVEL_NONE},    /* HIDAPP_MBI_CCC_HDL */
+  {HID_KEYBOARD_BOOT_IN_CH_CCC_HDL,     ATT_CLIENT_CFG_NOTIFY,    DM_SEC_LEVEL_NONE},    /* HIDAPP_KBI_CCC_HDL */
+  {HID_INPUT_REPORT_1_CH_CCC_HDL,       ATT_CLIENT_CFG_NOTIFY,    DM_SEC_LEVEL_NONE},    /* HIDAPP_IN_REMOTE_CCC_HDL */
+  {HID_INPUT_REPORT_2_CH_CCC_HDL,       ATT_CLIENT_CFG_NOTIFY,    DM_SEC_LEVEL_NONE},    /* HIDAPP_IN_KEYBOARD_CCC_HDL */
+  {HID_INPUT_REPORT_3_CH_CCC_HDL,       ATT_CLIENT_CFG_NOTIFY,    DM_SEC_LEVEL_NONE},    /* HIDAPP_IN_MOUSE_CCC_HDL */
 };
 
 /**************************************************************************************************
@@ -720,6 +726,7 @@ static void scannerScanReport(dmEvt_t *pMsg)
  *  \return None.
  */
 /*************************************************************************************************/
+void HidProcMsg(wsfMsgHdr_t *pMsg);
 static void bleProcMsg(bleMsg_t *pMsg)
 {
   hciLeConnCmplEvt_t *connOpen;
@@ -737,6 +744,7 @@ static void bleProcMsg(bleMsg_t *pMsg)
 
     case ATTS_HANDLE_VALUE_CNF:
       BasProcMsg(&pMsg->hdr);
+	  HidProcMsg(&pMsg->hdr);
       break;
 
     case ATTS_CCC_STATE_IND:
@@ -771,6 +779,7 @@ static void bleProcMsg(bleMsg_t *pMsg)
                connOpen->peerAddr[1], connOpen->peerAddr[0]);
       BasProcMsg(&pMsg->hdr);
       bleESS_ccc_update();
+      HidProcMsg(&pMsg->hdr);
       break;
 
     case DM_CONN_CLOSE_IND:
@@ -964,6 +973,8 @@ static void BleHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
   }
 }
 
+void hid_init(void);
+
 /*************************************************************************************************/
 /*!
  *  \brief  Start the application.
@@ -992,6 +1003,7 @@ void BleStart(void)
   SvcBattCbackRegister(BasReadCback, NULL);
   SvcBattAddGroup();
 
+  hid_init();
   /* Reset the device */
   DmDevReset();
 }
diff --git a/epicardium/ble/cccd.h b/epicardium/ble/cccd.h
index 2715f6ebb6252e4995b73bb7980795b4c0354083..1f75bc640d27efa41dbc64abd24c2f399d10c0af 100644
--- a/epicardium/ble/cccd.h
+++ b/epicardium/ble/cccd.h
@@ -7,6 +7,11 @@ enum
   BLE_ESS_TEMP_CCC_IDX,                   /*! Environmental sensing service, temperature characteristic */
   BLE_ESS_HUMI_CCC_IDX,                   /*! Environmental sensing service, humidity characteristic */
   BLE_ESS_PRES_CCC_IDX,                   /*! Environmental sensing service, pressure characteristic */
+  HIDAPP_MBI_CCC_HDL,                   /*! HID Boot Mouse Input characteristic */
+  HIDAPP_KBI_CCC_HDL,                   /*! HID Boot Keyboard Input characteristic */
+  HIDAPP_IN_REMOTE_CCC_HDL,             /*! HID Input Report characteristic for remote inputs */
+  HIDAPP_IN_KEYBOARD_CCC_HDL,           /*! HID Input Report characteristic for keyboard inputs */
+  HIDAPP_IN_MOUSE_CCC_HDL,              /*! HID Input Report characteristic for mouse inputs */
   BLE_NUM_CCC_IDX
 };
 
diff --git a/epicardium/ble/hid.c b/epicardium/ble/hid.c
new file mode 100644
index 0000000000000000000000000000000000000000..c5fedf45e8fa95fb729cd624e7f958157a9a0985
--- /dev/null
+++ b/epicardium/ble/hid.c
@@ -0,0 +1,217 @@
+/*
+ * Based on ble-profiles/sources/apps/hidapp/hidapp_main.c
+ */
+#include "cccd.h"
+#include "hid.h"
+
+#include "wsf_types.h"
+#include "dm_api.h"
+#include "att_api.h"
+#include "svc_hid.h"
+#include "hid/hid_api.h"
+//#include "hidapp/hidapp_api.h"
+
+#include "modules/log.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+/*! HidApp Report Map (Descriptor) */
+/* clang-format off */
+const uint8_t hidReportMap[] =
+{
+  0x05, 0x0c,                    /* Usage Page (Consumer Devices) */
+  0x09, 0x01,                    /* Usage (Consumer Control) */
+  0xa1, 0x01,                    /* Collection (Application) */
+  0x85, HIDAPP_REMOTE_REPORT_ID, /*   report ID (HIDAPP_REMOTE_REPORT_ID) */
+  0x15, 0x00,                    /*   Logical Minimum (0) */
+  0x25, 0x01,                    /*   Logical Maximum (1) */
+  0x09, 0xe9,                    /*   Usage (Volume Up) */
+  0x09, 0xea,                    /*   Usage (Volume Down) */
+  0x75, 0x01,                    /*   Report Size (1) */
+  0x95, 0x02,                    /*   Report Count (2) */
+  0x81, 0x06,                    /*   Input (Data, Variable, Relative) */
+  0x09, 0xe2,                    /*   Usage (Mute) */
+  0x95, 0x01,                    /*   Report Count (1) */
+  0x81, 0x06,                    /*   Input (Data, Variable, Relative) */
+  0x09, 0xb0,                    /*   Usage (Play) */
+  0x95, 0x01,                    /*   Report Count (1) */
+  0x81, 0x06,                    /*   Input (Data, Variable, Relative) */
+  0x09, 0xb1,                    /*   Usage (Pause) */
+  0x95, 0x01,                    /*   Report Count (1) */
+  0x81, 0x06,                    /*   Input (Data, Variable, Relative) */
+  0x09, 0xb7,                    /*   Usage (Stop) */
+  0x95, 0x01,                    /*   Report Count (1) */
+  0x81, 0x06,                    /*   Input (Data, Variable, Relative) */
+  0x09, 0xb5,                    /*   Usage (Next) */
+  0x95, 0x01,                    /*   Report Count (1) */
+  0x81, 0x06,                    /*   Input (Data, Variable, Relative) */
+  0x09, 0xb6,                    /*   Usage (Previous) */
+  0x95, 0x01,                    /*   Report Count (1) */
+  0x81, 0x06,                    /*   Input (Data, Variable, Relative) */
+  0xc0,                          /* End Collection */
+  0x05, 0x01,                    /* Usage Page (Generic Desktop) */
+  0x09, 0x06,                    /* Usage (Keyboard) */
+  0xA1, 0x01,                    /* Collection (Application) */
+  0x85, HIDAPP_KEYBOARD_REPORT_ID, /*   report ID (HIDAPP_KEYBOARD_REPORT_ID) */
+  0x75, 0x01,                    /*   Report Size (1) */
+  0x95, 0x08,                    /*   Report Count (8) */
+  0x05, 0x07,                    /*   Usage Page (Key Codes) */
+  0x19, 0xe0,                    /*   Usage Minimum (224) */
+  0x29, 0xe7,                    /*   Usage Maximum (231) */
+  0x15, 0x00,                    /*   Logical Minimum (0) */
+  0x25, 0x01,                    /*   Logical Maximum (1) */
+  0x81, 0x02,                    /*   Input (Data, Variable, Absolute) */
+  0x95, 0x01,                    /*   Report Count (1) */
+  0x75, 0x08,                    /*   Report Size (8) */
+  0x81, 0x01,                    /*   Input (Constant) reserved byte(1) */
+  0x95, 0x05,                    /*   Report Count (5) */
+  0x75, 0x01,                    /*   Report Size (1) */
+  0x05, 0x08,                    /*   Usage Page (Page# for LEDs) */
+  0x19, 0x01,                    /*   Usage Minimum (1) */
+  0x29, 0x05,                    /*   Usage Maximum (5) */
+  0x91, 0x02,                    /*   Output (Data, Variable, Absolute), Led report */
+  0x95, 0x01,                    /*   Report Count (1) */
+  0x75, 0x03,                    /*   Report Size (3) */
+  0x91, 0x01,                    /*   Output (Constant), Led report padding */
+  0x95, 0x06,                    /*   Report Count (6) */
+  0x75, 0x08,                    /*   Report Size (8) */
+  0x15, 0x00,                    /*   Logical Minimum (0) */
+  0x25, 0x65,                    /*   Logical Maximum (101) */
+  0x05, 0x07,                    /*   Usage Page (Key codes) */
+  0x19, 0x00,                    /*   Usage Minimum (0) */
+  0x29, 0x65,                    /*   Usage Maximum (101) */
+  0x81, 0x00,                    /*   Input (Data, Array) Key array(6 bytes) */
+  0xC0,                          /* End Collection (Application) */
+  0x05, 0x01,                    /* USAGE_PAGE (Generic Desktop) */
+  0x09, 0x02,                    /* USAGE (Mouse) */
+  0xa1, 0x01,                    /* COLLECTION (Application) */
+  0x85, HIDAPP_MOUSE_REPORT_ID,  /*   report ID (HIDAPP_MOUSE_REPORT_ID) */
+  0x09, 0x01,                    /*   USAGE (Pointer) */
+  0xa1, 0x00,                    /*   COLLECTION (Physical) */
+  0x95, 0x03,                    /*     REPORT_COUNT (3) */
+  0x75, 0x01,                    /*     REPORT_SIZE (1) */
+  0x05, 0x09,                    /*     USAGE_PAGE (Button) */
+  0x19, 0x01,                    /*     USAGE_MINIMUM (Button 1) */
+  0x29, 0x03,                    /*     USAGE_MAXIMUM (Button 3) */
+  0x15, 0x00,                    /*     LOGICAL_MINIMUM (0) */
+  0x25, 0x01,                    /*     LOGICAL_MAXIMUM (1) */
+  0x81, 0x02,                    /*     INPUT (Data, Variable, Absolute) */
+  0x95, 0x01,                    /*     REPORT_COUNT (1) */
+  0x75, 0x05,                    /*     REPORT_SIZE (5) */
+  0x81, 0x01,                    /*     INPUT (Constant) */
+  0x75, 0x08,                    /*     REPORT_SIZE (8) */
+  0x95, 0x02,                    /*     REPORT_COUNT (2) */
+  0x05, 0x01,                    /*     USAGE_PAGE (Generic Desktop) */
+  0x09, 0x30,                    /*     USAGE (X) */
+  0x09, 0x31,                    /*     USAGE (Y) */
+  0x15, 0x81,                    /*     LOGICAL_MINIMUM (-127) */
+  0x25, 0x7f,                    /*     LOGICAL_MAXIMUM (127) */
+  0x81, 0x06,                    /*     INPUT (Data, Variable, Relative) */
+  0xc0,                          /*   End Collection (Physical) */
+  0xc0                           /* End Collection (Application) */
+};
+/* clang-format on */
+
+const uint16_t hidReportMapLen = sizeof(hidReportMap);
+
+/*! HID Report Type/ID and attribute handle map */
+/* clang-format off */
+static const hidReportIdMap_t hidAppReportIdSet[] =
+{
+  /* type                       ID                            handle */
+  {HID_REPORT_TYPE_INPUT,       HIDAPP_REMOTE_REPORT_ID,      HID_INPUT_REPORT_1_HDL},     /* Remote Input Report */
+  {HID_REPORT_TYPE_INPUT,       HIDAPP_KEYBOARD_REPORT_ID,    HID_INPUT_REPORT_2_HDL},     /* Keyboard Input Report */
+  {HID_REPORT_TYPE_OUTPUT,      HIDAPP_KEYBOARD_REPORT_ID,    HID_OUTPUT_REPORT_HDL},      /* Keyboard Output Report */
+  {HID_REPORT_TYPE_FEATURE,     HIDAPP_KEYBOARD_REPORT_ID,    HID_FEATURE_REPORT_HDL},     /* Keyboard Feature Report */
+  {HID_REPORT_TYPE_INPUT,       HIDAPP_MOUSE_REPORT_ID,       HID_INPUT_REPORT_3_HDL},     /* Mouse Input Report */
+  {HID_REPORT_TYPE_INPUT,       HID_KEYBOARD_BOOT_ID,         HID_KEYBOARD_BOOT_IN_HDL},   /* Boot Keyboard Input Report */
+  {HID_REPORT_TYPE_OUTPUT,      HID_KEYBOARD_BOOT_ID,         HID_KEYBOARD_BOOT_OUT_HDL},  /* Boot Keyboard Output Report */
+  {HID_REPORT_TYPE_INPUT,       HID_MOUSE_BOOT_ID,            HID_MOUSE_BOOT_IN_HDL},      /* Boot Mouse Input Report */
+};
+/* clang-format on */
+
+void hidAppOutputCback(
+	dmConnId_t connId, uint8_t id, uint16_t len, uint8_t *pReport
+);
+void hidAppFeatureCback(
+	dmConnId_t connId, uint8_t id, uint16_t len, uint8_t *pReport
+);
+void hidAppInfoCback(dmConnId_t connId, uint8_t type, uint8_t value);
+
+/*! HID Profile Configuration */
+/* clang-format off */
+static const hidConfig_t hidAppHidConfig =
+{
+  (hidReportIdMap_t*) hidAppReportIdSet,                  /* Report ID to Attribute Handle map */
+  sizeof(hidAppReportIdSet)/sizeof(hidReportIdMap_t),     /* Size of Report ID to Attribute Handle map */
+  &hidAppOutputCback,                                     /* Output Report Callback */
+  &hidAppFeatureCback,                                    /* Feature Report Callback */
+  &hidAppInfoCback                                        /* Info Callback */
+};
+/* clang-format on */
+
+static void hidAppReportInit(void)
+{
+	uint8_t iKeyboardBuffer[HIDAPP_KEYBOARD_INPUT_REPORT_LEN];
+	uint8_t iMouseBuffer[HIDAPP_MOUSE_INPUT_REPORT_LEN];
+	uint8_t iRemoteBuffer[HIDAPP_REMOTE_INPUT_REPORT_LEN];
+	uint8_t oBuffer[HIDAPP_OUTPUT_REPORT_LEN];
+	uint8_t fBuffer[HIDAPP_FEATURE_REPORT_LEN];
+
+	/* Remote Input report */
+	memset(iRemoteBuffer, 0, HIDAPP_REMOTE_INPUT_REPORT_LEN);
+	AttsSetAttr(
+		HID_INPUT_REPORT_1_HDL,
+		HIDAPP_REMOTE_INPUT_REPORT_LEN,
+		iRemoteBuffer
+	);
+
+	/* Keyboard Input report */
+	memset(iKeyboardBuffer, 0, HIDAPP_KEYBOARD_INPUT_REPORT_LEN);
+	AttsSetAttr(
+		HID_INPUT_REPORT_2_HDL,
+		HIDAPP_KEYBOARD_INPUT_REPORT_LEN,
+		iKeyboardBuffer
+	);
+
+	/* Mouse Input report */
+	memset(iMouseBuffer, 0, HIDAPP_MOUSE_INPUT_REPORT_LEN);
+	AttsSetAttr(
+		HID_INPUT_REPORT_3_HDL,
+		HIDAPP_MOUSE_INPUT_REPORT_LEN,
+		iMouseBuffer
+	);
+
+	/* Output report */
+	memset(oBuffer, 0, HIDAPP_OUTPUT_REPORT_LEN);
+	AttsSetAttr(HID_OUTPUT_REPORT_HDL, HIDAPP_OUTPUT_REPORT_LEN, oBuffer);
+
+	/* Feature report */
+	memset(fBuffer, 0, HIDAPP_FEATURE_REPORT_LEN);
+	AttsSetAttr(HID_FEATURE_REPORT_HDL, HIDAPP_FEATURE_REPORT_LEN, fBuffer);
+}
+
+void hid_work_init(void);
+void hid_init(void)
+{
+#ifdef HID_ATT_DYNAMIC
+	/* Initialize the dynamic service system */
+	AttsDynInit();
+	/* Add the HID service dynamically */
+	pSHdl = SvcHidAddGroupDyn();
+	AttsDynRegister(pSHdl, NULL, HidAttsWriteCback);
+#else
+	/* Add the HID service statically */
+	SvcHidAddGroup();
+	SvcHidRegister(HidAttsWriteCback, NULL);
+#endif /* HID_ATT_DYNAMIC */
+	/* Initialize the HID profile */
+	HidInit(&hidAppHidConfig);
+
+	/* Initialize the report attributes */
+	hidAppReportInit();
+
+	hid_work_init();
+}
diff --git a/epicardium/ble/hid.h b/epicardium/ble/hid.h
new file mode 100644
index 0000000000000000000000000000000000000000..da489fcbb25a6c647439b011bb7500db6d313ed3
--- /dev/null
+++ b/epicardium/ble/hid.h
@@ -0,0 +1,14 @@
+#pragma once
+
+/* The input report fits in one byte */
+#define HIDAPP_KEYBOARD_INPUT_REPORT_LEN  8
+#define HIDAPP_MOUSE_INPUT_REPORT_LEN     3
+#define HIDAPP_REMOTE_INPUT_REPORT_LEN    1
+#define HIDAPP_OUTPUT_REPORT_LEN          1
+#define HIDAPP_FEATURE_REPORT_LEN         1
+
+
+/* HID Report IDs */
+#define HIDAPP_REMOTE_REPORT_ID           1
+#define HIDAPP_KEYBOARD_REPORT_ID         2
+#define HIDAPP_MOUSE_REPORT_ID            3
diff --git a/epicardium/ble/hid_work.c b/epicardium/ble/hid_work.c
new file mode 100644
index 0000000000000000000000000000000000000000..b63236d4e2b7b9a5024cc898d4e5854d607a1a1e
--- /dev/null
+++ b/epicardium/ble/hid_work.c
@@ -0,0 +1,423 @@
+#include "hid.h"
+#include "cccd.h"
+
+#include "modules/log.h"
+
+#include "dm_api.h"
+#include "att_api.h"
+#include "app_api.h"
+#include "hid/hid_api.h"
+#include "svc_hid.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+/* Remote Button Identifier bits */
+/* clang-format off */
+#define REMOTE_USAGE_NONE                 (0<<0)
+#define REMOTE_VOLUME_UP                  (1<<0)
+#define REMOTE_VOLUME_DOWN                (1<<1)
+#define REMOTE_MUTE                       (1<<2)
+#define REMOTE_PLAY                       (1<<3)
+#define REMOTE_PAUSE                      (1<<4)
+#define REMOTE_STOP                       (1<<5)
+#define REMOTE_NEXT                       (1<<6)
+#define REMOTE_PREVIOUS                   (1<<7)
+
+/* Keyboard input record message format */
+#define KEYBOARD_IR_MODIFIER_POS          0
+#define KEYBOARD_IR_RESERVED_POS          1
+#define KEYBOARD_IR_KEY_POS               2
+#define KEYBOARD_IR_MAX_KEYS              6
+
+/* Keyboard LED Identifier bits */
+#define KEYBOARD_LED_NUM_LOCK             (1<<0)
+#define KEYBOARD_LED_CAPS_LOCK            (1<<1)
+#define KEYBOARD_LED_SCROLL_LOCK          (1<<2)
+#define KEYBOARD_LED_COMPOSE              (1<<3)
+#define KEYBOARD_LED_KANA                 (1<<4)
+
+/* Mouse button bit mask */
+#define MOUSE_BUTTON_LEFT                 (1<<0)
+#define MOUSE_BUTTON_RIGHT                (1<<1)
+#define MOUSE_BUTTON_MIDDLE               (1<<2)
+
+/* Mouse input record message format */
+#define MOUSE_BUTTON_POS                  0
+#define MOUSE_X_POS                       1
+#define MOUSE_Y_POS                       2
+
+
+/* HidApp TX path flags */
+#define HIDAPP_TX_FLAGS_READY             0x01
+#define HIDAPP_TX_FLAGS_PENDING           0x02
+/* clang-format on */
+
+/*! application control block */
+/* clang-format off */
+struct
+{
+  /* Mouse pending event data */
+  uint8_t buttonMask;                   /* pending button mask */
+  uint8_t xDisplacement;                /* pending X Displacement */
+  uint8_t yDisplacement;                /* pending Y Displacement */
+  uint8_t devSpecific;                  /* pending Device Specific */
+
+  /* Keyboard pending event data */
+  uint8_t modifier;                     /* pending key modifiers */
+  uint8_t keys[KEYBOARD_IR_MAX_KEYS];   /* pending keys */
+
+  /* Remote pending event data */
+  uint8_t btnData;                      /* pending remote button data */
+
+  uint8_t reportId;                     /* pending reportId button data */
+  uint8_t txFlags;                      /* transmit flags */
+  uint8_t protocolMode;                 /* current protocol mode */
+  uint8_t hostSuspended;                /* TRUE if host suspended */
+} hidAppCb;
+/* clang-format on */
+
+/*************************************************************************************************/
+/*!
+ *  \brief  Send example data.
+ *
+ *  \param  connId    Connection identifier.
+ *
+ *  \return None.
+ */
+/*************************************************************************************************/
+static void hidAppMouseSendData(dmConnId_t connId)
+{
+	uint8_t cccHandle = HIDAPP_IN_MOUSE_CCC_HDL;
+	uint8_t protocolMode;
+
+	protocolMode = HidGetProtocolMode();
+
+	if (protocolMode == HID_PROTOCOL_MODE_BOOT) {
+		cccHandle = HIDAPP_MBI_CCC_HDL;
+	}
+
+	if (AttsCccEnabled(connId, cccHandle)) {
+		if (hidAppCb.txFlags & HIDAPP_TX_FLAGS_PENDING) {
+			if (hidAppCb.txFlags & HIDAPP_TX_FLAGS_READY) {
+				uint8_t buffer[HIDAPP_MOUSE_INPUT_REPORT_LEN];
+				uint8_t reportId = HIDAPP_MOUSE_REPORT_ID;
+
+				/* mouse record: button mask, x displacement, y displacement, device specific */
+				buffer[MOUSE_BUTTON_POS] = hidAppCb.buttonMask;
+				buffer[MOUSE_X_POS] = hidAppCb.xDisplacement;
+				buffer[MOUSE_Y_POS] = hidAppCb.yDisplacement;
+
+				hidAppCb.txFlags &=
+					~(HIDAPP_TX_FLAGS_READY |
+					  HIDAPP_TX_FLAGS_PENDING);
+
+				if (protocolMode == HID_PROTOCOL_MODE_BOOT) {
+					reportId = HID_MOUSE_BOOT_ID;
+				}
+
+				/* Send the message */
+				HidSendInputReport(
+					connId,
+					reportId,
+					HIDAPP_MOUSE_INPUT_REPORT_LEN,
+					buffer
+				);
+			}
+		}
+	} else {
+		hidAppCb.txFlags &= ~HIDAPP_TX_FLAGS_PENDING;
+	}
+}
+
+/*************************************************************************************************/
+/*!
+ *  \brief  Send example data.
+ *
+ *  \param  connId    Connection identifier.
+ *
+ *  \return None.
+ */
+/*************************************************************************************************/
+static void hidAppkeyboardSendData(dmConnId_t connId)
+{
+	uint8_t cccHandle = HIDAPP_IN_KEYBOARD_CCC_HDL;
+	uint8_t protocolMode;
+
+	protocolMode = HidGetProtocolMode();
+
+	if (protocolMode == HID_PROTOCOL_MODE_BOOT) {
+		cccHandle = HIDAPP_KBI_CCC_HDL;
+	}
+
+	if (AttsCccEnabled(connId, cccHandle)) {
+		if (hidAppCb.txFlags & HIDAPP_TX_FLAGS_PENDING) {
+			if (hidAppCb.txFlags & HIDAPP_TX_FLAGS_READY) {
+				uint8_t buffer[HIDAPP_KEYBOARD_INPUT_REPORT_LEN];
+				uint8_t reportId = HIDAPP_KEYBOARD_REPORT_ID;
+
+				/* modifier, reserved, keys[6] */
+				buffer[KEYBOARD_IR_MODIFIER_POS] =
+					hidAppCb.modifier;
+				buffer[KEYBOARD_IR_RESERVED_POS] = 0;
+				memcpy(buffer + KEYBOARD_IR_KEY_POS,
+				       hidAppCb.keys,
+				       sizeof(hidAppCb.keys));
+
+				hidAppCb.txFlags &=
+					~(HIDAPP_TX_FLAGS_READY |
+					  HIDAPP_TX_FLAGS_PENDING);
+
+				if (protocolMode == HID_PROTOCOL_MODE_BOOT) {
+					reportId = HID_KEYBOARD_BOOT_ID;
+				}
+
+				/* Send the message */
+				HidSendInputReport(
+					connId,
+					reportId,
+					HIDAPP_KEYBOARD_INPUT_REPORT_LEN,
+					buffer
+				);
+			}
+		}
+	} else {
+		hidAppCb.txFlags &= ~HIDAPP_TX_FLAGS_PENDING;
+	}
+}
+/*************************************************************************************************/
+/*!
+ *  \brief  Send example data.
+ *
+ *  \param  connId    Connection identifier.
+ *
+ *  \return None.
+ */
+/*************************************************************************************************/
+static void hidAppRemoteSendData(dmConnId_t connId)
+{
+	if (AttsCccEnabled(connId, HIDAPP_IN_REMOTE_CCC_HDL)) {
+		if (hidAppCb.txFlags & HIDAPP_TX_FLAGS_PENDING) {
+			if (hidAppCb.txFlags & HIDAPP_TX_FLAGS_READY) {
+				uint8_t buffer;
+
+				/* bitmask of remote buttons */
+				buffer = hidAppCb.btnData;
+
+				hidAppCb.txFlags &=
+					~(HIDAPP_TX_FLAGS_READY |
+					  HIDAPP_TX_FLAGS_PENDING);
+
+				/* Send the message */
+				HidSendInputReport(
+					connId,
+					hidAppCb.reportId,
+					HIDAPP_REMOTE_INPUT_REPORT_LEN,
+					&buffer
+				);
+			}
+		}
+	} else {
+		hidAppCb.txFlags &= ~HIDAPP_TX_FLAGS_PENDING;
+	}
+}
+
+/*************************************************************************************************/
+/*!
+ *  \brief  Send example data.
+ *
+ *  \param  connId    Connection identifier.
+ *
+ *  \return None.
+ */
+/*************************************************************************************************/
+static void hidAppSendData(dmConnId_t connId)
+{
+	/* Send the report based on report ID */
+	switch (hidAppCb.reportId) {
+	case HIDAPP_REMOTE_REPORT_ID:
+		hidAppRemoteSendData(connId);
+		break;
+	case HIDAPP_KEYBOARD_REPORT_ID:
+		hidAppkeyboardSendData(connId);
+		break;
+	case HIDAPP_MOUSE_REPORT_ID:
+		hidAppMouseSendData(connId);
+		break;
+	default:
+		break;
+	}
+}
+
+/*************************************************************************************************/
+/*!
+ *  \brief  Send or queue a remote event to the host
+ *
+ *  \param  button        Remote control depressed button
+ *
+ *  \return None.
+ */
+/*************************************************************************************************/
+void epic_hid_remote_report_event(uint8_t button)
+{
+	dmConnId_t connId;
+
+	if ((connId = AppConnIsOpen()) != DM_CONN_ID_NONE) {
+		LOG_INFO("hid", "send button %d\n", button);
+		/* record key data */
+		hidAppCb.btnData  = button;
+		hidAppCb.reportId = HIDAPP_REMOTE_REPORT_ID;
+
+		/* Indicate new data is pending */
+		hidAppCb.txFlags |= HIDAPP_TX_FLAGS_PENDING;
+
+		/* send the data */
+		hidAppSendData(connId);
+	}
+}
+
+/*************************************************************************************************/
+/*!
+ *  \brief  Send or queue a keyboard event to the host
+ *
+ *  \param  modifiers        Keyboard modifiers.
+ *  \param  keys             Keyboard depressed keys.
+ *  \param  numKeys          Size of keys parameters in bytes
+ *
+ *  \return None.
+ */
+/*************************************************************************************************/
+void epic_hid_keyboard_report_event(
+	uint8_t modifiers, uint8_t keys[], uint8_t numKeys
+) {
+	dmConnId_t connId;
+
+	if ((connId = AppConnIsOpen()) != DM_CONN_ID_NONE) {
+		/* max 6 keys in report map */
+		if (numKeys > KEYBOARD_IR_MAX_KEYS) {
+			numKeys = KEYBOARD_IR_MAX_KEYS;
+		}
+
+		/* record key data */
+		hidAppCb.modifier = modifiers;
+		memset(hidAppCb.keys, 0, sizeof(hidAppCb.keys));
+		memcpy(hidAppCb.keys, keys, numKeys);
+		hidAppCb.reportId = HIDAPP_KEYBOARD_REPORT_ID;
+
+		/* indicate new data is pending */
+		hidAppCb.txFlags |= HIDAPP_TX_FLAGS_PENDING;
+
+		/* send the data */
+		hidAppSendData(connId);
+	}
+}
+
+/*************************************************************************************************/
+/*!
+ *  \brief  Report or queue a mouse event to the host.
+ *
+ *  \param  buttonMask        Mouse button mask.
+ *  \param  xDisplacement     Mouse displacement in the x direction.
+ *  \param  yDisplacement     Mouse displacement in the y direction.
+ *
+ *  \return None.
+ */
+/*************************************************************************************************/
+void epic_hid_mouse_report_event(
+	uint8_t buttonMask, uint8_t xDisplacement, uint8_t yDisplacement
+) {
+	dmConnId_t connId;
+
+	if ((connId = AppConnIsOpen()) != DM_CONN_ID_NONE) {
+		/* record mouse data */
+		hidAppCb.buttonMask    = buttonMask;
+		hidAppCb.xDisplacement = xDisplacement;
+		hidAppCb.yDisplacement = yDisplacement;
+		hidAppCb.devSpecific   = 0;
+		hidAppCb.reportId      = HIDAPP_MOUSE_REPORT_ID;
+
+		/* Indicate new data is pending */
+		hidAppCb.txFlags |= HIDAPP_TX_FLAGS_PENDING;
+
+		/* send the data */
+		hidAppSendData(connId);
+	}
+}
+
+/*************************************************************************************************/
+/*!
+ *  \brief  Callback to handle an output report from the host.
+ *
+ *  \param  connId    The connection identifier.
+ *  \param  id        The ID of the report.
+ *  \param  len       The length of the report data in pReport.
+ *  \param  pReport   A buffer containing the report.
+ *
+ *  \return None.
+ */
+/*************************************************************************************************/
+void hidAppOutputCback(
+	dmConnId_t connId, uint8_t id, uint16_t len, uint8_t *pReport
+) {
+	/* TODO: process output reports */
+}
+
+/*************************************************************************************************/
+/*!
+ *  \brief  Callback to handle a feature report from the host.
+ *
+ *  \param  connId    The connection identifier.
+ *  \param  id        The ID of the report.
+ *  \param  len       The length of the report data in pReport.
+ *  \param  pReport   A buffer containing the report.
+ *
+ *  \return None.
+ */
+/*************************************************************************************************/
+void hidAppFeatureCback(
+	dmConnId_t connId, uint8_t id, uint16_t len, uint8_t *pReport
+) {
+	/* TODO: process feature reports */
+}
+
+/*************************************************************************************************/
+/*!
+ *  \brief  Callback to handle a change in protocol mode or control point from the host.
+ *
+ *  \param  connId    The connection identifier.
+ *  \param  mode      The type of information (HID_INFO_CONTROL_POINT or HID_INFO_PROTOCOL_MODE)
+ *  \param  value     The value of the information
+ *
+ *  \return None.
+ */
+/*************************************************************************************************/
+void hidAppInfoCback(dmConnId_t connId, uint8_t type, uint8_t value)
+{
+	if (type == HID_INFO_PROTOCOL_MODE) {
+		LOG_INFO("hid", "protocol mode: %u\n", value);
+		hidAppCb.protocolMode = value;
+	} else if (type == HID_INFO_CONTROL_POINT) {
+		LOG_INFO("hid", "host suspended: %u\n", value);
+		hidAppCb.hostSuspended =
+			(value == HID_CONTROL_POINT_SUSPEND) ? TRUE : FALSE;
+	}
+}
+
+void HidProcMsg(wsfMsgHdr_t *pMsg)
+{
+	if (pMsg->event == ATTS_HANDLE_VALUE_CNF) {
+		if (pMsg->status == ATT_SUCCESS) {
+			hidAppCb.txFlags |= HIDAPP_TX_FLAGS_READY;
+			hidAppSendData((dmConnId_t)pMsg->param);
+		}
+	}
+	if (pMsg->event == DM_CONN_OPEN_IND) {
+		hidAppCb.txFlags = HIDAPP_TX_FLAGS_READY;
+	}
+}
+
+void hid_work_init(void)
+{
+	hidAppCb.txFlags = HIDAPP_TX_FLAGS_READY;
+}
diff --git a/epicardium/ble/meson.build b/epicardium/ble/meson.build
index c2f10a12a8976cec3f049d9d8ca4617ef0cb70f9..341ad22571c4d5bc94c9bcf997c320682659142e 100644
--- a/epicardium/ble/meson.build
+++ b/epicardium/ble/meson.build
@@ -12,4 +12,6 @@ ble_sources = files(
   'card10.c',
   'ess.c',
   'filetransfer.c',
+  'hid.c',
+  'hid_work.c',
 )
diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h
index 842714028be6bdf0a9a86b31a052fbcf7fa1ec22..80102ee44d990d294fe6442efa8c20aaff8dad47 100644
--- a/epicardium/epicardium.h
+++ b/epicardium/epicardium.h
@@ -159,6 +159,10 @@ typedef _Bool bool;
 #define API_BLE_GET_PEER_DEVICE_NAME  0x146
 
 
+#define API_HID_REMOTE_REPORT      0x150
+#define API_HID_KEYBOARD_REPORT    0x151
+#define API_HID_MOUSE_REPORT       0x152
+
 /* clang-format on */
 
 typedef uint32_t api_int_id_t;
@@ -2320,5 +2324,18 @@ API(API_BLE_SET_MODE, void epic_ble_set_mode(bool bondable, bool scanner));
  *
  */
 API(API_BLE_GET_SCAN_REPORT, int epic_ble_get_scan_report(struct epic_scan_report *rpt));
+
+API(API_HID_REMOTE_REPORT, void epic_hid_remote_report_event(uint8_t button));
+
+API(API_HID_KEYBOARD_REPORT, void epic_hid_keyboard_report_event(
+	uint8_t modifiers,
+	uint8_t *keys,
+	uint8_t numKeys
+));
+API(API_HID_MOUSE_REPORT, void epic_hid_mouse_report_event(
+	uint8_t buttonMask,
+	uint8_t xDisplacement,
+	uint8_t yDisplacement
+));
 #endif /* _EPICARDIUM_H */
 
diff --git a/lib/sdk/Libraries/BTLE/meson.build b/lib/sdk/Libraries/BTLE/meson.build
index 1314ad583ea2e6239b81daa630f4ed454079c7df..2bf03dbb6af2f7d34b6e6c376f9c632a28006d09 100644
--- a/lib/sdk/Libraries/BTLE/meson.build
+++ b/lib/sdk/Libraries/BTLE/meson.build
@@ -48,7 +48,7 @@ sources = files(
 'stack/ble-profiles/sources/apps/meds/meds_htp.c',
 'stack/ble-profiles/sources/apps/meds/meds_plx.c',
 'stack/ble-profiles/sources/apps/meds/meds_glp.c',
-'stack/ble-profiles/sources/apps/hidapp/hidapp_main.c',
+#'stack/ble-profiles/sources/apps/hidapp/hidapp_main.c',
 'stack/ble-profiles/sources/apps/watch/watch_main.c',
 'stack/ble-profiles/sources/apps/datc/datc_main.c',
 'stack/ble-profiles/sources/apps/gluc/gluc_main.c',