Skip to content

Commit

Permalink
add timer with etl
Browse files Browse the repository at this point in the history
  • Loading branch information
tzhu committed Mar 16, 2024
1 parent 31c7a94 commit 298fe50
Show file tree
Hide file tree
Showing 6 changed files with 311 additions and 0 deletions.
24 changes: 24 additions & 0 deletions os-timer-port.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef _OS_TIMER_PORT_H_
#define _OS_TIMER_PORT_H_

#include "hal/timer/mtime.h"
#include "hal/timer/riscv_mtime_csr.h"

#define portTimerInit(cb) \
do \
{ \
MtimeSetPeriod(0); \
MtimeRegister(cb); \
} while (0)

#define portTimerStop() __mtime_set_compare(~0ULL)

#define portTimerTicksPerUs() ((MtimeGetPeriod() + 1) * 1000)

#define portTimerGetTick() __mtime_get_count()

#define portTimerComputeEndTick(tick) (portTimerGetTick() + (tick))

#define portTimerStart(end) __mtime_set_compare(end)

#endif
111 changes: 111 additions & 0 deletions os-timer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#include "os_timer.h"
#include "pt-os.h"
#include "os_timer_port.h"

constexpr int kMaxTimerItem = 16;

typedef struct
{
OsTimerCallback_t callback;
void *param;
uint64_t period_tick;
uint64_t end_tick;
int id;
bool repeatable;
} OsTimer_t;

volatile int kOsTimerTrigged_ = 0;
int kOsTimerHandled_ = 0;
int kOsTimerIdSeed_ = 0;
uint64_t kOsTimerTicksPerUs_ = 0;

struct tick_cmp
{
bool operator()(const OsTimer_t &a, const OsTimer_t &b) const { return a.end_tick < b.end_tick; }
};
etl::set<OsTimer_t, kMaxTimerItem, tick_cmp> gOsTimerObj_;

static void OsTimerIsrHandler_()
{
kOsTimerTrigged_ += 1;
portTimerStop();
}

TASK_DECLARE(OsTimerTask_(OsTaskId taskId, void *))
{
TASK_BEGIN(taskId);
while (1)
{
TASK_WAIT_UNTIL(taskId, kOsTimerTrigged_ > kOsTimerHandled_);
kOsTimerHandled_++;
// find the first timer. Which happened most recently.
auto tim = gOsTimerObj_.begin();
OS_ASSERT(tim != gOsTimerObj_.end()); // Shouldn't be empty.
if (tim->callback) tim->callback(tim->id, tim->param);
// update the repeatable timer.
if (tim->repeatable)
{
gOsTimerObj_.insert(
{tim->callback, tim->param, tim->period_tick, tim->end_tick + tim->period_tick, tim->id, true});
}
// remove the current timer.
gOsTimerObj_.erase(tim);
// if has one or more timer enable it.
if (gOsTimerObj_.size())
{
tim = gOsTimerObj_.begin();
portTimerStart(tim->end_tick);
}
}
TASK_END(taskId);
}

void OsTimerInit()
{
portTimerInit(OsTimerIsrHandler_);
portTimerStop();
kOsTimerTicksPerUs_ = portTimerTicksPerUs();
RegisterTask("thrTmr", OsTimerTask_, nullptr);
}

int OsTimerRegister(OsTimerCallback_t callback, void *param, uint64_t period_us, bool repeatable, int *id)
{
if (gOsTimerObj_.full()) return kLtMallocFail;
portTimerStop();
gOsTimerObj_.insert({callback, param, period_us * kOsTimerTicksPerUs_,
portTimerComputeEndTick(period_us * kOsTimerTicksPerUs_), ++kOsTimerIdSeed_, repeatable});
portTimerStart(gOsTimerObj_.begin()->end_tick);
if (id) *id = kOsTimerIdSeed_;
return TASK_OP_SUCCESS;
}

int OsTimerCount() { return gOsTimerObj_.size(); }

