Task 1 for the course "Real Time and Embedded Systems" of THMMY in AUTH university.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

209 lines
6.0 KiB

/* ===== INCLUDES ===== */
#include "test_sample_functions.h"
/* ===== CONSTANTS ===== */
const char *ARGUMENT_TIME = "-t";
const char *ARGUMENT_DELTA = "-d";
const char *ARGUMENT_OUTPUT_FILENAME = "-o";
char *DEFAULT_OUTPUT_FILENAME = "sample_test_output";
/* ===== STRUCTURES ===== */
struct timeval startwtime, endwtime;
/* ===== OTHER ===== */
volatile sig_atomic_t sample_flag = false;
/* ===== FUNCTIONS ===== */
/*
* testSampling implements the sampling experiment. Three different ways of sampling are
* implemented. On the first one sleep is used. On the second sleep is used and the sleep times are
* corrected based on the previous error. On the third alarms are used.
*/
void testSampling(double ***samplesMatrix, Parameters parameters) {
printf(ANSI_COLOR_CYAN "----- RUNNING FIRST EXPERIMENT\n" ANSI_COLOR_RESET);
for (int i = 0; i < parameters.numberOfSamples; ++i) {
gettimeofday (&startwtime, NULL);
usleep(parameters.delta * 1000000);
gettimeofday (&endwtime, NULL);
(*samplesMatrix)[i][0] = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6 +
endwtime.tv_sec - startwtime.tv_sec);
}
printf(ANSI_COLOR_CYAN "----- RUNNING SECOND EXPERIMENT\n" ANSI_COLOR_RESET);
double totalError = 0;
for (int i = 0; i < parameters.numberOfSamples; ++i) {
gettimeofday (&startwtime, NULL);
usleep((parameters.delta - (totalError / (i + 1))) * 1000000);
gettimeofday (&endwtime, NULL);
(*samplesMatrix)[i][1] = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6 +
endwtime.tv_sec - startwtime.tv_sec);
totalError += (*samplesMatrix)[i][1] - parameters.delta;
}
printf(ANSI_COLOR_CYAN "----- RUNNING THIRD EXPERIMENT\n" ANSI_COLOR_RESET);
signal(SIGALRM, handle_alarm);
struct itimerval new;
new.it_interval.tv_usec = (int) ((parameters.delta - ((int) parameters.delta)) * 1000000);
new.it_interval.tv_sec = ((int) parameters.delta);
new.it_value.tv_usec = (int) ((parameters.delta - ((int) parameters.delta)) * 1000000);
new.it_value.tv_sec = ((int) parameters.delta);
if (setitimer (ITIMER_REAL, &new, NULL) == -1) {
perror("setitimer");
exit(EXIT_FAILURE);
}
gettimeofday (&startwtime, NULL);
int i = 0 ;
while(i < parameters.numberOfSamples) {
if (sample_flag) {
sample_flag = false;
gettimeofday (&endwtime, NULL);
(*samplesMatrix)[i][2] = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6 +
endwtime.tv_sec - startwtime.tv_sec);
++i;
gettimeofday (&startwtime, NULL);
}
}
alarm(0);
printf(ANSI_COLOR_CYAN "----- RUNNING FOURTH EXPERIMENT\n" ANSI_COLOR_RESET);
if (setitimer (ITIMER_REAL, &new, NULL) == -1) {
perror("setitimer");
exit(EXIT_FAILURE);
}
for (i = 0; i < parameters.numberOfSamples; ++i){
gettimeofday (&startwtime, NULL);
// Sleeps until a signal wakes up the process.
sleep(parameters.time + 420);
while (!sample_flag) {
// Does nothing.
// Makes sure signal was indeed triggered.
}
sample_flag = false;
gettimeofday (&endwtime, NULL);
(*samplesMatrix)[i][3] = (double)((endwtime.tv_usec - startwtime.tv_usec)/1.0e6 +
endwtime.tv_sec - startwtime.tv_sec);
}
}
void handle_alarm(int sig) {
sample_flag = true;
}
// ==================== PROGRAM INPUT AND OUTPUT UTILS ====================
/*
* parseArguments parses the command line arguments given by the user.
*/
void parseArguments(int argumentCount, char **argumentVector, Parameters *parameters) {
if (argumentCount > 7) {
validUsage(argumentVector[0]);
}
(*parameters).time = 7200;
(*parameters).delta = 0.1;
(*parameters).outputFilename = DEFAULT_OUTPUT_FILENAME;
char *endPointer;
int argumentIndex = 1;
while (argumentIndex < argumentCount) {
if (!strcmp(argumentVector[argumentIndex], ARGUMENT_TIME)) {
argumentIndex = checkIncrement(argumentIndex, argumentCount, argumentVector[0]);
double timeInput = strtod(argumentVector[argumentIndex], &endPointer);
if ((timeInput <= 0) && endPointer) {
printf("Invalid time argument\n");
exit(EXIT_FAILURE);
}
(*parameters).time = timeInput;
} else if (!strcmp(argumentVector[argumentIndex], ARGUMENT_DELTA)) {
argumentIndex = checkIncrement(argumentIndex, argumentCount, argumentVector[0]);
double deltaInput = strtod(argumentVector[argumentIndex], &endPointer);
if ((deltaInput <= 0) && endPointer) {
printf("Invalid time argument\n");
exit(EXIT_FAILURE);
}
(*parameters).delta = deltaInput;
} else if (!strcmp(argumentVector[argumentIndex], ARGUMENT_OUTPUT_FILENAME)) {
argumentIndex = checkIncrement(argumentIndex, argumentCount, argumentVector[0]);
if (fopen(argumentVector[argumentIndex], "w") == NULL) {
printf("Invalid output filename. Reverting to default.\n");
continue;
}
(*parameters).outputFilename = argumentVector[argumentIndex];
} else {
validUsage(argumentVector[0]);
exit(EXIT_FAILURE);
}
++argumentIndex;
}
}
/*
* validUsage outputs a message to the console that informs the user of the
* correct (valid) way to use the program.
*/
void validUsage(char *programName) {
printf("Usage:\t%s [-t time] [-d delta] [-o output]" \
"\n-t time" \
"\n\ttotal duration of the sampling in seconds, default value is 7200" \
"\n-d delta" \
"\n\tsampling period in seconds, default value is 0.1" \
"\n-o output" \
"\n\tfilename and path for the output, default filename is 'sample_test_output'" \
"\n", programName);
exit(EXIT_FAILURE);
}
/*
* checkIncrement is a helper function for parseArguments function.
*/
int checkIncrement(int previousIndex, int maxIndex, char *programName) {
if (previousIndex == maxIndex) {
validUsage(programName);
exit(EXIT_FAILURE);
}
return ++previousIndex;
}
void saveSamplesToFile(char *filename, double **samplesMatrix, int matrixRows) {
FILE *outputFile;
outputFile = fopen(filename, "a");
if (outputFile == NULL) {
printf("Error while opening the output file.\n");
return;
}
// Saves the samples matrix
for (int i=0; i<matrixRows; ++i) {
fprintf(outputFile, "%.10g\t%.10g\t%.10g\t%.10g\n",
samplesMatrix[i][0], samplesMatrix[i][1], samplesMatrix[i][2], samplesMatrix[i][3]);
}
fclose(outputFile);
}