Lines Matching +full:analog +full:- +full:pass +full:- +full:through
1 // SPDX-License-Identifier: GPL-2.0+
5 * Generates fake waveform signals that can be read through
13 * COMEDI - Linux Control and Measurement Device Interface
24 * Updated: Sat, 16 Mar 2002 17:34:48 -0800
30 * Auto-configuration is the default mode if no parameter is supplied during
32 * To disable auto-configuration mode, pass "noauto=1" parameter for module
35 * Auto-configuration options:
39 * [0] - Amplitude in microvolts for fake waveforms (default 1 volt)
40 * [1] - Period in microseconds for fake waveforms (default 0.1 sec)
69 MODULE_PARM_DESC(noauto, "Disable auto-configuration: (1=disable [defaults to enable])");
93 /* fake analog input ranges */
105 struct waveform_private *devpriv = dev->private; in fake_sawtooth()
106 struct comedi_subdevice *s = dev->read_subdev; in fake_sawtooth()
107 unsigned int offset = s->maxdata / 2; in fake_sawtooth()
110 &s->range_table->range[range_index]; in fake_sawtooth()
113 binary_amplitude = s->maxdata; in fake_sawtooth()
114 binary_amplitude *= devpriv->wf_amplitude; in fake_sawtooth()
115 do_div(binary_amplitude, krange->max - krange->min); in fake_sawtooth()
119 do_div(value, devpriv->wf_period); in fake_sawtooth()
125 value -= binary_amplitude; in fake_sawtooth()
126 if (value > s->maxdata) in fake_sawtooth()
127 value = s->maxdata; /* positive saturation */ in fake_sawtooth()
137 struct waveform_private *devpriv = dev->private; in fake_squarewave()
138 struct comedi_subdevice *s = dev->read_subdev; in fake_squarewave()
139 unsigned int offset = s->maxdata / 2; in fake_squarewave()
142 &s->range_table->range[range_index]; in fake_squarewave()
144 value = s->maxdata; in fake_squarewave()
145 value *= devpriv->wf_amplitude; in fake_squarewave()
146 do_div(value, krange->max - krange->min); in fake_squarewave()
148 /* get one of two values for square-wave and clamp */ in fake_squarewave()
149 if (current_time < devpriv->wf_period / 2) { in fake_squarewave()
153 value = offset - value; in fake_squarewave()
156 if (value > s->maxdata) in fake_squarewave()
157 value = s->maxdata; /* positive saturation */ in fake_squarewave()
167 return dev->read_subdev->maxdata / 2; in fake_flatline()
199 struct comedi_device *dev = devpriv->dev; in waveform_ai_timer()
200 struct comedi_subdevice *s = dev->read_subdev; in waveform_ai_timer()
201 struct comedi_async *async = s->async; in waveform_ai_timer()
202 struct comedi_cmd *cmd = &async->cmd; in waveform_ai_timer()
210 while (nsamples && devpriv->ai_convert_time < now) { in waveform_ai_timer()
211 unsigned int chanspec = cmd->chanlist[async->cur_chan]; in waveform_ai_timer()
215 CR_RANGE(chanspec), devpriv->wf_current); in waveform_ai_timer()
218 time_increment = devpriv->ai_convert_period; in waveform_ai_timer()
219 if (async->scan_progress == 0) { in waveform_ai_timer()
221 time_increment += devpriv->ai_scan_period - in waveform_ai_timer()
222 devpriv->ai_convert_period * in waveform_ai_timer()
223 cmd->scan_end_arg; in waveform_ai_timer()
225 devpriv->wf_current += time_increment; in waveform_ai_timer()
226 if (devpriv->wf_current >= devpriv->wf_period) in waveform_ai_timer()
227 devpriv->wf_current %= devpriv->wf_period; in waveform_ai_timer()
228 devpriv->ai_convert_time += time_increment; in waveform_ai_timer()
229 nsamples--; in waveform_ai_timer()
232 if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) { in waveform_ai_timer()
233 async->events |= COMEDI_CB_EOA; in waveform_ai_timer()
235 if (devpriv->ai_convert_time > now) in waveform_ai_timer()
236 time_increment = devpriv->ai_convert_time - now; in waveform_ai_timer()
239 mod_timer(&devpriv->ai_timer, in waveform_ai_timer()
256 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW); in waveform_ai_cmdtest()
257 err |= comedi_check_trigger_src(&cmd->scan_begin_src, in waveform_ai_cmdtest()
259 err |= comedi_check_trigger_src(&cmd->convert_src, in waveform_ai_cmdtest()
261 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); in waveform_ai_cmdtest()
262 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); in waveform_ai_cmdtest()
269 err |= comedi_check_trigger_is_unique(cmd->convert_src); in waveform_ai_cmdtest()
270 err |= comedi_check_trigger_is_unique(cmd->stop_src); in waveform_ai_cmdtest()
274 if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW) in waveform_ai_cmdtest()
275 err |= -EINVAL; /* scan period would be 0 */ in waveform_ai_cmdtest()
282 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); in waveform_ai_cmdtest()
284 if (cmd->convert_src == TRIG_NOW) { in waveform_ai_cmdtest()
285 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0); in waveform_ai_cmdtest()
286 } else { /* cmd->convert_src == TRIG_TIMER */ in waveform_ai_cmdtest()
287 if (cmd->scan_begin_src == TRIG_FOLLOW) { in waveform_ai_cmdtest()
288 err |= comedi_check_trigger_arg_min(&cmd->convert_arg, in waveform_ai_cmdtest()
293 if (cmd->scan_begin_src == TRIG_FOLLOW) { in waveform_ai_cmdtest()
294 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0); in waveform_ai_cmdtest()
295 } else { /* cmd->scan_begin_src == TRIG_TIMER */ in waveform_ai_cmdtest()
296 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, in waveform_ai_cmdtest()
300 err |= comedi_check_trigger_arg_min(&cmd->chanlist_len, 1); in waveform_ai_cmdtest()
301 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, in waveform_ai_cmdtest()
302 cmd->chanlist_len); in waveform_ai_cmdtest()
304 if (cmd->stop_src == TRIG_COUNT) in waveform_ai_cmdtest()
305 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1); in waveform_ai_cmdtest()
306 else /* cmd->stop_src == TRIG_NONE */ in waveform_ai_cmdtest()
307 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); in waveform_ai_cmdtest()
314 if (cmd->convert_src == TRIG_TIMER) { in waveform_ai_cmdtest()
316 arg = cmd->convert_arg; in waveform_ai_cmdtest()
320 if (cmd->scan_begin_arg == TRIG_TIMER) { in waveform_ai_cmdtest()
322 limit = UINT_MAX / cmd->scan_end_arg; in waveform_ai_cmdtest()
326 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg); in waveform_ai_cmdtest()
329 if (cmd->scan_begin_src == TRIG_TIMER) { in waveform_ai_cmdtest()
331 arg = cmd->scan_begin_arg; in waveform_ai_cmdtest()
335 if (cmd->convert_src == TRIG_TIMER) { in waveform_ai_cmdtest()
337 arg = max(arg, cmd->convert_arg * cmd->scan_end_arg); in waveform_ai_cmdtest()
339 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg); in waveform_ai_cmdtest()
351 struct waveform_private *devpriv = dev->private; in waveform_ai_cmd()
352 struct comedi_cmd *cmd = &s->async->cmd; in waveform_ai_cmd()
356 if (cmd->flags & CMDF_PRIORITY) { in waveform_ai_cmd()
357 dev_err(dev->class_dev, in waveform_ai_cmd()
359 return -1; in waveform_ai_cmd()
362 if (cmd->convert_src == TRIG_NOW) in waveform_ai_cmd()
363 devpriv->ai_convert_period = 0; in waveform_ai_cmd()
364 else /* cmd->convert_src == TRIG_TIMER */ in waveform_ai_cmd()
365 devpriv->ai_convert_period = cmd->convert_arg / NSEC_PER_USEC; in waveform_ai_cmd()
367 if (cmd->scan_begin_src == TRIG_FOLLOW) { in waveform_ai_cmd()
368 devpriv->ai_scan_period = devpriv->ai_convert_period * in waveform_ai_cmd()
369 cmd->scan_end_arg; in waveform_ai_cmd()
370 } else { /* cmd->scan_begin_src == TRIG_TIMER */ in waveform_ai_cmd()
371 devpriv->ai_scan_period = cmd->scan_begin_arg / NSEC_PER_USEC; in waveform_ai_cmd()
381 first_convert_time = devpriv->ai_convert_period; in waveform_ai_cmd()
382 if (cmd->scan_begin_src == TRIG_TIMER) in waveform_ai_cmd()
383 first_convert_time += devpriv->ai_scan_period; in waveform_ai_cmd()
384 devpriv->ai_convert_time = ktime_to_us(ktime_get()) + in waveform_ai_cmd()
388 wf_current = devpriv->ai_convert_time; in waveform_ai_cmd()
389 devpriv->wf_current = do_div(wf_current, devpriv->wf_period); in waveform_ai_cmd()
396 devpriv->ai_timer.expires = in waveform_ai_cmd()
397 jiffies + usecs_to_jiffies(devpriv->ai_convert_period) + 1; in waveform_ai_cmd()
398 add_timer(&devpriv->ai_timer); in waveform_ai_cmd()
405 struct waveform_private *devpriv = dev->private; in waveform_ai_cancel()
409 del_timer(&devpriv->ai_timer); in waveform_ai_cancel()
411 del_timer_sync(&devpriv->ai_timer); in waveform_ai_cancel()
420 struct waveform_private *devpriv = dev->private; in waveform_ai_insn_read()
421 int i, chan = CR_CHAN(insn->chanspec); in waveform_ai_insn_read()
423 for (i = 0; i < insn->n; i++) in waveform_ai_insn_read()
424 data[i] = devpriv->ao_loopbacks[chan]; in waveform_ai_insn_read()
426 return insn->n; in waveform_ai_insn_read()
436 struct comedi_device *dev = devpriv->dev; in waveform_ao_timer()
437 struct comedi_subdevice *s = dev->write_subdev; in waveform_ao_timer()
438 struct comedi_async *async = s->async; in waveform_ao_timer()
439 struct comedi_cmd *cmd = &async->cmd; in waveform_ao_timer()
446 scans_since = now - devpriv->ao_last_scan_time; in waveform_ao_timer()
447 do_div(scans_since, devpriv->ao_scan_period); in waveform_ao_timer()
461 comedi_samples_to_bytes(s, cmd->scan_end_arg * in waveform_ao_timer()
462 (scans_avail - 1)); in waveform_ao_timer()
468 async->events |= COMEDI_CB_OVERFLOW; in waveform_ao_timer()
473 for (i = 0; i < cmd->scan_end_arg; i++) { in waveform_ao_timer()
474 unsigned int chan = CR_CHAN(cmd->chanlist[i]); in waveform_ao_timer()
477 pd = &devpriv->ao_loopbacks[chan]; in waveform_ao_timer()
481 async->events |= COMEDI_CB_OVERFLOW; in waveform_ao_timer()
486 devpriv->ao_last_scan_time += in waveform_ao_timer()
487 (u64)scans_avail * devpriv->ao_scan_period; in waveform_ao_timer()
490 if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg) { in waveform_ao_timer()
491 async->events |= COMEDI_CB_EOA; in waveform_ao_timer()
493 async->events |= COMEDI_CB_OVERFLOW; in waveform_ao_timer()
495 unsigned int time_inc = devpriv->ao_last_scan_time + in waveform_ao_timer()
496 devpriv->ao_scan_period - now; in waveform_ao_timer()
498 mod_timer(&devpriv->ao_timer, in waveform_ao_timer()
510 struct waveform_private *devpriv = dev->private; in waveform_ao_inttrig_start()
511 struct comedi_async *async = s->async; in waveform_ao_inttrig_start()
512 struct comedi_cmd *cmd = &async->cmd; in waveform_ao_inttrig_start()
514 if (trig_num != cmd->start_arg) in waveform_ao_inttrig_start()
515 return -EINVAL; in waveform_ao_inttrig_start()
517 async->inttrig = NULL; in waveform_ao_inttrig_start()
519 devpriv->ao_last_scan_time = ktime_to_us(ktime_get()); in waveform_ao_inttrig_start()
520 devpriv->ao_timer.expires = in waveform_ao_inttrig_start()
521 jiffies + usecs_to_jiffies(devpriv->ao_scan_period); in waveform_ao_inttrig_start()
522 add_timer(&devpriv->ao_timer); in waveform_ao_inttrig_start()
536 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_INT); in waveform_ao_cmdtest()
537 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); in waveform_ao_cmdtest()
538 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW); in waveform_ao_cmdtest()
539 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); in waveform_ao_cmdtest()
540 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); in waveform_ao_cmdtest()
547 err |= comedi_check_trigger_is_unique(cmd->stop_src); in waveform_ao_cmdtest()
556 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, in waveform_ao_cmdtest()
558 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0); in waveform_ao_cmdtest()
559 err |= comedi_check_trigger_arg_min(&cmd->chanlist_len, 1); in waveform_ao_cmdtest()
560 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, in waveform_ao_cmdtest()
561 cmd->chanlist_len); in waveform_ao_cmdtest()
562 if (cmd->stop_src == TRIG_COUNT) in waveform_ao_cmdtest()
563 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1); in waveform_ao_cmdtest()
564 else /* cmd->stop_src == TRIG_NONE */ in waveform_ao_cmdtest()
565 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); in waveform_ao_cmdtest()
573 arg = cmd->scan_begin_arg; in waveform_ao_cmdtest()
576 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg); in waveform_ao_cmdtest()
587 struct waveform_private *devpriv = dev->private; in waveform_ao_cmd()
588 struct comedi_cmd *cmd = &s->async->cmd; in waveform_ao_cmd()
590 if (cmd->flags & CMDF_PRIORITY) { in waveform_ao_cmd()
591 dev_err(dev->class_dev, in waveform_ao_cmd()
593 return -1; in waveform_ao_cmd()
596 devpriv->ao_scan_period = cmd->scan_begin_arg / NSEC_PER_USEC; in waveform_ao_cmd()
597 s->async->inttrig = waveform_ao_inttrig_start; in waveform_ao_cmd()
604 struct waveform_private *devpriv = dev->private; in waveform_ao_cancel()
606 s->async->inttrig = NULL; in waveform_ao_cancel()
609 del_timer(&devpriv->ao_timer); in waveform_ao_cancel()
611 del_timer_sync(&devpriv->ao_timer); in waveform_ao_cancel()
620 struct waveform_private *devpriv = dev->private; in waveform_ao_insn_write()
621 int i, chan = CR_CHAN(insn->chanspec); in waveform_ao_insn_write()
623 for (i = 0; i < insn->n; i++) in waveform_ao_insn_write()
624 devpriv->ao_loopbacks[chan] = data[i]; in waveform_ao_insn_write()
626 return insn->n; in waveform_ao_insn_write()
653 return -EINVAL; in waveform_ai_insn_config()
668 return -EINVAL; in waveform_ao_insn_config()
681 return -ENOMEM; in waveform_common_attach()
683 devpriv->wf_amplitude = amplitude; in waveform_common_attach()
684 devpriv->wf_period = period; in waveform_common_attach()
690 s = &dev->subdevices[0]; in waveform_common_attach()
691 dev->read_subdev = s; in waveform_common_attach()
692 /* analog input subdevice */ in waveform_common_attach()
693 s->type = COMEDI_SUBD_AI; in waveform_common_attach()
694 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; in waveform_common_attach()
695 s->n_chan = N_CHANS; in waveform_common_attach()
696 s->maxdata = 0xffff; in waveform_common_attach()
697 s->range_table = &waveform_ai_ranges; in waveform_common_attach()
698 s->len_chanlist = s->n_chan * 2; in waveform_common_attach()
699 s->insn_read = waveform_ai_insn_read; in waveform_common_attach()
700 s->do_cmd = waveform_ai_cmd; in waveform_common_attach()
701 s->do_cmdtest = waveform_ai_cmdtest; in waveform_common_attach()
702 s->cancel = waveform_ai_cancel; in waveform_common_attach()
703 s->insn_config = waveform_ai_insn_config; in waveform_common_attach()
705 s = &dev->subdevices[1]; in waveform_common_attach()
706 dev->write_subdev = s; in waveform_common_attach()
707 /* analog output subdevice (loopback) */ in waveform_common_attach()
708 s->type = COMEDI_SUBD_AO; in waveform_common_attach()
709 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; in waveform_common_attach()
710 s->n_chan = N_CHANS; in waveform_common_attach()
711 s->maxdata = 0xffff; in waveform_common_attach()
712 s->range_table = &waveform_ai_ranges; in waveform_common_attach()
713 s->len_chanlist = s->n_chan; in waveform_common_attach()
714 s->insn_write = waveform_ao_insn_write; in waveform_common_attach()
715 s->insn_read = waveform_ai_insn_read; /* do same as AI insn_read */ in waveform_common_attach()
716 s->do_cmd = waveform_ao_cmd; in waveform_common_attach()
717 s->do_cmdtest = waveform_ao_cmdtest; in waveform_common_attach()
718 s->cancel = waveform_ao_cancel; in waveform_common_attach()
719 s->insn_config = waveform_ao_insn_config; in waveform_common_attach()
722 for (i = 0; i < s->n_chan; i++) in waveform_common_attach()
723 devpriv->ao_loopbacks[i] = s->maxdata / 2; in waveform_common_attach()
725 devpriv->dev = dev; in waveform_common_attach()
726 timer_setup(&devpriv->ai_timer, waveform_ai_timer, 0); in waveform_common_attach()
727 timer_setup(&devpriv->ao_timer, waveform_ao_timer, 0); in waveform_common_attach()
729 dev_info(dev->class_dev, in waveform_common_attach()
731 dev->board_name, in waveform_common_attach()
732 devpriv->wf_amplitude, devpriv->wf_period); in waveform_common_attach()
740 int amplitude = it->options[0]; in waveform_attach()
741 int period = it->options[1]; in waveform_attach()
769 struct waveform_private *devpriv = dev->private; in waveform_detach()
772 del_timer_sync(&devpriv->ai_timer); in waveform_detach()
773 del_timer_sync(&devpriv->ao_timer); in waveform_detach()
786 * For auto-configuration, a device is created to stand in for a
814 pr_warn("comedi_test: unable to auto-configure device\n"); in comedi_test_init()
845 MODULE_DESCRIPTION("Comedi low-level driver");