[firmware] rev1 pcb brought up.

Change-Id: Ib2b638cf291343e092d05d70f6c301cbdeaf1d6c
diff --git a/firmware/app/zedmon/ina231.c b/firmware/app/zedmon/ina231.c
index 10e8d72..98f397d 100644
--- a/firmware/app/zedmon/ina231.c
+++ b/firmware/app/zedmon/ina231.c
@@ -3,8 +3,10 @@
 #include <app/zedmon/usb.h>
 #include <err.h>
 #include <dev/i2c.h>
+#include <lib/cbuf.h>
 #include <lib/console.h>
 #include <platform.h>
+#include <platform/timer_capture.h>
 #include <stdint.h>
 #include <stdio.h>
 
@@ -73,6 +75,14 @@
     INA231_ME_SOL  = 1 << 15, // Assert Alert on Shunt Over Voltage Limit.
 };
 
+typedef struct __attribute__((packed)) {
+    lk_bigtime_t time;
+    uint8_t channel;
+} ina231_alert_event_t;
+
+static cbuf_t ina231_alert_events;
+static stm32_timer_capture_t ina231_tc;
+
 static const int INA231_BUS = 2;
 static const uint8_t INA231_ADDR = 0x40;
 
@@ -83,6 +93,7 @@
 static uint16_t ina231_v_shunt;
 static uint16_t ina231_v_bus;
 
+
 static status_t ina231_write(uint8_t reg, uint16_t val) {
     uint8_t data[2];
     data[0] = val >> 8;
@@ -108,13 +119,62 @@
     return NO_ERROR;
 }
 
