Jef Driesen f6fa2b84bc Add a poll function to the I/O interface
The Linux implementation is very straighforward and just a lightweight
wrapper around the select function. But the Windows implementation is
much more complex, because the Windows event notification mechanism
behaves very different:

The WaitCommEvent function does not support a timeout and is always a
blocking call. The only way to implement a timeout is to use
asynchronous I/O (or overlapped I/O as it's called in the Windows API),
to run the operation in the background. This requires some additional
book keeping to keep track of the pending background operation.

The event mechanism is also edge triggered instead of level triggered,
and reading the event with the WaitCommEvent function clears the pending
event. Therefore, the state of the input buffer needs to be checked with
the ClearCommError function before and after the WaitCommEvent call.

The check before is necessary in case the event is already cleared by a
previous WaitCommEvent call, while there is still data present in the
input buffer. In this case, WaitCommEvent should not be called at all,
because it would wait until more data arrives.

The check afterwards is necessary in case WaitCommEvent reports a
pending event, while the data in the input buffer has already been
consumed. In this case, the current event must be ignored and
WaitCommEvent needs to be called again, to wait for the next event.
2020-01-06 13:44:07 +01:00

68 lines
2.6 KiB
C

/*
* libdivecomputer
*
* Copyright (C) 2017 Jef Driesen
*
* This library 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 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#ifndef DC_CUSTOM_H
#define DC_CUSTOM_H
#include "common.h"
#include "context.h"
#include "iostream.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct dc_custom_cbs_t {
dc_status_t (*set_timeout) (void *userdata, int timeout);
dc_status_t (*set_latency) (void *userdata, unsigned int value);
dc_status_t (*set_break) (void *userdata, unsigned int value);
dc_status_t (*set_dtr) (void *userdata, unsigned int value);
dc_status_t (*set_rts) (void *userdata, unsigned int value);
dc_status_t (*get_lines) (void *userdata, unsigned int *value);
dc_status_t (*get_available) (void *userdata, size_t *value);
dc_status_t (*configure) (void *userdata, unsigned int baudrate, unsigned int databits, dc_parity_t parity, dc_stopbits_t stopbits, dc_flowcontrol_t flowcontrol);
dc_status_t (*poll) (void *userdata, int timeout);
dc_status_t (*read) (void *userdata, void *data, size_t size, size_t *actual);
dc_status_t (*write) (void *userdata, const void *data, size_t size, size_t *actual);
dc_status_t (*flush) (void *userdata);
dc_status_t (*purge) (void *userdata, dc_direction_t direction);
dc_status_t (*sleep) (void *userdata, unsigned int milliseconds);
dc_status_t (*close) (void *userdata);
} dc_custom_cbs_t;
/**
* Create a custom I/O stream.
*
* @param[out] iostream A location to store the custom I/O stream.
* @param[in] context A valid context object.
* @param[in] callbacks The callback functions to call.
* @param[in] userdata User data to pass to the callback functions.
* @returns #DC_STATUS_SUCCESS on success, or another #dc_status_t code
* on failure.
*/
dc_status_t
dc_custom_open (dc_iostream_t **iostream, dc_context_t *context, dc_transport_t transport, const dc_custom_cbs_t *callbacks, void *userdata);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* DC_CUSTOM_H */