From 0473f463fa35836d70e10e8b3e1cd5c0e6298002 Mon Sep 17 00:00:00 2001
From: Rahix <rahix@rahix.de>
Date: Sat, 17 Aug 2019 08:12:20 +0200
Subject: [PATCH] feat(epicardium): Add buttons module

Co-authored-by: fleur <spacecarrot@fleurshax.net>
Signed-off-by: Rahix <rahix@rahix.de>
---
 epicardium/epicardium.h        | 64 ++++++++++++++++++++++++++++++++++
 epicardium/modules/buttons.c   | 32 +++++++++++++++++
 epicardium/modules/meson.build |  1 +
 3 files changed, 97 insertions(+)
 create mode 100644 epicardium/modules/buttons.c

diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h
index 36ea64b8..ce254cb6 100644
--- a/epicardium/epicardium.h
+++ b/epicardium/epicardium.h
@@ -88,6 +88,8 @@ typedef _Bool bool;
 #define API_LIGHT_SENSOR_RUN       0x80
 #define API_LIGHT_SENSOR_GET       0x81
 #define API_LIGHT_SENSOR_STOP      0x82
+
+#define API_BUTTONS_READ           0x90
 /* clang-format on */
 
 typedef uint32_t api_int_id_t;
@@ -274,6 +276,68 @@ API_ISR(EPIC_INT_UART_RX, epic_isr_uart_rx);
  */
 API_ISR(EPIC_INT_CTRL_C, epic_isr_ctrl_c);
 
+/**
+ * Buttons
+ * =======
+ *
+ */
+
+/** Button IDs */
+enum epic_button {
+	/** ``1``, Bottom left button (bit 0). */
+	BUTTON_LEFT_BOTTOM   = 1,
+	/** ``2``, Bottom right button (bit 1). */
+	BUTTON_RIGHT_BOTTOM  = 2,
+	/** ``4``, Top right button (bit 2). */
+	BUTTON_RIGHT_TOP     = 4,
+	/** ``8``, Top left (power) button (bit 3). */
+	BUTTON_LEFT_TOP      = 8,
+	/** ``8``, Top left (power) button (bit 3). */
+	BUTTON_RESET         = 8,
+};
+
+/**
+ * Read buttons.
+ *
+ * :c:func:`epic_buttons_read` will read all buttons specified in ``mask`` and
+ * return set bits for each button which was reported as pressed.
+ *
+ * .. note::
+ *
+ *    The reset button cannot be unmapped from reset functionality.  So, while
+ *    you can read it, it cannot be used for app control.
+ *
+ * **Example**:
+ *
+ * .. code-block:: cpp
+ *
+ *    #include "epicardium.h"
+ *
+ *    uint8_t pressed = epic_buttons_read(BUTTON_LEFT_BOTTOM | BUTTON_RIGHT_BOTTOM);
+ *
+ *    if (pressed & BUTTON_LEFT_BOTTOM) {
+ *            // Bottom left button is pressed
+ *    }
+ *
+ *    if (pressed & BUTTON_RIGHT_BOTTOM) {
+ *            // Bottom right button is pressed
+ *    }
+ *
+ * :param uint8_t mask: Mask of buttons to read.  The 4 LSBs correspond to the 4
+ *     buttons:
+ *
+ *     ===== ========= ============ ===========
+ *     ``3`` ``2``     ``1``        ``0``
+ *     ----- --------- ------------ -----------
+ *     Reset Right Top Right Bottom Left Bottom
+ *     ===== ========= ============ ===========
+ *
+ *     Use the values defined in :c:type:`epic_button` for masking, as shown in
+ *     the example above.
+ * :return: Returns nonzero value if unmasked buttons are pushed.
+ */
+API(API_BUTTONS_READ, uint8_t epic_buttons_read(uint8_t mask));
+
 /**
  * LEDs
  * ====
diff --git a/epicardium/modules/buttons.c b/epicardium/modules/buttons.c
new file mode 100644
index 00000000..e2cb20d3
--- /dev/null
+++ b/epicardium/modules/buttons.c
@@ -0,0 +1,32 @@
+#include "epicardium.h"
+
+#include "portexpander.h"
+#include "MAX77650-Arduino-Library.h"
+
+#include <stdint.h>
+
+static const uint8_t pin_mask[] = {
+	[BUTTON_LEFT_BOTTOM]  = 1 << 5,
+	[BUTTON_RIGHT_BOTTOM] = 1 << 3,
+	[BUTTON_RIGHT_TOP]    = 1 << 6,
+};
+
+uint8_t epic_buttons_read(uint8_t mask)
+{
+	uint8_t ret = 0;
+	if (portexpander_detected() && (mask & 0x3)) {
+		uint8_t pin_status = ~portexpander_get();
+
+		for (uint8_t m = 1; m < 0x8; m <<= 1) {
+			if (mask & m && pin_status & pin_mask[m]) {
+				ret |= m;
+			}
+		}
+	}
+
+	if (mask & BUTTON_RESET && MAX77650_getDebounceStatusnEN0()) {
+		ret |= BUTTON_RESET;
+	}
+
+	return ret;
+}
diff --git a/epicardium/modules/meson.build b/epicardium/modules/meson.build
index d7c9f40b..3389a409 100644
--- a/epicardium/modules/meson.build
+++ b/epicardium/modules/meson.build
@@ -1,4 +1,5 @@
 module_sources = files(
+  'buttons.c',
   'dispatcher.c',
   'display.c',
   'fileops.c',
-- 
GitLab