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

227 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
0c3f38b81b linux: freebsd: do check on proper pointer
We want to check here if we added something to the list, not if the
function argument was valid. Problem spotted by Coverity, CID 50754.

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2016-02-28 18:01:25 +01:00
3fcdc9f7d5 Bump libtool version (not package version) to 1:0:1.
The last release (0.1.0) had the libtool version (current:revision:age)
set to 0:0:0. Since this release doesn't change/remove any
interfaces (it does *add* new interfaces, though), 'current' and 'age'
are increased and 'revision' is set to 0, resulting in 1:0:1.

http://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info

Programs using libserialport don't need to be recompiled or relinked.
2016-01-27 12:36:01 +01:00
24a38c8094 NEWS: Last updates for the upcoming 0.1.1 release. 2016-01-27 12:36:01 +01:00
aee7d69195 Fix ERROR_SEM_TIMEOUT issue on Windows.
The sp_blocking_write() call was incorrectly returning an error upon
ERROR_SEM_TIMEOUT. It now returns 0 instead.
2016-01-27 12:35:45 +01:00
888fb45d66 Fix sp_blocking_read_next() implementation on Windows.
A ReadFile() call needed to check the actual number of bytes read,
instead of assuming all requested bytes were read.
2016-01-22 15:32:00 +01:00
02c8a1424d windows: Fix iSerial for composite devices.
USB composite devices can contain an ACM serial interface.
On Windows, the correct iSerial descriptor field is assigned to the parent
(composite) device instead of to the actual serial interface. A bogus
value is returned if the serial interface is asked to provide the S/N.
This patch provides a fallback for this kind of device (tested on Android
with adb + cdc gadgets and on Arduino Zero Programming Port)
2016-01-06 13:54:17 +00:00
aacba60dca macosx: Fix port listing on ElCapitan.
On OSX 10.11 (ElCapitan) the query for IOProviderClass fails to list ACM
devices as USB.
Add a fallback query using IOClass to correctly recognize these devices.
The fix has no effect on previous OSX versions (tested on Mavericks)
2016-01-06 13:54:11 +00:00
8062087ab3 Change debug message to "Port not open" when a closed port is used.
Fixes bug #710.
2015-12-29 13:30:30 +01:00
4d8195fe3f libserialport_internal: use new macro to enable timeradd, etc.
Since glibc 2.20, the usage of _BSD_SOURCE is deprecated. Fix it like
described here:

https://sourceware.org/glibc/wiki/Release/2.20#Deprecation_of__BSD_SOURCE_and__SVID_SOURCE_feature_macros

This fixes bug #716.

Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2015-12-29 01:16:28 +01:00
ae2c5825e7 windows: Handle ERROR_IO_PENDING from ReadFile in sp_nonblocking_read().
This fixes bug #707.
2015-12-09 12:43:11 +01:00
127d8d0ce7 sp_wait: Avoid overflow of timeout parameter to poll(). 2015-10-13 15:04:03 +01:00
1a584c45b0 Build: Include config.h first in all source files 2015-09-13 20:04:31 +02:00
962143bc5c Build: Use GNUMAKEFLAGS and $@ 2015-09-10 22:19:15 +02:00
c37c9f348d autogen.sh: Create autostuff/ dir if it does not exist 2015-08-27 11:46:06 +02:00
07f61c7131 configure: Enable largefile support on 32-bit systems 2015-08-26 22:49:40 +02:00
87f4a6f021 Clean up .gitignore 2015-08-26 22:01:03 +02:00
f1c916ede1 Build: Clean up configure.ac and Makefile.am
Among other things, rename some config defines so we can take
advantage of standard Autoconf macros.
2015-08-26 21:55:10 +02:00
ef08a6d52b Build: Reduce autogen.sh to trivial stub
Use autoreconf instead of invoking the various Auto tools
separately. Get rid of the Darwin-specific guesswork -- it does
not make sense to handle this at the level of libserialport.

People should set up their ACLOCAL_PATH themselves as appropriate
for their own system; just as they already need to set up various
other paths.
2015-08-26 19:46:43 +02:00
f77bb46df5 Update copyright notices. 2015-05-31 18:26:53 +02:00
d931da1042 Update AUTHORS file. 2015-05-31 18:26:53 +02:00
e2b7ba1214 NEWS: Update for the upcoming 0.1.1 release. 2015-05-30 22:11:46 +02:00
56fe6e3207 doc: Provided channel is binary, not necessarily 8-bit. 2015-05-30 21:03:38 +01:00
6b8eee0682 Fix possible use of uninitialised variable in poll() setup. 2015-05-30 21:38:03 +02:00
49fd7b1bc2 doc: Additional introductory text. 2015-05-30 21:38:03 +02:00
deef6e528c doc: Expanded introductory text. 2015-05-27 11:19:27 +02:00
ec4b55ae25 doc: Additional notes on sp_last_error_{code,message}. 2015-05-27 11:09:26 +02:00
46d8b0a039 Handle the case when /sys/class/tty/ entries are not symlinks.
For example:

$ uname -a
Linux RT-N66U 2.6.22.19 #1 Thu Feb 12 20:33:36 CST 2015 mips GNU/Linux

$ ls -lF /sys/class/tty/
drwxr-xr-x    2 foo  root             0 May 18 18:12 ttyACM0/

$ ls -lF /sys/class/tty/ttyACM0/
-r--r--r--    1 foo  root          4096 May 18 18:12 dev
lrwxrwxrwx    1 foo  root             0 May 18 18:12 device -> ../../../devices/pci0000:00/0000:00:04.1/usb1/1-1/1-1.1/1-1.1:1.0/
lrwxrwxrwx    1 foo  root             0 May 18 18:12 subsystem -> ../../../class/tty/
-rw-r--r--    1 foo  root          4096 May 18 18:12 uevent
2015-05-27 11:09:26 +02:00
e5c2630eee Add new sp_blocking_read_next() function. 2015-05-27 11:09:26 +02:00
0188a545c7 windows: Always check and set ReadTotalTimeoutMultiplier.
This is not currently touched, but will be by the upcoming
sp_blocking_read_next() function.
2015-05-27 11:09:25 +02:00
76222ee578 posix: Make sure blocking operations can't time out without trying. 2015-05-27 11:09:25 +02:00
c3cee38c3b posix: Consistent debug output when blocking operations time out. 2015-05-27 11:09:25 +02:00
772c586133 posix: Move FD_ZERO() and FD_SET() calls outside loops. 2015-05-27 11:09:25 +02:00
27911925c1 windows: Always check return value of GetOverlappedResult(). 2015-05-27 11:09:25 +02:00
bbe566fe1c windows: Restructure if/else blocks with unnecessary indentation. 2015-05-27 11:09:25 +02:00
8ebfaf8966 windows: restart_wait_if_needed(): Inline receive buffer check.
This removes all the debug spam arising from calling sp_input_waiting().
2015-05-27 11:09:25 +02:00
21ae5ce197 windows: restart_wait_if_needed(): Skip buffer check if no bytes read. 2015-05-27 11:09:25 +02:00
94a314a806 windows: Refactor duplicated code into a static function. 2015-05-27 11:09:25 +02:00
27a58c0521 windows: Avoid unnecessary calls to SetCommTimeouts().
This fixes bug #586.
2015-05-27 11:09:13 +02:00
9a0c4bbdbe windows: Strip CR/LF from end of system error messages.
This fixes bug #585.
2015-05-27 11:08:30 +02:00
480d750c59 doc: correct structure name in sp_get_port_handle() documentation. 2015-05-06 16:33:13 +01:00
ff6da776e8 libserialport.h.in: Fix/update some API docs. 2015-05-06 17:06:06 +02:00
6392641545 sp_list_ports(): Actually set list_ptr NULL as documented. 2015-05-06 17:06:06 +02:00
6aad5bdd47 Fix a potential segfault in sp_get_config_*(). 2015-05-06 17:06:06 +02:00
5f64c28551 Fix a potential segfault in sp_get_port_handle(). 2015-05-06 17:06:05 +02:00
eb50b1aca6 windows.c: Constify a few function parameters. 2015-04-19 19:50:56 +02:00
9eb9f07130 sp_get_port_usb_vid_pid(): Document that usb_vid/usb_pid can be NULL. 2015-04-19 19:18:05 +02:00
1b91c6eadb Rename timeout to timeout_ms for clarity in a few places. 2015-04-19 19:01:08 +02:00
025c264448 autotools: Don't set/override "user variables".
This fixes bug #577.
2015-04-19 19:01:08 +02:00
a630a469f6 Makefile.am: Simplify LDFLAGS handling a bit. 2015-04-19 19:01:08 +02:00
f14809393a Constify the sp_get_port_description() parameter. 2015-04-19 19:01:08 +02:00
ad036cc8ef Constify the sp_get_port_transport() parameter. 2015-04-19 18:28:10 +02:00
3dd4a2ae39 configure.ac: Drop no longer needed SP_PKGLIBS. 2015-04-19 18:21:19 +02:00
35578b063e Various Doxygen comment updates and fixes.
- Add some missing @param lines.

 - Add [in], [out], or [in,out] markers for @param tags.

 - Add explicit "Must not be NULL" comments for parameters where
   the caller should not pass in a NULL.
2015-04-19 18:16:01 +02:00
e4f44cf5f2 libserialport.h.in: Drop unneeded <windows.h> #include.
This is not needed and would pollute the namespace of every
libserialport user on Windows.
2015-04-19 18:15:29 +02:00
13efecf888 libserialport.h.in: Add @since tags for new enums. 2015-04-19 18:14:48 +02:00
3f2f48fc01 Set package version to 0.1.1, use "@since 0.1.1" Doxygen tags.
The next release will not contain any backwards-incompatible
API or ABI changes, thus changing the package version to 0.1.1.
2015-04-19 18:13:53 +02:00
777347a6bd windows: Drop no longer needed -luuid.
Also, use SP_LIBS in Makefile.am.

This is build-tested using a native MinGW-w64 based toolchain
as well as a MinGW-w64 based cross-compile setup.
2015-04-18 21:54:42 +02:00
8c6de591a5 configure.ac: Minor whitespace cosmetics. 2015-04-18 21:54:42 +02:00
1ff591d7b3 Doxyfile: Update to Doxygen 1.8.8 template.
(by running 'doxygen -u')
2015-04-18 21:54:42 +02:00
5ca38cdfe0 configure.ac: Add #include guard to config.h. 2015-04-18 21:54:42 +02:00
613c48f191 Fix a compiler warning when -Wshadow is used.
CC       serialport.lo
  In file included from ../serialport.c:25:0:
  ../serialport.c: In function 'get_config':
  ../libserialport_internal.h:227:25: warning: declaration of 'ret' shadows a previous local [-Wshadow]
   #define TRY(x) do { int ret = x; if (ret != SP_OK) RETURN_CODEVAL(ret); } while (0)
                           ^
  ../serialport.c:1566:3: note: in expansion of macro 'TRY'
     TRY(get_baudrate(port->fd, &config->baudrate));
     ^
  ../serialport.c:1543:6: warning: shadowed declaration is here [-Wshadow]
    int ret = get_flow(port->fd, data);
        ^

Also, add -Wshadow to the list of default compiler options.
2015-04-18 21:54:42 +02:00
b3e619c8b2 autogen.sh: Drop obsolete MinGW/MSYS items.
For Windows builds (which require MinGW-w64) we currently support:

 - cross-builds using MXE (mxe.cc) and possibly other cross-compile setups

 - native builds using MSYS2 (sf.net/projects/msys2/)

Neither of those require explicitly specifying ACLOCAL_DIR.
2015-04-07 02:35:03 +02:00
f11a67ed5f README: Refer to MSYS2 only.
The "old" MSYS related to the "old" and unsupported MinGW (from
mingw.org) may or may not work properly, so only refer to MSYS2 which
we currently recommend and which has been tested.
2015-04-07 01:32:40 +02:00
144a598f19 Minor Doxygen improvements and fixes. 2015-04-07 01:32:40 +02:00
3cb7aa98c2 configure.ac: Use $host_os instead of $target_os.
$build and $build_os refer to the machine on which the software is
built, $host and $host_os refer to the machine for which the software
is (cross-)built.

