This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new f63e1e2  Add generic support to LWL Console
f63e1e2 is described below

commit f63e1e277febef868848b2471be283ac144c2877
Author: Alan C. Assis <acas...@gmail.com>
AuthorDate: Sun Jan 24 17:15:49 2021 -0300

    Add generic support to LWL Console
---
 drivers/Kconfig                 |  16 ++
 drivers/Makefile                |   4 +
 drivers/lwl_console.c           | 321 ++++++++++++++++++++++++++++++++++++++++
 include/nuttx/drivers/drivers.h |  16 ++
 4 files changed, 357 insertions(+)

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 3e2ad26..5a69503 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -24,6 +24,22 @@ config DRVR_MKRD
                the selecting this option will also enable the BOARDIOC_MKRD
                command that will support creation of RAM disks from 
applications.
 
+# ARCH needs to support memory access while CPU is running to be able to use
+# the LWL CONSOLE
+
+config ARCH_HAVE_RDWR_MEM_CPU_RUN
+       bool
+       default n
+
+config LWL_CONSOLE
+bool "Lightweight Link Console Support"
+       default n
+       depends on DEV_CONSOLE && ARCH_HAVE_RDWR_MEM_CPU_RUN
+       ---help---
+               Use the lightweight link console which provides console over a
+               debug channel by means of shared memory.  A terminal application
+               for openocd as the debugger is available in tools/ocdconsole.py.
+
 menu "Buffering"
 
 config DRVR_WRITEBUFFER
diff --git a/drivers/Makefile b/drivers/Makefile
index ad8ea5e..17526c2 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -87,6 +87,10 @@ endif
 
 CSRCS += dev_null.c dev_zero.c
 
+ifeq ($(CONFIG_LWL_CONSOLE),y)
+  CSRCS += lwl_console.c
+endif
+
 ifneq ($(CONFIG_DISABLE_MOUNTPOINT),y)
   CSRCS += ramdisk.c
 ifeq ($(CONFIG_DRVR_MKRD),y)
