1
0
mirror of git://sigrok.org/libserialport synced 2023-08-10 21:13:24 +03:00

93 Commits

Author SHA1 Message Date
6f9b03e597 HACK: don't even check for termiox
termiox was removed from linux in e0efb3168d34
Some more information available in https://www.spinics.net/lists/linux-serial/msg41926.html

Attempting to use the termiox ioctls on more modern kernels results in
"Inappropriate IOCTL" errors.

While the "right" solution might be to remove the termiox code from the
linux path, simply not checking for termiox builds a libserialport that
functions on modern linux kernels.

Signed-off-by: Karl Palsson <karlp@etactica.com>
2021-07-01 18:03:31 +02:00
1abec20502 Apply a default baudrate when the OS does not provide one.
Handle the situation when the OS does not provide a baudrate in the code
path which opens the serial port. See bug #1632 and PR #6 for details.

  https://sigrok.org/bugzilla/show_bug.cgi?id=1632
  https://github.com/sigrokproject/libserialport/pull/6

This resolves bug #1632.

[ gsi: adjust comment style, rephrase comment and commit message ]
2021-07-01 17:55:13 +02:00
a06a765515 doc: update IRC reference to Libera.Chat 2021-06-16 21:42:41 +02:00
1b011060df sp: clear HUPCL to preserve control lines on close
The comment and code are out of sync. The comments say "leave control
lines alone on close." The HUPCL bit, when set, will "Lower modem control
lines after last process closes the device (hang up)."

To match the intent captured in the comment, the HUPCL bit should be
cleared.

Signed-off-by: Ben Gardiner <ben.l.gardiner@gmail.com>
2020-09-22 03:10:08 +00:00
086a418145 Return proper type when sp_get_port_transport() fails
The above function must always return an 'enum sp_transport'. So, return
NATIVE if no port is present because its effective meaning within the
API is "you shouldn't call any transport-specific functions for this
port handle".

Fixes bug #1531.

Signed-off-by: Wolfram Sang <wsa@kernel.org>
2020-05-04 22:05:00 +02:00
ffbfc5c76b Open the file descriptor of a serial port on POSIX systems exclusively
This fixes bug #1510.
2020-03-26 23:57:33 +01:00
0a24247de8 examples/send_receive: Fix receive check. 2020-03-26 22:38:41 +01:00
251890e3b9 Fix use of variable length array in send_receive example, for MSVC. 2020-02-07 14:09:06 +00:00
ba49ee82db Add send/receive example to VS2019 examples solution. 2020-02-07 14:00:35 +00:00
2913355f7e windows: Ignore fParity flag which is always 0 after GetCommState().
This is a known bug in Windows: https://stackoverflow.com/a/36650872

Reported here: https://github.com/martinling/libserialport/issues/36
2020-02-07 14:00:35 +00:00
6711e43e9b README: Remove note about old MinGW, it actually works fine. 2020-02-07 14:00:35 +00:00
75a280a597 configure.ac: remove broken handling for cygwin as $host_os.
I don't think these two mentions of cygwin ever did anything useful.
In fact they stop libserialport being buildable under cygwin.

The first one caused builds on cygwin to try to build windows.c,
which uses the Win32 API, not the POSIX layer provided by cygwin.

The second asserts that enumeration and port metadata are supported
on cygwin, but that isn't the case.

Without these matches for cygwin as $host_os, libserialport builds
and works just fine on old-school cygwin with the original mingw32.

The only reason that MSYS2 worked better is that it uses "msys" as
the $host_os identifier, not cygwin.
2020-02-07 14:00:35 +00:00
7b0686ed58 Add remaining examples to examples/README. 2020-02-07 13:59:31 +00:00
4349b1f6a2 Formatting fix for example descriptions. 2020-02-07 13:59:31 +00:00
cd1a7d4361 Add example of sending and receiving data. 2020-02-07 13:59:31 +00:00
d81a4dfdc6 unix: Fix calculation of poll() timeout in sp_wait(). 2020-02-02 09:36:52 +00:00
78c3db9bfb Minor whitespace- and consistency fixes. 2020-01-26 21:21:34 +01:00
42b3cf3b98 README: Add note on building for MSYS2/Cygwin. 2020-01-26 21:21:34 +01:00
fb58f12ee9 Relax timing test in the other direction.
On my test system under MSYS (Cygwin64), a period of 991ms was
measured after a sleep of 1s.
2020-01-26 21:21:34 +01:00
2be41b1265 Fix building on Cygwin.
There were two issues: first, feature test macros were only defined
for __linux__, so defintions we needed were not included. Enable the
same feature test macros for __CYGWIN__.

Second, the Cygwin headers do not define TIOCOUTQ, needed to use
ioctl() to get the number of bytes in the output queue. Return
SP_ERR_SUPP on Cygwin for this operation.

This fixes bug #963.
2020-01-26 21:21:21 +01:00
f6abee5c78 Relax timing test because it's too tight for Windows.
On my test system, a delay of 1016ms was measured after a
sleep of 1000ms.
2020-01-26 21:11:46 +01:00
6339fa04d6 README: update instructions for building with MSYS2. 2020-01-26 21:11:46 +01:00
28981e0793 README: update build instructions with VS2019/MSBuild options. 2020-01-26 21:11:46 +01:00
67b55d10b8 Add Visual Studio projects and solution to build example programs. 2020-01-26 21:11:46 +01:00
d8c4d388e8 Fix use of variable length local array in await_events example.
This prevented building with MSVC.
2020-01-26 21:11:46 +01:00
d6412d2801 windows: Fix another CreateFile usage.
When built with MSVC with unicode enabled, this gave:

warning C4133: 'function': incompatible types - from 'char *' to 'LPCWSTR'

due to CreateFile expanding to CreateFileW which accepts UTF-16 filenames.

The device name used here is in 8-bit format, having come from a call to
wc_to_utf8() in either get_root_hub_name() or get_external_hub_name(). So
we need to use CreateFileA.
2020-01-26 21:11:46 +01:00
60fc49ceab windows: Fix a warning on size_t to USHORT conversion.
Building with MSVC gave:
warning C4267: '=': conversion from 'size_t' to 'USHORT', possible loss of data

The value here is known to be safe for the sizes involved. Add an
explicit cast to suppress the warning.
2020-01-26 21:11:46 +01:00
41fc921ce4 windows: Fix a warning on conversion to unsigned int.
The result should be safe because we only use this function on time
differences as part of timeout calculations, not on absolute times.

Add an explicit cast to suppress the warning.
2020-01-26 21:11:46 +01:00
528e8c0002 windows: Fix warnings for conversions in time_as_timeval().
Building with MSVC gave:

warning C4244: '=': conversion from 'LONGLONG' to 'long', possible loss of data

when assigning the results of these calculation to the long fields
of struct timeval. The result should be OK, but put an explicit
cast in to make the change clear and suppress the warning.
2020-01-26 21:11:37 +01:00
988ace6c9f windows: Avoid leak of write buffer on realloc failure.
VS2019 IntelliSense reported:

Warning	C6308: 'realloc' might return null pointer: assigning null
               pointer to 'port->write_buf', which is passed as an
	       argument to 'realloc', will cause the original memory
	       block to be leaked.

This is correct, we would leak the buffer on a realloc failure.

Put the realloc result in a separate variable and handle the error
path before assigning the result to port->write_buf.
2020-01-24 05:39:16 +00:00
bf40b1cea9 windows: Use correct variant of FormatMessage.
When built with MSVC and unicode enabled, using 'message' gave:

warning C4133: 'initializing': incompatible types - from 'TCHAR *' to 'char *'

FormatMessage expands to either FormatMessageA or FormatMessageW
depending if unicode is enabled, and generates either a char (8-bit)
or WCHAR (UTF-16) string accordingly.

Since sp_last_error_message() returns char *, we must use the 8-bit
variant. The message will be encoded in the current code page.
2020-01-24 05:39:16 +00:00
e47c7dcbff windows: Use correct variant of CreateFile.
When built with MSVC and unicode enabled, using CreateFile gave:

warning C4133: 'function': incompatible types - from 'char *' to 'LPCWSTR'

CreateFile is a macro expanding to either CreateFileW if unicode
mode is enabled, or CreateFileA if not.

For CreateFileW, the filename is a UTF-16 string. For CreateFileA
it is an 'ANSI' string, meaning 8-bit chars in the current Windows
code page.

We do need to stick to 8-bit strings for port names, since
sp_get_port_by_name() and sp_get_port_name() are defined with
char * types, and that is what we store in struct sp_port. So
CreateFileA is the correct version to use.

Since Windows serial port names are always just 'COM' and a digit,
with a '\\.\' prefix for higher numbers, encoding is fortunately
not an issue - ASCII, UTF-8 and all the Windows code pages seem to
be equivalent for these characters.

We should however explicitly document what the encoding of strings
accepted and returned by libserialport is.
2020-01-24 05:39:16 +00:00
2149db9e93 Fix some warnings for size_t, DWORD and int conversions.
These cases are all in the sp_[non]blocking_{read,write} functions.

On MSVC, these conversions would generate warnings such as:
warning C4267: '=': conversion from 'size_t' to 'DWORD', possible loss of data

The warnings are genuine. There are some places where overflow is technically
possible, due to our use of size_t for sizes in function parameters (unsigned
64-bit on Windows x64), but an enum for return values (typically signed int
and 32-bit, but not guaranteed to be so by the standards), plus the Win32 API
usage of DWORD (unsigned 32-bit) for sizes in ReadFile/WriteFile.

However, overflow in practice would require reading/writing more than 2GB
over a serial port in a single call and is therefore unlikely to be a
real-world concern. I have therefore not tried to catch those cases - but the
places it is possible do now have explicit casts to the smaller types so that
they are more obvious.

We could document and test for a maximum read/write size of INT_MAX, but that
would still depend on the storage of 'enum sp_return' being at least a signed
int, which as I understand it the C standard does not require.

To be absolutely correct we would need a different API where sp_return
was only used for result codes, and the read/write functions took a
pointer to size_t for result sizes.
2020-01-24 05:39:16 +00:00
4651adb4f6 Replace some usages of int with size_t to fix overflow warnings.
On MSVC, these gave the following warning:

warning C4267: '=': conversion from 'size_t' to 'int', possible loss of data
2020-01-24 05:39:16 +00:00
75f468923b Add project files for Visual Studio 2019. 2020-01-24 05:39:16 +00:00
e919e2efaa Adjust headers and include ordering for MSVC support. 2020-01-24 05:39:12 +00:00
a20ed2965b Add example of waiting for events. 2020-01-23 04:11:45 +00:00
4720053160 Add an example of proper error handling. 2020-01-23 04:10:00 +00:00
6dba844779 Add some more narrative docs on the configuration API. 2020-01-23 03:56:41 +00:00
9ddf08588d Add example of how to configure a port. 2020-01-23 03:56:34 +00:00
0838c979cc Use SP_API prefix for functions in libserialport.h.
For MSVC, we need to set the __declspec() for public symbols to
dllexport or dllimport, depending if we are building or using the
library. So, detect MSVC and define SP_API appropriately if found.
We use the LIBSERIALPORT_MSBUILD define to distinguish between
building and using the library, which will need to be set in the
project configuration when building the library using MS tools.

For normal client use of the header on other systems, we need to
define SP_API to nothing to avoid it being undefined, but we need
to avoid doing this in the case where we are including the header
whilst building the library with autotools and SP_API is already
set by autoconf. So define LIBSERIALPORT_ATBUILD in AM_CFLAGS,
and don't touch SP_API in the header if that's set.
2020-01-23 03:35:47 +00:00
f6e32b2dfa Use a static header file, not dependent on autoconf. 2020-01-23 03:35:47 +00:00
6aaf844863 windows: wc_to_utf8: use some clearer variable names. 2020-01-23 03:35:47 +00:00
fdbb55ae1e windows: Don't try to include <unistd.h>.
This should enable compatibility with MSVC.
2020-01-23 03:35:47 +00:00
a9900f8b64 windows: wc_to_utf8: Eliminate variable-length array.
This should enable compatibility with MSVC.
2020-01-23 03:35:47 +00:00
e9d78d82c4 windows: Use a fixed worst-case WRITEFILE_MAX_SIZE.
This saves needing to include and isolate the DDK headers.
2020-01-23 03:35:47 +00:00
8488868187 windows: Handle the case where there are no serial ports at all.
It's possible for the HARDWARE\DEVICEMAP\SERIALCOMM key to not exist in
the registry if there are no serial ports at all and never have been, as
discovered on my rather minimalist gaming machine.

Handle that case gracefully and return an empty list.
2020-01-23 03:35:47 +00:00
c79e0ac8ef windows: Handle registry lookup failures correctly.
RegOpenKeyEx() and RegQueryInfoKey() return system error codes directly,
not by setting the thread-local errno equivalent that is returned by
GetLastError().

When returning SP_ERR_FAIL, our API specifies that sp_last_error_code()
may be called immediately afterwards to get the system error code. In
this case that would not work, as it would call GetLastError() and miss
the directly-returned result.

We therefore need to call SetLastError() with the error code before
returning with SP_ERR_FAIL.
2020-01-23 03:35:47 +00:00
060d1d8a73 windows: Loop over WriteFile() if write size exceeds limit.
Fixes #1469.
2020-01-23 03:35:47 +00:00
8073f87d45 Add test program for timing functions. 2020-01-23 03:35:47 +00:00
39acdc47db Move timing routines to separate file. 2020-01-20 04:33:24 +00:00
bd72614f08 Move commonly used start flag into timeout helpers. 2020-01-20 04:33:23 +00:00
9d1ca7c855 Move special case for poll() timeout to call site. 2020-01-20 04:31:59 +00:00
3317d678de Support timing helpers on Windows. 2020-01-20 04:31:59 +00:00
08eb25f53a More generic solution for limiting per-call timeout. 2020-01-20 04:31:59 +00:00
32dbe2d298 Move repetitive timeout code into helper functions. 2020-01-20 04:31:59 +00:00
9a7945af84 Abstract all time handling operations. 2020-01-20 04:31:59 +00:00
d9cc984fe7 Makefile.am: Add example files to the tarball. 2020-01-05 18:19:32 +01:00
44df415480 Doxygen: Fix an issue causing missing #define documentation output.
Searching for documented defines...
  [...]libserialport.h:1624: warning: documentation for unknown define SP_PACKAGE_VERSION_MAJOR found.
  [...]libserialport.h:1627: warning: documentation for unknown define SP_PACKAGE_VERSION_MINOR found.
  [...]libserialport.h:1630: warning: documentation for unknown define SP_PACKAGE_VERSION_MICRO found.
  [...]libserialport.h:1633: warning: documentation for unknown define SP_PACKAGE_VERSION_STRING found.
  [...]libserialport.h:1640: warning: documentation for unknown define SP_LIB_VERSION_CURRENT found.
  [...]libserialport.h:1643: warning: documentation for unknown define SP_LIB_VERSION_REVISION found.
  [...]libserialport.h:1646: warning: documentation for unknown define SP_LIB_VERSION_AGE found.
  [...]libserialport.h:1649: warning: documentation for unknown define SP_LIB_VERSION_STRING found.
2020-01-05 18:19:32 +01:00
89c3d63e1a Update Doxyfile for doxygen 1.8.16. 2020-01-05 18:19:32 +01:00
ee12a01e52 Release examples as public domain. 2020-01-05 18:19:32 +01:00
ad19d60493 Add some additional formatting hints to Doxygen comments. 2020-01-05 03:28:58 +00:00
7c8d67efdc Integrate examples into Doxygen. 2020-01-05 03:04:38 +00:00
8c1a14e658 Add examples directory with two example programs. 2020-01-05 02:04:06 +00:00
abd31fd9f9 android: Fix build compatibility with NDK platform 21 and up.
In platforms 21 and higher of the NDK, linux/serial.h is available,
which it was not before. This broke the build, because the configure
script would detect the availability of 'struct serial_struct' in that
header and set HAVE_STRUCT_SERIAL_STRUCT, but the #ifndef __ANDROID__
in libserialport_internal.h stopped us actually including the header.

This change fixes things to build with all versions of the NDK, and is
tested with builds for arm from versions 9 to 24.

Version 21 also added availability of tcdrain(), so we also use that
where available, and only use the direct ioctl() method on NDK < 21.

Fixes #1078.
2020-01-04 23:00:17 +00:00
277f832a6a Define _POSIX_C_SOURCE to 199309L to get clock_gettime(). 2020-01-04 18:27:25 +01:00
9118f753f4 linux: Fix compile warning on gcc 6+ for readlink() call.
Fixes #1268.
2020-01-04 18:24:00 +01:00
fa106ef155 Use O_CLOEXEC where available
Ensures that the file descriptor is (by default) not passed to
subprocesses spawned by applications using libserialport.

This fixes bug #1051.
2020-01-04 18:21:35 +01:00
bd0fb6094f windows: Fix a build error.
serialport.c: In function 'get_time':
  serialport.c:64:6: warning: implicit declaration of function 'clock_gettime' [-Wimplicit-function-declaration]
    if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
        ^
  serialport.c:64:20: error: 'CLOCK_MONOTONIC' undeclared (first use in this function)
    if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
                      ^
  serialport.c:64:20: note: each undeclared identifier is reported only once for each function it appears in
  serialport.c:65:17: error: 'CLOCK_REALTIME' undeclared (first use in this function)
     clock_gettime(CLOCK_REALTIME, &ts);
                   ^
  serialport.c: At top level:
  serialport.c:60:13: warning: 'get_time' defined but not used [-Wunused-function]
   static void get_time(struct timeval *time)
               ^
2019-12-28 23:39:15 +01:00
7fb9a7b0a7 Fall back to CLOCK_REALTIME if CLOCK_MONOTONIC not usable.
Sounds like this may be necessary on some older systems.
2019-12-28 22:02:19 +01:00
192e77492a Use mach_absolute_time() on OSX without clock_gettime().
This should fix #759 for OSX versions below 10.12.
2019-12-28 22:02:19 +01:00
f40ea9d461 Use clock_gettime(CLOCK_MONOTONIC) if available.
Should fix #759 except on OSX versions below 10.12, which don't
have clock_gettime.
2019-12-28 22:02:19 +01:00
46bdc20c26 configure: Check whether clock_gettime is available. 2019-12-28 22:02:19 +01:00
573feabc63 Move all gettimeofday() calls into a wrapper function. 2019-12-28 22:02:19 +01:00
b457865b8f windows: Use architecture-specific size limit for WriteFile calls. 2019-12-28 20:43:22 +01:00
39df7833f7 windows: Use an adaptively sized buffer for nonblocking writes. 2019-12-28 20:43:22 +01:00
6bd6a8b520 windows: Await completion of previous write before changing config. 2019-12-28 20:43:22 +01:00
55ab7e0b6b unix: Fix handling of EAGAIN in sp_nonblocking_write(). 2019-12-28 20:43:22 +01:00
81243567bc Random minor whitespace fixes. 2019-12-28 19:23:30 +01:00
2e0437c28e windows: Fix incorrect wc_to_utf8() calls.
This fixes bug #1079.
2019-12-28 17:08:49 +01:00
38b71192dd windows: wc_to_utf8(): Fix a WCHAR related issue causing crashes.
In wc_to_utf8() in windows.c, the zero terminator is written to an invalid
array index, which results in 2 bytes being zeroed in a random place in the
stack. This sometimes causes a crash when running sp_list_ports() (depending
on string length and compiler optimisation settings).

sizeof(wc_str) returns the size in bytes, so cannot be used directly as an
index into that array, it should be divided by sizeof(WCHAR). Otherwise the
zero terminator index is approximately twice what it should be.