The variables $target and $target_os (despite the confusing names)
are only relevant in the context of building cross-compilers.
2015-04-07 00:49:27 +02:00
cd71af4b93 README: Add link to online API docs. 2015-04-03 22:18:56 +02:00
a24671ade9 README: Mention FreeBSD port enumeration support. 2015-04-03 22:17:57 +02:00
1cda3e3dfc configure.ac: Add -Wmissing-prototypes. 2015-04-03 22:13:06 +02:00
23e7fa372a Fix two compiler warnings on platforms without enumeration support.
serialport.c: In function 'sp_list_ports':
  serialport.c:326:6: warning: unused variable 'ret' [-Wunused-variable]
    int ret;
        ^
  serialport.c:325:19: warning: unused variable 'list' [-Wunused-variable]
    struct sp_port **list;
                     ^
2015-04-03 22:11:07 +02:00
ac323d80e0 add_handle(): Fix a realloc() related issue. 2015-04-03 22:02:42 +02:00
e019e72ec0 Fix a compiler warning.
This fixes the following scan-build warning:

  serialport.c: In function 'sp_list_ports':
  serialport.c:354:1: warning: control reaches end of non-void function [-Wreturn-type]
2015-04-03 20:50:22 +02:00
b344a40bb2 Fix indentation of a switch(). 2015-04-03 17:51:47 +02:00
948f63f0fd add_handle(): Fix a memory leak.
This fixes the following scan-build warning:

  serialport.c:1170:3: warning: Potential leak of memory pointed to by 'new_handles'
                  RETURN_ERROR(SP_ERR_MEM, "Mask array realloc() failed");
                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2015-04-03 17:51:41 +02:00
5122d60849 Use libtool's -no-undefined option on all platforms. 2015-04-03 17:48:14 +02:00
8d12e620f2 Clarify sp_list_ports() code.
This also fixes the following scan-build warning:

  serialport.c:335:15: warning: Result of 'malloc' is converted to a
  pointer of type 'struct sp_port *', which is incompatible with sizeof
  operand type 'struct sp_port **'
          if (!(list = malloc(sizeof(struct sp_port **))))
                       ^~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~
2015-04-03 17:46:26 +02:00
34442106ef windows: Set fAbortOnError=FALSE.
Since we're not handling and clearing receive errors (framing, parity and
overrun), we should turn them off to avoid crashing out with
ERROR_OPERATION_ABORTED in various calls if they occur. Invalid data
will then simply not end up in the buffer. This is consistent with our
current behaviour on posix/termios systems.

It might be nice to be able to inform calling code about receive errors, but I
can't see a good way to do this in a cross-platform way at the moment.

This fixes (parts of) bug #341.
2015-03-29 22:18:46 +02:00
47fcf8ec85 windows: Revise management of WaitCommEvent() operations.
This fixes (at least parts of) bug #341.
2015-03-29 22:18:46 +02:00
6c6aebe78c Make std_baudrates[] static (only used in one file). 2015-03-26 23:57:56 +01:00
dc422c04af Various cosmetic and consistency fixes. 2015-03-26 23:57:56 +01:00
2b40f81454 libserialport_internal.h: Add #include guard. 2015-03-26 23:57:56 +01:00
cfa5af67fd Fix some typos. 2015-03-26 23:57:55 +01:00
64155cba8a linux_termios.h: Add missing #include of "config.h". 2015-03-25 14:52:54 +01:00
7c081505e5 Generate a config.h rather than passing defines on command line.
Fixes bug #553.
2015-03-24 23:15:32 +00:00
7c1101dc08 Fix misleading snprintf() arguments. 2015-02-20 18:57:08 +01:00
ea17bfca3d If present, add usb_serial to description for better identification 2015-02-20 18:54:12 +01:00
5497520891 Handle enumeration of native UART ports on FreeBSD 2015-02-16 23:25:14 +01:00
ccd512d51c Implement FreeBSD OS-specific serial port detection and query 2015-02-15 21:28:15 +01:00
f446cfbf65 windows: Fix restart of RX/error wait operation after reads.
This fixes bug #421.
2015-02-15 20:52:45 +01:00
e31f2c6b8b Fix free() of uninitialized pointer.
Explicitly set port->usb_path to NULL, otherwise a free(port->usb_path)
can happen where port->usb_path is uninitialized.

This closes bug #512.
2014-12-05 18:42:43 +01:00
b328a48b0f windows: Properly handle return value of SetupDiOpenDevRegKey().
This fixes bug #499.
2014-11-27 17:42:28 +01:00
59182fbbbf linux: Check for BOTHER macro at configure time.
This fixes bug #363.
2014-11-01 18:36:09 +01:00
ad7498553c Flush only the requested buffers
Fix the sp_flush() so that it flushes only the requested buffers
also in unix.
2014-10-12 21:38:03 +02:00
d66bbceaa7 Fix typos. 2014-10-05 02:38:35 +02:00
78940e6921 windows: Fix compile issues with multiply or not defined GUIDs.
This fixes bug #416.
2014-09-25 23:04:06 +02:00
6c444ade55 windows: Indentation (cosmetics only). 2014-09-24 12:54:36 +02:00
7aeb6736bd windows: Fix various memory leaks.
This fixes bug #419.
2014-09-24 12:52:21 +02:00
276ef1b92f Add SP_MODE_READ_WRITE enum value. 2014-09-20 21:24:31 +02:00
eb82be98a7 README: Add URL to the libserialport website. 2014-09-07 19:31:23 +02:00
a46ee5b4d7 README: Mention that only MinGW-w64 works (but not MinGW). 2014-09-07 19:27:02 +02:00
da8730199a windows: -no-undefined is required to make a DLL. 2014-09-07 19:18:22 +02:00
6692d8c13f windows: Add -lsetupapi when building for WIN32. 2014-09-07 19:18:19 +02:00
d179da05c0 windows: Include proper GUID defining header to fix build.
The initguid.h header must appear early or it does not have
an effect, at least on cross-build from Linux.
2014-09-07 18:51:04 +02:00
653cef3ab1 linux: remove readlinkat() dependency 2014-09-04 20:13:55 +02:00
546e9ae5c5 linux_termios: fix return types to actually match returned values
This fixes the following warning :

linux_termios.c: In function 'get_termios_get_ioctl':
linux_termios.c:42:2: warning: overflow in implicit constant conversion [-Woverflow]
  return TCGETS2;
  ^

This fixes bug #396.
2014-09-04 20:13:55 +02:00
23ef3bf125 Fix Mac OS X build (untested). 2014-08-27 14:56:19 +02:00
d38c7d2c70 Fix Windows build. 2014-08-27 14:53:19 +02:00
0666ccc7ca linux: Fix warning by marking vid, pid variables unsigned. 2014-08-24 14:08:00 +01:00
7f450f46bd Compile with -pedantic. 2014-08-24 14:06:21 +01:00
c51b846eee linux: Define feature macros to get required functions.
This is needed to build with -std=c99.
2014-08-24 14:06:21 +01:00
7890cef6cf Revise debug macros to work in strict C99. 2014-08-24 14:06:21 +01:00
9caa2e86aa Specialise RETURN_VALUE macro into RETURN_{INT,STRING,POINTER}.
This avoids the need to pass the required format string on every
call and also eliminates the need for the non-standard typeof() call.
2014-08-24 13:31:20 +01:00
79a8004637 libserialport.h.in: remove trailing commas in enum definitions
This makes it easier to use libserialport on projects that build with
the GCC -pedantic flag enabled.
2014-08-24 11:56:45 +01:00
942a6d349e Bump package version to 0.2.0. 2014-08-20 23:40:19 +02:00
f3ccf157cb Rename sp_get_signals() parameter to avoid name clash with Qt headers. 2014-08-20 22:39:29 +02:00
900904638b configure.ac: We no longer need to set WINVER explicitly.
Since we now require MinGW-w64, we no longer have to set WINVER manually,
since MinGW-w64 defaults to WINVER=0x0502 (which corresponds to
Windows Server 2003 SP1 / Windows XP SP2 apparently, which is fine for us).
2014-08-05 21:22:59 +02:00
34906a229b windows.c: Remove MinGW workarounds, require MinGW-w64 instead.
We're switching from MinGW (i686-pc-mingw32.static in MXE)...

  http://mingw.org/

...to MinGW-w64 (i686-w64-mingw32.static in MXE):

  http://mingw-w64.sourceforge.net/

The latter is a fork which nowadays seems to be more active and also to
have a more complete set of win32 API headers and libs.

History:
http://sourceforge.net/p/mingw-w64/wiki2/History/

This closes bug #393.
2014-08-05 21:22:50 +02:00
8eb18f7b5a windows.c: Define a bunch of stuff that's not in MinGW, yet.
Without these defineѕ the build fails with various (many) compile errors.
2014-07-31 23:14:35 +02:00
9a8d04bca6 configure.ac: MinGW build fix (setting WINVER=0x0501).
Without this the build fails with:

  windows.c:40:43: error: 'WC_NO_BEST_FIT_CHARS' undeclared (first use in
  this function)
2014-07-31 23:11:40 +02:00
5a8810e2b2 serialport.c: Fix an 'unused variable' compiler warning. 2014-07-31 23:09:24 +02:00
12056e2f75 Avoid use of struct serial_struct on systems which don't have it (Android)
This fixes bug #376.
2014-07-06 14:16:56 +02:00
5bd33b7c8b Don't use readlinkat if it does not exist
This fixes bug #377.
2014-07-06 14:15:46 +02:00
970f279ae4 Introduce SP_API/SP_PRIV to mark visibility of functions. 2014-07-02 14:43:32 +02:00
e4ce975a54 Fix build for platforms without enumeration & port metadata support. 2014-06-14 12:27:54 +01:00
48a4076f69 Move list_ports() implementations to OS-specific files. 2014-06-14 01:28:49 +02:00
235269990b Fix missing variable on macosx. 2014-06-13 23:47:45 +02:00
e59ecb3359 Ignore build leftovers. 2014-06-11 20:41:20 +02:00
65172beffe Check bus:address and vid:pid validity. 2014-06-11 17:21:51 +02:00
e33dcf90a0 Tidy up and split most OS-specific code to separate files. 2014-06-11 15:10:29 +01:00
a93fb46888 Add new APIs to get some USB descriptor details for USB serial ports. 2014-06-10 23:51:11 +02:00
98cac5d63e Remove the udev dependency and parse the /sys hierarchy instead. 2014-06-10 22:17:07 +02:00
073c86bd07 Simplify Mac OS implementation of sp_list_ports(). 2014-06-10 22:17:07 +02:00
f095f84164 Remove useless declaration. 2014-06-10 22:17:07 +02:00
da2ede60e4 Remove duplicated include. 2014-06-10 22:16:46 +02:00
8edf649caf Add format string support to RETURN_ERROR() and RETURN_FAIL(). 2014-06-02 12:08:54 +02:00
51 changed files with 7633 additions and 2410 deletions

37
.gitignore vendored
View File

@ -1,19 +1,22 @@
*.[ao]
*.l[ao]
.deps/
.libs/
INSTALL
Makefile
Makefile.in
aclocal.m4
autom4te.cache/
autostuff/
config.log
config.status
configure
libserialport.la
libserialport.pc
libserialport.h
libtool
serialport.lo
serialport.o
linux_termios.lo
linux_termios.o
/INSTALL
/Makefile
/Makefile.in
/aclocal.m4
/autom4te.cache/
/autostuff/
/config.*
/configure
/configure.lineno
/libserialport-*.tar.*
/libserialport.pc
/libtool
stamp-h?
.vs/
Debug/
Release/
x64/
*.vcxproj.user

24
AUTHORS
View File

