diff --git a/lib/include/srslte/common/epoll_helper.h b/lib/include/srslte/common/epoll_helper.h new file mode 100644 index 000000000..25fc31253 --- /dev/null +++ b/lib/include/srslte/common/epoll_helper.h @@ -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 +#include +#include +#include +#include +#include + +///< 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; + +///< 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 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 diff --git a/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h b/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h index c5742fc80..d222dbdc5 100644 --- a/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h +++ b/srsue/test/ttcn3/hdr/lte_ttcn3_phy.h @@ -45,7 +45,7 @@ public: typedef std::vector 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_); diff --git a/srsue/test/ttcn3/hdr/ttcn3_common.h b/srsue/test/ttcn3/hdr/ttcn3_common.h new file mode 100644 index 000000000..5e2e3c5b9 --- /dev/null +++ b/srsue/test/ttcn3/hdr/ttcn3_common.h @@ -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 + +const static uint32_t RX_BUF_SIZE = 1024 * 1024; +typedef std::array byte_array_t; +typedef std::unique_ptr unique_byte_array_t; + +#endif // SRSUE_TTCN3_COMMON_H diff --git a/srsue/test/ttcn3/hdr/ttcn3_ip_ctrl_interface.h b/srsue/test/ttcn3/hdr/ttcn3_ip_ctrl_interface.h index 6503c5286..354f6bec2 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_ip_ctrl_interface.h +++ b/srsue/test/ttcn3/hdr/ttcn3_ip_ctrl_interface.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); - 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_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 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"); - } + 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; } - running = false; + // Pretty-print + StringBuffer buffer; + PrettyWriter 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"); + } - 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()); } }; diff --git a/srsue/test/ttcn3/hdr/ttcn3_ip_sock_interface.h b/srsue/test/ttcn3/hdr/ttcn3_ip_sock_interface.h index ae4a9acc1..a1c3832ef 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_ip_sock_interface.h +++ b/srsue/test/ttcn3/hdr/ttcn3_ip_sock_interface.h @@ -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); - // 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); + 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); - - 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 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); - } + // Pretty-print + StringBuffer buffer; + PrettyWriter 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"); } - 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()); } }; diff --git a/srsue/test/ttcn3/hdr/ttcn3_port_handler.h b/srsue/test/ttcn3/hdr/ttcn3_port_handler.h new file mode 100644 index 000000000..5dbce8f89 --- /dev/null +++ b/srsue/test/ttcn3/hdr/ttcn3_port_handler.h @@ -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 +#include +#include + +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 diff --git a/srsue/test/ttcn3/hdr/ttcn3_srb_interface.h b/srsue/test/ttcn3/hdr/ttcn3_srb_interface.h index f173a21c0..e304680d7 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_srb_interface.h +++ b/srsue/test/ttcn3/hdr/ttcn3_srb_interface.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 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); - } - - // 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); - } - - 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); + 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); + // 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; - // 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; + } - 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 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"); - } + // Pretty-print + StringBuffer buffer; + PrettyWriter 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 = 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 \ No newline at end of file diff --git a/srsue/test/ttcn3/hdr/ttcn3_sys_interface.h b/srsue/test/ttcn3/hdr/ttcn3_sys_interface.h index dc1734fc7..6e83c74e8 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_sys_interface.h +++ b/srsue/test/ttcn3/hdr/ttcn3_sys_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 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 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; diff --git a/srsue/test/ttcn3/hdr/ttcn3_syssim.h b/srsue/test/ttcn3/hdr/ttcn3_syssim.h index 713f1fad9..481086ac3 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_syssim.h +++ b/srsue/test/ttcn3/hdr/ttcn3_syssim.h @@ -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 #include #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 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; } - void stop() + int add_port_handler() { - std::lock_guard lock(mutex); + // 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); - running = false; + return SRSLTE_SUCCESS; + } - if (ue != NULL) { - ue->stop(); + ///< 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); } + } - // Stopping system interface - ut.stop(); - sys.stop(); - ip_sock.stop(); - ip_ctrl.stop(); - srb.stop(); + void stop() + { + running = false; + 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 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; + } - // 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()); - 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(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; - } + // 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); - // Start simulator thread - running = true; - start(); - } 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"); + // 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; - - std::lock_guard lock(mutex); - - if (ue != nullptr) { - log.info("Deinitializing UE ID=%d\n", run_id); - log.console("Deinitializing UE ID=%d\n", run_id); - ue->stop(); + log.info("Deinitializing UE ID=%d\n", run_id); + log.console("Deinitializing UE ID=%d\n", run_id); + ue->stop(); - // wait until SS main thread has terminated before resetting UE - wait_thread_finish(); + // stop TTI timer + del_epoll(timer_handler.get_timer_fd(), epoll_fd); - ue.reset(); + logger_file->stop(); - // Reset SS' RLC and PDCP - reset(); + run_id++; - 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 lock(mutex); - - 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; - } - } + // 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); + + // 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; + } - 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 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 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 event_queue; @@ -975,6 +1035,7 @@ private: float attenuation = 0.0; uint32_t earfcn = 0; std::vector sibs; + int sib_idx = 0; ///< Index of SIB scheduled for next transmission } syssim_cell_t; typedef std::unique_ptr unique_syssim_cell_t; std::vector cells; @@ -1004,6 +1065,14 @@ private: std::vector 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 diff --git a/srsue/test/ttcn3/hdr/ttcn3_ut_interface.h b/srsue/test/ttcn3/hdr/ttcn3_ut_interface.h index 97adb9e79..c94457e5b 100644 --- a/srsue/test/ttcn3/hdr/ttcn3_ut_interface.h +++ b/srsue/test/ttcn3/hdr/ttcn3_ut_interface.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); - } - - // 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); + 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); - - running = true; - - int n; - while (run_enable) { - log->debug("Reading from UT port ..\n"); - - n = srslte_netsource_read(&net_source, rx_buf->begin(), RX_BUF_SIZE); - if (n > 0) { - // Terminate - 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"); - continue; - } - assert(document.IsObject()); - - // Pretty-print - StringBuffer buffer; - PrettyWriter writer(buffer); - document.Accept(writer); - log->info("Received %d bytes\n%s\n", n, (char*)buffer.GetString()); - - // 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"); + // Pretty-print + StringBuffer buffer; + PrettyWriter writer(buffer); + document.Accept(writer); + log->info("Received %d bytes\n%s\n", n, (char*)buffer.GetString()); + + // 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("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) diff --git a/srsue/test/ttcn3/src/CMakeLists.txt b/srsue/test/ttcn3/src/CMakeLists.txt index 4bc87d373..b7a35152d 100644 --- a/srsue/test/ttcn3/src/CMakeLists.txt +++ b/srsue/test/ttcn3/src/CMakeLists.txt @@ -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) \ No newline at end of file diff --git a/srsue/test/ttcn3/src/lte_ttcn3_phy.cc b/srsue/test/ttcn3/src/lte_ttcn3_phy.cc index 7a2c6744f..5f2a4795c 100644 --- a/srsue/test/ttcn3/src/lte_ttcn3_phy.cc +++ b/srsue/test/ttcn3/src/lte_ttcn3_phy.cc @@ -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_; diff --git a/srsue/test/ttcn3/src/ttcn3_dut.cc b/srsue/test/ttcn3/src/ttcn3_dut.cc index a84547281..2c6f42aa0 100644 --- a/srsue/test/ttcn3/src/ttcn3_dut.cc +++ b/srsue/test/ttcn3/src/ttcn3_dut.cc @@ -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 #include #include -#include 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 ue = std::unique_ptr(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(); } diff --git a/srsue/test/ttcn3/test/CMakeLists.txt b/srsue/test/ttcn3/test/CMakeLists.txt index eedc56779..9cf3aa7f2 100644 --- a/srsue/test/ttcn3/test/CMakeLists.txt +++ b/srsue/test/ttcn3/test/CMakeLists.txt @@ -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) \ No newline at end of file diff --git a/srsue/test/ttcn3/test/ttcn3_if_handler_test.cc b/srsue/test/ttcn3/test/ttcn3_if_handler_test.cc index ebb330c89..fcdc14b13 100644 --- a/srsue/test/ttcn3/test/ttcn3_if_handler_test.cc +++ b/srsue/test/ttcn3/test/ttcn3_if_handler_test.cc @@ -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 -#include -#include int if_handler_test() {