$<INSTALL_INTERFACE:include/soem>
)
+target_compile_options(soem PUBLIC
+ $<$<C_COMPILER_ID:GNU>:-std=c11>
+)
+
+target_compile_definitions(soem PUBLIC
+ $<$<C_COMPILER_ID:GNU>:_UCRT>
+)
+
+target_link_libraries(soem PUBLIC
+ $<$<C_COMPILER_ID:GNU>:ucrt>
+)
+
foreach(target IN ITEMS
soem
coetest
* license. See the file LICENSE.md distributed with this software for
* full license information.
*/
-
-#include <time.h>
-#include <sys/time.h>
-#include <unistd.h>
+#include <osal.h>
#include <stdlib.h>
#include <string.h>
-#include <osal.h>
-#define USECS_PER_SEC 1000000
-
-int osal_usleep(uint32 usec)
+/* Returns time from some unspecified moment in past,
+ * strictly increasing, used for time intervals measurement. */
+void osal_get_monotonic_time(ec_timet *ts)
{
- struct timespec ts;
- ts.tv_sec = usec / USECS_PER_SEC;
- ts.tv_nsec = (usec % USECS_PER_SEC) * 1000;
- /* usleep is deprecated, use nanosleep instead */
- return nanosleep(&ts, NULL);
+ /* Use clock_gettime to prevent possible live-lock.
+ * Gettimeofday uses CLOCK_REALTIME that can get NTP timeadjust.
+ * If this function preempts timeadjust and it uses vpage it live-locks.
+ * Also when using XENOMAI, only clock_gettime is RT safe */
+ clock_gettime(CLOCK_MONOTONIC, ts);
}
ec_timet osal_current_time(void)
{
- struct timespec current_time;
- ec_timet return_value;
-
- clock_gettime(CLOCK_REALTIME, ¤t_time);
- return_value.sec = current_time.tv_sec;
- return_value.usec = current_time.tv_nsec / 1000;
+ struct timespec ts;
- return return_value;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ return ts;
}
void osal_time_diff(ec_timet *start, ec_timet *end, ec_timet *diff)
{
- if (end->usec < start->usec)
- {
- diff->sec = end->sec - start->sec - 1;
- diff->usec = end->usec + 1000000 - start->usec;
- }
- else
- {
- diff->sec = end->sec - start->sec;
- diff->usec = end->usec - start->usec;
- }
+ osal_timespecsub(end, start, diff);
}
-/* Returns time from some unspecified moment in past,
- * strictly increasing, used for time intervals measurement. */
-static void osal_getrelativetime(struct timeval *tv)
+void osal_timer_start(osal_timert *self, uint32 timeout_usec)
{
- struct timespec ts;
+ struct timespec start_time;
+ struct timespec timeout;
- /* Use clock_gettime to prevent possible live-lock.
- * Gettimeofday uses CLOCK_REALTIME that can get NTP timeadjust.
- * If this function preempts timeadjust and it uses vpage it live-locks.
- * Also when using XENOMAI, only clock_gettime is RT safe */
- clock_gettime(CLOCK_MONOTONIC, &ts);
- tv->tv_sec = ts.tv_sec;
- tv->tv_usec = ts.tv_nsec / 1000;
+ osal_get_monotonic_time(&start_time);
+ osal_timespec_from_usec(timeout_usec, &timeout);
+ osal_timespecadd(&start_time, &timeout, &self->stop_time);
}
-void osal_timer_start(osal_timert *self, uint32 timeout_usec)
+boolean osal_timer_is_expired(osal_timert *self)
{
- struct timeval start_time;
- struct timeval timeout;
- struct timeval stop_time;
+ struct timespec current_time;
+ int is_not_yet_expired;
- osal_getrelativetime(&start_time);
- timeout.tv_sec = timeout_usec / USECS_PER_SEC;
- timeout.tv_usec = timeout_usec % USECS_PER_SEC;
- timeradd(&start_time, &timeout, &stop_time);
+ osal_get_monotonic_time(¤t_time);
+ is_not_yet_expired = osal_timespeccmp(¤t_time, &self->stop_time, <);
- self->stop_time.sec = stop_time.tv_sec;
- self->stop_time.usec = stop_time.tv_usec;
+ return is_not_yet_expired == FALSE;
}
-boolean osal_timer_is_expired(osal_timert *self)
+int osal_usleep(uint32 usec)
{
- struct timeval current_time;
- struct timeval stop_time;
- int is_not_yet_expired;
+ struct timespec ts;
+ int result;
- osal_getrelativetime(¤t_time);
- stop_time.tv_sec = self->stop_time.sec;
- stop_time.tv_usec = self->stop_time.usec;
- is_not_yet_expired = timercmp(¤t_time, &stop_time, <);
+ osal_timespec_from_usec(usec, &ts);
+ result = clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
+ return result == 0 ? 0 : -1;
+}
- return is_not_yet_expired == FALSE;
+int osal_monotonic_sleep(ec_timet *ts)
+{
+ int result;
+ result = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, ts, NULL);
+ return result == 0 ? 0 : -1;
}
void *osal_malloc(size_t size)
extern "C" {
#endif
+#include <pthread.h>
+#include <sys/time.h>
+
// define if debug printf is needed
#ifdef EC_DEBUG
#define EC_PRINT printf
#define PACKED_END
#endif
-#include <pthread.h>
+#define ec_timet struct timespec
+
#define OSAL_THREAD_HANDLE pthread_t *
#define OSAL_THREAD_FUNC void
#define OSAL_THREAD_FUNC_RT void
typedef float float32;
typedef double float64;
-typedef struct
-{
- uint32 sec; /*< Seconds elapsed since the Epoch (Jan 1, 1970) */
- uint32 usec; /*< Microseconds elapsed since last second boundary */
-} ec_timet;
-
typedef struct osal_timer
{
ec_timet stop_time;
} osal_timert;
+/* Returns time from some unspecified moment in past,
+ * strictly increasing, used for time intervals measurement. */
+void osal_get_monotonic_time(ec_timet *tv);
+int osal_monotonic_sleep(ec_timet *ts);
+
void osal_timer_start(osal_timert *self, uint32 timeout_us);
boolean osal_timer_is_expired(osal_timert *self);
int osal_usleep(uint32 usec);
void osal_mutex_lock(void *mutex);
void osal_mutex_unlock(void *mutex);
+#ifndef osal_timespec_from_usec
+#define osal_timespec_from_usec(usec, result) \
+ do \
+ { \
+ (result)->tv_sec = usec / 1000000; \
+ (result)->tv_nsec = (usec % 1000000) * 1000; \
+ } while (0)
+#endif
+
+#ifndef osal_timespeccmp
+#define osal_timespeccmp(a, b, CMP) \
+ (((a)->tv_sec == (b)->tv_sec) \
+ ? ((a)->tv_nsec CMP(b)->tv_nsec) \
+ : ((a)->tv_sec CMP(b)->tv_sec))
+#endif
+
+#ifndef osal_timespecadd
+#define osal_timespecadd(a, b, result) \
+ do \
+ { \
+ (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
+ (result)->tv_nsec = (a)->tv_nsec + (b)->tv_nsec; \
+ if ((result)->tv_nsec >= 1000000000) \
+ { \
+ ++(result)->tv_sec; \
+ (result)->tv_nsec -= 1000000000; \
+ } \
+ } while (0)
+#endif
+
+#ifndef osal_timespecsub
+#define osal_timespecsub(a, b, result) \
+ do \
+ { \
+ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
+ (result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \
+ if ((result)->tv_nsec < 0) \
+ { \
+ --(result)->tv_sec; \
+ (result)->tv_nsec += 1000000000; \
+ } \
+ } while (0)
+#endif
+
#ifdef __cplusplus
}
#endif
#include <osal.h>
#include <kern/kern.h>
-#include <time.h>
-#include <sys/time.h>
-#include <config.h>
-#define USECS_PER_SEC 1000000
-#define USECS_PER_TICK (USECS_PER_SEC / CFG_TICKS_PER_SECOND)
-
-int gettimeofday(struct timeval *tp, void *tzp)
+void osal_get_monotonic_time(ec_timet *tv)
{
tick_t tick = tick_get();
- tick_t ticks_left;
-
- ASSERT(tp != NULL);
-
- tp->tv_sec = tick / CFG_TICKS_PER_SECOND;
-
- ticks_left = tick % CFG_TICKS_PER_SECOND;
- tp->tv_usec = ticks_left * USECS_PER_TICK;
- ASSERT(tp->tv_usec < USECS_PER_SEC);
+ uint64_t usec = (uint64_t)(tick_to_ms(tick)) * 1000;
- return 0;
-}
-
-int osal_usleep(uint32 usec)
-{
- tick_t ticks = (usec / USECS_PER_TICK) + 1;
- task_delay(ticks);
- return 0;
-}
-
-int osal_gettimeofday(struct timeval *tv, struct timezone *tz)
-{
- return gettimeofday(tv, tz);
+ osal_timespec_from_usec(usec, tv);
}
ec_timet osal_current_time(void)
{
- struct timeval current_time;
- ec_timet return_value;
+ struct timeval tv;
+ struct timespec ts;
- gettimeofday(¤t_time, 0);
- return_value.sec = current_time.tv_sec;
- return_value.usec = current_time.tv_usec;
- return return_value;
+ gettimeofday(&tv, NULL);
+ TIMEVAL_TO_TIMESPEC(&tv, &ts);
+ return ts;
}
void osal_time_diff(ec_timet *start, ec_timet *end, ec_timet *diff)
{
- if (end->usec < start->usec)
- {
- diff->sec = end->sec - start->sec - 1;
- diff->usec = end->usec + 1000000 - start->usec;
- }
- else
- {
- diff->sec = end->sec - start->sec;
- diff->usec = end->usec - start->usec;
- }
+ osal_timespecsub(end, start, diff);
}
void osal_timer_start(osal_timert *self, uint32 timeout_usec)
{
- struct timeval start_time;
- struct timeval timeout;
- struct timeval stop_time;
-
- gettimeofday(&start_time, 0);
- timeout.tv_sec = timeout_usec / USECS_PER_SEC;
- timeout.tv_usec = timeout_usec % USECS_PER_SEC;
- timeradd(&start_time, &timeout, &stop_time);
+ struct timespec start_time;
+ struct timespec timeout;
- self->stop_time.sec = stop_time.tv_sec;
- self->stop_time.usec = stop_time.tv_usec;
+ osal_get_monotonic_time(&start_time);
+ osal_timespec_from_usec(timeout_usec, &timeout);
+ osal_timespecadd(&start_time, &timeout, &self->stop_time);
}
boolean osal_timer_is_expired(osal_timert *self)
{
- struct timeval current_time;
- struct timeval stop_time;
+ struct timespec current_time;
int is_not_yet_expired;
- gettimeofday(¤t_time, 0);
- stop_time.tv_sec = self->stop_time.sec;
- stop_time.tv_usec = self->stop_time.usec;
- is_not_yet_expired = timercmp(¤t_time, &stop_time, <);
+ osal_get_monotonic_time(¤t_time);
+ is_not_yet_expired = osal_timespeccmp(¤t_time, &self->stop_time, <);
- return is_not_yet_expired == false;
+ return is_not_yet_expired == FALSE;
+}
+
+int osal_usleep(uint32 usec)
+{
+ tick_t ticks = tick_from_ms(usec / 1000) + 1;
+ task_delay(ticks);
+ return 0;
}
void *osal_malloc(size_t size)
extern "C" {
#endif
+#include <sys/time.h>
+
// define if debug printf is needed
#ifdef EC_DEBUG
#define EC_PRINT printf
#define PACKED_END
#endif
+#define ec_timet struct timespec
+
#define OSAL_THREAD_HANDLE task_t *
#define OSAL_THREAD_FUNC void
#define OSAL_THREAD_FUNC_RT void
* full license information.
*/
-#include <winsock2.h>
#include <osal.h>
-#include "osal_win32.h"
+#include <stdlib.h>
+#include <inttypes.h>
+#include <timeapi.h>
-static int64_t sysfrequency;
-static double qpc2usec;
+static LARGE_INTEGER sysfrequency;
-#define USECS_PER_SEC 1000000
-
-static int osal_getrelativetime(struct timeval *tv, struct timezone *tz)
+void osal_get_monotonic_time(ec_timet *ts)
{
- int64_t wintime, usecs;
- (void)tz;
- if (!sysfrequency)
+ LARGE_INTEGER wintime;
+ uint64_t sec;
+ uint64_t nsec;
+
+ if (!sysfrequency.QuadPart)
{
timeBeginPeriod(1);
- QueryPerformanceFrequency((LARGE_INTEGER *)&sysfrequency);
- qpc2usec = 1000000.0 / sysfrequency;
+ QueryPerformanceFrequency(&sysfrequency);
}
- QueryPerformanceCounter((LARGE_INTEGER *)&wintime);
- usecs = (int64_t)((double)wintime * qpc2usec);
- tv->tv_sec = (long)(usecs / 1000000);
- tv->tv_usec = (long)(usecs - (tv->tv_sec * 1000000));
- return 1;
-}
+ QueryPerformanceCounter(&wintime);
-int osal_gettimeofday(struct timeval *tv, struct timezone *tz)
-{
- FILETIME system_time;
- int64 system_time64, usecs;
- (void)tz;
- /* The offset variable is required to switch from Windows epoch (January 1, 1601) to
- * Unix epoch (January 1, 1970). Number of days between both epochs: 134.774
- *
- * The time returned by GetSystemTimeAsFileTime() changes in 100 ns steps, so the
- * following factors are required for the conversion from days to 100 ns steps:
- *
- * 86.400 seconds per day; 1.000.000 microseconds per second; 10 * 100 ns per microsecond
- */
- int64 offset = -134774LL * 86400LL * 1000000LL * 10LL;
-
- GetSystemTimeAsFileTime(&system_time);
-
- system_time64 = ((int64)(system_time.dwHighDateTime) << 32) + (int64)system_time.dwLowDateTime;
- system_time64 += offset;
- usecs = system_time64 / 10;
-
- tv->tv_sec = (long)(usecs / 1000000);
- tv->tv_usec = (long)(usecs - (tv->tv_sec * 1000000));
+ /* Compute seconds */
+ sec = wintime.QuadPart / sysfrequency.QuadPart;
+ wintime.QuadPart = wintime.QuadPart - sec * sysfrequency.QuadPart;
- return 1;
+ /* Compute nanoseconds. Multiplying first acts as a guard against
+ potential loss of precision during the calculation. */
+ nsec = wintime.QuadPart * 1000000000;
+ nsec = nsec / sysfrequency.QuadPart;
+
+ ts->tv_sec = sec;
+ ts->tv_nsec = (uint32_t)nsec;
}
ec_timet osal_current_time(void)
{
- struct timeval current_time;
- ec_timet return_value;
-
- osal_gettimeofday(¤t_time, 0);
- return_value.sec = current_time.tv_sec;
- return_value.usec = current_time.tv_usec;
- return return_value;
+ struct timespec ts;
+ timespec_get(&ts, TIME_UTC);
+ return ts;
}
void osal_time_diff(ec_timet *start, ec_timet *end, ec_timet *diff)
{
- if (end->usec < start->usec)
- {
- diff->sec = end->sec - start->sec - 1;
- diff->usec = end->usec + 1000000 - start->usec;
- }
- else
- {
- diff->sec = end->sec - start->sec;
- diff->usec = end->usec - start->usec;
- }
+ osal_timespecsub(end, start, diff);
}
void osal_timer_start(osal_timert *self, uint32 timeout_usec)
{
- struct timeval start_time;
- struct timeval timeout;
- struct timeval stop_time;
-
- osal_getrelativetime(&start_time, 0);
- timeout.tv_sec = timeout_usec / USECS_PER_SEC;
- timeout.tv_usec = timeout_usec % USECS_PER_SEC;
- timeradd(&start_time, &timeout, &stop_time);
+ struct timespec start_time;
+ struct timespec timeout;
- self->stop_time.sec = stop_time.tv_sec;
- self->stop_time.usec = stop_time.tv_usec;
+ osal_get_monotonic_time(&start_time);
+ osal_timespec_from_usec(timeout_usec, &timeout);
+ osal_timespecadd(&start_time, &timeout, &self->stop_time);
}
boolean osal_timer_is_expired(osal_timert *self)
{
- struct timeval current_time;
- struct timeval stop_time;
+ struct timespec current_time;
int is_not_yet_expired;
- osal_getrelativetime(¤t_time, 0);
- stop_time.tv_sec = self->stop_time.sec;
- stop_time.tv_usec = self->stop_time.usec;
- is_not_yet_expired = timercmp(¤t_time, &stop_time, <);
+ osal_get_monotonic_time(¤t_time);
+ is_not_yet_expired = osal_timespeccmp(¤t_time, &self->stop_time, <);
return is_not_yet_expired == FALSE;
}
int osal_usleep(uint32 usec)
{
- osal_timert qtime;
- osal_timer_start(&qtime, usec);
- if (usec >= 1000)
+ struct timespec wakeup;
+ struct timespec timeout;
+
+ osal_get_monotonic_time(&wakeup);
+ osal_timespec_from_usec(usec, &timeout);
+ osal_timespecadd(&wakeup, &timeout, &wakeup);
+ osal_monotonic_sleep(&wakeup);
+ return 1;
+}
+
+/**
+ * @brief Suspends the execution of the calling thread until a
+ * specified absolute time.
+ *
+ * @param ts Pointer to a struct that specifies the
+ * absolute wakeup time in milliseconds.
+ * @return 0 on success, or a negative value on error.
+ */
+int osal_monotonic_sleep(ec_timet *ts)
+{
+ uint64_t millis;
+ struct timespec now;
+ struct timespec delay;
+
+ osal_get_monotonic_time(&now);
+
+ /* Delay already expired? */
+ if (!osal_timespeccmp(&now, ts, <))
+ return 0;
+
+ /* Sleep for whole milliseconds */
+ osal_timespecsub(ts, &now, &delay);
+ millis = delay.tv_sec * 1000 + delay.tv_nsec / 1000000;
+ if (millis > 0)
{
- SleepEx(usec / 1000, FALSE);
+ SleepEx((DWORD)millis, FALSE);
}
- while (!osal_timer_is_expired(&qtime))
- ;
- return 1;
+
+ /* Busy wait for remaining time */
+ do
+ {
+ osal_get_monotonic_time(&now);
+ } while osal_timespeccmp(&now, ts, <);
+
+ return 0;
}
void *osal_malloc(size_t size)
#define WIN32_LEAN_AND_MEAN // Exclude some conflicting definitions in windows header
#include <windows.h>
+#include <time.h>
// define if debug printf is needed
#ifdef EC_DEBUG
#define EC_PRINT printf
#define PACKED_BEGIN __pragma(pack(push, 1))
#define PACKED_END __pragma(pack(pop))
#endif
-
#endif
+#define ec_timet struct timespec
+
#define OSAL_THREAD_HANDLE HANDLE
#define OSAL_THREAD_FUNC void
#define OSAL_THREAD_FUNC_RT void
+++ /dev/null
-/*
- * This software is dual-licensed under GPLv3 and a commercial
- * license. See the file LICENSE.md distributed with this software for
- * full license information.
- */
-
-#ifndef _osal_win32_
-#define _osal_win32_
-
-/* Convenience macros for operations on timevals.
- NOTE: `timercmp' does not work for >= or <=. */
-#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
-#define timeradd(a, b, result) \
- do \
- { \
- (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
- (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
- if ((result)->tv_usec >= 1000000) \
- { \
- ++(result)->tv_sec; \
- (result)->tv_usec -= 1000000; \
- } \
- } while (0)
-#define timersub(a, b, result) \
- do \
- { \
- (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
- (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
- if ((result)->tv_usec < 0) \
- { \
- --(result)->tv_sec; \
- (result)->tv_usec += 1000000; \
- } \
- } while (0)
-
-struct timezone;
-// currently the tz parameter is ignored in the win32 implmentation.
-int osal_gettimeofday(struct timeval *tv, struct timezone *tz);
-
-#endif
#include <winsock2.h>
#include "soem/soem.h"
#include "nicdrv.h"
-#include "osal_win32.h"
/** Redundancy modes */
enum
if (mode == MODE_READINTEL) output_intelhex(fname, esize);
if (mode == MODE_READBIN) output_bin(fname, esize);
- printf("\nTotal EEPROM read time :%ldms\n", (tdif.usec + (tdif.sec * 1000000L)) / 1000);
+ printf("\nTotal EEPROM read time :%dms\n", (int)(tdif.tv_sec * 1000 + tdif.tv_nsec / 1000000));
}
if ((mode == MODE_WRITEBIN) || (mode == MODE_WRITEINTEL))
{
tend = osal_current_time();
osal_time_diff(&tstart, &tend, &tdif);
- printf("\nTotal EEPROM write time :%ldms\n", (tdif.usec + (tdif.sec * 1000000L)) / 1000);
+ printf("\nTotal EEPROM write time :%dms\n", (int)(tdif.tv_sec * 1000 + tdif.tv_nsec / 1000000));
}
else
printf("Error reading file, abort.\n");
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/time.h>
-#include <unistd.h>
#include "soem/soem.h"
wkc = ecx_receive_processdata(context, EC_TIMEOUTRET);
end = osal_current_time();
osal_time_diff(&start, &end, &diff);
- fieldbus->roundtrip_time = diff.sec * 1000000 + diff.usec;
+ fieldbus->roundtrip_time = (int)(diff.tv_sec * 1000000 + diff.tv_nsec / 1000);
return wkc;
}
ecx_BWR(context->port, 0, ECT_REG_DCTIME0, sizeof(ht), &ht, EC_TIMEOUTRET); /* latch DCrecvTimeA of all slaves */
mastertime = osal_current_time();
- mastertime.sec -= 946684800UL; /* EtherCAT uses 2000-01-01 as epoch start instead of 1970-01-01 */
- mastertime64 = (((uint64)mastertime.sec * 1000000) + (uint64)mastertime.usec) * 1000;
+ mastertime.tv_sec -= 946684800UL; /* EtherCAT uses 2000-01-01 as epoch start instead of 1970-01-01 */
+ mastertime64 = ((uint64)mastertime.tv_sec * 1000 * 1000 * 1000) + (uint64)mastertime.tv_nsec;
for (i = 1; i <= *(context->slavecount); i++)
{
context->slavelist[i].consumedports = context->slavelist[i].activeports;
char *ecx_err2string(const ec_errort Ec)
{
char timestr[20];
- sprintf(timestr, "Time:%12.3f", Ec.Time.sec + (Ec.Time.usec / 1000000.0));
+ sprintf(timestr, "Time:%12.3f", Ec.Time.tv_sec + (Ec.Time.tv_nsec / 1000000000.0));
switch (Ec.Etype)
{
case EC_ERR_TYPE_SDO_ERROR: