* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <config.h>
#include <string.h>
#include <stdlib.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <libserialport.h>
-#include "libsigrok.h"
+#include <libsigrok/libsigrok.h>
#include "libsigrok-internal.h"
+#ifdef G_OS_WIN32
+#include <windows.h> /* for HANDLE */
+#endif
+/** @cond PRIVATE */
#define LOG_PREFIX "serial"
+/** @endcond */
+
+/**
+ * @file
+ *
+ * Serial port handling.
+ */
+
+/**
+ * @defgroup grp_serial Serial port handling
+ *
+ * Serial port handling functions.
+ *
+ * @{
+ */
/**
* Open the specified serial port.
*
* @param serial Previously initialized serial port structure.
* @param[in] flags Flags to use when opening the serial port. Possible flags
- * include SERIAL_RDWR, SERIAL_RDONLY.
+ * include SERIAL_RDWR, SERIAL_RDONLY.
*
* If the serial structure contains a serialcomm string, it will be
* passed to serial_set_paramstr() after the port is opened.
*
* @retval SR_OK Success.
* @retval SR_ERR Failure.
+ *
+ * @private
*/
SR_PRIV int serial_open(struct sr_serial_dev_inst *serial, int flags)
{
*
* @retval SR_OK Success.
* @retval SR_ERR Failure.
+ *
+ * @private
*/
SR_PRIV int serial_close(struct sr_serial_dev_inst *serial)
{
*
* @retval SR_OK Success.
* @retval SR_ERR Failure.
+ *
+ * @private
*/
SR_PRIV int serial_flush(struct sr_serial_dev_inst *serial)
{
*
* @retval SR_OK Success.
* @retval SR_ERR Failure.
+ *
+ * @private
*/
SR_PRIV int serial_drain(struct sr_serial_dev_inst *serial)
{
return SR_ERR;
}
- sr_spew("Wrote %d/%d bytes.", ret, count);
+ sr_spew("Wrote %zd/%zu bytes.", ret, count);
return ret;
}
* @retval SR_ERR Other error.
* @retval other The number of bytes written. If this is less than the number
* specified in the call, the timeout was reached.
+ *
+ * @private
*/
SR_PRIV int serial_write_blocking(struct sr_serial_dev_inst *serial,
const void *buf, size_t count, unsigned int timeout_ms)
* @retval SR_ERR_ARG Invalid argument.
* @retval SR_ERR Other error.
* @retval other The number of bytes written.
-*/
+ *
+ * @private
+ */
SR_PRIV int serial_write_nonblocking(struct sr_serial_dev_inst *serial,
const void *buf, size_t count)
{
}
if (ret > 0)
- sr_spew("Read %d/%d bytes.", ret, count);
+ sr_spew("Read %zd/%zu bytes.", ret, count);
return ret;
}
* @param[in] timeout_ms Timeout in ms, or 0 for no timeout.
*
* @retval SR_ERR_ARG Invalid argument.
- * @retval SR_ERR Other error.
- * @retval other The number of bytes read. If this is less than the number
+ * @retval SR_ERR Other error.
+ * @retval other The number of bytes read. If this is less than the number
* requested, the timeout was reached.
+ *
+ * @private
*/
SR_PRIV int serial_read_blocking(struct sr_serial_dev_inst *serial, void *buf,
size_t count, unsigned int timeout_ms)
* @param[in] count The number of bytes to read.
*
* @retval SR_ERR_ARG Invalid argument.
- * @retval SR_ERR Other error.
- * @retval other The number of bytes read.
+ * @retval SR_ERR Other error.
+ * @retval other The number of bytes read.
+ *
+ * @private
*/
SR_PRIV int serial_read_nonblocking(struct sr_serial_dev_inst *serial, void *buf,
size_t count)
* @param[in] parity The parity setting to use (0 = none, 1 = even, 2 = odd).
* @param[in] stopbits The number of stop bits to use (1 or 2).
* @param[in] flowcontrol The flow control settings to use (0 = none,
- * 1 = RTS/CTS, 2 = XON/XOFF).
+ * 1 = RTS/CTS, 2 = XON/XOFF).
* @param[in] rts Status of RTS line (0 or 1; required by some interfaces).
* @param[in] dtr Status of DTR line (0 or 1; required by some interfaces).
*
* @retval SR_OK Success.
* @retval SR_ERR Failure.
+ *
+ * @private
*/
SR_PRIV int serial_set_params(struct sr_serial_dev_inst *serial, int baudrate,
int bits, int parity, int stopbits,
* @param serial Previously initialized serial port structure.
* @param[in] paramstr A serial communication parameters string of the form
* "<baudrate>/<bits><parity><stopbits>{/<option>}".\n
- * Examples: "9600/8n1", "600/7o2/dtr=1/rts=0" or "460800/8n1/flow=2".\n
+ * Examples: "9600/8n1", "600/7o2/dtr=1/rts=0" or "460800/8n1/flow=2".\n
* \<baudrate\>=integer Baud rate.\n
* \<bits\>=5|6|7|8 Number of data bits.\n
* \<parity\>=n|e|o None, even, odd.\n
* rts=0|1 Set RTS off resp. on.\n
* Please note that values and combinations of these parameters must be
* supported by the concrete serial interface hardware and the drivers for it.
+ *
* @retval SR_OK Success.
* @retval SR_ERR Failure.
+ *
+ * @private
*/
SR_PRIV int serial_set_paramstr(struct sr_serial_dev_inst *serial,
const char *paramstr)
{
+/** @cond PRIVATE */
#define SERIAL_COMM_SPEC "^(\\d+)/([5678])([neo])([12])(.*)$"
+/** @endcond */
GRegex *reg;
GMatchInfo *match;
if ((mstr = g_match_info_fetch(match, 3))) {
switch (mstr[0]) {
case 'n':
- parity = SERIAL_PARITY_NONE;
+ parity = SP_PARITY_NONE;
break;
case 'e':
- parity = SERIAL_PARITY_EVEN;
+ parity = SP_PARITY_EVEN;
break;
case 'o':
- parity = SERIAL_PARITY_ODD;
+ parity = SP_PARITY_ODD;
break;
}
}
*
* @retval SR_OK Success.
* @retval SR_ERR Failure.
+ *
+ * @private
*/
SR_PRIV int serial_readline(struct sr_serial_dev_inst *serial, char **buf,
int *buflen, gint64 timeout_ms)
maxlen = *buflen;
*buflen = len = 0;
- while(1) {
+ while (1) {
len = maxlen - *buflen - 1;
if (len < 1)
break;
* @param[in] packet_size Size, in bytes, of a valid packet.
* @param is_valid Callback that assesses whether the packet is valid or not.
* @param[in] timeout_ms The timeout after which, if no packet is detected, to
- * abort scanning.
+ * abort scanning.
* @param[in] baudrate The baudrate of the serial port. This parameter is not
- * critical, but it helps fine tune the serial port polling
- * delay.
+ * critical, but it helps fine tune the serial port polling
+ * delay.
*
* @retval SR_OK Valid packet was found within the given timeout.
* @retval SR_ERR Failure.
+ *
+ * @private
*/
SR_PRIV int serial_stream_detect(struct sr_serial_dev_inst *serial,
uint8_t *buf, size_t *buflen,
{
uint64_t start, time, byte_delay_us;
size_t ibuf, i, maxlen;
- int len;
+ ssize_t len;
maxlen = *buflen;
}
/* Assume 8n1 transmission. That is 10 bits for every byte. */
- byte_delay_us = 10 * (1000000 / baudrate);
+ byte_delay_us = 10 * ((1000 * 1000) / baudrate);
start = g_get_monotonic_time();
i = ibuf = len = 0;
if ((ibuf - i) >= packet_size) {
/* We have at least a packet's worth of data. */
if (is_valid(&buf[i])) {
- sr_spew("Found valid %d-byte packet after "
+ sr_spew("Found valid %zu-byte packet after "
"%" PRIu64 "ms.", (ibuf - i), time);
*buflen = ibuf;
return SR_OK;
} else {
- sr_spew("Got %d bytes, but not a valid "
+ sr_spew("Got %zu bytes, but not a valid "
"packet.", (ibuf - i));
}
/* Not a valid packet. Continue searching. */
}
if (time >= timeout_ms) {
/* Timeout */
- sr_dbg("Detection timed out after %dms.", time);
+ sr_dbg("Detection timed out after %" PRIu64 "ms.", time);
break;
}
if (len < 1)
*buflen = ibuf;
- sr_err("Didn't find a valid packet (read %d bytes).", *buflen);
+ sr_err("Didn't find a valid packet (read %zu bytes).", *buflen);
return SR_ERR;
}
* Extract the serial device and options from the options linked list.
*
* @param options List of options passed from the command line.
- * @param serial_device Pointer where to store the exctracted serial device.
+ * @param serial_device Pointer where to store the extracted serial device.
* @param serial_options Pointer where to store the optional extracted serial
* options.
*
* @return SR_OK if a serial_device is found, SR_ERR if no device is found. The
* returned string should not be freed by the caller.
+ *
+ * @private
*/
SR_PRIV int sr_serial_extract_options(GSList *options, const char **serial_device,
const char **serial_options)
switch (src->key) {
case SR_CONF_CONN:
*serial_device = g_variant_get_string(src->data, NULL);
- sr_dbg("Parsed serial device: %s", *serial_device);
+ sr_dbg("Parsed serial device: %s.", *serial_device);
break;
-
case SR_CONF_SERIALCOMM:
*serial_options = g_variant_get_string(src->data, NULL);
- sr_dbg("Parsed serial options: %s", *serial_options);
+ sr_dbg("Parsed serial options: %s.", *serial_options);
break;
}
}
if (!*serial_device) {
- sr_dbg("No serial device specified");
+ sr_dbg("No serial device specified.");
return SR_ERR;
}
return SR_OK;
}
-#ifdef _WIN32
+/** @cond PRIVATE */
+#ifdef G_OS_WIN32
typedef HANDLE event_handle;
#else
typedef int event_handle;
#endif
+/** @endcond */
+/** @private */
SR_PRIV int serial_source_add(struct sr_session *session,
struct sr_serial_dev_inst *serial, int events, int timeout,
sr_receive_data_callback cb, void *cb_data)
{
+ struct sp_event_set *event_set;
+ gintptr poll_fd;
+ unsigned int poll_events;
enum sp_event mask = 0;
- unsigned int i;
- if (sp_new_event_set(&serial->event_set) != SP_OK)
+ if ((events & (G_IO_IN|G_IO_ERR)) && (events & G_IO_OUT)) {
+ sr_err("Cannot poll input/error and output simultaneously.");
+ return SR_ERR_ARG;
+ }
+
+ if (sp_new_event_set(&event_set) != SP_OK)
return SR_ERR;
if (events & G_IO_IN)
if (events & G_IO_ERR)
mask |= SP_EVENT_ERROR;
- if (sp_add_port_events(serial->event_set, serial->data, mask) != SP_OK) {
- sp_free_event_set(serial->event_set);
+ if (sp_add_port_events(event_set, serial->data, mask) != SP_OK) {
+ sp_free_event_set(event_set);
return SR_ERR;
}
-
- serial->pollfds = (GPollFD *) g_malloc0(sizeof(GPollFD) * serial->event_set->count);
-
- for (i = 0; i < serial->event_set->count; i++) {
-
- serial->pollfds[i].fd = ((event_handle *) serial->event_set->handles)[i];
-
- mask = serial->event_set->masks[i];
-
- if (mask & SP_EVENT_RX_READY)
- serial->pollfds[i].events |= G_IO_IN;
- if (mask & SP_EVENT_TX_READY)
- serial->pollfds[i].events |= G_IO_OUT;
- if (mask & SP_EVENT_ERROR)
- serial->pollfds[i].events |= G_IO_ERR;
-
- if (sr_session_source_add_pollfd(session, &serial->pollfds[i],
- timeout, cb, cb_data) != SR_OK)
- return SR_ERR;
+ if (event_set->count != 1) {
+ sr_err("Unexpected number (%u) of event handles to poll.",
+ event_set->count);
+ sp_free_event_set(event_set);
+ return SR_ERR;
}
- return SR_OK;
+ poll_fd = (gintptr) ((event_handle *)event_set->handles)[0];
+ mask = event_set->masks[0];
+
+ sp_free_event_set(event_set);
+
+ poll_events = 0;
+ if (mask & SP_EVENT_RX_READY)
+ poll_events |= G_IO_IN;
+ if (mask & SP_EVENT_TX_READY)
+ poll_events |= G_IO_OUT;
+ if (mask & SP_EVENT_ERROR)
+ poll_events |= G_IO_ERR;
+ /*
+ * Using serial->data as the key for the event source is not quite
+ * proper, as it makes it impossible to create another event source
+ * for the same serial port. However, these fixed keys will soon be
+ * removed from the API anyway, so this is OK for now.
+ */
+ return sr_session_fd_source_add(session, serial->data,
+ poll_fd, poll_events, timeout, cb, cb_data);
}
+/** @private */
SR_PRIV int serial_source_remove(struct sr_session *session,
struct sr_serial_dev_inst *serial)
{
- unsigned int i;
-
- for (i = 0; i < serial->event_set->count; i++)
- if (sr_session_source_remove_pollfd(session, &serial->pollfds[i]) != SR_OK)
- return SR_ERR;
-
- g_free(serial->pollfds);
- sp_free_event_set(serial->event_set);
-
- serial->pollfds = NULL;
- serial->event_set = NULL;
-
- return SR_OK;
+ return sr_session_source_remove_internal(session, serial->data);
}
+/**
+ * Create/allocate a new sr_serial_port structure.
+ *
+ * @param name The OS dependent name of the serial port. Must not be NULL.
+ * @param description An end user friendly description for the serial port.
+ * Can be NULL (in that case the empty string is used
+ * as description).
+ *
+ * @return The newly allocated sr_serial_port struct.
+ */
static struct sr_serial_port *sr_serial_new(const char *name,
const char *description)
{
if (!name)
return NULL;
- serial = g_malloc(sizeof(*serial));
+ serial = g_malloc(sizeof(struct sr_serial_port));
serial->name = g_strdup(name);
serial->description = g_strdup(description ? description : "");
+
return serial;
}
+/**
+ * Free a previously allocated sr_serial_port structure.
+ *
+ * @param serial The sr_serial_port struct to free. Must not be NULL.
+ */
SR_API void sr_serial_free(struct sr_serial_port *serial)
{
- if (serial == NULL)
+ if (!serial)
return;
g_free(serial->name);
g_free(serial->description);
{
GSList *tty_devs = NULL;
struct sp_port **ports;
+ struct sr_serial_port *port;
int i;
+ /* Currently unused, but will be used by some drivers later on. */
(void)driver;
if (sp_list_ports(&ports) != SP_OK)
return NULL;
- for (i=0; ports[i]; i++) {
- struct sr_serial_port *port = sr_serial_new(sp_get_port_name(ports[i]),
- sp_get_port_description(ports[i]));
+ for (i = 0; ports[i]; i++) {
+ port = sr_serial_new(sp_get_port_name(ports[i]),
+ sp_get_port_description(ports[i]));
tty_devs = g_slist_append(tty_devs, port);
}
sp_free_port_list(ports);
+
return tty_devs;
}
* @return A GSList of strings containing the path of the serial device or
* NULL if no serial device is found. The returned list must be freed
* by the caller.
+ *
+ * @private
*/
SR_PRIV GSList *sr_serial_find_usb(uint16_t vendor_id, uint16_t product_id)
{
if (sp_list_ports(&ports) != SP_OK)
return NULL;
- for (i=0; ports[i]; i++)
+ for (i = 0; ports[i]; i++)
if (sp_get_port_transport(ports[i]) == SP_TRANSPORT_USB &&
sp_get_port_usb_vid_pid(ports[i], &vid, &pid) == SP_OK &&
- vid == vendor_id && pid == product_id)
+ vid == vendor_id && pid == product_id) {
tty_devs = g_slist_prepend(tty_devs,
- g_strdup(sp_get_port_name(ports[i])));
+ g_strdup(sp_get_port_name(ports[i])));
+ }
sp_free_port_list(ports);
+
return tty_devs;
}
+/** @private */
SR_PRIV int serial_timeout(struct sr_serial_dev_inst *port, int num_bytes)
{
struct sp_port_config *config;
return timeout_ms;
}
+
+/** @} */