@ -2,6 +2,26 @@
AUTHORS
-------------------------------------------------------------------------------
Please check the source code files and/or git history and/or ChangeLog for
a list of all authors and contributors.
Martin Ling conceived the idea for the library, designed the API and wrote much
of the implementation and documentation.
The initial codebase was adapted from serial code in libsigrok, written by Bert
Vermeulen and Uwe Hermann, who gave permission for it to be relicensed under
the LGPL3+ for inclusion in libserialport.
The package is maintained by Uwe Hermann, with input from Martin Ling.
Aurelien Jacobs made several contributions, including the USB metadata API,
improvements to the port enumeration code, and eliminating the previous
dependence on libudev for enumeration on Linux.
Uffe Jakobsen contributed the FreeBSD support.
Matthias Heidbrink contributed support for non-standard baudrates on Mac OS X.
Bug fixes have been contributed by Bert Vermeulen, silverbuddy, Marcus
Comstedt, Antti Nykanen, Michael B. Trausch and Janne Huttunen.
For a full history of contributions, see the git history.
Others have helped the project by contributing bug reports and discussion.

626
Doxyfile

File diff suppressed because it is too large Load Diff

View File

@ -19,35 +19,65 @@
##
ACLOCAL_AMFLAGS = -I autostuff
AM_LIBTOOLFLAGS = --silent
GNUMAKEFLAGS = --no-print-directory
AM_CPPFLAGS = -I$(top_srcdir)
# 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_la_SOURCES = serialport.c timing.c libserialport_internal.h
if LINUX
libserialport_la_SOURCES += linux_termios.c linux_termios.h
libserialport_la_SOURCES += linux.c linux_termios.c linux_termios.h
endif
if WIN32
libserialport_la_SOURCES += windows.c
endif
if MACOSX
libserialport_la_SOURCES += macosx.c
endif
if FREEBSD
libserialport_la_SOURCES += freebsd.c
endif
libserialport_la_LIBADD = $(LIBOBJS)
libserialport_la_LIBADD = $(SP_LIBS)
libserialport_la_LDFLAGS = $(SP_LIB_LDFLAGS)
libserialport_la_LDFLAGS = -version-info $(SP_LIB_VERSION) -no-undefined
if MACOSX
libserialport_la_LDFLAGS += -framework IOKit -framework CoreFoundation
endif
library_includedir = $(includedir)
library_include_HEADERS = libserialport.h
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
.PHONY: ChangeLog
.PHONY: ChangeLog doc
ChangeLog:
git --git-dir $(top_srcdir)/.git log > ChangeLog || touch ChangeLog
git --git-dir '$(top_srcdir)/.git' log >$@ || touch $@
dist-hook: ChangeLog
doc: $(library_include_HEADERS) $(top_srcdir)/Doxyfile
doc: $(nodist_include_HEADERS) $(top_srcdir)/Doxyfile
doxygen $(top_srcdir)/Doxyfile

76
NEWS
View File

