]> sigrok.org Git - libsigrok.git/blob - src/hardware/icstation-usbrelay/api.c
output/csv: use intermediate time_t var, silence compiler warning
[libsigrok.git] / src / hardware / icstation-usbrelay / api.c
1 /*
2  * This file is part of the libsigrok project.
3  *
4  * Copyright (C) 2021-2023 Frank Stettner <frank-stettner@gmx.net>
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
20 #include <config.h>
21
22 #include "protocol.h"
23
24 #define SERIALCOMM "9600/8n1"
25
26 static const uint32_t scanopts[] = {
27         SR_CONF_CONN,
28         SR_CONF_SERIALCOMM,
29 };
30
31 static const uint32_t drvopts[] = {
32         SR_CONF_MULTIPLEXER,
33 };
34
35 static const uint32_t devopts[] = {
36         SR_CONF_CONN | SR_CONF_GET,
37         SR_CONF_ENABLED | SR_CONF_SET, /* Enable/disable all relays at once. */
38 };
39
40 static const uint32_t devopts_cg[] = {
41         SR_CONF_ENABLED | SR_CONF_GET | SR_CONF_SET,
42 };
43
44 static const struct ics_usbrelay_profile supported_ics_usbrelay[] = {
45         { ICSE012A, 0xAB, "ICSE012A", 4 },
46         { ICSE013A, 0xAD, "ICSE013A", 2 },
47         { ICSE014A, 0xAC, "ICSE014A", 8 },
48 };
49
50 static GSList *scan(struct sr_dev_driver *di, GSList *options)
51 {
52         struct sr_dev_inst *sdi;
53         struct dev_context *devc;
54         struct sr_serial_dev_inst *serial;
55         GSList *devices;
56         size_t i, ch_idx;
57         const char *conn, *serialcomm;
58         int ret;
59         uint8_t device_id;
60         const struct ics_usbrelay_profile *profile;
61         struct sr_channel_group *cg;
62         struct channel_group_context *cgc;
63
64         devices = NULL;
65
66         /* Only scan for a device when conn= was specified. */
67         conn = NULL;
68         serialcomm = SERIALCOMM;
69         if (sr_serial_extract_options(options, &conn, &serialcomm) != SR_OK)
70                 return NULL;
71
72         serial = sr_serial_dev_inst_new(conn, serialcomm);
73         if (serial_open(serial, SERIAL_RDWR) != SR_OK)
74                 return NULL;
75
76         /* Get device model. */
77         ret = icstation_usbrelay_identify(serial, &device_id);
78         if (ret != SR_OK) {
79                 sr_err("Cannot retrieve identification details.");
80                 serial_close(serial);
81                 return NULL;
82         }
83
84         for (i = 0; i < ARRAY_SIZE(supported_ics_usbrelay); i++) {
85                 profile = &supported_ics_usbrelay[i];
86                 if (device_id != profile->id)
87                         continue;
88                 sdi = g_malloc0(sizeof(*sdi));
89                 sdi->status = SR_ST_INACTIVE;
90                 sdi->vendor = g_strdup("ICStation");
91                 sdi->model = g_strdup(profile->modelname);
92                 sdi->inst_type = SR_INST_SERIAL;
93                 sdi->conn = serial;
94                 sdi->connection_id = g_strdup(conn);
95
96                 devc = g_malloc0(sizeof(*devc));
97                 sdi->priv = devc;
98                 devc->relay_count = profile->nb_channels;
99                 devc->relay_mask = (1U << devc->relay_count) - 1;
100                 /* Assume that all relays are off at the start. */
101                 devc->relay_state = 0;
102                 for (ch_idx = 0; ch_idx < devc->relay_count; ch_idx++) {
103                         cg = g_malloc0(sizeof(*cg));
104                         cg->name = g_strdup_printf("R%zu", ch_idx + 1);
105                         cgc = g_malloc0(sizeof(*cgc));
106                         cg->priv = cgc;
107                         cgc->index = ch_idx;
108                         sdi->channel_groups = g_slist_append(sdi->channel_groups, cg);
109                 }
110
111                 devices = g_slist_append(devices, sdi);
112                 break;
113         }
114
115         serial_close(serial);
116         if (!devices) {
117                 sr_serial_dev_inst_free(serial);
118                 sr_warn("Unknown device identification 0x%02hhx.", device_id);
119         }
120
121         return std_scan_complete(di, devices);
122 }
123
124 static int config_get(uint32_t key, GVariant **data,
125         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
126 {
127         struct dev_context *devc;
128         struct channel_group_context *cgc;
129         uint8_t mask;
130         gboolean on;
131
132         if (!sdi || !data)
133                 return SR_ERR_ARG;
134         devc = sdi->priv;
135
136         if (!cg) {
137                 switch (key) {
138                 case SR_CONF_CONN:
139                         *data = g_variant_new_string(sdi->connection_id);
140                         break;
141                 default:
142                         return SR_ERR_NA;
143                 }
144         }
145
146         switch (key) {
147         case SR_CONF_ENABLED:
148                 cgc = cg->priv;
149                 mask = 1U << cgc->index;
150                 on = devc->relay_state & mask;
151                 *data = g_variant_new_boolean(on);
152                 return SR_OK;
153         default:
154                 return SR_ERR_NA;
155         }
156
157         return SR_OK;
158 }
159
160 static int config_set(uint32_t key, GVariant *data,
161         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
162 {
163         gboolean on;
164
165         if (!cg) {
166                 switch (key) {
167                 case SR_CONF_ENABLED:
168                         /* Enable/disable all channels at the same time. */
169                         on = g_variant_get_boolean(data);
170                         return icstation_usbrelay_switch_cg(sdi, cg, on);
171                 default:
172                         return SR_ERR_NA;
173                 }
174         } else {
175                 switch (key) {
176                 case SR_CONF_ENABLED:
177                         on = g_variant_get_boolean(data);
178                         return icstation_usbrelay_switch_cg(sdi, cg, on);
179                 default:
180                         return SR_ERR_NA;
181                 }
182         }
183
184         return SR_OK;
185 }
186
187 static int config_list(uint32_t key, GVariant **data,
188         const struct sr_dev_inst *sdi, const struct sr_channel_group *cg)
189 {
190         if (!cg) {
191                 switch (key) {
192                 case SR_CONF_SCAN_OPTIONS:
193                 case SR_CONF_DEVICE_OPTIONS:
194                         return STD_CONFIG_LIST(key, data, sdi, cg,
195                                 scanopts, drvopts, devopts);
196                 default:
197                         return SR_ERR_NA;
198                 }
199         }
200
201         switch (key) {
202         case SR_CONF_DEVICE_OPTIONS:
203                 *data = std_gvar_array_u32(ARRAY_AND_SIZE(devopts_cg));
204                 return SR_OK;
205         default:
206                 return SR_ERR_NA;
207         }
208 }
209
210 static int dev_open(struct sr_dev_inst *sdi)
211 {
212         struct sr_serial_dev_inst *serial;
213         int ret;
214
215         if (!sdi)
216                 return SR_ERR_ARG;
217         serial = sdi->conn;
218         if (!serial)
219                 return SR_ERR_ARG;
220
221         ret = std_serial_dev_open(sdi);
222         if (ret != SR_OK)
223                 return ret;
224
225         /* Start command mode. */
226         ret = icstation_usbrelay_start(sdi);
227         if (ret != SR_OK) {
228                 sr_err("Cannot initiate command mode.");
229                 serial_close(serial);
230                 return SR_ERR_IO;
231         }
232
233         return SR_OK;
234 }
235
236 static struct sr_dev_driver icstation_usbrelay_driver_info = {
237         .name = "icstation-usbrelay",
238         .longname = "ICStation USBRelay",
239         .api_version = 1,
240         .init = std_init,
241         .cleanup = std_cleanup,
242         .scan = scan,
243         .dev_list = std_dev_list,
244         .dev_clear = std_dev_clear,
245         .config_get = config_get,
246         .config_set = config_set,
247         .config_list = config_list,
248         .dev_open = dev_open,
249         .dev_close = std_serial_dev_close,
250         .dev_acquisition_start = std_dummy_dev_acquisition_start,
251         .dev_acquisition_stop = std_dummy_dev_acquisition_stop,
252         .context = NULL,
253 };
254 SR_REGISTER_DEV_DRIVER(icstation_usbrelay_driver_info);