boot: zephyr: adding indication LED and detect pin debounce

Add LED support and boot delay serial detect pin operation.

Signed-off-by: Jared Wolff <hello@jaredwolff.com>
diff --git a/boot/zephyr/Kconfig b/boot/zephyr/Kconfig
index ef3e834..cfbdd5e 100644
--- a/boot/zephyr/Kconfig
+++ b/boot/zephyr/Kconfig
@@ -435,6 +435,14 @@
 
 endchoice
 
+config MCUBOOT_INDICATION_LED
+	bool "Turns on LED indication when device is in DFU"
+	default n
+	help
+	  Device device activates the LED while in bootloader mode.
+	  bootloader-led0 alias must be set in the device's .dts
+	  definitions for this to work.
+
 config BOOT_MAX_LINE_INPUT_LEN
 	int "Maximum command line length"
 	default 512
@@ -466,6 +474,14 @@
 	  Logic value of the detect pin which triggers serial recovery
 	  mode.
 
+config BOOT_SERIAL_DETECT_DELAY
+	int "Prevents immediate boot into MCUBoot firmware."
+	default 0
+	help
+	  Used to prevent the bootloader from loading on button press.
+	  Useful for powering on when using the same button as
+	  the one used to place the device in bootloader mode.
+
 # Workaround for not being able to have commas in macro arguments
 DT_CHOSEN_Z_CONSOLE := zephyr,console
 
diff --git a/boot/zephyr/boards/circuitdojo_feather_nrf9160.conf b/boot/zephyr/boards/circuitdojo_feather_nrf9160.conf
index 078e390..82aac4b 100644
--- a/boot/zephyr/boards/circuitdojo_feather_nrf9160.conf
+++ b/boot/zephyr/boards/circuitdojo_feather_nrf9160.conf
@@ -14,6 +14,8 @@
 CONFIG_BOOT_SERIAL_DETECT_PORT="GPIO_0"
 CONFIG_BOOT_SERIAL_DETECT_PIN=12
 CONFIG_BOOT_SERIAL_DETECT_PIN_VAL=0
+CONFIG_BOOT_SERIAL_DETECT_DELAY=450
+CONFIG_MCUBOOT_INDICATION_LED=y
 
 # Size of mcuboot partition
 CONFIG_SIZE_OPTIMIZATIONS=y
\ No newline at end of file
diff --git a/boot/zephyr/boards/sparkfun_thing_plus_nrf9160.conf b/boot/zephyr/boards/sparkfun_thing_plus_nrf9160.conf
index 078e390..82aac4b 100644
--- a/boot/zephyr/boards/sparkfun_thing_plus_nrf9160.conf
+++ b/boot/zephyr/boards/sparkfun_thing_plus_nrf9160.conf
@@ -14,6 +14,8 @@
 CONFIG_BOOT_SERIAL_DETECT_PORT="GPIO_0"
 CONFIG_BOOT_SERIAL_DETECT_PIN=12
 CONFIG_BOOT_SERIAL_DETECT_PIN_VAL=0
+CONFIG_BOOT_SERIAL_DETECT_DELAY=450
+CONFIG_MCUBOOT_INDICATION_LED=y
 
 # Size of mcuboot partition
 CONFIG_SIZE_OPTIMIZATIONS=y
\ No newline at end of file
diff --git a/boot/zephyr/main.c b/boot/zephyr/main.c
index 747d36c..3f17358 100644
--- a/boot/zephyr/main.c
+++ b/boot/zephyr/main.c
@@ -105,6 +105,49 @@
 
 MCUBOOT_LOG_MODULE_REGISTER(mcuboot);
 
