]> sigrok.org Git - libsigrok.git/blob - hardware/common/scpi_serial.c
Revise SCPI read API to allow backend-independent data handling.
[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 struct scpi_serial {
33         struct sr_serial_dev_inst *serial;
34         char last_character;
35 };
36
37 SR_PRIV int scpi_serial_open(void *priv)
38 {
39         struct scpi_serial *sscpi = priv;
40         struct sr_serial_dev_inst *serial = sscpi->serial;
41
42         if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
43                 return SR_ERR;
44
45         if (serial_flush(serial) != SR_OK)
46                 return SR_ERR;
47
48         return SR_OK;
49 }
50
51 SR_PRIV int scpi_serial_source_add(void *priv, int events, int timeout,
52                         sr_receive_data_callback_t cb, void *cb_data)
53 {
54         struct scpi_serial *sscpi = priv;
55         struct sr_serial_dev_inst *serial = sscpi->serial;
56
57         return serial_source_add(serial, events, timeout, cb, cb_data);
58 }
59
60 SR_PRIV int scpi_serial_source_remove(void *priv)
61 {
62         struct scpi_serial *sscpi = priv;
63         struct sr_serial_dev_inst *serial = sscpi->serial;
64
65         return serial_source_remove(serial);
66 }
67
68 SR_PRIV int scpi_serial_send(void *priv, const char *command)
69 {
70         int len, result, written;
71         gchar *terminated_command;
72         struct scpi_serial *sscpi = priv;
73         struct sr_serial_dev_inst *serial = sscpi->serial;
74
75         terminated_command = g_strconcat(command, "\n", NULL);
76         len = strlen(terminated_command);
77         written = 0;
78         while (written < len) {
79                 result = serial_write(serial, terminated_command + written, len - written);
80                 if (result < 0) {
81                         sr_err("Error while sending SCPI command: '%s'.", command);
82                         g_free(terminated_command);
83                         return SR_ERR;
84                 }
85                 written += result;
86         }
87
88         g_free(terminated_command);
89
90         sr_spew("Successfully sent SCPI command: '%s'.", command);
91
92         return SR_OK;
93 }
94
95 SR_PRIV int scpi_serial_receive(void *priv, char **scpi_response)
96 {
97         int len, ret;
98         char buf[256];
99         unsigned int i;
100         GString *response;
101         struct scpi_serial *sscpi = priv;
102         struct sr_serial_dev_inst *serial = sscpi->serial;
103
104         response = g_string_sized_new(1024);
105
106         for (i = 0; i <= SCPI_READ_RETRIES; i++) {
107                 while ((len = serial_read(serial, buf, sizeof(buf))) > 0)
108                         response = g_string_append_len(response, buf, len);
109
110                 if (response->len > 0 &&
111                     response->str[response->len-1] == '\n') {
112                         sr_spew("Fetched full SCPI response.");
113                         break;
114                 }
115
116                 g_usleep(SCPI_READ_RETRY_TIMEOUT);
117         }
118
119         if (response->len == 0) {
120                 sr_dbg("No SCPI response received.");
121                 g_string_free(response, TRUE);
122                 *scpi_response = NULL;
123                 return SR_ERR;
124         } else if (response->str[response->len - 1] == '\n') {
125                 /*
126                  * The SCPI response contains a LF ('\n') at the end and we
127                  * don't need this so replace it with a '\0' and decrement
128                  * the length.
129                  */
130                 response->str[--response->len] = '\0';
131                 ret = SR_OK;
132         } else {
133                 sr_warn("Incomplete SCPI response received!");
134                 ret = SR_ERR;
135         }
136
137         /* Minor optimization: steal the string instead of copying. */
138         *scpi_response = response->str;
139
140         /* A SCPI response can be quite large, print at most 50 characters. */
141         sr_dbg("SCPI response received (length %d): '%.50s'",
142                response->len, response->str);
143
144         g_string_free(response, FALSE);
145
146         return ret;
147 }
148
149 SR_PRIV int scpi_serial_read_begin(void *priv)
150 {
151         struct scpi_serial *sscpi = priv;
152
153         sscpi->last_character = '\0';
154
155         return SR_OK;
156 }
157
158 SR_PRIV int scpi_serial_read_data(void *priv, char *buf, int maxlen)
159 {
160         struct scpi_serial *sscpi = priv;
161         int ret;
162
163         ret = serial_read(sscpi->serial, buf, maxlen);
164
165         if (ret < 0)
166                 return ret;
167
168         if (ret > 0) {
169                 sscpi->last_character = buf[ret - 1];
170                 if (sscpi->last_character == '\n')
171                         ret--;
172         }
173
174         return ret;
175 }
176
177 SR_PRIV int scpi_serial_read_complete(void *priv)
178 {
179         struct scpi_serial *sscpi = priv;
180
181         return (sscpi->last_character == '\n');
182 }
183
184 static int scpi_serial_close(void *priv)
185 {
186         struct scpi_serial *sscpi = priv;
187         struct sr_serial_dev_inst *serial = sscpi->serial;
188
189         return serial_close(serial);
190 }
191
192 static void scpi_serial_free(void *priv)
193 {
194         struct scpi_serial *sscpi = priv;
195         struct sr_serial_dev_inst *serial = sscpi->serial;
196
197         sr_serial_dev_inst_free(serial);
198         g_free(sscpi);
199 }
200
201 SR_PRIV struct sr_scpi_dev_inst *scpi_serial_dev_inst_new(const char *port,
202                 const char *serialcomm)
203 {
204         struct sr_scpi_dev_inst *scpi;
205         struct scpi_serial *sscpi;
206         struct sr_serial_dev_inst *serial;
207
208         if (!(serial = sr_serial_dev_inst_new(port, serialcomm)))
209                 return NULL;
210
211         sscpi = g_malloc(sizeof(struct scpi_serial));
212
213         sscpi->serial = serial;
214
215         scpi = g_malloc(sizeof(struct sr_scpi_dev_inst));
216
217         scpi->open = scpi_serial_open;
218         scpi->source_add = scpi_serial_source_add;
219         scpi->source_remove = scpi_serial_source_remove;
220         scpi->send = scpi_serial_send;
221         scpi->read_begin = scpi_serial_read_begin;
222         scpi->read_data = scpi_serial_read_data;
223         scpi->read_complete = scpi_serial_read_complete;
224         scpi->close = scpi_serial_close;
225         scpi->free = scpi_serial_free;
226         scpi->priv = sscpi;
227
228         return scpi;
229 }