[simulation] set virtual UART at runtime (#12199)

This commit changes the virtual UART to be configured at runtime, which
eliminates a build variants, which causes code coverage process problem.
This commit is contained in:
Yakun Xu
2025-12-10 00:48:37 +08:00
committed by GitHub
parent b800b1ad8e
commit a3b8361a19
7 changed files with 104 additions and 51 deletions
+1 -1
View File
@@ -351,7 +351,7 @@ jobs:
retention-days: 1
thread-1-4-posix:
runs-on: ubuntu-22.04
runs-on: ubuntu-24.04
env:
COVERAGE: 1
PYTHONUNBUFFERED: 1
@@ -354,4 +354,15 @@ void platformBleUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, struct time
*/
void platformBleProcess(otInstance *aInstance, const fd_set *aReadFdSet, const fd_set *aWriteFdSet);
/**
* Send bytes over Virtual UART.
*
* @param[in] aData A pointer to the data buffer.
* @param[in] aLength Number of bytes to transmit.
*
* @retval OT_ERROR_NONE Successfully started transmission.
* @retval OT_ERROR_FAILED Failed to start the transmission.
*/
otError platformUartSendVirtual(const uint8_t *aData, uint16_t aLength);
#endif // PLATFORM_SIMULATION_H_
@@ -53,6 +53,8 @@ typedef struct utilsSocket
extern const char *gLocalInterface; ///< Local interface name or address to use for sockets
extern bool gVirtualUart; ///< Whether to use Virtual UART or not.
/**
* Adds a file descriptor (FD) to a given FD set.
*
+58 -6
View File
@@ -45,13 +45,15 @@
#include "utils/code_utils.h"
#include "utils/uart.h"
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME_UART == 0
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME
bool gVirtualUart = ((OPENTHREAD_SIMULATION_VIRTUAL_TIME_UART) == 1);
#endif
static uint8_t s_receive_buffer[128];
static const uint8_t *s_write_buffer;
static uint16_t s_write_length;
static int s_in_fd;
static int s_out_fd;
static int s_in_fd = -1;
static int s_out_fd = -1;
static struct termios original_stdin_termios;
static struct termios original_stdout_termios;
@@ -62,9 +64,18 @@ static void restore_stdout_termios(void) { tcsetattr(s_out_fd, TCSAFLUSH, &origi
void platformUartRestore(void)
{
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME
otEXPECT(!gVirtualUart);
#endif
restore_stdin_termios();
restore_stdout_termios();
dup2(s_out_fd, STDOUT_FILENO);
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME
exit:
return;
#endif
}
otError otPlatUartEnable(void)
@@ -72,6 +83,10 @@ otError otPlatUartEnable(void)
otError error = OT_ERROR_NONE;
struct termios termios;
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME
otEXPECT(!gVirtualUart);
#endif
s_in_fd = dup(STDIN_FILENO);
s_out_fd = dup(STDOUT_FILENO);
dup2(STDERR_FILENO, STDOUT_FILENO);
@@ -144,8 +159,14 @@ otError otPlatUartEnable(void)
return error;
exit:
close(s_in_fd);
close(s_out_fd);
if (s_in_fd != -1)
{
close(s_in_fd);
}
if (s_out_fd != -1)
{
close(s_out_fd);
}
return error;
}
@@ -153,9 +174,16 @@ otError otPlatUartDisable(void)
{
otError error = OT_ERROR_NONE;
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME
otEXPECT(!gVirtualUart);
#endif
close(s_in_fd);
close(s_out_fd);
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME
exit:
#endif
return error;
}
@@ -163,6 +191,10 @@ otError otPlatUartSend(const uint8_t *aBuf, uint16_t aBufLength)
{
otError error = OT_ERROR_NONE;
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME
otEXPECT_ACTION(!gVirtualUart, error = platformUartSendVirtual(aBuf, aBufLength));
#endif
otEXPECT_ACTION(s_write_length == 0, error = OT_ERROR_BUSY);
s_write_buffer = aBuf;
@@ -174,6 +206,10 @@ exit:
void platformUartUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, fd_set *aErrorFdSet, int *aMaxFd)
{
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME
otEXPECT(!gVirtualUart);
#endif
utilsAddFdToFdSet(s_in_fd, aReadFdSet, aMaxFd);
utilsAddFdToFdSet(s_in_fd, aErrorFdSet, aMaxFd);
@@ -182,6 +218,11 @@ void platformUartUpdateFdSet(fd_set *aReadFdSet, fd_set *aWriteFdSet, fd_set *aE
utilsAddFdToFdSet(s_out_fd, aWriteFdSet, aMaxFd);
utilsAddFdToFdSet(s_out_fd, aErrorFdSet, aMaxFd);
}
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME
exit:
return;
#endif
}
otError otPlatUartFlush(void)
@@ -189,6 +230,10 @@ otError otPlatUartFlush(void)
otError error = OT_ERROR_NONE;
ssize_t count;
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME
otEXPECT(!gVirtualUart);
#endif
otEXPECT_ACTION(s_write_buffer != NULL && s_write_length > 0, error = OT_ERROR_INVALID_STATE);
while ((count = write(s_out_fd, s_write_buffer, s_write_length)) > 0 && (s_write_length -= count) > 0)
@@ -220,6 +265,10 @@ void platformUartProcess(void)
{s_out_fd, POLLOUT | error_flags, 0},
};
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME
otEXPECT(!gVirtualUart);
#endif
errno = 0;
rval = poll(pollfd, sizeof(pollfd) / sizeof(*pollfd), 0);
@@ -278,8 +327,11 @@ void platformUartProcess(void)
}
}
}
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME
exit:
return;
#endif
}
#endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME_UART == 0
#if OPENTHREAD_CONFIG_ENABLE_DEBUG_UART && (OPENTHREAD_CONFIG_LOG_OUTPUT == OPENTHREAD_CONFIG_LOG_OUTPUT_DEBUG_UART)
@@ -50,6 +50,7 @@
#include <openthread/tasklet.h>
#include <openthread/platform/alarm-milli.h>
#include "../simul_utils.h"
#include "lib/platform/exit_code.h"
#include "utils/uart.h"
@@ -148,14 +149,7 @@ static void platformSendSleepEvent(void)
otSimSendEvent(&event);
}
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME_UART
void platformUartRestore(void) {}
otError otPlatUartEnable(void) { return OT_ERROR_NONE; }
otError otPlatUartDisable(void) { return OT_ERROR_NONE; }
otError otPlatUartSend(const uint8_t *aData, uint16_t aLength)
otError platformUartSendVirtual(const uint8_t *aData, uint16_t aLength)
{
otError error = OT_ERROR_NONE;
struct Event event;
@@ -173,9 +167,6 @@ otError otPlatUartSend(const uint8_t *aData, uint16_t aLength)
return error;
}
otError otPlatUartFlush(void) { return OT_ERROR_NONE; }
#endif // OPENTHREAD_SIMULATION_VIRTUAL_TIME_UART
static void socket_init(void)
{
{
@@ -247,6 +238,7 @@ static void socket_init(void)
void otSysInit(int argc, char *argv[])
{
char *endptr;
int argi = 1;
if (gPlatformPseudoResetWasRequested)
{
@@ -254,22 +246,30 @@ void otSysInit(int argc, char *argv[])
return;
}
if (argc != 2)
{
DieNow(OT_EXIT_FAILURE);
}
openlog(basename(argv[0]), LOG_PID, LOG_USER);
setlogmask(setlogmask(0) & LOG_UPTO(LOG_NOTICE));
gArgumentsCount = argc;
gArguments = argv;
gNodeId = (uint32_t)strtol(argv[1], &endptr, 0);
if (!strcmp(argv[argi], "-U"))
{
gVirtualUart = true;
++argi;
}
gNodeId = (uint32_t)strtol(argv[argi], &endptr, 0);
if (*endptr != '\0' || gNodeId < 1 || gNodeId > MAX_NETWORK_SIZE)
{
fprintf(stderr, "Invalid NodeId: %s\n", argv[1]);
fprintf(stderr, "Invalid NodeId: %s\n", argv[argi]);
DieNow(OT_EXIT_FAILURE);
}
++argi;
if (argi != argc)
{
DieNow(OT_EXIT_FAILURE);
}
@@ -307,9 +307,7 @@ void otSysProcessDrivers(otInstance *aInstance)
FD_SET(sSockFd, &read_fds);
max_fd = sSockFd;
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME_UART == 0
platformUartUpdateFdSet(&read_fds, &write_fds, &error_fds, &max_fd);
#endif
if (!otTaskletsArePending(aInstance) && platformAlarmGetNext() > 0 && !platformRadioIsTransmitPending())
{
@@ -331,9 +329,7 @@ void otSysProcessDrivers(otInstance *aInstance)
platformAlarmProcess(aInstance);
platformRadioProcess(aInstance, &read_fds, &write_fds);
#if OPENTHREAD_SIMULATION_VIRTUAL_TIME_UART == 0
platformUartProcess();
#endif
}
#if OPENTHREAD_CONFIG_OTNS_ENABLE
-9
View File
@@ -164,20 +164,11 @@ build_simulation()
OT_CMAKE_BUILD_DIR="${OT_BUILDDIR}/openthread-simulation-${version}" "${OT_SRCDIR}"/script/cmake-build simulation "${options[@]}"
if [[ ${VIRTUAL_TIME} == 1 ]] && [[ ${OT_NODE_TYPE} == rcp* ]]; then
OT_CMAKE_NINJA_TARGET=ot-rcp OT_CMAKE_BUILD_DIR="${OT_BUILDDIR}/openthread-simulation-${version}" "${OT_SRCDIR}"/script/cmake-build simulation "${options[@]}" "-DOT_SIMULATION_VIRTUAL_TIME_UART=ON"
fi
if [[ ${version} != "1.1" && ${INTER_OP_BBR} == 1 ]]; then
options+=("-DOT_BACKBONE_ROUTER=ON")
OT_CMAKE_BUILD_DIR="${OT_BUILDDIR}/openthread-simulation-${version}-bbr" "${OT_SRCDIR}"/script/cmake-build simulation "${options[@]}"
if [[ ${VIRTUAL_TIME} == 1 ]] && [[ ${OT_NODE_TYPE} == rcp* ]]; then
OT_CMAKE_NINJA_TARGET=ot-rcp OT_CMAKE_BUILD_DIR="${OT_BUILDDIR}/openthread-simulation-${version}-bbr" "${OT_SRCDIR}"/script/cmake-build simulation "${options[@]}" "-DOT_SIMULATION_VIRTUAL_TIME_UART=ON"
fi
fi
}
+14 -13
View File
@@ -91,11 +91,12 @@ class OtbrDocker:
logging.info(f"socat running: device PTY: {rcp_device_pty}, device: {rcp_device}")
ot_rcp_path = self._get_ot_rcp_path()
self._ot_rcp_proc = subprocess.Popen(f"{ot_rcp_path} {nodeid} > {rcp_device_pty} < {rcp_device_pty}",
shell=True,
stdin=subprocess.DEVNULL,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
self._ot_rcp_proc = subprocess.Popen(
f"{ot_rcp_path} {'-U' if config.VIRTUAL_TIME else ''} {nodeid} > {rcp_device_pty} < {rcp_device_pty}",
shell=True,
stdin=subprocess.DEVNULL,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL)
try:
self._ot_rcp_proc.wait(1)
@@ -644,8 +645,8 @@ class OtCli:
cmd = '%s/examples/apps/cli/ot-cli-%s' % (srcdir, mode)
if 'RADIO_DEVICE' in os.environ:
cmd += ' --real-time-signal=+1 -v spinel+hdlc+uart://%s?forkpty-arg=%d' % (os.environ['RADIO_DEVICE'],
nodeid)
cmd += ' --real-time-signal=+1 -v spinel+hdlc+uart://%s?%sforkpty-arg=%d' % (
os.environ['RADIO_DEVICE'], 'forkpty-arg=-U&' if config.VIRTUAL_TIME else '', nodeid)
self.is_posix = True
else:
cmd += ' %d' % nodeid
@@ -660,8 +661,8 @@ class OtCli:
cmd = '%s/examples/apps/cli/ot-cli-%s' % (srcdir, mode)
if 'RADIO_DEVICE_1_1' in os.environ:
cmd += ' --real-time-signal=+1 -v spinel+hdlc+uart://%s?forkpty-arg=%d' % (
os.environ['RADIO_DEVICE_1_1'], nodeid)
cmd += ' --real-time-signal=+1 -v spinel+hdlc+uart://%s?%sforkpty-arg=%d' % (
os.environ['RADIO_DEVICE_1_1'], 'forkpty-arg=-U&' if config.VIRTUAL_TIME else '', nodeid)
self.is_posix = True
else:
cmd += ' %d' % nodeid
@@ -689,8 +690,8 @@ class OtCli:
# If Thread version of node matches the testing environment version.
if self.version == self.env_version:
if 'RADIO_DEVICE' in os.environ:
args = ' --real-time-signal=+1 spinel+hdlc+uart://%s?forkpty-arg=%d' % (os.environ['RADIO_DEVICE'],
nodeid)
args = ' --real-time-signal=+1 spinel+hdlc+uart://%s?%sforkpty-arg=%d' % (
os.environ['RADIO_DEVICE'], 'forkpty-arg=-U&' if config.VIRTUAL_TIME else '', nodeid)
self.is_posix = True
else:
args = ''
@@ -729,8 +730,8 @@ class OtCli:
# Load Thread 1.1 node when testing Thread 1.2 scenarios for interoperability.
elif self.version == '1.1':
if 'RADIO_DEVICE_1_1' in os.environ:
args = ' --real-time-signal=+1 spinel+hdlc+uart://%s?forkpty-arg=%d' % (os.environ['RADIO_DEVICE_1_1'],
nodeid)
args = ' --real-time-signal=+1 spinel+hdlc+uart://%s?%sforkpty-arg=%d' % (
os.environ['RADIO_DEVICE_1_1'], 'forkpty-arg=-U&' if config.VIRTUAL_TIME else '', nodeid)
self.is_posix = True
else:
args = ''