55#include "ui.h"
66#include "../input.h"
77#include "helper.h"
8+ #include "executor.h"
89#include "styles.h"
910#include "executor.h"
1011#include "gs_wifi.h"
@@ -13,8 +14,131 @@ extern lv_obj_t * menu;
1314extern gsmenu_control_mode_t control_mode ;
1415extern lv_group_t * default_group ;
1516
17+ extern lv_obj_t * rx_mode ;
18+
19+ lv_obj_t * this_page ;
1620lv_obj_t * ap_fpv_ssid ;
1721lv_obj_t * ap_fpv_password ;
22+ lv_obj_t * reset_apfpv ;
23+ lv_obj_t * autoconnect_cont ;
24+
25+ static int adapter_count = 0 ;
26+
27+ #define MAX_DEVICES 32
28+ #define MAX_NAME_LENGTH 64
29+ #define MAX_PATH_LENGTH 256
30+
31+ typedef struct {
32+ char device_name [MAX_NAME_LENGTH ];
33+ char usb_port [MAX_NAME_LENGTH ];
34+ } NetworkDevice ;
35+
36+ int get_usb_port_udev (const char * device_name , char * usb_port , size_t port_size ) {
37+ char cmd [256 ];
38+ snprintf (cmd , sizeof (cmd ),
39+ "udevadm info -q path /sys/class/net/%s 2>/dev/null | grep -o 'usb[0-9]*/.*' | head -1" ,
40+ device_name );
41+
42+ char * result = run_command (cmd );
43+ if (result == NULL || strlen (result ) == 0 ) {
44+ free (result );
45+ return -1 ;
46+ }
47+
48+ // Remove newline and extract relevant portion
49+ result [strcspn (result , "\n" )] = '\0' ;
50+
51+ // Find the USB port part (typically after usbX/)
52+ char * usb_part = strstr (result , "usb" );
53+ if (usb_part != NULL ) {
54+ char * port_part = strchr (usb_part , '/' );
55+ if (port_part != NULL ) {
56+ port_part ++ ; // Move past the slash
57+
58+ // Copy up to next slash or end of string
59+ char * next_slash = strchr (port_part , '/' );
60+ if (next_slash != NULL ) {
61+ size_t len = next_slash - port_part ;
62+ if (len < port_size ) {
63+ strncpy (usb_port , port_part , len );
64+ usb_port [len ] = '\0' ;
65+ free (result );
66+ return 0 ;
67+ }
68+ } else {
69+ // No more slashes, use the remaining string
70+ if (strlen (port_part ) < port_size ) {
71+ strcpy (usb_port , port_part );
72+ free (result );
73+ return 0 ;
74+ }
75+ }
76+ }
77+ }
78+
79+ free (result );
80+ return -1 ;
81+ }
82+
83+ // Main function to get the list of network devices with USB ports
84+ NetworkDevice * get_wireless_devices (int * count ) {
85+ NetworkDevice * devices = malloc (MAX_DEVICES * sizeof (NetworkDevice ));
86+ if (devices == NULL ) {
87+ * count = 0 ;
88+ return NULL ;
89+ }
90+
91+ // Get wireless device names using ip command
92+ char * ip_output = run_command ("ip -o link show | awk -F': ' '{print $2}' | grep '^wlx'" );
93+ if (ip_output == NULL ) {
94+ * count = 0 ;
95+ free (devices );
96+ return NULL ;
97+ }
98+
99+ * count = 0 ;
100+ char * line = ip_output ;
101+ char * next_line ;
102+
103+ while (* count < MAX_DEVICES && (next_line = strchr (line , '\n' )) != NULL ) {
104+ // Extract device name
105+ size_t name_len = next_line - line ;
106+ if (name_len > 0 && name_len < MAX_NAME_LENGTH ) {
107+ strncpy (devices [* count ].device_name , line , name_len );
108+ devices [* count ].device_name [name_len ] = '\0' ;
109+
110+ // Remove trailing whitespace
111+ devices [* count ].device_name [strcspn (devices [* count ].device_name , " \t\n" )] = '\0' ;
112+
113+ // Get USB port information
114+ devices [* count ].usb_port [0 ] = '\0' ;
115+
116+ // Try udev method first
117+ get_usb_port_udev (devices [* count ].device_name ,
118+ devices [* count ].usb_port ,
119+ MAX_NAME_LENGTH );
120+
121+ (* count )++ ;
122+ }
123+
124+ line = next_line + 1 ;
125+ }
126+
127+ free (ip_output );
128+ return devices ;
129+ }
130+
131+ // Example usage and cleanup function
132+ void free_devices (NetworkDevice * devices ) {
133+ free (devices );
134+ }
135+
136+ void focus_label (lv_event_t * e )
137+ {
138+ lv_obj_t * obj = lv_event_get_current_target (e );
139+ lv_obj_t * label = lv_event_get_user_data (e );
140+ lv_obj_scroll_to_view_recursive (label , LV_ANIM_ON );
141+ }
18142
19143static void btn_event_cb (lv_event_t * e )
20144{
@@ -78,18 +202,104 @@ static void kb_event_cb(lv_event_t * e)
78202 }
79203}
80204
205+ void checkbox_event_cb (void )
206+ {
207+ generic_page_load_callback (this_page );
208+ }
209+
210+ void apfpv_page_load_callback (lv_obj_t * page ) {
211+
212+ this_page = page ;
213+ menu_page_data_t * menu_page_data = lv_obj_get_user_data (page );
214+ PageEntry * entries = menu_page_data -> page_entries ;
215+
216+ if (adapter_count == 0 ) {
217+ NetworkDevice * devices = get_wireless_devices (& adapter_count );
218+
219+ if (devices == NULL ) {
220+ printf ("Failed to get device list\n" );
221+ }
222+
223+ printf ("Found %d wireless devices:\n" , adapter_count );
224+ for (int i = 0 ; i < adapter_count ; i ++ ) {
225+ printf ("Device: %s -> USB Port: %s\n" ,
226+ devices [i ].device_name ,
227+ devices [i ].usb_port [0 ] ? devices [i ].usb_port : "Unknown" );
228+ lv_group_set_default (menu_page_data -> indev_group );
229+
230+ // Create dynamic strings
231+ char checkbox_label [128 ];
232+ char loading_text [128 ];
233+ char param_text [128 ];
234+
235+ snprintf (checkbox_label , sizeof (checkbox_label ), "Device: %s USB: %s" ,
236+ devices [i ].device_name ,
237+ devices [i ].usb_port [0 ] ? devices [i ].usb_port : "Unknown" );
238+
239+ snprintf (loading_text , sizeof (loading_text ), "Loading device %s..." ,
240+ devices [i ].device_name );
241+
242+ snprintf (param_text , sizeof (param_text ), "status %s" ,
243+ devices [i ].device_name );
244+
245+ lv_obj_t * adapter = create_checkbox (autoconnect_cont , LV_SYMBOL_WIFI , checkbox_label , devices [i ].device_name , menu_page_data , false);
246+ thread_data_t * data = lv_obj_get_user_data (lv_obj_get_child_by_type (adapter ,0 ,& lv_checkbox_class ));
247+ data -> callback_fn = checkbox_event_cb ;
248+ lv_obj_t * adapter_status = create_text (autoconnect_cont , LV_SYMBOL_SETTINGS , "Status" , param_text , menu_page_data , false, LV_MENU_ITEM_BUILDER_VARIANT_1 );
249+
250+ lv_obj_add_event_cb (lv_obj_get_child_by_type (adapter ,0 ,& lv_checkbox_class ), focus_label , LV_EVENT_FOCUSED , adapter_status );
251+
252+ add_entry_to_menu_page (menu_page_data , loading_text , adapter , reload_checkbox_value );
253+ add_entry_to_menu_page (menu_page_data , loading_text , adapter_status , reload_label_value );
254+
255+ lv_group_set_default (default_group );
256+ }
257+
258+ free_devices (devices );
259+
260+ }
261+
262+ generic_page_load_callback (page );
263+ }
264+
265+ void gs_actions_reset_apfpv (lv_event_t * event )
266+ {
267+ lv_textarea_set_text (lv_obj_get_child_by_type (ap_fpv_ssid ,0 ,& lv_textarea_class ),"OpenIPC" );
268+ lv_textarea_set_text (lv_obj_get_child_by_type (ap_fpv_password ,0 ,& lv_textarea_class ),"12345678" );
269+ run_command_and_block (event ,"gsmenu.sh set gs apfpv reset" ,NULL );
270+ lv_obj_send_event (lv_obj_get_child_by_type (rx_mode ,0 ,& lv_dropdown_class ),LV_EVENT_VALUE_CHANGED ,NULL );
271+
272+ int child_count = lv_obj_get_child_count (autoconnect_cont );
273+ for (int i = child_count - 1 ; i >= 0 ; i -- ) {
274+ lv_obj_t * child = lv_obj_get_child (autoconnect_cont , i );
275+ int grand_child_count = lv_obj_get_child_count (child );
276+
277+ for (int j = grand_child_count - 1 ; j >= 0 ; j -- ) {
278+ lv_obj_t * grand_child = lv_obj_get_child (child , j );
279+ thread_data_t * user_data = lv_obj_get_user_data (grand_child );
280+
281+ if (user_data != NULL ) {
282+ delete_menu_page_entry_by_obj (user_data -> menu_page_data ,child );
283+ }
284+ }
285+ lv_obj_del (child );
286+ }
287+ adapter_count = 0 ;
288+ }
289+
81290void create_apfpv_menu (lv_obj_t * parent ) {
82291
83292 menu_page_data_t * menu_page_data = malloc (sizeof (menu_page_data_t ));
84293 strcpy (menu_page_data -> type , "gs" );
85294 strcpy (menu_page_data -> page , "apfpv" );
86- menu_page_data -> page_load_callback = generic_page_load_callback ;
295+ menu_page_data -> page_load_callback = apfpv_page_load_callback ;
87296 menu_page_data -> indev_group = lv_group_create ();
88297 menu_page_data -> entry_count = 0 ;
89298 menu_page_data -> page_entries = NULL ;
90299 lv_group_set_default (menu_page_data -> indev_group );
91300 lv_obj_set_user_data (parent ,menu_page_data );
92301
302+ create_text (parent , NULL , "Connection Settings" , NULL , NULL , false, LV_MENU_ITEM_BUILDER_VARIANT_1 );
93303 lv_obj_t * section = lv_menu_section_create (parent );
94304 lv_obj_add_style (section , & style_openipc_section , 0 );
95305
@@ -99,6 +309,9 @@ void create_apfpv_menu(lv_obj_t * parent) {
99309 ap_fpv_ssid = create_textarea (cont , "" , "SSID" , "ssid" , menu_page_data , false);
100310 ap_fpv_password = create_textarea (cont , "" , "Password" , "password" , menu_page_data , true);
101311
312+ reset_apfpv = create_button (section , "Reset APFPV" );
313+ lv_obj_add_event_cb (lv_obj_get_child_by_type (reset_apfpv ,0 ,& lv_button_class ),gs_actions_reset_apfpv ,LV_EVENT_CLICKED ,NULL );
314+
102315 lv_obj_t * kb = lv_keyboard_create (lv_obj_get_parent (section ));
103316 lv_obj_add_flag (kb , LV_OBJ_FLAG_SCROLL_ON_FOCUS );
104317 lv_obj_add_flag (kb , LV_OBJ_FLAG_HIDDEN );
@@ -113,6 +326,12 @@ void create_apfpv_menu(lv_obj_t * parent) {
113326 lv_obj_add_event_cb (kb , kb_event_cb , LV_EVENT_ALL ,kb );
114327 lv_keyboard_set_textarea (kb , NULL );
115328
329+ create_text (parent , NULL , "Autoconnect" , NULL , NULL , false, LV_MENU_ITEM_BUILDER_VARIANT_1 );
330+ section = lv_menu_section_create (parent );
331+ lv_obj_add_style (section , & style_openipc_section , 0 );
332+ autoconnect_cont = lv_menu_cont_create (section );
333+ lv_obj_set_flex_flow (autoconnect_cont , LV_FLEX_FLOW_COLUMN );
334+
116335 add_entry_to_menu_page (menu_page_data ,"Loading SSID ..." , ap_fpv_ssid , reload_textarea_value );
117336 add_entry_to_menu_page (menu_page_data ,"Loading Password ..." , ap_fpv_password , reload_textarea_value );
118337
0 commit comments