blob: b508049fdb5dfc3f592fcbb18c2952a6506bddfd [file] [log] [blame]
/*
* 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;
}