1 /*
2 * Copyright (c) 2018 Diego Sueiro
3 * Copyright (c) 2022 Thomas Stranger
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <stdlib.h>
9
10 #include <zephyr/drivers/w1.h>
11 #include <zephyr/shell/shell.h>
12 #include <zephyr/kernel.h>
13
14 #define BUF_SIZE CONFIG_W1_SHELL_BUFFER_SIZE
15 static uint8_t msg_buf[BUF_SIZE];
16
17 #define W1DEV_X_NOT_FOUND "1-Wire device not found: \"%s\""
18
19 #define OPTION_HELP_RESET "-r Perform bus reset before executing cmd."
20
21 static const char *w1_settings_name[W1_SETINGS_TYPE_COUNT] = {
22 [W1_SETTING_SPEED] = "speed",
23 [W1_SETTING_STRONG_PULLUP] = "spu",
24 };
25
read_io_options(const struct shell * sh,int pos,char ** argv,bool * reset)26 static int read_io_options(const struct shell *sh, int pos, char **argv,
27 bool *reset)
28 {
29 char *arg = argv[pos];
30
31 if (arg[0] != '-') {
32 return pos;
33 }
34
35 for (arg = &arg[1]; *arg; arg++) {
36 switch (*arg) {
37 case 'r':
38 *reset = true;
39 break;
40 default:
41 shell_error(sh, "Unknown option %c", *arg);
42 return -EINVAL;
43 }
44 }
45
46 return ++pos;
47 }
48
49 /* 1-Wire reset bus <device> */
cmd_w1_reset_bus(const struct shell * sh,size_t argc,char ** argv)50 static int cmd_w1_reset_bus(const struct shell *sh, size_t argc, char **argv)
51 {
52 const struct device *dev;
53 int ret;
54
55 dev = device_get_binding(argv[1]);
56 if (!dev) {
57 shell_error(sh, W1DEV_X_NOT_FOUND, argv[1]);
58 return -EINVAL;
59 }
60
61 (void)w1_lock_bus(dev);
62 ret = w1_reset_bus(dev);
63 if (ret < 0) {
64 shell_error(sh, "Failed to reset bus [%d]", ret);
65 }
66
67 (void)w1_unlock_bus(dev);
68 return ret;
69 }
70
71 /* 1-Wire read_bit <device> */
cmd_w1_read_bit(const struct shell * sh,size_t argc,char ** argv)72 static int cmd_w1_read_bit(const struct shell *sh, size_t argc, char **argv)
73 {
74 const struct device *dev;
75 int ret;
76
77 dev = device_get_binding(argv[1]);
78 if (!dev) {
79 shell_error(sh, W1DEV_X_NOT_FOUND, argv[1]);
80 return -EINVAL;
81 }
82
83 (void)w1_lock_bus(dev);
84 ret = w1_read_bit(dev);
85 if (ret < 0) {
86 shell_error(sh, "Failed to read bit [%d]", ret);
87 } else {
88 shell_print(sh, "Output: 0b%x", ret);
89 }
90
91 (void)w1_unlock_bus(dev);
92 return ret;
93 }
94
95 /* 1-Wire read_byte <device> */
cmd_w1_read_byte(const struct shell * sh,size_t argc,char ** argv)96 static int cmd_w1_read_byte(const struct shell *sh, size_t argc, char **argv)
97 {
98 const struct device *dev;
99 int ret;
100
101 dev = device_get_binding(argv[1]);
102 if (!dev) {
103 shell_error(sh, W1DEV_X_NOT_FOUND, argv[1]);
104 return -EINVAL;
105 }
106
107 (void)w1_lock_bus(dev);
108 ret = w1_read_byte(dev);
109 if (ret < 0) {
110 shell_error(sh, "Failed to read byte [%d]", ret);
111 } else {
112 shell_print(sh, "Output: 0x%x", ret);
113 }
114
115 (void)w1_unlock_bus(dev);
116 return ret;
117 }
118
119 /* 1-Wire read_block <device> [num_bytes] */
cmd_w1_read_block(const struct shell * sh,size_t argc,char ** argv)120 static int cmd_w1_read_block(const struct shell *sh, size_t argc, char **argv)
121 {
122 const struct device *dev;
123 char *end_ptr;
124 size_t read_len;
125 int ret;
126
127 dev = device_get_binding(argv[1]);
128 if (!dev) {
129 shell_error(sh, W1DEV_X_NOT_FOUND, argv[1]);
130 return -EINVAL;
131 }
132
133 read_len = strtoul(argv[2], &end_ptr, 0);
134 if (*end_ptr != '\0') {
135 shell_error(sh, "num_bytes is not a number");
136 return -EINVAL;
137 }
138 if (read_len > BUF_SIZE) {
139 shell_error(sh, "num_bytes limited to: %u", BUF_SIZE);
140 return -EINVAL;
141 }
142
143 (void)w1_lock_bus(dev);
144 ret = w1_read_block(dev, msg_buf, read_len);
145 if (ret < 0) {
146 shell_error(sh, "Failed to read byte [%d]", ret);
147 goto out;
148 }
149
150 shell_fprintf(sh, SHELL_NORMAL, "Output:");
151 for (int i = 0; i < read_len; i++) {
152 shell_fprintf(sh, SHELL_NORMAL, " 0x%02x", msg_buf[i]);
153 }
154 shell_fprintf(sh, SHELL_NORMAL, "\n");
155
156 out:
157 (void)w1_unlock_bus(dev);
158 return ret;
159 }
160
161 /* 1-Wire write_bit <device> <bit_value> */
cmd_w1_write_bit(const struct shell * sh,size_t argc,char ** argv)162 static int cmd_w1_write_bit(const struct shell *sh, size_t argc, char **argv)
163 {
164 const struct device *dev;
165 unsigned long input = strtoul(argv[2], NULL, 0);
166 int ret;
167
168 dev = device_get_binding(argv[1]);
169 if (!dev) {
170 shell_error(sh, W1DEV_X_NOT_FOUND, argv[1]);
171 return -EINVAL;
172 }
173 if (input > 1UL) {
174 shell_error(sh, "input must not be > 0b1");
175 return -EINVAL;
176 }
177
178 (void)w1_lock_bus(dev);
179 ret = w1_write_byte(dev, (bool)input);
180 if (ret < 0) {
181 shell_error(sh, "Failed to write bit [%d]", ret);
182 }
183
184 (void)w1_unlock_bus(dev);
185 return ret;
186 }
187
188 /* 1-Wire write_byte <device> <byte_value> */
cmd_w1_write_byte(const struct shell * sh,size_t argc,char ** argv)189 static int cmd_w1_write_byte(const struct shell *sh, size_t argc, char **argv)
190 {
191 const struct device *dev;
192 unsigned long input;
193 int pos = 1;
194 bool reset = false;
195 int ret;
196
197 dev = device_get_binding(argv[pos]);
198 if (!dev) {
199 shell_error(sh, W1DEV_X_NOT_FOUND, argv[pos]);
200 return -EINVAL;
201 }
202 pos++;
203
204 pos = read_io_options(sh, pos, argv, &reset);
205 if (pos < 0) {
206 return -EINVAL;
207 }
208 if (argc <= pos) {
209 shell_error(sh, "Missing data to be written.");
210 return -EINVAL;
211 }
212
213 input = strtoul(argv[pos], NULL, 0);
214 if (input > 0xFFUL) {
215 shell_error(sh, "input must not be > 0xFF");
216 return -EINVAL;
217 }
218
219 (void)w1_lock_bus(dev);
220 if (reset) {
221 ret = w1_reset_bus(dev);
222 if (ret <= 0) {
223 shell_error(sh, "Failed to reset bus [%d]", ret);
224 goto out;
225 }
226 }
227
228 ret = w1_write_byte(dev, (uint8_t)input);
229 if (ret < 0) {
230 shell_error(sh, "Failed to write byte [%d]", ret);
231 }
232 out:
233 (void)w1_unlock_bus(dev);
234 return ret;
235 }
236
237 /* 1-Wire write_block <device> <byt1> [byte2, ...] */
cmd_w1_write_block(const struct shell * sh,size_t argc,char ** argv)238 static int cmd_w1_write_block(const struct shell *sh, size_t argc, char **argv)
239 {
240 const struct device *dev;
241 int i;
242 int pos = 1;
243 bool reset = false;
244 int ret;
245
246 dev = device_get_binding(argv[pos]);
247 if (!dev) {
248 shell_error(sh, W1DEV_X_NOT_FOUND, argv[1]);
249 return -EINVAL;
250 }
251 pos++;
252
253 pos = read_io_options(sh, pos, argv, &reset);
254 if (pos < 0) {
255 return -EINVAL;
256 }
257 if (argc <= pos) {
258 shell_error(sh, "Missing data to be written.");
259 return -EINVAL;
260 }
261 if ((argc - pos) > BUF_SIZE) {
262 shell_error(sh, "Too much data to be written.");
263 return -EINVAL;
264 }
265
266 (void)w1_lock_bus(dev);
267 i = 0;
268 do {
269 msg_buf[i] = (uint8_t)strtoul(argv[i + pos], NULL, 16);
270 i++;
271 } while ((i + pos) < argc);
272
273 if (reset) {
274 ret = w1_reset_bus(dev);
275 if (ret <= 0) {
276 shell_error(sh, "Failed to reset bus [%d]", ret);
277 goto out;
278 }
279 }
280
281 ret = w1_write_block(dev, msg_buf, i);
282 if (ret < 0) {
283 shell_error(sh, "Failed to write block [%d]", ret);
284 }
285 out:
286 (void)w1_unlock_bus(dev);
287 return ret;
288 }
289
290 /* 1-Wire config <device> <type> <value> */
cmd_w1_configure(const struct shell * sh,size_t argc,char ** argv)291 static int cmd_w1_configure(const struct shell *sh, size_t argc, char **argv)
292 {
293 const struct device *dev;
294 char *type_endptr;
295 char *type_name = argv[2];
296 int ret;
297 uint32_t type = strtoul(type_name, &type_endptr, 0);
298 uint32_t value = strtoul(argv[3], NULL, 0);
299
300 dev = device_get_binding(argv[1]);
301 if (!dev) {
302 shell_error(sh, W1DEV_X_NOT_FOUND, argv[1]);
303 return -EINVAL;
304 }
305
306 /* if type is not given as number, search it via the name */
307 if (*type_endptr != '\0') {
308 for (type = 0; type < ARRAY_SIZE(w1_settings_name); type++) {
309 if (strcmp(type_name, w1_settings_name[type]) == 0) {
310 break;
311 }
312 }
313
314 if (type == ARRAY_SIZE(w1_settings_name)) {
315 shell_error(sh, "Unknown config name (%s)", type_name);
316 return -ENOTSUP;
317 }
318 }
319
320 if (type > W1_SETINGS_TYPE_COUNT) {
321 shell_error(sh, "invalid type %u", type);
322 return -EINVAL;
323 }
324
325 (void)w1_lock_bus(dev);
326 ret = w1_configure(dev, type, value);
327 if (ret < 0) {
328 shell_error(sh, "Failed to configure [%d]", ret);
329 goto out;
330 }
331
332 shell_info(sh, "Applied config: %s = %u (0x%08x)",
333 w1_settings_name[type], value, value);
334
335 out:
336 (void)w1_unlock_bus(dev);
337 return ret;
338 }
339
search_callback(struct w1_rom rom,void * user_data)340 static void search_callback(struct w1_rom rom, void *user_data)
341 {
342 const struct shell *sh = (const struct shell *)user_data;
343
344 shell_print(sh, "ROM found: %016llx", w1_rom_to_uint64(&rom));
345 }
346
347 /* 1-Wire search <device> */
cmd_w1_search(const struct shell * sh,size_t argc,char ** argv)348 static int cmd_w1_search(const struct shell *sh, size_t argc, char **argv)
349 {
350 const struct device *dev;
351 int ret;
352
353 dev = device_get_binding(argv[1]);
354 if (!dev) {
355 shell_error(sh, W1DEV_X_NOT_FOUND, argv[1]);
356 return -EINVAL;
357 }
358
359 (void)w1_lock_bus(dev);
360 ret = w1_search_rom(dev, search_callback, (void *)sh);
361 if (ret < 0) {
362 shell_error(sh, "Failed to initiate search [%d]", ret);
363 } else {
364 shell_print(sh, "Found %d device(s)", ret);
365 }
366
367 (void)w1_unlock_bus(dev);
368 return ret;
369 }
370
371 SHELL_STATIC_SUBCMD_SET_CREATE(sub_w1,
372 SHELL_CMD_ARG(reset, NULL,
373 "Reset 1-Wire bus.\n"
374 "Usage: <device>",
375 cmd_w1_reset_bus, 2, 0),
376 SHELL_CMD_ARG(read_bit, NULL,
377 "Read 1-Wire bit.\n"
378 "Usage: <device>",
379 cmd_w1_read_bit, 2, 0),
380 SHELL_CMD_ARG(read_byte, NULL,
381 "Read 1-Wire byte.\n"
382 "Usage: <device>",
383 cmd_w1_read_byte, 2, 0),
384 SHELL_CMD_ARG(read_block, NULL,
385 "Read 1-Wire block.\n"
386 "Usage: <device> <num_bytes>",
387 cmd_w1_read_block, 3, 0),
388 SHELL_CMD_ARG(write_bit, NULL,
389 "Write 1-Wire bit.\n"
390 "Usage: <device> <bit>",
391 cmd_w1_write_bit, 3, 0),
392 SHELL_CMD_ARG(write_byte, NULL,
393 "Write 1-Wire byte.\n"
394 "Usage: <device> [-r] <byte>\n"
395 OPTION_HELP_RESET,
396 cmd_w1_write_byte, 3, 1),
397 SHELL_CMD_ARG(write_block, NULL,
398 "Write 1-Wire block.\n"
399 "Usage: <device> [-r] <byte1> [<byte2>, ...]\n"
400 OPTION_HELP_RESET,
401 cmd_w1_write_block, 3, BUF_SIZE),
402 SHELL_CMD_ARG(config, NULL,
403 "Configure 1-Wire host.\n"
404 "Usage: <device> <type> <value>\n"
405 "<type> is either a name or an id.",
406 cmd_w1_configure, 4, 0),
407 SHELL_CMD_ARG(search, NULL,
408 "1-Wire devices.\n"
409 "Usage: <device>",
410 cmd_w1_search, 2, 0),
411 SHELL_SUBCMD_SET_END /* Array terminated. */
412 );
413
414 SHELL_CMD_ARG_REGISTER(w1, &sub_w1, "1-Wire commands", NULL, 2, 0);
415