From 54fdd3547bc8125721b3b0520a7b433f614d7625 Mon Sep 17 00:00:00 2001 From: Bartosz Podrygajlo Date: Fri, 8 Aug 2025 16:51:22 +0200 Subject: [PATCH] Clean exit of vrtsim client if server is stopped first Force exit in case current sample is not modified by the server with 2s. --- .../utils/shm_iq_channel/shm_td_iq_channel.c | 18 +++++----- .../utils/shm_iq_channel/shm_td_iq_channel.h | 4 ++- radio/vrtsim/vrtsim.c | 35 +++++++++++++++---- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/common/utils/shm_iq_channel/shm_td_iq_channel.c b/common/utils/shm_iq_channel/shm_td_iq_channel.c index 126c386be9..ecebbaf494 100644 --- a/common/utils/shm_iq_channel/shm_td_iq_channel.c +++ b/common/utils/shm_iq_channel/shm_td_iq_channel.c @@ -223,12 +223,12 @@ void shm_td_iq_channel_produce_samples(ShmTDIQChannel *channel, size_t num_sampl mutexunlock(data->mutex); } -void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp, uint64_t timeout_uS) +int shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp, uint64_t timeout_uS) { ShmTDIQChannelData *data = channel->data; size_t current_timestamp = data->timestamp; if (current_timestamp >= timestamp) { - return; + return 0; } if (timeout_uS == 0) { mutexlock(data->mutex); @@ -241,8 +241,7 @@ void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp, uint64_ struct timespec ts = {.tv_sec = 0, .tv_nsec = 0}; if (clock_gettime(CLOCK_REALTIME, &ts) != 0) { fprintf(stderr, "Error: clock_gettime failed: %s\n", strerror(errno)); - channel->abort = true; - return; + return 1; } ts.tv_sec += timeout_uS / 1000000; // Convert microseconds to seconds @@ -252,19 +251,20 @@ void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp, uint64_ while (current_timestamp < timestamp && !channel->abort) { int ret = pthread_cond_timedwait(&data->cond, &data->mutex, &ts); if (ret == ETIMEDOUT) { - channel->abort = true; - fprintf(stderr, "Error: Timed out waiting for samples. Aborting vrtsim\n");\ - break; + fprintf(stderr, "Error: Timed out waiting for samples.\n"); + mutexunlock(data->mutex); + return 1; } else if (ret != 0) { - channel->abort = true; fprintf(stderr, "Error: pthread_cond_timedwait failed: %s\n", strerror(ret)); - break; + mutexunlock(data->mutex); + return 1; } else { current_timestamp = data->timestamp; } } mutexunlock(data->mutex); } + return 0; } uint64_t shm_td_iq_channel_get_current_sample(const ShmTDIQChannel *channel) diff --git a/common/utils/shm_iq_channel/shm_td_iq_channel.h b/common/utils/shm_iq_channel/shm_td_iq_channel.h index 8c7bfad318..b71720c1f9 100644 --- a/common/utils/shm_iq_channel/shm_td_iq_channel.h +++ b/common/utils/shm_iq_channel/shm_td_iq_channel.h @@ -120,8 +120,10 @@ void shm_td_iq_channel_produce_samples(ShmTDIQChannel *channel, uint64_t num_sam * @param channel The ShmTDIQChannel structure. * @param timestamp The timestamp for which to wait. * @param timeout_uS The timeout in microseconds to wait for the sample. 0 means wait indefinitely. + * + * @return 0 if the sample is available, 1 if timed out */ -void shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp, uint64_t timeout_uS); +int shm_td_iq_channel_wait(ShmTDIQChannel *channel, uint64_t timestamp, uint64_t timeout_uS); /** * @brief Aborts the IQ channel causing the wait to return immediately diff --git a/radio/vrtsim/vrtsim.c b/radio/vrtsim/vrtsim.c index f5d2410bf1..97c820a859 100644 --- a/radio/vrtsim/vrtsim.c +++ b/radio/vrtsim/vrtsim.c @@ -223,6 +223,7 @@ static void *vrtsim_timing_job(void *arg) samples_to_produce += 1; leftover_samples -= 1; } + AssertFatal(samples_to_produce >= 0, "Negative samples to produce: %f\n", samples_to_produce); shm_td_iq_channel_produce_samples(vrtsim_state->channel, samples_to_produce); usleep(1); } @@ -544,6 +545,12 @@ static int vrtsim_write_with_chanmod(vrtsim_state_t *vrtsim_state, static int vrtsim_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) { + AssertFatal(nsamps > 0, "Number of samples must be greater than 0\n"); + AssertFatal(nbAnt > 0 && nbAnt <= MAX_NUM_ANTENNAS_TX, + "Number of antennas %d must be between 1 and %d\n", + nbAnt, + MAX_NUM_ANTENNAS_TX); + AssertFatal(timestamp >= 0, "Timestamp must be non-negative, got %ld\n", timestamp); timestamp -= device->openair0_cfg->command_line_sample_advance; vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv; bool channel_modelling = vrtsim_state->chanmod || vrtsim_state->taps_socket; @@ -555,13 +562,29 @@ static int vrtsim_read(openair0_device *device, openair0_timestamp *ptimestamp, { vrtsim_state_t *vrtsim_state = (vrtsim_state_t *)device->priv; if (shm_td_iq_channel_is_aborted(vrtsim_state->channel)) { - for (int i = 0; i < nbAnt; i++) { - memset(samplesVoid[i], 0, sizeof(c16_t) * nsamps); - } - return nsamps; + return 0; } - uint64_t timeout_uS = 2 * 1000 * 1000 / vrtsim_state->timescale; // 2 seconds in uS - shm_td_iq_channel_wait(vrtsim_state->channel, vrtsim_state->last_received_sample + nsamps, timeout_uS); + if (vrtsim_state->role == ROLE_SERVER) { + uint64_t timeout_uS = 0; // 0 means no timeout + shm_td_iq_channel_wait(vrtsim_state->channel, vrtsim_state->last_received_sample + nsamps, timeout_uS); + } else { + uint64_t start_sample = shm_td_iq_channel_get_current_sample(vrtsim_state->channel); + uint64_t timeout_uS = 2 * 1000 * 1000; // 2 seconds timeout waiting for sample number to change + // + while (shm_td_iq_channel_wait(vrtsim_state->channel, vrtsim_state->last_received_sample + nsamps, timeout_uS) == 1) { + uint64_t sample = shm_td_iq_channel_get_current_sample(vrtsim_state->channel); + if (sample == start_sample) { + LOG_E(HW, + "VRTSIM: Read timeout waiting for sample %lu to change, aborting channel\n", + vrtsim_state->last_received_sample + nsamps); + shm_td_iq_channel_abort(vrtsim_state->channel); + break; + } else { + start_sample = sample; + } + } + } + int ret = shm_td_iq_channel_rx(vrtsim_state->channel, vrtsim_state->last_received_sample, nsamps, 0, samplesVoid[0]); if (ret == CHANNEL_ERROR_TOO_LATE) { vrtsim_state->rx_samples_late += nsamps;