X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fprint_wireless_info.c;h=3a96b86f93b3d10147c49cace6105cf516dd99fb;hb=686b8798aa725eb5303d154c193e30766bd00094;hp=e5d38fb3c0ae1bed043a762ac2a81bb185607942;hpb=29e9a99f065137481dcab887971dae7e4a8c3e21;p=i3%2Fi3status diff --git a/src/print_wireless_info.c b/src/print_wireless_info.c index e5d38fb..3a96b86 100644 --- a/src/print_wireless_info.c +++ b/src/print_wireless_info.c @@ -1,9 +1,6 @@ // vim:ts=8:expandtab #include -#include #include -#include -#include #ifdef LINUX #include @@ -11,85 +8,151 @@ #include "i3status.h" -#ifdef LINUX -static int skfd = -1; +#define WIRELESS_INFO_FLAG_HAS_ESSID (1 << 0) +#define WIRELESS_INFO_FLAG_HAS_QUALITY (1 << 1) +#define WIRELESS_INFO_FLAG_HAS_SIGNAL (1 << 2) +#define WIRELESS_INFO_FLAG_HAS_NOISE (1 << 3) + +#define PERCENT_VALUE(value, total) ((int)(value * 100 / (float)total + 0.5f)) + +typedef struct { + int flags; + char essid[IW_ESSID_MAX_SIZE + 1]; + int quality; + int quality_max; + int quality_average; + int signal_level; + int signal_level_max; + int noise_level; + int noise_level_max; + int bitrate; +} wireless_info_t; + +static int get_wireless_info(const char *interface, wireless_info_t *info) { + memset(info, 0, sizeof(wireless_info_t)); -static int open_skfd() { - if (skfd == -1) { - skfd = iw_sockets_open(); +#ifdef LINUX + int skfd = iw_sockets_open(); if (skfd < 0) { - perror("iw_sockets_open"); + perror("iw_sockets_open"); + return 0; + } + + wireless_config wcfg; + if (iw_get_basic_config(skfd, interface, &wcfg) < 0) { + close(skfd); return 0; } - } - return -1; -} -static void close_skfd() { - if (skfd != -1) { - close(skfd); - skfd = -1; - } -} -#endif + if (wcfg.has_essid && wcfg.essid_on) { + info->flags |= WIRELESS_INFO_FLAG_HAS_ESSID; + strncpy(&info->essid[0], wcfg.essid, IW_ESSID_MAX_SIZE); + info->essid[IW_ESSID_MAX_SIZE] = '\0'; + } -const char *get_wireless_essid(const char *interface) { - static char part[512]; - part[0] = '\0'; -#ifdef LINUX - if (open_skfd()) { - wireless_config wcfg; - if (iw_get_basic_config(skfd, interface, &wcfg) >= 0) - snprintf(part, sizeof(part), "%s", wcfg.essid); - } -#endif - return part; -} + /* Wireless quality is a relative value in a driver-specific range. + Signal and noise level can be either relative or absolute values + in dBm. Furthermore, noise and quality can be expressed directly + in dBm or in RCPI (802.11k), which we convert to dBm. When those + values are expressed directly in dBm, they range from -192 to 63, + and since the values are packed into 8 bits, we need to perform + 8-bit arithmetic on them. Assume absolute values if everything + else fails (driver bug). */ -int get_wireless_quality_max(const char *interface) { -#ifdef LINUX - if (open_skfd()) { iwrange range; - if (iw_get_range_info(skfd, interface, &range) >= 0) - return range.max_qual.qual; - } + if (iw_get_range_info(skfd, interface, &range) < 0) { + close(skfd); + return 0; + } + + iwstats stats; + if (iw_get_stats(skfd, interface, &stats, &range, 1) < 0) { + close(skfd); + return 0; + } + + if (stats.qual.level != 0 || (stats.qual.updated & (IW_QUAL_DBM | IW_QUAL_RCPI))) { + if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) { + info->quality = stats.qual.qual; + info->quality_max = range.max_qual.qual; + info->quality_average = range.avg_qual.qual; + info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY; + } + + if (stats.qual.updated & IW_QUAL_RCPI) { + if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) { + info->signal_level = stats.qual.level / 2.0 - 110 + 0.5; + info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL; + } + if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) { + info->noise_level = stats.qual.noise / 2.0 - 110 + 0.5; + info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE; + } + } + else { + if ((stats.qual.updated & IW_QUAL_DBM) || stats.qual.level > range.max_qual.level) { + if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) { + info->signal_level = stats.qual.level; + if (info->signal_level > 63) + info->signal_level -= 256; + info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL; + } + if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) { + info->noise_level = stats.qual.noise; + if (info->noise_level > 63) + info->noise_level -= 256; + info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE; + } + } + else { + if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) { + info->signal_level = stats.qual.level; + info->signal_level_max = range.max_qual.level; + info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL; + } + if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) { + info->noise_level = stats.qual.noise; + info->noise_level_max = range.max_qual.noise; + info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE; + } + } + } + } + else { + if (!(stats.qual.updated & IW_QUAL_QUAL_INVALID)) { + info->quality = stats.qual.qual; + info->flags |= WIRELESS_INFO_FLAG_HAS_QUALITY; + } + if (!(stats.qual.updated & IW_QUAL_LEVEL_INVALID)) { + info->quality = stats.qual.level; + info->flags |= WIRELESS_INFO_FLAG_HAS_SIGNAL; + } + if (!(stats.qual.updated & IW_QUAL_NOISE_INVALID)) { + info->quality = stats.qual.noise; + info->flags |= WIRELESS_INFO_FLAG_HAS_NOISE; + } + } + + struct iwreq wrq; + if (iw_get_ext(skfd, interface, SIOCGIWRATE, &wrq) >= 0) + info->bitrate = wrq.u.bitrate.value; + + close(skfd); + return 1; #endif - return 0; } -/* - * Just parses /proc/net/wireless looking for lines beginning with - * wlan_interface, extracting the quality of the link and adding the - * current IP address of wlan_interface. - * - */ void print_wireless_info(const char *interface, const char *format_up, const char *format_down) { - char buf[1024]; - int quality = 0; - char *interfaces; const char *walk; - memset(buf, 0, sizeof(buf)); - - if (!slurp("/proc/net/wireless", buf, sizeof(buf))) - die("Could not open \"/proc/net/wireless\"\n"); - - interfaces = skip_character(buf, '\n', 1) + 1; - while ((interfaces = skip_character(interfaces, '\n', 1)+1) < buf+strlen(buf)) { - while (isspace((int)*interfaces)) - interfaces++; - if (!BEGINS_WITH(interfaces, interface)) - continue; - if (sscanf(interfaces, "%*[^:]: 0000 %d", &quality) != 1) - continue; - break; + wireless_info_t info; + if (get_wireless_info(interface, &info)) { + walk = format_up; + if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY) + printf("%s", info.quality < info.quality_average ? color("color_degraded") : color("color_good")); } - - if ((quality == UCHAR_MAX) || (quality == 0)) { + else { walk = format_down; - printf("%s", color("#FF0000")); - } else { - printf("%s", color("#00FF00")); - walk = format_up; + printf("%s", color("color_bad")); } for (; *walk != '\0'; walk++) { @@ -99,16 +162,49 @@ void print_wireless_info(const char *interface, const char *format_up, const cha } if (BEGINS_WITH(walk+1, "quality")) { - int max_qual = get_wireless_quality_max(interface); - if (max_qual && max_qual >= quality) - printf("%d/%d", quality, max_qual); - else - printf("%d", quality); + if (info.flags & WIRELESS_INFO_FLAG_HAS_QUALITY) { + if (info.quality_max) + printf("%03d%%", PERCENT_VALUE(info.quality, info.quality_max)); + else + printf("%d", info.quality); + } + else { + printf("no value"); + } walk += strlen("quality"); } + if (BEGINS_WITH(walk+1, "signal")) { + if (info.flags & WIRELESS_INFO_FLAG_HAS_SIGNAL) { + if (info.signal_level_max) + printf("%03d%%", PERCENT_VALUE(info.signal_level, info.signal_level_max)); + else + printf("%d dBm", info.signal_level); + } + else { + printf("no value"); + } + walk += strlen("signal"); + } + + if (BEGINS_WITH(walk+1, "noise")) { + if (info.flags & WIRELESS_INFO_FLAG_HAS_NOISE) { + if (info.noise_level_max) + printf("%03d%%", PERCENT_VALUE(info.noise_level, info.noise_level_max)); + else + printf("%d dBm", info.noise_level); + } + else { + printf("no value"); + } + walk += strlen("noise"); + } + if (BEGINS_WITH(walk+1, "essid")) { - (void)printf("%s", get_wireless_essid(interface)); + if (info.flags & WIRELESS_INFO_FLAG_HAS_ESSID) + printf("%s", info.essid); + else + printf("no value"); walk += strlen("essid"); } @@ -119,11 +215,16 @@ void print_wireless_info(const char *interface, const char *format_up, const cha else (void)printf("no IP"); walk += strlen("ip"); } - } -#ifdef LINUX - close_skfd(); -#endif + if (BEGINS_WITH(walk+1, "bitrate")) { + char buffer[128]; + + iw_print_bitrate(buffer, sizeof(buffer), info.bitrate); + + printf("%s", buffer); + walk += strlen("bitrate"); + } + } (void)printf("%s", endcolor()); }