api.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619
  1. /*
  2. * This file is part of the libsigrok project.
  3. *
  4. * Copyright (C) 2013, 2014 Matthias Heidbrink <m-sigrok@heidbrink.biz>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. /** @file
  20. * Gossen Metrawatt Metrahit 1x/2x drivers
  21. * @internal
  22. */
  23. #include <string.h>
  24. #include "protocol.h"
  25. /* Serial communication parameters for Metrahit 1x/2x with 'RS232' adaptor */
  26. #define SERIALCOMM_1X_RS232 "8228/6n1/dtr=1/rts=1/flow=0" /* =8192, closer with divider */
  27. #define SERIALCOMM_2X_RS232 "9600/6n1/dtr=1/rts=1/flow=0"
  28. #define SERIALCOMM_2X "9600/8n1/dtr=1/rts=1/flow=0"
  29. #define VENDOR_GMC "Gossen Metrawatt"
  30. SR_PRIV struct sr_dev_driver gmc_mh_1x_2x_rs232_driver_info;
  31. SR_PRIV struct sr_dev_driver gmc_mh_2x_bd232_driver_info;
  32. static const int32_t hwopts[] = {
  33. SR_CONF_CONN,
  34. SR_CONF_SERIALCOMM,
  35. };
  36. /** Hardware capabilities for Metrahit 1x/2x devices in send mode. */
  37. static const int32_t hwcaps_sm[] = {
  38. SR_CONF_MULTIMETER,
  39. SR_CONF_THERMOMETER, /**< All GMC 1x/2x multimeters seem to support this */
  40. SR_CONF_LIMIT_SAMPLES,
  41. SR_CONF_LIMIT_MSEC,
  42. SR_CONF_CONTINUOUS,
  43. };
  44. /** Hardware capabilities for Metrahit 2x devices in bidirectional Mode. */
  45. static const int32_t hwcaps_bd[] = {
  46. SR_CONF_MULTIMETER,
  47. SR_CONF_THERMOMETER, /**< All GMC 1x/2x multimeters seem to support this */
  48. SR_CONF_LIMIT_SAMPLES,
  49. SR_CONF_LIMIT_MSEC,
  50. SR_CONF_CONTINUOUS,
  51. SR_CONF_POWER_OFF,
  52. };
  53. /* TODO:
  54. * - For the 29S SR_CONF_ENERGYMETER, too.
  55. * - SR_CONF_PATTERN_MODE for some 2x devices
  56. * - SR_CONF_DATALOG for 22M, 26M, 29S and storage adaptors.
  57. * Need to implement device-specific lists.
  58. */
  59. /** Init driver gmc_mh_1x_2x_rs232. */
  60. static int init_1x_2x_rs232(struct sr_context *sr_ctx)
  61. {
  62. return std_init(sr_ctx, &gmc_mh_1x_2x_rs232_driver_info, LOG_PREFIX);
  63. }
  64. /** Init driver gmc_mh_2x_bd232. */
  65. static int init_2x_bd232(struct sr_context *sr_ctx)
  66. {
  67. return std_init(sr_ctx, &gmc_mh_2x_bd232_driver_info, LOG_PREFIX);
  68. }
  69. /**
  70. * Read single byte from serial port.
  71. *
  72. * @retval -1 Timeout or error.
  73. * @retval other Byte.
  74. */
  75. static int read_byte(struct sr_serial_dev_inst *serial, gint64 timeout)
  76. {
  77. uint8_t result = 0;
  78. int rc = 0;
  79. for (;;) {
  80. rc = serial_read(serial, &result, 1);
  81. if (rc == 1) {
  82. sr_spew("read: 0x%02x/%d", result, result);
  83. return result;
  84. }
  85. if (g_get_monotonic_time() > timeout)
  86. return -1;
  87. g_usleep(2000);
  88. }
  89. }
  90. /**
  91. * Try to detect GMC 1x/2x multimeter model in send mode for max. 1 second.
  92. *
  93. * @param serial Configured, open serial port.
  94. *
  95. * @retval NULL Detection failed.
  96. * @retval other Model code.
  97. */
  98. static enum model scan_model_sm(struct sr_serial_dev_inst *serial)
  99. {
  100. int byte, bytecnt, cnt;
  101. enum model model;
  102. gint64 timeout_us;
  103. model = METRAHIT_NONE;
  104. timeout_us = g_get_monotonic_time() + 1 * 1000 * 1000;
  105. /*
  106. * Try to find message consisting of device code and several
  107. * (at least 4) data bytes.
  108. */
  109. for (bytecnt = 0; bytecnt < 100; bytecnt++) {
  110. byte = read_byte(serial, timeout_us);
  111. if ((byte == -1) || (timeout_us < g_get_monotonic_time()))
  112. break;
  113. if ((byte & MSGID_MASK) == MSGID_INF) {
  114. if (!(model = gmc_decode_model_sm(byte & MSGC_MASK)))
  115. break;
  116. /* Now expect (at least) 4 data bytes. */
  117. for (cnt = 0; cnt < 4; cnt++) {
  118. byte = read_byte(serial, timeout_us);
  119. if ((byte == -1) ||
  120. ((byte & MSGID_MASK) != MSGID_DATA))
  121. {
  122. model = METRAHIT_NONE;
  123. bytecnt = 100;
  124. break;
  125. }
  126. }
  127. break;
  128. }
  129. }
  130. return model;
  131. }
  132. /**
  133. * Scan for Metrahit 1x and Metrahit 2x in send mode using Gossen Metrawatt
  134. * 'RS232' interface.
  135. *
  136. * The older 1x models use 8192 baud and the newer 2x 9600 baud.
  137. * The DMM usually sends up to about 20 messages per second. However, depending
  138. * on configuration and measurement mode the intervals can be much larger and
  139. * then the detection might not work.
  140. */
  141. static GSList *scan_1x_2x_rs232(GSList *options)
  142. {
  143. struct sr_dev_inst *sdi;
  144. struct drv_context *drvc;
  145. struct dev_context *devc;
  146. struct sr_config *src;
  147. struct sr_channel *ch;
  148. struct sr_serial_dev_inst *serial;
  149. GSList *l, *devices;
  150. const char *conn, *serialcomm;
  151. enum model model;
  152. gboolean serialcomm_given;
  153. devices = NULL;
  154. drvc = (&gmc_mh_1x_2x_rs232_driver_info)->priv;
  155. drvc->instances = NULL;
  156. conn = serialcomm = NULL;
  157. model = METRAHIT_NONE;
  158. serialcomm_given = FALSE;
  159. sr_spew("scan_1x_2x_rs232() called!");
  160. for (l = options; l; l = l->next) {
  161. src = l->data;
  162. switch (src->key) {
  163. case SR_CONF_CONN:
  164. conn = g_variant_get_string(src->data, NULL);
  165. break;
  166. case SR_CONF_SERIALCOMM:
  167. serialcomm = g_variant_get_string(src->data, NULL);
  168. serialcomm_given = TRUE;
  169. break;
  170. }
  171. }
  172. if (!conn)
  173. return NULL;
  174. if (!serialcomm)
  175. serialcomm = SERIALCOMM_2X_RS232;
  176. if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
  177. return NULL;
  178. if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK) {
  179. sr_serial_dev_inst_free(serial);
  180. return NULL;
  181. }
  182. serial_flush(serial);
  183. model = scan_model_sm(serial);
  184. /*
  185. * If detection failed and no user-supplied parameters,
  186. * try second baud rate.
  187. */
  188. if ((model == METRAHIT_NONE) && !serialcomm_given) {
  189. serialcomm = SERIALCOMM_1X_RS232;
  190. g_free(serial->serialcomm);
  191. serial->serialcomm = g_strdup(serialcomm);
  192. if (serial_set_paramstr(serial, serialcomm) == SR_OK) {
  193. serial_flush(serial);
  194. model = scan_model_sm(serial);
  195. }
  196. }
  197. if (model != METRAHIT_NONE) {
  198. sr_spew("%s %s detected!", VENDOR_GMC, gmc_model_str(model));
  199. if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR_GMC,
  200. gmc_model_str(model), NULL)))
  201. return NULL;
  202. if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
  203. sr_err("Device context malloc failed.");
  204. return NULL;
  205. }
  206. devc->model = model;
  207. devc->limit_samples = 0;
  208. devc->limit_msec = 0;
  209. devc->num_samples = 0;
  210. devc->elapsed_msec = g_timer_new();
  211. devc->settings_ok = FALSE;
  212. sdi->conn = serial;
  213. sdi->priv = devc;
  214. sdi->driver = &gmc_mh_1x_2x_rs232_driver_info;
  215. if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
  216. return NULL;
  217. sdi->channels = g_slist_append(sdi->channels, ch);
  218. drvc->instances = g_slist_append(drvc->instances, sdi);
  219. devices = g_slist_append(devices, sdi);
  220. }
  221. return devices;
  222. }
  223. /** Scan for Metrahit 2x in a bidirectional mode using Gossen Metrawatt 'BD 232' interface.
  224. *
  225. */
  226. static GSList *scan_2x_bd232(GSList *options)
  227. {
  228. struct sr_dev_inst *sdi;
  229. struct drv_context *drvc;
  230. struct dev_context *devc;
  231. struct sr_config *src;
  232. struct sr_channel *ch;
  233. struct sr_serial_dev_inst *serial;
  234. GSList *l, *devices;
  235. const char *conn, *serialcomm;
  236. int cnt, byte;
  237. gint64 timeout_us;
  238. sdi = NULL;
  239. devc = NULL;
  240. conn = serialcomm = NULL;
  241. devices = NULL;
  242. drvc = (&gmc_mh_2x_bd232_driver_info)->priv;
  243. drvc->instances = NULL;
  244. sr_spew("scan_2x_bd232() called!");
  245. for (l = options; l; l = l->next) {
  246. src = l->data;
  247. switch (src->key) {
  248. case SR_CONF_CONN:
  249. conn = g_variant_get_string(src->data, NULL);
  250. break;
  251. case SR_CONF_SERIALCOMM:
  252. serialcomm = g_variant_get_string(src->data, NULL);
  253. break;
  254. }
  255. }
  256. if (!conn)
  257. return NULL;
  258. if (!serialcomm)
  259. serialcomm = SERIALCOMM_2X;
  260. if (!(serial = sr_serial_dev_inst_new(conn, serialcomm)))
  261. return NULL;
  262. if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
  263. goto exit_err;
  264. if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
  265. sr_err("Device context malloc failed.");
  266. goto exit_err;
  267. }
  268. if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR_GMC, NULL, NULL)))
  269. goto exit_err;
  270. sdi->priv = devc;
  271. /* Send message 03 "Query multimeter version and status" */
  272. sdi->conn = serial;
  273. sdi->priv = devc;
  274. if (req_stat14(sdi, TRUE) != SR_OK)
  275. goto exit_err;
  276. /* Wait for reply from device(s) for up to 2s. */
  277. timeout_us = g_get_monotonic_time() + 2*1000*1000;
  278. while (timeout_us > g_get_monotonic_time()) {
  279. /* Receive reply (14 bytes) */
  280. devc->buflen = 0;
  281. for (cnt = 0; cnt < 14; cnt++) {
  282. byte = read_byte(serial, timeout_us);
  283. if (byte != -1)
  284. devc->buf[devc->buflen++] = (byte & MASK_6BITS);
  285. }
  286. if (devc->buflen != 14)
  287. continue;
  288. devc->addr = devc->buf[0];
  289. process_msg14(sdi);
  290. devc->buflen = 0;
  291. if (devc->model != METRAHIT_NONE) {
  292. sr_spew("%s %s detected!", VENDOR_GMC, gmc_model_str(devc->model));
  293. devc->elapsed_msec = g_timer_new();
  294. sdi->model = g_strdup(gmc_model_str(devc->model));
  295. sdi->version = g_strdup_printf("Firmware %d.%d", devc->fw_ver_maj, devc->fw_ver_min);
  296. sdi->conn = serial;
  297. sdi->priv = devc;
  298. sdi->driver = &gmc_mh_2x_bd232_driver_info;
  299. if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "P1")))
  300. goto exit_err;
  301. sdi->channels = g_slist_append(sdi->channels, ch);
  302. drvc->instances = g_slist_append(drvc->instances, sdi);
  303. devices = g_slist_append(devices, sdi);
  304. if (!(devc = g_try_malloc0(sizeof(struct dev_context)))) {
  305. sr_err("Device context malloc failed.");
  306. goto exit_err;
  307. }
  308. if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR_GMC, NULL, NULL)))
  309. goto exit_err;
  310. }
  311. };
  312. /* Free last alloc if no device found */
  313. if (devc->model == METRAHIT_NONE) {
  314. g_free(devc);
  315. sr_dev_inst_free(sdi);
  316. }
  317. return devices;
  318. exit_err:
  319. sr_info("scan_2x_bd232(): Error!");
  320. if (serial)
  321. sr_serial_dev_inst_free(serial);
  322. if (devc)
  323. g_free(devc);
  324. if (sdi)
  325. sr_dev_inst_free(sdi);
  326. return NULL;
  327. }
  328. /** Driver device list function */
  329. static GSList *dev_list_1x_2x_rs232(void)
  330. {
  331. return ((struct drv_context *)(gmc_mh_1x_2x_rs232_driver_info.priv))->instances;
  332. }
  333. /** Driver device list function */
  334. static GSList *dev_list_2x_bd232(void)
  335. {
  336. return ((struct drv_context *)(gmc_mh_2x_bd232_driver_info.priv))
  337. ->instances;
  338. }
  339. static int dev_close(struct sr_dev_inst *sdi)
  340. {
  341. struct dev_context *devc;
  342. std_serial_dev_close(sdi);
  343. sdi->status = SR_ST_INACTIVE;
  344. /* Free dynamically allocated resources. */
  345. if ((devc = sdi->priv) && devc->elapsed_msec) {
  346. g_timer_destroy(devc->elapsed_msec);
  347. devc->elapsed_msec = NULL;
  348. devc->model = METRAHIT_NONE;
  349. }
  350. return SR_OK;
  351. }
  352. static int cleanup_sm_rs232(void)
  353. {
  354. return std_dev_clear(&gmc_mh_1x_2x_rs232_driver_info, NULL);
  355. }
  356. static int cleanup_2x_bd232(void)
  357. {
  358. return std_dev_clear(&gmc_mh_2x_bd232_driver_info, NULL);
  359. }
  360. /** Get value of configuration item */
  361. static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
  362. const struct sr_channel_group *cg)
  363. {
  364. int ret;
  365. struct dev_context *devc;
  366. (void)cg;
  367. ret = SR_OK;
  368. if (!sdi || !(devc = sdi->priv))
  369. return SR_ERR_ARG;
  370. ret = SR_OK;
  371. switch (key) {
  372. case SR_CONF_LIMIT_SAMPLES:
  373. *data = g_variant_new_uint64(devc->limit_samples);
  374. break;
  375. case SR_CONF_LIMIT_MSEC:
  376. *data = g_variant_new_uint64(devc->limit_msec);
  377. break;
  378. case SR_CONF_POWER_OFF:
  379. *data = g_variant_new_boolean(FALSE);
  380. break;
  381. default:
  382. return SR_ERR_NA;
  383. }
  384. return ret;
  385. }
  386. /** Implementation of config_list, auxiliary function for common parts, */
  387. static int config_list_common(int key, GVariant **data, const struct sr_dev_inst *sdi,
  388. const struct sr_channel_group *cg)
  389. {
  390. (void)sdi;
  391. (void)cg;
  392. switch (key) {
  393. case SR_CONF_SCAN_OPTIONS:
  394. *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
  395. hwopts, ARRAY_SIZE(hwopts), sizeof(int32_t));
  396. break;
  397. default:
  398. return SR_ERR_NA;
  399. }
  400. return SR_OK;
  401. }
  402. /** Implementation of config_list for Metrahit 1x/2x send mode */
  403. static int config_list_sm(int key, GVariant **data, const struct sr_dev_inst *sdi,
  404. const struct sr_channel_group *cg)
  405. {
  406. switch (key) {
  407. case SR_CONF_DEVICE_OPTIONS:
  408. *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
  409. hwcaps_sm, ARRAY_SIZE(hwcaps_sm), sizeof(int32_t));
  410. break;
  411. default:
  412. return config_list_common(key, data, sdi, cg);
  413. }
  414. return SR_OK;
  415. }
  416. /** Implementation of config_list for Metrahit 2x bidirectional mode */
  417. static int config_list_bd(int key, GVariant **data, const struct sr_dev_inst *sdi,
  418. const struct sr_channel_group *cg)
  419. {
  420. switch (key) {
  421. case SR_CONF_DEVICE_OPTIONS:
  422. *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
  423. hwcaps_bd, ARRAY_SIZE(hwcaps_bd), sizeof(int32_t));
  424. break;
  425. default:
  426. return config_list_common(key, data, sdi, cg);
  427. }
  428. return SR_OK;
  429. }
  430. static int dev_acquisition_start_1x_2x_rs232(const struct sr_dev_inst *sdi,
  431. void *cb_data)
  432. {
  433. struct dev_context *devc;
  434. struct sr_serial_dev_inst *serial;
  435. if (!sdi || !cb_data || !(devc = sdi->priv))
  436. return SR_ERR_BUG;
  437. if (sdi->status != SR_ST_ACTIVE)
  438. return SR_ERR_DEV_CLOSED;
  439. devc->cb_data = cb_data;
  440. devc->settings_ok = FALSE;
  441. devc->buflen = 0;
  442. /* Send header packet to the session bus. */
  443. std_session_send_df_header(cb_data, LOG_PREFIX);
  444. /* Start timer, if required. */
  445. if (devc->limit_msec)
  446. g_timer_start(devc->elapsed_msec);
  447. /* Poll every 40ms, or whenever some data comes in. */
  448. serial = sdi->conn;
  449. serial_source_add(serial, G_IO_IN, 40, gmc_mh_1x_2x_receive_data,
  450. (void *)sdi);
  451. return SR_OK;
  452. }
  453. static int dev_acquisition_start_2x_bd232(const struct sr_dev_inst *sdi,
  454. void *cb_data)
  455. {
  456. struct dev_context *devc;
  457. struct sr_serial_dev_inst *serial;
  458. if (!sdi || !cb_data || !(devc = sdi->priv))
  459. return SR_ERR_BUG;
  460. if (sdi->status != SR_ST_ACTIVE)
  461. return SR_ERR_DEV_CLOSED;
  462. devc->cb_data = cb_data;
  463. devc->settings_ok = FALSE;
  464. devc->buflen = 0;
  465. /* Send header packet to the session bus. */
  466. std_session_send_df_header(cb_data, LOG_PREFIX);
  467. /* Start timer, if required. */
  468. if (devc->limit_msec)
  469. g_timer_start(devc->elapsed_msec);
  470. /* Poll every 40ms, or whenever some data comes in. */
  471. serial = sdi->conn;
  472. serial_source_add(serial, G_IO_IN, 40, gmc_mh_2x_receive_data,
  473. (void *)sdi);
  474. /* Send start message */
  475. return req_meas14(sdi);
  476. }
  477. static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
  478. {
  479. struct dev_context *devc;
  480. /* Stop timer, if required. */
  481. if (sdi && (devc = sdi->priv) && devc->limit_msec)
  482. g_timer_stop(devc->elapsed_msec);
  483. return std_serial_dev_acquisition_stop(sdi, cb_data, dev_close,
  484. sdi->conn, LOG_PREFIX);
  485. }
  486. SR_PRIV struct sr_dev_driver gmc_mh_1x_2x_rs232_driver_info = {
  487. .name = "gmc-mh-1x-2x-rs232",
  488. .longname = "Gossen Metrawatt Metrahit 1x/2x, RS232 interface",
  489. .api_version = 1,
  490. .init = init_1x_2x_rs232,
  491. .cleanup = cleanup_sm_rs232,
  492. .scan = scan_1x_2x_rs232,
  493. .dev_list = dev_list_1x_2x_rs232,
  494. .dev_clear = NULL,
  495. .config_get = config_get,
  496. .config_set = config_set,
  497. .config_list = config_list_sm,
  498. .dev_open = std_serial_dev_open,
  499. .dev_close = dev_close,
  500. .dev_acquisition_start = dev_acquisition_start_1x_2x_rs232,
  501. .dev_acquisition_stop = dev_acquisition_stop,
  502. .priv = NULL,
  503. };
  504. SR_PRIV struct sr_dev_driver gmc_mh_2x_bd232_driver_info = {
  505. .name = "gmc-mh-2x-bd232",
  506. .longname = "Gossen Metrawatt Metrahit 2x, BD232/SI232-II interface",
  507. .api_version = 1,
  508. .init = init_2x_bd232,
  509. .cleanup = cleanup_2x_bd232,
  510. .scan = scan_2x_bd232,
  511. .dev_list = dev_list_2x_bd232,
  512. .dev_clear = NULL,
  513. .config_get = config_get,
  514. .config_set = config_set,
  515. .config_list = config_list_bd,
  516. .dev_open = std_serial_dev_open,
  517. .dev_close = dev_close,
  518. .dev_acquisition_start = dev_acquisition_start_2x_bd232,
  519. .dev_acquisition_stop = dev_acquisition_stop,
  520. .priv = NULL,
  521. };