15
15
#include " eppp_link.h"
16
16
#include " wifi_remote_rpc_params.h"
17
17
#include " lwip/apps/snmp.h"
18
+ #include " esp_vfs.h"
19
+ #include " esp_vfs_eventfd.h"
18
20
19
21
extern " C" esp_netif_t *wifi_remote_eppp_init (eppp_type_t role);
20
22
@@ -32,30 +34,70 @@ const unsigned char key[] = "-----BEGIN PRIVATE KEY-----\n" CONFIG_ESP_WIFI_REMO
32
34
33
35
using namespace server ;
34
36
37
+ struct Events {
38
+ api_id type;
39
+ int32_t id;
40
+ esp_wifi_remote_eppp_ip_event *ip_data{nullptr };
41
+ bool clean_ip_data{true };
42
+ esp_err_t create_ip_data ()
43
+ {
44
+ ip_data = new (std::nothrow) esp_wifi_remote_eppp_ip_event;
45
+ return ip_data ? ESP_OK : ESP_ERR_NO_MEM;
46
+ }
47
+ ~Events ()
48
+ {
49
+ if (clean_ip_data) {
50
+ delete ip_data;
51
+ }
52
+ }
53
+ };
54
+
35
55
class Sync {
36
56
friend class RpcInstance ;
37
57
public:
38
- void lock ( )
58
+ esp_err_t put (Events &ev )
39
59
{
40
- xSemaphoreTake (mutex, portMAX_DELAY);
60
+ ESP_RETURN_ON_FALSE (xQueueSend (queue, &ev, pdMS_TO_TICKS (queue_timeout)), ESP_FAIL, TAG, " Failed to queue event %" PRIi32, ev.id );
61
+ ev.clean_ip_data = false ; // IP data were successfully sent to the queue, will free manually after receiving from it
62
+ uint64_t event_queued = 1 ;
63
+ write (fd, &event_queued, sizeof (event_queued)); // trigger the wait loop that
64
+ return ESP_OK;
41
65
}
42
- void unlock ()
66
+ Events get ()
43
67
{
44
- xSemaphoreGive (mutex);
68
+ Events ev{};
69
+ if (!xQueueReceive (queue, &ev, 0 )) {
70
+ ev.type = api_id::ERROR;
71
+ }
72
+ return ev;
45
73
}
46
74
esp_err_t init ()
47
75
{
48
- mutex = xSemaphoreCreateMutex ();
49
- return mutex == nullptr ? ESP_ERR_NO_MEM : ESP_OK;
76
+ queue = xQueueCreate (max_items, sizeof (Events));
77
+ esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT ();
78
+ esp_vfs_eventfd_register (&config);
79
+ fd = eventfd (0 , EFD_SUPPORT_ISR);
80
+ return queue == nullptr || fd < 0 ? ESP_ERR_NO_MEM : ESP_OK;
50
81
}
51
82
~Sync ()
52
83
{
53
- if (mutex) {
54
- vSemaphoreDelete (mutex);
84
+ if (queue) {
85
+ vQueueDelete (queue);
86
+ }
87
+ if (fd >= 0 ) {
88
+ close (fd);
55
89
}
56
90
}
91
+ int fd{-1 };
92
+ // Used to trigger task by either an internal event or rpc command
93
+ static const int NONE = 0 ;
94
+ static const int ERROR = 1 ;
95
+ static const int EVENT = 2 ;
96
+ static const int RPC = 4 ;
57
97
private:
58
- SemaphoreHandle_t mutex{nullptr };
98
+ QueueHandle_t queue{nullptr };
99
+ const int max_items = 15 ;
100
+ const int queue_timeout = 200 ;
59
101
};
60
102
61
103
class RpcInstance {
@@ -70,7 +112,7 @@ class RpcInstance {
70
112
ESP_RETURN_ON_ERROR (start_server (), TAG, " Failed to start RPC server" );
71
113
ESP_RETURN_ON_ERROR (rpc.init (), TAG, " Failed to init RPC engine" );
72
114
ESP_RETURN_ON_ERROR (esp_netif_napt_enable (netif), TAG, " Failed to enable NAPT" );
73
- ESP_RETURN_ON_ERROR (sync.init (), TAG, " Failed to init locks " );
115
+ ESP_RETURN_ON_ERROR (sync.init (), TAG, " Failed to init event queue " );
74
116
ESP_RETURN_ON_ERROR (esp_event_handler_register (WIFI_EVENT, ESP_EVENT_ANY_ID, handler, this ), TAG, " Failed to register event" );
75
117
ESP_RETURN_ON_ERROR (esp_event_handler_register (IP_EVENT, ESP_EVENT_ANY_ID, handler, this ), TAG, " Failed to register event" );
76
118
return xTaskCreate (task, " server" , 8192 , this , 5 , nullptr ) == pdTRUE ? ESP_OK : ESP_FAIL;
@@ -109,25 +151,24 @@ class RpcInstance {
109
151
esp_err_t wifi_event (int32_t id)
110
152
{
111
153
ESP_LOGI (TAG, " Received WIFI event %" PRIi32, id);
112
- std::lock_guard<Sync> lock (sync) ;
113
- ESP_RETURN_ON_ERROR (rpc. send (api_id::WIFI_EVENT, &id ), TAG, " Failed to marshall WiFi event" );
154
+ Events ev{api_id::WIFI_EVENT, id, nullptr } ;
155
+ ESP_RETURN_ON_ERROR (sync. put (ev ), TAG, " Failed to queue WiFi event" );
114
156
return ESP_OK;
115
157
}
116
158
esp_err_t ip_event (int32_t id, ip_event_got_ip_t *ip_data)
117
159
{
118
160
ESP_LOGI (TAG, " Received IP event %" PRIi32, id);
119
- esp_wifi_remote_eppp_ip_event ip_event{};
120
- ip_event.id = id;
161
+ Events ev{api_id::IP_EVENT, id, nullptr };
121
162
if (ip_data->esp_netif ) {
122
- // marshall additional data, only if netif available
123
- ESP_RETURN_ON_ERROR (esp_netif_get_dns_info (ip_data->esp_netif , ESP_NETIF_DNS_MAIN, &ip_event.dns ), TAG, " Failed to get DNS info" );
124
- ESP_LOGI (TAG, " Main DNS:" IPSTR, IP2STR (&ip_event.dns .ip .u_addr .ip4 ));
125
- memcpy (&ip_event.wifi_ip , &ip_data->ip_info , sizeof (ip_event.wifi_ip ));
126
- ESP_RETURN_ON_ERROR (esp_netif_get_ip_info (netif, &ip_event.ppp_ip ), TAG, " Failed to get IP info" );
163
+ ESP_RETURN_ON_ERROR (ev.create_ip_data (), TAG, " Failed to allocate event data" );
164
+ ev.ip_data ->id = id;
165
+ ESP_RETURN_ON_ERROR (esp_netif_get_dns_info (ip_data->esp_netif , ESP_NETIF_DNS_MAIN, &ev.ip_data ->dns ), TAG, " Failed to get DNS info" );
166
+ ESP_LOGI (TAG, " Main DNS:" IPSTR, IP2STR (&ev.ip_data ->dns .ip .u_addr .ip4 ));
167
+ memcpy (&ev.ip_data ->wifi_ip , &ip_data->ip_info , sizeof (ev.ip_data ->wifi_ip ));
168
+ ESP_RETURN_ON_ERROR (esp_netif_get_ip_info (netif, &ev.ip_data ->ppp_ip ), TAG, " Failed to get IP info" );
127
169
ESP_LOGI (TAG, " IP address:" IPSTR, IP2STR (&ip_data->ip_info .ip ));
128
170
}
129
- std::lock_guard<Sync> lock (sync);
130
- ESP_RETURN_ON_ERROR (rpc.send (api_id::IP_EVENT, &ip_event), TAG, " Failed to marshal IP event" );
171
+ ESP_RETURN_ON_ERROR (sync.put (ev), TAG, " Failed to queue IP event" );
131
172
return ESP_OK;
132
173
}
133
174
static void handler (void *ctx, esp_event_base_t base, int32_t id, void *data)
@@ -140,11 +181,83 @@ class RpcInstance {
140
181
instance->ip_event (id, ip_data);
141
182
}
142
183
}
184
+ int select ()
185
+ {
186
+ struct timeval timeout = { .tv_sec = 1 , .tv_usec = 0 };
187
+ int rpc_sock = rpc.get_socket_fd ();
188
+
189
+ ESP_RETURN_ON_FALSE (rpc_sock != -1 , Sync::ERROR, TAG, " failed ot get rpc socket" );
190
+ fd_set readset;
191
+ fd_set errset;
192
+ FD_ZERO (&readset);
193
+ FD_ZERO (&errset);
194
+ FD_SET (rpc_sock, &readset);
195
+ FD_SET (sync.fd , &readset);
196
+ FD_SET (rpc_sock, &errset);
197
+ int ret = ::select (std::max (rpc_sock, 5 ) + 1 , &readset, nullptr , &errset, &timeout);
198
+ if (ret == 0 ) {
199
+ ESP_LOGV (TAG, " poll_read: select - Timeout before any socket was ready!" );
200
+ return Sync::NONE;
201
+ }
202
+ if (ret < 0 ) {
203
+ ESP_LOGE (TAG, " select error: %d" , errno);
204
+ return Sync::ERROR;
205
+ }
206
+ if (FD_ISSET (rpc_sock, &errset)) {
207
+ int sock_errno = 0 ;
208
+ uint32_t optlen = sizeof (sock_errno);
209
+ getsockopt (rpc_sock, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen);
210
+ ESP_LOGE (TAG, " select failed, socket errno = %d" , sock_errno);
211
+ return Sync::ERROR;
212
+ }
213
+ int result = Sync::NONE;
214
+ if (FD_ISSET (rpc_sock, &readset)) {
215
+ result |= Sync::RPC;
216
+ }
217
+ if (FD_ISSET (sync.fd , &readset)) {
218
+ result |= Sync::EVENT;
219
+ }
220
+ return result;
221
+ }
222
+ esp_err_t marshall_events ()
223
+ {
224
+ api_id type;
225
+ do {
226
+ Events ev = sync.get ();
227
+ type = ev.type ;
228
+ if (ev.type == api_id::WIFI_EVENT) {
229
+ ESP_RETURN_ON_ERROR (rpc.send (api_id::WIFI_EVENT, &ev.id ), TAG, " Failed to marshall WiFi event" );
230
+ } else if (ev.type == api_id::IP_EVENT && ev.ip_data ) {
231
+ ESP_RETURN_ON_ERROR (rpc.send (api_id::IP_EVENT, ev.ip_data ), TAG, " Failed to marshal IP event" );
232
+ }
233
+ } while (type != api_id::ERROR);
234
+ return ESP_OK;
235
+ }
143
236
esp_err_t perform ()
237
+ {
238
+ auto res = select ();
239
+ if (res == Sync::ERROR) {
240
+ return ESP_FAIL;
241
+ }
242
+ if (res & Sync::EVENT) {
243
+ uint64_t data;
244
+ read (sync.fd , &data, sizeof (data));
245
+ if (marshall_events () != ESP_OK) {
246
+ return ESP_FAIL;
247
+ }
248
+ }
249
+ if (res & Sync::RPC) {
250
+ if (handle_commands () != ESP_OK) {
251
+ return ESP_FAIL;
252
+ }
253
+ }
254
+ return ESP_OK;
255
+ }
256
+
257
+ esp_err_t handle_commands ()
144
258
{
145
259
auto header = rpc.get_header ();
146
260
ESP_LOGI (TAG, " Received header id %d" , (int ) header.id );
147
- std::lock_guard<Sync> lock (sync);
148
261
switch (header.id ) {
149
262
case api_id::SET_MODE: {
150
263
auto req = rpc.get_payload <wifi_mode_t >(api_id::SET_MODE, header);
0 commit comments