1 /*
2 * Copyright (C) 2010 NXP Semiconductors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /**
18 * \file phOsalNfc_Timer.c
19 * \brief OSAL Timer Implementation for linux
20 *
21 * Project: Trusted NFC Linux Light
22 *
23 * $Date: 03 aug 2009
24 * $Author: Jérémie Corbier
25 * $Revision: 1.0
26 *
27 */
28
29 #include <stdlib.h>
30 #include <signal.h>
31 #include <time.h>
32
33 #include <phOsalNfc.h>
34 #include <phOsalNfc_Timer.h>
35 #include <stdio.h>
36
37 #include <phDal4Nfc_messageQueueLib.h>
38
39 #define NSECS 1000000
40 #define MAX_NO_TIMERS 16
41
42 /*!
43 * \struct phOsalNfc_Timer
44 * Internal OSAL timer structure
45 */
46 struct phOsalNfc_Timer
47 {
48 timer_t handle; /*!< System timer handle. */
49 ppCallBck_t callback; /*!< Callback to be called when timer expires. */
50 void* pContext; /*!< Callback context. */
51 #ifdef NXP_MESSAGING
52 void *ptr;
53 #endif
54 int nIsStopped;
55 };
56
57 static struct phOsalNfc_Timer timers[MAX_NO_TIMERS] =
58 {
59 {0, NULL, NULL
60 #ifdef NXP_MESSAGING
61 , NULL
62 #endif
63 , 0
64 },
65 };
66
67 #ifdef NXP_MESSAGING
68 extern int nDeferedCallMessageQueueId;
69
phOsalNfc_Timer_DeferredCall(void * params)70 void phOsalNfc_Timer_DeferredCall(void *params)
71 {
72 phOsalNfc_Timer_Msg_t *timer_msg;
73
74 if(params == NULL)
75 return;
76
77 timer_msg = (phOsalNfc_Timer_Msg_t *)params;
78
79 if((timer_msg != NULL) && (timer_msg->pCallBck != NULL))
80 timer_msg->pCallBck(timer_msg->TimerId, timer_msg->pContext);
81
82 if ((timer_msg->TimerId >= MAX_NO_TIMERS) || (timer_msg->TimerId < 0))
83 {
84 printf("Bad TimerId=%d, should be <= to %d\n", timer_msg->TimerId, MAX_NO_TIMERS);
85 }
86 else
87 {
88 if(timers[timer_msg->TimerId].ptr != NULL)
89 {
90 phOsalNfc_FreeMemory(timers[timer_msg->TimerId].ptr);
91 timers[timer_msg->TimerId].ptr = NULL;
92 }
93 }
94 phOsalNfc_FreeMemory(timer_msg);
95 }
96 #endif
97
98 /*!
99 * \brief System timer callback.
100 * This callback is called by Linux whenever one the timers expires. It
101 * calls the corresponding registered callback.
102 *
103 * \param sv structure storing the expired timer ID.
104 */
phOsalNfc_Timer_Expired(union sigval sv)105 static void phOsalNfc_Timer_Expired(union sigval sv)
106 {
107 uint32_t timerid = (uint32_t)(sv.sival_int);
108
109 if((timerid < MAX_NO_TIMERS)&&(timers[timerid].nIsStopped == 1))
110 {
111 //printf("phOsalNfc_Timer_Expired : Expired but already stopped TimerId=%d\n", timerid);
112 return;
113 }
114
115 if(timerid < MAX_NO_TIMERS)
116 {
117 #ifndef CYCLIC_TIMER
118 phOsalNfc_Timer_Stop(timerid);
119 #else
120
121 #endif
122 #ifdef NXP_MESSAGING
123 phOsalNfc_Timer_Msg_t *timer_msg;
124 phOsalNfc_DeferedCalldInfo_t *osal_defer_msg;
125 phDal4Nfc_Message_Wrapper_t wrapper;
126
127 timer_msg = phOsalNfc_GetMemory(sizeof(phOsalNfc_Timer_Msg_t));
128 if(timer_msg == NULL)
129 phOsalNfc_RaiseException(phOsalNfc_e_NoMemory, 0);
130
131 osal_defer_msg = phOsalNfc_GetMemory(sizeof(phOsalNfc_DeferedCalldInfo_t));
132 if(osal_defer_msg == NULL)
133 {
134 phOsalNfc_FreeMemory(timer_msg);
135 phOsalNfc_RaiseException(phOsalNfc_e_NoMemory, 0);
136 }
137
138 timer_msg->TimerId = timerid;
139 timer_msg->pCallBck = timers[timerid].callback;
140 timer_msg->pContext = timers[timerid].pContext;
141
142 osal_defer_msg->pCallback = phOsalNfc_Timer_DeferredCall;
143 osal_defer_msg->pParameter = timer_msg;
144
145 wrapper.mtype = 1;
146 wrapper.msg.eMsgType = PH_OSALNFC_TIMER_MSG;
147 wrapper.msg.pMsgData = osal_defer_msg;
148 wrapper.msg.Size = sizeof(phOsalNfc_DeferedCalldInfo_t);
149
150 timers[timerid].ptr = osal_defer_msg;
151
152 phDal4Nfc_msgsnd(nDeferedCallMessageQueueId, (void *)&wrapper,
153 sizeof(phOsalNfc_Message_t), 0);
154 #else
155 (timers[timerid].callback)(timerid, timers[timerid].pContext);
156 #endif
157 }
158 }
159
phOsalNfc_Timer_Dummy_Cb(uint32_t timerid,void * pContext)160 static void phOsalNfc_Timer_Dummy_Cb(uint32_t timerid, void *pContext) {}
161
162 /*!
163 * \brief Creates a new timer.
164 * This function checks whether there is an available timer slot. If
165 * this is the case, then it reserves it for future usage and returns its
166 * ID.
167 *
168 * \return a valid timer ID or PH_OSALNFC_INVALID_TIMER_ID if an error occured.
169 */
phOsalNfc_Timer_Create(void)170 uint32_t phOsalNfc_Timer_Create(void)
171 {
172 uint32_t timerid;
173 struct sigevent se;
174
175 se.sigev_notify = SIGEV_THREAD;
176 se.sigev_notify_function = phOsalNfc_Timer_Expired;
177 se.sigev_notify_attributes = NULL;
178
179 /* Look for available timer slot */
180 for(timerid = 0; timerid < MAX_NO_TIMERS; timerid++)
181 if(timers[timerid].callback == NULL)
182 break;
183 if(timerid == MAX_NO_TIMERS)
184 return PH_OSALNFC_INVALID_TIMER_ID;
185
186 se.sigev_value.sival_int = (int)timerid;
187
188 /* Create POSIX timer */
189 if(timer_create(CLOCK_REALTIME, &se, &(timers[timerid].handle)) == -1)
190 return PH_OSALNFC_INVALID_TIMER_ID;
191 timers[timerid].callback = phOsalNfc_Timer_Dummy_Cb;
192 #ifdef NXP_MESSAGING
193 timers[timerid].ptr = NULL;
194 #endif
195
196 return timerid;
197 }
198
199 /*!
200 * \brief Starts a timer.
201 * This function starts the timer \a TimerId with an expiration time of
202 * \a RegTimeCnt milliseconds. Each time it expires, \a
203 * Application_callback is called.
204 *
205 * \param TimerId a valid timer ID.
206 * \param RegTimeCnt expiration time in milliseconds.
207 * \param Application_callback callback to be called when timer expires.
208 */
phOsalNfc_Timer_Start(uint32_t TimerId,uint32_t RegTimeCnt,ppCallBck_t Application_callback,void * pContext)209 void phOsalNfc_Timer_Start(uint32_t TimerId,
210 uint32_t RegTimeCnt,
211 ppCallBck_t Application_callback,
212 void *pContext)
213 {
214 struct itimerspec its;
215
216 if(TimerId >= MAX_NO_TIMERS)
217 return;
218 if(Application_callback == NULL)
219 return;
220 if(timers[TimerId].callback == NULL)
221 return;
222
223 its.it_interval.tv_sec = 0;
224 its.it_interval.tv_nsec = 0;
225 its.it_value.tv_sec = RegTimeCnt / 1000;
226 its.it_value.tv_nsec = 1000000 * (RegTimeCnt % 1000);
227 if(its.it_value.tv_sec == 0 && its.it_value.tv_nsec == 0)
228 {
229 // this would inadvertently stop the timer
230 its.it_value.tv_nsec = 1;
231 }
232
233 timers[TimerId].callback = Application_callback;
234 timers[TimerId].pContext = pContext;
235 timers[TimerId].nIsStopped = 0;
236
237 timer_settime(timers[TimerId].handle, 0, &its, NULL);
238 }
239
240 /*!
241 * \brief Stops a timer.
242 * This function stops an already started timer.
243 *
244 * \param TimerId a valid timer ID.
245 */
phOsalNfc_Timer_Stop(uint32_t TimerId)246 void phOsalNfc_Timer_Stop(uint32_t TimerId)
247 {
248 struct itimerspec its = {{0, 0}, {0, 0}};
249
250 if(TimerId >= MAX_NO_TIMERS)
251 return;
252 if(timers[TimerId].callback == NULL)
253 return;
254 if(timers[TimerId].nIsStopped == 1)
255 return;
256
257 timers[TimerId].nIsStopped = 1;
258 timer_settime(timers[TimerId].handle, 0, &its, NULL);
259 }
260
261 /*!
262 * \brief Deletes a timer.
263 * This function deletes a timer.
264 *
265 * \param TimerId a valid timer ID.
266 */
phOsalNfc_Timer_Delete(uint32_t TimerId)267 void phOsalNfc_Timer_Delete(uint32_t TimerId)
268 {
269 if(TimerId >= MAX_NO_TIMERS)
270 return;
271 if(timers[TimerId].callback == NULL)
272 return;
273
274 timer_delete(timers[TimerId].handle);
275
276 timers[TimerId].callback = NULL;
277 timers[TimerId].pContext = NULL;
278 }
279