How to determine which Serial object is available on ESP32

I developed a library for DMX on an ESP32 which (as one would expect) uses the available UARTs on the board(s)
With the ESP32 coming in many variants, some with native USB, some without, and me not having all the specific boards available to me, i would like to know if there is a simple way of determining which UARTs are available and how they are referenced.

On an ESP32(S) devkit, Serial = UART0, Serial1 = UART1 and Serial2 = UART2

But it appears that for instance on an ESP32-C6, Serial = USB, Serial0 = UART0 and Serial1 = UART1 if i am not mistaken.

The documentation from Espressif is sketchy to say the least and i don't have a c6 to test on, but found this info in HardwareSerial.cpp in the core files.

From there also one can see that

SOC_UART_NUM

is the actual number of UARTs available.

But taking that back to the ESP32(S), it will state having 3 UARTs, but Serial0 == Serial
For examples (which is what this is actually about) i do want to put out messages through 'Serial', but may want to use Serial0 if that is different from that. Though in general i want to also keep it simple.

May be the #define for ARDUINO_USB_MODE and ARDUINO_USB_CDC_ON_BOOT could give you a clue if Serial is mapped to a native USB port or takes up one UART and then use SOC_UART_NUM for the numbers of real UARTs?

as they are #define, you could just try to compile for a given target and use compile time messages to see what those define are telling you

#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)

#ifdef ARDUINO_USB_CDC_ON_BOOT
  #pragma message("******** ARDUINO_USB_CDC_ON_BOOT is defined")
#else
  #pragma message("******** ARDUINO_USB_CDC_ON_BOOT is NOT defined")
#endif

#ifdef ARDUINO_USB_MODE
  #pragma message("******** ARDUINO_USB_MODE is defined")
#else
  #pragma message("******** ARDUINO_USB_MODE is NOT defined")
#endif

#pragma message("******** SOC_UART_NUM = " STR(SOC_UART_NUM))

void setup() {}
void loop() {}

Oh that is a good plan.

I am still uncertain of something though, taking the example of the C6 again (which i don't have)

C:\Data\Arduino\Sketches\ESP32\UART_Definition\UART_Definition.ino:5:64: note: '#pragma message: ******** ARDUINO_USB_CDC_ON_BOOT is defined'
    5 |   #pragma message("******** ARDUINO_USB_CDC_ON_BOOT is defined")
      |                                                                ^
C:\Data\Arduino\Sketches\ESP32\UART_Definition\UART_Definition.ino:11:57: note: '#pragma message: ******** ARDUINO_USB_MODE is defined'
   11 |   #pragma message("******** ARDUINO_USB_MODE is defined")
      |                                                         ^
C:\Data\Arduino\Sketches\ESP32\UART_Definition\UART_Definition.ino:16:61: note: '#pragma message: ******** SOC_UART_NUM = (3)'
   16 | #pragma message("******** SOC_UART_NUM = " STR(SOC_UART_NUM))

It reports 3 UARTs (technically speaking there are also another 2 LP_UARTs according to the datasheet) and ARDUINO_USB_MODE.

Which UART is the USB connected to ?

Normally speaking one would say 'Serial0' , but according to a user experimenting with my library, Serial0 could be used and Serial2 not (unverified)

LP UARTs are distinct UART peripherals implemented in the low-power domain, with their own registers, clocks, and power control, separate from the main UARTs counted by SOC_UART_NUM.

➜ They are intended to operate when the main system domain is powered down or sleeping and are therefore architecturally and functionally different from standard UARTs. You access them through dedicated low-power drivers in ESP-IDF and are not exposed by the Arduino-ESP32 core through Serial or HardwareSerial. So may be you don't need to count those ?

with such a report I would say that the USB interface is a native USB Serial/JTAG peripheral that is completely independent of the UART blocks and thus USB is connected to any UART.

When ARDUINO_USB_MODE and ARDUINO_USB_CDC_ON_BOOT are defined, the Arduino core usually maps Serial to the USB CDC interface by software choice. Serial0, Serial1, and Serial2 then map to the actual hardware UARTs according to the board variant configuration.

The observation that Serial0 works while Serial2 does not is likely a board or variant limitation, not a consequence of USB usage and I'm not sure you can detect that easily

Ok so i can disregard their existence.

Yeah but according to the datasheet of the C6 there are only 2 UARTs ?

Well then that is probably just what it is.

Thank you so much for the explanation.