[PATCH RTEMS v2] Add i2c command

2022-08-28 Thread chrisj
The patch adds an i2c command. It is a single command to test and 
explore I2C buses on hardware. The command lets you string together
reads and writes on a single command line to access a number of devices
so you can script basic functionality simply.

This command adds to the existing i2cdetect, i2cset and i2cget. I have
left those command as they are and we can decide on their future once
this patch is merged.

v2:
- Switch the detect to a zero length write. Add `-rw` option to detect
  as a fallback option to use reads and then writes.

Chris

___
devel mailing list
devel@rtems.org
http://lists.rtems.org/mailman/listinfo/devel


[PATCH v2] libmisc/shell: Add an i2c command

2022-08-28 Thread chrisj
From: Chris Johns 

Closes #4708
---
 cpukit/include/rtems/shellconfig.h |   7 +
 cpukit/libmisc/shell/main_i2c.c| 653 +
 spec/build/cpukit/objshell.yml |   1 +
 3 files changed, 661 insertions(+)
 create mode 100644 cpukit/libmisc/shell/main_i2c.c

diff --git a/cpukit/include/rtems/shellconfig.h 
b/cpukit/include/rtems/shellconfig.h
index a013840ee7..bd44d9d310 100644
--- a/cpukit/include/rtems/shellconfig.h
+++ b/cpukit/include/rtems/shellconfig.h
@@ -98,6 +98,7 @@ extern rtems_shell_cmd_t rtems_shell_MD5_Command;
 
 extern rtems_shell_cmd_t rtems_shell_RTC_Command;
 extern rtems_shell_cmd_t rtems_shell_SPI_Command;
+extern rtems_shell_cmd_t rtems_shell_I2C_Command;
 extern rtems_shell_cmd_t rtems_shell_I2CDETECT_Command;
 extern rtems_shell_cmd_t rtems_shell_I2CGET_Command;
 extern rtems_shell_cmd_t rtems_shell_I2CSET_Command;
@@ -556,6 +557,12 @@ extern rtems_shell_alias_t * const 
rtems_shell_Initial_aliases[];
   &rtems_shell_SPI_Command,
 #endif
 
+#if (defined(CONFIGURE_SHELL_COMMANDS_ALL) \
+  && !defined(CONFIGURE_SHELL_NO_COMMAND_I2C)) \
+|| defined(CONFIGURE_SHELL_COMMAND_I2C)
+  &rtems_shell_I2C_Command,
+#endif
+
 #if (defined(CONFIGURE_SHELL_COMMANDS_ALL) \
   && !defined(CONFIGURE_SHELL_NO_COMMAND_I2CDETECT)) \
 || defined(CONFIGURE_SHELL_COMMAND_I2CDETECT)
diff --git a/cpukit/libmisc/shell/main_i2c.c b/cpukit/libmisc/shell/main_i2c.c
new file mode 100644
index 00..bd43afbe38
--- /dev/null
+++ b/cpukit/libmisc/shell/main_i2c.c
@@ -0,0 +1,653 @@
+/* SPDX-License-Identifier: BSD-2-Clause */
+
+/**
+ * @file
+ *
+ * @ingroup
+ *
+ * @brief This source file contains the I2C command.
+ */
+
+/*
+ * Copyright (c) 2022 Chris Johns.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *notice, this list of conditions and the following disclaimer in the
+ *documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include 
+#include 
+
+#include 
+#include 
+
+#define BUF_SIZE  2048
+#define MAX_BUSES 8
+#define MIN_ADDR  1
+#define MAX_ADDR  127 /* needs updating for 10bit addresses */
+
+static char bus_template[128] = "/dev/i2c-%d";
+
+typedef struct {
+  int argc;
+  char** argv;
+  int arg;
+  int bus[MAX_BUSES];
+  uint8_t buffer[BUF_SIZE];
+} i2c_data;
+
+static void dump_memory(const uint8_t* mem, size_t len) {
+  size_t i;
+  for (i = 0; i < len; ++i) {
+if ((i % 16) == 0) {
+  if (i > 0) {
+printf("\n");
+  }
+  printf("%04zu", i);
+}
+if ((i % 8) == 0) {
+  printf(" ");
+}
+printf(" %02x", (unsigned int) mem[i]);
+  }
+  printf("\n");
+}
+
+static int hex_to_bin(const char hex) {
+  int bin = -1;
+  if (hex >= '0' && hex <= '9') {
+bin = hex - '0';
+  } else if (hex >= 'a' && hex <= 'z') {
+bin = hex - 'a' + 10;
+  } else if (hex >= 'A' && hex <= 'A') {
+bin = hex - 'A' + 10;
+  }
+  return bin;
+}
+
+static bool check_args(const char* cmd, int count, i2c_data* i2c) {
+  bool ok = count + i2c->arg <= i2c->argc;
+  if (!ok) {
+printf("error: %s: not enough arguments\n", cmd);
+  }
+  return ok;
+}
+
+static bool check_flag(i2c_data* i2c) {
+  if (i2c->arg >= i2c->argc) {
+return false;
+  }
+return i2c->argv[i2c->arg][0] == '-';
+}
+
+static const char* get_arg_inc(i2c_data* i2c) {
+  if (i2c->arg < i2c->argc) {
+return i2c->argv[i2c->arg++];
+  }
+  return "";
+}
+
+static int get_value(
+  const char* cmd, const char* type, int min, int max, int* val, i2c_data* 
i2c) {
+  const char* arg;
+  if (!check_args(cmd, 1, i2c)) {
+return -1;
+  }
+  arg = get_arg_inc(i2c);
+  *val = (int) strtol(arg, NULL, 0);
+  if (*val < min || *val > max) {
+printf("error: %s: invalid %s: %s\n", cmd, type, arg);