1 /***************************************************************************/ /**
2  * @file  sl_wifi_callback_framework.c
3  *******************************************************************************
4  * # License
5  * <b>Copyright 2024 Silicon Laboratories Inc. www.silabs.com</b>
6  *******************************************************************************
7  *
8  * SPDX-License-Identifier: Zlib
9  *
10  * The licensor of this software is Silicon Laboratories Inc.
11  *
12  * This software is provided 'as-is', without any express or implied
13  * warranty. In no event will the authors be held liable for any damages
14  * arising from the use of this software.
15  *
16  * Permission is granted to anyone to use this software for any purpose,
17  * including commercial applications, and to alter it and redistribute it
18  * freely, subject to the following restrictions:
19  *
20  * 1. The origin of this software must not be misrepresented; you must not
21  *    claim that you wrote the original software. If you use this software
22  *    in a product, an acknowledgment in the product documentation would be
23  *    appreciated but is not required.
24  * 2. Altered source versions must be plainly marked as such, and must not be
25  *    misrepresented as being the original software.
26  * 3. This notice may not be removed or altered from any source distribution.
27  *
28  ******************************************************************************/
29 
30 #include "sl_wifi_callback_framework.h"
31 #include "sl_si91x_host_interface.h"
32 #include "sl_constants.h"
33 #include "sl_si91x_core_utilities.h"
34 #include "sl_si91x_driver.h"
35 #include "sl_wifi.h"
36 
37 /// Entry in the callback table
38 typedef struct {
39   sl_wifi_callback_function_t function; /// User provided callback function pointer
40   void *arg;                            /// User provided callback argument
41 } sl_wifi_callback_entry_t;
42 
43 //#define EXECUTE_CALLBACK(id, packet) do { if (registered_callbacks[id].function) {return registered_callbacks[id].function(packet->command, packet->data, packet->length, registered_callbacks[id].arg); } } while(0)
44 static sl_wifi_callback_entry_t *get_callback_entry(sl_wifi_event_group_t group);
45 static sl_wifi_event_group_t get_event_group_from_event(sl_wifi_event_t event);
46 
47 sl_wifi_callback_entry_t registered_callbacks[SL_WIFI_EVENT_GROUP_COUNT];
48 
sl_wifi_set_callback(sl_wifi_event_group_t group,sl_wifi_callback_function_t function,void * optional_arg)49 sl_status_t sl_wifi_set_callback(sl_wifi_event_group_t group, sl_wifi_callback_function_t function, void *optional_arg)
50 {
51   sl_wifi_callback_entry_t *entry = get_callback_entry(group);
52   if (entry != NULL) {
53     entry->function = function;
54     entry->arg      = optional_arg;
55     return SL_STATUS_OK;
56   }
57   return SL_STATUS_FAIL;
58 }
59 
sl_wifi_default_event_handler(sl_wifi_event_t event,sl_wifi_buffer_t * buffer)60 sl_status_t sl_wifi_default_event_handler(sl_wifi_event_t event, sl_wifi_buffer_t *buffer)
61 {
62   sl_wifi_callback_entry_t *entry = get_callback_entry((sl_wifi_event_group_t)event);
63 
64   // Verify there is a callback registered, if not return immediately
65   if (entry == NULL || entry->function == NULL) {
66     return SL_STATUS_OK;
67   }
68 
69   // Start processing the event
70   sl_si91x_packet_t *packet = (sl_si91x_packet_t *)sl_si91x_host_get_buffer_data((sl_wifi_buffer_t *)buffer, 0, NULL);
71   if (SL_WIFI_CHECK_IF_EVENT_FAILED(event)) {
72     sl_status_t status = convert_and_save_firmware_status(get_si91x_frame_status(packet));
73     if (packet->command == RSI_WLAN_RSP_JOIN) {
74       sl_status_t temp_status = sl_si91x_driver_send_command(RSI_WLAN_REQ_INIT,
75                                                              SI91X_WLAN_CMD,
76                                                              NULL,
77                                                              0,
78                                                              SL_SI91X_WAIT_FOR_COMMAND_SUCCESS,
79                                                              NULL,
80                                                              NULL);
81       VERIFY_STATUS_AND_RETURN(temp_status);
82     }
83 
84     return entry->function(event, &status, 0, entry->arg);
85   }
86   if (RSI_WLAN_RSP_CLIENT_CONNECTED == packet->command) {
87     sli_si91x_update_ap_client_info();
88   }
89 
90   if (event == SL_WIFI_TRANSCEIVER_TX_DATA_STATUS_CB) {
91     sl_wifi_transceiver_tx_data_confirmation_t tx_cfm_cb_data = { 0 };
92     tx_cfm_cb_data.status                                     = packet->desc[15];
93     tx_cfm_cb_data.rate     = packet->data[0];          //Extended descriptor in data[] for rate
94     tx_cfm_cb_data.priority = packet->data[4];          //Extended descriptor in data[] for priority
95     memcpy(&tx_cfm_cb_data.token, &packet->data[8], 4); //Extended descriptor in data[] for token
96 
97     return entry->function(event, &tx_cfm_cb_data, 0, entry->arg);
98   } else if (event == SL_WIFI_TRANSCEIVER_RX_DATA_RECEIVE_CB) {
99     sl_wifi_transceiver_rx_data_t rx_cb_data = { 0 };
100     uint16_t payload_offset                  = packet->desc[4];
101     uint16_t payload_length                  = packet->length & 0xFFF;
102     uint32_t status                          = *(uint32_t *)(&packet->data[12]);
103 
104     rx_cb_data.length = payload_length - payload_offset;
105     rx_cb_data.buffer = packet->data + payload_offset;
106     rx_cb_data.rssi   = *(uint16_t *)(&packet->data[0]); //Extended descriptor in data[] for rssi
107     rx_cb_data.rate   = *(uint16_t *)(&packet->data[2]); //Extended descriptor in data[] for rate
108 
109     /*
110      * SL_STATUS_UNKNOWN_PEER - If SL_SI91X_FEAT_TRANSCEIVER_MAC_PEER_DS_SUPPORT is enabled but
111      * data packet is received from a peer not present in MAC layer.
112      */
113     if ((status & TRANSCEIVER_RX_PKT_TA_MATCH_BIT) || IS_BCAST_MCAST_MAC(rx_cb_data.buffer[4]))
114       rx_cb_data.status = SL_STATUS_OK;
115     else
116       rx_cb_data.status = SL_STATUS_UNKNOWN_PEER;
117 
118     return entry->function(event, &rx_cb_data, 0, entry->arg);
119   }
120 
121   if (packet->length) {
122     return entry->function(event, packet->data, packet->length, entry->arg);
123   } else {
124     return entry->function(event, NULL, packet->length, entry->arg);
125   }
126 }
127 
get_callback_entry(sl_wifi_event_group_t group)128 static sl_wifi_callback_entry_t *get_callback_entry(sl_wifi_event_group_t group)
129 {
130   if (group > SL_WIFI_EVENT_GROUP_COUNT) {
131     group = get_event_group_from_event((sl_wifi_event_t)group);
132   }
133   return &registered_callbacks[group];
134 }
135 
get_event_group_from_event(sl_wifi_event_t event)136 static sl_wifi_event_group_t get_event_group_from_event(sl_wifi_event_t event)
137 {
138   //For TWT Events
139   if (event == SL_WIFI_TWT_UNSOLICITED_SESSION_SUCCESS_EVENT || event == SL_WIFI_TWT_AP_REJECTED_EVENT
140       || event == SL_WIFI_TWT_OUT_OF_TOLERANCE_EVENT || event == SL_WIFI_TWT_RESPONSE_NOT_MATCHED_EVENT
141       || event == SL_WIFI_TWT_UNSUPPORTED_RESPONSE_EVENT || event == SL_WIFI_TWT_TEARDOWN_SUCCESS_EVENT
142       || event == SL_WIFI_TWT_AP_TEARDOWN_SUCCESS_EVENT || event == SL_WIFI_TWT_FAIL_MAX_RETRIES_REACHED_EVENT
143       || event == SL_WIFI_TWT_INACTIVE_DUE_TO_ROAMING_EVENT || event == SL_WIFI_TWT_INACTIVE_DUE_TO_DISCONNECT_EVENT
144       || event == SL_WIFI_RESCHEDULE_TWT_SUCCESS_EVENT || event == SL_WIFI_TWT_INFO_FRAME_EXCHANGE_FAILED_EVENT
145       || event == SL_WIFI_TWT_INACTIVE_NO_AP_SUPPORT_EVENT) {
146     return SL_WIFI_TWT_RESPONSE_EVENTS;
147   }
148   // for STATS Events
149   else if (event == SL_WIFI_STATS_EVENT || event == SL_WIFI_STATS_ASYNC_EVENT || event == SL_WIFI_STATS_ADVANCE_EVENT
150            || event == SL_WIFI_STATS_TEST_MODE_EVENT || event == SL_WIFI_STATS_MODULE_STATE_EVENT) {
151     return SL_WIFI_STATS_RESPONSE_EVENTS;
152   } else if (event == SL_WIFI_TRANSCEIVER_RX_DATA_RECEIVE_CB || event == SL_WIFI_TRANSCEIVER_TX_DATA_STATUS_CB) {
153     return SL_WIFI_TRANSCEIVER_EVENTS;
154   } else {
155     event = SL_WIFI_INVALID_EVENT;
156   }
157   return (sl_wifi_event_group_t)event;
158 }
159