+/** Scan for Metrahit 2x in a bidirectional mode using Gossen Metrawatt 'BD 232' interface.
+ *
+ */
+static GSList *scan_2x_bd232(GSList *options)
+{
+ struct sr_dev_inst *sdi;
+ struct drv_context *drvc;
+ struct dev_context *devc;
+ struct sr_config *src;
+ struct sr_channel *ch;
+ struct sr_serial_dev_inst *serial;
+ GSList *l, *devices;
+ const char *conn, *serialcomm;
+ int cnt, byte;
+ gint64 timeout_us;
+
+ sdi = NULL;
+ devc = NULL;
+ conn = serialcomm = NULL;
+ devices = NULL;
+
+ drvc = (&gmc_mh_2x_bd232_driver_info)->priv;
+ drvc->instances = NULL;
+
+ sr_spew("scan_2x_bd232() called!");
+
+ for (l = options; l; l = l->next) {
+ src = l->data;
+ switch (src->key) {
+ case SR_CONF_CONN:
+ conn = g_variant_get_string(src->data, NULL);
+ break;
+ case SR_CONF_SERIALCOMM:
+ serialcomm = g_variant_get_string(src->data, NULL);
+ break;
+ }
+ }
+ if (!conn)
+ return NULL;
+ if (!serialcomm)
+ serialcomm = SERIALCOMM_2X;
+
+ if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
+ return NULL;
+
+ if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
+ goto exit_err;
+
+ if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+ sr_err("Device context malloc failed.");
+ goto exit_err;
+ }
+
+ if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR_GMC, NULL, NULL)))
+ goto exit_err;
+
+ sdi->priv = devc;
+
+ /* Send message 03 "Query multimeter version and status" */
+ sdi->conn = serial;
+ sdi->priv = devc;
+ if (req_stat14(sdi, TRUE) != SR_OK)
+ goto exit_err;
+
+ /* Wait for reply from device(s) for up to 2s. */
+ timeout_us = g_get_monotonic_time() + 2*1000*1000;
+
+ while (timeout_us > g_get_monotonic_time()) {
+ /* Receive reply (14 bytes) */
+ devc->buflen = 0;
+ for (cnt = 0; cnt < 14; cnt++) {
+ byte = read_byte(serial, timeout_us);
+ if (byte != -1)
+ devc->buf[devc->buflen++] = (byte & MASK_6BITS);
+ }
+
+ if (devc->buflen != 14)
+ continue;
+
+ devc->addr = devc->buf[0];
+ process_msg14(sdi);
+ devc->buflen = 0;
+
+ if (devc->model != METRAHIT_NONE) {
+ sr_spew("%s %s detected!", VENDOR_GMC, gmc_model_str(devc->model));
+
+ devc->elapsed_msec = g_timer_new();
+
+ sdi->model = g_strdup(gmc_model_str(devc->model));
+ sdi->version = g_strdup_printf("Firmware %d.%d", devc->fw_ver_maj, devc->fw_ver_min);
+ sdi->conn = serial;
+ sdi->priv = devc;
+ sdi->driver = &gmc_mh_2x_bd232_driver_info;
+ if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
+ goto exit_err;
+ sdi->channels = g_slist_append(sdi->channels, ch);
+ drvc->instances = g_slist_append(drvc->instances, sdi);
+ devices = g_slist_append(devices, sdi);
+
+ if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
+ sr_err("Device context malloc failed.");
+ goto exit_err;
+ }
+
+ if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR_GMC, NULL, NULL)))
+ goto exit_err;
+ }
+ };
+
+ /* Free last alloc if no device found */
+ if (devc->model == METRAHIT_NONE) {
+ g_free(devc);
+ sr_dev_inst_free(sdi);
+ }
+
+ return devices;
+
+exit_err:
+ sr_info("scan_2x_bd232(): Error!");
+
+ if (serial)
+ sr_serial_dev_inst_free(serial);
+ if (devc)
+ g_free(devc);
+ if (sdi)
+ sr_dev_inst_free(sdi);
+
+ return NULL;
+}
+