summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Burnicki <martin.burnicki@meinberg.de>2009-10-09 12:00:00 +0200
committerMartin Burnicki <martin.burnicki@meinberg.de>2009-10-09 12:00:00 +0200
commitb73cfc31e68b854f3f7dbf8837168c1c7b6eb31b (patch)
tree1ae873ad91f4cc93247e78797ac0a37f2d9f69b3
downloadmbgreadtimestring-b73cfc31e68b854f3f7dbf8837168c1c7b6eb31b.tar.gz
mbgreadtimestring-b73cfc31e68b854f3f7dbf8837168c1c7b6eb31b.zip
Initial version1.1
-rw-r--r--mbglib/common/mbg_tgt.h406
-rw-r--r--mbglib/common/mbg_tmo.h312
-rw-r--r--mbglib/common/mbgserio.c960
-rw-r--r--mbglib/common/mbgserio.h213
-rw-r--r--mbglib/common/words.h294
-rw-r--r--mbgreadtimestring.c343
-rw-r--r--unix/Makefile55
7 files changed, 2583 insertions, 0 deletions
diff --git a/mbglib/common/mbg_tgt.h b/mbglib/common/mbg_tgt.h
new file mode 100644
index 0000000..d5aba94
--- /dev/null
+++ b/mbglib/common/mbg_tgt.h
@@ -0,0 +1,406 @@
+
+/**************************************************************************
+ *
+ * $Id: mbg_tgt.h 1.22 2009/10/01 08:20:50 martin REL_M $
+ *
+ * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
+ *
+ * Description:
+ * Check the build environment and setup control definitions
+ * for the Meinberg library modules.
+ *
+ * -----------------------------------------------------------------------
+ * $Log: mbg_tgt.h $
+ * Revision 1.22 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
+ * Don't define __mbg_inline for CVI and undefined targets.
+ * Revision 1.20 2009/08/18 15:14:26 martin
+ * Defined default MBG_INVALID_PORT_HANDLE for non-Windows targets.
+ * Revision 1.19 2009/06/09 10:03:58 daniel
+ * Preliminary support for ARM architecture.
+ * Revision 1.18 2009/04/01 14:10:55 martin
+ * Cleanup for CVI.
+ * Revision 1.17 2009/03/19 15:21:07Z martin
+ * Conditionally define DWORD_PTR type for old MS C compilers.
+ * Revision 1.16 2008/12/08 16:42:30 martin
+ * Defined _GNU_SOURCE for Linux.
+ * Revision 1.15 2008/11/19 15:31:49 martin
+ * Added symbol MBG_ARCH_I386.
+ * Revision 1.14 2008/09/03 15:06:04 martin
+ * Support DOS protected mode target.
+ * Support SUN SPARC architecture.
+ * Specified handle types for common host environments.
+ * Added macro MBG_USE_MM_IO_FOR_PCI.
+ * Added macro _nop_macro_fnc().
+ * Revision 1.13 2008/01/30 15:52:22 martin
+ * Modified checking for availability of wchar_t.
+ * Revision 1.13 2008/01/29 15:18:07Z martin
+ * Recognize DOS target under Watcom compilers.
+ * Flag Watcom C always supports wchar_t.
+ * Revision 1.12 2008/01/17 09:38:50Z daniel
+ * Added macros to determine whether C language extensions
+ * (e.g. C94, C99) are supported by the target environment.
+ * Added macro to check whether wchar_t and friends are
+ * supported, and some compatibility stuff.
+ * Revision 1.11 2007/10/31 16:58:03 martin
+ * Fixed __mbg_inline for Borland C (DOS).
+ * Revision 1.10 2007/09/25 08:10:27Z martin
+ * Support CVI target environment.
+ * Added MBG_PORT_HANDLE type for serial ports.
+ * Added macros for unified inline code syntax.
+ * Revision 1.9 2006/12/08 12:45:54Z martin
+ * Under Windows include ntddk.h rather than windows.h
+ * if building kernel driver .
+ * Revision 1.8 2006/10/25 12:20:45Z martin
+ * Initial support for FreeBSD, NetBSD, and OpenBSD.
+ * Added definitions for generic handle types.
+ * Revision 1.7 2006/08/23 13:43:55 martin
+ * Added definition for MBG_TGT_UNIX.
+ * Minor syntax fixes.
+ * Revision 1.6 2006/01/25 14:37:06 martin
+ * Added definitions for 64 bit Windows environments.
+ * Revision 1.5 2003/12/17 16:11:41Z martin
+ * Split API modifiers into _MBG_API and _MBG_API_ATTR.
+ * Revision 1.4 2003/06/19 08:20:22Z martin
+ * Added WINAPI attribute for DLL exported functions.
+ * Revision 1.3 2003/04/09 13:37:20Z martin
+ * Added definition for _MBG_API.
+ * Revision 1.2 2003/02/24 16:08:45Z martin
+ * Don't setup for Win32 PNP if explicitely configured non-PNP.
+ * Revision 1.1 2002/02/19 13:46:20Z MARTIN
+ * Initial revision
+ *
+ **************************************************************************/
+
+#ifndef _MBG_TGT_H
+#define _MBG_TGT_H
+
+
+/* Other headers to be included */
+
+#include <stddef.h>
+
+#ifdef _MBG_TGT
+ #define _ext
+#else
+ #define _ext extern
+#endif
+
+
+/* Start of header body */
+
+#if defined( _CVI ) || defined( _CVI_ )
+
+ #define MBG_TGT_WIN32
+ #define MBG_TGT_CVI
+
+#elif defined( _WIN32_WINNT )
+
+ // MS platform SDK
+ // WinNT 4.0 and above
+ #define MBG_TGT_WIN32
+
+ #if ( _WIN32_WINNT >= 0x0500 )
+ // Win2k and above
+ #if !defined( MBG_TGT_WIN32_NON_PNP )
+ // only if not explicitely disabled
+ #define MBG_TGT_WIN32_PNP
+ #endif
+ #endif
+
+#elif defined( WINVER )
+
+ // MS platform SDK
+ // Win95, WinNT 4.0 and above
+ #define MBG_TGT_WIN32
+
+ #if ( WINVER >= 0x0500 )
+ // Win98, Win2k and above
+ // #define ...
+ #endif
+
+#elif defined( __WIN32__ )
+
+ // Borland C++ Builder
+ #define MBG_TGT_WIN32
+
+#elif defined( _WIN32 )
+
+ // MS Visual C++
+ #define MBG_TGT_WIN32
+
+#elif defined( __WINDOWS_386__ )
+
+ // Watcom C/C++ for target Win32
+ #define MBG_TGT_WIN32
+
+#elif defined( __NETWARE_386__ )
+
+ // Watcom C/C++ for target NetWare
+ #define MBG_TGT_NETWARE
+
+#elif defined( __OS2__ )
+
+ // Watcom C/C++ for target OS/2
+ #define MBG_TGT_OS2
+
+#elif defined( __linux )
+
+ // GCC for target Linux
+ #define MBG_TGT_LINUX
+ #define _GNU_SOURCE 1
+
+#elif defined( __FreeBSD__ )
+
+ // GCC for target FreeBSD
+ #define MBG_TGT_FREEBSD
+
+#elif defined( __NetBSD__ )
+
+ // GCC for target NetBSD
+ #define MBG_TGT_NETBSD
+
+#elif defined( __OpenBSD__ )
+
+ // GCC for target FreeBSD
+ #define MBG_TGT_OPENBSD
+
+#elif defined( __QNX__ )
+
+ // any compiler for target QNX
+ #define MBG_TGT_QNX
+
+ #if defined( __QNXNTO__ )
+ // target QNX Neutrino
+ #define MBG_TGT_QNX_NTO
+ #endif
+
+#elif defined( __MSDOS__ ) || defined( __DOS__ )
+
+ // any compiler for target DOS
+ #define MBG_TGT_DOS
+
+ #if defined( __WATCOMC__ ) && defined( __386__ )
+
+ #define MBG_TGT_DOS_PM // protected mode DOS
+
+ #endif
+
+#endif
+
+// Some definitions which depend on the type of compiler ...
+
+#if defined( __GNUC__ )
+
+ #define __mbg_inline __inline__
+
+ #define MBG_TGT_HAS_WCHAR_T defined( MBG_TGT_WIN32 )
+
+ #if defined( __sparc__ )
+
+ #define MBG_ARCH_SPARC
+ #define _MBG_ARCH_DEFINED
+
+ #elif defined( __arm__ )
+
+ #define MBG_ARCH_ARM
+ #define _MBG_ARCH_DEFINED
+
+ #endif
+
+#elif defined( _MSC_VER )
+
+ #define __mbg_inline __forceinline
+
+ #define MBG_TGT_HAS_WCHAR_T 1
+
+#elif defined( _CVI ) || defined( _CVI_ )
+
+ // Inline code is not supported.
+
+ #define MBG_TGT_HAS_WCHAR_T 0
+
+#elif defined( __BORLANDC__ )
+
+ #if defined( __cplusplus )
+ #define __mbg_inline inline // standard C++ syntax
+ #elif ( __BORLANDC__ > 0x410 ) // BC3.1 defines 0x410 !
+ #define __mbg_inline __inline // newer BC versions support this for C
+ #else
+ #define __mbg_inline // up to BC3.1 not supported for C
+ #endif
+
+ #define MBG_TGT_HAS_WCHAR_T defined( MBG_TGT_WIN32 )
+
+#elif defined( __WATCOMC__ )
+
+ #define __mbg_inline _inline
+
+ #define MBG_TGT_HAS_WCHAR_T defined( MBG_TGT_WIN32 )
+
+#endif
+
+
+
+// Currently we support only Sparc and i386/x86_64 architectures,
+// so unless we have explicitely found sparc we assume i386.
+
+#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
+#endif
+
+#if defined( MBG_TGT_LINUX ) \
+ || defined( MBG_TGT_BSD ) \
+ || defined( MBG_TGT_QNX_NTO )
+ #define MBG_TGT_UNIX
+#endif
+
+
+
+#if defined( MBG_TGT_WIN32 )
+
+ #if defined( _AMD64_ )
+ // This is used for AMD64 architecture and for
+ // Intel XEON CPUs with 64 bit extension.
+ #define MBG_TGT_WIN32_PNP_X64
+ #define WIN32_FLAVOR "x64"
+ #elif defined( _IA64_ )
+ #define MBG_TGT_WIN32_PNP_IA64
+ #define WIN32_FLAVOR "ia64"
+ #endif
+
+ #if defined( _KDD_ )
+ #include <ntddk.h>
+ #else
+ // This must not be used for kernel drivers.
+ #include <windows.h>
+ typedef HANDLE MBG_HANDLE;
+
+ #define MBG_INVALID_HANDLE INVALID_HANDLE_VALUE
+
+ #if defined( MBG_TGT_CVI )
+ // CVI uses an own set of functions to support serial ports
+ typedef int MBG_PORT_HANDLE;
+ #define MBG_INVALID_PORT_HANDLE -1
+ #else
+ typedef HANDLE MBG_PORT_HANDLE;
+ #endif
+
+ // The DWORD_PTR type is not defined in the headers shipping
+ // with VC6. However, if the SDK is installed then the SDK's
+ // headers may declare this type. This is at least the case
+ // in the Oct 2001 SDK which also defines the symbol _W64.
+ #if !defined( _W64 )
+ typedef DWORD DWORD_PTR;
+ #endif
+
+ #endif
+
+ #define _MBG_API WINAPI
+
+ #if defined( MBG_LIB_EXPORT )
+ #define _MBG_API_ATTR __declspec( dllexport )
+ #else
+ #define _MBG_API_ATTR __declspec( dllimport )
+ #endif
+
+#elif defined( MBG_TGT_UNIX )
+
+ typedef int MBG_HANDLE;
+ typedef int MBG_PORT_HANDLE;
+
+ #define MBG_INVALID_HANDLE -1
+
+#else
+
+ typedef int MBG_HANDLE;
+ typedef int MBG_PORT_HANDLE;
+
+ #define MBG_INVALID_HANDLE -1
+
+#endif
+
+
+#if !defined( _MBG_API )
+ #define _MBG_API
+#endif
+
+#if !defined( _MBG_API_ATTR )
+ #define _MBG_API_ATTR
+#endif
+
+#if !defined( MBG_INVALID_PORT_HANDLE )
+ #define MBG_INVALID_PORT_HANDLE MBG_INVALID_HANDLE
+#endif
+
+#if !defined( MBG_USE_MM_IO_FOR_PCI )
+ #if ( 0 || defined( MBG_ARCH_SPARC ) )
+ #define MBG_USE_MM_IO_FOR_PCI 1
+ #else
+ #define MBG_USE_MM_IO_FOR_PCI 0
+ #endif
+#endif
+
+
+#if !defined( _nop_macro_fnc )
+ #define _nop_macro_fnc() do {} while (0)
+#endif
+
+
+// The macros below are defined in order to be able to check if
+// certain C language extensions are available on the target system:
+#define MBG_TGT_C94 ( defined( __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199409L ) )
+#define MBG_TGT_C99 ( defined( __STDC_VERSION__ ) && ( __STDC_VERSION__ >= 199901L ) )
+
+// Check if wchar_t is supported
+#if !defined( MBG_TGT_HAS_WCHAR_T )
+ #define MBG_TGT_HAS_WCHAR_T ( MBG_TGT_C94 || defined( WCHAR_MAX ) )
+#endif
+
+#if !MBG_TGT_HAS_WCHAR_T
+ // Even if wchar_t is not natively supported by the target platform
+ // there may already be a compatibility define (e.g. BC3.1)
+ // However, some functions may be missing (e.g. snwprintf()).
+ #if !defined( _WCHAR_T ) /* BC3.1 */ \
+ && !defined( _WCHAR_T_DEFINED_ ) /* WC11 */
+ //##++ #define _WCHAR_T
+ #define wchar_t char
+ #endif
+#endif
+
+
+
+/* End of header body */
+
+#undef _ext
+
+
+/* function prototypes: */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ----- function prototypes begin ----- */
+
+/* This section was generated automatically */
+/* by MAKEHDR, do not remove the comments. */
+
+/* (no header definitions found) */
+
+/* ----- function prototypes end ----- */
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MBG_TGT_H */
diff --git a/mbglib/common/mbg_tmo.h b/mbglib/common/mbg_tmo.h
new file mode 100644
index 0000000..daf4a25
--- /dev/null
+++ b/mbglib/common/mbg_tmo.h
@@ -0,0 +1,312 @@
+
+/**************************************************************************
+ *
+ * $Id: mbg_tmo.h 1.2 2009/09/01 10:38:21 martin REL_M $
+ *
+ * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
+ *
+ * Description:
+ * Inline functions for portable timeout handling.
+ *
+ * -----------------------------------------------------------------------
+ * $Log: mbg_tmo.h $
+ * Revision 1.2 2009/09/01 10:38:21 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.
+ *
+ **************************************************************************/
+
+#ifndef _MBG_TMO_H
+#define _MBG_TMO_H
+
+
+/* Other headers to be included */
+
+#include <mbg_tgt.h>
+#include <words.h>
+
+#ifdef _MBG_TMO
+ #define _ext
+ #define _DO_INIT
+#else
+ #define _ext extern
+#endif
+
+
+/* Start of header body */
+
+#if defined( MBG_TGT_UNIX )
+
+ #include <sys/time.h>
+
+ typedef struct timeval MBG_TMO_TIME;
+
+#elif defined( MBG_TGT_WIN32 )
+
+ typedef union
+ {
+ FILETIME ft;
+ uint64_t u64;
+
+ } MBG_TMO_TIME;
+
+#else // DOS, ...
+
+ #include <time.h>
+
+ #define MBG_TMO_TIME clock_t
+
+#endif
+
+
+
+#if defined( __mbg_inline )
+
+static __mbg_inline
+void mbg_tmo_get_time( MBG_TMO_TIME *t )
+{
+ #if defined( MBG_TGT_UNIX )
+
+ gettimeofday( t, NULL );
+
+ #elif defined( MBG_TGT_WIN32 )
+
+ GetSystemTimeAsFileTime( &t->ft );
+
+ #else // DOS, ...
+
+ *t = clock();
+
+ #endif
+
+} // mbg_tmo_get_time
+
+#elif defined( MBG_TGT_CVI )
+
+ #define mbg_tmo_get_time( _t ) \
+ GetSystemTimeAsFileTime( &(_t)->ft )
+
+#else // DOS, ...
+
+ #define mbg_tmo_get_time( _t ) \
+ *(_t) = clock();
+
+#endif
+
+
+#if defined( __mbg_inline )
+
+static __mbg_inline
+int mbg_tmo_time_is_set( const MBG_TMO_TIME *t )
+{
+ #if defined( MBG_TGT_UNIX )
+
+ return ( t->tv_sec != 0 ) || ( t->tv_usec != 0 );
+
+ #elif defined( MBG_TGT_WIN32 )
+
+ return ( t->u64 != 0 );
+
+ #else // DOS, ...
+
+ return ( *t != 0 );
+
+ #endif
+
+} // mbg_tmo_time_is_set
+
+#elif defined( MBG_TGT_CVI )
+
+ #define mbg_tmo_time_is_set( _t ) \
+ ( (_t)->u64 != 0 )
+
+#else // DOS, ...
+
+ #define mbg_tmo_time_is_set( _t ) \
+ ( *(_t) != 0 )
+
+#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 );
+
+ #if defined( MBG_TGT_UNIX )
+
+ t_tmo->tv_usec += msec * 1000;
+
+ while ( t_tmo->tv_usec > 1000000UL )
+ {
+ t_tmo->tv_usec -= 1000000UL;
+ t_tmo->tv_sec++;
+ }
+
+ #elif defined( MBG_TGT_WIN32 )
+
+ t_tmo->u64 += ( (uint64_t) msec ) * 10000;
+
+ #else // DOS, ...
+
+ *t_tmo += (clock_t) ( ( (double) msec * CLOCKS_PER_SEC ) / 1000 );
+
+ #endif
+
+} // mbg_tmo_set_timeout
+
+#elif defined( MBG_TGT_CVI )
+
+ #define mbg_tmo_set_timeout_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) ); \
+ *(_t) += (clock_t) ( ( (double) (_msec) * CLOCKS_PER_SEC ) / 1000 );
+#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 )
+
+ return ( t->tv_sec - t0->tv_sec ) * 1000
+ + ( t->tv_usec - t0->tv_usec ) / 1000;
+
+ #elif defined( MBG_TGT_WIN32 )
+
+ return (long) ( ( t->u64 - t0->u64 ) / 10000 );
+
+ #else // DOS, ...
+
+ return (long) ( (double) ( ( *t - *t0 ) * 1000 ) / CLOCKS_PER_SEC );
+
+ #endif
+
+} // mbg_tmo_time_diff_ms
+
+#elif defined( MBG_TGT_CVI )
+
+ #define mbg_tmo_time_diff_ms( _t, _t0 ) \
+ (long) ( ( (_t)->u64 - (_t0)->u64 ) / 10000 )
+
+#else // DOS, ...
+
+ #define mbg_tmo_time_diff_ms( _t, _t0 ) \
+ (long) ( (double) ( ( *(_t) - *(_t0) ) * 1000 ) / 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 )
+
+ return ( ( t_now->tv_sec > tmo->tv_sec ) ||
+ ( ( t_now->tv_sec == tmo->tv_sec ) && ( t_now->tv_usec > tmo->tv_usec ) ) );
+
+ #elif defined( MBG_TGT_WIN32 )
+
+ return ( t_now->u64 > tmo->u64 );
+
+ #else // DOS, ...
+
+ return ( *t_now > *tmo );
+
+ #endif
+
+} // mbg_tmo_time_is_after
+
+#elif defined( MBG_TGT_CVI )
+
+ #define mbg_tmo_time_is_after( _t, _tmo ) \
+ ( (_t)->u64 > (_tmo)->u64 )
+
+#else // DOS, ...
+
+ #define mbg_tmo_time_is_after( _t, _tmo ) \
+ ( *(_t) > *(_tmo) )
+
+#endif
+
+
+#if defined( __mbg_inline )
+
+static __mbg_inline
+int mbg_tmo_curr_time_is_after( const MBG_TMO_TIME *tmo )
+{
+ MBG_TMO_TIME t_now;
+
+ mbg_tmo_get_time( &t_now );
+
+ return mbg_tmo_time_is_after( &t_now, tmo );
+
+} // mbg_tmo_curr_time_is_after
+
+#else
+
+ // needs to be implemented as non-inline function in mbg_tmo.c
+ int mbg_tmo_curr_time_is_after( const MBG_TMO_TIME *tmo );
+
+#endif
+
+
+
+// The function below can be used to set up a timeout for select().
+
+// check for CVI first since this is a special case of WIN32
+#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 );
+
+#elif defined( MBG_TGT_UNIX ) || defined( MBG_TGT_WIN32 )
+
+static __mbg_inline
+void mbgserio_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 )
+
+
+/* function prototypes: */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ----- function prototypes begin ----- */
+
+/* This section was generated automatically */
+/* by MAKEHDR, do not remove the comments. */
+
+/* (no header definitions found) */
+
+/* ----- function prototypes end ----- */
+
+#ifdef __cplusplus
+}
+#endif
+
+/* End of header body */
+
+#undef _ext
+#undef _DO_INIT
+
+#endif /* _MBG_TMO_H */
diff --git a/mbglib/common/mbgserio.c b/mbglib/common/mbgserio.c
new file mode 100644
index 0000000..23005b7
--- /dev/null
+++ b/mbglib/common/mbgserio.c
@@ -0,0 +1,960 @@
+
+/**************************************************************************
+ *
+ * $Id: mbgserio.c 1.3 2009/09/01 10:49:30 martin REL_M $
+ *
+ * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
+ *
+ * Description:
+ * Meinberg serial I/O functions.
+ *
+ * -----------------------------------------------------------------------
+ * $Log: mbgserio.c $
+ * Revision 1.3 2009/09/01 10:49:30 martin
+ * Cleanup for CVI.
+ * Use new portable timeout functions from mbg_tmo.h.
+ * Timeouts are now specified in milliseconds.
+ * Set DOS/v24tools low level receive timeout to minimum on open.
+ * Let functions return predefined codes.
+ * Revision 1.2 2008/09/04 15:34:18Z martin
+ * Moved support for different target environments from other files here.
+ * Added mbgserio_set_parms() and don't set parms when opening a port.
+ * Fixed bugs in timeout calculations in mbgserio_read_wait().
+ * Preliminary support for port device lists.
+ * Revision 1.1 2007/11/12 16:48:02 martin
+ * Initial revision.
+ *
+ **************************************************************************/
+
+#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 <stdio.h>
+#include <ctype.h>
+#include <time.h>
+
+#if defined( MBG_TGT_UNIX )
+ #include <unistd.h>
+ #include <fcntl.h>
+#endif
+
+
+
+#if defined( _USE_V24TOOLS )
+
+/*------------------------------------------------------------------------
+ * 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.
+ *-----------------------------------------------------------------------*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int v24open( char *portname, int mode );
+/* Open a port with specified name (e.g. "COM1"). The functions return a
+ * handle to be used with the other functions. If the handle is < 0, the
+ * 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 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 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.
+ */
+
+int v24putc( int port, char c );
+/* Write a character to the port.
+ */
+
+int v24close( int port );
+/* Close the port
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // defined( _USE_V24TOOLS )
+
+/*------------------------------------------------------------------------*/
+
+
+
+/*HDR*/
+_MBG_API_ATTR int _MBG_API mbgserio_open( SERIAL_IO_STATUS *pst, const char *dev )
+{
+ MBG_PORT_HANDLE port_handle;
+
+ #if defined( MBG_TGT_CVI )
+ {
+ int data_bits = 8; //##++
+ int parity_code = 0;
+ int baud_rate = 19200;
+ int stop_bits = 1;
+ int i;
+ int len;
+ int rc;
+
+ // 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 );
+
+ for ( i = 0; i < len; i++ )
+ {
+ char c = dev[i];
+ if ( c >= '0' && c <= '9' )
+ break;
+ }
+
+ if ( i == len )
+ return MBGSERIO_INV_CFG; // no numeric substring found
+
+
+ port_handle = atoi( &dev[i] );
+
+ 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 = "\\\\.\\";
+
+ COMMTIMEOUTS commtimeouts;
+ int len = strlen( prefix ) + strlen( dev ) + 1;
+ char *tmp_name = (char *) malloc( len );
+
+ if ( tmp_name == NULL ) // unable to allocate memory
+ goto fail;
+
+
+ strcpy( tmp_name, prefix );
+ strcat( tmp_name, dev );
+
+ port_handle = CreateFile( tmp_name, GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
+ NULL );
+
+ free( tmp_name );
+
+ if ( port_handle == INVALID_HANDLE_VALUE )
+ goto fail;
+
+
+ pst->port_handle = port_handle;
+
+ // save original settings
+ pst->old_dcb.DCBlength = sizeof( pst->old_dcb );
+ GetCommState( port_handle, &pst->old_dcb );
+ GetCommTimeouts( port_handle, &pst->old_commtimeouts );
+
+ // configure our settings
+ memset( &commtimeouts, 0, sizeof( commtimeouts ) );
+ SetCommTimeouts( port_handle, &commtimeouts );
+
+ #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 )
+ {
+ // 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 );
+
+ //##++ 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 ( port_handle < 0 ) // check errno for the reason
+ goto fail;
+
+
+ pst->port_handle = port_handle;
+
+ /* save current device settings */
+ tcgetattr( port_handle, &pst->oldtio );
+
+ // atexit( port_deinit );
+
+ fflush( stdout ); //##++
+ setvbuf( stdout, NULL, _IONBF, 0 );
+ }
+ #elif defined( MBG_TGT_DOS )
+ #if defined( _USE_V24TOOLS )
+ {
+ port_handle = v24open( (char *) dev, OPEN_MODE );
+
+ if ( port_handle < 0 )
+ goto fail;
+
+ pst->port_handle = port_handle;
+ v24settimeout( port_handle, 1 );
+ }
+ #else
+
+ #error Target DOS requires v24tools for serial I/O.
+
+ #endif
+
+ #else
+
+ #error This target OS is not supported.
+
+ #endif
+
+ return 0;
+
+
+fail:
+ pst->port_handle = MBG_INVALID_PORT_HANDLE;
+ return MBGSERIO_FAIL;
+
+} // mbgserio_open
+
+
+
+/*HDR*/
+_MBG_API_ATTR int _MBG_API mbgserio_close( SERIAL_IO_STATUS *pst )
+{
+ if ( pst->port_handle != MBG_INVALID_PORT_HANDLE )
+ {
+ MBG_PORT_HANDLE port_handle = pst->port_handle;
+
+ #if defined( MBG_TGT_CVI )
+
+ CloseCom( port_handle );
+
+ #elif defined( MBG_TGT_WIN32 )
+
+ SetCommState( port_handle, &pst->old_dcb );
+ SetCommTimeouts( port_handle, &pst->old_commtimeouts );
+ CloseHandle( port_handle );
+
+ #elif defined( MBG_TGT_UNIX )
+
+ tcsetattr( port_handle, TCSANOW, &pst->oldtio );
+ close( port_handle );
+
+ #elif defined( MBG_TGT_DOS )
+ #if defined( _USE_V24TOOLS )
+
+ v24close( port_handle );
+
+ #else
+
+ #error Target DOS requires v24tools for serial I/O.
+
+ #endif
+
+ #else
+
+ #error This target OS is not supported.
+
+ #endif
+
+ pst->port_handle = MBG_INVALID_PORT_HANDLE;
+ }
+
+ return 0;
+
+} // mbgserio_close
+
+
+
+/*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;
+
+ (*list) = (MBG_STR_LIST *) malloc( sizeof( **list ) );
+ memset( (*list), 0, sizeof( **list ) );
+
+ list_head = (*list);
+
+ for ( i = 0; i < max_devs; i++ )
+ {
+ SERIAL_IO_STATUS iost;
+ char dev_name[100] = { 0 };
+ int rc;
+
+ #if defined( MBG_TGT_WIN32 )
+ sprintf( dev_name, "COM%i", i + 1 );
+ #elif defined( MBG_TGT_LINUX )
+ sprintf( dev_name, "/dev/ttyS%i", i );
+ #endif
+
+ rc = mbgserio_open( &iost, dev_name );
+
+ if ( rc < 0 )
+ continue;
+
+ mbgserio_close( &iost );
+
+ (*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++;
+
+// if ( ++i >= MBG_MAX_DEVICES )
+// break;
+ }
+
+ if ( n == 0 )
+ {
+ free( *list );
+ list_head = NULL;
+ }
+
+ *list = list_head;
+
+ return n;
+
+} // mbgserio_setup_port_str_list
+
+
+
+/*HDR*/
+_MBG_API_ATTR void _MBG_API _MBG_API mbgserio_free_str_list( MBG_STR_LIST *list )
+{
+ int i = 0;
+
+ while ( i < 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
+
+
+
+/*HDR*/
+_MBG_API_ATTR int _MBG_API mbgserio_set_parms( SERIAL_IO_STATUS *pst,
+ uint32_t baud_rate, const char *framing )
+{
+ MBG_PORT_HANDLE port_handle = pst->port_handle;
+ const char *cp;
+
+ #if defined( MBG_TGT_CVI )
+ {
+ int data_bits = 8;
+ int parity_code = 0;
+ int stop_bits = 1;
+ int rc;
+
+ // setup framing.
+ for ( cp = framing; *cp; cp++ )
+ {
+ char c = toupper( *cp );
+
+ switch ( c )
+ {
+ case '7':
+ case '8':
+ data_bits = c - '0';
+ break;
+
+ case 'N':
+ parity_code = 0;
+ break;
+
+ case 'E':
+ parity_code = 2;
+ break;
+
+ case 'O':
+ parity_code = 1;
+ break;
+
+ case '1':
+ case '2':
+ stop_bits = c - '0';
+ break;
+
+ default:
+ return MBGSERIO_INV_CFG; // invalid framing string
+ }
+ }
+
+ rc = OpenComConfig( port_handle, NULL, baud_rate, parity_code,
+ data_bits, stop_bits, 8192, 1024 );
+ if ( rc < 0 )
+ return rc;
+
+ SetComTime( port_handle, 1.0 ); //##++
+ SetXMode( port_handle, 0 );
+ }
+ #elif defined( MBG_TGT_WIN32 )
+ {
+ DCB dcb;
+
+ dcb.DCBlength = sizeof( DCB ) ;
+ GetCommState( port_handle, &dcb ) ;
+ dcb.BaudRate = baud_rate;
+
+
+ // setup framing.
+ for ( cp = framing; *cp; cp++ )
+ {
+ char c = toupper( *cp );
+
+ switch ( c )
+ {
+ case '7':
+ case '8':
+ dcb.ByteSize = c - '0';
+ break;
+
+ case 'N':
+ dcb.Parity = NOPARITY;
+ break;
+
+ case 'E':
+ dcb.Parity = EVENPARITY;
+ break;
+
+ case 'O':
+ dcb.Parity = ODDPARITY;
+ break;
+
+ case '1':
+ dcb.StopBits = ONESTOPBIT;
+ break;
+
+ case '2':
+ dcb.StopBits = TWOSTOPBITS;
+ break;
+
+ default:
+ return MBGSERIO_INV_CFG; // invalid framing string
+ }
+ }
+
+
+ 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 );
+ }
+ #elif defined( MBG_TGT_UNIX )
+ {
+ tcflag_t c_cflag = 0;
+ struct termios tio;
+
+ tcgetattr( port_handle, &tio );
+
+ // setup transmission speed
+ switch( baud_rate )
+ {
+ case 300: c_cflag = B300; break;
+ case 600: c_cflag = B600; break;
+ case 1200: c_cflag = B1200; break;
+ case 2400: c_cflag = B2400; break;
+ case 4800: c_cflag = B4800; break;
+ case 9600: c_cflag = B9600; break;
+ case 19200: c_cflag = B19200; break;
+ case 38400: c_cflag = B38400; break;
+ case 57600: c_cflag = B57600; break;
+
+ default: return MBGSERIO_INV_CFG; // invalid
+ }
+
+ #if 0 //##++ This should be used preferably for portability reasons
+ int cfsetispeed( struct termios *termios_p, speed_t speed );
+ int cfsetospeed( struct termios *termios_p, speed_t speed );
+ #endif
+
+ // setup framing.
+ for ( cp = framing; *cp; cp++ )
+ {
+ switch ( _toupper( *cp ) )
+ {
+ case '7': c_cflag |= CS7; break;
+ case '8': c_cflag |= CS8; break;
+
+ case 'N': break;
+ case 'E': c_cflag |= PARENB; break;
+ case 'O': c_cflag |= PARENB | PARODD; break;
+
+ case '1': break;
+ case '2': c_cflag |= CSTOPB; break;
+
+ default: return MBGSERIO_INV_CFG; // invalid framing string
+ }
+ }
+
+
+ // Setup control flags. The following flags are defined:
+ // CBAUD (not in POSIX) Baud speed mask (4+1 bits).
+ // CBAUDEX (not in POSIX) Extra baud speed mask (1 bit), included in CBAUD.
+ // (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,
+ // 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.
+ // CREAD Enable receiver.
+ // PARENB Enable parity generation on output and parity checking for input.
+ // PARODD Parity for input and output is odd.
+ // HUPCL Lower modem control lines after last process closes the device (hang up).
+ // CLOCAL Ignore modem control lines.
+ // LOBLK (not in POSIX) Block output from a noncurrent shell layer.
+ // (For use by shl)
+ // CIBAUD (not in POSIX) Mask for input speeds. The values for the CIBAUD bits are
+ // 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
+ 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
+ // queues to be flushed, and if the terminal is the controlling
+ // 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
+ // is set, read a character with a parity error or framing error as \0.
+ // INPCK Enable input parity checking.
+ // ISTRIP Strip off eighth bit.
+ // INLCR Translate NL to CR on input.
+ // IGNCR Ignore carriage return on input.
+ // ICRNL Translate carriage return to newline on input (unless IGNCR is set).
+ // IUCLC (not in POSIX) Map uppercase characters to lowercase on input.
+ // IXON Enable XON/XOFF flow control on output.
+ // IXANY (not in POSIX.1; XSI) Enable any character to restart output.
+ // IXOFF Enable XON/XOFF flow control on input.
+ // IMAXBEL (not in POSIX) Ring bell when input queue is full. Linux does not
+ // implement this bit, and acts as if it is always set.
+ tio.c_iflag = 0;
+
+ #if 0 //##++
+ if ( c_cflag & PARENB )
+ tio.c_iflag |= IGNPAR; //##++ this also ignores framing errors
+ #endif
+
+
+ // Setup output flags. The following flags are defined:
+ // OPOST Enable implementation-defined output processing.
+ // The remaining c_oflag flag constants are defined in POSIX 1003.1-2001,
+ // unless marked otherwise.
+ // OLCUC (not in POSIX) Map lowercase characters to uppercase on output.
+ // ONLCR (XSI) Map NL to CR-NL on output.
+ // OCRNL Map CR to NL on output.
+ // 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,
+ // 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
+ // spaces (with tab stops every eight columns).
+ // 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.
+ tio.c_oflag = 0;
+
+
+ // Setup local mode flags. The following flags are defined:
+ // ISIG When any of the characters INTR, QUIT, SUSP, or DSUSP are
+ // received, generate the corresponding signal.
+ // ICANON Enable canonical mode. This enables the special characters
+ // 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
+ // characters are converted to uppercase.
+ // ECHO Echo input characters.
+ // 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
+ // signal. For example, character 0x08 (BS) is echoed as ^H.
+ // 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
+ // 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
+ // 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.
+ // (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,
+ // 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
+ // 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,
+ // 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
+ // 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,
+ // which signifies end-of-file. Recognized when ICANON is set, and
+ // then not passed as input.
+ // VMIN Minimum number of characters for non-canonical read.
+ // VEOL (0, NUL) Additional end-of-line character. Recognized when ICANON is set.
+ // VTIME Timeout in deciseconds for non-canonical read.
+ // VEOL2 (not in POSIX; 0, NUL) Yet another end-of-line character.
+ // Recognized when ICANON is set.
+ // VSWTCH (not in POSIX; not supported under Linux; 0, NUL) Switch character.
+ // (Used by shl only.)
+ // VSTART (021, DC1, Ctrl-Q) Start character. Restarts output stopped by the Stop
+ // character. Recognized when IXON is set, and then not passed as input.
+ // VSTOP (023, DC3, Ctrl-S) Stop character. Stop output until Start character
+ // 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
+ // suspend character: send SIGTSTP signal when the character is read by
+ // 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
+ // when IEXTEN is set, and then not passed as input.
+ // VWERASE (not in POSIX; 027, ETB, Ctrl-W) Word erase. Recognized when ICANON
+ // 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:
+ // 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
+ // 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
+ // 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
+ // time between two characters exceeds TIME. The timer is restarted
+ // 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
+ // fcntl(fd, F_SETFL, FNDELAY); before reading to get the same result.
+
+ // 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 );
+
+ fflush( stdout );
+ setvbuf( stdout, NULL, _IONBF, 0 );
+ }
+ #elif defined( MBG_TGT_DOS )
+ #if defined( _USE_V24TOOLS )
+ {
+ int datab = 8;
+ char parity = 'N';
+ int stopb = 1;
+
+ // setup framing.
+ for ( cp = framing; *cp; cp++ )
+ {
+ char c = toupper( *cp );
+
+ switch ( c )
+ {
+ case '7':
+ case '8':
+ datab = c - '0';
+ break;
+
+ case 'N':
+ case 'E':
+ case 'O':
+ parity = *cp;
+ break;
+
+ case '1':
+ case '2':
+ stopb = c - '0';
+ break;
+
+ default:
+ return MBGSERIO_INV_CFG; // invalid framing string
+ }
+ }
+
+ v24setparams( port_handle, baud_rate, datab, parity, stopb );
+ }
+ #else
+
+ #error This has to be modified for DOS without v24tools.
+
+ #endif
+
+ #else
+
+ #error This target OS is not supported.
+
+ #endif
+
+ return 0;
+
+} // 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 )
+{
+ BOOL fReadStat;
+ COMSTAT ComStat;
+ DWORD dwErrorFlags;
+ DWORD dwLength;
+
+ ClearCommError( h, &dwErrorFlags, &ComStat );
+
+ if ( dwErrorFlags ) // transmission error (parity, framing, etc.)
+ return MBGSERIO_FAIL;
+
+
+ dwLength = min( (DWORD) count, ComStat.cbInQue );
+
+ if ( dwLength )
+ {
+ fReadStat = ReadFile( h, buffer, dwLength, &dwLength, NULL );
+
+ if ( !fReadStat )
+ return MBGSERIO_FAIL;
+ }
+
+ return dwLength;
+
+} // mbgserio_read
+
+
+
+/*HDR*/
+_MBG_API_ATTR int _MBG_API mbgserio_write( MBG_PORT_HANDLE h, const void *buffer, unsigned int count )
+{
+ BOOL fWriteStat;
+ COMSTAT ComStat;
+ DWORD dwErrorFlags;
+ DWORD dwThisBytesWritten;
+ DWORD dwTotalBytesWritten = 0;
+
+ while ( dwTotalBytesWritten < (DWORD) count )
+ {
+ dwThisBytesWritten = 0;
+
+ fWriteStat = WriteFile( h, ( (char *) buffer ) + dwTotalBytesWritten,
+ count - dwTotalBytesWritten,
+ &dwThisBytesWritten, NULL );
+ if ( !fWriteStat )
+ {
+ #if defined( _DEBUG )
+ DWORD dw = GetLastError();
+ #endif
+ break; //##++ Error: Unable to write
+ }
+
+ dwTotalBytesWritten += dwThisBytesWritten;
+
+ ClearCommError( h, &dwErrorFlags, &ComStat );
+
+ if ( dwErrorFlags )
+ break; //#++ Error: Check flags
+ }
+
+ return dwTotalBytesWritten;
+
+} // mbgserio_write
+
+#endif // defined( MBG_TGT_WIN32 ) && !defined( MBG_TGT_CVI )
+
+
+
+/*HDR*/
+_MBG_API_ATTR int _MBG_API mbgserio_read_wait( MBG_PORT_HANDLE h, void *buffer,
+ uint count, ulong char_timeout )
+{
+ int n_bytes;
+
+ #if _USE_SELECT_FOR_SERIAL_IO
+
+ struct timeval tv_char_timeout;
+ fd_set fds;
+ int rc;
+
+ mbgserio_msec_to_timeval( char_timeout, &tv_char_timeout );
+
+ FD_ZERO( &fds );
+ FD_SET( h, &fds );
+
+ rc = select( h + 1, &fds, NULL, NULL, &tv_char_timeout );
+
+ if ( rc < 0 ) // error
+ goto fail;
+
+ if ( rc == 0 ) // timeout
+ goto timeout;
+
+ // data is available
+ n_bytes = _mbgserio_read( h, buffer, count );
+
+ #else
+ MBG_TMO_TIME tmo;
+
+ mbg_tmo_set_timeout_ms( &tmo, char_timeout );
+
+ for (;;) // wait to read one new char
+ {
+ n_bytes = _mbgserio_read( h, buffer, count );
+
+ if ( n_bytes > 0 ) // new char(s) received
+ break;
+
+ if ( n_bytes < 0 ) // error
+ goto fail;
+
+ if ( mbg_tmo_curr_time_is_after( &tmo ) )
+ goto timeout;
+
+ #if defined( MBG_TGT_UNIX )
+ usleep( 10 * 1000 );
+ #endif
+ }
+ #endif
+
+ return n_bytes;
+
+timeout:
+ return MBGSERIO_TIMEOUT;
+
+fail:
+ return MBGSERIO_FAIL;
+
+} // mbgserio_read_wait
+
+
+
diff --git a/mbglib/common/mbgserio.h b/mbglib/common/mbgserio.h
new file mode 100644
index 0000000..2367e14
--- /dev/null
+++ b/mbglib/common/mbgserio.h
@@ -0,0 +1,213 @@
+
+/**************************************************************************
+ *
+ * $Id: mbgserio.h 1.4 2009/09/01 10:54:29 martin REL_M $
+ *
+ * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
+ *
+ * Description:
+ * Definitions and prototypes for mbgserio.c.
+ *
+ * -----------------------------------------------------------------------
+ * $Log: mbgserio.h $
+ * 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.
+ * Code cleanup.
+ * Revision 1.3 2009/04/01 14:17:31 martin
+ * Cleanup for CVI.
+ * Revision 1.2 2008/09/04 15:11:36Z martin
+ * Preliminary support for device lists.
+ * Updated function prototypes.
+ * Revision 1.1 2007/11/12 16:48:02 martin
+ * Initial revision.
+ *
+ **************************************************************************/
+
+#ifndef _MBGSERIO_H
+#define _MBGSERIO_H
+
+
+/* Other headers to be included */
+
+#include <mbg_tmo.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#if defined( MBG_TGT_UNIX )
+ #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 )
+ #define _USE_SELECT_FOR_SERIAL_IO 1
+ #else
+ #define _USE_SELECT_FOR_SERIAL_IO 0
+ #endif
+#endif
+
+
+#ifdef _MBGSERIO
+ #define _ext
+ #define _DO_INIT
+#else
+ #define _ext extern
+#endif
+
+
+/* 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
+
+
+#if !defined( DEFAULT_DEV_NAME )
+ #if defined( MBG_TGT_WIN32 ) || defined( MBG_TGT_DOS )
+ #define DEFAULT_DEV_NAME "COM1"
+ #elif defined( MBG_TGT_LINUX )
+ #define DEFAULT_DEV_NAME "/dev/ttyS0"
+ #endif
+#endif
+
+
+/*
+ * The following macros control parts of the build process.
+ * The default values are suitable for most cases but can be
+ * overridden by global definitions, if required.
+ */
+
+#if _IS_MBG_FIRMWARE
+
+ // This handle type in not used by the firmware.
+ // However, we define it to avoid build errors.
+ typedef int MBG_HANDLE;
+
+#else
+
+ #if defined( MBG_TGT_CVI )
+
+ #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
+
+
+
+typedef struct _MBG_STR_LIST
+{
+ char *s;
+ struct _MBG_STR_LIST *next;
+
+} MBG_STR_LIST;
+
+
+
+typedef struct
+{
+ MBG_PORT_HANDLE port_handle; // the handle that will be used for the device
+
+ #if defined( MBG_TGT_WIN32 )
+ DCB old_dcb;
+ COMMTIMEOUTS old_commtimeouts;
+ #endif
+ #if defined( MBG_TGT_UNIX )
+ struct termios oldtio;
+ //##++ struct termios newtio;
+ #endif
+
+} SERIAL_IO_STATUS;
+
+
+
+/* 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 ) ;
+
+/* ----- function prototypes end ----- */
+
+#ifdef __cplusplus
+}
+#endif
+
+/* End of header body */
+
+#undef _ext
+#undef _DO_INIT
+
+#endif /* _MBGSERIO_H */
diff --git a/mbglib/common/words.h b/mbglib/common/words.h
new file mode 100644
index 0000000..9f6f1a9
--- /dev/null
+++ b/mbglib/common/words.h
@@ -0,0 +1,294 @@
+
+/**************************************************************************
+ *
+ * $Id: words.h 1.21 2009/10/01 14:00:17 martin REL_M $
+ *
+ * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
+ *
+ * Description:
+ * Definitions of commonly used data types.
+ *
+ * -----------------------------------------------------------------------
+ * $Log: words.h $
+ * Revision 1.21 2009/10/01 14:00:17 martin
+ * Conditionally define ulong and friends also for Linux/glibc.
+ * Revision 1.20 2009/07/02 15:38:12 martin
+ * Added new macro _wswap32().
+ * Revision 1.19 2009/04/14 14:45:45Z martin
+ * Added BYTE_OF_P() and WORD_OF_P() macros.
+ * Revision 1.18 2009/03/27 14:05:18 martin
+ * Cleanup for CVI.
+ * Revision 1.17 2009/03/13 09:06:03Z martin
+ * Declared bit type for non-firmware environments.
+ * Revision 1.16 2008/12/05 12:05:41Z martin
+ * Define dummy int64_t/uint64_t types for targets
+ * which don't support 64 bit data types.
+ * Revision 1.15 2008/07/14 14:44:00Z martin
+ * Use fixed size C99 types which come with GCC and newer Borland compilers.
+ * Revision 1.14 2008/01/30 10:27:50Z martin
+ * Moved some macro definitions here.
+ * Revision 1.13 2007/03/08 15:00:30Z martin
+ * Fixed incompatibility of macro _IS_MBG_FIRMWARE.
+ * Added a workaround for _IS_MBG_FIRMWARE under CVI.
+ * Support for BSD.
+ * Revision 1.12 2006/12/15 10:45:46 martin
+ * Added macro _IS_MBG_FIRMWARE.
+ * Cleanup for Linux, QNX, and Watcom C.
+ * Include mbg_tgt.h for non-firmware targets.
+ * Revision 1.11 2004/11/10 10:45:34 martin
+ * Added C99 fixed-type handling for QNX.
+ * Revision 1.10 2004/11/09 13:12:56 martin
+ * Redefined C99 integer types with fixed sizes as standard types
+ * if required, depending on the environment.
+ * Revision 1.9 2003/02/07 11:36:54 MARTIN
+ * New macros _hilo_16() and _hilo_32() for endian conversion.
+ * Revision 1.8 2002/05/28 10:09:54 MARTIN
+ * Added new macros _var_bswap16() and _var_bswap32().
+ * Revision 1.7 2001/03/14 11:30:48 MARTIN
+ * Removed definitions for UINT8, UINT16, UINT32.
+ * Redefined preprocessor control for Win32.
+ * Revision 1.6 2001/02/28 15:43:20 MARTIN
+ * Modified preprocessor syntax.
+ * Revision 1.5 2001/02/05 10:20:53 MARTIN
+ * Include different Linux types for user space and kernel space programs.
+ * Source code cleanup.
+ * Revision 1.4 2000/09/15 08:34:11 MARTIN
+ * Exclude some definitions if compiling under Win NT.
+ * Revision 1.3 2000/08/22 15:04:28 MARTIN
+ * Added new file header.
+ * Added macros to revert endianess of 16 and 32 bit values.
+ *
+ **************************************************************************/
+
+#ifndef _WORDS_H
+#define _WORDS_H
+
+
+/* Other headers to be included */
+
+
+#if !defined( _IS_MBG_FIRMWARE )
+
+#if defined( _C166 ) || \
+ defined( _CC51 ) || \
+ defined( __ARM )
+ #define _IS_MBG_FIRMWARE 1
+#else
+ #define _IS_MBG_FIRMWARE 0
+#endif
+
+
+#endif
+
+#if !_IS_MBG_FIRMWARE
+ #include <mbg_tgt.h>
+
+ typedef unsigned char bit;
+#endif
+
+
+#ifdef _WORDS
+ #define _ext
+#else
+ #define _ext extern
+#endif
+
+
+/* Start of header body */
+
+
+// Check whether the target system supports C99 fixed-size types.
+
+#if defined( MBG_TGT_LINUX ) // any Linux target
+
+ #if defined( __KERNEL__ )
+ #include <linux/types.h>
+ #else
+ #include <stdint.h>
+ #include <sys/types.h>
+ #endif
+
+ #define _C99_BIT_TYPES_DEFINED 1
+
+#elif defined( MBG_TGT_BSD )
+
+ #include <sys/types.h>
+
+ #define _C99_BIT_TYPES_DEFINED 1
+
+#elif defined( MBG_TGT_QNX ) // QNX 4.x or QNX 6.x
+
+ #if defined( MBG_TGT_QNX_NTO ) // QNX 6.x (Neutrino) with gcc
+ #include <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
+
+#endif
+
+
+// If it's not yet clear whether fixed-size types are supported,
+// check the build environment which may be multi-platform.
+
+#if !defined( _C99_BIT_TYPES_DEFINED )
+
+ #if defined( __WATCOMC__ )
+ #if __WATCOMC__ > 1230 // Open Watcom C 1.3 and above
+ #include <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 _C99_BIT_TYPES_DEFINED 1
+ #endif
+ #endif
+
+ #if defined( __BORLANDC__ )
+ #if ( __BORLANDC__ >= 0x570 ) // at least Borland Developer Studio 2006
+ #define _C99_BIT_TYPES_DEFINED 1
+ #endif
+ #endif
+
+ #if defined( __GNUC__ )
+ #include <stdint.h>
+ #define _C99_BIT_TYPES_DEFINED 1
+ #endif
+
+#endif
+
+
+// If neither the target system nor the build environment define C99 fixed-size
+// types define those types based on standard types with the proper sizes
+// commonly used in 16/32 bit environments.
+
+#if defined( _C99_BIT_TYPES_DEFINED )
+
+ #define MBG_TGT_HAS_64BIT_TYPES 1
+
+#else
+
+ typedef char int8_t;
+ typedef unsigned char uint8_t;
+
+ typedef short int16_t;
+ typedef unsigned short uint16_t;
+
+ typedef long int32_t;
+ typedef unsigned long uint32_t;
+
+
+ #if defined( MBG_TGT_WIN32 )
+
+ typedef __int64 int64_t;
+ typedef unsigned __int64 uint64_t;
+
+ #define MBG_TGT_HAS_64BIT_TYPES 1
+
+ #else
+ // The types below are required to avoid build errors
+ // if these types are formally used in function prototypes.
+ // We explicitely use abnormal data types to hopefully
+ // cause compiler errors in case these types are
+ // unexpectedly used to generate real code for a target
+ // platform which does not support 64 bit types.
+ typedef void *int64_t;
+ typedef void *uint64_t;
+ #endif
+
+#endif
+
+
+
+#if !defined( MBG_TGT_HAS_64BIT_TYPES )
+
+ #define MBG_TGT_HAS_64BIT_TYPES 0
+
+#endif
+
+
+
+// Some commonly used types
+
+typedef unsigned char uchar;
+
+#if !defined( MBG_TGT_LINUX ) || !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;
+#endif
+
+typedef double udouble;
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned long longword;
+typedef unsigned long dword;
+
+
+#define HI_BYTE( _x ) ( (_x) >> 8 )
+#define LO_BYTE( _x ) ( (_x) & 0xFF )
+
+#define HI_WORD( _x ) ( (_x) >> 16 )
+#define LO_WORD( _x ) ( (_x) & 0xFFFF )
+
+// the macros below assume little endianess
+// these macros expect the name of a variable
+#define BYTE_OF( _v, _n ) *( ( (uint8_t *) &(_v) ) + (_n) )
+#define WORD_OF( _v, _n ) *( ( (uint16_t *) &(_v) ) + (_n) )
+
+// same as above, but taking pointers
+#define BYTE_OF_P( _p, _n ) *( ( (uint8_t *) (_p) ) + (_n) )
+#define WORD_OF_P( _p, _n ) *( ( (uint16_t *) (_p) ) + (_n) )
+
+
+// a macro to swap the byte order of a 16 bit value
+#define _bswap16( _x ) \
+( \
+ ( ( ( (uint16_t) (_x) ) & 0x00FF ) << 8 ) | \
+ ( ( ( (uint16_t) (_x) ) & 0xFF00 ) >> 8 ) \
+)
+
+// a macro to swap the byte order of a 32 bit value
+#define _bswap32( _x ) \
+( \
+ ( ( ( (uint32_t) (_x) ) & 0x000000FFUL ) << 24 ) | \
+ ( ( ( (uint32_t) (_x) ) & 0x0000FF00UL ) << 8 ) | \
+ ( ( ( (uint32_t) (_x) ) & 0x00FF0000UL ) >> 8 ) | \
+ ( ( ( (uint32_t) (_x) ) & 0xFF000000UL ) >> 24 ) \
+)
+
+// a macro to swap the word order of a 32 bit value
+#define _wswap32( _x ) \
+( \
+ ( ( ( (uint32_t) (_x) ) & 0x0000FFFFUL ) << 16 ) | \
+ ( ( ( (uint32_t) (_x) ) >> 16 ) & 0x0000FFFFUL ) \
+)
+
+#define _var_bswap16( _v ) (_v) = _bswap16( _v )
+#define _var_bswap32( _v ) (_v) = _bswap32( _v )
+
+
+// The C51 compiler is big-endian, that means the most
+// significant byte of a 16 or 32 bit value is stored in
+// the lowest memory location. Most other systems are
+// little-endian, so we must use macros to adjust the
+// byte order if the C51 is used.
+
+#if defined( _CC51 )
+ #define _hilo_16( _x ) _bswap16( _x )
+ #define _hilo_32( _x ) _bswap32( _x )
+#else
+ #define _hilo_16( _x ) (_x)
+ #define _hilo_32( _x ) (_x)
+#endif
+
+/* End of header body */
+
+#undef _ext
+
+#endif /* _WORDS_H */
diff --git a/mbgreadtimestring.c b/mbgreadtimestring.c
new file mode 100644
index 0000000..61c8ebf
--- /dev/null
+++ b/mbgreadtimestring.c
@@ -0,0 +1,343 @@
+
+/**************************************************************************
+ *
+ * $Id: mbgreadtimestring.c 1.1 2009/10/09 15:49:56 martin REL_M $
+ * $Name: MBGREADTIMESTR_1_1 $
+ *
+ * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
+ *
+ * Description:
+ * Sample program demonstrating how to read a serial time string from
+ * an external device. Optionally a request character can be sent.
+ * The received time string is printed to stdout.
+ *
+ * Other modules needed to build the executable:
+ * mbgserio.c
+ *
+ * For makefiles and build environment setups check the associated
+ * subdirectories.
+ *
+ * Please send changes required for other OSs to <support@meinberg.de>
+ *
+ * -----------------------------------------------------------------------
+ * $Log: mbgreadtimestring.c $
+ * Revision 1.1 2009/10/09 15:49:56 martin
+ * Initial revision.
+ *
+ **************************************************************************/
+
+#include <mbgserio.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+static const char *pname = "mbgreadtimestring";
+static const char *pversion = "v1.1";
+static const char *pcopyright = "(c) Meinberg 2009";
+
+
+/* other local variables */
+static const char *target;
+static int must_print_usage;
+static int must_query;
+static int quiet;
+
+#if !defined( DEFAULT_DEV_NAME )
+ #define DEFAULT_DEV_NAME NULL
+#endif
+
+static const char *default_target = DEFAULT_DEV_NAME;
+
+static SERIAL_IO_STATUS serio_st;
+
+#if _USE_SERIAL_IO
+ static uint32_t default_baudrate = 19200L;
+ static const char *default_framing = "8N1";
+ static uint32_t baudrate;
+ static const char *framing;
+ static int must_force_connection;
+#endif
+
+
+
+static /*HDR*/
+int read_timestring( MBG_PORT_HANDLE dh, char *ts, int max_len )
+{
+ char *cp = ts;
+ int received_stx = 0;
+
+ for (;;)
+ {
+ char buffer[80];
+ ssize_t bytes_read;
+ fd_set read_set;
+ struct timeval tv_timeout;
+ int rc;
+ int i;
+
+ tv_timeout.tv_sec = 2;
+ tv_timeout.tv_usec = 0;
+ FD_ZERO( &read_set );
+ FD_SET( dh, &read_set );
+
+ rc = select( dh + 1, &read_set, NULL, NULL, &tv_timeout );
+
+ if ( rc < 0 ) // select() failed
+ {
+ perror( "select failed" );
+ return rc;
+ }
+
+ if ( rc == 0 ) // select() timed out
+ return 0;
+
+
+ bytes_read = read( dh, buffer, sizeof( buffer ) );
+
+ if ( bytes_read <= 0 )
+ {
+ if ( bytes_read < 0 )
+ perror( "reading" );
+
+ return bytes_read;
+ }
+
+ for ( i = 0; i < bytes_read; i++ )
+ {
+ char c = buffer[i];
+
+ switch ( c )
+ {
+ case 2: // STX: ignore
+ received_stx = 1; // just remember we received it
+ continue;
+
+ case 3: // ETX: ignore
+ goto done; // but done
+ }
+
+ if ( !received_stx )
+ continue;
+
+ if ( max_len == 0 )
+ goto done;
+
+ *cp++ = c;
+ max_len--;
+ }
+
+ } while ( 0 );
+
+done:
+ return cp - ts; // number of bytes saved
+
+} // read_timestring
+
+
+
+/*HDR*/ static
+void close_connection( void )
+{
+ mbgserio_close( &serio_st );
+
+} /* close_connection */
+
+
+
+static /*HDR*/
+void usage( const char *progname )
+{
+ printf( "Optionally send a request character, then read a time string\n"
+ "from a Meinberg device connected via serial port.\n"
+ "\n"
+ );
+
+ printf( "Usage: %s [-r] [-q] target\n"
+ "\n",
+ progname
+ );
+
+ printf( " -r Send a query/request character first\n"
+ );
+
+ printf( " -q Quiet, print nothing but the received time string\n"
+ );
+
+ printf( "\n"
+ "Optional arguments:\n"
+ " -? or -h Print this usage\n"
+ );
+
+#if _USE_SERIAL_IO
+ printf( " -b speed serial port baud rate, default: %lu\n"
+ " -f xxx serial port framing, default: %s\n"
+ " -F force serial connection to %lu/%s\n",
+ (long) default_baudrate,
+ framing,
+ (long) default_baudrate,
+ framing
+ );
+#endif
+
+ printf( "\n"
+ "Target argument:\n"
+ );
+#if _USE_SERIAL_IO
+ printf( " can specify a serial port, e.g %s\n",
+ default_target
+ );
+#endif
+
+ printf( "\n" );
+
+} // usage
+
+
+
+// Do a very simple processing of command line parameters:
+
+static /*HDR*/
+int check_command_line( int argc, char *argv[] )
+{
+ int i;
+
+ for ( i = 1; i < argc; i++ )
+ {
+ if ( strcmp( argv[i], "-r" ) == 0 )
+ {
+ must_query = 1;
+ continue;
+ }
+
+ if ( strcmp( argv[i], "-q" ) == 0 )
+ {
+ quiet = 1;
+ continue;
+ }
+
+ if ( strcmp( argv[i], "-?" ) == 0 )
+ {
+ must_print_usage = 1;
+ continue;
+ }
+
+ if ( strcmp( argv[i], "-h" ) == 0 )
+ {
+ must_print_usage = 1;
+ continue;
+ }
+
+ #if _USE_SERIAL_IO
+ if ( strcmp( argv[i], "-b" ) == 0 )
+ {
+ if ( ++i < argc )
+ baudrate = strtoul( argv[i], NULL, 10 );
+ else
+ must_print_usage = 1;
+
+ continue;
+ }
+ #endif
+
+ #if _USE_SERIAL_IO
+ if ( strcmp( argv[i], "-f" ) == 0 )
+ {
+ if ( ++i < argc )
+ framing = argv[i];
+ else
+ must_print_usage = 1;
+
+ continue;
+ }
+ #endif
+
+ #if _USE_SERIAL_IO
+ if ( strcmp( argv[i], "-F" ) == 0 )
+ {
+ must_force_connection = 1;
+ continue;
+ }
+ #endif
+
+ if ( argv[i][0] != '-' )
+ target = argv[i];
+ else
+ must_print_usage = 1;
+ }
+
+ if ( target == NULL )
+ target = default_target;
+
+ return 0;
+
+} // check_command_line
+
+
+
+int main( int argc, char *argv[] )
+{
+ char ts[80];
+ int rc;
+
+ check_command_line( argc, argv );
+
+ if ( !quiet )
+ printf( "\n\n\n%s %s %s\n\n", pname, pversion, pcopyright );
+
+ #if _USE_SERIAL_IO
+ baudrate = default_baudrate;
+ framing = default_framing;
+ #endif
+
+ check_command_line( argc, argv );
+
+ if ( must_print_usage )
+ {
+ if ( !quiet )
+ usage( pname );
+
+ return 1;
+ }
+
+ #if _USE_SERIAL_IO
+ rc = mbgserio_open( &serio_st, target );
+
+ if ( rc < 0 )
+ {
+ if ( !quiet )
+ printf( "Error opening port %s.\n", target );
+ return 1; // Error ...
+ }
+
+ mbgserio_set_parms( &serio_st, baudrate, framing );
+
+ if ( !quiet )
+ printf( "Using %s with %li baud, %s\n",
+ target, (long) baudrate, framing );
+
+ #endif
+
+ atexit( close_connection );
+
+ // now send the new date and time to the device
+
+ if ( must_query )
+ {
+ char request_char = '?';
+ _mbgserio_write( serio_st.port_handle, &request_char, sizeof( request_char ) );
+ }
+
+ rc = read_timestring( serio_st.port_handle, ts, sizeof( ts ) );
+
+ if ( rc > 0 )
+ {
+ ts[rc] = 0; // terminating 0
+ printf( "%s\n", ts );
+ }
+
+ return 0;
+
+} /* main */
+
diff --git a/unix/Makefile b/unix/Makefile
new file mode 100644
index 0000000..0630759
--- /dev/null
+++ b/unix/Makefile
@@ -0,0 +1,55 @@
+
+#########################################################################
+#
+# $Id: Makefile 1.1 2009/10/09 15:49:56 martin REL_M $
+#
+# Description:
+# Makefile for mbgreadtimestring for Unix-like systems.
+# Currently supported OSs: Linux
+#
+# -----------------------------------------------------------------------
+# $Log: Makefile $
+# Revision 1.1 2009/10/09 15:49:56 martin
+# Initial revision.
+#
+#########################################################################
+
+TARGET = mbgreadtimestring
+
+MBGLIB = ../mbglib
+MBGLIB_COMMON=$(MBGLIB)/common
+LOC_INCL = -I. -I $(MBGLIB_COMMON)
+
+
+# set up the compiler flags
+
+CFLAGS = -Wall
+
+ifneq ($(DEBUG),)
+ # build with debugging enabled
+ CFLAGS += -g -DDEBUG=1
+else
+ # build with specified optimization level
+ CFLAGS += -O2
+endif
+
+CFLAGS += $(LOC_INCL)
+CFLAGS += -D_USE_SERIAL_IO=1
+
+
+SRCS=../$(TARGET).c \
+ $(MBGLIB_COMMON)/mbgserio.c
+
+
+all: $(TARGET)
+
+$(TARGET): $(SRCS) $(MAKEFILE_LIST)
+ $(CC) $(CFLAGS) $(SRCS) -o $@
+
+
+clean:
+ rm -f *.o *~ core
+ rm -f $(TARGET)
+
+distclean: clean
+