1 /*
2  * Copyright 2018 Oticon A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "bs_pc_base.h"
7 #include "bs_pc_2G4_types.h"
8 #include "bs_pc_2G4.h"
9 #include "bs_tracing.h"
10 #include <unistd.h>
11 
12 static pb_phy_state_t cb_med_state = {0};
13 
14 #pragma GCC diagnostic ignored "-Wunused-result"
15 
p2G4_phy_initcom(const char * s,const char * p,uint n)16 void p2G4_phy_initcom(const char* s, const char* p, uint n){
17   if (pb_phy_initcom(&cb_med_state, s, p, n))
18     bs_trace_error_line("Cannot establish communication with devices\n");
19 }
20 
p2G4_phy_disconnect_all_devices()21 void p2G4_phy_disconnect_all_devices(){
22   pb_phy_disconnect_devices(&cb_med_state);
23 }
24 
p2G4_phy_resp_wait(uint d)25 void p2G4_phy_resp_wait(uint d) {
26   pb_phy_resp_wait(&cb_med_state, d);
27 }
28 
29 /**
30  *  Respond to the device with P2G4_MSG_TX_END and the tx done structure
31  */
p2G4_phy_resp_tx(uint d,p2G4_tx_done_t * tx_done_s)32 void p2G4_phy_resp_tx(uint d, p2G4_tx_done_t *tx_done_s) {
33   if (pb_phy_is_connected_to_device(&cb_med_state, d)) {
34     pb_send_msg(cb_med_state.ff_ptd[d], P2G4_MSG_TX_END,
35                 (void *)tx_done_s, sizeof(p2G4_tx_done_t));
36   }
37 }
38 
39 /**
40  * Respond to the device with P2G4_MSG_RX_ADDRESSFOUND a
41  * p2G4_rx_done_t and a possible packet of p2G4_rx_done_t->packet_size bytes
42  */
p2G4_phy_resp_rx_addr_found(uint d,p2G4_rx_done_t * rx_done_s,uint8_t * packet)43 void p2G4_phy_resp_rx_addr_found(uint d, p2G4_rx_done_t* rx_done_s, uint8_t *packet) {
44   if (pb_phy_is_connected_to_device(&cb_med_state, d)) {
45     pb_send_msg(cb_med_state.ff_ptd[d], P2G4_MSG_RX_ADDRESSFOUND,
46                 (void *)rx_done_s, sizeof(p2G4_rx_done_t));
47     pb_send_payload(cb_med_state.ff_ptd[d], packet, rx_done_s->packet_size);
48   }
49 }
50 
51 /**
52  * Respond to the device with P2G4_MSG_RXV2_ADDRESSFOUND a
53  * p2G4_rx_done_t and a possible packet of p2G4_rxv2_done_t->packet_size bytes
54  */
p2G4_phy_resp_rxv2_addr_found(uint d,p2G4_rxv2_done_t * rx_done_s,uint8_t * packet)55 void p2G4_phy_resp_rxv2_addr_found(uint d, p2G4_rxv2_done_t* rx_done_s, uint8_t *packet) {
56   if (pb_phy_is_connected_to_device(&cb_med_state, d)) {
57     pb_send_msg(cb_med_state.ff_ptd[d], P2G4_MSG_RXV2_ADDRESSFOUND,
58                 (void *)rx_done_s, sizeof(p2G4_rxv2_done_t));
59     pb_send_payload(cb_med_state.ff_ptd[d], packet, rx_done_s->packet_size);
60   }
61 }
62 
63 /**
64  * Respond to the device with P2G4_MSG_RX_END and a p2G4_rx_done_t
65  * (note that the packet was already sent out in the address found)
66  */
p2G4_phy_resp_rx(uint d,p2G4_rx_done_t * rx_done_s)67 void p2G4_phy_resp_rx(uint d, p2G4_rx_done_t* rx_done_s) {
68   if (pb_phy_is_connected_to_device(&cb_med_state, d)) {
69     pb_send_msg(cb_med_state.ff_ptd[d], P2G4_MSG_RX_END,
70                 (void *)rx_done_s, sizeof(p2G4_rx_done_t));
71   }
72 }
73 
74 /**
75  * Respond to the device with P2G4_MSG_RX_ENDV2 and a p2G4_rx_donev2_t
76  * (note that the packet was already sent out in the address found)
77  */
p2G4_phy_resp_rxv2(uint d,p2G4_rxv2_done_t * rx_done_s)78 void p2G4_phy_resp_rxv2(uint d, p2G4_rxv2_done_t* rx_done_s) {
79   if (pb_phy_is_connected_to_device(&cb_med_state, d)) {
80     pb_send_msg(cb_med_state.ff_ptd[d], P2G4_MSG_RXV2_END,
81                 (void *)rx_done_s, sizeof(p2G4_rxv2_done_t));
82   }
83 }
84 
85 /**
86  * Respond to the device with P2G4_MSG_CCA_END and a p2G4_cca_done_t
87  */
p2G4_phy_resp_cca(uint d,p2G4_cca_done_t * sc_done_s)88 void p2G4_phy_resp_cca(uint d, p2G4_cca_done_t *sc_done_s) {
89   if (pb_phy_is_connected_to_device(&cb_med_state, d)) {
90     pb_send_msg(cb_med_state.ff_ptd[d], P2G4_MSG_CCA_END,
91                 (void *)sc_done_s, sizeof(p2G4_cca_done_t));
92   }
93 }
94 
95 /**
96  * Respond to the device with P2G4_MSG_RSSI_END and a p2G4_rssi_done_t
97  */
p2G4_phy_resp_RSSI(uint d,p2G4_rssi_done_t * RSSI_done_s)98 void p2G4_phy_resp_RSSI(uint d, p2G4_rssi_done_t* RSSI_done_s) {
99   if (pb_phy_is_connected_to_device(&cb_med_state, d)) {
100     pb_send_msg(cb_med_state.ff_ptd[d], P2G4_MSG_RSSI_END,
101                 (void *)RSSI_done_s, sizeof(p2G4_rssi_done_t));
102   }
103 }
104 
105 /**
106  * Respond to the device with P2G4_MSG_ABORTREVAL_RRSI and a p2G4_rssi_done_t
107  * (during an abort reeval procedure, as a result of the device asking for
108  * an immediate RSSI measurement)
109  */
p2G4_phy_resp_IMRSSI(uint d,p2G4_rssi_done_t * RSSI_done_s)110 void p2G4_phy_resp_IMRSSI(uint d, p2G4_rssi_done_t* RSSI_done_s) {
111   if (pb_phy_is_connected_to_device(&cb_med_state, d)) {
112     pb_send_msg(cb_med_state.ff_ptd[d], P2G4_MSG_IMMRSSI_RRSI_DONE,
113                 (void *)RSSI_done_s, sizeof(p2G4_rssi_done_t));
114   }
115 }
116 
p2G4_get_next_request(uint d)117 pc_header_t p2G4_get_next_request(uint d){
118   return pb_phy_get_next_request(&cb_med_state, d);
119 }
120 
p2G4_phy_get(uint d,void * b,size_t size)121 void p2G4_phy_get(uint d, void* b, size_t size) {
122   if (pb_phy_is_connected_to_device(&cb_med_state, d)) {
123     read(cb_med_state.ff_dtp[d], b, size);
124   }
125 }
126 
127 
128 /**
129  * Get abort structure from device
130  */
p2G4_phy_get_abort_struct(uint d,p2G4_abort_t * abort_s)131 void p2G4_phy_get_abort_struct(uint d, p2G4_abort_t* abort_s) {
132   ssize_t read_size = 0;
133   read_size = read(cb_med_state.ff_dtp[d], abort_s, sizeof(p2G4_abort_t));
134 
135   if (read_size != sizeof(p2G4_abort_t)) {
136     //There is some likelihood that a device will crash badly during abort
137     //reevaluation, therefore we try to handle it
138     bs_trace_warning_line(
139         "Low level communication with device %i broken during Abort reevaluation (tried to get %i got %i bytes) (most likely the device was terminated)\n",
140         d, sizeof(p2G4_abort_t), read_size);
141     pb_phy_disconnect_devices(&cb_med_state);
142     bs_trace_error_line("Exiting\n");
143   }
144 }
145 
146 /**
147  * Ask the device for a new abort struct for the ongoing Tx or Rx
148  */
p2G4_phy_get_new_abort(uint d,p2G4_abort_t * abort_s)149 int p2G4_phy_get_new_abort(uint d, p2G4_abort_t* abort_s) {
150   if (pb_phy_is_connected_to_device(&cb_med_state, d)) {
151     pc_header_t r_header = P2G4_MSG_ABORTREEVAL;
152     write(cb_med_state.ff_ptd[d], &r_header, sizeof(r_header));
153 
154     pc_header_t header = PB_MSG_DISCONNECT;
155     read(cb_med_state.ff_dtp[d], &header, sizeof(header));
156 
157     if (header == PB_MSG_TERMINATE) {
158       return PB_MSG_TERMINATE;
159     } else if (header == P2G4_MSG_RERESP_IMMRSSI) {
160       return P2G4_MSG_RERESP_IMMRSSI;
161     } else if (header != P2G4_MSG_RERESP_ABORTREEVAL) {
162       //if the read failed or the device really wants to disconnect in the
163       //middle of an abort (which is not really supported) we try to
164       //handle it gracefully
165       pb_phy_free_one_device(&cb_med_state ,d);
166     } else {
167       p2G4_phy_get_abort_struct(d, abort_s);
168     }
169   }
170   return 0;
171 }
172