#include <stdio.h>
#include <stdint.h>
#include <errno.h>
#include <getopt.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/mman.h>
#include <sched.h>
#include <stdlib.h>
#include <pthread.h>
#define MAX_SAFE_STACK (8 * 1024)
#define NSEC_PER_SEC (1000000000)
#define DIFF_NS(A, B) (((long long) (B).tv_sec - (A).tv_sec) * NSEC_PER_SEC \
+ (B).tv_nsec - (A).tv_nsec)
int priority = -1;
int daemonize = 0;
unsigned int duration_ns = 0;
const char *config = 0;
struct timespec* timer_add(struct timespec *t, unsigned int dt_ns)
{
t->tv_nsec += dt_ns;
while (t->tv_nsec >= NSEC_PER_SEC) {
t->tv_nsec -= NSEC_PER_SEC;
t->tv_sec++;
}
return t;
}
int gettime(struct timespec *time)
{
return clock_gettime(CLOCK_REALTIME, time);
}
void stack_prefault(void)
{
unsigned char dummy[MAX_SAFE_STACK];
memset(dummy, 0, MAX_SAFE_STACK);
}
void usage(FILE *f, const char *base_name)
{
fprintf(f,
"Usage: %s [OPTIONS]\n"
"PdServ library version: %s\n"
"Options:\n"
" --duration -d secs Set duration <float>\n"
" --config -c conffile Set configuration file\n"
" --priority -p <PRIO> Set task priority. Default: RT.\n"
" --help -h Show this help.\n",
}
void get_options(int argc, char **argv)
{
int c, arg_count;
static struct option longOptions[] = {
{"duration", required_argument, NULL, 'd'},
{"config", required_argument, NULL, 'c'},
{"priority", required_argument, NULL, 'p'},
{"help", no_argument, NULL, 'h'},
{NULL, no_argument, NULL, 0}
};
do {
c = getopt_long(argc, argv, "d:c:p:h", longOptions, NULL);
switch (c) {
case 'p':
if (!strcmp(optarg, "RT")) {
priority = -1;
} else {
char *end;
priority = strtoul(optarg, &end, 10);
if (!*optarg || *end) {
fprintf(stderr, "Invalid priority: %s\n", optarg);
exit(1);
}
}
break;
case 'd':
duration_ns = atof(optarg) * NSEC_PER_SEC;
break;
case 'c':
config = optarg;
break;
case 'h':
usage(stdout, argv[0]);
exit(0);
case '?':
usage(stderr, argv[0]);
exit(1);
default:
break;
}
}
while (c != -1);
arg_count = argc - optind;
if (arg_count) {
fprintf(stderr, "%s takes no arguments!\n", argv[0]);
usage(stderr, argv[0]);
exit(1);
}
}
int limit_test(const struct pdvariable* param,
void *dst, const void* src, size_t len,
struct timespec *time, void* priv_data)
{
double value = *(double*)src;
double limit = *(double*)priv_data;
(void)time;
(void)param;
if (value > limit || value < -limit)
return -EINVAL;
memcpy(dst, src, len);
clock_gettime(CLOCK_REALTIME, time);
return 0;
}
void lock_fn(int lock, void* priv_data)
{
if (lock)
pthread_mutex_lock(priv_data);
else
pthread_mutex_unlock(priv_data);
}
int main(int argc, char **argv)
{
struct pdserv* pdserv;
struct pdtask* pdtask;
struct pdevent* event;
struct pdvariable* var;
unsigned int tsample_ns = (uint64_t)(0.01e9);
const char* err = NULL;
int running = 1;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
double exec_time, cycle_time;
unsigned int overruns = 0;
struct timespec monotonic_time, world_time;
struct timespec start_time, stop_time = {0,0}, end_time, last_start_time;
double omega = 1.2;
char enable = 1;
char reset = 0;
double omega_limit = 5.0;
double amplitude_set = 10.0;
double ampl_limit = 20.0;
unsigned int event_state[5] = {0,0,0,0,0};
double sin = 0.0, cos = amplitude_set;
double amplitude;
double ampl_modulation;
double derivative[2];
uint8_t counter;
int decimation_counter = 1;
get_options(argc, argv);
if (!(pdserv =
pdserv_create(
"PdServ Test",
"1.234", gettime))) {
err = "Failed to init pdserv.";
goto out;
}
if (config)
err = "Failed to create task.";
goto out;
}
0666,
pd_double_T, &omega, 1, 0, limit_test, &omega_limit);
"Derivative of [cos,sin]");
{
static const char *text[] = {
"Event message 1",
"Event message 2",
"Event message 3",
"Event message 4",
"Event message 5",
};
}
if (ret) {
err = "Failed to prepare pdserv.";
goto out;
}
if (mlockall(MCL_CURRENT | MCL_FUTURE))
fprintf(stderr, "mlockall() failed: %s\n", strerror(errno));
stack_prefault();
{
struct sched_param param = {
.sched_priority = (priority == -1
? sched_get_priority_max(SCHED_FIFO)
: priority),
};
if (sched_setscheduler(0, SCHED_FIFO, ¶m) == -1) {
fprintf(stderr,
"Setting SCHED_FIFO with priority %i failed: %s\n",
param.sched_priority, strerror(errno));
priority = -1;
}
}
clock_gettime(CLOCK_MONOTONIC, &monotonic_time);
last_start_time = monotonic_time;
if (duration_ns) {
stop_time = last_start_time;
timer_add(&stop_time, duration_ns);
}
while (running && (!duration_ns || DIFF_NS(last_start_time, stop_time) > 0)) {
clock_gettime(CLOCK_MONOTONIC, &start_time);
clock_gettime(CLOCK_REALTIME, &world_time);
pthread_mutex_lock(&mutex);
if (reset) {
cos = amplitude_set;
sin = 0.0;
}
else if (enable) {
amplitude = cos*cos + sin*sin;
ampl_modulation = 1.0/3.1415
* (amplitude/amplitude_set/amplitude_set - 1);
if (ampl_modulation > 1.0)
ampl_modulation = 1.0;
derivative[0] = -omega*sin - ampl_modulation*cos;
derivative[1] = omega*cos - ampl_modulation*sin;
cos += 1.0e-9*tsample_ns*derivative[0];
sin += 1.0e-9*tsample_ns*derivative[1];
if (cos > ampl_limit) cos = ampl_limit;
if (cos < -ampl_limit) cos = -ampl_limit;
if (sin > ampl_limit) sin = ampl_limit;
if (sin < -ampl_limit) sin = -ampl_limit;
}
if (!--decimation_counter) {
decimation_counter = 10;
++counter;
}
pthread_mutex_unlock(&mutex);
cycle_time = 1.0e-9 * DIFF_NS(last_start_time, start_time);
exec_time = 1.0e-9 * DIFF_NS(last_start_time, end_time);
last_start_time = start_time;
timer_add(&monotonic_time, tsample_ns);
clock_gettime(CLOCK_MONOTONIC, &end_time);
overruns += DIFF_NS(monotonic_time, end_time) > 0;
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &monotonic_time, 0);
}
pthread_mutex_destroy(&mutex);
out:
if (err) {
fprintf(stderr, "Fatal error: %s\n", err);
return 1;
}
return 0;
}
void pdserv_event_set_all(const struct pdevent *event, const unsigned int *level, const struct timespec *t)
void pdserv_update(struct pdtask *pdtask, const struct timespec *t)
struct pdserv * pdserv_create(const char *name, const char *version, gettime_t gettime_cb)
int pdserv_prepare(struct pdserv *pdserv)
void pdserv_set_parameter_writelock_cb(struct pdserv *pdserv, void(*fn)(int lock, void *priv_data), void *priv_data)
#define pd_double_T
double precision floating point data type
Definition: pdserv.h:155
void pdserv_exit(struct pdserv *)
#define pd_sint8_T
8 bit signed integer data type
Definition: pdserv.h:158
struct pdevent * pdserv_event(struct pdserv *pdserv, const char *path, size_t n)
void pdserv_event_set_text(struct pdevent *event, const char *const *text)
struct pdvariable * pdserv_signal(struct pdtask *pdtask, unsigned int decimation, const char *path, int datatype, const void *addr, size_t n, const size_t *dim)
#define pd_uint_T
unsigned int data type
Definition: pdserv.h:172
struct pdvariable * pdserv_parameter(struct pdserv *pdserv, const char *path, unsigned int mode, int datatype, void *addr, size_t n, const size_t *dim, write_parameter_t write_cb, void *priv_data)
void pdserv_update_statistics(struct pdtask *pdtask, double exec_time, double cycle_time, unsigned int overrun)
#define pd_uint8_T
8 bit unsigned integer data type
Definition: pdserv.h:157
void pdserv_config_file(struct pdserv *pdserv, const char *file)
const char *const pdserv_full_version
Full String of pdserv version, generated by git describe.
void pdserv_set_signal_readlock_cb(struct pdtask *pdtask, void(*fn)(int lock, void *priv_data), void *priv_data)
struct pdtask * pdserv_create_task(struct pdserv *pdserv, double tsample, const char *name)
void pdserv_set_comment(struct pdvariable *variable, const char *comment)