1/*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "power_mgr_timer_util.h"
17
18#include <common.h>
19#include <errno.h>
20#include <securec.h>
21#include <signal.h>
22#include <stdint.h>
23#include <string.h>
24
25#include "hilog_wrapper.h"
26#include "power_mgr_time_util.h"
27
28typedef struct {
29    PowerTimer timerId;
30    BOOL isRunning;
31    int64_t whenMsec;
32    int64_t intervalMsec;
33    PowerTimerCallback timerCb;
34    void *data;
35} PowerTimerInfo;
36
37static inline PowerTimerInfo *GetPowerTimerInfo(PowerTimer *timer)
38{
39    return GET_OBJECT(timer, PowerTimerInfo, timerId);
40}
41
42static void SetTimeSpec(struct timespec *ts, int64_t msec)
43{
44    ts->tv_sec = MsecToSec(msec);
45    msec -= SecToMsec(ts->tv_sec);
46    ts->tv_nsec = MsecToNsec(msec);
47}
48
49static BOOL StartTimer(PowerTimer timer, int64_t whenMsec, int64_t intervalMsec)
50{
51    struct itimerspec ts;
52    SetTimeSpec(&ts.it_value, whenMsec);
53    SetTimeSpec(&ts.it_interval, intervalMsec);
54    int32_t ret = timer_settime(timer, 0, &ts, NULL);
55    if (ret < 0) {
56        POWER_HILOGE("Failed to start timer");
57        return FALSE;
58    }
59    return TRUE;
60}
61
62static void TimerHandle(union sigval v)
63{
64    PowerTimerInfo *info = (PowerTimerInfo *)v.sival_ptr;
65    if (info == NULL) {
66        POWER_HILOGE("Invalid timer info");
67        return;
68    }
69    if (info->timerCb != NULL) {
70        info->timerCb(info->data);
71    }
72}
73
74PowerTimer *PowerMgrCreateTimer(int64_t whenMsec, int64_t intervalMsec, PowerTimerCallback cb)
75{
76    PowerTimerInfo *info = (PowerTimerInfo *)malloc(sizeof(PowerTimerInfo));
77    if (info == NULL) {
78        POWER_HILOGE("Failed allocate timer info");
79        return NULL;
80    }
81    (void)memset_s(info, sizeof(PowerTimerInfo), 0, sizeof(PowerTimerInfo));
82    info->isRunning = FALSE;
83    info->whenMsec = whenMsec;
84    info->intervalMsec = intervalMsec;
85    info->timerCb = cb;
86
87    struct sigevent evp;
88    (void)memset_s(&evp, sizeof(evp), 0, sizeof(evp));
89    evp.sigev_value.sival_ptr = info;
90    evp.sigev_notify = SIGEV_THREAD;
91    evp.sigev_notify_function = TimerHandle;
92    int32_t ret = timer_create(CLOCK_REALTIME, &evp, &info->timerId);
93    if (ret < 0) {
94        POWER_HILOGE("Failed to create timer");
95        free(info);
96        return NULL;
97    }
98    POWER_HILOGD("Succeed to create timer, id: %p", info->timerId);
99
100    return &info->timerId;
101}
102
103BOOL PowerMgrResetTimer(PowerTimer *timer, int64_t whenMsec, int64_t intervalMsec)
104{
105    if (timer == NULL) {
106        POWER_HILOGE("Invalid timer");
107        return FALSE;
108    }
109    PowerMgrStopTimer(timer);
110    PowerTimerInfo *info = GetPowerTimerInfo(timer);
111    info->whenMsec = whenMsec;
112    info->intervalMsec = intervalMsec;
113    return TRUE;
114}
115
116BOOL PowerMgrStartTimer(PowerTimer *timer, void *privateData)
117{
118    if (timer == NULL) {
119        POWER_HILOGE("Invalid timer");
120        return FALSE;
121    }
122
123    PowerTimerInfo *info = GetPowerTimerInfo(timer);
124    info->data = privateData;
125    info->isRunning = TRUE;
126    return StartTimer(info->timerId, info->whenMsec, info->intervalMsec);
127}
128
129BOOL PowerMgrRestartTimer(PowerTimer *timer, void *privateData)
130{
131    if (timer == NULL) {
132        POWER_HILOGE("Invalid timer");
133        return FALSE;
134    }
135
136    return PowerMgrStartTimer(timer, privateData);
137}
138
139BOOL PowerMgrStopTimer(PowerTimer *timer)
140{
141    if (timer == NULL) {
142        POWER_HILOGE("Invalid timer");
143        return FALSE;
144    }
145
146    PowerTimerInfo *info = GetPowerTimerInfo(timer);
147    info->isRunning = FALSE;
148    return StartTimer(info->timerId, 0, 0);
149}
150
151void PowerMgrDestroyTimer(PowerTimer *timer)
152{
153    if (timer == NULL) {
154        POWER_HILOGE("Invalid timer");
155        return;
156    }
157
158    PowerTimerInfo *info = GetPowerTimerInfo(timer);
159    int32_t ret = timer_delete(info->timerId);
160    POWER_HILOGD("Destory timer: %d", ret);
161    free(info);
162}
163