+ return SR_OK;
+}
+
+/**
+ * Set serial parameters for the specified serial port from parameter string.
+ *
+ * @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
+ * \<baudrate\>=integer Baud rate.\n
+ * \<bits\>=5|6|7|8 Number of data bits.\n
+ * \<parity\>=n|e|o None, even, odd.\n
+ * \<stopbits\>=1|2 One or two stop bits.\n
+ * Options:\n
+ * dtr=0|1 Set DTR off resp. on.\n
+ * flow=0|1|2 Flow control. 0 for none, 1 for RTS/CTS, 2 for XON/XOFF.\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.
+ */
+SR_PRIV int serial_set_paramstr(struct sr_serial_dev_inst *serial,
+ const char *paramstr)
+{
+#define SERIAL_COMM_SPEC "^(\\d+)/([5678])([neo])([12])(.*)$"
+
+ GRegex *reg;
+ GMatchInfo *match;
+ int speed, databits, parity, stopbits, flow, rts, dtr, i;
+ char *mstr, **opts, **kv;
+
+ speed = databits = parity = stopbits = flow = 0;
+ rts = dtr = -1;
+ sr_spew("Parsing parameters from \"%s\".", paramstr);
+ reg = g_regex_new(SERIAL_COMM_SPEC, 0, 0, NULL);
+ if (g_regex_match(reg, paramstr, 0, &match)) {
+ if ((mstr = g_match_info_fetch(match, 1)))
+ speed = strtoul(mstr, NULL, 10);
+ g_free(mstr);
+ if ((mstr = g_match_info_fetch(match, 2)))
+ databits = strtoul(mstr, NULL, 10);
+ g_free(mstr);
+ if ((mstr = g_match_info_fetch(match, 3))) {
+ switch (mstr[0]) {
+ case 'n':
+ parity = SERIAL_PARITY_NONE;
+ break;
+ case 'e':
+ parity = SERIAL_PARITY_EVEN;
+ break;
+ case 'o':
+ parity = SERIAL_PARITY_ODD;
+ break;
+ }
+ }
+ g_free(mstr);
+ if ((mstr = g_match_info_fetch(match, 4)))
+ stopbits = strtoul(mstr, NULL, 10);
+ g_free(mstr);
+ if ((mstr = g_match_info_fetch(match, 5)) && mstr[0] != '\0') {
+ if (mstr[0] != '/') {
+ sr_dbg("missing separator before extra options");
+ speed = 0;
+ } else {
+ /* A set of "key=value" options separated by / */
+ opts = g_strsplit(mstr + 1, "/", 0);
+ for (i = 0; opts[i]; i++) {
+ kv = g_strsplit(opts[i], "=", 2);
+ if (!strncmp(kv[0], "rts", 3)) {
+ if (kv[1][0] == '1')
+ rts = 1;
+ else if (kv[1][0] == '0')
+ rts = 0;
+ else {
+ sr_dbg("invalid value for rts: %c", kv[1][0]);
+ speed = 0;
+ }
+ } else if (!strncmp(kv[0], "dtr", 3)) {
+ if (kv[1][0] == '1')
+ dtr = 1;
+ else if (kv[1][0] == '0')
+ dtr = 0;
+ else {
+ sr_dbg("invalid value for dtr: %c", kv[1][0]);
+ speed = 0;
+ }
+ } else if (!strncmp(kv[0], "flow", 4)) {
+ if (kv[1][0] == '0')
+ flow = 0;
+ else if (kv[1][0] == '1')
+ flow = 1;
+ else if (kv[1][0] == '2')
+ flow = 2;
+ else {
+ sr_dbg("invalid value for flow: %c", kv[1][0]);
+ speed = 0;
+ }
+ }
+ g_strfreev(kv);
+ }
+ g_strfreev(opts);
+ }
+ }
+ g_free(mstr);