Hallo,
attached is a piece of code where I want to aquire data using comedis callback
function. After insmod the module I can read the last message set "FP on
thread" and than the system reboots or is frozen.
IMO I have to use the oneshot mode ( As I right remember I have to use
HRTIME_INFINITY as period) for the thread. This is wakeup() by the callback and
gets suspended by pthread_suspend_np. rtl_schedule() is done by this function
itself- see the source on RTL.
In period mode with 1 Hz and pthread_wait_np() the thread_code seems to work
well.
What it's going here and where is the fault, please help. The reason why I'm
using threads is the use of fp inside for later use. If I'm right, that I can't
use fp inside a normal kernel module ?
Thanks Olaf
#ifdef __RTL__
# include <rtl_conf.h>
# ifndef RTLINUX_V2
# error "We need NMN RTLinux v2!"
# endif
#endif
/***
* standard linux modules includes
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/errno.h>
/***
* RTL 2.2 specific includes
*/
#ifdef RTLINUX_V2
#include <rtl.h>
#include <rtl_fifo.h>
#include <rtl_sched.h>
#include <rtl_sync.h>
#include <rtl_debug.h>
#endif
#include <comedi.h>
#define THREAD_STACK_SIZE 2048
pthread_t rt_thread; /* the thread */
unsigned int ai_dev=0;
unsigned int ai_subdev=0;
unsigned int ai_chan=CR_PACK(0,0,AREF_GROUND);
comedi_trig ai_trig;
unsigned int ao_dev=0;
unsigned int ao_subdev=1;
unsigned int ao_chan=CR_PACK(0,0,AREF_GROUND);
comedi_trig ao_trig;
sampl_t ai_data = 0;
sampl_t ao_data = 0;
void *thread_code(void *param)
{
static size_t ctr = 0;
int ret = 0;
static char buf[20];
rtl_printf("set FP on thread\n");
if((ret = pthread_setfp_np(pthread_self(), 1)) != 0) {
rtl_printf("unable to use floating-point operations in realtime thread (error %d) !\n",
ret);
}
while(1) {
//pthread_wait_np();
pthread_suspend_np(pthread_self());
ao_data = ai_data;
comedi_trig_ioctl(ao_dev, ao_subdev, &ao_trig);
sprintf(buf, "%10d\n", ctr++);
rtf_put(1, buf, 11);
rtl_printf("suspended pthread self\n");
}
return 0;
}
int callback(unsigned int flags, void *arg)
{
pthread_wakeup_np(rt_thread);
return 1;
}
int init_module(void)
{
int ret = 0;
pthread_attr_t attr;
struct sched_param sched_param;
// install rtf
rtf_destroy(1);
ret = rtf_create(1, 4096);
// set up input structure
ai_trig.subdev=ai_subdev; // Subdevice number
ai_trig.mode=2; // Mode 2: event-driven program
ai_trig.flags=TRIG_WAKE_EOS; // Trigger on end-of-scan event
ai_trig.n_chan=1; // One input channel
ai_trig.chanlist=&ai_chan; // Pointer to the channel variable
ai_trig.data=&ai_data; // Address of the variable to put conversion result
ai_trig.data_len = sizeof(ai_data); // lenght of data
ai_trig.n=1; // Single sample
ai_trig.trigsrc=0;
ai_trig.trigvar = 100000; // Sampling period in ns eq. 10 kHz
ai_trig.trigvar1 = 1000; //
// set up output structure
ao_trig.subdev=ao_subdev;
ao_trig.mode=0;
ao_trig.flags=0;
ao_trig.n_chan=1;
ao_trig.chanlist=&ao_chan;
ao_trig.data=&ao_data;
ao_trig.data_len=sizeof(ao_data);
ao_trig.n=1;
ao_trig.trigsrc=0;
ao_trig.trigvar=0;
ao_trig.trigvar1=0;
// lock the subdevices
comedi_lock_ioctl(ai_dev,ai_subdev);
comedi_lock_ioctl(ao_dev,ao_subdev);
// ... create the realtime task with the default function
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, THREAD_STACK_SIZE);
sched_param.sched_priority = 100;
pthread_attr_setschedparam(&attr, &sched_param);
rtl_printf("create thread\n");
if((ret = pthread_create(&rt_thread, &attr, thread_code, (void *)0)) != 0) {
rtl_printf("unable to create realtime thread (error %d) !\n", ret);
}
#if 1
rtl_printf("make thread periodic\n");
if((ret = pthread_make_periodic_np(rt_thread, gethrtime() + 1000, HRTIME_INFINITY)) != 0) {
rtl_printf("unable to make realtime thread periodic (error %d) !\n", ret);
}
#else
rtl_printf("make thread periodic (1s)\n");
if((ret = pthread_make_periodic_np(rt_thread, gethrtime() + 1000, 1000000000)) != 0) {
rtl_printf("unable to make realtime thread periodic (error %d) !\n", ret);
}
#endif
rtl_printf("register our callback function\n");
ret=comedi_register_callback(ai_dev, ai_subdev, COMEDI_CB_EOS, &callback, (void *)0);
/* start acq. */
ret=comedi_trig_ioctl(ai_dev,ai_subdev,&ai_trig);
rtl_printf("comedi_callback module started\n");
return 0;
}
void cleanup_module(void)
{
comedi_cancel_ioctl(ai_dev,ai_subdev);
comedi_unlock_ioctl(ai_dev,ai_subdev);
comedi_unlock_ioctl(ao_dev,ao_subdev);
pthread_suspend_np(rt_thread);
pthread_setfp_np(rt_thread, 0);
pthread_delete_np(rt_thread);
rtf_destroy(1);
rtl_printf("comedi_callback stopped\n");
}