From 9dc50363f78f47629e5f2153bc8c38cd872c1d1e Mon Sep 17 00:00:00 2001 From: Martin Burnicki Date: Fri, 4 Feb 2011 12:00:00 +0100 Subject: Builds and basically works fine on FreeBSD 8.1 (386 and amd64) --- Makefile | 450 +++ README | 246 ++ mbgclock/Makefile | 48 + mbgclock/mbgdrvr.c | 612 +++++ mbgctrl/Makefile | 45 + mbgctrl/mbgctrl.c | 1855 +++++++++++++ mbgfasttstamp/Makefile | 29 + mbgfasttstamp/mbgfasttstamp.c | 271 ++ mbggpscap/Makefile | 39 + mbggpscap/mbggpscap.c | 391 +++ mbghrtime/Makefile | 39 + mbghrtime/mbghrtime.c | 287 ++ mbgirigcfg/Makefile | 36 + mbgirigcfg/mbgirigcfg.c | 728 +++++ mbglib/bsd/mbg_bsd.h | 49 + mbglib/bsd/pci_bsd.h | 64 + mbglib/bsd/rsrc_bsd.c | 80 + mbglib/bsd/rsrc_bsd.h | 70 + mbglib/common/amccdefs.h | 111 + mbglib/common/cnv_wday.h | 100 + mbglib/common/ctry.c | 177 ++ mbglib/common/ctry.h | 233 ++ mbglib/common/ctrydttm.c | 184 ++ mbglib/common/ctrydttm.h | 74 + mbglib/common/gpsdefs.h | 4413 ++++++++++++++++++++++++++++++ mbglib/common/gpsutils.c | 194 ++ mbglib/common/gpsutils.h | 80 + mbglib/common/identdec.c | 164 ++ mbglib/common/identdec.h | 67 + mbglib/common/macioctl.h | 1817 ++++++++++++ mbglib/common/mbg_arch.h | 159 ++ mbglib/common/mbg_tgt.h | 430 +++ mbglib/common/mbgddmsg.h | 152 ++ mbglib/common/mbgdevio.c | 6071 +++++++++++++++++++++++++++++++++++++++++ mbglib/common/mbgdevio.h | 3108 +++++++++++++++++++++ mbglib/common/mbgerror.h | 156 ++ mbglib/common/mbggenio.h | 173 ++ mbglib/common/mbggeo.h | 297 ++ mbglib/common/mbgioctl.h | 450 +++ mbglib/common/mbgmktm.c | 117 + mbglib/common/mbgmktm.h | 57 + mbglib/common/mbgtime.h | 322 +++ mbglib/common/mbgutil.c | 615 +++++ mbglib/common/mbgutil.h | 180 ++ mbglib/common/myutil.h | 203 ++ mbglib/common/parmgps.c | 242 ++ mbglib/common/parmgps.h | 135 + mbglib/common/parmpcps.c | 115 + mbglib/common/parmpcps.h | 154 ++ mbglib/common/pci.h | 162 ++ mbglib/common/pci_asic.h | 333 +++ mbglib/common/pcidefs.h | 251 ++ mbglib/common/pcpsdefs.h | 1273 +++++++++ mbglib/common/pcpsdev.h | 1657 +++++++++++ mbglib/common/pcpsdrvr.c | 3395 +++++++++++++++++++++++ mbglib/common/pcpsdrvr.h | 1397 ++++++++++ mbglib/common/pcpsirq.h | 212 ++ mbglib/common/pcpslstr.c | 500 ++++ mbglib/common/pcpslstr.h | 1009 +++++++ mbglib/common/pcpsmktm.c | 53 + mbglib/common/pcpsmktm.h | 62 + mbglib/common/pcpsutil.c | 160 ++ mbglib/common/pcpsutil.h | 183 ++ mbglib/common/plxdefs.h | 76 + mbglib/common/qsdefs.h | 46 + mbglib/common/rsrc.h | 89 + mbglib/common/toolutil.c | 401 +++ mbglib/common/toolutil.h | 83 + mbglib/common/usbdefs.h | 110 + mbglib/common/use_pack.h | 39 + mbglib/common/words.h | 335 +++ mbgsetsystime/Makefile | 43 + mbgsetsystime/mbgsetsystime.c | 173 ++ mbgshowsignal/Makefile | 39 + mbgshowsignal/mbgshowsignal.c | 182 ++ mbgstatus/Makefile | 50 + mbgstatus/mbgstatus.c | 808 ++++++ mbgsvcd/Makefile | 31 + mbgsvcd/mbgsvcd.c | 436 +++ mbgxhrtime/Makefile | 33 + mbgxhrtime/mbgxhrtime.c | 334 +++ 81 files changed, 40044 insertions(+) create mode 100755 Makefile create mode 100755 README create mode 100755 mbgclock/Makefile create mode 100755 mbgclock/mbgdrvr.c create mode 100755 mbgctrl/Makefile create mode 100755 mbgctrl/mbgctrl.c create mode 100755 mbgfasttstamp/Makefile create mode 100755 mbgfasttstamp/mbgfasttstamp.c create mode 100755 mbggpscap/Makefile create mode 100755 mbggpscap/mbggpscap.c create mode 100755 mbghrtime/Makefile create mode 100755 mbghrtime/mbghrtime.c create mode 100755 mbgirigcfg/Makefile create mode 100755 mbgirigcfg/mbgirigcfg.c create mode 100755 mbglib/bsd/mbg_bsd.h create mode 100755 mbglib/bsd/pci_bsd.h create mode 100755 mbglib/bsd/rsrc_bsd.c create mode 100755 mbglib/bsd/rsrc_bsd.h create mode 100755 mbglib/common/amccdefs.h create mode 100755 mbglib/common/cnv_wday.h create mode 100755 mbglib/common/ctry.c create mode 100755 mbglib/common/ctry.h create mode 100755 mbglib/common/ctrydttm.c create mode 100755 mbglib/common/ctrydttm.h create mode 100755 mbglib/common/gpsdefs.h create mode 100755 mbglib/common/gpsutils.c create mode 100755 mbglib/common/gpsutils.h create mode 100755 mbglib/common/identdec.c create mode 100755 mbglib/common/identdec.h create mode 100755 mbglib/common/macioctl.h create mode 100755 mbglib/common/mbg_arch.h create mode 100755 mbglib/common/mbg_tgt.h create mode 100755 mbglib/common/mbgddmsg.h create mode 100755 mbglib/common/mbgdevio.c create mode 100755 mbglib/common/mbgdevio.h create mode 100755 mbglib/common/mbgerror.h create mode 100755 mbglib/common/mbggenio.h create mode 100755 mbglib/common/mbggeo.h create mode 100755 mbglib/common/mbgioctl.h create mode 100755 mbglib/common/mbgmktm.c create mode 100755 mbglib/common/mbgmktm.h create mode 100755 mbglib/common/mbgtime.h create mode 100755 mbglib/common/mbgutil.c create mode 100755 mbglib/common/mbgutil.h create mode 100755 mbglib/common/myutil.h create mode 100755 mbglib/common/parmgps.c create mode 100755 mbglib/common/parmgps.h create mode 100755 mbglib/common/parmpcps.c create mode 100755 mbglib/common/parmpcps.h create mode 100755 mbglib/common/pci.h create mode 100755 mbglib/common/pci_asic.h create mode 100755 mbglib/common/pcidefs.h create mode 100755 mbglib/common/pcpsdefs.h create mode 100755 mbglib/common/pcpsdev.h create mode 100755 mbglib/common/pcpsdrvr.c create mode 100755 mbglib/common/pcpsdrvr.h create mode 100755 mbglib/common/pcpsirq.h create mode 100755 mbglib/common/pcpslstr.c create mode 100755 mbglib/common/pcpslstr.h create mode 100755 mbglib/common/pcpsmktm.c create mode 100755 mbglib/common/pcpsmktm.h create mode 100755 mbglib/common/pcpsutil.c create mode 100755 mbglib/common/pcpsutil.h create mode 100755 mbglib/common/plxdefs.h create mode 100755 mbglib/common/qsdefs.h create mode 100755 mbglib/common/rsrc.h create mode 100755 mbglib/common/toolutil.c create mode 100755 mbglib/common/toolutil.h create mode 100755 mbglib/common/usbdefs.h create mode 100755 mbglib/common/use_pack.h create mode 100755 mbglib/common/words.h create mode 100755 mbgsetsystime/Makefile create mode 100755 mbgsetsystime/mbgsetsystime.c create mode 100755 mbgshowsignal/Makefile create mode 100755 mbgshowsignal/mbgshowsignal.c create mode 100755 mbgstatus/Makefile create mode 100755 mbgstatus/mbgstatus.c create mode 100755 mbgsvcd/Makefile create mode 100755 mbgsvcd/mbgsvcd.c create mode 100755 mbgxhrtime/Makefile create mode 100755 mbgxhrtime/mbgxhrtime.c diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..44fc7bb --- /dev/null +++ b/Makefile @@ -0,0 +1,450 @@ + +######################################################################### +# +# $Id: Makefile 1.1.1.4 2011/02/04 10:09:45 martin TEST $ +# +# Description: +# Makefile for mbgtools which recurses into the subdirectories. +# +# ----------------------------------------------------------------------- +# $Log: Makefile $ +# Revision 1.1.1.4 2011/02/04 10:09:45 martin +# Revision 1.1.1.3 2011/02/02 12:33:29 martin +# Revision 1.1.1.2 2011/01/28 09:29:47 martin +# Revision 1.1.1.1 2011/01/27 16:16:40 martin +# Revision 1.1 2011/01/27 15:41:01 martin +# Initial revision +# +######################################################################### + +.ifndef prefix + prefix := /usr/local +.endif + +.ifndef bindir + bindir := $(prefix)/bin +.endif + +.ifndef sbindir + sbindir := $(prefix)/sbin +.endif + +.ifndef sysconfdir + sysconfdir := /etc +.endif + +.ifndef includedir + includedir := $(prefix)/include +.endif + +.ifndef libdir + CUR_ARCH = $(shell uname -m) + find_libdirname := $(shell \ + if [ $(CUR_ARCH) = "ia64" -o $(CUR_ARCH) = "x86_64" ]; then \ + if test -d $(prefix)/lib64; \ + then echo "lib64"; \ + else echo "lib"; \ + fi \ + else \ + if test -d $(prefix)/lib32; \ + then echo "lib32"; \ + else echo "lib"; \ + fi \ + fi \ + ) + libdir := $(prefix)/$(call find_libdirname) +##$(warning $(INFO) libdir set to $(libdir)) +.endif + +INSTALL_PATHS = DESTDIR=$(DESTDIR) prefix=$(prefix) bindir=$(bindir) sbindir=$(sbindir) includedir=$(includedir) libdir=$(libdir) sysconfdir=$(sysconfdir) + +.ifndef SO_BASENAMES + SO_BASENAMES += devio + SO_BASENAMES += util + SO_BASENAMES += serio + SO_BASENAMES += extio +.endif + +.ifndef SO_SUBDIRS +# SO_SUBDIRS += $(foreach dir,$(SO_BASENAMES), libmbg_so/mbg$(dir) ) +## $(warning $(INFO) **************** SO_SUBDIRS set to $(SO_SUBDIRS)) +.endif + +##$(warning $(INFO) SO_SUBDIRS set to $(SO_SUBDIRS)) + +.ifndef BASEDIR + +.DEFAULT_GOAL := all +MAKECMDGOALS ?= $(.DEFAULT_GOAL) + +# This section is used only if this makefile is called by the top-level +# make. It specifies some common targets and some subdirs in which a +# recursive make will be executed, which may include this make file again +# and evaluate the second part. + +INFO=top 1st: +## $(warning $(INFO) reading top level part) + +## export COMMON_MAKEFILE := $(CURDIR)/Makefile +## $(warning $(INFO) COMMON_MAKEFILE set to $(COMMON_MAKEFILE)) + +# The macro function below prints an info string whether a target +# is supported by the kernel Makefile + +.ifndef SUBDIRS + +chk_subdir = $(shell test -f $(strip $(1))/Makefile && echo "$(1)" ) + +.ifndef DONT_BUILD_LIBS + SUBDIRS += $(SO_SUBDIRS) +## $(foreach dir,$(SO_SUBDIRS),$(eval SUBDIRS += $(call chk_subdir, $(dir)))) + SUBDIRS += $(call chk_subdir, "libmbg_so/devel" ) +.endif + +.ifndef DONT_BUILD_TOOLS + SUBDIRS += $(call chk_subdir, "mbgstatus" ) + SUBDIRS += $(call chk_subdir, "mbgsetsystime" ) + SUBDIRS += $(call chk_subdir, "mbgctrl" ) + SUBDIRS += $(call chk_subdir, "mbgirigcfg" ) + SUBDIRS += $(call chk_subdir, "mbgshowsignal" ) + SUBDIRS += $(call chk_subdir, "mbggpscap" ) + SUBDIRS += $(call chk_subdir, "mbghrtime" ) + SUBDIRS += $(call chk_subdir, "mbgfasttstamp" ) + SUBDIRS += $(call chk_subdir, "mbgsvcd" ) + SUBDIRS += $(call chk_subdir, "mbgxhrtime" ) + SUBDIRS += $(call chk_subdir, "test/mbgtestio" ) + SUBDIRS += $(call chk_subdir, "test/mbgtestmmio" ) + SUBDIRS += $(call chk_subdir, "test/mbgtestxhrt" ) + SUBDIRS += $(call chk_subdir, "test/mbgchksystime" ) + SUBDIRS += $(call chk_subdir, "test/mbgtestsettime" ) +.endif + +.ifndef DONT_BUILD_GUI +.ifndef DONT_BUILD_MBGMON + SUBDIRS += $(call chk_subdir, "wxwidgets/mbgmon" ) +.endif +.ifndef DONT_BUILD_MBGSTATSVIEWER + SUBDIRS += $(call chk_subdir, "wxwidgets/mbgstatsviewer" ) +.endif +.endif + +.ifndef DONT_BUILD_DRIVER + SUBDIRS += $(call chk_subdir, "mbgclock" ) + ##SUBDIRS += $(call chk_subdir, "test/mbgclock-test" ) +.endif + +## $(warning $(INFO) SUBDIRS = $(SUBDIRS)) +## $(warning $(INFO) MAKECMDGOALS = $(MAKECMDGOALS)) + +.endif + + +SUBDIRS += mbgstatus +SUBDIRS += mbgsvcd +SUBDIRS += mbgsetsystime +SUBDIRS += mbgctrl +SUBDIRS += mbgirigcfg +SUBDIRS += mbgshowsignal +SUBDIRS += mbggpscap +SUBDIRS += mbghrtime +SUBDIRS += mbgfasttstamp +# SUBDIRS += mbgxhrtime ## not yet tested +SUBDIRS += test/mbgtestio +SUBDIRS += test/mbgtestmmio +SUBDIRS += test/mbgtestxhrt +SUBDIRS += test/mbgchksystime +SUBDIRS += mbgclock + +.PHONY: all clean distclean install uninstall +all clean distclean install uninstall: + @for dir in $(SUBDIRS); do \ + if test -f $$dir/Makefile; then \ + $(MAKE) -C $$dir $@ || exit 1; \ + fi \ + done + +.PHONY: dev dev-nodes dev-clean suse_symvers probe ins rm test reload check \ + refclocks kernel_config +dev dev-nodes dev-clean suse_symvers probe ins rm test reload check \ + refclocks kernel_config: + @cd mbgclock && make $@ + +.PHONY: cleanreload +cleanreload: clean all install reload + +.else # ================================================================ + +# This section is evaluated only if this makefile is included from +# a subproject's makefile. + + +.ifndef MBGLIB + MBGLIB := $(BASEDIR)/mbglib +.endif + +MBGLIB_DIRS += common linux + +# Macros useful to run individual commands as root: +.ifndef CALLED_FROM_SPEC +.ifndef SUDO + SUDO := $(shell which sudo) +.endif + +.ifndef SU + SU := $(shell which su) +.endif + + UID = $(shell id -u) +.else + #fake running as root + UID = 0 +.endif + +run_as_root = $(shell echo "$(SUDO) $(1) || $(SU) -c \"$(1)\"" ) +make_as_root = $(call run_as_root, make $(1)) + +.ifndef MODULE_OBJS #=========================================================== + +# not building a kernel module + +CFLAGS += -Wall +## CFLAGS += -W + +.ifdef DEBUG + CFLAGS += -DDEBUG=$(DEBUG) + CFLAGS += -g +.else + CFLAGS += -O2 +.endif + +CFLAGS += -I. +CFLAGS += $(foreach dir,$(MBGLIB_DIRS),-I$(MBGLIB)/$(dir)) +######### +CFLAGS += -I$(BASEDIR)/mbglib/common +CFLAGS += -I$(BASEDIR)/mbglib/bsd + + +# Use all CFLAGS defined above also for C++ files. +CXXFLAGS += $(CFLAGS) + +# Additional C++-only compiler flags. +## CXXFLAGS += -Wno-deprecated + + +LDFLAGS += $(foreach dir,$(SO_SUBDIRS),-L $(BASEDIR)/$(dir) ) + + +SO_MAJOR_VERSION = 1 +SO_MINOR_VERSION = 0 + +.ifdef SO_TARGET_BASENAME +.ifndef SO_POINT_RELEASE + SO_POINT_RELEASE = 0 +.endif + + SO_TARGET_NAME = libmbg$(SO_TARGET_BASENAME) + SO_TARGET_LIBNAME = $(SO_TARGET_NAME).so + SO_TARGET_SONAME = $(SO_TARGET_LIBNAME).$(SO_MAJOR_VERSION) + TARGET = $(SO_TARGET_SONAME).$(SO_MINOR_VERSION).$(SO_POINT_RELEASE) + + OBJS += mbg$(SO_TARGET_BASENAME).o + + CLEAN_FILES += $(SO_TARGET_LIBNAME) + + CFLAGS += -fPIC + CFLAGS += -c + + LDFLAGS += -shared + LDFLAGS += -lc + LDFLAGS += -Wl,-soname,$(SO_TARGET_SONAME) + +.ifndef LIBDIR + LIBDIR := $(shell if [ -d /usr/lib64 ]; then echo /usr/lib64; else echo /usr/lib; fi ) +.endif +.endif + + + +.PHONY: all +all: $(TARGET) + +#### VPATH += $(foreach dir,$(MBGLIB_DIRS),$(MBGLIB)/$(dir)) +VPATH = $(BASEDIR)/mbglib/common:$(BASEDIR)/mbglib/bsd + +.ifndef MBGDEVIO_SIMPLE + MBGDEVIO_SIMPLE = 1 +.endif + +.ifdef MBGDEVIO_SIMPLE + CFLAGS += -DMBGDEVIO_SIMPLE=$(MBGDEVIO_SIMPLE) +.endif + + +.ifdef USE_THREAD_API + + # Check whether thread affinity is supported by the installed pthread library. + # Newer versions of glibc/pthread (at least glibc 2.5) supports this natively. + # Older versions of glibc/pthread (e.g. glibc 2.3) may not support this natively + # but may provide a NPTL (New Posix Thread Library) library located under separate + # include and lib paths. We try to detect NPTL and add those paths to the search + # paths only if USE_NTPL has been defined e.g. on the make command line. + + # Check whether pthread_getaffinity is supported by the standard pthread.h + USE_THREAD_AFFINITY := $(shell grep -q pthread_getaffinity /usr/include/pthread.h && echo 1) + + # If it is not, check nptl/pthread.h +.ifndef USE_THREAD_AFFINITY +.ifdef USE_NPTL + USE_THREAD_AFFINITY := $(shell grep -q pthread_getaffinity /usr/include/nptl/pthread.h && echo 1) +.endif + +.ifndef USE_THREAD_AFFINITY + ##++++ If not found either, don't support thread affinity + USE_THREAD_AFFINITY=0 +.else + #if supported via nptl add the associated search paths + CFLAGS += -I /usr/include/nptl -L /usr/lib/nptl +.endif +.endif + + # May want to use the result for our program + ## CFLAGS += -DUSE_THREAD_AFFINITY=$(USE_THREAD_AFFINITY) + + CFLAGS += -DMBGDEVIO_USE_THREAD_API=1 + + #LDFLAGS += -lpthread + LDFLAGS += -pthread +.endif + +.ifdef INST_TO_BIN + INST_DIR = $(DESTDIR)$(bindir) +.else +.ifdef INST_TO_SBIN + INST_DIR = $(DESTDIR)$(sbindir) +.else +.ifdef INST_TO_LIB + INST_DIR = $(DESTDIR)$(libdir) +.else +.ifdef INST_TO_INCLUDE + INST_DIR = $(DESTDIR)$(includedir)/mbglib +.endif +.endif +.endif +.endif + +.ifdef DO_GUI_INSTALLATION + EXT_INSTALL += gui_install + EXT_UNINSTALL += gui_uninstall +.endif + + +## $(warning $(INFO) CFLAGS=$(CFLAGS)) +## $(warning $(INFO) EXTRA_CFLAGS=$(EXTRA_CFLAGS)) +## $(warning $(INFO) MAKECMDGOALS = $(MAKECMDGOALS)) + +$(TARGET): $(OBJS) + $(CC) -o $@ $(OBJS) $(LDFLAGS) +.ifdef SO_TARGET_LIBNAME + ln -sf $(TARGET) $(SO_TARGET_LIBNAME) +.endif + +.PHONY: install +install: $(EXT_INSTALL) +.ifdef XXX #.ifneq ($(UID),0) + $(call make_as_root, $@) +.else +.ifdef INCLUDE_FILES #include files + mkdir -p $(INST_DIR) + for incfile in $(INCLUDE_FILES); do \ + install -m 644 $(BASEDIR)/mbglib/common/$$incfile $(INST_DIR)/; \ + done; + for basename in $(SO_BASENAMES); do \ + pushd $(DESTDIR)$(libdir); \ + ln -sf libmbg$$basename.so.$(SO_MAJOR_VERSION) libmbg$$basename.so; \ + popd; \ + done; +.else #usual installation +.ifdef CALLED_FROM_SPEC + mkdir -p $(INST_DIR) +.endif + install -s $(TARGET) $(INST_DIR) + +.ifndef CALLED_FROM_SPEC +.ifdef INST_TO_LIB + /sbin/ldconfig +.endif +.endif +.endif +.endif + + +.PHONY: uninstall +uninstall: $(EXT_UNINSTALL) +.ifdef INCLUDE_FILES #remove include files and + rm -rf $(INST_DIR) +.ifndef CALLED_FROM_SPEC #remove symbolic links + for basename in $(SO_BASENAMES); do \ + rm -f $(libdir)/libmbg$$basename.so; \ + done; +.endif +.else +.ifdef XXX #.ifneq ($(UID),0) + $(call make_as_root, $@) +.else + rm -f $(INST_DIR)/$(TARGET) +.ifndef CALLED_FROM_SPEC +.ifdef INST_TO_LIB + /sbin/ldconfig +.endif +.endif +.endif +.endif + +.PHONY: gui_install +gui_install: +.ifdef XXX #.ifneq ($(UID),0) + $(call make_as_root, $@) +.else + mkdir -p $(DESTDIR)$(prefix)/share/$(TARGET) + cp $(TARGET).png $(DESTDIR)$(prefix)/share/$(TARGET)/$(TARGET).png + mkdir -p $(DESTDIR)$(prefix)/share/applications + cp $(TARGET).desktop $(DESTDIR)$(prefix)/share/applications/$(TARGET).desktop +.endif + +.PHONY: gui_uninstall +gui_uninstall: +.ifdef XXX #.ifneq ($(UID),0) + $(call make_as_root, $@) +.else + rm -rf $(DESTDIR)$(prefix)/share/$(TARGET) + rm -f $(DESTDIR)$(prefix)/share/applications/$(TARGET).desktop +.endif + +CLEAN_FILES += *.o +CLEAN_FILES += *~ +CLEAN_FILES += core +CLEAN_FILES += $(TARGET) + +.PHONY: clean +clean: +.ifdef CLEAN_FILES + rm -f $(CLEAN_FILES) +.endif +.ifdef CLEAN_DIRS + rm -rf $(CLEAN_DIRS) +.endif + + +.else +# ===== Building module for kernel 2.6 ============================================= + +.endif # building kernel module +#================================================================================== + + +# common targets: + +.PHONY: distclean +distclean: clean + +.endif diff --git a/README b/README new file mode 100755 index 0000000..dc67692 --- /dev/null +++ b/README @@ -0,0 +1,246 @@ +$Id: README 1.1 2011/02/04 14:44:01 martin TEST $ + +This is the README file for mbgtools-fbsd-dev-2011-02-04 +-------------------------------------------------------- + + +Please send comments and required modifications to +Meinberg support + + +Contents +-------- + 1. Notes and description + 2. Driver files and programs + 3. Installation + 3.1 Unpacking the sources + 3.2 Compiling the driver + 3.3 Installing the driver + 3.4 Loading the kernel module + 4. Using the driver with NTP + + +1. Notes and description +------------------------ +This driver package has been implemented for FreeBSD 8.1 +on standard PCs (i386 architecture) and on Intel/AMD 64 bit +systems (amd64 architecture). + +Unless the BSD kernel API calls have changed the driver should +also work properly under earlier versions of FreeBSD. However, +other target platforms than i386 and amd64 are not yet supported. + +The driver supports all PCI cards manufactured by Meinberg which +have been shipped up to the release date of this driver version. + +This version of the driver package should compile fine +under FreeBSD 8.1 for kernels 2.6.x, . + + + +2. Driver files and programs +---------------------------- +mbgtools for Linux is based on Meinberg's common driver library mbglib +and implements the following programs each of which can be found in +its own subdirectory: + +mbgclock.ko + A kernel module which implements the device driver. + +mbgstatus + This program prints some status information for a device. The + kind of information to be printed depends on the specific type + of the card. + +mbgsvcd + This program periodically calls the kernel driver to retrieve + time stamps of both the system time and the PCI card as close + as possible after each other, and feeds the time stamp pairs + into a shared memory segment compatible with the NTP daemon ntpd. + This enables ntpd to use up to 4 PCI card(s) as refererence time + source, if configured accordingly. + + Usually the program runs as daemon, but using the -f parameter + it can also run in the foreground where it also prints the time + stamps and the time differences between the system time and the + PCI card's time on the console. + + This mode can be used to monitor how accurately the system time + is actually disciplined, even if the system time is disciplined + by some other means. + +mbgctrl + This program can be used to do some basic configuration of a card. + Run mbgctrl -? to get a list of valid options. + +mbgirigcfg + This program can be used to check and configure IRIG settings of + cards which provide an IRIG input or output. + Type "mbgirigcfg -h" for help. + +mbgsetsystime + This program reads the time from a device and sets the system time. + If NTP is used on a system which has an unreliable clock, this + program can be used to set the system time initially (before the + NTP daemon starts). The program should not be run if NTP is active + and controls the system time since NTP achieves a higher accuracy. + +mbgdcfmod + This program displays the modulation (i.e. the second marks) of a + received longwave signal, e.g. from DCF77. + +mbggpscap + This example program reads time capture events from a card's time + capture buffer. This works only with cards which provide time capture + inputs, and the DIP switches on those cards must be set up properly + to enable time capturing. + +mbghrtime + This example program checks whether a card supports high-resolution + time and reads those time stamps from the device, if supported. + +mbgfasttstamp + This examle program demonstrates how to read high resolution time stamps + from a card very much faster than mbghrtime. However, this works only + with cards which support memory mapped I/O. + As of this writing this applies to the GPS170PEX only. + +mbgxhrtime + This example program also shows how to get time stamps faster than + shown in mbghrtime. This is not as easy as mbgfasttstamp but can be + used with every card which can be used with mbghrtime, even if the + card does not support memory mapped I/O. + The program starts a polling thread which reads a high resolution + time stamp from the card once per second, and then uses the CPU's + time stamp counter to extrapolate the time. + A limitation of this approach is that the CPU's time stamp counters + may return different values on different CPUs. So the program + takes care to have the code executed always on the same CPU. Also, + power saving mechanisms (Intel Speedstep, or AMD Cool'n'Quiet) + should be disabled to prevent the extrapolated times from being + messed up. + + + +3. Installation +--------------- + +3.1 Unpacking the sources +------------------------- +Unpack the archive file using the command + + tar xvzf mbgtools-fbsd*.tar.gz + +After the archive file has been unpacked cd to the base directory +that has been created corresponding to the name and version of +the package. + + + +3.2 Compiling the driver +------------------------ +If the driver package has already been built before then + + make clean + +should be run first to remove old object files and binaries. + +Make sure your working directory is the driver base directory and +simply type + + make + +to compile the utility programs first, then the kernel module. +If *any* error or warning messages are displayed then please +report to Meinberg. + + + +3.3 Installing the driver +------------------------- +Installation must be done as user root. Type + + make install + +to copy the compiled binaries to their target directories. Programs +which only read the clock to display some information are copied to +/usr/local/bin, whereas programs which may change the device +configuration, or set the system time, are copied to /usr/local/sbin. + + + +3.4 Loading the kernel module +----------------------------- +After the binaries have been installed the module can be loaded +for the first time. The command syntax is: + + kldload mbgclock + +When the module is loaded some some startup messages are generated which +can be checked in the syslog, or using the dmesg command. If the module +was loaded successfully it should be listed if you type + + kldstat + +You may try to display the device status by entering + + mbgstatus + +The output shows some information on the device status, +depending on the type of the clock. + +Once the module has been loaded, the other utility programs can be +used accordingly. + + + +4. Using the driver with NTP +---------------------------- +The NTP daemon can be configured to use up to 4 Meinberg PCI cards +as reference time source to discipline the system time. In order to +achieve this, ntpd needs to be configured to use its shared memory +driver (SHM, type 28). + +The following entries needd to be made in the ntp.conf file +to enable support for 4 PCI cards: + + server 127.127.28.0 minpoll 4 maxpoll 4 iburst + fudge 127.127.28.0 refid SHM0 + + server 127.127.28.1 minpoll 4 maxpoll 4 iburst + fudge 127.127.28.1 refid SHM1 + + server 127.127.28.2 minpoll 4 maxpoll 4 iburst + fudge 127.127.28.2 refid SHM2 + + server 127.127.28.3 minpoll 4 maxpoll 4 iburst + fudge 127.127.28.3 refid SHM3 + +Of course, only the first entry is required if only a single PCI card +is installed. + +Please keep in mind the mbgsvcd program also needs to be running to feed +time stamp pairs of the system time and the PCI card's time into the +shared memory segment(s). + +If the NTP daemon is already running restart it and check the syslog file +for messages generated by the daemon. + +The NTP daemon shipped with a FreeBSD may have been compiled without +support for the SHM driver. If this is the case you will find a message +in the syslog saying the daemon is unable to handle 127.127.28.. +In this case you need to recompile the NTP package with support +for the SHM driver. + +Simply download the NTP source packge of your choice from +http://support.ntp.org + +Then unpack the sources and compile the package with the usual instructions: + +./configure +make +make install + +By default this installs the NTP binaries under /usr/local rather than /usr/sbin, +so be sure the right instance of ntpd is started on reboot or when you run the +"service ntpd start" command. diff --git a/mbgclock/Makefile b/mbgclock/Makefile new file mode 100755 index 0000000..2cb9258 --- /dev/null +++ b/mbgclock/Makefile @@ -0,0 +1,48 @@ + +######################################################################### +# +# $Id: Makefile 1.1.1.4 2011/02/03 14:10:39 martin TEST $ +# +# Description: +# Makefile for mbgclock driver to support Meinberg bus level +# devices under FreeBSD. +# +# ----------------------------------------------------------------------- +# $Log: Makefile $ +# Revision 1.1.1.4 2011/02/03 14:10:39 martin +# Revision 1.1.1.3 2011/01/26 17:38:58 martin +# Add support for DEBUG build. +# Revision 1.1.1.2 2011/01/26 16:36:37 martin +# Enabled all required source files. +# Revision 1.1.1.1 2011/01/26 14:12:02 martin +# Started modifications to build mbgclock. +# Revision 1.1 2011/01/26 13:56:32 martin +# Initial skeleton based on FreeBSD's mypci.c sample program by Murray Stokely. +# +######################################################################### + +KMOD= mbgclock + +MBGLIB= ../mbglib +MBGLIB_COMMON= $(MBGLIB)/common +MBGLIB_BSD= $(MBGLIB)/bsd + +.PATH: $(MBGLIB_COMMON) $(MBGLIB_BSD) + +CFLAGS= -I$(MBGLIB_COMMON) -I$(MBGLIB_BSD) + +.ifdef DEBUG +CFLAGS+= -D DEBUG=$(DEBUG) +.endif + +SRCS= mbgdrvr.c +SRCS+= pcpsdrvr.c +SRCS+= identdec.c +SRCS+= rsrc_bsd.c +SRCS+= device_if.h bus_if.h pci_if.h + +CLEANFILES= *~ +CLEANFILES+= machine +CLEANFILES+= @ + +.include diff --git a/mbgclock/mbgdrvr.c b/mbgclock/mbgdrvr.c new file mode 100755 index 0000000..7a8a9ac --- /dev/null +++ b/mbgclock/mbgdrvr.c @@ -0,0 +1,612 @@ + +/************************************************************************** + * + * $Id: mbgdrvr.c 1.1.1.11 2011/02/04 14:44:19 martin TEST $ + * + * Description: + * Main file for for mbgclock driver to support Meinberg bus level + * devices under FreeBSD. + * + * The binary is a loadable module called mbgclock which implements + * /dev/mbgclock* devices. + * + * Based on FreeBSD's mypci.c sample program by Murray Stokely. + * + * ----------------------------------------------------------------------- + * $Log: mbgdrvr.c $ + * Revision 1.1.1.11 2011/02/04 14:44:19 martin + * Revision 1.1.1.10 2011/02/02 12:33:52 martin + * Revision 1.1.1.9 2011/02/01 17:11:38 martin + * Revision 1.1.1.8 2011/02/01 14:49:42 martin + * Revision 1.1.1.7 2011/02/01 12:12:17 martin + * Revision 1.1.1.6 2011/01/31 17:28:56 martin + * Modified resource handling. + * Revision 1.1.1.5 2011/01/28 09:31:21 martin + * Fixed debug/non-debug build. + * Revision 1.1.1.4 2011/01/27 15:15:23 martin + * Loads and unloads properly. Calls pcps_start_device() which + * properly reads some data from a card. + * Revision 1.1.1.3 2011/01/26 16:37:18 martin + * Ioctl support compiled in. + * Revision 1.1.1.2 2011/01/26 15:05:53 martin + * Revision 1.1.1.1 2011/01/26 14:34:33 martin + * Started modifications to build mbgclock. + * Revision 1.1 2011/01/26 13:56:32 martin + * Initial skeleton based on FreeBSD's mypci.c sample program by Murray Stokely. + * + **************************************************************************/ + +#include +#include + +#include /* defines used in kernel.h */ +#include +#include +#include +#include /* types used in module initialization */ +#include /* cdevsw struct */ +#include /* uio struct */ +#include +#include /* structs, prototypes for pci bus stuff */ +#include + +#include /* For pci_get macros! */ +#include + + + +#if 1 //##++ move this elsewhere! + +#define REV_NUM 0x100 +#define REV_NUM_STR "1.00" + +#define MBG_COPYRIGHT "(c) Meinberg 2011" + +#define MBG_DRVR_NAME "mbgclock" +#define MBGCLK_NAME "mbgclk" +#define MBGNTP_NAME "mbgntp" + +const char pcps_driver_name[] = MBG_DRVR_NAME; + +static MBG_DBG_DATA mbg_dbg_data; +static MBG_DBG_PORT mbg_dbg_port = 0x378 + 0; //##++ +static PCPS_IO_ADDR_MAPPED mbg_dbg_port_mapped; //##++ + +static PCPS_DRVR_INFO drvr_info = { REV_NUM, 0, MBG_DRVR_NAME " radio clock driver" }; + +#if defined( DEBUG ) +int debug = DEBUG; +#endif + +MALLOC_DEFINE( M_MBGCLOCK, "short desc", "long desc" ); + +#include + +#endif + + + +/* The softc holds our per-instance data. */ +struct mbgclock_softc +{ + device_t device; + struct cdev *cdev; + PCPS_DDEV *pddev; +}; + + +/* Function prototypes */ +static d_open_t mbgclock_open; +static d_close_t mbgclock_close; +static d_read_t mbgclock_read; +static d_write_t mbgclock_write; +static d_ioctl_t mbgclock_ioctl; + + +/* Character device entry points */ + +static struct cdevsw mbgclock_cdevsw = +{ + .d_version = D_VERSION, + .d_open = mbgclock_open, + .d_close = mbgclock_close, + .d_read = mbgclock_read, + .d_write = mbgclock_write, + .d_ioctl = mbgclock_ioctl, + .d_name = "mbgclock" +}; + + + +static __mbg_inline +void set_dev_connected( PCPS_DDEV *pddev, int state ) +{ + _mbgddmsg_4( MBG_DBG_DETAIL, "%s: setting dev %s_%s connected state to %i", + pcps_driver_name, _pcps_ddev_type_name( pddev ), _pcps_ddev_sernum( pddev ), + state ); + atomic_store_rel_int( &pddev->connected, state ); + +} // set_dev_connected + + + +/* + * In the cdevsw routines, we find our softc by using the si_drv1 member + * of struct cdev. We set this variable to point to our softc in our + * attach routine when we create the /dev entry. + */ +int +mbgclock_open( struct cdev *dev, int oflags, int devtype, d_thread_t *td ) +{ + struct mbgclock_softc *psc = dev->si_drv1; + PCPS_DDEV *pddev = psc->pddev; + + _mbgddmsg_3( MBG_DBG_INFO, "%s: dev %s_%s opened successfully.", pcps_driver_name, + _pcps_ddev_type_name( pddev ), _pcps_ddev_sernum( pddev ) ); + + atomic_add_int( &pddev->open_count, 1 ); + + return 0; + +} // mbgclock_open + + + +int +mbgclock_close( struct cdev *dev, int fflag, int devtype, d_thread_t *td ) +{ + struct mbgclock_softc *psc = dev->si_drv1; + PCPS_DDEV *pddev = psc->pddev; + + atomic_subtract_int( &pddev->open_count, 1 ); + + _mbgddmsg_3( MBG_DBG_INFO, "%s: dev %s_%s closed.", pcps_driver_name, + _pcps_ddev_type_name( pddev ), _pcps_ddev_sernum( pddev ) ); + + return 0; + +} // mbgclock_close + + + +int +mbgclock_read( struct cdev *dev, struct uio *uio, int ioflag ) +{ + #if defined( DEBUG ) + struct mbgclock_softc *psc = dev->si_drv1; + PCPS_DDEV *pddev = psc->pddev; + + _mbgddmsg_4( MBG_DBG_INFO, "%s: dev %s_%s asked to read %li bytes", + pcps_driver_name, _pcps_ddev_type_name( pddev ), + _pcps_ddev_sernum( pddev ), (long) uio->uio_resid ); + #endif + + return 0; + +} // mbgclock_read + + + +int +mbgclock_write( struct cdev *dev, struct uio *uio, int ioflag ) +{ + #if defined( DEBUG ) + struct mbgclock_softc *psc = dev->si_drv1; + PCPS_DDEV *pddev = psc->pddev; + + _mbgddmsg_4( MBG_DBG_INFO, "%s: dev %s_%s asked to write %li bytes", + pcps_driver_name, _pcps_ddev_type_name( pddev ), + _pcps_ddev_sernum( pddev ), (long) uio->uio_resid ); + #endif + + return 0; + +} // mbgclock_write + + + +int +mbgclock_ioctl( struct cdev *dev, u_long cmd, caddr_t data, + int32_t flag, struct thread *td ) +{ + struct mbgclock_softc *psc = dev->si_drv1; + PCPS_DDEV *pddev = psc->pddev; + int rc; + + rc = ioctl_switch( pddev, cmd, (void *) data, (void *) data ); + + // On success we return quickly. + + if ( rc == MBG_SUCCESS ) + { + _mbgddmsg_5( MBG_DBG_INFO, "%s: %p IOCTL 0x%02lX: success, dev %s_%s", + pcps_driver_name, dev, cmd, _pcps_ddev_type_name( pddev ), _pcps_ddev_sernum( pddev ) ); + goto out; + } + + + // An error has occurred. + // Generate an appropriate debug/error message + // and return an error status. + + switch ( rc ) + { + case MBG_ERR_INV_DEV_REQUEST: + _mbgddmsg_6( MBG_DBG_WARN, "%s: %p ioctl 0x%02lX: invalid cmd %04lX, dev %s_%s", + pcps_driver_name, dev, cmd, IOCBASECMD( cmd ), + _pcps_ddev_type_name( pddev ), _pcps_ddev_sernum( pddev ) ); + rc = -EINVAL; + break; + + + case MBG_ERR_NOT_SUPP_BY_DEV: + _mbgddmsg_5( MBG_DBG_WARN, "%s: %p ioctl 0x%02lX: not supported by dev %s_%s", + pcps_driver_name, dev, cmd, _pcps_ddev_type_name( pddev ), _pcps_ddev_sernum( pddev ) ); + rc = -EIO; + break; + + + case MBG_ERR_NO_MEM: + _mbgddmsg_5( MBG_DBG_WARN, "%s: %p ioctl 0x%02lX: unable to allocate buffer for dev %s_%s", + pcps_driver_name, dev, cmd, _pcps_ddev_type_name( pddev ), _pcps_ddev_sernum( pddev ) ); + rc = -EFAULT; + break; + + + case MBG_ERR_IRQ_UNSAFE: + _mbgddmsg_5( MBG_DBG_DETAIL, "%s: %p ioctl 0x%02lX: busy since unsafe IRQ enabled, dev %s_%s", + pcps_driver_name, dev, cmd, _pcps_ddev_type_name( pddev ), _pcps_ddev_sernum( pddev ) ); + rc = -EBUSY; + break; + + + default: // any access error code returned by the low level routine + // or copying from or to user space + _mbgddmsg_6( MBG_DBG_WARN, "%s: %p ioctl 0x%02lX: error %i accessing dev %s_%s", + pcps_driver_name, dev, cmd, rc, _pcps_ddev_type_name( pddev ), _pcps_ddev_sernum( pddev ) ); + rc = -EFAULT; + + } // switch error rc + + +out: + return rc; + +} // mbgclock_ioctl + + + +/* PCI Support Functions */ + +static void +mbg_deallocate_resource( device_t device, BSD_RSRC_INFO *p_ri, int type ) +{ + if ( p_ri->res ) + { + bus_deactivate_resource( device, type, + p_ri->rid, p_ri->res ); + bus_release_resource( device, type, + p_ri->rid, p_ri->res ); + p_ri->res = NULL; + } + +} // mbg_deallocate_resource + + + +/* + * deallocate resources + */ +static void +mbg_dealloc_rsrcs( device_t device ) +{ + struct mbgclock_softc *psc = device_get_softc( device ); + PCPS_DDEV *pddev = psc->pddev; + PCPS_RSRC_INFO *prsrci = &pddev->rsrc_info; + int i; + +// mbg_deallocate_resource( device, &prsrci->irq.bsd, SYS_RES_IRQ ); + + for ( i = 0; i < N_PCPS_MEM_RSRC; i++ ) + mbg_deallocate_resource( device, &prsrci->mem[i].bsd, SYS_RES_MEMORY ); + + for ( i = 0; i < N_PCPS_PORT_RSRC; i++ ) + mbg_deallocate_resource( device, &prsrci->port[i].bsd, SYS_RES_IOPORT ); + +} // mbg_dealloc_rsrcs + + + +static void +mbg_alloc_rsrc( device_t device, int rid, BSD_RSRC_INFO *p_ri, int type, int flags ) +{ + p_ri->rid = rid; + + p_ri->res = bus_alloc_resource_any( device, type, &p_ri->rid, flags ); + + if ( p_ri->res ) + { + p_ri->bst = rman_get_bustag( p_ri->res ); + p_ri->bsh = rman_get_bushandle( p_ri->res ); + } + +} // mbg_alloc_rsrc + + + +static void +mbg_alloc_rsrcs( device_t device ) +{ + struct mbgclock_softc *psc = device_get_softc( device ); + PCPS_DDEV *pddev = psc->pddev; + PCPS_RSRC_INFO *prsrci = &pddev->rsrc_info; + BSD_RSRC_INFO ri; + int bar; + +// _mbgddmsg_3( MBG_DBG_INIT_DEV, "%s: alloc I/O range %i: PCI device 0x%04X:0x%04X supported", +// pcps_driver_name, vend_id, dev_id ); + + for ( bar = 0; bar < 5; bar ++ ) + { + int rid = PCIR_BAR( bar ); + + if ( prsrci->num_rsrc_io < N_PCPS_PORT_RSRC ) + { + mbg_alloc_rsrc( device, rid, &ri, SYS_RES_IOPORT, RF_ACTIVE ); + + if ( ri.res ) + { + prsrci->port[prsrci->num_rsrc_io].bsd = ri; + pcps_add_rsrc_io( pddev, rman_get_start( ri.res ), rman_get_size( ri.res ) ); + continue; + } + } + + if ( prsrci->num_rsrc_mem < N_PCPS_MEM_RSRC ) + { + mbg_alloc_rsrc( device, rid, &ri, SYS_RES_MEMORY, RF_ACTIVE ); + + if ( ri.res ) + { + prsrci->mem[prsrci->num_rsrc_mem].bsd = ri; + pcps_add_rsrc_mem( pddev, rman_get_start( ri.res ), rman_get_size( ri.res ) ); + continue; + } + } + } + + + // single IRQ resource +#if 0 + mbg_alloc_rsrc( device, 0, &ri, SYS_RES_IRQ, RF_SHAREABLE | RF_ACTIVE ); + + if ( ri.res ) + { + prsrci->port[prsrci->num_rsrc_irq].bsd = ri; + pcps_add_rsrc_irq( pddev, rman_get_start( ri.res ) ); + } +#endif + +} // mbg_alloc_rsrcs + + + +/* + * Probe: compare the device ID of this device against the IDs that this driver + * supports. If there is a match, set the description and return success. + */ +static int +mbgclock_probe( device_t device ) +{ + uint16_t vend_id = pci_get_vendor( device ); + uint16_t dev_id = pci_get_device( device ); + PCPS_DEV_TYPE *pdt; + + + if ( vend_id != PCI_VENDOR_MEINBERG ) + goto fail; + + pdt = pcps_get_dev_type( PCPS_BUS_PCI, dev_id ); + + if ( pdt == NULL ) + goto fail; + + device_set_desc( device, pdt->name ); + + _mbgddmsg_3( MBG_DBG_INIT_DEV, "%s: probe: PCI device 0x%04X:0x%04X supported", + pcps_driver_name, vend_id, dev_id ); + + return BUS_PROBE_DEFAULT; + + +fail: + _mbgddmsg_3( MBG_DBG_INIT_DEV, "%s: probe: PCI device 0x%04X:0x%04X not supported", + pcps_driver_name, vend_id, dev_id ); + return ENXIO; + +} // mbgclock_probe + + + +/* + * Attach function is only called if the probe is successful. + */ +static int +mbgclock_attach( device_t device ) +{ + uint16_t dev_id = pci_get_device( device ); + struct mbgclock_softc *psc = device_get_softc( device ); + int rc; + + _mbgddmsg_2( MBG_DBG_INIT_DEV, "%s: attach for device 0x%04X", + pcps_driver_name, dev_id ); + + psc->pddev = pcps_alloc_ddev(); + + if ( psc->pddev == NULL ) + { + _mbgddmsg_2( MBG_DBG_INIT_DEV, "%s: attach device 0x%04X: pcps_alloc_ddev() failed", + pcps_driver_name, dev_id ); + rc = ENOMEM; + goto fail; + } + + + rc = pcps_init_ddev( psc->pddev, PCPS_BUS_PCI, dev_id ); + + if ( rc != PCPS_SUCCESS ) + { + _mbgddmsg_3( MBG_DBG_INIT_DEV, "%s: attach device 0x%04X: pcps_init_ddev() failed, rc: %i", + pcps_driver_name, dev_id, rc ); + rc = ENXIO; + goto fail; + } + + + //##++++++ rc = pci_enable_device( dev ); + + + mbg_alloc_rsrcs( device ); + + //##++++++ rc = pcps_start_device( pddev, device->bus->number, device->devfn ); + rc = pcps_start_device( psc->pddev, 0, 0 ); + + if ( rc != PCPS_SUCCESS ) + { + _mbgddmsg_3( MBG_DBG_INIT_DEV, "%s: attach device 0x%04X: pcps_start_device() failed, rc: %i", + pcps_driver_name, dev_id, rc ); + rc = ENXIO; + goto fail; + } + + + set_dev_connected( psc->pddev, 1 ); + + /* Initialize our softc. */ + psc->device = device; + /* + * Create a /dev entry for this device. The kernel will assign us + * a major number automatically. We use the unit number of this + * device as the minor number and name the character device + * "mbgclock". + */ + psc->cdev = make_dev( &mbgclock_cdevsw, device_get_unit( device ), + UID_ROOT, GID_WHEEL, 0600, "mbgclock%u", device_get_unit( device ) ); + + psc->cdev->si_drv1 = psc; + + _mbgddmsg_2( MBG_DBG_INIT_DEV, "%s: device 0x%04X attached successfully", + pcps_driver_name, dev_id ); + + return 0; + + +fail: + mbg_dealloc_rsrcs( device ); + + if ( psc->pddev ) + pcps_free_ddev( psc->pddev ); + + _mbgddmsg_2( MBG_DBG_INIT_DEV, "%s: failed to attach device 0x%04X", + pcps_driver_name, dev_id ); + return rc; + +} // mbgclock_attach + + + +/* + * Detach device. + */ +static int +mbgclock_detach( device_t device ) +{ + #if defined( DEBUG ) + uint16_t dev_id = pci_get_device( device ); + #endif + struct mbgclock_softc *psc; + PCPS_DDEV *pddev; + + _mbgddmsg_2( MBG_DBG_INIT_DEV, "%s: detach for device 0x%04X", + pcps_driver_name, dev_id ); + + /* Teardown the state in our softc created in our attach routine. */ + psc = device_get_softc( device ); + pddev = psc->pddev; + + set_dev_connected( pddev, 0 ); + +// pcps_free_ddev( pddev ); //##++++++ should wait for outstanding requests + + mbg_dealloc_rsrcs( device ); + + destroy_dev( psc->cdev ); + + _mbgddmsg_2( MBG_DBG_INIT_DEV, "%s: device 0x%04X detached", + pcps_driver_name, dev_id ); + + return 0; + +} // mbgclock_detach + + + +/* + * Called during system shutdown after sync. + */ +static int +mbgclock_shutdown( device_t device ) +{ + printf( "mbgclock shutdown!\n" ); + + return 0; + +} // mbgclock_shutdown + + + +/* + * Device suspend routine. + */ +static int +mbgclock_suspend( device_t device ) +{ + printf( "mbgclock suspend!\n" ); + + return 0; + +} // mbgclock_suspend + + + +/* + * Device resume routine. + */ +static int +mbgclock_resume( device_t device ) +{ + printf( "mbgclock resume!\n" ); + + return 0; + +} // mbgclock_resume + + + +static device_method_t mbgclock_methods[] = +{ + /* Device interface */ + DEVMETHOD( device_probe, mbgclock_probe ), + DEVMETHOD( device_attach, mbgclock_attach ), + DEVMETHOD( device_detach, mbgclock_detach ), + DEVMETHOD( device_shutdown, mbgclock_shutdown ), + DEVMETHOD( device_suspend, mbgclock_suspend ), + DEVMETHOD( device_resume, mbgclock_resume ), + { 0, 0 } +}; + + +static devclass_t mbgclock_devclass; + +DEFINE_CLASS_0( mbgclock, mbgclock_driver, mbgclock_methods, sizeof( struct mbgclock_softc ) ); +DRIVER_MODULE( mbgclock, pci, mbgclock_driver, mbgclock_devclass, 0, 0 ); diff --git a/mbgctrl/Makefile b/mbgctrl/Makefile new file mode 100755 index 0000000..e485fc0 --- /dev/null +++ b/mbgctrl/Makefile @@ -0,0 +1,45 @@ + +######################################################################### +# +# $Id: Makefile 1.7.1.2 2010/08/30 09:05:22 martin TEST $ +# +# Description: +# Makefile for mbgctrl. +# +# ----------------------------------------------------------------------- +# $Log: Makefile $ +# Revision 1.7.1.2 2010/08/30 09:05:22 martin +# Revision 1.7.1.1 2010/08/30 08:20:54 martin +# Revision 1.7 2009/07/24 10:31:16 martin +# Moved declarations to a common file which is now included. +# Revision 1.6 2008/12/22 11:54:31 martin +# Changed enumeration of source files. +# Revision 1.5 2007/03/02 11:45:09 martin +# Parameter "DEBUG=1" lets the target be built with debug enabled. +# Revision 1.4 2003/04/25 10:21:05 martin +# Updated source module list. +# Revision 1.3 2002/11/21 14:56:31 martin +# New targets install and uninstall. +# Revision 1.2 2001/11/30 10:21:54 martin +# Added pcpsutil.o to the list of source files. +# Revision 1.1 2001/09/17 15:07:55 martin +# +######################################################################### + +TARGET = mbgctrl +INST_DIR = /usr/local/sbin + +# By default these tools only need a simple set of mbgdevio API +# functions, but here we use all API calls. +MBGDEVIO_SIMPLE = 0 + +OBJS = $(TARGET).o +OBJS += mbgdevio.o +OBJS += toolutil.o +OBJS += gpsutils.o +OBJS += pcpsutil.o +OBJS += parmgps.o +OBJS += parmpcps.o + +BASEDIR := .. +include $(BASEDIR)/Makefile diff --git a/mbgctrl/mbgctrl.c b/mbgctrl/mbgctrl.c new file mode 100755 index 0000000..0db595c --- /dev/null +++ b/mbgctrl/mbgctrl.c @@ -0,0 +1,1855 @@ + +/************************************************************************** + * + * $Id: mbgctrl.c 1.22 2009/09/29 14:58:18 martin REL_M $ + * + * Description: + * Main file for mbgctrl program which sends commands and + * configuration parameters to a Meinberg device via IOCTL calls. + * + * ----------------------------------------------------------------------- + * $Log: mbgctrl.c $ + * Revision 1.22 2009/09/29 14:58:18 martin + * Unified and simplified parameter evaluation. + * Updated version number to 3.4.0. + * Revision 1.21 2009/09/28 09:36:43 martin + * Support configuration of antenna cable length. + * Removed duplicate usage message for event time. + * Revision 1.20 2009/09/28 07:19:03 martin + * Made parameter syntax for enable_flags and LAN configuration more flexible. + * Revision 1.19 2009/08/20 14:19:29 martin + * Updated version number to 3.3.1. + * Support configuration of board's LAN interface. + * Revision 1.18 2009/07/24 09:50:08 martin + * Updated version number to 3.3.0. + * Revision 1.17 2009/06/19 12:38:51 martin + * Updated version number to 3.2.0. + * Revision 1.16 2009/06/18 15:14:53 martin + * Added command TZOFFS which can be used to set TZDL to UTC, and then + * configure the standard TZDL offset to a dedicated number of seconds, to the + * output time has a configurable UTC offset against the time derived from the + * input signal. + * Revision 1.15 2009/03/20 11:53:19 martin + * Updated version number to 3.1.0. + * Updated copyright year to include 2009. + * Support programmable time scales. + * Revision 1.14 2008/12/22 12:39:00 martin + * Updated description, copyright, revision number and string. + * Use unified functions from toolutil module. + * Accept device name(s) on the command line. + * Don't use printf() without format, which migth produce warnings + * with newer gcc versions. + * Revision 1.13 2008/11/07 10:25:49 martin + * Support modification of a card's ENABLE_FLAGS. + * Changes due to renamed library function. + * Changes due to renamed library function. + * Revision 1.12 2008/09/15 14:20:21 martin + * Support generic serial settings including string type and mode. + * Reworked evaluation of command line parameters. + * New parameter COM0= to configure an individual port. + * Account for renamed library symbols. + * Revision 1.11 2007/07/24 09:31:39 martin + * Changes due to renamed library symbols. + * Revision 1.10 2007/03/01 16:09:16 martin + * Be able to set the board date and/or time. + * Revision 1.9 2007/02/22 16:38:50 martin + * Added function to set on-board date. + * Revision 1.8 2006/08/28 10:45:50 martin + * Picked up Heiko's patch to set the GPS receiver position. + * Revision 1.7 2004/11/08 15:47:40 martin + * Using type cast to avoid compiler warning. + * Revision 1.6 2003/08/26 14:37:35 martin + * Support configuration of some standard time zones, + * also for GPS devices. + * Revision 1.5 2003/07/31 13:48:54 martin + * Added function to set COM port parms for GPS clocks. + * Usage shows which parameters are supported by a device. + * Revision 1.4 2003/04/25 10:27:58 martin + * Use new functions from mbgdevio library. + * New program version v2.1. + * Revision 1.3 2002/08/22 14:52:49 martin + * Added function to set clock's COM port parameters. + * Revision 1.2 2001/12/03 16:04:46 martin + * New program version 1.2. + * Added new function set_event_time(). + * Fixed a bug in eval of cmd line parameters. + * Revision 1.1 2001/09/17 15:07:56 martin + * + **************************************************************************/ + +// include Meinberg headers +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// include system headers +#include +#include +#include +#include +#include + + +static const char *pname = "mbgctrl"; +static const char *pversion = "v3.4.0"; +static const char *pcopyright = "(c) Meinberg 2001-2009"; + +static char *dev_name; + +static TZDL tzdl_utc = DEFAULT_TZDL_UTC; +static TZDL tzdl_cet_cest = DEFAULT_TZDL_CET_CEST_EN; +static TZDL tzdl_eet_eest = DEFAULT_TZDL_EET_EEST_EN; +static long max_tzdl_offs = 0x7FFFFFFFL; // max val for int32_t + +static const char *tz_info_utc = TZ_INFO_UTC; +static const char *tz_info_cet_cest = TZ_INFO_CET_CEST_EN; +static const char *tz_info_eet_eest = TZ_INFO_EET_EEST_EN; + +static const char *mode_names[N_STR_MODE] = DEFAULT_ENG_MODE_NAMES; +static const char *time_scale_name[N_MBG_TIME_SCALE] = MBG_TIME_SCALE_STRS; + +#define _get_time_scale_name( _i ) \ + ( ( (_i) < N_MBG_TIME_SCALE ) ? time_scale_name[_i] : "(unknown)" ) + + +static const char *no_gps_cmd = "does not support GPS commands"; +static const char *no_tzdl = "does not support configurable time zone"; +static const char *no_tz = "does not support time zones"; +static const char *no_event_time = "does not support event times"; +static const char *no_enable_flags = "does not support enable flags"; +static const char *no_time_scale = "does not support a configurable time scale"; +static const char *no_lan_intf = "does not provide a LAN interface"; +static const char *no_cab_len = "does not support antenna signal delay compensation"; + +typedef struct +{ + const char *name; + uint16_t *flags; + uint16_t on_flags; +} EF_INFO; + +#define N_EF_INFO 3 + +static const char *ef_name_serial = "SERIAL"; +static const char *ef_name_pulses = "PULSES"; +static const char *ef_name_synth = "SYNTH"; + + +typedef struct +{ + const char *name; + IP4_ADDR *addr; +} IP4_INFO; + +#define N_IP4_INFO 4 + +static const char *ip4_name_ip = "IP"; +static const char *ip4_name_nm = "NM"; +static const char *ip4_name_ba = "BA"; +static const char *ip4_name_gw = "GW"; + + + +static /*HDR*/ +void err_msg( const PCPS_DEV *p_dev, const char *msg ) +{ + printf( "This device %s.\n", msg ); + +} // err_msg + + + +static /*HDR*/ +int set_tz_code( MBG_DEV_HANDLE dh, PCPS_TZCODE tzcode, const char *s ) +{ + int rc = mbg_set_tzcode( dh, &tzcode ); + + if ( mbg_ioctl_err( rc, "mbg_set_tzcode" ) ) + return rc; + + printf( "The clock's time zone setting has been set to %s.\n", s ); + + return MBG_SUCCESS; + +} // set_tz_code + + + +static /*HDR*/ +int set_gps_tzdl( MBG_DEV_HANDLE dh, const TZDL *tzdl, const char *info ) +{ + int rc = mbg_set_gps_tzdl( dh, tzdl ); + + if ( mbg_ioctl_err( rc, "set_gps_tzdl" ) ) + return rc; + + if ( info ) + printf( "The clock's time zone setting has been set to %s.\n", info ); + + return MBG_SUCCESS; + +} // set_gps_tzdl + + + +static /*HDR*/ +int set_timezone( MBG_DEV_HANDLE dh, const char *tz_name, const PCPS_DEV *p_dev ) +{ + const char *tz_info = NULL; + TZDL *tz_tzdl = NULL; + PCPS_TZCODE tz_code = 0; + int rc = MBG_SUCCESS; + + if ( strcmp( tz_name, "UTC" ) == 0 ) + { + tz_info = tz_info_utc; + tz_tzdl = &tzdl_utc; + tz_code = PCPS_TZCODE_UTC; + } + else if ( strcmp( tz_name, "CET" ) == 0 ) + { + tz_info = tz_info_cet_cest; + tz_tzdl = &tzdl_cet_cest; + tz_code = PCPS_TZCODE_MEZMESZ; + } + else if ( strcmp( tz_name, "EET" ) == 0 ) + { + tz_info = tz_info_eet_eest; + tz_tzdl = &tzdl_eet_eest; + tz_code = PCPS_TZCODE_OEZ; + } + else + { + printf( "** Unknown timezone name %s\n", tz_name ); + rc = 1; + } + + if ( tz_info ) + { + if ( _pcps_has_tzcode( p_dev ) ) + rc = set_tz_code( dh, tz_code, tz_info ); + else + if ( _pcps_has_tzdl( p_dev ) ) + rc = set_gps_tzdl( dh, tz_tzdl, tz_info ); + else + err_msg( p_dev, no_tz ); + } + + return rc; + +} // set_timezone + + + +static /*HDR*/ +int show_tzdl_offs( MBG_DEV_HANDLE dh, const char *info ) +{ + TZDL tzdl; + int rc = mbg_get_gps_tzdl( dh, &tzdl ); + + if ( mbg_ioctl_err( rc, "mbg_get_gps_tzdl" ) ) + return rc; + + printf( "%s timezone offset: UTC%+lis", info, (long) tzdl.offs ); + + return MBG_SUCCESS; + +} // show_tzdl_offs + + + +static /*HDR*/ +int set_tzdl_offs( MBG_DEV_HANDLE dh, const char *s ) +{ + TZDL tzdl = tzdl_utc; + long tzdl_offs = atol( s ); + + if ( labs( tzdl_offs ) > max_tzdl_offs ) // max val for int32_t + { + fprintf( stderr, "** Time zone offset %li exceeds range (%li..%li)\n", + tzdl_offs, -max_tzdl_offs, max_tzdl_offs ); + return MBG_ERR_CFG; + } + + tzdl.offs = (int32_t) tzdl_offs; + + return set_gps_tzdl( dh, &tzdl, NULL ); + +} // set_tzdl_offs + + + +static /*HDR*/ +int snprint_ip4_addr( char *s, size_t max_len, const IP4_ADDR *addr ) +{ + int n; + + n = snprintf( s, max_len, "%i.%i.%i.%i", + BYTE_OF( *addr, 3 ), + BYTE_OF( *addr, 2 ), + BYTE_OF( *addr, 1 ), + BYTE_OF( *addr, 0 ) + ); + + return n; + +} // snprint_ip4_addr + + + +/*HDR*/ +const char *str_to_ip4_addr( IP4_ADDR *p, const char *s ) +{ + IP4_ADDR tmp_ip4_addr = 0; + char *cp; + int i; + + for ( i = 0, cp = (char *) s; ; ) + { + unsigned long ul = strtoul( cp, &cp, 10 ); + + if ( ul > 255 ) // invalid number + return NULL; + + tmp_ip4_addr |= ul << ( 8 * (3 - i) ); + + if ( ++i >= 4 ) + break; // done + + if ( *cp != '.' ) + return NULL; // invalid string format, dot expected + + cp++; // skip dot + } + + if ( p ) + *p = tmp_ip4_addr; + + return cp; // success + +} // str_to_ip4_addr + + + +static /*HDR*/ +int show_lan_intf( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev, const char *info ) +{ + IP4_SETTINGS ip4_settings; + char ws[256]; + + int rc = mbg_get_ip4_settings( dh, &ip4_settings ); + + if ( mbg_ioctl_err( rc, "mbg_get_ip4_settings" ) ) + return rc; + + printf( "On-board LAN interface settings:" ); + + if ( ip4_settings.flags & IP4_MSK_DHCP ) + printf( " (DHCP client)\n" ); + else + { + printf( "\n" ); + + snprint_ip4_addr( ws, sizeof( ws ), &ip4_settings.ip_addr ); + printf( " IP Address: %s\n", ws ); + + snprint_ip4_addr( ws, sizeof( ws ), &ip4_settings.netmask ); + printf( " Net Mask: %s\n", ws ); + + snprint_ip4_addr( ws, sizeof( ws ), &ip4_settings.broad_addr ); + printf( " Broadcast Addr: %s\n", ws ); + + snprint_ip4_addr( ws, sizeof( ws ), &ip4_settings.gateway ); + printf( " Gateway: %s\n", ws ); + } + + return MBG_SUCCESS; + +} // show_lan_intf + + + +static /*HDR*/ +int ip4_check_parm( const char *s, IP4_INFO *p ) +{ + int l = strlen( p->name ); + const char *cp; + + if ( strncmp( s, p->name, l ) != 0 ) + return 0; // parameter does not match + + if ( s[l] != ':' ) + goto fail; // parameter syntax error: name not followed by colon + + l++; + + cp = str_to_ip4_addr( p->addr, &s[l] ); + + if ( cp == NULL ) + goto fail; // parameter syntax error: failed to convert numeric address + + return cp - s; + +fail: + return MBG_ERR_CFG; + +} // ip4_check_parm + + + +static /*HDR*/ +int set_lan_intf( MBG_DEV_HANDLE dh, const char *arg, const PCPS_DEV *p_dev ) +{ + IP4_SETTINGS prv_ip4_settings; + IP4_SETTINGS ip4_settings = { 0 }; + IP4_ADDR default_broad_addr; + + IP4_INFO ip4_info[N_IP4_INFO] = + { + { ip4_name_ip, &ip4_settings.ip_addr }, + { ip4_name_nm, &ip4_settings.netmask }, + { ip4_name_ba, &ip4_settings.broad_addr }, + { ip4_name_gw, &ip4_settings.gateway } + }; + + int rc = mbg_get_ip4_settings( dh, &prv_ip4_settings ); + + if ( mbg_ioctl_err( rc, "mbg_get_ip4_settings" ) ) + return rc; + + if ( strcmp( arg, "DHCP" ) == 0 ) + { + ip4_settings = prv_ip4_settings; + ip4_settings.flags |= IP4_MSK_DHCP; + goto save; + } + + for (;;) + { + int i; + + for ( i = 0; i < N_IP4_INFO; i++ ) + { + rc = ip4_check_parm( arg, &ip4_info[i] ); + + if ( rc == 0 ) // check next + continue; + + if ( rc < 0 ) // error + goto invalid_msg; + + arg += rc; + + if ( *arg == 0 ) // end of parameter string + goto done; + + if ( *arg != ',' ) + goto invalid_msg; + + arg++; + } + } + + +done: // now check static configuration + if ( ip4_settings.ip_addr == 0 ) // no IP address specified on the command line + ip4_settings.ip_addr = prv_ip4_settings.ip_addr; // use previous IP address + + if ( ip4_settings.ip_addr == 0 ) // no IP address specified at all + { + printf( "*** Aborting: No IP address specified\n" ); + goto invalid; + } + + if ( ip4_settings.netmask == 0 ) // no network mask specified on the command line + ip4_settings.netmask = prv_ip4_settings.netmask; // use previous network mask + + if ( ip4_settings.netmask == 0 ) // no network mask specified at all + { + printf( "*** Aborting: No network mask specified\n" ); + goto invalid; + } + + // the default broadcast address is computed from the IP address and the network mask + default_broad_addr = ip4_settings.ip_addr | ~ip4_settings.netmask; + + if ( ip4_settings.broad_addr == 0 ) // no broadcast address specified on the command line + ip4_settings.broad_addr = default_broad_addr; + else + if ( ip4_settings.broad_addr != default_broad_addr ) + { + char ws1[40]; + char ws2[40]; + snprint_ip4_addr( ws1, sizeof( ws1 ), &ip4_settings.broad_addr ); + snprint_ip4_addr( ws2, sizeof( ws2 ), &default_broad_addr ); + printf( "*** Warning: Broadcast address %s does not match the default broadcast address %s\n", + ws1, ws2 ); + } + + if ( ip4_settings.gateway == 0 ) + ip4_settings.gateway = prv_ip4_settings.gateway; + + ip4_settings.flags = prv_ip4_settings.flags & ~IP4_MSK_DHCP; + // fall through to save: + +save: + rc = mbg_set_ip4_settings( dh, &ip4_settings ); + + if ( mbg_ioctl_err( rc, "mbg_set_ip4_settings" ) ) + return rc; + + return MBG_SUCCESS; + + +invalid_msg: + printf( "*** Warning: invalid LAN interface parameter syntax\n" ); + // fall through to invalid: + +invalid: + return MBG_ERR_CFG; // invalid parameter or parameter syntax error + +} // set_lan_intf + + + +static /*HDR*/ +int set_gps_pos( MBG_DEV_HANDLE dh, const char *gp ) +{ + LLA new_pos_lla; + char *cp; + int rc; + double r2d = 180 / PI; + + new_pos_lla[LAT] = strtod( gp, &cp ) / r2d; + + if ( *cp++ != ',' ) + goto invalid; + + new_pos_lla[LON] = strtod( cp, &cp ) / r2d; + + if ( *cp++ != ',' ) + goto invalid; + + new_pos_lla[ALT] = strtod( cp, &cp ); + + if ( + ( ( new_pos_lla[LAT] * r2d ) < -90 ) || + ( ( new_pos_lla[LAT] * r2d ) > +90 ) || + ( ( new_pos_lla[LON] * r2d ) < -180 ) || + ( ( new_pos_lla[LON] * r2d ) > +180 ) || + ( new_pos_lla[ALT] < -50 ) || + ( new_pos_lla[ALT] > 20000 ) + ) + goto invalid; + + + rc = mbg_set_gps_pos_lla ( dh, new_pos_lla ); + + if ( mbg_ioctl_err( rc, "mbg_set_gps_pos_lla" ) ) + return rc; + + printf( "The clock's receiver position has been set to lat=%+.4f, lon=%+.4f, alt=%.0fm\n", + new_pos_lla[LAT] * r2d, new_pos_lla[LON] * r2d, new_pos_lla[ALT] ); + + return rc; + + +invalid: + fprintf( stderr, "** Invalid GPS position parameters: %s\n", gp ); + + return MBG_ERR_CFG; + +} // set_gps_pos + + + +static /*HDR*/ +int set_date_time( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev, + const char *sdate, const char *stime ) +{ + PCPS_TIME_UNION u = { { 0 } }; + TTM ttm = { 0 }; + unsigned int year = 0; + unsigned int month = 0; + unsigned int mday = 0; + unsigned int hour = 0; + unsigned int min = 0; + unsigned int sec = 0; + unsigned int sec100 = 0; + int rc; + + // Either a date string, a time string, or both + // may have been passed to this function. + // If either of them is NULL read the current date/time + // as default values. + if ( sdate == NULL || stime == NULL ) + { + rc = mbg_get_time( dh, &u.t ); + + if ( mbg_ioctl_err( rc, "mbg_get_time" ) ) + return rc; + } + + + if ( sdate ) + { + rc = sscanf( sdate, "%u-%u-%u", &year, &month, &mday ); + + if ( ( rc < 3 ) + || ( month < 1 ) || ( month > 12 ) + || ( mday < 1 ) || ( mday > 31 ) ) + { + printf( "** Invalid date: %04u-%02u-%02u\n", year, month, mday ); + return MBG_ERR_CFG; + } + } + + + if ( stime ) + { + rc = sscanf( stime, "%u:%u:%u.%u", &hour, &min, &sec, &sec100 ); + + if ( ( rc < 2 ) // at least hours and minutes are required + || ( hour > 23 ) + || ( min > 59 ) + || ( sec > 60 ) + || ( sec100 > 99 ) ) + { + printf( "** Invalid time: %02u:%02u:%02u.%02u\n", hour, min, sec, sec100 ); + return MBG_ERR_CFG; + } + } + + // GPS and non-GPS cards require different API calls which use + // different structures to set the on-board date and time, + // so we have to distinguish. + + if ( _pcps_is_gps( p_dev ) ) // is a GPS card + { + ttm.channel = -1; + + if ( sdate ) // new date + { + ttm.tm.year = year; + ttm.tm.month = month; + ttm.tm.mday = mday; + } + else // copy current date as default + { + ttm.tm.year = u.t.year + 2000; + ttm.tm.month = u.t.month; + ttm.tm.mday = u.t.mday; + } + + if ( stime ) // new time + { + ttm.tm.hour = hour; + ttm.tm.min = min; + ttm.tm.sec = sec; + ttm.tm.frac = sec100; + } + else // copy current time as default + { + ttm.tm.hour = u.t.hour; + ttm.tm.min = u.t.min; + ttm.tm.sec = u.t.sec; + ttm.tm.frac = u.t.sec100; + } + + ttm.tm.frac *= 100000; // fracs are in 100 ns units + + #if 0 + // Existing versions of the GPS cards just take + // TTM.tm as local time without accounting for + // the status flags, or UTC offset. + // Instead, the TTM.tm time is converted on-board + // to UTC depending on the local TZDL configuration. + // This works if the system time and the + ttm.tm.offs_from_utc = 7200; + ttm.tm.status |= TM_UTC | TM_LOCAL; + ttm.tm.status |= TM_DL_ENB; + #endif + + rc = mbg_set_gps_time( dh, &ttm ); + + if ( mbg_ioctl_err( rc, "mbg_set_gps_time" ) ) + return rc; + } + else // is not a GPS card + { + if ( sdate ) // new date + { + // determine the day-of-week for the given date + struct tm tm = { 0 }; + + tm.tm_year = year - 1900; + tm.tm_mon = month - 1; + tm.tm_mday = mday; + tm.tm_hour = 12; + tm.tm_isdst = -1; + mktime( &tm ); + + u.stime.year = year % 100; + u.stime.month = month; + u.stime.mday = mday; + u.stime.wday = _wday_sun06_to_mon17( tm.tm_wday ); + } + + if ( stime ) // new time + { + u.stime.hour = hour; + u.stime.min = min; + u.stime.sec = sec; + u.stime.sec100 = sec100; + } + + if ( u.stime.wday == 0 ) + u.stime.wday = 1; // dummy + + rc = mbg_set_time( dh, &u.stime ); + + if ( mbg_ioctl_err( rc, "mbg_set_time" ) ) + return rc; + } + + printf( "Device date/time have been set.\n" ); + + return MBG_SUCCESS; + +} // set_date_time + + + +static /*HDR*/ +void check_setup_receiver_info( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev, + RECEIVER_INFO *p_ri ) +{ + // Set up the RECEIVER_INFO structure only if this has not been done + // before. Check the ticks_per_sec field to see if the structure + // has already been set up or not. + if ( p_ri->ticks_per_sec == 0 ) + mbg_setup_receiver_info( dh, p_dev, p_ri ); + +} // check_setup_receiver_info + + + +static /*HDR*/ +int check_get_receiver_port_cfg( MBG_DEV_HANDLE dh, RECEIVER_PORT_CFG *p_rpcfg, + const PCPS_DEV *p_dev, RECEIVER_INFO *p_ri ) +{ + int rc = MBG_SUCCESS; + + check_setup_receiver_info( dh, p_dev, p_ri ); + + // Set up the RECEIVER_PORT_CFG structure only if this has not been done + // before. Check whether the number of ports is > 0 and the first port's + // baud rate is still 0 to see if the structure has already been set up. + if ( ( p_ri->n_com_ports > 0 ) && + ( p_rpcfg->pii[0].port_info.port_settings.parm.baud_rate == 0 ) ) + { + rc = mbg_get_serial_settings( dh, p_dev, p_rpcfg, p_ri ); + + mbg_ioctl_err( rc, "mbg_get_serial_settings" ); + } + + return rc; + +} // check_get_receiver_port_cfg + + + +static /*HDR*/ +int snprint_port_cfg( char *s, int sz, unsigned int port_num, + const RECEIVER_PORT_CFG *p_rpcfg ) +{ + const PORT_SETTINGS *p_ps = &p_rpcfg->pii[port_num].port_info.port_settings; + + int n = snprintf( s, sz, "\"%s\" %s at %lu/%s", + p_rpcfg->stii[p_ps->str_type].str_type_info.long_name, + mode_names[p_ps->mode], + (unsigned long) p_ps->parm.baud_rate, + p_ps->parm.framing + ); + + return n; + +} // snprint_port_cfg + + + +static /*HDR*/ +void show_serial_settings( MBG_DEV_HANDLE dh, const RECEIVER_PORT_CFG *p_rpcfg, + const RECEIVER_INFO *p_ri ) +{ + char ws[256]; + unsigned int i; + + for ( i = 0; i < p_ri->n_com_ports; i ++ ) + { + snprint_port_cfg( ws, sizeof( ws ), i, p_rpcfg ); + printf( "Serial port COM%u: %s.\n", i, ws ); + } + +} // show_serial_settings + + + +static /*HDR*/ +void print_port_info_errors( const char *port_name, unsigned int port_num, + int flags, const RECEIVER_PORT_CFG *p_rpcfg ) +{ + const char *msg_nsupp_drvr = "is not supported by the driver software"; + + const PORT_INFO *p_pi = &p_rpcfg->pii[port_num].port_info; + const PORT_SETTINGS *p_ps = &p_pi->port_settings; + + + if ( flags & MBG_PS_MSK_BAUD_RATE_OVR_SW ) + printf( "** Baud rate %lu %s.\n", (ulong) p_ps->parm.baud_rate, msg_nsupp_drvr ); + else + if ( flags & MBG_PS_MSK_BAUD_RATE ) + printf( "** Baud rate %lu is not supported by %s%u.\n", + (ulong) p_ps->parm.baud_rate, port_name, port_num ); + + + if ( flags & MBG_PS_MSK_FRAMING_OVR_SW ) + printf( "** Framing %s %s.\n", p_ps->parm.framing, msg_nsupp_drvr ); + else + if ( flags & MBG_PS_MSK_FRAMING ) + printf( "** Framing %s is not supported by %s%u.\n", + p_ps->parm.framing, port_name, port_num ); + + + if ( flags & MBG_PS_MSK_HS_OVR_SW ) + printf( "** Handshake mode %u %s.\n", p_ps->parm.handshake, msg_nsupp_drvr ); + else + if ( flags & MBG_PS_MSK_HS ) + printf( "** Handshake mode %u is not supported by %s%u.\n", + (unsigned int) p_ps->parm.handshake, port_name, port_num ); + + + if ( flags & MBG_PS_MSK_STR_TYPE_OVR_DEV ) + printf( "** String type index %u exceeds number of string types supp. by device.\n", + p_ps->str_type ); + else + if ( flags & MBG_PS_MSK_STR_TYPE ) + printf( "** String type \"%s\" is not supported by %s%u.\n", + p_rpcfg->stii[p_ps->str_type].str_type_info.long_name, + port_name, port_num ); + + + if ( flags & MBG_PS_MSK_STR_MODE_OVR_SW ) + printf( "** String mode index %u exceeds number of string modes supported by driver software (%u).\n", + p_ps->mode, N_STR_MODE ); + else + if ( flags & MBG_PS_MSK_STR_MODE ) + printf( "** String mode \"%s\" is not supported by string type \"%s\" via %s%u .\n", + mode_names[p_ps->mode], + p_rpcfg->stii[p_ps->str_type].str_type_info.long_name, + port_name, port_num ); + +} // print_port_info_errors + + + +static /*HDR*/ +int save_serial_settings( MBG_DEV_HANDLE dh, unsigned int port_num, const char *parm_str, + const PCPS_DEV *p_dev, const RECEIVER_INFO *p_ri ) +{ + char ws[256]; + RECEIVER_PORT_CFG rpcfg = { { { 0 } } }; + PORT_INFO *p_pi = &rpcfg.pii[port_num].port_info; + PORT_SETTINGS *p_ps = &p_pi->port_settings; + ulong ul; + const char *cp; + char *p_tail; + int rc; + int flags; + int i; + + // load current settings and supported settings + rc = mbg_get_serial_settings( dh, p_dev, &rpcfg, p_ri ); + + if ( mbg_ioctl_err( rc, "mbg_get_serial_settings" ) ) + return rc; + + + cp = parm_str; + p_ps->parm.baud_rate = strtoul( cp, &p_tail, 10 ); + + if ( p_tail == cp ) // no number found + goto invalid; + + cp = p_tail; + + if ( *cp++ != ',' ) // separator before framing missing + goto invalid; + + for ( i = 0; i < sizeof( p_ps->parm.framing ); i++ ) + { + if ( !isalnum( *cp ) ) // stop copying if non-alpha and non-digit + break; + + p_ps->parm.framing[i] = *cp++; + } + + p_ps->parm.framing[i] = 0; // force terminating 0 + + p_ps->parm.handshake = HS_NONE; // this is the only supported setting + + + // get optional string type index + + if ( *cp++ != ',' ) + goto done_parm_str; + + ul = strtoul( cp, &p_tail, 10 ); + + if ( p_tail != cp ) + p_ps->str_type = ul; + + cp = p_tail; + + + // get optional string mode index + + if ( *cp++ != ',' ) + goto done_parm_str; + + ul = strtoul( cp, &p_tail, 10 ); + + if ( p_tail != cp ) + p_ps->mode = ul; + + +done_parm_str: + + // check if the new parameter set is valid + flags = check_valid_port_info( p_pi, rpcfg.stii, p_ri->n_str_type ); + + if ( flags ) // parameters not valid + { + print_port_info_errors( "COM", port_num, flags, &rpcfg ); + goto invalid; + } + + // save new parameters + rc = mbg_save_serial_settings( dh, p_dev, &rpcfg, port_num ); + + if ( mbg_ioctl_err( rc, "mbg_save_serial_settings" ) ) + return rc; + + + snprint_port_cfg( ws, sizeof( ws ), port_num, &rpcfg ); + printf( "The clock's COM%u port has been set to %s.\n", port_num, ws ); + + return MBG_SUCCESS; + + +invalid: + fprintf( stderr, "** Invalid COM port parameters: %s\n", parm_str ); + return MBG_ERR_CFG; + +} // save_serial_settings + + + +static /*HDR*/ +void printf_ef( uint16_t flag, const char *info ) +{ + printf( "%s:%u", info, ( flag == EF_OFF ) ? 0 : 1 ); + +} // printf_ef + + + +static /*HDR*/ +int show_enable_flags( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev, const char *info ) +{ + ENABLE_FLAGS ef; + int rc; + + rc = mbg_get_gps_enable_flags( dh, &ef ); + + if ( mbg_ioctl_err( rc, "mbg_get_gps_enable_flags" ) ) + return rc; + + printf( "%s enable flags: ", info ); + printf_ef( ef.serial, ef_name_serial ); + printf( "," ); + printf_ef( ef.pulses, ef_name_pulses ); + + if ( _pcps_has_synth( p_dev ) ) + { + printf( "," ); + printf_ef( ef.synth, ef_name_synth ); + } + + printf( "\n" ); + + return MBG_SUCCESS; + +} // show_enable_flags + + + +static /*HDR*/ +int ef_check_parm( const char *s, EF_INFO *p ) +{ + int l = strlen( p->name ); + + if ( strncmp( s, p->name, l ) != 0 ) + return 0; // parameter does not match + + if ( s[l] != ':' ) + goto fail; // parameter syntax error: name not followed by colon + + l++; + + if ( s[l] != '0' && s[l] != '1' ) + goto fail; // parameter syntax error: colon not followed by '0' or '1' + + *p->flags = ( s[l] == '0' ) ? EF_OFF : p->on_flags; + + l++; + + return l; + + +fail: + return MBG_ERR_CFG; + +} // ef_check_parm + + + +static /*HDR*/ +int set_enable_flags( MBG_DEV_HANDLE dh, const char *arg, const PCPS_DEV *p_dev ) +{ + ENABLE_FLAGS ef; + + EF_INFO ef_parms[N_EF_INFO] = + { + { ef_name_serial, &ef.serial, EF_SERIAL_BOTH }, + { ef_name_pulses, &ef.pulses, EF_PULSES_BOTH }, + { ef_name_synth, &ef.synth, EF_SYNTH } + }; + + int rc; + + rc = mbg_get_gps_enable_flags( dh, &ef ); + + if ( mbg_ioctl_err( rc, "mbg_get_gps_enable_flags" ) ) + return rc; + + // Scan input parameters + for (;;) + { + int i; + + for ( i = 0; i < N_EF_INFO; i++ ) + { + rc = ef_check_parm( arg, &ef_parms[i] ); + + if ( rc == 0 ) // check next + continue; + + if ( rc < 0 ) // error + return rc; + + arg += rc; + + if ( *arg == 0 ) // done + goto save; + + if ( *arg != ',' ) + return MBG_ERR_CFG; // invalid parameter or parameter syntax error + + arg++; + } + } + +save: + rc = mbg_set_gps_enable_flags( dh, &ef ); + + if ( mbg_ioctl_err( rc, "mbg_set_gps_enable_flags" ) ) + return rc; + + return MBG_SUCCESS; + +} // set_enable_flags + + + +static /*HDR*/ +int send_gps_cmd( MBG_DEV_HANDLE dh, ushort cmd ) +{ + int rc = mbg_set_gps_cmd( dh, &cmd ); + + if ( mbg_ioctl_err( rc, "mbg_set_gps_cmd" ) ) + return rc; + + printf( "NOTE: the command code %u has been sent to the GPS clock.\n", cmd ); + + return MBG_SUCCESS; + +} // send_gps_cmd + + + +static /*HDR*/ +int show_ant_cable_len( MBG_DEV_HANDLE dh, const char *info ) +{ + ANT_CABLE_LEN len; + int rc = mbg_get_gps_ant_cable_len( dh, &len ); + + if ( mbg_ioctl_err( rc, "mbg_get_gps_ant_cable_len" ) ) + return rc; + + printf( "%s antenna cable length: %u meter(s)", info, len ); + + return MBG_SUCCESS; + +} // show_ant_cable_len + + + +static /*HDR*/ +int set_ant_cable_len( MBG_DEV_HANDLE dh, const char *s ) +{ + ANT_CABLE_LEN len = atol( s ); + int rc = mbg_set_gps_ant_cable_len( dh, &len ); + + if ( mbg_ioctl_err( rc, "mbg_set_gps_ant_cable_len" ) ) + return rc; + + return MBG_SUCCESS; + +} // set_ant_cable_len + + + +static /*HDR*/ +int set_event_time( MBG_DEV_HANDLE dh, const char *s ) +{ + char ws[80]; + time_t event_time; + PCPS_TIME_STAMP event_ts; + int rc; + + // set event at current system time + number of seconds + event_time = time( NULL ) + strtol( s, NULL, 10 ); + event_ts.sec = event_time; // Unix UTC seconds + event_ts.frac = 0; // fraction of second, 0xFFFFFFFF == 0.99.. sec + + rc = mbg_set_event_time( dh, &event_ts ); + + if ( mbg_ioctl_err( rc, "mbg_set_event_time" ) ) + return rc; + + mbg_snprint_hr_tstamp( ws, sizeof( ws ), &event_ts ); + printf( "Event time set to UTC %s\n", ws ); + + return MBG_SUCCESS; + +} // set_event_time + + + +static /*HDR*/ +int get_n_time_scale( MBG_DEV_HANDLE dh, MBG_TIME_SCALE_INFO *p_tsci ) +{ + MBG_TIME_SCALE_INFO tsci = { { 0 } }; + int rc; + int i; + + rc = mbg_dev_has_time_scale( dh, &i ); + + if ( ( rc != MBG_SUCCESS ) || ( i == 0 ) ) + goto done; // failed or not supported + + rc = mbg_get_time_scale_info( dh, &tsci ); + + if ( rc != MBG_SUCCESS ) + goto done; + + if ( p_tsci ) + *p_tsci = tsci; + +done: + return tsci.max_settings.scale; + +} // get_n_time_scale + + + +static /*HDR*/ +int show_time_scale( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev, const char *info ) +{ + MBG_TIME_SCALE_INFO tsci = { { 0 } }; + int rc; + + rc = mbg_get_time_scale_info( dh, &tsci ); + + if ( mbg_ioctl_err( rc, "mbg_get_time_scale_info" ) ) + return rc; + + printf( "%s time scale index: %u (%s)", info, tsci.settings.scale, + _get_time_scale_name( tsci.settings.scale ) ); + + printf( "\n" ); + + return MBG_SUCCESS; + +} // show_time_scale + + + +static /*HDR*/ +int set_time_scale( MBG_DEV_HANDLE dh, const char *arg, const PCPS_DEV *p_dev ) +{ + MBG_TIME_SCALE_INFO tsci = { { 0 } }; + int rc; + + rc = mbg_get_time_scale_info( dh, &tsci ); + + if ( mbg_ioctl_err( rc, "mbg_get_time_scale_info" ) ) + return rc; + + + tsci.settings.scale = atoi( arg ); + + if ( tsci.settings.scale >= tsci.max_settings.scale ) + { + printf( "*** Error: new time scale index (%u) out of range (0..%u)\n", + tsci.settings.scale, tsci.max_settings.scale - 1 ); + return MBG_ERR_CFG; + } + + if ( !( tsci.supp_scales & ( 1UL << tsci.settings.scale ) ) ) + { + printf( "*** Warning: new time scale index (%u) not supported by device\n", + tsci.settings.scale ); + return MBG_ERR_CFG; + } + + rc = mbg_set_time_scale_settings( dh, &tsci.settings ); + + if ( mbg_ioctl_err( rc, "mbg_set_time_scale_settings" ) ) + return rc; + + return MBG_SUCCESS; + +} // set_time_scale + + + +static /*HDR*/ +void usage( MBG_DEV_HANDLE dh, PCPS_DEV *p_dev, RECEIVER_INFO *p_ri, + RECEIVER_PORT_CFG *p_rpcfg ) +{ + int i; + int n_time_scale; + + if ( p_dev ) + { + check_setup_receiver_info( dh, p_dev, p_ri ); + check_get_receiver_port_cfg( dh, p_rpcfg, p_dev, p_ri ); + } + + printf( "Usage: %s cmd [dev]\n" + "\n" + "where cmd can be one of the following:\n" + " BOOT set GPS clock to boot mode\n" + " GPSPOS=x.x,y.y,z set GPS position to (lat,lon,alt)\n", + pname + ); + + + printf( " DATE=yyyy-mm-dd set on-board date to year, month, day-of-month\n" + " TIME=hh:mm:ss.hh set on-board time to hours, mins, secs, hundredths\n" + ); + + + printf( " TIMESCALE show clock's time scale setting, if supported\n" + " TIMESCALE= set clock's time scale to scale with index \n" + ); + + n_time_scale = p_dev ? get_n_time_scale( dh, NULL ) : N_MBG_TIME_SCALE; + + if ( n_time_scale ) + { + printf( " Known time scales:\n" ); + for ( i = 0; i < n_time_scale; i++ ) + { + printf( " %u: %s", i, _get_time_scale_name( i ) ); + + if ( i == 0 ) + printf( " (default)" ); + + printf( "\n" ); + } + } + else + printf( " (Configurable time scales not supported by this device)\n" ); + + + printf( " TZOFFS show clock's time zone offset, if supported\n" + " TZOFFS= set clock's basic time zone to UTC with additional offset, in seconds\n" + ); + + printf( " TZ=UTC set time zone code to %s\n" + " TZ=CET set time zone code to %s\n" + " TZ=EET set time zone code to %s\n", + tz_info_utc, + tz_info_cet_cest, + tz_info_eet_eest + ); + + + printf( " COMPARM show clock's COM port parameters\n" + " COM=,[,[,]] set parameters of clock's port COM" + ); + + printf( ", where\n" + " is one of:" ); + for ( i = 0; i < N_MBG_BAUD_RATES; i++ ) + printf( " %s", mbg_baud_str[i] ); + + printf( "\n" + " is one of:" ); + for ( i = 0; i < N_MBG_FRAMINGS; i++ ) + printf( " %s", mbg_framing_str[i] ); + + printf( "\n optional time string format index" ); + + if ( p_dev ) + { + printf( ":" ); + + for ( i = 0; i < p_ri->n_str_type; i ++ ) + { + const STR_TYPE_INFO *p_sti = &p_rpcfg->stii[i].str_type_info; + + printf( "\n %u: %s", i, p_sti->long_name ); + } + } + + printf( "\n optional time string mode index" ); + + if ( p_dev ) + { + printf( ":" ); + + for ( i = 0; i < N_STR_MODE; i ++ ) + printf( "\n %u: %s", i, mode_names[i] ); + + printf( "\n" + " Please note not each baud rate, framing, string format and mode\n" + " must necessarily be supported by every individual serial port.\n" ); + } + + printf( "\n" ); + + printf( " EF show clock's enable flags\n" + " EF=SERIAL:0,PULSES:1,SYNTH:0 modify clock's enable flags\n" + "\n" + " SERIAL controls the serial port output\n" + " PULSES controls pulse outputs and IRIG timecode output, if available\n" + " SYNTH controls a programmable synthesizer output, if available\n" + "\n" + " 0 or 1 controls when the corresponding output signals are enabled:\n" + " 0: only after the card has synchronized to its incoming signal\n" + " 1: immediately after power-up\n" + "\n" + " Please note enable flags may not be supported by any device\n" + "\n" + ); + + printf( " LAN show board's LAN interface settings\n" + " LAN=DHCP set LAM interface to be configured via DHCP\n" + " LAN=IP:[,NM:][,BA:][,GW:] set LAN interface to given static settings\n" + "\n" + " where each of ,,, is an IPv4 address of the form aaa.bbb.ccc.ddd, e.g.:\n" + " IP:192.168.1.115 specifies the IP address\n" + " NM:255.255.255.0 specifies the net mask\n" + " BA:192.168.1.255 specifies the broadcast address\n" + " GW:192.168.1.1 specifies the default gateway\n" + "\n" + " If no broadcast address is specified then the default broadcast address\n" + " is computed from the IP address and the network mask.\n" + "\n" + " Please note a LAN interface may not be provided by any board type.\n" + " Also, the IP values above are examples only. The real values to be used\n" + " depend on the settings of the network to which the card is attached.\n" + "\n" + ); + + printf( " ANT_CABLE_LEN show the configured antenna cable length\n" + " ANT_CABLE_LEN= set the antenna cable length to be compensated to , in meters.\n" + "\n" + " Please note note this parameter is only supported with cards which provide\n" + " compensation of the antenna cable signal propagation delay, i.e. GPS cards.\n" + "\n" + ); + + if ( p_dev ) + { + if ( _pcps_has_event_time( p_dev ) ) + printf( " EVENT= set event time to system time + seconds\n" ); + } + +} // usage + + + +static /*HDR*/ +const char *str_parm_p(const char *s, const char *keyword ) +{ + return strstr( s, keyword ) ? &s[strlen( keyword )] : NULL; + +} // str_parm_p + + + +static /*HDR*/ +int check_cmd_line( int argc, char *argv[], MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev, + RECEIVER_INFO *p_ri, RECEIVER_PORT_CFG *p_rpcfg ) +{ + const char *sdate = NULL; + const char *stime = NULL; + const char *cp; + int i; + int rc = 0; + int error_occurred = 0; + + must_print_usage = 0; + + for ( i = 1; i < argc; i++ ) + { + if ( rc < 0 ) + error_occurred = 1; + + if ( rc > 0 ) + must_print_usage = 1; + + rc = 0; + + if ( ( strcmp( argv[i], "-?" ) == 0 ) || + ( strcmp( argv[i], "-h" ) == 0 ) || + ( strcmp( argv[i], "--help" ) == 0 ) ) + { + must_print_usage = 1; + continue; + } + + if ( strcmp( argv[i], "BOOT" ) == 0 ) + { + if ( p_dev ) + { + if ( _pcps_is_gps( p_dev ) ) + rc = send_gps_cmd( dh, PC_GPS_CMD_BOOT ); + else + err_msg( p_dev, no_gps_cmd ); + } + continue; + } + + + cp = str_parm_p( argv[i], "TZ=" ); + + if ( cp ) + { + if ( p_dev ) + rc = set_timezone( dh, cp, p_dev ); + + continue; + } + + + cp = str_parm_p( argv[i], "GPSPOS=" ); + + if ( cp ) + { + if ( p_dev ) + { + if ( _pcps_is_gps( p_dev ) ) + rc = set_gps_pos( dh, cp ); + else + err_msg( p_dev, no_gps_cmd ); + } + continue; + } + + + cp = str_parm_p( argv[i], "DATE=" ); + + if ( cp ) + { + sdate = cp; + continue; + } + + + cp = str_parm_p( argv[i], "TIME=" ); + + if ( cp ) + { + stime = cp; + continue; + } + + + cp = str_parm_p( argv[i], "COMPARM" ); + + if ( cp ) + { + if ( p_dev ) + { + check_setup_receiver_info( dh, p_dev, p_ri ); + check_get_receiver_port_cfg( dh, p_rpcfg, p_dev, p_ri ); + + if ( *cp != 0 ) + { + printf( "** Invalid parameter: %s\n", argv[i] ); + must_print_usage = 1; + continue; + } + + show_serial_settings( dh, p_rpcfg, p_ri ); + } + + continue; + } + + + cp = str_parm_p( argv[i], "COM" ); + + if ( cp ) + { + if ( p_dev ) + { + char *p_tail; + ulong port_num; + + check_setup_receiver_info( dh, p_dev, p_ri ); + check_get_receiver_port_cfg( dh, p_rpcfg, p_dev, p_ri ); + + port_num = strtoul( cp, &p_tail, 10 ); + + if ( p_tail == cp ) // no COM port number specified + { + printf( "** Invalid COM port specification: %s\n", argv[i] ); + must_print_usage = 1; + continue; + } + + cp = p_tail; + + if ( port_num >= (ulong) p_ri->n_com_ports ) + { + printf( "** COM port number %lu exceeds maximum %u\n", + port_num, p_ri->n_com_ports ); + must_print_usage = 1; + continue; + } + + if ( *cp != '=' ) + { + printf( "** Invalid COM port specification: %s\n", argv[i] ); + must_print_usage = 1; + continue; + } + + rc = save_serial_settings( dh, (unsigned) port_num, ++cp, p_dev, p_ri ); + } + continue; + } + + + cp = str_parm_p( argv[i], "EF" ); + + if ( cp ) + { + if ( p_dev ) + { + char *info = "Current"; + + if ( !_pcps_has_gps_data( p_dev ) ) + { + err_msg( p_dev, no_enable_flags ); + continue; + } + + if ( *cp == '=' ) + { + rc = set_enable_flags( dh, ++cp, p_dev ); + + if ( rc < 0 ) + { + printf( "*** Warning: invalid enable flag parameter syntax\n" ); + must_print_usage = 1; + continue; + } + + info = "New"; + } + + show_enable_flags( dh, p_dev, info ); + } + continue; + } + + + cp = str_parm_p( argv[i], "TIMESCALE" ); + + if ( cp ) + { + if ( p_dev ) + { + char *info = "Current"; + + if ( !_pcps_has_time_scale( p_dev ) ) + { + err_msg( p_dev, no_time_scale ); + continue; + } + + if ( *cp == '=' ) + { + rc = set_time_scale( dh, ++cp, p_dev ); + + if ( rc < 0 ) + { + must_print_usage = 1; + continue; + } + + info = "New"; + } + + show_time_scale( dh, p_dev, info ); + } + continue; + } + + + cp = str_parm_p( argv[i], "TZOFFS" ); + + if ( cp ) + { + if ( p_dev ) + { + char *info = "Current"; + + if ( !_pcps_has_tzdl( p_dev ) ) + { + err_msg( p_dev, no_tzdl ); + continue; + } + + if ( *cp == '=' ) + { + rc = set_tzdl_offs( dh, ++cp ); + + if ( rc < 0 ) + { + must_print_usage = 1; + continue; + } + + info = "New"; + } + + show_tzdl_offs( dh, info ); + } + continue; + } + + + cp = str_parm_p( argv[i], "LAN" ); + + if ( cp ) + { + if ( p_dev ) + { + char *info = "Current"; + + if ( !_pcps_has_lan_intf( p_dev ) ) + { + err_msg( p_dev, no_lan_intf ); + continue; + } + + if ( *cp == '=' ) + { + rc = set_lan_intf( dh, ++cp, p_dev ); + + if ( rc < 0 ) + { + must_print_usage = 1; + continue; + } + + info = "New"; + } + + show_lan_intf( dh, p_dev, info ); + } + continue; + } + + + cp = str_parm_p( argv[i], "ANT_CABLE_LEN" ); + + if ( cp ) + { + if ( p_dev ) + { + char *info = "Current"; + + if ( !_pcps_has_cab_len( p_dev ) ) + { + err_msg( p_dev, no_cab_len ); + continue; + } + + if ( *cp == '=' ) + { + rc = set_ant_cable_len( dh, ++cp ); + + if ( rc < 0 ) + { + must_print_usage = 1; + continue; + } + + info = "New"; + } + + show_ant_cable_len( dh, info ); + } + continue; + } + + + cp = str_parm_p( argv[i], "EVENT" ); + + if ( cp ) + { + if ( p_dev ) + { + if ( _pcps_has_event_time( p_dev ) ) + { + if ( *cp == '=' ) + rc = set_event_time( dh, ++cp ); + else + rc = -1; + + if ( rc < 0 ) + printf( "*** Warning: invalid event time parameter\n" ); + } + else + err_msg( p_dev, no_event_time ); + } + continue; + } + + if ( dev_name == NULL ) + dev_name = argv[i]; + +#if 0 //##++ + else + { + printf( "** Unknown command: %s\n", argv[i] ); + must_print_usage = 1; + } +#endif + + } + + if ( p_dev ) + if ( sdate || stime ) + rc = set_date_time( dh, p_dev, sdate, stime ); + + if ( error_occurred ) + return -1; + + if ( must_print_usage ) + return 1; + + return MBG_SUCCESS; + +} // check_cmd_line + + + +int main( int argc, char *argv[] ) +{ + RECEIVER_PORT_CFG rpcfg = { { { 0 } } }; + RECEIVER_INFO ri = { 0 }; + PCPS_DEV dev = { { 0 } }; + PCPS_DEV *pdev = NULL; + MBG_DEV_HANDLE dh = MBG_INVALID_DEV_HANDLE; + int rc; + + mbg_print_program_info( pname, pversion, pcopyright ); + + // If no arguments have been given, just print usage. + if ( argc < 2 ) + goto show_usage; + + // Check the command line for a device name, but don't + // pass a device handle, so commands are not evaluated. + check_cmd_line( argc, argv, dh, NULL, &ri, &rpcfg ); + + if ( dev_name ) + dh = open( dev_name, 0 ); // open specific device + else + dh = mbg_open_device( 0 ); // open first device found + + if ( dh == MBG_INVALID_DEV_HANDLE ) + { + perror( "Unable to open device" ); + goto fail; + } + + + // get information about the device + rc = mbg_get_show_dev_info( dh, dev_name, &dev ); + + if ( rc < 0 ) + goto fail; + + + pdev = &dev; + + rc = check_cmd_line( argc, argv, dh, pdev, &ri, &rpcfg ); + + if ( rc < 0 ) + goto fail; + + if ( rc > 0 ) + goto show_usage; + + printf( "\n" ); + + mbg_close_device( &dh ); + + return 0; + + +show_usage: + usage( dh, pdev, &ri, &rpcfg ); + return 1; + +fail: + return 2; +} diff --git a/mbgfasttstamp/Makefile b/mbgfasttstamp/Makefile new file mode 100755 index 0000000..92cfa46 --- /dev/null +++ b/mbgfasttstamp/Makefile @@ -0,0 +1,29 @@ + +######################################################################### +# +# $Id: Makefile 1.2.1.2 2010/08/30 09:05:23 martin TEST $ +# +# Description: +# Makefile for mbgfasttstamp. +# +# ----------------------------------------------------------------------- +# $Log: Makefile $ +# Revision 1.2.1.2 2010/08/30 09:05:23 martin +# Revision 1.2.1.1 2010/08/30 08:21:01 martin +# Revision 1.2 2009/07/24 10:31:16 martin +# Moved declarations to a common file which is now included. +# Revision 1.1 2008/12/22 11:45:01 martin +# Initial revision. +# +######################################################################### + +TARGET = mbgfasttstamp +INST_DIR = /usr/local/bin + +OBJS = $(TARGET).o +OBJS += mbgdevio.o +OBJS += toolutil.o +OBJS += gpsutils.o + +BASEDIR := .. +include $(BASEDIR)/Makefile diff --git a/mbgfasttstamp/mbgfasttstamp.c b/mbgfasttstamp/mbgfasttstamp.c new file mode 100755 index 0000000..35bad13 --- /dev/null +++ b/mbgfasttstamp/mbgfasttstamp.c @@ -0,0 +1,271 @@ + +/************************************************************************** + * + * $Id: mbgfasttstamp.c 1.6.1.3 2011/01/28 12:04:07 martin TEST $ + * + * Description: + * Main file for mbgfasttstamp program which demonstrates how to access + * a Meinberg device via memory mapped I/O, if supported by the device. + * + * ----------------------------------------------------------------------- + * $Log: mbgfasttstamp.c $ + * Revision 1.6.1.3 2011/01/28 12:04:07 martin + * Revision 1.6.1.2 2011/01/28 11:51:13 martin + * Revision 1.6.1.1 2011/01/28 11:17:00 martin + * Abort if MM access not supported on the target OS. + * Revision 1.6 2010/05/21 12:54:33 martin + * Print warning if no cycles supported on the target platform + * and thus latencies can not be computed. + * Revision 1.5 2009/09/29 15:02:14 martin + * Updated version number to 3.4.0. + * Revision 1.4 2009/07/24 09:50:08 martin + * Updated version number to 3.3.0. + * Revision 1.3 2009/06/19 14:01:32 martin + * Made print_hr_timestamp() to toolutil.c as mbg_print_hr_timestamp(). + * Updated version number to 3.2.0. + * Revision 1.2 2009/03/20 11:48:19 martin + * Updated version number to 3.1.0. + * Updated copyright year to include 2009. + * New parameter -r lets the program read raw timestamps + * using the new API call mbg_get_fast_hr_timestamp(). + * Revision 1.1 2008/12/22 11:45:01 martin + * Initial revision. + * Revision 1.1 2008/12/22 11:05:24 martin + * Initial revision. + * + **************************************************************************/ + +// include Meinberg headers +#include +#include +#include // common utility functions + +// include system headers +#include +#include +#include + + +static const char *pname = "mbgfasttstamp"; +static const char *pversion = "v3.4.0"; +static const char *pcopyright = "(c) Meinberg 2007-2009"; + + +#define MAX_TS_BURST 1000 + +static int loops; +static int burst_read; +static int read_raw; + + + +// The function below reads a number of time stamps and prints +// each timestamp immediately. This is not as fast as possible +// since printing the time stamp takes some time to execute. +// However, this can run continuously forever. + +static /*HDR*/ +int show_fast_hr_timestamp( MBG_DEV_HANDLE dh ) +{ + int this_loops = loops; + PCPS_TIME_STAMP ts; + int32_t hns_latency = 0; + + for (;;) + { + int rc = read_raw ? mbg_get_fast_hr_timestamp( dh, &ts ) : + mbg_get_fast_hr_timestamp_comp( dh, &ts, &hns_latency ); + + if ( mbg_ioctl_err( rc, "mbg_get_fast_hr_timestamp..." ) ) + goto fail; + + mbg_print_hr_timestamp( &ts, hns_latency, NULL, read_raw ); + + if ( this_loops > 0 ) + this_loops--; + + if ( this_loops == 0 ) + break; + + // if this_loops is < 0 then loop forever + } + + return 0; + +fail: + return -1; + +} // show_fast_hr_timestamp + + + +// The function below takes a number of time stamps and saves +// them to a buffer. After the time stamps have been read +// a second loop prints the time stamps from the buffer. +// This way the time stamps are read in shorter intervals. +// However, this can not run continuously forever since +// the buffer size is somewhat limited. + +static /*HDR*/ +int show_fast_hr_timestamp_burst( MBG_DEV_HANDLE dh ) +{ + PCPS_TIME_STAMP ts[MAX_TS_BURST]; + int32_t hns_latency[MAX_TS_BURST]; + int this_loops; + int i; + + this_loops = ( loops && ( loops < MAX_TS_BURST ) ) ? loops : MAX_TS_BURST; + + + if ( read_raw ) + { + for ( i = 0; i < this_loops; i++ ) + { + int rc = mbg_get_fast_hr_timestamp( dh, &ts[i] ); + + if ( mbg_ioctl_err( rc, "mbg_get_fast_hr_timestamp" ) ) + goto fail; + } + } + else + for ( i = 0; i < this_loops; i++ ) + { + int rc = mbg_get_fast_hr_timestamp_comp( dh, &ts[i], &hns_latency[i] ); + + if ( mbg_ioctl_err( rc, "mbg_get_fast_hr_timestamp_comp" ) ) + goto fail; + } + + for ( i = 0; i < this_loops; i++ ) + { + PCPS_TIME_STAMP *p_prv_ts = i ? &ts[i - 1] : NULL; + mbg_print_hr_timestamp( &ts[i], hns_latency[i], p_prv_ts, read_raw ); + } + + return 0; + + +fail: + return -1; + +} // show_fast_hr_timestamp_burst + + + +static /*HDR*/ +int do_mbgfasttstamp( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev ) +{ + int supported = 0; + int rc = mbg_dev_has_fast_hr_timestamp( dh, &supported ); + + if ( mbg_ioctl_err( rc, "mbg_has_fast_hr_timestamp" ) ) + goto done; + + if ( !supported ) + { + printf( "This device does not support fast (memory mapped) time stamps.\n" ); + goto done; + } + + if ( burst_read ) + show_fast_hr_timestamp_burst( dh ); + else + show_fast_hr_timestamp( dh ); + +done: + mbg_close_device( &dh ); + + return rc; + +} // do_mbgfasttstamp + + + +static /*HDR*/ +void usage( void ) +{ + mbg_print_usage_intro( pname, + "This example program reads fast high resolution time stamps.\n" + "\n" + "This is done using memory mapped I/O in the kernel driver, so\n" + "this works only with cards which support memory mapped I/O." + ); + mbg_print_help_options(); + mbg_print_opt_info( "-c", "run continuously" ); + mbg_print_opt_info( "-n num", "run num loops" ); + mbg_print_opt_info( "-b", "burst read" ); + mbg_print_opt_info( "-r", "read raw time stamps, no cycles" ); + mbg_print_device_options(); + puts( "" ); + +} // usage + + + +int main( int argc, char *argv[] ) +{ + int rc; + int c; + + mbg_print_program_info( pname, pversion, pcopyright ); + + // check command line parameters + while ( ( c = getopt( argc, argv, "bcn:rh?" ) ) != -1 ) + { + switch ( c ) + { + case 'b': + burst_read = 1; + break; + + case 'c': + loops = -1; + break; + + case 'n': + loops = atoi( optarg ); + break; + + case 'r': + read_raw = 1; + break; + + case 'h': + case '?': + default: + must_print_usage = 1; + } + } + + if ( must_print_usage ) + { + usage(); + return 1; + } + + #if !MBG_TGT_SUPP_MEM_ACC + printf( "** Memory mapped access not supported on this target platform.\n\n" ); + return 1; + #endif + + #if !defined( MBG_PC_CYCLES_SUPPORTED ) + printf( "** Warning: No cycles support to compute real latencies on this platform!\n" ); + + if ( !read_raw ) + { + read_raw = 1; + printf( "** Falling back to raw mode.\n" ); + } + + printf( "\n" ); + #endif + + // The function below checks which devices have been specified + // on the command, and for each device + // - tries to open the device + // - shows basic device info + // - calls the function passed as last parameter + rc = mbg_check_devices( argc, argv, optind, do_mbgfasttstamp ); + + return abs( rc ); +} diff --git a/mbggpscap/Makefile b/mbggpscap/Makefile new file mode 100755 index 0000000..6564761 --- /dev/null +++ b/mbggpscap/Makefile @@ -0,0 +1,39 @@ + +######################################################################### +# +# $Id: Makefile 1.7.1.2 2010/08/30 09:05:23 martin TEST $ +# +# Description: +# Makefile for mbggpscap. +# +# ----------------------------------------------------------------------- +# $Log: Makefile $ +# Revision 1.7.1.2 2010/08/30 09:05:23 martin +# Revision 1.7.1.1 2010/08/30 08:21:32 martin +# Revision 1.7 2009/07/24 10:31:16 martin +# Moved declarations to a common file which is now included. +# Revision 1.6 2008/12/22 11:56:58 martin +# Changed enumeration of source files. +# Define MBGDEVIO_SIMPLE to avoid inclusion of unnecessary modules. +# Revision 1.5 2007/03/02 11:45:10 martin +# Parameter "DEBUG=1" lets the target be built with debug enabled. +# Revision 1.4 2003/07/08 15:33:46 martin +# Added gpsutils.c to the module list. +# Revision 1.3 2003/04/25 10:21:06 martin +# Updated source module list. +# Revision 1.2 2002/11/21 14:56:31 martin +# New targets install and uninstall. +# Revision 1.1 2001/09/17 15:08:22 martin +# +######################################################################### + +TARGET = mbggpscap +INST_DIR = /usr/local/bin + +OBJS = $(TARGET).o +OBJS += mbgdevio.o +OBJS += gpsutils.o +OBJS += toolutil.o + +BASEDIR := .. +include $(BASEDIR)/Makefile diff --git a/mbggpscap/mbggpscap.c b/mbggpscap/mbggpscap.c new file mode 100755 index 0000000..bfa8804 --- /dev/null +++ b/mbggpscap/mbggpscap.c @@ -0,0 +1,391 @@ + +/************************************************************************** + * + * $Id: mbggpscap.c 1.10.1.2 2010/11/12 12:27:17 martin TEST $ + * + * Description: + * Main file for mbggpscap program which demonstrates how to access + * a Meinberg device via IOCTL calls and read entries from the time + * capture FIFO buffer. + * + * Please note that this may only work with devices which provide + * time capture input(s). + * + * ----------------------------------------------------------------------- + * $Log: mbggpscap.c $ + * Revision 1.10.1.2 2010/11/12 12:27:17 martin + * Improved reading capture events arriving at a high rate. + * Support validation of capture signals arriving at a constant rate. + * Revision 1.10.1.1 2010/03/10 16:42:33 martin + * Improved code execution paths. + * Revision 1.10 2009/09/29 15:02:15 martin + * Updated version number to 3.4.0. + * Revision 1.9 2009/07/24 09:50:08 martin + * Updated version number to 3.3.0. + * Revision 1.8 2009/06/19 12:38:51 martin + * Updated version number to 3.2.0. + * Revision 1.7 2009/03/19 17:04:26 martin + * Updated version number to 3.1.0. + * Updated copyright year to include 2009. + * Revision 1.6 2008/12/22 12:00:55 martin + * Updated description, copyright, revision number and string. + * Use unified functions from toolutil module. + * Accept device name(s) on the command line. + * Don't use printf() without format, which migth produce warnings + * with newer gcc versions. + * Revision 1.5 2007/07/24 09:32:26 martin + * Updated copyright to include 2007. + * Revision 1.4 2006/02/22 15:29:17 martin + * Support new ucap API. + * Print an error message if device can't be opened. + * Revision 1.3 2004/11/08 15:47:10 martin + * Using type cast to avoid compiler warning. + * Revision 1.2 2003/04/25 10:28:05 martin + * Use new functions from mbgdevio library. + * New program version v2.1. + * Revision 1.1 2001/09/17 15:08:22 martin + * + **************************************************************************/ + +// include Meinberg headers +#include +#include +#include // common utility functions + +// include system headers +#include +#include +#include +#include + + +#define USLEEP_INTV 10000 // [microseconds] + +static const char *pname = "mbggpscap"; +static const char *pversion = "v3.4.1"; +static const char *pcopyright = "(c) Meinberg 2001-2010"; + + +static int continuous; +static double nom_cap_intv; // nominal capture interval to check [s] +static double max_cap_jitter; // max allowed jitter [s] + +static int has_been_called; +static int must_check_intv; +static ulong err_cnt; +static PCPS_HR_TIME prv_ucap; + + +static /*HDR*/ +void show_ucap_status( ulong status ) +{ + // status bit definitions can be found in pcpsdefs.h. + + if ( status & PCPS_UCAP_OVERRUN ) // capture events have occurred too fast + printf( " << CAP OVR" ); + + if ( status & PCPS_UCAP_BUFFER_FULL ) // capture buffer has been full, events lost + printf( " << BUF OVR" ); + +} // show_ucap_status + + + +static /*HDR*/ +void show_ucap_event( const PCPS_HR_TIME *ucap ) +{ + char ws[80]; + + // Print converted date and time to a string: + mbg_snprint_hr_time( ws, sizeof( ws ), ucap ); + + // Print the time stamp, ucap->signal contains the channel number: + printf( "New capture: CH%i: %s", ucap->signal, ws ); + + if ( must_check_intv && has_been_called ) + { + double abs_delta; + double d = ucap->tstamp.sec - prv_ucap.tstamp.sec; + d += ( (double) ucap->tstamp.frac - prv_ucap.tstamp.frac ) / PCPS_HRT_BIN_FRAC_SCALE; + + printf( " %+.6f", d ); + + abs_delta = d - nom_cap_intv; + + if ( abs_delta < 0.0 ) + abs_delta = -abs_delta; + + if ( abs_delta > max_cap_jitter ) + err_cnt++; + + if ( err_cnt ) + printf( " ** %lu", err_cnt ); + } + + show_ucap_status( ucap->status ); + + prv_ucap = *ucap; + has_been_called = 1; + + printf( "\n" ); + +} // show_ucap_event + + + +// The function below is normally outdated, and show_ucap_event() +// above should be used if possible, together with the associated +// API calls. + +static /*HDR*/ +void show_gps_ucap( const TTM *ucap ) +{ + printf( "New capture: CH%i: %04i-%02i-%02i %2i:%02i:%02i.%07li", + ucap->channel, + ucap->tm.year, + ucap->tm.month, + ucap->tm.mday, + ucap->tm.hour, + ucap->tm.min, + ucap->tm.sec, + (ulong) ucap->tm.frac + ); + + show_ucap_status( ucap->tm.status ); + + printf( "\n" ); + +} // show_gps_ucap + + + +static /*HDR*/ +void check_serial_mode( MBG_DEV_HANDLE dh ) +{ + PORT_PARM port_parm; + int i; + int must_modify = 0; + + // read the clock's current port settings + int rc = mbg_get_gps_port_parm( dh, &port_parm ); + + if ( mbg_ioctl_err( rc, "mbg_get_gps_port_parm" ) ) + return; + + + // If one of the ports has been set to send user captures + // then the user capture buffer will most often be empty + // if we check for captures, so modify the port mode. + for ( i = 0; i < N_COM; i++ ) + { + if ( port_parm.mode[i] == STR_UCAP ) + { + port_parm.mode[i] = STR_UCAP_REQ; + must_modify = 1; + } + } + + if ( !must_modify ) + return; + + + rc = mbg_set_gps_port_parm( dh, &port_parm ); + + if ( mbg_ioctl_err( rc, "mbg_set_gps_port_parm" ) ) + return; + + printf( "NOTE: the clock's serial port mode has been changed.\n" ); + +} // check_serial_mode + + + +static /*HDR*/ +int do_mbggpscap( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev ) +{ + int rc; + + must_check_intv = continuous && ( nom_cap_intv != 0 ); + has_been_called = 0; + err_cnt = 0; + + if ( !_pcps_has_ucap( p_dev ) && !_pcps_is_gps( p_dev ) ) + { + printf( "This device type does not provide time capture inputs.\n" ); + return 0; + } + + check_serial_mode( dh ); + + printf( "Be sure the card has been properly configured to enable capture inputs.\n" ); + + // There's an older API which has been introduced with the first GPS boards + // and uses the TTM structure to return the capture events. However, that + // API call is slow and not very flexible, so a new set of API calls has been + // introduced to handle capture events. + // The new API calls are supported by all supported by all newer boards which + // provide user capture inputs, and also for older boards with a firmware update. + + if ( _pcps_has_ucap( p_dev ) ) // check if the new API is supported + { + // The new API provides the following functions: + // mbg_clr_ucap_buff() clear the on-board FIFO buffer + // mbg_get_ucap_entries() get the max number of FIFO entries, and the current number of entries + // mbg_get_ucap_event() read one entry from the FIFO + + PCPS_UCAP_ENTRIES ucap_entries; + + // retrieve and print information of the maximum number of events that can + // be stored in the on-board FIFO, and the number of events that are currently + // stored + rc = mbg_get_ucap_entries( dh, &ucap_entries ); + + if ( rc == MBG_SUCCESS ) + { + // Cards report they could save one more capture event + // than they actually do save, so adjust the reported value + // for a proper display. + if ( ucap_entries.max ) + ucap_entries.max--; + + printf( "\nOn-board FIFO: %u of %u entries used\n\n", + ucap_entries.used, ucap_entries.max ); + } + + // If the program is not to run continuously and no + // capture events are available then we're through. + if ( !continuous && ucap_entries.used == 0 ) + return 0; + + + printf( ( ucap_entries.used == 0 ) ? + "Waiting for capture events:\n" : + "Reading capture events:\n" + ); + + // Now read out all events from the FIFO and wait + // for new events if the FIFO is empty. + for (;;) + { + PCPS_HR_TIME ucap_event; + + rc = mbg_get_ucap_event( dh, &ucap_event ); + + if ( mbg_ioctl_err( rc, "mbg_get_ucap_event" ) ) + break; // an error has occurred + + // If a user capture event has been read then it + // has been removed from the card's FIFO buffer. + + // If the time stamp is not 0 then a new capture event has been retrieved. + if ( ucap_event.tstamp.sec || ucap_event.tstamp.frac ) + { + show_ucap_event( &ucap_event ); + continue; + } + + usleep( USLEEP_INTV ); // sleep, then try again + } + } + else // use the old API + { + printf( "Checking for capture events:\n" ); + + for (;;) + { + TTM ucap_ttm; + + rc = mbg_get_gps_ucap( dh, &ucap_ttm ); + + if ( mbg_ioctl_err( rc, "mbg_get_gps_ucap" ) ) + break; // an error has occurred + + + // If a user capture event has been read then it + // has been removed from the card's FIFO buffer. + + // If a new capture event has been available then + // the ucap.tm contains a time stamp. + if ( _pcps_time_is_read( &ucap_ttm.tm ) ) + show_gps_ucap( &ucap_ttm ); + + if ( !continuous ) + { + printf( "No capture event available!\n" ); + break; + } + + usleep( USLEEP_INTV ); // sleep, then try again + } + } + + return 0; + +} // do_mbggpscap + + + +static /*HDR*/ +void usage( void ) +{ + mbg_print_usage_intro( pname, + "This example program reads time capture events from a card.\n" + "This works only with cards which provide time capture inputs." + ); + mbg_print_help_options(); + mbg_print_opt_info( "-c", "run continuously" ); + mbg_print_opt_info( "-i val", "check interval between captures events [s]" ); + mbg_print_opt_info( "-j val", "max allowed jitter of capture interval [s]" ); + mbg_print_device_options(); + puts( "" ); + +} // usage + + + +int main( int argc, char *argv[] ) +{ + int rc; + int c; + + mbg_print_program_info( pname, pversion, pcopyright ); + + // check command line parameters + while ( ( c = getopt( argc, argv, "ci:j:h?" ) ) != -1 ) + { + switch ( c ) + { + case 'c': + continuous = 1; + break; + + case 'i': + nom_cap_intv = atof( optarg ); + break; + + case 'j': + max_cap_jitter = atof( optarg ); + break; + + case 'h': + case '?': + default: + must_print_usage = 1; + } + } + + if ( must_print_usage ) + { + usage(); + return 1; + } + + // The function below checks which devices have been specified + // on the command, and for each device + // - tries to open the device + // - shows basic device info + // - calls the function passed as last parameter + rc = mbg_check_devices( argc, argv, optind, do_mbggpscap ); + + return abs( rc ); +} diff --git a/mbghrtime/Makefile b/mbghrtime/Makefile new file mode 100755 index 0000000..e332204 --- /dev/null +++ b/mbghrtime/Makefile @@ -0,0 +1,39 @@ + +######################################################################### +# +# $Id: Makefile 1.7.1.2 2010/08/30 09:05:23 martin TEST $ +# +# Description: +# Makefile for mbghrtime. +# +# ----------------------------------------------------------------------- +# $Log: Makefile $ +# Revision 1.7.1.2 2010/08/30 09:05:23 martin +# Revision 1.7.1.1 2010/08/30 08:21:39 martin +# Revision 1.7 2009/07/24 10:31:16 martin +# Moved declarations to a common file which is now included. +# Revision 1.6 2008/12/22 11:56:59 martin +# Changed enumeration of source files. +# Define MBGDEVIO_SIMPLE to avoid inclusion of unnecessary modules. +# Revision 1.5 2007/03/02 11:45:10 martin +# Parameter "DEBUG=1" lets the target be built with debug enabled. +# Revision 1.4 2003/07/08 15:33:46 martin +# Added gpsutils.c to the module list. +# Revision 1.3 2003/04/25 10:21:06 martin +# Updated source module list. +# Revision 1.2 2002/11/21 14:56:31 martin +# New targets install and uninstall. +# Revision 1.1 2001/09/17 15:08:31 martin +# +######################################################################### + +TARGET = mbghrtime +INST_DIR = /usr/local/bin + +OBJS = $(TARGET).o +OBJS += mbgdevio.o +OBJS += toolutil.o +OBJS += gpsutils.o + +BASEDIR := .. +include $(BASEDIR)/Makefile diff --git a/mbghrtime/mbghrtime.c b/mbghrtime/mbghrtime.c new file mode 100755 index 0000000..86214a2 --- /dev/null +++ b/mbghrtime/mbghrtime.c @@ -0,0 +1,287 @@ + +/************************************************************************** + * + * $Id: mbghrtime.c 1.11.1.4 2011/01/28 12:04:08 martin TEST $ + * + * Description: + * Main file for mbghrtime program which demonstrates how to access + * a Meinberg device via IOCTL calls to read high resolution + * time stamps, if supported by the device. + * + * ----------------------------------------------------------------------- + * $Log: mbghrtime.c $ + * Revision 1.11.1.4 2011/01/28 12:04:08 martin + * Revision 1.11.1.3 2011/01/28 11:52:51 martin + * Revision 1.11.1.2 2011/01/28 11:51:13 martin + * Revision 1.11.1.1 2011/01/28 11:17:33 martin + * Starrted to support raw and burst. + * Revision 1.11 2010/05/21 12:54:33 martin + * Print warning if no cycles supported on the target platform + * and thus latencies can not be computed. + * Revision 1.10 2009/09/29 15:02:15 martin + * Updated version number to 3.4.0. + * Revision 1.9 2009/07/24 09:50:08 martin + * Updated version number to 3.3.0. + * Revision 1.8 2009/06/19 14:03:53 martin + * Use common mbg_print_hr_timestamp() for unified output format. + * Updated version number to 3.2.0. + * Revision 1.7 2009/03/20 11:45:16 martin + * Updated version number to 3.1.0. + * Updated copyright year to include 2009. + * Call mbg_get_hr_time_comp() instead of mbg_get_hr_time_cycles(). + * Revision 1.6 2008/12/22 12:02:00 martin + * Updated description, copyright, revision number and string. + * Use unified functions from toolutil module. + * Accept device name(s) on the command line. + * Revision 1.5 2007/07/24 09:32:41 martin + * Updated copyright to include 2007. + * Revision 1.4 2004/11/08 15:45:22 martin + * Modifications to support 64 bit systems in a clean way. + * Revision 1.3 2003/04/25 10:28:05 martin + * Use new functions from mbgdevio library. + * New program version v2.1. + * Revision 1.2 2001/11/30 10:01:49 martin + * Account for the modified definition of PCPS_HR_TIME which + * uses the new structure PCPS_TIME_STAMP now. + * Revision 1.1 2001/09/17 15:08:31 martin + * + **************************************************************************/ + +// include Meinberg headers +#include +#include +#include // common utility functions + +// include system headers +#include +#include +#include +#include +#include // gettimeofday() + + + +static const char *pname = "mbghrtime"; +static const char *pversion = "v3.4.0"; +static const char *pcopyright = "(c) Meinberg 2001-2009"; + + +#define MAX_TS_BURST 1000 + +static int loops; +static int burst_read; +static int read_raw; + + + +// The function below reads a number of time stamps and prints +// each timestamp immediately. This is not as fast as possible +// since printing the time stamp takes some time to execute. +// However, this can run continuously forever. + +static /*HDR*/ +int show_hr_timestamp( MBG_DEV_HANDLE dh ) +{ + PCPS_HR_TIME ht = { { 0 } }; + PCPS_HR_TIME prv_ht = { { 0 } }; + PCPS_TIME_STAMP *p = NULL; + int32_t hns_latency = 0; + int this_loops = loops; + + for (;;) + { + int rc = read_raw ? mbg_get_hr_time( dh, &ht ) : + mbg_get_hr_time_comp( dh, &ht, &hns_latency ); + + if ( mbg_ioctl_err( rc, "mbg_get_hr_time_..." ) ) + goto fail; + + mbg_print_hr_timestamp( &ht.tstamp, hns_latency, p, read_raw ); + + prv_ht = ht; + p = &prv_ht.tstamp; + + if ( this_loops > 0 ) + this_loops--; + + if ( this_loops == 0 ) + break; + + // if this_loops is < 0 then loop forever + } + + return 0; + +fail: + return -1; + +} // show_hr_timestamp + + + +// The function below takes a number of time stamps and saves +// them to a buffer. After the time stamps have been read +// a second loop prints the time stamps from the buffer. +// This way the time stamps are read in shorter intervals. +// However, this can not run continuously forever since +// the buffer size is somewhat limited. + +static /*HDR*/ +int show_hr_timestamp_burst( MBG_DEV_HANDLE dh ) +{ + PCPS_HR_TIME ht[MAX_TS_BURST] = { { { 0 } } }; + int32_t hns_latency[MAX_TS_BURST]; + int this_loops; + int i; + + this_loops = ( loops && ( loops < MAX_TS_BURST ) ) ? loops : MAX_TS_BURST; + + + if ( read_raw ) + { + for ( i = 0; i < this_loops; i++ ) + { + int rc = mbg_get_hr_time( dh, &ht[i] ); + + if ( mbg_ioctl_err( rc, "mbg_get_hr_time" ) ) + goto fail; + } + } + else + for ( i = 0; i < this_loops; i++ ) + { + int rc = mbg_get_hr_time_comp( dh, &ht[i], &hns_latency[i] ); + + if ( mbg_ioctl_err( rc, "mbg_get_hr_time_comp" ) ) + goto fail; + } + + for ( i = 0; i < this_loops; i++ ) + { + PCPS_HR_TIME *p_prv_ht = i ? &ht[i - 1] : NULL; + mbg_print_hr_timestamp( &ht[i].tstamp, hns_latency[i], &p_prv_ht->tstamp, read_raw ); + } + + return 0; + + +fail: + return -1; + +} // show_hr_timestamp_burst + + + +static /*HDR*/ +int do_mbghrtime( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev ) +{ + int supported = 0; + int rc = mbg_dev_has_hr_time( dh, &supported ); + + if ( mbg_ioctl_err( rc, "mbg_dev_has_hr_time" ) ) + goto done; + + if ( !supported ) + { + printf( "High resolution time not supported by this device.\n" ); + goto done; + } + + if ( burst_read ) + show_hr_timestamp_burst( dh ); + else + show_hr_timestamp( dh ); + +done: + mbg_close_device( &dh ); + + return rc; + +} // do_mbghrtime + + + +static /*HDR*/ +void usage( void ) +{ + mbg_print_usage_intro( pname, + "This example program reads high resolution time stamps (HR time)\n" + "from a device.\n" + "This works only for devices which support high resolution time (HR time)." + ); + mbg_print_help_options(); + mbg_print_opt_info( "-c", "run continuously" ); + mbg_print_opt_info( "-n num", "run num loops" ); + mbg_print_opt_info( "-b", "burst read" ); + mbg_print_opt_info( "-r", "read raw time stamps, no cycles" ); + mbg_print_device_options(); + puts( "" ); + +} // usage + + + +int main( int argc, char *argv[] ) +{ + int rc; + int c; + + mbg_print_program_info( pname, pversion, pcopyright ); + + // check command line parameters + while ( ( c = getopt( argc, argv, "bcn:rh?" ) ) != -1 ) + { + switch ( c ) + { + case 'b': + burst_read = 1; + break; + + case 'c': + loops = -1; + break; + + case 'n': + loops = atoi( optarg ); + break; + + case 'r': + read_raw = 1; + break; + + case 'h': + case '?': + default: + must_print_usage = 1; + } + } + + if ( must_print_usage ) + { + usage(); + return 1; + } + + + #if !defined( MBG_PC_CYCLES_SUPPORTED ) + printf( "** Warning: No cycles support to compute real latencies on this platform!\n" ); + + if ( !read_raw ) + { + read_raw = 1; + printf( "** Falling back to raw mode.\n" ); + } + + printf( "\n" ); + #endif + + + // The function below checks which devices have been specified + // on the command, and for each device + // - tries to open the device + // - shows basic device info + // - calls the function passed as last parameter + rc = mbg_check_devices( argc, argv, optind, do_mbghrtime ); + + return abs( rc ); +} diff --git a/mbgirigcfg/Makefile b/mbgirigcfg/Makefile new file mode 100755 index 0000000..fbeb4b5 --- /dev/null +++ b/mbgirigcfg/Makefile @@ -0,0 +1,36 @@ + +######################################################################### +# +# $Id: Makefile 1.5.1.2 2010/08/30 09:05:23 martin TEST $ +# +# Description: +# Makefile for mbgirigcfg. +# +# ----------------------------------------------------------------------- +# $Log: Makefile $ +# Revision 1.5.1.2 2010/08/30 09:05:23 martin +# Revision 1.5.1.1 2010/08/30 08:21:45 martin +# Revision 1.5 2009/07/24 10:31:17 martin +# Moved declarations to a common file which is now included. +# Revision 1.4 2008/12/22 11:56:59 martin +# Changed enumeration of source files. +# Define MBGDEVIO_SIMPLE to avoid inclusion of unnecessary modules. +# Revision 1.3 2007/03/02 11:45:10 martin +# Parameter "DEBUG=1" lets the target be built with debug enabled. +# Revision 1.2 2003/07/08 15:33:47 martin +# Added gpsutils.c to the module list. +# Revision 1.1 2003/04/25 10:42:10 martin +# +######################################################################### + +TARGET = mbgirigcfg +INST_DIR = /usr/local/sbin + +OBJS = $(TARGET).o +OBJS += mbgdevio.o +OBJS += toolutil.o +OBJS += gpsutils.o + +BASEDIR := .. +include $(BASEDIR)/Makefile + diff --git a/mbgirigcfg/mbgirigcfg.c b/mbgirigcfg/mbgirigcfg.c new file mode 100755 index 0000000..95f6238 --- /dev/null +++ b/mbgirigcfg/mbgirigcfg.c @@ -0,0 +1,728 @@ + +/************************************************************************** + * + * $Id: mbgirigcfg.c 1.10.1.4 2011/02/02 12:28:44 martin TEST $ + * + * Description: + * Main file for the mbgirigcfg program which can be used to configure + * the IRIG code frame and the UTC offset of the time contained in the + * IRIG code. + * + * ----------------------------------------------------------------------- + * $Log: mbgirigcfg.c $ + * Revision 1.10.1.4 2011/02/02 12:28:44 martin + * Revision 1.10.1.3 2010/08/30 08:22:24 martin + * Revision 1.10.1.2 2010/08/19 13:57:42 martin + * Revision 1.10.1.1 2010/08/19 11:26:12 martin + * Accept parameter -? to print usage. + * New parameter -i to let incoming TFOM flag be ignored. + * Revision 1.10 2009/09/29 15:02:15 martin + * Updated version number to 3.4.0. + * Revision 1.9 2009/07/24 09:50:08 martin + * Updated version number to 3.3.0. + * Revision 1.8 2009/06/19 12:38:51 martin + * Updated version number to 3.2.0. + * Revision 1.7 2009/03/19 17:07:16 martin + * Updated version number to 3.1.0. + * Updated copyright year to include 2009. + * Include mbgtime.h for some symbolic constants. + * Revision 1.6 2008/12/22 12:42:58 martin + * Updated description, copyright, revision number and string. + * Use unified functions from toolutil module. + * Accept device name(s) on the command line. + * Don't use printf() without format, which migth produce warnings + * with newer gcc versions. + * Revision 1.5 2007/07/24 09:34:46 martin + * Changes due to renamed library symbols. + * Updated copyright to include 2007. + * Revision 1.4 2006/08/28 10:08:17 martin + * Display TFOM settings only it the selected IRIG code format supports TFOM. + * Revision 1.3 2006/07/03 13:27:31 martin + * Source code cleanup and fixed a typo. + * Revision 1.2 2004/11/08 15:59:10 martin + * Support separate config of IRIG RX and TX. + * Changes due to renamed symbols. + * Revision 1.1 2003/04/25 10:42:10 martin + * + **************************************************************************/ + +// include Meinberg headers +#include +#include +#include +#include +#include +#include +#include + +// include system headers +#include +#include +#include +#include + + +static const char pname[] = "mbgirigcfg"; +static const char pversion[] = "v3.4.0"; +static const char pcopyright[] = "(c) Meinberg 2003-2009"; + +static const char str_yes[] = "YES"; +static const char str_no[] = "NO"; +static const char str_not_supp[] = " (not supp. by this frame type)"; + +static const char info_curr[] = "Current"; +static const char info_new[] = "New"; +static const char msg_rx[] = DEFAULT_OPT_NAME_IRIG_RX_EN; +static const char msg_tx[] = DEFAULT_OPT_NAME_IRIG_TX_EN; + +static IRIG_INFO irig_rx_info; +static IRIG_INFO irig_tx_info; +static MBG_REF_OFFS ref_offs; +static MBG_OPT_INFO opt_info; + +static int cfg_err; +static int changed_cfg_rx; +static int changed_cfg_tx; + +static const char *icode_rx_names[N_ICODE_RX] = DEFAULT_ICODE_RX_NAMES; +static const char *icode_rx_descr[N_ICODE_RX] = DEFAULT_ICODE_RX_DESCRIPTIONS_ENG; + +static const char *icode_tx_names[N_ICODE_TX] = DEFAULT_ICODE_TX_NAMES; +static const char *icode_tx_descr[N_ICODE_TX] = DEFAULT_ICODE_TX_DESCRIPTIONS_ENG; + +static int max_ref_offs_h = MBG_REF_OFFS_MAX / MINS_PER_HOUR; + + +static /*HDR*/ +int get_cfg( MBG_DEV_HANDLE dh, PCPS_DEV *pdev ) +{ + int rc_rx = MBG_SUCCESS; + int rc_tx = MBG_SUCCESS; + + if ( _pcps_is_irig_rx( pdev ) ) + { + rc_rx = mbg_get_irig_rx_info( dh, &irig_rx_info ); + + if ( rc_rx == MBG_SUCCESS && _pcps_has_ref_offs( pdev ) ) + rc_rx = mbg_get_ref_offs( dh, &ref_offs ); + + if ( rc_rx == MBG_SUCCESS && _pcps_has_opt_flags( pdev ) ) + rc_rx = mbg_get_opt_info( dh, &opt_info ); + } + + if ( _pcps_has_irig_tx( pdev ) ) + { + rc_tx = mbg_get_irig_tx_info( dh, &irig_tx_info ); + } + + + if ( rc_rx != MBG_SUCCESS ) + printf( "** Error reading current IRIG RX configuration.\n" ); + + if ( rc_tx != MBG_SUCCESS ) + printf( "** Error reading current IRIG TX configuration.\n" ); + + if ( rc_rx != MBG_SUCCESS || rc_tx != MBG_SUCCESS ) + return -1; //##++ + + return MBG_SUCCESS; + +} // get_cfg + + + +static /*HDR*/ +int save_cfg( MBG_DEV_HANDLE dh, PCPS_DEV *pdev ) +{ + int rc_rx = MBG_SUCCESS; + int rc_tx = MBG_SUCCESS; + + if ( _pcps_is_irig_rx( pdev ) ) + { + rc_rx = mbg_set_irig_rx_settings( dh, &irig_rx_info.settings ); + + if ( rc_rx == MBG_SUCCESS && _pcps_has_ref_offs( pdev ) ) + rc_rx = mbg_set_ref_offs( dh, &ref_offs ); + + if ( rc_rx == MBG_SUCCESS && _pcps_has_opt_flags( pdev ) ) + rc_rx = mbg_set_opt_settings( dh, &opt_info.settings ); + } + + if ( rc_rx == MBG_SUCCESS && _pcps_has_irig_tx( pdev ) ) + { + rc_tx = mbg_set_irig_tx_settings( dh, &irig_tx_info.settings ); + } + + if ( rc_rx != MBG_SUCCESS ) + printf( "** Error writing IRIG RX configuration.\n" ); + + if ( rc_tx != MBG_SUCCESS ) + printf( "** Error writing IRIG TX configuration.\n" ); + + if ( rc_rx != MBG_SUCCESS || rc_tx != MBG_SUCCESS ) + return -1; + + return MBG_SUCCESS; + +} // save_cfg + + + +static /*HDR*/ +void print_cfg_rx( const char *info, const char *msg ) +{ + int idx = irig_rx_info.settings.icode; + int ref_offs_h = ref_offs / MINS_PER_HOUR; + + printf( "%s %s:\n", info, msg ); + + printf( " " DEFAULT_STR_IRIG_FMT_EN ": %s, %s\n", + icode_rx_names[idx], + icode_rx_descr[idx] + ); + + printf( " " DEFAULT_IGNORE_RX_TFOM_EN ": %s%s\n", + ( irig_rx_info.settings.flags & IFLAGS_DISABLE_TFOM ) ? str_yes : str_no, + ( _idx_bit( idx ) & MSK_ICODE_RX_HAS_TFOM ) ? "" : str_not_supp ); + + printf( " " DEFAULT_STR_IRIG_OFFS_EN ": " ); + + if ( abs( ref_offs_h ) > max_ref_offs_h ) + printf( "** not configured **\n" ); + else + printf( "%+i h\n", ref_offs_h ); + + if ( opt_info.supp_flags & MBG_OPT_FLAG_STR_UTC ) + printf( " " DEFAULT_STR_IRIG_TIMESTR_UTC_EN ": %s\n", + ( opt_info.settings.flags & MBG_OPT_FLAG_STR_UTC ) ? + str_yes : str_no ); + +} // print_cfg_rx + + + +static /*HDR*/ +void print_cfg_tx( const char *info, const char *msg ) +{ + int idx = irig_tx_info.settings.icode; + + printf( "%s %s:\n", info, msg ); + + printf( " " DEFAULT_STR_IRIG_FMT_EN ": %s, %s\n", + icode_tx_names[idx], + icode_tx_descr[idx] + ); + + printf( " " DEFAULT_STR_TFOM_ALWAYS_SYNC_EN ": %s%s\n", + ( irig_tx_info.settings.flags & IFLAGS_DISABLE_TFOM ) ? str_yes : str_no, + ( _idx_bit( idx ) & MSK_ICODE_TX_HAS_TFOM ) ? "" : str_not_supp ); + + printf( " " DEFAULT_STR_IRIG_OUTPUT_LOC_TM_EN ": %s\n", + ( irig_tx_info.settings.flags & IFLAGS_TX_GEN_LOCAL_TIME ) ? + str_yes : str_no + ); + +} // print_cfg_tx + + + +static /*HDR*/ +void err_msg( PCPS_DEV *pdev, const char *msg ) +{ + printf( "The clock device %s %s.\n", _pcps_type_name( pdev ), msg ); + +} // err_msg + + + +static /*HDR*/ +void set_new_icode_rx( char *s ) +{ + int idx = atoi( s ); + + if ( idx >= N_ICODE_RX ) + { + printf( "** IRIG RX code index %i is out of range (0..%i).\n", + idx, N_ICODE_RX - 1 ); + cfg_err = 1; + return; + } + + if ( _is_supported( idx, irig_rx_info.supp_codes ) ) + { + irig_rx_info.settings.icode = idx; + changed_cfg_rx = 1; + } + else + { + printf( "** IRIG RX code \"%s\" not supported by this device.\n", + icode_rx_names[idx] ); + cfg_err = 1; + } + +} // set_new_icode_rx + + + +static /*HDR*/ +void set_new_ref_offs( char *s ) +{ + int new_ref_offs_h; + + new_ref_offs_h = atoi( s ); + + if ( abs( new_ref_offs_h ) > max_ref_offs_h ) + { + printf( "** New IRIG time offset %ih exceeds range (%+ih..%+ih).\n", + new_ref_offs_h, -max_ref_offs_h, max_ref_offs_h ); + cfg_err = 1; + } + else + { + ref_offs = new_ref_offs_h * MINS_PER_HOUR; + changed_cfg_rx = 1; + } + +} // set_new_ref_offs + + + +static /*HDR*/ +void set_new_str_utc( char *s ) +{ + int this_cfg_err; + + if ( !( opt_info.supp_flags & MBG_OPT_FLAG_STR_UTC ) ) + return; // not supported + + + this_cfg_err = 0; + + if ( strcmp( s, "1" ) == 0 ) + opt_info.settings.flags |= MBG_OPT_FLAG_STR_UTC; + else + if ( strcmp( s, "0" ) == 0 ) + opt_info.settings.flags &= ~MBG_OPT_FLAG_STR_UTC; + else + this_cfg_err = 1; + + if ( this_cfg_err ) + cfg_err = 1; + else + changed_cfg_rx = 1; + +} // set_new_str_utc + + + +static /*HDR*/ +void set_new_icode_tx( char *s ) +{ + int idx = atoi( s ); + + if ( idx >= N_ICODE_TX ) + { + printf( "** IRIG TX code index %i is out of range (0..%i).\n", + idx, N_ICODE_TX - 1 ); + cfg_err = 1; + return; + } + + if ( _is_supported( idx, irig_tx_info.supp_codes ) ) + { + irig_tx_info.settings.icode = idx; + changed_cfg_tx = 1; + } + else + { + printf( "** IRIG TX code \"%s\" not supported by this device.\n", + icode_tx_names[idx] ); + cfg_err = 1; + } + +} // set_new_icode_tx + + + +static /*HDR*/ +void set_new_irig_tx_local( char *s ) +{ + int this_cfg_err = 0; + + if ( strcmp( s, "1" ) == 0 ) + irig_tx_info.settings.flags |= IFLAGS_TX_GEN_LOCAL_TIME; + else + if ( strcmp( s, "0" ) == 0 ) + irig_tx_info.settings.flags &= ~IFLAGS_TX_GEN_LOCAL_TIME; + else + this_cfg_err = 1; + + if ( this_cfg_err ) + cfg_err = 1; + else + changed_cfg_tx = 1; + +} // set_new_irig_tx_local + + + +static /*HDR*/ +void set_new_tfom_flag( char *s, IRIG_SETTINGS *p, int *changed_flag ) +{ + if ( !(_idx_bit( p->icode ) & MSK_ICODE_TX_HAS_TFOM ) ) + return; // not supported + + + if ( strcmp( s, "1" ) == 0 ) + p->flags |= IFLAGS_DISABLE_TFOM; + else + if ( strcmp( s, "0" ) == 0 ) + p->flags &= ~IFLAGS_DISABLE_TFOM; + else + cfg_err = 1; + + *changed_flag = 1; + +} // set_new_tfom_flag + + + +static /*HDR*/ +int chk_dev_rx( const PCPS_DEV *pdev ) +{ + if ( !_pcps_is_irig_rx( pdev ) ) + { + printf( "** This device is no IRIG receiver.\n" ); + cfg_err = 1; + return 0; + } + + return 1; + +} // chk_dev_rx + + + +static /*HDR*/ +int chk_dev_tx( const PCPS_DEV *pdev ) +{ + if ( !_pcps_has_irig_tx( pdev ) ) + { + printf( "** This device has no IRIG transmitter.\n" ); + cfg_err = 1; + return 0; + } + + return 1; + +} // chk_dev_tx + + + +static /*HDR*/ +void check_cmd_line( int argc, char *argv[], const PCPS_DEV *pdev ) +{ + int i; + + for ( i = 1; i < argc; i++ ) + { + if ( strcmp( argv[i], "-?" ) == 0 ) + { + must_print_usage = 1; + continue; + } + + if ( strcmp( argv[i], "-h" ) == 0 ) + { + must_print_usage = 1; + continue; + } + + if ( strcmp( argv[i], "--help" ) == 0 ) + { + must_print_usage = 1; + continue; + } + + if ( strcmp( argv[i], "-r" ) == 0 ) // IRIG RX code frame + { + if ( ++i < argc ) + if ( chk_dev_rx( pdev ) ) + set_new_icode_rx( argv[i] ); + + continue; + } + + if ( strcmp( argv[i], "-o" ) == 0 ) // IRIG time offset from UTC + { + if ( ++i < argc ) + if ( chk_dev_rx( pdev ) ) + set_new_ref_offs( argv[i] ); + + continue; + } + + if ( strcmp( argv[i], "-u" ) == 0 ) // Option flag: serial output always UTC + { + if ( ++i < argc ) + if ( chk_dev_rx( pdev ) ) + set_new_str_utc( argv[i] ); + + continue; + } + + if ( strcmp( argv[i], "-t" ) == 0 ) // IRIG TX code frame + { + if ( ++i < argc ) + if ( chk_dev_tx( pdev ) ) + set_new_icode_tx( argv[i] ); + + continue; + } + + if ( strcmp( argv[i], "-l" ) == 0 ) // Option flag: transmit local time, not UTC + { + if ( ++i < argc ) + if ( chk_dev_tx( pdev ) ) + set_new_irig_tx_local( argv[i] ); + + continue; + } + + if ( strcmp( argv[i], "-s" ) == 0 ) // Option flag: send TFOM as always "sync" + { + if ( ++i < argc ) + if ( chk_dev_tx( pdev ) ) + set_new_tfom_flag( argv[i], &irig_tx_info.settings, &changed_cfg_tx ); + + continue; + } + + if ( strcmp( argv[i], "-i" ) == 0 ) // Option flag: ignore incoming TFOM flag, alway sync + { + if ( ++i < argc ) + if ( chk_dev_rx( pdev ) ) + set_new_tfom_flag( argv[i], &irig_rx_info.settings, &changed_cfg_rx ); + + continue; + } + + } + +} // check_cmd_line + + + +static /*HDR*/ +void usage( void ) +{ + const char *frame_fmt = " %4i %s, %s\n"; + int i; + + printf( + "Usage: %s [-h]|[option] [option] ...\n" + "\n", + pname + ); + + printf( + " -h or --help prints this info\n" + "\n" + ); + + + printf( + "Options supported by IRIG receivers:\n" + "\n" + ); + + printf( + " -r code specifies the IRIG receiver code format, where \"code\" \n" + " can be one a number according to the table below:\n" + ); + + for ( i = 0; i < N_ICODE_RX; i++ ) + printf( frame_fmt, i, icode_rx_names[i], icode_rx_descr[i] ); + + printf( "\n" ); + + printf( + " -o offs specifies the IRIG input time offset from UTC, in hours,\n" + " where \"offs\" can be a value in the range %+i..%+i\n" + "\n", + -max_ref_offs_h, max_ref_offs_h + ); + + printf( + " -u flag determines whether the time string sent via the\n" + " board's serial output contains always UTC time\n" + " or the same time as received from the IRIG input\n" + " signal. \"flag\" can be \"1\" for always UTC,\n" + " or \"0\" for IRIG time.\n" + "\n" + ); + + + printf( + "Options supported by IRIG transmitters:\n" + "\n" + ); + + printf( + " -t code specifies the IRIG transmitter code format, where \"code\" \n" + " can be one a number according to the table below:\n" + ); + + for ( i = 0; i < N_ICODE_TX; i++ ) + printf( frame_fmt, i, icode_tx_names[i], icode_tx_descr[i] ); + + printf( "\n" ); + + printf( + " -l flag determines whether IRIG output shall contain local\n" + " time, or UTC. \"flag\" must be \"1\" for local time,\n" + " or \"0\" for UTC.\n" + "\n" + ); + + printf( + " -s flag If \"flag\" is set to \"1\" then the TFOM qualifier in the\n" + " IRIG output is always set to \"synchronized\". If it is \"0\" \n" + " then the qualifier reflects the current status of the input signal.\n" + " Please note that most IRIG codes do not support a TFOM qualifier.\n" + "\n" + ); + + + printf( + "If no parameters are given the program reports the current settings.\n" + "Please note that not all IRIG codes must be supported by all devices.\n" + ); + +} // usage + + + +static /*HDR*/ +void help_info( void ) +{ + printf( "\nFor help type \"%s -h\"\n", pname ); + +} // help_info + + + +static /*HDR*/ +int do_mbgirigcfg( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev ) +{ + const char *no_irig = "is not an IRIG code receiver"; + PCPS_DEV dev = { { 0 } }; + int exit_code = 0; + int rc = 0; + + { + // if success, read the current IRIG configuration + if ( rc == MBG_SUCCESS ) + rc = get_cfg( dh, &dev ); + } + + +// check_cmd_line( argc, argv, &dev ); + + + if ( cfg_err ) + { + help_info(); + exit_code = 1; + goto done; + } + + + // At this point we shall either report or modify the current + // configuration. If there has been an error accessing the + // device, or the device is not an IRIG receiver, then we must + // print a message. + + if ( dh == MBG_INVALID_DEV_HANDLE ) + { + printf( "** Error opening the device.\n" ); + exit_code = 3; + goto done; + } + + if ( rc != MBG_SUCCESS ) + { + exit_code = 3; + goto done; + } + + if ( !_pcps_has_irig( &dev ) ) + { + err_msg( &dev, no_irig ); + exit_code = 2; + goto done; + } + + + if ( changed_cfg_rx || changed_cfg_tx ) + { + + if ( changed_cfg_rx ) + print_cfg_rx( info_new, msg_rx ); + + if ( changed_cfg_tx ) + print_cfg_tx( info_new, msg_tx ); + + rc = save_cfg( dh, &dev ); + + if ( mbg_ioctl_err( rc, "save IRIG configuration" ) ) + exit_code = 3; + } + else + { + if ( _pcps_is_irig_rx( &dev ) ) + print_cfg_rx( info_curr, msg_rx ); + + if ( _pcps_has_irig_tx( &dev ) ) + print_cfg_tx( info_curr, msg_tx ); + + help_info(); + } + +done: + printf( "\n" ); + + if ( dh != MBG_INVALID_DEV_HANDLE ) + mbg_close_device( &dh ); + + return exit_code; + +} // do_mbgirigcfg + + + +int main( int argc, char *argv[] ) +{ + int rc; + + mbg_print_program_info( pname, pversion, pcopyright ); + + check_cmd_line( argc, argv, NULL ); + + if ( must_print_usage ) + { + usage(); + return 1; + } + + + // The function below checks which devices have been specified + // on the command, and for each device + // - tries to open the device + // - shows basic device info + // - calls the function passed as last parameter + //##+++++++++++ rc = mbg_check_devices( argc, argv, optind, do_mbgirigcfg ); + rc = mbg_check_devices( argc, argv, 0, do_mbgirigcfg ); + + return abs( rc ); +} diff --git a/mbglib/bsd/mbg_bsd.h b/mbglib/bsd/mbg_bsd.h new file mode 100755 index 0000000..9efef59 --- /dev/null +++ b/mbglib/bsd/mbg_bsd.h @@ -0,0 +1,49 @@ + +/************************************************************************** + * + * $Id: mbg_bsd.h 1.1.1.1 2011/02/04 14:44:33 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * OS dependend definitions/redefinitions for *BSD. + * + * ----------------------------------------------------------------------- + * $Log: mbg_bsd.h $ + * Revision 1.1.1.1 2011/02/04 14:44:33 martin + * Revision 1.1 2011/01/26 16:09:33 martin + * Initial revision. + * + **************************************************************************/ + +#ifndef _MBG_BSD_H +#define _MBG_BSD_H + + +/* Other headers to be included */ + +#include +#include +#include + + +#ifdef _MBG_BSD + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + +// definitions for clock() support in kernel drivers +// extern unsigned long volatile jiffies; //##++ this is just a workaround to build without errors +// #define clock() jiffies + + +/* End of header body */ + +#undef _ext + +#endif /* _MBG_BSD_H */ + diff --git a/mbglib/bsd/pci_bsd.h b/mbglib/bsd/pci_bsd.h new file mode 100755 index 0000000..f032234 --- /dev/null +++ b/mbglib/bsd/pci_bsd.h @@ -0,0 +1,64 @@ + +/************************************************************************** + * + * $Id: pci_bsd.h 1.1 2011/01/26 16:09:33 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions to enable usage of Meinberg PCI function calls + * with *BSD. + * + * ----------------------------------------------------------------------- + * $Log: pci_bsd.h $ + * Revision 1.1 2011/01/26 16:09:33 martin + * Initial revision. + * + **************************************************************************/ + +#ifndef _PCI_BSD_H +#define _PCI_BSD_H + + +/* Other headers to be included */ + +#include + +#include +//##++ #include + + +#ifdef _PCI_BSD + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + +//##++ update comment +// The pcibios_..() calls use below are not supported by +// recent 2.6.x kernels. However, those kernels should use +// the PNP PCI interface anyway, whereas the functions below +// are only used by non-PNP environments. + +#define _mbg_pci_find_bios( _p1, _p2, _p3 ) \ + ( pcibios_present() ? PCI_SUCCESS : PCI_NO_SUCCESS ) + +#define _mbg_pci_find_device( _did, _vid, _ix, _pbn, _pdfn ) \ + pcibios_find_device( (_vid), (_did), (_ix), (_pbn), (_pdfn) ) + +#define _mbg_pci_read_cfg_byte pcibios_read_config_byte +#define _mbg_pci_read_cfg_word pcibios_read_config_word +#define _mbg_pci_read_cfg_dword pcibios_read_config_dword + +#define _mbg_pci_write_cfg_byte pcibios_write_config_byte +#define _mbg_pci_write_cfg_word pcibios_write_config_word +#define _mbg_pci_write_cfg_dword pcibios_write_config_dword + +/* End of header body */ + +#undef _ext + +#endif /* _PCI_BSD_H */ diff --git a/mbglib/bsd/rsrc_bsd.c b/mbglib/bsd/rsrc_bsd.c new file mode 100755 index 0000000..b65c95a --- /dev/null +++ b/mbglib/bsd/rsrc_bsd.c @@ -0,0 +1,80 @@ + +/************************************************************************** + * + * $Id: rsrc_bsd.c 1.1 2011/01/26 16:09:33 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Interface functions for the Linux resource manager. + * + * ----------------------------------------------------------------------- + * $Log: rsrc_bsd.c $ + * Revision 1.1 2011/01/26 16:09:33 martin + * Initial revision. + * + **************************************************************************/ + +#define _RSRC_BSD + #include +#undef _RSRC_BSD + + +extern const char *pcps_driver_name; + + +#if 1 //##++ ||defined( KERNEL_VERSION ) && ( LINUX_VERSION_CODE < KERNEL_VERSION( 2, 6, 0 ) ) + + // check_region(), request_region(), and release_region() used in 2.2.x and + // maybe early 2.4.x kernels have been replaced by more versatile functions. + // Additionally, there have been defined some macros with the names + // of the old functions, but calling the new functions. Those macros are still + // supported by early 2.6.x kernels, but may not be supported anymore in the future. + // So if those macros don't exist then only the old functions can be used and we + // use some macros with the new names and call the old functions. + + #if !defined( request_region ) + #define __check_region( _rsrc, _start, _n ) \ + check_region( (_start), (_n) ) + + #define __request_region( _rsrc, _start, _n, _name ) \ + request_region( (_start), (_n), (_name) ) + + #define __release_region( _rsrc, _start, _n ) \ + release_region( (_start), (_n) ) + #endif + +#endif + + + +/*HDR*/ +int rsrc_alloc_ports( ushort port, ushort n, ushort decode_width ) +{ +#if 0 //##++ + int rc = __check_region( &ioport_resource, port, n ); + + if ( rc < 0 ) + return( rc ); + + + __request_region( &ioport_resource, port, n, pcps_driver_name ); +#endif + + return 0; + +} // rsrc_alloc_ports + + + +/*HDR*/ +void rsrc_dealloc_ports( ushort port, ushort n ) +{ +#if 0 //##++ + __release_region( &ioport_resource, port, n ); +#endif + +} // rsrc_dealloc_ports + + + diff --git a/mbglib/bsd/rsrc_bsd.h b/mbglib/bsd/rsrc_bsd.h new file mode 100755 index 0000000..ba1af48 --- /dev/null +++ b/mbglib/bsd/rsrc_bsd.h @@ -0,0 +1,70 @@ + +/************************************************************************** + * + * $Id: rsrc_bsd.h 1.1 2011/01/26 16:09:34 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes for rsrc_bsd.c. + * + * ----------------------------------------------------------------------- + * $Log: rsrc_bsd.h $ + * Revision 1.1 2011/01/26 16:09:34 martin + * Initial revision. + * + **************************************************************************/ + +#ifndef _RSRC_BSD_H +#define _RSRC_BSD_H + + +/* Other headers to be included */ + +#include +#include +#include + +#ifdef _RSRC_BSD + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + +/* End of header body */ + +#undef _ext + + +/* function prototypes: */ + +#define _rsrc_alloc_ports( _ph, _pb, _n, _w ) \ + rsrc_alloc_ports( _pb, _n, _w ) + +#define _rsrc_dealloc_ports( _ph, _pb, _n ) \ + rsrc_dealloc_ports( _pb, _n ) + + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + + int rsrc_alloc_ports( ushort port, ushort n, ushort decode_width ) ; + void rsrc_dealloc_ports( ushort port, ushort n ) ; + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +#endif /* _RSRC_BSD_H */ diff --git a/mbglib/common/amccdefs.h b/mbglib/common/amccdefs.h new file mode 100755 index 0000000..1d68cbe --- /dev/null +++ b/mbglib/common/amccdefs.h @@ -0,0 +1,111 @@ + +/************************************************************************** + * + * $Id: amccdefs.h 1.2 2007/06/06 10:16:53 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions to be used with AMCC PCI interface chips. + * + * ----------------------------------------------------------------------- + * $Log: amccdefs.h $ + * Revision 1.2 2007/06/06 10:16:53 martin + * Moved some IRQ bit masks here. + * Revision 1.1 2000/07/20 09:19:39Z MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _AMCCDEFS_H +#define _AMCCDEFS_H + + +/* Other headers to be included */ + + +#ifdef _AMCCDEFS + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + + +// The following operation registers are implemented +// in the S5933. The registers can be accessed via port +// I/O to base_addr_0 + offset as defined below: + +#define AMCC_OP_REG_OMB1 0x00 // Outgoing Mail Box 1 +#define AMCC_OP_REG_OMB2 0x04 // Outgoing Mail Box 2 +#define AMCC_OP_REG_OMB3 0x08 // Outgoing Mail Box 3 +#define AMCC_OP_REG_OMB4 0x0C // Outgoing Mail Box 4 +#define AMCC_OP_REG_IMB1 0x10 // Incoming Mail Box 1 +#define AMCC_OP_REG_IMB2 0x14 // Incoming Mail Box 2 +#define AMCC_OP_REG_IMB3 0x18 // Incoming Mail Box 3 +#define AMCC_OP_REG_IMB4 0x1C // Incoming Mail Box 4 +#define AMCC_OP_REG_FIFO 0x20 // FIFO Register +#define AMCC_OP_REG_MWAR 0x24 // Master Write Address Register +#define AMCC_OP_REG_MWTC 0x28 // Master Write Transfer Count Register +#define AMCC_OP_REG_MRAR 0x2C // Master Read Address Register +#define AMCC_OP_REG_MRTC 0x30 // Master Read Transfer Count Register +#define AMCC_OP_REG_MBEF 0x34 // Mailbox Empty/Full Status +#define AMCC_OP_REG_INTCSR 0x38 // Interrupt Control/Status Register +#define AMCC_OP_REG_MCSR 0x3C // Bus Master Control/Status Register + +#define AMCC_OP_REG_RANGE_S5933 0x40 // number of operation registers + + + +// The following operation registers are implemented +// in the S5920. The registers can be accessed via port +// I/O to base_addr_0 + offset as defined below: + +#define AMCC_OP_REG_OMB 0x0C // Outgoing Mail Box +#define AMCC_OP_REG_IMB 0x1C // Incoming Mail Box +#define AMCC_OP_REG_MBEF 0x34 // Mailbox Empty/Full Status +#define AMCC_OP_REG_INTCSR 0x38 // Interrupt Control/Status Register +#define AMCC_OP_REG_RCR 0x3C // Reset Control Register +#define AMCC_OP_REG_PTCR 0x60 // Pass-Thru Configuration Register + +#define AMCC_OP_REG_RANGE_S5920 0x64 // number of operation registers + + + +// The following bit masks are used by the drivers in order to +// control interrupts on the PCI bus: + +#define AMCC_INT_MASK 0x0000FFFFL +#define AMCC_INT_ENB ( 1L << 12 ) +#define AMCC_INT_FLAG ( 1L << 17 ) +#define AMCC_INT_ACK ( AMCC_INT_ENB | AMCC_INT_FLAG ) + + +/* End of header body */ + +#undef _ext + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + +/* (no header definitions found) */ + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +#endif /* _AMCCDEFS_H */ diff --git a/mbglib/common/cnv_wday.h b/mbglib/common/cnv_wday.h new file mode 100755 index 0000000..7736135 --- /dev/null +++ b/mbglib/common/cnv_wday.h @@ -0,0 +1,100 @@ + +/***************************************************************************/ +/* */ +/* File: CNV_WDAY.H $Revision: 1.1 $ */ +/* */ +/* Project: Common C Library */ +/* */ +/* Compiler: Borland C++ and others */ +/* */ +/* Author: M. Burnicki, Meinberg Funkuhren */ +/* */ +/* */ +/* Description: */ +/* This header provides macros which can be used to convert */ +/* day-of-week codes from one convention to another. */ +/* */ +/* The conventions supported yet have been named as describrd below: */ +/* */ +/* name range assignment used with ... */ +/* ---------------------------------------------------------------- */ +/* sun06 0..6 0 = Sunday RTC72421, DOS1.10+, Novell */ +/* sun17 1..7 1 = Sunday RTC146818 */ +/* mon17 1..7 1 = Monday DCF77 */ +/* */ +/***************************************************************************/ + + +#ifndef _CNV_WDAY_H + + +/* Other headers to be included */ + + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _CNV_WDAY + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + + +/* use the following macros if sure that the source value is in range */ + +#define _wday_mon17_to_mon06( d ) ( ( d ) - 1 ) +#define _wday_mon06_to_mon17( d ) ( ( d ) + 1 ) + +#define _wday_mon17_to_sun17( d ) ( ( (d) >= 7 ) ? 1 : ( (d) + 1 ) ) +#define _wday_sun17_to_mon17( d ) ( ( (d) < 2 ) ? 7 : ( (d) - 1 ) ) + +#define _wday_mon17_to_sun06( d ) ( ( (d) >= 7 ) ? 0 : (d) ) +#define _wday_sun06_to_mon17( d ) ( ( (d) < 1 ) ? 7 : (d) ) + +#define _wday_sun17_to_sun06( d ) ( (d) - 1 ) +#define _wday_sun06_to_sun17( d ) ( (d) + 1 ) + + +/* use the macros below to check for valid ranges */ + +#define _inrng( d, what, min, lt, max, gt ) ( ( (d) < (min) ) ? (lt) : ( ( (d) > (max) ) ? (gt) : (what) ) ) + /* _inrng is a local macro which does the boundary check */ + /* d the day code to be converted */ + /* what the conversion algorithm if in range */ + /* min, lt if (d) is below (min), the macro returns (lt) */ + /* max, gt if (d) is above (max), the macro returns (gt) */ + +#define _wday_chk_mon17_to_sun17( d ) _inrng( (d), _wday_mon17_to_sun17( (d) ), 1, 7, 7, 6 ) +#define _wday_chk_sun17_to_mon17( d ) _inrng( (d), _wday_sun17_to_mon17( (d) ), 1, 7, 7, 6 ) + + +#define _wday_chk_mon17_to_sun06( d ) _inrng( (d), _wday_mon17_to_sun06( (d) ), 1, 1, 7, 0 ) +#define _wday_chk_sun06_to_mon17( d ) _inrng( (d), _wday_sun06_to_mon17( (d) ), 0, 1, 6, 6 ) + +#define _wday_chk_sun17_to_sun06( d ) _inrng( (d), _wday_sun17_to_sun06( (d) ), 1, 0, 7, 6 ) +#define _wday_chk_sun06_to_sun17( d ) _inrng( (d), _wday_sun06_to_sun17( (d) ), 0, 1, 6, 7 ) + + +/* function prototypes: */ + +/* #include not needed yet */ + +/* End of header body */ + + +#undef _ext + +#ifdef __cplusplus +} +#endif + +#define _CNV_WDAY_H + +#endif /* _CNV_WDAY_H */ + diff --git a/mbglib/common/ctry.c b/mbglib/common/ctry.c new file mode 100755 index 0000000..ef647d0 --- /dev/null +++ b/mbglib/common/ctry.c @@ -0,0 +1,177 @@ + +/************************************************************************** + * + * $Id: ctry.c 1.7 2010/07/15 08:26:57 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Functions providing support for different country settings + * and languages. + * + * Some OS dependent functions may be required which can be found + * in the OS dependent modules ctry_xxx.c. + * + * ----------------------------------------------------------------------- + * $Log: ctry.c $ + * Revision 1.7 2010/07/15 08:26:57 martin + * Added clstr_lng() implemented by stefan returning a translated string + * by giving the different strings as function arguments. + * Revision 1.6 2007/03/29 12:21:51 martin + * New functions lstr_idx() and lstr_array_idx(). + * Revision 1.1 2010/06/01 07:57:03 philipp + * Revision 1.5 2004/10/26 07:39:37Z martin + * Use C99 fixed-size definitions where appropriate. + * Revision 1.4 2001/09/14 12:02:12 MARTIN + * Modified parameters for lstr_lng(). + * Revision 1.3 2000/11/27 14:09:24 MARTIN + * Replaced lstr() by lstr_lng() with takes a language paramter to allow + * retrieval of strings for another than the current language. + * A new macro _lstr() has been added to ctry.h which calls lstr_lng() + * passing the current language. + * The functions ctry_fmt_dt() and ctry_fmt_times() and associated + * definitions have been moved to a new module ctry_fmt.c/ctry_fmt.h. + * Revision 1.2 2000/07/21 10:00:08 MARTIN + * Initial revision + * + **************************************************************************/ + +#define _CTRY + #include +#undef _CTRY + +#include +#include +#include + + +// Return the index of a CLSTR component for a +// certain language lng + +/*HDR*/ +int lstr_idx( CLSTR s, int lng ) +{ + if ( lng >= N_LNG ) // if lng out of range + return 0; // use default index + + // If there are duplicate strings for several languages + // then the duplicate strings may be NULL, in which case + // the string at index 0 must be used. + return s[lng] ? lng : 0; + +} // lstr_idx + + + +// Return the index of a CLSTR component for a +// certain language lng out of an array of CLSTRs. +// CLSTR s: the array of CLSTRs +// int idx: the index of the array element +// int n_lng: the number of supported languages +// int lng: the language for which the inex shall be retrieved + +/*HDR*/ +int lstr_array_idx( CLSTR s, int idx, int n_lng, int lng ) +{ + int str_idx = n_lng * idx; + return str_idx + lstr_idx( &s[str_idx], lng ); + +} // lstr_array_idx + + + +/*HDR*/ +const char *lstr_lng( CLSTR s, int lng ) +{ + return s[lstr_idx( s, lng)]; + +} // lstr_lng + + + +/*HDR*/ +void ctry_setup( CTRY_CODE code ) +{ + language = LNG_ENGLISH; + ctry.code = code; + + switch ( code ) + { + case CTRY_US: + ctry.dt_fmt = DT_FMT_MMDDYYYY; + ctry.dt_sep = DT_SEP_MINUS; + ctry.tm_fmt = TM_FMT_24H; + ctry.tm_sep = TM_SEP_COLON; + break; + + + case CTRY_UK: + ctry.dt_fmt = DT_FMT_DDMMYYYY; + ctry.dt_sep = DT_SEP_SLASH; + ctry.tm_fmt = TM_FMT_24H; + ctry.tm_sep = TM_SEP_COLON; + break; + + + default: + language = LNG_GERMAN; + ctry.code = CTRY_GERMANY; + + ctry.dt_fmt = DT_FMT_DDMMYYYY; + ctry.dt_sep = DT_SEP_DOT; + ctry.tm_fmt = TM_FMT_24H; + ctry.tm_sep = TM_SEP_COLON; + + } /* switch */ + + +} /* ctry_setup */ + + + +/*HDR*/ +void ctry_next( void ) +{ + switch ( ctry.code ) + { + case CTRY_GERMANY: + ctry_setup( CTRY_US ); + break; + + case CTRY_US: + ctry_setup( CTRY_UK ); + break; + + default: + ctry_setup( CTRY_GERMANY ); + break; + + } // switch + +} // ctry_next + + + +/*HDR*/ +const char *clstr_lng( int index, ... ) +{ + const char *ret; + const char *default_ret; + int i; + typedef char *MY_LSTR; + + va_list ap; + va_start( ap, index ); + + ret = va_arg( ap, MY_LSTR ); + default_ret = ret; + + for ( i = 1; ( i <= index ) && ( ret != NULL ); i++ ) + ret = va_arg( ap, MY_LSTR ); + + va_end( ap ); + + return ret ? ret : default_ret; + +} // clstr_lng + diff --git a/mbglib/common/ctry.h b/mbglib/common/ctry.h new file mode 100755 index 0000000..9c39a28 --- /dev/null +++ b/mbglib/common/ctry.h @@ -0,0 +1,233 @@ + +/************************************************************************** + * + * $Id: ctry.h 1.11 2010/07/15 08:33:41 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes for ctry.c. + * + * ----------------------------------------------------------------------- + * $Log: ctry.h $ + * Revision 1.11 2010/07/15 08:33:41 martin + * Added some macros implemented by Stefan. + * Updated function prototypes. + * Revision 1.10 2007/03/29 12:21:10 martin + * Updated function prototypes. + * Revision 1.1 2010/06/01 07:57:04 philipp + * Revision 1.9 2004/10/26 07:38:50Z martin + * Redefined interface data types using C99 fixed-size definitions. + * Updated function prototypes. + * Revision 1.8 2004/04/14 08:47:28 martin + * Pack structures 1 byte aligned. + * Revision 1.7 2002/02/19 09:28:00Z MARTIN + * Use new header mbg_tgt.h to check the target environment. + * Revision 1.6 2001/09/14 12:04:40 MARTIN + * Modified definition for CLSTR. + * Updated function prototypes. + * Revision 1.5 2001/02/28 15:07:06 MARTIN + * Modified preprocessor syntax. + * Revision 1.4 2000/11/27 14:13:27 MARTIN + * New types CLSTR, PLSTR, and PCLSTR. + * New macro _lstr() calls lstr_lng() for the current language. + * Definitions associated with ctry_fmt_dt() and ctry_fmt_times() + * have been moved to a new file ctry_fmt.h. + * Updated function prototypes. + * Revision 1.3 2000/08/17 15:35:02 MARTIN + * No init function by default (previously DOS), + * Revision 1.2 2000/07/21 09:48:34 MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _CTRY_H +#define _CTRY_H + + +/* Other headers to be included */ + +#include +#include + +#if defined( MBG_TGT_NETWARE ) + #include +#elif defined( MBG_TGT_OS2 ) + #include +#elif defined( MBG_TGT_WIN32 ) + // #include +#elif defined( MBG_TGT_LINUX ) + // #include +#elif defined( MBG_TGT_DOS ) + #include +#else + // nothing to include for C166 etc. +#endif + +#include + + +#ifdef _CTRY + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + +#if defined( _USE_PACK ) // set byte alignment + #pragma pack( 1 ) +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +// the definitions below are used to support different languages: +typedef uint8_t LANGUAGE; +typedef uint16_t CTRY_CODE; + +// codes used with LANGUAGE: +#if !defined LNG_DEFINED + enum + { + LNG_ENGLISH, + LNG_GERMAN, + N_LNG + }; + + #define LNG_DEFINED +#endif + +// the type below is used to declare string variables +// for several languages +typedef char *LSTR[N_LNG]; // array of strings +typedef char **PLSTR; // pointer to array + +// same as above, but const +typedef const char * const CLSTR[N_LNG]; // array of strings +typedef const char * const *PCLSTR; // pointer to array + + +// the definitions below are used to handle date and time +// formats used by different countries: +typedef struct +{ + CTRY_CODE code; + + uint8_t dt_fmt; // (codes defined below) + uint8_t tm_fmt; // (codes defined below) + char dt_sep; // (valid chars defined below) + char tm_sep; // (valid chars defined below) +} CTRY; + + +// codes used with CTRY.code: +#define CTRY_US 1 +#define CTRY_UK 44 +#define CTRY_GERMANY 49 + + +#ifndef CTRY_DEFINED + + #define CTRY_DEFINED + + // codes used with CTRY.dt_fmt: + enum + { + DT_FMT_DDMMYYYY, + DT_FMT_MMDDYYYY, + DT_FMT_YYYYMMDD, + N_DT_FMT + }; + + // codes used with CTRY.tm_fmt: + enum + { + TM_FMT_24H, + // TM_FMT_12H, // not yet supported + N_TM_FMT + }; + + + // codes used with CTRY.dt_sep: + #define DT_SEP_DOT '.' + #define DT_SEP_MINUS '-' + #define DT_SEP_SLASH '/' + + // a zero-terminated list of valid dt_sep characters + #define DT_SEP_LIST { DT_SEP_DOT, DT_SEP_MINUS, DT_SEP_SLASH, 0 } + + + // codes used with CTRY.tm_sep: + #define TM_SEP_COLON ':' + #define TM_SEP_DOT '.' + + // a zero-terminated list of valid tm_sep characters + #define TM_SEP_LIST { TM_SEP_COLON, TM_SEP_DOT, 0 } + +#endif // CTRY_DEFINED + + +extern LANGUAGE language; +extern CTRY ctry; + + +#define _ctry_init() \ + ctry_setup( ctry_get_code() ) + + +#define _next_language() \ +{ \ + if ( ++language >= N_LNG ) \ + language = 0; \ + \ +} // next_language + + +// macro to call lstr_lng with the current language +#define _lstr( _s ) lstr_lng( (_s), language ) + +// macro to call clstr_lng with the current language, and a set of strings +#define _clstr( _s ) clstr_lng( language, _s ) + +// macros used in wxWidgets projects +#if defined( __WXWINDOWS__ ) + #define _wx_lstr( _s ) wxString::From8BitData( lstr_lng( (_s), language ) ) + #define _wx_clstr( _s ) wxString::From8BitData( clstr_lng( language, _s ) ) +#endif + + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + + int lstr_idx( CLSTR s, int lng ) ; + int lstr_array_idx( CLSTR s, int idx, int n_lng, int lng ) ; + const char *lstr_lng( CLSTR s, int lng ) ; + void ctry_setup( CTRY_CODE code ) ; + void ctry_next( void ) ; + const char *clstr_lng( int index, ... ) ; + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +#if defined( _USE_PACK ) // set default alignment + #pragma pack() +#endif + +/* End of header body */ + + +#undef _ext + +#endif /* _CTRY_H */ + diff --git a/mbglib/common/ctrydttm.c b/mbglib/common/ctrydttm.c new file mode 100755 index 0000000..4d35644 --- /dev/null +++ b/mbglib/common/ctrydttm.c @@ -0,0 +1,184 @@ + +/************************************************************************** + * + * $Id: ctrydttm.c 1.5 2008/11/24 16:15:46 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Functions converting dates and time into strings depending on + * language/country settings. + * + * ----------------------------------------------------------------------- + * $Log: ctrydttm.c $ + * Revision 1.5 2008/11/24 16:15:46 martin + * Don't use sprintf() without format string. + * Revision 1.4 2000/11/27 10:06:27 MARTIN + * Renamed local variable wday_str to lstrs_wday. + * If macro USER_LSTR_WDAY is defined, lstrs_wday can be declared + * externally to override the defaults. + * Revision 1.3 2000/09/14 15:13:25 MARTIN + * Renamed sprint_short_ctry_dt() to sprint_ctry_dt_short() to match + * other naming conventions. + * Revision 1.2 2000/07/21 11:53:42 MARTIN + * Initial revision + * + **************************************************************************/ + +#define _CTRYDTTM + #include +#undef _CTRYDTTM + +#include + +#include + + +#ifndef DAYS_PER_WEEK + #define DAYS_PER_WEEK 7 +#endif + +#ifdef USER_LSTRS_WDAY + extern const char *lstrs_wday[N_LNG][DAYS_PER_WEEK]; +#else + static const char *lstrs_wday[N_LNG][DAYS_PER_WEEK] = + { + { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" }, + { "So", "Mo", "Di", "Mi", "Do", "Fr", "Sa" } + }; +#endif + +extern CTRY ctry; +extern LANGUAGE language; + + +/*HDR*/ +ushort sprint_02u( char *s, uchar uc ) +{ + return( sprintf( s, "%02u", uc ) ); + +} // sprint_02u + + + +/*HDR*/ +ushort sprint_04u( char *s, ushort us ) +{ + return( sprintf( s, "%04u", us ) ); + +} // sprint_04u + + + +/*HDR*/ +ushort sprint_ctry_wday( char *s, uchar wday, ushort language ) +{ + if ( language >= N_LNG ) + language = LNG_ENGLISH; + + return( sprintf( s, "%s", ( wday < DAYS_PER_WEEK ) ? + lstrs_wday[language][wday] : "--" ) ); + +} // sprint_ctry_wday + + + +/*HDR*/ +ushort sprint_ctry_dt_short( char *s, uchar mday, uchar month ) +{ + uchar tmp_1; + uchar tmp_2; + ushort n = 0; + + + switch( ctry.dt_fmt ) + { + case DT_FMT_YYYYMMDD: + case DT_FMT_MMDDYYYY: + tmp_1 = month; + tmp_2 = mday; + break; + + default: + tmp_1 = mday; + tmp_2 = month; + break; + + } // switch + + n = sprint_02u( s, tmp_1 ); + s[n++] = ctry.dt_sep; + n += sprint_02u( &s[n], tmp_2 ); + s[n++] = ctry.dt_sep; + s[n] = 0; + + return( n ); + +} // sprint_ctry_dt_short + + + +/*HDR*/ +ushort sprint_ctry_dt( char *s, uchar mday, uchar month, ushort year ) +{ + ushort n = 0; + + + if ( ctry.dt_fmt == DT_FMT_YYYYMMDD ) + { + n = sprint_04u( s, year ); + s[n++] = ctry.dt_sep; + } + + n += sprint_ctry_dt_short( &s[n], mday, month ); + + if ( ctry.dt_fmt == DT_FMT_YYYYMMDD ) + s[--n] = 0; + else + n += sprint_04u( &s[n], year ); + + return( n ); + +} // sprint_ctry_dt + + + +/*HDR*/ +ushort sprint_ctry_tm_short( char *s, uchar hour, uchar minute ) +{ + ushort n = sprint_02u( s, hour ); + s[n++] = ctry.tm_sep; + n += sprint_02u( &s[n], minute ); + + return( n ); + +} // sprint_ctry_tm_short + + + +/*HDR*/ +ushort sprint_ctry_tm( char *s, uchar hour, uchar minute, uchar second ) +{ + ushort n = sprint_ctry_tm_short( s, hour, minute ); + s[n++] = ctry.tm_sep; + n += sprint_02u( &s[n], second ); + + return( n ); + +} // sprint_ctry_tm + + + +/*HDR*/ +ushort sprint_ctry_tm_long( char *s, uchar hour, uchar minute, uchar second, + long frac, ushort frac_digits ) +{ + ushort n = sprint_ctry_tm( s, hour, minute, second ); + s[n++] = '.'; + n += sprintf( &s[n], "%0*lu", frac_digits, frac ); + + return( n ); + +} // sprint_ctry_tm_long + + diff --git a/mbglib/common/ctrydttm.h b/mbglib/common/ctrydttm.h new file mode 100755 index 0000000..ce613d7 --- /dev/null +++ b/mbglib/common/ctrydttm.h @@ -0,0 +1,74 @@ + +/************************************************************************** + * + * $Id: ctrydttm.h 1.3 2000/09/14 15:13:45 MARTIN REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes for ctrydttm.c. + * + * ----------------------------------------------------------------------- + * $Log: ctrydttm.h $ + * Revision 1.3 2000/09/14 15:13:45 MARTIN + * Updated function prototypes. + * Revision 1.2 2000/07/21 11:50:43 MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _CTRYDTTM_H +#define _CTRYDTTM_H + + +/* Other headers to be included */ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _CTRYDTTM + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + + + + + + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + + ushort sprint_02u( char *s, uchar uc ) ; + ushort sprint_04u( char *s, ushort us ) ; + ushort sprint_ctry_wday( char *s, uchar wday, ushort language ) ; + ushort sprint_ctry_dt_short( char *s, uchar mday, uchar month ) ; + ushort sprint_ctry_dt( char *s, uchar mday, uchar month, ushort year ) ; + ushort sprint_ctry_tm_short( char *s, uchar hour, uchar minute ) ; + ushort sprint_ctry_tm( char *s, uchar hour, uchar minute, uchar second ) ; + ushort sprint_ctry_tm_long( char *s, uchar hour, uchar minute, uchar second, long frac, ushort frac_digits ) ; + +/* ----- function prototypes end ----- */ + +/* End of header body */ + + +#undef _ext + +#ifdef __cplusplus +} +#endif + + +#endif /* _CTRYDTTM_H */ + diff --git a/mbglib/common/gpsdefs.h b/mbglib/common/gpsdefs.h new file mode 100755 index 0000000..d7156fd --- /dev/null +++ b/mbglib/common/gpsdefs.h @@ -0,0 +1,4413 @@ + +/************************************************************************** + * + * $Id: gpsdefs.h 1.91 2011/01/31 11:23:56 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * General definitions to be used with Meinberg clocks. + * These definitions have initially be used with GPS devices only. + * However, more and more Meinberg non-GPS devices also use some of + * these definitions. + * + * ----------------------------------------------------------------------- + * $Log: gpsdefs.h $ + * Revision 1.91 2011/01/31 11:23:56 martin + * Added model type name definitions for GPS180PEX and TCR180PEX. + * Introduced synthesizer mode for programmable outputs. + * Added IRIG-RX code TXC-101 DTR-6. + * Fixed missing comma bugs in DEFAULT_GPS_MODEL_NAMES. + * Fixed missing comma bugs in some IRIG string initializers. + * Fixed AFNOR notation. + * Modified some comments for doxygen. + * Revision 1.90 2010/10/15 11:47:53 martin + * Added definitions POUT_TIMEBASE_UTC and POUT_SUPP_DCF77_UTC. + * Added receiver info feature GPS_FEAT_RAW_IRIG_TIME. + * Support IRIG format C37.118. + * Added initializers for short IRIG code names. + * Cleaned up IRIG definitions and comments. + * Revision 1.89 2010/09/06 07:40:02Z martin + * Picked up Daniel's definitions for multi GNSS support. + * Moved MBG_IRIG_CTRL_BITS, MBG_RAW_IRIG_DATA and related definitions + * from pcpsdefs.h here. + * Added macros _pcps_tfom_from_irig_ctrl_bits() + * and _pcps_tfom_from_raw_irig_data(). + * Added RI_FEATURES type. + * Revision 1.88 2010/04/21 13:47:54 daniel + * Added support for new model GLN170. + * Revision 1.87 2010/03/10 11:29:37Z martin + * Added definitions for GPS180. + * Added multiref source 1 PPS plus associated string. + * Revision 1.86 2010/02/17 14:16:42 martin + * Added definitions for PZF600 and TCR600. + * Revision 1.85 2010/02/15 11:34:36 martin + * Changed definition of PTP_TABLE::name to const char *. + * Added definitions to support new model JJY511. + * Revision 1.84 2010/02/01 13:20:50 martin + * Support programmable outputs being disabled when sync. is lost. + * Revision 1.83 2010/01/28 09:15:50 martin + * Added new POUT mode DCF77_M59 and associated definitions. + * Revision 1.82 2010/01/07 09:04:55 martin + * Added XMR status bit XMRS_BIT_NOT_PHASE_LOCKED. + * Revision 1.81 2009/11/09 09:08:24 martin + * New TM_GPS status bit TM_INVT. + * Added definitions to support VLAN. + * Changed DEFAULT_PTP_DELAY_MECH_MASK to include also + * PTP_DELAY_MECH_MSK_P2P. + * There is now only one type of TCXO supported which matches the former + * TCXO HQ, so the default name for TCXO HQ has been changed to TCXO. + * TCXO LQ and MQ names are still supported for backward compatibility. + * Revision 1.80 2009/09/28 14:55:53 martin + * Support IRIG formats G002/G142 and G006/G146. + * Modified IRIG format description strings. + * Revision 1.79 2009/08/12 14:12:38 daniel + * Added definitions to support new model MGR170. + * Added definitions and commands to support configuration + * of navigation engine (currently supported by u-blox + * receivers only). + * Renamed simulation values in PTP_SETTINGS to reserved. + * Added "UNINITIALIZED" to PTP port state. + * Removed obsolete braces in initializer. + * Revision 1.78 2009/06/25 15:49:05Z martin + * Added macro _nano_time_negative(). + * Revision 1.77 2009/06/08 19:22:32Z daniel + * Added feature GPS_HAS_PTP. + * Added preliminary structures and definitions for PTP + * configuration and state. + * Added IP4_ADDR type. + * Added Bitmask IP4_MSK_DHCP. + * Added byte swapper macros for LAN and PTP structures. + * Moved LAN interface configuration definitions here. + * Moved DAC_VAL definition here. + * Changed type iof FPGA_INFO::start_addr for non-firmware applications. + * Revision 1.76 2009/04/08 08:26:56 daniel + * Added feature GPS_FEAT_IRIG_CTRL_BITS. + * Revision 1.75 2009/03/19 14:06:39Z martin + * Modified string initializer for unknown oscillator type. + * Revision 1.74 2009/03/18 13:45:53 daniel + * Added missing commas in + * MBG_DEBUG_STATUS_STRS initializer. + * Adjusted some comments for doxygen parser. + * Revision 1.73 2009/03/10 16:55:33Z martin + * Support configurable time scales GPS and TAI. + * Defined extended TM status type and associated flags. + * Added definition TM_MSK_TIME_VALID. + * Added some macros to swap endianess of structures. + * Revision 1.72 2008/11/28 09:26:21Z daniel + * Added definitions to support WWVB511 + * Revision 1.71 2008/10/31 14:31:44Z martin + * Added definitions for TCR170PEX. + * Revision 1.70 2008/09/18 11:14:39 martin + * Added definitions to support GEN170. + * Revision 1.69 2008/09/15 14:16:17 martin + * Added more macros to convert the endianess of structures. + * Added N_COM_HS to the enumeration of handshake modes. + * Added MBG_PS_... codes. + * Revision 1.68 2008/08/25 10:51:13 martin + * Added definitions for PTP270PEX and FRC511PEX. + * Revision 1.67 2008/07/17 08:54:52Z martin + * Added macros to convert the endianess of structures. + * Added multiref fixed frequency source. + * Revision 1.66 2008/05/19 14:49:07 daniel + * Renamed s_addr to start_addr in FPGA_INFO. + * Revision 1.65 2008/05/19 09:00:01Z martin + * Added definitions for GPS162. + * Added FPGA_INFO and GPS_HAS_FPGA. + * Added FPGA_START_INFO and associated definitions. + * Added new XMRS status XMRS_..._NOT_SETTLED. + * Added initializer XMULTI_REF_STATUS_INVALID. + * Revision 1.64 2008/01/17 11:50:33Z daniel + * Made IGNORE_LOCK bit maskable. + * Revision 1.63 2008/01/17 11:42:09Z daniel + * Made comments compatible for Doxygen parser. + * No sourcecode changes. + * Revision 1.62 2007/11/15 13:23:33Z martin + * Decide whether other Meinberg headers are to be included depending on whether + * CLOCK_MEINBERG is defined (as with NTP) or not. Previous versions checked + * for "PACKAGE" which is also defined by the Borland C++ build environment, though. + * Revision 1.61 2007/11/13 13:28:54 daniel + * Added definitions to support GPS170PEX. + * Revision 1.60 2007/09/13 12:37:35Z martin + * Modified and added initializers for TZDL. + * Added multiref source PTP over E1. + * Added codes for MSF511 and GRC170 devices. + * Modified XMULTI_REF_SETTINGS and XMULTI_REF_STATUS structures. + * Avoid inclusion of other Meinberg headers in non-Meinberg projects. + * Added device classification macros _mbg_rcvr_is_...(). + * Modified feature name string initializer for non-GPS devices. + * Updated some comments. + * Removed some obsolete comments. + * Revision 1.59 2007/07/19 07:41:56Z martin + * Added symbol MBG_REF_OFFS_NOT_CFGD. + * Revision 1.58 2007/05/21 15:46:44Z martin + * Fixed a typo. + * Revision 1.57 2007/03/29 12:20:43 martin + * Fixed some TZDL initializers. + * Revision 1.56 2007/02/14 14:17:10Z andre + * bug fixed in mask XMRS_MSK_NO_CONN + * Revision 1.55 2007/02/06 16:23:18Z martin + * Added definitions for AM511. + * Made SVNO unsigned. + * Added support for OPT_SETTINGS. + * Added XMULTI_REF_... definitions. + * Added string initializer DEFAULT_FREQ_RANGES. + * Revision 1.54 2007/01/04 11:39:39Z martin + * Added definitions for TCR511. + * Added definition GPS_FEAT_5_MHZ. + * Updated some comments related to duplicate features/options + * IGNORE_LOCK and EMU_SYNC. + * Revision 1.53 2006/12/13 09:31:49 martin + * Added feature flag for ignore_lock. + * Revision 1.52 2006/12/12 15:47:18 martin + * Added MBG_DEBUG_STATUS type and associated definitions. + * Added definition GPS_HAS_REF_OFFS. + * Moved PCPS_REF_OFFS and associated definitions from pcpsdefs.h here + * and renamed them to MBG_REF_OFFS, etc. + * Revision 1.51 2006/10/23 15:31:27 martin + * Added definitions for GPS170. + * Added definitions for new multi_ref sources IRIG, NTP, and PTP. + * Added some definitions useful when editing synth frequency. + * Revision 1.50 2006/08/25 09:29:28Z martin + * Added structure NANO_TIME. + * Revision 1.49 2006/08/09 07:06:42Z martin + * New TM_GPS status flag TM_EXT_SYNC. + * Revision 1.48 2006/08/08 12:51:20Z martin + * Added definitions for IRIG codes B006/B126 and B007/B127. + * Revision 1.47 2006/07/06 08:41:45Z martin + * Added definition of MEINBERG_MAGIC. + * Revision 1.46 2006/06/21 14:08:53Z martin + * Added masks of IRIG codes which contain time zone information. + * Revision 1.45 2006/06/15 12:13:32Z martin + * Added MULTI_REF_STATUS and associated flags. + * Added ROM_CSUM, RCV_TIMEOUT, and IGNORE_LOCK types. + * Revision 1.44 2006/05/18 09:34:41Z martin + * Added definitions for POUT max. pulse_len and max timeout. + * Changed comment for POUT_SETTINGS::timeout: + * Units are minutes, not seconds. + * Added definition for MAX_POUT_TIME_STR_PORTS. + * Added definitions for POUT mode 10MHz. + * Added hint strings for POUT modes. + * Added definitions for PZF511. + * Revision 1.43 2006/01/24 07:53:29Z martin + * New TM_GPS status flag TM_HOLDOVER. + * Revision 1.42 2005/11/24 14:53:22Z martin + * Added definitions for manchester encoded DC IRIG frames. + * Added POUT_TIMESTR and related definitions. + * Revision 1.41 2005/11/03 15:06:59Z martin + * Added definitions to support GPS170PCI. + * Revision 1.40 2005/10/28 08:58:29Z martin + * Added definitions for OCXO_DHQ. + * Revision 1.39 2005/09/08 14:06:00Z martin + * Added definition SYNTH_PHASE_SYNC_LIMIT. + * Revision 1.38 2005/08/18 10:27:35 andre + * added definitions for GPS164, + * added POUT_TIMECODE, + * struct SCU_STAT changed, + * ulong flags changed into two byte clk_info and ushort flags + * Revision 1.37 2005/05/02 14:44:55Z martin + * Added structure SYNTH_STATE and associated definitions. + * Revision 1.36 2005/03/29 12:44:07Z martin + * New RECEIVER_INFO::flags code: GPS_IRIG_FO_IN + * Revision 1.35 2004/12/09 14:04:38Z martin + * Changed max synth freq from 12 MHz to 10 MHz. + * Revision 1.34 2004/11/23 16:20:09Z martin + * Added bit definitions for the existing TTM status bit masks. + * Revision 1.33 2004/11/09 12:39:59Z martin + * Redefined interface data types using C99 fixed-size definitions. + * Added model code and name for TCR167PCI. + * New type GPS_CMD. + * Defined type BVAR_STAT and associated flags. + * Revision 1.32 2004/09/20 12:46:25 andre + * Added structures and definitions for SCU board. + * Revision 1.31 2004/07/08 08:30:36Z martin + * Added feature GPS_FEAT_RCV_TIMEOUT. + * Revision 1.30 2004/06/21 13:38:42 martin + * New flag MBG_OPT_BIT_EMU_SYNC/MBG_OPT_FLAG_EMU_SYNC + * lets the receicer emulate/pretend to be always synchronized. + * Revision 1.30 2004/06/21 13:35:46Z martin + * Revision 1.29 2004/06/16 12:47:53Z martin + * Moved OPT_SETTINGS related definitions from pcpsdefs.h + * here and renamed symbols from PCPS_.. to to MBG_... + * Revision 1.28 2004/03/26 10:37:00Z martin + * Added definitions to support multiple ref sources. + * Added definitions OSC_DAC_RANGE, OSC_DAC_BIAS. + * Revision 1.27 2004/03/08 14:06:45Z martin + * New model code and name for GPS169PCI. + * Existing feature GPS_FEAT_IRIG has been + * renamed to GPS_FEAT_IRIG_TX. + * Added feature GPS_FEAT_IRIG_RX. + * Added IPv4 LAN interface feature flags. + * Renamed IFLAGS_IGNORE_TFOM to IFLAGS_DISABLE_TFOM. + * Revision 1.26 2003/12/05 12:28:20Z martin + * Added some codes used with IRIG cfg. + * Revision 1.25 2003/10/29 16:18:14Z martin + * Added 7N2 to DEFAULT_GPS_FRAMINGS_GP2021. + * Revision 1.24 2003/09/30 08:49:48Z martin + * New flag TM_LS_ANN_NEG which is set in addition to + * TM_LS_ANN if next leap second is negative. + * Revision 1.23 2003/08/26 14:32:33Z martin + * Added some initializers for commonly used + * TZDL configurations. + * Revision 1.22 2003/04/25 10:18:11 martin + * Fixed typo inside an IRIG name string initializer. + * Revision 1.21 2003/04/15 09:18:48 martin + * New typedef ANT_CABLE_LEN. + * Revision 1.20 2003/04/03 11:03:44Z martin + * Extended definitions for IRIG support. + * Revision 1.19 2003/01/31 13:38:20 MARTIN + * Modified type of RECEIVER_INFO.fixed_freq field. + * Revision 1.18 2002/10/28 09:24:07 MARTIN + * Added/renamed some POUT related symbols. + * Revision 1.17 2002/09/05 10:58:39 MARTIN + * Renamed some symbols related to programmable outputs. + * Revision 1.16 2002/08/29 08:04:47 martin + * Renamed structure POUT_PROG to POUT_SETTINGS. + * New structures POUT_SETTINGS_IDX, POUT_INFO, + * POUT_INFO_IDX and associated definitions. + * Updated some comments. + * Revision 1.15 2002/07/17 07:39:39Z Andre + * comma added in definition DEFAULT_GPS_OSC_NAMES + * Revision 1.14 2002/06/27 12:17:29Z MARTIN + * Added new oscillator code TCXO_MQ. + * Added initializer for oscillator names. + * Added initializer for oscillator list ordered by quality. + * Revision 1.13 2002/05/08 08:16:03 MARTIN + * Added GPS_OSC_CFG_SUPP for RECEIVER_INFO::flags. + * Fixed some comments. + * Revision 1.12 2002/03/14 13:45:56 MARTIN + * Changed type CSUM from short to ushort. + * Revision 1.11 2002/03/01 12:29:30 Andre + * Added GPS_MODEL_GPS161 and GPS_MODEL_NAME_GPS161. + * Revision 1.10 2002/02/25 08:02:33Z MARTIN + * Added array of chars to union IDENT. + * Revision 1.9 2002/01/29 15:21:46 MARTIN + * Added new field "reserved" to struct SW_REV to fix C166 data + * alignment/structure size. Converted structure IDENT to a union. + * The changes above should not affect existing monitoring programs. + * New status flag TM_ANT_SHORT. + * New structure RECEIVER_INFO and associated definitions to + * enhance control from monitoring programs. + * New structures PORT_INFO, STR_TYPE_INFO, and associated + * definitions to simplify and unify configuration from external programs. + * New structures IRIG_INFO and POUT_PROG_IDX to configure an + * optional IRIG interface and programmable pulse outputs. + * Modified some comments. + * Revision 1.8 2001/03/30 11:44:11 MARTIN + * Control alignment of structures from new file use_pack.h. + * Defined initializers with valid baud rate and framing parameters. + * Modified some comments. + * Revision 1.7 2001/03/01 08:09:22 MARTIN + * Modified preprocessor syntax. + * Revision 1.6 2000/07/21 14:04:33 MARTIN + * Added som #if directives to protect structures against being multiply + * defined. + * Modified some comments. + * Comments using characters for +/- and degree now include ASCII + * characters only. + * + **************************************************************************/ + +#ifndef _GPSDEFS_H +#define _GPSDEFS_H + + +/* Other headers to be included */ + +#if defined( HAVE_CONFIG_H ) + // this is mainly to simplify usage in non-Meinberg projects + #include +#endif + +// CLOCK_MEINBERG is defined in NTP's config.h if configured +// to support Meinberg clocks. +#if !defined( CLOCK_MEINBERG ) + // avoid having to use these headers in non-Meinberg projects + #include + #include +#endif + + +#if defined( _USE_PACK ) // set byte alignment + #pragma pack( 1 ) +#endif + + +/* Start of header body */ + +/* "magic" number */ +#define MEINBERG_MAGIC 0x6AAC + +#define MIN_SVNO 1 /* min. SV number */ +#define MAX_SVNO 32 /* max. SV number */ +#define N_SVNO ( MAX_SVNO - MIN_SVNO + 1) /* number of possibly active SVs */ + + +#define GPS_ID_STR_LEN 16 +#define GPS_ID_STR_SIZE ( GPS_ID_STR_LEN + 1 ) + +#define GPS_EPLD_STR_LEN 8 +#define GPS_EPLD_STR_SIZE ( GPS_EPLD_STR_LEN + 1 ) + + +#define DEFAULT_GPS_TICKS_PER_SEC 10000000L /* system time base */ + +#if !defined( GPS_TICKS_PER_SEC ) + /* + * The actual ticks per seconds may vary for different + * GPS receiver models. If this is the case, the receiver + * model support the RECEIVER_INFO structure which contains + * the actual value. + */ + #define GPS_TICKS_PER_SEC DEFAULT_GPS_TICKS_PER_SEC +#endif + + +typedef uint16_t SVNO; /* the number of a SV */ +typedef uint16_t HEALTH; /* a SV's health code */ +typedef uint16_t CFG; /* a SV's configuration code */ +typedef uint16_t IOD; /* Issue-Of-Data code */ + + +/* the type of various checksums */ + +#ifndef _CSUM_DEFINED + typedef uint16_t CSUM; + #define _CSUM_DEFINED + + #define _mbg_swab_csum( _p ) _mbg_swab16( _p ) +#endif + + +/** + * @brief The type of a GPS command code + * + * These command codes can be passed via + * @ref gps_cmds_serial "serial port" (see @file gpsserio.h), or + * @ref gps_cmds_bus "system bus" (see @file pcpsdefs.h). + */ +typedef uint16_t GPS_CMD; + +#define _mbg_swab_gps_cmd( _p ) _mbg_swab16( _p ) + + +/** + * @brief Software revision information + * + * Contains a software revision code, plus an optional + * identifier for a customized version. + */ +typedef struct +{ + uint16_t code; /**< Version number, e.g. 0x0120 means v1.20 */ + char name[GPS_ID_STR_SIZE]; /**< Optional string identifying a customized version */ + uint8_t reserved; /**< Reserved field to yield even structure size */ +} SW_REV; + +#define _mbg_swab_sw_rev( _p ) \ +{ \ + _mbg_swab16( &(_p)->code ); \ +} + + + +/** + * @defgroup bvar_stat BVAR_STAT status of buffered GPS data + * + * Status word, associated bit numbers and bit masks indicating + * whether certain data from the GPS satellites are + * available and valid. + * + * These bits defined are set in ::BVAR_STAT if the corresponding + * parameters are NOT valid and complete. + * + * @{ */ + +/** + * @brief Status flags of battery buffered data received + * from GPS satellites. + * + * All '0' means OK, single bits set to '1' indicate + * the associated type of GPS data is not available. + */ +typedef uint16_t BVAR_STAT; + +#define _mbg_swab_bvar_stat( _p ) _mbg_swab16( (_p) ) + + +/** @brief Enumeration of bits used with BVAR_STAT */ +enum +{ + BVAR_BIT_CFGH_INVALID, + BVAR_BIT_ALM_NOT_COMPLETE, + BVAR_BIT_UTC_INVALID, + BVAR_BIT_IONO_INVALID, + BVAR_BIT_RCVR_POS_INVALID, + N_BVAR_BIT /**< @brief number of defined ::BVAR_STAT bits */ +}; + +#define BVAR_CFGH_INVALID ( 1UL << BVAR_BIT_CFGH_INVALID ) /**< @brief ::CFGH not valid*/ +#define BVAR_ALM_NOT_COMPLETE ( 1UL << BVAR_BIT_ALM_NOT_COMPLETE ) /**< @brief ::ALM not complete */ +#define BVAR_UTC_INVALID ( 1UL << BVAR_BIT_UTC_INVALID ) /**< @brief UTC data not valid */ +#define BVAR_IONO_INVALID ( 1UL << BVAR_BIT_IONO_INVALID ) /**< @brief IONO data not valid */ +#define BVAR_RCVR_POS_INVALID ( 1UL << BVAR_BIT_RCVR_POS_INVALID ) /**< @brief ::POS not valid */ + +#define BVAR_MASK ( ( 1UL << N_BVAR_BIT ) - 1 ) /**< @brief Bit mask for all defined bits */ + +/** @} */ + + + +/** + A structure used to hold a fixed frequency value. + frequ[kHz] = khz_val * 10^range +*/ + +typedef struct +{ + uint16_t khz_val; /* the base frequency in [kHz] */ + int16_t range; /* an optional base 10 exponent */ +} FIXED_FREQ_INFO; + +#define _mbg_swab_fixed_freq_info( _p ) \ +{ \ + _mbg_swab16( &(_p)->khz_val ); \ + _mbg_swab16( &(_p)->range ); \ +} + + +typedef uint32_t RI_FEATURES; // type of RECEIVER_INFO::features field + + +/* + * The following code defines features and properties + * of the various GPS receivers. Older GPS receivers + * may require a recent firmvare version to support + * this, or may not support this at all. + */ + +/** + * The structure is ordered in a way that all fields + * except chars or arrays of chars are word-aligned. + */ +typedef struct +{ + uint16_t model_code; /**< identifier for receiver model */ + SW_REV sw_rev; /**< software revision and ID */ + char model_name[GPS_ID_STR_SIZE]; /**< ASCIIZ, name of receiver model */ + char sernum[GPS_ID_STR_SIZE]; /**< ASCIIZ, serial number */ + char epld_name[GPS_EPLD_STR_SIZE]; /**< ASCIIZ, file name of EPLD image */ + uint8_t n_channels; /**< number of sats to be tracked simultaneously */ + uint32_t ticks_per_sec; /**< resolution of fractions of seconds */ + RI_FEATURES features; /**< optional features, see below */ + FIXED_FREQ_INFO fixed_freq; /**< optional non-standard fixed frequency */ + uint8_t osc_type; /**< type of installed oscillator, see below */ + uint8_t osc_flags; /**< oscillator flags, see below */ + uint8_t n_ucaps; /**< number of user time capture inputs */ + uint8_t n_com_ports; /**< number of on-board serial ports */ + uint8_t n_str_type; /**< max num of string types supported by any port */ + uint8_t n_prg_out; /**< number of programmable pulse outputs */ + uint16_t flags; /**< additional information, see below */ +} RECEIVER_INFO; + +#define _mbg_swab_receiver_info( _p ) \ +{ \ + _mbg_swab16( &(_p)->model_code ); \ + _mbg_swab_sw_rev( &(_p)->sw_rev ); \ + _mbg_swab16( &(_p)->ticks_per_sec ); \ + _mbg_swab32( &(_p)->features ); \ + _mbg_swab_fixed_freq_info( &(_p)->fixed_freq ); \ + _mbg_swab16( &(_p)->flags ); \ +} + + +/** + * Valid codes for RECEIVER_INFO.model_code: + */ +enum +{ + GPS_MODEL_UNKNOWN, + GPS_MODEL_GPS166, + GPS_MODEL_GPS167, + GPS_MODEL_GPS167SV, + GPS_MODEL_GPS167PC, + GPS_MODEL_GPS167PCI, + GPS_MODEL_GPS163, + GPS_MODEL_GPS168PCI, + GPS_MODEL_GPS161, + GPS_MODEL_GPS169PCI, + GPS_MODEL_TCR167PCI, + GPS_MODEL_GPS164, + GPS_MODEL_GPS170PCI, + GPS_MODEL_PZF511, + GPS_MODEL_GPS170, + GPS_MODEL_TCR511, + GPS_MODEL_AM511, + GPS_MODEL_MSF511, + GPS_MODEL_GRC170, + GPS_MODEL_GPS170PEX, + GPS_MODEL_GPS162, + GPS_MODEL_PTP270PEX, + GPS_MODEL_FRC511PEX, + GPS_MODEL_GEN170, + GPS_MODEL_TCR170PEX, + GPS_MODEL_WWVB511, + GPS_MODEL_MGR170, + GPS_MODEL_JJY511, + GPS_MODEL_PZF600, + GPS_MODEL_TCR600, + GPS_MODEL_GPS180, + GPS_MODEL_GLN170, + GPS_MODEL_GPS180PEX, + GPS_MODEL_TCR180PEX, + N_GPS_MODEL + /* If new model codes are added then care must be taken + * to update the associated string initializers below + * accordingly, and to check whether the classification macros + * also cover the new model names. */ +}; + + + + +/* + * String initializers for each of the GPS + * receiver models enum'ed above: + */ +#define GPS_MODEL_NAME_UNKNOWN "(unknown)" +#define GPS_MODEL_NAME_GPS166 "GPS166" +#define GPS_MODEL_NAME_GPS167 "GPS167" +#define GPS_MODEL_NAME_GPS167SV "GPS167SV" +#define GPS_MODEL_NAME_GPS167PC "GPS167PC" +#define GPS_MODEL_NAME_GPS167PCI "GPS167PCI" +#define GPS_MODEL_NAME_GPS163 "GPS163" +#define GPS_MODEL_NAME_GPS168PCI "GPS168PCI" +#define GPS_MODEL_NAME_GPS161 "GPS161" +#define GPS_MODEL_NAME_GPS169PCI "GPS169PCI" +#define GPS_MODEL_NAME_TCR167PCI "TCR167PCI" +#define GPS_MODEL_NAME_GPS164 "GPS164" +#define GPS_MODEL_NAME_GPS170PCI "GPS170PCI" +#define GPS_MODEL_NAME_PZF511 "PZF511" +#define GPS_MODEL_NAME_GPS170 "GPS170" +#define GPS_MODEL_NAME_TCR511 "TCR511" +#define GPS_MODEL_NAME_AM511 "AM511" +#define GPS_MODEL_NAME_MSF511 "MSF511" +#define GPS_MODEL_NAME_GRC170 "GRC170" +#define GPS_MODEL_NAME_GPS170PEX "GPS170PEX" +#define GPS_MODEL_NAME_GPS162 "GPS162" +#define GPS_MODEL_NAME_PTP270PEX "PTP270PEX" +#define GPS_MODEL_NAME_FRC511PEX "FRC511PEX" +#define GPS_MODEL_NAME_GEN170 "GEN170" +#define GPS_MODEL_NAME_TCR170PEX "TCR170PEX" +#define GPS_MODEL_NAME_WWVB511 "WWVB511" +#define GPS_MODEL_NAME_MGR170 "MGR170" +#define GPS_MODEL_NAME_JJY511 "JJY511" +#define GPS_MODEL_NAME_PZF600 "PZF600" +#define GPS_MODEL_NAME_TCR600 "TCR600" +#define GPS_MODEL_NAME_GPS180 "GPS180" +#define GPS_MODEL_NAME_GLN170 "GLN170" +#define GPS_MODEL_NAME_GPS180PEX "GPS180PEX" +#define GPS_MODEL_NAME_TCR180PEX "TCR180PEX" + + +/* + * The definition below can be used to initialize + * an array of N_GPS_MODEL type name strings. + * Including the trailing 0, each name must not + * exceed GPS_ID_STR_SIZE chars. + */ +#define DEFAULT_GPS_MODEL_NAMES \ +{ \ + GPS_MODEL_NAME_UNKNOWN, \ + GPS_MODEL_NAME_GPS166, \ + GPS_MODEL_NAME_GPS167, \ + GPS_MODEL_NAME_GPS167SV, \ + GPS_MODEL_NAME_GPS167PC, \ + GPS_MODEL_NAME_GPS167PCI, \ + GPS_MODEL_NAME_GPS163, \ + GPS_MODEL_NAME_GPS168PCI, \ + GPS_MODEL_NAME_GPS161, \ + GPS_MODEL_NAME_GPS169PCI, \ + GPS_MODEL_NAME_TCR167PCI, \ + GPS_MODEL_NAME_GPS164, \ + GPS_MODEL_NAME_GPS170PCI, \ + GPS_MODEL_NAME_PZF511, \ + GPS_MODEL_NAME_GPS170, \ + GPS_MODEL_NAME_TCR511, \ + GPS_MODEL_NAME_AM511, \ + GPS_MODEL_NAME_MSF511, \ + GPS_MODEL_NAME_GRC170, \ + GPS_MODEL_NAME_GPS170PEX, \ + GPS_MODEL_NAME_GPS162, \ + GPS_MODEL_NAME_PTP270PEX, \ + GPS_MODEL_NAME_FRC511PEX, \ + GPS_MODEL_NAME_GEN170, \ + GPS_MODEL_NAME_TCR170PEX, \ + GPS_MODEL_NAME_WWVB511, \ + GPS_MODEL_NAME_MGR170, \ + GPS_MODEL_NAME_JJY511, \ + GPS_MODEL_NAME_PZF600, \ + GPS_MODEL_NAME_TCR600, \ + GPS_MODEL_NAME_GPS180, \ + GPS_MODEL_NAME_GLN170, \ + GPS_MODEL_NAME_GPS180PEX, \ + GPS_MODEL_NAME_TCR180PEX \ +} + + +/* + * The macros below can be used to classify a receiver, + * e.g. depending on the time source and/or depending on + * whether it's a plug-in card or an external device. + */ + +#define _mbg_rcvr_is_plug_in( _p_ri ) \ + ( strstr( (_p_ri)->model_name, "PC" ) || \ + ( strstr( (_p_ri)->model_name, "PEX" ) ) + +#define _mbg_rcvr_is_gps( _p_ri ) \ + ( strstr( (_p_ri)->model_name, "GPS" ) || \ + ( strstr( (_p_ri)->model_name, "MGR" ) ) + +#define _mbg_rcvr_is_mobile_gps( _p_ri ) \ + ( strstr( (_p_ri)->model_name, "MGR" ) ) + +#define _mbg_rcvr_is_gps_plug_in( _p_ri ) \ + ( _mbg_rcvr_is_gps( _p_ri ) && \ + _mbg_rcvr_is_plug_in( _p_ri ) ) + +#define _mbg_rcvr_is_irig( _p_ri ) \ + ( strstr( (_p_ri)->model_name, "TCR" ) ) + +#define _mbg_rcvr_is_irig_plug_in( _p_ri ) \ + ( _mbg_rcvr_is_irig( _p_ri ) && \ + _mbg_rcvr_is_plug_in( _p_ri ) ) + +#define _mbg_rcvr_is_dcf77_am( _p_ri ) \ + ( strstr( (_p_ri)->model_name, "AM" ) ) + +#define _mbg_rcvr_is_dcf77_am_plug_in( _p_ri ) \ + ( _mbg_rcvr_is_dcf77_am( _p_ri ) && \ + _mbg_rcvr_is_plug_in( _p_ri ) ) + +#define _mbg_rcvr_is_dcf77_pzf( _p_ri ) \ + ( strstr( (_p_ri)->model_name, "PZF" ) ) + +#define _mbg_rcvr_is_dcf77_pzf_plug_in( _p_ri ) \ + ( _mbg_rcvr_is_dcf77_pzf( _p_ri ) && \ + _mbg_rcvr_is_plug_in( _p_ri ) ) + +#define _mbg_rcvr_is_any_dcf77( _p_ri ) \ + ( _mbg_rcvr_is_dcf77_am( _p_ri ) || \ + _mbg_rcvr_is_dcf77_pzf( _p_ri ) ) + +#define _mbg_rcvr_is_any_dcf77_plug_in( _p_ri ) \ + ( _mbg_rcvr_is_any_dcf77( _p_ri ) && \ + _mbg_rcvr_is_plug_in( _p_ri ) ) + +#define _mbg_rcvr_is_msf( _p_ri ) \ + ( strstr( (_p_ri)->model_name, "MSF" ) ) + +#define _mbg_rcvr_is_jjy( _p_ri ) \ + ( strstr( (_p_ri)->model_name, "JJY" ) ) + +#define _mbg_rcvr_is_msf_plug_in( _p_ri ) \ + ( _mbg_rcvr_is_msf( _p_ri ) && \ + _mbg_rcvr_is_plug_in( _p_ri ) ) + +#define _mbg_rcvr_is_glonass( _p_ri ) \ + ( strstr( (_p_ri)->model_name, "GRC" ) || \ + ( strstr( (_p_ri)->model_name, "GLN" ) ) + +#define _mbg_rcvr_is_glonass_plug_in( _p_ri ) \ + ( _mbg_rcvr_is_glonass( _p_ri ) && \ + _mbg_rcvr_is_plug_in( _p_ri ) ) + +#define _mbg_rcvr_is_wwvb( _p_ri ) \ + ( strstr( (_p_ri)->model_name, "WWVB" ) ) + +#define _mbg_rcvr_is_wwvb_plug_in( _p_ri ) \ + ( _mbg_rcvr_is_wwvb( _p_ri ) && \ + _mbg_rcvr_is_plug_in( _p_ri ) ) + + +/** + * The classification codes for oscillators below + * are used with RECEIVER_INFO.osc_type. New codes + * must be appended to the enumeration, so the sequence + * of codes does NOT reflect the order of quality: + */ +enum +{ + GPS_OSC_UNKNOWN, + GPS_OSC_TCXO_LQ, + GPS_OSC_TCXO_HQ, + GPS_OSC_OCXO_LQ, + GPS_OSC_OCXO_MQ, + GPS_OSC_OCXO_HQ, + GPS_OSC_OCXO_XHQ, + GPS_OSC_RUBIDIUM, + GPS_OSC_TCXO_MQ, + GPS_OSC_OCXO_DHQ, + N_GPS_OSC +}; + + +/* + * The sequence and number of oscillator names + * listed below must correspond to the enumeration + * above: + */ +#define DEFAULT_GPS_OSC_NAMES \ +{ \ + "[unknown]", \ + "TCXO LQ", \ + "TCXO", \ + "OCXO LQ", \ + "OCXO MQ", \ + "OCXO HQ", \ + "OCXO XHQ", \ + "RUBIDIUM", \ + "TCXO MQ", \ + "OCXO DHQ" \ +} + + +/* + * The initializer below can be used to initialize + * an array (e.g. "int osc_quality_idx[N_GPS_OSC]") + * which allows to display the oscillator types + * ordered by quality: + */ +#define DEFAULT_GPS_OSC_QUALITY_IDX \ +{ \ + GPS_OSC_UNKNOWN, \ + GPS_OSC_TCXO_LQ, \ + GPS_OSC_TCXO_MQ, \ + GPS_OSC_TCXO_HQ, \ + GPS_OSC_OCXO_LQ, \ + GPS_OSC_OCXO_MQ, \ + GPS_OSC_OCXO_HQ, \ + GPS_OSC_OCXO_DHQ, \ + GPS_OSC_OCXO_XHQ, \ + GPS_OSC_RUBIDIUM \ +} + + + +/* + * Codes to be used with RECEIVER_INFO.osc_flags + * are not yet used/required, so they are reserved + * for future use. + */ + + +/** + * The codes below enumerate some features which may be + * supported by a given clock, or not. + */ +enum +{ + GPS_FEAT_PPS, /**< has pulse per second output */ + GPS_FEAT_PPM, /**< has pulse per minute output */ + GPS_FEAT_SYNTH, /**< has programmable synthesizer output */ + GPS_FEAT_DCFMARKS, /**< has DCF77 compatible time mark output */ + GPS_FEAT_IRIG_TX, /**< has on-board IRIG output */ + GPS_FEAT_IRIG_RX, /**< has on-board IRIG input */ + GPS_FEAT_LAN_IP4, /**< has LAN IPv4 interface */ + GPS_FEAT_MULTI_REF, /**< has multiple input sources with priorities */ + GPS_FEAT_RCV_TIMEOUT, /**< timeout after GPS reception has stopped */ + GPS_FEAT_IGNORE_LOCK, /**< supports "ignore lock", alternatively */ + /**< MBG_OPT_BIT_EMU_SYNC may be supported */ + GPS_FEAT_5_MHZ, /**< output 5 MHz rather than 100 kHz */ + GPS_FEAT_XMULTI_REF, /**< has extended multiple input source configuration */ + GPS_FEAT_OPT_SETTINGS, /**< supports MBG_OPT_SETTINGS */ + GPS_FEAT_TIME_SCALE, /**< supports configurable time scale (UTC, TAI, GPS, ...) */ + GPS_FEAT_IRIG_CTRL_BITS, /**< supports IRIG control bits */ + GPS_FEAT_PTP, /**< has PTP support */ + GPS_FEAT_NAV_ENGINE_SETTINGS, /**< supports navigation engine configuration */ + GPS_FEAT_RAW_IRIG_DATA, /**< supports reading raw IRIG input data */ + GPS_FEAT_RAW_IRIG_TIME, /**< supports reading decoded IRIG time */ + N_GPS_FEATURE /**< the number of valid features */ +}; + + +#define DEFAULT_GPS_FEATURE_NAMES \ +{ \ + "Pulse Per Second", \ + "Pulse Per Minute", \ + "Programmable Synth.", \ + "DCF77 Time Marks", \ + "IRIG Out", \ + "IRIG In", \ + "IPv4 LAN Interface", \ + "Multiple Ref. Sources", \ + "Receive Timeout", \ + "Ignore Lock", \ + "5 MHz Output", \ + "Ext. Multiple Ref. Src. Cfg.", \ + "Optional Settings", \ + "Configurable Time Scale", \ + "IRIG Control Bits", \ + "PTP/IEEE1588", \ + "Nav. Engine Settings", \ + "Raw IRIG Data", \ + "Raw IRIG Time" \ +} + + +/* + * Bit masks used with RECEIVER_INFO.features + * (others are reserved): + */ +#define GPS_HAS_PPS ( 1UL << GPS_FEAT_PPS ) +#define GPS_HAS_PPM ( 1UL << GPS_FEAT_PPM ) +#define GPS_HAS_SYNTH ( 1UL << GPS_FEAT_SYNTH ) +#define GPS_HAS_DCFMARKS ( 1UL << GPS_FEAT_DCFMARKS ) +#define GPS_HAS_IRIG_TX ( 1UL << GPS_FEAT_IRIG_TX ) +#define GPS_HAS_IRIG_RX ( 1UL << GPS_FEAT_IRIG_RX ) +#define GPS_HAS_LAN_IP4 ( 1UL << GPS_FEAT_LAN_IP4 ) +#define GPS_HAS_MULTI_REF ( 1UL << GPS_FEAT_MULTI_REF ) +#define GPS_HAS_RCV_TIMEOUT ( 1UL << GPS_FEAT_RCV_TIMEOUT ) +#define GPS_HAS_IGNORE_LOCK ( 1UL << GPS_FEAT_IGNORE_LOCK ) +#define GPS_HAS_5_MHZ ( 1UL << GPS_FEAT_5_MHZ ) +#define GPS_HAS_XMULTI_REF ( 1UL << GPS_FEAT_XMULTI_REF ) +#define GPS_HAS_OPT_SETTINGS ( 1UL << GPS_FEAT_OPT_SETTINGS ) +#define GPS_HAS_TIME_SCALE ( 1UL << GPS_FEAT_TIME_SCALE ) +#define GPS_HAS_IRIG_CTRL_BITS ( 1UL << GPS_FEAT_IRIG_CTRL_BITS ) +#define GPS_HAS_PTP ( 1UL << GPS_FEAT_PTP ) +#define GPS_HAS_NAV_ENGINE_SETTINGS ( 1UL << GPS_FEAT_NAV_ENGINE_SETTINGS ) +#define GPS_HAS_RAW_IRIG_DATA ( 1UL << GPS_FEAT_RAW_IRIG_DATA ) +#define GPS_HAS_RAW_IRIG_TIME ( 1UL << GPS_FEAT_RAW_IRIG_TIME ) + +#define GPS_HAS_REF_OFFS GPS_HAS_IRIG_RX + + +/* + * The features below are supported by default by older + * C166 based GPS receivers: + */ +#define DEFAULT_GPS_FEATURES_C166 \ +{ \ + GPS_HAS_PPS | \ + GPS_HAS_PPM | \ + GPS_HAS_SYNTH | \ + GPS_HAS_DCFMARKS \ +} + + +/* + * Codes to be used with RECEIVER_INFO::flags: + */ +#define GPS_OSC_CFG_SUPP 0x0001 // GPS_OSC_CFG supported +#define GPS_IRIG_FO_IN 0x0002 // IRIG input via fiber optics +#define GPS_HAS_FPGA 0x0004 // device provides on-board FPGA + + +/* + * If the GPS_HAS_FPGA flag is set in RECEIVER_INFO::flags then the card + * provides an FPGA and the following information about the FPGA is available: + */ +#define FPGA_NAME_LEN 31 // max name length +#define FPGA_NAME_SIZE ( FPGA_NAME_LEN + 1 ) // size including trailing 0 + +#define FPGA_INFO_SIZE 128 + +typedef union +{ + struct + { + CSUM csum; + uint32_t fsize; + #if _IS_MBG_FIRMWARE + uint32_t start_addr; + #else + uint8_t *start_addr; + #endif + char name[FPGA_NAME_SIZE]; + } hdr; + + char b[FPGA_INFO_SIZE]; + +} FPGA_INFO; + + + +/* + * The definitions below are used to specify where a FPGA image is located + * in the flash memory: + */ +typedef struct +{ + CSUM csum; + uint16_t fpga_start_seg; // Number of the 4k block where an FPGA image is located +} FPGA_START_INFO; + +#define DEFAULT_FPGA_START_SEG 0x60 + +#define DEFAULT_FPGA_START_INFO \ +{ \ + 0x1234 + DEFAULT_FPGA_START_SEG, \ + DEFAULT_FPGA_START_SEG \ +} + + + +/** + Date and time referred to the linear time scale defined by GPS. + GPS time is defined by the number of weeks since midnight from + January 5, 1980 to January 6, 1980 plus the number of seconds of + the current week plus fractions of a second. GPS time differs from + UTC because UTC is corrected with leap seconds while GPS time scale + is continuous. +*/ +typedef struct +{ + uint16_t wn; /**< the week number since GPS has been installed */ + uint32_t sec; /**< the second of that week */ + uint32_t tick; /**< fractions of a second; scale: 1/GPS_TICKS_PER_SEC */ +} T_GPS; + +#define _mbg_swab_t_gps( _p ) \ +{ \ + _mbg_swab16( &(_p)->wn ); \ + _mbg_swab32( &(_p)->sec ); \ + _mbg_swab32( &(_p)->tick ); \ +} + + +/** + Local date and time computed from GPS time. The current number + of leap seconds have to be added to get UTC from GPS time. + Additional corrections could have been made according to the + time zone/daylight saving parameters (TZDL, see below) defined + by the user. The status field can be checked to see which corrections + have been applied. +*/ +typedef struct +{ + int16_t year; /**< year number, 0..9999 */ + int8_t month; /**< month, 1..12 */ + int8_t mday; /**< day of month, 1..31 */ + int16_t yday; /**< day of year, 1..366 */ + int8_t wday; /**< day of week, 0..6 == Sun..Sat */ + int8_t hour; /**< hours, 0..23 */ + int8_t min; /**< minutes, 0..59 */ + int8_t sec; /**< seconds, 0..59 */ + int32_t frac; /**< fractions of a second; scale: 1/GPS_TICKS_PER_SEC */ + int32_t offs_from_utc; /**< local time's offset from UTC */ + uint16_t status; /**< status flags */ +} TM_GPS; + +#define _mbg_swab_tm_gps( _p ) \ +{ \ + _mbg_swab16( &(_p)->year ); \ + _mbg_swab16( &(_p)->yday ); \ + _mbg_swab32( &(_p)->frac ); \ + _mbg_swab32( &(_p)->offs_from_utc ); \ + _mbg_swab16( &(_p)->status ); \ +} + + +/* status flag bits used with conversion from GPS time to local time */ + +enum +{ + TM_BIT_UTC, /* UTC correction has been made */ + TM_BIT_LOCAL, /* UTC has been converted to local time */ + TM_BIT_DL_ANN, /* state of daylight saving is going to change */ + TM_BIT_DL_ENB, /* daylight saving is enabled */ + TM_BIT_LS_ANN, /* leap second will be inserted */ + TM_BIT_LS_ENB, /* current second is leap second */ + TM_BIT_LS_ANN_NEG, /* set in addition to TM_LS_ANN if leap sec negative */ + TM_BIT_INVT, /* invalid time, e.g. if RTC battery empty */ + + TM_BIT_EXT_SYNC, /* sync'd externally */ + TM_BIT_HOLDOVER, /* holdover mode after previous sync. */ + TM_BIT_ANT_SHORT, /* antenna cable short circuited */ + TM_BIT_NO_WARM, /* OCXO has not warmed up */ + TM_BIT_ANT_DISCONN, /* antenna currently disconnected */ + TM_BIT_SYN_FLAG, /* TIME_SYN output is low */ + TM_BIT_NO_SYNC, /* time sync actually not verified */ + TM_BIT_NO_POS /* position actually not verified, LOCK LED off */ +}; + +// Type of an extended TM status which is mainly used by the firmware. +typedef uint32_t TM_STATUS_EXT; // extended status, mainly used by the firmware + +// The lower 16 bits of the TM_STATUS_X type correspond to those defined above, +// and the upper bits are defined below: +enum +{ + TM_BIT_SCALE_GPS = 16, + TM_BIT_SCALE_TAI + // the remaining bits are reserved +}; + + +/* bit masks corresponding to the flag bits above */ + +#define TM_UTC ( 1UL << TM_BIT_UTC ) +#define TM_LOCAL ( 1UL << TM_BIT_LOCAL ) +#define TM_DL_ANN ( 1UL << TM_BIT_DL_ANN ) +#define TM_DL_ENB ( 1UL << TM_BIT_DL_ENB ) +#define TM_LS_ANN ( 1UL << TM_BIT_LS_ANN ) +#define TM_LS_ENB ( 1UL << TM_BIT_LS_ENB ) +#define TM_LS_ANN_NEG ( 1UL << TM_BIT_LS_ANN_NEG ) +#define TM_INVT ( 1UL << TM_BIT_INVT ) + +#define TM_EXT_SYNC ( 1UL << TM_BIT_EXT_SYNC ) +#define TM_HOLDOVER ( 1UL << TM_BIT_HOLDOVER ) +#define TM_ANT_SHORT ( 1UL << TM_BIT_ANT_SHORT ) +#define TM_NO_WARM ( 1UL << TM_BIT_NO_WARM ) +#define TM_ANT_DISCONN ( 1UL << TM_BIT_ANT_DISCONN ) +#define TM_SYN_FLAG ( 1UL << TM_BIT_SYN_FLAG ) +#define TM_NO_SYNC ( 1UL << TM_BIT_NO_SYNC ) +#define TM_NO_POS ( 1UL << TM_BIT_NO_POS ) + +// The following bits are only used with the TM_STATUS_X type: +#define TM_SCALE_GPS ( 1UL << TM_BIT_SCALE_GPS ) +#define TM_SCALE_TAI ( 1UL << TM_BIT_SCALE_TAI ) + +#define TM_MSK_TIME_VALID ( TM_UTC | TM_SCALE_GPS | TM_SCALE_TAI ) + +/** + This structure is used to transmit information on date and time + */ +typedef struct +{ + int16_t channel; /**< -1: the current time; 0, 1: capture 0, 1 */ + T_GPS t; /**< time in GPS format */ + TM_GPS tm; /**< that time converted to local time */ +} TTM; + +#define _mbg_swab_ttm( _p ) \ +{ \ + _mbg_swab16( &(_p)->channel ); \ + _mbg_swab_t_gps( &(_p)->t ); \ + _mbg_swab_tm_gps( &(_p)->tm ); \ +} + + + +typedef struct +{ + int32_t nano_secs; // [nanoseconds] + int32_t secs; // [seconds] +} NANO_TIME; + +#define _mbg_swab_nano_time( _p ) \ +{ \ + _mbg_swab32( &(_p)->nano_secs ); \ + _mbg_swab32( &(_p)->secs ); \ +} + +// The macro below checks if a NANO_TIME value is negative. +#define _nano_time_negative( _nt ) \ + ( ( (_nt)->secs < 0 ) || ( (_nt)->nano_secs < 0 ) ) + + + +/* Two types of variables used to store a position. Type XYZ is */ +/* used with a position in earth centered, earth fixed (ECEF) */ +/* coordinates whereas type LLA holds such a position converted */ +/* to geographic coordinates as defined by WGS84 (World Geodetic */ +/* System from 1984). */ + +#ifndef _XYZ_DEFINED + /* sequence and number of components of a cartesian position */ + enum { XP, YP, ZP, N_XYZ }; + + /** a type of array holding a cartesian position */ + typedef double XYZ[N_XYZ]; /**< values are in [m] */ + + #define _XYZ_DEFINED +#endif + +#define _mbg_swab_xyz( _p ) _mbg_swab_doubles( _p, N_XYZ ) + + +#ifndef _LLA_DEFINED + /* sequence and number of components of a geographic position */ + enum { LAT, LON, ALT, N_LLA }; /* latitude, longitude, altitude */ + + /** a type of array holding a geographic position */ + typedef double LLA[N_LLA]; /**< lon, lat in [rad], alt in [m] */ + + #define _LLA_DEFINED +#endif + +#define _mbg_swab_lla( _p ) _mbg_swab_doubles( _p, N_LLA ) + + +/** + @defgroup group_synth Synthesizer parameters + + Synthesizer frequency is expressed as a + four digit decimal number (freq) to be multiplied by 0.1 Hz and an + base 10 exponent (range). If the effective frequency is less than + 10 kHz its phase is synchronized corresponding to the variable phase. + Phase may be in a range from -360 deg to +360 deg with a resolution + of 0.1 deg, so the resulting numbers to be stored are in a range of + -3600 to +3600. + + Example:
+ Assume the value of freq is 2345 (decimal) and the value of phase is 900. + If range == 0 the effective frequency is 234.5 Hz with a phase of +90 deg. + If range == 1 the synthesizer will generate a 2345 Hz output frequency + and so on. + + Limitations:
+ If freq == 0 the synthesizer is disabled. If range == 0 the least + significant digit of freq is limited to 0, 3, 5 or 6. The resulting + frequency is shown in the examples below: + - freq == 1230 --> 123.0 Hz + - freq == 1233 --> 123 1/3 Hz (real 1/3 Hz, NOT 123.3 Hz) + - freq == 1235 --> 123.5 Hz + - freq == 1236 --> 123 2/3 Hz (real 2/3 Hz, NOT 123.6 Hz) + + If range == MAX_RANGE the value of freq must not exceed 1000, so the + output frequency is limited to 10 MHz. + @{ +*/ + +#define N_SYNTH_FREQ_DIGIT 4 /**< number of digits to edit */ +#define MAX_SYNTH_FREQ 1000 /**< if range == MAX_SYNTH_RANGE */ + +#define MIN_SYNTH_RANGE 0 +#define MAX_SYNTH_RANGE 5 +#define N_SYNTH_RANGE ( MAX_SYNTH_RANGE - MIN_SYNTH_RANGE + 1 ) + +#define N_SYNTH_PHASE_DIGIT 4 +#define MAX_SYNTH_PHASE 3600 + + +#define MAX_SYNTH_FREQ_EDIT 9999 /**< max sequence of digits when editing */ + +/** The maximum frequency that can be configured for the synthesizer */ +#define MAX_SYNTH_FREQ_VAL 10000000UL /**< 10 MHz */ +/* == MAX_SYNTH_FREQ * 10^(MAX_SYNTH_RANGE-1) */ + +/** + The synthesizer phase will only be synchronized if the frequency + is below this limit: */ +#define SYNTH_PHASE_SYNC_LIMIT 10000UL /**< 10 kHz */ + +/** + the position of the decimal point if the frequency is + printed as 4 digit value */ +#define _synth_dp_pos_from_range( _r ) \ + ( ( ( N_SYNTH_RANGE - (_r) ) % ( N_SYNTH_FREQ_DIGIT - 1 ) ) + 1 ) + +/** + An initializer for commonly displayed synthesizer frequency units + (N_SYNTH_RANGE strings) */ +#define DEFAULT_FREQ_RANGES \ +{ \ + "Hz", \ + "kHz", \ + "kHz", \ + "kHz", \ + "MHz", \ + "MHz", \ +} + + + +typedef struct +{ + int16_t freq; /**< four digits used; scale: 0.1; e.g. 1234 -> 123.4 Hz */ + int16_t range; /**< scale factor for freq; 0..MAX_SYNTH_RANGE */ + int16_t phase; /**< -MAX_SYNTH_PHASE..+MAX_SYNTH_PHASE; >0 -> pulses later */ +} SYNTH; + +#define _mbg_swab_synth( _p ) \ +{ \ + _mbg_swab16( &(_p)->freq ); \ + _mbg_swab16( &(_p)->range ); \ + _mbg_swab16( &(_p)->phase ); \ +} + + +/** + The definitions below can be used to query the + current synthesizer state. + */ +enum +{ + SYNTH_DISABLED, /**< disbled by cfg, i.e. freq == 0.0 */ + SYNTH_OFF, /**< not enabled after power-up */ + SYNTH_FREE, /**< enabled, but not synchronized */ + SYNTH_DRIFTING, /**< has initially been sync'd, but now running free */ + SYNTH_SYNC, /**< fully synchronized */ + N_SYNTH_STATE /**< the number of known states */ +}; + +typedef struct +{ + uint8_t state; /**< state code as enumerated above */ + uint8_t flags; /**< reserved, currently always 0 */ +} SYNTH_STATE; + +#define _mbg_swab_synth_state( _p ) _nop_macro_fnc() + +#define SYNTH_FLAG_PHASE_IGNORED 0x01 + +/** @} */ // endgroup + +/** + @defgroup group_tzdl Time zone/daylight saving parameters + + Example:
+ For automatic daylight saving enable/disable in Central Europe, + the variables are to be set as shown below:
+ - offs = 3600L one hour from UTC + - offs_dl = 3600L one additional hour if daylight saving enabled + - tm_on = first Sunday from March 25, 02:00:00h ( year |= DL_AUTO_FLAG ) + - tm_off = first Sunday from October 25, 03:00:00h ( year |= DL_AUTO_FLAG ) + - name[0] == "CET " name if daylight saving not enabled + - name[1] == "CEST " name if daylight saving is enabled + @{ +*/ + +/** the name of a time zone, 5 characters plus trailing zero */ +typedef char TZ_NAME[6]; + +typedef struct +{ + int32_t offs; /**< offset from UTC to local time [sec] */ + int32_t offs_dl; /**< additional offset if daylight saving enabled [sec] */ + TM_GPS tm_on; /**< date/time when daylight saving starts */ + TM_GPS tm_off; /**< date/time when daylight saving ends */ + TZ_NAME name[2]; /**< names without and with daylight saving enabled */ +} TZDL; + +#define _mbg_swab_tzdl( _p ) \ +{ \ + _mbg_swab32( &(_p)->offs ); \ + _mbg_swab32( &(_p)->offs_dl ); \ + _mbg_swab_tm_gps( &(_p)->tm_on ); \ + _mbg_swab_tm_gps( &(_p)->tm_off ); \ +} + + +/** + If the year in tzdl.tm_on and tzdl.tm_off is or'ed with that constant, + the receiver automatically generates daylight saving year by year. + */ +#define DL_AUTO_FLAG 0x8000 + + + +// Below there are some initializers for commonly used TZDL configurations: + +#define DEFAULT_TZDL_AUTO_YEAR ( 2007 | DL_AUTO_FLAG ) + +#define DEFAULt_TZDL_OFFS_DL 3600L /**< usually DST is +1 hour */ + + +/** + The symbol below can be used to initialize both the tm_on + and tm_off fields for time zones which do not switch to DST: + */ +#define DEFAULT_TZDL_TM_ON_OFF_NO_DST \ + { DEFAULT_TZDL_AUTO_YEAR, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 } + + +// Settings used with UTC: + +#define TZ_INFO_UTC "UTC (Universal Time, Coordinated)" + +#define DEFAULT_TZDL_NAMES_UTC { "UTC ", "UTC " } + +#define DEFAULT_TZDL_UTC \ +{ \ + 0L, /**< offs */ \ + 0L, /**< offs_dl */ \ + DEFAULT_TZDL_TM_ON_OFF_NO_DST, /**< tm_on */ \ + DEFAULT_TZDL_TM_ON_OFF_NO_DST, /**< tm_off */ \ + DEFAULT_TZDL_NAMES_UTC /**< name[] */ \ +} + + +/** + The symbols below specify beginning and end of DST for + Central Europe, as constituted by the European Parliament: + */ + +#define DEFAULT_TZDL_TM_ON_CET_CEST \ + { DEFAULT_TZDL_AUTO_YEAR, 3, 25, 0, 0, 2, 0, 0, 0L, 0L, 0 } + +#define DEFAULT_TZDL_TM_OFF_CET_CEST \ + { DEFAULT_TZDL_AUTO_YEAR, 10, 25, 0, 0, 3, 0, 0, 0L, 0L, 0 } + + +// Settings used with Central European Time: + +#define TZ_INFO_CET_CEST_EN "CET/CEST (Central Europe)" +#define TZ_INFO_CET_CEST_DE "MEZ/MESZ (Mitteleuropa)" + +#define DEFAULT_TZDL_NAMES_CET_CEST_EN { "CET ", "CEST " } +#define DEFAULT_TZDL_NAMES_CET_CEST_DE { "MEZ ", "MESZ " } + +#define DEFAULT_TZDL_OFFS_CET 3600L + +#define DEFAULT_TZDL_CET_CEST_EN \ +{ \ + DEFAULT_TZDL_OFFS_CET, /**< offs */ \ + DEFAULt_TZDL_OFFS_DL, /**< offs_dl */ \ + DEFAULT_TZDL_TM_ON_CET_CEST, /**< tm_on */ \ + DEFAULT_TZDL_TM_OFF_CET_CEST, /**< tm_off */ \ + DEFAULT_TZDL_NAMES_CET_CEST_EN /**< name[] */ \ +} + +#define DEFAULT_TZDL_CET_CEST_DE \ +{ \ + DEFAULT_TZDL_OFFS_CET, /**< offs */ \ + DEFAULt_TZDL_OFFS_DL, /**< offs_dl */ \ + DEFAULT_TZDL_TM_ON_CET_CEST, /**< tm_on */ \ + DEFAULT_TZDL_TM_OFF_CET_CEST, /**< tm_off */ \ + DEFAULT_TZDL_NAMES_CET_CEST_DE /**< name[] */ \ +} + + +// The symbols below specify beginning and end of DST for +// Easter Europe, as constituted by the European Parliament: + +#define DEFAULT_TZDL_TM_ON_EET_EEST \ + { DEFAULT_TZDL_AUTO_YEAR, 3, 25, 0, 0, 3, 0, 0, 0L, 0L, 0 } + +#define DEFAULT_TZDL_TM_OFF_EET_EEST \ + { DEFAULT_TZDL_AUTO_YEAR, 10, 25, 0, 0, 4, 0, 0, 0L, 0L, 0 } + + +// Settings used with Eastern European Time: + +#define TZ_INFO_EET_EEST_EN "EET/EEST (East Europe)" +#define TZ_INFO_EET_EEST_DE "OEZ/OEST (Osteuropa)" + +#define DEFAULT_TZDL_NAMES_EET_EEST_EN { "EET ", "EEST " } +#define DEFAULT_TZDL_NAMES_EET_EEST_DE { "OEZ ", "OESZ " } + +#define DEFAULT_TZDL_OFFS_EET 7200L + +#define DEFAULT_TZDL_EET_EEST_EN \ +{ \ + DEFAULT_TZDL_OFFS_EET, /* offs */ \ + DEFAULt_TZDL_OFFS_DL, /* offs_dl */ \ + DEFAULT_TZDL_TM_ON_EET_EEST, /* tm_on */ \ + DEFAULT_TZDL_TM_OFF_EET_EEST, /* tm_off */ \ + DEFAULT_TZDL_NAMES_EET_EEST_EN /* name[] */ \ +} + +#define DEFAULT_TZDL_EET_EEST_DE \ +{ \ + DEFAULT_TZDL_OFFS_EET, /* offs */ \ + DEFAULt_TZDL_OFFS_DL, /* offs_dl */ \ + DEFAULT_TZDL_TM_ON_EET_EEST, /* tm_on */ \ + DEFAULT_TZDL_TM_OFF_EET_EEST, /* tm_off */ \ + DEFAULT_TZDL_NAMES_EET_EEST_DE /* name[] */ \ +} + +/** @} */ // endgroup + +/** + * The structure below reflects the status of the antenna, + * the times of last disconnect/reconnect, and the board's + * clock offset after the disconnection interval. + */ +typedef struct +{ + int16_t status; /**< current status of antenna */ + TM_GPS tm_disconn; /**< time of antenna disconnect */ + TM_GPS tm_reconn; /**< time of antenna reconnect */ + int32_t delta_t; /**< clock offs. at reconn. time in #GPS_TICKS_PER_SEC */ +} ANT_INFO; + +#define _mbg_swab_ant_info( _p ) \ +{ \ + _mbg_swab16( &(_p)->status ); \ + _mbg_swab_tm_gps( &(_p)->tm_disconn ); \ + _mbg_swab_tm_gps( &(_p)->tm_reconn ); \ + _mbg_swab32( &(_p)->delta_t ); \ +} + + +/** + The status field may be set to one of the values below: +*/ +enum +{ + ANT_INVALID, /**< struct not set yet because ant. has not been disconn. */ + ANT_DISCONN, /**< ant. now disconn., tm_reconn and delta_t not set */ + ANT_RECONN /**< ant. has been disconn. and reconn., all fields valid */ +}; + +/* Defines used with ENABLE_FLAGS */ + +#define EF_OFF 0x00 /**< outputs off until sync'd */ + +#define EF_SERIAL_BOTH 0x03 /**< both serial ports on */ +#define EF_PULSES_BOTH 0x03 /**< both pulses P_SEC and P_MIN on */ +#define EF_FREQ_ALL 0x07 /**< all fixed freq. outputs on */ +#define EF_SYNTH 0x01 /**< synth. on */ + +/** + The structure holds some flags which let + the corresponding outputs be disabled after power-up until + the receiver has synchronized (flag == 0x00, the default) or force + the outputs to be enabled immediately after power-up. The fixed + frequency output is hard-wired to be enabled immediately after + power-up, so the code for freq must always be 0x03. +*/ +typedef struct +{ + uint16_t serial; /**< #EF_OFF or #EF_SERIAL_BOTH */ + uint16_t pulses; /**< #EF_OFF or #EF_PULSES_BOTH */ + uint16_t freq; /**< always #EF_FREQ_ALL */ + uint16_t synth; /**< #EF_OFF or #EF_SYNTH */ +} ENABLE_FLAGS; + +#define _mbg_swab_enable_flags( _p ) \ +{ \ + _mbg_swab16( &(_p)->serial ); \ + _mbg_swab16( &(_p)->pulses ); \ + _mbg_swab16( &(_p)->freq ); \ + _mbg_swab16( &(_p)->synth ); \ +} + + +/* A struct used to hold the settings of a serial port: */ + +#ifndef _COM_HS_DEFINED + /* types of handshake */ + enum { HS_NONE, HS_XONXOFF, HS_RTSCTS, N_COM_HS }; + #define _COM_HS_DEFINED +#endif + +#ifndef _COM_PARM_DEFINED + typedef int32_t BAUD_RATE; + + /* indices used to identify a parameter in the framing string */ + enum { F_DBITS, F_PRTY, F_STBITS }; + + typedef struct + { + BAUD_RATE baud_rate; /* e.g. 19200L */ + char framing[4]; /* e.g. "8N1" */ + int16_t handshake; /* a numeric value, only HS_NONE supported yet */ + } COM_PARM; + + #define _COM_PARM_DEFINED +#endif + +#define _mbg_swab_baud_rate( _p ) _mbg_swab32( _p ) + +#define _mbg_swab_com_parm( _p ) \ +{ \ + _mbg_swab_baud_rate( &(_p)->baud_rate ); \ + _mbg_swab16( &(_p)->handshake ); \ +} + + +/* + * Indices of any supported baud rates. + * Note that not each baud rate must be supported by + * any clock model and/or port: + */ +enum +{ + MBG_BAUD_RATE_300, + MBG_BAUD_RATE_600, + MBG_BAUD_RATE_1200, + MBG_BAUD_RATE_2400, + MBG_BAUD_RATE_4800, + MBG_BAUD_RATE_9600, + MBG_BAUD_RATE_19200, + MBG_BAUD_RATE_38400, + N_MBG_BAUD_RATES /* the number of supported baud rates */ +}; + +/* + * An initializer for a table of baud rate values. + * The values must correspond to the enumeration above. + */ +#define MBG_BAUD_RATES \ +{ \ + 300L, \ + 600L, \ + 1200L, \ + 2400L, \ + 4800L, \ + 9600L, \ + 19200L, \ + 38400L \ +} + +/* + * An initializer for a table of baud rate strings. + * The values must correspond to the enumeration above. + */ +#define MBG_BAUD_STRS \ +{ \ + "300", \ + "600", \ + "1200", \ + "2400", \ + "4800", \ + "9600", \ + "19200", \ + "38400" \ +} + +/* + * The bit masks below can be used to determine which baud rates + * are supported by a serial port. This may vary between + * different ports of the same radio clock since different + * types of UART are used which must not necessarily support + * each baud rate: + */ +#define MBG_PORT_HAS_300 ( 1UL << MBG_BAUD_RATE_300 ) +#define MBG_PORT_HAS_600 ( 1UL << MBG_BAUD_RATE_600 ) +#define MBG_PORT_HAS_1200 ( 1UL << MBG_BAUD_RATE_1200 ) +#define MBG_PORT_HAS_2400 ( 1UL << MBG_BAUD_RATE_2400 ) +#define MBG_PORT_HAS_4800 ( 1UL << MBG_BAUD_RATE_4800 ) +#define MBG_PORT_HAS_9600 ( 1UL << MBG_BAUD_RATE_9600 ) +#define MBG_PORT_HAS_19200 ( 1UL << MBG_BAUD_RATE_19200 ) +#define MBG_PORT_HAS_38400 ( 1UL << MBG_BAUD_RATE_38400 ) + + +/* + * Indices of any supported framings. + * Note that not each framing must be supported by + * any clock model and/or port: + */ +enum +{ + MBG_FRAMING_7N2, + MBG_FRAMING_7E1, + MBG_FRAMING_7E2, + MBG_FRAMING_8N1, + MBG_FRAMING_8N2, + MBG_FRAMING_8E1, + MBG_FRAMING_7O1, + MBG_FRAMING_7O2, + MBG_FRAMING_8O1, + N_MBG_FRAMINGS /* the number of supported framings */ +}; + +/* + * An initializer for a table of framing strings. + * The values must correspond to the enumeration above. + */ +#define MBG_FRAMING_STRS \ +{ \ + "7N2", \ + "7E1", \ + "7E2", \ + "8N1", \ + "8N2", \ + "8E1", \ + "7O1", \ + "7O2", \ + "8O1" \ +} + +/* + * The bit masks below can be used to determine which framings + * are supported by a serial port. This may vary between + * different ports of the same radio clock since different + * types of UART are used which must not necessarily support + * each framing type: + */ +#define MBG_PORT_HAS_7N2 ( 1UL << MBG_FRAMING_7N2 ) +#define MBG_PORT_HAS_7E1 ( 1UL << MBG_FRAMING_7E1 ) +#define MBG_PORT_HAS_7E2 ( 1UL << MBG_FRAMING_7E2 ) +#define MBG_PORT_HAS_8N1 ( 1UL << MBG_FRAMING_8N1 ) +#define MBG_PORT_HAS_8N2 ( 1UL << MBG_FRAMING_8N2 ) +#define MBG_PORT_HAS_8E1 ( 1UL << MBG_FRAMING_8E1 ) +#define MBG_PORT_HAS_7O1 ( 1UL << MBG_FRAMING_7O1 ) +#define MBG_PORT_HAS_7O2 ( 1UL << MBG_FRAMING_7O2 ) +#define MBG_PORT_HAS_8O1 ( 1UL << MBG_FRAMING_8O1 ) + + + +/* + * By default, the baud rates and framings below + * are supported by the UARTs integrated into + * the C166 microcontroller: + */ +#define DEFAULT_GPS_BAUD_RATES_C166 \ +( \ + MBG_PORT_HAS_300 | \ + MBG_PORT_HAS_600 | \ + MBG_PORT_HAS_1200 | \ + MBG_PORT_HAS_2400 | \ + MBG_PORT_HAS_4800 | \ + MBG_PORT_HAS_9600 | \ + MBG_PORT_HAS_19200 \ +) + +#define DEFAULT_GPS_FRAMINGS_C166 \ +( \ + MBG_PORT_HAS_7N2 | \ + MBG_PORT_HAS_7E1 | \ + MBG_PORT_HAS_7E2 | \ + MBG_PORT_HAS_8N1 | \ + MBG_PORT_HAS_8N2 | \ + MBG_PORT_HAS_8E1 \ +) + + +/* + * By default, the baud rates and framings below + * are supported by the UARTs integrated into + * the GP2021 chipset: + */ +#define DEFAULT_GPS_BAUD_RATES_GP2021 \ +( \ + MBG_PORT_HAS_300 | \ + MBG_PORT_HAS_600 | \ + MBG_PORT_HAS_1200 | \ + MBG_PORT_HAS_2400 | \ + MBG_PORT_HAS_4800 | \ + MBG_PORT_HAS_9600 | \ + MBG_PORT_HAS_19200 \ +) + +#define DEFAULT_GPS_FRAMINGS_GP2021 \ +( \ + MBG_PORT_HAS_7N2 | \ + MBG_PORT_HAS_7E2 | \ + MBG_PORT_HAS_8N1 | \ + MBG_PORT_HAS_8E1 | \ + MBG_PORT_HAS_8O1 \ +) + + +/* + * The structure below is more flexible if different receiver + * models have different numbers of serial ports, so the old + * structure PORT_PARM will become obsolete. + */ +typedef struct +{ + COM_PARM parm; /* speed, framing, etc. */ + uint8_t mode; /* per second, per minute, etc. */ + uint8_t str_type; /* type of the output string */ + uint32_t flags; /* reserved for future use, currently 0 */ +} PORT_SETTINGS; + +#define _mbg_swab_port_settings( _p ) \ +{ \ + _mbg_swab_com_parm( &(_p)->parm ); \ + _mbg_swab32( &(_p)->flags ); \ +} + + +/* + * The definitions below can be used to mark specific fields of a + * PORT_SETTINGS structure, e.g. when editing build a mask indicating + * which of the fields have changed or which are not valid. + */ +enum +{ + MBG_PS_BIT_BAUD_RATE_OVR_SW, /* Baud rate index exceeds num supp by driver SW */ + MBG_PS_BIT_BAUD_RATE_OVR_DEV, /* Baud rate index exceeds num supp by device */ + MBG_PS_BIT_BAUD_RATE, /* Baud rate not supp by given port */ + MBG_PS_BIT_FRAMING_OVR_SW, /* Framing index exceeds num supp by driver SW */ + MBG_PS_BIT_FRAMING_OVR_DEV, /* Framing index exceeds num supp by device */ + MBG_PS_BIT_FRAMING, /* Framing not supp by given port */ + MBG_PS_BIT_HS_OVR_SW, /* Handshake index exceeds num supp by driver SW */ + MBG_PS_BIT_HS, /* Handshake mode not supp by given port */ + MBG_PS_BIT_STR_TYPE_OVR_SW, /* String type index exceeds num supp by driver SW */ + MBG_PS_BIT_STR_TYPE_OVR_DEV, /* String type index exceeds num supp by device */ + MBG_PS_BIT_STR_TYPE, /* String type not supp by given port */ + MBG_PS_BIT_STR_MODE_OVR_SW, /* String mode index exceeds num supp by driver SW */ + MBG_PS_BIT_STR_MODE_OVR_DEV, /* String mode index exceeds num supp by device */ + MBG_PS_BIT_STR_MODE, /* String mode not supp by given port and string type */ + MBG_PS_BIT_FLAGS_OVR_SW, /* Flags not supp by driver SW */ + MBG_PS_BIT_FLAGS, /* Flags not supp by device */ + N_MBG_PS_BIT +}; + +#define MBG_PS_MSK_BAUD_RATE_OVR_SW ( 1UL << MBG_PS_BIT_BAUD_RATE_OVR_SW ) +#define MBG_PS_MSK_BAUD_RATE_OVR_DEV ( 1UL << MBG_PS_BIT_BAUD_RATE_OVR_DEV ) +#define MBG_PS_MSK_BAUD_RATE ( 1UL << MBG_PS_BIT_BAUD_RATE ) +#define MBG_PS_MSK_FRAMING_OVR_SW ( 1UL << MBG_PS_BIT_FRAMING_OVR_SW ) +#define MBG_PS_MSK_FRAMING_OVR_DEV ( 1UL << MBG_PS_BIT_FRAMING_OVR_DEV ) +#define MBG_PS_MSK_FRAMING ( 1UL << MBG_PS_BIT_FRAMING ) +#define MBG_PS_MSK_HS_OVR_SW ( 1UL << MBG_PS_BIT_HS_OVR_SW ) +#define MBG_PS_MSK_HS ( 1UL << MBG_PS_BIT_HS ) +#define MBG_PS_MSK_STR_TYPE_OVR_SW ( 1UL << MBG_PS_BIT_STR_TYPE_OVR_SW ) +#define MBG_PS_MSK_STR_TYPE_OVR_DEV ( 1UL << MBG_PS_BIT_STR_TYPE_OVR_DEV ) +#define MBG_PS_MSK_STR_TYPE ( 1UL << MBG_PS_BIT_STR_TYPE ) +#define MBG_PS_MSK_STR_MODE_OVR_SW ( 1UL << MBG_PS_BIT_STR_MODE_OVR_SW ) +#define MBG_PS_MSK_STR_MODE_OVR_DEV ( 1UL << MBG_PS_BIT_STR_MODE_OVR_DEV ) +#define MBG_PS_MSK_STR_MODE ( 1UL << MBG_PS_BIT_STR_MODE ) +#define MBG_PS_MSK_FLAGS_OVR_SW ( 1UL << MBG_PS_BIT_FLAGS_OVR_SW ) +#define MBG_PS_MSK_FLAGS ( 1UL << MBG_PS_BIT_FLAGS ) + + + +/* + * The structure below adds an index number to the structure + * above to allow addressing of several instances: + */ +typedef struct +{ + uint16_t idx; /* 0..RECEIVER_INFO.n_com_port-1 */ + PORT_SETTINGS port_settings; +} PORT_SETTINGS_IDX; + +#define _mbg_swab_port_settings_idx( _p ) \ +{ \ + _mbg_swab16( &(_p)->idx ); \ + _mbg_swab_port_settings( &(_p)->port_settings ); \ +} + + +/* + * The structure below holds the current settings + * for a port, plus additional informaton on the + * port's capabilities. This can be read by setup + * programs to allow setup of supported features + * only. + */ +typedef struct +{ + PORT_SETTINGS port_settings; /* COM port settings as defined above */ + uint32_t supp_baud_rates; /* bit mask of baud rates supp. by this port */ + uint32_t supp_framings; /* bit mask of framings supp. by this port */ + uint32_t supp_str_types; /* bit mask, bit 0 set if str_type[0] supp. */ + uint32_t reserved; /* reserved for future use, currently 0 */ + uint32_t flags; /* reserved for future use, currently 0 */ +} PORT_INFO; + +#define _mbg_swab_port_info( _p ) \ +{ \ + _mbg_swab_port_settings( &(_p)->port_settings ); \ + _mbg_swab32( &(_p)->supp_baud_rates ); \ + _mbg_swab32( &(_p)->supp_framings ); \ + _mbg_swab32( &(_p)->supp_str_types ); \ + _mbg_swab32( &(_p)->reserved ); \ + _mbg_swab32( &(_p)->flags ); \ +} + + +/* + * The structure below adds an index number to the structure + * above to allow addressing of several instances: + */ +typedef struct +{ + uint16_t idx; /* 0..RECEIVER_INFO.n_com_port-1 */ + PORT_INFO port_info; +} PORT_INFO_IDX; + +#define _mbg_swab_port_info_idx( _p ) \ +{ \ + _mbg_swab16( &(_p)->idx ); \ + _mbg_swab_port_info( &(_p)->port_info ); \ +} + + +/* + * The structure below keeps information for a given + * string type, e.g. which modes can be used with that + * string type: + */ +typedef struct +{ + uint32_t supp_modes; /* bit mask of modes supp. with this string type */ + char long_name[23]; /* long name of the string format */ + char short_name[11]; /* short name of the string format */ + uint16_t flags; /* reserved, currently always 0 */ +} STR_TYPE_INFO; + +#define _mbg_swab_str_type_info( _p ) \ +{ \ + _mbg_swab32( &(_p)->supp_modes ); \ + _mbg_swab16( &(_p)->flags ); \ +} + + + +/* + * The structure below adds an index number to the structure + * above to allow addressing of several instances: + */ +typedef struct +{ + uint16_t idx; /* 0..RECEIVER_INFO.n_str_type-1 */ + STR_TYPE_INFO str_type_info; +} STR_TYPE_INFO_IDX; + +#define _mbg_swab_str_type_info_idx( _p ) \ +{ \ + _mbg_swab16( &(_p)->idx ); \ + _mbg_swab_str_type_info( &(_p)->str_type_info ); \ +} + + +/* + * The codes below define valid modes for time strings, + * i.e. the condition when a string is being sent + * via the serial port: + */ +enum +{ + STR_ON_REQ, /* on request only */ + STR_PER_SEC, /* automatically if second changes */ + STR_PER_MIN, /* automatically if minute changes */ + STR_AUTO, /* automatically if required, e.g. on capture event */ + STR_ON_REQ_SEC, /* if second changes and a request has been received */ + N_STR_MODE /* the number of valid modes */ +}; + + +#define DEFAULT_SHORT_MODE_NAMES \ +{ \ + "'?'", \ + "1 sec", \ + "1 min", \ + "auto", \ + "'?' sec" \ +} + + +/* + * Default initializers for English mode string names. Initializers + * for multi-language strings can be found in pcpslstr.h. + */ +#define ENG_MODE_NAME_STR_ON_REQ "on request '?' only" +#define ENG_MODE_NAME_STR_PER_SEC "per second" +#define ENG_MODE_NAME_STR_PER_MIN "per minute" +#define ENG_MODE_NAME_STR_AUTO "automatically" +#define ENG_MODE_NAME_STR_ON_REQ_SEC "sec after request" + +#define DEFAULT_ENG_MODE_NAMES \ +{ \ + ENG_MODE_NAME_STR_ON_REQ, \ + ENG_MODE_NAME_STR_PER_SEC, \ + ENG_MODE_NAME_STR_PER_MIN, \ + ENG_MODE_NAME_STR_AUTO, \ + ENG_MODE_NAME_STR_ON_REQ_SEC \ +} + +/* + * The definitions below are used to set up bit masks + * which restrict the modes which can be used with + * a given string type: + */ +#define MSK_STR_ON_REQ ( 1UL << STR_ON_REQ ) +#define MSK_STR_PER_SEC ( 1UL << STR_PER_SEC ) +#define MSK_STR_PER_MIN ( 1UL << STR_PER_MIN ) +#define MSK_STR_AUTO ( 1UL << STR_AUTO ) +#define MSK_STR_ON_REQ_SEC ( 1UL << STR_ON_REQ_SEC ) + + +/* + * The modes below are supported by most string types: + */ +#define DEFAULT_STR_MODES \ +( \ + MSK_STR_ON_REQ | \ + MSK_STR_PER_SEC | \ + MSK_STR_PER_MIN \ +) + + +/* + * The modes below can be used with the capture string: + */ +#define DEFAULT_STR_MODES_UCAP \ +( \ + MSK_STR_ON_REQ | \ + MSK_STR_AUTO \ +) + + + +/** + * The number of serial ports which were available + * with all GPS receiver models: + */ +#define DEFAULT_N_COM 2 + +/* + * By default that's also the number of ports + * currently available: + */ +#ifndef N_COM + #define N_COM DEFAULT_N_COM +#endif + +/** + * The structure used to store the modes of both serial ports:
+ * (now obsolete) + */ +typedef struct +{ + COM_PARM com[DEFAULT_N_COM]; /**< COM0 and COM1 settings */ + uint8_t mode[DEFAULT_N_COM]; /**< COM0 and COM1 output mode */ +} PORT_PARM; + +#define _mbg_swab_port_parm( _p ) \ +{ \ + int i; \ + for ( i = 0; i < DEFAULT_N_COM; i++ ) \ + { \ + _mbg_swab_com_parm( &(_p)->com[i] ); \ + /* no need to swap mode byte */ \ + } \ +} + + +/* + * The codes below were used with the obsolete + * PORT_PARM.mode above. They are defined for + * compatibility with older devices only: + */ +enum +{ + /* STR_ON_REQ, defined above */ + /* STR_PER_SEC, defined above */ + /* STR_PER_MIN, defined above */ + N_STR_MODE_0 = STR_AUTO, /* COM0 and COM1 */ + STR_UCAP = N_STR_MODE_0, + STR_UCAP_REQ, + N_STR_MODE_1 /* COM1 only */ +}; + + + +/** + @defgroup group_icode IRIG Codes + + The following definitions are used to configure an optional + on-board IRIG input or output. Which frame types are supported + by a device depends on the device type, and may eventually + depend on the device's firmware version. + + All IRIG frames transport the day-of-year number plus the time-of-day, + and include a control field segment which can transport user defined + information. + + Some newer IRIG frames are compatible with older frame types but support + well defined extensions like the year number, local time offset, DST status, + etc., in the control fields: + + - Supported IRIG signal code types: + - \b A002: 1000 bps, DCLS, time-of-year + - \b A003: 1000 bps, DCLS, time-of-year, SBS + - \b A132: 1000 bps, 10 kHz carrier, time-of-year + - \b A133: 1000 bps, 10 kHz carrier, time-of-year, SBS + - \b B002: 100 bps, DCLS, time-of-year + - \b B003: 100 bps, DCLS, time-of-year, SBS + - \b B122: 100 bps, 1 kHz carrier, time-of-year + - \b B123: 100 bps, 1 kHz carrier, time-of-year, SBS + - \b B006: 100 bps, DCLS, complete date + - \b B007: 100 bps, DCLS, complete date, SBS + - \b B126: 100 bps, 1 kHz carrier, complete date + - \b B127: 100 bps, 1 kHz carrier, complete date, SBS + - \b B220/1344: 100 bps, DCLS, manchester encoded, IEEE1344 extensions + - \b B222: 100 bps, DCLS, manchester encoded, time-of-year + - \b B223: 100 bps, DCLS, manchester encoded, time-of-year, SBS + - \b G002: 10 kbps, DCLS, time-of-year + - \b G142: 10 kbps, 100 kHz carrier, time-of-year + - \b G006: 10 kbps, DCLS, complete date + - \b G146: 10 kbps, 100 kHz carrier, complete date + - \b AFNOR: 100 bps, 1 kHz carrier, SBS, complete date + - AFNOR DC: 100 bps, DCLS, SBS, complete date + - \b IEEE1344: 100 bps, 1 kHz carrier, time-of-year, SBS, IEEE1344 extensions (B120) + - IEEE1344 DC: 100 bps, DCLS, time-of-year, SBS, IEEE1344 extensions (B000) + - \b C37.118: like IEEE1344, but UTC offset with reversed sign + - \b C37.118 DC: like IEEE1344 DC, but UTC offset with reversed sign + + - time-of-year: day-of-year, hours, minutes, seconds + - complete date: time-of-year plus year number + - SBS: straight binary seconds, second-of-day + + AFNOR codes are based on the french standard AFNOR NF S87-500 + + IEEE1344 codes are defined in IEEE standard 1344-1995. The code frame is compatible + with B002/B122 but provides some welldefined extensions in the control field which + include a quality indicator (time figure of merit, TFOM), year number, DST and leap + second status, and local time offset from UTC. + + C37.118 codes are defined in IEEE standard C37.118-2005 which includes a revised version + of the IEEE1344 standard from 1995. These codes provide the same extensions as IEEE1344 + but unfortunately define the UTC offset with reversed sign. + + ATTENTION: There are 3rd party IRIG devices out there which apply the UTC offset + as specified in C37.118, but claim to be compatible with IEEE1344. So if local time is + transmitted in the IRIG signal then care must be taken that the UTC offset is evaluated + by the IRIG receiver in the same way as output by the IRIG generator. Otherwise the UTC + time computed by the receiver may be wrong. + @{ + */ + +/** + * Definitions used with IRIG transmitters which usually output both + * the unmodulated and the modulated IRIG signals at the same time: */ +enum +{ + ICODE_TX_B002_B122, + ICODE_TX_B003_B123, + ICODE_TX_A002_A132, + ICODE_TX_A003_A133, + ICODE_TX_AFNOR, + ICODE_TX_IEEE1344, + ICODE_TX_B2201344, // DCLS only + ICODE_TX_B222, // DCLS only + ICODE_TX_B223, // DCLS only + ICODE_TX_B006_B126, + ICODE_TX_B007_B127, + ICODE_TX_G002_G142, + ICODE_TX_G006_G146, + ICODE_TX_C37118, + N_ICODE_TX /**< number of code types */ +}; + + +/** + * Initializers for format name strings. + */ +#define DEFAULT_ICODE_TX_NAMES \ +{ \ + "B002+B122", \ + "B003+B123", \ + "A002+A132", \ + "A003+A133", \ + "AFNOR NF S87-500", \ + "IEEE1344", \ + "B220(1344) DCLS", \ + "B222 DCLS", \ + "B223 DCLS", \ + "B006+B126", \ + "B007+B127", \ + "G002+G142", \ + "G006+G146", \ + "C37.118" \ +} + +/** + * Initializers for short name strings which must not + * be longer than 10 printable characters. + */ +#define DEFAULT_ICODE_TX_NAMES_SHORT \ +{ \ + "B002+B122", \ + "B003+B123", \ + "A002+A132", \ + "A003+A133", \ + "AFNOR NF-S", \ + "IEEE1344", \ + "B220/1344", \ + "B222 DC", \ + "B223 DC", \ + "B006+B126", \ + "B007+B127", \ + "G002+G142", \ + "G006+G146", \ + "C37.118" \ +} + + +/** + * Initializers for English format description strings. + */ +#define DEFAULT_ICODE_TX_DESCRIPTIONS_ENG \ +{ \ + "100 bps, DCLS or 1 kHz carrier", \ + "100 bps, DCLS or 1 kHz carrier, SBS", \ + "1000 bps, DCLS or 10 kHz carrier", \ + "1000 bps, DCLS or 10 kHz carrier, SBS", \ + "100 bps, DCLS or 1 kHz carrier, SBS, complete date", \ + "100 bps, DCLS or 1 kHz carrier, SBS, complete date, time zone info", \ + "100 bps, Manchester enc., DCLS only, SBS, complete date, time zone info", \ + "100 bps, Manchester enc., DCLS only", \ + "100 bps, Manchester enc., DCLS only, SBS", \ + "100 bps, DCLS or 1 kHz carrier, complete date", \ + "100 bps, DCLS or 1 kHz carrier, complete date, SBS", \ + "10 kbps, DCLS or 100 kHz carrier", \ + "10 kbps, DCLS or 100 kHz carrier, complete date", \ + "like IEEE1344, but UTC offset with reversed sign" \ +} + +/* + * The definitions below are used to set up bit masks + * which restrict the IRIG formats which are supported + * by a given IRIG transmitter device: + */ +#define MSK_ICODE_TX_B002_B122 ( 1UL << ICODE_TX_B002_B122 ) +#define MSK_ICODE_TX_B003_B123 ( 1UL << ICODE_TX_B003_B123 ) +#define MSK_ICODE_TX_A002_A132 ( 1UL << ICODE_TX_A002_A132 ) +#define MSK_ICODE_TX_A003_A133 ( 1UL << ICODE_TX_A003_A133 ) +#define MSK_ICODE_TX_AFNOR ( 1UL << ICODE_TX_AFNOR ) +#define MSK_ICODE_TX_IEEE1344 ( 1UL << ICODE_TX_IEEE1344 ) +#define MSK_ICODE_TX_B2201344 ( 1UL << ICODE_TX_B2201344 ) +#define MSK_ICODE_TX_B222 ( 1UL << ICODE_TX_B222 ) +#define MSK_ICODE_TX_B223 ( 1UL << ICODE_TX_B223 ) +#define MSK_ICODE_TX_B006_B126 ( 1UL << ICODE_TX_B006_B126 ) +#define MSK_ICODE_TX_B007_B127 ( 1UL << ICODE_TX_B007_B127 ) +#define MSK_ICODE_TX_G002_G142 ( 1UL << ICODE_TX_G002_G142 ) +#define MSK_ICODE_TX_G006_G146 ( 1UL << ICODE_TX_G006_G146 ) +#define MSK_ICODE_TX_C37118 ( 1UL << ICODE_TX_C37118 ) + +/** + * A mask of IRIG formats with manchester encoded DC output: + */ +#define MSK_ICODE_TX_DC_MANCH \ +( \ + MSK_ICODE_TX_B2201344 | \ + MSK_ICODE_TX_B222 | \ + MSK_ICODE_TX_B223 \ +) + +/** + * A mask of IRIG formats with 1 kHz carrier: + */ +#define MSK_ICODE_TX_1KHZ \ +( \ + MSK_ICODE_TX_B002_B122 | \ + MSK_ICODE_TX_B003_B123 | \ + MSK_ICODE_TX_AFNOR | \ + MSK_ICODE_TX_IEEE1344 | \ + MSK_ICODE_TX_B2201344 | \ + MSK_ICODE_TX_B222 | \ + MSK_ICODE_TX_B223 | \ + MSK_ICODE_TX_B006_B126 | \ + MSK_ICODE_TX_B007_B127 | \ + MSK_ICODE_TX_C37118 \ +) + +/** + * A mask of IRIG formats with 10 kHz carrier: + */ +#define MSK_ICODE_TX_10KHZ \ +( \ + MSK_ICODE_TX_A002_A132 | \ + MSK_ICODE_TX_A003_A133 \ +) + +/** + * A mask of IRIG formats with 100 kHz carrier: + */ +#define MSK_ICODE_TX_100KHZ \ +( \ + MSK_ICODE_TX_G002_G142 | \ + MSK_ICODE_TX_G006_G146 \ +) + +/** + * A mask of IRIG formats with 100 bps data rate: + */ +#define MSK_ICODE_TX_100BPS \ +( \ + MSK_ICODE_TX_B002_B122 | \ + MSK_ICODE_TX_B003_B123 | \ + MSK_ICODE_TX_AFNOR | \ + MSK_ICODE_TX_IEEE1344 | \ + MSK_ICODE_TX_B006_B126 | \ + MSK_ICODE_TX_B007_B127 | \ + MSK_ICODE_TX_C37118 \ +) + +/** + * A mask of IRIG formats with 1000 bps data rate: + */ +#define MSK_ICODE_TX_1000BPS \ +( \ + MSK_ICODE_TX_A002_A132 | \ + MSK_ICODE_TX_A003_A133 \ +) + +/** + * A mask of IRIG formats with 10 kbps data rate: + */ +#define MSK_ICODE_TX_10000BPS \ +( \ + MSK_ICODE_TX_G002_G142 | \ + MSK_ICODE_TX_G006_G146 \ +) + +/** + * A mask of IRIG formats which support TFOM: + */ +#define MSK_ICODE_TX_HAS_TFOM \ +( \ + MSK_ICODE_TX_IEEE1344 | \ + MSK_ICODE_TX_C37118 \ +) + +/** + * A mask of IRIG formats which support time zone information: + */ +#define MSK_ICODE_TX_HAS_TZI \ +( \ + MSK_ICODE_TX_IEEE1344 | \ + MSK_ICODE_TX_C37118 \ +) + +/** + * The default mask of IRIG formats supported by + * IRIG transmitters: + */ +#if !defined( SUPP_MSK_ICODE_TX ) + #define SUPP_MSK_ICODE_TX \ + ( \ + MSK_ICODE_TX_B002_B122 | \ + MSK_ICODE_TX_B003_B123 | \ + MSK_ICODE_TX_A002_A132 | \ + MSK_ICODE_TX_A003_A133 | \ + MSK_ICODE_TX_AFNOR \ + ) +#endif + + + +/** + * Definitions used with IRIG receivers which decode + * two similar IRIG codes (with or without SBS) + * at the same time. + */ +enum +{ + ICODE_RX_B122_B123, // modulated + ICODE_RX_A132_A133, // modulated + ICODE_RX_B002_B003, // DCLS + ICODE_RX_A002_A003, // DCLS + ICODE_RX_AFNOR, // modulated + ICODE_RX_AFNOR_DC, // DCLS + ICODE_RX_IEEE1344, // modulated + ICODE_RX_IEEE1344_DC, // DCLS + ICODE_RX_B126_B127, // modulated + ICODE_RX_B006_B007, // DCLS + ICODE_RX_G142_G146, // modulated + ICODE_RX_G002_G006, // DCLS + ICODE_RX_C37118, // modulated + ICODE_RX_C37118_DC, // DCLS + ICODE_RX_TXC_101, // modulated + ICODE_RX_TXC_101_DC, // DCLS + N_ICODE_RX /* the number of valid signal code types */ +}; + +/** + * Initializers for format name strings. + */ +#define DEFAULT_ICODE_RX_NAMES \ +{ \ + "B122/B123", \ + "A132/A133", \ + "B002/B003 (DCLS)", \ + "A002/A003 (DCLS)", \ + "AFNOR NF S87-500", \ + "AFNOR NF S87-500 (DCLS)", \ + "IEEE1344", \ + "IEEE1344 (DCLS)", \ + "B126/B127", \ + "B006/B007 (DCLS)", \ + "G142/G146", \ + "G002/G006 (DCLS)", \ + "C37.118", \ + "C37.118 (DCLS)", \ + "TXC-101 DTR-6", \ + "TXC-101 DTR-6 (DCLS)" \ +} + +/** + * Initializers for short name strings which must not + * be longer than 11 printable characters. + */ +#define DEFAULT_ICODE_RX_NAMES_SHORT \ +{ \ + "B122/B123", \ + "A132/A133", \ + "B002/B003", \ + "A002/A003", \ + "AFNOR NF-S", \ + "AFNOR DC", \ + "IEEE1344", \ + "IEEE1344 DC", \ + "B126/B127", \ + "B006/B007", \ + "G142/G146", \ + "G002/G006", \ + "C37.118", \ + "C37.118 DC", \ + "TXC-101", \ + "TXC-101 DC" \ +} + + +/** + * Initializers for English format description strings. + */ +#define DEFAULT_ICODE_RX_DESCRIPTIONS_ENG \ +{ \ + "100 bps, 1 kHz carrier, SBS optionally", \ + "1000 bps, 10 kHz carrier, SBS optionally", \ + "100 bps, DCLS, SBS optionally", \ + "1000 bps, DCLS, SBS optionally", \ + "100 bps, 1 kHz carrier, SBS, complete date", \ + "100 bps, DCLS, SBS, complete date", \ + "100 bps, 1 kHz carrier, SBS, time zone info", \ + "100 bps, DCLS, SBS, time zone info", \ + "100 bps, 1 kHz carrier, complete date, SBS optionally", \ + "100 bps, DCLS, complete date, SBS optionally", \ + "10 kbps, 100 kHz carrier, complete date optionally", \ + "10 kbps, DCLS, complete date optionally", \ + "like IEEE1344, but UTC offset with reversed sign", \ + "like IEEE1344 DC, but UTC offset with reversed sign", \ + "code from TV time sync device TXC-101 DTR-6", \ + "DC code from TV time sync device TXC-101 DTR-6" \ +} + +/* + * Bit masks corresponding to the enumeration above: + */ +#define MSK_ICODE_RX_B122_B123 ( 1UL << ICODE_RX_B122_B123 ) +#define MSK_ICODE_RX_A132_A133 ( 1UL << ICODE_RX_A132_A133 ) +#define MSK_ICODE_RX_B002_B003 ( 1UL << ICODE_RX_B002_B003 ) +#define MSK_ICODE_RX_A002_A003 ( 1UL << ICODE_RX_A002_A003 ) +#define MSK_ICODE_RX_AFNOR ( 1UL << ICODE_RX_AFNOR ) +#define MSK_ICODE_RX_AFNOR_DC ( 1UL << ICODE_RX_AFNOR_DC ) +#define MSK_ICODE_RX_IEEE1344 ( 1UL << ICODE_RX_IEEE1344 ) +#define MSK_ICODE_RX_IEEE1344_DC ( 1UL << ICODE_RX_IEEE1344_DC ) +#define MSK_ICODE_RX_B126_B127 ( 1UL << ICODE_RX_B126_B127 ) +#define MSK_ICODE_RX_B006_B007 ( 1UL << ICODE_RX_B006_B007 ) +#define MSK_ICODE_RX_G142_G146 ( 1UL << ICODE_RX_G142_G146 ) +#define MSK_ICODE_RX_G002_G006 ( 1UL << ICODE_RX_G002_G006 ) +#define MSK_ICODE_RX_C37118 ( 1UL << ICODE_RX_C37118 ) +#define MSK_ICODE_RX_C37118_DC ( 1UL << ICODE_RX_C37118_DC ) +#define MSK_ICODE_RX_TXC_101 ( 1UL << ICODE_RX_TXC_101 ) +#define MSK_ICODE_RX_TXC_101_DC ( 1UL << ICODE_RX_TXC_101_DC ) + +/** + * A mask of IRIG DCLS formats: + */ +#define MSK_ICODE_RX_DC \ +( \ + MSK_ICODE_RX_B002_B003 | \ + MSK_ICODE_RX_A002_A003 | \ + MSK_ICODE_RX_AFNOR_DC | \ + MSK_ICODE_RX_IEEE1344_DC | \ + MSK_ICODE_RX_B006_B007 | \ + MSK_ICODE_RX_G002_G006 | \ + MSK_ICODE_RX_C37118_DC \ +) + +/** + * A mask of IRIG formats with 1 kHz carrier: + */ +#define MSK_ICODE_RX_1KHZ \ +( \ + MSK_ICODE_RX_B122_B123 | \ + MSK_ICODE_RX_AFNOR | \ + MSK_ICODE_RX_IEEE1344 | \ + MSK_ICODE_RX_B126_B127 | \ + MSK_ICODE_RX_C37118 \ +) + +/** + * A mask of IRIG formats with 10 kHz carrier: + */ +#define MSK_ICODE_RX_10KHZ \ +( \ + MSK_ICODE_RX_A132_A133 \ +) + +/** + * A mask of IRIG formats with 100 kHz carrier: + */ +#define MSK_ICODE_RX_100KHZ \ +( \ + MSK_ICODE_RX_G142_G146 \ +) + +/** + * A mask of IRIG formats with 100 bps data rate: + */ +#define MSK_ICODE_RX_100BPS \ +( \ + MSK_ICODE_RX_B122_B123 | \ + MSK_ICODE_RX_B002_B003 | \ + MSK_ICODE_RX_AFNOR | \ + MSK_ICODE_RX_AFNOR_DC | \ + MSK_ICODE_RX_IEEE1344 | \ + MSK_ICODE_RX_IEEE1344_DC | \ + MSK_ICODE_RX_B126_B127 | \ + MSK_ICODE_RX_B006_B007 | \ + MSK_ICODE_RX_C37118 | \ + MSK_ICODE_RX_C37118_DC \ +) + +/** + * A mask of IRIG formats with 1000 bps data rate: + */ +#define MSK_ICODE_RX_1000BPS \ +( \ + MSK_ICODE_RX_A132_A133 | \ + MSK_ICODE_RX_A002_A003 \ +) + +/** + * A mask of IRIG formats with 10 kbps data rate: + */ +#define MSK_ICODE_RX_10000BPS \ +( \ + MSK_ICODE_RX_G142_G146 \ +) + +/** + * A mask of IRIG formats which support TFOM: + */ +#define MSK_ICODE_RX_HAS_TFOM \ +( \ + MSK_ICODE_RX_IEEE1344 | \ + MSK_ICODE_RX_IEEE1344_DC | \ + MSK_ICODE_RX_C37118 | \ + MSK_ICODE_RX_C37118_DC \ +) + +/** + * A mask of IRIG formats which support time zone information: + */ +#define MSK_ICODE_RX_HAS_TZI \ +( \ + MSK_ICODE_RX_IEEE1344 | \ + MSK_ICODE_RX_IEEE1344_DC | \ + MSK_ICODE_RX_C37118 | \ + MSK_ICODE_RX_C37118_DC \ +) + +/** + * The default mask of IRIG formats supported by + * IRIG receivers: + */ +#if !defined( SUPP_MSK_ICODE_RX ) + #define SUPP_MSK_ICODE_RX \ + ( \ + MSK_ICODE_RX_B122_B123 | \ + MSK_ICODE_RX_A132_A133 | \ + MSK_ICODE_RX_B002_B003 | \ + MSK_ICODE_RX_A002_A003 | \ + MSK_ICODE_RX_AFNOR | \ + MSK_ICODE_RX_AFNOR_DC \ + ) +#endif +/** @} */ + + + +/** + * The structure below is used to configure an optional + * on-board IRIG output: + */ +typedef struct +{ + uint16_t icode; /**< IRIG signal code, see \ref group_icode */ + uint16_t flags; /**< see \ref group_irig_flags */ +} IRIG_SETTINGS; + +#define _mbg_swab_irig_settings( _p ) \ +{ \ + _mbg_swab16( &(_p)->icode ); \ + _mbg_swab16( &(_p)->flags ); \ +} + + +/** + @defgroup group_irig_flags Bit Masks used with IRIG_SETTINGS::flags + + (others are reserved) +* @{ + */ +#define IFLAGS_DISABLE_TFOM 0x0001 /**< RX ignore/TX don't gen TFOM */ +#define IFLAGS_TX_GEN_LOCAL_TIME 0x0002 /**< gen local time, not UTC */ + +#define IFLAGS_MASK 0x0003 /**< flags above or'ed */ + +// Note: the presence or absence of the IFLAGS_DISABLE_TFOM flag for the IRIG RX +// settings of some PCI cards may not be evaluated correctly by some firmware +// versions for those cards, even if an IRIG code has been configured which supports +// this flag. See the comments near the declaration of the _pcps_incoming_tfom_ignored() +// macro in pcpsdev.h for details. + +/** @} */ + +/** + * @brief Current IRIG settings and supported codes + * + * Used to query the IRIG current IRIG settings + * plus a mask of supported codes. + */ +typedef struct +{ + IRIG_SETTINGS settings; + uint32_t supp_codes; /**< bit mask of supported codes */ +} IRIG_INFO; + +#define _mbg_swab_irig_info( _p ) \ +{ \ + _mbg_swab_irig_settings( &(_p)->settings ); \ + _mbg_swab32( &(_p)->supp_codes ); \ +} + + +// The type below is used to read the board's debug status +// which also include IRIG decoder status: +typedef uint32_t MBG_DEBUG_STATUS; + +// The debug status is bit coded as defined below: +enum +{ + MBG_IRIG_BIT_WARMED_UP, /**< Osc has warmed up */ + MBG_IRIG_BIT_PPS_ACTIVE, /**< PPS output is active */ + MBG_IRIG_BIT_INV_CONFIG, /**< Invalid config, e.g. data csum error */ + MBG_IRIG_BIT_MSG_DECODED, /**< IRIG msg could be decoded */ + MBG_IRIG_BIT_MSG_INCONSISTENT, /**< IRIG msg contains inconsistent data */ + MBG_IRIG_BIT_LOOP_LOCKED, /**< Decoder control loop is locked */ + MBG_IRIG_BIT_JITTER_TOO_LARGE, /**< Phase jitter too large */ + MBG_IRIG_BIT_INV_REF_OFFS, /**< UTC ref offset not configured */ + + MBG_SYS_BIT_INV_TIME, /**< Internal time not valid/set */ + MBG_SYS_BIT_TIME_SET_VIA_API, /**< On board time set externally */ + MBG_SYS_BIT_INV_RTC, /**< On board RTC invalid */ + MBG_SYS_BIT_CPU_PLL_FAILED, /**< The CPU's PLL watchdog */ + + N_MBG_DEBUG_BIT +}; + +/* + * Initializers for IRIG status bit strings. + */ +#define MBG_DEBUG_STATUS_STRS \ +{ \ + "Osc has warmed up", \ + "PPS output is active", \ + "Config set to default", \ + "IRIG msg decoded", \ + "IRIG msg not consistent", \ + "Decoder control loop locked", \ + "Phase jitter too large", \ + "Invalid ref offset", \ + \ + "Internal time not valid", \ + "On board time set via API", \ + "On board RTC invalid", \ + "CPU PLL failure, needs restart" \ +} + + + +#define MBG_IRIG_MSK_WARMED_UP ( 1UL << MBG_IRIG_BIT_WARMED_UP ) +#define MBG_IRIG_MSK_PPS_ACTIVE ( 1UL << MBG_IRIG_BIT_PPS_ACTIVE ) +#define MBG_IRIG_MSK_INV_CONFIG ( 1UL << MBG_IRIG_BIT_INV_CONFIG ) +#define MBG_IRIG_MSK_MSG_DECODED ( 1UL << MBG_IRIG_BIT_MSG_DECODED ) +#define MBG_IRIG_MSK_MSG_INCONSISTENT ( 1UL << MBG_IRIG_BIT_MSG_INCONSISTENT ) +#define MBG_IRIG_MSK_LOOP_LOCKED ( 1UL << MBG_IRIG_BIT_LOOP_LOCKED ) +#define MBG_IRIG_MSK_JITTER_TOO_LARGE ( 1UL << MBG_IRIG_BIT_JITTER_TOO_LARGE ) +#define MBG_IRIG_MSK_INV_REF_OFFS ( 1UL << MBG_IRIG_BIT_INV_REF_OFFS ) + +#define MBG_SYS_MSK_INV_TIME ( 1UL << MBG_SYS_BIT_INV_TIME ) +#define MBG_SYS_MSK_TIME_SET_VIA_API ( 1UL << MBG_SYS_BIT_TIME_SET_VIA_API ) +#define MBG_SYS_MSK_INV_RTC ( 1UL << MBG_SYS_BIT_INV_RTC ) +#define MBG_SYS_MSK_CPU_PLL_FAILED ( 1UL << MBG_SYS_BIT_CPU_PLL_FAILED ) + + + +typedef int16_t MBG_REF_OFFS; /**< -MBG_REF_OFFS_MAX..MBG_REF_OFFS_MAX */ + +#define _mbg_swab_mbg_ref_offs( _p ) _mbg_swab16( (_p) ) + + +/** the maximum allowed positive / negative offset */ +#define MBG_REF_OFFS_MAX ( ( 12L * 60 ) + 30 ) // [minutes] + +/** + * the following value is used to indicate that the ref offset + * value has not yet been configured + */ +#define MBG_REF_OFFS_NOT_CFGD 0x8000 + + +typedef struct +{ + uint32_t flags; +} MBG_OPT_SETTINGS; + +#define _mbg_swab_mbg_opt_settings( _p ) \ +{ \ + _mbg_swab32( &(_p)->flags ); \ +} + + +typedef struct +{ + MBG_OPT_SETTINGS settings; + uint32_t supp_flags; +} MBG_OPT_INFO; + +#define _mbg_swab_mbg_opt_info( _p ) \ +{ \ + _mbg_swab_mbg_opt_settings( &(_p)->settings ); \ + _mbg_swab32( &(_p)->supp_flags ); \ +} + + +enum +{ + MBG_OPT_BIT_STR_UTC, /**< serial string contains UTC time */ + MBG_OPT_BIT_EMU_SYNC, /**< emulate/pretend to be synchronized, */ + /**< alternatively GPS_FEAT_IGNORE_LOCK may be supported */ + N_MBG_OPT_BIT +}; + +/* + * Bit masks corresponding to the enumeration above: + */ +#define MBG_OPT_FLAG_STR_UTC ( 1UL << MBG_OPT_BIT_STR_UTC ) +#define MBG_OPT_FLAG_EMU_SYNC ( 1UL << MBG_OPT_BIT_EMU_SYNC ) + + + +// bit coded return type for PCPS_GET_IRIG_CTRL_BITS +typedef uint32_t MBG_IRIG_CTRL_BITS; + +#define _mbg_swab_irig_ctrl_bits( _p ) _mbg_swab32( _p ) + + +// The following macro extracts the 4 bit TFOM code from the +// IRIG control bits read from a card. This only works if the received +// IRIG code is a code which supports TFOM, this is currently +// only IEEE1344. +#define _pcps_tfom_from_irig_ctrl_bits( _p ) \ + ( ( ( *(_p) ) >> 24 ) & 0x0F ) + + + +#define RAW_IRIG_SIZE 16 + +/** + The buffer below can be used to get the raw data bits + from the IRIG decoder. A maximum number of RAW_IRIG_SIZE + bytes can be filled. If less bytes are used then the rest + of the bytes are filled with zeros. + + The first IRIG bit received from the transmitter is saved + in the MSB (bit 7) of data_bytes[0], etc. +*/ +typedef struct +{ + uint8_t data_bytes[RAW_IRIG_SIZE]; +} MBG_RAW_IRIG_DATA; + +// The following macro extracts the 4 bit TFOM code from the raw +// data bits read from a card. This only works if the received +// IRIG code is a code which supports TFOM, this is currently +// only IEEE1344. +#define _pcps_tfom_from_raw_irig_data( _p ) \ + ( ( ( (_p)->data_bytes[9] >> 2 ) & 0x08 ) \ + | ( ( (_p)->data_bytes[9] >> 4 ) & 0x04 ) \ + | ( ( (_p)->data_bytes[9] >> 6 ) & 0x02 ) \ + | ( ( (_p)->data_bytes[8] & 0x01 ) ) ) + + + +/** + @defgroup group_scale Time Scale Configuration + + The structures and defines can be used to configure the GPS receiver's + basic time scale. By default this is UTC which can optionally + be converted to some local time. However, some applications + prefer TAI or pure GPS time. This can be configured using the + structures below if the GPS_HAS_TIME_SCALE flag is set in + RECEIVER_INFO::features. + @{ +*/ + +enum +{ + MBG_TIME_SCALE_DEFAULT, /**< UTC or local time, t_gps - deltat_ls */ + MBG_TIME_SCALE_GPS, /**< GPS time, monotonical */ + MBG_TIME_SCALE_TAI, /**< TAI, t_gps + GPS_TAI_OFFSET seconds */ + N_MBG_TIME_SCALE +}; + +#define MBG_TIME_SCALE_MSK_DEFAULT ( 1UL << MBG_TIME_SCALE_DEFAULT ) +#define MBG_TIME_SCALE_MSK_GPS ( 1UL << MBG_TIME_SCALE_GPS ) +#define MBG_TIME_SCALE_MSK_TAI ( 1UL << MBG_TIME_SCALE_TAI ) + +// See also the extended status bits TM_SCALE_GPS and TM_SCALE_TAI +// indicating the active time scale setting. + + +#define MBG_TIME_SCALE_STRS \ +{ \ + "UTC/local", \ + "GPS", \ + "TAI" \ +} + + + +/** + The fixed time offset between the GPS and TAI time scales, in seconds +*/ +#define GPS_TAI_OFFSET 19 /**< [s], TAI = GPS + GPS_TAI_OFFSET */ + + +typedef struct +{ + uint8_t scale; /**< current time scale code from the enum above */ + uint8_t flags; /**< reserved, currently always 0 */ +} MBG_TIME_SCALE_SETTINGS; + +#define _mbg_swab_mbg_time_scale_settings( _p ) \ + _nop_macro_fnc() + + +typedef struct +{ + MBG_TIME_SCALE_SETTINGS settings; /**< current settings */ + MBG_TIME_SCALE_SETTINGS max_settings; /**< numb. of scales, all supported flags */ + uint32_t supp_scales; /**< bit masks of supported scales */ +} MBG_TIME_SCALE_INFO; + +#define _mbg_swab_mbg_time_scale_info( _p ) \ +{ \ + _mbg_swab_mbg_time_scale_settings( &(_p)->settings ); \ + _mbg_swab_mbg_time_scale_settings( &(_p)->max_settings ); \ + _mbg_swab32( &(_p)->supp_scales ); \ +} + +/** @} */ // endgroup + + +/* + * The structures below are required to setup the programmable + * pulse outputs which are provided by some GPS receivers. + * The number of programmable pulse outputs supported by a GPS + * receiver is reported in the RECEIVER_INFO.n_str_type field. + */ + +/** + * The structure is used to define a date of year: + */ +typedef struct +{ + uint8_t mday; /* 1..28,29,30,31 */ + uint8_t month; /* 1..12 */ + uint16_t year; /* including century */ +} MBG_DATE; + +#define _mbg_swab_mbg_date( _p ) \ +{ \ + _mbg_swab16( &(_p)->year ); \ +} + + +/** + * The structure is used to define a time of day: + */ +typedef struct +{ + uint8_t hour; /* 0..23 */ + uint8_t min; /* 0..59 */ + uint8_t sec; /* 0..59,60 */ + uint8_t sec100; /* reserved, currently always 0 */ +} MBG_TIME; + +#define _mbg_swab_mbg_time( _p ) \ + _nop_macro_fnc() // nothing to swap + + +/** + * The structure defines a single date and time + * for switching operations: + */ +typedef struct +{ + MBG_DATE d; /* date to switch */ + MBG_TIME t; /* time to switch */ + uint8_t wday; /* reserved, currently always 0 */ + uint8_t flags; /* reserved, currently 0 */ +} MBG_DATE_TIME; + +#define _mbg_swab_mbg_date_time( _p ) \ +{ \ + _mbg_swab_mbg_date( &(_p)->d ); \ + _mbg_swab_mbg_time( &(_p)->t ); \ +} + + +/** + * The structure defines times and dates + * for an on/off cycle: + */ +typedef struct +{ + MBG_DATE_TIME on; /* time and date to switch on */ + MBG_DATE_TIME off; /* time and date to switch off */ +} POUT_TIME; + +#define _mbg_swab_pout_time( _p ) \ +{ \ + _mbg_swab_mbg_date_time( &(_p)->on ); \ + _mbg_swab_mbg_date_time( &(_p)->off ); \ +} + + +/** + * The number of POUT_TIMEs for each programmable pulse output + */ +#define N_POUT_TIMES 3 + +/** + * The structure is used to configure a single programmable + * pulse output. + */ +typedef struct +{ + uint16_t mode; /**< mode of operation, codes defined below */ + uint16_t pulse_len; /**< 10 msec units, or COM port number */ + uint16_t timeout; /**< [min], for dcf_mode */ + uint16_t flags; /**< see below */ + POUT_TIME tm[N_POUT_TIMES]; /**< switching times */ +} POUT_SETTINGS; + +#define _mbg_swab_pout_settings( _p ) \ +{ \ + int i; \ + _mbg_swab16( &(_p)->mode ); \ + _mbg_swab16( &(_p)->pulse_len ); \ + _mbg_swab32( &(_p)->timeout ); \ + _mbg_swab16( &(_p)->flags ); \ + \ + for ( i = 0; i < N_POUT_TIMES; i++ ) \ + _mbg_swab_pout_time( &(_p)->tm[i] ); \ +} + + +#define MAX_POUT_PULSE_LEN 1000 /**< 10 secs, in 10 msec units */ +#define MAX_POUT_DCF_TIMOUT ( 48 * 60 ) /**< 48 hours, in minutes */ + + +/** + * These codes are defined for POUT_SETTINGS.mode to setup + * the basic mode of operation for a single programmable pulse + * output: + */ +enum +{ + POUT_IDLE, /**< always off, or on if POUT_INVERTED */ + POUT_TIMER, /**< switch on/off at configured times */ + POUT_SINGLE_SHOT, /**< pulse at time POUT_SETTINGS.tm[0].on */ + POUT_CYCLIC_PULSE, /**< pulse every POUT_SETTINGS.tm[0].on.t interval */ + POUT_PER_SEC, /**< pulse if second changes */ + POUT_PER_MIN, /**< pulse if minute changes */ + POUT_PER_HOUR, /**< pulse if hour changes */ + POUT_DCF77, /**< emulate DCF77 signal */ + POUT_POS_OK, /**< on if pos. OK (nav_solved) */ + POUT_TIME_SYNC, /**< on if time sync (time_syn) */ + POUT_ALL_SYNC, /**< on if pos. OK and time sync */ + POUT_TIMECODE, /**< IRIG/AFNOR DCLS output */ + POUT_TIMESTR, /**< COM port number in pulse_len field */ + POUT_10MHZ, /**< 10 MHz fixed frequency */ + POUT_DCF77_M59, /**< DCF77-like signal with 500 ms pulse in 59th second */ + POUT_SYNTH, /**< programmable synthesizer frequency */ + N_POUT_MODES +}; + + +/* + * Default initializers for English pulse mode names. Initializers + * for multi-language strings can be found in pcpslstr.h. + */ +#define ENG_POUT_NAME_IDLE "Idle" +#define ENG_POUT_NAME_TIMER "Timer" +#define ENG_POUT_NAME_SINGLE_SHOT "Single Shot" +#define ENG_POUT_NAME_CYCLIC_PULSE "Cyclic Pulse" +#define ENG_POUT_NAME_PER_SEC "Pulse Per Second" +#define ENG_POUT_NAME_PER_MIN "Pulse Per Min" +#define ENG_POUT_NAME_PER_HOUR "Pulse Per Hour" +#define ENG_POUT_NAME_DCF77 "DCF77 Marks" +#define ENG_POUT_NAME_POS_OK "Position OK" +#define ENG_POUT_NAME_TIME_SYNC "Time Sync" +#define ENG_POUT_NAME_ALL_SYNC "All Sync" +#define ENG_POUT_NAME_TIMECODE "DCLS Time Code" +#define ENG_POUT_NAME_TIMESTR "COM Time String" +#define ENG_POUT_NAME_10MHZ "10 MHz Frequency" +#define ENG_POUT_NAME_DCF77_M59 "DCF77-like M59" +#define ENG_POUT_NAME_SYNTH "Synthesizer Frequency" + +#define DEFAULT_ENG_POUT_NAMES \ +{ \ + ENG_POUT_NAME_IDLE, \ + ENG_POUT_NAME_TIMER, \ + ENG_POUT_NAME_SINGLE_SHOT, \ + ENG_POUT_NAME_CYCLIC_PULSE, \ + ENG_POUT_NAME_PER_SEC, \ + ENG_POUT_NAME_PER_MIN, \ + ENG_POUT_NAME_PER_HOUR, \ + ENG_POUT_NAME_DCF77, \ + ENG_POUT_NAME_POS_OK, \ + ENG_POUT_NAME_TIME_SYNC, \ + ENG_POUT_NAME_ALL_SYNC, \ + ENG_POUT_NAME_TIMECODE, \ + ENG_POUT_NAME_TIMESTR, \ + ENG_POUT_NAME_10MHZ, \ + ENG_POUT_NAME_DCF77_M59, \ + ENG_POUT_NAME_SYNTH \ +} + + +#define ENG_POUT_HINT_IDLE "Constant output level" +#define ENG_POUT_HINT_TIMER "Switch based on configured on/off times" +#define ENG_POUT_HINT_SINGLE_SHOT "Generate a single pulse of determined length" +#define ENG_POUT_HINT_CYCLIC_PULSE "Generate cyclic pulses of determined length" +#define ENG_POUT_HINT_PER_SEC "Generate pulse at beginning of new second" +#define ENG_POUT_HINT_PER_MIN "Generate pulse at beginning of new minute" +#define ENG_POUT_HINT_PER_HOUR "Generate pulse at beginning of new hour" +#define ENG_POUT_HINT_DCF77 "DCF77 compatible time marks" +#define ENG_POUT_HINT_POS_OK "Switch if receiver position has been verified" +#define ENG_POUT_HINT_TIME_SYNC "Switch if time is synchronized" +#define ENG_POUT_HINT_ALL_SYNC "Switch if full sync" +#define ENG_POUT_HINT_TIMECODE "Duplicate IRIG time code signal" +#define ENG_POUT_HINT_TIMESTR "Duplicate serial time string of specified port" +#define ENG_POUT_HINT_10MHZ "10 MHz fixed output frequency" +#define ENG_POUT_HINT_DCF77_M59 "DCF77 time marks with 500 ms pulse in 59th second" +#define ENG_POUT_HINT_SYNTH "Frequency generated by programmable synthesizer" + +#define DEFAULT_ENG_POUT_HINTS \ +{ \ + ENG_POUT_HINT_IDLE, \ + ENG_POUT_HINT_TIMER, \ + ENG_POUT_HINT_SINGLE_SHOT, \ + ENG_POUT_HINT_CYCLIC_PULSE, \ + ENG_POUT_HINT_PER_SEC, \ + ENG_POUT_HINT_PER_MIN, \ + ENG_POUT_HINT_PER_HOUR, \ + ENG_POUT_HINT_DCF77, \ + ENG_POUT_HINT_POS_OK, \ + ENG_POUT_HINT_TIME_SYNC, \ + ENG_POUT_HINT_ALL_SYNC, \ + ENG_POUT_HINT_TIMECODE, \ + ENG_POUT_HINT_TIMESTR, \ + ENG_POUT_HINT_10MHZ, \ + ENG_POUT_HINT_DCF77_M59, \ + ENG_POUT_HINT_SYNTH \ +} + + +/* + * The definitions below are used to set up bit masks + * which restrict the modes which can be used with + * a given programmable output: + */ +#define MSK_POUT_IDLE ( 1UL << POUT_IDLE ) +#define MSK_POUT_TIMER ( 1UL << POUT_TIMER ) +#define MSK_POUT_SINGLE_SHOT ( 1UL << POUT_SINGLE_SHOT ) +#define MSK_POUT_CYCLIC_PULSE ( 1UL << POUT_CYCLIC_PULSE ) +#define MSK_POUT_PER_SEC ( 1UL << POUT_PER_SEC ) +#define MSK_POUT_PER_MIN ( 1UL << POUT_PER_MIN ) +#define MSK_POUT_PER_HOUR ( 1UL << POUT_PER_HOUR ) +#define MSK_POUT_DCF77 ( 1UL << POUT_DCF77 ) +#define MSK_POUT_POS_OK ( 1UL << POUT_POS_OK ) +#define MSK_POUT_TIME_SYNC ( 1UL << POUT_TIME_SYNC ) +#define MSK_POUT_ALL_SYNC ( 1UL << POUT_ALL_SYNC ) +#define MSK_POUT_TIMECODE ( 1UL << POUT_TIMECODE ) +#define MSK_POUT_TIMESTR ( 1UL << POUT_TIMESTR ) +#define MSK_POUT_10MHZ ( 1UL << POUT_10MHZ ) +#define MSK_POUT_DCF77_M59 ( 1UL << POUT_DCF77_M59 ) +#define MSK_POUT_SYNTH ( 1UL << POUT_SYNTH ) + + +/* + * The codes below are used with POUT_SETTINGS::flags: + */ +#define POUT_INVERTED 0x0001 // invert output level +#define POUT_IF_SYNC_ONLY 0x0002 // disable in holdover mode +#define POUT_TIMEBASE_UTC 0x0004 // use UTC, only applicable for DCF77 output + + +/** + Since a clock may support more than one programmable + pulse output, setup tools must use the structure below + to read/set pulse output configuration. + The number of outputs supported by a receiver model + can be queried using the RECEIVER_INFO structure. + */ +typedef struct +{ + uint16_t idx; /**< 0..RECEIVER_INFO.n_prg_out-1 */ + POUT_SETTINGS pout_settings; +} POUT_SETTINGS_IDX; + +#define _mbg_swab_pout_settings_idx( _p ) \ +{ \ + _mbg_swab16( &(_p)->idx ); \ + _mbg_swab_pout_settings( &(_p)->pout_settings ); \ +} + + +/** + The structure below holds the current settings + for a programmable pulse output, plus additional + informaton on the output's capabilities. + This can be read by setup programs to allow setup + of supported features only. + */ +typedef struct +{ + POUT_SETTINGS pout_settings; + uint32_t supp_modes; /**< bit mask of modes supp. by this output */ + uint8_t timestr_ports; /**< bit mask of COM ports supported for POUT_TIMESTR */ + uint8_t reserved_0; /**< reserved for future use, currently 0 */ + uint16_t reserved_1; /**< reserved for future use, currently 0 */ + uint32_t flags; /**< see below */ +} POUT_INFO; + +#define _mbg_swab_pout_info( _p ) \ +{ \ + _mbg_swab_pout_settings( &(_p)->pout_settings ); \ + _mbg_swab32( &(_p)->supp_modes ); \ + _mbg_swab16( &(_p)->reserved_1 ); \ + _mbg_swab32( &(_p)->flags ); \ +} + + +/** The max number of COM ports that can be handled by POUT_INFO::timestr_ports */ +#define MAX_POUT_TIMESTR_PORTS 8 + + +/* + * The codes below are used with POUT_INFO::flags: + */ +#define POUT_SUPP_IF_SYNC_ONLY 0x0001 // supports disabling outputs in holdover mode +#define POUT_SUPP_DCF77_UTC 0x0002 // supports UTC output in DCF77 mode + + +/** + The structure below adds an index number to the structure + above to allow addressing of several instances: + */ +typedef struct +{ + uint16_t idx; /**< 0..RECEIVER_INFO.n_prg_out-1 */ + POUT_INFO pout_info; +} POUT_INFO_IDX; + +#define _mbg_swab_pout_info_idx( _p ) \ +{ \ + _mbg_swab16( &(_p)->idx ); \ + _mbg_swab_pout_info( &(_p)->pout_info ); \ +} + + +/* + * The codes below are used with devices which support multiple + * ref time sources at the same time. The priorities of the + * supported ref time sources is configurable. + */ + + +/* + * All possibly supported ref time sources + */ +enum +{ + MULTI_REF_NONE = -1, // nothing, undefined + MULTI_REF_GPS = 0, // standard GPS + MULTI_REF_10MHZ, // 10 MHz input frequency + MULTI_REF_PPS, // 1 PPS input signal + MULTI_REF_10MHZ_PPS, // combined 10 MHz plus PPS + MULTI_REF_IRIG, // IRIG input + MULTI_REF_NTP, // Network Time Protocol (NTP) + MULTI_REF_PTP, // Precision Time Protocol (PTP, IEEE1588) + MULTI_REF_PTP_E1, // PTP over E1 + MULTI_REF_FREQ, // fixed frequency + MULTI_REF_PPS_STRING, // 1 PPS in addition to string + N_MULTI_REF // the number of defined sources +}; + + +/* + * Names of supported ref time sources + */ +#define DEFAULT_MULTI_REF_NAMES \ +{ \ + "GPS", \ + "10 MHz freq in", \ + "PPS in", \ + "10 MHz + PPS in", \ + "IRIG", \ + "NTP", \ + "PTP (IEEE1588)", \ + "PTP over E1", \ + "Fixed Freq. in", \ + "PPS plus string" \ +} + + +/* + * Bit masks used to indicate supported reference sources + */ +#define HAS_MULTI_REF_GPS ( 1UL << MULTI_REF_GPS ) +#define HAS_MULTI_REF_10MHZ ( 1UL << MULTI_REF_10MHZ ) +#define HAS_MULTI_REF_PPS ( 1UL << MULTI_REF_PPS ) +#define HAS_MULTI_REF_10MHZ_PPS ( 1UL << MULTI_REF_10MHZ_PPS ) +#define HAS_MULTI_REF_IRIG ( 1UL << MULTI_REF_IRIG ) +#define HAS_MULTI_REF_NTP ( 1UL << MULTI_REF_NTP ) +#define HAS_MULTI_REF_PTP ( 1UL << MULTI_REF_PTP ) +#define HAS_MULTI_REF_PTP_E1 ( 1UL << MULTI_REF_PTP_E1 ) +#define HAS_MULTI_REF_FREQ ( 1UL << MULTI_REF_FREQ ) +#define HAS_MULTI_REF_PPS_STRING ( 1UL << MULTI_REF_PPS_STRING ) + + +/* + * There are 2 different ways to configure multi ref support + * provided by some devices. + * + * Newer devices which have the GPS_FEAT_XMULTI_REF flag set + * in RECEIVER_INFO::features support the newer XMULTI_REF_... + * structures which provide a more flexible interface. + * + * Older devices which have the GPS_FEAT_MULTI_REF flag set + * support these MULTI_REF_... structures below where + * the number of supported input sources and priorities + * is limited to N_MULTI_REF_PRIO. + */ + +#define N_MULTI_REF_PRIO 4 + + +/** + The structure below is used to configure the priority of + the supported ref sources. + + The number stored in prio[0] of the array indicates the ref time + source with highest priority. If that source fails, the device + falls back to the source indicated by prio[1]. Each field of + the prio[] array must be set to one of the values 0..N_MULTI_REF-1, + or to -1 (0xFF) if the value is not assigned. + */ +typedef struct +{ + uint8_t prio[N_MULTI_REF_PRIO]; +} MULTI_REF_SETTINGS; + + +/** + The structure below is used to query the MULTI_REF configuration, + plus the supported ref sources. + */ +typedef struct +{ + MULTI_REF_SETTINGS settings; /* current settings */ + uint32_t supp_ref; /* supp. HAS_MULTI_REF_... codes or'ed */ + uint16_t n_levels; /* supp. levels, 0..N_MULTI_REF_PRIO */ + uint16_t flags; /* reserved, currently 0 */ +} MULTI_REF_INFO; + + +/* + * The type below is used to query the MULTI_REF status information, + */ +typedef uint16_t MULTI_REF_STATUS; /* flag bits as defined below */ + + +/* + * The bits and associated bit masks below are used with the + * MULTI_REF_STATUS type. Each bit is set if the associated + * condition is true and is reset if the condition is not true: + */ +enum +{ + WRN_MODULE_MODE, /* selected input mode was invalid, set to default */ + WRN_COLD_BOOT, /* GPS is in cold boot mode */ + WRN_WARM_BOOT, /* GPS is in warm boot mode */ + WRN_ANT_DISCONN, /* antenna is disconnected */ + WRN_10MHZ_UNLOCK, /* impossible to lock to external 10MHz reference */ + WRN_1PPS_UNLOCK, /* impossible to lock to external 1PPS reference */ + WRN_GPS_UNLOCK, /* impossible to lock to GPS */ + WRN_10MHZ_MISSING, /* external 10MHz signal not available */ + WRN_1PPS_MISSING, /* external 1PPS signal not available */ + N_MULTI_REF_STATUS_BITS +}; + +#define MSK_WRN_COLD_BOOT ( 1UL << WRN_COLD_BOOT ) +#define MSK_WRN_WARM_BOOT ( 1UL << WRN_WARM_BOOT ) +#define MSK_WRN_ANT_DISCONN ( 1UL << WRN_ANT_DISCONN ) +#define MSK_WRN_10MHZ_UNLOCK ( 1UL << WRN_10MHZ_UNLOCK ) +#define MSK_WRN_1PPS_UNLOCK ( 1UL << WRN_1PPS_UNLOCK ) +#define MSK_WRN_GPS_UNLOCK ( 1UL << WRN_GPS_UNLOCK ) +#define MSK_WRN_10MHZ_MISSING ( 1UL << WRN_10MHZ_MISSING ) +#define MSK_WRN_1PPS_MISSING ( 1UL << WRN_1PPS_MISSING ) +#define MSK_WRN_MODULE_MODE ( 1UL << WRN_MODULE_MODE ) + + + +/* + * If the RECEIVER_INFO::features flag GPS_FEAT_XMULTI_REF is set + * then the following XMULTI_REF_... data structures must be used + * instead of the older MULTI_REF_... structures above. + * + * Those devices support a number of priority levels addressed by + * the priority index, starting at 0 for highest priority. A single + * reference time source from the set of supported sources can be + * assigned to each priority level. + * + * The structures below are used to configure the individual + * time source for each priority level, and retrieve the status + * of the time source at each priority level. + */ + +typedef struct +{ + uint8_t type; /* 0..N_MULTI_REF-1 from the enum above */ + uint8_t instance; /* reserved, currently always 0 */ +} XMULTI_REF_ID; + +typedef struct +{ + XMULTI_REF_ID id; /* time source identifier */ + uint16_t flags; /* reserved, currently always 0 */ + NANO_TIME bias; /* time bias, e.g. path delay */ + NANO_TIME precision; /* precision of the time source */ + uint32_t fine_limit; /* smooth control if below this limit */ +} XMULTI_REF_SETTINGS; + + +/* + * The structure below is used to retrieve or configure the time source + * for a specific priority level. + * After configuring, a structure with idx == 0xFFFF (-1) must be sent + * to let the changes become effective. + */ +typedef struct +{ + uint16_t idx; /* the priority level index, highest == 0 */ + XMULTI_REF_SETTINGS settings; /* the settings configured for this level */ + +} XMULTI_REF_SETTINGS_IDX; + + +/* + * The structure below contains the XMULTI_REF configuration + * for a single priority level, plus information on supported + * ref time sources, and the number of supported priority levels. + */ +typedef struct +{ + XMULTI_REF_SETTINGS settings; /* current settings */ + uint32_t supp_ref; /* supp. HAS_MULTI_REF_... codes or'ed */ + uint8_t n_supp_ref; /* number of supported ref time sources */ + uint8_t n_prio; /* number of supported priority levels */ + uint16_t flags; /* reserved, currently 0, e.g. multiple instance support */ + +} XMULTI_REF_INFO; + + +/* + * The structure below is used to retrieve the XMULTI_REF configuration + * information for a specific priority level. + */ +typedef struct +{ + uint16_t idx; /* the priority level index, highest == 0 */ + XMULTI_REF_INFO info; + +} XMULTI_REF_INFO_IDX; + + +/* + * The structure below contains status information on a single + * ref time source. + */ +typedef struct +{ + XMULTI_REF_ID id; /* time source identifier */ + uint16_t status; /* flag bits as defined below */ + NANO_TIME offset; /* time offset from main time base */ + uint32_t reserved; /* reserved, currently always 0 */ + +} XMULTI_REF_STATUS; + + +/* + * The structure below is used to retrieve the the status information + * of the time source at a specific priority level. + */ +typedef struct +{ + uint16_t idx; /* the priority level index, highest == 0 */ + XMULTI_REF_STATUS status; + +} XMULTI_REF_STATUS_IDX; + + +/* + * Bits used with XMULTI_REF_STATUS. + */ +enum +{ + XMRS_BIT_NOT_SUPP, /* ref type cfg'd for this level is not supported */ + XMRS_BIT_NO_CONN, /* input signal is disconnected */ + XMRS_BIT_NO_SIGNAL, /* no input signal */ + XMRS_BIT_IS_MASTER, /* reference is master source */ + XMRS_BIT_IS_LOCKED, /* locked to input signal */ + XMRS_BIT_IS_ACCURATE, /* oscillator control has reached full accuracy */ + XMRS_BIT_NOT_SETTLED, /* reference time signal not settled */ + XMRS_BIT_NOT_PHASE_LOCKED, /* oscillator not phase locked to PPS */ + N_XMRS_BITS +}; + + +/* bit masks corresponding to the flag bits above */ + +#define XMRS_MSK_NOT_SUPP ( 1UL << XMRS_BIT_NOT_SUPP ) +#define XMRS_MSK_NO_CONN ( 1UL << XMRS_BIT_NO_CONN ) +#define XMRS_MSK_NO_SIGNAL ( 1UL << XMRS_BIT_NO_SIGNAL ) +#define XMRS_MSK_IS_MASTER ( 1UL << XMRS_BIT_IS_MASTER ) +#define XMRS_MSK_IS_LOCKED ( 1UL << XMRS_BIT_IS_LOCKED ) +#define XMRS_MSK_IS_ACCURATE ( 1UL << XMRS_BIT_IS_ACCURATE ) +#define XMRS_MSK_NOT_SETTLED ( 1UL << XMRS_BIT_NOT_SETTLED ) +#define XMRS_MSK_NOT_PHASE_LOCKED ( 1UL << XMRS_BIT_NOT_PHASE_LOCKED ) + + + +/* + * An initializer for a XMULTI_REF_STATUS variable + * with status invalid / not used + */ +#define XMULTI_REF_STATUS_INVALID \ +{ \ + { (uint8_t) MULTI_REF_NONE, 0 }, /* id; instance 0 ? */ \ + XMRS_MSK_NO_CONN | XMRS_MSK_NO_SIGNAL, /* status */ \ + { 0 }, /* offset */ \ + 0 /* reserved */ \ +} + + + +/*------------------------------------------------------------------------*/ + +/* + * The types below are not used with all devices: + */ + +typedef uint16_t ROM_CSUM; /* The ROM checksum */ +typedef uint16_t RCV_TIMEOUT; /* [min] (only if HAS_RCV_TIMEOUT) */ +typedef uint16_t IGNORE_LOCK; /* (only if GPS_HAS_IGNORE_LOCK) */ + +/* + * Originally IGNORE_LOG above has been a boolean value (equal or + * not equal 0) which was evaluated the same way for all ports. + * + * Due to special firmware requirements it has been changed to a + * bit maskable property in order to be able to specify the behaviour + * for individual ports. + * + * In order to keep compatibility with older versions the LSB is used + * to specify ignore_lock for all ports. The next higher bits are used + * to specify ignore_lock for an individual port, where the bit position + * depends on the port number, e.g. 0x02 for COM0, 0x04 for COM1, etc. + * The macros below can be used to simplify the code: + */ + +/* return a bit mask depending on the port number */ +#define IGNORE_LOCK_FOR_ALL_PORTS 0x01 + +#define _ignore_lock_for_all_ports() ( IGNORE_LOCK_FOR_ALL_PORTS ) + +#define _ignore_lock_for_port( _n ) ( 0x02 << (_n) ) + +/* check if all ports are ignore_lock'ed */ +#define _is_ignore_lock_all_ports( _il ) ( (_il) & IGNORE_LOCK_FOR_ALL_PORTS ) + +/* check if a specific port is ignore_lock'ed */ +#define _is_ignore_lock_for_port( _il, _n ) \ + ( (_il) & ( _ignore_lock_for_port(_n) | IGNORE_LOCK_FOR_ALL_PORTS ) ) + + +/*------------------------------------------------------------------------*/ + +/* + * The structures below are used with the SCU multiplexer board + * in a redundant system: + */ + +typedef struct +{ + uint32_t hw_id; // hardware identification + uint32_t fw_id; // firmware identification + uint16_t flags; // reserved currently 0 + uint8_t clk0_info; // reference clock 0 type + uint8_t clk1_info; // reference clock 1 type + uint16_t epld_status; // epld status word, see defintions below + uint16_t epld_control; // epld control word, see defintions below +} SCU_STAT_INFO; + +typedef struct +{ + uint16_t epld_control_mask; // control mask, determines which bit is to be changed + uint16_t epld_control_value; // control value, determines value of bits to be changed + uint32_t flags; // reserved, currently 0 +} SCU_STAT_SETTINGS; + +// definitions for status word bit masks +#define MSK_EPLD_STAT_TS1 0x0001 // state of time sync signal clk_1 +#define MSK_EPLD_STAT_TS2 0x0002 // state of time sync signal clk_2 +#define MSK_EPLD_STAT_TL_ERROR 0x0004 // state of time limit error input +#define MSK_EPLD_STAT_PSU1_OK 0x0008 // state of power supply 1 monitoring input +#define MSK_EPLD_STAT_PSU2_OK 0x0010 // state of power supply 2 monitoring input +#define MSK_EPLD_STAT_AUTO 0x0020 // AUTOMATIC/REMOTE or MANUAL Mode +#define MSK_EPLD_STAT_SEL 0x0040 // select bit for output MUX, ( clk_1 = 0 ) +#define MSK_EPLD_STAT_ENA 0x0080 // enable Bit for output MUX, set if enabled +#define MSK_EPLD_STAT_ACO 0x4000 // Access control override bit +#define MSK_EPLD_STAT_WDOG_OK 0x8000 // WDT_OK set to zero if watchdog expired + + +#define MSK_EPLD_CNTL_SEL_REM 0x0800 // remote select for output MUX ( clk_1 = 0 ) +#define MSK_EPLD_CNTL_DIS_REM 0x1000 // remote disable for output MUX +#define MSK_EPLD_CNTL_REMOTE 0x2000 // must be set to enable remote operation +#define MSK_EPLD_CNTL_SEL_SNMP 0x4000 // connect COM0 channels to XPORT +#define MSK_EPLD_CNTL_ENA_SNMP 0x8000 // select clk for comm. ( clk1 = 0 ) + + +/* + * Definitions for clk0_info and clk1_info, can be used to determine + * the reference clock type connected to SCU input channel 0 and 1: + */ +enum +{ + SCU_CLK_INFO_GPS, // ref. clock is GPS receiver + SCU_CLK_INFO_DCF_PZF, // ref. clock is DCF77 PZF receiver + SCU_CLK_INFO_DCF_AM, // ref. clock is DCF77 AM receiver + SCU_CLK_INFO_TCR // ref. clock is IRIG time code receiver +}; + + + +/*------------------------------------------------------------------------*/ + +/* + * GPS receiver modes of operation. Some of the codes combinations + * are obsolete with recent GPS receivers. However, that doesn't + * matter since the mode is just read from the receiver: + */ +#define REMOTE 0x10 +#define BOOT 0x20 + +#define TRACK ( 0x01 ) +#define AUTO_166 ( 0x02 ) +#define WARM_166 ( 0x03 | BOOT ) +#define COLD_166 ( 0x04 | BOOT ) +#define AUTO_BC ( 0x05 | REMOTE ) +#define WARM_BC ( 0x06 | REMOTE | BOOT ) +#define COLD_BC ( 0x07 | REMOTE | BOOT ) +#define UPDA_166 ( 0x08 | BOOT ) +#define UPDA_BC ( 0x09 | REMOTE | BOOT ) + + + +typedef int16_t DAC_VAL; + +#define _mbg_swab_dac_val( _p ) \ + _mbg_swab16( _p ); + + + +typedef struct +{ + uint16_t mode; /**< Mode of operation */ + uint16_t good_svs; /**< Numb. of satellites that can currently be received and used */ + uint16_t svs_in_view; /**< Numb. of satellites that should be in view according to the almanac data */ + DAC_VAL dac_val; /**< Oscillator fine DAC value */ + DAC_VAL dac_cal; /**< Oscillator calibration DAC value ( see #OSC_DAC_RANGE, #OSC_DAC_BIAS ) */ +} STAT_INFO; + +#define _mbg_swab_stat_info( _p ) \ +{ \ + _mbg_swab16( &(_p)->mode ); \ + _mbg_swab16( &(_p)->good_svs ); \ + _mbg_swab16( &(_p)->svs_in_view ); \ + _mbg_swab_dac_val( &(_p)->dac_val ); \ + _mbg_swab_dac_val( &(_p)->dac_cal ); \ +} + + +#define OSC_DAC_RANGE 4096UL +#define OSC_DAC_BIAS ( OSC_DAC_RANGE / 2 ) + + + +/* + The enumeration below lists all + known satellite navigation systems +*/ +enum +{ + GNSS_TYPE_GPS, + GNSS_TYPE_GLONASS, + GNSS_TYPE_BEIDOU, + GNSS_TYPE_GALILEO, + N_GNSS_TYPES +}; + + + +#define GNSS_TYPE_STRS \ +{ \ + "GPS", \ + "GLONASS", \ + "BEIDOU" , \ + "GALILEO" \ +} + + + +#define MBG_GNSS_TYPE_MSK_GPS ( 1UL << GNSS_TYPE_GPS ) +#define MBG_GNSS_TYPE_MSK_GLONASS ( 1UL << GNSS_TYPE_GLONASS ) +#define MBG_GNSS_TYPE_MSK_BEIDOU ( 1UL << GNSS_TYPE_BEIDOU ) +#define MBG_GNSS_TYPE_MSK_GALILEO ( 1UL << GNSS_TYPE_GALILEO ) + + +#define N_GNSS_MODE_PRIO 8 + +typedef struct +{ + uint32_t gnss_set; /**< current set of GNSS types */ + uint8_t prio[N_GNSS_MODE_PRIO]; /**< index 0 for highest priority, use GNSS enumeration above, init with 0xFF if not supported */ + uint32_t flags; /**< see below */ +} MBG_GNSS_MODE_SETTINGS; + +#define _mbg_swab_mbg_gnss_mode_settings( _p ) \ +{ \ + _mbg_swab32( &(_p)->gnss_set ); \ + _mbg_swab32( &(_p)->flags ); \ +} + + + +typedef struct +{ + MBG_GNSS_MODE_SETTINGS settings; /**< current GNSS mode settings */ + uint32_t supp_gnss_types; /**< bit masks of supported GNSS types */ + uint32_t flags; /**< indicates which of the defined flags are supported by the device */ +} MBG_GNSS_MODE_INFO; + +#define _mbg_swab_mbg_gnss_mode_info( _p ) \ +{ \ + _mbg_swab_mbg_gnss_mode_settings( &(_p)->settings ); \ + _mbg_swab32( &(_p)->supp_gnss_types ); \ + _mbg_swab32( &(_p)->flags ); \ +} + + +/* Flags used with MBG_GNSS_MODE_SETTINGS::flags and MBG_GNSS_MODE_INFO::flags: */ + +enum +{ + MBG_GNSS_FLAG_EXCLUSIVE, /**< (read only) only one of the supported GNSS systems can be used at the same time */ + MBG_GNSS_FLAG_HAS_PRIORITY, /**< (read only) priority can be configured using the MBG_GNSS_MODE_SETTINGS::prio field */ + N_MBG_GNSS_FLAGS +}; + +#define MBG_GNSS_FLAG_MSK_EXCLUSIVE ( 1UL << MBG_GNSS_FLAG_EXCLUSIVE ) +#define MBG_GNSS_FLAG_MSK_HAS_PRIORITY ( 1UL << MBG_GNSS_FLAG_HAS_PRIORITY ) + + + +#define MAX_USED_SATS 32 + +/* + The structure below allos to transfer + SV information from a certain GNSS type. +*/ +typedef struct +{ + uint8_t gnss_type; /**< GNSS type from the enumeration above */ + uint8_t reserved; + uint16_t good_svs; + uint16_t svs_in_view; + uint8_t svs[MAX_USED_SATS]; +} GNSS_SAT_INFO; + +#define _mbg_swab_gnss_sat_info( _p ) \ +{ \ + _mbg_swab16( &(_p)->good_svs ); \ + _mbg_swab16( &(_p)->svs_in_view ); \ +} + + +#ifndef _IDENT_DEFINED + + typedef union + { + char c[16]; // as string which may NOT be terminated + int16_t wrd[8]; + uint32_t lw[4]; + } IDENT; + + #define _IDENT_DEFINED +#endif + +#define _mbg_swab_ident( _p ) \ +{ \ + int i; \ + for ( i = 0; i < 4; i++ ) \ + _mbg_swab32( &(_p)->lw[i] ); \ +} + +/** + * The type below is used to configure the length of the + * antenna cable in [m]: + */ +typedef uint16_t ANT_CABLE_LEN; + +#define _mbg_swab_ant_cable_len( _p ) _mbg_swab16( _p ) + + + +/* Configuration data for an optional LAN interface. + * + * This is only supported if the flag GPS_HAS_LAN_IP4 + * is set in RECEIVER_INFO::features. + */ + + +/* Basic network settings */ + +typedef uint32_t IP4_ADDR; + +#define _mbg_swab_ip4_addr( _p ) \ + _mbg_swab32( _p ); + + +typedef struct +{ + IP4_ADDR ip_addr; + IP4_ADDR netmask; + IP4_ADDR broad_addr; + IP4_ADDR gateway; + uint16_t flags; /* see below */ + uint16_t vlan_cfg; /* see below */ + +} IP4_SETTINGS; + +#define _mbg_swab_ip4_settings( _p ) \ +{ \ + _mbg_swab_ip4_addr( &(_p)->ip_addr ); \ + _mbg_swab_ip4_addr( &(_p)->netmask ); \ + _mbg_swab_ip4_addr( &(_p)->broad_addr ); \ + _mbg_swab_ip4_addr( &(_p)->gateway ); \ + _mbg_swab16( &(_p)->flags ); \ + _mbg_swab16( &(_p)->vlan_cfg ); \ +} + + +// IP4_SETTINGS::vlan_cfg contains a combination of +// a VLAN ID number plus a VLAN priiority code. +// Definitions used with IP4_SETTINGS::vlan_cfg: + +#define VLAN_ID_BITS 12 // number of bits to hold the ID +#define N_VLAN_ID ( 1 << VLAN_ID_BITS ) // number of ID values +#define MIN_VLAN_ID 0 // minimum ID value +#define MAX_VLAN_ID ( N_VLAN_ID - 1 ) // maximum ID value + +// vlan_id = ( vlan_cfg >> VLAN_ID_SHIFT ) & VLAN_ID_MSK +#define VLAN_ID_SHIFT 0 +#define VLAN_ID_MSK ( ( 1 << VLAN_ID_BITS ) - 1 ) + + +#define VLAN_PRIORITY_BITS 3 // number of bits to hold priority +#define N_VLAN_PRIORITY ( 1 << VLAN_PRIORITY_BITS ) // number of priority values +#define MIN_VLAN_PRIORITY 0 // minimum priority +#define MAX_VLAN_PRIORITY ( N_VLAN_PRIORITY - 1 ) // maximum priority + +// vlan_priority = ( vlan_cfg >> VLAN_PRIORITY_SHIFT ) & VLAN_PRIORITY_MSK +#define VLAN_PRIORITY_SHIFT ( ( 8 * sizeof( uint16_t ) ) - VLAN_PRIORITY_BITS ) +#define VLAN_PRIORITY_MSK ( ( 1 << VLAN_PRIORITY_BITS ) - 1 ) + +// The macros below can be used to encode/decode packed vlan_cfg variables: +#define _decode_vlan_id( _cfg ) ( ( (_cfg) >> VLAN_ID_SHIFT ) & VLAN_ID_MSK ) +#define _decode_vlan_priority( _cfg ) ( ( (_cfg) >> VLAN_PRIORITY_SHIFT ) & VLAN_PRIORITY_MSK ) +#define _encode_vlan_cfg( _id, _prty ) ( ( (_id) << VLAN_ID_SHIFT ) | ( (_prty) << VLAN_PRIORITY_SHIFT ) ) + + +#if 0 //##++ currently not used + +/* Misc configuration */ + +typedef struct +{ + uint16_t id; /* service ID, see below */ + uint16_t index; /* used if several same svcs must be cfg'd, e.g. DNS */ + char host[50]; /* see below */ + +} IP_CFG; + + + +/* Description of a service running on a device */ + +typedef struct +{ + uint16_t id; /* service ID, see below */ + uint16_t socket; /* the socket on which the service is listening */ + uint32_t flags; /* see below */ + +} IP_SERVICE; + +#endif // 0 + + + +/* LAN interface information */ + +typedef struct +{ + uint16_t type; /* codes see below */ + uint8_t mac_addr[6]; /* MAC address */ + uint16_t ver_code; /* high byte.low byte, in hex */ + char ver_str[GPS_ID_STR_SIZE]; + char sernum[GPS_ID_STR_SIZE]; + uint32_t rsvd_0; /* reserved, currently always 0 */ + uint16_t flags; /* see below */ + uint16_t rsvd_1; /* reserved, currently always 0 */ +} LAN_IF_INFO; + +#define _mbg_swab_lan_if_info( _p ) \ +{ \ + _mbg_swab16( &(_p)->type ); \ + _mbg_swab16( &(_p)->ver_code ); \ + _mbg_swab32( &(_p)->rsvd_0 ); \ + _mbg_swab16( &(_p)->flags ); \ + _mbg_swab16( &(_p)->rsvd_1 ); \ +} + + + +/* codes used with LAN_IF_INFO::type: */ + +enum +{ + LAN_IF_TYPE_XPORT, + LAN_IF_TYPE_PTP, + N_LAN_IF_TYPE +}; + + +/* Flags used with IP4_SETTINGS::flags and LAN_IF_INFO::flags: */ + +enum +{ + IP4_BIT_DHCP, // DHCP supported (LAN_IF_INFO) / enabled (IP4_SETTINGS) + IP4_BIT_LINK, // used only in IP4_SETTINGS to report link state + IP4_BIT_VLAN, // VLAN supported (LAN_IF_INFO) / enabled (IP4_SETTINGS) + N_IP4_BIT +}; + +#define IP4_MSK_DHCP ( 1UL << IP4_BIT_DHCP ) +#define IP4_MSK_LINK ( 1UL << IP4_BIT_LINK ) +#define IP4_MSK_VLAN ( 1UL << IP4_BIT_VLAN ) + + +enum +{ + PTP_NW_PROT_BIT_RESERVED, + PTP_NW_PROT_BIT_UDP_IPV4, + PTP_NW_PROT_BIT_UDP_IPV6, + PTP_NW_PROT_BIT_IEEE_802_3, + PTP_NW_PROT_BIT_DEVICE_NET, + PTP_NW_PROT_BIT_CONTROL_NET, + PTP_NW_PROT_BIT_PROFINET, + N_PTP_NW_PROT +}; + +#define PTP_NW_PROT_MSK_RESERVED ( 1UL << PTP_NW_PROT_BIT_RESERVED ) +#define PTP_NW_PROT_MSK_UDP_IPV4 ( 1UL << PTP_NW_PROT_BIT_UDP_IPV4 ) +#define PTP_NW_PROT_MSK_UDP_IPV6 ( 1UL << PTP_NW_PROT_BIT_UDP_IPV6 ) +#define PTP_NW_PROT_MSK_IEEE_802_3 ( 1UL << PTP_NW_PROT_BIT_IEEE_802_3 ) +#define PTP_NW_PROT_MSK_DEVICE_NET ( 1UL << PTP_NW_PROT_BIT_DEVICE_NET ) +#define PTP_NW_PROT_MSK_CONTROL_NET ( 1UL << PTP_NW_PROT_BIT_CONTROL_NET ) +#define PTP_NW_PROT_MSK_PROFINET ( 1UL << PTP_NW_PROT_BIT_PROFINET ) + +#if !defined( DEFAULT_PTP_NW_PROT_MASK ) + #define DEFAULT_PTP_NW_PROT_MASK ( PTP_NW_PROT_MSK_UDP_IPV4 | PTP_NW_PROT_MSK_IEEE_802_3 ) +#endif + +#define PTP_NW_PROT_STRS \ +{ \ + "Reserved", \ + "UDP/IPv4", \ + "UDP/IPv6", \ + "IEEE 802.3", \ + "DeviceNet", \ + "ControlNet", \ + "PROFINET" \ +} + + + +enum +{ + PTP_PORT_STATE_UNINITIALIZED, + PTP_PORT_STATE_INITIALIZING, + PTP_PORT_STATE_FAULTY, + PTP_PORT_STATE_DISABLED, + PTP_PORT_STATE_LISTENING, + PTP_PORT_STATE_PRE_MASTER, + PTP_PORT_STATE_MASTER, + PTP_PORT_STATE_PASSIVE, + PTP_PORT_STATE_UNCALIBRATED, + PTP_PORT_STATE_SLAVE, + N_PTP_PORT_STATE +}; + +#define PTP_PORT_STATE_STRS \ +{ \ + "UNINITIALIZED", \ + "INITIALIZING", \ + "FAULTY", \ + "DISABLED", \ + "LISTENING", \ + "PRE_MASTER", \ + "MASTER", \ + "PASSIVE", \ + "UNCALIBRATED", \ + "SLAVE" \ +} + + +typedef struct +{ + uint8_t value; + const char *name; +} PTP_TABLE; + + +enum +{ + PTP_DELAY_MECH_BIT_E2E, // in PTP2 specs: 0x01 + PTP_DELAY_MECH_BIT_P2P, // in PTP2 specs: 0x02 + N_PTP_DELAY_MECH // additionally the specs define 0xFE for disabled +}; + +#define PTP_DELAY_MECH_MSK_E2E ( 1UL << PTP_DELAY_MECH_BIT_E2E ) +#define PTP_DELAY_MECH_MSK_P2P ( 1UL << PTP_DELAY_MECH_BIT_P2P ) + +#if !defined( DEFAULT_PTP_DELAY_MECH_MASK ) + #define DEFAULT_PTP_DELAY_MECH_MASK ( PTP_DELAY_MECH_MSK_E2E | PTP_DELAY_MECH_MSK_P2P ) +#endif + +#define PTP_DELAY_MECH_NAMES \ +{ \ + "E2E", \ + "P2P" \ +} + + + +#define PTP_CLOCK_ACCURACY_RESERVED_OFFSET 0x20 + +enum +{ + PTP_CLOCK_ACCURACY_25ns = PTP_CLOCK_ACCURACY_RESERVED_OFFSET, + PTP_CLOCK_ACCURACY_100ns, + PTP_CLOCK_ACCURACY_250ns, + PTP_CLOCK_ACCURACY_1us, + PTP_CLOCK_ACCURACY_2_5us, + PTP_CLOCK_ACCURACY_10us, + PTP_CLOCK_ACCURACY_25us, + PTP_CLOCK_ACCURACY_100us, + PTP_CLOCK_ACCURACY_250us, + PTP_CLOCK_ACCURACY_1ms, + PTP_CLOCK_ACCURACY_2_5ms, + PTP_CLOCK_ACCURACY_10ms, + PTP_CLOCK_ACCURACY_25ms, + PTP_CLOCK_ACCURACY_100ms, + PTP_CLOCK_ACCURACY_250ms, + PTP_CLOCK_ACCURACY_1s, + PTP_CLOCK_ACCURACY_10s, + PTP_CLOCK_ACCURACY_MORE_10s, + PTP_CLOCK_ACCURACY_RESERVED_1, + PTP_CLOCK_ACCURACY_RESERVED_2, + PTP_CLOCK_ACCURACY_RESERVED_3, + PTP_CLOCK_ACCURACY_RESERVED_4, + N_PTP_CLOCK_ACCURACY +}; + + +// Attention: Substract offset of PTP_CLOCK_ACCURACY_RESERVED_OFFSET when +// using the enum above as index for the initializer below! +#define PTP_CLOCK_ACCURACY_STRS \ +{ \ + "< 25 ns", \ + "< 100 ns", \ + "< 250 ns", \ + "< 1 us", \ + "< 2.5 us", \ + "< 10 us", \ + "< 25 us", \ + "< 100 us", \ + "< 250 us", \ + "< 1 ms", \ + "< 2.5 ms", \ + "< 10 ms", \ + "< 25 ms", \ + "< 100 ms", \ + "< 250 ms", \ + "< 1 s", \ + "< 10 s", \ + "more than 10 s", \ + "reserved_1", \ + "reserved_2", \ + "reserved_3", \ + "reserved_4" \ +} + + + +#define PTP_TIME_SOURCE_ATOMIC_CLOCK 0x10 +#define PTP_TIME_SOURCE_GPS 0x20 +#define PTP_TIME_SOURCE_TERRESTRIAL_RADIO 0x30 +#define PTP_TIME_SOURCE_PTP 0x40 +#define PTP_TIME_SOURCE_NTP 0x50 +#define PTP_TIME_SOURCE_HAND_SET 0x60 +#define PTP_TIME_SOURCE_OTHER 0x90 +#define PTP_TIME_SOURCE_INTERNAL_OSCILLATOR 0xA0 + + + +#define PTP_TIME_SOURCE_TABLE \ +{ \ + { PTP_TIME_SOURCE_ATOMIC_CLOCK, "Atomic Clock" }, \ + { PTP_TIME_SOURCE_GPS, "GPS" }, \ + { PTP_TIME_SOURCE_TERRESTRIAL_RADIO, "Terrestrial Radio" }, \ + { PTP_TIME_SOURCE_PTP, "PTP" }, \ + { PTP_TIME_SOURCE_NTP, "NTP" }, \ + { PTP_TIME_SOURCE_HAND_SET, "HAND SET" }, \ + { PTP_TIME_SOURCE_OTHER, "OTHER" }, \ + { PTP_TIME_SOURCE_INTERNAL_OSCILLATOR, "Internal Oscillator" }, \ + { 0, NULL } \ +} + + + + +/* PTP configuration stuff */ + +typedef struct +{ + uint8_t b[8]; +} PTP_CLOCK_IDENTITY; + + + +typedef struct +{ + uint16_t network_protocol; // enum + uint8_t ptp_proto_version; // PTP v1 or v2 + uint8_t port_state; // enum + uint32_t flags; + NANO_TIME offset; + NANO_TIME path_delay; + NANO_TIME mean_path_delay; + NANO_TIME delay_asymmetry; + + PTP_CLOCK_IDENTITY gm_identity; + + uint16_t clock_offset_scaled_log_variance; + uint8_t clock_class; + uint8_t clock_accuracy; // enum + + uint32_t num_clients; + uint32_t num_masters; + + uint8_t domain_number; + uint8_t time_source; // enum + uint8_t delay_mech; + int8_t log_delay_req_intv; + + int16_t utc_offset; + DAC_VAL osc_dac_cal; + + uint32_t reserved; +} PTP_STATE; + +#define _mbg_swab_ptp_state( _p ) \ +{ \ + _mbg_swab16( &(_p)->network_protocol ); \ + _mbg_swab32( &(_p)->flags ); \ + _mbg_swab_nano_time( &(_p)->offset ); \ + _mbg_swab_nano_time( &(_p)->path_delay ); \ + _mbg_swab_nano_time( &(_p)->mean_path_delay ); \ + _mbg_swab_nano_time( &(_p)->delay_asymmetry ); \ + _mbg_swab16( &(_p)->clock_offset_scaled_log_variance ); \ + _mbg_swab32( &(_p)->num_clients ); \ + _mbg_swab32( &(_p)->num_masters ); \ + _mbg_swab32( &(_p)->utc_offset ); \ + _mbg_swab_dac_val( &(_p)->osc_dac_cal ); \ +} + + +enum +{ + PTP_FLAG_BIT_SLAVE_ONLY, + PTP_FLAG_BIT_IS_SLAVE, + PTP_FLAG_BIT_TIMESCALE_IS_PTP, + PTP_FLAG_BIT_LS_ANN, + PTP_FLAG_BIT_LS_ANN_NEG, + N_PTP_FLAG_BIT +}; + +#define PTP_FLAG_MSK_SLAVE_ONLY ( 1UL << PTP_FLAG_BIT_SLAVE_ONLY ) +#define PTP_FLAG_MSK_IS_SLAVE ( 1UL << PTP_FLAG_BIT_IS_SLAVE ) +#define PTP_FLAG_MSK_TIMESCALE_IS_PTP ( 1UL << PTP_FLAG_BIT_TIMESCALE_IS_PTP ) +#define PTP_FLAG_MSK_LS_ANN ( 1UL << PTP_FLAG_BIT_LS_ANN ) +#define PTP_FLAG_MSK_LS_ANN_NEG ( 1UL << PTP_FLAG_BIT_LS_ANN_NEG ) + + +#define PTP_SYNC_INTERVAL_MIN -6 +#define PTP_SYNC_INTERVAL_MAX 6 + +#define PTP_DELAY_REQ_INTERVAL_MIN -6 +#define PTP_DELAY_REQ_INTERVAL_MAX 6 + + +typedef struct +{ + uint16_t network_protocol; // enum, only 1 or 3 + uint8_t profile; // currently only 0 = default + uint8_t domain_number; // 0:3 + + uint8_t delay_mechanism; // 0 (E2E) or 1 (P2P), unless disabled + uint8_t reserved_0; + uint8_t priority_1; + uint8_t priority_2; + + uint8_t dflt_clk_class_unsync_cold; // 6:255 + uint8_t dflt_clk_class_unsync_warm; // 6:255 + uint8_t dflt_clk_class_sync_cold; // 6:255 + uint8_t dflt_clk_class_sync_warm; // 6:255 + + uint8_t reserved_1; // currently always 0 + uint8_t reserved_2; // currently always 0 + int16_t sync_interval; // log 2 + + int16_t announce_interval; // log 2 + int16_t delay_request_interval; // log 2 + + uint32_t upper_bound; // [ns] sync state set to false if above this limit + uint32_t lower_bound; // [ns] sync state set to true if below this limit + + uint32_t reserved_3; // currently always 0 + uint32_t flags; // (see below) + +} PTP_CFG_SETTINGS; + +#define _mbg_swab_ptp_cfg_settings( _p ) \ +{ \ + _mbg_swab16( &(_p)->network_protocol ); \ + _mbg_swab16( &(_p)->sync_interval ); \ + _mbg_swab16( &(_p)->announce_interval ); \ + _mbg_swab16( &(_p)->delay_request_interval ); \ + _mbg_swab32( &(_p)->upper_bound ); \ + _mbg_swab32( &(_p)->lower_bound ); \ + _mbg_swab32( &(_p)->reserved_1 ); \ + _mbg_swab32( &(_p)->flags ); \ +} + + + +typedef struct +{ + PTP_CFG_SETTINGS settings; + + uint8_t ptp_proto_version; // PTP v1 or v2 + uint8_t reserved_1; // currently always 0 + uint16_t reserved_2; // currently always 0 + + int16_t sync_interval_min; // log 2 + int16_t sync_interval_max; // log 2 + int16_t announce_interval_min; // log 2 + int16_t announce_interval_max; // log 2 + int16_t delay_request_interval_min; // log 2 + int16_t delay_request_interval_max; // log 2 + + uint32_t supported_flags; // (see below) + uint32_t supported_network_protocols; + uint32_t supported_profiles; + uint32_t supported_delay_mechanisms; + +} PTP_CFG_INFO; + +#define _mbg_swab_ptp_cfg_info( _p ) \ +{ \ + _mbg_swab_ptp_cfg_settings( &(_p)->settings ); \ + _mbg_swab16( &(_p)->sync_interval_min ); \ + _mbg_swab16( &(_p)->sync_interval_max ); \ + _mbg_swab16( &(_p)->announce_interval_min ); \ + _mbg_swab16( &(_p)->announce_interval_max ); \ + _mbg_swab16( &(_p)->delay_request_interval_min ); \ + _mbg_swab16( &(_p)->delay_request_interval_max ); \ + _mbg_swab32( &(_p)->supported_flags ); \ + _mbg_swab32( &(_p)->supported_profiles ); \ + _mbg_swab32( &(_p)->supported_delay_mechanisms ); \ +} + + + +// flags used with PTP_CFG_SETTINGS::flags and PTP_CFG_INFO::supported_flags: +// possibly also: can be master (i.e not slave only), v1 hw compat, ... +enum +{ + PTP_CFG_BIT_TIME_SCALE_IS_PTP, // time scale is PTP/TAI, else arbitrary + PTP_CFG_BIT_V1_HW_COMPAT, + N_PTP_CFG_BIT +}; + +#define PTP_CFG_MSK_TIME_SCALE_IS_PTP ( 1UL << PTP_CFG_BIT_TIME_SCALE_IS_PTP ) +#define PTP_CFG_MSK_V1_HW_COMPAT ( 1UL << PTP_CFG_BIT_V1_HW_COMPAT ) + + + +/*------------------------------------------------------------------------*/ + +/* Ephemeris parameters of one specific SV. Needed to compute the position */ +/* of a satellite at a given time with high precision. Valid for an */ +/* interval of 4 to 6 hours from start of transmission. */ + +typedef struct +{ + CSUM csum; /* checksum of the remaining bytes */ + int16_t valid; /* flag data are valid */ + + HEALTH health; /* health indication of transmitting SV [---] */ + IOD IODC; /* Issue Of Data, Clock */ + IOD IODE2; /* Issue of Data, Ephemeris (Subframe 2) */ + IOD IODE3; /* Issue of Data, Ephemeris (Subframe 3) */ + T_GPS tt; /* time of transmission */ + T_GPS t0c; /* Reference Time Clock [---] */ + T_GPS t0e; /* Reference Time Ephemeris [---] */ + + double sqrt_A; /* Square Root of semi-major Axis [sqrt(m)] */ + double e; /* Eccentricity [---] */ + double M0; /* +- Mean Anomaly at Ref. Time [rad] */ + double omega; /* +- Argument of Perigee [rad] */ + double OMEGA0; /* +- Longit. of Asc. Node of orbit plane [rad] */ + double OMEGADOT; /* +- Rate of Right Ascension [rad/sec] */ + double deltan; /* +- Mean Motion Diff. from computed value [rad/sec] */ + double i0; /* +- Inclination Angle [rad] */ + double idot; /* +- Rate of Inclination Angle [rad/sec] */ + double crc; /* +- Cosine Corr. Term to Orbit Radius [m] */ + double crs; /* +- Sine Corr. Term to Orbit Radius [m] */ + double cuc; /* +- Cosine Corr. Term to Arg. of Latitude [rad] */ + double cus; /* +- Sine Corr. Term to Arg. of Latitude [rad] */ + double cic; /* +- Cosine Corr. Term to Inclination Angle [rad] */ + double cis; /* +- Sine Corr. Term to Inclination Angle [rad] */ + + double af0; /* +- Clock Correction Coefficient 0 [sec] */ + double af1; /* +- Clock Correction Coefficient 1 [sec/sec] */ + double af2; /* +- Clock Correction Coefficient 2 [sec/sec^2] */ + double tgd; /* +- estimated group delay differential [sec] */ + + uint16_t URA; /* predicted User Range Accuracy */ + + uint8_t L2code; /* code on L2 channel [---] */ + uint8_t L2flag; /* L2 P data flag [---] */ +} EPH; + + + +/* Almanac parameters of one specific SV. A reduced precision set of */ +/* parameters used to check if a satellite is in view at a given time. */ +/* Valid for an interval of more than 7 days from start of transmission. */ + +typedef struct +{ + CSUM csum; /* checksum of the remaining bytes */ + int16_t valid; /* flag data are valid */ + + HEALTH health; /* [---] */ + T_GPS t0a; /* Reference Time Almanac [sec] */ + + double sqrt_A; /* Square Root of semi-major Axis [sqrt(m)] */ + double e; /* Eccentricity [---] */ + + double M0; /* +- Mean Anomaly at Ref. Time [rad] */ + double omega; /* +- Argument of Perigee [rad] */ + double OMEGA0; /* +- Longit. of Asc. Node of orbit plane [rad] */ + double OMEGADOT; /* +- Rate of Right Ascension [rad/sec] */ + double deltai; /* +- [rad] */ + double af0; /* +- Clock Correction Coefficient 0 [sec] */ + double af1; /* +- Clock Correction Coefficient 1 [sec/sec] */ +} ALM; + + + +/* Summary of configuration and health data of all SVs. */ + +typedef struct +{ + CSUM csum; /* checksum of the remaining bytes */ + int16_t valid; /* flag data are valid */ + + T_GPS tot_51; /* time of transmission, page 51 */ + T_GPS tot_63; /* time of transmission, page 63 */ + T_GPS t0a; /* complete reference time almanac */ + + CFG cfg[N_SVNO]; /* SV configuration from page 63 */ + HEALTH health[N_SVNO]; /* SV health from pages 51, 63 */ +} CFGH; + + + +/** + @brief GPS UTC correction parameters +*/ +typedef struct +{ + CSUM csum; /**< Checksum of the remaining bytes */ + int16_t valid; /**< Flag indicating UTC parameters are valid */ + + T_GPS t0t; /**< Reference Time UTC Parameters [wn|sec] */ + double A0; /**< +- Clock Correction Coefficient 0 [sec] */ + double A1; /**< +- Clock Correction Coefficient 1 [sec/sec] */ + + uint16_t WNlsf; /**< Week number of nearest leap second */ + int16_t DNt; /**< The day number at the end of which a leap second occurs */ + int8_t delta_tls; /**< Current UTC offset to GPS system time [sec] */ + int8_t delta_tlsf; /**< Future UTC offset to GPS system time after next leap second transition [sec] */ +} UTC; + +#define _mbg_swab_utc_parm( _p ) \ +{ \ + _mbg_swab_csum( &(_p)->csum ); \ + _mbg_swab16( &(_p)->valid ); \ + _mbg_swab_t_gps( &(_p)->t0t ); \ + _mbg_swab_double( &(_p)->A0 ); \ + _mbg_swab_double( &(_p)->A1 ); \ + _mbg_swab16( &(_p)->WNlsf ); \ + _mbg_swab16( &(_p)->DNt ); \ +} + + + +/* Ionospheric correction parameters */ + +typedef struct +{ + CSUM csum; /* checksum of the remaining bytes */ + int16_t valid; /* flag data are valid */ + + double alpha_0; /* Ionosph. Corr. Coeff. Alpha 0 [sec] */ + double alpha_1; /* Ionosph. Corr. Coeff. Alpha 1 [sec/deg] */ + double alpha_2; /* Ionosph. Corr. Coeff. Alpha 2 [sec/deg^2] */ + double alpha_3; /* Ionosph. Corr. Coeff. Alpha 3 [sec/deg^3] */ + + double beta_0; /* Ionosph. Corr. Coeff. Beta 0 [sec] */ + double beta_1; /* Ionosph. Corr. Coeff. Beta 1 [sec/deg] */ + double beta_2; /* Ionosph. Corr. Coeff. Beta 2 [sec/deg^2] */ + double beta_3; /* Ionosph. Corr. Coeff. Beta 3 [sec/deg^3] */ +} IONO; + + + +/* GPS ASCII message */ + +typedef struct +{ + CSUM csum; /* checksum of the remaining bytes */ + int16_t valid; /* flag data are valid */ + char s[23]; /* 22 chars GPS ASCII message plus trailing zero */ +} ASCII_MSG; + + + +enum +{ + GPS_PLATFORM_PORTABLE, + GPS_PLATFORM_FIXED, + GPS_PLATFORM_STATIONARY, + GPS_PLATFORM_PEDESTRIAN, + GPS_PLATFORM_AUTOMOTIVE, + GPS_PLATFORM_SEA, + GPS_PLATFORM_AIRBORNE_1G, + GPS_PLATFORM_AIRBORNE_2G, + GPS_PLATFORM_AIRBORNE_4G, + N_GPS_PLATFORMS +}; + + +#define GPS_PLATFORM_STRS \ +{ \ + "Portable ", \ + "Fixed ", \ + "Stationary ", \ + "Pedestrian ", \ + "Automotive ", \ + "Sea ", \ + "Airborne <1G", \ + "Airborne <2G", \ + "Airborne <4G" \ +} + + + +enum +{ + TIME_MODE_DISABLED, + TIME_MODE_SURVEY_IN, + TIME_MODE_FIXED +}; + + + +typedef struct +{ + uint32_t time_mode; + uint32_t survey_in_duration; + uint32_t survey_in_pos_var; + int32_t fixedPosX; // cm + int32_t fixedPosY; // cm + int32_t fixedPosZ; // cm + uint32_t fixedPosVar; // cm + uint32_t flags; // currently 0 + uint32_t reserved; // currently 0 +} NAV_TIME_MODE_SETTINGS; + + +/** + Navigation Engine settings to set configuration + parameters of a dynamic platform model. +*/ +typedef struct +{ + uint8_t dynamic_platform; + uint8_t fix_mode; + int8_t min_elevation; + uint8_t static_hold_threshold; + int32_t fixed_altitude; + uint32_t fixed_altitude_variance; + uint32_t flags; // currently 0 + uint32_t reserved; // currently 0 + NAV_TIME_MODE_SETTINGS nav_time_mode_settings; +} NAV_ENGINE_SETTINGS; + + +/* End of header body */ + + +#if defined( _USE_PACK ) // set default alignment + #pragma pack() +#endif + + +#endif /* _GPSDEFS_H */ diff --git a/mbglib/common/gpsutils.c b/mbglib/common/gpsutils.c new file mode 100755 index 0000000..f493af9 --- /dev/null +++ b/mbglib/common/gpsutils.c @@ -0,0 +1,194 @@ + +/************************************************************************** + * + * $Id: gpsutils.c 1.4.1.3 2010/07/15 13:33:43 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Utility functions useful with GPS data. + * + * ----------------------------------------------------------------------- + * $Log: gpsutils.c $ + * Revision 1.4.1.3 2010/07/15 13:33:43 martin + * Use DEG character definition from pcpslstr.h. + * Revision 1.4.1.2 2004/11/09 14:42:36Z martin + * Use C99 fixed-size types in swap_double(). + * Revision 1.4.1.1 2003/05/16 08:36:27 MARTIN + * Fixed sprint_dms() to work correctly under QNX. + * Revision 1.4 2003/01/31 13:45:19 MARTIN + * sprint_pos_geo() returns N/A if position not valid. + * Revision 1.3 2002/12/12 16:07:04 martin + * New functions swap_pos_doubles(), sprint_dms(), + * and sprint_pos_geo(). + * Revision 1.2 2001/02/05 09:39:12Z MARTIN + * New file header. + * Change include file name to lower case. + * Source code cleanup. + * + **************************************************************************/ + +#define _GPSUTILS + #include +#undef _GPSUTILS + +#include + +#include +#include + + + +#define _eos( _s ) ( &(_s)[strlen( _s )] ) + + +/*HDR*/ +void swap_double( double *d ) +{ + uint16_t *wp1; + uint16_t *wp2; + uint16_t w; + int i; + + wp1 = (uint16_t *) d; + wp2 = ( (uint16_t *) d ) + 3; + + for ( i = 0; i < 2; i++ ) + { + w = *wp1; + *wp1 = *wp2; + *wp2 = w; + wp1++; + wp2--; + } + +} /* swap_double */ + + + +/*HDR*/ +void swap_eph_doubles( EPH *ephp ) +{ + swap_double( &ephp->sqrt_A ); + swap_double( &ephp->e ); + swap_double( &ephp->M0 ); + swap_double( &ephp->omega ); + swap_double( &ephp->i0 ); + swap_double( &ephp->OMEGA0 ); + swap_double( &ephp->OMEGADOT ); + + swap_double( &ephp->deltan ); + swap_double( &ephp->idot ); + + swap_double( &ephp->crc ); + swap_double( &ephp->crs ); + swap_double( &ephp->cuc ); + swap_double( &ephp->cus ); + swap_double( &ephp->cic ); + swap_double( &ephp->cis ); + + swap_double( &ephp->af0 ); + swap_double( &ephp->af1 ); + swap_double( &ephp->af2 ); + + swap_double( &ephp->tgd ); + +} /* swap_eph_doubles */ + + + +/*HDR*/ +void swap_alm_doubles( ALM *almp ) +{ + swap_double( &almp->sqrt_A ); + swap_double( &almp->e ); + swap_double( &almp->deltai ); + swap_double( &almp->OMEGA0 ); + swap_double( &almp->OMEGADOT ); + swap_double( &almp->omega ); + swap_double( &almp->M0 ); + swap_double( &almp->af0 ); + swap_double( &almp->af1 ); + +} /* swap_alm_doubles */ + + + +/*HDR*/ +void swap_utc_doubles( UTC *utcp ) +{ + swap_double( &utcp->A0 ); + swap_double( &utcp->A1 ); + +} /* swap_utc_doubles */ + + + +/*HDR*/ +void swap_iono_doubles( IONO *ionop ) +{ + swap_double( &ionop->alpha_0 ); + swap_double( &ionop->alpha_1 ); + swap_double( &ionop->alpha_2 ); + swap_double( &ionop->alpha_3 ); + + swap_double( &ionop->beta_0 ); + swap_double( &ionop->beta_1 ); + swap_double( &ionop->beta_2 ); + swap_double( &ionop->beta_3 ); + +} /* swap_iono_doubles */ + + + +/*HDR*/ +void swap_pos_doubles( POS *posp ) +{ + int i; + + for ( i = 0; i < N_XYZ; i++ ) + swap_double( &posp->xyz[i] ); + + for ( i = 0; i < N_LLA; i++ ) + swap_double( &posp->lla[i] ); + + swap_double( &posp->longitude.sec ); + swap_double( &posp->latitude.sec ); + +} /* swap_pos_doubles */ + + + +/*HDR*/ +void sprint_dms( char *s, DMS *pdms, int prec ) +{ + sprintf( s, "%c %i" DEG "%02i'%02.*f\"", + pdms->prefix, + pdms->deg, + pdms->min, + prec, + pdms->sec + ); + +} /* sprint_dms */ + + + +/*HDR*/ +void sprint_pos_geo( char *s, POS *ppos, const char *sep, int prec ) +{ + if ( ppos->lla[LON] && ppos->lla[LAT] && ppos->lla[ALT] ) + { + sprint_dms( s, &ppos->latitude, prec ); + strcat( s, sep ); + sprint_dms( _eos( s ), &ppos->longitude, prec ); + strcat( s, sep ); + sprintf( _eos( s ), "%.0fm", ppos->lla[ALT] ); + } + else + strcpy( s, "N/A" ); + +} /* sprint_pos_geo */ + + + diff --git a/mbglib/common/gpsutils.h b/mbglib/common/gpsutils.h new file mode 100755 index 0000000..8716adf --- /dev/null +++ b/mbglib/common/gpsutils.h @@ -0,0 +1,80 @@ + +/************************************************************************** + * + * $Id: gpsutils.h 1.4.1.2 2010/07/15 09:19:04 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes for gpsutils.c. + * + * ----------------------------------------------------------------------- + * $Log: gpsutils.h $ + * Revision 1.4.1.2 2010/07/15 09:19:04 martin + * Use DEG character definition from pcpslstr.h. + * Revision 1.4.1.1 2003/05/15 09:40:25Z martin + * Changed degree string/char for QNX. + * Revision 1.4 2002/12/12 16:08:11 martin + * Definitions for degree character. + * Requires mbggeo.h. + * Updated function prototypes. + * Revision 1.3 2001/02/05 09:40:42Z MARTIN + * New file header. + * Source code cleanup. + * + **************************************************************************/ + +#ifndef _GPSUTILS_H +#define _GPSUTILS_H + + +/* Other headers to be included */ + +#include + + +#ifdef _GPSUTILS + #define _ext + #define _DO_INIT +#else + #define _ext extern +#endif + + +/* Start of header body */ + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + + void swap_double( double *d ) ; + void swap_eph_doubles( EPH *ephp ) ; + void swap_alm_doubles( ALM *almp ) ; + void swap_utc_doubles( UTC *utcp ) ; + void swap_iono_doubles( IONO *ionop ) ; + void swap_pos_doubles( POS *posp ) ; + void sprint_dms( char *s, DMS *pdms, int prec ) ; + void sprint_pos_geo( char *s, POS *ppos, const char *sep, int prec ) ; + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +/* End of header body */ + +#undef _ext +#undef _DO_INIT + +#endif /* _GPSUTILS_H */ + diff --git a/mbglib/common/identdec.c b/mbglib/common/identdec.c new file mode 100755 index 0000000..cab5d97 --- /dev/null +++ b/mbglib/common/identdec.c @@ -0,0 +1,164 @@ + +/************************************************************************** + * + * $Id: identdec.c 1.3 2009/04/01 14:15:05 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Supplies a function to decode various types of a GPS receiver's + * IDENT structure and generate a group code + S/N string. + * + * ----------------------------------------------------------------------- + * $Log: identdec.c $ + * Revision 1.3 2009/04/01 14:15:05 martin + * Fixed compiler warning. + * Revision 1.2 2002/11/21 08:11:59Z martin + * Avoid usage of strcpy functions since they may not + * be available in kernel space for some targets. + * Revision 1.1 2002/02/19 13:46:19 MARTIN + * Initial revision + * + **************************************************************************/ + +#define _IDENTDEC + #include +#undef _IDENTDEC + +#include + + +// Some targets don't support isdigit() from ctype.h: +#define _is_digit( _c ) ( (_c) >= '0' && (_c) <= '9' ) + + +// Some targets are unable to call functions from the +// stancard C library, so we provide necessary functions locally. + +static /*HDR*/ +char *do_strnpcpy( char *p_dst, const char *p_src, int n ) +{ + int i; + + for ( i = 0; i < n; i++ ) + { + char c = *p_src++; + *p_dst++ = c; + + if ( c == 0 ) + break; + } + + return p_dst; + +} // do_strnpcpy + + + +/*-------------------------------------------------------------- + * Name: mbg_gps_ident_decode() + * + * Purpose: Convert a GPS ident code to a string with + * serial number. + * + * Input: p_id pointer to the IDENT + * + * Output: s the resulting string + * + * Ret value: -- + *+-------------------------------------------------------------*/ + +/*HDR*/ +char *mbg_gps_ident_swap( char *p_dst, const char *p_src ) +{ + int i; + + for ( i = 0; i < 4; i++ ) + { + *p_dst++ = *( p_src + 3 ); + *p_dst++ = *( p_src + 2 ); + *p_dst++ = *( p_src + 1 ); + *p_dst++ = *( p_src ); + p_src += 4; + } + + return( p_dst ); + +} // mbg_gps_ident_swap + + + +/*HDR*/ +void mbg_gps_ident_decode( char *s, const IDENT *p_id ) +{ + char ws[sizeof( *p_id ) + 1]; // tmp buffer + char *cp; + char c = 0; + int n_spaces = 0; + int i; + + // get string from binary format used by firmware + mbg_gps_ident_swap( ws, (const char *) p_id ); + + // make sure the resulting string is terminated by 0 + ws[sizeof( *p_id )] = 0; + + // Now ws contains a raw string which may be in one + // of the following formats. The first one, which includes + // a group code is the preferred format: + // + // "gggg nnnnnnnn" group code, gap filled with spaces, S/N + // "nnnnnnnn........" S/N, plus non-digits + // "........nnnnnnnn" non-digits, followed by S/N + + cp = ws; + + // test for the number of digits at the beginning + for ( i = 0; i < MBG_SERNUM_LEN; i++ ) + { + c = *cp++; + + if ( !_is_digit( c ) ) + break; + } + + if ( i != MBG_GRP_CODE_LEN ) + goto copy; // not a group code + + + // expect a number of spaces + n_spaces = sizeof( *p_id ) - MBG_GRP_SERNUM_LEN; + + for ( i = 0; i < n_spaces; i++ ) + { + if ( c != ' ' ) + { + n_spaces = 0; + goto copy; + } + + c = *cp++; + } + + + // test number of S/N digits + for ( i = 0; i < MBG_SERNUM_LEN; i++ ) + { + if ( !_is_digit( c ) ) + { + n_spaces = 0; + goto copy; + } + + c = *cp++; + } + +copy: + cp = do_strnpcpy( s, ws, MBG_GRP_CODE_LEN ); + i = MBG_GRP_CODE_LEN + n_spaces; + do_strnpcpy( cp, &ws[i], sizeof( ws ) - i ); + +} // mbg_gps_ident_decode + + + diff --git a/mbglib/common/identdec.h b/mbglib/common/identdec.h new file mode 100755 index 0000000..6054ec7 --- /dev/null +++ b/mbglib/common/identdec.h @@ -0,0 +1,67 @@ + +/************************************************************************** + * + * $Id: identdec.h 1.1 2002/02/19 13:46:19 MARTIN REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes for identdec.h. + * + * ----------------------------------------------------------------------- + * $Log: identdec.h $ + * Revision 1.1 2002/02/19 13:46:19 MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _IDENTDEC_H +#define _IDENTDEC_H + + +/* Other headers to be included */ + +#include + + +#ifdef _IDENTDEC + #define _ext + #define _DO_INIT +#else + #define _ext extern +#endif + + +/* Start of header body */ + + + + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + + char *mbg_gps_ident_swap( char *p_dst, const char *p_src ) ; + void mbg_gps_ident_decode( char *s, const IDENT *p_id ) ; + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +/* End of header body */ + +#undef _ext +#undef _DO_INIT + +#endif /* _IDENTDEC_H */ diff --git a/mbglib/common/macioctl.h b/mbglib/common/macioctl.h new file mode 100755 index 0000000..d46dcf5 --- /dev/null +++ b/mbglib/common/macioctl.h @@ -0,0 +1,1817 @@ + +/************************************************************************** + * + * $Id: macioctl.h 1.33.1.7 2011/01/26 16:37:55 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Macros used inside the IOCTL handlers of device drivers + * for Meinberg radio clocks. + * + * ----------------------------------------------------------------------- + * $Log: macioctl.h $ + * Revision 1.33.1.7 2011/01/26 16:37:55 martin + * Modified inline declarations for gcc. + * Revision 1.33.1.6 2011/01/24 17:08:40 martin + * Fixed build under FreeBSD. + * Revision 1.33.1.5 2010/11/09 10:57:33 martin + * Added _sem_inc_safe_no_irp() macro (Windows only). + * Revision 1.33.1.4 2010/07/16 08:31:32Z martin + * Revision 1.33.1.3 2010/07/15 15:47:07 martin + * Revision 1.33.1.2 2010/07/14 14:48:52 martin + * Simplified code and renamed some inline functions. + * Revision 1.33.1.1 2010/03/03 15:11:51 martin + * Fixed macro. + * Revision 1.33 2009/12/21 16:22:55 martin + * Moved code reading memory mapped timestamps to inline functions. + * Revision 1.32 2009/12/15 15:34:57 daniel + * Support reading the raw IRIG data bits for firmware versions + * which support this feature. + * Revision 1.31 2009/11/04 14:58:52Z martin + * Conditionally exclude port status query from build. + * Revision 1.30 2009/09/29 15:08:39 martin + * Support retrieving time discipline info. + * Revision 1.29 2009/08/18 08:45:16 martin + * Removed IOCTL switch macro, inline code used for all targets. + * Revision 1.28 2009/06/26 13:16:11Z martin + * Fixed duplicate case in inline code (copy and paste error). + * Revision 1.27 2009/06/22 13:52:56 martin + * Fixed a bug where the size of GPS data had been truncated to 8 bits, + * which resulted in an IOCTL error if a buffer larger than 256 bytes had been + * used. This had been observed with the PC_GPS_ALL_STR_TYPE_INFO + * command if more than 6 string types are supported by a card. + * Revision 1.26 2009/06/19 12:21:12 martin + * Support reading raw IRIG time. + * Revision 1.25 2009/06/09 10:01:01 daniel + * Support configuration of LAN intf. and PTP. + * Started to support ARM / firmware. + * Conditionally compile ioctl_switch as inline function. + * Revision 1.24 2009/03/19 15:25:19 martin + * Support UTC parms and configurable time scales. + * Support IOCTL_DEV_HAS_IRIG_CTRL_BITS and IOCTL_GET_IRIG_CTRL_BITS. + * Support reading MM timestamps without cycles. + * IOCTL_GET_PCI_ASIC_VERSION now returns the ASIC + * version code from the device info structure which already + * has the correct endianess. + * For consistent naming renamed IOCTL_GET_FAST_HR_TIMESTAMP + * to IOCTL_GET_FAST_HR_TIMESTAMP_CYCLES. + * Use mbg_get_cycles...() instead of _pcps_get_cycles...(). + * Revision 1.23 2008/12/11 10:30:38Z martin + * _pcps_get_cycles() is now called inside the low level routines + * immediately when the command byte is written. + * Mutex for hardware access is now acquired/released in _pcps_sem_inc() + * and _pcps_sem_dec(), so other IOCTLs which don't access the card + * can be run in parallel. + * Moved definitions of _pcps_sem_inc(), _pcps_sem_dec(), and + * _pcps_get_cycles() to pcpsdrvr.h. + * Defined a macro which checks if access is safe (may be unsafe + * with certain PEX cards which have IRQs enabled). + * Use _pcps_sem_inc_safe() macro to check if access is safe and + * inhibit access if this is not the case. + * Consistenly use pcps_drvr_name instead of mbgclock_name + * for debug messages. + * Don't return error for unmap_mm...() under Linux. + * Account for ASIC_FEATURES being coded as flags, and account + * for new symbol PCI_ASIC_HAS_MM_IO. + * Handle new IOCTLs IOCTL_HAS_PCI_ASIC_FEATURES, IOCTL_HAS_PCI_ASIC_VERSION, + * IOCTL_DEV_IS_MSF, IOCTL_DEV_IS_LWR, IOCTL_DEV_IS_WWVB, + * IOCTL_GET_IRQ_STAT_INFO, IOCTL_GET_CYCLES_FREQUENCY, + * IOCTL_HAS_FAST_HR_TIMESTAMP, and IOCTL_GET_FAST_HR_TIMESTAMP. + * Support mapped I/O resources. + * Revision 1.22 2008/01/17 09:28:49 daniel + * Support for memory mapped I/O under Linux and Windows. + * Added macros _io_get_mapped_mem_address(), + * _io_unmap_mapped_mem_address(). + * Account for IOCTL_GET_PCI_ASIC_FEATURES + * Cleanup for PCI ASIC version. + * Revision 1.21 2007/09/26 07:31:47Z martin + * Support reading status port of USB devices. + * Use kernel malloc/free macros from pcpsdrvr.h. + * Modified _pcps_sem..() to take PCPS_DDEV argument. + * Revision 1.20 2007/05/21 15:00:00Z martin + * Unified naming convention for symbols related to ref_offs. + * Revision 1.19 2007/03/30 13:31:42 martin + * Changes due to renamed library symbol. + * Revision 1.18 2007/03/02 10:31:21Z martin + * Use generic port I/O macros. + * Preliminary support for *BSD. + * Preliminary _cmd_from_ioctl(). + * Revision 1.17 2006/03/10 10:35:43 martin + * Added support for programmable pulse outputs. + * Revision 1.16 2005/06/02 10:16:37Z martin + * Implemented IOCTL_PCPS_GENERIC_.. calls. + * Added support for SYNTH_STATE. + * Moved Debug IOCTL handling here. + * Revision 1.15 2005/01/14 10:26:41Z martin + * Support IOCTLs which query device features. + * Revision 1.14 2004/12/09 11:03:36Z martin + * Support configuration of on-board frequency synthesizer. + * Revision 1.13 2004/11/09 12:47:19Z martin + * Use new macro _pcps_ddev_has_gps_data() to check whether GPS large + * data I/O is supported. + * Changes due to renamed symbols, IRIG RX/TX. + * Modifications were required in order to be able to configure IRIG + * settings of cards which provide both IRIG input and output. + * GPS169PCI cards with IRIG output and early firmware versions + * used the same codes to configure the IRIG output as the TCR + * cards use to configure the IRIG input. Those codes are now + * exclusively used to configure the IRIG input. A workaround + * has been included for those GPS169PCI cards, because otherwise + * the IRIG configuration would not work properly after a driver + * update, without also doing a firmware update. + * Show debug msg if GPS169PCI workaround for IRIG cfg in effect. + * Use more specific data types than generic types. + * Modified contents of debug messages. + * Added (uchar FAR *) cast. + * Revision 1.12 2004/06/07 09:20:52 martin + * Account for renamed symbols. + * Revision 1.11 2004/04/07 09:05:17 martin + * Support OS dependent IOCTLs used to trigger debug events. + * Revision 1.10 2004/03/16 16:25:42Z martin + * Support new macro _pcps_has_irig(). + * Revision 1.9 2004/01/08 10:57:23Z martin + * Support codes to read ASIC version, and read times + * with associated cycle counter values. + * Support higher baud rates for TCR510PCI and PCI510. + * Support PCPS_HR_TIME for TCR510PCI. + * Revision 1.8 2003/09/17 12:49:57Z martin + * Use PCPS_GIVE_TIME_NOCLEAR in API mbg_get_time(). + * Revision 1.7 2003/09/09 13:33:55Z martin + * Support IOCTL_GET_PCPS_TIME_SEC_CHANGE. + * Revision 1.6 2003/06/19 09:18:02Z martin + * Supports new APIs IOCTL_PCPS_GET_UCAP_ENTRIES + * and IOCTL_PCPS_GET_UCAP_EVENT. + * Changes due to renamed symbols. + * Preliminary _pout_size for Linux. + * Revision 1.5 2003/04/15 08:50:38Z martin + * Support ALL_STR_TYPE_INFO, ALL_PORT_INFO for Win32. + * Revision 1.4 2003/04/09 16:51:29Z martin + * Use new common IOCTL codes from mbgioctl.h. + * Support almost all IOCTL codes. + * Support for Win32. + * Revision 1.3 2001/11/30 09:52:47Z martin + * Added support for event_time which, however, requires + * a custom GPS firmware. + * Revision 1.2 2001/09/14 12:01:17 martin + * Decode PCPS_IOCTL_SET_GPS_CMD. + * Added some comments. + * Revision 1.1 2001/04/09 07:47:01 MARTIN + * + **************************************************************************/ + +#ifndef _MACIOCTL_H +#define _MACIOCTL_H + +#include +#include +#include +#include + + +// The types below are used since the macros used in this file +// have been written to use structs and compilers return errors +// if those macros are used with array variables. + +typedef struct +{ + LLA lla; +} LLAs; + +typedef struct +{ + XYZ xyz; +} XYZs; + + +#define USE_DEBUG_PORT !defined( MBG_ARCH_ARM ) + + +// OS dependent definitions +#if defined( MBG_TGT_LINUX ) + + #define _pcps_iob( _type, _s ) _type _s + #define _pcps_iob_arr( _type, _s, n ) _type _s[_n] + + #define _pcps_iob_to_pout_size( _type, _iob, _pout, _size ) \ + if ( copy_to_user( (_type *)(_pout), &(_iob), _size ) ) \ + goto err_to_user; + + #define _pcps_iob_from_pin_size( _type, _iob, _pin, _size ) \ + if ( copy_from_user( &(_iob), (_type *) (_pin), _size ) ) \ + goto err_from_user; + + #define _io_wait_pcps_sec_change( _pddev, _cmd, _type, _pout ) \ + goto err_inval + + #define _io_get_mapped_mem_address( _pddev, _pout ) \ + { \ + _pcps_iob( PCPS_MAPPED_MEM, _s ); \ + _s.pfn_offset = ( pddev->rsrc_info.mem[0].start & ~PAGE_MASK ) + sizeof( PCI_ASIC ); \ + _s.len = pddev->rsrc_info.mem[0].len - sizeof( PCI_ASIC ); \ + _pcps_iob_to_pout_size( PCPS_MAPPED_MEM, _s, _pout, sizeof( PCPS_MAPPED_MEM ) ); \ + } + + #define _io_unmap_mapped_mem_address( _pddev, _pin ) \ + _nop_macro_fnc() + +#elif defined( MBG_TGT_BSD ) + + #include + + #define _pcps_iob( _type, _s ) _type _s + #define _pcps_iob_arr( _type, _s, n ) _type _s[_n] + + #define _pcps_iob_to_pout_size( _type, _iob, _pout, _size ) \ + memcpy( (_type *)(_pout), &(_iob), _size ) + + #define _pcps_iob_from_pin_size( _type, _iob, _pin, _size ) \ + memcpy( &(_iob), (_type *) (_pin), _size ) + + #define _io_wait_pcps_sec_change( _pddev, _cmd, _type, _pout ) \ + goto err_inval + + #define _io_get_mapped_mem_address( _pddev, _pout ) \ + goto err_inval + + #define _io_unmap_mapped_mem_address( _pddev, _pin ) \ + goto err_inval + +#elif defined( MBG_TGT_WIN32 ) + + #define _pcps_iob( _type, _s ) _type _s + #define _pcps_iob_arr( _type, _s, n ) _type _s[_n] + + #define _pcps_iob_to_pout_size( _type, _iob, _pout, _size ) \ + { \ + RtlCopyMemory( _pout, &_iob, _size ); \ + *ret_size = _size; \ + } + + #define _pcps_iob_from_pin_size( _type, _iob, _pin, _size ) \ + RtlCopyMemory( &_iob, _pin, _size ); + + // The following macros are defined in the OS dependent code: + // + // _io_wait_pcps_sec_change() + // _io_get_mapped_mem_address() + // _io_unmap_mapped_mem_address() + // _io_set_interrupt() + // + +#endif + + + +#define _pcps_iob_to_pout( _type, _iob, _pout ) \ + _pcps_iob_to_pout_size( _type, _iob, _pout, sizeof( _iob ) ) + +#define _pcps_iob_from_pin( _type, _iob, _pin ) \ + _pcps_iob_from_pin_size( _type, _iob, _pin, sizeof( _iob ) ) + + +// For some cards it may be unsafe to access the card while +// interrups are enabled for the card since IRQs may during +// access may mess up the interface. The macro below checks +// whether this is the case. +#define _pcps_access_is_unsafe( _pddev ) \ + ( ( (_pddev)->irq_stat_info & PCPS_IRQ_STATE_DANGER ) == PCPS_IRQ_STATE_DANGER ) + + + +// Check whether a card can be accessed safely and set a flag +// preventing the card from being accessed from IRQ handler. +#if defined( MBG_TGT_WIN32 ) + + // Under Windows.we need to save a pointer to the current + // IRP by default. + #define _pcps_sem_inc_safe( _pddev ) \ + if ( _pcps_access_is_unsafe( _pddev ) ) \ + goto err_busy_unsafe; \ + _pcps_sem_inc( _pddev ); \ + (_pddev)->irp = pIrp + + // If a function which is exported by our kernel driver + // is called from a different kernel driver then there is + // no IRP, so we provide a different, Windows-only macro + // which is used by those export functions and sets the + // IRP pointer of the device structure to NULL. + #define _pcps_sem_inc_safe_no_irp( _pddev ) \ + if ( _pcps_access_is_unsafe( _pddev ) ) \ + goto err_busy_unsafe; \ + _pcps_sem_inc( _pddev ); \ + (_pddev)->irp = NULL + +#else + + // Other OSs don't use an IRP, so no IRP pointer + // needs to be set up. + #define _pcps_sem_inc_safe( _pddev ) \ + if ( _pcps_access_is_unsafe( _pddev ) ) \ + goto err_busy_unsafe; \ + _pcps_sem_inc( _pddev ); \ + +#endif + + + + + +// Read a data structure from a clock device. +// Check the return code and if no error occurred, +// copy the data to the caller's memory space. +#define _io_read_var( _pddev, _cmd, _type, _pout ) \ +{ \ + _pcps_iob( _type, _s ); \ + \ + _pcps_sem_inc_safe( _pddev ); \ + rc = _pcps_read_var( _pddev, _cmd, _s ); \ + _pcps_sem_dec( _pddev ); \ + \ + if ( rc != MBG_SUCCESS ) \ + goto err_access; \ + \ + _pcps_iob_to_pout( _type, _s, _pout ); \ +} + + +// Retrieve a data structure from the caller's +// memory space, write it to a clock device and +// check the return code. +#define _io_write_var( _pddev, _cmd, _type, _pin ) \ +{ \ + _pcps_iob( _type, _s ); \ + \ + _pcps_iob_from_pin( _type, _s, _pin ); \ + \ + _pcps_sem_inc_safe( _pddev ); \ + rc = _pcps_write_var( _pddev, _cmd, _s ); \ + _pcps_sem_dec( _pddev ); \ + \ + if ( rc != MBG_SUCCESS ) \ + goto err_access; \ +} + + +// Retrieve a data structure from the caller's +// memory space, write it to a clock device and +// check the return code. +#define _io_write_cmd( _pddev, _cmd ) \ +{ \ + _pcps_sem_inc_safe( _pddev ); \ + rc = _pcps_write_byte( _pddev, _cmd ); \ + _pcps_sem_dec( _pddev ); \ + \ + if ( rc != MBG_SUCCESS ) \ + goto err_access; \ +} + + +// Check if a clock is a GPS device. If it is, +// read GPS data with variable size from the device. +// Check the return code and if no error occurred, +// copy the data to the caller's memory space. +#define _io_read_gps( _pddev, _cmd, _type, _pout, _size ) \ +{ \ + _pcps_iob( _type, _s ); \ + \ + if ( !_pcps_ddev_has_gps_data( _pddev ) ) \ + goto err_support; \ + \ + _pcps_sem_inc_safe( _pddev ); \ + rc = pcps_read_gps( _pddev, _cmd, (uchar FAR *) &_s, _size ); \ + _pcps_sem_dec( _pddev ); \ + \ + if ( rc != MBG_SUCCESS ) \ + goto err_access; \ + \ + _pcps_iob_to_pout_size( _type, _s, _pout, _size ); \ +} + + +// Check if a clock is a GPS device. If it is, +// read a GPS data structure from the device. +// Check the return code and if no error occurred, +// copy the data to the caller's memory space. +#define _io_read_gps_var( _pddev, _cmd, _type, _pout ) \ +{ \ + _pcps_iob( _type, _s ); \ + \ + if ( !_pcps_ddev_has_gps_data( _pddev ) ) \ + goto err_support; \ + \ + _pcps_sem_inc_safe( _pddev ); \ + rc = _pcps_read_gps_var( _pddev, _cmd, _s ); \ + _pcps_sem_dec( _pddev ); \ + \ + if ( rc != MBG_SUCCESS ) \ + goto err_access; \ + \ + _pcps_iob_to_pout( _type, _s, _pout ); \ +} + + +// Check if a clock is a GPS device. If it is, +// retrieve a data structure from the caller's +// memory space, write it to the clock device and +// check the return code. +#define _io_write_gps_var( _pddev, _cmd, _type, _pin ) \ +{ \ + _pcps_iob( _type, _s ); \ + \ + if ( !_pcps_ddev_has_gps_data( _pddev ) ) \ + goto err_support; \ + \ + _pcps_iob_from_pin( _type, _s, _pin ); \ + \ + _pcps_sem_inc_safe( _pddev ); \ + rc = _pcps_write_gps_var( _pddev, _cmd, _s ); \ + _pcps_sem_dec( _pddev ); \ + \ + if ( rc != MBG_SUCCESS ) \ + goto err_access; \ +} + + +// Check a condition an go to an error handler +// if the condition is not true. +#define _io_chk_cond( _cond ) \ + if ( !(_cond) ) \ + goto err_support; + + + +// The macros below are similar to those defined above except +// that they check if a condition is true before they really +// do anything. This is used for IOCTL calls which may not +// be supported with any type of clock device. +#define _io_read_var_chk( _pddev, _cmd, _type, _pout, _cond ) \ +{ \ + _io_chk_cond( _cond ); \ + _io_read_var( _pddev, _cmd, _type, _pout ); \ +} + +#define _io_write_var_chk( _pddev, _cmd, _type, _pin, _cond ) \ +{ \ + _io_chk_cond( _cond ); \ + _io_write_var( _pddev, _cmd, _type, _pin ); \ +} + +#define _io_write_cmd_chk( _pddev, _cmd, _cond ) \ +{ \ + _io_chk_cond( _cond ); \ + _io_write_cmd( _pddev, _cmd ); \ +} + +#define _io_read_gps_chk( _pddev, _cmd, _type, _pout, _size, _cond ) \ +{ \ + _io_chk_cond( _cond ); \ + _io_read_gps( _pddev, _cmd, _type, _pout, _size ); \ +} + +#define _io_read_gps_var_chk( _pddev, _cmd, _type, _pout, _cond ) \ +{ \ + _io_chk_cond( _cond ); \ + _io_read_gps_var( _pddev, _cmd, _type, _pout ); \ +} + +#define _io_write_gps_var_chk( _pddev, _cmd, _type, _pin, _cond ) \ +{ \ + _io_chk_cond( _cond ); \ + _io_write_gps_var( _pddev, _cmd, _type, _pin ); \ +} + + +#define _report_cond( _cond, _pout ) \ +{ \ + int retval = _cond; \ + _pcps_iob_to_pout( int, retval, _pout ); \ +} + + + +#define _mbg_dbg_set_bit( _d, _v ) \ +{ \ + mbg_dbg_data |= (_v); \ + _mbg_outp8( (_d), mbg_dbg_port_mapped, mbg_dbg_data ); \ +} + +#define _mbg_dbg_clr_bit( _d, _v ) \ +{ \ + mbg_dbg_data &= ~(_v); \ + _mbg_outp8( (_d), mbg_dbg_port_mapped, mbg_dbg_data ); \ +} + +#define _mbg_dbg_clr_all( _d ) \ +{ \ + mbg_dbg_data = 0; \ + _mbg_outp8( (_d), mbg_dbg_port_mapped, mbg_dbg_data ); \ +} + + + +#define TEST_MM_ACCESS_TIME ( 0 && defined( MBG_TGT_LINUX ) ) +#define TEST_MM_ACCESS_64 0 +#define TEST_FRAC_ONLY 0 + +#if TEST_MM_ACCESS_TIME + #include +#endif + + +#if defined( __GNUC__ ) +// Avoid "no previous prototype" with some gcc versions. +__mbg_inline +void swap_tstamp( PCPS_TIME_STAMP *p_ts ) __attribute__((always_inline)); +#endif + +__mbg_inline +void swap_tstamp( PCPS_TIME_STAMP *p_ts ) +{ + uint32_t tmp = p_ts->sec; + p_ts->sec = p_ts->frac; + p_ts->frac = tmp; + +} // swap_tstamp + + + +#if defined( __GNUC__ ) +// Avoid "no previous prototype" with some gcc versions. +__mbg_inline +void do_get_fast_hr_timestamp_safe( PCPS_DDEV *pddev, PCPS_TIME_STAMP *p_ts ) __attribute__((always_inline)); +#endif + + +__mbg_inline +void do_get_fast_hr_timestamp_safe( PCPS_DDEV *pddev, PCPS_TIME_STAMP *p_ts ) +{ +#if TEST_MM_ACCESS_64 + volatile uint64_t *p = (volatile uint64_t *) pddev->mm_tstamp_addr; +#else + volatile uint32_t *p = (volatile uint32_t *) pddev->mm_tstamp_addr; +#endif + +#if TEST_MM_ACCESS_TIME + PCPS_TIME_STAMP tmp; + MBG_PC_CYCLES cyc_1; + MBG_PC_CYCLES cyc_2; + MBG_PC_CYCLES cyc_3; + long delta_frac; + unsigned delta_ns; +#endif + +#if TEST_MM_ACCESS_TIME + mbg_get_pc_cycles( &cyc_1 ); +#endif + + _pcps_spin_lock( &pddev->mm_lock ); + +#if TEST_MM_ACCESS_64 + *( (volatile uint64_t *) p_ts ) = *p; +#else + p_ts->frac = _mbg32_to_cpu( *p ); + #if !TEST_FRAC_ONLY + p_ts->sec = _mbg32_to_cpu( *( p + 1 ) ); + #endif +#endif + +#if TEST_MM_ACCESS_TIME + #if TEST_MM_ACCESS_64 + *( (volatile uint64_t *) &tmp ) = *p; + #else + tmp.frac = _mbg32_to_cpu( *p ); + #if !TEST_FRAC_ONLY + tmp.sec = _mbg32_to_cpu( *( p + 1 ) ); + #endif + #endif +#endif + + _pcps_spin_unlock( &pddev->mm_lock ); + +#if TEST_FRAC_ONLY + p_ts->sec = 0; + #if TEST_MM_ACCESS_TIME + tmp.sec = 0; + #endif +#endif + +#if TEST_MM_ACCESS_64 + swap_tstamp( p_ts ); + #if TEST_MM_ACCESS_TIME + swap_tstamp( &tmp ); + #endif +#endif + + +#if TEST_MM_ACCESS_TIME + mbg_get_pc_cycles( &cyc_2 ); + mbg_get_pc_cycles( &cyc_3 ); +#endif + +#if TEST_MM_ACCESS_TIME + delta_frac = (long) ( tmp.frac - p_ts->frac ); + delta_ns = (unsigned) frac_sec_from_bin( delta_frac, 1000000000UL ); + + printk( KERN_INFO "MM tstamp dev %04X: %li/%li cyc (%lu kHz)" + " %08lX.%08lX->%08lX.%08lX: %li (%u.%03u us)" + "\n", + _pcps_ddev_dev_id( pddev ), + (long) ( cyc_2 - cyc_1 ), + (long) ( cyc_3 - cyc_2 ), + (ulong) cpu_khz, + (ulong) p_ts->sec, (ulong) p_ts->frac, + (ulong) tmp.sec, (ulong) tmp.frac, + (long) ( tmp.frac - p_ts->frac ), + delta_ns / 1000, + delta_ns % 1000 + ); +#endif + +} // do_get_fast_hr_timestamp_safe + + + +#if defined( __GNUC__ ) +// Avoid "no previous prototype" with some gcc versions. +__mbg_inline +void do_get_fast_hr_timestamp_cycles_safe( PCPS_DDEV *pddev, PCPS_TIME_STAMP_CYCLES *p_ts_cyc ) __attribute__((always_inline)); +#endif + +__mbg_inline +void do_get_fast_hr_timestamp_cycles_safe( PCPS_DDEV *pddev, PCPS_TIME_STAMP_CYCLES *p_ts_cyc ) +{ + volatile uint32_t *p = (volatile uint32_t *) pddev->mm_tstamp_addr; + + _pcps_spin_lock( &pddev->mm_lock ); + mbg_get_pc_cycles( &p_ts_cyc->cycles ); + p_ts_cyc->tstamp.frac = _mbg32_to_cpu( *p++ ); + p_ts_cyc->tstamp.sec = _mbg32_to_cpu( *p ); + _pcps_spin_unlock( &pddev->mm_lock ); + +} // do_get_fast_hr_timestamp_cycles_safe + + + +#if defined( __GNUC__ ) +// Avoid "no previous prototype" with some gcc versions. +__mbg_inline +int ioctl_switch( PCPS_DDEV *pddev, int ioctl_code, + #if defined( MBG_TGT_WIN32 ) + IRP *pIrp, int *ret_size, uint16_t pout_size, + #endif + void *pin, void *pout ) __attribute__((always_inline)); +#endif + +__mbg_inline +int ioctl_switch( PCPS_DDEV *pddev, int ioctl_code, + #if defined( MBG_TGT_WIN32 ) + IRP *pIrp, int *ret_size, uint16_t pout_size, + #endif + void *pin, void *pout ) +{ + int rc = MBG_SUCCESS; + + switch ( ioctl_code ) + { + case IOCTL_GET_PCPS_DRVR_INFO: + _pcps_iob_to_pout( PCPS_DRVR_INFO, + drvr_info, pout ); + break; + + + case IOCTL_GET_PCPS_DEV: + _pcps_iob_to_pout( PCPS_DEV, pddev->dev, pout ); + break; + + + #if !defined( OMIT_STATUS_PORT ) + case IOCTL_GET_PCPS_STATUS_PORT: + { + if ( _pcps_ddev_is_usb( pddev ) ) + { + _io_read_var( pddev, PCPS_GET_STATUS_PORT, + PCPS_STATUS_PORT, pout ); + + } + else + { + PCPS_STATUS_PORT status = + _pcps_ddev_read_status_port( pddev ); + _pcps_iob_to_pout( PCPS_STATUS_PORT, status, pout ); + } + break; + } + #endif + + + case IOCTL_PCPS_GENERIC_READ: + { + IOCTL_GENERIC_CTL ctl; + IOCTL_GENERIC_BUFFER *p_buff; + int buffer_size; + + _pcps_iob_from_pin( IOCTL_GENERIC_CTL, ctl, pin ); + buffer_size = sizeof( ctl ) + ctl.data_size_out; + p_buff = _pcps_kmalloc( buffer_size ); + + if ( p_buff == NULL ) + goto err_no_mem; + + _pcps_sem_inc_safe( pddev ); + rc = _pcps_read( pddev, (uint8_t) ctl.info, + p_buff->data, + (uint8_t) ctl.data_size_out ); + _pcps_sem_dec( pddev ); + + if ( rc == MBG_SUCCESS ) + { + p_buff->ctl = ctl; + _pcps_iob_to_pout_size( uint8_t, *p_buff, pout, + buffer_size ); + } + + _pcps_kfree( p_buff ); + + if ( rc != MBG_SUCCESS ) + goto err_access; + + break; + } + + + case IOCTL_PCPS_GENERIC_WRITE: + { + IOCTL_GENERIC_CTL ctl; + IOCTL_GENERIC_BUFFER *p_buff; + int buffer_size; + + _pcps_iob_from_pin( IOCTL_GENERIC_CTL, ctl, pin ); + buffer_size = sizeof( ctl ) + ctl.data_size_in; + p_buff = _pcps_kmalloc( buffer_size ); + + if ( p_buff == NULL ) + goto err_no_mem; + + _pcps_iob_from_pin_size( uint8_t, *p_buff, pin, + buffer_size ); + + _pcps_sem_inc_safe( pddev ); + rc = pcps_write( pddev, (uint8_t) ctl.info, + p_buff->data, + (uint8_t) ctl.data_size_in ); + _pcps_sem_dec( pddev ); + + _pcps_kfree( p_buff ); + + if ( rc != MBG_SUCCESS ) + goto err_access; + + break; + } + + + case IOCTL_PCPS_GENERIC_READ_GPS: + { + IOCTL_GENERIC_CTL ctl; + IOCTL_GENERIC_BUFFER *p_buff; + int buffer_size; + + _pcps_iob_from_pin( IOCTL_GENERIC_CTL, ctl, pin ); + buffer_size = sizeof( ctl ) + ctl.data_size_out; + p_buff = _pcps_kmalloc( buffer_size ); + + if ( p_buff == NULL ) + goto err_no_mem; + + _pcps_sem_inc_safe( pddev ); + rc = pcps_read_gps( pddev, (uint8_t) ctl.info, + p_buff->data, + (uint16_t) ctl.data_size_out ); + _pcps_sem_dec( pddev ); + + if ( rc == MBG_SUCCESS ) + { + p_buff->ctl = ctl; + _pcps_iob_to_pout_size( uint8_t, *p_buff, pout, + buffer_size ); + } + + _pcps_kfree( p_buff ); + + if ( rc != MBG_SUCCESS ) + goto err_access; + + break; + } + + + case IOCTL_PCPS_GENERIC_WRITE_GPS: + { + IOCTL_GENERIC_CTL ctl; + IOCTL_GENERIC_BUFFER *p_buff; + int buffer_size; + + _pcps_iob_from_pin( IOCTL_GENERIC_CTL, ctl, pin ); + buffer_size = sizeof( ctl ) + ctl.data_size_in; + p_buff = _pcps_kmalloc( buffer_size ); + + if ( p_buff == NULL ) + goto err_no_mem; + + _pcps_iob_from_pin_size( uint8_t, *p_buff, pin, + buffer_size ); + + _pcps_sem_inc_safe( pddev ); + rc = pcps_write_gps( pddev, (uint8_t) ctl.info, + p_buff->data, + (uint8_t) ctl.data_size_in ); + _pcps_sem_dec( pddev ); + + _pcps_kfree( p_buff ); + + if ( rc != MBG_SUCCESS ) + goto err_access; + + break; + } + + + case IOCTL_GET_PCPS_TIME: + _io_read_var( pddev, PCPS_GIVE_TIME_NOCLEAR, + PCPS_TIME, pout ); + break; + + + case IOCTL_SET_PCPS_TIME: + _io_write_var_chk( pddev, PCPS_SET_TIME, + PCPS_STIME, pin, + _pcps_ddev_can_set_time( pddev ) ); + break; + + + case IOCTL_GET_PCPS_SYNC_TIME: + _io_read_var_chk( pddev, PCPS_GIVE_SYNC_TIME, + PCPS_TIME, pout, + _pcps_ddev_has_sync_time( pddev ) ); + break; + + + case IOCTL_GET_PCPS_TIME_SEC_CHANGE: + _io_wait_pcps_sec_change( pddev, PCPS_GIVE_TIME, + PCPS_TIME, pout ); + break; + + + case IOCTL_GET_PCPS_HR_TIME: + _io_read_var_chk( pddev, PCPS_GIVE_HR_TIME, + PCPS_HR_TIME, pout, + _pcps_ddev_has_hr_time( pddev ) ); + break; + + + case IOCTL_SET_PCPS_EVENT_TIME: + _io_write_var_chk( pddev, PCPS_SET_EVENT_TIME, + PCPS_TIME_STAMP, pin, + _pcps_ddev_has_event_time( pddev ) ); + break; + + + case IOCTL_GET_PCPS_SERIAL: + _io_read_var( pddev, PCPS_GET_SERIAL, + PCPS_SERIAL, pout ); + break; + + + case IOCTL_SET_PCPS_SERIAL: + _io_write_var( pddev, PCPS_SET_SERIAL, + PCPS_SERIAL, pin ); + break; + + + case IOCTL_GET_PCPS_TZCODE: + _io_read_var_chk( pddev, PCPS_GET_TZCODE, + PCPS_TZCODE, pout, + _pcps_ddev_has_tzcode( pddev ) ); + break; + + + case IOCTL_SET_PCPS_TZCODE: + _io_write_var_chk( pddev, PCPS_SET_TZCODE, + PCPS_TZCODE, pin, + _pcps_ddev_has_tzcode( pddev ) ); + break; + + + case IOCTL_GET_PCPS_TZDL: + _io_read_var_chk( pddev, PCPS_GET_PCPS_TZDL, + PCPS_TZDL, pout, + _pcps_ddev_has_pcps_tzdl( pddev ) ); + break; + + + case IOCTL_SET_PCPS_TZDL: + _io_write_var_chk( pddev, PCPS_SET_PCPS_TZDL, + PCPS_TZDL, pin, + _pcps_ddev_has_pcps_tzdl( pddev ) ); + break; + + + case IOCTL_GET_REF_OFFS: + _io_read_var_chk( pddev, PCPS_GET_REF_OFFS, + MBG_REF_OFFS, pout, + _pcps_ddev_has_ref_offs( pddev ) ); + break; + + + case IOCTL_SET_REF_OFFS: + _io_write_var_chk( pddev, PCPS_SET_REF_OFFS, + MBG_REF_OFFS, pin, + _pcps_ddev_has_ref_offs( pddev ) ); + break; + + + case IOCTL_GET_MBG_OPT_INFO: + _io_read_var_chk( pddev, PCPS_GET_OPT_INFO, + MBG_OPT_INFO, pout, + _pcps_ddev_has_opt_flags( pddev ) ); + break; + + + case IOCTL_SET_MBG_OPT_SETTINGS: + _io_write_var_chk( pddev, PCPS_SET_OPT_SETTINGS, + MBG_OPT_SETTINGS, pin, + _pcps_ddev_has_opt_flags( pddev ) ); + break; + + + case IOCTL_GET_PCPS_IRIG_RX_INFO: + _io_read_var_chk( pddev, PCPS_GET_IRIG_RX_INFO, + IRIG_INFO, pout, + _pcps_ddev_is_irig_rx( pddev ) ); + break; + + + case IOCTL_SET_PCPS_IRIG_RX_SETTINGS: + _io_write_var_chk( pddev, PCPS_SET_IRIG_RX_SETTINGS, + IRIG_SETTINGS, pin, + _pcps_ddev_is_irig_rx( pddev ) ); + break; + + + case IOCTL_PCPS_CLR_UCAP_BUFF: + _io_write_cmd_chk( pddev, PCPS_CLR_UCAP_BUFF, + _pcps_ddev_can_clr_ucap_buff( pddev ) ); + break; + + + case IOCTL_GET_PCPS_UCAP_ENTRIES: + _io_read_var_chk( pddev, PCPS_GIVE_UCAP_ENTRIES, + PCPS_UCAP_ENTRIES, pout, + _pcps_ddev_has_ucap( pddev ) ); + break; + + + case IOCTL_GET_PCPS_UCAP_EVENT: + _io_read_var_chk( pddev, PCPS_GIVE_UCAP_EVENT, + PCPS_HR_TIME, pout, + _pcps_ddev_has_ucap( pddev ) ); + break; + + + /* slow read/write operations with GPS data */ + + case IOCTL_GET_GPS_TZDL: + _io_read_gps_var( pddev, PC_GPS_TZDL, TZDL, pout ); + break; + + + case IOCTL_SET_GPS_TZDL: + _io_write_gps_var( pddev, PC_GPS_TZDL, TZDL, pin ); + break; + + + case IOCTL_GET_GPS_SW_REV: + _io_read_gps_var( pddev, PC_GPS_SW_REV, + SW_REV, pout ); + break; + + + case IOCTL_GET_GPS_BVAR_STAT: + _io_read_gps_var( pddev, PC_GPS_BVAR_STAT, + BVAR_STAT, pout ); + break; + + + case IOCTL_GET_GPS_TIME: + _io_read_gps_var( pddev, PC_GPS_TIME, TTM, pout ); + break; + + + case IOCTL_SET_GPS_TIME: + _io_write_gps_var( pddev, PC_GPS_TIME, TTM, pin ); + break; + + + case IOCTL_GET_GPS_PORT_PARM: + _io_read_gps_var( pddev, PC_GPS_PORT_PARM, + PORT_PARM, pout ); + break; + + + case IOCTL_SET_GPS_PORT_PARM: + _io_write_gps_var( pddev, PC_GPS_PORT_PARM, + PORT_PARM, pin ); + break; + + + case IOCTL_GET_GPS_ANT_INFO: + _io_read_gps_var( pddev, PC_GPS_ANT_INFO, + ANT_INFO, pout ); + break; + + + case IOCTL_GET_GPS_UCAP: + _io_read_gps_var( pddev, PC_GPS_UCAP, TTM, pout ); + break; + + + case IOCTL_GET_GPS_ENABLE_FLAGS: + _io_read_gps_var( pddev, PC_GPS_ENABLE_FLAGS, + ENABLE_FLAGS, pout ); + break; + + + case IOCTL_SET_GPS_ENABLE_FLAGS: + _io_write_gps_var( pddev, PC_GPS_ENABLE_FLAGS, + ENABLE_FLAGS, pin ); + break; + + + case IOCTL_GET_GPS_STAT_INFO: + _io_read_gps_var( pddev, PC_GPS_STAT_INFO, + STAT_INFO, pout ); + break; + + + case IOCTL_SET_GPS_CMD: + _io_write_gps_var( pddev, PC_GPS_CMD, + GPS_CMD, pin ); + break; + + + case IOCTL_GET_GPS_IDENT: + _io_read_gps_var( pddev, PC_GPS_IDENT, + IDENT, pout ); + break; + + + case IOCTL_GET_GPS_POS: + _io_read_gps_var( pddev, PC_GPS_POS, + POS, pout ); + break; + + + case IOCTL_SET_GPS_POS_XYZ: + _io_write_gps_var( pddev, PC_GPS_POS_XYZ, + XYZs, pin ); + break; + + + case IOCTL_SET_GPS_POS_LLA: + _io_write_gps_var( pddev, PC_GPS_POS_LLA, + LLAs, pin ); + break; + + + case IOCTL_GET_GPS_ANT_CABLE_LEN: + _io_read_gps_var_chk( pddev, PC_GPS_ANT_CABLE_LEN, + ANT_CABLE_LEN, pout, + _pcps_ddev_has_cab_len( pddev ) ); + break; + + + case IOCTL_SET_GPS_ANT_CABLE_LEN: + _io_write_gps_var_chk( pddev, PC_GPS_ANT_CABLE_LEN, + ANT_CABLE_LEN, pin, + _pcps_ddev_has_cab_len( pddev ) ); + break; + + + case IOCTL_GET_GPS_RECEIVER_INFO: + _io_read_gps_var_chk( pddev, PC_GPS_RECEIVER_INFO, + RECEIVER_INFO, pout, + _pcps_ddev_has_receiver_info( pddev ) ); + break; + + + #if _MBG_SUPP_VAR_ACC_SIZE + case IOCTL_GET_GPS_ALL_STR_TYPE_INFO: + _io_read_gps_chk( pddev, PC_GPS_ALL_STR_TYPE_INFO, + ALL_STR_TYPE_INFO, pout, pout_size, + _pcps_ddev_has_receiver_info( pddev ) ); + break; + #endif + + + #if _MBG_SUPP_VAR_ACC_SIZE + case IOCTL_GET_GPS_ALL_PORT_INFO: + _io_read_gps_chk( pddev, PC_GPS_ALL_PORT_INFO, + ALL_PORT_INFO, pout, pout_size, + _pcps_ddev_has_receiver_info( pddev ) ); + break; + #endif + + + case IOCTL_SET_GPS_PORT_SETTINGS_IDX: + _io_write_gps_var_chk( pddev, PC_GPS_PORT_SETTINGS_IDX, + PORT_SETTINGS_IDX, pin, + _pcps_ddev_has_receiver_info( pddev ) ); + break; + + + case IOCTL_GET_PCI_ASIC_VERSION: + _io_chk_cond( _pcps_ddev_has_asic_version( pddev ) ); + { + _pcps_iob( PCI_ASIC_VERSION, _s ); + + _s = pddev->raw_asic_version; + rc = MBG_SUCCESS; + + _pcps_iob_to_pout( PCI_ASIC_VERSION, _s, pout ); + } + break; + + + case IOCTL_GET_PCPS_TIME_CYCLES: + { + _pcps_iob( PCPS_TIME_CYCLES, _s ); + + _pcps_sem_inc_safe( pddev ); + rc = _pcps_read_var( pddev, PCPS_GIVE_TIME_NOCLEAR, + _s.t ); + if ( _pcps_ddev_is_usb( pddev ) ) + _s.cycles =(pddev)->acc_cycles; + else + mbg_get_pc_cycles( &(_s).cycles ); + _pcps_sem_dec( pddev ); + + if ( rc != MBG_SUCCESS ) + goto err_access; + + _pcps_iob_to_pout( PCPS_TIME_CYCLES, _s, pout ); + } + break; + + + case IOCTL_GET_PCPS_HR_TIME_CYCLES: + { + _pcps_iob( PCPS_HR_TIME_CYCLES, _s ); + + _pcps_sem_inc_safe( pddev ); + rc = _pcps_read_var( pddev, PCPS_GIVE_HR_TIME, + _s.t ); + _s.cycles =(pddev)->acc_cycles; + _pcps_sem_dec( pddev ); + + if ( rc != MBG_SUCCESS ) + goto err_access; + + _pcps_iob_to_pout( PCPS_HR_TIME_CYCLES, _s, pout ); + } + break; + + + case IOCTL_GET_PCPS_IRIG_TX_INFO: + { + /* This is a workaround for GPS169PCIs with early */ + /* firmware versions. See RCS log for details. */ + uint8_t pcps_cmd = PCPS_GET_IRIG_TX_INFO; + + if ( _pcps_ddev_requires_irig_workaround( pddev ) ) + { + pcps_cmd = PCPS_GET_IRIG_RX_INFO; + _mbgddmsg_1( MBG_DBG_INFO, + "%s: workaround for GPS169PCI \"get IRIG TX cfg\"", + pcps_driver_name ); + } + + _io_read_var_chk( pddev, pcps_cmd, IRIG_INFO, pout, + _pcps_ddev_has_irig_tx( pddev ) ); + } + break; + + + case IOCTL_SET_PCPS_IRIG_TX_SETTINGS: + { + /* This is a workaround for GPS169PCIs with early */ + /* firmware versions. See RCS log for details. */ + uint8_t pcps_cmd = PCPS_SET_IRIG_TX_SETTINGS; + + if ( _pcps_ddev_requires_irig_workaround( pddev ) ) + { + pcps_cmd = PCPS_SET_IRIG_RX_SETTINGS; + _mbgddmsg_1( MBG_DBG_INFO, + "%s: workaround for GPS169PCI \"set IRIG TX cfg\"", + pcps_driver_name ); + } + + _io_write_var_chk( pddev, pcps_cmd, + IRIG_SETTINGS, pin, + _pcps_ddev_has_irig_tx( pddev ) ); + } + break; + + + case IOCTL_GET_SYNTH: + _io_read_var_chk( pddev, PCPS_GET_SYNTH, + SYNTH, pout, + _pcps_ddev_has_synth( pddev ) ); + break; + + + case IOCTL_SET_SYNTH: + _io_write_var_chk( pddev, PCPS_SET_SYNTH, + SYNTH, pin, + _pcps_ddev_has_synth( pddev ) ); + break; + + + case IOCTL_DEV_IS_GPS: + _report_cond( _pcps_ddev_is_gps( pddev ), pout ); + break; + + + case IOCTL_DEV_IS_DCF: + _report_cond( _pcps_ddev_is_dcf( pddev ), pout ); + break; + + + case IOCTL_DEV_IS_IRIG_RX: + _report_cond( _pcps_ddev_is_irig_rx( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_HR_TIME: + _report_cond( _pcps_ddev_has_hr_time( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_CAB_LEN: + _report_cond( _pcps_ddev_has_cab_len( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_TZDL: + _report_cond( _pcps_ddev_has_tzdl( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_PCPS_TZDL: + _report_cond( _pcps_ddev_has_pcps_tzdl( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_TZCODE: + _report_cond( _pcps_ddev_has_tzcode( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_TZ: + _report_cond( _pcps_ddev_has_tz( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_EVENT_TIME: + _report_cond( _pcps_ddev_has_event_time( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_RECEIVER_INFO: + _report_cond( _pcps_ddev_has_receiver_info( pddev ), pout ); + break; + + + case IOCTL_DEV_CAN_CLR_UCAP_BUFF: + _report_cond( _pcps_ddev_can_clr_ucap_buff( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_UCAP: + _report_cond( _pcps_ddev_has_ucap( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_IRIG_TX: + _report_cond( _pcps_ddev_has_irig_tx( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_SERIAL_HS: + _report_cond( _pcps_ddev_has_serial_hs( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_SIGNAL: + _report_cond( _pcps_ddev_has_signal( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_MOD: + _report_cond( _pcps_ddev_has_mod( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_IRIG: + _report_cond( _pcps_ddev_has_irig( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_REF_OFFS: + _report_cond( _pcps_ddev_has_ref_offs( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_OPT_FLAGS: + _report_cond( _pcps_ddev_has_opt_flags( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_GPS_DATA: + _report_cond( _pcps_ddev_has_gps_data( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_SYNTH: + _report_cond( _pcps_ddev_has_synth( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_GENERIC_IO: + _report_cond( _pcps_ddev_has_generic_io( pddev ), pout ); + break; + + + case IOCTL_PCPS_GENERIC_IO: + { + IOCTL_GENERIC_CTL ctl; + IOCTL_GENERIC_BUFFER *p_buff; + int buffer_size; + + _io_chk_cond( _pcps_ddev_has_generic_io( pddev ) ); + + _pcps_iob_from_pin( IOCTL_GENERIC_CTL, ctl, pin ); + buffer_size = sizeof( ctl ) + + ( ( ctl.data_size_in > ctl.data_size_out ) ? + ctl.data_size_in : ctl.data_size_out ); + p_buff = _pcps_kmalloc( buffer_size ); + + if ( p_buff == NULL ) + goto err_no_mem; + + _pcps_iob_from_pin_size( uint8_t, *p_buff, pin, + sizeof( p_buff->ctl ) + ctl.data_size_in ); + + _pcps_sem_inc_safe( pddev ); + rc = pcps_generic_io( pddev, (uint8_t) ctl.info, + p_buff->data, + (uint8_t) ctl.data_size_in, + p_buff->data, + (uint8_t) ctl.data_size_out ); + _pcps_sem_dec( pddev ); + + if ( rc == MBG_SUCCESS ) + { + p_buff->ctl = ctl; + _pcps_iob_to_pout_size( uint8_t, *p_buff, pout, + sizeof( p_buff->ctl ) + ctl.data_size_out ); + } + + _pcps_kfree( p_buff ); + + if ( rc != MBG_SUCCESS ) + goto err_access; + + break; + } + + + case IOCTL_GET_SYNTH_STATE: + _io_read_var_chk( pddev, PCPS_GET_SYNTH_STATE, + SYNTH_STATE, pout, + _pcps_ddev_has_synth( pddev ) ); + break; + + + #if _MBG_SUPP_VAR_ACC_SIZE + case IOCTL_GET_GPS_ALL_POUT_INFO: + _io_read_gps_chk( pddev, PC_GPS_ALL_POUT_INFO, + ALL_POUT_INFO, pout, pout_size, + _pcps_ddev_has_receiver_info( pddev ) ); + break; + #endif + + + case IOCTL_SET_GPS_POUT_SETTINGS_IDX: + _io_write_gps_var_chk( pddev, PC_GPS_POUT_SETTINGS_IDX, + POUT_SETTINGS_IDX, pin, + _pcps_ddev_has_receiver_info( pddev ) ); + break; + +#if USE_DEBUG_PORT + case IOCTL_MBG_DBG_GET_PORT_ADDR: + { + _pcps_iob( MBG_DBG_PORT, _s ); + + _s = mbg_dbg_port; + _pcps_iob_to_pout( MBG_DBG_PORT, _s, pout ); + + rc = MBG_SUCCESS; + } + break; + + + case IOCTL_MBG_DBG_SET_PORT_ADDR: + { + _pcps_iob( MBG_DBG_PORT, _s ); + + _pcps_iob_from_pin( MBG_DBG_PORT, _s, pin ); + mbg_dbg_port = _s; + mbg_dbg_port_mapped = _pcps_ioremap( mbg_dbg_port, sizeof( mbg_dbg_port ) ); + + rc = MBG_SUCCESS; + } + break; +#endif // USE_DEBUG_PORT + + + case IOCTL_GET_MAPPED_MEM_ADDR: + { + _io_chk_cond( ( pddev->asic_features & PCI_ASIC_HAS_MM_IO ) ); + _io_get_mapped_mem_address( pddev, pout ); + } + break; + + + case IOCTL_UNMAP_MAPPED_MEM: + { + _io_chk_cond( ( pddev->asic_features & PCI_ASIC_HAS_MM_IO ) ); + _io_unmap_mapped_mem_address( pddev, pin ); + } + break; + + + case IOCTL_GET_PCI_ASIC_FEATURES: + _io_chk_cond( _pcps_ddev_has_asic_features( pddev ) ); + { + _pcps_iob( PCI_ASIC_FEATURES, _s ); + + _s = pddev->asic_features; + rc = MBG_SUCCESS; + + _pcps_iob_to_pout( PCI_ASIC_FEATURES, _s, pout ); + } + break; + + + case IOCTL_HAS_PCI_ASIC_FEATURES: + _report_cond( _pcps_ddev_has_asic_features( pddev ), pout ); + break; + + + case IOCTL_HAS_PCI_ASIC_VERSION: + _report_cond( _pcps_ddev_has_asic_version( pddev ), pout ); + break; + + + case IOCTL_DEV_IS_MSF: + _report_cond( _pcps_ddev_is_msf( pddev ), pout ); + break; + + + case IOCTL_DEV_IS_WWVB: + _report_cond( _pcps_ddev_is_wwvb( pddev ), pout ); + break; + + + case IOCTL_DEV_IS_LWR: + _report_cond( _pcps_ddev_is_lwr( pddev ), pout ); + break; + + + case IOCTL_GET_IRQ_STAT_INFO: + { + _pcps_iob( PCPS_IRQ_STAT_INFO, _s ); + + _s = pddev->irq_stat_info; + rc = MBG_SUCCESS; + + _pcps_iob_to_pout( PCPS_IRQ_STAT_INFO, _s, pout ); + } + break; + + + case IOCTL_GET_CYCLES_FREQUENCY: + { + _pcps_iob( MBG_PC_CYCLES_FREQUENCY, _s ); + + mbg_get_pc_cycles_frequency( &(_s) ); + rc = MBG_SUCCESS; + + _pcps_iob_to_pout( MBG_PC_CYCLES_FREQUENCY, _s, pout ); + } + break; + + + case IOCTL_HAS_FAST_HR_TIMESTAMP: + _report_cond( _pcps_ddev_has_fast_hr_timestamp( pddev ), pout ); + break; + + + case IOCTL_GET_FAST_HR_TIMESTAMP_CYCLES: + { + _pcps_iob( PCPS_TIME_STAMP_CYCLES, _s ); + + if ( !_pcps_ddev_has_fast_hr_timestamp( pddev ) ) + goto err_support; + + do_get_fast_hr_timestamp_cycles_safe( pddev, &_s ); + rc = MBG_SUCCESS; + + _pcps_iob_to_pout( PCPS_TIME_STAMP_CYCLES, _s, pout ); + } + break; + + + case IOCTL_GET_FAST_HR_TIMESTAMP: + { + _pcps_iob( PCPS_TIME_STAMP, _s ); + + if ( !_pcps_ddev_has_fast_hr_timestamp( pddev ) ) + goto err_support; + + do_get_fast_hr_timestamp_safe( pddev, &_s ); + rc = MBG_SUCCESS; + + _pcps_iob_to_pout( PCPS_TIME_STAMP_CYCLES, _s, pout ); + } + break; + + + case IOCTL_DEV_HAS_GPS_TIME_SCALE: + _report_cond( _pcps_ddev_has_time_scale( pddev ), pout ); + break; + + + case IOCTL_GET_GPS_TIME_SCALE_INFO: + _io_read_gps_var_chk( pddev, PC_GPS_TIME_SCALE, + MBG_TIME_SCALE_INFO, pout, + _pcps_ddev_has_time_scale( pddev ) ); + break; + + + case IOCTL_SET_GPS_TIME_SCALE_SETTINGS: + _io_write_gps_var_chk( pddev, PC_GPS_TIME_SCALE, + MBG_TIME_SCALE_SETTINGS, pin, + _pcps_ddev_has_time_scale( pddev ) ); + break; + + + case IOCTL_DEV_HAS_GPS_UTC_PARM: + _report_cond( _pcps_ddev_has_utc_parm( pddev ), pout ); + break; + + + case IOCTL_GET_GPS_UTC_PARM: + _io_read_gps_var_chk( pddev, PC_GPS_UTC, + UTC, pout, + _pcps_ddev_has_utc_parm( pddev ) ); + break; + + + case IOCTL_SET_GPS_UTC_PARM: + _io_write_gps_var_chk( pddev, PC_GPS_UTC, + UTC, pin, + _pcps_ddev_has_utc_parm( pddev ) ); + break; + + + case IOCTL_DEV_HAS_IRIG_CTRL_BITS: + _report_cond( _pcps_ddev_has_irig_ctrl_bits( pddev ), pout ); + break; + + + case IOCTL_GET_IRIG_CTRL_BITS: + _io_read_var_chk( pddev, PCPS_GET_IRIG_CTRL_BITS, + MBG_IRIG_CTRL_BITS, pout, + _pcps_ddev_has_irig_ctrl_bits( pddev ) ); + break; + + + case IOCTL_DEV_HAS_LAN_INTF: + _report_cond( _pcps_ddev_has_lan_intf( pddev ), pout ); + break; + + + case IOCTL_GET_LAN_IF_INFO: + _io_read_gps_var_chk( pddev, PC_GPS_LAN_IF_INFO, + LAN_IF_INFO, pout, + _pcps_ddev_has_lan_intf( pddev ) ); + break; + + + case IOCTL_GET_IP4_STATE: + _io_read_gps_var_chk( pddev, PC_GPS_IP4_STATE, + IP4_SETTINGS, pout, + _pcps_ddev_has_lan_intf( pddev ) ); + break; + + + case IOCTL_GET_IP4_SETTINGS: + _io_read_gps_var_chk( pddev, PC_GPS_IP4_SETTINGS, + IP4_SETTINGS, pout, + _pcps_ddev_has_lan_intf( pddev ) ); + break; + + + case IOCTL_SET_IP4_SETTINGS: + _io_write_gps_var_chk( pddev, PC_GPS_IP4_SETTINGS, + IP4_SETTINGS, pin, + _pcps_ddev_has_lan_intf( pddev ) ); + break; + + + case IOCTL_DEV_IS_PTP: + _report_cond( _pcps_ddev_is_ptp( pddev ), pout ); + break; + + + case IOCTL_DEV_HAS_PTP: + _report_cond( _pcps_ddev_has_ptp( pddev ), pout ); + break; + + + case IOCTL_GET_PTP_STATE: + _io_read_gps_var_chk( pddev, PC_GPS_PTP_STATE, + PTP_STATE, pout, + _pcps_ddev_has_ptp( pddev ) ); + break; + + + case IOCTL_GET_PTP_CFG_INFO: + _io_read_gps_var_chk( pddev, PC_GPS_PTP_CFG, + PTP_CFG_INFO, pout, + _pcps_ddev_has_ptp( pddev ) ); + break; + + + case IOCTL_SET_PTP_CFG_SETTINGS: + _io_write_gps_var_chk( pddev, PC_GPS_PTP_CFG, + PTP_CFG_SETTINGS, pin, + _pcps_ddev_has_ptp( pddev ) ); + break; + + + case IOCTL_DEV_HAS_IRIG_TIME: + _report_cond( _pcps_ddev_has_irig_time( pddev ), pout ); + break; + + + case IOCTL_GET_IRIG_TIME: + _io_read_var_chk( pddev, PCPS_GIVE_IRIG_TIME, + PCPS_IRIG_TIME, pout, + _pcps_ddev_has_irig_time( pddev ) ); + break; + + + case IOCTL_GET_RAW_IRIG_DATA: + _io_read_var_chk( pddev, PCPS_GET_RAW_IRIG_DATA, + MBG_RAW_IRIG_DATA, pout, + _pcps_ddev_has_raw_irig_data( pddev ) ); + break; + + + case IOCTL_GET_TIME_INFO_HRT: + { + _pcps_iob( MBG_TIME_INFO_HRT, _s ); + + if ( !_pcps_ddev_has_hr_time( pddev ) ) + goto err_support; + + mbg_get_pc_cycles( &_s.sys_time_cycles.cyc_before ); + mbg_get_sys_time( &_s.sys_time_cycles.sys_time ); + mbg_get_pc_cycles( &_s.sys_time_cycles.cyc_after ); + + _pcps_sem_inc_safe( pddev ); + rc = _pcps_read_var( pddev, PCPS_GIVE_HR_TIME, _s.ref_hr_time_cycles.t ); + _s.ref_hr_time_cycles.cycles =(pddev)->acc_cycles; + _pcps_sem_dec( pddev ); + + if ( rc != MBG_SUCCESS ) + goto err_access; + + _pcps_iob_to_pout( MBG_TIME_INFO_HRT, _s, pout ); + } + break; + + + case IOCTL_GET_TIME_INFO_TSTAMP: + { + _pcps_iob( MBG_TIME_INFO_TSTAMP, _s ); + + if ( !_pcps_ddev_has_fast_hr_timestamp( pddev ) ) + goto err_support; + + mbg_get_pc_cycles( &_s.sys_time_cycles.cyc_before ); + mbg_get_sys_time( &_s.sys_time_cycles.sys_time ); + mbg_get_pc_cycles( &_s.sys_time_cycles.cyc_after ); + + do_get_fast_hr_timestamp_cycles_safe( pddev, &(_s).ref_tstamp_cycles ); + + rc = MBG_SUCCESS; + + _pcps_iob_to_pout( MBG_TIME_INFO_TSTAMP, _s, pout ); + } + break; + +#if USE_DEBUG_PORT + case IOCTL_MBG_DBG_SET_BIT: + { + _pcps_iob( MBG_DBG_DATA, _s ); + _pcps_iob( MBG_PC_CYCLES, _c ); + + _pcps_iob_from_pin( MBG_DBG_DATA, _s, pin ); + + _mbg_dbg_set_bit( pddev, _s ); + mbg_get_pc_cycles( &(_c) ); + + _pcps_iob_to_pout( MBG_PC_CYCLES, _c, pout ); + } + break; + + + case IOCTL_MBG_DBG_CLR_BIT: + { + _pcps_iob( MBG_DBG_DATA, _s ); + _pcps_iob( MBG_PC_CYCLES, _c ); + + _pcps_iob_from_pin( MBG_DBG_DATA, _s, pin ); + + _mbg_dbg_clr_bit( pddev, _s ); + mbg_get_pc_cycles( &(_c) ); + + _pcps_iob_to_pout( MBG_PC_CYCLES, _c, pout ); + } + break; + + + case IOCTL_MBG_DBG_CLR_ALL: + { + _pcps_iob( MBG_PC_CYCLES, _c ); + _mbg_dbg_clr_all( pddev ); + mbg_get_pc_cycles( &(_c) ); + + _pcps_iob_to_pout( MBG_PC_CYCLES, _c, pout ); + } + break; +#endif + + + default: + goto err_inval; + + } + + return rc; + + +err_inval: + return MBG_ERR_INV_DEV_REQUEST; + +err_support: + return MBG_ERR_NOT_SUPP_BY_DEV; + +err_no_mem: + return MBG_ERR_NO_MEM; + +err_busy_unsafe: + return MBG_ERR_IRQ_UNSAFE; + +err_access: + return rc; // return the rc from the low level routine + + +#if defined( MBG_TGT_LINUX ) + +err_to_user: + return -EFAULT; + +err_from_user: + return -EFAULT; + +#endif // defined( MBG_TGT_LINUX ) + +} // ioctl_switch + +#endif /* _MACIOCTL_H */ + diff --git a/mbglib/common/mbg_arch.h b/mbglib/common/mbg_arch.h new file mode 100755 index 0000000..ae42ad7 --- /dev/null +++ b/mbglib/common/mbg_arch.h @@ -0,0 +1,159 @@ + +/************************************************************************** + * + * $Id: mbg_arch.h 1.3 2009/06/12 13:12:37 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions to support different computer hardware architectures. + * + * ----------------------------------------------------------------------- + * $Log: mbg_arch.h $ + * Revision 1.3 2009/06/12 13:12:37 martin + * Fixed compiler warning. + * Revision 1.2 2009/03/19 15:14:15 martin + * Fixed byte swapping of doubles for SPARC architecture. + * Revision 1.1 2008/12/05 13:47:42 martin + * Initial revision. + * + **************************************************************************/ + +#ifndef _MBG_ARCH_H +#define _MBG_ARCH_H + +#include + + +#if defined( MBG_ARCH_SPARC ) + #define MBG_ARCH_BIG_ENDIAN 1 +#endif + + +#if !defined( MBG_ARCH_BIG_ENDIAN ) + #define MBG_ARCH_LITTLE_ENDIAN 1 +#endif + + + +#if defined( MBG_TGT_LINUX ) + + #include + + #if defined( __KERNEL__ ) + #include + + #define _mbg_put_unaligned( _v, _p ) put_unaligned( _v, _p ) + #define _mbg_get_unaligned( _p ) get_unaligned( _p ) + #endif + +#endif + + + +// If no macros required to access unaligned data have yet been defined, +// define some default macros assuming no special handling is required +// to access unaligned data. + +#if !defined( _pcps_put_unaligned ) + #define _pcps_put_unaligned( _v, _p ) ((void)( *(_p) = (_v) )) +#endif + +#if !defined( _pcps_get_unaligned ) + #define _pcps_get_unaligned( _p ) (*(_p)) +#endif + + + +// If no macros to convert endianess have yet been defined, define +// some default macros assuming endianess conversion is not required. + +#if !defined( __le16_to_cpu ) + #define __le16_to_cpu( _x ) (_x) +#endif + +#if !defined( __le32_to_cpu ) + #define __le32_to_cpu( _x ) (_x) +#endif + +#if !defined( __le64_to_cpu ) + #define __le64_to_cpu( _x ) (_x) +#endif + +#if !defined( __cpu_to_le16 ) + #define __cpu_to_le16( _x ) (_x) +#endif + +#if !defined( __cpu_to_le32 ) + #define __cpu_to_le32( _x ) (_x) +#endif + +#if !defined( __cpu_to_le64 ) + #define __cpu_to_le64( _x ) (_x) +#endif + + + +// The macros below are used to convert the endianess +// of the plug-in cards to the endianess of the host CPU + +#define _mbg8_to_cpu( _x ) ( _x ) +#define _mbg16_to_cpu( _x ) __le16_to_cpu( _x ) +#define _mbg32_to_cpu( _x ) __le32_to_cpu( _x ) +#define _mbg64_to_cpu( _x ) __le64_to_cpu( _x ) + +#define _cpu_to_mbg8( _x ) ( _x ) +#define _cpu_to_mbg16( _x ) __cpu_to_le16( _x ) +#define _cpu_to_mbg32( _x ) __cpu_to_le32( _x ) +#define _cpu_to_mbg64( _x ) __cpu_to_le64( _x ) + + + +// swap a double type variable bytewise e.g. to convert the endianess + +static __mbg_inline +void mbg_swab_double( double *p ) +{ +#if 0 // The __swab64() may not work correctly for whatever reason ... + __swab64p( p ); +#else // ... so we do the swapping manually + double d = 0; + size_t i; + + for ( i = 0; i < sizeof( double); i++ ) + BYTE_OF( d, i ) = BYTE_OF( *p, ( sizeof( double) - 1 - i ) ); + + for ( i = 0; i < sizeof( double); i++ ) + BYTE_OF( *p, i ) = BYTE_OF( d, i ); +#endif + +} // mbg_swab_double + + + +#if defined( MBG_ARCH_BIG_ENDIAN ) + + #define _mbg_swab16( _p ) *(_p) = __swab16( *(_p) ) + #define _mbg_swab32( _p ) *(_p) = __swab32( *(_p) ) + + #define _mbg_swab_double( _p ) mbg_swab_double( _p ) + + #define _mbg_swab_doubles( _p, _n ) \ + { \ + int i; \ + for ( i = 0; i < (_n); i++ ) \ + _mbg_swab_double( &_p[i] ); \ + } + +#else + + #define _mbg_swab16( _p ) _nop_macro_fnc() + #define _mbg_swab32( _p ) _nop_macro_fnc() + + #define _mbg_swab_double( _p ) _nop_macro_fnc() + + #define _mbg_swab_doubles( _p, _n ) _nop_macro_fnc() + +#endif + +#endif /* _MBG_ARCH_H */ diff --git a/mbglib/common/mbg_tgt.h b/mbglib/common/mbg_tgt.h new file mode 100755 index 0000000..edfec15 --- /dev/null +++ b/mbglib/common/mbg_tgt.h @@ -0,0 +1,430 @@ + +/************************************************************************** + * + * $Id: mbg_tgt.h 1.22.2.8 2011/02/04 10:15:54 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Check the build environment and setup control definitions + * for the Meinberg library modules. + * + * ----------------------------------------------------------------------- + * $Log: mbg_tgt.h $ + * Revision 1.22.2.8 2011/02/04 10:15:54 martin + * Revision 1.22.2.7 2011/02/01 17:11:54 martin + * Revision 1.22.2.6 2011/01/27 16:16:28 martin + * Support wchar_t for BSD. + * Revision 1.22.2.5 2011/01/24 17:08:40 martin + * Fixed build under FreeBSD. + * Revision 1.22.2.4 2010/12/14 11:04:02 martin + * Revision 1.22.2.3 2010/05/25 14:42:32Z martin + * Don't use MM I/O on IA64 platform. + * Revision 1.22.2.2 2010/05/21 13:09:35 martin + * Initial support for IA64 platform. + * Revision 1.22.2.1 2010/04/22 09:35:56 martin + * Distinguish between different gcc target platforms. + * Revision 1.22 2009/10/01 08:20:50 martin + * Fixed inline code support with different BC versions. + * Revision 1.1 2009/11/20 12:24:05 philipp + * Revision 1.21 2009/09/01 10:34:23Z martin + * Don't define __mbg_inline for CVI and undefined targets. + * Revision 1.20 2009/08/18 15:14:26 martin + * Defined default MBG_INVALID_PORT_HANDLE for non-Windows targets. + * Revision 1.19 2009/06/09 10:03:58 daniel + * Preliminary support for ARM architecture. + * Revision 1.18 2009/04/01 14:10:55 martin + * Cleanup for CVI. + * Revision 1.17 2009/03/19 15:21:07Z martin + * Conditionally define DWORD_PTR type for old MS C compilers. + * Revision 1.16 2008/12/08 16:42:30 martin + * Defined _GNU_SOURCE for Linux. + * Revision 1.15 2008/11/19 15:31:49 martin + * Added symbol MBG_ARCH_I386. + * Revision 1.14 2008/09/03 15:06:04 martin + * Support DOS protected mode target. + * Support SUN SPARC architecture. + * Specified handle types for common host environments. + * Added macro MBG_USE_MM_IO_FOR_PCI. + * Added macro _nop_macro_fnc(). + * Revision 1.13 2008/01/30 15:52:22 martin + * Modified checking for availability of wchar_t. + * Revision 1.13 2008/01/29 15:18:07Z martin + * Recognize DOS target under Watcom compilers. + * Flag Watcom C always supports wchar_t. + * Revision 1.12 2008/01/17 09:38:50Z daniel + * Added macros to determine whether C language extensions + * (e.g. C94, C99) are supported by the target environment. + * Added macro to check whether wchar_t and friends are + * supported, and some compatibility stuff. + * Revision 1.11 2007/10/31 16:58:03 martin + * Fixed __mbg_inline for Borland C (DOS). + * Revision 1.10 2007/09/25 08:10:27Z martin + * Support CVI target environment. + * Added MBG_PORT_HANDLE type for serial ports. + * Added macros for unified inline code syntax. + * Revision 1.9 2006/12/08 12:45:54Z martin + * Under Windows include ntddk.h rather than windows.h + * if building kernel driver . + * Revision 1.8 2006/10/25 12:20:45Z martin + * Initial support for FreeBSD, NetBSD, and OpenBSD. + * Added definitions for generic handle types. + * Revision 1.7 2006/08/23 13:43:55 martin + * Added definition for MBG_TGT_UNIX. + * Minor syntax fixes. + * Revision 1.6 2006/01/25 14:37:06 martin + * Added definitions for 64 bit Windows environments. + * Revision 1.5 2003/12/17 16:11:41Z martin + * Split API modifiers into _MBG_API and _MBG_API_ATTR. + * Revision 1.4 2003/06/19 08:20:22Z martin + * Added WINAPI attribute for DLL exported functions. + * Revision 1.3 2003/04/09 13:37:20Z martin + * Added definition for _MBG_API. + * Revision 1.2 2003/02/24 16:08:45Z martin + * Don't setup for Win32 PNP if explicitely configured non-PNP. + * Revision 1.1 2002/02/19 13:46:20Z MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _MBG_TGT_H +#define _MBG_TGT_H + + +/* Other headers to be included */ + +#ifdef _MBG_TGT + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + +#if defined( _CVI ) || defined( _CVI_ ) + + #define MBG_TGT_WIN32 + #define MBG_TGT_CVI + +#elif defined( _WIN32_WINNT ) + + // MS platform SDK + // WinNT 4.0 and above + #define MBG_TGT_WIN32 + + #if ( _WIN32_WINNT >= 0x0500 ) + // Win2k and above + #if !defined( MBG_TGT_WIN32_NON_PNP ) + // only if not explicitely disabled + #define MBG_TGT_WIN32_PNP + #endif + #endif + +#elif defined( WINVER ) + + // MS platform SDK + // Win95, WinNT 4.0 and above + #define MBG_TGT_WIN32 + + #if ( WINVER >= 0x0500 ) + // Win98, Win2k and above + // #define ... + #endif + +#elif defined( __WIN32__ ) + + // Borland C++ Builder + #define MBG_TGT_WIN32 + +#elif defined( _WIN32 ) + + // MS Visual C++ + #define MBG_TGT_WIN32 + +#elif defined( __WINDOWS_386__ ) + + // Watcom C/C++ for target Win32 + #define MBG_TGT_WIN32 + +#elif defined( __NETWARE_386__ ) + + // Watcom C/C++ for target NetWare + #define MBG_TGT_NETWARE + +#elif defined( __OS2__ ) + + // Watcom C/C++ for target OS/2 + #define MBG_TGT_OS2 + +#elif defined( __linux ) + + // GCC for target Linux + #define MBG_TGT_LINUX + #define _GNU_SOURCE 1 + +#elif defined( __FreeBSD__ ) + + // GCC for target FreeBSD + #define MBG_TGT_FREEBSD + +#elif defined( __NetBSD__ ) + + // GCC for target NetBSD + #define MBG_TGT_NETBSD + +#elif defined( __OpenBSD__ ) + + // GCC for target FreeBSD + #define MBG_TGT_OPENBSD + +#elif defined( __QNX__ ) + + // any compiler for target QNX + #define MBG_TGT_QNX + + #if defined( __QNXNTO__ ) + // target QNX Neutrino + #define MBG_TGT_QNX_NTO + #endif + +#elif defined( __MSDOS__ ) || defined( __DOS__ ) + + // any compiler for target DOS + #define MBG_TGT_DOS + + #if defined( __WATCOMC__ ) && defined( __386__ ) + + #define MBG_TGT_DOS_PM // protected mode DOS + + #endif + +#endif + +// Some definitions which depend on the type of compiler ... + +#if defined( __GNUC__ ) + + #define __mbg_inline __inline__ + + #define MBG_TGT_HAS_WCHAR_T 1 + + #if defined( __i386__ ) + + #define MBG_ARCH_I386 + #define MBG_ARCH_X86 + + #elif defined( __x86_64__ ) + + #define MBG_ARCH_X86_64 + #define MBG_ARCH_X86 + + #elif defined( __ia64__ ) + + #define MBG_ARCH_IA64 + + #elif defined( __sparc__ ) + + #define MBG_ARCH_SPARC + #define MBG_USE_MM_IO_FOR_PCI 1 + + #elif defined( __arm__ ) + + #define MBG_ARCH_ARM + + #endif + +#elif defined( _MSC_VER ) + + #define __mbg_inline __forceinline + + #define MBG_TGT_HAS_WCHAR_T 1 + +#elif defined( _CVI ) || defined( _CVI_ ) + + // Inline code is not supported. + + #define MBG_TGT_HAS_WCHAR_T 0 + +#elif defined( __BORLANDC__ ) + + #if defined( __cplusplus ) + #define __mbg_inline inline // standard C++ syntax + #elif ( __BORLANDC__ > 0x410 ) // BC3.1 defines 0x410 ! + #define __mbg_inline __inline // newer BC versions support this for C + #else + #define __mbg_inline // up to BC3.1 not supported for C + #endif + + #define MBG_TGT_HAS_WCHAR_T defined( MBG_TGT_WIN32 ) + +#elif defined( __WATCOMC__ ) + + #define __mbg_inline _inline + + #define MBG_TGT_HAS_WCHAR_T defined( MBG_TGT_WIN32 ) + +#endif + + + +#if defined( MBG_TGT_FREEBSD ) \ + || defined( MBG_TGT_NETBSD ) \ + || defined( MBG_TGT_OPENBSD ) + #define MBG_TGT_BSD +#endif + +#if defined( MBG_TGT_LINUX ) \ + || defined( MBG_TGT_BSD ) \ + || defined( MBG_TGT_QNX_NTO ) + #define MBG_TGT_UNIX +#endif + + + +#if defined( MBG_TGT_WIN32 ) + + #if defined( _AMD64_ ) + // This is used for AMD64 architecture and for + // Intel XEON CPUs with 64 bit extension. + #define MBG_TGT_WIN32_PNP_X64 + #define WIN32_FLAVOR "x64" + #elif defined( _IA64_ ) + #define MBG_TGT_WIN32_PNP_IA64 + #define WIN32_FLAVOR "ia64" + #endif + + #if defined( _KDD_ ) + #include + #else + // This must not be used for kernel drivers. + #include + typedef HANDLE MBG_HANDLE; + + #define MBG_INVALID_HANDLE INVALID_HANDLE_VALUE + + #if defined( MBG_TGT_CVI ) + // CVI uses an own set of functions to support serial ports + typedef int MBG_PORT_HANDLE; + #define MBG_INVALID_PORT_HANDLE -1 + #else + typedef HANDLE MBG_PORT_HANDLE; + #endif + + // The DWORD_PTR type is not defined in the headers shipping + // with VC6. However, if the SDK is installed then the SDK's + // headers may declare this type. This is at least the case + // in the Oct 2001 SDK which also defines the symbol _W64. + #if !defined( _W64 ) + typedef DWORD DWORD_PTR; + #endif + + #endif + + #define _MBG_API WINAPI + + #if defined( MBG_LIB_EXPORT ) + #define _MBG_API_ATTR __declspec( dllexport ) + #else + #define _MBG_API_ATTR __declspec( dllimport ) + #endif + +#elif defined( MBG_TGT_UNIX ) + + typedef int MBG_HANDLE; + typedef int MBG_PORT_HANDLE; + + #define MBG_INVALID_HANDLE -1 + +#else + + typedef int MBG_HANDLE; + typedef int MBG_PORT_HANDLE; + + #define MBG_INVALID_HANDLE -1 + +#endif + + +#if !defined( _MBG_API ) + #define _MBG_API +#endif + +#if !defined( _MBG_API_ATTR ) + #define _MBG_API_ATTR +#endif + +#if !defined( MBG_INVALID_PORT_HANDLE ) + #define MBG_INVALID_PORT_HANDLE MBG_INVALID_HANDLE +#endif + +#if !defined( MBG_USE_MM_IO_FOR_PCI ) + #define MBG_USE_MM_IO_FOR_PCI 0 +#endif + + +#if !defined( _nop_macro_fnc ) + #define _nop_macro_fnc() do {} while (0) +#endif + + +// The macros below are defined in order to be able to check if +// certain C language extensions are available on the target system: +#if defined( __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199409L ) + #define MBG_TGT_C94 1 +#else + #define MBG_TGT_C94 0 +#endif + + +#if defined( __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199901L ) + #define MBG_TGT_C99 1 +#else + #define MBG_TGT_C99 0 +#endif + +// Check if wchar_t is supported +#if !defined( MBG_TGT_HAS_WCHAR_T ) + #define MBG_TGT_HAS_WCHAR_T ( MBG_TGT_C94 || defined( WCHAR_MAX ) ) +#endif + +#if !MBG_TGT_HAS_WCHAR_T + // Even if wchar_t is not natively supported by the target platform + // there may already be a compatibility define (e.g. BC3.1) + // However, some functions may be missing (e.g. snwprintf()). + #if !defined( _WCHAR_T ) /* BC3.1 */ \ + && !defined( _WCHAR_T_DEFINED_ ) /* WC11 */ + //##++ #define _WCHAR_T + #define wchar_t char + #endif +#endif + + + +/* End of header body */ + +#undef _ext + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + +/* (no header definitions found) */ + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +#endif /* _MBG_TGT_H */ + diff --git a/mbglib/common/mbgddmsg.h b/mbglib/common/mbgddmsg.h new file mode 100755 index 0000000..d1aa8ae --- /dev/null +++ b/mbglib/common/mbgddmsg.h @@ -0,0 +1,152 @@ + +/************************************************************************** + * + * $Id: mbgddmsg.h 1.9 2011/01/26 18:13:49 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Print or remove debug messages by redefinitions. + * + * ----------------------------------------------------------------------- + * $Log: mbgddmsg.h $ + * Revision 1.9 2011/01/26 18:13:49 martin + * Support for *BSD. + * Revision 1.8 2009/04/22 09:54:55 martin + * Include mbg_tgt.h also if building without DEBUG. + * Revision 1.7 2009/03/19 15:22:54 martin + * Cleaned up debug levels. + * Revision 1.6 2008/12/05 13:31:47 martin + * Use do {} while (0) syntax to avoid potential syntax problems. + * Added _mbgddmsg_7(). + * Revision 1.5 2006/06/19 15:26:19 martin + * Fixed compiler warnings if DEBUG or DBG not defined. + * Revision 1.4 2002/06/12 12:25:54 martin + * Bug fix: check for target MBG_TGT_WIN32 instead of MBG_TGT_W32. + * Revision 1.3 2002/02/19 14:50:48Z MARTIN + * Added support for Win32. + * Revision 1.2 2002/02/19 09:28:00 MARTIN + * Use new header mbg_tgt.h to check the target environment. + * Revision 1.1 2001/03/02 13:51:23 MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _MBGDDMSG_H +#define _MBGDDMSG_H + + +#include + +#if defined( DEBUG ) || ( defined( DBG ) && DBG ) + +enum +{ + MBG_DBG_ERR, + MBG_DBG_WARN, + MBG_DBG_INFO, + MBG_DBG_DETAIL, + MBG_DBG_INIT_DEV, + MBG_DEBUG_SEM, + MBG_DBG_IRQ, + N_MBG_DBG_LVL +}; + +extern int debug; + +#define _chk_lvl( _lvl ) ( (_lvl) < debug ) + +#if defined( MBG_TGT_NETWARE ) + #include + #define _printf ConsolePrintf + #define _hd + #define _tl "\n" +#elif defined( MBG_TGT_OS2 ) + #include + #define _printf iprintf + #define _hd + #define _tl "\n" +#elif defined( MBG_TGT_WIN32 ) + #include + #define _printf DbgPrint + #define _hd + #define _tl "\n" +#elif defined( MBG_TGT_LINUX ) + // #include + #define _printf printk + #define _hd KERN_INFO + #define _tl "\n" +#elif defined( MBG_TGT_BSD ) + #define _printf printf + #define _hd + #define _tl "\n" +#else // MBG_TGT_QNX, MBG_TGT_DOS, ... + #include + #define _printf printf + #define _hd + #define _tl "\n" +#endif + + +#define _mbgddmsg_0( _lvl, _fmt ) \ +do { \ + if ( _chk_lvl( _lvl ) ) \ + { _printf( _hd _fmt _tl ); } \ +} while ( 0 ) + +#define _mbgddmsg_1( _lvl, _fmt, _p1 ) \ +do { \ + if ( _chk_lvl( _lvl ) ) \ + { _printf( _hd _fmt _tl, (_p1) ); } \ +} while ( 0 ) + +#define _mbgddmsg_2( _lvl, _fmt, _p1, _p2 ) \ +do { \ + if ( _chk_lvl( _lvl ) ) \ + { _printf( _hd _fmt _tl, (_p1), (_p2) ); } \ +} while ( 0 ) + +#define _mbgddmsg_3( _lvl, _fmt, _p1, _p2, _p3 ) \ +do { \ + if ( _chk_lvl( _lvl ) ) \ + { _printf( _hd _fmt _tl, (_p1), (_p2), (_p3) ); } \ +} while ( 0 ) + +#define _mbgddmsg_4( _lvl, _fmt, _p1, _p2, _p3, _p4 ) \ +do { \ + if ( _chk_lvl( _lvl ) ) \ + { _printf( _hd _fmt _tl, (_p1), (_p2), (_p3), (_p4) ); } \ +} while ( 0 ) + +#define _mbgddmsg_5( _lvl, _fmt, _p1, _p2, _p3, _p4, _p5 ) \ +do { \ + if ( _chk_lvl( _lvl ) ) \ + { _printf( _hd _fmt _tl, (_p1), (_p2), (_p3), (_p4), (_p5) ); } \ +} while ( 0 ) + +#define _mbgddmsg_6( _lvl, _fmt, _p1, _p2, _p3, _p4, _p5, _p6 ) \ +do { \ + if ( _chk_lvl( _lvl ) ) \ + { _printf( _hd _fmt _tl, (_p1), (_p2), (_p3), (_p4), (_p5), (_p6) ); } \ +} while ( 0 ) + +#define _mbgddmsg_7( _lvl, _fmt, _p1, _p2, _p3, _p4, _p5, _p6, _p7 ) \ +do { \ + if ( _chk_lvl( _lvl ) ) \ + { _printf( _hd _fmt _tl, (_p1), (_p2), (_p3), (_p4), (_p5), (_p6), (_p7) ); } \ +} while ( 0 ) + +#else + + #define _mbgddmsg_0( _lvl, _fmt ) _nop_macro_fnc() + #define _mbgddmsg_1( _lvl, _fmt, _p1 ) _nop_macro_fnc() + #define _mbgddmsg_2( _lvl, _fmt, _p1, _p2 ) _nop_macro_fnc() + #define _mbgddmsg_3( _lvl, _fmt, _p1, _p2, _p3 ) _nop_macro_fnc() + #define _mbgddmsg_4( _lvl, _fmt, _p1, _p2, _p3, _p4 ) _nop_macro_fnc() + #define _mbgddmsg_5( _lvl, _fmt, _p1, _p2, _p3, _p4, _p5 ) _nop_macro_fnc() + #define _mbgddmsg_6( _lvl, _fmt, _p1, _p2, _p3, _p4, _p5, _p6 ) _nop_macro_fnc() + #define _mbgddmsg_7( _lvl, _fmt, _p1, _p2, _p3, _p4, _p5, _p6, _p7 ) _nop_macro_fnc() + +#endif + +#endif /* _MBGDDMSG_H */ diff --git a/mbglib/common/mbgdevio.c b/mbglib/common/mbgdevio.c new file mode 100755 index 0000000..c3cafb8 --- /dev/null +++ b/mbglib/common/mbgdevio.c @@ -0,0 +1,6071 @@ + +/************************************************************************** + * + * $Id: mbgdevio.c 1.35.1.11 2011/02/01 15:08:08 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Functions called from user space to access Meinberg device drivers. + * + * ----------------------------------------------------------------------- + * $Log: mbgdevio.c $ + * Revision 1.35.1.11 2011/02/01 15:08:08 martin + * Revision 1.35.1.10 2011/01/28 09:33:21 martin + * Modifications to support FreeBSD. + * Revision 1.35.1.9 2010/12/14 11:23:47 martin + * Moved definition of MBG_HW_NAME to the header file. + * Revision 1.35.1.8 2010/12/14 10:56:33Z martin + * Revision 1.35.1.7 2010/08/18 13:43:20 martin + * Revision 1.35.1.6 2010/08/11 13:48:52 martin + * Cleaned up comments. + * Revision 1.35.1.5 2010/08/11 12:43:51 martin + * Revision 1.35.1.4 2010/05/21 13:10:37 martin + * Fixed platforms where cycles are not supported. + * Revision 1.35.1.3 2010/04/26 14:46:41 martin + * Compute PC cycles frequency under Linux if cpu_tick is not set by the kernel. + * Revision 1.35.1.2 2010/02/09 14:05:38 stefan + * Fixed a bug that kept the function mbg_open_device_by_name in a loop under certain conditions. + * Revision 1.35.1.1 2010/02/05 11:49:26 martin + * Made xhrt leap second check an inline function. + * Revision 1.35 2010/01/12 13:40:25 martin + * Fixed a typo in mbg_dev_has_raw_irig_data(). + * Revision 1.34 2009/12/15 15:34:58Z daniel + * Support reading the raw IRIG data bits for firmware versions + * which support this feature. + * Revision 1.33 2009/09/29 15:08:40Z martin + * Support retrieving time discipline info. + * Revision 1.32 2009/08/17 13:46:29 martin + * Moved specific definition of symbol _HAVE_IOCTL_WITH_SIZE + * to mbgioctl.h and renamed it to _MBG_SUPP_VAR_ACC_SIZE. + * Revision 1.31 2009/08/12 14:28:26 daniel + * Included PTP functions in build. + * Revision 1.30 2009/06/19 12:19:41Z martin + * Support reading raw IRIG time. + * Revision 1.29 2009/06/08 18:23:22 daniel + * Added PTP configuration functions and PTP state functions, but + * they are still excluded from build. + * Added calls to support simple LAN interface configuration. + * Revision 1.28 2009/03/19 15:30:04 martin + * Added support for configurable time scales. + * Support reading/writing GPS UTC parameters. + * Support reading IRIG control function bits. + * Support reading MM timestamps without cycles. + * Fixed endianess correction in mbg_get_gps_pos(). + * Endianess correction for ASIC version and ASIC features + * is now done by the kernel driver. + * Use generic cycles types and functions in mbg_get_default_cycles_frequency(). + * mbg_tgt.h is now included in mbgdevio.h. + * Account for renamed IOCTL codes. + * Revision 1.27 2008/12/17 10:37:37 martin + * Fixed a bug in mbg_open_device_by_name() with sel. mode MBG_MATCH_ANY. + * Support variable read buffer sizes under Linux, so + * mbg_get_all_port_info() and mbg_get_all_str_type_info() + * can now be used under Linux. + * Support PC cycles under Linux via inline rdtsc call. + * Use predefined constants to convert fractions. + * New API calls mbg_get_fast_hr_timestamp_cycles(), and + * mbg_get_fast_hr_timestamp_comp() which take memory mapped HR time stamps + * in kernel space, and mbg_dev_has_fast_hr_timestamp() to check whether + * this is supported by a device. + * Removed mm_*() functions since these are obsolete now. + * Support extrapolated HR time (xhrt) for Windows and Linux + * by providing a function mbg_xhrt_poll_thread_create() which + * starts a poll thread for a specific device which to read + * HR time plus associated cycles in regular intervals. + * Added functions mbg_get_process_affinity(), mbg_set_process_affinity(), + * and mbg_set_current_process_affinity_to_cpu(), and mbg_create_thread() + * and mbg_set_thread_affinity() to control the extrapolation feature. + * Use new preprocessor symbol MBGDEVIO_HAVE_THREAD_AFFINITY. + * Added new functions mbg_get_xhrt_time_as_pcps_hr_time() and + * mbg_get_xhrt_time_as_filetime() (Windows only) to retrieve + * fast extrapolated timestamps. + * Added function mbg_get_xhrt_cycles_frequency() to retrieve the + * cycles counter frequency computed by the polling thread. + * Added function mbg_get_default_cycles_frequency_from_dev(), + * and mbg_get_default_cycles_frequency() (Windows only). + * Moved mbg_open_device..() functions upwards. + * Made device_info_list common. + * New functions mbg_dev_is_msf(), mbg_dev_is_wwvb(), mbg_dev_is_lwr(), + * mbg_dev_has_asic_version(), mbg_dev_has_asic_features(), + * and mbg_get_irq_stat_info(). + * Exclude 2 more functions from build if symbol MBGDEVIO_SIMPLE is not 0. + * Account for MBG_VIRT_ADDR having beenrenamed to MBG_MEM_ADDR. + * Account Linux for device names renamed from /dev/mbgclk to /dev/mbgclock. + * Support bigendian target platforms. + * Revision 1.26 2008/02/26 16:54:21 martin + * New/changed functions for memory mapped access which are + * currently excluded from build. + * Changed separator for device names from ' ' to '_'. + * Added new type MBG_HW_NAME. + * Comment cleanup for doxygen. + * Revision 1.25 2008/02/04 13:42:45Z martin + * Account for preprocessor symbol MBG_TGT_SUPP_MMAP. + * Revision 1.24 2008/01/31 08:31:40Z martin + * Picked up changes from 1.19.1.2: + * Under DOS detect and disable any TSR while searching for devices. + * Exclude some complex configuration API calls from build + * If MBGDEVIO_SIMPLE is defined != 0. + * Revision 1.23 2008/01/30 10:32:35Z daniel + * Renamed mapped memory funtions. + * Revision 1.22 2008/01/25 15:27:42Z daniel + * Fixed a bug in mbg_get_hr_time_comp() where an overflow + * of the fractions was handled with wrong sign. + * Revision 1.21 2008/01/17 15:49:59Z daniel + * Added functions mbg_find_devices_with_hw_id() and + * mbg_free_devics_list() to work with Linux Win32 OSs. + * Added Doxygen compliant comments for API functions. + * Support for mapped memory I/O under linux and windows. + * Added functions mbg_get_mapped_memory_info(), + * mbg_unmap_mapped_memory() and + * mbg_get_hr_timestamp_memory_mapped(). + * Account for PCI_ASIC_FEATURES. + * Cleanup for PCI ASIC version. + * Revision 1.20 2007/09/27 07:31:12 daniel + * Moved declaration of portable inline specifier to mbg_tgt.h. + * Support hotplugging of devices as used with USB by Daniel's new + * functions mbg_find_devices_with_names(), mbg_free_device_name_list(), + * mbg_open_device_by_hw_id(), and mbg_open_device_by_name(). + * In mbg_get_serial_settings() account for devices which have no + * serial port at all. + * Register event source if Windows DLL is loaded. + * Revision 1.19 2007/05/21 15:00:00Z martin + * Unified naming convention for symbols related to ref_offs. + * Revision 1.18 2007/03/02 10:17:41Z martin + * Use generic port I/O macros. + * Changes due to modified/renamed macros. + * Changes due to renamed library symbols. + * Preliminary support for *BSD. + * Revision 1.17 2006/05/02 13:15:37 martin + * Added mbg_set_gps_port_settings(), mbg_get_gps_all_pout_info(), + * mbg_set_gps_pout_settings_idx(), mbg_set_gps_pout_settings(). + * Revision 1.16 2005/06/02 11:53:12Z martin + * Implemented existing mbg_generic_..() functions. + * Added new functions mbg_generic_io() and mbg_dev_has_generic_io(). + * Added new function mbg_get_synth_state(). + * Partially use inline function. + * Changed order of some functions. + * More simplifications using macros. + * Unified macros for Win32 and Linux. + * Fixed warning under Win32 using type cast. + * Revision 1.15 2005/01/31 16:44:21Z martin + * Added function mbg_get_hr_time_comp() which returns HR time stamp + * which has latency compensated. + * Revision 1.14 2005/01/14 10:22:23Z martin + * Added functions which query device features. + * Revision 1.13 2004/12/09 11:23:59Z martin + * Support configuration of on-board frequency synthesizer. + * Revision 1.12 2004/11/09 14:11:07Z martin + * Modifications were required in order to be able to configure IRIG + * settings of cards which provide both IRIG input and output. + * Renamed functions mbg_get_irig_info() and mbg_set_irig_settings() + * to mbg_get_irig_rx_info() and mbg_set_irig_rx_settings() + * New functions mbg_get_irig_tx_info() and mbg_set_irig_tx_settings(). + * All API functions now use well defined parameter types instead of + * generic types. Some new types have been defined therefore. + * Added a workaround for GPS169PCI cards with early firmware versions + * which used the same codes to configure the IRIG output as the TCR + * cards use to configure the IRIG input. Those codes are now + * exclusively used to configure the IRIG input. The workaround + * has been included in order to let GPS169PCI cards work properly + * after a driver update, without requiring a firmware update. + * The macro _pcps_ddev_requires_irig_workaround() is used to check + * if the workaround is required. + * Renamed function mbg_get_gps_stat() to mbg_get_gps_bvar_stat(). + * Revision 1.11 2004/08/17 11:13:45Z martin + * Account for renamed symbols. + * Revision 1.10 2004/04/14 09:39:17Z martin + * Allow [g|s]et_irig_info() also for new devices with IRIG output. + * Use MBGDEVIO_COMPAT_VERSION to check version. + * Revision 1.9 2003/12/22 15:30:52Z martin + * Added functions mbg_get_asic_version(), mbg_get_time_cycles(), + * and mbg_get_hr_time_cycles(). + * Support higher baud rates for TCR510PCI and PCI510. + * Support PCPS_HR_TIME for TCR510PCI. + * API calls return ioctl results instead of success/-1. + * Moved some Win32 specific code to mbgsvctl DLL. + * Log Win32 ioctl errors to event log for debugging. + * Revision 1.8 2003/06/19 08:42:33Z martin + * Renamed function mbg_clr_cap_buff() to mbg_clr_ucap_buff(). + * New functions mbg_get_ucap_entries() and mbg_get_ucap_event(). + * New function mbg_get_hr_ucap(). + * New functions mbgdevio_get_version() and mbgdevio_check_version(). + * New functions for generic read/write access. + * New functions mbg_get_pcps_tzdl() and mbg_set_pcps_tzdl(). + * Fixed a bug passing the wrong command code to a + * direct access target in mbg_get_sync_time(). + * Return driver info for direct access targets. + * Include pcpsdrvr.h and pcps_dos.h, if applicable. + * For direct access targets, check if a function is supported + * before accessing the hardware. + * Use const parameter pointers if applicable. + * Changes due to renamed symbols/macros. + * Source code cleanup. + * Revision 1.7 2003/05/16 08:52:46 MARTIN + * Swap doubles inside API functions. + * Enhanced support for direct access targets. + * Removed obsolete code. + * Revision 1.6 2003/04/25 10:14:16 martin + * Renamed macros. + * Extended macro calls for direct access targets. + * Updated macros for Linux. + * Revision 1.5 2003/04/15 19:35:25Z martin + * New functions mbg_setup_receiver_info(), + * mbg_get_serial_settings(), mbg_save_serial_settings(). + * Revision 1.4 2003/04/09 16:07:16Z martin + * New API functions mostly complete. + * Use renamed IOCTL codes from mbgioctl.h. + * Added DllEntry function foe Win32. + * Made MBG_Device_count and MBG_Device_Path local. + * Revision 1.3 2003/01/24 13:44:40Z martin + * Fixed get_ref_time_from_driver_at_sec_change() to be used + * with old kernel drivers. + * Revision 1.2 2002/09/06 11:04:01Z martin + * Some old API functions have been replaced by new ones + * for a common PnP/non-PnP API. + * New API function which clears capture buffer. + * New function get_ref_time_from_driver_at_sec_change(). + * Revision 1.1 2002/02/19 13:48:20Z MARTIN + * Initial revision + * + **************************************************************************/ + +#define _MBGDEVIO + #include +#undef _MBGDEVIO + +#include +#include +#include +#include + +#if defined( MBG_TGT_DOS_PM ) + #include +#endif + +#if defined( MBG_USE_KERNEL_DRIVER ) + + #include + +#else + + #include + #include + #include + + static PCPS_DRVR_INFO drvr_info = { MBGDEVIO_VERSION, 0, "MBGDEVIO direct" }; + +#endif + + + +#define MAX_INFO_LEN 260 + +typedef struct +{ + MBG_HW_NAME hw_name; + char model_name[PCPS_CLOCK_NAME_SZ]; + PCPS_SN_STR serial_number; + char hardware_id[MAX_INFO_LEN]; // OS dependent hardware_id to identify and open the device +} MBG_DEVICE_INFO; + + + +// target specific code for different environments + +#if defined( MBG_TGT_WIN32 ) + + #include + #include + #include + #include //##++ + #include + #include + + #include + #include + + #define _mbgdevio_vars() \ + DWORD rc + + #define _mbgdevio_ret_val \ + rc + + #define _do_mbgdevio_io( _dh, _ioctl, _p, _insz, _outsz ) \ + rc = do_mbgdevio_io( _dh, _ioctl, (LPVOID) _p, _insz, _outsz ) + + static __mbg_inline + DWORD do_mbgdevio_io( MBG_DEV_HANDLE dh, int ioctl_code, + LPVOID p, int in_sz, int out_sz ) + { + DWORD ReturnedLength; + + if ( !DeviceIoControl( dh, ioctl_code, + p, in_sz, p, out_sz, + &ReturnedLength, + NULL + ) ) + { + DWORD rc = GetLastError(); + + // do not report a USB device timeout error + if ( rc != _mbg_err_to_os( MBG_ERR_USB_ACCESS ) ) + mbgsvctl_log_mbgdevio_error( ioctl_code, rc ); + + return rc; + } + + return MBG_SUCCESS; + + } // do_mbgdevio_io + +#elif defined( MBG_TGT_UNIX ) + + #include + + #include + #include + #include + #include // sprintf() + #include + #include + + #define _mbgdevio_vars() \ + int rc + + #define _mbgdevio_ret_val \ + ( ( rc < 0 ) ? rc : MBG_SUCCESS ) + + #define _do_mbgdevio_io( _dh, _ioctl, _p, _insz, _outsz ) \ + rc = ioctl( _dh, _ioctl, _p ) + +#else // other target OSs which access the hardware directly + + #if defined( MBG_TGT_QNX_NTO ) + #include + #include + #endif + + #if MBG_USE_DOS_TSR + #include + #else + #define pcps_read_safe _pcps_read + #define pcps_write_safe pcps_write + #define pcps_read_gps_safe pcps_read_gps + #define pcps_write_gps_safe pcps_write_gps + + #define _pcps_write_byte_safe _pcps_write_byte + #define _pcps_read_var_safe _pcps_read_var + #define _pcps_write_var_safe _pcps_write_var + #define _pcps_read_gps_var_safe _pcps_read_gps_var + #define _pcps_write_gps_var_safe _pcps_write_gps_var + #endif + + #define _mbgdevio_vars() \ + int rc + + #define _mbgdevio_ret_val \ + rc + + #define _mbgdevio_chk_cond( _cond ) \ + { \ + if ( !(_cond) ) \ + return _mbg_err_to_os( MBG_ERR_NOT_SUPP_BY_DEV ); \ + } + +#endif // end of target specific code + + +#if !defined( _MBG_SUPP_VAR_ACC_SIZE ) + // If this symbol has not yet been defined then mbgioctl.h has probably + // not yet been included. On target systems where the hardware is accessed + // directly without a kernel driver variable buffer sizes are supported, + // so we set the default to 1. + #define _MBG_SUPP_VAR_ACC_SIZE 1 +#endif + + +#if !defined( _mbgdevio_chk_cond ) + // If the macro has not been defined previously then + // it is not be required for the target environment and + // is defined as empty string. + #define _mbgdevio_chk_cond( _cond ); +#endif + + + +// The code below depends on whether the target device is accessed via +// IOCTLs to a device driver, or the hardware is accessed directly. + +#if defined( _MBGIOCTL_H ) // using IOCTL to access device driver + + #define _mbgdevio_read( _dh, _cmd, _ioctl, _p, _sz ) \ + _do_mbgdevio_io( _dh, _ioctl, _p, 0, _sz ) + + #define _mbgdevio_write( _dh, _cmd, _ioctl, _p, _sz ) \ + _do_mbgdevio_io( _dh, _ioctl, _p, _sz, 0 ) + + #define _mbgdevio_read_gps _mbgdevio_read + + #define _mbgdevio_write_gps _mbgdevio_write + + + #define _mbgdevio_read_var( _dh, _cmd, _ioctl, _p ) \ + _mbgdevio_read( _dh, _cmd, _ioctl, _p, sizeof( *(_p) ) ) + + #define _mbgdevio_write_var( _dh, _cmd, _ioctl, _p ) \ + _mbgdevio_write( _dh, _cmd, _ioctl, _p, sizeof( *(_p) ) ) + + #define _mbgdevio_write_cmd( _dh, _cmd, _ioctl ) \ + _mbgdevio_write( _dh, _cmd, _ioctl, NULL, 0 ) + + #define _mbgdevio_read_gps_var _mbgdevio_read_var + + #define _mbgdevio_write_gps_var _mbgdevio_write_var + + + #define _mbgdevio_gen_read( _dh, _cmd, _p, _sz ) \ + rc = mbgdevio_do_gen_io( _dh, _cmd, IOCTL_PCPS_GENERIC_READ, NULL, 0, _p, _sz ) + + #define _mbgdevio_gen_write( _dh, _cmd, _p, _sz ) \ + rc = mbgdevio_do_gen_io( _dh, _cmd, IOCTL_PCPS_GENERIC_WRITE, _p, _sz, NULL, 0 ) + + #define _mbgdevio_gen_io( _dh, _type, _in_p, _in_sz, _out_p, _out_sz ) \ + rc = mbgdevio_do_gen_io( _dh, _type, IOCTL_PCPS_GENERIC_IO, _in_p, _in_sz, _out_p, _out_sz ) + + #define _mbgdevio_gen_read_gps( _dh, _cmd, _p, _sz ) \ + rc = mbgdevio_do_gen_io( _dh, _cmd, IOCTL_PCPS_GENERIC_READ_GPS, NULL, 0, _p, _sz ) + + #define _mbgdevio_gen_write_gps( _dh, _cmd, _p, _sz ) \ + rc = mbgdevio_do_gen_io( _dh, _cmd, IOCTL_PCPS_GENERIC_WRITE_GPS, _p, _sz, NULL, 0 ) + + + static __mbg_inline + int mbgdevio_do_gen_io( MBG_DEV_HANDLE dh, int info, int ioctl_code, + const void *in_p, int in_sz, + void *out_p, int out_sz ) + { + IOCTL_GENERIC_BUFFER *p_buff; + int buff_size = sizeof( p_buff->ctl ) + + ( ( in_sz > out_sz ) ? in_sz : out_sz ); + int rc; + + p_buff = (IOCTL_GENERIC_BUFFER *) malloc( buff_size ); + + if ( p_buff == NULL ) + return _mbg_err_to_os( MBG_ERR_NO_MEM ); + + p_buff->ctl.info = info; + p_buff->ctl.data_size_in = in_sz; + p_buff->ctl.data_size_out = out_sz; + + if ( in_p ) + memcpy( p_buff->data, in_p, in_sz ); + + _do_mbgdevio_io( dh, ioctl_code, + p_buff, + sizeof( IOCTL_GENERIC_CTL ) + in_sz, + sizeof( IOCTL_GENERIC_CTL ) + out_sz ); + + if ( out_p && ( rc == MBG_SUCCESS ) ) + memcpy( out_p, p_buff->data, out_sz ); + + free( p_buff ); + + return rc; + + } // mbgdevio_do_gen_io + +#else // accessing hardware device directly + + #define _mbgdevio_read( _dh, _cmd, _ioctl, _p, _sz ) \ + rc = pcps_read_safe( _dh, _cmd, _p, _sz ) + + #define _mbgdevio_write( _dh, _cmd, _ioctl, _p, _sz ) \ + rc = pcps_write_safe( _dh, _cmd, _p, _sz ) + + #define _mbgdevio_read_gps( _dh, _cmd, _ioctl, _p, _sz ) \ + rc = pcps_read_gps_safe( _dh, _cmd, _p, _sz ) + + #define _mbgdevio_write_gps( _dh, _cmd, _ioctl, _p, _sz ) \ + rc = pcps_write_gps_safe( _dh, _cmd, _p, _sz ) + + + #define _mbgdevio_read_var( _dh, _cmd, _ioctl, _p ) \ + rc = _pcps_read_var_safe( _dh, _cmd, *(_p) ) + + #define _mbgdevio_write_var( _dh, _cmd, _ioctl, _p ) \ + rc = _pcps_write_var_safe( _dh, _cmd, *(_p) ) + + #define _mbgdevio_write_cmd( _dh, _cmd, _ioctl ) \ + rc = _pcps_write_byte_safe( _dh, _cmd ); + + #define _mbgdevio_read_gps_var( _dh, _cmd, _ioctl, _p ) \ + rc = _pcps_read_gps_var_safe( _dh, _cmd, *(_p) ) + + #define _mbgdevio_write_gps_var( _dh, _cmd, _ioctl, _p ) \ + rc = _pcps_write_gps_var_safe( _dh, _cmd, *(_p) ) + + + #define _mbgdevio_gen_read( _dh, _cmd, _p, _sz ) \ + _mbgdevio_read( _dh, _cmd, -1, _p, _sz ) + + #define _mbgdevio_gen_write( _dh, _cmd, _p, _sz ) \ + _mbgdevio_write( _dh, _cmd, -1, _p, _sz ) + + #define _mbgdevio_gen_io( _dh, _type, _in_p, _in_sz, _out_p, _out_sz ); \ + { \ + _mbgdevio_chk_cond( _pcps_ddev_has_generic_io( _dh ) ); \ + rc = pcps_generic_io( _dh, _type, _in_p, _in_sz, _out_p, _out_sz ); \ + } + + #define _mbgdevio_gen_read_gps( _dh, _cmd, _p, _sz ) \ + _mbgdevio_read_gps( _dh, _cmd, -1, _p, _sz ) + + #define _mbgdevio_gen_write_gps( _dh, _cmd, _p, _sz ) \ + _mbgdevio_write_gps( _dh, _cmd, -1, _p, _sz ) + +#endif + + + + +#define _mbgdevio_read_chk( _dh, _cmd, _ioctl, _p, _sz, _cond ) \ +{ \ + _mbgdevio_chk_cond( _cond ); \ + _mbgdevio_read( _dh, _cmd, _ioctl, _p, _sz ); \ +} + +#define _mbgdevio_read_var_chk( _dh, _cmd, _ioctl, _p, _cond ) \ +{ \ + _mbgdevio_chk_cond( _cond ); \ + _mbgdevio_read_var( _dh, _cmd, _ioctl, _p ); \ +} + +#define _mbgdevio_write_var_chk( _dh, _cmd, _ioctl, _p, _cond ) \ +{ \ + _mbgdevio_chk_cond( _cond ); \ + _mbgdevio_write_var( _dh, _cmd, _ioctl, _p ); \ +} + +#define _mbgdevio_write_cmd_chk( _dh, _cmd, _ioctl, _cond ) \ +{ \ + _mbgdevio_chk_cond( _cond ); \ + _mbgdevio_write_cmd( _dh, _cmd, _ioctl ); \ +} + +#define _mbgdevio_read_gps_chk( _dh, _cmd, _ioctl, _p, _sz, _cond ) \ +{ \ + _mbgdevio_chk_cond( _cond ); \ + _mbgdevio_read_gps( _dh, _cmd, _ioctl, _p, _sz ); \ +} + +#define _mbgdevio_read_gps_var_chk( _dh, _cmd, _ioctl, _p, _cond ) \ +{ \ + _mbgdevio_chk_cond( _cond ); \ + _mbgdevio_read_gps_var( _dh, _cmd, _ioctl, _p ); \ +} + +#define _mbgdevio_write_gps_var_chk( _dh, _cmd, _ioctl, _p, _cond ) \ +{ \ + _mbgdevio_chk_cond( _cond ); \ + _mbgdevio_write_gps_var( _dh, _cmd, _ioctl, _p ); \ +} + + + +#if defined( _MBGIOCTL_H ) + #define _mbgdevio_query_cond( _dh, _cond, _ioctl, _p ) \ + { \ + _mbgdevio_vars(); \ + _mbgdevio_read_var( _dh, -1, _ioctl, _p ); \ + return _mbgdevio_ret_val; \ + } +#else + #define _mbgdevio_query_cond( _dh, _cond, _ioctl, _p ) \ + { \ + *p = _cond( _dh ); \ + return MBG_SUCCESS; \ + } +#endif + + +static MBG_PC_CYCLES_FREQUENCY pc_cycles_frequency; +static MBG_DEVICE_INFO device_info_list[MBG_MAX_DEVICES]; + + + + +static /*HDR*/ //##++ make this public ? +int mbg_comp_hr_latency( PCPS_TIME_STAMP *ts, + const MBG_PC_CYCLES *p_cyc_ts, + const MBG_PC_CYCLES *p_cyc_ontime, + const MBG_PC_CYCLES_FREQUENCY *p_cyc_freq, + int32_t *hns_latency ) +{ + #if defined( MBG_TGT_WIN32 ) || defined( MBG_TGT_UNIX ) + + int64_t cyc_latency; + int64_t frac_latency; + int64_t comp_frac; //uint?? + + // Compute latency in cycles counter units + cyc_latency = mbg_delta_pc_cycles( p_cyc_ts, p_cyc_ontime ); + + #if DEBUG && defined( MBG_TGT_LINUX ) && defined( MBG_ARCH_X86 ) + printf( "comp_lat: %08llX.%08llX %llX - %llX = %lli", + (unsigned long long) ts->sec, + (unsigned long long) ts->frac, + (unsigned long long) *p_cyc_ts, + (unsigned long long) *p_cyc_ontime, + (unsigned long long) cyc_latency + ); + #endif + + // Account for cycles counter overflow. This is + // supposed to happen once every 2^^63 units of the + // cycles counter frequency, i.e. about every + // 97 years on a system with 3 GHz clock. + if ( cyc_latency < 0 ) + { + cyc_latency += ( (uint64_t) -1 ) >> 1; + + #if DEBUG && defined( MBG_TGT_LINUX ) + printf( "->%lli (%llX)", + (unsigned long long) cyc_latency, + (unsigned long long) ( ( (uint64_t) -1 ) >> 1 ) + ); + #endif + } + + // convert latency to binary fractions of seconds, + // i.e. units of 2^^-32. + frac_latency = (*p_cyc_freq) ? ( cyc_latency * ( ( (int64_t) 1 ) << 32 ) / *p_cyc_freq ) : 0; + + // compute the compensated fractional part of the HR time stamp + // and account for borrows from the sec field + comp_frac = ts->frac - frac_latency; + ts->frac = (uint32_t) comp_frac; // yields 32 LSBs + ts->sec += (uint32_t) ( comp_frac >> 32 ); // yields 32 MSBs + + #if DEBUG && defined( MBG_TGT_LINUX ) + printf( " frac_lat: %llX comp_frac: %08llX.%08llX", + (unsigned long long) frac_latency, + (unsigned long long) ts->sec, + (unsigned long long) ts->frac + ); + #endif + + if ( hns_latency && *p_cyc_freq ) + { + int64_t tmp_hns_latency; + + // convert to hectonanoseconds + tmp_hns_latency = cyc_latency * 10000000 / *p_cyc_freq; + + // check for range overflow + #define MAX_HNS_LATENCY 0x7FFFFFFF // int32_t + #define MIN_HNS_LATENCY ( -MAX_HNS_LATENCY - 1 ) + + if ( tmp_hns_latency > MAX_HNS_LATENCY ) + tmp_hns_latency = MAX_HNS_LATENCY; + else + if ( tmp_hns_latency < MIN_HNS_LATENCY ) + tmp_hns_latency = MIN_HNS_LATENCY; + + *hns_latency = (int32_t) tmp_hns_latency; + } + + #if DEBUG && defined( MBG_TGT_LINUX ) + printf( "\n" ); + #endif + + return MBG_SUCCESS; + + #else + + // This is currently not supported by the target environment. + return _mbg_err_to_os( MBG_ERR_NOT_SUPP_ON_OS ); + + #endif + +} // mbg_comp_hr_latency + + + +/*HDR*/ +/** + Get the version number of the compiled mbgdevio library. + If the mbgdevio library is built as a DLL/shared object then + the version number of the compiled library may differ from + the version number of the import library and header files + which have been used to build an application. + + @return The version number + + @see ::MBGDEVIO_VERSION defined in mbgdevio.h. + */ +_MBG_API_ATTR int _MBG_API mbgdevio_get_version( void ) +{ + + return MBGDEVIO_VERSION; + +} // mbgdevio_get_version + + + +/*HDR*/ +/** + Check if the version of the compiled mbgdevio library is compatible + with a certain version which is passed as parameter. + + @param header_version Version number to be checked, should be ::MBGDEVIO_VERSION + defined in mbgdevio.h. + + @return ::MBG_SUCCESS if compatible, ::MBG_ERR_LIB_NOT_COMPATIBLE if not. + + @see ::MBGDEVIO_VERSION defined in mbgdevio.h. + */ +_MBG_API_ATTR int _MBG_API mbgdevio_check_version( int header_version ) +{ + if ( header_version >= MBGDEVIO_COMPAT_VERSION ) + return MBG_SUCCESS; + + return _mbg_err_to_os( MBG_ERR_LIB_NOT_COMPATIBLE ); + +} // mbgdevio_check_version + + + +/*HDR*/ +/** + Open a device by index, starting from 0. + This function is out of date, mbg_open_device_by_name() + should be used instead. + + See the note for mbg_find_device() for details. + + @param device_index Index of the device, use 0 for the first device. + */ +_MBG_API_ATTR MBG_DEV_HANDLE _MBG_API mbg_open_device( unsigned int device_index ) +{ +#if defined( MBG_TGT_WIN32 ) + + const char *device_path; + HANDLE dh; + + device_path = mbg_svc_get_device_path( device_index ); + + if ( device_path == NULL ) + goto fail; + + + dh = CreateFile( + device_path, // file name + GENERIC_READ | GENERIC_WRITE, // access mode + 0, // share mode + NULL, // security descriptor + OPEN_EXISTING, // how to create + 0, // file attributes + NULL // handle to template file + ); + + if ( INVALID_HANDLE_VALUE == dh ) + { + #if 0 //##++ + printf( "mbg_open_device: CreateFile failed for index %i\n", device_index ); + #endif + + goto fail; + } + + return dh; + +fail: + return MBG_INVALID_DEV_HANDLE; + +#elif defined( MBG_TGT_UNIX ) + + MBG_DEV_HANDLE dh; + char dev_fn[50]; + + if ( device_index > MBG_MAX_DEVICES ) + device_index = MBG_MAX_DEVICES; + + sprintf( dev_fn, "/dev/mbgclock%d", device_index ); //##++ + + dh = open( dev_fn, 0 ); + + return ( dh < 0 ) ? MBG_INVALID_DEV_HANDLE : dh; + +#else + + return ( device_index < n_ddevs ) ? &pcps_ddev[device_index] : NULL; + +#endif + +} // mbg_open_device + + + +static /*HDR*/ +/* (Intentionally excluded from Doxygen) + Return a handle to a device specified by a given hardware_id. + The format the hardware_id depends on the operating system, so + this function is used only internally to detect devices for + which a unique name of the format MBG_HW_NAME is generated, + which is in turn used with the public API functions. + */ +MBG_DEV_HANDLE _MBG_API mbg_open_device_by_hw_id( const char* hw_id ) +{ +#if defined( MBG_TGT_WIN32 ) + + HANDLE dh; + int ret = 0; + BOOL usb = FALSE; + + if ( hw_id == NULL ) + goto fail; + + dh = CreateFile( + hw_id, // file name + GENERIC_READ | GENERIC_WRITE, // access mode + 0, // share mode + NULL, // security descriptor + OPEN_EXISTING, // how to create + strstr(hw_id,"usb") ? FILE_FLAG_OVERLAPPED : 0, // file attributes + NULL // handle to template file + ); + + if ( INVALID_HANDLE_VALUE == dh ) + goto fail; + + return dh; + +fail: + return MBG_INVALID_DEV_HANDLE; + +#elif defined ( MBG_TGT_UNIX ) + + MBG_DEV_HANDLE dh = -1; + + if ( strlen( hw_id ) > 0 ) + dh = open( hw_id, 0 ); + + return ( dh < 0 ) ? MBG_INVALID_DEV_HANDLE : dh; + +#else + + return MBG_INVALID_DEV_HANDLE; + +#endif + +} // mbg_open_device_by_hw_id + + + +/*HDR*/ +/** + Get the number of supported devices installed on the computer. + This function is out of date, mbg_find_devices_with_names() + should be used instead. + + Note: This function is out of date since it may not work + correctly for Meinberg devices which are disconnected and reconnected + while the system is running (e.g. USB devices). However, the function + will be kept for compatibility reasons and works correctly if all + Meinberg devices are connected at system boot and are not disconnected + and reconnected during operation + + @return The number of devices found. + + @see mbg_find_devices_with_names() + */ +_MBG_API_ATTR int _MBG_API mbg_find_devices( void ) +{ + #if defined( _PCPSDRVR_H ) + + #if defined( MBG_TGT_QNX_NTO ) + // Since this program accessed the hardware directly + // I/O privileges must be assigned to the thread. + if ( ThreadCtl( _NTO_TCTL_IO, NULL ) == -1 ) + { + perror( "Fatal error" ); + exit( 1 ); + } + #endif + + #if defined( MBG_TGT_DOS ) && MBG_USE_DOS_TSR + { + short prv_busy; + + pcps_detect_any_tsr(); + prv_busy = pcps_tsr_set_busy_flag( 1 ); + pcps_detect_clocks( pcps_isa_ports, NULL ); + pcps_tsr_set_busy_flag( prv_busy ); + } + #else + pcps_detect_clocks( pcps_isa_ports, NULL ); + #endif + + return n_ddevs; + + #elif defined( MBG_TGT_WIN32 ) + + return mbg_svc_find_devices(); + +#elif defined ( MBG_TGT_UNIX ) + + MBG_DEV_HANDLE dh; + int i = 0; + int n = 0; + + while( i < MBG_MAX_DEVICES ) + { + dh = mbg_open_device( i ); + + if ( dh != MBG_INVALID_DEV_HANDLE ) + { + mbg_close_device( &dh ); + n++; + } + + i++; + } + + return n; + + #endif + +} // mbg_find_devices + + + +#if defined( MBG_TGT_WIN32 ) || defined ( MBG_TGT_UNIX ) + +static /*HDR*/ +int mbg_find_devices_with_hw_id( MBG_DEVICE_LIST ** list, int max_devs ) +{ + #if defined ( MBG_TGT_WIN32 ) + + return mbg_svc_find_devices_with_hw_id( list, max_devs ); + + #elif defined ( MBG_TGT_UNIX ) + + MBG_DEVICE_LIST *ListBegin; + int n = 0; + int i = 0; + + (*list) = (MBG_DEVICE_LIST *) malloc( sizeof( **list ) ); + memset( *list, 0, sizeof( **list ) ); + + ListBegin = (*list); + + for (;;) + { + char dev_name[100]; + MBG_DEV_HANDLE dh; + + sprintf( dev_name, "/dev/mbgclock%d", i ); + + dh = mbg_open_device_by_hw_id( dev_name ); + + if ( dh != MBG_INVALID_HANDLE ) + { + mbg_close_device( &dh ); + + (*list)->device_path = (char *) malloc( strlen( dev_name ) + 1 ); + strcpy( (*list)->device_path, dev_name ); + + (*list)->next = (MBG_DEVICE_LIST *) malloc( sizeof( **list ) ); + (*list) = (*list)->next; + + memset( *list, 0, sizeof( **list ) ); + n++; + } + + if ( ++i >= MBG_MAX_DEVICES ) + break; + } + + if ( n > 0 ) + *list = ListBegin; + else + { + free( *list ); + *list = NULL; + } + + return n; + + #else + + return 0; + + #endif +} + +#endif + + + +#if defined ( MBG_TGT_WIN32 ) || defined ( MBG_TGT_UNIX ) + +static /*HDR*/ +void _MBG_API mbg_free_device_list( MBG_DEVICE_LIST *devices ) +{ + + #if defined ( MBG_TGT_WIN32 ) + mbg_svc_free_device_list( devices ); + #else + int i = 0; + MBG_DEVICE_LIST *Next = NULL; + + while ( i < MBG_MAX_DEVICES) + { + if ( devices ) + { + if ( devices->device_path ) + { + free( devices->device_path ); + devices->device_path = NULL; + } + + if ( devices->next ) + { + Next = devices->next; + free(devices); + devices = Next; + } + else + { + if ( devices ) + { + free( devices ); + devices = NULL; + } + break; + } + } + else + break; + + i++; + } + + #endif +} + +#endif + + + +#if ( defined( MBG_TGT_WIN32 ) || defined ( MBG_TGT_UNIX ) ) + +static /*HDR*/ +void get_hw_name_from_hw_id( MBG_DEVICE_INFO *dev_info ) +{ + MBG_DEV_HANDLE dh; + PCPS_DEV pdev; + + dh = MBG_INVALID_HANDLE; + memset( &pdev, 0, sizeof( pdev ) ); + + // Default initializers + strcpy( dev_info->model_name, "N/A" ); + strcpy( dev_info->serial_number, "N/A" ); + strcpy( dev_info->hw_name, "N/A" ); + + dh = mbg_open_device_by_hw_id( dev_info->hardware_id ); + + if ( dh != MBG_INVALID_HANDLE ) + { + if ( mbg_get_device_info( dh, &pdev ) == MBG_SUCCESS ) + { + strcpy( dev_info->model_name, _pcps_type_name( &pdev ) ); + strcpy( dev_info->serial_number, _pcps_sernum( &pdev ) ); + sprintf( dev_info->hw_name, "%s_%s", _pcps_type_name( &pdev ), _pcps_sernum( &pdev ) ); + } + + mbg_close_device( &dh ); + } + +} // get_hw_name_from_hw_id + +#endif + + + +/*HDR*/ +/** + Return the number of supported devices installed on the system and + set up a list of unique names of those devices. + + This function should be used preferably instead of mbg_find_devices(). + + @param device_list Pointer to a linked list of type ::MBG_DEVICENAME_LIST + with device names. The list will be allocated by this + function and has to be freed after usage by calling + mbg_free_device_name_list(). + @param max_devices Maximum number of devices the function should look for + (can not exceed ::MBG_MAX_DEVICES). + + @return Number of present devices + + @see ::MBG_HW_NAME for the format of the unique names + @see mbg_free_device_name_list() + @see mbg_find_devices() + */ +_MBG_API_ATTR int _MBG_API mbg_find_devices_with_names( MBG_DEVICENAME_LIST **device_list, + int max_devices ) +{ +#if defined( MBG_TGT_WIN32 ) || defined( MBG_TGT_UNIX ) + + MBG_DEVICE_LIST *hardware_list = NULL; + MBG_DEVICE_LIST *hardware_list_begin = NULL; + MBG_DEVICENAME_LIST *ListBegin = NULL; + MBG_DEVICE_INFO dev_info; + + int n_devices = 0; + int i = 0; + + n_devices = mbg_find_devices_with_hw_id( &hardware_list, max_devices ); + + hardware_list_begin = hardware_list; + + if ( n_devices ) + { + *device_list = (MBG_DEVICENAME_LIST *) malloc( sizeof( MBG_DEVICENAME_LIST ) ); + (*device_list)->next = NULL; + + // Save begin of the list + ListBegin = *device_list; + + // Loop through the list of hardware_ids and get their readable names + for (;;) + { + if ( hardware_list->device_path && i++ < MBG_MAX_DEVICES ) + { + strcpy( dev_info.hardware_id, hardware_list->device_path ); + + get_hw_name_from_hw_id( &dev_info ); + + strcpy( (*device_list)->device_name, dev_info.hw_name ); + + if ( hardware_list->next ) + { + hardware_list = hardware_list->next; + (*device_list)->next = (MBG_DEVICENAME_LIST *) malloc( sizeof( MBG_DEVICENAME_LIST ) ); + (*device_list) = (*device_list)->next; + (*device_list)->next = NULL; + } + else + break; + } + else + break; + } + + *device_list = ListBegin; + } + + if ( hardware_list_begin ) + mbg_free_device_list( hardware_list_begin ); + + return n_devices; + +#else + + return 0; + +#endif + +} // mbg_find_devices_with_names + + + +/*HDR*/ +/** + Free the memory of the ::MBG_DEVICENAME_LIST that has been allocated before + by mbg_find_devices_with_names(). + + @param *list Linked list of type ::MBG_DEVICENAME_LIST + + @see mbg_find_devices_with_names() + */ +_MBG_API_ATTR void _MBG_API mbg_free_device_name_list( MBG_DEVICENAME_LIST *list) +{ +#if defined( MBG_TGT_WIN32 ) || defined( MBG_TGT_UNIX ) + + MBG_DEVICENAME_LIST *Next = NULL; + int i = 0; + + // Deallocate members of linked list + while ( i < MBG_MAX_DEVICES ) + { + if ( list ) + { + Next = list->next; + + free( list ); + list = NULL; + + if ( Next ) + list = Next->next; + else + break; + } + else + break; + + i++; + } + +#endif + +} // mbg_free_device_list + + + +/*HDR*/ +/** + Return a handle to a device with a certain unique name. + The names of the devices that are installed on the system can be retrieved by + the function mbg_find_devices_with_names(). + + This function should be used preferably instead of mbg_open_device(). + + @param hw_name String with the unique name of the device to be opened + @param selection_mode One of the enum values of ::MBG_MATCH_MODE + + @return On success, the function returns a handle to the device, otherwise ::MBG_INVALID_DEV_HANDLE + + @see ::MBG_HW_NAME for the format of the unique names. + @see ::MBG_MATCH_MODE + @see mbg_find_devices_with_names() + */ +_MBG_API_ATTR MBG_DEV_HANDLE _MBG_API mbg_open_device_by_name( const char* hw_name, int selection_mode ) //##++++ +{ + +#if ( defined( MBG_TGT_WIN32 ) || defined ( MBG_TGT_UNIX ) ) + + MBG_DEV_HANDLE dh; + + MBG_DEVICE_LIST *devices = NULL; + MBG_DEVICE_LIST *ListBegin = NULL; + char hw_id[MAX_INFO_LEN]; + char tmp_model_name[PCPS_CLOCK_NAME_SZ]; + PCPS_SN_STR tmp_sn; + int n_devices = 0; + int i = 0; + int j = 0; + + hw_id[0] = '\0'; + + memset( tmp_model_name, 0, sizeof( tmp_model_name) ); + memset( device_info_list, 0, sizeof( device_info_list ) ); + memset( tmp_sn, 0, sizeof( tmp_sn ) ); + + // separate hw_name into clock model and serial number + if ( hw_name && ( strlen( hw_name ) > 0 ) ) + { + // clock model + for ( i = 0; ( i < PCPS_CLOCK_NAME_SZ ) && ( hw_name[i] != '_' ) && ( (unsigned int) i < strlen( hw_name ) ); i++ ) + tmp_model_name[i] = hw_name[i]; + + tmp_model_name[i] = 0; + i++; + + // serial number + if ( ( unsigned int ) i < strlen( hw_name ) ) + { + j = 0; + + while( ( unsigned int ) i < strlen(hw_name) && j < PCPS_SN_SIZE ) + { + tmp_sn[j] = hw_name[i]; + j++; + i++; + } + tmp_sn[j] = '\0'; + } + } + else + goto fail; + + i = 0; + + // get OS-dependent hardware_id strings for devices that are present on the system + n_devices = mbg_find_devices_with_hw_id( &devices, MBG_MAX_DEVICES ); + + ListBegin = devices; + + if ( n_devices ) + { + for (;;) + { + if ( devices->device_path && i < MBG_MAX_DEVICES ) + { + strncpy( device_info_list[i].hardware_id, devices->device_path, MAX_INFO_LEN ); + + // get readable hw_name for the device + get_hw_name_from_hw_id( &device_info_list[i] ); + + if ( hw_name && device_info_list[i].hw_name && strcmp( device_info_list[i].hw_name, hw_name ) == 0 ) //##+++++ + { + // The requested device was found + strcpy( hw_id, device_info_list[i].hardware_id ); + break; + } + else if ( devices->next ) + devices = devices->next; + else + break; + } + else + break; + i++; + } + + // If the requested CLOCK_MODEL/SN combination was not found, + // decide what to do depending on the selection mode + if ( ( hw_id[0] == '\0' ) && ( selection_mode != MBG_MATCH_EXACTLY ) ) + { + for ( j = 0; j <= i; j++ ) + { + // Search for the same clock model + if ( ( tmp_model_name[0] != '\0' ) && strcmp( device_info_list[j].model_name, tmp_model_name ) == 0 ) + { + strcpy( hw_id, device_info_list[j].hardware_id ); + break; + } + } + + // Finally select the first device found on the system, if the clock model was not found + if ( ( selection_mode == MBG_MATCH_ANY ) && ( hw_id[0] == '\0' ) ) + strcpy( hw_id, device_info_list[0].hardware_id ); + } + } + + mbg_free_device_list( ListBegin ); + +#endif + +#if defined ( MBG_TGT_WIN32 ) + + if ( hw_id[0] == '\0' ) + goto fail; + + dh = CreateFile( + hw_id, // file name + GENERIC_READ | GENERIC_WRITE, // access mode + 0, // share mode + NULL, // security descriptor + OPEN_EXISTING, // how to create + strstr(hw_id,"usb") ? FILE_FLAG_OVERLAPPED : 0, // file attributes + NULL // handle to template file + ); + + if ( INVALID_HANDLE_VALUE == dh ) + goto fail; + + return dh; + +fail: + return MBG_INVALID_DEV_HANDLE; + +#elif defined ( MBG_TGT_UNIX ) + + if ( hw_id[0] != '\0' ) + dh = open( hw_id, 0 ); + else + goto fail; + + return ( dh < 0 ) ? MBG_INVALID_DEV_HANDLE : dh; + +fail: + return MBG_INVALID_DEV_HANDLE; + +#else + + //return ( device_index < n_ddevs ) ? &pcps_ddev[device_index] : NULL; + return MBG_INVALID_DEV_HANDLE; + +#endif + +} // mbg_open_device_by_name + + + +/*HDR*/ +/** + Close a handle to a device and set the handle value to ::MBG_INVALID_DEV_HANDLE. + If required, unmap mapped memory. + + @param dev_handle Handle to a Meinberg device. + */ +_MBG_API_ATTR void _MBG_API mbg_close_device( MBG_DEV_HANDLE *dev_handle ) +{ + if ( *dev_handle != MBG_INVALID_DEV_HANDLE && *dev_handle != 0 ) //##++++ dev_handle NULL/0 ??? + { + #if defined( MBG_TGT_WIN32 ) + CloseHandle( *dev_handle ); + #elif defined( MBG_TGT_UNIX ) + close( *dev_handle ); + #endif + } + + *dev_handle = MBG_INVALID_DEV_HANDLE; + +} // mbg_close_device + + + +/*HDR*/ +/** + Return a ::PCPS_DRVR_INFO structure that provides information + about the kernel device driver. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_DRVR_INFO structure which is filled up. + + @return ::MBG_SUCCESS or error code returned by device I/O control function + */ +_MBG_API_ATTR int _MBG_API mbg_get_drvr_info( MBG_DEV_HANDLE dh, PCPS_DRVR_INFO *p ) +{ + #if defined( _MBGIOCTL_H ) + _mbgdevio_vars(); + _mbgdevio_read_var( dh, -1, IOCTL_GET_PCPS_DRVR_INFO, p ); + return _mbgdevio_ret_val; + #else + #if defined( __BORLANDC__ ) + dh; // avoid warnings "never used" + #endif + drvr_info.n_devs = n_ddevs; + *p = drvr_info; + return MBG_SUCCESS; + #endif + +} // mbg_get_drvr_info + + + +/*HDR*/ +/** + Return a ::PCPS_DEV structure that provides detailed information about the device. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_DEV structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function + */ +_MBG_API_ATTR int _MBG_API mbg_get_device_info( MBG_DEV_HANDLE dh, PCPS_DEV *p ) +{ + #if defined( _MBGIOCTL_H ) + _mbgdevio_vars(); + _mbgdevio_read_var( dh, -1, IOCTL_GET_PCPS_DEV, p ); + // Endianess is converted inside the kernel driver, if necessary. + return _mbgdevio_ret_val; + #else + *p = dh->dev; + return MBG_SUCCESS; + #endif + +} // mbg_get_device_info + + + +/*HDR*/ +/** + Return the current state of the on-board::PCPS_STATUS_PORT. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_STATUS_PORT value to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function + + @see \ref group_status_port "bitmask" + */ +_MBG_API_ATTR int _MBG_API mbg_get_status_port( MBG_DEV_HANDLE dh, PCPS_STATUS_PORT *p ) +{ + #if defined( _MBGIOCTL_H ) + _mbgdevio_vars(); + _mbgdevio_read_var( dh, -1, IOCTL_GET_PCPS_STATUS_PORT, p ); + // No endianess conversion required. + return _mbgdevio_ret_val; + #else + *p = _pcps_ddev_read_status_port( dh ); + // No endianess conversion required. + return MBG_SUCCESS; + #endif + +} // mbg_get_status_port + + + +/*HDR*/ +/* (Intentionally excluded from Doxygen) + Generic read function which writes a command code to the device + and reads a number of replied data to a generic buffer. + + Warning: This is for debugging purposes only! + The specialized API calls should be used preferably. + A specific device may not support any command code. + + @param dh Valid handle to a Meinberg device + @param cmd Can be any \ref group_cmd_bytes "command byte" supported by the device + @param *p Pointer to a buffer to be filled up + @param size Size of the buffer *p + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_generic_write() + @see mbg_generic_read_gps() + @see mbg_generic_write_gps() + @see mbg_generic_io() + */ +_MBG_API_ATTR int _MBG_API mbg_generic_read( MBG_DEV_HANDLE dh, int cmd, + void *p, int size ) +{ + _mbgdevio_vars(); + _mbgdevio_gen_read( dh, cmd, p, size ); + // No type information available, so endianess must be + // converted by the caller, if required. + return _mbgdevio_ret_val; + +} // mbg_generic_read + + + +/*HDR*/ +/* (Intentionally excluded from Doxygen) + Generic read function which writes a GPS command code to the device + and reads a number of replied data to a generic buffer. + The macro _pcps_has_gps_data() or the API call mbg_dev_has_gps_data() + check whether this call is supported by a specific card. + + Warning: This is for debugging purposes only! + The specialized API calls should be used preferably. + A specific device may not support any GPS command code. + + @param dh Valid handle to a Meinberg device + @param cmd Can be any \ref group_cmd_bytes "command byte" supported by the device. + @param *p Pointer to a buffer to be filled up + @param size Size of the buffer *p + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_gps_data() + @see mbg_generic_write_gps() + @see mbg_generic_read() + @see mbg_generic_write() + @see mbg_generic_io() + */ +_MBG_API_ATTR int _MBG_API mbg_generic_read_gps( MBG_DEV_HANDLE dh, int cmd, + void *p, int size ) +{ + _mbgdevio_vars(); + _mbgdevio_gen_read_gps( dh, cmd, p, size ); + // No type information available, so endianess must be + // converted by the caller, if required. + return _mbgdevio_ret_val; + +} // mbg_generic_read_gps + + + +/*HDR*/ +/* (Intentionally excluded from Doxygen) + Generic write function which writes a command code plus an + associated number of data bytes to the device. + + Warning: This is for debugging purposes only! + The specialized API calls should be used preferably. + A specific device may not support any command code. + + @param dh Valid handle to a Meinberg device + @param cmd Can be any \ref group_cmd_bytes "command byte" supported by the device. + @param *p Pointer to a buffer to be written + @param size Size of the buffer *p + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_generic_read() + @see mbg_generic_read_gps() + @see mbg_generic_write_gps() + @see mbg_generic_io() + */ +_MBG_API_ATTR int _MBG_API mbg_generic_write( MBG_DEV_HANDLE dh, int cmd, + const void *p, int size ) +{ + _mbgdevio_vars(); + // No type information available, so endianess must be + // converted by the caller, if required. + _mbgdevio_gen_write( dh, cmd, p, size ); + return _mbgdevio_ret_val; + +} // mbg_generic_write + + + +/*HDR*/ +/* (Intentionally excluded from Doxygen) + Generic write function which writes a GPS command code plus an + associated number of data bytes to the device. + The macro _pcps_has_gps_data() or the API call mbg_dev_has_gps_data() + check whether this call is supported by a specific card. + + Warning: This is for debugging purposes only! + The specialized API calls should be used preferably. + A specific device may not support any GPS command code. + + @param dh Valid handle to a Meinberg device + @param cmd Can be any \ref group_cmd_bytes "command byte" supported by the device. + @param *p Pointer to a buffer to be written + @param size Size of the buffer *p + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_gps_data() + @see mbg_generic_read_gps() + @see mbg_generic_read() + @see mbg_generic_write() + @see mbg_generic_io() + */ +_MBG_API_ATTR int _MBG_API mbg_generic_write_gps( MBG_DEV_HANDLE dh, int cmd, + const void *p, int size ) +{ + _mbgdevio_vars(); + // No type information available, so endianess must be + // converted by the caller, if required. + _mbgdevio_gen_write_gps( dh, cmd, p, size ); + return _mbgdevio_ret_val; + +} // mbg_generic_write_gps + + + +/*HDR*/ +/* (Intentionally excluded from Doxygen) + Write and/or read generic data to/from a device. + The macro _pcps_has_generic_io() or the API call mbg_dev_has_generic_io() + check whether this call is supported by a specific card. + + Warning: This call is for debugging purposes and internal use only! + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_generic_io() + @see mbg_generic_read() + @see mbg_generic_write() + @see mbg_generic_read_gps() + @see mbg_generic_write_gps() + */ +_MBG_API_ATTR int _MBG_API mbg_generic_io( MBG_DEV_HANDLE dh, int type, + const void *in_p, int in_sz, + void *out_p, int out_sz ) +{ + _mbgdevio_vars(); + // No type information available, so endianess must be + // converted by the caller, if required. + _mbgdevio_gen_io( dh, type, in_p, in_sz, out_p, out_sz ); + return _mbgdevio_ret_val; + +} // mbg_generic_io + + + +/*HDR*/ +/** + Read a ::PCPS_TIME structure returning the current date/time/status. + The returned time is local time according to the card's time zone setting, + with a resolution of 10 ms (i.e. 10ths of seconds). + + This call is supported by any device manufactured by Meinberg. However, + for higher accuracy and resolution the mbg_get_hr_time..() group of calls + should be used preferably if supported by the specific device. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TIME structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_hr_time() + @see mbg_set_time() + @see mbg_get_sync_time() + */ +_MBG_API_ATTR int _MBG_API mbg_get_time( MBG_DEV_HANDLE dh, PCPS_TIME *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_var( dh, PCPS_GIVE_TIME, IOCTL_GET_PCPS_TIME, p ); + // No endianess conversion required. + return _mbgdevio_ret_val; + +} // mbg_get_time + + + +/*HDR*/ +/** + Set a device's on-board clock manually by passing a ::PCPS_STIME structure + The macro _pcps_can_set_time() checks whether this call + is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_STIME structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_time() + */ +_MBG_API_ATTR int _MBG_API mbg_set_time( MBG_DEV_HANDLE dh, const PCPS_STIME *p ) +{ + _mbgdevio_vars(); + // No endianess conversion required. + _mbgdevio_write_var_chk( dh, PCPS_SET_TIME, IOCTL_SET_PCPS_TIME, p, + _pcps_ddev_can_set_time( dh ) ); + return _mbgdevio_ret_val; + +} // mbg_set_time + + + +/*HDR*/ +/** + Read a ::PCPS_TIME structure returning the date/time/status reporting + when the device was synchronized the last time to its time source, + e.g. the DCF77 signal or the GPS satellites. + The macro _pcps_has_sync_time() or the API call mbg_dev_has_sync_time() + check whether this call is supported by a specific card. + + The macro _pcps_has_sync_time() checks whether this call + is supported by a specific card. + + Note: If that information is not available on the board then + the value of the returned ::PCPS_TIME::sec field is set to 0xFF. + The macro _pcps_time_is_read() can be used to check whether the + returned information is valid, or not available. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TIME structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_time() + */ +_MBG_API_ATTR int _MBG_API mbg_get_sync_time( MBG_DEV_HANDLE dh, PCPS_TIME *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_var_chk( dh, PCPS_GIVE_SYNC_TIME, IOCTL_GET_PCPS_SYNC_TIME, + p, _pcps_ddev_has_sync_time( dh ) ); + // No endianess conversion required. + return _mbgdevio_ret_val; + +} // mbg_get_sync_time + + + +/*HDR*/ +/** + Wait until the next second change, then return a ::PCPS_TIME + structure similar to mbg_get_time(). + + Note: This API call is supported under Windows only. + The call blocks until the kernel driver detects a second change + reported by the device. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TIME structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_time() + */ +_MBG_API_ATTR int _MBG_API mbg_get_time_sec_change( MBG_DEV_HANDLE dh, PCPS_TIME *p ) +{ + #if defined( MBG_TGT_WIN32 ) + _mbgdevio_vars(); + _mbgdevio_read_var( dh, -1, IOCTL_GET_PCPS_TIME_SEC_CHANGE, p ); + // No endianess conversion required. + return _mbgdevio_ret_val; + #else + #if defined( __BORLANDC__ ) + dh; p; // avoid warnings "never used" + #endif + return _mbg_err_to_os( MBG_ERR_NOT_SUPP_ON_OS ); + #endif + +} // mbg_get_time_sec_change + + + +/*HDR*/ +/** + Read a ::PCPS_HR_TIME (High Resolution time) structure returning + the current %UTC time (seconds since 1970), %UTC offset, and status. + The macro _pcps_has_hr_time() or the API call mbg_dev_has_hr_time() + check whether this call is supported by a specific card. + + Note: This API call provides a higher accuracy and resolution + than mbg_get_time(). However, it does not account for the latency + which is introduced when accessing the board. + The mbg_get_hr_time_cycles() and mbg_get_hr_time_comp() calls + provides mechanisms to account for and/or compensate the latency. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_HR_TIME structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_hr_time() + @see mbg_get_time() + @see mbg_get_hr_time_cycles() + @see mbg_get_hr_time_comp() + */ +_MBG_API_ATTR int _MBG_API mbg_get_hr_time( MBG_DEV_HANDLE dh, PCPS_HR_TIME *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_var_chk( dh, PCPS_GIVE_HR_TIME, IOCTL_GET_PCPS_HR_TIME, + p, _pcps_ddev_has_hr_time( dh ) ); + _mbg_swab_pcps_hr_time( p ); + return _mbgdevio_ret_val; + +} // mbg_get_hr_time + + + +/*HDR*/ +/* (Intentionally excluded from Doxygen ) + Write a high resolution time stamp ::PCPS_TIME_STAMP to the clock + to configure a %UTC time when the clock shall generate an event. + The macro _pcps_has_event_time() or the API call mbg_dev_has_event_time() + check whether this call is supported by a specific card. + + Note: This is only supported by some special firmware. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TIME_STAMP structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_event_time() + */ +_MBG_API_ATTR int _MBG_API mbg_set_event_time( MBG_DEV_HANDLE dh, const PCPS_TIME_STAMP *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + PCPS_TIME_STAMP tmp = *p; + _mbg_swab_pcps_time_stamp( &tmp ); + p = &tmp; + #endif + _mbgdevio_write_var_chk( dh, PCPS_SET_EVENT_TIME, IOCTL_SET_PCPS_EVENT_TIME, + p, _pcps_ddev_has_event_time( dh ) ); + return _mbgdevio_ret_val; + +} // mbg_set_event_time + + + +/*HDR*/ +/** + Read the configuration of a device's serial port. + The macro _pcps_has_serial() checks whether this call + is supported by a specific card. + + Note: This function is supported only by a certain class + of devices, so it should not be called directly. The generic + function mbg_get_serial_settings() should be used instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_SERIAL structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see \ref group_cmd_bytes + @see mbg_get_serial_settings() + */ +_MBG_API_ATTR int _MBG_API mbg_get_serial( MBG_DEV_HANDLE dh, PCPS_SERIAL *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_var( dh, PCPS_GET_SERIAL, IOCTL_GET_PCPS_SERIAL, p ); + // No endianess conversion required. + return _mbgdevio_ret_val; + +} // mbg_get_serial + + + +/*HDR*/ +/** + Write the configuration of a device's serial port. + The macro _pcps_has_serial() checks whether this call + is supported by a specific card. + + Note: This function is supported only by a certain class + of devices, so it should not be called directly. The generic + function mbg_save_serial_settings() should be used instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_SERIAL structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see \ref group_cmd_bytes + @see mbg_save_serial_settings() + */ +_MBG_API_ATTR int _MBG_API mbg_set_serial( MBG_DEV_HANDLE dh, const PCPS_SERIAL *p ) +{ + _mbgdevio_vars(); + // No endianess conversion required. + _mbgdevio_write_var( dh, PCPS_SET_SERIAL, IOCTL_SET_PCPS_SERIAL, p ); + return _mbgdevio_ret_val; + +} // mbg_set_serial + + + +/*HDR*/ +/** + Read the card's time zone/daylight saving configuration code. + That tzcode is supported by some simpler cards and only allows only + a very basic configuration. + The macro _pcps_has_tzcode() or the API call mbg_dev_has_tzcode() + check whether this call is supported by a specific card. + Other cards may support the mbg_get_pcps_tzdl() or mbg_get_gps_tzdl() + calls instead which allow for a more detailed configuration of the + time zone and daylight saving settings. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TZCODE structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_tzcode() + @see mbg_set_tzcode() + @see mbg_get_pcps_tzdl() + @see mbg_get_gps_tzdl() + @see \ref group_cmd_bytes + */ +_MBG_API_ATTR int _MBG_API mbg_get_tzcode( MBG_DEV_HANDLE dh, PCPS_TZCODE *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_var_chk( dh, PCPS_GET_TZCODE, IOCTL_GET_PCPS_TZCODE, + p, _pcps_ddev_has_tzcode( dh ) ); + // No endianess conversion required. + return _mbgdevio_ret_val; + +} // mbg_get_tzcode + + + +/*HDR*/ +/** + Write the card's time zone/daylight saving configuration code. + That tzcode is supported by some simpler cards and only allows only + a very basic configuration. + The macro _pcps_has_tzcode() or the API call mbg_dev_has_tzcode() + check whether this call is supported by a specific card. + Other cards may support the mbg_set_pcps_tzdl() or mbg_set_gps_tzdl() + calls instead which allow for a more detailed configuration of the + time zone and daylight saving settings. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TZCODE structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_tzcode() + @see mbg_get_tzcode() + @see mbg_set_pcps_tzdl() + @see mbg_set_gps_tzdl() + @see \ref group_cmd_bytes + */ +_MBG_API_ATTR int _MBG_API mbg_set_tzcode( MBG_DEV_HANDLE dh, const PCPS_TZCODE *p ) +{ + _mbgdevio_vars(); + // No endianess conversion required. + _mbgdevio_write_var_chk( dh, PCPS_SET_TZCODE, IOCTL_SET_PCPS_TZCODE, + p, _pcps_ddev_has_tzcode( dh ) ); + return _mbgdevio_ret_val; + +} // mbg_set_tzcode + + + +/*HDR*/ +/** + Read the card's time zone/daylight saving parameters using the + ::PCPS_TZDL structure. + The macro _pcps_has_pcps_tzdl() or the API call mbg_dev_has_pcps_tzdl() + check whether this call is supported by a specific card. + Other cards may support the mbg_get_tzcode() or mbg_get_gps_tzdl() + calls instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TZDL structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_pcps_tzdl() + @see mbg_set_pcps_tzdl() + @see mbg_get_tzcode() + @see mbg_get_gps_tzdl() + @see \ref group_cmd_bytes + */ +_MBG_API_ATTR int _MBG_API mbg_get_pcps_tzdl( MBG_DEV_HANDLE dh, PCPS_TZDL *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_var_chk( dh, PCPS_GET_PCPS_TZDL, IOCTL_GET_PCPS_TZDL, + p, _pcps_ddev_has_pcps_tzdl( dh ) ); + _mbg_swab_pcps_tzdl( p ); + return _mbgdevio_ret_val; + +} // mbg_get_pcps_tzdl + + + +/*HDR*/ +/** + Write the card's time zone/daylight saving parameters using the + ::PCPS_TZDL structure. + The macro _pcps_has_pcps_tzdl() or the API call mbg_dev_has_pcps_tzdl() + check whether this call is supported by a specific card. + Other cards may support the mbg_set_tzcode() or mbg_set_gps_tzdl() + calls instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TZDL structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_pcps_tzdl() + @see mbg_get_pcps_tzdl() + @see mbg_set_tzcode() + @see mbg_set_gps_tzdl() + @see \ref group_cmd_bytes + */ +_MBG_API_ATTR int _MBG_API mbg_set_pcps_tzdl( MBG_DEV_HANDLE dh, const PCPS_TZDL *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + PCPS_TZDL tmp = *p; + _mbg_swab_pcps_tzdl( &tmp ); + p = &tmp; + #endif + _mbgdevio_write_var_chk( dh, PCPS_SET_PCPS_TZDL, IOCTL_SET_PCPS_TZDL, + p, _pcps_ddev_has_pcps_tzdl( dh ) ); + return _mbgdevio_ret_val; + +} // mbg_set_pcps_tzdl + + + +/*HDR*/ +/** + Read the reference time offset from %UTC for clocks which can't determine + that offset automatically, e.g. from an IRIG input signal. + The macro _pcps_has_ref_offs() or the API call mbg_dev_has_ref_offs() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_REF_OFFS value to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_ref_offs() + @see mbg_set_ref_offs() + @see ::PCPS_GET_REF_OFFS + */ +_MBG_API_ATTR int _MBG_API mbg_get_ref_offs( MBG_DEV_HANDLE dh, MBG_REF_OFFS *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_var_chk( dh, PCPS_GET_REF_OFFS, IOCTL_GET_REF_OFFS, + p, _pcps_ddev_has_ref_offs( dh ) ); + _mbg_swab_mbg_ref_offs( p ); + return _mbgdevio_ret_val; + +} // mbg_get_ref_offs + + + +/*HDR*/ +/** + Write the reference time offset from %UTC for clocks which can't determine + that offset automatically, e.g. from an IRIG input signal. + The macro _pcps_has_ref_offs() or the API call mbg_dev_has_ref_offs() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_REF_OFFS value to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_ref_offs() + @see mbg_get_ref_offs() + @see ::PCPS_SET_REF_OFFS + */ +_MBG_API_ATTR int _MBG_API mbg_set_ref_offs( MBG_DEV_HANDLE dh, const MBG_REF_OFFS *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + MBG_REF_OFFS tmp = *p; + _mbg_swab_mbg_ref_offs( &tmp ); + p = &tmp; + #endif + _mbgdevio_write_var_chk( dh, PCPS_SET_REF_OFFS, IOCTL_SET_REF_OFFS, + p, _pcps_ddev_has_ref_offs( dh ) ); + return _mbgdevio_ret_val; + +} // mbg_set_ref_offs + + + +/*HDR*/ +/** + Read a ::MBG_OPT_INFO structure containing optional settings, controlled by flags. + The ::MBG_OPT_INFO structure contains a mask of supported flags plus the current + settings of those flags. + The macro _pcps_has_opt_flags() or the API call mbg_dev_has_opt_flags() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_OPT_INFO structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_opt_flags() + @see mbg_set_opt_settings() + */ +_MBG_API_ATTR int _MBG_API mbg_get_opt_info( MBG_DEV_HANDLE dh, MBG_OPT_INFO *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_var_chk( dh, PCPS_GET_OPT_INFO, IOCTL_GET_MBG_OPT_INFO, + p, _pcps_ddev_has_opt_flags( dh ) ); + _mbg_swab_mbg_opt_info( p ); + return _mbgdevio_ret_val; + +} // mbg_get_opt_info + + + +/*HDR*/ +/** + Write a ::MBG_OPT_SETTINGS structure contains optional settings, controlled by flags. + The macro _pcps_has_opt_flags() or the API call mbg_dev_has_opt_flags() + check whether this call is supported by a specific card. + The ::MBG_OPT_INFO structure should be read first to check which of the specified + flags is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_OPT_SETTINGS structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_opt_flags() + @see mbg_get_opt_info() + */ +_MBG_API_ATTR int _MBG_API mbg_set_opt_settings( MBG_DEV_HANDLE dh, const MBG_OPT_SETTINGS *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + MBG_OPT_SETTINGS tmp = *p; + _mbg_swab_mbg_opt_settings( &tmp ); + p = &tmp; + #endif + _mbgdevio_write_var_chk( dh, PCPS_SET_OPT_SETTINGS, + IOCTL_SET_MBG_OPT_SETTINGS, p, + _pcps_ddev_has_opt_flags( dh ) ); + return _mbgdevio_ret_val; + +} // mbg_set_opt_settings + + + +/*HDR*/ +/** + Read an ::IRIG_INFO structure containing the configuration of an IRIG input + plus the possible settings supported by that input. + The macro _pcps_is_irig_rx() or the API call mbg_dev_is_irig_rx() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an ::IRIG_INFO structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_set_irig_rx_settings() + @see mbg_dev_is_irig_rx() + @see mbg_dev_has_irig_tx() + @see mbg_dev_has_irig() + @see \ref group_icode + */ +_MBG_API_ATTR int _MBG_API mbg_get_irig_rx_info( MBG_DEV_HANDLE dh, IRIG_INFO *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_var_chk( dh, PCPS_GET_IRIG_RX_INFO, IOCTL_GET_PCPS_IRIG_RX_INFO, + p, _pcps_ddev_is_irig_rx( dh ) ); + _mbg_swab_irig_info( p ); + return _mbgdevio_ret_val; + +} // mbg_get_irig_rx_info + + + +/*HDR*/ +/** + Write an ::IRIG_SETTINGS structure containing the configuration of an IRIG input. + The macro _pcps_is_irig_rx() or the API call mbg_dev_is_irig_rx() + check whether this call is supported by a specific card. + The ::IRIG_INFO structure should be read first to determine the possible + settings supported by this card's IRIG input. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::IRIG_SETTINGS structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_irig_rx_info() + @see mbg_dev_is_irig_rx() + @see mbg_dev_has_irig_tx() + @see mbg_dev_has_irig() + @see \ref group_icode + */ +_MBG_API_ATTR int _MBG_API mbg_set_irig_rx_settings( MBG_DEV_HANDLE dh, const IRIG_SETTINGS *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + IRIG_SETTINGS tmp = *p; + _mbg_swab_irig_settings( &tmp ); + p = &tmp; + #endif + _mbgdevio_write_var_chk( dh, PCPS_SET_IRIG_RX_SETTINGS, + IOCTL_SET_PCPS_IRIG_RX_SETTINGS, p, + _pcps_ddev_is_irig_rx( dh ) ); + return _mbgdevio_ret_val; + +} // mbg_set_irig_rx_settings + + + +/*HDR*/ +/** + Check if a specific device supports the mbg_get_irig_ctrl_bits() call. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_irig_ctrl_bits() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_irig_ctrl_bits( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_irig_ctrl_bits, IOCTL_DEV_HAS_IRIG_CTRL_BITS, p ); + +} // mbg_dev_has_irig_ctrl_bits + + + +/*HDR*/ +/** + Read a ::MBG_IRIG_CTRL_BITS type which contains the control function + bits of the latest IRIG input frame. Those bits may carry some + well-known information, as in the IEEE1344 code, but may also contain + some customized information, depending on the IRIG frame type and + the configuration of the IRIG generator. So these bits are returned + as-is and must be interpreted by the application. + The macro _pcps_has_irig_ctrl_bits() or the API call mbg_dev_has_irig_ctrl_bits() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_IRIG_CTRL_BITS type to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_irig_ctrl_bits() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_irig_ctrl_bits( MBG_DEV_HANDLE dh, + MBG_IRIG_CTRL_BITS *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_var( dh, PCPS_GET_IRIG_CTRL_BITS, IOCTL_GET_IRIG_CTRL_BITS, p ); + _mbg_swab_irig_ctrl_bits( p ); + return _mbgdevio_ret_val; + +} // mbg_get_irig_ctrl_bits + + + +/*HDR*/ +/** + Check if a specific device supports the mbg_get_raw_irig_data() call. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_raw_irig_data() + @see mbg_get_raw_irig_data_on_sec_change() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_raw_irig_data( MBG_DEV_HANDLE dh, int *p) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_raw_irig_data, IOCTL_DEV_HAS_RAW_IRIG_DATA, p ); + +} // mbg_dev_has_raw_irig_data + + + +/*HDR*/ +/** + Read a ::MBG_RAW_IRIG_DATA type which contains all data + bits of the latest IRIG input frame. + The macro _pcps_has_raw_irig_data() or the API call mbg_dev_has_raw_irig_data() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_RAW_IRIG_DATA type to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_raw_irig_data() + @see mbg_get_raw_irig_data_on_sec_change() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_raw_irig_data( MBG_DEV_HANDLE dh, + MBG_RAW_IRIG_DATA *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_var( dh, PCPS_GET_RAW_IRIG_DATA, IOCTL_GET_RAW_IRIG_DATA, p ); + // No endianess conversion required. + return _mbgdevio_ret_val; + +} // mbg_get_raw_irig_data + + + +/*HDR*/ +/** + Read a ::MBG_RAW_IRIG_DATA type just after a second change which contains all data + bits of the latest IRIG input frame. + The macro _pcps_has_raw_irig_data() or the API call mbg_dev_has_raw_irig_data() + check whether this call is supported by a specific card. + + Note: The mbg_get_time_sec_change() function called by this function is + supported under Windows only, so this function can also only be used under Windows. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_RAW_IRIG_DATA type to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_raw_irig_data() + @see mbg_get_raw_irig_data() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_raw_irig_data_on_sec_change( MBG_DEV_HANDLE dh, + MBG_RAW_IRIG_DATA *p ) +{ + + PCPS_TIME t; + + _mbgdevio_vars(); + + rc = mbg_get_time_sec_change( dh, &t); + + if ( rc == MBG_SUCCESS ) + rc = mbg_get_raw_irig_data( dh, p ); + else + return rc; + + return _mbgdevio_ret_val; + +} // mbg_get_raw_irig_data_on_sec_change + + + +/*HDR*/ +/** + Check if a specific device supports the mbg_get_irig_time() call. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_irig_time() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_irig_time( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_irig_time, IOCTL_DEV_HAS_IRIG_TIME, p ); + +} // mbg_dev_has_irig_time + + + +/*HDR*/ +/** + Read a ::PCPS_IRIG_TIME type which returns the raw IRIG day-of-year number + and time decoded from the latest IRIG input frame. If the configured IRIG code + also contains the year number then the year number is also returned, otherwise + the returned year number is 0xFF. + The macro _pcps_has_irig_time() or the API call mbg_dev_has_irig_time() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_IRIG_TIME type to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_irig_time() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_irig_time( MBG_DEV_HANDLE dh, + PCPS_IRIG_TIME *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_var( dh, PCPS_GIVE_IRIG_TIME, IOCTL_GET_IRIG_TIME, p ); + _mbg_swab_pcps_irig_time( p ); + return _mbgdevio_ret_val; + +} // mbg_get_irig_time + + + +/*HDR*/ +/** + Clear the card's on-board time capture FIFO buffer. + The macro _pcps_can_clr_ucap_buff() or the API call mbg_dev_can_clr_ucap_buff() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_can_clr_ucap_buff() + @see mbg_get_ucap_entries() + @see mbg_get_ucap_event() + */ +_MBG_API_ATTR int _MBG_API mbg_clr_ucap_buff( MBG_DEV_HANDLE dh ) +{ + _mbgdevio_vars(); + _mbgdevio_write_cmd_chk( dh, PCPS_CLR_UCAP_BUFF, IOCTL_PCPS_CLR_UCAP_BUFF, + _pcps_ddev_can_clr_ucap_buff( dh ) ); + return _mbgdevio_ret_val; + +} // mbg_clr_ucap_buff + + + +/*HDR*/ +/** + Read a ::PCPS_UCAP_ENTRIES structure to retrieve the number of saved + user capture events and the maximum capture buffer size. + The macro _pcps_has_ucap() or the API call mbg_dev_has_ucap() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_UCAP_ENTRIES structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_ucap() + @see mbg_get_ucap_entries() + @see mbg_get_ucap_event() + */ +_MBG_API_ATTR int _MBG_API mbg_get_ucap_entries( MBG_DEV_HANDLE dh, PCPS_UCAP_ENTRIES *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_var_chk( dh, PCPS_GIVE_UCAP_ENTRIES, + IOCTL_GET_PCPS_UCAP_ENTRIES, p, + _pcps_ddev_has_ucap( dh ) ); + _mbg_swab_pcps_ucap_entries( p ); + return _mbgdevio_ret_val; + +} // mbg_get_ucap_entries + + + +/*HDR*/ +/** + Retrieve a single time capture event from the on-board FIFO buffer + using a ::PCPS_HR_TIME structure. The oldest entry of the FIFO is retrieved + and then removed from the FIFO. + If no capture event is available in the FIFO buffer then both the seconds + and the fractions of the returned timestamp are 0. + The macro _pcps_has_ucap() or the API call mbg_dev_has_ucap() + check whether this call is supported by a specific card. + + Note: This call is very much faster than the older mbg_get_gps_ucap() + call which is obsolete but still supported for compatibility with + older cards. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_HR_TIME structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_ucap() + @see mbg_get_ucap_entries() + @see mbg_clr_ucap_buff() + */ +_MBG_API_ATTR int _MBG_API mbg_get_ucap_event( MBG_DEV_HANDLE dh, PCPS_HR_TIME *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_var_chk( dh, PCPS_GIVE_UCAP_EVENT, + IOCTL_GET_PCPS_UCAP_EVENT, p, + _pcps_ddev_has_ucap( dh ) ); + _mbg_swab_pcps_hr_time( p ); + return _mbgdevio_ret_val; + +} // mbg_get_ucap_event + + + +/*HDR*/ +/** + Read the card's time zone/daylight saving parameters using the ::TZDL + structure. + The macro _pcps_has_tzdl() or the API call mbg_dev_has_tzdl() + check whether this call is supported by a specific card. + + Note: In spite of the function name this call may also be + supported by non-GPS cards. Other cards may support the mbg_get_tzcode() + or mbg_get_pcps_tzdl() calls instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::TZDL structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_tzdl() + @see mbg_set_gps_tzdl() + @see mbg_get_tzcode() + @see mbg_get_pcps_tzdl() + @see \ref group_tzdl + */ +_MBG_API_ATTR int _MBG_API mbg_get_gps_tzdl( MBG_DEV_HANDLE dh, TZDL *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var( dh, PC_GPS_TZDL, IOCTL_GET_GPS_TZDL, p ); + _mbg_swab_tzdl( p ); + return _mbgdevio_ret_val; + +} // mbg_get_gps_tzdl + + + +/*HDR*/ +/** + Write the card's time zone/daylight saving parameters using the ::TZDL + structure. + The macro _pcps_has_tzdl() or the API call mbg_dev_has_tzdl() + check whether this call is supported by a specific card. + + Note: In spite of the function name this call may also be + supported by non-GPS cards. Other cards may support the mbg_set_tzcode() + or mbg_set_pcps_tzdl() calls instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::TZDL structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_tzdl() + @see mbg_get_gps_tzdl() + @see mbg_set_tzcode() + @see mbg_set_pcps_tzdl() + @see \ref group_tzdl + */ +_MBG_API_ATTR int _MBG_API mbg_set_gps_tzdl( MBG_DEV_HANDLE dh, const TZDL *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + TZDL tmp = *p; + _mbg_swab_tzdl( &tmp ); + p = &tmp; + #endif + _mbgdevio_write_gps_var( dh, PC_GPS_TZDL, IOCTL_SET_GPS_TZDL, p ); + return _mbgdevio_ret_val; + +} // mbg_set_gps_tzdl + + + +/*HDR*/ +/** + Retrieve the software revision of a GPS receiver. + This call is obsolete but still supported for compatibility + with older GPS cards. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + Note: The function mbg_get_gps_receiver_info() should + be used instead, if supported by the card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::SW_REV structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_is_gps() + @see mbg_get_gps_receiver_info() + */ +_MBG_API_ATTR int _MBG_API mbg_get_gps_sw_rev( MBG_DEV_HANDLE dh, SW_REV *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var( dh, PC_GPS_SW_REV, IOCTL_GET_GPS_SW_REV, p ); + _mbg_swab_sw_rev( p ); + return _mbgdevio_ret_val; + +} // mbg_get_gps_sw_rev + + + +/*HDR*/ +/** + Retrieve the status of the battery buffered GPS variables. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + The GPS receiver stays in cold boot mode until all of the + data sets are valid. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::BVAR_STAT structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ +_MBG_API_ATTR int _MBG_API mbg_get_gps_bvar_stat( MBG_DEV_HANDLE dh, BVAR_STAT *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var( dh, PC_GPS_BVAR_STAT, IOCTL_GET_GPS_BVAR_STAT, p ); + _mbg_swab_bvar_stat( p ); + return _mbgdevio_ret_val; + +} // mbg_get_gps_stat + + + +/*HDR*/ +/** + Read the current board time using a ::TTM structure. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + Note: This call is pretty slow, so the mbg_get_hr_time_..() + group of calls should be used preferably. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::TTM structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ +_MBG_API_ATTR int _MBG_API mbg_get_gps_time( MBG_DEV_HANDLE dh, TTM *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var( dh, PC_GPS_TIME, IOCTL_GET_GPS_TIME, p ); + _mbg_swab_ttm( p ); + return _mbgdevio_ret_val; + +} // mbg_get_gps_time + + + +/*HDR*/ +/** + Write a ::TTM structure to a GPS receiver in order to set the + on-board date and time. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::TTM structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ +_MBG_API_ATTR int _MBG_API mbg_set_gps_time( MBG_DEV_HANDLE dh, const TTM *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + TTM tmp = *p; + _mbg_swab_ttm( &tmp ); + p = &tmp; + #endif + _mbgdevio_write_gps_var( dh, PC_GPS_TIME, IOCTL_SET_GPS_TIME, p ); + return _mbgdevio_ret_val; + +} // mbg_set_gps_time + + + +/*HDR*/ +/** + Read a ::PORT_PARM structure to retrieve the configuration + of the device's serial ports. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + Note: This function is obsolete since it is only + supported by a certain class of devices and can handle only + up to 2 ports. The generic function mbg_get_serial_settings() + should be used instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PORT_PARM structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_serial_settings() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_gps_port_parm( MBG_DEV_HANDLE dh, PORT_PARM *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var( dh, PC_GPS_PORT_PARM, IOCTL_GET_GPS_PORT_PARM, p ); + _mbg_swab_port_parm( p ); + return _mbgdevio_ret_val; + +} // mbg_get_gps_port_parm + + + +/*HDR*/ +/** + Write a ::PORT_PARM structure to configure the on-board + serial ports. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + Note: This function is obsolete since it is only + supported by a certain class of devices and can handle only + up to 2 ports. The generic function mbg_save_serial_settings() + should be used instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PORT_PARM structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_save_serial_settings() +*/ +_MBG_API_ATTR int _MBG_API mbg_set_gps_port_parm( MBG_DEV_HANDLE dh, const PORT_PARM *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + PORT_PARM tmp = *p; + _mbg_swab_port_parm( &tmp ); + p = &tmp; + #endif + _mbgdevio_write_gps_var( dh, PC_GPS_PORT_PARM, IOCTL_SET_GPS_PORT_PARM, p ); + return _mbgdevio_ret_val; + +} // mbg_set_gps_port_parm + + + +/*HDR*/ +/** + Read an ::ANT_INFO structure to retrieve status information of the GPS antenna. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + Note: Normally the antenna connection status can also be + determined by evaluation of the ::PCPS_TIME::signal or ::PCPS_HR_TIME::signal + fields. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ANT_INFO structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ +_MBG_API_ATTR int _MBG_API mbg_get_gps_ant_info( MBG_DEV_HANDLE dh, ANT_INFO *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var( dh, PC_GPS_ANT_INFO, IOCTL_GET_GPS_ANT_INFO, p ); + _mbg_swab_ant_info( p ); + return _mbgdevio_ret_val; + +} // mbg_get_gps_ant_info + + + +/*HDR*/ +/** + Read a time capture event from the on-board FIFO buffer using a ::TTM structure. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + Note: This call is pretty slow and has been obsoleted by + mbg_get_ucap_event() which should be used preferably, if supported + by the card. Anyway, this call is still supported for compatibility + with older cards. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::TTM structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_ucap_entries() + @see mbg_get_ucap_event() + @see mbg_clr_ucap_buff() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_gps_ucap( MBG_DEV_HANDLE dh, TTM *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var( dh, PC_GPS_UCAP, IOCTL_GET_GPS_UCAP, p ); + _mbg_swab_ttm( p ); + return _mbgdevio_ret_val; + +} // mbg_get_gps_ucap + + + +/*HDR*/ +/** + Read an ::ENABLE_FLAGS structure reporting whether certain outputs + shall be enabled immediately after the card's power-up, or only + after the card has synchronized to its input signal. + The macro _pcps_has_gps_data() or the API call mbg_dev_has_gps_data() + check whether this call is supported by a specific card. + + Note: Not all of the input signals specified for the + ::ENABLE_FLAGS structure can be modified individually. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::ENABLE_FLAGS structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see ::ENABLE_FLAGS + @see mbg_set_gps_enable_flags() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_gps_enable_flags( MBG_DEV_HANDLE dh, ENABLE_FLAGS *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var( dh, PC_GPS_ENABLE_FLAGS, + IOCTL_GET_GPS_ENABLE_FLAGS, p ); + _mbg_swab_enable_flags( p ); + return _mbgdevio_ret_val; + +} // mbg_get_gps_enable_flags + + + +/*HDR*/ +/** + Write an ENABLE_FLAGS structure to configure whether certain outputs + shall be enabled immediately after the card's power-up, or only + after the card has synchronized to its input signal. + The macro _pcps_has_gps_data() or the API call mbg_dev_has_gps_data() + check whether this call is supported by a specific card. + + Note: Not all of the input signals specified for the + ENABLE_FLAGS structure can be modified individually. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ENABLE_FLAGS structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see ENABLE_FLAGS + @see mbg_get_gps_enable_flags() +*/ +_MBG_API_ATTR int _MBG_API mbg_set_gps_enable_flags( MBG_DEV_HANDLE dh, + const ENABLE_FLAGS *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + ENABLE_FLAGS tmp = *p; + _mbg_swab_enable_flags( &tmp ); + p = &tmp; + #endif + _mbgdevio_write_gps_var( dh, PC_GPS_ENABLE_FLAGS, + IOCTL_SET_GPS_ENABLE_FLAGS, p ); + return _mbgdevio_ret_val; + +} // mbg_set_gps_enable_flags + + + +/*HDR*/ +/** + Read a ::STAT_INFO structure to retrieve the status of the + GPS receiver, including mode of operation and numer of + visible/usable satellites. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::STAT_INFO structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see ::STAT_INFO +*/ +_MBG_API_ATTR int _MBG_API mbg_get_gps_stat_info( MBG_DEV_HANDLE dh, STAT_INFO *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var( dh, PC_GPS_STAT_INFO, IOCTL_GET_GPS_STAT_INFO, p ); + _mbg_swab_stat_info( p ); + return _mbgdevio_ret_val; + +} // mbg_get_gps_stat_info + + + +/*HDR*/ +/** + Sends a ::GPS_CMD to a GPS receiver. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::GPS_CMD + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see ::PC_GPS_CMD_BOOT, ::PC_GPS_CMD_INIT_SYS, ::PC_GPS_CMD_INIT_USER, ::PC_GPS_CMD_INIT_DAC +*/ +_MBG_API_ATTR int _MBG_API mbg_set_gps_cmd( MBG_DEV_HANDLE dh, const GPS_CMD *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + GPS_CMD tmp = *p; + _mbg_swab_gps_cmd( &tmp ); + p = &tmp; + #endif + _mbgdevio_write_gps_var( dh, PC_GPS_CMD, IOCTL_SET_GPS_CMD, p ); + return _mbgdevio_ret_val; + +} // mbg_set_gps_cmd + + +/*HDR*/ +/** + Read the current GPS receiver position using the ::POS structure + which contains different coordinate formats. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device. + @param *p Pointer to a ::POS structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_set_gps_pos_xyz() + @see mbg_set_gps_pos_lla() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_gps_pos( MBG_DEV_HANDLE dh, POS *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var( dh, PC_GPS_POS, IOCTL_GET_GPS_POS, p ); + swap_pos_doubles( p ); + _mbg_swab_pos( p ); + return _mbgdevio_ret_val; + +} // mbg_get_gps_pos + + + +/*HDR*/ +/** + Preset the GPS receiver position using ::XYZ coordinates + (ECEF: WGS84 "Earth Centered, Earth fixed" kartesian coordinates). + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device. + @param p Position in ::XYZ format to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_set_gps_pos_lla() + @see mbg_get_gps_pos() +*/ +_MBG_API_ATTR int _MBG_API mbg_set_gps_pos_xyz( MBG_DEV_HANDLE dh, const XYZ p ) +{ + _mbgdevio_vars(); + XYZ xyz; + int i; + + for ( i = 0; i < N_XYZ; i++ ) + { + xyz[i] = p[i]; + swap_double( &xyz[i] ); + _mbg_swab_double( &xyz[i] ); + } + + _mbgdevio_write_gps_var( dh, PC_GPS_POS_XYZ, IOCTL_SET_GPS_POS_XYZ, xyz ); + return _mbgdevio_ret_val; + +} // mbg_set_gps_pos_xyz + + + +/*HDR*/ +/** + Preset the GPS receiver position using ::LLA coordinates + (longitude, latitude, altitude) + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device. + @param p Position in ::LLA format to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_set_gps_pos_xyz() + @see mbg_get_gps_pos() +*/ +_MBG_API_ATTR int _MBG_API mbg_set_gps_pos_lla( MBG_DEV_HANDLE dh, const LLA p ) +{ + _mbgdevio_vars(); + LLA lla; + int i; + + for ( i = 0; i < N_LLA; i++ ) + { + lla[i] = p[i]; + swap_double( &lla[i] ); + _mbg_swab_double( &lla[i] ); + } + + _mbgdevio_write_gps_var( dh, PC_GPS_POS_LLA, IOCTL_SET_GPS_POS_LLA, lla ); + return _mbgdevio_ret_val; + +} // mbg_set_gps_pos_lla + + + +/*HDR*/ +/** + Read the configured length of the GPS antenna cable (::ANT_CABLE_LEN). + The cable delay is internally compensated by 5ns per meter cable. + The macro _pcps_has_cab_len() or the API call mbg_dev_has_cab_len() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device. + @param *p ::ANT_CABLE_LEN structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_cab_len() + @see mbg_set_gps_ant_cable_len() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_gps_ant_cable_len( MBG_DEV_HANDLE dh, ANT_CABLE_LEN *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var_chk( dh, PC_GPS_ANT_CABLE_LEN, + IOCTL_GET_GPS_ANT_CABLE_LEN, p, + _pcps_ddev_has_cab_len( dh ) ); + _mbg_swab_ant_cable_len( p ); + return _mbgdevio_ret_val; + +} // mbg_get_gps_ant_cable_len + + + +/*HDR*/ +/** + Write the length of the GPS antenna cable (::ANT_CABLE_LEN). + The cable delay is internally compensated by 5ns per meter cable. + The macro _pcps_has_cab_len() or the API call mbg_dev_has_cab_len() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device. + @param *p ::ANT_CABLE_LEN structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_cab_len() + @see mbg_get_gps_ant_cable_len() +*/ +_MBG_API_ATTR int _MBG_API mbg_set_gps_ant_cable_len( MBG_DEV_HANDLE dh, + const ANT_CABLE_LEN *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + ANT_CABLE_LEN tmp = *p; + _mbg_swab_ant_cable_len( &tmp ); + p = &tmp; + #endif + _mbgdevio_write_gps_var_chk( dh, PC_GPS_ANT_CABLE_LEN, + IOCTL_SET_GPS_ANT_CABLE_LEN, p, + _pcps_ddev_has_cab_len( dh ) ); + return _mbgdevio_ret_val; + +} // mbg_set_gps_ant_cable_len + + + +/*HDR*/ +/** + Read a ::RECEIVER_INFO structure from a card. + The macro _pcps_has_receiver_info() or the API call mbg_dev_has_receiver_info() + check whether this call is supported by a specific card. + + Note: Applications should call mbg_setup_receiver_info() + preferably, which also sets up a basic ::RECEIVER_INFO structure + for card which don't provide that structure by themselves. + + @param dh Valid handle to a Meinberg device. + @param *p Pointer to a ::RECEIVER_INFO structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_setup_receiver_info() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_gps_receiver_info( MBG_DEV_HANDLE dh, RECEIVER_INFO *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var_chk( dh, PC_GPS_RECEIVER_INFO, + IOCTL_GET_GPS_RECEIVER_INFO, p, + _pcps_ddev_has_receiver_info( dh ) ); + + _mbg_swab_receiver_info( p ); + return _mbgdevio_ret_val; + +} // mbg_get_gps_receiver_info + + + +#if !MBGDEVIO_SIMPLE + +static /*HDR*/ +/* (Intentionally excluded from Doxygen) + Read a ::STR_TYPE_INFO_IDX array of supported string types. + The function mbg_setup_receiver_info() must have been called before, + and the returned ::RECEIVER_INFO structure passed to this function. + + Note: The function mbg_get_serial_settings() should be used preferably + to get retrieve the cuurrent port settings and configuration options. + + @param dh Valid handle to a Meinberg device. + @param stii Pointer to a an array of string type information to be filled up + @param *p_ri Pointer to a ::RECEIVER_INFO structure returned by mbg_setup_receiver_info() + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_setup_receiver_info() + @see mbg_get_gps_all_port_info() + @see mbg_get_serial_settings() +*/ +int _MBG_API mbg_get_gps_all_str_type_info( MBG_DEV_HANDLE dh, + STR_TYPE_INFO_IDX stii[], + const RECEIVER_INFO *p_ri ) +{ + _mbgdevio_vars(); + + #if _MBG_SUPP_VAR_ACC_SIZE + _mbgdevio_read_gps_chk( dh, PC_GPS_ALL_STR_TYPE_INFO, + IOCTL_GET_GPS_ALL_STR_TYPE_INFO, stii, + p_ri->n_str_type * sizeof( stii[0] ), + _pcps_ddev_has_receiver_info( dh ) ); + #else + // We check the model_code to see whether the receiver info + // has been read from a device which really supports it, or + // a dummy structure has been setup. + if ( p_ri && ( p_ri->model_code != GPS_MODEL_UNKNOWN ) ) + _mbgdevio_gen_read_gps( dh, PC_GPS_ALL_STR_TYPE_INFO, stii, + p_ri->n_str_type * sizeof( stii[0] ) ); + else + return _mbg_err_to_os( MBG_ERR_NOT_SUPP_BY_DEV ); + #endif + + #if defined( MBG_ARCH_BIG_ENDIAN ) + if ( rc == MBG_SUCCESS ) + { + int i; + for ( i = 0; i < p_ri->n_str_type; i++ ) + { + STR_TYPE_INFO_IDX *p = &stii[i]; + _mbg_swab_str_type_info_idx( p ); + } + } + #endif + + return _mbgdevio_ret_val; + +} // mbg_get_gps_all_str_type_info + + + +static /*HDR*/ +/* (Intentionally excluded from Doxygen) + Read a ::PORT_INFO_IDX array of supported serial port configurations. + The function mbg_setup_receiver_info() must have been called before, + and the returned ::RECEIVER_INFO structure passed to this function. + + Note: The function mbg_get_serial_settings() should be used preferably + to get retrieve the cuurrent port settings and configuration options. + + @param dh Valid handle to a Meinberg device. + @param pii Pointer to a an array of port configuration information to be filled up + @param *p_ri Pointer to a ::RECEIVER_INFO structure returned by mbg_setup_receiver_info() + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_setup_receiver_info() + @see mbg_get_gps_all_str_type_info() + @see mbg_get_serial_settings() +*/ +int _MBG_API mbg_get_gps_all_port_info( MBG_DEV_HANDLE dh, + PORT_INFO_IDX pii[], + const RECEIVER_INFO *p_ri ) +{ + _mbgdevio_vars(); + + #if _MBG_SUPP_VAR_ACC_SIZE + _mbgdevio_read_gps_chk( dh, PC_GPS_ALL_PORT_INFO, + IOCTL_GET_GPS_ALL_PORT_INFO, pii, + p_ri->n_com_ports * sizeof( pii[0] ), + _pcps_ddev_has_receiver_info( dh ) ); + #else + // We check the model_code to see whether the receiver info + // has been read from a device which really supports it, or + // a dummy structure has been setup. + if ( p_ri && ( p_ri->model_code != GPS_MODEL_UNKNOWN ) ) + _mbgdevio_gen_read_gps( dh, PC_GPS_ALL_PORT_INFO, pii, + p_ri->n_com_ports * sizeof( pii[0] ) ); + else + return _mbg_err_to_os( MBG_ERR_NOT_SUPP_BY_DEV ); + #endif + + #if defined( MBG_ARCH_BIG_ENDIAN ) + if ( rc == MBG_SUCCESS ) + { + int i; + for ( i = 0; i < p_ri->n_com_ports; i++ ) + { + PORT_INFO_IDX *p = &pii[i]; + _mbg_swab_port_info_idx( p ); + } + } + #endif + + return _mbgdevio_ret_val; + +} // mbg_get_gps_all_port_info + + + +/*HDR*/ +/** + Write the configuration for a single serial port using the ::PORT_SETTINGS_IDX + structure which contains both the ::PORT_SETTINGS and the port index value. + Except for the parameter types, this call is equivalent to mbg_set_gps_port_settings(). + The macro _pcps_has_receiver_info() or the API call mbg_dev_has_receiver_info() + check whether this call is supported by a specific card. + + Note: The function mbg_save_serial_settings() should be used preferably + to write new port configuration to the board. + + @param dh Valid handle to a Meinberg device. + @param *p Pointer to a ::PORT_SETTINGS_IDX structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_save_serial_settings() + @see mbg_set_gps_port_settings() + @see mbg_dev_has_receiver_info() +*/ +_MBG_API_ATTR int _MBG_API mbg_set_gps_port_settings_idx( MBG_DEV_HANDLE dh, + const PORT_SETTINGS_IDX *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + PORT_SETTINGS_IDX tmp = *p; + _mbg_swab_port_settings_idx( &tmp ); + p = &tmp; + #endif + _mbgdevio_write_gps_var_chk( dh, PC_GPS_PORT_SETTINGS_IDX, + IOCTL_SET_GPS_PORT_SETTINGS_IDX, p, + _pcps_ddev_has_receiver_info( dh ) ); + return _mbgdevio_ret_val; + +} // mbg_set_gps_port_settings_idx + + + +/*HDR*/ +/** + Write the configuration for a single serial port using the ::PORT_SETTINGS + structure plus the port index. + Except for the parameter types, this call is equivalent to mbg_set_gps_port_settings_idx(). + The macro _pcps_has_receiver_info() or the API call mbg_dev_has_receiver_info() + check whether this call is supported by a specific card. + + Note: The function mbg_save_serial_settings() should be used preferably + to write new port configuration to the board. + + @param dh Valid handle to a Meinberg device. + @param *p Pointer to a ::PORT_SETTINGS structure to be filled up + @param idx Index of the serial port to be configured (starting from 0 ). + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_save_serial_settings() + @see mbg_set_gps_port_settings_idx() + @see mbg_dev_has_receiver_info() +*/ +_MBG_API_ATTR int _MBG_API mbg_set_gps_port_settings( MBG_DEV_HANDLE dh, + const PORT_SETTINGS *p, int idx ) +{ + PORT_SETTINGS_IDX psi = { 0 }; + + psi.idx = idx; + psi.port_settings = *p; + _mbg_swab_port_settings_idx( &psi ); + + return mbg_set_gps_port_settings_idx( dh, &psi ); + +} // mbg_set_gps_port_settings + +#endif // !MBGDEVIO_SIMPLE + + + +/*HDR*/ +/** + Set up a ::RECEIVER_INFO structure for a device. + If the device supports the ::RECEIVER_INFO structure then the structure + is read from the device, otherwise a structure is set up using + default values depending on the device type. + The function mbg_get_device_info() must have been called before, + and the returned PCPS_DEV structure passed to this function. + + @param dh Valid handle to a Meinberg device. + @param *pdev Pointer to a ::PCPS_DEV structure returned by mbg_get_device_info() + @param *p Pointer to a ::RECEIVER_INFO structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_device_info() + @see mbg_dev_has_receiver_info() +*/ +_MBG_API_ATTR int _MBG_API mbg_setup_receiver_info( MBG_DEV_HANDLE dh, + const PCPS_DEV *pdev, + RECEIVER_INFO *p ) +{ + // If the clock supports the receiver_info structure then + // read it from the clock, otherwise set up some default + // values depending on the clock type. + if ( _pcps_has_receiver_info( pdev ) ) + { + int rc = mbg_get_gps_receiver_info( dh, p ); + + if ( rc != MBG_SUCCESS ) + return rc; + + goto check; + } + + if ( _pcps_is_gps( pdev ) ) + { // keep braces due to the macro call! + _setup_default_receiver_info_gps( p ); + } + else + { // keep braces due to the macro call! + _setup_default_receiver_info_dcf( p, pdev ); + } + +check: + // Make sure this program supports at least as many ports as + // the current clock device. + if ( p->n_com_ports > MAX_PARM_PORT ) + return _mbg_err_to_os( MBG_ERR_N_COM_EXCEEDS_SUPP ); + + // Make sure this program supports at least as many string types + // as the current clock device. + if ( p->n_str_type > MAX_PARM_STR_TYPE ) + return _mbg_err_to_os( MBG_ERR_N_STR_EXCEEDS_SUPP ); + + + return MBG_SUCCESS; + +} // mbg_setup_receiver_info + + + +#if !MBGDEVIO_SIMPLE + +// The functions below can conditionally be excluded from build +// for simple applications which don't do complex card configuration. +// This reduces the number of modules needed to be linked to the +// application. + +/*HDR*/ +/** + Read all serial port settings and supported configuration parameters. + + The functions mbg_get_device_info() and mbg_setup_receiver_info() + must have been called before, and the returned ::PCPS_DEV and + ::RECEIVER_INFO structures must be passed to this function. + + The complementary function mbg_save_serial_settings() should be used + to write the modified serial port configuration back to the board. + + @param dh Valid handle to a Meinberg device. + @param *pdev Pointer to a ::PCPS_DEV structure. + @param *pcfg Pointer to a ::RECEIVER_PORT_CFG structure to be filled up. + @param *p_ri Pointer to a ::RECEIVER_INFO structure. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_device_info() + @see mbg_setup_receiver_info() + @see mbg_save_serial_settings() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_serial_settings( MBG_DEV_HANDLE dh, + const PCPS_DEV *pdev, + RECEIVER_PORT_CFG *pcfg, + const RECEIVER_INFO *p_ri ) +{ + int rc; + int i; + + memset( pcfg, 0, sizeof( *pcfg ) ); + + if ( _pcps_has_receiver_info( pdev ) ) + { + rc = mbg_get_gps_all_port_info( dh, pcfg->pii, p_ri ); + if ( rc != MBG_SUCCESS ) + goto error; + + rc = mbg_get_gps_all_str_type_info( dh, pcfg->stii, p_ri ); + if ( rc != MBG_SUCCESS ) + goto error; + } + else + { + if ( _pcps_is_gps( pdev ) ) + { + rc = mbg_get_gps_port_parm( dh, &pcfg->tmp_pp ); + if ( rc != MBG_SUCCESS ) + goto error; + + for ( i = 0; i < p_ri->n_com_ports; i++ ) + { + PORT_INFO_IDX *p_pii = &pcfg->pii[i]; + PORT_INFO *p_pi = &p_pii->port_info; + + p_pii->idx = i; + port_settings_from_port_parm( &p_pi->port_settings, + i, &pcfg->tmp_pp, 1 ); + + p_pi->supp_baud_rates = DEFAULT_GPS_BAUD_RATES_C166; + p_pi->supp_framings = DEFAULT_GPS_FRAMINGS_C166; + p_pi->supp_str_types = DEFAULT_SUPP_STR_TYPES_GPS; + } + } + else + if ( _pcps_has_serial ( pdev ) ) // Not all non-GPS clocks have a serial port! + { + PCPS_SERIAL ser_code; + + rc = mbg_get_serial( dh, &ser_code ); + if ( rc != MBG_SUCCESS ) + goto error; + + + port_info_from_pcps_serial( pcfg->pii, ser_code, + _pcps_has_serial_hs( pdev ) ? + DEFAULT_BAUD_RATES_DCF_HS : + DEFAULT_BAUD_RATES_DCF + ); + } + + for ( i = 0; i < p_ri->n_str_type; i++ ) + { + STR_TYPE_INFO_IDX *stip = &pcfg->stii[i]; + stip->idx = i; + stip->str_type_info = default_str_type_info[i]; + } + } + + return MBG_SUCCESS; + + +error: + return rc; + +} // mbg_get_serial_settings + + + +/*HDR*/ +/** + Write the configuration settings for a single serial port to the board. + + Modifications to the serial port configuration should be made only + after mbg_get_serial_settings() had been called to read all serial port + settings and supported configuration parameters. + This function has finally to be called once for every serial port + the configuration of which has been modified. + + As also required by mbg_get_serial_settings(), the functions + mbg_get_device_info() and mbg_setup_receiver_info() must have been + called before, and the returned ::PCPS_DEV and ::RECEIVER_INFO structures + must be passed to this function. + + @param dh Valid handle to a Meinberg device + @param *pdev Pointer to a ::PCPS_DEV structure + @param *pcfg Pointer to a ::RECEIVER_PORT_CFG structure + @param port_num Index of the ::serial port to be saved + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_serial_settings() + @see mbg_get_device_info() + @see mbg_setup_receiver_info() +*/ +_MBG_API_ATTR int _MBG_API mbg_save_serial_settings( MBG_DEV_HANDLE dh, + const PCPS_DEV *pdev, + RECEIVER_PORT_CFG *pcfg, + int port_num ) +{ + int rc; + + if ( _pcps_has_receiver_info( pdev ) ) + { + rc = mbg_set_gps_port_settings( dh, &pcfg->pii[port_num].port_info.port_settings, port_num ); + } + else + { + if ( _pcps_is_gps( pdev ) ) + { + port_parm_from_port_settings( &pcfg->tmp_pp, port_num, + &pcfg->pii[port_num].port_info.port_settings, 1 ); + + rc = mbg_set_gps_port_parm( dh, &pcfg->tmp_pp ); + } + else + { + PCPS_SERIAL ser_code; + + pcps_serial_from_port_info( &ser_code, pcfg->pii ); + + rc = mbg_set_serial( dh, &ser_code ); + } + } + + return rc; + +} // mbg_save_serial_settings + +#endif // !MBGDEVIO_SIMPLE + + + +/*HDR*/ +/** + Read the version code of the on-board PCI/PCIe interface ASIC. + The macro _pcps_has_asic_version() or the API call mbg_dev_has_asic_version() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCI_ASIC_VERSION type to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function + + @see mbg_dev_has_asic_version() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_asic_version( MBG_DEV_HANDLE dh, PCI_ASIC_VERSION *p ) +{ + + #if defined( _MBGIOCTL_H ) + _mbgdevio_vars(); + _mbgdevio_read_var( dh, -1, IOCTL_GET_PCI_ASIC_VERSION, p ); + return _mbgdevio_ret_val; + #else + if ( !_pcps_ddev_has_asic_version( dh ) ) + return _mbg_err_to_os( MBG_ERR_NOT_SUPP_BY_DEV ); + + *p = _mbg_inp32_to_cpu( dh, _pcps_ddev_io_base_mapped( dh, 0 ) + + offsetof( PCI_ASIC, raw_version ) ); + + return MBG_SUCCESS; + #endif + +} // mbg_get_asic_version + + + +/*HDR*/ +/** + Read the features of the on-board PCI/PCIe interface ASIC. + The macro _pcps_has_asic_features() or the API call mbg_dev_has_asic_features() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device. + @param *p Pointer to a ::PCI_ASIC_FEATURES type to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_asic_features() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_asic_features( MBG_DEV_HANDLE dh, + PCI_ASIC_FEATURES *p ) +{ + + #if defined( _MBGIOCTL_H ) + _mbgdevio_vars(); + _mbgdevio_read_var( dh, -1, IOCTL_GET_PCI_ASIC_FEATURES, p ); + return _mbgdevio_ret_val; + #else + if ( !_pcps_ddev_has_asic_features( dh ) ) + { + *p = 0; + return _mbg_err_to_os( MBG_ERR_NOT_SUPP_BY_DEV ); + } + + *p = _mbg_inp32_to_cpu( dh, _pcps_ddev_io_base_mapped( dh, 0 ) + + offsetof( PCI_ASIC, features ) ); + + return MBG_SUCCESS; + #endif + +} // mbg_get_asic_features + + + +/*HDR*/ +/** + Check if a specific device supports configurable time scales. + + By default the cards return UTC and/or local time. However, some cards + can be configured to return pure GPS time or TAI instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_time_scale_info() + @see mbg_set_time_scale_settings() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_time_scale( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_time_scale, IOCTL_DEV_HAS_GPS_TIME_SCALE, p ); + +} // mbg_dev_has_time_scale + + + +/*HDR*/ +/** + Read a ::MBG_TIME_SCALE_INFO structure from a card telling which time scales + are supported by a card, and the current settings of the card. + + The macro _pcps_has_time_scale() or the API call mbg_dev_has_time_scale() + check whether this call is supported by a specific card. + See also the notes for mbg_dev_has_time_scale(). + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_TIME_SCALE_INFO structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_set_time_scale_settings() + @see mbg_dev_has_time_scale() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_time_scale_info( MBG_DEV_HANDLE dh, MBG_TIME_SCALE_INFO *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var_chk( dh, PC_GPS_TIME_SCALE, + IOCTL_GET_GPS_TIME_SCALE_INFO, p, + _pcps_ddev_has_time_scale( dh ) ); + _mbg_swab_mbg_time_scale_info( p ); + return _mbgdevio_ret_val; + +} // mbg_get_time_scale_info + + + +/*HDR*/ +/** + Write a ::MBG_TIME_SCALE_SETTINGS structure to a card which determines + which time scale shall be represented by time stamps read from the card. + + The macro _pcps_has_time_scale() or the API call mbg_dev_has_time_scale() + check whether this call is supported by a specific card. + See also the notes for mbg_dev_has_time_scale(). + + The function mbg_get_time_scale_info() should have been called before + in order to determine which time scales are supported by the card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_TIME_SCALE_SETTINGS structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_time_scale_info() + @see mbg_dev_has_time_scale() +*/ +_MBG_API_ATTR int _MBG_API mbg_set_time_scale_settings( MBG_DEV_HANDLE dh, MBG_TIME_SCALE_SETTINGS *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + MBG_TIME_SCALE_SETTINGS tmp = *p; + _mbg_swab_mbg_time_scale_settings( &tmp ); + p = &tmp; + #endif + _mbgdevio_write_gps_var_chk( dh, PC_GPS_TIME_SCALE, + IOCTL_SET_GPS_TIME_SCALE_SETTINGS, p, + _pcps_ddev_has_time_scale( dh ) ); + return _mbgdevio_ret_val; + +} // mbg_set_time_scale_settings + + + +/*HDR*/ +/** + Check if a specific device supports reading/writing a GPS UTC parameter + set via the PC bus (reading/writing these parameters via the serial port + is supported by all GPS devices). + + The UTC parameters are normally received from the satellites' broadcasts + and contain the current time offset between GPT time and UTC, plus information + on a pending leap second. + + It may be useful to overwrite them to do some tests, or for applications + where a card is freewheeling. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_utc_parm() + @see mbg_set_utc_parm() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_utc_parm( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_utc_parm, IOCTL_DEV_HAS_GPS_UTC_PARM, p ); + +} // mbg_dev_has_utc_parm + + + +/*HDR*/ +/** + Read a ::UTC structure from a card. + + The macro _pcps_has_utc_parm() or the API call mbg_dev_has_utc_parm() + check whether this call is supported by a specific card. + See also the notes for mbg_dev_has_utc_parm(). + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::UTC structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_utc_parm() + @see mbg_set_utc_parm() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_utc_parm( MBG_DEV_HANDLE dh, UTC *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var_chk( dh, PC_GPS_UTC, + IOCTL_GET_GPS_UTC_PARM, p, + _pcps_ddev_has_utc_parm( dh ) ); + _mbg_swab_utc_parm( p ); + swap_double( &p->A0 ); + swap_double( &p->A1 ); + return _mbgdevio_ret_val; + +} // mbg_get_utc_parm + + + +/*HDR*/ +/** + Write a ::UTC structure to a card. + + This should only be done for testing, or if a card is operated in + freewheeling mode. If the card receives any satellites the settings + written to the board are overwritten by the parameters broadcasted + by the satellites. + + The macro _pcps_has_utc_parm() or the API call mbg_dev_has_utc_parm() + check whether this call is supported by a specific card. + See also the notes for mbg_dev_has_utc_parm(). + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a valid ::UTC structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_utc_parm() + @see mbg_get_utc_parm() +*/ +_MBG_API_ATTR int _MBG_API mbg_set_utc_parm( MBG_DEV_HANDLE dh, UTC *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + UTC tmp = *p; + _mbg_swab_utc_parm( &tmp ); + p = &tmp; + #endif + swap_double( &p->A0 ); + swap_double( &p->A1 ); + _mbgdevio_write_gps_var_chk( dh, PC_GPS_UTC, + IOCTL_SET_GPS_UTC_PARM, p, + _pcps_ddev_has_utc_parm( dh ) ); + return _mbgdevio_ret_val; + +} // mbg_set_utc_parm + + + +/*HDR*/ +/** + Read a ::PCPS_TIME_CYCLES structure that contains a ::PCPS_TIME structure + and a PC cycle counter value which can be used to compensate the latency + of the call, i.e. the program execution time until the time stamp has actually + been read from the board. + + This call is supported for any card, similar to mbg_get_time(). However, + the mbg_get_hr_time_cyles() call should be used preferably if supported by + the specific card since that call provides much better accuracy than this one. + + The cycle counter value corresponds to a value returned by QueryPerformanceCounter() + under Windows, and get_cycles() under Linux. On other operating systems the returned + cycles value is always 0. + + Applications should first pick up their own cycle counter value and then call + this function. The difference of the cycle counter values corresponds to the + latency of the call in units of the cycle counter clock frequency, e.g as reported + by QueryPerformanceFrequency() under Windows. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TIME_CYCLES structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_hr_time_cycles() + @see mbg_get_hr_time_comp() + @see mbg_get_hr_time() + @see mbg_get_time() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_time_cycles( MBG_DEV_HANDLE dh, PCPS_TIME_CYCLES *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_var( dh, PCPS_GIVE_TIME, IOCTL_GET_PCPS_TIME_CYCLES, p ); + // No endianess conversion required. + #if !defined( _MBGIOCTL_H ) + // only if not using IOCTLs + // for PCPS_TIME, read stamp AFTER the call + p->cycles = 0; //##++ + #endif + return _mbgdevio_ret_val; + +} // mbg_get_time_cycles + + + +/*HDR*/ +/** + Read a ::PCPS_HR_TIME_CYCLES structure that contains a ::PCPS_HR_TIME structure + and a PC cycle counter value which can be used to compensate the latency + of the call, i.e. the program execution time until the time stamp has actually + been read from the board. + + The macro _pcps_has_hr_time() or the API call mbg_dev_has_hr_time() + check whether this call is supported by a specific card. + + The cycle counter value corresponds to a value returned by QueryPerformanceCounter() + under Windows, and get_cycles() under Linux. On other operating systems the returned + cycles value is always 0. + + Applications should first pick up their own cycle counter value and then call + this function. The difference of the cycle counter values corresponds to the + latency of the call in units of the cycle counter clock frequency, e.g as reported + by QueryPerformanceFrequency() under Windows. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_HR_TIME_CYCLES structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_hr_time_comp() + @see mbg_get_hr_time() + @see mbg_get_time_cycles() + @see mbg_get_time() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_hr_time_cycles( MBG_DEV_HANDLE dh, + PCPS_HR_TIME_CYCLES *p ) +{ + _mbgdevio_vars(); + #if !defined( _MBGIOCTL_H ) + // only if not using IOCTLs + // for PCPS_HR_TIME, read stamp BEFORE the call + p->cycles = 0; //##++ + #endif + _mbgdevio_read_var_chk( dh, PCPS_GIVE_HR_TIME, + IOCTL_GET_PCPS_HR_TIME_CYCLES, + p, _pcps_ddev_has_hr_time( dh ) ); + _mbg_swab_pcps_hr_time_cycles( p ); + return _mbgdevio_ret_val; + +} // mbg_get_hr_time_cycles + + + +/*HDR*/ +/** + Read a ::PCPS_HR_TIME structure plus cycle counter value, and correct the + time stamp for the latency of the call as described for mbg_get_hr_time_cycles(), + then return the compensated time stamp and optionally the latency. + + The macro _pcps_has_hr_time() or the API call mbg_dev_has_hr_time() + check whether this call is supported by a specific card. + + The cycle counter value corresponds to a value returned by QueryPerformanceCounter() + under Windows, and get_cycles() under Linux. On other operating systems the returned + cycles value is always 0. + + Applications should first pick up their own cycle counter value and then call + this function. The difference of the cycle counter values corresponds to the + latency of the call in units of the cycle counter clock frequency, e.g as reported + by QueryPerformanceFrequency() under Windows. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_HR_TIME structure to be filled up + @param *hns_latency Optional pointer to an int32_t value to return + the latency in 100ns units. Pass NULL if not used. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_hr_time_comp() + @see mbg_get_hr_time() + @see mbg_get_time_cycles() + @see mbg_get_time() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_hr_time_comp( MBG_DEV_HANDLE dh, PCPS_HR_TIME *p, + int32_t *hns_latency ) +{ + PCPS_HR_TIME_CYCLES htc; + MBG_PC_CYCLES cyc_now; + int rc; + + // First get current time stamp counter value, then read + // a high resolution time stamp from the board, plus the + // associated time stamp counter value. + mbg_get_pc_cycles( &cyc_now ); + + rc = mbg_get_hr_time_cycles( dh, &htc ); + + if ( rc == MBG_SUCCESS ) + { + mbg_init_pc_cycles_frequency( dh, &pc_cycles_frequency ); + rc = mbg_comp_hr_latency( &htc.t.tstamp, &htc.cycles, &cyc_now, &pc_cycles_frequency, hns_latency ); + *p = htc.t; + } + + return rc; + +} // mbg_get_hr_time_comp + + + +/*HDR*/ +/** + Read an ::IRIG_INFO structure containing the configuration of an IRIG output + plus the possible settings supported by that output. + The macro _pcps_has_irig_tx() or the API call mbg_dev_has_irig_tx() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an ::IRIG_INFO structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_set_irig_tx_settings() + @see mbg_dev_has_irig_tx() + @see mbg_dev_is_irig_rx() + @see mbg_dev_has_irig() + @see \ref group_icode +*/ +_MBG_API_ATTR int _MBG_API mbg_get_irig_tx_info( MBG_DEV_HANDLE dh, IRIG_INFO *p ) +{ + _mbgdevio_vars(); + + #if !defined( _MBGIOCTL_H ) + // This is a workaround for GPS169PCIs with early + // firmware versions. See RCS log for details. + uint8_t pcps_cmd = PCPS_GET_IRIG_TX_INFO; + + if ( _pcps_ddev_requires_irig_workaround( dh ) ) + pcps_cmd = PCPS_GET_IRIG_RX_INFO; + + #define _PCPS_CMD pcps_cmd + #else + #define _PCPS_CMD PCPS_GET_IRIG_TX_INFO + #endif + + _mbgdevio_read_var_chk( dh, _PCPS_CMD, IOCTL_GET_PCPS_IRIG_TX_INFO, + p, _pcps_ddev_has_irig_tx( dh ) ); + #undef _PCPS_CMD + + _mbg_swab_irig_info( p ); + return _mbgdevio_ret_val; + +} // mbg_get_irig_tx_info + + + +/*HDR*/ +/** + Write an ::IRIG_SETTINGS structure containing the configuration of an IRIG output. + The macro _pcps_has_irig_tx() or the API call mbg_dev_has_irig_tx() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an ::IRIG_INFO structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_irig_tx_info() + @see mbg_dev_has_irig_tx() + @see mbg_dev_is_irig_rx() + @see mbg_dev_has_irig() + @see \ref group_icode +*/ +_MBG_API_ATTR int _MBG_API mbg_set_irig_tx_settings( MBG_DEV_HANDLE dh, const IRIG_SETTINGS *p ) +{ + _mbgdevio_vars(); + #if !defined( _MBGIOCTL_H ) + uint8_t pcps_cmd; + #endif + + #if defined( MBG_ARCH_BIG_ENDIAN ) + IRIG_SETTINGS tmp = *p; + _mbg_swab_irig_settings( &tmp ); + p = &tmp; + #endif + + #if !defined( _MBGIOCTL_H ) + // This is a workaround for GPS169PCIs with early + // firmware versions. See RCS log for details. + pcps_cmd = PCPS_SET_IRIG_TX_SETTINGS; + + if ( _pcps_ddev_requires_irig_workaround( dh ) ) + pcps_cmd = PCPS_SET_IRIG_RX_SETTINGS; + + #define _PCPS_CMD pcps_cmd + #else + #define _PCPS_CMD PCPS_SET_IRIG_TX_SETTINGS + #endif + + _mbgdevio_write_var_chk( dh, _PCPS_CMD, IOCTL_SET_PCPS_IRIG_TX_SETTINGS, + p, _pcps_ddev_has_irig_tx( dh ) ); + #undef _PCPS_CMD + + return _mbgdevio_ret_val; + +} // mbg_set_irig_tx_settings + + + +/*HDR*/ +/** + Read a ::SYNTH structure containing the configuration of an optional + on-board programmable frequency synthesizer. + The macro _pcps_has_synth() or the API call mbg_dev_has_synth() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::SYNTH structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_synth() + @see mbg_set_synth() + @see mbg_get_synth_state() + @see \ref group_synth +*/ +_MBG_API_ATTR int _MBG_API mbg_get_synth( MBG_DEV_HANDLE dh, SYNTH *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_var_chk( dh, PCPS_GET_SYNTH, IOCTL_GET_SYNTH, + p, _pcps_ddev_has_synth( dh ) ); + _mbg_swab_synth( p ); + return _mbgdevio_ret_val; + +} // mbg_get_synth + + + +/*HDR*/ +/** + Write a ::SYNTH structure containing the configuration of an optional + on-board programmable frequency synthesizer. + The macro _pcps_has_synth() or the API call mbg_dev_has_synth() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::SYNTH structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_synth() + @see mbg_get_synth() + @see mbg_get_synth_state() + @see \ref group_synth +*/ +_MBG_API_ATTR int _MBG_API mbg_set_synth( MBG_DEV_HANDLE dh, const SYNTH *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + SYNTH tmp = *p; + _mbg_swab_synth( &tmp ); + p = &tmp; + #endif + _mbgdevio_write_var_chk( dh, PCPS_SET_SYNTH, IOCTL_SET_SYNTH, + p, _pcps_ddev_has_synth( dh ) ); + return _mbgdevio_ret_val; + +} // mbg_set_synth + + + +/*HDR*/ +/** + Read a ::SYNTH_STATE structure reporting the current state + of an optional on-board programmable frequency synthesizer. + The macro _pcps_has_synth() or the API call mbg_dev_has_synth() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::SYNTH_STATE structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_synth() + @see mbg_get_synth() + @see mbg_set_synth() + @see \ref group_synth +*/ +_MBG_API_ATTR int _MBG_API mbg_get_synth_state( MBG_DEV_HANDLE dh, SYNTH_STATE *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_var_chk( dh, PCPS_GET_SYNTH_STATE, IOCTL_GET_SYNTH_STATE, + p, _pcps_ddev_has_synth( dh ) ); + _mbg_swab_synth_state( p ); + return _mbgdevio_ret_val; + +} // mbg_get_synth_state + + + +/*HDR*/ +/** + Check if a specific device supports the mbg_get_fast_hr_timestamp_...() calls. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_fast_hr_timestamp_cycles() + @see mbg_get_fast_hr_timestamp_comp() + @see mbg_get_fast_hr_timestamp() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_fast_hr_timestamp( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_fast_hr_timestamp, IOCTL_HAS_FAST_HR_TIMESTAMP, p ); + +} // mbg_dev_has_fast_hr_timestamp + + + +/*HDR*/ +/** + Read a high resolution ::PCPS_TIME_STAMP_CYCLES structure via memory mapped access. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TIME_STAMP_CYCLES structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_fast_hr_timestamp() + @see mbg_get_fast_hr_timestamp_comp() + @see mbg_get_fast_hr_timestamp() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_fast_hr_timestamp_cycles( MBG_DEV_HANDLE dh, + PCPS_TIME_STAMP_CYCLES *p ) +{ + #if defined( _MBGIOCTL_H ) + _mbgdevio_vars(); + _mbgdevio_read_var( dh, -1, IOCTL_GET_FAST_HR_TIMESTAMP_CYCLES, p ); + // native endianess, no need to swap bytes + return _mbgdevio_ret_val; + #else + // This is currently not supported by the target environment. + return _mbg_err_to_os( MBG_ERR_NOT_SUPP_ON_OS ); + #endif +} // mbg_get_fast_hr_timestamp_cycles + + + +/*HDR*/ +/** + Read a high resolution ::PCPS_TIME_STAMP via memory mapped access, + and compensate the latency of the time stamp before it is returned. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TIME_STAMP structure to be filled up + @param *hns_latency Optionally receive the latency in hectonanoseconds + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_fast_hr_timestamp() + @see mbg_get_fast_hr_timestamp_cycles() + @see mbg_get_fast_hr_timestamp() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_fast_hr_timestamp_comp( MBG_DEV_HANDLE dh, + PCPS_TIME_STAMP *p, + int32_t *hns_latency ) +{ + PCPS_TIME_STAMP_CYCLES tc; + MBG_PC_CYCLES cyc_now; + int rc; + + // First get current time stamp counter value, then read + // a high resolution time stamp from the board, plus the + // associated time stamp counter value. + mbg_get_pc_cycles( &cyc_now ); + + rc = mbg_get_fast_hr_timestamp_cycles( dh, &tc ); + + if ( rc == MBG_SUCCESS ) + { + mbg_init_pc_cycles_frequency( dh, &pc_cycles_frequency ); + rc = mbg_comp_hr_latency( &tc.tstamp, &tc.cycles, &cyc_now, &pc_cycles_frequency, hns_latency ); + *p = tc.tstamp; + } + + return rc; + +} // mbg_get_fast_hr_timestamp_comp + + + +/*HDR*/ +/** + Read a high resolution ::PCPS_TIME_STAMP structure via memory mapped access. + + This function does not return or evaluate a cycles count, so the latency + of the call can not be determined. However, depending on the timer hardware + used as cycles counter it may take quite some time to read the cycles count + on some hardware architectures, so this call can be used to yield lower + latencies, under the restriction to be unable to determine the exact latency. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TIME_STAMP structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_fast_hr_timestamp() + @see mbg_get_fast_hr_timestamp_comp() + @see mbg_get_fast_hr_timestamp_cycles() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_fast_hr_timestamp( MBG_DEV_HANDLE dh, + PCPS_TIME_STAMP *p ) +{ + #if defined( _MBGIOCTL_H ) + _mbgdevio_vars(); + _mbgdevio_read_var( dh, -1, IOCTL_GET_FAST_HR_TIMESTAMP, p ); + // native endianess, no need to swap bytes + return _mbgdevio_ret_val; + #else + // This is currently not supported by the target environment. + return _mbg_err_to_os( MBG_ERR_NOT_SUPP_ON_OS ); + #endif +} // mbg_get_fast_hr_timestamp + + + +/*HDR*/ +/** + Check if a specific device is a GPS receiver. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_is_gps( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_is_gps, IOCTL_DEV_IS_GPS, p ); + +} // mbg_dev_is_gps + + + +/*HDR*/ +/** + Check if a specific device is a DCF77 receiver. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_is_dcf( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_is_dcf, IOCTL_DEV_IS_DCF, p ); + +} // mbg_dev_is_dcf + + + +/*HDR*/ +/** + Check if a specific device is a MSF receiver. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_is_msf( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_is_msf, IOCTL_DEV_IS_MSF, p ); + +} // mbg_dev_is_msf + + + +/*HDR*/ +/** + Check if a specific device is a WWVB receiver. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_is_wwvb( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_is_wwvb, IOCTL_DEV_IS_WWVB, p ); + +} // mbg_dev_is_msf + + + +/*HDR*/ +/** + Check if a specific device is a long wave signal receiver, e.g. DCF77, MSF or WWVB. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_is_lwr( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_is_lwr, IOCTL_DEV_IS_LWR, p ); + +} // mbg_dev_is_lwr + + + +/*HDR*/ +/** + Check if a specific device is an IRIG receiver which supports + configuration of the IRIG input. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_irig_rx_info() + @see mbg_set_irig_rx_settings() + @see mbg_dev_has_irig_tx() + @see mbg_dev_has_irig() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_is_irig_rx( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_is_irig_rx, IOCTL_DEV_IS_IRIG_RX, p ); + +} // mbg_dev_is_irig_rx + + + +/*HDR*/ +/** + Check if a specific device supports the HR_TIME functions. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_hr_time() + @see mbg_get_hr_time_cycles() + @see mbg_get_hr_time_comp() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_hr_time( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_hr_time, IOCTL_DEV_HAS_HR_TIME, p ); + +} // mbg_dev_has_hr_time + + + +/*HDR*/ +/** + Check if a specific device supports configuration of antenna cable length. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_gps_ant_cable_len() + @see mbg_set_gps_ant_cable_len() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_cab_len( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_cab_len, IOCTL_DEV_HAS_CAB_LEN, p ); + +} // mbg_dev_has_cab_len + + + +/*HDR*/ +/** + Check if a specific device supports timezone / daylight saving configuration + using the ::TZDL structure. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_gps_tzdl() + @see mbg_set_gps_tzdl() + @see mbg_dev_has_tz() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_tzdl( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_tzdl, IOCTL_DEV_HAS_TZDL, p ); + +} // mbg_dev_has_tzdl + + + +/*HDR*/ +/** + Check if a specific device supports timezone / daylight saving configuration + using the ::PCPS_TZDL structure. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_pcps_tzdl() + @see mbg_set_pcps_tzdl() + @see mbg_dev_has_tz() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_pcps_tzdl( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_pcps_tzdl, IOCTL_DEV_HAS_PCPS_TZDL, p ); + +} // mbg_dev_has_pcps_tzdl + + + +/*HDR*/ +/** + Check if a specific device supports timezone configuration + using the ::PCPS_TZCODE type. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_tzcode() + @see mbg_set_tzcode() + @see mbg_dev_has_tz() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_tzcode( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_tzcode, IOCTL_DEV_HAS_TZCODE, p ); + +} // mbg_dev_has_tzcode + + + +/*HDR*/ +/** + Check if a specific device supports any kind of timezone configuration. + This can be used e.g. to check if a specifig dialog or menu has to + be displayed. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_tzdl() + @see mbg_dev_has_pcps_tzdl() + @see mbg_dev_has_tzcode() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_tz( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_tz, IOCTL_DEV_HAS_TZ, p ); + +} // mbg_dev_has_tz + + + +/*HDR*/ +/* (Intentionally excluded from Doxygen) + Check if a specific device supports setting an event time, i.e. + configure a %UTC time when the clock shall generate an event. + + Note: This is only supported by some special firmware. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_set_event_time() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_event_time( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_event_time, IOCTL_DEV_HAS_EVENT_TIME, p ); + +} // mbg_dev_has_event_time + + + +/*HDR*/ +/** + Check if a specific device supports the ::RECEIVER_INFO structure and related calls. + Older GPS devices may not support that structure. + + The mbg_get_gps_receiver_info() call uses this call to decide whether a + ::RECEIVER_INFO can be read directly from a device, or whether a default + structure has to be set up using default values depending on the device type. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_gps_receiver_info() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_receiver_info( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_receiver_info, IOCTL_DEV_HAS_RECEIVER_INFO, p ); + +} // mbg_dev_has_receiver_info + + + +/*HDR*/ +/** + Check if a specific device supports the mbg_clr_ucap_buff() call + used to clear a card's on-board time capture FIFO buffer. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_clr_ucap_buff() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_can_clr_ucap_buff( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_can_clr_ucap_buff, IOCTL_DEV_CAN_CLR_UCAP_BUFF, p ); + +} // mbg_dev_can_clr_ucap_buff + + + +/*HDR*/ +/** + Check if a specific device supports the mbg_get_ucap_entries() and + mbg_get_ucap_event() calls. + + If the card does not but it is a GPS card then the card provides + a time capture FIFO buffer and the obsolete mbg_get_gps_ucap() + call can be used to retrieve entries from the FIFO buffer. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_ucap_entries() + @see mbg_get_ucap_event() + @see mbg_clr_ucap_buff() + @see mbg_get_gps_ucap() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_ucap( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_ucap, IOCTL_DEV_HAS_UCAP, p ); + +} // mbg_dev_has_ucap + + + +/*HDR*/ +/** + Check if a specific device provides an IRIG output which can + be configured. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_irig_tx_info() + @see mbg_set_irig_tx_settings() + @see mbg_dev_is_irig_rx() + @see mbg_dev_has_irig() + @see \ref group_icode + +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_irig_tx( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_irig_tx, IOCTL_DEV_HAS_IRIG_TX, p ); + +} // mbg_dev_has_irig_tx + + + +/*HDR*/ +/* (Intentionally excluded from Doxygen) + Check if a specific device provides a serial output supporting + higher baud rates than older cards, i.e. ::DEFAULT_BAUD_RATES_DCF_HS + rather than ::DEFAULT_BAUD_RATES_DCF. + + The mbg_get_serial_settings() takes care of this, so applications + which use that call as suggested won't need to use this call directly. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_serial_settings() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_serial_hs( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_serial_hs, IOCTL_DEV_HAS_SERIAL_HS, p ); + +} // mbg_dev_has_serial_hs + + + +/*HDR*/ +/** + Check if a specific device provides an input signal level value which + may be displayed, e.g. DCF77 or IRIG cards. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_signal( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_signal, IOCTL_DEV_HAS_SIGNAL, p ); + +} // mbg_dev_has_signal + + + +/*HDR*/ +/** + Check if a specific device provides an modulation signal which may be + displayed, e.g. the second marks of a DCF77 AM receiver. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_mod( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_mod, IOCTL_DEV_HAS_MOD, p ); + +} // mbg_dev_has_mod + + + +/*HDR*/ +/** + Check if a specific device provides either an IRIG input or output. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_is_irig_rx() + @see mbg_dev_has_irig_tx() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_irig( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_irig, IOCTL_DEV_HAS_IRIG, p ); + +} // mbg_dev_has_irig + + + +/*HDR*/ +/** + Check if a specific device provides a configurable ref time offset + required to convert the received time to %UTC. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_ref_offs() + @see mbg_set_ref_offs() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_ref_offs( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_ref_offs, IOCTL_DEV_HAS_REF_OFFS, p ); + +} // mbg_dev_has_ref_offs + + + +/*HDR*/ +/** + Check if a specific device supports the ::MBG_OPT_INFO/::MBG_OPT_SETTINGS + structures containing optional settings, controlled by flags. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_opt_info() + @see mbg_set_opt_settings() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_opt_flags( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_opt_flags, IOCTL_DEV_HAS_OPT_FLAGS, p ); + +} // mbg_dev_has_opt_flags + + + +/*HDR*/ +/** + Check if a specific device supports large configuration data structures + as have been introducesde with the GPS receivers. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_gps_data( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_gps_data, IOCTL_DEV_HAS_GPS_DATA, p ); + +} // mbg_dev_has_gps_data + + + +/*HDR*/ +/** + Check if a specific device provides a programmable frequency synthesizer. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_synth() + @see mbg_set_synth() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_synth( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_synth, IOCTL_DEV_HAS_SYNTH, p ); + +} // mbg_dev_has_synth + + + +/*HDR*/ +/* (Intentionally excluded from Doxygen) + Check if a specific device supports the mbg_generic_io() call. + + Warning: That call is for debugging purposes and internal use only! + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_generic_io() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_generic_io( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_generic_io, IOCTL_DEV_HAS_GENERIC_IO, p ); + +} // mbg_dev_has_generic_io + + + +/*HDR*/ +/** + Check if a specific device supports the mbg_get_asic_version() call. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_asic_version() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_asic_version( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_asic_version, IOCTL_HAS_PCI_ASIC_VERSION, p ); + +} // mbg_dev_has_asic_version + + + +/*HDR*/ +/** + Check if a specific device supports the mbg_get_asic_features() call. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_asic_features() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_asic_features( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_asic_features, IOCTL_HAS_PCI_ASIC_FEATURES, p ); + +} // mbg_dev_has_asic_features + + + +/*HDR*/ +/** + Read a ::POUT_INFO_IDX array of current settings and configuration + options of a card's programmable pulse outputs. + The function mbg_setup_receiver_info() must have been called before, + and the returned ::RECEIVER_INFO structure passed to this function. + The function should only be called if the ::RECEIVER_INFO::n_prg_out + field (i.e. the number of programmable outputs on the board) is not 0. + + The array passed to this function to receive the returned data + must be able to hold at least ::RECEIVER_INFO::n_prg_out elements. + + @param dh Valid handle to a Meinberg device. + @param pii Pointer to a an array of ::POUT_INFO_IDX structures to be filled up + @param *p_ri Pointer to a ::RECEIVER_INFO structure returned by mbg_setup_receiver_info() + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_set_gps_pout_settings_idx() + @see mbg_set_gps_pout_settings() + @see mbg_setup_receiver_info() +*/ +_MBG_API_ATTR int _MBG_API mbg_get_gps_all_pout_info( MBG_DEV_HANDLE dh, + POUT_INFO_IDX pii[], + const RECEIVER_INFO *p_ri ) +{ + _mbgdevio_vars(); + + #if _MBG_SUPP_VAR_ACC_SIZE + _mbgdevio_read_gps_chk( dh, PC_GPS_ALL_POUT_INFO, + IOCTL_GET_GPS_ALL_POUT_INFO, pii, + p_ri->n_prg_out * sizeof( pii[0] ), + _pcps_ddev_has_receiver_info( dh ) ); + #else + // We check the model_code to see whether the receiver info + // has been read from a device which really supports it, or + // a dummy structure has been setup. + if ( p_ri && ( p_ri->model_code != GPS_MODEL_UNKNOWN ) ) + _mbgdevio_gen_read_gps( dh, PC_GPS_ALL_POUT_INFO, pii, + p_ri->n_prg_out * sizeof( pii[0] ) ); + else + return _mbg_err_to_os( MBG_ERR_NOT_SUPP_BY_DEV ); + #endif + + #if defined( MBG_ARCH_BIG_ENDIAN ) + if ( rc == MBG_SUCCESS ) + { + int i; + for ( i = 0; i < p_ri->n_prg_out; i++ ) + { + POUT_INFO_IDX *p = &pii[i]; + _mbg_swab_pout_info_idx( p ); + } + } + #endif + + return _mbgdevio_ret_val; + +} // mbg_get_gps_all_pout_info + + + +/*HDR*/ +/** + Write the configuration for a single programmable pulse output using + the ::POUT_SETTINGS_IDX structure which contains both the ::POUT_SETTINGS + and the output index value. + Except for the parameter types, this call is equivalent to + mbg_set_gps_pout_settings(). + The function should only be called if the ::RECEIVER_INFO::n_prg_out field + (i.e. the number of programmable outputs on the board) is not 0, and the + output index value must be in the range 0..::RECEIVER_INFO::n_prg_out. + + @param dh Valid handle to a Meinberg device. + @param *p Pointer to a ::POUT_SETTINGS_IDX structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_gps_all_pout_info() + @see mbg_set_gps_pout_settings() +*/ +_MBG_API_ATTR int _MBG_API mbg_set_gps_pout_settings_idx( MBG_DEV_HANDLE dh, + const POUT_SETTINGS_IDX *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + POUT_SETTINGS_IDX tmp = *p; + _mbg_swab_pout_settings_idx( &tmp ); + p = &tmp; + #endif + _mbgdevio_write_gps_var_chk( dh, PC_GPS_POUT_SETTINGS_IDX, + IOCTL_SET_GPS_POUT_SETTINGS_IDX, p, + _pcps_ddev_has_receiver_info( dh ) ); + return _mbgdevio_ret_val; + +} // mbg_set_gps_pout_settings_idx + + + +/*HDR*/ +/** + Write the configuration for a single programmable pulse output using + the ::POUT_SETTINGS structure plus the index of the output to be configured. + Except for the parameter types, this call is equivalent to + mbg_set_gps_pout_settings_idx(). + The function should only be called if the ::RECEIVER_INFO::n_prg_out field + (i.e. the number of programmable outputs on the board) is not 0, and the + output index value must be in the range 0..::RECEIVER_INFO::n_prg_out. + + @param dh Valid handle to a Meinberg device. + @param *p Pointer to a ::POUT_SETTINGS structure to be written + @param idx Index of the programmable pulse output to be configured (starting from 0 ). + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_gps_all_pout_info() + @see mbg_set_gps_pout_settings_idx() +*/ +_MBG_API_ATTR int _MBG_API mbg_set_gps_pout_settings( MBG_DEV_HANDLE dh, + const POUT_SETTINGS *p, int idx ) +{ + POUT_SETTINGS_IDX psi = { 0 }; + + psi.idx = idx; + psi.pout_settings = *p; + + return mbg_set_gps_pout_settings_idx( dh, &psi ); + +} // mbg_set_gps_pout_settings + + + +/*HDR*/ +/** + Read a card's IRQ status information which includes flags indicating + whether IRQs are currently enabled, and whether IRQ support by a card + is possibly unsafe due to the firmware and interface chip version. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_IRQ_STAT_INFO variable to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + */ +_MBG_API_ATTR int _MBG_API mbg_get_irq_stat_info( MBG_DEV_HANDLE dh, PCPS_IRQ_STAT_INFO *p ) +{ + #if defined( _MBGIOCTL_H ) + _mbgdevio_vars(); + _mbgdevio_read_var( dh, -1, IOCTL_GET_IRQ_STAT_INFO, p ); + // native endianess, no need to swap bytes + return _mbgdevio_ret_val; + #else + *p = dh->irq_stat_info; + return MBG_SUCCESS; + #endif + +} // mbg_get_irq_stat_info + + + +/*HDR*/ +/** + Check if a specific device provides simple LAN interface API calls. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_lan_if_info() + @see mbg_get_ip4_state() + @see mbg_get_ip4_settings() + @see mbg_set_ip4_settings() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_lan_intf( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_lan_intf, IOCTL_DEV_HAS_LAN_INTF, p ); + +} // mbg_dev_has_lan_intf + + + +/*HDR*/ +/** + Read LAN interface information from a card which supports this. + The macro _pcps_has_lan_intf() or the API call mbg_dev_has_lan_intf() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::LAN_IF_INFO variable to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_lan_intf() + @see mbg_get_ip4_state() + @see mbg_get_ip4_settings() + @see mbg_set_ip4_settings() + */ +_MBG_API_ATTR int _MBG_API mbg_get_lan_if_info( MBG_DEV_HANDLE dh, LAN_IF_INFO *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var_chk( dh, PC_GPS_LAN_IF_INFO, + IOCTL_GET_LAN_IF_INFO, p, + _pcps_ddev_has_lan_intf( dh ) ); + _mbg_swab_lan_if_info( p ); + return _mbgdevio_ret_val; + +} // mbg_get_lan_if_info + + + +/*HDR*/ +/** + Read LAN IPv4 state from a card which supports this. + The macro _pcps_has_lan_intf() or the API call mbg_dev_has_lan_intf() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::IP4_SETTINGS variable to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_lan_intf() + @see mbg_get_lan_if_info() + @see mbg_get_ip4_settings() + @see mbg_set_ip4_settings() + */ +_MBG_API_ATTR int _MBG_API mbg_get_ip4_state( MBG_DEV_HANDLE dh, IP4_SETTINGS *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var_chk( dh, PC_GPS_IP4_STATE, + IOCTL_GET_IP4_STATE, p, + _pcps_ddev_has_lan_intf( dh ) ); + _mbg_swab_ip4_settings( p ); + return _mbgdevio_ret_val; + +} // mbg_get_ip4_state + + + +/*HDR*/ +/** + Read LAN IPv4 settings from a card which supports this. + The macro _pcps_has_lan_intf() or the API call mbg_dev_has_lan_intf() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::IP4_SETTINGS variable to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_lan_intf() + @see mbg_get_lan_if_info() + @see mbg_get_ip4_state() + @see mbg_set_ip4_settings() + */ +_MBG_API_ATTR int _MBG_API mbg_get_ip4_settings( MBG_DEV_HANDLE dh, IP4_SETTINGS *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var_chk( dh, PC_GPS_IP4_SETTINGS, + IOCTL_GET_IP4_SETTINGS, p, + _pcps_ddev_has_lan_intf( dh ) ); + _mbg_swab_ip4_settings( p ); + return _mbgdevio_ret_val; + +} // mbg_get_ip4_settings + + + +/*HDR*/ +/** + Write LAN IPv4 settings to a card which supports this. + The macro _pcps_has_lan_intf() or the API call mbg_dev_has_lan_intf() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device. + @param *p ::IP4_SETTINGS structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_lan_intf() + @see mbg_get_lan_if_info() + @see mbg_get_ip4_settings() +*/ +_MBG_API_ATTR int _MBG_API mbg_set_ip4_settings( MBG_DEV_HANDLE dh, + const IP4_SETTINGS *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + IP4_SETTINGS tmp = *p; + _mbg_swab_ip4_settings( &tmp ); + p = &tmp; + #endif + _mbgdevio_write_gps_var_chk( dh, PC_GPS_IP4_SETTINGS, + IOCTL_SET_IP4_SETTINGS, p, + _pcps_ddev_has_lan_intf( dh ) ); + return _mbgdevio_ret_val; + +} // mbg_set_ip4_settings + + + +/*HDR*/ +/** + Check if a specific device provides PTP configuration/status calls. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_ptp_state() + @see mbg_get_ptp_cfg_info() + @see mbg_set_ptp_cfg_settings() +*/ +_MBG_API_ATTR int _MBG_API mbg_dev_has_ptp( MBG_DEV_HANDLE dh, int *p ) +{ + _mbgdevio_query_cond( dh, _pcps_ddev_has_ptp, IOCTL_DEV_HAS_PTP, p ); + +} // mbg_dev_has_ptp + + + +/*HDR*/ +/** + Read PTP/IEEE1588 status from a card which supports this. + The macro _pcps_ddev_has_ptp() or the API call mbg_dev_has_ptp() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PTP_CFG_INFO variable to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_ptp() + @see mbg_get_ptp_cfg_info() + @see mbg_set_ptp_cfg_settings() + */ +_MBG_API_ATTR int _MBG_API mbg_get_ptp_state( MBG_DEV_HANDLE dh, PTP_STATE *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var_chk( dh, PC_GPS_PTP_STATE, + IOCTL_GET_PTP_STATE, p, + _pcps_ddev_has_ptp( dh ) ); + _mbg_swab_ptp_state( p ); + return _mbgdevio_ret_val; + +} // mbg_get_ptp_state + + + +/*HDR*/ +/** + Read PTP/IEEE1588 config info and current settings from a card which supports this. + The macro _pcps_ddev_has_ptp() or the API call mbg_dev_has_ptp() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PTP_CFG_INFO variable to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_ptp() + @see mbg_get_ptp_state() + @see mbg_set_ptp_cfg_settings() + */ +_MBG_API_ATTR int _MBG_API mbg_get_ptp_cfg_info( MBG_DEV_HANDLE dh, PTP_CFG_INFO *p ) +{ + _mbgdevio_vars(); + _mbgdevio_read_gps_var_chk( dh, PC_GPS_PTP_CFG, + IOCTL_GET_PTP_CFG_INFO, p, + _pcps_ddev_has_ptp( dh ) ); + _mbg_swab_ptp_cfg_info( p ); + return _mbgdevio_ret_val; + +} // mbg_get_ptp_cfg_info + + + +/*HDR*/ +/** + Write PTP/IEEE1588 configuration settings to a card which supports this. + The macro _pcps_ddev_has_ptp() or the API call mbg_dev_has_ptp() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device. + @param *p ::PTP_CFG_SETTINGS structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_ptp() + @see mbg_get_ptp_state() + @see mbg_get_ptp_cfg_info() +*/ +_MBG_API_ATTR int _MBG_API mbg_set_ptp_cfg_settings( MBG_DEV_HANDLE dh, + const PTP_CFG_SETTINGS *p ) +{ + _mbgdevio_vars(); + #if defined( MBG_ARCH_BIG_ENDIAN ) + PTP_CFG_SETTINGS tmp = *p; + _mbg_swab_ptp_cfg_settings( &tmp ); + p = &tmp; + #endif + _mbgdevio_write_gps_var_chk( dh, PC_GPS_PTP_CFG, + IOCTL_SET_PTP_CFG_SETTINGS, p, + _pcps_ddev_has_ptp( dh ) ); + return _mbgdevio_ret_val; + +} // mbg_set_ptp_cfg_settings + + + +/*HDR*/ +/** + Read system time and card time from the kernel driver. The kernel + driver reads the current system time plus a HR time structure from + a card immediately after each other. The returned info structure also + contains some cycles counts to be able to determine the execution times + required to read those time stamps. + + The advantage of this call compared to mbg_get_time_info_tstamp() is + that this call also returns the card's status. On the other hand, reading + the HR time from the card may block e.g. if another application accesses + the board. + + This call makes a mbg_get_hr_time_cycles() call internally so the macro + _pcps_has_hr_time() or the API call mbg_dev_has_hr_time() can be + used to check whether this call is supported with a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_TIME_INFO_HRT variable to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_hr_time() + @see mbg_get_time_info_tstamp() + */ +_MBG_API_ATTR int _MBG_API mbg_get_time_info_hrt( MBG_DEV_HANDLE dh, MBG_TIME_INFO_HRT *p ) +{ + #if defined( _MBGIOCTL_H ) + _mbgdevio_vars(); + _mbgdevio_read_var_chk( dh, -1, IOCTL_GET_TIME_INFO_HRT, p, + _pcps_ddev_has_hr_time( dh ) ); + _mbg_swab_mbg_time_info_hrt( p ); + return _mbgdevio_ret_val; + #else + return _mbg_err_to_os( MBG_ERR_NOT_SUPP_ON_OS ); + #endif + +} // mbg_get_time_info_hrt + + + +/*HDR*/ +/** + This call is similar to mbg_get_time_info_hrt() except that a + mbg_get_fast_hr_timestamp_cycles() call is made internally, so the macro + _pcps_has_fast_hr_timestamp() or the API call mbg_dev_has_fast_hr_timestamp() + can be used to check whether this call is supported with a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_TIME_INFO_TSTAMP variable to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_fast_hr_timestamp() + @see mbg_get_time_info_hrt() + */ +_MBG_API_ATTR int _MBG_API mbg_get_time_info_tstamp( MBG_DEV_HANDLE dh, MBG_TIME_INFO_TSTAMP *p ) +{ + #if defined( _MBGIOCTL_H ) + _mbgdevio_vars(); + _mbgdevio_read_var_chk( dh, -1, IOCTL_GET_TIME_INFO_TSTAMP, p, + _pcps_ddev_has_fast_hr_timestamp( dh ) ); + _mbg_swab_mbg_time_info_tstamp( p ); + return _mbgdevio_ret_val; + #else + return _mbg_err_to_os( MBG_ERR_NOT_SUPP_ON_OS ); + #endif + +} // mbg_get_time_info_tstamp + + + +/*HDR*/ +/** + Read the CPU affinity of a process, i.e. on which of the available + CPUs the process can be executed. + + @param pid The process ID. + @param *p Pointer to a ::MBG_CPU_SET variable which contains a mask of CPUs. + + @return ::MBG_SUCCESS or error code returned by the system call. + + @see mbg_set_process_affinity() + @see mbg_set_current_process_affinity_to_cpu() + */ +_MBG_API_ATTR int _MBG_API mbg_get_process_affinity( MBG_PROCESS_ID pid, MBG_CPU_SET *p ) +{ + #if defined( MBG_TGT_LINUX ) + + return sched_getaffinity( pid, sizeof( *p ), p ); + + #elif defined( MBG_TGT_WIN32 ) + + MBG_CPU_SET system_affinity_mask = 0; + + return GetProcessAffinityMask( pid, p, &system_affinity_mask ) ? 0 : -1; + + #else + + return -1; + + #endif + +} // mbg_get_process_affinity + + + +/*HDR*/ +/** + Set the CPU affinity of a process, i.e. on which of the available + CPUs the process is allowed to be executed. + + @param pid The process ID. + @param *p Pointer to a ::MBG_CPU_SET variable which contains a mask of CPUs. + + @return ::MBG_SUCCESS or error code returned by the system call. + + @see mbg_get_process_affinity() + @see mbg_set_current_process_affinity_to_cpu() + */ +_MBG_API_ATTR int _MBG_API mbg_set_process_affinity( MBG_PROCESS_ID pid, MBG_CPU_SET *p ) +{ + #if defined( MBG_TGT_LINUX ) + + return sched_setaffinity( pid, sizeof( *p ), p ); + + #elif defined( MBG_TGT_WIN32 ) + + return SetProcessAffinityMask( pid, *p ) ? 0 : -1; + + #else + + return -1; + + #endif + +} // mbg_set_process_affinity + + + +/*HDR*/ +/** + Set the CPU affinity of a process for a single CPU only, i.e. the process + may only be executed on that single CPU. + + @param cpu_num The number of the CPU. + + @return ::MBG_SUCCESS or error code returned by the system call. + + @see mbg_get_process_affinity() + @see mbg_set_process_affinity() + */ +_MBG_API_ATTR int _MBG_API mbg_set_current_process_affinity_to_cpu( int cpu_num ) +{ + MBG_CPU_SET cpu_set; + + _mbg_cpu_clear( &cpu_set ); + _mbg_cpu_set( cpu_num, &cpu_set ); + + return mbg_set_process_affinity( _mbg_get_current_process(), &cpu_set ); + +} // mbg_set_current_process_affinity_to_cpu + + + +#if MBGDEVIO_USE_THREAD_API + +/*HDR*/ +/** + Create a new execution thread for the current process. + This function is only implemented for targets which support threads. + + @param p_ti Pointer to a ::MBG_THREAD_INFO structure to be filled up. + @param fnc The name of the thread function to be started. + @param arg A generic argument passed to the thread function. + + @return ::MBG_SUCCESS or error code returned by the system call. + + @see mbg_thread_stop() + @see mbg_thread_sleep_interruptible() + @see mbg_thread_set_affinity() + */ +_MBG_API_ATTR int _MBG_API mbg_thread_create( MBG_THREAD_INFO *p_ti, + MBG_THREAD_FNC_RET_VAL (MBG_THREAD_FNC_ATTR *fnc)(void *), void *arg ) +{ + #if defined( MBG_TGT_LINUX ) + + return pthread_create( &p_ti->thread_id, NULL, fnc, arg ); + + #elif defined( MBG_TGT_WIN32 ) + + HANDLE h; + DWORD thread_id = 0; + + p_ti->exit_request = CreateEvent( NULL, FALSE, FALSE, NULL ); + + if ( p_ti->exit_request == NULL ) + goto fail; + + h = CreateThread( NULL, 0, fnc, arg, 0, &thread_id ); + + if ( h == NULL ) + { + CloseHandle( p_ti->exit_request ); + goto fail; + } + + p_ti->thread_id = h; + + return 0; + +fail: + return GetLastError(); + + #else + + return -1; + + #endif + +} // mbg_thread_create + + + +/*HDR*/ +/** + Stop a thread which has been created by mbg_thread_create(). Wait + until the thread has finished and release all resources. + This function is only implemented for targets which support threads. + + @param p_ti Pointer to a ::MBG_THREAD_INFO structure associated with the thread. + + @return ::MBG_SUCCESS or error code returned by the system call. + + @see mbg_thread_create() + @see mbg_thread_sleep_interruptible() + @see mbg_thread_set_affinity() + */ +_MBG_API_ATTR int _MBG_API mbg_thread_stop( MBG_THREAD_INFO *p_ti ) +{ + #if defined( MBG_TGT_LINUX ) + + pthread_cancel( p_ti->thread_id ); + + return pthread_join( p_ti->thread_id, NULL ); + + #elif defined( MBG_TGT_WIN32 ) + + if ( SetEvent( p_ti->exit_request ) && + WaitForSingleObject( p_ti->thread_id, 10000L ) == 0 ) + { + CloseHandle( p_ti->exit_request ); + p_ti->exit_request = NULL; + + CloseHandle( p_ti->thread_id ); + p_ti->thread_id = NULL; + + return 0; + } + + return GetLastError(); + + #else + + return -1; + + #endif + +} // mbg_thread_stop + + + +/*HDR*/ +/** + Let the current thread sleep for a certain interval unless a signal is + received indicating the thread should terminate. + This function is only implemented for targets which support threads. + + @param p_ti Pointer to a ::MBG_THREAD_INFO structure associated with the thread. + @param sleep_ms The number of milliseconds to sleep + @return 0 if the sleep interval has expired normally + 1 if a signal to terminate has been received + <0 if an error has occurred + + @see mbg_thread_create() + @see mbg_thread_stop() + @see mbg_thread_set_affinity() + */ +_MBG_API_ATTR int _MBG_API mbg_thread_sleep_interruptible( MBG_THREAD_INFO *p_ti, ulong sleep_ms ) +{ + #if defined( MBG_TGT_LINUX ) + + usleep( sleep_ms * 1000 ); + return 0; + + #elif defined( MBG_TGT_WIN32 ) + + DWORD dw = WaitForSingleObject( p_ti->exit_request, sleep_ms ); + + switch ( dw ) + { + case WAIT_OBJECT_0: // has been interrupted to terminate + return 1; + + case WAIT_TIMEOUT: // sleep interval expired without interruption + return 0; + } + + return -1; + + #else + + return -1; + + #endif + +} // mbg_thread_sleep_interruptible + + + +#if MBGDEVIO_HAVE_THREAD_AFFINITY + +/*HDR*/ +/** + Set the CPU affinity of a single thread, i.e. on which of the available + CPUs the thread is allowed to be executed. + This function is only implemented for targets which support thread affinity. + + @param p_ti Pointer to a ::MBG_THREAD_INFO structure associated with the thread. + @param *p Pointer to a ::MBG_CPU_SET variable which contains a mask of CPUs. + + @return ::MBG_SUCCESS or error code returned by the system call. + + @see mbg_thread_create() + @see mbg_thread_stop() + @see mbg_thread_sleep_interruptible() + */ +_MBG_API_ATTR int _MBG_API mbg_thread_set_affinity( MBG_THREAD_INFO *p_ti, MBG_CPU_SET *p ) +{ + #if defined( MBG_TGT_LINUX ) + + return pthread_setaffinity_np( tid, sizeof( *p ), p ); + + #elif defined( MBG_TGT_WIN32 ) + + MBG_CPU_SET prv_thread_affinity = SetThreadAffinityMask( p_ti->thread_id, *p ); + + return prv_thread_affinity ? 0 : -1; + + #else + + return -1; + + #endif + +} // mbg_thread_set_affinity + +#endif + + + +static /*HDR*/ +/** + A thread function which implements polling of a device at a regular interval. + At each polling a high resolution time stamp and an associated cycles count + are saved which can be used to retrieve extrapolated time stamps using the + cycles counter. The thread also computes the frequency of the system's cycles + counter. + On systems where the cycles counter is implemented by a CPU's time stamp + counter (TSC) it maybe required to set the thread or process affinity to a + single CPU to get reliable cycles counts. In this case also care should be + taken that the CPU's clock frequency is not stepped up and down e.g. due + to power saving mechanisms (e.g. Intel SpeedStep, or AMD Cool'n'Quiet). + Otherwise time interpolation may be messed up. + This function is only implemented for targets which support threads. + + @param *p_void Pointer to a ::MBG_POLL_THREAD_INFO structure. + + @return ::MBG_SUCCESS or nothing, depending on the taget system. + + @see mbg_xhrt_poll_thread_create() + @see mbg_xhrt_poll_thread_stop() + @see mbg_get_xhrt_time_as_pcps_hr_time() + @see mbg_get_xhrt_time_as_filetime() + @see mbg_get_xhrt_cycles_frequency() + */ +MBG_THREAD_FNC_RET_VAL MBG_THREAD_FNC_ATTR mbg_xhrt_poll_thread_fnc( void *p_void ) +{ + MBG_XHRT_VARS prv_xhrt_vars; + + MBG_POLL_THREAD_INFO *p_pti = (MBG_POLL_THREAD_INFO *) p_void; + MBG_XHRT_INFO *p = &p_pti->xhrt_info; + + memset( &prv_xhrt_vars, 0, sizeof( prv_xhrt_vars ) ); + + for (;;) + { + MBG_XHRT_VARS xhrt_vars; + MBG_PC_CYCLES_FREQUENCY freq = 0; + int sleep_ms; + + int rc = mbg_get_hr_time_cycles( p->dh, &xhrt_vars.htc ); + + if ( rc == MBG_SUCCESS ) + { + xhrt_vars.pcps_hr_tstamp64 = pcps_time_stamp_to_uint64( &xhrt_vars.htc.t.tstamp ); + + if ( prv_xhrt_vars.pcps_hr_tstamp64 && ( ( xhrt_vars.htc.t.status & PCPS_LS_ENB ) == 0 ) ) + freq = ( mbg_delta_pc_cycles( &xhrt_vars.htc.cycles, &prv_xhrt_vars.htc.cycles ) * PCPS_HRT_BIN_FRAC_SCALE ) + / ( xhrt_vars.pcps_hr_tstamp64 - prv_xhrt_vars.pcps_hr_tstamp64 ); + } + + + _mbg_mutex_lock( &p->mutex ); + + if ( rc == MBG_SUCCESS ) + { + p->vars = xhrt_vars; + p->prv_vars = prv_xhrt_vars; + + if ( freq ) + p->freq_hz = freq; + } + + p->ioctl_status = rc; + + sleep_ms = p->sleep_ms; + + _mbg_mutex_unlock( &p->mutex ); + + + if ( rc == MBG_SUCCESS ) + prv_xhrt_vars = xhrt_vars; + + if ( mbg_thread_sleep_interruptible( &p_pti->ti, sleep_ms ) ) + break; + } + + _mbg_thread_exit( 0 ); + +} // mbg_xhrt_poll_thread_fnc + + + +/*HDR*/ +/** + Set up a ::MBG_POLL_THREAD_INFO structure and start a new thread + which runs the mbg_xhrt_poll_thread_fnc() function. + This function is only implemented for targets which support threads. + + @param *p_pti Pointer to a ::MBG_POLL_THREAD_INFO structure. + @param dh the handle of the device to be polled. + @param freq_hz The initial cycles frequency, if known, in Hz. + @param sleep_ms the sleep interval for the poll thread function in ms. + If this parameter is 0 then the default sleep interval is used. + + @return ::MBG_SUCCESS on success, + ::MBG_ERR_NOT_SUPP_BY_DEV if the device to poll does not support HR time + else the result of mbg_thread_create() + + @see mbg_xhrt_poll_thread_fnc() + @see mbg_xhrt_poll_thread_stop() + @see mbg_get_xhrt_time_as_pcps_hr_time() + @see mbg_get_xhrt_time_as_filetime() + @see mbg_get_xhrt_cycles_frequency() + */ +_MBG_API_ATTR int _MBG_API mbg_xhrt_poll_thread_create( MBG_POLL_THREAD_INFO *p_pti, MBG_DEV_HANDLE dh, + MBG_PC_CYCLES_FREQUENCY freq_hz, int sleep_ms ) +{ + int has_hr_time; + int rc = mbg_dev_has_hr_time( dh, &has_hr_time ); + + if ( ( rc != MBG_SUCCESS ) || !has_hr_time ) + return _mbg_err_to_os( MBG_ERR_NOT_SUPP_BY_DEV ); + + memset( p_pti, 0, sizeof( *p_pti ) ); + + p_pti->xhrt_info.dh = dh; + p_pti->xhrt_info.freq_hz = freq_hz; + p_pti->xhrt_info.sleep_ms = sleep_ms ? sleep_ms : 1000; // sleep 1 second by default + _mbg_mutex_init( &p_pti->xhrt_info.mutex ); + + rc = mbg_thread_create( &p_pti->ti, mbg_xhrt_poll_thread_fnc, p_pti ); + + return rc; + +} // mbg_xhrt_poll_thread_create + + + +/*HDR*/ +/** + Stop a polling thread started by mbg_xhrt_poll_thread_create() + and release all associated resources. + + @param *p_pti Pointer to a ::MBG_POLL_THREAD_INFO structure. + + @return the result of mbg_thread_stop() + + @see mbg_xhrt_poll_thread_fnc() + @see mbg_xhrt_poll_thread_create() + @see mbg_get_xhrt_time_as_pcps_hr_time() + @see mbg_get_xhrt_time_as_filetime() + @see mbg_get_xhrt_cycles_frequency() + */ +_MBG_API_ATTR int _MBG_API mbg_xhrt_poll_thread_stop( MBG_POLL_THREAD_INFO *p_pti ) +{ + int rc = mbg_thread_stop( &p_pti->ti ); + + if ( rc == MBG_SUCCESS ) + _mbg_mutex_deinit( &p_pti->xhrt_info.mutex ); + + return rc; + +} // mbg_xhrt_poll_thread_stop + + + +static /*HDR*/ +int mbg_get_xhrt_data( MBG_XHRT_INFO *p, uint64_t *tstamp, MBG_XHRT_VARS *vars ) +{ + MBG_XHRT_VARS xhrt_vars; + MBG_PC_CYCLES cyc_now; + uint64_t t_now = 0; + MBG_PC_CYCLES_FREQUENCY freq_hz; + int ioctl_status; + + mbg_get_pc_cycles( &cyc_now ); + + _mbg_mutex_lock( &p->mutex ); + xhrt_vars = p->vars; + freq_hz = p->freq_hz; + ioctl_status = p->ioctl_status; + _mbg_mutex_unlock( &p->mutex ); + + if ( freq_hz && xhrt_vars.pcps_hr_tstamp64 ) + { + t_now = xhrt_vars.pcps_hr_tstamp64 + + ( mbg_delta_pc_cycles( &cyc_now, &xhrt_vars.htc.cycles ) * PCPS_HRT_BIN_FRAC_SCALE ) / freq_hz; + mbg_chk_tstamp64_leap_sec( &t_now, &xhrt_vars.htc.t.status ); + } + + if ( tstamp ) + *tstamp = t_now; + + if ( vars ) + *vars = xhrt_vars; + + return ioctl_status; + +} // mbg_get_xhrt_data + + + +/*HDR*/ +/** + Retrieve a time stamp in PCPS_HR_TIME format which is extrapolated + using the system's current cycles counter value and a time stamp + plus associated cycles counter value saved by the polling thread. + See mbg_xhrt_poll_thread_fnc() for details and limitations. + This function is only implemented for targets which support threads. + + @param *p Pointer to a ::MBG_XHRT_INFO structure used to retrieve data from the polling thread. + @param *p_hrt Pointer to a ::PCPS_HR_TIME structure to be filled up. + + @return MBG_SUCCESS or another return value from the polling thread's IOCTL call. + + @see mbg_xhrt_poll_thread_fnc() + @see mbg_xhrt_poll_thread_create() + @see mbg_xhrt_poll_thread_stop() + @see mbg_get_xhrt_time_as_filetime() + @see mbg_get_xhrt_cycles_frequency() + */ +_MBG_API_ATTR int _MBG_API mbg_get_xhrt_time_as_pcps_hr_time( MBG_XHRT_INFO *p, PCPS_HR_TIME *p_hrt ) +{ + uint64_t tstamp64; + MBG_XHRT_VARS xhrt_vars; + + int rc = mbg_get_xhrt_data( p, &tstamp64, &xhrt_vars ); + + // Even if an IOCTL error has occurred recently in the polling thread + // the interpolation may still work correctly. So we just continue + // normally but pass the return code on to the calling function. + + uint64_to_pcps_time_stamp( &p_hrt->tstamp, tstamp64 ); + + // Update status (valid only for the previous second!) + p_hrt->signal = xhrt_vars.htc.t.signal; + p_hrt->status = xhrt_vars.htc.t.status; + p_hrt->utc_offs = xhrt_vars.htc.t.utc_offs; + + return rc; + +} // mbg_get_xhrt_time_as_pcps_hr_time + + + +#if defined( MBG_TGT_WIN32 ) + +/*HDR*/ +/** + Retrieve a time stamp in FILETIME format which is extrapolated + using the system's current cycles counter value and a time stamp + plus associated cycles counter value saved by the polling thread. + See mbg_xhrt_poll_thread_fnc() for details and limitations. + Since FILETIME is a Windows specific type this function is only + implemented under Windows. + + @param *p Pointer to a ::MBG_XHRT_INFO structure used to retrieve data from the polling thread. + @param *p_ft Pointer to a ::FILETIME structure to be filled up. + + @return MBG_SUCCESS or another return value from the polling thread's IOCTL call. + + @see mbg_xhrt_poll_thread_fnc() + @see mbg_xhrt_poll_thread_create() + @see mbg_xhrt_poll_thread_stop() + @see mbg_get_xhrt_time_as_pcps_hr_time() + @see mbg_get_xhrt_cycles_frequency() + */ +_MBG_API_ATTR int _MBG_API mbg_get_xhrt_time_as_filetime( MBG_XHRT_INFO *p, FILETIME *p_ft ) +{ + uint64_t tstamp64; + + int rc = mbg_get_xhrt_data( p, &tstamp64, NULL ); + + // Even if an IOCTL error has occurred recently in the polling thread + // the interpolation may still work correctly. So we just continue + // normally but pass the return code on to the calling function. + + mbg_pcps_tstamp64_to_filetime( p_ft, &tstamp64 ); + + return rc; + +} // mbg_get_xhrt_time_as_filetime + +#endif + + + +/*HDR*/ +/** + Retrieve the frequency of the system's cycles counter as determined + by the device polling thread. + See mbg_xhrt_poll_thread_fnc() for details and limitations. + This function is only implemented for targets which support threads. + + @param *p Pointer to a ::MBG_XHRT_INFO structure used to retrieve data from the polling thread. + @param *p_freq_hz Pointer to a ::MBG_PC_CYCLES_FREQUENCY variable in which the frequency is returned. + @return a status code from the polling thread: MBG_SUCCESS or an IOCTL error code. + + @see mbg_xhrt_poll_thread_fnc() + @see mbg_xhrt_poll_thread_create() + @see mbg_xhrt_poll_thread_stop() + @see mbg_get_xhrt_time_as_pcps_hr_time() + @see mbg_get_xhrt_time_as_filetime() + */ +_MBG_API_ATTR int _MBG_API mbg_get_xhrt_cycles_frequency( MBG_XHRT_INFO *p, MBG_PC_CYCLES_FREQUENCY *p_freq_hz ) +{ + MBG_PC_CYCLES_FREQUENCY freq_hz; + int ioctl_status; + + _mbg_mutex_lock( &p->mutex ); + freq_hz = p->freq_hz; + ioctl_status = p->ioctl_status; + _mbg_mutex_unlock( &p->mutex ); + + if ( p_freq_hz ) + *p_freq_hz = freq_hz; + + return ioctl_status; + +} // mbg_get_xhrt_cycles_frequency + +#endif // defined MBGDEVIO_USE_THREAD_API + + + +/*HDR*/ +/** + Retrieve the default system's cycles counter frequency from the kernel driver. + + @param dh handle of the device to which the IOCTL call is sent. + @param *p Pointer of a ::MBG_PC_CYCLES_FREQUENCY variable to be filled up. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_default_cycles_frequency() + */ +_MBG_API_ATTR int _MBG_API mbg_get_default_cycles_frequency_from_dev( MBG_DEV_HANDLE dh, MBG_PC_CYCLES_FREQUENCY *p ) +{ + #if defined( _MBGIOCTL_H ) && defined( MBG_PC_CYCLES_SUPPORTED ) + _mbgdevio_vars(); + _mbgdevio_read_var( dh, -1, IOCTL_GET_CYCLES_FREQUENCY, p ); + // native endianess, no need to swap bytes + if ( rc != MBG_SUCCESS ) + *p = 0; + + #if defined( MBG_TGT_LINUX ) + if ( *p == 0 ) + { + int has_hr_time = 0; + + rc = mbg_dev_has_hr_time( dh, &has_hr_time ); + + if ( rc != MBG_SUCCESS ) + goto done; + + if ( ( rc == MBG_SUCCESS ) && has_hr_time ) + { + PCPS_HR_TIME_CYCLES htc1; + PCPS_HR_TIME_CYCLES htc2; + double delta_cycles; + double delta_t; + + rc = mbg_get_hr_time_cycles( dh, &htc1 ); + + if ( rc != MBG_SUCCESS ) + goto done; + + sleep( 1 ); + + rc = mbg_get_hr_time_cycles( dh, &htc2 ); + + if ( rc != MBG_SUCCESS ) + goto done; + + // compute cycles frequency from delta htc + delta_cycles = mbg_delta_pc_cycles( &htc2.cycles, &htc1.cycles ); + delta_t = pcps_time_stamp_to_uint64( &htc2.t.tstamp ) - pcps_time_stamp_to_uint64( &htc1.t.tstamp ); + *p = ( delta_cycles * PCPS_HRT_BIN_FRAC_SCALE ) / delta_t; + } + } +done: + #endif + + return _mbgdevio_ret_val; + + #else + + *p = 0; + + return _mbg_err_to_os( MBG_ERR_NOT_SUPP_ON_OS ); + + #endif + +} // mbg_get_default_cycles_frequency_from_dev + + + +/*HDR*/ +/** + Retrieve the default system's cycles counter frequency. + + @note This may not be supported on all target platforms, in which case the + returned frequency is 0 and the mbg_get_default_cycles_frequency_from_dev() + call should be used. + + @return the default cycles counter frequency in Hz, or 0 if the value is not available. + + @see mbg_get_default_cycles_frequency_from_dev() +*/ +_MBG_API_ATTR MBG_PC_CYCLES_FREQUENCY _MBG_API mbg_get_default_cycles_frequency( void ) +{ + #if defined MBG_TGT_WIN32 + + MBG_PC_CYCLES_FREQUENCY pc_cycles_frequency; + + mbg_get_pc_cycles_frequency( &pc_cycles_frequency ); + + return pc_cycles_frequency; + + #else + + return 0; + + #endif + +} // mbg_get_default_cycles_frequency + + + +#if defined( MBG_TGT_WIN32 ) + +#if defined( _USRDLL ) + +BOOL APIENTRY DllMain( HANDLE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved ) +{ + if ( ul_reason_for_call == DLL_PROCESS_ATTACH ) + mbg_svc_register_event_source( MBG_APP_EVTLOG_NAME_MBGDEVIO_DLL ); + + return TRUE; +} + +#endif // defined( _USRDLL ) + +#endif // defined( MBG_TGT_WIN32 ) + diff --git a/mbglib/common/mbgdevio.h b/mbglib/common/mbgdevio.h new file mode 100755 index 0000000..4b4de15 --- /dev/null +++ b/mbglib/common/mbgdevio.h @@ -0,0 +1,3108 @@ + +/************************************************************************** + * + * $Id: mbgdevio.h 1.39.1.11 2011/02/02 12:21:39 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes used with Meinberg device driver I/O. + * + * ----------------------------------------------------------------------- + * $Log: mbgdevio.h $ + * Revision 1.39.1.11 2011/02/02 12:21:39 martin + * Fixed a type. + * Revision 1.39.1.10 2011/01/28 09:33:45 martin + * Cosmetics. + * Revision 1.39.1.9 2010/12/14 11:23:49 martin + * Moved definition of MBG_HW_NAME to the header file. + * Revision 1.39.1.8 2010/12/14 10:56:35Z martin + * Revision 1.39.1.7 2010/08/11 13:48:53 martin + * Cleaned up comments. + * Revision 1.39.1.6 2010/08/11 12:43:52 martin + * Revision 1.39.1.5 2010/07/15 08:40:57 martin + * Revision 1.39.1.4 2010/01/08 15:04:17Z martin + * Revision 1.39.1.3 2010/01/08 11:24:02Z martin + * Compute and check time of day only if any leap second status bit set. + * Revision 1.39.1.2 2010/01/08 11:13:57Z martin + * Made xhrt leap second check an inline function. + * Revision 1.39.1.1 2010/01/07 15:49:37Z martin + * Fixed macro to avoid compiler warning. + * Revision 1.39 2009/12/15 15:34:59Z daniel + * Support reading the raw IRIG data bits for firmware versions + * which support this feature. + * Revision 1.38.1.2 2009/12/10 09:58:53Z daniel + * Revision 1.38.1.1 2009/12/10 09:45:29Z daniel + * Revision 1.38 2009/09/29 15:06:26Z martin + * Updated function prototypes. + * Revision 1.37 2009/08/12 14:31:51 daniel + * New version code 306, compatibility version still 210. + * Revision 1.36 2009/06/19 12:20:31Z martin + * Updated function prototypes. + * Revision 1.35 2009/06/09 08:57:09 daniel + * New version code 305, compatibility version still 210. + * Revision 1.34 2009/06/08 18:20:14Z daniel + * Updated function prototypes. + * Fixes for ARM target. + * Revision 1.33 2009/03/19 15:36:26 martin + * New version code 304, compatibility version still 210. + * Moved some inline functions dealing with MBG_PC_CYCLES + * from mbgdevio.h to pcpsdev.h. + * Include mbg_arch.h here. + * Removed unused doxygen comment. + * Updated function prototypes. + * Revision 1.32 2008/12/17 10:43:30Z martin + * New version code 303, compatibility version still 210. + * Increased MBG_MAX_DEVICES from 5 to 8. + * Added macros to read the time stamp counter (cycles), and + * added an inline rdtscll() call for user space Linux. + * Added some inline functions to deal with cycles and timestamps. + * Generic support for threads and process/thread affinity controlled + * by symbol MBGDEVIO_USE_THREAD_API. + * New preprocessor symbol MBGDEVIO_HAVE_THREAD_AFFINITY. + * Support extrapolated time stamps controlled + * by symbol MBGDEVIO_XHRT_API. + * Removed definition of MBG_TGT_SUPP_MMAP. + * Updated function prototypes and doxygen comments. + * Revision 1.31 2008/02/26 16:57:38Z martin + * Updated function prototypes and doxygen comments. + * Revision 1.30 2008/02/04 13:33:15Z martin + * New preprocessor symbol MBG_TGT_SUPP_MMAP. + * Revision 1.29 2008/01/31 08:55:39Z daniel + * Renamed functions related to mapped memory support + * Revision 1.28 2008/01/31 08:36:22Z martin + * Picked up changes from 1.24.1.1: + * Added default preprocessor symbol MBGDEVIO_SIMPLE. + * Revision 1.27 2008/01/17 15:56:37Z daniel + * New version code 302, compatibility version still 210. + * Added structure MBG_MAPPED_MEM_INFO. + * Updated function prototypes. + * Revision 1.26 2007/10/16 10:11:42Z daniel + * New version code 301, compatibility version still 210. + * Revision 1.25 2007/09/26 14:10:34Z martin + * New version code 300, compatibility version still 210. + * Added MBG_MAX_DEVICES. + * Added enum SELECTION_MODE. + * Added structures MBG_DEVICE_LIST and MBG_DEVICE_NAME_LIST. + * Updated function prototypes. + * Revision 1.24 2007/03/22 10:14:16Z martin + * New version code 219, compatibility version still 210. + * Revision 1.23 2007/03/02 10:18:10Z martin + * Updated function prototypes due to renamed data structures. + * Use new definitions of generic handle types. + * Preliminary support for *BSD. + * Revision 1.22 2006/08/09 13:47:29 martin + * New version code 218, compatibility version still 210. + * Revision 1.21 2006/06/08 12:30:22Z martin + * New version code 217, compatibility version still 210. + * Revision 1.20 2006/05/02 13:14:27Z martin + * New version code 216, compatibility version still 210. + * Updated function prototypes. + * Revision 1.19 2006/01/11 12:14:53Z martin + * New version code 215, compatibility version still 210. + * Revision 1.18 2005/12/15 09:38:39Z martin + * New version 214, compatibility version still 210. + * Revision 1.17 2005/06/02 11:54:40Z martin + * Updated function prototypes. + * Revision 1.16 2005/02/16 15:13:00Z martin + * New MBGDEVIO_VERSION 0x0212. + * Updated function prototypes. + * Revision 1.15 2005/01/14 10:22:44Z martin + * Updated function prototypes. + * Revision 1.14 2004/12/09 11:24:00Z martin + * Support configuration of on-board frequency synthesizer. + * Revision 1.13 2004/11/09 14:13:00Z martin + * Updated function prototypes. + * Revision 1.12 2004/08/17 11:13:46Z martin + * Account for renamed symbols. + * Revision 1.11 2004/04/14 09:34:23Z martin + * New definition MBGDEVIO_COMPAT_VERSION. + * Pack structures 1 byte aligned. + * Revision 1.10 2003/12/22 15:35:10Z martin + * New revision 2.03. + * Moved some definitions to pcpsdev.h. + * New structures to read device time together with associated + * PC high resolution timer cycles. + * Updated function prototypes. + * Revision 1.9 2003/06/19 08:50:05Z martin + * Definition of MBGDEVIO_VERSION number to allow DLL + * API version checking. + * Replaced some defines by typedefs. + * Renamed USE_DOS_TSR to MBG_USE_DOS_TSR. + * New preprocessor symbol MBG_USE_KERNEL_DRIVER which + * is defined only for targets which use IOCTLs. + * Don't include pcps_dos.h here. + * Updated function prototypes. + * Revision 1.8 2003/05/16 08:44:26 MARTIN + * Cleaned up inclusion of headers. + * Removed obsolete definitions. + * Changes for direct access targets. + * Revision 1.7 2003/04/25 10:16:00 martin + * Updated inclusion of headers. + * Made prototypes available for all targets. + * Revision 1.6 2003/04/15 19:38:05Z martin + * Updated function prototypes. + * Revision 1.5 2003/04/09 13:44:53Z martin + * Use new common IOCTL codes from mbgioctl.h. + * Updated function prototypes. + * Revision 1.4 2002/09/06 11:06:35Z martin + * Updated function prototypes for Win32 API.. + * Win32 compatibility macros to use old APIs with new functions. + * Support targets OS/2 and NetWare. + * Revision 1.3 2002/02/28 10:08:54Z MARTIN + * Syntax cleanup for Win32. + * Revision 1.2 2002/02/26 14:40:47 MARTIN + * Source code cleanup. + * Changes for DOS with and without TSR. + * Revision 1.1 2002/02/19 13:48:21 MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _MBGDEVIO_H +#define _MBGDEVIO_H + + +/* Other headers to be included */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define MBGDEVIO_VERSION 0x0307 + +#define MBGDEVIO_COMPAT_VERSION 0x0210 + +#define MBG_MAX_DEVICES 8 + +#if defined( MBG_TGT_WIN32 ) + + #if !defined( MBGDEVIO_XHRT_API ) + #define MBGDEVIO_XHRT_API 1 + #endif + + #if !defined( MBGDEVIO_USE_THREAD_API ) + #define MBGDEVIO_USE_THREAD_API 1 + #endif + + #if !defined( MBGDEVIO_HAVE_THREAD_AFFINITY ) + #define MBGDEVIO_HAVE_THREAD_AFFINITY 1 + #endif + + #define MBG_USE_KERNEL_DRIVER 1 + #include + +#elif defined( MBG_TGT_LINUX ) + + #if !defined( MBGDEVIO_XHRT_API ) + #define MBGDEVIO_XHRT_API 1 + #endif + + // Thread support under Linux depends strongly on + // the versions of some libraries, so the symbols + // MBGDEVIO_USE_THREAD_API and MBGDEVIO_HAVE_THREAD_AFFINITY + // should be set in the project's Makefile, depending on the + // target envionment. Otherwise thread support is disabled + // as per default. + + #define MBG_USE_KERNEL_DRIVER 1 + #include + +#elif defined( MBG_TGT_BSD ) + + #define MBG_USE_KERNEL_DRIVER 1 + #include + +#elif defined( MBG_TGT_OS2 ) + + #define MBG_USE_KERNEL_DRIVER 1 + +#elif defined( MBG_TGT_DOS ) + + #if !defined( MBG_USE_DOS_TSR ) + #define MBG_USE_DOS_TSR 1 + #endif + + #include + +#else // other target OSs which access the hardware directly + + #include + +#endif + + +#if !defined( MBGDEVIO_XHRT_API ) + #define MBGDEVIO_XHRT_API 0 +#endif + +#if !defined( MBGDEVIO_USE_THREAD_API ) + #define MBGDEVIO_USE_THREAD_API 0 +#endif + +#if !defined( MBGDEVIO_HAVE_THREAD_AFFINITY ) + #define MBGDEVIO_HAVE_THREAD_AFFINITY 0 +#endif + +#ifdef _MBGDEVIO + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + +#if defined( _USE_PACK ) // set byte alignment + #pragma pack( 1 ) +#endif + + +// If MBGDEVIO_SIMPLE != 0 then some complex configuration +// API calls are excluded from build, which would otherwise +// require some additional mbglib modules to be linked +// to the application. +#if !defined( MBGDEVIO_SIMPLE ) + #define MBGDEVIO_SIMPLE 0 +#endif + + +#if defined( MBG_USE_KERNEL_DRIVER ) + + typedef MBG_HANDLE MBG_DEV_HANDLE; + + #define MBG_INVALID_DEV_HANDLE MBG_INVALID_HANDLE + +#else // other target OSs which access the hardware directly + + typedef PCPS_DDEV *MBG_DEV_HANDLE; + + #define MBG_INVALID_DEV_HANDLE NULL + +#endif + + + +/** + The type below is used to store a unique ID for a device which + is made up of the device model name and its serial number, i.e.: + Format: [model_name]_[serial_number], e.g. "GPS170PCI_028210040670" + */ +typedef char MBG_HW_NAME[PCPS_CLOCK_NAME_SZ + PCPS_SN_SIZE + 1]; + + + +#if defined( MBG_TGT_LINUX ) && !defined( MBG_ARCH_ARM ) + + #include + + #define MBG_PROCESS_ID pid_t + #define _mbg_get_current_process() 0 + + #define MBG_CPU_SET cpu_set_t + #define MBG_CPU_SET_SIZE CPU_SETSIZE + #define _mbg_cpu_clear( _ps ) CPU_ZERO( (_ps) ) + #define _mbg_cpu_set( _i, _ps ) CPU_SET( (_i), (_ps) ) + #define _mbg_cpu_isset( _i, _ps ) CPU_ISSET( (_i), (_ps) ) + + #if MBGDEVIO_USE_THREAD_API + + #include + + #define MBG_THREAD_ID pthread_t + #define _mbg_get_current_thread() 0 + #define MBG_THREAD_FNC_ATTR // empty + #define MBG_THREAD_FNC_RET_VAL void * + #define _mbg_thread_exit( _v ) return (void *) (_v) + + #define MBG_MUTEX pthread_mutex_t + #define _mbg_mutex_init( _pm ) pthread_mutex_init( (_pm), NULL ) + #define _mbg_mutex_deinit( _pm ) _nop_macro_fnc() + #define _mbg_mutex_lock( _pm ) pthread_mutex_lock( (_pm) ) + #define _mbg_mutex_unlock( _pm ) pthread_mutex_unlock( (_pm) ) + + #endif + +#elif defined( MBG_TGT_WIN32 ) + + #define MBG_PROCESS_ID HANDLE + #define _mbg_get_current_process() GetCurrentProcess() + + #define MBG_CPU_SET DWORD_PTR // Attention: this is not used as pointer! + #define MBG_CPU_SET_SIZE ( sizeof( MBG_CPU_SET ) * 8 ) + + #define MBG_THREAD_ID HANDLE + #define _mbg_get_current_thread() GetCurrentThread() + #define MBG_THREAD_FNC_ATTR WINAPI + #define MBG_THREAD_FNC_RET_VAL DWORD + #define _mbg_thread_exit( _v ) ExitThread( _v ); return (_v) + + #define MBG_MUTEX CRITICAL_SECTION + #define _mbg_mutex_init( _pm ) InitializeCriticalSection( (_pm) ) + #define _mbg_mutex_deinit( _pm ) DeleteCriticalSection( (_pm) ) + #define _mbg_mutex_lock( _pm ) EnterCriticalSection( (_pm) ) + #define _mbg_mutex_unlock( _pm ) LeaveCriticalSection( (_pm) ) + +#endif // target specific + + +#if !defined( MBG_TGT_WIN32 ) + + #define FILETIME int // just a dummy to avoid build errors + +#endif + + +#if !defined( MBG_PROCESS_ID ) + #define MBG_PROCESS_ID int +#endif + +#if !defined( _mbg_get_current_process ) + #define _mbg_get_current_process() 0 +#endif + +#if !defined( MBG_CPU_SET ) + #define MBG_CPU_SET int +#endif + +#if !defined( MBG_CPU_SET_SIZE ) + #define MBG_CPU_SET_SIZE ( sizeof( MBG_CPU_SET ) * 8 ) +#endif + +#if !defined( _mbg_cpu_clear ) + #define _mbg_cpu_clear( _ps ) ( *(_ps) = 0 ) +#endif + +#if !defined( _mbg_cpu_set ) + #define _mbg_cpu_set( _i, _ps ) ( *(_ps) |= ( 1UL << (_i) ) ) +#endif + +#if !defined( _mbg_cpu_isset ) + #define _mbg_cpu_isset( _i, _ps ) ( *(_ps) & ( 1UL << (_i) ) ) +#endif + + +#if !defined( MBG_THREAD_ID ) + #define MBG_THREAD_ID int +#endif + +#if !defined( _mbg_get_current_thread ) + #define _mbg_get_current_thread() 0 +#endif + +#if !defined( MBG_THREAD_FNC_ATTR ) + #define MBG_THREAD_FNC_ATTR // empty +#endif + +#if !defined( MBG_THREAD_FNC_RET_VAL ) + #define MBG_THREAD_FNC_RET_VAL void +#endif + +#if !defined( _mbg_thread_exit ) + #define _mbg_thread_exit( _v ) _nop_macro_fnc() +#endif + + +#if !defined( MBG_MUTEX ) + #define MBG_MUTEX int +#endif + +#if !defined( _mbg_mutex_init ) + #define _mbg_mutex_init( _pm ) _nop_macro_fnc() +#endif + +#if !defined( _mbg_mutex_deinit ) + #define _mbg_mutex_deinit( _pm ) _nop_macro_fnc() +#endif + +#if !defined( _mbg_mutex_lock ) + #define _mbg_mutex_lock( _pm ) _nop_macro_fnc() +#endif + +#if !defined( _mbg_mutex_unlock ) + #define _mbg_mutex_unlock( _pm ) _nop_macro_fnc() +#endif + +typedef struct +{ + MBG_THREAD_ID thread_id; + #if defined( MBG_TGT_WIN32 ) + HANDLE exit_request; + #endif +} MBG_THREAD_INFO; + + + +typedef struct +{ + PCPS_HR_TIME_CYCLES htc; + uint64_t pcps_hr_tstamp64; +} MBG_XHRT_VARS; + + +typedef struct +{ + MBG_XHRT_VARS vars; + MBG_XHRT_VARS prv_vars; + MBG_PC_CYCLES_FREQUENCY freq_hz; + int ioctl_status; + int sleep_ms; + MBG_MUTEX mutex; + MBG_DEV_HANDLE dh; +} MBG_XHRT_INFO; + + +typedef struct +{ + MBG_XHRT_INFO xhrt_info; + MBG_THREAD_INFO ti; +} MBG_POLL_THREAD_INFO; + + + +/** + Match modes to decide how to proceed if a certain + model type with certain serial number can not be found + */ +enum MBG_MATCH_MODE +{ + MBG_MATCH_ANY, /**< open the next available device on the system */ + MBG_MATCH_MODEL, /**< open the next available device on the system with the same clock type */ + MBG_MATCH_EXACTLY, /**< force opening exactly the requested device otherwise exit with failure */ + N_MBG_MATCH_MODE /**< number of known modes */ +}; + + + +typedef struct _MBG_DEVICE_LIST +{ + char *device_path; /**< Hardware ID depending on the calling function */ + struct _MBG_DEVICE_LIST *next; + +} MBG_DEVICE_LIST; + + + +typedef struct _MBG_DEVICENAME_LIST +{ + char device_name[40]; /**< readable name */ + struct _MBG_DEVICENAME_LIST *next; + +} MBG_DEVICENAME_LIST; + + + +#define _mbg_generic_read_var( _dh, _cmd, _s ) \ + mbg_generic_read( _dh, _cmd, &(_s), sizeof( (_s) ) ) + +#define _mbg_generic_write_var( _dh, _cmd, _s ) \ + mbg_generic_write( _dh, _cmd, &(_s), sizeof( (_s) ) ) + +#define _mbg_generic_read_gps_var( _dh, _cmd, _s ) \ + mbg_generic_read_gps( _dh, _cmd, &(_s), sizeof( (_s) ) ) + +#define _mbg_generic_write_gps_var( _dh, _cmd, _s ) \ + mbg_generic_write_gps( _dh, _cmd, &(_s), sizeof( (_s) ) ) + + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + + /** + Get the version number of the compiled mbgdevio library. + If the mbgdevio library is built as a DLL/shared object then + the version number of the compiled library may differ from + the version number of the import library and header files + which have been used to build an application. + + @return The version number + + @see ::MBGDEVIO_VERSION defined in mbgdevio.h. + */ + _MBG_API_ATTR int _MBG_API mbgdevio_get_version( void ) ; + + /** + Check if the version of the compiled mbgdevio library is compatible + with a certain version which is passed as parameter. + + @param header_version Version number to be checked, should be ::MBGDEVIO_VERSION + defined in mbgdevio.h. + + @return ::MBG_SUCCESS if compatible, ::MBG_ERR_LIB_NOT_COMPATIBLE if not. + + @see ::MBGDEVIO_VERSION defined in mbgdevio.h. + */ + _MBG_API_ATTR int _MBG_API mbgdevio_check_version( int header_version ) ; + + /** + Open a device by index, starting from 0. + This function is out of date, mbg_open_device_by_name() + should be used instead. + + See the note for mbg_find_device() for details. + + @param device_index Index of the device, use 0 for the first device. + */ + _MBG_API_ATTR MBG_DEV_HANDLE _MBG_API mbg_open_device( unsigned int device_index ) ; + + /** + Get the number of supported devices installed on the computer. + This function is out of date, mbg_find_devices_with_names() + should be used instead. + + Note: This function is out of date since it may not work + correctly for Meinberg devices which are disconnected and reconnected + while the system is running (e.g. USB devices). However, the function + will be kept for compatibility reasons and works correctly if all + Meinberg devices are connected at system boot and are not disconnected + and reconnected during operation + + @return The number of devices found. + + @see mbg_find_devices_with_names() + */ + _MBG_API_ATTR int _MBG_API mbg_find_devices( void ) ; + + /** + Return the number of supported devices installed on the system and + set up a list of unique names of those devices. + + This function should be used preferably instead of mbg_find_devices(). + + @param device_list Pointer to a linked list of type ::MBG_DEVICENAME_LIST + with device names. The list will be allocated by this + function and has to be freed after usage by calling + mbg_free_device_name_list(). + @param max_devices Maximum number of devices the function should look for + (can not exceed ::MBG_MAX_DEVICES). + + @return Number of present devices + + @see ::MBG_HW_NAME for the format of the unique names + @see mbg_free_device_name_list() + @see mbg_find_devices() + */ + _MBG_API_ATTR int _MBG_API mbg_find_devices_with_names( MBG_DEVICENAME_LIST **device_list, int max_devices ) ; + + /** + Free the memory of the ::MBG_DEVICENAME_LIST that has been allocated before + by mbg_find_devices_with_names(). + + @param *list Linked list of type ::MBG_DEVICENAME_LIST + + @see mbg_find_devices_with_names() + */ + _MBG_API_ATTR void _MBG_API mbg_free_device_name_list( MBG_DEVICENAME_LIST *list) ; + + /** + Return a handle to a device with a certain unique name. + The names of the devices that are installed on the system can be retrieved by + the function mbg_find_devices_with_names(). + + This function should be used preferably instead of mbg_open_device(). + + @param hw_name String with the unique name of the device to be opened + @param selection_mode One of the enum values of ::MBG_MATCH_MODE + + @return On success, the function returns a handle to the device, otherwise ::MBG_INVALID_DEV_HANDLE + + @see ::MBG_HW_NAME for the format of the unique names. + @see ::MBG_MATCH_MODE + @see mbg_find_devices_with_names() + */ + _MBG_API_ATTR MBG_DEV_HANDLE _MBG_API mbg_open_device_by_name( const char* hw_name, int selection_mode ) //##++++ +; + + /** + Close a handle to a device and set the handle value to ::MBG_INVALID_DEV_HANDLE. + If required, unmap mapped memory. + + @param dev_handle Handle to a Meinberg device. + */ + _MBG_API_ATTR void _MBG_API mbg_close_device( MBG_DEV_HANDLE *dev_handle ) ; + + /** + Return a ::PCPS_DRVR_INFO structure that provides information + about the kernel device driver. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_DRVR_INFO structure which is filled up. + + @return ::MBG_SUCCESS or error code returned by device I/O control function + */ + _MBG_API_ATTR int _MBG_API mbg_get_drvr_info( MBG_DEV_HANDLE dh, PCPS_DRVR_INFO *p ) ; + + /** + Return a ::PCPS_DEV structure that provides detailed information about the device. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_DEV structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function + */ + _MBG_API_ATTR int _MBG_API mbg_get_device_info( MBG_DEV_HANDLE dh, PCPS_DEV *p ) ; + + /** + Return the current state of the on-board::PCPS_STATUS_PORT. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_STATUS_PORT value to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function + + @see \ref group_status_port "bitmask" + */ + _MBG_API_ATTR int _MBG_API mbg_get_status_port( MBG_DEV_HANDLE dh, PCPS_STATUS_PORT *p ) ; + + /* (Intentionally excluded from Doxygen) + Generic read function which writes a command code to the device + and reads a number of replied data to a generic buffer. + + Warning: This is for debugging purposes only! + The specialized API calls should be used preferably. + A specific device may not support any command code. + + @param dh Valid handle to a Meinberg device + @param cmd Can be any \ref group_cmd_bytes "command byte" supported by the device + @param *p Pointer to a buffer to be filled up + @param size Size of the buffer *p + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_generic_write() + @see mbg_generic_read_gps() + @see mbg_generic_write_gps() + @see mbg_generic_io() + */ + _MBG_API_ATTR int _MBG_API mbg_generic_read( MBG_DEV_HANDLE dh, int cmd, void *p, int size ) ; + + /* (Intentionally excluded from Doxygen) + Generic read function which writes a GPS command code to the device + and reads a number of replied data to a generic buffer. + The macro _pcps_has_gps_data() or the API call mbg_dev_has_gps_data() + check whether this call is supported by a specific card. + + Warning: This is for debugging purposes only! + The specialized API calls should be used preferably. + A specific device may not support any GPS command code. + + @param dh Valid handle to a Meinberg device + @param cmd Can be any \ref group_cmd_bytes "command byte" supported by the device. + @param *p Pointer to a buffer to be filled up + @param size Size of the buffer *p + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_gps_data() + @see mbg_generic_write_gps() + @see mbg_generic_read() + @see mbg_generic_write() + @see mbg_generic_io() + */ + _MBG_API_ATTR int _MBG_API mbg_generic_read_gps( MBG_DEV_HANDLE dh, int cmd, void *p, int size ) ; + + /* (Intentionally excluded from Doxygen) + Generic write function which writes a command code plus an + associated number of data bytes to the device. + + Warning: This is for debugging purposes only! + The specialized API calls should be used preferably. + A specific device may not support any command code. + + @param dh Valid handle to a Meinberg device + @param cmd Can be any \ref group_cmd_bytes "command byte" supported by the device. + @param *p Pointer to a buffer to be written + @param size Size of the buffer *p + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_generic_read() + @see mbg_generic_read_gps() + @see mbg_generic_write_gps() + @see mbg_generic_io() + */ + _MBG_API_ATTR int _MBG_API mbg_generic_write( MBG_DEV_HANDLE dh, int cmd, const void *p, int size ) ; + + /* (Intentionally excluded from Doxygen) + Generic write function which writes a GPS command code plus an + associated number of data bytes to the device. + The macro _pcps_has_gps_data() or the API call mbg_dev_has_gps_data() + check whether this call is supported by a specific card. + + Warning: This is for debugging purposes only! + The specialized API calls should be used preferably. + A specific device may not support any GPS command code. + + @param dh Valid handle to a Meinberg device + @param cmd Can be any \ref group_cmd_bytes "command byte" supported by the device. + @param *p Pointer to a buffer to be written + @param size Size of the buffer *p + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_gps_data() + @see mbg_generic_read_gps() + @see mbg_generic_read() + @see mbg_generic_write() + @see mbg_generic_io() + */ + _MBG_API_ATTR int _MBG_API mbg_generic_write_gps( MBG_DEV_HANDLE dh, int cmd, const void *p, int size ) ; + + /* (Intentionally excluded from Doxygen) + Write and/or read generic data to/from a device. + The macro _pcps_has_generic_io() or the API call mbg_dev_has_generic_io() + check whether this call is supported by a specific card. + + Warning: This call is for debugging purposes and internal use only! + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_generic_io() + @see mbg_generic_read() + @see mbg_generic_write() + @see mbg_generic_read_gps() + @see mbg_generic_write_gps() + */ + _MBG_API_ATTR int _MBG_API mbg_generic_io( MBG_DEV_HANDLE dh, int type, const void *in_p, int in_sz, void *out_p, int out_sz ) ; + + /** + Read a ::PCPS_TIME structure returning the current date/time/status. + The returned time is local time according to the card's time zone setting, + with a resolution of 10 ms (i.e. 10ths of seconds). + + This call is supported by any device manufactured by Meinberg. However, + for higher accuracy and resolution the mbg_get_hr_time..() group of calls + should be used preferably if supported by the specific device. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TIME structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_hr_time() + @see mbg_set_time() + @see mbg_get_sync_time() + */ + _MBG_API_ATTR int _MBG_API mbg_get_time( MBG_DEV_HANDLE dh, PCPS_TIME *p ) ; + + /** + Set a device's on-board clock manually by passing a ::PCPS_STIME structure + The macro _pcps_can_set_time() checks whether this call + is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_STIME structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_time() + */ + _MBG_API_ATTR int _MBG_API mbg_set_time( MBG_DEV_HANDLE dh, const PCPS_STIME *p ) ; + + /** + Read a ::PCPS_TIME structure returning the date/time/status reporting + when the device was synchronized the last time to its time source, + e.g. the DCF77 signal or the GPS satellites. + The macro _pcps_has_sync_time() or the API call mbg_dev_has_sync_time() + check whether this call is supported by a specific card. + + The macro _pcps_has_sync_time() checks whether this call + is supported by a specific card. + + Note: If that information is not available on the board then + the value of the returned ::PCPS_TIME::sec field is set to 0xFF. + The macro _pcps_time_is_read() can be used to check whether the + returned information is valid, or not available. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TIME structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_time() + */ + _MBG_API_ATTR int _MBG_API mbg_get_sync_time( MBG_DEV_HANDLE dh, PCPS_TIME *p ) ; + + /** + Wait until the next second change, then return a ::PCPS_TIME + structure similar to mbg_get_time(). + + Note: This API call is supported under Windows only. + The call blocks until the kernel driver detects a second change + reported by the device. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TIME structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_time() + */ + _MBG_API_ATTR int _MBG_API mbg_get_time_sec_change( MBG_DEV_HANDLE dh, PCPS_TIME *p ) ; + + /** + Read a ::PCPS_HR_TIME (High Resolution time) structure returning + the current %UTC time (seconds since 1970), %UTC offset, and status. + The macro _pcps_has_hr_time() or the API call mbg_dev_has_hr_time() + check whether this call is supported by a specific card. + + Note: This API call provides a higher accuracy and resolution + than mbg_get_time(). However, it does not account for the latency + which is introduced when accessing the board. + The mbg_get_hr_time_cycles() and mbg_get_hr_time_comp() calls + provides mechanisms to account for and/or compensate the latency. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_HR_TIME structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_hr_time() + @see mbg_get_time() + @see mbg_get_hr_time_cycles() + @see mbg_get_hr_time_comp() + */ + _MBG_API_ATTR int _MBG_API mbg_get_hr_time( MBG_DEV_HANDLE dh, PCPS_HR_TIME *p ) ; + + /* (Intentionally excluded from Doxygen ) + Write a high resolution time stamp ::PCPS_TIME_STAMP to the clock + to configure a %UTC time when the clock shall generate an event. + The macro _pcps_has_event_time() or the API call mbg_dev_has_event_time() + check whether this call is supported by a specific card. + + Note: This is only supported by some special firmware. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TIME_STAMP structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_event_time() + */ + _MBG_API_ATTR int _MBG_API mbg_set_event_time( MBG_DEV_HANDLE dh, const PCPS_TIME_STAMP *p ) ; + + /** + Read the configuration of a device's serial port. + The macro _pcps_has_serial() checks whether this call + is supported by a specific card. + + Note: This function is supported only by a certain class + of devices, so it should not be called directly. The generic + function mbg_get_serial_settings() should be used instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_SERIAL structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see \ref group_cmd_bytes + @see mbg_get_serial_settings() + */ + _MBG_API_ATTR int _MBG_API mbg_get_serial( MBG_DEV_HANDLE dh, PCPS_SERIAL *p ) ; + + /** + Write the configuration of a device's serial port. + The macro _pcps_has_serial() checks whether this call + is supported by a specific card. + + Note: This function is supported only by a certain class + of devices, so it should not be called directly. The generic + function mbg_save_serial_settings() should be used instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_SERIAL structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see \ref group_cmd_bytes + @see mbg_save_serial_settings() + */ + _MBG_API_ATTR int _MBG_API mbg_set_serial( MBG_DEV_HANDLE dh, const PCPS_SERIAL *p ) ; + + /** + Read the card's time zone/daylight saving configuration code. + That tzcode is supported by some simpler cards and only allows only + a very basic configuration. + The macro _pcps_has_tzcode() or the API call mbg_dev_has_tzcode() + check whether this call is supported by a specific card. + Other cards may support the mbg_get_pcps_tzdl() or mbg_get_gps_tzdl() + calls instead which allow for a more detailed configuration of the + time zone and daylight saving settings. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TZCODE structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_tzcode() + @see mbg_set_tzcode() + @see mbg_get_pcps_tzdl() + @see mbg_get_gps_tzdl() + @see \ref group_cmd_bytes + */ + _MBG_API_ATTR int _MBG_API mbg_get_tzcode( MBG_DEV_HANDLE dh, PCPS_TZCODE *p ) ; + + /** + Write the card's time zone/daylight saving configuration code. + That tzcode is supported by some simpler cards and only allows only + a very basic configuration. + The macro _pcps_has_tzcode() or the API call mbg_dev_has_tzcode() + check whether this call is supported by a specific card. + Other cards may support the mbg_set_pcps_tzdl() or mbg_set_gps_tzdl() + calls instead which allow for a more detailed configuration of the + time zone and daylight saving settings. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TZCODE structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_tzcode() + @see mbg_get_tzcode() + @see mbg_set_pcps_tzdl() + @see mbg_set_gps_tzdl() + @see \ref group_cmd_bytes + */ + _MBG_API_ATTR int _MBG_API mbg_set_tzcode( MBG_DEV_HANDLE dh, const PCPS_TZCODE *p ) ; + + /** + Read the card's time zone/daylight saving parameters using the + ::PCPS_TZDL structure. + The macro _pcps_has_pcps_tzdl() or the API call mbg_dev_has_pcps_tzdl() + check whether this call is supported by a specific card. + Other cards may support the mbg_get_tzcode() or mbg_get_gps_tzdl() + calls instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TZDL structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_pcps_tzdl() + @see mbg_set_pcps_tzdl() + @see mbg_get_tzcode() + @see mbg_get_gps_tzdl() + @see \ref group_cmd_bytes + */ + _MBG_API_ATTR int _MBG_API mbg_get_pcps_tzdl( MBG_DEV_HANDLE dh, PCPS_TZDL *p ) ; + + /** + Write the card's time zone/daylight saving parameters using the + ::PCPS_TZDL structure. + The macro _pcps_has_pcps_tzdl() or the API call mbg_dev_has_pcps_tzdl() + check whether this call is supported by a specific card. + Other cards may support the mbg_set_tzcode() or mbg_set_gps_tzdl() + calls instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TZDL structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_pcps_tzdl() + @see mbg_get_pcps_tzdl() + @see mbg_set_tzcode() + @see mbg_set_gps_tzdl() + @see \ref group_cmd_bytes + */ + _MBG_API_ATTR int _MBG_API mbg_set_pcps_tzdl( MBG_DEV_HANDLE dh, const PCPS_TZDL *p ) ; + + /** + Read the reference time offset from %UTC for clocks which can't determine + that offset automatically, e.g. from an IRIG input signal. + The macro _pcps_has_ref_offs() or the API call mbg_dev_has_ref_offs() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_REF_OFFS value to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_ref_offs() + @see mbg_set_ref_offs() + @see ::PCPS_GET_REF_OFFS + */ + _MBG_API_ATTR int _MBG_API mbg_get_ref_offs( MBG_DEV_HANDLE dh, MBG_REF_OFFS *p ) ; + + /** + Write the reference time offset from %UTC for clocks which can't determine + that offset automatically, e.g. from an IRIG input signal. + The macro _pcps_has_ref_offs() or the API call mbg_dev_has_ref_offs() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_REF_OFFS value to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_ref_offs() + @see mbg_get_ref_offs() + @see ::PCPS_SET_REF_OFFS + */ + _MBG_API_ATTR int _MBG_API mbg_set_ref_offs( MBG_DEV_HANDLE dh, const MBG_REF_OFFS *p ) ; + + /** + Read a ::MBG_OPT_INFO structure containing optional settings, controlled by flags. + The ::MBG_OPT_INFO structure contains a mask of supported flags plus the current + settings of those flags. + The macro _pcps_has_opt_flags() or the API call mbg_dev_has_opt_flags() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_OPT_INFO structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_opt_flags() + @see mbg_set_opt_settings() + */ + _MBG_API_ATTR int _MBG_API mbg_get_opt_info( MBG_DEV_HANDLE dh, MBG_OPT_INFO *p ) ; + + /** + Write a ::MBG_OPT_SETTINGS structure contains optional settings, controlled by flags. + The macro _pcps_has_opt_flags() or the API call mbg_dev_has_opt_flags() + check whether this call is supported by a specific card. + The ::MBG_OPT_INFO structure should be read first to check which of the specified + flags is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_OPT_SETTINGS structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_opt_flags() + @see mbg_get_opt_info() + */ + _MBG_API_ATTR int _MBG_API mbg_set_opt_settings( MBG_DEV_HANDLE dh, const MBG_OPT_SETTINGS *p ) ; + + /** + Read an ::IRIG_INFO structure containing the configuration of an IRIG input + plus the possible settings supported by that input. + The macro _pcps_is_irig_rx() or the API call mbg_dev_is_irig_rx() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an ::IRIG_INFO structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_set_irig_rx_settings() + @see mbg_dev_is_irig_rx() + @see mbg_dev_has_irig_tx() + @see mbg_dev_has_irig() + @see \ref group_icode + */ + _MBG_API_ATTR int _MBG_API mbg_get_irig_rx_info( MBG_DEV_HANDLE dh, IRIG_INFO *p ) ; + + /** + Write an ::IRIG_SETTINGS structure containing the configuration of an IRIG input. + The macro _pcps_is_irig_rx() or the API call mbg_dev_is_irig_rx() + check whether this call is supported by a specific card. + The ::IRIG_INFO structure should be read first to determine the possible + settings supported by this card's IRIG input. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::IRIG_SETTINGS structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_irig_rx_info() + @see mbg_dev_is_irig_rx() + @see mbg_dev_has_irig_tx() + @see mbg_dev_has_irig() + @see \ref group_icode + */ + _MBG_API_ATTR int _MBG_API mbg_set_irig_rx_settings( MBG_DEV_HANDLE dh, const IRIG_SETTINGS *p ) ; + + /** + Check if a specific device supports the mbg_get_irig_ctrl_bits() call. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_irig_ctrl_bits() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_irig_ctrl_bits( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Read a ::MBG_IRIG_CTRL_BITS type which contains the control function + bits of the latest IRIG input frame. Those bits may carry some + well-known information, as in the IEEE1344 code, but may also contain + some customized information, depending on the IRIG frame type and + the configuration of the IRIG generator. So these bits are returned + as-is and must be interpreted by the application. + The macro _pcps_has_irig_ctrl_bits() or the API call mbg_dev_has_irig_ctrl_bits() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_IRIG_CTRL_BITS type to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_irig_ctrl_bits() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_irig_ctrl_bits( MBG_DEV_HANDLE dh, MBG_IRIG_CTRL_BITS *p ) ; + + /** + Check if a specific device supports the mbg_get_raw_irig_data() call. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_raw_irig_data() + @see mbg_get_raw_irig_data_on_sec_change() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_raw_irig_data( MBG_DEV_HANDLE dh, int *p) ; + + /** + Read a ::MBG_RAW_IRIG_DATA type which contains all data + bits of the latest IRIG input frame. + The macro _pcps_has_raw_irig_data() or the API call mbg_dev_has_raw_irig_data() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_RAW_IRIG_DATA type to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_raw_irig_data() + @see mbg_get_raw_irig_data_on_sec_change() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_raw_irig_data( MBG_DEV_HANDLE dh, MBG_RAW_IRIG_DATA *p ) ; + + /** + Read a ::MBG_RAW_IRIG_DATA type just after a second change which contains all data + bits of the latest IRIG input frame. + The macro _pcps_has_raw_irig_data() or the API call mbg_dev_has_raw_irig_data() + check whether this call is supported by a specific card. + + Note: The mbg_get_time_sec_change() function called by this function is + supported under Windows only, so this function can also only be used under Windows. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_RAW_IRIG_DATA type to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_raw_irig_data() + @see mbg_get_raw_irig_data() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_raw_irig_data_on_sec_change( MBG_DEV_HANDLE dh, MBG_RAW_IRIG_DATA *p ) ; + + /** + Check if a specific device supports the mbg_get_irig_time() call. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_irig_time() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_irig_time( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Read a ::PCPS_IRIG_TIME type which returns the raw IRIG day-of-year number + and time decoded from the latest IRIG input frame. If the configured IRIG code + also contains the year number then the year number is also returned, otherwise + the returned year number is 0xFF. + The macro _pcps_has_irig_time() or the API call mbg_dev_has_irig_time() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_IRIG_TIME type to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_irig_time() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_irig_time( MBG_DEV_HANDLE dh, PCPS_IRIG_TIME *p ) ; + + /** + Clear the card's on-board time capture FIFO buffer. + The macro _pcps_can_clr_ucap_buff() or the API call mbg_dev_can_clr_ucap_buff() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_can_clr_ucap_buff() + @see mbg_get_ucap_entries() + @see mbg_get_ucap_event() + */ + _MBG_API_ATTR int _MBG_API mbg_clr_ucap_buff( MBG_DEV_HANDLE dh ) ; + + /** + Read a ::PCPS_UCAP_ENTRIES structure to retrieve the number of saved + user capture events and the maximum capture buffer size. + The macro _pcps_has_ucap() or the API call mbg_dev_has_ucap() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_UCAP_ENTRIES structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_ucap() + @see mbg_get_ucap_entries() + @see mbg_get_ucap_event() + */ + _MBG_API_ATTR int _MBG_API mbg_get_ucap_entries( MBG_DEV_HANDLE dh, PCPS_UCAP_ENTRIES *p ) ; + + /** + Retrieve a single time capture event from the on-board FIFO buffer + using a ::PCPS_HR_TIME structure. The oldest entry of the FIFO is retrieved + and then removed from the FIFO. + If no capture event is available in the FIFO buffer then both the seconds + and the fractions of the returned timestamp are 0. + The macro _pcps_has_ucap() or the API call mbg_dev_has_ucap() + check whether this call is supported by a specific card. + + Note: This call is very much faster than the older mbg_get_gps_ucap() + call which is obsolete but still supported for compatibility with + older cards. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_HR_TIME structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_ucap() + @see mbg_get_ucap_entries() + @see mbg_clr_ucap_buff() + */ + _MBG_API_ATTR int _MBG_API mbg_get_ucap_event( MBG_DEV_HANDLE dh, PCPS_HR_TIME *p ) ; + + /** + Read the card's time zone/daylight saving parameters using the ::TZDL + structure. + The macro _pcps_has_tzdl() or the API call mbg_dev_has_tzdl() + check whether this call is supported by a specific card. + + Note: In spite of the function name this call may also be + supported by non-GPS cards. Other cards may support the mbg_get_tzcode() + or mbg_get_pcps_tzdl() calls instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::TZDL structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_tzdl() + @see mbg_set_gps_tzdl() + @see mbg_get_tzcode() + @see mbg_get_pcps_tzdl() + @see \ref group_tzdl + */ + _MBG_API_ATTR int _MBG_API mbg_get_gps_tzdl( MBG_DEV_HANDLE dh, TZDL *p ) ; + + /** + Write the card's time zone/daylight saving parameters using the ::TZDL + structure. + The macro _pcps_has_tzdl() or the API call mbg_dev_has_tzdl() + check whether this call is supported by a specific card. + + Note: In spite of the function name this call may also be + supported by non-GPS cards. Other cards may support the mbg_set_tzcode() + or mbg_set_pcps_tzdl() calls instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::TZDL structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_tzdl() + @see mbg_get_gps_tzdl() + @see mbg_set_tzcode() + @see mbg_set_pcps_tzdl() + @see \ref group_tzdl + */ + _MBG_API_ATTR int _MBG_API mbg_set_gps_tzdl( MBG_DEV_HANDLE dh, const TZDL *p ) ; + + /** + Retrieve the software revision of a GPS receiver. + This call is obsolete but still supported for compatibility + with older GPS cards. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + Note: The function mbg_get_gps_receiver_info() should + be used instead, if supported by the card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::SW_REV structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_is_gps() + @see mbg_get_gps_receiver_info() + */ + _MBG_API_ATTR int _MBG_API mbg_get_gps_sw_rev( MBG_DEV_HANDLE dh, SW_REV *p ) ; + + /** + Retrieve the status of the battery buffered GPS variables. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + The GPS receiver stays in cold boot mode until all of the + data sets are valid. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::BVAR_STAT structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ + _MBG_API_ATTR int _MBG_API mbg_get_gps_bvar_stat( MBG_DEV_HANDLE dh, BVAR_STAT *p ) ; + + /** + Read the current board time using a ::TTM structure. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + Note: This call is pretty slow, so the mbg_get_hr_time_..() + group of calls should be used preferably. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::TTM structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ + _MBG_API_ATTR int _MBG_API mbg_get_gps_time( MBG_DEV_HANDLE dh, TTM *p ) ; + + /** + Write a ::TTM structure to a GPS receiver in order to set the + on-board date and time. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::TTM structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ + _MBG_API_ATTR int _MBG_API mbg_set_gps_time( MBG_DEV_HANDLE dh, const TTM *p ) ; + + /** + Read a ::PORT_PARM structure to retrieve the configuration + of the device's serial ports. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + Note: This function is obsolete since it is only + supported by a certain class of devices and can handle only + up to 2 ports. The generic function mbg_get_serial_settings() + should be used instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PORT_PARM structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_serial_settings() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_gps_port_parm( MBG_DEV_HANDLE dh, PORT_PARM *p ) ; + + /** + Write a ::PORT_PARM structure to configure the on-board + serial ports. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + Note: This function is obsolete since it is only + supported by a certain class of devices and can handle only + up to 2 ports. The generic function mbg_save_serial_settings() + should be used instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PORT_PARM structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_save_serial_settings() +*/ + _MBG_API_ATTR int _MBG_API mbg_set_gps_port_parm( MBG_DEV_HANDLE dh, const PORT_PARM *p ) ; + + /** + Read an ::ANT_INFO structure to retrieve status information of the GPS antenna. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + Note: Normally the antenna connection status can also be + determined by evaluation of the ::PCPS_TIME::signal or ::PCPS_HR_TIME::signal + fields. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ANT_INFO structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ + _MBG_API_ATTR int _MBG_API mbg_get_gps_ant_info( MBG_DEV_HANDLE dh, ANT_INFO *p ) ; + + /** + Read a time capture event from the on-board FIFO buffer using a ::TTM structure. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + Note: This call is pretty slow and has been obsoleted by + mbg_get_ucap_event() which should be used preferably, if supported + by the card. Anyway, this call is still supported for compatibility + with older cards. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::TTM structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_ucap_entries() + @see mbg_get_ucap_event() + @see mbg_clr_ucap_buff() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_gps_ucap( MBG_DEV_HANDLE dh, TTM *p ) ; + + /** + Read an ::ENABLE_FLAGS structure reporting whether certain outputs + shall be enabled immediately after the card's power-up, or only + after the card has synchronized to its input signal. + The macro _pcps_has_gps_data() or the API call mbg_dev_has_gps_data() + check whether this call is supported by a specific card. + + Note: Not all of the input signals specified for the + ::ENABLE_FLAGS structure can be modified individually. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::ENABLE_FLAGS structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see ::ENABLE_FLAGS + @see mbg_set_gps_enable_flags() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_gps_enable_flags( MBG_DEV_HANDLE dh, ENABLE_FLAGS *p ) ; + + /** + Write an ENABLE_FLAGS structure to configure whether certain outputs + shall be enabled immediately after the card's power-up, or only + after the card has synchronized to its input signal. + The macro _pcps_has_gps_data() or the API call mbg_dev_has_gps_data() + check whether this call is supported by a specific card. + + Note: Not all of the input signals specified for the + ENABLE_FLAGS structure can be modified individually. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ENABLE_FLAGS structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see ENABLE_FLAGS + @see mbg_get_gps_enable_flags() +*/ + _MBG_API_ATTR int _MBG_API mbg_set_gps_enable_flags( MBG_DEV_HANDLE dh, const ENABLE_FLAGS *p ) ; + + /** + Read a ::STAT_INFO structure to retrieve the status of the + GPS receiver, including mode of operation and numer of + visible/usable satellites. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::STAT_INFO structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see ::STAT_INFO +*/ + _MBG_API_ATTR int _MBG_API mbg_get_gps_stat_info( MBG_DEV_HANDLE dh, STAT_INFO *p ) ; + + /** + Sends a ::GPS_CMD to a GPS receiver. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::GPS_CMD + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see ::PC_GPS_CMD_BOOT, ::PC_GPS_CMD_INIT_SYS, ::PC_GPS_CMD_INIT_USER, ::PC_GPS_CMD_INIT_DAC +*/ + _MBG_API_ATTR int _MBG_API mbg_set_gps_cmd( MBG_DEV_HANDLE dh, const GPS_CMD *p ) ; + + /** + Read the current GPS receiver position using the ::POS structure + which contains different coordinate formats. + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device. + @param *p Pointer to a ::POS structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_set_gps_pos_xyz() + @see mbg_set_gps_pos_lla() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_gps_pos( MBG_DEV_HANDLE dh, POS *p ) ; + + /** + Preset the GPS receiver position using ::XYZ coordinates + (ECEF: WGS84 "Earth Centered, Earth fixed" kartesian coordinates). + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device. + @param p Position in ::XYZ format to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_set_gps_pos_lla() + @see mbg_get_gps_pos() +*/ + _MBG_API_ATTR int _MBG_API mbg_set_gps_pos_xyz( MBG_DEV_HANDLE dh, const XYZ p ) ; + + /** + Preset the GPS receiver position using ::LLA coordinates + (longitude, latitude, altitude) + The macro _pcps_is_gps() or the API call mbg_dev_is_gps() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device. + @param p Position in ::LLA format to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_set_gps_pos_xyz() + @see mbg_get_gps_pos() +*/ + _MBG_API_ATTR int _MBG_API mbg_set_gps_pos_lla( MBG_DEV_HANDLE dh, const LLA p ) ; + + /** + Read the configured length of the GPS antenna cable (::ANT_CABLE_LEN). + The cable delay is internally compensated by 5ns per meter cable. + The macro _pcps_has_cab_len() or the API call mbg_dev_has_cab_len() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device. + @param *p ::ANT_CABLE_LEN structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_cab_len() + @see mbg_set_gps_ant_cable_len() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_gps_ant_cable_len( MBG_DEV_HANDLE dh, ANT_CABLE_LEN *p ) ; + + /** + Write the length of the GPS antenna cable (::ANT_CABLE_LEN). + The cable delay is internally compensated by 5ns per meter cable. + The macro _pcps_has_cab_len() or the API call mbg_dev_has_cab_len() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device. + @param *p ::ANT_CABLE_LEN structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_cab_len() + @see mbg_get_gps_ant_cable_len() +*/ + _MBG_API_ATTR int _MBG_API mbg_set_gps_ant_cable_len( MBG_DEV_HANDLE dh, const ANT_CABLE_LEN *p ) ; + + /** + Read a ::RECEIVER_INFO structure from a card. + The macro _pcps_has_receiver_info() or the API call mbg_dev_has_receiver_info() + check whether this call is supported by a specific card. + + Note: Applications should call mbg_setup_receiver_info() + preferably, which also sets up a basic ::RECEIVER_INFO structure + for card which don't provide that structure by themselves. + + @param dh Valid handle to a Meinberg device. + @param *p Pointer to a ::RECEIVER_INFO structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_setup_receiver_info() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_gps_receiver_info( MBG_DEV_HANDLE dh, RECEIVER_INFO *p ) ; + + /** + Write the configuration for a single serial port using the ::PORT_SETTINGS_IDX + structure which contains both the ::PORT_SETTINGS and the port index value. + Except for the parameter types, this call is equivalent to mbg_set_gps_port_settings(). + The macro _pcps_has_receiver_info() or the API call mbg_dev_has_receiver_info() + check whether this call is supported by a specific card. + + Note: The function mbg_save_serial_settings() should be used preferably + to write new port configuration to the board. + + @param dh Valid handle to a Meinberg device. + @param *p Pointer to a ::PORT_SETTINGS_IDX structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_save_serial_settings() + @see mbg_set_gps_port_settings() + @see mbg_dev_has_receiver_info() +*/ + _MBG_API_ATTR int _MBG_API mbg_set_gps_port_settings_idx( MBG_DEV_HANDLE dh, const PORT_SETTINGS_IDX *p ) ; + + /** + Write the configuration for a single serial port using the ::PORT_SETTINGS + structure plus the port index. + Except for the parameter types, this call is equivalent to mbg_set_gps_port_settings_idx(). + The macro _pcps_has_receiver_info() or the API call mbg_dev_has_receiver_info() + check whether this call is supported by a specific card. + + Note: The function mbg_save_serial_settings() should be used preferably + to write new port configuration to the board. + + @param dh Valid handle to a Meinberg device. + @param *p Pointer to a ::PORT_SETTINGS structure to be filled up + @param idx Index of the serial port to be configured (starting from 0 ). + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_save_serial_settings() + @see mbg_set_gps_port_settings_idx() + @see mbg_dev_has_receiver_info() +*/ + _MBG_API_ATTR int _MBG_API mbg_set_gps_port_settings( MBG_DEV_HANDLE dh, const PORT_SETTINGS *p, int idx ) ; + + /** + Set up a ::RECEIVER_INFO structure for a device. + If the device supports the ::RECEIVER_INFO structure then the structure + is read from the device, otherwise a structure is set up using + default values depending on the device type. + The function mbg_get_device_info() must have been called before, + and the returned PCPS_DEV structure passed to this function. + + @param dh Valid handle to a Meinberg device. + @param *pdev Pointer to a ::PCPS_DEV structure returned by mbg_get_device_info() + @param *p Pointer to a ::RECEIVER_INFO structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_device_info() + @see mbg_dev_has_receiver_info() +*/ + _MBG_API_ATTR int _MBG_API mbg_setup_receiver_info( MBG_DEV_HANDLE dh, const PCPS_DEV *pdev, RECEIVER_INFO *p ) ; + + /** + Read all serial port settings and supported configuration parameters. + + The functions mbg_get_device_info() and mbg_setup_receiver_info() + must have been called before, and the returned ::PCPS_DEV and + ::RECEIVER_INFO structures must be passed to this function. + + The complementary function mbg_save_serial_settings() should be used + to write the modified serial port configuration back to the board. + + @param dh Valid handle to a Meinberg device. + @param *pdev Pointer to a ::PCPS_DEV structure. + @param *pcfg Pointer to a ::RECEIVER_PORT_CFG structure to be filled up. + @param *p_ri Pointer to a ::RECEIVER_INFO structure. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_device_info() + @see mbg_setup_receiver_info() + @see mbg_save_serial_settings() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_serial_settings( MBG_DEV_HANDLE dh, const PCPS_DEV *pdev, RECEIVER_PORT_CFG *pcfg, const RECEIVER_INFO *p_ri ) ; + + /** + Write the configuration settings for a single serial port to the board. + + Modifications to the serial port configuration should be made only + after mbg_get_serial_settings() had been called to read all serial port + settings and supported configuration parameters. + This function has finally to be called once for every serial port + the configuration of which has been modified. + + As also required by mbg_get_serial_settings(), the functions + mbg_get_device_info() and mbg_setup_receiver_info() must have been + called before, and the returned ::PCPS_DEV and ::RECEIVER_INFO structures + must be passed to this function. + + @param dh Valid handle to a Meinberg device + @param *pdev Pointer to a ::PCPS_DEV structure + @param *pcfg Pointer to a ::RECEIVER_PORT_CFG structure + @param port_num Index of the ::serial port to be saved + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_serial_settings() + @see mbg_get_device_info() + @see mbg_setup_receiver_info() +*/ + _MBG_API_ATTR int _MBG_API mbg_save_serial_settings( MBG_DEV_HANDLE dh, const PCPS_DEV *pdev, RECEIVER_PORT_CFG *pcfg, int port_num ) ; + + /** + Read the version code of the on-board PCI/PCIe interface ASIC. + The macro _pcps_has_asic_version() or the API call mbg_dev_has_asic_version() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCI_ASIC_VERSION type to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function + + @see mbg_dev_has_asic_version() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_asic_version( MBG_DEV_HANDLE dh, PCI_ASIC_VERSION *p ) ; + + /** + Read the features of the on-board PCI/PCIe interface ASIC. + The macro _pcps_has_asic_features() or the API call mbg_dev_has_asic_features() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device. + @param *p Pointer to a ::PCI_ASIC_FEATURES type to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_asic_features() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_asic_features( MBG_DEV_HANDLE dh, PCI_ASIC_FEATURES *p ) ; + + /** + Check if a specific device supports configurable time scales. + + By default the cards return UTC and/or local time. However, some cards + can be configured to return pure GPS time or TAI instead. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_time_scale_info() + @see mbg_set_time_scale_settings() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_time_scale( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Read a ::MBG_TIME_SCALE_INFO structure from a card telling which time scales + are supported by a card, and the current settings of the card. + + The macro _pcps_has_time_scale() or the API call mbg_dev_has_time_scale() + check whether this call is supported by a specific card. + See also the notes for mbg_dev_has_time_scale(). + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_TIME_SCALE_INFO structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_set_time_scale_settings() + @see mbg_dev_has_time_scale() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_time_scale_info( MBG_DEV_HANDLE dh, MBG_TIME_SCALE_INFO *p ) ; + + /** + Write a ::MBG_TIME_SCALE_SETTINGS structure to a card which determines + which time scale shall be represented by time stamps read from the card. + + The macro _pcps_has_time_scale() or the API call mbg_dev_has_time_scale() + check whether this call is supported by a specific card. + See also the notes for mbg_dev_has_time_scale(). + + The function mbg_get_time_scale_info() should have been called before + in order to determine which time scales are supported by the card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_TIME_SCALE_SETTINGS structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_time_scale_info() + @see mbg_dev_has_time_scale() +*/ + _MBG_API_ATTR int _MBG_API mbg_set_time_scale_settings( MBG_DEV_HANDLE dh, MBG_TIME_SCALE_SETTINGS *p ) ; + + /** + Check if a specific device supports reading/writing a GPS UTC parameter + set via the PC bus (reading/writing these parameters via the serial port + is supported by all GPS devices). + + The UTC parameters are normally received from the satellites' broadcasts + and contain the current time offset between GPT time and UTC, plus information + on a pending leap second. + + It may be useful to overwrite them to do some tests, or for applications + where a card is freewheeling. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_utc_parm() + @see mbg_set_utc_parm() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_utc_parm( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Read a ::UTC structure from a card. + + The macro _pcps_has_utc_parm() or the API call mbg_dev_has_utc_parm() + check whether this call is supported by a specific card. + See also the notes for mbg_dev_has_utc_parm(). + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::UTC structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_utc_parm() + @see mbg_set_utc_parm() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_utc_parm( MBG_DEV_HANDLE dh, UTC *p ) ; + + /** + Write a ::UTC structure to a card. + + This should only be done for testing, or if a card is operated in + freewheeling mode. If the card receives any satellites the settings + written to the board are overwritten by the parameters broadcasted + by the satellites. + + The macro _pcps_has_utc_parm() or the API call mbg_dev_has_utc_parm() + check whether this call is supported by a specific card. + See also the notes for mbg_dev_has_utc_parm(). + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a valid ::UTC structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_utc_parm() + @see mbg_get_utc_parm() +*/ + _MBG_API_ATTR int _MBG_API mbg_set_utc_parm( MBG_DEV_HANDLE dh, UTC *p ) ; + + /** + Read a ::PCPS_TIME_CYCLES structure that contains a ::PCPS_TIME structure + and a PC cycle counter value which can be used to compensate the latency + of the call, i.e. the program execution time until the time stamp has actually + been read from the board. + + This call is supported for any card, similar to mbg_get_time(). However, + the mbg_get_hr_time_cyles() call should be used preferably if supported by + the specific card since that call provides much better accuracy than this one. + + The cycle counter value corresponds to a value returned by QueryPerformanceCounter() + under Windows, and get_cycles() under Linux. On other operating systems the returned + cycles value is always 0. + + Applications should first pick up their own cycle counter value and then call + this function. The difference of the cycle counter values corresponds to the + latency of the call in units of the cycle counter clock frequency, e.g as reported + by QueryPerformanceFrequency() under Windows. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TIME_CYCLES structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_hr_time_cycles() + @see mbg_get_hr_time_comp() + @see mbg_get_hr_time() + @see mbg_get_time() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_time_cycles( MBG_DEV_HANDLE dh, PCPS_TIME_CYCLES *p ) ; + + /** + Read a ::PCPS_HR_TIME_CYCLES structure that contains a ::PCPS_HR_TIME structure + and a PC cycle counter value which can be used to compensate the latency + of the call, i.e. the program execution time until the time stamp has actually + been read from the board. + + The macro _pcps_has_hr_time() or the API call mbg_dev_has_hr_time() + check whether this call is supported by a specific card. + + The cycle counter value corresponds to a value returned by QueryPerformanceCounter() + under Windows, and get_cycles() under Linux. On other operating systems the returned + cycles value is always 0. + + Applications should first pick up their own cycle counter value and then call + this function. The difference of the cycle counter values corresponds to the + latency of the call in units of the cycle counter clock frequency, e.g as reported + by QueryPerformanceFrequency() under Windows. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_HR_TIME_CYCLES structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_hr_time_comp() + @see mbg_get_hr_time() + @see mbg_get_time_cycles() + @see mbg_get_time() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_hr_time_cycles( MBG_DEV_HANDLE dh, PCPS_HR_TIME_CYCLES *p ) ; + + /** + Read a ::PCPS_HR_TIME structure plus cycle counter value, and correct the + time stamp for the latency of the call as described for mbg_get_hr_time_cycles(), + then return the compensated time stamp and optionally the latency. + + The macro _pcps_has_hr_time() or the API call mbg_dev_has_hr_time() + check whether this call is supported by a specific card. + + The cycle counter value corresponds to a value returned by QueryPerformanceCounter() + under Windows, and get_cycles() under Linux. On other operating systems the returned + cycles value is always 0. + + Applications should first pick up their own cycle counter value and then call + this function. The difference of the cycle counter values corresponds to the + latency of the call in units of the cycle counter clock frequency, e.g as reported + by QueryPerformanceFrequency() under Windows. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_HR_TIME structure to be filled up + @param *hns_latency Optional pointer to an int32_t value to return + the latency in 100ns units. Pass NULL if not used. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_hr_time_comp() + @see mbg_get_hr_time() + @see mbg_get_time_cycles() + @see mbg_get_time() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_hr_time_comp( MBG_DEV_HANDLE dh, PCPS_HR_TIME *p, int32_t *hns_latency ) ; + + /** + Read an ::IRIG_INFO structure containing the configuration of an IRIG output + plus the possible settings supported by that output. + The macro _pcps_has_irig_tx() or the API call mbg_dev_has_irig_tx() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an ::IRIG_INFO structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_set_irig_tx_settings() + @see mbg_dev_has_irig_tx() + @see mbg_dev_is_irig_rx() + @see mbg_dev_has_irig() + @see \ref group_icode +*/ + _MBG_API_ATTR int _MBG_API mbg_get_irig_tx_info( MBG_DEV_HANDLE dh, IRIG_INFO *p ) ; + + /** + Write an ::IRIG_SETTINGS structure containing the configuration of an IRIG output. + The macro _pcps_has_irig_tx() or the API call mbg_dev_has_irig_tx() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an ::IRIG_INFO structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_irig_tx_info() + @see mbg_dev_has_irig_tx() + @see mbg_dev_is_irig_rx() + @see mbg_dev_has_irig() + @see \ref group_icode +*/ + _MBG_API_ATTR int _MBG_API mbg_set_irig_tx_settings( MBG_DEV_HANDLE dh, const IRIG_SETTINGS *p ) ; + + /** + Read a ::SYNTH structure containing the configuration of an optional + on-board programmable frequency synthesizer. + The macro _pcps_has_synth() or the API call mbg_dev_has_synth() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::SYNTH structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_synth() + @see mbg_set_synth() + @see mbg_get_synth_state() + @see \ref group_synth +*/ + _MBG_API_ATTR int _MBG_API mbg_get_synth( MBG_DEV_HANDLE dh, SYNTH *p ) ; + + /** + Write a ::SYNTH structure containing the configuration of an optional + on-board programmable frequency synthesizer. + The macro _pcps_has_synth() or the API call mbg_dev_has_synth() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::SYNTH structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_synth() + @see mbg_get_synth() + @see mbg_get_synth_state() + @see \ref group_synth +*/ + _MBG_API_ATTR int _MBG_API mbg_set_synth( MBG_DEV_HANDLE dh, const SYNTH *p ) ; + + /** + Read a ::SYNTH_STATE structure reporting the current state + of an optional on-board programmable frequency synthesizer. + The macro _pcps_has_synth() or the API call mbg_dev_has_synth() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::SYNTH_STATE structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_synth() + @see mbg_get_synth() + @see mbg_set_synth() + @see \ref group_synth +*/ + _MBG_API_ATTR int _MBG_API mbg_get_synth_state( MBG_DEV_HANDLE dh, SYNTH_STATE *p ) ; + + /** + Check if a specific device supports the mbg_get_fast_hr_timestamp_...() calls. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_fast_hr_timestamp_cycles() + @see mbg_get_fast_hr_timestamp_comp() + @see mbg_get_fast_hr_timestamp() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_fast_hr_timestamp( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Read a high resolution ::PCPS_TIME_STAMP_CYCLES structure via memory mapped access. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TIME_STAMP_CYCLES structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_fast_hr_timestamp() + @see mbg_get_fast_hr_timestamp_comp() + @see mbg_get_fast_hr_timestamp() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_fast_hr_timestamp_cycles( MBG_DEV_HANDLE dh, PCPS_TIME_STAMP_CYCLES *p ) ; + + /** + Read a high resolution ::PCPS_TIME_STAMP via memory mapped access, + and compensate the latency of the time stamp before it is returned. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TIME_STAMP structure to be filled up + @param *hns_latency Optionally receive the latency in hectonanoseconds + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_fast_hr_timestamp() + @see mbg_get_fast_hr_timestamp_cycles() + @see mbg_get_fast_hr_timestamp() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_fast_hr_timestamp_comp( MBG_DEV_HANDLE dh, PCPS_TIME_STAMP *p, int32_t *hns_latency ) ; + + /** + Read a high resolution ::PCPS_TIME_STAMP structure via memory mapped access. + + This function does not return or evaluate a cycles count, so the latency + of the call can not be determined. However, depending on the timer hardware + used as cycles counter it may take quite some time to read the cycles count + on some hardware architectures, so this call can be used to yield lower + latencies, under the restriction to be unable to determine the exact latency. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_TIME_STAMP structure to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_fast_hr_timestamp() + @see mbg_get_fast_hr_timestamp_comp() + @see mbg_get_fast_hr_timestamp_cycles() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_fast_hr_timestamp( MBG_DEV_HANDLE dh, PCPS_TIME_STAMP *p ) ; + + /** + Check if a specific device is a GPS receiver. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_is_gps( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device is a DCF77 receiver. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_is_dcf( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device is a MSF receiver. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_is_msf( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device is a WWVB receiver. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_is_wwvb( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device is a long wave signal receiver, e.g. DCF77, MSF or WWVB. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_is_lwr( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device is an IRIG receiver which supports + configuration of the IRIG input. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_irig_rx_info() + @see mbg_set_irig_rx_settings() + @see mbg_dev_has_irig_tx() + @see mbg_dev_has_irig() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_is_irig_rx( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device supports the HR_TIME functions. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_hr_time() + @see mbg_get_hr_time_cycles() + @see mbg_get_hr_time_comp() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_hr_time( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device supports configuration of antenna cable length. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_gps_ant_cable_len() + @see mbg_set_gps_ant_cable_len() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_cab_len( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device supports timezone / daylight saving configuration + using the ::TZDL structure. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_gps_tzdl() + @see mbg_set_gps_tzdl() + @see mbg_dev_has_tz() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_tzdl( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device supports timezone / daylight saving configuration + using the ::PCPS_TZDL structure. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_pcps_tzdl() + @see mbg_set_pcps_tzdl() + @see mbg_dev_has_tz() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_pcps_tzdl( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device supports timezone configuration + using the ::PCPS_TZCODE type. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_tzcode() + @see mbg_set_tzcode() + @see mbg_dev_has_tz() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_tzcode( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device supports any kind of timezone configuration. + This can be used e.g. to check if a specifig dialog or menu has to + be displayed. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_tzdl() + @see mbg_dev_has_pcps_tzdl() + @see mbg_dev_has_tzcode() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_tz( MBG_DEV_HANDLE dh, int *p ) ; + + /* (Intentionally excluded from Doxygen) + Check if a specific device supports setting an event time, i.e. + configure a %UTC time when the clock shall generate an event. + + Note: This is only supported by some special firmware. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_set_event_time() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_event_time( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device supports the ::RECEIVER_INFO structure and related calls. + Older GPS devices may not support that structure. + + The mbg_get_gps_receiver_info() call uses this call to decide whether a + ::RECEIVER_INFO can be read directly from a device, or whether a default + structure has to be set up using default values depending on the device type. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_gps_receiver_info() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_receiver_info( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device supports the mbg_clr_ucap_buff() call + used to clear a card's on-board time capture FIFO buffer. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_clr_ucap_buff() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_can_clr_ucap_buff( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device supports the mbg_get_ucap_entries() and + mbg_get_ucap_event() calls. + + If the card does not but it is a GPS card then the card provides + a time capture FIFO buffer and the obsolete mbg_get_gps_ucap() + call can be used to retrieve entries from the FIFO buffer. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_ucap_entries() + @see mbg_get_ucap_event() + @see mbg_clr_ucap_buff() + @see mbg_get_gps_ucap() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_ucap( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device provides an IRIG output which can + be configured. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_irig_tx_info() + @see mbg_set_irig_tx_settings() + @see mbg_dev_is_irig_rx() + @see mbg_dev_has_irig() + @see \ref group_icode + +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_irig_tx( MBG_DEV_HANDLE dh, int *p ) ; + + /* (Intentionally excluded from Doxygen) + Check if a specific device provides a serial output supporting + higher baud rates than older cards, i.e. ::DEFAULT_BAUD_RATES_DCF_HS + rather than ::DEFAULT_BAUD_RATES_DCF. + + The mbg_get_serial_settings() takes care of this, so applications + which use that call as suggested won't need to use this call directly. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_serial_settings() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_serial_hs( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device provides an input signal level value which + may be displayed, e.g. DCF77 or IRIG cards. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_signal( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device provides an modulation signal which may be + displayed, e.g. the second marks of a DCF77 AM receiver. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_mod( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device provides either an IRIG input or output. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_is_irig_rx() + @see mbg_dev_has_irig_tx() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_irig( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device provides a configurable ref time offset + required to convert the received time to %UTC. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_ref_offs() + @see mbg_set_ref_offs() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_ref_offs( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device supports the ::MBG_OPT_INFO/::MBG_OPT_SETTINGS + structures containing optional settings, controlled by flags. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_opt_info() + @see mbg_set_opt_settings() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_opt_flags( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device supports large configuration data structures + as have been introducesde with the GPS receivers. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_gps_data( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device provides a programmable frequency synthesizer. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_synth() + @see mbg_set_synth() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_synth( MBG_DEV_HANDLE dh, int *p ) ; + + /* (Intentionally excluded from Doxygen) + Check if a specific device supports the mbg_generic_io() call. + + Warning: That call is for debugging purposes and internal use only! + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_generic_io() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_generic_io( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device supports the mbg_get_asic_version() call. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_asic_version() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_asic_version( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Check if a specific device supports the mbg_get_asic_features() call. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_asic_features() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_asic_features( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Read a ::POUT_INFO_IDX array of current settings and configuration + options of a card's programmable pulse outputs. + The function mbg_setup_receiver_info() must have been called before, + and the returned ::RECEIVER_INFO structure passed to this function. + The function should only be called if the ::RECEIVER_INFO::n_prg_out + field (i.e. the number of programmable outputs on the board) is not 0. + + The array passed to this function to receive the returned data + must be able to hold at least ::RECEIVER_INFO::n_prg_out elements. + + @param dh Valid handle to a Meinberg device. + @param pii Pointer to a an array of ::POUT_INFO_IDX structures to be filled up + @param *p_ri Pointer to a ::RECEIVER_INFO structure returned by mbg_setup_receiver_info() + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_set_gps_pout_settings_idx() + @see mbg_set_gps_pout_settings() + @see mbg_setup_receiver_info() +*/ + _MBG_API_ATTR int _MBG_API mbg_get_gps_all_pout_info( MBG_DEV_HANDLE dh, POUT_INFO_IDX pii[], const RECEIVER_INFO *p_ri ) ; + + /** + Write the configuration for a single programmable pulse output using + the ::POUT_SETTINGS_IDX structure which contains both the ::POUT_SETTINGS + and the output index value. + Except for the parameter types, this call is equivalent to + mbg_set_gps_pout_settings(). + The function should only be called if the ::RECEIVER_INFO::n_prg_out field + (i.e. the number of programmable outputs on the board) is not 0, and the + output index value must be in the range 0..::RECEIVER_INFO::n_prg_out. + + @param dh Valid handle to a Meinberg device. + @param *p Pointer to a ::POUT_SETTINGS_IDX structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_gps_all_pout_info() + @see mbg_set_gps_pout_settings() +*/ + _MBG_API_ATTR int _MBG_API mbg_set_gps_pout_settings_idx( MBG_DEV_HANDLE dh, const POUT_SETTINGS_IDX *p ) ; + + /** + Write the configuration for a single programmable pulse output using + the ::POUT_SETTINGS structure plus the index of the output to be configured. + Except for the parameter types, this call is equivalent to + mbg_set_gps_pout_settings_idx(). + The function should only be called if the ::RECEIVER_INFO::n_prg_out field + (i.e. the number of programmable outputs on the board) is not 0, and the + output index value must be in the range 0..::RECEIVER_INFO::n_prg_out. + + @param dh Valid handle to a Meinberg device. + @param *p Pointer to a ::POUT_SETTINGS structure to be written + @param idx Index of the programmable pulse output to be configured (starting from 0 ). + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_gps_all_pout_info() + @see mbg_set_gps_pout_settings_idx() +*/ + _MBG_API_ATTR int _MBG_API mbg_set_gps_pout_settings( MBG_DEV_HANDLE dh, const POUT_SETTINGS *p, int idx ) ; + + /** + Read a card's IRQ status information which includes flags indicating + whether IRQs are currently enabled, and whether IRQ support by a card + is possibly unsafe due to the firmware and interface chip version. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PCPS_IRQ_STAT_INFO variable to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + */ + _MBG_API_ATTR int _MBG_API mbg_get_irq_stat_info( MBG_DEV_HANDLE dh, PCPS_IRQ_STAT_INFO *p ) ; + + /** + Check if a specific device provides simple LAN interface API calls. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_lan_if_info() + @see mbg_get_ip4_state() + @see mbg_get_ip4_settings() + @see mbg_set_ip4_settings() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_lan_intf( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Read LAN interface information from a card which supports this. + The macro _pcps_has_lan_intf() or the API call mbg_dev_has_lan_intf() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::LAN_IF_INFO variable to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_lan_intf() + @see mbg_get_ip4_state() + @see mbg_get_ip4_settings() + @see mbg_set_ip4_settings() + */ + _MBG_API_ATTR int _MBG_API mbg_get_lan_if_info( MBG_DEV_HANDLE dh, LAN_IF_INFO *p ) ; + + /** + Read LAN IPv4 state from a card which supports this. + The macro _pcps_has_lan_intf() or the API call mbg_dev_has_lan_intf() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::IP4_SETTINGS variable to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_lan_intf() + @see mbg_get_lan_if_info() + @see mbg_get_ip4_settings() + @see mbg_set_ip4_settings() + */ + _MBG_API_ATTR int _MBG_API mbg_get_ip4_state( MBG_DEV_HANDLE dh, IP4_SETTINGS *p ) ; + + /** + Read LAN IPv4 settings from a card which supports this. + The macro _pcps_has_lan_intf() or the API call mbg_dev_has_lan_intf() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::IP4_SETTINGS variable to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_lan_intf() + @see mbg_get_lan_if_info() + @see mbg_get_ip4_state() + @see mbg_set_ip4_settings() + */ + _MBG_API_ATTR int _MBG_API mbg_get_ip4_settings( MBG_DEV_HANDLE dh, IP4_SETTINGS *p ) ; + + /** + Write LAN IPv4 settings to a card which supports this. + The macro _pcps_has_lan_intf() or the API call mbg_dev_has_lan_intf() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device. + @param *p ::IP4_SETTINGS structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_lan_intf() + @see mbg_get_lan_if_info() + @see mbg_get_ip4_settings() +*/ + _MBG_API_ATTR int _MBG_API mbg_set_ip4_settings( MBG_DEV_HANDLE dh, const IP4_SETTINGS *p ) ; + + /** + Check if a specific device provides PTP configuration/status calls. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to an int which is set 0 or != 0 unless the call fails. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_ptp_state() + @see mbg_get_ptp_cfg_info() + @see mbg_set_ptp_cfg_settings() +*/ + _MBG_API_ATTR int _MBG_API mbg_dev_has_ptp( MBG_DEV_HANDLE dh, int *p ) ; + + /** + Read PTP/IEEE1588 status from a card which supports this. + The macro _pcps_ddev_has_ptp() or the API call mbg_dev_has_ptp() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PTP_CFG_INFO variable to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_ptp() + @see mbg_get_ptp_cfg_info() + @see mbg_set_ptp_cfg_settings() + */ + _MBG_API_ATTR int _MBG_API mbg_get_ptp_state( MBG_DEV_HANDLE dh, PTP_STATE *p ) ; + + /** + Read PTP/IEEE1588 config info and current settings from a card which supports this. + The macro _pcps_ddev_has_ptp() or the API call mbg_dev_has_ptp() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::PTP_CFG_INFO variable to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_ptp() + @see mbg_get_ptp_state() + @see mbg_set_ptp_cfg_settings() + */ + _MBG_API_ATTR int _MBG_API mbg_get_ptp_cfg_info( MBG_DEV_HANDLE dh, PTP_CFG_INFO *p ) ; + + /** + Write PTP/IEEE1588 configuration settings to a card which supports this. + The macro _pcps_ddev_has_ptp() or the API call mbg_dev_has_ptp() + check whether this call is supported by a specific card. + + @param dh Valid handle to a Meinberg device. + @param *p ::PTP_CFG_SETTINGS structure to be written + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_ptp() + @see mbg_get_ptp_state() + @see mbg_get_ptp_cfg_info() +*/ + _MBG_API_ATTR int _MBG_API mbg_set_ptp_cfg_settings( MBG_DEV_HANDLE dh, const PTP_CFG_SETTINGS *p ) ; + + /** + Read system time and card time from the kernel driver. The kernel + driver reads the current system time plus a HR time structure from + a card immediately after each other. The returned info structure also + contains some cycles counts to be able to determine the execution times + required to read those time stamps. + + The advantage of this call compared to mbg_get_time_info_tstamp() is + that this call also returns the card's status. On the other hand, reading + the HR time from the card may block e.g. if another application accesses + the board. + + This call makes a mbg_get_hr_time_cycles() call internally so the macro + _pcps_has_hr_time() or the API call mbg_dev_has_hr_time() can be + used to check whether this call is supported with a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_TIME_INFO_HRT variable to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_hr_time() + @see mbg_get_time_info_tstamp() + */ + _MBG_API_ATTR int _MBG_API mbg_get_time_info_hrt( MBG_DEV_HANDLE dh, MBG_TIME_INFO_HRT *p ) ; + + /** + This call is similar to mbg_get_time_info_hrt() except that a + mbg_get_fast_hr_timestamp_cycles() call is made internally, so the macro + _pcps_has_fast_hr_timestamp() or the API call mbg_dev_has_fast_hr_timestamp() + can be used to check whether this call is supported with a specific card. + + @param dh Valid handle to a Meinberg device + @param *p Pointer to a ::MBG_TIME_INFO_TSTAMP variable to be filled up + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_dev_has_fast_hr_timestamp() + @see mbg_get_time_info_hrt() + */ + _MBG_API_ATTR int _MBG_API mbg_get_time_info_tstamp( MBG_DEV_HANDLE dh, MBG_TIME_INFO_TSTAMP *p ) ; + + /** + Read the CPU affinity of a process, i.e. on which of the available + CPUs the process can be executed. + + @param pid The process ID. + @param *p Pointer to a ::MBG_CPU_SET variable which contains a mask of CPUs. + + @return ::MBG_SUCCESS or error code returned by the system call. + + @see mbg_set_process_affinity() + @see mbg_set_current_process_affinity_to_cpu() + */ + _MBG_API_ATTR int _MBG_API mbg_get_process_affinity( MBG_PROCESS_ID pid, MBG_CPU_SET *p ) ; + + /** + Set the CPU affinity of a process, i.e. on which of the available + CPUs the process is allowed to be executed. + + @param pid The process ID. + @param *p Pointer to a ::MBG_CPU_SET variable which contains a mask of CPUs. + + @return ::MBG_SUCCESS or error code returned by the system call. + + @see mbg_get_process_affinity() + @see mbg_set_current_process_affinity_to_cpu() + */ + _MBG_API_ATTR int _MBG_API mbg_set_process_affinity( MBG_PROCESS_ID pid, MBG_CPU_SET *p ) ; + + /** + Set the CPU affinity of a process for a single CPU only, i.e. the process + may only be executed on that single CPU. + + @param cpu_num The number of the CPU. + + @return ::MBG_SUCCESS or error code returned by the system call. + + @see mbg_get_process_affinity() + @see mbg_set_process_affinity() + */ + _MBG_API_ATTR int _MBG_API mbg_set_current_process_affinity_to_cpu( int cpu_num ) ; + + /** + Create a new execution thread for the current process. + This function is only implemented for targets which support threads. + + @param p_ti Pointer to a ::MBG_THREAD_INFO structure to be filled up. + @param fnc The name of the thread function to be started. + @param arg A generic argument passed to the thread function. + + @return ::MBG_SUCCESS or error code returned by the system call. + + @see mbg_thread_stop() + @see mbg_thread_sleep_interruptible() + @see mbg_thread_set_affinity() + */ + _MBG_API_ATTR int _MBG_API mbg_thread_create( MBG_THREAD_INFO *p_ti, MBG_THREAD_FNC_RET_VAL (MBG_THREAD_FNC_ATTR *fnc)(void *), void *arg ) ; + + /** + Stop a thread which has been created by mbg_thread_create(). Wait + until the thread has finished and release all resources. + This function is only implemented for targets which support threads. + + @param p_ti Pointer to a ::MBG_THREAD_INFO structure associated with the thread. + + @return ::MBG_SUCCESS or error code returned by the system call. + + @see mbg_thread_create() + @see mbg_thread_sleep_interruptible() + @see mbg_thread_set_affinity() + */ + _MBG_API_ATTR int _MBG_API mbg_thread_stop( MBG_THREAD_INFO *p_ti ) ; + + /** + Let the current thread sleep for a certain interval unless a signal is + received indicating the thread should terminate. + This function is only implemented for targets which support threads. + + @param p_ti Pointer to a ::MBG_THREAD_INFO structure associated with the thread. + @param sleep_ms The number of milliseconds to sleep + @return 0 if the sleep interval has expired normally + 1 if a signal to terminate has been received + <0 if an error has occurred + + @see mbg_thread_create() + @see mbg_thread_stop() + @see mbg_thread_set_affinity() + */ + _MBG_API_ATTR int _MBG_API mbg_thread_sleep_interruptible( MBG_THREAD_INFO *p_ti, ulong sleep_ms ) ; + + /** + Set the CPU affinity of a single thread, i.e. on which of the available + CPUs the thread is allowed to be executed. + This function is only implemented for targets which support thread affinity. + + @param p_ti Pointer to a ::MBG_THREAD_INFO structure associated with the thread. + @param *p Pointer to a ::MBG_CPU_SET variable which contains a mask of CPUs. + + @return ::MBG_SUCCESS or error code returned by the system call. + + @see mbg_thread_create() + @see mbg_thread_stop() + @see mbg_thread_sleep_interruptible() + */ + _MBG_API_ATTR int _MBG_API mbg_thread_set_affinity( MBG_THREAD_INFO *p_ti, MBG_CPU_SET *p ) ; + + /** + Set up a ::MBG_POLL_THREAD_INFO structure and start a new thread + which runs the mbg_xhrt_poll_thread_fnc() function. + This function is only implemented for targets which support threads. + + @param *p_pti Pointer to a ::MBG_POLL_THREAD_INFO structure. + @param dh the handle of the device to be polled. + @param freq_hz The initial cycles frequency, if known, in Hz. + @param sleep_ms the sleep interval for the poll thread function in ms. + If this parameter is 0 then the default sleep interval is used. + + @return ::MBG_SUCCESS on success, + ::MBG_ERR_NOT_SUPP_BY_DEV if the device to poll does not support HR time + else the result of mbg_thread_create() + + @see mbg_xhrt_poll_thread_fnc() + @see mbg_xhrt_poll_thread_stop() + @see mbg_get_xhrt_time_as_pcps_hr_time() + @see mbg_get_xhrt_time_as_filetime() + @see mbg_get_xhrt_cycles_frequency() + */ + _MBG_API_ATTR int _MBG_API mbg_xhrt_poll_thread_create( MBG_POLL_THREAD_INFO *p_pti, MBG_DEV_HANDLE dh, MBG_PC_CYCLES_FREQUENCY freq_hz, int sleep_ms ) ; + + /** + Stop a polling thread started by mbg_xhrt_poll_thread_create() + and release all associated resources. + + @param *p_pti Pointer to a ::MBG_POLL_THREAD_INFO structure. + + @return the result of mbg_thread_stop() + + @see mbg_xhrt_poll_thread_fnc() + @see mbg_xhrt_poll_thread_create() + @see mbg_get_xhrt_time_as_pcps_hr_time() + @see mbg_get_xhrt_time_as_filetime() + @see mbg_get_xhrt_cycles_frequency() + */ + _MBG_API_ATTR int _MBG_API mbg_xhrt_poll_thread_stop( MBG_POLL_THREAD_INFO *p_pti ) ; + + /** + Retrieve a time stamp in PCPS_HR_TIME format which is extrapolated + using the system's current cycles counter value and a time stamp + plus associated cycles counter value saved by the polling thread. + See mbg_xhrt_poll_thread_fnc() for details and limitations. + This function is only implemented for targets which support threads. + + @param *p Pointer to a ::MBG_XHRT_INFO structure used to retrieve data from the polling thread. + @param *p_hrt Pointer to a ::PCPS_HR_TIME structure to be filled up. + + @return MBG_SUCCESS or another return value from the polling thread's IOCTL call. + + @see mbg_xhrt_poll_thread_fnc() + @see mbg_xhrt_poll_thread_create() + @see mbg_xhrt_poll_thread_stop() + @see mbg_get_xhrt_time_as_filetime() + @see mbg_get_xhrt_cycles_frequency() + */ + _MBG_API_ATTR int _MBG_API mbg_get_xhrt_time_as_pcps_hr_time( MBG_XHRT_INFO *p, PCPS_HR_TIME *p_hrt ) ; + + /** + Retrieve a time stamp in FILETIME format which is extrapolated + using the system's current cycles counter value and a time stamp + plus associated cycles counter value saved by the polling thread. + See mbg_xhrt_poll_thread_fnc() for details and limitations. + Since FILETIME is a Windows specific type this function is only + implemented under Windows. + + @param *p Pointer to a ::MBG_XHRT_INFO structure used to retrieve data from the polling thread. + @param *p_ft Pointer to a ::FILETIME structure to be filled up. + + @return MBG_SUCCESS or another return value from the polling thread's IOCTL call. + + @see mbg_xhrt_poll_thread_fnc() + @see mbg_xhrt_poll_thread_create() + @see mbg_xhrt_poll_thread_stop() + @see mbg_get_xhrt_time_as_pcps_hr_time() + @see mbg_get_xhrt_cycles_frequency() + */ + _MBG_API_ATTR int _MBG_API mbg_get_xhrt_time_as_filetime( MBG_XHRT_INFO *p, FILETIME *p_ft ) ; + + /** + Retrieve the frequency of the system's cycles counter as determined + by the device polling thread. + See mbg_xhrt_poll_thread_fnc() for details and limitations. + This function is only implemented for targets which support threads. + + @param *p Pointer to a ::MBG_XHRT_INFO structure used to retrieve data from the polling thread. + @param *p_freq_hz Pointer to a ::MBG_PC_CYCLES_FREQUENCY variable in which the frequency is returned. + @return a status code from the polling thread: MBG_SUCCESS or an IOCTL error code. + + @see mbg_xhrt_poll_thread_fnc() + @see mbg_xhrt_poll_thread_create() + @see mbg_xhrt_poll_thread_stop() + @see mbg_get_xhrt_time_as_pcps_hr_time() + @see mbg_get_xhrt_time_as_filetime() + */ + _MBG_API_ATTR int _MBG_API mbg_get_xhrt_cycles_frequency( MBG_XHRT_INFO *p, MBG_PC_CYCLES_FREQUENCY *p_freq_hz ) ; + + /** + Retrieve the default system's cycles counter frequency from the kernel driver. + + @param dh handle of the device to which the IOCTL call is sent. + @param *p Pointer of a ::MBG_PC_CYCLES_FREQUENCY variable to be filled up. + + @return ::MBG_SUCCESS or error code returned by device I/O control function. + + @see mbg_get_default_cycles_frequency() + */ + _MBG_API_ATTR int _MBG_API mbg_get_default_cycles_frequency_from_dev( MBG_DEV_HANDLE dh, MBG_PC_CYCLES_FREQUENCY *p ) ; + + /** + Retrieve the default system's cycles counter frequency. + + @note This may not be supported on all target platforms, in which case the + returned frequency is 0 and the mbg_get_default_cycles_frequency_from_dev() + call should be used. + + @return the default cycles counter frequency in Hz, or 0 if the value is not available. + + @see mbg_get_default_cycles_frequency_from_dev() +*/ + _MBG_API_ATTR MBG_PC_CYCLES_FREQUENCY _MBG_API mbg_get_default_cycles_frequency( void ) ; + + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + + +#if defined( MBG_TGT_WIN32 ) || defined( MBG_TGT_UNIX ) + +static __mbg_inline +void mbg_chk_tstamp64_leap_sec( uint64_t *tstamp64, PCPS_TIME_STATUS_X *status ) +{ + if ( *status & ( PCPS_LS_ANN | PCPS_LS_ENB ) ) + { + time_t t = (uint32_t) ( *tstamp64 >> 32 ); + struct tm tm = *gmtime( &t ); + + // Handle leap second and status + if ( tm.tm_hour == 0 && tm.tm_min == 0 && tm.tm_sec == 0 ) + { + if ( *status & PCPS_LS_ANN ) + { + // Set leap second enabled flag on rollover to the leap second and clear announce flag + *status &= ~PCPS_LS_ANN; + *status |= PCPS_LS_ENB; + + // Decrement interpolated second to avoid automated overflow during the leap second. + // Second 59 appears for the second time. + *tstamp64 -= PCPS_HRT_BIN_FRAC_SCALE; + } + else + if ( *status & PCPS_LS_ENB ) // Clear bits when leap second expires and 0:00:00 UTC is reached + *status &= ~( PCPS_LS_ANN | PCPS_LS_ENB ); + } + } + +} // mbg_chk_tstamp64_leap_sec + +#endif // defined( MBG_TGT_WIN32 ) || defined( MBG_TGT_UNIX ) + + + +static __mbg_inline +void mbg_init_pc_cycles_frequency( MBG_DEV_HANDLE dh, MBG_PC_CYCLES_FREQUENCY *p ) +{ + if ( *p == 0 ) + mbg_get_default_cycles_frequency_from_dev( dh, p ); + +} // mbg_init_pc_cycles_frequency + + + +#if MBG_TGT_HAS_64BIT_TYPES + +static __mbg_inline +uint64_t pcps_time_stamp_to_uint64( const PCPS_TIME_STAMP *ts ) +{ + return ( ( (uint64_t) ts->sec ) << 32 ) + ts->frac; + +} // pcps_time_stamp_to_uint64 + + + +static __mbg_inline +void uint64_to_pcps_time_stamp( PCPS_TIME_STAMP *ts, uint64_t n ) +{ + ts->sec = (uint32_t) ( n >> 32 ); + ts->frac = (uint32_t) ( n & 0xFFFFFFFFUL ); + +} // uint64_to_pcps_time_stamp + +#endif + + + +#if defined( _USE_PACK ) // set default alignment + #pragma pack() +#endif + +/* End of header body */ + + +#undef _ext + +#endif /* _MBGDEVIO_H */ + diff --git a/mbglib/common/mbgerror.h b/mbglib/common/mbgerror.h new file mode 100755 index 0000000..f51c61d --- /dev/null +++ b/mbglib/common/mbgerror.h @@ -0,0 +1,156 @@ + +/************************************************************************** + * + * $Id: mbgerror.h 1.4 2008/12/05 13:28:50 martin REL_M $ + * $Name: $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Error codes used with Meinberg devices and drivers. + * The codes can be translated into an OS dependent error code. + * + * ----------------------------------------------------------------------- + * $Log: mbgerror.h $ + * Revision 1.4 2008/12/05 13:28:50 martin + * Added new code MBG_ERR_IRQ_UNSAFE. + * Revision 1.3 2008/02/26 14:50:14Z daniel + * Added codes: + * MBG_ERR_NOT_SUPP_ON_OS, MBG_ERR_LIB_NOT_COMPATIBLE, + * MBG_ERR_N_COM_EXCEEDS_SUPP, MBG_ERR_N_STR_EXCEEDS_SUPP + * Added doxygen compatible comments. + * Revision 1.2 2007/09/27 07:26:22Z martin + * Define STATUS_SUCCESS for Windows if not in kernel mode. + * Revision 1.1 2007/09/26 08:08:54Z martin + * Initial revision. + * + **************************************************************************/ + +#ifndef _MBGERROR_H +#define _MBGERROR_H + + +/* Other headers to be included */ + +#include + +#ifdef _MBGERROR + #define _ext + #define _DO_INIT +#else + #define _ext extern +#endif + + +/* Start of header body */ + +/** + @defgroup group_error_codes Error codes + + Error codes used with Meinberg devices and drivers. + The codes will be translated into an OS dependent error code, + when they are returned to the calling function. + + For Windows, these codes are made positive and or'ed with 0xE0000000 afterwards. + + Example: Code -19 (#MBG_ERR_GENERIC) will be converted to 0xE0000013 under Windows. + + @{ +*/ + +// Attention!! +// These error codes below must fit exactly to the corresponding codes that are evaluated in user space. +// For Windows, they are located in messages.mc/.h in mbgsvctl.dll + +#define MBG_SUCCESS PCPS_SUCCESS /**< 0, no error */ + +// The codes below are defined in pcpsdefs.h and returned by the firmware: +#define MBG_ERR_STIME PCPS_ERR_STIME /**< -1, invalid date/time/status passed */ +#define MBG_ERR_CFG PCPS_ERR_CFG /**< -2, invalid parms with a PCPS_CFG_GROUP cmd */ + +// Codes returned by the driver's low level functions: +#define MBG_ERR_GENERIC -19 /**< Generic error */ +#define MBG_ERR_TIMEOUT -20 /**< Timeout accessing the board */ +#define MBG_ERR_FW_ID -21 /**< Invalid firmware ID */ +#define MBG_ERR_NBYTES -22 /**< The number of parameter bytes + passed to the board did not match + the number of bytes expected. */ +#define MBG_ERR_INV_TIME -23 /**< The device's time is not valid */ +#define MBG_ERR_FIFO -24 /**< The device's FIFO is empty, though + it shouldn't be */ +#define MBG_ERR_NOT_READY -25 /**< Board is temporary unable to respond + (during initialization after RESET) */ +#define MBG_ERR_INV_TYPE -26 /**< Board did not recognize data type */ + + +// Codes returned by the driver's high level functions: +#define MBG_ERR_NO_MEM -27 /**< Failed to allocate memory */ +#define MBG_ERR_CLAIM_RSRC -28 /**< Failed to claim port or mem resource */ +#define MBG_ERR_DEV_NOT_SUPP -29 /**< Specified device type not supported by driver */ +#define MBG_ERR_INV_DEV_REQUEST -30 /**< IOCTL call not supported by driver */ +#define MBG_ERR_NOT_SUPP_BY_DEV -31 /**< Cmd or feature not supported by device */ +#define MBG_ERR_USB_ACCESS -32 /**< USB access failed */ +#define MBG_ERR_CYCLIC_TIMEOUT -33 /**< Cyclic event (IRQ, etc.) didn't occur */ +#define MBG_ERR_NOT_SUPP_ON_OS -34 /**< The function is not supported on this operating system */ +#define MBG_ERR_LIB_NOT_COMPATIBLE -35 /**< The installed version of the DLL/shared object is not + compatible with version used to build the application */ +#define MBG_ERR_N_COM_EXCEEDS_SUPP -36 /**< The number of COM ports provided by the device + exceeds the maximum supported by the driver */ +#define MBG_ERR_N_STR_EXCEEDS_SUPP -37 /**< The number of string formats supported by the device + exceeds the maximum supported by the driver */ +#define MBG_ERR_IRQ_UNSAFE -38 /**< The enabled IRQs are unsafe with this firmware/ASIC version */ + + +// Codes used with DOS TSRs only: +#define MBG_ERR_INV_INTNO -40 /**< Invalid interrupt number */ +#define MBG_ERR_NO_DRIVER -41 /**< A driver could not be found */ +#define MBG_ERR_DRV_VERSION -42 /**< The driver is too old */ + +/** @} */ // endgroup + +// Depending on the operating system, the codes above have to be converted before +// they are sent up to user space +#if defined( MBG_TGT_WIN32 ) + #if !defined( STATUS_SUCCESS ) // not in kernel mode + #define STATUS_SUCCESS 0 + #endif + + #define _mbg_err_to_os( _c ) \ + ( ( _c == MBG_SUCCESS ) ? STATUS_SUCCESS : ( abs( _c ) | 0xE0000000 ) ) +#endif + + +// If no specific conversion has been defined +// then use the original codes. +#if !defined( _mbg_err_to_os ) + #define _mbg_err_to_os( _c ) ( _c ) +#endif + + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + +/* (no header definitions found) */ + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +/* End of header body */ + +#undef _ext +#undef _DO_INIT + +#endif /* _MBGERROR_H */ diff --git a/mbglib/common/mbggenio.h b/mbglib/common/mbggenio.h new file mode 100755 index 0000000..a325203 --- /dev/null +++ b/mbglib/common/mbggenio.h @@ -0,0 +1,173 @@ + +/************************************************************************** + * + * $Id: mbggenio.h 1.5.1.2 2011/02/01 12:12:18 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions for generic port I/O. + * + * ----------------------------------------------------------------------- + * $Log: mbggenio.h $ + * Revision 1.5.1.2 2011/02/01 12:12:18 martin + * Revision 1.5.1.1 2011/01/31 17:29:26 martin + * Account for modified resource handling under *BSD. + * Revision 1.5 2008/12/05 13:27:33 martin + * Generally put macro arguments in brackets for evaluation + * to avoid potential side effects. + * There has been a problem with an improper written outp() macro + * in the Borland C 3.1 library's conio.h file. + * Support mapped I/O resources. + * Revision 1.4 2008/02/05 13:38:57 martin + * Added support for QNX. + * Revision 1.3 2007/03/21 14:48:56 martin + * Use standard inp(), outp() also under Windows since the generic + * Windows functions READ_PORT_UCHA(), etc., are not very + * compatible across DDK versions. + * Revision 1.2 2007/03/02 10:23:34Z martin + * Renamed generic port I/O macros. + * Fully support Linux, *BSD, Windows, NetWare, DOS, and OS/2. + * Revision 1.1 2006/09/20 10:47:21 martin + * + **************************************************************************/ + +#ifndef _MBGGENIO_H +#define _MBGGENIO_H + + +/* Other headers to be included */ + +#include + + +/* Start of header body */ + +#ifdef __cplusplus +extern "C" { +#endif + + +#if defined( MBG_TGT_LINUX ) + + #if MBG_USE_MM_IO_FOR_PCI + #define _mbg_inp8( _d, _p ) ( readb( (_p) ) ) + #define _mbg_inp16( _d, _p ) ( readw( (_p) ) ) + #define _mbg_inp32( _d, _p ) ( readl( (_p) ) ) + + #define _mbg_outp8( _d, _p, _v ) writeb( (_v), (_p) ) + #define _mbg_outp16( _d, _p, _v ) writew( (_v), (_p) ) + #define _mbg_outp32( _d, _p, _v ) writel( (_v), (_p) ) + #else + #define _mbg_inp8( _d, _p ) ( (uint8_t) inb( (_p) ) ) + #define _mbg_inp16( _d, _p ) ( (uint16_t) inw( (_p) ) ) + #define _mbg_inp32( _d, _p ) ( (uint32_t) inl( (_p) ) ) + + #define _mbg_outp8( _d, _p, _v ) outb( (_v), (_p) ) + #define _mbg_outp16( _d, _p, _v ) outw( (_v), (_p) ) + #define _mbg_outp32( _d, _p, _v ) outl( (_v), (_p) ) + #endif + +#elif defined( MBG_TGT_BSD ) + + #include + #include + #include + + #define _mbg_inp8( _d, _p ) ( (uint8_t) bus_space_read_1( ( (_d)->rsrc_info.port[0].bsd.bst ), \ + ( (_d)->rsrc_info.port[0].bsd.bsh ), (_p) ) ) + #define _mbg_inp16( _d, _p ) ( (uint16_t) bus_space_read_2( ( (_d)->rsrc_info.port[0].bsd.bst ), \ + ( (_d)->rsrc_info.port[0].bsd.bsh ), (_p) ) ) + #define _mbg_inp32( _d, _p ) ( (uint32_t) bus_space_read_4( ( (_d)->rsrc_info.port[0].bsd.bst), \ + ( (_d)->rsrc_info.port[0].bsd.bsh ), (_p) ) ) + + #define _mbg_outp8( _d, _p, _v ) bus_space_write_1( ( (_d)->rsrc_info.port[0].bsd.bst ), \ + ((_d)->rsrc_info.port[0].bsd.bsh ), (_p), (_v) ) + #define _mbg_outp16( _d, _p, _v ) bus_space_write_2( ( (_d)->rsrc_info.port[0].bsd.bst ), \ + ((_d)->rsrc_info.port[0].bsd.bsh ), (_p), (_v) ) + #define _mbg_outp32( _d, _p, _v ) bus_space_write_4( ( (_d)->rsrc_info.port[0].bsd.bst ), \ + ((_d)->rsrc_info.port[0].bsd.bsh ), (_p), (_v) ) + +#elif defined( MBG_TGT_WIN32 ) + + #define _mbg_inp8( _d, _p ) ( (uint8_t) inp( (_p) ) ) + #define _mbg_inp16( _d, _p ) ( (uint16_t) inpw( (_p) ) ) + #define _mbg_inp32( _d, _p ) ( (uint32_t) inpd( (_p) ) ) + + #define _mbg_outp8( _d, _p, _v ) outp( (_p), (_v) ) + #define _mbg_outp16( _d, _p, _v ) outpw( (_p), (_v) ) + #define _mbg_outp32( _d, _p, _v ) outpd( (_p), (_v) ) + +#elif defined( MBG_TGT_DOS ) || defined( MBG_TGT_NETWARE ) || defined( MBG_TGT_OS2 ) + + #include + + #if defined( MBG_TGT_DOS ) || defined( MBG_TGT_OS2 ) + #include + #endif + + #define _mbg_inp8( _d, _p ) ( (uint8_t) inp( (_p) ) ) + #define _mbg_inp16( _d, _p ) ( (uint16_t) inpw( (_p) ) ) + #define _mbg_inp32( _d, _p ) ( (uint32_t) inpd( (_p) ) ) + + #define _mbg_outp8( _d, _p, _v ) outp( (_p), (_v) ) + #define _mbg_outp16( _d, _p, _v ) outpw( (_p), (_v) ) + #define _mbg_outp32( _d, _p, _v ) outpd( (_p), (_v) ) + +#elif defined( MBG_TGT_QNX ) + + #if defined( MBG_TGT_QNX_NTO ) // compiling for QNX Neutrino + // don't know if we have to distinguish between different compilers + #include + + // ATTENTION: mmap_device_io() must be called on non-x86 architectures + // to remap the ports, otherwise a segmentation fault will occur if + // the port I/O functions are being called. + + #define _mbg_inp8( _d, _p ) ( (uint8_t) in8( (_p) ) ) + #define _mbg_inp16( _d, _p ) ( (uint16_t) in16( (_p) ) ) + #define _mbg_inp32( _d, _p ) ( (uint32_t) in32( (_p) ) ) + + #define _mbg_outp8( _d, _p, _v ) out8( (_p), (_v) ) + #define _mbg_outp16( _d, _p, _v ) out16( (_p), (_v) ) + #define _mbg_outp32( _d, _p, _v ) out32( (_p), (_v) ) + + #else // compiling for QNX 4 + + #if defined( __WATCOMC__ ) // using Watcom C + + // Include prototypes of port I/O functions + // which should match the calls used in the mbglib functions. + #include + + #define _mbg_inp8( _d, _p ) ( (uint8_t) inp( (_p) ) ) + #define _mbg_inp16( _d, _p ) ( (uint16_t) inpw( (_p) ) ) + #define _mbg_inp32( _d, _p ) ( (uint32_t) inpd( (_p) ) ) + + #define _mbg_outp8( _d, _p, _v ) outp( (_p), (_v) ) + #define _mbg_outp16( _d, _p, _v ) outpw( (_p), (_v) ) + #define _mbg_outp32( _d, _p, _v ) outpd( (_p), (_v) ) + + #endif + + #endif + +#endif + + + +#define _mbg_inp16_to_cpu( _d, _p ) _mbg16_to_cpu( _mbg_inp16( (_d), (_p) ) ) +#define _mbg_inp32_to_cpu( _d, _p ) _mbg32_to_cpu( _mbg_inp32( (_d), (_p) ) ) + +#define _mbg_outp16_to_mbg( _d, _p, _v ) _mbg_outp16( (_d), (_p), _cpu_to_mbg16( (_v) ) ) +#define _mbg_outp32_to_mbg( _d, _p, _v ) _mbg_outp32( (_d), (_p), _cpu_to_mbg32( (_v) ) ) + + + +#ifdef __cplusplus +} +#endif + +/* End of header body */ + +#endif /* _MBGGENIO_H */ diff --git a/mbglib/common/mbggeo.h b/mbglib/common/mbggeo.h new file mode 100755 index 0000000..c375570 --- /dev/null +++ b/mbglib/common/mbggeo.h @@ -0,0 +1,297 @@ + +/************************************************************************** + * + * $Id: mbggeo.h 1.10 2008/09/03 14:54:28 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes for mbggeo.c. + * + * Terms used: + * + * WGS84 world geodetic system of 1984 + * + * XYZ WGS84 earth centered, earth fixed (ECEF) kartesian + * coordinates + * + * LLA longitude, latitude, altitude depending on the reference + * ellipsoid used. + * + * DMS degrees, minutes, seconds + * + * ----------------------------------------------------------------------- + * $Log: mbggeo.h $ + * Revision 1.10 2008/09/03 14:54:28 martin + * Added macros to swap endianess of structures. + * Revision 1.9 2008/01/17 09:31:33 daniel + * Made comments compatible for doxygen parser. + * No sourcecode changes. + * Revision 1.8 2004/11/09 14:16:00Z martin + * Redefined interface data types using C99 fixed-size definitions. + * Revision 1.7 2003/02/14 13:23:04Z martin + * Omit inclusion of mystd.h. + * Revision 1.6 2003/01/13 15:17:15 martin + * Structures were defined with default alignment which + * could result in different data sizes on different platforms. + * Revision 1.5 2002/12/18 14:46:41Z martin + * Removed variable USER_POS meinberg. + * Updated function prototypes. + * Revision 1.4 2002/12/12 12:04:25Z martin + * Moved some definitions here. + * Use standard file format. + * + **************************************************************************/ + +#ifndef _MBGGEO_H +#define _MBGGEO_H + + +/* Other headers to be included */ + +#include +#include + +#ifdef _MBGGEO + #define _ext + #define _DO_INIT +#else + #define _ext extern +#endif + + +/* Start of header body */ + +#if defined( _USE_PACK ) // set byte alignment + #pragma pack( 1 ) +#endif + + +/** + Geographic longitude or latitude in [degrees, minutes, seconds] + longitude East latitude North and positve, South or West angles negative + */ +typedef struct +{ + uint16_t prefix; /**< 'N', 'E', 'S' or 'W' */ + uint16_t deg; /**< [0...90 (lat) or 0...180 (lon)] */ + uint16_t min; /**< [0...59] */ + double sec; /**< [0...59.999] */ +} DMS; + +// The corresponding macro _mbg_swab_dms() is defined in gpsdefs.h. +#define _mbg_swab_dms( _p ) \ +{ \ + _mbg_swab16( &(_p)->prefix ); \ + _mbg_swab16( &(_p)->deg ); \ + _mbg_swab16( &(_p)->min ); \ + _mbg_swab_double( &(_p)->sec ); \ +} + + + +typedef struct +{ + XYZ xyz; /**< always WGS84 ECEF coordinates */ + LLA lla; /**< depending on the ellipsoid used for reference */ + DMS longitude; /**< longitude in degrees, minutes, seconds */ + DMS latitude; /**< latitude in degrees, minutes, seconds */ + int16_t ellipsoid; /**< ellipsoid used for reference */ +} POS; + +#define _mbg_swab_pos( _p ) \ +{ \ + _mbg_swab_xyz( (_p)->xyz ); \ + _mbg_swab_lla( (_p)->lla ); \ + _mbg_swab_dms( &(_p)->longitude ); \ + _mbg_swab_dms( &(_p)->latitude ); \ + _mbg_swab16( &(_p)->ellipsoid ); \ +} + + + +typedef struct +{ + CSUM csum; /* checksum of the remaining bytes */ + int16_t valid; /* flag data are valid */ + + char name[40]; + POS pos; /* the position in WGS84 ECEF coords and LLA */ + double det; + + +/* The components below hold the results of intermediate terms */ +/* computed in complete_user_pos(). */ + +/* The sin.., cos.., nt.. and ut.. variables are used to compute the */ +/* enu_dcos[] parameters of a SV structure in xyz_to_ead(). */ + +/* The e_radius.. variables are used to compute the latitude, longitude */ +/* and altitude from ECEF coordinates in lla_to_xyz(). */ + + double sin_lat; /* sin( latitude ) */ + double cos_lat; /* cos( latitude ) */ + double sin_lon; /* sin( longitude ) */ + double cos_lon; /* cos( longitude ) */ + + double nt1; /* -sin_lat * cos_lon */ + double nt2; /* -sin_lat * sin_lon */ + double utx; /* cos_lat * cos_lon */ + double uty; /* cos_lat * sin_lon */ + + double e_radius; /* N */ + double e_radius_alt; /* N + h */ + +} USER_POS; + + + +typedef struct +{ + CSUM csum; /* checksum of the remaining bytes */ + int16_t valid; /* flag data are valid */ + + char name[40]; + XYZ dxyz; /* offset from the WGS84 ECEF coords */ + double a; /* semi major axis */ + double rcp_f; /* reciproke of flatness */ + +/* the variables below will be computed in the init_mbggeo() function: */ + + double f; /* flatness */ + double b; /* semi minor axis */ + double sqr_e; /* square of numerical eccentricity */ +} ELLIPSOID; + + + +enum { WGS84, BESSEL, N_ELLIPSOIDS }; + +_ext ELLIPSOID ellipsoid[N_ELLIPSOIDS] +#ifdef _DO_INIT + = { { 0, 0, + "WGS 84", + { 0.0, 0.0, 0.0 }, + 6378137.0, + 298.257223563 + }, + + { 0, 0, + "Bessel", + { -128.0, 481.0, 664.0 }, + 6377397.0, + 299.15 + } + + } +#endif +; + + +/* WGS84 constants used */ + +_ext double OMEGADOTe /* earth's rotation rate [rad/sec] */ +#ifdef _DO_INIT + = 7.2921151467e-5 +#endif +; + +_ext double mue /* earth's gravitational constant [m^3/sec^2] */ +#ifdef _DO_INIT + = 3.986005e14 +#endif +; + + + +_ext double vr_to_doppler; + + +_ext double gps_pi +#ifdef _DO_INIT + = 3.1415926535898 +#endif +; + +_ext double gps_c0 +#ifdef _DO_INIT + = 2.99792458e8 +#endif +; + + +#ifndef PI + #define PI 3.1415926535897932 +#endif + + +_ext double pi +#ifdef _DO_INIT + = PI +#endif +; + + +_ext double r2d +#ifdef _DO_INIT + = 180.0 / PI +#endif +; + + +_ext double d2r +#ifdef _DO_INIT + = PI / 180.0 +#endif +; + + +/* variables for simplifying computations */ + +_ext double gps_two_pi; +_ext double sqrt_mue; /* sqrt( mue ) */ + + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + + void dms_to_rad( const DMS *dms, double *rad ) ; + void rad_to_dms( const double *rad, DMS *dms, const char prefix ) ; + void dms_to_lla( POS *pos ) ; + void lla_to_dms( POS *pos ) ; + void lla_to_xyz( USER_POS *pos ) ; + void xyz_to_lla( POS *pos, void (*cyclic_func)( void ) ) ; + void dms_to_xyz( USER_POS *pos ) ; + void setup_user_pos_from_dms( USER_POS *user ) ; + void setup_user_pos_from_lla( USER_POS *user ) ; + void setup_user_pos_from_xyz( USER_POS *user, void (*cyclic_func)( void ) ) ; + double distance( XYZ xyz_1, XYZ xyz_2 ) ; + void init_mbggeo( void ) ; + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +#if defined( _USE_PACK ) // set default alignment + #pragma pack() +#endif + +/* End of header body */ + +#undef _ext +#undef _DO_INIT + +#endif /* _MBGGEO_H */ + diff --git a/mbglib/common/mbgioctl.h b/mbglib/common/mbgioctl.h new file mode 100755 index 0000000..c2150e7 --- /dev/null +++ b/mbglib/common/mbgioctl.h @@ -0,0 +1,450 @@ + +/************************************************************************** + * + * $Id: mbgioctl.h 1.24 2009/12/15 15:34:59 daniel REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions used with device driver IOCTL. + * + * ----------------------------------------------------------------------- + * $Log: mbgioctl.h $ + * Revision 1.24 2009/12/15 15:34:59 daniel + * Support reading the raw IRIG data bits for firmware versions + * which support this feature. + * Revision 1.23 2009/09/29 15:08:41Z martin + * Support retrieving time discipline info. + * Revision 1.22 2009/08/17 13:48:17 martin + * Moved specific definition of symbol _HAVE_IOCTL_WITH_SIZE from + * mbgdevio.c here and renamed it to _MBG_SUPP_VAR_ACC_SIZE. + * Revision 1.21 2009/06/19 12:18:53 martin + * Added PCPS_GIVE_IRIG_TIME command and associated definitions. + * Fixed a declaration which might have led to syntax errors. + * Revision 1.20 2009/06/09 10:02:36Z daniel + * Support PTP configuration and state. + * Support simple LAN interface configuration. + * Revision 1.19 2009/03/19 15:17:59 martin + * Support reading MM timestamps without cycles. + * Support UTC parms and configurable time scales. + * For consistent naming renamed IOCTL_GET_FAST_HR_TIMESTAMP + * to IOCTL_GET_FAST_HR_TIMESTAMP_CYCLES. + * Added IOCTL_DEV_HAS_IRIG_CTRL_BITS and IOCTL_GET_IRIG_CTRL_BITS. + * Revision 1.18 2008/12/11 10:32:56Z martin + * Added _cmd_from_ioctl_code() macro for Linux. + * Added IOCTL codes for .._has_asic_version() and .._has_asic_features(). + * Added IOCTL codes for ..._is_msf(), .._is_lwr(), .._is_wwvb(). + * Added IOCTL codes IOCTL_GET_IRQ_STAT_INFO, IOCTL_GET_CYCLES_FREQUENCY, + * IOCTL_HAS_FAST_HR_TIMESTAMP, and IOCTL_GET_FAST_HR_TIMESTAMP. + * Revision 1.17 2008/01/17 09:35:15 daniel + * Added ioctl calls IOCTL_GET_MAPPED_MEM_ADDR and + * IOCTL_UNMAP_MAPPED_MEM. + * Cleanup for PCI ASIC version and features. + * Revision 1.16 2007/09/25 10:37:04Z martin + * Added macro _cmd_from_ioctl_code() for Windows. + * Revision 1.15 2007/05/21 15:00:01Z martin + * Unified naming convention for symbols related to ref_offs. + * Revision 1.14 2007/03/02 10:27:03 martin + * Preliminary support for *BSD. + * Preliminary _cmd_from_ioctl(). + * Revision 1.13 2006/03/10 10:36:54 martin + * Added support for programmable pulse outputs. + * Revision 1.12 2005/06/02 10:22:05Z martin + * Added IOCTL code IOCTL_GET_SYNTH_STATE. + * Added IOCTL codes IOCTL_DEV_HAS_GENERIC_IO, + * IOCTL_PCPS_GENERIC_IO, and IOCTL_GET_SYNTH_STATE. + * Revision 1.11 2005/01/14 10:21:11Z martin + * Added IOCTLs which query device features. + * Revision 1.10 2004/12/09 11:03:36Z martin + * Support configuration of on-board frequency synthesizer. + * Revision 1.9 2004/11/09 12:49:41Z martin + * Modifications were required in order to be able to configure IRIG + * settings of cards which provide both IRIG input and output. + * The existing codes have been renamed with .._RX.. and are used to + * configure the IRIG receiver (input). New codes have been defined + * used to configure the IRIG transmitter. + * Renamed IOCTL_GET_GPS_STAT to IOCTL_GET_GPS_BVAR_STAT. + * Use more specific data types than generic types. + * Modified IOCTL codes used for hardware debugging. + * Revision 1.8 2004/09/06 15:46:04Z martin + * Changed definition of IOCTL codes to support syntax used + * with Linux kernel 2.6.x. + * Account for renamed symbols. + * Revision 1.7 2004/04/07 10:08:11 martin + * Added IOCTL codes used to trigger hardware debug events. + * Revision 1.6 2003/12/22 15:37:18Z martin + * Added codes to read ASIC version, and read times + * with associated cycle counter values. + * Revision 1.5 2003/06/19 09:02:30Z martin + * New codes IOCTL_GET_PCPS_UCAP_ENTRIES and IOCTL_GET_PCPS_UCAP_EVENT. + * Renamed IOCTL_PCPS_CLR_CAP_BUFF to IOCTL_PCPS_CLR_UCAP_BUFF. + * Cleaned up IOCTL code names related to PCPS_TZDL. + * Reordered upper IOCTL code numbers again. + * Revision 1.4 2003/04/09 13:50:39Z martin + * Re-organized IOCTL codes. + * Supports Win32. + * Added missing pragma pack(). + * Revision 1.3 2003/02/14 13:20:08Z martin + * Include mbggeo.h instead of mygeo.h. + * Revision 1.2 2001/11/30 09:52:48 martin + * Added support for event_time which, however, requires + * a custom GPS firmware. + * Revision 1.1 2001/03/05 16:34:22 MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _MBGIOCTL_H +#define _MBGIOCTL_H + + +/* Other headers to be included */ + +#include +#include +#include +#include + +#if defined( MBG_TGT_LINUX ) + + #include + + // a magic number used to generate IOCTL cmd codes + #define IOTYPE 'M' + + #define _MBG_IO _IO + #define _MBG_IOR _IOR + #define _MBG_IOW _IOW + + #define _cmd_from_ioctl_code( _ioc ) \ + _IOC_NR( _ioc ) + +#elif defined( MBG_TGT_BSD ) + + #include + + // a magic number used to generate IOCTL cmd codes + #define IOTYPE 'M' + + #define _MBG_IO _IO + #define _MBG_IOR _IOR + #define _MBG_IOW _IOW + +#elif defined( MBG_TGT_WIN32 ) + + #if !defined( _MBG_SUPP_VAR_ACC_SIZE ) + // Windows supports IOCTL commands where the sizes of + // input and output buffer can be specified dynamically. + #define _MBG_SUPP_VAR_ACC_SIZE 1 + #endif + + #ifndef _KDD_ // must be defined in the KDDs' SOURCES file + #include + #include + #endif + + #if !defined( MBG_TGT_WIN32_NON_PNP ) + #ifdef _MBGIOCTL + #include // instance the GUID + #else + #include // just define the GUID + #endif + #endif + + #ifdef DEFINE_GUID // don't break compiles of drivers that + // include this header but don't want the + // GUIDs + + // ClassGuid = { 78A1C341-4539-11d3-B88D-00C04FAD5171 } + DEFINE_GUID( GUID_MEINBERG_DEVICE, + 0x78A1C341L, 0x4539, 0x11D3, + 0xB8, 0x8D, 0x00, 0xC0, 0x4F, 0xAD, 0x51, 0x71 ); + #endif + + // Device type in the "User Defined" range." + #define PCPS_TYPE 40000 + + // IOCTL function codes from 0x800 to 0xFFF are for customer use. + #define _MBG_IOCTL_BIAS 0x930 + + #define _MBG_IO( _t, _n ) \ + CTL_CODE( PCPS_TYPE, _MBG_IOCTL_BIAS + _n, METHOD_BUFFERED, FILE_READ_ACCESS ) + + #define _MBG_IOR( _t, _n, _sz ) \ + _MBG_IO( _t, _n ) + + #define _MBG_IOW _MBG_IOR + + #define _cmd_from_ioctl_code( _ioc ) \ + ( ( ( (_ioc) >> 2 ) & 0x0FFF ) - _MBG_IOCTL_BIAS ) + +#endif + + +#if !defined( _MBG_SUPP_VAR_ACC_SIZE ) + // Many operating systems don't support specifying the sizes of IOCTL + // input and output buffers dynamically, so we disable this by default. + #define _MBG_SUPP_VAR_ACC_SIZE 0 +#endif + + +#ifdef _MBGIOCTL + #define _ext + #define _DO_INIT +#else + #define _ext extern +#endif + + +#if defined( _USE_PACK ) // set byte alignment + #pragma pack( 1 ) +#endif + + +/* Start of header body */ + +// read general driver info, device info, and status port +#define IOCTL_GET_PCPS_DRVR_INFO _MBG_IOR( IOTYPE, 0x00, PCPS_DRVR_INFO ) +#define IOCTL_GET_PCPS_DEV _MBG_IOR( IOTYPE, 0x01, PCPS_DEV ) +#define IOCTL_GET_PCPS_STATUS_PORT _MBG_IOR( IOTYPE, 0x02, PCPS_STATUS_PORT ) + +// generic read/write operations (preliminary) +#define IOCTL_PCPS_GENERIC_READ _MBG_IO( IOTYPE, 0x03 ) +#define IOCTL_PCPS_GENERIC_WRITE _MBG_IO( IOTYPE, 0x04 ) +#define IOCTL_PCPS_GENERIC_READ_GPS _MBG_IO( IOTYPE, 0x05 ) +#define IOCTL_PCPS_GENERIC_WRITE_GPS _MBG_IO( IOTYPE, 0x06 ) + +// normal direct read/write operations +#define IOCTL_GET_PCPS_TIME _MBG_IOR( IOTYPE, 0x10, PCPS_TIME ) +#define IOCTL_SET_PCPS_TIME _MBG_IOW( IOTYPE, 0x11, PCPS_STIME ) + +#define IOCTL_GET_PCPS_SYNC_TIME _MBG_IOR( IOTYPE, 0x12, PCPS_TIME ) + +#define IOCTL_GET_PCPS_TIME_SEC_CHANGE _MBG_IOR( IOTYPE, 0x13, PCPS_TIME ) + +#define IOCTL_GET_PCPS_HR_TIME _MBG_IOR( IOTYPE, 0x14, PCPS_HR_TIME ) + +// the next one is supported with custom GPS firmware only: +#define IOCTL_SET_PCPS_EVENT_TIME _MBG_IOW( IOTYPE, 0x15, PCPS_TIME_STAMP ) + +#define IOCTL_GET_PCPS_SERIAL _MBG_IOR( IOTYPE, 0x16, PCPS_SERIAL ) +#define IOCTL_SET_PCPS_SERIAL _MBG_IOW( IOTYPE, 0x17, PCPS_SERIAL ) + +#define IOCTL_GET_PCPS_TZCODE _MBG_IOR( IOTYPE, 0x18, PCPS_TZCODE ) +#define IOCTL_SET_PCPS_TZCODE _MBG_IOW( IOTYPE, 0x19, PCPS_TZCODE ) + +#define IOCTL_GET_PCPS_TZDL _MBG_IOR( IOTYPE, 0x1A, PCPS_TZDL ) +#define IOCTL_SET_PCPS_TZDL _MBG_IOW( IOTYPE, 0x1B, PCPS_TZDL ) + +#define IOCTL_GET_REF_OFFS _MBG_IOR( IOTYPE, 0x1C, MBG_REF_OFFS ) +#define IOCTL_SET_REF_OFFS _MBG_IOW( IOTYPE, 0x1D, MBG_REF_OFFS ) + +#define IOCTL_GET_MBG_OPT_INFO _MBG_IOR( IOTYPE, 0x1E, MBG_OPT_INFO ) +#define IOCTL_SET_MBG_OPT_SETTINGS _MBG_IOW( IOTYPE, 0x1F, MBG_OPT_SETTINGS ) + +#define IOCTL_GET_PCPS_IRIG_RX_INFO _MBG_IOR( IOTYPE, 0x20, IRIG_INFO ) +#define IOCTL_SET_PCPS_IRIG_RX_SETTINGS _MBG_IOW( IOTYPE, 0x21, IRIG_SETTINGS ) + +#define IOCTL_PCPS_CLR_UCAP_BUFF _MBG_IO( IOTYPE, 0x22 ) +#define IOCTL_GET_PCPS_UCAP_ENTRIES _MBG_IOR( IOTYPE, 0x23, PCPS_UCAP_ENTRIES ) +#define IOCTL_GET_PCPS_UCAP_EVENT _MBG_IOR( IOTYPE, 0x24, PCPS_HR_TIME ) + + +#define IOCTL_GET_GPS_TZDL _MBG_IOR( IOTYPE, 0x25, TZDL ) +#define IOCTL_SET_GPS_TZDL _MBG_IOW( IOTYPE, 0x26, TZDL ) + +#define IOCTL_GET_GPS_SW_REV _MBG_IOR( IOTYPE, 0x27, SW_REV ) + +#define IOCTL_GET_GPS_BVAR_STAT _MBG_IOR( IOTYPE, 0x28, BVAR_STAT ) + +#define IOCTL_GET_GPS_TIME _MBG_IOR( IOTYPE, 0x29, TTM ) +#define IOCTL_SET_GPS_TIME _MBG_IOW( IOTYPE, 0x2A, TTM ) + +#define IOCTL_GET_GPS_PORT_PARM _MBG_IOR( IOTYPE, 0x2B, PORT_PARM ) +#define IOCTL_SET_GPS_PORT_PARM _MBG_IOW( IOTYPE, 0x2C, PORT_PARM ) + +#define IOCTL_GET_GPS_ANT_INFO _MBG_IOR( IOTYPE, 0x2D, ANT_INFO ) + +#define IOCTL_GET_GPS_UCAP _MBG_IOR( IOTYPE, 0x2E, TTM ) + +#define IOCTL_GET_GPS_ENABLE_FLAGS _MBG_IOR( IOTYPE, 0x2F, ENABLE_FLAGS ) +#define IOCTL_SET_GPS_ENABLE_FLAGS _MBG_IOW( IOTYPE, 0x30, ENABLE_FLAGS ) + +#define IOCTL_GET_GPS_STAT_INFO _MBG_IOR( IOTYPE, 0x31, STAT_INFO ) + +#define IOCTL_SET_GPS_CMD _MBG_IOW( IOTYPE, 0x32, GPS_CMD ) + +#define IOCTL_GET_GPS_IDENT _MBG_IOR( IOTYPE, 0x33, IDENT ) + +#define IOCTL_GET_GPS_POS _MBG_IOR( IOTYPE, 0x34, POS ) +#define IOCTL_SET_GPS_POS_XYZ _MBG_IOW( IOTYPE, 0x35, XYZ ) +#define IOCTL_SET_GPS_POS_LLA _MBG_IOW( IOTYPE, 0x36, LLA ) + +#define IOCTL_GET_GPS_ANT_CABLE_LEN _MBG_IOR( IOTYPE, 0x37, ANT_CABLE_LEN ) +#define IOCTL_SET_GPS_ANT_CABLE_LEN _MBG_IOW( IOTYPE, 0x38, ANT_CABLE_LEN ) + +#define IOCTL_GET_GPS_RECEIVER_INFO _MBG_IOR( IOTYPE, 0x39, RECEIVER_INFO ) +#define IOCTL_GET_GPS_ALL_STR_TYPE_INFO _MBG_IO( IOTYPE, 0x3A ) // size variable +#define IOCTL_GET_GPS_ALL_PORT_INFO _MBG_IO( IOTYPE, 0x3B ) // size variable + +#define IOCTL_SET_GPS_PORT_SETTINGS_IDX _MBG_IOW( IOTYPE, 0x3C, PORT_SETTINGS_IDX ) + +#define IOCTL_GET_PCI_ASIC_VERSION _MBG_IOR( IOTYPE, 0x3D, PCI_ASIC_VERSION ) + +#define IOCTL_GET_PCPS_TIME_CYCLES _MBG_IOR( IOTYPE, 0x3E, PCPS_TIME_CYCLES ) +#define IOCTL_GET_PCPS_HR_TIME_CYCLES _MBG_IOR( IOTYPE, 0x3F, PCPS_HR_TIME_CYCLES ) + +#define IOCTL_GET_PCPS_IRIG_TX_INFO _MBG_IOR( IOTYPE, 0x40, IRIG_INFO ) +#define IOCTL_SET_PCPS_IRIG_TX_SETTINGS _MBG_IOW( IOTYPE, 0x41, IRIG_SETTINGS ) + +#define IOCTL_GET_SYNTH _MBG_IOR( IOTYPE, 0x42, SYNTH ) +#define IOCTL_SET_SYNTH _MBG_IOW( IOTYPE, 0x43, SYNTH ) + + +#define IOCTL_DEV_IS_GPS _MBG_IOR( IOTYPE, 0x44, int ) +#define IOCTL_DEV_IS_DCF _MBG_IOR( IOTYPE, 0x45, int ) +#define IOCTL_DEV_IS_IRIG_RX _MBG_IOR( IOTYPE, 0x46, int ) + +#define IOCTL_DEV_HAS_HR_TIME _MBG_IOR( IOTYPE, 0x47, int ) +#define IOCTL_DEV_HAS_CAB_LEN _MBG_IOR( IOTYPE, 0x48, int ) +#define IOCTL_DEV_HAS_TZDL _MBG_IOR( IOTYPE, 0x49, int ) +#define IOCTL_DEV_HAS_PCPS_TZDL _MBG_IOR( IOTYPE, 0x4A, int ) +#define IOCTL_DEV_HAS_TZCODE _MBG_IOR( IOTYPE, 0x4B, int ) +#define IOCTL_DEV_HAS_TZ _MBG_IOR( IOTYPE, 0x4C, int ) +#define IOCTL_DEV_HAS_EVENT_TIME _MBG_IOR( IOTYPE, 0x4D, int ) +#define IOCTL_DEV_HAS_RECEIVER_INFO _MBG_IOR( IOTYPE, 0x4E, int ) +#define IOCTL_DEV_CAN_CLR_UCAP_BUFF _MBG_IOR( IOTYPE, 0x4F, int ) +#define IOCTL_DEV_HAS_UCAP _MBG_IOR( IOTYPE, 0x50, int ) +#define IOCTL_DEV_HAS_IRIG_TX _MBG_IOR( IOTYPE, 0x51, int ) +#define IOCTL_DEV_HAS_SERIAL_HS _MBG_IOR( IOTYPE, 0x52, int ) +#define IOCTL_DEV_HAS_SIGNAL _MBG_IOR( IOTYPE, 0x53, int ) +#define IOCTL_DEV_HAS_MOD _MBG_IOR( IOTYPE, 0x54, int ) +#define IOCTL_DEV_HAS_IRIG _MBG_IOR( IOTYPE, 0x55, int ) +#define IOCTL_DEV_HAS_REF_OFFS _MBG_IOR( IOTYPE, 0x56, int ) +#define IOCTL_DEV_HAS_OPT_FLAGS _MBG_IOR( IOTYPE, 0x57, int ) +#define IOCTL_DEV_HAS_GPS_DATA _MBG_IOR( IOTYPE, 0x58, int ) +#define IOCTL_DEV_HAS_SYNTH _MBG_IOR( IOTYPE, 0x59, int ) +#define IOCTL_DEV_HAS_GENERIC_IO _MBG_IOR( IOTYPE, 0x5A, int ) + +#define IOCTL_PCPS_GENERIC_IO _MBG_IO( IOTYPE, 0x5B ) + +#define IOCTL_GET_SYNTH_STATE _MBG_IOR( IOTYPE, 0x5C, SYNTH_STATE ) + +#define IOCTL_GET_GPS_ALL_POUT_INFO _MBG_IO( IOTYPE, 0x5D ) // size variable +#define IOCTL_SET_GPS_POUT_SETTINGS_IDX _MBG_IOW( IOTYPE, 0x5E, POUT_SETTINGS_IDX ) + +#define IOCTL_GET_MAPPED_MEM_ADDR _MBG_IOR( IOTYPE, 0x5F, PCPS_MAPPED_MEM ) +#define IOCTL_UNMAP_MAPPED_MEM _MBG_IOR( IOTYPE, 0x60, PCPS_MAPPED_MEM ) + +#define IOCTL_GET_PCI_ASIC_FEATURES _MBG_IOR( IOTYPE, 0x61, PCI_ASIC_FEATURES ) + +#define IOCTL_HAS_PCI_ASIC_FEATURES _MBG_IOR( IOTYPE, 0x62, int ) +#define IOCTL_HAS_PCI_ASIC_VERSION _MBG_IOR( IOTYPE, 0x63, int ) + +#define IOCTL_DEV_IS_MSF _MBG_IOR( IOTYPE, 0x64, int ) +#define IOCTL_DEV_IS_LWR _MBG_IOR( IOTYPE, 0x65, int ) +#define IOCTL_DEV_IS_WWVB _MBG_IOR( IOTYPE, 0x66, int ) + +#define IOCTL_GET_IRQ_STAT_INFO _MBG_IOR( IOTYPE, 0x67, PCPS_IRQ_STAT_INFO ) +#define IOCTL_GET_CYCLES_FREQUENCY _MBG_IOR( IOTYPE, 0x68, MBG_PC_CYCLES_FREQUENCY ) + +#define IOCTL_HAS_FAST_HR_TIMESTAMP _MBG_IOR( IOTYPE, 0x69, int ) +#define IOCTL_GET_FAST_HR_TIMESTAMP_CYCLES _MBG_IOR( IOTYPE, 0x6A, PCPS_TIME_STAMP_CYCLES ) +#define IOCTL_GET_FAST_HR_TIMESTAMP _MBG_IOR( IOTYPE, 0x6B, PCPS_TIME_STAMP ) + +#define IOCTL_DEV_HAS_GPS_TIME_SCALE _MBG_IOR( IOTYPE, 0x6C, int ) +#define IOCTL_GET_GPS_TIME_SCALE_INFO _MBG_IOR( IOTYPE, 0x6D, MBG_TIME_SCALE_INFO ) +#define IOCTL_SET_GPS_TIME_SCALE_SETTINGS _MBG_IOW( IOTYPE, 0x6E, MBG_TIME_SCALE_SETTINGS ) + +#define IOCTL_DEV_HAS_GPS_UTC_PARM _MBG_IOR( IOTYPE, 0x6F, int ) +#define IOCTL_GET_GPS_UTC_PARM _MBG_IOR( IOTYPE, 0x70, UTC ) +#define IOCTL_SET_GPS_UTC_PARM _MBG_IOW( IOTYPE, 0x71, UTC ) + +#define IOCTL_DEV_HAS_IRIG_CTRL_BITS _MBG_IOR( IOTYPE, 0x72, int ) +#define IOCTL_GET_IRIG_CTRL_BITS _MBG_IOR( IOTYPE, 0x73, MBG_IRIG_CTRL_BITS ) + +#define IOCTL_DEV_HAS_LAN_INTF _MBG_IOR( IOTYPE, 0x74, int ) +#define IOCTL_GET_LAN_IF_INFO _MBG_IOR( IOTYPE, 0x75, LAN_IF_INFO ) +#define IOCTL_GET_IP4_STATE _MBG_IOR( IOTYPE, 0x76, IP4_SETTINGS ) +#define IOCTL_GET_IP4_SETTINGS _MBG_IOR( IOTYPE, 0x77, IP4_SETTINGS ) +#define IOCTL_SET_IP4_SETTINGS _MBG_IOW( IOTYPE, 0x78, IP4_SETTINGS ) + +#define IOCTL_DEV_IS_PTP _MBG_IOR( IOTYPE, 0x79, int ) +#define IOCTL_DEV_HAS_PTP _MBG_IOR( IOTYPE, 0x7A, int ) +#define IOCTL_GET_PTP_STATE _MBG_IOR( IOTYPE, 0x7B, PTP_STATE ) +#define IOCTL_GET_PTP_CFG_INFO _MBG_IOR( IOTYPE, 0x7C, PTP_CFG_INFO ) +#define IOCTL_SET_PTP_CFG_SETTINGS _MBG_IOW( IOTYPE, 0x7D, PTP_CFG_SETTINGS ) + +#define IOCTL_DEV_HAS_IRIG_TIME _MBG_IOR( IOTYPE, 0x7E, int ) +#define IOCTL_GET_IRIG_TIME _MBG_IOR( IOTYPE, 0x7F, PCPS_IRIG_TIME ) + +#define IOCTL_GET_TIME_INFO_HRT _MBG_IOR( IOTYPE, 0x80, MBG_TIME_INFO_HRT ) +#define IOCTL_GET_TIME_INFO_TSTAMP _MBG_IOR( IOTYPE, 0x81, MBG_TIME_INFO_TSTAMP ) + +#define IOCTL_DEV_HAS_RAW_IRIG_DATA _MBG_IOR( IOTYPE, 0x82, int ) +#define IOCTL_GET_RAW_IRIG_DATA _MBG_IOR( IOTYPE, 0x83, MBG_RAW_IRIG_DATA ) + +// The codes below are subject to changes without notice. They may be supported +// by some kernel drivers, but usage is restricted to Meinberg software development. +// Unrestricted usage may cause system malfunction !! +#define IOCTL_MBG_DBG_GET_PORT_ADDR _MBG_IOR( IOTYPE, 0xF0, uint16_t ) +#define IOCTL_MBG_DBG_SET_PORT_ADDR _MBG_IOW( IOTYPE, 0xF1, uint16_t ) +#define IOCTL_MBG_DBG_SET_BIT _MBG_IOW( IOTYPE, 0xF2, uint8_t ) +#define IOCTL_MBG_DBG_CLR_BIT _MBG_IOW( IOTYPE, 0xF3, uint8_t ) +#define IOCTL_MBG_DBG_CLR_ALL _MBG_IO( IOTYPE, 0xF4 ) + + +#if !defined( _cmd_from_ioctl_code ) + #define _cmd_from_ioctl_code( _ioctl_code ) _ioctl_code +#endif + + + +// The structure below is used by the IOCTL_PCPS_GENERIC_... calls. +typedef struct +{ + uint32_t info; + uint32_t data_size_in; + uint32_t data_size_out; +} IOCTL_GENERIC_CTL; + + +typedef struct +{ + IOCTL_GENERIC_CTL ctl; + uint8_t data[1]; +} IOCTL_GENERIC_BUFFER; + + + +/* End of header body */ + +#undef _ext +#undef _DO_INIT + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + +/* (no header definitions found) */ + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +#if defined( _USE_PACK ) // set byte alignment + #pragma pack() +#endif + +#endif /* _MBGIOCTL_H */ diff --git a/mbglib/common/mbgmktm.c b/mbglib/common/mbgmktm.c new file mode 100755 index 0000000..3285b73 --- /dev/null +++ b/mbglib/common/mbgmktm.c @@ -0,0 +1,117 @@ + +/************************************************************************** + * + * $Id: mbgmktm.c 1.1 2006/08/22 08:57:15 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Function to convert broken down time to Unix time (seconds since 1970) + * + * ----------------------------------------------------------------------- + * $Log: mbgmktm.c $ + * Revision 1.1 2006/08/22 08:57:15 martin + * Former function totalsec() moved here from pcpsmktm.c. + * + **************************************************************************/ + +#define _MBGMKTM + #include +#undef _MBGMKTM + +#include + + +static const char Days[12] = +{ + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +static int YDays[12] = +{ + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 +}; + + +/*-------------------------------------------------------------- + * Name: mbg_mktime() + * + * Purpose: This function works like the standard mktime() + * function but does not account for a timezone + * setting configured for the standard C library. + * Also, it does not take a structure but a set + * of variables which makes it more versatile. + * The accepted variables are in the same ranges + * as the struct tm members used by mktime(). + * + * Input: int year year - 1900 + * int month months since January, 0..11 + * int day days after 1st, 0..30 + * int hour 0..23 + * int min 0..59 + * int sec 0..59, 60 if leap second + * + * Output: -- + * + * Ret value: seconds since 1970 (Unix time_t format) + * or -1 if range overflow + *-------------------------------------------------------------*/ + +/*HDR*/ +long mbg_mktime( int year, int month, int day, + int hour, int min, int sec ) +{ + int leaps; + long days; + long secs; + + + if ( year < 70 || year > 138 ) + return ( -1 ); + + min += sec / 60; + sec %= 60; /* Seconds are normalized */ + hour += min / 60; + min %= 60; /* Minutes are normalized */ + day += hour / 24; + hour %= 24; /* Hours are normalized */ + + year += month / 12; /* Normalize month (not necessarily final) */ + month %= 12; + + while ( day >= Days[month] ) + { + if ( !( year & 3 ) && ( month == 1 ) ) + { + if (day > 28) + { + day -= 29; + month++; + } + else + break; + } + else + { + day -= Days[month]; + month++; + } + + year += month / 12; /* Normalize month */ + month %= 12; + } + + year -= 70; + leaps = ( year + 2 ) / 4; + + if ( !( ( year + 70 ) & 3 ) && ( month < 2 ) ) + --leaps; + + days = year * 365L + leaps + YDays[month] + day; + + secs = days * 86400L + hour * 3600L + min * 60L + sec; + + return( secs > 0 ? secs : -1 ); + +} // mbg_mktime + diff --git a/mbglib/common/mbgmktm.h b/mbglib/common/mbgmktm.h new file mode 100755 index 0000000..2aada2a --- /dev/null +++ b/mbglib/common/mbgmktm.h @@ -0,0 +1,57 @@ + +/************************************************************************** + * + * $Id: mbgmktm.h 1.1 2006/08/22 08:57:15 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes for mbgmktm.c. + * + * ----------------------------------------------------------------------- + * $Log: mbgmktm.h $ + * Revision 1.1 2006/08/22 08:57:15 martin + * Former function totalsec() moved here from pcpsmktm.c. + * + **************************************************************************/ + +#ifndef _MBGMKTM_H +#define _MBGMKTM_H + + +/* Other headers to be included */ + +#ifdef _MBGMKTM + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + +long mbg_mktime( int year, int month, int day, int hour, int min, int sec ) ; + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + +/* End of header body */ + +#undef _ext + +#endif /* _MBGMKTM_H */ diff --git a/mbglib/common/mbgtime.h b/mbglib/common/mbgtime.h new file mode 100755 index 0000000..b2fe544 --- /dev/null +++ b/mbglib/common/mbgtime.h @@ -0,0 +1,322 @@ + +/************************************************************************** + * + * $Id: mbgtime.h 1.17.1.3 2011/01/24 17:09:20 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes for mbgtime.c. + * + * ----------------------------------------------------------------------- + * $Log: mbgtime.h $ + * Revision 1.17.1.3 2011/01/24 17:09:20 martin + * Fixed build under FreeBSD. + * Revision 1.17.1.2 2010/08/13 11:57:13 martin + * Revision 1.17.1.1 2010/08/13 11:39:20Z martin + * Revision 1.17 2010/08/06 13:03:03 martin + * Removed obsolete code. + * Revision 1.16 2010/07/16 10:22:07Z martin + * Moved definitions of HNS_PER_SEC and HNS_PER_MS here. + * Conditionally define FILETIME_1970. + * Defined MASK_CLOCK_T for ARM/Cortex. + * Revision 1.15 2009/10/23 09:55:21 martin + * Added MJD numbers for commonly used epochs. + * Revision 1.14 2009/08/12 10:28:12 daniel + * Added definition NSECS_PER_SEC. + * Revision 1.13 2009/06/12 13:31:44Z martin + * Fix build errors with arm-linux-gcc. + * Revision 1.12 2009/03/27 14:14:00 martin + * Cleanup for CVI. + * Revision 1.11 2009/03/13 09:30:06Z martin + * Include mystd.h in mbgtime.c rather than here. The bit type used + * here is now defined in words.h. + * Updated comments for GPS_SEC_BIAS. + * Revision 1.10 2008/12/11 10:45:41Z martin + * Added clock_t mask for gcc (GnuC). + * Revision 1.9 2006/08/25 09:33:46Z martin + * Updated function prototypes. + * Revision 1.8 2004/12/28 11:29:02Z martin + * Added macro _n_days. + * Updated function prototypes. + * Revision 1.7 2002/09/06 07:15:48Z martin + * Added MASK_CLOCK_T for Linux. + * Revision 1.6 2002/02/25 08:37:44 Andre + * definition MASK_CLOCK_T for ARM added + * Revision 1.5 2001/03/02 10:18:10Z MARTIN + * Added MASK_CLOCK_T for Watcom C. + * Revision 1.4 2000/09/15 07:57:53 MARTIN + * Removed outdated function prototypes. + * Revision 1.3 2000/07/21 14:05:18 MARTIN + * Defined some new constants. + * + **************************************************************************/ + +#ifndef _MBGTIME_H +#define _MBGTIME_H + + +/* Other headers to be included */ + +#include + +#if !defined( MBG_ARCH_ARM ) && \ + !defined( MBG_TGT_BSD ) && \ + !defined( __KERNEL__ ) + #include +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MBGTIME + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + + +// The Unix time_t epoche is usually 1970-01-01 00:00 whereas +// the GPS epoche is 1980-01-06 00:00, so the difference is 10 years, +// plus 2 days due to leap years (1972 and 1976), plus the difference +// of the day-of-month (6 - 1). +#define GPS_SEC_BIAS 315964800UL // ( ( ( 10UL * 365UL ) + 2 + 5 ) * SECS_PER_DAY ) + +// time_t t = ( gps_week * SECS_PER_WEEK ) + sec_of_week + GPS_SEC_BIAS + + +// Modified Julian Day (MJD) numbers for some commonly used epochs. +// To compute the MJD for a given date just compute the days since epoch +// and add the constant number of days according to the epoch, e.g.: +// current_unix_mjd = ( time( NULL ) / SECS_PER_DAY ) + MJD_AT_UNIX_EPOCH; +#define MJD_AT_GPS_EPOCH 44244UL // MJD at 1980-01-06 +#define MJD_AT_UNIX_EPOCH 40587UL // MJD at 1970-01-01 +#define MJD_AT_NTP_EPOCH 40587UL // MJD at 1900-01-01 + + +// The constant below defines the Windows FILETIME number (100 ns intervals +// since 1601-01-01) for 1970-01-01, which is usually the epoche for the time_t +// type used by the standard C library. +#if !defined( FILETIME_1970 ) + // FILETIME represents a 64 bit number, so we need to defined the + // constant with an appendix depending on the compiler. + #if MBG_TGT_C99 || defined( __GNUC__ ) + // syntax introduced by C99 standard + #define FILETIME_1970 0x019db1ded53e8000ULL // Epoch offset from FILETIME to UNIX + #elif defined( MBG_TGT_WIN32 ) + // MSC-specific syntax + #define FILETIME_1970 0x019db1ded53e8000ui64 + #endif +#endif + + +#if defined( _C166 ) + #if _C166 >= 50 + #define MASK_CLOCK_T 0x7FFFFFFFL + #else + #define MASK_CLOCK_T 0x7FFF /* time.h not shipped with compiler */ + #endif +#endif + +#if defined( __WATCOMC__ ) + #define MASK_CLOCK_T 0x7FFFFFFFL +#endif + +#if defined( _CVI ) || defined( _CVI_ ) + #define MASK_CLOCK_T 0x7FFFFFFFL +#endif + +#if defined( _MSC_VER ) + #define MASK_CLOCK_T 0x7FFFFFFFL +#endif + +#if defined( __NETWARE_386__ ) + #define MASK_CLOCK_T 0x7FFFFFFFL +#endif + +#if defined( __ARM ) + #define MASK_CLOCK_T 0x7FFFFFFFL +#endif + +#if defined( __ARMCC_VERSION ) + #define MASK_CLOCK_T ( ( (ulong) (clock_t) -1 ) >> 1 ) +#endif + +#if defined( __GNUC__ ) + #if defined( __linux ) + #define MASK_CLOCK_T ( ( (ulong) (clock_t) -1 ) >> 1 ) + #else // Windows / MinGW + #define MASK_CLOCK_T 0x7FFFFFFFL + #endif +#endif + + +#if !defined( MASK_CLOCK_T ) + #if sizeof( clock_t ) == sizeof( short ) + #define MASK_CLOCK_T 0x7FFF + #elif sizeof( clock_t ) == sizeof( long ) + #define MASK_CLOCK_T 0x7FFFFFFFL + #endif +#endif + +typedef struct +{ + clock_t start; + clock_t stop; + short is_set; +} TIMEOUT; + + +#define DAYS_PER_WEEK 7 + +#define SECS_PER_MIN 60 +#define MINS_PER_HOUR 60 +#define HOURS_PER_DAY 24 +#define DAYS_PER_WEEK 7 + +#define MINS_PER_DAY ( MINS_PER_HOUR * HOURS_PER_DAY ) + +#define SECS_PER_HOUR 3600 +#define SECS_PER_DAY 86400L +#define SECS_PER_WEEK 604800L + +#define SEC100S_PER_SEC 100L +#define SEC100S_PER_MIN ( SEC100S_PER_SEC * SECS_PER_MIN ) +#define SEC100S_PER_HOUR ( SEC100S_PER_SEC * SECS_PER_HOUR ) +#define SEC100S_PER_DAY ( SEC100S_PER_SEC * SECS_PER_DAY ) + +#if !defined( MSEC_PER_SEC ) + #define MSEC_PER_SEC 1000L +#endif + +#define MSEC_PER_MIN ( MSEC_PER_SEC * SECS_PER_MIN ) +#define MSEC_PER_HOUR ( MSEC_PER_SEC * SECS_PER_HOUR ) +#define MSEC_PER_DAY ( MSEC_PER_SEC * SECS_PER_DAY ) + +#define NSECS_PER_SEC 1000000000UL + +#if !defined( HNS_PER_SEC ) + #define HNS_PER_SEC 10000000UL +#endif + +#if !defined( HNS_PER_MS ) + #define HNS_PER_MS 10000UL +#endif + + + +_ext TM_GPS dhms; +_ext TM_GPS datum; + + +_ext const char *short_time_fmt +#ifdef _MBGTIME + = "%2i:%02i" +#endif +; + +_ext const char *time_fmt +#ifdef _MBGTIME + = "%2i:%02i:%02i" +#endif +; + +_ext const char *long_time_fmt +#ifdef _MBGTIME + = "%2i:%02i:%02i.%02i" +#endif +; + +_ext const char *date_fmt +#ifdef _MBGTIME + = "%2i.%02i.%04i" +#endif +; + +_ext const char *day_date_fmt +#ifdef _MBGTIME + = "%s, %2i.%02i.%04i" +#endif +; + +_ext const char *day_name_eng[] +#ifdef _MBGTIME + = { "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" } +#endif +; + +_ext const char *day_name_ger[] +#ifdef _MBGTIME + = { "So", "Mo", "Di", "Mi", "Do", "Fr", "Sa" } +#endif +; + +_ext const TM_GPS init_tm +#ifdef _MBGTIME + = { 1980, 1, 1, 0, 0, 0, 0, 0, 0, 0 } +#endif +; + + +_ext char days_of_month[2][12] +#ifdef _MBGTIME + = { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } + } +#endif +; + + +// simplify call to n_days with structures +#define _n_days( _s ) \ + n_days( (_s)->mday, (_s)->month, (_s)->year ) + + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + + void set_timeout( TIMEOUT *t, clock_t clk, clock_t interval ) ; + void stretch_timeout( TIMEOUT *t, clock_t interval ) ; + bit check_timeout( TIMEOUT *t, clock_t clk ) ; + int err_tm( TM_GPS *tm ) ; + TM_GPS *clear_time( TM_GPS *tm ) ; + TM_GPS *wsec_to_tm( long wsec, TM_GPS *tm ) ; + long tm_to_wsec( TM_GPS *tm ) ; + int is_leap_year( int y ) ; + int day_of_year( int day, int month, int year ) ; + void date_of_year ( int year, int day_num, TM_GPS *tm ) ; + int day_of_week( int day, int month, int year ) ; + int days_to_years( long *day_num, int year ) ; + long n_days( ushort mday, ushort month, ushort year ) ; + double nano_time_to_double( const NANO_TIME *p ) ; + void double_to_nano_time( NANO_TIME *p, double d ) ; + int sprint_time( char *s, const TM_GPS *tm ) ; + int sprint_short_time( char *s, TM_GPS *time ) ; + int sprint_date( char *s, const TM_GPS *tm ) ; + int sprint_day_date( char *s, const TM_GPS *tm ) ; + int sprint_tm( char *s, const TM_GPS *tm ) ; + void sscan_time( char *s, TM_GPS *tm ) ; + void sscan_date( char *s, TM_GPS *tm ) ; + +/* ----- function prototypes end ----- */ + + +/* End of header body */ + + +#undef _ext + +#ifdef __cplusplus +} +#endif + + +#endif /* _MBGTIME_H */ diff --git a/mbglib/common/mbgutil.c b/mbglib/common/mbgutil.c new file mode 100755 index 0000000..1a4156e --- /dev/null +++ b/mbglib/common/mbgutil.c @@ -0,0 +1,615 @@ + +/************************************************************************** + * + * $Id: mbgutil.c 1.5.2.1 2010/07/15 13:06:59 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Utility function used by Meinberg device drivers. + * + * ----------------------------------------------------------------------- + * $Log: mbgutil.c $ + * Revision 1.5.2.1 2010/07/15 13:06:59 martin + * Revision 1.5 2009/03/19 09:09:55Z daniel + * Fixed ambiguous syntax in mbg_str_dev_name(). + * Support TAI and GPS time scales in mbg_str_pcps_hr_tstamp_loc(). + * In mbg_str_pcps_hr_time_offs() append offset only if != 0. + * Revision 1.4 2009/01/12 09:34:12Z daniel + * Added function mbg_str_dev_name(). + * Revision 1.3 2006/05/10 10:57:44Z martin + * Generally use and export mbg_snprintf(). + * Revision 1.2 2005/02/18 15:12:13Z martin + * Made functions mbg_strncpy() and mbg_strchar() public. + * New function mbg_str_tm_gps_date_time(). + * Don't expand year number if already expanded. + * Revision 1.1 2005/02/18 10:39:49Z martin + * Initial revision + * + **************************************************************************/ + +#define _MBGUTIL + #include +#undef _MBGUTIL + +#include +#include +//#include +#include + +#include +#include + +// required at least for Linux: +#include +#include +#include + + +#if defined( MBG_TGT_WIN32 ) + #include +#else +// #include <> +#endif + + +static int mbg_date_time_dist = 2; +//##++ static int mbg_time_tz_dist = 1; +static int mbg_pos_dist = 2; + +static uint16_t mbg_year_lim = 1980; + + +#if defined( MBG_TGT_WIN32 ) + #define mbg_vsnprintf _vsnprintf +#else + #define mbg_vsnprintf vsnprintf +#endif + + +#if defined( MBG_TGT_DOS ) + +static /*HDR*/ +int vsnprintf( char *s, int max_len, const char *fmt, va_list arg_list ) +{ + return vsprintf( s, fmt, arg_list ); + +} // vsnprintf + +#endif + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbgutil_get_version( void ) +{ + + return MBGUTIL_VERSION; + +} // mbgutil_get_version + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbgutil_check_version( int header_version ) +{ + if ( header_version >= MBGUTIL_COMPAT_VERSION ) + return PCPS_SUCCESS; + + return -1; + +} // mbgutil_check_version + + + +// We have our own version of snprintf() since under Windows +// _snprintf(), returns -1 and does not write a terminating 0 +// if the output exceeds the buffer size. +// +// This function terminates the output string properly. However, +// the maximum return value is (max_len - 1), so the function +// can not be used to determine the buffer size that would be +// required for an untruncated string. + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_snprintf( char *s, size_t max_len, const char * fmt, ... ) +{ + int n; + + va_list ap; + + va_start( ap, fmt ); + + n = mbg_vsnprintf( s, max_len, fmt, ap ); + + va_end( ap ); + + + #if defined( MBG_TGT_WIN32 ) + + // Terminate the output string properly under Windows. + // For other targets assume the POSIX version is available. + if ( n < 0 || n >= (int) max_len ) + { + n = max_len - 1; + s[n] = 0; + } + + #endif + + + return n; + +} // mbg_snprintf + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_strncpy( char *s, size_t max_len, const char *src ) +{ + //##++ This could be coded more efficiently + return mbg_snprintf( s, max_len, "%s", src ); + +} // mbg_strncpy + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_strchar( char *s, size_t max_len, char c, size_t n ) +{ + size_t i; + + max_len--; + + for ( i = 0; i < n; i++ ) + { + if ( i >= max_len ) + break; + + s[i] = c; + } + + s[i] = 0; + + return i; + +} // mbg_strchar + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_date_short( char *s, int max_len, + int mday, int month ) +{ + return mbg_snprintf( s, max_len, "%02u.%02u.", mday, month ); + +} // mbg_str_date_short + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_date( char *s, int max_len, + int mday, int month, int year ) +{ + int n = mbg_str_date_short( s, max_len, mday, month ); + n += mbg_snprintf( s + n, max_len - n, "%04u", + ( year < 256 ) ? + pcps_exp_year( (uint8_t) year, mbg_year_lim ) : + year + ); + return n; + +} // mbg_str_date + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_time_short( char *s, int max_len, + int hour, int min ) +{ + return mbg_snprintf( s, max_len, "%2u:%02u", hour, min ); + +} // mbg_str_time_short + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_time( char *s, int max_len, + int hour, int min, int sec ) +{ + int n = mbg_str_time_short( s, max_len, hour, min ); + + n += mbg_snprintf( s + n, max_len - n, ":%02u", sec ); + + return n; + +} // mbg_str_time + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_time_long( char *s, int max_len, + int hour, int min, int sec, int sec100 ) +{ + int n = mbg_str_time( s, max_len, hour, min, sec ); + + n += mbg_snprintf( s + n, max_len - n, ".%02u", sec100 ); + + return n; + +} // mbg_str_time_long + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_tm_gps_date_time( char *s, int max_len, + const TM_GPS *pt ) +{ + int n = mbg_str_date( s, max_len, pt->mday, pt->month, pt->year ); + n += mbg_strchar( s + n, max_len - n, ' ', mbg_date_time_dist ); + n += mbg_str_time( s + n, max_len - n, pt->hour, pt->min, pt->sec ); + + return n; + +} // mbg_str_tm_gps_date_time + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pcps_date_short( char *s, int max_len, + const PCPS_TIME *pt ) +{ + return mbg_str_date_short( s, max_len, pt->mday, pt->month ); + +} // mbg_str_pcps_date_short + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pcps_date( char *s, int max_len, + const PCPS_TIME *pt ) +{ + return mbg_str_date( s, max_len, pt->mday, pt->month, pt->year ); + +} // mbg_str_pcps_date + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pcps_time_short( char *s, int max_len, + const PCPS_TIME *pt ) +{ + return mbg_str_time_short( s, max_len, pt->hour, pt->min ); + +} // mbg_str_pcps_time_short + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pcps_time( char *s, int max_len, + const PCPS_TIME *pt ) +{ + return mbg_str_time( s, max_len, pt->hour, pt->min, pt->sec ); + +} // mbg_str_pcps_time + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pcps_time_long( char *s, int max_len, + const PCPS_TIME *pt ) +{ + return mbg_str_time_long( s, max_len, pt->hour, pt->min, pt->sec, pt->sec100 ); + +} // mbg_str_pcps_time_long + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pcps_date_time( char *s, int max_len, + const PCPS_TIME *pt, + const char *tz_str ) +{ + int n = mbg_str_pcps_date( s, max_len, pt ); + n += mbg_strchar( s + n, max_len - n, ' ', mbg_date_time_dist ); + n += mbg_str_pcps_time( s + n, max_len - n, pt ); + + return n; + +} // mbg_str_pcps_date_time + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_date( char *s, int max_len, + uint32_t sec ) +{ + time_t t = sec; + struct tm tm = *gmtime( &t ); + return mbg_str_date( s, max_len, tm.tm_mday, tm.tm_mon + 1, tm.tm_year ); + +} // mbg_str_pcps_hr_date + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_time( char *s, int max_len, + uint32_t sec ) +{ + time_t t = sec; + struct tm tm = *gmtime( &t ); + return mbg_str_time( s, max_len, tm.tm_hour, tm.tm_min, tm.tm_sec ); + +} // mbg_str_pcps_hr_time + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_date_time_utc( char *s, int max_len, + const PCPS_HR_TIME *pt ) +{ + time_t t = pt->tstamp.sec; + struct tm tm = *gmtime( &t ); + int n = mbg_str_date( s, max_len, tm.tm_mday , tm.tm_mon + 1, tm.tm_year ); + n += mbg_strchar( s + n, max_len - n, ' ', mbg_date_time_dist ); + n += mbg_str_time( s + n, max_len - n, tm.tm_hour, tm.tm_min, tm.tm_sec ); + + return n; + +} // mbg_str_pcps_hr_date_time_utc + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_date_time_loc( char *s, int max_len, + const PCPS_HR_TIME *pt ) +{ + time_t t = pt->tstamp.sec + pt->utc_offs; + struct tm tm = *gmtime( &t ); + int n = mbg_str_date( s, max_len, tm.tm_mday , tm.tm_mon + 1, tm.tm_year ); + n += mbg_strchar( s + n, max_len - n, ' ', mbg_date_time_dist ); + n += mbg_str_time( s + n, max_len - n, tm.tm_hour, tm.tm_min, tm.tm_sec ); + + return n; + +} // mbg_str_pcps_hr_date_time_loc + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_time_frac( char *s, int max_len, + uint32_t frac ) +{ + return mbg_snprintf( s, max_len, PCPS_HRT_FRAC_SCALE_FMT, + frac_sec_from_bin( frac, PCPS_HRT_FRAC_SCALE ) ); + +} // mbg_str_pcps_hr_time_frac + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_time_offs( char *s, int max_len, + const PCPS_HR_TIME *pt, + const char *info ) +{ + int n = mbg_snprintf( s, max_len, "%s", info ); + + if ( pt->utc_offs ) + { + ldiv_t ldt = ldiv( labs( pt->utc_offs ) / 60, 60 ); + + n += mbg_snprintf( s + n, max_len - n, "%c%02u:%02uh", + ( pt->utc_offs < 0 ) ? '-' : '+', + ldt.quot, ldt.rem ); + } + + return n; + +} // mbg_str_pcps_hr_time_offs + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_tstamp_utc( char *s, int max_len, + const PCPS_HR_TIME *pt ) +{ + int n = mbg_str_pcps_hr_date_time_utc( s, max_len, pt ); + + if ( n < ( max_len - 1 ) ) + { + s[n++] = '.'; + n += mbg_str_pcps_hr_time_frac( s + n, max_len - n, pt->tstamp.frac ); + } + + return n; + +} // mbg_str_pcps_hr_tstamp_utc + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_tstamp_loc( char *s, int max_len, + const PCPS_HR_TIME *pt ) +{ + int n = mbg_str_pcps_hr_date_time_loc( s, max_len, pt ); + + if ( n < ( max_len - 1 ) ) + { + s[n++] = '.'; + n += mbg_str_pcps_hr_time_frac( s + n, max_len - n, pt->tstamp.frac ); + } + + if ( n < ( max_len - 1 ) ) + { + const char *cp = "UTC"; + + if ( pt->status & PCPS_SCALE_TAI ) + cp = "TAI"; + else + if ( pt->status & PCPS_SCALE_GPS ) + cp = "GPS"; + + s[n++] = ' '; + n += mbg_str_pcps_hr_time_offs( s + n, max_len - n, pt, cp ); + } + + return n; + +} // mbg_str_pcps_hr_tstamp_loc + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pcps_tstamp_raw( char *s, int max_len, + const PCPS_TIME_STAMP *pt ) +{ + return mbg_snprintf( s, max_len, "%08lX.%08lX", pt->sec, pt->frac ); + +} // mbg_str_pcps_tstamp_raw + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_time_raw( char *s, int max_len, + const PCPS_HR_TIME *pt ) +{ + int n = mbg_str_pcps_tstamp_raw( s, max_len, &pt->tstamp ); + n += mbg_str_pcps_hr_time_offs( s + n, max_len - n, pt, ", Loc: " ); + n += mbg_snprintf( s + n, max_len - n, ", st: 0x%04X", pt->status ); + + return n; + +} // mbg_str_pcps_hr_time_raw + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_ucap( char *s, int max_len, + const PCPS_HR_TIME *pt ) +{ + int n = mbg_snprintf( s, max_len, "CAP%u: ", pt->signal ); + n += mbg_str_pcps_hr_tstamp_loc( s + n, max_len - n, pt ); + + return n; + +} // mbg_str_ucap + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pos_dms( char *s, int max_len, + const DMS *pdms, int prec ) +{ + return mbg_snprintf( s, max_len, "%c %i" DEG "%02i'%02.*f\"", + pdms->prefix, + pdms->deg, + pdms->min, + prec, + pdms->sec + ); + +} // mbg_str_pos_dms + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pos_alt( char *s, int max_len, double alt ) +{ + return mbg_snprintf( s, max_len, "%.0fm", alt ); + +} // mbg_str_pos_alt + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_pos( char *s, int max_len, + const POS *ppos, int prec ) +{ + int n; + + if ( ppos->lla[LON] || ppos->lla[LAT] || ppos->lla[ALT] ) + { + n = mbg_str_pos_dms( s, max_len, &ppos->latitude, prec ); + n += mbg_strchar( s + n, max_len - n, ',', 1 ); + n += mbg_strchar( s + n, max_len - n, ' ', mbg_pos_dist ); + n += mbg_str_pos_dms( s + n, max_len - n, &ppos->longitude, prec ); + n += mbg_strchar( s + n, max_len - n, ',', 1 ); + n += mbg_strchar( s + n, max_len - n, ' ', mbg_pos_dist ); + n += mbg_str_pos_alt( s + n, max_len - n, ppos->lla[ALT] ); + } + else + n = mbg_strncpy( s, max_len, "N/A" ); + + return n; + +} // mbg_str_pos + + + +/*HDR*/ +_MBG_API_ATTR int _MBG_API mbg_str_dev_name( char *s, int max_len, const char *short_name, + uint16_t fw_rev_num, PCI_ASIC_VERSION asic_version_num ) +{ + #define HW_NAME_SZ PCPS_CLOCK_NAME_SZ+PCPS_SN_SIZE+1 + + char model_code[HW_NAME_SZ]; + PCPS_SN_STR sernum; + unsigned int i = 0; + int n = 0; + + memset( model_code, 0, sizeof( model_code ) ); + memset( sernum, 0, sizeof( sernum ) ); + + if ( strlen( short_name ) > 0 ) + { + if ( strstr( short_name, "COM") ) + return mbg_snprintf(s, max_len,"%s", short_name); + + for ( i = 0; ( i < HW_NAME_SZ ) && ( i < strlen( short_name ) ); i++ ) + { + if ( short_name[i] == '_' ) + { + i++; + break; + } + model_code[i] = short_name[i]; + } + strncpy( sernum, &short_name[i], PCPS_SN_SIZE-1 ); + + if ( sernum[12] == ' ' ) + sernum[12] = '\0'; + } + + n = mbg_snprintf( s, max_len, "%s, S/N %s", model_code, sernum ); + + if ( fw_rev_num > 0 ) + n += mbg_snprintf( &s[n], max_len," (FW v%X.%02X", fw_rev_num>>8, fw_rev_num & 0x00FF ); + + if ( asic_version_num > 0 ) + { + mbg_snprintf( &s[n], max_len," / ASIC v%X.%02X)", _convert_asic_version_number( asic_version_num ) >> 8, + ( _convert_asic_version_number( asic_version_num ) ) & 0xFF ); + } + else + mbg_snprintf( &s[n], max_len,")" ); + + return strlen(s); + +} // mbg_str_dev_name + + + + +#if defined( MBG_TGT_WIN32 ) + +BOOL APIENTRY DllMain( HANDLE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved ) +{ + return TRUE; +} + +#endif // defined( MBG_TGT_WIN32 ) + + + diff --git a/mbglib/common/mbgutil.h b/mbglib/common/mbgutil.h new file mode 100755 index 0000000..5ae29a8 --- /dev/null +++ b/mbglib/common/mbgutil.h @@ -0,0 +1,180 @@ + +/************************************************************************** + * + * $Id: mbgutil.h 1.16 2009/08/14 10:11:53 daniel REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions used with mbgutil.c. + * + * ----------------------------------------------------------------------- + * $Log: mbgutil.h $ + * Revision 1.16 2009/08/14 10:11:53 daniel + * New version code 306, compatibility version still 110. + * Revision 1.15 2009/06/09 08:57:47Z daniel + * Rev No. 305 + * Revision 1.14 2009/03/19 09:06:00Z daniel + * New version code 304, compatibility version still 110. + * Revision 1.13 2009/01/12 09:35:41Z daniel + * New version code 303, compatibility version still 110. + * Updated function prototypes. + * Revision 1.12 2008/01/17 10:15:26Z daniel + * New version code 302, compatibility version still 110. + * Revision 1.11 2007/10/16 10:01:17Z daniel + * New version code 301, compatibility version still 110. + * Revision 1.9 2007/03/21 16:48:31Z martin + * New version code 219, compatibility version still 110. + * Revision 1.8 2006/08/09 13:18:18Z martin + * New version code 218, compatibility version still 110. + * Revision 1.7 2006/06/08 10:48:52Z martin + * New version code 217, compatibility version still 110. + * Added macro _mbg_strncpy(). + * Revision 1.6 2006/05/10 10:56:54Z martin + * Updated function prototypes. + * Revision 1.5 2006/05/02 13:24:49Z martin + * New version code 216, compatibility version still 110. + * Revision 1.4 2006/01/11 12:24:05Z martin + * New version code 215, compatibility version still 110. + * Revision 1.3 2005/12/15 10:01:51Z martin + * New version 214, compatibility version still 110. + * Revision 1.2 2005/02/18 15:13:42Z martin + * Updated function prototypes. + * Revision 1.1 2005/02/18 10:39:49Z martin + * Initial revision + * + **************************************************************************/ + +#ifndef _MBGUTIL_H +#define _MBGUTIL_H + + +/* Other headers to be included */ + +#include +#include +#include +#include +#include + + +#define MBGUTIL_VERSION 0x0306 + +#define MBGUTIL_COMPAT_VERSION 0x0110 + + +#if defined( MBG_TGT_WIN32 ) + + #include + +#elif defined( MBG_TGT_LINUX ) + + +#elif defined( MBG_TGT_OS2 ) + + +#elif defined( MBG_TGT_DOS ) + + #if !defined( MBG_USE_DOS_TSR ) + #endif + +#else + +#endif + +#ifdef _MBGUTIL + #define _ext + #define _DO_INIT +#else + #define _ext extern +#endif + + +/* Start of header body */ + +#if defined( _USE_PACK ) // set byte alignment + #pragma pack( 1 ) +#endif + + +#if defined( MBG_TGT_WIN32 ) + +#elif defined( MBG_TGT_LINUX ) + +#elif defined( MBG_TGT_OS2 ) + +#else + +#endif + + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +// The macro below can be used to simplify the API call if +// a string variable is used rather than a char *. +#define _mbg_strncpy( _s, _src ) \ + mbg_strncpy( _s, sizeof( _s ), _src ) + + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + + _MBG_API_ATTR int _MBG_API mbgutil_get_version( void ) ; + _MBG_API_ATTR int _MBG_API mbgutil_check_version( int header_version ) ; + _MBG_API_ATTR int _MBG_API mbg_snprintf( char *s, size_t max_len, const char * fmt, ... ) ; + _MBG_API_ATTR int _MBG_API mbg_strncpy( char *s, size_t max_len, const char *src ) ; + _MBG_API_ATTR int _MBG_API mbg_strchar( char *s, size_t max_len, char c, size_t n ) ; + _MBG_API_ATTR int _MBG_API mbg_str_date_short( char *s, int max_len, int mday, int month ) ; + _MBG_API_ATTR int _MBG_API mbg_str_date( char *s, int max_len, int mday, int month, int year ) ; + _MBG_API_ATTR int _MBG_API mbg_str_time_short( char *s, int max_len, int hour, int min ) ; + _MBG_API_ATTR int _MBG_API mbg_str_time( char *s, int max_len, int hour, int min, int sec ) ; + _MBG_API_ATTR int _MBG_API mbg_str_time_long( char *s, int max_len, int hour, int min, int sec, int sec100 ) ; + _MBG_API_ATTR int _MBG_API mbg_str_tm_gps_date_time( char *s, int max_len, const TM_GPS *pt ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pcps_date_short( char *s, int max_len, const PCPS_TIME *pt ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pcps_date( char *s, int max_len, const PCPS_TIME *pt ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pcps_time_short( char *s, int max_len, const PCPS_TIME *pt ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pcps_time( char *s, int max_len, const PCPS_TIME *pt ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pcps_time_long( char *s, int max_len, const PCPS_TIME *pt ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pcps_date_time( char *s, int max_len, const PCPS_TIME *pt, const char *tz_str ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_date( char *s, int max_len, uint32_t sec ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_time( char *s, int max_len, uint32_t sec ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_date_time_utc( char *s, int max_len, const PCPS_HR_TIME *pt ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_date_time_loc( char *s, int max_len, const PCPS_HR_TIME *pt ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_time_frac( char *s, int max_len, uint32_t frac ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_time_offs( char *s, int max_len, const PCPS_HR_TIME *pt, const char *info ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_tstamp_utc( char *s, int max_len, const PCPS_HR_TIME *pt ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_tstamp_loc( char *s, int max_len, const PCPS_HR_TIME *pt ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pcps_tstamp_raw( char *s, int max_len, const PCPS_TIME_STAMP *pt ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pcps_hr_time_raw( char *s, int max_len, const PCPS_HR_TIME *pt ) ; + _MBG_API_ATTR int _MBG_API mbg_str_ucap( char *s, int max_len, const PCPS_HR_TIME *pt ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pos_dms( char *s, int max_len, const DMS *pdms, int prec ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pos_alt( char *s, int max_len, double alt ) ; + _MBG_API_ATTR int _MBG_API mbg_str_pos( char *s, int max_len, const POS *ppos, int prec ) ; + _MBG_API_ATTR int _MBG_API mbg_str_dev_name( char *s, int max_len, const char *short_name, uint16_t fw_rev_num, PCI_ASIC_VERSION asic_version_num ) ; + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +#if defined( _USE_PACK ) // set default alignment + #pragma pack() +#endif + +/* End of header body */ + + +#undef _ext +#undef _DO_INIT + +#endif /* _MBGUTIL_H */ + diff --git a/mbglib/common/myutil.h b/mbglib/common/myutil.h new file mode 100755 index 0000000..ddec11b --- /dev/null +++ b/mbglib/common/myutil.h @@ -0,0 +1,203 @@ + +/************************************************************************** + * + * $Id: myutil.h 1.13 2010/12/13 15:59:39 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes for myutil.c. + * + * ----------------------------------------------------------------------- + * $Log: myutil.h $ + * Revision 1.13 2010/12/13 15:59:39 martin + * Moved definition of macro _frac() here. + * Revision 1.12 2008/01/30 10:28:17Z martin + * Moved some macro definitions to words.h. + * Revision 1.11 2004/11/09 14:20:24Z martin + * Redefined some data types using C99 fixed-size definitions. + * Removed duplicate definition of macro _mask(). + * Revision 1.10 2004/04/14 08:57:59Z martin + * Pack structures 1 byte aligned. + * Revision 1.9 2003/05/20 10:22:25Z MARTIN + * Corrected endianess of union UL for CC51. + * Revision 1.8 2002/09/03 13:40:43 MARTIN + * New macros _memfill() and _memclr(). + * Revision 1.7 2002/03/14 13:45:56 MARTIN + * Changed type CSUM from short to ushort. + * Revision 1.6 2002/03/05 14:14:21 MARTIN + * New macro _isdigit() to avoid inclusion of ctype.h. + * Revision 1.5 2002/01/25 10:54:26 MARTIN + * Added some useful macros. + * Revision 1.4 2001/03/30 09:07:52 Andre + * union UL byte order set to Big Endian if SH2 is used + * Revision 1.3 2000/08/18 07:22:07Z MARTIN + * Modified the _csum() macro to support far data objects. + * Revision 1.2 2000/07/21 13:50:49 MARTIN + * Added some definitions and macros. + * + **************************************************************************/ + +#ifndef _MYUTIL_H +#define _MYUTIL_H + + +/* Other headers to be included */ + +#include +#include + + +// _CS_FAR should be define far if the csum of far data +// structures must be computed +#if !defined( _CSFAR ) + #define _CSFAR +#endif + + +#ifdef _MYUTIL + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + +#if defined( _USE_PACK ) // set byte alignment + #pragma pack( 1 ) +#endif + +#if MBG_TGT_HAS_64BIT_TYPES + #define _frac( _x ) ( ( (_x) == 0.0 ) ? 0.0 : ( (_x) - (double) ( (int64_t) (_x) ) ) ) +#else + #define _frac( _x ) ( ( (_x) == 0.0 ) ? 0.0 : ( (_x) - (double) ( (long) (_x) ) ) ) +#endif + + +#define _isdigit( _c ) ( (_c) >= '0' && (_c) <= '9' ) + +#define _eos( _s ) ( &(_s)[strlen( _s )] ) + +#define MIN( _x, _y ) ( ( (_x) < (_y) ) ? (_x) : (_y) ) +#define MAX( _x, _y ) ( ( (_x) > (_y) ) ? (_x) : (_y) ) +#define SWAP( _x, _y ) { temp = (_x); (_x) = (_y); (_y) = temp; } +#define SQR( _x ) ( (_x) * (_x) ) + +#define DP (double *) + +#define bcd_from_bin( _x ) ( ( ( (_x) / 10 ) << 4 ) | ( (_x) % 10 ) ) +#define bin_from_bcd( _x ) ( ( ( (_x) >> 4 ) * 10 ) + ( (_x) & 0x0F ) ) + + +typedef union +{ + uint32_t ul; + + struct + { + #if defined( _CC51 ) || defined( _SH2 ) + uint16_t hi; // big endian + uint16_t lo; + #else + uint16_t lo; // little endian + uint16_t hi; + #endif + } us; + +} UL; + + +#ifndef _CSUM_DEFINED + typedef uint16_t CSUM; + #define _CSUM_DEFINED +#endif + + +// compute the csum of a structure +#define _csum( _p ) checksum( (void _CSFAR *)(_p), sizeof( *(_p) ) ) + +// set a structure's csum +#define _set_csum( _p ) (_p)->csum = _csum( (_p) ) + +// compare a structure's computed csum with its csum field +#define _valid_csum( _p ) ( (_p)->csum == _csum( (_p) ) ) + +// check if a value is in range +#define _inrange( _val, _min, _max ) \ + ( ( (_val) >= (_min) ) && ( (_val) <= (_max) ) ) + +// Return a bit mask with (_n) LSBs set to 1 +#define _mask( _n ) \ + ( ( 1UL << (_n) ) - 1 ) + +// Return a bit mask with the (_i)th LSB set to 1 +#define _idx_bit( _i ) \ + ( 1UL << (_i) ) + +// Check if the (_i)th bit is set in a mask (_msk) +#define _is_supported( _i, _msk ) \ + ( ( (_msk) & _idx_bit( _i ) ) != 0 ) + + +/* + * The macro below copies a string, taking care not to + * write past the end of the destination buffer, and + * making sure the string is terminated by 0. + */ +#define _strncpy_0( _dst, _src ) \ +{ \ + int n = sizeof( _dst ) - 1; \ + \ + strncpy( _dst, _src, n ); \ + (_dst)[n] = 0; \ +} + + +/* + * The macros below set a memory range used by a variable + * to a specified value, avoiding the need to type the name + * twice for base address and size. + */ +#define _memfill( _p, _v ) \ + memset( _p, _v, sizeof( *(_p) ) ) + +#define _memclr( _p ) \ + _memfill( _p, 0 ) + + + +// generate a DOS idle interrupt to release CPU time +#define _dos_idle() geninterrupt( 0x28 ) + + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + + void spaces_to_zeros( char *s ) ; + CSUM checksum( const void _CSFAR *vp, int n ) ; + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +#if defined( _USE_PACK ) // set default alignment + #pragma pack() +#endif + +/* End of header body */ + + +#undef _ext + + +#endif /* _MYUTIL_H */ diff --git a/mbglib/common/parmgps.c b/mbglib/common/parmgps.c new file mode 100755 index 0000000..44e620b --- /dev/null +++ b/mbglib/common/parmgps.c @@ -0,0 +1,242 @@ + +/************************************************************************** + * + * $Id: parmgps.c 1.5 2008/10/21 10:47:26 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Functions to handle/convert Meinberg GPS specific parameters. + * + * ----------------------------------------------------------------------- + * $Log: parmgps.c $ + * Revision 1.5 2008/10/21 10:47:26 martin + * Renamed check_port_info() to check_valid_port_info() + * to avoid naming conflicts. + * Revision 1.4 2008/09/15 14:11:25 martin + * New function check_port_info() which returns a bit mask indicating + * which fields of a PORT_SETTINGS structure are not valid. + * This is based on code taken from valid_port_info(), which now calls + * check_port_info() and returns a value compatible to the earlier version. + * Revision 1.3 2004/11/09 14:21:36 martin + * Redefined some data types using C99 fixed-size definitions. + * Revision 1.2 2002/02/19 13:30:23Z MARTIN + * Bug fix in port_settings_from_port_parm_mode(). + * Revision 1.1 2002/01/30 10:30:26 MARTIN + * Initial revision + * + **************************************************************************/ + +#define _PARMGPS + #include +#undef _PARMGPS + +#include +#include + + + +/*HDR*/ +int get_str_idx( const char *search, + const char *str_table[], + int n_entries ) +{ + int i; + + for ( i = 0; i < n_entries; i++ ) + if ( strcmp( search, str_table[i] ) == 0 ) + return i; + + return -1; + +} // get_str_idx + + + +/*HDR*/ +int get_baud_rate_idx( BAUD_RATE baud_rate ) +{ + int i; + + for ( i = 0; i < N_MBG_BAUD_RATES; i++ ) + if ( baud_rate == mbg_baud_rate[i] ) + return i; + + return -1; + +} // get_baud_rate_idx + + + +/*HDR*/ +int get_framing_idx( const char *framing ) +{ + return get_str_idx( framing, mbg_framing_str, N_MBG_FRAMINGS ); + +} // get_framing_idx + + + +/*HDR*/ +void port_settings_from_port_parm_mode( + PORT_SETTINGS *p_ps, + uint8_t pp_mode, + int str_type_cap + ) +{ + if ( pp_mode >= STR_UCAP ) + { + p_ps->str_type = str_type_cap; + p_ps->mode = ( pp_mode == STR_UCAP ) ? STR_AUTO : STR_ON_REQ; + } + else + { + p_ps->str_type = 0; + p_ps->mode = pp_mode; + } + +} // port_settings_from_port_parm_mode + + + +/*HDR*/ +void port_parm_mode_from_port_settings( + uint8_t *pp_mode, + const PORT_SETTINGS *p_ps, + int str_type_cap + ) +{ + if ( p_ps->str_type == str_type_cap ) + *pp_mode = ( p_ps->mode == STR_ON_REQ ) ? STR_UCAP_REQ : STR_UCAP; + else + *pp_mode = p_ps->mode; + +} // port_parm_mode_from_port_settings + + + +/*HDR*/ +void port_settings_from_port_parm( + PORT_SETTINGS *p_ps, + int port_num, + const PORT_PARM *p_pp, + int cap_str_idx +) +{ + p_ps->parm = p_pp->com[port_num]; + + port_settings_from_port_parm_mode( p_ps, p_pp->mode[port_num], + cap_str_idx ); + +} // port_info_from_port_parm + + + +/*HDR*/ +void port_parm_from_port_settings( + PORT_PARM *p_pp, + int port_num, + const PORT_SETTINGS *p_ps, + int cap_str_idx +) +{ + p_pp->com[port_num] = p_ps->parm; + + port_parm_mode_from_port_settings( &p_pp->mode[port_num], + p_ps, cap_str_idx ); + +} // port_parm_from_port_settings + + + +/*HDR*/ +int check_valid_port_info( const PORT_INFO *p_pi, + const STR_TYPE_INFO_IDX str_type_info_idx[], + int n_str_type ) + +{ + const PORT_SETTINGS *p_ps = &p_pi->port_settings; + int idx; + int flags = 0; + + + if ( p_pi->supp_baud_rates & ~_mask( N_MBG_BAUD_RATES ) ) + flags |= MBG_PS_MSK_BAUD_RATE_OVR_SW; // dev. supports more baud rates than driver + + idx = get_baud_rate_idx( p_ps->parm.baud_rate ); + + if ( !_inrange( idx, 0, N_MBG_BAUD_RATES ) || + !_is_supported( idx, p_pi->supp_baud_rates ) ) + flags |= MBG_PS_MSK_BAUD_RATE; + + + if ( p_pi->supp_framings & ~_mask( N_MBG_FRAMINGS ) ) + flags |= MBG_PS_MSK_FRAMING_OVR_SW; // dev. supports more framings than driver + + idx = get_framing_idx( p_ps->parm.framing ); + + if ( !_inrange( idx, 0, N_MBG_FRAMINGS ) || + !_is_supported( idx, p_pi->supp_framings ) ) + flags |= MBG_PS_MSK_FRAMING; + + + if ( p_ps->parm.handshake >= N_COM_HS ) + flags |= MBG_PS_MSK_HS_OVR_SW; // handshake index exceeds max. + + if ( p_ps->parm.handshake != HS_NONE ) // currently no device supports any handshake + flags |= MBG_PS_MSK_HS; // handshake mode not supp. by dev. + + + if ( p_pi->supp_str_types & ~_mask( n_str_type ) ) + flags |= MBG_PS_MSK_STR_TYPE_OVR_SW; // firmware error: more string types supported than reported + + idx = p_ps->str_type; + + if ( idx >= n_str_type ) + flags |= MBG_PS_MSK_STR_TYPE_OVR_DEV; // string type index exceeds max. + else + { + if ( !_is_supported( idx, p_pi->supp_str_types ) ) + flags |= MBG_PS_MSK_STR_TYPE; // string type not supported by this port + else + { + // Use the str_type index to get the supported output mode mask + // from the string type info table. This is required to check + // whether the selected mode is supported by the selected + // string type. + ulong supp_modes = str_type_info_idx[idx].str_type_info.supp_modes; + + if ( supp_modes & ~_mask( N_STR_MODE ) ) + flags |= MBG_PS_MSK_STR_MODE_OVR_SW; // dev. supports more string modes than driver + + idx = p_ps->mode; + + if ( idx >= N_STR_MODE ) // mode is always >= 0 + flags |= MBG_PS_MSK_STR_MODE_OVR_SW; // string mode index exceeds max. + else + if ( !_is_supported( idx, supp_modes ) ) + flags |= MBG_PS_MSK_STR_MODE; // string mode not supp. by this string type and port + } + } + + + if ( p_ps->flags != 0 ) /* currently always 0 */ + flags |= MBG_PS_MSK_FLAGS_OVR_SW | MBG_PS_MSK_FLAGS; + + + return flags; + +} // check_valid_port_info + + + +/*HDR*/ +int valid_port_info( const PORT_INFO *p_pi, + const STR_TYPE_INFO_IDX str_type_info_idx[], + int n_str_type ) +{ + return check_valid_port_info( p_pi, str_type_info_idx, n_str_type ) == 0; + +} // valid_port_info + + diff --git a/mbglib/common/parmgps.h b/mbglib/common/parmgps.h new file mode 100755 index 0000000..5208da9 --- /dev/null +++ b/mbglib/common/parmgps.h @@ -0,0 +1,135 @@ + +/************************************************************************** + * + * $Id: parmgps.h 1.6 2008/10/21 10:41:09 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes for parmgps.c. + * + * ----------------------------------------------------------------------- + * $Log: parmgps.h $ + * Revision 1.6 2008/10/21 10:41:09 martin + * Renamed check_port_info() to check_valid_port_info() + * to avoid naming conflicts. + * Revision 1.5 2008/09/10 16:22:32 martin + * Updated function prototypes. + * Revision 1.4 2004/11/09 14:22:34 martin + * Updated function prototypes. + * Revision 1.3 2004/05/19 07:50:16Z martin + * Use symbolic constant as initializer. + * Revision 1.2 2004/04/14 09:21:23Z martin + * Pack structures 1 byte aligned. + * Revision 1.1 2002/01/30 10:33:38Z MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _PARMGPS_H +#define _PARMGPS_H + + +/* Other headers to be included */ + +#include +#include + + +#ifdef _PARMGPS + #define _ext + #define _DO_INIT +#else + #define _ext extern +#endif + + +/* Start of header body */ + +#if defined( _USE_PACK ) // set byte alignment + #pragma pack( 1 ) +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define DEFAULT_N_STR_TYPE_GPS 2 + +#define DEFAULT_SUPP_STR_TYPES_GPS \ + ( ( 1UL << DEFAULT_N_STR_TYPE_GPS ) - 1 ) + + +/* + * The macro below can be used to initialize a + * RECEIVER_INFO structure for old GPS receiver models + * which don't supply that structure. + * + * Parameters: (RECEIVER_INFO *) _p + */ +#define _setup_default_receiver_info_gps( _p ); \ +{ \ + memset( (_p), 0, sizeof( *(_p) ) ); \ + \ + (_p)->ticks_per_sec = DEFAULT_GPS_TICKS_PER_SEC; \ + (_p)->n_ucaps = 2; \ + (_p)->n_com_ports = DEFAULT_N_COM; \ + (_p)->n_str_type = DEFAULT_N_STR_TYPE_GPS; \ +} + + +_ext BAUD_RATE mbg_baud_rate[N_MBG_BAUD_RATES] +#ifdef _DO_INIT + = MBG_BAUD_RATES +#endif +; + +_ext const char *mbg_baud_str[N_MBG_BAUD_RATES] +#ifdef _DO_INIT + = MBG_BAUD_STRS +#endif +; + +_ext const char *mbg_framing_str[N_MBG_FRAMINGS] +#ifdef _DO_INIT + = MBG_FRAMING_STRS +#endif +; + + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + + int get_str_idx( const char *search, const char *str_table[], int n_entries ) ; + int get_baud_rate_idx( BAUD_RATE baud_rate ) ; + int get_framing_idx( const char *framing ) ; + void port_settings_from_port_parm_mode( PORT_SETTINGS *p_ps, uint8_t pp_mode, int str_type_cap ) ; + void port_parm_mode_from_port_settings( uint8_t *pp_mode, const PORT_SETTINGS *p_ps, int str_type_cap ) ; + void port_settings_from_port_parm( PORT_SETTINGS *p_ps, int port_num, const PORT_PARM *p_pp, int cap_str_idx ) ; + void port_parm_from_port_settings( PORT_PARM *p_pp, int port_num, const PORT_SETTINGS *p_ps, int cap_str_idx ) ; + int check_valid_port_info( const PORT_INFO *p, const STR_TYPE_INFO_IDX str_type_info_idx[], int n_str_type ) ; + int valid_port_info( const PORT_INFO *p, const STR_TYPE_INFO_IDX str_type_info_idx[], int n_str_type ) ; + +/* ----- function prototypes end ----- */ + + +#ifdef __cplusplus +} +#endif + + +#if defined( _USE_PACK ) // set default alignment + #pragma pack() +#endif + +/* End of header body */ + +#undef _ext +#undef _DO_INIT + +#endif /* _PARMGPS_H */ + diff --git a/mbglib/common/parmpcps.c b/mbglib/common/parmpcps.c new file mode 100755 index 0000000..cd02754 --- /dev/null +++ b/mbglib/common/parmpcps.c @@ -0,0 +1,115 @@ + +/************************************************************************** + * + * $Id: parmpcps.c 1.4 2004/11/09 14:24:15 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Functions to handle/convert parameters used by Meinberg plug-in + * radio clocks. + * + * ----------------------------------------------------------------------- + * $Log: parmpcps.c $ + * Revision 1.4 2004/11/09 14:24:15 martin + * Redefined interface data types using C99 fixed-size definitions. + * Revision 1.3 2003/04/17 10:43:35Z martin + * Moved some definitions to parmpcps.h. + * Removed some functions which are now in mbgdevio.c. + * Revision 1.2 2002/03/25 09:03:43Z MARTIN + * Fixed a bug where the wrong framing was configured for DCF77 clocks. + * Revision 1.1 2002/02/19 14:00:19 MARTIN + * Initial revision + * + **************************************************************************/ + +#define _PARMPCPS + #include +#undef _PARMPCPS + +#include +#include +#include + +#include + + +static const int pcps_to_mbg_framing_tbl[N_PCPS_FR_DCF] = +{ + MBG_FRAMING_8N1, + MBG_FRAMING_7E2, + MBG_FRAMING_8N2, + MBG_FRAMING_8E1 +}; + + + +/*HDR*/ +void port_info_from_pcps_serial( + PORT_INFO_IDX *p_pii, + PCPS_SERIAL pcps_serial, + uint32_t supp_baud_rates +) +{ + PCPS_SER_PACK ser_pack; + PORT_INFO *p_pi; + PORT_SETTINGS *p_ps; + + ser_pack.pack = pcps_serial; + pcps_unpack_serial( &ser_pack ); + + p_pi = &p_pii[0].port_info; + p_ps = &p_pi->port_settings; + + p_ps->parm.baud_rate = mbg_baud_rate[ser_pack.baud]; + + _strncpy_0( p_ps->parm.framing, + mbg_framing_str[pcps_to_mbg_framing_tbl[ser_pack.frame]] ); + + p_ps->parm.handshake = HS_NONE; + + p_ps->str_type = 0; + p_ps->mode = ser_pack.mode; + + p_pi->supp_baud_rates = supp_baud_rates; + p_pi->supp_framings = DEFAULT_FRAMINGS_DCF; + p_pi->supp_str_types = DEFAULT_SUPP_STR_TYPES_DCF; + +} // port_info_from_pcps_serial + + +/*HDR*/ +void pcps_serial_from_port_info( + PCPS_SERIAL *p, + const PORT_INFO_IDX *p_pii +) +{ + PCPS_SER_PACK ser_pack; + const PORT_INFO *p_pi = &p_pii[0].port_info; + const PORT_SETTINGS *p_ps = &p_pi->port_settings; + int framing_idx = get_framing_idx( p_ps->parm.framing ); + int i; + + + ser_pack.baud = get_baud_rate_idx( p_ps->parm.baud_rate ); + + // Translate the common framing index to the corresponding + // number used with the old PCPS_SERIAL parameter. + // This should always return a valid result since the + // framing index is expected to be selected from + // supported framings. + for ( i = 0; i < N_PCPS_FR_DCF; i++ ) + if ( pcps_to_mbg_framing_tbl[i] == framing_idx ) + break; + + ser_pack.frame = i; + + ser_pack.mode = p_ps->mode; + + pcps_pack_serial( &ser_pack ); + + *p = ser_pack.pack; + +} // pcps_serial_from_port_info + + diff --git a/mbglib/common/parmpcps.h b/mbglib/common/parmpcps.h new file mode 100755 index 0000000..6bad879 --- /dev/null +++ b/mbglib/common/parmpcps.h @@ -0,0 +1,154 @@ + +/************************************************************************** + * + * $Id: parmpcps.h 1.5 2004/11/09 14:24:58 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes for parmpcps.c. + * + * ----------------------------------------------------------------------- + * $Log: parmpcps.h $ + * Revision 1.5 2004/11/09 14:24:58 martin + * Updated function prototypes. + * Revision 1.4 2004/05/19 07:52:25Z martin + * Fixed macro setting default number of string types. + * Revision 1.3 2004/04/14 09:21:44Z martin + * Pack structures 1 byte aligned. + * Revision 1.2 2003/04/17 10:42:46Z martin + * Moved typedef RECEIVER_PORT_CFG to pcpsdev.h. + * Moved some definitions from parmpcps.c here. + * Removed some global variables. + * Updated function prototypes. + * Revision 1.1 2002/02/19 14:00:19Z MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _PARMPCPS_H +#define _PARMPCPS_H + +/* Other headers to be included */ + +#include +#include + + +#ifdef _PARMPCPS + #define _ext + #define _DO_INIT +#else + #define _ext extern +#endif + + +/* Start of header body */ + +#if defined( _USE_PACK ) // set byte alignment + #pragma pack( 1 ) +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define DEFAULT_BAUD_RATES_DCF \ +( \ + MBG_PORT_HAS_300 | \ + MBG_PORT_HAS_600 | \ + MBG_PORT_HAS_1200 | \ + MBG_PORT_HAS_2400 | \ + MBG_PORT_HAS_4800 | \ + MBG_PORT_HAS_9600 \ +) + +#define DEFAULT_BAUD_RATES_DCF_HS \ +( \ + MBG_PORT_HAS_300 | \ + MBG_PORT_HAS_600 | \ + MBG_PORT_HAS_1200 | \ + MBG_PORT_HAS_2400 | \ + MBG_PORT_HAS_4800 | \ + MBG_PORT_HAS_9600 | \ + MBG_PORT_HAS_19200 | \ + MBG_PORT_HAS_38400 \ +) + + +#define DEFAULT_FRAMINGS_DCF \ +( \ + MBG_PORT_HAS_7E2 | \ + MBG_PORT_HAS_8N1 | \ + MBG_PORT_HAS_8N2 | \ + MBG_PORT_HAS_8E1 \ +) + + +#define DEFAULT_N_STR_TYPE_DCF 1 + +#define DEFAULT_SUPP_STR_TYPES_DCF \ + ( ( 1UL << DEFAULT_N_STR_TYPE_DCF ) - 1 ) + + +/* + * The macro below can be used to initialize a + * RECEIVER_INFO structure for DCF77 receivers + * which don't supply that structure. + * + * Parameters: (RECEIVER_INFO *) _p + */ +#define _setup_default_receiver_info_dcf( _p, _pdev ); \ +{ \ + memset( (_p), 0, sizeof( *(_p) ) ); \ + \ + (_p)->ticks_per_sec = DEFAULT_GPS_TICKS_PER_SEC; \ + (_p)->n_ucaps = 0; \ + (_p)->n_com_ports = _pcps_has_serial( _pdev ) ? 1 : 0; \ + (_p)->n_str_type = ( (_p)->n_com_ports != 0 ) ? \ + DEFAULT_N_STR_TYPE_DCF : 0; \ +} + + +#define DEFAULT_MAX_STR_TYPE 2 //##++DEFAULT_N_STR_TYPE_GPS + +_ext STR_TYPE_INFO default_str_type_info[DEFAULT_MAX_STR_TYPE] +#ifdef _DO_INIT + = { + { DEFAULT_STR_MODES, "Default Time String", "Time", 0 }, + { DEFAULT_STR_MODES_UCAP, "Capture String", "Cap", 0 } + } +#endif +; + + + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + + void port_info_from_pcps_serial( PORT_INFO_IDX *p_pii, PCPS_SERIAL pcps_serial, uint32_t supp_baud_rates ) ; + void pcps_serial_from_port_info( PCPS_SERIAL *p, const PORT_INFO_IDX *p_pii ) ; + +/* ----- function prototypes end ----- */ + + +#ifdef __cplusplus +} +#endif + + +#if defined( _USE_PACK ) // set default alignment + #pragma pack() +#endif + +/* End of header body */ + + +#undef _ext +#undef _DO_INIT + +#endif /* _PARMPCPS_H */ diff --git a/mbglib/common/pci.h b/mbglib/common/pci.h new file mode 100755 index 0000000..fc8abb5 --- /dev/null +++ b/mbglib/common/pci.h @@ -0,0 +1,162 @@ + +/************************************************************************** + * + * $Id: pci.h 1.9 2008/01/30 13:42:29 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions used to access the PC PCI BIOS. + * + * ----------------------------------------------------------------------- + * $Log: pci.h $ + * Revision 1.9 2008/01/30 13:42:29 martin + * Code cleanup to support different build environments properly. + * Revision 1.8 2006/07/11 08:59:00Z martin + * Account for PCI functions having been renamed in the library. + * Revision 1.7 2003/02/19 16:51:21Z martin + * Include pci_nt.h for Win32 non-pnp. + * Revision 1.6 2002/02/19 09:28:00Z MARTIN + * Use new header mbg_tgt.h to check the target environment. + * Revision 1.5 2002/01/15 15:47:30 Udo + * Don't include pci_nt.h under Win32. + * Revision 1.4 2001/03/15 13:01:40Z MARTIN + * Redefined preprocessor control for Win32. + * Revision 1.3 2001/03/01 09:23:36 MARTIN + * Added QNX support. + * Modified preprocessor syntax. + * Revision 1.2 2000/07/21 12:18:16 MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _PCI_H +#define _PCI_H + + +/* Other headers to be included */ + +#include + +#if defined( MBG_TGT_NETWARE ) + + #include // PCI functions for NetWare + +#elif defined( MBG_TGT_OS2 ) + + #include // PCI functions for OS/2 + +#elif defined( MBG_TGT_WIN32 ) + + #if !defined( MBG_TGT_WIN32_PNP ) + #include // PCI functions for Win32/non-pnp + #endif + +#elif defined( MBG_TGT_LINUX ) + + #include // PCI functions for Linux + +#elif defined( MBG_TGT_QNX ) + + #include // PCI functions for QNX + +#elif defined( MBG_TGT_DOS ) + + #include // PCI functions for DOS + +#endif + + + +#ifdef _PCI + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + +#if !defined( pci_fnc_init ) + #define pci_fnc_init() 0 +#endif + +#if !defined( pci_fnc_deinit ) + #define pci_fnc_deinit() +#endif + + +#if !defined( _mbg_pci_find_bios ) + #define _mbg_pci_find_bios mbg_pci_find_bios +#endif + +#if !defined( _mbg_pci_find_device ) + #define _mbg_pci_find_device mbg_pci_find_device +#endif + + +#if defined( MBG_PCI_MACROS_MAP_DIRECT ) + + #define _mbg_pci_find_device mbg_pci_find_device + #define _mbg_pci_read_cfg_byte mbg_pci_read_cfg_byte + #define _mbg_pci_read_cfg_word mbg_pci_read_cfg_word + #define _mbg_pci_read_cfg_dword mbg_pci_read_cfg_dword + #define _mbg_pci_write_cfg_byte mbg_pci_write_cfg_byte + #define _mbg_pci_write_cfg_word mbg_pci_write_cfg_word + #define _mbg_pci_write_cfg_dword mbg_pci_write_cfg_dword + +#endif // defined( MBG_PCI_MACROS_MAP_DIRECT ) + + +#if defined( MBG_PCI_MACROS_MAP_GENERIC ) + + #define _mbg_pci_read_cfg_byte( bus, dev_fnc, reg, addr ) \ + mbg_pci_read_cfg_reg( bus, dev_fnc, reg, sizeof( uint8_t ), addr ) + + #define _mbg_pci_read_cfg_word( bus, dev_fnc, reg, addr ) \ + mbg_pci_read_cfg_reg( bus, dev_fnc, reg, sizeof( uint16_t ), addr ) + + #define _mbg_pci_read_cfg_dword( bus, dev_fnc, reg, addr ) \ + mbg_pci_read_cfg_reg( bus, dev_fnc, reg, sizeof( uint32_t ), addr ) + + + #define _mbg_pci_write_cfg_byte( bus, dev_fnc, reg, addr ) \ + mbg_pci_write_cfg_reg( bus, dev_fnc, reg, sizeof( uint8_t ), addr ) + + #define _mbg_pci_write_cfg_word( bus, dev_fnc, reg, addr ) \ + mbg_pci_write_cfg_reg( bus, dev_fnc, reg, sizeof( uint16_t ), addr ) + + #define _mbg_pci_write_cfg_dword( bus, dev_fnc, reg, addr ) \ + mbg_pci_write_cfg_reg( bus, dev_fnc, reg, sizeof( uint32_t ), addr ) + +#endif // defined( MBG_PCI_MACROS_MAP_GENERIC ) + + +/* End of header body */ + +#undef _ext + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + +/* (no header definitions found) */ + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +#endif /* _PCI_H */ + + diff --git a/mbglib/common/pci_asic.h b/mbglib/common/pci_asic.h new file mode 100755 index 0000000..2feef9b --- /dev/null +++ b/mbglib/common/pci_asic.h @@ -0,0 +1,333 @@ + +/************************************************************************** + * + * $Id: pci_asic.h 1.16 2010/04/16 11:12:21 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions for the Meinberg PCI interface ASIC. + * + * ----------------------------------------------------------------------- + * $Log: pci_asic.h $ + * Revision 1.16 2010/04/16 11:12:21 martin + * Updated GPS170PEX ASIC version. + * Revision 1.15 2009/03/27 09:39:15 martin + * Increased current ASIC minor number for TCR170PEX to 0x02. + * Renamed some symbols. + * Revision 1.14 2009/03/11 16:54:10Z martin + * Increased current ASIC minor number for TCR511PEX to 0x04. + * Fixed a typo. + * Revision 1.13 2008/12/05 12:28:18Z martin + * Modified syntax of macro _convert_asic_version_number(). + * Added macros to deal with the ASIC version number. + * Added definition PCI_ASIC_HAS_PGMB_IRQ. + * Added ASIC revision numbers for PEX511, TCR511PEX, and GPS170PEX + * which fix an IRQ bug with these cards. + * Added definitions for PTP270PEX, FRC511PEX, and TCR170PEX. + * Revision 1.12 2008/07/21 10:30:00Z martin + * Added macros to convert the endianess of data types. + * Added PCI_ASIC_CURRENT_MINOR_... symbols. + * Revision 1.11 2008/06/11 09:49:43 martin + * Added definitions and comments how to handle version numbers + * of the PCI and PEX interface chips and EPLDs. + * Revision 1.10 2008/02/29 15:21:48Z martin + * Added definition PCI_ASIC_HAS_MM_IO. + * Revision 1.9 2008/01/17 09:51:05 daniel + * Added macro _convert_asic_version_number(). + * Cleanup for PCI ASIC version and features. + * Revision 1.8 2006/06/14 12:59:12Z martin + * Added support for TCR511PCI. + * Revision 1.7 2006/03/10 10:47:03 martin + * Added support for PCI511. + * Revision 1.6 2005/11/03 15:30:44Z martin + * Added support for GPS170PCI. + * Revision 1.5 2004/11/09 12:51:56Z martin + * Redefined fixed width data types using standard C99 types. + * Defined some constants unsigned. + * Revision 1.4 2004/10/14 15:01:23 martin + * Added support for TCR167PCI. + * Revision 1.3 2003/05/13 14:38:55Z MARTIN + * Added ushort fields to unions PCI_ASIC_REG and + * PCI_ASIC_ADDON_DATA. + * Revision 1.2 2003/04/03 10:56:38 martin + * Use unions for registers. + * Modified BADR0 initializer due to fixed size of address decoder. + * Revision 1.1 2003/02/07 11:42:52 MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _PCI_ASIC_H +#define _PCI_ASIC_H + + +/* Other headers to be included */ + +#include +#include + +#if defined( _USE_PACK ) // set byte alignment + #pragma pack( 1 ) +#endif + + +#ifdef _PCI_ASIC + #define _ext + #define _DO_INIT +#else + #define _ext extern +#endif + + +/* Start of header body */ + + +typedef struct +{ + uint32_t cfg_class_rev_id; + uint16_t cfg_badr_0; + uint16_t cfg_dev_id; +} PCI_ASIC_CFG; + + +typedef union +{ + uint32_t ul; + uint16_t us[2]; + uint8_t b[4]; +} PCI_ASIC_REG; + + +typedef uint32_t PCI_ASIC_VERSION; +#define _mbg_swab_asic_version( _p ) _mbg_swab32( _p ) + +typedef uint32_t PCI_ASIC_FEATURES; +#define _mbg_swab_asic_features( _p ) _mbg_swab32( _p ) + +#define PCI_ASIC_HAS_MM_IO 0x0001 +#define PCI_ASIC_HAS_PGMB_IRQ 0x0002 + + +typedef union +{ + uint32_t ul[4]; + uint16_t us[8]; + uint8_t b[16]; +} PCI_ASIC_ADDON_DATA; + + +typedef struct +{ + PCI_ASIC_CFG cfg; // writeable from add-on once after power-up + PCI_ASIC_VERSION raw_version; + PCI_ASIC_FEATURES features; + PCI_ASIC_REG status_port; + PCI_ASIC_REG control_status; // codes defined below + PCI_ASIC_REG pci_data; // pass byte from PCI bus to add-on + PCI_ASIC_REG reserved_1; + + PCI_ASIC_ADDON_DATA addon_data; // returns data from add-on to PCI bus + PCI_ASIC_ADDON_DATA reserved_2; // currently not implemented +} PCI_ASIC; + + +// The following bits are used with the control_status register. +// All other bits are reserved for future use. + +// The IRQ flag for the add-on side is set whenever data is +// written to the cmd register. It is cleared if the add-on +// microcontroller writes this bit back to the control_status +// register. If the bit is set, the add-on signals /ADD_ON_IRQ +// and ADD_ON_BUSY are asserted. +#define PCI_ASIC_ADD_ON_IRQF 0x00000001UL + +// The IRQ flag for the PCI bus is set whenever the add-on +// microcontroller asserts the ASIC's /PCI_IRQ line, or the +// add-on microcontroller sets this bit to 1. It is cleared +// if this bit is written back from the PCI side. If the bit +// is set, an IRQ is asserted on the PCI bus. +#define PCI_ASIC_PCI_IRQF 0x00010000UL + + +// The ASIC's address decoder always decodes 8 bits, so +// each device must request at least that number of +// addresses from the PCI BIOS: +#define PCI_ASIC_ADDR_RANGE 0x100U + + +// Initializers for device configurations + +#define PCPS_DEV_CLASS_CODE 0x08800000UL +#define PCI_ASIC_BADR0_INIT ( ~( PCI_ASIC_ADDR_RANGE - 1 ) | 0x01 ) + + +#define PCI_ASIC_CFG_PCI510 \ +{ \ + _hilo_32( PCPS_DEV_CLASS_CODE ), \ + _hilo_16( PCI_ASIC_BADR0_INIT ), \ + _hilo_16( PCI_DEV_PCI510 ) \ +} + +#define PCI_ASIC_CFG_GPS169PCI \ +{ \ + _hilo_32( PCPS_DEV_CLASS_CODE ), \ + _hilo_16( PCI_ASIC_BADR0_INIT ), \ + _hilo_16( PCI_DEV_GPS169PCI ) \ +} + +#define PCI_ASIC_CFG_TCR510PCI \ +{ \ + _hilo_32( PCPS_DEV_CLASS_CODE ), \ + _hilo_16( PCI_ASIC_BADR0_INIT ), \ + _hilo_16( PCI_DEV_TCR510PCI ) \ +} + +#define PCI_ASIC_CFG_TCR167PCI \ +{ \ + _hilo_32( PCPS_DEV_CLASS_CODE ), \ + _hilo_16( PCI_ASIC_BADR0_INIT ), \ + _hilo_16( PCI_DEV_TCR167PCI ) \ +} + +#define PCI_ASIC_CFG_GPS170PCI \ +{ \ + _hilo_32( PCPS_DEV_CLASS_CODE ), \ + _hilo_16( PCI_ASIC_BADR0_INIT ), \ + _hilo_16( PCI_DEV_GPS170PCI ) \ +} + +#define PCI_ASIC_CFG_PCI511 \ +{ \ + _hilo_32( PCPS_DEV_CLASS_CODE ), \ + _hilo_16( PCI_ASIC_BADR0_INIT ), \ + _hilo_16( PCI_DEV_PCI511 ) \ +} + +#define PCI_ASIC_CFG_TCR511PCI \ +{ \ + _hilo_32( PCPS_DEV_CLASS_CODE ), \ + _hilo_16( PCI_ASIC_BADR0_INIT ), \ + _hilo_16( PCI_DEV_TCR511PCI ) \ +} + +/* + Handling of the version numbers of the PCI interface + chips has changed between the ASICs used for standard PCI + and the EPLDs used to configure the PEX8311 chip + for a specific device. + + The macro below can be used to convert both types + of version number into the same format so that the + version numbers can be handled in the same way: +*/ +#define _convert_asic_version_number( _n ) \ + ( ( (_n) < 0x100 ) ? ( (_n) << 8 ) : (_n) ) + + + +/* + * Macros to extract the major and minor part of an ASIC version number */ + +#define _pcps_asic_version_major( _v ) \ + ( ( (_v) >> 8 ) & 0xFF ) + +#define _pcps_asic_version_minor( _v ) \ + ( (_v) & 0xFF ) + + +/* + * Macros to check whether a version number is correct + * and matches a required minimum version + */ +#define _pcps_asic_version_greater_equal( _v, _v_major, _v_minor ) \ + ( \ + ( _pcps_asic_version_major( _v ) == (_v_major) ) && \ + ( _pcps_asic_version_minor( _v ) >= (_v_minor) ) \ + ) + + +/* + The low byte of the converted version number is handled + as a minor version, whereas the remaining upper bytes are + interpreted as a major number which may be specific + for a device. +*/ +enum +{ + PCI_ASIC_MAJOR_PCI_0, // PCI ASIC with CRC bug + PCI_ASIC_MAJOR_PCI_1, // fixed version of PCI ASIC + PCI_ASIC_MAJOR_PEX511, // PEX EPLD for PEX511 + PCI_ASIC_MAJOR_GPS170PEX, // PEX EPLD for GPS170PEX + PCI_ASIC_MAJOR_TCR511PEX, // PEX EPLD for TCR511PEX + PCI_ASIC_MAJOR_PTP270PEX, // PEX EPLD for PTP270PEX + PCI_ASIC_MAJOR_FRC511PEX, // PEX EPLD for FRC511PEX + PCI_ASIC_MAJOR_TCR170PEX, // PEX EPLD for TCR170PEX + N_PCI_ASIC_MAJOR // the number of known codes +}; + +/* + The minor number increases when a new EPLD image is released. + At least EPLD images with the following "required minor" numbers + should be installed for proper operation. The "current minor" + numbers can be used to check if a newer EPLD image is available: +*/ +#define PCI_ASIC_CURRENT_MINOR_PEX511 0x04 +#define PCI_ASIC_REQUIRED_MINOR_PEX511 0x03 +#define PCI_ASIC_FIX_HRT_MINOR_PEX511 0x04 // increases HRT accuracy +#define PCI_ASIC_FIX_IRQ_MINOR_PEX511 0x03 // fixes IRQ problem +#define PCI_ASIC_HR_TIME_MINOR_PEX511 0x02 // supports HR time with PEX511 + +#define PCI_ASIC_CURRENT_MINOR_GPS170PEX 0x05 +#define PCI_ASIC_REQUIRED_MINOR_GPS170PEX 0x03 +#define PCI_ASIC_ENH_HRT_MINOR_GPS170PEX 0x05 // enhanced MM HRT accuracy +#define PCI_ASIC_FIX_HRT_MINOR_GPS170PEX 0x04 // increases MM HRT accuracy +#define PCI_ASIC_FIX_IRQ_MINOR_GPS170PEX 0x03 // fixes IRQ problem + +#define PCI_ASIC_CURRENT_MINOR_TCR511PEX 0x04 +#define PCI_ASIC_REQUIRED_MINOR_TCR511PEX 0x03 +// 0x04 // EPLD sources shared with PEX511 0x04 +#define PCI_ASIC_FIX_IRQ_MINOR_TCR511PEX 0x03 // fixes IRQ problem, increases HRT accuracy + +#define PCI_ASIC_CURRENT_MINOR_PTP270PEX 0x01 +#define PCI_ASIC_REQUIRED_MINOR_PTP270PEX 0x01 + +#define PCI_ASIC_CURRENT_MINOR_FRC511PEX 0x01 +#define PCI_ASIC_REQUIRED_MINOR_FRC511PEX 0x01 + +#define PCI_ASIC_CURRENT_MINOR_TCR170PEX 0x02 +#define PCI_ASIC_REQUIRED_MINOR_TCR170PEX 0x02 +#define PCI_ASIC_FIX_EE_ACCESS_TCR170PEX 0x02 // fixes EE access problem after reset + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + +/* (no header definitions found) */ + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +#if defined( _USE_PACK ) // set default alignment + #pragma pack() +#endif + +/* End of header body */ + +#undef _ext +#undef _DO_INIT + +#endif /* _PCI_ASIC_H */ + diff --git a/mbglib/common/pcidefs.h b/mbglib/common/pcidefs.h new file mode 100755 index 0000000..ed365d2 --- /dev/null +++ b/mbglib/common/pcidefs.h @@ -0,0 +1,251 @@ + +/************************************************************************** + * + * $Id: pcidefs.h 1.7 2008/06/09 10:43:09 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Common definitions to be used with PCI. + * + * ----------------------------------------------------------------------- + * $Log: pcidefs.h $ + * Revision 1.7 2008/06/09 10:43:09 martin + * Added PCI_CMD_ENB_MEM_ACC code. + * Revision 1.6 2005/09/19 13:06:15Z martin + * Added definition for number of base address registers. + * Revision 1.5 2004/11/09 13:15:05Z martin + * Redefined interface data types using C99 fixed-size definitions. + * Revision 1.4 2001/02/05 16:28:21Z MARTIN + * Don't include stdlib.h. + * Revision 1.3 2000/09/11 13:51:10 MARTIN + * Moved structure PCI_IRQ_ROUTE_BUFFER to pci_dos.h. + * Revision 1.2 2000/07/21 11:56:20 MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _PCIDEFS_H +#define _PCIDEFS_H + + +/* Other headers to be included */ + +#include + + +#ifdef _PCIDEFS + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + + +// Available PCI subfunction codes depend on the operating system +// so they are defined in the associated headers. + +// The interrupt number used to access PCI BIOS in real mode: +#define PCI_BIOS_INT 0x1A + + +// The function code is put into the AH register when a PCI function +// is called: +#define PCI_BIOS_FNC 0xB1 + + +// The PCI subfunction codes listed below are put into the AL register +// when PCI functions are called. Other registers must be set according +// to the subfunction specs: +#define PCI_BIOS_PRESENT 0x01 +#define PCI_FIND_DEVICE 0x02 +#define PCI_FIND_CLASS_CODE 0x03 +#define PCI_GEN_SPECIAL_CYCLE 0x06 +#define PCI_READ_CFG_BYTE 0x08 +#define PCI_READ_CFG_WORD 0x09 +#define PCI_READ_CFG_DWORD 0x0A +#define PCI_WRITE_CFG_BYTE 0x0B +#define PCI_WRITE_CFG_WORD 0x0C +#define PCI_WRITE_CFG_DWORD 0x0D +#define PCI_GET_IRQ_ROUTING 0x0E + + +// List of PCI BIOS return codes: +#define PCI_SUCCESS 0x00 +#define PCI_NO_SUCCESS 0x01 // (not returned by BIOS) +#define PCI_FUNC_NOT_SUPP 0x81 +#define PCI_BAD_VENDOR_ID 0x83 +#define PCI_DEVICE_NOT_FOUND 0x86 +#define PCI_BAD_REGISTER_NUMB 0x87 +#define PCI_BUFFER_TOO_SMALL 0x89 + + +// The 80x86 Flags Register Carry Flag bit returns completion status. +// If the Carry Flag is set, the function call did not succeed. +#define CARRY_FLAG 0x01 + + +// The signature "PCI " is returned in EDX when the subfunction +// PCI_BIOS_PRESENT has been called: +#define PCI_BIOS_SIGNATURE 0x20494350UL + + +// The code below represents an invalid vendor id +// or wildcard: +#define PCI_INV_VENDOR_ID 0xFFFFU + + +// The number of possible PCI devices per bus: +#define PCI_DEVICES_PER_BUS 32 + + +// A variable of the type below is used to keep +// the PCI interrupt routing information: +typedef struct +{ + uint8_t bus; + uint8_t device_number; + uint8_t inta_link; + uint16_t inta_map; + uint8_t intb_link; + uint16_t intb_map; + uint8_t intc_link; + uint16_t intc_map; + uint8_t intd_link; + uint16_t intd_map; + uint8_t slot; + uint8_t reserved; +} PCI_IRQ_ROUTE_ENTRY; + + +// List of PCI BIOS return codes + +#define PCI_SUCCESS 0x00 +#define PCI_NO_SUCCESS 0x01 // not returned by BIOS +#define PCI_FUNC_NOT_SUPP 0x81 +#define PCI_BAD_VENDOR_ID 0x83 +#define PCI_DEVICE_NOT_FOUND 0x86 +#define PCI_BAD_REGISTER_NUMB 0x87 +#define PCI_BUFFER_TOO_SMALL 0x89 + + + +// The 80x86 flags register carry flag bit returns completion status. +// If the carry flag is set, the function call did not succeed. + +#ifndef CARRY_FLAG + #define CARRY_FLAG 0x01 +#endif + + +// The signature "PCI " is returned in EDX when the subfunction +// PCI_BIOS_PRESENT has been called. + +#define PCI_BIOS_SIGNATURE 0x20494350UL + + +// PCI configuration space registers + +#define PCI_CS_VENDOR_ID 0x00 +#define PCI_CS_DEVICE_ID 0x02 +#define PCI_CS_COMMAND 0x04 +#define PCI_CS_STATUS 0x06 +#define PCI_CS_REVISION_ID 0x08 +#define PCI_CS_CLASS_CODE 0x09 +#define PCI_CS_CACHE_LINE_SIZE 0x0C +#define PCI_CS_MASTER_LATENCY 0x0D +#define PCI_CS_HEADER_TYPE 0x0E +#define PCI_CS_BIST 0x0F +#define PCI_CS_BASE_ADDRESS_0 0x10 +#define PCI_CS_BASE_ADDRESS_1 0x14 +#define PCI_CS_BASE_ADDRESS_2 0x18 +#define PCI_CS_BASE_ADDRESS_3 0x1C +#define PCI_CS_BASE_ADDRESS_4 0x20 +#define PCI_CS_BASE_ADDRESS_5 0x24 +#define PCI_CS_EXPANSION_ROM 0x30 +#define PCI_CS_INTERRUPT_LINE 0x3C +#define PCI_CS_INTERRUPT_PIN 0x3D +#define PCI_CS_MIN_GNT 0x3E +#define PCI_CS_MAX_LAT 0x3F + +#define PCI_CS_N_BASE_ADDRESS 6 /* max number of address spaces */ + + +#define PCI_CMD_ENB_IO_ACC 0x01 +#define PCI_CMD_ENB_MEM_ACC 0x02 + + +typedef struct +{ + uint8_t prog_if; + uint8_t sub; + uint8_t base; +} PCI_CLASS; + +#define PCI_N_BASE_ADDR_FIELD 6 + +typedef struct +{ + uint16_t vendor_id; + uint16_t device_id; + uint16_t command; + uint16_t status; + uint8_t revision_id; + PCI_CLASS class_code; + uint8_t cache_line_size; + uint8_t latency_timer; + uint8_t header_type; + uint8_t bist; + uint32_t base_addr[PCI_N_BASE_ADDR_FIELD]; + uint32_t cardbus_cis; + uint16_t sub_vendor_id; + uint16_t sub_system_id; + uint32_t expansion_rom_base; + uint32_t res_0; + uint32_t res_1; + uint8_t irq_line; + uint8_t irq_pin; + uint8_t min_gnt; + uint8_t max_lat; +} PCI_CFG_SPACE; + + + +// some known vendor IDs, in alphabetical order: + +#define PCI_VENDOR_3COM 0x10B7 +#define PCI_VENDOR_ADAPTEC_1 0x9004 +#define PCI_VENDOR_ADAPTEC_2 0x9005 +#define PCI_VENDOR_AMCC 0x10E8 +#define PCI_VENDOR_AMD 0x1022 +#define PCI_VENDOR_ASUS 0x1000 +#define PCI_VENDOR_CIRRUS_LOGIC 0x1013 +#define PCI_VENDOR_ELSA 0x5333 +#define PCI_VENDOR_IBM 0x1014 +#define PCI_VENDOR_INTEL 0x8086 +#define PCI_VENDOR_MATROX 0x102B +#define PCI_VENDOR_MEINBERG 0x1360 + +/* End of header body */ + +#undef _ext + + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +// currently none + +#ifdef __cplusplus +} +#endif + + +#endif /* _PCIDEFS_H */ + diff --git a/mbglib/common/pcpsdefs.h b/mbglib/common/pcpsdefs.h new file mode 100755 index 0000000..f499e3c --- /dev/null +++ b/mbglib/common/pcpsdefs.h @@ -0,0 +1,1273 @@ + +/************************************************************************** + * + * $Id: pcpsdefs.h 1.46 2011/01/13 11:44:29 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * General definitions for Meinberg plug-in radio clocks + * + * ----------------------------------------------------------------------- + * $Log: pcpsdefs.h $ + * Revision 1.46 2011/01/13 11:44:29 martin + * Moved status port register definitions here. + * Revision 1.45 2010/09/06 07:36:24 martin + * Support GPS180PEX and TCR180PEX. + * Moved some IRIG related definitions to gpsdefs.h. + * Revision 1.44 2010/06/30 11:09:49 martin + * Added definitions for JJY longwave transmitter. + * Renamed MBG_RAW_IRIG_DATA::data field to data_bytes + * since "data" is a reserved word for C51 architecture. + * Revision 1.43 2010/02/09 11:20:17Z martin + * Renamed yet unused CORR_INFO::flags field to signal and updated comments. + * Revision 1.42 2010/01/12 14:02:37 daniel + * Added definitions to support reading the raw IRIG data bits. + * Revision 1.41 2009/06/19 12:16:42Z martin + * Added PCPS_GIVE_IRIG_TIME command and associated definitions. + * Revision 1.40 2009/06/08 19:29:11 daniel + * Support PTP configuration. + * Support LAN_IF configuration + * Added definition of PCPS_CMD_INFO. + * Revision 1.39 2009/03/19 08:58:09 martin + * Added PCPS_GET_IRIG_CTRL_BITS cmd and associated data type. + * Revision 1.38 2009/03/10 17:07:09 martin + * Support configurable time scales and GPS UTC parameters. + * Added ext. status flag for time scales, and PCPS_LS_ANN_NEG. + * Added bit mask PCPS_SCALE_MASK. + * Revision 1.37 2008/12/05 16:01:37Z martin + * Added ref types PTP, FRC, and WWVB. + * Added ref names MSF, PTP, FRC, and WWVB. + * Added device codes TCR170PEX, PTP270PEX, and FRC511PEX. + * Added macros to convert the endianess of structures. + * Moved definitions of PCPS_HRT_FRAC_SCALE and + * PCPS_HRT_FRAC_SCALE_FMT here. + * Added definitions of PCPS_HRT_FRAC_CONVERSION_TYPE + * and PCPS_HRT_BIN_FRAC_SCALE. + * Escaped '<' and '>' characters for doxygen. + * Modified comments for PCPS_TZDL. + * Removed trailing spaces and obsolete comments. + * Revision 1.36 2008/01/17 09:20:25Z daniel + * Added new REF type PCPS_REF_MSF. + * Revision 1.35 2008/01/17 09:18:46Z daniel + * Made comments compatible for doxygen parser. + * No sourcecode changes. + * Revision 1.34 2007/07/17 08:22:47Z martin + * Added support for TCR511PEX and GPS170PEX. + * Revision 1.33 2007/05/20 21:39:51Z martin + * Added support for PEX511. + * Added PCPS_GET_STATUS_PORT cmd code for devices + * that do not support a hardware status port. + * Revision 1.32 2007/03/29 12:57:32Z martin + * Renamed some TZCODE numbers for unique naming conventions. + * Added definitions of the older symbols for compatibility. + * Revision 1.31 2007/03/26 15:42:31Z martin + * Replaced PCPS_REF_OFFS and associated definitions by MBG_REF_OFFS, etc., + * which are defined in gpsdefs.h. + * Added PCPS_GET_DEBUG_STATUS code. + * Revision 1.30 2006/06/29 10:13:13 martin + * Added some descriptive comments. + * Revision 1.29 2006/06/14 12:59:12Z martin + * Added support for TCR511PCI. + * Revision 1.28 2006/05/18 09:45:16 martin + * Added data types used with PZF receivers. + * Revision 1.27 2006/05/03 10:19:14Z martin + * Added initializers for reference source names. + * Revision 1.26 2006/03/10 10:24:45Z martin + * New definitions for PCI511. + * Added command codes to configure programmable pulse outputs. + * Revision 1.25 2005/11/03 15:05:16Z martin + * New definitions for GPS170PCI. + * New types PCPS_TIME_STATUS and PCPS_TIME_STATUS_X. + * Removed obsolete enumeration of PCPS_TIME fields. + * Revision 1.24 2005/05/03 07:56:55Z martin + * Added command PCPS_GET_SYNTH_STATE. + * Revision 1.23 2005/03/29 12:51:10Z martin + * New cmd code PCPS_GENERIC_IO. + * Revision 1.22 2004/12/09 11:03:37Z martin + * Support configuration of on-board frequency synthesizer. + * Revision 1.21 2004/11/09 12:55:32Z martin + * Redefined interface data types using C99 fixed-size definitions. + * Added workaround macros for some structure sizes because the C166 + * compiler always reports an even structure size even if the structure + * size is in fact odd, which might lead to different sizes in C166 and + * other environments. + * Modifications were required in order to be able to configure IRIG + * settings of cards which provide both IRIG input and output. + * The existing codes have been renamed with .._RX.. and are used to + * configure the IRIG receiver (input). New codes have been defined + * used to configure the IRIG transmitter. + * Renamed PC_GPS_STAT to PC_GPS_BVAR_STAT. + * Use more specific data types than generic types. + * Revision 1.20 2004/10/14 15:01:23 martin + * Added support for TCR167PCI. + * Revision 1.19 2004/06/16 12:46:33Z martin + * Moved OPT_SETTINGS related definitions to gpsdefs.h, + * and renamed symbols from PCPS_.. to to MBG_... + * Revision 1.18 2004/04/26 14:27:08Z martin + * Added union PCPS_TIME_UNION. + * Revision 1.17 2003/05/27 08:50:35Z MARTIN + * New commands PCPS_GIVE_UCAP_ENTRIES, PCPS_GIVE_UCAP_EVENT + * and associated definitions which allow faster reading of + * user capture events and monitoring of the capture buffer + * fill level. + * Revision 1.16 2003/04/03 10:48:53 martin + * Support for PCI510, GPS169PCI, and TCR510PCI. + * New codes PCPS_GET_REF_OFFS, PCPS_SET_REF_OFFS + * and related structures. + * New codes PCPS_GET_OPT_INFO, PCPS_SET_OPT_SETTINGS + * and related structures. + * New codes PCPS_GET_IRIG_INFO, PCPS_SET_IRIG_SETTINGS. + * Preliminary PCPS_TZDL structure and cmd codes + * to read/write that structure. + * Revision 1.15 2002/08/08 13:24:03 MARTIN + * Moved definition of ref time sources here. + * Added new ref time source IRIG. + * Added new cmd to clear time capture buffer. + * Fixed some comments. + * Revision 1.14 2002/01/31 13:39:38 MARTIN + * Added new GPS data type codes for RECEIVER_INFO, etc. + * New PCPS_HR_TIME status flag PCPS_IO_BLOCKED. + * Moved REV_NUMs defining special features to pcpsdev.h. + * Removed obsolete initializer for framing string table. + * Updated some comments. + * Removed obsolete code. + * Revision 1.13 2001/12/03 16:15:14 martin + * Introduced PCPS_TIME_STAMP which allows to handle high precision + * time stamps. + * Replaced the sec/frac fields in PCPS_HR_TIME by PCPS_TIME_STAMP. + * This is compatible on byte level but may require source code + * modifications. + * Introduced new command PCPS_SET_EVENT_TIME which is used + * EXCLUSIVELY with a custom GPS firmware. + * Revision 1.12 2001/10/16 10:07:42 MARTIN + * Defined PCI509 firmware revision number which supports + * baud rate higher than standard. + * Revision 1.11 2001/03/30 13:02:39 MARTIN + * Control alignment of structures from new file use_pack.h. + * Defined initializers with valid framing parameters. + * Revision 1.10 2001/02/28 15:39:25 MARTIN + * Modified preprocessor syntax. + * Revision 1.9 2001/02/16 11:32:05 MARTIN + * Renamed "PROM" or "EPROM" in comments or and names to + * "FW" or firmware. + * This includes the cmd codes PCPS_GIVE_PROM_ID_... which have + * been renamed to PCPS_GIVE_FW_ID_... + * Renamed structure PCPS_TIME_SET to PCPS_STIME. + * Renamed return code PCPS_ERR_NONE to PCPS_SUCCESS. + * Modified some comments. + * Revision 1.8 2000/10/11 09:17:09 MARTIN + * Cleaned up comment syntax. + * Revision 1.7 2000/07/21 14:16:30 MARTIN + * Modified some comments. + * Added PCI definitions. + * Renamed PCPS_GET_GPS_DATA to PCPS_READ_GPS_DATA. + * Renamed PCPS_SET_GPS_DATA to PCPS_WRITE_GPS_DATA. + * New types PCPS_SERIAL and PCPS_TZCODE. + * Removed PCPS_SERIAL_BYTES and PCPS_TZCODE_BYTES, may use sizeof() + * the types instead. + * New type PCPS_TIME_SET which can be used to write date and time + * to the clock. + * Revision 1.6 2000/06/07 12:09:31 MARTIN + * renamed PCPS_SERIAL_GROUP to PCPS_CFG_GROUP + * renamed PCPS_ERR_SERIAL to PCPS_ERR_CFG + * modified definitions for baud rate, framing, and mode + * added PCPS_SN_... definitions + * added PCPS_GET_TZCODE and PCPS_SET_TZCODE definitions + * added PC_GPS_ANT_CABLE_LEN definition + * added RCS keywords + * updated some comments + * + * ----------------------------------------------------------------------- + * Changes before put under RCS control: + * + * Revision 1.5 2000/03/24 + * Introduced PCPS_GIVE_SERNUM + * Cleaned up for definitions for serial parameter byte + * Reviewed and updated comments. + * + * 1998/07/22 + * Introduced PCPS_HR_TIME. + * Rearranged order of definitions. + * Reviewed and updated comments. + * + * 1997/06/12 + * GPS definitions added. + * + * 1996/01/25 + * PCPS_TIME redefined from an array of bytes to a structure. + * + **************************************************************************/ + +#ifndef _PCPSDEFS_H +#define _PCPSDEFS_H + + +/* Other headers to be included */ + +#include +#include + + +/* Start of header body */ + +#if defined( _USE_PACK ) // set byte alignment + #pragma pack( 1 ) +#endif + + +/** + * The following codes enumerate the ref time sources + * from which the clocks receive the reference time. + */ +enum +{ + PCPS_REF_NONE, /**< (unknown or not defined) */ + PCPS_REF_DCF, /**< see http://www.meinberg.de/english/info/dcf77.htm */ + PCPS_REF_GPS, /**< see http://www.meinberg.de/english/info/gps.htm */ + PCPS_REF_IRIG, /**< see http://www.meinberg.de/english/info/irig.htm */ + PCPS_REF_MSF, /**< MSF Receiver (UK) */ + PCPS_REF_PTP, /**< PTP Timestamp card */ + PCPS_REF_FRC, /**< Free Running Clock */ + PCPS_REF_WWVB, /**< WWVB Receiver (US) */ + PCPS_REF_JJY, /**< JJY Receiver (Japan) */ + N_PCPS_REF /**< number of valid ref time sources */ +}; + + +/* Initializers for the reference source names */ + +#define PCPS_REF_NAME_NONE_ENG "unknown" +#define PCPS_REF_NAME_NONE_GER "nicht bekannt" +#define PCPS_REF_NAME_DCF "DCF77" +#define PCPS_REF_NAME_GPS "GPS" +#define PCPS_REF_NAME_IRIG "IRIG" +#define PCPS_REF_NAME_MSF "MSF" +#define PCPS_REF_NAME_PTP "PTP" +#define PCPS_REF_NAME_FRC "FRC" +#define PCPS_REF_NAME_WWVB "WWVB" +#define PCPS_REF_NAME_JJY "JJY" + + +#define PCPS_REF_NAMES_ENG \ +{ \ + PCPS_REF_NAME_NONE_ENG, \ + PCPS_REF_NAME_DCF, \ + PCPS_REF_NAME_GPS, \ + PCPS_REF_NAME_IRIG, \ + PCPS_REF_NAME_MSF, \ + PCPS_REF_NAME_PTP, \ + PCPS_REF_NAME_FRC, \ + PCPS_REF_NAME_WWVB, \ + PCPS_REF_NAME_JJY \ +} + + +#define PCPS_REF_NAMES_LSTR \ +{ \ + { PCPS_REF_NAME_NONE_ENG, PCPS_REF_NAME_NONE_GER }, \ + { PCPS_REF_NAME_DCF, NULL }, \ + { PCPS_REF_NAME_GPS, NULL }, \ + { PCPS_REF_NAME_IRIG, NULL }, \ + { PCPS_REF_NAME_MSF, NULL }, \ + { PCPS_REF_NAME_PTP, NULL }, \ + { PCPS_REF_NAME_FRC, NULL }, \ + { PCPS_REF_NAME_WWVB, NULL }, \ + { PCPS_REF_NAME_JJY, NULL } \ +} + + + +/** + PCI vendor ID number (assigned by PCI SIG) +*/ +#define PCI_VENDOR_MEINBERG 0x1360 + +/* PCI device ID numbers (assigned by Meinberg) * + * High byte: type of ref time source + * Low Byte: enumeration of device types + */ +#define PCI_DEV_PCI32 ( ( PCPS_REF_DCF << 8 ) | 0x01 ) +#define PCI_DEV_PCI509 ( ( PCPS_REF_DCF << 8 ) | 0x02 ) +#define PCI_DEV_PCI510 ( ( PCPS_REF_DCF << 8 ) | 0x03 ) +#define PCI_DEV_PCI511 ( ( PCPS_REF_DCF << 8 ) | 0x04 ) +#define PCI_DEV_PEX511 ( ( PCPS_REF_DCF << 8 ) | 0x05 ) + +#define PCI_DEV_GPS167PCI ( ( PCPS_REF_GPS << 8 ) | 0x01 ) +#define PCI_DEV_GPS168PCI ( ( PCPS_REF_GPS << 8 ) | 0x02 ) +#define PCI_DEV_GPS169PCI ( ( PCPS_REF_GPS << 8 ) | 0x03 ) +#define PCI_DEV_GPS170PCI ( ( PCPS_REF_GPS << 8 ) | 0x04 ) +#define PCI_DEV_GPS170PEX ( ( PCPS_REF_GPS << 8 ) | 0x05 ) +#define PCI_DEV_GPS180PEX ( ( PCPS_REF_GPS << 8 ) | 0x06 ) + +#define PCI_DEV_TCR510PCI ( ( PCPS_REF_IRIG << 8 ) | 0x01 ) +#define PCI_DEV_TCR167PCI ( ( PCPS_REF_IRIG << 8 ) | 0x02 ) +#define PCI_DEV_TCR511PCI ( ( PCPS_REF_IRIG << 8 ) | 0x03 ) +#define PCI_DEV_TCR511PEX ( ( PCPS_REF_IRIG << 8 ) | 0x04 ) +#define PCI_DEV_TCR170PEX ( ( PCPS_REF_IRIG << 8 ) | 0x05 ) +#define PCI_DEV_TCR180PEX ( ( PCPS_REF_IRIG << 8 ) | 0x06 ) + +#define PCI_DEV_PTP270PEX ( ( PCPS_REF_PTP << 8 ) | 0x01 ) + +#define PCI_DEV_FRC511PEX ( ( PCPS_REF_FRC << 8 ) | 0x01 ) + + + +// definitions used for the status port register +// (not to be intermixed with PCPS_TIME_STATUS) +typedef uint8_t PCPS_STATUS_PORT; /**< see \ref group_status_port "Bitmask" */ + +/** @defgroup group_status_port Bit masks of PCPS_STATUS_PORT + + Bit definitions used with the #PCPS_STATUS_PORT register. + + The flags #PCPS_ST_SEC and #PCPS_ST_MIN are cleared whenever the clock + is read, so they are not very reliable in multitasking environments. + + NOTE: The PCPS_ST_IRQF flag originates from old ISA cards. + Some PCI cards also support this, but in case of PCI cards the + associated flag of the PCI interface chip should be checked to see + if a certain card has generated an IRQ on the PC bus. + + The macro _pcps_ddev_has_gen_irq() cares about this and should be used + to determine in a portable way whether a card has generated an IRQ. + + * @{ + */ + +#define PCPS_ST_BUSY 0x01 /**< the clock is busy filling the output FIFO */ +#define PCPS_ST_IRQF 0x02 /**< the clock has generated an IRQ on the PC bus (ISA only)*/ +#define PCPS_ST_MOD 0x20 /**< the raw demodulated DCF77 signal */ +#define PCPS_ST_SEC 0x40 /**< seconds have changed since last reading */ +#define PCPS_ST_MIN 0x80 /**< minutes have changed since last reading */ + +/** @} */ + + + +/** @defgroup group_cmd_bytes Command bytes used to access the device + + The commands described below can be used to access the Meinberg + computer peripherals. However, some of the commands have not been + implemented with older clock models, or firmware versions. + + The device driver library contains functions which detect the clocks + and check which features are supported by a given clock model/firmware + The header files pcpsdev.h and pcpsdrvr.h contain macros which can be + used to query whether a detected clock supports a feature. + If checking is required, the name of the macro is given in the + comments below. + + Some commands expect parameters to be passed to the board. In that + case, the board returns the number of parameter bytes expected when + the command code is passed. Every parameter byte has to be supplied + to the board exactly like a command byte. + Refer to function pcps_write_data() and the macro _pcps_write_var() + for details. + + + - #PCPS_GIVE_TIME
+ Return a PCPS_TIME structure with current date, + time and status. Supported by all clocks. + + - #PCPS_GIVE_TIME_NOCLEAR
+ Same as #PCPS_GIVE_TIME but the bits #PCPS_ST_SEC + and #PCPS_ST_MIN (see pcpsdev.h) of the status + port are not cleared. + Supported by all clocks except PC31/PS31 with + firmware version older than v3.0. + This is mainly used by the DOS TSR and should + not be used in other environments. + + - #PCPS_GIVE_SYNC_TIME
+ Return a ::PCPS_TIME structure with date and time + of last synchronization of the clock or + the last time set via the interface. + _pcps_has_sync_time() checks whether supported. + + - #PCPS_GIVE_HR_TIME
+ Return a PCPS_HR_TIME structure with current + date, time and status. This command should be + used to read the clock with higher resolution. + _pcps_has_hr_time() checks whether supported. + + - #PCPS_GIVE_IRIG_TIME
+ Return a PCPS_IRIG_TIME structure with day-of-year, + time and status as decoded from the IRIG signal. + _pcps_has_irig_time() checks whether supported. + + - #PCPS_SET_TIME
+ Set the board date, time and status. This + command expects sizeof( ::PCPS_STIME ) parameter + bytes. + _pcps_can_set_time() checks whether supported. + + - #PCPS_SET_EVENT_TIME
+ Send a high resolution time stamp to the clock to + configure a UTC time when the clock shall generate + some event. This command expects a PCPS_TIME_STAMP + parameter. + _pcps_has_event_time() checks whether supported. + (requires custom GPS CERN firmware) + + - #PCPS_IRQ_NONE
+ Disable the board's hardware IRQ
+ - #PCPS_IRQ_1_SEC
+ Enable hardware IRQs once per second
+ - #PCPS_IRQ_1_MIN
+ Enable hardware IRQs once per minute
+ - #PCPS_IRQ_10_MIN
+ Enable hardware IRQs once per 10 minutes
+ - #PCPS_IRQ_30_MIN
+ Enable hardware IRQs once per 30 minutes
+ + - #PCPS_GET_SERIAL
+ #PCPS_SET_SERIAL
+ These commands read or set the configuration + of a clock's serial port COM0. The commands + expect PCPS_SERIAL_BYTES parameter bytes and + should be used preferably with the DCF77 + clocks which have only one COM port. + _pcps_has_serial() checks whether supported. + Recent GPS clocks' COM ports should be cfg'd + using the structures RECEIVER_INFO, PORT_INFO, + and STR_TYPE_INFO. + _pcps_has_receiver_info() checks whether + these are supported. If they are not, then + the code #PC_GPS_PORT_PARM together with the + #PCPS_READ_GPS_DATA and #PCPS_WRITE_GPS_DATA + commands should be used. + + - #PCPS_GET_TZCODE
+ #PCPS_SET_TZCODE
+ These commands read or set a DCF77 clock's + time zone code and should be used preferably + with the newer DCF77 clocks which have limited + support of different time zones. + _pcps_has_tzcode() checks whether supported. + A GPS clock's time zone must be cfg'd using + the code #PC_GPS_TZDL together with the + #PCPS_READ_GPS_DATA and #PCPS_WRITE_GPS_DATA + commands. + + - #PCPS_GET_PCPS_TZDL
+ #PCPS_SET_PCPS_TZDL
+ These commands read or set a DCF77 clock's + time zone / daylight saving configuration. + _pcps_has_pcps_tzdl() checks whether supported. + A GPS clock's time zone must be cfg'd using + the code #PC_GPS_TZDL together with the + #PCPS_READ_GPS_DATA and #PCPS_WRITE_GPS_DATA + commands. + + - #PCPS_GET_REF_OFFS
+ #PCPS_SET_REF_OFFS
+ These commands can be used to configure the + reference time offset from UTC for clocks + which can't determine the offset automatically, + e.g. from an IRIG input signal. + _pcps_has_ref_offs() checks whether supported. + + - #PCPS_GET_OPT_INFO
+ #PCPS_SET_OPT_SETTINGS
+ These commands can be used to configure some + optional settings, controlled by flags. + When reading, the clock returns a MBG_OPT_INFO + structure which contains the supported values, + plus the current settings. + When writing, clocks accepts a MBG_OPT_SETTINGS + structure only which contain the desired settings + of the supported flags only. + _pcps_has_opt_flags() checks whether supported. + + - #PCPS_GET_IRIG_RX_INFO
+ #PCPS_SET_IRIG_RX_SETTINGS
+ #PCPS_GET_IRIG_TX_INFO
+ #PCPS_SET_IRIG_TX_SETTINGS
+ These commands can be used to configure IRIG + inputs and outputs.
+ When reading, the clock returns an IRIG_INFO + structure which contains the supported values, + plus the current settings.
+ When writing, clocks accepts an IRIG_SETTINGS + structure only which contain the desired settings + only. _pcps_is_irig_rx() and _pcps_is_irig_tx() + check whether supported. + + - #PCPS_GET_IRIG_CTRL_BITS
+ This command can be used to retrieve the control function + bits of the latest IRIG input frame. Those bits may carry + some well-known information as in the IEEE1344 code, but + may also contain some customized information, depending on + the IRIG frame type and the configuration of the IRIG generator. + So these bits are returned as-is and must be interpreted + by the application. + _pcps_has_irig_ctrl_bits() checks whether supported. + + - #PCPS_GET_SYNTH
+ #PCPS_SET_SYNTH
+ #PCPS_GET_SYNTH_STATE
+ These commands can be used to configure an on-board + frequency synthesizer and query the synthesizer + status. The commands are only supported if the board + supports the RECEIVER_INFO structure and the flag + #GPS_HAS_SYNTH is set in the RECEIVER_INFO::features. + _pcps_has_synth() checks whether supported. + The structures SYNTH and SYNTH_STATE used with these + commands are defined in gpsdefs.h. + + - #PCPS_GIVE_FW_ID_1
+ #PCPS_GIVE_FW_ID_2
+ Returns the first/second block of PCPS_FIFO_SIZE + characters of the firmware ID string. These + commands can be used to check if the board + responds properly. This is done by the clock + detection functions. + + - #PCPS_GIVE_SERNUM
+ Returns PCPS_FIFO_SIZE characters of the + clock's serial number. + _pcps_has_sernum() checks whether supported. + + - #PCPS_GENERIC_IO
+ Generic I/O read and write. Can be used to query + specific data, e.g. a selected element of an array. + _pcps_has_generic_io() checks whether supported. + + - #PCPS_GET_DEBUG_STATUS
+ This command reads a MBG_DEBUG_STATUS structure + which represents the internal status of the + IRIG decoder and some additional debug info. + _pcps_has_debug_status() checks whether supported. + + - #PCPS_READ_GPS_DATA
+ #PCPS_WRITE_GPS_DATA
+ These commands are used by the functions + pcps_read_gps_data() and pcps_write_gps_data() + to read or write large data structures to + Meinberg GPS plug-in clocks. + _pcps_is_gps() checks whether supported. + + - #PCPS_CLR_UCAP_BUFF
+ Clear a clock's time capture buffer. + _pcps_can_clr_ucap_buff() checks whether + supported. + + - #PCPS_GIVE_UCAP_ENTRIES
+ Read a PCPS_UCAP_ENTRIES structure which + reports the max number of entries and the + currently used number of entries in the + user capture buffer. + _pcps_has_ucap() checks whether supported. + + - #PCPS_GIVE_UCAP_EVENT
+ Read capture events using a PCPS_HR_TIME + structure. This is faster than reading using the + GPS command #PC_GPS_UCAP. If no capture event is + available then the structure is filled with 0s. + _pcps_has_ucap() checks whether supported. + + - #PCPS_FORCE_RESET
+ Resets the microprocessor on the radio clock + board. This is for debug purposes only and + should not be used by standard applications. + + The command codes listed above are defined below. The commands are + grouped for bytes having the same high nibble: + @{ +*/ +#define PCPS_GIVE_TIME_GROUP 0x00 +#define PCPS_SET_TIME_GROUP 0x10 +#define PCPS_IRQ_GROUP 0x20 +#define PCPS_CFG_GROUP 0x30 +#define PCPS_GIVE_DATA_GROUP 0x40 +#define PCPS_GPS_DATA_GROUP 0x50 +#define PCPS_CTRL_GROUP 0x60 +#define PCPS_CFG2_GROUP 0x70 + + +/* PCPS_GIVE_TIME_GROUP */ +#define PCPS_GIVE_TIME ( PCPS_GIVE_TIME_GROUP | 0x0 ) +#define PCPS_GIVE_TIME_NOCLEAR ( PCPS_GIVE_TIME_GROUP | 0x1 ) +#define PCPS_GIVE_SYNC_TIME ( PCPS_GIVE_TIME_GROUP | 0x2 ) // only supported if _pcps_has_sync_time() +#define PCPS_GIVE_HR_TIME ( PCPS_GIVE_TIME_GROUP | 0x3 ) // only supported if _pcps_has_hr_time() +#define PCPS_GIVE_IRIG_TIME ( PCPS_GIVE_TIME_GROUP | 0x4 ) // only supported if _pcps_has_irig_time() + + +/* PCPS_SET_TIME_GROUP */ +#define PCPS_SET_TIME ( PCPS_SET_TIME_GROUP | 0x0 ) +/* on error, return PCPS_ERR_STIME */ + +/* Attention: The code below can be used EXCLUSIVELY */ +/* with a GPS167PCI with customized CERN firmware !! */ +/* _pcps_has_event_time() checks whether supported. */ +#define PCPS_SET_EVENT_TIME ( PCPS_SET_TIME_GROUP | 0x4 ) + + +/* PCPS_IRQ_GROUP */ +#define PCPS_IRQ_NONE ( PCPS_IRQ_GROUP | 0x0 ) +#define PCPS_IRQ_1_SEC ( PCPS_IRQ_GROUP | 0x1 ) +#define PCPS_IRQ_1_MIN ( PCPS_IRQ_GROUP | 0x2 ) +#define PCPS_IRQ_10_MIN ( PCPS_IRQ_GROUP | 0x4 ) +#define PCPS_IRQ_30_MIN ( PCPS_IRQ_GROUP | 0x8 ) + + +/* PCPS_CFG_GROUP */ + +#define PCPS_GET_SERIAL ( PCPS_CFG_GROUP | 0x0 ) +#define PCPS_SET_SERIAL ( PCPS_CFG_GROUP | 0x1 ) +/* on error, return PCPS_ERR_CFG */ + +typedef uint8_t PCPS_SERIAL; + + +#define PCPS_GET_TZCODE ( PCPS_CFG_GROUP | 0x2 ) +#define PCPS_SET_TZCODE ( PCPS_CFG_GROUP | 0x3 ) +/* on error, return PCPS_ERR_CFG */ + +typedef uint8_t PCPS_TZCODE; + +/* the following codes are used with the PCPS_TZCODE parameter: */ +enum +{ + PCPS_TZCODE_CET_CEST, /* default as broadcasted by DCF77 (UTC+1h/UTC+2h) */ + PCPS_TZCODE_CET, /* always CET (UTC+1h), discard DST */ + PCPS_TZCODE_UTC, /* always UTC */ + PCPS_TZCODE_EET_EEST, /* East European Time, CET/CEST + 1h */ + N_PCPS_TZCODE /* the number of valid codes */ +}; + +/* the definitions below are for compatibily only: */ +#define PCPS_TZCODE_MEZMESZ PCPS_TZCODE_CET_CEST +#define PCPS_TZCODE_MEZ PCPS_TZCODE_CET +#define PCPS_TZCODE_OEZ PCPS_TZCODE_EET_EEST + + +#define PCPS_GET_PCPS_TZDL ( PCPS_CFG_GROUP | 0x4 ) +#define PCPS_SET_PCPS_TZDL ( PCPS_CFG_GROUP | 0x5 ) +/* on error, return PCPS_ERR_CFG */ + +/** + * The structures below can be used to configure a clock's + * time zone/daylight saving setting. This structure is shorter + * than the TZDL structure used with GPS clocks. + */ +typedef struct +{ + // The year_or_wday field below contains the full year number + // or 0..6 == Sun..Sat if the DL_AUTO_FLAG is set; see below. + uint16_t year_or_wday; + uint8_t month; + uint8_t mday; + uint8_t hour; + uint8_t min; +} PCPS_DL_ONOFF; + +#define _mbg_swab_pcps_dl_onoff( _p ) \ +{ \ + _mbg_swab16( &(_p)->year_or_wday ); \ +} + +/** + * If the field year_or_wday is or'ed with the constant DL_AUTO_FLAG + * defined below then this means that start and end of daylight saving + * time shall be computed automatically for each year. In this case + * the remaining bits represent the day-of-week after the specified + * mday/month at which the change shall occur. If that flag is not set + * then the field contains the full four-digit year number and the + * mday/month values specify the exact date of that year. + */ +#define DL_AUTO_FLAG 0x8000 // also defined in gpsdefs.h + +typedef struct +{ + int16_t offs; /**< offset from UTC to local time [min] */ + int16_t offs_dl; /**< additional offset if DST enabled [min] */ + PCPS_DL_ONOFF tm_on; /**< date/time when daylight saving starts */ + PCPS_DL_ONOFF tm_off; /**< date/time when daylight saving ends */ +} PCPS_TZDL; + +#define _mbg_swab_pcps_tzdl( _p ) \ +{ \ + _mbg_swab16( &(_p)->offs ); \ + _mbg_swab16( &(_p)->offs_dl ); \ + _mbg_swab_pcps_dl_onoff( &(_p)->tm_on ); \ + _mbg_swab_pcps_dl_onoff( &(_p)->tm_off ); \ +} + + + +#define PCPS_GET_REF_OFFS ( PCPS_CFG_GROUP | 0x6 ) +#define PCPS_SET_REF_OFFS ( PCPS_CFG_GROUP | 0x7 ) +/* on error, return PCPS_ERR_CFG */ + +/* The associated type MBG_REF_OFFS is defined in gpsdefs.h. */ + + +#define PCPS_GET_OPT_INFO ( PCPS_CFG_GROUP | 0x8 ) +#define PCPS_SET_OPT_SETTINGS ( PCPS_CFG_GROUP | 0x9 ) +/* on error, return PCPS_ERR_CFG */ + +/* The associated structures MBG_OPT_INFO and MBG_OPT_SETTINGS + are defined in gpsdefs.h. */ + + +#define PCPS_GET_IRIG_RX_INFO ( PCPS_CFG_GROUP | 0xA ) +#define PCPS_SET_IRIG_RX_SETTINGS ( PCPS_CFG_GROUP | 0xB ) +/* on error, return PCPS_ERR_CFG */ + +#define PCPS_GET_IRIG_TX_INFO ( PCPS_CFG_GROUP | 0xC ) +#define PCPS_SET_IRIG_TX_SETTINGS ( PCPS_CFG_GROUP | 0xD ) +/* on error, return PCPS_ERR_CFG */ + +/* The associated structures IRIG_INFO and IRIG_SETTINGS + are defined in gpsdefs.h. */ + + +#define PCPS_GET_SYNTH ( PCPS_CFG_GROUP | 0xE ) +#define PCPS_SET_SYNTH ( PCPS_CFG_GROUP | 0xF ) +/* on error, return PCPS_ERR_CFG */ + +/* The associated structure SYNTH is defined in gpsdefs.h. */ + + + +/* PCPS_GIVE_DATA_GROUP */ +#define PCPS_GIVE_FW_ID_1 ( PCPS_GIVE_DATA_GROUP | 0x0 ) +#define PCPS_GIVE_FW_ID_2 ( PCPS_GIVE_DATA_GROUP | 0x1 ) +#define PCPS_GIVE_SERNUM ( PCPS_GIVE_DATA_GROUP | 0x2 ) +#define PCPS_GENERIC_IO ( PCPS_GIVE_DATA_GROUP | 0x3 ) +#define PCPS_GET_SYNTH_STATE ( PCPS_GIVE_DATA_GROUP | 0x4 ) +#define PCPS_GET_IRIG_CTRL_BITS ( PCPS_GIVE_DATA_GROUP | 0x5 ) +#define PCPS_GET_RAW_IRIG_DATA ( PCPS_GIVE_DATA_GROUP | 0x6 ) + + + +#define PCPS_GET_STATUS_PORT ( PCPS_GIVE_DATA_GROUP | 0xB ) +#define PCPS_GET_DEBUG_STATUS ( PCPS_GIVE_DATA_GROUP | 0xC ) +// expects sizeof( MBG_DEBUG_STATUS ) chars + +// PCPS_GIVE_DATA_GROUP codes 0x0D, 0x0E, and 0x0F are reserved. + + +/* PCPS_GPS_DATA_GROUP */ +#define PCPS_READ_GPS_DATA ( PCPS_GPS_DATA_GROUP | 0x0 ) +#define PCPS_WRITE_GPS_DATA ( PCPS_GPS_DATA_GROUP | 0x1 ) + + +/* PCPS_CTRL_GROUP */ +#define PCPS_CLR_UCAP_BUFF ( PCPS_CTRL_GROUP | 0x0 ) +#define PCPS_GIVE_UCAP_ENTRIES ( PCPS_CTRL_GROUP | 0x1 ) +#define PCPS_GIVE_UCAP_EVENT ( PCPS_CTRL_GROUP | 0x2 ) + +typedef struct +{ + uint32_t used; /**< the number of saved capture events */ + uint32_t max; /**< capture buffer size */ +} PCPS_UCAP_ENTRIES; + +#define _mbg_swab_pcps_ucap_entries( _p ) \ +{ \ + _mbg_swab32( &(_p)->used ); \ + _mbg_swab32( &(_p)->max ); \ +} + + + +/** + special -- use with care ! +*/ +#define PCPS_FORCE_RESET 0x80 + +/** @} */ + +/* Codes returned when commands with parameters have been passed */ +/* to the board */ +#define PCPS_SUCCESS 0 /**< OK, no error */ +#define PCPS_ERR_STIME -1 /**< invalid date/time/status passed */ +#define PCPS_ERR_CFG -2 /**< invalid parms with a PCPS_CFG_GROUP cmd */ + + + +#ifndef BITMASK + #define BITMASK( b ) ( ( 1 << b ) - 1 ) +#endif + + +/** The size of the plug-in radio clock's on-board FIFO: */ +#define PCPS_FIFO_SIZE 16 + +typedef int8_t PCPS_BUFF[PCPS_FIFO_SIZE]; + + +#define PCPS_ID_SIZE ( 2 * PCPS_FIFO_SIZE + 1 ) /**< ASCIIZ string */ +typedef char PCPS_ID_STR[PCPS_ID_SIZE]; + + +#define PCPS_SN_SIZE ( PCPS_FIFO_SIZE + 1 ) /**< ASCIIZ string */ +typedef char PCPS_SN_STR[PCPS_SN_SIZE]; + + +/** + * The structure has been introduced to be able to handle + * high resolution time stamps. + */ +typedef struct +{ + uint32_t sec; /**< seconds since 1970 (UTC) */ + uint32_t frac; /**< fractions of second ( 0xFFFFFFFF == 0.9999.. sec) */ +} PCPS_TIME_STAMP; + +#define _mbg_swab_pcps_time_stamp( _p ) \ +{ \ + _mbg_swab32( &(_p)->sec ); \ + _mbg_swab32( &(_p)->frac ); \ +} + + + +// Depending on the target environment define a data type +// which can be used to convert binary fractions without +// range overflow. +#if defined( MBG_TGT_UNIX ) + #define PCPS_HRT_FRAC_CONVERSION_TYPE int64_t +#elif defined( MBG_TGT_WIN32 ) + #define PCPS_HRT_FRAC_CONVERSION_TYPE int64_t +#elif defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 ) + #define PCPS_HRT_FRAC_CONVERSION_TYPE int64_t +#else + #define PCPS_HRT_FRAC_CONVERSION_TYPE double +#endif + +// Max value of PCPS_TIME_STAMP::frac + 1 used for scaling +#define PCPS_HRT_BIN_FRAC_SCALE ( (PCPS_HRT_FRAC_CONVERSION_TYPE) 4294967296.0 ) // == 0x100000000 + + +// The scale and format to be used to print the fractions +// of a second as returned in the PCPS_TIME_STAMP structure. +// The function frac_sec_from_bin() can be used for +// the conversion. +#ifndef PCPS_HRT_FRAC_SCALE + #define PCPS_HRT_FRAC_SCALE 10000000UL +#endif + +#ifndef PCPS_HRT_FRAC_SCALE_FMT + #define PCPS_HRT_FRAC_SCALE_FMT "%07lu" +#endif + + + +typedef uint16_t PCPS_TIME_STATUS_X; /**< extended status */ + +#define _mbg_swab_pcps_time_status_x( _p ) _mbg_swab16( _p ) + + +/** + * The structure has been introduced to be able to read the + * current time with higher resolution of fractions of seconds and + * more detailed information on the time zone and status. + * The structure is returned if the new command #PCPS_GIVE_HR_TIME + * is written to the board. + * _pcps_has_hr_time() checks whether supported. + * + * Newer GPS boards also accept the #PCPS_GIVE_UCAP_EVENT command + * to return user capture event times using this format. In this + * case, the "signal" field contains the number of the capture + * input line, e.g. 0 or 1. + * _pcps_has_ucap() checks whether supported. + */ +typedef struct +{ + PCPS_TIME_STAMP tstamp; /**< High resolution time stamp (UTC) */ + int32_t utc_offs; /**< UTC offs [sec] (loc_time = UTC + utc_offs) */ + PCPS_TIME_STATUS_X status; /**< status flags as defined below */ + uint8_t signal; /**< for normal time, the relative RF signal level, for ucap, the channel number */ +} PCPS_HR_TIME; + +#define _mbg_swab_pcps_hr_time( _p ) \ +{ \ + _mbg_swab_pcps_time_stamp( &(_p)->tstamp ); \ + _mbg_swab32( &(_p)->utc_offs ); \ + _mbg_swab_pcps_time_status_x( &(_p)->status ); \ +} + + +typedef uint8_t PCPS_TIME_STATUS; + +/** + The standard structure used to read times from the board. + The time has a resultion of 10 ms. +*/ +typedef struct PCPS_TIME_s +{ + uint8_t sec100; /**< hundredths of seconds, 0..99 */ + uint8_t sec; /**< seconds, 0..59, or 60 if leap second */ + uint8_t min; /**< minutes, 0..59 */ + uint8_t hour; /**< hours, 0..23 */ + + uint8_t mday; /**< day of month, 0..31 */ + uint8_t wday; /**< day of week, 1..7, 1 = Monday */ + uint8_t month; /**< month, 1..12 */ + uint8_t year; /**< year of the century, 0..99 */ + + PCPS_TIME_STATUS status; /**< status bits, see below */ + uint8_t signal; /**< relative signal strength, range depends on device type */ + int8_t offs_utc; /**< [hours], 0 if !_pcps_has_utc_offs() */ +} PCPS_TIME; + + +/** + The structure is passed as parameter with the PCPS_SET_TIME cmd +*/ +typedef struct PCPS_STIME_s +{ + uint8_t sec100; /**< hundredths of seconds, 0..99 */ + uint8_t sec; /**< seconds, 0..59, or 60 if leap second */ + uint8_t min; /**< minutes, 0..59 */ + uint8_t hour; /**< hours, 0..23 */ + + uint8_t mday; /**< day of month, 0..31 */ + uint8_t wday; /**< day of week, 1..7, 1 = Monday */ + uint8_t month; /**< month, 1..12 */ + uint8_t year; /**< year of the century, 0..99 */ + + PCPS_TIME_STATUS status; /**< status bits, see below */ +} PCPS_STIME; + +#ifdef _C166 + // This is a workaround to specify some structure sizes. The C166 compiler + // always reports an even structure size although the structure size may + // be odd due to the number of bytes. This might lead to errors between + // the C166 and other build environments. + #define sizeof_PCPS_TIME ( sizeof( PCPS_TIME ) - 1 ) + #define sizeof_PCPS_STIME ( sizeof( PCPS_STIME ) - 1 ) +#else + #define sizeof_PCPS_TIME sizeof( PCPS_TIME ) + #define sizeof_PCPS_STIME sizeof( PCPS_STIME ) +#endif + +typedef union +{ + PCPS_TIME t; + PCPS_STIME stime; +} PCPS_TIME_UNION; + + + +/** + The structure below can be used to read the raw IRIG time + from an IRIG receiver card, if the card supports this. + See the #PCPS_GIVE_IRIG_TIME command. + + The granularity of the value in the .frac field depends on + the update interval of the structure as implementation + in the firmware. I.e. if the raw IRIG time is updated + only once per second, the .frac value can always be 0. +*/ +typedef struct PCPS_IRIG_TIME_s +{ + PCPS_TIME_STATUS_X status; /**< status bits, see below */ + int16_t offs_utc; /**< [minutes] */ + uint16_t yday; /**< day of year, 1..365/366 */ + uint16_t frac; /**< fractions of seconds, 0.1 ms units */ + uint8_t sec; /**< seconds, 0..59, or 60 if leap second */ + uint8_t min; /**< minutes, 0..59 */ + uint8_t hour; /**< hours, 0..23 */ + uint8_t year; /**< 2 digit year number, 0xFF if year not supp. by the IRIG code */ + uint8_t signal; /**< relative signal strength, range depends on device type */ + uint8_t reserved; /**< currently not used, always 0 */ +} PCPS_IRIG_TIME; + +#define _mbg_swab_pcps_irig_time( _p ) \ +{ \ + _mbg_swab_pcps_time_status_x( &(_p)->status ); \ + _mbg_swab16( &(_p)->offs_utc ); \ + _mbg_swab16( &(_p)->yday ); \ + _mbg_swab16( &(_p)->frac ); \ +} + + + + +/* Bit masks used with both PCPS_TIME_STATUS and PCPS_TIME_STATUS_X */ + +#define PCPS_FREER 0x01 /**< DCF77 clock running on xtal */ + /**< GPS receiver has not verified its position */ + +#define PCPS_DL_ENB 0x02 /**< daylight saving enabled */ + +#define PCPS_SYNCD 0x04 /**< clock has sync'ed at least once after pwr up */ + +#define PCPS_DL_ANN 0x08 /**< a change in daylight saving is announced */ + +#define PCPS_UTC 0x10 /**< a special UTC firmware is installed */ + +#define PCPS_LS_ANN 0x20 /**< leap second announced */ + /**< (requires firmware rev. REV_PCPS_LS_ANN_...) */ + +#define PCPS_IFTM 0x40 /**< the current time was set via PC */ + /**< (requires firmware rev. REV_PCPS_IFTM_...) */ + +#define PCPS_INVT 0x80 /**< invalid time because battery was disconn'd */ + + +/* Bit masks used only with PCPS_TIME_STATUS_X */ + +#define PCPS_LS_ENB 0x0100 /**< current second is leap second */ +#define PCPS_ANT_FAIL 0x0200 /**< antenna failure */ +#define PCPS_LS_ANN_NEG 0x0400 /**< announced leap second is negative */ +#define PCPS_SCALE_GPS 0x0800 /**< time stamp is GPS scale */ +#define PCPS_SCALE_TAI 0x1000 /**< time stamp is TAI scale */ + +/* The next two bits are used only if the structure */ +/* PCPS_HR_TIME contains a user capture event */ +#define PCPS_UCAP_OVERRUN 0x2000 /**< events interval too short */ +#define PCPS_UCAP_BUFFER_FULL 0x4000 /**< events read too slow */ + +/** + * Immediately after a clock has been accessed, subsequent accesses + * are blocked for up to 1.5 msec to give the clock's microprocessor + * some time to decode the incoming time signal. + * The flag below is set if a program tries to read the PCPS_HR_TIME + * during this interval. In this case the read function returns the + * proper time stamp which is taken if the command byte is written, + * however, the read function returns with delay. + * This flag is not supported by all clocks. + */ +#define PCPS_IO_BLOCKED 0x8000 + +/** + This bit mask can be used to extract the time scale information out + of a PCPS_TIME_STATUS_X value. +*/ +#define PCPS_SCALE_MASK ( PCPS_SCALE_TAI | PCPS_SCALE_GPS ) + + +/** + * Some DCF77 clocks have a serial interface that can be controlled + * using the commands PCPS_SET_SERIAL and PCPS_GET_SERIAL. Both commands + * use a parameter byte describing transmission speed, framing and mode + * of operation. The parameter byte can be build using the constants + * defined below, by or'ing one of the constants of each group, shifted + * to the right position. PCPS_GET_SERIAL expects that parameter byte + * and PCPS_GET_SERIAL returns the current configuration from the board. + * _pcps_has_serial() checks whether supported. + * For GPS clocks, please refer to the comments for the PCPS_GET_SERIAL + * command. + */ + +/** + * Baud rate indices. The values below are obsolete and should + * be replaced by the codes named MBG_BAUD_RATE_... which are + * defined in gpsdefs.h. The resulting index numbers, however, + * have not changed. + */ +enum +{ + PCPS_BD_300, + PCPS_BD_600, + PCPS_BD_1200, + PCPS_BD_2400, + PCPS_BD_4800, + PCPS_BD_9600, + PCPS_BD_19200, + N_PCPS_BD /* number of codes */ +}; + +#define PCPS_BD_BITS 4 /* field with in the cfg byte */ +#define PCPS_BD_SHIFT 0 /* num of bits to shift left */ + +/* + * Initializers for a table of all baud rate strings + * and values can be found in gpsdefs.h. + */ + + +/** + * Unfortunately, the framing codes below can not simply be + * replaced by the newer MBG_FRAMING_... definitions since + * the order of indices does not match. + */ +enum +{ + PCPS_FR_8N1, + PCPS_FR_7E2, + PCPS_FR_8N2, + PCPS_FR_8E1, + N_PCPS_FR_DCF /* number of valid codes */ +}; + +#define PCPS_FR_BITS 2 /* field with in the cfg byte */ +#define PCPS_FR_SHIFT PCPS_BD_BITS /* num of bits to shift left */ + +/* + * An initializer for a table of framing strings is only defined for + * the new MBG_FRAMING_... definitions. For editing the serial port + * configuration, the old codes above should be translated to the new + * codes to unify handling inside the edit functions. + */ + +/** + Modes of operation + + * Indices for modes of operation. The values below are obsolete + * and should be replaced by the codes named STR_... which are + * defined in gpsdefs.h. The resulting index numbers, however, + * have not changed. + */ +enum +{ + PCPS_MOD_REQ, /* time string on request '?' only */ + PCPS_MOD_SEC, /* time string once per second */ + PCPS_MOD_MIN, /* time string once per minute */ + PCPS_MOD_RSVD, /* reserved */ + N_PCPS_MOD_DCF /* number of possible codes */ +}; + +#define PCPS_MOD_BITS 2 /* field with in the cfg byte */ +#define PCPS_MOD_SHIFT ( PCPS_BD_BITS + PCPS_FR_BITS ) + /* num of bits to shift left */ + +/** + * The fixed-length standard time string being sent on the serial + * output is described below: + * + * \D:dd.mm.yy;T:d;U:hh.mm.ss;uvwx\ + * + * where \ and \ represent the ASCII codes 0x02 and 0x03, + * 'dd.mm.yy' is the format of the current date, 'd' is the current + * day of week (1..7, 1 == Monday ) and 'hh.mm.ss' is the format of + * the current time. The characters 'uvwx' reflect the clock's status: + * + * u clock status character: + * '#' clock has not synchronized after reset + * ' ' (space, 20h) clock has synchronized after reset + * + * v clock status character, different for DCF77 or GPS receivers: + * '*' DCF77 clock currently runs on XTAL + * GPS receiver has not checked its position + * ' ' (space, 20h): + * DCF77 clock is syncronized with transmitter + * GPS receiver has determined its position + * + * x time zone indicator: + * 'U' UTC Universal Time, Coordinated + * ' ' MEZ European Standard Time, daylight saving disabled + * 'S' MESZ European Summertime, daylight saving enabled + * + * y anouncement of discontinuity of time, enabled during last hour + * before discontinuity comes in effect: + * '!' announcement of start or end of daylight saving + * 'A' announcement of leap second insertion + * ' ' (space, 20h): nothing announced + */ + + + +/** + * Some definitions used with PZF receivers + */ + +/* receiver distance from transmitter [km] */ +typedef uint16_t TR_DISTANCE; + +/* correlation status info */ +typedef struct +{ + uint8_t val; /**< correlation value, or check count if status == PZF_CORR_CHECK */ + uint8_t status; /**< status codes, see below */ + char corr_dir; /**< space, '<', or '>' */ + uint8_t signal; /**< signal level, may always be 0 for devices which do not support this */ +} CORR_INFO; + +/** Codes used with CORR_INFO::status: */ +enum +{ + PZF_CORR_RAW, /**< trying raw correlation, combi receivers running in AM mode */ + PZF_CORR_CHECK, /**< raw correlation achieved, doing plausibility checks */ + PZF_CORR_FINE, /**< fine correlation achieved */ + N_PZF_CORR_STATE +}; + + +/** + * @defgroup gps_cmds_bus GPS commands passed via the system bus + * + * This enumeration defines the various types of data that can be read + * from or written to Meinberg bus level devices which support this. + * Access should be done using the functions ::pcps_read_gps_data() + * and ::pcps_write_gps_data() since the size of some of the structures + * exceeds the size of the devices's I/O buffer and must therefore be + * accessed in several portions. + * + * The structures to be used are defined in gpsdefs.h. Not all structures + * are supportet, yet. Check the R/W indicators for details. + */ +enum +{ // R/W data type description + // system data ----------------------------------------------- + PC_GPS_TZDL = 0, // R/W TZDL time zone / daylight saving + PC_GPS_SW_REV, // R/- SW_REV software revision + PC_GPS_BVAR_STAT, // R/- BVAR_STAT status of buffered variables + PC_GPS_TIME, // R/W TTM curr. time + PC_GPS_POS_XYZ, // -/W XYZ curr. pos. in ECEF coords + PC_GPS_POS_LLA, // -/W LLA curr. pos. in geogr. coords + PC_GPS_PORT_PARM, // R/W PORT_PARM param. of the serial ports + PC_GPS_ANT_INFO, // R/- ANT_INFO time diff after ant. disconn. + PC_GPS_UCAP, // R/- TTM user capture + PC_GPS_ENABLE_FLAGS, // R/W ENABLE_FLAGS controls when to enable outp. + PC_GPS_STAT_INFO, // R/- GPS_STAT_INFO + PC_GPS_CMD, // -/W GPS_CMD commands as described below + PC_GPS_IDENT, // R/- GPS_IDENT serial number + PC_GPS_POS, // R/- POS position XYZ, LLA, and DMS + PC_GPS_ANT_CABLE_LEN, // R/W ANT_CABLE_LEN used to compensate delay + // The codes below are supported by new GPS receiver boards: + PC_GPS_RECEIVER_INFO, // R/- RECEIVER_INFO rcvr model info + PC_GPS_ALL_STR_TYPE_INFO, // R/- n*STR_TYPE_INFO_IDX all string types + PC_GPS_ALL_PORT_INFO, // R/- n*PORT_INFO_IDX all port info + PC_GPS_PORT_SETTINGS_IDX, // -/W PORT_SETTINGS_IDX port settings only + PC_GPS_ALL_POUT_INFO, // R/- n*POUT_INFO_IDX all pout info + PC_GPS_POUT_SETTINGS_IDX, // -/W POUT_SETTINGS_IDX pout settings only + PC_GPS_TIME_SCALE, // R/W MBG_TIME_SCALE_{SETTINGS|INFO}, only if PCPS_HAS_TIME_SCALE + PC_GPS_LAN_IF_INFO, // R/- LAN_IF_INFO LAN interface info, only if PCPS_HAS_LAN_INTF + PC_GPS_IP4_STATE, // R/- IP4_SETTINGS LAN interface state, only if PCPS_HAS_LAN_INTF + PC_GPS_IP4_SETTINGS, // R/W IP4_SETTINGS LAN interface configuration, only if PCPS_HAS_LAN_INTF + PC_GPS_PTP_STATE, // R/- PTP_STATE, only if PCPS_HAS_PTP + PC_GPS_PTP_CFG, // R/W PTP_CFG_{SETTINGS|INFO}, only if PCPS_HAS_PTP + + // GPS data + PC_GPS_CFGH = 0x80, // -/- CFGH SVs' config. and health codes + PC_GPS_ALM, // -/- SV_ALM one SV's num and almanac + PC_GPS_EPH, // -/- SV_EPH one SV's num and ephemeris + PC_GPS_UTC, // R/W UTC UTC corr. param., only if PCPS_HAS_UTC_PARM + PC_GPS_IONO, // -/- IONO ionospheric corr. param. + PC_GPS_ASCII_MSG // -/- ASCII_MSG the GPS ASCII message +}; + + +/** codes used with PC_GPS_CMD */ +enum +{ + PC_GPS_CMD_BOOT = 1, /**< force the clock to boot mode */ + PC_GPS_CMD_INIT_SYS, /**< let the clock clear its system variables */ + PC_GPS_CMD_INIT_USER, /**< reset the clock's user parameters to defaults */ + PC_GPS_CMD_INIT_DAC, /**< initialize the oscillator disciplining values */ + N_PC_GPS_CMD /**< no command, just the number of known commands */ +}; + +// The type below can be used to store an unambiguous command code. +// In case of the standard PCPS_... commands the lower byte contains +// the command code and the upper byte is 0. +// In case of a GPS command the lower byte contains PCPS_READ_GPS_DATA +// or PCPS_WRITE_GPS_DATA, as appropriate, and the upper byte contains +// the associated PC_GPS_... type code. +typedef uint16_t PCPS_CMD_INFO; + +#if defined( _USE_PACK ) // set default alignment + #pragma pack() +#endif + +/* End of header body */ + +#endif /* _PCPSDEFS_H */ + diff --git a/mbglib/common/pcpsdev.h b/mbglib/common/pcpsdev.h new file mode 100755 index 0000000..4250a5a --- /dev/null +++ b/mbglib/common/pcpsdev.h @@ -0,0 +1,1657 @@ + +/************************************************************************** + * + * $Id: pcpsdev.h 1.49.1.25 2011/02/04 14:44:44 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions used to share information on radio clock devices + * between device drivers which have direct access to the hardware + * devices and user space programs which evaluate and present that + * information. + * + * At the bottom of the file there are some macros defined which + * should be used to access the structures to extract characteristics + * of an individual clock. + * + * ----------------------------------------------------------------------- + * $Log: pcpsdev.h $ + * Revision 1.49.1.25 2011/02/04 14:44:44 martin + * Revision 1.49.1.24 2011/02/04 10:10:00 martin + * Revision 1.49.1.23 2011/02/02 12:34:10 martin + * Revision 1.49.1.22 2011/02/01 17:12:04 martin + * Revision 1.49.1.21 2011/01/28 13:11:11 martin + * Preliminary implementation of mbg_get_sys_time for FreeBSD traps. + * Revision 1.49.1.20 2011/01/28 10:34:37 martin + * Moved MBG_TGT_SUPP_MEM_ACC definition here. + * Revision 1.49.1.19 2011/01/26 16:39:05 martin + * Preliminarily support FreeBSD build. + * Revision 1.49.1.18 2011/01/24 17:09:51 martin + * Preliminarily fixed build under FreeBSD. + * Revision 1.49.1.17 2010/12/14 13:19:58 martin + * Fixed doxgen comments. + * Revision 1.49.1.16 2010/12/14 12:20:10 martin + * Revision 1.49.1.15 2010/11/25 14:54:22 martin + * Moved status port register definitions to pcpsdefs.h. + * Revision 1.49.1.14 2010/11/11 09:15:38 martin + * Added definitions to support DCF600USB. + * Revision 1.49.1.13 2010/09/27 13:09:06 martin + * Features are now defined using enum and bit masks. + * Added initializer for feature names (used for debug). + * Revision 1.49.1.12 2010/08/25 12:44:42 martin + * Revision 1.49.1.11 2010/08/20 09:34:41Z martin + * Added macro _pcps_features(). + * Revision 1.49.1.10 2010/08/17 15:34:23 martin + * Revision 1.49.1.9 2010/08/16 15:41:32 martin + * Revision 1.49.1.8 2010/08/13 12:14:46 daniel + * Revision 1.49.1.7 2010/08/13 11:57:54Z martin + * Revision 1.49.1.6 2010/08/13 11:39:28Z martin + * Revision 1.49.1.5 2010/08/13 11:19:41 martin + * Implemented portable mbg_get_sys_uptime() and mbg_sleep_sec() + * functions and associated types. + * Revision 1.49.1.4 2010/08/11 14:32:14 martin + * Revision 1.49.1.3 2010/08/11 13:47:42 martin + * Cleanup. + * Revision 1.49.1.2 2010/07/14 14:50:42 martin + * Revision 1.49.1.1 2010/06/30 13:17:18 martin + * Support GPS180PEX and TCR180PEX. + * Revision 1.49 2010/06/30 13:03:48 martin + * Use new preprocessor symbol MBG_ARCH_X86. + * Use ulong port addresses for all platforms but x86. + * Support mbg_get_pc_cycles() for IA64, but mbg_get_pc_cycles_frequency() + * is not yet supported. + * Don't pack interface structures on Sparc and IA64 architecture. + * Revision 1.48 2010/04/26 14:47:42 martin + * Define symbol MBG_PC_CYCLES_SUPPORTED if this is the case. + * Revision 1.47 2010/01/12 14:03:22 daniel + * Added definitions to support reading the raw IRIG data bits. + * Revision 1.46 2009/09/29 15:10:35Z martin + * Support generic system time, and retrieving time discipline info. + * Added _pcps_has_fast_hr_timestamp() macro and associated feature flag. + * Revision 1.45 2009/06/19 12:15:18 martin + * Added has_irig_time feature and associated macros. + * Revision 1.44 2009/06/08 19:30:48 daniel + * Account for new features PCPS_HAS_LAN_INTF and + * PCPS_HAS_PTP. + * Revision 1.43 2009/04/08 08:26:20 daniel + * Define firmware version at which the TCR511PCI starts + * to support IRIG control bits. + * Revision 1.42 2009/03/19 14:58:47Z martin + * Tmp. workaround in mbg_delta_pc_cycles() under SPARC which might + * generate bus errors due to unaligned access. + * Revision 1.41 2009/03/16 16:01:22 martin + * Support reading IRIG control function bits. + * Revision 1.40 2009/03/13 09:13:39 martin + * Support new features .._has_time_scale() and .._has_utc_parm(). + * Moved some inline functions dealing with MBG_PC_CYCLES + * from mbgdevio.h here. + * Merged the code from _pcps_get_cycles() and _pcps_get_cycles_frequency() + * to the mbg_get_pc_cycles...() inline functions which now replace the + * _pcps_get_cycles...() macros. + * Fixed cycles code for non-x86 architectures. + * Revision 1.39 2008/12/05 16:24:24Z martin + * Changed MAX_PARM_STR_TYPE from 10 to 20. + * Added support for WWVB signal source. + * Support new devices PTP270PEX, FRC511PEX, TCR170PEX, and WWVB51USB. + * Added macros _pcps_is_ptp(), _pcps_is_frc(), and _pcps_is_wwvb(). + * Defined firmware version numbers which fix an IRQ problem with PEX511, + * TCR511PEX, and GPS170PEX cards. The fix also requires specific ASIC + * versions specified in pci_asic.h. + * Defined firmware versions at which PCI511 and PEX511 start + * to support HR time. + * Support mapped I/O resources. + * Changed MBG_PC_CYCLES type for Windows to int64_t. + * Renamed MBG_VIRT_ADDR to MBG_MEM_ADDR. + * Added MBG_PC_CYCLES_FREQUENCY type. + * Added definition of PCPS_TIME_STAMP_CYCLES. + * Added PCPS_IRQ_STAT_INFO type and associated flags. + * Added macros to convert the endianess of structures. + * Added macros _pcps_fw_rev_num_major() and _pcps_fw_rev_num_minor(). + * Made irq_num signed to use -1 for unassigned IRQ numbers. + * Revision 1.38 2008/01/17 10:12:34 daniel + * Added support for TCR51USB and MSF51USB. + * New type MBG_VIRT_ADDR to specify virtual address values. + * New struct PCPS_MAPPED_MEM + * Cleanup for PCI ASIC version and features. + * Added macros _pcps_is_msf(), _pcps_is_lwr(), + * _psps_has_asic_version(), _pcps_has_asic_features(). + * Revision 1.37 2008/01/17 09:58:11Z daniel + * Made comments compatible for doxygen parser. + * No sourcecode changes. + * Revision 1.36 2007/09/26 09:34:38Z martin + * Added support for USB in general and new USB device USB5131. + * Added new types PCPS_DEV_ID and PCPS_REF_TYPE. + * Removed old PCPS_ERR_... codes. Use MBG_ERR_... codes + * from mbgerror.h instead. The old values haven't changed. + * Revision 1.35 2007/07/17 08:22:47Z martin + * Added support for TCR511PEX and GPS170PEX. + * Revision 1.34 2007/07/16 12:50:41Z martin + * Added support for PEX511. + * Modified/renamed some macros and symbols. + * Revision 1.33 2007/03/02 09:40:04Z martin + * Changes due to renamed library symbols. + * Removed obsolete inclusion of headers. + * Preliminary support for *BSD. + * Preliminary support for USB. + * Revision 1.32 2006/10/23 08:47:55Z martin + * Don't use abs() in _pcps_ref_offs_out_of_range() since this might + * not work properly for 16 bit integers and value 0x8000. + * Revision 1.31 2006/06/14 12:59:13Z martin + * Added support for TCR511PCI. + * Revision 1.30 2006/04/05 14:58:41 martin + * Support higher baud rates for PCI511. + * Revision 1.29 2006/04/03 07:29:07Z martin + * Added a note about the missing PCPS_ST_IRQF signal + * on PCI510 cards. + * Revision 1.28 2006/03/10 10:32:56Z martin + * Added support for PCI511. + * Added support for programmable pulse outputs. + * Revision 1.27 2005/11/04 08:48:00Z martin + * Added support for GPS170PCI. + * Revision 1.26 2005/06/02 08:34:38Z martin + * New types MBG_DBG_PORT, MBG_DBG_DATA. + * Revision 1.25 2005/05/03 10:04:14 martin + * Added macro _pcps_is_pci_amcc(). + * Revision 1.24 2005/03/29 12:58:19Z martin + * Support GENERIC_IO feature. + * Revision 1.23 2004/12/09 11:03:37Z martin + * Support configuration of on-board frequency synthesizer. + * Revision 1.22 2004/11/09 12:57:52Z martin + * Redefined interface data types using C99 fixed-size definitions. + * Added support for TCR167PCI. + * New macro _pcps_has_gps_data(). + * New type PCPS_STATUS_PORT. + * Removed obsolete inclusion of asm/timex.h for Linux. + * Revision 1.21 2004/09/06 15:19:49Z martin + * Support a GPS_DATA interface where sizes are specified + * by 16 instead of the original 8 bit quantities, thus allowing + * to transfer data blocks which exceed 255 bytes. + * Modified inclusion of header files under Linux. + * Modified definition of MBG_PC_CYCLES for Linux. + * Revision 1.20 2004/04/14 09:09:11 martin + * Source code cleanup. + * Revision 1.19 2004/04/07 09:49:14Z martin + * Support new feature PCPS_HAS_IRIG_TX. + * New macros _pcps_has_irig(), _pcps_has_irig_tx(). + * Revision 1.18 2004/01/14 11:02:14Z MARTIN + * Added formal type MBG_PC_CYCLES for OS/2, + * though it's not really required or used. + * Revision 1.17 2003/12/22 15:40:16 martin + * Support higher baud rates for TCR510PCI and PCI510. + * Supports PCPS_HR_TIME for TCR510PCI. + * New structures used to read device time together with associated + * PC CPU cycles. + * For Win32, differentiate between kernel mode and non-kernel mode. + * Moved some definitions here from mbgdevio.h. + * New type PCPS_ASIC_VERSION. + * New macro _pcps_ref_offs_out_of_range(). + * Revision 1.16 2003/06/19 09:48:30Z MARTIN + * Renamed symbols ..clr_cap_buffer to ..clr_ucap_buffer. + * New macro _pcps_has_ucap(). + * New definitions to support cmds PCPS_GIVE_UCAP_ENTRIES + * and PCPS_GIVE_UCAP_EVENT. + * Revision 1.15 2003/04/15 09:57:25 martin + * New typedefs ALL_STR_TYPE_INFO, ALL_PORT_INFO, + * RECEIVER_PORT_CFG. + * Revision 1.14 2003/04/09 14:07:01Z martin + * Supports PCI510, GPS169PCI, and TCR510PCI, + * and new PCI_ASIC used by those devices. + * Renamed macro _pcps_is_irig() to _pcps_is_irig_rx(). + * New macros _pcps_has_ref_offs(), _pcps_has_opt_flags(). + * Fixed macro _pcps_has_hr_time(). + * New type PCPS_BUS_FLAGS. + * Preliminary support for PCPS_TZDL. + * Revision 1.13 2002/08/09 07:19:49 MARTIN + * Moved definition of ref time sources to pcpsdefs.h. + * New feature PCPS_CAN_CLR_CAP_BUFF and + * associated macro _pcps_can_clr_cap_buff(). + * New macros _pcps_is_irig(), _pcps_has_signal(), + * _pcps_has_mod(). + * Revision 1.12 2002/02/19 09:22:53 MARTIN + * Added definitions for the maximum number of clocks' serial ports + * and string types that can be handled by the configuration programs. + * Revision 1.11 2002/02/01 11:36:58 MARTIN + * Added new definitions for GPS168PCI. + * Inserted definitions of firmware REV_NUMs for supported features + * which had previously been defined in pcpsdefs.h. + * Include use_pack.h. + * Updated comments. + * Source code cleanup. + * Revision 1.10 2001/11/30 09:52:48 martin + * Added support for event_time which, however, requires + * a custom GPS firmware. + * Revision 1.9 2001/10/16 10:11:14 MARTIN + * New Macro _pcps_has_serial_hs() which determines whether + * DCF77 clock supports baud rate higher than default. + * Re-arranged order of macro definitions. + * Revision 1.8 2001/09/03 07:15:05 MARTIN + * Added macro to access the firmware revision number. + * Cleaned up macro syntax. + * Added some comments. + * Revision 1.7 2001/08/30 13:20:04 MARTIN + * New macro to mark a PCPS_TIME variable as unread. + * New macro to check if a PCPS_TIME variable is unread. + * Revision 1.6 2001/03/15 15:45:01 MARTIN + * Added types PCPS_ERR_FLAGS, PCPS_BUS_NUM, PCPS_SLOT_NUM. + * Revision 1.5 2001/03/01 13:53:10 MARTIN + * Initial version for the new driver library. + * + **************************************************************************/ + +#ifndef _PCPSDEV_H +#define _PCPSDEV_H + +#include +#include +#include +#include +#include +#include + +#if defined( MBG_TGT_LINUX ) + + #if defined( __KERNEL__ ) + #include + #else + #include + #endif + + #if defined( MBG_ARCH_IA64 ) + #include + #include + #endif + +#endif + +#if defined( MBG_TGT_BSD ) + #include +#endif + +#if defined( MBG_TGT_DOS ) + #include // for delay() +#endif + + + +/* Start of header body */ + +#if defined( MBG_ARCH_SPARC ) || defined( MBG_ARCH_IA64 ) + #undef _USE_PACK // don't pack interface structures +#endif + +#if defined( _USE_PACK ) // set byte alignment + #pragma pack( 1 ) +#endif + + + + +/** + Define generic types to hold PC cycle counter values and system timestamps. + The generic types are defined using native types used by the target operating + systems. + + The cycle counter value is usually derived from the PC CPU's TSC or some other + timer hardware on the mainboard. + */ +#if defined( MBG_TGT_WIN32 ) + + #define MBG_TGT_SUPP_MEM_ACC 1 + + // used with QueryPerformanceCounter() + typedef int64_t MBG_PC_CYCLES; + typedef uint64_t MBG_PC_CYCLES_FREQUENCY; + + typedef int64_t MBG_SYS_UPTIME; // [s] + + typedef LARGE_INTEGER MBG_SYS_TIME; + +#elif defined( MBG_TGT_LINUX ) + + #define MBG_TGT_SUPP_MEM_ACC 1 + + typedef uint64_t MBG_PC_CYCLES; + typedef uint64_t MBG_PC_CYCLES_FREQUENCY; + + typedef int64_t MBG_SYS_UPTIME; // [s] + + #if defined( __KERNEL__ ) + #include + #else + #include + #endif + + typedef struct timeval MBG_SYS_TIME; + +#elif defined( MBG_TGT_BSD ) + + #define MBG_TGT_SUPP_MEM_ACC 1 + + typedef uint64_t MBG_PC_CYCLES; + typedef uint64_t MBG_PC_CYCLES_FREQUENCY; + + typedef int64_t MBG_SYS_UPTIME; // [s] + + typedef struct timeval MBG_SYS_TIME; + + #if defined( _KERNEL ) + #include + #include + #else + #include + #endif + +#elif defined( MBG_TGT_OS2 ) + + typedef uint32_t MBG_PC_CYCLES; //##++ should differentiate more + typedef uint32_t MBG_PC_CYCLES_FREQUENCY; + + typedef long MBG_SYS_UPTIME; //## dummy + + typedef uint32_t MBG_SYS_TIME; //## dummy + +#elif defined( MBG_TGT_DOS ) + + typedef uint32_t MBG_PC_CYCLES; //##++ should differentiate more + typedef uint32_t MBG_PC_CYCLES_FREQUENCY; + #define MBG_MEM_ADDR uint32_t // 64 bit not supported, nor required. + + typedef long MBG_SYS_UPTIME; //## dummy + + typedef uint32_t MBG_SYS_TIME; //## dummy + +#else // other target OSs which access the hardware directly + + typedef uint32_t MBG_PC_CYCLES; //##++ should differentiate more + typedef uint32_t MBG_PC_CYCLES_FREQUENCY; + + typedef long MBG_SYS_UPTIME; //## dummy + + typedef uint32_t MBG_SYS_TIME; //## dummy + +#endif + + +#if !defined( MBG_TGT_SUPP_MEM_ACC ) + #define MBG_TGT_SUPP_MEM_ACC 0 +#endif + + +// MBG_PC_CYCLES, MBG_PC_CYCLES_FREQUENCY, and MBG_SYS_TIME are always read +// in native machine endianess, so no endianess conversion is required. +#define _mbg_swab_mbg_pc_cycles( _p ) \ + _nop_macro_fnc() + +#define _mbg_swab_mbg_pc_cycles_frequency( _p ) \ + _nop_macro_fnc() + +#define _mbg_swab_mbg_sys_time( _p ) \ + _nop_macro_fnc() + + + +/** + The structure holds a system timestamp in a format depending on the target OS + plus two cycles counter values which can be taken before and after reading + the system time. These cycles values can be used to determine the execution + time required to read the system time. + + Limitations of the operating system need to be taken into account, + e.g. the Windows system time may increase once every ~16 ms only. + */ +typedef struct +{ + MBG_PC_CYCLES cyc_before; /**< cycles count before sys time is read */ + MBG_PC_CYCLES cyc_after; /**< cycles count after sys time has been read */ + MBG_SYS_TIME sys_time; /**< system time stamp */ +} MBG_SYS_TIME_CYCLES; + +#define _mbg_swab_mbg_sys_time_cycles( _p ) \ +{ \ + _mbg_swab_mbg_pc_cycles( &(_p)->cyc_before ); \ + _mbg_swab_mbg_pc_cycles( &(_p)->cyc_after ); \ + _mbg_swab_mbg_sys_time( &(_p)->sys_time ); \ +} + + + + +#if ( defined( MBG_TGT_LINUX ) || defined( MBG_TGT_BSD ) ) && defined( MBG_ARCH_X86 ) + + static __mbg_inline unsigned long long int mbg_rdtscll( void ) + { + // The code below is a hack to get around issues with + // different versions of gcc. + // + // Normally the inline asm code could look similar to: + // + // __asm__ volatile ( "rdtsc" : "=A" (x) ) + // + // which would copy the output regs edx:eax as a 64 bit + // number to a variable x. + // + // The "=A" expression should implicitely tell the compiler + // the edx and eax registers have been clobbered. However, + // this does not seem to work properly at least with gcc 4.1.2 + // shipped with Centos 5. + // + // If optimization level 1 or higher is used then function + // parameters are also passed in registers. If the inline + // code above is used inside a function then the edx register + // is clobbered but the gcc 4.1.2 is not aware of this and + // assumes edx is unchanged, which may yield faulty results + // or even lead to segmentation faults. + // + // A possible workaround could be to mark edx explicitely as + // being clobbered in the asm inline code, but unfortunately + // other gcc versions report an error if a register which is + // implicitely (by "=A") known to be clobbered is also listed + // explicitely to be clobbered. + // + // So the code below is a workaround which tells the compiler + // implicitely that the eax ("=a") and edx ("=d") registers + // are being used and thus clobbered. + + union + { + struct + { + uint32_t lo; + uint32_t hi; + } u32; + + uint64_t u64; + + } tsc_val; + + __asm__ __volatile__( "rdtsc" : "=a" (tsc_val.u32.lo), "=d" (tsc_val.u32.hi) ); + + return tsc_val.u64; + + } // mbg_rdtscll + +#endif + + + +static __mbg_inline +void mbg_get_pc_cycles( MBG_PC_CYCLES *p ) +{ + #if defined( MBG_TGT_WIN32 ) + + #if defined( _KDD_ ) // kernel space + *p = (MBG_PC_CYCLES) KeQueryPerformanceCounter( NULL ).QuadPart; + #else // user space + QueryPerformanceCounter( (LARGE_INTEGER *) p ); + #endif + + #define MBG_PC_CYCLES_SUPPORTED 1 + + #elif defined( MBG_TGT_LINUX ) && defined( MBG_ARCH_X86 ) + + #if 0 && ( defined( CONFIG_X86_TSC ) || defined( CONFIG_M586TSC ) ) //##++++ + #define _pcps_get_cycles( _c ) \ + _c = get_cycles() + #else + *p = mbg_rdtscll(); + #endif + + #define MBG_PC_CYCLES_SUPPORTED 1 + + #elif defined( MBG_TGT_BSD ) && defined( MBG_ARCH_X86 ) + + *p = mbg_rdtscll(); + + #define MBG_PC_CYCLES_SUPPORTED 1 + + #elif defined( MBG_TGT_LINUX ) && defined( MBG_ARCH_IA64 ) + + unsigned long result = ia64_getreg( _IA64_REG_AR_ITC ); + ia64_barrier(); + + #ifdef CONFIG_ITANIUM + while (unlikely((__s32) result == -1)) { + result = ia64_getreg(_IA64_REG_AR_ITC); + ia64_barrier(); + } + #endif + + *p = result; + + #define MBG_PC_CYCLES_SUPPORTED 1 + + #else + + *p = 0; + + #endif + +} // mbg_get_pc_cycles + + + +static __mbg_inline +void mbg_get_pc_cycles_frequency( MBG_PC_CYCLES_FREQUENCY *p ) +{ + #if defined( MBG_TGT_WIN32 ) + LARGE_INTEGER li; + + #if defined( _KDD_ ) // kernel space + KeQueryPerformanceCounter( &li ); + #else // user space + QueryPerformanceFrequency( &li ); + #endif + + *p = li.QuadPart; + + #elif defined( MBG_TGT_LINUX ) && defined( MBG_ARCH_X86 ) + + #if defined( __KERNEL__ ) + + *p = ( cpu_khz * 1000 ); + + #else + + *p = 0; + + #endif + + #elif defined( MBG_TGT_LINUX ) && defined( MBG_ARCH_IA64 ) + + #error A way to get cycles frequency needs to be defined for Linux/IA64. + + // we probably can use + // ia64_sal_freq_base(unsigned long which, unsigned long *ticks_per_second, + // unsigned long *drift_info) + // However, this is not tested. + + #elif defined( MBG_TGT_BSD ) + + #if defined( MBG_ARCH_X86 ) && defined( _KERNEL ) + + *p = tsc_freq; + + #else + + *p = 0; + + #endif + + #else + + #if MBG_PC_CYCLES_SUPPORTED + + #error A way to get cycles frequency needs to be defined for this target. + + #else + *p = 0; + #endif + + #endif + +} // mbg_get_pc_cycles_frequency + + + +static __mbg_inline +MBG_PC_CYCLES mbg_delta_pc_cycles( const MBG_PC_CYCLES *p1, const MBG_PC_CYCLES *p2 ) +{ +#if !defined( MBG_PC_CYCLES_SUPPORTED ) + // Cycle counts not supported on this target platform. + // Under SPARC this may even result in bus errors + // due to alignment of the underlying data structures. + return 0; +#else + return *p1 - *p2; +#endif + +} // mbg_delta_pc_cycles + + + +static __mbg_inline +void mbg_get_sys_time( MBG_SYS_TIME *p ) +{ + #if defined( MBG_TGT_WIN32 ) + + #if defined( _KDD_ ) // kernel space + KeQuerySystemTime( p ); + #else // user space + { + FILETIME ft; + GetSystemTimeAsFileTime( &ft ); + p->LowPart = ft.dwLowDateTime; + p->HighPart = ft.dwHighDateTime; + } + #endif + + #elif defined( MBG_TGT_LINUX ) + + #if defined( __KERNEL__ ) + do_gettimeofday( p ); + #else + gettimeofday( p, NULL ); + #endif + + #elif defined( MBG_TGT_BSD ) + + #if defined( _KERNEL ) + microtime( p ); + #else + gettimeofday( p, NULL ); + #endif + + #else + + *p = 0; + + #endif + +} // mbg_get_sys_time + + + +static __mbg_inline +void mbg_get_sys_uptime( MBG_SYS_UPTIME *p ) +{ + #if defined( MBG_TGT_WIN32 ) + + #if defined( _KDD_ ) // kernel space + + ULONGLONG time_increment = KeQueryTimeIncrement(); + LARGE_INTEGER tick_count; + + KeQueryTickCount( &tick_count ); + + // multiplication by time_increment yields HNS units, + // but we need seconds + *p = ( tick_count.QuadPart * time_increment ) / HNS_PER_SEC; + + #else // user space + + DWORD tickCount; + DWORD timeAdjustment; + DWORD timeIncrement; + BOOL timeAdjustmentDisabled; + + if ( !GetSystemTimeAdjustment( &timeAdjustment, &timeIncrement, &timeAdjustmentDisabled ) ) + *p = -1; // failed + + // ATTENTION: This is compatible with older Windows versions, but + // the returned tick count wraps around to zero after 49.7 days. + // A new GetTickCount64() call is available under Windows Vista and newer, + // but the function call had to be imported dynamically since otherwise + // programs refused to start under pre-Vista versions due to undefined DLL symbol. + tickCount = GetTickCount(); + + *p = ( ( (MBG_SYS_UPTIME) tickCount ) * timeIncrement ) / HNS_PER_SEC; + + #endif + + #elif defined( MBG_TGT_LINUX ) + + #if defined( __KERNEL__ ) + { + // Using a simple 64 bit division may result in a linker error + // in kernel mode due to a missing symbol __udivdi3, so we use + // a specific inline function do_div(). + // Also, the jiffies counter is not set to 0 at startup but to + // a defined initialization value we need to account for. + uint64_t tmp = get_jiffies_64() - INITIAL_JIFFIES; + do_div( tmp, HZ ); + *p = tmp; + } + #else + //##++++ Still need to implement this for Linux user space. + // A possible way would be to parse the contents + // of the pseudo-file /proc/uptime. + *p = -1; + #endif + + #elif defined( MBG_TGT_BSD ) + + #if defined( _KERNEL ) + { + struct timeval tv; + + getmicrouptime( &tv ); + + *p = tv.tv_sec; + } + #else + //##++++ Still need to implement this for user space. + *p = -1; + #endif + + #else + + *p = -1; // not supported + + #endif + +} // mbg_get_sys_uptime + + + +static __mbg_inline +void mbg_sleep_sec( long sec ) +{ + #if defined( MBG_TGT_WIN32 ) + + #if defined( _KDD_ ) // kernel space + LARGE_INTEGER delay; + + // we need to pass a negative value to KeDelayExecutionThread() + // since the given time is a relative time interval, not absolute + // time. See the API docs for KeDelayExecutionThread(). + delay.QuadPart = (LONGLONG) sec * HNS_PER_SEC; + + KeDelayExecutionThread( KernelMode, FALSE, &delay ); + #else // user space + // Sleep() expects milliseconds + Sleep( sec * 1000 ); + #endif + + #elif defined( MBG_TGT_LINUX ) + + #if defined( __KERNEL__ ) + // msleep is not defined in older kernels, so we use this + // only if it is surely supported. + #if ( LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 16 ) ) //##+++++ + msleep( sec * 1000 ); + #else + { + DECLARE_WAIT_QUEUE_HEAD( tmp_wait ); + wait_event_interruptible_timeout( tmp_wait, 0, sec * HZ + 1 ); + } + #endif + #else + sleep( sec ); + #endif + + #elif defined( MBG_TGT_BSD ) + + //##+++++++++++++++++++ needs to be defined + + #elif defined( MBG_TGT_DOS ) + + delay( sec * 1000 ); + + #else + + // This needs to be implemented for the target OS + // and thus will probably yield a linker error. + do_sleep_sec( sec ); + + #endif + +} // mbg_sleep_sec + + + +#if !defined( MBG_MEM_ADDR ) + // By default a memory address is stored + // as a 64 bit quantitiy. + #define MBG_MEM_ADDR uint64_t +#endif + + +typedef uint8_t MBG_DBG_DATA; +typedef uint16_t MBG_DBG_PORT; + + +// The following flags describe the bus types which are +// supported by the plugin clocks. +#define PCPS_BUS_ISA 0x0001 // IBM compatible PC/AT ISA bus +#define PCPS_BUS_MCA 0x0002 // IBM PS/2 micro channel +#define PCPS_BUS_PCI 0x0004 // PCI +#define PCPS_BUS_USB 0x0008 // USB + +// The flags below are or'ed to the PC_BUS_PCI code +// in order to indicate which PCI interface chip is used +// on a PCI card. If no flag is set then the S5933 chip is +// installed which has been used for the first generation +// of Meinberg PCI cards. + +// S5920 PCI interface chip. +#define PCPS_BUS_PCI_CHIP_S5920 0x8000 + +// Meinberg's own PCI interface chip. +#define PCPS_BUS_PCI_CHIP_ASIC 0x4000 + +// PEX8311 PCI Express interface chip +#define PCPS_BUS_PCI_CHIP_PEX8311 0x2000 + +// Meinberg's own PCI Express interface chip +#define PCPS_BUS_PCI_CHIP_MBGPEX 0x1000 + + +// The constant below combines the PCI bus flags. +#define PCPS_BUS_PCI_S5933 ( PCPS_BUS_PCI ) +#define PCPS_BUS_PCI_S5920 ( PCPS_BUS_PCI | PCPS_BUS_PCI_CHIP_S5920 ) +#define PCPS_BUS_PCI_ASIC ( PCPS_BUS_PCI | PCPS_BUS_PCI_CHIP_ASIC ) +#define PCPS_BUS_PCI_PEX8311 ( PCPS_BUS_PCI | PCPS_BUS_PCI_CHIP_PEX8311 ) +#define PCPS_BUS_PCI_MBGPEX ( PCPS_BUS_PCI | PCPS_BUS_PCI_CHIP_MBGPEX ) + + + +/** A list of known radio clocks. */ +enum PCPS_TYPES +{ + PCPS_TYPE_PC31, + PCPS_TYPE_PS31_OLD, + PCPS_TYPE_PS31, + PCPS_TYPE_PC32, + PCPS_TYPE_PCI32, + PCPS_TYPE_GPS167PC, + PCPS_TYPE_GPS167PCI, + PCPS_TYPE_PCI509, + PCPS_TYPE_GPS168PCI, + PCPS_TYPE_PCI510, + PCPS_TYPE_GPS169PCI, + PCPS_TYPE_TCR510PCI, + PCPS_TYPE_TCR167PCI, + PCPS_TYPE_GPS170PCI, + PCPS_TYPE_PCI511, + PCPS_TYPE_TCR511PCI, + PCPS_TYPE_PEX511, + PCPS_TYPE_TCR511PEX, + PCPS_TYPE_GPS170PEX, + PCPS_TYPE_USB5131, + PCPS_TYPE_TCR51USB, + PCPS_TYPE_MSF51USB, + PCPS_TYPE_PTP270PEX, + PCPS_TYPE_FRC511PEX, + PCPS_TYPE_TCR170PEX, + PCPS_TYPE_WWVB51USB, + PCPS_TYPE_GPS180PEX, + PCPS_TYPE_TCR180PEX, + PCPS_TYPE_DCF600USB, + N_PCPS_DEV_TYPE +}; + + +#define PCPS_CLOCK_NAME_SZ 10 // including terminating 0 + +typedef uint16_t PCPS_DEV_ID; +typedef uint16_t PCPS_REF_TYPE; +typedef uint16_t PCPS_BUS_FLAGS; + +/** + The structure contains the characteristics of each + of the clocks listed above. These fields are always the + same for a single type of clock and do not change with + firmware version, port address, etc. + */ +typedef struct +{ + uint16_t num; + char name[PCPS_CLOCK_NAME_SZ]; + PCPS_DEV_ID dev_id; + PCPS_REF_TYPE ref_type; + PCPS_BUS_FLAGS bus_flags; +} PCPS_DEV_TYPE; + + + +#if !defined( MBG_TGT_LINUX ) || defined( MBG_ARCH_X86 ) + typedef uint16_t PCPS_PORT_ADDR; +#else + typedef ulong PCPS_PORT_ADDR; +#endif + + + +/** + The structure below describes an I/O port resource + used by a clock. +*/ +typedef struct +{ + PCPS_PORT_ADDR base; + uint16_t num; +} PCPS_PORT_RSRC; + +/** The max number of I/O port resources used by a clock. */ +#define N_PCPS_PORT_RSRC 2 + + + +typedef struct +{ + MBG_MEM_ADDR user_virtual_address; + ulong len; + #if defined( MBG_TGT_LINUX ) + uint32_t pfn_offset; + #endif +} PCPS_MAPPED_MEM; + + + +typedef uint32_t PCPS_ERR_FLAGS; /**< see \ref group_err_flags "Error flags" */ +typedef uint32_t PCPS_FEATURES; /**< see \ref group_features "Features" */ +typedef uint16_t PCPS_BUS_NUM; +typedef uint16_t PCPS_SLOT_NUM; + +/** + The structure below contains data which depends + on a individual instance of the clock, e.g. + the firmware which is currently installed, the + port address which has been configured, etc. +*/ +typedef struct +{ + PCPS_ERR_FLAGS err_flags; /**< See \ref group_err_flags "Error flags" */ + PCPS_BUS_NUM bus_num; + PCPS_SLOT_NUM slot_num; + PCPS_PORT_RSRC port[N_PCPS_PORT_RSRC]; + uint16_t status_port; + int16_t irq_num; + uint32_t timeout_clk; + uint16_t fw_rev_num; + PCPS_FEATURES features; /**< See \ref group_features "Feature flags" */ + PCPS_ID_STR fw_id; + PCPS_SN_STR sernum; +} PCPS_DEV_CFG; + +/** @defgroup group_err_flags Error flags in PCPS_DEV_CFG + Flags used with PCPS_DEV_CFG::err_flags + @{ +*/ +#define PCPS_EF_TIMEOUT 0x00000001 /**< timeout occured */ +#define PCPS_EF_INV_EPROM_ID 0x00000002 /**< invalid EPROM ID */ +#define PCPS_EF_IO_INIT 0x00000004 /**< I/O intf not init'd */ +#define PCPS_EF_IO_CFG 0x00000008 /**< I/O intf not cfg'd */ +#define PCPS_EF_IO_ENB 0x00000010 /**< I/O intf not enabled */ +#define PCPS_EF_IO_RSRC 0x00000020 /**< I/O not registered w/ rsrcmgr */ +/** @} */ + +/** @defgroup group_features Feature flags used with PCPS_FEATURES + + Some features of the radio clocks have been introduced with + specific firmware versions, so depending on the firmware version + a clock may support a feature or not. The clock detection function + checks the clock model and firmware version and updates the field + PCPS_DEV_CFG::features accordingly. There are some macros which + can easily be used to query whether a clock device actually + supports a function, or not. The definitions define + the possible features. + @{ +*/ +enum +{ + PCPS_BIT_CAN_SET_TIME, + PCPS_BIT_HAS_SERIAL, + PCPS_BIT_HAS_SYNC_TIME, + PCPS_BIT_HAS_TZDL, + PCPS_BIT_HAS_IDENT, + PCPS_BIT_HAS_UTC_OFFS, + PCPS_BIT_HAS_HR_TIME, + PCPS_BIT_HAS_SERNUM, + PCPS_BIT_HAS_TZCODE, + PCPS_BIT_HAS_CABLE_LEN, + PCPS_BIT_HAS_EVENT_TIME, // custom GPS firmware only + PCPS_BIT_HAS_RECEIVER_INFO, + PCPS_BIT_CAN_CLR_UCAP_BUFF, + PCPS_BIT_HAS_PCPS_TZDL, + PCPS_BIT_HAS_UCAP, + PCPS_BIT_HAS_IRIG_TX, + PCPS_BIT_HAS_GPS_DATA_16, // use 16 bit size specifiers + PCPS_BIT_HAS_SYNTH, + PCPS_BIT_HAS_GENERIC_IO, + PCPS_BIT_HAS_TIME_SCALE, + PCPS_BIT_HAS_UTC_PARM, + PCPS_BIT_HAS_IRIG_CTRL_BITS, + PCPS_BIT_HAS_LAN_INTF, + PCPS_BIT_HAS_PTP, + PCPS_BIT_HAS_IRIG_TIME, + PCPS_BIT_HAS_FAST_HR_TSTAMP, + PCPS_BIT_HAS_RAW_IRIG_DATA, + N_PCPS_FEATURE +}; + + +#define PCPS_CAN_SET_TIME ( 1UL << PCPS_BIT_CAN_SET_TIME ) +#define PCPS_HAS_SERIAL ( 1UL << PCPS_BIT_HAS_SERIAL ) +#define PCPS_HAS_SYNC_TIME ( 1UL << PCPS_BIT_HAS_SYNC_TIME ) +#define PCPS_HAS_TZDL ( 1UL << PCPS_BIT_HAS_TZDL ) +#define PCPS_HAS_IDENT ( 1UL << PCPS_BIT_HAS_IDENT ) +#define PCPS_HAS_UTC_OFFS ( 1UL << PCPS_BIT_HAS_UTC_OFFS ) +#define PCPS_HAS_HR_TIME ( 1UL << PCPS_BIT_HAS_HR_TIME ) +#define PCPS_HAS_SERNUM ( 1UL << PCPS_BIT_HAS_SERNUM ) +#define PCPS_HAS_TZCODE ( 1UL << PCPS_BIT_HAS_TZCODE ) +#define PCPS_HAS_CABLE_LEN ( 1UL << PCPS_BIT_HAS_CABLE_LEN ) +#define PCPS_HAS_EVENT_TIME ( 1UL << PCPS_BIT_HAS_EVENT_TIME ) +#define PCPS_HAS_RECEIVER_INFO ( 1UL << PCPS_BIT_HAS_RECEIVER_INFO ) +#define PCPS_CAN_CLR_UCAP_BUFF ( 1UL << PCPS_BIT_CAN_CLR_UCAP_BUFF ) +#define PCPS_HAS_PCPS_TZDL ( 1UL << PCPS_BIT_HAS_PCPS_TZDL ) +#define PCPS_HAS_UCAP ( 1UL << PCPS_BIT_HAS_UCAP ) +#define PCPS_HAS_IRIG_TX ( 1UL << PCPS_BIT_HAS_IRIG_TX ) +#define PCPS_HAS_GPS_DATA_16 ( 1UL << PCPS_BIT_HAS_GPS_DATA_16 ) +#define PCPS_HAS_SYNTH ( 1UL << PCPS_BIT_HAS_SYNTH ) +#define PCPS_HAS_GENERIC_IO ( 1UL << PCPS_BIT_HAS_GENERIC_IO ) +#define PCPS_HAS_TIME_SCALE ( 1UL << PCPS_BIT_HAS_TIME_SCALE ) +#define PCPS_HAS_UTC_PARM ( 1UL << PCPS_BIT_HAS_UTC_PARM ) +#define PCPS_HAS_IRIG_CTRL_BITS ( 1UL << PCPS_BIT_HAS_IRIG_CTRL_BITS ) +#define PCPS_HAS_LAN_INTF ( 1UL << PCPS_BIT_HAS_LAN_INTF ) +#define PCPS_HAS_PTP ( 1UL << PCPS_BIT_HAS_PTP ) +#define PCPS_HAS_IRIG_TIME ( 1UL << PCPS_BIT_HAS_IRIG_TIME ) +#define PCPS_HAS_FAST_HR_TSTAMP ( 1UL << PCPS_BIT_HAS_FAST_HR_TSTAMP ) +#define PCPS_HAS_RAW_IRIG_DATA ( 1UL << PCPS_BIT_HAS_RAW_IRIG_DATA ) + + + +#define PCPS_FEATURE_NAMES \ +{ \ + "PCPS_CAN_SET_TIME", \ + "PCPS_HAS_SERIAL", \ + "PCPS_HAS_SYNC_TIME", \ + "PCPS_HAS_TZDL", \ + "PCPS_HAS_IDENT", \ + "PCPS_HAS_UTC_OFFS", \ + "PCPS_HAS_HR_TIME", \ + "PCPS_HAS_SERNUM", \ + "PCPS_HAS_TZCODE", \ + "PCPS_HAS_CABLE_LEN", \ + "PCPS_HAS_EVENT_TIME", \ + "PCPS_HAS_RECEIVER_INFO", \ + "PCPS_CAN_CLR_UCAP_BUFF", \ + "PCPS_HAS_PCPS_TZDL", \ + "PCPS_HAS_UCAP", \ + "PCPS_HAS_IRIG_TX", \ + "PCPS_HAS_GPS_DATA_16", \ + "PCPS_HAS_SYNTH", \ + "PCPS_HAS_GENERIC_IO", \ + "PCPS_HAS_TIME_SCALE", \ + "PCPS_HAS_UTC_PARM", \ + "PCPS_HAS_IRIG_CTRL_BITS", \ + "PCPS_HAS_LAN_INTF", \ + "PCPS_HAS_PTP", \ + "PCPS_HAS_IRIG_TIME", \ + "PCPS_HAS_FAST_HR_TSTAMP", \ + "PCPS_HAS_RAW_IRIG_DATA" \ +} + +/** @} */ + + + +// The constants below define those features which are available +// in ALL firmware versions which have been shipped with a +// specific clock. + +#define PCPS_FEAT_PC31PS31 0 + +// Some of the features are available in all newer clocks, +// so these have been put together in one definition: +#define PCPS_FEAT_LVL2 ( PCPS_CAN_SET_TIME \ + | PCPS_HAS_SERIAL \ + | PCPS_HAS_SYNC_TIME \ + | PCPS_HAS_UTC_OFFS ) + +#define PCPS_FEAT_PC32 ( PCPS_FEAT_LVL2 ) + +#define PCPS_FEAT_PCI32 ( PCPS_FEAT_LVL2 ) + +#define PCPS_FEAT_PCI509 ( PCPS_FEAT_LVL2 \ + | PCPS_HAS_SERNUM \ + | PCPS_HAS_TZCODE ) + +#define PCPS_FEAT_PCI510 ( PCPS_FEAT_PCI509 ) + +#define PCPS_FEAT_PCI511 ( PCPS_FEAT_PCI510 ) + +#define PCPS_FEAT_GPS167PC ( PCPS_FEAT_LVL2 \ + | PCPS_HAS_TZDL \ + | PCPS_HAS_IDENT ) + +#define PCPS_FEAT_GPS167PCI ( PCPS_FEAT_LVL2 \ + | PCPS_HAS_TZDL \ + | PCPS_HAS_IDENT \ + | PCPS_HAS_HR_TIME ) + +#define PCPS_FEAT_GPS168PCI ( PCPS_FEAT_LVL2 \ + | PCPS_HAS_TZDL \ + | PCPS_HAS_IDENT \ + | PCPS_HAS_HR_TIME \ + | PCPS_HAS_CABLE_LEN \ + | PCPS_HAS_RECEIVER_INFO ) + +#define PCPS_FEAT_GPS169PCI ( PCPS_FEAT_GPS168PCI \ + | PCPS_CAN_CLR_UCAP_BUFF \ + | PCPS_HAS_UCAP ) + +#define PCPS_FEAT_GPS170PCI ( PCPS_FEAT_GPS169PCI \ + | PCPS_HAS_IRIG_TX \ + | PCPS_HAS_GPS_DATA_16 \ + | PCPS_HAS_GENERIC_IO ) + +#define PCPS_FEAT_TCR510PCI ( PCPS_FEAT_LVL2 \ + | PCPS_HAS_SERNUM ) + +#define PCPS_FEAT_TCR167PCI ( PCPS_FEAT_LVL2 \ + | PCPS_HAS_SERNUM \ + | PCPS_HAS_TZDL \ + | PCPS_HAS_HR_TIME \ + | PCPS_HAS_RECEIVER_INFO \ + | PCPS_CAN_CLR_UCAP_BUFF \ + | PCPS_HAS_UCAP \ + | PCPS_HAS_IRIG_TX \ + | PCPS_HAS_GPS_DATA_16 \ + | PCPS_HAS_GENERIC_IO ) + +#define PCPS_FEAT_TCR511PCI ( PCPS_FEAT_TCR510PCI \ + | PCPS_HAS_HR_TIME ) + +#define PCPS_FEAT_PEX511 ( PCPS_FEAT_PCI511 ) + +#define PCPS_FEAT_TCR511PEX ( PCPS_FEAT_TCR511PCI ) + +#define PCPS_FEAT_GPS170PEX ( PCPS_FEAT_GPS170PCI ) + +#define PCPS_FEAT_USB5131 ( PCPS_HAS_UTC_OFFS \ + | PCPS_HAS_SERNUM \ + | PCPS_HAS_SYNC_TIME \ + | PCPS_HAS_HR_TIME \ + | PCPS_CAN_SET_TIME \ + | PCPS_HAS_TZCODE ) + +#define PCPS_FEAT_TCR51USB ( PCPS_HAS_UTC_OFFS \ + | PCPS_HAS_SERNUM \ + | PCPS_HAS_SYNC_TIME \ + | PCPS_HAS_HR_TIME \ + | PCPS_CAN_SET_TIME ) + +#define PCPS_FEAT_MSF51USB ( PCPS_HAS_UTC_OFFS \ + | PCPS_HAS_SERNUM \ + | PCPS_HAS_SYNC_TIME \ + | PCPS_HAS_HR_TIME \ + | PCPS_CAN_SET_TIME ) + +#define PCPS_FEAT_PTP270PEX ( PCPS_HAS_SERNUM \ + | PCPS_HAS_SYNC_TIME \ + | PCPS_HAS_HR_TIME \ + | PCPS_HAS_RECEIVER_INFO \ + | PCPS_CAN_SET_TIME \ + | PCPS_CAN_CLR_UCAP_BUFF \ + | PCPS_HAS_UCAP \ + | PCPS_HAS_GPS_DATA_16 ) + +#define PCPS_FEAT_FRC511PEX ( PCPS_HAS_SERNUM \ + | PCPS_HAS_HR_TIME \ + | PCPS_HAS_RECEIVER_INFO \ + | PCPS_CAN_SET_TIME \ + | PCPS_CAN_CLR_UCAP_BUFF \ + | PCPS_HAS_UCAP \ + | PCPS_HAS_GPS_DATA_16 ) + +#define PCPS_FEAT_TCR170PEX ( PCPS_FEAT_TCR167PCI ) + +#define PCPS_FEAT_WWVB51USB ( PCPS_FEAT_MSF51USB ) + +#define PCPS_FEAT_GPS180PEX ( PCPS_FEAT_GPS170PEX | PCPS_HAS_FAST_HR_TSTAMP ) + +#define PCPS_FEAT_TCR180PEX ( PCPS_FEAT_TCR170PEX | PCPS_HAS_FAST_HR_TSTAMP ) + +#define PCPS_FEAT_DCF600USB ( PCPS_FEAT_USB5131 ) + +// Some features of the API used to access Meinberg plug-in radio clocks +// have been implemented starting with the special firmware revision +// numbers defined below. +// +// If no number is specified for a feature/clock model then the feature +// is either always supported by that clock model, or not at all. + + +// There are some versions of PCI Express cards out there which do not +// safely support hardware IRQs. The following firmware versions are required +// for safe IRQ operation: +#define REV_HAS_IRQ_FIX_MINOR_PEX511 0x0106 +#define REV_HAS_IRQ_FIX_MINOR_TCR511PEX 0x0105 +#define REV_HAS_IRQ_FIX_MINOR_GPS170PEX 0x0104 +// Additionally there are certain revisions of the bus interface logic +// required. The associated version codes are defined in pci_asic.h. + +// The macro below can be used to check whether the required versions are there: +#define _pcps_pex_irq_is_safe( _curr_fw_ver, _req_fw_ver, _curr_asic_ver, \ + _req_asic_ver_major, _req_asic_ver_minor ) \ + ( ( (_curr_fw_ver) >= (_req_fw_ver) ) && _pcps_asic_version_greater_equal( \ + (_curr_asic_ver), (_req_asic_ver_major), (_req_asic_ver_minor ) ) \ + ) + +/* command PCPS_GIVE_RAW_IRIG_DATA: */ +#define REV_HAS_RAW_IRIG_DATA_TCR511PEX 0x0111 +#define REV_HAS_RAW_IRIG_DATA_TCR511PCI 0x0111 +#define REV_HAS_RAW_IRIG_DATA_TCR51USB 0x0106 + +/* command PCPS_GIVE_IRIG_TIME: */ +#define REV_HAS_IRIG_TIME_TCR511PEX 0x0109 +#define REV_HAS_IRIG_TIME_TCR511PCI 0x0109 +#define REV_HAS_IRIG_TIME_TCR51USB 0x0106 + +/* command PCPS_GET_IRIG_CTRL_BITS: */ +#define REV_HAS_IRIG_CTRL_BITS_TCR511PEX 0x0107 +#define REV_HAS_IRIG_CTRL_BITS_TCR511PCI 0x0107 +#define REV_HAS_IRIG_CTRL_BITS_TCR51USB 0x0106 + +/* This board uses the GPS_DATA interface with 16 bit buffer sizes + instead of the original 8 bit sizes, thus allowing to transfer + data blocks which exceed 255 bytes (PCPS_HAS_GPS_DATA_16) */ +#define REV_HAS_GPS_DATA_16_GPS169PCI 0x0202 + +/* the clock supports a higher baud rate than N_PCPS_BD_DCF */ +#define REV_HAS_SERIAL_HS_PCI509 0x0104 + +/* commands PCPS_GIVE_UCAP_ENTRIES, PCPS_GIVE_UCAP_EVENT */ +#define REV_HAS_UCAP_GPS167PCI 0x0421 +#define REV_HAS_UCAP_GPS168PCI 0x0104 + +/* command PCPS_CLR_UCAP_BUFF */ +#define REV_CAN_CLR_UCAP_BUFF_GPS167PCI 0x0419 +#define REV_CAN_CLR_UCAP_BUFF_GPS168PCI 0x0101 + +/* commands PCPS_READ_GPS_DATA and PCPS_WRITE_GPS_DATA with */ +/* code PC_GPS_ANT_CABLE_LEN */ +#define REV_HAS_CABLE_LEN_GPS167PCI 0x0411 +#define REV_HAS_CABLE_LEN_GPS167PC 0x0411 + +/* command PCPS_GIVE_HR_TIME, structure PCPS_HR_TIME: */ +#define REV_HAS_HR_TIME_GPS167PC 0x0305 +#define REV_HAS_HR_TIME_TCR510PCI 0x0200 +#define REV_HAS_HR_TIME_PEX511 0x0105 // This also requires a certain ASIC version. +#define REV_HAS_HR_TIME_PCI511 0x0103 + +/* field offs_utc in structure PCPS_TIME: */ +#define REV_HAS_UTC_OFFS_PC31PS31 0x0300 + +/* command PCPS_GIVE_SYNC_TIME: */ +#define REV_HAS_SYNC_TIME_PC31PS31 0x0300 + +/* command PCPS_GET_SERIAL, PCPS_SET_SERIAL: */ +#define REV_HAS_SERIAL_PC31PS31 0x0300 + +/* command PCPS_GIVE_TIME_NOCLEAR: */ +#define REV_GIVE_TIME_NOCLEAR_PC31PS31 0x0300 + +/* status bit PCPS_LS_ANN: */ +#define REV_PCPS_LS_ANN_PC31PS31 0x0300 + +/* status bit PCPS_IFTM: */ +#define REV_PCPS_IFTM_PC31PS31 0x0300 + +/* command PCPS_SET_TIME: */ +#define REV_CAN_SET_TIME_PC31PS31 0x0240 + +/* command PCPS_GIVE_TIME_NOCLEAR: */ +// This is supported by all clocks but PC31/PS31 with +// firmware versions before v3.0. If such a card shall +// be used then the firmware should be updated to the +// last recent version. + + +/** + The structure has been defined to pass all + information on a clock device from a device driver + to a user program. */ +typedef struct +{ + PCPS_DEV_TYPE type; + PCPS_DEV_CFG cfg; +} PCPS_DEV; + + +// The macros below simplify access to the data +// stored in PCPS_DEV structure and should be used +// to extract the desired information. +// If the formal parameter is called _d then a pointer +// to device structure PCPS_DEV is expected. +// If the formal parameter is called _c then a pointer +// to configuration structure PCPS_DEV_CFG is expected. + +// Access device type information: +#define _pcps_type_num( _d ) ( (_d)->type.num ) +#define _pcps_type_name( _d ) ( (_d)->type.name ) +#define _pcps_dev_id( _d ) ( (_d)->type.dev_id ) +#define _pcps_ref_type( _d ) ( (_d)->type.ref_type ) +#define _pcps_bus_flags( _d ) ( (_d)->type.bus_flags ) + +// Query device type features: +#define _pcps_is_gps( _d ) ( _pcps_ref_type( _d ) == PCPS_REF_GPS ) +#define _pcps_is_dcf( _d ) ( _pcps_ref_type( _d ) == PCPS_REF_DCF ) +#define _pcps_is_msf( _d ) ( _pcps_ref_type( _d ) == PCPS_REF_MSF ) +#define _pcps_is_wwvb( _d ) ( _pcps_ref_type( _d ) == PCPS_REF_WWVB ) +#define _pcps_is_irig_rx( _d ) ( _pcps_ref_type( _d ) == PCPS_REF_IRIG ) +#define _pcps_is_ptp( _d ) ( _pcps_ref_type( _d ) == PCPS_REF_PTP ) +#define _pcps_is_frc( _d ) ( _pcps_ref_type( _d ) == PCPS_REF_FRC ) + +#define _pcps_is_lwr( _d ) ( _pcps_is_dcf( _d ) || _pcps_is_msf( _d ) || _pcps_is_wwvb( _d ) ) + +#define _pcps_is_isa( _d ) ( _pcps_bus_flags( _d ) & PCPS_BUS_ISA ) +#define _pcps_is_mca( _d ) ( _pcps_bus_flags( _d ) & PCPS_BUS_MCA ) +#define _pcps_is_pci( _d ) ( _pcps_bus_flags( _d ) & PCPS_BUS_PCI ) +#define _pcps_is_usb( _d ) ( _pcps_bus_flags( _d ) & PCPS_BUS_USB ) + +#define _pcps_is_pci_s5933( _d ) ( _pcps_bus_flags( _d ) == PCPS_BUS_PCI_S5933 ) +#define _pcps_is_pci_s5920( _d ) ( _pcps_bus_flags( _d ) == PCPS_BUS_PCI_S5920 ) +#define _pcps_is_pci_amcc( _d ) ( _pcps_is_pci_s5920( _d ) || _pcps_is_pci_s5933( _d ) ) +#define _pcps_is_pci_asic( _d ) ( _pcps_bus_flags( _d ) == PCPS_BUS_PCI_ASIC ) +#define _pcps_is_pci_pex8311( _d ) ( _pcps_bus_flags( _d ) == PCPS_BUS_PCI_PEX8311 ) +#define _pcps_is_pci_mbgpex( _d ) ( _pcps_bus_flags( _d ) == PCPS_BUS_PCI_MBGPEX ) + + +// Access device configuration information: +#define _pcps_bus_num( _d ) ( (_d)->cfg.bus_num ) +#define _pcps_slot_num( _d ) ( (_d)->cfg.slot_num ) + +#define _pcps_cfg_port_rsrc( _c, _n ) ( (_c)->port[_n] ) +#define _pcps_port_rsrc( _d, _n ) _pcps_cfg_port_rsrc( &(_d)->cfg, (_n) ) +#define _pcps_port_rsrc_unused( _d ) ( (_d)->base == 0 || (_d)->num == 0 ) + +#define _pcps_cfg_port_base( _c, _n ) ( _pcps_cfg_port_rsrc( (_c), (_n) ).base ) +#define _pcps_port_base( _d, _n ) ( _pcps_port_rsrc( (_d), (_n) ).base ) + +#define _pcps_cfg_irq_num( _c ) ( (_c)->irq_num ) +#define _pcps_irq_num( _d ) _pcps_cfg_irq_num( &(_d)->cfg ) + +#define _pcps_cfg_timeout_clk( _c ) ( (_c)->timeout_clk ) +#define _pcps_timeout_clk( _d ) _pcps_cfg_timeout_clk( &(_d)->cfg ) + +#define _pcps_fw_rev_num( _d ) ( (_d)->cfg.fw_rev_num ) +#define _pcps_features( _d ) ( (_d)->cfg.features ) +#define _pcps_fw_id( _d ) ( (_d)->cfg.fw_id ) +#define _pcps_sernum( _d ) ( (_d)->cfg.sernum ) + + +// The macros below handle the clock device's err_flags. +#define _pcps_err_flags( _d ) ( (_d)->cfg.err_flags ) +#define _pcps_chk_err_flags( _d, _msk ) ( _pcps_err_flags( _d ) & (_msk) ) +#define _pcps_set_err_flags( _d, _msk ) ( _pcps_err_flags( _d ) |= (_msk) ) +#define _pcps_clr_err_flags( _d, _msk ) ( _pcps_err_flags( _d ) &= ~(_msk) ) + + +// Query whether a special feature is supported: +#define _pcps_has_feature( _d, _f ) ( ( (_d)->cfg.features & (_f) ) != 0 ) +#define _pcps_can_set_time( _d ) _pcps_has_feature( (_d), PCPS_CAN_SET_TIME ) +#define _pcps_has_serial( _d ) _pcps_has_feature( (_d), PCPS_HAS_SERIAL ) +#define _pcps_has_sync_time( _d ) _pcps_has_feature( (_d), PCPS_HAS_SYNC_TIME ) +#define _pcps_has_ident( _d ) _pcps_has_feature( (_d), PCPS_HAS_IDENT ) +#define _pcps_has_utc_offs( _d ) _pcps_has_feature( (_d), PCPS_HAS_UTC_OFFS ) +#define _pcps_has_hr_time( _d ) _pcps_has_feature( (_d), PCPS_HAS_HR_TIME ) +#define _pcps_has_sernum( _d ) _pcps_has_feature( (_d), PCPS_HAS_SERNUM ) +#define _pcps_has_cab_len( _d ) _pcps_has_feature( (_d), PCPS_HAS_CABLE_LEN ) +#define _pcps_has_tzdl( _d ) _pcps_has_feature( (_d), PCPS_HAS_TZDL ) +#define _pcps_has_pcps_tzdl( _d ) _pcps_has_feature( (_d), PCPS_HAS_PCPS_TZDL ) +#define _pcps_has_tzcode( _d ) _pcps_has_feature( (_d), PCPS_HAS_TZCODE ) +#define _pcps_has_tz( _d ) _pcps_has_feature( (_d), PCPS_HAS_TZDL \ + | PCPS_HAS_PCPS_TZDL \ + | PCPS_HAS_TZCODE ) +// The next one is supported only with a certain GPS firmware version: +#define _pcps_has_event_time( _d ) _pcps_has_feature( (_d), PCPS_HAS_EVENT_TIME ) +#define _pcps_has_receiver_info( _d ) _pcps_has_feature( (_d), PCPS_HAS_RECEIVER_INFO ) +#define _pcps_can_clr_ucap_buff( _d ) _pcps_has_feature( (_d), PCPS_CAN_CLR_UCAP_BUFF ) +#define _pcps_has_ucap( _d ) _pcps_has_feature( (_d), PCPS_HAS_UCAP ) +#define _pcps_has_irig_tx( _d ) _pcps_has_feature( (_d), PCPS_HAS_IRIG_TX ) + +// The macro below determines whether a DCF77 clock +// supports a higher baud rate than standard +#define _pcps_has_serial_hs( _d ) \ + ( ( _pcps_type_num( _d ) == PCPS_TYPE_TCR511PEX ) || \ + ( _pcps_type_num( _d ) == PCPS_TYPE_PEX511 ) || \ + ( _pcps_type_num( _d ) == PCPS_TYPE_TCR511PCI ) || \ + ( _pcps_type_num( _d ) == PCPS_TYPE_TCR510PCI ) || \ + ( _pcps_type_num( _d ) == PCPS_TYPE_PCI511 ) || \ + ( _pcps_type_num( _d ) == PCPS_TYPE_PCI510 ) || \ + ( _pcps_type_num( _d ) == PCPS_TYPE_PCI509 && \ + _pcps_fw_rev_num( _d ) >= REV_HAS_SERIAL_HS_PCI509 ) ) + + +#define _pcps_has_signal( _d ) \ + ( _pcps_is_dcf( _d ) || _pcps_is_msf( _d ) || _pcps_is_wwvb( _d ) || _pcps_is_irig_rx( _d ) ) + +#define _pcps_has_mod( _d ) \ + ( _pcps_is_dcf( _d ) || _pcps_is_msf( _d ) || _pcps_is_wwvb( _d ) ) + + +#define _pcps_has_irig( _d ) \ + ( _pcps_is_irig_rx( _d ) || _pcps_has_irig_tx( _d ) ) + +#define _pcps_has_irig_ctrl_bits( _d ) \ + _pcps_has_feature( (_d), PCPS_HAS_IRIG_CTRL_BITS ) + +#define _pcps_has_irig_time( _d ) \ + _pcps_has_feature( (_d), PCPS_HAS_IRIG_TIME ) + +#define _pcps_has_raw_irig_data( _d ) \ + _pcps_has_feature( (_d), PCPS_HAS_RAW_IRIG_DATA ) + +#define _pcps_has_ref_offs( _d ) \ + _pcps_is_irig_rx( _d ) + +#define _pcps_ref_offs_out_of_range( _n ) \ + ( ( (_n) > MBG_REF_OFFS_MAX ) || ( (_n) < -MBG_REF_OFFS_MAX ) ) + +#define _pcps_has_opt_flags( _d ) \ + _pcps_is_irig_rx( _d ) + +#define _pcps_has_gps_data_16( _d ) _pcps_has_feature( (_d), PCPS_HAS_GPS_DATA_16 ) + +#define _pcps_has_gps_data( _d ) \ + ( _pcps_is_gps( _d ) || _pcps_has_gps_data_16( _d ) ) + +#define _pcps_has_synth( _d ) _pcps_has_feature( (_d), PCPS_HAS_SYNTH ) + +#define _pcps_has_generic_io( _d ) _pcps_has_feature( (_d), PCPS_HAS_GENERIC_IO ) + +#define _pcps_has_time_scale( _d ) _pcps_has_feature( (_d), PCPS_HAS_TIME_SCALE ) + +#define _pcps_has_utc_parm( _d ) _pcps_has_feature( (_d), PCPS_HAS_UTC_PARM ) + +#define _pcps_has_fast_hr_timestamp( _d ) _pcps_has_feature( (_d), PCPS_HAS_FAST_HR_TSTAMP ) + +#define _pcps_has_lan_intf( _d ) _pcps_has_feature( (_d), PCPS_HAS_LAN_INTF ) + +#define _pcps_has_ptp( _d ) _pcps_has_feature( (_d), PCPS_HAS_PTP ) + + +#define _pcps_has_asic_version( _d ) ( _pcps_is_pci_asic( _d ) \ + || _pcps_is_pci_pex8311( _d ) \ + || _pcps_is_pci_mbgpex( _d ) ) + +#define _pcps_has_asic_features( _d ) _pcps_has_asic_version( _d ) + + + +// There are some versions of IRIG receiver cards which ignore the TFOM code +// of an incoming IRIG signal even if an IRIG code has been configured which +// supports this. In this case these cards synchronize to the incoming IRIG +// signal even if the TFOM code reports the IRIG generator is not synchronized. +// The intended behaviour is that the IRIG receiver card changes its status +// to "freewheeling" in this case, unless it has been configured to ignore +// the TFOM code of the incoming IRIG signal (see the IFLAGS_DISABLE_TFOM flag +// defined in gpsdefs.h). + +// The macro below can be used to check based on the device info if a specific +// card with a specific firmware always ignores the TFOM code: +#define _pcps_incoming_tfom_ignored( _d ) \ + ( ( ( _pcps_type_num( _d ) == PCPS_TYPE_TCR167PCI ) && ( _pcps_fw_rev_num( _d ) <= 0x121 ) ) \ + || ( ( _pcps_type_num( _d ) == PCPS_TYPE_TCR170PEX ) && ( _pcps_fw_rev_num( _d ) <= 0x103 ) ) ) + + + +/** + The structure is used to return info + on the device driver.*/ +typedef struct +{ + uint16_t ver_num; /**< the device driver's version number */ + uint16_t n_devs; /**< the number of radio clocks handled by the driver */ + PCPS_ID_STR id_str; /**< the device driver's ID string */ +} PCPS_DRVR_INFO; + + + +/* + * The definitions and types below are used to collect + * all configuration parameters of a clock's serial ports + * that can be handled by this library: + */ + +// The maximum number of clocks' serial ports and string types +// that can be handled by the configuration programs: +#define MAX_PARM_PORT 4 +#define MAX_PARM_STR_TYPE 20 + +typedef PORT_INFO_IDX ALL_PORT_INFO[MAX_PARM_PORT]; +typedef STR_TYPE_INFO_IDX ALL_STR_TYPE_INFO[MAX_PARM_STR_TYPE]; + +typedef struct +{ + ALL_PORT_INFO pii; + ALL_STR_TYPE_INFO stii; + PORT_PARM tmp_pp; + +} RECEIVER_PORT_CFG; + + + +/* + * The definitions and types below are used to collect + * all configuration parameters of a clock's programmable + * pulse outputs that can be handled by this library: + */ + +#define MAX_PARM_POUT 4 + +typedef POUT_INFO_IDX ALL_POUT_INFO[MAX_PARM_POUT]; + + + +// The macros below can be used to mark a PCPS_TIME variable +// as unread, i.e. its contents have not been read from the clock, +// and to check if such a variable is marked as unread. +#define _pcps_time_set_unread( _t ); { (_t)->sec = 0xFF; } +#define _pcps_time_is_read( _t ) ( (uchar) (_t)->sec != 0xFF ) + + + +/** + The structure is used to read the current time from + a device, combined with an associated PC cycle counter value + to compensate program execution time. + */ +typedef struct +{ + MBG_PC_CYCLES cycles; + PCPS_TIME t; +} PCPS_TIME_CYCLES; + + + +/** + The structure is used to read a high resolution UTC time stamp + plus associated PC cycles counter value to compensate the latency. + */ +typedef struct +{ + MBG_PC_CYCLES cycles; + PCPS_TIME_STAMP tstamp; /**< High resolution time stamp (UTC) */ +} PCPS_TIME_STAMP_CYCLES; + +#define _mbg_swab_pcps_time_stamp_cycles( _p ) \ +{ \ + _mbg_swab_mbg_pc_cycles( &(_p)->cycles ); \ + _mbg_swab_pcps_time_stamp( &(_p)->tstamp ); \ +} + + + +/** + The structure is used to read the current high resolution time + from a device, combined with an associated PC cycle counter value + to compensate program execution time. + */ +typedef struct +{ + MBG_PC_CYCLES cycles; + PCPS_HR_TIME t; +} PCPS_HR_TIME_CYCLES; + +#define _mbg_swab_pcps_hr_time_cycles( _p ) \ +{ \ + _mbg_swab_mbg_pc_cycles( &(_p)->cycles ); \ + _mbg_swab_pcps_hr_time( &(_p)->t ); \ +} + + + +/** + The structure below can be used to let the kernel driver read + the current system time plus the associated HR time from a plugin card + as close as possibly, and return the results to a user space application + which can then compute the time difference and latencies. + This structure also contains the card's status information (e.g. sync status). + */ +typedef struct +{ + PCPS_HR_TIME_CYCLES ref_hr_time_cycles; /**< HR time read from the card, plus cycles */ + MBG_SYS_TIME_CYCLES sys_time_cycles; /**< system timestamp plus associated cycles */ +} MBG_TIME_INFO_HRT; + +#define _mbg_swab_mbg_time_info_hrt( _p ) \ +{ \ + _mbg_swab_pcps_hr_time_cycles( &(_p)->ref_hr_time_cycles ); \ + _mbg_swab_mbg_sys_time_cycles( &(_p)->sys_time_cycles ); \ +} + + + +/** + The structure below can be used to let the kernel driver read + the current system time plus an associated HR timestamp from a plugin card + as close as possibly, and return the results to a user space application + which can then compute the time difference and latencies. + Since the card's time stamp is usually taken using the fast memory mapped + access this structure does *not* contain the card's status information + (e.g. sync status). + */ +typedef struct +{ + PCPS_TIME_STAMP_CYCLES ref_tstamp_cycles; /**< HR timestamp from the card, plus cycles */ + MBG_SYS_TIME_CYCLES sys_time_cycles; /**< system timestamp plus associated cycles */ +} MBG_TIME_INFO_TSTAMP; + +#define _mbg_swab_mbg_time_info_tstamp( _p ) \ +{ \ + _mbg_swab_pcps_time_stamp_cycles( &(_p)->ref_tstamp_cycles ); \ + _mbg_swab_mbg_sys_time_cycles( &(_p)->sys_time_cycles ); \ +} + + + +typedef uint32_t PCPS_IRQ_STAT_INFO; + +// Flags used with PCPS_IRQ_STAT_INFO: +#define PCPS_IRQ_STAT_ENABLE_CALLED 0x01 +#define PCPS_IRQ_STAT_ENABLED 0x02 +#define PCPS_IRQ_STAT_UNSAFE 0x04 // IRQs unsafe with this firmeware version / ASIC + +#define PCPS_IRQ_STATE_DANGER ( PCPS_IRQ_STAT_ENABLED | PCPS_IRQ_STAT_UNSAFE ) + +#define _pcps_fw_rev_num_major( _v ) \ + ( ( (_v) >> 8 ) & 0xFF ) + +#define _pcps_fw_rev_num_minor( _v ) \ + ( (_v) & 0xFF ) + + +#if defined( _USE_PACK ) // set default alignment + #pragma pack() +#endif + +/* End of header body */ + +#undef _ext + +#endif /* _PCPSDEV_H */ + diff --git a/mbglib/common/pcpsdrvr.c b/mbglib/common/pcpsdrvr.c new file mode 100755 index 0000000..ae179e6 --- /dev/null +++ b/mbglib/common/pcpsdrvr.c @@ -0,0 +1,3395 @@ + +/************************************************************************** + * + * $Id: pcpsdrvr.c 1.46.2.24 2011/02/04 14:44:45 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Driver functions that detect Meinberg PC plug-in devices and set up + * the software environment (port base address, clock features, etc.). + * + * These functions should be used with programs which have direct + * access to the hardware (e.g. device drivers). + * + * Programs which access the devices via device drivers should + * use the functions provided by the mbgdevio module. + * + * There are several preprocessor symbols defined at the top of + * pcpsdrvr.h which control the default support of some features + * under the different operating systems. If required, each of + * those symbols can be overridden by compiler arguments. + * + * Basically the following radio clocks are supported: + * USB: USB5131, TCR51USB, MSF51USB, WWVB51USB, DCF600USB + * PCI express: PEX511, TCR511PEX, GPS170PEX, PTP270PEX, + * FRC511PEX, TCR170PEX, GPS180PEX, TCR180PEX + * PCI bus 5V/3.3V: PCI510, PCI511, GPS169PCI, GPS170PCI, + * TCR510PCI, TCR167PCI, TCR511PCI + * PCI bus 5V: PCI32, GPS167PCI, PCI509, GPS168PCI + * MCA bus: PS31 + * ISA bus: PC31, PC32, GPS167PC + * + * USB is not supported for some target environments, mainly because + * those operating systems don't provide full USB support. + * + * PCI support is possible in two different ways. The preferred + * functions are compiled in if one of the symbols _PCPS_USE_PCI_PNP + * or _PCPS_USE_PCI_BIOS is defined != 0. + * + * If _PCPS_USE_PCI_PNP is != 0 it is assumed that the operating + * system's PCI layer detects a new PCI device and calls a driver's + * add_device()/start_device() function to initialize the device. + * This new technique is supported with PNP operating systems + * (e.g. Win98, Win2K, newer Linux versions). + * + * If _PCPS_USE_PCI_BIOS is != 0 the program scans the PCI bus + * during startup to detect and initialize supported PCI devices. + * This techique is used with non-PNP operating systems. + * + * The symbol _PCPS_USE_RSRCMGR must be defined != 0 to include + * support of resource managers, if necessary. + * + * If the symbol _PCPS_USE_MCA is defined != 0 then Micro Channel + * detection (and therefore auto-detection of a MCA clock) is + * supported. + * + * MCA clocks are accessed using the same low level functions as + * ISA clocks, so if autodetection of MCA clocks is not supported + * then a MCA clock's known port number can be passed to + * pcps_detect_clocks() to let it be treated like an ISA clock. + * + * ----------------------------------------------------------------------- + * $Log: pcpsdrvr.c $ + * Revision 1.46.2.24 2011/02/04 14:44:45 martin + * Revision 1.46.2.23 2011/02/01 17:12:04 martin + * Revision 1.46.2.22 2011/02/01 15:08:34 martin + * Revision 1.46.2.21 2011/02/01 12:12:18 martin + * Revision 1.46.2.20 2011/01/31 17:30:28 martin + * Preliminary virt addr under *BSD. + * Revision 1.46.2.19 2011/01/28 10:34:06 martin + * Moved MBG_TGT_SUPP_MEM_ACC definition to pcpsdev.h. + * Revision 1.46.2.18 2011/01/27 15:13:08 martin + * Added some debug messages in pcps_start_device(). + * Revision 1.46.2.17 2011/01/27 13:39:33 martin + * Revision 1.46.2.16 2011/01/27 11:01:48 martin + * Support static device list (no malloc) and use it under FreeBSD. + * Revision 1.46.2.15 2011/01/26 16:40:14 martin + * Fixed build under FreeBSD. + * Revision 1.46.2.14 2011/01/26 11:30:29 martin + * Fixed PTP270PEX boot delay. + * Revision 1.46.2.13 2011/01/07 14:00:58 daniel + * Re-enabled wait period for PTP270PEX + * Revision 1.46.2.12 2010/11/23 11:07:56Z martin + * Support memory mapped access under DOS. + * Revision 1.46.2.11 2010/11/22 14:19:27Z martin + * Support DCF600USB. + * Cleanup. + * Revision 1.46.2.10 2010/10/06 09:24:02 martin + * Revision 1.46.2.9 2010/09/27 13:09:22Z martin + * Revision 1.46.2.8 2010/09/21 13:10:15 daniel + * Check for raw IRIG data support in reciver info. + * Revision 1.46.2.7 2010/09/02 12:19:24Z martin + * Introduced and use new function check_ri_feature(). + * Also detect support for raw IRIG data from RECEIVER_INFO. + * Added debug code. + * Sleeping for PTP270PEX if uptime is too low needs to be fixed. + * Revision 1.46.2.6 2010/08/16 15:41:28 martin + * Revision 1.46.2.5 2010/08/13 11:56:49 martin + * Fixed build on WIN32_NON_PNP. + * Revision 1.46.2.4 2010/08/13 11:20:23Z martin + * If required, wait until PTP270PEX has finished booting. + * Revision 1.46.2.3 2010/08/11 13:41:47Z martin + * Code cleanup. + * Revision 1.46.2.2 2010/07/14 14:51:56 martin + * Use direct pointer to memory maopped timestamp. + * Revision 1.46.2.1 2010/06/30 15:02:12 martin + * Support GPS180PEX and TCR180PEX. + * Revision 1.46 2009/12/15 14:45:33 daniel + * Account for feature to read the raw IRIG bits. + * Revision 1.45 2009/09/29 07:24:50Z martin + * Use standard feature flag to check if fast HR time is supported. + * Revision 1.44 2009/06/23 07:10:47 martin + * Fixed/modified some debug messages. + * Revision 1.43 2009/06/19 12:13:59 martin + * Check if TCR cards support raw IRIG time. + * Revision 1.42 2009/06/09 10:15:33 daniel + * Check if card has LAN interface and supports PTP. + * Revision 1.41 2009/04/08 08:33:20 daniel + * Check whether the TCR511PCI or devices with + * RECEIVER_INFO support IRIG control function bits. + * Revision 1.40 2009/03/27 09:55:13Z martin + * Added some debug messages. + * Account for renamed library symbols. + * Revision 1.39 2009/03/19 12:04:31Z martin + * Adjust endianess of ASIC version and ASIC features after having read. + * Revision 1.38 2009/03/17 15:33:53 martin + * Support reading IRIG control function bits. + * Revision 1.37 2009/03/13 09:17:00Z martin + * Bug fix: Hadn't checked whether TCR170PEX card provides the + * programmable synthesizer. + * As a fix moved the code from the body of check_opt_features() + * into pcps_start_device() so that the check is done for every + * type of card. + * Swap receiver_info to make this work on non-x86 architectures. + * Support configurable time scales, and reading/writing GPS UTC + * parameters via the PC bus. + * Use mbg_get_pc_cycles() instead of _pcps_get_cycles(). + * Revision 1.36 2009/01/13 12:03:57Z martin + * Generate a separate warning message if the firmware could not + * be read from an ISA card. + * Care about "long long" in debug msg. + * Revision 1.35 2008/12/16 14:38:49Z martin + * Account for new devices PTP270PEX, FRC270PEX, TCR170PEX, and WWVB51USB. + * Check the firmware / ASIC version of PEX cards and flag the device + * unsafe for IRQs if the versions are older than required. + * Check whether PEX511 and PCI511 support HR time. + * Moved initialization of common spinlocks and mutexes to pcps_start_device(). + * Take access cycles count in the low level routines, with interrupts disabled. + * Cleanup for pcps_read_usb() which is now possible since access cycles count + * is now taken inside the low evel routines. + * Support mapped I/O resources, unaligned access and endianess conversion. + * Account for ASIC_FEATURES being coded as flags, and account for + * new symbol PCI_ASIC_HAS_MM_IO. + * Account for new MBG_PC_CYCLES type. + * Account for signed irq_num. + * Renamed MBG_VIRT_ADDR to MBG_MEM_ADDR. + * Use MBG_MEM_ADDR type for memory rather than split high/low types. + * Distinguish device port variables for IRQ handling. + * Preliminarily support USB latency compensation under Win32 PNP targets + * and account for USB EHCI microframe timing which requires a different + * latency compensation approach. This is useful if a USB 2.0 hub is connected + * between device and host. + * Also read the ASIC version at device initialization. + * pcps_alloc_ddev() does not take a parameter anymore. + * Cleaned up comments. + * Revision 1.34 2008/02/27 10:03:02 martin + * Support TCR51USB and MSF51USB. + * Preliminary support for mapped memory access under Windows and Linux. + * Enabled PCPS_IRQ_1_SEC for USB within WIN32 targets + * in pcps_start_device(). + * Fixed a bug in pcps_write() where the error code + * that was returned from a USB device was misinterpreted + * due to a signed/unsigned mismatch (added typecast). + * Removed obsolete function pcps_cleanup_all_devices(). + * Code cleanup. + * Revision 1.33 2008/01/31 08:51:30Z martin + * Picked up changes from 1.31.2.1: + * Changed default definition of PCI_DWORD to uint32_t. + * Removed erraneous brace from debug code. + * Revision 1.32 2007/09/26 11:05:57Z martin + * Added support for USB in general and new USB device USB5131. + * Renamed ..._USE_PCIMGR symbols to ..._USE_PCI_PNP. + * Renamed ..._USE_PCIBIOS symbols to ..._USE_PCI_BIOS. + * Added new symbol _USE_ISA_PNP to exclude non-PNP stuff. + * from build if ISA devices are also handled by the PNP manager. + * Use new MBG_... codes defined in mbgerror.h. + * Unified timeout handling in low level functions by using an inline function. + * Renamed pcps_pnp_start_device() to pcps_start_device(). + * Renamed pcps_setup_pci_dev() to pcps_setup_and_startpci_dev(). + * Merged code from init_ddev_cfg() and finish_ddev_cfg() into pcps_start_device(). + * Improved and unified handling of ISA devices. + * Removed calling register_pnp_devices() from pcps_detect_clocks(), + * this is now called directly. + * Added missing IRIG support to pcps_rsrc_register_device(). + * Revision 1.31 2007/07/17 08:22:47Z martin + * Added support for TCR511PEX and GPS170PEX. + * Revision 1.30 2007/07/16 12:56:01Z martin + * Added support for PEX511. + * Rewrote common resource handling code in order to simplify + * OS specific code. + * Revision 1.29 2007/03/02 09:40:33Z martin + * Use generic port I/O macros. + * Pass PCPS_DDEV structure to the low level read functions. + * Use new _pcps_..._timeout_clk() macros. + * Added init code qualifier. + * Preliminary support for *BSD. + * Preliminary support for USB. + * Revision 1.28 2006/07/11 10:24:20 martin + * Use _fmemcpy() in pcps_generic_io() to support environments which + * require far data pointers. + * Revision 1.27 2006/07/07 09:41:15 martin + * Renamed pci_..() function calls to _mbg_pci_..() calls which are defined according to the + * OS requirements, in order to avoid naming conflicts. + * Revision 1.26 2006/06/19 15:28:52 martin + * Added support for TCR511PCI. + * Modified parameters required to detect ISA cards. + * The array of port addresses does no more require a 0 address + * as last value. + * Revision 1.25 2006/03/10 11:01:27 martin + * Added support for PCI511. + * Revision 1.24 2005/11/03 15:50:45Z martin + * Added support for GPS170PCI. + * Revision 1.23 2005/09/16 08:21:08Z martin + * Also flag PCI cards which have base_addr set to 0 as uninitialized. + * Revision 1.22 2005/06/02 10:32:07Z martin + * Changed more types to C99 fixed size types. + * New function pcps_generic_io(). + * Revision 1.21 2004/12/13 14:19:38Z martin + * Support configuration of on-board frequency synthesizer. + * Revision 1.20 2004/11/09 13:02:48Z martin + * Redefined fixed width data types using standard C99 types. + * Fixed warnings about lvalue casts. + * Revision 1.19 2004/10/14 15:01:24 martin + * Added support for TCR167PCI. + * Revision 1.18 2004/09/06 15:16:57Z martin + * Support a GPS_DATA interface where sizes are specified + * by 16 instead of the original 8 bit quantities, thus allowing + * to transfer data blocks which exceed 255 bytes. + * Conditionally skip assertions under Linux. + * Revision 1.17 2004/04/22 14:47:54 martin + * Fixed conversion of firmware rev. number. + * Revision 1.16 2004/04/07 09:45:04Z martin + * Support new feature PCPS_HAS_IRIG_TX for GPS169PCI. + * Revision 1.15 2003/12/22 16:15:21Z martin + * Support PCPS_HR_TIME for TCR510PCI. + * Revision 1.14 2003/07/30 07:28:23Z martin + * Moved prototype for register_pci_devices() outside to top of file. + * Revision 1.13 2003/07/08 15:11:55 martin + * Support PCI PNP interface under Linux. + * New function pcps_rsrc_release(). + * Made some functions public. + * Renamed some public functions to start with pcps_... + * Revision 1.12 2003/06/19 10:08:43 MARTIN + * Renamed some functions to follow common naming conventions. + * Made a function's parameter pointer const. + * Changes due to renamed symbols in pcpsdev.h. + * Check devices for _pcps_has_ucap() support. + * Revision 1.11 2003/05/16 09:28:06 MARTIN + * Moved inclusion of some headers to pcpsdrvr.h. + * Revision 1.10 2003/04/09 16:35:57 martin + * Supports PCI510, GPS169PCI, and TCR510PCI, + * and new PCI_ASIC used by those devices. + * Revision 1.9 2003/03/20 11:42:37 martin + * Fixed syntax for QNX. + * Revision 1.8 2002/08/09 08:25:50 MARTIN + * Support feature PCPS_CAN_CLR_CAP_BUFF. + * Fixed a bug resulting in an unterminated string + * if SERNUM was being read. + * Revision 1.7 2002/02/26 09:31:57 MARTIN + * New function pcps_read_sernum(). + * Revision 1.6 2002/02/19 09:46:26 MARTIN + * Use new header mbg_tgt.h to check the target environment. + * Removed function pcps_sn_str_from_ident(), use new + * function mbg_gps_ident_decode() from identdec.c now. + * If a PCI clock's interface is not properly configured don't + * enable the device and set the read function to the new + * dummy function pcps_read_null() to prevent driver from + * accessing random ports. + * Revision 1.5 2002/02/01 12:06:12 MARTIN + * Added support for GPS168PCI. + * Removed obsolete code. + * Revision 1.4 2001/11/30 09:52:48 martin + * Added support for event_time which, however, requires + * a custom GPS firmware. + * Revision 1.3 2001/09/18 06:59:18 MARTIN + * Account for new preprocessor symbols in the header file. + * Added some type casts to avoid compiler warnings under Win32. + * Added some debug messages to clock detection functions. + * Revision 1.2 2001/03/16 14:45:33 MARTIN + * New functions and definitions to support PNP drivers. + * Revision 1.1 2001/03/01 16:26:41 MARTIN + * Initial revision for the new library. + * + **************************************************************************/ + +#define _PCPSDRVR + #include +#undef _PCPSDRVR + +#include +#include +#include +#include +#include + +#if defined( MBG_TGT_WIN32_PNP ) + #include + #include + #include + #include +#elif defined( MBG_TGT_WIN32 ) + #include + #include +#endif + +#if !defined( MBG_TGT_LINUX ) && !defined( MBG_TGT_BSD ) + #include +#endif + +#if defined( MBG_TGT_BSD ) + #include + #include +#endif + +#if _PCPS_USE_MCA + #include +#endif + +#if _PCPS_USE_PCI + #include +#endif + +#if _PCPS_USE_USB + #define MBGUSB_MIN_ENDPOINTS_REQUIRED 3 +#endif + + +// time required for PTP270PEX to be ready after booting +#define MAX_BOOT_TIME_PTP270PEX 27 // [s] + + +#if !defined( DEBUG_IO ) + #define DEBUG_IO ( defined( DEBUG ) && ( DEBUG >= DEBUG_LVL_IO ) ) +#endif + +#if !defined( DEBUG_PORTS ) + #define DEBUG_PORTS ( defined( DEBUG ) && ( DEBUG >= DEBUG_LVL_PORTS ) ) +#endif + +#if !defined( DEBUG_SERNUM ) + #define DEBUG_SERNUM ( defined( DEBUG ) && ( DEBUG >= DEBUG_LVL_SERNUM ) ) +#endif + +extern const char *pcps_driver_name; + + +// In some environments special far functions are are neither +// required nor supported, so redefine calls to those functions +// to appropriate standard function calls. +#if defined( MBG_TGT_NETWARE ) || defined( MBG_TGT_WIN32 ) || \ + defined( MBG_TGT_LINUX ) || defined( MBG_TGT_BSD ) || \ + defined( MBG_TGT_QNX ) + #define _fmemcpy( _d, _s, _n ) memcpy( _d, _s, _n ) + #define _fstrlen( _s ) strlen( _s ) + #define _fstrncmp( _s1, _s2, _n ) strncmp( (_s1), (_s2), (_n) ) +#elif defined( MBG_TGT_OS2 ) + #define _fstrncmp( _s1, _s2, _n ) _fmemcmp( (_s1), (_s2), (_n) ) +#endif + +#if defined( MBG_TGT_OS2 ) + // Watcom C Compiler options for the OS/2 device driver result in + // warnings if automatic stack addresses are passed to functions. + #define static_wc static + #define FMT_03X "%X" + #define FMT_08X "%X" +#else + #define static_wc + #define FMT_03X "%03X" + #define FMT_08X "%08lX" +#endif + +#if defined( MBG_TGT_LINUX ) + typedef unsigned int PCI_DWORD; +#else + typedef uint32_t PCI_DWORD; +#endif + + +#if defined( MBG_TGT_LINUX ) + + #define _pcps_irq_flags \ + unsigned long irq_flags; + + #define _pcps_disb_local_irq_save() \ + local_irq_save( irq_flags ) + + #define _pcps_local_irq_restore() \ + local_irq_restore( irq_flags ) + +#elif defined( MBG_TGT_WIN32 ) + + #define _pcps_irq_flags \ + KIRQL old_irq_lvl; + + #define _pcps_disb_local_irq_save() \ + KeRaiseIrql( HIGH_LEVEL, &old_irq_lvl ) + + #define _pcps_local_irq_restore() \ + KeLowerIrql( old_irq_lvl ) + +#else + + // Nothing to define here. + +#endif + +#if !defined( _pcps_irq_flags ) && \ + !defined( _pcps_disb_local_irq_save ) && \ + !defined( _pcps_local_irq_restore) + #define _pcps_irq_flags + #define _pcps_disb_local_irq_save(); + #define _pcps_local_irq_restore(); +#endif + + +#if defined( MBG_TGT_LINUX ) && defined( time_after ) + #define _pcps_time_after( _curr, _tmo ) \ + time_after( (unsigned long) _curr, (unsigned long) _tmo ) +#else + #define _pcps_time_after( _curr, _tmo ) ( _curr >= _tmo ) +#endif + + + +static /*HDR*/ +long mbg_delta_sys_time_ms( const MBG_SYS_TIME *t2, const MBG_SYS_TIME *t1 ) +{ + #if defined( MBG_TGT_LINUX ) || defined( MBG_TGT_BSD ) + long dt = ( t2->tv_sec - t1->tv_sec ) * 1000; + dt += ( t2->tv_usec - t1->tv_usec ) / 1000; + return dt; + #elif defined( MBG_TGT_WIN32 ) + return (long) ( ( t2->QuadPart - t1->QuadPart ) / HNS_PER_MS ); + #else + #error mbg_delta_sys_time_ms not implemented for this target + #endif + +} // mbg_delta_sys_time_ms + + + +static /*HDR*/ +void report_uptime( const MBG_SYS_UPTIME *p_uptime ) +{ + #if defined( MBG_TGT_LINUX ) + printk( KERN_INFO "%s: uptime %Lu jiffies -> %Lu s, required %u s\n", + pcps_driver_name, (uint64_t) get_jiffies_64() - INITIAL_JIFFIES, + (uint64_t) *p_uptime, MAX_BOOT_TIME_PTP270PEX ); + #elif defined( MBG_TGT_BSD ) + printf( "%s: uptime %lli s, required %u s\n", + pcps_driver_name, (long long) *p_uptime, MAX_BOOT_TIME_PTP270PEX ); + #elif defined( MBG_TGT_WIN32 ) + WCHAR wcs_msg[120]; + + swprintf( wcs_msg, L"uptime: %I64u s, required %u s", + (uint64_t) *p_uptime, MAX_BOOT_TIME_PTP270PEX ); + _evt_msg( GlbDriverObject, wcs_msg ); + #endif + +} // report_uptime + + + +static /*HDR*/ +int pcps_check_pex_irq_unsafe( PCPS_DDEV *pddev, uint16_t req_fw_ver, + uint8_t req_asic_ver_major, uint8_t req_asic_ver_minor ) +{ + int rc = !_pcps_pex_irq_is_safe( _pcps_ddev_fw_rev_num( pddev ), req_fw_ver, + _pcps_ddev_asic_version( pddev ), + req_asic_ver_major, req_asic_ver_minor ); + + if ( rc ) + { + pddev->irq_stat_info |= PCPS_IRQ_STAT_UNSAFE; + + // Prevent the driver from writing IRQ ACK to the card even if IRQs + // should be unintentionally enabled. + pddev->irq_ack_port = 0; + pddev->irq_ack_mask = 0; + } + + return rc; + +} // pcps_check_pex_irq_unsafe + + + +#if MBG_TGT_SUPP_MEM_ACC + +static __mbg_inline /*HDR*/ +int map_sys_virtual_address( PCPS_DDEV *pddev ) +{ + pddev->mm_tstamp_addr = NULL; // unless configured below + + #if defined ( MBG_TGT_WIN32 ) + { + PHYSICAL_ADDRESS pAD; + + pAD.QuadPart = pddev->rsrc_info.mem[0].start; + pddev->mm_addr = MmMapIoSpace( pAD, sizeof( *pddev->mm_addr ), MmNonCached ); + } + #elif defined ( MBG_TGT_LINUX ) + + pddev->mm_addr = ioremap( ( (ulong) pddev->rsrc_info.mem[0].start ), sizeof( *pddev->mm_addr ) ); + + #elif defined ( MBG_TGT_BSD ) + + pddev->mm_addr = rman_get_virtual( pddev->rsrc_info.mem[0].bsd.res ); + + #else // DOS, ... + + pddev->mm_addr = (PCPS_MM_LAYOUT FAR *) pddev->rsrc_info.mem[0].start; + + #endif // target specific code + + if ( pddev->mm_addr == NULL ) + return -1; + + if ( _pcps_ddev_is_pci_mbgpex( pddev ) ) + pddev->mm_tstamp_addr = &pddev->mm_addr->mbgpex.tstamp; + else + if ( _pcps_ddev_is_pci_pex8311( pddev ) ) + pddev->mm_tstamp_addr = &pddev->mm_addr->pex8311.tstamp; + + _mbgddmsg_3( MBG_DBG_INIT_DEV, "MM addr: base: 0x%p, tstamp: 0x%p, offs: 0x%02lX", + pddev->mm_addr, pddev->mm_tstamp_addr, + (ulong) pddev->mm_tstamp_addr - (ulong) pddev->mm_addr ); + + return 0; + +} // map_sys_virtual_address + + + +static __mbg_inline /*HDR*/ +void unmap_sys_virtual_address( PCPS_DDEV *pddev ) +{ + if ( pddev->mm_addr ) + { + #if defined ( MBG_TGT_WIN32 ) + MmUnmapIoSpace( pddev->mm_addr, sizeof( *pddev->mm_addr ) ); + #elif defined ( MBG_TGT_LINUX ) + iounmap( pddev->mm_addr ); + #else // DOS, ... + // nothing to do + #endif + + pddev->mm_addr = NULL; + pddev->mm_tstamp_addr = NULL; + } + +} // unmap_sys_virtual_address + +#endif // MBG_TGT_SUPP_MEM_ACC + + + +#if defined( __GNUC__ ) +// Avoid "no previous prototype" with some gcc versions. +__mbg_inline +int pcps_wait_busy( PCPS_DDEV *pddev ) __attribute__((always_inline)); +#endif + +__mbg_inline /*HDR*/ +int pcps_wait_busy( PCPS_DDEV *pddev ) +{ + if ( _pcps_ddev_status_busy( pddev ) ) + { + #if defined( MBG_TGT_BSD ) + struct timeval tv_start; + + getmicrouptime( &tv_start ); + + while ( _pcps_ddev_status_busy( pddev ) ) + { + struct timeval tv_now; + long long delta_ms; + + getmicrouptime( &tv_now ); + delta_ms = ( ( tv_now.tv_sec - tv_start.tv_sec ) * 1000 ) + + ( ( tv_now.tv_usec - tv_start.tv_usec ) / 1000 ); + if ( delta_ms > _pcps_ddev_timeout_clk( pddev ) ) + return MBG_ERR_TIMEOUT; + } + #elif _PCPS_USE_CLOCK_TICK + clock_t timeout_val = clock() + _pcps_ddev_timeout_clk( pddev ); + + while ( _pcps_ddev_status_busy( pddev ) ) + if ( _pcps_time_after( clock(), timeout_val ) ) + return MBG_ERR_TIMEOUT; + #else + long cnt = _pcps_ddev_timeout_clk( pddev ); + + for ( ; _pcps_ddev_status_busy( pddev ); cnt-- ) + if ( cnt == 0 ) + return MBG_ERR_TIMEOUT; + #endif + } + + return 0; + +} // pcps_wait_busy + + + +/*-------------------------------------------------------------- + * Name: pcps_read_null() + * pcps_read_std() + * pcps_read_amcc_s5933() + * pcps_read_amcc_s5920() + * pcps_read_asic() + * pcps_read_usb() + * + * Purpose: These functions are used for low level access + * to Meinberg plug-in radio clocks. The function + * to be used depends on the clock's bus type and + * interface chip. + * + * Input: pcfg pointer to the clock's configuration + * cmd the command code for the board + * count the number of bytes to be read + * + * Output: buffer the bytes that could be read + * + * Ret value: MBG_SUCCESS no error + * MBG_ERR_TIMEOUT board is busy for too long + *-------------------------------------------------------------*/ + +// The dummy read function below is used if a clock is +// not properly initialized, in order to avoid I/O access +// on unspecified ports. + +static /*HDR*/ /* type: PCPS_READ_FNC */ +short pcps_read_null( PCPS_DDEV *pddev, uint8_t cmd, + uint8_t FAR *buffer, uint8_t count ) +{ + + return MBG_ERR_TIMEOUT; + +} // pcps_read_null + + + +// The function below must be used to access a clock with +// standard ISA or micro channel bus. + +static /*HDR*/ /* type: PCPS_READ_FNC */ +short pcps_read_std( PCPS_DDEV *pddev, uint8_t cmd, + uint8_t FAR *buffer, uint8_t count ) +{ + PCPS_IO_ADDR_MAPPED port = _pcps_ddev_io_base_mapped( pddev, 0 ); + int i; + _pcps_irq_flags + + #if DEBUG_IO + _mbgddmsg_1( MBG_DBG_INIT_DEV, "pcps_read_std: cmd %02X", cmd ); + #endif + + _pcps_disb_local_irq_save(); + mbg_get_pc_cycles( &pddev->acc_cycles ); + // write the command byte + _mbg_outp8( pddev, port, cmd ); + _pcps_local_irq_restore(); + + // wait until BUSY flag goes low or timeout + if ( pcps_wait_busy( pddev ) < 0 ) + return MBG_ERR_TIMEOUT; + + + // no timeout: read bytes from the board's FIFO + for ( i = 0; i < count; i++ ) + { + *buffer++ = _mbg_inp8( pddev, port ); + + #if DEBUG_IO + _mbgddmsg_1( MBG_DBG_DETAIL, "pcps_read_std: %02X", buffer[i] ); + #endif + } + + return MBG_SUCCESS; + +} // pcps_read_std + + + +#if _PCPS_USE_PCI + +// The function below must be used to access a clock with +// PCI bus and AMCC S5933 interface chip. + +static /*HDR*/ /* type: PCPS_READ_FNC */ +short pcps_read_amcc_s5933( PCPS_DDEV *pddev, uint8_t cmd, + uint8_t FAR *buffer, uint8_t count ) +{ + PCPS_IO_ADDR_MAPPED port = _pcps_ddev_io_base_mapped( pddev, 0 ); + int i; + _pcps_irq_flags + + + #if DEBUG_IO + _mbgddmsg_1( MBG_DBG_INIT_DEV, "pcps_read_amcc_s5933: cmd %02X", cmd ); + #endif + + // reset inbound mailbox and FIFO status + _mbg_outp8( pddev, port + AMCC_OP_REG_MCSR + 3, 0x0C ); + + // set FIFO + _mbg_outp8( pddev, port + AMCC_OP_REG_INTCSR + 3, 0x3C ); + + _pcps_disb_local_irq_save(); + mbg_get_pc_cycles( &pddev->acc_cycles ); + // write the command byte + _mbg_outp8( pddev, port + AMCC_OP_REG_OMB1, cmd ); + _pcps_local_irq_restore(); + + // wait until BUSY flag goes low or timeout + if ( pcps_wait_busy( pddev ) < 0 ) + return MBG_ERR_TIMEOUT; + + + // no timeout: read bytes from the board's FIFO + for ( i = 0; i < count; i++ ) + { + if ( _mbg_inp16_to_cpu( pddev, port + AMCC_OP_REG_MCSR ) & 0x20 ) + return MBG_ERR_FIFO; + + buffer[i] = _mbg_inp8( pddev, port + AMCC_OP_REG_FIFO + ( i % sizeof( uint32_t) ) ); + + #if DEBUG_IO + _mbgddmsg_1( MBG_DBG_DETAIL, "pcps_read_amcc_s5933: %02X", buffer[i] ); + #endif + } + + return MBG_SUCCESS; + +} /* pcps_read_amcc_s5933 */ + +#endif /* _PCPS_USE_PCI */ + + + +#if _PCPS_USE_PCI + +// The function below must be used to access a clock with +// PCI bus and AMCC S5920 interface chip. + +static /*HDR*/ /* type: PCPS_READ_FNC */ +short pcps_read_amcc_s5920( PCPS_DDEV *pddev, uint8_t cmd, + uint8_t FAR *buffer, uint8_t count ) +{ + uint8_t FAR *p = buffer; + PCPS_IO_ADDR_MAPPED data_port = _pcps_ddev_io_base_mapped( pddev, 1 ); + int i; + int dt_quot; + int dt_rem; + _pcps_irq_flags + + + #if DEBUG_IO + _mbgddmsg_1( MBG_DBG_INIT_DEV, "pcps_read_amcc_s5920: cmd %02X", cmd ); + #endif + + _pcps_disb_local_irq_save(); + mbg_get_pc_cycles( &pddev->acc_cycles ); + // write the command byte + _mbg_outp8( pddev, _pcps_ddev_io_base_mapped( pddev, 0 ) + AMCC_OP_REG_OMB, cmd ); + _pcps_local_irq_restore(); + + dt_quot = count / 4; + dt_rem = count % 4; + + // wait until BUSY flag goes low or timeout + if ( pcps_wait_busy( pddev ) < 0 ) + return MBG_ERR_TIMEOUT; + + + if ( count ) + { + // do this only if we must read data + + uint32_t ul; + + // first read full 32 bit words + for ( i = 0; i < dt_quot; i++ ) + { + ul = _mbg_inp32_to_cpu( pddev, data_port ); + #if DEBUG_IO + _mbgddmsg_1( MBG_DBG_INIT_DEV, "pcps_read_amcc_s5920: %08X", ul ); + #endif + _pcps_put_unaligned( ul, (uint32_t FAR *) p ); + p += sizeof( ul ); + } + + // then read the remaining bytes, if required + if ( dt_rem ) + { + ul = _mbg_inp32_to_cpu( pddev, data_port ); + + for ( i = 0; i < dt_rem; i++ ) + { + #if DEBUG_IO + _mbgddmsg_1( MBG_DBG_INIT_DEV, "pcps_read_amcc_s5920: %02X", BYTE_OF( ul, i ) ); + #endif + + *p++ = BYTE_OF( ul, i ); + } + } + } + else + _mbg_inp32( pddev, data_port ); // do a dummy read + + return MBG_SUCCESS; + +} // pcps_read_amcc_s5920 + +#endif /* _PCPS_USE_PCI */ + + + +#if _PCPS_USE_PCI + +// The function below must be used to access a clock with +// PCI bus and Meinberg PCI interface ASIC. + +static /*HDR*/ /* type: PCPS_READ_FNC */ +short pcps_read_asic( PCPS_DDEV *pddev, uint8_t cmd, + uint8_t FAR *buffer, uint8_t count ) +{ + uint8_t FAR *p = buffer; + PCPS_IO_ADDR_MAPPED data_port; + PCI_ASIC_REG ar; + int i; + int dt_quot; + int dt_rem; + _pcps_irq_flags + + + #if DEBUG_IO + _mbgddmsg_3( MBG_DBG_INIT_DEV, "pcps_read_asic: cmd: 0x%02X (0x%08X), cnt: %u", + cmd, _cpu_to_mbg32( cmd ), count ); + #endif + + _pcps_disb_local_irq_save(); + mbg_get_pc_cycles( &pddev->acc_cycles ); + // write the command byte + _mbg_outp32( pddev, _pcps_ddev_io_base_mapped( pddev, 0 ) + + offsetof( PCI_ASIC, pci_data ), cmd ); + _pcps_local_irq_restore(); + + data_port = _pcps_ddev_io_base_mapped( pddev, 0 ) + + offsetof( PCI_ASIC, addon_data ); + dt_quot = count / 4; + dt_rem = count % 4; + + // wait until BUSY flag goes low or timeout + if ( pcps_wait_busy( pddev ) < 0 ) + return MBG_ERR_TIMEOUT; + + + // no timeout: read bytes from the board's FIFO + + // first read full 32 bit words + for ( i = 0; i < dt_quot; i++ ) + { + ar.ul = _mbg_inp32_to_cpu( pddev, data_port ); + #if DEBUG_IO + _mbgddmsg_1( MBG_DBG_INIT_DEV, "pcps_read_asic: %08X", ar.ul ); + #endif + _pcps_put_unaligned( ar.ul, (uint32_t FAR *) p ); + p += sizeof( ar.ul ); + data_port += sizeof( ar.ul ); + } + + // then read the remaining bytes, if required + if ( dt_rem ) + { + ar.ul = _mbg_inp32_to_cpu( pddev, data_port ); + + for ( i = 0; i < dt_rem; i++ ) + { + #if DEBUG_IO + _mbgddmsg_1( MBG_DBG_INIT_DEV, "pcps_read_asic: %02X", ar.b[i] ); + #endif + + *p++ = ar.b[i]; + } + } + + return MBG_SUCCESS; + +} // pcps_read_asic + +#endif /* _PCPS_USE_PCI */ + + + +#if _PCPS_USE_USB + +// The function below must be used to access a clock +// connected via USB bus. + +static /*HDR*/ /* type: PCPS_READ_FNC */ +short pcps_read_usb( PCPS_DDEV *pddev, uint8_t cmd, + uint8_t FAR *buffer, uint8_t count ) +{ + int actual_count = 0; + short rc; + + mbg_get_pc_cycles( &pddev->acc_cycles ); + + rc = _pcps_usb_write_var( pddev, &cmd ); + + if ( ( rc == MBG_SUCCESS ) && ( count && buffer ) ) + { + #if defined( MBG_TGT_WIN32_PNP ) + int temp_fn1 = frame_number_1; + int temp_fn2 = frame_number_2; + LARGE_INTEGER UsbPreCount = Count1; + LARGE_INTEGER UsbPostCount = Count2; + #endif + + rc = _pcps_usb_read( pddev, buffer, count ); + + #if defined( MBG_TGT_WIN32_PNP ) + if ( cmd == PCPS_GIVE_HR_TIME && rc == PCPS_SUCCESS ) + { + ULONGLONG usb_latency_cycles; + ULONGLONG cycles_diff; + ULONGLONG time_diff; + ULONGLONG frame_length_cycles; + int FrameNumberDiff; + + if ( pddev->usb_20_mode ) + { + // USB 2.0 microframe timing. + // Just add an offset to compensate constant latency. + // This value has been determined experimentally on different hardware platforms + usb_latency_cycles = ( (ULONGLONG) PerfFreq.QuadPart ) / 20000UL; // represents 50 us + } + else + { + // USB 1.1 mode with millisecond timing. + // Compensate latency to millisecond frame boundaries. + + if ( (temp_fn2 - temp_fn1) < 0 ) + FrameNumberDiff = 2; + else + FrameNumberDiff = temp_fn2 - temp_fn1; + + cycles_diff = (ULONGLONG) ( UsbPostCount.QuadPart - UsbPreCount.QuadPart ); + frame_length_cycles = (ULONGLONG) ( (ULONGLONG) PerfFreq.QuadPart ) / 1000UL; + + if ( ( temp_fn1 == 0 ) && ( temp_fn2 == 0 ) ) + { + if ( cycles_diff > frame_length_cycles ) + usb_latency_cycles = cycles_diff - frame_length_cycles; + else + usb_latency_cycles = frame_length_cycles - cycles_diff; + } + else + usb_latency_cycles = cycles_diff - ( ( FrameNumberDiff - 1 ) * frame_length_cycles ); + + #if DBG + swprintf( pddev->wcs_msg, L"FD %d CD %I64u l %I64u fl %I64u", FrameNumberDiff, cycles_diff, usb_latency_cycles, frame_length_cycles ); + _dbg_evt_msg( GlbDriverObject, pddev->wcs_msg ); + #endif + } + + pddev->acc_cycles += usb_latency_cycles; + } + #endif + } + + return rc; + +} // pcps_read_usb + +#endif + + + +/*-------------------------------------------------------------- + * Name: pcps_write() + * + * Purpose: Write data to the radio clock. + * + * Input: pddev pointer to the device information + * cmd the address of buffer holding the + * date/time/status information + * read_fnc function to access the board + * + * Output: -- + * + * Ret value: MBG_SUCCESS no error + * MBG_ERR_TIMEOUT board is busy for too long + * MBG_ERR_NBYTES the number of parameter bytes + * did not match the number of + * data bytes expected + * MBG_ERR_STIME the date, time or status + * has been invalid + *-------------------------------------------------------------*/ + +/*HDR*/ +short pcps_write( PCPS_DDEV *pddev, uint8_t cmd, + const void FAR *buffer, uint8_t count ) +{ + short rc; + +#if _PCPS_USE_USB + if ( _pcps_ddev_is_usb( pddev ) ) + { + int actual_count = 0; // required by macro + int n = sizeof( cmd ) + count; + uint8_t *p = _pcps_kmalloc( n ); + + if ( p == NULL ) + return MBG_ERR_NO_MEM; + + p[0] = cmd; + memcpy( &p[1], buffer, count ); + + rc = _pcps_usb_write( pddev, p, n ); + + if ( rc == MBG_SUCCESS ) + { + rc = _pcps_usb_read( pddev, p, 1 ); + + if ( rc == MBG_SUCCESS ) + rc = (int8_t) p[0]; // return the rc from the board + } + + _pcps_kfree( p ); + } + else +#endif // _PCPS_USE_USB + { + const uint8_t FAR *p = (const uint8_t FAR *) buffer; + int i; + uint8_t bytes_expected; + int8_t write_rc; + + // Write the command and read one byte which will contain + // the number of data bytes that must follow. + rc = _pcps_read_var( pddev, cmd, bytes_expected ); + + #if DEBUG_IO + _mbgddmsg_4( MBG_DBG_DETAIL, "pcps_write: cmd %02X, %u bytes, expects %u, rc: %i", + cmd, count, bytes_expected, rc ); + #endif + + if ( rc < 0 ) + goto done; + + + // Check if the number of data bytes to be written is correct. + if ( bytes_expected != count ) + { + rc = MBG_ERR_NBYTES; + goto done; + } + + + // Write all bytes but the last one without reading anything. + bytes_expected--; + + for ( i = 0; i < bytes_expected; i++ ) + { + #if DEBUG_IO + _mbgddmsg_2( MBG_DBG_DETAIL, "pcps_write: byte %i: 0x%02X", i, *p ); + #endif + + rc = _pcps_write_byte( pddev, *p++ ); + + if ( rc < 0 ) + goto done; + } + + // Write the last byte and read the completion code. + #if DEBUG_IO + _mbgddmsg_2( MBG_DBG_DETAIL, "pcps_write: last byte %i: 0x%02X", i, *p ); + #endif + + rc = _pcps_read_var( pddev, *p++, write_rc ); + + // If an error code has been returned by the I/O function, + // return that code, otherwise return the completion code + // read from the board. + if ( !( rc < 0 ) ) + rc = write_rc; + } + +done: + #if DEBUG_IO + _mbgddmsg_1( MBG_DBG_DETAIL, "pcps_write: return %i", rc ); + #endif + + return rc; + +} // pcps_write + + + +/*-------------------------------------------------------------- + * Name: pcps_generic_io() + * + * Purpose: Write data to the radio clock. + * + * Input: pddev pointer to the device information + * cmd the address of buffer holding the + * date/time/status information + * read_fnc function to access the board + * + * Output: -- + * + * Ret value: MBG_SUCCESS no error + * MBG_ERR_TIMEOUT board is busy for too long + * MBG_ERR_NBYTES the number of parameter bytes + * did not match the number of + * data bytes expected + * MBG_ERR_STIME the date, time or status + * has been invalid + *-------------------------------------------------------------*/ + +/*HDR*/ +short pcps_generic_io( PCPS_DDEV *pddev, uint8_t type, + const void FAR *in_buff, uint8_t in_cnt, + void FAR *out_buff, uint8_t out_cnt ) +{ + const uint8_t FAR *p; + int i; + short rc; + uint8_t tmp_byte; + int8_t data_read[PCPS_FIFO_SIZE]; + uint8_t bytes_to_read; + + // Write the command and read one byte which will contain + // the number of data bytes that must follow. + rc = _pcps_read_var( pddev, PCPS_GENERIC_IO, tmp_byte ); + + if ( rc < 0 ) + return rc; + + + // Check if the number of data bytes to be written is correct. + if ( tmp_byte != 3 ) + return MBG_ERR_NBYTES; + + + // Write the 3 bytes which are expected: + rc = _pcps_write_byte( pddev, type ); + + if ( rc != MBG_SUCCESS ) + goto done; + + + rc = _pcps_write_byte( pddev, in_cnt ); + + if ( rc != MBG_SUCCESS ) + goto done; + + + if ( in_cnt == 0 ) + tmp_byte = out_cnt; + else + { + rc = _pcps_write_byte( pddev, out_cnt ); + + if ( rc != MBG_SUCCESS ) + goto done; + + + // Write the input parameters + p = (const uint8_t FAR *) in_buff; + tmp_byte = in_cnt - 1; + + for ( i = 0; i < tmp_byte; i++ ) + { + rc = _pcps_write_byte( pddev, *p++ ); + + if ( rc < 0 ) + goto done; + } + + tmp_byte = *p; + } + + + bytes_to_read = 2 + out_cnt; + + if ( bytes_to_read > sizeof( data_read ) ) + bytes_to_read = sizeof( data_read ); + + + // Write the last byte and read the completion code. + rc = _pcps_read( pddev, tmp_byte, data_read, bytes_to_read ); + + if ( out_cnt ) //##++ should do some more plausibility checks + if ( rc == MBG_SUCCESS ) + { + _fmemcpy( out_buff, &data_read[2], out_cnt ); + } + +done: + // If an error code has been returned by the I/O function, + // return that code, otherwise return the completion code + // read from the board. + return ( rc < 0 ) ? rc : data_read[0]; + +} // pcps_generic_io + + + +/*-------------------------------------------------------------- + * Name: pcps_read_gps_block() + * + * Purpose: Get a block of data from GPS clock device. + * This is a local function which is called + * by pcps_read_gps(). + * + * Input: pddev pointer to the device information + * data_type the code assigned to the data type + * buffer_size the size of the buffer + * block_num the number of the block to read + * block_size the size of the block to read + * + * Output: buffer filled with data + * + * Ret value: MBG_SUCCESS + * MBG_ERR_TIMEOUT + * MBG_ERR_NBYTES + *-------------------------------------------------------------*/ + +static /*HDR*/ +short pcps_read_gps_block( PCPS_DDEV *pddev, + uint8_t data_type, + void FAR *buffer, + uint16_t buffer_size, + uint8_t block_num, + uint8_t block_size ) +{ + short rc; + uint16_t n_bytes; + uint8_t size_n_bytes; + uint8_t uc; + + + /* Determine which interface buffer size is supported + and use the appropriate size specification */ + if ( _pcps_ddev_has_gps_data_16( pddev ) ) + size_n_bytes = 2; + else + { + if ( buffer_size > 255 ) + return MBG_ERR_NBYTES; // Error ... + + size_n_bytes = 1; + } + + #if DEBUG_IO + _mbgddmsg_4( MBG_DBG_DETAIL, + "pcps_read_gps_block: cmd 0x%02X, block %u (%u), size_n_bytes = %u", + data_type, block_num, block_size, size_n_bytes ); + #endif + + // Write the command, expect to read one byte. + rc = _pcps_read_var( pddev, PCPS_READ_GPS_DATA, uc ); + + if ( rc != MBG_SUCCESS ) // Error ... + return rc; + + if ( uc != 1 ) // The board doesn't expect exactly one more byte + { + if ( uc == 0 ) + { + // The board can't respond now. This may occur if a + // GPS receiver is still initializing after power-up. + #if DEBUG_IO + _mbgddmsg_0( MBG_DBG_DETAIL, "pcps_read_gps_block: board not yet initialized" ); + #endif + + return MBG_ERR_NOT_READY; + } + else + { + #if DEBUG_IO + _mbgddmsg_1( MBG_DBG_DETAIL, "pcps_read_gps_block: board expects %u bytes rather than 1", uc ); + #endif + + return MBG_ERR_NBYTES; // Error ... + } + } + + // Write the code corresponding to the type of data we + // want to read, expect to read the expected size. + n_bytes = 0; + rc = _pcps_read( pddev, data_type, &n_bytes, size_n_bytes ); + + if ( rc != MBG_SUCCESS ) // Error ... + return rc; + + #if defined( MBG_ARCH_BIG_ENDIAN ) + // Swap n_bytes regardless of whether we have actuall read 1 or 2 bytes. + // If we have read only 1 byte then the other one is 0. + n_bytes = _mbg16_to_cpu( n_bytes ); + #endif + + #if DEBUG_IO + _mbgddmsg_2( MBG_DBG_DETAIL, "pcps_read_gps_block: board expects data size %u, buffer size %u", + n_bytes, buffer_size ); + #endif + + if ( n_bytes == 0 ) + return MBG_ERR_INV_TYPE; + + if ( n_bytes != buffer_size ) // Size of data structure does not match. + return MBG_ERR_NBYTES; + + + // Write the block number and read n bytes of data. + rc = _pcps_read( pddev, block_num, buffer, block_size ); + + return rc; + +} // pcps_read_gps_block + + + +/*-------------------------------------------------------------- + * Name: pcps_read_gps() + * + * Purpose: Get a data structure from a GPS clock. + * + * Input: pddev pointer to the device information + * data_type the code assigned to the data type + * buffer_size the size of the buffer + * + * Output: buffer filled with data + * + * Ret value: MBG_SUCCESS + * MBG_ERR_TIMEOUT + * MBG_ERR_NBYTES + *-------------------------------------------------------------*/ + +/*HDR*/ +short pcps_read_gps( PCPS_DDEV *pddev, + uint8_t data_type, + void FAR *buffer, + uint16_t buffer_size ) +{ + uint8_t FAR *p = (uint8_t FAR *) buffer; + short rc = 0; + int dt_quot; + int dt_rem; + int block_num; + + + #if DEBUG_IO + _mbgddmsg_3( MBG_DBG_DETAIL, "Going to read GPS data, type: %02X, addr: %p, size: %u", + data_type, buffer, buffer_size ); + #endif + + // Split buffer size to a number of blocks of PCPS_FIFO_SIZE + // and a number of remaining bytes (less than PCPS_FIFO_SIZE). + dt_quot = buffer_size / PCPS_FIFO_SIZE; + dt_rem = buffer_size % PCPS_FIFO_SIZE; + + // Read dt_quot full blocks of data. + for ( block_num = 0; block_num < dt_quot; block_num++ ) + { + rc = pcps_read_gps_block( pddev, data_type, p, buffer_size, + (uint8_t) block_num, PCPS_FIFO_SIZE ); + + if ( rc != MBG_SUCCESS ) // Error ... + goto done; + + // Move the destination pointer to the next free byte. + p += PCPS_FIFO_SIZE; + } + + + // Read dt_rem additional bytes of data. + if ( dt_rem ) + rc = pcps_read_gps_block( pddev, data_type, p, buffer_size, + (uint8_t) block_num, (uint8_t) dt_rem ); + +done: + #if DEBUG_IO + _mbgddmsg_1( MBG_DBG_DETAIL, "Done reading GPS data, rc: %i", rc ); + #endif + + return rc; + +} // pcps_read_gps + + + +/*-------------------------------------------------------------- + * Name: pcps_write_gps() + * + * Purpose: Write a data structure to a GPS clock. + * + * Input: pddev pointer to the device information + * data_type the code assigned to the data type + * buffer the data to write + * buffer_size the size of the buffer + * read_fnc function to access the board + * + * Output: -- + * + * Ret value: MBG_SUCCESS + * MBG_ERR_TIMEOUT + * MBG_ERR_NBYTES + *-------------------------------------------------------------*/ + +/*HDR*/ +short pcps_write_gps( PCPS_DDEV *pddev, + uint8_t data_type, + const void FAR *buffer, + uint16_t buffer_size ) +{ + const uint8_t FAR *p = (const uint8_t FAR *) buffer; + short rc; + short i; + uint16_t n_bytes; + uint8_t size_n_bytes; + uint8_t uc; + + + /* Determine which interface buffer size is supported + and use the appropriate size specification */ + if ( _pcps_ddev_has_gps_data_16( pddev ) ) + size_n_bytes = 2; + else + { + if ( buffer_size > 255 ) + return MBG_ERR_NBYTES; // Error ... + + size_n_bytes = 1; + } + + #if DEBUG_IO + _mbgddmsg_1( MBG_DBG_DETAIL, "pcps_write_gps: size_n_bytes = %u", size_n_bytes ); + #endif + + // Write the command, expect to read one byte. + rc = _pcps_read_var( pddev, PCPS_WRITE_GPS_DATA, uc ); + + if ( rc != MBG_SUCCESS ) // Error ... + return rc; + + if ( uc != 1 ) // The board doesn't expect exactly one more byte + { + if ( uc == 0 ) + { + // The board can't respond now. This may occur if a + // GPS receiver is still initializing after power-up. + #if DEBUG_IO + _mbgddmsg_0( MBG_DBG_DETAIL, "pcps_write_gps: board not yet initialized" ); + #endif + + return MBG_ERR_NOT_READY; + } + else + { + #if DEBUG_IO + _mbgddmsg_1( MBG_DBG_DETAIL, "pcps_write_gps: board expects %u bytes rather than 1", uc ); + #endif + + return MBG_ERR_NBYTES; // Error ... + } + } + + // Write the code corresponding to the type of data we + // want to write, expect to read the expected size. + n_bytes = 0; + rc = _pcps_read( pddev, data_type, &n_bytes, size_n_bytes ); + + if ( rc != MBG_SUCCESS ) // Error ... + return rc; + + #if defined( MBG_ARCH_BIG_ENDIAN ) + // Swap n_bytes regardless of whether we have actuall read 1 or 2 bytes. + // If we have read only 1 byte then the other one is 0. + n_bytes = _mbg16_to_cpu( n_bytes ); + #endif + + #if DEBUG_IO + _mbgddmsg_2( MBG_DBG_DETAIL, "pcps_write_gps: board expects data size %u, buffer size %u", + n_bytes, buffer_size ); + #endif + + if ( n_bytes != buffer_size ) // The board doesn't expect the number + return MBG_ERR_NBYTES; // of bytes we were going to write. + + + // Write all bytes but the last one without reading. + buffer_size--; + + for ( i = 0; i < buffer_size; i++ ) + { + rc = _pcps_write_byte( pddev, *p++ ); + + if ( rc != MBG_SUCCESS ) // Error ... + return rc; + } + + + // Write the last byte and read the completion code. + rc = _pcps_read_var( pddev, *p, n_bytes ); + + // If an error code has been returned by read_fnc, return that + // code, otherwise return the completion code read from the board. + return rc ? rc : n_bytes; + +} // pcps_write_gps + + + +/*-------------------------------------------------------------- + * Name: pcps_get_fw_id() + * + * Purpose: This function tries to read the firmware ID + * from the board. It should be used to check + * if the board is properly installed and can + * be accessed without problems. + * + * Input: pddev pointer to the device information + * + * Output: fw_id buffer filled with ASCIIZ string + * + * Ret value: MBG_SUCCESS no error + * MBG_ERR_TIMEOUT the board is busy for too long + *-------------------------------------------------------------*/ + +/*HDR*/ +short pcps_get_fw_id( PCPS_DDEV *pddev, PCPS_ID_STR FAR fw_id ) +{ + short rc; + + + // read first part of the firmware ID + rc = _pcps_read( pddev, PCPS_GIVE_FW_ID_1, &fw_id[0], PCPS_FIFO_SIZE ); + + if ( rc != MBG_SUCCESS ) + return rc; // may be timeout + + + // read second part of the firmware ID + rc = _pcps_read( pddev, PCPS_GIVE_FW_ID_2, &fw_id[PCPS_FIFO_SIZE], PCPS_FIFO_SIZE ); + + if ( rc != MBG_SUCCESS ) + return rc; // may be timeout + + + // terminate the string with 0 + + fw_id[PCPS_ID_SIZE - 1] = 0; + + + return MBG_SUCCESS; + +} // pcps_get_fw_id + + + +/*-------------------------------------------------------------- + * Name: pcps_check_id() + * + * Purpose: Check an ASCIIZ string for a valid signature. + * + * Input: pddev pointer to the device information + * ref the reference signature + * + * Output: -- + * + * Ret value: MBG_SUCCESS no error + * MBG_ERR_FW_ID the firmware ID is not valid + *-------------------------------------------------------------*/ + +/*HDR*/ +short pcps_check_id( PCPS_DDEV *pddev, const char FAR *ref ) +{ + // check if the first characters of the string match the reference + + if ( ref ) + if ( _fstrncmp( _pcps_ddev_fw_id( pddev ), ref, _fstrlen( ref ) ) ) + return MBG_ERR_FW_ID; + + return MBG_SUCCESS; + +} // pcps_check_id + + + +/*-------------------------------------------------------------- + * Name: pcps_get_rev_num() + * + * Purpose: Get a version number from an ID string. + * + * Input: idstr the ID string + * + * Output: -- + * + * Ret value: on success: the version number in hex + * (e.g. 0x0270 for version 2.7) + * on error: 0 + *-------------------------------------------------------------*/ + +/*HDR*/ +short pcps_get_rev_num( char FAR *idstr ) +{ + int i; + int len = _fstrlen( idstr ) - 2; + char c; + + uchar rev_num_hi; + uchar rev_num_lo; + + for ( i = 0; i < len; i++ ) + { + if ( idstr[i + 1] == '.' ) + { + rev_num_hi = idstr[i] & 0x0F; + rev_num_lo = ( idstr[i + 2] & 0x0F ) << 4; + + c = idstr[i + 3]; + + if ( c >= '0' && c <= '9' ) + rev_num_lo |= c & 0x0F; + + return ( rev_num_hi << 8 ) | rev_num_lo; + } + } + + return 0; + +} // pcps_get_rev_num + + + +/*-------------------------------------------------------------- + * Name: pcps_read_sernum() + * + * Purpose: This function tries to read the clock's S/N + * from the board, if supported by the clock. + * + * Input: pddev pointer to the device information + * + * Output: pddev sernum field filled with ASCIIZ + * + * Ret value: MBG_SUCCESS no error + * other error + *-------------------------------------------------------------*/ + +/*HDR*/ +int pcps_read_sernum( PCPS_DDEV *pddev ) +{ + char *cp; + int i; + int rc = MBG_SUCCESS; + + + memset( pddev->dev.cfg.sernum, 0, sizeof( pddev->dev.cfg.sernum ) ); + + // There are different ways to read the clock's S/N. + // Check which way is supported by the clock, and + // read the S/N, + + // Read directly. This is supported by newer DCF77 clocks. + if ( _pcps_ddev_has_sernum( pddev ) ) + { + #if DEBUG_SERNUM + _mbgddmsg_0( MBG_DBG_DETAIL, "getting S/N via PCPS_GIVE_SERNUM cmd" ); + #endif + + rc = _pcps_read( pddev, PCPS_GIVE_SERNUM, pddev->dev.cfg.sernum, PCPS_FIFO_SIZE ); + + if ( rc != MBG_SUCCESS ) + { + _mbgddmsg_2( MBG_DBG_INIT_DEV, "PCPS read SERNUM %X: rc = %i", + _pcps_ddev_dev_id( pddev ), rc ); + goto fail; + } + + goto check; + } + + + // The S/N is part of the RECEIVER_INFO structure, + // so use that one, if supported. + if ( _pcps_ddev_has_receiver_info( pddev ) ) + { + static_wc RECEIVER_INFO ri; + + #if DEBUG_SERNUM + _mbgddmsg_0( MBG_DBG_DETAIL, "getting S/N from receiver info" ); + #endif + + rc = _pcps_read_gps_var( pddev, PC_GPS_RECEIVER_INFO, ri ); + + if ( rc != MBG_SUCCESS ) + { + _mbgddmsg_2( MBG_DBG_INIT_DEV, "PCPS read GPS receiver info %X: rc = %i", + _pcps_ddev_dev_id( pddev ), rc ); + goto fail; + } + + _mbg_swab_receiver_info( &ri ); + + #if DEBUG_IO + _mbgddmsg_1( MBG_DBG_DETAIL, "ri.sw_rev.code: %04X", ri.sw_rev.code ); + _mbgddmsg_1( MBG_DBG_DETAIL, "ri.model_code: %04X", ri.model_code ); + _mbgddmsg_3( MBG_DBG_DETAIL, "ri.model_name: %-*.*s", (int) sizeof( ri.model_name ), (int) sizeof( ri.model_name ), ri.model_name ); + _mbgddmsg_1( MBG_DBG_DETAIL, "ri.features: %08X", ri.features ); + #endif + + strncpy( pddev->dev.cfg.sernum, ri.sernum, + sizeof( pddev->dev.cfg.sernum ) ); + goto check; + } + + + // Older GPS clocks store the S/N in an IDENT structure + // which must be decoded to get the S/N. + if ( _pcps_ddev_has_ident( pddev ) ) + { + static_wc IDENT ident = { { 0 } }; + + #if DEBUG_SERNUM + _mbgddmsg_0( MBG_DBG_DETAIL, "getting S/N from ident" ); + #endif + + rc = _pcps_read_gps_var( pddev, PC_GPS_IDENT, ident ); + + #if !defined( MBG_TGT_LINUX ) && !defined( MBG_TGT_BSD ) + assert( sizeof( ident ) < sizeof( pddev->dev.cfg.sernum ) ); + #endif + + if ( rc != MBG_SUCCESS ) + { + _mbgddmsg_2( MBG_DBG_INIT_DEV, "PCPS read GPS ident %X: rc = %i", + _pcps_ddev_dev_id( pddev ), rc ); + goto fail; + } + + // The ident union must never be swapped due to endianess since we are + // using it only as an array of characters. + + #if DEBUG_SERNUM + for ( i = 0; i < sizeof( ident ); i += 4 ) + _mbgddmsg_5( MBG_DBG_DETAIL, "ident[%02i]: %02X %02X %02X %02X", + i, ident.c[i], ident.c[i+1], ident.c[i+2], ident.c[i+3] ); + #endif + + mbg_gps_ident_decode( _pcps_ddev_sernum( pddev ), &ident ); + goto check; + } + + // The clock doesn't support a S/N. + // Assume the rc is still set to MBG_SUCCESS. + strcpy( _pcps_ddev_sernum( pddev ), "N/A" ); + goto done; + + +check: + // Remove unprintable characters. + for ( i = 0, cp = pddev->dev.cfg.sernum; + i < sizeof( pddev->dev.cfg.sernum ); i++, cp++ ) + if ( ( *cp < 0x20 ) || ( *cp >= 0x7F ) ) + { + #if DEBUG_SERNUM + *cp = '#'; + #else + *cp = 0; + #endif + } + +#if DEBUG_SERNUM + +fail: + goto done; + +#else + // Remove trailing spaces which may unfortunately + // be returned by some devices. + for ( i = strlen( pddev->dev.cfg.sernum ); ; ) + { + if ( i == 0 ) + break; + + --i; + cp = &pddev->dev.cfg.sernum[i]; + if ( *cp > ' ' ) // not a trailing space, done + break; + + *cp = 0; + } + + if ( strlen( pddev->dev.cfg.sernum ) ) + goto done; + + +fail: + // No valid serial number has been found, though the device + // should have one. In order to distinguish from devices which + // don't even support a serial number we return a number of '?' + // rather than "N/A". + memset( pddev->dev.cfg.sernum, '?', 8 ); + pddev->dev.cfg.sernum[8] = 0; +#endif + +done: + // Make sure the S/N is terminated by 0. + pddev->dev.cfg.sernum[sizeof( pddev->dev.cfg.sernum ) - 1] = 0; + + return rc; + +} // pcps_read_sernum + + + +#if _PCPS_USE_RSRCMGR + +/*HDR*/ +int pcps_rsrc_claim( PCPS_DDEV *pddev ) +{ + ushort decode_width; + int i; + + if ( _pcps_ddev_is_pci( pddev ) ) + decode_width = PCPS_DECODE_WIDTH_PCI; + else + if ( _pcps_ddev_is_mca( pddev ) ) + decode_width = PCPS_DECODE_WIDTH_MCA; + else + decode_width = PCPS_DECODE_WIDTH_ISA; + + for ( i = 0; i < pddev->rsrc_info.num_rsrc_io; i++ ) + { + PCPS_IO_RSRC *p = &_pcps_ddev_io_rsrc( pddev, i ); + ushort rc; + + rc = _rsrc_alloc_ports( &pddev->rsrc, p->base_raw, p->num, decode_width ); //##++ + + // If the resource manager was unable to alloc the resources + // then the selected range of ports is probably in use + // by another hardware device and/or driver + if ( rc ) + { + _pcps_ddev_set_err_flags( pddev, PCPS_EF_IO_RSRC ); + return MBG_ERR_CLAIM_RSRC; + } + } + + return 0; + +} // pcps_rsrc_claim + + + +/*HDR*/ +void pcps_rsrc_release( PCPS_DDEV *pddev ) +{ + int i; + + for ( i = 0; i < N_PCPS_PORT_RSRC; i++ ) + { + PCPS_PORT_RSRC *p = &_pcps_ddev_port_rsrc( pddev, i ); + + if ( _pcps_port_rsrc_unused( p ) ) + continue; + + // clean up if clock not found + _rsrc_dealloc_ports( &pddev->rsrc.hResource[i], p->base, p->num ); + } + +} // pcps_rsrc_release + + + +#if defined( MBG_TGT_OS2 ) + +static /*HDR*/ +void pcps_rsrc_register_device( PCPS_DDEV *pddev ) +{ + #define RSRC_BASE_NAME "RADIOCLK_# Meinberg Radio Clock " + static const char rsrc_type_dcf77[] = RSRC_BASE_NAME "(DCF77)"; + static const char rsrc_type_gps[] = RSRC_BASE_NAME "(GPS)"; + static const char rsrc_type_irig[] = RSRC_BASE_NAME "(IRIG)"; + + uchar bus_type; + ushort rc; + const char *cp; + + #if _PCPS_USE_USB + #error USB not supported for this target environment! + #endif + + if ( _pcps_ddev_is_pci( pddev ) ) + bus_type = RSRC_BUS_PCI; + else + if ( _pcps_ddev_is_mca( pddev ) ) + bus_type = RSRC_BUS_MCA; + else + bus_type = RSRC_BUS_ISA; + + if ( _pcps_ddev_is_irig_rx( pddev ) ) + cp = rsrc_type_irig; + else + if ( _pcps_ddev_is_gps( pddev ) ) + cp = rsrc_type_gps; + else + cp = rsrc_type_dcf77; + + rc = rsrc_register_device( &pddev->hDev, &pddev->rsrc, n_ddevs - 1, cp, bus_type ); + +} // pcps_rsrc_register_device + +#endif // defined( MBG_TGT_OS2 ) + +#endif // _PCPS_USE_RSRCMGR + + + +#if _PCPS_USE_MCA + +/*-------------------------------------------------------------- + * PS31 only: + * + * The scheme below shows the way the bits of the POS 103 + * configuration byte are mapped to the PS31's programmable + * address decoder: + * + * MSB LSB + * | || | + * 0bbbbbb1000bxxxx <-- 16 bit port base address (binary) + * |||||| | + * \\\\\\ | b: configurable bit + * \\\\\\ | x: don't care bit + * ||||||| + * 1bbbbbbb <-- 8 bit configuration byte (POS 103) + * | + * | + * decoder enable bit, always 1 if adapter enabled + * + *-------------------------------------------------------------*/ + +/*-------------------------------------------------------------- + * Convert the code read from PS/2 POS to the port base address. + *-------------------------------------------------------------*/ + +/*HDR*/ +ushort pcps_port_from_pos( ushort pos ) +{ + ushort us = ( ( pos & 0x007E ) << 8 ) | 0x0100; + + if ( pos & 0x0001 ) + us |= 0x0010; + + return us; + +} // pcps_port_from_pos + + + +/*-------------------------------------------------------------- + * Convert the port base address to a PS/2 POS code. + *-------------------------------------------------------------*/ + +/*HDR*/ +uchar pcps_pos_from_port( ushort port ) +{ + uchar uc; + + + uc = *( ( (uchar *) (&port) ) + 1 ) & 0x7E; + + if ( port & 0x0010 ) + uc |= 1; + + return uc; + +} // pcps_pos_from_port + + + +static /*HDR*/ +void pcps_detect_mca_clocks( PCPS_DDEV_ALLOC_FNC alloc_fnc, void *alloc_arg ) +{ + short rc; + ushort type_idx; + + rc = mca_fnc_init(); + + if ( rc != MCA_SUCCESS ) + return; + + + // MCA is installed, now try to find a MCA clock with + // known ID. + for ( type_idx = 0; type_idx < N_PCPS_DEV_TYPE; type_idx++ ) + { + static_wc MCA_POS_DATA pos_data; + PCPS_DDEV *pddev; + PCPS_DEV_TYPE *p = &pcps_dev_type[type_idx]; + + static_wc uchar slot_num; // the slot in which the board is installed + + + if ( !( p->bus_flags & PCPS_BUS_MCA ) ) + continue; + + + rc = mca_find_adapter( p->dev_id, &slot_num, &pos_data ); + + if ( rc != MCA_SUCCESS ) + continue; + + + // New device found, try to add to list. + pddev = alloc_fnc( alloc_arg ); + + if ( pddev ) // Setup only if successful. + { + pddev->dev.type = *p; + pcps_add_rsrc_io( pddev, pcps_port_from_pos( pos_data.pos_103 ), + PCPS_NUM_PORTS_MCA ); + + //##++ Should try to read the interrupt line assigned to the clock. + // The standard functions, however, don't use any interrupt. + + pcps_start_device( pddev, 0, slot_num ); + } + } + + mca_fnc_deinit(); + +} // pcps_detect_mca_clocks + +#endif /* _PCPS_USE_MCA */ + + + +// The function below takes a bus flag and device ID to search +// the table of known devices for a device which matches the +// given criteria. + +/*HDR*/ +PCPS_DEV_TYPE *pcps_get_dev_type( int bus_mask, ushort dev_id ) +{ + int i; + + for ( i = 0; i < N_PCPS_DEV_TYPE; i++ ) + { + PCPS_DEV_TYPE *p = &pcps_dev_type[i]; + + if ( !( p->bus_flags & bus_mask ) ) + continue; + + if ( p->dev_id == dev_id ) + return p; + } + + return NULL; + +} // pcps_get_dev_type + + + +/*HDR*/ +PCPS_DDEV *pcps_alloc_ddev( void ) +{ + PCPS_DDEV *pddev; + + #if !_PCPS_STATIC_DEV_LIST + pddev = _pcps_kmalloc( sizeof( *pddev ) ); + #else + if ( n_ddevs >= PCPS_MAX_DDEVS ) + { + _mbgddmsg_0( MBG_DBG_INIT_DEV, + "Unable to add new device: max count reached" ); + + return NULL; + } + + pddev = &pcps_ddev[n_ddevs]; + n_ddevs++; + #endif + + if ( pddev ) + memset( pddev, 0, sizeof( *pddev ) ); + + return pddev; + +} // pcps_alloc_ddev + + + +/*HDR*/ +void pcps_free_ddev( PCPS_DDEV *pddev ) +{ + #if !_PCPS_STATIC_DEV_LIST + if ( pddev ) + _pcps_kfree( pddev ); + #else + memset( pddev, 0, sizeof( *pddev ) ); + + if ( n_ddevs ) + n_ddevs--; + #endif + +} // pcps_free_ddev + + + +static /*HDR*/ +void rsrc_port_to_cfg_port( PCPS_PORT_RSRC *p_port_rsrc, const PCPS_IO_RSRC *p_io_rsrc ) +{ + p_port_rsrc->base = (PCPS_PORT_ADDR) p_io_rsrc->base_raw; + p_port_rsrc->num = p_io_rsrc->num; + +} // rsrc_port_to_cfg_port + + + +/*HDR*/ +int pcps_add_rsrc_io( PCPS_DDEV *pddev, ulong base, ulong num ) +{ + PCPS_RSRC_INFO *prsrci = &pddev->rsrc_info; + + if ( prsrci->num_rsrc_io < N_PCPS_PORT_RSRC ) + { + PCPS_IO_RSRC *p = &prsrci->port[prsrci->num_rsrc_io]; + + p->base_mapped = (PCPS_IO_ADDR_MAPPED) _pcps_ioremap( base, num ); + p->base_raw = (PCPS_IO_ADDR_RAW) base; + p->num = (uint16_t) num; + + prsrci->num_rsrc_io++; + + _mbgddmsg_3( MBG_DBG_INIT_DEV, "Adding I/O rsrc #%i: %03lX(%lu)", + prsrci->num_rsrc_io, (ulong) base, (ulong) num ); + + return MBG_SUCCESS; + } + + return MBG_ERR_GENERIC; + +} // pcps_add_rsrc_io + + + +/*HDR*/ +int pcps_add_rsrc_mem( PCPS_DDEV *pddev, MBG_MEM_ADDR start, ulong len ) +{ + PCPS_RSRC_INFO *prsrci = &pddev->rsrc_info; + + if ( prsrci->num_rsrc_mem < N_PCPS_MEM_RSRC ) + { + PCPS_MEM_RSRC *p = &prsrci->mem[prsrci->num_rsrc_mem]; + p->start = start; + p->len = len; + prsrci->num_rsrc_mem++; + + #if defined( MBG_TGT_UNIX ) + _mbgddmsg_3( MBG_DBG_INIT_DEV, "Adding mem rsrc #%i: %08llX(%lu)", + prsrci->num_rsrc_mem, (unsigned long long) start, len ); + #else + _mbgddmsg_3( MBG_DBG_INIT_DEV, "Adding mem rsrc #%i: %08lX(%lu)", + prsrci->num_rsrc_mem, (unsigned long) start, len ); + #endif + + return MBG_SUCCESS; + } + + return MBG_ERR_GENERIC; + +} // pcps_add_rsrc_mem + + + +/*HDR*/ +int pcps_add_rsrc_irq( PCPS_DDEV *pddev, int16_t irq_num ) +{ + PCPS_RSRC_INFO *prsrci = &pddev->rsrc_info; + + if ( prsrci->num_rsrc_irq == 0 ) + { + prsrci->irq.num = irq_num; + prsrci->num_rsrc_irq++; + + _mbgddmsg_2( MBG_DBG_INIT_DEV, "Adding IRQ rsrc #%i: %i", + prsrci->num_rsrc_irq, irq_num ); + + return MBG_SUCCESS; + } + + return MBG_ERR_GENERIC; + +} // pcps_add_rsrc_irq + + + +#if _PCPS_USE_PNP + +/*HDR*/ +int pcps_init_ddev( PCPS_DDEV *pddev, int bus_flags, ushort dev_id ) +{ + // First check if we really support the device to be added. + PCPS_DEV_TYPE *pdt = pcps_get_dev_type( bus_flags, dev_id ); + + if ( pdt == NULL ) + { + _mbgddmsg_1( MBG_DBG_INIT_DEV, "PCPS add PNP device %X: unknown type", + dev_id ); + + return MBG_ERR_DEV_NOT_SUPP; + } + + + pddev->dev.type = *pdt; + + _mbgddmsg_2( MBG_DBG_INIT_DEV, "PCPS add PNP device %X: found %s", + dev_id, pdt->name ); + + return MBG_SUCCESS; + +} // pcps_init_ddev + +#endif // _PCPS_USE_PNP + + + +#if defined( DEBUG ) +static /*HDR*/ +const char *get_feature_name( PCPS_FEATURES flag ) +{ + static const char *pcps_feature_names[N_PCPS_FEATURE] = PCPS_FEATURE_NAMES; + + int i; + + for ( i = 0; i < N_PCPS_FEATURE; i++ ) + if ( ( 1UL << i ) == flag ) + return pcps_feature_names[i]; + + return "unknown"; + +} // get_feature_name + +#endif + + + +static /*HDR*/ +void check_feature( PCPS_DDEV *pddev, ushort req_rev_num, + PCPS_FEATURES flag ) +{ + int supported = _pcps_ddev_fw_rev_num( pddev ) >= req_rev_num; + + if ( supported ) + pddev->dev.cfg.features |= flag; + + #if defined( DEBUG ) + _mbgddmsg_5( MBG_DBG_INIT_DEV, "%s v%03X: feature 0x%08lX (%s) %ssupported", + _pcps_ddev_type_name( pddev ), + _pcps_ddev_fw_rev_num( pddev ), + (ulong) flag, get_feature_name( flag ), + supported ? "" : "not " ); + #endif + +} // check_feature + + + +static /*HDR*/ +void check_ri_feature( PCPS_DDEV *pddev, const RECEIVER_INFO *p_ri, + RI_FEATURES ri_flag, PCPS_FEATURES flag ) +{ + int supported = ( p_ri->features & ri_flag ) != 0; + + if ( supported ) + pddev->dev.cfg.features |= flag; + + #if defined( DEBUG ) + _mbgddmsg_5( MBG_DBG_INIT_DEV, "%s v%03X: feature 0x%08lX (%s) %ssupported according to RECEIVER_INFO", + _pcps_ddev_type_name( pddev ), + _pcps_ddev_fw_rev_num( pddev ), + (ulong) flag, get_feature_name( flag ), + supported ? "" : "not " ); + #endif + +} // check_ri_feature + + + +/*HDR*/ +int pcps_start_device( PCPS_DDEV *pddev, + PCPS_BUS_NUM bus_num, + PCPS_SLOT_NUM dev_fnc_num ) +{ + ushort port_rsrc_len[N_PCPS_PORT_RSRC] = { 0 }; + int port_ranges_required = 0; + ushort status_port_offs = 0; + int i; + int rc; + + _mbgddmsg_1( MBG_DBG_INIT_DEV, "PCPS start device %X", + _pcps_ddev_dev_id( pddev ) ); + + pddev->read = pcps_read_null; + pddev->dev.cfg.bus_num = bus_num; + pddev->dev.cfg.slot_num = dev_fnc_num; + + if ( _pcps_ddev_chk_err_flags( pddev, PCPS_EF_IO_INIT | PCPS_EF_IO_ENB ) ) + { + _mbgddmsg_1( MBG_DBG_INIT_DEV, "PCPS start device %X: failing due to error flags.", + _pcps_ddev_dev_id( pddev ) ); + goto fail; + } + + _pcps_mutex_init( &pddev->dev_mutex ); + _pcps_spin_lock_init( &pddev->mm_lock ); + _pcps_spin_lock_init( &pddev->irq_lock ); + + switch ( _pcps_ddev_bus_flags( pddev ) ) + { + #if _PCPS_USE_USB + case PCPS_BUS_USB: + // No direct port I/O required. + pddev->read = pcps_read_usb; + + // In case of an USB device, do some additional + // USB initializiation + #if defined( MBG_TGT_WIN32_PNP ) + rc = pcps_usb_init( pddev ); + #elif defined( MBG_TGT_LINUX ) + rc = usb_set_interface( pddev->udev, 0, 0 ); + + if ( rc ) + _mbgddmsg_1( MBG_DBG_INIT_DEV, "usb_set_interface returned %d", rc ); + else + { + struct usb_host_interface *iface_desc = pddev->intf->cur_altsetting; + int i; + + pddev->n_usb_ep = 0; + + for ( i = 0; i < iface_desc->desc.bNumEndpoints; i++ ) + { + struct usb_endpoint_descriptor *endpoint = &iface_desc->endpoint[i].desc; + PCPS_USB_EP *pep = &pddev->ep[i]; + pep->addr = endpoint->bEndpointAddress; + pep->max_packet_size = le16_to_cpu( endpoint->wMaxPacketSize ); + _mbgddmsg_3( MBG_DBG_INIT_DEV, "endpoint %d: addr %02X, size: %d", + i, pep->addr, pep->max_packet_size ); + pddev->n_usb_ep++; + } + } + #else + #error USB endpoint configuration can not be determined for this target. + #endif + + if ( rc == MBG_SUCCESS ) + if ( pddev->n_usb_ep < MBGUSB_MIN_ENDPOINTS_REQUIRED ) + { + #if defined( MBG_TGT_LINUX ) + printk( KERN_INFO "device supports only %d endpoints while %d are required\n", + pddev->n_usb_ep, MBGUSB_MIN_ENDPOINTS_REQUIRED ); + #elif defined( MBG_TGT_WIN32_PNP ) + swprintf( pddev->wcs_msg, L"device supports only %d endpoints while %d are required", + pddev->n_usb_ep, MBGUSB_MIN_ENDPOINTS_REQUIRED ); + _evt_msg( GlbDriverObject, pddev->wcs_msg ); + #else + //##++ + #endif + + rc = MBG_ERR_GENERIC; + } + #if defined( MBG_TGT_WIN32_PNP ) + else + { + LARGE_INTEGER Count1, Count2, PerfFreq; + PCPS_HR_TIME t; + + uint8_t irq_cmd = PCPS_IRQ_1_SEC; + rc = _pcps_usb_write_var( pddev, &irq_cmd ); + + // get access time to determine latency compensation mode + Count1 = KeQueryPerformanceCounter( &PerfFreq ); + rc = _pcps_read_var( pddev, PCPS_GIVE_HR_TIME, t ); + Count2 = KeQueryPerformanceCounter( NULL ); + + // If access time is below 1 ms then there might be a V2.0 Hub between device and host. + // In this case, you can expect that there is the 125 us microframe timing of USB 2.0. + if ( ( (ULONGLONG) ( Count2.QuadPart - Count1.QuadPart ) ) < ( (ULONGLONG) PerfFreq.QuadPart ) / 1000UL ) + pddev->usb_20_mode = 1; + else + pddev->usb_20_mode = 0; + } + #endif + + if ( rc != MBG_SUCCESS ) + { + _pcps_ddev_set_err_flags( pddev, PCPS_EF_IO_INIT ); + goto fail; + } + break; + #endif + + case PCPS_BUS_PCI_PEX8311: + port_rsrc_len[0] = 0; + port_rsrc_len[1] = sizeof( PCI_ASIC ); // same as ASIC + port_ranges_required = 2; // will be swapped later + status_port_offs = offsetof( PCI_ASIC, status_port ); // same as ASIC + pddev->read = pcps_read_asic; + break; + + case PCPS_BUS_PCI_ASIC: + case PCPS_BUS_PCI_MBGPEX: + port_rsrc_len[0] = sizeof( PCI_ASIC ); + port_ranges_required = 1; + status_port_offs = offsetof( PCI_ASIC, status_port ); + pddev->read = pcps_read_asic; + break; + + case PCPS_BUS_PCI_S5920: + port_rsrc_len[0] = AMCC_OP_REG_RANGE_S5920; + port_rsrc_len[1] = 16; //##++ + port_ranges_required = 2; + status_port_offs = AMCC_OP_REG_IMB4 + 3; + pddev->read = pcps_read_amcc_s5920; + break; + + case PCPS_BUS_PCI_S5933: + port_rsrc_len[0] = AMCC_OP_REG_RANGE_S5933; + port_ranges_required = 1; + status_port_offs = AMCC_OP_REG_IMB4 + 3; + pddev->read = pcps_read_amcc_s5933; + break; + + case PCPS_BUS_MCA: + case PCPS_BUS_ISA: + // resource lengths have always been set + port_ranges_required = 1; + status_port_offs = 1; + pddev->read = pcps_read_std; + break; + + } // switch ( _pcps_ddev_bus_flags( pddev ) ) + + + // check if all required resources have been assigned + if ( pddev->rsrc_info.num_rsrc_io < port_ranges_required ) + { + _mbgddmsg_3( MBG_DBG_INIT_DEV, "PCPS start device %X fails: port ranges (%u) less than required (%u)", + _pcps_ddev_dev_id( pddev ), pddev->rsrc_info.num_rsrc_io, port_ranges_required ); + _pcps_ddev_set_err_flags( pddev, PCPS_EF_IO_INIT ); + goto fail; + } + + if ( _pcps_ddev_is_pci_mbgpex( pddev ) ) + { + pddev->irq_enb_disb_port = _pcps_ddev_io_base_mapped( pddev, 0 ) + + offsetof( PCI_ASIC, control_status ); + pddev->irq_flag_port = pddev->irq_enb_disb_port; + pddev->irq_flag_mask = PCI_ASIC_PCI_IRQF; + + pddev->irq_ack_port = pddev->irq_enb_disb_port; + pddev->irq_ack_mask = PCI_ASIC_PCI_IRQF; + goto chip_setup_done; + } + + + // setup additional properties depending on the + // type of bus interface chip + if ( _pcps_ddev_is_pci_pex8311( pddev ) ) + { + // I/O and memory ranges must be swapped for the + // low level functions because otherwise the first + // range addressed the chip configuration registers + // while the second range addressed data registers. + + PCPS_MEM_RSRC tmp_mem_rsrc; + PCPS_IO_RSRC tmp_io_rsrc; + + tmp_mem_rsrc = pddev->rsrc_info.mem[0]; + pddev->rsrc_info.mem[0] = pddev->rsrc_info.mem[1]; + pddev->rsrc_info.mem[1] = tmp_mem_rsrc; + + #if DEBUG_IO + _mbgddmsg_4( MBG_DBG_DETAIL, "Ports before swapping: %04lX (%08lX), %04lX (%08lX)", + (ulong) pddev->rsrc_info.port[0].base_raw, (ulong) pddev->rsrc_info.port[0].base_mapped, + (ulong) pddev->rsrc_info.port[1].base_raw, (ulong) pddev->rsrc_info.port[1].base_mapped ); + #endif + + tmp_io_rsrc = pddev->rsrc_info.port[0]; + pddev->rsrc_info.port[0] = pddev->rsrc_info.port[1]; + pddev->rsrc_info.port[1] = tmp_io_rsrc; + + #if DEBUG_IO + _mbgddmsg_4( MBG_DBG_DETAIL, "Ports after swapping: %04lX (%08lX), %04lX (%08lX)", + (ulong) pddev->rsrc_info.port[0].base_raw, (ulong) pddev->rsrc_info.port[0].base_mapped, + (ulong) pddev->rsrc_info.port[1].base_raw, (ulong) pddev->rsrc_info.port[1].base_mapped ); + #endif + + // Attention: the interrupt control/status register is located in + // the PLX configuration space which is addressed by a different + // port address range than the normal data ports !! + pddev->irq_enb_disb_port = _pcps_ddev_io_base_mapped( pddev, 1 ) + PLX8311_REG_INTCSR; + pddev->irq_enb_mask = PLX8311_INT_ENB; + pddev->irq_disb_mask = PLX8311_INT_ENB; + + pddev->irq_flag_port = _pcps_ddev_io_base_mapped( pddev, 1 ) + PLX8311_REG_INTCSR; + pddev->irq_flag_mask = PLX8311_INT_FLAG; + + pddev->irq_ack_port = _pcps_ddev_io_base_mapped( pddev, 0 ) + offsetof( PCI_ASIC, control_status ); + pddev->irq_ack_mask = PCI_ASIC_PCI_IRQF; + goto chip_setup_done; + } + + if ( _pcps_ddev_is_pci_asic( pddev ) ) + { + pddev->irq_enb_disb_port = _pcps_ddev_io_base_mapped( pddev, 0 ) + + offsetof( PCI_ASIC, control_status ); + pddev->irq_flag_port = pddev->irq_enb_disb_port; + pddev->irq_flag_mask = PCI_ASIC_PCI_IRQF; + + pddev->irq_ack_port = pddev->irq_enb_disb_port; + pddev->irq_ack_mask = PCI_ASIC_PCI_IRQF; + goto chip_setup_done; + } + + if ( _pcps_ddev_is_pci_amcc( pddev ) ) + { + pddev->irq_enb_disb_port = _pcps_ddev_io_base_mapped( pddev, 0 ) + + AMCC_OP_REG_INTCSR; + pddev->irq_enb_mask = AMCC_INT_ENB; + pddev->irq_disb_mask = AMCC_INT_MASK; + + pddev->irq_flag_port = pddev->irq_enb_disb_port; + pddev->irq_flag_mask = AMCC_INT_FLAG; + + pddev->irq_ack_port = pddev->irq_enb_disb_port; + pddev->irq_ack_mask = AMCC_INT_ACK; + goto chip_setup_done; + } + +chip_setup_done: + + pddev->status_port = _pcps_ddev_io_base_mapped( pddev, 0 ) + status_port_offs; + + // Set up the resource list in pddev->dev.cfg which + // isn't real required anymore, but just informational: + + for ( i = 0; i < N_PCPS_PORT_RSRC; i++ ) + { + PCPS_IO_RSRC *prsrc; + + if ( i >= port_ranges_required ) + break; + + prsrc = &pddev->rsrc_info.port[i]; + + // if the resource len has not yet been set + // then use the default resource len + if ( prsrc->num == 0 ) + prsrc->num = port_rsrc_len[i]; + + rsrc_port_to_cfg_port( &pddev->dev.cfg.port[i], &pddev->rsrc_info.port[i] ); + } + + pddev->dev.cfg.irq_num = pddev->rsrc_info.num_rsrc_irq ? + pddev->rsrc_info.irq.num : -1; + pddev->dev.cfg.status_port = _pcps_ddev_port_base( pddev, 0 ) + status_port_offs; + + pddev->dev.cfg.timeout_clk = PCPS_TIMEOUT_CNT; + + #if DEBUG_PORTS + _mbgddmsg_3( MBG_DBG_DETAIL, "IRQ enb/disb port: %04lX, enb: %08lX, disb: %08lX", + (ulong) pddev->irq_enb_disb_port, + (ulong) pddev->irq_enb_mask, + (ulong) pddev->irq_disb_mask + ); + _mbgddmsg_2( MBG_DBG_DETAIL, "IRQ flag port: %04lX, mask: %08lX", + (ulong) pddev->irq_flag_port, + (ulong) pddev->irq_flag_mask + ); + _mbgddmsg_2( MBG_DBG_DETAIL, "IRQ ack port: %04lX, mask: %08lX", + (ulong) pddev->irq_ack_port, + (ulong) pddev->irq_ack_mask + ); + _mbgddmsg_1( MBG_DBG_DETAIL, "status port: %04lX", (ulong) pddev->status_port ); + #endif + + #if _PCPS_USE_RSRCMGR + rc = pcps_rsrc_claim( pddev ); + + if ( rc < 0 ) + { + _mbgddmsg_1( MBG_DBG_INIT_DEV, "PCPS start device %X: failed to alloc resources", + _pcps_ddev_dev_id( pddev ) ); + + goto fail_with_cleanup; + } + #endif + + // Make sure a PTP270PEX card has finished booting. + if ( _pcps_ddev_dev_id( pddev ) == PCI_DEV_PTP270PEX ) + { + MBG_SYS_TIME t1; + MBG_SYS_TIME t2; + MBG_SYS_UPTIME uptime; + int delayed = 0; + + mbg_get_sys_time( &t1 ); + + for (;;) + { + mbg_get_sys_uptime( &uptime ); + + #if !defined( DEBUG ) + if ( !delayed ) + #endif + report_uptime( &uptime ); + + if ( uptime == 0 ) + break; // assume uptime not supported + + if ( uptime >= MAX_BOOT_TIME_PTP270PEX ) + break; + + mbg_sleep_sec( 1 ); + delayed = 1; + } + + if ( delayed ) + { + long dt; + + mbg_get_sys_time( &t2 ); + + dt = mbg_delta_sys_time_ms( &t2, &t1 ); + + #if defined( MBG_TGT_LINUX ) + printk( KERN_INFO "PTP270PEX startup delay: %li.%03li s\n", + dt / 1000, ( ( dt < 0 ) ? -dt : dt ) % 1000 ); + #elif defined( MBG_TGT_BSD ) + printf( "PTP270PEX startup delay: %li.%03li s\n", + dt / 1000, ( ( dt < 0 ) ? -dt : dt ) % 1000 ); + #elif defined( MBG_TGT_WIN32 ) + swprintf( pddev->wcs_msg, L"PTP270PEX startup delay: %li.%03li s", + dt / 1000, ( ( dt < 0 ) ? -dt : dt ) % 1000 ); + _evt_msg( GlbDriverObject, pddev->wcs_msg ); + #endif + } + } + + + // try to read EPROM ID + rc = pcps_get_fw_id( pddev, pddev->dev.cfg.fw_id ); + + if ( rc < 0 ) + { + if ( _pcps_ddev_is_isa( pddev ) ) + { + // ISA devices are detected by trying to read a firmware ID via + // a given port, so if the firmware ID could not be read then this + // just means there is no device using the given port address. + #if defined( MBG_TGT_WIN32 ) + swprintf( pddev->wcs_msg, L"No ISA card found at port %03lXh.", + (ulong) _pcps_ddev_port_base( pddev, 0 ) ); + _evt_msg( GlbDriverObject, pddev->wcs_msg ); + #else + _mbgddmsg_1( MBG_DBG_INIT_DEV, "No ISA card found at port %03lXh.", + (ulong) _pcps_ddev_port_base( pddev, 0 ) ); + #endif + } + else + { + // Non-ISA devices are detected by some other means, so if the firmware + // ID could not be read this is a serious error. + #if defined( MBG_TGT_WIN32 ) //##+++ debug or not debug ... ;-) + _evt_msg( GlbDriverObject, L"StartDevice: failed to read firmware ID" ); + #else + _mbgddmsg_1( MBG_DBG_INIT_DEV, "PCPS start device %X: failed to read firmware ID", + _pcps_ddev_dev_id( pddev ) ); + #endif + } + + _pcps_ddev_set_err_flags( pddev, PCPS_EF_TIMEOUT ); + goto fail_with_cleanup; + } + + if ( _pcps_ddev_bus_flags( pddev ) == PCPS_BUS_ISA ) + { + ushort dev_type; + + // Still need to find out which type of ISA clock we have found. + // Check EPROM ID to find out which kind of clock is installed. + if ( pcps_check_id( pddev, fw_id_ref_gps ) == MBG_SUCCESS ) + dev_type = PCPS_TYPE_GPS167PC; + else + { + if ( pcps_check_id( pddev, fw_id_ref_pcps ) == MBG_SUCCESS ) + { + // Device is a PC31, or a PC32 if it has signature code. + // If no support for MCA has been compiled in, it may even + // be a PS31 which is software compatible with a PC31. + dev_type = + ( _mbg_inp16_to_cpu( pddev, _pcps_ddev_io_base_mapped( pddev, 0 ) + 2 ) + == pcps_dev_type[PCPS_TYPE_PC32].dev_id ) ? + PCPS_TYPE_PC32 : PCPS_TYPE_PC31; + } + else + { + _pcps_ddev_set_err_flags( pddev, PCPS_EF_INV_EPROM_ID ); + goto fail_with_cleanup; + } + } + + pddev->dev.type = pcps_dev_type[dev_type]; + } + + #if defined( MBG_TGT_OS2 ) + pcps_rsrc_register_device( pddev ); + #endif + + // Extract the firmware revision number from the ID string. + pddev->dev.cfg.fw_rev_num = pcps_get_rev_num( _pcps_ddev_fw_id( pddev ) ); + + // If the device has an ASIC or EPLD read the ASIC version number + if ( _pcps_ddev_has_asic_version( pddev ) ) + { + pddev->raw_asic_version = _mbg_inp32_to_cpu( pddev, _pcps_ddev_io_base_mapped( pddev, 0 ) + + offsetof( PCI_ASIC, raw_version ) ); + + _mbg_swab_asic_version( &pddev->raw_asic_version ); + + pddev->asic_version = _convert_asic_version_number( pddev->raw_asic_version ); + } + + // Setup some feature flags which depend on the device type + // and firmware version. + switch( _pcps_ddev_type_num( pddev ) ) + { + case PCPS_TYPE_PC31: + case PCPS_TYPE_PS31_OLD: + case PCPS_TYPE_PS31: + pddev->dev.cfg.features = PCPS_FEAT_PC31PS31; + check_feature( pddev, REV_CAN_SET_TIME_PC31PS31, PCPS_CAN_SET_TIME ); + check_feature( pddev, REV_HAS_SERIAL_PC31PS31, PCPS_HAS_SERIAL ); + check_feature( pddev, REV_HAS_SYNC_TIME_PC31PS31, PCPS_HAS_SYNC_TIME ); + check_feature( pddev, REV_HAS_UTC_OFFS_PC31PS31, PCPS_HAS_UTC_OFFS ); + break; + + case PCPS_TYPE_PC32: + pddev->dev.cfg.features = PCPS_FEAT_PC32; + break; + + case PCPS_TYPE_PCI32: + pddev->dev.cfg.features = PCPS_FEAT_PCI32; + break; + + case PCPS_TYPE_GPS167PC: + pddev->dev.cfg.features = PCPS_FEAT_GPS167PC; + check_feature( pddev, REV_HAS_HR_TIME_GPS167PC, PCPS_HAS_HR_TIME ); + check_feature( pddev, REV_HAS_CABLE_LEN_GPS167PC, PCPS_HAS_CABLE_LEN ); + break; + + case PCPS_TYPE_GPS167PCI: + pddev->dev.cfg.features = PCPS_FEAT_GPS167PCI; + check_feature( pddev, REV_HAS_CABLE_LEN_GPS167PCI, PCPS_HAS_CABLE_LEN ); + check_feature( pddev, REV_CAN_CLR_UCAP_BUFF_GPS167PCI, PCPS_CAN_CLR_UCAP_BUFF ); + check_feature( pddev, REV_HAS_UCAP_GPS167PCI, PCPS_HAS_UCAP ); + break; + + case PCPS_TYPE_PCI509: + pddev->dev.cfg.features = PCPS_FEAT_PCI509; + break; + + case PCPS_TYPE_GPS168PCI: + pddev->dev.cfg.features = PCPS_FEAT_GPS168PCI; + check_feature( pddev, REV_CAN_CLR_UCAP_BUFF_GPS168PCI, PCPS_CAN_CLR_UCAP_BUFF ); + check_feature( pddev, REV_HAS_UCAP_GPS168PCI, PCPS_HAS_UCAP ); + break; + + case PCPS_TYPE_PCI510: + pddev->dev.cfg.features = PCPS_FEAT_PCI510; + break; + + case PCPS_TYPE_GPS169PCI: + pddev->dev.cfg.features = PCPS_FEAT_GPS169PCI; + check_feature( pddev, REV_HAS_GPS_DATA_16_GPS169PCI, PCPS_HAS_GPS_DATA_16 ); + break; + + case PCPS_TYPE_TCR510PCI: + pddev->dev.cfg.features = PCPS_FEAT_TCR510PCI; + check_feature( pddev, REV_HAS_HR_TIME_TCR510PCI, PCPS_HAS_HR_TIME ); + break; + + case PCPS_TYPE_TCR167PCI: + pddev->dev.cfg.features = PCPS_FEAT_TCR167PCI; + break; + + case PCPS_TYPE_GPS170PCI: + pddev->dev.cfg.features = PCPS_FEAT_GPS170PCI; + break; + + case PCPS_TYPE_PCI511: + pddev->dev.cfg.features = PCPS_FEAT_PCI511; + check_feature( pddev, REV_HAS_HR_TIME_PCI511, PCPS_HAS_HR_TIME ); + break; + + case PCPS_TYPE_TCR511PCI: + pddev->dev.cfg.features = PCPS_FEAT_TCR511PCI; + check_feature( pddev, REV_HAS_IRIG_CTRL_BITS_TCR511PCI, PCPS_HAS_IRIG_CTRL_BITS ); + check_feature( pddev, REV_HAS_IRIG_TIME_TCR511PCI, PCPS_HAS_IRIG_TIME ); + check_feature( pddev, REV_HAS_RAW_IRIG_DATA_TCR511PCI, PCPS_HAS_RAW_IRIG_DATA ); + break; + + case PCPS_TYPE_PEX511: + pddev->dev.cfg.features = PCPS_FEAT_PEX511; + // HR time support for the PEX511 requires both a certain ASIC + // version plus a certain firmware version. + if ( _pcps_asic_version_greater_equal( _pcps_ddev_asic_version( pddev ), + PCI_ASIC_MAJOR_PEX511, PCI_ASIC_HR_TIME_MINOR_PEX511 ) ) + check_feature( pddev, REV_HAS_HR_TIME_PEX511, PCPS_HAS_HR_TIME ); + + pcps_check_pex_irq_unsafe( pddev, REV_HAS_IRQ_FIX_MINOR_PEX511, + PCI_ASIC_MAJOR_PEX511, PCI_ASIC_FIX_IRQ_MINOR_PEX511 ); + break; + + case PCPS_TYPE_TCR511PEX: + pddev->dev.cfg.features = PCPS_FEAT_TCR511PEX; + check_feature( pddev, REV_HAS_IRIG_CTRL_BITS_TCR511PEX, PCPS_HAS_IRIG_CTRL_BITS ); + check_feature( pddev, REV_HAS_IRIG_TIME_TCR511PEX, PCPS_HAS_IRIG_TIME ); + check_feature( pddev, REV_HAS_RAW_IRIG_DATA_TCR511PEX, PCPS_HAS_RAW_IRIG_DATA ); + pcps_check_pex_irq_unsafe( pddev, REV_HAS_IRQ_FIX_MINOR_TCR511PEX, + PCI_ASIC_MAJOR_TCR511PEX, PCI_ASIC_FIX_IRQ_MINOR_TCR511PEX ); + break; + + case PCPS_TYPE_GPS170PEX: + pddev->dev.cfg.features = PCPS_FEAT_GPS170PEX; + pcps_check_pex_irq_unsafe( pddev, REV_HAS_IRQ_FIX_MINOR_GPS170PEX, + PCI_ASIC_MAJOR_GPS170PEX, PCI_ASIC_FIX_IRQ_MINOR_GPS170PEX ); + break; + + case PCPS_TYPE_USB5131: + pddev->dev.cfg.features = PCPS_FEAT_USB5131; + break; + + case PCPS_TYPE_TCR51USB: + pddev->dev.cfg.features = PCPS_FEAT_TCR51USB; + check_feature( pddev, REV_HAS_IRIG_CTRL_BITS_TCR51USB, PCPS_HAS_IRIG_CTRL_BITS ); + check_feature( pddev, REV_HAS_IRIG_TIME_TCR51USB, PCPS_HAS_IRIG_TIME ); + check_feature( pddev, REV_HAS_RAW_IRIG_DATA_TCR51USB, PCPS_HAS_RAW_IRIG_DATA ); + break; + + case PCPS_TYPE_MSF51USB: + pddev->dev.cfg.features = PCPS_FEAT_MSF51USB; + break; + + case PCPS_TYPE_PTP270PEX: + pddev->dev.cfg.features = PCPS_FEAT_PTP270PEX; + break; + + case PCPS_TYPE_FRC511PEX: + pddev->dev.cfg.features = PCPS_FEAT_FRC511PEX; + break; + + case PCPS_TYPE_TCR170PEX: + pddev->dev.cfg.features = PCPS_FEAT_TCR170PEX; + break; + + case PCPS_TYPE_WWVB51USB: + pddev->dev.cfg.features = PCPS_FEAT_WWVB51USB; + break; + + case PCPS_TYPE_GPS180PEX: + pddev->dev.cfg.features = PCPS_FEAT_GPS180PEX; + break; + + case PCPS_TYPE_TCR180PEX: + pddev->dev.cfg.features = PCPS_FEAT_TCR180PEX; + break; + + case PCPS_TYPE_DCF600USB: + pddev->dev.cfg.features = PCPS_FEAT_DCF600USB; + break; + + } // switch + + + if ( _pcps_ddev_has_receiver_info( pddev ) ) + { + // detect the presence of some optional features at run time + RECEIVER_INFO rcvr_info; + int rc; + + rc = _pcps_read_gps_var( pddev, PC_GPS_RECEIVER_INFO, rcvr_info ); + + if ( rc == MBG_SUCCESS ) + { + _mbg_swab_receiver_info( &rcvr_info ); + + _mbgddmsg_3( MBG_DBG_INIT_DEV, "%s v%03X RECEIVER_INFO features: 0x%08lX", + _pcps_ddev_type_name( pddev ), _pcps_ddev_fw_rev_num( pddev ), + (ulong) rcvr_info.features ); + + check_ri_feature( pddev, &rcvr_info, GPS_HAS_IRIG_TX, PCPS_HAS_IRIG_TX ); + check_ri_feature( pddev, &rcvr_info, GPS_HAS_IRIG_CTRL_BITS, PCPS_HAS_IRIG_CTRL_BITS ); + check_ri_feature( pddev, &rcvr_info, GPS_HAS_SYNTH, PCPS_HAS_SYNTH ); + check_ri_feature( pddev, &rcvr_info, GPS_HAS_TIME_SCALE, PCPS_HAS_TIME_SCALE ); + + // Devices which support a configurable time scale do also + // support reading/writing the GPS UTC parameters via the PC bus. + // This is not explicitely coded in the rcvr_info structure + // since the the rcvr_info structure can also be read via + // the serial port, and reading/writing the GPS UTC parameters + // via the serial port is supported by all GPS devices anyway. + check_ri_feature( pddev, &rcvr_info, GPS_HAS_TIME_SCALE, PCPS_HAS_UTC_PARM ); + + // Devices which support reading raw IRIG data via the PC interface also support + // reading the raw IRIG time. However, there is no receiver info feature flag + // since this call is not supported via the serial interface, so we use the + // GPS_HAS_RAW_IRIG_DATA flag to check both features. + check_ri_feature( pddev, &rcvr_info, GPS_HAS_RAW_IRIG_DATA, PCPS_HAS_IRIG_TIME ); + check_ri_feature( pddev, &rcvr_info, GPS_HAS_RAW_IRIG_DATA, PCPS_HAS_RAW_IRIG_DATA ); + + check_ri_feature( pddev, &rcvr_info, GPS_HAS_LAN_IP4, PCPS_HAS_LAN_INTF ); + check_ri_feature( pddev, &rcvr_info, GPS_HAS_PTP, PCPS_HAS_PTP ); + } + } + + + #if !defined( MBG_TGT_OS2 ) && !defined( MBG_TGT_BSD ) + // Function strstr may not be supported at kernel level, + // but this is not required, in most cases, either. + if ( strstr( _pcps_ddev_fw_id( pddev ), "CERN" ) != NULL ) + pddev->dev.cfg.features |= PCPS_HAS_EVENT_TIME; + #endif + + #if DEBUG_IO && defined( MBG_TGT_LINUX ) + { + PCPS_TIME t = { 0 }; + rc = _pcps_read( pddev, PCPS_GIVE_TIME, &t, sizeof( t ) ); + printk( KERN_INFO "read time, sz: %lu, returned %i\n", (ulong) sizeof( t ), rc ); + printk( KERN_INFO " sec100 %02X, sec %02X, min %02X hour %02X\n", + t.sec100, t.sec, t.min, t.hour ); + printk( KERN_INFO " mday %02X, wday %02X, month %02X year %02X\n", + t.mday, t.wday, t.month, t.year ); + printk( KERN_INFO " status %02X, sig %02X, offs_utc %02X\n", + t.status, t.signal, t.offs_utc ); + } + #endif + + if ( _pcps_ddev_has_asic_features( pddev ) ) + { + pddev->asic_features = _mbg_inp32_to_cpu( pddev, _pcps_ddev_io_base_mapped( pddev, 0 ) + + offsetof( PCI_ASIC, features ) ); + + _mbg_swab_asic_features( &pddev->asic_features ); + + #if MBG_TGT_SUPP_MEM_ACC + if ( pddev->asic_features & PCI_ASIC_HAS_MM_IO ) + pddev->dev.cfg.features |= PCPS_HAS_FAST_HR_TSTAMP; + else + if ( pddev->dev.cfg.features & PCPS_HAS_FAST_HR_TSTAMP ) + { + // The device supports memory mapped time stamps by default. + // However, this is not reflected by the ASIC features. + _mbgddmsg_0( MBG_DBG_INIT_DEV, + "Warning: ASIC features don't reflect memory mapped time stamp support." ); + } + + if ( pddev->dev.cfg.features & PCPS_HAS_FAST_HR_TSTAMP ) + if ( map_sys_virtual_address( pddev ) < 0 ) + goto fail_with_cleanup; + + #endif + } + + pcps_read_sernum( pddev ); + + _mbgddmsg_3( MBG_DBG_INIT_DEV, "%s v%03X actual features: 0x%08lX", + _pcps_ddev_type_name( pddev ), _pcps_ddev_fw_rev_num( pddev ), + (ulong) _pcps_ddev_features( pddev ) ); + + return MBG_SUCCESS; + + +fail_with_cleanup: + pcps_cleanup_device( pddev ); + +fail: + return MBG_ERR_GENERIC; + +} // pcps_start_device + + + +/*HDR*/ +void pcps_cleanup_device( PCPS_DDEV *pddev ) +{ + pddev->read = pcps_read_null; + + #if MBG_TGT_SUPP_MEM_ACC + unmap_sys_virtual_address( pddev ); + #endif + + #if _PCPS_USE_RSRCMGR + pcps_rsrc_release( pddev ); + #endif + +} // pcps_cleanup_device + + + +/*-------------------------------------------------------------- + * PCI functions + *-------------------------------------------------------------*/ + +#if _PCPS_USE_PCI_BIOS + +static /*HDR*/ +PCPS_ERR_FLAGS pcps_read_pci_rsrc( PCPS_BUS_NUM bus_num, + PCPS_SLOT_NUM dev_fnc_num, + PCPS_DDEV *pddev, + PCPS_BUS_FLAGS bus_flags ) +{ + PCPS_ERR_FLAGS err_flags = 0; + uchar irq; + short rc; + PCI_DWORD dw; + int i; + + // Clear resources + memset( &pddev->rsrc_info, 0, sizeof( pddev->rsrc_info ) ); + + for ( i = 0; i < MAX_PCPS_RSRC; i++ ) + { + rc = _mbg_pci_read_cfg_dword( bus_num, dev_fnc_num, + PCI_CS_BASE_ADDRESS_0 + i * sizeof( uint32_t ), &dw ); + + if ( rc != PCI_SUCCESS ) + break; + + if ( dw == 0 ) // base address register not used + continue; + + if ( dw & 0x0001 ) // is an I/O resource + { + if ( dw & 0xFFFF0000UL ) + { + // The PCI interface chip is not initialized. This + // should occur ONLY at the first-time installation + // at the factory. + err_flags |= PCPS_EF_IO_INIT; + goto done; + } + + pcps_add_rsrc_io( pddev, (uint16_t) ( dw & ~0x0001 ), 0 ); + } + else + pcps_add_rsrc_mem( pddev, dw, 0 ); //##++ range length? + } + + // Read the interrupt line assigned to the clock. + // The standard functions, however, don't use any + // interrupt. + rc = _mbg_pci_read_cfg_byte( bus_num, dev_fnc_num, + PCI_CS_INTERRUPT_LINE, &irq ); + + if ( rc == PCI_SUCCESS ) + pcps_add_rsrc_irq( pddev, irq ); + +done: + return err_flags; + +} // pcps_read_pci_rsrc + + + +static /*HDR*/ +PCPS_ERR_FLAGS pcps_enable_pci_dev( PCPS_BUS_NUM bus_num, + PCPS_SLOT_NUM dev_fnc_num, + int num_rsrc_mem ) +{ + PCPS_ERR_FLAGS err_flags = 0; + uint16_t pci_command; + uint16_t new_pci_command; + int rc; + + + // If the option "PNP OS installed" is set to "YES" in the + // PC's BIOS setup, then I/O access to the board may still + // be disabled, so check if the clock is enabled and enable + // access to the board, if nessessary. + rc = _mbg_pci_read_cfg_word( bus_num, dev_fnc_num, + PCI_CS_COMMAND, &pci_command ); + new_pci_command = pci_command | PCI_CMD_ENB_IO_ACC; + + if ( num_rsrc_mem ) + new_pci_command |= PCI_CMD_ENB_MEM_ACC; + + if ( new_pci_command != pci_command ) + { + rc = _mbg_pci_write_cfg_word( bus_num, dev_fnc_num, + PCI_CS_COMMAND, pci_command ); + if ( rc != PCI_SUCCESS ) + { + err_flags |= PCPS_EF_IO_ENB; + + _mbgddmsg_1( MBG_DBG_INIT_DEV, + "PCI enable device returned %d", rc ); + } + } + + return err_flags; + +} // pcps_enable_pci_dev + + + +/*HDR*/ +void pcps_setup_and_start_pci_dev( PCPS_DDEV *pddev, + PCPS_BUS_NUM bus_num, PCPS_SLOT_NUM dev_fnc_num ) +{ + PCPS_ERR_FLAGS err_flags; + + err_flags = pcps_read_pci_rsrc( bus_num, dev_fnc_num, + pddev, _pcps_ddev_bus_flags( pddev ) ); + _pcps_ddev_set_err_flags( pddev, err_flags ); + + if ( !( err_flags & PCPS_EF_IO_INIT ) ) + { + err_flags = pcps_enable_pci_dev( bus_num, dev_fnc_num, + pddev->rsrc_info.num_rsrc_mem ); + _pcps_ddev_set_err_flags( pddev, err_flags ); + } + + pcps_start_device( pddev, bus_num, dev_fnc_num ); + +} // pcps_setup_and_start_pci_dev + + + +/*HDR*/ +void pcps_detect_pci_clocks( PCPS_DDEV_ALLOC_FNC alloc_fnc, void *alloc_arg, + PCPS_DDEV_CLEANUP_FNC cleanup_fnc, + ushort vendor_id, PCPS_DEV_TYPE dev_type[], + int n_dev_types ) +{ + #if defined( MBG_TGT_QNX ) + #if defined( MBG_TGT_QNX_NTO ) + unsigned int pci_handle; // specific to QNX Neutrino + #endif + unsigned int pci_hardware_mechanism; + unsigned int pci_last_bus_number; + unsigned int pci_interface_level_version; + #elif defined( MBG_TGT_LINUX ) + // not yet supported/used + #else + uchar pci_hardware_mechanism; + uchar pci_last_bus_number; + ushort pci_interface_level_version; + #endif + ushort type_idx; + int rc; + + + #ifdef _mbg_pci_fnc_init + rc = _mbg_pci_fnc_init(); + + if ( rc != PCI_SUCCESS ) + return; + #endif + + + // See if PCI BIOS is installed on the machine. + rc = _mbg_pci_find_bios( &pci_hardware_mechanism, + &pci_interface_level_version, + &pci_last_bus_number + ); + + if ( rc == PCI_SUCCESS ) + { + // PCI BIOS is installed, now try to find a PCI clock with + // known ID (the list is terminated with a ID of 0). + for ( type_idx = 0; type_idx < n_dev_types; type_idx++ ) + { + ushort dev_idx; + PCPS_DEV_TYPE *p = &dev_type[type_idx]; + + if ( !( p->bus_flags & PCPS_BUS_PCI ) ) + continue; + + + for ( dev_idx = 0; ; dev_idx++ ) + { + PCPS_DDEV *pddev; + #if defined( MBG_TGT_QNX ) + unsigned bus_num; + unsigned dev_fnc_num; + #else + uchar bus_num; + uchar dev_fnc_num; + #endif + + rc = _mbg_pci_find_device( p->dev_id, vendor_id, + dev_idx, &bus_num, &dev_fnc_num ); + + if ( rc != PCI_SUCCESS ) + break; // go to try next device ID + + + // New device found, try to add to list. + pddev = alloc_fnc(); + + if ( pddev ) // Setup only if successful. + { + #if _PCPS_USE_PCI_PNP //##++ + // This can be used to test the PNP functions in a + // non-PNP environment. + pcps_init_ddev( pddev, PCPS_BUS_PCI, p->dev_id ); + #else + pddev->dev.type = *p; + #endif + + pcps_setup_and_start_pci_dev( pddev, bus_num, dev_fnc_num ); + + #if !_ACCEPT_UNINITD_CLOCKS + if ( pddev->dev.cfg.err_flags ) + { + _mbgddmsg_1( MBG_DBG_INIT_DEV, + "Remove PCI device: err_flags " FMT_08X "h", + (ulong) pddev->dev.cfg.err_flags ); + + if ( cleanup_fnc ) + cleanup_fnc( pddev ); + } + #endif + } + } + } + } + + #ifdef _mbg_pci_fnc_deinit + _mbg_pci_fnc_deinit(); + #endif + +} // pcps_detect_pci_clocks + +#endif // _PCPS_USE_PCI_BIOS + + + +/*-------------------------------------------------------------- + * Try to detect ISA clocks + *-------------------------------------------------------------*/ + +#if !_PCPS_USE_ISA_PNP + +/*HDR*/ +void pcps_detect_isa_clocks( PCPS_DDEV_ALLOC_FNC alloc_fnc, + PCPS_DDEV_CLEANUP_FNC cleanup_fnc, + PCPS_DDEV_REGISTER_FNC register_fnc, + int isa_ports[PCPS_MAX_ISA_CARDS], + int isa_irqs[PCPS_MAX_ISA_CARDS] ) +{ + int *p_port = isa_ports; + int *p_irq = isa_irqs; + PCPS_DDEV *pddev; + int i; + + if ( p_port == NULL ) // No list has been passed + return; // so don't try to detect ISA clocks. + + + for( i = 0; i < PCPS_MAX_ISA_CARDS; + i++, p_port++, p_irq ? ( p_irq++ ) : p_irq ) + { + int irq_num; + + if ( *p_port == 0 ) + continue; + + irq_num = p_irq ? *p_irq : -1; + + _mbgddmsg_2( MBG_DBG_INIT_DEV, + "Check ISA device at port " FMT_03X "h, irq %d", + *p_port, irq_num ); + + // Assume ISA device is available, + // but clock type is unknown, yet. + pddev = alloc_fnc(); + + if ( pddev ) // Setup only if successfull. + { + pddev->dev.type.bus_flags = PCPS_BUS_ISA; + + // Set up basic cfg for ISA devices. + pcps_add_rsrc_io( pddev, (uint16_t) *p_port, PCPS_NUM_PORTS_ISA ); + + if ( irq_num != -1 ) + pcps_add_rsrc_irq( pddev, (uint16_t) *p_irq ); + + // Init the device structure. This includes registration + // of I/O ports with the OS's resource manager (if supported), + // and reading the firmware ID. + pcps_start_device( pddev, 0, 0 ); + + // If an error has occurred, then remove the last + // device from the list and try next. + if ( pddev->dev.cfg.err_flags ) + { + _mbgddmsg_1( MBG_DBG_INIT_DEV, + "ISA device not found: err_flags " FMT_08X "h", + (ulong) pddev->dev.cfg.err_flags ); + if ( cleanup_fnc ) + cleanup_fnc( pddev ); + + continue; + } + + // Register the device with the OS, if required. + if ( register_fnc ) + register_fnc( pddev ); //##++ + } + } + +} // pcps_detect_isa_clocks + +#endif //!_PCPS_USE_ISA_PNP + + + +#if !_PCPS_USE_PNP + +/*-------------------------------------------------------------- + * Try to detect any plug-in radio clock. If a DOS TSR is + * installed, be sure it is disabled (BUSY flag set) when + * this function is called. + *-------------------------------------------------------------*/ + +/*HDR*/ +void _MBG_INIT_CODE_ATTR pcps_detect_clocks_alloc( PCPS_DDEV_ALLOC_FNC alloc_fnc, + void *alloc_arg, + PCPS_DDEV_CLEANUP_FNC cleanup_fnc, + int isa_ports[PCPS_MAX_ISA_CARDS], + int isa_irqs[PCPS_MAX_ISA_CARDS] ) +{ + #if defined( MBG_TGT_OS2 ) + rsrc_register_driver(); // register driver and init resource manager + #endif + + #if _PCPS_USE_PCI_BIOS + pcps_detect_pci_clocks( alloc_fnc, alloc_arg, cleanup_fnc, + PCI_VENDOR_MEINBERG, pcps_dev_type, N_PCPS_DEV_TYPE ); + #endif + + #if _PCPS_USE_MCA + pcps_detect_mca_clocks( alloc_fnc, alloc_arg ); + #endif + + #if !_PCPS_USE_ISA_PNP + pcps_detect_isa_clocks( alloc_fnc, cleanup_fnc, NULL, isa_ports, isa_irqs ); + #endif + +} // pcps_detect_clocks_alloc + + + +/*HDR*/ +void _MBG_INIT_CODE_ATTR pcps_detect_clocks( int isa_ports[PCPS_MAX_ISA_CARDS], + int isa_irqs[PCPS_MAX_ISA_CARDS] ) +{ + pcps_detect_clocks_alloc( pcps_alloc_ddev, NULL, pcps_free_ddev, + isa_ports, isa_irqs ); + +} // pcps_detect_clocks + +#endif // !_PCPS_USE_PNP + + diff --git a/mbglib/common/pcpsdrvr.h b/mbglib/common/pcpsdrvr.h new file mode 100755 index 0000000..5a5cfa2 --- /dev/null +++ b/mbglib/common/pcpsdrvr.h @@ -0,0 +1,1397 @@ + +/************************************************************************** + * + * $Id: pcpsdrvr.h 1.41.1.17 2011/02/04 14:44:46 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes for pcpsdrvr.c. + * + * ----------------------------------------------------------------------- + * $Log: pcpsdrvr.h $ + * Revision 1.41.1.17 2011/02/04 14:44:46 martin + * Revision 1.41.1.16 2011/02/04 10:10:18 martin + * Revision 1.41.1.15 2011/02/02 12:20:42 martin + * Revision 1.41.1.14 2011/02/01 17:12:05 martin + * Revision 1.41.1.13 2011/02/01 14:49:43 martin + * Revision 1.41.1.12 2011/02/01 12:12:19 martin + * Revision 1.41.1.11 2011/01/31 17:30:02 martin + * Modified resource storage for *BSD. + * Revision 1.41.1.10 2011/01/27 13:39:01 martin + * Revision 1.41.1.9 2011/01/27 11:04:45 martin + * Revision 1.41.1.8 2011/01/27 11:01:49 martin + * Support static device list (no malloc) and use it under FreeBSD. + * Revision 1.41.1.7 2011/01/26 16:42:07 martin + * Fixed build under FreeBSD. + * Revision 1.41.1.6 2011/01/25 09:47:27 martin + * Fixed build under FreeBSD. + * Revision 1.41.1.5 2010/11/23 11:07:57 martin + * Support memory mapped access under DOS. + * Revision 1.41.1.4 2010/11/11 09:15:39Z martin + * Added definitions to support DCF600USB. + * Revision 1.41.1.3 2010/08/20 09:35:12 martin + * Added macro _pcps_ddev_features(). + * Revision 1.41.1.2 2010/07/14 14:52:12 martin + * Revision 1.41.1.1 2010/06/30 15:01:52 martin + * Support GPS180PEX and TCR180PEX. + * Revision 1.41 2010/06/30 13:44:49 martin + * Use new preprocessor symbol MBG_ARCH_X86. + * Revision 1.40 2010/01/12 14:05:05 daniel + * Added macro to check if reading the + * raw IRIG data bits is supported. + * Revision 1.39 2009/09/29 07:24:51Z martin + * Use standard feature flag to check if fast HR time is supported. + * Revision 1.38 2009/06/19 12:13:05 martin + * Added _pcps_ddev_has_irig_time() macro. + * Revision 1.37 2009/06/09 10:13:59 daniel + * Added macros _pcps_ddev_has_lan_intf( _p ) and + * _pcps_ddev_has_ptp_cfg( _p ). + * Cleaned up the low level interface and provided a + * possibility to override the macros for special purposes. + * Set USB cyclic timeout interval to 1200 ms as default. + * Revision 1.36 2009/03/16 16:01:24Z martin + * Support reading IRIG control function bits. + * Revision 1.35 2009/03/13 09:23:36 martin + * Added _pcps_ddev_has_time_scale( _p ) and _pcps_ddev_has_utc_parm( _p ). + * Moved _pcps_get_cycles() and _pcps_get_cycles_frequency() to pcpsdev.h + * and replaced/merged them with mbg_get_pc_cycles...() functions. + * Under Linux use own inline function to read TSC on x86 architectures. + * Normally USB timeouts are short with retries in order to increase + * responsiveness. On some systems this may lead to problems, so + * optionally one long timeout can be used now by define. + * Revision 1.34 2008/12/16 14:40:47 martin + * Account for new devices PTP270PEX, FRC270PEX, TCR170PEX, and WWVB51USB. + * Added macros _pcps_ddev_is_ptp(), _pcps_ddev_is_frc(), + * and _pcps_ddev_is_wwvb(). + * Don't use pragma pack( 1 ) but use native alignment since structures + * defined here are not used across system boundaries. + * Added fields to PCPS_DDEV to store the ASIC version, and macros + * _pcps_ddev_raw_asic_version() and _pcps_ddev_asic_version(). + * Moved PC cycles types and macros here, and defined dummy _pcps_get_cycles() + * for targets which don't support this. + * Use generic spinlock/mutex macros and common device access mutex. + * Support getting cycles frequency from device driver. + * Use MBG_MEM_ADDR type for memory rather than split high/low types. + * Renamed MBG_VIRT_ADDR to MBG_MEM_ADDR. + * Additional device port variables for IRQ handling. + * Use new MBG_ARCH_I386 symbol. + * Added DEBUG_LVL_... symbols. + * Use PCPS_IRQ_STAT_INFO type. + * Account for signed irq_num. + * New PCPS_DDEV field acc_cycles. + * Added variable usb_20_mode in PCPS_DDEV. + * Added connected flag to PCPS_DDEV structure. + * Added macro _pcps_ddev_has_fast_hr_timestamp(). + * Use macros for unaligned access and endianess conversion. + * Support mapped I/O resources. + * Use some atomic_t types under Linux. + * Conditionally use Linux kthread API. + * Updated function prototypes. + * Revision 1.33 2008/02/27 10:25:30 martin + * Added support for TCR51USB and MSF51USB. + * Increased N_PCPS_MEM_RSRC to 2. + * Modified PCPS_MEM_RSRC to support memory mapped I/O. + * Added PCI_ASIC_FEATURES to PCPS_DDEV. + * Added new macros and modified some older macros to support + * cyclic reading for USB within WIN32 targets. + * New macros _pcps_ddev_is_lwr() (long wave receiver), + * _pcps_ddev_is_msf(), _pcps_ddev_has_asic_version(), + * _pcps_ddev_has_asic_features(). + * Moved Linux version-specific stuff to mbg_lx.h. + * Don't support MCA under DOS by default. + * Updated function prototypes. + * Revision 1.32 2008/01/31 09:06:03Z martin + * Don't support MCA under DOS by default. + * Revision 1.31 2007/09/26 09:28:03Z martin + * Added support for USB in general and new USB device USB5131. + * Renamed ..._USE_PCIMGR symbols to ..._USE_PCI_PNP. + * Renamed ..._USE_PCIBIOS symbols to ..._USE_PCI_BIOS. + * Added definition _PCPS_USE_PNP. + * Added new symbol _USE_ISA_PNP to exclude non-PNP stuff. + * from build if ISA devices are also handled by the PNP manager. + * Include mbgerror.h for new MBG_... codes. + * Added macro _pcps_ddev_status_busy(). + * Added kernel malloc/free macros and USB I/O macros. + * Use PCPS_DDEV as private device data. + * Use ms values for USB timeouts also under Linux. This may not be + * appropriate for older kernels. + * Limited length of some older RCS log messages. + * Revision 1.30 2007/07/25 14:22:23Z martin + * Under Linux include param.h for definition of HZ under + * kernels 2.6.21 and newer. + * Revision 1.29 2007/07/17 08:22:48 martin + * Added support for TCR511PEX and GPS170PEX. + * Revision 1.28 2007/07/16 12:58:00Z martin + * Added support for PEX511. + * Added new structures used for unified resource handling. + * Account for renamed library symbols. + * Revision 1.27 2007/03/02 09:41:05Z martin + * Use generic port I/O macros. + * Added DEVICE_OBJECT to PCPS_DDEV under Windows. + * Define init code qualifier. + * Added new _pcps_..._timeout_clk() macros. + * Preliminary support for *BSD. + * Preliminary support for USB. + * Revision 1.26 2006/07/07 09:44:23 martin + * Fixed definition of control macros for the case where + * _PCPS_USE_PCI_PNP is overridden from the command line. + * Revision 1.25 2006/06/19 15:31:09 martin + * Added support for TCR511PCI. + * Updated function prototypes. + * Revision 1.24 2006/03/10 11:01:51 martin + * Added support for PCI511. + * Revision 1.23 2005/11/03 15:50:45Z martin + * Added support for GPS170PCI. + * Revision 1.22 2005/06/02 10:35:09Z martin + * Added macro _pcps_ddev_is_pci_amcc(). + * Added macro _pcps_ddev_has_generic_io(). + * Updated function prototypes. + * Revision 1.21 2004/12/09 11:03:38Z martin + * Support configuration of on-board frequency synthesizer. + * Revision 1.20 2004/11/09 13:05:12Z martin + * Fixed syntax bug in macro _pcps_ddev_fw_rev_num(). + * New macro _pcps_ddev_has_gps_data(). + * New macro _pcps_ddev_requires_irig_workaround(). + * Revision 1.19 2004/10/14 15:01:24Z martin + * Added support for TCR167PCI. + * Revision 1.18 2004/09/06 15:11:04Z martin + * Support a GPS_DATA interface where sizes are specified + * by 16 instead of the original 8 bit quantities, thus allowing + * to transfer data blocks which exceed 255 bytes. + * Revision 1.17 2004/04/14 10:29:45Z martin + * Pack structures 1 byte aligned. + * Revision 1.16 2004/04/07 09:47:19Z martin + * New macros _pcps_ddev_has_irig() and + * _pcps_ddev_has_irig_tx(). + * Revision 1.15 2004/03/10 17:32:23Z martin + * Use CLOCKS_PER_SEC for timeout under QNX6 (Neutrino). + * Revision 1.14 2003/11/17 16:15:01 martin + * Support clock tick timeout for QNX. + * Revision 1.13 2003/07/08 15:07:32Z martin + * Simplified definitions of default preprocessor macros. + * Compile for plug'n'play for Linux kernels 2.4.0 or newer. + * Updated function prototypes. + * Revision 1.12 2003/06/19 09:56:29 MARTIN + * Renamed macro ..clr_cap_buffer to ..clr_ucap_buffer. + * New macro _pcps_ddev_has_ucap(). + * Changes due to renamed symbols. + * Updated function prototypes. + * Revision 1.11 2003/05/16 09:31:54 MARTIN + * Increased timeout loop count from 0x1000 to 0x7FFFFF. + * Rearranged inclusion of headers depending on the target. + * Added array for ISA port addresses. + * Revision 1.10 2003/04/09 16:30:24 martin + * Supports PCI510, GPS169PCI, and TCR510PCI, + * and new PCI_ASIC used by those devices. + * Renamed macro _pcps_ddev_is_irig() to _pcps_ddev_is_irig_rx(). + * New macros _pcps_ddev_has_ref_offs(), _pcps_ddev_has_opt_flags(). + * Preliminary support for PCPS_TZDL. + * Revision 1.9 2002/08/09 08:53:53 MARTIN + * New macro _pcps_ddev_can_clr_cap_buff(). + * New macro _pcps_ddev_is_irig(). + * New macro _pcps_ddev_has_signal(). + * New macro _pcps_ddev_has_mod(). + * Revision 1.8 2002/02/26 09:34:03 MARTIN + * Removed macro _pcps_read_sernum() which was replaced + * by a function pcps_read_sernum() which reads the S/N from + * any clock that supports a S/N. + * Updated function prototypes. + * Revision 1.7 2002/02/19 09:28:01 MARTIN + * Use new header mbg_tgt.h to check the target environment. + * Revision 1.6 2002/02/01 12:00:10 MARTIN + * Added new definitions for GPS168PCI. + * Renamed macro _pcps_ddev_rev_num to _pcps_ddev_fw_rev_num + * to follow naming conventions. + * Source code cleanup. + * Revision 1.5 2001/11/30 09:52:48 martin + * Added support for event_time which, however, requires + * a custom GPS firmware. + * Revision 1.4 2001/10/16 10:15:44 MARTIN + * New Macro _pcps_ddev_has_serial_hs() which determines + * whether DCF77 clock supports baud rate higher than default. + * Added some macros and comments corresponding to + * pcpsdev.h. + * Revision 1.3 2001/09/18 06:53:57 MARTIN + * Two sets of preprocessor symbols for Win9x/ME and WinNT/2k. + * New preprocessor symbol controls usage of clock ticks for timeout. + * Changed type of PCPS_RSRC.irq_num from int to ushort. + * Updated function prototypes. + * Revision 1.2 2001/03/16 14:45:34 MARTIN + * New functions and definitions to support PNP drivers. + * Revision 1.1 2001/03/01 16:29:22 MARTIN + * Initial version for the new library. + * + **************************************************************************/ + +#ifndef _PCPSDRVR_H +#define _PCPSDRVR_H + +// Setup default controls to include support for +// special features. + +#define DEBUG_LVL_SEM 7 +#define DEBUG_LVL_PORTS 10 +#define DEBUG_LVL_SERNUM 11 +#define DEBUG_LVL_IO 12 + + +#include + +#if defined( MBG_TGT_NETWARE ) + #define _DEFAULT_PCPS_USE_CLOCK_TICK 1 + #define _DEFAULT_PCPS_USE_ISA 1 + #define _DEFAULT_PCPS_USE_MCA 0 + #define _DEFAULT_PCPS_USE_PCI 1 + #define _DEFAULT_PCPS_USE_ISA_PNP 0 + #define _DEFAULT_PCPS_USE_PCI_PNP 0 + #define _DEFAULT_PCPS_USE_USB 0 + #define _DEFAULT_PCPS_USE_RSRCMGR 0 +#elif defined( MBG_TGT_OS2 ) + #define _DEFAULT_PCPS_USE_CLOCK_TICK 0 + #define _DEFAULT_PCPS_USE_ISA 1 + #define _DEFAULT_PCPS_USE_MCA 0 + #define _DEFAULT_PCPS_USE_PCI 1 + #define _DEFAULT_PCPS_USE_ISA_PNP 0 + #define _DEFAULT_PCPS_USE_PCI_PNP 0 + #define _DEFAULT_PCPS_USE_USB 0 + #define _DEFAULT_PCPS_USE_RSRCMGR 1 +#elif defined( MBG_TGT_WIN32_PNP ) + #define _DEFAULT_PCPS_USE_CLOCK_TICK 1 + #define _DEFAULT_PCPS_USE_ISA 1 + #define _DEFAULT_PCPS_USE_MCA 0 + #define _DEFAULT_PCPS_USE_PCI 1 + #define _DEFAULT_PCPS_USE_ISA_PNP 1 + #define _DEFAULT_PCPS_USE_PCI_PNP 1 + #define _DEFAULT_PCPS_USE_USB 1 + #define _DEFAULT_PCPS_USE_RSRCMGR 0 +#elif defined( MBG_TGT_WIN32 ) + #define _DEFAULT_PCPS_USE_CLOCK_TICK 1 + #define _DEFAULT_PCPS_USE_ISA 1 + #define _DEFAULT_PCPS_USE_MCA 0 + #define _DEFAULT_PCPS_USE_PCI 1 + #define _DEFAULT_PCPS_USE_ISA_PNP 0 + #define _DEFAULT_PCPS_USE_PCI_PNP 0 + #define _DEFAULT_PCPS_USE_USB 0 + #define _DEFAULT_PCPS_USE_RSRCMGR 0 +#elif defined( MBG_TGT_LINUX ) + #include + #define _DEFAULT_PCPS_USE_CLOCK_TICK 1 + #define _DEFAULT_PCPS_USE_ISA defined( MBG_ARCH_X86 ) + #define _DEFAULT_PCPS_USE_MCA 0 + #define _DEFAULT_PCPS_USE_PCI 1 + #define _DEFAULT_PCPS_USE_ISA_PNP 0 + #define _DEFAULT_PCPS_USE_PCI_PNP _DEFAULT_MBG_TGT_LINUX_USE_PCI_PNP + #define _DEFAULT_PCPS_USE_USB _DEFAULT_MBG_TGT_LINUX_USE_USB + #define _DEFAULT_PCPS_USE_RSRCMGR 1 +#elif defined( MBG_TGT_BSD ) //##++ + #define _DEFAULT_PCPS_USE_CLOCK_TICK 1 + #define _DEFAULT_PCPS_USE_ISA 1 + #define _DEFAULT_PCPS_USE_MCA 0 + #define _DEFAULT_PCPS_USE_PCI 1 + #define _DEFAULT_PCPS_USE_ISA_PNP 0 + #define _DEFAULT_PCPS_USE_PCI_PNP 1 + #define _DEFAULT_PCPS_USE_USB 0 + #define _DEFAULT_PCPS_USE_RSRCMGR 1 +#elif defined( MBG_TGT_QNX ) + #define _DEFAULT_PCPS_USE_CLOCK_TICK 1 + #define _DEFAULT_PCPS_USE_ISA 1 + #define _DEFAULT_PCPS_USE_MCA 0 + #define _DEFAULT_PCPS_USE_PCI 1 + #define _DEFAULT_PCPS_USE_ISA_PNP 0 + #define _DEFAULT_PCPS_USE_PCI_PNP 0 + #define _DEFAULT_PCPS_USE_USB 0 + #define _DEFAULT_PCPS_USE_RSRCMGR 0 +#else // DOS ... + #define _DEFAULT_PCPS_USE_CLOCK_TICK 1 + #define _DEFAULT_PCPS_USE_ISA 1 + #define _DEFAULT_PCPS_USE_MCA 0 + #define _DEFAULT_PCPS_USE_PCI 1 + #define _DEFAULT_PCPS_USE_PCI_PNP 0 + #define _DEFAULT_PCPS_USE_ISA_PNP 0 + #define _DEFAULT_PCPS_USE_USB 0 + #define _DEFAULT_PCPS_USE_RSRCMGR 0 +#endif + +#ifndef _PCPS_USE_CLOCK_TICK + #define _PCPS_USE_CLOCK_TICK _DEFAULT_PCPS_USE_CLOCK_TICK +#endif + +#ifndef _PCPS_USE_ISA + #define _PCPS_USE_ISA _DEFAULT_PCPS_USE_ISA +#endif + +#ifndef _PCPS_USE_MCA + #define _PCPS_USE_MCA _DEFAULT_PCPS_USE_MCA +#endif + +#ifndef _PCPS_USE_PCI + #define _PCPS_USE_PCI _DEFAULT_PCPS_USE_PCI +#endif + +#ifndef _PCPS_USE_ISA_PNP + #define _PCPS_USE_ISA_PNP _DEFAULT_PCPS_USE_ISA_PNP +#endif + +#ifndef _PCPS_USE_PCI_PNP + #define _PCPS_USE_PCI_PNP _DEFAULT_PCPS_USE_PCI_PNP +#endif + +#ifndef _PCPS_USE_USB + #define _PCPS_USE_USB _DEFAULT_PCPS_USE_USB +#endif + +#ifndef _PCPS_USE_RSRCMGR + #define _PCPS_USE_RSRCMGR _DEFAULT_PCPS_USE_RSRCMGR +#endif + + +#ifndef _PCPS_USE_PCI_BIOS + #define _PCPS_USE_PCI_BIOS ( _PCPS_USE_PCI && !_PCPS_USE_PCI_PNP ) +#endif + +#define _PCPS_USE_PNP ( _PCPS_USE_PCI_PNP || _PCPS_USE_ISA_PNP || _PCPS_USE_USB ) + +#if _PCPS_USE_PCI_PNP && _PCPS_USE_PCI_BIOS + #error "PCI PNP and non-PNP can't be used at the same time" +#endif + + +#if !defined( _MBG_INIT_CODE_ATTR ) + // define to empty string by default + #define _MBG_INIT_CODE_ATTR +#endif + + + +/* Other headers to be included */ +#include +#include +#include +#include +#include + +#if defined( MBG_TGT_BSD ) + #include + #include + #include + #include + #include + #include + #include +#else + #include +#endif + +#if defined( MBG_TGT_DOS ) + #include + #include +#endif + +#if defined( MBG_TGT_WIN32 ) + #include +#endif + +#if defined( MBG_TGT_LINUX ) + #if _PCPS_USE_USB + #include + #endif +#endif + +#if defined( MBG_TGT_QNX ) + #include + #include + #include +#endif + +#if defined( MBG_TGT_NETWARE ) + #include + #include + #include +#endif + +#if defined( MBG_TGT_OS2 ) + #ifndef OS2_INCLUDED + #define INCL_DOSSEMAPHORES + #include + #include + #endif + + #include + #include + #include + #include +#elif defined( MBG_TGT_DOS ) + #define FAR far +#else + #define FAR +#endif + +#if _PCPS_USE_RSRCMGR + #include +#endif + +#ifdef _PCPSDRVR + #define _ext + #define _DO_INIT +#else + #define _ext extern +#endif + + +/* Start of header body */ + +// We use native alignment for structures which are not accessed across system boundaries. + +#if defined( MBG_TGT_LINUX ) + + #define _pcps_kmalloc( _sz ) kmalloc( _sz, GFP_ATOMIC ) + #define _pcps_kfree( _p ) kfree( _p ) + + #define MBG_SPINLOCK spinlock_t + #define _pcps_spin_lock_init( _spl ) spin_lock_init( _spl ) + #define _pcps_spin_lock( _spl ) spin_lock( _spl ) + #define _pcps_spin_unlock( _spl ) spin_unlock( _spl ) + + #define MBG_SYS_MUTEX struct semaphore + #define _pcps_mutex_init( _pmtx ) sema_init( _pmtx, 1 ) + + // The special versions of _pcps_sem_inc() and _pcps_sem_dec() below + // are only required to prevent interference with the IRQ handler + // under Linux which implements the serial port emulation for the + // NTP parse driver. + #define _pcps_sem_inc( _pddev ) \ + { \ + ulong flags; \ + \ + if ( down_interruptible( &(_pddev)->dev_mutex ) < 0 ) \ + return -ERESTARTSYS; \ + \ + spin_lock_irqsave( &(_pddev)->irq_lock, flags ); \ + atomic_inc( &(_pddev)->access_in_progress ); \ + spin_unlock_irqrestore( &(_pddev)->irq_lock, flags ); \ + } + + #define _pcps_sem_dec( _pddev ) \ + atomic_dec( &(_pddev)->access_in_progress ); \ + up( &(_pddev)->dev_mutex ) + +#elif defined( MBG_TGT_BSD ) + + // malloc/free in kernel mode require usage of the + // MALLOC_DECLARE() / MALLOC_DEFINE() macros. + // See "man 9 malloc" for details. + + MALLOC_DECLARE( M_MBGCLOCK ); + #define _pcps_kmalloc( _sz ) malloc( _sz, M_MBGCLOCK, M_NOWAIT | M_ZERO ) + #define _pcps_kfree( _p ) free( _p, M_MBGCLOCK ) + + #define MBG_SPINLOCK struct mtx + #define _pcps_spin_lock_init( _spl ) mtx_init( _spl, "mbgclock_spin", NULL, MTX_SPIN ) + #define _pcps_spin_lock( _spl ) mtx_lock_spin( _spl ) + #define _pcps_spin_unlock( _spl ) mtx_unlock_spin( _spl ) + + #define MBG_SYS_MUTEX struct mtx + #define _pcps_mutex_init( _pmtx ) mtx_init( _pmtx, "mbgclock_sema", NULL, MTX_DEF ) + #define _pcps_mutex_acquire( _pmtx ) mtx_lock( _pmtx ) + #define _pcps_mutex_release( _pmtx ) mtx_unlock( _pmtx ) + +#elif defined( MBG_TGT_WIN32 ) + + #define _pcps_kmalloc( _sz ) ExAllocatePool( PagedPool, _sz ) + #define _pcps_kfree( _p ) ExFreePool( _p ) + + #define MBG_SPINLOCK KSPIN_LOCK + #define _pcps_spin_lock_init( _spl ) KeInitializeSpinLock( _spl ) + #define _pcps_spin_lock( _spl ) KeAcquireSpinLockAtDpcLevel( _spl ) + #define _pcps_spin_unlock( _spl ) KeReleaseSpinLockFromDpcLevel( _spl ) + + #define MBG_SYS_MUTEX FAST_MUTEX + #define _pcps_mutex_init( _pmtx ) ExInitializeFastMutex( _pmtx ) + #define _pcps_mutex_acquire( _pmtx ) ExAcquireFastMutex( _pmtx ) + #define _pcps_mutex_release( _pmtx ) ExReleaseFastMutex( _pmtx ) + +#endif + + +#if !defined( _PCPS_STATIC_DEV_LIST ) + // On PNP systems buffers for device specific data are by default malloc'ed + // whenever a device appears. However, a static array of a given maximum number + // of devices is used on non-PNP systems. + // This can be overridden for testing to avoid calling malloc in kernel space. + #define _PCPS_STATIC_DEV_LIST ( !_PCPS_USE_PNP ) +#endif + + + +// If the macros below have not yet been defined then define some dummies: + +#if !defined( MBG_SYS_MUTEX ) + + #define _pcps_mutex_init( _pmtx ) _nop_macro_fnc() + #define _pcps_mutex_acquire( _pmtx ) _nop_macro_fnc() + #define _pcps_mutex_release( _pmtx ) _nop_macro_fnc() + +#endif + + +#if !defined( MBG_SPINLOCK ) + + #define _pcps_spin_lock_init( _spl ) _nop_macro_fnc() + #define _pcps_spin_lock( _spl ) _nop_macro_fnc() + #define _pcps_spin_unlock( _spl ) _nop_macro_fnc() + +#endif + + +#if !defined( _pcps_sem_inc ) || !defined( _pcps_sem_dec ) + + #define _pcps_sem_inc( _pddev ) \ + _pcps_mutex_acquire( &(_pddev)->dev_mutex ) + + #define _pcps_sem_dec( _pddev ) \ + _pcps_mutex_release( &(_pddev)->dev_mutex ) + +#endif + + + +/* ------ definitions used with PCI clocks -------------------------- */ + +/* Default timeout count accessing the board */ + +#if _PCPS_USE_CLOCK_TICK + #if defined( MBG_TGT_NETWARE ) + #define PCPS_TIMEOUT_CNT ( (ulong)( 200 * __get_CLK_TCK() ) / 1000 ) + #elif defined( MBG_TGT_LINUX ) + #define PCPS_TIMEOUT_CNT ( (ulong)( 200 * HZ ) / 1000 ) + #elif defined( MBG_TGT_BSD ) + #define PCPS_TIMEOUT_CNT ( (ulong)( 200 ) ) // [ms] + #elif defined( MBG_TGT_WIN32 ) + #define PCPS_TIMEOUT_CNT ( (ulong)( 200 * MBG_TICKS_PER_SEC ) / 1000 ) + #elif defined( MBG_TGT_QNX_NTO ) + #define PCPS_TIMEOUT_CNT ( (ulong)( 200 * CLOCKS_PER_SEC ) / 1000 ) + #else + #define PCPS_TIMEOUT_CNT ( (ulong)( 200 * CLK_TCK ) / 1000 ) + #endif +#else + #define PCPS_TIMEOUT_CNT 0x7FFFFFUL +#endif + + +// The structures below are used to provide a consistent +// resource handling across different platforms. +// This is kept completely inside the kernel drivers, so these +// structures can be modified safely to suit our needs. + +#if MBG_USE_MM_IO_FOR_PCI + + typedef ulong PCPS_IO_ADDR_RAW; + + #if defined( MBG_TGT_LINUX ) + + typedef volatile void __iomem *PCPS_IO_ADDR_MAPPED; + + #define _pcps_ioremap( _base, _num ) ioremap_nocache( (_base), (_num) ) + + #else + + #error Not supported for target environment. + + #endif + +#else + + typedef PCPS_PORT_ADDR PCPS_IO_ADDR_RAW; + typedef PCPS_IO_ADDR_RAW PCPS_IO_ADDR_MAPPED; + + #if defined( MBG_TGT_BSD ) + // Under *BSD we use only the offset. The base address + // is determined by a handle. + #define _pcps_ioremap( _base, _num ) 0 + #else + #define _pcps_ioremap( _base, _num ) ( _base ) + #endif +#endif + + + +#if defined( MBG_TGT_BSD ) + +typedef struct +{ + int rid; /* resource ID */ + struct resource *res; + bus_space_tag_t bst; + bus_space_handle_t bsh; +} BSD_RSRC_INFO; + +#endif + + + +/** + The structure below describes an I/O port resource + used by a clock. +*/ +typedef struct +{ + #if defined( MBG_TGT_BSD ) + BSD_RSRC_INFO bsd; + #endif + PCPS_IO_ADDR_MAPPED base_mapped; + PCPS_IO_ADDR_RAW base_raw; + uint16_t num; +} PCPS_IO_RSRC; + + +// The structure below describes a bus memory resource +// used by a clock. + +typedef struct +{ + #if defined( MBG_TGT_BSD ) + BSD_RSRC_INFO bsd; + #endif + MBG_MEM_ADDR start; + ulong len; + +} PCPS_MEM_RSRC; + + + +// The structure below describes a bus IRQ resource +// used by a clock. + +typedef struct +{ + #if defined( MBG_TGT_BSD ) + BSD_RSRC_INFO bsd; + #endif + ushort num; + +} PCPS_IRQ_RSRC; + + + +// The max number of bus memory resources used by a device. +#define N_PCPS_MEM_RSRC 2 + +// The max number of bus memory and I/O resources used by a device. +#define MAX_PCPS_RSRC ( N_PCPS_MEM_RSRC + N_PCPS_PORT_RSRC ) + +typedef struct +{ + int num_rsrc_io; + int num_rsrc_mem; + int num_rsrc_irq; + PCPS_IO_RSRC port[N_PCPS_PORT_RSRC]; + PCPS_MEM_RSRC mem[N_PCPS_MEM_RSRC]; + PCPS_IRQ_RSRC irq; +} PCPS_RSRC_INFO; + + + +#if _PCPS_USE_USB + + typedef struct + { + uint8_t addr; + uint16_t max_packet_size; + } PCPS_USB_EP; + + + #if defined( MBG_TGT_LINUX ) + + // definitions used to control the cyclic USB read thread + + #if _PCPS_USE_LINUX_KTHREAD + + // use kthread_run() / kthread_stop() + typedef struct task_struct *PCPS_THREAD_INFO; + + #else + + // use kernel_thread() / daemonize() / kill_proc() + typedef struct + { + pid_t pid; + char name[17]; // 16 chars as supported by the kernel, plus trailing 0 + struct completion exit; + } PCPS_THREAD_INFO; + + #endif // _PCPS_USE_LINUX_KTHREAD + + #endif // defined( MBG_TGT_LINUX ) + +#endif // _PCPS_USE_USB + + + +typedef union +{ + struct + { + PCI_ASIC asic; + PCPS_TIME_STAMP tstamp; + } pex8311; + + struct + { + PCI_ASIC asic; + uint8_t b[256 - sizeof( PCI_ASIC ) ]; + PCPS_TIME_STAMP ucap[2]; + PCPS_TIME_STAMP tstamp; + } mbgpex; + +} PCPS_MM_LAYOUT; + + + +typedef struct PCPS_DDEV_s +{ + // the device info data + PCPS_DEV dev; + + // the read function to be used to access the clock + short (*read)( struct PCPS_DDEV_s *pddev, uchar cmd, + uchar FAR *buffer, uchar count ); + + PCPS_IO_ADDR_MAPPED status_port; + PCPS_IO_ADDR_MAPPED irq_enb_disb_port; + PCPS_IO_ADDR_MAPPED irq_flag_port; + PCPS_IO_ADDR_MAPPED irq_ack_port; + uint32_t irq_enb_mask; + uint32_t irq_disb_mask; + uint32_t irq_flag_mask; + uint32_t irq_ack_mask; + + PCI_ASIC_VERSION raw_asic_version; + PCI_ASIC_VERSION asic_version; + PCI_ASIC_FEATURES asic_features; + PCPS_RSRC_INFO rsrc_info; + + MBG_PC_CYCLES acc_cycles; + + #if defined( MBG_SYS_MUTEX ) + MBG_SYS_MUTEX dev_mutex; + #endif + + PCPS_MM_LAYOUT FAR *mm_addr; + volatile PCPS_TIME_STAMP FAR *mm_tstamp_addr; + + #if defined( MBG_SPINLOCK ) + MBG_SPINLOCK mm_lock; + MBG_SPINLOCK irq_lock; + #endif + + // The flag below holds IRQ information, e.g. whether the device's + // IRQ is possibly unsafe, and whether IRQ has been enabled on the device. + PCPS_IRQ_STAT_INFO irq_stat_info; + + #if _PCPS_USE_USB + int n_usb_ep; // number of endpoints supp. by the device + PCPS_USB_EP ep[MBGUSB_MAX_ENDPOINTS]; + uint8_t usb_20_mode; + #endif + + #if defined( MBG_TGT_WIN32 ) + _pcps_ddev_data_win + #endif + + #if defined( MBG_TGT_LINUX ) + atomic_t connected; + atomic_t access_in_progress; + atomic_t data_avail; + unsigned long jiffies_at_irq; + struct fasync_struct *fasyncptr; + PCPS_TIME t; + + #if NEW_WAIT_QUEUE + wait_queue_head_t wait_queue; + #else + struct wait_queue *wait_queue; + #endif + + dev_t lx_dev; + atomic_t open_count; + + #if _PCPS_USE_LINUX_CHRDEV + struct cdev cdev; + #elif _PCPS_USE_LINUX_MISC_DEV + struct miscdevice mdev; + #endif + + #if _PCPS_USE_USB + struct usb_device *udev; + struct usb_interface *intf; + PCPS_THREAD_INFO usb_read_thread; + struct semaphore sem_usb_cyclic; + #endif + #endif + + #if defined( MBG_TGT_BSD ) + int connected; + int open_count; + #endif + + #if _PCPS_USE_RSRCMGR + #if defined( MBG_TGT_OS2 ) + PCPS_HDEV hDev; + RSRC_LIST rsrc; + #endif + #endif + +} PCPS_DDEV; + + + +/* The PCI vendor ID and device ID numbers are used to detect a + * PCI clock in a system and query which resources have been + * assigned by the BIOS. + * (PCI vendor ID and PCI device IDs are defined in PCPSDEFS.H) + */ + +/* the number of address lines decoded by a PCI clock */ +#define PCPS_DECODE_WIDTH_PCI 16 + + +/* ------ definitions used with MCA clocks -------------------------- */ + +/* The MCA adapter ID number is used to detect a MCA clock in a + * system and query which resources have been assigned by the + * system's POS (programmable option select). + */ + +/* MCA Adapter ID numbers */ +#define MCA_ID_PS31 0x6AAC /* assigned by IBM */ +#define MCA_ID_PS31_OLD 0x6303 /* assigned by Meinberg, used with */ + /* the first series of PS31 boards */ + +/* the total number of ports acquired by a MCA clock */ +#define PCPS_NUM_PORTS_MCA 16 + +/* the number of address lines decoded by a MCA clock */ +#define PCPS_DECODE_WIDTH_MCA 16 + + +/* ------ definitions used with ISA clocks -------------------------- */ + +/* A board ID for the newer clocks with ISA bus. The number can + * be read at port_base+2 (low byte) and port_base+3 (high byte) + * of ISA clocks. This ID number matches the MCA adapter ID + * defined above and is not available on PC31 clocks. + */ +#define ISA_ID_PCPS MCA_ID_PS31 + +/* The default port base address for ISA clocks. + * Some programs assume a default port for an ISA clock, + * others do not but require a cmd line parameter. + */ +#define PCPS_DEFAULT_PORT 0x0300 + +/* the total number of ports acquired by a ISA clock */ +#define PCPS_NUM_PORTS_ISA 4 + +/* the number of address lines decoded by a ISA clock */ +#define PCPS_DECODE_WIDTH_ISA 10 + + +/* ------ common definitions -------------------------- */ + +_ext PCPS_DEV_TYPE pcps_dev_type[N_PCPS_DEV_TYPE] +#ifdef _DO_INIT += { + { PCPS_TYPE_PC31, "PC31", 0, PCPS_REF_DCF, PCPS_BUS_ISA }, + { PCPS_TYPE_PS31_OLD, "PS31", MCA_ID_PS31_OLD, PCPS_REF_DCF, PCPS_BUS_MCA }, + { PCPS_TYPE_PS31, "PS31", MCA_ID_PS31, PCPS_REF_DCF, PCPS_BUS_MCA }, + { PCPS_TYPE_PC32, "PC32", ISA_ID_PCPS, PCPS_REF_DCF, PCPS_BUS_ISA }, + { PCPS_TYPE_PCI32, "PCI32", PCI_DEV_PCI32, PCPS_REF_DCF, PCPS_BUS_PCI_S5933 }, + { PCPS_TYPE_GPS167PC, "GPS167PC", 0, PCPS_REF_GPS, PCPS_BUS_ISA }, + { PCPS_TYPE_GPS167PCI, "GPS167PCI", PCI_DEV_GPS167PCI, PCPS_REF_GPS, PCPS_BUS_PCI_S5933 }, + { PCPS_TYPE_PCI509, "PCI509", PCI_DEV_PCI509, PCPS_REF_DCF, PCPS_BUS_PCI_S5920 }, + { PCPS_TYPE_GPS168PCI, "GPS168PCI", PCI_DEV_GPS168PCI, PCPS_REF_GPS, PCPS_BUS_PCI_S5920 }, + { PCPS_TYPE_PCI510, "PCI510", PCI_DEV_PCI510, PCPS_REF_DCF, PCPS_BUS_PCI_ASIC }, + { PCPS_TYPE_GPS169PCI, "GPS169PCI", PCI_DEV_GPS169PCI, PCPS_REF_GPS, PCPS_BUS_PCI_ASIC }, + { PCPS_TYPE_TCR510PCI, "TCR510PCI", PCI_DEV_TCR510PCI, PCPS_REF_IRIG, PCPS_BUS_PCI_ASIC }, + { PCPS_TYPE_TCR167PCI, "TCR167PCI", PCI_DEV_TCR167PCI, PCPS_REF_IRIG, PCPS_BUS_PCI_ASIC }, + { PCPS_TYPE_GPS170PCI, "GPS170PCI", PCI_DEV_GPS170PCI, PCPS_REF_GPS, PCPS_BUS_PCI_ASIC }, + { PCPS_TYPE_PCI511, "PCI511", PCI_DEV_PCI511, PCPS_REF_DCF, PCPS_BUS_PCI_ASIC }, + { PCPS_TYPE_TCR511PCI, "TCR511PCI", PCI_DEV_TCR511PCI, PCPS_REF_IRIG, PCPS_BUS_PCI_ASIC }, + { PCPS_TYPE_PEX511, "PEX511", PCI_DEV_PEX511, PCPS_REF_DCF, PCPS_BUS_PCI_PEX8311 }, + { PCPS_TYPE_TCR511PEX, "TCR511PEX", PCI_DEV_TCR511PEX, PCPS_REF_IRIG, PCPS_BUS_PCI_PEX8311 }, + { PCPS_TYPE_GPS170PEX, "GPS170PEX", PCI_DEV_GPS170PEX, PCPS_REF_GPS, PCPS_BUS_PCI_PEX8311 }, + { PCPS_TYPE_USB5131, "USB5131", USB_DEV_USB5131, PCPS_REF_DCF, PCPS_BUS_USB }, + { PCPS_TYPE_TCR51USB, "TCR51USB", USB_DEV_TCR51USB, PCPS_REF_IRIG, PCPS_BUS_USB }, + { PCPS_TYPE_MSF51USB, "MSF51USB", USB_DEV_MSF51USB, PCPS_REF_MSF, PCPS_BUS_USB }, + { PCPS_TYPE_PTP270PEX, "PTP270PEX", PCI_DEV_PTP270PEX, PCPS_REF_PTP, PCPS_BUS_PCI_PEX8311 }, + { PCPS_TYPE_FRC511PEX, "FRC511PEX", PCI_DEV_FRC511PEX, PCPS_REF_FRC, PCPS_BUS_PCI_PEX8311 }, + { PCPS_TYPE_TCR170PEX, "TCR170PEX", PCI_DEV_TCR170PEX, PCPS_REF_IRIG, PCPS_BUS_PCI_PEX8311 }, + { PCPS_TYPE_WWVB51USB, "WWVB51USB", USB_DEV_WWVB51USB, PCPS_REF_WWVB, PCPS_BUS_USB }, + { PCPS_TYPE_GPS180PEX, "GPS180PEX", PCI_DEV_GPS180PEX, PCPS_REF_GPS, PCPS_BUS_PCI_MBGPEX }, + { PCPS_TYPE_TCR180PEX, "TCR180PEX", PCI_DEV_TCR180PEX, PCPS_REF_IRIG, PCPS_BUS_PCI_MBGPEX }, + { PCPS_TYPE_DCF600USB, "DCF600USB", USB_DEV_DCF600USB, PCPS_REF_DCF, PCPS_BUS_USB } + + // If a new device is added here, don't forget to add it also + // to the Windows .inf file of supported PCI an USB devices, + // and in case of USB to the Linux driver file mbgdrvr.c. +} +#endif +; + + +#if !defined( PCPS_MAX_DDEVS ) + #define PCPS_MAX_DDEVS 4 +#endif + +#if !defined( PCPS_MAX_ISA_CARDS ) + #define PCPS_MAX_ISA_CARDS PCPS_MAX_DDEVS // the number of ISA cards supported +#endif + +_ext int pcps_isa_ports[PCPS_MAX_ISA_CARDS + 1]; + +#if _PCPS_STATIC_DEV_LIST + _ext PCPS_DDEV pcps_ddev[PCPS_MAX_DDEVS]; + _ext int n_ddevs; +#endif + +#if defined( MBG_TGT_DOS ) || defined( MBG_TGT_NETWARE ) //##++ + _ext int curr_ddev_num; + _ext PCPS_DDEV *curr_ddev + #ifdef _DO_INIT + = &pcps_ddev[0] + #endif + ; +#endif + +/* the first characters of a valid EPROM ID */ + +_ext const char *fw_id_ref[] +#ifdef _DO_INIT + = { + "PC3", // PC31, PS31, PC32 + "PCI", // PCI32, PCI509, PCI510, PCI511 + "GPS", // GPS167PC, GPS167PCI, GPS168PCI, GPS169PCI, GPS170PCI, GPS170PEX, GPS180PEX + "TCR", // TCR510PCI, TCR167PCI, TCR511PCI, TCR511PEX, TCR51USB, TCR170PEX, TCR180PEX + "PEX", // PEX511 + "USB", // USB5131 + "MSF", // MSF51USB + "WWVB", // WWVB51USB + "DCF", // DCF600USB + NULL + } +#endif +; + + +// The macros below are used to distinguish ISA cards: + +#define fw_id_ref_pcps fw_id_ref[0] +#define fw_id_ref_gps fw_id_ref[2] + + + +// The macros below accept a (PCPS_DDEV *) for easy access +// to the information stored in PCPS_DDEV structures. + +// Access device type information: +#define _pcps_ddev_type_num( _p ) _pcps_type_num( &(_p)->dev ) +#define _pcps_ddev_type_name( _p ) _pcps_type_name( &(_p)->dev ) +#define _pcps_ddev_dev_id( _p ) _pcps_dev_id( &(_p)->dev ) +#define _pcps_ddev_ref_type( _p ) _pcps_ref_type( &(_p)->dev ) +#define _pcps_ddev_bus_flags( _p ) _pcps_bus_flags( &(_p)->dev ) + +// Query device type features: +#define _pcps_ddev_is_gps( _p ) _pcps_is_gps( &(_p)->dev ) +#define _pcps_ddev_is_dcf( _p ) _pcps_is_dcf( &(_p)->dev ) +#define _pcps_ddev_is_msf( _p ) _pcps_is_msf( &(_p)->dev ) +#define _pcps_ddev_is_wwvb( _p ) _pcps_is_wwvb( &(_p)->dev ) +#define _pcps_ddev_is_irig_rx( _p ) _pcps_is_irig_rx( &(_p)->dev ) +#define _pcps_ddev_is_ptp( _p ) _pcps_is_ptp( &(_p)->dev ) +#define _pcps_ddev_is_frc( _p ) _pcps_is_frc( &(_p)->dev ) + +#define _pcps_ddev_is_lwr( _p ) _pcps_is_lwr( &(_p)->dev ) + +#define _pcps_ddev_is_isa( _p ) _pcps_is_isa( &(_p)->dev ) +#define _pcps_ddev_is_mca( _p ) _pcps_is_mca( &(_p)->dev ) +#define _pcps_ddev_is_pci( _p ) _pcps_is_pci( &(_p)->dev ) +#define _pcps_ddev_is_usb( _p ) _pcps_is_usb( &(_p)->dev ) + +#define _pcps_ddev_is_pci_s5933( _p ) _pcps_is_pci_s5933( &(_p)->dev ) +#define _pcps_ddev_is_pci_s5920( _p ) _pcps_is_pci_s5920( &(_p)->dev ) +#define _pcps_ddev_is_pci_amcc( _p ) _pcps_is_pci_amcc( &(_p)->dev ) +#define _pcps_ddev_is_pci_asic( _p ) _pcps_is_pci_asic( &(_p)->dev ) +#define _pcps_ddev_is_pci_pex8311( _p ) _pcps_is_pci_pex8311( &(_p)->dev ) +#define _pcps_ddev_is_pci_mbgpex( _p ) _pcps_is_pci_mbgpex( &(_p)->dev ) + + +// Access device configuration information: +#define _pcps_ddev_bus_num( _p ) _pcps_bus_num( &(_p)->dev ) +#define _pcps_ddev_slot_num( _p ) _pcps_slot_num( &(_p)->dev ) + +#define _pcps_ddev_port_rsrc( _p, _n ) _pcps_port_rsrc( &(_p)->dev, _n ) +#define _pcps_ddev_port_base( _p, _n ) _pcps_port_base( &(_p)->dev, _n ) +#define _pcps_ddev_io_rsrc( _p, _n ) ( (_p)->rsrc_info.port[_n] ) +#define _pcps_ddev_io_base_mapped( _p, _n ) ( _pcps_ddev_io_rsrc( _p, _n ).base_mapped ) +#define _pcps_ddev_irq_num( _p ) _pcps_irq_num( &(_p)->dev ) +#define _pcps_ddev_timeout_clk( _p ) _pcps_timeout_clk( &(_p)->dev ) + +#define _pcps_ddev_fw_rev_num( _p ) _pcps_fw_rev_num( &(_p)->dev ) +#define _pcps_ddev_features( _p ) _pcps_features( &(_p)->dev ) +#define _pcps_ddev_fw_id( _p ) _pcps_fw_id( &(_p)->dev ) +#define _pcps_ddev_sernum( _p ) _pcps_sernum( &(_p)->dev ) +#define _pcps_ddev_raw_asic_version( _p ) ( (_p)->raw_asic_version ) +#define _pcps_ddev_asic_version( _p ) ( (_p)->asic_version ) + +// The macros below handle the clock device's err_flags. +#define _pcps_ddev_set_err_flags( _p, _msk ) \ + _pcps_set_err_flags( &(_p)->dev, _msk ) + +#define _pcps_ddev_clr_err_flags( _p, _msk ) \ + _pcps_clr_err_flags( &(_p)->dev, _msk ) + +#define _pcps_ddev_chk_err_flags( _p, _msk ) \ + _pcps_chk_err_flags( &(_p)->dev, _msk ) + + +// Query whether a special feature is supported: +#define _pcps_ddev_has_feature( _p, _f ) _pcps_has_feature( &(_p)->dev, _f ) +#define _pcps_ddev_can_set_time( _p ) _pcps_can_set_time( &(_p)->dev ) +#define _pcps_ddev_has_serial( _p ) _pcps_has_serial( &(_p)->dev ) +#define _pcps_ddev_has_sync_time( _p ) _pcps_has_sync_time( &(_p)->dev ) +#define _pcps_ddev_has_ident( _p ) _pcps_has_ident( &(_p)->dev ) +#define _pcps_ddev_has_utc_offs( _p ) _pcps_has_utc_offs( &(_p)->dev ) +#define _pcps_ddev_has_hr_time( _p ) _pcps_has_hr_time( &(_p)->dev ) +#define _pcps_ddev_has_sernum( _p ) _pcps_has_sernum( &(_p)->dev ) +#define _pcps_ddev_has_cab_len( _p ) _pcps_has_cab_len( &(_p)->dev ) +#define _pcps_ddev_has_tzdl( _p ) _pcps_has_tzdl( &(_p)->dev ) +#define _pcps_ddev_has_pcps_tzdl( _p ) _pcps_has_pcps_tzdl( &(_p)->dev ) +#define _pcps_ddev_has_tzcode( _p ) _pcps_has_tzcode( &(_p)->dev ) +#define _pcps_ddev_has_tz( _p ) _pcps_has_tz( &(_p)->dev ) +// The next one is supported only with a certain GPS firmware version: +#define _pcps_ddev_has_event_time( _p ) _pcps_has_event_time( &(_p)->dev ) +#define _pcps_ddev_has_receiver_info( _p ) _pcps_has_receiver_info( &(_p)->dev ) +#define _pcps_ddev_can_clr_ucap_buff( _p ) _pcps_can_clr_ucap_buff( &(_p)->dev ) +#define _pcps_ddev_has_ucap( _p ) _pcps_has_ucap( &(_p)->dev ) +#define _pcps_ddev_has_irig_tx( _p ) _pcps_has_irig_tx( &(_p)->dev ) + +// The macro below determines whether a DCF77 clock +// supports a higher baud rate than standard +#define _pcps_ddev_has_serial_hs( _p ) \ + _pcps_has_serial_hs( &(_p)->dev ) + + +#define _pcps_ddev_has_signal( _p ) \ + _pcps_has_signal( &(_p)->dev ) + +#define _pcps_ddev_has_mod( _p ) \ + _pcps_has_mod( &(_p)->dev ) + + +#define _pcps_ddev_has_irig( _p ) \ + _pcps_has_irig( &(_p)->dev ) + +#define _pcps_ddev_has_irig_ctrl_bits( _p ) \ + _pcps_has_irig_ctrl_bits( &(_p)->dev ) + +#define _pcps_ddev_has_irig_time( _p ) \ + _pcps_has_irig_time( &(_p)->dev ) + +#define _pcps_ddev_has_raw_irig_data( _p ) \ + _pcps_has_raw_irig_data( &(_p)->dev ) + +#define _pcps_ddev_has_ref_offs( _p ) \ + _pcps_has_ref_offs( &(_p)->dev ) + +#define _pcps_ddev_has_opt_flags( _p ) \ + _pcps_has_opt_flags( &(_p)->dev ) + +#define _pcps_ddev_has_gps_data( _p ) \ + _pcps_has_gps_data( &(_p)->dev ) + +#define _pcps_ddev_has_gps_data_16( _p ) \ + _pcps_has_gps_data_16( &(_p)->dev ) + +#define _pcps_ddev_has_synth( _p ) \ + _pcps_has_synth( &(_p)->dev ) + +#define _pcps_ddev_has_generic_io( _p ) \ + _pcps_has_generic_io( &(_p)->dev ) + +#define _pcps_ddev_has_time_scale( _p ) \ + _pcps_has_time_scale( &(_p)->dev ) + +#define _pcps_ddev_has_utc_parm( _p ) \ + _pcps_has_utc_parm( &(_p)->dev ) + +#define _pcps_ddev_has_asic_version( _p ) \ + _pcps_has_asic_version( &(_p)->dev ) + +#define _pcps_ddev_has_asic_features( _p ) \ + _pcps_has_asic_features( &(_p)->dev ) + +#define _pcps_ddev_has_fast_hr_timestamp( _p ) \ + _pcps_has_fast_hr_timestamp( &(_p)->dev ) + +#define _pcps_ddev_has_lan_intf( _p ) \ + _pcps_has_lan_intf( &(_p)->dev ) + +#define _pcps_ddev_has_ptp( _p ) \ + _pcps_has_ptp( &(_p)->dev ) + + +// The macros below simplify read/write access to the clocks. + +// Call the device's read function to write the command byte _cmd +// and read _n bytes to buffer _s. +#if !defined( _pcps_read ) + #define _pcps_read( _pddev, _cmd, _p, _n ) \ + ( (_pddev)->read( _pddev, (_cmd), (uchar FAR *)(_p), (_n) ) ) +#endif + +// Write a byte _b to the radio clock device. This is typically +// done by just writing the command byte from inside the read function. +#if !defined( _pcps_write_byte ) + #define _pcps_write_byte( _pddev, _b ) \ + _pcps_read( (_pddev), (_b), NULL, 0 ) +#endif + +// write a command plus the contents of a data buffer to the device. +// This is typically implemented as a function which uses the +// _pcps_write_byte() macro repeatedly. +#if !defined( _pcps_write ) + #define _pcps_write( _pddev, _cmd, _p, _n ) \ + pcps_write( (_pddev), (_cmd), (uchar FAR *)(_p), (_n) ) +#endif + +// Read data structures which exceed PCPS_FIFO_SIZE bytes. +// This can't be handled in a single read cycle and due to limitations +// of the clock's microprocessor these calls can up to 20 milliseconds. +// Currently these function is only used to read GPS specific data +// from GPS clocks. +#define _pcps_read_gps( _pddev, _cmd, _p, _n ) \ + pcps_read_gps( (_pddev), (_cmd), (uchar FAR *) (_p), (_n) ) + +// The write function opposite to the read function above. +#define _pcps_write_gps( _pddev, _cmd, _p, _n ) \ + pcps_write_gps( (_pddev), (_cmd), (uchar FAR *) (_p), (_n) ) + + + +// The macros below simplify reading/writing typed variables by +// determining the size automatically from the type of the variable. + +// Read data from the radio clock board to variable _s. +// The number of bytes to read is determined by the size +// of _s. The accepted type of _s depends on the _cmd code. +#define _pcps_read_var( _pddev, _cmd, _s ) \ + _pcps_read( (_pddev), (_cmd), &(_s), sizeof( (_s) ) ) + +// Write data from variable _s to the radio clock board . +// The number of bytes to write is determined by the size +// of _s. The accepted type of _s depends on the _cmd code. +#define _pcps_write_var( _pddev, _cmd, _s ) \ + _pcps_write( (_pddev), (_cmd), &(_s), sizeof( (_s) ) ) + + +// Read data structures which exceed PCPS_FIFO_SIZE bytes. +// This can't be handled in a single read cycle and due to limitations +// of the clock's microprocessor these calls can up to 20 milliseconds. +// Currently these function is only used to read GPS specific data +// from GPS clocks. +#define _pcps_read_gps_var( _pddev, _cmd, _s ) \ + _pcps_read_gps( (_pddev), (_cmd), &(_s), sizeof( (_s) ) ) + +// The write function opposite to the read function above. +#define _pcps_write_gps_var( _pddev, _cmd, _s ) \ + _pcps_write_gps( (_pddev), (_cmd), &(_s), sizeof( (_s) ) ) + + +// Generate a hardware reset on the radio clock board. This +// macro should be used VERY carefully and should be avoided +// if possible. +#define _pcps_force_reset( _pddev ) \ + _pcps_write_byte( (_pddev), PCPS_FORCE_RESET ) + + +// The macro below reads a radio clock's status port which +// includes the BUSY flag and the modulation signal of DCF77 +// clocks. The macro takes a (PCPS_DDEV *) as argument. +#define _pcps_ddev_read_status_port( _d ) \ + _mbg_inp8( (_d), (_d)->status_port ) + +#define _pcps_ddev_status_busy( _d ) \ + ( _pcps_ddev_read_status_port( pddev ) & PCPS_ST_BUSY ) + + +// The macro below checks whether a workaround is required to get/set +// IRIG cfg from a GPS169PCI with IRIG output and early firmware version +// This is handled in mbgdevio.c for direct access environments, and in +// macioctl.h for kernel device drivers. +#define _pcps_ddev_requires_irig_workaround( _d ) \ + ( ( _pcps_ddev_type_num( _d ) == PCPS_TYPE_GPS169PCI ) && \ + ( _pcps_ddev_fw_rev_num( _d ) < REV_HAS_GPS_DATA_16_GPS169PCI ) ) + + +#if _PCPS_USE_USB + + #if !defined( MBGUSB_TIMEOUT_SEND_MS ) + #define MBGUSB_TIMEOUT_SEND_MS 500 // [ms] + #endif + + #if !defined( MBGUSB_TIMEOUT_RECEIVE_MS ) + #define MBGUSB_TIMEOUT_RECEIVE_MS 500 // [ms] + #endif + + #if !defined( MBGUSB_TIMEOUT_RECEIVE_CYCLIC_MS ) + // The USB read function may block until a packet has been received, or a + // receive timeout has occurred. The cyclic USB read function has an overall + // timeout of more than 1 second. In order to increase responsiveness we use + // by default a shorter timeout interval plus some retries, if required. + // + // For some target environments it may be preferable to use only one + // full timeout interval, so this setting can be overridden if required. + #if !defined( _PCPS_USB_FULL_CYCLIC_INTV ) + #define _PCPS_USB_FULL_CYCLIC_INTV 1 + #endif + + #if _PCPS_USB_FULL_CYCLIC_INTV + #define MBGUSB_TIMEOUT_RECEIVE_CYCLIC_MS 1200 + #else + #define MBGUSB_TIMEOUT_RECEIVE_CYCLIC_MS 50 + #endif + #endif + + + #if !defined( _pcps_ms_to_usb_timeout ) + #define _pcps_ms_to_usb_timeout( _ms ) (_ms) + #endif + + + #if !defined( MBGUSB_TIMEOUT_SEND ) + #define MBGUSB_TIMEOUT_SEND _pcps_ms_to_usb_timeout( MBGUSB_TIMEOUT_SEND_MS ) + #endif + + #if !defined( MBGUSB_TIMEOUT_RECEIVE ) + #define MBGUSB_TIMEOUT_RECEIVE _pcps_ms_to_usb_timeout( MBGUSB_TIMEOUT_RECEIVE_MS ) + #endif + + #if !defined( MBGUSB_TIMEOUT_RECEIVE_CYCLIC ) + #define MBGUSB_TIMEOUT_RECEIVE_CYCLIC _pcps_ms_to_usb_timeout( MBGUSB_TIMEOUT_RECEIVE_CYCLIC_MS ) + #endif + + + #if defined( MBG_TGT_WIN32_PNP ) + + #define _pcps_usb_write_ep_tmo( _d, _p, _sz, _ep_idx, _tmo, _irp ) \ + pcps_usb_transfer( _d, _ep_idx, _p, _sz, 1, _tmo, _irp ) + + #define _pcps_usb_read_ep_tmo( _d, _p, _sz, _ep_idx, _tmo, _irp ) \ + pcps_usb_transfer( _d, _ep_idx, _p, _sz, 0, _tmo, _irp ) + + #define _pcps_usb_write( _d, _p, _sz ) \ + _pcps_usb_write_ep_tmo( _d, _p, _sz, MBGUSB_EP_IDX_HOST_OUT, MBGUSB_TIMEOUT_SEND, (_d)->irp ) + + #define _pcps_usb_read( _d, _p, _sz ) \ + _pcps_usb_read_ep_tmo( _d, _p, _sz, MBGUSB_EP_IDX_HOST_IN, MBGUSB_TIMEOUT_RECEIVE, (_d)->irp ) + + #define _pcps_usb_read_cyclic( _d, _p, _sz, _irp ) \ + _pcps_usb_read_ep_tmo( _d, _p, _sz, MBGUSB_EP_IDX_HOST_IN_CYCLIC, MBGUSB_TIMEOUT_RECEIVE_CYCLIC, _irp ) + + #define _pcps_usb_read_var_cyclic( _d, _p, _irp ) \ + _pcps_usb_read_cyclic( _d, _p, sizeof( *(_p) ), _irp ) + + #elif defined( MBG_TGT_LINUX ) + + #define _pcps_usb_write_ep_tmo( _d, _p, _sz, _ep_idx, _tmo ) \ + usb_bulk_msg( (_d)->udev, \ + usb_sndbulkpipe( (_d)->udev, (_d)->ep[_ep_idx].addr ), \ + _p, _sz, &actual_count, _tmo ) + + #define _pcps_usb_read_ep_tmo( _d, _p, _sz, _ep_idx, _tmo ) \ + usb_bulk_msg( (_d)->udev, \ + usb_rcvbulkpipe( (_d)->udev, (_d)->ep[_ep_idx].addr ), \ + _p, _sz, &actual_count, _tmo ) + + #define _pcps_usb_write( _d, _p, _sz ) \ + _pcps_usb_write_ep_tmo( _d, _p, _sz, MBGUSB_EP_IDX_HOST_OUT, MBGUSB_TIMEOUT_SEND ) + + #define _pcps_usb_read( _d, _p, _sz ) \ + _pcps_usb_read_ep_tmo( _d, _p, _sz, MBGUSB_EP_IDX_HOST_IN, MBGUSB_TIMEOUT_RECEIVE ) + + #define _pcps_usb_read_cyclic( _d, _p, _sz ) \ + _pcps_usb_read_ep_tmo( _d, _p, _sz, MBGUSB_EP_IDX_HOST_IN_CYCLIC, MBGUSB_TIMEOUT_RECEIVE_CYCLIC ) + + #define _pcps_usb_read_var_cyclic( _d, _p ) \ + _pcps_usb_read_cyclic( _d, _p, sizeof( *(_p) ) ) + + #endif // target specific definitions + + + #define _pcps_usb_write_var( _d, _p ) \ + _pcps_usb_write( _d, _p, sizeof( *(_p) ) ) + + #define _pcps_usb_read_var( _d, _p ) \ + _pcps_usb_read( _d, _p, sizeof( *(_p) ) ) + +#endif + + + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef PCPS_DDEV *(*PCPS_DDEV_ALLOC_FNC)( void ); +typedef void (*PCPS_DDEV_CLEANUP_FNC)( PCPS_DDEV * ); +typedef int (*PCPS_DDEV_REGISTER_FNC)( PCPS_DDEV * ); + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + + short pcps_write( PCPS_DDEV *pddev, uint8_t cmd, const void FAR *buffer, uint8_t count ) ; + short pcps_generic_io( PCPS_DDEV *pddev, uint8_t type, const void FAR *in_buff, uint8_t in_cnt, void FAR *out_buff, uint8_t out_cnt ) ; + short pcps_read_gps( PCPS_DDEV *pddev, uint8_t data_type, void FAR *buffer, uint16_t buffer_size ) ; + short pcps_write_gps( PCPS_DDEV *pddev, uint8_t data_type, const void FAR *buffer, uint16_t buffer_size ) ; + short pcps_get_fw_id( PCPS_DDEV *pddev, PCPS_ID_STR FAR fw_id ) ; + short pcps_check_id( PCPS_DDEV *pddev, const char FAR *ref ) ; + short pcps_get_rev_num( char FAR *idstr ) ; + int pcps_read_sernum( PCPS_DDEV *pddev ) ; + int pcps_rsrc_claim( PCPS_DDEV *pddev ) ; + void pcps_rsrc_release( PCPS_DDEV *pddev ) ; + ushort pcps_port_from_pos( ushort pos ) ; + uchar pcps_pos_from_port( ushort port ) ; + PCPS_DEV_TYPE *pcps_get_dev_type( int bus_mask, ushort dev_id ) ; + PCPS_DDEV *pcps_alloc_ddev( void ) ; + void pcps_free_ddev( PCPS_DDEV *pddev ) ; + int pcps_add_rsrc_io( PCPS_DDEV *pddev, ulong base, ulong num ) ; + int pcps_add_rsrc_mem( PCPS_DDEV *pddev, MBG_MEM_ADDR start, ulong len ) ; + int pcps_add_rsrc_irq( PCPS_DDEV *pddev, int16_t irq_num ) ; + int pcps_init_ddev( PCPS_DDEV *pddev, int bus_flags, ushort dev_id ) ; + int pcps_start_device( PCPS_DDEV *pddev, PCPS_BUS_NUM bus_num, PCPS_SLOT_NUM dev_fnc_num ) ; + void pcps_cleanup_device( PCPS_DDEV *pddev ) ; + void pcps_setup_and_start_pci_dev( PCPS_DDEV *pddev, PCPS_BUS_NUM bus_num, PCPS_SLOT_NUM dev_fnc_num ) ; + void pcps_detect_pci_clocks( PCPS_DDEV_ALLOC_FNC alloc_fnc, void *alloc_arg, PCPS_DDEV_CLEANUP_FNC cleanup_fnc, ushort vendor_id, PCPS_DEV_TYPE dev_type[], int n_dev_types ) ; + void pcps_detect_isa_clocks( PCPS_DDEV_ALLOC_FNC alloc_fnc, PCPS_DDEV_CLEANUP_FNC cleanup_fnc, PCPS_DDEV_REGISTER_FNC register_fnc, int isa_ports[PCPS_MAX_ISA_CARDS], int isa_irqs[PCPS_MAX_ISA_CARDS] ) ; + void _MBG_INIT_CODE_ATTR pcps_detect_clocks_alloc( PCPS_DDEV_ALLOC_FNC alloc_fnc, void *alloc_arg, PCPS_DDEV_CLEANUP_FNC cleanup_fnc, int isa_ports[PCPS_MAX_ISA_CARDS], int isa_irqs[PCPS_MAX_ISA_CARDS] ) ; + void _MBG_INIT_CODE_ATTR pcps_detect_clocks( int isa_ports[PCPS_MAX_ISA_CARDS], int isa_irqs[PCPS_MAX_ISA_CARDS] ) ; + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + +// We have used native alignment here, so no need to undo alignment at this place. + +/* End of header body */ + +#undef _ext +#undef _DO_INIT + +#endif /* _PCPSDRVR_H */ diff --git a/mbglib/common/pcpsirq.h b/mbglib/common/pcpsirq.h new file mode 100755 index 0000000..7bb2b1f --- /dev/null +++ b/mbglib/common/pcpsirq.h @@ -0,0 +1,212 @@ + +/************************************************************************** + * + * $Id: pcpsirq.h 1.7 2008/12/05 12:20:36 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * OS independent definitions used to handle interrupts from + * Meinberg radio clock devices. + * + * ----------------------------------------------------------------------- + * $Log: pcpsirq.h $ + * Revision 1.7 2008/12/05 12:20:36 martin + * Protect HW access to enable/disable IRQ by mutex. + * Support mapped I/O resources. + * Changes due to renamed library macros. + * Revision 1.6 2007/07/20 10:16:52 martin + * Reworte some IRQ macros. + * Moved some AMCC specific definitions to amccdefs.h. + * Removed obsolete code. + * Revision 1.5 2007/06/06 11:15:27Z martin + * Fixed syntax of some macros. + * Revision 1.4 2007/03/01 16:15:34Z martin + * Use generic port I/O macros. + * Revision 1.3 2004/11/09 14:44:21 martin + * Use C99 fixed-size data types if required. + * Revision 1.2 2003/04/02 07:51:37 martin + * Added support for devices with PCI_ASIC. + * Revision 1.1 2001/03/28 09:36:43Z MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _PCPSIRQ_H +#define _PCPSIRQ_H + + +#include +#include +#include + + +#define _set_port_bit( _d, _adr, _msk ) \ + _mbg_outp8( (_d), _adr, _mbg_inp8( (_d), _adr ) | (_msk) ) + +#define _clear_port_bit( _d, _adr, _msk ) \ + _mbg_outp8( (_d), _adr, _mbg_inp8( (_d), _adr ) & ~(_msk) ) + + +// Each of the macros below expects a parameter _d which is +// a pointer to the PCPS_DDEV structure which represents the +// hardware device. + +// The macros below generate code only if MCA support is enabled. + +#if _PCPS_USE_MCA + #define MCIC_IRQ 0x04 + #define _mcic_enb_reg( _r ) ( (_r) + 0x0A ) + #define _mcic_ack_reg( _r ) ( (_r) + 0x0B ) + + // No MCA dependent local variables required, and no + // MCA dependent interrupt flag to check. + + // In ISR function, pass acknowledge to the MCA + // interface chip. + #define _pcps_ddev_ack_irq_mca( _d ) \ + if ( _pcps_ddev_is_mca( _d ) ) \ + { \ + PCPS_IO_ADDR_MAPPED port = _mcic_ack_reg( _pcps_ddev_io_base_mapped( _d, 0 ) ); \ + _set_port_bit( (_d), port, MCIC_IRQ ); \ + } + + // In IRQ init function, enable IRQ on the + // interface chip. + #define _pcps_ddev_enb_irq_mca( _d ) \ + if ( _pcps_ddev_is_mca( _d ) ) \ + { \ + uint16_t port = _mcic_enb_reg( _pcps_ddev_io_base_mapped( _d, 0 ) ); \ + set_pos_reg( 4, _pcps_ddev_slot_num( _d ), active_irq.map_code ); \ + _set_port_bit( (_d), port, MCIC_IRQ ); \ + } + + // In IRQ de-init function, disable IRQ on the + // interface chip. + #define _pcps_ddev_disb_irq_mca( _d ) \ + if ( _pcps_ddev_is_mca( _d ) ) \ + { \ + uint16_t port = _mcic_enb_reg( _pcps_ddev_io_base_mapped( _d, 0 ) ); \ + _clear_port_bit( (_d), port, MCIC_IRQ ); \ + } + +#else + + // Do nothing if MCA not supported. + #define _pcps_ddev_enb_irq_mca( _d ); + #define _pcps_ddev_disb_irq_mca( _d ); + #define _pcps_ddev_ack_irq_mca( _d ); + +#endif + + + +// The macros below generate code only if PCI support is enabled. + +#if ( _PCPS_USE_PCI ) + // In ISR function, pass acknowledge to the PCI + // interface chip. + // 1.) Read PCI incoming mailbox to clear IRQ. + // 2.) Clear interrupt source, deassert INTA# signal + // and leave interrupt enabled by writing '1's to + // the interrupt flag and interrupt enable bits. + #define _pcps_ddev_ack_irq_pci( _d ) \ + if ( (_d)->irq_ack_mask ) \ + { \ + if ( _pcps_ddev_is_pci_amcc( _d ) ) \ + _mbg_inp32( (_d), _pcps_ddev_io_base_mapped( _d, 0 ) \ + + AMCC_OP_REG_IMB4 ); \ + \ + _mbg_outp32( (_d), (_d)->irq_ack_port, (_d)->irq_ack_mask ); \ + } + + // In IRQ init function, enable IRQ on the + // interface chip. + #define _pcps_ddev_enb_irq_pci( _d ) \ + if ( (_d)->irq_enb_mask ) \ + { \ + uint32_t intcsr = _mbg_inp32_to_cpu( (_d), (_d)->irq_enb_disb_port ); \ + _mbg_outp32( (_d), (_d)->irq_enb_disb_port, \ + intcsr | (_d)->irq_enb_mask ); \ + } + + // In IRQ de-init function, disable IRQ on the + // interface chip. + #define _pcps_ddev_disb_irq_pci( _d ) \ + if ( (_d)->irq_disb_mask ) \ + { \ + uint32_t intcsr = _mbg_inp32_to_cpu( (_d), (_d)->irq_enb_disb_port ); \ + _mbg_outp32( (_d), (_d)->irq_enb_disb_port, \ + intcsr & ~(_d)->irq_disb_mask ); \ + } + +#else + // Do nothing if PCI not supported. + #define _pcps_ddev_enb_irq_pci( _d ); + #define _pcps_ddev_disb_irq_pci( _d ); + #define _pcps_ddev_ack_irq_pci( _d ); +#endif + + + +// In ISR function, verify that the hardware device has +// really generated the current IRQ. +// If device is PCI the interface chip's IRQ flag is set. +// For non-PCI devices check the IRQ flag of the clock's +// status port. +#if ( _PCPS_USE_PCI ) + #define _pcps_ddev_has_gen_irq( _d ) \ + ( ( (_d)->irq_flag_mask ) ? \ + ( _mbg_inp32( (_d), (_d)->irq_flag_port ) & (_d)->irq_flag_mask ) : \ + ( _pcps_ddev_read_status_port( _d ) & PCPS_ST_IRQF ) \ + ) + +#else + #define _pcps_ddev_has_gen_irq( _d ) \ + ( _pcps_ddev_read_status_port( _d ) & PCPS_ST_IRQF ) +#endif + + +// In ISR function, acknowledge IRQ requests to the +// hardware device. +#define _pcps_ddev_ack_irq( _d ) \ +{ \ + _pcps_ddev_ack_irq_pci( _d ); \ + _pcps_ddev_ack_irq_mca( _d ); \ +} + + +// The macro below should be called at the end of the +// interrupt initialization function to instruct the +// radio clock hardware to generate IRQs. This code +// must be executed after the IRQ service function +// has been registered. +// The _cmd parameter must be one of the PCPS_IRQ_... +// codes defined in pcpsdefs.h which determine the +// IRQ rate (per second, per minute, etc.) +#define _pcps_ddev_enb_irq( _d, _cmd ) \ +{ \ + _pcps_sem_inc( _d ); \ + _pcps_ddev_enb_irq_mca( _d ); \ + _pcps_ddev_enb_irq_pci( _d ); \ + _pcps_write_byte( _d, _cmd ); \ + _pcps_sem_dec( _d ); \ +} + + +// The macro below should be called at the beginning +// of the interrupt deinitialization function to instruct +// the radio clock hardware to stop generating IRQs. +// This code must be executed before the IRQ service function +// is deregistered. +#define _pcps_ddev_disb_irq( _d ) \ +{ \ + _pcps_sem_inc( _d ); \ + _pcps_write_byte( _d, PCPS_IRQ_NONE ); \ + _pcps_ddev_disb_irq_mca( _d ); \ + _pcps_ddev_disb_irq_pci( _d ); \ + _pcps_sem_dec( _d ); \ +} + + +#endif /* _PCPSIRQ_H */ diff --git a/mbglib/common/pcpslstr.c b/mbglib/common/pcpslstr.c new file mode 100755 index 0000000..95197f3 --- /dev/null +++ b/mbglib/common/pcpslstr.c @@ -0,0 +1,500 @@ + +/************************************************************************** + * + * $Id: pcpslstr.c 1.22.1.3 2011/01/28 09:34:20 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Functions generating commonly used multi-language strings used + * with programs for Meinberg radio clocks. + * + * ----------------------------------------------------------------------- + * $Log: pcpslstr.c $ + * Revision 1.22.1.3 2011/01/28 09:34:20 martin + * Fixed build under FreeBSD. + * Revision 1.22.1.2 2010/11/05 12:55:10 martin + * Revision 1.22.1.1 2010/07/15 12:39:34 martin + * Added function sprint_utc_offs(). + * Revision 1.22 2010/06/25 13:57:57Z daniel + * Account for time zone offsets with minutes other than 0. + * Revision 1.21 2009/03/19 08:06:58Z daniel + * Added function pcps_tz_name_hr_status() to + * handle different time scales. + * Revision 1.20 2008/11/14 12:12:26Z martin + * Made some parameters for some functions const. + * Revision 1.19 2008/07/18 10:50:46Z martin + * Use _snwprintf with underscore for MS compilers. + * Revision 1.18 2008/01/30 14:51:12Z martin + * Fixed gcc compiler warnings. + * Revision 1.17 2008/01/17 09:08:12 daniel + * Added function pcps_date_time_wstr(). + * Changed function pcps_tz_name() to support MSF related time zones. + * Exclude functions using wchar_t from build if wide chars are + * not supported by the target environment. + * Revision 1.16 2007/08/14 09:08:25Z martin + * Addad a workaround for older Borland compilers which don't + * like "const" inside structures. + * Revision 1.15 2007/07/20 10:55:27Z martin + * Some modifications to avoid compiler warnings. + * Revision 1.14 2007/03/30 13:23:42 martin + * In pcps_status_strs() handle case where time has been + * set manually. + * Revision 1.13 2007/03/29 12:58:18Z martin + * Moved some definitions to the header file to make them public. + * Revision 1.12 2006/05/04 14:56:03Z martin + * Strings returned by inv_str() ar surrounded by "**"s. + * Revision 1.11 2004/11/09 15:06:44Z martin + * Type cast to avoid warning with format string. + * Revision 1.10 2004/08/18 14:58:02 martin + * pcps_tz_name() now expects a flags parameter which controls + * the format of the output string. + * Revision 1.9 2004/04/28 08:06:12Z martin + * Append DST status to TZ names labeled "UTC+xh" + * in pcps_tz_name(). + * Revision 1.8 2003/04/15 10:46:31Z martin + * Pass RECEIVER_INFO to pcps_serial_str(). + * Revision 1.7 2002/12/18 09:57:03Z martin + * Made some vaiables and definitions global. + * Revision 1.6 2002/02/19 10:03:16Z MARTIN + * New function pcps_serial_str(). + * Revision 1.5 2001/09/17 13:17:40 MARTIN + * New function pcps_tz_name_from_status() which should be used + * instead of pcps_tz_name() if offset from UTC is not known. + * New function pcps_status_strs(). + * Enhanced language support. + * Don't require myutil.h anymore. + * Added some comments. + * Source code cleanup. + * Revision 1.4 2001/08/14 11:32:24 MARTIN + * Modified pcps_date_time_str() to allow for variable + * spacing between date, time, and time zone.. + * Revision 1.3 2001/02/28 15:47:29 MARTIN + * Replaced access to some structure elements by new macro calls. + * Revision 1.2 2000/08/31 14:03:46 MARTIN + * Modified initializers for tzcode_name for non CPP-compilers. + * Revision 1.1 2000/07/21 12:14:01 MARTIN + * Initial revision + * + **************************************************************************/ + +#define _PCPSLSTR + #include +#undef _PCPSLSTR + +#include +#include +#include + +#include +#include +#include + + +#define _eos( _s ) ( &(_s)[strlen( _s )] ) + +typedef struct +{ + #if defined( __BORLANDC__ ) && ( __BORLANDC__ < 0x0500 ) + // old BCs don't like "const" inside the structure + LSTR ok; + LSTR err; + #else + CLSTR ok; + CLSTR err; + #endif +} CLSTR_STATUS; + + +static const char *tz_name_utc = TZ_NAME_UTC; +static CLSTR str_dst = { "DST", "Sommerzeit" }; + + + +/*HDR*/ +const char *inv_str( void ) +{ + static CLSTR s = { "** invalid **", "** ung" LCUE "ltig **" }; + + return _lstr( s ); + +} /* inv_str */ + + + +/*HDR*/ +int sprint_utc_offs( char *s, const char *info, long utc_offs ) +{ + int n = 0; + + // utc_offs is in [s] + char utc_offs_sign = ( utc_offs < 0 ) ? '-' : '+'; + ulong abs_utc_offs = labs( utc_offs ); + ulong utc_offs_hours = abs_utc_offs / SECS_PER_HOUR; + ulong tmp = abs_utc_offs % SECS_PER_HOUR; + ulong utc_offs_mins = tmp / MINS_PER_HOUR; + ulong utc_offs_secs = tmp % MINS_PER_HOUR; + + if ( info ) + n += sprintf( &s[n], info ); + + n += sprintf( &s[n], "%c%lu", utc_offs_sign, utc_offs_hours ); + + if ( utc_offs_mins || utc_offs_secs ) + n += sprintf( &s[n], ":%02lu", utc_offs_mins ); + + if ( utc_offs_secs ) + n += sprintf( &s[n], ":%02lu", utc_offs_secs ); + + n += sprintf( &s[n], "h" ); + + return n; + +} // sprint_utc_offs + + + +static /*HDR*/ +const char *get_tz_name( PCPS_TIME_STATUS_X pcps_status, long utc_offs, + ushort flags, int is_msf ) +{ + static char ws[40]; + const char *cp = NULL; + int n = 0; + + if ( ( pcps_status & PCPS_UTC ) && ( utc_offs == 0 ) ) + return tz_name_utc; // no offset, no DST + + if ( pcps_status & PCPS_DL_ENB ) + { + if ( utc_offs == ( 2 * SECS_PER_HOUR ) ) + { + cp = _lstr( lstr_cest ); + goto check_flags; + } + else + if ( ( utc_offs == SECS_PER_HOUR ) && is_msf ) + { + cp = _lstr( lstr_bst ); + goto check_flags; + } + } + + if ( !( pcps_status & PCPS_DL_ENB ) ) + { + if ( utc_offs == SECS_PER_HOUR ) + { + cp = _lstr( lstr_cet ); + goto check_flags; + } + else + if ( ( utc_offs == 0 ) && is_msf ) + { + cp = _lstr( lstr_gmt ); + goto check_flags; + } + } + + n = sprint_utc_offs( ws, tz_name_utc, utc_offs ); + +check_flags: + if ( cp ) + { + if ( flags == 0 ) + return cp; + + strcpy( ws, cp ); + + if ( flags & PCPS_TZ_NAME_FORCE_UTC_OFFS ) + { + n = strlen( ws ); + n += sprintf( &ws[n], "%*c(", pcps_time_tz_dist, ' ' ); + n += sprint_utc_offs( &ws[n], tz_name_utc, utc_offs ); + sprintf( &ws[n], ")" ); + } + } + + if ( flags & PCPS_TZ_NAME_APP_DST ) + { + if ( pcps_status & PCPS_DL_ENB ) + sprintf( _eos( ws ), ",%*c%s", pcps_time_tz_dist, + ' ', _lstr( str_dst ) ); + } + + return ws; +} + + + +/*HDR*/ +const char *pcps_tz_name( const PCPS_TIME *t, ushort flags, int is_msf ) +{ + return get_tz_name( t->status, t->offs_utc * SECS_PER_HOUR, flags, is_msf ); + +} // pcps_tz_name + + + +/*HDR*/ +const char *pcps_tz_name_from_hr_time( const PCPS_HR_TIME *hrt, ushort flags, int is_msf ) +{ + return get_tz_name( hrt->status, hrt->utc_offs, flags, is_msf ); + +} // pcps_tz_name_from_hr_time + + + +// The function below can be used to build a name for +// the time zone if the TIMESCALE, the UTC/DST status and the +// UTC offset are known, e.g. from plug-in clocks. + +/*HDR*/ +const char *pcps_tz_name_hr_status( const PCPS_HR_TIME *t, ushort flags, int is_msf ) +{ + static char ws[40]; + + if ( t->status & PCPS_SCALE_GPS ) + strcpy( ws, "GPS" ); + else + if ( t->status & PCPS_SCALE_TAI ) + strcpy( ws, "TAI" ); + else + return pcps_tz_name_from_hr_time( t, flags, is_msf); + + return ws; + +} // pcps_tz_name_hr_status + + + +// The function below can be used to build a name for +// the time zone if only the UTC/DST status is known +// but the UTC offset is not. This is the case, for example, +// if the Meinberg standard time string is decoded. + +/*HDR*/ +const char *pcps_tz_name_from_status( ushort status ) +{ + if ( status & PCPS_UTC ) + return tz_name_utc; + + return ( status & PCPS_DL_ENB ) ? _lstr( str_dst ) : ""; + +} // pcps_tz_name_from_status + + + +/*HDR*/ +char *pcps_date_time_str( char *s, const PCPS_TIME *t, + ushort year_limit, const char *tz_str ) +{ + if ( !_pcps_time_is_read( t ) ) + strcpy( s, str_not_avail ); + else + { + char *cp; + int i; + + _pcps_sprint_wday( s, t, language ); + cp = _eos( s ); + *cp++ = ','; + for ( i = 0; i < pcps_wday_date_dist; i++ ) + *cp++ = ' '; + _pcps_sprint_date( cp, t, year_limit ); + cp = _eos( s ); + for ( i = 0; i < pcps_date_time_dist; i++ ) + *cp++ = ' '; + _pcps_sprint_time_long( cp, t ); + + if ( tz_str ) + { + cp = _eos( s ); + for ( i = 0; i < pcps_time_tz_dist; i++ ) + *cp++ = ' '; + strcpy( cp, tz_str ); + } + } + + return s; + +} // pcps_date_time_str + + + +#if MBG_TGT_HAS_WCHAR_T && defined( MBG_TGT_WIN32 ) + +/*HDR*/ +wchar_t *pcps_date_time_wstr( wchar_t *ws, const PCPS_TIME *t, + ushort year_limit, const wchar_t *tz_str ) +{ + char stemp[80]; + wchar_t wstemp[80]; + + if ( !_pcps_time_is_read( t ) ) + mbstowcs( ws, str_not_avail, 32 ); + else + { + char *cp; + int i; + + _pcps_sprint_wday( stemp, t, language ); + cp = _eos( stemp ); + *cp++ = ','; + for ( i = 0; i < pcps_wday_date_dist; i++ ) + *cp++ = ' '; + _pcps_sprint_date( cp, t, year_limit ); + cp = _eos( stemp ); + for ( i = 0; i < pcps_date_time_dist; i++ ) + *cp++ = ' '; + _pcps_sprint_time_long( cp, t ); + + mbstowcs( wstemp, stemp, sizeof( wstemp ) ); + + if ( tz_str ) + _snwprintf( ws, sizeof( wstemp ) + 32, L"%s %s", wstemp, tz_str ); + } + + return ws; + +} // pcps_date_time_wstr + +#endif // MBG_TGT_HAS_WCHAR + + + +static /*HDR*/ +void pcps_setup_status_str( PCPS_STATUS_STR *pstr, int err_cond, + CLSTR_STATUS *pss ) +{ + pstr->is_err = err_cond != 0; + pstr->cp = _lstr( pstr->is_err ? pss->err : pss->ok ); + +} // pcps_setup_status_str + + + +// to return status strings to be displayed depending on the +// a clocks PCPS_TIME.status. + +/*HDR*/ +void pcps_status_strs( ushort status, int status_is_read, + int is_gps, PCPS_STATUS_STRS *pstrs ) +{ + CLSTR clstr_time_inval = DEFAULT_STR_TIME_INVAL; + CLSTR clstr_set_manually = DEFAULT_STR_SET_MANUALLY; + + CLSTR_STATUS lstr_dcf_has_syncd = + { DEFAULT_STR_DCF_HAS_SYNCD, DEFAULT_STR_DCF_HAS_NOT_SYNCD }; + + CLSTR_STATUS lstr_gps_syncd = + { DEFAULT_STR_GPS_SYNCD, DEFAULT_STR_GPS_NOT_SYNCD }; + + CLSTR_STATUS lstr_dcf_not_free_running = + { DEFAULT_STR_DCF_NOT_FREE_RUNNING, DEFAULT_STR_DCF_FREE_RUNNING }; + + CLSTR_STATUS lstr_gps_pos = + { DEFAULT_STR_GPS_POS_OK, DEFAULT_STR_GPS_POS_NOT_OK }; + + CLSTR clstr_ann_dst = DEFAULT_STR_ANN_DST; + CLSTR clstr_ann_ls = DEFAULT_STR_ANN_LS; + + PCPS_STATUS_STRS tmp_strs; + PCPS_STATUS_STR *pstr = &tmp_strs.s[0]; + + memset( &tmp_strs, 0, sizeof( tmp_strs ) ); + + if ( !status_is_read ) + pstr->cp = str_not_avail; + else + { + if ( status & PCPS_INVT ) + { + pstr->cp = _lstr( clstr_time_inval ); + pstr->is_err = 1; + } + else + if ( status & PCPS_IFTM ) + { + pstr->cp = _lstr( clstr_set_manually ); + pstr->is_err = 1; + } + else + { + pcps_setup_status_str( pstr, ( status & PCPS_SYNCD ) == 0, + is_gps ? &lstr_gps_syncd : &lstr_dcf_has_syncd ); + + pstr++; + + pcps_setup_status_str( pstr, ( status & PCPS_FREER ) != 0, + is_gps ? &lstr_gps_pos : &lstr_dcf_not_free_running ); + } + + pstr++; + + if ( status & PCPS_DL_ANN ) + pstr->cp = _lstr( clstr_ann_dst ); + else + if ( status & PCPS_LS_ANN ) + pstr->cp = _lstr( clstr_ann_ls ); + } + + *pstrs = tmp_strs; + +} // pcps_status_strs + + + +/*HDR*/ +char *pcps_port_str( char *s, const PCPS_DEV *pdev ) +{ + ushort port = _pcps_port_base( pdev, 0 ); + + ushort n = sprintf( s, "%3Xh", port ); + + port = _pcps_port_base( pdev, 1 ); + + if ( port ) + sprintf( &s[n], ", %3Xh", port ); + + return s; + +} // pcps_port_str + + + +/*HDR*/ +const char *pcps_tzcode_str( PCPS_TZCODE tzcode ) +{ + if ( language < N_LNG && tzcode < N_PCPS_TZCODE ) + return tzcode_name[tzcode][language]; + + return inv_str(); + +} // pcps_tzcode_str + + + +/*HDR*/ +char *pcps_serial_str( char *s, int i, const RECEIVER_PORT_CFG *p, + const RECEIVER_INFO *p_ri, int short_strs ) +{ + const PORT_SETTINGS *p_ps = &p->pii[i].port_info.port_settings; + const STR_TYPE_INFO *p_sti = &p->stii[p_ps->str_type].str_type_info; + + sprintf( s, "%lu,%s", (ulong) p_ps->parm.baud_rate, p_ps->parm.framing ); + + if ( short_strs ) + sprintf( _eos( s ), ",%s", short_mode_name[p_ps->mode] ); + else + { + if ( p_ri->n_str_type > 1 ) + sprintf( _eos( s ), ", %s", p_sti->long_name ); + + sprintf( _eos( s ), ", %s", _lstr( mode_name[p_ps->mode] ) ); + } + + return( s ); + +} // pcps_serial_str + + diff --git a/mbglib/common/pcpslstr.h b/mbglib/common/pcpslstr.h new file mode 100755 index 0000000..860ce2b --- /dev/null +++ b/mbglib/common/pcpslstr.h @@ -0,0 +1,1009 @@ + +/************************************************************************** + * + * $Id: pcpslstr.h 1.27.1.3 2011/01/28 09:34:38 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes for pcpslstr.c. + * + * ----------------------------------------------------------------------- + * $Log: pcpslstr.h $ + * Revision 1.27.1.3 2011/01/28 09:34:38 martin + * Fixed build under FreeBSD. + * Revision 1.27.1.2 2010/11/22 15:23:06 martin + * Added strings for programmable output synthesizer mode. + * Revision 1.27.1.1 2010/07/15 13:02:16 martin + * Also use ANSI umlauts under QNX. + * Updated function prototypes. + * Revision 1.27 2010/06/28 08:28:17Z stefan + * Added greek character mu. + * Corrected a spelling mistake. + * Defined umlauts as hex codes. + * Added _pcps_sprint_vernum macro which is either _dec or _hex, + * depending on the target platform. + * Revision 1.26 2010/06/25 13:58:25 daniel + * Added IgnoreTFOM related language strings + * Revision 1.25 2010/01/28 09:02:27 martin + * Added menu option name for LAN interface. + * Added German POUT mode names for DCF77_M59. + * Revision 1.24 2009/03/19 08:07:45Z daniel + * Updated function prototypes. + * Revision 1.23 2008/11/14 12:12:45Z martin + * Updated function prototypes. + * Revision 1.22 2008/01/17 09:12:41Z daniel + * Use mbg_tgt.h, specially to care about wchar_t. + * Added strings for WEZ/WESZ, BST, GMT. + * Updated function prototypes. + * Revision 1.21 2007/03/30 13:24:42Z martin + * Added initializer for status string if time has been set manually. + * Revision 1.20 2007/03/29 12:59:23Z martin + * Moved some definitions here. + * Added and modified some definitions related to TZCODE. + * Revision 1.19 2006/10/23 15:18:15Z martin + * Added some configuration warning msg texts. + * Added definitions for uppercase umlauts. + * Separated English and German initializers for some strings. + * Revision 1.18 2006/09/26 14:57:22Z martin + * Added DEFAULT_OPT_NAME_POUT. + * Revision 1.17 2000/07/02 07:02:16Z martin + * Separate English and German initializers for "invalid time". + * Revision 1.16 2006/05/23 20:13:24Z martin + * Added initializers for German POUT mode strings. + * Revision 1.15 2005/12/20 10:30:56Z martin + * Made some strings start with uppercase letters. + * Revision 1.14 2005/08/12 12:35:34Z martin + * Fixed missing comma in a macro. + * Revision 1.13 2005/03/03 08:49:38Z martin + * Modified DEFAULT_OPT_NAME_SERIAL. + * Modified DEFAULT_OPT_NAME_IRIG_... + * Added default strings for synthesizer. + * Revision 1.12 2004/11/23 09:36:12Z martin + * Fixed a typo. + * Revision 1.11 2004/11/09 15:08:08Z martin + * Defined some separate strings for English and German. + * Modified some string contents. + * Revision 1.10 2004/10/26 15:03:57 martin + * Distinguish between IRIG RX and TX strings. + * Revision 1.9 2004/08/18 14:59:04Z martin + * Defined some flag bits to control the format of the output string + * generated by pcps_tz_name(). + * Updated function prototypes. + * Revision 1.8 2004/04/07 12:49:06Z martin + * Added initializers for IRIG output cfg strings. + * Revision 1.7 2003/04/15 10:47:29Z martin + * Added initializers for IRIG menu strings. + * Updated function prototypes. + * Revision 1.6 2002/12/18 13:57:53 martin + * Some definitions and variables made global. + * Added some new macros _pcps_sprint_vernum...() + * and _pcps_sprint_dev_id(). + * Revision 1.5 2002/02/19 10:01:36Z MARTIN + * New initializers for string mode names. + * New global variables mode_name and short_mode_name. + * Updated function prototypes. + * Revision 1.4 2001/09/17 13:26:16 MARTIN + * Added definitions for PCPS_STATUS_STRS. + * Added initializers for strings. + * Added some comments. + * Updated function prototypes. + * Revision 1.3 2001/08/14 11:35:40 MARTIN + * Added initializers for commonly used mulit-language + * text strings. + * Revision 1.2 2001/02/28 15:48:34 MARTIN + * Updated function prototypes. + * Modified syntax to initialize variables. + * Revision 1.1 2000/07/21 12:15:12 MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _PCPSLSTR_H +#define _PCPSLSTR_H + + +/* Other headers to be included */ + +#include +#include +#include +#include + +#if defined MBG_TGT_HAS_WCHAR_T + #include +#endif + +#ifdef _PCPSLSTR + #define _ext + #define _DO_INIT +#else + #define _ext extern +#endif + + +/* Start of header body */ + +// upper case 'A' umlaut +#define ANSI_UC_A_UML '\xC4' // single char +#define ANSI_US_A_UML "\xC4" // string + +// upper case 'O' umlaut +#define ANSI_UC_O_UML '\xD6' // single char +#define ANSI_US_O_UML "\xD6" // string + +// upper case 'U' umlaut +#define ANSI_UC_U_UML '\xDC' // single char +#define ANSI_US_U_UML "\xDC" // string + +// lower case 'a' umlaut +#define ANSI_LC_A_UML '\xE4' // single char +#define ANSI_LS_A_UML "\xE4" // string + +// lower case 'o' umlaut +#define ANSI_LC_O_UML '\xF6' // single char +#define ANSI_LS_O_UML "\xF6" // string + +// lower case 'u' umlaut +#define ANSI_LC_U_UML '\xFC' // single char +#define ANSI_LS_U_UML "\xFC" // string + +// 'sz' umlaut +#define ANSI_LC_SZ_UML '\xDF' // single char +#define ANSI_LS_SZ_UML "\xDF" // string + +// degree character +#define ANSI_C_DEGREE '\xB0' // single char +#define ANSI_S_DEGREE "\xB0" // string + +// greek mu character +#define ANSI_C_MU '\xB5' //single char +#define ANSI_S_MU "\xB5" //string + +#if defined( MBG_TGT_WIN32 ) \ + || defined( MBG_TGT_UNIX ) \ + || defined( MBG_TGT_QNX ) + #define DEFAULT_PCPS_WDAY_DATE_DIST 1 + #define DEFAULT_PCPS_DATE_TIME_DIST 2 + #define DEFAULT_PCPS_TIME_TZ_DIST 1 + + #define UCAE ANSI_US_A_UML + #define UCOE ANSI_US_O_UML + #define UCUE ANSI_US_U_UML + + #define LCAE ANSI_LS_A_UML + #define LCOE ANSI_LS_O_UML + #define LCUE ANSI_LS_U_UML + + #define LCSZ ANSI_LS_SZ_UML + #define DEG ANSI_S_DEGREE + #define MU ANSI_S_MU +#else + #define DEFAULT_PCPS_WDAY_DATE_DIST 1 + #define DEFAULT_PCPS_DATE_TIME_DIST 2 + #define DEFAULT_PCPS_TIME_TZ_DIST 1 + + #define UCAE "\x8E" + #define UCOE "\x99" + #define UCUE "\x9A" + + #define LCAE "\x84" + #define LCOE "\x94" + #define LCUE "\x81" + + #define LCSZ "\xE1" + #define DEG "\xF8" + #define MU "\xE6" +#endif + + +// The flags defined below can be passed to pcps_tz_name() +// in order to control the generation of time zone names + +enum +{ + PCPS_TZ_NAME_BIT_FORCE_UTC_OFFS, // always print "UTC+offs" + PCPS_TZ_NAME_BIT_APP_DST, // append DST status + N_PCPS_TZ_NAME_FLAG +}; + +// bit masks corresponding to the flags above +#define PCPS_TZ_NAME_FORCE_UTC_OFFS ( 1UL << PCPS_TZ_NAME_BIT_FORCE_UTC_OFFS ) +#define PCPS_TZ_NAME_APP_DST ( 1UL << PCPS_TZ_NAME_BIT_APP_DST ) + + +// The definitions below are used with pcps_get_status_strs(). + +#define N_PCPS_STATUS_STR 3 + +typedef struct +{ + const char *cp; + int is_err; +} PCPS_STATUS_STR; + +typedef struct +{ + PCPS_STATUS_STR s[N_PCPS_STATUS_STR]; +} PCPS_STATUS_STRS; + + +// initializers for commonly use multi-language strings +// (type: CLSTR ) + + +// time adjustment window + +#define DEFAULT_STR_TIME_ADJ_STATUS \ +{ \ + "Time Adjustment Status", \ + "Status der Zeitkontrolle" \ +} + +#define DEFAULT_STR_SYS_TIME \ +{ \ + "System Time:", \ + "Systemzeit:" \ +} + +#define DEFAULT_STR_REF_TIME \ +{ \ + "Reference Time:", \ + "Referenzzeit:" \ +} + +#define DEFAULT_STR_DELTA_TIME \ +{ \ + "Difference:", \ + "Zeitdifferenz:" \ +} + +#define DEFAULT_STR_LAST_CORR \ +{ \ + "Last Correction:", \ + "Letzte Korrektur:" \ +} + +#define DEFAULT_STR_WAIT_SYNC \ +{ \ + "Waiting for Sync After Reset ...", \ + "Warte auf Sync. nach Reset ..." \ +} + + +// ref time window + +#define DEFAULT_STR_REF_TIME_INFO \ +{ \ + "Reference Time Info", \ + "Referenzzeit" \ +} + +#define DEFAULT_STR_REF_SRC_LABEL \ +{ \ + "Time Source:", \ + "Funkuhr ID:" \ +} + +#define DEFAULT_STR_REF_SYNC_LABEL \ +{ \ + "Last Sync.:", \ + "Letzte Sync.:" \ +} + + +// Clock status messages: + +// Time is not valid (i.e. after batt. empty). +#define DEFAULT_STR_TIME_INVAL_EN \ + "Ref. Time is Invalid" + +#define DEFAULT_STR_TIME_INVAL_DE \ + "Referenzzeit nicht g" LCUE "ltig" + +#define DEFAULT_STR_TIME_INVAL \ +{ \ + DEFAULT_STR_TIME_INVAL_EN, \ + DEFAULT_STR_TIME_INVAL_DE \ +} + +// on-board time has been set manually +#define DEFAULT_STR_SET_MANUALLY \ +{ \ + "Time has been set manually", \ + "Zeit wurde manuell gesetzt" \ +} + +// DCF77 receiver has synch'd at least once +// after reset. +#define DEFAULT_STR_DCF_HAS_SYNCD \ +{ \ + "Synchronized after last RESET", \ + "Sync. nach RESET ist erfolgt" \ +} + +// DCF77 receiver has not synch'd after reset. +#define DEFAULT_STR_DCF_HAS_NOT_SYNCD \ +{ \ + "Not synchronized after last RESET", \ + "Sync. nach RESET noch nicht erfolgt" \ +} + +// DCF77 receiver currently runs on XTAL. +#define DEFAULT_STR_DCF_FREE_RUNNING \ +{ \ + "Clock running on Xtal oscillator", \ + "Funkuhr l" LCAE "uft frei auf Quarzbasis" \ +} + +// DCF77 receiver is currently synchronized. +#define DEFAULT_STR_DCF_NOT_FREE_RUNNING \ +{ \ + "Clock is synchronized", \ + "Senderf" LCUE "hrung" \ +} + +// GPS receiver is currently synchronized. +#define DEFAULT_STR_GPS_SYNCD \ +{ \ + "Time is synchronized", \ + "Zeitsynchronisation ist erfolgt" \ +} + +// GPS receiver is currently synchronized. +#define DEFAULT_STR_GPS_NOT_SYNCD \ +{ \ + "Time not synchronized", \ + "Zeit ist nicht synchron" \ +} + +// GPS receiver has verified its position. +#define DEFAULT_STR_GPS_POS_OK \ +{ \ + "Receiver position has been verified", \ + "Positionbestimmung durchgef" LCUE "hrt" \ +} + +// GPS receiver has not verified its position. +#define DEFAULT_STR_GPS_POS_NOT_OK \ +{ \ + "Receiver pos. not verified", \ + "Position nicht gepr" LCUE "ft" \ +} + +// Announcement of DST change. +#define DEFAULT_STR_ANN_DST \ +{ \ + "Change in Daylight Saving Announced", \ + "Zeitumschaltung angek" LCUE "ndigt" \ +} + +// Announcement of leap second. +#define DEFAULT_STR_ANN_LS \ +{ \ + "Leap Second Announced", \ + "Schaltsekunde angek" LCUE "ndigt" \ +} + + +// menu option: setup (title) + +#define DEFAULT_OPT_NAME_SETUP_EN \ + "Setup" + +#define DEFAULT_OPT_NAME_SETUP_DE \ + "Einstellungen" + +#define DEFAULT_OPT_NAME_SETUP \ +{ \ + DEFAULT_OPT_NAME_SETUP_EN, \ + DEFAULT_OPT_NAME_SETUP_DE \ +} + + +// menu option: setup date/time + +#define DEFAULT_OPT_NAME_SET_TIME_EN \ + "Radio Clock's Date/Time" + +#define DEFAULT_OPT_NAME_SET_TIME_DE \ + "Datum/Zeit der Funkuhr" + +#define DEFAULT_OPT_NAME_SET_TIME \ +{ \ + DEFAULT_OPT_NAME_SET_TIME_EN, \ + DEFAULT_OPT_NAME_SET_TIME_DE \ +} + +#define DEFAULT_STR_NEW_DATE \ +{ \ + "New date", \ + "Neues Datum" \ +} + +#define DEFAULT_STR_NEW_TIME \ +{ \ + "New time", \ + "Neue Zeit" \ +} + + +// menu option: setup time zone + +#define TZ_NAME_UTC "UTC" + +#define TZ_NAME_MEZ "MEZ" +#define TZ_NAME_MESZ "MESZ" +#define TZ_NAME_CET "CET" +#define TZ_NAME_CEST "CEST" + +#define TZ_NAME_OEZ "OEZ" +#define TZ_NAME_OESZ "OESZ" +#define TZ_NAME_EET "EET" +#define TZ_NAME_EEST "EEST" + +#define TZ_NAME_WEZ "WEZ" +#define TZ_NAME_WESZ "WESZ" +#define TZ_NAME_GMT "GMT" +#define TZ_NAME_BST "BST" + +#define DEFAULT_OPT_NAME_TZ \ +{ \ + "Radio Clock's Time Zone", \ + "Zeitzone der Funkuhr" \ +} + + +// menu option: setup time zone + +#define DEFAULT_TZCODE_NAME_CET_CEST \ +{ \ + TZ_NAME_CET "/" TZ_NAME_CEST, \ + TZ_NAME_MEZ "/" TZ_NAME_MESZ \ +} + +#define DEFAULT_TZCODE_HINT_CET_CEST \ +{ \ + "Central European Time or Summer Time, as broadcasted by DCF77", \ + "Mitteleurop" LCAE "ische Zeit oder Sommerzeit, wie von DCF77 gesendet" \ +} + +#define DEFAULT_TZCODE_NAME_GMT_BST \ +{ \ + TZ_NAME_GMT "/" TZ_NAME_BST, \ + TZ_NAME_WEZ "/" TZ_NAME_WESZ \ +} + +#define DEFAULT_TZCODE_HINT_GMT_BST \ +{ \ + "Greenwich Mean Time or British Summer Time, as broadcasted by MSF", \ + "Westeurop" LCAE "ische Zeit oder britische Sommerzeit, wie von MSF gesendet" \ +} + + + +#define DEFAULT_TZCODE_NAME_CET \ +{ \ + "always " TZ_NAME_CET, \ + "immer " TZ_NAME_MEZ \ +} + +#define DEFAULT_TZCODE_HINT_CET \ +{ \ + "always CET (UTC+1h), daylight saving suppressed", \ + "immer MEZ (UTC+1h), Sommerzeit wird unterdr" LCUE "ckt" \ +} + + +#define DEFAULT_TZCODE_NAME_UTC \ +{ \ + TZ_NAME_UTC, \ + TZ_NAME_UTC \ +} + +#define DEFAULT_TZCODE_HINT_UTC \ +{ \ + "always UTC", \ + "immer UTC" \ +} + + +#define DEFAULT_TZCODE_NAME_EET_EEST \ +{ \ + TZ_NAME_EET "/" TZ_NAME_EEST, \ + TZ_NAME_OEZ "/" TZ_NAME_OESZ \ +} + +#define DEFAULT_TZCODE_HINT_EET_EEST \ +{ \ + "East European Time, CET/CEST + 1h", \ + "Osteurop" LCAE "ische Zeit, MEZ/MESZ + 1h" \ +} + + +#define DEFAULT_TZCODE_NAMES \ +{ \ + DEFAULT_TZCODE_NAME_CET_CEST, \ + DEFAULT_TZCODE_NAME_CET, \ + DEFAULT_TZCODE_NAME_UTC, \ + DEFAULT_TZCODE_NAME_EET_EEST \ +} + +#define DEFAULT_TZCODE_HINTS \ +{ \ + DEFAULT_TZCODE_HINT_CET_CEST, \ + DEFAULT_TZCODE_HINT_CET, \ + DEFAULT_TZCODE_HINT_UTC, \ + DEFAULT_TZCODE_HINT_EET_EEST \ +} + + +// menu option: setup serial parameters + +#define DEFAULT_OPT_NAME_SERIAL \ +{ \ + "On-Board Serial Ports", \ + "Serielle Schnittstellen der Karte" \ +} + + +// menu option: setup enable flags + +#define DEFAULT_OPT_NAME_EF \ +{ \ + "Enable Outputs", \ + "Freischaltung der Ausg" LCAE "nge" \ +} + + +// menu option: setup length of antenna cable + +#define DEFAULT_OPT_NAME_CAB_LEN \ +{ \ + "Antenna Cable", \ + "Antennenkabel" \ +} + + +// menu option: setup IRIG config + +#define DEFAULT_OPT_NAME_IRIG_TX_EN "IRIG Output" +#define DEFAULT_OPT_NAME_IRIG_TX_DE "IRIG-Ausgang" + +#define DEFAULT_OPT_NAME_IRIG_TX \ +{ \ + DEFAULT_OPT_NAME_IRIG_TX_EN, \ + DEFAULT_OPT_NAME_IRIG_TX_DE \ +} + + +#define DEFAULT_OPT_NAME_IRIG_RX_EN "IRIG Input" +#define DEFAULT_OPT_NAME_IRIG_RX_DE "IRIG-Eingang" + +#define DEFAULT_OPT_NAME_IRIG_RX \ +{ \ + DEFAULT_OPT_NAME_IRIG_RX_EN, \ + DEFAULT_OPT_NAME_IRIG_RX_DE \ +} + + +#define DEFAULT_STR_IRIG_FMT_EN "IRIG Code Format" +#define DEFAULT_STR_IRIG_FMT_DE "IRIG Code-Format" + +#define DEFAULT_STR_IRIG_FMT \ +{ \ + DEFAULT_STR_IRIG_FMT_EN, \ + DEFAULT_STR_IRIG_FMT_DE \ +} + + +#define DEFAULT_STR_IRIG_OFFS_EN "IRIG Time Offset from UTC" +#define DEFAULT_STR_IRIG_OFFS_DE "IRIG-Zeitoffset zu UTC" + +#define DEFAULT_STR_IRIG_OFFS \ +{ \ + DEFAULT_STR_IRIG_OFFS_EN, \ + DEFAULT_STR_IRIG_OFFS_DE \ +} + + +#define DEFAULT_STR_IRIG_TIMESTR_UTC_EN "Send serial UTC" +#define DEFAULT_STR_IRIG_TIMESTR_UTC_DE "Seriell UTC ausgeben" + +#define DEFAULT_STR_IRIG_TIMESTR_UTC \ +{ \ + DEFAULT_STR_IRIG_TIMESTR_UTC_EN, \ + DEFAULT_STR_IRIG_TIMESTR_UTC_DE \ +} + + +#define DEFAULT_STR_IRIG_OUTPUT_LOC_TM_EN "Transmit local time instead of UTC" +#define DEFAULT_STR_IRIG_OUTPUT_LOC_TM_DE "Ortszeit statt UTC aussenden" + +#define DEFAULT_STR_IRIG_OUTPUT_LOC_TM \ +{ \ + DEFAULT_STR_IRIG_OUTPUT_LOC_TM_EN, \ + DEFAULT_STR_IRIG_OUTPUT_LOC_TM_DE \ +} + +#define DEFAULT_IGNORE_RX_TFOM_EN "Ignore TFOM" +#define DEFAULT_IGNORE_RX_TFOM_DE "Ignoriere TFOM" + +#define DEFAULT_IGNORE_RX_TFOM \ +{ \ + DEFAULT_IGNORE_RX_TFOM_EN, \ + DEFAULT_IGNORE_RX_TFOM_DE \ +} + +#define DEFAULT_STR_TFOM_ALWAYS_SYNC_EN "Output TFOM always as 'sync'" +#define DEFAULT_STR_TFOM_ALWAYS_SYNC_DE "TFOM immer als 'sync' ausgeben" + +#define DEFAULT_STR_TFOM_ALWAYS_SYNC \ +{ \ + DEFAULT_STR_TFOM_ALWAYS_SYNC_EN, \ + DEFAULT_STR_TFOM_ALWAYS_SYNC_DE \ +} + + +#define DEFAULT_STR_IRIG_NOT_CFGD_EN \ + "The IRIG receiver has not yet been configured!\n" \ + "\n" \ + "Please make sure the correct " DEFAULT_STR_IRIG_FMT_EN " has been\n" \ + "selected, and enter the correct " DEFAULT_STR_IRIG_OFFS_EN "\n" \ + "according to the settings of the IRIG generator." + +#define DEFAULT_STR_IRIG_NOT_CFGD_DE \ + "Der IRIG-Empf" LCAE "nger wurde noch nicht konfiguriert!\n" \ + "\n" \ + "Das ausgew" LCAE "hlte " DEFAULT_STR_IRIG_FMT_DE " sowie der\n" \ + DEFAULT_STR_IRIG_OFFS_DE " m" LCUE "ssen den Einstellungen\n" \ + "des verwendeten IRIG-Generators entsprechen." + +#define DEFAULT_STR_IRIG_NOT_CFGD \ +{ \ + DEFAULT_STR_IRIG_NOT_CFGD_EN, \ + DEFAULT_STR_IRIG_NOT_CFGD_DE \ +} + + +#define DEFAULT_STR_IRIG_INVT_EN \ + "Please note that the IRIG receiver status may read\n" \ + "\"" DEFAULT_STR_TIME_INVAL_EN "\" if the receiver's on-board date\n" \ + "does not correspond to the date (day-of-year number)\n" \ + "transmitted by the IRIG source." + +#define DEFAULT_STR_IRIG_INVT_DE \ + "Wenn im Status des IRIG-Empf" LCAE "ngers \"" DEFAULT_STR_TIME_INVAL_DE "\"\n" \ + "angezeigt wird, kann der Grund daf" LCUE "r sein, dass das Datum\n" \ + "auf der Einsteckkarte nicht mit dem vom IRIG-Generator\n" \ + "gesendeten Datum (bzw. dem Jahrestag) " LCUE "bereinstimmt." \ + +#define DEFAULT_STR_IRIG_INVT \ +{ \ + DEFAULT_STR_IRIG_INVT_EN, \ + DEFAULT_STR_IRIG_INVT_DE \ +} + + +// menu option: programmable outputs + +#define DEFAULT_OPT_NAME_POUT \ +{ \ + "Programmable Pulse Outputs", \ + "Programmierbare Schaltausg" LCAE "nge" \ +} + + +// menu option: frequency synthesizer + +#define DEFAULT_OPT_NAME_SYNTH \ +{ \ + "Frequency Synthesizer", \ + "Frequenz-Synthesizer" \ +} + +#define DEFAULT_STR_SYNTH_FREQ \ +{ \ + "Frequency", \ + "Frequenz" \ +} + +#define DEFAULT_STR_SYNTH_PHASE \ +{ \ + "Phase", \ + NULL \ +} + + +// menu option: LAN interface + +#define DEFAULT_OPT_NAME_LAN_INTF_EN "LAN Interface" +#define DEFAULT_OPT_NAME_LAN_INTF_DE "Netzwerkschnittstelle" + +#define DEFAULT_OPT_NAME_LAN_INTF \ +{ \ + DEFAULT_OPT_NAME_LAN_INTF_EN, \ + DEFAULT_OPT_NAME_LAN_INTF_DE \ +} + + + +/* + * Default initializers for German mode string names. + * English strings are defined in in gpsdefs.h. + */ +#define GER_MODE_NAME_STR_ON_REQ "nur auf Anfrage '?'" +#define GER_MODE_NAME_STR_PER_SEC "sek" LCUE "ndlich" +#define GER_MODE_NAME_STR_PER_MIN "min" LCUE "tlich" +#define GER_MODE_NAME_STR_AUTO "automatisch" +#define GER_MODE_NAME_STR_ON_REQ_SEC "sek" LCUE "ndlich nach Anfrage" + +#define DEFAULT_MODE_NAMES \ +{ \ + { ENG_MODE_NAME_STR_ON_REQ, GER_MODE_NAME_STR_ON_REQ }, \ + { ENG_MODE_NAME_STR_PER_SEC, GER_MODE_NAME_STR_PER_SEC }, \ + { ENG_MODE_NAME_STR_PER_MIN, GER_MODE_NAME_STR_PER_MIN }, \ + { ENG_MODE_NAME_STR_AUTO, GER_MODE_NAME_STR_AUTO }, \ + { ENG_MODE_NAME_STR_ON_REQ_SEC, GER_MODE_NAME_STR_ON_REQ_SEC } \ +} + + +/* + * Default initializers for German pulse output mode string names. + * English strings are defined in in gpsdefs.h. + */ +#define GER_POUT_NAME_IDLE "Nicht verwendet" +#define GER_POUT_NAME_TIMER "Zeitschaltung" +#define GER_POUT_NAME_SINGLE_SHOT "Einzelimpuls" +#define GER_POUT_NAME_CYCLIC_PULSE "Zyklischer Impuls" +#define GER_POUT_NAME_PER_SEC "Sek" LCUE "ndlicher Impuls" +#define GER_POUT_NAME_PER_MIN "Min" LCUE "tlicher Impuls" +#define GER_POUT_NAME_PER_HOUR "St" LCUE "ndlicher Impuls" +#define GER_POUT_NAME_DCF77 "DCF77-Zeitmarken" +#define GER_POUT_NAME_POS_OK "Position OK" +#define GER_POUT_NAME_TIME_SYNC "Zeit synchron" +#define GER_POUT_NAME_ALL_SYNC "alles synchron" +#define GER_POUT_NAME_TIMECODE "DCLS-Zeitcode" +#define GER_POUT_NAME_TIMESTR "COM-Zeittelegramm" +#define GER_POUT_NAME_10MHZ "Festfrequenz 10 MHz" +#define GER_POUT_NAME_DCF77_M59 "DCF77-Zeitmarken mit 59. Impuls" +#define GER_POUT_NAME_SYNTH "Frequenz-Synthesizer" + +#define DEFAULT_GER_POUT_NAMES \ +{ \ + GER_POUT_NAME_IDLE, \ + GER_POUT_NAME_TIMER, \ + GER_POUT_NAME_SINGLE_SHOT, \ + GER_POUT_NAME_CYCLIC_PULSE, \ + GER_POUT_NAME_PER_SEC, \ + GER_POUT_NAME_PER_MIN, \ + GER_POUT_NAME_PER_HOUR, \ + GER_POUT_NAME_DCF77, \ + GER_POUT_NAME_POS_OK, \ + GER_POUT_NAME_TIME_SYNC, \ + GER_POUT_NAME_ALL_SYNC, \ + GER_POUT_NAME_TIMECODE, \ + GER_POUT_NAME_TIMESTR, \ + GER_POUT_NAME_10MHZ, \ + GER_POUT_NAME_DCF77_M59, \ + GER_POUT_NAME_SYNTH \ +} + +/* + * Default initializers for German pulse output mode hints. + * English strings are defined in in gpsdefs.h. + */ +#define GER_POUT_HINT_IDLE "Konstanter Ausgangspegel" +#define GER_POUT_HINT_TIMER "Schalten zu den angegebenen Zeiten" +#define GER_POUT_HINT_SINGLE_SHOT "Einzelner Impuls mit angegebener L" LCAE "nge" +#define GER_POUT_HINT_CYCLIC_PULSE "Impulse wiederholt nach angegebenem Intervall" +#define GER_POUT_HINT_PER_SEC "Impuls zu Beginn jeder Sekunde" +#define GER_POUT_HINT_PER_MIN "Impuls zu Beginn jeder Minute" +#define GER_POUT_HINT_PER_HOUR "Impuls zu Beginn jeder Stunde" +#define GER_POUT_HINT_DCF77 "DCF77-kompatible Zeitmarken" +#define GER_POUT_HINT_POS_OK "Schalten, wenn Empf" LCAE "ngerposition " LCUE "berpr" LCUE "ft" +#define GER_POUT_HINT_TIME_SYNC "Schalten, wenn Zeit synchron" +#define GER_POUT_HINT_ALL_SYNC "Schalten, wenn Zeit synchron und Position " LCUE "berpr" LCUE "ft" +#define GER_POUT_HINT_TIMECODE "Unmodulierter Zeitcode des IRIG-Ausgangs" +#define GER_POUT_HINT_TIMESTR "Zeittelegramm der seriellen Schnittstelle der Karte duplizieren" +#define GER_POUT_HINT_10MHZ "Feste Ausgangsfrequenz 10 MHz" +#define GER_POUT_HINT_DCF77_M59 "Zeitmarken wie DCF77, aber mit 500 ms Impuls in 59. Sekunde" +#define GER_POUT_HINT_SYNTH "Durch programmierbaren Synthesizer erzeugte Frequenz" + +#define DEFAULT_GER_POUT_HINTS \ +{ \ + GER_POUT_HINT_IDLE, \ + GER_POUT_HINT_TIMER, \ + GER_POUT_HINT_SINGLE_SHOT, \ + GER_POUT_HINT_CYCLIC_PULSE, \ + GER_POUT_HINT_PER_SEC, \ + GER_POUT_HINT_PER_MIN, \ + GER_POUT_HINT_PER_HOUR, \ + GER_POUT_HINT_DCF77, \ + GER_POUT_HINT_POS_OK, \ + GER_POUT_HINT_TIME_SYNC, \ + GER_POUT_HINT_ALL_SYNC, \ + GER_POUT_HINT_TIMECODE, \ + GER_POUT_HINT_TIMESTR, \ + GER_POUT_HINT_10MHZ, \ + GER_POUT_HINT_DCF77_M59, \ + GER_POUT_HINT_SYNTH \ +} + + + +// some macros which generate proper function calls + +#define _pcps_sprint_vernum_dec( _s, _v ) \ + sprintf( (_s), "v%u.%02u", \ + ( (unsigned) (_v) ) / 100, \ + ( (unsigned) (_v) ) % 100 ) + +#define _pcps_sprint_vernum_hex( _s, _v ) \ + sprintf( (_s), "v%X.%02X", \ + ( (unsigned) (_v) ) >> 8, \ + ( (unsigned) (_v) ) & 0xFF ) + +#if defined( MBG_TGT_WIN32 ) + #define _pcps_sprint_vernum _pcps_sprint_vernum_dec +#else + #define _pcps_sprint_vernum _pcps_sprint_vernum_hex +#endif + + +#define _pcps_sprint_dev_id( _s, _n ) \ + sprintf( (_s), "%04Xh", _n ) + + +#define _pcps_sprint_wday( _s, _t, _l ) \ + sprint_ctry_wday( (_s), _wday_mon17_to_sun06( (_t)->wday ), (_l) ) + +#define _pcps_sprint_date( _s, _t, _yl ) \ + sprint_ctry_dt( (_s), (_t)->mday, (_t)->month, \ + pcps_exp_year( (_t)->year, (_yl) ) ) + +#define _pcps_sprint_time( _s, _t ) \ + sprint_ctry_tm( (_s), (_t)->hour, (_t)->min, (_t)->sec ) + +#define _pcps_sprint_time_long( _s, _t ) \ + sprint_ctry_tm_long( (_s), (_t)->hour, (_t)->min, (_t)->sec, (_t)->sec100, 2 ) + + +#define _cput_pcps_date( _t, _yl ) \ +{ \ + char s[80]; \ + _pcps_sprint_date( s, (_t), (_yl) ); \ + cputs( s ); \ +} + +#define _cput_pcps_time( _t ) \ +{ \ + char s[80]; \ + _pcps_sprint_time( s, (_t) ); \ + cputs( s ); \ +} + +#define _cput_pcps_time_long( _t ) \ +{ \ + char s[80]; \ + _pcps_sprint_time_long( s, (_t) ); \ + cputs( s ); \ +} + +#define _cput_pcps_date_and_time( _t, _yl, _tz ) \ +{ \ + char s[80]; \ + cputs( pcps_date_time_str( s, (_t), (_yl), (_tz) ) ); \ +} + + +_ext const char *str_not_avail +#ifdef _DO_INIT + = "N/A" +#endif +; + + +_ext CLSTR lstr_cet +#ifdef _DO_INIT + = { TZ_NAME_CET, TZ_NAME_MEZ } +#endif +; + + +_ext CLSTR lstr_cest +#ifdef _DO_INIT + = { TZ_NAME_CEST, TZ_NAME_MESZ } +#endif +; + +_ext CLSTR lstr_gmt +#ifdef _DO_INIT + = { TZ_NAME_GMT, TZ_NAME_WEZ } +#endif +; + + +_ext CLSTR lstr_bst +#ifdef _DO_INIT + = { TZ_NAME_BST, TZ_NAME_WESZ } +#endif +; + +_ext CLSTR tzcode_name[N_PCPS_TZCODE] +#ifdef _DO_INIT + = DEFAULT_TZCODE_NAMES +#endif +; + + +_ext int pcps_wday_date_dist +#ifdef _DO_INIT + = DEFAULT_PCPS_WDAY_DATE_DIST +#endif +; + + +_ext int pcps_date_time_dist +#ifdef _DO_INIT + = DEFAULT_PCPS_DATE_TIME_DIST +#endif +; + + +_ext int pcps_time_tz_dist +#ifdef _DO_INIT + = DEFAULT_PCPS_TIME_TZ_DIST +#endif +; + + +_ext const char *mode_name[N_STR_MODE][N_LNG] +#ifdef _DO_INIT + = DEFAULT_MODE_NAMES +#endif +; + + +_ext const char *short_mode_name[N_STR_MODE] +#ifdef _DO_INIT + = DEFAULT_SHORT_MODE_NAMES +#endif +; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + + const char *inv_str( void ) ; + int sprint_utc_offs( char *s, const char *info, long utc_offs ) ; + const char *pcps_tz_name( const PCPS_TIME *t, ushort flags, int is_msf ) ; + const char *pcps_tz_name_from_hr_time( const PCPS_HR_TIME *hrt, ushort flags, int is_msf ) ; + const char *pcps_tz_name_hr_status( const PCPS_HR_TIME *t, ushort flags, int is_msf ) ; + const char *pcps_tz_name_from_status( ushort status ) ; + char *pcps_date_time_str( char *s, const PCPS_TIME *t, ushort year_limit, const char *tz_str ) ; + wchar_t *pcps_date_time_wstr( wchar_t *ws, const PCPS_TIME *t, ushort year_limit, const wchar_t *tz_str ) ; + void pcps_status_strs( ushort status, int status_is_read, int is_gps, PCPS_STATUS_STRS *pstrs ) ; + char *pcps_port_str( char *s, const PCPS_DEV *pdev ) ; + const char *pcps_tzcode_str( PCPS_TZCODE tzcode ) ; + char *pcps_serial_str( char *s, int i, const RECEIVER_PORT_CFG *p, const RECEIVER_INFO *p_ri, int short_strs ) ; + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + +/* End of header body */ + +#undef _ext +#undef _DO_INIT + +#endif /* _PCPSLSTR_H */ + diff --git a/mbglib/common/pcpsmktm.c b/mbglib/common/pcpsmktm.c new file mode 100755 index 0000000..212dfb3 --- /dev/null +++ b/mbglib/common/pcpsmktm.c @@ -0,0 +1,53 @@ + +/************************************************************************** + * + * $Id: pcpsmktm.c 1.4 2006/12/14 15:27:49 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Function to convert PCPS_TIME to Unix time (seconds since 1970) + * + * ----------------------------------------------------------------------- + * $Log: pcpsmktm.c $ + * Revision 1.4 2006/12/14 15:27:49 martin + * Include time.h. + * Revision 1.3 2006/08/22 09:10:03 martin + * Renamed function totalsec() to mbg_mktime() and moved it + * to a separate file mbgmktm.c. + * Revision 1.2 2001/08/14 11:58:08 MARTIN + * Included sys/time.h for time_t definition. + * Revision 1.1 2001/02/02 15:30:09 MARTIN + * + **************************************************************************/ + +#define _PCPSMKTM + #include +#undef _PCPSMKTM + +#include + +#include + + +/*HDR*/ +long pcps_mktime( PCPS_TIME *tp ) +{ + time_t secs; + int year = tp->year; + + if ( year < 70 ) + year += 100; + + secs = mbg_mktime( year, tp->month - 1, tp->mday - 1, + tp->hour, tp->min, tp->sec ); + + if ( secs != -1 ) + secs -= tp->offs_utc * 3600; + + return( secs ); + +} // pcps_mktime + + + diff --git a/mbglib/common/pcpsmktm.h b/mbglib/common/pcpsmktm.h new file mode 100755 index 0000000..efcc2df --- /dev/null +++ b/mbglib/common/pcpsmktm.h @@ -0,0 +1,62 @@ + +/************************************************************************** + * + * $Id: pcpsmktm.h 1.1 2001/02/02 15:31:07 MARTIN REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes for pcpsmktm.c. + * + * ----------------------------------------------------------------------- + * $Log: pcpsmktm.h $ + * Revision 1.1 2001/02/02 15:31:07 MARTIN + * + **************************************************************************/ + +#ifndef _PCPSMKTM_H +#define _PCPSMKTM_H + + +/* Other headers to be included */ + +#include + + +#ifdef _PCPSMKTM + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + +//_ext PCPS_TIME tx; + +/* End of header body */ + +#undef _ext + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + + long pcps_mktime( PCPS_TIME *tp ) ; + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +#endif /* _PCPSMKTM_H */ diff --git a/mbglib/common/pcpsutil.c b/mbglib/common/pcpsutil.c new file mode 100755 index 0000000..e35ea25 --- /dev/null +++ b/mbglib/common/pcpsutil.c @@ -0,0 +1,160 @@ + +/************************************************************************** + * + * $Id: pcpsutil.c 1.13 2009/03/09 13:39:45 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Utility functions used with programs for Meinberg radio clocks. + * + * ----------------------------------------------------------------------- + * $Log: pcpsutil.c $ + * Revision 1.13 2009/03/09 13:39:45 martin + * Made pcps_exp_year() an inline function. + * Revision 1.12 2008/12/10 19:59:48 martin + * Made frac_sec_from_bin() an inline function. + * Revision 1.11 2008/11/25 10:00:25 martin + * Use new definitions of fraction conversion type and scale + * from pcpsdefs.h. + * Revision 1.10 2006/06/29 10:38:24Z martin + * New function pcps_time_is_valid(). + * Modified pcps_str_to_port(), doesn't add a 0 entry to the list anymore. + * Fixed a compiler warning related to type conversion. + * Revision 1.9 2005/01/14 10:14:31Z martin + * Changed type of ISA port addr to int. + * Revision 1.8 2004/11/09 14:29:27Z martin + * Rewrote functions using C99 fixed-size definitions. + * Revision 1.7 2003/04/17 10:08:59Z martin + * Added some type casts to fix compiler warnings. + * Revision 1.6 2001/11/28 14:39:16Z MARTIN + * In frac_sec_from_bin(), define the divisor as floating point + * constant to avoid a domain errors on 16 bit systems. + * Revision 1.5 2001/09/17 07:28:01 MARTIN + * New function frac_sec_from_bin() to convert + * PCPS_HR_TIME fractions. + * Revision 1.4 2001/03/01 14:01:09 MARTIN + * Modified parameters for pcps_setup_isa_ports(). + * Revision 1.3 2000/08/31 14:05:30 MARTIN + * Replaced pcps_str_to_port() by pcps_setup_isa_ports(). + * Revision 1.2 2000/07/21 13:42:54 MARTIN + * Initial revision + * + **************************************************************************/ + +#define _PCPSUTIL + #include +#undef _PCPSUTIL + +#include + + +/*-------------------------------------------------------------- + * Name: pcps_time_is_valid() + * + * Purpose: Pack a structure with serial port parameters + * + * Input/Output: p address of a structure holding both the + * packed and unpacked information + * + * Ret value: -- + *-------------------------------------------------------------*/ + +/*HDR*/ +int pcps_time_is_valid( const PCPS_TIME *p ) +{ + return ( p->sec100 <= 99 ) + && ( p->sec <= 60 ) /* allow for leap second */ + && ( p->min <= 59 ) + && ( p->hour <= 23 ) + && ( p->mday >= 1 ) && ( p->mday <= 31 ) + && ( p->wday >= 1 ) && ( p->wday <= 7 ) + && ( p->month >= 1 ) && ( p->month <= 12 ) + && ( p->year <= 99 ); + +} /* pcps_time_is_valid */ + + + +/*-------------------------------------------------------------- + * Name: pcps_str_to_port() + * + * Purpose: Try to convert a string to a valid port + * address. + * + * Input: s the string + * + * Output: -- + * + * Ret value: a valid port number or 0 + *+-------------------------------------------------------------*/ + +/*HDR*/ +void pcps_setup_isa_ports( char *s, + int *port_vals, + int n_vals ) +{ + ushort i; + + + for ( i = 0; i < n_vals; i++ ) + { + if ( *s == 0 ) + break; + + *port_vals++ = (uint16_t) strtoul( s, &s, 16 ); + + if ( *s == ',' ) + s++; + } + +} // pcps_setup_isa_ports + + + +/*-------------------------------------------------------------- + * Name: pcps_unpack_serial() + * + * Purpose: Unpack a structure with serial port parameters + * + * Input/Output: p address of a structure holding both the + * packed and unpacked information + * + * Ret value: -- + *-------------------------------------------------------------*/ + +/*HDR*/ +void pcps_unpack_serial( PCPS_SER_PACK *p ) +{ + uint8_t pack = p->pack; + + p->baud = (uint8_t) ( pack & BITMASK( PCPS_BD_BITS ) ); + p->frame = (uint8_t) ( ( pack >> PCPS_FR_SHIFT ) & BITMASK( PCPS_FR_BITS ) ); + p->mode = (uint8_t) ( ( pack >> PCPS_MOD_SHIFT ) & BITMASK( PCPS_MOD_BITS ) ); + +} // pcps_unpack_serial + + + +/*-------------------------------------------------------------- + * Name: pcps_pack_serial() + * + * Purpose: Pack a structure with serial port parameters + * + * Input/Output: p address of a structure holding both the + * packed and unpacked information + * + * Ret value: -- + *-------------------------------------------------------------*/ + +/*HDR*/ +void pcps_pack_serial( PCPS_SER_PACK *p ) +{ + p->pack = (uint8_t) ( ( p->baud & BITMASK( PCPS_BD_BITS ) ) + | ( ( p->frame & BITMASK( PCPS_FR_BITS ) ) << PCPS_FR_SHIFT ) + | ( ( p->mode & BITMASK( PCPS_MOD_BITS ) ) << PCPS_MOD_SHIFT ) ); + +} /* pcps_pack_serial */ + + + diff --git a/mbglib/common/pcpsutil.h b/mbglib/common/pcpsutil.h new file mode 100755 index 0000000..e5cab81 --- /dev/null +++ b/mbglib/common/pcpsutil.h @@ -0,0 +1,183 @@ + +/************************************************************************** + * + * $Id: pcpsutil.h 1.14 2009/03/09 13:39:45 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes for pcpsutil.c. + * + * ----------------------------------------------------------------------- + * $Log: pcpsutil.h $ + * Revision 1.14 2009/03/09 13:39:45 martin + * Made pcps_exp_year() an inline function. + * Revision 1.13 2008/12/10 19:59:48 martin + * Made frac_sec_from_bin() an inline function. + * Revision 1.12 2008/11/25 09:59:01 martin + * Moved definitions of PCPS_HRT_FRAC_SCALE and + * PCPS_HRT_FRAC_SCALE_FMT to pcpsdefs.h. + * Revision 1.11 2006/06/29 10:15:02Z martin + * Updated function prototypes. + * Revision 1.10 2005/01/14 10:16:12Z martin + * Updated function prototypes. + * Revision 1.9 2004/11/09 14:30:50Z martin + * Redefined interface data types using C99 fixed-size definitions. + * Updated function prototypes. + * Revision 1.8 2004/04/14 09:22:09Z martin + * Pack structures 1 byte aligned. + * Revision 1.7 2001/11/28 14:41:25Z MARTIN + * Changed PCPS_HRT_FRAC_SCALE and PCPS_HRT_FRAC_SCALE_FMT + * to print 7 rather than 6 digits. + * Revision 1.6 2001/09/14 11:59:33 MARTIN + * Support for PCPS_HR_TIME fraction conversion. + * Updated function prototypes. + * Revision 1.5 2001/08/14 12:06:44 MARTIN + * Defined constants used to draw a signal bar + * depending on a DCF77 clock's signal value. + * Revision 1.4 2001/03/01 14:03:18 MARTIN + * Updated function prototypes. + * Revision 1.3 2000/08/31 14:06:05 MARTIN + * Updated function prototypes. + * Revision 1.2 2000/07/21 13:43:40 MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _PCPSUTIL_H +#define _PCPSUTIL_H + + +/* Other headers to be included */ + +#include +#include + + +#ifdef _PCPSUTIL + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + +#if defined( _USE_PACK ) // set byte alignment + #pragma pack( 1 ) +#endif + + +// The following constants are used to draw a signal bar +// depending on a DCF77 clock's signal value: +#define PCPS_SIG_BIAS 55 +#define PCPS_SIG_ERR 1 +#define PCPS_SIG_MIN 20 +#define PCPS_SIG_MAX 68 + + +// the structure below is used with a DCF77 clock's serial interface +typedef struct +{ + PCPS_SERIAL pack; // this byte is passed to the board as parameter + + uint8_t baud; // the other bytes can hold the unpacked values + uint8_t frame; + uint8_t mode; + +} PCPS_SER_PACK; + + + +/*-------------------------------------------------------------- + * Name: pcps_exp_year() + * + * Purpose: Convert a 2-digit year number to a 4-digit + * year number. The resulting year number is in + * the range [year_lim ... ( year_lim + 99 )]. + * + * Input: year the 2-digit year number + * year_lim the smallest 4-digit year number + * to be returned + * + * Output: -- + * + * Ret value: the calculated 4-digit year num + *+-------------------------------------------------------------*/ + +static __mbg_inline +uint16_t pcps_exp_year( uint8_t year, uint16_t year_lim ) +{ + uint16_t lyear = (uint16_t) ( (uint16_t) year + year_lim + - ( year_lim % 100 ) ); + + if ( lyear < year_lim ) + lyear += 100; + + return lyear; + +} // pcps_exp_year + + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + + int pcps_time_is_valid( const PCPS_TIME *p ) ; + void pcps_setup_isa_ports( char *s, int *port_vals, int n_vals ) ; + void pcps_unpack_serial( PCPS_SER_PACK *p ) ; + void pcps_pack_serial( PCPS_SER_PACK *p ) ; + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +/*-------------------------------------------------------------- + * Name: frac_sec_from_bin() + * + * Purpose: Convert a fraction of a second from binary + * format (as returned in a PCPS_HR_TIME structure + * to a decimal fraction, using a specified scale + * factor. See also the definitions of + * PCPS_HRT_FRAC_SCALE and PCPS_HRT_FRAC_SCALE_FMT + * in the header file. + * + * Input: b the binary fraction + * scale the scale factor + * + * Output: -- + * + * Ret value: the calculated number + *+-------------------------------------------------------------*/ + +static __mbg_inline +uint32_t frac_sec_from_bin( uint32_t b, uint32_t scale ) +{ + return (uint32_t) ( (PCPS_HRT_FRAC_CONVERSION_TYPE) b * scale + / PCPS_HRT_BIN_FRAC_SCALE ); + +} // frac_sec_from_bin + + + +#if defined( _USE_PACK ) // set default alignment + #pragma pack() +#endif + +/* End of header body */ + +#undef _ext + + +#endif /* _PCPSUTIL_H */ diff --git a/mbglib/common/plxdefs.h b/mbglib/common/plxdefs.h new file mode 100755 index 0000000..ba1ce53 --- /dev/null +++ b/mbglib/common/plxdefs.h @@ -0,0 +1,76 @@ + +/************************************************************************** + * + * $Id: plxdefs.h 1.2 2010/01/28 15:46:31 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions to be used with PLX PCIexpress interface chips. + * + * ----------------------------------------------------------------------- + * $Log: plxdefs.h $ + * Revision 1.2 2010/01/28 15:46:31 martin + * Added PLX8311_REG_CTRL. + * Revision 1.1 2007/06/08 07:46:56Z martin + * Initial revision. + * + **************************************************************************/ + +#ifndef _PLXDEFS_H +#define _PLXDEFS_H + + +/* Other headers to be included */ + + +#ifdef _PLXDEFS + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + +// The following PLX8311 operation registers can +// be accessed via port I/O or memory mapped: +#define PLX8311_REG_INTCSR 0x68 + +// The following bits must be set in the INTCSR register +// to let the local microcontroller be able to generate +// interrupts on the PCI bus via the chip's LINTi# line: +#define PLX8311_INT_ENB ( (1UL << 11) | (1UL << 8) ) + +// The bit below signals if an LINTi# interrupt is active: +#define PLX8311_INT_FLAG (1UL << 15) + +#define PLX8311_REG_CNTRL 0x6C + + +/* End of header body */ + +#undef _ext + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + +/* (no header definitions found) */ + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +#endif /* _PLXDEFS_H */ diff --git a/mbglib/common/qsdefs.h b/mbglib/common/qsdefs.h new file mode 100755 index 0000000..352924b --- /dev/null +++ b/mbglib/common/qsdefs.h @@ -0,0 +1,46 @@ + +/************************************************************************** + * + * $Id: qsdefs.h 1.1 2002/02/19 13:46:20 MARTIN REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions used with the Meinberg Quality Management System. + * + * ----------------------------------------------------------------------- + * $Log: qsdefs.h $ + * Revision 1.1 2002/02/19 13:46:20 MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _QSDEFS_H +#define _QSDEFS_H + + +/* Other headers to be included */ + +/* Start of header body */ + +// The fixed length of the group code string: +#define MBG_GRP_CODE_LEN 4 + +// The mem size required to store a group code string +// including terminating 0: +#define MBG_GRP_CODE_SIZE ( MBG_GRP_CODE_LEN + 1 ) + +// A data type used to store a group code string: +typedef char MBG_GRP_CODE[MBG_GRP_CODE_SIZE]; + + +// The length of the serial number: +#define MBG_SERNUM_LEN 8 + +// The length of the group code + serial number: +#define MBG_GRP_SERNUM_LEN ( MBG_GRP_CODE_LEN + MBG_SERNUM_LEN ) + + +/* End of header body */ + +#endif /* _QSDEFS_H */ diff --git a/mbglib/common/rsrc.h b/mbglib/common/rsrc.h new file mode 100755 index 0000000..744e443 --- /dev/null +++ b/mbglib/common/rsrc.h @@ -0,0 +1,89 @@ + +/************************************************************************** + * + * $Id: rsrc.h 1.4.1.1 2006/09/19 14:52:02 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions used to access resource manager functions under + * different operating systems. + * + * ----------------------------------------------------------------------- + * $Log: rsrc.h $ + * Revision 1.4.1.1 2006/09/19 14:52:02 martin + * Preliminary support for *BSD. + * Revision 1.4 2001/02/28 15:45:11 MARTIN + * Modified preprocessor syntax. + * Revision 1.3 2001/02/05 10:22:24 MARTIN + * Linux support. + * Revision 1.2 2000/09/20 08:15:34 MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _RSRC_H +#define _RSRC_H + + +/* Other headers to be included */ + +#include + +#if defined( MBG_TGT_OS2 ) + #include // resource manager functions for OS/2 +#elif defined( MBG_TGT_WIN32 ) + #include // resource manager functions for Win NT +#elif defined( MBG_TGT_LINUX ) + #include // resource manager functions for Linux +#elif defined( MBG_TGT_BSD ) + #include // resource manager functions for *BSD +#endif + + + +#ifdef _RSRC + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + +enum +{ + RSRC_BUS_ISA, + RSRC_BUS_EISA, + RSRC_BUS_MCA, + RSRC_BUS_PCI +}; + + +/* End of header body */ + +#undef _ext + + +/* function prototypes: */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + +/* (no header definitions found) */ + +/* ----- function prototypes end ----- */ + +#ifdef __cplusplus +} +#endif + + +#endif /* _RSRC_H */ + diff --git a/mbglib/common/toolutil.c b/mbglib/common/toolutil.c new file mode 100755 index 0000000..50a4ad8 --- /dev/null +++ b/mbglib/common/toolutil.c @@ -0,0 +1,401 @@ + +/************************************************************************** + * + * $Id: toolutil.c 1.3.2.1 2010/11/05 12:56:02 martin TEST $ + * + * Description: + * Common functions which can be used with Meinberg command line + * utility programs. + * + * ----------------------------------------------------------------------- + * $Log: toolutil.c $ + * Revision 1.3.2.1 2010/11/05 12:56:02 martin + * Revision 1.3 2009/06/19 12:12:14 martin + * Added function mbg_print_hr_timestamp(). + * Revision 1.2 2009/02/18 09:15:55 martin + * Support TAI and GPS time scales in mbg_snprint_hr_time(). + * Revision 1.1 2008/12/17 10:45:13 martin + * Initial revision. + * Revision 1.1 2008/12/15 08:35:07 martin + * Initial revision. + * + **************************************************************************/ + +#define _TOOLUTIL + #include +#undef _TOOLUTIL + +// include Meinberg headers +#include + +// include system headers +#include +#include +#include + + +/*HDR*/ +void mbg_print_program_info( const char *pname, const char *pversion, const char *pcopyright ) +{ + printf( "\n%s %s %s\n\n", pname, pversion, pcopyright ); + +} // mbg_print_program_info + + + +/*HDR*/ +void mbg_print_usage_intro( const char *pname, const char *info ) +{ + printf( "Usage: %s [[opt] [opt] ...] [[dev] [dev] ...]\n\n", pname ); + + if ( info ) + printf( "%s\n\n", info ); + + +} // mbg_print_usage_intro + + + +/*HDR*/ +void mbg_print_help_options( void ) +{ + puts( "where opt is one of the options:" ); + mbg_print_opt_info( "-? or -h", "print this usage information" ); + +} // mbg_print_help_options + + + +/*HDR*/ +void mbg_print_opt_info( const char *opt_name, const char *opt_info ) +{ + if ( opt_name == NULL ) + opt_name = ""; + + if ( opt_info == NULL ) + opt_info = ""; + + printf( " %8s %s\n", opt_name, opt_info ); + +} // mbg_print_opt_info + + + +/*HDR*/ +void mbg_print_device_options( void ) +{ + puts( "\nwhere dev is the name of a device, e.g.:\n" + " /dev/mbgclock0" + ); + +} // mbg_print_device_options + + + +/*HDR*/ +void mbg_print_default_usage( const char *pname, const char *prog_info ) +{ + mbg_print_usage_intro( pname, prog_info ); + mbg_print_help_options(); + mbg_print_device_options(); + puts( "" ); + +} // mbg_print_default_usage + + + +// test if ioctl error and print msg if true + +/*HDR*/ +int mbg_ioctl_err( int rc, const char *descr ) +{ + if ( rc < 0 ) + { + fprintf( stderr, "** IOCTL error %i: ", rc ); + perror( descr ); + return -1; + } + + return 0; + +} // mbg_ioctl_err + + + +/*HDR*/ +int mbg_get_show_dev_info( MBG_DEV_HANDLE dh, const char *dev_name, PCPS_DEV *p_dev ) +{ + unsigned long long port; + int irq_num; + int ret_val = 0; + int rc; + + if ( dev_name ) + printf( "%s:\n", dev_name ); + + // get information about the device + rc = mbg_get_device_info( dh, p_dev ); + + if ( mbg_ioctl_err( rc, "mbg_get_device_info" ) ) + goto fail; + + + printf( "%s", _pcps_type_name( p_dev ) ); + + if ( strlen( _pcps_sernum( p_dev ) ) && + strcmp( _pcps_sernum( p_dev ), "N/A" ) ) + printf( " %s", _pcps_sernum( p_dev ) ); + + printf( " (FW %X.%02X", + _pcps_fw_rev_num_major( _pcps_fw_rev_num( p_dev ) ), + _pcps_fw_rev_num_minor( _pcps_fw_rev_num( p_dev ) ) + ); + + if ( _pcps_has_asic_version( p_dev ) ) + { + PCI_ASIC_VERSION av; + int rc = mbg_get_asic_version( dh, &av ); + + if ( rc == MBG_SUCCESS ) + { + av = _convert_asic_version_number( av ); + + printf( ", ASIC %X.%02X", + _pcps_asic_version_major( av ), + _pcps_asic_version_minor( av ) + ); + } + } + + printf( ")" ); + + port = _pcps_port_base( p_dev, 0 ); + + if ( port ) + printf( " at port 0x%03LX", port ); + + port = _pcps_port_base( p_dev, 1 ); + + if ( port ) + printf( "/0x%03LX", port ); + + irq_num = _pcps_irq_num( p_dev ); + + if ( irq_num != -1 ) + printf( ", irq %i", irq_num ); + + goto done; + +fail: + ret_val = -1; + +done: + puts( "" ); + return ret_val; + +} // mbg_get_show_dev_info + + + +/*HDR*/ +int mbg_check_device( MBG_DEV_HANDLE dh, const char *dev_name, + int (*fnc)( MBG_DEV_HANDLE, const PCPS_DEV *) ) +{ + PCPS_DEV dev; + int ret_val = 0; + + if ( dh == MBG_INVALID_DEV_HANDLE ) + { + if ( dev_name ) + fprintf( stderr, "%s: ", dev_name ); + + perror( "Unable to open device" ); + return -1; + } + + if ( mbg_get_show_dev_info( dh, dev_name, &dev ) < 0 ) + goto fail; + + if ( fnc ) + ret_val = fnc( dh, &dev ); + + goto done; + +fail: + ret_val = -1; + +done: + mbg_close_device( &dh ); + puts( "" ); + + return ret_val; + +} // mbg_check_device + + + +/*HDR*/ +int mbg_check_devices( int argc, char *argv[], int optind, int (*fnc)( MBG_DEV_HANDLE, const PCPS_DEV *) ) +{ + MBG_DEV_HANDLE dh; + int ret_val = 0; + int num_devices = argc - optind; + + if ( num_devices == 0 ) // no device name given on the command line + { + // No devices specified on the command line, so + // try to find devices. + int devices = mbg_find_devices(); + + if ( devices == 0 ) + { + printf( "No device found.\n" ); + return 1; + } + + // Handle only first device found. + dh = mbg_open_device( 0 ); + ret_val = mbg_check_device( dh, NULL, fnc ); + } + else + { + int i; + // One or more device names have been specified + // on the command line, so handle each device. + for ( i = optind; i < argc; i++ ) + { + // Print device name only if output for several devices + // shall be displayed. + const char *fn = ( num_devices > 1 ) ? argv[i] : NULL; + + dh = open( argv[i], 0 ); + ret_val = mbg_check_device( dh, fn, fnc ); + + if ( ret_val ) + break; + } + } + + return ret_val; + +} // mbg_check_devices + + + +/*HDR*/ +int mbg_snprint_hr_tstamp( char *s, int len_s, const PCPS_TIME_STAMP *p ) +{ + int n = 0; + + // We'll use the standard C library functions to convert the seconds + // to broken-down calendar date and time. + time_t t = p->sec; + + // Our time stamp may be UTC, or have been converted to local time. + // Anyway, since we don't want to account for the system's time zone + // settings, we always use the gmtime() function for conversion: + struct tm *tmp = gmtime( &t ); + + #if defined( DEBUG ) + n += snprintf( s + n, len_s - n, "raw: %08lX.%08lX, ", + (ulong) p->sec, + (ulong) p->frac ); + #endif + + n += snprintf( s + n, len_s - n, "%04i-%02i-%02i %02i:%02i:%02i." PCPS_HRT_FRAC_SCALE_FMT, + tmp->tm_year + 1900, + tmp->tm_mon + 1, + tmp->tm_mday, + tmp->tm_hour, + tmp->tm_min, + tmp->tm_sec, + (ulong) frac_sec_from_bin( p->frac, PCPS_HRT_FRAC_SCALE ) + ); + + return n; + +} // mbg_snprint_hr_tstamp + + + +/*HDR*/ +int mbg_snprint_hr_time( char *s, int len_s, const PCPS_HR_TIME *p ) +{ + char ws[80]; + PCPS_TIME_STAMP ts = p->tstamp; + int n; + const char *time_scale_name; + const char *cp; + + // If the local time offset is not 0 then add this to the time stamp + // and set up a string telling the offset. + if ( p->utc_offs ) + { + ldiv_t ldt; + + ts.sec += p->utc_offs; + + // The local time offset is in seconds and may be negative, so we + // convert to absolute hours and minutes first. + ldt = ldiv( labs( p->utc_offs ) / 60, 60 ); + + snprintf( ws, sizeof( ws ), "%c%lu:%02luh", + ( p->utc_offs < 0 ) ? '-' : '+', + ldt.quot, + ldt.rem + ); + cp = ws; + } + else + cp = ""; // no local time offset + + + // Convert the local time stamp to calendar date and time. + n = mbg_snprint_hr_tstamp( s, len_s, &ts ); + + // By default the time stamp represents UTC plus an optional local time offset. + time_scale_name = "UTC"; + + // However, some cards may be configured to output TAI or GPS time. + if ( p->status & PCPS_SCALE_TAI ) + time_scale_name = "TAI"; // time stamp represents TAI + else + if ( p->status & PCPS_SCALE_GPS ) + time_scale_name = "GPS"; // time stamp represents GPS system time + + n += snprintf( s + n, len_s - n, " %s%s", time_scale_name, cp ); + + return n; + +} // mbg_snprint_hr_time + + + +/*HDR*/ +void mbg_print_hr_timestamp( PCPS_TIME_STAMP *p_ts, int32_t hns_latency, PCPS_TIME_STAMP *p_prv_ts, int raw ) +{ + char ws[80]; + + mbg_snprint_hr_tstamp( ws, sizeof( ws ), p_ts ); + printf( "Fast HR time %s", ws ); + + if ( p_prv_ts ) + { + // print the difference between the current and the previous time stamp + uint64_t ts = pcps_time_stamp_to_uint64( p_ts ); + uint64_t prv_ts = pcps_time_stamp_to_uint64( p_prv_ts ); + // we divide by PCPS_HRT_BIN_FRAC_SCALE to get the correct fractions + // and we multiply by 1E6 to get the result in microseconds + double delta_t = (double) ( ts - prv_ts ) * 1E6 / PCPS_HRT_BIN_FRAC_SCALE; + printf( " (%+.1f us)", delta_t ); + } + + if ( !raw ) + printf( ", latency: %.1f us", ( (double) hns_latency ) / 10 ); + + puts( "" ); + +} // mbg_print_hr_timestamp + + + diff --git a/mbglib/common/toolutil.h b/mbglib/common/toolutil.h new file mode 100755 index 0000000..7c69e84 --- /dev/null +++ b/mbglib/common/toolutil.h @@ -0,0 +1,83 @@ + +/************************************************************************** + * + * $Id: toolutil.h 1.2 2009/06/19 12:11:35 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions and prototypes for toolutil.c. + * + * ----------------------------------------------------------------------- + * $Log: toolutil.h $ + * Revision 1.2 2009/06/19 12:11:35 martin + * Updated function prototypes. + * Revision 1.1 2008/12/17 10:45:14 martin + * Initial revision. + * Revision 1.1 2008/12/15 08:35:08 martin + * Initial revision. + * + **************************************************************************/ + +#ifndef _TOOLUTIL_H +#define _TOOLUTIL_H + + +/* Other headers to be included */ + +#include + + + +#ifdef _TOOLUTIL + #define _ext + #define _DO_INIT +#else + #define _ext extern +#endif + + +/* Start of header body */ + +_ext int must_print_usage; + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* ----- function prototypes begin ----- */ + +/* This section was generated automatically */ +/* by MAKEHDR, do not remove the comments. */ + +void mbg_print_program_info( const char *pname, const char *pversion, const char *pcopyright ); +void mbg_print_usage_intro( const char *pname, const char *info ); +void mbg_print_help_options( void ); +void mbg_print_opt_info( const char *opt_name, const char *opt_info ); +void mbg_print_device_options( void ); +void mbg_print_default_usage( const char *pname, const char *prog_info ); +int mbg_ioctl_err( int rc, const char *descr ) ; +int mbg_get_show_dev_info( MBG_DEV_HANDLE dh, const char *dev_name, PCPS_DEV *p_dev ); +int mbg_check_device( MBG_DEV_HANDLE dh, const char *dev_name, int (*fnc)( MBG_DEV_HANDLE, const PCPS_DEV *) ); +int mbg_check_devices( int argc, char *argv[], int optind, int (*fnc)( MBG_DEV_HANDLE, const PCPS_DEV *) ); +int mbg_snprint_hr_tstamp( char *s, int len_s, const PCPS_TIME_STAMP *p ); +int mbg_snprint_hr_time( char *s, int len_s, const PCPS_HR_TIME *p ); +void mbg_print_hr_timestamp( PCPS_TIME_STAMP *p_ts, int32_t hns_latency, PCPS_TIME_STAMP *p_prv_ts, int raw ); + +/* ----- function prototypes end ----- */ + + +#ifdef __cplusplus +} +#endif + + +/* End of header body */ + +#undef _ext +#undef _DO_INIT + +#endif /* _TOOLUTIL_H */ + diff --git a/mbglib/common/usbdefs.h b/mbglib/common/usbdefs.h new file mode 100755 index 0000000..d853118 --- /dev/null +++ b/mbglib/common/usbdefs.h @@ -0,0 +1,110 @@ + +/************************************************************************** + * + * $Id: usbdefs.h 1.10 2010/11/11 09:16:33 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions used with USB devices. + * + * ----------------------------------------------------------------------- + * $Log: usbdefs.h $ + * Revision 1.10 2010/11/11 09:16:33 martin + * Added device ID for DCF600USB. + * Revision 1.9 2009/03/13 09:02:24 martin + * Removed definitions for timeout intervals. + * Revision 1.8 2009/02/18 11:08:44 daniel + * Added new class code and device ID for SCU_USB + * Revision 1.7 2008/11/28 07:45:30Z daniel + * Added new class code and device ID for WWVB51USB + * Revision 1.6 2008/01/09 10:39:18Z daniel + * Added new class code and device ID for MSF51USB + * Revision 1.5 2007/10/29 08:23:26Z daniel + * Added new class code and device ID for TCR51USB + * Revision 1.4 2007/09/25 09:59:50Z daniel + * Added indices for endpoint definitions. + * Added timeout definitions. + * Revision 1.3 2006/12/20 16:11:36Z daniel + * Added new device class and device_id for nCipher CMC-device. + * Revision 1.2 2006/12/07 09:10:57Z daniel + * Added new class code and device ID for USB5131. + * Revision 1.1 2006/04/21 08:14:56Z martin + * Initial revision + * + **************************************************************************/ + +#ifndef _USBDEFS_H +#define _USBDEFS_H + + +/* Other headers to be included */ + + +/* Start of header body */ + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Meinberg's USB vendor ID number (assigned by USB-IF Administration) */ +#define USB_VENDOR_MEINBERG 0x1938 + + +/* + * USB device class codes (assigned by Meinberg) + */ +enum +{ + MBG_USB_CLASS_NONE, // (unknown or not defined) + MBG_USB_CLASS_CPC, // Control Panel Controller + MBG_USB_CLASS_TSU, // Time Stamp Unit + MBG_USB_CLASS_DCF, // DCF77 Radio Clock + MBG_USB_CLASS_CMC, // nCipher Crypto Module Carrier + MBG_USB_CLASS_TCR, // IRIG Time Code Receiver + MBG_USB_CLASS_MSF, // MSF Radio Clock + MBG_USB_CLASS_WWVB, // WWVB Radio Clock + MBG_USB_CLASS_SCU, // Meinberg Signal Changeover Unit + N_MBG_USB_CLASS // number of known device class codes +}; + + +/* + * USB device ID numbers (assigned by Meinberg) + * High byte: USB device class as specified above + * Low byte: enumeration of device of a class + */ +#define USB_DEV_CPC_01 ( ( MBG_USB_CLASS_CPC << 8 ) | 0x01 ) + +#define USB_DEV_TSU_01 ( ( MBG_USB_CLASS_TSU << 8 ) | 0x01 ) + +#define USB_DEV_USB5131 ( ( MBG_USB_CLASS_DCF << 8 ) | 0x01 ) +#define USB_DEV_DCF600USB ( ( MBG_USB_CLASS_DCF << 8 ) | 0x02 ) + +#define USB_DEV_CMC ( ( MBG_USB_CLASS_CMC << 8 ) | 0x01 ) + +#define USB_DEV_TCR51USB ( ( MBG_USB_CLASS_TCR << 8 ) | 0x01 ) + +#define USB_DEV_MSF51USB ( ( MBG_USB_CLASS_MSF << 8 ) | 0x01 ) + +#define USB_DEV_WWVB51USB ( ( MBG_USB_CLASS_WWVB << 8 ) | 0x01 ) + +#define USB_DEV_SCU_USB ( ( MBG_USB_CLASS_SCU << 8 ) | 0x01 ) + +enum +{ + MBGUSB_EP_IDX_HOST_IN, // transfers from device to host + MBGUSB_EP_IDX_HOST_OUT, // transfers from host to device + MBGUSB_EP_IDX_HOST_IN_CYCLIC, // cyclic auto-transfer to host + MBGUSB_MAX_ENDPOINTS // max number of supported endpoints +}; + + +#ifdef __cplusplus +} +#endif + +/* End of header body */ + +#endif /* _USBDEFS_H */ diff --git a/mbglib/common/use_pack.h b/mbglib/common/use_pack.h new file mode 100755 index 0000000..aaacd42 --- /dev/null +++ b/mbglib/common/use_pack.h @@ -0,0 +1,39 @@ + +/************************************************************************** + * + * $Id: use_pack.h 1.3 2011/01/26 10:01:41 martin REL_M $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Check the current compiler type to decide if pragma pack() is + * required to pack cross-platform data structures. + * + * ----------------------------------------------------------------------- + * $Log: use_pack.h $ + * Revision 1.3 2011/01/26 10:01:41 martin + * Provided a way to suppress packing of structures on a project base. + * Revision 1.2 2002/02/25 08:50:33 Andre + * query __ARM added, __SH2 removed + * Revision 1.1 2001/03/30 08:54:33Z MARTIN + * Initial revision + * + **************************************************************************/ + +#ifndef _USE_PACK_H +#define _USE_PACK_H + +#if ( !defined( _C166 ) && \ + !defined( _CC51 ) && \ + !defined( __ARM ) ) + + // _NO_USE_PACK can be defined for specific projects + // to avoid packing of structures. + #if ( !defined( _NO_USE_PACK ) ) + #define _USE_PACK + #endif + +#endif + +#endif /* _USE_PACK_H */ + diff --git a/mbglib/common/words.h b/mbglib/common/words.h new file mode 100755 index 0000000..6860911 --- /dev/null +++ b/mbglib/common/words.h @@ -0,0 +1,335 @@ + +/************************************************************************** + * + * $Id: words.h 1.25.1.1 2011/01/25 08:25:49 martin TEST $ + * + * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany + * + * Description: + * Definitions of commonly used data types. + * + * ----------------------------------------------------------------------- + * $Log: words.h $ + * Revision 1.25.1.1 2011/01/25 08:25:49 martin + * Avoid build errors under FreeBSD. + * Revision 1.25 2010/11/17 10:23:09 martin + * Define _BIT_REDEFINED if bit type is redefined. + * Revision 1.24 2010/11/17 08:44:56Z martin + * If supported, use type "bool" to implement "bit". + * Revision 1.23 2010/05/27 08:54:30Z martin + * Support fixed size data types with Keil RealView compiler for ARM. + * Keil RealView ARM targets are always considered as firmware. + * Revision 1.22 2009/10/21 07:53:55 martin + * Undid changes introduced in 1.21 since they were not consistent + * across glibc and/or Linux kernel header versions. + * Revision 1.21 2009/10/01 14:00:17 martin + * Conditionally define ulong and friends also for Linux/glibc. + * Revision 1.20 2009/07/02 15:38:12 martin + * Added new macro _wswap32(). + * Revision 1.19 2009/04/14 14:45:45Z martin + * Added BYTE_OF_P() and WORD_OF_P() macros. + * Revision 1.18 2009/03/27 14:05:18 martin + * Cleanup for CVI. + * Revision 1.17 2009/03/13 09:06:03Z martin + * Declared bit type for non-firmware environments. + * Revision 1.16 2008/12/05 12:05:41Z martin + * Define dummy int64_t/uint64_t types for targets + * which don't support 64 bit data types. + * Revision 1.15 2008/07/14 14:44:00Z martin + * Use fixed size C99 types which come with GCC and newer Borland compilers. + * Revision 1.14 2008/01/30 10:27:50Z martin + * Moved some macro definitions here. + * Revision 1.13 2007/03/08 15:00:30Z martin + * Fixed incompatibility of macro _IS_MBG_FIRMWARE. + * Added a workaround for _IS_MBG_FIRMWARE under CVI. + * Support for BSD. + * Revision 1.12 2006/12/15 10:45:46 martin + * Added macro _IS_MBG_FIRMWARE. + * Cleanup for Linux, QNX, and Watcom C. + * Include mbg_tgt.h for non-firmware targets. + * Revision 1.11 2004/11/10 10:45:34 martin + * Added C99 fixed-type handling for QNX. + * Revision 1.10 2004/11/09 13:12:56 martin + * Redefined C99 integer types with fixed sizes as standard types + * if required, depending on the environment. + * Revision 1.9 2003/02/07 11:36:54 MARTIN + * New macros _hilo_16() and _hilo_32() for endian conversion. + * Revision 1.8 2002/05/28 10:09:54 MARTIN + * Added new macros _var_bswap16() and _var_bswap32(). + * Revision 1.7 2001/03/14 11:30:48 MARTIN + * Removed definitions for UINT8, UINT16, UINT32. + * Redefined preprocessor control for Win32. + * Revision 1.6 2001/02/28 15:43:20 MARTIN + * Modified preprocessor syntax. + * Revision 1.5 2001/02/05 10:20:53 MARTIN + * Include different Linux types for user space and kernel space programs. + * Source code cleanup. + * Revision 1.4 2000/09/15 08:34:11 MARTIN + * Exclude some definitions if compiling under Win NT. + * Revision 1.3 2000/08/22 15:04:28 MARTIN + * Added new file header. + * Added macros to revert endianess of 16 and 32 bit values. + * + **************************************************************************/ + +#ifndef _WORDS_H +#define _WORDS_H + + +/* Other headers to be included */ + + +#if !defined( _IS_MBG_FIRMWARE ) + +#if defined( _C166 ) || \ + defined( _CC51 ) || \ + defined( __ARM ) || \ + defined( __ARMCC_VERSION ) + #define _IS_MBG_FIRMWARE 1 +#else + #define _IS_MBG_FIRMWARE 0 +#endif + + +#endif + +#if !_IS_MBG_FIRMWARE + #include +#endif + + +#ifdef _WORDS + #define _ext +#else + #define _ext extern +#endif + + +/* Start of header body */ + + +// The compilers below support native bit types. + +#if defined( _C166 ) || defined( _CC51 ) + #define _BIT_DEFINED 1 +#endif + + + +// Check whether the target system supports C99 fixed-size types. + +#if defined( MBG_TGT_LINUX ) // any Linux target + + #if defined( __KERNEL__ ) + #include + #else + #include + #include + #endif + + #define _C99_BIT_TYPES_DEFINED 1 + +#elif defined( MBG_TGT_BSD ) + + #include + + #define _C99_BIT_TYPES_DEFINED 1 + + //##++ a workaround for now to avoid inclusion of stdbool.h later + #define bit int + #define _BIT_DEFINED + +#elif defined( MBG_TGT_QNX ) // QNX 4.x or QNX 6.x + + #if defined( MBG_TGT_QNX_NTO ) // QNX 6.x (Neutrino) with gcc + #include + #else // QNX 4.x with Watcom C 10.6 + #include // 64 bit types not supported + #endif + + #define _C99_BIT_TYPES_DEFINED 1 + +#endif + + + +// If it's not yet clear whether fixed-size types are supported, +// check the build environment which may be multi-platform. + +#if !defined( _C99_BIT_TYPES_DEFINED ) + + #if defined( __WATCOMC__ ) + #if __WATCOMC__ > 1230 // Open Watcom C 1.3 and above + #include + #define _C99_BIT_TYPES_DEFINED 1 + #elif defined( __WATCOM_INT64__ ) // Watcom C 11, non-QNX + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; + + #define _C99_BIT_TYPES_DEFINED 1 + #endif + #endif + + #if defined( __BORLANDC__ ) + #if ( __BORLANDC__ >= 0x570 ) // at least Borland Developer Studio 2006 + #define _C99_BIT_TYPES_DEFINED 1 + #endif + #endif + + #if defined( __GNUC__ ) + #include + #define _C99_BIT_TYPES_DEFINED 1 + #endif + + #if defined( __ARMCC_VERSION ) // Keil RealView Compiler for ARM + #include + #define _C99_BIT_TYPES_DEFINED 1 + #endif + +#endif + + +// If neither the target system nor the build environment define C99 fixed-size +// types define those types based on standard types with the proper sizes +// commonly used in 16/32 bit environments. + +#if defined( _C99_BIT_TYPES_DEFINED ) + + #define MBG_TGT_HAS_64BIT_TYPES 1 + +#else + + typedef char int8_t; + typedef unsigned char uint8_t; + + typedef short int16_t; + typedef unsigned short uint16_t; + + typedef long int32_t; + typedef unsigned long uint32_t; + + + #if defined( MBG_TGT_WIN32 ) + + typedef __int64 int64_t; + typedef unsigned __int64 uint64_t; + + #define MBG_TGT_HAS_64BIT_TYPES 1 + + #else + // The types below are required to avoid build errors + // if these types are formally used in function prototypes. + // We explicitely use abnormal data types to hopefully + // cause compiler errors in case these types are + // unexpectedly used to generate real code for a target + // platform which does not support 64 bit types. + typedef void *int64_t; + typedef void *uint64_t; + #endif + +#endif + + + +#if !defined( MBG_TGT_HAS_64BIT_TYPES ) + + #define MBG_TGT_HAS_64BIT_TYPES 0 + +#endif + + + +// Some commonly used types + +typedef unsigned char uchar; + +#if !defined( MBG_TGT_LINUX ) + typedef unsigned short ushort; + typedef unsigned int uint; + typedef unsigned long ulong; +#endif + +typedef double udouble; + +typedef unsigned char byte; +typedef unsigned short word; +typedef unsigned long longword; +typedef unsigned long dword; + +#if !defined( _BIT_DEFINED ) + + #if _C99_BIT_TYPES_DEFINED + #include + + typedef bool bit; + #else + typedef int bit; + #endif + + #define _BIT_REDEFINED 1 + +#endif + + +#define HI_BYTE( _x ) ( (_x) >> 8 ) +#define LO_BYTE( _x ) ( (_x) & 0xFF ) + +#define HI_WORD( _x ) ( (_x) >> 16 ) +#define LO_WORD( _x ) ( (_x) & 0xFFFF ) + +// the macros below assume little endianess +// these macros expect the name of a variable +#define BYTE_OF( _v, _n ) *( ( (uint8_t *) &(_v) ) + (_n) ) +#define WORD_OF( _v, _n ) *( ( (uint16_t *) &(_v) ) + (_n) ) + +// same as above, but taking pointers +#define BYTE_OF_P( _p, _n ) *( ( (uint8_t *) (_p) ) + (_n) ) +#define WORD_OF_P( _p, _n ) *( ( (uint16_t *) (_p) ) + (_n) ) + + +// a macro to swap the byte order of a 16 bit value +#define _bswap16( _x ) \ +( \ + ( ( ( (uint16_t) (_x) ) & 0x00FF ) << 8 ) | \ + ( ( ( (uint16_t) (_x) ) & 0xFF00 ) >> 8 ) \ +) + +// a macro to swap the byte order of a 32 bit value +#define _bswap32( _x ) \ +( \ + ( ( ( (uint32_t) (_x) ) & 0x000000FFUL ) << 24 ) | \ + ( ( ( (uint32_t) (_x) ) & 0x0000FF00UL ) << 8 ) | \ + ( ( ( (uint32_t) (_x) ) & 0x00FF0000UL ) >> 8 ) | \ + ( ( ( (uint32_t) (_x) ) & 0xFF000000UL ) >> 24 ) \ +) + +// a macro to swap the word order of a 32 bit value +#define _wswap32( _x ) \ +( \ + ( ( ( (uint32_t) (_x) ) & 0x0000FFFFUL ) << 16 ) | \ + ( ( ( (uint32_t) (_x) ) >> 16 ) & 0x0000FFFFUL ) \ +) + +#define _var_bswap16( _v ) (_v) = _bswap16( _v ) +#define _var_bswap32( _v ) (_v) = _bswap32( _v ) + + +// The C51 compiler is big-endian, that means the most +// significant byte of a 16 or 32 bit value is stored in +// the lowest memory location. Most other systems are +// little-endian, so we must use macros to adjust the +// byte order if the C51 is used. + +#if defined( _CC51 ) + #define _hilo_16( _x ) _bswap16( _x ) + #define _hilo_32( _x ) _bswap32( _x ) +#else + #define _hilo_16( _x ) (_x) + #define _hilo_32( _x ) (_x) +#endif + +/* End of header body */ + +#undef _ext + +#endif /* _WORDS_H */ diff --git a/mbgsetsystime/Makefile b/mbgsetsystime/Makefile new file mode 100755 index 0000000..07ec4e4 --- /dev/null +++ b/mbgsetsystime/Makefile @@ -0,0 +1,43 @@ + +######################################################################### +# +# $Id: Makefile 1.8.1.2 2010/08/30 09:05:23 martin TEST $ +# +# Description: +# Makefile for mbgsetsystime. +# +# ----------------------------------------------------------------------- +# $Log: Makefile $ +# Revision 1.8.1.2 2010/08/30 09:05:23 martin +# Revision 1.8.1.1 2010/08/30 08:21:54 martin +# Revision 1.8 2009/07/24 10:31:17 martin +# Moved declarations to a common file which is now included. +# Revision 1.7 2008/12/22 11:56:59 martin +# Changed enumeration of source files. +# Define MBGDEVIO_SIMPLE to avoid inclusion of unnecessary modules. +# Revision 1.6 2007/03/02 11:45:10 martin +# Parameter "DEBUG=1" lets the target be built with debug enabled. +# Revision 1.5 2006/08/22 09:06:07 martin +# Added new library module mbgmktm.c. +# Revision 1.4 2003/07/08 15:33:47 martin +# Added gpsutils.c to the module list. +# Revision 1.3 2003/04/25 10:21:06 martin +# Updated source module list. +# Revision 1.2 2002/11/21 14:56:31 martin +# New targets install and uninstall. +# Revision 1.1 2001/09/17 15:08:46 martin +# +######################################################################### + +TARGET = mbgsetsystime +INST_DIR = /usr/local/sbin + +OBJS = $(TARGET).o +OBJS += mbgdevio.o +OBJS += toolutil.o +OBJS += gpsutils.o +OBJS += mbgmktm.o +OBJS += pcpsmktm.o + +BASEDIR := .. +include $(BASEDIR)/Makefile diff --git a/mbgsetsystime/mbgsetsystime.c b/mbgsetsystime/mbgsetsystime.c new file mode 100755 index 0000000..6015f12 --- /dev/null +++ b/mbgsetsystime/mbgsetsystime.c @@ -0,0 +1,173 @@ + +/************************************************************************** + * + * $Id: mbgsetsystime.c 1.8 2009/09/29 15:02:15 martin REL_M $ + * + * Description: + * Main file for mbgsetsystime program which reads the current date + * and time from a Meinberg device and sets the system time accordingly. + * The program returns 0 if successfull, otherwise a value greater + * than 0. + * + * Be careful if using this program while (x)ntpd is running because + * (x)ntpd does not like time steps and may react unexpectedly. + * + * ----------------------------------------------------------------------- + * $Log: mbgsetsystime.c $ + * Revision 1.8 2009/09/29 15:02:15 martin + * Updated version number to 3.4.0. + * Revision 1.7 2009/07/24 09:50:09 martin + * Updated version number to 3.3.0. + * Revision 1.6 2009/06/19 12:38:52 martin + * Updated version number to 3.2.0. + * Revision 1.5 2009/03/19 17:04:26 martin + * Updated version number to 3.1.0. + * Updated copyright year to include 2009. + * Revision 1.4 2008/12/22 12:43:31 martin + * Updated description, copyright, revision number and string. + * Use unified functions from toolutil module. + * Accept device name(s) on the command line. + * Don't use printf() without format, which migth produce warnings + * with newer gcc versions. + * Revision 1.3 2007/07/24 09:33:01 martin + * Updated copyright to include 2007. + * Revision 1.2 2003/04/25 10:28:05 martin + * Use new functions from mbgdevio library. + * New program version v2.1. + * Revision 1.1 2001/09/17 15:08:46 martin + * + **************************************************************************/ + +// include Meinberg headers +#include +#include +#include + +// include system headers +#include +#include +#include + +#include +#include + + +static const char *pname = "mbgsetsystime"; +static const char *pversion = "v3.4.0"; +static const char *pcopyright = "(c) Meinberg 2001-2009"; + + + + +static /*HDR*/ +void set_system_time( PCPS_TIME *tp ) +{ + struct timeval tv_set; + + + tv_set.tv_sec = pcps_mktime( tp ); + tv_set.tv_usec = (ulong) tp->sec100 * 10000; + settimeofday( &tv_set, NULL ); + + printf( "Date/time set to %02u.%02u.%02u %02u:%02u:%02u.%02u (UTC %+02ih)\n", + tp->mday, tp->month, tp->year, + tp->hour, tp->min, tp->sec, tp->sec100, + tp->offs_utc + ); + +} // set_system_time + + + +static /*HDR*/ +int do_mbgsetsystime( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev ) +{ + static int system_time_has_been_set; + + PCPS_TIME t; + int ret_val = 0; + int rc; + + if ( system_time_has_been_set ) + goto done; + + rc = mbg_get_time( dh, &t ); + + if ( mbg_ioctl_err( rc, "mbg_get_time" ) ) + { + ret_val = -2; + goto done; + } + + if ( t.status & PCPS_INVT ) + { + // This may happen if the radio clock's battery + // was low or disconnected. + printf( "Radio clock has no valid date/time.\n" ); + ret_val = -1; + goto done; + } + + set_system_time( &t ); + system_time_has_been_set = 1; + + puts( "" ); + +done: + mbg_close_device( &dh ); + + return 0; + +} // do_mbgsetsystime + + + +static /*HDR*/ +void usage( void ) +{ + mbg_print_usage_intro( pname, + "This program can be used to set the system time to the card's time.\n" + "This should be done only at boot time, before the NTP daemon is started." + ); + mbg_print_help_options(); + mbg_print_device_options(); + puts( "" ); + +} // usage + + + +int main( int argc, char *argv[] ) +{ + int c; + int rc; + + mbg_print_program_info( pname, pversion, pcopyright ); + + // check command line parameters + while ( ( c = getopt( argc, argv, "h?" ) ) != -1 ) + { + switch ( c ) + { + case 'h': + case '?': + default: + must_print_usage = 1; + } + } + + if ( must_print_usage ) + { + usage(); + return 1; + } + + // The function below checks which devices have been specified + // on the command, and for each device + // - tries to open the device + // - shows basic device info + // - calls the function passed as last parameter + rc = mbg_check_devices( argc, argv, optind, do_mbgsetsystime ); + + return abs( rc ); +} diff --git a/mbgshowsignal/Makefile b/mbgshowsignal/Makefile new file mode 100755 index 0000000..c10b915 --- /dev/null +++ b/mbgshowsignal/Makefile @@ -0,0 +1,39 @@ + +######################################################################### +# +# $Id: Makefile 1.7.1.2 2010/08/30 09:05:23 martin TEST $ +# +# Description: +# Makefile for mbgshowsignal. +# +# ----------------------------------------------------------------------- +# $Log: Makefile $ +# Revision 1.7.1.2 2010/08/30 09:05:23 martin +# Revision 1.7.1.1 2010/08/30 08:22:00 martin +# Revision 1.7 2009/07/24 10:31:17 martin +# Moved declarations to a common file which is now included. +# Revision 1.6 2008/12/22 11:56:59 martin +# Changed enumeration of source files. +# Define MBGDEVIO_SIMPLE to avoid inclusion of unnecessary modules. +# Revision 1.5 2007/03/02 11:45:10 martin +# Parameter "DEBUG=1" lets the target be built with debug enabled. +# Revision 1.4 2003/07/08 15:33:46 martin +# Added gpsutils.c to the module list. +# Revision 1.3 2003/04/25 10:21:06 martin +# Updated source module list. +# Revision 1.2 2002/11/21 14:56:31 martin +# New targets install and uninstall. +# Revision 1.1 2001/09/17 15:08:09 martin +# +######################################################################### + +TARGET = mbgshowsignal +INST_DIR = /usr/local/bin + +OBJS = $(TARGET).o +OBJS += mbgdevio.o +OBJS += toolutil.o +OBJS += gpsutils.o + +BASEDIR := .. +include $(BASEDIR)/Makefile diff --git a/mbgshowsignal/mbgshowsignal.c b/mbgshowsignal/mbgshowsignal.c new file mode 100755 index 0000000..308fec8 --- /dev/null +++ b/mbgshowsignal/mbgshowsignal.c @@ -0,0 +1,182 @@ + +/************************************************************************** + * + * $Id: mbgshowsignal.c 1.8 2009/09/29 15:02:15 martin REL_M $ + * + * Description: + * Main file for mbgshowsignal program which demonstrates how to + * access a Meinberg device via IOCTL calls and show the modulation + * signal (second marks) of a longwave receiver, e.g. for DCF77. + * + * ----------------------------------------------------------------------- + * $Log: mbgshowsignal.c $ + * Revision 1.8 2009/09/29 15:02:15 martin + * Updated version number to 3.4.0. + * Revision 1.7 2009/07/24 09:50:09 martin + * Updated version number to 3.3.0. + * Revision 1.6 2009/06/19 12:38:52 martin + * Updated version number to 3.2.0. + * Revision 1.5 2009/03/19 17:04:26 martin + * Updated version number to 3.1.0. + * Updated copyright year to include 2009. + * Revision 1.4 2008/12/22 12:44:43 martin + * Changed ealier program name mbgdcfmod to mbgshowsignal. + * Updated description, copyright, revision number and string. + * Use unified functions from toolutil module. + * Accept device name(s) on the command line. + * Don't use printf() without format, which migth produce warnings + * with newer gcc versions. + * Revision 1.3 2007/07/24 09:32:11 martin + * Updated copyright to include 2007. + * Revision 1.2 2003/04/25 10:28:05 martin + * Use new functions from mbgdevio library. + * New program version v2.1. + * Revision 1.1 2001/09/17 15:08:09 martin + * + **************************************************************************/ + +// include Meinberg headers +#include +#include +#include // common utility functions + +// include system headers +#include +#include +#include +#include + + +static const char *pname = "mbgshowsignal"; +static const char *pversion = "v3.4.0"; +static const char *pcopyright = "(c) Meinberg 2001-2009"; + + + +static /*HDR*/ +int show_modulation( MBG_DEV_HANDLE dh ) +{ + static time_t prv_sys_t; + time_t sys_t; + uchar status_port; // current value of the clock's status port + PCPS_TIME t; + int signal; + int rc = mbg_get_status_port( dh, &status_port ); // read status port + + if ( mbg_ioctl_err( rc, "mbg_get_status_port" ) ) + return -1; + + // show signal only once per second + sys_t = time( NULL ); + + if ( sys_t == prv_sys_t ) + return 0; + + prv_sys_t = sys_t; + + rc = mbg_get_time( dh, &t ); + + if ( mbg_ioctl_err( rc, "mbg_get_time" ) ) + return -1; + + + // The current value of the modulation (second mark) is returned + // in a single bit of the status port, so ignore the other bits. + printf( "\rMod: %c", ( status_port & PCPS_ST_MOD ) ? '*' : '_' ); + + signal = t.signal - PCPS_SIG_BIAS; + + if ( signal < 0 ) + signal = 0; + else + if ( signal > PCPS_SIG_MAX ) + signal = PCPS_SIG_MAX; + + printf( " Signal: %u%% ", signal * 100 / PCPS_SIG_MAX ); + + return 0; + +} // show_modulation + + + +static /*HDR*/ +int do_mbgshowsignal( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev ) +{ + int has_mod = 0; + int rc = mbg_dev_has_mod( dh, &has_mod ); + + if ( mbg_ioctl_err( rc, "mbg_dev_has_mod" ) ) + goto fail; + + if ( !has_mod ) + { + printf( "This device does not support monitoring signal modulation.\n" ); + goto done; + } + + printf( "\nMonitoring signal modulation:\n" ); + + for (;;) + if ( show_modulation( dh ) < 0 ) + goto fail; + +done: + return 0; + +fail: + return -1; + +} // do_mbgshowsignal + + + +static /*HDR*/ +void usage( void ) +{ + mbg_print_usage_intro( pname, + "This program displays the modulation signal of cards which receive\n" + "a slowly modulated input signal, e.g. the longwave signal from DCF77.\n" + ); + mbg_print_help_options(); + mbg_print_device_options(); + puts( "" ); + +} // usage + + + +int main( int argc, char *argv[] ) +{ + int c; + int rc; + + mbg_print_program_info( pname, pversion, pcopyright ); + + // check command line parameters + while ( ( c = getopt( argc, argv, "h?" ) ) != -1 ) + { + switch ( c ) + { + case 'h': + case '?': + default: + must_print_usage = 1; + } + } + + if ( must_print_usage ) + { + usage(); + return 1; + } + + // The function below checks which devices have been specified + // on the command, and for each device + // - tries to open the device + // - shows basic device info + // - calls the function passed as last parameter + rc = mbg_check_devices( argc, argv, optind, do_mbgshowsignal ); + + return abs( rc ); +} diff --git a/mbgstatus/Makefile b/mbgstatus/Makefile new file mode 100755 index 0000000..3501003 --- /dev/null +++ b/mbgstatus/Makefile @@ -0,0 +1,50 @@ + +######################################################################### +# +# $Id: Makefile 1.7.1.4 2010/08/30 09:05:24 martin TEST $ +# +# Description: +# Makefile for mbgstatus. +# +# ----------------------------------------------------------------------- +# $Log: Makefile $ +# Revision 1.7.1.4 2010/08/30 09:05:24 martin +# Revision 1.7.1.3 2010/08/30 08:20:32 martin +# Revision 1.7.1.2 2010/08/24 08:35:11 martin +# This basically builds kernel modules and user space apps correctly. +# However, there's still an absolute path specification which needs +# to be resolved. +# Revision 1.7.1.1 2010/08/24 08:02:05 martin +# Revision 1.7 2009/07/24 10:31:17 martin +# Moved declarations to a common file which is now included. +# Revision 1.6 2008/12/22 11:54:32 martin +# Changed enumeration of source files. +# Revision 1.5 2007/03/02 11:45:10 martin +# Parameter "DEBUG=1" lets the target be built with debug enabled. +# Revision 1.4 2006/08/22 09:06:07 martin +# Added new library module mbgmktm.c. +# Revision 1.3 2003/04/25 10:21:06 martin +# Updated source module list. +# Revision 1.2 2002/11/21 14:56:31 martin +# New targets install and uninstall. +# Revision 1.1 2001/09/17 15:08:59 martin +# +######################################################################### + +TARGET = mbgstatus +INST_DIR = /usr/local/bin + +OBJS := $(TARGET).o +OBJS += mbgdevio.o +OBJS += toolutil.o +OBJS += gpsutils.o +OBJS += pcpsutil.o +OBJS += mbgmktm.o +OBJS += pcpslstr.o +OBJS += parmpcps.o +OBJS += parmgps.o +OBJS += ctrydttm.o +OBJS += ctry.o + +BASEDIR := .. +include $(BASEDIR)/Makefile diff --git a/mbgstatus/mbgstatus.c b/mbgstatus/mbgstatus.c new file mode 100755 index 0000000..e1251a3 --- /dev/null +++ b/mbgstatus/mbgstatus.c @@ -0,0 +1,808 @@ + +/************************************************************************** + * + * $Id: mbgstatus.c 1.13.1.6 2010/11/25 14:54:51 martin TEST $ + * + * Description: + * Main file for mbgstatus program which demonstrates how to + * access a Meinberg device via IOCTL calls and prints device + * information. + * + * ----------------------------------------------------------------------- + * $Log: mbgstatus.c $ + * Revision 1.13.1.6 2010/11/25 14:54:51 martin + * Revision 1.13.1.5 2010/11/05 12:54:22 martin + * Introduce "verbose" flag and associated command line parameter -v. + * Revision 1.13.1.4 2010/10/15 11:28:56 martin + * Display UTC offs from IRIG signal. + * Revision 1.13.1.3 2010/08/30 08:22:24 martin + * Revision 1.13.1.2 2010/08/11 15:06:49 martin + * Preliminarily display raw IRIG data, if supported by the device. + * Revision 1.13.1.1 2010/02/17 14:11:43 martin + * Cosmetics ... + * Revision 1.13 2009/09/29 15:02:16 martin + * Updated version number to 3.4.0. + * Revision 1.12 2009/07/24 14:02:59 martin + * Display LAN and PTP status of PTP cards. + * Updated version number to 3.3.0. + * Revision 1.11 2009/06/19 14:20:36 martin + * Display raw IRIG time with TCR cards which support this. + * Revision 1.10 2009/06/16 08:21:08 martin + * Intermediate version 3.1.0a. + * Display IRIG debug status, if supported by the card. + * Revision 1.9 2009/03/20 11:35:41 martin + * Updated version number to 3.1.0. + * Updated copyright year to include 2009. + * Display signal source after signal level. + * Display GPS UTC parameter info, if supported by the card. + * Display IRIG control bits, if supported by the card. + * Revision 1.8 2008/12/22 12:48:18 martin + * Updated description, copyright, revision number and string. + * Use unified functions from toolutil module. + * Warn if a PCI Express device with unsafe IRQ support is detected. + * Account for signed irq_num. + * Accept device name(s) on the command line. + * Don't use printf() without format, which migth produce warnings + * with newer gcc versions. + * Revision 1.7 2007/07/24 09:33:52 martin + * Fixed display of port and IRQ resources. + * Updated copyright to include 2007. + * Revision 1.6 2006/03/10 12:38:22 martin + * Fixed printing of sign in print_position(). + * Revision 1.5 2004/11/08 15:41:56 martin + * Modified formatted printing of date/time string. + * Using type casts to avoid compiler warnings. + * Revision 1.4 2003/07/30 08:16:39 martin + * Also displays oscillator DAC values for GPS. + * Revision 1.3 2003/07/08 15:38:57 martin + * Call mbg_find_devices(). + * Account for swap_doubles() now being called inside + * the mbgdevio API functions. + * Show IRQ number assigned to a device. + * Revision 1.2 2003/04/25 10:28:05 martin + * Use new functions from mbgdevio library. + * New program version v2.1. + * Revision 1.1 2001/09/17 15:08:59 martin + * + **************************************************************************/ + +// include Meinberg headers +#include +#include +#include +#include +#include // common utility functions + + +// include system headers +#include +#include +#include + + +static const char *pname = "mbgstatus"; +static const char *pversion = "v3.4.0"; +static const char *pcopyright = "(c) Meinberg 2001-2009"; + +static unsigned int verbose; + +static const char *ref_name[N_PCPS_REF]= PCPS_REF_NAMES_ENG; +static const char *icode_rx_names[N_ICODE_RX] = DEFAULT_ICODE_RX_NAMES; +static const char *osc_name[N_GPS_OSC] = DEFAULT_GPS_OSC_NAMES; + +static int year_limit = 1990; + +static int max_ref_offs_h = MBG_REF_OFFS_MAX / MINS_PER_HOUR; + +LANGUAGE language; +CTRY ctry; + + + +static /*HDR*/ +void print_pcps_time( const char *s, const PCPS_TIME *tp, const char *tail ) +{ + const char *fmt = "%s"; + char ws[256]; + + if ( s ) + printf( fmt, s ); + + printf( fmt, pcps_date_time_str( ws, tp, year_limit, pcps_tz_name( tp, PCPS_TZ_NAME_FORCE_UTC_OFFS, 0 ) ) ); + + if ( verbose > 1 ) + printf( ", st: 0x%02lX", (ulong) tp->status ); + + if ( tail ) + printf( fmt, tail ); + +} // print_pcps_time + + + +static /*HDR*/ +void print_dms( const char *s, const DMS *p, const char *tail ) +{ + const char *fmt = "%s"; + + printf( "%s %c %3i deg %02i min %05.2f sec", + s, + p->prefix, + p->deg, + p->min, + p->sec + ); + + if ( tail ) + printf( fmt, tail ); + +} // print_dms + + + +static /*HDR*/ +void print_position( const char *s, const POS *p, const char *tail ) +{ + const char *fmt = "%s"; + double r2d = 180 / PI; + + + if ( s ) + printf( fmt, s ); + + if ( verbose > 0 ) + { + printf( " x: %.0fm y: %.0fm z: %.0fm", + p->xyz[XP], p->xyz[YP], p->xyz[ZP] ); + + if ( tail ) + printf( fmt, tail ); + } + + // LLA latitude and longitude are in radians, convert to degrees + printf( " lat: %+.4f lon: %+.4f alt: %.0fm", + p->lla[LAT] * r2d, p->lla[LON] * r2d, p->lla[ALT] ); + + if ( tail ) + printf( fmt, tail ); + + print_dms( " latitude: ", &p->latitude, tail ); + print_dms( " longitude:", &p->longitude, tail ); + +} // print_position + + + +/*HDR*/ +int snprint_ip4_addr( char *s, size_t max_len, const IP4_ADDR *addr ) +{ + int n; + + n = snprintf( s, max_len, "%i.%i.%i.%i", + BYTE_OF( *addr, 3 ), + BYTE_OF( *addr, 2 ), + BYTE_OF( *addr, 1 ), + BYTE_OF( *addr, 0 ) + ); + + return n; + +} // snprint_ip4_addr + + + +static /*HDR*/ +void show_time_and_status( MBG_DEV_HANDLE dh, const PCPS_DEV *pdev, const char *tail ) +{ + const char *status_fmt = "Status info: %s%s\n"; + const char *status_err = "*** "; + const char *status_ok = ""; + PCPS_TIME t; + PCPS_STATUS_STRS strs; + int signal; + int ref_type; + int i; + int rc = mbg_get_time( dh, &t ); + if ( mbg_ioctl_err( rc, "mbg_get_time" ) ) + return; + + + print_pcps_time( "Date/time: ", &t, tail ); + + if ( ( verbose > 0 ) && _pcps_has_hr_time( pdev ) ) + { + PCPS_HR_TIME ht; + char ws[80]; + + rc = mbg_get_hr_time( dh, &ht ); + + if ( mbg_ioctl_err( rc, "mbg_get_hr_time" ) ) + return; + + mbg_snprint_hr_time( ws, sizeof( ws ), &ht ); + printf( "Local HR time: %s", ws ); + + if ( verbose > 1 ) + printf( ", st: 0x%04lX", (ulong) ht.status ); + + printf( "%s", tail ); + } + + signal = t.signal - PCPS_SIG_BIAS; + + if ( signal < 0 ) + signal = 0; + else + if ( signal > PCPS_SIG_MAX ) + signal = PCPS_SIG_MAX; + + ref_type = _pcps_ref_type( pdev ); + + if ( ref_type >= N_PCPS_REF ) + ref_type = PCPS_REF_NONE; + + printf( "Signal: %u%% (%s", signal * 100 / PCPS_SIG_MAX, ref_name[ref_type] ); + + if ( _pcps_is_irig_rx( pdev ) ) + { + IRIG_INFO irig_rx_info; + MBG_REF_OFFS ref_offs; + + rc = mbg_get_irig_rx_info( dh, &irig_rx_info ); + + if ( rc == MBG_SUCCESS ) + { + int idx = irig_rx_info.settings.icode; + + if ( idx < N_ICODE_RX ) + { + printf( " %s", icode_rx_names[idx] ); + + if ( !( MSK_ICODE_RX_HAS_TZI & ( 1UL << idx ) ) ) + { + if ( _pcps_has_ref_offs( pdev ) ) + { + rc = mbg_get_ref_offs( dh, &ref_offs ); + + if ( rc == MBG_SUCCESS ) + { + int ref_offs_h = ref_offs / MINS_PER_HOUR; + + if ( abs( ref_offs_h ) > max_ref_offs_h ) + printf( ", ** UTC offs not configured **" ); + else + printf( ", UTC%+ih", ref_offs_h ); + } + } + } + } + } + } + + puts( ")" ); + + if ( _pcps_has_irig_time( pdev ) ) + { + PCPS_IRIG_TIME it; + + rc = mbg_get_irig_time( dh, &it ); + + if ( !mbg_ioctl_err( rc, "mbg_get_irig_time" ) ) + printf( "Raw IRIG time: yday %u, %02u:%02u:%02u\n", + it.yday, it.hour, it.min, it.sec ); + } + + if ( _pcps_is_irig_rx( pdev ) ) + { + printf( status_fmt, + ( signal < PCPS_SIG_ERR ) ? status_err : status_ok, + ( signal < PCPS_SIG_ERR ) ? "NO INPUT SIGNAL" + : "Input signal available" ); + } + else + { + printf( status_fmt, + ( signal < PCPS_SIG_ERR ) ? status_err : status_ok, + ( signal < PCPS_SIG_ERR ) ? "ANTENNA IS NOT CONNECTED" + : "Antenna is connected" ); + } + + // Evaluate the status code and setup status messages. + pcps_status_strs( t.status, _pcps_time_is_read( &t ), + _pcps_is_gps( pdev ), &strs ); + + // Print the status messages. + for ( i = 0; i < N_PCPS_STATUS_STR; i++ ) + { + PCPS_STATUS_STR *pstr = &strs.s[i]; + if ( pstr->cp ) + printf( status_fmt, + pstr->is_err ? status_err : status_ok, + pstr->cp ); + } + +} // show_time_and_status + + + +static /*HDR*/ +void show_sync_time( MBG_DEV_HANDLE dh, const char *tail ) +{ + PCPS_TIME t; + int rc = mbg_get_sync_time( dh, &t ); + + if ( mbg_ioctl_err( rc, "mbg_get_sync_time" ) ) + return; + + print_pcps_time( "Last sync: ", &t, tail ); + +} // show_sync_time + + + +static /*HDR*/ +void show_ext_stat_info( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev, const char *tail ) +{ + const char *fmt = "%s"; + RECEIVER_INFO ri; + STAT_INFO si = { 0 }; + char ws[80]; + char *mode_name; + + int rc = mbg_setup_receiver_info( dh, p_dev, &ri ); + + if ( mbg_ioctl_err( rc, "mbg_get_gps_stat_info" ) ) + return; + + + if ( _pcps_is_gps( p_dev ) ) + { + rc = mbg_get_gps_stat_info( dh, &si ); + + if ( mbg_ioctl_err( rc, "mbg_get_gps_stat_info" ) ) + return; + + switch ( si.mode ) + { + case AUTO_166: mode_name = "Normal Operation"; break; + case WARM_166: mode_name = "Warm Boot"; break; + case COLD_166: mode_name = "Cold Boot"; break; + + default: // This should never happen! + sprintf( ws, "Unknown mode of operation: %02Xh", si.mode ); + mode_name = ws; + + } // switch + + printf( "%s, %i sats in view, %i sats used\n", mode_name, si.svs_in_view, si.good_svs ); + } + + printf( "Osc type: %s", osc_name[( ri.osc_type < N_GPS_OSC ) ? ri.osc_type : GPS_OSC_UNKNOWN] ); + + if ( _pcps_is_gps( p_dev ) ) + { + printf( ", DAC cal: %+i, fine: %+i", + (int) ( si.dac_cal - OSC_DAC_BIAS ), + (int) ( si.dac_val - OSC_DAC_BIAS ) ); + } + + puts( "" ); + + if ( tail ) + printf( fmt, tail ); + +} // show_ext_stat_info + + + +static /*HDR*/ +void show_gps_pos( MBG_DEV_HANDLE dh, const char *tail ) +{ + POS pos; + int rc = mbg_get_gps_pos( dh, &pos ); + + if ( mbg_ioctl_err( rc, "mbg_get_gps_pos" ) ) + return; + + print_position( "Receiver Position:\n", &pos, tail ); + +} // show_gps_pos + + + +static /*HDR*/ +void show_utc_info( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev ) +{ + UTC utc; + + int rc = mbg_get_utc_parm( dh, &utc ); + + if ( mbg_ioctl_err( rc, "mbg_get_utc_parm" ) ) + return; + + if ( !utc.valid ) + { + puts( "** UTC parameters not valid" ); + return; + } + + if ( verbose > 1 ) + { + //##++++ utc.delta_tls = utc.delta_tlsf - 1; + + printf( "CSUM: %04X, valid: %04X\n", utc.csum, utc.valid ); + printf( "t0t: %u|%u.%07u, A0: %g A1: %g\n", + utc.t0t.wn, utc.t0t.sec, utc.t0t.tick, + utc.A0, utc.A1 ); + printf( "WNlsf: %u, DN: %u, offs: %i/%i\n", + utc.WNlsf, utc.DNt, utc.delta_tls, utc.delta_tlsf ); + } + + if ( utc.delta_tls != utc.delta_tlsf ) + { + // a leap second is currently being announced + time_t t_ls = (time_t) utc.WNlsf * SECS_PER_WEEK + + (time_t) utc.DNt * SECS_PER_DAY + + GPS_SEC_BIAS - 1; + + struct tm *tm = gmtime( &t_ls ); + + printf( "UTC offset transition from %is to %is due to leap second\n" + "%s at UTC midnight at the end of %04i-%02i-%02i.\n", + utc.delta_tls, utc.delta_tlsf, + ( utc.delta_tls < utc.delta_tlsf ) ? "insertion" : "deletion", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday + ); + } + else + printf( "UTC offset parameter: %is, no leap second announced.\n", utc.delta_tls ); + +} // show_utc_info + + + +static /*HDR*/ +void show_irig_ctrl_bits( MBG_DEV_HANDLE dh ) +{ + MBG_IRIG_CTRL_BITS irig_ctrl_bits; + + int rc = mbg_get_irig_ctrl_bits( dh, &irig_ctrl_bits ); + + if ( mbg_ioctl_err( rc, "mbg_get_irig_ctrl_bits" ) ) + return; + + printf( "IRIG control bits: %08lX (hex, LSB first)", (ulong) irig_ctrl_bits ); + printf( ", TFOM: 0x%X", _pcps_tfom_from_irig_ctrl_bits( &irig_ctrl_bits ) ); + printf( "\n" ); + +} // show_irig_ctrl_bits + + + +static /*HDR*/ +char *str_raw_irig_utc_offs_hours( char *s, int max_len, const MBG_RAW_IRIG_DATA *p ) +{ + int n; + long offs = ( p->data_bytes[8] & 0x08 ) + | ( ( p->data_bytes[8] >> 2 ) & 0x04 ) + | ( ( p->data_bytes[8] >> 4 ) & 0x02 ) + | ( ( p->data_bytes[8] >> 6 ) & 0x01 ); + + n = snprintf( s, max_len, "%c%li", ( p->data_bytes[8] & 0x80 ) ? '-' : '+', offs ); + + if ( p->data_bytes[8] & 0x02 ) + n += snprintf( &s[n], max_len - n, "%s", ".5" ); + + return s; + +} // str_raw_irig_utc_offs_hours + + + +static /*HDR*/ +void show_raw_irig_data( MBG_DEV_HANDLE dh ) +{ + MBG_RAW_IRIG_DATA raw_irig_data; + char ws[80]; + int i; + + int rc = mbg_get_raw_irig_data( dh, &raw_irig_data ); + + if ( mbg_ioctl_err( rc, "mbg_get_raw_irig_data" ) ) + return; + + printf( "Raw IRIG data:" ); + + for ( i = 0; i < sizeof( raw_irig_data ); i++ ) + printf( " %02X", raw_irig_data.data_bytes[i] ); + + printf( " (hex)" ); + printf( ", TFOM: 0x%X", _pcps_tfom_from_raw_irig_data( &raw_irig_data ) ); + printf( ", UTC offs: %sh", str_raw_irig_utc_offs_hours( ws, sizeof( ws ), &raw_irig_data ) ); + printf( "\n" ); + +} // show_raw_irig_data + + + +static /*HDR*/ +void show_irig_debug_status( MBG_DEV_HANDLE dh ) +{ + static const char *status_str[N_MBG_DEBUG_BIT] = MBG_DEBUG_STATUS_STRS; + + MBG_DEBUG_STATUS st; + int i; + int rc = _mbg_generic_read_var( dh, PCPS_GET_DEBUG_STATUS, st ); + + if ( mbg_ioctl_err( rc, "show_irig_debug_status" ) ) + return; + + printf( "Debug status (hex): %08lX\n", (ulong) st ); + + for ( i = 0; i < N_MBG_DEBUG_BIT; i++ ) + if ( st & ( 1UL << i ) ) + printf( " %s\n", status_str[i] ); + +} // show_irig_debug_status + + + +static /*HDR*/ +void show_lan_intf_state( MBG_DEV_HANDLE dh ) +{ + IP4_SETTINGS ip4_settings; + LAN_IF_INFO lan_if_info; + char ws[100]; + + int rc = mbg_get_ip4_state( dh, &ip4_settings ); + + if ( mbg_ioctl_err( rc, "mbg_get_ip4_state" ) ) + return; + + rc = mbg_get_lan_if_info( dh, &lan_if_info ); + + if ( mbg_ioctl_err( rc, "mbg_get_lan_if_info" ) ) + return; + + + printf( "On-board LAN interface settings:\n" ); + + snprintf( ws, sizeof( ws ), "%02X-%02X-%02X-%02X-%02X-%02X", + lan_if_info.mac_addr[0], + lan_if_info.mac_addr[1], + lan_if_info.mac_addr[2], + lan_if_info.mac_addr[3], + lan_if_info.mac_addr[4], + lan_if_info.mac_addr[5] + ); + printf( " MAC Address: %s\n", ws ); + + snprint_ip4_addr( ws, sizeof( ws ), &ip4_settings.ip_addr ); + printf( " IP Address: %s%s\n", ws, ( ip4_settings.flags & IP4_MSK_DHCP ) ? + " (DHCP)" : "" ); + + snprint_ip4_addr( ws, sizeof( ws ), &ip4_settings.netmask ); + printf( " Net Mask: %s\n", ws ); + + snprint_ip4_addr( ws, sizeof( ws ), &ip4_settings.broad_addr ); + printf( " Broadcast Addr: %s\n", ws ); + + snprint_ip4_addr( ws, sizeof( ws ), &ip4_settings.gateway ); + printf( " Gateway: %s\n", ws ); + + printf( " Link detected: %s\n", ( ip4_settings.flags & IP4_MSK_LINK ) ? "YES" : "NO" ); + +} // show_lan_intf_state + + + +static /*HDR*/ +void show_ptp_state( MBG_DEV_HANDLE dh ) +{ + static const char *ptp_stat_str[N_PTP_PORT_STATE] = PTP_PORT_STATE_STRS; + char ws[100]; + const char *cp; + int ptp_state_available; + PTP_STATE ptp_state; + + int rc = _mbg_generic_read_gps_var( dh, PC_GPS_PTP_STATE, ptp_state ); + + if ( mbg_ioctl_err( rc, "reading PTP state" ) ) + return; + + + printf( "PTP port status:\n" ); + + printf( " Port mode: %s\n", ( ptp_state.port_state < N_PTP_PORT_STATE ) ? + ptp_stat_str[ptp_state.port_state] : "(undefined)" ); + + ptp_state_available = ( ptp_state.port_state == PTP_PORT_STATE_SLAVE ); + + cp = ptp_state_available ? ws : str_not_avail; + + snprintf( ws, sizeof( ws ), "%02X-%02X-%02X-%02X-%02X-%02X", + ptp_state.gm_identity.b[0], + ptp_state.gm_identity.b[1], + ptp_state.gm_identity.b[2], + ptp_state.gm_identity.b[5], + ptp_state.gm_identity.b[6], + ptp_state.gm_identity.b[7] + ); + printf( " Grandmaster MAC: %s\n", cp ); + + + snprintf( ws, sizeof( ws ), "%c%li.%09li s", + _nano_time_negative( &ptp_state.path_delay ) ? '-' : '+', + labs( (long) ptp_state.path_delay.secs ), + labs( (long) ptp_state.path_delay.nano_secs ) + ); + printf( " PTP path delay: %s\n", cp ); + + + snprintf( ws, sizeof( ws ), "%c%li.%09li s", + _nano_time_negative( &ptp_state.offset ) ? '-' : '+', + labs( (long) ptp_state.offset.secs ), + labs( (long) ptp_state.offset.nano_secs ) + ); + printf( " PTP time offset: %s\n", cp ); + +} // show_ptp_state + + + +static /*HDR*/ +int check_irq_unsafe( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev ) +{ + PCPS_IRQ_STAT_INFO irq_stat_info; + int ret_val = 0; + int rc = mbg_get_irq_stat_info( dh, &irq_stat_info ); + + if ( mbg_ioctl_err( rc, "mbg_get_irq_stat_info" ) ) + return -1; + + if ( irq_stat_info & PCPS_IRQ_STAT_UNSAFE ) + { + static const char *warn_line = "************************************************************************************"; + + puts( "" ); + puts( warn_line ); + + printf( + "** WARNING!\n" + "**\n" + "** Device %s with S/N %s has a firmware version and ASIC version\n" + "** which do not allow safe operation with hardware interrupts (IRQs) enabled.\n" + "**\n" + "** Please see http://www.meinberg.de/english/info/pex-upgrades.htm\n" + "** for information how the card can easily be upgraded, or contact\n" + "** Meinberg support (Email: support@meinberg.de) or your local\n" + "** representative.\n" + , + _pcps_type_name( p_dev ), _pcps_sernum( p_dev ) + ); + + if ( irq_stat_info & PCPS_IRQ_STAT_ENABLED ) + { + printf( + "**\n" + "** Interrupts are currently enabled for this card (NTP daemon running?)\n" + "** so other access is inhibited to prevent the system from hanging.\n" + ); + + ret_val = -1; + } + + puts( warn_line ); + puts( "" ); + } + + return ret_val; + +} // check_irq_unsafe + + + +static /*HDR*/ +int do_mbgstatus( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev ) +{ + int ret_val = 0; + + if ( check_irq_unsafe( dh, p_dev ) < 0 ) + goto done; + + if ( _pcps_has_gps_data( p_dev ) ) + show_ext_stat_info( dh, p_dev, NULL ); + + show_time_and_status( dh, p_dev, "\n" ); + show_sync_time( dh, "\n" ); + + if ( _pcps_is_gps( p_dev ) ) + show_gps_pos( dh, "\n" ); + + if ( _pcps_has_utc_parm( p_dev ) ) + show_utc_info( dh, p_dev ); + + if ( _pcps_has_irig_ctrl_bits( p_dev ) ) + show_irig_ctrl_bits( dh ); + + if ( _pcps_has_raw_irig_data( p_dev ) ) + show_raw_irig_data( dh ); + + if ( _pcps_is_irig_rx( p_dev ) ) + show_irig_debug_status( dh ); + + if ( _pcps_has_lan_intf( p_dev ) ) + show_lan_intf_state( dh ); + + if ( _pcps_has_ptp( p_dev ) ) + show_ptp_state( dh ); + +done: + return ret_val; + +} // do_mbgstatus + + + +static /*HDR*/ +void usage( void ) +{ + mbg_print_usage_intro( pname, + "This program prints status information for a device.\n" + "The displayed information depends on the type of the card." + ); + mbg_print_help_options(); + mbg_print_device_options(); + puts( "" ); + +} // usage + + + +int main( int argc, char *argv[] ) +{ + int c; + int rc; + + ctry_setup( 0 ); + language = LNG_ENGLISH; + ctry.dt_fmt = DT_FMT_YYYYMMDD; + ctry.dt_sep = '-'; + + mbg_print_program_info( pname, pversion, pcopyright ); + + // check command line parameters + while ( ( c = getopt( argc, argv, "vh?" ) ) != -1 ) + { + switch ( c ) + { + case 'v': + verbose++; + break; + + case 'h': + case '?': + default: + must_print_usage = 1; + } + } + + if ( must_print_usage ) + { + usage(); + return 1; + } + + + if ( verbose ) + pcps_date_time_dist = 1; + + // The function below checks which devices have been specified + // on the command, and for each device + // - tries to open the device + // - shows basic device info + // - calls the function passed as last parameter + rc = mbg_check_devices( argc, argv, optind, do_mbgstatus ); + + return abs( rc ); +} diff --git a/mbgsvcd/Makefile b/mbgsvcd/Makefile new file mode 100755 index 0000000..d8a8fe8 --- /dev/null +++ b/mbgsvcd/Makefile @@ -0,0 +1,31 @@ + +######################################################################### +# +# $Id: Makefile 1.1.1.2.1.1 2010/09/20 12:07:10 stefan TEST $ +# +# Description: +# Makefile for mbgsvcd. +# +# ----------------------------------------------------------------------- +# $Log: Makefile $ +# Revision 1.1.1.2.1.1 2010/09/20 12:07:10 stefan +# Updated for use with latest base Makefile. +# Revision 1.1.1.2 2010/08/30 09:05:24 martin +# Revision 1.1.1.1 2010/08/30 08:22:06 martin +# Revision 1.1 2010/02/03 16:07:18 daniel +# Revision 1.1 2009/09/29 08:34:23 martin +# +######################################################################### + +TARGET = mbgsvcd +INST_TO_BIN = 1 + +OBJS = $(TARGET).o +OBJS += mbgdevio.o +OBJS += toolutil.o +OBJS += gpsutils.o +OBJS += mbgmktm.o +OBJS += pcpsmktm.o + +BASEDIR := .. +include $(BASEDIR)/Makefile diff --git a/mbgsvcd/mbgsvcd.c b/mbgsvcd/mbgsvcd.c new file mode 100755 index 0000000..54e4410 --- /dev/null +++ b/mbgsvcd/mbgsvcd.c @@ -0,0 +1,436 @@ + +/************************************************************************** + * + * $Id: mbgsvcd.c 1.3.1.1 2010/04/26 14:37:41 martin TEST $ + * + * Description: + * Main file for mbgsvcd which compares the system time to a PCI card's + * time and transfers this data pair to the SHM driver of the ntpd. + * + * ----------------------------------------------------------------------- + * $Log: mbgsvcd.c $ + * Revision 1.3.1.1 2010/04/26 14:37:41 martin + * Print PC cycles counter frequency at program start. + * Revision 1.3 2010/03/03 14:59:36 martin + * Support -p parameter to pretend sync. + * Revision 1.2 2010/02/03 16:15:09 daniel + * Revision 1.1 2010/02/03 16:07:18 daniel + * + **************************************************************************/ + +// include Meinberg headers +#include +#include +#include // common utility functions +#include + +// include system headers +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +#define NTPD_BASE 0x4e545030 /* "NTP0" */ +#define SHM_UNIT 0 /* SHM driver unit number (0..3) */ +#define MAX_SHM_REFCLOCKS 4 + +#define RUNNING_DIR "/var/run/mbgsvcd" +#define LOCK_FILE "mbgsvcd.pid" + +#define EXEC_TIME_SAMPLES 20 + +static const char *pname = "mbgsvcd"; +static const char *pversion = "v1.1"; +static const char *pcopyright = "(c) Meinberg 2010"; + +static int sleep_intv = 1; +static int pretend_sync; + + +struct shmTime { + int mode; /* 0 - if valid set + * use values, + * clear valid + * 1 - if valid set + * if count before and after read of + * values is equal, + * use values + * clear valid + */ + int count; + time_t clockTimeStampSec; /* external clock */ + int clockTimeStampUSec; /* external clock */ + time_t receiveTimeStampSec; /* internal clock, when external value was received */ + int receiveTimeStampUSec; /* internal clock, when external value was received */ + int leap; + int precision; + int nsamples; + int valid; + int dummy[10]; +}; + +struct shmTime *shmTime[MAX_SHM_REFCLOCKS]; + + +static +struct shmTime *getShmTime(int unit) +{ + int shmid = shmget( (key_t) ( NTPD_BASE + unit ), + sizeof( struct shmTime ), IPC_CREAT | 0644 ); + + if ( shmid == -1 ) + { + syslog(LOG_ERR, "shmget failed\n"); + return NULL; + } + else + { + struct shmTime *p = ( struct shmTime * ) shmat( shmid, 0, 0); + + if ( (int) (long) p == -1 ) + { + syslog(LOG_ERR, "shmat failed\n" ); + return NULL; + } + + syslog(LOG_INFO, "shmat(%d,0,0) succeeded\n", shmid); + return p; + } +} + + + +void ntpshm_init( void ) +{ + int i = 0; + + syslog(LOG_INFO, "Initializing shared memory for ntpd"); + + for ( i = 0; i< MAX_SHM_REFCLOCKS; i++) + shmTime[i] = getShmTime(i); +} + + + +int ntpshm_alloc( void ) +{ + int i; + + for ( i = 0; i< MAX_SHM_REFCLOCKS; i++) + { + if ( shmTime[i] != NULL ) + { + memset( (void* ) shmTime[i], 0, sizeof( struct shmTime ) ); + + shmTime[i]->mode = 1; + shmTime[i]->precision = -5; /* initially 0.5 sec */ + shmTime[i]->nsamples = 3; /* stages of median filter */ + + printf( "Shared memory %d initialized\n", i ); + } + } + return 0; +} + + + +static /*HDR*/ +int do_mbgsvctasks( void ) +{ + MBG_PC_CYCLES_FREQUENCY cyc_freq; + MBG_TIME_INFO_HRT hrti; + PCPS_TIME_STAMP *p_ref_ts; + MBG_PC_CYCLES *p_ref_cyc; + MBG_SYS_TIME_CYCLES *p_sys_tic; + char ws[256]; + double d_ref; + double d_sys; + int rc = 0; + int n_devices = 0; + MBG_DEV_HANDLE dhs[4]; + PCPS_DEV devs[4]; + int i,excnt; + double exec_limit = 30.0; + double exec_times[EXEC_TIME_SAMPLES]; + + n_devices = mbg_find_devices(); + + i = excnt = 0; + + if ( n_devices == 0 ) + { + printf("No devices found!\n"); + goto done; + } + + // Search for devices up to the maximum of supported NTP SHM refclocks + if ( n_devices > MAX_SHM_REFCLOCKS ) + n_devices = MAX_SHM_REFCLOCKS; + + syslog(LOG_INFO, "Found %d devices for NTPD", n_devices); + + for ( i = 0; i < n_devices; i++ ) + { + dhs[i] = mbg_open_device(i); + mbg_get_device_info( dhs[i], &devs[i] ); + } + + rc = mbg_get_default_cycles_frequency_from_dev( dhs[0], &cyc_freq ); + + if ( mbg_ioctl_err( rc, "mbg_get_default_cycles_frequency_from_dev" ) ) + goto done; + + printf( "PC cycles counter clock frequency: %Lu Hz\n", + (unsigned long long) cyc_freq ); + + // Initialize NTP shared memory area + ntpshm_init(); + ntpshm_alloc(); + + for (;;) + { + + for ( i = 0; i < n_devices; i++ ) + { + double ltcy_us,exec_us; + + if ( !_pcps_has_hr_time( &devs[i] ) ) + { + printf( "This device does not support HR time stamps.\n" ); + continue; + } + else + { + rc = mbg_get_time_info_hrt( dhs[i], &hrti ); + + if ( mbg_ioctl_err( rc, "mbg_get_time_info_..." ) ) + continue; + + p_ref_ts = &hrti.ref_hr_time_cycles.t.tstamp; + p_ref_cyc = &hrti.ref_hr_time_cycles.cycles; + p_sys_tic = &hrti.sys_time_cycles; + } + + mbg_snprint_hr_tstamp( ws, sizeof( ws ), p_ref_ts ); + d_ref = (double) p_ref_ts->sec + ( (double) p_ref_ts->frac ) / (double) PCPS_HRT_BIN_FRAC_SCALE; + d_sys = (double) p_sys_tic->sys_time.tv_sec + (double) p_sys_tic->sys_time.tv_usec / 1e6; + + printf ( "%-9s: %s UTC: %.6f-%.6f: %+.6f s",_pcps_type_name( &devs[i] ), + ws, d_ref, d_sys, d_ref - d_sys ); + { + double ltcy_sec,exec_sec; + + MBG_PC_CYCLES ltcy_cyc = mbg_delta_pc_cycles( p_ref_cyc, &p_sys_tic->cyc_after ); + MBG_PC_CYCLES exec_cyc = mbg_delta_pc_cycles( &p_sys_tic->cyc_after, &p_sys_tic->cyc_before ); + + ltcy_sec = ( (double) ltcy_cyc ) / (double) cyc_freq; + exec_sec = ( (double) exec_cyc ) / (double) cyc_freq; + + // compensate latencies between time stamps -> + // normalize ref time to system time stamp + d_ref -= ltcy_sec; + + ltcy_us = ltcy_sec * 1e6; + exec_us = exec_sec * 1e6; + + exec_times[excnt++] = exec_us; + + if (excnt == EXEC_TIME_SAMPLES) + { + exec_limit = 0; + + for ( excnt = 0; excnt < EXEC_TIME_SAMPLES; excnt++) + exec_limit += exec_times[excnt]; + + exec_limit /= ( (double) EXEC_TIME_SAMPLES ); + exec_limit = (exec_limit * 1.7); + excnt = 0; + } + + printf( ", ltcy: %.2f us, exec: %.2f us, limit: %.2f us: %+.6f s", ltcy_us, exec_us, exec_limit, d_ref - d_sys ); + } + + // check if refclock is sync and if exec time of the system time call was fast enough + if ( pretend_sync || ( ( ( hrti.ref_hr_time_cycles.t.status & PCPS_FREER ) == 0 ) + && ( ( hrti.ref_hr_time_cycles.t.status & PCPS_SYNCD ) != 0 ) + && ( exec_us < exec_limit ) ) ) + { + printf(" *\n"); + + // fill SHM structure + shmTime[i]->count++; + shmTime[i]->clockTimeStampSec = (time_t) d_ref; + shmTime[i]->clockTimeStampUSec = (int) ( ( d_ref - shmTime[i]->clockTimeStampSec ) * 1e6 ); // get µs from d_ref + shmTime[i]->receiveTimeStampSec = (time_t) p_sys_tic->sys_time.tv_sec; + shmTime[i]->receiveTimeStampUSec = (int) p_sys_tic->sys_time.tv_usec; + + // patch precision value according to the ref time accuracy + if ( _pcps_is_lwr( &devs[i] ) ) + shmTime[i]->precision = -8; + else if (_pcps_is_irig_rx( &devs[i] ) ) + { + if ( _pcps_is_usb( &devs[i] ) ) + shmTime[i]->precision = -10; + else + shmTime[i]->precision = -18; + } + else + shmTime[i]->precision = -20; + + shmTime[i]->count++; + shmTime[i]->valid = 1; + } + else + printf("\n"); + + usleep(10); + } + + printf("\n"); + + if ( sleep_intv ) + sleep( sleep_intv ); + } + +done: + for ( i = 0; i < n_devices; i++ ) + mbg_close_device( &dhs[i] ); + + return rc; + +} // do_mbgchksystime + + + +static /*HDR*/ +void usage( void ) +{ + mbg_print_usage_intro( pname, + "This deamon reads a time stamp from every refclock together.\n" + "with an associated system time stamp and transfers it to the SHM\n" + "refclock driver of NTP.\n" + "This works only with cards which support high resolution time stamps." + ); + mbg_print_help_options(); + mbg_print_opt_info( "-f", "run program in foreground" ); + mbg_print_opt_info( "-s num", "sleep num seconds between calls" ); + mbg_print_opt_info( "-p", "pretend device is always synchronized" ); + mbg_print_device_options(); + puts( "" ); + +} // usage + + + +void startup_daemon( void ) +{ + int i,lfp; + char str[1024]; + + if (getppid()==1) + return; /* already a daemon */ + + printf ("Daemon mode, backgrounding ... \n"); + i=fork(); + + if (i<0) + exit(1); /* fork error */ + + if (i>0) + exit(0); /* parent exits */ + + /* child (daemon) continues */ + setsid(); /* obtain a new process group */ + for (i=getdtablesize(); i>=0; --i) + close(i); /* close all descriptors */ + + i=open("/dev/null",O_RDWR); dup(i); dup(i); /* handle standart I/O */ + + umask(027); /* set newly created file permissions */ + chdir(RUNNING_DIR); /* change running directory */ + + lfp = open(LOCK_FILE,O_RDWR|O_CREAT,0640); + + if (lfp<0) + exit(1); /* can not open */ + + if (lockf(lfp,F_TLOCK,0)<0) + { + syslog(LOG_ERR, "Lock file already exists, another instance of this daemon seems to be running"); + closelog(); + exit(0); /* can not lock */ + } + + /* first instance continues */ + sprintf(str,"%d\n",getpid()); + write(lfp,str,strlen(str)); /* record pid to lockfile */ + + signal(SIGCHLD,SIG_IGN); /* ignore child */ + signal(SIGTSTP,SIG_IGN); /* ignore tty signals */ + signal(SIGTTOU,SIG_IGN); + signal(SIGTTIN,SIG_IGN); +} + + + + + +int main( int argc, char *argv[] ) +{ + int rc; + int c; + int foreground = 0; + + mbg_print_program_info( pname, pversion, pcopyright ); + + // check command line parameters + while ( ( c = getopt( argc, argv, "fps:h?" ) ) != -1 ) + { + switch ( c ) + { + case 'f': + foreground = 1; + break; + case 'p': + pretend_sync = 1; + break; + case 's': + sleep_intv = atoi( optarg ); + break; + + case 'h': + case '?': + default: + must_print_usage = 1; + } + } + + if ( must_print_usage ) + { + usage(); + return 1; + } + + if ( foreground == 0 ) + startup_daemon(); + + syslog(LOG_INFO, "Starting Meinberg Service Daemon %s %s %s", pname, pversion, pcopyright ); + + rc = do_mbgsvctasks(); + + return abs( rc ); +} diff --git a/mbgxhrtime/Makefile b/mbgxhrtime/Makefile new file mode 100755 index 0000000..75d6673 --- /dev/null +++ b/mbgxhrtime/Makefile @@ -0,0 +1,33 @@ + +######################################################################### +# +# $Id: Makefile 1.2.1.2.1.1 2010/09/20 12:07:14 stefan TEST $ +# +# Description: +# Makefile for mbgxhrtime. +# +# ----------------------------------------------------------------------- +# $Log: Makefile $ +# Revision 1.2.1.2.1.1 2010/09/20 12:07:14 stefan +# Updated for use with latest base Makefile. +# Revision 1.2.1.2 2010/08/30 09:05:24 martin +# Revision 1.2.1.1 2010/08/30 08:22:11 martin +# Revision 1.2 2009/07/24 10:31:17 martin +# Moved declarations to a common file which is now included. +# Revision 1.1 2008/12/22 11:05:24 martin +# Initial revision. +# +######################################################################### + +TARGET = mbgxhrtime +INST_TO_BIN = 1 + +USE_THREAD_API = 1 + +OBJS = $(TARGET).o +OBJS += mbgdevio.o +OBJS += toolutil.o +OBJS += gpsutils.o + +BASEDIR := .. +include $(BASEDIR)/Makefile diff --git a/mbgxhrtime/mbgxhrtime.c b/mbgxhrtime/mbgxhrtime.c new file mode 100755 index 0000000..bceb331 --- /dev/null +++ b/mbgxhrtime/mbgxhrtime.c @@ -0,0 +1,334 @@ + +/************************************************************************** + * + * $Id: mbgxhrtime.c 1.5 2009/09/29 14:25:07 martin REL_M $ + * + * Description: + * Main file for mbgxhrtime program which demonstrates how to retrieve + * fast and accurate timestamps. + * + * This program starts a polling thread which reads a high resolution + * time stamp and associated CPU cycles counter value once per second + * and saves that data pair. + * + * Current time stamps are then computed by taking the current CPU + * cycles value and extrapolating the time from the last data pair. + * + * This is very much faster than accessing the PCI card for every + * single time stamp. + * + * Notes: + * + * 1.) This approach works / makes sense only with cards which support + * high resolution time stamps (HR time). If a card doesn't support + * that then this program prints a warning. + * + * 2.) Under Linux extrapolation is done using the time stamp counter + * (TSC) registers provided by Pentium CPUs and newer/compatible + * types as the cycles counter. On SMP / multicore CPUs those + * counters may not be synchronized, so this works only correctly + * if all cycles counter values are taken from the same CPU. + * To achieve this the process CPU affinity is by default set to + * the first CPU at program start, which means all threads of this + * process are executed only on that CPU. + * + * 3.) Under Linux there's no easy way to find the accurate clock + * frequency of the cycles counter, so the polling thread computes + * the frequency from the time differences of 2 subsequent polls + * of the PCI card. If the time extrapolation function is called + * before the cycles clock frequency has been determined the + * returned time stamp is always 0. + * + * ----------------------------------------------------------------------- + * $Log: mbgxhrtime.c $ + * Revision 1.5 2009/09/29 14:25:07 martin + * Display measured and default PC cycles frequency. + * Updated version number to 3.4.0. + * Revision 1.4 2009/07/24 09:50:09 martin + * Updated version number to 3.3.0. + * Revision 1.3 2009/06/19 12:38:52 martin + * Updated version number to 3.2.0. + * Revision 1.2 2009/03/19 17:04:26 martin + * Updated version number to 3.1.0. + * Updated copyright year to include 2009. + * Revision 1.1 2008/12/22 11:05:24 martin + * Initial revision. + * + **************************************************************************/ + +// include Meinberg headers +#include +#include +#include // common utility functions + +// include system headers +#include +#include +#include +#include +#include +#include + + +#if !defined( MBGDEVIO_USE_THREAD_API ) + #error Symbol MBGDEVIO_USE_THREAD_API needs to be defined, see the Makefile. +#endif + +#if !defined ( USE_PROCESS_AFFINITY ) + #define USE_PROCESS_AFFINITY 1 +#endif + + +static const char *pname = "mbgxhrtime"; +static const char *pversion = "v3.4.0"; +static const char *pcopyright = "(c) Meinberg 2008-2009"; + +static int loops; + + + +#if USE_PROCESS_AFFINITY + +static /*HDR*/ +void print_cpu_set( const char *info, MBG_CPU_SET *p_cpu_set ) +{ + int min_cpu = MBG_CPU_SET_SIZE + 1; + int max_cpu = 0; + int i; + + for ( i = 0; i < MBG_CPU_SET_SIZE; i++ ) + { + if ( !_mbg_cpu_isset( i, p_cpu_set ) ) + continue; + + if ( i < min_cpu ) + min_cpu = i; + + if ( i > max_cpu ) + max_cpu = i; + } + + printf( "%s: CPU%i", info, min_cpu ); + + if ( max_cpu == min_cpu ) + printf( " only" ); + else + printf( "...CPU%i", max_cpu ); + + printf( "\n" ); + +} // print_cpu_set + + + +/*HDR*/ +void check_set_process_affinity_mask( MBG_PROCESS_ID pid, int cpu_num ) +{ + MBG_CPU_SET cpu_set; + + int rc = mbg_get_process_affinity( pid, &cpu_set ); + + if ( rc < 0 ) + { + perror( "Failed to get process affinity mask" ); + exit( 1 ); + } + + print_cpu_set( "Initial process affinity mask", &cpu_set ); + + _mbg_cpu_clear( &cpu_set ); + _mbg_cpu_set( cpu_num, &cpu_set ); + + rc = mbg_set_process_affinity( pid, &cpu_set ); + + if ( rc < 0 ) + { + perror( "Failed to set process affinity mask" ); + exit( 1 ); + } + + printf( "Process affinity mask set for CPU%i only\n", cpu_num ); + +} // check_set_process_affinity_mask + +#endif + + + +static /*HDR*/ +int do_mbgxhrtime( MBG_DEV_HANDLE dh, const PCPS_DEV *p_dev ) +{ + MBG_PC_CYCLES_FREQUENCY freq_hz = 0; + MBG_PC_CYCLES_FREQUENCY default_freq_hz = 0; + int this_loops = loops; + MBG_POLL_THREAD_INFO poll_thread_info = { { { { 0 } } } }; + int rc; + + if ( !_pcps_has_hr_time( p_dev ) ) + { + printf( "High resolution time not supported by this device.\n" ); + return 0; + } + + mbg_get_default_cycles_frequency_from_dev( dh, &default_freq_hz ); + + rc = mbg_xhrt_poll_thread_create( &poll_thread_info, dh, 0, 0 ); + + if ( rc != MBG_SUCCESS ) + return -1; + + + for (;;) + { + static int has_printed_msg = 0; + + PCPS_HR_TIME hrt; + char ws[80]; + MBG_PC_CYCLES cyc_1; + MBG_PC_CYCLES cyc_2; + double latency; + + rc = mbg_get_xhrt_cycles_frequency( &poll_thread_info.xhrt_info, &freq_hz ); + + if ( rc != MBG_SUCCESS ) + goto fail; + + if ( freq_hz == 0 ) + { + if ( !has_printed_msg ) + { + printf( "Waiting until PC cycles frequency has been computed ... " ); + has_printed_msg = 1; + } + + usleep( 50000 ); + continue; + } + + if ( has_printed_msg ) + { + puts( "" ); + + printf( "PC cycles freq: %.6f MHz", ( (double) freq_hz ) / 1E6 ); + + if ( default_freq_hz ) + printf( ", default: %.6f MHz", ( (double) default_freq_hz ) / 1E6 ); + + printf( "\n" ); + + has_printed_msg = 0; + } + + // get an extrapolated time stamp bracketed by + // mbg_get_pc_cycles() calls to compute the latency + mbg_get_pc_cycles( &cyc_1 ); + rc = mbg_get_xhrt_time_as_pcps_hr_time( &poll_thread_info.xhrt_info, &hrt ); + mbg_get_pc_cycles( &cyc_2 ); + + if ( rc != MBG_SUCCESS ) + goto fail; + + // compute the latency + latency = ( (double) cyc_2 - (double) cyc_1 ) / (double) freq_hz * 1E6; + + // convert to human readable date and time + mbg_snprint_hr_time( ws, sizeof( ws ), &hrt ); + printf( "t: %s (%.3f us)\n", ws, latency ); + + if ( this_loops > 0 ) + this_loops--; + + if ( this_loops == 0 ) + break; + + // if this_loops is < 0 then loop forever + } + + goto done; + +fail: + fprintf( stderr, "** Aborting: xhrt function returned %i\n", rc ); + +done: + mbg_xhrt_poll_thread_stop( &poll_thread_info ); + + mbg_close_device( &dh ); + + return rc; + +} // do_mbgxhrtime + + + +static /*HDR*/ +void usage( void ) +{ + mbg_print_usage_intro( pname, + "This example program reads fast extrapolated high resolution time stamps.\n" + "\n" + "The program starts an extra polling thread which reads a high resolution\n" + "time stamp plus associated PC cycles counter at regular intervals.\n" + "The returned time stamps are extrapolated using the current PC cycles\n" + "count value plus the last time stamp/cycles pair read by the polling thread.\n" + "\n" + "This is very much faster than accessing the card every time a time stamp\n" + "needs to be retrieved.\n" + "This works only for devices which support high resolution time (HR time)." + ); + mbg_print_help_options(); + mbg_print_opt_info( "-c", "run continuously" ); + mbg_print_opt_info( "-n num", "run num loops" ); + mbg_print_device_options(); + puts( "" ); + +} // usage + + + +int main( int argc, char *argv[] ) +{ + int rc; + int c; + + mbg_print_program_info( pname, pversion, pcopyright ); + + // check command line parameters + while ( ( c = getopt( argc, argv, "cn:h?" ) ) != -1 ) + { + switch ( c ) + { + case 'c': + loops = -1; + break; + + case 'n': + loops = atoi( optarg ); + break; + + case 'h': + case '?': + default: + must_print_usage = 1; + } + } + + if ( must_print_usage ) + { + usage(); + return 1; + } + + #if USE_PROCESS_AFFINITY + check_set_process_affinity_mask( _mbg_get_current_process(), 0 ); + puts( "" ); + #endif + + // The function below checks which devices have been specified + // on the command, and for each device + // - tries to open the device + // - shows basic device info + // - calls the function passed as last parameter + rc = mbg_check_devices( argc, argv, optind, do_mbgxhrtime ); + + return abs( rc ); +} -- cgit v1.2.3