1 #include "WLAN_actmod_argparse.h"
2 #include "bs_pc_2G4.h"
3 #include "bs_tracing.h"
4 #include "bs_utils.h"
5 
6 p2G4_dev_state_s_t dev_phy_state[WLAN_MAX_NBR_PORTS];
7 static bs_time_t time = 0;
8 static bs_time_t offset = 0;
9 
offset_time(bs_time_t time)10 static bs_time_t offset_time(bs_time_t time) {
11   bs_time_t phy_time;
12   if (time != TIME_NEVER) {
13     phy_time = time + offset;
14   } else {
15     phy_time = TIME_NEVER;
16   }
17   return phy_time;
18 }
19 
WLAN_actmod_get_time()20 bs_time_t WLAN_actmod_get_time(){
21   return time;
22 }
23 
24 static int number_ports = 0;
25 
WLAN_actmod_init_phy_com(WLAN_actmod_args_t * args)26 void WLAN_actmod_init_phy_com(WLAN_actmod_args_t *args){
27   offset = args->start_offset;
28   if ( args->start_offset < 0 ){
29     bs_trace_error_line("Time offset (%d) cannot be smaller than 0\n",args->start_offset);
30   }
31   bs_trace_raw_time(5,"Connecting to Phy in %i ports..\n", args->number_ports);
32 
33   number_ports = args->number_ports;
34   for (int i = 0 ; i < number_ports; i++) {
35     bs_trace_raw_time(8,"Connecting to port %i..\n", args->device_nbr[i]);
36     if (p2G4_dev_initcom_s_c(&dev_phy_state[i],
37                              args->device_nbr[i],
38                              args->s_id,
39                              args->p_id,
40                              NULL)
41           != 0 )
42       bs_trace_error_line("Couldn't connect to Phy in port %i\n", args->device_nbr[i]);
43   }
44 }
45 
WLAN_actmod_disconnect_phy_com()46 void WLAN_actmod_disconnect_phy_com(){
47   for ( int i = 0 ; i < number_ports; i++ ){
48     p2G4_dev_disconnect_s_c(&dev_phy_state[i]);
49   }
50 }
51 
WLAN_actmod_Tx_in_port(p2G4_tx_t * tx_s,uint port_nbr)52 int WLAN_actmod_Tx_in_port(p2G4_tx_t* tx_s, uint port_nbr){
53   /*
54    * We do a little trick to avoid deadlocking in between the ports
55    * (as the phy services one port at a time assuming each port is
56    * owned by an independent thread)
57    *  We queue ReqQueueDepth-1 requests before we try to pick any response
58    *  We keep a FIFO with a list of what we have requested in each port, so
59    *  that we remember what to pick back (FIFO_pending_resp)
60    *  Each time we are going to send a new request, we check if we have already
61    *  queued ReqQueueDepth, and if we did, we pick one response before
62    *  proceeding
63    *
64    *  Right now when we send a Tx request in one port, we send also a wait
65    *  response of the same duration in the other ports
66    */
67 
68   #define ReqQueueDepth 5
69   /*
70    * Increasing ReqQueueDepth increases slightly the speed of the simulation
71    * as we don't context switch so often between this model and the Phy
72    */
73 
74   typedef enum {None = 0, Wait, Tx} Pending_resp_t;
75 
76   static Pending_resp_t FIFO_pending_resp[ReqQueueDepth][WLAN_MAX_NBR_PORTS] = {{0}};
77   static int number_pending_requests = 0;
78   static int FIFO_read_ptr  = 0;
79   static int FIFO_write_ptr = 0;
80 
81   if (number_pending_requests == ReqQueueDepth) {
82     bs_trace_raw_time(9, "Removing one pending entry\n");
83     //let's pick one response from each port:
84     for (int i = 0 ; i < number_ports; i++) {
85       if (FIFO_pending_resp[FIFO_read_ptr][i] == Wait) {
86         bs_trace_raw_time(8, "Port %i pick Wait response\n", i);
87         if (p2G4_dev_pick_wait_resp_s_c_b(&dev_phy_state[i]) != 0) {
88           dev_phy_state[i].pb_dev_state.connected = false;
89           return -1;
90         }
91       } else if (FIFO_pending_resp[FIFO_read_ptr][i] == Tx) {
92         p2G4_tx_done_t tx_done_s;
93         bs_trace_raw_time(8, "Port %i pick Tx response\n", i);
94         if (p2G4_dev_pick_txresp_s_c_b(&dev_phy_state[i], &tx_done_s ) != 0) {
95           dev_phy_state[i].pb_dev_state.connected = false;
96           return -1;
97         }
98       }
99     }
100     number_pending_requests--;
101     FIFO_read_ptr = (FIFO_read_ptr + 1) % ReqQueueDepth;
102   }
103 
104   bs_trace_raw_time(9, "Sending one requests in each port\n");
105 
106   if (tx_s->start_time <= time) {
107     char Times[20];
108     bs_trace_warning_line_time("Requested Tx starts in the past (%s) == bad error\n",
109                                bs_time_to_str(Times, tx_s->start_time));
110     return -1;
111   }
112 
113   time = tx_s->end_time + 1;
114 
115   bs_time_t tx_start_time = offset_time(tx_s->start_time);
116   bs_time_t time_delta = tx_s->end_time - tx_s->start_time;
117   tx_s->start_time = tx_start_time;
118   tx_s->end_time = tx_start_time + time_delta;
119 
120   pb_wait_t wait_s;
121   wait_s.end = tx_s->end_time + 1;
122   for (int i = 0 ; i < number_ports; i++) {
123     if (i != port_nbr) {
124       bs_trace_raw_time(8, "Port %i: requesting Wait\n", i);
125       if (p2G4_dev_req_wait_s_c(&dev_phy_state[i], &wait_s) != 0) {
126         return -1;
127       }
128       FIFO_pending_resp[FIFO_write_ptr][i] = Wait;
129     } else {
130       bs_trace_raw_time(8, "Port %i: requesting Tx\n", i);
131       int ret = p2G4_dev_req_tx_s_c(&dev_phy_state[i], tx_s, NULL);
132       if ( ret == -1 ){
133         return -1;
134       }
135       FIFO_pending_resp[FIFO_write_ptr][i] = Tx;
136     }
137   }
138 
139   FIFO_write_ptr = ( FIFO_write_ptr + 1 ) % ReqQueueDepth;
140   number_pending_requests++;
141 
142   return 0;
143 }
144