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,