diff --git a/drivers/lwl_console.c b/drivers/lwl_console.c
new file mode 100644
index 0000000..ba545d2
--- /dev/null
+++ b/drivers/lwl_console.c
@@ -0,0 +1,321 @@
+/****************************************************************************
+ * drivers/lwlconsole.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/fs/fs.h>
+#include <nuttx/drivers/drivers.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Lightweight Link (lwl)
+ * ======================
+ *
+ * Lightweight bidirectional communication between target and debug host
+ * without any need for additional hardware.
+ *
+ * Works with openOCD and other debuggers that are capable of reading and
+ * writing memory while the target is running.
+ *
+ * Principle of operation is simple; An 'upword' of 32 bits communicates
+ * from the target to the host, a 'downword' of the same size runs in the
+ * opposite direction. These two words can be in any memory that is
+ * read/write access for both the target and the debug host. A simple ping
+ * pong handshake protocol over these words allows up/down link
+ * communication.  On the upside no additional integration is needed. On
+ * the downside it may be necessary to feed lwl with cycles to poll for
+ * changes in the downword, depending on the use case.
+ *
+ * Bit configuration
+ * -----------------
+ *
+ * Downword (Host to target);
+ *
+ * A D U VV XXX
+ *
+ * A   31    1 - Service Active (Set by host)
+ * D   30    1 - Downsense (Toggled when there is data)
+ * U   29    1 - Upsense ack (Toggled to acknowledge receipt of uplink data)
+ * VV  28-27 2 - Valid Octets (Number of octets valid in the message)
+ * XXX 26-24 3 - Port in use (Type of the message)
+ * O2  23-16 8 - Octet 2
+ * O1  15-08 8 - Octet 1
+ * O0  07-00 8 - Octet 0
+ *
+ * Upword (Target to Host);
+ *
+ * A   31    1 - Service Active (Set by device)
+ * D   30    1 - Downsense ack (Toggled to acknowledge receipt of downlink
+ *               data)
+ * U   29    1 - Upsense (Toggled when there is data)
+ * VV  28-27 2 - Valid upword octets
+ * XXX 26-24 3 - Port in use (Type of the message)
+ * O2  23-16 8 - Octet 2
+ * O1  15-08 8 - Octet 1
+ * O0  07-00 8 - Octet 0
+ *
+ */
+
+/* Protocol bits */
+
+#define LWL_GETACTIVE(x) (((x) & (1 << 31)) != 0)
+#define LWL_ACTIVE(x) (((x)&1) << 31)
+
+#define LWL_DNSENSEBIT (1 << 30)
+#define LWL_DNSENSE(x) ((x)&LWL_DNSENSEBIT)
+#define LWL_UPSENSEBIT (1 << 29)
+#define LWL_UPSENSE(x) ((x)&LWL_UPSENSEBIT)
+#define LWL_SENSEMASK (3 << 29)
+
+#define LWL_GETOCTVAL(x) (((x) >> 27) & 3)
+#define LWL_OCTVAL(x) (((x)&3) << 27)
+#define LWL_GETPORT(x) (((x) >> 24) & 7)
+#define LWL_PORT(x) (((x)&7) << 24)
+
+#define LWL_PORT_CONSOLE 1
+#define LWL_ID_SIG 0x7216A318
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static ssize_t lwlconsole_read(FAR struct file *filep, FAR char *buffer,
+                               size_t buflen);
+static ssize_t lwlconsole_write(FAR struct file *filep,
+                                FAR const char *buffer, size_t buflen);
+static int lwlconsole_ioctl(FAR struct file *filep, int cmd,
+                            unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+struct lwl_entry_s
+{
+  uint32_t sig;               /* Location signature */
+  volatile uint32_t downword; /* Host to Target word */
+  uint32_t upword;            /* Target to Host word */
+};
+
+static struct lwl_entry_s g_d =
+{
+  .sig = LWL_ID_SIG
+};
+
+static const struct file_operations g_consoleops =
+{
+  NULL,                       /* open */
+  NULL,                       /* close */
+  lwlconsole_read,            /* read */
+  lwlconsole_write,           /* write */
+  NULL,                       /* seek */
+  lwlconsole_ioctl,           /* ioctl */
+  NULL                        /* poll */
+#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+    ,
+  NULL                        /* unlink */
+#endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static bool linkactive(void)
+{
+  return (LWL_GETACTIVE(g_d.downword) != 0);
+}
+
+static bool writeword(uint32_t newupword)
+{
+  /* Check link is active */
+
+  if (!linkactive())
+    {
+      return false;
+    }
+
+  /* Spin waiting for previous data to be collected */
+
+  while (LWL_UPSENSE(g_d.downword) != LWL_UPSENSE(g_d.upword))
+    {
+    }
+
+  /* Load new data, toggling UPSENSE bit to show it is new */
+
+  g_d.upword = LWL_DNSENSE(g_d.upword) | newupword |
+               (LWL_UPSENSE(g_d.upword) ? 0 : LWL_UPSENSEBIT);
+
+  return true;
+}
+
+static bool write8bits(uint8_t port, uint8_t val)
+{
+  /* Prepare new word */
+
+  uint32_t newupword = LWL_ACTIVE(true) | LWL_OCTVAL(1) |
+                       LWL_PORT(port) | (val & 0xff);
+
+  return writeword(newupword);
+}
+
+static bool write16bits(uint8_t port, uint32_t val)
+{
+  /* Prepare new word */
+
+  uint32_t newupword = LWL_ACTIVE(true) | LWL_OCTVAL(2) |
+                       LWL_PORT(port) | (val & 0xffff);
+
+  return writeword(newupword);
+}
+
+static bool write24bits(uint8_t port, uint32_t val)
+{
+  /* Prepare new word */
+
+  uint32_t newupword = LWL_ACTIVE(true) | LWL_OCTVAL(3) |
+                       LWL_PORT(port) | (val & 0xffffff);
+
+  return writeword(newupword);
+}
+
+static bool read8bits(uint8_t port, FAR uint8_t *store)
+{
+  if (!linkactive())
+    {
+      return false;
+    }
+
+  /* Spin waiting for a byte to be received */
+
+  while (LWL_DNSENSE(g_d.downword) == LWL_DNSENSE(g_d.upword))
+    {
+    }
+
+  *store = g_d.downword & 255;
+
+  /* Flip the bit to indicate the datum is read */
+
+  g_d.upword = (g_d.upword & ~LWL_DNSENSEBIT) | LWL_DNSENSE(g_d.downword);
+
+  return true;
+}
+
+/****************************************************************************
+ * Name: lwlconsole_ioctl
+ ****************************************************************************/
+
+static int lwlconsole_ioctl(FAR struct file *filep, int cmd,
+                            unsigned long arg)
+{
+  return -ENOTTY;
+}
+
+/****************************************************************************
+ * Name: lwlconsole_read
+ ****************************************************************************/
+
+static ssize_t lwlconsole_read(FAR struct file *filep, FAR char *buffer,
+                               size_t buflen)
+{
+  if (buflen == 0)
+    {
+      return 0;
+    }
+
+  if (!read8bits(LWL_PORT_CONSOLE, (FAR uint8_t *) buffer))
+    {
+      return 0;
+    }
+
+  return 1;
+}
+
+/****************************************************************************
+ * Name: lwlconsole_write
+ ****************************************************************************/
+
+static ssize_t lwlconsole_write(FAR struct file *filep,
+                                FAR const char *buffer, size_t buflen)
+{
+  uint32_t oc = 0;
+
+  while (buflen)
+    {
+      switch (buflen)
+        {
+          case 0:
+            return oc;
+
+          case 1:
+            if (write8bits(LWL_PORT_CONSOLE, buffer[0]))
+              {
+                oc++;
+                buffer++;
+                buflen--;
+              }
+            break;
+
+          case 2:
+            if (write16bits(LWL_PORT_CONSOLE, buffer[0] | (buffer[1] << 8)))
+              {
+                oc += 2;
+                buffer += 2;
+                buflen -= 2;
+              }
+            break;
+
+          default:
+            if (write24bits(LWL_PORT_CONSOLE, buffer[0] |
+                            (buffer[1] << 8) | (buffer[2] << 16)))
+              {
+                oc += 3;
+                buffer += 3;
+                buflen -= 3;
+              }
+            break;
+        }
+    }
+
+  return oc;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lwlconsole_init
+ ****************************************************************************/
+
+void lwlconsole_init(void)
+{
+  register_driver("/dev/console", &g_consoleops, 0666, NULL);
+}
diff --git a/include/nuttx/drivers/drivers.h b/include/nuttx/drivers/drivers.h
index a0d08ad..c507b23 100644
--- a/include/nuttx/drivers/drivers.h
+++ b/include/nuttx/drivers/drivers.h
@@ -217,6 +217,22 @@ ssize_t bchlib_read(FAR void *handle, FAR char *buffer, 
size_t offset,
 ssize_t bchlib_write(FAR void *handle, FAR const char *buffer, size_t offset,
                      size_t len);
 
+/****************************************************************************
+ * Name: lwlconsole_init
+ *
+ * Description:
+ *   Register /dev/console
+ *
+ * Input Parameters:
+ *   None
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+void lwlconsole_init(void);
+
 #undef EXTERN
 #if defined(__cplusplus)
 }

Reply via email to