-void ina231_init(void) {
+lk_bigtime_t current_time_hires_irq(void);
 
-    status_t ret = ina231_write(INA231_REG_CONFIG,
-                                INA231_CONFIG_MODE_CONT_SHUNT_BUS
-                                | INA231_CONFIG_V_SHUNT_CT_332_US
-                                | INA231_CONFIG_V_BUS_CT_332_US
-                                | INA231_CONFIG_AVG_1);
+bool stm32_exti6_irq(void) {
+    lk_bigtime_t now = current_time_hires_irq();
+    ina231_alert_event_t event = {
+        .channel = 0,
+        .time = now,
+    };
+
+    // This won't race because we're in interrupt context.
+    if (cbuf_space_avail(&ina231_alert_events) >= sizeof(event)) {
+        cbuf_write(&ina231_alert_events, &event, sizeof(event), false);
+        return true;
+    }
+    return false;
+}
+
+bool stm32_exti7_irq(void) {
+    // TODO(konkers): Implement.
+    return false;
+}
+
+static bool ina231_alert0_irq(uint64_t val) {
+    ina231_alert_event_t event = {
+        .channel = 0,
+        .time = val,
+    };
+
+    // This won't race because we're in interrupt context.
+    if (cbuf_space_avail(&ina231_alert_events) >= sizeof(event)) {
+        cbuf_write(&ina231_alert_events, &event, sizeof(event), false);
+        return true;
+    }
+    return false;
+}
+
+void ina231_init(void) {
+    cbuf_initialize(&ina231_alert_events, 32);
+
+    ina231_tc.chan[0] = (stm32_timer_capture_channel_t){
+        .flags = STM32_TIMER_CAPTURE_CHAN_FLAG_FALLING | STM32_TIMER_CAPTURE_CHAN_FLAG_ENABLE,
+        .cb = ina231_alert0_irq,
+    };
+
+    stm32_timer_capture_setup(&ina231_tc, 3, 48);
+
+    status_t ret = ina231_write(INA231_REG_MASK_ENABLE, INA231_ME_CNVR);
+    if (ret != NO_ERROR) {
+        printf("Error configuring ina231: %d\n", ret);
+    }
+
+    ret = ina231_write(INA231_REG_CONFIG,
+                       INA231_CONFIG_MODE_CONT_SHUNT_BUS
+                       | INA231_CONFIG_V_SHUNT_CT_332_US
+                       | INA231_CONFIG_V_BUS_CT_332_US
+                       | INA231_CONFIG_AVG_1);
     if (ret != NO_ERROR) {
         printf("Error configuring ina231: %d\n", ret);
     }
@@ -123,40 +183,44 @@
 }
 
 
-void ina231_ping(void) {
-    status_t ret;
+void ina231_loop(void) {
+    while (true) {
+        ina231_alert_event_t event;
+        cbuf_read(&ina231_alert_events, &event, sizeof(event), true);
+        status_t ret;
 
-    uint16_t status;
-    ret = ina231_read(INA231_REG_MASK_ENABLE, &status);
-    if (ret != NO_ERROR) {
-        ina231_errors++;
-        return;
+        uint16_t status;
+        ret = ina231_read(INA231_REG_MASK_ENABLE, &status);
+        if (ret != NO_ERROR) {
+            ina231_errors++;
+            continue;
+        }
+
+        if (!(status & INA231_ME_CRVF)) {
+            printf("alert with no crvf!\n");
+            continue;
+        }
+
+        uint16_t v_shunt;
+        uint16_t v_bus;
+        ret = ina231_read(INA231_REG_SHUNT_VOLTAGE, &v_shunt);
+        if (ret != NO_ERROR) {
+            ina231_errors++;
+            continue;
+        }
+
+        ret = ina231_read(INA231_REG_BUS_VOLTAGE, &v_bus);
+        if (ret != NO_ERROR) {
+            ina231_errors++;
+            continue;
+        }
+
+        ina231_v_shunt = v_shunt;
+        ina231_v_bus = v_bus;
+
+        ina231_samples++;
+        zedmon_usb_add_sample(event.time, v_shunt, v_bus);
     }
-
-    if (!(status & INA231_ME_CRVF)) {
-        return;
-    }
-    lk_bigtime_t timestamp = current_time_hires();
-
-    uint16_t v_shunt;
-    uint16_t v_bus;
-    ret = ina231_read(INA231_REG_SHUNT_VOLTAGE, &v_shunt);
-    if (ret != NO_ERROR) {
-        ina231_errors++;
-        return;
-    }
-
-    ret = ina231_read(INA231_REG_BUS_VOLTAGE, &v_bus);
-    if (ret != NO_ERROR) {
-        ina231_errors++;
-        return;
-    }
-
-    ina231_v_shunt = v_shunt;
-    ina231_v_bus = v_bus;
-
-    ina231_samples++;
-    zedmon_usb_add_sample(timestamp, v_shunt, v_bus);
 }
 
 static int cmd_ina231_status(int argc, const cmd_args *argv) {
@@ -197,7 +261,6 @@
 }
 
 static int cmd_ina231_read(int argc, const cmd_args *argv) {
-
     if (argc != 2) {
         printf("usage: ina_231_read <reg>\n");
         return 1;
diff --git a/firmware/app/zedmon/ina231.h b/firmware/app/zedmon/ina231.h
index b8855d7..9f22726 100644
--- a/firmware/app/zedmon/ina231.h
+++ b/firmware/app/zedmon/ina231.h
@@ -2,7 +2,6 @@
 #define __APP_ZEDMON_INA321_H
 
 void ina231_init(void);
-void ina231_ping(void);
+void ina231_loop(void);
 
 #endif  // __APP_ZEDMON_INA321_H
-
diff --git a/firmware/app/zedmon/main.c b/firmware/app/zedmon/main.c
index cadb59d..1d1104f 100644
--- a/firmware/app/zedmon/main.c
+++ b/firmware/app/zedmon/main.c
@@ -1,7 +1,10 @@
 #include <app.h>
+#include <dev/gpio.h>
 #include <kernel/thread.h>
+#include <lib/console.h>
 #include <stdint.h>
 #include <stdio.h>
+#include <target/gpioconfig.h>
 
 #include "ina231.h"
 
@@ -13,13 +16,25 @@
 static void zedmon_entry(const struct app_descriptor *app, void *args)
 {
     printf("zedmon app started\n");
-    while(true) {
-        ina231_ping();
-    }
+    ina231_loop();
 }
 
+static int cmd_relay(int argc, const cmd_args *argv) {
+    if (argc != 2) {
+        printf("usage: relay <bool>\n");
+        return 1;
+    }
+
+    gpio_set(GPIO_POWER_ENABLE_J, argv[1].b);
+
+    return 0;
+}
+
+STATIC_COMMAND_START
+STATIC_COMMAND("relay", "set relay state", &cmd_relay)
+STATIC_COMMAND_END(relay);
+
 APP_START(zedmon)
     .init = zedmon_init,
     .entry = zedmon_entry,
 APP_END
-
diff --git a/firmware/target/zedmon/include/target/gpioconfig.h b/firmware/target/zedmon/include/target/gpioconfig.h
index 6e8145f..df12759 100644
--- a/firmware/target/zedmon/include/target/gpioconfig.h
+++ b/firmware/target/zedmon/include/target/gpioconfig.h
@@ -29,8 +29,10 @@
 #define GPIO_LED_GREEN GPIO(GPIO_PORT_B, 14)
 #define GPIO_LED_BLUE  GPIO(GPIO_PORT_B, 15)
 
-#define GPIO_SCL       GPIO(GPIO_PORT_B, 10)
-#define GPIO_SDA       GPIO(GPIO_PORT_B, 11)
+#define GPIO_SCL        GPIO(GPIO_PORT_B, 10)
+#define GPIO_SDA        GPIO(GPIO_PORT_B, 11)
+#define GPIO_ALERT_HIGH GPIO(GPIO_PORT_A, 6)
+#define GPIO_ALERT_LOW  GPIO(GPIO_PORT_A, 7)
 
 #define GPIO_BOARD_ID0 GPIO(GPIO_PORT_A, 0)
 #define GPIO_BOARD_ID1 GPIO(GPIO_PORT_A, 1)
@@ -40,4 +42,6 @@
 #define GPIO_UART_TX   GPIO(GPIO_PORT_A, 9)
 #define GPIO_UART_RX   GPIO(GPIO_PORT_A, 10)
 
+#define GPIO_POWER_ENABLE_J GPIO(GPIO_PORT_B, 12)
+
 #endif
diff --git a/firmware/target/zedmon/init.c b/firmware/target/zedmon/init.c
index 9a6b4e7..c08a0fa 100644
--- a/firmware/target/zedmon/init.c
+++ b/firmware/target/zedmon/init.c
@@ -48,6 +48,8 @@
 
     gpio_config(GPIO_SCL, GPIO_STM32_AF | GPIO_STM32_AFn(1));
     gpio_config(GPIO_SDA, GPIO_STM32_AF | GPIO_STM32_AFn(1));
+    gpio_config(GPIO_ALERT_HIGH, GPIO_STM32_AF | GPIO_STM32_AFn(1));
+    gpio_config(GPIO_ALERT_LOW, GPIO_STM32_AF | GPIO_STM32_AFn(1));
 
     gpio_config(GPIO_BOARD_ID0, GPIO_INPUT);
     gpio_config(GPIO_BOARD_ID1, GPIO_INPUT);
@@ -57,10 +59,14 @@
     gpio_set(GPIO_LED_RED, 1);
     gpio_set(GPIO_LED_GREEN, 1);
     gpio_set(GPIO_LED_BLUE, 1);
+
     gpio_config(GPIO_LED_RED, GPIO_OUTPUT | GPIO_STM32_OD);
     gpio_config(GPIO_LED_GREEN, GPIO_OUTPUT | GPIO_STM32_OD);
     gpio_config(GPIO_LED_BLUE, GPIO_OUTPUT | GPIO_STM32_OD);
 
+    gpio_set(GPIO_POWER_ENABLE_J, 0);
+    gpio_config(GPIO_POWER_ENABLE_J, GPIO_OUTPUT);
+
     board_id = gpio_get(GPIO_BOARD_ID0)
         | gpio_get(GPIO_BOARD_ID1) << 1
         | gpio_get(GPIO_BOARD_ID2) << 2