diff --git a/src/epics/seq/gps.hh b/src/epics/seq/gps.hh new file mode 100644 index 0000000000000000000000000000000000000000..5f13af3aeb382aca51f55867a147eb98d3f4f344 --- /dev/null +++ b/src/epics/seq/gps.hh @@ -0,0 +1,136 @@ +// +// Created by jonathan.hanks on 10/20/17. +// + +#ifndef TRANSFER_GPS_H +#define TRANSFER_GPS_H + +#include <ostream> + +#include <time.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> + +#include <unistd.h> + + +/** + * Operations on GPS time. + * Note for purposes of this testing, this does not return GPS time but system time. + */ +namespace GPS { + + struct gps_time + { + long sec; + long nanosec; + + gps_time(): sec(0), nanosec(0) {} + explicit gps_time(long s): sec(s), nanosec(0) {} + gps_time(long s, long ns): sec(s), nanosec(ns) {} + gps_time(const gps_time& other): sec(other.sec), nanosec(other.nanosec) {} + + gps_time operator-(const gps_time& other) const + { + + gps_time result(sec - other.sec, nanosec - other.nanosec); + while (result.nanosec < 0) { + result.nanosec += 1000000000; + --result.sec; + } + return result; + } + + gps_time operator+(const gps_time& other) const + { + gps_time result(sec + other.sec, nanosec + other.nanosec); + while (result.nanosec >= 1000000000) { + result.nanosec -= 1000000000; + ++result.sec; + } + return result; + } + + bool operator==(const gps_time& other) const + { + return (sec == other.sec && nanosec == other.nanosec); + } + + bool operator!=(const gps_time& other) const + { + return !(*this == other); + } + + bool operator<(const gps_time& other) const + { + if (sec < other.sec) return true; + if (sec > other.sec) return false; + return (nanosec < other.nanosec); + } + }; + + std::ostream& operator<<(std::ostream& os, const gps_time& gps) + { + os << gps.sec << ":" << gps.nanosec; + return os; + } + + + class gps_clock + { + private: + int fd_; + int offset_; + bool ok_; + + static const int SYMMETRICOM_STATUS = 0; + static const int SYMMETRICOM_TIME = 1; + static bool symm_ok(int fd) + { + if (fd < 0) return false; + unsigned long req = 0; + ioctl (fd, gps_clock::SYMMETRICOM_STATUS, &req); + return req != 0; + } + + public: + explicit gps_clock(int offset):fd_(open ("/dev/gpstime", O_RDWR | O_SYNC)), + offset_(offset), + ok_(gps_clock::symm_ok(fd_)) {} + ~gps_clock() + { + if (fd_ >= 0) close(fd_); + } + bool ok() const + { + return ok_; + } + + gps_time now() const + { + gps_time result; + + if (ok_) + { + unsigned long t[3]; + ioctl (fd_, gps_clock::SYMMETRICOM_TIME, &t); + t[1] *= 1000; + t[1] += t[2]; + result.nanosec = t[1]; + result.sec = t[0] + offset_; + } + else + { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + result.sec = ts.tv_sec; + result.nanosec = ts.tv_nsec; + } + return result; + } + }; +} + +#endif //TRANSFER_GPS_H