@ -1,3 +1,79 @@
0.1.1 (2016-01-27)
------------------
Note: This release does NOT change the libserialport API or ABI in
backwards-incompatible ways. Programs using libserialport should
continue to work fine without recompiling or relinking.
* New API calls:
- sp_get_port_description(): Obtain a user friendly port description.
- sp_get_port_transport(): Obtain the underlying transport type.
- sp_get_port_usb_bus_address(): Obtain the USB bus number & device address.
- sp_get_port_usb_vid_pid(): Obtain the USB VID and PID.
- sp_get_port_usb_manufacturer(): Obtain the USB manufacturer string.
- sp_get_port_usb_product(): Obtain the USB product string.
- sp_get_port_usb_serial(): Obtain the USB serial number string.
- sp_get_port_bluetooth_address(): Obtain the Bluetooth MAC address.
- sp_blocking_read_next(): Read bytes from the specified serial port,
returning as soon as any data is available.
* API related additions:
- enum sp_mode: Add SP_MODE_READ_WRITE.
- Add enum sp_transport with the following enum entries:
SP_TRANSPORT_NATIVE, SP_TRANSPORT_USB, SP_TRANSPORT_BLUETOOTH.
* Fix the build on platforms where port enumeration and/or port
metadata is not available or implemented.
* Build system:
- Don't set/override "user variables" such as CFLAGS or LDFLAGS, since
those are meant to be controlled by the "user" (bug #577).
- Modernize and cleanup autotools setup.
* Remove trailing commas in libserialport.h enum definitions to allow
the code to build with the -pedantic compiler option.
* Fix various issues to allow successful builds with -std=c99.
* Fix various (non-fatal) compiler warnings.
* Fix various memory leaks (bug #419, among others).
* Fix a potential overflow of the timeout parameter of poll().
* Fix ReadFile() ERROR_IO_PENDING in sp_nonblocking_read() (bug #707).
* Fix a glibc >= 2.20 compiler warning for deprecated _BSD_SOURCE (bug #716).
* Rename a 'signals' parameter to 'signal_mask' to avoid a conflict with Qt.
* Fix two potential segfaults in sp_get_port_handle() and sp_get_config_*()
(which only occurred if the user incorrectly passed in a NULL argument).
* sp_list_ports(): Actually set list_ptr NULL as documented.
* Use "Port not open" debug message when a closed port is used (bug #710).
* Linux:
- The libudev requirement has been dropped (/sys is now used directly).
- Fix a build issue in the get_termios_get_ioctl() call (bug #396).
- Fix sp_flush() so that it only flushes the requested buffers.
- Fix a build error if BOTHER is not available (bug #363).
- If present, add the USB "description" for better port identification.
- Handle the case when /sys/class/tty/ entries are not symlinks.
* Windows:
- MinGW-w64 (mingw-w64.sf.net) is now required for building, and MinGW
(mingw.org) is no longer supported (bug #393).
- Fix a build issue due to a missing <initguid.h> #include.
- Fix a build issue due to the missing -lsetupapi linker argument.
- Use libtool's -no-undefined option to allow shared (DLL) builds.
- Fix a compile error due to multiply or not defined GUIDs (bug #416).
- Fix a build issue related to the SP_PRIV/SP_API macros (bug #553).
- Fix a bug where an uninitialized pointer was free()'d (bug #512).
- Fix a bug wrt the SetupDiOpenDevRegKey() return code (bug #499).
- Fix a bug wrt restart of RX/error wait operations after read (bug #421).
- Fix a bug wrt WaitCommEvents() and/or fAbortOnError handling (bug #341).
- Fix USB iSerial queries on USB composite devices.
- Strip CR/LF from end of system error messages (bug #585).
- Avoid unnecessary calls to the SetCommTimeouts() function (bug #586).
- Fix a bug in the Windows implementation of sp_blocking_read_next().
- Fix an ERROR_SEM_TIMEOUT related issue in sp_blocking_write().
* FreeBSD:
- Implement serial port enumeration for FreeBSD systems.
* Android:
- Fix a portability issue wrt the unavailable 'serial_struct' (bug #376).
- Fix a portability issue wrt a readlinkat() call (bug #377).
* Mac OS X:
- Fix port listing on Mac OS X 10.11 (El Capitan).
* README: Various documentation updates and fixes.
* AUTHORS: Add/update list of contributors.
* Doxygen API docs: Various documentation updates and fixes.
0.1.0 (2014-05-06)
------------------

63
README
View File

@ -11,6 +11,7 @@ transparently on any platform supported by the library.
The operations that are supported are:
- Port enumeration (obtaining a list of serial ports on the system).
- Obtaining port metadata (USB device information, Bluetooth address, etc).
- Opening and closing ports.
- Setting port parameters (baud rate, parity, etc).
- Reading, writing and flushing data.
@ -24,38 +25,68 @@ Status
The library should build and work on any Windows or Unix-based system. If it
does not, please submit a bug.
Enumeration is currently only implemented on Windows, Mac OS X and Linux. On
other systems enumeration is not supported, but ports can still be opened by
name and then used.
Enumeration is currently implemented on Windows, Mac OS X, FreeBSD and Linux.
On other systems enumeration is not supported, but ports can still be opened
by name and then used.
If you know how to enumerate available ports on another OS, please submit a bug
with this information, or better still a patch implementing it.
Future
======
Future versions will add additional API calls for obtaining metadata about a
port, e.g. for USB devices the USB VID and PID of the underlying device.
Dependencies
============
On Linux, libudev is required. On other systems no other libraries are required.
The libudev dependency could be eliminated in favour of direct sysfs queries at
the cost of some brevity. This is not currently a priority but if you feel like
doing this feel free to submit a patch.
No other libraries are required.
Building
========
The package uses a GNU style build system and requires a Unix style shell.
On Windows it can be built with the MinGW toolchain and MSYS environment.
On Windows, libserialport can be built with Visual Studio 2019 or with
the standalone MSBuild tool, using the solution and project files provided.
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
===
Doxygen API documentation is included.
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
=======
http://sigrok.org/wiki/Libserialport

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/sh -e
##
## This file is part of the libserialport project.
##
@ -19,42 +19,8 @@
## along with this program. If not, see <http://www.gnu.org/licenses/>.
##
OS=`uname`
LIBTOOLIZE=libtoolize
ACLOCAL_DIR=
if [ "x$OS" = "xDarwin" ]; then
LIBTOOLIZE=glibtoolize
if [ -d /sw/share/aclocal ]; then
# fink installs aclocal macros here
ACLOCAL_DIR="-I /sw/share/aclocal"
elif [ -d /opt/local/share/aclocal ]; then
# Macports installs aclocal macros here
ACLOCAL_DIR="-I /opt/local/share/aclocal"
elif [ -d /usr/local/share/aclocal ]; then
# Homebrew installs aclocal macros here
ACLOCAL_DIR="-I /usr/local/share/aclocal"
elif [ -d /usr/share/aclocal ]; then
# Xcode installs aclocal macros here
ACLOCAL_DIR="-I /usr/share/aclocal"
fi
elif [ "x$OS" = "xMINGW32_NT-5.1" ]; then
# Windows XP
ACLOCAL_DIR="-I /usr/local/share/aclocal"
elif [ "x$OS" = "xMINGW32_NT-6.0" ]; then
# Windows Vista
ACLOCAL_DIR="-I /usr/local/share/aclocal"
elif [ "x$OS" = "xMINGW32_NT-6.1" ]; then
# Windows 7
ACLOCAL_DIR="-I /usr/local/share/aclocal"
fi
echo "Generating build system..."
${LIBTOOLIZE} --install --copy --quiet || exit 1
aclocal ${ACLOCAL_DIR} || exit 1
automake --add-missing --copy || exit 1
autoconf || exit 1
test -n "$srcdir" || srcdir=`dirname "$0"`
test -n "$srcdir" || srcdir=.
test -d "$srcdir/autostuff" || mkdir "$srcdir/autostuff"
autoreconf --force --install --verbose "$srcdir"

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

@ -1,32 +1,38 @@
/**
* Set the {2} for the specified serial port.
*
* @param port Pointer to port structure.
* @param {0} {3}.
* @param[in] port Pointer to a port structure. Must not be NULL.
* @param[in] {0} {3}.
*
* @return SP_OK upon success, a negative error code otherwise.
*
* @since 0.1.0
*/
enum sp_return sp_set_{0}(struct sp_port *port, {1} {0});
/**
* Get the {2} from a port configuration.
*
* The user should allocate a variable of type {1} and pass a pointer to this
* to receive the result.
* The user should allocate a variable of type {1} and
* pass a pointer to this to receive the result.
*
* @param config Pointer to configuration structure.
* @param {0}_ptr Pointer to variable to store result.
* @param[in] config Pointer to a configuration structure. Must not be NULL.
* @param[out] {0}_ptr Pointer to a variable to store the result. Must not be NULL.
*
* @return SP_OK upon success, a negative error code otherwise.
*
* @since 0.1.0
*/
enum sp_return sp_get_config_{0}(const struct sp_port_config *config, {1} *{0}_ptr);
/**
* Set the {2} in a port configuration.
*
* @param config Pointer to configuration structure.
* @param {0} {3}, or -1 to retain current setting.
* @param[in] config Pointer to a configuration structure. Must not be NULL.
* @param[in] {0} {3}, or -1 to retain the current setting.
*
* @return SP_OK upon success, a negative error code otherwise.
*
* @since 0.1.0
*/
enum sp_return sp_set_config_{0}(struct sp_port_config *config, {1} {0});

View File

@ -24,117 +24,158 @@ AC_PREREQ([2.63])
# libserialport package version number (NOT the same as shared lib version!).
m4_define([sp_package_version_major], [0])
m4_define([sp_package_version_minor], [1])
m4_define([sp_package_version_micro], [0])
m4_define([sp_package_version_micro], [1])
m4_define([sp_package_version], [sp_package_version_major.sp_package_version_minor.sp_package_version_micro])
AC_INIT([libserialport], [sp_package_version], [martin-libserialport@earth.li],
[libserialport], [http://sigrok.org/wiki/Libserialport])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIR([autostuff])
AC_CONFIG_AUX_DIR([autostuff])
AC_CANONICAL_TARGET
AH_BOTTOM([#if HAVE_STRUCT_TERMIOS_C_ISPEED && HAVE_STRUCT_TERMIOS_C_OSPEED
# define HAVE_TERMIOS_SPEED 1
#endif
#if HAVE_STRUCT_TERMIOS2_C_ISPEED && HAVE_STRUCT_TERMIOS2_C_OSPEED
# define HAVE_TERMIOS2_SPEED 1
#endif])
# We require at least automake 1.11 (needed for 'silent rules').
AM_INIT_AUTOMAKE([1.11 -Wall -Werror check-news])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AM_INIT_AUTOMAKE([1.11 -Wall -Werror no-define check-news])
AM_SILENT_RULES([yes])
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
# Enable more compiler warnings via -Wall and -Wextra.
CFLAGS="$CFLAGS -Wall -Wextra"
# Checks for programs.
AC_PROG_CC
AC_PROG_CPP
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
# Initialize pkg-config.
# We require at least 0.22, as "Requires.private" behaviour changed there.
PKG_PROG_PKG_CONFIG([0.22])
AC_DEFINE([SP_PACKAGE_VERSION_MAJOR], [sp_package_version_major], [.])
AC_DEFINE([SP_PACKAGE_VERSION_MINOR], [sp_package_version_minor], [.])
AC_DEFINE([SP_PACKAGE_VERSION_MICRO], [sp_package_version_micro], [.])
AC_DEFINE([SP_PACKAGE_VERSION_STRING], ["sp_package_version"], [.])
AC_SUBST([SP_PACKAGE_VERSION], [sp_package_version])
# Library version for libserialport (NOT the same as the package version).
# Carefully read the libtool docs before updating these numbers!
# The algorithm for determining which number to change (and how) is nontrivial!
# http://www.gnu.org/software/libtool/manual/libtool.html#Updating-version-info
SP_LIB_VERSION_CURRENT=0
SP_LIB_VERSION_CURRENT=1
SP_LIB_VERSION_REVISION=0
SP_LIB_VERSION_AGE=0
SP_LIB_VERSION="$SP_LIB_VERSION_CURRENT:$SP_LIB_VERSION_REVISION:$SP_LIB_VERSION_AGE"
SP_LIB_LDFLAGS="-version-info $SP_LIB_VERSION"
AC_SUBST(SP_LIB_VERSION_CURRENT)
AC_SUBST(SP_LIB_VERSION_REVISION)
AC_SUBST(SP_LIB_VERSION_AGE)
AC_SUBST(SP_LIB_VERSION)
AC_SUBST(SP_LIB_LDFLAGS)
SP_LIB_VERSION_AGE=1
AC_SUBST([SP_LIB_VERSION],
["$SP_LIB_VERSION_CURRENT:$SP_LIB_VERSION_REVISION:$SP_LIB_VERSION_AGE"])
# Checks for libraries.
AC_DEFINE_UNQUOTED([SP_LIB_VERSION_CURRENT], [$SP_LIB_VERSION_CURRENT], [.])
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"], [.])
# This variable collects the pkg-config names of all detected libs.
# It is then used to construct the "Requires.private:" field in the
# libserialport.pc file.
SP_PKGLIBS=""
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*}"])
case $target_os in
*linux*)
AM_CONDITIONAL([LINUX], true)
# On Linux libudev is currently required for enumeration.
AC_ARG_WITH([libudev],
[AS_HELP_STRING([--with-libudev],
[use libudev for serial port enumeration @<:@default=check@:>@])],
[], [with_libudev=check])
AS_IF([test "x$with_libudev" != xno], [
PKG_CHECK_MODULES([libudev], [libudev >= 0],
[CFLAGS="$CFLAGS $libudev_CFLAGS"; LIBS="$LIBS $libudev_LIBS";
SP_PKGLIBS="$SP_PKGLIBS libudev"; AC_DEFINE(HAVE_LIBUDEV)])], [])
;;
*darwin*)
AM_CONDITIONAL([LINUX], false)
LDFLAGS="$LDFLAGS -Wl,-framework -Wl,IOKit -Wl,-framework -Wl,CoreFoundation"
AC_CHECK_HEADER(IOKit/IOKitLib.h, [], [AC_MSG_ERROR([IOKit/IOKitLib.h not found])])
;;
*)
AM_CONDITIONAL([LINUX], false)
esac
AM_COND_IF([WIN32], [SP_LIBS='-lsetupapi'], [SP_LIBS=])
AC_SUBST([SP_LIBS])
AC_SUBST(SP_PKGLIBS)
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*|freebsd*],, [
AC_DEFINE([NO_ENUMERATION], [1], [Enumeration is unsupported.])
AC_DEFINE([NO_PORT_METADATA], [1], [Port metadata is unavailable.])
])
AC_SYS_LARGEFILE
# Define size_t if not defined as standard.
AC_TYPE_SIZE_T
# Check for specific termios structures.
AC_CHECK_TYPE([struct termios2], [AC_DEFINE(HAVE_TERMIOS2, 1)], [], [[#include <linux/termios.h>]])
AC_CHECK_TYPE([struct termiox], [AC_DEFINE(HAVE_TERMIOX, 1)], [], [[#include <linux/termios.h>]])
AC_CHECK_MEMBERS([struct termios.c_ispeed, struct termios.c_ospeed],
[AC_DEFINE(HAVE_TERMIOS_SPEED, 1)], [], [[#include <linux/termios.h>]])
AC_CHECK_MEMBERS([struct termios2.c_ispeed, struct termios2.c_ospeed],
[AC_DEFINE(HAVE_TERMIOS2_SPEED, 1)], [], [[#include <linux/termios.h>]])
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],,,
[[#include <linux/termios.h>]])
AC_SUBST(MAKEFLAGS, '--no-print-directory')
AC_SUBST(AM_LIBTOOLFLAGS, '--silent')
# Check for the BOTHER definition, needed for setting arbitrary baud rates.
# We can't just #ifdef BOTHER in the code, because of the separation between
# code using libc headers and code using kernel termios.h headers.
AC_CHECK_DECLS([BOTHER],,, [[#include <linux/termios.h>]])
SP_PACKAGE_VERSION_MAJOR=sp_package_version_major
SP_PACKAGE_VERSION_MINOR=sp_package_version_minor
SP_PACKAGE_VERSION_MICRO=sp_package_version_micro
SP_PACKAGE_VERSION=sp_package_version
# Check for serial_struct.
AC_CHECK_TYPES([struct serial_struct],,, [[#include <linux/serial.h>]])
AC_SUBST(SP_PACKAGE_VERSION_MAJOR)
AC_SUBST(SP_PACKAGE_VERSION_MINOR)
AC_SUBST(SP_PACKAGE_VERSION_MICRO)
AC_SUBST(SP_PACKAGE_VERSION)
# Check for realpath().
AC_CHECK_FUNC([realpath], [AC_DEFINE(HAVE_REALPATH, 1, [realpath is available.])], [])
AC_CONFIG_FILES([Makefile libserialport.h libserialport.pc])
# 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"
AC_COMPILE_IFELSE([AC_LANG_SOURCE(
[[__attribute__((visibility("hidden"))) void foo(void) {}]])],
[sp_cv_visibility_control=attribute],
[AC_COMPILE_IFELSE([AC_LANG_SOURCE(
[[__declspec(dllexport) void foo(void) {}]])],
[sp_cv_visibility_control=declspec],
[sp_cv_visibility_control=none])])
CFLAGS=$sp_saved_CFLAGS
])
AS_CASE([$sp_cv_visibility_control],
[attribute], [SP_API='__attribute__((visibility("default")))'
SP_PRIV='__attribute__((visibility("hidden")))'],
[declspec], [SP_API='__declspec(dllexport)' SP_PRIV=],
[SP_API= SP_PRIV=])
AC_DEFINE_UNQUOTED([SP_API], [$SP_API], [Macro preceding public API functions])
AC_DEFINE_UNQUOTED([SP_PRIV], [$SP_PRIV], [Macro preceding private functions])
AC_CONFIG_FILES([Makefile libserialport.pc])
AC_OUTPUT
echo
echo "libserialport configuration summary:"
echo
echo " - Package version (major.minor.micro): $SP_PACKAGE_VERSION"
echo " - Library version (current:revision:age): $SP_LIB_VERSION"
echo " - Prefix: $prefix"
echo " - Building on: $build"
echo " - Building for: $host"
echo
cat >&AS_MESSAGE_FD <<_EOF
libserialport configuration summary:
- 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;
}
}

383
freebsd.c Normal file
View File

@ -0,0 +1,383 @@
/*
* This file is part of the libserialport project.
*
* Copyright (C) 2015 Uffe Jakobsen <uffe@uffe.org>
*
* 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/>.
*/
/*
* FreeBSD platform specific serial port information:
*
* FreeBSD has two device nodes for each serial port:
*
* 1) a call-in port
* 2) a call-out port
*
* Quoting FreeBSD Handbook section 26.2.1
* (https://www.freebsd.org/doc/handbook/serial.html)
*
* In FreeBSD, each serial port is accessed through an entry in /dev.
* There are two different kinds of entries:
*
* 1) Call-in ports are named /dev/ttyuN where N is the port number,
* starting from zero. If a terminal is connected to the first serial port
* (COM1), use /dev/ttyu0 to refer to the terminal. If the terminal is on
* the second serial port (COM2), use /dev/ttyu1, and so forth.
* Generally, the call-in port is used for terminals. Call-in ports require
* that the serial line assert the "Data Carrier Detect" signal to work
* correctly.
*
* 2) Call-out ports are named /dev/cuauN on FreeBSD versions 10.x and higher
* and /dev/cuadN on FreeBSD versions 9.x and lower. Call-out ports are
* usually not used for terminals, but are used for modems. The call-out
* port can be used if the serial cable or the terminal does not support
* the "Data Carrier Detect" signal.
*
* FreeBSD also provides initialization devices (/dev/ttyuN.init and
* /dev/cuauN.init or /dev/cuadN.init) and locking devices (/dev/ttyuN.lock
* and /dev/cuauN.lock or /dev/cuadN.lock). The initialization devices are
* used to initialize communications port parameters each time a port is
* opened, such as crtscts for modems which use RTS/CTS signaling for flow
* control. The locking devices are used to lock flags on ports to prevent
* users or programs changing certain parameters.
*
* In line with the above device naming USB-serial devices have
* the following naming:
*
* 1) call-in ports: /dev/ttyUN where N is the port number
* 2) call-out ports: /dev/cuaUN where N is the port number
*
* See also: ucom(4), https://www.freebsd.org/cgi/man.cgi?query=ucom
*
* Getting USB serial port device description:
*
* In order to query USB serial ports for device description - the mapping
* between the kernel device driver instances must be correlated with the
* above mentioned device nodes.
*
* 1) For each USB-serial port (/dev/cuaUN) use libusb to lookup the device
* description and the name of the kernel device driver instance.
* 2) Query sysctl for the kernel device driver instance info.
* 3) Derive the ttyname and (serial) port count for the kernel device
* driver instance.
* 4) If sysctl ttyname and port matches /dev/cuaUN apply the libusb
* device description.
*/
#include <config.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <dirent.h>
#include <libusb20.h>
#include <libusb20_desc.h>
#include "libserialport.h"
#include "libserialport_internal.h"
#define DEV_CUA_PATH "/dev/cua"
//#define DBG(...) printf(__VA_ARGS__)
#define DBG(...)
static char *strrspn(const char *s, const char *charset)
{
char *t = (char *)s + strlen(s);
while (t != (char *)s)
if (!strchr(charset, *(--t)))
return ++t;
return t;
}
static int strend(const char *str, const char *pattern)
{
size_t slen = strlen(str);
size_t plen = strlen(pattern);
if (slen >= plen)
return (!memcmp(pattern, (str + slen - plen), plen));
return 0;
}
static int libusb_query_port(struct libusb20_device *dev, int idx,
char **drv_name_str, char **drv_inst_str)
{
int rc;
char *j;
char sbuf[FILENAME_MAX];
if (!drv_name_str || !drv_inst_str)
return -1;
rc = libusb20_dev_kernel_driver_active(dev, idx);
if (rc < 0)
return rc;
sbuf[0] = 0;
libusb20_dev_get_iface_desc(dev, idx, (char *)&sbuf,
(uint8_t)sizeof(sbuf) - 1);
if (sbuf[0] == 0)
return rc;
DBG("Device interface descriptor: idx=%003d '%s'\n", idx, sbuf);
j = strchr(sbuf, ':');
if (j > sbuf) {
sbuf[j - sbuf] = 0;
/*
* The device driver name may contain digits that
* is not a part of the device instance number - like "u3g".
*/
j = strrspn(sbuf, "0123456789");
if (j > sbuf) {
*drv_name_str = strndup(sbuf, j - sbuf);
*drv_inst_str = strdup((j));
}
}
return rc;
}
static int sysctl_query_dev_drv(const char *drv_name_str,
const char *drv_inst_str, char **ttyname, int *const ttyport_cnt)
{
int rc;
char sbuf[FILENAME_MAX];
char tbuf[FILENAME_MAX];
size_t tbuf_len;
if (!ttyname || !ttyport_cnt)
return -1;
snprintf(sbuf, sizeof(sbuf), "dev.%s.%s.ttyname", drv_name_str,
drv_inst_str);
tbuf_len = sizeof(tbuf) - 1;
if ((rc = sysctlbyname(sbuf, tbuf, &tbuf_len, NULL, 0)) != 0)
return rc;
tbuf[tbuf_len] = 0;
*ttyname = strndup(tbuf, tbuf_len);
DBG("sysctl: '%s' (%d) (%d): '%.*s'\n", sbuf, rc, (int)tbuf_len,
(int)tbuf_len, tbuf);
snprintf(sbuf, sizeof(sbuf), "dev.%s.%s.ttyports",
drv_name_str, drv_inst_str);
tbuf_len = sizeof(tbuf) - 1;
rc = sysctlbyname(sbuf, tbuf, &tbuf_len, NULL, 0);
if (rc == 0) {
*ttyport_cnt = *(uint32_t *)tbuf;
DBG("sysctl: '%s' (%d) (%d): '%d'\n", sbuf, rc,
(int)tbuf_len, (int)ttyport_cnt);
} else {
*ttyport_cnt = 0;
}
return rc;
}
static int populate_port_struct_from_libusb_desc(struct sp_port *const port,
struct libusb20_device *dev)
{
char tbuf[FILENAME_MAX];
/* Populate port structure from libusb description. */
struct LIBUSB20_DEVICE_DESC_DECODED *dev_desc =
libusb20_dev_get_device_desc(dev);
if (!dev_desc)
return -1;
port->transport = SP_TRANSPORT_USB;
port->usb_vid = dev_desc->idVendor;
port->usb_pid = dev_desc->idProduct;
port->usb_bus = libusb20_dev_get_bus_number(dev);
port->usb_address = libusb20_dev_get_address(dev);
if (libusb20_dev_req_string_simple_sync
(dev, dev_desc->iManufacturer, tbuf, sizeof(tbuf)) == 0) {
port->usb_manufacturer = strdup(tbuf);
}
if (libusb20_dev_req_string_simple_sync
(dev, dev_desc->iProduct, tbuf, sizeof(tbuf)) == 0) {
port->usb_product = strdup(tbuf);
}
if (libusb20_dev_req_string_simple_sync
(dev, dev_desc->iSerialNumber, tbuf, sizeof(tbuf)) == 0) {
port->usb_serial = strdup(tbuf);
}
/* If present, add serial to description for better identification. */
tbuf[0] = '\0';
if (port->usb_product && port->usb_product[0])
strncat(tbuf, port->usb_product, sizeof(tbuf) - 1);
else
strncat(tbuf, libusb20_dev_get_desc(dev), sizeof(tbuf) - 1);
if (port->usb_serial && port->usb_serial[0]) {
strncat(tbuf, " ", sizeof(tbuf) - 1);
strncat(tbuf, port->usb_serial, sizeof(tbuf) - 1);
}
port->description = strdup(tbuf);
port->bluetooth_address = NULL;
return 0;
}
SP_PRIV enum sp_return get_port_details(struct sp_port *port)
{
int rc;
struct libusb20_backend *be;
struct libusb20_device *dev, *dev_last;
char tbuf[FILENAME_MAX];
char *cua_sfx;
int cua_dev_found;
uint8_t idx;
int sub_inst;
DBG("Portname: '%s'\n", port->name);
if (!strncmp(port->name, DEV_CUA_PATH, strlen(DEV_CUA_PATH))) {
cua_sfx = port->name + strlen(DEV_CUA_PATH);
DBG("'%s': '%s'\n", DEV_CUA_PATH, cua_sfx);
} else {
RETURN_ERROR(SP_ERR_ARG, "Device name not recognized");
}
/* Native UART enumeration. */
if ((cua_sfx[0] == 'u') || (cua_sfx[0] == 'd')) {
port->transport = SP_TRANSPORT_NATIVE;
snprintf(tbuf, sizeof(tbuf), "cua%s", cua_sfx);
port->description = strdup(tbuf);
RETURN_OK();
}
/* USB device enumeration. */
dev = dev_last = NULL;
be = libusb20_be_alloc_default();
cua_dev_found = 0;
while (cua_dev_found == 0) {
dev = libusb20_be_device_foreach(be, dev_last);
if (!dev)
break;
libusb20_dev_open(dev, 0);
DBG("Device descriptor: '%s'\n", libusb20_dev_get_desc(dev));
for (idx = 0; idx <= UINT8_MAX - 1; idx++) {
char *drv_name_str = NULL;
char *drv_inst_str = NULL;
char *ttyname = NULL;
int ttyport_cnt;
rc = libusb_query_port(dev, idx, &drv_name_str, &drv_inst_str);
if (rc == 0) {
rc = sysctl_query_dev_drv(drv_name_str,
drv_inst_str, &ttyname, &ttyport_cnt);
if (rc == 0) {
/* Handle multiple subinstances of serial ports in the same driver instance. */
for (sub_inst = 0; sub_inst < ttyport_cnt; sub_inst++) {
if (ttyport_cnt == 1)
snprintf(tbuf, sizeof(tbuf), "%s", ttyname);
else
snprintf(tbuf, sizeof(tbuf), "%s.%d", ttyname, sub_inst);
if (!strcmp(cua_sfx, tbuf)) {
DBG("MATCH: '%s' == '%s'\n", cua_sfx, tbuf);
cua_dev_found = 1;
populate_port_struct_from_libusb_desc(port, dev);
break; /* Break out of sub instance loop. */
}
}
}
}
/* Clean up. */
if (ttyname)
free(ttyname);
if (drv_name_str)
free(drv_name_str);
if (drv_inst_str)
free(drv_inst_str);
if (cua_dev_found)
break; /* Break out of USB device port idx loop. */
}
libusb20_dev_close(dev);
dev_last = dev;
}
libusb20_be_free(be);
if (cua_dev_found == 0)
DBG("WARN: Found no match '%s' %s'\n", port->name, cua_sfx);
RETURN_OK();
}
SP_PRIV enum sp_return list_ports(struct sp_port ***list)
{
DIR *dir;
struct dirent *entry;
struct termios tios;
char name[PATH_MAX];
int fd, ret;
DEBUG("Enumerating tty devices");
if (!(dir = opendir("/dev")))
RETURN_FAIL("Could not open dir /dev");
DEBUG("Iterating over results");
while ((entry = readdir(dir))) {
ret = SP_OK;
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)
continue;
if (strend(entry->d_name, ".init"))
continue;
if (strend(entry->d_name, ".lock"))
continue;
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. */
if ((fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY | O_TTY_INIT | O_CLOEXEC)) < 0) {
DEBUG("Open failed, skipping");
continue;
}
/* Sanity check if we got a real tty. */
if (!isatty(fd)) {
close(fd);
continue;
}
ret = tcgetattr(fd, &tios);
close(fd);
if (ret < 0 || cfgetospeed(&tios) <= 0 || cfgetispeed(&tios) <= 0)
continue;
DEBUG_FMT("Found port %s", name);
DBG("%s: %s\n", __func__, entry->d_name);
*list = list_append(*list, name);
if (!*list) {
SET_ERROR(ret, SP_ERR_MEM, "List append failed");
break;
}
}
closedir(dir);
return ret;
}

1827
libserialport.h Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

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>

311
libserialport_internal.h Normal file
View File

@ -0,0 +1,311 @@
/*
* This file is part of the libserialport project.
*
* Copyright (C) 2014 Martin Ling <martin-libserialport@earth.li>
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
*
* 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/>.
*/
#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
/* 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 <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#include <setupapi.h>
#include <cfgmgr32.h>
#undef DEFINE_GUID
#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
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 <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>
#include <IOKit/IOKitLib.h>
#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>
/* 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"
/* TCGETX/TCSETX is not available everywhere. */
#if defined(TCGETX) && defined(TCSETX) && defined(HAVE_STRUCT_TERMIOX)
#define USE_TERMIOX
#endif
#endif
/* TIOCINQ/TIOCOUTQ is not available everywhere. */
#if !defined(TIOCINQ) && defined(FIONREAD)
#define TIOCINQ FIONREAD
#endif
#if !defined(TIOCOUTQ) && defined(FIONWRITE)
#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)) && HAVE_DECL_BOTHER
#define USE_TERMIOS_SPEED
#endif
struct sp_port {
char *name;
char *description;
enum sp_transport transport;
int usb_bus;
int usb_address;
int usb_vid;
int usb_pid;
char *usb_manufacturer;
char *usb_product;
char *usb_serial;
char *bluetooth_address;
#ifdef _WIN32
char *usb_path;
HANDLE hdl;
COMMTIMEOUTS timeouts;
OVERLAPPED write_ovl;
OVERLAPPED read_ovl;
OVERLAPPED wait_ovl;
DWORD events;
BYTE *write_buf;
DWORD write_buf_size;
BOOL writing;
BOOL wait_running;
#else
int fd;
#endif
};
struct sp_port_config {
int baudrate;
int bits;
enum sp_parity parity;
int stopbits;
enum sp_rts rts;
enum sp_cts cts;
enum sp_dtr dtr;
enum sp_dsr dsr;
enum sp_xonxoff xon_xoff;
};
struct port_data {
#ifdef _WIN32
DCB dcb;
#else
struct termios term;
int controlbits;
int termiox_supported;
int rts_flow;
int cts_flow;
int dtr_flow;
int dsr_flow;
#endif
};
#ifdef _WIN32
typedef HANDLE event_handle;
#else
typedef int event_handle;
#endif
/* Standard baud rates. */
#ifdef _WIN32
#define BAUD_TYPE DWORD
#define BAUD(n) {CBR_##n, n}
#else
#define BAUD_TYPE speed_t
#define BAUD(n) {B##n, n}
#endif
struct std_baudrate {
BAUD_TYPE index;
int value;
};
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
extern void (*sp_debug_handler)(const char *format, ...);
/* Debug output macros. */
#define DEBUG_FMT(fmt, ...) do { \
if (sp_debug_handler) \
sp_debug_handler(fmt ".\n", __VA_ARGS__); \
} while (0)
#define DEBUG(msg) DEBUG_FMT(msg, NULL)
#define DEBUG_ERROR(err, msg) DEBUG_FMT("%s returning " #err ": " msg, __func__)
#define DEBUG_FAIL(msg) do { \
char *errmsg = sp_last_error_message(); \
DEBUG_FMT("%s returning SP_ERR_FAIL: " msg ": %s", __func__, errmsg); \
sp_free_error_message(errmsg); \
} while (0);
#define RETURN() do { \
DEBUG_FMT("%s returning", __func__); \
return; \
} while (0)
#define RETURN_CODE(x) do { \
DEBUG_FMT("%s returning " #x, __func__); \
return x; \
} while (0)
#define RETURN_CODEVAL(x) do { \
switch (x) { \
case SP_OK: RETURN_CODE(SP_OK); \
case SP_ERR_ARG: RETURN_CODE(SP_ERR_ARG); \
case SP_ERR_FAIL: RETURN_CODE(SP_ERR_FAIL); \
case SP_ERR_MEM: RETURN_CODE(SP_ERR_MEM); \
case SP_ERR_SUPP: RETURN_CODE(SP_ERR_SUPP); \
default: RETURN_CODE(SP_ERR_FAIL); \
} \
} while (0)
#define RETURN_OK() RETURN_CODE(SP_OK);
#define RETURN_ERROR(err, msg) do { \
DEBUG_ERROR(err, msg); \
return err; \
} while (0)
#define RETURN_FAIL(msg) do { \
DEBUG_FAIL(msg); \
return SP_ERR_FAIL; \
} while (0)
#define RETURN_INT(x) do { \
int _x = x; \
DEBUG_FMT("%s returning %d", __func__, _x); \
return _x; \
} while (0)
#define RETURN_STRING(x) do { \
char *_x = x; \
DEBUG_FMT("%s returning %s", __func__, _x); \
return _x; \
} while (0)
#define RETURN_POINTER(x) do { \
void *_x = x; \
DEBUG_FMT("%s returning %p", __func__, _x); \
return _x; \
} while (0)
#define SET_ERROR(val, err, msg) do { DEBUG_ERROR(err, msg); val = err; } while (0)
#define SET_FAIL(val, msg) do { DEBUG_FAIL(msg); val = SP_ERR_FAIL; } while (0)
#define TRACE(fmt, ...) DEBUG_FMT("%s(" fmt ") called", __func__, __VA_ARGS__)
#define TRACE_VOID() DEBUG_FMT("%s() called", __func__)
#define TRY(x) do { int retval = x; if (retval != SP_OK) RETURN_CODEVAL(retval); } while (0)
SP_PRIV struct sp_port **list_append(struct sp_port **list, const char *portname);
/* OS-specific Helper functions. */
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

259
linux.c Normal file
View File

@ -0,0 +1,259 @@
/*
* This file is part of the libserialport project.
*
* Copyright (C) 2013 Martin Ling <martin-libserialport@earth.li>
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
*
* 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 <config.h>
#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)
{
/*
* Description limited to 127 char, anything longer
* would not be user friendly anyway.
*/
char description[128];
int bus, address;
unsigned int vid, pid;
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] = "", link_name[PATH_MAX], file_name[PATH_MAX];
char *ptr, *dev = port->name + 5;
FILE *file;
int i, count;
struct stat statbuf;
if (strncmp(port->name, "/dev/", 5))
RETURN_ERROR(SP_ERR_ARG, "Device name not recognized");
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(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;
if (strstr(file_name, "bluetooth"))
port->transport = SP_TRANSPORT_BLUETOOTH;
else if (strstr(file_name, "usb"))
port->transport = SP_TRANSPORT_USB;
if (port->transport == SP_TRANSPORT_USB) {
for (i = 0; i < 5; i++) {
strcat(sub_dir, "../");
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "busnum");
if (!(file = fopen_cloexec_rdonly(file_name)))
continue;
count = fscanf(file, "%d", &bus);
fclose(file);
if (count != 1)
continue;
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "devnum");
if (!(file = fopen_cloexec_rdonly(file_name)))
continue;
count = fscanf(file, "%d", &address);
fclose(file);
if (count != 1)
continue;
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "idVendor");
if (!(file = fopen_cloexec_rdonly(file_name)))
continue;
count = fscanf(file, "%4x", &vid);
fclose(file);
if (count != 1)
continue;
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "idProduct");
if (!(file = fopen_cloexec_rdonly(file_name)))
continue;
count = fscanf(file, "%4x", &pid);
fclose(file);
if (count != 1)
continue;
port->usb_bus = bus;
port->usb_address = address;
port->usb_vid = vid;
port->usb_pid = pid;
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "product");
if ((file = fopen_cloexec_rdonly(file_name))) {
if ((ptr = fgets(description, sizeof(description), file))) {
ptr = description + strlen(description) - 1;
if (ptr >= description && *ptr == '\n')
*ptr = 0;
port->description = strdup(description);
}
fclose(file);
}
if (!file || !ptr)
port->description = strdup(dev);
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "manufacturer");
if ((file = fopen_cloexec_rdonly(file_name))) {
if ((ptr = fgets(manufacturer, sizeof(manufacturer), file))) {
ptr = manufacturer + strlen(manufacturer) - 1;
if (ptr >= manufacturer && *ptr == '\n')
*ptr = 0;
port->usb_manufacturer = strdup(manufacturer);
}
fclose(file);
}
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "product");
if ((file = fopen_cloexec_rdonly(file_name))) {
if ((ptr = fgets(product, sizeof(product), file))) {
ptr = product + strlen(product) - 1;
if (ptr >= product && *ptr == '\n')
*ptr = 0;
port->usb_product = strdup(product);
}
fclose(file);
}
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "serial");
if ((file = fopen_cloexec_rdonly(file_name))) {
if ((ptr = fgets(serial, sizeof(serial), file))) {
ptr = serial + strlen(serial) - 1;
if (ptr >= serial && *ptr == '\n')
*ptr = 0;
port->usb_serial = strdup(serial);
}
fclose(file);
}
/* If present, add serial to description for better identification. */
if (port->usb_serial && strlen(port->usb_serial)) {
snprintf(description, sizeof(description),
"%s - %s", port->description, port->usb_serial);
if (port->description)
free(port->description);
port->description = strdup(description);
}
break;
}
} else {
port->description = strdup(dev);
if (port->transport == SP_TRANSPORT_BLUETOOTH) {
snprintf(file_name, sizeof(file_name), dir_name, dev, "", "address");
if ((file = fopen_cloexec_rdonly(file_name))) {
if ((ptr = fgets(baddr, sizeof(baddr), file))) {
ptr = baddr + strlen(baddr) - 1;
if (ptr >= baddr && *ptr == '\n')
*ptr = 0;
port->bluetooth_address = strdup(baddr);
}
fclose(file);
}
}
}
RETURN_OK();
}
SP_PRIV enum sp_return list_ports(struct sp_port ***list)
{
char name[PATH_MAX], target[PATH_MAX];
struct dirent *entry;
#ifdef HAVE_STRUCT_SERIAL_STRUCT
struct serial_struct serial_info;
int ioctl_result;
#endif
char buf[sizeof(entry->d_name) + 23];
int len, fd;
DIR *dir;
int ret = SP_OK;
struct stat statbuf;
DEBUG("Enumerating tty devices");
if (!(dir = opendir("/sys/class/tty")))
RETURN_FAIL("Could not open /sys/class/tty");
DEBUG("Iterating over results");
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);
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);
DEBUG_FMT("Found device %s", name);
if (strstr(target, "serial8250")) {
/*
* The serial8250 driver has a hardcoded number of ports.
* The only way to tell which actually exist on a given system
* 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 | O_CLOEXEC)) < 0) {
DEBUG("Open failed, skipping");
continue;
}
#ifdef HAVE_STRUCT_SERIAL_STRUCT
ioctl_result = ioctl(fd, TIOCGSERIAL, &serial_info);
#endif
close(fd);
#ifdef HAVE_STRUCT_SERIAL_STRUCT
if (ioctl_result != 0) {
DEBUG("ioctl failed, skipping");
continue;
}
if (serial_info.type == PORT_UNKNOWN) {
DEBUG("Port type is unknown, skipping");
continue;
}
#endif
}
DEBUG_FMT("Found port %s", name);
*list = list_append(*list, name);
if (!*list) {
SET_ERROR(ret, SP_ERR_MEM, "List append failed");
break;
}
}
closedir(dir);
return ret;
}

View File

@ -33,40 +33,42 @@
* TCSETX/TCGETX ioctls used with struct termiox, others do not.
*/
#include <config.h>
#include <stdlib.h>
#include <linux/termios.h>
#include "linux_termios.h"
int get_termios_get_ioctl(void)
SP_PRIV unsigned long get_termios_get_ioctl(void)
{
#ifdef HAVE_TERMIOS2
#ifdef HAVE_STRUCT_TERMIOS2
return TCGETS2;
#else
return TCGETS;
#endif
}
int get_termios_set_ioctl(void)
SP_PRIV unsigned long get_termios_set_ioctl(void)
{
#ifdef HAVE_TERMIOS2
#ifdef HAVE_STRUCT_TERMIOS2
return TCSETS2;
#else
return TCSETS;
#endif
}
int get_termios_size(void)
SP_PRIV size_t get_termios_size(void)
{
#ifdef HAVE_TERMIOS2
#ifdef HAVE_STRUCT_TERMIOS2
return sizeof(struct termios2);
#else
return sizeof(struct termios);
#endif
}
#if defined(HAVE_TERMIOS_SPEED) || defined(HAVE_TERMIOS2_SPEED)
int get_termios_speed(void *data)
#if (defined(HAVE_TERMIOS_SPEED) || defined(HAVE_TERMIOS2_SPEED)) && HAVE_DECL_BOTHER
SP_PRIV int get_termios_speed(void *data)
{
#ifdef HAVE_TERMIOS2
#ifdef HAVE_STRUCT_TERMIOS2
struct termios2 *term = (struct termios2 *) data;
#else
struct termios *term = (struct termios *) data;
@ -77,9 +79,9 @@ int get_termios_speed(void *data)
return term->c_ispeed;
}
void set_termios_speed(void *data, int speed)
SP_PRIV void set_termios_speed(void *data, int speed)
{
#ifdef HAVE_TERMIOS2
#ifdef HAVE_STRUCT_TERMIOS2
struct termios2 *term = (struct termios2 *) data;
#else
struct termios *term = (struct termios *) data;
@ -90,13 +92,13 @@ void set_termios_speed(void *data, int speed)
}
#endif
#ifdef HAVE_TERMIOX
int get_termiox_size(void)
#ifdef HAVE_STRUCT_TERMIOX
SP_PRIV size_t get_termiox_size(void)
{
return sizeof(struct termiox);
}
int get_termiox_flow(void *data, int *rts, int *cts, int *dtr, int *dsr)
SP_PRIV int get_termiox_flow(void *data, int *rts, int *cts, int *dtr, int *dsr)
{
struct termiox *termx = (struct termiox *) data;
int flags = 0;
@ -109,7 +111,7 @@ int get_termiox_flow(void *data, int *rts, int *cts, int *dtr, int *dsr)
return flags;
}
void set_termiox_flow(void *data, int rts, int cts, int dtr, int dsr)
SP_PRIV void set_termiox_flow(void *data, int rts, int cts, int dtr, int dsr)
{
struct termiox *termx = (struct termiox *) data;

View File

@ -20,13 +20,15 @@
#ifndef LIBSERIALPORT_LINUX_TERMIOS_H
#define LIBSERIALPORT_LINUX_TERMIOS_H
int get_termios_get_ioctl(void);
int get_termios_set_ioctl(void);
int get_termios_size(void);
int get_termios_speed(void *data);
void set_termios_speed(void *data, int speed);
int get_termiox_size(void);
int get_termiox_flow(void *data, int *rts, int *cts, int *dtr, int *dsr);
void set_termiox_flow(void *data, int rts, int cts, int dtr, int dsr);
#include <stdlib.h>
SP_PRIV unsigned long get_termios_get_ioctl(void);
SP_PRIV unsigned long get_termios_set_ioctl(void);
SP_PRIV size_t get_termios_size(void);
SP_PRIV int get_termios_speed(void *data);
SP_PRIV void set_termios_speed(void *data, int speed);
SP_PRIV size_t get_termiox_size(void);
SP_PRIV int get_termiox_flow(void *data, int *rts, int *cts, int *dtr, int *dsr);
SP_PRIV void set_termiox_flow(void *data, int rts, int cts, int dtr, int dsr);
#endif

243
macosx.c Normal file
View File

@ -0,0 +1,243 @@
/*
* This file is part of the libserialport project.
*
* Copyright (C) 2013-2014 Martin Ling <martin-libserialport@earth.li>
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
*
* 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 <config.h>
#include "libserialport.h"
#include "libserialport_internal.h"
SP_PRIV enum sp_return get_port_details(struct sp_port *port)
{
/*
* Description limited to 127 char, anything longer
* would not be user friendly anyway.
*/
char description[128];
int bus, address, vid, pid = -1;
char manufacturer[128], product[128], serial[128];
CFMutableDictionaryRef classes;
io_iterator_t iter;
io_object_t ioport, ioparent;
CFTypeRef cf_property, cf_bus, cf_address, cf_vendor, cf_product;
Boolean result;
char path[PATH_MAX], class[16];
DEBUG("Getting serial port list");
if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue)))
RETURN_FAIL("IOServiceMatching() failed");
if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes,
&iter) != KERN_SUCCESS)
RETURN_FAIL("IOServiceGetMatchingServices() failed");
DEBUG("Iterating over results");
while ((ioport = IOIteratorNext(iter))) {
if (!(cf_property = IORegistryEntryCreateCFProperty(ioport,
CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0))) {
IOObjectRelease(ioport);
continue;
}
result = CFStringGetCString(cf_property, path, sizeof(path),
kCFStringEncodingASCII);
CFRelease(cf_property);
if (!result || strcmp(path, port->name)) {
IOObjectRelease(ioport);
continue;
}
DEBUG_FMT("Found port %s", path);
IORegistryEntryGetParentEntry(ioport, kIOServicePlane, &ioparent);
if ((cf_property=IORegistryEntrySearchCFProperty(ioparent,kIOServicePlane,
CFSTR("IOClass"), kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents))) {
if (CFStringGetCString(cf_property, class, sizeof(class),
kCFStringEncodingASCII) &&
strstr(class, "USB")) {
DEBUG("Found USB class device");
port->transport = SP_TRANSPORT_USB;
}
CFRelease(cf_property);
}
if ((cf_property=IORegistryEntrySearchCFProperty(ioparent,kIOServicePlane,
CFSTR("IOProviderClass"), kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents))) {
if (CFStringGetCString(cf_property, class, sizeof(class),
kCFStringEncodingASCII) &&
strstr(class, "USB")) {
DEBUG("Found USB class device");
port->transport = SP_TRANSPORT_USB;
}
CFRelease(cf_property);
}
IOObjectRelease(ioparent);
if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
CFSTR("USB Interface Name"), kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
(cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
CFSTR("USB Product Name"), kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
(cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
CFSTR("Product Name"), kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
(cf_property = IORegistryEntryCreateCFProperty(ioport,
CFSTR(kIOTTYDeviceKey), kCFAllocatorDefault, 0))) {
if (CFStringGetCString(cf_property, description, sizeof(description),
kCFStringEncodingASCII)) {
DEBUG_FMT("Found description %s", description);
port->description = strdup(description);
}
CFRelease(cf_property);
} else {
DEBUG("No description for this device");
}
cf_bus = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
CFSTR("USBBusNumber"),
kCFAllocatorDefault,
kIORegistryIterateRecursively
| kIORegistryIterateParents);
cf_address = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
CFSTR("USB Address"),
kCFAllocatorDefault,
kIORegistryIterateRecursively
| kIORegistryIterateParents);
if (cf_bus && cf_address &&
CFNumberGetValue(cf_bus , kCFNumberIntType, &bus) &&
CFNumberGetValue(cf_address, kCFNumberIntType, &address)) {
DEBUG_FMT("Found matching USB bus:address %03d:%03d", bus, address);
port->usb_bus = bus;
port->usb_address = address;
}
if (cf_bus)
CFRelease(cf_bus);
if (cf_address)
CFRelease(cf_address);
cf_vendor = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
CFSTR("idVendor"),
kCFAllocatorDefault,
kIORegistryIterateRecursively
| kIORegistryIterateParents);
cf_product = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
CFSTR("idProduct"),
kCFAllocatorDefault,
kIORegistryIterateRecursively
| kIORegistryIterateParents);
if (cf_vendor && cf_product &&
CFNumberGetValue(cf_vendor , kCFNumberIntType, &vid) &&
CFNumberGetValue(cf_product, kCFNumberIntType, &pid)) {
DEBUG_FMT("Found matching USB VID:PID %04X:%04X", vid, pid);
port->usb_vid = vid;
port->usb_pid = pid;
}
if (cf_vendor)
CFRelease(cf_vendor);
if (cf_product)
CFRelease(cf_product);
if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
CFSTR("USB Vendor Name"), kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents))) {
if (CFStringGetCString(cf_property, manufacturer, sizeof(manufacturer),
kCFStringEncodingASCII)) {
DEBUG_FMT("Found manufacturer %s", manufacturer);
port->usb_manufacturer = strdup(manufacturer);
}
CFRelease(cf_property);
}
if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
CFSTR("USB Product Name"), kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents))) {
if (CFStringGetCString(cf_property, product, sizeof(product),
kCFStringEncodingASCII)) {
DEBUG_FMT("Found product name %s", product);
port->usb_product = strdup(product);
}
CFRelease(cf_property);
}
if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
CFSTR("USB Serial Number"), kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents))) {
if (CFStringGetCString(cf_property, serial, sizeof(serial),
kCFStringEncodingASCII)) {
DEBUG_FMT("Found serial number %s", serial);
port->usb_serial = strdup(serial);
}
CFRelease(cf_property);
}
IOObjectRelease(ioport);
break;
}
IOObjectRelease(iter);
RETURN_OK();
}
SP_PRIV enum sp_return list_ports(struct sp_port ***list)
{
CFMutableDictionaryRef classes;
io_iterator_t iter;
char path[PATH_MAX];
io_object_t port;
CFTypeRef cf_path;
Boolean result;
int ret = SP_OK;
DEBUG("Creating matching dictionary");
if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue))) {
SET_FAIL(ret, "IOServiceMatching() failed");
goto out_done;
}
DEBUG("Getting matching services");
if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes,
&iter) != KERN_SUCCESS) {
SET_FAIL(ret, "IOServiceGetMatchingServices() failed");
goto out_done;
}
DEBUG("Iterating over results");
while ((port = IOIteratorNext(iter))) {
cf_path = IORegistryEntryCreateCFProperty(port,
CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
if (cf_path) {
result = CFStringGetCString(cf_path, path, sizeof(path),
kCFStringEncodingASCII);
CFRelease(cf_path);
if (result) {
DEBUG_FMT("Found port %s", path);
if (!(*list = list_append(*list, path))) {
SET_ERROR(ret, SP_ERR_MEM, "List append failed");
IOObjectRelease(port);
goto out;
}
}
}
IOObjectRelease(port);
}
out:
IOObjectRelease(iter);
out_done:
return ret;
}

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>

