xref: /netbsd-src/usr.bin/scmdctl/scmdctl.c (revision 9fc190edc0fd2e662c3f996959b35e47bf57ed5e)
1*9fc190edSrillig /*	$NetBSD: scmdctl.c,v 1.3 2024/12/01 10:32:48 rillig Exp $	*/
2bf53d441Sbrad 
3bf53d441Sbrad /*
4bf53d441Sbrad  * Copyright (c) 2021 Brad Spencer <brad@anduin.eldar.org>
5bf53d441Sbrad  *
6bf53d441Sbrad  * Permission to use, copy, modify, and distribute this software for any
7bf53d441Sbrad  * purpose with or without fee is hereby granted, provided that the above
8bf53d441Sbrad  * copyright notice and this permission notice appear in all copies.
9bf53d441Sbrad  *
10bf53d441Sbrad  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11bf53d441Sbrad  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12bf53d441Sbrad  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13bf53d441Sbrad  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14bf53d441Sbrad  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15bf53d441Sbrad  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16bf53d441Sbrad  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17bf53d441Sbrad  */
18bf53d441Sbrad 
19bf53d441Sbrad #include <sys/cdefs.h>
20bf53d441Sbrad #ifdef __RCSID
21*9fc190edSrillig __RCSID("$NetBSD: scmdctl.c,v 1.3 2024/12/01 10:32:48 rillig Exp $");
22bf53d441Sbrad #endif
23bf53d441Sbrad 
24bf53d441Sbrad /* Main userland program that knows how to talk to the Sparkfun
25bf53d441Sbrad  * Serial Controlled Motor Driver (SCMD).  The device provides
26bf53d441Sbrad  * 127 registers that are used to interact with the motors.
27bf53d441Sbrad  * This program provides some convience commands to work with most
28bf53d441Sbrad  * of the abilities of the SCMD device.
29bf53d441Sbrad  *
30bf53d441Sbrad  * This knows how to talk to a SCMD device via:
31bf53d441Sbrad  *
32bf53d441Sbrad  * 1) The uart tty interface that is provided by the SCMD device
33bf53d441Sbrad  * 2) Userland SPI talking to something like /dev/spi0 directly
34bf53d441Sbrad  *    In most ways this acts like talking to the tty uart.
35bf53d441Sbrad  * 3) Using the scmd(4) i2c or spi driver.  This is, by far, the
36bf53d441Sbrad  *    fastest way to access the driver.  The other methods have
37bf53d441Sbrad  *    increased latency.
38bf53d441Sbrad  */
39bf53d441Sbrad 
40bf53d441Sbrad #include <inttypes.h>
41bf53d441Sbrad #include <stdbool.h>
42bf53d441Sbrad #include <stdio.h>
43bf53d441Sbrad #include <stdlib.h>
44bf53d441Sbrad #include <unistd.h>
45bf53d441Sbrad #include <err.h>
46bf53d441Sbrad #include <fcntl.h>
47bf53d441Sbrad #include <string.h>
48bf53d441Sbrad #include <limits.h>
49bf53d441Sbrad #include <termios.h>
50bf53d441Sbrad #include <sys/ioctl.h>
51bf53d441Sbrad #include <sys/time.h>
52bf53d441Sbrad #include <dev/spi/spi_io.h>
53bf53d441Sbrad 
54bf53d441Sbrad #include <dev/ic/scmdreg.h>
55bf53d441Sbrad 
56bf53d441Sbrad #define EXTERN extern
57bf53d441Sbrad #include "common.h"
58bf53d441Sbrad #include "scmdctl.h"
59bf53d441Sbrad #include "uart.h"
60bf53d441Sbrad #include "i2cspi.h"
61bf53d441Sbrad #include "printscmd.h"
62bf53d441Sbrad #include "responses.h"
63bf53d441Sbrad #include "scmdctlconst.h"
64bf53d441Sbrad 
65bf53d441Sbrad int	ul_spisetup(int, int);
66bf53d441Sbrad int	ttysetup(int, speed_t);
67bf53d441Sbrad int	valid_cmd(const struct scmdcmd[], long unsigned int, char *);
68bf53d441Sbrad 
69bf53d441Sbrad 
70bf53d441Sbrad static void
71bf53d441Sbrad usage(void)
72bf53d441Sbrad {
73bf53d441Sbrad 	const char *p = getprogname();
74bf53d441Sbrad 
75bf53d441Sbrad 	fprintf(stderr, "Usage: %s [-dlh] [-b baud rate] [-s SPI slave addr] device cmd args\n\n",
76bf53d441Sbrad 	    p);
77bf53d441Sbrad 
78bf53d441Sbrad 	for(long unsigned int i = 0;i < __arraycount(scmdcmds);i++) {
79bf53d441Sbrad 		fprintf(stderr,"%s [-dlh] [-b baud rate] [-s SPI slave addr] device %s %s\n",
80bf53d441Sbrad 		    p,scmdcmds[i].cmd,scmdcmds[i].helpargs);
81bf53d441Sbrad 	}
82bf53d441Sbrad }
83bf53d441Sbrad 
84bf53d441Sbrad int
85bf53d441Sbrad valid_cmd(const struct scmdcmd c[], long unsigned int csize, char *cmdtocheck)
86bf53d441Sbrad {
87bf53d441Sbrad 	int r = -1;
88bf53d441Sbrad 
89bf53d441Sbrad 	for(long unsigned int i = 0;i < csize;i++) {
90bf53d441Sbrad 		if (strncmp(cmdtocheck,c[i].cmd,16) == 0) {
91bf53d441Sbrad 			r = i;
92bf53d441Sbrad 			break;
93bf53d441Sbrad 		}
94bf53d441Sbrad 	}
95bf53d441Sbrad 
96bf53d441Sbrad 	return r;
97bf53d441Sbrad }
98bf53d441Sbrad 
99bf53d441Sbrad /* This is expected to fail if the device is not a classic tty */
100bf53d441Sbrad int
101bf53d441Sbrad ttysetup(int fd, speed_t spd)
102bf53d441Sbrad {
103bf53d441Sbrad         struct termios  cntrl;
104bf53d441Sbrad 
105bf53d441Sbrad         (void)tcgetattr(fd, &cntrl);
106bf53d441Sbrad         (void)cfsetospeed(&cntrl, spd);
107bf53d441Sbrad         (void)cfsetispeed(&cntrl, spd);
108bf53d441Sbrad         cntrl.c_cflag &= ~(CSIZE|PARENB);
109bf53d441Sbrad         cntrl.c_cflag |= CS8;
110bf53d441Sbrad 	cntrl.c_cflag |= CLOCAL;
111bf53d441Sbrad         cntrl.c_iflag &= ~(ISTRIP|ICRNL);
112bf53d441Sbrad         cntrl.c_oflag &= ~OPOST;
113bf53d441Sbrad         cntrl.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
114bf53d441Sbrad         cntrl.c_cc[VMIN] = 1;
115bf53d441Sbrad         cntrl.c_cc[VTIME] = 0;
116bf53d441Sbrad 	cntrl.c_iflag &= ~(IXOFF|IXON);
117bf53d441Sbrad         return tcsetattr(fd, TCSAFLUSH, &cntrl);
118bf53d441Sbrad }
119bf53d441Sbrad 
120bf53d441Sbrad /* This is for userland SPI and is expected to fail if the device is
121bf53d441Sbrad  * not a /dev/spiN
122bf53d441Sbrad  */
123bf53d441Sbrad int
124bf53d441Sbrad ul_spisetup(int fd, int slave_addr)
125bf53d441Sbrad {
126bf53d441Sbrad 	struct timespec ts;
127bf53d441Sbrad 	struct spi_ioctl_configure spi_c;
128bf53d441Sbrad 	int e;
129bf53d441Sbrad 
130bf53d441Sbrad 	spi_c.sic_addr = slave_addr;
131bf53d441Sbrad #define SPI_MODE_0 0
132bf53d441Sbrad #define SPI_MODE_1 1
133bf53d441Sbrad #define SPI_MODE_2 2
134bf53d441Sbrad #define SPI_MODE_3 3
135bf53d441Sbrad 	spi_c.sic_mode = SPI_MODE_0;
136bf53d441Sbrad 	spi_c.sic_speed = 1000000;
137bf53d441Sbrad 
138bf53d441Sbrad 	e = ioctl(fd,SPI_IOCTL_CONFIGURE,&spi_c);
139bf53d441Sbrad 	if (e != -1) {
140bf53d441Sbrad 		ts.tv_sec = 0;
141bf53d441Sbrad 		ts.tv_nsec = 50;
142bf53d441Sbrad 		nanosleep(&ts,NULL);
143bf53d441Sbrad 	}
144bf53d441Sbrad 
145bf53d441Sbrad 	return e;
146bf53d441Sbrad }
147bf53d441Sbrad 
148bf53d441Sbrad int
149bf53d441Sbrad main(int argc, char *argv[])
150bf53d441Sbrad {
151bf53d441Sbrad 	int c;
152bf53d441Sbrad 	bool debug = false;
153bf53d441Sbrad 	int fd = -1, error, ttyerror = 0, ul_spierror = 0, valid, validsub = -1;
154bf53d441Sbrad 	long baud_rate = 9600;
155bf53d441Sbrad 	long slave_a = 0;
156bf53d441Sbrad 	bool dev_is_uart = true;
157bf53d441Sbrad 	int uart_s = UART_IS_PURE_UART;
158bf53d441Sbrad 	struct scmd_identify_response ir;
159bf53d441Sbrad 	struct scmd_diag_response diag;
160bf53d441Sbrad 	struct scmd_motor_response motors;
161bf53d441Sbrad 	long module;
162bf53d441Sbrad 	char motor;
163bf53d441Sbrad 	int8_t reg_value;
164bf53d441Sbrad 	uint8_t reg = 0, reg_e = 0, ur, ebus_s, lock_state;
165bf53d441Sbrad 	uint8_t register_shadow[SCMD_REG_SIZE];
166bf53d441Sbrad 	int lock_type = -1;
167bf53d441Sbrad 	bool list_names = false;
168bf53d441Sbrad 	struct function_block func_block;
169bf53d441Sbrad 
170bf53d441Sbrad 	while ((c = getopt(argc, argv, "db:s:lh")) != -1 ) {
171bf53d441Sbrad 		switch (c) {
172bf53d441Sbrad 		case 'd':
173bf53d441Sbrad 			debug = true;
174bf53d441Sbrad 			break;
175bf53d441Sbrad 		case 'b':
176bf53d441Sbrad 			baud_rate = (long)strtoi(optarg, NULL, 0, 1, LONG_MAX, &error);
177bf53d441Sbrad 			if (error)
178bf53d441Sbrad 				warnc(error, "Conversion of `%s' to a baud rate "
179bf53d441Sbrad 				    "failed, using %ld", optarg, baud_rate);
180bf53d441Sbrad 			break;
181bf53d441Sbrad 		case 's':
182bf53d441Sbrad 			slave_a = (long)strtoi(optarg, NULL, 0, 0, LONG_MAX, &error);
183bf53d441Sbrad 			if (error)
184bf53d441Sbrad 				warnc(error, "Conversion of `%s' to a SPI slave address "
185bf53d441Sbrad 				    "failed, using %ld", optarg, slave_a);
186bf53d441Sbrad 			break;
187bf53d441Sbrad 		case 'l':
188bf53d441Sbrad 			list_names = true;
189bf53d441Sbrad 			break;
190bf53d441Sbrad 		case 'h':
191bf53d441Sbrad 		default:
192bf53d441Sbrad 			usage();
193bf53d441Sbrad 			exit(0);
194bf53d441Sbrad 		}
195bf53d441Sbrad 	}
196bf53d441Sbrad 
197bf53d441Sbrad 	argc -= optind;
198bf53d441Sbrad 	argv += optind;
199bf53d441Sbrad 
200bf53d441Sbrad 	if (debug) {
201bf53d441Sbrad 		fprintf(stderr,"ARGC: %d\n", argc);
202bf53d441Sbrad 		fprintf(stderr,"ARGV[0]: %s ; ARGV[1]: %s ; ARGV[2]: %s ; ARGV[3]: %s; ARGV[4]: %s; ARGV[5]: %s\n",
203bf53d441Sbrad 		    argv[0],argv[1],argv[2],argv[3],argv[4],argv[5]);
204bf53d441Sbrad 	}
205bf53d441Sbrad 
206bf53d441Sbrad 	if (list_names) {
207bf53d441Sbrad 		for(c = 0x00; c < SCMD_REG_SIZE;c++)
208bf53d441Sbrad 			printf("Register %d (0x%02X): %s\n",c,c,scmdregisternames[c]);
209bf53d441Sbrad 		exit(0);
210bf53d441Sbrad 	}
211bf53d441Sbrad 
212bf53d441Sbrad 	if (argc <= 1) {
213bf53d441Sbrad 		usage();
214bf53d441Sbrad 		exit(0);
215bf53d441Sbrad 	}
216bf53d441Sbrad 
217bf53d441Sbrad 	fd = open(argv[0], O_RDWR, 0);
218bf53d441Sbrad 	if (fd == -1) {
219bf53d441Sbrad 		err(EXIT_FAILURE, "open %s", argv[0]);
220bf53d441Sbrad 	}
221bf53d441Sbrad 
222bf53d441Sbrad 	/* Figure out what the device is.  First try uart tty,
223bf53d441Sbrad 	 * then SPI userland and the if those two fail, assume
224bf53d441Sbrad 	 * scmd(4).
225bf53d441Sbrad 	 */
226bf53d441Sbrad 	ttyerror = ttysetup(fd,(speed_t)baud_rate);
227bf53d441Sbrad 
228bf53d441Sbrad 	if (ttyerror) {
229bf53d441Sbrad 		ul_spierror = ul_spisetup(fd, slave_a);
230bf53d441Sbrad 		if (ul_spierror) {
231bf53d441Sbrad 			dev_is_uart = false;
232bf53d441Sbrad 		} else {
233bf53d441Sbrad 			uart_s = UART_IS_SPI_USERLAND;
234bf53d441Sbrad 		}
235bf53d441Sbrad 	}
236bf53d441Sbrad 	uart_set_subtype(uart_s, slave_a);
237bf53d441Sbrad 
238bf53d441Sbrad 	if (debug) {
239bf53d441Sbrad 		fprintf(stderr, "ttysetup: error return %d\n", ttyerror);
240bf53d441Sbrad 		fprintf(stderr, "ul_spisetup: error return %d\n", ul_spierror);
241bf53d441Sbrad 	}
242bf53d441Sbrad 
243bf53d441Sbrad 	/* A UART here is either a tty uart or a SPI userland device.
244bf53d441Sbrad 	 * They mostly end up working the same.
245bf53d441Sbrad 	 */
246bf53d441Sbrad 	if (dev_is_uart) {
247bf53d441Sbrad 		func_block.func_clear = &uart_clear;
248bf53d441Sbrad 		func_block.func_phy_read = &uart_read_register;
249bf53d441Sbrad 		func_block.func_phy_write = &uart_write_register;
250bf53d441Sbrad 	} else {
251bf53d441Sbrad 		func_block.func_clear = &i2cspi_clear;
252bf53d441Sbrad 		func_block.func_phy_read = &i2cspi_read_register;
253bf53d441Sbrad 		func_block.func_phy_write = &i2cspi_write_register;
254bf53d441Sbrad 	}
255bf53d441Sbrad 
256bf53d441Sbrad 	valid = valid_cmd(scmdcmds,__arraycount(scmdcmds),argv[1]);
257bf53d441Sbrad 
258bf53d441Sbrad 	if (valid != -1) {
259bf53d441Sbrad 		switch (scmdcmds[valid].id) {
260bf53d441Sbrad 		case SCMD_IDENTIFY:
261bf53d441Sbrad 			module = 0;
262bf53d441Sbrad 			if (argc == 3) {
263bf53d441Sbrad 				module = (long)strtoi(argv[2], NULL, 10, 0, 16, &error);
264bf53d441Sbrad 				if (error)
265bf53d441Sbrad 					warnc(error, "Conversion of '%s' module failed,"
266bf53d441Sbrad 					    " using %ld", argv[2], module);
267bf53d441Sbrad 			}
268bf53d441Sbrad 			error = common_identify(&func_block, fd, debug, module, &ir);
269bf53d441Sbrad 			break;
270bf53d441Sbrad 		case SCMD_DIAG:
271bf53d441Sbrad 			module = 0;
272bf53d441Sbrad 			if (argc == 3) {
273bf53d441Sbrad 				module = (long)strtoi(argv[2], NULL, 10, 0, 16, &error);
274bf53d441Sbrad 				if (error)
275bf53d441Sbrad 					warnc(error, "Conversion of '%s' module failed,"
276bf53d441Sbrad 					    " using %ld", argv[2], module);
277bf53d441Sbrad 			}
278bf53d441Sbrad 			error = common_diag(&func_block, fd, debug, module, &diag);
279bf53d441Sbrad 			break;
280bf53d441Sbrad 		case SCMD_MOTOR:
281bf53d441Sbrad 			if (argc >= 3) {
282bf53d441Sbrad 				validsub = valid_cmd(motorsubcmds,__arraycount(motorsubcmds),argv[2]);
283bf53d441Sbrad 				if (validsub != -1) {
284bf53d441Sbrad 					switch (motorsubcmds[validsub].id) {
285bf53d441Sbrad 					case SCMD_SUBMOTORGET:
286bf53d441Sbrad 						module = SCMD_ANY_MODULE;
287bf53d441Sbrad 						if (argc == 4) {
288bf53d441Sbrad 							module = (long)strtoi(argv[3], NULL, 10, 0, 16, &error);
289bf53d441Sbrad 							if (error)
290bf53d441Sbrad 								warnc(error, "Conversion of '%s' module failed,"
291bf53d441Sbrad 								    " using %ld", argv[3], module);
292bf53d441Sbrad 						}
293bf53d441Sbrad 						error = common_get_motor(&func_block, fd, debug, (int)module, &motors);
294bf53d441Sbrad 						break;
295bf53d441Sbrad 					case SCMD_SUBMOTORSET:
296bf53d441Sbrad 						if (argc == 6) {
297bf53d441Sbrad 							module = (long)strtoi(argv[3], NULL, 10, 0, 16, &error);
298bf53d441Sbrad 							if (error)
299bf53d441Sbrad 								warnc(error, "Conversion of '%s' module failed,"
300bf53d441Sbrad 								    " using %ld", argv[3], module);
301bf53d441Sbrad 							motor = argv[4][0];
302bf53d441Sbrad 							reg_value = (int8_t)strtoi(argv[5], NULL, 0, -127, 127, &error);
303bf53d441Sbrad 							if (error)
304bf53d441Sbrad 								err(EXIT_FAILURE,"Bad conversion for set motor for reg_value: %s", argv[5]);
305bf53d441Sbrad 						} else {
306bf53d441Sbrad 							fprintf(stderr,"Missing arguments to set motor command\n\n");
307bf53d441Sbrad 							usage();
308bf53d441Sbrad 							exit(1);
309bf53d441Sbrad 						}
310bf53d441Sbrad 						error = common_set_motor(&func_block, fd, debug, (int)module, motor, reg_value);
311bf53d441Sbrad 						break;
312bf53d441Sbrad 					case SCMD_SUBMOTORINVERT:
313bf53d441Sbrad 						if (argc == 5) {
314bf53d441Sbrad 							module = (long)strtoi(argv[3], NULL, 10, 0, 16, &error);
315bf53d441Sbrad 							if (error)
316bf53d441Sbrad 								warnc(error, "Conversion of '%s' module failed,"
317bf53d441Sbrad 								    " using %ld", argv[3], module);
318bf53d441Sbrad 							motor = argv[4][0];
319bf53d441Sbrad 						} else {
320bf53d441Sbrad 							fprintf(stderr,"Missing arguments to invert motor command\n\n");
321bf53d441Sbrad 							usage();
322bf53d441Sbrad 							exit(1);
323bf53d441Sbrad 						}
324bf53d441Sbrad 						error = common_invert_motor(&func_block, fd, debug, (int)module, motor);
325bf53d441Sbrad 						break;
326bf53d441Sbrad 					case SCMD_SUBMOTORBRIDGE:
327bf53d441Sbrad 						if (argc == 4) {
328bf53d441Sbrad 							module = (long)strtoi(argv[3], NULL, 10, 0, 16, &error);
329bf53d441Sbrad 							if (error)
330bf53d441Sbrad 								warnc(error, "Conversion of '%s' module failed,"
331bf53d441Sbrad 								    " using %ld", argv[3], module);
332bf53d441Sbrad 						} else {
333bf53d441Sbrad 							fprintf(stderr,"Missing arguments to bridge motor command\n\n");
334bf53d441Sbrad 							usage();
335bf53d441Sbrad 							exit(1);
336bf53d441Sbrad 						}
337bf53d441Sbrad 						error = common_bridge_motor(&func_block, fd, debug, (int)module);
338bf53d441Sbrad 						break;
339bf53d441Sbrad 					case SCMD_SUBMOTORDISABLE:
340bf53d441Sbrad 						error = common_enable_disable(&func_block, fd, debug, SCMD_DISABLE);
341bf53d441Sbrad 						break;
342bf53d441Sbrad 					case SCMD_SUBMOTORENABLE:
343bf53d441Sbrad 						error = common_enable_disable(&func_block, fd, debug, SCMD_ENABLE);
344bf53d441Sbrad 						break;
345bf53d441Sbrad 					default:
346bf53d441Sbrad 						fprintf(stderr,"Unhandled subcommand to motor: %s %d\n\n", argv[2], validsub);
347bf53d441Sbrad 						usage();
348bf53d441Sbrad 						exit(1);
349bf53d441Sbrad 					}
350bf53d441Sbrad 				} else {
351bf53d441Sbrad 					fprintf(stderr,"Unknown subcommand to motor: %s\n\n", argv[2]);
352bf53d441Sbrad 					usage();
353bf53d441Sbrad 					exit(1);
354bf53d441Sbrad 				}
355bf53d441Sbrad 			} else {
356bf53d441Sbrad 				fprintf(stderr,"Missing arguments to motor command\n\n");
357bf53d441Sbrad 				usage();
358bf53d441Sbrad 				exit(1);
359bf53d441Sbrad 			}
360bf53d441Sbrad 			break;
361bf53d441Sbrad 		case SCMD_READ:
362bf53d441Sbrad 			memset(register_shadow,SCMD_HOLE_VALUE + 1,SCMD_REG_SIZE);
363bf53d441Sbrad 			if (argc >= 4) {
364bf53d441Sbrad 				module = (long)strtoi(argv[2], NULL, 10, 0, 16, &error);
365bf53d441Sbrad 				if (error)
366bf53d441Sbrad 					warnc(error, "Conversion of '%s' module failed,"
367bf53d441Sbrad 					    " using %ld", argv[2], module);
368bf53d441Sbrad 				reg = (uint8_t)strtoi(argv[3], NULL, 0, 0, 0x7e, &error);
369bf53d441Sbrad 				if (error) {
370bf53d441Sbrad 					for(c = 0x00; c < SCMD_REG_SIZE;c++)
371bf53d441Sbrad 						if (strncmp(argv[3],scmdregisternames[c],15) == 0)
372bf53d441Sbrad 							break;
373bf53d441Sbrad 					if (c == SCMD_REG_SIZE) {
374bf53d441Sbrad 						fprintf(stderr,"Bad conversion for read register start: %s\n", argv[3]);
375bf53d441Sbrad 						exit(1);
376bf53d441Sbrad 					}
377bf53d441Sbrad 					reg = c;
378bf53d441Sbrad 				}
379bf53d441Sbrad 				reg_e = reg;
380bf53d441Sbrad 				if (argc == 5) {
381bf53d441Sbrad 					reg_e = (uint8_t)strtoi(argv[4], NULL, 0, 0, 0x7e, &error);
382bf53d441Sbrad 					if (error) {
383bf53d441Sbrad 						for(c = 0x00; c < SCMD_REG_SIZE;c++)
384bf53d441Sbrad 							if (strncmp(argv[4],scmdregisternames[c],15) == 0)
385bf53d441Sbrad 								break;
386bf53d441Sbrad 						if (c == SCMD_REG_SIZE) {
387bf53d441Sbrad 							fprintf(stderr,"Bad conversion for read register end: %s\n", argv[4]);
388bf53d441Sbrad 							exit(1);
389bf53d441Sbrad 						}
390bf53d441Sbrad 						reg_e = c;
391bf53d441Sbrad 					}
392bf53d441Sbrad 				}
393bf53d441Sbrad 				if (reg_e < reg) {
394bf53d441Sbrad 					fprintf(stderr,"Register end can not be less than register start: %d %d\n\n", reg, reg_e);
395bf53d441Sbrad 					usage();
396bf53d441Sbrad 					exit(1);
397bf53d441Sbrad 				}
398bf53d441Sbrad 				if (dev_is_uart) {
399bf53d441Sbrad 					error = uart_read_register(fd,debug,module,reg,reg_e,&register_shadow[reg]);
400bf53d441Sbrad 				} else {
401bf53d441Sbrad 					error = i2cspi_read_register(fd,debug,module,reg,reg_e,&register_shadow[reg]);
402bf53d441Sbrad 				}
403bf53d441Sbrad 			} else {
404bf53d441Sbrad 				fprintf(stderr,"Missing arguments to read_register command\n\n");
405bf53d441Sbrad 				usage();
406bf53d441Sbrad 				exit(1);
407bf53d441Sbrad 			}
408bf53d441Sbrad 			break;
409bf53d441Sbrad 		case SCMD_WRITE:
410bf53d441Sbrad 			if (argc == 5) {
411bf53d441Sbrad 				module = (long)strtoi(argv[2], NULL, 10, 0, 16, &error);
412bf53d441Sbrad 				if (error)
413bf53d441Sbrad 					warnc(error, "Conversion of '%s' module failed,"
414bf53d441Sbrad 					    " using %ld", argv[2], module);
415bf53d441Sbrad 				reg = (uint8_t)strtoi(argv[3], NULL, 0, 0, 0x7e, &error);
416bf53d441Sbrad 				if (error) {
417bf53d441Sbrad 					for(c = 0x00; c < SCMD_REG_SIZE;c++)
418bf53d441Sbrad 						if (strncmp(argv[3],scmdregisternames[c],15) == 0)
419bf53d441Sbrad 							break;
420bf53d441Sbrad 					if (c == SCMD_REG_SIZE) {
421bf53d441Sbrad 						fprintf(stderr,"Bad conversion for write register start: %s\n", argv[3]);
422bf53d441Sbrad 						exit(1);
423bf53d441Sbrad 					}
424bf53d441Sbrad 					reg = c;
425bf53d441Sbrad 				}
426bf53d441Sbrad 				reg_value = (int8_t)strtoi(argv[4], NULL, 0, 0, 0xff, &error);
427bf53d441Sbrad 				if (error)
428bf53d441Sbrad 					err(EXIT_FAILURE,"Bad conversion for write register for reg_value: %s", argv[4]);
429bf53d441Sbrad 				if (dev_is_uart) {
430bf53d441Sbrad 					error = uart_write_register(fd,debug,module,reg,reg_value);
431bf53d441Sbrad 				} else {
432bf53d441Sbrad 					error = i2cspi_write_register(fd,debug,module,reg,reg_value);
433bf53d441Sbrad 				}
434bf53d441Sbrad 			} else {
435bf53d441Sbrad 				fprintf(stderr,"Missing arguments to write_register command\n\n");
436bf53d441Sbrad 				usage();
437bf53d441Sbrad 				exit(1);
438bf53d441Sbrad 			}
439bf53d441Sbrad 			break;
440bf53d441Sbrad 		case SCMD_RESTART:
441bf53d441Sbrad 		case SCMD_ENUMERATE:
442bf53d441Sbrad 			error = common_control_1(&func_block, fd, debug, scmdcmds[valid].id);
443bf53d441Sbrad 			break;
444bf53d441Sbrad 		case SCMD_UPDATERATE:
445bf53d441Sbrad 			if (argc >= 3) {
446bf53d441Sbrad 				validsub = valid_cmd(updateratesubcmds,__arraycount(updateratesubcmds),argv[2]);
447bf53d441Sbrad 				if (validsub != -1) {
448bf53d441Sbrad 					switch (updateratesubcmds[validsub].id) {
449bf53d441Sbrad 					case SCMD_SUBURGET:
450bf53d441Sbrad 						error = common_get_update_rate(&func_block, fd, debug, &ur);
451bf53d441Sbrad 						break;
452bf53d441Sbrad 					case SCMD_SUBURSET:
453bf53d441Sbrad 						if (argc == 4) {
454bf53d441Sbrad 							ur = (uint8_t)strtoi(argv[3], NULL, 0, 0, 0xff, &error);
455bf53d441Sbrad 							if (error)
456bf53d441Sbrad 								err(EXIT_FAILURE,"Bad conversion for update_rate: %s", argv[3]);
457bf53d441Sbrad 							error = common_set_update_rate(&func_block, fd, debug, ur);
458bf53d441Sbrad 						} else {
459bf53d441Sbrad 							fprintf(stderr,"Missing arguments to set update_rate command\n\n");
460bf53d441Sbrad 							usage();
461bf53d441Sbrad 							exit(1);
462bf53d441Sbrad 						}
463bf53d441Sbrad 						break;
464bf53d441Sbrad 					case SCMD_SUBURFORCE:
465bf53d441Sbrad 						error = common_force_update(&func_block, fd, debug);
466bf53d441Sbrad 						break;
467bf53d441Sbrad 					default:
468bf53d441Sbrad 						fprintf(stderr,"Unhandled subcommand to updaterate: %s %d\n\n", argv[2], validsub);
469bf53d441Sbrad 						usage();
470bf53d441Sbrad 						exit(1);
471bf53d441Sbrad 					}
472bf53d441Sbrad 				} else {
473bf53d441Sbrad 					fprintf(stderr,"Unknown subcommand to updaterate: %s\n\n", argv[2]);
474bf53d441Sbrad 					usage();
475bf53d441Sbrad 					exit(1);
476bf53d441Sbrad 				}
477bf53d441Sbrad 			} else {
478bf53d441Sbrad 				fprintf(stderr,"Missing arguments to update_rate command\n\n");
479bf53d441Sbrad 				usage();
480bf53d441Sbrad 				exit(1);
481bf53d441Sbrad 			}
482bf53d441Sbrad 			break;
483bf53d441Sbrad 		case SCMD_EBUS:
484bf53d441Sbrad 			if (argc >= 3) {
485bf53d441Sbrad 				validsub = valid_cmd(ebussubcmds,__arraycount(ebussubcmds),argv[2]);
486bf53d441Sbrad 				if (validsub != -1) {
487bf53d441Sbrad 					switch (ebussubcmds[validsub].id) {
488bf53d441Sbrad 					case SCMD_SUBEBUSGET:
489bf53d441Sbrad 						error = common_get_ebus_speed(&func_block, fd, debug, &ebus_s);
490bf53d441Sbrad 						break;
491bf53d441Sbrad 					case SCMD_SUBEBUSSET:
492bf53d441Sbrad 						if (argc == 4) {
493bf53d441Sbrad 							for(ebus_s = 0; ebus_s < __arraycount(ebus_speeds);ebus_s++)
494bf53d441Sbrad 								if (strncmp(argv[3],ebus_speeds[ebus_s],8) == 0)
495bf53d441Sbrad 									break;
496bf53d441Sbrad 							if (ebus_s == __arraycount(ebus_speeds)) {
497bf53d441Sbrad 								fprintf(stderr,"Bad conversion for set expansion bus speed: %s\n", argv[3]);
498bf53d441Sbrad 								exit(1);
499bf53d441Sbrad 							}
500bf53d441Sbrad 							error = common_set_ebus_speed(&func_block, fd, debug, ebus_s);
501bf53d441Sbrad 						} else {
502bf53d441Sbrad 							fprintf(stderr,"Missing arguments to set expansion_bus command\n\n");
503bf53d441Sbrad 							usage();
504bf53d441Sbrad 							exit(1);
505bf53d441Sbrad 						}
506bf53d441Sbrad 						break;
507bf53d441Sbrad 					default:
508bf53d441Sbrad 						fprintf(stderr,"Unhandled subcommand to expansion_bus: %s %d\n\n", argv[2], validsub);
509bf53d441Sbrad 						usage();
510bf53d441Sbrad 						exit(1);
511bf53d441Sbrad 					}
512bf53d441Sbrad 				} else {
513bf53d441Sbrad 					fprintf(stderr,"Unknown subcommand to expansion_bus: %s\n\n", argv[2]);
514bf53d441Sbrad 					usage();
515bf53d441Sbrad 					exit(1);
516bf53d441Sbrad 				}
517bf53d441Sbrad 			} else {
518bf53d441Sbrad 				fprintf(stderr,"Missing arguments to expansion_bus_speed command\n\n");
519bf53d441Sbrad 				usage();
520bf53d441Sbrad 				exit(1);
521bf53d441Sbrad 			}
522bf53d441Sbrad 			break;
523bf53d441Sbrad 		case SCMD_LOCK:
524bf53d441Sbrad 			if (argc == 4) {
525bf53d441Sbrad 				validsub = valid_cmd(locksubcmds,__arraycount(locksubcmds),argv[2]);
526bf53d441Sbrad 				if (validsub != -1) {
527bf53d441Sbrad 					lock_type = valid_cmd(lockcmdtypes,__arraycount(lockcmdtypes),argv[3]);
528bf53d441Sbrad 					if (lock_type == -1) {
529bf53d441Sbrad 						fprintf(stderr,"Unknown lock type: %s\n\n", argv[3]);
530bf53d441Sbrad 						usage();
531bf53d441Sbrad 						exit(1);
532bf53d441Sbrad 					}
533bf53d441Sbrad 					lock_type = lockcmdtypes[lock_type].id;
534bf53d441Sbrad 
535bf53d441Sbrad 					if (debug)
536bf53d441Sbrad 						fprintf(stderr,"Lock type in lock command: %d\n",lock_type);
537bf53d441Sbrad 
538bf53d441Sbrad 					switch (locksubcmds[validsub].id) {
539bf53d441Sbrad 					case SCMD_SUBLOCKGET:
540bf53d441Sbrad 						error = common_get_lock_state(&func_block, fd, debug, lock_type, &lock_state);
541bf53d441Sbrad 						break;
542bf53d441Sbrad 					case SCMD_SUBLOCKLOCK:
543bf53d441Sbrad 						error = common_set_lock_state(&func_block, fd, debug, lock_type, SCMD_LOCK_LOCKED);
544bf53d441Sbrad 						break;
545bf53d441Sbrad 					case SCMD_SUBLOCKUNLOCK:
546bf53d441Sbrad 						error = common_set_lock_state(&func_block, fd, debug, lock_type, SCMD_LOCK_UNLOCK);
547bf53d441Sbrad 						break;
548bf53d441Sbrad 					default:
549bf53d441Sbrad 						fprintf(stderr,"Unhandled subcommand to lock: %s %d\n\n", argv[2], validsub);
550bf53d441Sbrad 						usage();
551bf53d441Sbrad 						exit(1);
552bf53d441Sbrad 					}
553bf53d441Sbrad 				} else {
554bf53d441Sbrad 					fprintf(stderr,"Unknown subcommand to lock: %s\n\n", argv[2]);
555bf53d441Sbrad 					usage();
556bf53d441Sbrad 					exit(1);
557bf53d441Sbrad 				}
558bf53d441Sbrad 			} else {
559bf53d441Sbrad 				fprintf(stderr,"Missing arguments to lock command\n\n");
560bf53d441Sbrad 				usage();
561bf53d441Sbrad 				exit(1);
562bf53d441Sbrad 			}
563bf53d441Sbrad 			break;
564bf53d441Sbrad 		case SCMD_SPIREADONE:
565bf53d441Sbrad 			error = 0;
566bf53d441Sbrad 			if (dev_is_uart &&
567bf53d441Sbrad 			    uart_s == UART_IS_SPI_USERLAND) {
568bf53d441Sbrad 				error = uart_ul_spi_read_one(fd,debug);
569bf53d441Sbrad 			}
570bf53d441Sbrad 			break;
571bf53d441Sbrad 		default:
572bf53d441Sbrad 			fprintf(stderr,"Unknown handling of command: %d\n",valid);
573bf53d441Sbrad 			exit(2);
574bf53d441Sbrad 		}
575bf53d441Sbrad 
576bf53d441Sbrad 		if (! error) {
577bf53d441Sbrad 			switch (scmdcmds[valid].id) {
578bf53d441Sbrad 			case SCMD_IDENTIFY:
579bf53d441Sbrad 				print_identify(&ir);
580bf53d441Sbrad 				break;
581bf53d441Sbrad 			case SCMD_DIAG:
582bf53d441Sbrad 				print_diag(&diag);
583bf53d441Sbrad 				break;
584bf53d441Sbrad 			case SCMD_MOTOR:
585bf53d441Sbrad 				if (validsub != -1 &&
586bf53d441Sbrad 				    motorsubcmds[validsub].id == SCMD_SUBMOTORGET)
587bf53d441Sbrad 					print_motor(&motors);
588bf53d441Sbrad 				break;
589bf53d441Sbrad 			case SCMD_READ:
590bf53d441Sbrad 				for(int g = reg; g <= reg_e; g++)
591bf53d441Sbrad 					printf("Register %d (0x%02X) (%s): %d (0x%02X)\n",g,g,scmdregisternames[g],register_shadow[g],register_shadow[g]);
592bf53d441Sbrad 				break;
593bf53d441Sbrad 			case SCMD_UPDATERATE:
594bf53d441Sbrad 				if (validsub != -1 &&
595bf53d441Sbrad 				    updateratesubcmds[validsub].id == SCMD_SUBURGET)
596bf53d441Sbrad 					printf("Update rate: %dms\n",ur);
597bf53d441Sbrad 				break;
598bf53d441Sbrad 			case SCMD_EBUS:
599bf53d441Sbrad 				if (validsub != -1 &&
600bf53d441Sbrad 				    ebussubcmds[validsub].id == SCMD_SUBEBUSGET)
601bf53d441Sbrad 					printf("Expansion bus speed: %s (0x%02X)\n",(ebus_s <= 0x03) ? ebus_speeds[ebus_s] : "Unknown",ebus_s);
602bf53d441Sbrad 				break;
603bf53d441Sbrad 			case SCMD_LOCK:
604bf53d441Sbrad 				if (validsub != -1 &&
605bf53d441Sbrad 				    locksubcmds[validsub].id == SCMD_SUBLOCKGET) {
606bf53d441Sbrad 					int x = SCMD_MASTER_LOCK_UNLOCKED;
607bf53d441Sbrad 
608bf53d441Sbrad 					if (lock_type == SCMD_LOCAL_USER_LOCK ||
609bf53d441Sbrad 					    lock_type == SCMD_GLOBAL_USER_LOCK)
610bf53d441Sbrad 						x = SCMD_USER_LOCK_UNLOCKED;
611bf53d441Sbrad 					printf("Lock state: %s (0x%02X)\n",(lock_state == x ? "Unlocked" : "Locked"),lock_state);
612bf53d441Sbrad 				}
613bf53d441Sbrad 				break;
614bf53d441Sbrad 			case SCMD_WRITE:
615bf53d441Sbrad 			case SCMD_RESTART:
616bf53d441Sbrad 			case SCMD_ENUMERATE:
617bf53d441Sbrad 			case SCMD_SPIREADONE:
618bf53d441Sbrad 				break;
619bf53d441Sbrad 			default:
620bf53d441Sbrad 				fprintf(stderr,"Unknown printing of command: %d\n",valid);
621bf53d441Sbrad 				exit(2);
622bf53d441Sbrad 			}
623bf53d441Sbrad 		} else {
624bf53d441Sbrad 			fprintf(stderr,"Error: %d\n", error);
625bf53d441Sbrad 			exit(1);
626bf53d441Sbrad 		}
627bf53d441Sbrad 	} else {
628bf53d441Sbrad 		fprintf(stderr,"Unknown command: %s\n\n",argv[1]);
629bf53d441Sbrad 		usage();
630bf53d441Sbrad 		exit(1);
631bf53d441Sbrad 	}
632bf53d441Sbrad 
633bf53d441Sbrad 	close(fd);
634bf53d441Sbrad 	exit(0);
635bf53d441Sbrad }
636