blob: b3d323ca0a9f487ee2684b29cbcc5f6a16edcebd [file] [log] [blame]
/* Industrialio buffer test code.
*
* 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.
*
* This program is primarily intended as an example application.
* Reads the current buffer setup from sysfs and starts a short capture
* from the specified device, pretty printing the result after appropriate
* conversion.
*
* Command line parameters
* generic_buffer -n <device_name> -t <trigger_name>
* If trigger name is not specified the program assumes you want a dataready
* trigger associated with the device and goes looking for it.
*
*/
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
#include <dirent.h>
#include <linux/types.h>
#include <string.h>
#include <poll.h>
#include "iio_utils.h"
#include "ml_load_dmp.h"
#include "ml_sysfs_helper.h"
#include "authenticate.h"
#define FLICK_SUPPORTED (0)
/**
* size_from_channelarray() - calculate the storage size of a scan
* @channels: the channel info array
* @num_channels: size of the channel info array
*
* Has the side effect of filling the channels[i].location values used
* in processing the buffer output.
**/
int size_from_channelarray(struct iio_channel_info *channels, int num_channels)
{
int bytes = 0;
int i = 0;
while (i < num_channels) {
if (bytes % channels[i].bytes == 0)
channels[i].location = bytes;
else
channels[i].location = bytes - bytes%channels[i].bytes
+ channels[i].bytes;
bytes = channels[i].location + channels[i].bytes;
i++;
}
return bytes;
}
void print2byte(int input, struct iio_channel_info *info)
{
/* shift before conversion to avoid sign extension
of left aligned data */
input = input >> info->shift;
if (info->is_signed) {
int16_t val = input;
val &= (1 << info->bits_used) - 1;
val = (int16_t)(val << (16 - info->bits_used)) >>
(16 - info->bits_used);
/*printf("%d, %05f, scale=%05f", val,
(float)(val + info->offset)*info->scale, info->scale);*/
printf("%d, ", val);
} else {
uint16_t val = input;
val &= (1 << info->bits_used) - 1;
printf("%05f ", ((float)val + info->offset)*info->scale);
}
}
/**
* process_scan() - print out the values in SI units
* @data: pointer to the start of the scan
* @infoarray: information about the channels. Note
* size_from_channelarray must have been called first to fill the
* location offsets.
* @num_channels: the number of active channels
**/
void process_scan(char *data,
struct iio_channel_info *infoarray,
int num_channels)
{
int k;
//char *tmp;
for (k = 0; k < num_channels; k++) {
switch (infoarray[k].bytes) {
/* only a few cases implemented so far */
case 2:
print2byte(*(uint16_t *)(data + infoarray[k].location),
&infoarray[k]);
//tmp = data + infoarray[k].location;
break;
case 4:
if (infoarray[k].is_signed) {
int32_t val = *(int32_t *)
(data +
infoarray[k].location);
if ((val >> infoarray[k].bits_used) & 1)
val = (val & infoarray[k].mask) |
~infoarray[k].mask;
/* special case for timestamp */
printf(" %d ", val);
}
break;
case 8:
if (infoarray[k].is_signed) {
int64_t val = *(int64_t *)
(data +
infoarray[k].location);
if ((val >> infoarray[k].bits_used) & 1)
val = (val & infoarray[k].mask) |
~infoarray[k].mask;
/* special case for timestamp */
if (infoarray[k].scale == 1.0f &&
infoarray[k].offset == 0.0f)
printf(" %lld", val);
else
printf("%05f ", ((float)val +
infoarray[k].offset)*
infoarray[k].scale);
}
break;
default:
break;
}
}
printf("\n");
}
#if FLICK_SUPPORTED /* hide flick, not offially supported */
void enable_flick(char *p, int on){
int ret;
printf("flick:%s\n", p);
ret = write_sysfs_int_and_verify("flick_int_on", p, on);
if (ret < 0)
return;
ret = write_sysfs_int_and_verify("flick_upper", p, 3147790);
if (ret < 0)
return;
ret = write_sysfs_int_and_verify("flick_lower", p, -3147790);
if (ret < 0)
return;
ret = write_sysfs_int_and_verify("flick_counter", p, 50);
if (ret < 0)
return;
ret = write_sysfs_int_and_verify("flick_message_on", p, 0);
if (ret < 0)
return;
ret = write_sysfs_int_and_verify("flick_axis", p, 0);
}
#endif
void HandleOrient(int orient)
{
if (orient & 0x01)
printf("INV_X_UP\n");
if (orient & 0x02)
printf("INV_X_DOWN\n");
if (orient & 0x04)
printf("INV_Y_UP\n");
if (orient & 0x08)
printf("INV_Y_DOWN\n");
if (orient & 0x10)
printf("INV_Z_UP\n");
if (orient & 0x20)
printf("INV_Z_DOWN\n");
if (orient & 0x40)
printf("INV_ORIENTATION_FLIP\n");
}
void HandleTap(int tap)
{
int tap_dir = tap/8;
int tap_num = tap%8 + 1;
switch (tap_dir) {
case 1:
printf("INV_TAP_AXIS_X_POS\n");
break;
case 2:
printf("INV_TAP_AXIS_X_NEG\n");
break;
case 3:
printf("INV_TAP_AXIS_Y_POS\n");
break;
case 4:
printf("INV_TAP_AXIS_Y_NEG\n");
break;
case 5:
printf("INV_TAP_AXIS_Z_POS\n");
break;
case 6:
printf("INV_TAP_AXIS_Z_NEG\n");
break;
default:
break;
}
printf("Tap number: %d\n", tap_num);
}
#define DMP_CODE_SIZE 3060
void verify_img(char *dmp_path){
FILE *fp;
int i;
char dmp_img[DMP_CODE_SIZE];
if ((fp = fopen(dmp_path, "rb")) < 0 ) {
perror("dmp fail");
}
i = fread(dmp_img, 1, DMP_CODE_SIZE, fp);
printf("Result=%d\n", i);
fclose(fp);
fp = fopen("/dev/read_img.h", "wt");
fprintf(fp, "char rec[]={\n");
for(i=0; i<DMP_CODE_SIZE; i++) {
fprintf(fp, "0x%02x, ", dmp_img[i]);
if(((i+1)%16) == 0) {
fprintf(fp, "\n");
}
}
fprintf(fp, "};\n ");
fclose(fp);
}
void setup_dmp(char *dev_path, int p_event){
char sysfs_path[200];
char dmp_path[200];
int ret;
FILE *fd;
sprintf(sysfs_path, "%s", dev_path);
printf("sysfs: %s\n", sysfs_path);
ret = write_sysfs_int_and_verify("power_state", sysfs_path, 1);
if (ret < 0)
return;
ret = write_sysfs_int("in_accel_scale", dev_path, 0);
if (ret < 0)
return;
ret = write_sysfs_int("in_anglvel_scale", dev_path, 2);
if (ret < 0)
return;
ret = write_sysfs_int("sampling_frequency", sysfs_path, 200);
if (ret < 0)
return;
ret = write_sysfs_int_and_verify("firmware_loaded", sysfs_path, 0);
if (ret < 0)
return;
sprintf(dmp_path, "%s/dmp_firmware", dev_path);
if ((fd = fopen(dmp_path, "wb")) < 0 ) {
perror("dmp fail");
}
inv_load_dmp(fd);
fclose(fd);
printf("firmware_loaded=%d\n", read_sysfs_posint("firmware_loaded", sysfs_path));
ret = write_sysfs_int_and_verify("in_accel_x_offset", sysfs_path, 0xabcd0000);
ret = write_sysfs_int_and_verify("in_accel_y_offset", sysfs_path, 0xffff0000);
ret = write_sysfs_int_and_verify("in_accel_z_offset", sysfs_path, 0xcdef0000);
ret = write_sysfs_int_and_verify("dmp_on", sysfs_path, 1);
if (ret < 0)
return;
ret = write_sysfs_int_and_verify("dmp_int_on", sysfs_path, 1);
if (ret < 0)
return;
/* selelct which event to enable and interrupt on/off here */
//enable_flick(sysfs_path, 1);
ret = write_sysfs_int_and_verify("tap_on", sysfs_path, 1);
if (ret < 0)
return;
ret = write_sysfs_int_and_verify("display_orientation_on", sysfs_path, 1);
if (ret < 0)
return;
ret = write_sysfs_int_and_verify("orientation_on", sysfs_path, 1);
if (ret < 0)
return;
printf("rate\n");
ret = write_sysfs_int_and_verify("dmp_output_rate", sysfs_path, 25);
if (ret < 0)
return;
ret = write_sysfs_int_and_verify("dmp_event_int_on", sysfs_path, p_event);
if (ret < 0)
return;
//verify_img(dmp_path);
}
void get_dmp_event(char *dev_dir_name)
{
char file_name[100];
int i;
#if FLICK_SUPPORTED /* hide flick, not offially supported */
int fp_tap, fp_orient, fp_disp, fp_flick;
const int n_gest = 6;
#else
int fp_tap, fp_orient, fp_disp, fp_motion;
//int fp_no_motion;
const int n_gest = 4;
#endif
int data;
char d[6];
FILE *fp;
struct pollfd pfd[4];
printf("%s\n", dev_dir_name);
while(1) {
sprintf(file_name, "%s/event_tap", dev_dir_name);
fp_tap = open(file_name, O_RDONLY | O_NONBLOCK);
sprintf(file_name, "%s/event_orientation", dev_dir_name);
fp_orient = open(file_name, O_RDONLY | O_NONBLOCK);
sprintf(file_name, "%s/event_display_orientation", dev_dir_name);
fp_disp = open(file_name, O_RDONLY | O_NONBLOCK);
//sprintf(file_name, "%s/event_accel_motion", dev_dir_name);
sprintf(file_name, "%s/event_accel_wom", dev_dir_name);
fp_motion = open(file_name, O_RDONLY | O_NONBLOCK);
//sprintf(file_name, "%s/event_accel_no_motion", dev_dir_name);
//fp_no_motion = open(file_name, O_RDONLY | O_NONBLOCK);
#if FLICK_SUPPORTED /* hide flick, not offially supported */
sprintf(file_name, "%s/event_flick", dev_dir_name);
fp_flick = open(file_name, O_RDONLY | O_NONBLOCK);
#endif
pfd[0].fd = fp_tap;
pfd[0].events = POLLPRI|POLLERR,
pfd[0].revents = 0;
pfd[1].fd = fp_orient;
pfd[1].events = POLLPRI|POLLERR,
pfd[1].revents = 0;
pfd[2].fd = fp_disp;
pfd[2].events = POLLPRI|POLLERR,
pfd[2].revents = 0;
pfd[3].fd = fp_motion;
pfd[3].events = POLLPRI|POLLERR,
pfd[3].revents = 0;
//pfd[4].fd = fp_no_motion;
//pfd[4].events = POLLPRI|POLLERR,
//pfd[4].revents = 0;
#if FLICK_SUPPORTED /* hide flick, not offially supported */
pfd[5].fd = fp_flick;
pfd[5].events = POLLPRI|POLLERR,
pfd[5].revents = 0;
#endif
read(fp_tap, d, 4);
read(fp_orient, d, 4);
read(fp_disp, d, 4);
read(fp_motion, d, 4);
//read(fp_no_motion, d, 4);
#if FLICK_SUPPORTED /* hide flick, not offially supported */
read(fp_flick, d, 4);
#endif
poll(pfd, n_gest, -1);
close(fp_tap);
close(fp_orient);
close(fp_disp);
close(fp_motion);
//close(fp_no_motion);
#if FLICK_SUPPORTED /* hide flick, not offially supported */
close(fp_flick);
#endif
for (i = 0; i < ARRAY_SIZE(pfd); i++) {
if(pfd[i].revents != 0) {
switch (i){
case 0:
sprintf(file_name, "%s/event_tap", dev_dir_name);
fp = fopen(file_name, "rt");
fscanf(fp, "%d\n", &data);
printf("tap=%x\n", data);
HandleTap(data);
fclose(fp);
break;
case 1:
sprintf(file_name, "%s/event_orientation", dev_dir_name);
fp = fopen(file_name, "rt");
fscanf(fp, "%d\n", &data);
printf("orient=%x\n", data);
HandleOrient(data);
fclose(fp);
break;
case 2:
sprintf(file_name, "%s/event_display_orientation", dev_dir_name);
fp = fopen(file_name, "rt");
fscanf(fp, "%d\n", &data);
printf("display_orient=%x\n", data);
fclose(fp);
break;
case 3:
sprintf(file_name, "%s/event_accel_wom", dev_dir_name);
fp = fopen(file_name, "rt");
fscanf(fp, "%d\n", &data);
printf("motion=%x\n", data);
fclose(fp);
break;
case 4:
sprintf(file_name, "%s/event_accel_no_motion", dev_dir_name);
fp = fopen(file_name, "rt");
fscanf(fp, "%d\n", &data);
printf("No motion=%x\n", data);
fclose(fp);
break;
#if FLICK_SUPPORTED /* hide flick, not offially supported */
case 5:
sprintf(file_name, "%s/event_flick", dev_dir_name);
fp = fopen(file_name, "rt");
fscanf(fp, "%d\n", &data);
printf("flick=%x\n", data);
fclose(fp);
break;
#endif
}
}
}
}
}
int main(int argc, char **argv)
{
unsigned long num_loops = 2;
unsigned long timedelay = 100000;
unsigned long buf_len = 128;
int ret, c, i, j, toread;
int fp;
int num_channels;
char *trigger_name = NULL;
char *dev_dir_name, *buf_dir_name;
int datardytrigger = 1;
char *data;
int read_size;
int dev_num, trig_num;
char *buffer_access;
int scan_size;
int noevents = 0;
int p_event = 0, nodmp = 0;
char *dummy;
char chip_name[10];
char device_name[10];
char sysfs[100];
struct iio_channel_info *infoarray;
/* -r means no DMP is enabled (raw) -> should be used for mpu3050.
-p means no print of data */
/* when using -p, 1 means orientation, 2 means tap, 3 means flick */
while ((c = getopt(argc, argv, "l:w:c:pret:")) != -1) {
switch (c) {
case 't':
trigger_name = optarg;
datardytrigger = 0;
break;
case 'e':
noevents = 1;
break;
case 'p':
p_event = 1;
break;
case 'r':
nodmp = 1;
break;
case 'c':
num_loops = strtoul(optarg, &dummy, 10);
break;
case 'w':
timedelay = strtoul(optarg, &dummy, 10);
break;
case 'l':
buf_len = strtoul(optarg, &dummy, 10);
break;
case '?':
return -1;
}
}
inv_get_sysfs_path(sysfs);
printf("sss:::%s\n", sysfs);
if (inv_get_chip_name(chip_name) != INV_SUCCESS) {
printf("get chip name fail\n");
exit(0);
}
printf("chip_name=%s\n", chip_name);
if (INV_SUCCESS != inv_check_key())
printf("key check fail\n");
else
printf("key authenticated\n");
for (i=0; i<strlen(chip_name); i++) {
device_name[i] = tolower(chip_name[i]);
}
device_name[strlen(chip_name)] = '\0';
printf("device name: %s\n", device_name);
/* Find the device requested */
dev_num = find_type_by_name(device_name, "iio:device");
if (dev_num < 0) {
printf("Failed to find the %s\n", device_name);
ret = -ENODEV;
goto error_ret;
}
printf("iio device number being used is %d\n", dev_num);
asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num);
if (trigger_name == NULL) {
/*
* Build the trigger name. If it is device associated it's
* name is <device_name>_dev[n] where n matches the device
* number found above
*/
ret = asprintf(&trigger_name,
"%s-dev%d", device_name, dev_num);
if (ret < 0) {
ret = -ENOMEM;
goto error_ret;
}
}
ret = write_sysfs_int("buffer/enable", dev_dir_name, 0);
ret = write_sysfs_int_and_verify("power_state", dev_dir_name, 1);
ret = write_sysfs_int_and_verify("gyro_enable", dev_dir_name, 1);
ret = write_sysfs_int_and_verify("accl_enable", dev_dir_name, 1);
ret = write_sysfs_int_and_verify("compass_enable", dev_dir_name, 1);
/*
ret = write_sysfs_int_and_verify("zero_motion_on", dev_dir_name, 1);
ret = write_sysfs_int_and_verify("zero_motion_dur", dev_dir_name, 12);
ret = write_sysfs_int_and_verify("zero_motion_threshold", dev_dir_name, 13);
ret = write_sysfs_int_and_verify("motion_on", dev_dir_name, 1);
ret = write_sysfs_int_and_verify("motion_dur", dev_dir_name, 1);
ret = write_sysfs_int_and_verify("motion_threshold", dev_dir_name, 1);
*/
ret = write_sysfs_int_and_verify("accel_wom_on", dev_dir_name, 1);
ret = write_sysfs_int_and_verify("accel_wom_threshold", dev_dir_name, 100);
/* Verify the trigger exists */
trig_num = find_type_by_name(trigger_name, "trigger");
if (trig_num < 0) {
printf("Failed to find the trigger %s\n", trigger_name);
ret = -ENODEV;
goto error_free_triggername;
}
printf("iio trigger number being used is %d\n", trig_num);
/*
* Parse the files in scan_elements to identify what channels are
* present
*/
ret = 0;
ret = enable(dev_dir_name, &infoarray, &num_channels);
if (ret) {
printf("error enable\n");
goto error_free_triggername;
}
if (!nodmp)
setup_dmp(dev_dir_name, p_event);
/*
* Construct the directory name for the associated buffer.
* As we know that the lis3l02dq has only one buffer this may
* be built rather than found.
*/
ret = asprintf(&buf_dir_name, "%siio:device%d/buffer", iio_dir, dev_num);
if (ret < 0) {
ret = -ENOMEM;
goto error_free_triggername;
}
printf("%s %s\n", dev_dir_name, trigger_name);
/* Set the device trigger to be the data rdy trigger found above */
ret = write_sysfs_string_and_verify("trigger/current_trigger",
dev_dir_name,
trigger_name);
if (ret < 0) {
printf("Failed to write current_trigger file\n");
goto error_free_buf_dir_name;
}
/* Setup ring buffer parameters */
/* length must be even number because iio_store_to_sw_ring is expecting
half pointer to be equal to the read pointer, which is impossible
when buflen is odd number. This is actually a bug in the code */
ret = write_sysfs_int("length", buf_dir_name, buf_len*2);
if (ret < 0)
goto exit_here;
ret = write_sysfs_int_and_verify("gyro_enable", dev_dir_name, 1);
ret = write_sysfs_int_and_verify("accl_enable", dev_dir_name, 1);
//ret = write_sysfs_int_and_verify("compass_enable", dev_dir_name, 0);
if (nodmp == 0) {
ret = write_sysfs_int_and_verify("quaternion_on", dev_dir_name, 1);
} else {
ret = disable_q_out(dev_dir_name, &infoarray, &num_channels);
ret = write_sysfs_int_and_verify("dmp_on", dev_dir_name, 0);
}
ret = build_channel_array(dev_dir_name, &infoarray, &num_channels);
if (ret) {
printf("Problem reading scan element information\n");
goto exit_here;
}
/* Enable the buffer */
ret = write_sysfs_int("enable", buf_dir_name, 1);
if (ret < 0)
goto exit_here;
scan_size = size_from_channelarray(infoarray, num_channels);
data = malloc(scan_size*buf_len);
if (!data) {
ret = -ENOMEM;
goto exit_here;
}
ret = asprintf(&buffer_access,
"/dev/iio:device%d",
dev_num);
if (ret < 0) {
ret = -ENOMEM;
goto error_free_data;
}
if (p_event) {
get_dmp_event(dev_dir_name);
goto error_free_buffer_access;
}
/* Attempt to open non blocking the access dev */
fp = open(buffer_access, O_RDONLY | O_NONBLOCK);
if (fp == -1) { /*If it isn't there make the node */
printf("Failed to open %s\n", buffer_access);
ret = -errno;
goto error_free_buffer_access;
}
/* Wait for events 10 times */
for (j = 0; j < num_loops; j++) {
if (!noevents) {
struct pollfd pfd = {
.fd = fp,
.events = POLLIN,
};
poll(&pfd, 1, -1);
toread = 1;
if ((j%128)==0)
usleep(timedelay);
} else {
usleep(timedelay);
toread = 1;
}
read_size = read(fp,
data,
toread*scan_size);
if (read_size == -EAGAIN) {
printf("nothing available\n");
continue;
}
if (0 == p_event) {
for (i = 0; i < read_size/scan_size; i++)
process_scan(data + scan_size*i,
infoarray,
num_channels);
}
}
close(fp);
error_free_buffer_access:
free(buffer_access);
error_free_data:
free(data);
exit_here:
/* Stop the ring buffer */
ret = write_sysfs_int("enable", buf_dir_name, 0);
error_free_buf_dir_name:
free(buf_dir_name);
error_free_triggername:
if (datardytrigger)
free(trigger_name);
error_ret:
return ret;
}