api.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. /*
  2. * This file is part of the libsigrok project.
  3. *
  4. * Copyright (C) 2013 Bert Vermeulen <bert@biot.com>
  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. #include <string.h>
  20. #include "protocol.h"
  21. #define USB_CONN "1041.8101"
  22. #define VENDOR "Kecheng"
  23. #define USB_INTERFACE 0
  24. static const int32_t hwcaps[] = {
  25. SR_CONF_SOUNDLEVELMETER,
  26. SR_CONF_LIMIT_SAMPLES,
  27. SR_CONF_CONTINUOUS,
  28. SR_CONF_DATALOG,
  29. SR_CONF_SPL_WEIGHT_FREQ,
  30. SR_CONF_SPL_WEIGHT_TIME,
  31. SR_CONF_DATA_SOURCE,
  32. };
  33. SR_PRIV const uint64_t kecheng_kc_330b_sample_intervals[][2] = {
  34. { 1, 8 },
  35. { 1, 2 },
  36. { 1, 1 },
  37. { 2, 1 },
  38. { 5, 1 },
  39. { 10, 1 },
  40. { 60, 1 },
  41. };
  42. static const char *weight_freq[] = {
  43. "A",
  44. "C",
  45. };
  46. static const char *weight_time[] = {
  47. "F",
  48. "S",
  49. };
  50. static const char *data_sources[] = {
  51. "Live",
  52. "Memory",
  53. };
  54. SR_PRIV struct sr_dev_driver kecheng_kc_330b_driver_info;
  55. static struct sr_dev_driver *di = &kecheng_kc_330b_driver_info;
  56. static int init(struct sr_context *sr_ctx)
  57. {
  58. return std_init(sr_ctx, di, LOG_PREFIX);
  59. }
  60. static int scan_kecheng(struct sr_usb_dev_inst *usb, char **model)
  61. {
  62. struct drv_context *drvc;
  63. int len, ret;
  64. unsigned char cmd, buf[32];
  65. drvc = di->priv;
  66. if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
  67. return SR_ERR;
  68. cmd = CMD_IDENTIFY;
  69. ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, &cmd, 1, &len, 5);
  70. if (ret != 0) {
  71. libusb_close(usb->devhdl);
  72. sr_dbg("Failed to send Identify command: %s", libusb_error_name(ret));
  73. return SR_ERR;
  74. }
  75. ret = libusb_bulk_transfer(usb->devhdl, EP_IN, buf, 32, &len, 10);
  76. if (ret != 0) {
  77. libusb_close(usb->devhdl);
  78. sr_dbg("Failed to receive response: %s", libusb_error_name(ret));
  79. return SR_ERR;
  80. }
  81. libusb_close(usb->devhdl);
  82. usb->devhdl = NULL;
  83. if (len < 2 || buf[0] != (CMD_IDENTIFY | 0x80) || buf[1] > 30) {
  84. sr_dbg("Invalid response to Identify command");
  85. return SR_ERR;
  86. }
  87. buf[buf[1] + 2] = '\x0';
  88. *model = g_strndup((const gchar *)buf + 2, 30);
  89. return SR_OK;
  90. }
  91. static GSList *scan(GSList *options)
  92. {
  93. struct drv_context *drvc;
  94. struct dev_context *devc;
  95. struct sr_dev_inst *sdi;
  96. struct sr_channel *ch;
  97. GSList *usb_devices, *devices, *l;
  98. char *model;
  99. (void)options;
  100. drvc = di->priv;
  101. drvc->instances = NULL;
  102. devices = NULL;
  103. if ((usb_devices = sr_usb_find(drvc->sr_ctx->libusb_ctx, USB_CONN))) {
  104. /* We have a list of sr_usb_dev_inst matching the connection
  105. * string. Wrap them in sr_dev_inst and we're done. */
  106. for (l = usb_devices; l; l = l->next) {
  107. if (scan_kecheng(l->data, &model) != SR_OK)
  108. continue;
  109. if (!(sdi = sr_dev_inst_new(0, SR_ST_INACTIVE, VENDOR,
  110. model, NULL)))
  111. return NULL;
  112. g_free(model);
  113. sdi->driver = di;
  114. sdi->inst_type = SR_INST_USB;
  115. sdi->conn = l->data;
  116. if (!(ch = sr_channel_new(0, SR_CHANNEL_ANALOG, TRUE, "SPL")))
  117. return NULL;
  118. sdi->channels = g_slist_append(sdi->channels, ch);
  119. if (!(devc = g_try_malloc(sizeof(struct dev_context)))) {
  120. sr_dbg("Device context malloc failed.");
  121. return NULL;
  122. }
  123. sdi->priv = devc;
  124. devc->limit_samples = 0;
  125. /* The protocol provides no way to read the current
  126. * settings, so we'll enforce these. */
  127. devc->sample_interval = DEFAULT_SAMPLE_INTERVAL;
  128. devc->alarm_low = DEFAULT_ALARM_LOW;
  129. devc->alarm_high = DEFAULT_ALARM_HIGH;
  130. devc->mqflags = DEFAULT_WEIGHT_TIME | DEFAULT_WEIGHT_FREQ;
  131. devc->data_source = DEFAULT_DATA_SOURCE;
  132. devc->config_dirty = FALSE;
  133. /* TODO: Set date/time? */
  134. drvc->instances = g_slist_append(drvc->instances, sdi);
  135. devices = g_slist_append(devices, sdi);
  136. }
  137. g_slist_free(usb_devices);
  138. } else
  139. g_slist_free_full(usb_devices, g_free);
  140. return devices;
  141. }
  142. static GSList *dev_list(void)
  143. {
  144. return ((struct drv_context *)(di->priv))->instances;
  145. }
  146. static int dev_open(struct sr_dev_inst *sdi)
  147. {
  148. struct drv_context *drvc;
  149. struct sr_usb_dev_inst *usb;
  150. int ret;
  151. if (!(drvc = di->priv)) {
  152. sr_err("Driver was not initialized.");
  153. return SR_ERR;
  154. }
  155. usb = sdi->conn;
  156. if (sr_usb_open(drvc->sr_ctx->libusb_ctx, usb) != SR_OK)
  157. return SR_ERR;
  158. if ((ret = libusb_set_configuration(usb->devhdl, 1))) {
  159. sr_err("Failed to set configuration: %s.", libusb_error_name(ret));
  160. return SR_ERR;
  161. }
  162. if ((ret = libusb_claim_interface(usb->devhdl, USB_INTERFACE))) {
  163. sr_err("Failed to claim interface: %s.", libusb_error_name(ret));
  164. return SR_ERR;
  165. }
  166. sdi->status = SR_ST_ACTIVE;
  167. return ret;
  168. }
  169. static int dev_close(struct sr_dev_inst *sdi)
  170. {
  171. struct dev_context *devc;
  172. struct sr_usb_dev_inst *usb;
  173. if (!di->priv) {
  174. sr_err("Driver was not initialized.");
  175. return SR_ERR;
  176. }
  177. usb = sdi->conn;
  178. if (!usb->devhdl)
  179. /* Nothing to do. */
  180. return SR_OK;
  181. /* This allows a frontend to configure the device without ever
  182. * doing an acquisition step. */
  183. devc = sdi->priv;
  184. if (!devc->config_dirty)
  185. kecheng_kc_330b_configure(sdi);
  186. libusb_release_interface(usb->devhdl, USB_INTERFACE);
  187. libusb_close(usb->devhdl);
  188. usb->devhdl = NULL;
  189. sdi->status = SR_ST_INACTIVE;
  190. return SR_OK;
  191. }
  192. static int cleanup(void)
  193. {
  194. int ret;
  195. struct drv_context *drvc;
  196. if (!(drvc = di->priv))
  197. /* Can get called on an unused driver, doesn't matter. */
  198. return SR_OK;
  199. ret = std_dev_clear(di, NULL);
  200. g_free(drvc);
  201. di->priv = NULL;
  202. return ret;
  203. }
  204. static int config_get(int key, GVariant **data, const struct sr_dev_inst *sdi,
  205. const struct sr_channel_group *cg)
  206. {
  207. struct dev_context *devc;
  208. GVariant *rational[2];
  209. const uint64_t *si;
  210. (void)cg;
  211. devc = sdi->priv;
  212. switch (key) {
  213. case SR_CONF_LIMIT_SAMPLES:
  214. *data = g_variant_new_uint64(devc->limit_samples);
  215. break;
  216. case SR_CONF_SAMPLE_INTERVAL:
  217. si = kecheng_kc_330b_sample_intervals[devc->sample_interval];
  218. rational[0] = g_variant_new_uint64(si[0]);
  219. rational[1] = g_variant_new_uint64(si[1]);
  220. *data = g_variant_new_tuple(rational, 2);
  221. break;
  222. case SR_CONF_DATALOG:
  223. /* There really isn't a way to be sure the device is logging. */
  224. return SR_ERR_NA;
  225. break;
  226. case SR_CONF_SPL_WEIGHT_FREQ:
  227. if (devc->mqflags & SR_MQFLAG_SPL_FREQ_WEIGHT_A)
  228. *data = g_variant_new_string("A");
  229. else
  230. *data = g_variant_new_string("C");
  231. break;
  232. case SR_CONF_SPL_WEIGHT_TIME:
  233. if (devc->mqflags & SR_MQFLAG_SPL_TIME_WEIGHT_F)
  234. *data = g_variant_new_string("F");
  235. else
  236. *data = g_variant_new_string("S");
  237. break;
  238. case SR_CONF_DATA_SOURCE:
  239. if (devc->data_source == DATA_SOURCE_LIVE)
  240. *data = g_variant_new_string("Live");
  241. else
  242. *data = g_variant_new_string("Memory");
  243. break;
  244. default:
  245. return SR_ERR_NA;
  246. }
  247. return SR_OK;
  248. }
  249. static int config_set(int key, GVariant *data, const struct sr_dev_inst *sdi,
  250. const struct sr_channel_group *cg)
  251. {
  252. struct dev_context *devc;
  253. uint64_t p, q;
  254. unsigned int i;
  255. int tmp, ret;
  256. const char *tmp_str;
  257. (void)cg;
  258. if (sdi->status != SR_ST_ACTIVE)
  259. return SR_ERR_DEV_CLOSED;
  260. if (!di->priv) {
  261. sr_err("Driver was not initialized.");
  262. return SR_ERR;
  263. }
  264. devc = sdi->priv;
  265. ret = SR_OK;
  266. switch (key) {
  267. case SR_CONF_LIMIT_SAMPLES:
  268. devc->limit_samples = g_variant_get_uint64(data);
  269. sr_dbg("Setting sample limit to %" PRIu64 ".",
  270. devc->limit_samples);
  271. break;
  272. case SR_CONF_SAMPLE_INTERVAL:
  273. g_variant_get(data, "(tt)", &p, &q);
  274. for (i = 0; i < ARRAY_SIZE(kecheng_kc_330b_sample_intervals); i++) {
  275. if (kecheng_kc_330b_sample_intervals[i][0] != p || kecheng_kc_330b_sample_intervals[i][1] != q)
  276. continue;
  277. devc->sample_interval = i;
  278. devc->config_dirty = TRUE;
  279. break;
  280. }
  281. if (i == ARRAY_SIZE(kecheng_kc_330b_sample_intervals))
  282. ret = SR_ERR_ARG;
  283. break;
  284. case SR_CONF_SPL_WEIGHT_FREQ:
  285. tmp_str = g_variant_get_string(data, NULL);
  286. if (!strcmp(tmp_str, "A"))
  287. tmp = SR_MQFLAG_SPL_FREQ_WEIGHT_A;
  288. else if (!strcmp(tmp_str, "C"))
  289. tmp = SR_MQFLAG_SPL_FREQ_WEIGHT_C;
  290. else
  291. return SR_ERR_ARG;
  292. devc->mqflags &= ~(SR_MQFLAG_SPL_FREQ_WEIGHT_A | SR_MQFLAG_SPL_FREQ_WEIGHT_C);
  293. devc->mqflags |= tmp;
  294. devc->config_dirty = TRUE;
  295. break;
  296. case SR_CONF_SPL_WEIGHT_TIME:
  297. tmp_str = g_variant_get_string(data, NULL);
  298. if (!strcmp(tmp_str, "F"))
  299. tmp = SR_MQFLAG_SPL_TIME_WEIGHT_F;
  300. else if (!strcmp(tmp_str, "S"))
  301. tmp = SR_MQFLAG_SPL_TIME_WEIGHT_S;
  302. else
  303. return SR_ERR_ARG;
  304. devc->mqflags &= ~(SR_MQFLAG_SPL_TIME_WEIGHT_F | SR_MQFLAG_SPL_TIME_WEIGHT_S);
  305. devc->mqflags |= tmp;
  306. devc->config_dirty = TRUE;
  307. break;
  308. case SR_CONF_DATA_SOURCE:
  309. tmp_str = g_variant_get_string(data, NULL);
  310. if (!strcmp(tmp_str, "Live"))
  311. devc->data_source = DATA_SOURCE_LIVE;
  312. else if (!strcmp(tmp_str, "Memory"))
  313. devc->data_source = DATA_SOURCE_MEMORY;
  314. else
  315. return SR_ERR;
  316. devc->config_dirty = TRUE;
  317. break;
  318. default:
  319. ret = SR_ERR_NA;
  320. }
  321. return ret;
  322. }
  323. static int config_list(int key, GVariant **data, const struct sr_dev_inst *sdi,
  324. const struct sr_channel_group *cg)
  325. {
  326. GVariant *tuple, *rational[2];
  327. GVariantBuilder gvb;
  328. unsigned int i;
  329. (void)sdi;
  330. (void)cg;
  331. switch (key) {
  332. case SR_CONF_DEVICE_OPTIONS:
  333. *data = g_variant_new_fixed_array(G_VARIANT_TYPE_INT32,
  334. hwcaps, ARRAY_SIZE(hwcaps), sizeof(int32_t));
  335. break;
  336. case SR_CONF_SAMPLE_INTERVAL:
  337. g_variant_builder_init(&gvb, G_VARIANT_TYPE_ARRAY);
  338. for (i = 0; i < ARRAY_SIZE(kecheng_kc_330b_sample_intervals); i++) {
  339. rational[0] = g_variant_new_uint64(kecheng_kc_330b_sample_intervals[i][0]);
  340. rational[1] = g_variant_new_uint64(kecheng_kc_330b_sample_intervals[i][1]);
  341. tuple = g_variant_new_tuple(rational, 2);
  342. g_variant_builder_add_value(&gvb, tuple);
  343. }
  344. *data = g_variant_builder_end(&gvb);
  345. break;
  346. case SR_CONF_SPL_WEIGHT_FREQ:
  347. *data = g_variant_new_strv(weight_freq, ARRAY_SIZE(weight_freq));
  348. break;
  349. case SR_CONF_SPL_WEIGHT_TIME:
  350. *data = g_variant_new_strv(weight_time, ARRAY_SIZE(weight_time));
  351. break;
  352. case SR_CONF_DATA_SOURCE:
  353. *data = g_variant_new_strv(data_sources, ARRAY_SIZE(data_sources));
  354. break;
  355. default:
  356. return SR_ERR_NA;
  357. }
  358. return SR_OK;
  359. }
  360. static int dev_acquisition_start(const struct sr_dev_inst *sdi,
  361. void *cb_data)
  362. {
  363. struct drv_context *drvc;
  364. struct dev_context *devc;
  365. struct sr_datafeed_packet packet;
  366. struct sr_datafeed_meta meta;
  367. struct sr_config *src;
  368. struct sr_usb_dev_inst *usb;
  369. GVariant *gvar, *rational[2];
  370. const uint64_t *si;
  371. int stored_mqflags, req_len, buf_len, len, ret;
  372. unsigned char buf[9];
  373. if (sdi->status != SR_ST_ACTIVE)
  374. return SR_ERR_DEV_CLOSED;
  375. drvc = di->priv;
  376. devc = sdi->priv;
  377. usb = sdi->conn;
  378. devc->cb_data = cb_data;
  379. devc->num_samples = 0;
  380. /* Send header packet to the session bus. */
  381. std_session_send_df_header(cb_data, LOG_PREFIX);
  382. if (devc->data_source == DATA_SOURCE_LIVE) {
  383. /* Force configuration. */
  384. kecheng_kc_330b_configure(sdi);
  385. if (kecheng_kc_330b_status_get(sdi, &ret) != SR_OK)
  386. return SR_ERR;
  387. if (ret != DEVICE_ACTIVE) {
  388. sr_err("Device is inactive");
  389. /* Still continue though, since the device will
  390. * just return 30.0 until the user hits the button
  391. * on the device -- and then start feeding good
  392. * samples back. */
  393. }
  394. } else {
  395. if (kecheng_kc_330b_log_info_get(sdi, buf) != SR_OK)
  396. return SR_ERR;
  397. stored_mqflags = buf[4] ? SR_MQFLAG_SPL_TIME_WEIGHT_S : SR_MQFLAG_SPL_TIME_WEIGHT_F;
  398. stored_mqflags |= buf[5] ? SR_MQFLAG_SPL_FREQ_WEIGHT_C : SR_MQFLAG_SPL_FREQ_WEIGHT_A;
  399. devc->stored_samples = (buf[7] << 8) | buf[8];
  400. if (devc->stored_samples == 0) {
  401. /* Notify frontend of empty log by sending start/end packets. */
  402. packet.type = SR_DF_END;
  403. sr_session_send(cb_data, &packet);
  404. return SR_OK;
  405. }
  406. if (devc->limit_samples && devc->limit_samples < devc->stored_samples)
  407. devc->stored_samples = devc->limit_samples;
  408. si = kecheng_kc_330b_sample_intervals[buf[1]];
  409. rational[0] = g_variant_new_uint64(si[0]);
  410. rational[1] = g_variant_new_uint64(si[1]);
  411. gvar = g_variant_new_tuple(rational, 2);
  412. src = sr_config_new(SR_CONF_SAMPLE_INTERVAL, gvar);
  413. packet.type = SR_DF_META;
  414. packet.payload = &meta;
  415. meta.config = g_slist_append(NULL, src);
  416. sr_session_send(devc->cb_data, &packet);
  417. g_free(src);
  418. }
  419. if (!(devc->xfer = libusb_alloc_transfer(0)))
  420. return SR_ERR;
  421. usb_source_add(drvc->sr_ctx, 10,
  422. kecheng_kc_330b_handle_events, (void *)sdi);
  423. if (devc->data_source == DATA_SOURCE_LIVE) {
  424. buf[0] = CMD_GET_LIVE_SPL;
  425. buf_len = 1;
  426. devc->state = LIVE_SPL_WAIT;
  427. devc->last_live_request = g_get_monotonic_time() / 1000;
  428. req_len = 3;
  429. } else {
  430. buf[0] = CMD_GET_LOG_DATA;
  431. buf[1] = 0;
  432. buf[2] = 0;
  433. buf_len = 4;
  434. devc->state = LOG_DATA_WAIT;
  435. if (devc->stored_samples < 63)
  436. buf[3] = devc->stored_samples;
  437. else
  438. buf[3] = 63;
  439. /* Command ack byte + 2 bytes per sample. */
  440. req_len = 1 + buf[3] * 2;
  441. }
  442. ret = libusb_bulk_transfer(usb->devhdl, EP_OUT, buf, buf_len, &len, 5);
  443. if (ret != 0 || len != 1) {
  444. sr_dbg("Failed to start acquisition: %s", libusb_error_name(ret));
  445. libusb_free_transfer(devc->xfer);
  446. return SR_ERR;
  447. }
  448. libusb_fill_bulk_transfer(devc->xfer, usb->devhdl, EP_IN, devc->buf,
  449. req_len, kecheng_kc_330b_receive_transfer, (void *)sdi, 15);
  450. if (libusb_submit_transfer(devc->xfer) != 0) {
  451. libusb_free_transfer(devc->xfer);
  452. return SR_ERR;
  453. }
  454. return SR_OK;
  455. }
  456. static int dev_acquisition_stop(struct sr_dev_inst *sdi, void *cb_data)
  457. {
  458. struct dev_context *devc;
  459. (void)cb_data;
  460. if (sdi->status != SR_ST_ACTIVE)
  461. return SR_ERR_DEV_CLOSED;
  462. /* Signal USB transfer handler to clean up and stop. */
  463. sdi->status = SR_ST_STOPPING;
  464. devc = sdi->priv;
  465. if (devc->data_source == DATA_SOURCE_MEMORY && devc->config_dirty) {
  466. /* The protocol doesn't have a command to clear stored data;
  467. * it clears it whenever new configuration is set. That means
  468. * we can't just configure the device any time we want when
  469. * it's in DATA_SOURCE_MEMORY mode. The only safe time to do
  470. * it is now, when we're sure we've pulled in all the stored
  471. * data. */
  472. kecheng_kc_330b_configure(sdi);
  473. }
  474. return SR_OK;
  475. }
  476. SR_PRIV struct sr_dev_driver kecheng_kc_330b_driver_info = {
  477. .name = "kecheng-kc-330b",
  478. .longname = "Kecheng KC-330B",
  479. .api_version = 1,
  480. .init = init,
  481. .cleanup = cleanup,
  482. .scan = scan,
  483. .dev_list = dev_list,
  484. .dev_clear = NULL,
  485. .config_get = config_get,
  486. .config_set = config_set,
  487. .config_list = config_list,
  488. .dev_open = dev_open,
  489. .dev_close = dev_close,
  490. .dev_acquisition_start = dev_acquisition_start,
  491. .dev_acquisition_stop = dev_acquisition_stop,
  492. .priv = NULL,
  493. };