3 * Copyright 2019 AT&T Intellectual Property
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
23 #include <unistd.h> //for close()
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <netinet/sctp.h>
28 #include <arpa/inet.h> //for inet_ntop()
31 #include "e2sim_defs.h"
32 #include "e2sim_sctp.h"
33 #include "x2ap_message_handler.h"
35 #include "x2ap_generate_messages.h"
38 #include "Pendulum_asn_codec.h"
42 #include <sys/epoll.h>
44 #include "rmr_wrapper.h"
49 //these are the metrics being sent to the a1 mediator
50 int ave_ric_rtt_last_epoch=0;
51 int ave_msg_rate_last_epoch=0;
52 int ave_pendulum_msg_rate_last_epoch=0;
54 int total_rtt_current_epoch=0;
55 int total_messages_current_epoch=0;
56 int total_pendulum_messages_current_epoch=0;
58 int total_rtt_entries_current_epoch=0;
60 int epoch_duration = 1;//in seconds
62 long rtt_epoch_start_time =0;
64 long msg_rate_epoch_start_time =0;
65 long pendulum_msg_rate_epoch_start_time = 0;
67 long current_timestamp_in_us(){
68 struct timeval currentTime;
69 gettimeofday(¤tTime, NULL);
70 return currentTime.tv_sec * (int)1e6 + currentTime.tv_usec;
72 void update_rtt_metrics(long rtt){//called every time there is a new rtt measurement
73 if(rtt_epoch_start_time == 0)
74 rtt_epoch_start_time = current_timestamp_in_us(); //start of a new epoch
76 total_rtt_current_epoch = total_rtt_current_epoch+rtt;
77 total_rtt_entries_current_epoch++;
79 if((current_timestamp_in_us() - rtt_epoch_start_time) > (epoch_duration*1000000)){//an epoch has passed
80 ave_ric_rtt_last_epoch = total_rtt_current_epoch/total_rtt_entries_current_epoch;
81 total_rtt_current_epoch =0;
82 rtt_epoch_start_time = 0;
86 void update_msg_rate_metrics(){
87 if(msg_rate_epoch_start_time == 0)
88 msg_rate_epoch_start_time= current_timestamp_in_us(); //start of a new epoch
89 total_messages_current_epoch++;
90 if((current_timestamp_in_us() - msg_rate_epoch_start_time) > (epoch_duration*1000000)){//an epoch has passed
91 ave_msg_rate_last_epoch = total_messages_current_epoch;
92 total_messages_current_epoch =0;
93 msg_rate_epoch_start_time =0;
97 void update_pendulum_control_rate()
99 if(pendulum_msg_rate_epoch_start_time == 0)
100 pendulum_msg_rate_epoch_start_time = current_timestamp_in_us(); //start of a new epoch
101 total_pendulum_messages_current_epoch++;
103 if((current_timestamp_in_us() - pendulum_msg_rate_epoch_start_time) > (epoch_duration*1000000)){//an epoch has passed
104 ave_pendulum_msg_rate_last_epoch = total_pendulum_messages_current_epoch;
105 total_pendulum_messages_current_epoch = 0;
106 pendulum_msg_rate_epoch_start_time = 0;
111 void send_metrics_to_a1_med(struct rmr_context *rmr_c){
113 char* metrics= malloc(1024);
114 int time_int = current_timestamp_in_us()/1000000;
115 //int ave_msg_rate_last_epoch=500;
116 snprintf(metrics, 1024, "{%s:%d, %s:%d, %s:%d, %s:%d}", \
117 "\"latency\"", ave_ric_rtt_last_epoch/1000, \
118 "\"ricload\"",ave_msg_rate_last_epoch, \
119 "\"load\"",ave_pendulum_msg_rate_last_epoch, \
120 "\"time\"",time_int);
121 rmr_send_wrapper(rmr_c, mtype, metrics);
122 printf("Sent message of type:%d to a1_med with content:%s\n",mtype,metrics);
125 void forward_to_load_consumer(struct rmr_context *rmr_c){//the content does not matter
127 char* load_message="dummy load";
128 rmr_send_wrapper(rmr_c, mtype, load_message);
129 printf("Sent message of type:%d to load consumer with content:%s\n",mtype,load_message);
132 static void pendulum_control_E2_Termination(int client_fd)
134 printf("--------------------------------------\n");
135 printf("E2 TERMINATION - START PENDULUM CONTROL\n");
136 printf("--------------------------------------\n");
138 uint8_t *send_buffer;
139 uint8_t recv_buffer[1024];
143 clock_t begin = clock();
145 double rtt_stats[100000];
147 long fail_count = -1; //ignore the first message (see adruino code)
152 //=================================
155 struct rmr_context *rmr_c; //obtain our enhanced rmr_context
156 int mtype = 0; // we can loop through several message types
157 char* lport = "43086"; // default listen port
158 long rcount = 0; // number of acks received
160 if( (eparm = getenv( "E2TERM_RMR_RCV_PORT" )) != NULL ) {
161 lport = strdup( eparm );
164 rmr_c = rmr_init_wrapper(lport);
166 while( ! rmr_ready( rmr_c->mrc ) ) {
167 fprintf( stderr, "<TEST> waiting for RMR to indicate ready\n" );
170 fprintf( stderr, "[OK] initialisation complete\n" );
173 //==================================
174 long loop_start_time = 0;
176 printf("----------------\n");
178 loop_start_time = current_timestamp_in_us();
179 //0. Receiving ASN message from E2 Agent
180 memset(recv_buffer, 0, sizeof(recv_buffer));
181 printf("Time to receive asn message after starting main loop: %ld microseconds \n",current_timestamp_in_us() - loop_start_time);
184 printf(" 1Time to receive asn message after starting main loop: %ld microseconds \n",current_timestamp_in_us() - loop_start_time);
185 //long time_of_message_from_e2agent = current_timestamp_in_us();
187 if((recv_len = recv(client_fd, &recv_buffer, sizeof(recv_buffer), 0)) == -1) {
192 long time_of_message_from_e2agent = current_timestamp_in_us();
194 printf(" 2Time to receive asn message after starting main loop: %ld microseconds \n",current_timestamp_in_us() - loop_start_time);
196 rmr_close_wrapper(rmr_c);
198 printf("Connection from closed by remote peer.\n");
199 if(close(client_fd) == -1) {
205 printf(" 3Time to receive asn message after starting main loop: %ld microseconds \n",current_timestamp_in_us() - loop_start_time);
206 // begin = clock() - begin;
207 // rtt = 1000*((double)begin)/CLOCKS_PER_SEC; // in ms
208 //printf("E2Term-Adruino-E2Term = %f ms\n", rtt);
210 //2. Decode ASN message and Extract pendulum angle
212 recv_str = pendulum_get_strval(recv_buffer, recv_len);
213 // if( (strcmp(recv_str, "-1") == 0) || (strcmp(recv_str, "") == 0) )
215 if(strcmp(recv_str, "\n") == 0)
217 printf("RECEIVED EOL\n");
220 printf(" 4Time to receive asn message after starting main loop: %ld microseconds \n",current_timestamp_in_us() - loop_start_time);
221 // if(atof(recv_str) <= 0)
223 // printf("FAILLLLLL\n");
227 // rtt_stats[recv_count] = atof(recv_str);
231 printf("Time to receive angle message from arduino after starting main loop: %ld microseconds \n",current_timestamp_in_us() - loop_start_time);
232 printf("Received message #%d from Adruino: %s\n", count, recv_str);
233 //printf("Last reported RTT (Adruino-RIC-Adruino): %f ms, fail_count = %ld\n",
234 // atof(recv_str)/1000, fail_count);
236 // 3. [BHARATH] send_to_xApp(&pendulum_state, &response)
239 // char* message = "foo 111";
241 int got_pend_control=0;
242 rmr_send_wrapper(rmr_c, mtype, recv_str );
243 printf("Sent message of type:%d to pendulum xApp with content:%s\n",mtype,recv_str);
244 long angle_receive_time =0;
245 while (got_pend_control == 0){
246 if(rmr_poll_for_message(rmr_c) == 1) {
247 update_msg_rate_metrics();
248 switch(rmr_c->rbuf->mtype) {
250 angle_receive_time = current_timestamp_in_us();
252 update_pendulum_control_rate(); //add this
253 strcpy(reply,rmr_c->rbuf->payload);
254 printf("Received control message from pendulum xapp with message type: %d and content %s\n",rmr_c->rbuf->mtype, reply);
257 printf("Received METRIC request from A1 mediator with message type: %d and content %s\n",rmr_c->rbuf->mtype,rmr_c->rbuf->payload);
258 send_metrics_to_a1_med(rmr_c);
261 printf("***************************Received load from load generator****************************");
262 forward_to_load_consumer(rmr_c);
270 printf("Time to receive control message from xapp after starting main loop: %ld microseconds \n",current_timestamp_in_us() - loop_start_time);
271 // snprintf(reply, 1024, "$%d#\n", (int)ave_ric_rtt_last_epoch/1000);
272 send_len = pendulum_create_asn_msg(&send_buffer, 0, 0, 0, reply);
273 printf("Time to create asn message after receiving angle: %ld microseconds\n",current_timestamp_in_us() - angle_receive_time);
276 //6. Send ASN1 message to socket
277 if(sctp_send_to_socket(client_fd, send_buffer, (size_t)send_len) > 0){
278 printf("Sent ASN1 response to E2 Agent\n");
280 long time_of_reply_to_e2agent = current_timestamp_in_us();
281 printf("Time to send asn message after receiving angle: %ld microseconds \n",current_timestamp_in_us() - angle_receive_time);
282 long rtt = (time_of_reply_to_e2agent - time_of_message_from_e2agent);
283 ave_ric_rtt_last_epoch = rtt;
284 printf("RIC RTT is %lf milliseconds\n", rtt/1000.0);
285 //update_rtt_metrics(rtt);
288 rmr_close_wrapper(rmr_c);
292 int main(int argc, char* argv[])
294 // test_rmr(); return 0;
296 const char* server_ip = DEFAULT_SCTP_IP;
297 int server_port = X2AP_SCTP_PORT;
300 if(argc == 3) //user provided IP and PORT
303 server_port = atoi(argv[2]);
304 if(server_port < 1 || server_port > 65535) {
305 printf("Invalid port number (%d). Valid values are between 1 and 65535.\n", server_port);
309 else if(argc == 2) //user provided only IP
315 server_ip = DEFAULT_SCTP_IP;
319 printf("Unrecognized option.\n");
320 printf("Usage: %s [SERVER IP ADDRESS] [SERVER PORT]\n", argv[0]);
325 client_fd = sctp_start_client(server_ip, server_port);
330 //Note: put a while(1) loop here if want client to stay
331 // for(int i = 0; i < 3; i++)
336 printf("------------------------\n");
340 //Create pdu for x2 message and send to socket
341 len = x2ap_generate_x2_setup_request(&buffer);
342 if(sctp_send_to_socket(client_fd, buffer, (size_t)len) > 0){
343 printf("Sent X2 SETUP REQUEST\n");
346 //=======================================================================
347 //printf("waiting for server response\n");
348 uint8_t recv_buf[MAX_SCTP_BUFFER];
351 //sctp_recv_from_socket(client_fd, recv_buf, sizeof(recv_buf));
352 memset(recv_buf, 0, sizeof(recv_buf));
353 recv_len = recv(client_fd, &recv_buf, sizeof(recv_buf), 0);
360 //printf("Received a message of size %d\n", recv_len);
361 x2ap_eNB_handle_message(recv_buf, recv_len, NULL);
363 begin = clock() - begin;
364 double time_taken = 1000*((double)begin)/CLOCKS_PER_SEC; // in ms
365 printf("Close-loop time: %f ms \n", time_taken);
366 printf("X2 Setup Completed \n");
370 //=========================================================================
371 // Pendulum interaction
372 // Receive pendulum state from E2 Agent and send response
373 pendulum_control_E2_Termination(client_fd);