- From: Calin A. Culianu <calin_at_ajvar.org>
- Date: Fri, 24 May 2002 17:58:28 -0400 (EDT)
Here is a simple example that I sent to you privately today but I am now
posting publicly to the mailing list so that the maybe others can see.
I am posting it inline to the message because I am not sure how this
mailing list handles attachments....
Cheers,
-Calin
Here goes:
------------------------------------------------------
./Makefile
------------------------------------------------------
#######################################################################
#
# Makefile for rt_module.o
#
#
#######################################################################
# Makefile.dirs sets up variables that point to your
# rtl directory and your comedi direcories
include ./Makefile.dirs
include ${RTL_DIR}/rtl.mk
# These are the headers that go with comedi. They are kernel headers for
# kcomedilib stuff and don't get installed in the usual /usr/include.
# Please point this define to your comedi source directory in the include/
# subdirectory.
COMEDI_DEVEL_HEADERS = ${COMEDI_DIR}/include
all: rt_module.o test
rt_module.o: rt_module.c rt_module.h
# Some checks are on the next line
_at_( [ -d "${COMEDI_DEVEL_HEADERS}" ] && [ -r
"${COMEDI_DEVEL_HEADERS}/linux/comedilib.h" ] || ( \
echo
"***************************************************************************";
\
echo "ERROR: Cannot find the comedi kernel headers. "; \
echo " These are usually in your comedi source dirctory in
the include/ "; \
echo " subdirectory. Please set these in
Makefile.rt_process!"; \
echo " (COMEDI_DEVEL_HEADERS = /path/to/comedi/src/include)"
; \
echo
"***************************************************************************";
\
exit 1 ) )
_at_echo
"***************************************************************************"
_at_echo " Compiling The RT-Module RealTime Kernel
Module"
_at_echo
"***************************************************************************"
$(CC) ${INCLUDE} ${CFLAGS} -I ${COMEDI_DEVEL_HEADERS} -c
rt_module.c
test.o: test.c rt_module.h
$(CC) -I ${RTL_DIR}/include -c test.c
test: test.o
$(CC) -o test test.o
clean:
-rm -f test *.o *~
------------------------------------------------------
./test.c
------------------------------------------------------
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <mbuff.h>
#include "rt_module.h"
int main(void)
{
struct SharedMem *shm = 0;
int fd, n_read;
const char *rtfname = "/dev/rtf" STR(DEFAULT_FIFO_MINOR);
char fifo_buf[DEFAULT_FIFO_SIZE];
shm = (struct SharedMem *)
mbuff_attach(SHARED_MEM_NAME, sizeof(struct SharedMem));
if (!shm || shm->magic != SHARED_MEM_MAGIC ) {
fprintf(stderr, "Cannot attach to shared memory.. "
"load rt_module.o!\n");
return EINVAL;
}
fprintf(stderr, "Opening /dev/rtf%d...\n", DEFAULT_FIFO_MINOR);
fflush(stderr);
sleep(1); // for dramatic effect...
fd = open(rtfname, O_RDONLY);
if (fd < 0) {
int saved_errno = errno;
fprintf(stderr, "Error opening %s:%s", rtfname,
strerror(errno));
exit(saved_errno);
}
fprintf(stderr, "Reading samples...");
fflush(stderr);
sleep(1); // for dramatic effect...
while ( (n_read = read(fd, fifo_buf, DEFAULT_FIFO_SIZE)) >= 0) {
int i, n_doubles = n_read / sizeof(double);
for (i = 0; i < n_read; i++)
printf("Read %g volts\n", ((double
*)fifo_buf)[n_doubles]);
}
return 0;
}
------------------------------------------------------
./rt_module.h
------------------------------------------------------
#ifndef _RT_PROCESS_H
# define _RT_PROCESS_H
#ifdef __cplusplus
extern "C" {
#endif
#define BILLION 1000000000
#define MILLION 1000000
#define DEFAULT_SAMPLING_RATE_HZ 1000
#define DEFAULT_COMEDI_MINOR 0 // /dev/comedi0
#define DEFAULT_COMEDI_CHANNEL 0 // just use the first channel
#define DEFAULT_CHANNEL_GAIN 0 // initial channel gain (COMEDI)
#define DEFAULT_FIFO_MINOR 0 // /dev/rtf0
#define DEFAULT_FIFO_SIZE (1000 * sizeof(double))
#define STR_(x) #x
#define STR(x) "" STR_(x) ""
#ifdef __KERNEL__
#define const_
#else
#define const_ const
#endif
#define SHARED_MEM_MAGIC (0xdeadbeef)
struct SharedMem {
const_ unsigned int ai_subdev;
const_ double max_volts;
const_ double min_volts;
const_ unsigned long long scan_index;
const_ int magic;
};
#define SHARED_MEM_NAME "Shared Memory Blah Blah"
#ifdef __cplusplus
}
#endif
#endif
------------------------------------------------------
./rt_module.c
------------------------------------------------------
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/bitops.h>
#include <asm/semaphore.h> /* for synchronizing the exported functions */
#include <asm/bitops.h> /* for set/clear bit */
#include <linux/malloc.h>
#include <linux/string.h> /* some memory copyage */
#include <linux/fs.h> /* for the determine_minor() functionality */
#include <rtl.h>
#include <rtl_fifo.h>
#include <rtl_sched.h>
#include <rtl_sync.h>
#include <mbuff.h>
#include <linux/comedilib.h>
#include "rt_module.h" /* header file specific to this program */
int init_module(void); /* set up RT stuff */
void cleanup_module(void) ; /* clean up RT stuff */
static int init_shared_mem(comedi_krange *); /* initialize shm */
static void *daq_rt_task (void *arg); /* our periodic loop */
static inline double sampl_to_volts(lsampl_t sampl);
#define KRANGE_MULTIPLIER (1e-6)
/* operates on krange_cache below to determine the voltage for a sample */
inline double sampl_to_volts(lsampl_t data);
static pthread_t daq_task = 0; /* main RT task */
/* some vars to keep track of the rt task period/rate */
static hrtime_t task_period = 0;
/* the shared memory we will create and chare with userland */
static struct SharedMem *shm = 0;
/* Used in init_module so that subroutines can report errors... */
static int error;
static const char *errorMessage = "Success";
static lsampl_t maxdata = 0; // from comedi_get_maxdata()
static unsigned int ai_subdev;
static int is_locked = 0, is_open = 0, have_rtf = 0;
/* this is our realtime periodic loop */
static void *daq_rt_task (void *arg)
{
while (1) {
lsampl_t data = 0;
double ddata = 0;
/* read 1 sample from the comedi device */
comedi_data_read(DEFAULT_COMEDI_MINOR, shm->ai_subdev,
DEFAULT_COMEDI_CHANNEL, DEFAULT_CHANNEL_GAIN,
AREF_GROUND, &data);
/* now put it in our realtime fifo, so user process can the sample */
ddata = sampl_to_volts(data);
rtf_put(DEFAULT_FIFO_MINOR, &ddata, sizeof(ddata));
/* increment scan_index counter */
++shm->scan_index;
/* wait for the next period (1 millisecond currently */
pthread_wait_np();
}
return (void *)0;
}
int init_module(void)
{
pthread_attr_t attr;
struct sched_param sched_param;
int tmp;
comedi_krange krange; // from comedi_krange struct
error = -EBUSY;
tmp =
comedi_find_subdevice_by_type(DEFAULT_COMEDI_MINOR, COMEDI_SUBD_AI,
0);
if ( tmp < 0 ) {
error = tmp;
errorMessage = "Cannot find an analog input subdevice on comedi device
"
"minor number " STR(DEFAULT_COMEDI_MINOR) ".";
goto init_error;
}
ai_subdev = tmp;
tmp = comedi_lock(DEFAULT_COMEDI_MINOR, ai_subdev);
if (tmp < 0) {
error = tmp;
errorMessage = "Cannot lock analog input subdevice.";
goto init_error;
}
is_locked = 1;
tmp = comedi_open(DEFAULT_COMEDI_MINOR);
if (tmp < 0) {
error = tmp;
errorMessage = "Cannot open device with comedi minor number "
STR(DEFAULT_COMEDI_MINOR);
goto init_error;
}
is_open = 1;
maxdata = comedi_get_maxdata(DEFAULT_COMEDI_MINOR, ai_subdev,
DEFAULT_COMEDI_CHANNEL);
comedi_get_krange(DEFAULT_COMEDI_MINOR, ai_subdev,
DEFAULT_COMEDI_CHANNEL,
DEFAULT_CHANNEL_GAIN, &krange);
if ( init_shared_mem(&krange) ) {
/* error initializing shared memory */
errorMessage = "Cannot allocate mbuff shared memory. Did you create
the "
"device node? Are you low on memory?";
error = -ENOMEM;
goto init_error;
}
tmp = rtf_create(DEFAULT_FIFO_MINOR, DEFAULT_FIFO_SIZE);
if (tmp != DEFAULT_FIFO_SIZE && tmp != 0) {
error = -EBUSY;
errorMessage = "Couldn't create fifo at minor "
STR(DEFAULT_FIFO_MINOR) ". ";
goto init_error;
}
have_rtf = 1;
/* create the realtime task */
pthread_attr_init(&attr);
pthread_attr_setfp_np(&attr, 1);
sched_param.sched_priority = 1;
pthread_attr_setschedparam(&attr, &sched_param);
if ( (error = pthread_create(&daq_task, &attr, daq_rt_task, (void *)0) )
) {
errorMessage = "Cannot create the daq pthread";
goto init_error;
}
task_period = ((1000 / DEFAULT_SAMPLING_RATE_HZ ) * MILLION);
/* now re-tune the period, note that this is dangerous if set too
fast, as the user task may never get to run! */
error = pthread_make_periodic_np (daq_task, gethrtime() + task_period,
task_period);
if ( error ) {
errorMessage = "Cannot make DAQ RT Task periodic";
goto init_error;
}
printk("rt_module : acquisition started at %d Hz (%s)\n",
DEFAULT_SAMPLING_RATE_HZ, errorMessage);
return 0;
init_error:
cleanup_module();
printk("rt_module: Failure -- can't initalize RT task (%s)\n",
errorMessage);
return error;
}
/* Initializes the rtlinux shared memory returns 0 on success, 1 on
failure */
static int
init_shared_mem(comedi_krange * krange)
{
/* Open mbuff Shared Memory structure */
shm =
(struct SharedMem *) mbuff_alloc (SHARED_MEM_NAME,
sizeof(struct SharedMem));
if (! shm) { /* means there was some sort of error allocating mbuff */
return -ENOMEM;
}
/* initialize shared memory variables ... see rt_module.h for
definitions */
shm->magic = SHARED_MEM_MAGIC;
shm->ai_subdev = ai_subdev;
shm->scan_index = 0;
shm->max_volts = krange->max * (double)KRANGE_MULTIPLIER;
shm->min_volts = krange->min * (double)KRANGE_MULTIPLIER;
if (RF_UNIT(krange->flags) == UNIT_mA) {
shm->max_volts *= 0.001;
shm->min_volts *= 0.001;
}
return 0;
}
void cleanup_module(void)
{
/* delete daq_task */
if (daq_task) {
if (!pthread_delete_np(daq_task))
printk ("rt_module: deleted RT task after %lu cycles.\n",
(unsigned long int)(shm ? shm->scan_index + 1 : 0));
else
printk ("rt_module: cannot find RT task (it died?).\n");
}
/* close all successfully opened fifos */
if (have_rtf) rtf_destroy(DEFAULT_FIFO_MINOR);
if (is_locked) {
comedi_cancel(DEFAULT_COMEDI_MINOR, ai_subdev);
comedi_unlock(DEFAULT_COMEDI_MINOR, ai_subdev);
}
if (is_open) comedi_close(DEFAULT_COMEDI_MINOR);
if (shm) mbuff_free(SHARED_MEM_NAME, shm);
}
static inline double sampl_to_volts(lsampl_t sampl)
{
double ret;
ret =
((shm->max_volts - shm->min_volts) * (sampl/(double)maxdata)
+ shm->min_volts) * KRANGE_MULTIPLIER;
return ret;
}
------------------------------------------------------
./Makefile.dirs
------------------------------------------------------
RTL_DIR = /usr/src/rtlinux
COMEDI_DIR = /usr/src/comedi
On Thu, 23 May 2002, Igal Brener wrote:
> List,
>
> Can anyone send me a VERY simple example of an rtlinux program that uses
> comedi, say for just one simple ADC call?
>
> I'm using Rtlinux 3.0, Comedi 0.7.64 and Comedilib 0.7.18.
>
> Thanks a lot.
>
> Igal
>
>
> _______________________________________________
> comedi mailing list
> comedi_at_stm.lbl.gov
> http://stm.lbl.gov/cgi-bin/mailman/listinfo/comedi
>
Received on 2002-05-24Z20:58:28