//System header files
#include
#include <stdio.h>
#include <errno.h>
#include <pthread.h> //to use thread functions
#include <sys/netmgr.h>
#include <sys/neutrino.h> //to use ‘ChannelCreate’ function
#include <time.h>
#include <unistd.h>
#include <sys/siginfo.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syspage.h>
#include <stdint.h>
using namespace std;
//Constants
const int MAX_TIMER = 10;
const int CLOCKS_PER_MS = CLOCKS_PER_SEC / 1000;
//Global variables used across the functions
int nCHNL_ID = NULL; //Channel Id
int nCONN_ID = NULL; //Connection Id
pthread_t nTHRD_ID = NULL; //Thread Id
char cStr[500] = “”; //To store lengthy string
char cStr1[500] = “”; //The string which will be used by Signal handler
timer_t Timers[MAX_TIMER] = { NULL }; //To store the timer ids
int nTimerVal[MAX_TIMER][2] = { { NULL } }; //To store the timer value for all the timers, it stores the one shot as well as interval
double nLastClock_ts[MAX_TIMER] = { 0.0 };
unsigned int nLastClock[MAX_TIMER] = { NULL }; //to store the last clock cycles which will be used to calculate the elapsed time
const unsigned long FULL_RECORD_SIZE = 64 *1024;
const unsigned long SINGLE_RECORD_SIZE = 56;
unsigned long uiTop =0;
unsigned long uiBottom=0;
const double dTwoPower32 = 4.0 * (double)(1<<30);
double dClockSpeed;
void setClockSpeed(double dCSpeed){
if (0.0 < dCSpeed)
{
dClockSpeed = dCSpeed;
}
}
double GetTimeStampInSeconds(void){
asm (“push %eax;”
“push %edx;”
“rdtsc;”
“mov %edx,uiTop;”
“mov %eax,uiBottom;”
“pop %edx;”
“pop %eax;”);
return(((double)uiBottom+(double)uiTop * dTwoPower32)/ dClockSpeed);
}
double GetTimeStampInMilliSeconds(void){
return(GetTimeStampInSeconds() * 1000.0);
}
// *****************************************************************************
// Function : Print
// Description : This function creates a thread which will block on MsgReceive.
// Notes : None
// : NA
// *****************************************************************************
void Print(int TimerNum, char cStr[])
{
char cFileName[30] = “”;
sprintf(cFileName, “Timer_%d_Output”, TimerNum);
int fd = NULL;
int nSizeWritten = NULL;
// open file for output
// replace existing file if it exists
// with read/write perms for owner
if ( ( fd = open( cFileName, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR ) ) != 0)
{
nSizeWritten = write( fd, cStr, strlen(cStr) );
if ( nSizeWritten != strlen(cStr) )
{
printf("\nError on writing to the file %s. Retry!\n", cFileName);
exit(0);
}
close(fd);
}
return;
}
// *****************************************************************************
// Function : CreateConnection
// Description : This function creates channel and attaches this process to the channel so that the
// timer pulses shall be received through this channel.
// Notes : None
// : NA
// *****************************************************************************
void CreateConnection(void)
{
int nChannelId = NULL;
//The ChannelCreate kernel call create a channel that can be used to receive messages and pulses
if ( ( nCHNL_ID = ChannelCreate(NULL) ) < 0 )
{
printf("\nChannel Create failed. Retry!");
exit(0);
}
//Treating a connection as a file descriptor can lead to unexpected behavior. Therefore,
//you should have _NTO_SIDE_CHANNEL in index when you create a connection. If you do
//this, the connection ID is returned from a different space than file descriptors;
//the ID is greater than any valid file descriptor
if ( ( nCONN_ID = ConnectAttach(ND_LOCAL_NODE , NULL, nCHNL_ID, _NTO_SIDE_CHANNEL, NULL) ) == -1 )
{
printf("\nConnectAttach failed. Retry!");
exit(0);
}
return;
}
// *****************************************************************************
// Function : Thrd_ReceivePulse
// Description : This is a thread function which will be waiting on the channel to receive the pulse .
// Notes : None
// : NA
// *****************************************************************************
void * Thrd_ReceivePulse(void* ptr)
{
struct _pulse stPulse = { NULL };
unsigned int nElapseTime = NULL;
double nElapseTime_ts = NULL;
//Wait for a message or pulse on a channel
while( MsgReceive(nCHNL_ID, &stPulse, sizeof(stPulse), NULL) == 0 )
{
nElapseTime = clock() - nLastClock[stPulse.code];
double fFinaltime=GetTimeStampInMilliSeconds();
nElapseTime_ts=fFinaltime-nLastClock_ts[stPulse.code];
nLastClock_ts[stPulse.code]=GetTimeStampInMilliSeconds();
nLastClock[stPulse.code] = clock();
if ( nTimerVal[stPulse.code][1] == 0 )
{
sprintf(cStr, "\nConfigured Elapse time: %d,timestamp diff: %f", nTimerVal[stPulse.code][0],nElapseTime_ts);
Print(stPulse.code + 1, cStr);
Timers[stPulse.code] = NULL;
}
else
{
sprintf(cStr, "\nConfigured one shot value: %d, Configured interval value: %d,timestamp diff: %f", \
nTimerVal[stPulse.code][0], nTimerVal[stPulse.code][1],nElapseTime_ts);
Print(stPulse.code + 1, cStr);
}
}
return NULL;
}
// *****************************************************************************
// Function : CreateRxThread
// Description : This function creates a thread which will block on MsgReceive.
// Notes : None
// : NA
// *****************************************************************************
void CreateRxThread(void)
{
if ( pthread_create(&nTHRD_ID, NULL, &Thrd_ReceivePulse, NULL) != EOK )
{
printf("\nThread Create failed. Retry!");
exit(0);
}
return;
}
// *****************************************************************************
// Function : IsTimerRunning
// Description : This function is used to find out whether the mentioned timer is running or not.
// Notes : None
// : NA
// *****************************************************************************
unsigned char IsTimerRunning(int nTimerId)
{
if ( nTimerId != 0 )
{
struct itimerspec timer = { { NULL } };
(void)timer_gettime(nTimerId, &timer);
return(! ((timer.it_value.tv_sec == 0) &&
(timer.it_value.tv_nsec == 0)));
}
return false;
}
// *****************************************************************************
// Function : StopTimer
// Description : This function stops the timer
// Notes : None
// : NA
// *****************************************************************************
void StopTimer(int nTimerId)
{
if ( nTimerId != 0 )
{
struct itimerspec timer; // values of 0 stops the timer
timer.it_value.tv_sec = NULL;
timer.it_value.tv_nsec = NULL;
timer.it_interval.tv_sec = NULL;
timer.it_interval.tv_nsec = NULL;
// stop the timer
if ( timer_settime(nTimerId, NULL, &timer, NULL) < 0 )
{
printf("\n\nTimer Stop failed. Retry!\n");
exit(0);
}
}
return;
}
// *****************************************************************************
// Function : DeleteTimers
// Description : This function deletes all the timers which are currently running.
// Notes : None
// : NA
// *****************************************************************************
void DeleteTimers(int nSigNumber)
{
for(int i = NULL; i < MAX_TIMER; ++i)
{
if ( Timers[i] != 0 )
{
StopTimer(Timers[i]);
if ( timer_delete(Timers[i]) != 0 )
{
printf("\nTimer Delete Failed. Retry!\n");
exit(0);
}
}
}
printf("\nExited Normally\n");
exit(0);
}
// *****************************************************************************
// Function : HandleSignal
// Description : This function handles the signals raised by the timers.
// Notes : None
// : NA
// *****************************************************************************
void HandleSignal(int nTimerNum)
{
nTimerNum = ( nTimerNum == SIGUSR1 ) ? 2 : ( ( nTimerNum == SIGUSR2 ) ? 9 : nTimerNum);
int nElapseTime = clock() - nLastClock[nTimerNum - 1];
double fFinaltime=GetTimeStampInMilliSeconds();
double nElapseTime_ts=fFinaltime-nLastClock_ts[nTimerNum -1];
nLastClock_ts[nTimerNum -1]=GetTimeStampInMilliSeconds();
nLastClock[nTimerNum - 1] = clock();
if ( nTimerVal[nTimerNum - 1][1] == 0 )
{
sprintf(cStr1, "\nConfigured Elapse time: %d, timestamp difference: %f", nTimerVal[nTimerNum -1][0], nElapseTime_ts);
Print(nTimerNum, cStr1);
Timers[nTimerNum - 1] = NULL;
}
else
{
sprintf(cStr1, "\nConfigured one shot value: %d, timestamp difference: %f",\
nTimerVal[nTimerNum -1][1],nElapseTime_ts) ;
Print(nTimerNum, cStr1);
}
return;
}
// *****************************************************************************
// Function : main
// Description : This is the main funtion.
// Notes : None
// : NA
// *****************************************************************************
int main(void)
{
(void)signal(SIGINT, DeleteTimers); //Configure CTRL + C;
(void)signal(SIGHUP, HandleSignal); // SIGHUP = 1
(void)signal(SIGQUIT, HandleSignal); // SIGQUIT = 3
(void)signal(SIGILL, HandleSignal); // SIGILL = 4
(void)signal(SIGTRAP, HandleSignal); // SIGTRAP = 5
(void)signal(SIGABRT, HandleSignal); // SIGABRT = 6
(void)signal(SIGEMT, HandleSignal); // SIGEMT = 7
(void)signal(SIGFPE, HandleSignal); // SIGFPE = 8
(void)signal(SIGBUS, HandleSignal); // SIGBUS = 10
(void)signal(SIGUSR1, HandleSignal); // SIGUSR1 = 16
(void)signal(SIGUSR2, HandleSignal); // SIGUSR2 = 17
int nContinue = NULL; //to hold the value whether the user wants to try one more time or not
int nTimerType = NULL; //to hold the the value for timer type
char nLoopInd = NULL; //to count the number of timers created
struct sigevent stTimerCreate = { NULL }; //Structure to be filled for creating a timer
struct itimerspec stTimerSettime = { { NULL} }; //Structure to be filled to start a timer
int nNotifyType[MAX_TIMER] = { NULL }; //to hold the value for the notification type
uint64_t un64CpuSpeed = SYSPAGE_ENTRY(qtime) ->cycles_per_sec;
setClockSpeed((double)un64CpuSpeed);
CreateConnection();
CreateRxThread();
do
{
do
{
printf("\nEnter the timer type: ");
printf("\n1. Single shot timer");
printf("\n2. Periodic timer");
/*printf("\n\nYour choice: ");
scanf("%d", &nTimerType);*/
cout<<"\n\nYour choice:";
cin >> nTimerType;
}while( ( nTimerType < 1 ) || ( nTimerType > 2 ) );
if ( nTimerType == 1 )
{
do
{
/*printf("\nEnter the timer value in milliseconds: ");
scanf("%d", &nTimerVal[nLoopInd][0]);*/
cout << "\nEnter the timer value in milliseconds:";
cin >> nTimerVal[nLoopInd][0];
}while(nTimerVal[nLoopInd][0] < 0);
nTimerVal[nLoopInd][1] = NULL;
}
else
{
do
{
/*printf("\nEnter the one shot value in milliseconds: ");
scanf("%d", &nTimerVal[nLoopInd][0]);*/
cout<<"\nEnter the one shot value in milliseconds: ";
cin>>nTimerVal[nLoopInd][0];
}while(nTimerVal[nLoopInd][0] < 0);
do
{
/*printf("\nEnter the interval value in milliseconds: ");
scanf("%d", &nTimerVal[nLoopInd][1]);*/
cout<<"\nEnter the interval value in milliseconds: ";
cin>>nTimerVal[nLoopInd][1];
}while(nTimerVal[nLoopInd][1] < 0);
}
do
{
printf("\nChoose the notification scheme you want to test: ");
printf("\n1. Send a Pulse");
printf("\n2. Send a Signal");
/*printf("\n\nYour choice: ");
scanf("%d", &nNotifyType[nLoopInd]);*/
cout<<"\n\nYour choice: ";
cin>>nNotifyType[nLoopInd];
}while( ( nNotifyType[nLoopInd] < 1 ) || ( nNotifyType[nLoopInd] > 3 ) );
sprintf(cStr, "\nTimer: %d, Timer value (msec): %d, Timer type: %s, Notification scheme: %s\n",
nLoopInd + 1, nTimerVal[nLoopInd][0], ( nTimerType == 1 ) ? "Single Shot" : "Periodic",
( nNotifyType[nLoopInd] == 1 ) ? "Pulse" : ( ( nNotifyType[nLoopInd] == 2 ) ? "Signal" : "Thread" ) );
Print(nLoopInd + 1, cStr);
nLoopInd++;
/* printf("\nDo you want to create one more timer? (Yes -1, No -0): ");
scanf("%d", &nContinue);*/
cout<<"\nDo you want to create one more timer? (Yes -1, No -0): ";
cin>>nContinue;
}while( ( nContinue == 1 ) && ( nLoopInd < MAX_TIMER ) );
if ( ( nLoopInd == MAX_TIMER ) && (nContinue == 1 ) )
{
printf("\n No more timers can be created.");
}
for(int i = NULL; i < nLoopInd; ++i)
{
switch( nNotifyType[i] )
{
case 1: //Pulse notification
{
//Initialize the sigevent structure for pulse notification
stTimerCreate.sigev_notify = SIGEV_PULSE;
stTimerCreate.sigev_coid = nCONN_ID;
stTimerCreate.sigev_value.sival_int = NULL;
nLastClock[i] = clock();
nLastClock_ts[i]=GetTimeStampInMilliSeconds();
stTimerCreate.sigev_code = i;
stTimerCreate.sigev_priority = getprio(NULL);
//Create the timer
if ( timer_create(CLOCK_REALTIME, &stTimerCreate, &Timers[i]) == -1 )
{
printf("\nError on creating timer. Retry!");
exit(0);
}
//Fill the structure to set the timer value
stTimerSettime.it_value.tv_sec = (long) nTimerVal[i][0] / 1000; //One shot value
stTimerSettime.it_value.tv_nsec = (long) ( ( nTimerVal[i][0] % 1000 ) * 1000 * 1000);
stTimerSettime.it_interval.tv_sec = (long) nTimerVal[i][1] / 1000; //Interval value
stTimerSettime.it_interval.tv_nsec = (long) ( ( nTimerVal[i][1] % 1000 ) * 1000 * 1000);
//Start the timer, this timer is a relative timer
timer_settime(Timers[i], NULL, &stTimerSettime, NULL);
}
break;
case 2: //Signal
{
//Initialize the sigevent structure for pulse notification
nLastClock[i] = clock();
nLastClock_ts[i]=GetTimeStampInMilliSeconds();
stTimerCreate.sigev_signo = ( i == 1 ) ? SIGUSR1 :
( ( i == 8 ) ? SIGUSR2 : i + 1 );
stTimerCreate.sigev_notify = SIGEV_SIGNAL;
//Create the timer
if ( timer_create(CLOCK_REALTIME, &stTimerCreate, &Timers[i]) == -1 )
{
printf("\nError on creating timer. Retry!");
exit(0);
}
//Fill the structure to set the timer value
stTimerSettime.it_value.tv_sec = (long) nTimerVal[i][0] / 1000; //One shot value
stTimerSettime.it_value.tv_nsec = (long) ( ( nTimerVal[i][0] % 1000 ) * 1000 * 1000);
stTimerSettime.it_interval.tv_sec = (long) nTimerVal[i][1] / 1000; //Interval value
stTimerSettime.it_interval.tv_nsec = (long) ( ( nTimerVal[i][1] % 1000 ) * 1000 * 1000);
//Start the timer, this timer is a relative timer
timer_settime(Timers[i], NULL, &stTimerSettime, NULL);
}
break;
default:
{
printf("Code never reaches here");
}
break;
}
}
printf("\nPress CTRL+C to terminate the program...\n");
while(1);
return NULL;
}