]> sigrok.org Git - libsigrok.git/blob - hardware/common/scpi_serial.c
scpi: add a struct drv_context parameter to scpi_dev_inst_new()
[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 BUFFER_SIZE 1024
30
31 struct scpi_serial {
32         struct sr_serial_dev_inst *serial;
33         char buffer[BUFFER_SIZE];
34         size_t count;
35         size_t read;
36 };
37
38 static int scpi_serial_dev_inst_new(void *priv, struct drv_context *drvc,
39                 const char *resource, char **params, const char *serialcomm)
40 {
41         struct scpi_serial *sscpi = priv;
42
43         (void)drvc;
44         (void)params;
45
46         if (!(sscpi->serial = sr_serial_dev_inst_new(resource, serialcomm)))
47                 return SR_ERR;
48
49         return SR_OK;
50 }
51
52 static int scpi_serial_open(void *priv)
53 {
54         struct scpi_serial *sscpi = priv;
55         struct sr_serial_dev_inst *serial = sscpi->serial;
56
57         if (serial_open(serial, SERIAL_RDWR | SERIAL_NONBLOCK) != SR_OK)
58                 return SR_ERR;
59
60         if (serial_flush(serial) != SR_OK)
61                 return SR_ERR;
62
63         sscpi->count = 0;
64         sscpi->read = 0;
65
66         return SR_OK;
67 }
68
69 static int scpi_serial_source_add(void *priv, int events, int timeout,
70                         sr_receive_data_callback_t cb, void *cb_data)
71 {
72         struct scpi_serial *sscpi = priv;
73         struct sr_serial_dev_inst *serial = sscpi->serial;
74
75         return serial_source_add(serial, events, timeout, cb, cb_data);
76 }
77
78 static int scpi_serial_source_remove(void *priv)
79 {
80         struct scpi_serial *sscpi = priv;
81         struct sr_serial_dev_inst *serial = sscpi->serial;
82
83         return serial_source_remove(serial);
84 }
85
86 static int scpi_serial_send(void *priv, const char *command)
87 {
88         int len, result, written;
89         gchar *terminated_command;
90         struct scpi_serial *sscpi = priv;
91         struct sr_serial_dev_inst *serial = sscpi->serial;
92
93         terminated_command = g_strconcat(command, "\n", NULL);
94         len = strlen(terminated_command);
95         written = 0;
96         while (written < len) {
97                 result = serial_write(serial, terminated_command + written, len - written);
98                 if (result < 0) {
99                         sr_err("Error while sending SCPI command: '%s'.", command);
100                         g_free(terminated_command);
101                         return SR_ERR;
102                 }
103                 written += result;
104         }
105
106         g_free(terminated_command);
107
108         sr_spew("Successfully sent SCPI command: '%s'.", command);
109
110         return SR_OK;
111 }
112
113 static int scpi_serial_read_begin(void *priv)
114 {
115         (void) priv;
116
117         return SR_OK;
118 }
119
120 static int scpi_serial_read_data(void *priv, char *buf, int maxlen)
121 {
122         struct scpi_serial *sscpi = priv;
123         int len, ret;
124
125         len = BUFFER_SIZE - sscpi->count;
126
127         /* Try to read new data into the buffer if there is space. */
128         if (len > 0) {
129                 ret = serial_read(sscpi->serial, sscpi->buffer + sscpi->read,
130                                 BUFFER_SIZE - sscpi->count);
131
132                 if (ret < 0)
133                         return ret;
134
135                 sscpi->count += ret;
136
137                 if (ret > 0)
138                         sr_spew("Read %d bytes into buffer.", ret);
139         }
140
141         /* Return as many bytes as possible from buffer, excluding any trailing newline. */
142         if (sscpi->read < sscpi->count) {
143                 len = sscpi->count - sscpi->read;
144                 if (len > maxlen)
145                         len = maxlen;
146                 if (sscpi->buffer[sscpi->read + len - 1] == '\n')
147                         len--;
148                 sr_spew("Returning %d bytes from buffer.", len);
149                 memcpy(buf, sscpi->buffer + sscpi->read, len);
150                 sscpi->read += len;
151                 if (sscpi->read == BUFFER_SIZE) {
152                         sr_spew("Resetting buffer.");
153                         sscpi->count = 0;
154                         sscpi->read = 0;
155                 }
156                 return len;
157         }
158
159         return 0;
160 }
161
162 static int scpi_serial_read_complete(void *priv)
163 {
164         struct scpi_serial *sscpi = priv;
165
166         /* If the next character is a newline, discard it and report complete. */
167         if (sscpi->read < sscpi->count && sscpi->buffer[sscpi->read] == '\n') {
168                 sscpi->read++;
169                 return 1;
170         } else {
171                 return 0;
172         }
173 }
174
175 static int scpi_serial_close(void *priv)
176 {
177         struct scpi_serial *sscpi = priv;
178
179         return serial_close(sscpi->serial);
180 }
181
182 static void scpi_serial_free(void *priv)
183 {
184         struct scpi_serial *sscpi = priv;
185
186         sr_serial_dev_inst_free(sscpi->serial);
187 }
188
189 SR_PRIV const struct sr_scpi_dev_inst scpi_serial_dev = {
190         .name          = "serial",
191         .prefix        = "",
192         .priv_size     = sizeof(struct scpi_serial),
193         .dev_inst_new  = scpi_serial_dev_inst_new,
194         .open          = scpi_serial_open,
195         .source_add    = scpi_serial_source_add,
196         .source_remove = scpi_serial_source_remove,
197         .send          = scpi_serial_send,
198         .read_begin    = scpi_serial_read_begin,
199         .read_data     = scpi_serial_read_data,
200         .read_complete = scpi_serial_read_complete,
201         .close         = scpi_serial_close,
202         .free          = scpi_serial_free,
203 };