360 lines
7.6 KiB
C
360 lines
7.6 KiB
C
|
|
/*
|
||
|
|
* libiio - Library for interfacing industrial I/O (IIO) devices
|
||
|
|
*
|
||
|
|
* Copyright (C) 2014 Analog Devices, Inc.
|
||
|
|
* Author: Paul Cercueil <paul.cercueil@analog.com>
|
||
|
|
*
|
||
|
|
* This library is free software; you can redistribute it and/or
|
||
|
|
* modify it under the terms of the GNU Lesser General Public
|
||
|
|
* License as published by the Free Software Foundation; either
|
||
|
|
* version 2.1 of the License, or (at your option) any later version.
|
||
|
|
*
|
||
|
|
* This library is distributed in the hope that it will be useful,
|
||
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
|
* Lesser General Public License for more details.
|
||
|
|
*
|
||
|
|
* */
|
||
|
|
|
||
|
|
#define _BSD_SOURCE
|
||
|
|
#define _GNU_SOURCE
|
||
|
|
#define _DEFAULT_SOURCE
|
||
|
|
|
||
|
|
#include <cdk/cdk.h>
|
||
|
|
#include <locale.h>
|
||
|
|
#include <pthread.h>
|
||
|
|
#include <stdbool.h>
|
||
|
|
#include <unistd.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
#ifdef __APPLE__
|
||
|
|
#include <iio/iio.h>
|
||
|
|
#else
|
||
|
|
#include <iio.h>
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#define ARRAY_SIZE(x) (sizeof(x) ? sizeof(x) / sizeof((x)[0]) : 0)
|
||
|
|
|
||
|
|
#define RED 020
|
||
|
|
#define YELLOW 040
|
||
|
|
#define BLUE 050
|
||
|
|
|
||
|
|
static int selected = -1;
|
||
|
|
|
||
|
|
static WINDOW *win, *left, *right;
|
||
|
|
static bool stop;
|
||
|
|
|
||
|
|
static bool channel_has_attr(struct iio_channel *chn, const char *attr)
|
||
|
|
{
|
||
|
|
unsigned int i, nb = iio_channel_get_attrs_count(chn);
|
||
|
|
for (i = 0; i < nb; i++)
|
||
|
|
if (!strcmp(attr, iio_channel_get_attr(chn, i)))
|
||
|
|
return true;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
static bool is_valid_channel(struct iio_channel *chn)
|
||
|
|
{
|
||
|
|
return !iio_channel_is_output(chn) &&
|
||
|
|
(channel_has_attr(chn, "raw") ||
|
||
|
|
channel_has_attr(chn, "input"));
|
||
|
|
}
|
||
|
|
|
||
|
|
static double get_channel_value(struct iio_channel *chn)
|
||
|
|
{
|
||
|
|
char *old_locale;
|
||
|
|
char buf[1024];
|
||
|
|
double val;
|
||
|
|
|
||
|
|
old_locale = strdup(setlocale(LC_NUMERIC, NULL));
|
||
|
|
setlocale(LC_NUMERIC, "C");
|
||
|
|
|
||
|
|
if (channel_has_attr(chn, "input")) {
|
||
|
|
iio_channel_attr_read(chn, "input", buf, sizeof(buf));
|
||
|
|
val = strtod(buf, NULL);
|
||
|
|
} else {
|
||
|
|
iio_channel_attr_read(chn, "raw", buf, sizeof(buf));
|
||
|
|
val = strtod(buf, NULL);
|
||
|
|
|
||
|
|
if (channel_has_attr(chn, "offset")) {
|
||
|
|
iio_channel_attr_read(chn, "offset", buf, sizeof(buf));
|
||
|
|
val += strtod(buf, NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (channel_has_attr(chn, "scale")) {
|
||
|
|
iio_channel_attr_read(chn, "scale", buf, sizeof(buf));
|
||
|
|
val *= strtod(buf, NULL);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
setlocale(LC_NUMERIC, old_locale);
|
||
|
|
free(old_locale);
|
||
|
|
|
||
|
|
return val / 1000.0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static struct {
|
||
|
|
const char *id;
|
||
|
|
const char *unit;
|
||
|
|
} map[] = {
|
||
|
|
{ "current", "A" },
|
||
|
|
{ "power", "W" },
|
||
|
|
{ "temp", "°C" },
|
||
|
|
{ "voltage", "V" },
|
||
|
|
{ 0, },
|
||
|
|
};
|
||
|
|
|
||
|
|
static const char *id_to_unit(const char *id)
|
||
|
|
{
|
||
|
|
unsigned int i;
|
||
|
|
|
||
|
|
for (i = 0; map[i].id; i++) {
|
||
|
|
if (!strncmp(id, map[i].id, strlen(map[i].id)))
|
||
|
|
return map[i].unit;
|
||
|
|
}
|
||
|
|
|
||
|
|
return "";
|
||
|
|
}
|
||
|
|
|
||
|
|
static void * read_thd(void *d)
|
||
|
|
{
|
||
|
|
struct iio_context *ctx = d;
|
||
|
|
|
||
|
|
while (!stop) {
|
||
|
|
struct iio_device *dev;
|
||
|
|
const char *name;
|
||
|
|
int row, col, len, align, line = 2;
|
||
|
|
unsigned int i, nb_channels, nb = 0;
|
||
|
|
char buf[1024];
|
||
|
|
chtype *str;
|
||
|
|
(void) row; /* Prevent warning */
|
||
|
|
|
||
|
|
usleep(100000);
|
||
|
|
|
||
|
|
if (selected < 0)
|
||
|
|
continue;
|
||
|
|
|
||
|
|
dev = iio_context_get_device(ctx, selected);
|
||
|
|
|
||
|
|
name = iio_device_get_name(dev);
|
||
|
|
if (!name)
|
||
|
|
name = iio_device_get_id(dev);
|
||
|
|
|
||
|
|
getmaxyx(right, row, col);
|
||
|
|
|
||
|
|
werase(right);
|
||
|
|
|
||
|
|
sprintf(buf, "</B>Device selected: </%u>%s<!%u><!B>",
|
||
|
|
RED, name, RED);
|
||
|
|
str = char2Chtype(buf, &len, &align);
|
||
|
|
writeChtype(right, 2, line, str, HORIZONTAL, 0, len);
|
||
|
|
freeChtype(str);
|
||
|
|
line += 2;
|
||
|
|
|
||
|
|
nb_channels = iio_device_get_channels_count(dev);
|
||
|
|
for (i = 0; i < nb_channels; i++) {
|
||
|
|
const char *id;
|
||
|
|
const char *unit;
|
||
|
|
struct iio_channel *chn =
|
||
|
|
iio_device_get_channel(dev, i);
|
||
|
|
if (!is_valid_channel(chn))
|
||
|
|
continue;
|
||
|
|
|
||
|
|
nb++;
|
||
|
|
name = iio_channel_get_name(chn);
|
||
|
|
id = iio_channel_get_id(chn);
|
||
|
|
if (!name)
|
||
|
|
name = id;
|
||
|
|
unit = id_to_unit(id);
|
||
|
|
|
||
|
|
sprintf(buf, "</%u></B>%s<!B><!%u>",
|
||
|
|
BLUE, name, BLUE);
|
||
|
|
str = char2Chtype(buf, &len, &align);
|
||
|
|
writeChtype(right, 2, line, str,
|
||
|
|
HORIZONTAL, 0, len);
|
||
|
|
freeChtype(str);
|
||
|
|
|
||
|
|
sprintf(buf, "</%u></B>%.3lf %s<!B><!%u>",
|
||
|
|
YELLOW, get_channel_value(chn), unit,
|
||
|
|
YELLOW);
|
||
|
|
str = char2Chtype(buf, &len, &align);
|
||
|
|
writeChtype(right, col / 2, line++,
|
||
|
|
str, HORIZONTAL, 0, len);
|
||
|
|
freeChtype(str);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (nb == 0) {
|
||
|
|
char msg[] = "No valid input channels found.";
|
||
|
|
writeChar(right, 2, line++, msg,
|
||
|
|
HORIZONTAL, 0, sizeof(msg) - 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
boxWindow(right, 0);
|
||
|
|
}
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
static struct iio_context *show_contexts_screen(void)
|
||
|
|
{
|
||
|
|
struct iio_context *ctx = NULL;
|
||
|
|
struct iio_scan_context *scan_ctx;
|
||
|
|
struct iio_context_info **info;
|
||
|
|
unsigned int num_contexts;
|
||
|
|
CDKSCREEN *screen;
|
||
|
|
CDKSCROLL *list;
|
||
|
|
const char *uri;
|
||
|
|
unsigned int i;
|
||
|
|
bool free_uri;
|
||
|
|
char **items;
|
||
|
|
int ret;
|
||
|
|
|
||
|
|
scan_ctx = iio_create_scan_context(NULL, 0);
|
||
|
|
if (!scan_ctx)
|
||
|
|
return NULL;
|
||
|
|
|
||
|
|
screen = initCDKScreen(win);
|
||
|
|
|
||
|
|
do {
|
||
|
|
ret = iio_scan_context_get_info_list(scan_ctx, &info);
|
||
|
|
if (ret < 0)
|
||
|
|
break;
|
||
|
|
|
||
|
|
num_contexts = ret;
|
||
|
|
|
||
|
|
items = calloc(num_contexts + 1, sizeof(*items));
|
||
|
|
|
||
|
|
for (i = 0; i < num_contexts; i++) {
|
||
|
|
asprintf(&items[i], "</%d>%s<!%d> </%d>[%s]<!%d>", YELLOW,
|
||
|
|
iio_context_info_get_description(info[i]),
|
||
|
|
YELLOW, BLUE,
|
||
|
|
iio_context_info_get_uri(info[i]),
|
||
|
|
BLUE);
|
||
|
|
}
|
||
|
|
|
||
|
|
items[i] = "Enter location";
|
||
|
|
|
||
|
|
list = newCDKScroll(screen, LEFT, TOP, RIGHT, 0, 0,
|
||
|
|
"\n Select a IIO context to use:\n",
|
||
|
|
items, num_contexts + 1, TRUE,
|
||
|
|
A_BOLD | A_REVERSE, TRUE, FALSE);
|
||
|
|
|
||
|
|
drawCDKScroll(list, TRUE);
|
||
|
|
|
||
|
|
ret = activateCDKScroll(list, NULL);
|
||
|
|
if (ret < num_contexts) {
|
||
|
|
uri = iio_context_info_get_uri(info[ret]);
|
||
|
|
free_uri = FALSE;
|
||
|
|
} else if (ret == num_contexts) {
|
||
|
|
uri = getString(screen,
|
||
|
|
"Please enter the location of the server",
|
||
|
|
"Location: ", "ip:localhost");
|
||
|
|
free_uri = TRUE;
|
||
|
|
} else {
|
||
|
|
uri = NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (uri) {
|
||
|
|
ctx = iio_create_context_from_uri(uri);
|
||
|
|
if (ctx == NULL) {
|
||
|
|
char *msg[] = { "</16>Failed to create IIO context.<!16>" };
|
||
|
|
popupLabel(screen, msg, 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (free_uri)
|
||
|
|
freeChar((char *)uri);
|
||
|
|
}
|
||
|
|
|
||
|
|
destroyCDKScroll(list);
|
||
|
|
iio_context_info_list_free(info);
|
||
|
|
for (i = 0; i < num_contexts; i++)
|
||
|
|
free(items[i]);
|
||
|
|
free(items);
|
||
|
|
|
||
|
|
} while (!ctx && ret >= 0);
|
||
|
|
|
||
|
|
destroyCDKScreen(screen);
|
||
|
|
|
||
|
|
iio_scan_context_destroy(scan_ctx);
|
||
|
|
|
||
|
|
return ctx;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void show_main_screen(struct iio_context *ctx)
|
||
|
|
{
|
||
|
|
unsigned int i, nb_devices;
|
||
|
|
CDKSCREEN *screen;
|
||
|
|
char **dev_names;
|
||
|
|
CDKSCROLL *list;
|
||
|
|
pthread_t thd;
|
||
|
|
|
||
|
|
stop = FALSE;
|
||
|
|
screen = initCDKScreen(left);
|
||
|
|
|
||
|
|
pthread_create(&thd, NULL, read_thd, ctx);
|
||
|
|
|
||
|
|
nb_devices = iio_context_get_devices_count(ctx);
|
||
|
|
dev_names = malloc(nb_devices * sizeof(char *));
|
||
|
|
|
||
|
|
for (i = 0; i < nb_devices; i++) {
|
||
|
|
char buf[1024];
|
||
|
|
struct iio_device *dev = iio_context_get_device(ctx, i);
|
||
|
|
const char *name = iio_device_get_name(dev);
|
||
|
|
if (!name)
|
||
|
|
name = iio_device_get_id(dev);
|
||
|
|
sprintf(buf, "</B> %s", name);
|
||
|
|
dev_names[i] = strdup(buf);
|
||
|
|
}
|
||
|
|
|
||
|
|
boxWindow(right, 0);
|
||
|
|
list = newCDKScroll(screen, LEFT, TOP, RIGHT, 0, 0,
|
||
|
|
"\n List of available IIO devices:\n",
|
||
|
|
dev_names, nb_devices, FALSE,
|
||
|
|
A_BOLD | A_REVERSE, TRUE, FALSE);
|
||
|
|
|
||
|
|
drawCDKScroll(list, TRUE);
|
||
|
|
|
||
|
|
while (!stop) {
|
||
|
|
int ret = activateCDKScroll(list, NULL);
|
||
|
|
stop = ret < 0;
|
||
|
|
selected = ret;
|
||
|
|
usleep(100000);
|
||
|
|
}
|
||
|
|
|
||
|
|
pthread_join(thd, NULL);
|
||
|
|
|
||
|
|
destroyCDKScroll(list);
|
||
|
|
for (i = 0; i < nb_devices; i++)
|
||
|
|
free(dev_names[i]);
|
||
|
|
free(dev_names);
|
||
|
|
destroyCDKScreen(screen);
|
||
|
|
}
|
||
|
|
|
||
|
|
int main(void)
|
||
|
|
{
|
||
|
|
struct iio_context *ctx;
|
||
|
|
int row, col;
|
||
|
|
|
||
|
|
win = initscr();
|
||
|
|
noecho();
|
||
|
|
keypad(win, TRUE);
|
||
|
|
getmaxyx(win, row, col);
|
||
|
|
initCDKColor();
|
||
|
|
|
||
|
|
left = newwin(row, col / 2, 0, 0);
|
||
|
|
right = newwin(row, col / 2, 0, col / 2);
|
||
|
|
|
||
|
|
while (TRUE) {
|
||
|
|
ctx = show_contexts_screen();
|
||
|
|
if (!ctx)
|
||
|
|
break;
|
||
|
|
|
||
|
|
show_main_screen(ctx);
|
||
|
|
iio_context_destroy(ctx);
|
||
|
|
}
|
||
|
|
|
||
|
|
endCDK();
|
||
|
|
delwin(left);
|
||
|
|
delwin(right);
|
||
|
|
return 0;
|
||
|
|
}
|