diff --git a/Documentation/README.html b/Documentation/README.html
index 8287cadb283..348a2278cb4 100644
--- a/Documentation/README.html
+++ b/Documentation/README.html
@@ -29,9 +29,13 @@ nuttx/
|- arch/
| |
| |- arm/
- | | |- src
- | | |- lpc214x/README.txt
- | | `- stm32l4/README.txt
+ | | `- src
+ | | |- common
+ | | | `- README_lwl_console.txt
+ | | |- lpc214x
+ | | | `- README.txt
+ | | `- stm32l4
+ | | `- stm32l4/README.txt
| |- renesas/
| | |- include/
| | | `-README.txt
diff --git a/README.txt b/README.txt
index b95e425525a..a5f6c41d98d 100644
--- a/README.txt
+++ b/README.txt
@@ -1707,8 +1707,12 @@ nuttx/
| |
| |- arm/
| | `- src
- | | |- lpc214x/README.txt
- | | `- stm32l4/README.txt
+ | | |- common
+ | | | `- README_lwl_console.txt
+ | | |- lpc214x
+ | | | `-README.txt
+ | | `- stm32l4
+ | | `- README.txt
| |- renesas/
| | |- include/
| | | `-README.txt
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 471315d6810..1a0e67c6881 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -813,6 +813,19 @@ config ARM_SEMIHOSTING_HOSTFS
---help---
Mount HostFS through semihosting.
+config ARM_LWL_CONSOLE
+ bool "Lightweight Link Console Support"
+ default n
+ depends on DEV_CONSOLE && ARCH_CHIP_STM32
+ ---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.
+
+ Currently only available for STM32 architectures, but easily
+ added to other ARM architectures be addd up_low_console.c to the
+ architecture Make.defs file.
+
if ARCH_CORTEXM0
source arch/arm/src/armv6-m/Kconfig
endif
diff --git a/arch/arm/src/common/README_lwl_console.txt b/arch/arm/src/common/README_lwl_console.txt
new file mode 100644
index 00000000000..3e2cd3dfa43
--- /dev/null
+++ b/arch/arm/src/common/README_lwl_console.txt
@@ -0,0 +1,59 @@
+The file up_lwl_console.c implements a 'Lightweight Link' protocol between
+a target and debugger for use when you need a console but the target doesn't
+have a spare serial port or other available resource. This implements a
+new console type which uses two words of memory for data exchange.
+
+It is not particularly efficient because of the various compromises that are
+made (polling in busy loops, mostly) but it works well enough to give you
+something where you previously had nothing...typically the case when you're
+bring up a new CPU, or when the hardware designer thought the softies could
+cope without a logging port. It has an advantage over semi-hosting in that
+it doesn't put the target into debug mode while it's running, so you've got
+some hope of maintaining real time semantics. To be clear, for output only
+use you'd be better off with SWO if you've got it available!
+
+There is a terminal program in python(*) for the host side in
+tools/ocdconsole.py for use with openocd...the NuttX side functionality is
+not dependent on a specific debugger, the only requirement on it being that
+the debugger can watch and modify a memory location on the target while it is executing.
+
+Typical use is;
+
+$ tools/ocdconsole.py
+==Link Activated
+
+NuttShell (NSH)
+nsh> help
+help usage: help [-v] []
+
+ ? echo exit hexdump ls mh sleep xd
+ cat exec help kill mb mw usleep
+nsh>
+
+On the target side it's transparent, and is just a console;
+
+nsh> ls /dev
+/dev:
+ console
+ null
+ ttyS0
+nsh> echo "Hello World" > /dev/console
+Hello World
+nsh>
+
+CPU load on the host is surprisingly low given that the polling loop is
+continuous (probably due to the fact that openocd is spending most of it's
+time waiting for messages to/from the debug port on the target). When not
+actively doing anything there's no load on the target, but waiting for input
+is done in a busy polled loop (so the thread is effectively busy-locked)
+and output busy-waits for the previous message to be collected before it
+sends the next one.
+
+For now I've only made it available on stm32, but it should only be a case
+of changing the Kconfig and Make.defs for other arm CPUs to make it
+available for them too. Moving beyond arm needs knowledge of the targets
+that I don't have.
+
+If anyone fancies extending this proof-of-concept to full Segger-RTT-style
+functionality then drop me a note, there are plenty of ways to improve
+performance.
diff --git a/arch/arm/src/common/up_initialize.c b/arch/arm/src/common/up_initialize.c
index b951a7dca52..7c0d1dcc0ea 100644
--- a/arch/arm/src/common/up_initialize.c
+++ b/arch/arm/src/common/up_initialize.c
@@ -204,7 +204,9 @@ void up_initialize(void)
* serial driver).
*/
-#if defined(CONFIG_DEV_LOWCONSOLE)
+#if defined (CONFIG_ARM_LWL_CONSOLE)
+ lwlconsole_init();
+#elif defined(CONFIG_DEV_LOWCONSOLE)
lowconsole_init();
#elif defined(CONFIG_CONSOLE_SYSLOG)
syslog_console_init();
diff --git a/arch/arm/src/common/up_internal.h b/arch/arm/src/common/up_internal.h
index 51ea73f4a4e..64290551729 100644
--- a/arch/arm/src/common/up_internal.h
+++ b/arch/arm/src/common/up_internal.h
@@ -63,7 +63,11 @@
# undef CONFIG_DEV_LOWCONSOLE
# undef CONFIG_RAMLOG_CONSOLE
#else
-# if defined(CONFIG_RAMLOG_CONSOLE)
+# if defined(CONFIG_ARM_LWL_CONSOLE)
+# undef USE_SERIALDRIVER
+# undef USE_EARLYSERIALINIT
+# undef CONFIG_DEV_LOWCONSOLE
+# elif defined(CONFIG_RAMLOG_CONSOLE)
# undef USE_SERIALDRIVER
# undef USE_EARLYSERIALINIT
# undef CONFIG_DEV_LOWCONSOLE
@@ -299,7 +303,7 @@ EXTERN uint32_t _eramfuncs; /* Copy destination end address in RAM */
****************************************************************************/
/****************************************************************************
- * Public Functions
+ * Public Function Prototypes
****************************************************************************/
#ifndef __ASSEMBLY__
@@ -449,10 +453,18 @@ void up_earlyserialinit(void);
# define up_earlyserialinit()
#endif
+#ifdef CONFIG_ARM_LWL_CONSOLE
+
+/* Defined in src/common/up_lwl_console.c */
+
+void lwlconsole_init(void);
+
+#elif defined(CONFIG_DEV_LOWCONSOLE)
+
/* Defined in drivers/lowconsole.c */
-#ifdef CONFIG_DEV_LOWCONSOLE
void lowconsole_init(void);
+
#else
# define lowconsole_init()
#endif
diff --git a/arch/arm/src/common/up_lwl_console.c b/arch/arm/src/common/up_lwl_console.c
new file mode 100644
index 00000000000..a915a3879f5
--- /dev/null
+++ b/arch/arm/src/common/up_lwl_console.c
@@ -0,0 +1,327 @@
+/****************************************************************************
+ * drivers/serial/lwlconsole.c
+ *
+ * Copyright (C) 2019 Gregory Nutt. All rights reserved.
+ * Author: Dave Marples
+ *
+ * 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.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+/****************************************************************************
+ * 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 ID_SIG 0x7216A318
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static ssize_t lwlconsole_read(struct file *filep, char *buffer,
+ size_t buflen);
+static ssize_t lwlconsole_write(struct file *filep, const char *buffer,
+ size_t buflen);
+static int lwlconsole_ioctl(struct file *filep, int cmd, unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static struct
+{
+ uint32_t sig; /* Location signature */
+ volatile uint32_t downword; /* Host to Target word */
+ uint32_t upword; /* Target to Host word */
+} g_d =
+{
+ .sig = 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, uint8_t * store)
+{
+ if (LWL_DNSENSE(g_d.downword) == LWL_DNSENSE(g_d.upword))
+ {
+ return false;
+ }
+
+ *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(struct file *filep, int cmd, unsigned long arg)
+{
+ return -ENOTTY;
+}
+
+/****************************************************************************
+ * Name: lwlconsole_read
+ ****************************************************************************/
+
+static ssize_t lwlconsole_read(struct file *filep, char *buffer,
+ size_t buflen)
+{
+ if (buflen == 0 || !linkactive())
+ {
+ return 0;
+ }
+
+ while (!read8bits(LWL_PORT_CONSOLE, (uint8_t *) buffer))
+ {
+ }
+
+ return 1;
+}
+
+/****************************************************************************
+ * Name: lwlconsole_write
+ ****************************************************************************/
+
+static ssize_t lwlconsole_write(struct file *filep, 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)
+{
+ g_d.upword = 0;
+ (void)register_driver("/dev/console", &g_consoleops, 0666, NULL);
+}
diff --git a/arch/arm/src/stm32/Make.defs b/arch/arm/src/stm32/Make.defs
index 7cddffac7b6..45a182cb7a1 100644
--- a/arch/arm/src/stm32/Make.defs
+++ b/arch/arm/src/stm32/Make.defs
@@ -54,6 +54,10 @@ ifeq ($(CONFIG_ARMV7M_STACKCHECK),y)
CMN_CSRCS += up_stackcheck.c
endif
+ifeq ($(CONFIG_ARM_LWL_CONSOLE),y)
+CMN_CSRCS += up_lwl_console.c
+endif
+
ifeq ($(CONFIG_ARMV7M_LAZYFPU),y)
CMN_ASRCS += up_lazyexception.S
else
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 39b1d457e6a..2aa8311d97c 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -6,8 +6,7 @@
config DEV_LOWCONSOLE
bool "Low-level console support"
default n
- depends on ARCH_LOWPUTC
- depends on DEV_CONSOLE
+ depends on ARCH_LOWPUTC && DEV_CONSOLE
---help---
Use the simple, low-level, write-only serial console driver (minimal support)
diff --git a/tools/ocdconsole.py b/tools/ocdconsole.py
new file mode 100755
index 00000000000..ae6badf7bbd
--- /dev/null
+++ b/tools/ocdconsole.py
@@ -0,0 +1,308 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2019 Dave Marples. All rights reserved.
+# Author: Dave Marples
+#
+# 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.
+# 3. Neither the name NuttX nor the names of its contributors may be
+# used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# 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.
+#
+#
+# Console over Lightweight Link
+# =============================
+#
+# LWL is a Lightweight bidirectional communication between target and debug host
+# without any need for additional hardware.
+#
+# It works with openOCD and other debuggers that are capable of reading and
+# writing memory while the target is running...it should run with JLink
+# for example, if you've got the SDK and modify this file accordingly.
+#
+# 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
+# nessessary to feed lwl with cycles to poll for changes in the downword,
+# depending on the use case. For the case of a simple console, that's not
+# needed.
+#
+# For convinence these communication locations are automatically discovered
+# from the RAM by searching through it. Just define downwordaddr and
+# upwordaddr if you want to work with fixed locations.
+#
+#
+# Bit configuration
+# -----------------
+#
+# Downword (Host to target);
+#
+# A D U VV XXX O2 O1 O0
+#
+# 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
+#
+# Port 1 is used for Console. No other ports are currently defined.
+#
+# Use
+# ===
+#
+# No special python modules are needed, it should be possible to run the
+# application simply as shown below;
+#
+# ------------------------------------------
+# $ ./ocdconsole.py
+# ==Link Activated
+#
+# nsh>
+# nsh> help
+# help usage: help [-v] []
+#
+# ? echo exit hexdump ls mh sleep xd
+# cat exec help kill mb mw usleep
+# nsh>
+# ------------------------------------------
+#
+# This code is designed to be 'hardy' and will survive a shutdown and
+# restart of the openocd process. When your target application
+# changes then the location of the upword and downword may change,
+# so they are re-searched for again. To speed up the start process
+# consider putting those words at fixed locations (e.g. via the
+# linker file) and referencing them directly.
+#
+
+LWL_ACTIVESHIFT = 31
+LWL_DNSENSESHIFT = 30
+LWL_UPSENSESHIFT = 29
+LWL_OCTVALSHIFT = 27
+LWL_PORTSHIFT = 24
+
+LWL_PORTMASK = (7<=length):
+ print("ERROR: Cannot find signature\r")
+ exit(1)
+
+ # We have the base address, so get the variables themselves
+ # =========================================================
+ downwordaddr=baseaddr+downwordaddr+4
+ upwordaddr=downwordaddr+4
+ downword=LWL_ACTIVE
+
+ # Now wake up the link...keep on trying if it goes down
+ # =====================================================
+ while True:
+ ocd.writeVariable(downwordaddr, downword)
+ upword = ocd.readVariable(upwordaddr)
+ if (upword&LWL_ACTIVE!=0):
+ print("==Link Activated\r")
+ break
+ except (BrokenPipeError, ConnectionRefusedError, ConnectionResetError) as e:
+ raise e
+
+ # Now run the comms loop until something fails
+ # ============================================
+ try:
+ while True:
+ ocd.writeVariable(downwordaddr, downword)
+ upword = ocd.readVariable(upwordaddr)
+ if (upword&LWL_ACTIVE==0):
+ print("\r==Link Deactivated\r")
+ break
+ if kbhit():
+ charin = sys.stdin.read(1)
+ if (ord(charin)==3):
+ sys.exit(0)
+ if (downword&LWL_DNSENSEBIT):
+ downword=(downword&LWL_UPSENSEBIT)
+ else:
+ downword=(downword&LWL_UPSENSEBIT)|LWL_DNSENSEBIT
+ downword|=(LWL_PORT_CONSOLE<>LWL_PORTSHIFT
+ if (incomingPort==LWL_PORT_CONSOLE):
+ incomingBytes=(upword&LWL_OCTVALMASK)>>LWL_OCTVALSHIFT
+ if (incomingBytes>=1): dooutput(upword&255);
+ if (incomingBytes>=2): dooutput((upword>>8)&255);
+ if (incomingBytes==3): dooutput((upword>>16)&255);
+
+ if (downword&LWL_UPSENSEBIT):
+ downword = downword&~LWL_UPSENSEBIT
+ else:
+ downword = downword|LWL_UPSENSEBIT
+ except (ConnectionResetError, ConnectionResetError, BrokenPipeError) as e:
+ print("\r==Link Lost\r")
+ raise e
+
+ except (BrokenPipeError, ConnectionRefusedError, ConnectionResetError) as e:
+ time.sleep(1)
+ continue
+ finally:
+ termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
+