Skip to content
Snippets Groups Projects
Commit 197cec58 authored by Sebastien Lorquet's avatar Sebastien Lorquet Committed by Gregory Nutt
Browse files

timer driver: Use signal to notify of timer expiration. Add generic argument...

timer driver: Use signal to notify of timer expiration. Add generic argument so that there can be additional usage.
parent 18ad40b9
No related branches found
No related tags found
No related merge requests found
......@@ -3,9 +3,11 @@
*
* Copyright (C) 2015 Wail Khemir. All rights reserved.
* Copyright (C) 2015 Omni Hoverboards Inc. All rights reserved.
* Copyright (C) 2016 Sebastien Lorquet All rights reserved.
* Authors: Wail Khemir <khemirwail@gmail.com>
* Paul Alexander Patience <paul-a.patience@polymtl.ca>
* dev@ziggurat29.com
* Sebastien Lorquet <sebastien@lorquet.fr>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
......@@ -91,7 +93,8 @@ struct stm32l4_lowerhalf_s
{
FAR const struct timer_ops_s *ops; /* Lower half operations */
FAR struct stm32l4_tim_dev_s *tim; /* stm32 timer driver */
tccb_t usrhandler; /* Current user interrupt handler */
tccb_t callback; /* Current upper half interrupt callback */
FAR void *arg; /* Argument passed to upper half callback */
const xcpt_t timhandler; /* Current timer interrupt handler */
bool started; /* True: Timer has been started */
const uint8_t resolution; /* Number of bits in the timer (16 or 32 bits) */
......@@ -145,8 +148,8 @@ static int stm32l4_start(FAR struct timer_lowerhalf_s *lower);
static int stm32l4_stop(FAR struct timer_lowerhalf_s *lower);
static int stm32l4_settimeout(FAR struct timer_lowerhalf_s *lower,
uint32_t timeout);
static tccb_t stm32l4_sethandler(FAR struct timer_lowerhalf_s *lower,
tccb_t handler);
static tccb_t stm32l4_setcallback(FAR struct timer_lowerhalf_s *lower,
tccb_t callback, FAR void *arg);
/****************************************************************************
* Private Data
......@@ -155,110 +158,110 @@ static tccb_t stm32l4_sethandler(FAR struct timer_lowerhalf_s *lower,
static const struct timer_ops_s g_timer_ops =
{
.start = stm32l4_start,
.stop = stm32l4_stop,
.getstatus = NULL,
.settimeout = stm32l4_settimeout,
.sethandler = stm32l4_sethandler,
.ioctl = NULL,
.start = stm32l4_start,
.stop = stm32l4_stop,
.getstatus = NULL,
.settimeout = stm32l4_settimeout,
.setcallback = stm32l4_setcallback,
.ioctl = NULL,
};
#ifdef CONFIG_STM32L4_TIM1
static struct stm32l4_lowerhalf_s g_tim1_lowerhalf =
{
.ops = &g_timer_ops,
.timhandler = stm32l4_tim1_interrupt,
.resolution = STM32L4_TIM1_RES,
.ops = &g_timer_ops,
.timhandler = stm32l4_tim1_interrupt,
.resolution = STM32L4_TIM1_RES,
};
#endif
#ifdef CONFIG_STM32L4_TIM2
static struct stm32l4_lowerhalf_s g_tim2_lowerhalf =
{
.ops = &g_timer_ops,
.timhandler = stm32l4_tim2_interrupt,
.resolution = STM32L4_TIM2_RES,
.ops = &g_timer_ops,
.timhandler = stm32l4_tim2_interrupt,
.resolution = STM32L4_TIM2_RES,
};
#endif
#ifdef CONFIG_STM32L4_TIM3
static struct stm32l4_lowerhalf_s g_tim3_lowerhalf =
{
.ops = &g_timer_ops,
.timhandler = stm32l4_tim3_interrupt,
.resolution = STM32L4_TIM3_RES,
.ops = &g_timer_ops,
.timhandler = stm32l4_tim3_interrupt,
.resolution = STM32L4_TIM3_RES,
};
#endif
#ifdef CONFIG_STM32L4_TIM4
static struct stm32l4_lowerhalf_s g_tim4_lowerhalf =
{
.ops = &g_timer_ops,
.timhandler = stm32l4_tim4_interrupt,
.resolution = STM32L4_TIM4_RES,
.ops = &g_timer_ops,
.timhandler = stm32l4_tim4_interrupt,
.resolution = STM32L4_TIM4_RES,
};
#endif
#ifdef CONFIG_STM32L4_TIM5
static struct stm32l4_lowerhalf_s g_tim5_lowerhalf =
{
.ops = &g_timer_ops,
.timhandler = stm32l4_tim5_interrupt,
.resolution = STM32L4_TIM5_RES,
.ops = &g_timer_ops,
.timhandler = stm32l4_tim5_interrupt,
.resolution = STM32L4_TIM5_RES,
};
#endif
#ifdef CONFIG_STM32L4_TIM6
static struct stm32l4_lowerhalf_s g_tim6_lowerhalf =
{
.ops = &g_timer_ops,
.timhandler = stm32l4_tim6_interrupt,
.resolution = STM32L4_TIM6_RES,
.ops = &g_timer_ops,
.timhandler = stm32l4_tim6_interrupt,
.resolution = STM32L4_TIM6_RES,
};
#endif
#ifdef CONFIG_STM32L4_TIM7
static struct stm32l4_lowerhalf_s g_tim7_lowerhalf =
{
.ops = &g_timer_ops,
.timhandler = stm32l4_tim7_interrupt,
.resolution = STM32L4_TIM7_RES,
.ops = &g_timer_ops,
.timhandler = stm32l4_tim7_interrupt,
.resolution = STM32L4_TIM7_RES,
};
#endif
#ifdef CONFIG_STM32L4_TIM8
static struct stm32l4_lowerhalf_s g_tim8_lowerhalf =
{
.ops = &g_timer_ops,
.timhandler = stm32l4_tim8_interrupt,
.resolution = STM32L4_TIM8_RES,
.ops = &g_timer_ops,
.timhandler = stm32l4_tim8_interrupt,
.resolution = STM32L4_TIM8_RES,
};
#endif
#ifdef CONFIG_STM32L4_TIM15
static struct stm32l4_lowerhalf_s g_tim15_lowerhalf =
{
.ops = &g_timer_ops,
.timhandler = stm32l4_tim15_interrupt,
.resolution = STM32L4_TIM15_RES,
.ops = &g_timer_ops,
.timhandler = stm32l4_tim15_interrupt,
.resolution = STM32L4_TIM15_RES,
};
#endif
#ifdef CONFIG_STM32L4_TIM16
static struct stm32l4_lowerhalf_s g_tim16_lowerhalf =
{
.ops = &g_timer_ops,
.timhandler = stm32l4_tim16_interrupt,
.resolution = STM32L4_TIM16_RES,
.ops = &g_timer_ops,
.timhandler = stm32l4_tim16_interrupt,
.resolution = STM32L4_TIM16_RES,
};
#endif
#ifdef CONFIG_STM32L4_TIM17
static struct stm32l4_lowerhalf_s g_tim17_lowerhalf =
{
.ops = &g_timer_ops,
.timhandler = stm32l4_tim17_interrupt,
.resolution = STM32L4_TIM17_RES,
.ops = &g_timer_ops,
.timhandler = stm32l4_tim17_interrupt,
.resolution = STM32L4_TIM17_RES,
};
#endif
......@@ -369,7 +372,7 @@ static int stm32l4_timer_handler(FAR struct stm32l4_lowerhalf_s *lower)
STM32L4_TIM_ACKINT(lower->tim, 0);
if (lower->usrhandler(&next_interval_us))
if (lower->callback(&next_interval_us, lower->arg))
{
if (next_interval_us > 0)
{
......@@ -407,7 +410,7 @@ static int stm32l4_start(FAR struct timer_lowerhalf_s *lower)
{
STM32L4_TIM_SETMODE(priv->tim, STM32L4_TIM_MODE_UP);
if (priv->usrhandler != NULL)
if (priv->callback != NULL)
{
STM32L4_TIM_SETISR(priv->tim, priv->timhandler, 0);
STM32L4_TIM_ENABLEINT(priv->tim, 0);
......@@ -505,11 +508,12 @@ static int stm32l4_settimeout(FAR struct timer_lowerhalf_s *lower,
* Call this user provided timeout handler.
*
* Input Parameters:
* lower - A pointer the publicly visible representation of the "lower-half"
* driver state structure.
* newhandler - The new timer expiration function pointer. If this
* function pointer is NULL, then the reset-on-expiration
* behavior is restored,
* lower - A pointer the publicly visible representation of the "lower-half"
* driver state structure.
* callback - The new timer expiration function pointer. If this
* function pointer is NULL, then the reset-on-expiration
* behavior is restored,
* arg - Argument that will be provided in the callback
*
* Returned Values:
* The previous timer expiration function pointer or NULL is there was
......@@ -517,22 +521,18 @@ static int stm32l4_settimeout(FAR struct timer_lowerhalf_s *lower,
*
****************************************************************************/
static tccb_t stm32l4_sethandler(FAR struct timer_lowerhalf_s *lower,
tccb_t newhandler)
static void stm32l4_setcallback(FAR struct timer_lowerhalf_s *lower,
tccb_t callback, FAR void *arg)
{
FAR struct stm32l4_lowerhalf_s *priv = (FAR struct stm32l4_lowerhalf_s *)lower;
irqstate_t flags = enter_critical_section();
/* Get the old handler return value */
tccb_t oldhandler = priv->usrhandler;
/* Save the new handler */
/* Save the new callback */
priv->usrhandler = newhandler;
priv->callback = callback;
priv->arg = arg;
if (newhandler != NULL && priv->started)
if (callback != NULL && priv->started)
{
STM32L4_TIM_SETISR(priv->tim, priv->timhandler, 0);
STM32L4_TIM_ENABLEINT(priv->tim, 0);
......@@ -544,7 +544,6 @@ static tccb_t stm32l4_sethandler(FAR struct timer_lowerhalf_s *lower,
}
leave_critical_section(flags);
return oldhandler;
}
/****************************************************************************
......@@ -636,9 +635,9 @@ int stm32l4_timer_initialize(FAR const char *devpath, int timer)
/* Initialize the elements of lower half state structure */
lower->started = false;
lower->usrhandler = NULL;
lower->tim = stm32l4_tim_init(timer);
lower->started = false;
lower->callback = NULL;
lower->tim = stm32l4_tim_init(timer);
if (lower->tim == NULL)
{
......
......@@ -46,6 +46,7 @@
#include <string.h>
#include <semaphore.h>
#include <fcntl.h>
#include <signal.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
......@@ -66,11 +67,9 @@
struct timer_upperhalf_s
{
uint8_t crefs; /* The number of times the device has been opened */
#ifdef HAVE_NOTIFICATION
uint8_t signal; /* The signal number to use in the notification */
uint8_t signo; /* The signal number to use in the notification */
pid_t pid; /* The ID of the task/thread to receive the signal */
FAR void *arg; /* An argument to pass with the signal */
#endif
FAR char *path; /* Registration path */
/* The contained lower-half driver */
......@@ -82,12 +81,7 @@ struct timer_upperhalf_s
* Private Function Prototypes
****************************************************************************/
#ifdef HAVE_NOTIFICATION
/* REVISIT: This function prototype is insufficient to support signaling */
static bool timer_notifier(FAR uint32_t *next_interval_us);
#endif
static bool timer_notifier(FAR uint32_t *next_interval_us, FAR void *arg);
static int timer_open(FAR struct file *filep);
static int timer_close(FAR struct file *filep);
static ssize_t timer_read(FAR struct file *filep, FAR char *buffer,
......@@ -131,15 +125,18 @@ static const struct file_operations g_timerops =
*
************************************************************************************/
#ifdef HAVE_NOTIFICATION
static bool timer_notifier(FAR uint32_t *next_interval_us)
static bool timer_notifier(FAR uint32_t *next_interval_us, FAR void *arg)
{
FAR struct timer_upperhalf_s *upper = HOW?;
FAR struct timer_upperhalf_s *upper = (FAR struct timer_upperhalf_s *)arg;
#ifdef CONFIG_CAN_PASS_STRUCTS
union sigval value;
#endif
int ret;
DEBUGASSERT(upper != NULL);
/* Signal the waiter.. if there is one */
#ifdef CONFIG_CAN_PASS_STRUCTS
value.sival_ptr = upper->arg;
ret = sigqueue(upper->pid, upper->signo, value);
......@@ -149,7 +146,6 @@ static bool timer_notifier(FAR uint32_t *next_interval_us)
return ret == OK;
}
#endif
/************************************************************************************
* Name: timer_open
......@@ -363,7 +359,6 @@ static int timer_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
}
break;
#ifdef HAVE_NOTIFICATION
/* cmd: TCIOC_NOTIFICATION
* Description: Notify application via a signal when the timer expires.
* Argument: signal number
......@@ -375,15 +370,15 @@ static int timer_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
case TCIOC_NOTIFICATION:
{
FAR struct timer_notify_s *notify =
(FAR struct timer_notify_s *)((uintptr_t)arg)
(FAR struct timer_notify_s *)((uintptr_t)arg);
if (notify != NULL)
{
upper->signo = notify->signal;
upper->get = notify->signal;
upper->arg = noify->arg;
upper->signo = notify->signo;
upper->pid = notify->pid;
upper->arg = notify->arg;
ret = timer_sethandler((FAR void *handle)upper, timer_notifier, NULL);
ret = timer_setcallback((FAR void *)upper, timer_notifier, upper);
}
else
{
......@@ -391,7 +386,6 @@ static int timer_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
}
}
break;
#endif
/* Any unrecognized IOCTL commands might be platform-specific ioctl commands */
......@@ -548,7 +542,7 @@ void timer_unregister(FAR void *handle)
}
/****************************************************************************
* Name: timer_sethandler
* Name: timer_setcallback
*
* Description:
* This function can be called to add a callback into driver-related code
......@@ -556,21 +550,20 @@ void timer_unregister(FAR void *handle)
* and may NOT be used by appliction code.
*
* Input parameters:
* handle - This is the handle that was returned by timer_register()
* newhandler - The new timer interrupt handler
* oldhandler - The previous timer interrupt handler (if any)
* handle - This is the handle that was returned by timer_register()
* newcallback - The new timer interrupt callback
* oldcallback - The previous timer interrupt callback (if any)
* arg - Argument to be provided with the callback
*
* Returned Value:
* None
*
****************************************************************************/
int timer_sethandler(FAR void *handle, tccb_t newhandler,
FAR tccb_t *oldhandler)
int timer_setcallback(FAR void *handle, tccb_t newcallback, FAR void *arg)
{
FAR struct timer_upperhalf_s *upper;
FAR struct timer_lowerhalf_s *lower;
tccb_t tmphandler;
/* Recover the pointer to the upper-half driver state */
......@@ -579,21 +572,13 @@ int timer_sethandler(FAR void *handle, tccb_t newhandler,
lower = upper->lower;
DEBUGASSERT(lower->ops != NULL);
/* Check if the lower half driver supports the sethandler method */
/* Check if the lower half driver supports the setcallback method */
if (lower->ops->sethandler != NULL) /* Optional */
if (lower->ops->setcallback != NULL) /* Optional */
{
/* Yes.. Defer the hander attachment to the lower half driver */
tmphandler = lower->ops->sethandler(lower, newhandler);
/* Return the oldhandler if a location to return it was provided */
if (oldhandler != NULL)
{
*oldhandler = tmphandler;
}
lower->ops->setcallback(lower, newcallback, arg);
return OK;
}
......
......@@ -52,11 +52,6 @@
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* It would require some interface modifcations in order to support
* notifications.
*/
#undef HAVE_NOTIFICATION
/* IOCTL Commands ***********************************************************/
/* The timer driver uses a standard character driver framework. However,
......@@ -96,9 +91,7 @@
#define TCIOC_STOP _TCIOC(0x0002)
#define TCIOC_GETSTATUS _TCIOC(0x0003)
#define TCIOC_SETTIMEOUT _TCIOC(0x0004)
#ifdef HAVE_NOTIFICATION
#define TCIOC_NOTIFICATION _TCIOC(0x0005)
#endif
/* Bit Settings *************************************************************/
/* Bit settings for the struct timer_status_s flags field */
......@@ -111,11 +104,11 @@
* Public Types
****************************************************************************/
/* User function prototype. Returns true to reload the timer, and the
/* Upper half callback prototype. Returns true to reload the timer, and the
* function can modify the next interval if desired.
*/
typedef CODE bool (*tccb_t)(FAR uint32_t *next_interval_us);
typedef CODE bool (*tccb_t)(FAR uint32_t *next_interval_us, FAR void *arg);
/* This is the type of the argument passed to the TCIOC_GETSTATUS ioctl and
* and returned by the "lower half" getstatus() method.
......@@ -129,16 +122,14 @@ struct timer_status_s
* (in microseconds) */
};
#ifdef HAVE_NOTIFICATION
/* This is the type of the argument passed to the TCIOC_NOTIFICATION ioctl */
struct timer_notify_s
{
FAR void *arg; /* An argument to pass with the signal */
pid_t pid; /* The ID of the task/thread to receive the signal */
uint8_t signal; /* The signal number to use in the notification */
uint8_t signo; /* The signal number to use in the notification */
};
#endif
/* This structure provides the "lower-half" driver operations available to
* the "upper-half" driver.
......@@ -166,12 +157,13 @@ struct timer_ops_s
CODE int (*settimeout)(FAR struct timer_lowerhalf_s *lower,
uint32_t timeout);
/* Call this user provider timeout handler on timeout.
* NOTE: Providing handler==NULL disable.
/* Call the NuttX INTERNAL timeout callback on timeout.
* NOTE: Providing callback==NULL disable.
* NOT to call back into applications.
*/
CODE tccb_t (*sethandler)(FAR struct timer_lowerhalf_s *lower,
CODE tccb_t handler);
CODE void (*setcallback)(FAR struct timer_lowerhalf_s *lower,
CODE tccb_t callback, FAR void *arg);
/* Any ioctl commands that are not recognized by the "upper-half" driver
* are forwarded to the lower half driver through this method.
......@@ -272,7 +264,7 @@ void timer_unregister(FAR void *handle);
****************************************************************************/
/****************************************************************************
* Name: timer_sethandler
* Name: timer_setcallback
*
* Description:
* This function can be called to add a callback into driver-related code
......@@ -280,9 +272,9 @@ void timer_unregister(FAR void *handle);
* and may NOT be used by appliction code.
*
* Input parameters:
* handle - This is the handle that was returned by timer_register()
* newhandler - The new timer interrupt handler
* oldhandler - The previous timer interrupt handler (if any)
* handle - This is the handle that was returned by timer_register()
* callback - The new timer interrupt callback
* arg - Argument provided when the callback is called.
*
* Returned Value:
* None
......@@ -290,8 +282,7 @@ void timer_unregister(FAR void *handle);
****************************************************************************/
#ifdef __KERNEL__
int timer_sethandler(FAR void *handle, tccb_t newhandler,
FAR tccb_t *oldhandler);
int timer_setcallback(FAR void *handle, tccb_t callback, FAR void *arg);
#endif
/****************************************************************************
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment