diff --git a/src/main/drivers/serial_softserial.c b/src/main/drivers/serial_softserial.c index 010c1ee1e7..dbaf5d75e6 100644 --- a/src/main/drivers/serial_softserial.c +++ b/src/main/drivers/serial_softserial.c @@ -197,8 +197,8 @@ static void resetBuffers(softSerial_t *softSerial) softSerial_t* softSerialFromIdentifier(serialPortIdentifier_e identifier) { - if (identifier >= SERIAL_PORT_SOFTSERIAL1 && identifier < SERIAL_PORT_SOFTSERIAL1 + SERIAL_SOFTSERIAL_COUNT) { - return &softSerialPorts[identifier - SERIAL_PORT_SOFTSERIAL1]; + if (identifier >= SERIAL_PORT_SOFTSERIAL_FIRST && identifier < SERIAL_PORT_SOFTSERIAL_FIRST + SERIAL_SOFTSERIAL_COUNT) { + return &softSerialPorts[identifier - SERIAL_PORT_SOFTSERIAL_FIRST]; } return NULL; } diff --git a/src/main/drivers/serial_uart.c b/src/main/drivers/serial_uart.c index 42c7846932..24bfb66c8a 100644 --- a/src/main/drivers/serial_uart.c +++ b/src/main/drivers/serial_uart.c @@ -174,7 +174,7 @@ uartDeviceIdx_e uartDeviceIdxFromIdentifier(serialPortIdentifier_e identifier) } #else { - const int idx = identifier - SERIAL_PORT_USART1; + const int idx = identifier - SERIAL_PORT_UART_FIRST; if (idx >= 0 && idx < SERIAL_UART_MAX) { if (BIT(idx) & SERIAL_UART_MASK) { // return number of enabled UART ports smaller than idx diff --git a/src/main/io/serial.h b/src/main/io/serial.h index 9d2a3ce667..af10830fa2 100644 --- a/src/main/io/serial.h +++ b/src/main/io/serial.h @@ -83,7 +83,14 @@ extern const uint32_t baudRates[]; typedef enum { SERIAL_PORT_ALL = -2, SERIAL_PORT_NONE = -1, - SERIAL_PORT_USART1 = 0, + // prepare for transition to SERIAL_PORT_UART0 + SERIAL_PORT_UART_FIRST = 0, +#if SERIAL_UART_FIRST_INDEX == 0 + SERIAL_PORT_UART0 = SERIAL_PORT_UART_FIRST, + SERIAL_PORT_USART1, +#else + SERIAL_PORT_USART1 = SERIAL_PORT_UART_FIRST, +#endif SERIAL_PORT_UART1 = SERIAL_PORT_USART1, SERIAL_PORT_USART2, SERIAL_PORT_UART2 = SERIAL_PORT_USART2, @@ -103,10 +110,12 @@ typedef enum { SERIAL_PORT_USB_VCP = 20, - SERIAL_PORT_SOFTSERIAL1 = 30, + SERIAL_PORT_SOFTSERIAL_FIRST = 30, + SERIAL_PORT_SOFTSERIAL1 = SERIAL_PORT_SOFTSERIAL_FIRST, SERIAL_PORT_SOFTSERIAL2, - SERIAL_PORT_LPUART1 = 40, + SERIAL_PORT_LPUART_FIRST = 40, + SERIAL_PORT_LPUART1 = SERIAL_PORT_LPUART_FIRST, } serialPortIdentifier_e; // use value from target serial port normalization diff --git a/src/main/io/serial_resource.c b/src/main/io/serial_resource.c index 33eb938bb9..962e0d7d25 100644 --- a/src/main/io/serial_resource.c +++ b/src/main/io/serial_resource.c @@ -36,8 +36,9 @@ serialType_e serialType(serialPortIdentifier_e identifier) } #endif #ifdef USE_UART - if (identifier >= SERIAL_PORT_USART1 && identifier < SERIAL_PORT_USART1 + SERIAL_UART_MAX) { - const unsigned idx = identifier - SERIAL_PORT_USART1; + if (identifier >= SERIAL_PORT_UART_FIRST + && identifier < SERIAL_PORT_UART_FIRST + SERIAL_UART_MAX) { + const unsigned idx = identifier - SERIAL_PORT_UART_FIRST; if (BIT(idx) & SERIAL_UART_MASK) { return SERIALTYPE_UART; } else { @@ -47,8 +48,9 @@ serialType_e serialType(serialPortIdentifier_e identifier) } #endif #ifdef USE_LPUART - if (identifier >= SERIAL_PORT_LPUART1 && identifier < SERIAL_PORT_LPUART1 + SERIAL_LPUART_MAX) { - const unsigned idx = identifier - SERIAL_PORT_LPUART1; + if (identifier >= SERIAL_PORT_LPUART_FIRST + && identifier < SERIAL_PORT_LPUART_FIRST + SERIAL_LPUART_MAX) { + const unsigned idx = identifier - SERIAL_PORT_LPUART_FIRST; if (BIT(idx) & SERIAL_LPUART_MASK) { return SERIALTYPE_LPUART; } else { @@ -58,8 +60,9 @@ serialType_e serialType(serialPortIdentifier_e identifier) } #endif #ifdef USE_SOFTSERIAL - if (identifier >= SERIAL_PORT_SOFTSERIAL1 && identifier < SERIAL_PORT_SOFTSERIAL1 + SERIAL_SOFTSERIAL_MAX) { - // sotserials always start from 1, without holes + if (identifier >= SERIAL_PORT_SOFTSERIAL_FIRST + && identifier < SERIAL_PORT_SOFTSERIAL_FIRST + SERIAL_SOFTSERIAL_MAX) { + // sotserials always start from first index, without holes return SERIALTYPE_SOFTSERIAL; } #endif @@ -72,9 +75,9 @@ static const struct SerialTypeInfo { int8_t resourceOffset; } serialTypeMap[] = { [SERIALTYPE_USB_VCP] = { OWNER_FREE /* no owner*/, SERIAL_PORT_USB_VCP, -1 }, - [SERIALTYPE_UART] = { OWNER_SERIAL_TX, SERIAL_PORT_USART1, RESOURCE_UART_OFFSET }, - [SERIALTYPE_LPUART] = { OWNER_LPUART_TX, SERIAL_PORT_LPUART1, RESOURCE_LPUART_OFFSET }, - [SERIALTYPE_SOFTSERIAL] = { OWNER_SOFTSERIAL_TX, SERIAL_PORT_SOFTSERIAL1, RESOURCE_SOFTSERIAL_OFFSET }, + [SERIALTYPE_UART] = { OWNER_SERIAL_TX, SERIAL_PORT_UART_FIRST, RESOURCE_UART_OFFSET }, + [SERIALTYPE_LPUART] = { OWNER_LPUART_TX, SERIAL_PORT_LPUART_FIRST, RESOURCE_LPUART_OFFSET }, + [SERIALTYPE_SOFTSERIAL] = { OWNER_SOFTSERIAL_TX, SERIAL_PORT_SOFTSERIAL_FIRST, RESOURCE_SOFTSERIAL_OFFSET }, }; STATIC_ASSERT(ARRAYLEN(serialTypeMap) == SERIALTYPE_COUNT, "type table mismatch"); diff --git a/src/main/target/serial_post.h b/src/main/target/serial_post.h index ffc7569257..dc7c812c32 100644 --- a/src/main/target/serial_post.h +++ b/src/main/target/serial_post.h @@ -30,7 +30,7 @@ in Betaflight topmost directory. This include will provide following defines: SERIAL__USED 0/1 - always defined, value depends on target configuration -SERIAL__MASK - bitmask of used ports or given type. 1 is BIT(0) +SERIAL__MASK - bitmask of used ports or given type. 0 or 1 is BIT(0), based on port first_index SERIAL__COUNT - number of enabled ports of given type SERIAL__MAX - + 1, 0 when no port is enabled @@ -39,22 +39,41 @@ All _(RX|TX)_PINS are normalized too: - if port is not enable, both will be undefined, possibly with warning - pass -DWARN_UNUSED_SERIAL_PORT to compiler to check pin defined without corresponding port being enabled. -Generated on 2024-11-04 +Generated on 2024-12-20 Configuration used: { 'LPUART': {'depends': {'UART'}, 'ids': [1]}, 'SOFTSERIAL': { 'force_continuous': True, 'ids': [1, 2], 'use_enables_all': True}, - 'UART': {'ids': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'inverter': True}, + 'UART': { 'first_index': True, + 'ids': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + 'inverter': True}, 'VCP': {'no_pins': True, 'singleton': True}} - */ #include "common/utils.h" // BIT, LOG2 /**** UART *****/ +// normalize SERIAL_UART_FIRST_INDEX +#ifndef SERIAL_UART_FIRST_INDEX +#define SERIAL_UART_FIRST_INDEX 1 +#endif + +#if SERIAL_UART_FIRST_INDEX == 0 +#if defined(USE_UART0) +# define SERIAL_UART0_USED 1 +#else +# define SERIAL_UART0_USED 0 +#endif +#else // USE_UART0 is not allowed +# if defined(USE_UART0) +# error "USE_UART0 is defined, but SERIAL_UART does not allow index 0" +# else +# define SERIAL_UART0_USED 0 +# endif +#endif #if defined(USE_UART1) # define SERIAL_UART1_USED 1 #else @@ -106,16 +125,43 @@ Configuration used: # define SERIAL_UART10_USED 0 #endif -#define SERIAL_UART_MASK ((SERIAL_UART1_USED * BIT(1 - 1)) | (SERIAL_UART2_USED * BIT(2 - 1)) | (SERIAL_UART3_USED * BIT(3 - 1)) | (SERIAL_UART4_USED * BIT(4 - 1)) | (SERIAL_UART5_USED * BIT(5 - 1)) | (SERIAL_UART6_USED * BIT(6 - 1)) | (SERIAL_UART7_USED * BIT(7 - 1)) | (SERIAL_UART8_USED * BIT(8 - 1)) | (SERIAL_UART9_USED * BIT(9 - 1)) | (SERIAL_UART10_USED * BIT(10 - 1))) -#define SERIAL_UART_COUNT (SERIAL_UART1_USED + SERIAL_UART2_USED + SERIAL_UART3_USED + SERIAL_UART4_USED + SERIAL_UART5_USED + SERIAL_UART6_USED + SERIAL_UART7_USED + SERIAL_UART8_USED + SERIAL_UART9_USED + SERIAL_UART10_USED) +#define SERIAL_UART_MASK ((SERIAL_UART0_USED * BIT(0)) | (SERIAL_UART1_USED * BIT(1 - SERIAL_UART_FIRST_INDEX)) | (SERIAL_UART2_USED * BIT(2 - SERIAL_UART_FIRST_INDEX)) | (SERIAL_UART3_USED * BIT(3 - SERIAL_UART_FIRST_INDEX)) | (SERIAL_UART4_USED * BIT(4 - SERIAL_UART_FIRST_INDEX)) | (SERIAL_UART5_USED * BIT(5 - SERIAL_UART_FIRST_INDEX)) | (SERIAL_UART6_USED * BIT(6 - SERIAL_UART_FIRST_INDEX)) | (SERIAL_UART7_USED * BIT(7 - SERIAL_UART_FIRST_INDEX)) | (SERIAL_UART8_USED * BIT(8 - SERIAL_UART_FIRST_INDEX)) | (SERIAL_UART9_USED * BIT(9 - SERIAL_UART_FIRST_INDEX)) | (SERIAL_UART10_USED * BIT(10 - SERIAL_UART_FIRST_INDEX))) +#define SERIAL_UART_COUNT (SERIAL_UART0_USED + SERIAL_UART1_USED + SERIAL_UART2_USED + SERIAL_UART3_USED + SERIAL_UART4_USED + SERIAL_UART5_USED + SERIAL_UART6_USED + SERIAL_UART7_USED + SERIAL_UART8_USED + SERIAL_UART9_USED + SERIAL_UART10_USED) // 0 if no port is defined #define SERIAL_UART_MAX (SERIAL_UART_MASK ? LOG2(SERIAL_UART_MASK) + 1 : 0) - // enable USE_INVERTED first, before normalization -#if !defined(USE_INVERTER) && (INVERTER_PIN_UART1 || INVERTER_PIN_UART2 || INVERTER_PIN_UART3 || INVERTER_PIN_UART4 || INVERTER_PIN_UART5 || INVERTER_PIN_UART6 || INVERTER_PIN_UART7 || INVERTER_PIN_UART8 || INVERTER_PIN_UART9 || INVERTER_PIN_UART10) +#if !defined(USE_INVERTER) && (INVERTER_PIN_UART0 || INVERTER_PIN_UART1 || INVERTER_PIN_UART2 || INVERTER_PIN_UART3 || INVERTER_PIN_UART4 || INVERTER_PIN_UART5 || INVERTER_PIN_UART6 || INVERTER_PIN_UART7 || INVERTER_PIN_UART8 || INVERTER_PIN_UART9 || INVERTER_PIN_UART10) # define USE_INVERTER #endif + // Normalize UART TX/RX/INVERTER +#if SERIAL_UART0_USED && !defined(UART0_RX_PIN) +# define UART0_RX_PIN NONE +#endif +#if defined(WARN_UNUSED_SERIAL_PORT) && !SERIAL_UART0_USED && defined(UART0_RX_PIN) +# warning "UART0_RX_PIN is defined but UART0 is not enabled" +#endif +#if !SERIAL_UART0_USED && defined(UART0_RX_PIN) +# undef UART0_RX_PIN +#endif +#if SERIAL_UART0_USED && !defined(UART0_TX_PIN) +# define UART0_TX_PIN NONE +#endif +#if defined(WARN_UNUSED_SERIAL_PORT) && !SERIAL_UART0_USED && defined(UART0_TX_PIN) +# warning "UART0_TX_PIN is defined but UART0 is not enabled" +#endif +#if !SERIAL_UART0_USED && defined(UART0_TX_PIN) +# undef UART0_TX_PIN +#endif +#if SERIAL_UART0_USED && !defined(INVERTER_PIN_UART0) +# define INVERTER_PIN_UART0 NONE +#endif +#if defined(WARN_UNUSED_SERIAL_PORT) && !SERIAL_UART0_USED && defined(INVERTER_PIN_UART0) +# warning "INVERTER_PIN_UART0 is defined but UART0 is not enabled" +#endif +#if !SERIAL_UART0_USED && defined(INVERTER_PIN_UART0) +# undef INVERTER_PIN_UART0 +#endif #if SERIAL_UART1_USED && !defined(UART1_RX_PIN) # define UART1_RX_PIN NONE #endif @@ -421,7 +467,9 @@ Configuration used: #endif /**** SOFTSERIAL *****/ + #if defined(USE_SOFTSERIAL) +// USE_SOFTSERIAL enables all SOFTSERIAL ports # if !defined(USE_SOFTSERIAL1) # define USE_SOFTSERIAL1 # endif @@ -496,7 +544,7 @@ Configuration used: # define SERIAL_VCP_USED 0 #endif -// set one bit if port is enabled for consistency +// for consistency, set one bit if port is enabled #define SERIAL_VCP_MASK (SERIAL_VCP_USED * BIT(0)) #define SERIAL_VCP_COUNT (SERIAL_VCP_USED) // 0 if no port is defined diff --git a/src/utils/gen-serial-j2.py b/src/utils/gen-serial-j2.py index daefa9654d..79da84a4fa 100644 --- a/src/utils/gen-serial-j2.py +++ b/src/utils/gen-serial-j2.py @@ -8,14 +8,15 @@ import pprint # configuration for template generation serials = { - "UART": {"ids": [i + 1 for i in range(10)], + "UART": {"ids": list(range(0, 10 + 1)), "inverter": True, + "first_index": True, # support configurable first index for this port }, "LPUART": {"ids": [1], "depends": {"UART"}, # "inverter": True, # TODO: old code compatibility only, disabled }, - "SOFTSERIAL": {"ids": [i + 1 for i in range(2)], + "SOFTSERIAL": {"ids": list(range(1, 2 + 1)), "use_enables_all": True, "force_continuous": True, }, @@ -69,6 +70,7 @@ def main(): singleton = cfg.setdefault('singleton', False) no_pins = cfg.setdefault('no_pins', False) inverter = cfg.setdefault('inverter', False) + cfg.setdefault('first_index', False) cfg.setdefault("use_enables_all", False) cfg.setdefault("force_continuous", False) cfg.setdefault("depends", {}) diff --git a/src/utils/templates/serial_post.h b/src/utils/templates/serial_post.h index f6455ee68b..83ce3d4b32 100644 --- a/src/utils/templates/serial_post.h +++ b/src/utils/templates/serial_post.h @@ -1,7 +1,6 @@ {# serial_post.h #} {# DEFAULT_LICENCE.md is used #} {{ license|safe }} - /* {# Start with generated warning. It you want to change something, edit this file #} This file is automatically generated by src/utils/gen-serial.py script from src/utils/templates/serial_post.h jinja2 template. @@ -14,7 +13,7 @@ in Betaflight topmost directory. This include will provide following defines: SERIAL__USED 0/1 - always defined, value depends on target configuration -SERIAL__MASK - bitmask of used ports or given type. 1 is BIT(0) +SERIAL__MASK - bitmask of used ports or given type. 0 or 1 is BIT(0), based on port first_index SERIAL__COUNT - number of enabled ports of given type SERIAL__MAX - + 1, 0 when no port is enabled @@ -30,56 +29,77 @@ Configuration used: {# TODO - maybe store configuration in this file, not Python one #} {# TODO - pretty is not enough pretty #} {{ user_config|pprint|safe }} - */ #include "common/utils.h" // BIT, LOG2 -{# config array is passed to this script. It is flattened version of user_config, with default fileld in #} +{# config array is passed to this script. It is flattened version of user_config, with defaults filled in #} {% for cfg in config %} /**** {{ cfg.typ }} *****/ + +{% if cfg.first_index %} +// normalize SERIAL_{{ cfg.typ }}_FIRST_INDEX +#ifndef SERIAL_{{ cfg.typ }}_FIRST_INDEX +#define SERIAL_{{ cfg.typ }}_FIRST_INDEX 1 +#endif + +{% endif %} {# use_enables_all - USE_ enables all ports of this type #} {% if cfg.use_enables_all %} #if defined(USE_{{cfg.typ}}) +// USE_{{cfg.typ}} enables all {{cfg.typ}} ports {% for port in cfg.ports %} # if !defined(USE_{{port}}) # define USE_{{port}} # endif {% endfor %} #endif -{% endif %} +{% endif %} {# USE_ - SERIAL__USED 0/1 #} -{% for port in cfg.ports %} +{% for port, i in cfg.ports|zip(cfg.ids|default([-1])) %}{# handle singleton without ids #} +{% if i == 0 and cfg.first_index %}{# port 0, test if it is allowed #} +#if SERIAL_{{ cfg.typ }}_FIRST_INDEX == 0 +{% endif %} #if defined(USE_{{port}}) # define SERIAL_{{port}}_USED 1 #else # define SERIAL_{{port}}_USED 0 #endif +{% if i == 0 and cfg.first_index %}{# port 0, #else branch #} +#else // USE_{{port}} is not allowed +# if defined(USE_{{port}}) +# error "USE_{{port}} is defined, but SERIAL_{{ cfg.typ }} does not allow index 0" +# else +# define SERIAL_{{port}}_USED 0 +# endif +#endif +{% endif %} {% endfor %} {# SERIAL__* summary macros #} {% if not cfg.singleton %} {% set pipe = joiner(' | ') %} -#define SERIAL_{{ cfg.typ }}_MASK ({% for port, i in cfg.ports|zip(cfg.ids) %}{{ pipe() }}(SERIAL_{{ port }}_USED * BIT({{ i }} - 1)){% endfor %}) +#define SERIAL_{{ cfg.typ }}_MASK ({% for port, i in cfg.ports|zip(cfg.ids) %} + {{- pipe() }}(SERIAL_{{ port }}_USED * BIT({{ "0" if i==0 else "{} - SERIAL_{}_FIRST_INDEX".format(i, cfg.typ) if cfg.first_index else "{} - 1".format(i) }})){% endfor %}) +{# export first index information, so serial.h can assert that it does match #} {% else %} {# one port without number is defined #} -// set one bit if port is enabled for consistency +// for consistency, set one bit if port is enabled #define SERIAL_{{ cfg.typ }}_MASK (SERIAL_{{ cfg.ports[0] }}_USED * BIT(0)) {% endif %} {% set plus = joiner(' + ') %} #define SERIAL_{{ cfg.typ }}_COUNT ({% for port in cfg.ports %}{{ plus() }}SERIAL_{{ port }}_USED{% endfor %}) -{# LOG2 is simpler than chaining MAX(SERIAL_x1_USED * 1, MAX(SERIAL_x2_USED * 2, ... #} // 0 if no port is defined +{# LOG2 is simpler than chaining MAX(SERIAL_x1_USED * 1, MAX(SERIAL_x2_USED * 2, ... #} #define SERIAL_{{ cfg.typ }}_MAX (SERIAL_{{cfg.typ}}_MASK ? LOG2(SERIAL_{{cfg.typ}}_MASK) + 1 : 0) - {# for softserial, we don't want softserial2 only #} {% if cfg.force_continuous %} + #if SERIAL_{{cfg.typ}}_COUNT != SERIAL_{{cfg.typ}}_MAX # error {{cfg.typ}} ports must start with {{cfg.typ}}1 and be continuous #endif {% endif %} - {# backward compatibility, code did set USE_INVERTER this way. It must be done before normalizing to NONE #} {% if cfg.inverter %} // enable USE_INVERTED first, before normalization @@ -90,6 +110,7 @@ Configuration used: {% endif %} {# no pins for VCP port #} {% if not cfg.no_pins %} + // Normalize {{cfg.typ}} TX/RX{{ "/INVERTER" if cfg.inverter else "" }} {% for port in cfg.ports %} {% set pins = [ port ~ '_RX_PIN', port ~ '_TX_PIN' ] + (['INVERTER_PIN_' ~ port] if cfg.inverter else []) %}