int OsTimerKill(int id)
{
for (auto it = gOsTimerObj_.begin(); it != gOsTimerObj_.end(); it++)
{
if (it->id == id)
{
gOsTimerObj_.erase(it);
return TASK_OP_SUCCESS;
}
}
}

static void timerDelayCallback_(int id, void *param)
{
bool *triggerred = (bool *)param;
// HAL_UartPrint("[TIM]: to %llu\n", portTimerGetTick());
*triggerred = true;
}

int OsTimerDelayUs(uint64_t delay_us)
{
bool timerTriggered = false;
// HAL_UartPrint("[TIM]: from %llu - %lluUs\n", portTimerGetTick(), delay_us);
int rc = OsTimerRegister(timerDelayCallback_, &timerTriggered, delay_us, false, 0);
if (rc != TASK_OP_SUCCESS) return rc;
while (timerTriggered == false) TaskYield();
return TASK_OP_SUCCESS;
}
47 changes: 47 additions & 0 deletions os-timer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#ifndef _OS_TIMER_H_
#define _OS_TIMER_H_

#ifdef __cplusplus
extern "C"
{
#endif
typedef void (*OsTimerCallback_t)(int id, void *param);
/*****************************************************************************\
* @description : Initialize the OsTimer module.
* @return {*}
\*****************************************************************************/
void OsTimerInit();

/*****************************************************************************\
* @description : Register a timer
* ------------
* @callback [I]: timer triggered callback function.
* @param [I]: input parameter for callback function.
* @period_us [I]: micro second delay to trigger the timer.
* @repeatable [I]: true=auto reload period_us.
* @id [O]: output the timer id for Kill. (Will be auto killed after
* triggered, if not repeatable timer)
* @return error or success
\*****************************************************************************/
int OsTimerRegister(OsTimerCallback_t callback, void *param, uint64_t period_us, bool repeatable, int *id);

/*****************************************************************************\
* @description : return number of active timer
* @return number of active timer
\*****************************************************************************/
int OsTimerCount();

/*****************************************************************************\
* @description : Kill a timer
* @id [I]: timer id, which given by OsTimerRegister(...,&id)
* @return error or success
\*****************************************************************************/
int OsTimerKill(int id);

int OsTimerDelayUs(uint64_t delay_us);

#ifdef __cplusplus
}
#endif

#endif
1 change: 1 addition & 0 deletions pt-os.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <pt.h>
#include "pt-osConfig.h"
#include "os-timer.h"

#define TASK_BEGIN(id) PT_BEGIN(id)
#define TASK_YIELD(id) PT_YIELD(id)
Expand Down
3 changes: 3 additions & 0 deletions tests/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ int Test2p1c();
int Test1p2c();
int TestResume();
int TestSubfunction();
int TestTimer();

int main()
{
Expand All @@ -27,5 +28,7 @@ int main()
rc += Test2p1c();
rc += TestResume();
rc += TestSubfunction();
rc += TestTimer();

return rc;
}
125 changes: 125 additions & 0 deletions tests/timer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#include <os.h>
#include <os-timer-port.h>

constexpr int kMaxTestNum_ = 10;
volatile int testCount = 0;
uint64_t tickStart;
static long testTimerParam[kMaxTestNum_];
constexpr long testTimerGolden[kMaxTestNum_] = {11, 33, 50, 51, 33, 99, 33, 33, 33, 33};
static uint64_t testTickCounter[kMaxTestNum_];
constexpr uint64_t testTickGolden[kMaxTestNum_] = {100, 300, 500, 500, 600, 900, 900, 1200, 1500, 1800};

void testTimerCallback_(int id, void *param)
{
testTickCounter[testCount] = portTimerGetTick() / 1000 - tickStart;
testTimerParam[testCount] = (long)param;
OS_TRACE("Timer%d: %lld happened at %llu\n", id, testTimerParam[testCount], testTickCounter[testCount]);
testCount++;
}

