⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 comedi_rt_timer.c

📁 rtlinux-3.2-pre3.tar.bz2 rtlinux3.2-pre3的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    module/comedi_rt_timer.c    virtual driver for using RTL timing sources    Authors: David A. Schleef, Frank M. Hess    COMEDI - Linux Control and Measurement Device Interface    Copyright (C) 1999,2001 David A. Schleef <ds@schleef.org>    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., 675 Mass Ave, Cambridge, MA 02139, USA.***************************************************************************//*Driver: comedi_rt_timer.oDescription: Command emulator using real-time tasksAuthor: ds, fmhessDevices:Status: worksThis driver requires RTAI or RTLinux to work correctly.  It doesn'tactually drive hardware directly, but calls other drivers and usesa real-time task to emulate commands for drivers and devices thatare incapable of native commands.  Thus, you can get accuratelytimed I/O on any device.Since the timing is all done in software, sampling jitter is muchhigher than with a device that has an on-board timer, and maximumsample rate is much lower.Configuration options:  [0] - minor number of device you wish to emulate commands for  [1] - subdevice number you wish to emulate commands for*//*TODO:	Support for digital io commands could be added, except I can't see why		anyone would want to use them	What happens if device we are emulating for is de-configured?*/#include <linux/comedidev.h>#include <linux/comedilib.h>#include "comedi_fc.h"#ifdef CONFIG_COMEDI_RTL_V1#include <rtl_sched.h>#include <asm/rt_irq.h>#endif#ifdef CONFIG_COMEDI_RTL#include <rtl.h>#include <rtl_sched.h>#include <rtl_compat.h>#include <asm/div64.h>#ifndef RTLINUX_VERSION_CODE#define RTLINUX_VERSION_CODE 0#endif#ifndef RTLINUX_VERSION#define RTLINUX_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))#endif// begin hack to workaround broken HRT_TO_8254() function on rtlinux#if RTLINUX_VERSION_CODE <= RTLINUX_VERSION(3,0,100)// this function sole purpose is to divide a long long by 838static inline RTIME nano2count(long long ns){	do_div(ns, 838);	return ns;}#ifdef rt_get_time()#undef rt_get_time()#endif#define rt_get_time() nano2count(gethrtime())#else#define nano2count(x) HRT_TO_8254(x)#endif// end hack// rtl-rtai compatibility#define rt_task_wait_period() rt_task_wait()#define rt_pend_linux_srq(irq) rtl_global_pend_irq(irq)#define rt_free_srq(irq) rtl_free_soft_irq(irq)#define rt_request_srq(x,y,z) rtl_get_soft_irq(y,"timer")#define rt_task_init(a,b,c,d,e,f,g) rt_task_init(a,b,c,d,(e)+1)#define rt_task_resume(x) rt_task_wakeup(x)#define rt_set_oneshot_mode()#define start_rt_timer(x)#define stop_rt_timer()#endif#ifdef CONFIG_COMEDI_RTAI#include <rtai.h>#include <rtai_sched.h>#endif/* This defines the fastest speed we will emulate.  Note that * without a watchdog (like in RTAI), we could easily overrun our * task period because analog input tends to be slow. */#define SPEED_LIMIT 100000	/* in nanoseconds */static int timer_attach(comedi_device *dev,comedi_devconfig *it);static int timer_detach(comedi_device *dev);static int timer_inttrig(comedi_device *dev, comedi_subdevice *s, unsigned int trig_num);static int timer_start_cmd(comedi_device *dev, comedi_subdevice *s);static comedi_driver driver_timer={	module:		THIS_MODULE,	driver_name:	"comedi_rt_timer",	attach:		timer_attach,	detach:		timer_detach,//	open:		timer_open,};COMEDI_INITCLEANUP(driver_timer);typedef struct{	comedi_t *device;	// device we are emulating commands for	int subd;		// subdevice we are emulating commands for	RT_TASK *rt_task;	// rt task that starts scans	RT_TASK *scan_task;	// rt task that controls conversion timing in a scan	/* io_function can point to either an input or output function	 * depending on what kind of subdevice we are emulating for */	int (*io_function)(comedi_device *dev, comedi_cmd *cmd, unsigned int index);	// RTIME has units of 1 = 838 nanoseconds	// time at which first scan started, used to check scan timing	RTIME start;	// time between scans	RTIME scan_period;	// time between conversions in a scan	RTIME convert_period;	// flags	volatile int stop;	// indicates we should stop	volatile int rt_task_active;	// indicates rt_task is servicing a comedi_cmd	volatile int scan_task_active;	// indicates scan_task is servicing a comedi_cmd	unsigned timer_running : 1;}timer_private;#define devpriv ((timer_private *)dev->private)static int timer_cancel(comedi_device *dev,comedi_subdevice *s){	devpriv->stop = 1;	return 0;}// checks for scan timing errorinline static int check_scan_timing(comedi_device *dev,	unsigned long long scan){	RTIME now, timing_error;	now = rt_get_time();	timing_error = now - (devpriv->start + scan * devpriv->scan_period);	if(timing_error > devpriv->scan_period){		comedi_error(dev, "timing error");		rt_printk("scan started %i ns late\n", timing_error * 838);		return -1;	}	return 0;}// checks for conversion timing errorinline static int check_conversion_timing(comedi_device *dev,	RTIME scan_start, unsigned int conversion){	RTIME now, timing_error;	now = rt_get_time();	timing_error = now - (scan_start + conversion * devpriv->convert_period);	if(timing_error > devpriv->convert_period){		comedi_error(dev, "timing error");		rt_printk("conversion started %i ns late\n", timing_error * 838);		return -1;	}	return 0;}// devpriv->io_function for an input subdevicestatic int timer_data_read(comedi_device *dev, comedi_cmd *cmd,	unsigned int index){	comedi_subdevice *s = dev->read_subdev;	int ret;	lsampl_t data;	ret = comedi_data_read(devpriv->device, devpriv->subd,		CR_CHAN(cmd->chanlist[index]),		CR_RANGE(cmd->chanlist[index]),		CR_AREF(cmd->chanlist[index]),		&data);	if(ret<0){		comedi_error(dev, "read error");		return -EIO;	}	if( s->flags & SDF_LSAMPL ){		cfc_write_long_to_buffer( s, data );	}else{		comedi_buf_put( s->async, data );	}	return 0;}// devpriv->io_function for an output subdevicestatic int timer_data_write(comedi_device *dev, comedi_cmd *cmd,	unsigned int index){	comedi_subdevice *s = dev->write_subdev;	unsigned int num_bytes;	sampl_t data;	lsampl_t long_data;	int ret;	if( s->flags & SDF_LSAMPL ) {		num_bytes = cfc_read_array_from_buffer( s, &long_data, sizeof( long_data ) );	}else{		num_bytes = cfc_read_array_from_buffer( s, &data, sizeof( data ) );		long_data = data;	}	if(num_bytes == 0)	{		comedi_error(dev, "buffer underrun");		return -EAGAIN;	}	ret = comedi_data_write(devpriv->device, devpriv->subd,		CR_CHAN(cmd->chanlist[index]),		CR_RANGE(cmd->chanlist[index]),		CR_AREF(cmd->chanlist[index]),		long_data);	if(ret<0){		comedi_error(dev, "write error");		return -EIO;	}	return 0;}// devpriv->io_function for DIO subdevicesstatic int timer_dio_read(comedi_device *dev, comedi_cmd *cmd,	unsigned int index){	comedi_subdevice *s = dev->read_subdev;	int ret;	lsampl_t data;	ret = comedi_dio_bitfield(devpriv->device, devpriv->subd, 0, &data);	if(ret<0){		comedi_error(dev, "read error");		return -EIO;	}	if( s->flags & SDF_LSAMPL )		cfc_write_long_to_buffer( s, data );	else		cfc_write_to_buffer( s, data );	return 0;}// performs scansstatic void scan_task_func(int d){	comedi_device *dev=(comedi_device *)d;	comedi_subdevice *s = dev->subdevices + 0;	comedi_async *async = s->async;	comedi_cmd *cmd = &async->cmd;	int i, ret;	unsigned long long n;	RTIME scan_start;	// every comedi_cmd causes one execution of while loop	while(1){		devpriv->scan_task_active = 1;		// each for loop completes one scan		for(n = 0; n < cmd->stop_arg || cmd->stop_src == TRIG_NONE; n++){			if(n){				// suspend task until next scan				ret = rt_task_suspend(devpriv->scan_task);				if(ret < 0){					comedi_error(dev, "error suspending scan task");					async->events |= COMEDI_CB_ERROR;					goto cleanup;				}			}			// check if stop flag was set (by timer_cancel())			if(devpriv->stop)				goto cleanup;			ret = check_scan_timing(dev, n);			if(ret < 0){				async->events |= COMEDI_CB_ERROR;				goto cleanup;			}			scan_start = rt_get_time();			for(i = 0; i < cmd->scan_end_arg; i++){				// conversion timing				if(cmd->convert_src == TRIG_TIMER && i){					rt_task_wait_period();					ret = check_conversion_timing(dev, scan_start, i);					if(ret < 0){						async->events |= COMEDI_CB_ERROR;						goto cleanup;					}				}				ret = devpriv->io_function(dev, cmd, i);				if(ret < 0){					async->events |= COMEDI_CB_ERROR;					goto cleanup;				}			}			s->async->events |= COMEDI_CB_BLOCK;			comedi_event(dev,s,s->async->events);			s->async->events = 0;		}cleanup:		comedi_unlock(devpriv->device,devpriv->subd);		async->events |= COMEDI_CB_EOA;		comedi_event(dev, s, async->events);		async->events = 0;		devpriv->scan_task_active = 0;		// suspend task until next comedi_cmd		rt_task_suspend(devpriv->scan_task);	}}static void timer_task_func(int d){	comedi_device *dev=(comedi_device *)d;	comedi_subdevice *s = dev->subdevices + 0;	comedi_cmd *cmd=&s->async->cmd;	int ret;	unsigned long long n;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -