diff --git a/.devcontainer.json b/.devcontainer.json index 1425cfd3..326f2425 100644 --- a/.devcontainer.json +++ b/.devcontainer.json @@ -3,10 +3,17 @@ "customizations": { "vscode": { "extensions": [ - "ms-vscode.cpptools" + "ms-vscode.cpptools", + "marus25.cortex-debug" ] } }, + "features": { + "ghcr.io/devcontainers/features/common-utils:2": { + "configureZshAsDefaultShell": true + } + }, + "postCreateCommand": "zsh -c '. ~/.oh-my-zsh/lib/cli.zsh && omz theme set frontcube'", "runArgs": [ // Ensure our workspace gets mounted under the non-root user (podman) "--userns=keep-id:uid=1000,gid=1000", @@ -14,4 +21,4 @@ "--security-opt", "label=disable" ] -} +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 7743e8d9..033427d4 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,13 +6,30 @@ "type": "cortex-debug", "request": "launch", "servertype": "openocd", + "configFiles": [ + "ut-robomaster/openocd.cfg" + ], "cwd": "${workspaceRoot}", - "preLaunchTask": "Flash - Debug", - "executable": "./ut-robomaster/build/hardware/scons-debug/ut-robomaster.elf", + "preLaunchTask": "Build - Debug", + "executable": "ut-robomaster/build/hardware/scons-debug/ut-robomaster.elf", "device": "STM32F427II", - "configFiles": [ - "./ut-robomaster/openocd.cfg" - ] - } + "liveWatch": { + "enabled": true, + "samplesPerSecond": 10 + }, + "rttConfig": { + "enabled": true, + "address": "auto", + "decoders": [ + { + "port": 0, + "type": "console" + } + ] + }, + "postResetCommands": [ + "monitor rtt start" + ], + }, ] } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index b0bda71b..63a8f9d8 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -74,12 +74,16 @@ "SConscript": "python", "stop_token": "cpp", "cassert": "cpp", + "string.h": "c", "bit": "cpp", "compare": "cpp", "concepts": "cpp", "numbers": "cpp", "ranges": "cpp", - "span": "cpp" + "span": "cpp", + "stdlib.h": "c", + "stdarg.h": "c", + "reent.h": "c" }, "C_Cpp.errorSquiggles": "enabled", "C_Cpp.default.includePath": [ @@ -98,5 +102,7 @@ "editor.rulers": [ 100 ] - } + }, + "remote.autoForwardPorts": false, + "cortex-debug.variableUseNaturalFormat": true, } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 1aa1b4e7..b689953a 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -18,30 +18,26 @@ { "label": "Build - Release", "type": "shell", - "command": "scons build robot=${input:robot} ", + "command": "scons build robot=${input:robot}", "group": "build", "options": { "cwd": "${workspaceRoot}/ut-robomaster" } }, { - "label": "Flash - Debug", + "label": "Connect to Remote Debugger", "type": "shell", - "command": "scons run robot=${input:robot} profile=debug profiling=true", - "group": "build", - "options": { - "cwd": "${workspaceRoot}/ut-robomaster" + "command": "ssh -L 7184:localhost:7184 ${input:debug_dest}", + "problemMatcher": [], + "isBackground": true, + "presentation": { + "echo": true, + "focus": true, + "panel": "dedicated", + "showReuseMessage": false, + "clear": false } - }, - { - "label": "Flash - Release", - "type": "shell", - "command": "scons run robot=${input:robot}", - "group": "build", - "options": { - "cwd": "${workspaceRoot}/ut-robomaster" - } - }, + } ], "inputs": [ { @@ -55,5 +51,11 @@ ], "default": "standard" }, + { + "id": "debug_dest", + "description": "Remote destination (SSH):", + "type": "promptString", + "default": "" + }, ] } \ No newline at end of file diff --git a/Containerfile b/Containerfile index e0053395..469ad9d0 100644 --- a/Containerfile +++ b/Containerfile @@ -11,16 +11,12 @@ RUN apt-get update -qq \ && rm -rf /var/lib/apt/lists/* RUN ARCH=$(uname -m) \ - URL=https://developer.arm.com/-/media/Files/downloads/gnu-rm/${ARM_GCC_VERSION}/gcc-arm-none-eabi-${ARM_GCC_VERSION}-${ARCH}-linux.tar.bz2 \ - && wget -qO- $URL | tar xj \ - && mv gcc-arm-none-eabi-${ARM_GCC_VERSION} gcc-arm + URL="https://developer.arm.com/-/media/Files/downloads/gnu-rm/${ARM_GCC_VERSION}/gcc-arm-none-eabi-${ARM_GCC_VERSION}-${ARCH}-linux.tar.bz2" \ + && mkdir gcc-arm \ + && wget -qO- "$URL" | tar xj --strip-components=1 -C gcc-arm # Main stage -FROM ubuntu:22.04 - -ARG USERNAME=dev -ARG USER_UID=1000 -ARG USER_GID=$USER_UID +FROM ubuntu:24.04 COPY --from=gcc-arm /gcc-arm /gcc-arm ENV PATH="/gcc-arm/bin:$PATH" @@ -30,21 +26,21 @@ RUN apt-get update -qq \ bash-completion \ doxygen \ git \ - libncurses5 \ + libncurses6 \ nano \ openocd \ + openssh-client \ python3-pip \ - scons \ + python-is-python3 \ sudo \ && rm -rf /var/lib/apt/lists/* -# Setup non-root user -RUN groupadd --gid $USER_GID $USERNAME \ - && useradd --uid $USER_UID --gid $USER_GID -m $USERNAME -s /usr/bin/bash \ - && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \ - && chmod 0440 /etc/sudoers.d/$USERNAME -WORKDIR /home/$USERNAME -USER $USERNAME +# Create symlinks for old GCC compilers +RUN cd /usr/lib/x86_64-linux-gnu \ + && ln -s libncurses.so.6.4 libncurses.so.5 \ + && ln -s libtinfo.so.6.4 libtinfo.so.5 # Install tools (user-space) -RUN pip3 install lbuild pyelftools modm +USER ubuntu +# --break-system-packages is fine because we are not installing these through apt +RUN pip3 install lbuild pyelftools modm scons==3.1.2 --break-system-packages \ No newline at end of file diff --git a/ut-robomaster/SConstruct b/ut-robomaster/SConstruct index 8b28903b..3828cbb7 100644 --- a/ut-robomaster/SConstruct +++ b/ut-robomaster/SConstruct @@ -24,6 +24,10 @@ IGNORED_FILES_WHILE_TESTING = ["src/main.cpp"] # Parse and validate arguments args = parse_args.parse_args() +c_flags = [args["ROBOT_TYPE"]] + +if args["DEMO_MODE"] == "true": + c_flags.append("DEMO_MODE") def _get_hosted_target_name_for_current_platform(): @@ -59,7 +63,7 @@ sources = [] # Building all libraries (read from sconscript files located in provided dirs) # Ensure that modm is first, since Taproot depends on modm # Append include path to environment so both src/test environments have access to them -env.SConscript(dirs=[TAPROOT_PATH, SRC_PATH, TEST_PATH], exports=["env", "args", "sources"]) +env.SConscript(dirs=[TAPROOT_PATH, SRC_PATH, TEST_PATH], exports=["env", "args", "c_flags", "sources"]) # Tests must be included as sources (rather than built as a separate library) in order for @@ -70,7 +74,7 @@ if args["TARGET_ENV"] == "tests": print("Configured {0} parallel build jobs (-j{0}), {1}" - .format(GetOption("num_jobs"), args["ROBOT_TYPE"])) + .format(GetOption("num_jobs"), c_flags)) if args["TARGET_ENV"] == "hardware": diff --git a/ut-robomaster/build_tools/parse_args.py b/ut-robomaster/build_tools/parse_args.py index 39c07b59..25e021ad 100644 --- a/ut-robomaster/build_tools/parse_args.py +++ b/ut-robomaster/build_tools/parse_args.py @@ -6,12 +6,12 @@ SIM_BUILD_TARGET_ACCEPTED_ARGS = ["build-sim", "run-sim"] HARDWARE_BUILD_TARGET_ACCEPTED_ARGS = ["build", "run", "size", "gdb", "all"] VALID_BUILD_PROFILES = ["debug", "release", "fast"] -VALID_PROFILING_TYPES = ["true", "false"] +VALID_BOOL_TYPES = ["true", "false"] ROBOT_TYPE_DEFINES = {"standard": "TARGET_STANDARD", "hero": "TARGET_HERO", "sentry": "TARGET_SENTRY"} -USAGE = "Usage: scons robot= [profile=] [profiling=]\n\ +USAGE = "Usage: scons robot= [profile=] [profiling=] [demo=]\n\ \"\" is one of:\n\ - \"build\": build all code for the hardware platform.\n\ - \"run\": build all code for the hardware platform, and deploy it to the board via a connected ST-Link.\n\ @@ -32,6 +32,7 @@ def parse_args(): "BUILD_PROFILE": "", "PROFILING": "", "ROBOT_TYPE": "", + "DEMO_MODE": "", } if len(COMMAND_LINE_TARGETS) > CMD_LINE_ARGS: throw_error("You entered too many arguments.") @@ -68,7 +69,11 @@ def parse_args(): throw_error("You specified an invalid build profile.") args["PROFILING"] = ARGUMENTS.get("profiling", "false") - if args["PROFILING"] not in VALID_PROFILING_TYPES: - throw_error("You specified an invalid profiling type.") + if args["PROFILING"] not in VALID_BOOL_TYPES: + throw_error("You specified an invalid profiling setting.") + + args["DEMO_MODE"] = ARGUMENTS.get("demo", "false") + if args["DEMO_MODE"] not in VALID_BOOL_TYPES: + throw_error("You specified an invalid demo setting.") return args diff --git a/ut-robomaster/openocd.cfg b/ut-robomaster/openocd.cfg index e30c26a4..b95836bc 100644 --- a/ut-robomaster/openocd.cfg +++ b/ut-robomaster/openocd.cfg @@ -1,4 +1,5 @@ source [find interface/stlink.cfg] +hla_stlink_backend tcp 7184 transport select hla_swd @@ -9,3 +10,5 @@ source [find target/stm32f4x.cfg] reset_config none +# bindto 0.0.0.0 +# gdb_port 3333 diff --git a/ut-robomaster/src/SConscript b/ut-robomaster/src/SConscript index b9282cd7..1a14f96b 100644 --- a/ut-robomaster/src/SConscript +++ b/ut-robomaster/src/SConscript @@ -2,6 +2,7 @@ from os.path import abspath Import("env") Import("args") +Import("c_flags") Import("sources") @@ -16,8 +17,8 @@ if args["TARGET_ENV"] == "tests": env_cpy = env.Clone() -# Append on the global robot target build flag -env_cpy.AppendUnique(CCFLAGS=["-D " + args["ROBOT_TYPE"]]) +# Append global build flags +env_cpy.AppendUnique(CCFLAGS=[f"-D {x}" for x in c_flags]) ignored_files.append("main_src_not_compiled.cpp") rawSrcs = env_cpy.FindSourceFiles(".", ignorePaths=ignored_dirs, ignoreFiles=ignored_files) diff --git a/ut-robomaster/src/communication/rtt.hpp b/ut-robomaster/src/communication/rtt.hpp new file mode 100644 index 00000000..69777bc6 --- /dev/null +++ b/ut-robomaster/src/communication/rtt.hpp @@ -0,0 +1,17 @@ +#include + +#include "rtt/SEGGER_RTT.h" + +int printf_rtt(const char* fmt, ...) +{ + int r; + char data[64]; + va_list params; + + va_start(params, fmt); + r = vsnprintf(data, 64, fmt, params); + va_end(params); + + SEGGER_RTT_Write(0, data, r); + return r; +} \ No newline at end of file diff --git a/ut-robomaster/src/communication/rtt/LICENSE.md b/ut-robomaster/src/communication/rtt/LICENSE.md new file mode 100644 index 00000000..14881c29 --- /dev/null +++ b/ut-robomaster/src/communication/rtt/LICENSE.md @@ -0,0 +1,36 @@ + + SEGGER Microcontroller GmbH + The Embedded Experts + + (c) 1995 - 2021 SEGGER Microcontroller GmbH + www.segger.com Support: support@segger.com + + SEGGER RTT Real Time Transfer for embedded targets + + + All rights reserved. + + SEGGER strongly recommends to not make any changes + to or modify the source code of this software in order to stay + compatible with the RTT protocol and J-Link. + + Redistribution and use in source and binary forms, with or + without modification, are permitted provided that the following + condition is met: + + - Redistributions of source code must retain the above copyright + notice, this condition and the following disclaimer. + + 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 SEGGER Microcontroller 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. diff --git a/ut-robomaster/src/communication/rtt/SEGGER_RTT.c b/ut-robomaster/src/communication/rtt/SEGGER_RTT.c new file mode 100644 index 00000000..11138ea4 --- /dev/null +++ b/ut-robomaster/src/communication/rtt/SEGGER_RTT.c @@ -0,0 +1,2437 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2019 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER RTT * Real Time Transfer for embedded targets * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the RTT protocol and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* 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 SEGGER Microcontroller 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. * +* * +********************************************************************** +---------------------------END-OF-HEADER------------------------------ +File : SEGGER_RTT.c +Purpose : Implementation of SEGGER real-time transfer (RTT) which + allows real-time communication on targets which support + debugger memory accesses while the CPU is running. +Revision: $Rev: 29668 $ + +Additional information: + Type "int" is assumed to be 32-bits in size + H->T Host to target communication + T->H Target to host communication + + RTT channel 0 is always present and reserved for Terminal usage. + Name is fixed to "Terminal" + + Effective buffer size: SizeOfBuffer - 1 + + WrOff == RdOff: Buffer is empty + WrOff == (RdOff - 1): Buffer is full + WrOff > RdOff: Free space includes wrap-around + WrOff < RdOff: Used space includes wrap-around + (WrOff == (SizeOfBuffer - 1)) && (RdOff == 0): + Buffer full and wrap-around after next byte + + +---------------------------------------------------------------------- +*/ + +#include "SEGGER_RTT.h" + +#include // for memcpy + +/********************************************************************* + * + * Configuration, default values + * + ********************************************************************** + */ + +#if SEGGER_RTT_CPU_CACHE_LINE_SIZE +#ifdef SEGGER_RTT_CB_ALIGN +#error "Custom SEGGER_RTT_CB_ALIGN() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" +#endif +#ifdef SEGGER_RTT_BUFFER_ALIGN +#error "Custom SEGGER_RTT_BUFFER_ALIGN() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" +#endif +#ifdef SEGGER_RTT_PUT_CB_SECTION +#error "Custom SEGGER_RTT_PUT_CB_SECTION() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" +#endif +#ifdef SEGGER_RTT_PUT_BUFFER_SECTION +#error \ + "Custom SEGGER_RTT_PUT_BUFFER_SECTION() is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" +#endif +#ifdef SEGGER_RTT_BUFFER_ALIGNMENT +#error "Custom SEGGER_RTT_BUFFER_ALIGNMENT is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" +#endif +#ifdef SEGGER_RTT_ALIGNMENT +#error "Custom SEGGER_RTT_ALIGNMENT is not supported for SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" +#endif +#endif + +#ifndef BUFFER_SIZE_UP +#define BUFFER_SIZE_UP 1024 // Size of the buffer for terminal output of target, up to host +#endif + +#ifndef BUFFER_SIZE_DOWN +#define BUFFER_SIZE_DOWN \ + 16 // Size of the buffer for terminal input to target from host (Usually keyboard input) +#endif + +#ifndef SEGGER_RTT_MAX_NUM_UP_BUFFERS +#define SEGGER_RTT_MAX_NUM_UP_BUFFERS 2 // Number of up-buffers (T->H) available on this target +#endif + +#ifndef SEGGER_RTT_MAX_NUM_DOWN_BUFFERS +#define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS 2 // Number of down-buffers (H->T) available on this target +#endif + +#ifndef SEGGER_RTT_BUFFER_SECTION +#if defined(SEGGER_RTT_SECTION) +#define SEGGER_RTT_BUFFER_SECTION SEGGER_RTT_SECTION +#endif +#endif + +#ifndef SEGGER_RTT_ALIGNMENT +#define SEGGER_RTT_ALIGNMENT SEGGER_RTT_CPU_CACHE_LINE_SIZE +#endif + +#ifndef SEGGER_RTT_BUFFER_ALIGNMENT +#define SEGGER_RTT_BUFFER_ALIGNMENT SEGGER_RTT_CPU_CACHE_LINE_SIZE +#endif + +#ifndef SEGGER_RTT_MODE_DEFAULT +#define SEGGER_RTT_MODE_DEFAULT SEGGER_RTT_MODE_NO_BLOCK_SKIP +#endif + +#ifndef SEGGER_RTT_LOCK +#define SEGGER_RTT_LOCK() +#endif + +#ifndef SEGGER_RTT_UNLOCK +#define SEGGER_RTT_UNLOCK() +#endif + +#ifndef STRLEN +#define STRLEN(a) strlen((a)) +#endif + +#ifndef STRCPY +#define STRCPY(pDest, pSrc) strcpy((pDest), (pSrc)) +#endif + +#ifndef SEGGER_RTT_MEMCPY_USE_BYTELOOP +#define SEGGER_RTT_MEMCPY_USE_BYTELOOP 0 +#endif + +#ifndef SEGGER_RTT_MEMCPY +#ifdef MEMCPY +#define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) MEMCPY((pDest), (pSrc), (NumBytes)) +#else +#define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) memcpy((pDest), (pSrc), (NumBytes)) +#endif +#endif + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +/********************************************************************* + * + * Defines, fixed + * + ********************************************************************** + */ +#if (defined __ICCARM__) || (defined __ICCRX__) +#define RTT_PRAGMA(P) _Pragma(#P) +#endif + +#if SEGGER_RTT_ALIGNMENT || SEGGER_RTT_BUFFER_ALIGNMENT +#if ((defined __GNUC__) || (defined __clang__)) +#define SEGGER_RTT_ALIGN(Var, Alignment) Var __attribute__((aligned(Alignment))) +#elif (defined __ICCARM__) || (defined __ICCRX__) +#define PRAGMA(A) _Pragma(#A) +#define SEGGER_RTT_ALIGN(Var, Alignment) \ + RTT_PRAGMA(data_alignment = Alignment) \ + Var +#elif (defined __CC_ARM) +#define SEGGER_RTT_ALIGN(Var, Alignment) Var __attribute__((aligned(Alignment))) +#else +#error "Alignment not supported for this compiler." +#endif +#else +#define SEGGER_RTT_ALIGN(Var, Alignment) Var +#endif + +#if defined(SEGGER_RTT_SECTION) || defined(SEGGER_RTT_BUFFER_SECTION) +#if ((defined __GNUC__) || (defined __clang__)) +#define SEGGER_RTT_PUT_SECTION(Var, Section) __attribute__((section(Section))) Var +#elif (defined __ICCARM__) || (defined __ICCRX__) +#define SEGGER_RTT_PUT_SECTION(Var, Section) \ + RTT_PRAGMA(location = Section) \ + Var +#elif (defined __CC_ARM) +#define SEGGER_RTT_PUT_SECTION(Var, Section) __attribute__((section(Section), zero_init)) Var +#else +#error "Section placement not supported for this compiler." +#endif +#else +#define SEGGER_RTT_PUT_SECTION(Var, Section) Var +#endif + +#if SEGGER_RTT_ALIGNMENT +#define SEGGER_RTT_CB_ALIGN(Var) SEGGER_RTT_ALIGN(Var, SEGGER_RTT_ALIGNMENT) +#else +#define SEGGER_RTT_CB_ALIGN(Var) Var +#endif + +#if SEGGER_RTT_BUFFER_ALIGNMENT +#define SEGGER_RTT_BUFFER_ALIGN(Var) SEGGER_RTT_ALIGN(Var, SEGGER_RTT_BUFFER_ALIGNMENT) +#else +#define SEGGER_RTT_BUFFER_ALIGN(Var) Var +#endif + +#if defined(SEGGER_RTT_SECTION) +#define SEGGER_RTT_PUT_CB_SECTION(Var) SEGGER_RTT_PUT_SECTION(Var, SEGGER_RTT_SECTION) +#else +#define SEGGER_RTT_PUT_CB_SECTION(Var) Var +#endif + +#if defined(SEGGER_RTT_BUFFER_SECTION) +#define SEGGER_RTT_PUT_BUFFER_SECTION(Var) SEGGER_RTT_PUT_SECTION(Var, SEGGER_RTT_BUFFER_SECTION) +#else +#define SEGGER_RTT_PUT_BUFFER_SECTION(Var) Var +#endif + +/********************************************************************* + * + * Static const data + * + ********************************************************************** + */ + +static const unsigned char _aTerminalId[16] = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + +/********************************************************************* + * + * Static data + * + ********************************************************************** + */ + +// +// RTT Control Block and allocate buffers for channel 0 +// +#if SEGGER_RTT_CPU_CACHE_LINE_SIZE +#if ((defined __GNUC__) || (defined __clang__)) +SEGGER_RTT_CB _SEGGER_RTT __attribute__((aligned(SEGGER_RTT_CPU_CACHE_LINE_SIZE))); +static char _acUpBuffer[SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_UP)] + __attribute__((aligned(SEGGER_RTT_CPU_CACHE_LINE_SIZE))); +static char _acDownBuffer[SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_DOWN)] + __attribute__((aligned(SEGGER_RTT_CPU_CACHE_LINE_SIZE))); +#elif (defined __ICCARM__) +#pragma data_alignment = SEGGER_RTT_CPU_CACHE_LINE_SIZE +SEGGER_RTT_CB _SEGGER_RTT; +#pragma data_alignment = SEGGER_RTT_CPU_CACHE_LINE_SIZE +static char _acUpBuffer[SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_UP)]; +#pragma data_alignment = SEGGER_RTT_CPU_CACHE_LINE_SIZE +static char _acDownBuffer[SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(BUFFER_SIZE_DOWN)]; +#else +#error "Don't know how to place _SEGGER_RTT, _acUpBuffer, _acDownBuffer cache-line aligned" +#endif +#else +SEGGER_RTT_PUT_CB_SECTION(SEGGER_RTT_CB_ALIGN(SEGGER_RTT_CB _SEGGER_RTT)); +SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acUpBuffer[BUFFER_SIZE_UP])); +SEGGER_RTT_PUT_BUFFER_SECTION(SEGGER_RTT_BUFFER_ALIGN(static char _acDownBuffer[BUFFER_SIZE_DOWN])); +#endif + +static unsigned char _ActiveTerminal; + +/********************************************************************* + * + * Static functions + * + ********************************************************************** + */ + +/********************************************************************* + * + * _DoInit() + * + * Function description + * Initializes the control block an buffers. + * + * Notes + * (1) May only be called via INIT() to avoid overriding settings. + * The only exception is SEGGER_RTT_Init(), to make an intentional override possible. + */ +#define INIT() \ + do \ + { \ + volatile SEGGER_RTT_CB* pRTTCBInit; \ + pRTTCBInit = \ + (volatile SEGGER_RTT_CB*)((uintptr_t) & _SEGGER_RTT + SEGGER_RTT_UNCACHED_OFF); \ + if (pRTTCBInit->acID[0] != 'S') \ + { \ + _DoInit(); \ + } \ + } while (0) + +static void _DoInit(void) +{ + volatile SEGGER_RTT_CB* p; // Volatile to make sure that compiler cannot change the order of + // accesses to the control block + static const char _aInitStr[] = + "\0\0\0\0\0\0TTR REGGES"; // Init complete ID string to make sure that things also work if + // RTT is linked to a no-init memory area + unsigned i; + // + // Initialize control block + // + p = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + + SEGGER_RTT_UNCACHED_OFF); // Access control block uncached so + // that nothing in the cache ever + // becomes dirty and all changes are + // visible in HW directly + memset( + (SEGGER_RTT_CB*)p, + 0, + sizeof(_SEGGER_RTT)); // Make sure that the RTT CB is always zero initialized. + p->MaxNumUpBuffers = SEGGER_RTT_MAX_NUM_UP_BUFFERS; + p->MaxNumDownBuffers = SEGGER_RTT_MAX_NUM_DOWN_BUFFERS; + // + // Initialize up buffer 0 + // + p->aUp[0].sName = "Terminal"; + p->aUp[0].pBuffer = _acUpBuffer; + p->aUp[0].SizeOfBuffer = BUFFER_SIZE_UP; + p->aUp[0].RdOff = 0u; + p->aUp[0].WrOff = 0u; + p->aUp[0].Flags = SEGGER_RTT_MODE_DEFAULT; + // + // Initialize down buffer 0 + // + p->aDown[0].sName = "Terminal"; + p->aDown[0].pBuffer = _acDownBuffer; + p->aDown[0].SizeOfBuffer = BUFFER_SIZE_DOWN; + p->aDown[0].RdOff = 0u; + p->aDown[0].WrOff = 0u; + p->aDown[0].Flags = SEGGER_RTT_MODE_DEFAULT; + // + // Finish initialization of the control block. + // Copy Id string backwards to make sure that "SEGGER RTT" is not found in initializer memory + // (usually flash), as this would cause J-Link to "find" the control block at a wrong address. + // + RTT__DMB(); // Force order of memory accesses for cores that may perform out-of-order memory + // accesses + for (i = 0; i < sizeof(_aInitStr) - 1; ++i) + { + p->acID[i] = + _aInitStr[sizeof(_aInitStr) - 2 - i]; // Skip terminating \0 at the end of the array + } + RTT__DMB(); // Force order of memory accesses for cores that may perform out-of-order memory + // accesses +} + +/********************************************************************* + * + * _WriteBlocking() + * + * Function description + * Stores a specified number of characters in SEGGER RTT ring buffer + * and updates the associated write pointer which is periodically + * read by the host. + * The caller is responsible for managing the write chunk sizes as + * _WriteBlocking() will block until all data has been posted successfully. + * + * Parameters + * pRing Ring buffer to post to. + * pBuffer Pointer to character array. Does not need to point to a \0 terminated string. + * NumBytes Number of bytes to be stored in the SEGGER RTT control block. + * + * Return value + * >= 0 - Number of bytes written into buffer. + */ +static unsigned _WriteBlocking(SEGGER_RTT_BUFFER_UP* pRing, const char* pBuffer, unsigned NumBytes) +{ + unsigned NumBytesToWrite; + unsigned NumBytesWritten; + unsigned RdOff; + unsigned WrOff; + volatile char* pDst; + // + // Write data to buffer and handle wrap-around if necessary + // + NumBytesWritten = 0u; + WrOff = pRing->WrOff; + do + { + RdOff = pRing->RdOff; // May be changed by host (debug probe) in the meantime + if (RdOff > WrOff) + { + NumBytesToWrite = RdOff - WrOff - 1u; + } + else + { + NumBytesToWrite = pRing->SizeOfBuffer - (WrOff - RdOff + 1u); + } + NumBytesToWrite = + MIN(NumBytesToWrite, + (pRing->SizeOfBuffer - + WrOff)); // Number of bytes that can be written until buffer wrap-around + NumBytesToWrite = MIN(NumBytesToWrite, NumBytes); + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytesWritten += NumBytesToWrite; + NumBytes -= NumBytesToWrite; + WrOff += NumBytesToWrite; + while (NumBytesToWrite--) + { + *pDst++ = *pBuffer++; + }; +#else + SEGGER_RTT_MEMCPY((void*)pDst, pBuffer, NumBytesToWrite); + NumBytesWritten += NumBytesToWrite; + pBuffer += NumBytesToWrite; + NumBytes -= NumBytesToWrite; + WrOff += NumBytesToWrite; +#endif + if (WrOff == pRing->SizeOfBuffer) + { + WrOff = 0u; + } + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is + // allowed to change the order of memory accesses + pRing->WrOff = WrOff; + } while (NumBytes); + return NumBytesWritten; +} + +/********************************************************************* + * + * _WriteNoCheck() + * + * Function description + * Stores a specified number of characters in SEGGER RTT ring buffer + * and updates the associated write pointer which is periodically + * read by the host. + * It is callers responsibility to make sure data actually fits in buffer. + * + * Parameters + * pRing Ring buffer to post to. + * pBuffer Pointer to character array. Does not need to point to a \0 terminated string. + * NumBytes Number of bytes to be stored in the SEGGER RTT control block. + * + * Notes + * (1) If there might not be enough space in the "Up"-buffer, call _WriteBlocking + */ +static void _WriteNoCheck(SEGGER_RTT_BUFFER_UP* pRing, const char* pData, unsigned NumBytes) +{ + unsigned NumBytesAtOnce; + unsigned WrOff; + unsigned Rem; + volatile char* pDst; + + WrOff = pRing->WrOff; + Rem = pRing->SizeOfBuffer - WrOff; + if (Rem > NumBytes) + { + // + // All data fits before wrap around + // + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + WrOff += NumBytes; + while (NumBytes--) + { + *pDst++ = *pData++; + }; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is + // allowed to change the order of memory accesses + pRing->WrOff = WrOff; +#else + SEGGER_RTT_MEMCPY((void*)pDst, pData, NumBytes); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is + // allowed to change the order of memory accesses + pRing->WrOff = WrOff + NumBytes; +#endif + } + else + { + // + // We reach the end of the buffer, so need to wrap around + // +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; + NumBytesAtOnce = Rem; + while (NumBytesAtOnce--) + { + *pDst++ = *pData++; + }; + pDst = pRing->pBuffer + SEGGER_RTT_UNCACHED_OFF; + NumBytesAtOnce = NumBytes - Rem; + while (NumBytesAtOnce--) + { + *pDst++ = *pData++; + }; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is + // allowed to change the order of memory accesses + pRing->WrOff = NumBytes - Rem; +#else + NumBytesAtOnce = Rem; + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; + SEGGER_RTT_MEMCPY((void*)pDst, pData, NumBytesAtOnce); + NumBytesAtOnce = NumBytes - Rem; + pDst = pRing->pBuffer + SEGGER_RTT_UNCACHED_OFF; + SEGGER_RTT_MEMCPY((void*)pDst, pData + Rem, NumBytesAtOnce); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is + // allowed to change the order of memory accesses + pRing->WrOff = NumBytesAtOnce; +#endif + } +} + +/********************************************************************* + * + * _PostTerminalSwitch() + * + * Function description + * Switch terminal to the given terminal ID. It is the caller's + * responsibility to ensure the terminal ID is correct and there is + * enough space in the buffer for this to complete successfully. + * + * Parameters + * pRing Ring buffer to post to. + * TerminalId Terminal ID to switch to. + */ +static void _PostTerminalSwitch(SEGGER_RTT_BUFFER_UP* pRing, unsigned char TerminalId) +{ + unsigned char ac[2]; + + ac[0] = 0xFFu; + ac[1] = _aTerminalId[TerminalId]; // Caller made already sure that TerminalId does not exceed + // our terminal limit + _WriteBlocking(pRing, (const char*)ac, 2u); +} + +/********************************************************************* + * + * _GetAvailWriteSpace() + * + * Function description + * Returns the number of bytes that can be written to the ring + * buffer without blocking. + * + * Parameters + * pRing Ring buffer to check. + * + * Return value + * Number of bytes that are free in the buffer. + */ +static unsigned _GetAvailWriteSpace(SEGGER_RTT_BUFFER_UP* pRing) +{ + unsigned RdOff; + unsigned WrOff; + unsigned r; + // + // Avoid warnings regarding volatile access order. It's not a problem + // in this case, but dampen compiler enthusiasm. + // + RdOff = pRing->RdOff; + WrOff = pRing->WrOff; + if (RdOff <= WrOff) + { + r = pRing->SizeOfBuffer - 1u - WrOff + RdOff; + } + else + { + r = RdOff - WrOff - 1u; + } + return r; +} + +/********************************************************************* + * + * Public code + * + ********************************************************************** + */ + +/********************************************************************* + * + * SEGGER_RTT_ReadUpBufferNoLock() + * + * Function description + * Reads characters from SEGGER real-time-terminal control block + * which have been previously stored by the application. + * Do not lock against interrupts and multiple access. + * Used to do the same operation that J-Link does, to transfer + * RTT data via other channels, such as TCP/IP or UART. + * + * Parameters + * BufferIndex Index of Up-buffer to be used. + * pBuffer Pointer to buffer provided by target application, to copy characters from + * RTT-up-buffer to. BufferSize Size of the target application buffer. + * + * Return value + * Number of bytes that have been read. + * + * Additional information + * This function must not be called when J-Link might also do RTT. + */ +unsigned SEGGER_RTT_ReadUpBufferNoLock(unsigned BufferIndex, void* pData, unsigned BufferSize) +{ + unsigned NumBytesRem; + unsigned NumBytesRead; + unsigned RdOff; + unsigned WrOff; + unsigned char* pBuffer; + SEGGER_RTT_BUFFER_UP* pRing; + volatile char* pSrc; + + INIT(); + pRing = + (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see + // changes made by the J-Link side and + // all of our changes go into HW directly + pBuffer = (unsigned char*)pData; + RdOff = pRing->RdOff; + WrOff = pRing->WrOff; + NumBytesRead = 0u; + // + // Read from current read position to wrap-around of buffer, first + // + if (RdOff > WrOff) + { + NumBytesRem = pRing->SizeOfBuffer - RdOff; + NumBytesRem = MIN(NumBytesRem, BufferSize); + pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytesRead += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; + while (NumBytesRem--) + { + *pBuffer++ = *pSrc++; + }; +#else + SEGGER_RTT_MEMCPY(pBuffer, (void*)pSrc, NumBytesRem); + NumBytesRead += NumBytesRem; + pBuffer += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; +#endif + // + // Handle wrap-around of buffer + // + if (RdOff == pRing->SizeOfBuffer) + { + RdOff = 0u; + } + } + // + // Read remaining items of buffer + // + NumBytesRem = WrOff - RdOff; + NumBytesRem = MIN(NumBytesRem, BufferSize); + if (NumBytesRem > 0u) + { + pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytesRead += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; + while (NumBytesRem--) + { + *pBuffer++ = *pSrc++; + }; +#else + SEGGER_RTT_MEMCPY(pBuffer, (void*)pSrc, NumBytesRem); + NumBytesRead += NumBytesRem; + pBuffer += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; +#endif + } + // + // Update read offset of buffer + // + if (NumBytesRead) + { + pRing->RdOff = RdOff; + } + // + return NumBytesRead; +} + +/********************************************************************* + * + * SEGGER_RTT_ReadNoLock() + * + * Function description + * Reads characters from SEGGER real-time-terminal control block + * which have been previously stored by the host. + * Do not lock against interrupts and multiple access. + * + * Parameters + * BufferIndex Index of Down-buffer to be used (e.g. 0 for "Terminal"). + * pBuffer Pointer to buffer provided by target application, to copy characters from + * RTT-down-buffer to. BufferSize Size of the target application buffer. + * + * Return value + * Number of bytes that have been read. + */ +unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned BufferSize) +{ + unsigned NumBytesRem; + unsigned NumBytesRead; + unsigned RdOff; + unsigned WrOff; + unsigned char* pBuffer; + SEGGER_RTT_BUFFER_DOWN* pRing; + volatile char* pSrc; + // + INIT(); + pRing = (SEGGER_RTT_BUFFER_DOWN*)((uintptr_t)&_SEGGER_RTT.aDown[BufferIndex] + + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we + // see changes made by the J-Link + // side and all of our changes go + // into HW directly + pBuffer = (unsigned char*)pData; + RdOff = pRing->RdOff; + WrOff = pRing->WrOff; + NumBytesRead = 0u; + // + // Read from current read position to wrap-around of buffer, first + // + if (RdOff > WrOff) + { + NumBytesRem = pRing->SizeOfBuffer - RdOff; + NumBytesRem = MIN(NumBytesRem, BufferSize); + pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytesRead += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; + while (NumBytesRem--) + { + *pBuffer++ = *pSrc++; + }; +#else + SEGGER_RTT_MEMCPY(pBuffer, (void*)pSrc, NumBytesRem); + NumBytesRead += NumBytesRem; + pBuffer += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; +#endif + // + // Handle wrap-around of buffer + // + if (RdOff == pRing->SizeOfBuffer) + { + RdOff = 0u; + } + } + // + // Read remaining items of buffer + // + NumBytesRem = WrOff - RdOff; + NumBytesRem = MIN(NumBytesRem, BufferSize); + if (NumBytesRem > 0u) + { + pSrc = (pRing->pBuffer + RdOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytesRead += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; + while (NumBytesRem--) + { + *pBuffer++ = *pSrc++; + }; +#else + SEGGER_RTT_MEMCPY(pBuffer, (void*)pSrc, NumBytesRem); + NumBytesRead += NumBytesRem; + pBuffer += NumBytesRem; + BufferSize -= NumBytesRem; + RdOff += NumBytesRem; +#endif + } + if (NumBytesRead) + { + pRing->RdOff = RdOff; + } + // + return NumBytesRead; +} + +/********************************************************************* + * + * SEGGER_RTT_ReadUpBuffer + * + * Function description + * Reads characters from SEGGER real-time-terminal control block + * which have been previously stored by the application. + * Used to do the same operation that J-Link does, to transfer + * RTT data via other channels, such as TCP/IP or UART. + * + * Parameters + * BufferIndex Index of Up-buffer to be used. + * pBuffer Pointer to buffer provided by target application, to copy characters from + * RTT-up-buffer to. BufferSize Size of the target application buffer. + * + * Return value + * Number of bytes that have been read. + * + * Additional information + * This function must not be called when J-Link might also do RTT. + * This function locks against all other RTT operations. I.e. during + * the read operation, writing is also locked. + * If only one consumer reads from the up buffer, + * call sEGGER_RTT_ReadUpBufferNoLock() instead. + */ +unsigned SEGGER_RTT_ReadUpBuffer(unsigned BufferIndex, void* pBuffer, unsigned BufferSize) +{ + unsigned NumBytesRead; + + SEGGER_RTT_LOCK(); + // + // Call the non-locking read function + // + NumBytesRead = SEGGER_RTT_ReadUpBufferNoLock(BufferIndex, pBuffer, BufferSize); + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + // + return NumBytesRead; +} + +/********************************************************************* + * + * SEGGER_RTT_Read + * + * Function description + * Reads characters from SEGGER real-time-terminal control block + * which have been previously stored by the host. + * + * Parameters + * BufferIndex Index of Down-buffer to be used (e.g. 0 for "Terminal"). + * pBuffer Pointer to buffer provided by target application, to copy characters from + * RTT-down-buffer to. BufferSize Size of the target application buffer. + * + * Return value + * Number of bytes that have been read. + */ +unsigned SEGGER_RTT_Read(unsigned BufferIndex, void* pBuffer, unsigned BufferSize) +{ + unsigned NumBytesRead; + + SEGGER_RTT_LOCK(); + // + // Call the non-locking read function + // + NumBytesRead = SEGGER_RTT_ReadNoLock(BufferIndex, pBuffer, BufferSize); + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + // + return NumBytesRead; +} + +/********************************************************************* + * + * SEGGER_RTT_WriteWithOverwriteNoLock + * + * Function description + * Stores a specified number of characters in SEGGER RTT + * control block. + * SEGGER_RTT_WriteWithOverwriteNoLock does not lock the application + * and overwrites data if the data does not fit into the buffer. + * + * Parameters + * BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). + * pBuffer Pointer to character array. Does not need to point to a \0 terminated string. + * NumBytes Number of bytes to be stored in the SEGGER RTT control block. + * + * Notes + * (1) If there is not enough space in the "Up"-buffer, data is overwritten. + * (2) For performance reasons this function does not call Init() + * and may only be called after RTT has been initialized. + * Either by calling SEGGER_RTT_Init() or calling another RTT API function first. + * (3) Do not use SEGGER_RTT_WriteWithOverwriteNoLock if a J-Link + * connection reads RTT data. + */ +void SEGGER_RTT_WriteWithOverwriteNoLock( + unsigned BufferIndex, + const void* pBuffer, + unsigned NumBytes) +{ + const char* pData; + SEGGER_RTT_BUFFER_UP* pRing; + unsigned Avail; + volatile char* pDst; + // + // Get "to-host" ring buffer and copy some elements into local variables. + // + pData = (const char*)pBuffer; + pRing = + (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see + // changes made by the J-Link side and + // all of our changes go into HW directly + // + // Check if we will overwrite data and need to adjust the RdOff. + // + if (pRing->WrOff == pRing->RdOff) + { + Avail = pRing->SizeOfBuffer - 1u; + } + else if (pRing->WrOff < pRing->RdOff) + { + Avail = pRing->RdOff - pRing->WrOff - 1u; + } + else + { + Avail = pRing->RdOff - pRing->WrOff - 1u + pRing->SizeOfBuffer; + } + if (NumBytes > Avail) + { + pRing->RdOff += (NumBytes - Avail); + while (pRing->RdOff >= pRing->SizeOfBuffer) + { + pRing->RdOff -= pRing->SizeOfBuffer; + } + } + // + // Write all data, no need to check the RdOff, but possibly handle multiple wrap-arounds + // + Avail = pRing->SizeOfBuffer - pRing->WrOff; + do + { + if (Avail > NumBytes) + { + // + // Last round + // + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + Avail = NumBytes; + while (NumBytes--) + { + *pDst++ = *pData++; + }; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU + // is allowed to change the order of memory accesses + pRing->WrOff += Avail; +#else + SEGGER_RTT_MEMCPY((void*)pDst, pData, NumBytes); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU + // is allowed to change the order of memory accesses + pRing->WrOff += NumBytes; +#endif + break; + } + else + { + // + // Wrap-around necessary, write until wrap-around and reset WrOff + // + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; +#if SEGGER_RTT_MEMCPY_USE_BYTELOOP + NumBytes -= Avail; + while (Avail--) + { + *pDst++ = *pData++; + }; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU + // is allowed to change the order of memory accesses + pRing->WrOff = 0; +#else + SEGGER_RTT_MEMCPY((void*)pDst, pData, Avail); + pData += Avail; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU + // is allowed to change the order of memory accesses + pRing->WrOff = 0; + NumBytes -= Avail; +#endif + Avail = (pRing->SizeOfBuffer - 1); + } + } while (NumBytes); +} + +/********************************************************************* + * + * SEGGER_RTT_WriteSkipNoLock + * + * Function description + * Stores a specified number of characters in SEGGER RTT + * control block which is then read by the host. + * SEGGER_RTT_WriteSkipNoLock does not lock the application and + * skips all data, if the data does not fit into the buffer. + * + * Parameters + * BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). + * pBuffer Pointer to character array. Does not need to point to a \0 terminated string. + * NumBytes Number of bytes to be stored in the SEGGER RTT control block. + * MUST be > 0!!! + * This is done for performance reasons, so no initial check has do be done. + * + * Return value + * 1: Data has been copied + * 0: No space, data has not been copied + * + * Notes + * (1) If there is not enough space in the "Up"-buffer, all data is dropped. + * (2) For performance reasons this function does not call Init() + * and may only be called after RTT has been initialized. + * Either by calling SEGGER_RTT_Init() or calling another RTT API function first. + */ +#if (RTT_USE_ASM == 0) +unsigned SEGGER_RTT_WriteSkipNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) +{ + const char* pData; + SEGGER_RTT_BUFFER_UP* pRing; + unsigned Avail; + unsigned RdOff; + unsigned WrOff; + unsigned Rem; + volatile char* pDst; + // + // Cases: + // 1) RdOff <= WrOff => Space until wrap-around is sufficient + // 2) RdOff <= WrOff => Space after wrap-around needed (copy in 2 chunks) + // 3) RdOff < WrOff => No space in buf + // 4) RdOff > WrOff => Space is sufficient + // 5) RdOff > WrOff => No space in buf + // + // 1) is the most common case for large buffers and assuming that J-Link reads the data fast + // enough + // + pData = (const char*)pBuffer; + pRing = + (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see + // changes made by the J-Link side and + // all of our changes go into HW directly + RdOff = pRing->RdOff; + WrOff = pRing->WrOff; + pDst = (pRing->pBuffer + WrOff) + SEGGER_RTT_UNCACHED_OFF; + if (RdOff <= WrOff) + { // Case 1), 2) or 3) + Avail = pRing->SizeOfBuffer - WrOff - + 1u; // Space until wrap-around (assume 1 byte not usable for case that RdOff == 0) + if (Avail >= NumBytes) + { // Case 1)? + memcpy((void*)pDst, pData, NumBytes); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU + // is allowed to change the order of memory accesses + pRing->WrOff = WrOff + NumBytes; + return 1; + } + Avail += RdOff; // Space incl. wrap-around + if (Avail >= NumBytes) + { // Case 2? => If not, we have case 3) (does not fit) + Rem = pRing->SizeOfBuffer - WrOff; // Space until end of buffer + memcpy((void*)pDst, pData, Rem); // Copy 1st chunk + NumBytes -= Rem; + // + // Special case: First check that assumed RdOff == 0 calculated that last element before + // wrap-around could not be used But 2nd check (considering space until wrap-around and + // until RdOff) revealed that RdOff is not 0, so we can use the last element In this + // case, we may use a copy straight until buffer end anyway without needing to copy 2 + // chunks Therefore, check if 2nd memcpy is necessary at all + // + if (NumBytes) + { + pDst = pRing->pBuffer + SEGGER_RTT_UNCACHED_OFF; + memcpy((void*)pDst, pData + Rem, NumBytes); + } + RTT__DMB(); // Force data write to be complete before writing the , in case CPU + // is allowed to change the order of memory accesses + pRing->WrOff = NumBytes; + return 1; + } + } + else + { // Potential case 4) + Avail = RdOff - WrOff - 1u; + if (Avail >= NumBytes) + { // Case 4)? => If not, we have case 5) (does not fit) + memcpy((void*)pDst, pData, NumBytes); + RTT__DMB(); // Force data write to be complete before writing the , in case CPU + // is allowed to change the order of memory accesses + pRing->WrOff = WrOff + NumBytes; + return 1; + } + } + return 0; // No space in buffer +} +#endif + +/********************************************************************* + * + * SEGGER_RTT_WriteDownBufferNoLock + * + * Function description + * Stores a specified number of characters in SEGGER RTT + * control block inside a buffer. + * SEGGER_RTT_WriteDownBufferNoLock does not lock the application. + * Used to do the same operation that J-Link does, to transfer + * RTT data from other channels, such as TCP/IP or UART. + * + * Parameters + * BufferIndex Index of "Down"-buffer to be used. + * pBuffer Pointer to character array. Does not need to point to a \0 terminated string. + * NumBytes Number of bytes to be stored in the SEGGER RTT control block. + * + * Return value + * Number of bytes which have been stored in the "Down"-buffer. + * + * Notes + * (1) Data is stored according to buffer flags. + * (2) For performance reasons this function does not call Init() + * and may only be called after RTT has been initialized. + * Either by calling SEGGER_RTT_Init() or calling another RTT API function first. + * + * Additional information + * This function must not be called when J-Link might also do RTT. + */ +unsigned SEGGER_RTT_WriteDownBufferNoLock( + unsigned BufferIndex, + const void* pBuffer, + unsigned NumBytes) +{ + unsigned Status; + unsigned Avail; + const char* pData; + SEGGER_RTT_BUFFER_UP* pRing; + // + // Get "to-target" ring buffer. + // It is save to cast that to a "to-host" buffer. Up and Down buffer differ in volatility of + // offsets that might be modified by J-Link. + // + pData = (const char*)pBuffer; + pRing = + (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aDown[BufferIndex] + + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see + // changes made by the J-Link side and + // all of our changes go into HW directly + // + // How we output depends upon the mode... + // + switch (pRing->Flags) + { + case SEGGER_RTT_MODE_NO_BLOCK_SKIP: + // + // If we are in skip mode and there is no space for the whole + // of this output, don't bother. + // + Avail = _GetAvailWriteSpace(pRing); + if (Avail < NumBytes) + { + Status = 0u; + } + else + { + Status = NumBytes; + _WriteNoCheck(pRing, pData, NumBytes); + } + break; + case SEGGER_RTT_MODE_NO_BLOCK_TRIM: + // + // If we are in trim mode, trim to what we can output without blocking. + // + Avail = _GetAvailWriteSpace(pRing); + Status = Avail < NumBytes ? Avail : NumBytes; + _WriteNoCheck(pRing, pData, Status); + break; + case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL: + // + // If we are in blocking mode, output everything. + // + Status = _WriteBlocking(pRing, pData, NumBytes); + break; + default: + Status = 0u; + break; + } + // + // Finish up. + // + return Status; +} + +/********************************************************************* + * + * SEGGER_RTT_WriteNoLock + * + * Function description + * Stores a specified number of characters in SEGGER RTT + * control block which is then read by the host. + * SEGGER_RTT_WriteNoLock does not lock the application. + * + * Parameters + * BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). + * pBuffer Pointer to character array. Does not need to point to a \0 terminated string. + * NumBytes Number of bytes to be stored in the SEGGER RTT control block. + * + * Return value + * Number of bytes which have been stored in the "Up"-buffer. + * + * Notes + * (1) Data is stored according to buffer flags. + * (2) For performance reasons this function does not call Init() + * and may only be called after RTT has been initialized. + * Either by calling SEGGER_RTT_Init() or calling another RTT API function first. + */ +unsigned SEGGER_RTT_WriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) +{ + unsigned Status; + unsigned Avail; + const char* pData; + SEGGER_RTT_BUFFER_UP* pRing; + // + // Get "to-host" ring buffer. + // + pData = (const char*)pBuffer; + pRing = + (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see + // changes made by the J-Link side and + // all of our changes go into HW directly + // + // How we output depends upon the mode... + // + switch (pRing->Flags) + { + case SEGGER_RTT_MODE_NO_BLOCK_SKIP: + // + // If we are in skip mode and there is no space for the whole + // of this output, don't bother. + // + Avail = _GetAvailWriteSpace(pRing); + if (Avail < NumBytes) + { + Status = 0u; + } + else + { + Status = NumBytes; + _WriteNoCheck(pRing, pData, NumBytes); + } + break; + case SEGGER_RTT_MODE_NO_BLOCK_TRIM: + // + // If we are in trim mode, trim to what we can output without blocking. + // + Avail = _GetAvailWriteSpace(pRing); + Status = Avail < NumBytes ? Avail : NumBytes; + _WriteNoCheck(pRing, pData, Status); + break; + case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL: + // + // If we are in blocking mode, output everything. + // + Status = _WriteBlocking(pRing, pData, NumBytes); + break; + default: + Status = 0u; + break; + } + // + // Finish up. + // + return Status; +} + +/********************************************************************* + * + * SEGGER_RTT_WriteDownBuffer + * + * Function description + * Stores a specified number of characters in SEGGER RTT control block in a buffer. + * + * Parameters + * BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). + * pBuffer Pointer to character array. Does not need to point to a \0 terminated string. + * NumBytes Number of bytes to be stored in the SEGGER RTT control block. + * + * Return value + * Number of bytes which have been stored in the "Down"-buffer. + * + * Notes + * (1) Data is stored according to buffer flags. + * + * Additional information + * This function must not be called when J-Link might also do RTT. + * This function locks against all other RTT operations. I.e. during + * the write operation, writing from the application is also locked. + * If only one consumer writes to the down buffer, + * call SEGGER_RTT_WriteDownBufferNoLock() instead. + */ +unsigned SEGGER_RTT_WriteDownBuffer(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) +{ + unsigned Status; + + INIT(); + SEGGER_RTT_LOCK(); + Status = SEGGER_RTT_WriteDownBufferNoLock( + BufferIndex, + pBuffer, + NumBytes); // Call the non-locking write function + SEGGER_RTT_UNLOCK(); + return Status; +} + +/********************************************************************* + * + * SEGGER_RTT_Write + * + * Function description + * Stores a specified number of characters in SEGGER RTT + * control block which is then read by the host. + * + * Parameters + * BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). + * pBuffer Pointer to character array. Does not need to point to a \0 terminated string. + * NumBytes Number of bytes to be stored in the SEGGER RTT control block. + * + * Return value + * Number of bytes which have been stored in the "Up"-buffer. + * + * Notes + * (1) Data is stored according to buffer flags. + */ +unsigned SEGGER_RTT_Write(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes) +{ + unsigned Status; + + INIT(); + SEGGER_RTT_LOCK(); + Status = SEGGER_RTT_WriteNoLock( + BufferIndex, + pBuffer, + NumBytes); // Call the non-locking write function + SEGGER_RTT_UNLOCK(); + return Status; +} + +/********************************************************************* + * + * SEGGER_RTT_WriteString + * + * Function description + * Stores string in SEGGER RTT control block. + * This data is read by the host. + * + * Parameters + * BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). + * s Pointer to string. + * + * Return value + * Number of bytes which have been stored in the "Up"-buffer. + * + * Notes + * (1) Data is stored according to buffer flags. + * (2) String passed to this function has to be \0 terminated + * (3) \0 termination character is *not* stored in RTT buffer + */ +unsigned SEGGER_RTT_WriteString(unsigned BufferIndex, const char* s) +{ + unsigned Len; + + Len = STRLEN(s); + return SEGGER_RTT_Write(BufferIndex, s, Len); +} + +/********************************************************************* + * + * SEGGER_RTT_PutCharSkipNoLock + * + * Function description + * Stores a single character/byte in SEGGER RTT buffer. + * SEGGER_RTT_PutCharSkipNoLock does not lock the application and + * skips the byte, if it does not fit into the buffer. + * + * Parameters + * BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). + * c Byte to be stored. + * + * Return value + * Number of bytes which have been stored in the "Up"-buffer. + * + * Notes + * (1) If there is not enough space in the "Up"-buffer, the character is dropped. + * (2) For performance reasons this function does not call Init() + * and may only be called after RTT has been initialized. + * Either by calling SEGGER_RTT_Init() or calling another RTT API function first. + */ + +unsigned SEGGER_RTT_PutCharSkipNoLock(unsigned BufferIndex, char c) +{ + SEGGER_RTT_BUFFER_UP* pRing; + unsigned WrOff; + unsigned Status; + volatile char* pDst; + // + // Get "to-host" ring buffer. + // + pRing = + (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see + // changes made by the J-Link side and + // all of our changes go into HW directly + // + // Get write position and handle wrap-around if necessary + // + WrOff = pRing->WrOff + 1; + if (WrOff == pRing->SizeOfBuffer) + { + WrOff = 0; + } + // + // Output byte if free space is available + // + if (WrOff != pRing->RdOff) + { + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; + *pDst = c; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is + // allowed to change the order of memory accesses + pRing->WrOff = WrOff; + Status = 1; + } + else + { + Status = 0; + } + // + return Status; +} + +/********************************************************************* + * + * SEGGER_RTT_PutCharSkip + * + * Function description + * Stores a single character/byte in SEGGER RTT buffer. + * + * Parameters + * BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). + * c Byte to be stored. + * + * Return value + * Number of bytes which have been stored in the "Up"-buffer. + * + * Notes + * (1) If there is not enough space in the "Up"-buffer, the character is dropped. + */ + +unsigned SEGGER_RTT_PutCharSkip(unsigned BufferIndex, char c) +{ + SEGGER_RTT_BUFFER_UP* pRing; + unsigned WrOff; + unsigned Status; + volatile char* pDst; + // + // Prepare + // + INIT(); + SEGGER_RTT_LOCK(); + // + // Get "to-host" ring buffer. + // + pRing = + (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see + // changes made by the J-Link side and + // all of our changes go into HW directly + // + // Get write position and handle wrap-around if necessary + // + WrOff = pRing->WrOff + 1; + if (WrOff == pRing->SizeOfBuffer) + { + WrOff = 0; + } + // + // Output byte if free space is available + // + if (WrOff != pRing->RdOff) + { + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; + *pDst = c; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is + // allowed to change the order of memory accesses + pRing->WrOff = WrOff; + Status = 1; + } + else + { + Status = 0; + } + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + // + return Status; +} + +/********************************************************************* + * + * SEGGER_RTT_PutChar + * + * Function description + * Stores a single character/byte in SEGGER RTT buffer. + * + * Parameters + * BufferIndex Index of "Up"-buffer to be used (e.g. 0 for "Terminal"). + * c Byte to be stored. + * + * Return value + * Number of bytes which have been stored in the "Up"-buffer. + * + * Notes + * (1) Data is stored according to buffer flags. + */ + +unsigned SEGGER_RTT_PutChar(unsigned BufferIndex, char c) +{ + SEGGER_RTT_BUFFER_UP* pRing; + unsigned WrOff; + unsigned Status; + volatile char* pDst; + // + // Prepare + // + INIT(); + SEGGER_RTT_LOCK(); + // + // Get "to-host" ring buffer. + // + pRing = + (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see + // changes made by the J-Link side and + // all of our changes go into HW directly + // + // Get write position and handle wrap-around if necessary + // + WrOff = pRing->WrOff + 1; + if (WrOff == pRing->SizeOfBuffer) + { + WrOff = 0; + } + // + // Wait for free space if mode is set to blocking + // + if (pRing->Flags == SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL) + { + while (WrOff == pRing->RdOff) + { + ; + } + } + // + // Output byte if free space is available + // + if (WrOff != pRing->RdOff) + { + pDst = (pRing->pBuffer + pRing->WrOff) + SEGGER_RTT_UNCACHED_OFF; + *pDst = c; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is + // allowed to change the order of memory accesses + pRing->WrOff = WrOff; + Status = 1; + } + else + { + Status = 0; + } + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + return Status; +} + +/********************************************************************* + * + * SEGGER_RTT_GetKey + * + * Function description + * Reads one character from the SEGGER RTT buffer. + * Host has previously stored data there. + * + * Return value + * < 0 - No character available (buffer empty). + * >= 0 - Character which has been read. (Possible values: 0 - 255) + * + * Notes + * (1) This function is only specified for accesses to RTT buffer 0. + */ +int SEGGER_RTT_GetKey(void) +{ + char c; + int r; + + r = (int)SEGGER_RTT_Read(0u, &c, 1u); + if (r == 1) + { + r = (int)(unsigned char)c; + } + else + { + r = -1; + } + return r; +} + +/********************************************************************* + * + * SEGGER_RTT_WaitKey + * + * Function description + * Waits until at least one character is avaible in the SEGGER RTT buffer. + * Once a character is available, it is read and this function returns. + * + * Return value + * >=0 - Character which has been read. + * + * Notes + * (1) This function is only specified for accesses to RTT buffer 0 + * (2) This function is blocking if no character is present in RTT buffer + */ +int SEGGER_RTT_WaitKey(void) +{ + int r; + + do + { + r = SEGGER_RTT_GetKey(); + } while (r < 0); + return r; +} + +/********************************************************************* + * + * SEGGER_RTT_HasKey + * + * Function description + * Checks if at least one character for reading is available in the SEGGER RTT buffer. + * + * Return value + * == 0 - No characters are available to read. + * == 1 - At least one character is available. + * + * Notes + * (1) This function is only specified for accesses to RTT buffer 0 + */ +int SEGGER_RTT_HasKey(void) +{ + SEGGER_RTT_BUFFER_DOWN* pRing; + unsigned RdOff; + int r; + + INIT(); + pRing = (SEGGER_RTT_BUFFER_DOWN*)((uintptr_t)&_SEGGER_RTT.aDown[0] + + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we + // see changes made by the J-Link + // side and all of our changes go + // into HW directly + RdOff = pRing->RdOff; + if (RdOff != pRing->WrOff) + { + r = 1; + } + else + { + r = 0; + } + return r; +} + +/********************************************************************* + * + * SEGGER_RTT_HasData + * + * Function description + * Check if there is data from the host in the given buffer. + * + * Return value: + * ==0: No data + * !=0: Data in buffer + * + */ +unsigned SEGGER_RTT_HasData(unsigned BufferIndex) +{ + SEGGER_RTT_BUFFER_DOWN* pRing; + unsigned v; + + pRing = (SEGGER_RTT_BUFFER_DOWN*)((uintptr_t)&_SEGGER_RTT.aDown[BufferIndex] + + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we + // see changes made by the J-Link + // side and all of our changes go + // into HW directly + v = pRing->WrOff; + return v - pRing->RdOff; +} + +/********************************************************************* + * + * SEGGER_RTT_HasDataUp + * + * Function description + * Check if there is data remaining to be sent in the given buffer. + * + * Return value: + * ==0: No data + * !=0: Data in buffer + * + */ +unsigned SEGGER_RTT_HasDataUp(unsigned BufferIndex) +{ + SEGGER_RTT_BUFFER_UP* pRing; + unsigned v; + + pRing = + (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see + // changes made by the J-Link side and + // all of our changes go into HW directly + v = pRing->RdOff; + return pRing->WrOff - v; +} + +/********************************************************************* + * + * SEGGER_RTT_AllocDownBuffer + * + * Function description + * Run-time configuration of the next down-buffer (H->T). + * The next buffer, which is not used yet is configured. + * This includes: Buffer address, size, name, flags, ... + * + * Parameters + * sName Pointer to a constant name string. + * pBuffer Pointer to a buffer to be used. + * BufferSize Size of the buffer. + * Flags Operating modes. Define behavior if buffer is full (not enough space for entire + * message). Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for + * future use. Flags[1:0] = RTT operating mode. + * + * Return value + * >= 0 - O.K. Buffer Index + * < 0 - Error + */ +int SEGGER_RTT_AllocDownBuffer( + const char* sName, + void* pBuffer, + unsigned BufferSize, + unsigned Flags) +{ + int BufferIndex; + volatile SEGGER_RTT_CB* pRTTCB; + + INIT(); + SEGGER_RTT_LOCK(); + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make + // sure we see changes made by the + // J-Link side and all of our + // changes go into HW directly + BufferIndex = 0; + do + { + if (pRTTCB->aDown[BufferIndex].pBuffer == NULL) + { + break; + } + BufferIndex++; + } while (BufferIndex < pRTTCB->MaxNumDownBuffers); + if (BufferIndex < pRTTCB->MaxNumDownBuffers) + { + pRTTCB->aDown[BufferIndex].sName = sName; + pRTTCB->aDown[BufferIndex].pBuffer = (char*)pBuffer; + pRTTCB->aDown[BufferIndex].SizeOfBuffer = BufferSize; + pRTTCB->aDown[BufferIndex].RdOff = 0u; + pRTTCB->aDown[BufferIndex].WrOff = 0u; + pRTTCB->aDown[BufferIndex].Flags = Flags; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is + // allowed to change the order of memory accesses + } + else + { + BufferIndex = -1; + } + SEGGER_RTT_UNLOCK(); + return BufferIndex; +} + +/********************************************************************* + * + * SEGGER_RTT_AllocUpBuffer + * + * Function description + * Run-time configuration of the next up-buffer (T->H). + * The next buffer, which is not used yet is configured. + * This includes: Buffer address, size, name, flags, ... + * + * Parameters + * sName Pointer to a constant name string. + * pBuffer Pointer to a buffer to be used. + * BufferSize Size of the buffer. + * Flags Operating modes. Define behavior if buffer is full (not enough space for entire + * message). Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for + * future use. Flags[1:0] = RTT operating mode. + * + * Return value + * >= 0 - O.K. Buffer Index + * < 0 - Error + */ +int SEGGER_RTT_AllocUpBuffer(const char* sName, void* pBuffer, unsigned BufferSize, unsigned Flags) +{ + int BufferIndex; + volatile SEGGER_RTT_CB* pRTTCB; + + INIT(); + SEGGER_RTT_LOCK(); + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make + // sure we see changes made by the + // J-Link side and all of our + // changes go into HW directly + BufferIndex = 0; + do + { + if (pRTTCB->aUp[BufferIndex].pBuffer == NULL) + { + break; + } + BufferIndex++; + } while (BufferIndex < pRTTCB->MaxNumUpBuffers); + if (BufferIndex < pRTTCB->MaxNumUpBuffers) + { + pRTTCB->aUp[BufferIndex].sName = sName; + pRTTCB->aUp[BufferIndex].pBuffer = (char*)pBuffer; + pRTTCB->aUp[BufferIndex].SizeOfBuffer = BufferSize; + pRTTCB->aUp[BufferIndex].RdOff = 0u; + pRTTCB->aUp[BufferIndex].WrOff = 0u; + pRTTCB->aUp[BufferIndex].Flags = Flags; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is + // allowed to change the order of memory accesses + } + else + { + BufferIndex = -1; + } + SEGGER_RTT_UNLOCK(); + return BufferIndex; +} + +/********************************************************************* + * + * SEGGER_RTT_ConfigUpBuffer + * + * Function description + * Run-time configuration of a specific up-buffer (T->H). + * Buffer to be configured is specified by index. + * This includes: Buffer address, size, name, flags, ... + * + * Parameters + * BufferIndex Index of the buffer to configure. + * sName Pointer to a constant name string. + * pBuffer Pointer to a buffer to be used. + * BufferSize Size of the buffer. + * Flags Operating modes. Define behavior if buffer is full (not enough space for entire + * message). Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for + * future use. Flags[1:0] = RTT operating mode. + * + * Return value + * >= 0 - O.K. + * < 0 - Error + * + * Additional information + * Buffer 0 is configured on compile-time. + * May only be called once per buffer. + * Buffer name and flags can be reconfigured using the appropriate functions. + */ +int SEGGER_RTT_ConfigUpBuffer( + unsigned BufferIndex, + const char* sName, + void* pBuffer, + unsigned BufferSize, + unsigned Flags) +{ + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_UP* pUp; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make + // sure we see changes made by the + // J-Link side and all of our + // changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_UP_BUFFERS) + { + SEGGER_RTT_LOCK(); + pUp = &pRTTCB->aUp[BufferIndex]; + if (BufferIndex) + { + pUp->sName = sName; + pUp->pBuffer = (char*)pBuffer; + pUp->SizeOfBuffer = BufferSize; + pUp->RdOff = 0u; + pUp->WrOff = 0u; + } + pUp->Flags = Flags; + SEGGER_RTT_UNLOCK(); + r = 0; + } + else + { + r = -1; + } + return r; +} + +/********************************************************************* + * + * SEGGER_RTT_ConfigDownBuffer + * + * Function description + * Run-time configuration of a specific down-buffer (H->T). + * Buffer to be configured is specified by index. + * This includes: Buffer address, size, name, flags, ... + * + * Parameters + * BufferIndex Index of the buffer to configure. + * sName Pointer to a constant name string. + * pBuffer Pointer to a buffer to be used. + * BufferSize Size of the buffer. + * Flags Operating modes. Define behavior if buffer is full (not enough space for entire + * message). Flags[31:24] are used for validity check and must be zero. Flags[23:2] are reserved for + * future use. Flags[1:0] = RTT operating mode. + * + * Return value + * >= 0 O.K. + * < 0 Error + * + * Additional information + * Buffer 0 is configured on compile-time. + * May only be called once per buffer. + * Buffer name and flags can be reconfigured using the appropriate functions. + */ +int SEGGER_RTT_ConfigDownBuffer( + unsigned BufferIndex, + const char* sName, + void* pBuffer, + unsigned BufferSize, + unsigned Flags) +{ + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_DOWN* pDown; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make + // sure we see changes made by the + // J-Link side and all of our + // changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_DOWN_BUFFERS) + { + SEGGER_RTT_LOCK(); + pDown = &pRTTCB->aDown[BufferIndex]; + if (BufferIndex) + { + pDown->sName = sName; + pDown->pBuffer = (char*)pBuffer; + pDown->SizeOfBuffer = BufferSize; + pDown->RdOff = 0u; + pDown->WrOff = 0u; + } + pDown->Flags = Flags; + RTT__DMB(); // Force data write to be complete before writing the , in case CPU is + // allowed to change the order of memory accesses + SEGGER_RTT_UNLOCK(); + r = 0; + } + else + { + r = -1; + } + return r; +} + +/********************************************************************* + * + * SEGGER_RTT_SetNameUpBuffer + * + * Function description + * Run-time configuration of a specific up-buffer name (T->H). + * Buffer to be configured is specified by index. + * + * Parameters + * BufferIndex Index of the buffer to renamed. + * sName Pointer to a constant name string. + * + * Return value + * >= 0 O.K. + * < 0 Error + */ +int SEGGER_RTT_SetNameUpBuffer(unsigned BufferIndex, const char* sName) +{ + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_UP* pUp; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make + // sure we see changes made by the + // J-Link side and all of our + // changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_UP_BUFFERS) + { + SEGGER_RTT_LOCK(); + pUp = &pRTTCB->aUp[BufferIndex]; + pUp->sName = sName; + SEGGER_RTT_UNLOCK(); + r = 0; + } + else + { + r = -1; + } + return r; +} + +/********************************************************************* + * + * SEGGER_RTT_SetNameDownBuffer + * + * Function description + * Run-time configuration of a specific Down-buffer name (T->H). + * Buffer to be configured is specified by index. + * + * Parameters + * BufferIndex Index of the buffer to renamed. + * sName Pointer to a constant name string. + * + * Return value + * >= 0 O.K. + * < 0 Error + */ +int SEGGER_RTT_SetNameDownBuffer(unsigned BufferIndex, const char* sName) +{ + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_DOWN* pDown; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make + // sure we see changes made by the + // J-Link side and all of our + // changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_DOWN_BUFFERS) + { + SEGGER_RTT_LOCK(); + pDown = &pRTTCB->aDown[BufferIndex]; + pDown->sName = sName; + SEGGER_RTT_UNLOCK(); + r = 0; + } + else + { + r = -1; + } + return r; +} + +/********************************************************************* + * + * SEGGER_RTT_SetFlagsUpBuffer + * + * Function description + * Run-time configuration of specific up-buffer flags (T->H). + * Buffer to be configured is specified by index. + * + * Parameters + * BufferIndex Index of the buffer. + * Flags Flags to set for the buffer. + * Flags[31:24] are used for validity check and must be zero. Flags[23:2] are + * reserved for future use. Flags[1:0] = RTT operating mode. + * + * Return value + * >= 0 O.K. + * < 0 Error + */ +int SEGGER_RTT_SetFlagsUpBuffer(unsigned BufferIndex, unsigned Flags) +{ + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_UP* pUp; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make + // sure we see changes made by the + // J-Link side and all of our + // changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_UP_BUFFERS) + { + SEGGER_RTT_LOCK(); + pUp = &pRTTCB->aUp[BufferIndex]; + pUp->Flags = Flags; + SEGGER_RTT_UNLOCK(); + r = 0; + } + else + { + r = -1; + } + return r; +} + +/********************************************************************* + * + * SEGGER_RTT_SetFlagsDownBuffer + * + * Function description + * Run-time configuration of specific Down-buffer flags (T->H). + * Buffer to be configured is specified by index. + * + * Parameters + * BufferIndex Index of the buffer to renamed. + * Flags Flags to set for the buffer. + * Flags[31:24] are used for validity check and must be zero. Flags[23:2] are + * reserved for future use. Flags[1:0] = RTT operating mode. + * + * Return value + * >= 0 O.K. + * < 0 Error + */ +int SEGGER_RTT_SetFlagsDownBuffer(unsigned BufferIndex, unsigned Flags) +{ + int r; + volatile SEGGER_RTT_CB* pRTTCB; + volatile SEGGER_RTT_BUFFER_DOWN* pDown; + + INIT(); + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make + // sure we see changes made by the + // J-Link side and all of our + // changes go into HW directly + if (BufferIndex < SEGGER_RTT_MAX_NUM_DOWN_BUFFERS) + { + SEGGER_RTT_LOCK(); + pDown = &pRTTCB->aDown[BufferIndex]; + pDown->Flags = Flags; + SEGGER_RTT_UNLOCK(); + r = 0; + } + else + { + r = -1; + } + return r; +} + +/********************************************************************* + * + * SEGGER_RTT_Init + * + * Function description + * Initializes the RTT Control Block. + * Should be used in RAM targets, at start of the application. + * + */ +void SEGGER_RTT_Init(void) { _DoInit(); } + +/********************************************************************* + * + * SEGGER_RTT_SetTerminal + * + * Function description + * Sets the terminal to be used for output on channel 0. + * + * Parameters + * TerminalId Index of the terminal. + * + * Return value + * >= 0 O.K. + * < 0 Error (e.g. if RTT is configured for non-blocking mode and there was no space in the + * buffer to set the new terminal Id) + * + * Notes + * (1) Buffer 0 is always reserved for terminal I/O, so we can use index 0 here, fixed + */ +int SEGGER_RTT_SetTerminal(unsigned char TerminalId) +{ + unsigned char ac[2]; + SEGGER_RTT_BUFFER_UP* pRing; + unsigned Avail; + int r; + + INIT(); + r = 0; + ac[0] = 0xFFu; + if (TerminalId < sizeof(_aTerminalId)) + { // We only support a certain number of channels + ac[1] = _aTerminalId[TerminalId]; + pRing = (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[0] + + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure + // we see changes made by the + // J-Link side and all of our + // changes go into HW directly + SEGGER_RTT_LOCK(); // Lock to make sure that no other task is writing into buffer, while we + // are and number of free bytes in buffer does not change downwards + // after checking and before writing + if ((pRing->Flags & SEGGER_RTT_MODE_MASK) == SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL) + { + _ActiveTerminal = TerminalId; + _WriteBlocking(pRing, (const char*)ac, 2u); + } + else + { // Skipping mode or trim mode? => We cannot trim this command so handling is the same for + // both modes + Avail = _GetAvailWriteSpace(pRing); + if (Avail >= 2) + { + _ActiveTerminal = TerminalId; // Only change active terminal in case of success + _WriteNoCheck(pRing, (const char*)ac, 2u); + } + else + { + r = -1; + } + } + SEGGER_RTT_UNLOCK(); + } + else + { + r = -1; + } + return r; +} + +/********************************************************************* + * + * SEGGER_RTT_TerminalOut + * + * Function description + * Writes a string to the given terminal + * without changing the terminal for channel 0. + * + * Parameters + * TerminalId Index of the terminal. + * s String to be printed on the terminal. + * + * Return value + * >= 0 - Number of bytes written. + * < 0 - Error. + * + */ +int SEGGER_RTT_TerminalOut(unsigned char TerminalId, const char* s) +{ + int Status; + unsigned FragLen; + unsigned Avail; + SEGGER_RTT_BUFFER_UP* pRing; + // + INIT(); + // + // Validate terminal ID. + // + if (TerminalId < (char)sizeof(_aTerminalId)) + { // We only support a certain number of channels + // + // Get "to-host" ring buffer. + // + pRing = (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[0] + + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure + // we see changes made by the + // J-Link side and all of our + // changes go into HW directly + // + // Need to be able to change terminal, write data, change back. + // Compute the fixed and variable sizes. + // + FragLen = STRLEN(s); + // + // How we output depends upon the mode... + // + SEGGER_RTT_LOCK(); + Avail = _GetAvailWriteSpace(pRing); + switch (pRing->Flags & SEGGER_RTT_MODE_MASK) + { + case SEGGER_RTT_MODE_NO_BLOCK_SKIP: + // + // If we are in skip mode and there is no space for the whole + // of this output, don't bother switching terminals at all. + // + if (Avail < (FragLen + 4u)) + { + Status = 0; + } + else + { + _PostTerminalSwitch(pRing, TerminalId); + Status = (int)_WriteBlocking(pRing, s, FragLen); + _PostTerminalSwitch(pRing, _ActiveTerminal); + } + break; + case SEGGER_RTT_MODE_NO_BLOCK_TRIM: + // + // If we are in trim mode and there is not enough space for everything, + // trim the output but always include the terminal switch. If no room + // for terminal switch, skip that totally. + // + if (Avail < 4u) + { + Status = -1; + } + else + { + _PostTerminalSwitch(pRing, TerminalId); + Status = (int) + _WriteBlocking(pRing, s, (FragLen < (Avail - 4u)) ? FragLen : (Avail - 4u)); + _PostTerminalSwitch(pRing, _ActiveTerminal); + } + break; + case SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL: + // + // If we are in blocking mode, output everything. + // + _PostTerminalSwitch(pRing, TerminalId); + Status = (int)_WriteBlocking(pRing, s, FragLen); + _PostTerminalSwitch(pRing, _ActiveTerminal); + break; + default: + Status = -1; + break; + } + // + // Finish up. + // + SEGGER_RTT_UNLOCK(); + } + else + { + Status = -1; + } + return Status; +} + +/********************************************************************* + * + * SEGGER_RTT_GetAvailWriteSpace + * + * Function description + * Returns the number of bytes available in the ring buffer. + * + * Parameters + * BufferIndex Index of the up buffer. + * + * Return value + * Number of bytes that are free in the selected up buffer. + */ +unsigned SEGGER_RTT_GetAvailWriteSpace(unsigned BufferIndex) +{ + SEGGER_RTT_BUFFER_UP* pRing; + + pRing = + (SEGGER_RTT_BUFFER_UP*)((uintptr_t)&_SEGGER_RTT.aUp[BufferIndex] + + SEGGER_RTT_UNCACHED_OFF); // Access uncached to make sure we see + // changes made by the J-Link side and + // all of our changes go into HW directly + return _GetAvailWriteSpace(pRing); +} + +/********************************************************************* + * + * SEGGER_RTT_GetBytesInBuffer() + * + * Function description + * Returns the number of bytes currently used in the up buffer. + * + * Parameters + * BufferIndex Index of the up buffer. + * + * Return value + * Number of bytes that are used in the buffer. + */ +unsigned SEGGER_RTT_GetBytesInBuffer(unsigned BufferIndex) +{ + unsigned RdOff; + unsigned WrOff; + unsigned r; + volatile SEGGER_RTT_CB* pRTTCB; + // + // Avoid warnings regarding volatile access order. It's not a problem + // in this case, but dampen compiler enthusiasm. + // + pRTTCB = (volatile SEGGER_RTT_CB*)((uintptr_t)&_SEGGER_RTT + + SEGGER_RTT_UNCACHED_OFF); // Access RTTCB uncached to make + // sure we see changes made by the + // J-Link side and all of our + // changes go into HW directly + RdOff = pRTTCB->aUp[BufferIndex].RdOff; + WrOff = pRTTCB->aUp[BufferIndex].WrOff; + if (RdOff <= WrOff) + { + r = WrOff - RdOff; + } + else + { + r = pRTTCB->aUp[BufferIndex].SizeOfBuffer - (WrOff - RdOff); + } + return r; +} + +/*************************** End of file ****************************/ diff --git a/ut-robomaster/src/communication/rtt/SEGGER_RTT.h b/ut-robomaster/src/communication/rtt/SEGGER_RTT.h new file mode 100644 index 00000000..6bae11af --- /dev/null +++ b/ut-robomaster/src/communication/rtt/SEGGER_RTT.h @@ -0,0 +1,576 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2019 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER RTT * Real Time Transfer for embedded targets * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the RTT protocol and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* 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 SEGGER Microcontroller 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. * +* * +********************************************************************** +---------------------------END-OF-HEADER------------------------------ +File : SEGGER_RTT.h +Purpose : Implementation of SEGGER real-time transfer which allows + real-time communication on targets which support debugger + memory accesses while the CPU is running. +Revision: $Rev: 25842 $ +---------------------------------------------------------------------- +*/ + +#ifndef SEGGER_RTT_H +#define SEGGER_RTT_H + +#include "SEGGER_RTT_Conf.h" + +/********************************************************************* + * + * Defines, defaults + * + ********************************************************************** + */ + +#ifndef RTT_USE_ASM +// +// Some cores support out-of-order memory accesses (reordering of memory accesses in the core) +// For such cores, we need to define a memory barrier to guarantee the order of certain accesses to +// the RTT ring buffers. Needed for: +// Cortex-M7 (ARMv7-M) +// Cortex-M23 (ARM-v8M) +// Cortex-M33 (ARM-v8M) +// Cortex-A/R (ARM-v7A/R) +// +// We do not explicitly check for "Embedded Studio" as the compiler in use determines what we +// support. You can use an external toolchain like IAR inside ES. So there is no point in checking +// for "Embedded Studio" +// +#if (defined __CROSSWORKS_ARM) // Rowley Crossworks +#define _CC_HAS_RTT_ASM_SUPPORT 1 +#if (defined __ARM_ARCH_7M__) // Cortex-M3 +#define _CORE_HAS_RTT_ASM_SUPPORT 1 +#elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7 +#define _CORE_HAS_RTT_ASM_SUPPORT 1 +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() __asm volatile("dmb\n" : : :); +#elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23 +#define _CORE_HAS_RTT_ASM_SUPPORT 0 +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() __asm volatile("dmb\n" : : :); +#elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33 +#define _CORE_HAS_RTT_ASM_SUPPORT 1 +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() __asm volatile("dmb\n" : : :); +#elif (defined(__ARM_ARCH_8_1M_MAIN__)) // Cortex-M85 +#define _CORE_HAS_RTT_ASM_SUPPORT 1 +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() __asm volatile("dmb\n" : : :); +#else +#define _CORE_HAS_RTT_ASM_SUPPORT 0 +#endif +#elif (defined __ARMCC_VERSION) +// +// ARM compiler +// ARM compiler V6.0 and later is clang based. +// Our ASM part is compatible to clang. +// +#if (__ARMCC_VERSION >= 6000000) +#define _CC_HAS_RTT_ASM_SUPPORT 1 +#else +#define _CC_HAS_RTT_ASM_SUPPORT 0 +#endif +#if (defined __ARM_ARCH_6M__) // Cortex-M0 / M1 +#define _CORE_HAS_RTT_ASM_SUPPORT 0 // No ASM support for this architecture +#elif (defined __ARM_ARCH_7M__) // Cortex-M3 +#define _CORE_HAS_RTT_ASM_SUPPORT 1 +#elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7 +#define _CORE_HAS_RTT_ASM_SUPPORT 1 +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() __asm volatile("dmb\n" : : :); +#elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23 +#define _CORE_HAS_RTT_ASM_SUPPORT 0 +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() __asm volatile("dmb\n" : : :); +#elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33 +#define _CORE_HAS_RTT_ASM_SUPPORT 1 +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() __asm volatile("dmb\n" : : :); +#elif (defined __ARM_ARCH_8_1M_MAIN__) // Cortex-M85 +#define _CORE_HAS_RTT_ASM_SUPPORT 1 +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() __asm volatile("dmb\n" : : :); +#elif ((defined __ARM_ARCH_7A__) || (defined __ARM_ARCH_7R__)) // Cortex-A/R 32-bit ARMv7-A/R +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() __asm volatile("dmb\n" : : :); +#else +#define _CORE_HAS_RTT_ASM_SUPPORT 0 +#endif +#elif ((defined __GNUC__) || (defined __clang__)) +// +// GCC / Clang +// +#define _CC_HAS_RTT_ASM_SUPPORT 1 +// ARM 7/9: __ARM_ARCH_5__ / __ARM_ARCH_5E__ / __ARM_ARCH_5T__ / __ARM_ARCH_5T__ / __ARM_ARCH_5TE__ +#if (defined __ARM_ARCH_7M__) // Cortex-M3 +#define _CORE_HAS_RTT_ASM_SUPPORT 1 +#elif (defined __ARM_ARCH_7EM__) // Cortex-M4/M7 +#define _CORE_HAS_RTT_ASM_SUPPORT 1 +#define _CORE_NEEDS_DMB 1 // Only Cortex-M7 needs a DMB but we cannot distinguish M4 and M7 here... +#define RTT__DMB() __asm volatile("dmb\n" : : :); +#elif (defined __ARM_ARCH_8M_BASE__) // Cortex-M23 +#define _CORE_HAS_RTT_ASM_SUPPORT 0 +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() __asm volatile("dmb\n" : : :); +#elif (defined __ARM_ARCH_8M_MAIN__) // Cortex-M33 +#define _CORE_HAS_RTT_ASM_SUPPORT 1 +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() __asm volatile("dmb\n" : : :); +#elif (defined __ARM_ARCH_8_1M_MAIN__) // Cortex-M85 +#define _CORE_HAS_RTT_ASM_SUPPORT 1 +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() __asm volatile("dmb\n" : : :); +#elif ((defined __ARM_ARCH_7A__) || (defined __ARM_ARCH_7R__)) // Cortex-A/R 32-bit ARMv7-A/R +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() __asm volatile("dmb\n" : : :); +#else +#define _CORE_HAS_RTT_ASM_SUPPORT 0 +#endif +#elif ((defined __IASMARM__) || (defined __ICCARM__)) +// +// IAR assembler/compiler +// +#define _CC_HAS_RTT_ASM_SUPPORT 1 +#if (__VER__ < 6300000) +#define VOLATILE +#else +#define VOLATILE volatile +#endif +#if (defined __ARM7M__) // Needed for old versions that do not know the define yet +#if (__CORE__ == __ARM7M__) // Cortex-M3 +#define _CORE_HAS_RTT_ASM_SUPPORT 1 +#endif +#endif +#if (defined __ARM7EM__) +#if (__CORE__ == __ARM7EM__) // Cortex-M4/M7 +#define _CORE_HAS_RTT_ASM_SUPPORT 1 +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() asm VOLATILE("DMB"); +#endif +#endif +#if (defined __ARM8M_BASELINE__) +#if (__CORE__ == __ARM8M_BASELINE__) // Cortex-M23 +#define _CORE_HAS_RTT_ASM_SUPPORT 0 +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() asm VOLATILE("DMB"); +#endif +#endif +#if (defined __ARM8M_MAINLINE__) +#if (__CORE__ == __ARM8M_MAINLINE__) // Cortex-M33 +#define _CORE_HAS_RTT_ASM_SUPPORT 1 +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() asm VOLATILE("DMB"); +#endif +#endif +#if (defined __ARM8EM_MAINLINE__) +#if (__CORE__ == __ARM8EM_MAINLINE__) // Cortex-??? +#define _CORE_HAS_RTT_ASM_SUPPORT 1 +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() asm VOLATILE("DMB"); +#endif +#endif +#if (defined __ARM7A__) +#if (__CORE__ == __ARM7A__) // Cortex-A 32-bit ARMv7-A +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() asm VOLATILE("DMB"); +#endif +#endif +#if (defined __ARM7R__) +#if (__CORE__ == __ARM7R__) // Cortex-R 32-bit ARMv7-R +#define _CORE_NEEDS_DMB 1 +#define RTT__DMB() asm VOLATILE("DMB"); +#endif +#endif +// TBD: __ARM8A__ => Cortex-A 64-bit ARMv8-A +// TBD: __ARM8R__ => Cortex-R 64-bit ARMv8-R +#else +// +// Other compilers +// +#define _CC_HAS_RTT_ASM_SUPPORT 0 +#define _CORE_HAS_RTT_ASM_SUPPORT 0 +#endif +// +// If IDE and core support the ASM version, enable ASM version by default +// +#ifndef _CORE_HAS_RTT_ASM_SUPPORT +#define _CORE_HAS_RTT_ASM_SUPPORT 0 // Default for unknown cores +#endif +#if (_CC_HAS_RTT_ASM_SUPPORT && _CORE_HAS_RTT_ASM_SUPPORT) +#define RTT_USE_ASM (1) +#else +#define RTT_USE_ASM (0) +#endif +#endif + +#ifndef _CORE_NEEDS_DMB +#define _CORE_NEEDS_DMB 0 +#endif + +#ifndef RTT__DMB +#if _CORE_NEEDS_DMB +#error "Don't know how to place inline assembly for DMB" +#else +#define RTT__DMB() +#endif +#endif + +#ifndef SEGGER_RTT_CPU_CACHE_LINE_SIZE +#define SEGGER_RTT_CPU_CACHE_LINE_SIZE \ + (0) // On most target systems where RTT is used, we do not have a CPU cache, therefore 0 is a + // good default here +#endif + +#ifndef SEGGER_RTT_UNCACHED_OFF +#if SEGGER_RTT_CPU_CACHE_LINE_SIZE +#error "SEGGER_RTT_UNCACHED_OFF must be defined when setting SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" +#else +#define SEGGER_RTT_UNCACHED_OFF (0) +#endif +#endif +#if RTT_USE_ASM +#if SEGGER_RTT_CPU_CACHE_LINE_SIZE +#error "RTT_USE_ASM is not available if SEGGER_RTT_CPU_CACHE_LINE_SIZE != 0" +#endif +#endif + +#ifndef SEGGER_RTT_ASM // defined when SEGGER_RTT.h is included from assembly file +#include +#include +#include + +/********************************************************************* + * + * Defines, fixed + * + ********************************************************************** + */ + +// +// Determine how much we must pad the control block to make it a multiple of a cache line in size +// Assuming: U8 = 1B +// U16 = 2B +// U32 = 4B +// U8/U16/U32* = 4B +// +#if SEGGER_RTT_CPU_CACHE_LINE_SIZE // Avoid division by zero in case we do not have any cache +#define SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(NumBytes) \ + (((NumBytes + SEGGER_RTT_CPU_CACHE_LINE_SIZE - 1) / SEGGER_RTT_CPU_CACHE_LINE_SIZE) * \ + SEGGER_RTT_CPU_CACHE_LINE_SIZE) +#else +#define SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(NumBytes) (NumBytes) +#endif +#define SEGGER_RTT__CB_SIZE \ + (16 + 4 + 4 + (SEGGER_RTT_MAX_NUM_UP_BUFFERS * 24) + (SEGGER_RTT_MAX_NUM_DOWN_BUFFERS * 24)) +#define SEGGER_RTT__CB_PADDING \ + (SEGGER_RTT__ROUND_UP_2_CACHE_LINE_SIZE(SEGGER_RTT__CB_SIZE) - SEGGER_RTT__CB_SIZE) + +/********************************************************************* + * + * Types + * + ********************************************************************** + */ + +// +// Description for a circular buffer (also called "ring buffer") +// which is used as up-buffer (T->H) +// +typedef struct +{ + const char* + sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4" + char* pBuffer; // Pointer to start of buffer + unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this + // implementation does not fill up the buffer in order to avoid the + // problem of being unable to distinguish between full and empty. + unsigned WrOff; // Position of next item to be written by either target. + volatile unsigned RdOff; // Position of next item to be read by host. Must be volatile since it + // may be modified by host. + unsigned Flags; // Contains configuration flags. Flags[31:24] are used for validity check and + // must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT + // operating mode. +} SEGGER_RTT_BUFFER_UP; + +// +// Description for a circular buffer (also called "ring buffer") +// which is used as down-buffer (H->T) +// +typedef struct +{ + const char* + sName; // Optional name. Standard names so far are: "Terminal", "SysView", "J-Scope_t4i4" + char* pBuffer; // Pointer to start of buffer + unsigned SizeOfBuffer; // Buffer size in bytes. Note that one byte is lost, as this + // implementation does not fill up the buffer in order to avoid the + // problem of being unable to distinguish between full and empty. + volatile unsigned WrOff; // Position of next item to be written by host. Must be volatile since + // it may be modified by host. + unsigned RdOff; // Position of next item to be read by target (down-buffer). + unsigned Flags; // Contains configuration flags. Flags[31:24] are used for validity check and + // must be zero. Flags[23:2] are reserved for future use. Flags[1:0] = RTT + // operating mode. +} SEGGER_RTT_BUFFER_DOWN; + +// +// RTT control block which describes the number of buffers available +// as well as the configuration for each buffer +// +// +typedef struct +{ + char acID[16]; // Initialized to "SEGGER RTT" + int MaxNumUpBuffers; // Initialized to SEGGER_RTT_MAX_NUM_UP_BUFFERS (type. 2) + int MaxNumDownBuffers; // Initialized to SEGGER_RTT_MAX_NUM_DOWN_BUFFERS (type. 2) + SEGGER_RTT_BUFFER_UP + aUp[SEGGER_RTT_MAX_NUM_UP_BUFFERS]; // Up buffers, transferring information up from target + // via debug probe to host + SEGGER_RTT_BUFFER_DOWN + aDown[SEGGER_RTT_MAX_NUM_DOWN_BUFFERS]; // Down buffers, transferring information down from + // host via debug probe to target +#if SEGGER_RTT__CB_PADDING + unsigned char aDummy[SEGGER_RTT__CB_PADDING]; +#endif +} SEGGER_RTT_CB; + +/********************************************************************* + * + * Global data + * + ********************************************************************** + */ +extern SEGGER_RTT_CB _SEGGER_RTT; + +/********************************************************************* + * + * RTT API functions + * + ********************************************************************** + */ +#ifdef __cplusplus +extern "C" +{ +#endif + int SEGGER_RTT_AllocDownBuffer( + const char* sName, + void* pBuffer, + unsigned BufferSize, + unsigned Flags); + int SEGGER_RTT_AllocUpBuffer( + const char* sName, + void* pBuffer, + unsigned BufferSize, + unsigned Flags); + int SEGGER_RTT_ConfigUpBuffer( + unsigned BufferIndex, + const char* sName, + void* pBuffer, + unsigned BufferSize, + unsigned Flags); + int SEGGER_RTT_ConfigDownBuffer( + unsigned BufferIndex, + const char* sName, + void* pBuffer, + unsigned BufferSize, + unsigned Flags); + int SEGGER_RTT_GetKey(void); + unsigned SEGGER_RTT_HasData(unsigned BufferIndex); + int SEGGER_RTT_HasKey(void); + unsigned SEGGER_RTT_HasDataUp(unsigned BufferIndex); + void SEGGER_RTT_Init(void); + unsigned SEGGER_RTT_Read(unsigned BufferIndex, void* pBuffer, unsigned BufferSize); + unsigned SEGGER_RTT_ReadNoLock(unsigned BufferIndex, void* pData, unsigned BufferSize); + int SEGGER_RTT_SetNameDownBuffer(unsigned BufferIndex, const char* sName); + int SEGGER_RTT_SetNameUpBuffer(unsigned BufferIndex, const char* sName); + int SEGGER_RTT_SetFlagsDownBuffer(unsigned BufferIndex, unsigned Flags); + int SEGGER_RTT_SetFlagsUpBuffer(unsigned BufferIndex, unsigned Flags); + int SEGGER_RTT_WaitKey(void); + unsigned SEGGER_RTT_Write(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); + unsigned SEGGER_RTT_WriteNoLock(unsigned BufferIndex, const void* pBuffer, unsigned NumBytes); + unsigned SEGGER_RTT_WriteSkipNoLock( + unsigned BufferIndex, + const void* pBuffer, + unsigned NumBytes); + unsigned SEGGER_RTT_ASM_WriteSkipNoLock( + unsigned BufferIndex, + const void* pBuffer, + unsigned NumBytes); + unsigned SEGGER_RTT_WriteString(unsigned BufferIndex, const char* s); + void SEGGER_RTT_WriteWithOverwriteNoLock( + unsigned BufferIndex, + const void* pBuffer, + unsigned NumBytes); + unsigned SEGGER_RTT_PutChar(unsigned BufferIndex, char c); + unsigned SEGGER_RTT_PutCharSkip(unsigned BufferIndex, char c); + unsigned SEGGER_RTT_PutCharSkipNoLock(unsigned BufferIndex, char c); + unsigned SEGGER_RTT_GetAvailWriteSpace(unsigned BufferIndex); + unsigned SEGGER_RTT_GetBytesInBuffer(unsigned BufferIndex); +// +// Function macro for performance optimization +// +#define SEGGER_RTT_HASDATA(n) \ + (((SEGGER_RTT_BUFFER_DOWN*)((uintptr_t) & _SEGGER_RTT.aDown[n] + SEGGER_RTT_UNCACHED_OFF)) \ + ->WrOff - \ + ((SEGGER_RTT_BUFFER_DOWN*)((uintptr_t) & _SEGGER_RTT.aDown[n] + SEGGER_RTT_UNCACHED_OFF)) \ + ->RdOff) + +#if RTT_USE_ASM +#define SEGGER_RTT_WriteSkipNoLock SEGGER_RTT_ASM_WriteSkipNoLock +#endif + + /********************************************************************* + * + * RTT transfer functions to send RTT data via other channels. + * + ********************************************************************** + */ + unsigned SEGGER_RTT_ReadUpBuffer(unsigned BufferIndex, void* pBuffer, unsigned BufferSize); + unsigned SEGGER_RTT_ReadUpBufferNoLock(unsigned BufferIndex, void* pData, unsigned BufferSize); + unsigned SEGGER_RTT_WriteDownBuffer( + unsigned BufferIndex, + const void* pBuffer, + unsigned NumBytes); + unsigned SEGGER_RTT_WriteDownBufferNoLock( + unsigned BufferIndex, + const void* pBuffer, + unsigned NumBytes); + +#define SEGGER_RTT_HASDATA_UP(n) \ + (((SEGGER_RTT_BUFFER_UP*)((uintptr_t) & _SEGGER_RTT.aUp[n] + SEGGER_RTT_UNCACHED_OFF)) \ + ->WrOff - \ + ((SEGGER_RTT_BUFFER_UP*)((uintptr_t) & _SEGGER_RTT.aUp[n] + SEGGER_RTT_UNCACHED_OFF)) \ + ->RdOff) // Access uncached to make sure we see changes made by the J-Link side and all of + // our changes go into HW directly + + /********************************************************************* + * + * RTT "Terminal" API functions + * + ********************************************************************** + */ + int SEGGER_RTT_SetTerminal(unsigned char TerminalId); + int SEGGER_RTT_TerminalOut(unsigned char TerminalId, const char* s); + + /********************************************************************* + * + * RTT printf functions (require SEGGER_RTT_printf.c) + * + ********************************************************************** + */ + int SEGGER_RTT_printf(unsigned BufferIndex, const char* sFormat, ...); + int SEGGER_RTT_vprintf(unsigned BufferIndex, const char* sFormat, va_list* pParamList); + +#ifdef __cplusplus +} +#endif + +#endif // ifndef(SEGGER_RTT_ASM) + +// +// For some environments, NULL may not be defined until certain headers are included +// +#ifndef NULL +#define NULL ((void*)0) +#endif + +/********************************************************************* + * + * Defines + * + ********************************************************************** + */ + +// +// Operating modes. Define behavior if buffer is full (not enough space for entire message) +// +#define SEGGER_RTT_MODE_NO_BLOCK_SKIP (0) // Skip. Do not block, output nothing. (Default) +#define SEGGER_RTT_MODE_NO_BLOCK_TRIM (1) // Trim: Do not block, output as much as fits. +#define SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL (2) // Block: Wait until there is space in the buffer. +#define SEGGER_RTT_MODE_MASK (3) + +// +// Control sequences, based on ANSI. +// Can be used to control color, and clear the screen +// +#define RTT_CTRL_RESET "\x1B[0m" // Reset to default colors +#define RTT_CTRL_CLEAR "\x1B[2J" // Clear screen, reposition cursor to top left + +#define RTT_CTRL_TEXT_BLACK "\x1B[2;30m" +#define RTT_CTRL_TEXT_RED "\x1B[2;31m" +#define RTT_CTRL_TEXT_GREEN "\x1B[2;32m" +#define RTT_CTRL_TEXT_YELLOW "\x1B[2;33m" +#define RTT_CTRL_TEXT_BLUE "\x1B[2;34m" +#define RTT_CTRL_TEXT_MAGENTA "\x1B[2;35m" +#define RTT_CTRL_TEXT_CYAN "\x1B[2;36m" +#define RTT_CTRL_TEXT_WHITE "\x1B[2;37m" + +#define RTT_CTRL_TEXT_BRIGHT_BLACK "\x1B[1;30m" +#define RTT_CTRL_TEXT_BRIGHT_RED "\x1B[1;31m" +#define RTT_CTRL_TEXT_BRIGHT_GREEN "\x1B[1;32m" +#define RTT_CTRL_TEXT_BRIGHT_YELLOW "\x1B[1;33m" +#define RTT_CTRL_TEXT_BRIGHT_BLUE "\x1B[1;34m" +#define RTT_CTRL_TEXT_BRIGHT_MAGENTA "\x1B[1;35m" +#define RTT_CTRL_TEXT_BRIGHT_CYAN "\x1B[1;36m" +#define RTT_CTRL_TEXT_BRIGHT_WHITE "\x1B[1;37m" + +#define RTT_CTRL_BG_BLACK "\x1B[24;40m" +#define RTT_CTRL_BG_RED "\x1B[24;41m" +#define RTT_CTRL_BG_GREEN "\x1B[24;42m" +#define RTT_CTRL_BG_YELLOW "\x1B[24;43m" +#define RTT_CTRL_BG_BLUE "\x1B[24;44m" +#define RTT_CTRL_BG_MAGENTA "\x1B[24;45m" +#define RTT_CTRL_BG_CYAN "\x1B[24;46m" +#define RTT_CTRL_BG_WHITE "\x1B[24;47m" + +#define RTT_CTRL_BG_BRIGHT_BLACK "\x1B[4;40m" +#define RTT_CTRL_BG_BRIGHT_RED "\x1B[4;41m" +#define RTT_CTRL_BG_BRIGHT_GREEN "\x1B[4;42m" +#define RTT_CTRL_BG_BRIGHT_YELLOW "\x1B[4;43m" +#define RTT_CTRL_BG_BRIGHT_BLUE "\x1B[4;44m" +#define RTT_CTRL_BG_BRIGHT_MAGENTA "\x1B[4;45m" +#define RTT_CTRL_BG_BRIGHT_CYAN "\x1B[4;46m" +#define RTT_CTRL_BG_BRIGHT_WHITE "\x1B[4;47m" + +#endif + +/*************************** End of file ****************************/ diff --git a/ut-robomaster/src/communication/rtt/SEGGER_RTT_Conf.h b/ut-robomaster/src/communication/rtt/SEGGER_RTT_Conf.h new file mode 100644 index 00000000..747506a6 --- /dev/null +++ b/ut-robomaster/src/communication/rtt/SEGGER_RTT_Conf.h @@ -0,0 +1,462 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2020 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER RTT * Real Time Transfer for embedded targets * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the RTT protocol and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* 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 SEGGER Microcontroller 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. * +* * +********************************************************************** +---------------------------END-OF-HEADER------------------------------ +File : SEGGER_RTT_Conf.h +Purpose : Implementation of SEGGER real-time transfer (RTT) which + allows real-time communication on targets which support + debugger memory accesses while the CPU is running. +Revision: $Rev: 24316 $ + +*/ + +#ifndef SEGGER_RTT_CONF_H +#define SEGGER_RTT_CONF_H + +#ifdef __IAR_SYSTEMS_ICC__ +#include +#endif + +/********************************************************************* + * + * Defines, configurable + * + ********************************************************************** + */ + +// +// Take in and set to correct values for Cortex-A systems with CPU cache +// +// #define SEGGER_RTT_CPU_CACHE_LINE_SIZE (32) // Largest cache line size (in +// bytes) in the current system #define SEGGER_RTT_UNCACHED_OFF (0xFB000000) // +// Address alias where RTT CB and buffers can be accessed uncached +// +// Most common case: +// Up-channel 0: RTT +// Up-channel 1: SystemView +// +#ifndef SEGGER_RTT_MAX_NUM_UP_BUFFERS +#define SEGGER_RTT_MAX_NUM_UP_BUFFERS \ + (3) // Max. number of up-buffers (T->H) available on this target (Default: 3) +#endif +// +// Most common case: +// Down-channel 0: RTT +// Down-channel 1: SystemView +// +#ifndef SEGGER_RTT_MAX_NUM_DOWN_BUFFERS +#define SEGGER_RTT_MAX_NUM_DOWN_BUFFERS \ + (3) // Max. number of down-buffers (H->T) available on this target (Default: 3) +#endif + +#ifndef BUFFER_SIZE_UP +#define BUFFER_SIZE_UP \ + (1024) // Size of the buffer for terminal output of target, up to host (Default: 1k) +#endif + +#ifndef BUFFER_SIZE_DOWN +#define BUFFER_SIZE_DOWN \ + (16) // Size of the buffer for terminal input to target from host (Usually keyboard input) + // (Default: 16) +#endif + +#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE +#define SEGGER_RTT_PRINTF_BUFFER_SIZE \ + (64u) // Size of buffer for RTT printf to bulk-send chars via RTT (Default: 64) +#endif + +#ifndef SEGGER_RTT_MODE_DEFAULT +#define SEGGER_RTT_MODE_DEFAULT \ + SEGGER_RTT_MODE_NO_BLOCK_SKIP // Mode for pre-initialized terminal channel (buffer 0) +#endif + +/********************************************************************* + * + * RTT memcpy configuration + * + * memcpy() is good for large amounts of data, + * but the overhead is big for small amounts, which are usually stored via RTT. + * With SEGGER_RTT_MEMCPY_USE_BYTELOOP a simple byte loop can be used instead. + * + * SEGGER_RTT_MEMCPY() can be used to replace standard memcpy() in RTT functions. + * This is may be required with memory access restrictions, + * such as on Cortex-A devices with MMU. + */ +#ifndef SEGGER_RTT_MEMCPY_USE_BYTELOOP +#define SEGGER_RTT_MEMCPY_USE_BYTELOOP \ + 0 // 0: Use memcpy/SEGGER_RTT_MEMCPY, 1: Use a simple byte-loop +#endif +// +// Example definition of SEGGER_RTT_MEMCPY to external memcpy with GCC toolchains and Cortex-A +// targets +// +// #if ((defined __SES_ARM) || (defined __CROSSWORKS_ARM) || (defined __GNUC__)) && (defined +// (__ARM_ARCH_7A__)) +// #define SEGGER_RTT_MEMCPY(pDest, pSrc, NumBytes) SEGGER_memcpy((pDest), (pSrc), (NumBytes)) +// #endif + +// +// Target is not allowed to perform other RTT operations while string still has not been stored +// completely. Otherwise we would probably end up with a mixed string in the buffer. If using RTT +// from within interrupts, multiple tasks or multi processors, define the SEGGER_RTT_LOCK() and +// SEGGER_RTT_UNLOCK() function here. +// +// SEGGER_RTT_MAX_INTERRUPT_PRIORITY can be used in the sample lock routines on Cortex-M3/4. +// Make sure to mask all interrupts which can send RTT data, i.e. generate SystemView events, or +// cause task switches. When high-priority interrupts must not be masked while sending RTT data, +// SEGGER_RTT_MAX_INTERRUPT_PRIORITY needs to be adjusted accordingly. (Higher priority = lower +// priority number) Default value for embOS: 128u Default configuration in FreeRTOS: +// configMAX_SYSCALL_INTERRUPT_PRIORITY: ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - +// configPRIO_BITS) ) In case of doubt mask all interrupts: 1 << (8 - BASEPRI_PRIO_BITS) i.e. 1 << 5 +// when 3 bits are implemented in NVIC or define SEGGER_RTT_LOCK() to completely disable interrupts. +// +#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY +#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY \ + (0x20) // Interrupt priority to lock on SEGGER_RTT_LOCK on Cortex-M3/4 (Default: 0x20) +#endif + +/********************************************************************* + * + * RTT lock configuration for SEGGER Embedded Studio, + * Rowley CrossStudio and GCC + */ +#if ( \ + (defined(__SES_ARM) || defined(__SES_RISCV) || defined(__CROSSWORKS_ARM) || \ + defined(__GNUC__) || defined(__clang__)) && \ + !defined(__CC_ARM) && !defined(WIN32)) +#if (defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_8M_BASE__)) +#define SEGGER_RTT_LOCK() \ + { \ + unsigned int _SEGGER_RTT__LockState; \ + __asm volatile( \ + "mrs %0, primask \n\t" \ + "movs r1, #1 \n\t" \ + "msr primask, r1 \n\t" \ + : "=r"(_SEGGER_RTT__LockState) \ + : \ + : "r1", "cc"); + +#define SEGGER_RTT_UNLOCK() \ + __asm volatile("msr primask, %0 \n\t" : : "r"(_SEGGER_RTT__LockState) :); \ + } +#elif (defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__)) +#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY +#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) +#endif +#define SEGGER_RTT_LOCK() \ + { \ + unsigned int _SEGGER_RTT__LockState; \ + __asm volatile( \ + "mrs %0, basepri \n\t" \ + "mov r1, %1 \n\t" \ + "msr basepri, r1 \n\t" \ + : "=r"(_SEGGER_RTT__LockState) \ + : "i"(SEGGER_RTT_MAX_INTERRUPT_PRIORITY) \ + : "r1", "cc"); + +#define SEGGER_RTT_UNLOCK() \ + __asm volatile("msr basepri, %0 \n\t" : : "r"(_SEGGER_RTT__LockState) :); \ + } + +#elif (defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__)) +#define SEGGER_RTT_LOCK() \ + { \ + unsigned int _SEGGER_RTT__LockState; \ + __asm volatile( \ + "mrs r1, CPSR \n\t" \ + "mov %0, r1 \n\t" \ + "orr r1, r1, #0xC0 \n\t" \ + "msr CPSR_c, r1 \n\t" \ + : "=r"(_SEGGER_RTT__LockState) \ + : \ + : "r1", "cc"); + +#define SEGGER_RTT_UNLOCK() \ + __asm volatile( \ + "mov r0, %0 \n\t" \ + "mrs r1, CPSR \n\t" \ + "bic r1, r1, #0xC0 \n\t" \ + "and r0, r0, #0xC0 \n\t" \ + "orr r1, r1, r0 \n\t" \ + "msr CPSR_c, r1 \n\t" \ + : \ + : "r"(_SEGGER_RTT__LockState) \ + : "r0", "r1", "cc"); \ + } +#elif defined(__riscv) || defined(__riscv_xlen) +#define SEGGER_RTT_LOCK() \ + { \ + unsigned int _SEGGER_RTT__LockState; \ + __asm volatile( \ + "csrr %0, mstatus \n\t" \ + "csrci mstatus, 8 \n\t" \ + "andi %0, %0, 8 \n\t" \ + : "=r"(_SEGGER_RTT__LockState) \ + : \ + :); + +#define SEGGER_RTT_UNLOCK() \ + __asm volatile( \ + "csrr a1, mstatus \n\t" \ + "or %0, %0, a1 \n\t" \ + "csrs mstatus, %0 \n\t" \ + : \ + : "r"(_SEGGER_RTT__LockState) \ + : "a1"); \ + } +#else +#define SEGGER_RTT_LOCK() +#define SEGGER_RTT_UNLOCK() +#endif +#endif + +/********************************************************************* + * + * RTT lock configuration for IAR EWARM + */ +#ifdef __ICCARM__ +#if (defined(__ARM6M__) && (__CORE__ == __ARM6M__)) || \ + (defined(__ARM8M_BASELINE__) && (__CORE__ == __ARM8M_BASELINE__)) +#define SEGGER_RTT_LOCK() \ + { \ + unsigned int _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_PRIMASK(); \ + __set_PRIMASK(1); + +#define SEGGER_RTT_UNLOCK() \ + __set_PRIMASK(_SEGGER_RTT__LockState); \ + } +#elif (defined(__ARM7EM__) && (__CORE__ == __ARM7EM__)) || \ + (defined(__ARM7M__) && (__CORE__ == __ARM7M__)) || \ + (defined(__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__)) || \ + (defined(__ARM8M_MAINLINE__) && (__CORE__ == __ARM8M_MAINLINE__)) +#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY +#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) +#endif +#define SEGGER_RTT_LOCK() \ + { \ + unsigned int _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_BASEPRI(); \ + __set_BASEPRI(SEGGER_RTT_MAX_INTERRUPT_PRIORITY); + +#define SEGGER_RTT_UNLOCK() \ + __set_BASEPRI(_SEGGER_RTT__LockState); \ + } +#elif (defined(__ARM7A__) && (__CORE__ == __ARM7A__)) || \ + (defined(__ARM7R__) && (__CORE__ == __ARM7R__)) +#define SEGGER_RTT_LOCK() \ + { \ + unsigned int _SEGGER_RTT__LockState; \ + __asm volatile( \ + "mrs r1, CPSR \n\t" \ + "mov %0, r1 \n\t" \ + "orr r1, r1, #0xC0 \n\t" \ + "msr CPSR_c, r1 \n\t" \ + : "=r"(_SEGGER_RTT__LockState) \ + : \ + : "r1", "cc"); + +#define SEGGER_RTT_UNLOCK() \ + __asm volatile( \ + "mov r0, %0 \n\t" \ + "mrs r1, CPSR \n\t" \ + "bic r1, r1, #0xC0 \n\t" \ + "and r0, r0, #0xC0 \n\t" \ + "orr r1, r1, r0 \n\t" \ + "msr CPSR_c, r1 \n\t" \ + : \ + : "r"(_SEGGER_RTT__LockState) \ + : "r0", "r1", "cc"); \ + } +#endif +#endif + +/********************************************************************* + * + * RTT lock configuration for IAR RX + */ +#ifdef __ICCRX__ +#define SEGGER_RTT_LOCK() \ + { \ + unsigned long _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_interrupt_state(); \ + __disable_interrupt(); + +#define SEGGER_RTT_UNLOCK() \ + __set_interrupt_state(_SEGGER_RTT__LockState); \ + } +#endif + +/********************************************************************* + * + * RTT lock configuration for IAR RL78 + */ +#ifdef __ICCRL78__ +#define SEGGER_RTT_LOCK() \ + { \ + __istate_t _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_interrupt_state(); \ + __disable_interrupt(); + +#define SEGGER_RTT_UNLOCK() \ + __set_interrupt_state(_SEGGER_RTT__LockState); \ + } +#endif + +/********************************************************************* + * + * RTT lock configuration for KEIL ARM + */ +#ifdef __CC_ARM +#if (defined __TARGET_ARCH_6S_M) +#define SEGGER_RTT_LOCK() \ + { \ + unsigned int _SEGGER_RTT__LockState; \ + register unsigned char _SEGGER_RTT__PRIMASK __asm("primask"); \ + _SEGGER_RTT__LockState = _SEGGER_RTT__PRIMASK; \ + _SEGGER_RTT__PRIMASK = 1u; \ + __schedule_barrier(); + +#define SEGGER_RTT_UNLOCK() \ + _SEGGER_RTT__PRIMASK = _SEGGER_RTT__LockState; \ + __schedule_barrier(); \ + } +#elif (defined(__TARGET_ARCH_7_M) || defined(__TARGET_ARCH_7E_M)) +#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY +#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) +#endif +#define SEGGER_RTT_LOCK() \ + { \ + unsigned int _SEGGER_RTT__LockState; \ + register unsigned char BASEPRI __asm("basepri"); \ + _SEGGER_RTT__LockState = BASEPRI; \ + BASEPRI = SEGGER_RTT_MAX_INTERRUPT_PRIORITY; \ + __schedule_barrier(); + +#define SEGGER_RTT_UNLOCK() \ + BASEPRI = _SEGGER_RTT__LockState; \ + __schedule_barrier(); \ + } +#endif +#endif + +/********************************************************************* + * + * RTT lock configuration for TI ARM + */ +#ifdef __TI_ARM__ +#if defined(__TI_ARM_V6M0__) +#define SEGGER_RTT_LOCK() \ + { \ + unsigned int _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = __get_PRIMASK(); \ + __set_PRIMASK(1); + +#define SEGGER_RTT_UNLOCK() \ + __set_PRIMASK(_SEGGER_RTT__LockState); \ + } +#elif (defined(__TI_ARM_V7M3__) || defined(__TI_ARM_V7M4__)) +#ifndef SEGGER_RTT_MAX_INTERRUPT_PRIORITY +#define SEGGER_RTT_MAX_INTERRUPT_PRIORITY (0x20) +#endif +#define SEGGER_RTT_LOCK() \ + { \ + unsigned int _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = _set_interrupt_priority(SEGGER_RTT_MAX_INTERRUPT_PRIORITY); + +#define SEGGER_RTT_UNLOCK() \ + _set_interrupt_priority(_SEGGER_RTT__LockState); \ + } +#endif +#endif + +/********************************************************************* + * + * RTT lock configuration for CCRX + */ +#ifdef __RX +#include +#define SEGGER_RTT_LOCK() \ + { \ + unsigned long _SEGGER_RTT__LockState; \ + _SEGGER_RTT__LockState = get_psw() & 0x010000; \ + clrpsw_i(); + +#define SEGGER_RTT_UNLOCK() \ + set_psw(get_psw() | _SEGGER_RTT__LockState); \ + } +#endif + +/********************************************************************* + * + * RTT lock configuration for embOS Simulation on Windows + * (Can also be used for generic RTT locking with embOS) + */ +#if defined(WIN32) || defined(SEGGER_RTT_LOCK_EMBOS) + +void OS_SIM_EnterCriticalSection(void); +void OS_SIM_LeaveCriticalSection(void); + +#define SEGGER_RTT_LOCK() \ + { \ + OS_SIM_EnterCriticalSection(); + +#define SEGGER_RTT_UNLOCK() \ + OS_SIM_LeaveCriticalSection(); \ + } +#endif + +/********************************************************************* + * + * RTT lock configuration fallback + */ +#ifndef SEGGER_RTT_LOCK +#define SEGGER_RTT_LOCK() // Lock RTT (nestable) (i.e. disable interrupts) +#endif + +#ifndef SEGGER_RTT_UNLOCK +#define SEGGER_RTT_UNLOCK() // Unlock RTT (nestable) (i.e. enable previous interrupt lock state) +#endif + +#endif +/*************************** End of file ****************************/ diff --git a/ut-robomaster/src/communication/rtt/SEGGER_RTT_printf.c b/ut-robomaster/src/communication/rtt/SEGGER_RTT_printf.c new file mode 100644 index 00000000..f3979482 --- /dev/null +++ b/ut-robomaster/src/communication/rtt/SEGGER_RTT_printf.c @@ -0,0 +1,621 @@ +/********************************************************************* +* SEGGER Microcontroller GmbH * +* The Embedded Experts * +********************************************************************** +* * +* (c) 1995 - 2019 SEGGER Microcontroller GmbH * +* * +* www.segger.com Support: support@segger.com * +* * +********************************************************************** +* * +* SEGGER RTT * Real Time Transfer for embedded targets * +* * +********************************************************************** +* * +* All rights reserved. * +* * +* SEGGER strongly recommends to not make any changes * +* to or modify the source code of this software in order to stay * +* compatible with the RTT protocol and J-Link. * +* * +* Redistribution and use in source and binary forms, with or * +* without modification, are permitted provided that the following * +* condition is met: * +* * +* o Redistributions of source code must retain the above copyright * +* notice, this condition and the following disclaimer. * +* * +* 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 SEGGER Microcontroller 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. * +* * +********************************************************************** +---------------------------END-OF-HEADER------------------------------ +File : SEGGER_RTT_printf.c +Purpose : Replacement for printf to write formatted data via RTT +Revision: $Rev: 17697 $ +---------------------------------------------------------------------- +*/ +#include "SEGGER_RTT.h" +#include "SEGGER_RTT_Conf.h" + +/********************************************************************* + * + * Defines, configurable + * + ********************************************************************** + */ + +#ifndef SEGGER_RTT_PRINTF_BUFFER_SIZE +#define SEGGER_RTT_PRINTF_BUFFER_SIZE (64) +#endif + +#include +#include + +#define FORMAT_FLAG_LEFT_JUSTIFY (1u << 0) +#define FORMAT_FLAG_PAD_ZERO (1u << 1) +#define FORMAT_FLAG_PRINT_SIGN (1u << 2) +#define FORMAT_FLAG_ALTERNATE (1u << 3) + +/********************************************************************* + * + * Types + * + ********************************************************************** + */ + +typedef struct +{ + char* pBuffer; + unsigned BufferSize; + unsigned Cnt; + + int ReturnValue; + + unsigned RTTBufferIndex; +} SEGGER_RTT_PRINTF_DESC; + +/********************************************************************* + * + * Function prototypes + * + ********************************************************************** + */ + +/********************************************************************* + * + * Static code + * + ********************************************************************** + */ +/********************************************************************* + * + * _StoreChar + */ +static void _StoreChar(SEGGER_RTT_PRINTF_DESC* p, char c) +{ + unsigned Cnt; + + Cnt = p->Cnt; + if ((Cnt + 1u) <= p->BufferSize) + { + *(p->pBuffer + Cnt) = c; + p->Cnt = Cnt + 1u; + p->ReturnValue++; + } + // + // Write part of string, when the buffer is full + // + if (p->Cnt == p->BufferSize) + { + if (SEGGER_RTT_Write(p->RTTBufferIndex, p->pBuffer, p->Cnt) != p->Cnt) + { + p->ReturnValue = -1; + } + else + { + p->Cnt = 0u; + } + } +} + +/********************************************************************* + * + * _PrintUnsigned + */ +static void _PrintUnsigned( + SEGGER_RTT_PRINTF_DESC* pBufferDesc, + unsigned v, + unsigned Base, + unsigned NumDigits, + unsigned FieldWidth, + unsigned FormatFlags) +{ + static const char _aV2C[16] = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + unsigned Div; + unsigned Digit; + unsigned Number; + unsigned Width; + char c; + + Number = v; + Digit = 1u; + // + // Get actual field width + // + Width = 1u; + while (Number >= Base) + { + Number = (Number / Base); + Width++; + } + if (NumDigits > Width) + { + Width = NumDigits; + } + // + // Print leading chars if necessary + // + if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) + { + if (FieldWidth != 0u) + { + if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && (NumDigits == 0u)) + { + c = '0'; + } + else + { + c = ' '; + } + while ((FieldWidth != 0u) && (Width < FieldWidth)) + { + FieldWidth--; + _StoreChar(pBufferDesc, c); + if (pBufferDesc->ReturnValue < 0) + { + break; + } + } + } + } + if (pBufferDesc->ReturnValue >= 0) + { + // + // Compute Digit. + // Loop until Digit has the value of the highest digit required. + // Example: If the output is 345 (Base 10), loop 2 times until Digit is 100. + // + while (1) + { + if (NumDigits > 1u) + { // User specified a min number of digits to print? => Make sure we loop at least that + // often, before checking anything else (> 1 check avoids problems with NumDigits + // being signed / unsigned) + NumDigits--; + } + else + { + Div = v / Digit; + if (Div < Base) + { // Is our divider big enough to extract the highest digit from value? => Done + break; + } + } + Digit *= Base; + } + // + // Output digits + // + do + { + Div = v / Digit; + v -= Div * Digit; + _StoreChar(pBufferDesc, _aV2C[Div]); + if (pBufferDesc->ReturnValue < 0) + { + break; + } + Digit /= Base; + } while (Digit); + // + // Print trailing spaces if necessary + // + if ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == FORMAT_FLAG_LEFT_JUSTIFY) + { + if (FieldWidth != 0u) + { + while ((FieldWidth != 0u) && (Width < FieldWidth)) + { + FieldWidth--; + _StoreChar(pBufferDesc, ' '); + if (pBufferDesc->ReturnValue < 0) + { + break; + } + } + } + } + } +} + +/********************************************************************* + * + * _PrintInt + */ +static void _PrintInt( + SEGGER_RTT_PRINTF_DESC* pBufferDesc, + int v, + unsigned Base, + unsigned NumDigits, + unsigned FieldWidth, + unsigned FormatFlags) +{ + unsigned Width; + int Number; + + Number = (v < 0) ? -v : v; + + // + // Get actual field width + // + Width = 1u; + while (Number >= (int)Base) + { + Number = (Number / (int)Base); + Width++; + } + if (NumDigits > Width) + { + Width = NumDigits; + } + if ((FieldWidth > 0u) && + ((v < 0) || ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN))) + { + FieldWidth--; + } + + // + // Print leading spaces if necessary + // + if ((((FormatFlags & FORMAT_FLAG_PAD_ZERO) == 0u) || (NumDigits != 0u)) && + ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u)) + { + if (FieldWidth != 0u) + { + while ((FieldWidth != 0u) && (Width < FieldWidth)) + { + FieldWidth--; + _StoreChar(pBufferDesc, ' '); + if (pBufferDesc->ReturnValue < 0) + { + break; + } + } + } + } + // + // Print sign if necessary + // + if (pBufferDesc->ReturnValue >= 0) + { + if (v < 0) + { + v = -v; + _StoreChar(pBufferDesc, '-'); + } + else if ((FormatFlags & FORMAT_FLAG_PRINT_SIGN) == FORMAT_FLAG_PRINT_SIGN) + { + _StoreChar(pBufferDesc, '+'); + } + else + { + } + if (pBufferDesc->ReturnValue >= 0) + { + // + // Print leading zeros if necessary + // + if (((FormatFlags & FORMAT_FLAG_PAD_ZERO) == FORMAT_FLAG_PAD_ZERO) && + ((FormatFlags & FORMAT_FLAG_LEFT_JUSTIFY) == 0u) && (NumDigits == 0u)) + { + if (FieldWidth != 0u) + { + while ((FieldWidth != 0u) && (Width < FieldWidth)) + { + FieldWidth--; + _StoreChar(pBufferDesc, '0'); + if (pBufferDesc->ReturnValue < 0) + { + break; + } + } + } + } + if (pBufferDesc->ReturnValue >= 0) + { + // + // Print number without sign + // + _PrintUnsigned(pBufferDesc, (unsigned)v, Base, NumDigits, FieldWidth, FormatFlags); + } + } + } +} + +/********************************************************************* + * + * Public code + * + ********************************************************************** + */ +/********************************************************************* + * + * SEGGER_RTT_vprintf + * + * Function description + * Stores a formatted string in SEGGER RTT control block. + * This data is read by the host. + * + * Parameters + * BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal") + * sFormat Pointer to format string + * pParamList Pointer to the list of arguments for the format string + * + * Return values + * >= 0: Number of bytes which have been stored in the "Up"-buffer. + * < 0: Error + */ +int SEGGER_RTT_vprintf(unsigned BufferIndex, const char* sFormat, va_list* pParamList) +{ + char c; + SEGGER_RTT_PRINTF_DESC BufferDesc; + int v; + unsigned NumDigits; + unsigned FormatFlags; + unsigned FieldWidth; + char acBuffer[SEGGER_RTT_PRINTF_BUFFER_SIZE]; + + BufferDesc.pBuffer = acBuffer; + BufferDesc.BufferSize = SEGGER_RTT_PRINTF_BUFFER_SIZE; + BufferDesc.Cnt = 0u; + BufferDesc.RTTBufferIndex = BufferIndex; + BufferDesc.ReturnValue = 0; + + do + { + c = *sFormat; + sFormat++; + if (c == 0u) + { + break; + } + if (c == '%') + { + // + // Filter out flags + // + FormatFlags = 0u; + v = 1; + do + { + c = *sFormat; + switch (c) + { + case '-': + FormatFlags |= FORMAT_FLAG_LEFT_JUSTIFY; + sFormat++; + break; + case '0': + FormatFlags |= FORMAT_FLAG_PAD_ZERO; + sFormat++; + break; + case '+': + FormatFlags |= FORMAT_FLAG_PRINT_SIGN; + sFormat++; + break; + case '#': + FormatFlags |= FORMAT_FLAG_ALTERNATE; + sFormat++; + break; + default: + v = 0; + break; + } + } while (v); + // + // filter out field with + // + FieldWidth = 0u; + do + { + c = *sFormat; + if ((c < '0') || (c > '9')) + { + break; + } + sFormat++; + FieldWidth = (FieldWidth * 10u) + ((unsigned)c - '0'); + } while (1); + + // + // Filter out precision (number of digits to display) + // + NumDigits = 0u; + c = *sFormat; + if (c == '.') + { + sFormat++; + do + { + c = *sFormat; + if ((c < '0') || (c > '9')) + { + break; + } + sFormat++; + NumDigits = NumDigits * 10u + ((unsigned)c - '0'); + } while (1); + } + // + // Filter out length modifier + // + c = *sFormat; + do + { + if ((c == 'l') || (c == 'h')) + { + sFormat++; + c = *sFormat; + } + else + { + break; + } + } while (1); + // + // Handle specifiers + // + switch (c) + { + case 'c': + { + char c0; + v = va_arg(*pParamList, int); + c0 = (char)v; + _StoreChar(&BufferDesc, c0); + break; + } + case 'd': + v = va_arg(*pParamList, int); + _PrintInt(&BufferDesc, v, 10u, NumDigits, FieldWidth, FormatFlags); + break; + case 'u': + v = va_arg(*pParamList, int); + _PrintUnsigned( + &BufferDesc, + (unsigned)v, + 10u, + NumDigits, + FieldWidth, + FormatFlags); + break; + case 'x': + case 'X': + v = va_arg(*pParamList, int); + _PrintUnsigned( + &BufferDesc, + (unsigned)v, + 16u, + NumDigits, + FieldWidth, + FormatFlags); + break; + case 's': + { + const char* s = va_arg(*pParamList, const char*); + if (s == NULL) + { + s = "(NULL)"; // Print (NULL) instead of crashing or breaking, as it is + // more informative to the user. + } + do + { + c = *s; + s++; + if (c == '\0') + { + break; + } + _StoreChar(&BufferDesc, c); + } while (BufferDesc.ReturnValue >= 0); + } + break; + case 'p': + v = va_arg(*pParamList, int); + _PrintUnsigned(&BufferDesc, (unsigned)v, 16u, 8u, 8u, 0u); + break; + case '%': + _StoreChar(&BufferDesc, '%'); + break; + default: + break; + } + sFormat++; + } + else + { + _StoreChar(&BufferDesc, c); + } + } while (BufferDesc.ReturnValue >= 0); + + if (BufferDesc.ReturnValue > 0) + { + // + // Write remaining data, if any + // + if (BufferDesc.Cnt != 0u) + { + SEGGER_RTT_Write(BufferIndex, acBuffer, BufferDesc.Cnt); + } + BufferDesc.ReturnValue += (int)BufferDesc.Cnt; + } + return BufferDesc.ReturnValue; +} + +/********************************************************************* + * + * SEGGER_RTT_printf + * + * Function description + * Stores a formatted string in SEGGER RTT control block. + * This data is read by the host. + * + * Parameters + * BufferIndex Index of "Up"-buffer to be used. (e.g. 0 for "Terminal") + * sFormat Pointer to format string, followed by the arguments for conversion + * + * Return values + * >= 0: Number of bytes which have been stored in the "Up"-buffer. + * < 0: Error + * + * Notes + * (1) Conversion specifications have following syntax: + * %[flags][FieldWidth][.Precision]ConversionSpecifier + * (2) Supported flags: + * -: Left justify within the field width + * +: Always print sign extension for signed conversions + * 0: Pad with 0 instead of spaces. Ignored when using '-'-flag or precision + * Supported conversion specifiers: + * c: Print the argument as one char + * d: Print the argument as a signed integer + * u: Print the argument as an unsigned integer + * x: Print the argument as an hexadecimal integer + * s: Print the string pointed to by the argument + * p: Print the argument as an 8-digit hexadecimal integer. (Argument shall be a pointer to + * void.) + */ +int SEGGER_RTT_printf(unsigned BufferIndex, const char* sFormat, ...) +{ + int r; + va_list ParamList; + + va_start(ParamList, sFormat); + r = SEGGER_RTT_vprintf(BufferIndex, sFormat, &ParamList); + va_end(ParamList); + return r; +} +/*************************** End of file ****************************/ diff --git a/ut-robomaster/src/main.cpp b/ut-robomaster/src/main.cpp index 54acf0c7..18ac04c9 100644 --- a/ut-robomaster/src/main.cpp +++ b/ut-robomaster/src/main.cpp @@ -1,114 +1,114 @@ -#ifdef PLATFORM_HOSTED -/* hosted environment (simulator) includes --------------------------------- */ -#include - -#include "tap/communication/tcp-server/tcp_server.hpp" -#include "tap/motor/motorsim/sim_handler.hpp" -#endif - -#include "modm/architecture/interface/delay.hpp" - -#include "board.hpp" - -/* arch includes ------------------------------------------------------------*/ -#include "tap/architecture/periodic_timer.hpp" -#include "tap/architecture/profiler.hpp" - -/* communication includes ---------------------------------------------------*/ -#include "drivers.hpp" -#include "drivers_singleton.hpp" - -/* error handling includes --------------------------------------------------*/ -#include "tap/errors/create_errors.hpp" - -/* control includes ---------------------------------------------------------*/ -#include "tap/architecture/clock.hpp" - -#include "robots/robot_constants.hpp" -#include "robots/robot_control.hpp" - -/* define timers here -------------------------------------------------------*/ -tap::arch::PeriodicMilliTimer refreshTimer(REFRESH_PERIOD); - -// Place any sort of input/output initialization here. For example, place -// serial init stuff here. -static void initializeIo(src::Drivers *drivers); - -// Anything that you would like to be called place here. It will be called -// very frequently. Use PeriodicMilliTimers if you don't want something to be -// called as frequently. -static void updateIo(src::Drivers *drivers); - -using namespace tap::gpio; - -int main() -{ -#ifdef PLATFORM_HOSTED - std::cout << "Simulation starting..." << std::endl; -#endif - - /* - * NOTE: We are using DoNotUse_getDrivers here because in the main - * robot loop we must access the singleton drivers to update - * IO states and run the scheduler. - */ - src::Drivers *drivers = src::DoNotUse_getDrivers(); - - Board::initialize(); - initializeIo(drivers); - Board::initialize_i2c(); - control::initSubsystemCommands(drivers); - -#ifdef PLATFORM_HOSTED - tap::motorsim::SimHandler::resetMotorSims(); - // Blocking call, waits until Windows Simulator connects. - tap::communication::TCPServer::MainServer()->getConnection(); -#endif - - while (1) - { - // do this as fast as you can - PROFILE(drivers->profiler, updateIo, (drivers)); - - if (refreshTimer.execute()) - { - PROFILE(drivers->profiler, drivers->bmi088.periodicIMUUpdate, ()); - PROFILE(drivers->profiler, drivers->commandScheduler.run, ()); - PROFILE(drivers->profiler, drivers->djiMotorTxHandler.encodeAndSendCanData, ()); - PROFILE(drivers->profiler, drivers->terminalSerial.update, ()); - } - - modm::delay_us(10); - } - return 0; -} - -static void initializeIo(src::Drivers *drivers) -{ - drivers->analog.init(); - drivers->pwm.init(); - drivers->digital.init(); - drivers->leds.init(); - drivers->can.initialize(); - drivers->errorController.init(); - drivers->remote.initialize(); - drivers->refSerial.initialize(); - // drivers->cvBoard.initialize(); - drivers->terminalSerial.initialize(); - drivers->schedulerTerminalHandler.init(); - drivers->djiMotorTerminalSerialHandler.init(); - drivers->bmi088.initialize(IMU_SAMPLE_FREQUENCY, IMU_KP, IMU_KI); - drivers->bmi088.requestRecalibration(); -} - -static void updateIo(src::Drivers *drivers) -{ -#ifdef PLATFORM_HOSTED - tap::motorsim::SimHandler::updateSims(); -#endif - - drivers->canRxHandler.pollCanData(); - drivers->refSerial.updateSerial(); - // drivers->cvBoard.updateSerial(); - drivers->remote.read(); -} +#ifdef PLATFORM_HOSTED +/* hosted environment (simulator) includes --------------------------------- */ +#include + +#include "tap/communication/tcp-server/tcp_server.hpp" +#include "tap/motor/motorsim/sim_handler.hpp" +#endif + +#include "modm/architecture/interface/delay.hpp" + +#include "board.hpp" + +/* arch includes ------------------------------------------------------------*/ +#include "tap/architecture/periodic_timer.hpp" +#include "tap/architecture/profiler.hpp" + +/* communication includes ---------------------------------------------------*/ +#include "drivers.hpp" +#include "drivers_singleton.hpp" + +/* error handling includes --------------------------------------------------*/ +#include "tap/errors/create_errors.hpp" + +/* control includes ---------------------------------------------------------*/ +#include "tap/architecture/clock.hpp" + +#include "robots/robot_constants.hpp" +#include "robots/robot_control.hpp" + +/* define timers here -------------------------------------------------------*/ +tap::arch::PeriodicMilliTimer refreshTimer(REFRESH_PERIOD); + +// Place any sort of input/output initialization here. For example, place +// serial init stuff here. +static void initializeIo(src::Drivers *drivers); + +// Anything that you would like to be called place here. It will be called +// very frequently. Use PeriodicMilliTimers if you don't want something to be +// called as frequently. +static void updateIo(src::Drivers *drivers); + +using namespace tap::gpio; + +int main() +{ +#ifdef PLATFORM_HOSTED + std::cout << "Simulation starting..." << std::endl; +#endif + + /* + * NOTE: We are using DoNotUse_getDrivers here because in the main + * robot loop we must access the singleton drivers to update + * IO states and run the scheduler. + */ + src::Drivers *drivers = src::DoNotUse_getDrivers(); + + Board::initialize(); + initializeIo(drivers); + Board::initialize_i2c(); + control::initSubsystemCommands(drivers); + +#ifdef PLATFORM_HOSTED + tap::motorsim::SimHandler::resetMotorSims(); + // Blocking call, waits until Windows Simulator connects. + tap::communication::TCPServer::MainServer()->getConnection(); +#endif + + while (1) + { + // do this as fast as you can + PROFILE(drivers->profiler, updateIo, (drivers)); + + if (refreshTimer.execute()) + { + PROFILE(drivers->profiler, drivers->bmi088.periodicIMUUpdate, ()); + PROFILE(drivers->profiler, drivers->commandScheduler.run, ()); + PROFILE(drivers->profiler, drivers->djiMotorTxHandler.encodeAndSendCanData, ()); + PROFILE(drivers->profiler, drivers->terminalSerial.update, ()); + } + + modm::delay_us(10); + } + return 0; +} + +static void initializeIo(src::Drivers *drivers) +{ + drivers->analog.init(); + drivers->pwm.init(); + drivers->digital.init(); + drivers->leds.init(); + drivers->can.initialize(); + drivers->errorController.init(); + drivers->remote.initialize(); + drivers->refSerial.initialize(); + // drivers->cvBoard.initialize(); + drivers->terminalSerial.initialize(); + drivers->schedulerTerminalHandler.init(); + drivers->djiMotorTerminalSerialHandler.init(); + drivers->bmi088.initialize(IMU_SAMPLE_FREQUENCY, IMU_KP, IMU_KI); + drivers->bmi088.requestRecalibration(); +} + +static void updateIo(src::Drivers *drivers) +{ +#ifdef PLATFORM_HOSTED + tap::motorsim::SimHandler::updateSims(); +#endif + + drivers->canRxHandler.pollCanData(); + drivers->refSerial.updateSerial(); + // drivers->cvBoard.updateSerial(); + drivers->remote.read(); +} diff --git a/ut-robomaster/test/SConscript b/ut-robomaster/test/SConscript index 63961f78..22d4a5d3 100644 --- a/ut-robomaster/test/SConscript +++ b/ut-robomaster/test/SConscript @@ -2,6 +2,7 @@ from os.path import abspath Import("env") Import("args") +Import("c_flags") Import("sources") @@ -9,8 +10,8 @@ if args["TARGET_ENV"] == "tests": print("etss") env_cpy = env.Clone() - # Append on the global robot target build flag - env_cpy.AppendUnique(CCFLAGS=["-D " + args["ROBOT_TYPE"]]) + # Append global build flags + env_cpy.AppendUnique(CFLAGS=[f"-D {x}" for x in c_flags]) rawSrcs = env_cpy.FindSourceFiles(".")