RF simulator: Fix concurrency issues during new client connections
Fix concurrency issues happening when a new client connects, sometimes leading to a total softmodem deadlock. Key changes: - Fix sample sending on new client connection: send the first sample only to the newly connected client. - Remove the --rfsimulator.hanging-workaround option - Replace global nb_ue and Sockmutex with nb_cnx and Sockmutex in rfsimulator_state_t for better concurrency and clarity.
This commit is contained in:
@@ -179,7 +179,6 @@ services:
|
|||||||
--uicc0.imsi 208990100001100
|
--uicc0.imsi 208990100001100
|
||||||
--rfsimulator.options chanmod
|
--rfsimulator.options chanmod
|
||||||
--rfsimulator.serveraddr server
|
--rfsimulator.serveraddr server
|
||||||
--rfsimulator.hanging-workaround 1
|
|
||||||
--telnetsrv --telnetsrv.shrmod ciUE --telnetsrv.listenaddr 192.168.71.181 --telnetsrv.listenport 8091
|
--telnetsrv --telnetsrv.shrmod ciUE --telnetsrv.listenaddr 192.168.71.181 --telnetsrv.listenport 8091
|
||||||
--channelmod.modellist_rfsimu_1.[0].model_name rfsimu_channel_ue0
|
--channelmod.modellist_rfsimu_1.[0].model_name rfsimu_channel_ue0
|
||||||
--channelmod.modellist_rfsimu_1.[1].model_name rfsimu_channel_ue1
|
--channelmod.modellist_rfsimu_1.[1].model_name rfsimu_channel_ue1
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ The RF simulator is using the configuration module, and its parameters are defin
|
|||||||
|`--rfsimulator.IQfile <file>` | path to a file to store the IQ samples to (only with `saviq`) | `/tmp/rfsimulator.iqs` |
|
|`--rfsimulator.IQfile <file>` | path to a file to store the IQ samples to (only with `saviq`) | `/tmp/rfsimulator.iqs` |
|
||||||
|`--rfsimulator.prop_delay` | simulated receive-path (gNB: UL, UE: DL) propagation delay in ms | 0 |
|
|`--rfsimulator.prop_delay` | simulated receive-path (gNB: UL, UE: DL) propagation delay in ms | 0 |
|
||||||
|`--rfsimulator.wait_timeout` | wait timeout when no UE is connected | 1 |
|
|`--rfsimulator.wait_timeout` | wait timeout when no UE is connected | 1 |
|
||||||
|`--rfismulator.hanging-workaround`| Enable workaround to de-block potentially hanging server on new client connection. | 0 |
|
|
||||||
|
|
||||||
Please refer to this document [`SIMULATION/TOOLS/DOC/channel_simulation.md`](../../openair1/SIMULATION/TOOLS/DOC/channel_simulation.md) for information about using the RFSimulator options to run the simulator with a channel model.
|
Please refer to this document [`SIMULATION/TOOLS/DOC/channel_simulation.md`](../../openair1/SIMULATION/TOOLS/DOC/channel_simulation.md) for information about using the RFSimulator options to run the simulator with a channel model.
|
||||||
|
|
||||||
|
|||||||
@@ -80,31 +80,30 @@ typedef enum { SIMU_ROLE_SERVER = 1, SIMU_ROLE_CLIENT } simuRole;
|
|||||||
#define RFSIMU_SECTION "rfsimulator"
|
#define RFSIMU_SECTION "rfsimulator"
|
||||||
#define RFSIMU_OPTIONS_PARAMNAME "options"
|
#define RFSIMU_OPTIONS_PARAMNAME "options"
|
||||||
|
|
||||||
|
#define RFSIM_CONFIG_HELP_OPTIONS \
|
||||||
#define RFSIM_CONFIG_HELP_OPTIONS " list of comma separated options to enable rf simulator functionalities. Available options: \n"\
|
" list of comma separated options to enable rf simulator functionalities. Available options: \n" \
|
||||||
" chanmod: enable channel modelisation\n"\
|
" chanmod: enable channel modelisation\n" \
|
||||||
" saviq: enable saving written iqs to a file\n"
|
" saviq: enable saving written iqs to a file\n"
|
||||||
#define CONFIG_HELP_HANG_WORKAROUND "Enable workaroud for server mode hanging on new client connection.\n"
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||||
/* configuration parameters for the rfsimulator device */
|
/* configuration parameters for the rfsimulator device */
|
||||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||||
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||||
#define simOpt PARAMFLAG_NOFREE|PARAMFLAG_CMDLINE_NOPREFIXENABLED
|
#define simOpt PARAMFLAG_NOFREE|PARAMFLAG_CMDLINE_NOPREFIXENABLED
|
||||||
|
// clang-format off
|
||||||
#define RFSIMULATOR_PARAMS_DESC { \
|
#define RFSIMULATOR_PARAMS_DESC { \
|
||||||
{"serveraddr", "<ip address to connect to>\n", simOpt, .strptr=&rfsimulator->ip, .defstrval="127.0.0.1", TYPE_STRING, 0 },\
|
{"serveraddr", "<ip address to connect to>\n", simOpt, .strptr=&rfsimulator->ip, .defstrval="127.0.0.1", TYPE_STRING, 0 },\
|
||||||
{"serverport", "<port to connect to>\n", simOpt, .u16ptr=&(rfsimulator->port), .defuintval=PORT, TYPE_UINT16, 0 },\
|
{"serverport", "<port to connect to>\n", simOpt, .u16ptr = &(rfsimulator->port), .defuintval = PORT, TYPE_UINT16, 0}, \
|
||||||
{RFSIMU_OPTIONS_PARAMNAME, RFSIM_CONFIG_HELP_OPTIONS, 0, .strlistptr=NULL, .defstrlistval=NULL, TYPE_STRINGLIST,0 },\
|
{RFSIMU_OPTIONS_PARAMNAME, RFSIM_CONFIG_HELP_OPTIONS, 0, .strlistptr = NULL, .defstrlistval = NULL, TYPE_STRINGLIST, 0}, \
|
||||||
{"IQfile", "<file path to use when saving IQs>\n",simOpt, .strptr=&saveF, .defstrval="/tmp/rfsimulator.iqs",TYPE_STRING, 0 },\
|
{"IQfile", "<file path to use when saving IQs>\n",simOpt, .strptr=&saveF, .defstrval="/tmp/rfsimulator.iqs",TYPE_STRING, 0 },\
|
||||||
{"modelname", "<channel model name>\n", simOpt, .strptr=&modelname, .defstrval="AWGN", TYPE_STRING, 0 },\
|
{"modelname", "<channel model name>\n", simOpt, .strptr = &modelname, .defstrval = "AWGN", TYPE_STRING, 0}, \
|
||||||
{"ploss", "<channel path loss in dB>\n", simOpt, .dblptr=&(rfsimulator->chan_pathloss), .defdblval=0, TYPE_DOUBLE, 0 },\
|
{"ploss", "<channel path loss in dB>\n", simOpt, .dblptr = &(rfsimulator->chan_pathloss), .defdblval = 0, TYPE_DOUBLE, 0}, \
|
||||||
{"forgetfact", "<channel forget factor ((0 to 1)>\n", simOpt, .dblptr=&(rfsimulator->chan_forgetfact),.defdblval=0, TYPE_DOUBLE, 0 },\
|
{"forgetfact", "<channel forget factor ((0 to 1)>\n", simOpt, .dblptr=&(rfsimulator->chan_forgetfact),.defdblval=0, TYPE_DOUBLE, 0 },\
|
||||||
{"offset", "<channel offset in samps>\n", simOpt, .u64ptr=&(rfsimulator->chan_offset), .defint64val=0, TYPE_UINT64, 0 },\
|
{"offset", "<channel offset in samps>\n", simOpt, .u64ptr = &(rfsimulator->chan_offset), .defint64val = 0, TYPE_UINT64, 0}, \
|
||||||
{"prop_delay", "<propagation delay in ms>\n", simOpt, .dblptr=&(rfsimulator->prop_delay_ms), .defdblval=0.0, TYPE_DOUBLE, 0 },\
|
{"prop_delay", "<propagation delay in ms>\n", simOpt, .dblptr=&(rfsimulator->prop_delay_ms), .defdblval=0.0, TYPE_DOUBLE, 0 },\
|
||||||
{"wait_timeout", "<wait timeout if no UE connected>\n", simOpt, .iptr=&(rfsimulator->wait_timeout), .defintval=1, TYPE_INT, 0 },\
|
{"wait_timeout", "<wait timeout if no UE connected>\n", simOpt, .iptr=&(rfsimulator->wait_timeout), .defintval=1, TYPE_INT, 0 },\
|
||||||
{"hanging-workaround", CONFIG_HELP_HANG_WORKAROUND, simOpt, .iptr=&rfsimulator->hanging_workaround, .defintval=0, TYPE_INT, 0 },\
|
|
||||||
};
|
};
|
||||||
|
// clang-format on
|
||||||
static void getset_currentchannels_type(char *buf, int debug, webdatadef_t *tdata, telnet_printfunc_t prnt);
|
static void getset_currentchannels_type(char *buf, int debug, webdatadef_t *tdata, telnet_printfunc_t prnt);
|
||||||
extern int get_currentchannels_type(char *buf, int debug, webdatadef_t *tdata, telnet_printfunc_t prnt); // in random_channel.c
|
extern int get_currentchannels_type(char *buf, int debug, webdatadef_t *tdata, telnet_printfunc_t prnt); // in random_channel.c
|
||||||
static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg);
|
static int rfsimu_setchanmod_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg);
|
||||||
@@ -122,11 +121,7 @@ static telnetshell_cmddef_t rfsimu_cmdarray[] = {
|
|||||||
static telnetshell_cmddef_t *setmodel_cmddef = &(rfsimu_cmdarray[1]);
|
static telnetshell_cmddef_t *setmodel_cmddef = &(rfsimu_cmdarray[1]);
|
||||||
|
|
||||||
static telnetshell_vardef_t rfsimu_vardef[] = {{"", 0, 0, NULL}};
|
static telnetshell_vardef_t rfsimu_vardef[] = {{"", 0, 0, NULL}};
|
||||||
pthread_mutex_t Sockmutex;
|
|
||||||
unsigned int nb_ue = 0;
|
|
||||||
|
|
||||||
static uint64_t CirSize = minCirSize;
|
static uint64_t CirSize = minCirSize;
|
||||||
|
|
||||||
typedef c16_t sample_t; // 2*16 bits complex number
|
typedef c16_t sample_t; // 2*16 bits complex number
|
||||||
|
|
||||||
typedef struct buffer_s {
|
typedef struct buffer_s {
|
||||||
@@ -144,6 +139,8 @@ typedef struct buffer_s {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int listen_sock, epollfd;
|
int listen_sock, epollfd;
|
||||||
|
pthread_mutex_t Sockmutex;
|
||||||
|
unsigned int nb_cnx;
|
||||||
openair0_timestamp nextRxTstamp;
|
openair0_timestamp nextRxTstamp;
|
||||||
openair0_timestamp lastWroteTS;
|
openair0_timestamp lastWroteTS;
|
||||||
simuRole role;
|
simuRole role;
|
||||||
@@ -165,7 +162,6 @@ typedef struct {
|
|||||||
poll_telnetcmdq_func_t poll_telnetcmdq;
|
poll_telnetcmdq_func_t poll_telnetcmdq;
|
||||||
int wait_timeout;
|
int wait_timeout;
|
||||||
double prop_delay_ms;
|
double prop_delay_ms;
|
||||||
int hanging_workaround;
|
|
||||||
} rfsimulator_state_t;
|
} rfsimulator_state_t;
|
||||||
|
|
||||||
static buffer_t *allocCirBuf(rfsimulator_state_t *bridge, int sock)
|
static buffer_t *allocCirBuf(rfsimulator_state_t *bridge, int sock)
|
||||||
@@ -214,7 +210,11 @@ static buffer_t *allocCirBuf(rfsimulator_state_t *bridge, int sock)
|
|||||||
init_done=true;
|
init_done=true;
|
||||||
}
|
}
|
||||||
char modelname[30];
|
char modelname[30];
|
||||||
snprintf(modelname, sizeofArray(modelname), "rfsimu_channel_%s%d", (bridge->role == SIMU_ROLE_SERVER) ? "ue" : "enB", nb_ue);
|
snprintf(modelname,
|
||||||
|
sizeofArray(modelname),
|
||||||
|
"rfsimu_channel_%s%d",
|
||||||
|
(bridge->role == SIMU_ROLE_SERVER) ? "ue" : "enB",
|
||||||
|
bridge->nb_cnx);
|
||||||
ptr->channel_model = find_channel_desc_fromname(modelname); // path_loss in dB
|
ptr->channel_model = find_channel_desc_fromname(modelname); // path_loss in dB
|
||||||
if (!ptr->channel_model) {
|
if (!ptr->channel_model) {
|
||||||
// Use legacy method to find channel model - this will use the same channel model for all clients
|
// Use legacy method to find channel model - this will use the same channel model for all clients
|
||||||
@@ -246,7 +246,7 @@ static void removeCirBuf(rfsimulator_state_t *bridge, buffer_t *buf)
|
|||||||
// free(bridge->buf[sock].channel_model);
|
// free(bridge->buf[sock].channel_model);
|
||||||
memset(buf, 0, sizeof(buffer_t));
|
memset(buf, 0, sizeof(buffer_t));
|
||||||
buf->conn_sock = -1;
|
buf->conn_sock = -1;
|
||||||
nb_ue--;
|
bridge->nb_cnx--;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void socketError(rfsimulator_state_t *bridge, buffer_t *buf)
|
static void socketError(rfsimulator_state_t *bridge, buffer_t *buf)
|
||||||
@@ -286,8 +286,6 @@ static int setblocking(int sock, enum blocking_t active)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps);
|
|
||||||
|
|
||||||
static void fullwrite(int fd, void *_buf, ssize_t count, rfsimulator_state_t *t) {
|
static void fullwrite(int fd, void *_buf, ssize_t count, rfsimulator_state_t *t) {
|
||||||
if (t->saveIQfile != -1) {
|
if (t->saveIQfile != -1) {
|
||||||
if (write(t->saveIQfile, _buf, count) != count )
|
if (write(t->saveIQfile, _buf, count) != count )
|
||||||
@@ -450,25 +448,6 @@ static void getset_currentchannels_type(char *buf, int debug, webdatadef_t *tdat
|
|||||||
get_currentchannels_type("modify type", debug, tdata, prnt);
|
get_currentchannels_type("modify type", debug, tdata, prnt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*getset_currentchannels_type */
|
|
||||||
|
|
||||||
//static void print_cirBuf(struct complex16 *circularBuf,
|
|
||||||
// uint64_t firstSample,
|
|
||||||
// uint32_t cirSize,
|
|
||||||
// int neg,
|
|
||||||
// int pos,
|
|
||||||
// int nbTx)
|
|
||||||
//{
|
|
||||||
// for (int i = -neg; i < pos ; ++i) {
|
|
||||||
// for (int txAnt = 0; txAnt < nbTx; txAnt++) {
|
|
||||||
// const int idx = ((firstSample + i) * nbTx + txAnt + cirSize) % cirSize;
|
|
||||||
// if (i == 0)
|
|
||||||
// printf("->");
|
|
||||||
// printf("%08x%08x\n", circularBuf[idx].r, circularBuf[idx].i);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// printf("\n");
|
|
||||||
//}
|
|
||||||
|
|
||||||
static int rfsimu_setdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg)
|
static int rfsimu_setdistance_cmd(char *buff, int debug, telnet_printfunc_t prnt, void *arg)
|
||||||
{
|
{
|
||||||
@@ -681,10 +660,14 @@ static int startClient(openair0_device *device)
|
|||||||
return allocCirBuf(t, sock) == NULL ? -1 : 0;
|
return allocCirBuf(t, sock) == NULL ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags, bool alreadyLocked) {
|
static int rfsimulator_write_internal(rfsimulator_state_t *t,
|
||||||
if (!alreadyLocked)
|
openair0_timestamp timestamp,
|
||||||
pthread_mutex_lock(&Sockmutex);
|
void **samplesVoid,
|
||||||
|
int nsamps,
|
||||||
|
int nbAnt,
|
||||||
|
int flags)
|
||||||
|
{
|
||||||
|
mutexlock(t->Sockmutex);
|
||||||
LOG_D(HW, "Sending %d samples at time: %ld, nbAnt %d\n", nsamps, timestamp, nbAnt);
|
LOG_D(HW, "Sending %d samples at time: %ld, nbAnt %d\n", nsamps, timestamp, nbAnt);
|
||||||
|
|
||||||
for (int i = 0; i < MAX_FD_RFSIMU; i++) {
|
for (int i = 0; i < MAX_FD_RFSIMU; i++) {
|
||||||
@@ -692,24 +675,17 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp
|
|||||||
|
|
||||||
if (b->conn_sock >= 0 ) {
|
if (b->conn_sock >= 0 ) {
|
||||||
samplesBlockHeader_t header = {nsamps, nbAnt, timestamp};
|
samplesBlockHeader_t header = {nsamps, nbAnt, timestamp};
|
||||||
fullwrite(b->conn_sock,&header, sizeof(header), t);
|
fullwrite(b->conn_sock, &header, sizeof(header), t);
|
||||||
sample_t tmpSamples[nsamps][nbAnt];
|
|
||||||
|
|
||||||
if (nbAnt == 1) {
|
if (nbAnt == 1) {
|
||||||
if (b->conn_sock >= 0) {
|
fullwrite(b->conn_sock, samplesVoid[0], sampleToByte(nsamps, nbAnt), t);
|
||||||
fullwrite(b->conn_sock, samplesVoid[0], sampleToByte(nsamps, nbAnt), t);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
sample_t tmpSamples[nsamps][nbAnt];
|
||||||
for (int a = 0; a < nbAnt; a++) {
|
for (int a = 0; a < nbAnt; a++) {
|
||||||
sample_t *in = (sample_t *)samplesVoid[a];
|
sample_t *in = (sample_t *)samplesVoid[a];
|
||||||
|
|
||||||
for (int s = 0; s < nsamps; s++)
|
for (int s = 0; s < nsamps; s++)
|
||||||
tmpSamples[s][a] = in[s];
|
tmpSamples[s][a] = in[s];
|
||||||
}
|
}
|
||||||
|
fullwrite(b->conn_sock, (void *)tmpSamples, sampleToByte(nsamps, nbAnt), t);
|
||||||
if (b->conn_sock >= 0) {
|
|
||||||
fullwrite(b->conn_sock, (void *)tmpSamples, sampleToByte(nsamps, nbAnt), t);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -727,10 +703,8 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp
|
|||||||
timestamp,
|
timestamp,
|
||||||
timestamp - t->lastWroteTS);
|
timestamp - t->lastWroteTS);
|
||||||
|
|
||||||
t->lastWroteTS=timestamp+nsamps;
|
t->lastWroteTS = timestamp + nsamps;
|
||||||
|
mutexunlock(t->Sockmutex);
|
||||||
if (!alreadyLocked)
|
|
||||||
pthread_mutex_unlock(&Sockmutex);
|
|
||||||
|
|
||||||
LOG_D(HW,
|
LOG_D(HW,
|
||||||
"Sent %d samples at time: %ld->%ld, energy in first antenna: %d\n",
|
"Sent %d samples at time: %ld->%ld, energy in first antenna: %d\n",
|
||||||
@@ -743,8 +717,7 @@ static int rfsimulator_write_internal(rfsimulator_state_t *t, openair0_timestamp
|
|||||||
|
|
||||||
static int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) {
|
static int rfsimulator_write(openair0_device *device, openair0_timestamp timestamp, void **samplesVoid, int nsamps, int nbAnt, int flags) {
|
||||||
timestamp -= device->openair0_cfg->command_line_sample_advance;
|
timestamp -= device->openair0_cfg->command_line_sample_advance;
|
||||||
return rfsimulator_write_internal(device->priv, timestamp, samplesVoid, nsamps, nbAnt, flags, false); // false = with lock
|
return rfsimulator_write_internal(device->priv, timestamp, samplesVoid, nsamps, nbAnt, flags);
|
||||||
// return rfsimulator_write_internal(device->priv, timestamp, samplesVoid, nsamps, nbAnt, flags, true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initial) {
|
static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initial) {
|
||||||
@@ -766,8 +739,9 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi
|
|||||||
buffer_t *b = events[nbEv].data.ptr;
|
buffer_t *b = events[nbEv].data.ptr;
|
||||||
|
|
||||||
if (events[nbEv].events & EPOLLIN && b == NULL) {
|
if (events[nbEv].events & EPOLLIN && b == NULL) {
|
||||||
int conn_sock;
|
struct sockaddr_storage sa = {0};
|
||||||
conn_sock = accept(t->listen_sock, NULL, NULL);
|
socklen_t socklen = sizeof(sa);
|
||||||
|
int conn_sock = accept(t->listen_sock, (struct sockaddr *)&sa, &socklen);
|
||||||
if (conn_sock == -1) {
|
if (conn_sock == -1) {
|
||||||
LOG_E(HW, "accept() failed, errno(%d)\n", errno);
|
LOG_E(HW, "accept() failed, errno(%d)\n", errno);
|
||||||
return false;
|
return false;
|
||||||
@@ -775,22 +749,28 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi
|
|||||||
if (setblocking(conn_sock, notBlocking)) {
|
if (setblocking(conn_sock, notBlocking)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
mutexlock(t->Sockmutex);
|
||||||
buffer_t *new_buf = allocCirBuf(t, conn_sock);
|
buffer_t *new_buf = allocCirBuf(t, conn_sock);
|
||||||
if (new_buf == NULL) {
|
if (new_buf == NULL) {
|
||||||
|
mutexunlock(t->Sockmutex);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
LOG_I(HW, "A client connects, sending the current time\n");
|
t->nb_cnx++;
|
||||||
c16_t v= {0};
|
char ip[INET6_ADDRSTRLEN];
|
||||||
nb_ue++;
|
getnameinfo((struct sockaddr*)&sa, socklen, ip, sizeof(ip), NULL, 0, NI_NUMERICHOST);
|
||||||
|
uint16_t port = ((struct sockaddr_in *)&sa)->sin_port;
|
||||||
|
LOG_I(HW, "Client connects from %s:%d\n", ip, port);
|
||||||
|
c16_t v = {0};
|
||||||
void *samplesVoid[t->tx_num_channels];
|
void *samplesVoid[t->tx_num_channels];
|
||||||
|
|
||||||
for ( int i=0; i < t->tx_num_channels; i++)
|
for ( int i=0; i < t->tx_num_channels; i++)
|
||||||
samplesVoid[i]=(void *)&v;
|
samplesVoid[i] = (void *)&v;
|
||||||
|
samplesBlockHeader_t header = {1, t->tx_num_channels, t->lastWroteTS};
|
||||||
rfsimulator_write_internal(t, t->lastWroteTS > 1 ? t->lastWroteTS - 1 : 0, samplesVoid, 1, t->tx_num_channels, 1, false);
|
fullwrite(conn_sock, &header, sizeof(header), t);
|
||||||
|
fullwrite(conn_sock, samplesVoid, sampleToByte(1, t->tx_num_channels), t);
|
||||||
|
|
||||||
if (new_buf->channel_model)
|
if (new_buf->channel_model)
|
||||||
new_buf->channel_model->start_TS = t->lastWroteTS;
|
new_buf->channel_model->start_TS = t->lastWroteTS;
|
||||||
|
mutexunlock(t->Sockmutex);
|
||||||
} else {
|
} else {
|
||||||
if ( events[nbEv].events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP) ) {
|
if ( events[nbEv].events & (EPOLLHUP | EPOLLERR | EPOLLRDHUP) ) {
|
||||||
socketError(t, b);
|
socketError(t, b);
|
||||||
@@ -867,12 +847,11 @@ static bool flushInput(rfsimulator_state_t *t, int timeout, int nsamps_for_initi
|
|||||||
b->trashingPacket=true;
|
b->trashingPacket=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&Sockmutex);
|
mutexlock(t->Sockmutex);
|
||||||
|
|
||||||
if (t->lastWroteTS != 0 && (fabs((double)t->lastWroteTS-b->lastReceivedTS) > (double)CirSize))
|
if (t->lastWroteTS != 0 && (fabs((double)t->lastWroteTS-b->lastReceivedTS) > (double)CirSize))
|
||||||
LOG_W(HW, "UEsock(%d) Tx/Rx shift too large Tx:%lu, Rx:%lu\n", b->conn_sock, t->lastWroteTS, b->lastReceivedTS);
|
LOG_W(HW, "UEsock(%d) Tx/Rx shift too large Tx:%lu, Rx:%lu\n", b->conn_sock, t->lastWroteTS, b->lastReceivedTS);
|
||||||
|
mutexunlock(t->Sockmutex);
|
||||||
|
|
||||||
pthread_mutex_unlock(&Sockmutex);
|
|
||||||
b->transferPtr=(char *)&b->circularBuf[(b->lastReceivedTS*b->th.nbAnt)%CirSize];
|
b->transferPtr=(char *)&b->circularBuf[(b->lastReceivedTS*b->th.nbAnt)%CirSize];
|
||||||
b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt);
|
b->remainToTransfer=sampleToByte(b->th.size, b->th.nbAnt);
|
||||||
}
|
}
|
||||||
@@ -929,7 +908,6 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bool have_to_wait;
|
bool have_to_wait;
|
||||||
int loops = 0;
|
|
||||||
do {
|
do {
|
||||||
have_to_wait=false;
|
have_to_wait=false;
|
||||||
|
|
||||||
@@ -951,16 +929,9 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest
|
|||||||
t->nextRxTstamp + nsamps);
|
t->nextRxTstamp + nsamps);
|
||||||
flushInput(t, 3, nsamps);
|
flushInput(t, 3, nsamps);
|
||||||
}
|
}
|
||||||
if (t->hanging_workaround && loops++ > 10 && t->role == SIMU_ROLE_SERVER && nb_ue > 1) {
|
|
||||||
// Just start producing samples. The clients will catch up.
|
|
||||||
have_to_wait = false;
|
|
||||||
LOG_W(HW,
|
|
||||||
"No longer waiting for clients to catch up, starting to produce samples\n");
|
|
||||||
}
|
|
||||||
} while (have_to_wait);
|
} while (have_to_wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct timespec start_time;
|
struct timespec start_time;
|
||||||
int ret = clock_gettime(CLOCK_REALTIME, &start_time);
|
int ret = clock_gettime(CLOCK_REALTIME, &start_time);
|
||||||
AssertFatal(ret == 0, "clock_gettime() failed: errno %d, %s\n", errno, strerror(errno));
|
AssertFatal(ret == 0, "clock_gettime() failed: errno %d, %s\n", errno, strerror(errno));
|
||||||
@@ -1005,7 +976,7 @@ static int rfsimulator_read(openair0_device *device, openair0_timestamp *ptimest
|
|||||||
int nbAnt_tx = ptr->th.nbAnt; // number of Tx antennas
|
int nbAnt_tx = ptr->th.nbAnt; // number of Tx antennas
|
||||||
int firstIndex = (CirSize + t->nextRxTstamp - t->chan_offset) % CirSize;
|
int firstIndex = (CirSize + t->nextRxTstamp - t->chan_offset) % CirSize;
|
||||||
sample_t *out = (sample_t *)samplesVoid[a];
|
sample_t *out = (sample_t *)samplesVoid[a];
|
||||||
if ((nbAnt_tx == 1) && ((nb_ue == 1) || (t->role == SIMU_ROLE_CLIENT))) { // optimized for 1 Tx and 1 UE
|
if ((nbAnt_tx == 1) && ((t->nb_cnx == 1) || (t->role == SIMU_ROLE_CLIENT))) { // optimized for 1 Tx and 1 UE
|
||||||
sample_t *firstSample = (sample_t *)&(ptr->circularBuf[firstIndex]);
|
sample_t *firstSample = (sample_t *)&(ptr->circularBuf[firstIndex]);
|
||||||
if (firstIndex + nsamps > CirSize) {
|
if (firstIndex + nsamps > CirSize) {
|
||||||
int tailSz = CirSize - firstIndex;
|
int tailSz = CirSize - firstIndex;
|
||||||
@@ -1137,7 +1108,7 @@ int device_init(openair0_device *device, openair0_config_t *openair0_cfg) {
|
|||||||
rfsimulator->prop_delay_ms = rfsimulator->chan_offset * 1000 / rfsimulator->sample_rate;
|
rfsimulator->prop_delay_ms = rfsimulator->chan_offset * 1000 / rfsimulator->sample_rate;
|
||||||
LOG_I(HW, "propagation delay %f ms, %lu samples\n", rfsimulator->prop_delay_ms, rfsimulator->chan_offset);
|
LOG_I(HW, "propagation delay %f ms, %lu samples\n", rfsimulator->prop_delay_ms, rfsimulator->chan_offset);
|
||||||
}
|
}
|
||||||
pthread_mutex_init(&Sockmutex, NULL);
|
mutexinit(rfsimulator->Sockmutex);
|
||||||
LOG_I(HW,
|
LOG_I(HW,
|
||||||
"Running as %s\n",
|
"Running as %s\n",
|
||||||
rfsimulator->role == SIMU_ROLE_SERVER ? "server waiting opposite rfsimulators to connect"
|
rfsimulator->role == SIMU_ROLE_SERVER ? "server waiting opposite rfsimulators to connect"
|
||||||
|
|||||||
Reference in New Issue
Block a user