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 */
46struct 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
57static 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
68extern int nDeferedCallMessageQueueId;
69
70void 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 */
105static 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
160static 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 */
170uint32_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 */
209void 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 */
246void 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 */
267void 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