File diff suppressed because it is too large Load Diff

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);
}

569
windows.c Normal file
View File

@ -0,0 +1,569 @@
/*
* This file is part of the libserialport project.
*
* Copyright (C) 2013-2014 Martin Ling <martin-libserialport@earth.li>
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
*
* 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"
/* USB path is a string of at most 8 decimal numbers < 128 separated by dots. */
#define MAX_USB_PATH ((8 * 3) + (7 * 1) + 1)
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 wc_bytes)
{
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, wc_bytes);
wc_str[wc_length] = 0;
/* Compute the size of the UTF-8 converted string. */
if (!(utf8_bytes = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1,
NULL, 0, NULL, NULL)))
goto wc_to_utf8_end;
/* Allocate UTF-8 output buffer. */
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, utf8_bytes, NULL, NULL)) {
free(utf8_str);
utf8_str = NULL;
goto wc_to_utf8_end;
}
wc_to_utf8_end:
if (wc_str)
free(wc_str);
return utf8_str;
}
static char *get_root_hub_name(HANDLE host_controller)
{
USB_ROOT_HUB_NAME root_hub_name;
PUSB_ROOT_HUB_NAME root_hub_name_wc;
char *root_hub_name_utf8;
ULONG size = 0;
/* Compute the size of the root hub name string. */
if (!DeviceIoControl(host_controller, IOCTL_USB_GET_ROOT_HUB_NAME, 0, 0,
&root_hub_name, sizeof(root_hub_name), &size, NULL))
return NULL;
/* Allocate wide char root hub name string. */
size = root_hub_name.ActualLength;
if (!(root_hub_name_wc = malloc(size)))
return NULL;
/* Actually get the root hub name string. */
if (!DeviceIoControl(host_controller, IOCTL_USB_GET_ROOT_HUB_NAME,
NULL, 0, root_hub_name_wc, size, &size, NULL)) {
free(root_hub_name_wc);
return NULL;
}
/* Convert the root hub name string to UTF-8. */
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;
}
static char *get_external_hub_name(HANDLE hub, ULONG connection_index)
{
USB_NODE_CONNECTION_NAME ext_hub_name;
PUSB_NODE_CONNECTION_NAME ext_hub_name_wc;
char *ext_hub_name_utf8;
ULONG size;
/* Compute the size of the external hub name string. */
ext_hub_name.ConnectionIndex = connection_index;
if (!DeviceIoControl(hub, IOCTL_USB_GET_NODE_CONNECTION_NAME,
&ext_hub_name, sizeof(ext_hub_name),
&ext_hub_name, sizeof(ext_hub_name), &size, NULL))
return NULL;
/* Allocate wide char external hub name string. */
size = ext_hub_name.ActualLength;
if (size <= sizeof(ext_hub_name)
|| !(ext_hub_name_wc = malloc(size)))
return NULL;
/* Get the name of the external hub attached to the specified port. */
ext_hub_name_wc->ConnectionIndex = connection_index;
if (!DeviceIoControl(hub, IOCTL_USB_GET_NODE_CONNECTION_NAME,
ext_hub_name_wc, size,
ext_hub_name_wc, size, &size, NULL)) {
free(ext_hub_name_wc);
return NULL;
}
/* Convert the external hub name string to UTF-8. */
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;
}
static char *get_string_descriptor(HANDLE hub_device, ULONG connection_index,
UCHAR descriptor_index)
{
char desc_req_buf[sizeof(USB_DESCRIPTOR_REQUEST) +
MAXIMUM_USB_STRING_LENGTH] = { 0 };
PUSB_DESCRIPTOR_REQUEST desc_req = (void *)desc_req_buf;
PUSB_STRING_DESCRIPTOR desc = (void *)(desc_req + 1);
ULONG size = sizeof(desc_req_buf);
desc_req->ConnectionIndex = connection_index;
desc_req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8)
| descriptor_index;
desc_req->SetupPacket.wIndex = 0;
desc_req->SetupPacket.wLength = (USHORT) (size - sizeof(*desc_req));
if (!DeviceIoControl(hub_device,
IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
desc_req, size, desc_req, size, &size, NULL)
|| size < 2
|| desc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE
|| desc->bLength != size - sizeof(*desc_req)
|| desc->bLength % 2)
return NULL;
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,
ULONG nb_ports, const char *parent_path, DEVINST dev_inst)
{
char path[MAX_USB_PATH];
ULONG index = 0;
for (index = 1; index <= nb_ports; index++) {
PUSB_NODE_CONNECTION_INFORMATION_EX connection_info_ex;
ULONG size = sizeof(*connection_info_ex) + (30 * sizeof(USB_PIPE_INFO));
if (!(connection_info_ex = malloc(size)))
break;
connection_info_ex->ConnectionIndex = index;
if (!DeviceIoControl(hub_device,
IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
connection_info_ex, size,
connection_info_ex, size, &size, NULL)) {
/*
* Try to get CONNECTION_INFORMATION if
* CONNECTION_INFORMATION_EX did not work.
*/
PUSB_NODE_CONNECTION_INFORMATION connection_info;
size = sizeof(*connection_info) + (30 * sizeof(USB_PIPE_INFO));
if (!(connection_info = malloc(size))) {
free(connection_info_ex);
continue;
}
connection_info->ConnectionIndex = index;
if (!DeviceIoControl(hub_device,
IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,
connection_info, size,
connection_info, size, &size, NULL)) {
free(connection_info);
free(connection_info_ex);
continue;
}
connection_info_ex->ConnectionIndex = connection_info->ConnectionIndex;
connection_info_ex->DeviceDescriptor = connection_info->DeviceDescriptor;
connection_info_ex->DeviceIsHub = connection_info->DeviceIsHub;
connection_info_ex->DeviceAddress = connection_info->DeviceAddress;
free(connection_info);
}
if (connection_info_ex->DeviceIsHub) {
/* Recursively enumerate external hub. */
PCHAR ext_hub_name;
if ((ext_hub_name = get_external_hub_name(hub_device, index))) {
snprintf(path, sizeof(path), "%s%ld.",
parent_path, connection_info_ex->ConnectionIndex);
enumerate_hub(port, ext_hub_name, path, dev_inst);
}
free(connection_info_ex);
} else {
snprintf(path, sizeof(path), "%s%ld",
parent_path, connection_info_ex->ConnectionIndex);
/* Check if this device is the one we search for. */
if (strcmp(path, port->usb_path)) {
free(connection_info_ex);
continue;
}
/* Finally grab detailed information regarding the device. */
port->usb_address = connection_info_ex->DeviceAddress + 1;
port->usb_vid = connection_info_ex->DeviceDescriptor.idVendor;
port->usb_pid = connection_info_ex->DeviceDescriptor.idProduct;
if (connection_info_ex->DeviceDescriptor.iManufacturer)
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,
connection_info_ex->DeviceDescriptor.iProduct);
if (connection_info_ex->DeviceDescriptor.iSerialNumber) {
port->usb_serial = get_string_descriptor(hub_device, index,
connection_info_ex->DeviceDescriptor.iSerialNumber);
if (port->usb_serial == NULL) {
//composite device, get the parent's serial number
char device_id[MAX_DEVICE_ID_LEN];
if (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS) {
if (CM_Get_Device_IDA(dev_inst, device_id, sizeof(device_id), 0) == CR_SUCCESS)
port->usb_serial = strdup(strrchr(device_id, '\\')+1);
}
}
}
free(connection_info_ex);
break;
}
}
}
static void enumerate_hub(struct sp_port *port, const char *hub_name,
const char *parent_path, DEVINST dev_inst)
{
USB_NODE_INFORMATION hub_info;
HANDLE hub_device;
ULONG size = sizeof(hub_info);
char *device_name;
/* Open the hub with its full name. */
if (!(device_name = malloc(strlen("\\\\.\\") + strlen(hub_name) + 1)))
return;
strcpy(device_name, "\\\\.\\");
strcat(device_name, hub_name);
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;
/* Get the number of ports of the hub. */
if (DeviceIoControl(hub_device, IOCTL_USB_GET_NODE_INFORMATION,
&hub_info, size, &hub_info, size, &size, NULL))
/* Enumerate the ports of the hub. */
enumerate_hub_ports(port, hub_device,
hub_info.u.HubInformation.HubDescriptor.bNumberOfPorts, parent_path, dev_inst);
CloseHandle(hub_device);
}
static void enumerate_host_controller(struct sp_port *port,
HANDLE host_controller_device,
DEVINST dev_inst)
{
char *root_hub_name;
if ((root_hub_name = get_root_hub_name(host_controller_device))) {
enumerate_hub(port, root_hub_name, "", dev_inst);
free(root_hub_name);
}
}
static void get_usb_details(struct sp_port *port, DEVINST dev_inst_match)
{
HDEVINFO device_info;
SP_DEVINFO_DATA device_info_data;
ULONG i, size = 0;
device_info = SetupDiGetClassDevs(&GUID_CLASS_USB_HOST_CONTROLLER, NULL, NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
device_info_data.cbSize = sizeof(device_info_data);
for (i = 0; SetupDiEnumDeviceInfo(device_info, i, &device_info_data); i++) {
SP_DEVICE_INTERFACE_DATA device_interface_data;
PSP_DEVICE_INTERFACE_DETAIL_DATA device_detail_data;
DEVINST dev_inst = dev_inst_match;
HANDLE host_controller_device;
device_interface_data.cbSize = sizeof(device_interface_data);
if (!SetupDiEnumDeviceInterfaces(device_info, 0,
&GUID_CLASS_USB_HOST_CONTROLLER,
i, &device_interface_data))
continue;
if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data,
NULL, 0, &size, NULL)
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER)
continue;
if (!(device_detail_data = malloc(size)))
continue;
device_detail_data->cbSize = sizeof(*device_detail_data);
if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data,
device_detail_data, size, &size,
NULL)) {
free(device_detail_data);
continue;
}
while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS
&& dev_inst != device_info_data.DevInst) { }
if (dev_inst != device_info_data.DevInst) {
free(device_detail_data);
continue;
}
port->usb_bus = i + 1;
host_controller_device = CreateFile(device_detail_data->DevicePath,
GENERIC_WRITE, FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (host_controller_device != INVALID_HANDLE_VALUE) {
enumerate_host_controller(port, host_controller_device, dev_inst_match);
CloseHandle(host_controller_device);
}
free(device_detail_data);
}
SetupDiDestroyDeviceInfoList(device_info);
return;
}
SP_PRIV enum sp_return get_port_details(struct sp_port *port)
{
/*
* Description limited to 127 char, anything longer
* would not be user friendly anyway.
*/
char description[128];
SP_DEVINFO_DATA device_info_data = { .cbSize = sizeof(device_info_data) };
HDEVINFO device_info;
int i;
device_info = SetupDiGetClassDevs(NULL, 0, 0,
DIGCF_PRESENT | DIGCF_ALLCLASSES);
if (device_info == INVALID_HANDLE_VALUE)
RETURN_FAIL("SetupDiGetClassDevs() failed");
for (i = 0; SetupDiEnumDeviceInfo(device_info, i, &device_info_data); i++) {
HKEY device_key;
DEVINST dev_inst;
char value[8], class[16];
DWORD size, type;
CONFIGRET cr;
/* Check if this is the device we are looking for. */
device_key = SetupDiOpenDevRegKey(device_info, &device_info_data,
DICS_FLAG_GLOBAL, 0,
DIREG_DEV, KEY_QUERY_VALUE);
if (device_key == INVALID_HANDLE_VALUE)
continue;
size = sizeof(value);
if (RegQueryValueExA(device_key, "PortName", NULL, &type, (LPBYTE)value,
&size) != ERROR_SUCCESS || type != REG_SZ) {
RegCloseKey(device_key);
continue;
}
RegCloseKey(device_key);
value[sizeof(value) - 1] = 0;
if (strcmp(value, port->name))
continue;
/* Check port transport type. */
dev_inst = device_info_data.DevInst;
size = sizeof(class);
cr = CR_FAILURE;
while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS &&
(cr = CM_Get_DevNode_Registry_PropertyA(dev_inst,
CM_DRP_CLASS, 0, class, &size, 0)) != CR_SUCCESS) { }
if (cr == CR_SUCCESS) {
if (!strcmp(class, "USB"))
port->transport = SP_TRANSPORT_USB;
}
/* Get port description (friendly name). */
dev_inst = device_info_data.DevInst;
size = sizeof(description);
while ((cr = CM_Get_DevNode_Registry_PropertyA(dev_inst,
CM_DRP_FRIENDLYNAME, 0, description, &size, 0)) != CR_SUCCESS
&& CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS) { }
if (cr == CR_SUCCESS)
port->description = strdup(description);
/* Get more informations for USB connected ports. */
if (port->transport == SP_TRANSPORT_USB) {
char usb_path[MAX_USB_PATH] = "", tmp[MAX_USB_PATH];
char device_id[MAX_DEVICE_ID_LEN];
/* Recurse over parents to build the USB device path. */
dev_inst = device_info_data.DevInst;
do {
/* Verify that this layer of the tree is USB related. */
if (CM_Get_Device_IDA(dev_inst, device_id,
sizeof(device_id), 0) != CR_SUCCESS
|| strncmp(device_id, "USB\\", 4))
continue;
/* Discard one layer for composite devices. */
char compat_ids[512], *p = compat_ids;
size = sizeof(compat_ids);
if (CM_Get_DevNode_Registry_PropertyA(dev_inst,
CM_DRP_COMPATIBLEIDS, 0,
&compat_ids,
&size, 0) == CR_SUCCESS) {
while (*p) {
if (!strncmp(p, "USB\\COMPOSITE", 13))
break;
p += strlen(p) + 1;
}
if (*p)
continue;
}
/* Stop the recursion when reaching the USB root. */
if (!strncmp(device_id, "USB\\ROOT", 8))
break;
/* Prepend the address of current USB layer to the USB path. */
DWORD address;
size = sizeof(address);
if (CM_Get_DevNode_Registry_PropertyA(dev_inst, CM_DRP_ADDRESS,
0, &address, &size, 0) == CR_SUCCESS) {
strcpy(tmp, usb_path);
snprintf(usb_path, sizeof(usb_path), "%d%s%s",
(int)address, *tmp ? "." : "", tmp);
}
} while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS);
port->usb_path = strdup(usb_path);
/* Wake up the USB device to be able to read string descriptor. */
char *escaped_port_name;
HANDLE handle;
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 = CreateFileA(escaped_port_name, GENERIC_READ, 0, 0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0);
free(escaped_port_name);
CloseHandle(handle);
/* Retrieve USB device details from the device descriptor. */
get_usb_details(port, device_info_data.DevInst);
}
break;
}
SetupDiDestroyDeviceInfoList(device_info);
RETURN_OK();
}
SP_PRIV enum sp_return list_ports(struct sp_port ***list)
{
HKEY key;
TCHAR *value, *data;
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 ((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 ((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;
}
max_data_len = max_data_size / sizeof(TCHAR);
if (!(value = malloc((max_value_len + 1) * sizeof(TCHAR)))) {
SET_ERROR(ret, SP_ERR_MEM, "Registry value malloc failed");
goto out_close;
}
if (!(data = malloc((max_data_len + 1) * sizeof(TCHAR)))) {
SET_ERROR(ret, SP_ERR_MEM, "Registry data malloc failed");
goto out_free_value;
}
DEBUG("Iterating over values");
while (
value_len = max_value_len + 1,
data_size = max_data_size,
RegEnumValue(key, index, value, &value_len,
NULL, &type, (LPBYTE)data, &data_size) == ERROR_SUCCESS)
{
if (type == REG_SZ) {
data_len = data_size / sizeof(TCHAR);
data[data_len] = '\0';
#ifdef UNICODE
name_len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL);
#else
name_len = data_len + 1;
#endif
if (!(name = malloc(name_len))) {
SET_ERROR(ret, SP_ERR_MEM, "Registry port name malloc failed");
goto out;
}
#ifdef UNICODE
WideCharToMultiByte(CP_ACP, 0, data, -1, name, name_len, NULL, NULL);
#else
strcpy(name, data);
#endif
DEBUG_FMT("Found port %s", name);
if (!(*list = list_append(*list, name))) {
SET_ERROR(ret, SP_ERR_MEM, "List append failed");
free(name);
goto out;
}
free(name);
}
index++;
}
out:
free(data);
out_free_value:
free(value);
out_close:
RegCloseKey(key);
out_done:
return ret;
}