ohmu
·
2026-10-15
1#include "common/printing.h"
2#include "common/jsonconfig.h"
3#include "common/strutil.h"
4#include "detection/wifi/wifi.h"
5#include "modules/wifi/wifi.h"
6
7bool ffPrintWifi(FFWifiOptions* options) {
8 FF_LIST_AUTO_DESTROY result = ffListCreate();
9
10 const char* error = ffDetectWifi(&result);
11 if (error) {
12 ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Wifi), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "%s", error);
13 return false;
14 }
15 if (!result.length) {
16 ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Wifi), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "No Wifi interfaces found");
17 return false;
18 }
19
20 FFPercentageTypeFlags percentType = options->percent.type == 0 ? instance.config.display.percentType : options->percent.type;
21
22 for (uint32_t index = 0; index < result.length; ++index) {
23 FFWifiResult* item = FF_LIST_GET(FFWifiResult, result, index);
24 uint8_t moduleIndex = result.length == 1 ? 0 : (uint8_t) (index + 1);
25
26 // https://en.wikipedia.org/wiki/List_of_WLAN_channels
27 char bandStr[8];
28 if (item->conn.frequency > 58000) {
29 strcpy(bandStr, "60");
30 } else if (item->conn.frequency > 40000) {
31 strcpy(bandStr, "45");
32 } else if (item->conn.frequency > 5900) {
33 strcpy(bandStr, "6");
34 } else if (item->conn.frequency > 5100) {
35 strcpy(bandStr, "5");
36 } else if (item->conn.frequency > 4900) {
37 strcpy(bandStr, "4.9");
38 } else if (item->conn.frequency > 3600) {
39 strcpy(bandStr, "3.65");
40 } else if (item->conn.frequency > 2000) {
41 strcpy(bandStr, "2.4");
42 } else if (item->conn.frequency > 800) {
43 strcpy(bandStr, "0.9");
44 } else {
45 bandStr[0] = '\0';
46 }
47
48 if (options->moduleArgs.outputFormat.length == 0) {
49 ffPrintLogoAndKey(FF_MODULE_GET_DISPLAY_NAME(Wifi), moduleIndex, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT);
50
51 FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
52 if (item->conn.ssid.length) {
53 if (item->conn.signalQuality != -DBL_MAX) {
54 if (percentType & FF_PERCENTAGE_TYPE_BAR_BIT) {
55 ffPercentAppendBar(&buffer, item->conn.signalQuality, options->percent, &options->moduleArgs);
56 ffStrbufAppendC(&buffer, ' ');
57 }
58 }
59
60 if (!(percentType & FF_PERCENTAGE_TYPE_HIDE_OTHERS_BIT)) {
61 ffStrbufAppend(&buffer, &item->conn.ssid);
62
63 if (item->conn.protocol.length) {
64 ffStrbufAppendS(&buffer, " - ");
65 ffStrbufAppend(&buffer, &item->conn.protocol);
66 }
67 if (bandStr[0]) {
68 ffStrbufAppendF(&buffer, " - %s%sGHz", bandStr, instance.config.display.freqSpaceBeforeUnit == FF_SPACE_BEFORE_UNIT_NEVER ? "" : " ");
69 }
70 if (item->conn.security.length) {
71 ffStrbufAppendS(&buffer, " - ");
72 ffStrbufAppend(&buffer, &item->conn.security);
73 }
74 ffStrbufAppendC(&buffer, ' ');
75 }
76
77 if (item->conn.signalQuality != -DBL_MAX) {
78 if (percentType & FF_PERCENTAGE_TYPE_NUM_BIT) {
79 ffPercentAppendNum(&buffer, item->conn.signalQuality, options->percent, buffer.length > 0, &options->moduleArgs);
80 }
81 }
82
83 ffStrbufTrimRight(&buffer, ' ');
84 } else {
85 ffStrbufAppend(&buffer, &item->inf.status);
86 }
87 ffStrbufPutTo(&buffer, stdout);
88 } else {
89 FF_STRBUF_AUTO_DESTROY percentNum = ffStrbufCreate();
90 if (percentType & FF_PERCENTAGE_TYPE_NUM_BIT) {
91 ffPercentAppendNum(&percentNum, item->conn.signalQuality, options->percent, false, &options->moduleArgs);
92 }
93 FF_STRBUF_AUTO_DESTROY percentBar = ffStrbufCreate();
94 if (percentType & FF_PERCENTAGE_TYPE_BAR_BIT) {
95 ffPercentAppendBar(&percentBar, item->conn.signalQuality, options->percent, &options->moduleArgs);
96 }
97
98 FF_PRINT_FORMAT_CHECKED(FF_MODULE_GET_DISPLAY_NAME(Wifi), moduleIndex, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, ((FFformatarg[]) {
99 FF_ARG(item->inf.description, "inf-desc"),
100 FF_ARG(item->inf.status, "inf-status"),
101 FF_ARG(item->conn.status, "status"),
102 FF_ARG(item->conn.ssid, "ssid"),
103 FF_ARG(item->conn.bssid, "bssid"),
104 FF_ARG(item->conn.protocol, "protocol"),
105 FF_ARG(percentNum, "signal-quality"),
106 FF_ARG(item->conn.rxRate, "rx-rate"),
107 FF_ARG(item->conn.txRate, "tx-rate"),
108 FF_ARG(item->conn.security, "security"),
109 FF_ARG(percentBar, "signal-quality-bar"),
110 FF_ARG(item->conn.channel, "channel"),
111 FF_ARG(item->conn.channelWidth, "channel-width"),
112 FF_ARG(bandStr, "band"),
113 }));
114 }
115 }
116
117 FF_LIST_FOR_EACH (FFWifiResult, item, result) {
118 ffStrbufDestroy(&item->inf.description);
119 ffStrbufDestroy(&item->inf.status);
120 ffStrbufDestroy(&item->conn.status);
121 ffStrbufDestroy(&item->conn.ssid);
122 ffStrbufDestroy(&item->conn.bssid);
123 ffStrbufDestroy(&item->conn.protocol);
124 ffStrbufDestroy(&item->conn.security);
125 }
126
127 return true;
128}
129
130void ffParseWifiJsonObject(FFWifiOptions* options, yyjson_val* module) {
131 yyjson_val *key, *val;
132 size_t idx, max;
133 yyjson_obj_foreach (module, idx, max, key, val) {
134 if (ffJsonConfigParseModuleArgs(key, val, &options->moduleArgs)) {
135 continue;
136 }
137
138 if (ffPercentParseJsonObject(key, val, &options->percent)) {
139 continue;
140 }
141
142 ffPrintError(FF_MODULE_GET_DISPLAY_NAME(Wifi), 0, &options->moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown JSON key %s", unsafe_yyjson_get_str(key));
143 }
144}
145
146[[gnu::cold]]
147void ffGenerateWifiJsonConfig(FFWifiOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
148 ffJsonConfigGenerateModuleArgsConfig(doc, module, &options->moduleArgs);
149
150 ffPercentGenerateJsonConfig(doc, module, options->percent);
151}
152
153bool ffGenerateWifiJsonResult([[maybe_unused]] FFWifiOptions* options, yyjson_mut_doc* doc, yyjson_mut_val* module) {
154 FF_LIST_AUTO_DESTROY result = ffListCreate();
155 const char* error = ffDetectWifi(&result);
156 if (error) {
157 yyjson_mut_obj_add_str(doc, module, "error", error);
158 return false;
159 }
160
161 yyjson_mut_val* arr = yyjson_mut_obj_add_arr(doc, module, "result");
162 FF_LIST_FOR_EACH (FFWifiResult, wifi, result) {
163 yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
164
165 yyjson_mut_val* inf = yyjson_mut_obj_add_obj(doc, obj, "inf");
166 yyjson_mut_obj_add_strbuf(doc, inf, "description", &wifi->inf.description);
167 yyjson_mut_obj_add_strbuf(doc, inf, "status", &wifi->inf.status);
168
169 yyjson_mut_val* conn = yyjson_mut_obj_add_obj(doc, obj, "conn");
170 yyjson_mut_obj_add_strbuf(doc, conn, "status", &wifi->conn.status);
171 yyjson_mut_obj_add_strbuf(doc, conn, "ssid", &wifi->conn.ssid);
172 yyjson_mut_obj_add_strbuf(doc, conn, "bssid", &wifi->conn.bssid);
173 yyjson_mut_obj_add_strbuf(doc, conn, "protocol", &wifi->conn.protocol);
174 yyjson_mut_obj_add_strbuf(doc, conn, "security", &wifi->conn.security);
175 if (wifi->conn.signalQuality != -DBL_MAX) {
176 yyjson_mut_obj_add_real(doc, conn, "signalQuality", wifi->conn.signalQuality);
177 } else {
178 yyjson_mut_obj_add_null(doc, conn, "signalQuality");
179 }
180 if (wifi->conn.rxRate != -DBL_MAX) {
181 yyjson_mut_obj_add_real(doc, conn, "rxRate", wifi->conn.rxRate);
182 } else {
183 yyjson_mut_obj_add_null(doc, conn, "rxRate");
184 }
185 if (wifi->conn.txRate != -DBL_MAX) {
186 yyjson_mut_obj_add_real(doc, conn, "txRate", wifi->conn.txRate);
187 } else {
188 yyjson_mut_obj_add_null(doc, conn, "txRate");
189 }
190 yyjson_mut_obj_add_uint(doc, conn, "channel", wifi->conn.channel);
191 yyjson_mut_obj_add_uint(doc, conn, "channelWidth", wifi->conn.channelWidth);
192 yyjson_mut_obj_add_uint(doc, conn, "frequency", wifi->conn.frequency);
193 }
194
195 FF_LIST_FOR_EACH (FFWifiResult, item, result) {
196 ffStrbufDestroy(&item->inf.description);
197 ffStrbufDestroy(&item->inf.status);
198 ffStrbufDestroy(&item->conn.status);
199 ffStrbufDestroy(&item->conn.ssid);
200 ffStrbufDestroy(&item->conn.bssid);
201 ffStrbufDestroy(&item->conn.protocol);
202 ffStrbufDestroy(&item->conn.security);
203 }
204
205 return true;
206}
207
208void ffInitWifiOptions(FFWifiOptions* options) {
209 ffOptionInitModuleArg(&options->moduleArgs, "");
210
211 options->percent = (FFPercentageModuleConfig) { 75, 50, 0 };
212}
213
214void ffDestroyWifiOptions(FFWifiOptions* options) {
215 ffOptionDestroyModuleArg(&options->moduleArgs);
216}
217
218FFModuleBaseInfo ffWifiModuleInfo = {
219 .name = "Wifi",
220 .description = "Print connected Wi-Fi info (SSID, connection and security protocol)",
221 .displayName = {
222 .en = "Wi-Fi",
223 .ar = "واي فاي",
224 .cs = "Wi-Fi",
225 .de = "WLAN",
226 .es = "Wi-Fi",
227 .fi = "Wi-Fi",
228 .fr = "Wi-Fi",
229 .gl = "Wi-Fi",
230 .he = "Wi-Fi",
231 .id = "Wi-Fi",
232 .it = "Wi-Fi",
233 .ja = "Wi-Fi",
234 .ko = "와이파이",
235 .pl = "Wi-Fi",
236 .pt = "Wi-Fi",
237 .ru = "Wi-Fi",
238 .tr = "Wi-Fi",
239 .uk = "Wi-Fi",
240 .vi = "Wi-Fi",
241 .zh_CN = "无线网络",
242 .zh_TW = "無線網路",
243 },
244 .initOptions = (void*) ffInitWifiOptions,
245 .destroyOptions = (void*) ffDestroyWifiOptions,
246 .parseJsonObject = (void*) ffParseWifiJsonObject,
247 .printModule = (void*) ffPrintWifi,
248 .generateJsonResult = (void*) ffGenerateWifiJsonResult,
249 .generateJsonConfig = (void*) ffGenerateWifiJsonConfig,
250 .formatArgs = FF_FORMAT_ARG_LIST(((FFModuleFormatArg[]) {
251 { "Interface description", "inf-desc" },
252 { "Interface status", "inf-status" },
253 { "Connection status", "status" },
254 { "Connection SSID", "ssid" },
255 { "Connection BSSID", "bssid" },
256 { "Connection protocol", "protocol" },
257 { "Connection signal quality (percentage num)", "signal-quality" },
258 { "Connection RX rate", "rx-rate" },
259 { "Connection TX rate", "tx-rate" },
260 { "Connection Security algorithm", "security" },
261 { "Connection signal quality (percentage bar)", "signal-quality-bar" },
262 { "Connection channel number", "channel" },
263 { "Connection channel width in MHz", "channel-width" },
264 { "Connection channel band in GHz", "band" },
265 })),
266 .defaultOrder = 52,
267};