Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Os timer #5

Merged
merged 6 commits into from
Mar 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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