]> sigrok.org Git - libsigrok.git/blobdiff - src/serial.c
Revert "bindings/ruby: Disable Ruby bindings until we have a fix for #1526."
[libsigrok.git] / src / serial.c
index 5c3648317298af1d9232fc6e4bea69ed0443f2c1..106090b72927e230a6dd389f04a640fe312f94ab 100644 (file)
 
 #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;