From 876de3ddc85facb62b4eb24e07ca06a5b0f37e4f Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Wed, 8 Jun 2016 22:26:40 +0200 Subject: [PATCH] added new internal data structure for samples (instead of the old struct msg) --- include/sample.h | 95 +++++++++++++++++++++++++++++++ lib/sample.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 236 insertions(+) create mode 100644 include/sample.h create mode 100644 lib/sample.c diff --git a/include/sample.h b/include/sample.h new file mode 100644 index 000000000..7875ce3d2 --- /dev/null +++ b/include/sample.h @@ -0,0 +1,95 @@ +/** The internal datastructure for a sample of simulation data. + * + * @file + * @author Steffen Vogel + * @copyright 2014-2016, 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 _SAMPLE_H_ +#define _SAMPLE_H_ + +#include +#include +#include +#include +#include + +/** The length of a sample datastructure with \p values values in bytes. */ +#define SAMPLE_LEN(values) (sizeof(struct sample) + SAMPLE_DATA_LEN(values)) + +/** The length of a sample data portion of a sample datastructure with \p values values in bytes. */ +#define SAMPLE_DATA_LEN(values) ((values) * sizeof(float)) + +/** The offset to the beginning of the data section. */ +#define SAMPLE_DATA_OFFSET(smp) ((char *) (smp) + offsetof(struct sample, values)) + +/** These flags define the format which is used by sample_fscan() and sample_fprint(). */ +enum sample_flags { + SAMPLE_NANOSECONDS = 1, + SAMPLE_OFFSET = 2, + SAMPLE_SEQUENCE = 4, + SAMPLE_VALUES = 8, + SAMPLE_ALL = 16-1 +}; + +struct sample { + int length; /**< The number of values in sample::values. */ + int sequence; /**< The sequence number of this sample. */ + + /** All timestamps are seconds / nano seconds after 1.1.1970 UTC */ + struct { + struct timespec origin; /**< The point in time when this data was sampled. */ + struct timespec received; /**< The point in time when this data was received. */ + struct timespec sent; /**< The point in time this data was send for the last time. */ + } ts; + + /** The values. */ + union { + float f; /**< Floating point values (note msg::endian) */ + uint32_t i; /**< Integer values (note msg::endian) */ + } values[]; +}; + +/** Print a sample in human readable form to a file stream. + * + * @param buf A character buffer of len bytes. + * @param len The size of buf. + * @param m A pointer to the sample. + * @param flags See sample_flags. + * @return Number of bytes written to buf. + */ +int sample_print(char *buf, size_t len, struct sample *s, int flags); + +/** Read a sample from a character buffer. + * + * @param line A string which should be parsed. + * @param s A pointer to the sample. + * @param flags et SAMPLE_* flags for each component found in sample if not NULL. See sample_flags. + * @retval 0 Success. Everything went well. + * @retval <0 Error. Something went wrong. + */ +int sample_scan(const char *line, struct sample *s, int *fl); + +/** Print a sample in human readable form to a file stream. + * + * @see sample_print() + * @param f The file handle from fopen() or stdout, stderr. + * @param s A pointer to the sample. + * @retval 0 Success. Everything went well. + * @retval <0 Error. Something went wrong. + */ +int sample_fprint(FILE *f, struct sample *s, int flags); + +/** Read a sample from a file stream. + * + * @see sample_scan() + * @param f The file handle from fopen() or stdin. + * @param s A pointer to the sample. + * @retval 0 Success. Everything went well. + * @retval <0 Error. Something went wrong. + */ +int sample_fscan(FILE *f, struct sample *s, int *flags); + +#endif /* _SAMPLE_H_ */ \ No newline at end of file diff --git a/lib/sample.c b/lib/sample.c new file mode 100644 index 000000000..bad1ecdc1 --- /dev/null +++ b/lib/sample.c @@ -0,0 +1,141 @@ +/** The internal datastructure for a sample of simulation data. + * + * @author Steffen Vogel + * @copyright 2014-2016, 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 "sample.h" +#include "timing.h" + +int sample_print(char *buf, size_t len, struct sample *s, int flags) +{ + size_t off = snprintf(buf, len, "%llu", (unsigned long long) s->ts.origin.tv_sec); + + if (flags & SAMPLE_NANOSECONDS) + off += snprintf(buf + off, len - off, ".%09llu", (unsigned long long) s->ts.origin.tv_nsec); + + if (flags & SAMPLE_OFFSET) + off += snprintf(buf + off, len - off, "%+g", time_delta(&s->ts.received, &s->ts.origin)); + + if (flags & SAMPLE_SEQUENCE) + off += snprintf(buf + off, len - off, "(%u)", s->sequence); + + if (flags & SAMPLE_VALUES) { + for (int i = 0; i < s->length; i++) + off += snprintf(buf + off, len - off, "\t%.6f", s->values[i].f); + } + + off += snprintf(buf + off, len - off, "\n"); + + return off + 1; /* trailing '\0' */ +} + +int sample_scan(const char *line, struct sample *s, int *fl) +{ + char *end; + const char *ptr = line; + + int flags = 0; + double offset = 0; + + /* Format: Seconds.NanoSeconds+Offset(SequenceNumber) Value1 Value2 ... + * RegEx: (\d+(?:\.\d+)?)([-+]\d+(?:\.\d+)?(?:e[+-]?\d+)?)?(?:\((\d+)\))? + * + * Please note that only the seconds and at least one value are mandatory + */ + + /* Mandatory: seconds */ + s->ts.origin.tv_sec = (uint32_t) strtoul(ptr, &end, 10); + if (ptr == end) + return -2; + + /* Optional: nano seconds */ + if (*end == '.') { + ptr = end + 1; + + s->ts.origin.tv_nsec = (uint32_t) strtoul(ptr, &end, 10); + if (ptr != end) + flags |= SAMPLE_NANOSECONDS; + else + return -3; + } + else + s->ts.origin.tv_nsec = 0; + + /* Optional: offset / delay */ + if (*end == '+' || *end == '-') { + ptr = end; + + offset = strtof(ptr, &end); /* offset is ignored for now */ + if (ptr != end) + flags |= SAMPLE_OFFSET; + else + return -4; + } + + /* Optional: sequence */ + if (*end == '(') { + ptr = end + 1; + + s->sequence = strtoul(ptr, &end, 10); + if (ptr != end) + flags |= SAMPLE_SEQUENCE; + else + return -5; + + if (*end == ')') + end++; + } + + for (s->length = 0, ptr = end; ; + s->length++, ptr = end) { + + /** @todo We only support floating point values at the moment */ + s->values[s->length].f = strtod(ptr, &end); + + if (end == ptr) /* there are no valid FP values anymore */ + break; + } + + if (s->length > 0) + flags |= SAMPLE_VALUES; + + if (fl) + *fl = flags; + if (flags & SAMPLE_OFFSET) { + struct timespec off = time_from_double(offset); + s->ts.received = time_diff(&s->ts.origin, &off); + } + + return s->length; +} + +int sample_fprint(FILE *f, struct sample *s, int flags) +{ + char line[4096]; + + int len = sample_print(line, sizeof(line), s, flags); + + fputs(line, f); + + return len; +} + +int sample_fscan(FILE *f, struct sample *s, int *fl) +{ + char *ptr, line[4096]; + +skip: if (fgets(line, sizeof(line), f) == NULL) + return -1; /* An error occured */ + + /* Skip whitespaces, empty and comment lines */ + for (ptr = line; isspace(*ptr); ptr++); + if (*ptr == '\0' || *ptr == '#') + goto skip; + + return sample_scan(line, s, fl); +} \ No newline at end of file