+ if (devc->child.running) {
+ sr_err("Vendor application already running.");
+ return SR_ERR_BUG;
+ }
+
+ /* Prepare to feed sample data to the session. */
+ memset(&devc->rawdata, 0, sizeof(devc->rawdata));
+ memset(&devc->samples, 0, sizeof(devc->samples));
+ devc->samples.queue = feed_queue_logic_alloc(sdi,
+ FEED_QUEUE_DEPTH, sizeof(devc->samples.last_sample));
+
+ /*
+ * Start the background process. May take considerable time
+ * before actual acquisition starts.
+ */
+ sr_dbg("Starting vendor application");
+ argv = devc->child.argv;
+ flags = devc->child.flags;
+ error = NULL;
+ ok = g_spawn_async_with_pipes(NULL, argv, NULL, flags, NULL, NULL,
+ &pid, &fd_in, &fd_out, NULL, &error);
+ if (error) {
+ sr_err("Cannot execute RTM CLI process: %s", error->message);
+ g_error_free(error);
+ ok = FALSE;
+ }
+ if (fd_in < 0 || fd_out < 0)
+ ok = FALSE;
+ if (!ok) {
+ sr_err("Vendor application start failed.");
+ return SR_ERR_IO;
+ }
+ devc->child.pid = pid;
+ devc->child.fd_stdin_write = fd_in;
+ devc->child.fd_stdout_read = fd_out;
+ devc->child.running = TRUE;
+ sr_dbg("Started vendor application, in %d, out %d", fd_in, fd_out);
+ txt = sr_hexdump_new((const uint8_t *)&pid, sizeof(pid));
+ sr_dbg("Vendor application PID (OS dependent): %s", txt->str);
+ sr_hexdump_free(txt);
+
+ /*
+ * Get the initial response. Verifies its operation, and only
+ * returns with success when acquisition became operational.
+ */
+ rcvd = read(fd_out, rsp, sizeof(rsp));
+ sr_dbg("Read from vendor application, ret %zd", rcvd);
+ if (rcvd < 0)
+ ok = FALSE;
+ if (ok && (size_t)rcvd != sizeof(rsp))
+ ok = FALSE;
+ if (!ok) {
+ omega_rtm_cli_close(sdi);
+ return SR_ERR_IO;
+ }
+
+ /*
+ * Ignore the first timestamp. Grab the most recent sample data
+ * to feed the session from it upon later repetition.
+ */
+ rdptr = rsp;
+ stamp = read_u16le_inc(&rdptr);
+ sample1 = read_u16le_inc(&rdptr);
+ sample2 = read_u16le_inc(&rdptr);
+ sr_dbg("stamp %u, samples %x %x", stamp, sample1, sample2);
+ write_u16le(devc->samples.last_sample, sample2);
+
+ return SR_OK;
+}
+
+/*
+ * Terminate the external acquisition process (vendor's CLI application).
+ */
+SR_PRIV int omega_rtm_cli_close(const struct sr_dev_inst *sdi)
+{
+ struct dev_context *devc;
+
+ if (!sdi)
+ return SR_ERR_ARG;
+ devc = sdi->priv;
+ if (!devc)
+ return SR_ERR_ARG;
+
+ /* Close the external process' stdin. Discard its stdout. */
+ sr_dbg("Closing vendor application file descriptors.");
+ if (devc->child.fd_stdin_write >= 0) {
+ sr_dbg("Closing vendor application stdin descriptor.");
+ close(devc->child.fd_stdin_write);
+ devc->child.fd_stdin_write = -1;
+ }
+ if (devc->child.fd_stdout_read >= 0) {
+ sr_dbg("Closing vendor application stdout descriptor.");
+ close(devc->child.fd_stdout_read);
+ devc->child.fd_stdout_read = -1;
+ }
+
+ /* Terminate the external process. */
+ if (devc->child.running) {
+ sr_dbg("Closing vendor application process.");
+ (void)g_spawn_close_pid(devc->child.pid);
+ memset(&devc->child.pid, 0, sizeof(devc->child.pid));
+ devc->child.running = FALSE;
+ }
+
+ /* Release the session feed queue. */
+ if (devc->samples.queue) {
+ feed_queue_logic_free(devc->samples.queue);
+ devc->samples.queue = NULL;
+ }
+
+ sr_dbg("Done closing vendor application.");