Skip to content

Commit

Permalink
Merge pull request #5 from ZhuLingQing/os-timer
Browse files Browse the repository at this point in the history
Os timer
  • Loading branch information
ZhuLingQing authored Mar 17, 2024
2 parents 31c7a94 + d28f765 commit b370037
Show file tree
Hide file tree
Showing 13 changed files with 447 additions and 10 deletions.
25 changes: 18 additions & 7 deletions .github/workflows/c-cpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,24 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: check the environment
run: g++ --version && git --version && bash --version
- name: list the environment
run: ls -la
- name: build with bash
run: bash bash_build.sh
- name: run tests
run: |
g++ --version
git --version
cmake --version
- name: make the project
run: |
mkdir build
pushd build
./test_pt_os
cmake ..
make
popd
- name: test
run: |
pushd build
make test
popd
- name: test with bash
run: |
./build/tests/test_pt_os
echo "DONE
"
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
build/
.vscode/
*.bak
11 changes: 10 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
cmake_minimum_required(VERSION 3.16)

add_subdirectory("protothreads")
add_subdirectory("etl")

# cd ./build && make test
enable_testing()

if (DEBUG)
SET(CMAKE_BUILD_TYPE "Debug")
message(STATUS "Build with debug mode")
else()
SET(CMAKE_BUILD_TYPE "Release")
message(STATUS "Build with release mode as default")
endif()

set( LIB_NAME pt_os_lib )

file( GLOB SRCS
Expand All @@ -16,7 +25,7 @@ include_directories(${PROJECT_SOURCE_DIR})

target_include_directories(${LIB_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

target_link_libraries(${LIB_NAME} protothreads)
target_link_libraries(${LIB_NAME} protothreads etl)

set( OS_LIB_DIR "${CMAKE_CURRENT_SOURCE_DIR}" PARENT_SCOPE )

Expand Down
10 changes: 8 additions & 2 deletions bash_build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,15 @@ pushd ${build_dir}

#clone the dependency repo
git clone https://github.com/ZhuLingQing/protothreads.git
git clone https://github.com/ETLCPP/etl.git
pushd etl
git checkout 20.38.10
popd
#build the os static library
g++ -g -o ${lib_name}.o -c ../pt-os.cpp -I./protothreads
ar -rv lib${lib_name}.a ${lib_name}.o
g++ -g -o ${pt-os}.o -c ../pt-os.cpp -I./protothreads -I./etl
g++ -g -o ${os-timer}.o -c ../os-timer.cpp -I./protothreads -I./etl
g++ -g -o ${os-timer-port}.o -c ../os-timer-port.cpp -I./protothreads -I./etl
ar -rv lib${lib_name}.a ${pt-os}.o ${os-timer}.o ${os-timer-port}.o
#build the test
g++ -g -o test_pt_os ../tests/*.cpp -I./protothreads -I.. -I../tests -L. -l${lib_name}
#run the test
Expand Down
9 changes: 9 additions & 0 deletions etl/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
include(FetchContent)

fetchcontent_declare(
etl
GIT_REPOSITORY https://github.com/ETLCPP/etl.git
GIT_TAG 20.38.10
)

FetchContent_MakeAvailable(etl)
36 changes: 36 additions & 0 deletions os-timer-port.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef _OS_TIMER_PORT_H_
#define _OS_TIMER_PORT_H_

#if __linux__

void portTimerInit( void (*callback)());

void portTimerStop();

long portTimerGetUs();

void portTimerStart(long end_us);

#elif __riscv__

#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 portTimerGetUs() __mtime_get_count()

#define portTimerStart(end) __mtime_set_compare(end)

#endif

#endif
110 changes: 110 additions & 0 deletions os-timer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#include "os-timer.h"
#include "pt-os.h"
#include "os-timer-port.h"
#include <etl/set.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;

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.
tim = gOsTimerObj_.begin();
if (tim != gOsTimerObj_.end())
portTimerStart(tim->end_tick);
}
TASK_END(taskId);
}

void OsTimerInit()
{
gOsTimerObj_.clear();
portTimerInit(OsTimerIsrHandler_);
portTimerStop();
RegisterTask("thrTmr", OsTimerTask_, nullptr);
}

int OsTimerRegister(OsTimerCallback_t callback, void *param, uint64_t period_us, bool repeatable, int *id)
{
if (gOsTimerObj_.full()) return NO_RESOURCE;
portTimerStop();
gOsTimerObj_.insert({callback, param, period_us,
portTimerGetUs() + period_us, ++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;
}
}
return INVALID_TASK_ID;
}

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

int OsTimerDelayUs(uint64_t delay_us)
{
bool timerTriggered = false;
// HAL_UartPrint("[TIM]: from %llu - %lluUs\n", portTimerGetUs(), 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;
}
50 changes: 50 additions & 0 deletions os-timer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#ifndef _OS_TIMER_H_
#define _OS_TIMER_H_

#include <stdint.h>
#include <stdbool.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
2 changes: 2 additions & 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 All @@ -29,6 +30,7 @@ extern "C"
#define TASK_OP_SUCCESS (0)
#define INVALID_TASK_ID (-1)
#define INVALID_TASK_STATUS (-2)
#define NO_RESOURCE (-3)

typedef enum
{
Expand Down
2 changes: 2 additions & 0 deletions pt-osConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@
#include <cassert>
#define OS_ASSERT assert

#define OS_PRINT printf

#endif
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;
}
64 changes: 64 additions & 0 deletions tests/os-timer-port.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include "os-timer-port.h"
#include "os-timer.h"
#include "pt-os.h"
#include <stdio.h>

#if __linux__

#include <signal.h>
#include <time.h>
#include <sys/time.h>

static void (*TimerCallback_)();
static long TimerBaseUs_ = 0;

static void TimerRoutine(int signo)
{
struct itimerval value, ovalue;
switch (signo){
case SIGALRM:
portTimerStop();
TimerCallback_();
break;
}
}

void portTimerInit( void (*callback)())
{
struct timeval tv;
gettimeofday(&tv,NULL);
TimerBaseUs_ = tv.tv_sec*1000000 + tv.tv_usec;
TimerCallback_ = callback;
signal(SIGALRM, TimerRoutine);
}

void portTimerStop()
{
struct itimerval value, ovalue;
value.it_value.tv_sec = 0;
value.it_value.tv_usec = 0;
value.it_interval.tv_sec = 0;
value.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &value, &ovalue);
}

long portTimerGetUs()
{
struct timeval tv;
gettimeofday(&tv,NULL);
return (tv.tv_sec*1000000 + tv.tv_usec - TimerBaseUs_);
}

void portTimerStart(long end_us)
{
struct itimerval value, ovalue;
long offset = end_us - portTimerGetUs();
if (offset < 10) offset = 100;
value.it_value.tv_sec = offset/1000000;
value.it_value.tv_usec = offset%1000000;
value.it_interval.tv_sec = value.it_value.tv_sec;
value.it_interval.tv_usec = value.it_value.tv_usec;
setitimer(ITIMER_REAL, &value, &ovalue);
}

#endif
Loading

0 comments on commit b370037

Please sign in to comment.