summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Burnicki <martin.burnicki@meinberg.de>2023-02-28 23:12:41 +0100
committerMartin Burnicki <martin.burnicki@meinberg.de>2023-02-28 23:12:41 +0100
commit31dc5b6f6a84517a0e7b7f2fe4c49210771992fa (patch)
tree64e08b43ac2f72dc78bc674ff25d2d094883b816
parentb73cfc31e68b854f3f7dbf8837168c1c7b6eb31b (diff)
downloadmbgreadtimestring-31dc5b6f6a84517a0e7b7f2fe4c49210771992fa.tar.gz
mbgreadtimestring-31dc5b6f6a84517a0e7b7f2fe4c49210771992fa.zip
Update existing mbglib files
-rw-r--r--mbglib/common/mbg_tgt.h910
-rw-r--r--mbglib/common/mbg_tmo.h181
-rw-r--r--mbglib/common/mbgserio.c1753
-rw-r--r--mbglib/common/mbgserio.h410
-rw-r--r--mbglib/common/words.h647
5 files changed, 3228 insertions, 673 deletions
diff --git a/mbglib/common/mbg_tgt.h b/mbglib/common/mbg_tgt.h
index d5aba94..07bdcf8 100644
--- a/mbglib/common/mbg_tgt.h
+++ b/mbglib/common/mbg_tgt.h
@@ -1,7 +1,7 @@
/**************************************************************************
*
- * $Id: mbg_tgt.h 1.22 2009/10/01 08:20:50 martin REL_M $
+ * $Id: mbg_tgt.h 1.54 2022/09/01 15:46:33 martin.burnicki REL_M $
*
* Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
*
@@ -11,6 +11,129 @@
*
* -----------------------------------------------------------------------
* $Log: mbg_tgt.h $
+ * Revision 1.54 2022/09/01 15:46:33 martin.burnicki
+ * Suppress deprecated function warnings if
+ * NO_WARN_DEPRECATED is defined.
+ * Revision 1.53 2022/03/17 16:38:57Z martin.burnicki
+ * Added definitions MBG_DEV_HANDLE_FMT.
+ * Revision 1.52 2021/10/05 09:10:44Z martin
+ * Clean up definitions _MBG_API_ATTR_EXPORT and _MBG_API_ATTR_IMPORT.
+ * Revision 1.51 2021/09/13 08:59:55 martin
+ * New definitions _MBG_API_ATTR_EXPORT and _MBG_API_ATTR_IMPORT.
+ * Required if variables that are exported by a DLL are to be
+ * imported into a different DLL.
+ * Revision 1.50 2021/03/18 11:08:51 martin
+ * Updated some comments.
+ * Revision 1.49 2021/03/12 11:51:37 martin
+ * Corrected the wording of some comments.
+ * Revision 1.48 2021/02/10 13:34:35 martin
+ * Defined MBG_TGT_MISSING_STRUCT_TIMESPEC for CVI.
+ * Revision 1.47 2019/11/12 15:33:59 martin
+ * Added some doxygen comments.
+ * Revision 1.46 2019/08/28 12:52:02 martin
+ * Changes for mingw.
+ * Revision 1.45 2019/02/11 09:53:02Z martin
+ * Support the mingw build environment.
+ * Changed inclusion of winsock2.h/windows.h on Windows.
+ * Removed obsolete RCS log entries.
+ * Revision 1.44 2018/12/11 15:34:15 martin
+ * Older Visual Studio versions don't support _strtoi64().
+ * Revision 1.43 2018/11/22 11:28:01Z martin
+ * New preprocessor symbol MBG_TGT_USE_IOCTL.
+ * Provide 'uintptr_t' for old Linux kernels.
+ * Removed obsolete Windows driver stuff.
+ * Revision 1.42 2018/09/20 09:40:21 martin
+ * Define MBG_TGT_MISSTNG_STRTOLL and
+ * MBG_TGT_MISSING_LLDDIV_T, if appropriate.
+ * Revision 1.41 2018/08/23 10:49:56Z martin
+ * Enhanced handling of Windows DDK builds.
+ * Revision 1.40 2018/07/02 16:57:49Z martin
+ * Removed obsolete define MBG_USE_MM_IO_FOR_PCI.
+ * Revision 1.39 2018/06/25 10:52:00 martin
+ * Support MBG_TGT_NO_TGT.
+ * Default settings for KERNEL_HAS_BOOL and KERNEL_HAS_TRUE_FALSE
+ * for Linux can be overridden by project settings.
+ * Renamed MBG_PRE64_PREFIX to MBG_PRI_64_PREFIX.
+ * MBG_PRI_64_PREFIX_L or MBG_PRI_64_PREFIX_LL can be used
+ * to override the defaults with specific project settings.
+ * MBG_TGT_HAS_DEV_FN is supported on Windows, but
+ * MBG_TGT_HAS_DEV_FN_BASE is not supported.
+ * Enhanced debug support for Windows kernel drivers.
+ * Include limits.h on Windows.
+ * Defined MBG_TGT_MISSING_STRUCT_TIMESPEC for Borland C.
+ * Defined __func__ for BC 5 and for DOS, and provide a
+ * common default declaration..
+ * Updated some comments.
+ * Revision 1.38 2017/08/08 13:07:31 martin
+ * Proper fix for PRId64 and others.
+ * Define _CRT_SECURE_NO_WARNINGS only if not already defined.
+ * Revision 1.37 2017/07/10 07:08:45 thomas-b
+ * Define PRId64 if it is not defined in inttypes.h
+ * Revision 1.36 2017/07/04 12:35:11 martin
+ * Fixed build for Windows kernel space.
+ * Don't define ssize_t if HAVE_SSIZE_T is already defined.
+ * Added definition for _NO_MBG_API.
+ * Fixed missing 'bool' type for old Linux kernels.
+ * Fixed missing 'struct timespec' for DOS.
+ * Evaluate preprocessor symbol KERNEL_HAS_BOOL to avoid
+ * compiler errors due to duplicate definitions in specific
+ * Linux kernels patched by the distro maintainers.
+ * Provide ssize_t for C++Builder 5.
+ * Improved Visual Studio version checking.
+ * New define MBG_TGT_HAS_NODE_NAME.
+ * Revision 1.35 2016/08/05 12:21:34 martin
+ * Conditionally define a macro _DEPRECATED_BY which can be used to
+ * tag functions as deprecated, so compilers can emit appropriate warnings.
+ * New symbol MBG_TGT_HAS_ABS64.
+ * Moved some compatibility definitions from gpsserio.h here.
+ * Define ssize_t for Windows, if required.
+ * Conditionally provided struct timespec for Windows.
+ * Added compatible 64 bit type print format specifiers.
+ * Include inttypes.h for all targets providing also stdint.h.
+ * Added some MSVC version code information.
+ * Fixes for FreeBSD.
+ * Fixed some spelling.
+ * Tmp workaround for 2.6.32-5-sparc64.
+ * Proper fix required.
+ * Revision 1.34 2015/03/03 13:32:49 martin
+ * Provide __func__ for MS Visual Studio.
+ * Revision 1.33 2015/03/02 11:27:59Z martin
+ * Windows only:
+ * Define _CRT_SECURE_NO_WARNINGS to quiet compiler warnings.
+ * Define WIN32_LEAN_AND_MEAN only if it hasn't been defined before.
+ * Revision 1.32 2014/06/24 09:21:44 martin
+ * Update for newer C++Builder versions.
+ * Revision 1.31 2014/05/27 10:23:33 martin
+ * Finer control of which types are required for or already
+ * available on particular target systems.
+ * First definitions to support SunOS/Solaris.
+ * Revision 1.30 2014/04/01 12:55:58 martin
+ * Define MBG_TGT_WIN32 also for MS resource compiler.
+ * New target MBG_TGT_POSIX.
+ * Always include winsock2.h and windows.h for MBG_TGT_WIN32.
+ * Always include unistd.h for MBG_TGT_POSIX.
+ * Define empty __attribute__ macro for non-gcc environments.
+ * Revision 1.29 2013/02/01 14:50:46 martin
+ * Fixed a typo which caused an error with Borland CBuilder 5.
+ * Revision 1.28 2012/12/12 10:03:16Z martin
+ * Fix for Borland C 3.1.
+ * Revision 1.27 2012/11/29 12:03:14Z martin
+ * Moved definition of _no_macro_fnc() to words.h.
+ * Revision 1.26 2012/11/02 09:01:47Z martin
+ * Merged some stuff depending on the build environment here
+ * and cleaned up.
+ * Revision 1.25 2012/04/04 07:17:18 martin
+ * Treat QNX Neutrino as Unix target.
+ * Revision 1.24 2011/08/23 10:21:23 martin
+ * New symbol _NO_MBG_API_ATTR which can be used with functions
+ * which are going to be exported by a DLL, but actually aren't, yet.
+ * Revision 1.23 2011/08/19 10:47:00 martin
+ * Don't include stddef.h.
+ * Distinguish between different gcc target platforms.
+ * Initial support for IA64 platform.
+ * Support wchar_t for BSD.
+ * Defined _NO_USE_PACK_INTF for Sparc and IA64.
+ * Fixed typo in comment.
* Revision 1.22 2009/10/01 08:20:50 martin
* Fixed inline code support with different BC versions.
* Revision 1.21 2009/09/01 10:34:23Z martin
@@ -36,12 +159,12 @@
* 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.
+ * Recognize DOS target with 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
+ * 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
+ * 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).
@@ -50,7 +173,7 @@
* 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
+ * On 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.
@@ -67,7 +190,7 @@
* 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.
+ * Don't setup for Win32 PNP if explicitly configured non-PNP.
* Revision 1.1 2002/02/19 13:46:20Z MARTIN
* Initial revision
*
@@ -79,7 +202,9 @@
/* Other headers to be included */
-#include <stddef.h>
+#ifdef MBG_TGT_NO_TGT
+ #include <mbg_no_tgt.h>
+#else
#ifdef _MBG_TGT
#define _ext
@@ -90,11 +215,35 @@
/* Start of header body */
-#if defined( _CVI ) || defined( _CVI_ )
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// The prefix required in a printf() format string to print an
+// int64_t type (i.e. "%li", "%lli", "I64i", etc.) may vary depending
+// on the compiler type and version, and the associated run time library.
+// For user space applications this is usually defined in the header
+// files provided by the build environment, but for kernel code there
+// are often no such defines, but there are some commonly used defaults.
+// This is a hack that can be used to override these defaults in the
+// project settings for kernel code, e.g. in the Makefile.
+#if defined( MBG_PRI_64_PREFIX_L )
+ #define MBG_PRI_64_PREFIX "l"
+#elif defined( MBG_PRI_64_PREFIX_LL )
+ #define MBG_PRI_64_PREFIX "ll"
+#endif
+
+
+#if defined( _CVI_ )
- #define MBG_TGT_WIN32
#define MBG_TGT_CVI
+ #if defined( _NI_mswin_ )
+ #define MBG_TGT_WIN32
+ #else
+ #error Unsupported CVI target platform.
+ #endif
+
#elif defined( _WIN32_WINNT )
// MS platform SDK
@@ -104,7 +253,7 @@
#if ( _WIN32_WINNT >= 0x0500 )
// Win2k and above
#if !defined( MBG_TGT_WIN32_NON_PNP )
- // only if not explicitely disabled
+ // only if not explicitly disabled
#define MBG_TGT_WIN32_PNP
#endif
#endif
@@ -130,6 +279,11 @@
// MS Visual C++
#define MBG_TGT_WIN32
+#elif defined( RC_INVOKED )
+
+ // MS resource compiler
+ #define MBG_TGT_WIN32
+
#elif defined( __WINDOWS_386__ )
// Watcom C/C++ for target Win32
@@ -144,6 +298,7 @@
// Watcom C/C++ for target OS/2
#define MBG_TGT_OS2
+ #define MBG_TGT_USE_IOCTL 1
#elif defined( __linux )
@@ -151,6 +306,10 @@
#define MBG_TGT_LINUX
#define _GNU_SOURCE 1
+ #if defined( __KERNEL__ )
+ #define MBG_TGT_KERNEL
+ #endif
+
#elif defined( __FreeBSD__ )
// GCC for target FreeBSD
@@ -163,9 +322,20 @@
#elif defined( __OpenBSD__ )
- // GCC for target FreeBSD
+ // GCC for target OpenBSD
#define MBG_TGT_OPENBSD
+#elif defined( __sun ) // Oracle Solaris or other SunOS derived operating system
+
+ // __SUNPRO_C Oracle Solaris Studio C compiler, __SUNPRO_C value is the version number
+ // __SUNPRO_CC Oracle Solaris Studio C++ compiler, __SUNPRO_CC value is the version number
+ // __sparc generate code for SPARC (R) architecture (32-bit or 64-bit)
+ // __sparcv9 generate code for 64-bit SPARC architecture
+ // __i386 generate code for 32-bit x86 architecture
+ // __amd64 generate code for 64-bit x64 architecture
+
+ #define MBG_TGT_SUNOS
+
#elif defined( __QNX__ )
// any compiler for target QNX
@@ -189,39 +359,481 @@
#endif
-// Some definitions which depend on the type of compiler ...
-#if defined( __GNUC__ )
- #define __mbg_inline __inline__
+#if defined( MBG_TGT_FREEBSD ) \
+ || defined( MBG_TGT_NETBSD ) \
+ || defined( MBG_TGT_OPENBSD )
+ #define MBG_TGT_BSD
+
+ #if defined( _KERNEL )
+ #define MBG_TGT_KERNEL
+ #endif
- #define MBG_TGT_HAS_WCHAR_T defined( MBG_TGT_WIN32 )
+#endif
+
+#if defined( MBG_TGT_LINUX ) \
+ || defined( MBG_TGT_BSD ) \
+ || defined( MBG_TGT_QNX_NTO ) \
+ || defined( MBG_TGT_SUNOS )
+
+ #define MBG_TGT_POSIX
+ #define MBG_TGT_UNIX
+
+#endif
+
+#if defined( MBG_TGT_WIN32 )
+
+ #if !defined( _CRT_SECURE_NO_WARNINGS )
+ #define _CRT_SECURE_NO_WARNINGS 1
+ #endif
+
+ #include <limits.h>
+
+ #define MBG_TGT_HAS_DEV_FN 1
+ #define MBG_TGT_HAS_DEV_FN_BASE 0
+ #define MBG_TGT_USE_IOCTL 1
+
+#endif
+
+
+// Some definitions depending on the build environment ...
+
+#define FUNC_UNKNOWN "func_???"
+
+#if defined( __GNUC__ ) || defined( __clang__ )
+
+ #if defined( __clang__ )
+ #define _CLANG_VERSION ( __clang_major__ * 10000 \
+ + __clang_minor__ * 100 \
+ + __clang_patchlevel__ )
+ #endif // defined( __clang__ )
+
+ #define _GCC_VERSION ( __GNUC__ * 10000 \
+ + __GNUC_MINOR__ * 100 \
+ + __GNUC_PATCHLEVEL__ )
+
+ #if defined( __MINGW32__ )
+ #define MBG_TGT_MINGW
+ #endif
+
+ #if defined( __MINGW64__ )
+ #define MBG_TGT_MINGW
+ #endif
+
+ #if defined( MBG_TGT_MINGW ) && defined( __MINGW_EXTENSION )
+ // MSYS2 / MinGW defines __MINGW_EXTENSION
+ // and provides _abs64() and some other stuff,
+ // but the standard MinGW environment does not.
+ #if !defined( MBG_TGT_HAS_ABS64 )
+ #define MBG_TGT_HAS_ABS64 1
+ #endif
+ #endif
+
+ #if defined( __i386__ )
+
+ #define MBG_ARCH_I386
+ #define MBG_ARCH_X86
+
+ #elif defined( __x86_64__ )
- #if defined( __sparc__ )
+ #define MBG_ARCH_X86_64
+ #define MBG_ARCH_X86
+
+ #elif defined( __ia64__ )
+
+ #define MBG_ARCH_IA64
+
+ #define _NO_USE_PACK_INTF
+
+ #elif defined( __sparc__ )
#define MBG_ARCH_SPARC
- #define _MBG_ARCH_DEFINED
+
+ #define _NO_USE_PACK_INTF
#elif defined( __arm__ )
#define MBG_ARCH_ARM
- #define _MBG_ARCH_DEFINED
#endif
+ #if defined( MBG_TGT_LINUX )
+
+ #if defined( MBG_TGT_KERNEL )
+
+ #include <linux/types.h>
+ #include <linux/version.h>
+
+ #if ( LINUX_VERSION_CODE <= KERNEL_VERSION( 2, 6, 4 ) ) || \
+ ( LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 4 ) ) // must be true for 2.6.32-5-sparc64
+ #define _ULONG_DEFINED 1
+ #define _USHORT_DEFINED 1
+ #define _UINT_DEFINED 1
+ #endif
+
+ // The 'bool' type is supported by the vanilla Linux kernel 2.6.19 and later.
+ #if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2, 6, 19 ) )
+
+ // However, looks like at least the RedHat folks have backported this
+ // to 2.6.18, so KERNEL_HAS_BOOL can be defined to avoid a compiler error
+ // due to a duplicate definition.
+ #if !defined( KERNEL_HAS_BOOL )
+ typedef _Bool bool;
+ #define bool bool
+ #endif
+
+ // Similar for 'true' and 'false'.
+ #if !defined( KERNEL_HAS_TRUE_FALSE )
+ enum
+ {
+ false,
+ true
+ };
+ #define falso false
+ #define true true
+ #endif
+
+ #endif
+
+ // The 'uintptr_t' type has been introduced
+ // after v2.6.24-rc1 and before v2.6.24-rc2.
+ #if ( LINUX_VERSION_CODE < KERNEL_VERSION( 2, 6, 24 ) )
+ typedef unsigned long uintptr_t;
+ #define uintptr_t uintptr_t
+ #endif
+
+ // String formatter codes like "PRIi64" for int64_t types
+ // don't seem to be defined in Linux kernel mode, so we
+ // define the required "ll" or "l" modifier here as a hack.
+ // Code below uses this to define appropriate "PRIi64"-like
+ // definitions as "lli" or "li".
+ #if !defined( MBG_PRI_64_PREFIX )
+ // Please note that e.g. Linux 2.6.16 on Itanium (ia64)
+ // with gcc 4.1.2 expects "%li" to print an int64_t.
+ // This may be a bug in the specific gcc version, though.
+ #define MBG_PRI_64_PREFIX "ll"
+ #endif
+
+ #else
+
+ #include <stdint.h>
+ #include <inttypes.h>
+ #include <stdbool.h>
+
+ #if defined( __u_char_defined )
+ #define _ULONG_DEFINED 1
+ #define _USHORT_DEFINED 1
+ #define _UINT_DEFINED 1
+ #endif
+
+ #endif
+
+ #define MBG_TGT_HAS_DEV_FN 1
+ #define MBG_TGT_HAS_DEV_FN_BASE 1
+ #define MBG_TGT_USE_IOCTL 1
+
+ #elif defined( MBG_TGT_BSD )
+
+ #if defined( MBG_TGT_KERNEL )
+ #include <sys/types.h>
+ #else
+ #include <stdint.h>
+ #include <inttypes.h>
+ #include <stdbool.h>
+ #endif
+
+ #define MBG_TGT_HAS_DEV_FN 1
+ #define MBG_TGT_HAS_DEV_FN_BASE 1
+ #define MBG_TGT_USE_IOCTL 1
+
+ #if defined( MBG_TGT_FREEBSD ) && defined( MBG_TGT_KERNEL )
+ #if !defined( MBG_PRI_64_PREFIX )
+ // String formatter codes like "PRIi64" for int64_t types
+ // don't seem to be defined in FreeBSD kernel mode, so we
+ // define the required "ll" or "l" modifier here as a hack.
+ // Code below uses this to define appropriate "PRIi64"-like
+ // definitions as "lli" or "li".
+ #define MBG_PRI_64_PREFIX "l"
+ #endif
+ #endif
+
+ #elif defined( MBG_TGT_QNX_NTO ) // QNX 6.x (Neutrino)
+
+ #include <unistd.h>
+ #include <stdint.h>
+ #include <inttypes.h>
+ #include <stdbool.h>
+
+ #else
+
+ #include <stdint.h>
+ #include <inttypes.h>
+ #include <stdbool.h>
+
+ #endif
+
+ #define MBG_TGT_HAS_EXACT_SIZE_TYPES 1
+
+ #define MBG_TGT_HAS_WCHAR_T 1
+
+ #if !defined( NO_WARN_DEPRECATED )
+ #if defined( __clang__ )
+ #define _DEPRECATED_BY( _s ) __attribute__((deprecated("use \"" _s "\" instead"))) // works with clang 3.4.1
+ #elif ( _GCC_VERSION > 40500 ) // gcc 4.5.0 and newer
+ #define _DEPRECATED_BY( _s ) __attribute__((deprecated("use \"" _s "\" instead")))
+ #elif ( _GCC_VERSION > 30100 ) // gcc 3.1 and newer
+ #define _DEPRECATED_BY( _s ) __attribute__((deprecated))
+ #else
+ // Not supported at all, use empty default definiton below.
+ #endif
+ #endif
+
+ #if ( _GCC_VERSION > 30100 ) // gcc 3.1 and newer
+ #define __mbg_inline __inline__ __attribute__((always_inline))
+ #else
+ // Not supported at all, use empty default definiton below.
+ #define __mbg_inline __inline__
+ #endif
+
#elif defined( _MSC_VER )
+ // Known predifined MS compiler version codes:
+ // 1910: MSVC++ 15.0 (Visual Studio 2017)
+ // 1900: MSVC++ 14.0 (Visual Studio 2015)
+ // 1800: MSVC++ 12.0 (Visual Studio 2013)
+ // 1700: MSVC++ 11.0 (Visual Studio 2012)
+ // 1600: MSVC++ 10.0 (Visual Studio 2010)
+ // 1500: MSVC++ 9.0 (Visual Studio 2008)
+ // 1400: MSVC++ 8.0 (Visual Studio 2005, Windows Server 2003 SP1 DDK - AMD64)
+ // 1310: MSVC++ 7.1 (Visual Studio .NET 2003, Windows Server 2003 DDK)
+ // 1300: MSVC++ 7.0 (Visual Studio .NET 2002, Windows XP SP1 DDK / DDK 2600)
+ // 1200: MSVC++ 6.0
+ // 1100: MSVC++ 5.0
+
+ // Enable this to get compile-time messages on the compiler version
+ #if 0
+ #if ( _MSC_VER >= 1910 )
+ #error >= 1910: MSVC++ 15.0 (Visual Studio 2017), or later
+ #elif ( _MSC_VER >= 1900 )
+ #error 1900: MSVC++ 14.0 (Visual Studio 2015)
+ #elif ( _MSC_VER >= 1800 )
+ #error 1800: MSVC++ 12.0 (Visual Studio 2013)
+ #elif ( _MSC_VER >= 1700 )
+ #error 1700: MSVC++ 11.0 (Visual Studio 2012)
+ #elif ( _MSC_VER >= 1600 )
+ #error 1600: MSVC++ 10.0 (Visual Studio 2010)
+ #elif ( _MSC_VER >= 1500 )
+ #error 1500: MSVC++ 9.0 (Visual Studio 2008)
+ #elif ( _MSC_VER >= 1400 )
+ #error STRINGIFY( _MSC_VER ) MSVC++ 8.0 (Visual Studio 2005, Windows Server 2003 SP1 DDK - AMD64)
+ #elif ( _MSC_VER >= 1310 )
+ #error 1310: MSVC++ 7.1 (Visual Studio .NET 2003, Windows Server 2003 DDK)
+ #elif ( _MSC_VER >= 1300 )
+ #error 1300: MSVC++ 7.0 (Visual Studio .NET 2002, Windows XP SP1 DDK / DDK 2600)
+ #elif ( _MSC_VER >= 1200 )
+ #error 1200: MSVC++ 6.0
+ #elif ( _MSC_VER >= 1100 )
+ #error 1100: MSVC++ 5.0
+ #else
+ #error <1100: Older than MSVC 4
+ #endif
+ #endif
+
+ // "struct timespec" is supported only since VS2015
+ // If it is, also the symbol TIME_UTC should be defined.
+ // Functions to read the current time as struct timespec
+ // are timespec_get() and friends, which are also only provided
+ // by VS2015 and later.
+ // As of VS2015, only TIME_UTC is supported to read
+ // the UTC system time, there is no equivalent for
+ // the POSIX CLOCK_MONOTONIC. However, QPC can be used
+ // to get monotonic time stamps and intervals.
+ #if ( _MSC_VER < 1900 )
+ #if !defined( HAVE_STRUCT_TIMESPEC )
+ #define MBG_TGT_MISSING_STRUCT_TIMESPEC 1
+ #endif
+ #endif
+
+ #if ( _MSC_VER >= 1600 ) // TODO Even 1600 probably doesn't support this.
+ #include <stdint.h>
+ #include <inttypes.h>
+ #define MBG_TGT_HAS_EXACT_SIZE_TYPES 1
+
+ #if !defined( PRId64 )
+ #define MBG_PRI_64_PREFIX "I64"
+ #endif
+ #else
+ #define MBG_TGT_HAS_INT_8_16_32 1
+ #define MBG_PRI_64_PREFIX "I64"
+ #endif
+
+ #if !defined( __cplusplus )
+ // no bool support anyway
+ #define MBG_TGT_MISSING_BOOL_TYPE 1
+ #endif
+
+ #define MBG_TGT_HAS_WCHAR_T 1
+
#define __mbg_inline __forceinline
- #define MBG_TGT_HAS_WCHAR_T 1
+ // At least up to VS2008 the C99 builtin symbol __func__
+ // is not supported. Some VS versions support __FUNCTION__
+ // instead, but at least VC6 doesn't support this, either.
+ // of the current function instead.
+ #if ( _MSC_VER >= 1300 )
+ #define __func__ __FUNCTION__
+ #else
+ #define __func__ FUNC_UNKNOWN
+ #endif
+
+ // The "deprecated" attribute should be supported since Visual Studio 2005,
+ // but doesn't seem to be supported e.g. by the compiler shipped with the
+ // "Windows Server 2003 SP1 DDK", which is used to build kernel drivers
+ // and defines the same _MSC_VER number as VS2005. For now we assume
+ // that this is supported by compilers shipped with newer DDKs.
+ // The _DDK_BUILD_ symbol has to be explicitly defined in the "sources"
+ // file of the DDK project.
+ #if ( ( _MSC_VER >= 1500 ) || \
+ ( ( _MSC_VER >= 1400 ) && !defined( _DDK_BUILD_ ) ) )
+ #if !defined( NO_WARN_DEPRECATED )
+ #define _DEPRECATED_BY( _s ) __declspec(deprecated("deprecated, use \"" _s "\""))
+ #endif
+ #endif
+
+ // availability of _abs64()
+ #if ( _MSC_VER >= 1310 )
+ // This is supported at least since Visual Studio 2008
+ // and Windows Server 2003 SP1 DDK.
+
+ #if !defined( MBG_TGT_HAS_ABS64 )
+ #define MBG_TGT_HAS_ABS64 1
+ #endif
+ #endif
+
+ #if !defined ( HAVE_SSIZE_T )
+
+ // ssize_t support
+ #if ( _MSC_VER >= 1500 )
+ // ssize_t may not be defined, but SSIZE_T is
+ #include <basetsd.h>
+ typedef SSIZE_T ssize_t;
+ #else
+ // At least VC6 hasn't SIZE_T, either, but size_t
+ // is typedef'ed as unsigned int, so we just typedef
+ // the signed variant here.
+ typedef int ssize_t;
+ #endif
-#elif defined( _CVI ) || defined( _CVI_ )
+ #define HAVE_SSIZE_T 1
- // Inline code is not supported.
+ #endif // !defined ( HAVE_SSIZE_T )
- #define MBG_TGT_HAS_WCHAR_T 0
+ #if ( _MSC_VER <= 1500 )
+ // At least MSVC++ 9.0 / Visual Studio 2008 and older
+ // don't provide lldiv_t and lldiv().
+ #define MBG_TGT_MISSING_LLDIV_T 1
+ #endif
-#elif defined( __BORLANDC__ )
+ #if ( _MSC_VER <= 1400 )
+ #define MBG_TGT_MISSING_STRTOLL 1
+ #elif ( _MSC_VER <= 1600 )
+ // At least MSVC++ 10.0 / Visual Studio 2010 and older
+ // don't provide strtoll(), but may provide _strtoi64 instead.
+ #define strtoll _strtoi64
+ #endif
+
+#elif defined( _CVI_ )
+
+ // 1000 for CVI v10.0 (CVI 2010)
+ // 911 for CVI v9.1.1 (CVI 2009 SP1)
+ // 910 for CVI v9.1 (CVI 2009)
+ // 310 for CVI v3.1
+ // 301 for CVI v3.0.1
+ // 1 for CVI v3.0
+
+ #if ( _CVI_ >= 910 )
+ // LabWindows/CVI 2009 is the first version providing stdint.h.
+ #include <stdint.h>
+ #include <inttypes.h>
+ #define MBG_TGT_HAS_EXACT_SIZE_TYPES 1
+ #else
+ #define USE_LONG_FOR_INT32 1
+ #endif
+
+ // As of LabWindows/CVI 2010, stdbool.h is still missing.
+ #define MBG_TGT_MISSING_BOOL_TYPE 1
+
+ #define MBG_TGT_HAS_WCHAR_T 0
+
+ // Inline code is not supported, though the inline keyword
+ // is silently accepted since CVI v9.0
+
+#elif defined( __BORLANDC__ ) // or __CODEGEARC__ in newer versions
+
+ // 0x0200 Borland C/C++ 2.0
+ // 0x0400 Borland C/C++ 3.0
+ // 0x0410 Borland C/C++ 3.1
+ // 0x0550 Borland C/C++ 5.5 (C++Builder 5.0)
+
+ // Next codes are in addition defined as __CODEGEARC__
+ // See http://docwiki.embarcadero.com
+
+ // 0x0570 for Borland Developer Studio 2006 (BDS 2006)
+ // 0x0590 for C++Builder 2007
+ // 0x0591 for update 1 to C++Builder 2007
+ // 0x0592 for RAD Studio 2007
+ // 0x0593 for the December update to RAD Studio 2007
+ // 0x0610 for C++Builder 2009 and for C++Builder 2009 Update 1
+ // 0x0620 for C++Builder 2010 and for C++Builder 2010 Update 1
+ // 0x0621 for C++Builder 2010 Update 2
+ // 0x0630 for C++Builder XE
+ // 0x0631 for C++Builder XE Update 1
+ // 0x0640 for C++Builder XE2
+ // 0x0650 for C++Builder XE3
+
+ #if ( __BORLANDC__ >= 0x630 )
+ // C++Builder XE starts to provide stdbool.h
+ #include <stdint.h>
+ #include <inttypes.h>
+ #include <stdbool.h>
+ #define MBG_TGT_HAS_EXACT_SIZE_TYPES 1
+ #elif ( __BORLANDC__ >= 0x570 )
+ // BDS/Borland C++ Builder 2006 starts to provide at least stdint.h
+ #include <stdint.h>
+ #include <inttypes.h>
+ #define MBG_TGT_HAS_EXACT_SIZE_TYPES 1
+ #if !defined( __cplusplus )
+ #define MBG_TGT_MISSING_BOOL_TYPE 1
+ #endif
+ #elif ( __BORLANDC__ >= 0x0550 )
+ #define MBG_TGT_HAS_INT_8_16_32 1
+ #define MBG_PRI_64_PREFIX "I64"
+ #if !defined( __cplusplus )
+ #define MBG_TGT_MISSING_BOOL_TYPE 1
+ #endif
+ #define __func__ FUNC_UNKNOWN
+ #else // e.g. BC 3.1 or earlier
+ #if ( __BORLANDC__ <= 0x410 )
+ #define MBG_TGT_MISSING_64_BIT_TYPES 1
+ #define MBG_TGT_MISSING_BOOL_TYPE 1
+ #define USE_LONG_FOR_INT32 1
+ #define MBG_TGT_MISSING_STRUCT_TIMESPEC 1
+ #define __func__ __FILE__ ":" STRINGIFY(__LINE__)
+
+ typedef int ssize_t;
+ #endif
+ #endif
+
+ #if ( __BORLANDC__ <= 0x0550 )
+ // At least CBuilder 5 and earlier.
+ #define MBG_TGT_MISSING_STRTOLL 1
+ #define MBG_TGT_MISSING_LLDIV_T 1
+ #endif
+
+ #define MBG_TGT_HAS_WCHAR_T defined( MBG_TGT_WIN32 )
+
+ #define MBG_TGT_MISSING_STRUCT_TIMESPEC 1
#if defined( __cplusplus )
#define __mbg_inline inline // standard C++ syntax
@@ -231,44 +843,76 @@
#define __mbg_inline // up to BC3.1 not supported for C
#endif
- #define MBG_TGT_HAS_WCHAR_T defined( MBG_TGT_WIN32 )
+ #if !defined ( HAVE_SSIZE_T )
+ typedef int ssize_t; // required at least for C++ Builder 5
+ #define HAVE_SSIZE_T 1
+ #endif
#elif defined( __WATCOMC__ )
- #define __mbg_inline _inline
+ // 1050 v10.5
+ // 1100 v11.0
+ // 1200 Open Watcom C++ v1.0
+ // 1230 Open Watcom C++ v1.3
+ // 1270 Open Watcom C++ v1.7
- #define MBG_TGT_HAS_WCHAR_T defined( MBG_TGT_WIN32 )
+ #if defined( MBG_TGT_QNX ) // QNX 4.x
-#endif
+ #include <sys/types.h>
+
+ #define MBG_TGT_MISSING_64_BIT_TYPES 1
+ #elif ( __WATCOMC__ > 1230 ) // Open Watcom C 1.3 and above
+ #include <stdint.h>
+ #include <inttypes.h>
-// Currently we support only Sparc and i386/x86_64 architectures,
-// so unless we have explicitely found sparc we assume i386.
+ #elif !defined( __WATCOM_INT64__ ) // Watcom C 11
+
+ #define MBG_TGT_MISSING_64_BIT_TYPES 1
+
+ #endif
+
+ #define MBG_TGT_HAS_WCHAR_T defined( MBG_TGT_WIN32 )
+
+ #define __mbg_inline _inline
-#if !defined( _MBG_ARCH_DEFINED )
- #define MBG_ARCH_I386
#endif
-#if defined( MBG_TGT_FREEBSD ) \
- || defined( MBG_TGT_NETBSD ) \
- || defined( MBG_TGT_OPENBSD )
- #define MBG_TGT_BSD
+#if !defined( MBG_TGT_USE_IOCTL )
+ #define MBG_TGT_USE_IOCTL 0
#endif
-#if defined( MBG_TGT_LINUX ) \
- || defined( MBG_TGT_BSD ) \
- || defined( MBG_TGT_QNX_NTO )
- #define MBG_TGT_UNIX
+
+// If the build environment doesn't provide an inttypes.h file
+// with print format specifiers for 64 bit fixed size types,
+// MBG_PRI_64_PREFIX should be defined, which is used to
+// define our own C99 compatible format specifiers.
+// Maybe similar definitions are required for 32, 16,
+// and 8 bit fixed size types.
+#if defined( MBG_PRI_64_PREFIX )
+ #define PRIi64 MBG_PRI_64_PREFIX "i"
+ #define PRId64 MBG_PRI_64_PREFIX "d"
+ #define PRIo64 MBG_PRI_64_PREFIX "o"
+ #define PRIu64 MBG_PRI_64_PREFIX "u"
+ #define PRIx64 MBG_PRI_64_PREFIX "x"
+ #define PRIX64 MBG_PRI_64_PREFIX "X"
+#endif
+
+#if !defined( __GNUC__ ) && !defined( __attribute__ )
+ #define __attribute__( _x )
#endif
+#if !defined( _DEPRECATED_BY )
+ #define _DEPRECATED_BY( _s ) // empty definition
+#endif
#if defined( MBG_TGT_WIN32 )
#if defined( _AMD64_ )
- // This is used for AMD64 architecture and for
+ // 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"
@@ -278,11 +922,29 @@
#endif
#if defined( _KDD_ )
+ #define MBG_TGT_KERNEL
+
#include <ntddk.h>
+
+ #if defined( DBG ) && DBG
+ #define DEBUG 1
+ #endif
+
+ #define _MBG_API
#else
// This must not be used for kernel drivers.
+
+ // Prevent inclusion of obsolete winsock.h in windows.h
+ #if !defined( WIN32_LEAN_AND_MEAN )
+ #define WIN32_LEAN_AND_MEAN 1
+ #endif
+
+ #include <winsock2.h>
#include <windows.h>
+ #include <ws2tcpip.h>
+
typedef HANDLE MBG_HANDLE;
+ #define MBG_DEV_HANDLE_FMT "%p"
#define MBG_INVALID_HANDLE INVALID_HANDLE_VALUE
@@ -290,32 +952,61 @@
// CVI uses an own set of functions to support serial ports
typedef int MBG_PORT_HANDLE;
#define MBG_INVALID_PORT_HANDLE -1
+
+ // At least CVI 13.02 doesn't provide a declaration of struct timespec.
+ #define MBG_TGT_MISSING_STRUCT_TIMESPEC 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
+ // with VC6. However, if the SDK is installed, 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
+ // socklen_t support
+ #if ( _MSC_VER < 1500 )
+ // At least VS2008 has a socklen_t type
+ typedef int socklen_t;
+ #endif
+
+ #define _MBG_API WINAPI
+
#endif
- #define _MBG_API WINAPI
+ #if !defined( MBG_TGT_MINGW ) // Not required for MinGW
+ // The definitions below have to be used if a variable
+ // is exported from one DLL, and imported by a different
+ // DLL. It has to be used in the header file with the _ext
+ // symbol, depending on whether the file is included by
+ // its "parent" .c or .cpp file which implements the
+ // variable, or by a different file which just references
+ // the exported variable.
+ #define _MBG_API_ATTR_EXPORT __declspec( dllexport )
+ #define _MBG_API_ATTR_IMPORT __declspec( dllimport )
+ #endif
+ // The old code below works well when exporting functions
+ // from a DLL, but fails if a variable is exported from
+ // one DLL, and imported by a different DLL.
#if defined( MBG_LIB_EXPORT )
- #define _MBG_API_ATTR __declspec( dllexport )
+ #define _MBG_API_ATTR _MBG_API_ATTR_EXPORT
#else
- #define _MBG_API_ATTR __declspec( dllimport )
+ #define _MBG_API_ATTR _MBG_API_ATTR_IMPORT
#endif
-#elif defined( MBG_TGT_UNIX )
+#elif defined( MBG_TGT_POSIX )
+
+ #if !defined( MBG_TGT_KERNEL )
+ #include <unistd.h>
+ #endif
typedef int MBG_HANDLE;
typedef int MBG_PORT_HANDLE;
+ #define MBG_DEV_HANDLE_FMT "%i"
#define MBG_INVALID_HANDLE -1
@@ -323,12 +1014,66 @@
typedef int MBG_HANDLE;
typedef int MBG_PORT_HANDLE;
+ #define MBG_DEV_HANDLE_FMT "%i"
#define MBG_INVALID_HANDLE -1
#endif
+/**
+ * @brief A portable socket descriptor type returned by socket().
+ *
+ * @see ::MBG_INVALID_SOCK_FD for the value returned in case of error.
+ */
+#if defined( MBG_TGT_WIN32 ) // && !defined( MBG_TGT_MINGW )
+ #if !defined( MBG_TGT_KERNEL ) // we don't need this in kernel space
+ /// On Windows usually evaluates to @a UINT_PTR, which in turn
+ /// evaluates to <em>(unsigned int)</em>, or <em>(unsigned __int64)</em>.
+ typedef SOCKET MBG_SOCK_FD;
+ #endif
+#elif defined( MBG_TGT_POSIX )
+ typedef int MBG_SOCK_FD; //### TODO
+ //### TODO typedef int SOCKET;
+#endif
+
+
+
+/**
+ * @brief The value returned by the socket() function in case of error.
+ *
+ * On Windows usually evaluates to (SOCKET)(~0),
+ * since the SOCKET type is unsigned.
+ * For POSIX systems the value is usually -1.
+ *
+ * If the @a socket() call returns this value,
+ * call ::mbg_get_last_socket_error to retrieve
+ * one of the portable @ref MBG_ERROR_CODES.
+ *
+ * @see ::MBG_SOCK_FD for a portable socket descriptor type.
+ */
+#if defined( MBG_TGT_WIN32 )
+ #define MBG_INVALID_SOCK_FD INVALID_SOCKET // usually evaluates to (SOCKET)(~0) since SOCKET is unsigned
+#elif defined( MBG_TGT_POSIX )
+ #define MBG_INVALID_SOCK_FD -1
+#endif
+
+
+
+/**
+ * @brief The return code of networking functions in case of error.
+ *
+ * The code is returned by functions like @a select(),
+ * @a recv(), etc. in case of error.
+ */
+#if defined( MBG_TGT_WIN32 )
+ #define MBG_SOCKET_ERR_RETVAL SOCKET_ERROR // usually evaluates to -1
+#elif defined( MBG_TGT_POSIX )
+ #define MBG_SOCKET_ERR_RETVAL -1
+#endif
+
+
+
#if !defined( _MBG_API )
#define _MBG_API
#endif
@@ -337,28 +1082,61 @@
#define _MBG_API_ATTR
#endif
+#if !defined( _MBG_API_ATTR_EXPORT )
+ #define _MBG_API_ATTR_EXPORT
+#endif
+
+#if !defined( _MBG_API_ATTR_IMPORT )
+ #define _MBG_API_ATTR_IMPORT
+#endif
+
+#if !defined( _NO_MBG_API )
+ #define _NO_MBG_API
+#endif
+
+#if !defined( _NO_MBG_API_ATTR )
+ #define _NO_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 )
- #if ( 0 || defined( MBG_ARCH_SPARC ) )
- #define MBG_USE_MM_IO_FOR_PCI 1
- #else
- #define MBG_USE_MM_IO_FOR_PCI 0
- #endif
+#if !defined( MBG_TGT_HAS_DEV_FN )
+ #define MBG_TGT_HAS_DEV_FN 0
#endif
-
-#if !defined( _nop_macro_fnc )
- #define _nop_macro_fnc() do {} while (0)
+#if !defined( MBG_TGT_HAS_DEV_FN_BASE )
+ #define MBG_TGT_HAS_DEV_FN_BASE 0
#endif
+#if defined( MBG_TGT_MISSING_STRUCT_TIMESPEC )
+
+ #include <time.h>
+
+ struct timespec
+ {
+ time_t tv_sec;
+ long tv_nsec;
+ };
+
+#endif // defined( MBG_TGT_MISSING_STRUCT_TIMESPEC )
+
// The macros below are defined in order to be able to check if
// certain C language extensions are available on the target system:
-#define MBG_TGT_C94 ( defined( __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199409L ) )
-#define MBG_TGT_C99 ( defined( __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199901L ) )
+#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 )
@@ -371,24 +1149,13 @@
// 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
#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 */
@@ -402,5 +1169,10 @@ extern "C" {
}
#endif
+/* End of header body */
+
+#undef _ext
+
+#endif // !defined( MBG_TGT_NO_TGT )
-#endif /* _MBG_TGT_H */
+#endif // !defined( _MBG_TGT_H )
diff --git a/mbglib/common/mbg_tmo.h b/mbglib/common/mbg_tmo.h
index daf4a25..c2c670e 100644
--- a/mbglib/common/mbg_tmo.h
+++ b/mbglib/common/mbg_tmo.h
@@ -1,7 +1,7 @@
/**************************************************************************
*
- * $Id: mbg_tmo.h 1.2 2009/09/01 10:38:21 martin REL_M $
+ * $Id: mbg_tmo.h 1.9 2018/09/21 09:01:53 martin REL_M $
*
* Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
*
@@ -10,7 +10,28 @@
*
* -----------------------------------------------------------------------
* $Log: mbg_tmo.h $
- * Revision 1.2 2009/09/01 10:38:21 martin
+ * Revision 1.9 2018/09/21 09:01:53 martin
+ * New function mbg_tmo_add_ms().
+ * Renamed mbgserio_msec_to_timeval to mbg_msec_to_timeval.
+ * Use clock_gettime( CLOCK_MONOTONIC, ... ) for timeouts.
+ * Include mbgtime.h.
+ * Windows headers are now included elsewhere.
+ * Use NSEC_PER_SEC symbol instead of numeric value.
+ * Check symbol MBG_TGT_POSIX rather than MBG_TGT_POSIX.
+ * Fixed some compiler warnings.
+ * Revision 1.8 2013/12/11 12:08:29 martin
+ * Fixed Windows build.
+ * Revision 1.7 2012/11/02 09:04:36Z martin
+ * Fix to have struct timeval defined under Windows.
+ * Revision 1.6 2012/03/16 11:56:23 martin
+ * Added mbg_tmo_delta_t().
+ * Revision 1.5 2011/11/28 15:26:47 martin
+ * Enabled mbgserio_msec_to_timeval() for Windows.
+ * Revision 1.4 2011/01/26 16:55:33Z martin
+ * Fixed compiler warnings with gcc/Linux.
+ * Revision 1.3 2010/06/02 12:29:44 daniel
+ * Excluded mbgserio_msec_to_timeval() from build under WIN32 targets.
+ * Revision 1.2 2009/09/01 10:38:21Z martin
* Cleanup for CVI and other targets which don't support inline code.
* Revision 1.1 2009/08/24 13:08:56 martin
* Initial revision.
@@ -25,6 +46,13 @@
#include <mbg_tgt.h>
#include <words.h>
+#include <mbgtime.h>
+
+#include <stdlib.h>
+
+#if !defined( MBG_TGT_WIN32 ) && !defined( MBG_TGT_DOS )
+ #include <sys/time.h>
+#endif
#ifdef _MBG_TMO
#define _ext
@@ -36,11 +64,15 @@
/* Start of header body */
-#if defined( MBG_TGT_UNIX )
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined( MBG_TGT_POSIX )
- #include <sys/time.h>
+ #include <time.h>
- typedef struct timeval MBG_TMO_TIME;
+ typedef struct timespec MBG_TMO_TIME;
#elif defined( MBG_TGT_WIN32 )
@@ -61,14 +93,24 @@
+typedef struct
+{
+ MBG_TMO_TIME t_start;
+ MBG_TMO_TIME t_tmo;
+ MBG_TMO_TIME t_now;
+
+} MBG_MSG_TIMES;
+
+
+
#if defined( __mbg_inline )
static __mbg_inline
void mbg_tmo_get_time( MBG_TMO_TIME *t )
{
- #if defined( MBG_TGT_UNIX )
+ #if defined( MBG_TGT_POSIX )
- gettimeofday( t, NULL );
+ clock_gettime( CLOCK_MONOTONIC, t );
#elif defined( MBG_TGT_WIN32 )
@@ -95,14 +137,15 @@ void mbg_tmo_get_time( MBG_TMO_TIME *t )
#endif
+
#if defined( __mbg_inline )
static __mbg_inline
int mbg_tmo_time_is_set( const MBG_TMO_TIME *t )
{
- #if defined( MBG_TGT_UNIX )
+ #if defined( MBG_TGT_POSIX )
- return ( t->tv_sec != 0 ) || ( t->tv_usec != 0 );
+ return ( t->tv_sec != 0 ) || ( t->tv_nsec != 0 );
#elif defined( MBG_TGT_WIN32 )
@@ -132,20 +175,27 @@ int mbg_tmo_time_is_set( const MBG_TMO_TIME *t )
#if defined( __mbg_inline )
static __mbg_inline
-void mbg_tmo_set_timeout_ms( MBG_TMO_TIME *t_tmo, ulong msec )
+void mbg_tmo_add_ms( MBG_TMO_TIME *t_tmo, long msec )
{
- mbg_tmo_get_time( t_tmo );
+ #if defined( MBG_TGT_POSIX )
- #if defined( MBG_TGT_UNIX )
+ ldiv_t ldt = ldiv( msec, 1000 );
- t_tmo->tv_usec += msec * 1000;
+ t_tmo->tv_sec += ldt.quot;
+ t_tmo->tv_nsec += ldt.rem * 1000000L;
- while ( t_tmo->tv_usec > 1000000UL )
+ while ( t_tmo->tv_nsec > NSEC_PER_SEC )
{
- t_tmo->tv_usec -= 1000000UL;
+ t_tmo->tv_nsec -= NSEC_PER_SEC;
t_tmo->tv_sec++;
}
+ while ( t_tmo->tv_nsec < 0L )
+ {
+ t_tmo->tv_nsec += NSEC_PER_SEC;
+ t_tmo->tv_sec--;
+ }
+
#elif defined( MBG_TGT_WIN32 )
t_tmo->u64 += ( (uint64_t) msec ) * 10000;
@@ -156,31 +206,60 @@ void mbg_tmo_set_timeout_ms( MBG_TMO_TIME *t_tmo, ulong msec )
#endif
-} // mbg_tmo_set_timeout
+} // mbg_tmo_add_ms
#elif defined( MBG_TGT_CVI )
- #define mbg_tmo_set_timeout_ms( _t, _msec ) \
- mbg_tmo_get_time( (_t) ); \
+ #error FIXME
+
+ #define mbg_tmo_add_ms( _t, _msec ) \
+ mbg_tmo_get_time( (_t) ); \
(_t)->u64 += ( (uint64_t) (_msec) ) * 10000
#else // DOS, ...
- #define mbg_tmo_set_timeout_ms( _t, _msec ) \
- mbg_tmo_get_time( (_t) ); \
+ #error FIXME
+
+ #define mbg_tmo_add_ms( _t, _msec ) \
+ mbg_tmo_get_time( (_t) ); \
*(_t) += (clock_t) ( ( (double) (_msec) * CLOCKS_PER_SEC ) / 1000 );
+
#endif
+
+#if defined( __mbg_inline )
+
+static __mbg_inline
+void mbg_tmo_set_timeout_ms( MBG_TMO_TIME *t_tmo, ulong msec )
+{
+ mbg_tmo_get_time( t_tmo );
+ mbg_tmo_add_ms( t_tmo, msec );
+
+} // mbg_tmo_set_timeout
+
+#else
+
+ #define mbg_tmo_set_timeout_ms( _t, _msec ) \
+ do \
+ { \
+ mbg_tmo_get_time( (_t) ); \
+ mbg_tmo_add_ms( (_t), (_msec) ); \
+ } while 0
+
+#endif
+
+
+
#if defined( __mbg_inline )
static __mbg_inline
long mbg_tmo_time_diff_ms( const MBG_TMO_TIME *t, const MBG_TMO_TIME *t0 )
{
- #if defined( MBG_TGT_UNIX )
+ #if defined( MBG_TGT_POSIX )
return ( t->tv_sec - t0->tv_sec ) * 1000
- + ( t->tv_usec - t0->tv_usec ) / 1000;
+ + ( t->tv_nsec - t0->tv_nsec ) / 1000000L;
#elif defined( MBG_TGT_WIN32 )
@@ -207,15 +286,52 @@ long mbg_tmo_time_diff_ms( const MBG_TMO_TIME *t, const MBG_TMO_TIME *t0 )
#endif
+
+#if defined( __mbg_inline )
+
+static __mbg_inline
+double mbg_tmo_delta_t( const MBG_TMO_TIME *t, const MBG_TMO_TIME *t0 )
+{
+ #if defined( MBG_TGT_POSIX )
+
+ return (double) ( t->tv_sec - t0->tv_sec )
+ + (double) ( t->tv_nsec - t0->tv_nsec ) / 1e9;
+
+ #elif defined( MBG_TGT_WIN32 )
+
+ return ( (double) (int64_t) ( t->u64 - t0->u64 ) ) / 1e7;
+
+ #else // DOS, ...
+
+ return (double) ( *t - *t0 ) / (double) CLOCKS_PER_SEC;
+
+ #endif
+
+} // mbg_tmo_delta_t
+
+#elif defined( MBG_TGT_CVI )
+
+ #define mbg_tmo_delta_t( _t, _t0 ) \
+ ( (double) ( (_t)->u64 - (_t0)->u64 ) / (double) CLOCKS_PER_SEC )
+
+#else // DOS, ...
+
+ #define mbg_tmo_delta_t( _t, _t0 ) \
+ ( (double) ( *(_t) - *(_t0) ) / (double) CLOCKS_PER_SEC )
+
+#endif
+
+
+
#if defined( __mbg_inline )
static __mbg_inline
int mbg_tmo_time_is_after( const MBG_TMO_TIME *t_now, const MBG_TMO_TIME *tmo )
{
- #if defined( MBG_TGT_UNIX )
+ #if defined( MBG_TGT_POSIX )
return ( ( t_now->tv_sec > tmo->tv_sec ) ||
- ( ( t_now->tv_sec == tmo->tv_sec ) && ( t_now->tv_usec > tmo->tv_usec ) ) );
+ ( ( t_now->tv_sec == tmo->tv_sec ) && ( t_now->tv_nsec > tmo->tv_nsec ) ) );
#elif defined( MBG_TGT_WIN32 )
@@ -270,26 +386,21 @@ int mbg_tmo_curr_time_is_after( const MBG_TMO_TIME *tmo )
#if defined( MBG_TGT_CVI )
// needs to be implemented as non-inline function in mbg_tmo.c
- void mbgserio_msec_to_timeval( ulong msec, struct timeval *tv );
+ void mbg_msec_to_timeval( ulong msec, struct timeval *tv );
-#elif defined( MBG_TGT_UNIX ) || defined( MBG_TGT_WIN32 )
+#elif defined( MBG_TGT_POSIX ) || defined( MBG_TGT_WIN32 )
static __mbg_inline
-void mbgserio_msec_to_timeval( ulong msec, struct timeval *tv )
+void mbg_msec_to_timeval( ulong msec, struct timeval *tv )
{
+
tv->tv_sec = msec / 1000;
tv->tv_usec = ( msec % 1000 ) * 1000;
-} // mbgserio_msec_to_timeval
-
-#endif // defined( MBG_TGT_UNIX ) || defined( MBG_TGT_WIN32 )
+} // mbg_msec_to_timeval
+#endif // defined( MBG_TGT_POSIX ) || defined( MBG_TGT_WIN32 )
-/* function prototypes: */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
/* ----- function prototypes begin ----- */
diff --git a/mbglib/common/mbgserio.c b/mbglib/common/mbgserio.c
index 23005b7..c69a775 100644
--- a/mbglib/common/mbgserio.c
+++ b/mbglib/common/mbgserio.c
@@ -1,7 +1,7 @@
/**************************************************************************
*
- * $Id: mbgserio.c 1.3 2009/09/01 10:49:30 martin REL_M $
+ * $Id: mbgserio.c 1.11 2021/12/01 10:19:07 martin.burnicki REL_M $
*
* Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
*
@@ -10,6 +10,50 @@
*
* -----------------------------------------------------------------------
* $Log: mbgserio.c $
+ * Revision 1.11 2021/12/01 10:19:07 martin.burnicki
+ * Make a parameter of mbgserio_get_duration_rcv() const.
+ * Revision 1.10 2021/05/04 20:31:36 martin
+ * New functions mbgserio_get_rx_fifo_threshold,
+ * mbgserio_get_port_basename and mbgserio_free_port_basename,
+ * mbgserio_get_dev_poll_timeout and mbgserio_set_dev_poll_timeout,
+ * mbgserio_get_duration_xmt and mbgserio_get_duration_rcv.
+ * New structure MBGSERIO_SPEED_PARMS which is also
+ * part of the control structure, and useful to calculate
+ * the transmission time.
+ * Renamed some local variables.
+ * Moved device list functions to the bottom of the file.
+ * Updated some comments and removed trailing spaces.
+ * Revision 1.9 2021/04/07 17:20:04 martin
+ * Updated a bunch of comments, and renamed some local variables.
+ * Revision 1.8 2019/09/27 15:33:18 martin
+ * Account for a renamed library function.
+ * Excluded definition of dev_dir from build since it is
+ * anyway only used in some conditional code.
+ * Revision 1.7 2017/07/06 07:21:18 martin
+ * Allocate a device control structure when opening a port,
+ * and free the structure when the port is closed.
+ * Use safe string functions from str_util.c.
+ * Use common Meinberg error codes from mbgerror.h.
+ * Check for MBG_TGT_POSIX instead of MBG_TGT_UNIX.
+ * Account for renamed library symbols.
+ * Added doxygen comments.
+ * Revision 1.6 2013/04/18 13:50:58Z udo
+ * use O_CLOEXEC on open serial port if defined
+ * Revision 1.5 2013/02/01 16:06:33 martin
+ * Always use mbgserio_read/write rather than the macros.
+ * Got rid of _mbg_open/close/read/write() macros.
+ * Check return code of tcgetattr() when opening port on Linux.
+ * Set up DCB on Windows when opening the port,
+ * not when setting parameters.
+ * Fixed setting up COM port list on Windows.
+ * Flush output on close.
+ * Debug code to test flush on Windows (doesn't seem
+ * to work properly).
+ * New code trying different ways to detect existing ports
+ * reliably on Linux.
+ * Syntax workaround which is required until this module becomes a DLL.
+ * Revision 1.4 2011/07/29 10:12:15 martin
+ * Allow baud rates 115200 and 230400 on Linux, if supported by the OS version.
* Revision 1.3 2009/09/01 10:49:30 martin
* Cleanup for CVI.
* Use new portable timeout functions from mbg_tmo.h.
@@ -28,21 +72,32 @@
#define _MBGSERIO
#include <mbgserio.h>
-
- //##++ The following lines are required
- // until mbgserio becomes a DLL:
- #undef _MBG_API_ATTR
- #define _MBG_API_ATTR
-
#undef _MBGSERIO
+#include <mbgerror.h>
+#include <str_util.h>
+
#include <stdio.h>
#include <ctype.h>
#include <time.h>
-#if defined( MBG_TGT_UNIX )
- #include <unistd.h>
+#if defined( MBG_TGT_POSIX )
#include <fcntl.h>
+ #include <dirent.h>
+ #include <errno.h>
+#endif
+
+#if defined( MBG_TGT_WIN32 )
+ #define strdup _strdup
+#endif
+
+
+// This can be defined != 0 to enabled some
+// preliminary, untested code.
+#define USE_LINUX_DEV_DIR 0
+
+#if USE_LINUX_DEV_DIR
+ static const char dev_dir[] = "/dev";
#endif
@@ -53,9 +108,8 @@
* The definitions in this block and all v24...() functions are part of a
* third-party library called V.24 Tools Plus by Langner Expertensysteme.
*
- * This library may no be distributed freely, so the v24..() functions
- * must be replaced by user-written functions or some library available
- * to the user of this demo.
+ * That library may not be freely distributed, so the v24..() functions
+ * must be replaced by user-written functions or some other library.
*-----------------------------------------------------------------------*/
#ifdef __cplusplus
@@ -68,358 +122,653 @@ int v24open( char *portname, int mode );
* port could not be opened.
*/
-#define O_DIRECT 0x0100 /* Schnittstelle fuer direkten Hardware-Zugriff oeffnen */
-#define O_HIGHPRIO 0x2000 /* Schnittstelle mit hoher Prioritaet oeffnen (fastopen) */
+#define O_DIRECT 0x0100 /* open port with direct access to the hardware */
+#define O_HIGHPRIO 0x2000 /* open port with high priority (fastopen) */
+/* This is the open mode we use here. */
#define OPEN_MODE ( O_DIRECT | O_HIGHPRIO )
int v24setparams( int port, long speed, int dbits, int parity, int stopbits );
-/* Set the port's transmission speed, number of data bits, parity and
- * number of stop bits. Returns 0 on success.
- */
+int v24write(int port,void *s,unsigned len);
+int v24read(int port,void *s,unsigned len);
+int v24flush(int port);
+int v24close( int port );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // defined( _USE_V24TOOLS )
+
-int v24qempty( int port, int which );
-/* Returns 1 if the receive buffer is empty, 0 if it is not, or an other
- * value on error.
- */
-int v24getch( int port );
-/* Return a character from the receive buffer.
+static /*HDR*/
+/**
+ * @brief Deallocate a serial device control structure.
+ *
+ * Free the memory allocated for the device control structure
+ * and set the pointer to @a NULL.
+ *
+ * @param[in,out] pp_sdev Address of a pointer to a device control structure.
+ *
+ * @see ::alloc_mbgserio_dev
*/
+void dealloc_mbgserio_dev( MBGSERIO_DEV **pp_sdev )
+{
+ MBGSERIO_DEV *sdev = *pp_sdev;
+
+ if ( sdev )
+ {
+ free( sdev );
+ *pp_sdev = NULL;
+ }
+
+} // dealloc_mbgserio_dev
-int v24putc( int port, char c );
-/* Write a character to the port.
+
+
+static /*HDR*/
+/**
+ * @brief Allocate a serial device control structure.
+ *
+ * @param[in,out] pp_sdev Address of a pointer to a device control structure.
+ *
+ * @return ::MBG_SUCCESS or one of the @ref MBG_ERROR_CODES.
+ *
+ * @see ::dealloc_mbgserio_dev
*/
+int alloc_mbgserio_dev( MBGSERIO_DEV **pp_sdev )
+{
+ int rc;
+ MBGSERIO_DEV *sdev = (MBGSERIO_DEV *) malloc( sizeof( *sdev ) );
-int v24close( int port );
-/* Close the port
+ if ( sdev == NULL )
+ {
+ rc = mbg_get_last_error( "malloc failed in alloc_mbgserio_dev" );
+ goto out;
+ }
+
+ memset( sdev, 0, sizeof( *sdev ) );
+ sdev->port_handle = MBG_INVALID_PORT_HANDLE;
+ rc = MBG_SUCCESS;
+
+out:
+ *pp_sdev = sdev;
+ return rc;
+
+} // alloc_mbgserio_dev
+
+
+
+/*HDR*/
+/**
+ * @brief Return the base name of the device name of a serial port.
+ *
+ * In order to leave the original device name string unchanged,
+ * a buffer is allocated with a duplicate of the original string,
+ * and a pointer to the basename component in that buffer is returned.
+ *
+ * After usage, the allocated buffer whose address is saved in
+ * @p *pp_dup_port_name should be freed by calling ::mbgserio_free_port_basename.
+ *
+ * @param[in] pp_dup_port_name Address of a <em>char *</em> that takes the address
+ * of the allocated string buffer.
+ * @param[in] port_name The original device name string.
+ *
+ * @return A pointer to the basename which is part of an allocated copy of the original string.
+ *
+ * @see ::mbgserio_free_port_basename
*/
+_NO_MBG_API_ATTR char * _MBG_API mbgserio_get_port_basename( char **pp_dup_port_name, const char *port_name )
+{
+ char *cp = NULL;
-#ifdef __cplusplus
-}
-#endif
+ *pp_dup_port_name = strdup( port_name );
-#endif // defined( _USE_V24TOOLS )
+ if ( *pp_dup_port_name )
+ {
+ #if defined( MBG_TGT_POSIX )
+ // We remove e.g. the "/dev/" part
+ // of the device name.
+ cp = basename( *pp_dup_port_name );
+ #else
+ // Nothing to be removed from a
+ // device name like "COM1".
+ cp = *pp_dup_port_name;
+ #endif
+ }
+
+ return cp;
-/*------------------------------------------------------------------------*/
+} // mbgserio_get_port_basename
/*HDR*/
-_MBG_API_ATTR int _MBG_API mbgserio_open( SERIAL_IO_STATUS *pst, const char *dev )
+/**
+ * @brief Free a buffer that has been allocated by ::mbgserio_get_port_basename.
+ *
+ * This function should be called whenever a string buffer allocated
+ * by an earlier ::mbgserio_get_port_basename call isn't needed anymore.
+ *
+ * @param[in] pp_dup_port_name Address of a <em>char *</em> with the address
+ * of the allocated string buffer.
+ *
+ * @see ::mbgserio_get_port_basename
+ */
+_NO_MBG_API_ATTR void _MBG_API mbgserio_free_port_basename( char **pp_dup_port_name )
{
- MBG_PORT_HANDLE port_handle;
+ if ( *pp_dup_port_name )
+ {
+ free( *pp_dup_port_name );
+ *pp_dup_port_name = NULL;
+ }
- #if defined( MBG_TGT_CVI )
+} // mbgserio_free_port_basename
+
+
+
+/*HDR*/
+/**
+ * @brief Determine the threshold of a serial RX FIFO buffer.
+ *
+ * This is useful to be able to exactly compensate the delay
+ * of a received serial data string.
+ *
+ * @note This may not be supported on each target system.
+ *
+ * @param[in] port_name The device name of the serial port.
+ *
+ * @return The number of bytes in the FIFO buffer after which
+ * a receive event (e.g. IRQ) is generated,
+ * or 0 if the real threshold can't be determined.
+ */
+_NO_MBG_API_ATTR int _MBG_API mbgserio_get_rx_fifo_threshold( const char *port_name )
+{
+ int n = 0;
+
+ #if defined( MBG_TGT_LINUX )
{
- int data_bits = 8; //##++
- int parity_code = 0;
- int baud_rate = 19200;
- int stop_bits = 1;
- int i;
- int len;
- int rc;
+ static const char tty_basename[] = "/sys/class/tty";
+ static const char tty_rx_trig_fn[] = "rx_trig_bytes";
- // Under CVI the port handle passed to OpenComConfig and used furtheron
- // corresponds to the COM port number, e.g. 1 for COM1, so we extract
- // the number from the device name passed as parameter.
- port_handle = 0;
- len = strlen( dev );
+ char *dup_name = NULL;
+ const char *cp = mbgserio_get_port_basename( &dup_name, port_name );
+ char fn[256];
+ FILE *fp;
- for ( i = 0; i < len; i++ )
+ snprintf_safe( fn, sizeof( fn ), "%s/%s/%s",
+ tty_basename, cp, tty_rx_trig_fn );
+
+ fp = fopen( fn, "rt" );
+
+ if ( fp )
{
- char c = dev[i];
- if ( c >= '0' && c <= '9' )
- break;
+ char s[80];
+ cp = fgets( s, sizeof( s ), fp );
+
+ if ( cp )
+ n = atoi( cp );
+
+ fclose( fp );
}
- if ( i == len )
- return MBGSERIO_INV_CFG; // no numeric substring found
+ mbgserio_free_port_basename( &dup_name );
+ }
+ #endif
+ return n;
- port_handle = atoi( &dev[i] );
+} // mbgserio_get_rx_fifo_threshold
- rc = OpenComConfig (port_handle, NULL, baud_rate, parity_code, data_bits, stop_bits, 8192, 1024); //##++
- if ( rc < 0 )
- goto fail;
- pst->port_handle = port_handle;
- SetComTime( port_handle, 1.0 ); //##++
- SetXMode( port_handle, 0 );
- }
- #elif defined( MBG_TGT_WIN32 )
- {
- static const char *prefix = "\\\\.\\";
+#if defined( MBG_TGT_WIN32 )
- COMMTIMEOUTS commtimeouts;
- int len = strlen( prefix ) + strlen( dev ) + 1;
- char *tmp_name = (char *) malloc( len );
+static /*HDR*/
+/**
+ * @brief Win32-specific function which opens a serial port.
+ *
+ * @param[in] dev_name Basic device name, e.g. "COM1".
+ * @param[out] ph Pointer to a @a HANDLE which is set up on success.
+ *
+ * @return ::MBG_SUCCESS on success, or one of the @ref MBG_ERROR_CODES.
+ */
+int win32_open_serial_port( const char *dev_name, HANDLE *ph )
+{
+ // A prefix is required for the device name to be able
+ // to open ports with large numbers, e.g. COM15.
+ static const char prefix[] = "\\\\.\\";
+
+ size_t len;
+ char *tmp_name;
+ size_t n = 0;
+ int rc = MBG_ERR_UNSPEC;
- if ( tmp_name == NULL ) // unable to allocate memory
- goto fail;
+ if ( dev_name == NULL )
+ return MBG_ERR_INV_PARM;
+ len = strlen( prefix ) + strlen( dev_name ) + 1;
+ tmp_name = (char *) malloc( len );
- strcpy( tmp_name, prefix );
- strcat( tmp_name, dev );
+ if ( tmp_name == NULL ) // Unable to allocate memory.
+ {
+ rc = MBG_ERR_NO_MEM;
+ goto out;
+ }
+
+ n = sn_cpy_str_safe( tmp_name, len, prefix );
+ n += sn_cpy_str_safe( &tmp_name[n], len - n, dev_name );
- port_handle = CreateFile( tmp_name, GENERIC_READ | GENERIC_WRITE,
+ *ph = CreateFileA( tmp_name, GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
+ FILE_ATTRIBUTE_NORMAL, // TODO Also use FILE_FLAG_WRITE_THROUGH ?
NULL );
- free( tmp_name );
+ if ( *ph == INVALID_HANDLE_VALUE )
+ {
+ rc = mbg_win32_sys_err_to_mbg( GetLastError(), "CreateFile failed in win32_open_serial_port" );
+ goto out_free;
+ }
- if ( port_handle == INVALID_HANDLE_VALUE )
- goto fail;
+ rc = MBG_SUCCESS;
+out_free:
+ free( tmp_name );
- pst->port_handle = port_handle;
+out:
+ return rc;
- // save original settings
- pst->old_dcb.DCBlength = sizeof( pst->old_dcb );
- GetCommState( port_handle, &pst->old_dcb );
- GetCommTimeouts( port_handle, &pst->old_commtimeouts );
+} // win32_open_serial_port
- // configure our settings
- memset( &commtimeouts, 0, sizeof( commtimeouts ) );
- SetCommTimeouts( port_handle, &commtimeouts );
+#endif // defined( MBG_TGT_WIN32 )
- #if defined( MBGSERIO_IN_BUFFER_SIZE ) && defined( MBGSERIO_OUT_BUFFER_SIZE )
- SetupComm( port_handle, MBGSERIO_IN_BUFFER_SIZE, MBGSERIO_OUT_BUFFER_SIZE );
- #endif
- PurgeComm( port_handle, PURGE_TXABORT|PURGE_TXCLEAR );
- PurgeComm( port_handle, PURGE_RXABORT|PURGE_RXCLEAR );
- //##++ mbgextio_set_console_control_handler();
- }
- #elif defined( MBG_TGT_UNIX )
+/*HDR*/
+/**
+ * @brief Close a serial port specified by a ::MBGSERIO_DEV structure.
+ *
+ * After the port has been closed, the buffer that had been allocated
+ * for the ::MBGSERIO_DEV structure is freed, and the pointer to that
+ * buffer is set to @a NULL.
+ *
+ * @param[in,out] pp_sdev Address of a pointer to the control structure including the port handle.
+ *
+ * @return One of the @ref MBG_RETURN_CODES.
+ */
+_NO_MBG_API_ATTR int _MBG_API mbgserio_close( MBGSERIO_DEV **pp_sdev )
+{
+ if ( *pp_sdev) // Only if a MBGSERIO_DEV structure has been allocated.
{
- // Open as not controlling TTY to prevent from being
- // killed if CTRL-C is received.
- // O_NONBLOCK is the same as O_NDELAY.
- port_handle = _mbg_open( dev, O_RDWR | O_NOCTTY | O_NONBLOCK );
+ MBGSERIO_DEV *sdev = *pp_sdev;
+ MBG_PORT_HANDLE *p_handle = &sdev->port_handle;
- //##++ TODO: Under Unix a serial port can by default be opened
- // by several processes. However, we don't want that, so we
- // should care about this using a lock file for the device
- // and/or setting the TIOCEXCL flag (which unfortunately
- // is not an atomic operation with open()).
+ if ( *p_handle != MBG_INVALID_PORT_HANDLE )
+ {
+ mbgserio_flush_tx( sdev );
- if ( port_handle < 0 ) // check errno for the reason
- goto fail;
+ #if defined( MBG_TGT_CVI )
+ CloseCom( *p_handle );
- pst->port_handle = port_handle;
+ #elif defined( MBG_TGT_WIN32 )
- /* save current device settings */
- tcgetattr( port_handle, &pst->oldtio );
+ // Restore original settings that have been saved.
- // atexit( port_deinit );
+ if ( sdev->org_dcb_has_been_read )
+ SetCommState( *p_handle, &sdev->org_dcb );
- fflush( stdout ); //##++
- setvbuf( stdout, NULL, _IONBF, 0 );
- }
- #elif defined( MBG_TGT_DOS )
- #if defined( _USE_V24TOOLS )
- {
- port_handle = v24open( (char *) dev, OPEN_MODE );
+ if ( sdev->org_commtimeouts_have_been_read )
+ SetCommTimeouts( *p_handle, &sdev->org_commtimeouts );
- if ( port_handle < 0 )
- goto fail;
+ CloseHandle( *p_handle );
- pst->port_handle = port_handle;
- v24settimeout( port_handle, 1 );
- }
- #else
+ #elif defined( MBG_TGT_POSIX )
- #error Target DOS requires v24tools for serial I/O.
+ // Restore original settings that have been saved.
- #endif
+ if ( sdev->org_tio_has_been_read )
+ tcsetattr( *p_handle, TCSANOW, &sdev->org_tio );
- #else
+ close( *p_handle );
- #error This target OS is not supported.
+ #elif defined( MBG_TGT_DOS )
+ #if defined( _USE_V24TOOLS )
- #endif
+ v24close( *p_handle );
- return 0;
+ #else
+ #error Target DOS requires v24tools for serial I/O.
-fail:
- pst->port_handle = MBG_INVALID_PORT_HANDLE;
- return MBGSERIO_FAIL;
+ #endif
-} // mbgserio_open
+ #else
+
+ #error This target OS is not supported.
+
+ #endif
+ }
+
+ dealloc_mbgserio_dev( pp_sdev );
+ }
+
+ return MBG_SUCCESS;
+
+} // mbgserio_close
/*HDR*/
-_MBG_API_ATTR int _MBG_API mbgserio_close( SERIAL_IO_STATUS *pst )
+/**
+ * @brief Open a serial port and set up a ::MBGSERIO_DEV structure.
+ *
+ * @param[in,out] pp_sdev Address of a pointer to a ::MBGSERIO_DEV device control structure
+ * allocated and set up by this call. Set to @a NULL on error.
+ * @param[in] dev_name Device name of the port to be opened.
+ *
+ * @return One of the @ref MBG_RETURN_CODES.
+ */
+_NO_MBG_API_ATTR int _MBG_API mbgserio_open( MBGSERIO_DEV **pp_sdev, const char *dev_name )
{
- if ( pst->port_handle != MBG_INVALID_PORT_HANDLE )
- {
- MBG_PORT_HANDLE port_handle = pst->port_handle;
+ MBGSERIO_DEV *sdev;
+ MBG_PORT_HANDLE *p_handle;
- #if defined( MBG_TGT_CVI )
+ int rc = alloc_mbgserio_dev( pp_sdev );
- CloseCom( port_handle );
+ if ( mbg_rc_is_error( rc ) )
+ return rc;
- #elif defined( MBG_TGT_WIN32 )
- SetCommState( port_handle, &pst->old_dcb );
- SetCommTimeouts( port_handle, &pst->old_commtimeouts );
- CloseHandle( port_handle );
+ sdev = *pp_sdev;
+ p_handle = &sdev->port_handle;
+
+ #if defined( MBG_TGT_CVI )
+ {
+ MBGSERIO_SPEED_PARMS sp = { 0 };
+ int parity_code = 0;
+ int i;
+ int len;
+ int rc;
- #elif defined( MBG_TGT_UNIX )
+ sp.data_bits = 8;
+ sp.baud_rate = 19200;
+ sp.stop_bits = 1;
- tcsetattr( port_handle, TCSANOW, &pst->oldtio );
- close( port_handle );
+ // On CVI, the port handle passed to OpenComConfig and used furtheron
+ // corresponds to the COM port number, e.g. 1 for COM1, so we extract
+ // the number from the device name passed as parameter.
+ len = strlen( dev_name );
- #elif defined( MBG_TGT_DOS )
- #if defined( _USE_V24TOOLS )
+ for ( i = 0; i < len; i++ )
+ {
+ char c = dev_name[i];
- v24close( port_handle );
+ if ( c >= '0' && c <= '9' )
+ break;
+ }
- #else
+ if ( i == len )
+ {
+ rc = MBG_ERR_PARM_FMT; // No numeric substring found.
+ goto out;
+ }
- #error Target DOS requires v24tools for serial I/O.
+ *p_handle = atoi( &dev_name[i] );
- #endif
+ rc = OpenComConfig( *p_handle, NULL, sp.baud_rate, parity_code,
+ sp.data_bits, sp.stop_bits, 8192, 1024 ); // TODO
- #else
+ if ( rc < 0 )
+ {
+ rc = mbg_get_last_error( "OpenComConfig failed in mbgserio_open" );
+ *p_handle = MBG_INVALID_PORT_HANDLE;
+ goto out;
+ }
- #error This target OS is not supported.
+ rc = SetComTime( *p_handle, 1.0 ); // FIXME TODO WTF?
- #endif
+ if ( rc < 0 )
+ {
+ rc = mbg_get_last_error( "SetComTime failed in mbgserio_open" );
+ goto out;
+ }
+
+ rc = SetXMode( *p_handle, 0 );
+
+ if ( rc < 0 )
+ {
+ rc = mbg_get_last_error( "SetXMode failed in mbgserio_open" );
+ goto out;
+ }
- pst->port_handle = MBG_INVALID_PORT_HANDLE;
+ sdev->sp = sp;
}
+ #elif defined( MBG_TGT_WIN32 )
+ {
+ COMMTIMEOUTS commtimeouts;
+ DCB dcb;
- return 0;
+ rc = win32_open_serial_port( dev_name, p_handle );
-} // mbgserio_close
+ // rc is now one of the @ref MBG_RETURN_CODES, and in case of an error
+ // the handle has already been set to ::MBG_INVALID_PORT_HANDLE.
+ if ( mbg_rc_is_error( rc ) )
+ goto out;
+ // Save the settings found at startup.
+ sdev->org_dcb.DCBlength = sizeof( sdev->org_dcb );
+ if ( !GetCommState( *p_handle, &sdev->org_dcb ) )
+ {
+ rc = mbg_get_last_error( "GetCommState failed in mbgserio_open" );
+ goto out;
+ }
-/*HDR*/
-_MBG_API_ATTR int _MBG_API mbgserio_setup_port_str_list( MBG_STR_LIST **list, int max_devs )
-{
- MBG_STR_LIST *list_head;
- int n = 0;
- int i = 0;
+ sdev->org_dcb_has_been_read = 1;
- (*list) = (MBG_STR_LIST *) malloc( sizeof( **list ) );
- memset( (*list), 0, sizeof( **list ) );
+ if ( !GetCommTimeouts( *p_handle, &sdev->org_commtimeouts ) )
+ {
+ rc = mbg_get_last_error( "GetCommTimeouts failed in mbgserio_open" );
+ goto out;
+ }
- list_head = (*list);
+ sdev->org_commtimeouts_have_been_read = 1;
- for ( i = 0; i < max_devs; i++ )
- {
- SERIAL_IO_STATUS iost;
- char dev_name[100] = { 0 };
- int rc;
+ if ( !GetCommProperties( *p_handle, &sdev->comm_prop ) )
+ {
+ rc = mbg_get_last_error( "GetCommProperties failed in mbgserio_open" );
+ goto out;
+ }
- #if defined( MBG_TGT_WIN32 )
- sprintf( dev_name, "COM%i", i + 1 );
- #elif defined( MBG_TGT_LINUX )
- sprintf( dev_name, "/dev/ttyS%i", i );
+ sdev->comm_prop_have_been_read = 1;
+
+ #if 0 // fields provided by the Windows DCB structure
+ DWORD DCBlength; /* sizeof(DCB) */
+ DWORD BaudRate; /* Baudrate at which running */
+ DWORD fBinary: 1; /* Binary Mode (skip EOF check) */
+ DWORD fParity: 1; /* Enable parity checking */
+ DWORD fOutxCtsFlow:1; /* CTS handshaking on output */
+ DWORD fOutxDsrFlow:1; /* DSR handshaking on output */
+ DWORD fDtrControl:2; /* DTR Flow control */
+ DWORD fDsrSensitivity:1; /* DSR Sensitivity */
+ DWORD fTXContinueOnXoff: 1; /* Continue TX when Xoff sent */
+ DWORD fOutX: 1; /* Enable output X-ON/X-OFF */
+ DWORD fInX: 1; /* Enable input X-ON/X-OFF */
+ DWORD fErrorChar: 1; /* Enable Err Replacement */
+ DWORD fNull: 1; /* Enable Null stripping */
+ DWORD fRtsControl:2; /* Rts Flow control */
+ DWORD fAbortOnError:1; /* Abort all reads and writes on Error */
+ DWORD fDummy2:17; /* Reserved */
+ WORD wReserved; /* Not currently used */
+ WORD XonLim; /* Transmit X-ON threshold */
+ WORD XoffLim; /* Transmit X-OFF threshold */
+ BYTE ByteSize; /* Number of bits/byte, 4-8 */
+ BYTE Parity; /* 0-4=None,Odd,Even,Mark,Space */
+ BYTE StopBits; /* 0,1,2 = 1, 1.5, 2 */
+ char XonChar; /* Tx and Rx X-ON character */
+ char XoffChar; /* Tx and Rx X-OFF character */
+ char ErrorChar; /* Error replacement char */
+ char EofChar; /* End of Input character */
+ char EvtChar; /* Received Event character */
+ WORD wReserved1; /* Fill for now. */
#endif
- rc = mbgserio_open( &iost, dev_name );
+ // Configure our settings.
+ dcb = sdev->org_dcb; // Current settings as default.
+ dcb.fOutxCtsFlow = FALSE; // CTS output flow control.
+ dcb.fOutxDsrFlow = FALSE; // DSR output flow control.
+ dcb.fDtrControl = DTR_CONTROL_ENABLE; // Enable DTR.
+ dcb.fDsrSensitivity = FALSE; // Don't require DSR input active.
+ // TODO more missing here.
+ dcb.fRtsControl = RTS_CONTROL_ENABLE; // Enable RTS as required for for C28COM.
+ dcb.fOutX = FALSE;
- if ( rc < 0 )
- continue;
+ if ( !SetCommState( *p_handle, &dcb ) )
+ {
+ rc = mbg_get_last_error( "SetCommState failed in mbgserio_open" );
+ goto out;
+ }
- mbgserio_close( &iost );
+ memset( &commtimeouts, 0, sizeof( commtimeouts ) );
- (*list)->s = (char *) malloc( strlen( dev_name ) + 1 );
- strcpy( (*list)->s, dev_name );
+ if ( !SetCommTimeouts( *p_handle, &commtimeouts ) )
+ {
+ rc = mbg_get_last_error( "SetCommTimeout failed in mbgserio_open" );
+ goto out;
+ }
- (*list)->next = (MBG_STR_LIST *) malloc( sizeof( **list ) );
- (*list) = (*list)->next;
+ #if !defined( MBGSERIO_IN_BUFFER_SIZE )
+ #define MBGSERIO_IN_BUFFER_SIZE 2048
+ #endif
- memset( (*list), 0, sizeof( **list ) );
- n++;
+ #if !defined( MBGSERIO_OUT_BUFFER_SIZE )
+ #define MBGSERIO_OUT_BUFFER_SIZE 2048
+ #endif
-// if ( ++i >= MBG_MAX_DEVICES )
-// break;
- }
+ if ( !SetupComm( *p_handle, MBGSERIO_IN_BUFFER_SIZE, MBGSERIO_OUT_BUFFER_SIZE ) )
+ {
+ rc = mbg_get_last_error( "SetupComm failed in mbgserio_open" );
+ goto out;
+ }
- if ( n == 0 )
- {
- free( *list );
- list_head = NULL;
+ PurgeComm( *p_handle, PURGE_TXABORT | PURGE_TXCLEAR );
+ PurgeComm( *p_handle, PURGE_RXABORT | PURGE_RXCLEAR );
+
+ // TODO Call mbgextio_set_console_control_handler() ?
}
+ #elif defined( MBG_TGT_POSIX )
+ {
+ // Open as not controlling TTY to prevent from being
+ // killed if CTRL-C is received.
+ // O_NONBLOCK is the same as O_NDELAY.
+ int flags = O_RDWR | O_NOCTTY | O_NONBLOCK;
- *list = list_head;
+ #if defined( O_CLOEXEC )
+ flags |= O_CLOEXEC;
+ #endif
- return n;
+ *p_handle = open( dev_name, flags ); // Returns -1 on error.
-} // mbgserio_setup_port_str_list
+ if ( *p_handle < 0 )
+ {
+ rc = mbg_get_last_error( "open failed in mbgserio_open" );
+ *p_handle = MBG_INVALID_PORT_HANDLE;
+ goto out;
+ }
+ // TODO On Unix, a serial port can by default be opened
+ // by several processes. However, we don't want that, so we
+ // should care about this using a lock file for the device
+ // and/or setting the TIOCEXCL flag (which unfortunately
+ // is not an atomic operation with open()).
+ // Save current device settings.
+ if ( tcgetattr( *p_handle, &sdev->org_tio ) < 0 )
+ {
+ rc = mbg_get_last_error( "tcgetattr failed in mbgserio_open" );
+ goto out;
+ }
-/*HDR*/
-_MBG_API_ATTR void _MBG_API _MBG_API mbgserio_free_str_list( MBG_STR_LIST *list )
-{
- int i = 0;
+ sdev->org_tio_has_been_read = 1;
- while ( i < 1000 ) //##++
- {
- if ( list )
+ // TODO Set an atexit() function to close the port?
+ }
+ #elif defined( MBG_TGT_DOS )
+ #if defined( _USE_V24TOOLS )
{
- if ( list->s )
- {
- free( list->s );
- list->s = NULL;
- }
+ *p_handle = v24open( (char *) dev_name, OPEN_MODE );
- if ( list->next )
- {
- MBG_STR_LIST *next = list->next;
- free( list );
- list = next;
- }
- else
+ if ( *p_handle < 0 )
{
- if ( list )
- {
- free( list );
- list = NULL;
- }
- break;
+ rc = MBG_ERR_UNSPEC; // TODO Translate rc ?
+ *p_handle = MBG_INVALID_PORT_HANDLE;
+ goto out;
}
+
+ v24settimeout( *p_handle, 1 );
}
- else
- break;
+ #else
- i++;
- }
+ #error Target DOS requires v24tools for serial I/O.
+ rc = MBG_ERR_NOT_SUPP_ON_OS;
+ goto out;
-} // mbgserio_free_str_list
+ #endif
+
+ #else
+
+ #error This target OS is not supported.
+ rc = MBG_ERR_NOT_SUPP_ON_OS;
+ goto out;
+
+ #endif
+
+ // Try to get the receive FIFO threshold.
+ // Will be 0 if this isn't supported.
+ sdev->rcv_fifo_threshold = mbgserio_get_rx_fifo_threshold( dev_name );
+
+ rc = MBG_SUCCESS;
+
+out:
+ if ( mbg_rc_is_error( rc ) )
+ mbgserio_close( pp_sdev );
+
+ return rc;
+
+} // mbgserio_open
/*HDR*/
-_MBG_API_ATTR int _MBG_API mbgserio_set_parms( SERIAL_IO_STATUS *pst,
- uint32_t baud_rate, const char *framing )
+/**
+ * @brief Set the transmission parameters of a serial port.
+ *
+ * @param[in,out] sdev Control structure of the device.
+ * @param[in] baud_rate One of the well-known baud rates, e.g. 19200.
+ * @param[in] framing A short string providing the framing, e.g. "8N1".
+ *
+ * @return One of the @ref MBG_RETURN_CODES.
+ */
+_NO_MBG_API_ATTR int _MBG_API mbgserio_set_parms( MBGSERIO_DEV *sdev,
+ uint32_t baud_rate, const char *framing )
{
- MBG_PORT_HANDLE port_handle = pst->port_handle;
+ MBG_PORT_HANDLE port_handle = sdev->port_handle;
+ MBGSERIO_SPEED_PARMS sp = { 0 };
const char *cp;
+ int rc = MBG_ERR_UNSPEC;
+
+ sp.baud_rate = baud_rate;
#if defined( MBG_TGT_CVI )
{
- int data_bits = 8;
- int parity_code = 0;
- int stop_bits = 1;
- int rc;
+ int parity_code = 0;
- // setup framing.
+ // Setup framing.
for ( cp = framing; *cp; cp++ )
{
char c = toupper( *cp );
@@ -428,49 +777,66 @@ _MBG_API_ATTR int _MBG_API mbgserio_set_parms( SERIAL_IO_STATUS *pst,
{
case '7':
case '8':
- data_bits = c - '0';
+ sp.data_bits = c - '0';
break;
case 'N':
parity_code = 0;
+ sp.parity_bits = 0;
break;
case 'E':
parity_code = 2;
+ sp.parity_bits = 1;
break;
case 'O':
parity_code = 1;
+ sp.parity_bits = 1;
break;
case '1':
case '2':
- stop_bits = c - '0';
+ sp.stop_bits = c - '0';
break;
default:
- return MBGSERIO_INV_CFG; // invalid framing string
+ return MBG_ERR_PARM_FMT; // Invalid framing string.
}
}
- rc = OpenComConfig( port_handle, NULL, baud_rate, parity_code,
- data_bits, stop_bits, 8192, 1024 );
+ rc = OpenComConfig( port_handle, NULL, sp.baud_rate, parity_code,
+ sp.data_bits, sp.stop_bits, 8192, 1024 );
if ( rc < 0 )
- return rc;
+ return mbg_cvi_rs232_error_to_mbg( rc, "OpenComConfig failed in mbgserio_set_parms" );
- SetComTime( port_handle, 1.0 ); //##++
- SetXMode( port_handle, 0 );
+ rc = SetComTime( port_handle, 1.0 );
+
+ if ( rc < 0 )
+ return mbg_cvi_rs232_error_to_mbg( rc, "SetComTime failed in mbgserio_set_parms" );
+
+ rc = SetXMode( port_handle, 0 );
+
+ if ( rc < 0 )
+ return mbg_cvi_rs232_error_to_mbg( rc, "SetXMode failed in mbgserio_set_parms" );
+
+ // On success, fall through.
}
#elif defined( MBG_TGT_WIN32 )
{
DCB dcb;
- dcb.DCBlength = sizeof( DCB ) ;
- GetCommState( port_handle, &dcb ) ;
- dcb.BaudRate = baud_rate;
+ // Get current settings.
+ dcb.DCBlength = sizeof( DCB );
+ if ( GetCommState( port_handle, &dcb ) == FALSE )
+ return mbg_get_last_error( "GetCommState failed in mbgserio_set_parms" );
- // setup framing.
+ // Change settings as requested.
+
+ dcb.BaudRate = baud_rate;
+
+ // Setup framing.
for ( cp = framing; *cp; cp++ )
{
char c = toupper( *cp );
@@ -480,53 +846,56 @@ _MBG_API_ATTR int _MBG_API mbgserio_set_parms( SERIAL_IO_STATUS *pst,
case '7':
case '8':
dcb.ByteSize = c - '0';
+ sp.data_bits = dcb.ByteSize;
break;
case 'N':
dcb.Parity = NOPARITY;
+ sp.parity_bits = 0;
break;
case 'E':
dcb.Parity = EVENPARITY;
+ sp.parity_bits = 1;
break;
case 'O':
dcb.Parity = ODDPARITY;
+ sp.parity_bits = 1;
break;
case '1':
dcb.StopBits = ONESTOPBIT;
+ sp.stop_bits = 1;
break;
case '2':
dcb.StopBits = TWOSTOPBITS;
+ sp.stop_bits = 2;
break;
default:
- return MBGSERIO_INV_CFG; // invalid framing string
+ return MBG_ERR_PARM_FMT; // Invalid framing string.
}
}
+ if ( SetCommState( port_handle, &dcb ) == FALSE )
+ return mbg_get_last_error( "SetCommState failed in mbgserio_set_parms" );
- dcb.fOutxCtsFlow = FALSE; // CTS output flow control
- dcb.fOutxDsrFlow = FALSE; // DSR output flow control
- dcb.fDtrControl = DTR_CONTROL_ENABLE; // enable DTR for C28COM
- dcb.fDsrSensitivity = FALSE; // don't require DSR input active
- //##++ more missing here
- dcb.fRtsControl = RTS_CONTROL_ENABLE; // enable RTS for C28COM
- dcb.fOutX = FALSE;
-
- SetCommState ( port_handle, &dcb );
+ // On success, fall through.
}
- #elif defined( MBG_TGT_UNIX )
+ #elif defined( MBG_TGT_POSIX )
{
tcflag_t c_cflag = 0;
struct termios tio;
- tcgetattr( port_handle, &tio );
+ rc = tcgetattr( port_handle, &tio );
- // setup transmission speed
- switch( baud_rate )
+ if ( rc < 0 )
+ return mbg_get_last_error( "tcgetattr failed in mbgserio_set_parms" );
+
+ // Setup transmission speed.
+ switch ( baud_rate )
{
case 300: c_cflag = B300; break;
case 600: c_cflag = B600; break;
@@ -537,31 +906,100 @@ _MBG_API_ATTR int _MBG_API mbgserio_set_parms( SERIAL_IO_STATUS *pst,
case 19200: c_cflag = B19200; break;
case 38400: c_cflag = B38400; break;
case 57600: c_cflag = B57600; break;
+ #if defined( B115200 )
+ case 115200: c_cflag = B115200; break;
+ #endif
+ #if defined( B230400 )
+ case 230400: c_cflag = B230400; break;
+ #endif
+ #if defined( B460800 )
+ case 460800: c_cflag = B460800; break;
+ #endif
+ #if defined( B500000 )
+ case 500000: c_cflag = B500000; break;
+ #endif
+ #if defined( B576000 )
+ case 576000: c_cflag = B576000; break;
+ #endif
+ #if defined( B921600 )
+ case 921600: c_cflag = B921600; break;
+ #endif
+ #if defined( B1000000 )
+ case 1000000: c_cflag = B1000000; break;
+ #endif
+ #if defined( B1152000 )
+ case 1152000: c_cflag = B1152000; break;
+ #endif
+ #if defined( B1500000 )
+ case 1500000: c_cflag = B1500000; break;
+ #endif
+ #if defined( B2000000 )
+ case 2000000: c_cflag = B2000000; break;
+ #endif
+ #if defined( B2500000 )
+ case 2500000: c_cflag = B2500000; break;
+ #endif
+ #if defined( B3000000 )
+ case 3000000: c_cflag = B3000000; break;
+ #endif
+ #if defined( B3500000 )
+ case 3500000: c_cflag = B3500000; break;
+ #endif
+ #if defined( B4000000 )
+ case 4000000: c_cflag = B4000000; break;
+ #endif
- default: return MBGSERIO_INV_CFG; // invalid
+ default:
+ return MBG_ERR_INV_PARM; // Invalid baud rate.
}
- #if 0 //##++ This should be used preferably for portability reasons
+ #if 0 // TODO This should preferably be used for portability reasons.
int cfsetispeed( struct termios *termios_p, speed_t speed );
int cfsetospeed( struct termios *termios_p, speed_t speed );
#endif
- // setup framing.
+ // Setup framing.
for ( cp = framing; *cp; cp++ )
{
- switch ( _toupper( *cp ) )
+ char c = toupper( *cp );
+
+ switch ( c )
{
- case '7': c_cflag |= CS7; break;
- case '8': c_cflag |= CS8; break;
+ case '7':
+ c_cflag |= CS7;
+ sp.data_bits = 7;
+ break;
+
+ case '8':
+ c_cflag |= CS8;
+ sp.data_bits = 8;
+ break;
- case 'N': break;
- case 'E': c_cflag |= PARENB; break;
- case 'O': c_cflag |= PARENB | PARODD; break;
+ case 'N':
+ sp.parity_bits = 0;
+ break;
- case '1': break;
- case '2': c_cflag |= CSTOPB; break;
+ case 'E':
+ c_cflag |= PARENB;
+ sp.parity_bits = 1;
+ break;
+
+ case 'O':
+ c_cflag |= PARENB | PARODD;
+ sp.parity_bits = 1;
+ break;
- default: return MBGSERIO_INV_CFG; // invalid framing string
+ case '1':
+ sp.stop_bits = 1;
+ break;
+
+ case '2':
+ c_cflag |= CSTOPB;
+ sp.stop_bits = 2;
+ break;
+
+ default:
+ return MBG_ERR_INV_PARM; // Invalid framing string.
}
}
@@ -572,7 +1010,7 @@ _MBG_API_ATTR int _MBG_API mbgserio_set_parms( SERIAL_IO_STATUS *pst,
// (POSIX says that the baud speed is stored in the termios structure
// without specifying where precisely, and provides cfgetispeed() and
// cfsetispeed() for getting at it. Some systems use bits selected
- // by CBAUD in c_cflag, other systems use separate fields,
+ // by CBAUD in c_cflag, other systems use separate fields,
// e.g. sg_ispeed and sg_ospeed.)
// CSIZE Character size mask. Values are CS5, CS6, CS7, or CS8.
// CSTOPB Set two stop bits, rather than one.
@@ -587,25 +1025,26 @@ _MBG_API_ATTR int _MBG_API mbgserio_set_parms( SERIAL_IO_STATUS *pst,
// the same as the values for the CBAUD bits, shifted left IBSHIFT bits.
// CRTSCTS (not in POSIX) Enable RTS/CTS (hardware) flow control.
- // local connection, no modem control (CLOCAL)
- // no flow control (no CRTSCTS)
- // enable receiving
+ // We use these flags:
+ // Local connection, no modem control (CLOCAL).
+ // No flow control (no CRTSCTS).
+ // Enable receiving (CREAD).
tio.c_cflag = c_cflag | CLOCAL | CREAD;
// Setup input flags. The following flags are defined:
// IGNBRK Ignore BREAK condition on input
- // BRKINT If IGNBRK is set, a BREAK is ignored. If it is not set
- // but BRKINT is set, then a BREAK causes the input and output
+ // BRKINT If IGNBRK is set, a BREAK is ignored. If it is not set
+ // but BRKINT is set, then a BREAK causes the input and output
// queues to be flushed, and if the terminal is the controlling
- // terminal of a foreground process group, it will cause a
+ // terminal of a foreground process group, it will cause a
// SIGINT to be sent to this foreground process group. When
// neither IGNBRK nor BRKINT are set, a BREAK reads as a NUL
// character, except when PARMRK is set, in which case it reads
// as the sequence \377 \0 \0.
// IGNPAR Ignore framing errors and parity errors.
- // PARMRK If IGNPAR is not set, prefix a character with a parity error
- // framing error with \377 \0. If neither IGNPAR nor PARMRK or
+ // PARMRK If IGNPAR is not set, prefix a character with a parity error
+ // framing error with \377 \0. If neither IGNPAR nor PARMRK or
// is set, read a character with a parity error or framing error as \0.
// INPCK Enable input parity checking.
// ISTRIP Strip off eighth bit.
@@ -620,9 +1059,9 @@ _MBG_API_ATTR int _MBG_API mbgserio_set_parms( SERIAL_IO_STATUS *pst,
// implement this bit, and acts as if it is always set.
tio.c_iflag = 0;
- #if 0 //##++
+ #if 0 // TODO Do we want or need this?
if ( c_cflag & PARENB )
- tio.c_iflag |= IGNPAR; //##++ this also ignores framing errors
+ tio.c_iflag |= IGNPAR; // This also ignores framing errors.
#endif
@@ -636,14 +1075,14 @@ _MBG_API_ATTR int _MBG_API mbgserio_set_parms( SERIAL_IO_STATUS *pst,
// ONOCR Don't output CR at column 0.
// ONLRET Don't output CR.
// OFILL Send fill characters for a delay, rather than using a timed delay.
- // OFDEL (not in POSIX) Fill character is ASCII DEL (0177). If unset,
+ // OFDEL (not in POSIX) Fill character is ASCII DEL (0177). If unset,
// fill character is ASCII NUL.
// NLDLY Newline delay mask. Values are NL0 and NL1.
// CRDLY Carriage return delay mask. Values are CR0, CR1, CR2, or CR3.
- // TABDLY Horizontal tab delay mask. Values are TAB0, TAB1, TAB2, TAB3
- // (or XTABS). A value of TAB3, that is, XTABS, expands tabs to
+ // TABDLY Horizontal tab delay mask. Values are TAB0, TAB1, TAB2, TAB3
+ // (or XTABS). A value of TAB3, that is, XTABS, expands tabs to
// spaces (with tab stops every eight columns).
- // BSDLY Backspace delay mask. Values are BS0 or BS1.
+ // BSDLY Backspace delay mask. Values are BS0 or BS1.
// (Has never been implemented.)
// VTDLY Vertical tab delay mask. Values are VT0 or VT1.
// FFDLY Form feed delay mask. Values are FF0 or FF1.
@@ -657,53 +1096,53 @@ _MBG_API_ATTR int _MBG_API mbgserio_set_parms( SERIAL_IO_STATUS *pst,
// EOF, EOL, EOL2, ERASE, KILL, LNEXT, REPRINT, STATUS, and
// WERASE, and buffers by lines.
// XCASE (not in POSIX; not supported under Linux) If ICANON is also
- // set, terminal is uppercase only. Input is converted to
- // lowercase, except for characters preceded by \. On output,
- // uppercase characters are preceded by \ and lowercase
+ // set, terminal is uppercase only. Input is converted to
+ // lowercase, except for characters preceded by \. On output,
+ // uppercase characters are preceded by \ and lowercase
// characters are converted to uppercase.
// ECHO Echo input characters.
- // ECHOE If ICANON is also set, the ERASE character erases the preceding
+ // ECHOE If ICANON is also set, the ERASE character erases the preceding
// input character, and WERASE erases the preceding word.
// ECHOK If ICANON is also set, the KILL character erases the current line.
// ECHONL If ICANON is also set, echo the NL character even if ECHO is not set.
// ECHOCTL (not in POSIX) If ECHO is also set, ASCII control signals
// other than TAB, NL, START, and STOP are echoed as ^X, where
- // X is the character with ASCII code 0x40 greater than the control
+ // X is the character with ASCII code 0x40 greater than the control
// signal. For example, character 0x08 (BS) is echoed as ^H.
- // ECHOPRT (not in POSIX) If ICANON and IECHO are also set, characters are
+ // ECHOPRT (not in POSIX) If ICANON and IECHO are also set, characters are
// printed as they are being erased.
- // ECHOKE (not in POSIX) If ICANON is also set, KILL is echoed by erasing
+ // ECHOKE (not in POSIX) If ICANON is also set, KILL is echoed by erasing
// each character on the line, as specified by ECHOE and ECHOPRT.
// DEFECHO (not in POSIX) Echo only when a process is reading.
// FLUSHO (not in POSIX; not supported under Linux) Output is being flushed.
// This flag is toggled by typing the DISCARD character.
// NOFLSH Disable flushing the input and output queues when generating the
// SIGINT, SIGQUIT and SIGSUSP signals.
- // TOSTOP Send the SIGTTOU signal to the process group of a background
+ // TOSTOP Send the SIGTTOU signal to the process group of a background
// process which tries to write to its controlling terminal.
// PENDIN (not in POSIX; not supported under Linux) All characters in the
- // input queue are reprinted when the next character is read.
+ // input queue are reprinted when the next character is read.
// (bash handles typeahead this way.)
// IEXTEN Enable implementation-defined input processing. This flag, as
- // well as ICANON must be enabled for the special characters EOL2,
+ // well as ICANON must be enabled for the special characters EOL2,
// LNEXT, REPRINT, WERASE to be interpreted, and for the IUCLC flag
// to be effective.
tio.c_lflag = 0;
// VINTR (003, ETX, Ctrl-C, or also 0177, DEL, rubout) Interrupt character.
- // Send a SIGINT signal. Recognized when ISIG is set, and then not
+ // Send a SIGINT signal. Recognized when ISIG is set, and then not
// passed as input.
// VQUIT (034, FS, Ctrl-\) Quit character. Send SIGQUIT signal. Recognized
// when ISIG is set, and then not passed as input.
// VERASE (0177, DEL, rubout, or 010, BS, Ctrl-H, or also #) Erase character.
// This erases the previous not-yet-erased character, but does not erase
- // past EOF or beginning-of-line. Recognized when ICANON is set,
+ // past EOF or beginning-of-line. Recognized when ICANON is set,
// and then not passed as input.
// VKILL (025, NAK, Ctrl-U, or Ctrl-X, or also @) Kill character. This erases
// the input since the last EOF or beginning-of-line. Recognized when
// ICANON is set, and then not passed as input.
- // VEOF (004, EOT, Ctrl-D) End-of-file character. More precisely: this
+ // VEOF (004, EOT, Ctrl-D) End-of-file character. More precisely: this
// character causes the pending tty buffer to be sent to the waiting
// user program without waiting for end-of-line. If it is the first
// character of the line, the read() in the user program returns 0,
@@ -722,9 +1161,9 @@ _MBG_API_ATTR int _MBG_API mbgserio_set_parms( SERIAL_IO_STATUS *pst,
// typed. Recognized when IXON is set, and then not passed as input.
// VSUSP (032, SUB, Ctrl-Z) Suspend character. Send SIGTSTP signal. Recognized
// when ISIG is set, and then not passed as input.
- // VDSUSP (not in POSIX; not supported under Linux; 031, EM, Ctrl-Y) Delayed
+ // VDSUSP (not in POSIX; not supported under Linux; 031, EM, Ctrl-Y) Delayed
// suspend character: send SIGTSTP signal when the character is read by
- // the user program. Recognized when IEXTEN and ISIG are set, and the
+ // the user program. Recognized when IEXTEN and ISIG are set, and the
// system supports job control, and then not passed as input.
// VLNEXT (not in POSIX; 026, SYN, Ctrl-V) Literal next. Quotes the next input
// character, depriving it of a possible special meaning. Recognized
@@ -733,18 +1172,18 @@ _MBG_API_ATTR int _MBG_API mbgserio_set_parms( SERIAL_IO_STATUS *pst,
// and IEXTEN are set, and then not passed as input.
// VREPRINT (not in POSIX; 022, DC2, Ctrl-R) Reprint unread characters. Recognized
// when ICANON and IEXTEN are set, and then not passed as input.
- // VDISCARD (not in POSIX; not supported under Linux; 017, SI, Ctrl-O) Toggle:
+ // VDISCARD (not in POSIX; not supported under Linux; 017, SI, Ctrl-O) Toggle:
// start/stop discarding pending output. Recognized when IEXTEN is set,
// and then not passed as input.
// VSTATUS (not in POSIX; not supported under Linux; status request: 024, DC4, Ctrl-T).
// Setting up c_cc[VMIN] and c_cc[VTIME]:
- // If MIN > 0 and TIME = 0, MIN sets the number of characters to receive before
+ // If MIN > 0 and TIME = 0, MIN sets the number of characters to receive before
// the read is satisfied. As TIME is zero, the timer is not used.
// If MIN = 0 and TIME > 0, TIME serves as a timeout value. The read will be
- // satisfied if a single character is read, or TIME is exceeded
- // (t = TIME *0.1 s). If TIME is exceeded, no character will be
+ // satisfied if a single character is read, or TIME is exceeded
+ // (t = TIME *0.1 s). If TIME is exceeded, no character will be
// returned.
// If MIN > 0 and TIME > 0, TIME serves as an inter-character timer. The
// read will be satisfied if MIN characters are received, or the
@@ -752,29 +1191,33 @@ _MBG_API_ATTR int _MBG_API mbgserio_set_parms( SERIAL_IO_STATUS *pst,
// every time a character is received and only becomes active after
// the first character has been received.
// If MIN = 0 and TIME = 0, read will be satisfied immediately. The number of
- // characters currently available, or the number of characters
- // requested will be returned. You could issue a
+ // characters currently available, or the number of characters
+ // requested will be returned. You could issue a
// fcntl(fd, F_SETFL, FNDELAY); before reading to get the same result.
- // setup control characters for non-blocking read
+ // Setup control characters for non-blocking read.
tio.c_cc[VMIN] = 0;
tio.c_cc[VTIME] = 0;
- // now clean the modem line and activate the settings for modem
- tcflush( port_handle, TCIFLUSH );
- tcsetattr( port_handle, TCSANOW, &tio );
+ // Now clean the modem line and activate the settings for modem.
+ if ( tcflush( port_handle, TCIFLUSH ) < 0 )
+ return mbg_get_last_error( "tcflush failed in mbgserio_set_parms" );
+
+ if ( tcsetattr( port_handle, TCSANOW, &tio ) < 0 )
+ return mbg_get_last_error( "tcsetattr failed in mbgserio_set_parms" );
- fflush( stdout );
- setvbuf( stdout, NULL, _IONBF, 0 );
+ // On success, fall through.
}
#elif defined( MBG_TGT_DOS )
#if defined( _USE_V24TOOLS )
{
- int datab = 8;
char parity = 'N';
- int stopb = 1;
- // setup framing.
+ sp.data_bits = 8;
+ sp.parity_bits = 0;
+ sp.stop_bits = 1;
+
+ // Setup framing.
for ( cp = framing; *cp; cp++ )
{
char c = toupper( *cp );
@@ -783,26 +1226,33 @@ _MBG_API_ATTR int _MBG_API mbgserio_set_parms( SERIAL_IO_STATUS *pst,
{
case '7':
case '8':
- datab = c - '0';
+ sp.data_bits = c - '0';
break;
case 'N':
+ parity = c;
+ sp.parity_bits = 0;
+ break;
+
case 'E':
case 'O':
- parity = *cp;
+ parity = c;
+ sp.parity_bits = 1;
break;
case '1':
case '2':
- stopb = c - '0';
+ sp.stop_bits = c - '0';
break;
default:
- return MBGSERIO_INV_CFG; // invalid framing string
+ return MBG_ERR_PARM_FMT; // Invalid framing string.
}
}
- v24setparams( port_handle, baud_rate, datab, parity, stopb );
+ v24setparams( port_handle, baud_rate, datab, parity, stopb ); // TODO check rc?
+
+ // On success, fall through.
}
#else
@@ -816,145 +1266,668 @@ _MBG_API_ATTR int _MBG_API mbgserio_set_parms( SERIAL_IO_STATUS *pst,
#endif
- return 0;
+ // Remember the configured speed parameters.
+ sdev->sp = sp;
-} // mbgserio_set_parms
+ rc = MBG_SUCCESS;
+
+ return rc;
+} // mbgserio_set_parms
-#if defined( MBG_TGT_WIN32 ) && !defined( MBG_TGT_CVI )
/*HDR*/
-_MBG_API_ATTR int _MBG_API mbgserio_read( MBG_PORT_HANDLE h, void *buffer, unsigned int count )
+/**
+ * @brief Read from a serial port.
+ *
+ * @param[in,out] sdev Control structure of the device.
+ * @param[out] buffer Buffer to take the bytes read.
+ * @param[in] count Size of @p buffer.
+ *
+ * @return On Success, the (positive) number of byte read,
+ * or one of the (negative) @ref MBG_ERROR_CODES on error.
+ */
+_NO_MBG_API_ATTR int _MBG_API mbgserio_read( MBGSERIO_DEV *sdev, void *buffer, unsigned int count )
{
- BOOL fReadStat;
- COMSTAT ComStat;
- DWORD dwErrorFlags;
- DWORD dwLength;
+ #if defined( MBG_TGT_CVI )
- ClearCommError( h, &dwErrorFlags, &ComStat );
+ return ComRd( sdev->port_handle, (char *) buffer, count ); // TODO Check or translate return code.
- if ( dwErrorFlags ) // transmission error (parity, framing, etc.)
- return MBGSERIO_FAIL;
+ #elif defined( MBG_TGT_WIN32 )
+ BOOL fReadStat;
+ COMSTAT ComStat;
+ DWORD dwErrorFlags;
+ DWORD dwLength;
- dwLength = min( (DWORD) count, ComStat.cbInQue );
+ ClearCommError( sdev->port_handle, &dwErrorFlags, &ComStat );
- if ( dwLength )
- {
- fReadStat = ReadFile( h, buffer, dwLength, &dwLength, NULL );
+ if ( dwErrorFlags ) // Transmission error (parity, framing, etc.).
+ return MBG_ERR_IO; // TODO Retrieve and return real error code.
- if ( !fReadStat )
- return MBGSERIO_FAIL;
- }
- return dwLength;
+ dwLength = min( (DWORD) count, ComStat.cbInQue );
+
+ if ( dwLength )
+ {
+ fReadStat = ReadFile( sdev->port_handle, buffer, dwLength, &dwLength, NULL );
+
+ if ( !fReadStat )
+ return MBG_ERR_IO; // TODO Retrieve and return real error code.
+ }
+
+ return dwLength;
+
+ #elif defined( MBG_TGT_POSIX )
+
+ int rc = read( sdev->port_handle, buffer, count );
+
+ if ( rc < 0 ) // Usually -1 in case of error.
+ rc = mbg_get_last_error( "read failed in mbgserio_read" );
+
+ return rc;
+
+ #elif defined( MBG_TGT_DOS ) && defined( _USE_V24TOOLS )
+
+ int rc = v24read( sdev->port_handle, buffer, count );
+
+ if ( rc < 0 )
+ rc = MBG_ERR_UNSPEC;
+
+ return rc;
+
+ #else
+
+ #error mbgserio_read() not implemented for this target
+
+ #endif
} // mbgserio_read
/*HDR*/
-_MBG_API_ATTR int _MBG_API mbgserio_write( MBG_PORT_HANDLE h, const void *buffer, unsigned int count )
+/**
+ * @brief Write to a serial port.
+ *
+ * @param[in,out] sdev Control structure of the device.
+ * @param[in] buffer Buffer with the bytes to write.
+ * @param[in] count Number of bytes in @p buffer to write.
+ *
+ * @return On Success, the (positive) number of byte read,
+ * or one of the (negative) @ref MBG_ERROR_CODES on error.
+ */
+_NO_MBG_API_ATTR int _MBG_API mbgserio_write( MBGSERIO_DEV *sdev, const void *buffer, unsigned int count )
{
- BOOL fWriteStat;
- COMSTAT ComStat;
- DWORD dwErrorFlags;
- DWORD dwThisBytesWritten;
- DWORD dwTotalBytesWritten = 0;
+ #if defined( MBG_TGT_CVI )
- while ( dwTotalBytesWritten < (DWORD) count )
- {
- dwThisBytesWritten = 0;
+ return ComWrt( sdev->port_handle, (char *) buffer, count ); // TODO Check or translate return code.
- fWriteStat = WriteFile( h, ( (char *) buffer ) + dwTotalBytesWritten,
- count - dwTotalBytesWritten,
- &dwThisBytesWritten, NULL );
- if ( !fWriteStat )
+ #elif defined( MBG_TGT_WIN32 )
+
+ BOOL fWriteStat;
+ COMSTAT ComStat;
+ DWORD dwErrorFlags;
+ DWORD dwThisBytesWritten;
+ DWORD dwTotalBytesWritten = 0;
+ MBG_PORT_HANDLE h = sdev->port_handle;
+
+ while ( dwTotalBytesWritten < (DWORD) count )
{
- #if defined( _DEBUG )
- DWORD dw = GetLastError();
- #endif
- break; //##++ Error: Unable to write
+ dwThisBytesWritten = 0;
+
+ fWriteStat = WriteFile( h, ( (char *) buffer ) + dwTotalBytesWritten,
+ count - dwTotalBytesWritten,
+ &dwThisBytesWritten, NULL );
+ if ( !fWriteStat )
+ return mbg_get_last_error( "write failed in mbgserio_write" );
+
+ dwTotalBytesWritten += dwThisBytesWritten;
+
+ ClearCommError( h, &dwErrorFlags, &ComStat );
+
+ if ( dwErrorFlags )
+ {
+ // Possible errors:
+ //
+ // CE_RXOVER 0x0001 // Receive Queue overflow
+ // CE_OVERRUN 0x0002 // Receive Overrun Error, next character(s) lost
+ // CE_RXPARITY 0x0004 // Receive Parity Error
+ // CE_FRAME 0x0008 // Receive Framing error
+ // CE_BREAK 0x0010 // Break Detected
+ // CE_TXFULL 0x0100 // TX Queue is full
+ // CE_PTO 0x0200 // LPTx Timeout
+ // CE_IOE 0x0400 // LPTx I/O Error
+ // CE_DNS 0x0800 // LPTx Device not selected
+ // CE_OOP 0x1000 // LPTx Out-Of-Paper
+ // CE_MODE 0x8000 // Requested mode unsupported
+ //
+ // Except CE_TXFULL these are usually RX error flags,
+ // so we just ignore them.
+ }
}
- dwTotalBytesWritten += dwThisBytesWritten;
+ return dwTotalBytesWritten;
- ClearCommError( h, &dwErrorFlags, &ComStat );
+ #elif defined( MBG_TGT_POSIX )
- if ( dwErrorFlags )
- break; //#++ Error: Check flags
- }
+ int rc = write( sdev->port_handle, buffer, count ); // Returns -1 on error, else number of byte written.
+
+ if ( rc == -1 )
+ rc = mbg_get_last_error( "write failed in mbgserio_write" );
+
+ return rc;
+
+ #elif defined( MBG_TGT_DOS ) && defined( _USE_V24TOOLS )
+
+ int rc = v24write( sdev->port_handle, buffer, count ); // TODO Check or translate return code.
- return dwTotalBytesWritten;
+ if ( rc < 0 )
+ rc = MBG_ERR_UNSPEC;
+
+ return rc;
+
+ #else
+
+ #error mbgserio_write() not implemented for this target
+
+ #endif
} // mbgserio_write
-#endif // defined( MBG_TGT_WIN32 ) && !defined( MBG_TGT_CVI )
+
+
+/*HDR*/
+/**
+ * @brief Flush the transmit buffer of a serial port.
+ *
+ * @param[in,out] sdev Control structure of the device.
+ */
+_NO_MBG_API_ATTR void _MBG_API mbgserio_flush_tx( MBGSERIO_DEV *sdev )
+{
+ #if defined( MBG_TGT_CVI )
+
+ FlushOutQ( sdev->port_handle );
+
+ #elif defined( MBG_TGT_WIN32 )
+
+ #if defined( DEBUG )
+ printf( "Flushing TX buffers ...\n" );
+ #endif
+
+ FlushFileBuffers( sdev->port_handle );
+
+ #if ( 1 && defined( DEBUG ) ) // TODO
+ {
+ COMSTAT ComStat;
+ DWORD dwErrorFlags;
+
+ for (;;)
+ {
+ ClearCommError( sdev->port_handle, &dwErrorFlags, &ComStat );
+
+ printf( "ErrFlags: %04X, out queue: %u\n", dwErrorFlags, ComStat.cbOutQue );
+
+ if ( ComStat.cbOutQue == 0 )
+ break;
+
+ Sleep( 1 );
+ }
+ }
+ #endif
+
+ #elif defined( MBG_TGT_POSIX )
+
+ tcdrain( sdev->port_handle );
+
+ #elif defined( MBG_TGT_DOS ) && defined( _USE_V24TOOLS )
+
+ v24flush( sdev->port_handle, SND );
+
+ #else
+
+ #error mbgserio_flush_tx() not implemented for this target
+
+ #endif
+
+} // mbgserio_flush_tx
/*HDR*/
-_MBG_API_ATTR int _MBG_API mbgserio_read_wait( MBG_PORT_HANDLE h, void *buffer,
- uint count, ulong char_timeout )
+/**
+ * @brief Get the current poll timeout count, in milliseconds.
+ *
+ * Used for timeout in ::mbgserio_read_wait.
+ *
+ * @param[in] sdev Control structure of the device.
+ *
+ * @return The current timeout value, in milliseconds.
+ *
+ * @see ::mbgserio_set_dev_poll_timeout
+ * @see ::mbgserio_read_wait
+ */
+ulong mbgserio_get_dev_poll_timeout( const MBGSERIO_DEV *sdev )
{
- int n_bytes;
+ return sdev->poll_timeout;
+
+} // mbgserio_get_dev_poll_timeout
- #if _USE_SELECT_FOR_SERIAL_IO
+
+
+/*HDR*/
+/**
+ * @brief Set a new poll timeout, in milliseconds.
+ *
+ * Used for timeout in ::mbgserio_read_wait.
+ *
+ * @param[in,out] sdev Control structure of the device.
+ * @param[in] new_timeout New timeout, in milliseconds.
+ *
+ * @return The previous timeout value, in milliseconds.
+ *
+ * @see ::mbgserio_get_dev_poll_timeout
+ * @see ::mbgserio_read_wait
+ */
+ulong mbgserio_set_dev_poll_timeout( MBGSERIO_DEV *sdev, ulong new_timeout )
+{
+ ulong prev_timeout = mbgserio_get_dev_poll_timeout( sdev );
+
+ sdev->poll_timeout = new_timeout;
+
+ return prev_timeout;
+
+} // mbgserio_set_dev_poll_timeout
+
+
+
+/*HDR*/
+/**
+ * @brief Wait for data and read from a serial port.
+ *
+ * @param[in,out] sdev Control structure of the device.
+ * @param[out] buffer Buffer to take the bytes read.
+ * @param[in] count Size of @p buffer.
+ *
+ * @return On Success, the (positive) number of byte read,
+ * or one of the (negative) @ref MBG_ERROR_CODES on error.
+ */
+_NO_MBG_API_ATTR int _MBG_API mbgserio_read_wait( MBGSERIO_DEV *sdev, void *buffer,
+ unsigned int count )
+{
+ int rc;
+
+ #if _USE_SELECT_FOR_SERIAL_IO // Should be used preferably.
struct timeval tv_char_timeout;
fd_set fds;
- int rc;
+ int max_fd;
- mbgserio_msec_to_timeval( char_timeout, &tv_char_timeout );
+ mbg_msec_to_timeval( sdev->poll_timeout, &tv_char_timeout );
FD_ZERO( &fds );
- FD_SET( h, &fds );
+ FD_SET( sdev->port_handle, &fds );
+
+ #if defined( MBG_TGT_WIN32 )
+ // On Windows, an fd is a handle which can't simply
+ // be converted to an int, but the first argument of
+ // select() is ignored on Windows anyway, so we just
+ // set max_fd to 0.
+ max_fd = 0;
+ #else
+ max_fd = sdev->port_handle;
+ #endif
- rc = select( h + 1, &fds, NULL, NULL, &tv_char_timeout );
+ rc = select( max_fd + 1, &fds, NULL, NULL, &tv_char_timeout );
- if ( rc < 0 ) // error
- goto fail;
+ if ( rc < 0 ) // Error.
+ return mbg_get_last_error( "select failed in mbgserio_read_wait" );
- if ( rc == 0 ) // timeout
- goto timeout;
+ if ( rc == 0 ) // Timeout.
+ return MBG_ERR_TIMEOUT;
- // data is available
- n_bytes = _mbgserio_read( h, buffer, count );
+ // Data is available.
+ rc = mbgserio_read( sdev, buffer, count );
#else
+
MBG_TMO_TIME tmo;
- mbg_tmo_set_timeout_ms( &tmo, char_timeout );
+ mbg_tmo_set_timeout_ms( &tmo, sdev->poll_timeout );
for (;;) // wait to read one new char
{
- n_bytes = _mbgserio_read( h, buffer, count );
+ rc = mbgserio_read( sdev, buffer, count );
- if ( n_bytes > 0 ) // new char(s) received
+ if ( rc != 0 ) // Byte(s) received, or error.
break;
- if ( n_bytes < 0 ) // error
- goto fail;
-
if ( mbg_tmo_curr_time_is_after( &tmo ) )
- goto timeout;
+ return MBG_ERR_TIMEOUT;
- #if defined( MBG_TGT_UNIX )
+ #if defined( MBG_TGT_POSIX )
usleep( 10 * 1000 );
#endif
}
#endif
- return n_bytes;
+ return rc;
-timeout:
- return MBGSERIO_TIMEOUT;
+} // mbgserio_read_wait
-fail:
- return MBGSERIO_FAIL;
-} // mbgserio_read_wait
+
+/*HDR*/
+/**
+ * @brief Compute the time required to transmit a number of bytes, in nanoseconds.
+ *
+ * Depends on the baud rate and the effective number of
+ * bits per byte, i.e. data / parity / stop bits.
+ * Assuming the transmission is without gaps.
+ *
+ * If 2 stobits are used, this differs from ::mbgserio_get_duration_rcv.
+ * See ::mbgserio_get_duration_rcv.
+ *
+ * @param[in] p_sp The relevant parameters of the transmission.
+ * @param[in] n_bytes The number of bytes to transmit.
+ *
+ * @return The the computed duration, in nanoseconds.
+ *
+ * @see ::mbgserio_get_duration_rcv
+ */
+_NO_MBG_API_ATTR int32_t _MBG_API mbgserio_get_duration_xmt( MBGSERIO_SPEED_PARMS *p_sp, int n_bytes )
+{
+ // Total number of bits, including start bit.
+ int n_bits = n_bytes * ( 1 + p_sp->data_bits + p_sp->parity_bits + p_sp->stop_bits );
+
+ return (int32_t) ( ( (int64_t) n_bits * NSEC_PER_SEC ) / p_sp->baud_rate );
+
+} // mbgserio_get_duration_xmt
+/*HDR*/
+/**
+ * @brief Compute the receive delay for a number of bytes, in nanoseconds.
+ *
+ * Depends on the baud rate and the effective number of
+ * bits per byte, i.e. data / parity / stop bits.
+ * Assuming the transmission is without gaps.
+ *
+ * Differs from ::mbgserio_get_duration_xmt in case there are
+ * 2 stop bits. This is because because UARTS usually flag
+ * reception of a byte after the first stop bit, even if
+ * 2 stop bits are used for transmission.
+ *
+ * @param[in] p_sp The relevant parameters of the transmission.
+ * @param[in] n_bytes The number of bytes to receive.
+ * @param[in] n_bits A number of additional bits to account for.
+ *
+ * @return The the computed duration, in nanoseconds.
+ *
+ * @see ::mbgserio_get_duration_xmt
+ */
+_NO_MBG_API_ATTR int32_t _MBG_API mbgserio_get_duration_rcv( const MBGSERIO_SPEED_PARMS *p_sp,
+ int n_bytes, int n_bits )
+{
+ // Total number of bits, including start bit.
+ int n_bits_total = n_bytes * ( 1 + p_sp->data_bits + p_sp->parity_bits + p_sp->stop_bits + n_bits );
+
+ // If 2 stop bits are used for transmission, we
+ // subtract 1 stop bit from the total number of bits.
+ if ( p_sp->stop_bits > 1 )
+ n_bits_total--;
+
+ return (int32_t) ( ( (int64_t) n_bits_total * NSEC_PER_SEC ) / p_sp->baud_rate );
+
+} // mbgserio_get_duration_rcv
+
+
+
+#if USE_LINUX_DEV_DIR
+
+static /*HDR*/
+int scandir_filter_serial_port( const struct dirent *pde )
+{
+ static const char dev_name_1[] = "ttyS";
+ static const char dev_name_2[] = "ttyUSB";
+ char tmp_str[100];
+ MBGSERIO_DEV *sdev;
+ int rc;
+
+ int l;
+
+ l = strlen( dev_name_1 );
+
+ if ( strncmp( pde->d_name, dev_name_1, l ) == 0 )
+ goto check;
+
+
+ l = strlen( dev_name_2 );
+
+ if ( strncmp( pde->d_name, dev_name_2, l ) == 0 )
+ goto check;
+
+ return 0;
+
+check:
+ // If the first character after the search string is not a digit,
+ // the search result is not what we want.
+ if ( pde->d_name[l] < '0' || pde->d_name[l] > '9' )
+ return 0;
+
+ snprintf_safe( tmp_str, sizeof( tmp_str ), "%s/%s", dev_dir, pde->d_name );
+
+ rc = mbgserio_open( &sdev, tmp_str );
+
+ if ( rc < 0 )
+ {
+ #if defined( DEBUG )
+ fprintf( stderr, "failed to open %s: %i\n", tmp_str, rc );
+ #endif
+
+ return 0;
+ }
+
+ #if defined( DEBUG )
+ fprintf( stderr, "port %s opened successfully\n", tmp_str );
+ #endif
+
+ mbgserio_close( &sdev );
+
+ return 1;
+
+} // scandir_filter_serial_port
+
+#endif // USE_LINUX_DEV_DIR
+
+
+
+/*HDR*/
+/**
+ * @brief Set up a string list with names of available serial ports.
+ *
+ * @param[out] list Address of the header of a list to be set up.
+ * @param[in] max_devs Maximum number of list entries to create.
+ *
+ * @return The number of entries in the list.
+ *
+ * @see ::mbgserio_free_str_list
+ */
+_NO_MBG_API_ATTR int _MBG_API mbgserio_setup_port_str_list( MBG_STR_LIST **list, int max_devs )
+{
+ MBG_STR_LIST *list_head;
+ int n = 0;
+ int i = 0;
+
+ (*list) = (MBG_STR_LIST *) malloc( sizeof( **list ) );
+ memset( (*list), 0, sizeof( **list ) );
+
+ list_head = (*list);
+
+
+#if 0 && USE_LINUX_DEV_DIR
+
+ struct dirent **namelist;
+
+ n = scandir( dev_dir, &namelist, scandir_filter_serial_port, versionsort );
+
+ if ( n < 0 )
+ perror( "scandir" );
+ else
+ {
+ for ( i = 0; i < n; i++ )
+ {
+ printf( "%s/%s\n", dev_dir, namelist[i]->d_name );
+ free( namelist[i] );
+ }
+
+ free( namelist );
+ }
+
+#elif 0 && USE_LINUX_DEV_DIR
+
+ DIR *pd = opendir( dev_dir );
+
+ if ( pd )
+ {
+ struct dirent *pde;
+
+ while ( ( pde = readdir( pd ) ) != NULL )
+ {
+ if ( strncmp( pde->d_name, "ttyS", 4 ) == 0 )
+ goto found;
+
+ if ( strncmp( pde->d_name, "ttyUSB", 6 ) == 0 )
+ goto found;
+
+ continue;
+
+found:
+ fprintf( stderr, "found /dev/%s\n", pde->d_name );
+ }
+
+ closedir( pd );
+ }
+
+#else
+
+ for ( i = 0; i < max_devs; i++ )
+ {
+ char dev_name[100] = { 0 };
+ int rc;
+
+ #if defined( MBG_TGT_WIN32 )
+
+ HANDLE h = INVALID_HANDLE_VALUE;
+
+ snprintf_safe( dev_name, sizeof( dev_name ), "COM%i", i + 1 );
+ rc = win32_open_serial_port( dev_name, &h );
+
+ // If access is denied, the port exists but is in use.
+ if ( rc != MBG_SUCCESS && rc != MBG_ERR_ACCESS )
+ continue; // Memory allocation error.
+
+ if ( h != INVALID_HANDLE_VALUE )
+ CloseHandle( h );
+
+ #elif defined( MBG_TGT_LINUX )
+
+ MBGSERIO_DEV *sdev;
+ snprintf_safe( dev_name, sizeof( dev_name ), "/dev/ttyS%i", i );
+ rc = mbgserio_open( &sdev, dev_name );
+
+ if ( rc < 0 )
+ {
+ snprintf_safe( dev_name, sizeof( dev_name ), "/dev/ttyUSB%i", i );
+
+ rc = mbgserio_open( &sdev, dev_name );
+
+ if ( rc < 0 )
+ continue;
+ }
+
+ mbgserio_close( &sdev );
+
+ #endif
+
+
+ // Add the device name to the list.
+
+ (*list)->s = (char *) malloc( strlen( dev_name ) + 1 );
+ strcpy( (*list)->s, dev_name );
+
+ (*list)->next = (MBG_STR_LIST *) malloc( sizeof( **list ) );
+ (*list) = (*list)->next;
+
+ memset( (*list), 0, sizeof( **list ) );
+ n++;
+
+ // TODO Do we want or need this?
+ //
+ // if ( ++i >= N_SUPP_DEV_EXT )
+ // break;
+ }
+
+ if ( n == 0 )
+ {
+ free( *list );
+ list_head = NULL;
+ }
+#endif
+
+ *list = list_head;
+
+ return n;
+
+} // mbgserio_setup_port_str_list
+
+
+
+/*HDR*/
+/**
+ * @brief Free a string list that has been allocated before.
+ *
+ * @param[out] list Address of the string list to be freed.
+ *
+ * @see ::mbgserio_setup_port_str_list
+ */
+_NO_MBG_API_ATTR void _MBG_API mbgserio_free_str_list( MBG_STR_LIST *list )
+{
+ int i = 0;
+
+ while ( i < 1000 ) // FIXME TODO Why 1000 ?
+ {
+ if ( list )
+ {
+ if ( list->s )
+ {
+ free( list->s );
+ list->s = NULL;
+ }
+
+ if ( list->next )
+ {
+ MBG_STR_LIST *next = list->next;
+ free( list );
+ list = next;
+ }
+ else
+ {
+ if ( list )
+ {
+ free( list );
+ list = NULL;
+ }
+ break;
+ }
+ }
+ else
+ break;
+
+ i++;
+ }
+
+} // mbgserio_free_str_list
+
diff --git a/mbglib/common/mbgserio.h b/mbglib/common/mbgserio.h
index 2367e14..96c3be7 100644
--- a/mbglib/common/mbgserio.h
+++ b/mbglib/common/mbgserio.h
@@ -1,7 +1,7 @@
/**************************************************************************
*
- * $Id: mbgserio.h 1.4 2009/09/01 10:54:29 martin REL_M $
+ * $Id: mbgserio.h 1.12 2021/12/01 10:19:10 martin.burnicki REL_M $
*
* Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
*
@@ -10,6 +10,36 @@
*
* -----------------------------------------------------------------------
* $Log: mbgserio.h $
+ * Revision 1.12 2021/12/01 10:19:10 martin.burnicki
+ * Make a parameter of mbgserio_get_duration_rcv() const.
+ * Revision 1.11 2021/05/04 20:43:25 martin
+ * New field MBGSERIO_DEV::rcv_fifo_threshold, for the receive FIFO
+ * threshold, and structure MBGSERIO_SPEED_PARMS. These are useful
+ * to determine the transmission delay of a received time string.
+ * Removed some trailing spaces.
+ * Updated some comments and function prototypes.
+ * Revision 1.10 2021/04/07 16:32:11 martin
+ * Updated a bunch of comments, and renamed some local variables.
+ * Revision 1.9 2018/11/29 16:03:58 martin
+ * Removed obsolete conditional _USE_MBG_TSTR stuff.
+ * Revision 1.8 2017/07/06 07:41:00Z martin
+ * Renamed SERIAL_IO_STATUS to MBGSERIO_DEV,
+ * and renamed some fields of the structure.
+ * Defined default device names for serial ports
+ * depending on the target system.
+ * Check preprocessor symbol _USE_MBG_TSTR instead
+ * of _USE_CHK_TSTR.
+ * Check for MBG_TGT_POSIX instead of MBG_TGT_UNIX.
+ * Updated function prototypes.
+ * Revision 1.7 2013/02/01 16:10:45 martin
+ * Got rid of _mbg_open/close/read/write() macros.
+ * Functions are now used instead.
+ * Updated function prototypes.
+ * Revision 1.6 2011/08/23 10:15:25Z martin
+ * Updated function prototypes.
+ * Revision 1.5 2011/08/04 09:48:55 martin
+ * Support flushing output.
+ * Re-ordered some definitions.
* Revision 1.4 2009/09/01 10:54:29 martin
* Include mbg_tmo.h for the new portable timeout functions.
* Added symbols for return codes in case of an error.
@@ -30,21 +60,19 @@
/* Other headers to be included */
+#include <mbg_tgt.h>
#include <mbg_tmo.h>
+#include <mbgerror.h>
#include <stdlib.h>
#include <string.h>
-#if defined( MBG_TGT_UNIX )
+#if defined( MBG_TGT_POSIX )
#include <termios.h>
#endif
-#if _USE_CHK_TSTR
- #include <chk_tstr.h>
-#endif
-
#if !defined( _USE_SELECT_FOR_SERIAL_IO )
- #if defined( MBG_TGT_UNIX )
+ #if defined( MBG_TGT_POSIX )
#define _USE_SELECT_FOR_SERIAL_IO 1
#else
#define _USE_SELECT_FOR_SERIAL_IO 0
@@ -62,16 +90,41 @@
/* Start of header body */
-#define MBGSERIO_FAIL -1 // Generic I/O error
-#define MBGSERIO_TIMEOUT -2 // timeout
-#define MBGSERIO_INV_CFG -3 // invalid configuration parameters
-
+#ifdef __cplusplus
+extern "C" {
+#endif
-#if !defined( DEFAULT_DEV_NAME )
+#if !defined( DEFAULT_SERIAL_DEVICE_NAME )
+ // For applications that support 2 serial ports, we also
+ // define default names for the second port to be used.
#if defined( MBG_TGT_WIN32 ) || defined( MBG_TGT_DOS )
- #define DEFAULT_DEV_NAME "COM1"
+ #define DEFAULT_SERIAL_DEVICE_NAME "COM1"
+ #define DEFAULT_SERIAL_DEVICE_NAME_2 "COM2"
#elif defined( MBG_TGT_LINUX )
- #define DEFAULT_DEV_NAME "/dev/ttyS0"
+ #define DEFAULT_SERIAL_DEVICE_NAME "/dev/ttyS0"
+ #define DEFAULT_SERIAL_DEVICE_NAME_2 "/dev/ttyS1"
+ #elif defined( MBG_TGT_FREEBSD )
+ // Call-in ports are named /dev/ttyuN where N is the port number, starting from 0.
+ // Generally, the call-in port is used for terminals. Call-in ports require that
+ // the serial line assert the "Data Carrier Detect" signal to work correctly.
+ // Call-out ports are named /dev/cuauN on FreeBSD versions 8.X and later and
+ // /dev/cuadN on FreeBSD versions 7.X and earlier. Call-out ports are usually not
+ // used for terminals, but are used for modems. The call-out port can be used if the
+ // serial cable or the terminal does not support the "Data Carrier Detect" signal.
+ #if ( __FreeBSD__ > 7 )
+ #define DEFAULT_SERIAL_DEVICE_NAME "/dev/cuau0"
+ #define DEFAULT_SERIAL_DEVICE_NAME_2 "/dev/cuau1"
+ #else
+ #define DEFAULT_SERIAL_DEVICE_NAME "/dev/cuad0"
+ #define DEFAULT_SERIAL_DEVICE_NAME_2 "/dev/cuad1"
+ #endif
+ #elif defined( MBG_TGT_NETBSD )
+ // The ttyXX devices are traditional dial-in devices;
+ // the dtyXX devices are used for dial-out. See tty(4).
+ #define DEFAULT_SERIAL_DEVICE_NAME "/dev/dty00"
+ #define DEFAULT_SERIAL_DEVICE_NAME_2 "/dev/dty01"
+ #else
+ #error DEFAULT_SERIAL_DEVICE_NAME needs to be defined for this target.
#endif
#endif
@@ -94,61 +147,18 @@
#include <rs232.h>
- #define _mbg_open _open
- #define _mbg_close _close
- #define _mbg_read _read
- #define _mbg_write _write
-
- #define _mbgserio_write( _dh, _p, _sz ) \
- ComWrt( _dh, (char *) (_p), _sz )
-
- #define _mbgserio_read( _dh, _p, _sz ) \
- ComRd( _dh, (char *) (_p), _sz )
-
#elif defined( MBG_TGT_WIN32 )
- #include <windows.h>
#include <io.h>
- #define _mbg_open _open
- #define _mbg_close _close
- #define _mbg_read _read
- #define _mbg_write _write
-
- #define _mbgserio_write mbgserio_write
- #define _mbgserio_read mbgserio_read
-
- #elif defined( MBG_TGT_UNIX )
-
- #include <unistd.h>
-
- #define _mbg_open open
- #define _mbg_close close
- #define _mbg_read read
- #define _mbg_write write
-
#elif defined( MBG_TGT_DOS )
#if defined( _USE_V24TOOLS )
#include <v24tools.h>
-
- #define _mbgserio_open v24open
- #define _mbgserio_read v24read
- #define _mbgserio_write v24write
#endif
#endif
- #if !defined( _mbgserio_open )
- #define _mbgserio_open _mbg_open
- #endif
- #if !defined( _mbgserio_write )
- #define _mbgserio_write _mbg_write
- #endif
- #if !defined( _mbgserio_read )
- #define _mbgserio_read _mbg_read
- #endif
-
#endif
@@ -162,42 +172,286 @@ typedef struct _MBG_STR_LIST
+/**
+ * @brief Serial parameters required to compute the transmission time.
+ *
+ * @see ::mbgserio_get_duration_xmt
+ * @see ::mbgserio_get_duration_rcv
+ */
typedef struct
{
- MBG_PORT_HANDLE port_handle; // the handle that will be used for the device
+ uint32_t baud_rate; ///< Baud rate (0 if unknown).
+ int data_bits; ///< Number of data bits (7 or 8, 0 if unknown).
+ int parity_bits; ///< Number of parity bits (0 or 1).
+ int stop_bits; ///< Number of stop bits (1 or 2, 0 if unknown).
+
+} MBGSERIO_SPEED_PARMS;
+
+
+
+/**
+ * @brief Control structure for a serial device.
+ *
+ * Should be considered opaque.
+ */
+typedef struct
+{
+ MBG_PORT_HANDLE port_handle; ///< The handle that will be used for the device.
+
+ MBGSERIO_SPEED_PARMS sp; ///< Can be used to compute the transmission time.
+
+ /// @brief The receive FIFO threshold of the UART.
+ ///
+ /// The UART generates a receive event (e.g. an IRQ) after
+ /// at least this number of bytes has been received. This may
+ /// affect the timing. 0 if unknown or can't be determined.
+ int rcv_fifo_threshold;
+
+ ulong poll_timeout; ///< The default timeout when waiting for data, [ms].
#if defined( MBG_TGT_WIN32 )
- DCB old_dcb;
- COMMTIMEOUTS old_commtimeouts;
- #endif
- #if defined( MBG_TGT_UNIX )
- struct termios oldtio;
- //##++ struct termios newtio;
- #endif
+ DCB org_dcb;
+ int org_dcb_has_been_read;
+
+ COMMTIMEOUTS org_commtimeouts; ///< Original timeout configuration when the port was opened.
+ int org_commtimeouts_have_been_read; ///< Flag indicating that @p org_commtimeouts has been read.
-} SERIAL_IO_STATUS;
+ COMMPROP comm_prop; ///< Configuration settings supported by the driver (r/o).
+ int comm_prop_have_been_read; ///< Flag indicating that @p comm_prop has been read.
+ #endif
+ #if defined( MBG_TGT_POSIX )
+ struct termios org_tio; ///< Original port settings when the port was opened.
+ int org_tio_has_been_read; ///< Flag indicating that @p org_tio has been read.
+ #endif
+} MBGSERIO_DEV;
-/* function prototypes: */
-#ifdef __cplusplus
-extern "C" {
-#endif
/* ----- function prototypes begin ----- */
/* This section was generated automatically */
/* by MAKEHDR, do not remove the comments. */
- _MBG_API_ATTR int _MBG_API mbgserio_open( SERIAL_IO_STATUS *pst, const char *dev ) ;
- _MBG_API_ATTR int _MBG_API mbgserio_close( SERIAL_IO_STATUS *pst ) ;
- _MBG_API_ATTR int _MBG_API mbgserio_setup_port_str_list( MBG_STR_LIST **list, int max_devs ) ;
- _MBG_API_ATTR void _MBG_API _MBG_API mbgserio_free_str_list( MBG_STR_LIST *list ) ;
- _MBG_API_ATTR int _MBG_API mbgserio_set_parms( SERIAL_IO_STATUS *pst, uint32_t baud_rate, const char *framing ) ;
- _MBG_API_ATTR int _MBG_API mbgserio_read( MBG_PORT_HANDLE h, void *buffer, unsigned int count ) ;
- _MBG_API_ATTR int _MBG_API mbgserio_write( MBG_PORT_HANDLE h, const void *buffer, unsigned int count ) ;
- _MBG_API_ATTR int _MBG_API mbgserio_read_wait( MBG_PORT_HANDLE h, void *buffer, uint count, ulong char_timeout ) ;
+ /**
+ * @brief Return the base name of the device name of a serial port.
+ *
+ * In order to leave the original device name string unchanged,
+ * a buffer is allocated with a duplicate of the original string,
+ * and a pointer to the basename component in that buffer is returned.
+ *
+ * After usage, the allocated buffer whose address is saved in
+ * @p *pp_dup_port_name should be freed by calling ::mbgserio_free_port_basename.
+ *
+ * @param[in] pp_dup_port_name Address of a <em>char *</em> that takes the address
+ * of the allocated string buffer.
+ * @param[in] port_name The original device name string.
+ *
+ * @return A pointer to the basename which is part of an allocated copy of the original string.
+ *
+ * @see ::mbgserio_free_port_basename
+ */
+ _NO_MBG_API_ATTR char * _MBG_API mbgserio_get_port_basename( char **pp_dup_port_name, const char *port_name ) ;
+
+ /**
+ * @brief Free a buffer that has been allocated by ::mbgserio_get_port_basename.
+ *
+ * This function should be called whenever a string buffer allocated
+ * by an earlier ::mbgserio_get_port_basename call isn't needed anymore.
+ *
+ * @param[in] pp_dup_port_name Address of a <em>char *</em> with the address
+ * of the allocated string buffer.
+ *
+ * @see ::mbgserio_get_port_basename
+ */
+ _NO_MBG_API_ATTR void _MBG_API mbgserio_free_port_basename( char **pp_dup_port_name ) ;
+
+ /**
+ * @brief Determine the threshold of a serial RX FIFO buffer.
+ *
+ * This is useful to be able to exactly compensate the delay
+ * of a received serial data string.
+ *
+ * @note This may not be supported on each target system.
+ *
+ * @param[in] port_name The device name of the serial port.
+ *
+ * @return The number of bytes in the FIFO buffer after which
+ * a receive event (e.g. IRQ) is generated,
+ * or 0 if the real threshold can't be determined.
+ */
+ _NO_MBG_API_ATTR int _MBG_API mbgserio_get_rx_fifo_threshold( const char *port_name ) ;
+
+ /**
+ * @brief Close a serial port specified by a ::MBGSERIO_DEV structure.
+ *
+ * After the port has been closed, the buffer that had been allocated
+ * for the ::MBGSERIO_DEV structure is freed, and the pointer to that
+ * buffer is set to @a NULL.
+ *
+ * @param[in,out] pp_sdev Address of a pointer to the control structure including the port handle.
+ *
+ * @return One of the @ref MBG_RETURN_CODES.
+ */
+ _NO_MBG_API_ATTR int _MBG_API mbgserio_close( MBGSERIO_DEV **pp_sdev ) ;
+
+ /**
+ * @brief Open a serial port and set up a ::MBGSERIO_DEV structure.
+ *
+ * @param[in,out] pp_sdev Address of a pointer to a ::MBGSERIO_DEV device control structure
+ * allocated and set up by this call. Set to @a NULL on error.
+ * @param[in] dev_name Device name of the port to be opened.
+ *
+ * @return One of the @ref MBG_RETURN_CODES.
+ */
+ _NO_MBG_API_ATTR int _MBG_API mbgserio_open( MBGSERIO_DEV **pp_sdev, const char *dev_name ) ;
+
+ /**
+ * @brief Set the transmission parameters of a serial port.
+ *
+ * @param[in,out] sdev Control structure of the device.
+ * @param[in] baud_rate One of the well-known baud rates, e.g. 19200.
+ * @param[in] framing A short string providing the framing, e.g. "8N1".
+ *
+ * @return One of the @ref MBG_RETURN_CODES.
+ */
+ _NO_MBG_API_ATTR int _MBG_API mbgserio_set_parms( MBGSERIO_DEV *sdev, uint32_t baud_rate, const char *framing ) ;
+
+ /**
+ * @brief Read from a serial port.
+ *
+ * @param[in,out] sdev Control structure of the device.
+ * @param[out] buffer Buffer to take the bytes read.
+ * @param[in] count Size of @p buffer.
+ *
+ * @return On Success, the (positive) number of byte read,
+ * or one of the (negative) @ref MBG_ERROR_CODES on error.
+ */
+ _NO_MBG_API_ATTR int _MBG_API mbgserio_read( MBGSERIO_DEV *sdev, void *buffer, unsigned int count ) ;
+
+ /**
+ * @brief Write to a serial port.
+ *
+ * @param[in,out] sdev Control structure of the device.
+ * @param[in] buffer Buffer with the bytes to write.
+ * @param[in] count Number of bytes in @p buffer to write.
+ *
+ * @return On Success, the (positive) number of byte read,
+ * or one of the (negative) @ref MBG_ERROR_CODES on error.
+ */
+ _NO_MBG_API_ATTR int _MBG_API mbgserio_write( MBGSERIO_DEV *sdev, const void *buffer, unsigned int count ) ;
+
+ /**
+ * @brief Flush the transmit buffer of a serial port.
+ *
+ * @param[in,out] sdev Control structure of the device.
+ */
+ _NO_MBG_API_ATTR void _MBG_API mbgserio_flush_tx( MBGSERIO_DEV *sdev ) ;
+
+ /**
+ * @brief Get the current poll timeout count, in milliseconds.
+ *
+ * Used for timeout in ::mbgserio_read_wait.
+ *
+ * @param[in] sdev Control structure of the device.
+ *
+ * @return The current timeout value, in milliseconds.
+ *
+ * @see ::mbgserio_set_dev_poll_timeout
+ * @see ::mbgserio_read_wait
+ */
+ ulong mbgserio_get_dev_poll_timeout( const MBGSERIO_DEV *sdev ) ;
+
+ /**
+ * @brief Set a new poll timeout, in milliseconds.
+ *
+ * Used for timeout in ::mbgserio_read_wait.
+ *
+ * @param[in,out] sdev Control structure of the device.
+ * @param[in] new_timeout New timeout, in milliseconds.
+ *
+ * @return The previous timeout value, in milliseconds.
+ *
+ * @see ::mbgserio_get_dev_poll_timeout
+ * @see ::mbgserio_read_wait
+ */
+ ulong mbgserio_set_dev_poll_timeout( MBGSERIO_DEV *sdev, ulong new_timeout ) ;
+
+ /**
+ * @brief Wait for data and read from a serial port.
+ *
+ * @param[in,out] sdev Control structure of the device.
+ * @param[out] buffer Buffer to take the bytes read.
+ * @param[in] count Size of @p buffer.
+ *
+ * @return On Success, the (positive) number of byte read,
+ * or one of the (negative) @ref MBG_ERROR_CODES on error.
+ */
+ _NO_MBG_API_ATTR int _MBG_API mbgserio_read_wait( MBGSERIO_DEV *sdev, void *buffer, unsigned int count ) ;
+
+ /**
+ * @brief Compute the time required to transmit a number of bytes, in nanoseconds.
+ *
+ * Depends on the baud rate and the effective number of
+ * bits per byte, i.e. data / parity / stop bits.
+ * Assuming the transmission is without gaps.
+ *
+ * If 2 stobits are used, this differs from ::mbgserio_get_duration_rcv.
+ * See ::mbgserio_get_duration_rcv.
+ *
+ * @param[in] p_sp The relevant parameters of the transmission.
+ * @param[in] n_bytes The number of bytes to transmit.
+ *
+ * @return The the computed duration, in nanoseconds.
+ *
+ * @see ::mbgserio_get_duration_rcv
+ */
+ _NO_MBG_API_ATTR int32_t _MBG_API mbgserio_get_duration_xmt( MBGSERIO_SPEED_PARMS *p_sp, int n_bytes ) ;
+
+ /**
+ * @brief Compute the receive delay for a number of bytes, in nanoseconds.
+ *
+ * Depends on the baud rate and the effective number of
+ * bits per byte, i.e. data / parity / stop bits.
+ * Assuming the transmission is without gaps.
+ *
+ * Differs from ::mbgserio_get_duration_xmt in case there are
+ * 2 stop bits. This is because because UARTS usually flag
+ * reception of a byte after the first stop bit, even if
+ * 2 stop bits are used for transmission.
+ *
+ * @param[in] p_sp The relevant parameters of the transmission.
+ * @param[in] n_bytes The number of bytes to receive.
+ * @param[in] n_bits A number of additional bits to account for.
+ *
+ * @return The the computed duration, in nanoseconds.
+ *
+ * @see ::mbgserio_get_duration_xmt
+ */
+ _NO_MBG_API_ATTR int32_t _MBG_API mbgserio_get_duration_rcv( const MBGSERIO_SPEED_PARMS *p_sp, int n_bytes, int n_bits ) ;
+
+ /**
+ * @brief Set up a string list with names of available serial ports.
+ *
+ * @param[out] list Address of the header of a list to be set up.
+ * @param[in] max_devs Maximum number of list entries to create.
+ *
+ * @return The number of entries in the list.
+ *
+ * @see ::mbgserio_free_str_list
+ */
+ _NO_MBG_API_ATTR int _MBG_API mbgserio_setup_port_str_list( MBG_STR_LIST **list, int max_devs ) ;
+
+ /**
+ * @brief Free a string list that has been allocated before.
+ *
+ * @param[out] list Address of the string list to be freed.
+ *
+ * @see ::mbgserio_setup_port_str_list
+ */
+ _NO_MBG_API_ATTR void _MBG_API mbgserio_free_str_list( MBG_STR_LIST *list ) ;
+
/* ----- function prototypes end ----- */
diff --git a/mbglib/common/words.h b/mbglib/common/words.h
index 9f6f1a9..7d6c70e 100644
--- a/mbglib/common/words.h
+++ b/mbglib/common/words.h
@@ -1,7 +1,7 @@
/**************************************************************************
*
- * $Id: words.h 1.21 2009/10/01 14:00:17 martin REL_M $
+ * $Id: words.h 1.53 2021/11/29 14:22:49 martin.burnicki REL_M $
*
* Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
*
@@ -10,6 +10,90 @@
*
* -----------------------------------------------------------------------
* $Log: words.h $
+ * Revision 1.53 2021/11/29 14:22:49 martin.burnicki
+ * New macros _nano_time_64_from_timespec() and
+ * _nano_time_64_from_timeval().
+ * Revision 1.52 2021/03/18 11:08:31 martin
+ * Updated some comments.
+ * Revision 1.51 2021/03/16 12:20:31 martin
+ * Updated some comments.
+ * Revision 1.50 2021/03/12 10:48:34 martin
+ * Corrected the wording of a comment.
+ * Revision 1.49 2019/10/23 08:31:48 thomas-b
+ * Added struct name for NANO_TIME_64
+ * Revision 1.48 2019/06/17 08:38:59 thomas-b
+ * Renamed structs according to Meinberg naming convention
+ * Revision 1.47 2019/06/06 12:17:14 thomas-b
+ * Added several struct names to allow forward declaration
+ * Revision 1.46 2019/02/07 14:38:56 martin
+ * Removed a duplicate definition.
+ * Revision 1.45 2018/11/22 16:38:15 martin
+ * Removed inclusion of mbg_no_tgt.h which is obsolete here.
+ * Revision 1.44 2018/06/25 09:21:02 martin
+ * Support MBG_TGT_NO_TGT.
+ * Improved STRINGIFY() macro.
+ * Revision 1.43 2018/01/29 10:30:23 martin
+ * Modified some comments.
+ * Revision 1.42 2017/07/26 14:28:50Z martin
+ * Fixed build for NetBSD.
+ * Revision 1.41 2017/07/05 12:06:35 martin
+ * Moved macro _int_from_size_t() here.
+ * Revision 1.40 2017/06/12 11:14:25 martin
+ * Empty _DEPRECATED_BY definition for firmware targets.
+ * Revision 1.39 2017/03/15 10:01:09 martin
+ * Added comments how to represent negative numbers in NANO_TIME
+ * and NANO_TIME_64 structures.
+ * Added macros _nano_time_zero() and _nano_time_64_zero().
+ * Revision 1.38 2017/02/22 11:56:33 martin
+ * Made MBG_CODE_NAME_TABLE_ENTRY::code signed to
+ * avoid signed/unsigned warnings with some code tables.
+ * Revision 1.37 2017/01/27 12:24:35Z martin
+ * Moved STRINGIFY() macro here.
+ * Revision 1.36 2017/01/27 08:59:43 martin
+ * Fixed macro syntax.
+ * Revision 1.35 2016/08/05 12:17:21 martin
+ * Moved definitions for NANO_TIME and NANO_TIME_64 here.
+ * New macro _nano_time_64_negative().
+ * Conditionally define _abs64() macro.
+ * Include <inttypes.h> for Keil ARMCC target.
+ * Added some conditional debugging code.
+ * Fixed some spelling.
+ * Revision 1.34 2014/10/20 12:31:20 martin
+ * Moved macro _isdigit() here.
+ * Revision 1.33 2014/05/27 10:18:35Z martin
+ * Finer control of which types are required for or already
+ * available on particular target systems.
+ * Added macros helpful to simplify declarations of code/name tables.
+ * Revision 1.32 2014/01/07 15:43:52 martin
+ * Define __mbg_inline for ARM firmware targets.
+ * Revision 1.31 2012/11/29 11:54:39Z martin
+ * Removed #if sizeof() definitions which may cause build errors
+ * with some older compilers.
+ * Include stdbool.h for __ARMCC_VERSION targets.
+ * Moved _nop_macro_fnc() definition here.
+ * Revision 1.30 2012/11/02 09:12:29Z martin
+ * Moved most feature detection code to mbg_tgt.h.
+ * Tried to define missing features most flexibly and portably.
+ * Revision 1.29 2012/07/11 16:45:45Z martin
+ * New macros to access individual bytes of long constants.
+ * Revision 1.28 2012/04/05 14:36:18Z martin
+ * Support CVI 2010 compiler which provides C99 types.
+ * Revision 1.27 2011/07/18 10:21:38Z martin
+ * Added definition for MBG_CODE_NAME_TABLE_ENTRY which can
+ * be used to define tables assigning strings to numeric codes.
+ * Revision 1.26 2011/04/06 10:23:03 martin
+ * Added FBYTE_OF() and FWORD_OF() macros.
+ * Modifications required for *BSD.
+ * 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
@@ -69,24 +153,38 @@
#if !defined( _IS_MBG_FIRMWARE )
-#if defined( _C166 ) || \
- defined( _CC51 ) || \
- defined( __ARM )
- #define _IS_MBG_FIRMWARE 1
-#else
- #define _IS_MBG_FIRMWARE 0
-#endif
-
+ #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 <mbg_tgt.h>
+#else
+ #if defined( __ARMCC_VERSION ) // Keil RealView Compiler for ARM
+ #define __mbg_inline __inline
+ #include <stdint.h>
+ #include <inttypes.h>
+ #include <stdbool.h>
+ #define MBG_TGT_HAS_EXACT_SIZE_TYPES 1
+ #else
+ #define MBG_TGT_MISSING_64_BIT_TYPES 1
+ #endif
- typedef unsigned char bit;
+ #if !defined( _DEPRECATED_BY )
+ #define _DEPRECATED_BY( _s ) // empty definition
+ #endif
#endif
+
#ifdef _WORDS
#define _ext
#else
@@ -96,164 +194,285 @@
/* Start of header body */
+#if defined( _C166 ) \
+ || defined( _CC51 )
+ #define _BIT_DEFINED 1 // These compilers natively support the "bit" type.
+ #define USE_LONG_FOR_INT32 1
+#endif
+
+
+
+#if !defined( MBG_TGT_HAS_EXACT_SIZE_TYPES )
-// Check whether the target system supports C99 fixed-size types.
+ #if defined( MBG_TGT_HAS_INT_8_16_32 )
-#if defined( MBG_TGT_LINUX ) // any Linux target
+ // Define C99 exact size types using non-standard exact-size types.
+ typedef __int8 int8_t;
+ typedef unsigned __int8 uint8_t;
+
+ typedef __int16 int16_t;
+ typedef unsigned __int16 uint16_t;
+
+ typedef __int32 int32_t;
+ typedef unsigned __int32 uint32_t;
- #if defined( __KERNEL__ )
- #include <linux/types.h>
#else
- #include <stdint.h>
- #include <sys/types.h>
- #endif
- #define _C99_BIT_TYPES_DEFINED 1
+ // Assume a 16 or 32 bit compiler which doesn't
+ // support exact-size types.
-#elif defined( MBG_TGT_BSD )
+ typedef char int8_t;
+ typedef unsigned char uint8_t;
- #include <sys/types.h>
+ typedef short int16_t;
+ typedef unsigned short uint16_t;
- #define _C99_BIT_TYPES_DEFINED 1
+ // Using #if sizeof() to determine the size of a type may not
+ // be supported by all preprocessors, and may even result in
+ // build errors if used in a conditional preprocessor section,
+ // so we can't use this here without compatibility problems.
-#elif defined( MBG_TGT_QNX ) // QNX 4.x or QNX 6.x
+ #if defined( USE_LONG_FOR_INT32 )
+ typedef long int32_t;
+ typedef unsigned long uint32_t;
+ #elif defined( USE_INT_FOR_INT32 )
+ typedef int int32_t;
+ typedef unsigned int uint32_t;
+ #else
+ #error Need to define int32_t and uint32_t
+ #endif
- #if defined( MBG_TGT_QNX_NTO ) // QNX 6.x (Neutrino) with gcc
- #include <stdint.h>
- #else // QNX 4.x with Watcom C 10.6
- #include <sys/types.h> // 64 bit types not supported
#endif
- #define _C99_BIT_TYPES_DEFINED 1
+ #if defined( MBG_TGT_MISSING_64_BIT_TYPES )
+
+ // The build environment does not support 64 bit types. However,
+ // 64 bit types need to be defined to avoid build errors e.g.
+ // if these types are formally used in function prototypes.
+ // We explicitly 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;
+
+ #else
+
+ // Define C99 types using non-standard exact-size types
+ // which are usually supported by build environments that
+ // support 64 bit types but don't support C99 types.
+ typedef __int64 int64_t;
+ typedef unsigned __int64 uint64_t;
+
+ #endif
#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( MBG_TGT_MISSING_64_BIT_TYPES )
- #if defined( __WATCOMC__ )
- #if __WATCOMC__ > 1230 // Open Watcom C 1.3 and above
- #include <stdint.h>
- #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 MBG_TGT_HAS_64BIT_TYPES 0
- #define _C99_BIT_TYPES_DEFINED 1
- #endif
- #endif
+#else
- #if defined( __BORLANDC__ )
- #if ( __BORLANDC__ >= 0x570 ) // at least Borland Developer Studio 2006
- #define _C99_BIT_TYPES_DEFINED 1
- #endif
- #endif
+ #define MBG_TGT_HAS_64BIT_TYPES 1
- #if defined( __GNUC__ )
- #include <stdint.h>
- #define _C99_BIT_TYPES_DEFINED 1
+ #if !defined( MBG_TGT_HAS_ABS64 )
+ #define _abs64( _i ) ( (int64_t) ( ( (_i) < 0 ) ? -(_i) : (_i) ) )
#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 )
+// Some commonly used types
- #define MBG_TGT_HAS_64BIT_TYPES 1
+#if !defined( _UCHAR_DEFINED )
+ typedef unsigned char uchar;
+ #define uchar uchar
+#endif
-#else
+#if !defined( _USHORT_DEFINED )
+ typedef unsigned short ushort;
+ #define ushort ushort
+#endif
- typedef char int8_t;
- typedef unsigned char uint8_t;
+#if !defined( _UINT_DEFINED )
+ typedef unsigned int uint;
+ #define uint uint
+#endif
- typedef short int16_t;
- typedef unsigned short uint16_t;
+#if !defined( _ULONG_DEFINED )
+ typedef unsigned long ulong;
+ #define ulong ulong
+#endif
- typedef long int32_t;
- typedef unsigned long uint32_t;
+#if !defined( _UDOUBLE_DEFINED )
+ typedef double udouble;
+ #define udouble udouble
+#endif
+#if !defined( _BYTE_DEFINED )
+ typedef unsigned char byte;
+ #define byte byte
+#endif
- #if defined( MBG_TGT_WIN32 )
+#if !defined( _WORD_DEFINED )
+ typedef unsigned short word;
+ #define word word
+#endif
- typedef __int64 int64_t;
- typedef unsigned __int64 uint64_t;
+#if !defined( _LONGWORD_DEFINED )
+ typedef unsigned long longword;
+ #define longword longword
+#endif
- #define MBG_TGT_HAS_64BIT_TYPES 1
+#if !defined( _DWORD_DEFINED )
+// typedef unsigned long dword;
+// #define dword dword
+#endif
- #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
+#if defined( MBG_TGT_MISSING_BOOL_TYPE )
+ //#error MBG_TGT_MISSING_BOOL_TYPE is defined
+ // BDS/Borland C++ Builder 2006 (non-C++ mode)
+ // Borland C++ Builder 5 (non-C++ mode)
+ // BC 3.1
+ // VC6
+ // DDKbuild
+ // VS2008
#endif
+#if defined( __cplusplus )
+ //#error __cplusplus is defined
+#endif
+#if defined( __bool_true_false_are_defined )
+ //#error __bool_true_false_are_defined is defined
+ // Keil armcc
+ // gcc / Linux user space
+ // clang / FreeBSD user space and kernel
+#endif
-#if !defined( MBG_TGT_HAS_64BIT_TYPES )
- #define MBG_TGT_HAS_64BIT_TYPES 0
+#if defined( MBG_TGT_MISSING_BOOL_TYPE ) /* from mbg_tgt.h */ \
+ || ( !defined( __cplusplus ) /* C++ */ \
+ && !defined( __bool_true_false_are_defined ) /* C99 */ \
+ && !defined( _LINUX_TYPES_H ) ) /* Linux kernel */ \
+ && !( defined( MBG_TGT_NETBSD ) && defined( _SYS_TYPES_H_ ) ) /* NetBSD kernel */
-#endif
+ // There's no native support for a "bool" type, so we
+ // need a substitute.
+ #if defined( _BIT_DEFINED )
+ // A native "bit" type is supported, so we use it for bool.
+ //#error substituting bit for bool
+ // C166
+ typedef bit bool;
+ #else
+ // Fall back to "int". This is just a hack which
+ // may yield unexpected results with code like:
+ // return (bool) ( val & 0x10 );
+ // A safe way of coding would be:
+ // return (bool) ( ( val & 0x10 ) != 0 );
+ //#error substituting int for bool
+ // Borland C++ Builder 5
+ // BC 3.1
+ // VC6
+ // DDKbuild
+ // VS2008
+ typedef int bool;
+ #endif
+ // Try to provoke a build error if the build
+ // environment unexpectedly supports "bool" natively.
+ #define bool bool
+ #define true 1
+ #define false 0
+#else
+ //#error native bool type supported
+ // Borland C++ Builder 5 and newer (C++ mode only)
+ // Keil armcc
+ // gcc / Linux user space
+ // gcc / Linux kernel
+ // clang / FreeBSD user space and kernel
+#endif
-// Some commonly used types
-typedef unsigned char uchar;
+#if !defined( _BIT_DEFINED )
+
+ // There's no native support for a "bit" type, so we
+ // need a substitute. The "bool" type would fit best
+ // and should be fine if it's supported natively.
+ //
+ // However, if "bool" has been substituted above
+ // by "int", this is just a hack which may yield
+ // unexpected results with code like:
+ // return (bit) ( val & 0x10 );
+ // A safe way of coding would be:
+ // return (bit) ( ( val & 0x10 ) != 0 );
+
+ //#error substituting bool for bit
+ // Keil armcc
+ // Borland C++ Builder 5
+ // BC 3.1
+ // VC6
+ // DDKbuild
+ // VS2008
+ // gcc / Linux user space
+ // gcc / Linux kernel
+ // clang / FreeBSD user space and kernel
+ typedef bool bit;
+
+ // Try to provoke a build error if the build
+ // environment unexpectedly supports "bit" natively.
+ #define bit bit
+
+ #define _BIT_REDEFINED 1
-#if !defined( MBG_TGT_LINUX ) || !defined( __USE_MISC )
- // The glibc headers define the types below if __USE_MISC is
- // defined, otherwise we need to define them here.
- typedef unsigned short ushort;
- typedef unsigned int uint;
- typedef unsigned long ulong;
+#else
+ //#error native bit type supported
+ // C166
#endif
-typedef double udouble;
-typedef unsigned char byte;
-typedef unsigned short word;
-typedef unsigned long longword;
-typedef unsigned long dword;
+#define BYTE_0( _x ) ( (uint8_t ) ( (_x) & 0xFF ) )
+#define BYTE_1( _x ) ( (uint8_t ) ( ( ( (uint16_t) (_x) ) >> 8 ) & 0xFF ) )
+#define BYTE_2( _x ) ( (uint8_t ) ( ( ( (uint32_t) (_x) ) >> 16 ) & 0xFF ) )
+#define BYTE_3( _x ) ( (uint8_t ) ( ( ( (uint32_t) (_x) ) >> 24 ) & 0xFF ) )
+
+
+#define HI_BYTE( _x ) ( (uint8_t ) ( (_x) >> 8 ) )
+#define LO_BYTE( _x ) ( (uint8_t ) ( (_x) & 0xFF ) )
-#define HI_BYTE( _x ) ( (_x) >> 8 )
-#define LO_BYTE( _x ) ( (_x) & 0xFF )
+#define HI_WORD( _x ) ( (uint16_t ) ( (_x) >> 16 ) )
+#define LO_WORD( _x ) ( (uint16_t ) ( (_x) & 0xFFFF ) )
-#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
+// 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 FBYTE_OF( _v, _n ) *( ( (uint8_t far *) &(_v) ) + (_n) )
+#define FWORD_OF( _v, _n ) *( ( (uint16_t far *) &(_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
+// 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
+// A macro to swap the byte order of a 32 bit value.
#define _bswap32( _x ) \
( \
( ( ( (uint32_t) (_x) ) & 0x000000FFUL ) << 24 ) | \
@@ -262,7 +481,7 @@ typedef unsigned long dword;
( ( ( (uint32_t) (_x) ) & 0xFF000000UL ) >> 24 ) \
)
-// a macro to swap the word order of a 32 bit value
+// A macro to swap the word order of a 32 bit value.
#define _wswap32( _x ) \
( \
( ( ( (uint32_t) (_x) ) & 0x0000FFFFUL ) << 16 ) | \
@@ -273,7 +492,7 @@ typedef unsigned long dword;
#define _var_bswap32( _v ) (_v) = _bswap32( _v )
-// The C51 compiler is big-endian, that means the most
+// The C51 compiler is big-endian, this 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
@@ -287,6 +506,232 @@ typedef unsigned long dword;
#define _hilo_32( _x ) (_x)
#endif
+
+
+#define _set_array_bit( _n, _byte_array, _max_bytes ) \
+do \
+{ \
+ int byte_idx = (_n) >> 3; \
+ \
+ if ( byte_idx < _max_bytes ) \
+ _byte_array[byte_idx] |= ( 1 << ( (_n) & 0x07 ) ); \
+ \
+} while ( 0 )
+
+
+#define _clear_array_bit( _n, _byte_array, _max_bytes ) \
+do \
+{ \
+ int byte_idx = (_n) >> 3; \
+ \
+ if ( byte_idx < _max_bytes ) \
+ _byte_array[byte_idx] &= ~( 1 << ( (_n) & 0x07 ) ); \
+ \
+} while ( 0 )
+
+
+
+#define _isdigit( _c ) ( (_c) >= '0' && (_c) <= '9' )
+
+
+// A macro function which can safely be used without
+// side effects as a macro doing nothing.
+// This is useful to define debug macros away in
+// release builds, etc.
+#if !defined( _nop_macro_fnc )
+ #define _nop_macro_fnc() do {} while (0)
+#endif
+
+
+/**
+ * @brief A table entry which can be used to map codes to names.
+ */
+typedef struct
+{
+ long code;
+ const char *name;
+
+} MBG_CODE_NAME_TABLE_ENTRY;
+
+/**
+ * @brief A macro defining a ::MBG_CODE_NAME_TABLE_ENTRY.
+ *
+ * The stringified parameter is used for the name.
+ *
+ * @param[in] _n The symbolic name of the numeric code.
+ */
+#define _mbg_cn_table_entry( _n ) { _n, #_n }
+
+/**
+ * @brief A macro defining an empty ::MBG_CODE_NAME_TABLE_ENTRY.
+ *
+ * This is used to terminate a table.
+ */
+#define _mbg_cn_table_end() { 0, NULL }
+
+
+
+/**
+ * @brief A timestamp with nanosecond resolution.
+ *
+ * @note If the structure is to represent a negative value, both the
+ * fields @p nano_secs and @p secs have to be set to the negative values.
+ * Otherwise the sign of the represented number was ambiguous if either
+ * of the fields was 0 by accident, and only the other field was not 0.
+ * The macro ::_nano_time_negative should always be used to determine
+ * if the sign of the represented value is negative, or not.
+ *
+ * @note The @p secs field will roll over on 2038-01-19 03:14:07
+ * if used for the number of seconds since 1970-01-01, just like
+ * 32 bit POSIX @a time_t.
+ *
+ * @see ::_nano_time_negative
+ * @see ::_nano_time_zero
+ * @see ::NANO_TIME_64
+ */
+typedef struct nano_time_s
+{
+ // ATTENTION:
+ // This structure is and has been used in public API calls for a long time,
+ // so even though the order of member fields is different than in NANO_TIME_64
+ // this must *NOT* be changed, or API compatibility will get lost!
+ int32_t nano_secs; ///< [nanoseconds].
+ int32_t secs; ///< [seconds], usually since 1970-01-01 00:00:00.
+
+} NANO_TIME;
+
+#define _mbg_swab_nano_time( _p ) \
+do \
+{ \
+ _mbg_swab32( &(_p)->nano_secs ); \
+ _mbg_swab32( &(_p)->secs ); \
+} while ( 0 )
+
+/**
+ * @brief Check if the value of the ::NANO_TIME structure _nt is negative.
+ */
+#define _nano_time_negative( _nt ) \
+ ( ( (_nt)->secs < 0 ) || ( (_nt)->nano_secs < 0 ) )
+
+/**
+ * @brief Check if the value of the ::NANO_TIME structure _nt is 0.
+ */
+#define _nano_time_zero( _nt ) \
+ ( ( (_nt)->secs == 0 ) && ( (_nt)->nano_secs == 0 ) )
+
+
+
+/**
+ * @brief A timestamp with nanosecond resolution, but 64 bit size.
+ *
+ * @note If the structure is to represent a negative value, both the
+ * fields @p nano_secs and @p secs have to be set to the negative values.
+ * Otherwise the sign of the represented number was ambiguous if either
+ * of the fields was 0 by accident, and only the other field was not 0.
+ * The macro ::_nano_time_64_negative should always be used to determine
+ * if the sign of the represented value is negative, or not.
+ *
+ * @see ::_nano_time_64_negative
+ * @see ::_nano_time_64_zero
+ * @see ::NANO_TIME
+ */
+typedef struct nano_time_64_s
+{
+ // ATTENTION:
+ // This structure is and has been used in public API calls for a long time,
+ // so even though the order of member fields is different than in ::NANO_TIME,
+ // this must *NOT* be changed, or API compatibility will get lost!
+ int64_t secs; ///< [seconds], usually since 1970-01-01 00:00:00.
+ int64_t nano_secs; ///< [nanoseconds].
+
+} NANO_TIME_64;
+
+#define _mbg_swab_nano_time_64( _p ) \
+do \
+{ \
+ _mbg_swab64( &(_p)->secs ); \
+ _mbg_swab64( &(_p)->nano_secs ); \
+} while ( 0 )
+
+/**
+ * @brief Check if the value of the ::NANO_TIME_64 structure _nt is negative.
+ */
+#define _nano_time_64_negative( _nt ) \
+ ( ( (_nt)->secs < 0 ) || ( (_nt)->nano_secs < 0 ) )
+
+/**
+ * @brief Check if the value of the ::NANO_TIME_64 structure _nt is 0.
+ */
+#define _nano_time_64_zero( _nt ) \
+ ( ( (_nt)->secs == 0 ) && ( (_nt)->nano_secs == 0 ) )
+
+
+/**
+ * @brief Set up a ::NANO_TIME_64 structure from struct timespec.
+ */
+#define _nano_time_64_from_timespec( _p, _p_ts ) \
+do \
+{ \
+ (_p)->secs = (_p_ts)->tv_sec; \
+ (_p)->nano_secs = (_p_ts)->tv_nsec; \
+} while ( 0 )
+
+/**
+ * @brief Set up a ::NANO_TIME_64 structure from struct timeval.
+ */
+#define _nano_time_64_from_timeval( _p, _p_ts ) \
+do \
+{ \
+ (_p)->secs = (_p_ts)->tv_sec; \
+ (_p)->nano_secs = (_p_ts)->tv_usec * 1000; \
+} while ( 0 )
+
+
+// The size_t type may be larger than an int type.
+// However, some snprintf-like functions expect a size_t value
+// to specify the buffer size, but just return an int value.
+// So we take care that at least the return value is limited
+// to MAXINT.
+#if defined( MBG_TGT_WIN32 )
+ #define _int_from_size_t( _n ) \
+ ( ( (_n) > INT_MAX ) ? INT_MAX : (int) (_n) )
+#else
+ #define _int_from_size_t( _n ) (_n)
+#endif
+
+
+
+/**
+ * @brief A helper macro to implement ::STRINGIFY correctly.
+ *
+ * This just a helper macro which must be defined before
+ * ::STRINGIFY to work correctly, and should not be used alone.
+ *
+ * @see ::STRINGIFY
+ */
+#define XSTRINGIFY(x) #x
+
+
+/**
+ * @brief Make a string from a constant definition.
+ *
+ * This macro can be used e.g. to define a constant string on the
+ * compiler's command line, e.g. like -DVERSION_STRING="v1.0 BETA".
+ * Source code like
+ * @code{.c}
+ const char version_string[] = VERSION_STRING;
+ * @endcode
+ *
+ * may not work for every compiler since the double quotes
+ * in VERSION_STRING may be removed when the definition is evaluated.
+ * A proper solution is to use the STRINGIFY() macro defined here:
+ * @code{.c}
+ const char version_string[] = STRINGIFY( VERSION_STRING );
+ * @endcode
+ */
+#define STRINGIFY(x) XSTRINGIFY(x)
+
+
/* End of header body */
#undef _ext