mirror of https://github.com/PentHertz/srsLTE.git
ttcn3: make SS single threaded and use SCTP for test ports
- remove all threading from SS - use epoll to handle test port connections, signals, and timers - convert testport interface to SCTP
This commit is contained in:
parent
6d88b640b7
commit
b88e877b4c
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \brief Common helper function for epoll
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSLTE_EPOLL_HELPER_H
|
||||
#define SRSLTE_EPOLL_HELPER_H
|
||||
|
||||
#include <functional>
|
||||
#include <signal.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/timerfd.h>
|
||||
#include <unistd.h>
|
||||
|
||||
///< A virtual interface to handle epoll events (used by timer and port handler)
|
||||
class epoll_handler
|
||||
{
|
||||
public:
|
||||
virtual int handle_event(int fd, epoll_event e, int epoll_fd) = 0;
|
||||
};
|
||||
|
||||
///< Callback function called when timer expires
|
||||
using epoll_timer_callback = std::function<void(uint64_t res)>;
|
||||
|
||||
///< Epoll timer handler
|
||||
class epoll_timer_handler : public epoll_handler
|
||||
{
|
||||
public:
|
||||
epoll_timer_handler(int fd_, epoll_timer_callback callback_) : timer_fd(fd_), callback(callback_){};
|
||||
int handle_event(int fd, epoll_event e, int epoll_fd)
|
||||
{
|
||||
uint64_t res;
|
||||
int ret = read(fd, &res, sizeof(res));
|
||||
callback(res);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int get_timer_fd() { return timer_fd; };
|
||||
|
||||
private:
|
||||
int timer_fd = -1;
|
||||
epoll_timer_callback callback;
|
||||
};
|
||||
|
||||
///< Basic epoll signal handler
|
||||
class epoll_signal_handler : public epoll_handler
|
||||
{
|
||||
public:
|
||||
epoll_signal_handler(bool* running_) : running(running_) {}
|
||||
|
||||
int handle_event(int fd, epoll_event e, int epoll_fd)
|
||||
{
|
||||
struct signalfd_siginfo info;
|
||||
if (read(fd, &info, sizeof(info)) != sizeof(info)) {
|
||||
fprintf(stderr, "failed to read signal fd buffer\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
switch (info.ssi_signo) {
|
||||
case SIGTERM:
|
||||
case SIGINT:
|
||||
case SIGHUP:
|
||||
case SIGQUIT:
|
||||
*running = false;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "got signal %d\n", info.ssi_signo);
|
||||
break;
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
private:
|
||||
bool* running = nullptr;
|
||||
};
|
||||
|
||||
///< Create periodic epoll timer every 1ms
|
||||
int create_tti_timer()
|
||||
{
|
||||
int timer_fd = timerfd_create(CLOCK_MONOTONIC, 0);
|
||||
if (timer_fd == -1) {
|
||||
printf("timerfd_create() failed: errno=%d\n", errno);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
int msec = 1; // our 1ms TTI timer
|
||||
struct itimerspec ts = {};
|
||||
ts.it_value.tv_sec = msec / 1000;
|
||||
ts.it_value.tv_nsec = (msec % 1000) * 1000000;
|
||||
ts.it_interval.tv_sec = msec / 1000;
|
||||
ts.it_interval.tv_nsec = (msec % 1000) * 1000000;
|
||||
|
||||
if (timerfd_settime(timer_fd, 0, &ts, NULL) < 0) {
|
||||
printf("timerfd_settime() failed: errno=%d\n", errno);
|
||||
close(timer_fd);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
return timer_fd;
|
||||
}
|
||||
|
||||
///< Create signalfd for handling signals
|
||||
int add_signalfd()
|
||||
{
|
||||
// block all signals. we take signals synchronously via signalfd
|
||||
sigset_t all;
|
||||
sigfillset(&all);
|
||||
sigprocmask(SIG_SETMASK, &all, NULL);
|
||||
|
||||
// add signals we accept synchronously via signalfd
|
||||
std::vector<int> sigs = {SIGIO, SIGHUP, SIGTERM, SIGINT, SIGQUIT, SIGALRM};
|
||||
|
||||
sigset_t sw;
|
||||
sigemptyset(&sw);
|
||||
for (auto& sig : sigs) {
|
||||
sigaddset(&sw, sig);
|
||||
}
|
||||
|
||||
// create the signalfd for receiving signals
|
||||
int sig_fd = signalfd(-1, &sw, 0);
|
||||
if (sig_fd == -1) {
|
||||
fprintf(stderr, "signalfd: %s\n", strerror(errno));
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
return sig_fd;
|
||||
}
|
||||
|
||||
///< Add fd to epoll fd
|
||||
int add_epoll(int fd, int epoll_fd)
|
||||
{
|
||||
struct epoll_event ev = {};
|
||||
ev.data.fd = fd;
|
||||
ev.events = EPOLLIN;
|
||||
if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {
|
||||
fprintf(stderr, "epoll_ctl failed for fd=%d\n", fd);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
///< Remove fd from epoll
|
||||
int del_epoll(int fd, int epoll_fd)
|
||||
{
|
||||
struct epoll_event ev = {};
|
||||
ev.data.fd = fd;
|
||||
ev.events = EPOLLIN;
|
||||
if (epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fd, &ev) == -1) {
|
||||
fprintf(stderr, "epoll_ctl failed for fd=%d\n", fd);
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
#endif // SRSLTE_EPOLL_HELPER_H
|
|
@ -45,7 +45,7 @@ public:
|
|||
typedef std::vector<cell_t> cell_list_t;
|
||||
|
||||
lte_ttcn3_phy(srslte::logger* logger_);
|
||||
~lte_ttcn3_phy();
|
||||
~lte_ttcn3_phy() = default;
|
||||
|
||||
int init(const phy_args_t& args_, stack_interface_phy_lte* stack_, syssim_interface_phy* syssim_);
|
||||
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \brief Common types for TTCN3 test systems
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSUE_TTCN3_COMMON_H
|
||||
#define SRSUE_TTCN3_COMMON_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
const static uint32_t RX_BUF_SIZE = 1024 * 1024;
|
||||
typedef std::array<uint8_t, RX_BUF_SIZE> byte_array_t;
|
||||
typedef std::unique_ptr<byte_array_t> unique_byte_array_t;
|
||||
|
||||
#endif // SRSUE_TTCN3_COMMON_H
|
|
@ -24,78 +24,56 @@
|
|||
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "srslte/common/netsource_handler.h"
|
||||
#include "srslte/phy/io/netsource.h"
|
||||
#include "ttcn3_helpers.h"
|
||||
#include "ttcn3_port_handler.h"
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
// The IP CTRL interface to the IP_PTC
|
||||
class ttcn3_ip_ctrl_interface : public netsource_handler
|
||||
class ttcn3_ip_ctrl_interface : public ttcn3_port_handler
|
||||
{
|
||||
public:
|
||||
ttcn3_ip_ctrl_interface() : netsource_handler("TTCN3_IP_CTRL_IF"){};
|
||||
~ttcn3_ip_ctrl_interface(){};
|
||||
ttcn3_ip_ctrl_interface() = default;
|
||||
~ttcn3_ip_ctrl_interface() = default;
|
||||
|
||||
void init(srslte::log* log_, std::string net_ip_, uint32_t net_port_)
|
||||
int init(srslte::log* log_, std::string net_ip_, uint32_t net_port_)
|
||||
{
|
||||
net_ip = net_ip_;
|
||||
net_port = net_port_;
|
||||
log = log_;
|
||||
initialized = true;
|
||||
log->debug("Initialized.\n");
|
||||
return port_listen();
|
||||
}
|
||||
|
||||
private:
|
||||
void run_thread()
|
||||
///< Main message handler
|
||||
int handle_message(const unique_byte_array_t& rx_buf, const uint32_t n)
|
||||
{
|
||||
// open TCP socket
|
||||
if (srslte_netsource_init(&net_source, net_ip.c_str(), net_port, SRSLTE_NETSOURCE_TCP)) {
|
||||
fprintf(stderr, "Error creating input TCP socket at port %d\n", net_port);
|
||||
exit(-1);
|
||||
log->debug("Received %d B from remote.\n", n);
|
||||
|
||||
Document document;
|
||||
if (document.Parse((char*)rx_buf->begin()).HasParseError() || document.IsObject() == false) {
|
||||
log->error_hex(rx_buf->begin(), n, "Error parsing incoming data.\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
log->info("Listening on %s:%d for incoming connections ..\n", net_ip.c_str(), net_port);
|
||||
// Pretty-print
|
||||
StringBuffer buffer;
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
document.Accept(writer);
|
||||
log->info("Received %d bytes\n%s\n", n, (char*)buffer.GetString());
|
||||
|
||||
running = true;
|
||||
|
||||
int n;
|
||||
while (run_enable) {
|
||||
log->debug("Reading from IP_CTRL port ..\n");
|
||||
n = srslte_netsource_read(&net_source, rx_buf->begin(), RX_BUF_SIZE);
|
||||
if (n > 0) {
|
||||
rx_buf->at(n) = '\0';
|
||||
|
||||
Document document;
|
||||
if (document.Parse((char*)rx_buf->begin()).HasParseError()) {
|
||||
log->error_hex(rx_buf->begin(), n, "Error parsing incoming data.\n");
|
||||
break;
|
||||
}
|
||||
assert(document.IsObject());
|
||||
|
||||
// Pretty-print
|
||||
StringBuffer buffer;
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
document.Accept(writer);
|
||||
log->info("Received %d bytes\n%s\n", n, (char*)buffer.GetString());
|
||||
|
||||
// Get message
|
||||
if (document.HasMember("RoutingInfo")) {
|
||||
log->info("Received RoutingInfo\n");
|
||||
handle_routing_info(document);
|
||||
} else {
|
||||
log->error("Received unknown request.\n");
|
||||
}
|
||||
} else if (n == 0) {
|
||||
log->error("Receiving null from network\n");
|
||||
} else {
|
||||
log->error("Error receiving from network\n");
|
||||
}
|
||||
// Get message
|
||||
if (document.HasMember("RoutingInfo")) {
|
||||
log->info("Received RoutingInfo\n");
|
||||
handle_routing_info(document);
|
||||
} else {
|
||||
log->error("Received unknown request.\n");
|
||||
}
|
||||
|
||||
running = false;
|
||||
|
||||
srslte_netsource_free(&net_source);
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void handle_routing_info(Document& document)
|
||||
|
@ -118,9 +96,7 @@ private:
|
|||
std::string resp = ttcn3_helpers::get_drbmux_common_ind_cnf();
|
||||
|
||||
log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length());
|
||||
if (srslte_netsource_write(&net_source, (char*)resp.c_str(), resp.length()) != SRSLTE_SUCCESS) {
|
||||
log->error("Error sending message to tester.\n");
|
||||
};
|
||||
send((const uint8_t*)resp.c_str(), resp.length());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -22,78 +22,52 @@
|
|||
#ifndef SRSUE_TTCN3_IP_SOCK_INTERFACE_H
|
||||
#define SRSUE_TTCN3_IP_SOCK_INTERFACE_H
|
||||
|
||||
#include "ttcn3_port_handler.h"
|
||||
|
||||
// The IP Socket interface to the IP_PTC
|
||||
class ttcn3_ip_sock_interface : public netsource_handler
|
||||
class ttcn3_ip_sock_interface : public ttcn3_port_handler
|
||||
{
|
||||
public:
|
||||
ttcn3_ip_sock_interface() : netsource_handler("TTCN3_IP_SOCK_IF"){};
|
||||
~ttcn3_ip_sock_interface(){};
|
||||
ttcn3_ip_sock_interface() = default;
|
||||
~ttcn3_ip_sock_interface() = default;
|
||||
|
||||
void init(srslte::log* log_, std::string net_ip_, uint32_t net_port_)
|
||||
int init(srslte::log* log_, std::string net_ip_, uint32_t net_port_)
|
||||
{
|
||||
net_ip = net_ip_;
|
||||
net_port = net_port_;
|
||||
log = log_;
|
||||
initialized = true;
|
||||
log->debug("Initialized.\n");
|
||||
return port_listen();
|
||||
}
|
||||
|
||||
private:
|
||||
void run_thread()
|
||||
///< Main message handler
|
||||
int handle_message(const unique_byte_array_t& rx_buf, const uint32_t n)
|
||||
{
|
||||
if (!initialized) {
|
||||
fprintf(stderr, "IP_SOCK interface not initialized. Exiting.\n");
|
||||
exit(-1);
|
||||
log->debug("Received %d B from remote.\n", n);
|
||||
|
||||
Document document;
|
||||
if (document.Parse((char*)rx_buf->begin()).HasParseError() || document.IsObject() == false) {
|
||||
log->error_hex(rx_buf->begin(), n, "Error parsing incoming data.\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// open TCP socket
|
||||
if (srslte_netsource_init(&net_source, net_ip.c_str(), net_port, SRSLTE_NETSOURCE_TCP)) {
|
||||
fprintf(stderr, "Error creating input TCP socket at port %d\n", net_port);
|
||||
exit(-1);
|
||||
// Pretty-print
|
||||
StringBuffer buffer;
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
document.Accept(writer);
|
||||
log->info("Received %d bytes\n%s\n", n, (char*)buffer.GetString());
|
||||
|
||||
// Get message
|
||||
if (document.HasMember("CTRL")) {
|
||||
log->info("Received CTRL command.\n");
|
||||
handle_ctrl(document);
|
||||
} else {
|
||||
log->error("Received unknown request.\n");
|
||||
}
|
||||
|
||||
log->info("Listening on %s:%d for incoming connections ..\n", net_ip.c_str(), net_port);
|
||||
|
||||
running = true;
|
||||
|
||||
int n;
|
||||
while (run_enable) {
|
||||
log->debug("Reading from IP_SOCK port ..\n");
|
||||
n = srslte_netsource_read(&net_source, rx_buf->begin(), RX_BUF_SIZE);
|
||||
if (n > 0) {
|
||||
rx_buf->at(n) = '\0';
|
||||
|
||||
Document document;
|
||||
if (document.Parse((char*)rx_buf->begin()).HasParseError()) {
|
||||
log->error_hex(rx_buf->begin(), n, "Error parsing incoming data.\n");
|
||||
break;
|
||||
}
|
||||
assert(document.IsObject());
|
||||
|
||||
// Pretty-print
|
||||
StringBuffer buffer;
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
document.Accept(writer);
|
||||
log->info("Received %d bytes\n%s\n", n, (char*)buffer.GetString());
|
||||
|
||||
// Get message
|
||||
if (document.HasMember("CTRL")) {
|
||||
log->info("Received CTRL command.\n");
|
||||
handle_ctrl(document);
|
||||
} else {
|
||||
log->error("Received unknown request.\n");
|
||||
}
|
||||
} else if (n == 0) {
|
||||
log->error("Receiving null from network\n");
|
||||
} else {
|
||||
log->error("Error receiving from network\n");
|
||||
// exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
running = false;
|
||||
|
||||
srslte_netsource_free(&net_source);
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void handle_ctrl(Document& document)
|
||||
|
@ -127,9 +101,7 @@ private:
|
|||
string resp = ttcn3_helpers::get_ctrl_cnf(protocol.GetString(), ip_version, addr.GetString());
|
||||
|
||||
log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length());
|
||||
if (srslte_netsource_write(&net_source, (char*)resp.c_str(), resp.length()) != SRSLTE_SUCCESS) {
|
||||
log->error("Error sending message to tester.\n");
|
||||
}
|
||||
send((const uint8_t*)resp.c_str(), resp.length());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,224 @@
|
|||
/*
|
||||
* Copyright 2013-2019 Software Radio Systems Limited
|
||||
*
|
||||
* This file is part of srsLTE.
|
||||
*
|
||||
* srsLTE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* srsLTE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* A copy of the GNU Affero General Public License can be found in
|
||||
* the LICENSE file in the top-level directory of this distribution
|
||||
* and at http://www.gnu.org/licenses/.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! \brief This class provides a common function for all TTCN3
|
||||
* ports for SCTP socket creation, notification handling, etc.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SRSUE_TTCN3_PORT_HANDLER_H
|
||||
#define SRSUE_TTCN3_PORT_HANDLER_H
|
||||
|
||||
#include "srslte/common/epoll_helper.h"
|
||||
#include "srslte/common/log.h"
|
||||
#include "ttcn3_common.h"
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <netinet/sctp.h>
|
||||
|
||||
class ttcn3_port_handler : public epoll_handler
|
||||
{
|
||||
public:
|
||||
ttcn3_port_handler() : rx_buf(unique_byte_array_t(new byte_array_t)) {}
|
||||
virtual ~ttcn3_port_handler() {}
|
||||
|
||||
virtual int handle_message(const unique_byte_array_t& rx_buf, const uint32_t n) = 0;
|
||||
|
||||
int handle_event(int fd, epoll_event e, int epoll_fd)
|
||||
{
|
||||
if (e.events & EPOLLIN) {
|
||||
struct sctp_sndrcvinfo sri = {};
|
||||
socklen_t fromlen = sizeof(client_addr);
|
||||
int msg_flags = 0;
|
||||
int rd_sz =
|
||||
sctp_recvmsg(fd, rx_buf->begin(), RX_BUF_SIZE, (struct sockaddr*)&client_addr, &fromlen, &sri, &msg_flags);
|
||||
if (rd_sz == -1 && errno != EAGAIN) {
|
||||
log->error("Error reading from SCTP socket: %s", strerror(errno));
|
||||
} else if (rd_sz == -1 && errno == EAGAIN) {
|
||||
log->debug("Socket timeout reached");
|
||||
} else {
|
||||
if (msg_flags & MSG_NOTIFICATION) {
|
||||
// Received notification
|
||||
handle_notification(rx_buf->begin(), rd_sz);
|
||||
} else {
|
||||
// Received data
|
||||
rx_buf->at(rd_sz) = '\0'; // Terminate buffer
|
||||
handle_message(rx_buf, rd_sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int handle_notification(const uint8_t* payload, const uint32_t len)
|
||||
{
|
||||
union sctp_notification* notif = (union sctp_notification*)payload;
|
||||
uint32_t notif_header_size = sizeof(((union sctp_notification*)NULL)->sn_header);
|
||||
if (notif_header_size > len) {
|
||||
printf("Error: Notification msg size is smaller than notification header size!\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
switch (notif->sn_header.sn_type) {
|
||||
case SCTP_ASSOC_CHANGE: {
|
||||
if (sizeof(struct sctp_assoc_change) > len) {
|
||||
printf("Error notification msg size is smaller than struct sctp_assoc_change size\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
const char* state = NULL;
|
||||
struct sctp_assoc_change* n = ¬if->sn_assoc_change;
|
||||
|
||||
switch (n->sac_state) {
|
||||
case SCTP_COMM_UP:
|
||||
state = "COMM UP";
|
||||
break;
|
||||
case SCTP_COMM_LOST:
|
||||
state = "COMM_LOST";
|
||||
break;
|
||||
case SCTP_RESTART:
|
||||
state = "RESTART";
|
||||
break;
|
||||
case SCTP_SHUTDOWN_COMP:
|
||||
state = "SHUTDOWN_COMP";
|
||||
break;
|
||||
case SCTP_CANT_STR_ASSOC:
|
||||
state = "CAN'T START ASSOC";
|
||||
break;
|
||||
}
|
||||
|
||||
log->debug(
|
||||
"SCTP_ASSOC_CHANGE notif: state: %s, error code: %d, out streams: %d, in streams: %d, assoc id: %d\n",
|
||||
state,
|
||||
n->sac_error,
|
||||
n->sac_outbound_streams,
|
||||
n->sac_inbound_streams,
|
||||
n->sac_assoc_id);
|
||||
break;
|
||||
}
|
||||
|
||||
case SCTP_SHUTDOWN_EVENT: {
|
||||
if (sizeof(struct sctp_shutdown_event) > len) {
|
||||
printf("Error notification msg size is smaller than struct sctp_assoc_change size\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
struct sctp_shutdown_event* n = ¬if->sn_shutdown_event;
|
||||
log->debug("SCTP_SHUTDOWN_EVENT notif: assoc id: %d\n", n->sse_assoc_id);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
log->warning("Unhandled notification type %d\n", notif->sn_header.sn_type);
|
||||
break;
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
///< Send buffer to tester
|
||||
void send(const uint8_t* buffer, const uint32_t len)
|
||||
{
|
||||
if (sendto(sock_fd, buffer, len, 0, (struct sockaddr*)&client_addr, sizeof(client_addr)) == -1) {
|
||||
log->error("Error sending message to tester.\n");
|
||||
}
|
||||
}
|
||||
|
||||
///< Set socket to non-blocking-mode
|
||||
int set_non_blocking(uint32_t fd)
|
||||
{
|
||||
int flags = fcntl(fd, F_GETFL, 0);
|
||||
if (flags == -1) {
|
||||
perror("fcntl");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
flags |= O_NONBLOCK;
|
||||
int s = fcntl(fd, F_SETFL, flags);
|
||||
if (s == -1) {
|
||||
perror("fcntl");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
///< Create, bind and listen on SCTP socket
|
||||
int port_listen()
|
||||
{
|
||||
int ret = SRSLTE_ERROR;
|
||||
|
||||
sock_fd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
|
||||
if (sock_fd == -1) {
|
||||
log->console("Could not create SCTP socket\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Sets the data_io_event to be able to use sendrecv_info
|
||||
// Subscribes to the SCTP_SHUTDOWN event, to handle graceful shutdown
|
||||
struct sctp_event_subscribe events = {};
|
||||
events.sctp_data_io_event = 1;
|
||||
events.sctp_shutdown_event = 1;
|
||||
events.sctp_association_event = 1;
|
||||
if (setsockopt(sock_fd, IPPROTO_SCTP, SCTP_EVENTS, &events, sizeof(events))) {
|
||||
close(sock_fd);
|
||||
log->console("Subscribing to sctp_data_io_events failed\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Port bind
|
||||
struct sockaddr_in bind_addr = {};
|
||||
bind_addr.sin_family = AF_INET;
|
||||
inet_pton(AF_INET, net_ip.c_str(), &(bind_addr.sin_addr));
|
||||
bind_addr.sin_port = htons(net_port);
|
||||
|
||||
int one = 1;
|
||||
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
|
||||
ret = bind(sock_fd, (struct sockaddr*)&bind_addr, sizeof(bind_addr));
|
||||
if (ret != 0) {
|
||||
close(sock_fd);
|
||||
log->error("Error binding SCTP socket\n");
|
||||
log->console("Error binding SCTP socket\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Listen for connections
|
||||
ret = listen(sock_fd, SOMAXCONN);
|
||||
if (ret != SRSLTE_SUCCESS) {
|
||||
close(sock_fd);
|
||||
log->error("Error in SCTP socket listen\n");
|
||||
log->console("Error in SCTP socket listen\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
set_non_blocking(sock_fd);
|
||||
return sock_fd;
|
||||
}
|
||||
|
||||
bool initialized = false;
|
||||
std::string net_ip = "0.0.0.0";
|
||||
uint32_t net_port = 0;
|
||||
int sock_fd = -1;
|
||||
struct sockaddr client_addr = {};
|
||||
srslte::log* log = nullptr;
|
||||
unique_byte_array_t rx_buf; ///< Receive buffer for this port
|
||||
};
|
||||
|
||||
#endif // SRSUE_TTCN3_PORT_HANDLER_H
|
|
@ -26,120 +26,87 @@
|
|||
#include "srslte/common/common.h"
|
||||
#include "srslte/common/pdu.h"
|
||||
#include "ttcn3_interfaces.h"
|
||||
#include "ttcn3_port_handler.h"
|
||||
#include <srslte/interfaces/ue_interfaces.h>
|
||||
|
||||
using namespace srslte;
|
||||
|
||||
// The SRB interface
|
||||
class ttcn3_srb_interface : public netsource_handler
|
||||
class ttcn3_srb_interface : public ttcn3_port_handler
|
||||
{
|
||||
public:
|
||||
ttcn3_srb_interface() : pool(byte_buffer_pool::get_instance()), netsource_handler("TTCN3_SRB_IF"){};
|
||||
~ttcn3_srb_interface(){};
|
||||
ttcn3_srb_interface() : pool(byte_buffer_pool::get_instance()) {}
|
||||
~ttcn3_srb_interface() = default;
|
||||
|
||||
void init(ss_srb_interface* syssim_, srslte::log* log_, std::string net_ip_, uint32_t net_port_)
|
||||
int init(ss_srb_interface* syssim_, srslte::log* log_, std::string net_ip_, uint32_t net_port_)
|
||||
{
|
||||
syssim = syssim_;
|
||||
log = log_;
|
||||
net_ip = net_ip_;
|
||||
net_port = net_port_;
|
||||
|
||||
initialized = true;
|
||||
log->debug("Initialized.\n");
|
||||
return port_listen();
|
||||
}
|
||||
|
||||
void tx(unique_byte_buffer_t pdu)
|
||||
{
|
||||
if (running) {
|
||||
if (initialized) {
|
||||
log->info_hex(pdu->msg, pdu->N_bytes, "Sending %d B to Titan\n", pdu->N_bytes);
|
||||
if (srslte_netsource_write(&net_source, (void*)pdu->msg, pdu->N_bytes) != SRSLTE_SUCCESS) {
|
||||
log->error("Error sending message to tester.\n");
|
||||
};
|
||||
send(pdu->msg, pdu->N_bytes);
|
||||
} else {
|
||||
log->error("Trying to transmit but port not connected.\n");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void run_thread()
|
||||
///< Main message handler
|
||||
int handle_message(const unique_byte_array_t& rx_buf, const uint32_t n)
|
||||
{
|
||||
if (!initialized) {
|
||||
fprintf(stderr, "SRB interface not initialized. Exiting.\n");
|
||||
exit(-1);
|
||||
log->debug_hex(rx_buf->begin(), n, "Received %d B from remote.\n", n);
|
||||
|
||||
// Chop incoming msg, first two bytes are length of the JSON
|
||||
// (see IPL4_EUTRA_SYSTEM_Definitions.ttcn
|
||||
uint16_t json_len = ((uint16_t)rx_buf->at(0) << 8) | rx_buf->at(1);
|
||||
|
||||
// The data part after the JSON starts right here but handling
|
||||
// is done in the respective functions
|
||||
uint16_t rx_buf_offset = json_len + 2;
|
||||
|
||||
Document document;
|
||||
if (document.Parse((char*)&rx_buf->at(2)).HasParseError() || document.IsObject() == false) {
|
||||
log->error_hex((uint8*)&rx_buf->at(2), json_len, "Error parsing incoming data.\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// open TCP socket
|
||||
if (srslte_netsource_init(&net_source, net_ip.c_str(), net_port, SRSLTE_NETSOURCE_TCP)) {
|
||||
fprintf(stderr, "Error creating input TCP socket at port %d\n", net_port);
|
||||
exit(-1);
|
||||
// Pretty-print
|
||||
StringBuffer buffer;
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
document.Accept(writer);
|
||||
log->info("Received JSON with %d B\n%s\n", json_len, (char*)buffer.GetString());
|
||||
|
||||
// check for common
|
||||
assert(document.HasMember("Common"));
|
||||
assert(document["Common"].IsObject());
|
||||
|
||||
// Check for request type
|
||||
assert(document.HasMember("RrcPdu"));
|
||||
assert(document["RrcPdu"].IsObject());
|
||||
|
||||
// Get request type
|
||||
const Value& rrcpdu = document["RrcPdu"];
|
||||
if (rrcpdu.HasMember("Ccch")) {
|
||||
rx_buf_offset += 2;
|
||||
handle_ccch_pdu(document, &rx_buf->at(rx_buf_offset), n - rx_buf_offset);
|
||||
} else if (rrcpdu.HasMember("Dcch")) {
|
||||
rx_buf_offset += 2;
|
||||
uint32_t lcid = document["Common"]["RoutingInfo"]["RadioBearerId"]["Srb"].GetInt();
|
||||
handle_dcch_pdu(document, lcid, &rx_buf->at(rx_buf_offset), n - rx_buf_offset);
|
||||
} else {
|
||||
log->error("Received unknown request.\n");
|
||||
}
|
||||
|
||||
running = true;
|
||||
|
||||
int n;
|
||||
while (run_enable) {
|
||||
log->debug("Reading from SRB port ..\n");
|
||||
n = srslte_netsource_read(&net_source, rx_buf->begin(), RX_BUF_SIZE);
|
||||
if (n > 0) {
|
||||
rx_buf->at(n) = '\0';
|
||||
|
||||
log->debug_hex(rx_buf->begin(), n, "Received %d B from remote.\n", n);
|
||||
|
||||
// Chop incoming msg, first two bytes are length of the JSON
|
||||
// (see IPL4_EUTRA_SYSTEM_Definitions.ttcn
|
||||
uint16_t json_len = ((uint16_t)rx_buf->at(0) << 8) | rx_buf->at(1);
|
||||
|
||||
// Copy JSON from received buffer and null-terminate
|
||||
char json[json_len + 1];
|
||||
memcpy(json, &rx_buf->at(2), json_len);
|
||||
json[json_len] = '\0';
|
||||
|
||||
// The data part after the JSON starts right here but handling
|
||||
// is done in the respective functions
|
||||
uint16_t rx_buf_offset = json_len + 2;
|
||||
|
||||
Document document;
|
||||
if (document.Parse(json).HasParseError()) {
|
||||
log->error_hex((uint8*)json, json_len, "Error parsing incoming data.\n");
|
||||
break;
|
||||
}
|
||||
assert(document.IsObject());
|
||||
|
||||
// Pretty-print
|
||||
StringBuffer buffer;
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
document.Accept(writer);
|
||||
log->info("Received JSON with %d B\n%s\n", json_len, (char*)buffer.GetString());
|
||||
|
||||
// check for common
|
||||
assert(document.HasMember("Common"));
|
||||
assert(document["Common"].IsObject());
|
||||
|
||||
// Check for request type
|
||||
assert(document.HasMember("RrcPdu"));
|
||||
assert(document["RrcPdu"].IsObject());
|
||||
|
||||
// Get request type
|
||||
const Value& rrcpdu = document["RrcPdu"];
|
||||
if (rrcpdu.HasMember("Ccch")) {
|
||||
rx_buf_offset += 2;
|
||||
handle_ccch_pdu(document, &rx_buf->at(rx_buf_offset), n - rx_buf_offset);
|
||||
} else if (rrcpdu.HasMember("Dcch")) {
|
||||
rx_buf_offset += 2;
|
||||
uint32_t lcid = document["Common"]["RoutingInfo"]["RadioBearerId"]["Srb"].GetInt();
|
||||
handle_dcch_pdu(document, lcid, &rx_buf->at(rx_buf_offset), n - rx_buf_offset);
|
||||
} else {
|
||||
log->error("Received unknown request.\n");
|
||||
}
|
||||
} else if (n == 0) {
|
||||
log->error("Receiving null from network\n");
|
||||
} else {
|
||||
log->error("Error receiving from network\n");
|
||||
}
|
||||
}
|
||||
running = false;
|
||||
|
||||
srslte_netsource_free(&net_source);
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
// Todo: move to SYSSIM
|
||||
|
@ -188,6 +155,10 @@ private:
|
|||
|
||||
ss_srb_interface* syssim = nullptr;
|
||||
byte_buffer_pool* pool = nullptr;
|
||||
|
||||
int srb_fd = 0;
|
||||
// struct sctp_sndrcvinfo sri = {};
|
||||
// struct sockaddr_in client_addr;
|
||||
};
|
||||
|
||||
#endif // SRSUE_TTCN3_SRB_INTERFACE_H
|
|
@ -29,13 +29,13 @@
|
|||
using namespace srslte;
|
||||
|
||||
// The EUTRA.SYS interface
|
||||
class ttcn3_sys_interface : public netsource_handler
|
||||
class ttcn3_sys_interface : public ttcn3_port_handler
|
||||
{
|
||||
public:
|
||||
ttcn3_sys_interface() : netsource_handler("TTCN3_SYS_IF"){};
|
||||
ttcn3_sys_interface(){};
|
||||
~ttcn3_sys_interface(){};
|
||||
|
||||
void init(ss_sys_interface* syssim_, srslte::log* log_, std::string net_ip_, uint32_t net_port_)
|
||||
int init(ss_sys_interface* syssim_, srslte::log* log_, std::string net_ip_, uint32_t net_port_)
|
||||
{
|
||||
syssim = syssim_;
|
||||
net_ip = net_ip_;
|
||||
|
@ -44,9 +44,81 @@ public:
|
|||
initialized = true;
|
||||
log->debug("Initialized.\n");
|
||||
pool = byte_buffer_pool::get_instance();
|
||||
return port_listen();
|
||||
}
|
||||
|
||||
private:
|
||||
///< Main message handler
|
||||
int handle_message(const unique_byte_array_t& rx_buf, const uint32_t n)
|
||||
{
|
||||
log->debug("Received %d B from remote.\n", n);
|
||||
|
||||
// Chop incoming msg, first two bytes are length of the JSON
|
||||
// (see IPL4_EUTRA_SYSTEM_Definitions.ttcn
|
||||
uint16_t json_len = ((uint16_t)rx_buf->at(0) << 8) | rx_buf->at(1);
|
||||
|
||||
// Copy JSON from received buffer and null-terminate
|
||||
char json[json_len + 1];
|
||||
memcpy(json, &rx_buf->at(2), json_len);
|
||||
json[json_len] = '\0';
|
||||
|
||||
// The data part after the JSON starts right here but handling
|
||||
// is done in the respective functions
|
||||
uint16_t rx_buf_offset = json_len + 2;
|
||||
|
||||
Document document;
|
||||
if (document.Parse(json).HasParseError() || document.IsObject() == false) {
|
||||
log->error_hex((uint8*)json, json_len, "Error parsing incoming data.\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Pretty-print
|
||||
StringBuffer buffer;
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
document.Accept(writer);
|
||||
log->info_long("Received %d bytes\n%s\n", json_len, (char*)buffer.GetString());
|
||||
|
||||
// check for common
|
||||
assert(document.HasMember("Common"));
|
||||
assert(document["Common"].IsObject());
|
||||
|
||||
// Check for request type
|
||||
assert(document.HasMember("Request"));
|
||||
assert(document["Request"].IsObject());
|
||||
|
||||
// Get request type
|
||||
const Value& request = document["Request"];
|
||||
if (request.HasMember("Cell")) {
|
||||
log->info("Received Cell request.\n");
|
||||
handle_request_cell(document, &rx_buf->at(rx_buf_offset), n - rx_buf_offset);
|
||||
} else if (request.HasMember("L1MacIndCtrl")) {
|
||||
log->info("Received L1MacIndCtrl request.\n");
|
||||
handle_request_l1_mac_ind_ctrl(document);
|
||||
} else if (request.HasMember("RadioBearerList")) {
|
||||
log->info("Received RadioBearerList request.\n");
|
||||
handle_request_radio_bearer_list(document);
|
||||
} else if (request.HasMember("CellAttenuationList")) {
|
||||
log->info("Received CellAttenuationList request.\n");
|
||||
handle_request_cell_attenuation_list(document);
|
||||
} else if (request.HasMember("PdcpCount")) {
|
||||
log->info("Received PdcpCount request.\n");
|
||||
handle_request_pdcp_count(document);
|
||||
} else if (request.HasMember("AS_Security")) {
|
||||
log->info("Received AS_Security request.\n");
|
||||
handle_request_as_security(document);
|
||||
} else if (request.HasMember("EnquireTiming")) {
|
||||
log->info("Received EnquireTiming request.\n");
|
||||
handle_request_enquire_timing(document);
|
||||
} else if (request.HasMember("Paging")) {
|
||||
log->info("Received Paging request.\n");
|
||||
handle_request_paging(document, &rx_buf->at(rx_buf_offset), n - rx_buf_offset);
|
||||
} else {
|
||||
log->error("Received unknown request.\n");
|
||||
}
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void handle_request_cell_basic(Document& document, const uint8_t* payload, const uint16_t len)
|
||||
{
|
||||
if (document["Request"]["Cell"]["AddOrReconfigure"]["Basic"].HasMember("StaticCellInfo")) {
|
||||
|
@ -113,9 +185,7 @@ private:
|
|||
std::string resp = ttcn3_helpers::get_basic_sys_req_cnf(cell_name.GetString(), "Cell");
|
||||
|
||||
log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length());
|
||||
if (srslte_netsource_write(&net_source, (char*)resp.c_str(), resp.length()) != SRSLTE_SUCCESS) {
|
||||
log->error("Error sending message to tester.\n");
|
||||
}
|
||||
send((const uint8_t*)resp.c_str(), resp.length());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,9 +197,7 @@ private:
|
|||
std::string resp = ttcn3_helpers::get_basic_sys_req_cnf(cell_id, "Cell");
|
||||
|
||||
log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length());
|
||||
if (srslte_netsource_write(&net_source, (char*)resp.c_str(), resp.length()) != SRSLTE_SUCCESS) {
|
||||
log->error("Error sending message to tester.\n");
|
||||
}
|
||||
send((const uint8_t*)resp.c_str(), resp.length());
|
||||
}
|
||||
|
||||
void handle_request_cell(Document& document, const uint8_t* payload, const uint16_t len)
|
||||
|
@ -187,9 +255,7 @@ private:
|
|||
std::string resp = ttcn3_helpers::get_basic_sys_req_cnf(cell_id.GetString(), "L1MacIndCtrl");
|
||||
|
||||
log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length());
|
||||
if (srslte_netsource_write(&net_source, (char*)resp.c_str(), resp.length()) != SRSLTE_SUCCESS) {
|
||||
log->error("Error sending message to tester.\n");
|
||||
}
|
||||
send((const uint8_t*)resp.c_str(), resp.length());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -248,9 +314,7 @@ private:
|
|||
std::string resp = ttcn3_helpers::get_basic_sys_req_cnf(cell_id.GetString(), "RadioBearerList");
|
||||
|
||||
log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length());
|
||||
if (srslte_netsource_write(&net_source, (char*)resp.c_str(), resp.length()) != SRSLTE_SUCCESS) {
|
||||
log->error("Error sending message to tester.\n");
|
||||
}
|
||||
send((const uint8_t*)resp.c_str(), resp.length());
|
||||
}
|
||||
|
||||
void handle_request_cell_attenuation_list(Document& document)
|
||||
|
@ -299,9 +363,7 @@ private:
|
|||
std::string resp = ttcn3_helpers::get_basic_sys_req_cnf(cell_id.GetString(), "CellAttenuationList");
|
||||
|
||||
log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length());
|
||||
if (srslte_netsource_write(&net_source, (char*)resp.c_str(), resp.length()) != SRSLTE_SUCCESS) {
|
||||
log->error("Error sending message to tester.\n");
|
||||
}
|
||||
send((const uint8_t*)resp.c_str(), resp.length());
|
||||
}
|
||||
|
||||
void handle_request_pdcp_count(Document& document)
|
||||
|
@ -338,9 +400,7 @@ private:
|
|||
std::string resp = ttcn3_helpers::get_pdcp_count_response(cell_id.GetString(), bearers);
|
||||
|
||||
log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length());
|
||||
if (srslte_netsource_write(&net_source, (char*)resp.c_str(), resp.length()) != SRSLTE_SUCCESS) {
|
||||
log->error("Error sending message to tester.\n");
|
||||
}
|
||||
send((const uint8_t*)resp.c_str(), resp.length());
|
||||
}
|
||||
|
||||
void handle_request_as_security(Document& document)
|
||||
|
@ -429,9 +489,7 @@ private:
|
|||
if (config_flag.GetBool() == true) {
|
||||
std::string resp = ttcn3_helpers::get_basic_sys_req_cnf(cell_id.GetString(), "AS_Security");
|
||||
log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length());
|
||||
if (srslte_netsource_write(&net_source, (char*)resp.c_str(), resp.length()) != SRSLTE_SUCCESS) {
|
||||
log->error("Error sending message to tester.\n");
|
||||
}
|
||||
send((const uint8_t*)resp.c_str(), resp.length());
|
||||
} else {
|
||||
log->info("Skipping response for AS_Security message.\n");
|
||||
}
|
||||
|
@ -469,9 +527,7 @@ private:
|
|||
ttcn3_helpers::get_sys_req_cnf_with_time(cell_id.GetString(), "EnquireTiming", syssim->get_tti());
|
||||
|
||||
log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length());
|
||||
if (srslte_netsource_write(&net_source, (char*)resp.c_str(), resp.length()) != SRSLTE_SUCCESS) {
|
||||
log->error("Error sending message to tester.\n");
|
||||
}
|
||||
send((const uint8_t*)resp.c_str(), resp.length());
|
||||
}
|
||||
|
||||
void handle_request_paging(Document& document, const uint8_t* payload, const uint16_t len)
|
||||
|
@ -512,112 +568,12 @@ private:
|
|||
std::string resp = ttcn3_helpers::get_sys_req_cnf_with_time(cell_id.GetString(), "Paging", syssim->get_tti());
|
||||
|
||||
log->info("Sending %s to tester (%zd B)\n", resp.c_str(), resp.length());
|
||||
if (srslte_netsource_write(&net_source, (char*)resp.c_str(), resp.length()) != SRSLTE_SUCCESS) {
|
||||
log->error("Error sending message to tester.\n");
|
||||
}
|
||||
send((const uint8_t*)resp.c_str(), resp.length());
|
||||
} else {
|
||||
log->info("Skipping response for Paging message.\n");
|
||||
}
|
||||
}
|
||||
|
||||
void run_thread()
|
||||
{
|
||||
if (!initialized) {
|
||||
fprintf(stderr, "SYS interface not initialized. Exiting.\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// open TCP socket
|
||||
if (srslte_netsource_init(&net_source, net_ip.c_str(), net_port, SRSLTE_NETSOURCE_TCP)) {
|
||||
fprintf(stderr, "Error creating input TCP socket at port %d\n", net_port);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
log->info("Listening on %s:%d for incoming connections ..\n", net_ip.c_str(), net_port);
|
||||
|
||||
running = true;
|
||||
|
||||
int n;
|
||||
while (run_enable) {
|
||||
log->debug("Reading from SYS port ..\n");
|
||||
n = srslte_netsource_read(&net_source, rx_buf->begin(), RX_BUF_SIZE);
|
||||
if (n > 0) {
|
||||
rx_buf->at(n) = '\0';
|
||||
|
||||
log->debug("Received %d B from remote.\n", n);
|
||||
|
||||
// Chop incoming msg, first two bytes are length of the JSON
|
||||
// (see IPL4_EUTRA_SYSTEM_Definitions.ttcn
|
||||
uint16_t json_len = ((uint16_t)rx_buf->at(0) << 8) | rx_buf->at(1);
|
||||
|
||||
// Copy JSON from received buffer and null-terminate
|
||||
char json[json_len + 1];
|
||||
memcpy(json, &rx_buf->at(2), json_len);
|
||||
json[json_len] = '\0';
|
||||
|
||||
// The data part after the JSON starts right here but handling
|
||||
// is done in the respective functions
|
||||
uint16_t rx_buf_offset = json_len + 2;
|
||||
|
||||
Document document;
|
||||
if (document.Parse(json).HasParseError()) {
|
||||
log->error_hex((uint8*)json, json_len, "Error parsing incoming data.\n");
|
||||
break;
|
||||
}
|
||||
assert(document.IsObject());
|
||||
|
||||
// Pretty-print
|
||||
StringBuffer buffer;
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
document.Accept(writer);
|
||||
log->info_long("Received %d bytes\n%s\n", json_len, (char*)buffer.GetString());
|
||||
|
||||
// check for common
|
||||
assert(document.HasMember("Common"));
|
||||
assert(document["Common"].IsObject());
|
||||
|
||||
// Check for request type
|
||||
assert(document.HasMember("Request"));
|
||||
assert(document["Request"].IsObject());
|
||||
|
||||
// Get request type
|
||||
const Value& request = document["Request"];
|
||||
if (request.HasMember("Cell")) {
|
||||
log->info("Received Cell request.\n");
|
||||
handle_request_cell(document, &rx_buf->at(rx_buf_offset), n - rx_buf_offset);
|
||||
} else if (request.HasMember("L1MacIndCtrl")) {
|
||||
log->info("Received L1MacIndCtrl request.\n");
|
||||
handle_request_l1_mac_ind_ctrl(document);
|
||||
} else if (request.HasMember("RadioBearerList")) {
|
||||
log->info("Received RadioBearerList request.\n");
|
||||
handle_request_radio_bearer_list(document);
|
||||
} else if (request.HasMember("CellAttenuationList")) {
|
||||
log->info("Received CellAttenuationList request.\n");
|
||||
handle_request_cell_attenuation_list(document);
|
||||
} else if (request.HasMember("PdcpCount")) {
|
||||
log->info("Received PdcpCount request.\n");
|
||||
handle_request_pdcp_count(document);
|
||||
} else if (request.HasMember("AS_Security")) {
|
||||
log->info("Received AS_Security request.\n");
|
||||
handle_request_as_security(document);
|
||||
} else if (request.HasMember("EnquireTiming")) {
|
||||
log->info("Received EnquireTiming request.\n");
|
||||
handle_request_enquire_timing(document);
|
||||
} else if (request.HasMember("Paging")) {
|
||||
log->info("Received Paging request.\n");
|
||||
handle_request_paging(document, &rx_buf->at(rx_buf_offset), n - rx_buf_offset);
|
||||
} else {
|
||||
log->error("Received unknown request.\n");
|
||||
}
|
||||
} else {
|
||||
log->error("Error receiving from network\n");
|
||||
}
|
||||
}
|
||||
running = false;
|
||||
|
||||
srslte_netsource_free(&net_source);
|
||||
}
|
||||
|
||||
phy_interface_syssim* phy = nullptr;
|
||||
ss_sys_interface* syssim = nullptr;
|
||||
byte_buffer_pool* pool = nullptr;
|
||||
|
|
|
@ -23,24 +23,23 @@
|
|||
#define SRSUE_TTCN3_SYSSIM_H
|
||||
|
||||
#include "dut_utils.h"
|
||||
#include "srslte/common/netsource_handler.h"
|
||||
#include "srslte/common/pdu_queue.h"
|
||||
#include "srslte/common/threads.h"
|
||||
#include "srslte/upper/pdcp.h"
|
||||
#include "srslte/upper/rlc.h"
|
||||
#include "ttcn3_common.h"
|
||||
#include "ttcn3_ip_ctrl_interface.h"
|
||||
#include "ttcn3_ip_sock_interface.h"
|
||||
#include "ttcn3_srb_interface.h"
|
||||
#include "ttcn3_sys_interface.h"
|
||||
#include "ttcn3_ue.h"
|
||||
#include "ttcn3_ut_interface.h"
|
||||
|
||||
#include <functional>
|
||||
#include <srslte/interfaces/ue_interfaces.h>
|
||||
|
||||
#define TTCN3_CRNTI (0x1001)
|
||||
|
||||
class ttcn3_syssim : public thread,
|
||||
public syssim_interface_phy,
|
||||
class ttcn3_syssim : public syssim_interface_phy,
|
||||
public ss_ut_interface,
|
||||
public ss_sys_interface,
|
||||
public ss_srb_interface,
|
||||
|
@ -50,7 +49,7 @@ class ttcn3_syssim : public thread,
|
|||
public srslte::pdu_queue::process_callback
|
||||
{
|
||||
public:
|
||||
ttcn3_syssim(srslte::logger_file* logger_file_) :
|
||||
ttcn3_syssim(srslte::logger_file* logger_file_, ttcn3_ue* ue_) :
|
||||
mac_msg_ul(20, &ss_mac_log),
|
||||
mac_msg_dl(20, &ss_mac_log),
|
||||
timers(8),
|
||||
|
@ -58,16 +57,16 @@ public:
|
|||
logger(logger_file_),
|
||||
logger_file(logger_file_),
|
||||
pool(byte_buffer_pool::get_instance()),
|
||||
thread("TTCN3_SYSSIM"),
|
||||
ue(ue_),
|
||||
rlc(&ss_rlc_log),
|
||||
signal_handler(&running),
|
||||
timer_handler(create_tti_timer(), [&](uint64_t res) { new_tti_indication(res); }),
|
||||
pdcp(&timers, &ss_pdcp_log){};
|
||||
|
||||
~ttcn3_syssim(){};
|
||||
|
||||
void init(const all_args_t& args_)
|
||||
int init(const all_args_t& args_)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
|
||||
args = args_;
|
||||
|
||||
// Make sure to get SS logging as well
|
||||
|
@ -106,40 +105,236 @@ public:
|
|||
ss_rlc_log.set_hex_limit(args.log.all_hex_limit);
|
||||
ss_pdcp_log.set_hex_limit(args.log.all_hex_limit);
|
||||
|
||||
// Init epoll socket and add FDs
|
||||
epoll_fd = epoll_create1(0);
|
||||
if (epoll_fd == -1) {
|
||||
log.error("Error creating epoll\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// add signalfd
|
||||
signal_fd = add_signalfd();
|
||||
if (add_epoll(signal_fd, epoll_fd) != SRSLTE_SUCCESS) {
|
||||
log.error("Error while adding signalfd to epoll\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
event_handler.insert({signal_fd, &signal_handler});
|
||||
|
||||
// init system interfaces to tester
|
||||
ut.init(this, &ut_log, "0.0.0.0", 2222);
|
||||
sys.init(this, &sys_log, "0.0.0.0", 2223);
|
||||
ip_sock.init(&ip_sock_log, "0.0.0.0", 2224);
|
||||
ip_ctrl.init(&ip_ctrl_log, "0.0.0.0", 2225);
|
||||
srb.init(this, &srb_log, "0.0.0.0", 2226);
|
||||
|
||||
ut.start(-2);
|
||||
sys.start(-2);
|
||||
ip_sock.start(-2);
|
||||
ip_ctrl.start(-2);
|
||||
srb.start(-2);
|
||||
if (add_port_handler() != SRSLTE_SUCCESS) {
|
||||
log.error("Error creating port handlers\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// Init SS layers
|
||||
pdus.init(this, &log);
|
||||
rlc.init(&pdcp, this, &timers, 0 /* RB_ID_SRB0 */);
|
||||
pdcp.init(&rlc, this, nullptr);
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
int add_port_handler()
|
||||
{
|
||||
// UT port
|
||||
int ut_fd = ut.init(this, &ut_log, listen_address, UT_PORT);
|
||||
if (add_epoll(ut_fd, epoll_fd) != SRSLTE_SUCCESS) {
|
||||
log.error("Error while adding UT port to epoll\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
event_handler.insert({ut_fd, &ut});
|
||||
log.console("UT handler listening on SCTP port %d\n", UT_PORT);
|
||||
|
||||
// SYS port
|
||||
int sys_fd = sys.init(this, &sys_log, listen_address, SYS_PORT);
|
||||
if (add_epoll(sys_fd, epoll_fd) != SRSLTE_SUCCESS) {
|
||||
log.error("Error while adding SYS port to epoll\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
event_handler.insert({sys_fd, &sys});
|
||||
log.console("SYS handler listening on SCTP port %d\n", SYS_PORT);
|
||||
|
||||
// IPsock port
|
||||
int ip_sock_fd = ip_sock.init(&ip_sock_log, listen_address, IPSOCK_PORT);
|
||||
if (add_epoll(ip_sock_fd, epoll_fd) != SRSLTE_SUCCESS) {
|
||||
log.error("Error while adding IP sock port to epoll\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
event_handler.insert({ip_sock_fd, &ip_sock});
|
||||
log.console("IPSOCK handler listening on SCTP port %d\n", IPSOCK_PORT);
|
||||
|
||||
// IPctrl port
|
||||
int ip_ctrl_fd = ip_ctrl.init(&ip_ctrl_log, listen_address, IPCTRL_PORT);
|
||||
if (add_epoll(ip_ctrl_fd, epoll_fd) != SRSLTE_SUCCESS) {
|
||||
log.error("Error while adding IP ctrl port to epoll\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
event_handler.insert({ip_ctrl_fd, &ip_ctrl});
|
||||
log.console("IPCTRL handler listening on SCTP port %d\n", IPCTRL_PORT);
|
||||
|
||||
// add SRB fd
|
||||
int srb_fd = srb.init(this, &srb_log, listen_address, SRB_PORT);
|
||||
if (add_epoll(srb_fd, epoll_fd) != SRSLTE_SUCCESS) {
|
||||
log.error("Error while adding SRB port to epoll\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
event_handler.insert({srb_fd, &srb});
|
||||
log.console("SRB handler listening on SCTP port %d\n", SRB_PORT);
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
///< Function called by epoll timer handler when TTI timer expires
|
||||
void new_tti_indication(uint64_t res)
|
||||
{
|
||||
tti = (tti + 1) % 10240;
|
||||
|
||||
log.step(tti);
|
||||
log.debug("Start new TTI\n");
|
||||
|
||||
ue->set_current_tti(tti);
|
||||
|
||||
// process events, if any
|
||||
while (not event_queue.empty()) {
|
||||
ss_events_t ev = event_queue.wait_pop();
|
||||
switch (ev) {
|
||||
case UE_SWITCH_ON:
|
||||
log.console("Switching on UE ID=%d\n", run_id);
|
||||
ue->switch_on();
|
||||
break;
|
||||
case UE_SWITCH_OFF:
|
||||
log.console("Switching off UE ID=%d\n", run_id);
|
||||
ue->switch_off();
|
||||
break;
|
||||
case ENABLE_DATA:
|
||||
log.console("Enabling data for UE ID=%d\n", run_id);
|
||||
ue->enable_data();
|
||||
break;
|
||||
case DISABLE_DATA:
|
||||
log.console("Disabling data for UE ID=%d\n", run_id);
|
||||
ue->disable_data();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pcell_idx == -1) {
|
||||
log.debug("Skipping TTI. Pcell not yet selected.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// DL/UL processing if UE has selected cell
|
||||
dl_rnti = ue->get_dl_sched_rnti(tti);
|
||||
if (SRSLTE_RNTI_ISSI(dl_rnti)) {
|
||||
// deliver SIBs one after another
|
||||
mac_interface_phy_lte::mac_grant_dl_t dl_grant = {};
|
||||
dl_grant.pid = get_pid(tti);
|
||||
dl_grant.rnti = dl_rnti;
|
||||
dl_grant.tb[0].tbs = cells[pcell_idx]->sibs[cells[pcell_idx]->sib_idx]->N_bytes;
|
||||
dl_grant.tb[0].ndi = get_ndi_for_new_dl_tx(tti);
|
||||
ue->new_tb(dl_grant, cells[pcell_idx]->sibs[cells[pcell_idx]->sib_idx]->msg);
|
||||
log.info("Delivered SIB%d for pcell_idx=%d\n", cells[pcell_idx]->sib_idx, pcell_idx);
|
||||
cells[pcell_idx]->sib_idx = (cells[pcell_idx]->sib_idx + 1) % cells[pcell_idx]->sibs.size();
|
||||
} else if (SRSLTE_RNTI_ISRAR(dl_rnti)) {
|
||||
if (prach_tti != -1) {
|
||||
rar_tti = (prach_tti + 3) % 10240;
|
||||
if (tti == rar_tti) {
|
||||
send_rar(prach_preamble_index);
|
||||
}
|
||||
}
|
||||
} else if (SRSLTE_RNTI_ISPA(dl_rnti)) {
|
||||
log.debug("Searching for paging RNTI\n");
|
||||
// PCH will be triggered from SYSSIM after receiving Paging
|
||||
} else if (SRSLTE_RNTI_ISUSER(dl_rnti)) {
|
||||
// check if this is for contention resolution after PRACH/RAR
|
||||
if (dl_rnti == crnti) {
|
||||
log.debug("Searching for C-RNTI=%d\n", crnti);
|
||||
|
||||
if (rar_tti != -1) {
|
||||
msg3_tti = (rar_tti + 3) % 10240;
|
||||
if (tti == msg3_tti) {
|
||||
send_msg3_grant();
|
||||
rar_tti = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for SR
|
||||
if (sr_tti != -1) {
|
||||
send_sr_ul_grant();
|
||||
}
|
||||
|
||||
if (dl_rnti != SRSLTE_INVALID_RNTI) {
|
||||
log.debug("Searching for RNTI=%d\n", dl_rnti);
|
||||
|
||||
// look for DL data to be send in each bearer and provide grant accordingly
|
||||
for (int lcid = 0; lcid < SRSLTE_N_RADIO_BEARERS; lcid++) {
|
||||
uint32_t buf_state = rlc.get_buffer_state(lcid);
|
||||
if (buf_state > 0) {
|
||||
log.debug("LCID=%d, buffer_state=%d\n", lcid, buf_state);
|
||||
const uint32_t mac_header_size = 10; // Add MAC header (10 B for all subheaders, etc)
|
||||
if (tmp_rlc_buffer.get_tailroom() > (buf_state + mac_header_size)) {
|
||||
uint32_t pdu_size = rlc.read_pdu(lcid, tmp_rlc_buffer.msg, buf_state);
|
||||
tx_payload_buffer.clear();
|
||||
mac_msg_dl.init_tx(&tx_payload_buffer, pdu_size + mac_header_size, false);
|
||||
|
||||
// check if this is Msg4 that needs to contain the contention resolution ID CE
|
||||
if (msg3_tti != -1) {
|
||||
if (lcid == 0) {
|
||||
if (mac_msg_dl.new_subh()) {
|
||||
if (mac_msg_dl.get()->set_con_res_id(conres_id)) {
|
||||
log.info("CE: Added Contention Resolution ID=0x%" PRIx64 "\n", conres_id);
|
||||
} else {
|
||||
log.error("CE: Setting Contention Resolution ID CE\n");
|
||||
}
|
||||
} else {
|
||||
log.error("CE: Setting Contention Resolution ID CE. No space for a subheader\n");
|
||||
}
|
||||
msg3_tti = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Add payload
|
||||
if (mac_msg_dl.new_subh()) {
|
||||
int n = mac_msg_dl.get()->set_sdu(lcid, pdu_size, tmp_rlc_buffer.msg);
|
||||
if (n == -1) {
|
||||
log.error("Error while adding SDU (%d B) to MAC PDU\n", pdu_size);
|
||||
mac_msg_dl.del_subh();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* mac_pdu_ptr = mac_msg_dl.write_packet(&log);
|
||||
if (mac_pdu_ptr != nullptr) {
|
||||
log.info_hex(mac_pdu_ptr, mac_msg_dl.get_pdu_len(), "DL MAC PDU (%d B):\n", mac_msg_dl.get_pdu_len());
|
||||
|
||||
// Prepare MAC grant for CCCH
|
||||
mac_interface_phy_lte::mac_grant_dl_t dl_grant = {};
|
||||
dl_grant.pid = get_pid(tti);
|
||||
dl_grant.rnti = dl_rnti;
|
||||
dl_grant.tb[0].tbs = mac_msg_dl.get_pdu_len();
|
||||
dl_grant.tb[0].ndi_present = true;
|
||||
dl_grant.tb[0].ndi = get_ndi_for_new_dl_tx(tti);
|
||||
|
||||
ue->new_tb(dl_grant, (const uint8_t*)mac_pdu_ptr);
|
||||
} else {
|
||||
log.error("Error writing DL MAC PDU\n");
|
||||
}
|
||||
mac_msg_dl.reset();
|
||||
} else {
|
||||
log.error("Can't fit RLC PDU into buffer (%d > %d)\n", buf_state, tmp_rlc_buffer.get_tailroom());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check if we need to provide a UL grant as well
|
||||
}
|
||||
} else {
|
||||
log.debug("Not handling RNTI=%d\n", dl_rnti);
|
||||
}
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
|
||||
running = false;
|
||||
|
||||
if (ue != NULL) {
|
||||
ue->stop();
|
||||
}
|
||||
|
||||
// Stopping system interface
|
||||
ut.stop();
|
||||
sys.stop();
|
||||
ip_sock.stop();
|
||||
ip_ctrl.stop();
|
||||
srb.stop();
|
||||
ue->stop();
|
||||
}
|
||||
|
||||
// Internal function called with acquired lock
|
||||
|
@ -148,85 +343,66 @@ public:
|
|||
rlc.reset();
|
||||
pdcp.reset();
|
||||
cells.clear();
|
||||
pcell_idx = -1;
|
||||
pcell_idx = -1;
|
||||
as_security_enabled = false;
|
||||
}
|
||||
|
||||
// Called from UT before starting testcase
|
||||
void tc_start(const char* name)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
// strip testsuite name
|
||||
std::string tc_name = get_tc_name(name);
|
||||
|
||||
if (ue == nullptr) {
|
||||
// strip testsuite name
|
||||
std::string tc_name = get_tc_name(name);
|
||||
// Make a copy of the UE args for this run
|
||||
all_args_t local_args = args;
|
||||
|
||||
// Make a copy of the UE args for this run
|
||||
all_args_t local_args = args;
|
||||
|
||||
// set up logging
|
||||
if (args.log.filename == "stdout") {
|
||||
logger = &logger_stdout;
|
||||
} else {
|
||||
logger_file->init(get_filename_with_tc_name(local_args.log.filename, run_id, tc_name).c_str(), -1);
|
||||
logger = logger_file;
|
||||
}
|
||||
|
||||
log.info("Initializing UE ID=%d for TC=%s\n", run_id, tc_name.c_str());
|
||||
log.console("Initializing UE ID=%d for TC=%s\n", run_id, tc_name.c_str());
|
||||
|
||||
// Patch UE config
|
||||
local_args.stack.pcap.filename = get_filename_with_tc_name(args.stack.pcap.filename, run_id, tc_name);
|
||||
local_args.stack.pcap.nas_filename = get_filename_with_tc_name(args.stack.pcap.nas_filename, run_id, tc_name);
|
||||
|
||||
// bring up UE
|
||||
ue = std::unique_ptr<ttcn3_ue>(new ttcn3_ue());
|
||||
if (ue->init(local_args, logger, this, tc_name)) {
|
||||
ue->stop();
|
||||
ue.reset(nullptr);
|
||||
std::string err("Couldn't initialize UE.\n");
|
||||
log.error("%s\n", err.c_str());
|
||||
log.console("%s\n", err.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// Start simulator thread
|
||||
running = true;
|
||||
start();
|
||||
// set up logging
|
||||
if (args.log.filename == "stdout") {
|
||||
logger = &logger_stdout;
|
||||
} else {
|
||||
log.error("UE hasn't been deallocated properly because TC didn't finish correctly.\n");
|
||||
log.console("UE hasn't been deallocated properly because TC didn't finish correctly.\n");
|
||||
logger_file->init(get_filename_with_tc_name(local_args.log.filename, run_id, tc_name).c_str(), -1);
|
||||
logger = logger_file;
|
||||
}
|
||||
|
||||
log.info("Initializing UE ID=%d for TC=%s\n", run_id, tc_name.c_str());
|
||||
log.console("Initializing UE ID=%d for TC=%s\n", run_id, tc_name.c_str());
|
||||
|
||||
// Patch UE config
|
||||
local_args.stack.pcap.filename = get_filename_with_tc_name(args.stack.pcap.filename, run_id, tc_name);
|
||||
local_args.stack.pcap.nas_filename = get_filename_with_tc_name(args.stack.pcap.nas_filename, run_id, tc_name);
|
||||
|
||||
// bring up UE
|
||||
if (ue->init(local_args, logger, this, tc_name)) {
|
||||
ue->stop();
|
||||
std::string err("Couldn't initialize UE.\n");
|
||||
log.error("%s\n", err.c_str());
|
||||
log.console("%s\n", err.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
// create and add TTI timer to epoll
|
||||
if (add_epoll(timer_handler.get_timer_fd(), epoll_fd) != SRSLTE_SUCCESS) {
|
||||
log.error("Error while adding TTI timer to epoll\n");
|
||||
}
|
||||
event_handler.insert({timer_handler.get_timer_fd(), &timer_handler});
|
||||
}
|
||||
|
||||
// Called from UT to terminate the testcase
|
||||
void tc_end()
|
||||
{
|
||||
// ask periodic thread to stop before locking mutex
|
||||
running = false;
|
||||
log.info("Deinitializing UE ID=%d\n", run_id);
|
||||
log.console("Deinitializing UE ID=%d\n", run_id);
|
||||
ue->stop();
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
// stop TTI timer
|
||||
del_epoll(timer_handler.get_timer_fd(), epoll_fd);
|
||||
|
||||
if (ue != nullptr) {
|
||||
log.info("Deinitializing UE ID=%d\n", run_id);
|
||||
log.console("Deinitializing UE ID=%d\n", run_id);
|
||||
ue->stop();
|
||||
logger_file->stop();
|
||||
|
||||
// wait until SS main thread has terminated before resetting UE
|
||||
wait_thread_finish();
|
||||
run_id++;
|
||||
|
||||
ue.reset();
|
||||
|
||||
// Reset SS' RLC and PDCP
|
||||
reset();
|
||||
|
||||
logger_file->stop();
|
||||
|
||||
run_id++;
|
||||
} else {
|
||||
log.error("UE is not allocated. Nothing needs to be done.\n");
|
||||
log.console("UE is not allocated. Nothing needs to be done.\n");
|
||||
}
|
||||
// Reset SS' RLC and PDCP
|
||||
reset();
|
||||
}
|
||||
|
||||
void power_off_ue()
|
||||
|
@ -248,8 +424,7 @@ public:
|
|||
{
|
||||
// verify that UE intends to send PRACH on current Pcell
|
||||
if (cells[pcell_idx]->cell.id != cell_id) {
|
||||
log.error(
|
||||
"UE is attempting to PRACH on pci=%d while current Pcell is pci=%d\n", cell_id, cells[pcell_idx]->cell.id);
|
||||
log.error("UE is attempting to PRACH on pci=%d, current Pcell=%d\n", cell_id, cells[pcell_idx]->cell.id);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -374,7 +549,7 @@ public:
|
|||
ul_grant.rnti = crnti;
|
||||
ul_grant.pid = get_pid(tti);
|
||||
ul_grant.is_rar = true;
|
||||
|
||||
|
||||
ue->new_grant_ul(ul_grant);
|
||||
}
|
||||
|
||||
|
@ -467,163 +642,42 @@ public:
|
|||
return last_dl_ndi[pid];
|
||||
}
|
||||
|
||||
void run_thread()
|
||||
int run()
|
||||
{
|
||||
uint32_t sib_idx = 0;
|
||||
running = true;
|
||||
|
||||
while (running) {
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
// wait for event
|
||||
const int32_t epoll_timeout_ms = -1;
|
||||
const uint32_t MAX_EVENTS = 1;
|
||||
struct epoll_event events[MAX_EVENTS] = {};
|
||||
int nof_events = epoll_wait(epoll_fd, events, MAX_EVENTS, epoll_timeout_ms);
|
||||
|
||||
tti = (tti + 1) % 10240;
|
||||
// handle event
|
||||
if (nof_events == -1) {
|
||||
perror("epoll_wait() error");
|
||||
break;
|
||||
}
|
||||
if (nof_events == 0) {
|
||||
printf("time out %f sec expired\n", epoll_timeout_ms / 1000.0);
|
||||
continue;
|
||||
}
|
||||
|
||||
log.step(tti);
|
||||
log.debug("Start new TTI\n");
|
||||
|
||||
ue->set_current_tti(tti);
|
||||
|
||||
// process events, if any
|
||||
while (not event_queue.empty()) {
|
||||
ss_events_t ev = event_queue.wait_pop();
|
||||
switch (ev) {
|
||||
case UE_SWITCH_ON:
|
||||
log.console("Switching on UE ID=%d\n", run_id);
|
||||
ue->switch_on();
|
||||
break;
|
||||
case UE_SWITCH_OFF:
|
||||
log.console("Switching off UE ID=%d\n", run_id);
|
||||
ue->switch_off();
|
||||
break;
|
||||
case ENABLE_DATA:
|
||||
log.console("Enabling data for UE ID=%d\n", run_id);
|
||||
ue->enable_data();
|
||||
break;
|
||||
case DISABLE_DATA:
|
||||
log.console("Disabling data for UE ID=%d\n", run_id);
|
||||
ue->disable_data();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pcell_idx == -1) {
|
||||
log.debug("Skipping TTI. Pcell not yet selected.\n");
|
||||
for (int i = 0; i < nof_events; ++i) {
|
||||
if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) {
|
||||
///< An error has occured on this fd, or the socket is not ready for reading
|
||||
fprintf(stderr, "epoll error\n");
|
||||
close(events[i].data.fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
// DL/UL processing if UE has selected cell
|
||||
dl_rnti = ue->get_dl_sched_rnti(tti);
|
||||
if (SRSLTE_RNTI_ISSI(dl_rnti)) {
|
||||
// deliver SIBs one after another
|
||||
mac_interface_phy_lte::mac_grant_dl_t dl_grant = {};
|
||||
dl_grant.pid = get_pid(tti);
|
||||
dl_grant.rnti = dl_rnti;
|
||||
dl_grant.tb[0].tbs = cells[pcell_idx]->sibs[sib_idx]->N_bytes;
|
||||
dl_grant.tb[0].ndi = get_ndi_for_new_dl_tx(tti);
|
||||
ue->new_tb(dl_grant, cells[pcell_idx]->sibs[sib_idx]->msg);
|
||||
log.info("Delivered SIB%d for pcell_idx=%d\n", sib_idx, pcell_idx);
|
||||
sib_idx = (sib_idx + 1) % cells[pcell_idx]->sibs.size();
|
||||
} else if (SRSLTE_RNTI_ISRAR(dl_rnti)) {
|
||||
if (prach_tti != -1) {
|
||||
rar_tti = (prach_tti + 3) % 10240;
|
||||
if (tti == rar_tti) {
|
||||
send_rar(prach_preamble_index);
|
||||
}
|
||||
}
|
||||
} else if (SRSLTE_RNTI_ISPA(dl_rnti)) {
|
||||
log.debug("Searching for paging RNTI\n");
|
||||
// PCH will be triggered from SYSSIM after receiving Paging
|
||||
} else if (SRSLTE_RNTI_ISUSER(dl_rnti)) {
|
||||
// check if this is for contention resolution after PRACH/RAR
|
||||
if (dl_rnti == crnti) {
|
||||
log.debug("Searching for C-RNTI=%d\n", crnti);
|
||||
|
||||
if (rar_tti != -1) {
|
||||
msg3_tti = (rar_tti + 3) % 10240;
|
||||
if (tti == msg3_tti) {
|
||||
send_msg3_grant();
|
||||
rar_tti = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check for SR
|
||||
if (sr_tti != -1) {
|
||||
send_sr_ul_grant();
|
||||
}
|
||||
|
||||
if (dl_rnti != 0) {
|
||||
log.debug("Searching for RNTI=%d\n", dl_rnti);
|
||||
|
||||
// look for DL data to be send in each bearer and provide grant accordingly
|
||||
for (int lcid = 0; lcid < SRSLTE_N_RADIO_BEARERS; lcid++) {
|
||||
uint32_t buf_state = rlc.get_buffer_state(lcid);
|
||||
if (buf_state > 0) {
|
||||
log.debug("LCID=%d, buffer_state=%d\n", lcid, buf_state);
|
||||
const uint32_t mac_header_size = 10; // Add MAC header (10 B for all subheaders, etc)
|
||||
if (tmp_rlc_buffer.get_tailroom() > (buf_state + mac_header_size)) {
|
||||
uint32_t pdu_size = rlc.read_pdu(lcid, tmp_rlc_buffer.msg, buf_state);
|
||||
tx_payload_buffer.clear();
|
||||
mac_msg_dl.init_tx(&tx_payload_buffer, pdu_size + mac_header_size, false);
|
||||
|
||||
// check if this is Msg4 that needs to contain the contention resolution ID CE
|
||||
if (msg3_tti != -1) {
|
||||
if (lcid == 0) {
|
||||
if (mac_msg_dl.new_subh()) {
|
||||
if (mac_msg_dl.get()->set_con_res_id(conres_id)) {
|
||||
log.info("CE: Added Contention Resolution ID=0x%" PRIx64 "\n", conres_id);
|
||||
} else {
|
||||
log.error("CE: Setting Contention Resolution ID CE\n");
|
||||
}
|
||||
} else {
|
||||
log.error("CE: Setting Contention Resolution ID CE. No space for a subheader\n");
|
||||
}
|
||||
msg3_tti = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Add payload
|
||||
if (mac_msg_dl.new_subh()) {
|
||||
int n = mac_msg_dl.get()->set_sdu(lcid, pdu_size, tmp_rlc_buffer.msg);
|
||||
if (n == -1) {
|
||||
log.error("Error while adding SDU (%d B) to MAC PDU\n", pdu_size);
|
||||
mac_msg_dl.del_subh();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* mac_pdu_ptr = mac_msg_dl.write_packet(&log);
|
||||
if (mac_pdu_ptr != nullptr) {
|
||||
log.info_hex(
|
||||
mac_pdu_ptr, mac_msg_dl.get_pdu_len(), "DL MAC PDU (%d B):\n", mac_msg_dl.get_pdu_len());
|
||||
|
||||
// Prepare MAC grant for CCCH
|
||||
mac_interface_phy_lte::mac_grant_dl_t dl_grant = {};
|
||||
dl_grant.pid = get_pid(tti);
|
||||
dl_grant.rnti = dl_rnti;
|
||||
dl_grant.tb[0].tbs = mac_msg_dl.get_pdu_len();
|
||||
dl_grant.tb[0].ndi_present = true;
|
||||
dl_grant.tb[0].ndi = get_ndi_for_new_dl_tx(tti);
|
||||
|
||||
ue->new_tb(dl_grant, (const uint8_t*)mac_pdu_ptr);
|
||||
} else {
|
||||
log.error("Error writing DL MAC PDU\n");
|
||||
}
|
||||
mac_msg_dl.reset();
|
||||
} else {
|
||||
log.error("Can't fit RLC PDU into buffer (%d > %d)\n", buf_state, tmp_rlc_buffer.get_tailroom());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Check if we need to provide a UL grant as well
|
||||
}
|
||||
} else {
|
||||
log.debug("Not handling RNTI=%d\n", dl_rnti);
|
||||
int fd = events[i].data.fd;
|
||||
if (event_handler.find(fd) != event_handler.end()) {
|
||||
event_handler[fd]->handle_event(fd, events[i], epoll_fd);
|
||||
}
|
||||
}
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
log.info("Leaving main thread.\n");
|
||||
log.console("Leaving main thread.\n");
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
uint32_t get_tti() { return tti; }
|
||||
|
@ -927,6 +981,13 @@ private:
|
|||
ttcn3_ip_ctrl_interface ip_ctrl;
|
||||
ttcn3_srb_interface srb;
|
||||
|
||||
// Epoll
|
||||
int epoll_fd = -1;
|
||||
int signal_fd = -1; ///< FD for signals
|
||||
std::map<uint32_t, epoll_handler*> event_handler; ///< Lookup table for handler
|
||||
epoll_timer_handler timer_handler;
|
||||
epoll_signal_handler signal_handler;
|
||||
|
||||
// Logging stuff
|
||||
srslte::logger_stdout logger_stdout;
|
||||
srslte::logger_file* logger_file = nullptr;
|
||||
|
@ -946,9 +1007,8 @@ private:
|
|||
srslte::byte_buffer_pool* pool = nullptr;
|
||||
|
||||
// Simulator vars
|
||||
unique_ptr<ttcn3_ue> ue = nullptr;
|
||||
std::mutex mutex;
|
||||
bool running = false;
|
||||
ttcn3_ue* ue = nullptr;
|
||||
bool running = false;
|
||||
|
||||
typedef enum { UE_SWITCH_ON = 0, UE_SWITCH_OFF, ENABLE_DATA, DISABLE_DATA } ss_events_t;
|
||||
block_queue<ss_events_t> event_queue;
|
||||
|
@ -975,6 +1035,7 @@ private:
|
|||
float attenuation = 0.0;
|
||||
uint32_t earfcn = 0;
|
||||
std::vector<unique_byte_buffer_t> sibs;
|
||||
int sib_idx = 0; ///< Index of SIB scheduled for next transmission
|
||||
} syssim_cell_t;
|
||||
typedef std::unique_ptr<syssim_cell_t> unique_syssim_cell_t;
|
||||
std::vector<unique_syssim_cell_t> cells;
|
||||
|
@ -1004,6 +1065,14 @@ private:
|
|||
|
||||
std::vector<std::string> rb_id_vec =
|
||||
{"SRB0", "SRB1", "SRB2", "DRB1", "DRB2", "DRB3", "DRB4", "DRB5", "DRB6", "DRB7", "DRB8"};
|
||||
|
||||
// port constants
|
||||
const std::string listen_address = "0.0.0.0";
|
||||
const uint32_t UT_PORT = 2222;
|
||||
const uint32_t SYS_PORT = 2223;
|
||||
const uint32_t IPSOCK_PORT = 2224;
|
||||
const uint32_t IPCTRL_PORT = 2225;
|
||||
const uint32_t SRB_PORT = 2226;
|
||||
};
|
||||
|
||||
#endif // SRSUE_TTCN3_SYSSIM_H
|
||||
|
|
|
@ -31,119 +31,88 @@
|
|||
using namespace rapidjson;
|
||||
|
||||
// The UpperTester interface
|
||||
class ttcn3_ut_interface : public netsource_handler
|
||||
class ttcn3_ut_interface : public ttcn3_port_handler
|
||||
{
|
||||
public:
|
||||
ttcn3_ut_interface() : netsource_handler("TTCN3_UT_IF") {}
|
||||
ttcn3_ut_interface() {}
|
||||
~ttcn3_ut_interface(){};
|
||||
|
||||
void init(ss_ut_interface* syssim_, srslte::log* log_, std::string net_ip_, uint32_t net_port_)
|
||||
int init(ss_ut_interface* syssim_, srslte::log* log_, std::string net_ip_, uint32_t net_port_)
|
||||
{
|
||||
syssim = syssim_;
|
||||
log = log_;
|
||||
net_ip = net_ip_;
|
||||
net_port = net_port_;
|
||||
initialized = true;
|
||||
log->debug("Initialized.\n");
|
||||
|
||||
// create socket and
|
||||
return port_listen();
|
||||
}
|
||||
|
||||
private:
|
||||
void run_thread()
|
||||
int handle_message(const unique_byte_array_t& rx_buf, const uint32_t n)
|
||||
{
|
||||
if (!initialized) {
|
||||
fprintf(stderr, "UT interface not initialized. Exiting.\n");
|
||||
exit(-1);
|
||||
Document document;
|
||||
if (document.Parse((char*)rx_buf->begin()).HasParseError() || document.IsObject() == false) {
|
||||
log->error_hex(rx_buf->begin(), n, "Error parsing incoming data.\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
// open TCP socket
|
||||
if (srslte_netsource_init(&net_source, net_ip.c_str(), net_port, SRSLTE_NETSOURCE_TCP)) {
|
||||
fprintf(stderr, "Error creating input TCP socket at port %d\n", net_port);
|
||||
exit(-1);
|
||||
}
|
||||
// Pretty-print
|
||||
StringBuffer buffer;
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
document.Accept(writer);
|
||||
log->info("Received %d bytes\n%s\n", n, (char*)buffer.GetString());
|
||||
|
||||
log->info("Listening on %s:%d for incoming connections ..\n", net_ip.c_str(), net_port);
|
||||
// check for command
|
||||
assert(document.HasMember("Cmd"));
|
||||
assert(document["Cmd"].IsObject());
|
||||
|
||||
running = true;
|
||||
// get Cmd
|
||||
const Value& a = document["Cmd"];
|
||||
|
||||
int n;
|
||||
while (run_enable) {
|
||||
log->debug("Reading from UT port ..\n");
|
||||
if (a.HasMember("MMI")) {
|
||||
assert(a.HasMember("MMI"));
|
||||
|
||||
n = srslte_netsource_read(&net_source, rx_buf->begin(), RX_BUF_SIZE);
|
||||
if (n > 0) {
|
||||
// Terminate
|
||||
rx_buf->at(n) = '\0';
|
||||
// get MMI and make sure it has another Cmd nested
|
||||
const Value& mmi = a["MMI"];
|
||||
assert(mmi.HasMember("Cmd"));
|
||||
|
||||
Document document;
|
||||
if (document.Parse((char*)rx_buf->begin()).HasParseError()) {
|
||||
log->error_hex(rx_buf->begin(), n, "Error parsing incoming data.\n");
|
||||
continue;
|
||||
}
|
||||
assert(document.IsObject());
|
||||
// get MMI cmd
|
||||
const Value& mmi_cmd = mmi["Cmd"];
|
||||
assert(mmi_cmd.IsString());
|
||||
|
||||
// Pretty-print
|
||||
StringBuffer buffer;
|
||||
PrettyWriter<StringBuffer> writer(buffer);
|
||||
document.Accept(writer);
|
||||
log->info("Received %d bytes\n%s\n", n, (char*)buffer.GetString());
|
||||
// check for CnfRequired
|
||||
assert(document.HasMember("CnfRequired"));
|
||||
|
||||
// check for command
|
||||
assert(document.HasMember("Cmd"));
|
||||
assert(document["Cmd"].IsObject());
|
||||
|
||||
// get Cmd
|
||||
const Value& a = document["Cmd"];
|
||||
|
||||
if (a.HasMember("MMI")) {
|
||||
assert(a.HasMember("MMI"));
|
||||
|
||||
// get MMI and make sure it has another Cmd nested
|
||||
const Value& mmi = a["MMI"];
|
||||
assert(mmi.HasMember("Cmd"));
|
||||
|
||||
// get MMI cmd
|
||||
const Value& mmi_cmd = mmi["Cmd"];
|
||||
assert(mmi_cmd.IsString());
|
||||
|
||||
// check for CnfRequired
|
||||
assert(document.HasMember("CnfRequired"));
|
||||
|
||||
if (strcmp(mmi_cmd.GetString(), "POWER_OFF") == 0) {
|
||||
log->info("Received POWER_OFF command.\n");
|
||||
handle_power_off(document);
|
||||
} else if (strcmp(mmi_cmd.GetString(), "SWITCH_ON") == 0) {
|
||||
log->info("Received SWITCH_ON command.\n");
|
||||
syssim->switch_on_ue();
|
||||
} else if (strcmp(mmi_cmd.GetString(), "SWITCH_OFF") == 0) {
|
||||
log->info("Received SWITCH_OFF command.\n");
|
||||
syssim->switch_off_ue();
|
||||
} else {
|
||||
log->error("Received unknown command: %s\n", mmi_cmd.GetString());
|
||||
}
|
||||
} else if (a.HasMember("AT")) {
|
||||
handle_at_command(document);
|
||||
} else if (a.HasMember("TC_START")) {
|
||||
log->info("Received TC_START command.\n");
|
||||
const Value& cmd = a["TC_START"];
|
||||
assert(cmd.HasMember("Name"));
|
||||
const Value& tc_name = cmd["Name"];
|
||||
syssim->tc_start(tc_name.GetString());
|
||||
} else if (a.HasMember("TC_END")) {
|
||||
log->info("Received TC_END command.\n");
|
||||
syssim->tc_end();
|
||||
} else {
|
||||
log->error("Unknown command type.\n");
|
||||
}
|
||||
} else if (n == 0) {
|
||||
log->error("Connection closed on UT interface.\n");
|
||||
if (strcmp(mmi_cmd.GetString(), "POWER_OFF") == 0) {
|
||||
log->info("Received POWER_OFF command.\n");
|
||||
handle_power_off(document);
|
||||
} else if (strcmp(mmi_cmd.GetString(), "SWITCH_ON") == 0) {
|
||||
log->info("Received SWITCH_ON command.\n");
|
||||
syssim->switch_on_ue();
|
||||
} else if (strcmp(mmi_cmd.GetString(), "SWITCH_OFF") == 0) {
|
||||
log->info("Received SWITCH_OFF command.\n");
|
||||
syssim->switch_off_ue();
|
||||
} else {
|
||||
log->error("Error receiving from network\n");
|
||||
exit(-1);
|
||||
log->error("Received unknown command: %s\n", mmi_cmd.GetString());
|
||||
}
|
||||
} else if (a.HasMember("AT")) {
|
||||
handle_at_command(document);
|
||||
} else if (a.HasMember("TC_START")) {
|
||||
log->info("Received TC_START command.\n");
|
||||
const Value& cmd = a["TC_START"];
|
||||
assert(cmd.HasMember("Name"));
|
||||
const Value& tc_name = cmd["Name"];
|
||||
syssim->tc_start(tc_name.GetString());
|
||||
} else if (a.HasMember("TC_END")) {
|
||||
log->info("Received TC_END command.\n");
|
||||
syssim->tc_end();
|
||||
} else {
|
||||
log->error("Unknown command type.\n");
|
||||
}
|
||||
running = false;
|
||||
|
||||
srslte_netsource_free(&net_source);
|
||||
return SRSLTE_SUCCESS;
|
||||
}
|
||||
|
||||
void handle_power_off(Document& document)
|
||||
|
@ -161,9 +130,7 @@ private:
|
|||
resp.Accept(writer);
|
||||
|
||||
log->info("Sending %s to tester (%zd B)\n", buffer.GetString(), buffer.GetSize());
|
||||
if (srslte_netsource_write(&net_source, (char*)buffer.GetString(), buffer.GetSize()) != SRSLTE_SUCCESS) {
|
||||
log->error("Error sending message to tester.\n");
|
||||
}
|
||||
send((const uint8_t*)buffer.GetString(), buffer.GetSize());
|
||||
}
|
||||
|
||||
void handle_at_command(Document& document)
|
||||
|
|
|
@ -30,5 +30,6 @@ target_link_libraries(ttcn3_dut srsue_stack
|
|||
srsue_phy
|
||||
srsue_mac
|
||||
rrc_asn1
|
||||
sctp
|
||||
${Boost_LIBRARIES})
|
||||
include_directories(${PROJECT_SOURCE_DIR}/srsue/test/ttcn3/hdr)
|
|
@ -28,8 +28,6 @@ namespace srsue {
|
|||
|
||||
lte_ttcn3_phy::lte_ttcn3_phy(srslte::logger* logger_) : logger(logger_) {}
|
||||
|
||||
lte_ttcn3_phy::~lte_ttcn3_phy() {}
|
||||
|
||||
int lte_ttcn3_phy::init(const phy_args_t& args_, stack_interface_phy_lte* stack_, syssim_interface_phy* syssim_)
|
||||
{
|
||||
stack = stack_;
|
||||
|
|
|
@ -19,8 +19,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "rapidjson/document.h" // rapidjson's DOM-style API
|
||||
#include "rapidjson/prettywriter.h" // for stringify JSON
|
||||
#include "srslte/build_info.h"
|
||||
#include "srslte/common/logmap.h"
|
||||
#include "srsue/hdr/ue.h"
|
||||
|
@ -28,7 +26,6 @@
|
|||
#include <boost/program_options.hpp>
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
#include <iostream>
|
||||
#include <signal.h>
|
||||
|
||||
using namespace srslte;
|
||||
using namespace srsue;
|
||||
|
@ -112,39 +109,26 @@ all_args_t parse_args(ttcn3_dut_args_t* args, int argc, char* argv[])
|
|||
return all_args;
|
||||
}
|
||||
|
||||
bool go_exit = false;
|
||||
void sig_int_handler(int signo)
|
||||
{
|
||||
printf("SIGINT received. Exiting...\n");
|
||||
if (signo == SIGINT) {
|
||||
go_exit = true;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
std::cout << "Built in " << srslte_get_build_mode() << " mode using " << srslte_get_build_info() << "." << std::endl;
|
||||
|
||||
ttcn3_dut_args_t dut_args;
|
||||
|
||||
ttcn3_dut_args_t dut_args = {};
|
||||
all_args_t ue_args = parse_args(&dut_args, argc, argv);
|
||||
|
||||
signal(SIGINT, sig_int_handler);
|
||||
|
||||
// Instantiate file logger
|
||||
srslte::logger_file logger_file;
|
||||
srslte::logmap::get_instance()->set_default_logger(&logger_file);
|
||||
|
||||
// create and init SYSSIM
|
||||
ttcn3_syssim syssim(&logger_file);
|
||||
syssim.init(ue_args);
|
||||
// Create UE object
|
||||
unique_ptr<ttcn3_ue> ue = std::unique_ptr<ttcn3_ue>(new ttcn3_ue());
|
||||
|
||||
// Loop until finished ..
|
||||
while (!go_exit) {
|
||||
sleep(1);
|
||||
// create and init SYSSIM
|
||||
ttcn3_syssim syssim(&logger_file, ue.get());
|
||||
if (syssim.init(ue_args) != SRSLTE_SUCCESS) {
|
||||
fprintf(stderr, "Error: Couldn't initialize system simulator\n");
|
||||
return SRSLTE_ERROR;
|
||||
}
|
||||
|
||||
syssim.stop();
|
||||
|
||||
return SRSLTE_SUCCESS;
|
||||
return syssim.run();
|
||||
}
|
||||
|
|
|
@ -24,5 +24,5 @@ add_executable(rapidjson_test rapidjson_test.cc)
|
|||
add_test(rapidjson_test rapidjson_test)
|
||||
|
||||
add_executable(ttcn3_if_handler_test ttcn3_if_handler_test.cc)
|
||||
target_link_libraries(ttcn3_if_handler_test srslte_phy srslte_common)
|
||||
target_link_libraries(ttcn3_if_handler_test sctp srslte_phy srslte_common)
|
||||
add_test(ttcn3_if_handler_test ttcn3_if_handler_test)
|
|
@ -19,15 +19,11 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include "srslte/srslte.h"
|
||||
#include "ttcn3_ip_ctrl_interface.h"
|
||||
#include "ttcn3_ip_sock_interface.h"
|
||||
#include "ttcn3_srb_interface.h"
|
||||
#include "ttcn3_sys_interface.h"
|
||||
#include "ttcn3_ut_interface.h"
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <vector>
|
||||
|
||||
int if_handler_test()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue