/* * BlueALSA - hcitop.c * Copyright (c) 2016-2018 Arkadiusz Bokowy * * This file is a part of bluez-alsa. * * This project is licensed under the terms of the MIT license. * */ #if HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include static const struct { unsigned int bit; char flag; } hci_flags_map[] = { { HCI_UP, 'U' }, { HCI_INIT, 'I' }, { HCI_RUNNING, 'R' }, { HCI_PSCAN, 'P' }, { HCI_ISCAN, 'I' }, { HCI_AUTH, 'A' }, { HCI_ENCRYPT, 'E' }, { HCI_INQUIRY, 'Q' }, { HCI_RAW, 'X' }, }; static int get_devinfo(struct hci_dev_info di[HCI_MAX_DEV]) { int i, num; for (i = num = 0; i < HCI_MAX_DEV; i++) if (hci_devinfo(i, &di[num]) == 0) num++; return num; } static unsigned int get_average_rate(unsigned int *array, size_t size) { /* at least two points are required */ if (size < 2) return 0; unsigned int x = 0; unsigned int y = 0; size_t i; size--; i = size; while (i--) { int b = (array[i] - array[i + 1]) % size; x += (array[i] - array[i + 1]) / size; if (y >= size - b) { y -= size - b; x++; } else { y += b; } } return x + y / size; } static void sprint_hci_flags(char *str, unsigned int flags) { size_t i; for (i = 0; i < sizeof(hci_flags_map) / sizeof(*hci_flags_map); i++) str[i] = hci_test_bit(hci_flags_map[i].bit, &flags) ? hci_flags_map[i].flag : ' '; str[i] = '\0'; } int main(int argc, char *argv[]) { int opt; const char *opts = "hVd:"; const struct option longopts[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'V' }, { "delay", required_argument, NULL, 'd' }, { 0, 0, 0, 0 }, }; int delay_sec = 1; int delay_msec = 0; while ((opt = getopt_long(argc, argv, opts, longopts, NULL)) != -1) switch (opt) { case 'h' /* --help */ : printf("usage: %s [ -d sec ]\n" " -h, --help\t\tprint this help and exit\n" " -V, --version\t\tprint version and exit\n" " -d, --delay=SEC\tdelay time interval\n", argv[0]); return EXIT_SUCCESS; case 'V' /* --version */ : printf("%s\n", PACKAGE_VERSION); return EXIT_SUCCESS; case 'd' /* --delay=SEC */ : delay_sec = atoi(optarg); delay_msec = (int)((atof(optarg) - delay_sec) * 10) * 100; if (delay_sec < 0 || delay_msec < 0 || (delay_sec == 0 && delay_msec == 0)) { fprintf(stderr, "%s: -d requires positive argument (max precision: 0.1)\n", argv[0]); return EXIT_FAILURE; } break; default: fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]); return EXIT_FAILURE; } struct hci_dev_info devices[HCI_MAX_DEV]; unsigned int byte_rx[HCI_MAX_DEV][3]; unsigned int byte_tx[HCI_MAX_DEV][3]; size_t ii; memset(byte_rx, 0, sizeof(byte_rx)); memset(byte_tx, 0, sizeof(byte_tx)); initscr(); cbreak(); noecho(); curs_set(0); for (ii = 1;; ii++) { const char *template_top = "%5s %9s %8s %8s %8s %8s"; const char *template_row = "%5s %9s %8s %8s %8s %8s"; int i, count; attron(A_REVERSE); mvprintw(0, 0, template_top, "HCI", "FLAGS", "RX", "TX", "RX/s", "TX/s"); attroff(A_REVERSE); count = get_devinfo(devices); for (i = 0; i < HCI_MAX_DEV; i++) { /* shift historic data to the right by one sample */ memmove(&byte_rx[i][1], &byte_rx[i][0], sizeof(*byte_rx) - sizeof(**byte_rx)); memmove(&byte_tx[i][1], &byte_tx[i][0], sizeof(*byte_tx) - sizeof(**byte_tx)); if (i >= count) continue; char flags[sizeof(hci_flags_map) / sizeof(*hci_flags_map) + 1]; sprint_hci_flags(flags, devices[i].flags); byte_rx[i][0] = devices[i].stat.byte_rx; byte_tx[i][0] = devices[i].stat.byte_tx; const size_t ii_max = sizeof(*byte_rx) / sizeof(**byte_rx); const size_t samples = ii < ii_max ? ii : ii_max; unsigned int rate_rx = get_average_rate(byte_rx[i], samples); unsigned int rate_tx = get_average_rate(byte_tx[i], samples); rate_rx = rate_rx * 10 / (delay_sec * 10 + delay_msec / 100); rate_tx = rate_tx * 10 / (delay_sec * 10 + delay_msec / 100); char rx[7], rx_rate[9]; char tx[7], tx_rate[9]; humanize_number(rx, sizeof(rx), byte_rx[i][0], "B", HN_AUTOSCALE, 0); humanize_number(tx, sizeof(tx), byte_tx[i][0], "B", HN_AUTOSCALE, 0); humanize_number(rx_rate, sizeof(rx_rate), rate_rx, "B", HN_AUTOSCALE, 0); humanize_number(tx_rate, sizeof(tx_rate), rate_tx, "B", HN_AUTOSCALE, 0); mvprintw(i + 1, 0, template_row, devices[i].name, flags, rx, tx, rx_rate, tx_rate); } timeout(delay_sec * 1000 + delay_msec); if (getch() == 'q') break; } endwin(); return EXIT_SUCCESS; }