X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=src%2Fserial.c;h=106090b72927e230a6dd389f04a640fe312f94ab;hb=856433b26e0b06860463321c34b715e9c1393bb6;hp=5c3648317298af1d9232fc6e4bea69ed0443f2c1;hpb=b79c3422789d181ad47d4a3707d18d7feea73b5d;p=libsigrok.git diff --git a/src/serial.c b/src/serial.c index 5c364831..106090b7 100644 --- a/src/serial.c +++ b/src/serial.c @@ -55,12 +55,10 @@ #ifdef HAVE_SERIAL_COMM -/* See if a (assumed opened) serial port is of any supported type. */ +/* See if an (assumed opened) serial port is of any supported type. */ static int dev_is_supported(struct sr_serial_dev_inst *serial) { - if (!serial) - return 0; - if (!serial->lib_funcs) + if (!serial || !serial->lib_funcs) return 0; return 1; @@ -226,21 +224,53 @@ SR_PRIV int serial_drain(struct sr_serial_dev_inst *serial) * via UART can get stored in a GString (which is a char array). Since * the API hides this detail, we can address this issue later when needed. * Callers use the API which communicates bytes. + * + * Applications optionally can register a "per RX chunk" callback, when + * they depend on the frame boundaries of the respective physical layer. + * Most callers just want the stream of RX data, and can use the buffer. + * + * The availability of RX chunks to callbacks, as well as the capability + * to pass on exact frames as chunks or potential re-assembly of chunks + * to a single data block, depend on each transport's implementation. */ +/** + * Register application callback for RX data chunks. + * + * @param[in] serial Previously initialized serial port instance. + * @param[in] cb Routine to call as RX data becomes available. + * @param[in] cb_data User data to pass to the callback in addition to RX data. + * + * @retval SR_ERR_ARG Invalid parameters. + * @retval SR_OK Successful registration. + * + * Callbacks get unregistered by specifying NULL for the 'cb' parameter. + * + * @private + */ +SR_PRIV int serial_set_read_chunk_cb(struct sr_serial_dev_inst *serial, + serial_rx_chunk_callback cb, void *cb_data) +{ + if (!serial) + return SR_ERR_ARG; + + serial->rx_chunk_cb_func = cb; + serial->rx_chunk_cb_data = cb_data; + + return SR_OK; +} + /** * Discard previously queued RX data. Internal to the serial subsystem, * coordination between common and transport specific support code. * * @param[in] serial Previously opened serial port instance. * - * @internal + * @private */ SR_PRIV void sr_ser_discard_queued_data(struct sr_serial_dev_inst *serial) { - if (!serial) - return; - if (!serial->rcv_buffer) + if (!serial || !serial->rcv_buffer) return; g_string_truncate(serial->rcv_buffer, 0); @@ -252,13 +282,11 @@ SR_PRIV void sr_ser_discard_queued_data(struct sr_serial_dev_inst *serial) * * @param[in] serial Previously opened serial port instance. * - * @internal + * @private */ SR_PRIV size_t sr_ser_has_queued_data(struct sr_serial_dev_inst *serial) { - if (!serial) - return 0; - if (!serial->rcv_buffer) + if (!serial || !serial->rcv_buffer) return 0; return serial->rcv_buffer->len; @@ -272,17 +300,17 @@ SR_PRIV size_t sr_ser_has_queued_data(struct sr_serial_dev_inst *serial) * @param[in] data Pointer to data bytes to queue. * @param[in] len Number of data bytes to queue. * - * @internal + * @private */ SR_PRIV void sr_ser_queue_rx_data(struct sr_serial_dev_inst *serial, const uint8_t *data, size_t len) { - if (!serial) - return; - if (!data || !len) + if (!serial || !data || !len) return; - if (serial->rcv_buffer) + if (serial->rx_chunk_cb_func) + serial->rx_chunk_cb_func(serial, serial->rx_chunk_cb_data, data, len); + else if (serial->rcv_buffer) g_string_append_len(serial->rcv_buffer, (const gchar *)data, len); } @@ -294,7 +322,7 @@ SR_PRIV void sr_ser_queue_rx_data(struct sr_serial_dev_inst *serial, * @param[out] data Pointer to store retrieved data bytes into. * @param[in] len Number of data bytes to retrieve. * - * @internal + * @private */ SR_PRIV size_t sr_ser_unqueue_rx_data(struct sr_serial_dev_inst *serial, uint8_t *data, size_t len) @@ -302,9 +330,7 @@ SR_PRIV size_t sr_ser_unqueue_rx_data(struct sr_serial_dev_inst *serial, size_t qlen; GString *buf; - if (!serial) - return 0; - if (!data || !len) + if (!serial || !data || !len) return 0; qlen = sr_ser_has_queued_data(serial); @@ -331,6 +357,8 @@ SR_PRIV size_t sr_ser_unqueue_rx_data(struct sr_serial_dev_inst *serial, * * Returns 0 if no receive data is available, or if the amount of * available receive data cannot get determined. + * + * @private */ SR_PRIV size_t serial_has_receive_data(struct sr_serial_dev_inst *serial) { @@ -546,7 +574,7 @@ 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])(.*)$" +#define SERIAL_COMM_SPEC "^(\\d+)(/([5678])([neo])([12]))?(.*)$" /** @endcond */ GRegex *reg; @@ -554,7 +582,10 @@ SR_PRIV int serial_set_paramstr(struct sr_serial_dev_inst *serial, int speed, databits, parity, stopbits, flow, rts, dtr, i; char *mstr, **opts, **kv; - speed = databits = parity = stopbits = flow = 0; + speed = flow = 0; + databits = 8; + parity = SP_PARITY_NONE; + stopbits = 1; rts = dtr = -1; sr_spew("Parsing parameters from \"%s\".", paramstr); reg = g_regex_new(SERIAL_COMM_SPEC, 0, 0, NULL); @@ -562,10 +593,10 @@ SR_PRIV int serial_set_paramstr(struct sr_serial_dev_inst *serial, if ((mstr = g_match_info_fetch(match, 1))) speed = strtoul(mstr, NULL, 10); g_free(mstr); - if ((mstr = g_match_info_fetch(match, 2))) + if ((mstr = g_match_info_fetch(match, 3)) && mstr[0]) databits = strtoul(mstr, NULL, 10); g_free(mstr); - if ((mstr = g_match_info_fetch(match, 3))) { + if ((mstr = g_match_info_fetch(match, 4)) && mstr[0]) { switch (mstr[0]) { case 'n': parity = SP_PARITY_NONE; @@ -579,10 +610,10 @@ SR_PRIV int serial_set_paramstr(struct sr_serial_dev_inst *serial, } } g_free(mstr); - if ((mstr = g_match_info_fetch(match, 4))) + if ((mstr = g_match_info_fetch(match, 5)) && mstr[0]) stopbits = strtoul(mstr, NULL, 10); g_free(mstr); - if ((mstr = g_match_info_fetch(match, 5)) && mstr[0] != '\0') { + if ((mstr = g_match_info_fetch(match, 6)) && mstr[0] != '\0') { if (mstr[0] != '/') { sr_dbg("missing separator before extra options"); speed = 0; @@ -630,6 +661,8 @@ SR_PRIV int serial_set_paramstr(struct sr_serial_dev_inst *serial, } g_match_info_unref(match); g_regex_unref(reg); + sr_spew("Got params: rate %d, frame %d/%d/%d, flow %d, rts %d, dtr %d.", + speed, databits, parity, stopbits, flow, rts, dtr); if (speed) { return serial_set_params(serial, speed, databits, parity, @@ -715,9 +748,6 @@ SR_PRIV int serial_readline(struct sr_serial_dev_inst *serial, * @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. - * @param[in] baudrate The baudrate of the serial port. This parameter is not - * 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. @@ -728,7 +758,7 @@ SR_PRIV int serial_stream_detect(struct sr_serial_dev_inst *serial, uint8_t *buf, size_t *buflen, size_t packet_size, packet_valid_callback is_valid, - uint64_t timeout_ms, int baudrate) + uint64_t timeout_ms) { uint64_t start, time, byte_delay_us; size_t ibuf, i, maxlen; @@ -736,16 +766,16 @@ SR_PRIV int serial_stream_detect(struct sr_serial_dev_inst *serial, maxlen = *buflen; - sr_dbg("Detecting packets on %s (timeout = %" PRIu64 - "ms, baudrate = %d).", serial->port, timeout_ms, baudrate); + sr_dbg("Detecting packets on %s (timeout = %" PRIu64 "ms).", + serial->port, timeout_ms); - if (maxlen < (packet_size / 2) ) { + if (maxlen < (packet_size * 2) ) { sr_err("Buffer size must be at least twice the packet size."); return SR_ERR; } /* Assume 8n1 transmission. That is 10 bits for every byte. */ - byte_delay_us = 10 * ((1000 * 1000) / baudrate); + byte_delay_us = serial_timeout(serial, 1) * 1000; start = g_get_monotonic_time(); i = ibuf = len = 0; @@ -996,9 +1026,7 @@ SR_PRIV GSList *sr_serial_find_usb(uint16_t vendor_id, uint16_t product_id) /** @private */ SR_PRIV int serial_timeout(struct sr_serial_dev_inst *port, int num_bytes) { - int bits, baud; - int ret; - int timeout_ms; + int bits, baud, ret, timeout_ms; /* Get the bitrate and frame length. */ bits = baud = 0;