3838#define PORT_REPLY_SIZE (TUPLE_SIZE(2) + REF_SIZE)
3939
4040static const char * const ap_atom = ATOM_STR ("\x2" , "ap" );
41+ static const char * const ap_sta_connected_atom = ATOM_STR ("\x10" , "ap_sta_connected" );
42+ static const char * const ap_sta_disconnected_atom = ATOM_STR ("\x13" , "ap_sta_disconnected" );
43+ static const char * const ap_started_atom = ATOM_STR ("\xA" , "ap_started" );
4144static const char * const psk_atom = ATOM_STR ("\x3" , "psk" );
4245static const char * const ssid_atom = ATOM_STR ("\x4" , "ssid" );
4346static const char * const sta_atom = ATOM_STR ("\x3" , "sta" );
@@ -63,13 +66,16 @@ struct NetworkDriverData
6366 uint32_t owner_process_id ;
6467 uint64_t ref_ticks ;
6568 int link_status ;
69+ int stas_count ;
70+ uint8_t * stas_mac ;
6671};
6772
6873// Callbacks do not allow for user data
6974// netif->state is actually pointing to &cyw43_state
7075static struct NetworkDriverData * driver_data ;
7176
7277static void network_driver_netif_status_cb (struct netif * netif );
78+ static void network_driver_cyw43_assoc_cb (bool assoc );
7379
7480static term tuple_from_addr (Heap * heap , uint32_t addr )
7581{
@@ -129,6 +135,38 @@ static void send_got_ip(struct netif *netif)
129135 END_WITH_STACK_HEAP (heap , driver_data -> global );
130136}
131137
138+ static void send_ap_started ()
139+ {
140+ // {Ref, ap_started}
141+ BEGIN_WITH_STACK_HEAP (PORT_REPLY_SIZE , heap );
142+ {
143+ send_term (& heap , globalcontext_make_atom (driver_data -> global , ap_started_atom ));
144+ }
145+ END_WITH_STACK_HEAP (heap , driver_data -> global );
146+ }
147+
148+ static void send_atom_mac (term atom , uint8_t * mac )
149+ {
150+ // {Ref, {ap_connected | ap_disconnected, <<1,2,3,4,5,6>>}}
151+ BEGIN_WITH_STACK_HEAP (PORT_REPLY_SIZE + TUPLE_SIZE (2 ) + TERM_BINARY_HEAP_SIZE (6 ), heap );
152+ {
153+ term mac_term = term_from_literal_binary (mac , 6 , & heap , driver_data -> global );
154+ term reply = port_heap_create_tuple2 (& heap , atom , mac_term );
155+ send_term (& heap , reply );
156+ }
157+ END_WITH_STACK_HEAP (heap , driver_data -> global );
158+ }
159+
160+ static void send_ap_sta_connected (uint8_t * mac )
161+ {
162+ send_atom_mac (globalcontext_make_atom (driver_data -> global , ap_sta_connected_atom ), mac );
163+ }
164+
165+ static void send_ap_sta_disconnected (uint8_t * mac )
166+ {
167+ send_atom_mac (globalcontext_make_atom (driver_data -> global , ap_sta_disconnected_atom ), mac );
168+ }
169+
132170static term start_sta (term sta_config , GlobalContext * global )
133171{
134172 term ssid_term = interop_kv_get_value (sta_config , ssid_atom , global );
@@ -171,32 +209,124 @@ static term start_sta(term sta_config, GlobalContext *global)
171209 return OK_ATOM ;
172210}
173211
174- static term start_ap ( term ap_config , GlobalContext * glb )
212+ static char * get_default_device_name ( )
175213{
176- UNUSED (ap_config );
177- UNUSED (glb );
178- return BADARG_ATOM ;
214+ uint8_t mac [6 ];
215+ int err = cyw43_wifi_get_mac (& cyw43_state , CYW43_ITF_STA , mac );
216+ if (err ) {
217+ return NULL ;
218+ }
219+
220+ size_t buf_size = strlen ("atomvm-" ) + 12 + 1 ;
221+ char * buf = malloc (buf_size );
222+ if (IS_NULL_PTR (buf )) {
223+ return NULL ;
224+ }
225+ snprintf (buf , buf_size ,
226+ "atomvm-%02x%02x%02x%02x%02x%02x" , mac [0 ], mac [1 ], mac [2 ], mac [3 ], mac [4 ], mac [5 ]);
227+ return buf ;
179228}
180229
181- static void network_driver_netif_status_cb ( struct netif * netif )
230+ static void network_driver_cyw43_assoc_cb ( bool assoc )
182231{
183- if (netif == & cyw43_state .netif [CYW43_ITF_STA ]) {
184- // We don't really need to lock to call cyw43_tcpip_link_status
185- // However, we take advantage of this lock to protect driver_data->link_status.
186- cyw43_arch_lwip_begin ();
187- int link_status = cyw43_tcpip_link_status (& cyw43_state , CYW43_ITF_STA );
188- int previous_link_status = driver_data -> link_status ;
189- driver_data -> link_status = link_status ;
190- cyw43_arch_lwip_end ();
191- if (link_status != previous_link_status ) {
192- if (link_status == CYW43_LINK_DOWN ) {
193- send_sta_disconnected ();
194- } else if (link_status == CYW43_LINK_JOIN ) {
195- send_sta_connected ();
196- } else if (link_status == CYW43_LINK_UP ) {
197- send_got_ip (netif );
232+ UNUSED (assoc );
233+
234+ int max_stas ;
235+ cyw43_wifi_ap_get_max_stas (& cyw43_state , & max_stas );
236+ uint8_t * new_macs = malloc (6 * max_stas );
237+ int nb_stas ;
238+ cyw43_wifi_ap_get_stas (& cyw43_state , & nb_stas , new_macs );
239+ // Determine new macs.
240+ for (int i = 0 ; i < nb_stas ; i ++ ) {
241+ bool new_mac = true;
242+ for (int j = 0 ; j < driver_data -> stas_count ; j ++ ) {
243+ if (memcmp (& driver_data -> stas_mac [6 * j ], & new_macs [6 * i ], 6 ) == 0 ) {
244+ new_mac = false;
245+ break ;
198246 }
199247 }
248+ if (new_mac ) {
249+ send_ap_sta_connected (& new_macs [6 * i ]);
250+ }
251+ }
252+ // Determine old macs
253+ for (int j = 0 ; j < driver_data -> stas_count ; j ++ ) {
254+ bool old_mac = true;
255+ for (int i = 0 ; i < nb_stas ; i ++ ) {
256+ if (memcmp (& driver_data -> stas_mac [6 * j ], & new_macs [6 * i ], 6 ) == 0 ) {
257+ old_mac = false;
258+ break ;
259+ }
260+ }
261+ if (old_mac ) {
262+ send_ap_sta_disconnected (& driver_data -> stas_mac [6 * j ]);
263+ }
264+ }
265+ free (driver_data -> stas_mac );
266+ new_macs = realloc (new_macs , 6 * nb_stas );
267+ driver_data -> stas_mac = new_macs ;
268+ driver_data -> stas_count = nb_stas ;
269+ }
270+
271+ static term start_ap (term ap_config , GlobalContext * global )
272+ {
273+ term ssid_term = interop_kv_get_value (ap_config , ssid_atom , global );
274+ term pass_term = interop_kv_get_value (ap_config , psk_atom , global );
275+
276+ //
277+ // Check parameters
278+ //
279+ char * ssid = NULL ;
280+ if (term_is_invalid_term (ssid_term )) {
281+ ssid = get_default_device_name ();
282+ } else {
283+ int ok = 0 ;
284+ ssid = interop_term_to_string (ssid_term , & ok );
285+ if (!ok || IS_NULL_PTR (ssid )) {
286+ return BADARG_ATOM ;
287+ }
288+ }
289+ char * psk = NULL ;
290+ if (!term_is_invalid_term (pass_term )) {
291+ int ok = 0 ;
292+ psk = interop_term_to_string (pass_term , & ok );
293+ if (strlen (psk ) < 8 ) {
294+ free (ssid );
295+ return BADARG_ATOM ;
296+ }
297+ if (!ok ) {
298+ free (ssid );
299+ return BADARG_ATOM ;
300+ }
301+ }
302+
303+ uint32_t auth = (psk == NULL ) ? CYW43_AUTH_OPEN : CYW43_AUTH_WPA2_AES_PSK ;
304+ cyw43_state .assoc_cb = network_driver_cyw43_assoc_cb ;
305+ cyw43_arch_enable_ap_mode (ssid , psk , auth );
306+ send_ap_started ();
307+ free (ssid );
308+ free (psk );
309+
310+ return OK_ATOM ;
311+ }
312+
313+ static void network_driver_netif_status_cb (struct netif * netif )
314+ {
315+ // We don't really need to lock to call cyw43_tcpip_link_status
316+ // However, we take advantage of this lock to protect driver_data->link_status.
317+ cyw43_arch_lwip_begin ();
318+ int link_status = cyw43_tcpip_link_status (& cyw43_state , CYW43_ITF_STA );
319+ int previous_link_status = driver_data -> link_status ;
320+ driver_data -> link_status = link_status ;
321+ cyw43_arch_lwip_end ();
322+ if (link_status != previous_link_status ) {
323+ if (link_status == CYW43_LINK_DOWN ) {
324+ send_sta_disconnected ();
325+ } else if (link_status == CYW43_LINK_JOIN ) {
326+ send_sta_connected ();
327+ } else if (link_status == CYW43_LINK_UP ) {
328+ send_got_ip (netif );
329+ }
200330 }
201331}
202332
@@ -210,11 +340,15 @@ static void start_network(Context *ctx, term pid, term ref, term config)
210340
211341 if (driver_data == NULL ) {
212342 driver_data = malloc (sizeof (struct NetworkDriverData ));
343+ driver_data -> stas_mac = NULL ;
213344 }
214345 driver_data -> global = ctx -> global ;
215346 driver_data -> owner_process_id = term_to_local_process_id (pid );
216347 driver_data -> ref_ticks = term_to_ref_ticks (ref );
217348 driver_data -> link_status = CYW43_LINK_DOWN ;
349+ free (driver_data -> stas_mac );
350+ driver_data -> stas_count = 0 ;
351+ driver_data -> stas_mac = NULL ;
218352
219353 //
220354 // Get the STA and AP config, if set
@@ -317,6 +451,9 @@ void network_driver_destroy(GlobalContext *global)
317451{
318452 UNUSED (global );
319453
454+ if (driver_data ) {
455+ free (driver_data -> stas_mac );
456+ }
320457 free (driver_data );
321458 driver_data = NULL ;
322459}
0 commit comments