+#ifdef CONFIG_MCUBOOT_INDICATION_LED
+/*
+ * Devicetree helper macro which gets the 'flags' cell from a 'gpios'
+ * property, or returns 0 if the property has no 'flags' cell.
+ */
+#define FLAGS_OR_ZERO(node)                        \
+  COND_CODE_1(DT_PHA_HAS_CELL(node, gpios, flags), \
+              (DT_GPIO_FLAGS(node, gpios)),        \
+              (0))
+
+/*
+ * The led0 devicetree alias is optional. If present, we'll use it
+ * to turn on the LED whenever the button is pressed.
+ */
+
+#define LED0_NODE DT_ALIAS(bootloader_led0)
+
+#if DT_NODE_HAS_STATUS(LED0_NODE, okay) && DT_NODE_HAS_PROP(LED0_NODE, gpios)
+#define LED0_GPIO_LABEL DT_GPIO_LABEL(LED0_NODE, gpios)
+#define LED0_GPIO_PIN DT_GPIO_PIN(LED0_NODE, gpios)
+#define LED0_GPIO_FLAGS (GPIO_OUTPUT | FLAGS_OR_ZERO(LED0_NODE))
+#else 
+/* A build error here means your board isn't set up to drive an LED. */
+#error "Unsupported board: led0 devicetree alias is not defined"
+#endif
+
+const static struct device *led;
+
+void led_init(void)
+{
+    
+  led = device_get_binding(LED0_GPIO_LABEL);
+  if (led == NULL)
+  {
+    BOOT_LOG_ERR("Didn't find LED device %s\n", LED0_GPIO_LABEL);
+    return;
+  }
+
+  gpio_pin_configure(led, LED0_GPIO_PIN, LED0_GPIO_FLAGS);
+
+}
+#endif
+
 void os_heap_init(void);
 
 #if defined(CONFIG_ARM)
@@ -330,6 +373,11 @@
 
     BOOT_LOG_INF("Starting bootloader");
 
+#ifdef CONFIG_MCUBOOT_INDICATION_LED
+    /* LED init */
+    led_init();
+#endif
+
     os_heap_init();
 
     ZEPHYR_BOOT_LOG_START();
@@ -382,12 +430,52 @@
     __ASSERT(rc >= 0, "Error of the reading the detect pin.\n");
     if (detect_value == CONFIG_BOOT_SERIAL_DETECT_PIN_VAL &&
         !boot_skip_serial_recovery()) {
-        BOOT_LOG_INF("Enter the serial recovery mode");
-        rc = boot_console_init();
-        __ASSERT(rc == 0, "Error initializing boot console.\n");
-        boot_serial_start(&boot_funcs);
-        __ASSERT(0, "Bootloader serial process was terminated unexpectedly.\n");
-    }
+            
+#if CONFIG_BOOT_SERIAL_DETECT_DELAY > 0 
+        k_sleep(K_MSEC(50));
+
+        /* Get the uptime for debounce purposes. */
+        int64_t timestamp = k_uptime_get();
+
+        for(;;) {
+            
+#ifdef GPIO_INPUT
+            rc = gpio_pin_get_raw(detect_port, CONFIG_BOOT_SERIAL_DETECT_PIN);
+            detect_value = rc;
+#else
+            rc = gpio_pin_read(detect_port, CONFIG_BOOT_SERIAL_DETECT_PIN,
+                            &detect_value);
+#endif
+            __ASSERT(rc >= 0, "Error of the reading the detect pin.\n");
+
+            /* Get delta from when this started */
+            uint32_t delta = k_uptime_get() -  timestamp;
+
+            /* If not pressed OR if pressed > debounce period stop loop*/
+            if( delta >= CONFIG_BOOT_SERIAL_DETECT_DELAY || 
+                detect_value != CONFIG_BOOT_SERIAL_DETECT_PIN_VAL ) {
+                    break;
+                }
+
+
+            /* Delay 1 ms */
+            k_sleep(K_MSEC(1));
+        }
+#endif 
+
+        /* Then run DFU */
+        if (detect_value == CONFIG_BOOT_SERIAL_DETECT_PIN_VAL) {
+#ifdef CONFIG_MCUBOOT_INDICATION_LED
+            gpio_pin_set(led, LED0_GPIO_PIN, 1);
+#endif
+            BOOT_LOG_INF("Enter the serial recovery mode");
+            rc = boot_console_init();
+            __ASSERT(rc == 0, "Error initializing boot console.\n");
+            boot_serial_start(&boot_funcs);
+            __ASSERT(0, "Bootloader serial process was terminated unexpectedly.\n");
+        
+        }
+}
 #endif
 
 #ifdef CONFIG_BOOT_WAIT_FOR_USB_DFU