| /* |
| * Copyright (C) 2010 NXP Semiconductors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * \file phOsalNfc_Timer.c |
| * \brief OSAL Timer Implementation for linux |
| * |
| * Project: Trusted NFC Linux Light |
| * |
| * $Date: 03 aug 2009 |
| * $Author: Jérémie Corbier |
| * $Revision: 1.0 |
| * |
| */ |
| |
| #include <stdlib.h> |
| #include <signal.h> |
| #include <time.h> |
| |
| #include <phOsalNfc.h> |
| #include <phOsalNfc_Timer.h> |
| #include <stdio.h> |
| |
| #include <phDal4Nfc_messageQueueLib.h> |
| |
| #define NSECS 1000000 |
| #define MAX_NO_TIMERS 16 |
| |
| /*! |
| * \struct phOsalNfc_Timer |
| * Internal OSAL timer structure |
| */ |
| struct phOsalNfc_Timer |
| { |
| timer_t handle; /*!< System timer handle. */ |
| ppCallBck_t callback; /*!< Callback to be called when timer expires. */ |
| void* pContext; /*!< Callback context. */ |
| #ifdef NXP_MESSAGING |
| void *ptr; |
| #endif |
| int nIsStopped; |
| }; |
| |
| static struct phOsalNfc_Timer timers[MAX_NO_TIMERS] = |
| { |
| {0, NULL, NULL |
| #ifdef NXP_MESSAGING |
| , NULL |
| #endif |
| , 0 |
| }, |
| }; |
| |
| #ifdef NXP_MESSAGING |
| extern int nDeferedCallMessageQueueId; |
| |
| void phOsalNfc_Timer_DeferredCall(void *params) |
| { |
| phOsalNfc_Timer_Msg_t *timer_msg; |
| |
| if(params == NULL) |
| return; |
| |
| timer_msg = (phOsalNfc_Timer_Msg_t *)params; |
| |
| if((timer_msg != NULL) && (timer_msg->pCallBck != NULL)) |
| timer_msg->pCallBck(timer_msg->TimerId, timer_msg->pContext); |
| |
| if ((timer_msg->TimerId >= MAX_NO_TIMERS) || (timer_msg->TimerId < 0)) |
| { |
| printf("Bad TimerId=%d, should be <= to %d\n", timer_msg->TimerId, MAX_NO_TIMERS); |
| } |
| else |
| { |
| if(timers[timer_msg->TimerId].ptr != NULL) |
| { |
| phOsalNfc_FreeMemory(timers[timer_msg->TimerId].ptr); |
| timers[timer_msg->TimerId].ptr = NULL; |
| } |
| } |
| phOsalNfc_FreeMemory(timer_msg); |
| } |
| #endif |
| |
| /*! |
| * \brief System timer callback. |
| * This callback is called by Linux whenever one the timers expires. It |
| * calls the corresponding registered callback. |
| * |
| * \param sv structure storing the expired timer ID. |
| */ |
| static void phOsalNfc_Timer_Expired(union sigval sv) |
| { |
| uint32_t timerid = (uint32_t)(sv.sival_int); |
| |
| if((timerid < MAX_NO_TIMERS)&&(timers[timerid].nIsStopped == 1)) |
| { |
| //printf("phOsalNfc_Timer_Expired : Expired but already stopped TimerId=%d\n", timerid); |
| return; |
| } |
| |
| if(timerid < MAX_NO_TIMERS) |
| { |
| #ifndef CYCLIC_TIMER |
| phOsalNfc_Timer_Stop(timerid); |
| #else |
| |
| #endif |
| #ifdef NXP_MESSAGING |
| phOsalNfc_Timer_Msg_t *timer_msg; |
| phOsalNfc_DeferedCalldInfo_t *osal_defer_msg; |
| phDal4Nfc_Message_Wrapper_t wrapper; |
| |
| timer_msg = phOsalNfc_GetMemory(sizeof(phOsalNfc_Timer_Msg_t)); |
| if(timer_msg == NULL) |
| phOsalNfc_RaiseException(phOsalNfc_e_NoMemory, 0); |
| |
| osal_defer_msg = phOsalNfc_GetMemory(sizeof(phOsalNfc_DeferedCalldInfo_t)); |
| if(osal_defer_msg == NULL) |
| { |
| phOsalNfc_FreeMemory(timer_msg); |
| phOsalNfc_RaiseException(phOsalNfc_e_NoMemory, 0); |
| } |
| |
| timer_msg->TimerId = timerid; |
| timer_msg->pCallBck = timers[timerid].callback; |
| timer_msg->pContext = timers[timerid].pContext; |
| |
| osal_defer_msg->pCallback = phOsalNfc_Timer_DeferredCall; |
| osal_defer_msg->pParameter = timer_msg; |
| |
| wrapper.mtype = 1; |
| wrapper.msg.eMsgType = PH_OSALNFC_TIMER_MSG; |
| wrapper.msg.pMsgData = osal_defer_msg; |
| wrapper.msg.Size = sizeof(phOsalNfc_DeferedCalldInfo_t); |
| |
| timers[timerid].ptr = osal_defer_msg; |
| |
| phDal4Nfc_msgsnd(nDeferedCallMessageQueueId, (void *)&wrapper, |
| sizeof(phOsalNfc_Message_t), 0); |
| #else |
| (timers[timerid].callback)(timerid, timers[timerid].pContext); |
| #endif |
| } |
| } |
| |
| static void phOsalNfc_Timer_Dummy_Cb(uint32_t timerid, void *pContext) {} |
| |
| /*! |
| * \brief Creates a new timer. |
| * This function checks whether there is an available timer slot. If |
| * this is the case, then it reserves it for future usage and returns its |
| * ID. |
| * |
| * \return a valid timer ID or PH_OSALNFC_INVALID_TIMER_ID if an error occured. |
| */ |
| uint32_t phOsalNfc_Timer_Create(void) |
| { |
| uint32_t timerid; |
| struct sigevent se; |
| |
| se.sigev_notify = SIGEV_THREAD; |
| se.sigev_notify_function = phOsalNfc_Timer_Expired; |
| se.sigev_notify_attributes = NULL; |
| |
| /* Look for available timer slot */ |
| for(timerid = 0; timerid < MAX_NO_TIMERS; timerid++) |
| if(timers[timerid].callback == NULL) |
| break; |
| if(timerid == MAX_NO_TIMERS) |
| return PH_OSALNFC_INVALID_TIMER_ID; |
| |
| se.sigev_value.sival_int = (int)timerid; |
| |
| /* Create POSIX timer */ |
| if(timer_create(CLOCK_REALTIME, &se, &(timers[timerid].handle)) == -1) |
| return PH_OSALNFC_INVALID_TIMER_ID; |
| timers[timerid].callback = phOsalNfc_Timer_Dummy_Cb; |
| #ifdef NXP_MESSAGING |
| timers[timerid].ptr = NULL; |
| #endif |
| |
| return timerid; |
| } |
| |
| /*! |
| * \brief Starts a timer. |
| * This function starts the timer \a TimerId with an expiration time of |
| * \a RegTimeCnt milliseconds. Each time it expires, \a |
| * Application_callback is called. |
| * |
| * \param TimerId a valid timer ID. |
| * \param RegTimeCnt expiration time in milliseconds. |
| * \param Application_callback callback to be called when timer expires. |
| */ |
| void phOsalNfc_Timer_Start(uint32_t TimerId, |
| uint32_t RegTimeCnt, |
| ppCallBck_t Application_callback, |
| void *pContext) |
| { |
| struct itimerspec its; |
| |
| if(TimerId >= MAX_NO_TIMERS) |
| return; |
| if(Application_callback == NULL) |
| return; |
| if(timers[TimerId].callback == NULL) |
| return; |
| |
| its.it_interval.tv_sec = 0; |
| its.it_interval.tv_nsec = 0; |
| its.it_value.tv_sec = RegTimeCnt / 1000; |
| its.it_value.tv_nsec = 1000000 * (RegTimeCnt % 1000); |
| if(its.it_value.tv_sec == 0 && its.it_value.tv_nsec == 0) |
| { |
| // this would inadvertently stop the timer |
| its.it_value.tv_nsec = 1; |
| } |
| |
| timers[TimerId].callback = Application_callback; |
| timers[TimerId].pContext = pContext; |
| timers[TimerId].nIsStopped = 0; |
| |
| timer_settime(timers[TimerId].handle, 0, &its, NULL); |
| } |
| |
| /*! |
| * \brief Stops a timer. |
| * This function stops an already started timer. |
| * |
| * \param TimerId a valid timer ID. |
| */ |
| void phOsalNfc_Timer_Stop(uint32_t TimerId) |
| { |
| struct itimerspec its = {{0, 0}, {0, 0}}; |
| |
| if(TimerId >= MAX_NO_TIMERS) |
| return; |
| if(timers[TimerId].callback == NULL) |
| return; |
| if(timers[TimerId].nIsStopped == 1) |
| return; |
| |
| timers[TimerId].nIsStopped = 1; |
| timer_settime(timers[TimerId].handle, 0, &its, NULL); |
| } |
| |
| /*! |
| * \brief Deletes a timer. |
| * This function deletes a timer. |
| * |
| * \param TimerId a valid timer ID. |
| */ |
| void phOsalNfc_Timer_Delete(uint32_t TimerId) |
| { |
| if(TimerId >= MAX_NO_TIMERS) |
| return; |
| if(timers[TimerId].callback == NULL) |
| return; |
| |
| timer_delete(timers[TimerId].handle); |
| |
| timers[TimerId].callback = NULL; |
| timers[TimerId].pContext = NULL; |
| } |