/*
* 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;
}