[firmware] Add beginnings of usb proto support.
Change-Id: Iaa4f51f650f4e58fff0c576a5a22a7fd85de7b7e
diff --git a/firmware/app/zedmon/include/app/zedmon/usb.h b/firmware/app/zedmon/include/app/zedmon/usb.h
new file mode 100644
index 0000000..e41d7b9
--- /dev/null
+++ b/firmware/app/zedmon/include/app/zedmon/usb.h
@@ -0,0 +1,7 @@
+#ifndef __APP_ZEDMON_USB_H
+#define __APP_ZEDMON_USB_H
+
+void zedmon_usb_init(int data_ep_addr);
+
+#endif // __APP_ZEDMON_USB_H
+
diff --git a/firmware/app/zedmon/include/app/zedmon/usb_proto.h b/firmware/app/zedmon/include/app/zedmon/usb_proto.h
new file mode 100644
index 0000000..ccf10b2
--- /dev/null
+++ b/firmware/app/zedmon/include/app/zedmon/usb_proto.h
@@ -0,0 +1,47 @@
+#ifndef __APP_ZEDMON_USB_PROTO_H_
+#define __APP_ZEDMON_USB_PROTO_H_
+
+#include <assert.h>
+#include <stdint.h>
+
+typedef enum {
+ ZEDMON_USB_PACKET_QUERY = 0x00,
+ ZEDMON_USB_PACKET_ENABLE_REPORTING = 0x10,
+ ZEDMON_USB_PACKET_DISABLE_REPORTING = 0x11,
+ ZEDMON_USB_PACKET_REPORT_FORMAT = 0x80,
+ ZEDMON_USB_PACKET_REPORT = 0x81,
+} zedmon_usb_packet_type_t;
+
+typedef enum {
+ ZEDMON_USB_TYPE_UINT8 = 0x00,
+ ZEDMON_USB_TYPE_UINT16 = 0x01,
+ ZEDMON_USB_TYPE_UINT32 = 0x02,
+ ZEDMON_USB_TYPE_UINT64 = 0x03,
+ ZEDMON_USB_TYPE_FLOAT32 = 0x10,
+ ZEDMON_USB_TYPE_STRING = 0x11,
+} zedmon_usb_type_t;
+
+typedef enum {
+ ZEDMON_USB_UNIT_AMPERE = 0x00,
+ ZEDMON_USB_UNIT_VOLTS = 0x01,
+} zedmon_usb_unit_t;
+
+typedef struct {
+ uint8_t packet_type;
+ uint8_t index;
+ uint8_t type; // zedmon_usb_type_t
+ uint8_t unit; // zedmon_usb_unit_t
+ float scale;
+ char name[56];
+} zedmon_usb_report_format_t;
+
+static_assert(sizeof(zedmon_usb_report_format_t) == 64);
+static_assert(offsetof(zedmon_usb_report_format_t, packet_type) == 0);
+static_assert(offsetof(zedmon_usb_report_format_t, index) == 1);
+static_assert(offsetof(zedmon_usb_report_format_t, type) == 2);
+static_assert(offsetof(zedmon_usb_report_format_t, unit) == 3);
+static_assert(offsetof(zedmon_usb_report_format_t, scale) == 4);
+static_assert(offsetof(zedmon_usb_report_format_t, name) == 8);
+
+#endif // __APP_ZEDMON_USB_PROTO_H_
+
diff --git a/firmware/app/zedmon/rules.mk b/firmware/app/zedmon/rules.mk
index 23676bb..24651ef 100644
--- a/firmware/app/zedmon/rules.mk
+++ b/firmware/app/zedmon/rules.mk
@@ -4,6 +4,8 @@
MODULE_SRCS += \
$(LOCAL_DIR)/ina231.c \
- $(LOCAL_DIR)/main.c
+ $(LOCAL_DIR)/main.c \
+ $(LOCAL_DIR)/usb.c
+
include make/module.mk
diff --git a/firmware/app/zedmon/usb.c b/firmware/app/zedmon/usb.c
new file mode 100644
index 0000000..093310a
--- /dev/null
+++ b/firmware/app/zedmon/usb.c
@@ -0,0 +1,336 @@
+#include <app/zedmon/usb.h>
+
+#include <assert.h>
+#include <app/zedmon/usb_proto.h>
+#include <compiler.h>
+#include <debug.h>
+#include <dev/udc.h>
+#include <dev/usb.h>
+#include <dev/usbc.h>
+#include <err.h>
+#include <kernel/mutex.h>
+#include <kernel/port.h>
+#include <kernel/thread.h>
+#include <lib/console.h>
+#include <stdint.h>
+#include <string.h>
+#include <trace.h>
+
+#define DATA_IN_EP_ADDR_OFFSET (0x0B)
+#define DATA_OUT_EP_ADDR_OFFSET (0x12)
+
+#define W(w) (w & 0xff), (w >> 8)
+
+static uint8_t zedmon_if_descriptor[] = {
+ 0x09, /* length */
+ INTERFACE, /* type */
+ 0x00, /* interface num */
+ 0x00, /* alternates */
+ 0x02, /* endpoint count */
+ 0xff, /* interface class */
+ 0xff, /* interface subclass */
+ 0x00, /* interface protocol */
+ 0x00, /* string index */
+
+ /* endpoint 1 IN */
+ 0x07, /* length */
+ ENDPOINT, /* type */
+ 0x83, /* address: 1 IN */
+ 0x02, /* type: bulk */
+ W(64), /* max packet size: 64 */
+ 00, /* interval */
+
+ /* endpoint 1 OUT */
+ 0x07, /* length */
+ ENDPOINT, /* type */
+ 0x03, /* address: 1 OUT */
+ 0x02, /* type: bulk */
+ W(64), /* max packet size: 64 */
+ 00, /* interval */
+};
+
+static zedmon_usb_report_format_t zedmon_report_formats[] = {
+ {
+ .packet_type = ZEDMON_USB_PACKET_REPORT_FORMAT,
+ .index = 0,
+ .type = ZEDMON_USB_TYPE_UINT16,
+ .unit = ZEDMON_USB_UNIT_VOLTS,
+ .scale = 2.5e-6f,
+ .name = "v_shunt",
+ },
+ {
+ .packet_type = ZEDMON_USB_PACKET_REPORT_FORMAT,
+ .index = 1,
+ .type = ZEDMON_USB_TYPE_UINT16,
+ .unit = ZEDMON_USB_UNIT_VOLTS,
+ .scale = 1.5e-3f,
+ .name = "v_bus",
+ },
+ {
+ .packet_type = ZEDMON_USB_PACKET_REPORT_FORMAT,
+ .index = 0xff,
+ .type = 0,
+ .unit = 0,
+ .scale =0.0f,
+ .name = "",
+ },
+};
+
+static int zedmon_ep;
+
+typedef enum {
+ ZEDMON_PORT_CTX_USB_RX = 0x0,
+ ZEDMON_PORT_CTX_USB_TX = 0x1,
+ ZEDMON_PORT_CTX_I2C = 0x2,
+} zedmon_port_context_t;
+
+static port_t zedmon_usb_rx_port;
+static port_t zedmon_usb_tx_port;
+static port_t zedmon_usb_port_group;
+
+static thread_t *zedmon_usb_thread;
+static bool zedmon_tx_busy;
+
+static status_t ep_cb_rx(ep_t endpoint, usbc_transfer_t *t);
+static status_t ep_cb_tx(ep_t endpoint, usbc_transfer_t *t);
+
+static void queue_rx(void)
+{
+ static usbc_transfer_t transfer;
+ static uint8_t buf[512];
+
+ transfer.callback = &ep_cb_rx;
+ transfer.result = 0;
+ transfer.buf = &buf;
+ transfer.buflen = sizeof(buf);
+ transfer.bufpos = 0;
+ transfer.extra = 0;
+
+ usbc_queue_rx(zedmon_ep, &transfer);
+}
+
+static status_t queue_tx(void *data, size_t len)
+{
+ if (zedmon_tx_busy) {
+ return ERR_BUSY;
+ }
+
+ static usbc_transfer_t transfer;
+ transfer.callback = &ep_cb_tx;
+ transfer.result = 0;
+ transfer.buf = data;
+ transfer.buflen = len;
+ transfer.bufpos = 0;
+ transfer.extra = 0;
+
+ zedmon_tx_busy = true;
+ usbc_queue_tx(zedmon_ep, &transfer);
+ return NO_ERROR;
+}
+
+static status_t ep_cb_rx(ep_t endpoint, usbc_transfer_t *t)
+{
+#if LOCAL_TRACE
+ LTRACEF("ep %u transfer %p\n", endpoint, t);
+ usbc_dump_transfer(t);
+
+ if (t->result >= 0) {
+ hexdump8(t->buf, t->bufpos);
+ }
+#endif
+
+ //printf("ep %u transfer %p\n", endpoint, t);
+
+ if (t->result >= 0) {
+ if (t->bufpos > 1) {
+ port_packet_t packet;
+ int command_length =
+ t->bufpos < sizeof(packet.value) ? t->bufpos : sizeof(packet.value);
+ memcpy(&packet.value, t->buf, command_length);
+ packet.value[0] = ((uint8_t *)t->buf)[0];
+ port_write(zedmon_usb_rx_port, &packet, 1);
+ }
+ queue_rx();
+ } else {
+ printf("bad rx\n");
+ }
+
+
+ return NO_ERROR;
+}
+
+static status_t ep_cb_tx(ep_t endpoint, usbc_transfer_t *t)
+{
+ //printf("ep %u transfer %p\n", endpoint, t);
+#if LOCAL_TRACE
+ LTRACEF("ep %u transfer %p\n", endpoint, t);
+ usbc_dump_transfer(t);
+#endif
+
+ if (t->result >= 0) {
+ port_packet_t packet;
+ packet.value[0] = 0x0;
+ port_write(zedmon_usb_tx_port, &packet, 1);
+ } else {
+ printf("bad tx\n");
+ }
+ return NO_ERROR;
+}
+
+
+static status_t zedmon_usb_callback(void *cookie, usb_callback_op_t op,
+ const union usb_callback_args *args)
+{
+#if LOCAL_TRACE
+ LTRACEF("cookie %p, op %u, args %p\n", cookie, op, args);
+#endif
+
+ if (op == USB_CB_ONLINE) {
+ usbc_setup_endpoint(zedmon_ep, USB_IN, 0x40, USB_BULK);
+ usbc_setup_endpoint(zedmon_ep, USB_OUT, 0x40, USB_BULK);
+
+ queue_rx();
+ } else if (op == USB_CB_SETUP_MSG) {
+ //usbc_ep0_ack();
+ }
+ return NO_ERROR;
+}
+
+
+static void zedmon_usb_handle_query_packet(uint8_t values[7]) {
+ uint8_t index = values[0];
+
+ if (index >= countof(zedmon_report_formats)) {
+ index = countof(zedmon_report_formats) - 1;
+ }
+
+ queue_tx(&zedmon_report_formats[index], sizeof(zedmon_report_formats[index]));
+}
+
+static void zedmon_usb_handle_usb_rx_port(port_result_t *result) {
+ zedmon_usb_packet_type_t type =
+ (zedmon_usb_packet_type_t) result->packet.value[0];
+
+ switch (type) {
+ case ZEDMON_USB_PACKET_QUERY:
+ zedmon_usb_handle_query_packet((uint8_t *)result->packet.value + 1);
+ break;
+ case ZEDMON_USB_PACKET_ENABLE_REPORTING:
+ break;
+ case ZEDMON_USB_PACKET_DISABLE_REPORTING:
+ break;
+
+ // These are Device -> Host packets which we should never see.
+ case ZEDMON_USB_PACKET_REPORT_FORMAT:
+ break;
+ case ZEDMON_USB_PACKET_REPORT:
+ break;
+ }
+}
+
+static int zedmon_usb_thread_entry(void *arg) {
+ while (true) {
+ port_result_t result;
+ port_read(zedmon_usb_port_group, INFINITE_TIME, &result);
+ zedmon_port_context_t context = (zedmon_port_context_t)result.ctx;
+ switch(context) {
+ case ZEDMON_PORT_CTX_USB_RX:
+ zedmon_usb_handle_usb_rx_port(&result);
+ if (zedmon_tx_busy == false) {
+ //queue_rx();
+ }
+ break;
+
+ case ZEDMON_PORT_CTX_USB_TX:
+ zedmon_tx_busy = false;
+ //queue_rx();
+ break;
+
+ case ZEDMON_PORT_CTX_I2C:
+ break;
+
+ }
+ }
+ return 0;
+}
+
+void zedmon_usb_init(int data_ep_addr) {
+ status_t ret;
+
+ ret = port_create("zm_usb_rx", PORT_MODE_UNICAST, &zedmon_usb_rx_port);
+ if (ret != NO_ERROR) {
+ printf("error creating zm_usb_rx: %d\n", ret);
+ }
+
+ port_t usb_rx_reader;
+ ret = port_open("zm_usb_rx", (void *)ZEDMON_PORT_CTX_USB_RX, &usb_rx_reader);
+ if (ret != NO_ERROR) {
+ printf("error opening zm_usb_rx: %d\n", ret);
+ }
+
+ ret = port_create("zm_usb_tx", PORT_MODE_UNICAST, &zedmon_usb_tx_port);
+ if (ret != NO_ERROR) {
+ printf("error creating zm_usb_rx: %d\n", ret);
+ }
+
+ port_t usb_tx_reader;
+ ret = port_open("zm_usb_tx", (void *)ZEDMON_PORT_CTX_USB_TX, &usb_tx_reader);
+ if (ret != NO_ERROR) {
+ printf("error opening zm_usb_tx: %d\n", ret);
+ }
+
+
+ port_t ports[] = {usb_rx_reader, usb_tx_reader};
+
+ ret = port_group(ports, countof(ports), &zedmon_usb_port_group);
+
+ zedmon_ep = data_ep_addr;
+
+ zedmon_if_descriptor[DATA_IN_EP_ADDR_OFFSET] = data_ep_addr | 0x80;
+ zedmon_if_descriptor[DATA_OUT_EP_ADDR_OFFSET] = data_ep_addr;
+
+ usb_append_interface_lowspeed(zedmon_if_descriptor, sizeof(zedmon_if_descriptor));
+ usb_append_interface_highspeed(zedmon_if_descriptor, sizeof(zedmon_if_descriptor));
+
+ usb_register_callback(&zedmon_usb_callback, NULL);
+
+ zedmon_tx_busy = false;
+ zedmon_usb_thread = thread_create("zedmon_usb", &zedmon_usb_thread_entry, 0x0,
+ DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
+ thread_detach(zedmon_usb_thread);
+ thread_resume(zedmon_usb_thread);
+}
+
+#include "stm32f0xx_hal.h"
+static void print_epr(int i, uint16_t epr) {
+ printf("ep%dr: ea:%d stat_tx:%d dtog_tx:%d ctr_tx:%d ep_kind:%d ep_type:%d\n"
+ " setup:%d stat_rx:%d dtog_rx:%d ctr_rx:%d\n",
+ i,
+ epr & 0xf,
+ (epr >> 4) & 0x3,
+ (epr >> 6) & 0x1,
+ (epr >> 7) & 0x1,
+ (epr >> 8) & 0x1,
+ (epr >> 9) & 0x3,
+ (epr >> 11) & 0x1,
+ (epr >> 12) & 0x3,
+ (epr >> 14) & 0x1,
+ (epr >> 15) & 0x1);
+}
+
+static int cmd_usb_dump(int argc, const cmd_args *argv) {
+ print_epr(0, USB->EP0R);
+ print_epr(1, USB->EP1R);
+ print_epr(2, USB->EP2R);
+ print_epr(3, USB->EP3R);
+ print_epr(4, USB->EP4R);
+ print_epr(5, USB->EP5R);
+ print_epr(6, USB->EP6R);
+ print_epr(7, USB->EP7R);
+
+ return NO_ERROR;
+}
+
+STATIC_COMMAND_START
+STATIC_COMMAND("usb_dump", "usb dump", &cmd_usb_dump)
+STATIC_COMMAND_END(usb);
diff --git a/firmware/target/zedmon/usb.c b/firmware/target/zedmon/usb.c
index 3e98cf6..b12fe53 100644
--- a/firmware/target/zedmon/usb.c
+++ b/firmware/target/zedmon/usb.c
@@ -21,17 +21,19 @@
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <err.h>
-#include <debug.h>
-#include <stdio.h>
-#include <trace.h>
-#include <target.h>
+#include <app/zedmon/usb.h>
#include <compiler.h>
+#include <debug.h>
#include <dev/usb.h>
#include <dev/usbc.h>
#include <dev/usb/class/cdcserial.h>
+#include <err.h>
#include <hw/usb.h>
#include <lk/init.h>
+#include <stdio.h>
+#include <stm32f0xx.h>
+#include <target.h>
+#include <trace.h>
#define LOCAL_TRACE 0
@@ -52,7 +54,7 @@
W(0x0000), /* release */
0x2, /* manufacturer string */
0x1, /* product string */
- 0x0, /* serialno string */
+ 0x3, /* serialno string */
0x1, /* num configs */
};
@@ -82,34 +84,6 @@
static const uchar langid[] = { 0x04, 0x03, 0x09, 0x04 };
-static const uint8_t if_descriptor_lowspeed[] = {
- 0x09, /* length */
- INTERFACE, /* type */
- 0x01, /* interface num */
- 0x00, /* alternates */
- 0x02, /* endpoint count */
- 0xff, /* interface class */
- 0xff, /* interface subclass */
- 0x00, /* interface protocol */
- 0x00, /* string index */
-
- /* endpoint 1 IN */
- 0x07, /* length */
- ENDPOINT, /* type */
- 0x83, /* address: 1 IN */
- 0x02, /* type: bulk */
- W(64), /* max packet size: 64 */
- 00, /* interval */
-
- /* endpoint 1 OUT */
- 0x07, /* length */
- ENDPOINT, /* type */
- 0x03, /* address: 1 OUT */
- 0x02, /* type: bulk */
- W(64), /* max packet size: 64 */
- 00, /* interval */
-};
-
usb_config config = {
.lowspeed = {
.device = USB_DESC_STATIC(dev_descr),
@@ -125,85 +99,14 @@
.langid = USB_DESC_STATIC(langid),
};
-static status_t ep_cb_rx(ep_t endpoint, usbc_transfer_t *t);
-static status_t ep_cb_tx(ep_t endpoint, usbc_transfer_t *t);
+static const char *hex_digits = "0123456789abcdef";
-static void queue_rx(void)
-{
- static usbc_transfer_t transfer;
- static uint8_t buf[512];
-
- transfer.callback = &ep_cb_rx;
- transfer.result = 0;
- transfer.buf = &buf;
- transfer.buflen = sizeof(buf);
- transfer.bufpos = 0;
- transfer.extra = 0;
-
- usbc_queue_rx(3, &transfer);
-}
-
-static void queue_tx(void)
-{
- static usbc_transfer_t transfer;
- static uint8_t buf[512];
-
- for (uint i = 0; i < sizeof(buf); i++) {
- buf[i] = ~i;
+void set_serial_substr(uint32_t val, char *str) {
+ int i;
+ for (i = 0; i < 8; i++) {
+ *str++ = hex_digits[(val >> 28) & 0xf];
+ val <<= 4;
}
-
- transfer.callback = &ep_cb_tx;
- transfer.result = 0;
- transfer.buf = &buf;
- transfer.buflen = sizeof(buf);
- transfer.bufpos = 0;
- transfer.extra = 0;
-
- usbc_queue_tx(3, &transfer);
-}
-
-static status_t ep_cb_rx(ep_t endpoint, usbc_transfer_t *t)
-{
-#if LOCAL_TRACE
- LTRACEF("ep %u transfer %p\n", endpoint, t);
- usbc_dump_transfer(t);
-
- if (t->result >= 0) {
- hexdump8(t->buf, t->bufpos);
- }
-#endif
-
- if (t->result >= 0)
- queue_rx();
-
- return NO_ERROR;
-}
-
-static status_t ep_cb_tx(ep_t endpoint, usbc_transfer_t *t)
-{
-#if LOCAL_TRACE
- LTRACEF("ep %u transfer %p\n", endpoint, t);
- usbc_dump_transfer(t);
-#endif
-
- if (t->result >= 0)
- queue_tx();
-
- return NO_ERROR;
-}
-
-static status_t usb_cb(void *cookie, usb_callback_op_t op, const union usb_callback_args *args)
-{
- LTRACEF("cookie %p, op %u, args %p\n", cookie, op, args);
-
- if (op == USB_CB_ONLINE) {
- usbc_setup_endpoint(3, USB_IN, 0x40, USB_BULK);
- usbc_setup_endpoint(3, USB_OUT, 0x40, USB_BULK);
-
- queue_rx();
- queue_tx();
- }
- return NO_ERROR;
}
void target_usb_setup(void)
@@ -213,12 +116,19 @@
cdcserial_create_channel(0x1, 0x2);
cdcserial_init();
- usb_append_interface_lowspeed(if_descriptor_lowspeed, sizeof(if_descriptor_lowspeed));
- usb_append_interface_highspeed(if_descriptor_lowspeed, sizeof(if_descriptor_lowspeed));
- usb_register_callback(&usb_cb, NULL);
+ zedmon_usb_init(0x3);
usb_add_string("Zedmon", 1);
usb_add_string("Google Inc.", 2);
+ char serial_no[25];
+ volatile uint32_t *uid_regs = (volatile uint32_t *)UID_BASE;
+ int i;
+ for (i = 0; i < 3; i++) {
+ set_serial_substr(uid_regs[i], &serial_no[(2 - i) * 8]);
+ }
+ serial_no[24] = '\0';
+ usb_add_string(serial_no, 3);
+
usb_start();
}