From 9251ea69f7bc59f94436b71b7c89bcb9a671273f Mon Sep 17 00:00:00 2001
From: schneider <schneider@blinkenlichts.net>
Date: Sun, 7 Jul 2019 08:58:26 +0200
Subject: [PATCH] fix(pb): Push button via portexpander support

---
 bootloader/bootloader-usb.c                   |   4 +-
 bootloader/main.c                             |   2 +-
 hw-tests/ecgtest/main.c                       |   4 +-
 lib/card10/card10.c                           |  29 +++-
 lib/card10/meson.build                        |   1 +
 lib/card10/pb.c                               | 130 ++++++++++++++++++
 lib/card10/portexpander.c                     |  28 +++-
 lib/card10/portexpander.h                     |   2 +
 .../Libraries/Boards/card10/Source/board.c    |  22 +--
 lib/sdk/Libraries/Boards/card10/meson.build   |   2 -
 10 files changed, 192 insertions(+), 32 deletions(-)
 create mode 100644 lib/card10/pb.c

diff --git a/bootloader/bootloader-usb.c b/bootloader/bootloader-usb.c
index 2e1bd9f32..a1e85ffef 100644
--- a/bootloader/bootloader-usb.c
+++ b/bootloader/bootloader-usb.c
@@ -182,9 +182,9 @@ void run_usbmsc(void)
     while (1) {
 
         if (suspended || !configured) {
-            LED_Off(0);
+            //LED_Off(0);
         } else {
-            LED_On(0);
+            //LED_On(0);
         }
 
         if (event_flags) {
diff --git a/bootloader/main.c b/bootloader/main.c
index 1e06e0eeb..3c3376919 100644
--- a/bootloader/main.c
+++ b/bootloader/main.c
@@ -208,7 +208,7 @@ int main(void)
     LCD_Update();
 
     // If the button is pressed, we go into MSC mode.
-    if (PB_Get(0) || PB_Get(1)) {
+    if (PB_Get(3)) {
         Paint_DrawString_EN(0, 16*2, "USB activated. Waiting.", &Font16, 0x0000, 0xffff);
         LCD_Update();
         run_usbmsc();
diff --git a/hw-tests/ecgtest/main.c b/hw-tests/ecgtest/main.c
index 70337ebd4..da01840f8 100644
--- a/hw-tests/ecgtest/main.c
+++ b/hw-tests/ecgtest/main.c
@@ -434,7 +434,7 @@ int main(void)
         if( ecgFIFOIntFlag ) {
             ecgFIFOIntFlag = false;
 
-            if(PB_Get(0)) {
+            if(PB_Get(3)) {
                 ecg_switch = !ecg_switch;
                 while(PB_Get(0));
                 if(ecg_switch) {
@@ -444,7 +444,7 @@ int main(void)
                 }
             }
 
-            if(PB_Get(2)) {
+            if(PB_Get(4)) {
                 internal_pull =! internal_pull;
                 while(PB_Get(2));
                 ecg_config(internal_pull);
diff --git a/lib/card10/card10.c b/lib/card10/card10.c
index 5bcf409cd..8f9587d24 100644
--- a/lib/card10/card10.c
+++ b/lib/card10/card10.c
@@ -12,6 +12,7 @@
 
 #include "mxc_config.h"
 #include "board.h"
+#include "pb.h"
 
 #include "tmr_utils.h"
 #include "i2c.h"
@@ -38,6 +39,12 @@ void card10_init(void)
     I2C_Shutdown(MXC_I2C1_BUS0);
     I2C_Init(MXC_I2C1_BUS0, I2C_FAST_MODE, NULL);
 
+    portexpander_init();
+
+    GPIO_Init();
+
+    PB_Init();
+
     pmic_init();
     pmic_set_led(0, 0);
     pmic_set_led(1, 0);
@@ -71,7 +78,6 @@ void card10_init(void)
 
     GPIO_Config(&bhi_interrupt_pin);
 
-    portexpander_init();
 }
 
 static uint32_t ecg_read_reg(uint8_t reg)
@@ -189,3 +195,24 @@ void card10_poll(void)
 {
     pmic_poll();
 }
+
+void GPIO0_IRQHandler(void)
+{
+    GPIO_Handler(PORT_0);
+}
+
+void GPIO1_IRQHandler(void)
+{
+    GPIO_Handler(PORT_1);
+}
+
+void GPIO2_IRQHandler(void)
+{
+    GPIO_Handler(PORT_2);
+}
+
+void GPIO3_IRQHandler(void)
+{
+    GPIO_Handler(PORT_3);
+}
+
diff --git a/lib/card10/meson.build b/lib/card10/meson.build
index 4def91a10..085e89929 100644
--- a/lib/card10/meson.build
+++ b/lib/card10/meson.build
@@ -8,6 +8,7 @@ sources = files(
   'leds.c',
   'pmic.c',
   'portexpander.c',
+  'pb.c'
 )
 
 deps = [
diff --git a/lib/card10/pb.c b/lib/card10/pb.c
new file mode 100644
index 000000000..cb1527225
--- /dev/null
+++ b/lib/card10/pb.c
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
+ * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of Maxim Integrated
+ * Products, Inc. shall not be used except as stated in the Maxim Integrated
+ * Products, Inc. Branding Policy.
+ *
+ * The mere transfer of this software does not imply any licenses
+ * of trade secrets, proprietary technology, copyrights, patents,
+ * trademarks, maskwork rights, or any other form of intellectual
+ * property whatsoever. Maxim Integrated Products, Inc. retains all
+ * ownership rights.
+ *
+ * $Date: 2018-08-13 23:38:48 +0000 (Mon, 13 Aug 2018) $
+ * $Revision: 36945 $
+ *
+ ******************************************************************************/
+
+#include <stddef.h>
+#include "mxc_config.h"
+#include "mxc_assert.h"
+#include "pb.h"
+#include "portexpander.h"
+
+/******************************************************************************/
+int PB_Init(void)
+{
+    int retval = E_NO_ERROR;
+    unsigned int i;
+
+    // If we have a port expander, its pins are already configured
+    if(!portexpander_detected()) {
+        // Enable pushbutton inputs
+        for (i = 0; i < num_pbs; i++) {
+            if (GPIO_Config(&pb_pin[i]) != E_NO_ERROR) {
+                retval = E_UNKNOWN;
+            }
+        }
+    }
+
+    return retval;
+}
+
+/******************************************************************************/
+int PB_RegisterCallback(unsigned int pb, pb_callback callback)
+{
+    MXC_ASSERT(pb < num_pbs);
+
+    // TODO: portexpander support
+    if (callback) {
+        // Register callback
+        GPIO_RegisterCallback(&pb_pin[pb], callback, (void*)pb);
+
+        // Configure and enable interrupt
+        GPIO_IntConfig(&pb_pin[pb], GPIO_INT_EDGE, GPIO_INT_FALLING);
+        GPIO_IntEnable(&pb_pin[pb]);
+        NVIC_EnableIRQ((IRQn_Type)MXC_GPIO_GET_IRQ(pb_pin[pb].port));
+    } else {
+        // Disable interrupt and clear callback
+        GPIO_IntDisable(&pb_pin[pb]);
+        GPIO_RegisterCallback(&pb_pin[pb], NULL, NULL);
+    }
+
+    return E_NO_ERROR;
+}
+
+//******************************************************************************
+void PB_IntEnable(unsigned int pb)
+{
+    // TODO: portexpander support
+    MXC_ASSERT(pb < num_pbs);
+    GPIO_IntEnable(&pb_pin[pb]);
+}
+
+//******************************************************************************
+void PB_IntDisable(unsigned int pb)
+{
+    // TODO: portexpander support
+    MXC_ASSERT(pb < num_pbs);
+    GPIO_IntDisable(&pb_pin[pb]);
+}
+
+//******************************************************************************
+void PB_IntClear(unsigned int pb)
+{
+    // TODO: portexpander support
+    MXC_ASSERT(pb < num_pbs);
+    GPIO_IntClr(&pb_pin[pb]);
+}
+
+//******************************************************************************
+int PB_Get(unsigned int pb)
+{
+    static const uint8_t expander_pins[] = {5, 0x0, 3, 6};
+    MXC_ASSERT(pb < 4);
+    switch(pb) {
+        case 1:
+        case 3:
+        case 4:
+            if(portexpander_detected()) {
+                uint8_t port = portexpander_get();
+                return (port & (1 << expander_pins[pb-1])) == 0;
+            } else {
+                return GPIO_InGet(&pb_pin[pb-1]) == 0;
+            }
+            break;
+        case 2:
+            // TODO: read pmic button
+            break;
+    }
+    return 0;
+}
diff --git a/lib/card10/portexpander.c b/lib/card10/portexpander.c
index 60dbfc612..dcb2a20d9 100644
--- a/lib/card10/portexpander.c
+++ b/lib/card10/portexpander.c
@@ -5,14 +5,25 @@
 #include <stdio.h>
 #include <stdint.h>
 #include <string.h>
+#include <stdbool.h>
+
+static bool detected = false;
 
 void portexpander_init(void)
 {
     uint8_t addr = 0x21;
+    int ret;
 
     // Enable pull-ups for buttons
     uint8_t command[] = {0x43, 0x68};
-    I2C_MasterWrite(MXC_I2C1_BUS0, addr << 1, command, 2, 0);
+    ret = I2C_MasterWrite(MXC_I2C1_BUS0, addr << 1, command, 2, 0);
+
+    if(ret != 2) {
+        printf("portexpander NOT detected\n");
+        detected = false;
+        return;
+    }
+    detected = true;
 
     // Set _all_ outputs to open-drain to support the high side p-channel transistors.
     command[0] = 0x4F; command[1] = 0x01;
@@ -31,10 +42,17 @@ uint8_t portexpander_get(void)
 {
     uint8_t addr = 0x21;
     uint8_t command[] = {0x00};
-    I2C_MasterWrite(MXC_I2C1_BUS0, addr << 1, command, 1, 1);
-    uint8_t buf;
-    I2C_MasterRead(MXC_I2C1_BUS0, addr << 1, &buf, 1, 0);
+    uint8_t buf = 0xFF;
+
+    if(detected) {
+        I2C_MasterWrite(MXC_I2C1_BUS0, addr << 1, command, 1, 1);
+        I2C_MasterRead(MXC_I2C1_BUS0, addr << 1, &buf, 1, 0);
+    }
+
     return buf;
 }
 
-
+bool portexpander_detected(void)
+{
+    return detected;
+}
diff --git a/lib/card10/portexpander.h b/lib/card10/portexpander.h
index a2532cc36..66937c29d 100644
--- a/lib/card10/portexpander.h
+++ b/lib/card10/portexpander.h
@@ -2,8 +2,10 @@
 #define PORTEXPANDER_H
 
 #include <stdint.h>
+#include <stdbool.h>
 
 void portexpander_init(void);
 uint8_t portexpander_get(void);
+bool portexpander_detected(void);
 
 #endif
diff --git a/lib/sdk/Libraries/Boards/card10/Source/board.c b/lib/sdk/Libraries/Boards/card10/Source/board.c
index 8c00f9ec6..e1407f08c 100644
--- a/lib/sdk/Libraries/Boards/card10/Source/board.c
+++ b/lib/sdk/Libraries/Boards/card10/Source/board.c
@@ -42,7 +42,6 @@
 #include "uart.h"
 #include "gpio.h"
 #include "mxc_pins.h"
-#include "led.h"
 #include "pb.h"
 #include "spixfc.h"
 
@@ -51,18 +50,13 @@ mxc_uart_regs_t * ConsoleUart = MXC_UART_GET_UART(CONSOLE_UART);
 extern uint32_t SystemCoreClock;
 
 const gpio_cfg_t pb_pin[] = {
-    {PORT_0, PIN_23, GPIO_FUNC_IN, GPIO_PAD_PULL_UP},   // TOP GPIO3 / Button 1
     {PORT_0, PIN_20, GPIO_FUNC_IN, GPIO_PAD_PULL_UP},   // Wristband GPIO1
-    {PORT_1, PIN_7, GPIO_FUNC_IN, GPIO_PAD_PULL_UP},   // TOP GPIO5 / Button 2
+    {PORT_0, PIN_20, GPIO_FUNC_IN, GPIO_PAD_PULL_UP},   // Wristband GPIO1
+    {PORT_0, PIN_23, GPIO_FUNC_IN, GPIO_PAD_PULL_UP},   // TOP GPIO3 / Button 3
+    {PORT_1, PIN_7, GPIO_FUNC_IN, GPIO_PAD_PULL_UP},   // TOP GPIO5 / Button 4
 };
 const unsigned int num_pbs = (sizeof(pb_pin) / sizeof(gpio_cfg_t));
 
-const gpio_cfg_t led_pin[] = {
-    {PORT_0, PIN_21, GPIO_FUNC_OUT, GPIO_PAD_NONE},     // Wristband GPIO2
-    {PORT_0, PIN_22, GPIO_FUNC_OUT, GPIO_PAD_NONE},     // Wristband GPIO3
-};
-const unsigned int num_leds = (sizeof(led_pin) / sizeof(gpio_cfg_t));
-
 /***** File Scope Variables *****/
 const uart_cfg_t uart_cfg = {
     .parity = UART_PARITY_DISABLE,
@@ -115,16 +109,6 @@ int Board_Init(void)
         return err;
     }
 
-    if ((err = PB_Init()) != E_NO_ERROR) {
-        MXC_ASSERT_FAIL();
-        return err;
-    }
-
-    if ((err = LED_Init()) != E_NO_ERROR) {
-        MXC_ASSERT_FAIL();
-        return err;
-    }
-
     return E_NO_ERROR;
 }
 
diff --git a/lib/sdk/Libraries/Boards/card10/meson.build b/lib/sdk/Libraries/Boards/card10/meson.build
index 7d28fc044..06ee6ae34 100644
--- a/lib/sdk/Libraries/Boards/card10/meson.build
+++ b/lib/sdk/Libraries/Boards/card10/meson.build
@@ -5,9 +5,7 @@ includes = include_directories(
 
 sources = files(
   './Source/board.c',
-  '../Source/led.c',
   '../Source/mx25.c',
-  '../Source/pb.c',
   '../Source/stdio.c',
 )
 
-- 
GitLab