diff --git a/librtt/Makefile b/librtt/Makefile new file mode 100644 index 00000000..86859e64 --- /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 := librtt.c +LOCAL_HEADERS := librtt.h + +include $(static-lib.mk) diff --git a/librtt/librtt.c b/librtt/librtt.c new file mode 100644 index 00000000..4e01bb7f --- /dev/null +++ b/librtt/librtt.c @@ -0,0 +1,429 @@ +/* + * 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 "librtt.h" + +#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; + volatile 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 channel[]; +}; + + +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; + librtt_cacheOp_t invalFn; + librtt_cacheOp_t cleanFn; + unsigned int lastRd[LIBRTT_TXCHANNELS]; +} librtt_common = { 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)) { + return; + } + + if (wr < rd) { + op((void *)(buf + rd), sz - rd); + op((void *)buf, wr + 1); + } + else { + op((void *)(buf + rd), wr - rd + 1); + } +} + + +int librtt_checkTx(unsigned int ch) +{ + if ((librtt_common.rtt == NULL) || (ch >= librtt_common.rtt->txChannels) || (ch >= LIBRTT_TXCHANNELS)) { + return -ENODEV; + } + + return 0; +} + + +int librtt_checkRx(unsigned int ch) +{ + if ((librtt_common.rtt == NULL) || (ch >= librtt_common.rtt->rxChannels) || (ch >= LIBRTT_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_checkRx(ch) < 0) { + return -ENODEV; + } + + dataMemoryBarrier(); + ch += rtt->txChannels; + volatile unsigned char *srcBuf = rtt->channel[ch].ptr; + unsigned char *dstBuf = (unsigned char *)buf; + 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, (void *)srcBuf, sz + 1, rd, wr); + while ((todo != 0) && (rd != wr)) { + *dstBuf++ = srcBuf[rd]; + rd = (rd + 1) & sz; + todo--; + } + + dataMemoryBarrier(); + + rtt->channel[ch].rd = rd; + + return count - todo; +} + + +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_checkTx(ch) < 0) { + return -ENODEV; + } + + dataMemoryBarrier(); + + const unsigned char *srcBuf = (const unsigned char *)buf; + 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)) { + dstBuf[wr] = *srcBuf++; + wr = (wr + 1) & sz; + todo--; + } + + 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(); + + rtt->channel[ch].wr = wr; + + return count - todo; +} + + +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->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); + } + else { + return rd - wr; + } +} + + +void librtt_rxReset(unsigned int ch) +{ + dataMemoryBarrier(); + 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(unsigned int ch) +{ + dataMemoryBarrier(); + if (librtt_checkTx(ch) < 0) { + return; + } + + librtt_common.rtt->channel[ch].wr = librtt_common.rtt->channel[ch].rd; + dataMemoryBarrier(); +} + + +int librtt_txCheckReaderAttached(unsigned int ch) +{ + if (librtt_checkTx(ch) < 0) { + return 0; + } + + unsigned int rd = librtt_common.rtt->channel[ch].rd; + if (librtt_common.lastRd[ch] != rd) { + librtt_common.lastRd[ch] = rd; + return 1; + } + + return 0; +} + + +static int librtt_verifyChannel(volatile struct rtt_desc *rtt, unsigned int ch, unsigned char *buffers, size_t buffersSize) +{ + 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; + } + + 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; +} + + +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) { + 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; + } + } + + 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 (int 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; + } + + /* Check buffer size is non-zero and power of 2 */ + if ((sz == 0) || ((sz & (sz - 1)) != 0)) { + return -EINVAL; + } + + const char *name = NULL; + if (isTx != 0) { + if ((ch >= LIBRTT_TXCHANNELS) || (ch >= rtt->txChannels)) { + return -EINVAL; + } + + 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; + } + + 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; +} + + +void librtt_done(void) +{ + volatile struct rtt_desc *rtt = librtt_common.rtt; + + if (rtt != NULL) { + memset((void *)rtt, 0, sizeof(*rtt)); + librtt_common.rtt = NULL; + } +} diff --git a/librtt/librtt.h b/librtt/librtt.h new file mode 100644 index 00000000..000ce520 --- /dev/null +++ b/librtt/librtt.h @@ -0,0 +1,77 @@ +/* + * 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); + + +/* 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); + + +/* 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 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(unsigned int ch, void *buf, size_t count); + + +/* Non-blocking write to channel */ +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(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(unsigned int ch); + + +/* Reset tx fifo pointers */ +void librtt_txReset(unsigned int ch); + + +#endif /* end of LIBRTT_H */ diff --git a/multi/imxrt-multi/Makefile b/multi/imxrt-multi/Makefile index f970cdc2..3f0422e5 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 26b06c6e..5eb5ceb3 100644 --- a/multi/imxrt-multi/config.h +++ b/multi/imxrt-multi/config.h @@ -766,6 +766,63 @@ #endif #endif +#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 RTT0 +#define RTT0 0 +#elif !ISBOOLEAN(RTT0) +#error "RTT0 must have a value of 0, 1, or be undefined" +#endif + +#ifndef RTT1 +#define RTT1 0 +#elif !ISBOOLEAN(RTT1) +#error "RTT1 must have a value of 0, 1, or be undefined" +#endif + +#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 RTT1_BLOCKING +#define RTT1_BLOCKING 0 +#elif !ISBOOLEAN(RTT1_BLOCKING) +#error "RTT1_BLOCKING must have a value of 0, 1, or be undefined" +#endif + + +#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 +#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 d3691cef..75a58671 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,14 @@ static void uart_dispatchMsg(msg_t *msg) switch (id) { case id_console: - uart_handleMsg(msg, UART_CONSOLE - 1 + id_uart1); +#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 + /* TODO: Add support for no console */ + msg->o.err = -ENODEV; +#endif break; case id_uart1: @@ -191,6 +199,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 +348,18 @@ static int createDevFiles(void) } #endif +#endif + +#if RTT0 + if (mkFile(&dir, id_rtt0, "rtt0", common.uart_port) < 0) { + return -1; + } +#endif + +#if RTT1 + if (mkFile(&dir, id_rtt1, "rtt1", common.uart_port) < 0) { + return -1; + } #endif /* GPIOs */ @@ -577,6 +602,7 @@ int main(void) #endif uart_init(); + rtt_init(); gpio_init(); spi_init(); i2c_init(); @@ -585,7 +611,11 @@ int main(void) oid.id = id_console; create_dev(&oid, _PATH_CONSOLE); +#if !ISEMPTY(RTT_CONSOLE_USER) + 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 13f768d2..ac954cbc 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 00000000..cf60cdf4 --- /dev/null +++ b/multi/imxrt-multi/rtt.c @@ -0,0 +1,336 @@ +/* + * 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 + +#include "common.h" +#include "rtt.h" + + +#ifndef RTT_SYSPAGE_MAP_NAME +#define RTT_SYSPAGE_MAP_NAME "rtt" +#endif + +#define RTT_TX_BUF_SIZE 1024 +#define RTT_RX_BUF_SIZE 256 +#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 + +#define RTT0_POS 0 +#define RTT1_POS (RTT0_POS + RTT0) +#define RTT_ACTIVE_CNT (RTT0 + RTT1) + +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[] = { RTT0, RTT1 }; + + +static const int rttBlocking[] = { RTT0_BLOCKING, RTT1_BLOCKING }; + + +static const int rttPos[] = { RTT0_POS, RTT1_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) +{ + 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; + 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) { + timeout[chn_idx] = RTT_NO_PICKUP_TIMEOUT_US; + } + else if (onTx == 0) { + if (timeout[chn_idx] == 0) { + onTx = 1; + } + else { + timeout[chn_idx] = max(0, timeout[chn_idx] - pollingRate); + } + } + + if ((onRx == 0) && ((txReady == 0) || (onTx == 0))) { + chnsIdle++; + 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 != 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 = (timeout[chn_idx] == 0) ? 1 : rtt_txAvailMode(uart->chn); + txReady = libtty_txready(&uart->tty_common); + } + + mutexUnlock(uart->lock); + } + + 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); + } +} + + +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; + 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; + + return ret; +} + + +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_CHANNEL_CNT == 0) { + return EOK; + } + + int doInit = 0; + void *rttMemPtr = NULL; + size_t rttMemSz = 0; + int ret = rtt_getMemInfo(&rttMemPtr, &rttMemSz); + if (ret != 0) { + return ret; + } + + 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) { + doInit = 1; + ret = librtt_init(cbAddr, NULL, NULL); + if (ret != 0) { + return ret; + } + } + + 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++]; + 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(); + return ret; + } + } + + ret = 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) +{ +#if !ISEMPTY(RTT_CONSOLE_USER) + libtty_write(&rtt_common.uarts[rttPos[RTT_CONSOLE_USER]].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 00000000..488d2770 --- /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 2eead088..e5f237ee 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); +#if !ISEMPTY(UART_CONSOLE_USER) + libtty_write(&uart_common.uarts[uartPos[UART_CONSOLE_USER - 1]].tty_common, data, size, 0); +#endif }