This fixes bug #1031.
2019-06-30 14:23:59 +02:00
a84ffb5372 README: Add link to bug tracker. 2017-12-17 18:15:56 +01:00
42ad781896 README: Add missing contact info. 2017-12-15 18:38:11 +01:00
62ed9f801a windows: Break out helper function for awaiting previous write completion. 2017-09-13 19:27:50 +02:00
15541ebd78 Remove redundant inclusions of limits.h
The first one would be included for Windows too which seems to be
an error. The second one is obviously redundant.
2017-09-13 19:27:50 +02:00
95bad38c5b Canonicalize symlinks in portnames
This allows users to supply symlinks created e.g. by udev rules instead
of the actual device names.
2017-09-13 19:27:50 +02:00
2a6c24be33 FreeBSD: Add missing libusb-2.0 to pkg-config file.
This fixes bug #1033.
2017-09-13 15:04:56 +02:00
6c8115820d Linux: fix for alpha where BOTHER is not defined.
Fixes bug #363.
2017-03-19 12:16:49 +00:00
d8de88de32 configure summary: Show compiler version and flags. 2017-03-05 17:01:17 +01:00
0b53933127 configure summary: Show whether shared/static build is enabled. 2017-03-05 16:43:58 +01:00
5ec2f93bce configure summary: Slightly change formatting. 2017-03-05 16:42:37 +01:00
df3b70a888 use readdir() instead of the deprecated readir_r()
readir() is threadsafe on both linux and freebsd anyway.
The rationale behind the readdir_r() deprecation is in the glibc manual:
https://www.gnu.org/software/libc/manual/html_node/Reading_002fClosing-Directory.html

This fixes the following warning with recent glibc:

