diff --git a/server/include/timing.h b/server/include/timing.h new file mode 100644 index 000000000..3a8fbccc9 --- /dev/null +++ b/server/include/timing.h @@ -0,0 +1,55 @@ +/** Time related functions. + * + * @file + * @author Steffen Vogel + * @copyright 2014-2015, Institute for Automation of Complex Power Systems, EONERC + * This file is part of S2SS. All Rights Reserved. Proprietary and confidential. + * Unauthorized copying of this file, via any medium is strictly prohibited. + *********************************************************************************/ + +#ifndef _TIME_H_ +#define _TIME_H_ + +#include +#include +#include + +/** Wait until timer elapsed + * + * @param fd A file descriptor which was created by timerfd_create(3). + * @retval 0 An error occured. Maybe the timer was stopped. + * @retval >0 The nummer of runs this timer already fired. + */ +uint64_t timerfd_wait(int fd); + +/** Wait until a fixed time in the future is reached + * + * @param fd A file descriptor which was created by timerfd_create(3). + * @param until A pointer to a time in the future. + * @retval 0 An error occured. Maybe the timer was stopped. + * @retval >0 The nummer of runs this timer already fired. + */ +uint64_t timerfd_wait_until(int fd, struct timespec *until); + +/** Get delta between two timespec structs */ +struct timespec time_diff(struct timespec *start, struct timespec *end); + +/** Get sum of two timespec structs */ +struct timespec time_add(struct timespec *start, struct timespec *end); + +/** Return the diffrence off two timestamps as double value in seconds. */ +double time_delta(struct timespec *start, struct timespec *end); + +/** Convert timespec to double value representing seconds */ +double time_to_double(struct timespec *ts); + +/** Convert double containing seconds after 1970 to timespec. */ +struct timespec time_from_double(double secs); + +/** Read a timestamp from a file with the format: "secs.nanosecs\t" */ +int time_fscan(FILE *f, struct timespec *ts); + +/** Write a timestamp to a file with the format: "secs.nanosecs\t" */ +int time_fprint(FILE *f, struct timespec *ts); + +#endif \ No newline at end of file diff --git a/server/src/file.c b/server/src/file.c index 378a04f14..80682a2b6 100644 --- a/server/src/file.c +++ b/server/src/file.c @@ -13,7 +13,7 @@ #include "file.h" #include "utils.h" - +#include "timing.h" int file_init(int argc, char *argv[], struct settings *set) { INDENT @@ -53,10 +53,7 @@ int file_parse(config_setting_t *cfg, struct node *n) f->mode = "w+"; if (!config_setting_lookup_float(cfg, "rate", &f->rate)) - f->rate = 1; - - if (!config_setting_lookup_bool(cfg, "timestamp", &f->timestamp)) - f->timestamp = 0; + f->rate = 0; n->file = f; @@ -76,10 +73,19 @@ int file_open(struct node *n) if (f->tfd < 0) serror("Failed to create timer"); - struct itimerspec its = { - .it_interval = timespec_rate(f->rate), - .it_value = { 1, 0 } - }; + /* Arm the timer */ + struct itimerspec its; + if (f->rate) { + /* Send with fixed rate */ + its.it_interval = time_from_double(1 / f->rate); + its.it_value = (struct timespec) { 1, 0 }; + } + else { + /* Read timestamp from first line to get an epoch offset */ + time_fscan(f->in, &f->offset); + rewind(f->in); + } + int ret = timerfd_settime(f->tfd, 0, &its, NULL); if (ret) serror("Failed to start timer"); @@ -116,14 +122,16 @@ int file_read(struct node *n, struct msg *pool, int poolsize, int first, int cnt struct file *f = n->file; if (f->in) { - /* Blocking for 1/f->rate seconds */ - if (timerfd_wait(f->tfd)) { - for (i = 0; i < cnt; i++) { - struct msg *m = &pool[(first+i) % poolsize]; + struct timespec ts; - msg_fscan(f->in, m); - } - } + for (i = 0; i < cnt; i++) + msg_fscan(f->in, &pool[(first+i) % poolsize]); + + if (f->rate) + timerfd_wait(f->tfd); + else + timerfd_wait_until(f->tfd, &ts); + } else warn("Can not read from node '%s'", n->name); @@ -136,18 +144,12 @@ int file_write(struct node *n, struct msg *pool, int poolsize, int first, int cn int i = 0; struct file *f = n->file; - if (f->out) { - for (i = 0; i < cnt; i++) { - struct msg *m = &pool[(first+i) % poolsize]; + if (f->out) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); - if (f->timestamp) { - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - fprintf(f->out, "%lu.%06lu\t", ts.tv_sec, (long) (ts.tv_nsec / 1e3)); - } - - msg_fprint(f->out, m); - } + for (i = 0; i < cnt; i++) + msg_fprint(f->out, &pool[(first+i) % poolsize]); } else warn("Can not write to node '%s", n->name); diff --git a/server/src/gtfpga.c b/server/src/gtfpga.c index fb4d4c3cb..f2ac1a468 100644 --- a/server/src/gtfpga.c +++ b/server/src/gtfpga.c @@ -211,7 +211,7 @@ int gtfpga_open(struct node *n) serror("Failed to create timer"); struct itimerspec its = { - .it_interval = timespec_rate(g->rate), + .it_interval = time_from_double(1 / g->rate), .it_value = { 1, 0 } }; ret = timerfd_settime(g->fd_irq, 0, &its, NULL); diff --git a/server/src/path.c b/server/src/path.c index 465a82d58..636a6538e 100644 --- a/server/src/path.c +++ b/server/src/path.c @@ -17,6 +17,7 @@ #include "utils.h" #include "path.h" #include "socket.h" +#include "timing.h" #ifndef sigev_notify_thread_id #define sigev_notify_thread_id _sigev_un._tid @@ -46,7 +47,7 @@ static void * path_run_async(void *arg) { struct path *p = arg; struct itimerspec its = { - .it_interval = timespec_rate(p->rate), + .it_interval = time_from_double(1 / p->rate), .it_value = { 1, 0 } }; diff --git a/server/src/random.c b/server/src/random.c index 3c9d5bde7..958c7670c 100644 --- a/server/src/random.c +++ b/server/src/random.c @@ -41,7 +41,7 @@ int main(int argc, char *argv[]) /* Setup timer */ struct itimerspec its = { - .it_interval = timespec_rate(rate), + .it_interval = time_from_double(1 / rate), .it_value = { 1, 0 } }; diff --git a/server/src/test.c b/server/src/test.c index 853d57468..54a956f10 100644 --- a/server/src/test.c +++ b/server/src/test.c @@ -173,7 +173,7 @@ void test_rtt() { node_read_single(node, &m); /* Pong */ clock_gettime(CLOCK_ID, ts2); - rtt = timespec_delta(ts1, ts2); + rtt = time_delta(ts1, ts2); if (rtt < 0) continue; if (rtt > rtt_max) rtt_max = rtt; diff --git a/server/src/timing.c b/server/src/timing.c new file mode 100644 index 000000000..d8ecf18d8 --- /dev/null +++ b/server/src/timing.c @@ -0,0 +1,93 @@ +/** Time related functions. + * + * @author Steffen Vogel + * @copyright 2014-2015, Institute for Automation of Complex Power Systems, EONERC + * This file is part of S2SS. All Rights Reserved. Proprietary and confidential. + * Unauthorized copying of this file, via any medium is strictly prohibited. + *********************************************************************************/ + +#include +#include + +#include "timing.h" + +uint64_t timerfd_wait(int fd) +{ + uint64_t runs; + + return read(fd, &runs, sizeof(runs)) < 0 ? 0 : runs; +} + +uint64_t timerfd_wait_until(int fd, struct timespec *until) +{ + struct itimerspec its = { + .it_value = *until + }; + + if (timerfd_settime(fd, TFD_TIMER_ABSTIME, &its, NULL)) + return 0; + else + return timerfd_wait(fd); +} + +struct timespec time_add(struct timespec *start, struct timespec *end) +{ + struct timespec sum = { + .tv_sec = end->tv_sec + start->tv_sec, + .tv_nsec = end->tv_nsec + start->tv_nsec + }; + + if (sum.tv_nsec > 1000000000) { + sum.tv_sec += 1; + sum.tv_nsec -= 1000000000; + } + + return sum; +} + +struct timespec time_diff(struct timespec *start, struct timespec *end) +{ + struct timespec diff = { + .tv_sec = end->tv_sec - start->tv_sec, + .tv_nsec = end->tv_nsec - start->tv_nsec + }; + + if (diff.tv_nsec < 0) { + diff.tv_sec -= 1; + diff.tv_nsec += 1000000000; + } + + return diff; +} + +struct timespec time_from_double(double secs) +{ + struct timespec ts; + + ts.tv_sec = secs; + ts.tv_nsec = 1.0e9 * (secs - ts.tv_sec); + + return ts; +} + +double time_to_double(struct timespec *ts) +{ + return ts->tv_sec + ts->tv_nsec * 1e-9; +} + +double time_delta(struct timespec *start, struct timespec *end) +{ + struct timespec diff = time_diff(start, end); + + return time_to_double(&diff); +} + +int time_fscan(FILE *f, struct timespec *ts) +{ + return fscanf(f, "%lu.%lu", &ts->tv_sec, &ts->tv_nsec); +} + +int time_fprint(FILE *f, struct timespec *ts) +{ + return fprintf(f, "%lu.%09lu\t", ts->tv_sec, ts->tv_nsec); +} \ No newline at end of file diff --git a/server/src/utils.c b/server/src/utils.c index 8ea6f2654..4808abd73 100644 --- a/server/src/utils.c +++ b/server/src/utils.c @@ -113,36 +113,6 @@ void * alloc(size_t bytes) return p; } -uint64_t timerfd_wait(int fd) -{ - uint64_t runs; - - return read(fd, &runs, sizeof(runs)) < 0 ? 0 : runs; -} - -double timespec_delta(struct timespec *start, struct timespec *end) -{ - double sec = end->tv_sec - start->tv_sec; - double nsec = end->tv_nsec - start->tv_nsec; - - if (nsec < 0) { - sec -= 1; - nsec += 1e9; - } - - return sec + nsec * 1e-9; -} - -struct timespec timespec_rate(double rate) -{ - struct timespec ts; - - ts.tv_sec = 1 / rate; - ts.tv_nsec = 1.0e9 * (1 / rate - ts.tv_sec); - - return ts; -} - /** @todo: Proper way: create additional pipe for stderr in child process */ int system2(const char *cmd, ...) {