]> sigrok.org Git - libsigrok.git/blob - hardware/common/scpi_serial.c
Centralise duplicated logging helper defines.
[libsigrok.git] / hardware / common / scpi_serial.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2013 poljar (Damir Jelić) <poljarinho@gmail.com>
5  * Copyright (C) 2013 Martin Ling <martin-sigrok@earth.li>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "libsigrok.h"
22 #include "libsigrok-internal.h"
23
24 #include <glib.h>
25 #include <string.h>
26
27 #define LOG_PREFIX "scpi_serial"
28
29 #define SCPI_READ_RETRIES 100
30 #define SCPI_READ_RETRY_TIMEOUT 10000
31
32 SR_PRIV int scpi_serial_open(void *priv)
33 {
34         struct sr_serial_dev_inst *serial = priv;
35
36         if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
37                 return SR_ERR;
38
39         if (serial_flush(serial) != SR_OK)
40                 return SR_ERR;
41
42         return SR_OK;
43 }
44
45 SR_PRIV int scpi_serial_source_add(void *priv, int events, int timeout,
46                         sr_receive_data_callback_t cb, void *cb_data)
47 {
48         struct sr_serial_dev_inst *serial = priv;
49
50         return serial_source_add(serial, events, timeout, cb, cb_data);
51 }
52
53 SR_PRIV int scpi_serial_source_remove(void *priv)
54 {
55         struct sr_serial_dev_inst *serial = priv;
56
57         return serial_source_remove(serial);
58 }
59
60 SR_PRIV int scpi_serial_send(void *priv, const char *command)
61 {
62         int len, result, written;
63         gchar *terminated_command;
64         struct sr_serial_dev_inst *serial = priv;
65
66         terminated_command = g_strconcat(command, "\n", NULL);
67         len = strlen(terminated_command);
68         written = 0;
69         while (written < len) {
70                 result = serial_write(serial, terminated_command + written, len - written);
71                 if (result < 0) {
72                         sr_err("Error while sending SCPI command: '%s'.", command);
73                         g_free(terminated_command);
74                         return SR_ERR;
75                 }
76                 written += result;
77         }
78
79         g_free(terminated_command);
80
81         sr_spew("Successfully sent SCPI command: '%s'.", command);
82
83         return SR_OK;
84 }
85
86 SR_PRIV int scpi_serial_receive(void *priv, char **scpi_response)
87 {
88         int len, ret;
89         char buf[256];
90         unsigned int i;
91         GString *response;
92         struct sr_serial_dev_inst *serial = priv;
93
94         response = g_string_sized_new(1024);
95
96         for (i = 0; i <= SCPI_READ_RETRIES; i++) {
97                 while ((len = serial_read(serial, buf, sizeof(buf))) > 0)
98                         response = g_string_append_len(response, buf, len);
99
100                 if (response->len > 0 &&
101                     response->str[response->len-1] == '\n') {
102                         sr_spew("Fetched full SCPI response.");
103                         break;
104                 }
105
106                 g_usleep(SCPI_READ_RETRY_TIMEOUT);
107         }
108
109         if (response->len == 0) {
110                 sr_dbg("No SCPI response received.");
111                 g_string_free(response, TRUE);
112                 *scpi_response = NULL;
113                 return SR_ERR;
114         } else if (response->str[response->len - 1] == '\n') {
115                 /*
116                  * The SCPI response contains a LF ('\n') at the end and we
117                  * don't need this so replace it with a '\0' and decrement
118                  * the length.
119                  */
120                 response->str[--response->len] = '\0';
121                 ret = SR_OK;
122         } else {
123                 sr_warn("Incomplete SCPI response received!");
124                 ret = SR_ERR;
125         }
126
127         /* Minor optimization: steal the string instead of copying. */
128         *scpi_response = response->str;
129
130         /* A SCPI response can be quite large, print at most 50 characters. */
131         sr_dbg("SCPI response received (length %d): '%.50s'",
132                response->len, response->str);
133
134         g_string_free(response, FALSE);
135
136         return ret;
137 }
138
139 /* Some stubs to keep the compiler from whining. */
140 static int scpi_serial_read(void *priv, char *buf, int maxlen)
141 {
142         return serial_read(priv, buf, maxlen);
143 }
144 static int scpi_serial_close(void *priv)
145 {
146         return serial_close(priv);
147 }
148 static void scpi_serial_free(void *priv)
149 {
150         return sr_serial_dev_inst_free(priv);
151 }
152
153 SR_PRIV struct sr_scpi_dev_inst *scpi_serial_dev_inst_new(const char *port,
154                 const char *serialcomm)
155 {
156         struct sr_scpi_dev_inst *scpi;
157         struct sr_serial_dev_inst *serial;
158
159         scpi = g_try_malloc(sizeof(struct sr_scpi_dev_inst));
160
161         if (!(serial = sr_serial_dev_inst_new(port, serialcomm)))
162         {
163                 g_free(scpi);
164                 return NULL;
165         }
166
167         scpi->open = scpi_serial_open;
168         scpi->source_add = scpi_serial_source_add;
169         scpi->source_remove = scpi_serial_source_remove;
170         scpi->send = scpi_serial_send;
171         scpi->receive = scpi_serial_receive;
172         scpi->read = scpi_serial_read;
173         scpi->close = scpi_serial_close;
174         scpi->free = scpi_serial_free;
175         scpi->priv = serial;
176
177         return scpi;
178 }