summaryrefslogtreecommitdiff
path: root/cesar/hal/timer/src
diff options
context:
space:
mode:
Diffstat (limited to 'cesar/hal/timer/src')
-rw-r--r--cesar/hal/timer/src/timer.c311
1 files changed, 311 insertions, 0 deletions
diff --git a/cesar/hal/timer/src/timer.c b/cesar/hal/timer/src/timer.c
new file mode 100644
index 0000000000..3fe8c2b950
--- /dev/null
+++ b/cesar/hal/timer/src/timer.c
@@ -0,0 +1,311 @@
+/* Cesar project {{{
+ *
+ * Copyright (C) 2008 Spidcom
+ *
+ * <<<Licence>>>
+ *
+ * }}} */
+/**
+ * \file hal/timer/src/timer.c
+ * \brief API source file for timers.
+ * \ingroup hal_timer
+ *
+ */
+#include "common/std.h"
+#include "hal/timer/timer.h"
+#include "hal/leon/timer.h"
+
+#include "hal/timer/inc/context.h"
+#include "hal/timer/inc/timer.h"
+
+static hal_timer_t hal_timer_global;
+
+/**
+ * Initialise software timer.
+ * \param phy the phy context.
+ * \return the newly created context
+ */
+hal_timer_t *
+hal_timer_init (phy_t *phy)
+{
+ dbg_assert (phy);
+
+ hal_timer_global.leon_timer = leon_timer_init (&hal_timer_global,
+ (leon_timer_cb_t) hal_timer_instance_process,
+ phy);
+
+ // initialise the heap.
+ heap_init (&hal_timer_global.heap, hal_timer_instance_lesser);
+
+ hal_timer_global.phy = phy;
+ hal_timer_global.current_instance = NULL;
+
+ return &hal_timer_global;
+}
+
+/**
+ * Uninitialise the software timer.
+ * \param ctx software timer context
+ *
+ * All timers should be stopped.
+ */
+void
+hal_timer_uninit (hal_timer_t *ctx)
+{
+ dbg_assert (ctx);
+ leon_timer_uninit(ctx->leon_timer);
+}
+
+/**
+ * Initialise a new timer instance.
+ * \param  ctx  software timer context
+ * \param  instance  instance to initialise
+ * \param  user_data  user data passed to the callback
+ * \param  cb  timer instance callback, called in DSR context
+ *
+ * The instance is initialised to unprogrammed state.
+ */
+void
+hal_timer_instance_init (hal_timer_t *ctx, hal_timer_instance_t *instance,
+ void *user_data, hal_timer_instance_cb_t cb)
+{
+ dbg_assert (ctx);
+ dbg_assert (instance);
+ dbg_assert (cb);
+
+ instance->user_data = user_data;
+ instance->cb = cb;
+ // Timer not armed.
+ instance->status = false;
+}
+
+/**
+ * Uninitialise a timer instance.
+ * \param  ctx  software timer context
+ * \param  instance  instance to uninitialise
+ *
+ * The timer instance is canceled if necessary.
+ */
+void
+hal_timer_instance_uninit (hal_timer_t *ctx, hal_timer_instance_t *instance)
+{
+ dbg_assert (ctx);
+ dbg_assert (instance);
+
+ instance->status = false;
+}
+
+/**
+ * Program an instance at the given date.
+ * \param  ctx  software timer context
+ * \param  instance  instance to program
+ * \param  date  instance expiration date
+ */
+void
+hal_timer_instance_program (hal_timer_t *ctx,
+ hal_timer_instance_t *instance, u32 date)
+{
+ dbg_assert (ctx);
+ dbg_assert (instance);
+ dbg_assert (ctx->phy);
+ dbg_assert (date > phy_date(ctx->phy));
+ // The real timer as 24 bits register.
+ dbg_assert (date < TIMER_MAX_TIME );
+
+ // initialise the node.
+ heap_node_init (&instance->node);
+ instance->date = date;
+
+ // lock the mutex to access to the heap.
+ cyg_mutex_lock (&ctx->heap_mutex);
+
+ // add the node to the heap.
+ heap_insert (&ctx->heap, &instance->node);
+
+ // unlock the mutex.
+ cyg_mutex_unlock (&ctx->heap_mutex);
+
+ // Modify the status of the timer.
+ instance->status = true;
+
+ // reprogram the leon timer
+ if (ctx->current_instance && (ctx->current_instance->date > date))
+ {
+ ctx->current_instance = instance;
+ leon_timer_cancel (ctx->leon_timer);
+ leon_timer_program (ctx->leon_timer, instance->date);
+ }
+ else if (ctx->current_instance == NULL)
+ {
+ ctx->current_instance = instance;
+ leon_timer_program (ctx->leon_timer, instance->date);
+ }
+}
+
+/**
+ * Get the next instance to program the timer.
+ *
+ * \param ctx the hal_timer context.
+ */
+void
+hal_timer_reprogram (hal_timer_t *ctx)
+{
+ hal_timer_instance_t *instance;
+ dbg_assert (ctx);
+
+ // Verify if the heap contains any node.
+ if (heap_empty(&ctx->heap))
+ return;
+
+ // lock the mutex to access to the heap.
+ cyg_mutex_lock (&ctx->heap_mutex);
+
+ // Get the root instance from the heap.
+ instance = PARENT_OF (hal_timer_instance_t, node, heap_get_root(&ctx->heap));
+
+ // unlock the mutex.
+ cyg_mutex_unlock (&ctx->heap_mutex);
+
+ if (instance)
+ {
+ // program the hardware timer.
+ leon_timer_program (ctx->leon_timer, instance->date);
+ }
+}
+
+/**
+ * Cancel an instance programmation.
+ * \param  ctx  software timer context
+ * \param  instance  instance to cancel
+ */
+void
+hal_timer_instance_cancel (hal_timer_t *ctx, hal_timer_instance_t *instance)
+{
+ dbg_assert (ctx);
+ dbg_assert (instance);
+
+ // verify the instance status.
+ if (instance->status == false)
+ return;
+
+ // lock the mutex to access to the heap.
+ cyg_mutex_lock (&ctx->heap_mutex);
+
+ // add the node to the heap.
+ if (!heap_empty (&ctx->heap))
+ heap_remove (&ctx->heap, &instance->node);
+
+ // unlock the mutex.
+ cyg_mutex_unlock (&ctx->heap_mutex);
+
+ // Cancel the timer.
+ if (ctx->current_instance == instance)
+ {
+ leon_timer_cancel (ctx->leon_timer);
+ hal_timer_reprogram (ctx);
+ }
+
+ instance->status = false;
+}
+
+/**
+ * Process the instance when the timer as rised the Interruption.
+ * This function will be call in dsr context.
+ *
+ * \param ctx the hal_timer context.
+ */
+void
+hal_timer_instance_process (hal_timer_t *ctx)
+{
+ hal_timer_instance_t *instance;
+
+ // lock the mutex to access
+ cyg_mutex_lock (&ctx->heap_mutex);
+
+ instance = PARENT_OF (hal_timer_instance_t, node, heap_get_root
+ (&ctx->heap));
+ heap_remove (&ctx->heap, &instance->node);
+
+ // unlock the mutex
+ cyg_mutex_unlock (&ctx->heap_mutex);
+
+ // call the callback function.
+ (*instance->cb) (instance->user_data);
+ instance->status = false;
+
+ // Verify the other next instance in the heap, if it has a previous date
+ // the callback will be called and the instance will be removed.
+ while (!heap_empty(&ctx->heap))
+ {
+ // lock the mutex to access
+ cyg_mutex_lock (&ctx->heap_mutex);
+
+ instance = PARENT_OF (hal_timer_instance_t, node, heap_get_root
+ (&ctx->heap));
+ // unlock the mutex
+ cyg_mutex_unlock (&ctx->heap_mutex);
+
+ if (instance->date < phy_date (ctx->phy))
+ {
+ // call the callback function.
+ (*instance->cb) (instance->user_data);
+
+ // remove the instance from the heap.
+ cyg_mutex_lock (&ctx->heap_mutex);
+
+ heap_remove (&ctx->heap, &instance->node);
+
+ // unlock the mutex
+ cyg_mutex_unlock (&ctx->heap_mutex);
+ instance->status = false;
+ }
+ else
+ break;
+ }
+
+ // program the timer with the next instance.
+ hal_timer_reprogram (ctx);
+}
+
+/**
+ * Compare the date of two node of the heap in the hal_timer context.
+ * \param left left hand node
+ * \param right right hand node
+ * \return true iff left is lesser than right
+ */
+bool
+hal_timer_instance_lesser (heap_node_t *left, heap_node_t *right)
+{
+ hal_timer_instance_t *left_node;
+ hal_timer_instance_t *right_node;
+
+
+ if ((left == NULL) && (right != NULL))
+ return false;
+ else if ((left != NULL) && (right == NULL))
+ return true;
+
+ left_node = PARENT_OF (hal_timer_instance_t, node, left);
+ right_node = PARENT_OF (hal_timer_instance_t, node, right);
+
+ // compare the dates
+ if (left_node->date < right_node->date)
+ return true;
+ else
+ return false;
+}
+
+/**
+ * Get the status of the timer intance.
+ *
+ * \return true if the instance is programed.
+ * false if the instance is not programed.
+ */
+bool
+hal_timer_instance_get_status (hal_timer_instance_t *instance)
+{
+ dbg_assert (instance);
+
+ return instance->status;
+}
+