[prev in list] [next in list] [prev in thread] [next in thread]
List: comedi
Subject: Re: RTAI and Comedi: Problems with commands
From: "Andreas Leuner" <al14 () inf ! tu-dresden ! de>
Date: 2006-11-07 15:59:18
Message-ID: 58008.145.254.71.82.1162915158.squirrel () mail ! inf ! tu-dresden ! de
[Download RAW message or body]
> Hi everybody,
>
> I am trying to use the comedi commands using RTAI (RTAI 3.3CV, latest
> comedi/comedilib). On the RTAI CVS I have found an (old?) example
testa.c > that I used as base.
> I have debugged into the driver (I use a simple PCI NI 6024-E) and I found
> out that the data is transferred correctly via DMA to the async
> prealloc_buf.
I have used both a PCI NI 6024-E and a DAQCard NI 6024-E successfully
(read on!) ...
> It seams as the only thing that misses is the transfer from the internal
> (kernel space) memory that holds the input values (written by DMA) to the
> user space value.
>
> One strange thing that I have detected was the following:
> The function rt_comedi_alloc_cmd() sets internally the values of cmd->data
> and cmd->chanlist and returns the values in the arguments **chanlist and
> **data.
> However, when testa returns from comedi_command_test() the value of
> cmd->data has changed - it points now somewhere in a 0xexxxxxxx address
> space.
> Could this be an issue?
Exactly...
The buffer address returned by comedi_command_test() seems to be a kernel
space address and not directly usable by an lxrt userspace program.
The LXRT support for comedi _commands_ has been broken for a few years
(since 2002?) now.
At that time the comedi drivers must have been changed to no longer access
the buffer made known to them via "data" in rt_comedi_alloc_cmd().
Instead they read from/write to a transfer buffer preallocated per
subdevice at module load time or even only at the time a device is
configured.
LXRT-Comedi has never been accomodated to that change.
>
> Is there somewhere a running example available that shows working comedi
> commands with RTAI?
I had to make that stuff work for myself last year -- a little rewrite of
rtai_comedi.h and kcomedi_module.c from addons/comedi subdirectory of rtai
sources.
They can be used as drop-in replacements for the original files from RTAI
versions from at least 3.1. However they miss support for one kcomedilib
call that has been added to magma CVS meanwhile.
I have made a new version of rt_comedi_alloc_cmd -- its interface is no
longer source compatible to the old one.
Please be aware that its method to make the buffer available to lxrt user
space is at least questionable -- but it works for me.
The userspace non-rt comedilib just makes the transfer buffer available as
a mmap()able device (/dev/comediX) -- which is far better but not
supported by _kcomedilib_.
My kernel-side implementation of rt_comedi_alloc_cmd _fakes_ the
allocation of a SHM segment for the transfer buffer and provides its lxrt
name for userspace. That might be *dangerous* if the module is removed
before rt_comedi_free_cmd has been called. Just look at a dmesg trace of
this.
I'll attach my modified files to this mail together with a modified
"testa.c" example. In it you'll find a use case for
rt_comedi_mark_wait_munge(..) -- which I added to LXRT-Comedi.
My solution is by no means elegant -- better would be to modify kcomedilib
to support userspace mmap()ing /dev/comediX just like comedilib does.
Look at comedilib/demo/mmap.c of the comedilib distribution for an example
of using that support.
Since these files are derivatives of RTAI sources I offer them under the
same licenses and the same warranty disclaimer :-)
Good luck
Andreas Leuner
["kcomedi-module.c" (text/x-csrc)]
/*
* Copyright (C) 2002 Thomas Leibner (leibner@t-online.de) (first complete writeup)
* 2002 David Schleef (ds@schleef.org) (COMEDI master)
* 2002 Lorenzo Dozio (dozio@aero.polimi.it) (made it all work)
* 2002 Paolo Mantegazza (mantegazza@aero.polimi.it) (hints/support)
*
* 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, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/**
* This file is the kernel module counterpart of the KComedi-LXRT support.
* It will be compiled to a rtai_comedi.o kernel module.
*/
#include <linux/module.h>
#include <linux/version.h>
#include <asm/uaccess.h>
#include <rtai_sched.h>
#include <rtai_lxrt.h>
#include <rtai_shm.h>
#include <rtai_registry.h>
#include <rtai_comedi.h>
#define MODULE_NAME "rtai_comedi.o"
MODULE_DESCRIPTION("RTAI LXRT binding for COMEDI kcomedilib");
MODULE_AUTHOR("Thomas Leibner <tl@leibner-it.de>");
MODULE_LICENSE("GPL");
static int rtai_comedi_callback(unsigned int, SEM *) __attribute__ ((__unused__));
static int rtai_comedi_callback(unsigned int val, SEM *sem)
{
sem->owndby = (void *)val;
//rt_printk("CALLBACK MASK: %u\n", val);
rt_sem_signal(sem);
return 0;
}
int rt_comedi_register_callback(void *dev, unsigned int subdev, unsigned int mask, \
SEM *sem) {
sem->type = (CNT_SEM & 3) - 2;
return comedi_register_callback(dev, subdev, mask, (void *)rtai_comedi_callback, \
sem); }
unsigned int rt_comedi_wait(SEM *sem, int *semcnt)
{
int count;
count = rt_sem_wait(sem);
if (semcnt) {
*semcnt = count;
}
return (unsigned int)sem->owndby;
}
unsigned int rt_comedi_mark_wait_munge( void *dev, unsigned int subdev, int oldbytes, \
int *newbytes, SEM *sem, int *semcnt ) {
int count;
//newbytes _must not_ be NULL - for now still checked
if (newbytes == 0)
{
rt_printk("rt_comedi_mark_wait_munge: newbytes==0");
return 0;
}
if (sem == 0)
{
rt_printk("rt_comedi_mark_wait_munge: sem==0");
return 0;
}
if (oldbytes != 0) {
int type;
type = comedi_get_subdevice_type(dev, subdev);
switch (type){
case COMEDI_SUBD_AI :
case COMEDI_SUBD_DI : comedi_mark_buffer_read(dev,subdev,oldbytes); break;
/* comedi_mark_buffer_written is not (yet) part of kcomedilib api
case COMEDI_SUBD_AO :
case COMEDI_SUBD_DO : comedi_mark_buffer_written(dev,subdev,oldbytes); break;
*/
//TODO what about bidirectional devices? find out if DI or DO in progress
case COMEDI_SUBD_DIO: break;
default: return 0;
}
}
count = rt_sem_wait(sem);
*newbytes = comedi_get_buffer_contents(dev,subdev);
if (semcnt) {
*semcnt = count;
}
return (unsigned int)sem->owndby;
}
unsigned int rt_comedi_wait_if(SEM *sem, int *semcnt)
{
int count;
count = rt_sem_wait_if(sem);
if (semcnt) {
*semcnt = count;
}
return (unsigned int)sem->owndby;
}
unsigned int rt_comedi_wait_until(SEM *sem, RTIME until, int *semcnt)
{
int count;
count = rt_sem_wait_until(sem, until);
if (semcnt) {
*semcnt = count;
}
return (unsigned int)sem->owndby;
}
unsigned int rt_comedi_wait_timed(SEM *sem, RTIME delay, int *semcnt)
{
int count;
count = rt_sem_wait_timed(sem, delay);
if (semcnt) {
*semcnt = count;
}
return (unsigned int)sem->owndby;
}
char *rt_comedi_get_driver_name(void *dev, char *name)
{
void *p;
if ((p = comedi_get_driver_name((void *)dev)) != 0) {
strncpy(name, p, COMEDI_NAMELEN);
return name;
};
return 0;
}
char *rt_comedi_get_board_name(void *dev, char *name)
{
void *p;
if ((p = comedi_get_board_name((void *)dev)) != 0) {
strncpy(name, p, COMEDI_NAMELEN);
return name;
}
return 0;
}
struct rt_cmd { comedi_cmd cmd; void *kcmd, *kchanlist, *kdata; unsigned long name; \
}; static unsigned long namebase = (unsigned long)&namebase;
static int rt_comedi_command(void *dev, struct rt_cmd *cmd)
{
struct rt_cmd *kcmd;
get_user(kcmd, &cmd->kcmd);
kcmd->cmd.chanlist = kcmd->kchanlist;
kcmd->cmd.data = kcmd->kdata;
return comedi_command(dev, (void *)kcmd);
}
static int rt_comedi_command_test(void *dev, struct rt_cmd *cmd)
{
struct rt_cmd *kcmd;
get_user(kcmd, &cmd->kcmd);
kcmd->cmd.chanlist = kcmd->kchanlist;
kcmd->cmd.data = kcmd->kdata;
return comedi_command_test(dev, (void *)kcmd);
}
/**
* allocates a RTAI shared memory area for a comedi_cmd structure, a channel
* list, and provides a RTAI <em>name</em> for the asynchronous DAQ transfer buffer.
*
* This function makes memory available for structures relevant for asynchronous
* data acquisition. A shared memory area is allocated for the comedi_cmd
* structure and the channel list array. Further the transfer buffer which is
* maintained by comedi's DAQ driver is registered as a RTAI SHM segment to be
* available under a RTAI <em>name</em>.
*
* @param dev (must be) a pointer to a comedi_t structure
* @param subdev the number of the comedi subdevice to perform acquistion on
* @param chanlist_len the length of the channel list
* @param ofst contains pointers to implicit rt_cmd structure's members
* @return name of a shm area for comedi_cmd structure.
*/
static unsigned long rt_comedi_alloc_cmd(void *dev, unsigned int subdev, unsigned int \
chanlist_len, unsigned long *ofst ) {
struct rt_cmd *kcmd;
unsigned long name, namebuf;
int bufsz,result;
name = namebase++;
namebuf = namebase++;
void *async_buf = NULL;
if ( 0 != (result = comedi_map(dev, subdev, &async_buf)) )
{
rt_printk
(
"rt_comedi_alloc_cmd: ERROR getting subdev buffer pointer: comedi_map: %i.\n",
result
);
}
else
{
int size;
//rt_printk("rt_comedi_alloc_cmd: Got subdev buffer pointer: %p\n", async_buf);
if ( 0 < (bufsz = comedi_get_buffer_size(dev,subdev)) )
{
//third parameter specifies the type of the resource
//mimic a RTAI shm allocation (see rtai-core/ipc/shm/shm.c)
//to masquerade the drivers async buffer as a RTAI shm area
size = ((bufsz -1) & PAGE_MASK) + PAGE_SIZE;
if(!rt_register(namebuf,async_buf,size,0))
rt_printk("rt_comedi_alloc_cmd: Couldn't register memory area as RTAI shm\n");
}
else
rt_printk("rt_comedi_alloc_cmd: ERROR getting subdev buffer length: %i\n", bufsz);
}
kcmd = rtai_kmalloc(name, sizeof(comedi_cmd) + 3*sizeof(void *) + sizeof(unsigned \
long) + chanlist_len*sizeof(unsigned int) + 16); //kcmd->cmd.data_len = data_len;
kcmd->name = name;
kcmd->kcmd = kcmd;
kcmd->kchanlist = &kcmd->name + 1;
//TODO Allow more than one simultaneous cmd acq
//kcmd->kdata = &kcmd->name + chanlist_len + 1;
kcmd->kdata = async_buf;
ofst[0] = (unsigned long)(kcmd->kchanlist - (unsigned long)kcmd);
ofst[1] = (unsigned long)(kcmd->kdata - (unsigned long)kcmd);
return name;
}
static unsigned long rt_comedi_free_cmd(struct rt_cmd *cmd)
{
struct rt_cmd *kcmd;
get_user(kcmd, &cmd->kcmd);
rt_drg_on_name((kcmd->name)+1);
rtai_kfree(kcmd->name);
return kcmd->name;
}
static struct rt_fun_entry rtai_comedi_fun[] = {
[_KCOMEDI_OPEN] = { 0, comedi_open }
,[_KCOMEDI_CLOSE] = { 0, comedi_close }
,[_KCOMEDI_LOCK] = { 0, comedi_lock }
,[_KCOMEDI_UNLOCK] = { 0, comedi_unlock }
,[_KCOMEDI_CANCEL] = { 0, comedi_cancel }
,[_KCOMEDI_REGISTER_CALLBACK] = { 0, rt_comedi_register_callback }
,[_KCOMEDI_COMMAND] = { 0, rt_comedi_command }
,[_KCOMEDI_COMMAND_TEST] = { 0, rt_comedi_command_test }
/* DEPRECATED
,[_KCOMEDI_TRIGGER ] = { 0, comedi_trigger }
*/
,[_KCOMEDI_DATA_WRITE] = { 0, comedi_data_write}
,[_KCOMEDI_DATA_READ] = { 0, comedi_data_read }
,[_KCOMEDI_DIO_CONFIG] = { 0, comedi_dio_config }
,[_KCOMEDI_DIO_READ] = { 0, comedi_dio_read }
,[_KCOMEDI_DIO_WRITE] = { 0, comedi_dio_write }
,[_KCOMEDI_DIO_BITFIELD] = { 0, comedi_dio_bitfield }
,[_KCOMEDI_GET_N_SUBDEVICES] = { 0, comedi_get_n_subdevices }
,[_KCOMEDI_GET_VERSION_CODE] = { 0, comedi_get_version_code }
,[_KCOMEDI_GET_DRIVER_NAME] = { 0, rt_comedi_get_driver_name }
,[_KCOMEDI_GET_BOARD_NAME] = { 0, rt_comedi_get_board_name }
,[_KCOMEDI_GET_SUBDEVICE_TYPE] = { 0, comedi_get_subdevice_type }
,[_KCOMEDI_FIND_SUBDEVICE_TYPE] = { 0, comedi_find_subdevice_by_type }
,[_KCOMEDI_GET_N_CHANNELS] = { 0, comedi_get_n_channels }
,[_KCOMEDI_GET_MAXDATA] = { 0, comedi_get_maxdata }
,[_KCOMEDI_GET_N_RANGES] = { 0, comedi_get_n_ranges }
,[_KCOMEDI_DO_INSN] = { 0, comedi_do_insn }
/* NOT YET IMPLEMENTED
,[_KCOMEDI_DO_INSN_LIST] = { 0, comedi_di_insn_list }
*/
,[_KCOMEDI_POLL] = { 0, comedi_poll }
/* DEPRECATED FUNCTION
,[_KCOMEDI_GET_RANGETYPE] = { 0, comedi_get_rangetype }
*/
,[_KCOMEDI_GET_SUBDEVICE_FLAGS] = { 0, comedi_get_subdevice_flags }
,[_KCOMEDI_GET_LEN_CHANLIST] = { 0, comedi_get_len_chanlist }
,[_KCOMEDI_GET_KRANGE] = { 0, comedi_get_krange }
,[_KCOMEDI_GET_BUF_HEAD_POS] = { 0, comedi_get_buf_head_pos }
/*
,[_KCOMEDI_SET_USER_INT_COUNT] = { 0, comedi_set_user_int_count }
*/
,[_KCOMEDI_MAP] = { 0, comedi_map }
,[_KCOMEDI_UNMAP] = { 0, comedi_unmap }
,[_KCOMEDI_WAIT] = { UW1(2, 3), rt_comedi_wait }
,[_KCOMEDI_WAIT_IF] = { UW1(2, 3), rt_comedi_wait_if }
,[_KCOMEDI_WAIT_UNTIL] = { UW1(4, 5), rt_comedi_wait_until }
,[_KCOMEDI_WAIT_TIMED] = { UW1(4, 5), rt_comedi_wait_timed }
,[_KCOMEDI_ALLOC_CMD] = { 0, rt_comedi_alloc_cmd }
,[_KCOMEDI_FREE_CMD] = { 0, rt_comedi_free_cmd }
,[_KCOMEDI_GET_BUFFER_CONTENTS] = { 0, comedi_get_buffer_contents }
,[_KCOMEDI_MARK_BUFFER_READ] = { 0, comedi_mark_buffer_read }
,[_KCOMEDI_GET_BUFFER_SIZE] = { 0, comedi_get_buffer_size }
,[_KCOMEDI_GET_BUFFER_OFFSET] = { 0, comedi_get_buffer_offset }
/*
,[_KCOMEDI_MARK_BUFFER_WRITTEN] = { 0, comedi_mark_buffer_written }
*/
,[_KCOMEDI_MARK_WAIT_MUNGE] = { UW1(4, 7) | UW2(6, 7) , \
rt_comedi_mark_wait_munge } };
int __rtai_comedi_init(void)
{
if( set_rt_fun_ext_index(rtai_comedi_fun, FUN_COMEDI_LXRT_INDX) ) {
printk("Recompile your module with a different index\n");
return -EACCES;
}
return(0);
}
void __rtai_comedi_exit(void)
{
reset_rt_fun_ext_index(rtai_comedi_fun, FUN_COMEDI_LXRT_INDX);
}
module_init(__rtai_comedi_init);
module_exit(__rtai_comedi_exit);
["rtai_comedi.h" (text/x-chdr)]
/*
* Copyright (C) 2002 Thomas Leibner (leibner@t-online.de) (first complete writeup)
* 2002 David Schleef (ds@schleef.org) (COMEDI master)
* 2002 Lorenzo Dozio (dozio@aero.polimi.it) (made it all work)
* 2002 Paolo Mantegazza (mantegazza@aero.polimi.it) (hints/support)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#ifndef _RTAI_COMEDI_H_
#define _RTAI_COMEDI_H_
#include <rtai_types.h>
#include <rtai_sem.h>
#define FUN_COMEDI_LXRT_INDX 9
#define _KCOMEDI_OPEN 0
#define _KCOMEDI_CLOSE 1
#define _KCOMEDI_LOCK 2
#define _KCOMEDI_UNLOCK 3
#define _KCOMEDI_CANCEL 4
#define _KCOMEDI_REGISTER_CALLBACK 5
#define _KCOMEDI_COMMAND 6
#define _KCOMEDI_COMMAND_TEST 7
/* DEPRECATED function */
#define _KCOMEDI_TRIGGER 8
#define _KCOMEDI_DATA_WRITE 9
#define _KCOMEDI_DATA_READ 10
#define _KCOMEDI_DIO_CONFIG 11
#define _KCOMEDI_DIO_READ 12
#define _KCOMEDI_DIO_WRITE 13
#define _KCOMEDI_DIO_BITFIELD 14
#define _KCOMEDI_GET_N_SUBDEVICES 15
#define _KCOMEDI_GET_VERSION_CODE 16
#define _KCOMEDI_GET_DRIVER_NAME 17
#define _KCOMEDI_GET_BOARD_NAME 18
#define _KCOMEDI_GET_SUBDEVICE_TYPE 19
#define _KCOMEDI_FIND_SUBDEVICE_TYPE 20
#define _KCOMEDI_GET_N_CHANNELS 21
#define _KCOMEDI_GET_MAXDATA 22
#define _KCOMEDI_GET_N_RANGES 23
#define _KCOMEDI_DO_INSN 24
#define _KCOMEDI_DO_INSN_LIST 25 // not yet in kcomedilib... (tl)
#define _KCOMEDI_POLL 26
/* DEPRECATED function */
#define _KCOMEDI_GET_RANGETYPE 27
/* ALPHA functions */
#define _KCOMEDI_GET_SUBDEVICE_FLAGS 28
#define _KCOMEDI_GET_LEN_CHANLIST 29
#define _KCOMEDI_GET_KRANGE 30
#define _KCOMEDI_GET_BUF_HEAD_POS 31
#define _KCOMEDI_SET_USER_INT_COUNT 32
#define _KCOMEDI_MAP 33
#define _KCOMEDI_UNMAP 34
/* RTAI specific callbacks from kcomedi to user space */
#define _KCOMEDI_WAIT 35
#define _KCOMEDI_WAIT_IF 36
#define _KCOMEDI_WAIT_UNTIL 37
#define _KCOMEDI_WAIT_TIMED 38
/* RTAI specific functions to allocate/free comedi_cmd */
#define _KCOMEDI_ALLOC_CMD 39
#define _KCOMEDI_FREE_CMD 40
/* buffer control functions (together with idx 31 above)*/
#define _KCOMEDI_GET_BUFFER_CONTENTS 41
#define _KCOMEDI_MARK_BUFFER_READ 42
#define _KCOMEDI_GET_BUFFER_SIZE 43
#define _KCOMEDI_GET_BUFFER_OFFSET 44
#define _KCOMEDI_MARK_BUFFER_WRITTEN 45 // not yet in kcomedilib api... (al)
#define _KCOMEDI_MARK_WAIT_MUNGE 46
#ifdef __KERNEL__ /* For kernel module build. */
#include <linux/comedilib.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int rt_comedi_register_callback(
void *dev,
unsigned int subdev,
unsigned int mask,
SEM *sem
);
unsigned int rt_comedi_wait(
SEM *sem,
int *semcnt
);
unsigned int rt_comedi_mark_wait_munge(
void *dev,
unsigned int subdev,
int oldbytes,
int *newbytes,
SEM *sem,
int *semcnt
);
unsigned int rt_comedi_wait_if(
SEM *sem,
int *semcnt
);
unsigned int rt_comedi_wait_until(
SEM *sem,
RTIME until,
int *semcnt
);
unsigned int rt_comedi_wait_timed(
SEM *sem,
RTIME delay,
int *semcnt
);
char *rt_comedi_get_driver_name(
void *dev,
char *name
);
char *rt_comedi_get_board_name(
void *dev,
char *name
);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#else /* __KERNEL__ not defined */
#include <string.h>
#include <asm/rtai_lxrt.h>
#include <rtai_shm.h>
#include <linux/comedi.h>
#define COMEDI_LXRT_SIZARG sizeof(arg)
RTAI_PROTO(void *, comedi_open,(const char *filename))
{
char lfilename[COMEDI_NAMELEN];
struct { char *minor; } arg = { lfilename };
strncpy(lfilename, filename, COMEDI_NAMELEN - 1);
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_OPEN, \
&arg).v[LOW]; }
RTAI_PROTO(int, comedi_close,(void *dev))
{
struct { void *dev; } arg = { dev };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_CLOSE, \
&arg).i[LOW]; }
RTAI_PROTO(int, comedi_lock,(void *dev, unsigned int subdev))
{
struct { void *dev; unsigned int subdev; } arg = { dev, subdev };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_LOCK, \
&arg).i[LOW]; }
RTAI_PROTO(int, comedi_unlock,(void *dev, unsigned int subdev))
{
struct { void *dev; unsigned int subdev; } arg = { dev, subdev };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_UNLOCK, \
&arg).i[LOW]; }
RTAI_PROTO(int, comedi_cancel,(void *dev, unsigned int subdev))
{
struct { void *dev; unsigned int subdev; } arg = { dev, subdev };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_CANCEL, \
&arg).i[LOW]; }
RTAI_PROTO(int, rt_comedi_register_callback,(void *dev, unsigned int subdev, unsigned \
int mask, SEM *sem)) {
struct
{
void *dev; unsigned int subdev; unsigned int mask; SEM *sem;
} arg = { dev, subdev, mask, sem };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, \
_KCOMEDI_REGISTER_CALLBACK, &arg).i[LOW]; }
#define comedi_register_callback(dev, subdev, mask, cb, arg) \
rt_comedi_register_callback(dev, subdev, mask, arg)
RTAI_PROTO(unsigned int, rt_comedi_wait,(SEM *sem, int *semcnt))
{
int lsemcnt;
unsigned int retval;
struct { SEM *sem; int *semcnt; int size; } arg = { sem, &lsemcnt, sizeof(int *) };
retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_WAIT, \
&arg).i[LOW]; if (semcnt) {
*semcnt = lsemcnt;
}
return retval;
}
/**
* allows buffer synchronisation between comedi driver and lxrt program in a single
* call. Can replace calls to comedi_mark_buffer_read, comedi_get_buffer_contents and \
* rt_comedi_wait in an asynchronous _input_ acquisition.
* @param dev (must be) a pointer to a comedi_t structure
* @param subdev the number of the comedi subdevice to perform acquistion on
* @param *newbytes reference to the number of bytes read by userspace
* before the function call and to the number of bytes written by the comedi driver
* after the function call
* @param *sem pointer to the RTAI semaphore used to synchronize comedi driver with
* lxrt program
* @param *semcnt contains the semaphore count after return.
* In case of TRIG_WAKE_EOS it is increased by one for each scan
* @return callback mask indicating transfer status (see comedi.h: "callback stuff")
*/
RTAI_PROTO(unsigned int, rt_comedi_mark_wait_munge,(void *dev, unsigned int subdev, \
int *newbytes, SEM *sem, int *semcnt)) {
int lnewbytes, lsemcnt;
unsigned int retval;
if (newbytes) {
lnewbytes = *newbytes;
struct {
void *dev; unsigned int subdev; int oldbytes; int *newbytes; SEM *sem; int \
*semcnt; int nbsmsize; } arg = { dev, subdev, lnewbytes, &lnewbytes, sem, &lsemcnt, \
sizeof(int *)}; retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, \
_KCOMEDI_MARK_WAIT_MUNGE, &arg).i[LOW];
*newbytes = lnewbytes;
if (semcnt) {
*semcnt = lsemcnt;
}
}
else {
retval = rt_comedi_wait(sem, semcnt);
}
return retval;
}
RTAI_PROTO(unsigned int, rt_comedi_wait_if,(SEM *sem, int *semcnt))
{
int lsemcnt;
unsigned int retval;
struct { SEM *sem; int *semcnt; int size; } arg = { sem, &lsemcnt, sizeof(int *) };
retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_WAIT_IF, \
&arg).i[LOW]; if (semcnt) {
*semcnt = lsemcnt;
}
return retval;
}
RTAI_PROTO(unsigned int, rt_comedi_wait_until,(SEM *sem, RTIME until, int *semcnt))
{
int lsemcnt;
unsigned int retval;
struct { SEM *sem; RTIME until; int *semcnt; int size; } arg = { sem, until, \
&lsemcnt, sizeof(int *) }; retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, \
COMEDI_LXRT_SIZARG, _KCOMEDI_WAIT_UNTIL, &arg).i[LOW]; if (semcnt) {
*semcnt = lsemcnt;
}
return retval;
}
RTAI_PROTO(unsigned int, rt_comedi_wait_timed,(SEM *sem, RTIME delay, int *semcnt))
{
int lsemcnt;
unsigned int retval;
struct
{
SEM *sem; RTIME delay; int *semcnt; int size;
} arg = { sem, delay, &lsemcnt, sizeof(int *) };
retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_WAIT_TIMED, \
&arg).i[LOW]; if (semcnt) {
*semcnt = lsemcnt;
}
return retval;
}
RTAI_PROTO(int, comedi_command,(void *dev, comedi_cmd *cmd))
{
struct { void *dev; comedi_cmd *cmd; } arg = { dev, cmd };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_COMMAND, \
&arg).i[LOW]; }
RTAI_PROTO(int, comedi_command_test,(void *dev, comedi_cmd *cmd))
{
struct { void *dev; comedi_cmd *cmd; } arg = { dev, cmd };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_COMMAND_TEST, \
&arg).i[LOW]; }
RTAI_PROTO(int, comedi_trigger,(void *dev, unsigned int subdev, comedi_trig *it))
{
return -1;
}
RTAI_PROTO(int, comedi_data_write,(void *dev, unsigned int subdev, unsigned int chan, \
unsigned int range, unsigned int aref, lsampl_t data)) {
struct { void *dev; unsigned int subdev; unsigned int chan; unsigned int range; \
unsigned int aref; lsampl_t data; } arg = { dev, subdev, chan, range, aref, data }; \
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_DATA_WRITE, \
&arg).i[LOW]; }
RTAI_PROTO(int, comedi_data_read,(void *dev, unsigned int subdev, unsigned int chan, \
unsigned int range, unsigned int aref, lsampl_t *data)) {
int retval;
lsampl_t ldata;
struct { void *dev; unsigned int subdev; unsigned int chan; unsigned int range; \
unsigned int aref; lsampl_t *data; } arg = { dev, subdev, chan, range, aref, &ldata \
}; retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_DATA_READ, \
&arg).i[LOW]; memcpy(data, &ldata, sizeof(lsampl_t));
return retval;
}
RTAI_PROTO(int, comedi_dio_config,(void *dev, unsigned int subdev, unsigned int chan, \
unsigned int io)) {
struct { void *dev; unsigned int subdev; unsigned int chan; unsigned int io; } arg = \
{ dev, subdev, chan, io }; return rtai_lxrt(FUN_COMEDI_LXRT_INDX, \
COMEDI_LXRT_SIZARG, _KCOMEDI_DIO_CONFIG, &arg).i[LOW]; }
RTAI_PROTO(int, comedi_dio_read,(void *dev, unsigned int subdev, unsigned int chan, \
unsigned int *val)) {
int retval;
unsigned int lval;
struct { void *dev; unsigned int subdev; unsigned int chan; unsigned int *val; } arg \
= { dev, subdev, chan, &lval }; retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, \
COMEDI_LXRT_SIZARG, _KCOMEDI_DIO_READ, &arg).i[LOW];
*val = lval;
return retval;
}
RTAI_PROTO(int, comedi_dio_write,(void *dev, unsigned int subdev, unsigned int chan, \
unsigned int val)) {
struct { void *dev; unsigned int subdev; unsigned int chan; unsigned int val; } arg \
= { dev, subdev, chan, val }; return rtai_lxrt(FUN_COMEDI_LXRT_INDX, \
COMEDI_LXRT_SIZARG, _KCOMEDI_DIO_WRITE, &arg).i[LOW]; }
RTAI_PROTO(int, comedi_dio_bitfield,(void *dev, unsigned int subdev, unsigned int \
mask, unsigned int *bits)) {
int retval;
unsigned int lbits;
struct { void *dev; unsigned int subdev; unsigned int mask; unsigned int *bits; } \
arg = { dev, subdev, mask, &lbits }; retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, \
COMEDI_LXRT_SIZARG, _KCOMEDI_DIO_BITFIELD, &arg).i[LOW];
*bits = lbits;
return retval;
}
RTAI_PROTO(int, comedi_get_n_subdevices,(void *dev))
{
struct { void *dev;} arg = { dev };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, \
_KCOMEDI_GET_N_SUBDEVICES, &arg).i[LOW]; }
RTAI_PROTO(int, comedi_get_version_code,(void *dev))
{
struct { void *dev;} arg = { dev };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, \
_KCOMEDI_GET_VERSION_CODE, &arg).i[LOW]; }
RTAI_PROTO(char *, rt_comedi_get_driver_name,(void *dev, char *name))
{
void *p;
char lname[COMEDI_NAMELEN];
struct { void *dev; char *name; } arg = { dev, lname };
if ((p = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, \
_KCOMEDI_GET_DRIVER_NAME, &arg).v[LOW])) { strncpy(name, lname, COMEDI_NAMELEN);
return name;
}
return 0;
}
RTAI_PROTO(char *, rt_comedi_get_board_name,(void *dev, char *name))
{
void *p;
char lname[COMEDI_NAMELEN];
struct { void *dev; char *name; } arg = { dev, lname };
if ((p = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, \
_KCOMEDI_GET_BOARD_NAME, &arg).v[LOW])) { strncpy(name, lname, COMEDI_NAMELEN);
return name;
}
return 0;
}
RTAI_PROTO(int, comedi_get_subdevice_type,(void *dev, unsigned int subdev))
{
struct { void *dev; unsigned int subdev; } arg = { dev, subdev };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, \
_KCOMEDI_GET_SUBDEVICE_TYPE, &arg).i[LOW]; }
RTAI_PROTO(int, comedi_find_subdevice_by_type,(void *dev, int type, unsigned int \
subd)) {
struct { void *dev; int type; unsigned int subd; } arg = { dev, type, subd };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, \
_KCOMEDI_FIND_SUBDEVICE_TYPE, &arg).i[LOW]; }
RTAI_PROTO(int, comedi_get_n_channels,(void *dev, unsigned int subdev))
{
struct { void *dev; unsigned int subdev; } arg = { dev, subdev };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_N_CHANNELS, \
&arg).i[LOW]; }
RTAI_PROTO(lsampl_t, comedi_get_maxdata,(void *dev, unsigned int subdev, unsigned int \
chan)) {
struct { void *dev; unsigned int subdev; unsigned int chan;} arg = { dev, subdev, \
chan }; return (lsampl_t)rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, \
_KCOMEDI_GET_MAXDATA, &arg).i[LOW]; }
RTAI_PROTO(int, comedi_get_n_ranges,(void *dev, unsigned int subdev, unsigned int \
chan)) {
struct { void *dev; unsigned int subdev; unsigned int chan;} arg = { dev, subdev, \
chan }; return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, \
_KCOMEDI_GET_N_RANGES, &arg).i[LOW]; }
RTAI_PROTO(int, comedi_do_insn,(void *dev, comedi_insn *insn))
{
int retval;
comedi_insn linsn = *insn;
struct { void *dev; comedi_insn *insn; } arg = { dev, &linsn };
retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_DO_INSN, \
&arg).i[LOW]; memcpy(insn, &linsn, sizeof(comedi_insn));
return retval;
}
RTAI_PROTO(int, comedi_poll,(void *dev, unsigned int subdev))
{
struct { void *dev; unsigned int subdev; } arg = { dev, subdev };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_POLL, \
&arg).i[LOW]; }
RTAI_PROTO(int, comedi_get_krange,(void *dev, unsigned int subdev, unsigned int chan, \
unsigned int range, comedi_krange *krange)) {
int retval;
comedi_krange lkrange;
struct
{
void *dev; unsigned int subdev; unsigned int chan; unsigned int range; \
comedi_krange *krange; } arg = { dev, subdev, chan, range, &lkrange };
retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_KRANGE, \
&arg).i[LOW]; memcpy(krange, &lkrange, sizeof(comedi_krange));
return retval;
}
RTAI_PROTO(unsigned int, comedi_get_buf_head_pos,(void *dev, unsigned int subdev))
{
struct { void *dev; unsigned int subdev;} arg = { dev, subdev };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, \
_KCOMEDI_GET_BUF_HEAD_POS, &arg).i[LOW]; }
RTAI_PROTO(int, comedi_map,(void *dev, unsigned int subdev, void *ptr))
{
int retval;
unsigned int liptr;
struct { void *dev; unsigned int subdevice; void *ptr; } arg = { dev, subdev, &liptr \
}; retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_MAP, \
&arg).i[LOW];
*((void **) ptr) = (void *)liptr;
return retval;
}
RTAI_PROTO(int, comedi_unmap,(void *dev, unsigned int subdev))
{
int retval;
struct { void *dev; unsigned int subdevice; } arg = { dev, subdev };
retval = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_UNMAP, \
&arg).i[LOW]; return retval;
}
RTAI_PROTO(int, comedi_get_len_chanlist,(void *dev, unsigned int subdev))
{
struct { void *dev; unsigned int subdev;} arg = { dev, subdev };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, \
_KCOMEDI_GET_SUBDEVICE_FLAGS, &arg).i[LOW]; }
/**
* allocates a RTAI SHM area for a comedi_cmd structure, a channel list, and
* provides reference to Comedi's asynchronous DAQ transfer buffer.
*
* This function makes memory available for structures relevant for asynchronous
* data acquisition. A shared memory area is allocated for the comedi_cmd
* structure and the channel list array. Further the transfer buffer which is
* maintained by comedi's DAQ driver is registered as a RTAI SHM segment to be
* referenced by <em>data</em>.
*
* @param dev (must be) a pointer to a comedi_t structure
* @param subdev the number of the comedi subdevice to perform acquistion on
* @param chanlist reference to a channel list array's pointer
* @param chanlist_len the length of the channel list (maximum is driver specific)
* @param data reference to a pointer -- will be set to point to the comedi transfer \
buffer
* @return pointer to a shm area for a comedi_cmd structure.
*/
RTAI_PROTO(
comedi_cmd *, rt_comedi_alloc_cmd,
(
void *dev, unsigned int subdev, unsigned int **chanlist, unsigned int chanlist_len, \
void **data )
)
{
unsigned long ofst[2], name;
comedi_cmd *cmd;
comedi_cmd *p;
if ((int)chanlist_len>comedi_get_len_chanlist(dev,subdev))
return NULL;
if ((chanlist==NULL) || (data==NULL))
return NULL;
struct
{
void *dev; unsigned int subdev; unsigned int chanlist_len; unsigned long *ofst;
} arg = { dev, subdev, chanlist_len, ofst };
name = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_ALLOC_CMD, \
&arg).i[LOW];
cmd = p = (comedi_cmd *)rtai_malloc(name, 1);
*chanlist = cmd->chanlist = (unsigned int *)((char *)p + ofst[0]);
*data = rtai_malloc(name+1,1);
cmd->data = (sampl_t*)data;
return cmd;
}
RTAI_PROTO(void, rt_comedi_free_cmd,(void *cmd))
{
unsigned long name;
struct { void *cmd; } arg = { cmd };
name = rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_FREE_CMD, \
&arg).i[LOW]; rtai_free(name+1,cmd->data);
rtai_free(name, cmd);
}
RTAI_PROTO(int, comedi_get_buffer_contents,(void *dev, unsigned int subdev))
{
struct { void *dev; unsigned int subdev;} arg = { dev, subdev };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, \
_KCOMEDI_GET_BUFFER_CONTENTS, &arg).i[LOW]; }
RTAI_PROTO(int, comedi_mark_buffer_read,(void *dev, unsigned int subdev, unsigned int \
num_bytes)) {
struct { void *dev; unsigned int subdev; unsigned int num_bytes;} arg = { dev, \
subdev, num_bytes }; return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, \
_KCOMEDI_MARK_BUFFER_READ, &arg).i[LOW]; }
/* This function is not declared as a kcomdilib symbol
RTAI_PROTO(int, comedi_mark_buffer_written,(void *dev, unsigned int subdev, unsigned \
int num_bytes)) {
struct { void *dev; unsigned int subdev; unsigned int num_bytes;} arg = { dev, \
subdev, num_bytes }; return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, \
_KCOMEDI_MARK_BUFFER_READ, &arg).i[LOW]; }
*/
RTAI_PROTO(int, comedi_get_buffer_size,(void *dev, unsigned int subdev))
{
struct { void *dev; unsigned int subdev;} arg = { dev, subdev };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, _KCOMEDI_GET_BUFFER_SIZE, \
&arg).i[LOW]; }
RTAI_PROTO(int, comedi_get_buffer_offset,(void *dev, unsigned int subdev))
{
struct { void *dev; unsigned int subdev;} arg = { dev, subdev };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, \
_KCOMEDI_GET_BUFFER_OFFSET, &arg).i[LOW]; }
RTAI_PROTO(unsigned int, comedi_get_subdevice_flags,(void *dev, unsigned int subdev))
{
struct { void *dev; unsigned int subdev;} arg = { dev, subdev };
return rtai_lxrt(FUN_COMEDI_LXRT_INDX, COMEDI_LXRT_SIZARG, \
_KCOMEDI_GET_SUBDEVICE_FLAGS, &arg).i[LOW]; }
#endif /* #ifdef __KERNEL__ */
#endif /* #ifndef _RTAI_COMEDI_H_ */
["testa.c" (text/x-csrc)]
/*
COPYRIGHT (C) 2002 Lorenzo Dozio (dozio@aero.polimi.it)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#define KEEP_STATIC_INLINE
#include <rtai_lxrt.h>
#include <rtai_comedi.h>
//using hard real-time?
#ifdef USE_HRT
#define HRT_IF_ELSE(arg1, arg2) arg1
#define HRT_IF(arg) arg
#define HRT_IF_NOT(arg)
#else
#define HRT_IF_ELSE(arg1, arg2) arg2
#define HRT_IF(arg)
#define HRT_IF_NOT(arg) arg
#endif
#define N_CHANS 4
#define N_SCANS 20
#define T_CONVERT_ARG 10000000
char *subdevice_types[]={
"unused",
"analog input",
"analog output",
"digital input",
"digital output",
"digital I/O",
"counter",
"timer",
"memory",
"calibration",
"processor"
};
char *cmdtest_messages[]={
"success",
"invalid source",
"source conflict",
"invalid argument",
"argument conflict",
"invalid chanlist",
};
char *cmd_src(int src,char *buf)
{
buf[0]=0;
if(src&TRIG_NONE)strcat(buf,"none|");
if(src&TRIG_NOW)strcat(buf,"now|");
if(src&TRIG_FOLLOW)strcat(buf, "follow|");
if(src&TRIG_TIME)strcat(buf, "time|");
if(src&TRIG_TIMER)strcat(buf, "timer|");
if(src&TRIG_COUNT)strcat(buf, "count|");
if(src&TRIG_EXT)strcat(buf, "ext|");
if(src&TRIG_INT)strcat(buf, "int|");
#ifdef TRIG_OTHER
if(src&TRIG_OTHER)strcat(buf, "other|");
#endif
if(strlen(buf)==0){
sprintf(buf,"unknown(0x%08x)",src);
}else{
buf[strlen(buf)-1]=0;
}
return buf;
}
void dump_cmd(comedi_cmd *cmd)
{
char buf[100];
printf("start: %-8s %d\n",
cmd_src(cmd->start_src,buf),
cmd->start_arg);
printf("scan_begin: %-8s %d\n",
cmd_src(cmd->scan_begin_src,buf),
cmd->scan_begin_arg);
printf("convert: %-8s %d\n",
cmd_src(cmd->convert_src,buf),
cmd->convert_arg);
printf("scan_end: %-8s %d\n",
cmd_src(cmd->scan_end_src,buf),
cmd->scan_end_arg);
printf("stop: %-8s %d\n",
cmd_src(cmd->stop_src,buf),
cmd->stop_arg);
}
static void *dev;
static int subdev_ai = -1;
static comedi_cmd *cmd;
//this can save trouble:
void SEGVhandler(int i);
int main(int argc, char **argv)
{
RT_TASK *comedi_task;
int i, subdev_ao, subdev_dio, n_subdevs, nch, type;
char name[50];
SEM *sem;
unsigned int *chanlist;
int ret;
void *buf;
rt_set_oneshot_mode();
start_rt_timer(0);
mlockall(MCL_CURRENT | MCL_FUTURE);
if (!(comedi_task = rt_task_init(nam2num("COMEDI"), 0, 0, 0))) {
printf("CANNOT INIT COMEDI TASK\n");
exit(1);
}
if (0 == (sem = rt_sem_init(nam2num("CMDSEM"), 0))) {
printf("CANNOT INIT SEMAPHORE\n");
exit(1);
}
dev = comedi_open("/dev/comedi0");
signal(SIGSEGV,SEGVhandler);
printf("\n OVERALL INFO:\n");
printf(" Version code : 0x%06x\n", comedi_get_version_code(dev));
rt_comedi_get_board_name(dev, name);
printf(" Board name : %s\n", name);
rt_comedi_get_driver_name(dev, name);
printf(" Driver name : %s\n", name);
printf(" Number of subdevices : %d\n", n_subdevs = comedi_get_n_subdevices(dev));
for (i = 0; i < n_subdevs; i++) {
printf("\n Subdevice : %d\n", i);
type = comedi_get_subdevice_type(dev, i);
printf(" Type : %d (%s)\n", type, subdevice_types[type]);
printf(" Number of channels : %d\n", nch = comedi_get_n_channels(dev, i));
if (nch != -1) {
printf(" Maxdata : %d\n", comedi_get_maxdata(dev, i, 0));
printf(" Number of ranges : %d\n", comedi_get_n_ranges(dev, i, 0));
}
}
subdev_ai = comedi_find_subdevice_by_type(dev, COMEDI_SUBD_AI, 0);
subdev_ao = comedi_find_subdevice_by_type(dev, COMEDI_SUBD_AO, 0);
subdev_dio = comedi_find_subdevice_by_type(dev, COMEDI_SUBD_DIO, 0);
printf("\n Asynchronous test (with comedi commands).\n");
comedi_lock(dev, subdev_ai);
comedi_register_callback(dev, subdev_ai, COMEDI_CB_EOS, 0, sem);
cmd = 0;
buf2 = 0;
cmd = rt_comedi_alloc_cmd(dev, subdev_ai, &chanlist, N_CHANS, &buf);
int buf_len = comedi_get_buffer_size(dev, subdev_ai);
buf_len /=sizeof(sampl_t);
printf("\n Buffer size is %i samples.\n", buf_len);
/* the subdevice that the command is sent to */
cmd->subdev = subdev_ai;
/* flags */
cmd->flags = TRIG_WAKE_EOS HRT_IF(| TRIG_RT);
/* start of acquisition: immediately after call to comedi_command() */
cmd->start_src = TRIG_NOW;
cmd->start_arg = 0;
/* event signalling the beginning of each scan: expiring TIMER */
cmd->scan_begin_src = TRIG_TIMER;
cmd->scan_begin_arg = N_CHANS*T_CONVERT_ARG;
/* event triggering each A/D conversion: expiring TIMER */
cmd->convert_src = TRIG_TIMER;
cmd->convert_arg = T_CONVERT_ARG;
/* end of each scan: after N_CHANS conversions*/
cmd->scan_end_src = TRIG_COUNT;
cmd->scan_end_arg = N_CHANS;
/* event signalling the end of acquisition: after N_SCANS*N_CHANS conversions*/
cmd->stop_src = TRIG_COUNT;
cmd->stop_arg = N_SCANS*N_CHANS;
/* the channel list */
cmd->chanlist = chanlist;
cmd->chanlist_len = N_CHANS;
chanlist[0] = CR_PACK(0,0,0);
chanlist[1] = CR_PACK(1,0,0);
chanlist[2] = CR_PACK(0,1,0);
chanlist[3] = CR_PACK(1,1,0);
/* chanlist[4] = CR_PACK(0,0,0);
chanlist[5] = CR_PACK(0,1,0);
chanlist[6] = CR_PACK(1,0,0);
chanlist[7] = CR_PACK(1,1,0);
*/
/* No longer in use by Comedi drivers:
cmd->data = buf;
cmd->data_len = BUFSZ*sizeof(sampl_t);
*/
printf("\n command before testing : \n");
dump_cmd(cmd);
ret = comedi_command_test(dev, cmd);
printf("\n First test returned %d (%s)\n", ret, cmdtest_messages[ret]);
dump_cmd(cmd);
ret = comedi_command_test(dev, cmd);
printf("\n Second test returned %d (%s)\n\n", ret, cmdtest_messages[ret]);
if (ret != 0) {
dump_cmd(cmd);
printf(" ERROR PREPARING COMMAND\n");
exit(1);
}
printf("Press Enter to start acquisition -- or Ctrl+C to (safely) quit.\n");
getchar();
comedi_command(dev, cmd);
{
unsigned int mask = 0, front = 0, rear = 0;
int new_bytes = 0, semcnt = 0, n = 0;
//give daq card a head start for testing semcnt's return values
rt_sleep(nano2count(3*N_CHANS*T_CONVERT_ARG));
HRT_IF( printf("Going hard real-time. Please inspect dmesg output for \
messages.\n"); rt_make_hard_real_time();
)
while (!(mask&COMEDI_CB_EOA) && !(front < rear)) {
mask = rt_comedi_mark_wait_munge(dev, subdev_ai, &new_bytes, sem, &semcnt);
HRT_IF_ELSE(rt_printk,printf)("\nMASK: %x, SEMCNT: %d, numnewbytes: %d, # %d", \
mask, semcnt, new_bytes, rear );
//(new_bytes % sizeof(sampl_t)) _will_ be zero (see comedi_buf_read_n_available in \
comedi/comedi/drivers.c) front += new_bytes/sizeof(sampl_t);
for (n = rear; n < front; n++) {
HRT_IF_ELSE(rt_printk,printf)(" %d",((sampl_t *)buf)[n % buf_len]);
}
rear = front;
}
HRT_IF(rt_make_soft_real_time();)
printf("\n");
}
comedi_cancel(dev, subdev_ai);
rt_comedi_free_cmd(cmd);
comedi_unlock(dev, subdev_ai);
comedi_close(dev);
//reset to default SIGINT, SIGSEGV handling
signal(SIGSEGV,SIG_DFL);
rt_sem_delete(sem);
stop_rt_timer();
rt_task_delete(comedi_task);
return 0;
}
void SEGVhandler(int i)
{
rt_make_soft_real_time();
printf("testa SEGVhandler: ");
if ((dev!=0)&&(subdev_ai!=-1)) {
if ( comedi_unlock(dev,subdev_ai) == 0 ) {
if (cmd != 0)
rt_comedi_free_cmd(cmd);
if (0 == comedi_close(dev))
printf("Unlocked, Closed, Nice.\n");
else
printf("Failed to close comedi device.\n");
}
else {
if (comedi_cancel(dev,subdev_ai) != 0)
printf("Failed to cancel, unlock, close.\n");
else {
if (cmd != 0)
rt_comedi_free_cmd(cmd);
if ( comedi_unlock(dev,subdev_ai) == 0 )
if (0 == comedi_close(dev))
printf("Cancelled, Unlocked, Closed, Nice.\n");
else
printf("Failed to close comedi device.\n");
}
}
printf("testa crashing on ...\n");
}
else {
if (dev!=0) {
if (0 == comedi_close(dev))
printf("Closed, Nice.\n");
else
printf("Failed to close comedi device.\n");
}
else
printf("Couldn't close device because I know none.\n");
}
signal(SIGSEGV,SIG_DFL);
raise(i);
}
_______________________________________________
comedi mailing list
comedi@comedi.org
https://cvs.comedi.org/cgi-bin/mailman/listinfo/comedi
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic