diff --git a/Documentation/components/drivers/character/timers/capture.rst b/Documentation/components/drivers/character/timers/capture.rst index 03b492146f18e..046f1b049116a 100644 --- a/Documentation/components/drivers/character/timers/capture.rst +++ b/Documentation/components/drivers/character/timers/capture.rst @@ -72,17 +72,58 @@ Supported ``ioctl`` Commands **Argument:** ``int`` (value to watch for). +.. c:macro:: CAPIOC_REGISTER + + Register for capture edge event notifications. This allows applications + to receive asynchronous signal notifications when capture edge events + occur, instead of polling for events. + + **Argument:** ``struct cap_notify_s *`` (pointer to notification structure). + + The ``struct cap_notify_s`` contains: + + * ``event`` - The signal event configuration (``struct sigevent``) + * ``chan`` - Capture channel number + * ``type`` - Edge type (``CAP_TYPE_RISING``, ``CAP_TYPE_FALLING``, or ``CAP_TYPE_BOTH``) + * ``ptr`` - User data pointer + + **Returns:** + + * ``OK`` on success + * ``-EINVAL`` for invalid channel + * ``-EBUSY`` if channel already registered by another task + +.. c:macro:: CAPIOC_UNREGISTER + + Unregister capture edge event notifications. + + **Argument:** ``int`` (channel number). + + **Returns:** ``OK`` on success. + Configuration ------------- To enable the capture driver, enable the following configuration options: -* ``CONFIG_CAPTURE`` -* ``CONFIG_STM32H7_TIM4_CAP`` (for STM32H7 Timer 4) +* ``CONFIG_CAPTURE`` - Enable the capture driver framework +* ``CONFIG_CAPTURE_NOTIFY`` - Enable signal notification support for edge events +* ``CONFIG_FAKE_CAPTURE`` - Enable fake capture driver for testing (generates 10Hz signal with 50% duty cycle) +* ``CONFIG_STM32H7_TIM4_CAP`` (for STM32H7 Timer 4, platform-specific) The ``CONFIG_CAPTURE`` option enables the lower-half driver and registers the ``/dev/capture`` device. +The ``CONFIG_CAPTURE_NOTIFY`` option enables the signal notification feature, +allowing applications to receive asynchronous notifications when capture +edge events occur. This requires hardware support for edge interrupts and +depends on ``CONFIG_CAPTURE``. + +The ``CONFIG_FAKE_CAPTURE`` option enables a software-based fake capture +driver that simulates a 10Hz square wave with 50% duty cycle. This is +useful for development and testing without requiring actual hardware. +It depends on ``CONFIG_CAPTURE`` and ``CONFIG_CAPTURE_NSIGNALS > 0``. + Without it, capture is still possible manually by including the appropriate header (e.g., ``arch/arm/src/stm32h7/stm32_capture.h``) and performing a manual initialization. @@ -125,6 +166,129 @@ frequency: return 0; } +Signal Notification Example +---------------------------- + +Here is an example using signal notifications for event-driven capture +(requires ``CONFIG_CAPTURE_NOTIFY``): + +.. code-block:: c + + #include + #include + #include + #include + #include + + static volatile int edge_count = 0; + + static void capture_handler(int signo, siginfo_t *info, void *context) + { + edge_count++; + } + + int main(int argc, char *argv[]) + { + int fd; + struct cap_notify_s notify; + struct sigaction sa; + uint32_t frequency; + uint8_t duty; + + /* Set up signal handler */ + sa.sa_sigaction = capture_handler; + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + sigaction(SIGUSR1, &sa, NULL); + + /* Open capture device */ + fd = open("/dev/capture0", O_RDONLY); + if (fd < 0) + { + perror("Failed to open capture device"); + return 1; + } + + /* Configure notification for both edges on channel 0 */ + notify.chan = 0; + notify.type = CAP_TYPE_BOTH; + notify.event.sigev_notify = SIGEV_SIGNAL; + notify.event.sigev_signo = SIGUSR1; + notify.event.sigev_value.sival_ptr = NULL; + + if (ioctl(fd, CAPIOC_REGISTER, (unsigned long)¬ify) < 0) + { + perror("Failed to register notification"); + close(fd); + return 1; + } + + printf("Waiting for capture events...\n"); + + /* Wait for some events */ + sleep(2); + + /* Get frequency and duty cycle */ + ioctl(fd, CAPIOC_FREQUENCE, (unsigned long)&frequency); + ioctl(fd, CAPIOC_DUTYCYCLE, (unsigned long)&duty); + + printf("Captured %d edges\n", edge_count); + printf("Frequency: %u Hz, Duty: %u%%\n", frequency, duty); + + /* Unregister notification */ + ioctl(fd, CAPIOC_UNREGISTER, 0); + + close(fd); + return 0; + } + +Fake Capture Testing Example +----------------------------- + +The fake capture driver can be used for testing without hardware +(requires ``CONFIG_FAKE_CAPTURE``): + +.. code-block:: c + + #include + #include + #include + #include + + int main(int argc, char *argv[]) + { + int fd; + uint32_t frequency; + uint8_t duty; + + /* Open fake capture device */ + fd = open("/dev/fake_capture0", O_RDONLY); + if (fd < 0) + { + perror("Failed to open fake capture device"); + return 1; + } + + /* Start capture */ + ioctl(fd, CAPIOC_START, 0); + + /* Wait for capture to stabilize */ + sleep(1); + + /* Read values (should be 10Hz, 50% duty) */ + ioctl(fd, CAPIOC_FREQUENCE, (unsigned long)&frequency); + ioctl(fd, CAPIOC_DUTYCYCLE, (unsigned long)&duty); + + printf("Fake Capture - Frequency: %u Hz, Duty: %u%%\n", + frequency, duty); + + /* Stop capture */ + ioctl(fd, CAPIOC_STOP, 0); + + close(fd); + return 0; + } + Notes ----- @@ -136,3 +300,38 @@ Notes * **Important:** In debug builds of NuttX, calling an unsupported ``ioctl`` command will trigger a ``DEBUGASSERT`` in the driver, which will halt or crash the system. + +Signal Notification Features +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When ``CONFIG_CAPTURE_NOTIFY`` is enabled: + +* Applications can register for asynchronous edge event notifications +* Supports per-channel registration with independent configurations +* Edge types supported: rising edge (``CAP_TYPE_RISING``), falling edge + (``CAP_TYPE_FALLING``), or both (``CAP_TYPE_BOTH``) +* Only one task can register per channel at a time +* Signal notifications use standard POSIX ``sigevent`` mechanism +* Lower-half drivers must implement ``bind()`` and ``unbind()`` operations +* Ideal for event-driven applications like tachometers, encoders, and + frequency counters + +Fake Capture Driver +~~~~~~~~~~~~~~~~~~~ + +The fake capture driver (``CONFIG_FAKE_CAPTURE``) provides: + +* Software simulation of capture events using watchdog timers +* Fixed 10Hz frequency with 50% duty cycle +* Edge toggles every 50ms (rising and falling) +* Supports all standard capture operations including notifications +* Available at ``/dev/fake_capture0``, ``/dev/fake_capture1``, etc. +* Useful for development, testing, and CI/CD without hardware +* Platform-independent implementation +* Automatically initialized at boot (2 channels by default) + +Limitations: + +* Fixed timing parameters (not configurable at runtime) +* Software timing accuracy (not hardware-precise) +* Suitable for functional testing, not timing precision validation diff --git a/drivers/drivers_initialize.c b/drivers/drivers_initialize.c index fec2a9857580c..0494768dbac0a 100644 --- a/drivers/drivers_initialize.c +++ b/drivers/drivers_initialize.c @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -298,5 +299,9 @@ void drivers_initialize(void) ptp_clock_dummy_initialize(0); #endif +#ifdef CONFIG_FAKE_CAPTURE + fake_capture_initialize(2); +#endif + drivers_trace_end(); } diff --git a/drivers/timers/CMakeLists.txt b/drivers/timers/CMakeLists.txt index 0f1370b71bedd..bde7acf51444f 100644 --- a/drivers/timers/CMakeLists.txt +++ b/drivers/timers/CMakeLists.txt @@ -84,6 +84,10 @@ endif() if(CONFIG_CAPTURE) list(APPEND SRCS capture.c) + + if(CONFIG_FAKE_CAPTURE) + list(APPEND SRCS fake_capture.c) + endif() endif() if(CONFIG_GOLDFISH_TIMER) diff --git a/drivers/timers/Kconfig b/drivers/timers/Kconfig index b96322734c952..7a822250c6bfa 100644 --- a/drivers/timers/Kconfig +++ b/drivers/timers/Kconfig @@ -92,6 +92,25 @@ config CAPTURE This selection enables building of the "upper-half" Capture driver. See include/nuttx/timers/capture.h for further Capture driver information. +if CAPTURE + +config CAPTURE_NOTIFY + bool "Capture Notification Support" + default n + ---help--- + Some hardware will support notification when a capture event + occurs. If the hardware will support notification, then this + configuration should be set to enable the capability. + +config FAKE_CAPTURE + bool "Fake Capture Driver" + default n + depends on CAPTURE_NSIGNALS > 0 + ---help--- + Enables a fake capture driver for testing purposes. + +endif # CAPTURE + config TIMER bool "Timer Support" default n diff --git a/drivers/timers/Make.defs b/drivers/timers/Make.defs index b9ab14e0fbdaf..03e8247813ed1 100644 --- a/drivers/timers/Make.defs +++ b/drivers/timers/Make.defs @@ -114,6 +114,11 @@ endif ifeq ($(CONFIG_CAPTURE),y) CSRCS += capture.c + + ifeq ($(CONFIG_FAKE_CAPTURE),y) + CSRCS += fake_capture.c + endif + TMRDEPPATH = --dep-path timers TMRVPATH = :timers endif diff --git a/drivers/timers/capture.c b/drivers/timers/capture.c index f39a338852746..e9746a9a43739 100644 --- a/drivers/timers/capture.c +++ b/drivers/timers/capture.c @@ -57,14 +57,32 @@ * Private Types ****************************************************************************/ +#ifdef CONFIG_CAPTURE_NOTIFY +struct cap_signal_s +{ + pid_t pid; /* The pid of the registering task */ + struct cap_notify_s notify; /* The notification callback info */ +#ifdef CONFIG_SIG_EVTHREAD + struct sigwork_s work; /* The signal work structure */ +#endif +}; +#endif + /* This structure describes the state of the upper half driver */ struct cap_upperhalf_s { - uint8_t crefs; /* The number of times the device has been opened */ - uint8_t nchan; /* The number of channels, only invalid for multi channels */ - mutex_t lock; /* Supports mutual exclusion */ - FAR struct cap_lowerhalf_s **lower; /* lower-half state */ + uint8_t crefs; /* The number of times the device has been opened */ + uint8_t nchan; /* The number of channels, only invalid for multi channels */ + mutex_t lock; /* Supports mutual exclusion */ + FAR struct cap_lowerhalf_s **lower; /* lower-half state */ +#ifdef CONFIG_CAPTURE_NOTIFY + /* The array of signal structures, the length of the array is nchan, + * save signal info for each channel. + */ + + struct cap_signal_s signals[1]; +#endif }; /**************************************************************************** @@ -97,6 +115,41 @@ static const struct file_operations g_capops = * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: cap_notify_cb + * + * Description: + * Capture edge interrupt notification callback + * + ****************************************************************************/ + +#ifdef CONFIG_CAPTURE_NOTIFY +static void cap_notify_cb(FAR struct cap_lowerhalf_s *lower, FAR void *priv) +{ + FAR struct cap_upperhalf_s *upper = priv; + uint8_t i; + + DEBUGASSERT(upper != NULL); + + for (i = 0; i < upper->nchan; i++) + { + if (lower == upper->lower[i]) + { + FAR struct cap_signal_s *signal = &upper->signals[i]; + +# ifdef CONFIG_SIG_EVTHREAD + nxsig_notification(signal->pid, &signal->notify.event, + SI_QUEUE, &signal->work); +# else + nxsig_notification(signal->pid, &signal->notify.event, + SI_QUEUE, NULL); +# endif + break; + } + } +} +#endif + /**************************************************************************** * Name: cap_open * @@ -384,6 +437,69 @@ static int cap_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } break; + /* CAPIOC_REGISTER - Register to receive a signal whenever there is + * an interrupt received on an input capture pin. This feature, + * of course, depends upon interrupt capture support from the platform. + * Argument: The event of signal to be generated when the interrupt + * occurs. + * + * the argument is a pointer to a struct cap_notify_s, that contains + * the channel number, edge type and signal event info. + */ + +#ifdef CONFIG_CAPTURE_NOTIFY + case CAPIOC_REGISTER: + { + FAR struct cap_signal_s *tmp; + FAR struct cap_notify_s *new; + pid_t pid; + + new = (FAR struct cap_notify_s *)(uintptr_t)arg; + if (!new || (new->chan >= upper->nchan && new->chan < 0)) + { + ret = -EINVAL; + break; + } + + pid = nxsched_getpid(); + tmp = &upper->signals[new->chan]; + if (tmp->pid != 0 && tmp->pid != pid) + { + ret = -EBUSY; + break; + } + + tmp->pid = pid; + memcpy(&tmp->notify, new, sizeof(*new)); + DEBUGASSERT(lower[new->chan]->ops->bind != NULL); + ret = lower[new->chan]->ops->bind(lower[new->chan], new->type, + cap_notify_cb, upper); + } + break; + + /* CAPIOC_UNREGISTER - Stop receiving signals for capture interrupts. + * Argument: The channel number + */ + + case CAPIOC_UNREGISTER: + { +# ifdef CONFIG_SIG_EVTHREAD + FAR struct sigwork_s *work; +# endif + int chan = (int)arg; + + upper->signals[chan].pid = 0; +# ifdef CONFIG_SIG_EVTHREAD + work = &upper->signals[chan].work; + nxsig_cancel_notification(work); +# endif + + DEBUGASSERT(lower[chan]->ops->unbind != NULL); + ret = lower[chan]->ops->unbind(lower[chan]); + } + break; +#endif + /* Any unrecognized IOCTL commands might be platform-specific ioctl * commands */ diff --git a/drivers/timers/fake_capture.c b/drivers/timers/fake_capture.c new file mode 100644 index 0000000000000..ffa9cf1ffc9bd --- /dev/null +++ b/drivers/timers/fake_capture.c @@ -0,0 +1,352 @@ +/**************************************************************************** + * drivers/timers/fake_capture.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define CAPTURE_DUTY_DEFAULT 50 +#define CAPTURE_FREQ_DEFAULT 10 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct fake_capture_s +{ + struct cap_lowerhalf_s lower; /* Lower half capture driver */ + spinlock_t lock; /* For mutually exclusive access */ + struct wdog_s wdog; /* For timing capture events */ + bool high; /* Current edge state */ + capture_notify_t cb; /* Capture event callback function pointer */ + FAR void *priv; /* Pointer to private data */ + enum cap_type_e type; /* Edge type for the capture channel */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int fake_capture_start(FAR struct cap_lowerhalf_s *lower); +static int fake_capture_stop(FAR struct cap_lowerhalf_s *lower); +static int fake_capture_getduty(FAR struct cap_lowerhalf_s *lower, + FAR uint8_t *duty); +static int fake_capture_getfreq(FAR struct cap_lowerhalf_s *lower, + FAR uint32_t *freq); +static int fake_capture_getedges(FAR struct cap_lowerhalf_s *lower, + FAR uint32_t *edges); +static int fake_capture_bind(FAR struct cap_lowerhalf_s *lower, + enum cap_type_e type, capture_notify_t cb, + FAR void *priv); +static int fake_capture_unbind(FAR struct cap_lowerhalf_s *lower); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct cap_ops_s g_fake_cap_ops = +{ + .start = fake_capture_start, + .stop = fake_capture_stop, + .getduty = fake_capture_getduty, + .getfreq = fake_capture_getfreq, + .getedges = fake_capture_getedges, + .bind = fake_capture_bind, + .unbind = fake_capture_unbind, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void fake_capture_isr(wdparm_t arg) +{ + FAR struct fake_capture_s *capture = (FAR struct fake_capture_s *)arg; + irqstate_t flags; + bool last; + + flags = spin_lock_irqsave(&capture->lock); + + last = capture->high; + capture->high = !capture->high; + + if (capture->cb != NULL && + (capture->type == CAP_TYPE_BOTH || + (capture->type == CAP_TYPE_RISING && !last) || + (capture->type == CAP_TYPE_FALLING && last))) + { + capture->cb(&capture->lower, capture->priv); + } + + spin_unlock_irqrestore(&capture->lock, flags); + + wd_start_next(&capture->wdog, MSEC2TICK(1000 / CAPTURE_FREQ_DEFAULT), + fake_capture_isr, (wdparm_t)capture); +} + +/**************************************************************************** + * Name: fake_capture_start + * + * Description: + * This function is a requirement of the upper-half driver. When called, + * enables the capture channel, interruption routine, sets the positive + * edge to trigger this interrupt and resets the frequency and duty + * values. The positive edge is always the first expected. + * + * Input Parameters: + * lower - Pointer to the capture channel lower-half data structure. + * + * Returned Value: + * Returns OK on success. + * + ****************************************************************************/ + +static int fake_capture_start(FAR struct cap_lowerhalf_s *lower) +{ + FAR struct fake_capture_s *capture = (FAR struct fake_capture_s *)lower; + + wd_start(&capture->wdog, MSEC2TICK(1000 / CAPTURE_FREQ_DEFAULT), + fake_capture_isr, (wdparm_t)capture); + return OK; +} + +/**************************************************************************** + * Name: fake_capture_stop + * + * Description: + * This function is a requirement of the upper-half driver. When called, + * disables the capture channel and the interrupt routine associated. + * + * Input Parameters: + * lower - Pointer to the capture channel lower-half data structure. + * + * Returned Value: + * Returns OK on success. + * + ****************************************************************************/ + +static int fake_capture_stop(FAR struct cap_lowerhalf_s *lower) +{ + FAR struct fake_capture_s *capture = (FAR struct fake_capture_s *)lower; + + wd_cancel(&capture->wdog); + return OK; +} + +/**************************************************************************** + * Name: fake_capture_getduty + * + * Description: + * This function is a requirement of the upper-half driver. Returns + * the last calculated duty cycle value. + * + * Input Parameters: + * lower - Pointer to the capture channel lower-half data structure. + * duty - uint8_t pointer where the duty cycle value is written. + * + * Returned Value: + * Returns OK on success. + * + ****************************************************************************/ + +static int fake_capture_getduty(FAR struct cap_lowerhalf_s *lower, + FAR uint8_t *duty) +{ + *duty = CAPTURE_DUTY_DEFAULT; + + return OK; +} + +/**************************************************************************** + * Name: fake_capture_getfreq + * + * Description: + * This function is a requirement of the upper-half driver. Returns + * the last calculated frequency value. + * + * Input Parameters: + * lower - Pointer to the capture channel lower-half data structure. + * duty - uint8_t pointer where the frequency value is written. + * + * Returned Value: + * Returns OK on success. + * + ****************************************************************************/ + +static int fake_capture_getfreq(FAR struct cap_lowerhalf_s *lower, + FAR uint32_t *freq) +{ + *freq = CAPTURE_FREQ_DEFAULT; + + return OK; +} + +/**************************************************************************** + * Name: fake_capture_getedges + * + * Description: + * This function is a requirement of the upper-half driver. Returns + * the current edge type configured for the capture channel. + * + * Input Parameters: + * lower - Pointer to the capture channel lower-half data structure. + * type - Pointer to the edge type variable to be updated. + * + * Returned Value: + * Returns OK on success. + * + ****************************************************************************/ + +static int fake_capture_getedges(FAR struct cap_lowerhalf_s *lower, + FAR uint32_t *edges) +{ + FAR struct fake_capture_s *capture = (FAR struct fake_capture_s *)lower; + irqstate_t flags = spin_lock_irqsave(&capture->lock); + + *edges = capture->high; + + spin_unlock_irqrestore(&capture->lock, flags); + return OK; +} + +/**************************************************************************** + * Name: fake_capture_bind + * + * Description: + * This function is used to bind a upper-half provided callback that will + * be invoked upon capture edge events. + * + * Input Parameters: + * lower - Pointer to the capture channel lower-half data structure. + * cb - The callback function pointer. + * priv - The private argument to be passed to the callback function. + * edge - The edge type that will trigger the callback. + * + * Returned Value: + * Returns OK on success. + * + ****************************************************************************/ + +static int fake_capture_bind(FAR struct cap_lowerhalf_s *lower, + enum cap_type_e type, capture_notify_t cb, + FAR void *priv) +{ + FAR struct fake_capture_s *capture = (FAR struct fake_capture_s *)lower; + irqstate_t flags = spin_lock_irqsave(&capture->lock); + + capture->cb = cb; + capture->priv = priv; + capture->type = type; + + spin_unlock_irqrestore(&capture->lock, flags); + return 0; +} + +/**************************************************************************** + * Name: fake_capture_unbind + * + * Description: + * This function is used to un-bind a previously bound upper-half provided + * callback that was to be invoked upon capture edge events. + * + * Input Parameters: + * lower - Pointer to the capture channel lower-half data structure. + * + * Returned Value: + * Returns OK on success. + * + ****************************************************************************/ + +static int fake_capture_unbind(FAR struct cap_lowerhalf_s *lower) +{ + FAR struct fake_capture_s *capture = (FAR struct fake_capture_s *)lower; + irqstate_t flags = spin_lock_irqsave(&capture->lock); + + capture->cb = NULL; + capture->priv = NULL; + + spin_unlock_irqrestore(&capture->lock, flags); + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: fake_capture_initialize + * + * Description: + * This function is called by board-specific logic to initialize + * fake capture. + * + * Input Parameters: + * channel - The capture channel number to initialize. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. The following + * possible error values may be returned (most are returned by + * register_driver()): + * + ****************************************************************************/ + +int fake_capture_initialize(int channels) +{ + char path[32]; + int ret = 0; + int i; + + for (i = 0; i < channels; i++) + { + FAR struct fake_capture_s *priv; + + priv = kmm_zalloc(sizeof(*priv)); + DEBUGASSERT(priv); + + spin_lock_init(&priv->lock); + priv->lower.ops = &g_fake_cap_ops; + snprintf(path, sizeof(path), "/dev/fake_capture%d", i); + ret = cap_register(path, &priv->lower); + if (ret < 0) + { + cperr("Failed to register capture:%d\n", ret); + kmm_free(priv); + break; + } + } + + return ret; +} diff --git a/include/nuttx/timers/capture.h b/include/nuttx/timers/capture.h index 2b72b22d26a6f..1e658d75ba4a0 100644 --- a/include/nuttx/timers/capture.h +++ b/include/nuttx/timers/capture.h @@ -29,6 +29,9 @@ #include #include +#include + +#include /**************************************************************************** * Pre-processor Definitions @@ -115,6 +118,22 @@ #define CAPIOC_ADD_WP _CAPIOC(9) +/* Command: CAPIOC_REGISTER + * Description: Register capture event notification. + * Arguments: A reference to struct cap_notify_s. + * Return: OK on success; ERROR on failure. + */ + +#define CAPIOC_REGISTER _CAPIOC(10) + +/* Command: CAPIOC_UNREGISTER + * Description: Unregister capture event notification. + * Arguments: Int value for capture channel. + * Return: OK on success; ERROR on failure. + */ + +#define CAPIOC_UNREGISTER _CAPIOC(11) + /**************************************************************************** * Public Types ****************************************************************************/ @@ -126,11 +145,38 @@ struct cap_all_s uint8_t duty; }; +struct cap_lowerhalf_s; +#ifdef CONFIG_CAPTURE_NOTIFY + +/* Capture type */ + +enum cap_type_e +{ + CAP_TYPE_RISING, + CAP_TYPE_FALLING, + CAP_TYPE_BOTH, +}; + +/* Capture notify information, used to cmd:CAPIOC_REGISTER */ + +struct cap_notify_s +{ + struct sigevent event; /* The signal to be sent */ + int chan; /* Capture channel */ + enum cap_type_e type; /* Capture edge type */ + FAR void *ptr; /* User data pointer */ +}; + +/* Capture edge interrupt notification callback */ + +typedef CODE void (*capture_notify_t)(FAR struct cap_lowerhalf_s *lower, + FAR void *priv); +#endif + /* This structure provides the "lower-half" driver operations available to * the "upper-half" driver. */ -struct cap_lowerhalf_s; struct cap_ops_s { /* Required methods *******************************************************/ @@ -162,6 +208,18 @@ struct cap_ops_s CODE int (*ioctl)(FAR struct cap_lowerhalf_s *dev, int cmd, unsigned long arg); + +#ifdef CONFIG_CAPTURE_NOTIFY + /* Bind the capture edge interrupt notification callback */ + + CODE int (*bind)(FAR struct cap_lowerhalf_s *lower, + enum cap_type_e type, capture_notify_t cb, + FAR void *priv); + + /* Un-Bind the capture edge interrupt notification callback */ + + CODE int (*unbind)(FAR struct cap_lowerhalf_s *lower); +#endif }; /* This structure provides the publicly visible representation of the @@ -218,6 +276,27 @@ int cap_register(FAR const char *devpath, int cap_register_multiple(FAR const char *devpath, FAR struct cap_lowerhalf_s **lower, int n); +/**************************************************************************** + * Name: fake_capture_initialize + * + * Description: + * This function is called by board-specific logic to initialize + * fake capture. + * + * Input Parameters: + * channel - The capture channel number to initialize. + * + * Returned Value: + * Zero (OK) on success; a negated errno value on failure. The following + * possible error values may be returned (most are returned by + * register_driver()): + * + ****************************************************************************/ + +#ifdef CONFIG_FAKE_CAPTURE +int fake_capture_initialize(int channels); +#endif + #undef EXTERN #ifdef __cplusplus }