2010-10-08 12:14:14 +01:00
/* 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>
2015-02-26 10:49:24 +02:00
# include <stdlib.h>
2010-10-08 12:14:14 +01:00
# include <dirent.h>
# include <fcntl.h>
# include <stdio.h>
# include <errno.h>
# include <sys/stat.h>
# include <sys/dir.h>
# include <linux/types.h>
2011-02-11 13:09:12 +00:00
# include <string.h>
2011-05-18 14:41:19 +01:00
# include <poll.h>
2011-12-04 19:10:59 +00:00
# include <endian.h>
2012-06-25 23:12:17 +02:00
# include <getopt.h>
2012-06-25 23:12:16 +02:00
# include <inttypes.h>
2010-10-08 12:14:14 +01:00
# include "iio_utils.h"
/**
* size_from_channelarray ( ) - calculate the storage size of a scan
2012-06-25 23:12:14 +02:00
* @ channels : the channel info array
* @ num_channels : number of channels
2010-10-08 12:14:14 +01:00
*
* 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 ;
2014-10-03 23:34:50 +03:00
2010-10-08 12:14:14 +01:00
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 ;
}
2011-05-18 14:41:19 +01:00
void print2byte ( int input , struct iio_channel_info * info )
{
2011-12-04 19:10:59 +00:00
/* First swap if incorrect endian */
if ( info - > be )
2012-04-10 21:11:04 +01:00
input = be16toh ( ( uint16_t ) input ) ;
2011-12-04 19:10:59 +00:00
else
2012-04-10 21:11:04 +01:00
input = le16toh ( ( uint16_t ) input ) ;
2011-12-04 19:10:59 +00:00
2012-06-25 23:12:14 +02:00
/*
* Shift before conversion to avoid sign extension
* of left aligned data
*/
2015-02-26 11:45:26 +02:00
input > > = info - > shift ;
2011-05-18 14:41:19 +01:00
if ( info - > is_signed ) {
int16_t val = input ;
2014-10-03 23:34:50 +03:00
2011-05-18 14:41:19 +01:00
val & = ( 1 < < info - > bits_used ) - 1 ;
val = ( int16_t ) ( val < < ( 16 - info - > bits_used ) ) > >
( 16 - info - > bits_used ) ;
2012-06-25 23:12:11 +02:00
printf ( " %05f " , ( ( float ) val + info - > offset ) * info - > scale ) ;
2011-05-18 14:41:19 +01:00
} else {
uint16_t val = input ;
2014-10-03 23:34:50 +03:00
2011-05-18 14:41:19 +01:00
val & = ( 1 < < info - > bits_used ) - 1 ;
printf ( " %05f " , ( ( float ) val + info - > offset ) * info - > scale ) ;
}
}
2010-10-08 12:14:14 +01:00
/**
* process_scan ( ) - print out the values in SI units
* @ data : pointer to the start of the scan
2012-06-25 23:12:14 +02:00
* @ channels : information about the channels . Note
2010-10-08 12:14:14 +01:00
* size_from_channelarray must have been called first to fill the
* location offsets .
2012-06-25 23:12:14 +02:00
* @ num_channels : number of channels
2010-10-08 12:14:14 +01:00
* */
void process_scan ( char * data ,
2012-06-25 23:12:14 +02:00
struct iio_channel_info * channels ,
2010-10-08 12:14:14 +01:00
int num_channels )
{
int k ;
2014-10-03 23:34:50 +03:00
2010-10-08 12:14:14 +01:00
for ( k = 0 ; k < num_channels ; k + + )
2012-06-25 23:12:14 +02:00
switch ( channels [ k ] . bytes ) {
2010-10-08 12:14:14 +01:00
/* only a few cases implemented so far */
case 2 :
2012-06-25 23:12:14 +02:00
print2byte ( * ( uint16_t * ) ( data + channels [ k ] . location ) ,
& channels [ k ] ) ;
2010-10-08 12:14:14 +01:00
break ;
2012-08-12 16:21:00 +01:00
case 4 :
if ( ! channels [ k ] . is_signed ) {
uint32_t val = * ( uint32_t * )
( data + channels [ k ] . location ) ;
printf ( " %05f " , ( ( float ) val +
channels [ k ] . offset ) *
channels [ k ] . scale ) ;
}
break ;
2010-10-08 12:14:14 +01:00
case 8 :
2012-06-25 23:12:14 +02:00
if ( channels [ k ] . is_signed ) {
2010-10-08 12:14:14 +01:00
int64_t val = * ( int64_t * )
( data +
2012-06-25 23:12:14 +02:00
channels [ k ] . location ) ;
if ( ( val > > channels [ k ] . bits_used ) & 1 )
val = ( val & channels [ k ] . mask ) |
~ channels [ k ] . mask ;
2010-10-08 12:14:14 +01:00
/* special case for timestamp */
2012-06-25 23:12:14 +02:00
if ( channels [ k ] . scale = = 1.0f & &
channels [ k ] . offset = = 0.0f )
2012-06-25 23:12:16 +02:00
printf ( " % " PRId64 " " , val ) ;
2010-10-08 12:14:14 +01:00
else
printf ( " %05f " , ( ( float ) val +
2012-06-25 23:12:14 +02:00
channels [ k ] . offset ) *
channels [ k ] . scale ) ;
2010-10-08 12:14:14 +01:00
}
break ;
default :
break ;
}
printf ( " \n " ) ;
}
int main ( int argc , char * * argv )
{
2011-02-11 13:09:13 +00:00
unsigned long num_loops = 2 ;
unsigned long timedelay = 1000000 ;
unsigned long buf_len = 128 ;
2010-10-08 12:14:14 +01:00
int ret , c , i , j , toread ;
int fp ;
int num_channels ;
char * trigger_name = NULL , * device_name = NULL ;
char * dev_dir_name , * buf_dir_name ;
int datardytrigger = 1 ;
char * data ;
2011-04-15 18:56:00 +01:00
ssize_t read_size ;
2010-10-08 12:14:14 +01:00
int dev_num , trig_num ;
2011-05-18 14:41:19 +01:00
char * buffer_access ;
2010-10-08 12:14:14 +01:00
int scan_size ;
2011-02-11 13:09:12 +00:00
int noevents = 0 ;
2014-11-04 15:29:39 +01:00
int notrigger = 0 ;
2011-02-11 13:09:13 +00:00
char * dummy ;
2010-10-08 12:14:14 +01:00
2012-06-25 23:12:14 +02:00
struct iio_channel_info * channels ;
2010-10-08 12:14:14 +01:00
2014-11-04 15:29:39 +01:00
while ( ( c = getopt ( argc , argv , " l:w:c:et:n:g " ) ) ! = - 1 ) {
2010-10-08 12:14:14 +01:00
switch ( c ) {
case ' n ' :
device_name = optarg ;
break ;
case ' t ' :
trigger_name = optarg ;
datardytrigger = 0 ;
break ;
2011-02-11 13:09:12 +00:00
case ' e ' :
noevents = 1 ;
break ;
2011-02-11 13:09:13 +00:00
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 ;
2014-11-04 15:29:39 +01:00
case ' g ' :
notrigger = 1 ;
break ;
2010-10-08 12:14:14 +01:00
case ' ? ' :
return - 1 ;
}
}
2011-02-24 16:34:50 +01:00
if ( device_name = = NULL )
return - 1 ;
2010-10-08 12:14:14 +01:00
/* Find the device requested */
2011-08-30 12:32:47 +01:00
dev_num = find_type_by_name ( device_name , " iio:device " ) ;
2010-10-08 12:14:14 +01:00
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 ) ;
2011-08-30 12:32:47 +01:00
asprintf ( & dev_dir_name , " %siio:device%d " , iio_dir , dev_num ) ;
2014-11-04 15:29:39 +01:00
if ( ! notrigger ) {
if ( trigger_name = = NULL ) {
/*
* Build the trigger name . If it is device associated
* its 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 ;
}
2010-10-08 12:14:14 +01:00
}
2014-11-04 15:29:39 +01:00
/* 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 ) ;
} else
printf ( " trigger-less mode selected \n " ) ;
2010-10-08 12:14:14 +01:00
/*
* Parse the files in scan_elements to identify what channels are
* present
*/
2012-06-25 23:12:14 +02:00
ret = build_channel_array ( dev_dir_name , & channels , & num_channels ) ;
2010-10-08 12:14:14 +01:00
if ( ret ) {
2011-05-18 14:41:19 +01:00
printf ( " Problem reading scan element information \n " ) ;
2011-08-30 12:32:47 +01:00
printf ( " diag %s \n " , dev_dir_name ) ;
2010-10-08 12:14:14 +01:00
goto error_free_triggername ;
}
/*
* 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 .
*/
2011-08-30 12:32:47 +01:00
ret = asprintf ( & buf_dir_name ,
" %siio:device%d/buffer " , iio_dir , dev_num ) ;
2010-10-08 12:14:14 +01:00
if ( ret < 0 ) {
ret = - ENOMEM ;
goto error_free_triggername ;
}
2014-11-04 15:29:39 +01:00
if ( ! notrigger ) {
printf ( " %s %s \n " , dev_dir_name , trigger_name ) ;
/* Set the device trigger to be the data ready 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 ;
}
2010-10-08 12:14:14 +01:00
}
/* Setup ring buffer parameters */
ret = write_sysfs_int ( " length " , buf_dir_name , buf_len ) ;
if ( ret < 0 )
goto error_free_buf_dir_name ;
/* Enable the buffer */
ret = write_sysfs_int ( " enable " , buf_dir_name , 1 ) ;
if ( ret < 0 )
goto error_free_buf_dir_name ;
2012-06-25 23:12:14 +02:00
scan_size = size_from_channelarray ( channels , num_channels ) ;
2010-10-08 12:14:14 +01:00
data = malloc ( scan_size * buf_len ) ;
if ( ! data ) {
ret = - ENOMEM ;
goto error_free_buf_dir_name ;
}
2011-08-30 12:32:47 +01:00
ret = asprintf ( & buffer_access , " /dev/iio:device%d " , dev_num ) ;
2010-10-08 12:14:14 +01:00
if ( ret < 0 ) {
ret = - ENOMEM ;
goto error_free_data ;
}
/* Attempt to open non blocking the access dev */
fp = open ( buffer_access , O_RDONLY | O_NONBLOCK ) ;
2012-06-25 23:12:14 +02:00
if ( fp = = - 1 ) { /* If it isn't there make the node */
2010-10-08 12:14:14 +01:00
printf ( " Failed to open %s \n " , buffer_access ) ;
ret = - errno ;
2011-05-18 14:41:19 +01:00
goto error_free_buffer_access ;
2010-10-08 12:14:14 +01:00
}
/* Wait for events 10 times */
for ( j = 0 ; j < num_loops ; j + + ) {
2011-02-11 13:09:12 +00:00
if ( ! noevents ) {
2011-05-18 14:41:19 +01:00
struct pollfd pfd = {
. fd = fp ,
. events = POLLIN ,
} ;
poll ( & pfd , 1 , - 1 ) ;
toread = buf_len ;
2011-02-11 13:09:12 +00:00
} else {
2011-02-11 13:09:13 +00:00
usleep ( timedelay ) ;
2011-02-11 13:09:12 +00:00
toread = 64 ;
2010-10-08 12:14:14 +01:00
}
2011-02-11 13:09:12 +00:00
2010-10-08 12:14:14 +01:00
read_size = read ( fp ,
data ,
toread * scan_size ) ;
2014-12-06 06:00:00 +00:00
if ( read_size < 0 ) {
if ( errno = = - EAGAIN ) {
printf ( " nothing available \n " ) ;
continue ;
} else
break ;
2010-10-08 12:14:14 +01:00
}
for ( i = 0 ; i < read_size / scan_size ; i + + )
process_scan ( data + scan_size * i ,
2012-06-25 23:12:14 +02:00
channels ,
2010-10-08 12:14:14 +01:00
num_channels ) ;
}
2012-06-25 23:12:14 +02:00
/* Stop the buffer */
2010-10-08 12:14:14 +01:00
ret = write_sysfs_int ( " enable " , buf_dir_name , 0 ) ;
if ( ret < 0 )
2011-05-18 14:41:19 +01:00
goto error_close_buffer_access ;
2010-10-08 12:14:14 +01:00
2014-11-04 15:29:39 +01:00
if ( ! notrigger )
/* Disconnect the trigger - just write a dummy name. */
write_sysfs_string ( " trigger/current_trigger " ,
dev_dir_name , " NULL " ) ;
2010-10-08 12:14:14 +01:00
error_close_buffer_access :
close ( fp ) ;
error_free_data :
free ( data ) ;
error_free_buffer_access :
free ( buffer_access ) ;
error_free_buf_dir_name :
free ( buf_dir_name ) ;
error_free_triggername :
if ( datardytrigger )
free ( trigger_name ) ;
error_ret :
return ret ;
}