diff --git a/demos/STM32/RT-XHAL-STM32G474RE-NUCLEO64/Makefile b/demos/STM32/RT-XHAL-STM32G474RE-NUCLEO64/Makefile
index 6f824ef57..aeb722440 100644
--- a/demos/STM32/RT-XHAL-STM32G474RE-NUCLEO64/Makefile
+++ b/demos/STM32/RT-XHAL-STM32G474RE-NUCLEO64/Makefile
@@ -100,6 +100,7 @@ include $(CHIBIOS)/os/license/license.mk
include $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_stm32g4xx.mk
# Common files.
include $(CHIBIOS)/os/common/oop/oop.mk
+include $(CHIBIOS)/os/common/lib/lib.mk
# HAL-OSAL files (optional).
include $(CHIBIOS)/os/xhal/hal.mk
include $(CHIBIOS)/os/xhal/ports/STM32/STM32G4xx/platform.mk
diff --git a/os/common/lib/codegen/config.fmpp b/os/common/lib/codegen/config.fmpp
new file mode 100644
index 000000000..b8f49c449
--- /dev/null
+++ b/os/common/lib/codegen/config.fmpp
@@ -0,0 +1,15 @@
+sourceRoot: ../../../../tools/ftl/processors/ccode
+outputRoot: ..
+dataRoot: .
+
+freemarkerLinks: {
+ ftllibs: ../../../../tools/ftl/libs
+}
+
+data : {
+ xml:xml (
+ modules.xml
+ {
+ }
+ )
+}
diff --git a/os/common/lib/codegen/memstreams.xml b/os/common/lib/codegen/memstreams.xml
new file mode 100644
index 000000000..b755d0e28
--- /dev/null
+++ b/os/common/lib/codegen/memstreams.xml
@@ -0,0 +1,128 @@
+
+
+ Memory streams class.
+
+ oop_base_object.xml
+ oop_sequential_stream.xml
+
+
+
+ string.h
+ oop_base_object.h
+ oop_sequential_stream.h
+
+
+
+ Memory streams class.
+
+
+
+
+ size - self->eos < n) {
+ n = self->size - self->eos;
+}
+
+memcpy(self->buffer + self->eos, bp, n);
+self->eos += n;
+
+return n;]]>
+
+
+ eos - self->offset < n) {
+ n = self->eos - self->offset;
+}
+
+memcpy(bp, self->buffer + self->offset, n);
+self->offset += n;
+
+return n;]]>
+
+
+ size - self->eos <= 0U) {
+ return STM_RESET;
+}
+
+*(self->buffer + self->eos) = b;
+self->eos++;
+
+return STM_OK;]]>
+
+
+ eos - self->offset <= 0U) {
+ return STM_RESET;
+}
+
+b = *(self->buffer + self->offset);
+self->offset++;
+
+return b;]]>
+
+
+ offset <= 0U)) {
+ return STM_RESET;
+}
+
+self->offset--;
+*(self->buffer + self->offset) = (uint8_t)b;
+
+return STM_OK;]]>
+
+
+
+
+
+ Pointer to the memory buffer.
+
+
+ Size of the memory buffer.
+
+
+ Current end of the stream.
+
+
+ Current read offset.
+
+
+
+
+ Pointer to the memory
+ buffer for the memory stream.
+
+ Size of the memory stream
+ buffer.
+
+ buffer = buffer;
+self->size = size;
+self->eos = eos;
+self->offset = 0U;]]>
+
+
+
+
+
+
+
+
+
+
+
diff --git a/os/common/lib/codegen/modules.xml b/os/common/lib/codegen/modules.xml
new file mode 100644
index 000000000..0a94ee7e9
--- /dev/null
+++ b/os/common/lib/codegen/modules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+]>
+
+
+
+ ../../oop/codegen
+
+
+ &memstreams;
+
+
diff --git a/os/common/lib/include/chprintf.h b/os/common/lib/include/chprintf.h
new file mode 100644
index 000000000..95d28bdc8
--- /dev/null
+++ b/os/common/lib/include/chprintf.h
@@ -0,0 +1,52 @@
+/*
+ ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file chprintf.h
+ * @brief Mini printf-like functionality.
+ *
+ * @addtogroup HAL_CHPRINTF
+ * @{
+ */
+
+#ifndef CHPRINTF_H
+#define CHPRINTF_H
+
+#include
+
+#include "oop_sequential_stream.h"
+
+/**
+ * @brief Float type support.
+ */
+#if !defined(CHPRINTF_USE_FLOAT) || defined(__DOXYGEN__)
+#define CHPRINTF_USE_FLOAT FALSE
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ int chvprintf(sequential_stream_i *chp, const char *fmt, va_list ap);
+ int chprintf(sequential_stream_i *chp, const char *fmt, ...);
+ int chsnprintf(char *str, size_t size, const char *fmt, ...);
+ int chvsnprintf(char *str, size_t size, const char *fmt, va_list ap);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CHPRINTF_H */
+
+/** @} */
diff --git a/os/common/lib/include/errcodes.h b/os/common/lib/include/errcodes.h
new file mode 100644
index 000000000..01b6b585c
--- /dev/null
+++ b/os/common/lib/include/errcodes.h
@@ -0,0 +1,128 @@
+/*
+ ChibiOS - Copyright (C) 2006,2007,2008,2009,2010,2011,2012,2013,2014,
+ 2015,2016,2017,2018,2019,2020,2021 Giovanni Di Sirio.
+
+ This file is part of ChibiOS.
+
+ ChibiOS is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation version 3 of the License.
+
+ ChibiOS is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+/**
+ * @file errcodes.h
+ * @brief Errors handling header file.
+ *
+ * @addtogroup UTILS_ERRCODES
+ * @{
+ */
+
+#ifndef ERRCODES_H
+#define ERRCODES_H
+
+#include
+
+/*===========================================================================*/
+/* Module constants. */
+/*===========================================================================*/
+
+/**
+ * @name Error codes
+ * @{
+ */
+#define CH_RET_SUCCESS (int)MSG_OK /* Success */
+#define CH_RET_TIMEOUT (int)MSG_TIMEOUT /* Timeout */
+#define CH_RET_INNER_ERROR (int)-3 /* Unexpected condition */
+/** @} */
+
+/**
+ * @name Extra error codes mapped on Posix errors
+ * @{
+ */
+#define CH_RET_ENOENT CH_ENCODE_ERROR(ENOENT) /* No such file or directory */
+#define CH_RET_EIO CH_ENCODE_ERROR(EIO) /* I/O error */
+#define CH_RET_EBADF CH_ENCODE_ERROR(EBADF) /* Bad file number */
+#define CH_RET_ENOMEM CH_ENCODE_ERROR(ENOMEM) /* Not enough space */
+#define CH_RET_EACCES CH_ENCODE_ERROR(EACCES) /* Permission denied */
+#define CH_RET_EFAULT CH_ENCODE_ERROR(EACCES) /* Bad address */
+#define CH_RET_EEXIST CH_ENCODE_ERROR(EEXIST) /* File exists */
+#define CH_RET_ENOTDIR CH_ENCODE_ERROR(ENOTDIR) /* Not a directory */
+#define CH_RET_EISDIR CH_ENCODE_ERROR(EISDIR) /* Is a directory */
+#define CH_RET_EINVAL CH_ENCODE_ERROR(EINVAL) /* Invalid argument */
+#define CH_RET_EMFILE CH_ENCODE_ERROR(EMFILE) /* Too many open files in process */
+#define CH_RET_ENFILE CH_ENCODE_ERROR(ENFILE) /* Too many open files in system */
+#define CH_RET_EFBIG CH_ENCODE_ERROR(EFBIG) /* File too large */
+#define CH_RET_ENOSPC CH_ENCODE_ERROR(ENOSPC) /* No space left on device */
+#define CH_RET_ESPIPE CH_ENCODE_ERROR(ESPIPE) /* Illegal seek */
+#define CH_RET_EROFS CH_ENCODE_ERROR(EROFS) /* Read-only file system */
+#define CH_RET_ERANGE CH_ENCODE_ERROR(ERANGE) /* Result too large */
+#define CH_RET_ENAMETOOLONG CH_ENCODE_ERROR(ENAMETOOLONG)/* File or path name too long */
+#define CH_RET_ENOSYS CH_ENCODE_ERROR(ENOSYS) /* Syscall not implemented */
+#define CH_RET_EOVERFLOW CH_ENCODE_ERROR(EOVERFLOW) /* File offset overflow */
+#define CH_RET_ENOEXEC CH_ENCODE_ERROR(ENOEXEC) /* Invalid executable */
+#define CH_RET_EXDEV CH_ENCODE_ERROR(EXDEV) /* Not same volume */
+/** @} */
+
+/*===========================================================================*/
+/* Module pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module data structures and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module macros. */
+/*===========================================================================*/
+
+/**
+ * @name Errors handling macros
+ * @{
+ */
+#define CH_ERRORS_MASK (int)0xFF
+#define CH_ENCODE_ERROR(posixerr) (~CH_ERRORS_MASK | (int)(posixerr))
+#define CH_DECODE_ERROR(err) ((int)(err) & CH_ERRORS_MASK)
+#define CH_RET_IS_ERROR(x) (((int)(x) & ~CH_ERRORS_MASK) == ~CH_ERRORS_MASK)
+
+#define CH_BREAK_ON_ERROR(err) \
+ if (CH_RET_IS_ERROR(err)) break
+
+#define CH_RETURN_ON_ERROR(err) do { \
+ int __ret = (err); \
+ if (CH_RET_IS_ERROR(__ret)) { \
+ return __ret; \
+ } \
+} while (false)
+/** @} */
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/*===========================================================================*/
+/* Module inline functions. */
+/*===========================================================================*/
+
+#endif /* ERRCODES_H */
+
+/** @} */
diff --git a/os/common/lib/include/memstreams.h b/os/common/lib/include/memstreams.h
new file mode 100644
index 000000000..dedc4dded
--- /dev/null
+++ b/os/common/lib/include/memstreams.h
@@ -0,0 +1,164 @@
+/*
+ ChibiOS - Copyright (C) 2006..2023 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file memstreams.h
+ * @brief Generated Memory Streams header.
+ * @note This is a generated file, do not edit directly.
+ *
+ * @addtogroup MEMSTREAMS
+ * @brief Memory streams class.
+ * @{
+ */
+
+#ifndef MEMSTREAMS_H
+#define MEMSTREAMS_H
+
+#include
+#include "oop_base_object.h"
+#include "oop_sequential_stream.h"
+
+/*===========================================================================*/
+/* Module constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module pre-compile time settings. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @class memory_stream_c
+ * @extends base_object_c.
+ * @implements sequential_stream_i
+ *
+ * @brief Memory streams class.
+ * @details This class allows to manage a memory buffer using a stream
+ * interface.
+ *
+ * @name Class @p memory_stream_c structures
+ * @{
+ */
+
+/**
+ * @brief Type of a memory stream class.
+ */
+typedef struct memory_stream memory_stream_c;
+
+/**
+ * @brief Class @p memory_stream_c virtual methods table.
+ */
+struct memory_stream_vmt {
+ /* From base_object_c.*/
+ void (*dispose)(void *ip);
+ /* From memory_stream_c.*/
+};
+
+/**
+ * @brief Structure representing a memory stream class.
+ */
+struct memory_stream {
+ /**
+ * @brief Virtual Methods Table.
+ */
+ const struct memory_stream_vmt *vmt;
+ /**
+ * @brief Implemented interface @p sequential_stream_i.
+ */
+ sequential_stream_i stm;
+ /**
+ * @brief Pointer to the memory buffer.
+ */
+ uint8_t *buffer;
+ /**
+ * @brief Size of the memory buffer.
+ */
+ size_t size;
+ /**
+ * @brief Current end of the stream.
+ */
+ size_t eos;
+ /**
+ * @brief Current read offset.
+ */
+ size_t offset;
+};
+/** @} */
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ /* Methods of memory_stream_c.*/
+ void *__memstm_objinit_impl(void *ip, const void *vmt, uint8_t *buffer,
+ size_t size, size_t eos);
+ void __memstm_dispose_impl(void *ip);
+#ifdef __cplusplus
+}
+#endif
+
+/*===========================================================================*/
+/* Module inline functions. */
+/*===========================================================================*/
+
+/**
+ * @name Default constructor of memory_stream_c
+ * @{
+ */
+/**
+ * @memberof memory_stream_c
+ *
+ * @brief Default initialization function of @p memory_stream_c.
+ *
+ * @param[out] self Pointer to a @p memory_stream_c instance to be
+ * initialized.
+ * @param buffer Pointer to the memory buffer for the memory
+ * stream.
+ * @param size Size of the memory stream buffer.
+ * @param eos Initial End Of Stream offset. Normally you need
+ * to put this to zero for RAM buffers or equal to
+ * @p size for ROM streams.
+ * @return Pointer to the initialized object.
+ *
+ * @objinit
+ */
+CC_FORCE_INLINE
+static inline memory_stream_c *memstmObjectInit(memory_stream_c *self,
+ uint8_t *buffer, size_t size,
+ size_t eos) {
+ extern const struct memory_stream_vmt __memory_stream_vmt;
+
+ return __memstm_objinit_impl(self, &__memory_stream_vmt, buffer, size, eos);
+}
+/** @} */
+
+#endif /* MEMSTREAMS_H */
+
+/** @} */
diff --git a/os/common/lib/lib.mk b/os/common/lib/lib.mk
new file mode 100644
index 000000000..53444cae3
--- /dev/null
+++ b/os/common/lib/lib.mk
@@ -0,0 +1,9 @@
+# List of the ChibiOS common library modules.
+CLIBSRC = ${CHIBIOS}/os/common/lib/src/memstreams.c \
+ ${CHIBIOS}/os/common/lib/src/chprintf.c
+
+CLIBINC = ${CHIBIOS}/os/common/lib/include
+
+# Shared variables
+ALLCSRC += $(CLIBSRC)
+ALLINC += $(CLIBINC)
diff --git a/os/common/lib/src/chprintf.c b/os/common/lib/src/chprintf.c
new file mode 100644
index 000000000..0c97edf9b
--- /dev/null
+++ b/os/common/lib/src/chprintf.c
@@ -0,0 +1,470 @@
+/*
+ ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/*
+ Concepts and parts of this file have been contributed by Fabio Utzig,
+ chvprintf() added by Brent Roman.
+ */
+
+/**
+ * @file chprintf.c
+ * @brief Mini printf-like functionality.
+ *
+ * @addtogroup HAL_CHPRINTF
+ * @details Mini printf-like functionality.
+ * @{
+ */
+
+#include "chprintf.h"
+#include "memstreams.h"
+
+#define MAX_FILLER 11
+#define FLOAT_PRECISION 9
+
+static char *long_to_string_with_divisor(char *p,
+ long num,
+ unsigned radix,
+ long divisor) {
+ int i;
+ char *q;
+ long l, ll;
+
+ l = num;
+ if (divisor == 0) {
+ ll = num;
+ } else {
+ ll = divisor;
+ }
+
+ q = p + MAX_FILLER;
+ do {
+ i = (int)(l % radix);
+ i += '0';
+ if (i > '9') {
+ i += 'A' - '0' - 10;
+ }
+ *--q = i;
+ l /= radix;
+ } while ((ll /= radix) != 0);
+
+ i = (int)(p + MAX_FILLER - q);
+ do
+ *p++ = *q++;
+ while (--i);
+
+ return p;
+}
+
+static char *ch_ltoa(char *p, long num, unsigned radix) {
+
+ return long_to_string_with_divisor(p, num, radix, 0);
+}
+
+#if CHPRINTF_USE_FLOAT
+static const long pow10[FLOAT_PRECISION] = {
+ 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000
+};
+
+static char *ftoa(char *p, double num, unsigned long precision) {
+ long l;
+
+ if ((precision == 0) || (precision > FLOAT_PRECISION)) {
+ precision = FLOAT_PRECISION;
+ }
+ precision = pow10[precision - 1];
+
+ l = (long)num;
+ p = long_to_string_with_divisor(p, l, 10, 0);
+ *p++ = '.';
+ l = (long)((num - l) * precision);
+
+ return long_to_string_with_divisor(p, l, 10, precision / 10);
+}
+#endif
+
+/**
+ * @brief System formatted output function.
+ * @details This function implements a minimal @p vprintf()-like functionality
+ * with output on a @p BaseSequentialStream.
+ * The general parameters format is: %[-][width|*][.precision|*][l|L]p.
+ * The following parameter types (p) are supported:
+ * - x hexadecimal integer.
+ * - X hexadecimal long.
+ * - o octal integer.
+ * - O octal long.
+ * - d decimal signed integer.
+ * - D decimal signed long.
+ * - u decimal unsigned integer.
+ * - U decimal unsigned long.
+ * - c character.
+ * - s string.
+ * .
+ *
+ * @param[in] stmp pointer to a @p sequential_stream_i interface
+ * @param[in] fmt formatting string
+ * @param[in] ap list of parameters
+ * @return The number of bytes that would have been
+ * written to @p chp if no stream error occurs
+ *
+ * @api
+ */
+int chvprintf(sequential_stream_i *stmp, const char *fmt, va_list ap) {
+ char *p, *s, c, filler;
+ int i, precision, width;
+ int n = 0;
+ bool is_long, left_align, do_sign;
+ long l;
+#if CHPRINTF_USE_FLOAT
+ float f;
+ char tmpbuf[2*MAX_FILLER + 1];
+#else
+ char tmpbuf[MAX_FILLER + 1];
+#endif
+
+ while (true) {
+ c = *fmt++;
+ if (c == 0) {
+ return n;
+ }
+
+ if (c != '%') {
+ stmPut(stmp, (uint8_t)c);
+ n++;
+ continue;
+ }
+
+ p = tmpbuf;
+ s = tmpbuf;
+
+ /* Alignment mode.*/
+ left_align = false;
+ if (*fmt == '-') {
+ fmt++;
+ left_align = true;
+ }
+
+ /* Sign mode.*/
+ do_sign = false;
+ if (*fmt == '+') {
+ fmt++;
+ do_sign = true;
+ }
+
+ /* Filler mode.*/
+ filler = ' ';
+ if (*fmt == '0') {
+ fmt++;
+ filler = '0';
+ }
+
+ /* Width modifier.*/
+ if ( *fmt == '*') {
+ width = va_arg(ap, int);
+ ++fmt;
+ c = *fmt++;
+ }
+ else {
+ width = 0;
+ while (true) {
+ c = *fmt++;
+ if (c == 0) {
+ return n;
+ }
+ if (c >= '0' && c <= '9') {
+ c -= '0';
+ width = width * 10 + c;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ /* Precision modifier.*/
+ precision = 0;
+ if (c == '.') {
+ c = *fmt++;
+ if (c == 0) {
+ return n;
+ }
+ if (c == '*') {
+ precision = va_arg(ap, int);
+ c = *fmt++;
+ }
+ else {
+ while (c >= '0' && c <= '9') {
+ c -= '0';
+ precision = precision * 10 + c;
+ c = *fmt++;
+ if (c == 0) {
+ return n;
+ }
+ }
+ }
+ }
+
+ /* Long modifier.*/
+ if (c == 'l' || c == 'L') {
+ is_long = true;
+ c = *fmt++;
+ if (c == 0) {
+ return n;
+ }
+ }
+ else {
+ is_long = (c >= 'A') && (c <= 'Z');
+ }
+
+ /* Command decoding.*/
+ switch (c) {
+ case 'c':
+ filler = ' ';
+ *p++ = va_arg(ap, int);
+ break;
+ case 's':
+ filler = ' ';
+ if ((s = va_arg(ap, char *)) == 0) {
+ s = "(null)";
+ }
+ if (precision == 0) {
+ precision = 32767;
+ }
+ for (p = s; *p && (--precision >= 0); p++)
+ ;
+ break;
+ case 'D':
+ case 'd':
+ case 'I':
+ case 'i':
+ if (is_long) {
+ l = va_arg(ap, long);
+ }
+ else {
+ l = va_arg(ap, int);
+ }
+ if (l < 0) {
+ *p++ = '-';
+ l = -l;
+ }
+ else
+ if (do_sign) {
+ *p++ = '+';
+ }
+ p = ch_ltoa(p, l, 10);
+ break;
+#if CHPRINTF_USE_FLOAT
+ case 'f':
+ f = (float) va_arg(ap, double);
+ if (f < 0) {
+ *p++ = '-';
+ f = -f;
+ }
+ else {
+ if (do_sign) {
+ *p++ = '+';
+ }
+ }
+ p = ftoa(p, f, precision);
+ break;
+#endif
+ case 'X':
+ case 'x':
+ case 'P':
+ case 'p':
+ c = 16;
+ goto unsigned_common;
+ case 'U':
+ case 'u':
+ c = 10;
+ goto unsigned_common;
+ case 'O':
+ case 'o':
+ c = 8;
+unsigned_common:
+ if (is_long) {
+ l = va_arg(ap, unsigned long);
+ }
+ else {
+ l = va_arg(ap, unsigned int);
+ }
+ p = ch_ltoa(p, l, c);
+ break;
+ default:
+ *p++ = c;
+ break;
+ }
+ i = (int)(p - s);
+ if ((width -= i) < 0) {
+ width = 0;
+ }
+ if (left_align == false) {
+ width = -width;
+ }
+ if (width < 0) {
+ if ((*s == '-' || *s == '+') && filler == '0') {
+ stmPut(stmp, (uint8_t)*s++);
+ n++;
+ i--;
+ }
+ do {
+ stmPut(stmp, (uint8_t)filler);
+ n++;
+ } while (++width != 0);
+ }
+ while (--i >= 0) {
+ stmPut(stmp, (uint8_t)*s++);
+ n++;
+ }
+
+ while (width) {
+ stmPut(stmp, (uint8_t)filler);
+ n++;
+ width--;
+ }
+ }
+}
+
+/**
+ * @brief System formatted output function.
+ * @details This function implements a minimal @p printf() like functionality
+ * with output on a @p BaseSequentialStream.
+ * The general parameters format is: %[-][width|*][.precision|*][l|L]p.
+ * The following parameter types (p) are supported:
+ * - x hexadecimal integer.
+ * - X hexadecimal long.
+ * - o octal integer.
+ * - O octal long.
+ * - d decimal signed integer.
+ * - D decimal signed long.
+ * - u decimal unsigned integer.
+ * - U decimal unsigned long.
+ * - c character.
+ * - s string.
+ * .
+ *
+ * @param[in] stmp pointer to a @p sequential_stream_i interface
+ * @param[in] fmt formatting string
+ * @return The number of bytes that would have been
+ * written to @p chp if no stream error occurs
+ *
+ * @api
+ */
+int chprintf(sequential_stream_i *stmp, const char *fmt, ...) {
+ va_list ap;
+ int formatted_bytes;
+
+ va_start(ap, fmt);
+ formatted_bytes = chvprintf(stmp, fmt, ap);
+ va_end(ap);
+
+ return formatted_bytes;
+}
+
+/**
+ * @brief System formatted output function.
+ * @details This function implements a minimal @p snprintf()-like functionality.
+ * The general parameters format is: %[-][width|*][.precision|*][l|L]p.
+ * The following parameter types (p) are supported:
+ * - x hexadecimal integer.
+ * - X hexadecimal long.
+ * - o octal integer.
+ * - O octal long.
+ * - d decimal signed integer.
+ * - D decimal signed long.
+ * - u decimal unsigned integer.
+ * - U decimal unsigned long.
+ * - c character.
+ * - s string.
+ * .
+ * @post @p str is NUL-terminated, unless @p size is 0.
+ *
+ * @param[in] str pointer to a buffer
+ * @param[in] size maximum size of the buffer
+ * @param[in] fmt formatting string
+ * @return The number of characters (excluding the
+ * terminating NUL byte) that would have been
+ * stored in @p str if there was room.
+ *
+ * @api
+ */
+int chsnprintf(char *str, size_t size, const char *fmt, ...) {
+ va_list ap;
+ int retval;
+
+ /* Performing the print operation.*/
+ va_start(ap, fmt);
+ retval = chvsnprintf(str, size, fmt, ap);
+ va_end(ap);
+
+ /* Return number of bytes that would have been written.*/
+ return retval;
+}
+
+/**
+ * @brief System formatted output function.
+ * @details This function implements a minimal @p vsnprintf()-like functionality.
+ * The general parameters format is: %[-][width|*][.precision|*][l|L]p.
+ * The following parameter types (p) are supported:
+ * - x hexadecimal integer.
+ * - X hexadecimal long.
+ * - o octal integer.
+ * - O octal long.
+ * - d decimal signed integer.
+ * - D decimal signed long.
+ * - u decimal unsigned integer.
+ * - U decimal unsigned long.
+ * - c character.
+ * - s string.
+ * .
+ * @post @p str is NUL-terminated, unless @p size is 0.
+ *
+ * @param[in] str pointer to a buffer
+ * @param[in] size maximum size of the buffer
+ * @param[in] fmt formatting string
+ * @param[in] ap list of parameters
+ * @return The number of characters (excluding the
+ * terminating NUL byte) that would have been
+ * stored in @p str if there was room.
+ *
+ * @api
+ */
+int chvsnprintf(char *str, size_t size, const char *fmt, va_list ap) {
+ memory_stream_c ms;
+ size_t size_wo_nul;
+ int retval;
+
+ if (size > 0)
+ size_wo_nul = size - 1;
+ else
+ size_wo_nul = 0;
+
+ /* Memory stream object to be used as a string writer, reserving one
+ byte for the final zero.*/
+ memstmObjectInit(&ms, (uint8_t *)str, size_wo_nul, 0U);
+
+ /* Performing the print operation using the common code.*/
+ retval = chvprintf(oopGetIf(&ms, stm), fmt, ap);
+
+ /* Terminate with a zero, unless size==0.*/
+ if (ms.eos < size) {
+ str[ms.eos] = 0;
+ }
+
+ /* Return number of bytes that would have been written.*/
+ return retval;
+}
+
+/** @} */
diff --git a/os/common/lib/src/memstreams.c b/os/common/lib/src/memstreams.c
new file mode 100644
index 000000000..4ea89f9dd
--- /dev/null
+++ b/os/common/lib/src/memstreams.c
@@ -0,0 +1,272 @@
+/*
+ ChibiOS - Copyright (C) 2006..2023 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @file memstreams.c
+ * @brief Generated Memory Streams source.
+ * @note This is a generated file, do not edit directly.
+ *
+ * @addtogroup MEMSTREAMS
+ * @{
+ */
+
+#include "memstreams.h"
+
+/*===========================================================================*/
+/* Module local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module local macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module local types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module local variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module exported functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Module class "memory_stream_c" methods. */
+/*===========================================================================*/
+
+/**
+ * @name Interfaces implementation of memory_stream_c
+ * @{
+ */
+/**
+ * @memberof memory_stream_c
+ * @private
+ *
+ * @brief Implementation of interface method @p stmWrite().
+ *
+ * @param[in,out] ip Pointer to the @p sequential_stream_i class
+ * interface.
+ * @param[in] bp Pointer to the data buffer.
+ * @param[in] n The maximum amount of data to be transferred.
+ * @return The number of bytes transferred. The returned
+ * value can be less than the specified number of
+ * bytes if an end-of-file condition has been met.
+ */
+static size_t __memstm_stm_write_impl(void *ip, const uint8_t *bp, size_t n) {
+ memory_stream_c *self = oopIfGetOwner(memory_stream_c, ip);
+
+ if (self->size - self->eos < n) {
+ n = self->size - self->eos;
+ }
+
+ memcpy(self->buffer + self->eos, bp, n);
+ self->eos += n;
+
+ return n;
+}
+
+/**
+ * @memberof memory_stream_c
+ * @private
+ *
+ * @brief Implementation of interface method @p stmRead().
+ *
+ * @param[in,out] ip Pointer to the @p sequential_stream_i class
+ * interface.
+ * @param[out] bp Pointer to the data buffer.
+ * @param[in] n The maximum amount of data to be transferred.
+ * @return The number of bytes transferred. The returned
+ * value can be less than the specified number of
+ * bytes if an end-of-file condition has been met.
+ */
+static size_t __memstm_stm_read_impl(void *ip, uint8_t *bp, size_t n) {
+ memory_stream_c *self = oopIfGetOwner(memory_stream_c, ip);
+
+ if (self->eos - self->offset < n) {
+ n = self->eos - self->offset;
+ }
+
+ memcpy(bp, self->buffer + self->offset, n);
+ self->offset += n;
+
+ return n;
+}
+
+/**
+ * @memberof memory_stream_c
+ * @private
+ *
+ * @brief Implementation of interface method @p stmPut().
+ *
+ * @param[in,out] ip Pointer to the @p sequential_stream_i class
+ * interface.
+ * @param[in] b The byte value to be written to the stream.
+ * @return The operation status.
+ */
+static int __memstm_stm_put_impl(void *ip, uint8_t b) {
+ memory_stream_c *self = oopIfGetOwner(memory_stream_c, ip);
+
+ if (self->size - self->eos <= 0U) {
+ return STM_RESET;
+ }
+
+ *(self->buffer + self->eos) = b;
+ self->eos++;
+
+ return STM_OK;
+}
+
+/**
+ * @memberof memory_stream_c
+ * @private
+ *
+ * @brief Implementation of interface method @p stmGet().
+ *
+ * @param[in,out] ip Pointer to the @p sequential_stream_i class
+ * interface.
+ * @return A byte value from the stream.
+ */
+static int __memstm_stm_get_impl(void *ip) {
+ memory_stream_c *self = oopIfGetOwner(memory_stream_c, ip);
+ uint8_t b;
+
+ if (self->eos - self->offset <= 0U) {
+ return STM_RESET;
+ }
+
+ b = *(self->buffer + self->offset);
+ self->offset++;
+
+ return b;
+}
+
+/**
+ * @memberof memory_stream_c
+ * @private
+ *
+ * @brief Implementation of interface method @p stmUnget().
+ *
+ * @param[in,out] ip Pointer to the @p sequential_stream_i class
+ * interface.
+ * @param[in] b The byte value to be pushed back to the stream.
+ * @return The operation status.
+ */
+static int __memstm_stm_unget_impl(void *ip, int b) {
+ memory_stream_c *self = oopIfGetOwner(memory_stream_c, ip);
+
+ if ((b == STM_RESET) || (self->offset <= 0U)) {
+ return STM_RESET;
+ }
+
+ self->offset--;
+ *(self->buffer + self->offset) = (uint8_t)b;
+
+ return STM_OK;
+}
+/** @} */
+
+/**
+ * @name Methods implementations of memory_stream_c
+ * @{
+ */
+/**
+ * @memberof memory_stream_c
+ * @protected
+ *
+ * @brief Implementation of object creation.
+ * @note This function is meant to be used by derived classes.
+ *
+ * @param[out] ip Pointer to a @p memory_stream_c instance to be
+ * initialized.
+ * @param[in] vmt VMT pointer for the new object.
+ * @param buffer Pointer to the memory buffer for the memory
+ * stream.
+ * @param size Size of the memory stream buffer.
+ * @param eos Initial End Of Stream offset. Normally you need
+ * to put this to zero for RAM buffers or equal to
+ * @p size for ROM streams.
+ * @return A new reference to the object.
+ */
+void *__memstm_objinit_impl(void *ip, const void *vmt, uint8_t *buffer,
+ size_t size, size_t eos) {
+ memory_stream_c *self = (memory_stream_c *)ip;
+
+ /* Initialization of the ancestors-defined parts.*/
+ __bo_objinit_impl(self, vmt);
+
+ /* Initialization of interface sequential_stream_i.*/
+ {
+ static const struct sequential_stream_vmt memstm_stm_vmt = {
+ .instance_offset = offsetof(memory_stream_c, stm),
+ .write = __memstm_stm_write_impl,
+ .read = __memstm_stm_read_impl,
+ .put = __memstm_stm_put_impl,
+ .get = __memstm_stm_get_impl,
+ .unget = __memstm_stm_unget_impl
+ };
+ oopIfObjectInit(&self->stm, &memstm_stm_vmt);
+ }
+
+ /* Initialization code.*/
+
+ self->buffer = buffer;
+ self->size = size;
+ self->eos = eos;
+ self->offset = 0U;
+
+ return self;
+}
+
+/**
+ * @memberof memory_stream_c
+ * @protected
+ *
+ * @brief Implementation of object finalization.
+ * @note This function is meant to be used by derived classes.
+ *
+ * @param[in,out] ip Pointer to a @p memory_stream_c instance to be
+ * disposed.
+ */
+void __memstm_dispose_impl(void *ip) {
+ memory_stream_c *self = (memory_stream_c *)ip;
+
+ /* No finalization code.*/
+ (void)self;
+
+ /* Finalization of the ancestors-defined parts.*/
+ __bo_dispose_impl(self);
+}
+/** @} */
+
+/**
+ * @brief VMT structure of memory stream class.
+ * @note It is public because accessed by the inlined constructor.
+ */
+const struct memory_stream_vmt __memory_stream_vmt = {
+ .dispose = __memstm_dispose_impl
+};
+
+/** @} */
diff --git a/os/common/oop/codegen/oop_sequential_stream.xml b/os/common/oop/codegen/oop_sequential_stream.xml
index 7217d6701..26d2a1e1f 100644
--- a/os/common/oop/codegen/oop_sequential_stream.xml
+++ b/os/common/oop/codegen/oop_sequential_stream.xml
@@ -12,9 +12,18 @@
-
-
-
+
+ Returned code for operation successful.
+ It is an alias of @p MSG_OK.
+
+
+ Returned code for operation timeout.
+ It is an alias of @p MSG_TIMEOUT.
+
+
+ Returned code for stream reset or End-of-File.
+ It is an alias of @p MSG_RESET.
+
@@ -72,7 +81,7 @@
value can be less than the specified number of bytes
if an end-of-file condition has been met.]]>
-
+
Sequential Stream blocking byte write.
The operation status.
+ If the byte has been written.
+ If an end-of-file condition has been met.
-
+
Sequential Stream blocking byte read.
A byte value from the stream.
+ If an end-of-file condition has been met.
+
+
+ Pushes back a byte into the stream.
+
+
+ The byte value to
+ be pushed back to the stream.
+
+ The operation status.
+ If the byte has been pushed back.
+ If there is no push-back capacity left.
diff --git a/os/common/oop/include/oop_sequential_stream.h b/os/common/oop/include/oop_sequential_stream.h
index 4b79f2e42..26cc59d70 100644
--- a/os/common/oop/include/oop_sequential_stream.h
+++ b/os/common/oop/include/oop_sequential_stream.h
@@ -37,9 +37,23 @@
* @name Streams return codes
* @{
*/
-#define STM_OK MSG_OK
-#define STM_TIMEOUT MSG_TIMEOUT
-#define STM_RESET MSG_RESET
+/**
+ * @brief Returned code for operation successful.
+ * @note It is an alias of @p MSG_OK.
+ */
+#define STM_OK 0
+
+/**
+ * @brief Returned code for operation timeout.
+ * @note It is an alias of @p MSG_TIMEOUT.
+ */
+#define STM_TIMEOUT -1
+
+/**
+ * @brief Returned code for stream reset or End-of-File.
+ * @note It is an alias of @p MSG_RESET.
+ */
+#define STM_RESET -2
/** @} */
#if (defined(OOP_USE_LEGACY)) || defined (__DOXYGEN__)
@@ -102,8 +116,9 @@ struct sequential_stream_vmt {
/* From sequential_stream_i.*/
size_t (*write)(void *ip, const uint8_t *bp, size_t n);
size_t (*read)(void *ip, uint8_t *bp, size_t n);
- msg_t (*put)(void *ip, uint8_t b);
- msg_t (*get)(void *ip);
+ int (*put)(void *ip, uint8_t b);
+ int (*get)(void *ip);
+ int (*unget)(void *ip, int b);
};
/**
@@ -196,9 +211,11 @@ static inline size_t stmRead(void *ip, uint8_t *bp, size_t n) {
* @param[in,out] ip Pointer to a @p sequential_stream_i instance.
* @param[in] b The byte value to be written to the stream.
* @return The operation status.
+ * @retval STM_OK If the byte has been written.
+ * @retval STM_RESET If an end-of-file condition has been met.
*/
CC_FORCE_INLINE
-static inline msg_t stmPut(void *ip, uint8_t b) {
+static inline int stmPut(void *ip, uint8_t b) {
sequential_stream_i *self = (sequential_stream_i *)ip;
return self->vmt->put(ip, b);
@@ -214,13 +231,36 @@ static inline msg_t stmPut(void *ip, uint8_t b) {
*
* @param[in,out] ip Pointer to a @p sequential_stream_i instance.
* @return A byte value from the stream.
+ * @retval STM_RESET If an end-of-file condition has been met.
*/
CC_FORCE_INLINE
-static inline msg_t stmGet(void *ip) {
+static inline int stmGet(void *ip) {
sequential_stream_i *self = (sequential_stream_i *)ip;
return self->vmt->get(ip);
}
+
+/**
+ * @memberof sequential_stream_i
+ * @public
+ *
+ * @brief Pushes back a byte into the stream.
+ * @details The specified byte is pushed back into the stream.
+ * @note Implementing classes may have limited push-back buffer capacity
+ * or not be able to push-back at all.
+ *
+ * @param[in,out] ip Pointer to a @p sequential_stream_i instance.
+ * @param[in] b The byte value to be pushed back to the stream.
+ * @return The operation status.
+ * @retval STM_OK If the byte has been pushed back.
+ * @retval STM_RESET If there is no push-back capacity left.
+ */
+CC_FORCE_INLINE
+static inline int stmUnget(void *ip, int b) {
+ sequential_stream_i *self = (sequential_stream_i *)ip;
+
+ return self->vmt->unget(ip, b);
+}
/** @} */
#endif /* OOP_SEQUENTIAL_STREAM_H */
diff --git a/os/xhal/codegen/hal_buffered_serial.xml b/os/xhal/codegen/hal_buffered_serial.xml
index 14af0b4d3..748f50765 100644
--- a/os/xhal/codegen/hal_buffered_serial.xml
+++ b/os/xhal/codegen/hal_buffered_serial.xml
@@ -36,6 +36,14 @@ return oqPutTimeout(&self->oqueue, b, TIME_INFINITE);]]>
return iqGetTimeout(&self->iqueue, TIME_INFINITE);]]>
+
+
+
+
+
+
oqueue, b, TIME_INFINITE);
@@ -128,12 +128,32 @@ static msg_t __bs_chn_put_impl(void *ip, uint8_t b) {
* interface.
* @return A byte value from the stream.
*/
-static msg_t __bs_chn_get_impl(void *ip) {
+static int __bs_chn_get_impl(void *ip) {
hal_buffered_serial_c *self = oopIfGetOwner(hal_buffered_serial_c, ip);
return iqGetTimeout(&self->iqueue, TIME_INFINITE);
}
+/**
+ * @memberof hal_buffered_serial_c
+ * @private
+ *
+ * @brief Implementation of interface method @p stmUnget().
+ *
+ * @param[in,out] ip Pointer to the @p asynchronous_channel_i class
+ * interface.
+ * @param[in] b The byte value to be pushed back to the stream.
+ * @return The operation status.
+ */
+static int __bs_chn_unget_impl(void *ip, int b) {
+ hal_buffered_serial_c *self = oopIfGetOwner(hal_buffered_serial_c, ip);
+
+ (void)self;
+ (void)b;
+
+ return STM_RESET;
+}
+
/**
* @memberof hal_buffered_serial_c
* @private
@@ -316,6 +336,7 @@ void *__bs_objinit_impl(void *ip, const void *vmt, uint8_t *ib, size_t ibsize,
.read = __bs_chn_read_impl,
.put = __bs_chn_put_impl,
.get = __bs_chn_get_impl,
+ .unget = __bs_chn_unget_impl,
.writet = __bs_chn_writet_impl,
.readt = __bs_chn_readt_impl,
.putt = __bs_chn_putt_impl,
diff --git a/os/xhal/src/hal_sio.c b/os/xhal/src/hal_sio.c
index 77a665118..545d38a46 100644
--- a/os/xhal/src/hal_sio.c
+++ b/os/xhal/src/hal_sio.c
@@ -171,7 +171,7 @@ static size_t __sio_chn_read_impl(void *ip, uint8_t *bp, size_t n) {
* @param[in] b The byte value to be written to the stream.
* @return The operation status.
*/
-static msg_t __sio_chn_put_impl(void *ip, uint8_t b) {
+static int __sio_chn_put_impl(void *ip, uint8_t b) {
hal_sio_driver_c *self = oopIfGetOwner(hal_sio_driver_c, ip);
msg_t msg;
@@ -194,7 +194,7 @@ static msg_t __sio_chn_put_impl(void *ip, uint8_t b) {
* interface.
* @return A byte value from the stream.
*/
-static msg_t __sio_chn_get_impl(void *ip) {
+static int __sio_chn_get_impl(void *ip) {
hal_sio_driver_c *self = oopIfGetOwner(hal_sio_driver_c, ip);
msg_t msg;
@@ -206,6 +206,26 @@ static msg_t __sio_chn_get_impl(void *ip) {
return sioGetX(self);
}
+/**
+ * @memberof hal_sio_driver_c
+ * @private
+ *
+ * @brief Implementation of interface method @p stmUnget().
+ *
+ * @param[in,out] ip Pointer to the @p asynchronous_channel_i class
+ * interface.
+ * @param[in] b The byte value to be pushed back to the stream.
+ * @return The operation status.
+ */
+static int __sio_chn_unget_impl(void *ip, int b) {
+ hal_sio_driver_c *self = oopIfGetOwner(hal_sio_driver_c, ip);
+
+ (void)self;
+ (void)b;
+
+ return STM_RESET;
+}
+
/**
* @memberof hal_sio_driver_c
* @private
@@ -392,6 +412,7 @@ void *__sio_objinit_impl(void *ip, const void *vmt) {
.read = __sio_chn_read_impl,
.put = __sio_chn_put_impl,
.get = __sio_chn_get_impl,
+ .unget = __sio_chn_unget_impl,
.writet = __sio_chn_writet_impl,
.readt = __sio_chn_readt_impl,
.putt = __sio_chn_putt_impl,