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