linux.c: In function ‘list_ports’:
linux.c:197:2: warning: ‘readdir_r’ is deprecated [-Wdeprecated-declarations]
  while (!readdir_r(dir, &entry, &result) && result) {
  ^~~~~
2016-10-14 23:58:22 +02:00
b2359c5c99 libserialport: Fix Linux files not compiled in with a toolchain for ucLinux
Buildroot can create toolchains for the no-MMU flavour of Linux, with a triple
containing 'uclinux' instead of just 'linux'.

Signed-off-by: Paul Cercueil <paul.cercueil@analog.com>
2016-09-04 18:42:43 +02:00
44 changed files with 3561 additions and 610 deletions

6
.gitignore vendored
View File

@ -12,7 +12,11 @@
/configure
/configure.lineno
/libserialport-*.tar.*
/libserialport.h
/libserialport.pc
/libtool
stamp-h?
.vs/
Debug/
Release/
x64/
*.vcxproj.user

529
Doxyfile

File diff suppressed because it is too large Load Diff

View File

@ -24,10 +24,13 @@ GNUMAKEFLAGS = --no-print-directory
# Enable more compiler warnings.
AM_CFLAGS = -std=c99 -Wall -Wextra -pedantic -Wmissing-prototypes -Wshadow
# Set flag used in libserialport.h to indicate we are building the library
# using autotools.
AM_CFLAGS += -DLIBSERIALPORT_ATBUILD
lib_LTLIBRARIES = libserialport.la
libserialport_la_SOURCES = serialport.c libserialport_internal.h
libserialport_la_SOURCES = serialport.c timing.c libserialport_internal.h
if LINUX
libserialport_la_SOURCES += linux.c linux_termios.c linux_termios.h
endif
@ -53,7 +56,19 @@ nodist_include_HEADERS = libserialport.h
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libserialport.pc
EXTRA_DIST = Doxyfile
TESTS = test_timing
check_PROGRAMS = test_timing
test_timing_SOURCES = timing.c test_timing.c
test_timing_CFLAGS = $(AM_CFLAGS)
EXTRA_DIST = Doxyfile \
examples/Makefile \
examples/README \
examples/list_ports.c \
examples/port_info.c \
examples/port_config.c \
examples/await_events.c \
examples/handle_errors.c
MAINTAINERCLEANFILES = ChangeLog

38
README
View File

@ -40,18 +40,27 @@ No other libraries are required.
Building
========
The package uses a GNU style build system and requires a Unix style shell.
On Windows, libserialport can be built with Visual Studio 2019 or with
the standalone MSBuild tool, using the solution and project files provided.
Windows builds can be created natively with the MinGW-w64 toolchain and
MSYS2 environment, or cross-compiled using a MinGW-w64 toolchain:
http://mingw-w64.sourceforge.net/
The "old" MinGW from http://mingw.org/ is not supported.
For other environments, the package uses a GNU style build based on autotools.
Run "./autogen.sh" to generate the build system, "./configure" to setup, then
"make" to build the library and "make install" to install it.
Windows builds can also be created using the autotools build system, using the
MinGW-w64 toolchain from http://mingw-w64.sourceforge.net/ - either natively
in Windows with the MSYS2 environment, or cross-compiling from another system.
To build from MSYS2, the following packages must be installed: autoconf,
automake-wrapper, libtool, make, and either mingw-w64-i686-gcc (for 32-bit)
or mingw-w64-x86_64-gcc (for 64-bit). Open either the "MSYS2 MinGW 32-bit" or
"MSYS2 MinGW 64-bit" command window from the Start menu and use this when
configuring and building the package. Using the "MSYS2 MSYS" shell will build
against the Cygwin compatibility layer; this works, but port enumeration and
metadata will not be available, and binaries will depend on Cygwin. The builds
produced by MinGW-w64 are normal Windows DLLs without additional dependencies.
API
===
@ -61,6 +70,21 @@ It can also be viewed online at:
http://sigrok.org/api/libserialport/unstable/
Bug reports
===========
You can report bugs for libserialport at https://sigrok.org/bugzilla.
Mailing list
============
https://lists.sourceforge.net/lists/listinfo/sigrok-devel
IRC
===
You can find the developers in the #sigrok IRC channel on Libera.Chat.
Website
=======

23
common.props Normal file
View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_PropertySheetDisplayName>Common</_PropertySheetDisplayName>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
<AdditionalDependencies>setupapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup />
</Project>

View File

@ -29,7 +29,7 @@ m4_define([sp_package_version], [sp_package_version_major.sp_package_version_min
AC_INIT([libserialport], [sp_package_version], [martin-libserialport@earth.li],
[libserialport], [http://sigrok.org/wiki/Libserialport])
AC_CONFIG_HEADERS([config.h libserialport.h])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([autostuff])
AC_CONFIG_AUX_DIR([autostuff])
@ -50,6 +50,19 @@ AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_LN_S
## SP_PROG_VERSION(program, sh-var)
## Obtain the version of <program> and store it in <sh-var>.
AC_DEFUN([SP_PROG_VERSION],
[dnl
m4_assert([$# >= 2])[]dnl
sp_prog_ver=`$1 --version 2>&AS_MESSAGE_LOG_FD | sed 1q 2>&AS_MESSAGE_LOG_FD`
AS_CASE([[$]?:$sp_prog_ver],
[[0:*[0-9].[0-9]*]], [$2=$sp_prog_ver],
[$2=unknown])[]dnl
])
SP_PROG_VERSION([$CC], [sp_cc_version])
# Initialize libtool.
LT_INIT
@ -74,18 +87,21 @@ AC_DEFINE_UNQUOTED([SP_LIB_VERSION_REVISION], [$SP_LIB_VERSION_REVISION], [.])
AC_DEFINE_UNQUOTED([SP_LIB_VERSION_AGE], [$SP_LIB_VERSION_AGE], [.])
AC_DEFINE_UNQUOTED([SP_LIB_VERSION_STRING], ["$SP_LIB_VERSION"], [.])
AM_CONDITIONAL([LINUX], [test -z "${host_os##linux*}"])
AM_CONDITIONAL([WIN32], [test -z "${host_os##mingw*}" || test -z "${host_os##cygwin*}"])
AM_CONDITIONAL([LINUX], [test -z "${host_os##linux*}" || test -z "${host_os##uclinux*}"])
AM_CONDITIONAL([WIN32], [test -z "${host_os##mingw*}"])
AM_CONDITIONAL([MACOSX], [test -z "${host_os##darwin*}"])
AM_CONDITIONAL([FREEBSD], [test -z "${host_os##freebsd*}"])
AM_COND_IF([WIN32], [SP_LIBS='-lsetupapi'], [SP_LIBS=])
AC_SUBST([SP_LIBS])
AM_COND_IF([FREEBSD], [SP_PKGLIBS='libusb-2.0'], [SP_PKGLIBS=])
AC_SUBST([SP_PKGLIBS])
AM_COND_IF([MACOSX], [AC_CHECK_HEADER([IOKit/IOKitLib.h], [],
[AC_MSG_ERROR([IOKit/IOKitLib.h not found])])])
AS_CASE([$host_os], [linux*|darwin*|mingw*|cygwin*|freebsd*],, [
AS_CASE([$host_os], [linux*|darwin*|mingw*|freebsd*],, [
AC_DEFINE([NO_ENUMERATION], [1], [Enumeration is unsupported.])
AC_DEFINE([NO_PORT_METADATA], [1], [Port metadata is unavailable.])
])
@ -96,7 +112,7 @@ AC_SYS_LARGEFILE
AC_TYPE_SIZE_T
# Check for specific termios structures.
AC_CHECK_TYPES([struct termios2, struct termiox],,,
AC_CHECK_TYPES([struct termios2],,,
[[#include <linux/termios.h>]])
AC_CHECK_MEMBERS([struct termios.c_ispeed, struct termios.c_ospeed,
struct termios2.c_ispeed, struct termios2.c_ospeed],,,
@ -110,6 +126,17 @@ AC_CHECK_DECLS([BOTHER],,, [[#include <linux/termios.h>]])
# Check for serial_struct.
AC_CHECK_TYPES([struct serial_struct],,, [[#include <linux/serial.h>]])
# Check for realpath().
AC_CHECK_FUNC([realpath], [AC_DEFINE(HAVE_REALPATH, 1, [realpath is available.])], [])
# Check for flock().
AC_CHECK_HEADER([sys/file.h], [AC_DEFINE(HAVE_SYS_FILE_H, 1, [sys/file.h is available.])], [])
AC_CHECK_FUNC([flock], [AC_DEFINE(HAVE_FLOCK, 1, [flock is available.])], [])
# Check for clock_gettime().
AC_CHECK_FUNC([clock_gettime],
[AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [clock_gettime is available.])], [])
AC_CACHE_CHECK([for visibility control], [sp_cv_visibility_control], [
sp_saved_CFLAGS=$CFLAGS
CFLAGS="$CFLAGS -Werror"
@ -138,10 +165,17 @@ cat >&AS_MESSAGE_FD <<_EOF
libserialport configuration summary:
- Package version (major.minor.micro): $SP_PACKAGE_VERSION
- Library version (current:revision:age): $SP_LIB_VERSION
- Prefix: $prefix
- Building on: $build
- Building for: $host
- Package version................. $SP_PACKAGE_VERSION
- Library ABI version............. $SP_LIB_VERSION
- Prefix.......................... $prefix
- Building on..................... $build
- Building for.................... $host
- Building shared / static........ $enable_shared / $enable_static
Compile configuration:
- C compiler...................... $CC
- C compiler version.............. $sp_cc_version
- C compiler flags................ $CFLAGS
- Linker flags.................... $LDFLAGS
_EOF

17
debug.props Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_PropertySheetDisplayName>Debug</_PropertySheetDisplayName>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>LIBSERIALPORT_MSBUILD;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup />
</Project>

6
examples/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
await_events
handle_errors
list_ports
port_info
port_config
send_receive

20
examples/Makefile Normal file
View File

@ -0,0 +1,20 @@
# A simple Makefile to build the examples in this directory.
#
# This example file is released to the public domain.
CC = gcc
PKG_CONFIG = pkg-config
CFLAGS = -g -Wall $(shell $(PKG_CONFIG) --cflags libserialport)
LIBS = $(shell $(PKG_CONFIG) --libs libserialport)
SOURCES = $(wildcard *.c)
BINARIES = $(SOURCES:.c=)
%: %.c
$(CC) $(CFLAGS) $< $(LIBS) -o $@
all: $(BINARIES)
clean:
rm $(BINARIES)

33
examples/README Normal file
View File

@ -0,0 +1,33 @@
This directory contains example programs showing how to use libserialport.
The examples currently included are:
list_ports.c - displays a list of ports on the system.
port_info.c - displays info about a particular port on the system.
port_config.c - sets and displays configuration settings on a port.
send_receive.c - loopback test sending & receiving data on 1 or 2 ports.
await_events.c - awaits receive events on multiple ports simultaneously.
handle_errors.c - demonstrates handling errors returned from the library.
The programs themselves are completely OS-independent, and require only a
C compiler and libserialport.
The 'examples.sln' file is a solution file for Microsoft Visual Studio 2019
which will build libserialport and all of the example programs.
The Makefile in this directory will attempt to build all the examples,
using 'gcc' to compile them and 'pkg-config' to discover the include
paths and linker settings needed to build with libserialport. It provides
a minimal example of how to write a Makefile to build a program using
libserialport.
If you have make, gcc, pkg-config and libserialport installed correctly
then running 'make' should build the example programs in this directory.
If this doesn't work, you may need to modify the Makefile or set necessary
paths in your environment to suit your system.
You can also build these examples using any other compiler, IDE or build
system. You just need the libserialport.h header available to compile them,
and the libserialport library available to link and run them.
These example files are hereby released into the public domain by the author.

101
examples/await_events.c Normal file
View File

@ -0,0 +1,101 @@
#include <libserialport.h>
#include <stdio.h>
#include <stdlib.h>
/* Example of how to wait for events on multiple ports.
*
* This example file is released to the public domain. */
/* Helper function for error handling. */
int check(enum sp_return result);
int main(int argc, char **argv)
{
/* Get the port names from the command line. */
if (argc < 2) {
printf("Usage: %s <port name>...\n", argv[0]);
return -1;
}
int num_ports = argc - 1;
char **port_names = argv + 1;
/* The ports we will use. */
struct sp_port **ports = malloc(num_ports * sizeof(struct sp_port *));
if (!ports)
abort();
/* The set of events we will wait for. */
struct sp_event_set *event_set;
/* Allocate the event set. */
check(sp_new_event_set(&event_set));
/* Open and configure each port, and then add its RX event
* to the event set. */
for (int i = 0; i < num_ports; i++) {
printf("Looking for port %s.\n", port_names[i]);
check(sp_get_port_by_name(port_names[i], &ports[i]));
printf("Opening port.\n");
check(sp_open(ports[i], SP_MODE_READ));
printf("Setting port to 9600 8N1, no flow control.\n");
check(sp_set_baudrate(ports[i], 9600));
check(sp_set_bits(ports[i], 8));
check(sp_set_parity(ports[i], SP_PARITY_NONE));
check(sp_set_stopbits(ports[i], 1));
check(sp_set_flowcontrol(ports[i], SP_FLOWCONTROL_NONE));
printf("Adding port RX event to event set.\n");
check(sp_add_port_events(event_set, ports[i], SP_EVENT_RX_READY));
}
/* Now we can call sp_wait() to await any event in the set.
* It will return when an event occurs, or the timeout elapses. */
printf("Waiting up to 5 seconds for RX on any port...\n");
check(sp_wait(event_set, 5000));
/* Iterate over ports to see which have data waiting. */
for (int i = 0; i < num_ports; i++) {
/* Get number of bytes waiting. */
int bytes_waiting = check(sp_input_waiting(ports[i]));
printf("Port %s: %d bytes received.\n",
sp_get_port_name(ports[i]), bytes_waiting);
}
/* Close ports and free resources. */
sp_free_event_set(event_set);
for (int i = 0; i < num_ports; i++) {
check(sp_close(ports[i]));
sp_free_port(ports[i]);
}
return 0;
}
/* Helper function for error handling. */
int check(enum sp_return result)
{
/* For this example we'll just exit on any error by calling abort(). */
char *error_message;
switch (result) {
case SP_ERR_ARG:
printf("Error: Invalid argument.\n");
abort();
case SP_ERR_FAIL:
error_message = sp_last_error_message();
printf("Error: Failed: %s\n", error_message);
sp_free_error_message(error_message);
abort();
case SP_ERR_SUPP:
printf("Error: Not supported.\n");
abort();
case SP_ERR_MEM:
printf("Error: Couldn't allocate memory.\n");
abort();
case SP_OK:
default:
return result;
}
}

91
examples/examples.sln Normal file
View File

@ -0,0 +1,91 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29613.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "list_ports", "projects\list_ports.vcxproj", "{4447C677-0B59-4E1A-9EFD-50D0BE8A0F64}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "port_info", "projects\port_info.vcxproj", "{4BD48C7E-E097-4580-BC63-B4F586D53B8A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libserialport", "..\libserialport.vcxproj", "{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "port_config", "projects\port_config.vcxproj", "{6CD526C6-0710-4ECA-BE23-6F85032C95F4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "await_events", "projects\await_events.vcxproj", "{E757BAB5-C79B-49AD-B9C1-B81276B0A6FA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "handle_errors", "projects\handle_errors.vcxproj", "{09EC5FFB-4DB0-4FE8-BF1E-050F03EC7ED4}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "send_receive", "projects\send_receive.vcxproj", "{F0B68251-C73A-4B7F-AA62-6778586A72A0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4447C677-0B59-4E1A-9EFD-50D0BE8A0F64}.Debug|x64.ActiveCfg = Debug|x64
{4447C677-0B59-4E1A-9EFD-50D0BE8A0F64}.Debug|x64.Build.0 = Debug|x64
{4447C677-0B59-4E1A-9EFD-50D0BE8A0F64}.Debug|x86.ActiveCfg = Debug|Win32
{4447C677-0B59-4E1A-9EFD-50D0BE8A0F64}.Debug|x86.Build.0 = Debug|Win32
{4447C677-0B59-4E1A-9EFD-50D0BE8A0F64}.Release|x64.ActiveCfg = Release|x64
{4447C677-0B59-4E1A-9EFD-50D0BE8A0F64}.Release|x64.Build.0 = Release|x64
{4447C677-0B59-4E1A-9EFD-50D0BE8A0F64}.Release|x86.ActiveCfg = Release|Win32
{4447C677-0B59-4E1A-9EFD-50D0BE8A0F64}.Release|x86.Build.0 = Release|Win32
{4BD48C7E-E097-4580-BC63-B4F586D53B8A}.Debug|x64.ActiveCfg = Debug|x64
{4BD48C7E-E097-4580-BC63-B4F586D53B8A}.Debug|x64.Build.0 = Debug|x64
{4BD48C7E-E097-4580-BC63-B4F586D53B8A}.Debug|x86.ActiveCfg = Debug|Win32
{4BD48C7E-E097-4580-BC63-B4F586D53B8A}.Debug|x86.Build.0 = Debug|Win32
{4BD48C7E-E097-4580-BC63-B4F586D53B8A}.Release|x64.ActiveCfg = Release|x64
{4BD48C7E-E097-4580-BC63-B4F586D53B8A}.Release|x64.Build.0 = Release|x64
{4BD48C7E-E097-4580-BC63-B4F586D53B8A}.Release|x86.ActiveCfg = Release|Win32
{4BD48C7E-E097-4580-BC63-B4F586D53B8A}.Release|x86.Build.0 = Release|Win32
{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}.Debug|x64.ActiveCfg = Debug|x64
{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}.Debug|x64.Build.0 = Debug|x64
{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}.Debug|x86.ActiveCfg = Debug|Win32
{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}.Debug|x86.Build.0 = Debug|Win32
{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}.Release|x64.ActiveCfg = Release|x64
{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}.Release|x64.Build.0 = Release|x64
{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}.Release|x86.ActiveCfg = Release|Win32
{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}.Release|x86.Build.0 = Release|Win32
{6CD526C6-0710-4ECA-BE23-6F85032C95F4}.Debug|x64.ActiveCfg = Debug|x64
{6CD526C6-0710-4ECA-BE23-6F85032C95F4}.Debug|x64.Build.0 = Debug|x64
{6CD526C6-0710-4ECA-BE23-6F85032C95F4}.Debug|x86.ActiveCfg = Debug|Win32
{6CD526C6-0710-4ECA-BE23-6F85032C95F4}.Debug|x86.Build.0 = Debug|Win32
{6CD526C6-0710-4ECA-BE23-6F85032C95F4}.Release|x64.ActiveCfg = Release|x64
{6CD526C6-0710-4ECA-BE23-6F85032C95F4}.Release|x64.Build.0 = Release|x64
{6CD526C6-0710-4ECA-BE23-6F85032C95F4}.Release|x86.ActiveCfg = Release|Win32
{6CD526C6-0710-4ECA-BE23-6F85032C95F4}.Release|x86.Build.0 = Release|Win32
{E757BAB5-C79B-49AD-B9C1-B81276B0A6FA}.Debug|x64.ActiveCfg = Debug|x64
{E757BAB5-C79B-49AD-B9C1-B81276B0A6FA}.Debug|x64.Build.0 = Debug|x64
{E757BAB5-C79B-49AD-B9C1-B81276B0A6FA}.Debug|x86.ActiveCfg = Debug|Win32
{E757BAB5-C79B-49AD-B9C1-B81276B0A6FA}.Debug|x86.Build.0 = Debug|Win32
{E757BAB5-C79B-49AD-B9C1-B81276B0A6FA}.Release|x64.ActiveCfg = Release|x64
{E757BAB5-C79B-49AD-B9C1-B81276B0A6FA}.Release|x64.Build.0 = Release|x64
{E757BAB5-C79B-49AD-B9C1-B81276B0A6FA}.Release|x86.ActiveCfg = Release|Win32
{E757BAB5-C79B-49AD-B9C1-B81276B0A6FA}.Release|x86.Build.0 = Release|Win32
{09EC5FFB-4DB0-4FE8-BF1E-050F03EC7ED4}.Debug|x64.ActiveCfg = Debug|x64
{09EC5FFB-4DB0-4FE8-BF1E-050F03EC7ED4}.Debug|x64.Build.0 = Debug|x64
{09EC5FFB-4DB0-4FE8-BF1E-050F03EC7ED4}.Debug|x86.ActiveCfg = Debug|Win32
{09EC5FFB-4DB0-4FE8-BF1E-050F03EC7ED4}.Debug|x86.Build.0 = Debug|Win32
{09EC5FFB-4DB0-4FE8-BF1E-050F03EC7ED4}.Release|x64.ActiveCfg = Release|x64
{09EC5FFB-4DB0-4FE8-BF1E-050F03EC7ED4}.Release|x64.Build.0 = Release|x64
{09EC5FFB-4DB0-4FE8-BF1E-050F03EC7ED4}.Release|x86.ActiveCfg = Release|Win32
{09EC5FFB-4DB0-4FE8-BF1E-050F03EC7ED4}.Release|x86.Build.0 = Release|Win32
{F0B68251-C73A-4B7F-AA62-6778586A72A0}.Debug|x64.ActiveCfg = Debug|x64
{F0B68251-C73A-4B7F-AA62-6778586A72A0}.Debug|x64.Build.0 = Debug|x64
{F0B68251-C73A-4B7F-AA62-6778586A72A0}.Debug|x86.ActiveCfg = Debug|Win32
{F0B68251-C73A-4B7F-AA62-6778586A72A0}.Debug|x86.Build.0 = Debug|Win32
{F0B68251-C73A-4B7F-AA62-6778586A72A0}.Release|x64.ActiveCfg = Release|x64
{F0B68251-C73A-4B7F-AA62-6778586A72A0}.Release|x64.Build.0 = Release|x64
{F0B68251-C73A-4B7F-AA62-6778586A72A0}.Release|x86.ActiveCfg = Release|Win32
{F0B68251-C73A-4B7F-AA62-6778586A72A0}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EEED7125-B08F-4EB9-8F10-F036CCD5F4CF}
EndGlobalSection
EndGlobal

117
examples/handle_errors.c Normal file
View File

@ -0,0 +1,117 @@
#include <libserialport.h>
#include <stdio.h>
#include <stdlib.h>
/* Example of how to handle errors from libserialport.
*
* This example file is released to the public domain. */
/* Pointers used in the program to resources that may need to be freed. */
struct sp_port **port_list = NULL;
struct sp_port_config *config = NULL;
struct sp_port *port = NULL;
/* Example of a function to clean up and exit the program with a given return code. */
void end_program(int return_code)
{
/* Free any structures we allocated. */
if (port_list != NULL)
sp_free_port_list(port_list);
if (config != NULL)
sp_free_config(config);
if (port != NULL)
sp_free_port(port);
/* Exit with the given return code. */
exit(return_code);
}
/* Example of a helper function for error handling. */
int check(enum sp_return result)
{
int error_code;
char *error_message;
switch (result) {
/* Handle each of the four negative error codes that can be returned.
*
* In this example, we will end the program on any error, using
* a different return code for each possible class of error. */
case SP_ERR_ARG:
/* When SP_ERR_ARG is returned, there was a problem with one
* or more of the arguments passed to the function, e.g. a null
* pointer or an invalid value. This generally implies a bug in
* the calling code. */
printf("Error: Invalid argument.\n");
end_program(1);
case SP_ERR_FAIL:
/* When SP_ERR_FAIL is returned, there was an error from the OS,
* which we can obtain the error code and message for. These
* calls must be made in the same thread as the call that
* returned SP_ERR_FAIL, and before any other system functions
* are called in that thread, or they may not return the
* correct results. */
error_code = sp_last_error_code();
error_message = sp_last_error_message();
printf("Error: Failed: OS error code: %d, message: '%s'\n",
error_code, error_message);
/* The error message should be freed after use. */
sp_free_error_message(error_message);
end_program(2);
case SP_ERR_SUPP:
/* When SP_ERR_SUPP is returned, the function was asked to do
* something that isn't supported by the current OS or device,
* or that libserialport doesn't know how to do in the current
* version. */
printf("Error: Not supported.\n");
end_program(3);
case SP_ERR_MEM:
/* When SP_ERR_MEM is returned, libserialport wasn't able to
* allocate some memory it needed. Since the library doesn't
* normally use any large data structures, this probably means
* the system is critically low on memory and recovery will
* require very careful handling. The library itself will
* always try to handle any allocation failure safely.
*
* In this example, we'll just try to exit gracefully without
* calling printf, which might need to allocate further memory. */
end_program(4);
case SP_OK:
default:
/* A return value of SP_OK, defined as zero, means that the
* operation succeeded. */
printf("Operation succeeded.\n");
/* Some fuctions can also return a value greater than zero to
* indicate a numeric result, such as the number of bytes read by
* sp_blocking_read(). So when writing an error handling wrapper
* function like this one, it's helpful to return the result so
* that it can be used. */
return result;
}
}
int main(int argc, char **argv)
{
/* Call some functions that should not result in errors. */
printf("Getting list of ports.\n");
check(sp_list_ports(&port_list));
printf("Creating a new port configuration.\n");
check(sp_new_config(&config));
/* Now make a function call that will result in an error. */
printf("Trying to find a port that doesn't exist.\n");
check(sp_get_port_by_name("NON-EXISTENT-PORT", &port));
/* We could now clean up and exit normally if an error hadn't occured. */
end_program(0);
}

50
examples/list_ports.c Normal file
View File

@ -0,0 +1,50 @@
#include <libserialport.h>
#include <stdio.h>
/* Example of how to get a list of serial ports on the system.
*
* This example file is released to the public domain. */
int main(int argc, char **argv)
{
/* A pointer to a null-terminated array of pointers to
* struct sp_port, which will contain the ports found.*/
struct sp_port **port_list;
printf("Getting port list.\n");
/* Call sp_list_ports() to get the ports. The port_list
* pointer will be updated to refer to the array created. */
enum sp_return result = sp_list_ports(&port_list);
if (result != SP_OK) {
printf("sp_list_ports() failed!\n");
return -1;
}
/* Iterate through the ports. When port_list[i] is NULL
* this indicates the end of the list. */
int i;
for (i = 0; port_list[i] != NULL; i++) {
struct sp_port *port = port_list[i];
/* Get the name of the port. */
char *port_name = sp_get_port_name(port);
printf("Found port: %s\n", port_name);
}
printf("Found %d ports.\n", i);
printf("Freeing port list.\n");
/* Free the array created by sp_list_ports(). */
sp_free_port_list(port_list);
/* Note that this will also free all the sp_port structures
* it points to. If you want to keep one of them (e.g. to
* use that port in the rest of your program), take a copy
* of it first using sp_copy_port(). */
return 0;
}

174
examples/port_config.c Normal file
View File

@ -0,0 +1,174 @@
#include <libserialport.h>
#include <stdio.h>
#include <stdlib.h>
/* Example of how to configure a serial port.
*
* This example file is released to the public domain. */
/* Helper function for error handling. */
int check(enum sp_return result);
/* Helper function to give a name for each parity mode. */
const char *parity_name(enum sp_parity parity);
int main(int argc, char **argv)
{
/* Get the port name from the command line. */
if (argc != 2) {
printf("Usage: %s <port name>\n", argv[0]);
return -1;
}
char *port_name = argv[1];
/* A pointer to a struct sp_port, which will refer to
* the port found. */
struct sp_port *port;
printf("Looking for port %s.\n", port_name);
/* Call sp_get_port_by_name() to find the port. The port
* pointer will be updated to refer to the port found. */
check(sp_get_port_by_name(port_name, &port));
/* Display some basic information about the port. */
printf("Port name: %s\n", sp_get_port_name(port));
printf("Description: %s\n", sp_get_port_description(port));
/* The port must be open to access its configuration. */
printf("Opening port.\n");
check(sp_open(port, SP_MODE_READ_WRITE));
/* There are two ways to access a port's configuration:
*
* 1. You can read and write a whole configuration (all settings at
* once) using sp_get_config() and sp_set_config(). This is handy
* if you want to change between some preset combinations, or save
* and restore an existing configuration. It also ensures the
* changes are made together, via an efficient set of calls into
* the OS - in some cases a single system call can be used.
*
* Use accessor functions like sp_get_config_baudrate() and
* sp_set_config_baudrate() to get and set individual settings
* from a configuration.
*
* Configurations are allocated using sp_new_config() and freed
* with sp_free_config(). You need to manage them yourself.
*
* 2. As a shortcut, you can set individual settings on a port
* directly by calling functions like sp_set_baudrate() and
* sp_set_parity(). This saves you the work of allocating
* a temporary config, setting it up, applying it to a port
* and then freeing it.
*
* In this example we'll do a bit of both: apply some initial settings
* to the port, read out that config and display it, then switch to a
* different configuration and back using sp_set_config(). */
/* First let's set some initial settings directly on the port.
*
* You should always configure all settings before using a port.
* There are no "default" settings applied by libserialport.
* When you open a port it has the defaults from the OS or driver,
* or the settings left over by the last program to use it. */
printf("Setting port to 115200 8N1, no flow control.\n");
check(sp_set_baudrate(port, 115200));
check(sp_set_bits(port, 8));
check(sp_set_parity(port, SP_PARITY_NONE));
check(sp_set_stopbits(port, 1));
check(sp_set_flowcontrol(port, SP_FLOWCONTROL_NONE));
/* A pointer to a struct sp_port_config, which we'll use for the config
* read back from the port. The pointer will be set by sp_new_config(). */
struct sp_port_config *initial_config;
/* Allocate a configuration for us to read the port config into. */
check(sp_new_config(&initial_config));
/* Read the current config from the port into that configuration. */
check(sp_get_config(port, initial_config));
/* Display some of the settings read back from the port. */
int baudrate, bits, stopbits;
enum sp_parity parity;
check(sp_get_config_baudrate(initial_config, &baudrate));
check(sp_get_config_bits(initial_config, &bits));
check(sp_get_config_stopbits(initial_config, &stopbits));
check(sp_get_config_parity(initial_config, &parity));
printf("Baudrate: %d, data bits: %d, parity: %s, stop bits: %d\n",
baudrate, bits, parity_name(parity), stopbits);
/* Create a different configuration to have ready for use. */
printf("Creating new config for 9600 7E2, XON/XOFF flow control.\n");
struct sp_port_config *other_config;
check(sp_new_config(&other_config));
check(sp_set_config_baudrate(other_config, 9600));
check(sp_set_config_bits(other_config, 7));
check(sp_set_config_parity(other_config, SP_PARITY_EVEN));
check(sp_set_config_stopbits(other_config, 2));
check(sp_set_config_flowcontrol(other_config, SP_FLOWCONTROL_XONXOFF));
/* We can apply the new config to the port in one call. */
printf("Applying new configuration.\n");
check(sp_set_config(port, other_config));
/* And now switch back to our original config. */
printf("Setting port back to previous config.\n");
check(sp_set_config(port, initial_config));
/* Now clean up by closing the port and freeing structures. */
check(sp_close(port));
sp_free_port(port);
sp_free_config(initial_config);
sp_free_config(other_config);
return 0;
}
/* Helper function for error handling. */
int check(enum sp_return result)
{
/* For this example we'll just exit on any error by calling abort(). */
char *error_message;
switch (result) {
case SP_ERR_ARG:
printf("Error: Invalid argument.\n");
abort();
case SP_ERR_FAIL:
error_message = sp_last_error_message();
printf("Error: Failed: %s\n", error_message);
sp_free_error_message(error_message);
abort();
case SP_ERR_SUPP:
printf("Error: Not supported.\n");
abort();
case SP_ERR_MEM:
printf("Error: Couldn't allocate memory.\n");
abort();
case SP_OK:
default:
return result;
}
}
/* Helper function to give a name for each parity mode. */
const char *parity_name(enum sp_parity parity)
{
switch (parity) {
case SP_PARITY_INVALID:
return "(Invalid)";
case SP_PARITY_NONE:
return "None";
case SP_PARITY_ODD:
return "Odd";
case SP_PARITY_EVEN:
return "Even";
case SP_PARITY_MARK:
return "Mark";
case SP_PARITY_SPACE:
return "Space";
default:
return NULL;
}
}

80
examples/port_info.c Normal file
View File

@ -0,0 +1,80 @@
#include <libserialport.h>
#include <stdio.h>
/* Example of how to get information about a serial port.
*
* This example file is released to the public domain. */
int main(int argc, char **argv)
{
/* Get the port name from the command line. */
if (argc != 2) {
printf("Usage: %s <port name>\n", argv[0]);
return -1;
}
char *port_name = argv[1];
/* A pointer to a struct sp_port, which will refer to
* the port found. */
struct sp_port *port;
printf("Looking for port %s.\n", port_name);
/* Call sp_get_port_by_name() to find the port. The port
* pointer will be updated to refer to the port found. */
enum sp_return result = sp_get_port_by_name(port_name, &port);
if (result != SP_OK) {
printf("sp_get_port_by_name() failed!\n");
return -1;
}
/* Display some basic information about the port. */
printf("Port name: %s\n", sp_get_port_name(port));
printf("Description: %s\n", sp_get_port_description(port));
/* Identify the transport which this port is connected through,
* e.g. native port, USB or Bluetooth. */
enum sp_transport transport = sp_get_port_transport(port);
if (transport == SP_TRANSPORT_NATIVE) {
/* This is a "native" port, usually directly connected
* to the system rather than some external interface. */
printf("Type: Native\n");
} else if (transport == SP_TRANSPORT_USB) {
/* This is a USB to serial converter of some kind. */
printf("Type: USB\n");
/* Display string information from the USB descriptors. */
printf("Manufacturer: %s\n", sp_get_port_usb_manufacturer(port));
printf("Product: %s\n", sp_get_port_usb_product(port));
printf("Serial: %s\n", sp_get_port_usb_serial(port));
/* Display USB vendor and product IDs. */
int usb_vid, usb_pid;
sp_get_port_usb_vid_pid(port, &usb_vid, &usb_pid);
printf("VID: %04X PID: %04X\n", usb_vid, usb_pid);
/* Display bus and address. */
int usb_bus, usb_address;
sp_get_port_usb_bus_address(port, &usb_bus, &usb_address);
printf("Bus: %d Address: %d\n", usb_bus, usb_address);
} else if (transport == SP_TRANSPORT_BLUETOOTH) {
/* This is a Bluetooth serial port. */
printf("Type: Bluetooth\n");
/* Display Bluetooth MAC address. */
printf("MAC: %s\n", sp_get_port_bluetooth_address(port));
}
printf("Freeing port.\n");
/* Free the port structure created by sp_get_port_by_name(). */
sp_free_port(port);
/* Note that this will also free the port name and other
* strings retrieved from the port structure. If you want
* to keep these, copy them before freeing the port. */
return 0;
}

View File

@ -0,0 +1,167 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\await_events.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\libserialport.vcxproj">
<Project>{1c8eaaf2-133e-4cee-8981-4a903a8b3935}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\libserialport.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{E757BAB5-C79B-49AD-B9C1-B81276B0A6FA}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>listports</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\await_events.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\libserialport.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_PropertySheetDisplayName>Common</_PropertySheetDisplayName>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>$(ProjectDir)\..\..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/FS %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
</Link>
</ItemDefinitionGroup>
<ItemGroup />
</Project>

View File

@ -0,0 +1,167 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\handle_errors.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\libserialport.vcxproj">
<Project>{1c8eaaf2-133e-4cee-8981-4a903a8b3935}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\libserialport.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{09EC5FFB-4DB0-4FE8-BF1E-050F03EC7ED4}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>listports</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\handle_errors.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\libserialport.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,167 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\list_ports.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\libserialport.vcxproj">
<Project>{1c8eaaf2-133e-4cee-8981-4a903a8b3935}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\libserialport.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{4447C677-0B59-4E1A-9EFD-50D0BE8A0F64}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>listports</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\list_ports.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\libserialport.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,167 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\port_config.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\libserialport.vcxproj">
<Project>{1c8eaaf2-133e-4cee-8981-4a903a8b3935}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\libserialport.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{6CD526C6-0710-4ECA-BE23-6F85032C95F4}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>listports</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\port_config.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\libserialport.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,167 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\port_info.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\libserialport.vcxproj">
<Project>{1c8eaaf2-133e-4cee-8981-4a903a8b3935}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\libserialport.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{4BD48C7E-E097-4580-BC63-B4F586D53B8A}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>listports</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\port_info.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\libserialport.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@ -0,0 +1,167 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\send_receive.c" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\libserialport.vcxproj">
<Project>{1c8eaaf2-133e-4cee-8981-4a903a8b3935}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\libserialport.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{F0B68251-C73A-4B7F-AA62-6778586A72A0}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>listports</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\send_receive.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\libserialport.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

139
examples/send_receive.c Normal file
View File

@ -0,0 +1,139 @@
#include <libserialport.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Example of how to send and receive data.
*
* This example file is released to the public domain. */
/* Helper function for error handling. */
int check(enum sp_return result);
int main(int argc, char **argv)
{
/* This example can be used with one or two ports. With one port, it
* will send data and try to receive it on the same port. This can be
* done by connecting a single wire between the TX and RX pins of the
* port.
*
* Alternatively it can be used with two serial ports connected to each
* other, so that data can be sent on one and received on the other.
* This can be done with two ports with TX/RX cross-connected, e.g. by
* a "null modem" cable, or with a pair of interconnected virtual ports,
* such as those created by com0com on Windows or tty0tty on Linux. */
/* Get the port names from the command line. */
if (argc < 2 || argc > 3) {
printf("Usage: %s <port 1> [<port 2>]\n", argv[0]);
return -1;
}
int num_ports = argc - 1;
char **port_names = argv + 1;
/* The ports we will use. */
struct sp_port *ports[2];
/* Open and configure each port. */
for (int i = 0; i < num_ports; i++) {
printf("Looking for port %s.\n", port_names[i]);
check(sp_get_port_by_name(port_names[i], &ports[i]));
printf("Opening port.\n");
check(sp_open(ports[i], SP_MODE_READ_WRITE));
printf("Setting port to 9600 8N1, no flow control.\n");
check(sp_set_baudrate(ports[i], 9600));
check(sp_set_bits(ports[i], 8));
check(sp_set_parity(ports[i], SP_PARITY_NONE));
check(sp_set_stopbits(ports[i], 1));
check(sp_set_flowcontrol(ports[i], SP_FLOWCONTROL_NONE));
}
/* Now send some data on each port and receive it back. */
for (int tx = 0; tx < num_ports; tx++) {
/* Get the ports to send and receive on. */
int rx = num_ports == 1 ? 0 : ((tx == 0) ? 1 : 0);
struct sp_port *tx_port = ports[tx];
struct sp_port *rx_port = ports[rx];
/* The data we will send. */
char *data = "Hello!";
int size = strlen(data);
/* We'll allow a 1 second timeout for send and receive. */
unsigned int timeout = 1000;
/* On success, sp_blocking_write() and sp_blocking_read()
* return the number of bytes sent/received before the
* timeout expired. We'll store that result here. */
int result;
/* Send data. */
printf("Sending '%s' (%d bytes) on port %s.\n",
data, size, sp_get_port_name(tx_port));
result = check(sp_blocking_write(tx_port, data, size, timeout));
/* Check whether we sent all of the data. */
if (result == size)
printf("Sent %d bytes successfully.\n", size);
else
printf("Timed out, %d/%d bytes sent.\n", result, size);
/* Allocate a buffer to receive data. */
char *buf = malloc(size + 1);
/* Try to receive the data on the other port. */
printf("Receiving %d bytes on port %s.\n",
size, sp_get_port_name(rx_port));
result = check(sp_blocking_read(rx_port, buf, size, timeout));
/* Check whether we received the number of bytes we wanted. */
if (result == size)
printf("Received %d bytes successfully.\n", size);
else
printf("Timed out, %d/%d bytes received.\n", result, size);
/* Check if we received the same data we sent. */
buf[result] = '\0';
printf("Received '%s'.\n", buf);
/* Free receive buffer. */
free(buf);
}
/* Close ports and free resources. */
for (int i = 0; i < num_ports; i++) {
check(sp_close(ports[i]));
sp_free_port(ports[i]);
}
return 0;
}
/* Helper function for error handling. */
int check(enum sp_return result)
{
/* For this example we'll just exit on any error by calling abort(). */
char *error_message;
switch (result) {
case SP_ERR_ARG:
printf("Error: Invalid argument.\n");
abort();
case SP_ERR_FAIL:
error_message = sp_last_error_message();
printf("Error: Failed: %s\n", error_message);
sp_free_error_message(error_message);
abort();
case SP_ERR_SUPP:
printf("Error: Not supported.\n");
abort();
case SP_ERR_MEM:
printf("Error: Couldn't allocate memory.\n");
abort();
case SP_OK:
default:
return result;
}
}

View File

@ -325,8 +325,7 @@ SP_PRIV enum sp_return get_port_details(struct sp_port *port)
SP_PRIV enum sp_return list_ports(struct sp_port ***list)
{
DIR *dir;
struct dirent entry;
struct dirent *result;
struct dirent *entry;
struct termios tios;
char name[PATH_MAX];
int fd, ret;
@ -336,20 +335,20 @@ SP_PRIV enum sp_return list_ports(struct sp_port ***list)
RETURN_FAIL("Could not open dir /dev");
DEBUG("Iterating over results");
while (!readdir_r(dir, &entry, &result) && result) {
while ((entry = readdir(dir))) {
ret = SP_OK;
if (entry.d_type != DT_CHR)
if (entry->d_type != DT_CHR)
continue;
if (strncmp(entry.d_name, "cuaU", 4) != 0)
if (strncmp(entry.d_name, "cuau", 4) != 0)
if (strncmp(entry.d_name, "cuad", 4) != 0)
if (strncmp(entry->d_name, "cuaU", 4) != 0)
if (strncmp(entry->d_name, "cuau", 4) != 0)
if (strncmp(entry->d_name, "cuad", 4) != 0)
continue;
if (strend(entry.d_name, ".init"))
if (strend(entry->d_name, ".init"))
continue;
if (strend(entry.d_name, ".lock"))
if (strend(entry->d_name, ".lock"))
continue;
snprintf(name, sizeof(name), "/dev/%s", entry.d_name);
snprintf(name, sizeof(name), "/dev/%s", entry->d_name);
DEBUG_FMT("Found device %s", name);
/* Check that we can open tty/cua device in rw mode - we need that. */
@ -370,7 +369,7 @@ SP_PRIV enum sp_return list_ports(struct sp_port ***list)
continue;
DEBUG_FMT("Found port %s", name);
DBG("%s: %s\n", __func__, entry.d_name);
DBG("%s: %s\n", __func__, entry->d_name);
*list = list_append(*list, name);
if (!*list) {

View File

@ -59,19 +59,38 @@
* to restructure things somewhat, or do without some specialised features.
* For particular notes on porting existing code, see @ref Porting.
*
* The following subsections will help explain the principles of the API.
* Examples
* --------
*
* Some simple example programs using libserialport are included in the
* @c examples directory in the source package:
*
* - @ref list_ports.c - Getting a list of ports present on the system.
* - @ref port_info.c - Getting information on a particular serial port.
* - @ref port_config.c - Accessing configuration settings of a port.
* - @ref send_receive.c - Sending and receiving data.
* - @ref await_events.c - Awaiting events on multiple ports.
* - @ref handle_errors.c - Handling errors returned from the library.
*
* These examples are linked with the API documentation. Each function
* in the API reference includes links to where it is used in an example
* program, and each appearance of a function in the examples links
* to that function's entry in the API reference.
*
* Headers
* -------
*
* To use libserialport functions in your code, you should include the
* libserialport.h header, i.e. "#include <libserialport.h>".
* libserialport.h header, i.e.
* @code
* #include <libserialport.h>
* @endcode
*
* Namespace
* ---------
*
* All identifiers defined by the public libserialport headers use the prefix
* sp_ (for functions and data types) or SP_ (for macros and constants).
* @c sp_ (for functions and data types) or @c SP_ (for macros and constants).
*
* Functions
* ---------
@ -132,12 +151,12 @@
* numeric result, e.g. sp_blocking_read() or sp_blocking_write().
*
* An error message is only available via sp_last_error_message() in the case
* where SP_ERR_FAIL was returned by the previous function call. The error
* where @ref SP_ERR_FAIL was returned by the previous function call. The error
* message returned is that provided by the OS, using the current language
* settings. It is an error to call sp_last_error_code() or
* sp_last_error_message() except after a previous function call returned
* SP_ERR_FAIL. The library does not define its own error codes or messages
* to accompany other return codes.
* @ref SP_ERR_FAIL. The library does not define its own error codes or
* messages to accompany other return codes.
*
* Thread safety
* -------------
@ -178,7 +197,7 @@
*
* The library can output extensive tracing and debugging information. The
* simplest way to use this is to set the environment variable
* LIBSERIALPORT_DEBUG to any value; messages will then be output to the
* @c LIBSERIALPORT_DEBUG to any value; messages will then be output to the
* standard error stream.
*
* This behaviour is implemented by a default debug message handling
@ -206,21 +225,21 @@
* libserialport provides only a raw binary channel with no special handling.
*
* The second relates to blocking versus non-blocking I/O behaviour. In
* Unix-like systems this is normally specified by setting the O_NONBLOCK
* flag on the file descriptor, affecting the semantics of subsequent read()
* and write() calls.
* Unix-like systems this is normally specified by setting the @c O_NONBLOCK
* flag on the file descriptor, affecting the semantics of subsequent @c read()
* and @c write() calls.
*
* In libserialport, blocking and nonblocking operations are both available at
* any time. If your existing code ѕets O_NONBLOCK, you should use
* any time. If your existing code ѕets @c O_NONBLOCK, you should use
* sp_nonblocking_read() and sp_nonblocking_write() to get the same behaviour
* as your existing read() and write() calls. If it does not, you should use
* sp_blocking_read() and sp_blocking_write() instead. You may also find
* as your existing @c read() and @c write() calls. If it does not, you should
* use sp_blocking_read() and sp_blocking_write() instead. You may also find
* sp_blocking_read_next() useful, which reproduces the semantics of a blocking
* read() with VTIME = 0 and VMIN = 1 set in termios.
* read() with @c VTIME=0 and @c VMIN=1 set in termios.
*
* Finally, you should take care if your program uses custom signal handlers.
* The blocking calls provided by libserialport will restart system calls that
* return with EINTR, so you will need to make your own arrangements if you
* return with @c EINTR, so you will need to make your own arrangements if you
* need to interrupt blocking operations when your signal handlers are called.
* This is not an issue if you only use the default handlers.
*
@ -231,23 +250,23 @@
*
* If your program does not use overlapped I/O, you can simply use
* sp_blocking_read() and sp_blocking_write() as direct equivalents for
* ReadFile() and WriteFile(). You may also find sp_blocking_read_next()
* useful, which reproduces the special semantics of ReadFile() with
* ReadIntervalTimeout and ReadTotalTimeoutMultiplier set to MAXDWORD
* and 0 < ReadTotalTimeoutConstant < MAXDWORD.
* @c ReadFile() and @c WriteFile(). You may also find sp_blocking_read_next()
* useful, which reproduces the special semantics of @c ReadFile() with
* @c ReadIntervalTimeout and @c ReadTotalTimeoutMultiplier set to @c MAXDWORD
* and @c ReadTotalTimeoutConstant set to between @c 1 and @c MAXDWORD-1 .
*
* If your program makes use of overlapped I/O to continue work while a serial
* operation is in progress, then you can achieve the same results using
* sp_nonblocking_read() and sp_nonblocking_write().
*
* Generally, overlapped I/O is combined with either waiting for completion
* once there is no more background work to do (using WaitForSingleObject() or
* WaitForMultipleObjects()), or periodically checking for completion with
* GetOverlappedResult(). If the aim is to start a new operation for further
* data once the previous one has completed, you can instead simply call the
* nonblocking functions again with the next data. If you need to wait for
* completion, use sp_wait() to determine when the port is ready to send or
* receive further data.
* once there is no more background work to do (using @c WaitForSingleObject()
* or @c WaitForMultipleObjects()), or periodically checking for completion
* with @c GetOverlappedResult(). If the aim is to start a new operation for
* further data once the previous one has completed, you can instead simply
* call the nonblocking functions again with the next data. If you need to
* wait for completion, use sp_wait() to determine when the port is ready to
* send or receive further data.
*/
#ifndef LIBSERIALPORT_LIBSERIALPORT_H
@ -259,6 +278,25 @@ extern "C" {
#include <stddef.h>
/** @cond */
#ifdef _MSC_VER
/* Microsoft Visual C/C++ compiler in use */
#ifdef LIBSERIALPORT_MSBUILD
/* Building the library - need to export DLL symbols */
#define SP_API __declspec(dllexport)
#else
/* Using the library - need to import DLL symbols */
#define SP_API __declspec(dllimport)
#endif
#else
/* Some other compiler in use */
#ifndef LIBSERIALPORT_ATBUILD
/* Not building the library itself - don't need any special prefixes. */
#define SP_API
#endif
#endif
/** @endcond */
/** Return values. */
enum sp_return {
/** Operation completed successfully. */
@ -445,6 +483,8 @@ struct sp_event_set {
*
* Enumerating the serial ports of a system.
*
* See @ref list_ports.c for a working example of port enumeration.
*
* @{
*/
@ -465,7 +505,7 @@ struct sp_event_set {
*
* @since 0.1.0
*/
enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr);
SP_API enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_ptr);
/**
* Free a port structure obtained from sp_get_port_by_name() or sp_copy_port().
@ -474,7 +514,7 @@ enum sp_return sp_get_port_by_name(const char *portname, struct sp_port **port_p
*
* @since 0.1.0
*/
void sp_free_port(struct sp_port *port);
SP_API void sp_free_port(struct sp_port *port);
/**
* List the serial ports available on the system.
@ -495,7 +535,7 @@ void sp_free_port(struct sp_port *port);
*
* @since 0.1.0
*/
enum sp_return sp_list_ports(struct sp_port ***list_ptr);
SP_API enum sp_return sp_list_ports(struct sp_port ***list_ptr);
/**
* Make a new copy of an sp_port structure.
@ -514,7 +554,7 @@ enum sp_return sp_list_ports(struct sp_port ***list_ptr);
*
* @since 0.1.0
*/
enum sp_return sp_copy_port(const struct sp_port *port, struct sp_port **copy_ptr);
SP_API enum sp_return sp_copy_port(const struct sp_port *port, struct sp_port **copy_ptr);
/**
* Free a port list obtained from sp_list_ports().
@ -526,7 +566,7 @@ enum sp_return sp_copy_port(const struct sp_port *port, struct sp_port **copy_pt
*
* @since 0.1.0
*/
void sp_free_port_list(struct sp_port **ports);
SP_API void sp_free_port_list(struct sp_port **ports);
/**
* @}
@ -534,6 +574,8 @@ void sp_free_port_list(struct sp_port **ports);
*
* Opening, closing and querying ports.
*
* See @ref port_info.c for a working example of getting port information.
*
* @{
*/
@ -547,7 +589,7 @@ void sp_free_port_list(struct sp_port **ports);
*
* @since 0.1.0
*/
enum sp_return sp_open(struct sp_port *port, enum sp_mode flags);
SP_API enum sp_return sp_open(struct sp_port *port, enum sp_mode flags);
/**
* Close the specified serial port.
@ -558,7 +600,7 @@ enum sp_return sp_open(struct sp_port *port, enum sp_mode flags);
*
* @since 0.1.0
*/
enum sp_return sp_close(struct sp_port *port);
SP_API enum sp_return sp_close(struct sp_port *port);
/**
* Get the name of a port.
@ -575,7 +617,7 @@ enum sp_return sp_close(struct sp_port *port);
*
* @since 0.1.0
*/
char *sp_get_port_name(const struct sp_port *port);
SP_API char *sp_get_port_name(const struct sp_port *port);
/**
* Get a description for a port, to present to end user.
@ -588,7 +630,7 @@ char *sp_get_port_name(const struct sp_port *port);
*
* @since 0.1.1
*/
char *sp_get_port_description(const struct sp_port *port);
SP_API char *sp_get_port_description(const struct sp_port *port);
/**
* Get the transport type used by a port.
@ -599,7 +641,7 @@ char *sp_get_port_description(const struct sp_port *port);
*
* @since 0.1.1
*/
enum sp_transport sp_get_port_transport(const struct sp_port *port);
SP_API enum sp_transport sp_get_port_transport(const struct sp_port *port);
/**
* Get the USB bus number and address on bus of a USB serial adapter port.
@ -614,7 +656,7 @@ enum sp_transport sp_get_port_transport(const struct sp_port *port);
*
* @since 0.1.1
*/
enum sp_return sp_get_port_usb_bus_address(const struct sp_port *port,
SP_API enum sp_return sp_get_port_usb_bus_address(const struct sp_port *port,
int *usb_bus, int *usb_address);
/**
@ -630,7 +672,7 @@ enum sp_return sp_get_port_usb_bus_address(const struct sp_port *port,
*
* @since 0.1.1
*/
enum sp_return sp_get_port_usb_vid_pid(const struct sp_port *port, int *usb_vid, int *usb_pid);
SP_API enum sp_return sp_get_port_usb_vid_pid(const struct sp_port *port, int *usb_vid, int *usb_pid);
/**
* Get the USB manufacturer string of a USB serial adapter port.
@ -643,7 +685,7 @@ enum sp_return sp_get_port_usb_vid_pid(const struct sp_port *port, int *usb_vid,
*
* @since 0.1.1
*/
char *sp_get_port_usb_manufacturer(const struct sp_port *port);
SP_API char *sp_get_port_usb_manufacturer(const struct sp_port *port);
/**
* Get the USB product string of a USB serial adapter port.
@ -656,7 +698,7 @@ char *sp_get_port_usb_manufacturer(const struct sp_port *port);
*
* @since 0.1.1
*/
char *sp_get_port_usb_product(const struct sp_port *port);
SP_API char *sp_get_port_usb_product(const struct sp_port *port);
/**
* Get the USB serial number string of a USB serial adapter port.
@ -669,7 +711,7 @@ char *sp_get_port_usb_product(const struct sp_port *port);
*
* @since 0.1.1
*/
char *sp_get_port_usb_serial(const struct sp_port *port);
SP_API char *sp_get_port_usb_serial(const struct sp_port *port);
/**
* Get the MAC address of a Bluetooth serial adapter port.
@ -682,7 +724,7 @@ char *sp_get_port_usb_serial(const struct sp_port *port);
*
* @since 0.1.1
*/
char *sp_get_port_bluetooth_address(const struct sp_port *port);
SP_API char *sp_get_port_bluetooth_address(const struct sp_port *port);
/**
* Get the operating system handle for a port.
@ -714,7 +756,7 @@ char *sp_get_port_bluetooth_address(const struct sp_port *port);
*
* @since 0.1.0
*/
enum sp_return sp_get_port_handle(const struct sp_port *port, void *result_ptr);
SP_API enum sp_return sp_get_port_handle(const struct sp_port *port, void *result_ptr);
/**
* @}
@ -722,6 +764,63 @@ enum sp_return sp_get_port_handle(const struct sp_port *port, void *result_ptr);
* @defgroup Configuration Configuration
*
* Setting and querying serial port parameters.
*
* See @ref port_config.c for a working example of port configuration.
*
* You should always configure all settings before using a port.
* There are no default settings applied by libserialport.
* When you open a port it may have default settings from the OS or
* driver, or the settings left over by the last program to use it.
*
* You should always set baud rate, data bits, parity and stop bits.
*
* You should normally also set one of the preset @ref sp_flowcontrol
* flow control modes, which will set up the RTS, CTS, DTR and DSR pin
* behaviours and enable or disable XON/XOFF. If you need an unusual
* configuration not covered by the preset flow control modes, you
* will need to configure these settings individually, and avoid
* calling sp_set_flowcontrol() or sp_set_config_flowcontrol() which
* will overwrite these settings.
*
* A port must be opened before you can change its settings.
*
* There are two ways of accessing port settings:
*
* Configuration structures
* ------------------------
*
* You can read and write a whole configuration (all settings at once)
* using sp_get_config() and sp_set_config(). This is handy if you want
* to change between some preset combinations, or save and restore an
* existing configuration. It also ensures the changes are made
* together, via an efficient set of calls into the OS - in some cases
* a single system call can be used.
*
* Use accessor functions like sp_get_config_baudrate() and
* sp_set_config_baudrate() to get and set individual settings
* from a configuration.
*
* For each setting in a port configuration, a special value of -1 can
* be used, which will cause that setting to be left alone when the
* configuration is applied by sp_set_config().
*
* This value is also be used by sp_get_config() for any settings
* which are unconfigured at the OS level, or in a state that is
* not representable within the libserialport API.
*
* Configurations are allocated using sp_new_config() and freed
* with sp_free_config(). You need to manage them yourself. When
* a new configuration is allocated by sp_new_config(), all of
* its settings are initially set to the special -1 value.
*
* Direct functions for changing port settings
* -------------------------------------------
*
* As a shortcut, you can set individual settings on a port directly
* by calling functions like sp_set_baudrate() and sp_set_parity().
* This saves you the work of allocating a temporary config, setting it
* up, applying it to a port and then freeing it.
*
* @{
*/
@ -747,7 +846,7 @@ enum sp_return sp_get_port_handle(const struct sp_port *port, void *result_ptr);
*
* @since 0.1.0
*/
enum sp_return sp_new_config(struct sp_port_config **config_ptr);
SP_API enum sp_return sp_new_config(struct sp_port_config **config_ptr);
/**
* Free a port configuration structure.
@ -756,7 +855,7 @@ enum sp_return sp_new_config(struct sp_port_config **config_ptr);
*
* @since 0.1.0
*/
void sp_free_config(struct sp_port_config *config);
SP_API void sp_free_config(struct sp_port_config *config);
/**
* Get the current configuration of the specified serial port.
@ -778,7 +877,7 @@ void sp_free_config(struct sp_port_config *config);
*
* @since 0.1.0
*/
enum sp_return sp_get_config(struct sp_port *port, struct sp_port_config *config);
SP_API enum sp_return sp_get_config(struct sp_port *port, struct sp_port_config *config);
/**
* Set the configuration for the specified serial port.
@ -797,7 +896,7 @@ enum sp_return sp_get_config(struct sp_port *port, struct sp_port_config *config
*
* @since 0.1.0
*/
enum sp_return sp_set_config(struct sp_port *port, const struct sp_port_config *config);
SP_API enum sp_return sp_set_config(struct sp_port *port, const struct sp_port_config *config);
/**
* Set the baud rate for the specified serial port.
@ -809,7 +908,7 @@ enum sp_return sp_set_config(struct sp_port *port, const struct sp_port_config *
*
* @since 0.1.0
*/
enum sp_return sp_set_baudrate(struct sp_port *port, int baudrate);
SP_API enum sp_return sp_set_baudrate(struct sp_port *port, int baudrate);
/**
* Get the baud rate from a port configuration.
@ -824,7 +923,7 @@ enum sp_return sp_set_baudrate(struct sp_port *port, int baudrate);
*
* @since 0.1.0
*/
enum sp_return sp_get_config_baudrate(const struct sp_port_config *config, int *baudrate_ptr);
SP_API enum sp_return sp_get_config_baudrate(const struct sp_port_config *config, int *baudrate_ptr);
/**
* Set the baud rate in a port configuration.
@ -836,7 +935,7 @@ enum sp_return sp_get_config_baudrate(const struct sp_port_config *config, int *
*
* @since 0.1.0
*/
enum sp_return sp_set_config_baudrate(struct sp_port_config *config, int baudrate);
SP_API enum sp_return sp_set_config_baudrate(struct sp_port_config *config, int baudrate);
/**
* Set the data bits for the specified serial port.
@ -848,7 +947,7 @@ enum sp_return sp_set_config_baudrate(struct sp_port_config *config, int baudrat
*
* @since 0.1.0
*/
enum sp_return sp_set_bits(struct sp_port *port, int bits);
SP_API enum sp_return sp_set_bits(struct sp_port *port, int bits);
/**
* Get the data bits from a port configuration.
@ -863,7 +962,7 @@ enum sp_return sp_set_bits(struct sp_port *port, int bits);
*
* @since 0.1.0
*/
enum sp_return sp_get_config_bits(const struct sp_port_config *config, int *bits_ptr);
SP_API enum sp_return sp_get_config_bits(const struct sp_port_config *config, int *bits_ptr);
/**
* Set the data bits in a port configuration.
@ -875,7 +974,7 @@ enum sp_return sp_get_config_bits(const struct sp_port_config *config, int *bits
*
* @since 0.1.0
*/
enum sp_return sp_set_config_bits(struct sp_port_config *config, int bits);
SP_API enum sp_return sp_set_config_bits(struct sp_port_config *config, int bits);
/**
* Set the parity setting for the specified serial port.
@ -887,7 +986,7 @@ enum sp_return sp_set_config_bits(struct sp_port_config *config, int bits);
*
* @since 0.1.0
*/
enum sp_return sp_set_parity(struct sp_port *port, enum sp_parity parity);
SP_API enum sp_return sp_set_parity(struct sp_port *port, enum sp_parity parity);
/**
* Get the parity setting from a port configuration.
@ -902,7 +1001,7 @@ enum sp_return sp_set_parity(struct sp_port *port, enum sp_parity parity);
*
* @since 0.1.0
*/
enum sp_return sp_get_config_parity(const struct sp_port_config *config, enum sp_parity *parity_ptr);
SP_API enum sp_return sp_get_config_parity(const struct sp_port_config *config, enum sp_parity *parity_ptr);
/**
* Set the parity setting in a port configuration.
@ -914,7 +1013,7 @@ enum sp_return sp_get_config_parity(const struct sp_port_config *config, enum sp
*
* @since 0.1.0
*/
enum sp_return sp_set_config_parity(struct sp_port_config *config, enum sp_parity parity);
SP_API enum sp_return sp_set_config_parity(struct sp_port_config *config, enum sp_parity parity);
/**
* Set the stop bits for the specified serial port.
@ -926,7 +1025,7 @@ enum sp_return sp_set_config_parity(struct sp_port_config *config, enum sp_parit
*
* @since 0.1.0
*/
enum sp_return sp_set_stopbits(struct sp_port *port, int stopbits);
SP_API enum sp_return sp_set_stopbits(struct sp_port *port, int stopbits);
/**
* Get the stop bits from a port configuration.
@ -941,7 +1040,7 @@ enum sp_return sp_set_stopbits(struct sp_port *port, int stopbits);
*
* @since 0.1.0
*/
enum sp_return sp_get_config_stopbits(const struct sp_port_config *config, int *stopbits_ptr);
SP_API enum sp_return sp_get_config_stopbits(const struct sp_port_config *config, int *stopbits_ptr);
/**
* Set the stop bits in a port configuration.
@ -953,7 +1052,7 @@ enum sp_return sp_get_config_stopbits(const struct sp_port_config *config, int *
*
* @since 0.1.0
*/
enum sp_return sp_set_config_stopbits(struct sp_port_config *config, int stopbits);
SP_API enum sp_return sp_set_config_stopbits(struct sp_port_config *config, int stopbits);
/**
* Set the RTS pin behaviour for the specified serial port.
@ -965,7 +1064,7 @@ enum sp_return sp_set_config_stopbits(struct sp_port_config *config, int stopbit
*
* @since 0.1.0
*/
enum sp_return sp_set_rts(struct sp_port *port, enum sp_rts rts);
SP_API enum sp_return sp_set_rts(struct sp_port *port, enum sp_rts rts);
/**
* Get the RTS pin behaviour from a port configuration.
@ -980,7 +1079,7 @@ enum sp_return sp_set_rts(struct sp_port *port, enum sp_rts rts);
*
* @since 0.1.0
*/
enum sp_return sp_get_config_rts(const struct sp_port_config *config, enum sp_rts *rts_ptr);
SP_API enum sp_return sp_get_config_rts(const struct sp_port_config *config, enum sp_rts *rts_ptr);
/**
* Set the RTS pin behaviour in a port configuration.
@ -992,7 +1091,7 @@ enum sp_return sp_get_config_rts(const struct sp_port_config *config, enum sp_rt
*
* @since 0.1.0
*/
enum sp_return sp_set_config_rts(struct sp_port_config *config, enum sp_rts rts);
SP_API enum sp_return sp_set_config_rts(struct sp_port_config *config, enum sp_rts rts);
/**
* Set the CTS pin behaviour for the specified serial port.
@ -1004,7 +1103,7 @@ enum sp_return sp_set_config_rts(struct sp_port_config *config, enum sp_rts rts)
*
* @since 0.1.0
*/
enum sp_return sp_set_cts(struct sp_port *port, enum sp_cts cts);
SP_API enum sp_return sp_set_cts(struct sp_port *port, enum sp_cts cts);
/**
* Get the CTS pin behaviour from a port configuration.
@ -1019,7 +1118,7 @@ enum sp_return sp_set_cts(struct sp_port *port, enum sp_cts cts);
*
* @since 0.1.0
*/
enum sp_return sp_get_config_cts(const struct sp_port_config *config, enum sp_cts *cts_ptr);
SP_API enum sp_return sp_get_config_cts(const struct sp_port_config *config, enum sp_cts *cts_ptr);
/**
* Set the CTS pin behaviour in a port configuration.
@ -1031,7 +1130,7 @@ enum sp_return sp_get_config_cts(const struct sp_port_config *config, enum sp_ct
*
* @since 0.1.0
*/
enum sp_return sp_set_config_cts(struct sp_port_config *config, enum sp_cts cts);
SP_API enum sp_return sp_set_config_cts(struct sp_port_config *config, enum sp_cts cts);
/**
* Set the DTR pin behaviour for the specified serial port.
@ -1043,7 +1142,7 @@ enum sp_return sp_set_config_cts(struct sp_port_config *config, enum sp_cts cts)
*
* @since 0.1.0
*/
enum sp_return sp_set_dtr(struct sp_port *port, enum sp_dtr dtr);
SP_API enum sp_return sp_set_dtr(struct sp_port *port, enum sp_dtr dtr);
/**
* Get the DTR pin behaviour from a port configuration.
@ -1058,7 +1157,7 @@ enum sp_return sp_set_dtr(struct sp_port *port, enum sp_dtr dtr);
*
* @since 0.1.0
*/
enum sp_return sp_get_config_dtr(const struct sp_port_config *config, enum sp_dtr *dtr_ptr);
SP_API enum sp_return sp_get_config_dtr(const struct sp_port_config *config, enum sp_dtr *dtr_ptr);
/**
* Set the DTR pin behaviour in a port configuration.
@ -1070,7 +1169,7 @@ enum sp_return sp_get_config_dtr(const struct sp_port_config *config, enum sp_dt
*
* @since 0.1.0
*/
enum sp_return sp_set_config_dtr(struct sp_port_config *config, enum sp_dtr dtr);
SP_API enum sp_return sp_set_config_dtr(struct sp_port_config *config, enum sp_dtr dtr);
/**
* Set the DSR pin behaviour for the specified serial port.
@ -1082,7 +1181,7 @@ enum sp_return sp_set_config_dtr(struct sp_port_config *config, enum sp_dtr dtr)
*
* @since 0.1.0
*/
enum sp_return sp_set_dsr(struct sp_port *port, enum sp_dsr dsr);
SP_API enum sp_return sp_set_dsr(struct sp_port *port, enum sp_dsr dsr);
/**
* Get the DSR pin behaviour from a port configuration.
@ -1097,7 +1196,7 @@ enum sp_return sp_set_dsr(struct sp_port *port, enum sp_dsr dsr);
*
* @since 0.1.0
*/
enum sp_return sp_get_config_dsr(const struct sp_port_config *config, enum sp_dsr *dsr_ptr);
SP_API enum sp_return sp_get_config_dsr(const struct sp_port_config *config, enum sp_dsr *dsr_ptr);
/**
* Set the DSR pin behaviour in a port configuration.
@ -1109,7 +1208,7 @@ enum sp_return sp_get_config_dsr(const struct sp_port_config *config, enum sp_ds
*
* @since 0.1.0
*/
enum sp_return sp_set_config_dsr(struct sp_port_config *config, enum sp_dsr dsr);
SP_API enum sp_return sp_set_config_dsr(struct sp_port_config *config, enum sp_dsr dsr);
/**
* Set the XON/XOFF configuration for the specified serial port.
@ -1121,7 +1220,7 @@ enum sp_return sp_set_config_dsr(struct sp_port_config *config, enum sp_dsr dsr)
*
* @since 0.1.0
*/
enum sp_return sp_set_xon_xoff(struct sp_port *port, enum sp_xonxoff xon_xoff);
SP_API enum sp_return sp_set_xon_xoff(struct sp_port *port, enum sp_xonxoff xon_xoff);
/**
* Get the XON/XOFF configuration from a port configuration.
@ -1136,7 +1235,7 @@ enum sp_return sp_set_xon_xoff(struct sp_port *port, enum sp_xonxoff xon_xoff);
*
* @since 0.1.0
*/
enum sp_return sp_get_config_xon_xoff(const struct sp_port_config *config, enum sp_xonxoff *xon_xoff_ptr);
SP_API enum sp_return sp_get_config_xon_xoff(const struct sp_port_config *config, enum sp_xonxoff *xon_xoff_ptr);
/**
* Set the XON/XOFF configuration in a port configuration.
@ -1148,7 +1247,7 @@ enum sp_return sp_get_config_xon_xoff(const struct sp_port_config *config, enum
*
* @since 0.1.0
*/
enum sp_return sp_set_config_xon_xoff(struct sp_port_config *config, enum sp_xonxoff xon_xoff);
SP_API enum sp_return sp_set_config_xon_xoff(struct sp_port_config *config, enum sp_xonxoff xon_xoff);
/**
* Set the flow control type in a port configuration.
@ -1165,7 +1264,7 @@ enum sp_return sp_set_config_xon_xoff(struct sp_port_config *config, enum sp_xon
*
* @since 0.1.0
*/
enum sp_return sp_set_config_flowcontrol(struct sp_port_config *config, enum sp_flowcontrol flowcontrol);
SP_API enum sp_return sp_set_config_flowcontrol(struct sp_port_config *config, enum sp_flowcontrol flowcontrol);
/**
* Set the flow control type for the specified serial port.
@ -1182,7 +1281,7 @@ enum sp_return sp_set_config_flowcontrol(struct sp_port_config *config, enum sp_
*
* @since 0.1.0
*/
enum sp_return sp_set_flowcontrol(struct sp_port *port, enum sp_flowcontrol flowcontrol);
SP_API enum sp_return sp_set_flowcontrol(struct sp_port *port, enum sp_flowcontrol flowcontrol);
/**
* @}
@ -1191,6 +1290,8 @@ enum sp_return sp_set_flowcontrol(struct sp_port *port, enum sp_flowcontrol flow
*
* Reading, writing, and flushing data.
*
* See @ref send_receive.c for an example of sending and receiving data.
*
* @{
*/
@ -1220,7 +1321,7 @@ enum sp_return sp_set_flowcontrol(struct sp_port *port, enum sp_flowcontrol flow
*
* @since 0.1.0
*/
enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, unsigned int timeout_ms);
SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, unsigned int timeout_ms);
/**
* Read bytes from the specified serial port, returning as soon as any data is
@ -1248,7 +1349,7 @@ enum sp_return sp_blocking_read(struct sp_port *port, void *buf, size_t count, u
*
* @since 0.1.1
*/
enum sp_return sp_blocking_read_next(struct sp_port *port, void *buf, size_t count, unsigned int timeout_ms);
SP_API enum sp_return sp_blocking_read_next(struct sp_port *port, void *buf, size_t count, unsigned int timeout_ms);
/**
* Read bytes from the specified serial port, without blocking.
@ -1263,7 +1364,7 @@ enum sp_return sp_blocking_read_next(struct sp_port *port, void *buf, size_t cou
*
* @since 0.1.0
*/
enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, size_t count);
SP_API enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, size_t count);
/**
* Write bytes to the specified serial port, blocking until complete.
@ -1299,7 +1400,7 @@ enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf, size_t count
*
* @since 0.1.0
*/
enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t count, unsigned int timeout_ms);
SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t count, unsigned int timeout_ms);
/**
* Write bytes to the specified serial port, without blocking.
@ -1320,7 +1421,7 @@ enum sp_return sp_blocking_write(struct sp_port *port, const void *buf, size_t c
*
* @since 0.1.0
*/
enum sp_return sp_nonblocking_write(struct sp_port *port, const void *buf, size_t count);
SP_API enum sp_return sp_nonblocking_write(struct sp_port *port, const void *buf, size_t count);
/**
* Gets the number of bytes waiting in the input buffer.
@ -1331,7 +1432,7 @@ enum sp_return sp_nonblocking_write(struct sp_port *port, const void *buf, size_
*
* @since 0.1.0
*/
enum sp_return sp_input_waiting(struct sp_port *port);
SP_API enum sp_return sp_input_waiting(struct sp_port *port);
/**
* Gets the number of bytes waiting in the output buffer.
@ -1342,7 +1443,7 @@ enum sp_return sp_input_waiting(struct sp_port *port);
*
* @since 0.1.0
*/
enum sp_return sp_output_waiting(struct sp_port *port);
SP_API enum sp_return sp_output_waiting(struct sp_port *port);
/**
* Flush serial port buffers. Data in the selected buffer(s) is discarded.
@ -1354,7 +1455,7 @@ enum sp_return sp_output_waiting(struct sp_port *port);
*
* @since 0.1.0
*/
enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers);
SP_API enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers);
/**
* Wait for buffered data to be transmitted.
@ -1372,7 +1473,7 @@ enum sp_return sp_flush(struct sp_port *port, enum sp_buffer buffers);
*
* @since 0.1.0
*/
enum sp_return sp_drain(struct sp_port *port);
SP_API enum sp_return sp_drain(struct sp_port *port);
/**
* @}
@ -1381,6 +1482,8 @@ enum sp_return sp_drain(struct sp_port *port);
*
* Waiting for events and timeout handling.
*
* See @ref await_events.c for an example of awaiting events on multiple ports.
*
* @{
*/
@ -1400,7 +1503,7 @@ enum sp_return sp_drain(struct sp_port *port);
*
* @since 0.1.0
*/
enum sp_return sp_new_event_set(struct sp_event_set **result_ptr);
SP_API enum sp_return sp_new_event_set(struct sp_event_set **result_ptr);
/**
* Add events to a struct sp_event_set for a given port.
@ -1419,7 +1522,7 @@ enum sp_return sp_new_event_set(struct sp_event_set **result_ptr);
*
* @since 0.1.0
*/
enum sp_return sp_add_port_events(struct sp_event_set *event_set,
SP_API enum sp_return sp_add_port_events(struct sp_event_set *event_set,
const struct sp_port *port, enum sp_event mask);
/**
@ -1432,7 +1535,7 @@ enum sp_return sp_add_port_events(struct sp_event_set *event_set,
*
* @since 0.1.0
*/
enum sp_return sp_wait(struct sp_event_set *event_set, unsigned int timeout_ms);
SP_API enum sp_return sp_wait(struct sp_event_set *event_set, unsigned int timeout_ms);
/**
* Free a structure allocated by sp_new_event_set().
@ -1441,7 +1544,7 @@ enum sp_return sp_wait(struct sp_event_set *event_set, unsigned int timeout_ms);
*
* @since 0.1.0
*/
void sp_free_event_set(struct sp_event_set *event_set);
SP_API void sp_free_event_set(struct sp_event_set *event_set);
/**
* @}
@ -1469,7 +1572,7 @@ void sp_free_event_set(struct sp_event_set *event_set);
*
* @since 0.1.0
*/
enum sp_return sp_get_signals(struct sp_port *port, enum sp_signal *signal_mask);
SP_API enum sp_return sp_get_signals(struct sp_port *port, enum sp_signal *signal_mask);
/**
* Put the port transmit line into the break state.
@ -1480,7 +1583,7 @@ enum sp_return sp_get_signals(struct sp_port *port, enum sp_signal *signal_mask)
*
* @since 0.1.0
*/
enum sp_return sp_start_break(struct sp_port *port);
SP_API enum sp_return sp_start_break(struct sp_port *port);
/**
* Take the port transmit line out of the break state.
@ -1491,7 +1594,7 @@ enum sp_return sp_start_break(struct sp_port *port);
*
* @since 0.1.0
*/
enum sp_return sp_end_break(struct sp_port *port);
SP_API enum sp_return sp_end_break(struct sp_port *port);
/**
* @}
@ -1500,6 +1603,8 @@ enum sp_return sp_end_break(struct sp_port *port);
*
* Obtaining error information.
*
* See @ref handle_errors.c for an example of error handling.
*
* @{
*/
@ -1516,7 +1621,7 @@ enum sp_return sp_end_break(struct sp_port *port);
*
* @since 0.1.0
*/
int sp_last_error_code(void);
SP_API int sp_last_error_code(void);
/**
* Get the error message for a failed operation.
@ -1532,7 +1637,7 @@ int sp_last_error_code(void);
*
* @since 0.1.0
*/
char *sp_last_error_message(void);
SP_API char *sp_last_error_message(void);
/**
* Free an error message returned by sp_last_error_message().
@ -1541,7 +1646,7 @@ char *sp_last_error_message(void);
*
* @since 0.1.0
*/
void sp_free_error_message(char *message);
SP_API void sp_free_error_message(char *message);
/**
* Set the handler function for library debugging messages.
@ -1560,7 +1665,7 @@ void sp_free_error_message(char *message);
*
* @since 0.1.0
*/
void sp_set_debug_handler(void (*handler)(const char *format, ...));
SP_API void sp_set_debug_handler(void (*handler)(const char *format, ...));
/**
* Default handler function for library debugging messages.
@ -1574,7 +1679,7 @@ void sp_set_debug_handler(void (*handler)(const char *format, ...));
*
* @since 0.1.0
*/
void sp_default_debug_handler(const char *format, ...);
SP_API void sp_default_debug_handler(const char *format, ...);
/** @} */
@ -1603,32 +1708,32 @@ void sp_default_debug_handler(const char *format, ...);
*/
/** The libserialport package 'major' version number. */
#undef SP_PACKAGE_VERSION_MAJOR
#define SP_PACKAGE_VERSION_MAJOR 0
/** The libserialport package 'minor' version number. */
#undef SP_PACKAGE_VERSION_MINOR
#define SP_PACKAGE_VERSION_MINOR 1
/** The libserialport package 'micro' version number. */
#undef SP_PACKAGE_VERSION_MICRO
#define SP_PACKAGE_VERSION_MICRO 1
/** The libserialport package version ("major.minor.micro") as string. */
#undef SP_PACKAGE_VERSION_STRING
#define SP_PACKAGE_VERSION_STRING "0.1.1"
/*
* Library/libtool version macros (can be used for conditional compilation).
*/
/** The libserialport libtool 'current' version number. */
#undef SP_LIB_VERSION_CURRENT
#define SP_LIB_VERSION_CURRENT 1
/** The libserialport libtool 'revision' version number. */
#undef SP_LIB_VERSION_REVISION
#define SP_LIB_VERSION_REVISION 0
/** The libserialport libtool 'age' version number. */
#undef SP_LIB_VERSION_AGE
#define SP_LIB_VERSION_AGE 1
/** The libserialport libtool version ("current:revision:age") as string. */
#undef SP_LIB_VERSION_STRING
#define SP_LIB_VERSION_STRING "1:0:1"
/**
* Get the major libserialport package version number.
@ -1637,7 +1742,7 @@ void sp_default_debug_handler(const char *format, ...);
*
* @since 0.1.0
*/
int sp_get_major_package_version(void);
SP_API int sp_get_major_package_version(void);
/**
* Get the minor libserialport package version number.
@ -1646,7 +1751,7 @@ int sp_get_major_package_version(void);
*
* @since 0.1.0
*/
int sp_get_minor_package_version(void);
SP_API int sp_get_minor_package_version(void);
/**
* Get the micro libserialport package version number.
@ -1655,7 +1760,7 @@ int sp_get_minor_package_version(void);
*
* @since 0.1.0
*/
int sp_get_micro_package_version(void);
SP_API int sp_get_micro_package_version(void);
/**
* Get the libserialport package version number as a string.
@ -1665,7 +1770,7 @@ int sp_get_micro_package_version(void);
*
* @since 0.1.0
*/
const char *sp_get_package_version_string(void);
SP_API const char *sp_get_package_version_string(void);
/**
* Get the "current" part of the libserialport library version number.
@ -1674,7 +1779,7 @@ const char *sp_get_package_version_string(void);
*
* @since 0.1.0
*/
int sp_get_current_lib_version(void);
SP_API int sp_get_current_lib_version(void);
/**
* Get the "revision" part of the libserialport library version number.
@ -1683,7 +1788,7 @@ int sp_get_current_lib_version(void);
*
* @since 0.1.0
*/
int sp_get_revision_lib_version(void);
SP_API int sp_get_revision_lib_version(void);
/**
* Get the "age" part of the libserialport library version number.
@ -1692,7 +1797,7 @@ int sp_get_revision_lib_version(void);
*
* @since 0.1.0
*/
int sp_get_age_lib_version(void);
SP_API int sp_get_age_lib_version(void);
/**
* Get the libserialport library version number as a string.
@ -1702,10 +1807,19 @@ int sp_get_age_lib_version(void);
*
* @since 0.1.0
*/
const char *sp_get_lib_version_string(void);
SP_API const char *sp_get_lib_version_string(void);
/** @} */
/**
* @example list_ports.c Getting a list of ports present on the system.
* @example port_info.c Getting information on a particular serial port.
* @example port_config.c Accessing configuration settings of a port.
* @example send_receive.c Sending and receiving data.
* @example await_events.c Awaiting events on multiple ports.
* @example handle_errors.c Handling errors returned from the library.
*/
#ifdef __cplusplus
}
#endif

View File

@ -6,7 +6,7 @@ includedir=@includedir@
Name: libserialport
Description: Cross-platform serial port access library.
URL: http://sigrok.org/wiki/Libserialport
Requires.private:
Requires.private: @SP_PKGLIBS@
Version: @SP_PACKAGE_VERSION@
Libs: -L${libdir} -lserialport
Libs.private: @SP_LIBS@

31
libserialport.sln Normal file
View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29613.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libserialport", "libserialport.vcxproj", "{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}.Debug|x64.ActiveCfg = Debug|x64
{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}.Debug|x64.Build.0 = Debug|x64
{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}.Debug|x86.ActiveCfg = Debug|Win32
{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}.Debug|x86.Build.0 = Debug|Win32
{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}.Release|x64.ActiveCfg = Release|x64
{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}.Release|x64.Build.0 = Release|x64
{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}.Release|x86.ActiveCfg = Release|Win32
{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C2042526-D57D-45CA-B39F-6D9A782D1A05}
EndGlobalSection
EndGlobal

84
libserialport.vcxproj Normal file
View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="libserialport.h" />
<ClInclude Include="libserialport_internal.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="serialport.c" />
<ClCompile Include="timing.c" />
<ClCompile Include="windows.c" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{1C8EAAF2-133E-4CEE-8981-4A903A8B3935}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>libserialport</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)'=='Debug'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
<Import Project="debug.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)'=='Release'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="common.props" />
<Import Project="release.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="libserialport.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="libserialport_internal.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="serialport.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="windows.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="timing.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -21,23 +21,44 @@
#ifndef LIBSERIALPORT_LIBSERIALPORT_INTERNAL_H
#define LIBSERIALPORT_LIBSERIALPORT_INTERNAL_H
/* These MSVC-specific defines must appear before other headers.*/
#ifdef _MSC_VER
#define _CRT_NONSTDC_NO_DEPRECATE
#define _CRT_SECURE_NO_WARNINGS
#endif
#ifdef __linux__
/* For timeradd, timersub, timercmp. */
/* These feature test macros must appear before other headers.*/
#if defined(__linux__) || defined(__CYGWIN__)
/* For timeradd, timersub, timercmp, realpath. */
#define _BSD_SOURCE 1 /* for glibc < 2.19 */
#define _DEFAULT_SOURCE 1 /* for glibc >= 2.20 */
/* For clock_gettime and associated types. */
#define _POSIX_C_SOURCE 199309L
#endif
#ifdef LIBSERIALPORT_ATBUILD
/* If building with autoconf, include the generated config.h. */
#include <config.h>
#endif
#ifdef LIBSERIALPORT_MSBUILD
/* If building with MS tools, define necessary things that
would otherwise appear in config.h. */
#define SP_PRIV
#endif
#include "libserialport.h"
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
@ -48,13 +69,22 @@
static const GUID name = { l,w1,w2,{ b1,b2,b3,b4,b5,b6,b7,b8 } }
#include <usbioctl.h>
#include <usbiodef.h>
/* The largest size that can be passed to WriteFile() safely
* on any architecture. This arises from the expression:
* PAGE_SIZE * (65535 - sizeof(MDL)) / sizeof(ULONG_PTR)
* and this worst-case value is found on x64. */
#define WRITEFILE_MAX_SIZE 33525760
#else
#include <limits.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <limits.h>
#include <time.h>
#include <poll.h>
#include <unistd.h>
#ifdef HAVE_SYS_FILE_H
#include <sys/file.h>
#endif
#endif
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
@ -62,11 +92,13 @@
#include <IOKit/serial/IOSerialKeys.h>
#include <IOKit/serial/ioss.h>
#include <sys/syslimits.h>
#include <mach/mach_time.h>
#endif
#ifdef __linux__
#include <dirent.h>
#ifndef __ANDROID__
#include "linux/serial.h"
/* Android only has linux/serial.h from platform 21 onwards. */
#if !(defined(__ANDROID__) && (__ANDROID_API__ < 21))
#include <linux/serial.h>
#endif
#include "linux_termios.h"
@ -84,8 +116,18 @@
#define TIOCOUTQ FIONWRITE
#endif
/*
* O_CLOEXEC is not available everywhere, fallback to not setting the
* flag on those systems.
*/
#ifndef _WIN32
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
#endif
/* Non-standard baudrates are not available everywhere. */
#if (defined(HAVE_TERMIOS_SPEED) || defined(HAVE_TERMIOS2_SPEED)) && defined(HAVE_DECL_BOTHER)
#if (defined(HAVE_TERMIOS_SPEED) || defined(HAVE_TERMIOS2_SPEED)) && HAVE_DECL_BOTHER
#define USE_TERMIOS_SPEED
#endif
@ -109,7 +151,8 @@ struct sp_port {
OVERLAPPED read_ovl;
OVERLAPPED wait_ovl;
DWORD events;
BYTE pending_byte;
BYTE *write_buf;
DWORD write_buf_size;
BOOL writing;
BOOL wait_running;
#else
@ -234,4 +277,35 @@ SP_PRIV struct sp_port **list_append(struct sp_port **list, const char *portname
SP_PRIV enum sp_return get_port_details(struct sp_port *port);
SP_PRIV enum sp_return list_ports(struct sp_port ***list);
/* Timing abstraction */
struct time {
#ifdef _WIN32
int64_t ticks;
#else
struct timeval tv;
#endif
};
struct timeout {
unsigned int ms, limit_ms;
struct time start, now, end, delta, delta_max;
struct timeval delta_tv;
bool calls_started, overflow;
};
SP_PRIV void time_get(struct time *time);
SP_PRIV void time_set_ms(struct time *time, unsigned int ms);
SP_PRIV void time_add(const struct time *a, const struct time *b, struct time *result);
SP_PRIV void time_sub(const struct time *a, const struct time *b, struct time *result);
SP_PRIV bool time_greater(const struct time *a, const struct time *b);
SP_PRIV void time_as_timeval(const struct time *time, struct timeval *tv);
SP_PRIV unsigned int time_as_ms(const struct time *time);
SP_PRIV void timeout_start(struct timeout *timeout, unsigned int timeout_ms);
SP_PRIV void timeout_limit(struct timeout *timeout, unsigned int limit_ms);
SP_PRIV bool timeout_check(struct timeout *timeout);
SP_PRIV void timeout_update(struct timeout *timeout);
SP_PRIV struct timeval *timeout_timeval(struct timeout *timeout);
SP_PRIV unsigned int timeout_remaining_ms(struct timeout *timeout);
#endif

54
linux.c
View File

@ -22,6 +22,18 @@
#include "libserialport.h"
#include "libserialport_internal.h"
/*
* The 'e' modifier for O_CLOEXEC is glibc >= 2.7 only, hence not
* portable, so provide an own wrapper for this functionality.
*/
static FILE *fopen_cloexec_rdonly(const char *pathname)
{
int fd;
if ((fd = open(pathname, O_RDONLY | O_CLOEXEC)) < 0)
return NULL;
return fdopen(fd, "r");
}
SP_PRIV enum sp_return get_port_details(struct sp_port *port)
{
/*
@ -34,7 +46,7 @@ SP_PRIV enum sp_return get_port_details(struct sp_port *port)
char manufacturer[128], product[128], serial[128];
char baddr[32];
const char dir_name[] = "/sys/class/tty/%s/device/%s%s";
char sub_dir[32] = "", file_name[PATH_MAX];
char sub_dir[32] = "", link_name[PATH_MAX], file_name[PATH_MAX];
char *ptr, *dev = port->name + 5;
FILE *file;
int i, count;
@ -43,12 +55,12 @@ SP_PRIV enum sp_return get_port_details(struct sp_port *port)
if (strncmp(port->name, "/dev/", 5))
RETURN_ERROR(SP_ERR_ARG, "Device name not recognized");
snprintf(file_name, sizeof(file_name), "/sys/class/tty/%s", dev);
if (lstat(file_name, &statbuf) == -1)
snprintf(link_name, sizeof(link_name), "/sys/class/tty/%s", dev);
if (lstat(link_name, &statbuf) == -1)
RETURN_ERROR(SP_ERR_ARG, "Device not found");
if (!S_ISLNK(statbuf.st_mode))
snprintf(file_name, sizeof(file_name), "/sys/class/tty/%s/device", dev);
count = readlink(file_name, file_name, sizeof(file_name));
snprintf(link_name, sizeof(link_name), "/sys/class/tty/%s/device", dev);
count = readlink(link_name, file_name, sizeof(file_name));
if (count <= 0 || count >= (int)(sizeof(file_name) - 1))
RETURN_ERROR(SP_ERR_ARG, "Device not found");
file_name[count] = 0;
@ -62,7 +74,7 @@ SP_PRIV enum sp_return get_port_details(struct sp_port *port)
strcat(sub_dir, "../");
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "busnum");
if (!(file = fopen(file_name, "r")))
if (!(file = fopen_cloexec_rdonly(file_name)))
continue;
count = fscanf(file, "%d", &bus);
fclose(file);
@ -70,7 +82,7 @@ SP_PRIV enum sp_return get_port_details(struct sp_port *port)
continue;
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "devnum");
if (!(file = fopen(file_name, "r")))
if (!(file = fopen_cloexec_rdonly(file_name)))
continue;
count = fscanf(file, "%d", &address);
fclose(file);
@ -78,7 +90,7 @@ SP_PRIV enum sp_return get_port_details(struct sp_port *port)
continue;
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "idVendor");
if (!(file = fopen(file_name, "r")))
if (!(file = fopen_cloexec_rdonly(file_name)))
continue;
count = fscanf(file, "%4x", &vid);
fclose(file);
@ -86,7 +98,7 @@ SP_PRIV enum sp_return get_port_details(struct sp_port *port)
continue;
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "idProduct");
if (!(file = fopen(file_name, "r")))
if (!(file = fopen_cloexec_rdonly(file_name)))
continue;
count = fscanf(file, "%4x", &pid);
fclose(file);
@ -99,7 +111,7 @@ SP_PRIV enum sp_return get_port_details(struct sp_port *port)
port->usb_pid = pid;
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "product");
if ((file = fopen(file_name, "r"))) {
if ((file = fopen_cloexec_rdonly(file_name))) {
if ((ptr = fgets(description, sizeof(description), file))) {
ptr = description + strlen(description) - 1;
if (ptr >= description && *ptr == '\n')
@ -112,7 +124,7 @@ SP_PRIV enum sp_return get_port_details(struct sp_port *port)
port->description = strdup(dev);
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "manufacturer");
if ((file = fopen(file_name, "r"))) {
if ((file = fopen_cloexec_rdonly(file_name))) {
if ((ptr = fgets(manufacturer, sizeof(manufacturer), file))) {
ptr = manufacturer + strlen(manufacturer) - 1;
if (ptr >= manufacturer && *ptr == '\n')
@ -123,7 +135,7 @@ SP_PRIV enum sp_return get_port_details(struct sp_port *port)
}
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "product");
if ((file = fopen(file_name, "r"))) {
if ((file = fopen_cloexec_rdonly(file_name))) {
if ((ptr = fgets(product, sizeof(product), file))) {
ptr = product + strlen(product) - 1;
if (ptr >= product && *ptr == '\n')
@ -134,7 +146,7 @@ SP_PRIV enum sp_return get_port_details(struct sp_port *port)
}
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "serial");
if ((file = fopen(file_name, "r"))) {
if ((file = fopen_cloexec_rdonly(file_name))) {
if ((ptr = fgets(serial, sizeof(serial), file))) {
ptr = serial + strlen(serial) - 1;
if (ptr >= serial && *ptr == '\n')
@ -160,7 +172,7 @@ SP_PRIV enum sp_return get_port_details(struct sp_port *port)
if (port->transport == SP_TRANSPORT_BLUETOOTH) {
snprintf(file_name, sizeof(file_name), dir_name, dev, "", "address");
if ((file = fopen(file_name, "r"))) {
if ((file = fopen_cloexec_rdonly(file_name))) {
if ((ptr = fgets(baddr, sizeof(baddr), file))) {
ptr = baddr + strlen(baddr) - 1;
if (ptr >= baddr && *ptr == '\n')
@ -178,12 +190,12 @@ SP_PRIV enum sp_return get_port_details(struct sp_port *port)
SP_PRIV enum sp_return list_ports(struct sp_port ***list)
{
char name[PATH_MAX], target[PATH_MAX];
struct dirent entry, *result;
struct dirent *entry;
#ifdef HAVE_STRUCT_SERIAL_STRUCT
struct serial_struct serial_info;
int ioctl_result;
#endif
char buf[sizeof(entry.d_name) + 23];
char buf[sizeof(entry->d_name) + 23];
int len, fd;
DIR *dir;
int ret = SP_OK;
@ -194,19 +206,19 @@ SP_PRIV enum sp_return list_ports(struct sp_port ***list)
RETURN_FAIL("Could not open /sys/class/tty");
DEBUG("Iterating over results");
while (!readdir_r(dir, &entry, &result) && result) {
snprintf(buf, sizeof(buf), "/sys/class/tty/%s", entry.d_name);
while ((entry = readdir(dir))) {
snprintf(buf, sizeof(buf), "/sys/class/tty/%s", entry->d_name);
if (lstat(buf, &statbuf) == -1)
continue;
if (!S_ISLNK(statbuf.st_mode))
snprintf(buf, sizeof(buf), "/sys/class/tty/%s/device", entry.d_name);
snprintf(buf, sizeof(buf), "/sys/class/tty/%s/device", entry->d_name);
len = readlink(buf, target, sizeof(target));
if (len <= 0 || len >= (int)(sizeof(target) - 1))
continue;
target[len] = 0;
if (strstr(target, "virtual"))
continue;
snprintf(name, sizeof(name), "/dev/%s", entry.d_name);
snprintf(name, sizeof(name), "/dev/%s", entry->d_name);
DEBUG_FMT("Found device %s", name);
if (strstr(target, "serial8250")) {
/*
@ -215,7 +227,7 @@ SP_PRIV enum sp_return list_ports(struct sp_port ***list)
* is to try to open them and make an ioctl call.
*/
DEBUG("serial8250 device, attempting to open");
if ((fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0) {
if ((fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY | O_CLOEXEC)) < 0) {
DEBUG("Open failed, skipping");
continue;
}

View File

@ -65,7 +65,7 @@ SP_PRIV size_t get_termios_size(void)
#endif
}
#if (defined(HAVE_TERMIOS_SPEED) || defined(HAVE_TERMIOS2_SPEED)) && defined(HAVE_DECL_BOTHER)
#if (defined(HAVE_TERMIOS_SPEED) || defined(HAVE_TERMIOS2_SPEED)) && HAVE_DECL_BOTHER
SP_PRIV int get_termios_speed(void *data)
{
#ifdef HAVE_STRUCT_TERMIOS2

20
release.props Normal file
View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<_PropertySheetDisplayName>Release</_PropertySheetDisplayName>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>LIBSERIALPORT_MSBUILD;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
</Link>
</ItemDefinitionGroup>
<ItemGroup />
</Project>

View File

@ -21,8 +21,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "libserialport.h"
#include "libserialport_internal.h"
static const struct std_baudrate std_baudrates[] = {
@ -61,7 +59,7 @@ SP_API enum sp_return sp_get_port_by_name(const char *portname, struct sp_port *
#ifndef NO_PORT_METADATA
enum sp_return ret;
#endif
int len;
size_t len;
TRACE("%s, %p", portname, port_ptr);
@ -75,6 +73,20 @@ SP_API enum sp_return sp_get_port_by_name(const char *portname, struct sp_port *
DEBUG_FMT("Building structure for port %s", portname);
#if !defined(_WIN32) && defined(HAVE_REALPATH)
/*
* get_port_details() below tries to be too smart and figure out
* some transport properties from the port name which breaks with
* symlinks. Therefore we canonicalize the portname first.
*/
char pathbuf[PATH_MAX + 1];
char *res = realpath(portname, pathbuf);
if (!res)
RETURN_ERROR(SP_ERR_ARG, "Could not retrieve realpath behind port name");
portname = pathbuf;
#endif
if (!(port = malloc(sizeof(struct sp_port))))
RETURN_ERROR(SP_ERR_MEM, "Port structure malloc failed");
@ -90,6 +102,8 @@ SP_API enum sp_return sp_get_port_by_name(const char *portname, struct sp_port *
#ifdef _WIN32
port->usb_path = NULL;
port->hdl = INVALID_HANDLE_VALUE;
port->write_buf = NULL;
port->write_buf_size = 0;
#else
port->fd = -1;
#endif
@ -141,10 +155,7 @@ SP_API enum sp_transport sp_get_port_transport(const struct sp_port *port)
{
TRACE("%p", port);
if (!port)
RETURN_ERROR(SP_ERR_ARG, "Null port");
RETURN_INT(port->transport);
RETURN_INT(port ? port->transport : SP_TRANSPORT_NATIVE);
}
SP_API enum sp_return sp_get_port_usb_bus_address(const struct sp_port *port,
@ -296,6 +307,8 @@ SP_API void sp_free_port(struct sp_port *port)
#ifdef _WIN32
if (port->usb_path)
free(port->usb_path);
if (port->write_buf)
free(port->write_buf);
#endif
free(port);
@ -307,9 +320,10 @@ SP_PRIV struct sp_port **list_append(struct sp_port **list,
const char *portname)
{
void *tmp;
unsigned int count;
size_t count;
for (count = 0; list[count]; count++);
for (count = 0; list[count]; count++)
;
if (!(tmp = realloc(list, sizeof(struct sp_port *) * (count + 2))))
goto fail;
list = tmp;
@ -471,7 +485,7 @@ SP_API enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
if (flags & SP_MODE_WRITE)
desired_access |= GENERIC_WRITE;
port->hdl = CreateFile(escaped_port_name, desired_access, 0, 0,
port->hdl = CreateFileA(escaped_port_name, desired_access, 0, 0,
OPEN_EXISTING, flags_and_attributes, 0);
free(escaped_port_name);
@ -522,7 +536,7 @@ SP_API enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
RETURN_CODEVAL(ret);
}
#else
int flags_local = O_NONBLOCK | O_NOCTTY;
int flags_local = O_NONBLOCK | O_NOCTTY | O_CLOEXEC;
/* Map 'flags' to the OS-specific settings. */
if ((flags & SP_MODE_READ_WRITE) == SP_MODE_READ_WRITE)
@ -534,6 +548,39 @@ SP_API enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
if ((port->fd = open(port->name, flags_local)) < 0)
RETURN_FAIL("open() failed");
/*
* On POSIX in the default case the file descriptor of a serial port
* is not opened exclusively. Therefore the settings of a port are
* overwritten if the serial port is opened a second time. Windows
* opens all serial ports exclusively.
* So the idea is to open the serial ports alike in the exclusive mode.
*
* ioctl(*, TIOCEXCL) defines the file descriptor as exclusive. So all
* further open calls on the serial port will fail.
*
* There is a race condition if two processes open the same serial
* port. None of the processes will notice the exclusive ownership of
* the other process because ioctl() doesn't return an error code if
* the file descriptor is already marked as exclusive.
* This can be solved with flock(). It returns an error if the file
* descriptor is already locked by another process.
*/
#ifdef HAVE_FLOCK
if (flock(port->fd, LOCK_EX | LOCK_NB) < 0)
RETURN_FAIL("flock() failed");
#endif
#ifdef TIOCEXCL
/*
* Before Linux 3.8 ioctl(*, TIOCEXCL) was not implemented and could
* lead to EINVAL or ENOTTY.
* These errors aren't fatal and can be ignored.
*/
if (ioctl(port->fd, TIOCEXCL) < 0 && errno != EINVAL && errno != ENOTTY)
RETURN_FAIL("ioctl() failed");
#endif
#endif
ret = get_config(port, &data, &config);
@ -543,6 +590,15 @@ SP_API enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
RETURN_CODEVAL(ret);
}
/*
* Assume a default baudrate if the OS does not provide one.
* Cannot assign -1 here since Windows holds the baudrate in
* the DCB and does not configure the rate individually.
*/
if (config.baudrate == 0) {
config.baudrate = 9600;
}
/* Set sane port settings. */
#ifdef _WIN32
data.dcb.fBinary = TRUE;
@ -586,7 +642,8 @@ SP_API enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
data.term.c_cc[VTIME] = 0;
/* Ignore modem status lines; enable receiver; leave control lines alone on close. */
data.term.c_cflag |= (CLOCAL | CREAD | HUPCL);
data.term.c_cflag |= (CLOCAL | CREAD);
data.term.c_cflag &= ~(HUPCL);
#endif
#ifdef _WIN32
@ -628,6 +685,10 @@ SP_API enum sp_return sp_close(struct sp_port *port)
CLOSE_OVERLAPPED(write_ovl);
CLOSE_OVERLAPPED(wait_ovl);
if (port->write_buf) {
free(port->write_buf);
port->write_buf = NULL;
}
#else
/* Returns 0 upon success, -1 upon failure. */
if (close(port->fd) == -1)
@ -697,7 +758,9 @@ SP_API enum sp_return sp_drain(struct sp_port *port)
#else
int result;
while (1) {
#ifdef __ANDROID__
#if defined(__ANDROID__) && (__ANDROID_API__ < 21)
/* Android only has tcdrain from platform 21 onwards.
* On previous API versions, use the ioctl directly. */
int arg = 1;
result = ioctl(port->fd, TCSBRK, &arg);
#else
@ -717,6 +780,27 @@ SP_API enum sp_return sp_drain(struct sp_port *port)
#endif
}
#ifdef _WIN32
static enum sp_return await_write_completion(struct sp_port *port)
{
TRACE("%p", port);
DWORD bytes_written;
BOOL result;
/* Wait for previous non-blocking write to complete, if any. */
if (port->writing) {
DEBUG("Waiting for previous write to complete");
result = GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE);
port->writing = 0;
if (!result)
RETURN_FAIL("Previous write failed to complete");
DEBUG("Previous write completed");
}
RETURN_OK();
}
#endif
SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf,
size_t count, unsigned int timeout_ms)
{
@ -738,82 +822,87 @@ SP_API enum sp_return sp_blocking_write(struct sp_port *port, const void *buf,
RETURN_INT(0);
#ifdef _WIN32
DWORD bytes_written = 0;
BOOL result;
DWORD remaining_ms, write_size, bytes_written;
size_t remaining_bytes, total_bytes_written = 0;
const uint8_t *write_ptr = (uint8_t *) buf;
bool result;
struct timeout timeout;
/* Wait for previous non-blocking write to complete, if any. */
if (port->writing) {
DEBUG("Waiting for previous write to complete");
result = GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE);
port->writing = 0;
if (!result)
RETURN_FAIL("Previous write failed to complete");
DEBUG("Previous write completed");
}
timeout_start(&timeout, timeout_ms);
/* Set timeout. */
if (port->timeouts.WriteTotalTimeoutConstant != timeout_ms) {
port->timeouts.WriteTotalTimeoutConstant = timeout_ms;
if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
RETURN_FAIL("SetCommTimeouts() failed");
}
TRY(await_write_completion(port));
/* Start write. */
if (WriteFile(port->hdl, buf, count, NULL, &port->write_ovl)) {
DEBUG("Write completed immediately");
RETURN_INT(count);
} else if (GetLastError() == ERROR_IO_PENDING) {
DEBUG("Waiting for write to complete");
if (GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE) == 0) {
if (GetLastError() == ERROR_SEM_TIMEOUT) {
DEBUG("Write timed out");
RETURN_INT(0);
} else {
RETURN_FAIL("GetOverlappedResult() failed");
}
while (total_bytes_written < count) {
if (timeout_check(&timeout))
break;
remaining_ms = timeout_remaining_ms(&timeout);
if (port->timeouts.WriteTotalTimeoutConstant != remaining_ms) {
port->timeouts.WriteTotalTimeoutConstant = remaining_ms;
if (SetCommTimeouts(port->hdl, &port->timeouts) == 0)
RETURN_FAIL("SetCommTimeouts() failed");
}
DEBUG_FMT("Write completed, %d/%d bytes written", bytes_written, count);
RETURN_INT(bytes_written);
} else {
RETURN_FAIL("WriteFile() failed");
/* Reduce write size if it exceeds the WriteFile limit. */
remaining_bytes = count - total_bytes_written;
if (remaining_bytes > WRITEFILE_MAX_SIZE)
write_size = WRITEFILE_MAX_SIZE;
else
write_size = (DWORD) remaining_bytes;
/* Start write. */
result = WriteFile(port->hdl, write_ptr, write_size, NULL, &port->write_ovl);
timeout_update(&timeout);
if (result) {
DEBUG("Write completed immediately");
bytes_written = write_size;
} else if (GetLastError() == ERROR_IO_PENDING) {
DEBUG("Waiting for write to complete");
if (GetOverlappedResult(port->hdl, &port->write_ovl, &bytes_written, TRUE) == 0) {
if (GetLastError() == ERROR_SEM_TIMEOUT) {
DEBUG("Write timed out");
break;
} else {
RETURN_FAIL("GetOverlappedResult() failed");
}
}
DEBUG_FMT("Write completed, %d/%d bytes written", bytes_written, write_size);
} else {
RETURN_FAIL("WriteFile() failed");
}
write_ptr += bytes_written;
total_bytes_written += bytes_written;
}
RETURN_INT((int) total_bytes_written);
#else
size_t bytes_written = 0;
unsigned char *ptr = (unsigned char *) buf;
struct timeval start, delta, now, end = {0, 0};
int started = 0;
struct timeout timeout;
fd_set fds;
int result;
if (timeout_ms) {
/* Get time at start of operation. */
gettimeofday(&start, NULL);
/* Define duration of timeout. */
delta.tv_sec = timeout_ms / 1000;
delta.tv_usec = (timeout_ms % 1000) * 1000;
/* Calculate time at which we should give up. */
timeradd(&start, &delta, &end);
}
timeout_start(&timeout, timeout_ms);
FD_ZERO(&fds);
FD_SET(port->fd, &fds);
/* Loop until we have written the requested number of bytes. */
while (bytes_written < count) {
/*
* Check timeout only if we have run select() at least once,
* to avoid any issues if a short timeout is reached before
* select() is even run.
*/
if (timeout_ms && started) {
gettimeofday(&now, NULL);
if (timercmp(&now, &end, >))
/* Timeout has expired. */
break;
timersub(&end, &now, &delta);
}
result = select(port->fd + 1, NULL, &fds, NULL, timeout_ms ? &delta : NULL);
started = 1;
if (timeout_check(&timeout))
break;
result = select(port->fd + 1, NULL, &fds, NULL, timeout_timeval(&timeout));
timeout_update(&timeout);
if (result < 0) {
if (errno == EINTR) {
DEBUG("select() call was interrupted, repeating");
@ -865,8 +954,7 @@ SP_API enum sp_return sp_nonblocking_write(struct sp_port *port,
RETURN_INT(0);
#ifdef _WIN32
DWORD written = 0;
BYTE *ptr = (BYTE *) buf;
size_t buf_bytes;
/* Check whether previous write is complete. */
if (port->writing) {
@ -887,48 +975,43 @@ SP_API enum sp_return sp_nonblocking_write(struct sp_port *port,
RETURN_FAIL("SetCommTimeouts() failed");
}
/*
* Keep writing data until the OS has to actually start an async IO
* for it. At that point we know the buffer is full.
*/
while (written < count) {
/* Copy first byte of user buffer. */
port->pending_byte = *ptr++;
/* Reduce count if it exceeds the WriteFile limit. */
if (count > WRITEFILE_MAX_SIZE)
count = WRITEFILE_MAX_SIZE;
/* Start asynchronous write. */
if (WriteFile(port->hdl, &port->pending_byte, 1, NULL, &port->write_ovl) == 0) {
if (GetLastError() == ERROR_IO_PENDING) {
if (HasOverlappedIoCompleted(&port->write_ovl)) {
DEBUG("Asynchronous write completed immediately");
port->writing = 0;
written++;
continue;
} else {
DEBUG("Asynchronous write running");
port->writing = 1;
RETURN_INT(++written);
}
} else {
/* Actual failure of some kind. */
RETURN_FAIL("WriteFile() failed");
}
/* Copy data to our write buffer. */
buf_bytes = min(port->write_buf_size, count);
memcpy(port->write_buf, buf, buf_bytes);
/* Start asynchronous write. */
if (WriteFile(port->hdl, port->write_buf, (DWORD) buf_bytes, NULL, &port->write_ovl) == 0) {
if (GetLastError() == ERROR_IO_PENDING) {
if ((port->writing = !HasOverlappedIoCompleted(&port->write_ovl)))
DEBUG("Asynchronous write completed immediately");
else
DEBUG("Asynchronous write running");
} else {
DEBUG("Single byte written immediately");
written++;
/* Actual failure of some kind. */
RETURN_FAIL("WriteFile() failed");
}
}
DEBUG("All bytes written immediately");
RETURN_INT(written);
RETURN_INT((int) buf_bytes);
#else
/* Returns the number of bytes written, or -1 upon failure. */
ssize_t written = write(port->fd, buf, count);
if (written < 0)
RETURN_FAIL("write() failed");
else
if (written < 0) {
if (errno == EAGAIN)
// Buffer is full, no bytes written.
RETURN_INT(0);
else
RETURN_FAIL("write() failed");
} else {
RETURN_INT(written);
}
#endif
}
@ -973,7 +1056,7 @@ SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf,
RETURN_INT(0);
#ifdef _WIN32
DWORD bytes_read = 0;
DWORD bytes_read;
/* Set timeout. */
if (port->timeouts.ReadIntervalTimeout != 0 ||
@ -987,9 +1070,9 @@ SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf,
}
/* Start read. */
if (ReadFile(port->hdl, buf, count, NULL, &port->read_ovl)) {
if (ReadFile(port->hdl, buf, (DWORD) count, NULL, &port->read_ovl)) {
DEBUG("Read completed immediately");
bytes_read = count;
bytes_read = (DWORD) count;
} else if (GetLastError() == ERROR_IO_PENDING) {
DEBUG("Waiting for read to complete");
if (GetOverlappedResult(port->hdl, &port->read_ovl, &bytes_read, TRUE) == 0)
@ -1001,45 +1084,31 @@ SP_API enum sp_return sp_blocking_read(struct sp_port *port, void *buf,
TRY(restart_wait_if_needed(port, bytes_read));
RETURN_INT(bytes_read);
RETURN_INT((int) bytes_read);
#else
size_t bytes_read = 0;
unsigned char *ptr = (unsigned char *) buf;
struct timeval start, delta, now, end = {0, 0};
int started = 0;
struct timeout timeout;
fd_set fds;
int result;
if (timeout_ms) {
/* Get time at start of operation. */
gettimeofday(&start, NULL);
/* Define duration of timeout. */
delta.tv_sec = timeout_ms / 1000;
delta.tv_usec = (timeout_ms % 1000) * 1000;
/* Calculate time at which we should give up. */
timeradd(&start, &delta, &end);
}
timeout_start(&timeout, timeout_ms);
FD_ZERO(&fds);
FD_SET(port->fd, &fds);
/* Loop until we have the requested number of bytes. */
while (bytes_read < count) {
/*
* Check timeout only if we have run select() at least once,
* to avoid any issues if a short timeout is reached before
* select() is even run.
*/
if (timeout_ms && started) {
gettimeofday(&now, NULL);
if (timercmp(&now, &end, >))
/* Timeout has expired. */
break;
timersub(&end, &now, &delta);
}
result = select(port->fd + 1, &fds, NULL, NULL, timeout_ms ? &delta : NULL);
started = 1;
if (timeout_check(&timeout))
/* Timeout has expired. */
break;
result = select(port->fd + 1, &fds, NULL, NULL, timeout_timeval(&timeout));
timeout_update(&timeout);
if (result < 0) {
if (errno == EINTR) {
DEBUG("select() call was interrupted, repeating");
@ -1118,7 +1187,7 @@ SP_API enum sp_return sp_blocking_read_next(struct sp_port *port, void *buf,
/* Loop until we have at least one byte, or timeout is reached. */
while (bytes_read == 0) {
/* Start read. */
if (ReadFile(port->hdl, buf, count, &bytes_read, &port->read_ovl)) {
if (ReadFile(port->hdl, buf, (DWORD) count, &bytes_read, &port->read_ovl)) {
DEBUG("Read completed immediately");
} else if (GetLastError() == ERROR_IO_PENDING) {
DEBUG("Waiting for read to complete");
@ -1143,40 +1212,26 @@ SP_API enum sp_return sp_blocking_read_next(struct sp_port *port, void *buf,
#else
size_t bytes_read = 0;
struct timeval start, delta, now, end = {0, 0};
int started = 0;
struct timeout timeout;
fd_set fds;
int result;
if (timeout_ms) {
/* Get time at start of operation. */
gettimeofday(&start, NULL);
/* Define duration of timeout. */
delta.tv_sec = timeout_ms / 1000;
delta.tv_usec = (timeout_ms % 1000) * 1000;
/* Calculate time at which we should give up. */
timeradd(&start, &delta, &end);
}
timeout_start(&timeout, timeout_ms);
FD_ZERO(&fds);
FD_SET(port->fd, &fds);
/* Loop until we have at least one byte, or timeout is reached. */
while (bytes_read == 0) {
/*
* Check timeout only if we have run select() at least once,
* to avoid any issues if a short timeout is reached before
* select() is even run.
*/
if (timeout_ms && started) {
gettimeofday(&now, NULL);
if (timercmp(&now, &end, >))
/* Timeout has expired. */
break;
timersub(&end, &now, &delta);
}
result = select(port->fd + 1, &fds, NULL, NULL, timeout_ms ? &delta : NULL);
started = 1;
if (timeout_check(&timeout))
/* Timeout has expired. */
break;
result = select(port->fd + 1, &fds, NULL, NULL, timeout_timeval(&timeout));
timeout_update(&timeout);
if (result < 0) {
if (errno == EINTR) {
DEBUG("select() call was interrupted, repeating");
@ -1238,7 +1293,7 @@ SP_API enum sp_return sp_nonblocking_read(struct sp_port *port, void *buf,
}
/* Do read. */
if (ReadFile(port->hdl, buf, count, NULL, &port->read_ovl) == 0)
if (ReadFile(port->hdl, buf, (DWORD) count, NULL, &port->read_ovl) == 0)
if (GetLastError() != ERROR_IO_PENDING)
RETURN_FAIL("ReadFile() failed");
@ -1292,6 +1347,11 @@ SP_API enum sp_return sp_output_waiting(struct sp_port *port)
{
TRACE("%p", port);
#ifdef __CYGWIN__
/* TIOCOUTQ is not defined in Cygwin headers */
RETURN_ERROR(SP_ERR_SUPP,
"Getting output bytes waiting is not supported on Cygwin");
#else
CHECK_OPEN_PORT();
DEBUG_FMT("Checking output bytes waiting on port %s", port->name);
@ -1309,6 +1369,7 @@ SP_API enum sp_return sp_output_waiting(struct sp_port *port)
RETURN_FAIL("TIOCOUTQ ioctl failed");
RETURN_INT(bytes_waiting);
#endif
#endif
}
SP_API enum sp_return sp_new_event_set(struct sp_event_set **result_ptr)
@ -1426,11 +1487,9 @@ SP_API enum sp_return sp_wait(struct sp_event_set *event_set,
RETURN_OK();
#else
struct timeval start, delta, now, end = {0, 0};
const struct timeval max_delta = {
(INT_MAX / 1000), (INT_MAX % 1000) * 1000};
int started = 0, timeout_overflow = 0;
int result, timeout_remaining_ms;
struct timeout timeout;
int poll_timeout;
int result;
struct pollfd *pollfds;
unsigned int i;
@ -1438,7 +1497,7 @@ SP_API enum sp_return sp_wait(struct sp_event_set *event_set,
RETURN_ERROR(SP_ERR_MEM, "pollfds malloc() failed");
for (i = 0; i < event_set->count; i++) {
pollfds[i].fd = ((int *) event_set->handles)[i];
pollfds[i].fd = ((int *)event_set->handles)[i];
pollfds[i].events = 0;
pollfds[i].revents = 0;
if (event_set->masks[i] & SP_EVENT_RX_READY)
@ -1449,42 +1508,24 @@ SP_API enum sp_return sp_wait(struct sp_event_set *event_set,
pollfds[i].events |= POLLERR;
}
if (timeout_ms) {
/* Get time at start of operation. */
gettimeofday(&start, NULL);
/* Define duration of timeout. */
delta.tv_sec = timeout_ms / 1000;
delta.tv_usec = (timeout_ms % 1000) * 1000;
/* Calculate time at which we should give up. */
timeradd(&start, &delta, &end);
}
timeout_start(&timeout, timeout_ms);
timeout_limit(&timeout, INT_MAX);
/* Loop until an event occurs. */
while (1) {
/*
* Check timeout only if we have run poll() at least once,
* to avoid any issues if a short timeout is reached before
* poll() is even run.
*/
if (!timeout_ms) {
timeout_remaining_ms = -1;
} else if (!started) {
timeout_overflow = (timeout_ms > INT_MAX);
timeout_remaining_ms = timeout_overflow ? INT_MAX : timeout_ms;
} else {
gettimeofday(&now, NULL);
if (timercmp(&now, &end, >)) {
DEBUG("Wait timed out");
break;
}
timersub(&end, &now, &delta);
if ((timeout_overflow = timercmp(&delta, &max_delta, >)))
delta = max_delta;
timeout_remaining_ms = delta.tv_sec * 1000 + delta.tv_usec / 1000;
if (timeout_check(&timeout)) {
DEBUG("Wait timed out");
break;
}
result = poll(pollfds, event_set->count, timeout_remaining_ms);
started = 1;
poll_timeout = (int) timeout_remaining_ms(&timeout);
if (poll_timeout == 0)
poll_timeout = -1;
result = poll(pollfds, event_set->count, poll_timeout);
timeout_update(&timeout);
if (result < 0) {
if (errno == EINTR) {
@ -1496,7 +1537,7 @@ SP_API enum sp_return sp_wait(struct sp_event_set *event_set,
}
} else if (result == 0) {
DEBUG("poll() timed out");
if (!timeout_overflow)
if (!timeout.overflow)
break;
} else {
DEBUG("poll() completed");
@ -1647,28 +1688,25 @@ static enum sp_return get_config(struct sp_port *port, struct port_data *data,
config->bits = data->dcb.ByteSize;
if (data->dcb.fParity)
switch (data->dcb.Parity) {
case NOPARITY:
config->parity = SP_PARITY_NONE;
break;
case ODDPARITY:
config->parity = SP_PARITY_ODD;
break;
case EVENPARITY:
config->parity = SP_PARITY_EVEN;
break;
case MARKPARITY:
config->parity = SP_PARITY_MARK;
break;
case SPACEPARITY:
config->parity = SP_PARITY_SPACE;
break;
default:
config->parity = -1;
}
else
switch (data->dcb.Parity) {
case NOPARITY:
config->parity = SP_PARITY_NONE;
break;
case ODDPARITY:
config->parity = SP_PARITY_ODD;
break;
case EVENPARITY:
config->parity = SP_PARITY_EVEN;
break;
case MARKPARITY:
config->parity = SP_PARITY_MARK;
break;
case SPACEPARITY:
config->parity = SP_PARITY_SPACE;
break;
default:
config->parity = -1;
}
switch (data->dcb.StopBits) {
case ONESTOPBIT:
@ -1848,6 +1886,10 @@ static enum sp_return set_config(struct sp_port *port, struct port_data *data,
DEBUG_FMT("Setting configuration for port %s", port->name);
#ifdef _WIN32
BYTE* new_buf;
TRY(await_write_completion(port));
if (config->baudrate >= 0) {
for (i = 0; i < NUM_STD_BAUDRATES; i++) {
if (config->baudrate == std_baudrates[i].value) {
@ -1858,6 +1900,13 @@ static enum sp_return set_config(struct sp_port *port, struct port_data *data,
if (i == NUM_STD_BAUDRATES)
data->dcb.BaudRate = config->baudrate;
/* Allocate write buffer for 50ms of data at baud rate. */
port->write_buf_size = max(config->baudrate / (8 * 20), 1);
new_buf = realloc(port->write_buf, port->write_buf_size);
if (!new_buf)
RETURN_ERROR(SP_ERR_MEM, "Allocating write buffer failed");
port->write_buf = new_buf;
}
if (config->bits >= 0)
@ -2477,17 +2526,17 @@ SP_API char *sp_last_error_message(void)
TRACE_VOID();
#ifdef _WIN32
TCHAR *message;
char *message;
DWORD error = GetLastError();
DWORD length = FormatMessage(
DWORD length = FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
error,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &message,
(LPSTR) &message,
0, NULL );
if (length >= 2 && message[length - 2] == '\r')

69
test_timing.c Normal file
View File

@ -0,0 +1,69 @@
#include "config.h"
#include "libserialport.h"
#include "libserialport_internal.h"
#include <assert.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
(void) argc;
(void) argv;
struct time a, b, c;
struct timeval tv;
struct timeout to;
printf("Testing arithmetic\n");
time_set_ms(&a, 10050);
time_set_ms(&b, 100);
assert(time_greater(&a, &b));
assert(!time_greater(&b, &a));
time_add(&a, &b, &c);
assert(time_as_ms(&c) == 10150);
time_sub(&a, &b, &c);
assert(time_as_ms(&c) == 9950);
time_as_timeval(&a, &tv);
assert(tv.tv_sec == 10);
assert(tv.tv_usec == 50000);
time_get(&a);
printf("Sleeping for 1s\n");
sleep(1);
time_get(&b);
time_sub(&b, &a, &c);
printf("Measured: %ums\n", time_as_ms(&c));
assert(time_as_ms(&c) >= 950);
assert(time_as_ms(&c) <= 1050);
printf("Starting 3s timeout\n");
timeout_start(&to, 3000);
printf("Time to wait: %dms\n", timeout_remaining_ms(&to));
printf("Sleeping for 1s\n");
sleep(1);
timeout_update(&to);
assert(!timeout_check(&to));
printf("Sleeping for 1s\n");
sleep(1);
timeout_update(&to);
assert(!timeout_check(&to));
printf("Remaining: %ums\n", timeout_remaining_ms(&to));
printf("Sleeping for 1s\n");
sleep(1);
timeout_update(&to);
assert(timeout_check(&to));
printf("Timeout expired\n");
printf("Starting 2s timeout\n");
timeout_start(&to, 2000);
printf("Limiting steps to 1s\n");
timeout_limit(&to, 1000);
printf("Time to wait: %ums\n", timeout_remaining_ms(&to));
printf("Sleeping for 1s\n");
sleep(1);
timeout_update(&to);
assert(!timeout_check(&to));
printf("Remaining: %ums\n", timeout_remaining_ms(&to));
printf("Sleeping for 1s\n");
sleep(1);
timeout_update(&to);
assert(timeout_check(&to));
printf("Timeout expired\n");
return 0;
}

174
timing.c Normal file
View File

@ -0,0 +1,174 @@
/*
* This file is part of the libserialport project.
*
* Copyright (C) 2019 Martin Ling <martin-libserialport@earth.li>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "libserialport_internal.h"
SP_PRIV void time_get(struct time *time)
{
#ifdef _WIN32
LARGE_INTEGER count;
QueryPerformanceCounter(&count);
time->ticks = count.QuadPart;
#elif defined(HAVE_CLOCK_GETTIME)
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
clock_gettime(CLOCK_REALTIME, &ts);
time->tv.tv_sec = ts.tv_sec;
time->tv.tv_usec = ts.tv_nsec / 1000;
#elif defined(__APPLE__)
mach_timebase_info_data_t info;
mach_timebase_info(&info);
uint64_t ticks = mach_absolute_time();
uint64_t ns = (ticks * info.numer) / info.denom;
time->tv.tv_sec = ns / 1000000000;
time->tv.tv_usec = (ns % 1000000000) / 1000;
#else
gettimeofday(&time->tv, NULL);
#endif
}
SP_PRIV void time_set_ms(struct time *time, unsigned int ms)
{
#ifdef _WIN32
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
time->ticks = ms * (frequency.QuadPart / 1000);
#else
time->tv.tv_sec = ms / 1000;
time->tv.tv_usec = (ms % 1000) * 1000;
#endif
}
SP_PRIV void time_add(const struct time *a,
const struct time *b, struct time *result)
{
#ifdef _WIN32
result->ticks = a->ticks + b->ticks;
#else
timeradd(&a->tv, &b->tv, &result->tv);
#endif
}
SP_PRIV void time_sub(const struct time *a,
const struct time *b, struct time *result)
{
#ifdef _WIN32
result->ticks = a->ticks - b->ticks;
#else
timersub(&a->tv, &b->tv, &result->tv);
#endif
}
SP_PRIV bool time_greater(const struct time *a, const struct time *b)
{
#ifdef _WIN32
return (a->ticks > b->ticks);
#else
return timercmp(&a->tv, &b->tv, >);
#endif
}
SP_PRIV void time_as_timeval(const struct time *time, struct timeval *tv)
{
#ifdef _WIN32
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
tv->tv_sec = (long) (time->ticks / frequency.QuadPart);
tv->tv_usec = (long) ((time->ticks % frequency.QuadPart) /
(frequency.QuadPart / 1000000));
#else
*tv = time->tv;
#endif
}
SP_PRIV unsigned int time_as_ms(const struct time *time)
{
#ifdef _WIN32
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
return (unsigned int) (time->ticks / (frequency.QuadPart / 1000));
#else
return time->tv.tv_sec * 1000 + time->tv.tv_usec / 1000;
#endif
}
SP_PRIV void timeout_start(struct timeout *timeout, unsigned int timeout_ms)
{
timeout->ms = timeout_ms;
/* Get time at start of operation. */
time_get(&timeout->start);
/* Define duration of timeout. */
time_set_ms(&timeout->delta, timeout_ms);
/* Calculate time at which we should give up. */
time_add(&timeout->start, &timeout->delta, &timeout->end);
/* Disable limit unless timeout_limit() called. */
timeout->limit_ms = 0;
/* First blocking call has not yet been made. */
timeout->calls_started = false;
}
SP_PRIV void timeout_limit(struct timeout *timeout, unsigned int limit_ms)
{
timeout->limit_ms = limit_ms;
timeout->overflow = (timeout->ms > timeout->limit_ms);
time_set_ms(&timeout->delta_max, timeout->limit_ms);
}
SP_PRIV bool timeout_check(struct timeout *timeout)
{
if (!timeout->calls_started)
return false;
if (timeout->ms == 0)
return false;
time_get(&timeout->now);
time_sub(&timeout->end, &timeout->now, &timeout->delta);
if (timeout->limit_ms)
if ((timeout->overflow = time_greater(&timeout->delta, &timeout->delta_max)))
timeout->delta = timeout->delta_max;
return time_greater(&timeout->now, &timeout->end);
}
SP_PRIV void timeout_update(struct timeout *timeout)
{
timeout->calls_started = true;
}
#ifndef _WIN32
SP_PRIV struct timeval *timeout_timeval(struct timeout *timeout)
{
if (timeout->ms == 0)
return NULL;
time_as_timeval(&timeout->delta, &timeout->delta_tv);
return &timeout->delta_tv;
}
#endif
SP_PRIV unsigned int timeout_remaining_ms(struct timeout *timeout)
{
if (timeout->limit_ms && timeout->overflow)
return timeout->limit_ms;
else
return time_as_ms(&timeout->delta);
}

View File

@ -18,8 +18,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include "libserialport.h"
#include "libserialport_internal.h"
/* USB path is a string of at most 8 decimal numbers < 128 separated by dots. */
@ -28,31 +26,42 @@
static void enumerate_hub(struct sp_port *port, const char *hub_name,
const char *parent_path, DEVINST dev_inst);
static char *wc_to_utf8(PWCHAR wc_buffer, ULONG size)
static char *wc_to_utf8(PWCHAR wc_buffer, ULONG wc_bytes)
{
WCHAR wc_str[(size / sizeof(WCHAR)) + 1];
char *utf8_str;
ULONG wc_length = wc_bytes / sizeof(WCHAR);
ULONG utf8_bytes;
WCHAR *wc_str = NULL;
char *utf8_str = NULL;
/* Allocate aligned wide char buffer */
if (!(wc_str = malloc((wc_length + 1) * sizeof(WCHAR))))
goto wc_to_utf8_end;
/* Zero-terminate the wide char string. */
memcpy(wc_str, wc_buffer, size);
wc_str[sizeof(wc_str) - 1] = 0;
memcpy(wc_str, wc_buffer, wc_bytes);
wc_str[wc_length] = 0;
/* Compute the size of the UTF-8 converted string. */
if (!(size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1,
if (!(utf8_bytes = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1,
NULL, 0, NULL, NULL)))
return NULL;
goto wc_to_utf8_end;
/* Allocate UTF-8 output buffer. */
if (!(utf8_str = malloc(size)))
return NULL;
if (!(utf8_str = malloc(utf8_bytes)))
goto wc_to_utf8_end;
/* Actually converted to UTF-8. */
if (!WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1,
utf8_str, size, NULL, NULL)) {
utf8_str, utf8_bytes, NULL, NULL)) {
free(utf8_str);
return NULL;
utf8_str = NULL;
goto wc_to_utf8_end;
}
wc_to_utf8_end:
if (wc_str)
free(wc_str);
return utf8_str;
}
@ -81,7 +90,7 @@ static char *get_root_hub_name(HANDLE host_controller)
}
/* Convert the root hub name string to UTF-8. */
root_hub_name_utf8 = wc_to_utf8(root_hub_name_wc->RootHubName, size);
root_hub_name_utf8 = wc_to_utf8(root_hub_name_wc->RootHubName, size - offsetof(USB_ROOT_HUB_NAME, RootHubName));
free(root_hub_name_wc);
return root_hub_name_utf8;
}
@ -116,7 +125,7 @@ static char *get_external_hub_name(HANDLE hub, ULONG connection_index)
}
/* Convert the external hub name string to UTF-8. */
ext_hub_name_utf8 = wc_to_utf8(ext_hub_name_wc->NodeName, size);
ext_hub_name_utf8 = wc_to_utf8(ext_hub_name_wc->NodeName, size - offsetof(USB_NODE_CONNECTION_NAME, NodeName));
free(ext_hub_name_wc);
return ext_hub_name_utf8;
}
@ -134,7 +143,7 @@ static char *get_string_descriptor(HANDLE hub_device, ULONG connection_index,
desc_req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8)
| descriptor_index;
desc_req->SetupPacket.wIndex = 0;
desc_req->SetupPacket.wLength = size - sizeof(*desc_req);
desc_req->SetupPacket.wLength = (USHORT) (size - sizeof(*desc_req));
if (!DeviceIoControl(hub_device,
IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
@ -145,7 +154,7 @@ static char *get_string_descriptor(HANDLE hub_device, ULONG connection_index,
|| desc->bLength % 2)
return NULL;
return wc_to_utf8(desc->bString, desc->bLength);
return wc_to_utf8(desc->bString, desc->bLength - offsetof(USB_STRING_DESCRIPTOR, bString));
}
static void enumerate_hub_ports(struct sp_port *port, HANDLE hub_device,
@ -219,7 +228,7 @@ static void enumerate_hub_ports(struct sp_port *port, HANDLE hub_device,
port->usb_pid = connection_info_ex->DeviceDescriptor.idProduct;
if (connection_info_ex->DeviceDescriptor.iManufacturer)
port->usb_manufacturer = get_string_descriptor(hub_device,index,
port->usb_manufacturer = get_string_descriptor(hub_device, index,
connection_info_ex->DeviceDescriptor.iManufacturer);
if (connection_info_ex->DeviceDescriptor.iProduct)
port->usb_product = get_string_descriptor(hub_device, index,
@ -256,8 +265,8 @@ static void enumerate_hub(struct sp_port *port, const char *hub_name,
return;
strcpy(device_name, "\\\\.\\");
strcat(device_name, hub_name);
hub_device = CreateFile(device_name, GENERIC_WRITE, FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
hub_device = CreateFileA(device_name, GENERIC_WRITE, FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
free(device_name);
if (hub_device == INVALID_HANDLE_VALUE)
return;
@ -380,7 +389,7 @@ SP_PRIV enum sp_return get_port_details(struct sp_port *port)
continue;
}
RegCloseKey(device_key);
value[sizeof(value)-1] = 0;
value[sizeof(value) - 1] = 0;
if (strcmp(value, port->name))
continue;
@ -458,9 +467,9 @@ SP_PRIV enum sp_return get_port_details(struct sp_port *port)
if (!(escaped_port_name = malloc(strlen(port->name) + 5)))
RETURN_ERROR(SP_ERR_MEM, "Escaped port name malloc failed");
sprintf(escaped_port_name, "\\\\.\\%s", port->name);
handle = CreateFile(escaped_port_name, GENERIC_READ, 0, 0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0);
handle = CreateFileA(escaped_port_name, GENERIC_READ, 0, 0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0);
free(escaped_port_name);
CloseHandle(handle);
@ -482,19 +491,26 @@ SP_PRIV enum sp_return list_ports(struct sp_port ***list)
DWORD max_value_len, max_data_size, max_data_len;
DWORD value_len, data_size, data_len;
DWORD type, index = 0;
LSTATUS result;
char *name;
int name_len;
int ret = SP_OK;
DEBUG("Opening registry key");
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) {
SET_FAIL(ret, "RegOpenKeyEx() failed");
if ((result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
0, KEY_QUERY_VALUE, &key)) != ERROR_SUCCESS) {
/* It's possible for this key to not exist if there are no serial ports
* at all. In that case we're done. Return a failure for any other error. */
if (result != ERROR_FILE_NOT_FOUND) {
SetLastError(result);
SET_FAIL(ret, "RegOpenKeyEx() failed");
}
goto out_done;
}
DEBUG("Querying registry key value and data sizes");
if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
&max_value_len, &max_data_size, NULL, NULL) != ERROR_SUCCESS) {
if ((result = RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
&max_value_len, &max_data_size, NULL, NULL)) != ERROR_SUCCESS) {
SetLastError(result);
SET_FAIL(ret, "RegQueryInfoKey() failed");
goto out_close;
}