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