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,®ister_shadow[reg]); 400bf53d441Sbrad } else { 401bf53d441Sbrad error = i2cspi_read_register(fd,debug,module,reg,reg_e,®ister_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