From e3dd0ae77ade79a76fa983d5ff65175b3dac4213 Mon Sep 17 00:00:00 2001 From: Gerard Swiderski Date: Wed, 7 Feb 2024 11:40:49 +0100 Subject: [PATCH 1/7] librtt: implement RTT-PIPE library CHange implements library for RTT (multichannel, bidirectional) communicaton over debug probe JTAG/SWD. JIRA: RTOS-754 --- librtt/Makefile | 11 ++ librtt/rtt.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++++ librtt/rtt.h | 50 +++++++++ 3 files changed, 333 insertions(+) create mode 100644 librtt/Makefile create mode 100644 librtt/rtt.c create mode 100644 librtt/rtt.h diff --git a/librtt/Makefile b/librtt/Makefile new file mode 100644 index 000000000..76fd16e3c --- /dev/null +++ b/librtt/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for Phoenix-RTOS rtt pipes library +# +# Copyright 2023-2024 Phoenix Systems +# + +NAME := librtt +LOCAL_SRCS := rtt.c +LOCAL_HEADERS := rtt.h + +include $(static-lib.mk) diff --git a/librtt/rtt.c b/librtt/rtt.c new file mode 100644 index 000000000..cc28024bd --- /dev/null +++ b/librtt/rtt.c @@ -0,0 +1,272 @@ +/* + * Phoenix-RTOS + * + * RTT pipes: communication through debug probe + * + * Copyright 2023-2024 Phoenix Systems + * Author: Gerard Swiderski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include +#include +#include +#include +#include + + +static inline void dataMemoryBarrier(void) +{ +#if (defined __ARM_ARCH_7EM__) /* Cortex-M4/M7 */ \ + || (defined __ARM_ARCH_8M_BASE__) /* Cortex-M23 */ \ + || (defined __ARM_ARCH_8M_MAIN__) /* Cortex-M33 */ \ + || ((defined __ARM_ARCH_7A__) || (defined __ARM_ARCH_7R__)) /* Cortex-A/R 32-bit ARMv7-A/R */ + + /* clang-format off */ + __asm__ volatile("dmb\n":::); + /* clang-format on */ +#endif +} + + +/* + * Note: LIBRTT_TAG needs to be backward written string. This tag is used by + * the RTT remote side e.g. openocd to find descriptor location during memory + * scan, so as not to mislead the descriptor scan procedure, this tag needs + * to be simply hidden before it is copied into RAM together with initialized + * descriptors, that's why it is written backwards. + * - Default LIBRTT_TAG_REVERSED="EPIP TTR", which corresponds to "RTT PIPE" + */ + +/* clang-format off */ + +#ifndef LIBRTT_TAG_BACKWARD +#define LIBRTT_TAG_BACKWARD "EPIP TTR" +#endif + + +#ifndef LIBRTT_TXCHANNELS +#define LIBRTT_TXCHANNELS 2 +#define LIBRTT_TXCHANNELS_NAMES { "rtt1_tx", "rtt2_tx" } +#endif + +#ifndef LIBRTT_RXCHANNELS +#define LIBRTT_RXCHANNELS 2 +#define LIBRTT_RXCHANNELS_NAMES { "rtt1_rx", "rtt2_rx" } +#endif + +/* clang-format on */ + + +struct rtt_pipe { + const char *name; + unsigned char *ptr; + unsigned int sz; + volatile unsigned int wr; + volatile unsigned int rd; + unsigned int flags; +}; + + +struct rtt_desc { + char tag[16]; + unsigned int txChannels; + unsigned int rxChannels; + struct rtt_pipe txChannel[LIBRTT_TXCHANNELS]; + struct rtt_pipe rxChannel[LIBRTT_RXCHANNELS]; +}; + + +static const char rtt_tagReversed[] = LIBRTT_TAG_BACKWARD; +static const char *const rtt_txName[LIBRTT_TXCHANNELS] = LIBRTT_TXCHANNELS_NAMES; +static const char *const rtt_rxName[LIBRTT_RXCHANNELS] = LIBRTT_RXCHANNELS_NAMES; + + +static struct { + volatile struct rtt_desc *rtt; + void *memptr; +} librtt_common = { 0 }; + + +int rtt_check(int chan) +{ + if (librtt_common.rtt == NULL || chan < 0 || chan >= LIBRTT_TXCHANNELS) { + return -ENODEV; + } + + return 0; +} + + +ssize_t rtt_read(int chan, void *buf, size_t count) +{ + volatile struct rtt_desc *rtt = librtt_common.rtt; + + if (rtt_check(chan) < 0) { + return -ENODEV; + } + + dataMemoryBarrier(); + + unsigned char *srcBuf = (unsigned char *)rtt->rxChannel[chan].ptr; + unsigned char *dstBuf = (unsigned char *)buf; + unsigned int sz = rtt->rxChannel[chan].sz - 1; + unsigned int rd = rtt->rxChannel[chan].rd & sz; + unsigned int wr = rtt->rxChannel[chan].wr & sz; + size_t todo = count; + + while ((todo != 0) && (rd != wr)) { + *dstBuf++ = srcBuf[rd]; + rd = (rd + 1) & sz; + todo--; + } + + rtt->rxChannel[chan].rd = rd; + + dataMemoryBarrier(); + + return count - todo; +} + + +ssize_t rtt_write(int chan, const void *buf, size_t count) +{ + volatile struct rtt_desc *rtt = librtt_common.rtt; + + if (rtt_check(chan) < 0) { + return -ENODEV; + } + + dataMemoryBarrier(); + + const unsigned char *srcBuf = (const unsigned char *)buf; + unsigned char *dstBuf = (unsigned char *)rtt->txChannel[chan].ptr; + unsigned int sz = rtt->txChannel[chan].sz - 1; + unsigned int rd = (rtt->txChannel[chan].rd + sz) & sz; + unsigned int wr = rtt->txChannel[chan].wr & sz; + size_t todo = count; + + while ((todo != 0) && (rd != wr)) { + dstBuf[wr] = *srcBuf++; + wr = (wr + 1) & sz; + todo--; + } + + rtt->txChannel[chan].wr = wr; + + dataMemoryBarrier(); + + return count - todo; +} + + +ssize_t rtt_txAvail(int chan) +{ + volatile struct rtt_desc *rtt = librtt_common.rtt; + + dataMemoryBarrier(); + unsigned int sz = rtt->txChannel[chan].sz - 1; + unsigned int rd = (rtt->txChannel[chan].rd + sz) & sz; + unsigned int wr = rtt->txChannel[chan].wr & sz; + + if (wr > rd) { + return sz + 1 - (wr - rd); + } + else { + return rd - wr; + } +} + + +void rtt_rxReset(int chan) +{ + dataMemoryBarrier(); + librtt_common.rtt->rxChannel[chan].rd = librtt_common.rtt->rxChannel[chan].wr; + dataMemoryBarrier(); +} + + +void rtt_txReset(int chan) +{ + dataMemoryBarrier(); + librtt_common.rtt->txChannel[chan].wr = librtt_common.rtt->txChannel[chan].rd; + dataMemoryBarrier(); +} + + +int rtt_init(void *addr, void *bufptr, size_t bufsz) +{ + unsigned int n, m; + volatile struct rtt_desc *rtt = librtt_common.rtt; + + if ((rtt != NULL) && (bufsz != 0) && ((bufsz & (bufsz - 1)) != 0)) { + return -EINVAL; + } + + if (bufptr == NULL) { + bufptr = mmap(NULL, + bufsz * rtt->txChannels * rtt->rxChannels, + PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_UNCACHED, + -1, + 0); + if (bufptr == MAP_FAILED) { + return -ENOMEM; + } + librtt_common.memptr = bufptr; + } + + rtt = (volatile struct rtt_desc *)addr; + memset((void *)rtt, 0, sizeof(*rtt)); + + rtt->txChannels = LIBRTT_TXCHANNELS; + rtt->rxChannels = LIBRTT_RXCHANNELS; + + bufsz /= (rtt->txChannels + rtt->rxChannels); + + m = 0; + for (n = 0; n < rtt->txChannels; n++) { + rtt->txChannel[n].name = rtt_txName[n]; + rtt->txChannel[n].ptr = (unsigned char *)bufptr + m * bufsz; + rtt->txChannel[n].sz = bufsz; + m++; + } + + for (n = 0; n < rtt->rxChannels; n++) { + rtt->rxChannel[n].name = rtt_rxName[n]; + rtt->rxChannel[n].ptr = (unsigned char *)bufptr + m * bufsz; + rtt->rxChannel[n].sz = bufsz; + m++; + } + + n = 0; + m = sizeof(rtt_tagReversed) - 1; + while (n < sizeof(rtt->tag) && m > 0) { + rtt->tag[n++] = rtt_tagReversed[--m]; + } + + return 0; +} + + +void rtt_done(void) +{ + volatile struct rtt_desc *rtt = librtt_common.rtt; + + if (rtt != NULL) { + if (librtt_common.memptr != NULL) { + size_t n, sz = 0; + for (n = 0; rtt->txChannels; n++) { + sz += rtt->txChannel[n].sz; + } + for (n = 0; rtt->rxChannels; n++) { + sz += rtt->rxChannel[n].sz; + } + munmap(librtt_common.memptr, sz); + } + memset((void *)rtt, 0, sizeof(*rtt)); + librtt_common.rtt = NULL; + } +} diff --git a/librtt/rtt.h b/librtt/rtt.h new file mode 100644 index 000000000..35303bc57 --- /dev/null +++ b/librtt/rtt.h @@ -0,0 +1,50 @@ +/* + * Phoenix-RTOS + * + * RTT pipes: communication through debug probe + * + * Copyright 2023-2024 Phoenix Systems + * Author: Gerard Swiderski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef LIBRTT_H +#define LIBRTT_H + + +/* Initialize rtt descriptor and rtt internal structures */ +int rtt_init(void *addr, void *bufptr, size_t bufsz); + + +/* Release resources, cleanup */ +void rtt_done(void); + + +/* Check if channel is present */ +int rtt_check(int chan); + + +/* Non-blocking read from channel */ +ssize_t rtt_read(int chan, void *buf, size_t count); + + +/* Non-blocking write to channel */ +ssize_t rtt_write(int chan, const void *buf, size_t count); + + +/* Check for available space in tx */ +ssize_t rtt_txAvail(int chan); + + +/* Reset rx fifo pointers */ +void rtt_rxReset(int chan); + + +/* Reset tx fifo pointers */ +void rtt_txReset(int chan); + + +#endif /* end of LIBRTT_H */ From e172347f896708e104af2a82b4e7b5a26a34d3dc Mon Sep 17 00:00:00 2001 From: Jacek Maksymowicz Date: Tue, 13 Aug 2024 11:02:29 +0200 Subject: [PATCH 2/7] librtt: fix bugs in initialization Fix rtt structure read before initialization Add better argument validation Add volatile modifier where necessary Add option to use cached memory for buffers Renamed files and functions from "rtt" to "librtt" JIRA: RTOS-754 --- librtt/Makefile | 4 +- librtt/{rtt.c => librtt.c} | 110 +++++++++++++++++++++++-------------- librtt/librtt.h | 59 ++++++++++++++++++++ librtt/rtt.h | 50 ----------------- 4 files changed, 130 insertions(+), 93 deletions(-) rename librtt/{rtt.c => librtt.c} (61%) create mode 100644 librtt/librtt.h delete mode 100644 librtt/rtt.h diff --git a/librtt/Makefile b/librtt/Makefile index 76fd16e3c..86859e643 100644 --- a/librtt/Makefile +++ b/librtt/Makefile @@ -5,7 +5,7 @@ # NAME := librtt -LOCAL_SRCS := rtt.c -LOCAL_HEADERS := rtt.h +LOCAL_SRCS := librtt.c +LOCAL_HEADERS := librtt.h include $(static-lib.mk) diff --git a/librtt/rtt.c b/librtt/librtt.c similarity index 61% rename from librtt/rtt.c rename to librtt/librtt.c index cc28024bd..192fa1d7c 100644 --- a/librtt/rtt.c +++ b/librtt/librtt.c @@ -11,6 +11,8 @@ * %LICENSE% */ +#include "librtt.h" + #include #include #include @@ -20,10 +22,10 @@ static inline void dataMemoryBarrier(void) { -#if (defined __ARM_ARCH_7EM__) /* Cortex-M4/M7 */ \ - || (defined __ARM_ARCH_8M_BASE__) /* Cortex-M23 */ \ - || (defined __ARM_ARCH_8M_MAIN__) /* Cortex-M33 */ \ - || ((defined __ARM_ARCH_7A__) || (defined __ARM_ARCH_7R__)) /* Cortex-A/R 32-bit ARMv7-A/R */ +#if (defined __ARM_ARCH_7EM__) /* Cortex-M4/M7 */ \ + || (defined __ARM_ARCH_8M_BASE__) /* Cortex-M23 */ \ + || (defined __ARM_ARCH_8M_MAIN__) /* Cortex-M33 */ \ + || ((defined __ARM_ARCH_7A__) || (defined __ARM_ARCH_7R__)) /* Cortex-A/R 32-bit ARMv7-A/R */ /* clang-format off */ __asm__ volatile("dmb\n":::); @@ -63,7 +65,7 @@ static inline void dataMemoryBarrier(void) struct rtt_pipe { const char *name; - unsigned char *ptr; + volatile unsigned char *ptr; unsigned int sz; volatile unsigned int wr; volatile unsigned int rd; @@ -80,20 +82,22 @@ struct rtt_desc { }; -static const char rtt_tagReversed[] = LIBRTT_TAG_BACKWARD; -static const char *const rtt_txName[LIBRTT_TXCHANNELS] = LIBRTT_TXCHANNELS_NAMES; -static const char *const rtt_rxName[LIBRTT_RXCHANNELS] = LIBRTT_RXCHANNELS_NAMES; +static const char librtt_tagReversed[] = LIBRTT_TAG_BACKWARD; +static const char *const librtt_txName[LIBRTT_TXCHANNELS] = LIBRTT_TXCHANNELS_NAMES; +static const char *const librtt_rxName[LIBRTT_RXCHANNELS] = LIBRTT_RXCHANNELS_NAMES; static struct { volatile struct rtt_desc *rtt; void *memptr; + librtt_cacheOp_t invalFn; + librtt_cacheOp_t cleanFn; } librtt_common = { 0 }; -int rtt_check(int chan) +int librtt_check(int chan) { - if (librtt_common.rtt == NULL || chan < 0 || chan >= LIBRTT_TXCHANNELS) { + if ((librtt_common.rtt == NULL) || (chan < 0) || (chan >= LIBRTT_TXCHANNELS)) { return -ENODEV; } @@ -101,49 +105,66 @@ int rtt_check(int chan) } -ssize_t rtt_read(int chan, void *buf, size_t count) +static void performCacheOp(librtt_cacheOp_t op, volatile unsigned char *buf, unsigned int sz, unsigned int rd, unsigned int wr) +{ + if ((rd == wr) || (op == NULL)) { + return; + } + + if (wr < rd) { + op((void *)(buf + rd), sz - rd); + op((void *)buf, wr + 1); + } + else { + op((void *)(buf + rd), wr - rd + 1); + } +} + + +ssize_t librtt_read(int chan, void *buf, size_t count) { volatile struct rtt_desc *rtt = librtt_common.rtt; - if (rtt_check(chan) < 0) { + if (librtt_check(chan) < 0) { return -ENODEV; } dataMemoryBarrier(); - unsigned char *srcBuf = (unsigned char *)rtt->rxChannel[chan].ptr; + volatile unsigned char *srcBuf = rtt->rxChannel[chan].ptr; unsigned char *dstBuf = (unsigned char *)buf; unsigned int sz = rtt->rxChannel[chan].sz - 1; unsigned int rd = rtt->rxChannel[chan].rd & sz; unsigned int wr = rtt->rxChannel[chan].wr & sz; size_t todo = count; + performCacheOp(librtt_common.invalFn, srcBuf, sz + 1, rd, wr); while ((todo != 0) && (rd != wr)) { *dstBuf++ = srcBuf[rd]; rd = (rd + 1) & sz; todo--; } - rtt->rxChannel[chan].rd = rd; - dataMemoryBarrier(); + rtt->channel[ch].rd = rd; + return count - todo; } -ssize_t rtt_write(int chan, const void *buf, size_t count) +ssize_t librtt_write(int chan, const void *buf, size_t count) { volatile struct rtt_desc *rtt = librtt_common.rtt; - if (rtt_check(chan) < 0) { + if (librtt_check(chan) < 0) { return -ENODEV; } dataMemoryBarrier(); const unsigned char *srcBuf = (const unsigned char *)buf; - unsigned char *dstBuf = (unsigned char *)rtt->txChannel[chan].ptr; + volatile unsigned char *dstBuf = rtt->txChannel[chan].ptr; unsigned int sz = rtt->txChannel[chan].sz - 1; unsigned int rd = (rtt->txChannel[chan].rd + sz) & sz; unsigned int wr = rtt->txChannel[chan].wr & sz; @@ -155,15 +176,17 @@ ssize_t rtt_write(int chan, const void *buf, size_t count) todo--; } - rtt->txChannel[chan].wr = wr; + performCacheOp(librtt_common.cleanFn, dstBuf, sz + 1, rd, wr); dataMemoryBarrier(); + rtt->channel[ch].wr = wr; + return count - todo; } -ssize_t rtt_txAvail(int chan) +ssize_t librtt_txAvail(int chan) { volatile struct rtt_desc *rtt = librtt_common.rtt; @@ -181,7 +204,7 @@ ssize_t rtt_txAvail(int chan) } -void rtt_rxReset(int chan) +void librtt_rxReset(int chan) { dataMemoryBarrier(); librtt_common.rtt->rxChannel[chan].rd = librtt_common.rtt->rxChannel[chan].wr; @@ -189,7 +212,7 @@ void rtt_rxReset(int chan) } -void rtt_txReset(int chan) +void librtt_txReset(int chan) { dataMemoryBarrier(); librtt_common.rtt->txChannel[chan].wr = librtt_common.rtt->txChannel[chan].rd; @@ -197,61 +220,66 @@ void rtt_txReset(int chan) } -int rtt_init(void *addr, void *bufptr, size_t bufsz) +int librtt_init(void *addr, void *bufptr, size_t bufsz, librtt_cacheOp_t invalFn, librtt_cacheOp_t cleanFn) { unsigned int n, m; - volatile struct rtt_desc *rtt = librtt_common.rtt; - - if ((rtt != NULL) && (bufsz != 0) && ((bufsz & (bufsz - 1)) != 0)) { + const size_t bufSzPerChannel = bufsz / (LIBRTT_TXCHANNELS + LIBRTT_RXCHANNELS); + if ((LIBRTT_DESC_SIZE < sizeof(struct rtt_desc)) || + (librtt_common.rtt != NULL) || + (bufSzPerChannel == 0) || + ((bufSzPerChannel & (bufSzPerChannel - 1)) != 0)) { return -EINVAL; } if (bufptr == NULL) { bufptr = mmap(NULL, - bufsz * rtt->txChannels * rtt->rxChannels, + bufsz, PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_UNCACHED, -1, 0); + if (bufptr == MAP_FAILED) { return -ENOMEM; } - librtt_common.memptr = bufptr; } - rtt = (volatile struct rtt_desc *)addr; + librtt_common.memptr = bufptr; + librtt_common.invalFn = invalFn; + librtt_common.cleanFn = cleanFn; + + volatile struct rtt_desc *rtt = addr; memset((void *)rtt, 0, sizeof(*rtt)); rtt->txChannels = LIBRTT_TXCHANNELS; rtt->rxChannels = LIBRTT_RXCHANNELS; - bufsz /= (rtt->txChannels + rtt->rxChannels); - m = 0; for (n = 0; n < rtt->txChannels; n++) { - rtt->txChannel[n].name = rtt_txName[n]; - rtt->txChannel[n].ptr = (unsigned char *)bufptr + m * bufsz; - rtt->txChannel[n].sz = bufsz; + rtt->txChannel[n].name = librtt_txName[n]; + rtt->txChannel[n].ptr = (unsigned char *)bufptr + m * bufSzPerChannel; + rtt->txChannel[n].sz = bufSzPerChannel; m++; } for (n = 0; n < rtt->rxChannels; n++) { - rtt->rxChannel[n].name = rtt_rxName[n]; - rtt->rxChannel[n].ptr = (unsigned char *)bufptr + m * bufsz; - rtt->rxChannel[n].sz = bufsz; + rtt->rxChannel[n].name = librtt_rxName[n]; + rtt->rxChannel[n].ptr = (unsigned char *)bufptr + m * bufSzPerChannel; + rtt->rxChannel[n].sz = bufSzPerChannel; m++; } n = 0; - m = sizeof(rtt_tagReversed) - 1; - while (n < sizeof(rtt->tag) && m > 0) { - rtt->tag[n++] = rtt_tagReversed[--m]; + m = sizeof(librtt_tagReversed) - 1; + while ((n < sizeof(rtt->tag)) && (m > 0)) { + rtt->tag[n++] = librtt_tagReversed[--m]; } + librtt_common.rtt = rtt; return 0; } -void rtt_done(void) +void librtt_done(void) { volatile struct rtt_desc *rtt = librtt_common.rtt; diff --git a/librtt/librtt.h b/librtt/librtt.h new file mode 100644 index 000000000..7ed907732 --- /dev/null +++ b/librtt/librtt.h @@ -0,0 +1,59 @@ +/* + * Phoenix-RTOS + * + * RTT pipes: communication through debug probe + * + * Copyright 2023-2024 Phoenix Systems + * Author: Gerard Swiderski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef LIBRTT_H +#define LIBRTT_H + +#include + +/* Size of the common descriptor for RTT channels */ +#define LIBRTT_DESC_SIZE 256 + +typedef int (*librtt_cacheOp_t)(void *addr, unsigned int sz); + +/* Initialize rtt descriptor and rtt internal structures. + TODO: on armv7m targets MAP_UNCACHED flag seems to not be implemented. + Caller must supply `bufptr` in non-cached memory. +*/ +int librtt_init(void *addr, void *bufptr, size_t bufsz, librtt_cacheOp_t invalFn, librtt_cacheOp_t cleanFn); + + +/* Release resources, cleanup */ +void librtt_done(void); + + +/* Check if channel is present */ +int librtt_check(int chan); + + +/* Non-blocking read from channel */ +ssize_t librtt_read(int chan, void *buf, size_t count); + + +/* Non-blocking write to channel */ +ssize_t librtt_write(int chan, const void *buf, size_t count); + + +/* Check for available space in tx */ +ssize_t librtt_txAvail(int chan); + + +/* Reset rx fifo pointers */ +void librtt_rxReset(int chan); + + +/* Reset tx fifo pointers */ +void librtt_txReset(int chan); + + +#endif /* end of LIBRTT_H */ diff --git a/librtt/rtt.h b/librtt/rtt.h deleted file mode 100644 index 35303bc57..000000000 --- a/librtt/rtt.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Phoenix-RTOS - * - * RTT pipes: communication through debug probe - * - * Copyright 2023-2024 Phoenix Systems - * Author: Gerard Swiderski - * - * This file is part of Phoenix-RTOS. - * - * %LICENSE% - */ - -#ifndef LIBRTT_H -#define LIBRTT_H - - -/* Initialize rtt descriptor and rtt internal structures */ -int rtt_init(void *addr, void *bufptr, size_t bufsz); - - -/* Release resources, cleanup */ -void rtt_done(void); - - -/* Check if channel is present */ -int rtt_check(int chan); - - -/* Non-blocking read from channel */ -ssize_t rtt_read(int chan, void *buf, size_t count); - - -/* Non-blocking write to channel */ -ssize_t rtt_write(int chan, const void *buf, size_t count); - - -/* Check for available space in tx */ -ssize_t rtt_txAvail(int chan); - - -/* Reset rx fifo pointers */ -void rtt_rxReset(int chan); - - -/* Reset tx fifo pointers */ -void rtt_txReset(int chan); - - -#endif /* end of LIBRTT_H */ From 5cc081d0c1f75ec25ac3a006a640257ea5a1786b Mon Sep 17 00:00:00 2001 From: Jacek Maksymowicz Date: Mon, 19 Aug 2024 21:36:39 +0200 Subject: [PATCH 3/7] librtt: change API to allow per-channel initialization. Add more utility functions to probe channel status. JIRA: RTOS-754 --- librtt/librtt.c | 245 ++++++++++++++++++++++++++++++++---------------- librtt/librtt.h | 38 +++++--- 2 files changed, 191 insertions(+), 92 deletions(-) diff --git a/librtt/librtt.c b/librtt/librtt.c index 192fa1d7c..8b3185133 100644 --- a/librtt/librtt.c +++ b/librtt/librtt.c @@ -77,34 +77,24 @@ struct rtt_desc { char tag[16]; unsigned int txChannels; unsigned int rxChannels; - struct rtt_pipe txChannel[LIBRTT_TXCHANNELS]; - struct rtt_pipe rxChannel[LIBRTT_RXCHANNELS]; + struct rtt_pipe channel[LIBRTT_TXCHANNELS + LIBRTT_RXCHANNELS]; }; static const char librtt_tagReversed[] = LIBRTT_TAG_BACKWARD; +static const size_t librtt_tagLength = sizeof(librtt_tagReversed) - 1; static const char *const librtt_txName[LIBRTT_TXCHANNELS] = LIBRTT_TXCHANNELS_NAMES; static const char *const librtt_rxName[LIBRTT_RXCHANNELS] = LIBRTT_RXCHANNELS_NAMES; static struct { volatile struct rtt_desc *rtt; - void *memptr; librtt_cacheOp_t invalFn; librtt_cacheOp_t cleanFn; + unsigned int lastRd[LIBRTT_TXCHANNELS]; } librtt_common = { 0 }; -int librtt_check(int chan) -{ - if ((librtt_common.rtt == NULL) || (chan < 0) || (chan >= LIBRTT_TXCHANNELS)) { - return -ENODEV; - } - - return 0; -} - - static void performCacheOp(librtt_cacheOp_t op, volatile unsigned char *buf, unsigned int sz, unsigned int rd, unsigned int wr) { if ((rd == wr) || (op == NULL)) { @@ -121,24 +111,44 @@ static void performCacheOp(librtt_cacheOp_t op, volatile unsigned char *buf, uns } -ssize_t librtt_read(int chan, void *buf, size_t count) +int librtt_checkTx(unsigned int ch) +{ + if ((librtt_common.rtt == NULL) || (ch >= librtt_common.rtt->txChannels)) { + return -ENODEV; + } + + return 0; +} + + +int librtt_checkRx(unsigned int ch) +{ + if ((librtt_common.rtt == NULL) || (ch >= librtt_common.rtt->rxChannels)) { + return -ENODEV; + } + + return 0; +} + + +ssize_t librtt_read(unsigned int ch, void *buf, size_t count) { volatile struct rtt_desc *rtt = librtt_common.rtt; - if (librtt_check(chan) < 0) { + if (librtt_checkRx(ch) < 0) { return -ENODEV; } dataMemoryBarrier(); - - volatile unsigned char *srcBuf = rtt->rxChannel[chan].ptr; + ch += rtt->txChannels; + volatile unsigned char *srcBuf = rtt->channel[ch].ptr; unsigned char *dstBuf = (unsigned char *)buf; - unsigned int sz = rtt->rxChannel[chan].sz - 1; - unsigned int rd = rtt->rxChannel[chan].rd & sz; - unsigned int wr = rtt->rxChannel[chan].wr & sz; + unsigned int sz = rtt->channel[ch].sz - 1; + unsigned int rd = rtt->channel[ch].rd & sz; + unsigned int wr = rtt->channel[ch].wr & sz; size_t todo = count; - performCacheOp(librtt_common.invalFn, srcBuf, sz + 1, rd, wr); + performCacheOp(librtt_common.invalFn, (void *)srcBuf, sz + 1, rd, wr); while ((todo != 0) && (rd != wr)) { *dstBuf++ = srcBuf[rd]; rd = (rd + 1) & sz; @@ -153,21 +163,21 @@ ssize_t librtt_read(int chan, void *buf, size_t count) } -ssize_t librtt_write(int chan, const void *buf, size_t count) +ssize_t librtt_write(unsigned int ch, const void *buf, size_t count, int allowOverwrite) { volatile struct rtt_desc *rtt = librtt_common.rtt; - if (librtt_check(chan) < 0) { + if (librtt_checkTx(ch) < 0) { return -ENODEV; } dataMemoryBarrier(); const unsigned char *srcBuf = (const unsigned char *)buf; - volatile unsigned char *dstBuf = rtt->txChannel[chan].ptr; - unsigned int sz = rtt->txChannel[chan].sz - 1; - unsigned int rd = (rtt->txChannel[chan].rd + sz) & sz; - unsigned int wr = rtt->txChannel[chan].wr & sz; + volatile unsigned char *dstBuf = rtt->channel[ch].ptr; + unsigned int sz = rtt->channel[ch].sz - 1; + unsigned int rd = (rtt->channel[ch].rd + sz) & sz; + unsigned int wr = rtt->channel[ch].wr & sz; size_t todo = count; while ((todo != 0) && (rd != wr)) { @@ -176,7 +186,17 @@ ssize_t librtt_write(int chan, const void *buf, size_t count) todo--; } - performCacheOp(librtt_common.cleanFn, dstBuf, sz + 1, rd, wr); + if ((rd == wr) && (allowOverwrite != 0)) { + while (todo != 0) { + dstBuf[wr] = *srcBuf++; + wr = (wr + 1) & sz; + todo--; + } + + rtt->channel[ch].rd = wr; + } + + performCacheOp(librtt_common.cleanFn, (void *)dstBuf, sz + 1, rd, wr); dataMemoryBarrier(); @@ -186,14 +206,39 @@ ssize_t librtt_write(int chan, const void *buf, size_t count) } -ssize_t librtt_txAvail(int chan) +ssize_t librtt_rxAvail(unsigned int ch) +{ + volatile struct rtt_desc *rtt = librtt_common.rtt; + if (librtt_checkRx(ch) < 0) { + return 0; + } + + dataMemoryBarrier(); + ch += librtt_common.rtt->txChannels; + unsigned int sz = rtt->channel[ch].sz - 1; + unsigned int rd = rtt->channel[ch].rd & sz; + unsigned int wr = rtt->channel[ch].wr & sz; + + if (rd > wr) { + return sz + 1 - (rd - wr); + } + else { + return wr - rd; + } +} + + +ssize_t librtt_txAvail(unsigned int ch) { volatile struct rtt_desc *rtt = librtt_common.rtt; + if (librtt_checkTx(ch) < 0) { + return 0; + } dataMemoryBarrier(); - unsigned int sz = rtt->txChannel[chan].sz - 1; - unsigned int rd = (rtt->txChannel[chan].rd + sz) & sz; - unsigned int wr = rtt->txChannel[chan].wr & sz; + unsigned int sz = rtt->channel[ch].sz - 1; + unsigned int rd = (rtt->channel[ch].rd + sz) & sz; + unsigned int wr = rtt->channel[ch].wr & sz; if (wr > rd) { return sz + 1 - (wr - rd); @@ -204,77 +249,127 @@ ssize_t librtt_txAvail(int chan) } -void librtt_rxReset(int chan) +void librtt_rxReset(unsigned int ch) { dataMemoryBarrier(); - librtt_common.rtt->rxChannel[chan].rd = librtt_common.rtt->rxChannel[chan].wr; + if (librtt_checkRx(ch) < 0) { + return; + } + + ch += librtt_common.rtt->txChannels; + librtt_common.rtt->channel[ch].rd = librtt_common.rtt->channel[ch].wr; dataMemoryBarrier(); } -void librtt_txReset(int chan) +void librtt_txReset(unsigned int ch) { dataMemoryBarrier(); - librtt_common.rtt->txChannel[chan].wr = librtt_common.rtt->txChannel[chan].rd; + if (librtt_checkTx(ch) < 0) { + return; + } + + librtt_common.rtt->channel[ch].wr = librtt_common.rtt->channel[ch].rd; dataMemoryBarrier(); } -int librtt_init(void *addr, void *bufptr, size_t bufsz, librtt_cacheOp_t invalFn, librtt_cacheOp_t cleanFn) +int librtt_txCheckReaderAttached(unsigned int ch) { - unsigned int n, m; - const size_t bufSzPerChannel = bufsz / (LIBRTT_TXCHANNELS + LIBRTT_RXCHANNELS); - if ((LIBRTT_DESC_SIZE < sizeof(struct rtt_desc)) || - (librtt_common.rtt != NULL) || - (bufSzPerChannel == 0) || - ((bufSzPerChannel & (bufSzPerChannel - 1)) != 0)) { - return -EINVAL; + if (librtt_checkTx(ch) < 0) { + return 0; } - if (bufptr == NULL) { - bufptr = mmap(NULL, - bufsz, - PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_UNCACHED, - -1, - 0); + unsigned int rd = librtt_common.rtt->channel[ch].rd; + if (librtt_common.lastRd[ch] != rd) { + librtt_common.lastRd[ch] = rd; + return 1; + } - if (bufptr == MAP_FAILED) { - return -ENOMEM; - } + return 0; +} + + +int librtt_init(void *addr, librtt_cacheOp_t invalFn, librtt_cacheOp_t cleanFn) +{ + if ((LIBRTT_DESC_SIZE < sizeof(struct rtt_desc)) || (librtt_common.rtt != NULL)) { + return -EINVAL; } - librtt_common.memptr = bufptr; librtt_common.invalFn = invalFn; librtt_common.cleanFn = cleanFn; volatile struct rtt_desc *rtt = addr; + + int n; + for (n = 0; n < librtt_tagLength; n++) { + if (librtt_tagReversed[n] != rtt->tag[librtt_tagLength - 1 - n]) { + break; + } + } + + if (n == librtt_tagLength) { + if ((rtt->txChannels + rtt->rxChannels) <= (LIBRTT_TXCHANNELS + LIBRTT_RXCHANNELS)) { + librtt_common.rtt = rtt; + return 0; + } + } + memset((void *)rtt, 0, sizeof(*rtt)); rtt->txChannels = LIBRTT_TXCHANNELS; rtt->rxChannels = LIBRTT_RXCHANNELS; - m = 0; - for (n = 0; n < rtt->txChannels; n++) { - rtt->txChannel[n].name = librtt_txName[n]; - rtt->txChannel[n].ptr = (unsigned char *)bufptr + m * bufSzPerChannel; - rtt->txChannel[n].sz = bufSzPerChannel; - m++; + for (n = 0; n < librtt_tagLength; n++) { + rtt->tag[librtt_tagLength - 1 - n] = librtt_tagReversed[n]; + } + + librtt_common.rtt = rtt; + return 0; +} + + +int librtt_initChannel(int isTx, unsigned int ch, unsigned char *buf, size_t sz) +{ + volatile struct rtt_desc *rtt = librtt_common.rtt; + if (rtt == NULL) { + return -EINVAL; } - for (n = 0; n < rtt->rxChannels; n++) { - rtt->rxChannel[n].name = librtt_rxName[n]; - rtt->rxChannel[n].ptr = (unsigned char *)bufptr + m * bufSzPerChannel; - rtt->rxChannel[n].sz = bufSzPerChannel; - m++; + unsigned int chMax = (isTx != 0) ? rtt->txChannels : rtt->rxChannels; + if ((ch >= chMax)) { + return -EINVAL; } - n = 0; - m = sizeof(librtt_tagReversed) - 1; - while ((n < sizeof(rtt->tag)) && (m > 0)) { - rtt->tag[n++] = librtt_tagReversed[--m]; + /* Check buffer size is non-zero and power of 2 */ + if ((sz == 0) || ((sz & (sz - 1)) != 0)) { + return -EINVAL; } - librtt_common.rtt = rtt; + const char *name = NULL; + if (isTx != 0) { + if (ch < LIBRTT_TXCHANNELS) { + name = librtt_txName[ch]; + } + } + else { + if (ch < LIBRTT_RXCHANNELS) { + name = librtt_rxName[ch]; + } + } + + if (isTx != 0) { + librtt_common.lastRd[ch] = 0; + } + else { + ch += rtt->txChannels; + } + + rtt->channel[ch].name = name; + rtt->channel[ch].ptr = buf; + rtt->channel[ch].sz = sz; + rtt->channel[ch].rd = 0; + rtt->channel[ch].wr = 0; return 0; } @@ -284,16 +379,6 @@ void librtt_done(void) volatile struct rtt_desc *rtt = librtt_common.rtt; if (rtt != NULL) { - if (librtt_common.memptr != NULL) { - size_t n, sz = 0; - for (n = 0; rtt->txChannels; n++) { - sz += rtt->txChannel[n].sz; - } - for (n = 0; rtt->rxChannels; n++) { - sz += rtt->rxChannel[n].sz; - } - munmap(librtt_common.memptr, sz); - } memset((void *)rtt, 0, sizeof(*rtt)); librtt_common.rtt = NULL; } diff --git a/librtt/librtt.h b/librtt/librtt.h index 7ed907732..d01c821ef 100644 --- a/librtt/librtt.h +++ b/librtt/librtt.h @@ -21,39 +21,53 @@ typedef int (*librtt_cacheOp_t)(void *addr, unsigned int sz); -/* Initialize rtt descriptor and rtt internal structures. - TODO: on armv7m targets MAP_UNCACHED flag seems to not be implemented. - Caller must supply `bufptr` in non-cached memory. -*/ -int librtt_init(void *addr, void *bufptr, size_t bufsz, librtt_cacheOp_t invalFn, librtt_cacheOp_t cleanFn); + +/* Initialize rtt descriptor if it is not initialized already */ +int librtt_init(void *addr, librtt_cacheOp_t invalFn, librtt_cacheOp_t cleanFn); + + +/* Initialize a single RTT channel */ +int librtt_initChannel(int isTx, unsigned int ch, unsigned char *buf, size_t sz); /* Release resources, cleanup */ void librtt_done(void); -/* Check if channel is present */ -int librtt_check(int chan); +/* Check if TX channel is present */ +int librtt_checkTx(unsigned int ch); + + +/* Check if RX channel is present */ +int librtt_checkRx(unsigned int ch); /* Non-blocking read from channel */ -ssize_t librtt_read(int chan, void *buf, size_t count); +ssize_t librtt_read(unsigned int ch, void *buf, size_t count); /* Non-blocking write to channel */ -ssize_t librtt_write(int chan, const void *buf, size_t count); +ssize_t librtt_write(unsigned int ch, const void *buf, size_t count, int allowOverwrite); + + +/* Check for available data in rx */ +ssize_t librtt_rxAvail(unsigned int ch); /* Check for available space in tx */ -ssize_t librtt_txAvail(int chan); +ssize_t librtt_txAvail(unsigned int ch); + + +/* Check if a reader has read something from chosen TX channel since the last check */ +int librtt_txCheckReaderAttached(unsigned int ch); /* Reset rx fifo pointers */ -void librtt_rxReset(int chan); +void librtt_rxReset(unsigned int ch); /* Reset tx fifo pointers */ -void librtt_txReset(int chan); +void librtt_txReset(unsigned int ch); #endif /* end of LIBRTT_H */ From 97f3900f3ddbc9ef63e2ea2da2e05ab1740afb7e Mon Sep 17 00:00:00 2001 From: Jacek Maksymowicz Date: Thu, 12 Sep 2024 16:10:13 +0200 Subject: [PATCH 4/7] imxrt-multi: add support for console over RTT JIRA: RTOS-754 --- multi/imxrt-multi/Makefile | 4 +- multi/imxrt-multi/config.h | 50 +++++- multi/imxrt-multi/imxrt-multi.c | 27 ++++ multi/imxrt-multi/imxrt-multi.h | 3 +- multi/imxrt-multi/rtt.c | 265 ++++++++++++++++++++++++++++++++ multi/imxrt-multi/rtt.h | 32 ++++ multi/imxrt-multi/uart.c | 4 +- 7 files changed, 380 insertions(+), 5 deletions(-) create mode 100644 multi/imxrt-multi/rtt.c create mode 100644 multi/imxrt-multi/rtt.h diff --git a/multi/imxrt-multi/Makefile b/multi/imxrt-multi/Makefile index f970cdc2a..3f0422e56 100644 --- a/multi/imxrt-multi/Makefile +++ b/multi/imxrt-multi/Makefile @@ -8,13 +8,13 @@ NAME := imxrt-multi LOCAL_PATH := $(call my-dir) -LOCAL_SRCS = imxrt-multi.c common.c uart.c gpio.c spi.c i2c.c fs.c posixsrv.c pct2075.c +LOCAL_SRCS = imxrt-multi.c common.c uart.c gpio.c spi.c i2c.c fs.c posixsrv.c pct2075.c rtt.c ifneq ($(TARGET_SUBFAMILY), imxrt117x) LOCAL_SRCS += trng.c else LOCAL_SRCS += cm4.c endif -DEP_LIBS := libtty libklog libpseudodev i2c-common +DEP_LIBS := libtty libklog libpseudodev i2c-common librtt LIBS := libdummyfs libklog libpseudodev libposixsrv LOCAL_HEADERS := imxrt-multi.h diff --git a/multi/imxrt-multi/config.h b/multi/imxrt-multi/config.h index 26b06c6e5..5f1c7f680 100644 --- a/multi/imxrt-multi/config.h +++ b/multi/imxrt-multi/config.h @@ -754,7 +754,7 @@ /* clang-format on */ -#ifndef UART_CONSOLE +#if !defined(UART_CONSOLE) && !defined(RTT_CHANNEL_CONSOLE) #if defined(__CPU_IMXRT105X) #define UART_CONSOLE 1 #elif defined(__CPU_IMXRT106X) @@ -766,6 +766,54 @@ #endif #endif +#if defined(UART_CONSOLE) +#if ISEMPTY(UART_CONSOLE) +#error "UART_CONSOLE must not be empty" +#elif UART_CONSOLE <= 0 +#error "Invalid value for UART_CONSOLE" +#endif +#endif + + +/* RTT */ + +#ifndef RTT_CHANNEL0 +#define RTT_CHANNEL0 0 +#elif !ISBOOLEAN(RTT_CHANNEL0) +#error "RTT_CHANNEL0 must have a value of 0, 1, or be undefined" +#endif + +#ifndef RTT_CHANNEL1 +#define RTT_CHANNEL1 0 +#elif !ISBOOLEAN(RTT_CHANNEL1) +#error "RTT_CHANNEL1 must have a value of 0, 1, or be undefined" +#endif + +#ifndef RTT_CHANNEL0_BLOCKING +#define RTT_CHANNEL0_BLOCKING 0 +#elif !ISBOOLEAN(RTT_CHANNEL0_BLOCKING) +#error "RTT_CHANNEL0_BLOCKING must have a value of 0, 1, or be undefined" +#endif + +#ifndef RTT_CHANNEL1_BLOCKING +#define RTT_CHANNEL1_BLOCKING 0 +#elif !ISBOOLEAN(RTT_CHANNEL1_BLOCKING) +#error "RTT_CHANNEL1_BLOCKING must have a value of 0, 1, or be undefined" +#endif + + +#if defined(UART_CONSOLE) && defined(RTT_CHANNEL_CONSOLE) +#error "Console on UART and RTT not supported" +#elif defined(RTT_CHANNEL_CONSOLE) +#if ISEMPTY(RTT_CHANNEL_CONSOLE) +#error "RTT_CHANNEL_CONSOLE must not be empty" +#elif RTT_CHANNEL_CONSOLE < 0 +#error "Invalid value for RTT_CHANNEL_CONSOLE" +#endif + +#define ONLY_RTT_CONSOLE +#endif + /* SPI */ diff --git a/multi/imxrt-multi/imxrt-multi.c b/multi/imxrt-multi/imxrt-multi.c index d3691cefa..3394290d5 100644 --- a/multi/imxrt-multi/imxrt-multi.c +++ b/multi/imxrt-multi/imxrt-multi.c @@ -33,6 +33,7 @@ #include "common.h" #include "uart.h" +#include "rtt.h" #include "gpio.h" #include "spi.h" #include "i2c.h" @@ -168,7 +169,11 @@ static void uart_dispatchMsg(msg_t *msg) switch (id) { case id_console: +#ifdef ONLY_RTT_CONSOLE + rtt_handleMsg(msg, RTT_CHANNEL_CONSOLE + id_rtt0); +#else uart_handleMsg(msg, UART_CONSOLE - 1 + id_uart1); +#endif break; case id_uart1: @@ -191,6 +196,11 @@ static void uart_dispatchMsg(msg_t *msg) break; #endif + case id_rtt0: + case id_rtt1: + rtt_handleMsg(msg, id); + break; + default: msg->o.err = -ENODEV; break; @@ -335,6 +345,18 @@ static int createDevFiles(void) } #endif +#endif + +#if RTT_CHANNEL0 + if (mkFile(&dir, id_rtt0, "rtt0", common.uart_port) < 0) { + return -1; + } +#endif + +#if RTT_CHANNEL1 + if (mkFile(&dir, id_rtt1, "rtt1", common.uart_port) < 0) { + return -1; + } #endif /* GPIOs */ @@ -577,6 +599,7 @@ int main(void) #endif uart_init(); + rtt_init(); gpio_init(); spi_init(); i2c_init(); @@ -585,7 +608,11 @@ int main(void) oid.id = id_console; create_dev(&oid, _PATH_CONSOLE); +#ifdef ONLY_RTT_CONSOLE + libklog_init(rtt_klogCblk); +#else libklog_init(uart_klogCblk); +#endif oid_t kmsgctrl = { .port = common.uart_port, .id = id_kmsgctrl }; libklog_ctrlRegister(&kmsgctrl); diff --git a/multi/imxrt-multi/imxrt-multi.h b/multi/imxrt-multi/imxrt-multi.h index 13f768d27..ac954cbcd 100644 --- a/multi/imxrt-multi/imxrt-multi.h +++ b/multi/imxrt-multi/imxrt-multi.h @@ -31,7 +31,8 @@ enum { id_console = 0, id_uart1, id_uart2, id_uart3, id_uart4, id_uart5, id_uart id_i2c5, id_i2c6, id_cm4_0, id_cm4_1, id_cm4_2, id_cm4_3, #endif - id_trng, id_pseudoNull, id_pseudoZero, id_pseudoFull, id_pseudoRandom, id_kmsgctrl, id_temp1 + id_trng, id_pseudoNull, id_pseudoZero, id_pseudoFull, id_pseudoRandom, id_kmsgctrl, id_temp1, + id_rtt0, id_rtt1, }; /* clang-format on */ diff --git a/multi/imxrt-multi/rtt.c b/multi/imxrt-multi/rtt.c new file mode 100644 index 000000000..d93ffc4cc --- /dev/null +++ b/multi/imxrt-multi/rtt.c @@ -0,0 +1,265 @@ +/* + * Phoenix-RTOS + * + * iMX RT RTT communication driver + * + * Copyright 2017-2024 Phoenix Systems + * Author: Kamil Amanowicz, Marek Bialowas, Aleksander Kaminski, Jacek Maksymowicz + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" +#include "rtt.h" + + +#ifndef RTT_ADDR +/* RTT descriptors location, last 256 bytes of DTCM */ +#define RTT_ADDR (0x20040000 - 0x100) +#endif + +#define RTT_TX_BUF_SIZE 1024 +#define RTT_RX_BUF_SIZE 256 +#define RTT_POLLING_RATE_MS 20 +#define RTT_NO_PICKUP_TIMEOUT_MS (2 * RTT_POLLING_RATE_MS) +#define RTT_RETRIES (RTT_NO_PICKUP_TIMEOUT_MS / RTT_POLLING_RATE_MS) + +/* Doesn't need to be large, data will mostly be stored in RTT buffers */ +#define TTY_BUF_SIZE 64 + +#define RTT_CHANNEL0_POS 0 +#define RTT_CHANNEL1_POS (RTT_CHANNEL0_POS + RTT_CHANNEL0) +#define RTT_ACTIVE_CNT (RTT_CHANNEL0 + RTT_CHANNEL1) + +typedef struct rtt_s { + int chn; + handle_t lock; + libtty_common_t tty_common; + volatile unsigned int diag_txSkipped; /* Accessed using a debugger */ +} rtt_t; + +static struct { + char stack[1024] __attribute__((aligned(8))); + rtt_t uarts[RTT_ACTIVE_CNT]; +} rtt_common; + + +static const int rttConfig[] = { RTT_CHANNEL0, RTT_CHANNEL1 }; + + +static const int rttBlocking[] = { RTT_CHANNEL0_BLOCKING, RTT_CHANNEL1_BLOCKING }; + + +static const int rttPos[] = { RTT_CHANNEL0_POS, RTT_CHANNEL1_POS }; + + +#define RTT_CHANNEL_CNT (sizeof(rttConfig) / sizeof(rttConfig[0])) + + +static inline ssize_t rtt_txAvailMode(unsigned int chn) +{ + return (rttBlocking[chn] != 0) ? librtt_txAvail(chn) : 1; +} + + +static void rtt_thread(void *arg) +{ + unsigned retries[RTT_ACTIVE_CNT]; + memset(retries, 0, sizeof(retries)); + + for (;;) { + for (int chn_idx = 0; chn_idx < RTT_ACTIVE_CNT; chn_idx++) { + rtt_t *uart = &rtt_common.uarts[chn_idx]; + unsigned char data; + ssize_t onRx = librtt_rxAvail(uart->chn); + ssize_t onTx = rtt_txAvailMode(uart->chn); + int txReady = libtty_txready(&uart->tty_common); + + if (rttBlocking[uart->chn] == 0) { + /* Do nothing, in this case the remaining code is unnecessary */ + } + else if (librtt_txCheckReaderAttached(uart->chn) != 0) { + retries[chn_idx] = RTT_RETRIES; + } + else if (onTx == 0) { + if (retries[chn_idx] == 0) { + onTx = 1; + } + else { + retries[chn_idx]--; + } + } + + + if ((onRx == 0) && ((txReady == 0) || (onTx == 0))) { + continue; + } + + mutexLock(uart->lock); + const unsigned char mask = ((uart->tty_common.term.c_cflag & CSIZE) == CS7) ? 0x7f : 0xff; + while (onRx > 0) { + librtt_read(uart->chn, &data, 1); + libtty_putchar(&uart->tty_common, data & mask, NULL); + onRx = librtt_rxAvail(uart->chn); + } + + while (onTx > 0 && txReady) { + data = libtty_getchar(&uart->tty_common, NULL); + ssize_t written = librtt_write(uart->chn, &data, 1, 0); + if (written <= 0) { + uart->diag_txSkipped++; + } + + onTx = rtt_txAvailMode(uart->chn); + txReady = libtty_txready(&uart->tty_common); + } + + mutexUnlock(uart->lock); + } + + usleep(RTT_POLLING_RATE_MS * 1000); + } +} + + +static int rtt_initOne(rtt_t *uart, int chn, unsigned char *buf) +{ + libtty_callbacks_t callbacks; + callbacks.arg = uart; + callbacks.set_baudrate = NULL; + callbacks.set_cflag = NULL; + callbacks.signal_txready = NULL; + + uart->chn = chn; + + int ret = 0; + ret = (ret == 0) ? librtt_initChannel(1, chn, buf, RTT_TX_BUF_SIZE) : ret; + ret = (ret == 0) ? librtt_initChannel(0, chn, buf + RTT_TX_BUF_SIZE, RTT_RX_BUF_SIZE) : ret; + ret = (ret == 0) ? mutexCreate(&uart->lock) : ret; + /* TODO: calculate approx. baud rate based on buffer size and polling rate */ + ret = (ret == 0) ? libtty_init(&uart->tty_common, &callbacks, TTY_BUF_SIZE, libtty_int_to_baudrate(115200)) : ret; + + return ret; +} + + +int rtt_init(void) +{ + if (RTT_ACTIVE_CNT == 0) { + return EOK; + } + + /* Reserve memory for the descriptor and buffers */ + intptr_t startAddr = (RTT_ADDR - (RTT_ACTIVE_CNT * (RTT_TX_BUF_SIZE + RTT_RX_BUF_SIZE))) & ~(_PAGE_SIZE - 1); + size_t mapSize = RTT_ADDR + LIBRTT_DESC_SIZE - startAddr; + unsigned char *rttBuffer = mmap( + NULL, + mapSize, + PROT_WRITE | PROT_READ, + MAP_ANONYMOUS | MAP_UNCACHED | MAP_PHYSMEM, + -1, + startAddr); + + if (rttBuffer == MAP_FAILED) { + return -ENOMEM; + } + + int ret = librtt_init((void *)RTT_ADDR, NULL, NULL); + if (ret != 0) { + librtt_done(); + munmap(rttBuffer, mapSize); + return ret; + } + + unsigned char *buf = rttBuffer; + for (int i = 0, chn = 0; chn < RTT_CHANNEL_CNT; ++chn) { + if (rttConfig[chn] == 0) { + continue; + } + + rtt_t *uart = &rtt_common.uarts[i++]; + int ret = rtt_initOne(uart, chn, buf); + if (ret != 0) { + librtt_done(); + munmap(rttBuffer, mapSize); + return ret; + } + + buf += RTT_RX_BUF_SIZE + RTT_TX_BUF_SIZE; + } + + beginthread(rtt_thread, IMXRT_MULTI_PRIO, rtt_common.stack, sizeof(rtt_common.stack), NULL); + return ret; +} + +void rtt_klogCblk(const char *data, size_t size) +{ +#ifdef RTT_CHANNEL_CONSOLE + libtty_write(&rtt_common.uarts[rttPos[RTT_CHANNEL_CONSOLE]].tty_common, data, size, 0); +#endif +} + + +int rtt_handleMsg(msg_t *msg, int dev) +{ + unsigned long request; + const void *in_data, *out_data = NULL; + pid_t pid; + int err; + rtt_t *uart; + + dev -= id_rtt0; + + if ((dev < 0) || (dev >= RTT_CHANNEL_CNT) || (rttConfig[dev] == 0)) { + return -EINVAL; + } + + uart = &rtt_common.uarts[rttPos[dev]]; + + switch (msg->type) { + case mtWrite: + msg->o.err = libtty_write(&uart->tty_common, msg->i.data, msg->i.size, msg->i.io.mode); + break; + + case mtRead: + msg->o.err = libtty_read(&uart->tty_common, msg->o.data, msg->o.size, msg->i.io.mode); + break; + + case mtGetAttr: + if (msg->i.attr.type != atPollStatus) { + msg->o.err = -ENOSYS; + break; + } + + msg->o.attr.val = libtty_poll_status(&uart->tty_common); + msg->o.err = EOK; + break; + + case mtDevCtl: + in_data = ioctl_unpack(msg, &request, NULL); + pid = ioctl_getSenderPid(msg); + err = libtty_ioctl(&uart->tty_common, pid, request, in_data, &out_data); + ioctl_setResponse(msg, request, err, out_data); + break; + + default: + msg->o.err = -ENOSYS; + break; + } + + return EOK; +} diff --git a/multi/imxrt-multi/rtt.h b/multi/imxrt-multi/rtt.h new file mode 100644 index 000000000..488d2770c --- /dev/null +++ b/multi/imxrt-multi/rtt.h @@ -0,0 +1,32 @@ +/* + * Phoenix-RTOS + * + * iMX RT RTT communication driver + * + * Copyright 2024 Phoenix Systems + * Author: Jacek Maksymowicz + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _RTT_H_ +#define _RTT_H_ + +#include +#include + +#include + + +int rtt_init(void); + + +int rtt_handleMsg(msg_t *msg, int dev); + + +void rtt_klogCblk(const char *data, size_t size); + + +#endif /* _RTT_H_ */ diff --git a/multi/imxrt-multi/uart.c b/multi/imxrt-multi/uart.c index 2eead0884..c27b78f07 100644 --- a/multi/imxrt-multi/uart.c +++ b/multi/imxrt-multi/uart.c @@ -772,7 +772,9 @@ static void uart_initPins(void) void uart_klogCblk(const char *data, size_t size) { - libtty_write(&uart_common.uarts[uartPos[UART_CONSOLE - id_uart1]].tty_common, data, size, 0); +#ifdef UART_CONSOLE + libtty_write(&uart_common.uarts[uartPos[UART_CONSOLE - 1]].tty_common, data, size, 0); +#endif } From 5394ad942cea2341d5378a0ac2d3f7ab4abb16a4 Mon Sep 17 00:00:00 2001 From: Jacek Maksymowicz Date: Thu, 19 Sep 2024 13:53:42 +0200 Subject: [PATCH 5/7] imxrt-multi: change RTT initialization Remove hard-coded RTT address and get it from memory map. Change RTT initialization to keep existing buffer contents if buffers are valid. Allow more channels in the control block than defined at compile time (they will not be usable by the userspace driver). JIRA: RTOS-754 --- librtt/librtt.c | 102 +++++++++++++++++++++++++++----------- librtt/librtt.h | 6 ++- multi/imxrt-multi/rtt.c | 107 +++++++++++++++++++++++++++++----------- 3 files changed, 155 insertions(+), 60 deletions(-) diff --git a/librtt/librtt.c b/librtt/librtt.c index 8b3185133..4e01bb7fb 100644 --- a/librtt/librtt.c +++ b/librtt/librtt.c @@ -77,7 +77,7 @@ struct rtt_desc { char tag[16]; unsigned int txChannels; unsigned int rxChannels; - struct rtt_pipe channel[LIBRTT_TXCHANNELS + LIBRTT_RXCHANNELS]; + struct rtt_pipe channel[]; }; @@ -113,7 +113,7 @@ static void performCacheOp(librtt_cacheOp_t op, volatile unsigned char *buf, uns int librtt_checkTx(unsigned int ch) { - if ((librtt_common.rtt == NULL) || (ch >= librtt_common.rtt->txChannels)) { + if ((librtt_common.rtt == NULL) || (ch >= librtt_common.rtt->txChannels) || (ch >= LIBRTT_TXCHANNELS)) { return -ENODEV; } @@ -123,7 +123,7 @@ int librtt_checkTx(unsigned int ch) int librtt_checkRx(unsigned int ch) { - if ((librtt_common.rtt == NULL) || (ch >= librtt_common.rtt->rxChannels)) { + if ((librtt_common.rtt == NULL) || (ch >= librtt_common.rtt->rxChannels) || (ch >= LIBRTT_RXCHANNELS)) { return -ENODEV; } @@ -290,37 +290,87 @@ int librtt_txCheckReaderAttached(unsigned int ch) } -int librtt_init(void *addr, librtt_cacheOp_t invalFn, librtt_cacheOp_t cleanFn) +static int librtt_verifyChannel(volatile struct rtt_desc *rtt, unsigned int ch, unsigned char *buffers, size_t buffersSize) { - if ((LIBRTT_DESC_SIZE < sizeof(struct rtt_desc)) || (librtt_common.rtt != NULL)) { + unsigned char *bufEnd = buffers + buffersSize; + size_t sz = rtt->channel[ch].sz; + /* Check buffer size is non-zero and power of 2 */ + if ((sz == 0) || ((sz & (sz - 1)) != 0)) { return -EINVAL; } - librtt_common.invalFn = invalFn; - librtt_common.cleanFn = cleanFn; + if ((rtt->channel[ch].ptr < buffers) || (rtt->channel[ch].ptr >= bufEnd)) { + return -EINVAL; + } + + if (((rtt->channel[ch].ptr + rtt->channel[ch].sz) <= buffers) || ((rtt->channel[ch].ptr + rtt->channel[ch].sz) > bufEnd)) { + return -EINVAL; + } + + return 0; +} - volatile struct rtt_desc *rtt = addr; - int n; +int librtt_verify(void *addr, size_t cbSize, void *buffers, size_t buffersSize, librtt_cacheOp_t invalFn, librtt_cacheOp_t cleanFn) +{ + int n, ret; + if (cbSize < sizeof(struct rtt_desc)) { + return -EINVAL; + } + + volatile struct rtt_desc *rtt = addr; for (n = 0; n < librtt_tagLength; n++) { if (librtt_tagReversed[n] != rtt->tag[librtt_tagLength - 1 - n]) { break; } } - if (n == librtt_tagLength) { - if ((rtt->txChannels + rtt->rxChannels) <= (LIBRTT_TXCHANNELS + LIBRTT_RXCHANNELS)) { - librtt_common.rtt = rtt; - return 0; + if (n != librtt_tagLength) { + return -EINVAL; + } + + size_t realCbSize = sizeof(struct rtt_desc) + ((rtt->txChannels + rtt->rxChannels) * sizeof(struct rtt_pipe)); + if (cbSize < realCbSize) { + return -EINVAL; + } + + int totalChannels = rtt->txChannels + rtt->rxChannels; + for (n = 0; n < totalChannels; n++) { + ret = librtt_verifyChannel(rtt, n, buffers, buffersSize); + if (ret != 0) { + return ret; + } + + if (n < LIBRTT_TXCHANNELS) { + librtt_common.lastRd[n] = rtt->channel[n].rd; } } - memset((void *)rtt, 0, sizeof(*rtt)); + librtt_common.invalFn = invalFn; + librtt_common.cleanFn = cleanFn; + librtt_common.rtt = rtt; + return 0; +} + + +int librtt_init(void *addr, librtt_cacheOp_t invalFn, librtt_cacheOp_t cleanFn) +{ + const size_t cbSize = sizeof(struct rtt_desc) + (LIBRTT_TXCHANNELS + LIBRTT_RXCHANNELS) * sizeof(struct rtt_pipe); + if ((LIBRTT_DESC_SIZE < cbSize) || (librtt_common.rtt != NULL)) { + return -EINVAL; + } + + librtt_common.invalFn = invalFn; + librtt_common.cleanFn = cleanFn; + + volatile struct rtt_desc *rtt = addr; + + memset((void *)rtt, 0, cbSize); rtt->txChannels = LIBRTT_TXCHANNELS; rtt->rxChannels = LIBRTT_RXCHANNELS; - for (n = 0; n < librtt_tagLength; n++) { + for (int n = 0; n < librtt_tagLength; n++) { rtt->tag[librtt_tagLength - 1 - n] = librtt_tagReversed[n]; } @@ -336,11 +386,6 @@ int librtt_initChannel(int isTx, unsigned int ch, unsigned char *buf, size_t sz) return -EINVAL; } - unsigned int chMax = (isTx != 0) ? rtt->txChannels : rtt->rxChannels; - if ((ch >= chMax)) { - return -EINVAL; - } - /* Check buffer size is non-zero and power of 2 */ if ((sz == 0) || ((sz & (sz - 1)) != 0)) { return -EINVAL; @@ -348,20 +393,19 @@ int librtt_initChannel(int isTx, unsigned int ch, unsigned char *buf, size_t sz) const char *name = NULL; if (isTx != 0) { - if (ch < LIBRTT_TXCHANNELS) { - name = librtt_txName[ch]; + if ((ch >= LIBRTT_TXCHANNELS) || (ch >= rtt->txChannels)) { + return -EINVAL; } - } - else { - if (ch < LIBRTT_RXCHANNELS) { - name = librtt_rxName[ch]; - } - } - if (isTx != 0) { + name = librtt_txName[ch]; librtt_common.lastRd[ch] = 0; } else { + if ((ch >= LIBRTT_RXCHANNELS) || (ch >= rtt->rxChannels)) { + return -EINVAL; + } + + name = librtt_rxName[ch]; ch += rtt->txChannels; } diff --git a/librtt/librtt.h b/librtt/librtt.h index d01c821ef..000ce5202 100644 --- a/librtt/librtt.h +++ b/librtt/librtt.h @@ -22,7 +22,11 @@ typedef int (*librtt_cacheOp_t)(void *addr, unsigned int sz); -/* Initialize rtt descriptor if it is not initialized already */ +/* Verify contents of rtt descriptor and initialize data structure if successful */ +int librtt_verify(void *addr, size_t cbSize, void *buffers, size_t buffersSize, librtt_cacheOp_t invalFn, librtt_cacheOp_t cleanFn); + + +/* Initialize rtt descriptor */ int librtt_init(void *addr, librtt_cacheOp_t invalFn, librtt_cacheOp_t cleanFn); diff --git a/multi/imxrt-multi/rtt.c b/multi/imxrt-multi/rtt.c index d93ffc4cc..bc22a6fda 100644 --- a/multi/imxrt-multi/rtt.c +++ b/multi/imxrt-multi/rtt.c @@ -27,9 +27,8 @@ #include "rtt.h" -#ifndef RTT_ADDR -/* RTT descriptors location, last 256 bytes of DTCM */ -#define RTT_ADDR (0x20040000 - 0x100) +#ifndef RTT_SYSPAGE_MAP_NAME +#define RTT_SYSPAGE_MAP_NAME "rtt" #endif #define RTT_TX_BUF_SIZE 1024 @@ -147,8 +146,11 @@ static int rtt_initOne(rtt_t *uart, int chn, unsigned char *buf) uart->chn = chn; int ret = 0; - ret = (ret == 0) ? librtt_initChannel(1, chn, buf, RTT_TX_BUF_SIZE) : ret; - ret = (ret == 0) ? librtt_initChannel(0, chn, buf + RTT_TX_BUF_SIZE, RTT_RX_BUF_SIZE) : ret; + if (buf != NULL) { + ret = (ret == 0) ? librtt_initChannel(1, chn, buf, RTT_TX_BUF_SIZE) : ret; + ret = (ret == 0) ? librtt_initChannel(0, chn, buf + RTT_TX_BUF_SIZE, RTT_RX_BUF_SIZE) : ret; + } + ret = (ret == 0) ? mutexCreate(&uart->lock) : ret; /* TODO: calculate approx. baud rate based on buffer size and polling rate */ ret = (ret == 0) ? libtty_init(&uart->tty_common, &callbacks, TTY_BUF_SIZE, libtty_int_to_baudrate(115200)) : ret; @@ -157,52 +159,97 @@ static int rtt_initOne(rtt_t *uart, int chn, unsigned char *buf) } +static int rtt_getMemInfo(void **rttMemPtr_out, size_t *rttMemSz_out) +{ + void *rttMemPtr = NULL; + size_t rttMemSz = 0; + meminfo_t mi; + mi.page.mapsz = -1; + mi.entry.kmapsz = -1; + mi.entry.mapsz = -1; + mi.maps.mapsz = 0; + mi.maps.map = NULL; + meminfo(&mi); + + mi.maps.map = malloc(mi.maps.mapsz * sizeof(mapinfo_t)); + if (mi.maps.map == NULL) { + return -ENOMEM; + } + + meminfo(&mi); + for (int i = 0; i < mi.maps.mapsz; i++) { + if (strcmp(mi.maps.map[i].name, RTT_SYSPAGE_MAP_NAME) == 0) { + rttMemPtr = (void *)mi.maps.map[i].vstart; + rttMemSz = mi.maps.map[i].vend - mi.maps.map[i].vstart; + break; + } + } + + free(mi.maps.map); + if (rttMemPtr == NULL) { + return -ENODEV; + } + + *rttMemPtr_out = rttMemPtr; + *rttMemSz_out = rttMemSz; + return EOK; +} + + int rtt_init(void) { - if (RTT_ACTIVE_CNT == 0) { + if (RTT_CHANNEL_CNT == 0) { return EOK; } - /* Reserve memory for the descriptor and buffers */ - intptr_t startAddr = (RTT_ADDR - (RTT_ACTIVE_CNT * (RTT_TX_BUF_SIZE + RTT_RX_BUF_SIZE))) & ~(_PAGE_SIZE - 1); - size_t mapSize = RTT_ADDR + LIBRTT_DESC_SIZE - startAddr; - unsigned char *rttBuffer = mmap( - NULL, - mapSize, - PROT_WRITE | PROT_READ, - MAP_ANONYMOUS | MAP_UNCACHED | MAP_PHYSMEM, - -1, - startAddr); - - if (rttBuffer == MAP_FAILED) { - return -ENOMEM; + int doInit = 0; + void *rttMemPtr = NULL; + size_t rttMemSz = 0; + int ret = rtt_getMemInfo(&rttMemPtr, &rttMemSz); + if (ret != 0) { + return ret; } - int ret = librtt_init((void *)RTT_ADDR, NULL, NULL); + size_t bufSz = rttMemSz - LIBRTT_DESC_SIZE; + void *cbAddr = rttMemPtr + bufSz; + ret = librtt_verify( + cbAddr, + LIBRTT_DESC_SIZE, + rttMemPtr, + bufSz, + NULL, + NULL); if (ret != 0) { - librtt_done(); - munmap(rttBuffer, mapSize); - return ret; + doInit = 1; + ret = librtt_init(cbAddr, NULL, NULL); + if (ret != 0) { + return ret; + } } - unsigned char *buf = rttBuffer; - for (int i = 0, chn = 0; chn < RTT_CHANNEL_CNT; ++chn) { + unsigned char *buf = (doInit != 0) ? rttMemPtr : NULL; + unsigned char *nextBuf = buf; + for (int i = 0, chn = 0; chn < RTT_CHANNEL_CNT; chn++, buf = nextBuf) { if (rttConfig[chn] == 0) { continue; } rtt_t *uart = &rtt_common.uarts[i++]; - int ret = rtt_initOne(uart, chn, buf); + if (buf != NULL) { + nextBuf = buf + RTT_TX_BUF_SIZE + RTT_RX_BUF_SIZE; + if ((nextBuf - (unsigned char *)rttMemPtr) > bufSz) { + break; + } + } + + ret = rtt_initOne(uart, chn, buf); if (ret != 0) { librtt_done(); - munmap(rttBuffer, mapSize); return ret; } - - buf += RTT_RX_BUF_SIZE + RTT_TX_BUF_SIZE; } - beginthread(rtt_thread, IMXRT_MULTI_PRIO, rtt_common.stack, sizeof(rtt_common.stack), NULL); + ret = beginthread(rtt_thread, IMXRT_MULTI_PRIO, rtt_common.stack, sizeof(rtt_common.stack), NULL); return ret; } From d974d1c8d897ac6c9a42584d48df945682086b33 Mon Sep 17 00:00:00 2001 From: Jacek Maksymowicz Date: Thu, 26 Sep 2024 18:45:13 +0200 Subject: [PATCH 6/7] imxrt-multi: Allow UART_CONSOLE_USER to be defined empty Rename RTT_CHANNEL_* to RTT* JIRA: RTOS-754 --- multi/imxrt-multi/config.h | 69 +++++++++++++++++++-------------- multi/imxrt-multi/imxrt-multi.c | 15 ++++--- multi/imxrt-multi/rtt.c | 16 ++++---- multi/imxrt-multi/uart.c | 4 +- 4 files changed, 58 insertions(+), 46 deletions(-) diff --git a/multi/imxrt-multi/config.h b/multi/imxrt-multi/config.h index 5f1c7f680..5eb5ceb3f 100644 --- a/multi/imxrt-multi/config.h +++ b/multi/imxrt-multi/config.h @@ -754,7 +754,7 @@ /* clang-format on */ -#if !defined(UART_CONSOLE) && !defined(RTT_CHANNEL_CONSOLE) +#ifndef UART_CONSOLE #if defined(__CPU_IMXRT105X) #define UART_CONSOLE 1 #elif defined(__CPU_IMXRT106X) @@ -766,54 +766,63 @@ #endif #endif -#if defined(UART_CONSOLE) -#if ISEMPTY(UART_CONSOLE) -#error "UART_CONSOLE must not be empty" -#elif UART_CONSOLE <= 0 +#if !ISEMPTY(UART_CONSOLE) +#if UART_CONSOLE <= 0 #error "Invalid value for UART_CONSOLE" #endif #endif +#if defined(UART_CONSOLE_USER) +#if !ISEMPTY(UART_CONSOLE_USER) +#if (UART_CONSOLE_USER <= 0) +#error "Invalid value for UART_CONSOLE_USER" +#endif +#endif +#else +#define UART_CONSOLE_USER UART_CONSOLE +#endif + /* RTT */ -#ifndef RTT_CHANNEL0 -#define RTT_CHANNEL0 0 -#elif !ISBOOLEAN(RTT_CHANNEL0) -#error "RTT_CHANNEL0 must have a value of 0, 1, or be undefined" +#ifndef RTT0 +#define RTT0 0 +#elif !ISBOOLEAN(RTT0) +#error "RTT0 must have a value of 0, 1, or be undefined" #endif -#ifndef RTT_CHANNEL1 -#define RTT_CHANNEL1 0 -#elif !ISBOOLEAN(RTT_CHANNEL1) -#error "RTT_CHANNEL1 must have a value of 0, 1, or be undefined" +#ifndef RTT1 +#define RTT1 0 +#elif !ISBOOLEAN(RTT1) +#error "RTT1 must have a value of 0, 1, or be undefined" #endif -#ifndef RTT_CHANNEL0_BLOCKING -#define RTT_CHANNEL0_BLOCKING 0 -#elif !ISBOOLEAN(RTT_CHANNEL0_BLOCKING) -#error "RTT_CHANNEL0_BLOCKING must have a value of 0, 1, or be undefined" +#ifndef RTT0_BLOCKING +#define RTT0_BLOCKING 0 +#elif !ISBOOLEAN(RTT0_BLOCKING) +#error "RTT0_BLOCKING must have a value of 0, 1, or be undefined" #endif -#ifndef RTT_CHANNEL1_BLOCKING -#define RTT_CHANNEL1_BLOCKING 0 -#elif !ISBOOLEAN(RTT_CHANNEL1_BLOCKING) -#error "RTT_CHANNEL1_BLOCKING must have a value of 0, 1, or be undefined" +#ifndef RTT1_BLOCKING +#define RTT1_BLOCKING 0 +#elif !ISBOOLEAN(RTT1_BLOCKING) +#error "RTT1_BLOCKING must have a value of 0, 1, or be undefined" #endif -#if defined(UART_CONSOLE) && defined(RTT_CHANNEL_CONSOLE) -#error "Console on UART and RTT not supported" -#elif defined(RTT_CHANNEL_CONSOLE) -#if ISEMPTY(RTT_CHANNEL_CONSOLE) -#error "RTT_CHANNEL_CONSOLE must not be empty" -#elif RTT_CHANNEL_CONSOLE < 0 -#error "Invalid value for RTT_CHANNEL_CONSOLE" +#ifndef RTT_CONSOLE_USER +#define RTT_CONSOLE_USER +#elif !ISEMPTY(RTT_CONSOLE_USER) +#if RTT_CONSOLE_USER < 0 +#error "Invalid value for RTT_CONSOLE_USER" #endif - -#define ONLY_RTT_CONSOLE #endif +#if !ISEMPTY(UART_CONSOLE_USER) && !ISEMPTY(RTT_CONSOLE_USER) +#error "Console on both UART and RTT not supported" +#elif ISEMPTY(UART_CONSOLE_USER) && ISEMPTY(RTT_CONSOLE_USER) +#error "Console must be either on UART or RTT" +#endif /* SPI */ diff --git a/multi/imxrt-multi/imxrt-multi.c b/multi/imxrt-multi/imxrt-multi.c index 3394290d5..75a586716 100644 --- a/multi/imxrt-multi/imxrt-multi.c +++ b/multi/imxrt-multi/imxrt-multi.c @@ -169,10 +169,13 @@ static void uart_dispatchMsg(msg_t *msg) switch (id) { case id_console: -#ifdef ONLY_RTT_CONSOLE - rtt_handleMsg(msg, RTT_CHANNEL_CONSOLE + id_rtt0); +#if !ISEMPTY(RTT_CONSOLE_USER) + rtt_handleMsg(msg, RTT_CONSOLE_USER + id_rtt0); +#elif !ISEMPTY(UART_CONSOLE_USER) + uart_handleMsg(msg, UART_CONSOLE_USER - 1 + id_uart1); #else - uart_handleMsg(msg, UART_CONSOLE - 1 + id_uart1); + /* TODO: Add support for no console */ + msg->o.err = -ENODEV; #endif break; @@ -347,13 +350,13 @@ static int createDevFiles(void) #endif -#if RTT_CHANNEL0 +#if RTT0 if (mkFile(&dir, id_rtt0, "rtt0", common.uart_port) < 0) { return -1; } #endif -#if RTT_CHANNEL1 +#if RTT1 if (mkFile(&dir, id_rtt1, "rtt1", common.uart_port) < 0) { return -1; } @@ -608,7 +611,7 @@ int main(void) oid.id = id_console; create_dev(&oid, _PATH_CONSOLE); -#ifdef ONLY_RTT_CONSOLE +#if !ISEMPTY(RTT_CONSOLE_USER) libklog_init(rtt_klogCblk); #else libklog_init(uart_klogCblk); diff --git a/multi/imxrt-multi/rtt.c b/multi/imxrt-multi/rtt.c index bc22a6fda..4464d1938 100644 --- a/multi/imxrt-multi/rtt.c +++ b/multi/imxrt-multi/rtt.c @@ -40,9 +40,9 @@ /* Doesn't need to be large, data will mostly be stored in RTT buffers */ #define TTY_BUF_SIZE 64 -#define RTT_CHANNEL0_POS 0 -#define RTT_CHANNEL1_POS (RTT_CHANNEL0_POS + RTT_CHANNEL0) -#define RTT_ACTIVE_CNT (RTT_CHANNEL0 + RTT_CHANNEL1) +#define RTT0_POS 0 +#define RTT1_POS (RTT0_POS + RTT0) +#define RTT_ACTIVE_CNT (RTT0 + RTT1) typedef struct rtt_s { int chn; @@ -57,13 +57,13 @@ static struct { } rtt_common; -static const int rttConfig[] = { RTT_CHANNEL0, RTT_CHANNEL1 }; +static const int rttConfig[] = { RTT0, RTT1 }; -static const int rttBlocking[] = { RTT_CHANNEL0_BLOCKING, RTT_CHANNEL1_BLOCKING }; +static const int rttBlocking[] = { RTT0_BLOCKING, RTT1_BLOCKING }; -static const int rttPos[] = { RTT_CHANNEL0_POS, RTT_CHANNEL1_POS }; +static const int rttPos[] = { RTT0_POS, RTT1_POS }; #define RTT_CHANNEL_CNT (sizeof(rttConfig) / sizeof(rttConfig[0])) @@ -255,8 +255,8 @@ int rtt_init(void) void rtt_klogCblk(const char *data, size_t size) { -#ifdef RTT_CHANNEL_CONSOLE - libtty_write(&rtt_common.uarts[rttPos[RTT_CHANNEL_CONSOLE]].tty_common, data, size, 0); +#if !ISEMPTY(RTT_CONSOLE_USER) + libtty_write(&rtt_common.uarts[rttPos[RTT_CONSOLE_USER]].tty_common, data, size, 0); #endif } diff --git a/multi/imxrt-multi/uart.c b/multi/imxrt-multi/uart.c index c27b78f07..e5f237ee1 100644 --- a/multi/imxrt-multi/uart.c +++ b/multi/imxrt-multi/uart.c @@ -772,8 +772,8 @@ static void uart_initPins(void) void uart_klogCblk(const char *data, size_t size) { -#ifdef UART_CONSOLE - libtty_write(&uart_common.uarts[uartPos[UART_CONSOLE - 1]].tty_common, data, size, 0); +#if !ISEMPTY(UART_CONSOLE_USER) + libtty_write(&uart_common.uarts[uartPos[UART_CONSOLE_USER - 1]].tty_common, data, size, 0); #endif } From 0dd1c94b15ff8eb0c88cac9438e5bae30c57d092 Mon Sep 17 00:00:00 2001 From: Jacek Maksymowicz Date: Wed, 25 Sep 2024 14:29:24 +0200 Subject: [PATCH 7/7] imxrt-multi: implement adaptive polling rate for RTT JIRA: RTOS-754 --- multi/imxrt-multi/rtt.c | 48 ++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/multi/imxrt-multi/rtt.c b/multi/imxrt-multi/rtt.c index 4464d1938..cf60cdf4d 100644 --- a/multi/imxrt-multi/rtt.c +++ b/multi/imxrt-multi/rtt.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -33,9 +34,11 @@ #define RTT_TX_BUF_SIZE 1024 #define RTT_RX_BUF_SIZE 256 -#define RTT_POLLING_RATE_MS 20 -#define RTT_NO_PICKUP_TIMEOUT_MS (2 * RTT_POLLING_RATE_MS) -#define RTT_RETRIES (RTT_NO_PICKUP_TIMEOUT_MS / RTT_POLLING_RATE_MS) +#define RTT_IDLE_TIMEOUT_US 1048576 +#define RTT_NO_PICKUP_TIMEOUT_US 131072 +#define RTT_RATE_IDLE_US 131072 +#define RTT_RATE_MAX_US 32768 +#define RTT_RATE_MIN_US 2048 /* Doesn't need to be large, data will mostly be stored in RTT buffers */ #define TTY_BUF_SIZE 64 @@ -77,10 +80,13 @@ static inline ssize_t rtt_txAvailMode(unsigned int chn) static void rtt_thread(void *arg) { - unsigned retries[RTT_ACTIVE_CNT]; - memset(retries, 0, sizeof(retries)); + int timeout[RTT_ACTIVE_CNT]; + memset(timeout, 0, sizeof(timeout)); + int pollingRate = RTT_RATE_MAX_US; + int idleTimeout = 0; for (;;) { + unsigned chnsIdle = 0; for (int chn_idx = 0; chn_idx < RTT_ACTIVE_CNT; chn_idx++) { rtt_t *uart = &rtt_common.uarts[chn_idx]; unsigned char data; @@ -92,19 +98,19 @@ static void rtt_thread(void *arg) /* Do nothing, in this case the remaining code is unnecessary */ } else if (librtt_txCheckReaderAttached(uart->chn) != 0) { - retries[chn_idx] = RTT_RETRIES; + timeout[chn_idx] = RTT_NO_PICKUP_TIMEOUT_US; } else if (onTx == 0) { - if (retries[chn_idx] == 0) { + if (timeout[chn_idx] == 0) { onTx = 1; } else { - retries[chn_idx]--; + timeout[chn_idx] = max(0, timeout[chn_idx] - pollingRate); } } - if ((onRx == 0) && ((txReady == 0) || (onTx == 0))) { + chnsIdle++; continue; } @@ -116,21 +122,39 @@ static void rtt_thread(void *arg) onRx = librtt_rxAvail(uart->chn); } - while (onTx > 0 && txReady) { + while ((onTx > 0) && (txReady != 0)) { data = libtty_getchar(&uart->tty_common, NULL); ssize_t written = librtt_write(uart->chn, &data, 1, 0); if (written <= 0) { uart->diag_txSkipped++; } - onTx = rtt_txAvailMode(uart->chn); + onTx = (timeout[chn_idx] == 0) ? 1 : rtt_txAvailMode(uart->chn); txReady = libtty_txready(&uart->tty_common); } mutexUnlock(uart->lock); } - usleep(RTT_POLLING_RATE_MS * 1000); + if (chnsIdle == RTT_ACTIVE_CNT) { + if (idleTimeout == 0) { + pollingRate = RTT_RATE_IDLE_US; + } + else { + idleTimeout = max(0, idleTimeout - pollingRate); + pollingRate = min(RTT_RATE_MAX_US, (pollingRate * 3) / 2); + } + } + else { + if (idleTimeout == 0) { + pollingRate = RTT_RATE_MAX_US; + } + + idleTimeout = RTT_IDLE_TIMEOUT_US; + pollingRate = max(RTT_RATE_MIN_US, pollingRate / 2); + } + + usleep(pollingRate); } }