dey-examples: remove old examples now superseeded by digiapix
This commit removes the following examples that were accessing hardware interfaces: - dey-examples-adc - dey-examples-can - dey-examples-gpio-sysfs - dey-examples-spidev - dey-examples-watchdog The recipe 'dey-examples-digiapix' builds similar examples that make use of Digi's APIX for accessing the hardware. Add this recipe to images - dey-image-qt - core-image-base Signed-off-by: Hector Palacios <hector.palacios@digi.com> https://jira.digi.com/browse/DEL-5169
This commit is contained in:
parent
04aa734d75
commit
42d28c76cb
|
|
@ -13,6 +13,10 @@ IMAGE_FEATURES += " \
|
|||
${@bb.utils.contains('MACHINE_FEATURES', 'wifi', 'dey-wireless', '', d)} \
|
||||
"
|
||||
|
||||
IMAGE_INSTALL = " \
|
||||
dey-examples-digiapix \
|
||||
"
|
||||
|
||||
# SDK features (for toolchains generated from an image with populate_sdk)
|
||||
SDKIMAGE_FEATURES ?= "dev-pkgs dbg-pkgs staticdev-pkgs"
|
||||
|
||||
|
|
|
|||
|
|
@ -58,4 +58,5 @@ export IMAGE_BASENAME = "dey-image-qt-${GRAPHICAL_BACKEND}"
|
|||
CORE_IMAGE_EXTRA_INSTALL += " \
|
||||
${@bb.utils.contains('DISTRO_FEATURES', 'wayland', 'weston-init weston-examples gtk+3-demo clutter-1.0-examples', '', d)} \
|
||||
${@bb.utils.contains('DISTRO_FEATURES', 'x11 wayland', 'weston-xwayland xterm', '', d)} \
|
||||
dey-examples-digiapix \
|
||||
"
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
SUMMARY = "DEY examples: ADC test application"
|
||||
SECTION = "examples"
|
||||
LICENSE = "GPL-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6"
|
||||
|
||||
SRC_URI = "file://adc_sample"
|
||||
|
||||
S = "${WORKDIR}/adc_sample"
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${bindir}
|
||||
install -m 0755 adc_sample ${D}${bindir}
|
||||
}
|
||||
|
||||
PACKAGE_ARCH = "${MACHINE_ARCH}"
|
||||
COMPATIBLE_MACHINE = "(ccimx6ul|ccimx8x)"
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
# Copyright (C) 2013-2018, Digi International Inc.
|
||||
|
||||
SUMMARY = "DEY examples: CAN bus test application"
|
||||
SECTION = "examples"
|
||||
LICENSE = "GPL-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6"
|
||||
|
||||
SRC_URI = "file://can_test"
|
||||
|
||||
S = "${WORKDIR}/can_test"
|
||||
|
||||
do_compile() {
|
||||
${CC} -O2 -Wall ${LDFLAGS} can_test.c -o can_test -pthread
|
||||
}
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${bindir}
|
||||
install -m 0755 can_test ${D}${bindir}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
# Copyright (C) 2013,2017 Digi International.
|
||||
|
||||
SUMMARY = "DEY examples: GPIO sysfs API test application"
|
||||
SECTION = "examples"
|
||||
LICENSE = "GPL-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6"
|
||||
|
||||
SRC_URI = "file://gpio_sysfs_test"
|
||||
|
||||
S = "${WORKDIR}/gpio_sysfs_test"
|
||||
|
||||
do_compile() {
|
||||
${CC} -O2 -Wall ${LDFLAGS} gpio_sysfs_test.c sysfsgpio.c -o gpio_sysfs_test
|
||||
}
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${bindir}
|
||||
install -m 0755 gpio_sysfs_test ${D}${bindir}
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
# Copyright (C) 2013-2017, Digi International Inc.
|
||||
|
||||
SUMMARY = "DEY examples: SPI device driver test application"
|
||||
SECTION = "examples"
|
||||
LICENSE = "GPL-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6"
|
||||
|
||||
SRC_URI = "file://spidev_test"
|
||||
|
||||
S = "${WORKDIR}/spidev_test"
|
||||
|
||||
do_compile() {
|
||||
${CC} -O2 -Wall ${LDFLAGS} spidev_test.c -o spidev_test
|
||||
}
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${bindir}
|
||||
install -m 0755 spidev_test ${D}${bindir}
|
||||
}
|
||||
|
||||
PACKAGE_ARCH = "${MACHINE_ARCH}"
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
# Copyright (C) 2013,2017 Digi International.
|
||||
|
||||
SUMMARY = "DEY examples: watchdog test application"
|
||||
SECTION = "examples"
|
||||
LICENSE = "GPL-2.0"
|
||||
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/GPL-2.0;md5=801f80980d171dd6425610833a22dbe6"
|
||||
|
||||
SRC_URI = "file://watchdog_test"
|
||||
|
||||
S = "${WORKDIR}/watchdog_test"
|
||||
|
||||
do_compile() {
|
||||
${CC} -O2 -Wall ${LDFLAGS} watchdog_test.c -o watchdog_test
|
||||
}
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${bindir}
|
||||
install -m 0755 watchdog_test ${D}${bindir}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
CFLAGS = -Wall -g -D_GNU_SOURCE
|
||||
|
||||
all: adc_sample
|
||||
|
||||
adc_sample: adc_sample.o iio_utils.o
|
||||
|
||||
%.o: %.c iio_utils.h
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f *.o adc_sample
|
||||
|
|
@ -1,359 +0,0 @@
|
|||
/*
|
||||
* ConnectCore 6UL ADC sample application.
|
||||
*
|
||||
* Copyright (c) 2016 Digi International Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Partially based on iio_event_monitor.c from the tools/iio directory, of the
|
||||
* linux kernel.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "iio_utils.h"
|
||||
|
||||
#define ARRAY_SIZE(v) (sizeof(v) / sizeof((v)[0]))
|
||||
#define BUFFER_LEN 20
|
||||
|
||||
#define ADC_SAMPLE_USAGE \
|
||||
"Usage:\n" \
|
||||
"adc_sample -t ADC_type -c channel [options]\n\n"
|
||||
|
||||
#define ADC_SAMPLE_FULL_USAGE \
|
||||
"Usage:\n" \
|
||||
"adc_sample -t ADC_type -c channel [options]\n\n" \
|
||||
"Options:\n" \
|
||||
" -t : ADC_type ('MX6UL', 'MCA-CC6UL', 'MX8X', 'MCA-CC8X', 'IOEXP')\n" \
|
||||
" -c : channel number to read from\n" \
|
||||
" -n : Number of samples (default: 1)\n" \
|
||||
" -d : Delay (in ms) between samples (default: 1000)\n" \
|
||||
" -v : Show output in V (otherwise raw ADC value is shown)\n" \
|
||||
" -h : help\n\n"
|
||||
|
||||
enum adc_type {
|
||||
ADC_TYPE_UNKNOWN,
|
||||
ADC_TYPE_MX6UL,
|
||||
ADC_TYPE_MCA_CC6UL,
|
||||
ADC_TYPE_MX8X,
|
||||
ADC_TYPE_MCA_CC8X,
|
||||
ADC_TYPE_IOEXP,
|
||||
};
|
||||
|
||||
struct adc_data {
|
||||
enum adc_type type;
|
||||
const char *name;
|
||||
const char *dev_name;
|
||||
unsigned int nbits;
|
||||
};
|
||||
|
||||
struct adc_data adc_list[] = {
|
||||
{
|
||||
.type = ADC_TYPE_MX6UL,
|
||||
.name = "MX6UL",
|
||||
.dev_name = "2198000.adc",
|
||||
.nbits = 12,
|
||||
},
|
||||
{
|
||||
.type = ADC_TYPE_MCA_CC6UL,
|
||||
.name = "MCA-CC6UL",
|
||||
.dev_name = "mca-cc6ul-adc",
|
||||
.nbits = 12,
|
||||
},
|
||||
{
|
||||
.type = ADC_TYPE_MX8X,
|
||||
.name = "MX8X",
|
||||
.dev_name = "5a880000.adc",
|
||||
.nbits = 12,
|
||||
},
|
||||
{
|
||||
.type = ADC_TYPE_MCA_CC8X,
|
||||
.name = "MCA-CC8X",
|
||||
.dev_name = "mca-cc8x-adc",
|
||||
.nbits = 12,
|
||||
},
|
||||
{
|
||||
.type = ADC_TYPE_IOEXP,
|
||||
.name = "IOEXP",
|
||||
.dev_name = "mca-ioexp-adc",
|
||||
.nbits = 12,
|
||||
},
|
||||
};
|
||||
|
||||
typedef struct adc {
|
||||
struct adc_data *data;
|
||||
char *chrdev_name;
|
||||
char *sysfs_file;
|
||||
char *sysfs_dir;
|
||||
int dev_num;
|
||||
unsigned long channel;
|
||||
double voltage_scale;
|
||||
} adc_t;
|
||||
|
||||
static void show_usage(int full)
|
||||
{
|
||||
fprintf(stdout, "%s", full ?
|
||||
ADC_SAMPLE_FULL_USAGE : ADC_SAMPLE_USAGE);
|
||||
}
|
||||
|
||||
static struct adc_data *get_adc_data(const char *type_str)
|
||||
{
|
||||
struct adc_data *data = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(adc_list); i++) {
|
||||
if (!strcmp(adc_list[i].name, type_str)) {
|
||||
data = &adc_list[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static int read_adc_sample_sysfs(adc_t *adc, long int *val)
|
||||
{
|
||||
int fd, ret;
|
||||
char buffer[BUFFER_LEN];
|
||||
|
||||
fd = open(adc->sysfs_file, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stdout, "%s: failed to open %s\n",
|
||||
__func__, adc->sysfs_file);
|
||||
ret = fd;
|
||||
goto just_ret;
|
||||
}
|
||||
|
||||
ret = read(fd, buffer, BUFFER_LEN);
|
||||
if (ret < 0) {
|
||||
fprintf(stdout, "%s: failed to read ADC sample from %s (%d)\n",
|
||||
__func__, adc->sysfs_file, ret);
|
||||
goto close_ret;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
fprintf(stdout, "%s: no data available in %s\n",
|
||||
__func__, adc->sysfs_file);
|
||||
ret = -ENODATA;
|
||||
goto close_ret;
|
||||
}
|
||||
|
||||
*val = strtol(buffer, NULL, 10);
|
||||
ret = 0;
|
||||
|
||||
close_ret:
|
||||
close(fd);
|
||||
just_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int read_voltage_scale(adc_t *adc, double *val)
|
||||
{
|
||||
int fd, ret;
|
||||
char buffer[BUFFER_LEN];
|
||||
char *temp;
|
||||
|
||||
/* Read the voltage scale from the sysfs */
|
||||
ret = asprintf(&temp, "%s/in_voltage_scale", adc->sysfs_dir);
|
||||
if (ret < 0) {
|
||||
fprintf(stdout, "%s: failed to allocate memory\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fd = open(temp, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stdout, "%s: failed to open %s\n", __func__, temp);
|
||||
ret = fd;
|
||||
goto free_temp;
|
||||
}
|
||||
|
||||
ret = read(fd, buffer, BUFFER_LEN);
|
||||
if (ret < 0) {
|
||||
fprintf(stdout, "%s: failed to voltage scale from %s (%d)\n",
|
||||
__func__, temp, ret);
|
||||
goto close_fd;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
fprintf(stdout, "%s: no data available in %s\n", __func__, temp);
|
||||
ret = -ENODATA;
|
||||
goto close_fd;
|
||||
}
|
||||
|
||||
*val = atof(buffer);
|
||||
|
||||
close_fd:
|
||||
close(fd);
|
||||
free_temp:
|
||||
free(temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
adc_t *adc;
|
||||
unsigned long nsamples = 1;
|
||||
unsigned long delay_ms = 1000;
|
||||
long sample_val;
|
||||
bool raw = true;
|
||||
int ret, opt, i;
|
||||
|
||||
if (argc <= 2) {
|
||||
show_usage(1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
adc = malloc(sizeof(adc_t));
|
||||
if (!adc) {
|
||||
fprintf(stdout, "Failed to allocate memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto error_ret;
|
||||
}
|
||||
memset(adc, 0, sizeof(adc_t));
|
||||
|
||||
adc->channel = ~0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "t:n:d:c:vh")) > 0) {
|
||||
switch (opt) {
|
||||
case 't':
|
||||
adc->data = get_adc_data(optarg);
|
||||
if (!adc->data) {
|
||||
fprintf(stdout, "Unknown ADC type %s\n", optarg);
|
||||
show_usage(0);
|
||||
ret = EXIT_FAILURE;
|
||||
goto error_ret2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
nsamples = strtoul(optarg, NULL, 10);
|
||||
if (!nsamples) {
|
||||
fprintf(stdout,
|
||||
"Invalid number of samples parameter (%s)\n",
|
||||
optarg);
|
||||
show_usage(0);
|
||||
ret = EXIT_FAILURE;
|
||||
goto error_ret2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
delay_ms = strtoul(optarg, NULL, 10);
|
||||
if (!delay_ms) {
|
||||
fprintf(stdout,
|
||||
"Invalid inter sample delay parameter (%s)\n",
|
||||
optarg);
|
||||
show_usage(0);
|
||||
ret = EXIT_FAILURE;
|
||||
goto error_ret2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
adc->channel = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
raw = false;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
show_usage(1);
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
default:
|
||||
show_usage(0);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that the application params provide what we need */
|
||||
if (!adc->data || adc->data->type == ADC_TYPE_UNKNOWN) {
|
||||
fprintf(stdout, "ADC type must be provided\n");
|
||||
show_usage(1);
|
||||
ret = EXIT_FAILURE;
|
||||
goto error_ret2;
|
||||
}
|
||||
|
||||
if (adc->channel == ~0) {
|
||||
fprintf(stdout, "ADC channel must be provided\n");
|
||||
show_usage(1);
|
||||
ret = EXIT_FAILURE;
|
||||
goto error_ret2;
|
||||
}
|
||||
|
||||
adc->dev_num = find_type_by_name(adc->data->dev_name, "iio:device");
|
||||
if (adc->dev_num < 0) {
|
||||
fprintf(stdout, "Failed to find iio:device for %s\n",
|
||||
adc->data->dev_name);
|
||||
ret = -ENODEV;
|
||||
goto error_ret2;
|
||||
}
|
||||
ret = asprintf(&adc->chrdev_name, "/dev/iio:device%d", adc->dev_num);
|
||||
if (ret < 0) {
|
||||
fprintf(stdout, "Failed to allocate memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto error_ret2;
|
||||
}
|
||||
|
||||
ret = asprintf(&adc->sysfs_dir, "/sys/bus/iio/devices/iio:device%d",
|
||||
adc->dev_num);
|
||||
if (ret < 0) {
|
||||
fprintf(stdout, "Failed to allocate memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto error_ret3;
|
||||
}
|
||||
|
||||
ret = asprintf(&adc->sysfs_file, "%s/in_voltage%lu_raw",
|
||||
adc->sysfs_dir, adc->channel);
|
||||
if (ret < 0) {
|
||||
fprintf(stdout, "Failed to allocate memory\n");
|
||||
ret = -ENOMEM;
|
||||
goto error_ret4;
|
||||
}
|
||||
|
||||
if (!raw) {
|
||||
ret = read_voltage_scale(adc, &adc->voltage_scale);
|
||||
if (ret < 0) {
|
||||
goto error_ret5;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < nsamples; i++) {
|
||||
ret = read_adc_sample_sysfs(adc, &sample_val);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
if (raw) {
|
||||
fprintf(stdout, "Sample %i: 0x%04x\n",
|
||||
i, (unsigned int)sample_val);
|
||||
} else {
|
||||
fprintf(stdout, "Sample %i: %.2f V\n",
|
||||
i, sample_val * adc->voltage_scale / 1000);
|
||||
}
|
||||
|
||||
usleep(delay_ms * 1000);
|
||||
}
|
||||
|
||||
error_ret5:
|
||||
free(adc->sysfs_file);
|
||||
error_ret4:
|
||||
free(adc->sysfs_dir);
|
||||
error_ret3:
|
||||
free(adc->chrdev_name);
|
||||
error_ret2:
|
||||
free(adc);
|
||||
error_ret:
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,669 +0,0 @@
|
|||
/* IIO - useful set of util functionality
|
||||
*
|
||||
* Copyright (c) 2008 Jonathan Cameron
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
#ifndef _IIO_UTILS_H
|
||||
#define _IIO_UTILS_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include "iio_utils.h"
|
||||
|
||||
const char *iio_dir = "/sys/bus/iio/devices/";
|
||||
|
||||
static char * const iio_direction[] = {
|
||||
"in",
|
||||
"out",
|
||||
};
|
||||
|
||||
/**
|
||||
* iioutils_break_up_name() - extract generic name from full channel name
|
||||
* @full_name: the full channel name
|
||||
* @generic_name: the output generic channel name
|
||||
**/
|
||||
int iioutils_break_up_name(const char *full_name,
|
||||
char **generic_name)
|
||||
{
|
||||
char *current;
|
||||
char *w, *r;
|
||||
char *working, *prefix = "";
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(iio_direction) / sizeof(iio_direction[0]); i++)
|
||||
if (!strncmp(full_name, iio_direction[i],
|
||||
strlen(iio_direction[i]))) {
|
||||
prefix = iio_direction[i];
|
||||
break;
|
||||
}
|
||||
|
||||
current = strdup(full_name + strlen(prefix) + 1);
|
||||
working = strtok(current, "_\0");
|
||||
|
||||
w = working;
|
||||
r = working;
|
||||
|
||||
while (*r != '\0') {
|
||||
if (!isdigit(*r)) {
|
||||
*w = *r;
|
||||
w++;
|
||||
}
|
||||
r++;
|
||||
}
|
||||
*w = '\0';
|
||||
asprintf(generic_name, "%s_%s", prefix, working);
|
||||
free(current);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* iioutils_get_type() - find and process _type attribute data
|
||||
* @is_signed: output whether channel is signed
|
||||
* @bytes: output how many bytes the channel storage occupies
|
||||
* @mask: output a bit mask for the raw data
|
||||
* @be: big endian
|
||||
* @device_dir: the iio device directory
|
||||
* @name: the channel name
|
||||
* @generic_name: the channel type name
|
||||
**/
|
||||
int iioutils_get_type(unsigned *is_signed,
|
||||
unsigned *bytes,
|
||||
unsigned *bits_used,
|
||||
unsigned *shift,
|
||||
uint64_t *mask,
|
||||
unsigned *be,
|
||||
const char *device_dir,
|
||||
const char *name,
|
||||
const char *generic_name)
|
||||
{
|
||||
FILE *sysfsfp;
|
||||
int ret;
|
||||
DIR *dp;
|
||||
char *scan_el_dir, *builtname, *builtname_generic, *filename = 0;
|
||||
char signchar, endianchar;
|
||||
unsigned padint;
|
||||
const struct dirent *ent;
|
||||
|
||||
ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir);
|
||||
if (ret < 0) {
|
||||
ret = -ENOMEM;
|
||||
goto error_ret;
|
||||
}
|
||||
ret = asprintf(&builtname, FORMAT_TYPE_FILE, name);
|
||||
if (ret < 0) {
|
||||
ret = -ENOMEM;
|
||||
goto error_free_scan_el_dir;
|
||||
}
|
||||
ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name);
|
||||
if (ret < 0) {
|
||||
ret = -ENOMEM;
|
||||
goto error_free_builtname;
|
||||
}
|
||||
|
||||
dp = opendir(scan_el_dir);
|
||||
if (dp == NULL) {
|
||||
ret = -errno;
|
||||
goto error_free_builtname_generic;
|
||||
}
|
||||
while (ent = readdir(dp), ent != NULL)
|
||||
/*
|
||||
* Do we allow devices to override a generic name with
|
||||
* a specific one?
|
||||
*/
|
||||
if ((strcmp(builtname, ent->d_name) == 0) ||
|
||||
(strcmp(builtname_generic, ent->d_name) == 0)) {
|
||||
ret = asprintf(&filename,
|
||||
"%s/%s", scan_el_dir, ent->d_name);
|
||||
if (ret < 0) {
|
||||
ret = -ENOMEM;
|
||||
goto error_closedir;
|
||||
}
|
||||
sysfsfp = fopen(filename, "r");
|
||||
if (sysfsfp == NULL) {
|
||||
printf("failed to open %s\n", filename);
|
||||
ret = -errno;
|
||||
goto error_free_filename;
|
||||
}
|
||||
|
||||
ret = fscanf(sysfsfp,
|
||||
"%ce:%c%u/%u>>%u",
|
||||
&endianchar,
|
||||
&signchar,
|
||||
bits_used,
|
||||
&padint, shift);
|
||||
if (ret < 0) {
|
||||
printf("failed to pass scan type description\n");
|
||||
ret = -errno;
|
||||
goto error_close_sysfsfp;
|
||||
}
|
||||
*be = (endianchar == 'b');
|
||||
*bytes = padint / 8;
|
||||
if (*bits_used == 64)
|
||||
*mask = ~0;
|
||||
else
|
||||
*mask = (1 << *bits_used) - 1;
|
||||
if (signchar == 's')
|
||||
*is_signed = 1;
|
||||
else
|
||||
*is_signed = 0;
|
||||
fclose(sysfsfp);
|
||||
free(filename);
|
||||
|
||||
filename = 0;
|
||||
sysfsfp = 0;
|
||||
}
|
||||
error_close_sysfsfp:
|
||||
if (sysfsfp)
|
||||
fclose(sysfsfp);
|
||||
error_free_filename:
|
||||
if (filename)
|
||||
free(filename);
|
||||
error_closedir:
|
||||
closedir(dp);
|
||||
error_free_builtname_generic:
|
||||
free(builtname_generic);
|
||||
error_free_builtname:
|
||||
free(builtname);
|
||||
error_free_scan_el_dir:
|
||||
free(scan_el_dir);
|
||||
error_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iioutils_get_param_float(float *output,
|
||||
const char *param_name,
|
||||
const char *device_dir,
|
||||
const char *name,
|
||||
const char *generic_name)
|
||||
{
|
||||
FILE *sysfsfp;
|
||||
int ret;
|
||||
DIR *dp;
|
||||
char *builtname, *builtname_generic;
|
||||
char *filename = NULL;
|
||||
const struct dirent *ent;
|
||||
|
||||
ret = asprintf(&builtname, "%s_%s", name, param_name);
|
||||
if (ret < 0) {
|
||||
ret = -ENOMEM;
|
||||
goto error_ret;
|
||||
}
|
||||
ret = asprintf(&builtname_generic,
|
||||
"%s_%s", generic_name, param_name);
|
||||
if (ret < 0) {
|
||||
ret = -ENOMEM;
|
||||
goto error_free_builtname;
|
||||
}
|
||||
dp = opendir(device_dir);
|
||||
if (dp == NULL) {
|
||||
ret = -errno;
|
||||
goto error_free_builtname_generic;
|
||||
}
|
||||
while (ent = readdir(dp), ent != NULL)
|
||||
if ((strcmp(builtname, ent->d_name) == 0) ||
|
||||
(strcmp(builtname_generic, ent->d_name) == 0)) {
|
||||
ret = asprintf(&filename,
|
||||
"%s/%s", device_dir, ent->d_name);
|
||||
if (ret < 0) {
|
||||
ret = -ENOMEM;
|
||||
goto error_closedir;
|
||||
}
|
||||
sysfsfp = fopen(filename, "r");
|
||||
if (!sysfsfp) {
|
||||
ret = -errno;
|
||||
goto error_free_filename;
|
||||
}
|
||||
fscanf(sysfsfp, "%f", output);
|
||||
break;
|
||||
}
|
||||
error_free_filename:
|
||||
if (filename)
|
||||
free(filename);
|
||||
error_closedir:
|
||||
closedir(dp);
|
||||
error_free_builtname_generic:
|
||||
free(builtname_generic);
|
||||
error_free_builtname:
|
||||
free(builtname);
|
||||
error_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* bsort_channel_array_by_index() - reorder so that the array is in index order
|
||||
*
|
||||
**/
|
||||
|
||||
void bsort_channel_array_by_index(struct iio_channel_info **ci_array,
|
||||
int cnt)
|
||||
{
|
||||
|
||||
struct iio_channel_info temp;
|
||||
int x, y;
|
||||
|
||||
for (x = 0; x < cnt; x++)
|
||||
for (y = 0; y < (cnt - 1); y++)
|
||||
if ((*ci_array)[y].index > (*ci_array)[y+1].index) {
|
||||
temp = (*ci_array)[y + 1];
|
||||
(*ci_array)[y + 1] = (*ci_array)[y];
|
||||
(*ci_array)[y] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* build_channel_array() - function to figure out what channels are present
|
||||
* @device_dir: the IIO device directory in sysfs
|
||||
* @
|
||||
**/
|
||||
int build_channel_array(const char *device_dir,
|
||||
struct iio_channel_info **ci_array,
|
||||
int *counter)
|
||||
{
|
||||
DIR *dp;
|
||||
FILE *sysfsfp;
|
||||
int count, i;
|
||||
struct iio_channel_info *current;
|
||||
int ret;
|
||||
const struct dirent *ent;
|
||||
char *scan_el_dir;
|
||||
char *filename;
|
||||
|
||||
*counter = 0;
|
||||
ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir);
|
||||
if (ret < 0) {
|
||||
ret = -ENOMEM;
|
||||
goto error_ret;
|
||||
}
|
||||
dp = opendir(scan_el_dir);
|
||||
if (dp == NULL) {
|
||||
ret = -errno;
|
||||
goto error_free_name;
|
||||
}
|
||||
while (ent = readdir(dp), ent != NULL)
|
||||
if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
|
||||
"_en") == 0) {
|
||||
ret = asprintf(&filename,
|
||||
"%s/%s", scan_el_dir, ent->d_name);
|
||||
if (ret < 0) {
|
||||
ret = -ENOMEM;
|
||||
goto error_close_dir;
|
||||
}
|
||||
sysfsfp = fopen(filename, "r");
|
||||
if (sysfsfp == NULL) {
|
||||
ret = -errno;
|
||||
free(filename);
|
||||
goto error_close_dir;
|
||||
}
|
||||
fscanf(sysfsfp, "%i", &ret);
|
||||
if (ret == 1)
|
||||
(*counter)++;
|
||||
fclose(sysfsfp);
|
||||
free(filename);
|
||||
}
|
||||
*ci_array = malloc(sizeof(**ci_array) * (*counter));
|
||||
if (*ci_array == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error_close_dir;
|
||||
}
|
||||
seekdir(dp, 0);
|
||||
count = 0;
|
||||
while (ent = readdir(dp), ent != NULL) {
|
||||
if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"),
|
||||
"_en") == 0) {
|
||||
int current_enabled = 0;
|
||||
|
||||
current = &(*ci_array)[count++];
|
||||
ret = asprintf(&filename,
|
||||
"%s/%s", scan_el_dir, ent->d_name);
|
||||
if (ret < 0) {
|
||||
ret = -ENOMEM;
|
||||
/* decrement count to avoid freeing name */
|
||||
count--;
|
||||
goto error_cleanup_array;
|
||||
}
|
||||
sysfsfp = fopen(filename, "r");
|
||||
if (sysfsfp == NULL) {
|
||||
free(filename);
|
||||
ret = -errno;
|
||||
goto error_cleanup_array;
|
||||
}
|
||||
fscanf(sysfsfp, "%i", ¤t_enabled);
|
||||
fclose(sysfsfp);
|
||||
|
||||
if (!current_enabled) {
|
||||
free(filename);
|
||||
count--;
|
||||
continue;
|
||||
}
|
||||
|
||||
current->scale = 1.0;
|
||||
current->offset = 0;
|
||||
current->name = strndup(ent->d_name,
|
||||
strlen(ent->d_name) -
|
||||
strlen("_en"));
|
||||
if (current->name == NULL) {
|
||||
free(filename);
|
||||
ret = -ENOMEM;
|
||||
goto error_cleanup_array;
|
||||
}
|
||||
/* Get the generic and specific name elements */
|
||||
ret = iioutils_break_up_name(current->name,
|
||||
¤t->generic_name);
|
||||
if (ret) {
|
||||
free(filename);
|
||||
goto error_cleanup_array;
|
||||
}
|
||||
ret = asprintf(&filename,
|
||||
"%s/%s_index",
|
||||
scan_el_dir,
|
||||
current->name);
|
||||
if (ret < 0) {
|
||||
free(filename);
|
||||
ret = -ENOMEM;
|
||||
goto error_cleanup_array;
|
||||
}
|
||||
sysfsfp = fopen(filename, "r");
|
||||
fscanf(sysfsfp, "%u", ¤t->index);
|
||||
fclose(sysfsfp);
|
||||
free(filename);
|
||||
/* Find the scale */
|
||||
ret = iioutils_get_param_float(¤t->scale,
|
||||
"scale",
|
||||
device_dir,
|
||||
current->name,
|
||||
current->generic_name);
|
||||
if (ret < 0)
|
||||
goto error_cleanup_array;
|
||||
ret = iioutils_get_param_float(¤t->offset,
|
||||
"offset",
|
||||
device_dir,
|
||||
current->name,
|
||||
current->generic_name);
|
||||
if (ret < 0)
|
||||
goto error_cleanup_array;
|
||||
ret = iioutils_get_type(¤t->is_signed,
|
||||
¤t->bytes,
|
||||
¤t->bits_used,
|
||||
¤t->shift,
|
||||
¤t->mask,
|
||||
¤t->be,
|
||||
device_dir,
|
||||
current->name,
|
||||
current->generic_name);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dp);
|
||||
/* reorder so that the array is in index order */
|
||||
bsort_channel_array_by_index(ci_array, *counter);
|
||||
|
||||
return 0;
|
||||
|
||||
error_cleanup_array:
|
||||
for (i = count - 1; i >= 0; i--)
|
||||
free((*ci_array)[i].name);
|
||||
free(*ci_array);
|
||||
error_close_dir:
|
||||
closedir(dp);
|
||||
error_free_name:
|
||||
free(scan_el_dir);
|
||||
error_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* find_type_by_name() - function to match top level types by name
|
||||
* @name: top level type instance name
|
||||
* @type: the type of top level instance being sort
|
||||
*
|
||||
* Typical types this is used for are device and trigger.
|
||||
**/
|
||||
int find_type_by_name(const char *name, const char *type)
|
||||
{
|
||||
const struct dirent *ent;
|
||||
int number, numstrlen;
|
||||
|
||||
FILE *nameFile;
|
||||
DIR *dp;
|
||||
char thisname[IIO_MAX_NAME_LENGTH];
|
||||
char *filename;
|
||||
|
||||
dp = opendir(iio_dir);
|
||||
if (dp == NULL) {
|
||||
printf("No industrialio devices available\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
while (ent = readdir(dp), ent != NULL) {
|
||||
if (strcmp(ent->d_name, ".") != 0 &&
|
||||
strcmp(ent->d_name, "..") != 0 &&
|
||||
strlen(ent->d_name) > strlen(type) &&
|
||||
strncmp(ent->d_name, type, strlen(type)) == 0) {
|
||||
numstrlen = sscanf(ent->d_name + strlen(type),
|
||||
"%d",
|
||||
&number);
|
||||
/* verify the next character is not a colon */
|
||||
if (strncmp(ent->d_name + strlen(type) + numstrlen,
|
||||
":",
|
||||
1) != 0) {
|
||||
filename = malloc(strlen(iio_dir)
|
||||
+ strlen(type)
|
||||
+ numstrlen
|
||||
+ 6);
|
||||
if (filename == NULL) {
|
||||
closedir(dp);
|
||||
return -ENOMEM;
|
||||
}
|
||||
sprintf(filename, "%s%s%d/name",
|
||||
iio_dir,
|
||||
type,
|
||||
number);
|
||||
nameFile = fopen(filename, "r");
|
||||
if (!nameFile) {
|
||||
free(filename);
|
||||
continue;
|
||||
}
|
||||
free(filename);
|
||||
fscanf(nameFile, "%s", thisname);
|
||||
fclose(nameFile);
|
||||
if (strcmp(name, thisname) == 0) {
|
||||
closedir(dp);
|
||||
return number;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dp);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int _write_sysfs_int(char *filename, char *basedir, int val, int verify)
|
||||
{
|
||||
int ret = 0;
|
||||
FILE *sysfsfp;
|
||||
int test;
|
||||
char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
|
||||
|
||||
if (temp == NULL)
|
||||
return -ENOMEM;
|
||||
sprintf(temp, "%s/%s", basedir, filename);
|
||||
sysfsfp = fopen(temp, "w");
|
||||
if (sysfsfp == NULL) {
|
||||
printf("failed to open %s\n", temp);
|
||||
ret = -errno;
|
||||
goto error_free;
|
||||
}
|
||||
fprintf(sysfsfp, "%d", val);
|
||||
fclose(sysfsfp);
|
||||
if (verify) {
|
||||
sysfsfp = fopen(temp, "r");
|
||||
if (sysfsfp == NULL) {
|
||||
printf("failed to open %s\n", temp);
|
||||
ret = -errno;
|
||||
goto error_free;
|
||||
}
|
||||
fscanf(sysfsfp, "%d", &test);
|
||||
fclose(sysfsfp);
|
||||
if (test != val) {
|
||||
printf("Possible failure in int write %d to %s%s\n",
|
||||
val,
|
||||
basedir,
|
||||
filename);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
error_free:
|
||||
free(temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int write_sysfs_int(char *filename, char *basedir, int val)
|
||||
{
|
||||
return _write_sysfs_int(filename, basedir, val, 0);
|
||||
}
|
||||
|
||||
int write_sysfs_int_and_verify(char *filename, char *basedir, int val)
|
||||
{
|
||||
return _write_sysfs_int(filename, basedir, val, 1);
|
||||
}
|
||||
|
||||
int _write_sysfs_string(char *filename, char *basedir, char *val, int verify)
|
||||
{
|
||||
int ret = 0;
|
||||
FILE *sysfsfp;
|
||||
char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
|
||||
|
||||
if (temp == NULL) {
|
||||
printf("Memory allocation failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
sprintf(temp, "%s/%s", basedir, filename);
|
||||
sysfsfp = fopen(temp, "w");
|
||||
if (sysfsfp == NULL) {
|
||||
printf("Could not open %s\n", temp);
|
||||
ret = -errno;
|
||||
goto error_free;
|
||||
}
|
||||
fprintf(sysfsfp, "%s", val);
|
||||
fclose(sysfsfp);
|
||||
if (verify) {
|
||||
sysfsfp = fopen(temp, "r");
|
||||
if (sysfsfp == NULL) {
|
||||
printf("could not open file to verify\n");
|
||||
ret = -errno;
|
||||
goto error_free;
|
||||
}
|
||||
fscanf(sysfsfp, "%s", temp);
|
||||
fclose(sysfsfp);
|
||||
if (strcmp(temp, val) != 0) {
|
||||
printf("Possible failure in string write of %s "
|
||||
"Should be %s "
|
||||
"written to %s\%s\n",
|
||||
temp,
|
||||
val,
|
||||
basedir,
|
||||
filename);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
error_free:
|
||||
free(temp);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* write_sysfs_string_and_verify() - string write, readback and verify
|
||||
* @filename: name of file to write to
|
||||
* @basedir: the sysfs directory in which the file is to be found
|
||||
* @val: the string to write
|
||||
**/
|
||||
int write_sysfs_string_and_verify(char *filename, char *basedir, char *val)
|
||||
{
|
||||
return _write_sysfs_string(filename, basedir, val, 1);
|
||||
}
|
||||
|
||||
int write_sysfs_string(char *filename, char *basedir, char *val)
|
||||
{
|
||||
return _write_sysfs_string(filename, basedir, val, 0);
|
||||
}
|
||||
|
||||
int read_sysfs_posint(char *filename, char *basedir)
|
||||
{
|
||||
int ret;
|
||||
FILE *sysfsfp;
|
||||
char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
|
||||
|
||||
if (temp == NULL) {
|
||||
printf("Memory allocation failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
sprintf(temp, "%s/%s", basedir, filename);
|
||||
sysfsfp = fopen(temp, "r");
|
||||
if (sysfsfp == NULL) {
|
||||
ret = -errno;
|
||||
goto error_free;
|
||||
}
|
||||
fscanf(sysfsfp, "%d\n", &ret);
|
||||
fclose(sysfsfp);
|
||||
error_free:
|
||||
free(temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int read_sysfs_float(char *filename, char *basedir, float *val)
|
||||
{
|
||||
int ret = 0;
|
||||
FILE *sysfsfp;
|
||||
char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
|
||||
|
||||
if (temp == NULL) {
|
||||
printf("Memory allocation failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
sprintf(temp, "%s/%s", basedir, filename);
|
||||
sysfsfp = fopen(temp, "r");
|
||||
if (sysfsfp == NULL) {
|
||||
ret = -errno;
|
||||
goto error_free;
|
||||
}
|
||||
fscanf(sysfsfp, "%f\n", val);
|
||||
fclose(sysfsfp);
|
||||
error_free:
|
||||
free(temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int read_sysfs_string(const char *filename, const char *basedir, char *str)
|
||||
{
|
||||
int ret = 0;
|
||||
FILE *sysfsfp;
|
||||
char *temp = malloc(strlen(basedir) + strlen(filename) + 2);
|
||||
|
||||
if (temp == NULL) {
|
||||
printf("Memory allocation failed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
sprintf(temp, "%s/%s", basedir, filename);
|
||||
sysfsfp = fopen(temp, "r");
|
||||
if (sysfsfp == NULL) {
|
||||
ret = -errno;
|
||||
goto error_free;
|
||||
}
|
||||
fscanf(sysfsfp, "%s\n", str);
|
||||
fclose(sysfsfp);
|
||||
error_free:
|
||||
free(temp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* _IIO_UTILS_H */
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
#ifndef _IIO_UTILS_H_
|
||||
#define _IIO_UTILS_H_
|
||||
|
||||
/* IIO - useful set of util functionality
|
||||
*
|
||||
* Copyright (c) 2008 Jonathan Cameron
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Made up value to limit allocation sizes */
|
||||
#define IIO_MAX_NAME_LENGTH 30
|
||||
|
||||
#define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements"
|
||||
#define FORMAT_TYPE_FILE "%s_type"
|
||||
|
||||
extern const char *iio_dir;
|
||||
|
||||
/**
|
||||
* struct iio_channel_info - information about a given channel
|
||||
* @name: channel name
|
||||
* @generic_name: general name for channel type
|
||||
* @scale: scale factor to be applied for conversion to si units
|
||||
* @offset: offset to be applied for conversion to si units
|
||||
* @index: the channel index in the buffer output
|
||||
* @bytes: number of bytes occupied in buffer output
|
||||
* @mask: a bit mask for the raw output
|
||||
* @is_signed: is the raw value stored signed
|
||||
* @enabled: is this channel enabled
|
||||
**/
|
||||
struct iio_channel_info {
|
||||
char *name;
|
||||
char *generic_name;
|
||||
float scale;
|
||||
float offset;
|
||||
unsigned index;
|
||||
unsigned bytes;
|
||||
unsigned bits_used;
|
||||
unsigned shift;
|
||||
uint64_t mask;
|
||||
unsigned be;
|
||||
unsigned is_signed;
|
||||
unsigned location;
|
||||
};
|
||||
|
||||
int iioutils_break_up_name(const char *full_name, char **generic_name);
|
||||
int iioutils_get_type(unsigned *is_signed, unsigned *bytes,
|
||||
unsigned *bits_used, unsigned *shift,
|
||||
uint64_t *mask, unsigned *be,
|
||||
const char *device_dir, const char *name,
|
||||
const char *generic_name);
|
||||
int iioutils_get_param_float(float *output, const char *param_name,
|
||||
const char *device_dir, const char *name,
|
||||
const char *generic_name);
|
||||
void bsort_channel_array_by_index(struct iio_channel_info **ci_array, int cnt);
|
||||
int build_channel_array(const char *device_dir,
|
||||
struct iio_channel_info **ci_array, int *counter);
|
||||
int find_type_by_name(const char *name, const char *type);
|
||||
int write_sysfs_int(char *filename, char *basedir, int val);
|
||||
int write_sysfs_int_and_verify(char *filename, char *basedir, int val);
|
||||
int write_sysfs_string_and_verify(char *filename, char *basedir, char *val);
|
||||
int write_sysfs_string(char *filename, char *basedir, char *val);
|
||||
int read_sysfs_posint(char *filename, char *basedir);
|
||||
int read_sysfs_float(char *filename, char *basedir, float *val);
|
||||
int read_sysfs_string(const char *filename, const char *basedir, char *str);
|
||||
|
||||
#endif /* _IIO_UTILS_H_ */
|
||||
|
|
@ -1,571 +0,0 @@
|
|||
/*
|
||||
* can_test.c
|
||||
*
|
||||
* Copyright (C) 2009-2013 by Digi International Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Description: CAN bus test application
|
||||
*
|
||||
* Based on canecho.c from socket-can project with following notice:
|
||||
*
|
||||
* Copyright (c) 2002-2007 Volkswagen Group Electronic Research
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Volkswagen nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* Alternatively, provided that this notice is retained in full, this
|
||||
* software may be distributed under the terms of the GNU General
|
||||
* Public License ("GPL") version 2, in which case the provisions of the
|
||||
* GPL apply INSTEAD OF those given above.
|
||||
*
|
||||
* The provided data structures and external interfaces from this code
|
||||
* are not restricted to be used by modules with a GPL compatible license.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* Send feedback to <socketcan-users@lists.berlios.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <libgen.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/uio.h>
|
||||
#include <net/if.h>
|
||||
#include <getopt.h>
|
||||
#include <stdarg.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
|
||||
/* Application infos */
|
||||
#define APP_NAME "can_test"
|
||||
#define APP_VERSION "2.0"
|
||||
|
||||
#define pr_error(...) do { myprintf(ERROR, __VA_ARGS__); } while(0)
|
||||
#define pr_warning(...) do { myprintf(WARNING, __VA_ARGS__); } while(0)
|
||||
#define pr_info(...) do { myprintf(INFO, __VA_ARGS__); } while(0)
|
||||
#define pr_debug(...) do { myprintf(DEBUG, __VA_ARGS__); } while(0)
|
||||
#define pr_naked(...) do { printf(__VA_ARGS__); } while(0)
|
||||
|
||||
#define CAN_FRAME_SIZE sizeof(struct can_frame)
|
||||
|
||||
/* Operation modes */
|
||||
typedef enum can_mode {
|
||||
MODE_RECEIVER = 0,
|
||||
MODE_TRANSMITTER,
|
||||
} can_mode_t;
|
||||
|
||||
/* Used for the configuration varaible st.verbose */
|
||||
typedef enum verbosity_t {
|
||||
ERROR = 0,
|
||||
WARNING,
|
||||
INFO,
|
||||
DEBUG,
|
||||
} verbosity_t;
|
||||
static verbosity_t selected_verbosity;
|
||||
|
||||
/* Internal structure */
|
||||
struct opts_t {
|
||||
char *iface;
|
||||
canid_t *canids;
|
||||
double *tx_rates;
|
||||
int ids;
|
||||
int extended;
|
||||
unsigned char pattern;
|
||||
int same_pattern;
|
||||
can_mode_t mode;
|
||||
int bytes;
|
||||
unsigned long loops;
|
||||
pthread_t *threads;
|
||||
int xdelay;
|
||||
};
|
||||
|
||||
static struct opts_t *main_opts;
|
||||
|
||||
/*
|
||||
* Return the current time in seconds, using a double precision number.
|
||||
* This code is coming from NetPipe (used for the time meassurement)
|
||||
*/
|
||||
inline static double now(void)
|
||||
{
|
||||
struct timeval tp;
|
||||
gettimeofday(&tp, NULL);
|
||||
return ((double)tp.tv_sec + (double)tp.tv_usec * 1e-6);
|
||||
}
|
||||
|
||||
inline static void myprintf(verbosity_t level, const char *format, ...)
|
||||
{
|
||||
va_list lst;
|
||||
char *marke;
|
||||
int weg = 0;
|
||||
|
||||
if (level > selected_verbosity)
|
||||
return;
|
||||
|
||||
switch (level) {
|
||||
case ERROR:
|
||||
marke = "ERROR";
|
||||
weg = 1;
|
||||
break;
|
||||
case WARNING:
|
||||
marke = "WARNING";
|
||||
break;
|
||||
case INFO:
|
||||
marke = "INFO";
|
||||
break;
|
||||
case DEBUG:
|
||||
marke = "DEBUG";
|
||||
break;
|
||||
default:
|
||||
marke = "UNKNOW";
|
||||
weg = 1;
|
||||
break;
|
||||
}
|
||||
printf("[ %s ] ", marke);
|
||||
va_start(lst, format);
|
||||
vprintf(format, lst);
|
||||
va_end(lst);
|
||||
|
||||
if (weg)
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void print_version(void)
|
||||
{
|
||||
pr_naked("CAN test application v%s\n", APP_VERSION);
|
||||
}
|
||||
|
||||
static void print_usage(void)
|
||||
{
|
||||
fprintf(stdout, "Usage: %s [OPTIONS]\n"
|
||||
"%s %s Copyright Digi International Inc.\n\n"
|
||||
"Data transfer using CAN-sockets\n"
|
||||
"\n"
|
||||
" -m, --master Run the test as master (trasmitter)\n"
|
||||
" -D, --tx-delay= Delay (in usec.) between each TX frame\n"
|
||||
" -i, --ids= IDs to use for the test (in hex)\n"
|
||||
" -E, --extended Enables the extended ID support\n"
|
||||
" -d, --device= Interface to use (e.g. can0)\n"
|
||||
" -b, --bytes= Number of the data bytes per CAN-frame\n"
|
||||
" -l, --loops= Number of test loops to execute\n"
|
||||
" -p, --pattern= Data pattern to use (in hex)\n"
|
||||
" -v, --verbosity= Verbosity level (3: loud | 0: quiet)\n"
|
||||
" -V, --version Show version and exit\n"
|
||||
" -h, --help Display usage information\n\n",
|
||||
APP_NAME, APP_NAME, APP_VERSION);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the input options and return the structure with the parse options.
|
||||
* By errors return NULL
|
||||
*/
|
||||
static struct opts_t *process_options(int argc, char *argv[])
|
||||
{
|
||||
int opt_index, opt;
|
||||
static const char *short_options = "mD:d:i:Ed:b:l:p:v:Vh";
|
||||
struct opts_t *retval;
|
||||
char *str1, *token;
|
||||
char *savearg = NULL;
|
||||
int cnt;
|
||||
static const struct option long_options[] = {
|
||||
{"master", no_argument, NULL, 'm'},
|
||||
{"tx-delay", required_argument, NULL, 'D'},
|
||||
{"ids", required_argument, NULL, 'i'},
|
||||
{"extended", no_argument, NULL, 'E'},
|
||||
{"device", required_argument, NULL, 'd'},
|
||||
{"bytes", required_argument, NULL, 'b'},
|
||||
{"loops", required_argument, NULL, 'l'},
|
||||
{"pattern", required_argument, NULL, 'p'},
|
||||
{"verbosity", required_argument, NULL, 'v'},
|
||||
{"version", no_argument, NULL, 'V'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{0, 0, 0, 0},
|
||||
};
|
||||
|
||||
/* Allocate the space for the internal data structure */
|
||||
retval = calloc(1, sizeof(struct opts_t));
|
||||
if (!retval) {
|
||||
pr_error("calloc failed, %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (opt_index = 0;;) {
|
||||
opt = getopt_long(argc, argv, short_options, long_options, &opt_index);
|
||||
if (opt == EOF)
|
||||
break;
|
||||
|
||||
switch (opt) {
|
||||
case 'm':
|
||||
retval->mode = MODE_TRANSMITTER;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
retval->xdelay = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
|
||||
/* Obtain a copy of the passed argument first */
|
||||
savearg = malloc(strlen(optarg) + 1);
|
||||
if (!savearg) {
|
||||
pr_error("malloc failed, %s\n", strerror(errno));
|
||||
goto err_free_mem;
|
||||
}
|
||||
strncpy(savearg, optarg, strlen(optarg));
|
||||
|
||||
for (cnt = 0, str1 = optarg; (token = strtok(str1, ",")); str1 = NULL)
|
||||
cnt++;
|
||||
|
||||
retval->canids = calloc(cnt, sizeof(canid_t));
|
||||
retval->threads = calloc(cnt, sizeof(pthread_t));
|
||||
retval->tx_rates = calloc(cnt, sizeof(ulong));
|
||||
if (!retval->canids || !retval->threads || !retval->tx_rates) {
|
||||
pr_error("calloc failed, %s\n", strerror(errno));
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
for (cnt = 0, str1 = savearg; (token = strtok(str1, ",")); str1 = NULL)
|
||||
*(retval->canids + cnt++) = strtol(token, NULL, 16);
|
||||
|
||||
retval->ids = cnt;
|
||||
|
||||
/* Free savearg */
|
||||
free(savearg);
|
||||
savearg = NULL;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
retval->iface = optarg;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
selected_verbosity = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
retval->bytes = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
retval->loops = atol(optarg);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
retval->pattern = (unsigned char)strtol(optarg, NULL, 16);
|
||||
retval->same_pattern = 1;
|
||||
break;
|
||||
|
||||
case 'E':
|
||||
retval->extended = 1;
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
print_version();
|
||||
goto err_free_mem;
|
||||
|
||||
case '?':
|
||||
fprintf(stderr, "Unknown option -- %c\n", opt);
|
||||
/* FALLTHROUGH */
|
||||
case 'h':
|
||||
default:
|
||||
print_usage();
|
||||
goto err_free_mem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sanity checks */
|
||||
if (retval->bytes > 8) {
|
||||
pr_error("Invalid data length %i\n", retval->bytes);
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
if (!retval->loops) {
|
||||
pr_error("A valid number of test loops is required\n");
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
if (!retval->iface) {
|
||||
pr_error("Need a CAN device for the test\n");
|
||||
goto err_free_mem;
|
||||
}
|
||||
|
||||
/* Print the information about the started mode */
|
||||
if (retval->mode == MODE_TRANSMITTER)
|
||||
pr_naked("Running the test as TRANSMITTER\n");
|
||||
else
|
||||
pr_naked("Running the test as RECEIVER\n");
|
||||
|
||||
pr_info("Testing with %i loops\n", retval->loops);
|
||||
return retval;
|
||||
|
||||
err_free_mem:
|
||||
free(savearg);
|
||||
free(retval->threads);
|
||||
free(retval->canids);
|
||||
free(retval->tx_rates);
|
||||
free(retval);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Depending on the selected command line options, the below function configures
|
||||
* the CAN-frames in two different modes:
|
||||
* - With a modified incremented frame Id (RTR or extended ID)
|
||||
* - Modified data pattern (incremented with 0x11)
|
||||
*/
|
||||
static void update_frame(struct opts_t *opts, struct can_frame *frame, canid_t id,
|
||||
unsigned char pattern)
|
||||
{
|
||||
frame->can_id = (opts->extended) ? (id | CAN_EFF_FLAG) : (id);
|
||||
frame->can_dlc = opts->bytes;
|
||||
|
||||
/* Now update the data bytes of the frame */
|
||||
memset(frame->data, pattern, opts->bytes);
|
||||
}
|
||||
|
||||
/* Dump the content of a CAN-frame */
|
||||
inline static void dump_frame(struct can_frame *frame, const char *name)
|
||||
{
|
||||
int cnt;
|
||||
|
||||
pr_naked("%s: ID 0x%03x | DLC 0x%02x | DATA ", name, frame->can_id, frame->can_dlc);
|
||||
for (cnt = 0; cnt < frame->can_dlc; cnt++)
|
||||
pr_naked("0x%02x ", frame->data[cnt]);
|
||||
pr_naked("\n");
|
||||
}
|
||||
|
||||
/* Return zero if the frames are equal, otherwise one */
|
||||
static int compare_frames(struct can_frame *rcv, struct can_frame *exp)
|
||||
{
|
||||
if (rcv->can_id != exp->can_id)
|
||||
return 1;
|
||||
|
||||
if (rcv->can_dlc != exp->can_dlc)
|
||||
return 1;
|
||||
|
||||
return memcmp(rcv->data, exp->data, rcv->can_dlc);
|
||||
}
|
||||
|
||||
static int xmit_frame(int sock, struct can_frame *frame)
|
||||
{
|
||||
return write(sock, frame, CAN_FRAME_SIZE);
|
||||
}
|
||||
|
||||
/* The argument must be the CAN-ID for this thread */
|
||||
static void *xmit_thread(void *arg)
|
||||
{
|
||||
int sock, fl;
|
||||
int family = PF_CAN, type = SOCK_RAW, proto = CAN_RAW;
|
||||
struct sockaddr_can addr;
|
||||
struct ifreq ifr;
|
||||
int loop, retop;
|
||||
canid_t id;
|
||||
struct can_frame txframe, rxframe;
|
||||
struct can_filter rfilter;
|
||||
unsigned char pattern;
|
||||
double jetzt, time_delta;
|
||||
ulong rate = 0;
|
||||
|
||||
/* Create the socket first */
|
||||
if ((sock = socket(family, type, proto)) < 0) {
|
||||
pr_error("socket() failed, %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
id = (canid_t) arg;
|
||||
/* Check ID length */
|
||||
if (id >= (1 << 29)) {
|
||||
pr_error("ID 0x%x exceeds max number of bits (normal=11, extended=29)\n");
|
||||
close(sock);
|
||||
return NULL;
|
||||
}
|
||||
if (id >= (1 << 11) && !main_opts->extended) {
|
||||
pr_error("ID 0x%x requires extended mode. Enable extended mode with '-E' option\n");
|
||||
close(sock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If started in receiver mode, then set the correct filter first.
|
||||
* According to the documentation from (@TODO: Link) the filter matches if:
|
||||
* <received id> & mask = id & mask
|
||||
*/
|
||||
if (main_opts->mode != MODE_TRANSMITTER) {
|
||||
rfilter.can_id = id;
|
||||
rfilter.can_mask = (main_opts->extended) ? CAN_EFF_MASK : CAN_SFF_MASK;
|
||||
retop = setsockopt(sock, SOL_CAN_RAW, CAN_RAW_FILTER,
|
||||
&rfilter, /* sizeof(struct can_filter) */ 8);
|
||||
if (retop) {
|
||||
pr_error("Socket setup failed, %s\n", strerror(errno));
|
||||
goto close_socket;
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(ifr.ifr_name, main_opts->iface);
|
||||
retop = ioctl(sock, SIOCGIFINDEX, &ifr);
|
||||
if (retop < 0) {
|
||||
pr_error("The IOCTL for `%s' failed, %s\n", main_opts->iface, strerror(errno));
|
||||
goto close_socket;
|
||||
}
|
||||
|
||||
addr.can_ifindex = ifr.ifr_ifindex;
|
||||
addr.can_family = family;
|
||||
|
||||
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||
pr_error("bind() failed, %s\n", strerror(errno));
|
||||
goto close_socket;
|
||||
}
|
||||
|
||||
/* Configure the socket correctly */
|
||||
fl = fcntl(sock, F_GETFD);
|
||||
if (fcntl(sock, F_SETFD, fl | O_SYNC | O_NDELAY | O_NOCTTY | FD_CLOEXEC) == -1) {
|
||||
pr_error("Socket config failed, %s\n", strerror(errno));
|
||||
goto close_socket;
|
||||
}
|
||||
|
||||
/* Set the initial pattern first */
|
||||
pattern = main_opts->pattern;
|
||||
jetzt = now();
|
||||
for (loop = 1; loop <= main_opts->loops; loop++) {
|
||||
|
||||
/* Increment the pattern if not pattern was passed */
|
||||
if (!main_opts->same_pattern)
|
||||
pattern++;
|
||||
|
||||
/*
|
||||
* Update the next CAN-frame
|
||||
* The transmitter will send the frame and the receiver expects it
|
||||
*/
|
||||
update_frame(main_opts, &txframe, id, pattern);
|
||||
|
||||
/* In the transmitter mode only send the CAN-frame */
|
||||
if (main_opts->mode == MODE_TRANSMITTER) {
|
||||
pr_debug("Going to transmit the frame %i with the ID 0x%x\n",
|
||||
loop, txframe.can_id);
|
||||
retop = xmit_frame(sock, &txframe);
|
||||
if (retop < 0) {
|
||||
pr_error("write() returned with errors, %s\n", strerror(errno));
|
||||
goto close_socket;
|
||||
} else if (retop != CAN_FRAME_SIZE) {
|
||||
pr_error("Couldn't send the %i bytes (%i sent)\n",
|
||||
CAN_FRAME_SIZE, retop);
|
||||
goto close_socket;
|
||||
}
|
||||
|
||||
if (main_opts->xdelay)
|
||||
usleep(main_opts->xdelay);
|
||||
} else {
|
||||
retop = read(sock, &rxframe, CAN_FRAME_SIZE);
|
||||
if (retop < 0) {
|
||||
pr_error("Read of CAN frame failed (loop %i), %s\n",
|
||||
loop, strerror(errno));
|
||||
goto close_socket;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since we need to wait for the transmitter, restart the
|
||||
* internal timer
|
||||
*/
|
||||
if (loop == 1)
|
||||
jetzt = now();
|
||||
|
||||
pr_debug("Frame %i with ID 0x%x received\n", loop, rxframe.can_id);
|
||||
if (compare_frames(&txframe, &rxframe)) {
|
||||
pr_error("Different CAN-frames at loop %i\n", loop);
|
||||
dump_frame(&txframe, "\t* EXPECTED");
|
||||
dump_frame(&rxframe, "\t* RECEIVED");
|
||||
goto close_socket;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Print some infos about the executed test */
|
||||
time_delta = now() - jetzt;
|
||||
if (main_opts->mode == MODE_TRANSMITTER) {
|
||||
rate = main_opts->loops * main_opts->bytes / (time_delta);
|
||||
pr_naked("ID 0x%03x : %lu Bps\n", id, rate);
|
||||
} else
|
||||
pr_naked("ID 0x%03x : %.4lg seconds\n", id, time_delta);
|
||||
|
||||
close_socket:
|
||||
close(sock);
|
||||
return (void *)rate;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int retval = -1;
|
||||
int cnt;
|
||||
canid_t id;
|
||||
pthread_t *thr;
|
||||
|
||||
/* Create the internal options */
|
||||
if (!(main_opts = process_options(argc, argv)))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
/* And start the test threads */
|
||||
for (cnt = 0; cnt < main_opts->ids; cnt++) {
|
||||
id = *(main_opts->canids + cnt);
|
||||
thr = main_opts->threads + cnt;
|
||||
pr_info("Starting the thread for the ID 0x%x\n", id);
|
||||
pthread_create(thr, NULL, xmit_thread, (void *)id);
|
||||
}
|
||||
|
||||
/* Now wait for the threads */
|
||||
for (cnt = 0; cnt < main_opts->ids; cnt++) {
|
||||
|
||||
/* @TODO: Pass the pointer for obtaining the transfer rate */
|
||||
pthread_join(*(main_opts->threads + cnt), NULL);
|
||||
}
|
||||
|
||||
/* @TODO: Print some test results: min and max values, etc. */
|
||||
if (main_opts->mode == MODE_TRANSMITTER) {
|
||||
|
||||
}
|
||||
|
||||
retval = EXIT_SUCCESS;
|
||||
|
||||
free(main_opts->tx_rates);
|
||||
free(main_opts->canids);
|
||||
free(main_opts->threads);
|
||||
free(main_opts);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
/*
|
||||
* gpio_sysfs_test.c
|
||||
*
|
||||
* Copyright (C) 2011 by Digi International Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* Description: GPIO SYSFS test application
|
||||
*
|
||||
*/
|
||||
|
||||
#include "sysfsgpio.h"
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
static int run = 1;
|
||||
|
||||
#define ABORT_ON_ERROR(fn) if( fn < 0 ) abort()
|
||||
#define RETURN_ON_ERROR(fn) if( fn < 0 ) return
|
||||
|
||||
void signal_handler(int sig)
|
||||
{
|
||||
switch (sig) {
|
||||
case SIGHUP:
|
||||
printf("hangup signal catched\n");
|
||||
break;
|
||||
case SIGTERM:
|
||||
printf("terminate signal catched\n");
|
||||
break;
|
||||
case SIGINT:
|
||||
printf("Interrupt signal catched\n");
|
||||
break;
|
||||
default:
|
||||
printf("signal %d catched\n", sig);
|
||||
break;
|
||||
}
|
||||
run = 0;
|
||||
}
|
||||
|
||||
void print_settings(unsigned int gpio)
|
||||
{
|
||||
unsigned int active_low;
|
||||
char edge[MAX_LEN];
|
||||
|
||||
sysfs_gpio_get_active_low(gpio, &active_low);
|
||||
sysfs_gpio_get_edge(gpio, edge, sizeof(edge));
|
||||
printf("GPIO %d: Active %s and %s edge\n", gpio, active_low ? "low"
|
||||
: "high", edge);
|
||||
}
|
||||
|
||||
int gpio_sysfs_test_loop(unsigned int gpioin, unsigned int gpiout, int loops)
|
||||
{
|
||||
int i;
|
||||
int value = 0;
|
||||
|
||||
if (!run)
|
||||
return -1;
|
||||
|
||||
print_settings(gpioin);
|
||||
printf("Press the button (for %d events):\n",loops);
|
||||
for (i = 0; (i < loops) && run; i++) {
|
||||
ABORT_ON_ERROR (sysfs_gpio_poll(gpioin,-1 /* no timeout */));
|
||||
ABORT_ON_ERROR(sysfs_gpio_set_value(gpiout,!value));
|
||||
value = !value;
|
||||
printf("Press %d\n", i+1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void poll_test(unsigned int gpioin, unsigned int gpioout)
|
||||
{
|
||||
char buf[MAX_LEN]="";
|
||||
|
||||
ABORT_ON_ERROR ( sysfs_gpio_set_direction( gpioin , 0 /* in */) );
|
||||
ABORT_ON_ERROR ( sysfs_gpio_set_direction( gpioout , 1 /* out */) );
|
||||
|
||||
// Active low and rising edge
|
||||
ABORT_ON_ERROR( sysfs_gpio_set_active_low( gpioin, 1 /*low*/) );
|
||||
ABORT_ON_ERROR ( sysfs_gpio_set_edge( gpioin, "rising") );
|
||||
RETURN_ON_ERROR( gpio_sysfs_test_loop(gpioin,gpioout,10) );
|
||||
|
||||
// Active low and falling edge
|
||||
ABORT_ON_ERROR ( sysfs_gpio_set_edge( gpioin, "falling") );
|
||||
RETURN_ON_ERROR( gpio_sysfs_test_loop(gpioin,gpioout,10) );
|
||||
|
||||
// Active low and both edges
|
||||
ABORT_ON_ERROR ( sysfs_gpio_set_edge( gpioin, "both") );
|
||||
sysfs_gpio_get_edge( gpioin , buf, sizeof(buf) );
|
||||
if( !strcmp(buf,"both") )
|
||||
RETURN_ON_ERROR( gpio_sysfs_test_loop(gpioin,gpioout,10) );
|
||||
|
||||
// Active high and rising edge
|
||||
ABORT_ON_ERROR( sysfs_gpio_set_active_low( gpioin, 0 /*high*/) );
|
||||
ABORT_ON_ERROR ( sysfs_gpio_set_edge( gpioin, "rising") );
|
||||
RETURN_ON_ERROR( gpio_sysfs_test_loop(gpioin,gpioout,10) );
|
||||
|
||||
// Active high and falling edge
|
||||
ABORT_ON_ERROR ( sysfs_gpio_set_edge( gpioin, "falling") );
|
||||
RETURN_ON_ERROR( gpio_sysfs_test_loop(gpioin,gpioout,10) );
|
||||
|
||||
// Active high and both edges
|
||||
ABORT_ON_ERROR ( sysfs_gpio_set_edge( gpioin, "both") );
|
||||
sysfs_gpio_get_edge( gpioin , buf, sizeof(buf) );
|
||||
if( !strcmp(buf,"both") )
|
||||
RETURN_ON_ERROR( gpio_sysfs_test_loop(gpioin,gpioout,10) );
|
||||
}
|
||||
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
int gpioin;
|
||||
int gpioout = -1;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("Usage: gpio-sysfs-test <gpio_in> [gpio_out]\n\n");
|
||||
printf("Where gpio_in is a pushbutton and gpio_out an optional LED.\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
gpioin = atoi(argv[1]);
|
||||
if(argv[2])
|
||||
gpioout = atoi(argv[2]);
|
||||
|
||||
ABORT_ON_ERROR (sysfs_gpio_export(gpioin) );
|
||||
ABORT_ON_ERROR (sysfs_gpio_export(gpioout) );
|
||||
|
||||
signal(SIGTERM, signal_handler);
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGHUP, signal_handler);
|
||||
|
||||
poll_test(gpioin, gpioout);
|
||||
|
||||
sysfs_gpio_unexport(gpioin);
|
||||
sysfs_gpio_unexport(gpioout);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,351 +0,0 @@
|
|||
/*
|
||||
* sysfsgpio.c
|
||||
*
|
||||
* Copyright (C) 2011 by Digi International Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* Description: GPIO SYSFS API library.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <poll.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "sysfsgpio.h"
|
||||
|
||||
int sysfs_gpio_export(int gpio)
|
||||
{
|
||||
int fd, len;
|
||||
char buf[MAX_LEN];
|
||||
|
||||
if( gpio < 0 )
|
||||
return 0;
|
||||
|
||||
fd = open(SYSFS_GPIO_DIR "/export", O_WRONLY);
|
||||
if (fd < 0) {
|
||||
perror("Error on GPIO export\n");
|
||||
return fd;
|
||||
}
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%d", gpio);
|
||||
write(fd, buf, len);
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sysfs_gpio_unexport(int gpio)
|
||||
{
|
||||
int fd, len;
|
||||
char buf[MAX_LEN];
|
||||
|
||||
if( gpio < 0 )
|
||||
return 0;
|
||||
|
||||
fd = open(SYSFS_GPIO_DIR "/unexport", O_WRONLY);
|
||||
if (fd < 0) {
|
||||
perror("Error on GPIO unexport");
|
||||
return fd;
|
||||
}
|
||||
|
||||
len = snprintf(buf, sizeof(buf), "%d", gpio);
|
||||
write(fd, buf, len);
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sysfs_gpio_set_direction(int gpio, unsigned int out)
|
||||
{
|
||||
int fd, len;
|
||||
char buf[MAX_LEN];
|
||||
|
||||
if( gpio < 0 )
|
||||
return 0;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/direction", gpio);
|
||||
|
||||
fd = open(buf, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
perror("Error setting GPIO direction\n");
|
||||
return fd;
|
||||
}
|
||||
|
||||
if (out)
|
||||
write(fd, "out", 4);
|
||||
else
|
||||
write(fd, "in", 3);
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sysfs_gpio_get_direction(int gpio, char * dir, int len)
|
||||
{
|
||||
int fd, length;
|
||||
char buf[MAX_LEN];
|
||||
|
||||
if( gpio < 0 )
|
||||
return 0;
|
||||
|
||||
length = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/direction",
|
||||
gpio);
|
||||
|
||||
fd = open(buf, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("Error getting GPIO direction\n");
|
||||
return fd;
|
||||
}
|
||||
|
||||
memset(dir,0,len);
|
||||
read(fd, dir, len);
|
||||
dir[strlen(dir) - 1] = '\0';
|
||||
if (strcmp(dir, "out") && strcmp(dir, "in")) {
|
||||
perror("Error getting direction\n");
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sysfs_gpio_set_active_low(int gpio, unsigned int low)
|
||||
{
|
||||
int fd, len;
|
||||
char buf[MAX_LEN];
|
||||
|
||||
if( gpio < 0 )
|
||||
return 0;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/active_low", gpio);
|
||||
|
||||
fd = open(buf, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
perror("Error setting GPIO value\n");
|
||||
return fd;
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s", low ? "1" : "0");
|
||||
write(fd, buf, 2);
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sysfs_gpio_get_active_low(int gpio, unsigned int *value)
|
||||
{
|
||||
int fd, len;
|
||||
char buf[MAX_LEN];
|
||||
char ch;
|
||||
|
||||
if( gpio < 0 )
|
||||
return 0;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/active_low", gpio);
|
||||
|
||||
fd = open(buf, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("Error getting GPIO value\n");
|
||||
return fd;
|
||||
}
|
||||
|
||||
read(fd, &ch, 1);
|
||||
|
||||
if (ch != '0') {
|
||||
*value = 1;
|
||||
}
|
||||
else {
|
||||
*value = 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sysfs_gpio_set_value(int gpio, unsigned int value)
|
||||
{
|
||||
int fd, len;
|
||||
char buf[MAX_LEN];
|
||||
|
||||
if( gpio < 0 )
|
||||
return 0;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
|
||||
|
||||
fd = open(buf, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
perror("Error setting GPIO value\n");
|
||||
return fd;
|
||||
}
|
||||
snprintf(buf, sizeof(buf), "%s", value ? "1" : "0");
|
||||
write(fd, buf, 2);
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sysfs_gpio_get_value(int gpio, unsigned int *value)
|
||||
{
|
||||
int fd, len;
|
||||
char buf[MAX_LEN];
|
||||
char ch;
|
||||
|
||||
if( gpio < 0 )
|
||||
return 0;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
|
||||
|
||||
fd = open(buf, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("Error getting GPIO value\n");
|
||||
return fd;
|
||||
}
|
||||
|
||||
read(fd, &ch, 1);
|
||||
|
||||
if (ch != '0') {
|
||||
*value = 1;
|
||||
}
|
||||
else {
|
||||
*value = 0;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sysfs_gpio_fset_value(int fd, unsigned int value)
|
||||
{
|
||||
char buf[MAX_LEN];
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s", value ? "1" : "0");
|
||||
write(fd, buf, 2);
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int sysfs_gpio_fget_value(int fd, unsigned int *value)
|
||||
{
|
||||
char buf;
|
||||
|
||||
read(fd, &buf, sizeof(char));
|
||||
|
||||
if (buf != '0') {
|
||||
*value = 1;
|
||||
}
|
||||
else {
|
||||
*value = 0;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int sysfs_gpio_set_edge(int gpio, char *edge)
|
||||
{
|
||||
int fd, len;
|
||||
char buf[MAX_LEN];
|
||||
|
||||
if( gpio < 0 )
|
||||
return 0;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/edge", gpio);
|
||||
|
||||
fd = open(buf, O_WRONLY);
|
||||
if (fd < 0) {
|
||||
perror("Error setting GPIO edge\n");
|
||||
return fd;
|
||||
}
|
||||
|
||||
write(fd, edge, strlen(edge) + 1);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sysfs_gpio_get_edge(int gpio, char *edge, int len)
|
||||
{
|
||||
int fd, length;
|
||||
char buf[MAX_LEN];
|
||||
|
||||
if( gpio < 0 )
|
||||
return 0;
|
||||
|
||||
length = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/edge", gpio);
|
||||
|
||||
fd = open(buf, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("Error setting GPIO edge\n");
|
||||
return fd;
|
||||
}
|
||||
|
||||
memset(edge,0,len);
|
||||
read(fd, edge, len);
|
||||
//Remove trailing newline
|
||||
edge[strlen(edge) - 1] = '\0';
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sysfs_gpio_poll(int gpio, unsigned int timeout)
|
||||
{
|
||||
int fd, len;
|
||||
char buf[MAX_LEN];
|
||||
struct pollfd pfd;
|
||||
int ret = 0;
|
||||
unsigned int inval;
|
||||
|
||||
if( gpio < 0 )
|
||||
return 0;
|
||||
|
||||
len = snprintf(buf, sizeof(buf), SYSFS_GPIO_DIR "/gpio%d/value", gpio);
|
||||
|
||||
fd = open(buf, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("Error on GPIO open\n");
|
||||
ret = -1;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Edge triggers are relative to the last read by the application
|
||||
* and not to the start of poll. Read here to avoid poll returning
|
||||
* immediately.*/
|
||||
read(fd, &buf, sizeof(char));
|
||||
|
||||
memset((void*) &pfd, 0, sizeof(pfd));
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLPRI;
|
||||
ret = poll(&pfd, 1, timeout);
|
||||
if (ret > 0) {
|
||||
|
||||
if (pfd.revents & POLLNVAL) {
|
||||
printf("Return error event %x\n", pfd.revents);
|
||||
ret = -1;
|
||||
}
|
||||
else if ((pfd.revents & POLLPRI)) {
|
||||
sysfs_gpio_fget_value(fd, &inval);
|
||||
}
|
||||
else {
|
||||
printf("Unhandled event %x\n", pfd.revents);
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
else if (ret == 0) {
|
||||
printf("Timeout on poll\n");
|
||||
}
|
||||
else {
|
||||
perror("Error on poll\n");
|
||||
ret = -1;
|
||||
;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
error: return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* sysfsgpio.h
|
||||
*
|
||||
* Copyright (C) 2011 by Digi International Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* Description: GPIO SYSFS API header file.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SYSFSGPIO_H_
|
||||
#define SYSFSGPIO_H_
|
||||
|
||||
#define SYSFS_GPIO_DIR "/sys/class/gpio"
|
||||
#define MAX_LEN 64
|
||||
|
||||
int sysfs_gpio_export(int gpio);
|
||||
int sysfs_gpio_unexport(int gpio);
|
||||
|
||||
int sysfs_gpio_set_direction(int gpio, unsigned int out);
|
||||
int sysfs_gpio_get_direction(int gpio, char * dir, int len);
|
||||
|
||||
int sysfs_gpio_set_active_low(int gpio, unsigned int low);
|
||||
int sysfs_gpio_get_active_low(int gpio, unsigned int *value);
|
||||
|
||||
int sysfs_gpio_set_value(int gpio, unsigned int value);
|
||||
int sysfs_gpio_get_value(int gpio, unsigned int *value);
|
||||
|
||||
int sysfs_gpio_set_edge(int gpio, char *edge);
|
||||
int sysfs_gpio_get_edge(int gpio, char *edge, int len);
|
||||
|
||||
int sysfs_gpio_poll(int gpio, unsigned int timeout);
|
||||
|
||||
#endif /* SYSFSGPIO_H_ */
|
||||
|
|
@ -1,483 +0,0 @@
|
|||
/*
|
||||
* SPI testing utility (using spidev driver)
|
||||
*
|
||||
* Copyright (c) 2007 MontaVista Software, Inc.
|
||||
* Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License.
|
||||
*
|
||||
* Cross-compile with cross-gcc -I/path/to/cross-kernel/include
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
static void pabort(const char *s)
|
||||
{
|
||||
perror(s);
|
||||
abort();
|
||||
}
|
||||
|
||||
static const char *device = "/dev/spidev1.1";
|
||||
static uint32_t mode;
|
||||
static uint8_t bits = 8;
|
||||
static char *input_file;
|
||||
static char *output_file;
|
||||
static uint32_t speed = 500000;
|
||||
static uint16_t delay;
|
||||
static int verbose;
|
||||
static int transfer_size;
|
||||
static int iterations;
|
||||
static int interval = 5; /* interval in seconds for showing transfer rate */
|
||||
|
||||
uint8_t default_tx[] = {
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xF0, 0x0D,
|
||||
};
|
||||
|
||||
uint8_t default_rx[ARRAY_SIZE(default_tx)] = {0, };
|
||||
char *input_tx;
|
||||
|
||||
static void hex_dump(const void *src, size_t length, size_t line_size,
|
||||
char *prefix)
|
||||
{
|
||||
int i = 0;
|
||||
const unsigned char *address = src;
|
||||
const unsigned char *line = address;
|
||||
unsigned char c;
|
||||
|
||||
printf("%s | ", prefix);
|
||||
while (length-- > 0) {
|
||||
printf("%02X ", *address++);
|
||||
if (!(++i % line_size) || (length == 0 && i % line_size)) {
|
||||
if (length == 0) {
|
||||
while (i++ % line_size)
|
||||
printf("__ ");
|
||||
}
|
||||
printf(" | "); /* right close */
|
||||
while (line < address) {
|
||||
c = *line++;
|
||||
printf("%c", (c < 33 || c == 255) ? 0x2E : c);
|
||||
}
|
||||
printf("\n");
|
||||
if (length > 0)
|
||||
printf("%s | ", prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Unescape - process hexadecimal escape character
|
||||
* converts shell input "\x23" -> 0x23
|
||||
*/
|
||||
static int unescape(char *_dst, char *_src, size_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
int match;
|
||||
char *src = _src;
|
||||
char *dst = _dst;
|
||||
unsigned int ch;
|
||||
|
||||
while (*src) {
|
||||
if (*src == '\\' && *(src+1) == 'x') {
|
||||
match = sscanf(src + 2, "%2x", &ch);
|
||||
if (!match)
|
||||
pabort("malformed input string");
|
||||
|
||||
src += 4;
|
||||
*dst++ = (unsigned char)ch;
|
||||
} else {
|
||||
*dst++ = *src++;
|
||||
}
|
||||
ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void transfer(int fd, uint8_t const *tx, uint8_t const *rx, size_t len)
|
||||
{
|
||||
int ret;
|
||||
int out_fd;
|
||||
struct spi_ioc_transfer tr = {
|
||||
.tx_buf = (unsigned long)tx,
|
||||
.rx_buf = (unsigned long)rx,
|
||||
.len = len,
|
||||
.delay_usecs = delay,
|
||||
.speed_hz = speed,
|
||||
.bits_per_word = bits,
|
||||
};
|
||||
|
||||
if (mode & SPI_TX_QUAD)
|
||||
tr.tx_nbits = 4;
|
||||
else if (mode & SPI_TX_DUAL)
|
||||
tr.tx_nbits = 2;
|
||||
if (mode & SPI_RX_QUAD)
|
||||
tr.rx_nbits = 4;
|
||||
else if (mode & SPI_RX_DUAL)
|
||||
tr.rx_nbits = 2;
|
||||
if (!(mode & SPI_LOOP)) {
|
||||
if (mode & (SPI_TX_QUAD | SPI_TX_DUAL))
|
||||
tr.rx_buf = 0;
|
||||
else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL))
|
||||
tr.tx_buf = 0;
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
|
||||
if (ret < 1)
|
||||
pabort("can't send spi message");
|
||||
|
||||
if (verbose)
|
||||
hex_dump(tx, len, 32, "TX");
|
||||
|
||||
if (output_file) {
|
||||
out_fd = open(output_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
|
||||
if (out_fd < 0)
|
||||
pabort("could not open output file");
|
||||
|
||||
ret = write(out_fd, rx, len);
|
||||
if (ret != len)
|
||||
pabort("not all bytes written to output file");
|
||||
|
||||
close(out_fd);
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
hex_dump(rx, len, 32, "RX");
|
||||
}
|
||||
|
||||
static void print_usage(const char *prog)
|
||||
{
|
||||
printf("Usage: %s [-DsbdlHOLC3vpNR24SI]\n", prog);
|
||||
puts(" -D --device device to use (default /dev/spidev1.1)\n"
|
||||
" -s --speed max speed (Hz)\n"
|
||||
" -d --delay delay (usec)\n"
|
||||
" -b --bpw bits per word\n"
|
||||
" -i --input input data from a file (e.g. \"test.bin\")\n"
|
||||
" -o --output output data to a file (e.g. \"results.bin\")\n"
|
||||
" -l --loop loopback\n"
|
||||
" -H --cpha clock phase\n"
|
||||
" -O --cpol clock polarity\n"
|
||||
" -L --lsb least significant bit first\n"
|
||||
" -C --cs-high chip select active high\n"
|
||||
" -3 --3wire SI/SO signals shared\n"
|
||||
" -v --verbose Verbose (show tx buffer)\n"
|
||||
" -p Send data (e.g. \"1234\\xde\\xad\")\n"
|
||||
" -N --no-cs no chip select\n"
|
||||
" -R --ready slave pulls low to pause\n"
|
||||
" -2 --dual dual transfer\n"
|
||||
" -4 --quad quad transfer\n"
|
||||
" -S --size transfer size\n"
|
||||
" -I --iter iterations\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void parse_opts(int argc, char *argv[])
|
||||
{
|
||||
while (1) {
|
||||
static const struct option lopts[] = {
|
||||
{ "device", 1, 0, 'D' },
|
||||
{ "speed", 1, 0, 's' },
|
||||
{ "delay", 1, 0, 'd' },
|
||||
{ "bpw", 1, 0, 'b' },
|
||||
{ "input", 1, 0, 'i' },
|
||||
{ "output", 1, 0, 'o' },
|
||||
{ "loop", 0, 0, 'l' },
|
||||
{ "cpha", 0, 0, 'H' },
|
||||
{ "cpol", 0, 0, 'O' },
|
||||
{ "lsb", 0, 0, 'L' },
|
||||
{ "cs-high", 0, 0, 'C' },
|
||||
{ "3wire", 0, 0, '3' },
|
||||
{ "no-cs", 0, 0, 'N' },
|
||||
{ "ready", 0, 0, 'R' },
|
||||
{ "dual", 0, 0, '2' },
|
||||
{ "verbose", 0, 0, 'v' },
|
||||
{ "quad", 0, 0, '4' },
|
||||
{ "size", 1, 0, 'S' },
|
||||
{ "iter", 1, 0, 'I' },
|
||||
{ NULL, 0, 0, 0 },
|
||||
};
|
||||
int c;
|
||||
|
||||
c = getopt_long(argc, argv, "D:s:d:b:i:o:lHOLC3NR24p:vS:I:",
|
||||
lopts, NULL);
|
||||
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'D':
|
||||
device = optarg;
|
||||
break;
|
||||
case 's':
|
||||
speed = atoi(optarg);
|
||||
break;
|
||||
case 'd':
|
||||
delay = atoi(optarg);
|
||||
break;
|
||||
case 'b':
|
||||
bits = atoi(optarg);
|
||||
break;
|
||||
case 'i':
|
||||
input_file = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
output_file = optarg;
|
||||
break;
|
||||
case 'l':
|
||||
mode |= SPI_LOOP;
|
||||
break;
|
||||
case 'H':
|
||||
mode |= SPI_CPHA;
|
||||
break;
|
||||
case 'O':
|
||||
mode |= SPI_CPOL;
|
||||
break;
|
||||
case 'L':
|
||||
mode |= SPI_LSB_FIRST;
|
||||
break;
|
||||
case 'C':
|
||||
mode |= SPI_CS_HIGH;
|
||||
break;
|
||||
case '3':
|
||||
mode |= SPI_3WIRE;
|
||||
break;
|
||||
case 'N':
|
||||
mode |= SPI_NO_CS;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
case 'R':
|
||||
mode |= SPI_READY;
|
||||
break;
|
||||
case 'p':
|
||||
input_tx = optarg;
|
||||
break;
|
||||
case '2':
|
||||
mode |= SPI_TX_DUAL;
|
||||
break;
|
||||
case '4':
|
||||
mode |= SPI_TX_QUAD;
|
||||
break;
|
||||
case 'S':
|
||||
transfer_size = atoi(optarg);
|
||||
break;
|
||||
case 'I':
|
||||
iterations = atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mode & SPI_LOOP) {
|
||||
if (mode & SPI_TX_DUAL)
|
||||
mode |= SPI_RX_DUAL;
|
||||
if (mode & SPI_TX_QUAD)
|
||||
mode |= SPI_RX_QUAD;
|
||||
}
|
||||
}
|
||||
|
||||
static void transfer_escaped_string(int fd, char *str)
|
||||
{
|
||||
size_t size = strlen(str);
|
||||
uint8_t *tx;
|
||||
uint8_t *rx;
|
||||
|
||||
tx = malloc(size);
|
||||
if (!tx)
|
||||
pabort("can't allocate tx buffer");
|
||||
|
||||
rx = malloc(size);
|
||||
if (!rx)
|
||||
pabort("can't allocate rx buffer");
|
||||
|
||||
size = unescape((char *)tx, str, size);
|
||||
transfer(fd, tx, rx, size);
|
||||
free(rx);
|
||||
free(tx);
|
||||
}
|
||||
|
||||
static void transfer_file(int fd, char *filename)
|
||||
{
|
||||
ssize_t bytes;
|
||||
struct stat sb;
|
||||
int tx_fd;
|
||||
uint8_t *tx;
|
||||
uint8_t *rx;
|
||||
|
||||
if (stat(filename, &sb) == -1)
|
||||
pabort("can't stat input file");
|
||||
|
||||
tx_fd = open(filename, O_RDONLY);
|
||||
if (tx_fd < 0)
|
||||
pabort("can't open input file");
|
||||
|
||||
tx = malloc(sb.st_size);
|
||||
if (!tx)
|
||||
pabort("can't allocate tx buffer");
|
||||
|
||||
rx = malloc(sb.st_size);
|
||||
if (!rx)
|
||||
pabort("can't allocate rx buffer");
|
||||
|
||||
bytes = read(tx_fd, tx, sb.st_size);
|
||||
if (bytes != sb.st_size)
|
||||
pabort("failed to read input file");
|
||||
|
||||
transfer(fd, tx, rx, sb.st_size);
|
||||
free(rx);
|
||||
free(tx);
|
||||
close(tx_fd);
|
||||
}
|
||||
|
||||
static uint64_t _read_count;
|
||||
static uint64_t _write_count;
|
||||
|
||||
static void show_transfer_rate(void)
|
||||
{
|
||||
static uint64_t prev_read_count, prev_write_count;
|
||||
double rx_rate, tx_rate;
|
||||
|
||||
rx_rate = ((_read_count - prev_read_count) * 8) / (interval*1000.0);
|
||||
tx_rate = ((_write_count - prev_write_count) * 8) / (interval*1000.0);
|
||||
|
||||
printf("rate: tx %.1fkbps, rx %.1fkbps\n", rx_rate, tx_rate);
|
||||
|
||||
prev_read_count = _read_count;
|
||||
prev_write_count = _write_count;
|
||||
}
|
||||
|
||||
static void transfer_buf(int fd, int len)
|
||||
{
|
||||
uint8_t *tx;
|
||||
uint8_t *rx;
|
||||
int i;
|
||||
|
||||
tx = malloc(len);
|
||||
if (!tx)
|
||||
pabort("can't allocate tx buffer");
|
||||
for (i = 0; i < len; i++)
|
||||
tx[i] = random();
|
||||
|
||||
rx = malloc(len);
|
||||
if (!rx)
|
||||
pabort("can't allocate rx buffer");
|
||||
|
||||
transfer(fd, tx, rx, len);
|
||||
|
||||
_write_count += len;
|
||||
_read_count += len;
|
||||
|
||||
if (mode & SPI_LOOP) {
|
||||
if (memcmp(tx, rx, len)) {
|
||||
fprintf(stderr, "transfer error !\n");
|
||||
hex_dump(tx, len, 32, "TX");
|
||||
hex_dump(rx, len, 32, "RX");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
free(rx);
|
||||
free(tx);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret = 0;
|
||||
int fd;
|
||||
|
||||
parse_opts(argc, argv);
|
||||
|
||||
fd = open(device, O_RDWR);
|
||||
if (fd < 0)
|
||||
pabort("can't open device");
|
||||
|
||||
/*
|
||||
* spi mode
|
||||
*/
|
||||
ret = ioctl(fd, SPI_IOC_WR_MODE32, &mode);
|
||||
if (ret == -1)
|
||||
pabort("can't set spi mode");
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_RD_MODE32, &mode);
|
||||
if (ret == -1)
|
||||
pabort("can't get spi mode");
|
||||
|
||||
/*
|
||||
* bits per word
|
||||
*/
|
||||
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
|
||||
if (ret == -1)
|
||||
pabort("can't set bits per word");
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
|
||||
if (ret == -1)
|
||||
pabort("can't get bits per word");
|
||||
|
||||
/*
|
||||
* max speed hz
|
||||
*/
|
||||
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
|
||||
if (ret == -1)
|
||||
pabort("can't set max speed hz");
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
|
||||
if (ret == -1)
|
||||
pabort("can't get max speed hz");
|
||||
|
||||
printf("spi mode: 0x%x\n", mode);
|
||||
printf("bits per word: %d\n", bits);
|
||||
printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
|
||||
|
||||
if (input_tx && input_file)
|
||||
pabort("only one of -p and --input may be selected");
|
||||
|
||||
if (input_tx)
|
||||
transfer_escaped_string(fd, input_tx);
|
||||
else if (input_file)
|
||||
transfer_file(fd, input_file);
|
||||
else if (transfer_size) {
|
||||
struct timespec last_stat;
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &last_stat);
|
||||
|
||||
while (iterations-- > 0) {
|
||||
struct timespec current;
|
||||
|
||||
transfer_buf(fd, transfer_size);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, ¤t);
|
||||
if (current.tv_sec - last_stat.tv_sec > interval) {
|
||||
show_transfer_rate();
|
||||
last_stat = current;
|
||||
}
|
||||
}
|
||||
printf("total: tx %.1fKB, rx %.1fKB\n",
|
||||
_write_count/1024.0, _read_count/1024.0);
|
||||
} else
|
||||
transfer(fd, default_tx, default_rx, sizeof(default_tx));
|
||||
|
||||
close(fd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,199 +0,0 @@
|
|||
/*
|
||||
* watchdog_test.c
|
||||
*
|
||||
* Copyright (C) 2009-2013 by Digi International Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published by
|
||||
* the Free Software Foundation.
|
||||
*
|
||||
* Description: Watchdog test application
|
||||
*
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/watchdog.h> /* WDIOC_SETTIMEOUT */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define PROGRAM "wd_test"
|
||||
#define VERSION "2.0"
|
||||
|
||||
#define WD_DEVICE_FILE "/dev/watchdog"
|
||||
|
||||
#define wd_test_usage \
|
||||
"[-t timeout (2)] [-d dead | disable (dead)] [-s write | ioctl (write)] [-n test_time (60)]\n"
|
||||
#define wd_test_full_usage \
|
||||
"wd_test [options]\n\n" \
|
||||
"Tests the hardware watchdog\n" \
|
||||
"Options:\n" \
|
||||
" -t : timeout in seconds (default 2)\n" \
|
||||
" -d : dead | disable, action when the test finishs (default dead)\n" \
|
||||
" -s : write | ioctl, system call used to kick the watchdog (default write)\n" \
|
||||
" -n : test duration in seconds (default 60)\n" \
|
||||
" -h : help\n\n"
|
||||
|
||||
/*
|
||||
* Function: wd_test_banner
|
||||
* Description: print message
|
||||
*/
|
||||
static void wd_test_banner(void)
|
||||
{
|
||||
fprintf(stdout, "%s %s Copyright Digi International Inc.\n\n"
|
||||
"Watchdog test/demo application\n\n", PROGRAM, VERSION);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function: exit_error
|
||||
* Description: print error message and exit
|
||||
*/
|
||||
static void exit_error(char *error_msg, int exit_val)
|
||||
{
|
||||
if (error_msg != NULL)
|
||||
fprintf(stderr, "%s", error_msg);
|
||||
|
||||
exit(exit_val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function: show_usage_exit
|
||||
* Description: print usage information and exit
|
||||
*/
|
||||
static void show_usage_exit(int exit_val, int full)
|
||||
{
|
||||
if (full) {
|
||||
wd_test_banner();
|
||||
fprintf(stdout, "%s", wd_test_full_usage);
|
||||
} else {
|
||||
fprintf(stdout, "%s", wd_test_usage);
|
||||
}
|
||||
|
||||
exit_error(NULL, exit_val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function: wd_keep_alive
|
||||
* Description: kick the watchdog using write or ioctl depending on the parameter
|
||||
*/
|
||||
static void wd_keep_alive(int fd, int system_call)
|
||||
{
|
||||
int dummy;
|
||||
|
||||
if (system_call) {
|
||||
if (ioctl(fd, WDIOC_KEEPALIVE, &dummy) < 0) {
|
||||
perror("ioctl");
|
||||
printf("Unable to kick the watchdog.\n");
|
||||
}
|
||||
} else {
|
||||
write(fd, "\0", 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Function: main
|
||||
* Description: application's main function
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int opt;
|
||||
int wd_timeout = 2;
|
||||
int wd_disable = 0;
|
||||
int wd_syscall = 0;
|
||||
int wd_test_time = 60;
|
||||
int wd_fd;
|
||||
|
||||
if (argc > 1) {
|
||||
while ((opt = getopt(argc, argv, "t:d:s:n:h")) > 0) {
|
||||
switch (opt) {
|
||||
case 't':
|
||||
wd_timeout = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
wd_test_time = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (!strcmp(optarg, "dead")) {
|
||||
wd_disable = 0;
|
||||
} else if (!strcmp(optarg, "disable")) {
|
||||
wd_disable = 1;
|
||||
} else {
|
||||
show_usage_exit(EXIT_FAILURE, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (!strcmp(optarg, "write")) {
|
||||
wd_syscall = 0;
|
||||
} else if (!strcmp(optarg, "ioctl")) {
|
||||
wd_syscall = 1;
|
||||
} else {
|
||||
show_usage_exit(EXIT_FAILURE, 0);
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
show_usage_exit((opt == 'h') ? EXIT_SUCCESS : EXIT_FAILURE, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wd_test_banner();
|
||||
|
||||
/* Open watchdog, this will start the watchdog counters */
|
||||
wd_fd = open(WD_DEVICE_FILE, O_RDWR);
|
||||
if (wd_fd < 0) {
|
||||
perror(WD_DEVICE_FILE);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
printf("Watchdog (%s) opened and started\n", WD_DEVICE_FILE);
|
||||
|
||||
if (ioctl(wd_fd, WDIOC_SETTIMEOUT, &wd_timeout) < 0) {
|
||||
perror("ioctl");
|
||||
close(wd_fd);
|
||||
show_usage_exit(EXIT_FAILURE, 0);
|
||||
}
|
||||
printf(" -Setting watchdog timeout to %d (sec)\n", wd_timeout);
|
||||
printf(" -Test will finish with %s\n",
|
||||
wd_disable ? "watchdog disabled" : "board reset");
|
||||
|
||||
printf("\n");
|
||||
|
||||
while (wd_test_time) {
|
||||
wd_keep_alive(wd_fd, wd_syscall);
|
||||
sleep(1);
|
||||
wd_test_time--;
|
||||
printf("\r Remaining time: %d ", wd_test_time);
|
||||
fflush(stdout);
|
||||
}
|
||||
/* Kick it for the last time, so that the last sleep() does
|
||||
* not affect the programmed reset time.
|
||||
*/
|
||||
wd_keep_alive(wd_fd, wd_syscall);
|
||||
printf("\n\n");
|
||||
|
||||
if (wd_disable) {
|
||||
wd_timeout = WDIOS_DISABLECARD;
|
||||
if (ioctl(wd_fd, WDIOC_SETOPTIONS, &wd_timeout) < 0) {
|
||||
perror("ioctl");
|
||||
printf("Unable to disable watchdog. System will reset\n");
|
||||
}
|
||||
else {
|
||||
printf("Disabling watchdog\n");
|
||||
}
|
||||
} else {
|
||||
printf("Sayonara baby...");
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
close(wd_fd);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (C) 2013-2018, Digi International Inc.
|
||||
# Copyright (C) 2013-2019, Digi International Inc.
|
||||
|
||||
SUMMARY = "DEY examples packagegroup"
|
||||
|
||||
|
|
@ -15,13 +15,9 @@ RDEPENDS_${PN} = "\
|
|||
${@bb.utils.contains("MACHINE_FEATURES", "bluetooth", "dey-examples-hdp", "", d)} \
|
||||
${@bb.utils.contains("MACHINE_FEATURES", "cryptochip", "dey-examples-cryptochip", "", d)} \
|
||||
awsiotsdk-demo \
|
||||
dey-examples-can \
|
||||
dey-examples-cloudconnector \
|
||||
dey-examples-digiapix \
|
||||
dey-examples-gpio-sysfs \
|
||||
dey-examples-rtc \
|
||||
dey-examples-spidev \
|
||||
dey-examples-watchdog \
|
||||
"
|
||||
|
||||
RDEPENDS_${PN}_append_ccimx6 = "\
|
||||
|
|
@ -30,13 +26,11 @@ RDEPENDS_${PN}_append_ccimx6 = "\
|
|||
"
|
||||
|
||||
RDEPENDS_${PN}_append_ccimx6ul = "\
|
||||
dey-examples-adc \
|
||||
dey-examples-adc-cmp \
|
||||
dey-examples-tamper \
|
||||
"
|
||||
|
||||
RDEPENDS_${PN}_append_ccimx8x = "\
|
||||
dey-examples-adc \
|
||||
dey-examples-adc-cmp \
|
||||
dey-examples-tamper \
|
||||
dey-examples-v4l2 \
|
||||
|
|
|
|||
Loading…
Reference in New Issue