summaryrefslogtreecommitdiff
path: root/extra/sps_errs
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2015-07-10 13:07:50 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-07-11 00:28:11 +0000
commit47ccb26dd06fbe4782fac349d356f6c58fc8951e (patch)
tree35238920d2030ba09722b7a0cf8388ccfeea0a88 /extra/sps_errs
parent18ea8f4ec3c328cbbe2e9a432caa3337f26d4340 (diff)
downloadchrome-ec-47ccb26dd06fbe4782fac349d356f6c58fc8951e.tar.gz
Cr50: Add extra/sps_errs/ test program
This adds another test program to use with the EC connected to the build host via an FTDI USB-to-SPI adapater, This program sends an EC_CMD_HELLO host command to the EC. Options exist to display the bytes transferred over the SPI interface, and to truncate the message before its complete, to see how the EC reacts. BUG=chrome-os-partner:40969 BRANCH=none TEST=make buildall To try out the new test program: cd extra/sps_errs make ./prog ./prog -v ./prog -v -c 22 Change-Id: I1d370ecdbae047d9504bc6e5f73949d4e3aed9d9 Signed-off-by: Bill Richardson <wfrichar@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/284865 Reviewed-by: Vadim Bendebury <vbendeb@google.com>
Diffstat (limited to 'extra/sps_errs')
-rw-r--r--extra/sps_errs/.gitignore1
-rw-r--r--extra/sps_errs/Makefile37
-rw-r--r--extra/sps_errs/README28
-rw-r--r--extra/sps_errs/prog.c447
4 files changed, 513 insertions, 0 deletions
diff --git a/extra/sps_errs/.gitignore b/extra/sps_errs/.gitignore
new file mode 100644
index 0000000000..ea17491321
--- /dev/null
+++ b/extra/sps_errs/.gitignore
@@ -0,0 +1 @@
+prog
diff --git a/extra/sps_errs/Makefile b/extra/sps_errs/Makefile
new file mode 100644
index 0000000000..12224ad803
--- /dev/null
+++ b/extra/sps_errs/Makefile
@@ -0,0 +1,37 @@
+# Copyright 2015 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Use your own libmpsse if you want, but we're going to use the files
+# that are part of the Chromium OS trunks_client program.
+PLATFORM2 = ../../../../platform2
+MPSSE_DIR = $(PLATFORM2)/trunks/ftdi
+
+PROG = prog
+SRCS = prog.c $(MPSSE_DIR)/mpsse.c $(MPSSE_DIR)/support.c
+
+CFLAGS = \
+ -std=gnu99 \
+ -g3 \
+ -O3 \
+ -Wall \
+ -Werror \
+ -Wpointer-arith \
+ -Wcast-align \
+ -Wcast-qual \
+ -Wundef \
+ -Wsign-compare \
+ -Wredundant-decls \
+ -Wmissing-declarations
+
+CFLAGS += -I../../include -I${MPSSE_DIR} -I${PLATFORM2}
+
+CFLAGS += $(shell pkg-config --cflags libusb-1.0 libftdi1)
+LIBS += $(shell pkg-config --libs libusb-1.0 libftdi1)
+
+$(PROG): $(SRCS) Makefile
+ gcc $(CFLAGS) $(SRCS) $(LDFLAGS) $(LIBS) -o $@
+
+.PHONY: clean
+clean:
+ rm -rf $(PROG)
diff --git a/extra/sps_errs/README b/extra/sps_errs/README
new file mode 100644
index 0000000000..d1fbb6b43f
--- /dev/null
+++ b/extra/sps_errs/README
@@ -0,0 +1,28 @@
+SETUP:
+
+ Attach an EC to the build host using an FTDI USB-to-SPI adapter.
+
+BUILD:
+
+ make
+ ./prog
+
+
+USAGE:
+
+ Usage: ./prog [-v] [-c BYTES]
+
+ This sends a EC_CMD_HELLO host command. The -c option can
+ be used to truncate the exchange early, to see how the EC
+ deals with the interruption.
+
+NOTE:
+
+ Ubuntu Trusty uses an ancient version of libftdi.
+
+ If building outside of the Chromium chroot, you'll probably want to grab the
+ latest libftdi1-1.2.tar.bz2 from
+
+ http://www.intra2net.com/en/developer/libftdi/
+
+ and install it into /usr instead.
diff --git a/extra/sps_errs/prog.c b/extra/sps_errs/prog.c
new file mode 100644
index 0000000000..b649199068
--- /dev/null
+++ b/extra/sps_errs/prog.c
@@ -0,0 +1,447 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "mpsse.h"
+
+#include "ec_commands.h"
+
+static int opt_verbose;
+static size_t stop_after = -1;
+
+/* Communication handle */
+static struct mpsse_context *mpsse;
+
+/* enum ec_status meaning */
+static const char *ec_strerr(enum ec_status r)
+{
+ static const char * const strs[] = {
+ "SUCCESS",
+ "INVALID_COMMAND",
+ "ERROR",
+ "INVALID_PARAM",
+ "ACCESS_DENIED",
+ "INVALID_RESPONSE",
+ "INVALID_VERSION",
+ "INVALID_CHECKSUM",
+ "IN_PROGRESS",
+ "UNAVAILABLE",
+ "TIMEOUT",
+ "OVERFLOW",
+ "INVALID_HEADER",
+ "REQUEST_TRUNCATED",
+ "RESPONSE_TOO_BIG",
+ "BUS_ERROR",
+ "BUSY",
+ };
+ if (r >= EC_RES_SUCCESS && r <= EC_RES_BUSY)
+ return strs[r];
+
+ return "<undefined result>";
+};
+
+
+/****************************************************************************
+ * Debugging output
+ */
+
+#define LINELEN 16
+
+static void showline(uint8_t *buf, int len)
+{
+ int i;
+ printf(" ");
+ for (i = 0; i < len; i++)
+ printf(" %02x", buf[i]);
+ for (i = len; i < LINELEN; i++)
+ printf(" ");
+ printf(" ");
+ for (i = 0; i < len; i++)
+ printf("%c",
+ (buf[i] >= ' ' && buf[i] <= '~') ? buf[i] : '.');
+ printf("\n");
+}
+
+static void show(const char *fmt, uint8_t *buf, int len)
+{
+ int i, m, n;
+
+ if (!opt_verbose)
+ return;
+
+ printf(fmt, len);
+
+ m = len / LINELEN;
+ n = len % LINELEN;
+
+ for (i = 0; i < m; i++)
+ showline(buf + i * LINELEN, LINELEN);
+ if (n)
+ showline(buf + m * LINELEN, n);
+}
+
+/****************************************************************************
+ * Send command & receive result
+ */
+
+/*
+ * With proto v3, the kernel driver asks the EC for the max param size
+ * (EC_CMD_GET_PROTOCOL_INFO) at probe time, because it can vary depending on
+ * the bus and/or the supported commands.
+ *
+ * FIXME: For now we'll just hard-code a size.
+ */
+static uint8_t txbuf[128];
+
+/*
+ * Load the output buffer with a proto v3 request (header, then data, with
+ * checksum correct in header).
+ */
+static size_t prepare_request(int cmd, int version,
+ const uint8_t *data, size_t data_len)
+{
+ struct ec_host_request *request;
+ size_t i, total_len;
+ uint8_t csum = 0;
+
+ total_len = sizeof(*request) + data_len;
+ if (total_len > sizeof(txbuf)) {
+ printf("Request too large (%zd > %zd)\n",
+ total_len, sizeof(txbuf));
+ return -1;
+ }
+
+ /* Header first */
+ request = (struct ec_host_request *)txbuf;
+ request->struct_version = EC_HOST_REQUEST_VERSION;
+ request->checksum = 0;
+ request->command = cmd;
+ request->command_version = version;
+ request->reserved = 0;
+ request->data_len = data_len;
+
+ /* Then data */
+ memcpy(txbuf + sizeof(*request), data, data_len);
+
+ /* Update checksum */
+ for (i = 0; i < total_len; i++)
+ csum += txbuf[i];
+ request->checksum = -csum;
+
+ return total_len;
+}
+
+
+/* Timeout flag, so we don't wait forever */
+static int timedout;
+static void alarm_handler(int sig)
+{
+ timedout = 1;
+}
+
+/*
+ * Send command, wait for result. Return zero if communication succeeded; check
+ * response to see if the EC liked the command.
+ */
+static int send_cmd(int cmd, int version,
+ void *outbuf,
+ size_t outsize,
+ struct ec_host_response *hdr,
+ void *bodydest,
+ size_t bodylen)
+{
+ uint8_t *tptr, *hptr = 0, *bptr = 0;
+ size_t len, i;
+ uint8_t sum = 0;
+ int lastone = 0x1111;
+ int ret = 0;
+ size_t bytes_left = stop_after;
+ size_t bytes_sent = 0;
+
+
+ /* Load up the txbuf with the stuff to send */
+ len = prepare_request(cmd, version, outbuf, outsize);
+ if (len < 0)
+ return -1;
+
+ if (MPSSE_OK != Start(mpsse)) {
+ fprintf(stderr, "Start failed: %s\n",
+ ErrorString(mpsse));
+ return -1;
+ }
+
+ /* Send the command request */
+ if (len > bytes_left) {
+ printf("len %zd => %zd\n", len, bytes_left);
+ len = bytes_left;
+ }
+
+ show("Transfer(%d) =>\n", txbuf, len);
+ tptr = Transfer(mpsse, txbuf, len);
+ bytes_left -= len;
+ bytes_sent += len;
+ if (!tptr) {
+ fprintf(stderr, "Transfer failed: %s\n",
+ ErrorString(mpsse));
+ goto out;
+ }
+
+ show("Transfer(%d) <=\n", tptr, len);
+
+ /* Make sure the EC was listening */
+ for (i = 0; i < len; i++) {
+ switch (tptr[i]) {
+ case EC_SPI_PAST_END:
+ case EC_SPI_RX_BAD_DATA:
+ case EC_SPI_NOT_READY:
+ ret = tptr[i];
+ /* FALLTHROUGH */
+ default:
+ break;
+ }
+ if (ret)
+ break;
+ }
+ free(tptr);
+ if (ret) {
+ printf("HEY: EC no good (0x%02x)\n", ret);
+ goto out;
+ }
+
+ if (!bytes_left)
+ goto out;
+
+ /* Read until we see the response come along */
+
+ /* Give up eventually */
+ timedout = 0;
+ if (SIG_ERR == signal(SIGALRM, alarm_handler)) {
+ perror("Problem with signal handler");
+ goto out;
+ }
+ alarm(1);
+
+ if (opt_verbose)
+ printf("Wait:");
+
+ /* Read a byte at a time until we see the start of the frame.
+ * This is slow, but still faster than the EC. */
+ while (bytes_left) {
+ uint8_t *ptr = Read(mpsse, 1);
+ bytes_left--;
+ bytes_sent++;
+ if (!ptr) {
+ fprintf(stderr, "Read failed: %s\n",
+ ErrorString(mpsse));
+ alarm(0);
+ goto out;
+ }
+ if (opt_verbose && lastone != *ptr) {
+ printf(" %02x", *ptr);
+ lastone = *ptr;
+ }
+ if (*ptr == EC_SPI_FRAME_START) {
+ free(ptr);
+ break;
+ }
+ free(ptr);
+
+ if (timedout) {
+ fprintf(stderr, "timed out\n");
+ goto out;
+ }
+ }
+ alarm(0);
+
+ if (opt_verbose)
+ printf("\n");
+
+ if (!bytes_left)
+ goto out;
+
+ /* Now read the response header */
+ len = sizeof(*hdr);
+ if (len > bytes_left) {
+ printf("len %zd => %zd\n", len, bytes_left);
+ len = bytes_left;
+ }
+
+ hptr = Read(mpsse, len);
+ bytes_left -= len;
+ bytes_sent += len;
+ if (!hptr) {
+ fprintf(stderr, "Read failed: %s\n",
+ ErrorString(mpsse));
+ goto out;
+ }
+ show("Header(%d):\n", hptr, sizeof(*hdr));
+ memcpy(hdr, hptr, sizeof(*hdr));
+
+ /* Check the header */
+ if (hdr->struct_version != EC_HOST_RESPONSE_VERSION) {
+ printf("HEY: response version %d (should be %d)\n",
+ hdr->struct_version,
+ EC_HOST_RESPONSE_VERSION);
+ goto out;
+ }
+
+ if (hdr->data_len > bodylen) {
+ printf("HEY: response data_len %d is > %zd\n",
+ hdr->data_len,
+ bodylen);
+ goto out;
+ }
+
+ if (!bytes_left)
+ goto out;
+
+ len = hdr->data_len;
+ if (len > bytes_left) {
+ printf("len %zd => %zd\n", len, bytes_left);
+ len = bytes_left;
+ }
+
+ /* Read the data */
+ if (len) {
+ bptr = Read(mpsse, len);
+ bytes_left -= len;
+ bytes_sent += len;
+ if (!bptr) {
+ fprintf(stderr, "Read failed: %s\n",
+ ErrorString(mpsse));
+ goto out;
+ }
+ show("Body(%d):\n", bptr, hdr->data_len);
+ memcpy(bodydest, bptr, hdr->data_len);
+ }
+
+ /* Verify the checksum */
+ for (i = 0; i < sizeof(hdr); i++)
+ sum += hptr[i];
+ for (i = 0; i < hdr->data_len; i++)
+ sum += bptr[i];
+ if (sum)
+ printf("HEY: Checksum invalid\n");
+
+out:
+ printf("sent %zd bytes\n", bytes_sent);
+ if (!bytes_left)
+ printf("hit byte limit\n");
+ if (hptr)
+ free(hptr);
+ if (bptr)
+ free(bptr);
+
+ if (MPSSE_OK != Stop(mpsse)) {
+ fprintf(stderr, "Stop failed: %s\n",
+ ErrorString(mpsse));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/****************************************************************************/
+
+/**
+ * Try it.
+ *
+ * @return zero on success
+ */
+static int hello(void)
+{
+ struct ec_params_hello p;
+ struct ec_host_response resp;
+ struct ec_response_hello r;
+ uint32_t expected;
+ int retval;
+
+ memset(&p, 0, sizeof(p));
+ memset(&resp, 0, sizeof(resp));
+ memset(&r, 0, sizeof(r));
+
+ p.in_data = 0xa5a5a5a5;
+ expected = p.in_data + 0x01020304;
+
+ retval = send_cmd(EC_CMD_HELLO, 0,
+ &p, sizeof(p),
+ &resp,
+ &r, sizeof(r));
+
+ if (retval) {
+ printf("Transmission error\n");
+ return -1;
+ }
+
+ if (EC_RES_SUCCESS != resp.result) {
+ printf("EC result is %d: %s\n",
+ resp.result, ec_strerr(resp.result));
+ return -1;
+ }
+
+ printf("sent %08x, expected %08x, got %08x => %s\n",
+ p.in_data, expected, r.out_data,
+ expected == r.out_data ? "yay" : "boo");
+
+ return !(expected == r.out_data);
+}
+
+static void usage(char *progname)
+{
+ printf("\nUsage: %s [-v] [-c BYTES]\n\n", progname);
+ printf("This sends a EC_CMD_HELLO host command. The -c option can\n");
+ printf("be used to truncate the exchange early, to see how the EC\n");
+ printf("deals with the interruption.\n\n");
+}
+
+int main(int argc, char *argv[])
+{
+ int retval = 1;
+ int errorcnt = 0;
+ int i;
+
+ while ((i = getopt(argc, argv, ":vc:")) != -1) {
+ switch (i) {
+ case 'c':
+ stop_after = atoi(optarg);
+ printf("stopping after %zd bytes\n", stop_after);
+ break;
+ case 'v':
+ opt_verbose++;
+ break;
+ case '?':
+ printf("unrecognized option: -%c\n", optopt);
+ errorcnt++;
+ break;
+ }
+ }
+ if (errorcnt) {
+ usage(argv[0]);
+ return 1;
+ }
+
+ /* Find something to talk to */
+ mpsse = MPSSE(SPI0, 2000000, 0);
+ if (!mpsse) {
+ printf("Can't find a device to open\n");
+ return 1;
+ }
+
+ if (0 != hello())
+ goto out;
+
+ retval = 0;
+out:
+ Close(mpsse);
+ mpsse = 0;
+ return retval;
+}