constexpr long kTimerTaskSeconds_ = 3;
long tCount1Ms = 0;
long tCount100Us = 0;
long tCountIdle = 0;

static void timerDelayCallback_(int id, void *param)
{
bool *triggerred = (bool *)param;
// OS_TRACE("[TIM]: to %llu\n", portTimerGetTick());
*triggerred = true;
}

PT_THREAD(testTimerThread1Ms_(OsTaskId taskId, void *param))
{
static bool timerTriggered;
TASK_BEGIN(taskId);
while (1)
{
OsTimerDelayUs(1000);
TASK_YIELD(taskId); // force Yield
tCount1Ms++;
// OS_TRACE("1Ms hit %ld, idleYield %ld\n", tCount1Ms, tCountIdle);
}
TASK_END(taskId);
}

PT_THREAD(testTimerThread100Us_(OsTaskId taskId, void *param))
{
static bool timerTriggered;
TASK_BEGIN(taskId);
while (1)
{
OsTimerDelayUs(100);
TASK_YIELD(taskId); // force Yield
tCount100Us++;
// OS_TRACE("100Us hit %ld, idleYield %ld\n", tCount100Us, tCountIdle);
}
TASK_END(taskId);
}

PT_THREAD(testIdleThread_(OsTaskId taskId, void *param))
{
TASK_BEGIN(taskId);
while (1)
{
tCountIdle++;
TASK_YIELD(taskId); // force Yield
}
TASK_END(taskId);
}

int TestTimer()
{
int repeat_timer_id;
OsInit();
OsTimerInit();

tickStart = portTimerGetTick() / 1000;
LT_ASSERT(kLtSc == OsTimerRegister(testTimerCallback_, (void *)(11), 100, false, nullptr));
LT_ASSERT(kLtSc == OsTimerRegister(testTimerCallback_, (void *)(50), 500, false, nullptr));
LT_ASSERT(kLtSc == OsTimerRegister(testTimerCallback_, (void *)(99), 900, false, nullptr));
LT_ASSERT(kLtSc == OsTimerRegister(testTimerCallback_, (void *)(33), 300, true, &repeat_timer_id));
LT_ASSERT(kLtSc == OsTimerRegister(testTimerCallback_, (void *)(51), 500, false, nullptr));

while (testCount < kMaxTestNum_) TaskYield();
for (int i = 0; i < kMaxTestNum_; i++)
{
if (testTimerParam[i] != testTimerGolden[i] || testTickCounter[i] / 10 != testTickGolden[i] / 10)
{
OS_TRACE("Test%d Failed\n", i);
OS_TRACE("Timer [%lld : %lld]. Tick [%llu : %llu]\n", testTimerParam[i], testTimerGolden[i],
testTickCounter[i], testTickGolden[i]);
return 1;
}
}
if (OsTimerCount() != 1)
{
OS_TRACE("Timer count error 1 - %d\n", OsTimerCount());
return 2;
}
LT_ASSERT(OsTimerKill(repeat_timer_id) == kLtSc);
if (OsTimerCount() != 0)
{
OS_TRACE("Timer count error 0 - %d\n", OsTimerCount());
return 3;
}

OS_TRACE("Test Timer in task\n");
RegisterTask("thr1Ms", &testTimerThread1Ms_, nullptr);
RegisterTask("thr100Us", &testTimerThread100Us_, nullptr);
RegisterTask("thrIdle", &testIdleThread_, nullptr);
OS_TRACE("Test Timer start\n");
while (tCount1Ms < kTimerTaskSeconds_)
{
TaskYield();
}
if ((tCount1Ms * 10 - tCount100Us) <= 2)
{
OS_TRACE("Timer task error %ld - %ld\n", tCount1Ms, tCount100Us);
return 4;
}
OS_TRACE("Idle task yield %ld\n", tCountIdle);

OS_TRACE("Test Passed\n");
return 0;
}

0 comments on commit 298fe50

Please sign in to comment.