| | |
| | | //POSIX.1b Timer |
| | | #include <jni.h> |
| | | #include <stdbool.h> |
| | | #include <stdint.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <unistd.h> |
| | | #include <signal.h> |
| | | #include <string.h> |
| | | #include <sys/time.h> |
| | | #include <pthread.h> |
| | | #include <errno.h> |
| | | #include <time.h> |
| | | #include "../jni_log.h" |
| | | // |
| | | // Created by YY on 2021/3/16. |
| | | // |
| | | |
| | | #include "apptimer.h" |
| | | #include "../jni_log.h" |
| | | |
| | | #define MAX_TIMER 32 |
| | | #include <cstdint> |
| | | #include <functional> |
| | | #include <chrono> |
| | | #include <mutex> |
| | | #include <condition_variable> |
| | | #include <list> |
| | | #include <thread> |
| | | #include <map> |
| | | #include <string> |
| | | #include <sstream> |
| | | #include <iomanip> |
| | | |
| | | static struct { |
| | | timer_t timerId; |
| | | #define DEBUG(fmt, args...) LOGD("<apptimer> <%s>: " fmt, __func__, ##args) |
| | | |
| | | void (*func)(union sigval sig); |
| | | std::mutex mtx; |
| | | |
| | | int value; |
| | | uint8_t *user_data; |
| | | } AppTimer[MAX_TIMER]; |
| | | std::map<void(*)(apptimer_var_t), CTimer *> TimerList; |
| | | |
| | | static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; |
| | | static void RemoveTimerList(const CTimer *p); |
| | | |
| | | static int createTimer(timer_t *timerId, void (*func)(union sigval sig), |
| | | int value, |
| | | uint8_t *usr_data, int usr_data_length, |
| | | uint8_t **usr_data_ptr) { |
| | | struct sigevent sev; |
| | | pthread_attr_t attr; |
| | | CTimer::CTimer() { |
| | | flag = 0; |
| | | var.var_ptr = nullptr; |
| | | var.var1 = var.var2 = var.var_length = 0; |
| | | pthread = nullptr; |
| | | } |
| | | |
| | | // Register printMsg to SIGALRM |
| | | pthread_attr_init(&attr); |
| | | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//detached |
| | | CTimer::~CTimer() { |
| | | if (pthread != nullptr) { |
| | | delete pthread; |
| | | } |
| | | if (var.var_ptr != nullptr) { |
| | | delete var.var_ptr; |
| | | } |
| | | } |
| | | |
| | | memset(&sev, 0, sizeof(sev)); |
| | | bool CTimer::_updateStatus(CTimer *timer) { |
| | | if (timer->flag == 0) { |
| | | return false; |
| | | } else { |
| | | return true; //cancel |
| | | } |
| | | } |
| | | |
| | | sev.sigev_notify = SIGEV_THREAD; |
| | | sev.sigev_notify_function = func; |
| | | sev.sigev_notify_attributes = &attr; |
| | | void CTimer::_do_task_func(uint32_t msec, CTimer *timer, std::function<void(apptimer_var_t)> callback) { |
| | | std::unique_lock<std::mutex> lk(timer->cv_mtx); |
| | | |
| | | if (usr_data != NULL && usr_data_length != 0) { |
| | | if ((sev.sigev_value.sival_ptr = malloc(usr_data_length)) != NULL) { |
| | | *usr_data_ptr = (uint8_t *) sev.sigev_value.sival_ptr; |
| | | memcpy(sev.sigev_value.sival_ptr, usr_data, usr_data_length); //Copy usr data |
| | | sev.sigev_value.sival_int = usr_data_length; |
| | | } else { |
| | | return -1; |
| | | auto now = std::chrono::steady_clock::now(); |
| | | |
| | | if (timer->cv.wait_until(lk, now + std::chrono::milliseconds(msec), std::bind(_updateStatus, timer)) == false) { |
| | | RemoveTimerList(timer); // 从列表中删除索引 |
| | | |
| | | if (timer->flag == 0) { |
| | | callback(timer->var); |
| | | } |
| | | } else { |
| | | sev.sigev_value.sival_int = value; |
| | | // LOGD("Cancel %d", static_cast<int>(timer->flag)); |
| | | RemoveTimerList(timer); |
| | | } |
| | | |
| | | /* create timer */ |
| | | if (timer_create(CLOCK_REALTIME, &sev, timerId) == -1) { |
| | | return -1; |
| | | //delete timer; |
| | | lk.unlock(); |
| | | std::thread(clear, timer).detach(); |
| | | } |
| | | |
| | | void CTimer::copy(int value1, int value2, const void *data, int length) |
| | | { |
| | | this->var.var1 = value1; |
| | | this->var.var2 = value2; |
| | | this->var.var_length = length; |
| | | if (length > 0 && data != nullptr) { |
| | | this->var.var_ptr = new uint8_t[length]; |
| | | memcpy(this->var.var_ptr, data, length); |
| | | } else { |
| | | this->var.var_ptr = nullptr; |
| | | } |
| | | // LOGD("timer_create\n"); |
| | | return 0; |
| | | } |
| | | |
| | | static int setTimer(timer_t timerId, int timeMSec) { |
| | | struct itimerspec its; |
| | | |
| | | /* Start the timer */ |
| | | its.it_value.tv_sec = timeMSec / 1000; |
| | | its.it_value.tv_nsec = (timeMSec % 1000) * 1000000; |
| | | |
| | | its.it_interval.tv_sec = 0; |
| | | its.it_interval.tv_nsec = 0; |
| | | |
| | | if (timer_settime(timerId, 0, &its, NULL) == -1) { |
| | | return -1; |
| | | void CTimer::clear(CTimer *timer) |
| | | { |
| | | if (timer != nullptr) { |
| | | delete timer; |
| | | } |
| | | // LOGD("timer_settime\n"); |
| | | return 0; |
| | | } |
| | | |
| | | void AppTimer_Init(void) { |
| | | memset(AppTimer, 0, sizeof(AppTimer)); |
| | | pthread_mutex_init(&mutex, NULL); |
| | | bool CTimer::start(uint32_t msec, std::function<void(apptimer_var_t)> callback) { |
| | | if (pthread == nullptr) { |
| | | try { |
| | | pthread = new std::thread(_do_task_func, msec, this, callback); |
| | | pthread->detach(); |
| | | } catch (std::exception &ex) { |
| | | DEBUG("%s", ex.what()); |
| | | return false; |
| | | } |
| | | // this->callbackThread = std::thread(_do_task_func, msec, this, callback); |
| | | // this->callbackThread.detach(); |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | void AppTimer_add(void (*func)(union sigval), int timeMS) { |
| | | int i; |
| | | // LOGD("AppTimer_add\n"); |
| | | pthread_mutex_lock(&mutex); |
| | | for (i = 0; i < MAX_TIMER; i++) { |
| | | if (AppTimer[i].func == NULL) { |
| | | if (createTimer(&(AppTimer[i].timerId), func, 0, NULL, 0, &(AppTimer[i].user_data)) == 0) { |
| | | AppTimer[i].func = func; |
| | | void CTimer::stop() { |
| | | std::unique_lock<std::mutex> lk(this->cv_mtx); |
| | | this->flag = 1; |
| | | this->cv.notify_one(); |
| | | } |
| | | |
| | | if (setTimer(AppTimer[i].timerId, timeMS) != |
| | | 0) { //Set timer fail, delele it |
| | | timer_delete(AppTimer[i].timerId); |
| | | if (AppTimer[i].user_data != NULL) { |
| | | free(AppTimer[i].user_data); |
| | | AppTimer[i].user_data = NULL; |
| | | } |
| | | AppTimer[i].func = NULL; |
| | | } |
| | | } |
| | | void AppTimer_init(void) |
| | | { |
| | | TimerList.clear(); |
| | | } |
| | | |
| | | void AppTimer_add(void(*cb)(apptimer_var_t), uint32_t msec) |
| | | { |
| | | CTimer *cTimer = new CTimer(); |
| | | cTimer->copy(0, 0, nullptr, 0); |
| | | |
| | | std::lock_guard<std::mutex> lock(mtx); |
| | | TimerList.insert(std::pair<void (*)(apptimer_var_t), CTimer *>(cb, cTimer)); |
| | | |
| | | if (cTimer->start(msec, cb) == false) { |
| | | auto it = TimerList.find(cb); |
| | | if (it != TimerList.end()) { |
| | | CTimer *ptr = it->second; |
| | | TimerList.erase(it); |
| | | } |
| | | delete cTimer; |
| | | } |
| | | } |
| | | |
| | | void AppTimer_add(void(*cb)(apptimer_var_t), uint32_t msec, int value1, int value2) |
| | | { |
| | | CTimer *cTimer = new CTimer(); |
| | | cTimer->copy(value1, value2, nullptr, 0); |
| | | |
| | | std::lock_guard<std::mutex> lock(mtx); |
| | | TimerList.insert(std::pair<void (*)(apptimer_var_t), CTimer *>(cb, cTimer)); |
| | | |
| | | if (cTimer->start(msec, cb) == false) { |
| | | LOGD("建立失败"); |
| | | auto it = TimerList.find(cb); |
| | | if (it != TimerList.end()) { |
| | | CTimer *ptr = it->second; |
| | | TimerList.erase(it); |
| | | } |
| | | delete cTimer; |
| | | } |
| | | } |
| | | |
| | | void AppTimer_add(void(*cb)(apptimer_var_t), uint32_t msec, void *data, int lenght) |
| | | { |
| | | CTimer *cTimer = new CTimer(); |
| | | cTimer->copy(0, 0, data, lenght); |
| | | |
| | | std::lock_guard<std::mutex> lock(mtx); |
| | | TimerList.insert(std::pair<void (*)(apptimer_var_t), CTimer *>(cb, cTimer)); |
| | | |
| | | if (cTimer->start(msec, cb) == false) { |
| | | auto it = TimerList.find(cb); |
| | | if (it != TimerList.end()) { |
| | | CTimer *ptr = it->second; |
| | | TimerList.erase(it); |
| | | } |
| | | delete cTimer; |
| | | } |
| | | } |
| | | |
| | | void AppTimer_delete(void(*cb)(apptimer_var_t)) |
| | | { |
| | | std::lock_guard<std::mutex> lock(mtx); |
| | | |
| | | auto it = TimerList.find(cb); |
| | | if (it != TimerList.end()) { |
| | | CTimer *ptr = it->second; |
| | | TimerList.erase(it); |
| | | ptr->stop(); |
| | | } |
| | | } |
| | | |
| | | static void RemoveTimerList(const CTimer *p) |
| | | { |
| | | std::lock_guard<std::mutex> lock(mtx); |
| | | |
| | | for (auto it = TimerList.begin(); it != TimerList.end(); ++it) { |
| | | CTimer *ptr = it->second; |
| | | if (ptr == p) { |
| | | TimerList.erase(it); |
| | | break; |
| | | } |
| | | } |
| | | pthread_mutex_unlock(&mutex); |
| | | } |
| | | |
| | | void AppTimer_add(void (*func)(union sigval), int timeMS, uint8_t *data, int length) { |
| | | int i; |
| | | // LOGD("AppTimer_add\n"); |
| | | pthread_mutex_lock(&mutex); |
| | | for (i = 0; i < MAX_TIMER; i++) { |
| | | if (AppTimer[i].func == NULL) { |
| | | if (createTimer(&(AppTimer[i].timerId), func, 0, data, length, &(AppTimer[i].user_data)) == 0) { |
| | | AppTimer[i].func = func; |
| | | |
| | | if (setTimer(AppTimer[i].timerId, timeMS) != |
| | | 0) { //Set timer fail, delele it |
| | | timer_delete(AppTimer[i].timerId); |
| | | if (AppTimer[i].user_data != NULL) { |
| | | free(AppTimer[i].user_data); |
| | | AppTimer[i].user_data = NULL; |
| | | } |
| | | AppTimer[i].func = NULL; |
| | | } |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | pthread_mutex_unlock(&mutex); |
| | | } |
| | | |
| | | void AppTimer_add(void (*func)(union sigval), int timeMS, int value) { |
| | | int i; |
| | | // LOGD("AppTimer_add\n"); |
| | | pthread_mutex_lock(&mutex); |
| | | for (i = 0; i < MAX_TIMER; i++) { |
| | | if (AppTimer[i].func == NULL) { |
| | | if (createTimer(&(AppTimer[i].timerId), func, value, NULL, 0, &(AppTimer[i].user_data)) == 0) { |
| | | AppTimer[i].func = func; |
| | | |
| | | if (setTimer(AppTimer[i].timerId, timeMS) != |
| | | 0) { //Set timer fail, delele it |
| | | timer_delete(AppTimer[i].timerId); |
| | | if (AppTimer[i].user_data != NULL) { |
| | | free(AppTimer[i].user_data); |
| | | AppTimer[i].user_data = NULL; |
| | | } |
| | | AppTimer[i].func = NULL; |
| | | } |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | pthread_mutex_unlock(&mutex); |
| | | } |
| | | |
| | | void AppTimer_delete(void (*func)(union sigval)) { |
| | | int i; |
| | | // LOGD("AppTimer_delete\n"); |
| | | pthread_mutex_lock(&mutex); |
| | | for (i = 0; i < MAX_TIMER; i++) { |
| | | if (AppTimer[i].func == func) { |
| | | timer_delete(AppTimer[i].timerId); |
| | | if (AppTimer[i].user_data != NULL) { |
| | | free(AppTimer[i].user_data); |
| | | AppTimer[i].user_data = NULL; |
| | | } |
| | | AppTimer[i].func = NULL; |
| | | } |
| | | } |
| | | pthread_mutex_unlock(&mutex); |
| | | } |
| | | |
| | | uint32_t AppTimer_GetTickCount(void) |
| | | { |
| | | struct timespec ts; |
| | | std::chrono::milliseconds as = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now().time_since_epoch()); |
| | | |
| | | clock_gettime(CLOCK_MONOTONIC, &ts); |
| | | return as.count(); |
| | | } |
| | | |
| | | return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000); |
| | | uint32_t AppTimer_GetGmtTickCount(void) |
| | | { |
| | | std::chrono::seconds as = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()); |
| | | |
| | | return as.count(); |
| | | } |
| | | |
| | | std::string FormatTime(const char *fmt) |
| | | { |
| | | auto now = std::chrono::system_clock::now(); |
| | | auto timet = std::chrono::system_clock::to_time_t(now); |
| | | auto localTime = *std::localtime(&timet); |
| | | |
| | | std::stringstream ss; |
| | | std::string str; |
| | | ss << std::put_time(&localTime, "%Y-%m-%d %H:%M:%S"); |
| | | str = ss.str(); |
| | | return str; |
| | | } |
| | | |
| | | std::time_t MktimeString(const char *str, const char *fmt) |
| | | { |
| | | struct std::tm dt; |
| | | std::istringstream ss(str); |
| | | |
| | | ss >> std::get_time(&dt, fmt); |
| | | |
| | | std::stringstream out; |
| | | out << std::put_time(&dt, "%Y-%m-%d %H:%M:%S"); |
| | | // DEBUG("%s, %ld", out.str().c_str(), std::mktime(&dt)); |
| | | |
| | | time_t utc = std::mktime(&dt); |
| | | |
| | | return utc; |
| | | } |
| | | |
| | | time_t TimeStamp(int year, int mon, int day, int hour, int min, int sec) |
| | | { |
| | | // YYHHDDhhmmss(GMT+8) |
| | | struct tm test_tm; |
| | | |
| | | struct timeval tv; |
| | | struct timezone tz; |
| | | |
| | | gettimeofday(&tv,&tz); |
| | | |
| | | memset(&test_tm, 0, sizeof(test_tm)); |
| | | |
| | | test_tm.tm_year = year - 1900; |
| | | test_tm.tm_mon = mon - 1; |
| | | test_tm.tm_mday = day; |
| | | test_tm.tm_hour = hour; |
| | | test_tm.tm_min = min; |
| | | test_tm.tm_sec = sec; |
| | | |
| | | return mktime(&test_tm) - tz.tz_minuteswest*60; |
| | | } |