├── .gitignore ├── README.md ├── bw_dmx ├── Makefile ├── bw_dmx.c ├── dmx.h ├── dmx2ola.c ├── dmx_uart.c ├── makechar.c ├── mon_dmx.c └── set_output.c ├── bw_tool ├── Makefile ├── bw_tool.c └── usb_protocol.h └── gpio ├── Makefile ├── README └── gpio_list.c /.gitignore: -------------------------------------------------------------------------------- 1 | \#*# 2 | *~ 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | bw_rpi_tools 2 | ============ 3 | 4 | Tools to access the bitwizard I2C and SPI expansion boards 5 | on raspberry pi. 6 | 7 | 8 | Getting / compiling / installing 9 | ================================ 10 | 11 | If you don't have git installed already, on debian or derived 12 | operating systems (raspian): 13 | 14 | sudo apt-get install git-core 15 | 16 | Then get the bw_rpi_tools: 17 | 18 | git clone https://github.com/rewolff/bw_rpi_tools.git 19 | 20 | now, change into the directory: 21 | 22 | cd bw_rpi_tools 23 | cd bw_tool 24 | 25 | and build: 26 | 27 | make 28 | 29 | If that looks succesful, you can install with "make install". 30 | 31 | The "gpio" tools that are included were written before others wrote 32 | similar tools. Those seem more popular right now. Unless you need a 33 | specific feature from my gpio tools, just use what everybody else 34 | uses. 35 | 36 | The "wiringpi" library is the "similar tools" that I'm talking about. 37 | It uses the kernel interfaces to GPIO of the platform, and therefore 38 | does not have to do SOC-specific low-level-stuff that my GPIO tools 39 | here have to do. VZ just notified me that the base address of GPIOs 40 | changed on the "upgrade" from the raspberry pi model B+ to the 41 | raspberry pi 2 model B. That change has also been made to the kernel 42 | on the new platform, so the wiring pi library continues to work without 43 | modification while my gpio tools (unmaintained "two years" before the 44 | pi2 came out) would need a patch. 45 | 46 | 47 | -------------------------------------------------------------------------------- /bw_dmx/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CFLAGS=-Wall -O2 3 | CC=gcc 4 | 5 | MYBIN=bw_dmx mon_dmx dmx2ola dmx_uart makechar set_output 6 | all: $(MYBIN) 7 | 8 | install: $(MYBIN) 9 | cp $(MYBIN) /usr/bin 10 | 11 | clean: 12 | rm -f *~ *.o 13 | -------------------------------------------------------------------------------- /bw_dmx/bw_dmx.c: -------------------------------------------------------------------------------- 1 | /* 2 | * bw_dmx.c. 3 | * 4 | * Control the BitWizard SPI and I2C expansion boards on 5 | * Linux computers with spidev or i2c-dev. 6 | * 7 | * based on: 8 | * SPI testing utility (using spidev driver) 9 | * 10 | * Copyright (c) 2007 MontaVista Software, Inc. 11 | * Copyright (c) 2007 Anton Vorontsov 12 | * Copyright (c) 2012-2013 Roger Wolff 13 | * 14 | * This program is free software; you can redistribute it and/or modify 15 | * it under the terms of the GNU General Public License as published by 16 | * the Free Software Foundation; version 2 of the License. 17 | * 18 | * Cross-compile with cross-gcc -I/path/to/cross-kernel/include 19 | * 20 | * Compile on raspberry pi with 21 | * 22 | * gcc -Wall -O2 bw_dmx.c -o bw_dmx 23 | * 24 | * or with the included Makefile (type "make"). 25 | */ 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | 40 | #include 41 | #include 42 | #include 43 | 44 | #include "dmx.h" 45 | 46 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 47 | 48 | 49 | 50 | struct spi_txrx spibuf; 51 | static enum mode_t dmxmode = DMX_TX; 52 | 53 | enum {SPI_MODE = 1, I2C_MODE, USB_I2CMODE, USB_SPIMODE }; 54 | static int mode = SPI_MODE; 55 | 56 | static const char *device = "/dev/spidev0.0"; 57 | static uint8_t spi_mode; 58 | static uint8_t bits = 8; 59 | static uint32_t speed = 6000000; 60 | static int delay = 0; 61 | static int wait = 22000; 62 | //static int addr = 0x82; 63 | //static int text = 0; 64 | //static char *monitor_file; 65 | //static int readmode = 0; 66 | 67 | //static int reg = -1; 68 | //static long long val = -1; 69 | //static int cls = 0; 70 | //static int write8mode, writemiscmode, ident, readee; 71 | //static int scan = 0; 72 | //static int hexmode = 0; 73 | //static char numberformat = 'x'; 74 | 75 | static int debug = 0; 76 | #define DEBUG_REGSETTING 0x0001 77 | #define DEBUG_TRANSFER 0x0002 78 | 79 | static void pabort(const char *s) 80 | { 81 | perror(s); 82 | exit(1); 83 | } 84 | 85 | void dump_buffer (unsigned char *buf, int n) 86 | { 87 | int i; 88 | for (i=0;i tlen) tr.len = rlen; 111 | // else tr.len = tlen; 112 | tr.len = tlen + rlen; 113 | tr.tx_buf = (unsigned long) buf; 114 | tr.rx_buf = (unsigned long) buf; 115 | 116 | ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); 117 | if (ret < 1) 118 | pabort("can't send spi message"); 119 | 120 | } 121 | 122 | 123 | static void i2c_txrx (int fd, unsigned char *buf, int tlen, int rlen) 124 | { 125 | static int slave = -1; 126 | 127 | if (buf[0] != slave) { 128 | if (ioctl(fd, I2C_SLAVE, buf[0] >> 1) < 0) 129 | pabort ("can't set slave addr"); 130 | slave = buf[0]; 131 | } 132 | if (write (fd, buf+1, tlen-1) != (tlen-1)) { 133 | pabort ("can't write i2c"); 134 | } 135 | //XXX: check return code. 136 | if (rlen) 137 | if (read (fd, buf+tlen, rlen) != rlen) 138 | pabort ("can't read i2c"); 139 | } 140 | 141 | 142 | int myread (int fd, unsigned char *buf, int len) 143 | { 144 | int nr, cr; 145 | 146 | nr = 0; 147 | while (nr < len) { 148 | cr = read (fd, buf+nr, len-nr); 149 | if (cr < 0) return nr?nr:cr; 150 | nr += cr; 151 | } 152 | return nr; 153 | } 154 | 155 | 156 | static void usb_spitxrx (int fd, unsigned char *buf, int tlen, int rlen) 157 | { 158 | // static int slave = -1; 159 | static char cmd[] = {0x01, 0x10, 0 }; 160 | 161 | cmd[2] = tlen + rlen; 162 | 163 | if (write (fd, cmd, 3) != 3) { 164 | pabort ("can't write USB cmd"); 165 | } 166 | if (write (fd, buf, tlen+rlen) != tlen+rlen) { 167 | pabort ("can't write USB buf"); 168 | } 169 | 170 | //XXX: check return code. 171 | if (myread (fd, buf, 2) != 2) { 172 | pabort ("can't read USB"); 173 | } 174 | 175 | if (buf[0] != 0x90) 176 | pabort ("invalid response code from USB"); 177 | 178 | if (buf[1] != tlen+rlen) 179 | pabort ("invalid lenght code from USB"); 180 | 181 | if (myread (fd, buf, tlen+rlen) != tlen+rlen) 182 | pabort ("can't read USB"); 183 | } 184 | 185 | 186 | 187 | static void usb_i2ctxrx (int fd, unsigned char *buf, int tlen, int rlen) 188 | { 189 | // static int slave = -1; 190 | static char cmd[] = {1, 2, 0,0 }; 191 | 192 | cmd[1] = 2; // I2C txrx 193 | cmd[2] = tlen+1; 194 | cmd[3] = rlen; 195 | 196 | if (write (fd, cmd, 4) != 4) { 197 | pabort ("can't write USB cmd"); 198 | } 199 | if (write (fd, buf, tlen) != tlen) { 200 | pabort ("can't write USB buf"); 201 | } 202 | 203 | if (myread (fd, buf, 3) != 3) { 204 | pabort ("can't read USB"); 205 | } 206 | 207 | // printf ("buf[] = %02x %02x %02x\n", buf[0], buf[1], buf[2]); 208 | 209 | if (buf[0] != 0x82) 210 | pabort ("invalid response code from USB"); 211 | 212 | if (buf[1] != rlen+1) 213 | pabort ("i2c rlen incorrect"); 214 | 215 | if (buf[2] != 0) 216 | pabort ("i2c transaction failed"); 217 | 218 | if (myread (fd, buf+tlen, rlen) != rlen) 219 | pabort ("can't read USB"); 220 | } 221 | 222 | 223 | static void transfer(int fd, unsigned char *buf, int tlen, int rlen) 224 | { 225 | //printf ("buf=%p.\n", buf); 226 | if (debug & DEBUG_TRANSFER) 227 | dump_buf ("Before tx:", buf, tlen); 228 | if (mode == SPI_MODE) 229 | spi_txrx (fd, buf, tlen, rlen); 230 | else if (mode == I2C_MODE) 231 | i2c_txrx (fd, buf, tlen, rlen); 232 | else if (mode == USB_SPIMODE) 233 | usb_spitxrx (fd, buf, tlen, rlen); 234 | else if (mode == USB_I2CMODE) 235 | usb_i2ctxrx (fd, buf, tlen, rlen); 236 | else 237 | pabort ("invalid mode...\n"); 238 | 239 | if (debug & DEBUG_TRANSFER) 240 | dump_buf ("rx:", buf, tlen+rlen); 241 | } 242 | 243 | 244 | #if 0 245 | static void send_text (int fd, unsigned char *str) 246 | { 247 | unsigned char *buf; 248 | int l; 249 | 250 | l = strlen ((char*)str); 251 | buf = malloc (l + 5); 252 | buf[0] = addr; 253 | if (reg <= 0) 254 | buf [1] = 0; 255 | else { 256 | buf [1] = reg; 257 | l++; 258 | } 259 | strcpy ((char *)buf+2, (char*)str); 260 | strcat ((char *)buf+2, "\xff\0"); // always append the 0xff, but it won't be sent if reg = 0; 261 | transfer (fd, buf, l+2, 0); 262 | free (buf); 263 | } 264 | 265 | 266 | static void set_reg_value8 (int fd, int reg, int val) 267 | { 268 | unsigned char buf[5]; 269 | 270 | buf[0] = addr; 271 | buf[1] = reg; 272 | buf[2] = val; 273 | transfer (fd, buf, 3, 0); 274 | } 275 | 276 | 277 | 278 | static void set_reg_value16 (int fd, int reg, int val) 279 | { 280 | unsigned char buf[5]; 281 | 282 | buf[0] = addr; 283 | buf[1] = reg; 284 | buf[2] = val; 285 | buf[3] = val >> 8; 286 | transfer (fd, buf, 4, 0); 287 | } 288 | 289 | static void set_reg_value32 (int fd, int reg, int val) 290 | { 291 | unsigned char buf[15]; 292 | 293 | buf[0] = addr; 294 | buf[1] = reg; 295 | buf[2] = val; 296 | buf[3] = val >> 8; 297 | buf[4] = val >> 16; 298 | buf[5] = val >> 24; 299 | transfer (fd, buf, 6, 0); 300 | } 301 | 302 | 303 | static void set_reg_value64 (int fd, int reg, long long val) 304 | { 305 | unsigned char buf[15]; 306 | 307 | buf[0] = addr; 308 | buf[1] = reg; 309 | buf[2] = val; 310 | buf[3] = val >> 8; 311 | buf[4] = val >> 16; 312 | buf[5] = val >> 24; 313 | buf[6] = val >> 32; 314 | buf[7] = val >> 40; 315 | buf[8] = val >> 48; 316 | buf[9] = val >> 56; 317 | transfer (fd, buf, 10, 0); 318 | } 319 | 320 | 321 | static unsigned int get_reg_value8 (int fd, int reg) 322 | { 323 | unsigned char buf[5]; 324 | 325 | buf[0] = addr | 1; 326 | buf[1] = reg; 327 | transfer (fd, buf, 2, 1); 328 | //dump_buffer (buf, 5); 329 | return buf[2]; 330 | } 331 | 332 | 333 | static unsigned int get_reg_value16 (int fd, int reg) 334 | { 335 | unsigned char buf[5]; 336 | 337 | buf[0] = addr | 1; 338 | buf[1] = reg; 339 | transfer (fd, buf, 2, 2); 340 | //dump_buffer (buf, 5); 341 | return buf[2] | (buf[3] << 8); 342 | } 343 | 344 | 345 | static unsigned int get_reg_value32 (int fd, int reg) 346 | { 347 | unsigned char buf[10]; 348 | 349 | buf[0] = addr | 1; 350 | buf[1] = reg; 351 | transfer (fd, buf, 2, 4); 352 | //dump_buffer (buf, 5); 353 | return buf[2] | (buf[3] << 8) | (buf[4] << 16) | (buf[5] << 24); 354 | } 355 | 356 | static long long get_reg_value64 (int fd, int reg) 357 | { 358 | unsigned char buf[10]; 359 | unsigned int t, tt; 360 | 361 | buf[0] = addr | 1; 362 | buf[1] = reg; 363 | transfer (fd, buf, 2, 8); 364 | t = buf[2] | (buf[3] << 8) | (buf[4] << 16) | (buf[5] << 24); 365 | tt = buf[6] | (buf[7] << 8) | (buf[8] << 16) | (buf[9] << 24); 366 | return ((long long) tt << 32) | t; 367 | } 368 | 369 | 370 | static void do_ident (int fd) 371 | { 372 | unsigned char buf[0x20]; 373 | int i; 374 | 375 | buf [0] = addr | 1; 376 | buf [1] = 1; 377 | 378 | transfer (fd, buf, 0x2,0x20); 379 | 380 | for (i= 2 ;i<0x20;i++) { 381 | if (!buf[i]) break; 382 | putchar (buf[i]); 383 | } 384 | putchar ('\n'); 385 | } 386 | 387 | 388 | static void do_readee (int fd) 389 | { 390 | #define EELEN 0x80 391 | unsigned char buf[EELEN]; 392 | int i; 393 | 394 | buf [0] = addr | 1; 395 | buf [1] = 2; 396 | 397 | transfer (fd, buf, 0x2, 0x80); 398 | 399 | for (i = 0;i < EELEN;i++) { 400 | if (!(i & 0xf)) printf ("\n%04x: ", i); 401 | printf ("%02x ", ((unsigned char *) buf)[i+2]); 402 | 403 | } 404 | printf ("\n"); 405 | } 406 | 407 | 408 | #endif 409 | 410 | char mkprintable (char ch) 411 | { 412 | if (ch < ' ') return '.'; 413 | if (ch <= '~') return ch; 414 | return '.'; 415 | } 416 | 417 | 418 | #if 0 419 | 420 | static void do_scan (int fd) 421 | { 422 | unsigned char buf[0x20]; 423 | int add; 424 | int i; 425 | 426 | for (add = 0;add < 255;add += 2) { 427 | buf[0] = add | 1; 428 | buf[1] = 1; 429 | transfer (fd, buf, 0x2, 0x20); 430 | for (i=(mode==I2C_MODE)?0:2;i<0x20;i++) { 431 | if (mkprintable (buf[i]) != '.') break; 432 | } 433 | if (i != 0x20) { 434 | printf ("%02x: ", add); 435 | for (i=(mode==I2C_MODE)?0:2;i<0x20;i++) { 436 | if (buf[i] == 0) break; 437 | putchar (mkprintable (buf[i])); 438 | } 439 | printf ("\n"); 440 | } 441 | } 442 | 443 | } 444 | 445 | #endif 446 | 447 | 448 | static void print_usage(const char *prog) 449 | { 450 | printf("Usage: %s [-DsbdlHOLC3]\n", prog); 451 | puts(" -D --device device to use (default /dev/spidev1.1)\n" 452 | " -s --speed max speed (Hz)\n" 453 | " -d --delay delay (usec)\n" 454 | " -r --rx \n" 455 | " -v --val value\n" 456 | " -a --addr address\n" 457 | " -w --write8 write an octet\n" 458 | " -W --write write arbitrary type\n" 459 | " -i --interval set the interval\n" 460 | " -S --scan Scan the bus for devices \n" 461 | " -R --read multi-datasize read\n" 462 | " -I --i2c I2C mode (uses /dev/i2c-0, change with -D)\n" 463 | " -U --usb USB mode (uses /dev/ttyACM0, change with -D)\n" 464 | " -1 --decimal Numbers are decimal. (registers remain in hex)\n" 465 | ); 466 | 467 | exit(1); 468 | } 469 | 470 | static const struct option lopts[] = { 471 | 472 | // SPI options. 473 | { "device", 1, 0, 'D' }, 474 | { "speed", 1, 0, 's' }, 475 | { "delay", 1, 0, 'd' }, 476 | { "wait", 1, 0, 'w' }, 477 | 478 | { "idle", 0, 0, 'i' }, 479 | { "rx", 0, 0, 'r' }, 480 | // { "addr", 1, 0, 'a' }, 481 | // { "write8", 0, 0, 'w' }, 482 | // { "write", 0, 0, 'W' }, 483 | //{ "interval", 1, 0, 'i' }, 484 | //{ "scan", 0, 0, 'S' }, 485 | //{ "read", 0, 0, 'R' }, 486 | //{ "eeprom", 0, 0, 'e' }, 487 | 488 | 489 | // Options for LCD 490 | //{ "text", 0, 0, 't' }, 491 | //{ "cls", 0, 0, 'C' }, 492 | //{ "monitor", 1, 0, 'm' }, 493 | 494 | //{ "hex", 0, 0, 'h' }, 495 | 496 | //{ "i2c", 0, 0, 'I' }, 497 | //{ "usbspi", 0, 0, 'u' }, 498 | //{ "usbi2c", 0, 0, 'U' }, 499 | //{ "decimal", 0, 0, '1' }, 500 | 501 | { "verbose", 1, 0, 'V' }, 502 | { "help", 0, 0, '?' }, 503 | { NULL, 0, 0, 0 }, 504 | }; 505 | 506 | 507 | 508 | static int parse_opts(int argc, char *argv[]) 509 | { 510 | while (1) { 511 | int c; 512 | 513 | c = getopt_long(argc, argv, "D:s:d:rV:w:i", lopts, NULL); 514 | 515 | if (c == -1) 516 | break; 517 | 518 | switch (c) { 519 | case 'D': 520 | device = strdup (optarg); 521 | if (strstr (device, "i2c")) mode=I2C_MODE; 522 | else mode=SPI_MODE; 523 | break; 524 | case 's': 525 | speed = atoi(optarg); 526 | break; 527 | case 'd': 528 | delay = atoi(optarg); 529 | break; 530 | case 'w': 531 | wait = 1000*atoi(optarg); 532 | break; 533 | case 'r': 534 | dmxmode = DMX_RX; 535 | break; 536 | case 'V': 537 | debug = atoi(optarg); 538 | break; 539 | case 'i': 540 | dmxmode = DMX_IDLE; 541 | break; 542 | 543 | case '?': 544 | print_usage (argv[0]); 545 | exit (0); 546 | break; 547 | 548 | default: 549 | print_usage(argv[0]); 550 | break; 551 | } 552 | } 553 | return optind; 554 | } 555 | 556 | 557 | void setup_spi_mode (int fd) 558 | { 559 | int ret; 560 | /* 561 | * spi mode 562 | */ 563 | // printf ("setting spi mode. \n"); 564 | ret = ioctl(fd, SPI_IOC_WR_MODE, &spi_mode); 565 | if (ret == -1) 566 | pabort("can't set spi mode"); 567 | 568 | ret = ioctl(fd, SPI_IOC_RD_MODE, &spi_mode); 569 | if (ret == -1) 570 | pabort("can't get spi mode"); 571 | 572 | /* 573 | * bits per word 574 | */ 575 | ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); 576 | if (ret == -1) 577 | pabort("can't set bits per word"); 578 | 579 | ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits); 580 | if (ret == -1) 581 | pabort("can't get bits per word"); 582 | 583 | /* 584 | * max speed hz 585 | */ 586 | ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); 587 | if (ret == -1) 588 | pabort("can't set max speed hz"); 589 | 590 | ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); 591 | if (ret == -1) 592 | pabort("can't get max speed hz"); 593 | 594 | //printf("spi mode: %d\n", spi_mode); 595 | //printf("bits per word: %d\n", bits); 596 | //printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); 597 | } 598 | 599 | 600 | 601 | #if 0 602 | void wait_for_file_changed (char *fname) 603 | { 604 | static time_t lastmtime = 0; 605 | struct stat statb; 606 | 607 | while (1) { 608 | if (stat (fname, &statb) < 0) { 609 | pabort (fname); 610 | } 611 | 612 | if (lastmtime != statb.st_mtime) { 613 | //printf ("fc: %x / %x\n", (int) lastmtime, (int) statb.st_mtime); 614 | lastmtime = statb.st_mtime; 615 | return; 616 | } 617 | usleep (250000); 618 | } 619 | } 620 | 621 | 622 | unsigned char *get_file_line (char *fname, int lno) 623 | { 624 | static unsigned char buf[0x50], *p; 625 | FILE *f; 626 | int i; 627 | 628 | 629 | f = fopen (fname, "r"); 630 | if (!f) pabort (fname); 631 | for (i = 0;i<=lno;i++) { 632 | buf [0] = 0; 633 | p = (unsigned char*)fgets ((char*)buf, 0x3f, f); 634 | if (!p) return p; 635 | } 636 | 637 | fclose (f); 638 | buf[strlen((char*)buf)-1] = 0; // chop! 639 | return buf; 640 | } 641 | 642 | 643 | void do_monitor_file (int fd, char *fname) 644 | { 645 | int i; 646 | unsigned char *buf; 647 | char olddisplay[4][0x20]; 648 | 649 | //fprintf (stderr, "monitoring %s on fd %d.\n", fname, fd); 650 | while (1) { 651 | wait_for_file_changed (fname); 652 | //set_reg_value8 (fd, 0x10, 0xaa); 653 | for (i=0;i<4;i++) { 654 | buf = get_file_line (fname, i); 655 | if (!buf) break; 656 | while (strlen ((char*)buf) < 20) strcat ((char*)buf, " "); 657 | buf[20] = 0; 658 | if (strcmp ((char*)buf, olddisplay[i])) { 659 | strcpy (olddisplay[i], (char *)buf); 660 | set_reg_value8 (fd, 0x11, i<<5); 661 | send_text (fd, buf); 662 | usleep (50000); 663 | } 664 | } 665 | } 666 | } 667 | 668 | #endif 669 | 670 | 671 | 672 | #define MAXUNIV 16 673 | 674 | int main(int argc, char *argv[]) 675 | { 676 | int fd; 677 | int nonoptions; 678 | int last; 679 | // int i, rv; 680 | // char typech; 681 | // char format[32]; 682 | char *thefile; 683 | int infd; 684 | unsigned char *data[MAXUNIV]; 685 | int nodata = 0; 686 | int i, u, numuniv; 687 | 688 | if (argc <= 1) { 689 | print_usage (argv[0]); 690 | exit (0); 691 | } 692 | 693 | nonoptions = parse_opts(argc, argv); 694 | 695 | //fprintf (stderr, "dev = %s\n", device); 696 | //fprintf (stderr, "mode = %d\n", mode); 697 | fd = open(device, O_RDWR); 698 | if (fd < 0) 699 | pabort("can't open device"); 700 | 701 | if (mode == SPI_MODE) setup_spi_mode (fd); 702 | 703 | if (dmxmode == DMX_IDLE) { 704 | spibuf.cmd = CMD_IDLE; 705 | transfer (fd, (void*) &spibuf, 0x209, 0); 706 | exit (0); 707 | } 708 | 709 | numuniv = 0; 710 | for (i=nonoptions;i= numuniv) u = 0; 734 | } 735 | 736 | if (dmxmode == DMX_RX) { 737 | spibuf.cmd = CMD_READ_DMX; 738 | } 739 | 740 | // transfer 8 byte header + 513 byte datablock. 741 | transfer (fd, (void*) &spibuf, 0x209, 0); 742 | 743 | if (dmxmode == DMX_RX) { 744 | if (spibuf.p1 != last) { 745 | memcpy (data[0], spibuf.dmxbuf, 0x200); 746 | last = spibuf.p1; 747 | } else { 748 | if (spibuf.cmd == STAT_RX_IN_PROGRESS) { 749 | usleep (1000); 750 | continue; 751 | } 752 | printf ("no data %d\r", nodata++); 753 | fflush (stdout); 754 | } 755 | } 756 | usleep (wait); 757 | } 758 | 759 | exit (0); 760 | } 761 | -------------------------------------------------------------------------------- /bw_dmx/dmx.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | struct spi_txrx { 5 | int cmd; 6 | int p1, p2; 7 | union { 8 | unsigned char r_dmxbuf[516]; // 513 + alignment. 9 | int r_params[10]; 10 | } rest; 11 | }; 12 | 13 | struct spi_txrx spi_in, spi_out; 14 | 15 | #define dmxbuf rest.r_dmxbuf 16 | #define params rest.r_params 17 | 18 | 19 | 20 | struct config { 21 | int mab; 22 | int breaktime; 23 | int autosend; 24 | int datalen; 25 | } config; 26 | 27 | 28 | enum mode_t { DMX_IDLE, DMX_TX, DMX_RX}; 29 | 30 | 31 | /* ******************** the protocol *******************************/ 32 | enum spi_cmd_t { CMD_DMXDATA=0x1234, 33 | CMD_DMX_DATA, 34 | CMD_SETBREAK, 35 | CMD_SETMAB, 36 | CMD_SETDATALEN, 37 | CMD_AUTOSEND, 38 | CMD_IDLE, 39 | CMD_READ_DMX, // 0x123a 40 | STAT_NODATA, // 0x123b 41 | STAT_RX_IN_PROGRESS, //3c 42 | STAT_RXDONE, // 0x123d 43 | STAT_RXOK, // 0x123e 44 | STAT_TX_ACTIVE, 45 | STAT_TX_DONE, 46 | }; 47 | 48 | -------------------------------------------------------------------------------- /bw_dmx/dmx2ola.c: -------------------------------------------------------------------------------- 1 | /* 2 | * dmx2ola.c. 3 | * 4 | * Control the BitWizard SPI and I2C expansion boards on 5 | * Linux computers with spidev or i2c-dev. 6 | * 7 | * based on: 8 | * SPI testing utility (using spidev driver) 9 | * 10 | * Copyright (c) 2007 MontaVista Software, Inc. 11 | * Copyright (c) 2007 Anton Vorontsov 12 | * Copyright (c) 2012-2013 Roger Wolff 13 | * 14 | * This program is free software; you can redistribute it and/or modify 15 | * it under the terms of the GNU General Public License as published by 16 | * the Free Software Foundation; version 2 of the License. 17 | * 18 | * Cross-compile with cross-gcc -I/path/to/cross-kernel/include 19 | * 20 | * Compile on raspberry pi with 21 | * 22 | * gcc -Wall -O2 dmx2ola.c -o dmx2ola 23 | * 24 | * or with the included Makefile (type "make"). 25 | */ 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | 40 | #include 41 | #include 42 | #include 43 | 44 | #include "dmx.h" 45 | 46 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 47 | 48 | 49 | 50 | struct spi_txrx spibuf; 51 | //static enum mode_t dmxmode = DMX_TX; 52 | 53 | enum {SPI_MODE = 1, I2C_MODE, USB_I2CMODE, USB_SPIMODE }; 54 | static int mode = SPI_MODE; 55 | 56 | static const char *device = "/dev/spidev0.0"; 57 | static uint8_t spi_mode; 58 | static uint8_t bits = 8; 59 | 60 | static uint32_t speed = 6000000; 61 | static int delay = 0; 62 | static int wait = 22000; 63 | static int universe = 0; 64 | 65 | 66 | static int debug = 0; 67 | #define DEBUG_REGSETTING 0x0001 68 | #define DEBUG_TRANSFER 0x0002 69 | 70 | static void pabort(const char *s) 71 | { 72 | perror(s); 73 | exit(1); 74 | } 75 | 76 | void dump_buffer (unsigned char *buf, int n) 77 | { 78 | int i; 79 | for (i=0;i tlen) tr.len = rlen; 102 | // else tr.len = tlen; 103 | tr.len = tlen + rlen; 104 | tr.tx_buf = (unsigned long) buf; 105 | tr.rx_buf = (unsigned long) buf; 106 | 107 | ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); 108 | if (ret < 1) 109 | pabort("can't send spi message"); 110 | 111 | } 112 | 113 | 114 | static void i2c_txrx (int fd, unsigned char *buf, int tlen, int rlen) 115 | { 116 | static int slave = -1; 117 | 118 | if (buf[0] != slave) { 119 | if (ioctl(fd, I2C_SLAVE, buf[0] >> 1) < 0) 120 | pabort ("can't set slave addr"); 121 | slave = buf[0]; 122 | } 123 | if (write (fd, buf+1, tlen-1) != (tlen-1)) { 124 | pabort ("can't write i2c"); 125 | } 126 | //XXX: check return code. 127 | if (rlen) 128 | if (read (fd, buf+tlen, rlen) != rlen) 129 | pabort ("can't read i2c"); 130 | } 131 | 132 | 133 | int myread (int fd, unsigned char *buf, int len) 134 | { 135 | int nr, cr; 136 | 137 | nr = 0; 138 | while (nr < len) { 139 | cr = read (fd, buf+nr, len-nr); 140 | if (cr < 0) return nr?nr:cr; 141 | nr += cr; 142 | } 143 | return nr; 144 | } 145 | 146 | 147 | static void usb_spitxrx (int fd, unsigned char *buf, int tlen, int rlen) 148 | { 149 | // static int slave = -1; 150 | static char cmd[] = {0x01, 0x10, 0 }; 151 | 152 | cmd[2] = tlen + rlen; 153 | 154 | if (write (fd, cmd, 3) != 3) { 155 | pabort ("can't write USB cmd"); 156 | } 157 | if (write (fd, buf, tlen+rlen) != tlen+rlen) { 158 | pabort ("can't write USB buf"); 159 | } 160 | 161 | //XXX: check return code. 162 | if (myread (fd, buf, 2) != 2) { 163 | pabort ("can't read USB"); 164 | } 165 | 166 | if (buf[0] != 0x90) 167 | pabort ("invalid response code from USB"); 168 | 169 | if (buf[1] != tlen+rlen) 170 | pabort ("invalid lenght code from USB"); 171 | 172 | if (myread (fd, buf, tlen+rlen) != tlen+rlen) 173 | pabort ("can't read USB"); 174 | } 175 | 176 | 177 | 178 | static void usb_i2ctxrx (int fd, unsigned char *buf, int tlen, int rlen) 179 | { 180 | // static int slave = -1; 181 | static char cmd[] = {1, 2, 0,0 }; 182 | 183 | cmd[1] = 2; // I2C txrx 184 | cmd[2] = tlen+1; 185 | cmd[3] = rlen; 186 | 187 | if (write (fd, cmd, 4) != 4) { 188 | pabort ("can't write USB cmd"); 189 | } 190 | if (write (fd, buf, tlen) != tlen) { 191 | pabort ("can't write USB buf"); 192 | } 193 | 194 | if (myread (fd, buf, 3) != 3) { 195 | pabort ("can't read USB"); 196 | } 197 | 198 | // printf ("buf[] = %02x %02x %02x\n", buf[0], buf[1], buf[2]); 199 | 200 | if (buf[0] != 0x82) 201 | pabort ("invalid response code from USB"); 202 | 203 | if (buf[1] != rlen+1) 204 | pabort ("i2c rlen incorrect"); 205 | 206 | if (buf[2] != 0) 207 | pabort ("i2c transaction failed"); 208 | 209 | if (myread (fd, buf+tlen, rlen) != rlen) 210 | pabort ("can't read USB"); 211 | } 212 | 213 | 214 | static void transfer(int fd, unsigned char *buf, int tlen, int rlen) 215 | { 216 | //printf ("buf=%p.\n", buf); 217 | if (debug & DEBUG_TRANSFER) 218 | dump_buf ("Before tx:", buf, tlen); 219 | if (mode == SPI_MODE) 220 | spi_txrx (fd, buf, tlen, rlen); 221 | else if (mode == I2C_MODE) 222 | i2c_txrx (fd, buf, tlen, rlen); 223 | else if (mode == USB_SPIMODE) 224 | usb_spitxrx (fd, buf, tlen, rlen); 225 | else if (mode == USB_I2CMODE) 226 | usb_i2ctxrx (fd, buf, tlen, rlen); 227 | else 228 | pabort ("invalid mode...\n"); 229 | 230 | if (debug & DEBUG_TRANSFER) 231 | dump_buf ("rx:", buf, tlen+rlen); 232 | } 233 | 234 | 235 | 236 | static void print_usage(const char *prog) 237 | { 238 | printf("Usage: %s [-DsbdlHOLC3]\n", prog); 239 | puts(" -D --device device to use (default /dev/spidev1.1)\n" 240 | " -s --speed max speed (Hz)\n" 241 | " -d --delay delay (usec)\n" 242 | " -r --rx \n" 243 | " -v --val value\n" 244 | " -a --addr address\n" 245 | " -w --write8 write an octet\n" 246 | " -W --write write arbitrary type\n" 247 | " -i --interval set the interval\n" 248 | " -S --scan Scan the bus for devices \n" 249 | " -R --read multi-datasize read\n" 250 | " -I --i2c I2C mode (uses /dev/i2c-0, change with -D)\n" 251 | " -U --usb USB mode (uses /dev/ttyACM0, change with -D)\n" 252 | " -1 --decimal Numbers are decimal. (registers remain in hex)\n" 253 | ); 254 | 255 | exit(1); 256 | } 257 | 258 | static const struct option lopts[] = { 259 | 260 | // SPI options. 261 | { "device", 1, 0, 'D' }, 262 | { "speed", 1, 0, 's' }, 263 | { "delay", 1, 0, 'd' }, 264 | 265 | { "universe", 1, 0, 'u' }, 266 | 267 | { "help", 0, 0, '?' }, 268 | { NULL, 0, 0, 0 }, 269 | }; 270 | 271 | 272 | 273 | static int parse_opts(int argc, char *argv[]) 274 | { 275 | while (1) { 276 | int c; 277 | 278 | c = getopt_long(argc, argv, "D:s:d:u:?", lopts, NULL); 279 | 280 | if (c == -1) 281 | break; 282 | 283 | switch (c) { 284 | case 'D': 285 | device = strdup (optarg); 286 | if (strstr (device, "i2c")) mode=I2C_MODE; 287 | else mode=SPI_MODE; 288 | break; 289 | case 's': 290 | speed = atoi(optarg); 291 | break; 292 | case 'd': 293 | delay = atoi(optarg); 294 | break; 295 | case 'u': 296 | universe = atoi(optarg); 297 | break; 298 | 299 | case '?': 300 | print_usage (argv[0]); 301 | exit (0); 302 | break; 303 | 304 | default: 305 | print_usage(argv[0]); 306 | break; 307 | } 308 | } 309 | return optind; 310 | } 311 | 312 | 313 | void setup_spi_mode (int fd) 314 | { 315 | int ret; 316 | /* 317 | * spi mode 318 | */ 319 | // printf ("setting spi mode. \n"); 320 | ret = ioctl(fd, SPI_IOC_WR_MODE, &spi_mode); 321 | if (ret == -1) 322 | pabort("can't set spi mode"); 323 | 324 | ret = ioctl(fd, SPI_IOC_RD_MODE, &spi_mode); 325 | if (ret == -1) 326 | pabort("can't get spi mode"); 327 | 328 | /* 329 | * bits per word 330 | */ 331 | ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); 332 | if (ret == -1) 333 | pabort("can't set bits per word"); 334 | 335 | ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits); 336 | if (ret == -1) 337 | pabort("can't get bits per word"); 338 | 339 | /* 340 | * max speed hz 341 | */ 342 | ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); 343 | if (ret == -1) 344 | pabort("can't set max speed hz"); 345 | 346 | ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); 347 | if (ret == -1) 348 | pabort("can't get max speed hz"); 349 | 350 | //printf("spi mode: %d\n", spi_mode); 351 | //printf("bits per word: %d\n", bits); 352 | //printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); 353 | } 354 | 355 | 356 | 357 | int main(int argc, char *argv[]) 358 | { 359 | int fd; 360 | //int nonoptions; 361 | int last; 362 | int i; 363 | char ola_streaming_cmd[0x80]; 364 | FILE *ola_streaming_fp; 365 | //int infd; 366 | unsigned char data[0x210]; 367 | int nodata = 0; 368 | int yesdata = 0; 369 | 370 | #if 0 371 | if (argc <= 1) { 372 | print_usage (argv[0]); 373 | exit (0); 374 | } 375 | #endif 376 | 377 | // nonoptions = 378 | parse_opts(argc, argv); 379 | 380 | //fprintf (stderr, "dev = %s\n", device); 381 | //fprintf (stderr, "mode = %d\n", mode); 382 | 383 | fd = open(device, O_RDWR); 384 | if (fd < 0) 385 | pabort("can't open device"); 386 | 387 | if (mode == SPI_MODE) setup_spi_mode (fd); 388 | 389 | sprintf (ola_streaming_cmd, "ola_streaming_client -u %d", universe); 390 | ola_streaming_fp = popen (ola_streaming_cmd, "w"); 391 | if (ola_streaming_fp == NULL ) { 392 | perror ("opening pipe to ola_streaming_client"); 393 | exit (1); 394 | } 395 | 396 | last = -1; 397 | while (1) { 398 | spibuf.cmd = CMD_READ_DMX; 399 | 400 | // transfer 8 byte header + 513 byte datablock. 401 | transfer (fd, (void*) &spibuf, 0x209, 0); 402 | 403 | if (spibuf.p1 != last) { 404 | if (memcmp (data, spibuf.dmxbuf, 0x200) != 0) { 405 | memcpy (data, spibuf.dmxbuf, 0x200); 406 | // The DMX data starts at offset 1. 407 | for (i=1;i<512;i++) 408 | fprintf (ola_streaming_fp, "%d,", data[i]); 409 | //fprintf (ola_streaming_fp, "%d\n", data[i]); 410 | fflush (ola_streaming_fp); 411 | } 412 | last = spibuf.p1; 413 | printf ("data/nodata %d/%d \r", yesdata++, nodata); 414 | fflush (stdout); 415 | } else { 416 | if (spibuf.cmd == STAT_RX_IN_PROGRESS) { 417 | usleep (1000); 418 | continue; 419 | } 420 | printf ("data/nodata %d/%d \r", yesdata, nodata++); 421 | fflush (stdout); 422 | } 423 | 424 | usleep (wait); 425 | } 426 | 427 | 428 | exit (0); 429 | } 430 | -------------------------------------------------------------------------------- /bw_dmx/dmx_uart.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | #include 10 | #include 11 | 12 | //#include 13 | 14 | extern int tcgetattr (int __fd, struct termios *__termios_p) __THROW; 15 | extern void cfmakeraw (struct termios *__termios_p) __THROW; 16 | extern int tcsetattr (int __fd, int __optional_actions, 17 | const struct termios *__termios_p) __THROW; 18 | 19 | 20 | 21 | int main (int argc, char **argv) 22 | { 23 | char *thefile; 24 | char *data; 25 | int infd, uartfd; 26 | char *theuart = "/dev/ttyAMA0"; 27 | struct termios my_tios; 28 | struct termios2 tio; 29 | 30 | 31 | thefile = argv[1]; 32 | infd = open (thefile, O_RDWR); 33 | if (infd < 0) { 34 | perror (thefile); 35 | exit (1); 36 | } 37 | data = mmap (NULL, 0x200, PROT_READ | PROT_WRITE, MAP_SHARED, infd, 0); 38 | 39 | uartfd = open (theuart, O_RDWR); 40 | if (uartfd < 0) { 41 | perror (theuart); 42 | exit (1); 43 | } 44 | 45 | if (tcgetattr(uartfd, &my_tios) < 0) { // get current settings 46 | perror ("tcgetattr"); 47 | exit (1); 48 | } 49 | 50 | cfmakeraw(&my_tios); // make it a binary data port 51 | my_tios.c_cflag |= CLOCAL; // port is local, no flow control 52 | my_tios.c_cflag &= ~CSIZE; 53 | my_tios.c_cflag |= CS8; // 8 bit chars 54 | my_tios.c_cflag &= ~PARENB; // no parity 55 | my_tios.c_cflag |= CSTOPB; // 2 stop bit for DMX 56 | my_tios.c_cflag &= ~CRTSCTS; // no CTS/RTS flow control 57 | 58 | if (tcsetattr(uartfd, TCSANOW, &my_tios) < 0) { // apply settings 59 | perror ("tcsetattr"); 60 | exit (1); 61 | } 62 | static const int rate = 250000; 63 | 64 | if (ioctl(uartfd, TCGETS2, &tio) < 0) { 65 | perror ("tcgets2"); 66 | exit (1); 67 | } 68 | 69 | tio.c_cflag &= ~CBAUD; 70 | tio.c_cflag |= BOTHER; 71 | tio.c_ispeed = rate; 72 | tio.c_ospeed = rate; // set custom speed directly 73 | if (ioctl(uartfd, TCSETS2, &tio) < 0) { 74 | perror ("tcsets2"); 75 | exit (1); 76 | } 77 | 78 | while (1) { 79 | if (ioctl(uartfd, TIOCSBRK, NULL) < 0) { 80 | perror ("TIOCCBRK"); 81 | exit (1); 82 | } 83 | usleep (100); 84 | if (ioctl(uartfd, TIOCCBRK, NULL) < 0) { 85 | perror ("TIOCSBRK"); 86 | exit (1); 87 | } 88 | usleep (10); 89 | if (write (uartfd, data, 0x200) < 0) { 90 | perror ("write"); 91 | exit (1); 92 | } 93 | usleep (25000); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /bw_dmx/makechar.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | int main (int argc,char **argv) 7 | { 8 | long i,ch; 9 | 10 | for (i=1;i 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main (int argc, char **argv) 11 | { 12 | char *thefile; 13 | unsigned char *data, tdata[0x200]; 14 | int i, infd; 15 | 16 | if (argc > 1) 17 | thefile = argv[1]; 18 | else 19 | thefile = "dmxdata"; 20 | 21 | infd = open (thefile, O_RDWR); 22 | if (infd < 0) { 23 | perror (thefile); 24 | exit (1); 25 | } 26 | 27 | data = mmap (NULL, 0x201, PROT_READ | PROT_WRITE, MAP_SHARED, infd, 0); 28 | // printf ("data=%p.\n", data); 29 | //dmxmode = DMX_TX; 30 | while (1) { 31 | if (memcmp (data, tdata, 0x200) != 0) { 32 | // the first byte should be zero indicating "DMX transfer". 33 | // The DMX data starts at offset 1. 34 | for (i=1;i<512;i++) 35 | printf ("%d,", data[i]); 36 | printf ("%d\n", data[i]); 37 | fflush (stdout); 38 | memcpy (tdata, data, 0x200); 39 | } 40 | usleep (10000); 41 | } 42 | exit (0); 43 | } 44 | -------------------------------------------------------------------------------- /bw_dmx/set_output.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | 13 | static char *thefile = "dmxfile"; 14 | static int offset = 1; 15 | enum dsize_t {DS_SHORT, DS_BYTE, DS_WORD} dsize; 16 | 17 | static int dlen[] = {2,1,4}; 18 | 19 | static void pabort(const char *s) 20 | { 21 | perror(s); 22 | exit(1); 23 | } 24 | 25 | static const struct option lopts[] = { 26 | 27 | // SPI options. 28 | { "file", 1, 0, 'f' }, 29 | { "offset", 1, 0, 'o' }, 30 | { "short", 0, 0, 's' }, 31 | { "byte", 0, 0, 'b' }, 32 | { "word", 0, 0, 'w' }, 33 | }; 34 | 35 | 36 | static int parse_opts(int argc, char *argv[]) 37 | { 38 | // int r; 39 | int c; 40 | 41 | while (1) { 42 | 43 | c = getopt_long(argc, argv, "f:o:sbw", lopts, NULL); 44 | 45 | if (c == -1) 46 | break; 47 | 48 | switch (c) { 49 | case 'f':thefile=strdup (optarg);break; 50 | case 'o':offset = atoi (optarg);break; 51 | case 's':dsize = DS_SHORT;break; 52 | case 'b':dsize = DS_BYTE;break; 53 | case 'w':dsize = DS_WORD;break; 54 | } 55 | } 56 | return optind; 57 | } 58 | 59 | 60 | int main (int argc, char **argv) 61 | { 62 | int nonoptions, i , v, infd; 63 | char *data; 64 | 65 | nonoptions = parse_opts(argc, argv); 66 | 67 | infd = open(thefile, O_RDWR); 68 | if (infd < 0) 69 | pabort("can't open dxmfile"); 70 | 71 | infd = open (thefile, O_RDWR); 72 | if (infd < 0) { 73 | perror (thefile); 74 | exit (1); 75 | } 76 | data = mmap (NULL, 0x201, PROT_READ | PROT_WRITE, MAP_SHARED, infd, 0); 77 | 78 | if (!data) pabort ("mmap"); 79 | 80 | for (i=nonoptions;i 12 | * Copyright (c) 2012-2013 Roger Wolff 13 | * 14 | * This program is free software; you can redistribute it and/or modify 15 | * it under the terms of the GNU General Public License as published by 16 | * the Free Software Foundation; version 2 of the License. 17 | * 18 | * Cross-compile with cross-gcc -I/path/to/cross-kernel/include 19 | * 20 | * Compile on raspberry pi with 21 | * 22 | * gcc -Wall -O2 bw_tool.c -o bw_tool 23 | * 24 | * or with the included Makefile (type "make"). 25 | */ 26 | 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include 42 | #include 43 | #include 44 | 45 | 46 | #include "usb_protocol.h" 47 | 48 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) 49 | 50 | 51 | enum {MODE_NONE = -1, SPI_MODE = 1, I2C_MODE, USB_I2CMODE, USB_SPIMODE }; 52 | static int mode = MODE_NONE; 53 | 54 | static const char *device = NULL; // = "/dev/spidev0.0"; 55 | static uint8_t spi_mode; 56 | static uint8_t bits = 8; 57 | 58 | static uint32_t speed = 100000; 59 | #define MAX_READ_SPEED 100000 60 | 61 | static uint16_t delay = 20; 62 | static int addr = 0x82; 63 | static int text = 0; 64 | static char *monitor_file; 65 | static int readmode = 0; 66 | static int xtendedvalidation = 0, valid=1; 67 | 68 | static int rs485_lid = 0, rs485_rid = -1; 69 | 70 | static int reg = -1; 71 | static long long val = -1; 72 | static int cls = 0; 73 | static int write8mode, writemiscmode, ident, readee; 74 | static int scan = 0; 75 | static int hexmode = 0; 76 | static char numberformat = 'x'; 77 | static int mode2 = 0; 78 | static char tidfnamebuf[0x100], *tidfname; 79 | 80 | static int tid; // Transaction ID. Best if not recycled... (but wraps after 256). 81 | 82 | static int debug = 0; 83 | #define DEBUG_REGSETTING 0x0001 84 | #define DEBUG_TRANSFER 0x0002 85 | 86 | static void pabort(const char *s) 87 | { 88 | if (errno) 89 | perror(s); 90 | else 91 | fprintf (stderr, "%s.\n", s); 92 | exit(1); 93 | } 94 | 95 | void dump_buffer (unsigned char *buf, int n) 96 | { 97 | int i; 98 | for (i=0;i tlen) tr.len = rlen; 120 | // else tr.len = tlen; 121 | tr.len = tlen + rlen; 122 | tr.tx_buf = (unsigned long) buf; 123 | tr.rx_buf = (unsigned long) buf; 124 | 125 | ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); 126 | if (ret < 1) 127 | pabort("can't send spi message"); 128 | valid = buf[1] != 0; 129 | 130 | } 131 | 132 | 133 | static void i2c_txrx (int fd, unsigned char *buf, int tlen, int rlen) 134 | { 135 | static int slave = -1; 136 | 137 | if (buf[0] != slave) { 138 | if (ioctl(fd, I2C_SLAVE, buf[0] >> 1) < 0) 139 | pabort ("can't set slave addr"); 140 | slave = buf[0]; 141 | } 142 | if (write (fd, buf+1, tlen-1) != (tlen-1)) { 143 | pabort ("can't write i2c"); 144 | } 145 | //XXX: check return code. 146 | if (rlen) 147 | if (read (fd, buf+tlen, rlen) != rlen) 148 | pabort ("can't read i2c"); 149 | } 150 | 151 | 152 | 153 | int myread (int fd, unsigned char *buf, int len) 154 | { 155 | int nr, cr; 156 | 157 | nr = 0; 158 | while (nr < len) { 159 | cr = read (fd, buf+nr, len-nr); 160 | if (!cr) break; 161 | if (cr < 0) return nr?nr:cr; 162 | nr += cr; 163 | } 164 | return nr; 165 | } 166 | 167 | 168 | int myread_to (int fd, unsigned char *buf, int len, int to) 169 | { 170 | fd_set read_fds, write_fds, except_fds; 171 | int nr, cr, rv; 172 | struct timeval timeout; 173 | 174 | timeout.tv_sec = to / 1000000; 175 | timeout.tv_usec = to % 1000000; 176 | 177 | FD_ZERO(&read_fds); 178 | FD_ZERO(&write_fds); 179 | FD_ZERO(&except_fds); 180 | FD_SET(fd, &read_fds); 181 | 182 | nr = 0; 183 | while (nr < len) { 184 | // XXX we count on timeout being modified. Linux is documented to 185 | // do this, others usually don't. 186 | rv = select(fd + 1, &read_fds, &write_fds, &except_fds, &timeout); 187 | if (rv > 0) { 188 | if (FD_ISSET (fd, &read_fds)) { 189 | cr = read (fd, buf+nr, len-nr); 190 | if (!cr) break; // handle EOF. 191 | if (cr < 0) return nr?nr:cr; 192 | nr += cr; 193 | } 194 | } else if (rv == 0) { 195 | // timeout. 196 | return nr; 197 | } else { 198 | // error. 199 | return nr?nr:-1; 200 | } 201 | } 202 | return nr; 203 | } 204 | 205 | 206 | 207 | static void usb_spitxrx (int fd, unsigned char *buf, int tlen, int rlen) 208 | { 209 | int hdrlen; 210 | // static int slave = -1; 211 | static char cmd[] = { BINSTART, 212 | USB_CMD_FWD, 0 /*Local ID */, 0 /* Len */, 213 | USB_CMD_SPI_TXRX, 0 /* ID */, 0 /* Len */ }; 214 | 215 | if (rs485_rid == -1) { 216 | // Local 217 | cmd[1] = USB_CMD_SPI_TXRX; 218 | cmd[2] = rs485_lid; 219 | cmd[3] = tlen + rlen; 220 | hdrlen = 4; 221 | } else { 222 | cmd[1] = USB_CMD_FWD; 223 | cmd[2] = rs485_lid; 224 | cmd[3] = tlen + rlen + 3; 225 | cmd[4] = USB_CMD_SPI_TXRX; 226 | cmd[5] = rs485_rid; 227 | cmd[6] = tlen + rlen; 228 | hdrlen = 7; 229 | } 230 | 231 | if (write (fd, cmd, hdrlen) != hdrlen) { 232 | pabort ("can't write USB cmd"); 233 | } 234 | if (write (fd, buf, tlen+rlen) != tlen+rlen) { 235 | pabort ("can't write USB buf"); 236 | } 237 | 238 | //XXX: check return code. 239 | if (myread_to (fd, buf, 4, 1000000) != 4) { 240 | pabort ("can't read USB"); 241 | } 242 | 243 | if (buf[0] != BINSTART) 244 | pabort ("invalid binstart code from USB"); 245 | 246 | if (buf[1] != (USB_CMD_SPI_TXRX | USB_RESPONSE)) 247 | pabort ("invalid response code from USB"); 248 | 249 | if (buf[3] != tlen+rlen) { 250 | printf ("got %d instead of %d: ", buf[3], tlen+rlen); 251 | pabort ("invalid length code from USB"); 252 | } 253 | if (myread_to (fd, buf, tlen+rlen, 1000000) != tlen+rlen) 254 | pabort ("can't read USB"); 255 | } 256 | 257 | 258 | static void usb_i2ctxrx (int fd, unsigned char *buf, int tlen, int rlen) 259 | { 260 | // static int slave = -1; 261 | static char cmd[] = {1, 2, 0,0 }; 262 | 263 | cmd[1] = 2; // I2C txrx 264 | cmd[2] = tlen+1; 265 | cmd[3] = rlen; 266 | 267 | if (write (fd, cmd, 4) != 4) { 268 | pabort ("can't write USB cmd"); 269 | } 270 | if (write (fd, buf, tlen) != tlen) { 271 | pabort ("can't write USB buf"); 272 | } 273 | 274 | if (myread (fd, buf, 3) != 3) { 275 | pabort ("can't read USB"); 276 | } 277 | 278 | // printf ("buf[] = %02x %02x %02x\n", buf[0], buf[1], buf[2]); 279 | 280 | if (buf[0] != 0x82) 281 | pabort ("invalid response code from USB"); 282 | 283 | if (buf[1] != rlen+1) 284 | pabort ("i2c rlen incorrect"); 285 | 286 | if (buf[2] != 0) 287 | pabort ("i2c transaction failed"); 288 | 289 | if (myread (fd, buf+tlen, rlen) != rlen) 290 | pabort ("can't read USB"); 291 | } 292 | 293 | 294 | #define CRC16 0x8005 295 | 296 | 297 | uint16_t crc16 (uint16_t crc, unsigned char *data, int size) 298 | { 299 | int i; 300 | unsigned char c; 301 | 302 | /* Sanity check: */ 303 | if(data == NULL) 304 | return 0; 305 | 306 | while(size > 0) { 307 | c = *data++; 308 | size--; 309 | for (i=0;i<8;i++) { 310 | /* the shift part*/ 311 | if (crc & 0x8000) 312 | crc = (crc << 1) ^ CRC16; /* the feedback part: */ 313 | else 314 | crc = (crc << 1); 315 | 316 | crc ^= c & 1; // get next bit. 317 | c >>= 1; 318 | } 319 | } 320 | return crc; 321 | } 322 | 323 | 324 | static void transfer(int fd, unsigned char *buf, int tlen, int rlen) 325 | { 326 | if (debug & DEBUG_TRANSFER) 327 | dump_buf ("tx", buf, tlen); 328 | if (mode == SPI_MODE) 329 | spi_txrx (fd, buf, tlen, rlen); 330 | else if (mode == I2C_MODE) 331 | i2c_txrx (fd, buf, tlen, rlen); 332 | else if (mode == USB_SPIMODE) 333 | usb_spitxrx (fd, buf, tlen, rlen); 334 | else if (mode == USB_I2CMODE) 335 | usb_i2ctxrx (fd, buf, tlen, rlen); 336 | else 337 | pabort ("invalid mode...\n"); 338 | 339 | if (debug & DEBUG_TRANSFER) 340 | dump_buf ("rx", buf, tlen+rlen); 341 | } 342 | 343 | 344 | static void send_text (int fd, unsigned char *str) 345 | { 346 | unsigned char *buf; 347 | int l; 348 | 349 | l = strlen ((char*)str); 350 | buf = malloc (l + 5); 351 | buf[0] = addr; 352 | if (reg <= 0) 353 | buf [1] = 0; 354 | else { 355 | buf [1] = reg; 356 | l++; 357 | } 358 | strcpy ((char *)buf+2, (char*)str); 359 | strcat ((char *)buf+2, "\xff\0"); // always append the 0xff, but it won't be sent if reg = 0; 360 | transfer (fd, buf, l+2, 0); 361 | free (buf); 362 | } 363 | 364 | 365 | static void set_reg_value8 (int fd, int reg, int val) 366 | { 367 | unsigned char buf[5]; 368 | 369 | buf[0] = addr; 370 | buf[1] = reg; 371 | buf[2] = val; 372 | transfer (fd, buf, 3, 0); 373 | } 374 | 375 | 376 | 377 | static void set_reg_value16 (int fd, int reg, int val) 378 | { 379 | unsigned char buf[5]; 380 | 381 | buf[0] = addr; 382 | buf[1] = reg; 383 | buf[2] = val; 384 | buf[3] = val >> 8; 385 | transfer (fd, buf, 4, 0); 386 | } 387 | 388 | static void set_reg_value32 (int fd, int reg, int val) 389 | { 390 | unsigned char buf[15]; 391 | 392 | buf[0] = addr; 393 | buf[1] = reg; 394 | buf[2] = val; 395 | buf[3] = val >> 8; 396 | buf[4] = val >> 16; 397 | buf[5] = val >> 24; 398 | transfer (fd, buf, 6, 0); 399 | } 400 | 401 | 402 | static void set_reg_value64 (int fd, int reg, long long val) 403 | { 404 | unsigned char buf[15]; 405 | 406 | buf[0] = addr; 407 | buf[1] = reg; 408 | buf[2] = val; 409 | buf[3] = val >> 8; 410 | buf[4] = val >> 16; 411 | buf[5] = val >> 24; 412 | buf[6] = val >> 32; 413 | buf[7] = val >> 40; 414 | buf[8] = val >> 48; 415 | buf[9] = val >> 56; 416 | transfer (fd, buf, 10, 0); 417 | } 418 | 419 | 420 | static unsigned int get_reg_value8 (int fd, int reg) 421 | { 422 | unsigned char buf[5]; 423 | 424 | buf[0] = addr | 1; 425 | buf[1] = reg; 426 | transfer (fd, buf, 2, 1); 427 | //dump_buffer (buf, 5); 428 | return buf[2]; 429 | } 430 | 431 | 432 | static unsigned int get_reg_value16 (int fd, int reg) 433 | { 434 | unsigned char buf[5]; 435 | 436 | buf[0] = addr | 1; 437 | buf[1] = reg; 438 | transfer (fd, buf, 2, 2); 439 | //dump_buffer (buf, 5); 440 | return buf[2] | (buf[3] << 8); 441 | } 442 | 443 | 444 | static unsigned int get_reg_value32 (int fd, int reg) 445 | { 446 | unsigned char buf[10]; 447 | 448 | buf[0] = addr | 1; 449 | buf[1] = reg; 450 | transfer (fd, buf, 2, 4); 451 | //dump_buffer (buf, 5); 452 | return buf[2] | (buf[3] << 8) | (buf[4] << 16) | (buf[5] << 24); 453 | } 454 | 455 | static long long get_reg_value64 (int fd, int reg) 456 | { 457 | unsigned char buf[10]; 458 | unsigned int t, tt; 459 | 460 | buf[0] = addr | 1; 461 | buf[1] = reg; 462 | transfer (fd, buf, 2, 8); 463 | t = buf[2] | (buf[3] << 8) | (buf[4] << 16) | (buf[5] << 24); 464 | tt = buf[6] | (buf[7] << 8) | (buf[8] << 16) | (buf[9] << 24); 465 | return ((long long) tt << 32) | t; 466 | } 467 | 468 | static void do_readee (int fd) 469 | { 470 | #define EELEN 0x80 471 | unsigned char buf[EELEN]; 472 | int i; 473 | 474 | buf [0] = addr | 1; 475 | buf [1] = 2; 476 | 477 | transfer (fd, buf, 0x2, 0x80); 478 | 479 | for (i = 0;i < EELEN;i++) { 480 | if (!(i & 0xf)) printf ("\n%04x: ", i); 481 | printf ("%02x ", ((unsigned char *) buf)[i+2]); 482 | 483 | } 484 | printf ("\n"); 485 | } 486 | 487 | 488 | 489 | 490 | unsigned long long get_value (unsigned char *buf, int len) 491 | { 492 | if (len == 1) 493 | return *buf; 494 | if (len == 2) 495 | return get_value (buf, 1) | get_value (buf+1, 1) << 8; 496 | if (len == 4) 497 | return get_value (buf, 2) | get_value (buf+2, 2) << 16; 498 | if (len == 8) 499 | return get_value (buf, 4) | get_value (buf+4, 4) << 32; 500 | return *buf; 501 | } 502 | 503 | 504 | #define FLAG_ADDR 1 505 | #define FLAG_ERR 2 506 | #define FLAG_DBG 4 507 | #define FLAG_RETRIES 8 508 | 509 | static void do_ident (int fd, int a, int flags) 510 | { 511 | unsigned char buf[0x20]; 512 | int i; 513 | int bp, crc; 514 | 515 | 516 | #define IDLEN 0x18 517 | if (mode2) { 518 | //flags |= FLAG_DBG; 519 | //usleep (200); 520 | bp = 0; 521 | buf [bp++] = a; 522 | buf [bp++] = 0xc1; 523 | buf [bp++] = tid; 524 | buf [bp++] = IDLEN; 525 | buf [bp++] = 1; 526 | crc = crc16 (0, buf, bp); 527 | buf [bp++] = crc; 528 | buf [bp++] = crc >> 8; 529 | //if (flags & FLAG_DBG) if (debug & DEBUG_TRANSFER) dump_buf ("D: ident before TX: ", buf, bp); 530 | 531 | transfer (fd, buf, bp,0); 532 | usleep (700); 533 | buf[0] = a | 1; 534 | transfer (fd, buf, IDLEN+7,0); 535 | //if (flags & FLAG_DBG) if (debug & DEBUG_TRANSFER) dump_buf ("nD: ident got:", buf, IDLEN+7); 536 | 537 | //printf ("D:<%02x>\n", a);fflush (stdout); 538 | 539 | if (buf [1] != a) { 540 | //printf ("xx");fflush (stdout); 541 | if (flags & FLAG_ERR) 542 | printf ("E: ident: Didn't get addr back: %02x\n", buf[1]); 543 | return; 544 | } 545 | //printf ("yy");fflush (stdout); 546 | if (buf [2] != 0xaa) { 547 | //printf ("zz");fflush (stdout); 548 | if (flags & FLAG_ERR) 549 | printf ("E: ident: Didn't get read ack: %02x\n", buf[2]); 550 | return; 551 | } 552 | //printf ("aa");fflush (stdout); 553 | 554 | if (buf [3] != (tid & 0xff)) { 555 | //printf ("bb");fflush (stdout); 556 | if (flags & FLAG_ERR) 557 | printf ("E: ident: Didn't get tid: %02x/%02x\n", buf[2], tid &0xff); 558 | return; 559 | } 560 | //printf ("cc");fflush (stdout); 561 | 562 | crc = crc16 (0, buf+1, IDLEN+3); 563 | if (get_value (buf+IDLEN+4, 2) != crc) { 564 | //printf ("dd");fflush (stdout); 565 | if (flags & FLAG_ERR) 566 | printf ("E: ident: invalid CRC: %04llx/%04x\n", 567 | get_value (buf+IDLEN+3, 2), crc); 568 | return; 569 | } 570 | i = 4; 571 | //printf ("ee");fflush (stdout); 572 | //printf ("D: ident got: "); 573 | //dump_buffer (buf, IDLEN+7); 574 | //printf ("\n"); 575 | 576 | if (flags & FLAG_ADDR) 577 | printf ("%02x: ", a); 578 | 579 | } else { 580 | buf [0] = addr | 1; 581 | buf [1] = 1; 582 | 583 | transfer (fd, buf, 0x2,0x20); 584 | i = 2; 585 | } 586 | 587 | for ( ;i<0x20;i++) { 588 | if (!buf[i]) break; 589 | printf ("%c", buf[i]); 590 | //putchar (buf[i]); 591 | } 592 | printf ("\n"); 593 | //putchar ('\n'); 594 | fflush (stdout); 595 | } 596 | 597 | 598 | 599 | char mkprintable (char ch) 600 | { 601 | if (ch < ' ') return '.'; 602 | if (ch <= '~') return ch; 603 | return '.'; 604 | } 605 | 606 | 607 | static void do_scan (int fd) 608 | { 609 | unsigned char buf[0x20]; 610 | int add; 611 | int i; 612 | 613 | if (mode2) { 614 | //printf ("Scanning.\n"); 615 | for (add = 0;add < 255;add += 2) { 616 | //printf ("scan %d starting.\n", add); 617 | do_ident (fd, add, FLAG_ADDR); 618 | //printf ("scan %d done. \n", add); 619 | } 620 | return; 621 | } 622 | 623 | 624 | for (add = 0;add < 255;add += 2) { 625 | buf[0] = add | 1; 626 | buf[1] = 1; 627 | transfer (fd, buf, 0x2, 0x20); 628 | for (i=(mode==I2C_MODE)?0:2;i<0x20;i++) { 629 | if (mkprintable (buf[i]) != '.') break; 630 | } 631 | if (i != 0x20) { 632 | printf ("%02x: ", add); 633 | for (i=(mode==I2C_MODE)?0:2;i<0x20;i++) { 634 | if (buf[i] == 0) break; 635 | putchar (mkprintable (buf[i])); 636 | } 637 | printf ("\n"); 638 | } 639 | } 640 | 641 | } 642 | 643 | 644 | 645 | static void print_usage(const char *prog) 646 | { 647 | printf("Usage: %s [-DsbdlHOLC3]\n", prog); 648 | puts(" -D --device device to use (default /dev/spidev1.1)\n" 649 | " -s --speed max speed (Hz)\n" 650 | " -d --delay delay (usec)\n" 651 | " -r --reg \n" 652 | " -v --val value\n" 653 | " -a --addr address\n" 654 | " -w --write8 write an octet\n" 655 | " -W --write write arbitrary type\n" 656 | " -i --identify Identify the indicated device\n" 657 | " -S --scan Scan the bus for devices \n" 658 | " -R --read multi-datasize read\n" 659 | " -I --i2c I2C mode (uses /dev/i2c-0, change with -D)\n" 660 | " -U --usb USB mode (uses /dev/ttyACM0, change with -D)\n" 661 | " -1 --decimal Numbers are decimal. (registers remain in hex)\n" 662 | ); 663 | 664 | exit(1); 665 | } 666 | 667 | static const struct option lopts[] = { 668 | 669 | // SPI options. 670 | { "device", 1, 0, 'D' }, 671 | { "speed", 1, 0, 's' }, 672 | { "delay", 1, 0, 'd' }, 673 | { "xtend", 0, 0, 'x' }, 674 | 675 | { "mode2", 0, 0, '2' }, 676 | { "tidfile", 1, 0, 'T' }, 677 | 678 | { "reg", 1, 0, 'r' }, 679 | { "val", 1, 0, 'v' }, 680 | { "addr", 1, 0, 'a' }, 681 | { "write8", 0, 0, 'w' }, 682 | { "write", 0, 0, 'W' }, 683 | { "identify", 0, 0, 'i' }, 684 | { "scan", 0, 0, 'S' }, 685 | { "read", 0, 0, 'R' }, 686 | { "eeprom", 0, 0, 'e' }, 687 | 688 | 689 | 690 | // Options for LCD 691 | { "text", 0, 0, 't' }, 692 | { "cls", 0, 0, 'C' }, 693 | { "monitor", 1, 0, 'm' }, 694 | 695 | { "hex", 0, 0, 'h' }, 696 | 697 | { "i2c", 0, 0, 'I' }, 698 | { "usbspi", 0, 0, 'u' }, 699 | { "usbi2c", 0, 0, 'U' }, 700 | { "decimal", 0, 0, '1' }, 701 | 702 | { "rs485_ids", 1, 0, '4' }, 703 | 704 | { "verbose", 1, 0, 'V' }, 705 | { "help", 0, 0, '?' }, 706 | { NULL, 0, 0, 0 }, 707 | }; 708 | 709 | 710 | 711 | static int parse_opts(int argc, char *argv[]) 712 | { 713 | int r; 714 | 715 | while (1) { 716 | int c; 717 | 718 | c = getopt_long(argc, argv, "D:s:d:r:v:a:wWietxCm:I1SRUu4:V:2", lopts, NULL); 719 | 720 | if (c == -1) 721 | break; 722 | 723 | switch (c) { 724 | case 'D': 725 | device = strdup (optarg); 726 | if (mode == MODE_NONE) { 727 | if (strstr (device, "i2c")) mode=I2C_MODE; 728 | else mode=SPI_MODE; 729 | } 730 | break; 731 | case 's': 732 | speed = atoi(optarg); 733 | break; 734 | case 'd': 735 | delay = atoi(optarg); 736 | break; 737 | case 'r': 738 | reg = atoi(optarg); 739 | break; 740 | case 'v': 741 | val = atoi(optarg); 742 | break; 743 | case 'V': 744 | debug = atoi(optarg); 745 | break; 746 | case 'a': 747 | sscanf (optarg, "%x", &addr); 748 | break; 749 | 750 | case 'e': 751 | readee = 1; 752 | break; 753 | case 'h': 754 | hexmode = 1; 755 | break; 756 | case 'w': 757 | write8mode = 1; 758 | break; 759 | case 'W': 760 | writemiscmode = 1; 761 | break; 762 | case 'R': 763 | if (speed > MAX_READ_SPEED) speed = MAX_READ_SPEED; 764 | readmode = 1; 765 | break; 766 | case 'i': 767 | if (speed > MAX_READ_SPEED) speed = MAX_READ_SPEED; 768 | ident = 1; 769 | break; 770 | case 'I': 771 | mode=I2C_MODE; 772 | if (!device) 773 | device = "/dev/i2c-0"; 774 | break; 775 | case 'S': 776 | if (speed > MAX_READ_SPEED) speed = MAX_READ_SPEED; 777 | scan=1; 778 | break; 779 | case 't': 780 | text = 1; 781 | break; 782 | 783 | case 'x': 784 | xtendedvalidation = 1; 785 | break; 786 | 787 | case 'C': 788 | cls = 1; 789 | break; 790 | 791 | case '1': 792 | numberformat = 'd'; 793 | break; 794 | 795 | case 'm': 796 | monitor_file = strdup (optarg); 797 | break; 798 | 799 | case 'u': 800 | mode = USB_SPIMODE; 801 | if (!device) 802 | device = "/dev/ttyACM0"; 803 | break; 804 | case 'T': 805 | tidfname = strdup (optarg); 806 | break; 807 | case '2': 808 | mode2 = 1; 809 | break; 810 | case '4': 811 | r = sscanf (optarg, "%d:%d", &rs485_lid, &rs485_rid); 812 | if (r == 0) { 813 | fprintf (stderr, "no RS485ID found\n"); 814 | exit (1); 815 | } 816 | break; 817 | case 'U': 818 | mode = USB_I2CMODE; 819 | if (!device) 820 | device = "/dev/ttyACM0"; 821 | break; 822 | 823 | case '?': 824 | print_usage (argv[0]); 825 | exit (0); 826 | break; 827 | 828 | default: 829 | print_usage(argv[0]); 830 | break; 831 | } 832 | } 833 | 834 | if (!device) 835 | device = "/dev/spidev0.0"; 836 | 837 | if (mode == MODE_NONE) 838 | mode = SPI_MODE; 839 | 840 | return optind; 841 | } 842 | 843 | 844 | void setup_spi_mode (int fd) 845 | { 846 | int ret; 847 | /* 848 | * spi mode 849 | */ 850 | //printf ("setting spi mode. %d/%d\n", speed, spi_mode); 851 | ret = ioctl(fd, SPI_IOC_WR_MODE, &spi_mode); 852 | if (ret == -1) 853 | pabort("can't set spi mode"); 854 | 855 | ret = ioctl(fd, SPI_IOC_RD_MODE, &spi_mode); 856 | if (ret == -1) 857 | pabort("can't get spi mode"); 858 | 859 | /* 860 | * bits per word 861 | */ 862 | ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); 863 | if (ret == -1) 864 | pabort("can't set bits per word"); 865 | 866 | ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits); 867 | if (ret == -1) 868 | pabort("can't get bits per word"); 869 | 870 | /* 871 | * max speed hz 872 | */ 873 | ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); 874 | if (ret == -1) 875 | pabort("can't set max speed hz"); 876 | 877 | ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed); 878 | if (ret == -1) 879 | pabort("can't get max speed hz"); 880 | 881 | //printf("spi mode: %d\n", spi_mode); 882 | //printf("bits per word: %d\n", bits); 883 | //printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000); 884 | } 885 | 886 | 887 | 888 | void wait_for_file_changed (char *fname) 889 | { 890 | static time_t lastmtime = 0; 891 | struct stat statb; 892 | 893 | while (1) { 894 | if (stat (fname, &statb) < 0) { 895 | pabort (fname); 896 | } 897 | 898 | if (lastmtime != statb.st_mtime) { 899 | //printf ("fc: %x / %x\n", (int) lastmtime, (int) statb.st_mtime); 900 | lastmtime = statb.st_mtime; 901 | return; 902 | } 903 | usleep (250000); 904 | } 905 | } 906 | 907 | 908 | unsigned char *get_file_line (char *fname, int lno) 909 | { 910 | static unsigned char buf[0x50], *p; 911 | FILE *f; 912 | int i; 913 | 914 | 915 | f = fopen (fname, "r"); 916 | if (!f) pabort (fname); 917 | for (i = 0;i<=lno;i++) { 918 | buf [0] = 0; 919 | p = (unsigned char*)fgets ((char*)buf, 0x3f, f); 920 | if (!p) return p; 921 | } 922 | 923 | fclose (f); 924 | buf[strlen((char*)buf)-1] = 0; // chop! 925 | return buf; 926 | } 927 | 928 | 929 | void do_monitor_file (int fd, char *fname) 930 | { 931 | int i; 932 | unsigned char *buf; 933 | char olddisplay[4][0x20]; 934 | 935 | //fprintf (stderr, "monitoring %s on fd %d.\n", fname, fd); 936 | while (1) { 937 | wait_for_file_changed (fname); 938 | //set_reg_value8 (fd, 0x10, 0xaa); 939 | for (i=0;i<4;i++) { 940 | buf = get_file_line (fname, i); 941 | if (!buf) break; 942 | while (strlen ((char*)buf) < 20) strcat ((char*)buf, " "); 943 | buf[20] = 0; 944 | if (strcmp ((char*)buf, olddisplay[i])) { 945 | strcpy (olddisplay[i], (char *)buf); 946 | set_reg_value8 (fd, 0x11, i<<5); 947 | send_text (fd, buf); 948 | usleep (50000); 949 | } 950 | } 951 | } 952 | } 953 | 954 | void setup_virtual_serial (int fd) 955 | { 956 | struct termios tio; 957 | 958 | memset (&tio, 0, sizeof (tio)); 959 | if (tcgetattr (fd, &tio) < 0) 960 | pabort ("TCGETS on device"); 961 | 962 | tio.c_lflag = 0; 963 | tio.c_oflag = 0; 964 | tio.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl 965 | 966 | tio.c_cflag |= (CLOCAL | CREAD); 967 | tio.c_cflag &= ~(PARENB | PARODD); 968 | if (tcsetattr (fd, TCSANOW, &tio) != 0) 969 | pabort ("TCSETS on devcie"); 970 | } 971 | 972 | void init_device (int fd) 973 | { 974 | //printf ("init device %d.\n", speed); 975 | switch (mode) { 976 | case SPI_MODE: 977 | setup_spi_mode (fd); 978 | break; 979 | case USB_SPIMODE: 980 | case USB_I2CMODE: 981 | setup_virtual_serial (fd); 982 | break; 983 | case I2C_MODE: 984 | // nothing special. 985 | break; 986 | } 987 | } 988 | 989 | int typelen (char typech) 990 | { 991 | 992 | switch (typech) { 993 | case 'b':return 1; 994 | case 's':return 2; 995 | case 'i':return 4; 996 | case 'l':return 8; 997 | default: 998 | fprintf (stderr, "Don't understand the type '%c'\n", typech); 999 | exit (1); 1000 | } 1001 | } 1002 | 1003 | char *formatstr (char typech) 1004 | { 1005 | if (numberformat != 'x') return "%lld"; 1006 | switch (typech) { 1007 | case 'b':return "%02llx "; 1008 | case 's':return "%04llx "; 1009 | case 'i':return "%08llx "; 1010 | case 'l':return "%016llx "; 1011 | } 1012 | return "%lld"; // should not happen. 1013 | } 1014 | 1015 | 1016 | int get_update_tid (void) 1017 | { 1018 | //char *tidp; 1019 | //char buf[32]; 1020 | int ltid; 1021 | FILE *fp; 1022 | 1023 | 1024 | fp = fopen (tidfname, "r"); 1025 | if (!fp || (fscanf (fp, "%d", <id) < 1)) { 1026 | srand (time (NULL)); 1027 | ltid = rand () & 0xff; 1028 | } 1029 | if (fp) fclose (fp); 1030 | 1031 | if (!tidfname) return ltid; 1032 | 1033 | fp = fopen (tidfname, "w"); 1034 | #if 1 1035 | if (!fp) { 1036 | fprintf (stderr, "Can't open %s", tidfname); 1037 | perror (""); 1038 | exit (1); 1039 | } 1040 | #endif 1041 | 1042 | fprintf (fp, "%d\n", ltid+1); 1043 | fclose (fp); 1044 | 1045 | return ltid; 1046 | } 1047 | 1048 | 1049 | 1050 | int main(int argc, char *argv[]) 1051 | { 1052 | int fd; 1053 | int nonoptions; 1054 | unsigned char buf[0x100]; 1055 | int i, rv; 1056 | char typech; 1057 | char format[32]; 1058 | unsigned char tbuf[0x100]; 1059 | int bp, crc, rlen; 1060 | int tries; 1061 | #define MAXTRIES 5 1062 | 1063 | if (argc <= 1) { 1064 | print_usage (argv[0]); 1065 | exit (0); 1066 | } 1067 | if (getenv ("HOME")) { 1068 | sprintf (tidfnamebuf, "%s/.tid", getenv ("HOME")); 1069 | tidfname = tidfnamebuf; 1070 | } else tidfname = NULL; 1071 | 1072 | nonoptions = parse_opts(argc, argv); 1073 | 1074 | if (write8mode && writemiscmode) { 1075 | fprintf (stderr, "Can't use write8 and write misc at the same time\n"); 1076 | exit (1); 1077 | } 1078 | 1079 | //fprintf (stderr, "dev = %s\n", device); 1080 | //fprintf (stderr, "mode = %d\n", mode); 1081 | fd = open(device, O_RDWR); 1082 | if (fd < 0) 1083 | pabort(device); 1084 | 1085 | init_device (fd); 1086 | 1087 | if (ident) 1088 | do_ident (fd, addr, FLAG_ERR | FLAG_DBG); 1089 | 1090 | if (readee) 1091 | do_readee (fd); 1092 | 1093 | if (cls) set_reg_value8 (fd, 0x10, 0xaa); 1094 | 1095 | if (write8mode) { 1096 | sprintf (format, "%%x:%%ll%c", numberformat); 1097 | for (i=nonoptions;i> 0) & 0xff; 1134 | tbuf[bp++] = (val >> 8) & 0xff; 1135 | break; 1136 | case 'i':tbuf[bp++] = 4;tbuf[bp++] = reg; 1137 | tbuf[bp++] = (val >> 0) & 0xff; 1138 | tbuf[bp++] = (val >> 8) & 0xff; 1139 | tbuf[bp++] = (val >> 16) & 0xff; 1140 | tbuf[bp++] = (val >> 24) & 0xff; 1141 | break; 1142 | case 'l':tbuf[bp++] = 8;tbuf[bp++] = reg; 1143 | tbuf[bp++] = (val >> 0) & 0xff; 1144 | tbuf[bp++] = (val >> 8) & 0xff; 1145 | tbuf[bp++] = (val >> 16) & 0xff; 1146 | tbuf[bp++] = (val >> 24) & 0xff; 1147 | tbuf[bp++] = (val >> 32) & 0xff; 1148 | tbuf[bp++] = (val >> 40) & 0xff; 1149 | tbuf[bp++] = (val >> 48) & 0xff; 1150 | tbuf[bp++] = (val >> 56) & 0xff; 1151 | break; 1152 | default: 1153 | fprintf (stderr, "Don't understand the type value in %s\n", argv[i]); 1154 | exit (1); 1155 | } 1156 | } else { 1157 | switch (typech) { 1158 | case 'b': set_reg_value8 (fd, reg, val);break; 1159 | case 's': set_reg_value16 (fd, reg, val);break; 1160 | case 'i': set_reg_value32 (fd, reg, val);break; 1161 | case 'l': set_reg_value64 (fd, reg, val);break; 1162 | default: 1163 | fprintf (stderr, "Don't understand the type value in %s\n", argv[i]); 1164 | exit (1); 1165 | } 1166 | } 1167 | } 1168 | if (mode2) { 1169 | crc = crc16 (0, tbuf, bp); 1170 | tbuf[bp++] = crc & 0xff; 1171 | tbuf[bp++] = crc >> 8; 1172 | //if (debug & DEBUG_TRANSFER) dump_buf ("D: m2: Before tx:", tbuf, bp); 1173 | 1174 | if (bp > 33) printf ("W: Transfer %d > 32 bytes. Target may not support this.\n", bp); 1175 | transfer (fd, tbuf, bp, 0); 1176 | 1177 | tries = 0; 1178 | do { 1179 | usleep (100); 1180 | tbuf[0] = addr+1; 1181 | transfer (fd, tbuf, 8,0); 1182 | } while ((tries++ < MAXTRIES) && (tbuf[2] == 0xbb)); 1183 | 1184 | if ((debug & FLAG_RETRIES) && (tries != 1)) 1185 | printf ("W: required %d tries.\n", tries); 1186 | 1187 | //if (debug & DEBUG_TRANSFER) dump_buf ("D: got: ", tbuf, 8); 1188 | if (tbuf[1] != addr) 1189 | printf ("E: Didn't return addr: %02x\n", tbuf[1]); 1190 | if (tbuf[3] != (tid & 0xff)) 1191 | printf ("E: Didn't get tid: %02x/%02x\n", tbuf[3], tid & 0xff); 1192 | if (tbuf[2] == 0xcc) { 1193 | crc = crc16 (0, tbuf+1, 3); 1194 | if (crc != get_value (tbuf+4, 2)) 1195 | printf ("E: Invalid checksum on write-ack: %04x/%04llx\n", crc, get_value(tbuf+4,2)); 1196 | // All ok. do nothing. 1197 | 1198 | } else if (tbuf[2] == 0xee) { 1199 | // XXX check checksum. 1200 | printf ("E: Got badCRC reply! slave expected: %02x%02x\n", tbuf[4], tbuf[3]); 1201 | } else { 1202 | printf ("E: got unexpected reply type: %02x\n", tbuf[2]); 1203 | } 1204 | } exit (0); 1205 | } 1206 | 1207 | if (readmode) { 1208 | if (mode2) { 1209 | bp = 0; 1210 | rlen = 0; 1211 | tbuf[bp++] = addr; 1212 | tbuf[bp++] = 0xc1; 1213 | tbuf[bp++] = tid; 1214 | for (i=nonoptions;i> 8; 1227 | 1228 | //if (debug & DEBUG_TRANSFER) dump_buf ("D: m2read: sending: ", tbuf, bp); 1229 | transfer (fd, tbuf, bp, 0); 1230 | 1231 | tries = 0; 1232 | do { 1233 | usleep (100); 1234 | tbuf[0] = addr+1; 1235 | transfer (fd, tbuf, rlen+6,0); 1236 | } while ((tries++ < MAXTRIES) && (tbuf[2] == 0xbb)); 1237 | 1238 | if ((debug & FLAG_RETRIES) && (tries != 1)) 1239 | printf ("W: required %d tries.\n", tries); 1240 | 1241 | if ((rlen+6) > 33) printf ("W: Transfer %d > 32 bytes. Target may not support this.\n", rlen+6); 1242 | 1243 | //printf ("rlen=%2d ", rlen); 1244 | // if (debug & DEBUG_TRANSFER) dump_buf ("D: got: ", tbuf, rlen+6); 1245 | 1246 | if (tbuf[1] != addr) 1247 | printf ("E: Didn't return addr: %02x\n", tbuf[1]); 1248 | if (tbuf[2] != 0xaa) 1249 | printf ("E: Didn't get ack response: %02x\n", tbuf[2]); 1250 | if (tbuf[3] != (tid & 0xff)) 1251 | printf ("E: Didn't get tid: %02x/%02x\n", tbuf[3], tid & 0xff); 1252 | 1253 | crc = crc16 (0, tbuf+1, rlen+3); // transferred rlen+6: address+data+crc 1254 | if ( get_value(tbuf+rlen+4, 2) != crc) { 1255 | printf ("E: bad crc: %04llx / %04x \n", get_value(tbuf+rlen+3, 2), crc); 1256 | } 1257 | bp=4; 1258 | for (i=nonoptions;i sudo gpio_list 37 | 0 INP INP INP INP INP INP OUT INP INP INP 38 | 10 INP INP INP INP ALT0 ALT0 OUT INP INP INP 39 | 20 INP INP INP INP INP INP INP INP INP INP 40 | 30 INP INP INP INP INP INP INP INP INP INP 41 | 40 ALT0 INP INP INP INP ALT0 INP INP ALT3 ALT3 42 | 50 ALT3 ALT3 ALT3 ALT3 INP 43 | raspberrypi:~/gpio> sudo gpio_setfunc 0 OUT 44 | raspberrypi:~/gpio> sudo gpio_setfunc 1 OUT 45 | raspberrypi:~/gpio> sudo gpio_set 1 46 | raspberrypi:~/gpio> sudo gpio_clr 1 47 | raspberrypi:~/gpio> sudo gpio_set 1 48 | raspberrypi:~/gpio> sudo gpio_clr 1 49 | raspberrypi:~/gpio> sudo gpio_setfunc 0 ALT0 50 | raspberrypi:~/gpio> sudo gpio_setfunc 1 ALT0 51 | 52 | 53 | First we list the current values for configuration of the GPIO pins. 54 | Then we make GPIO 0 and 1 outputs and toggle gpio 1 a couple of times. 55 | You should see the SCL line toggle if you have something connected with 56 | which to observe that. 57 | 58 | Next we configure those two outputs for ALT0 function: the I2C module 59 | (BSC in Broadcom language). 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /gpio/gpio_list.c: -------------------------------------------------------------------------------- 1 | // 2 | // How to access GPIO registers from C-code on the Raspberry-Pi 3 | // Example program 4 | // 15-January-2012 5 | // Dom and Gert 6 | // 7 | // Modified to provide a useable commandline userinterface 8 | // R.E.Wolff@BitWizard.nl 9 | // 18-04-2012. 10 | // 11 | 12 | // Access from ARM Running Linux 13 | 14 | 15 | // This is for the original "pi" 16 | #define BCM2708_PERI_BASE 0x20000000 17 | // This is for the new (as of late 2014/early 2015) "pi 2" (with BCM2836) 18 | //#define BCM2708_PERI_BASE 0x3F000000 19 | 20 | #define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */ 21 | 22 | 23 | #define BCM2835_NUMIOS 55 24 | 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #define PAGE_SIZE (4*1024) 34 | #define BLOCK_SIZE (4*1024) 35 | 36 | 37 | // I/O access 38 | volatile unsigned *gpio; 39 | 40 | 41 | #define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0 42 | #define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0 43 | 44 | 45 | int get_3b (int g) 46 | { 47 | return (gpio[g/10] >> ((g%10)*3)) & 7; 48 | } 49 | 50 | void set_3b (int g, int v) 51 | { 52 | gpio[g/10] = (gpio[g/10] & ~(7 << ((g%10)*3))) | 53 | ((v & 7) << ((g%10) *3)); 54 | } 55 | 56 | void gpio_set (int g) 57 | { 58 | gpio[7 + (g/32)] = 1 << (g %32); 59 | } 60 | 61 | void gpio_clr (int g) 62 | { 63 | gpio[10 + (g/32)] = 1 << (g %32); 64 | } 65 | 66 | int gpio_get (int g) 67 | { 68 | return (gpio[0xd + (g/32)] >> (g % 32)) & 1; 69 | } 70 | 71 | 72 | 73 | enum gpio_funcs {GP_INP, GP_OUT, GP_ALT5, GP_ALT4, 74 | GP_ALT0, GP_ALT1, GP_ALT2, GP_ALT3}; 75 | 76 | 77 | volatile unsigned * setup_io(); 78 | 79 | int main(int argc, char **argv) 80 | { 81 | int i; 82 | int g; 83 | 84 | char *gp_funcs[] = {"INP", "OUT", "ALT5", "ALT4", 85 | "ALT0", "ALT1", "ALT2", "ALT3"}; 86 | 87 | // Set up gpi pointer for direct register access 88 | gpio = setup_io(); 89 | 90 | if (strstr (argv[0], "list")) { 91 | for (i=0;i BCM2835_NUMIOS) { 100 | fprintf (stderr, "IO pin number out of range.\n"); 101 | exit (1); 102 | } 103 | if (strstr (argv[0], "setfunc")) { 104 | for (i=0;i<8;i++) if (strcmp (argv[2], gp_funcs[i]) == 0) break; 105 | if (i == 8) { 106 | printf ("Unknown function: %s\n", argv[2]); 107 | exit (1); 108 | } 109 | set_3b (g, i); 110 | } else if (strstr (argv[0], "set")) { 111 | gpio_set (g); 112 | } else if (strstr (argv[0], "clr")) { 113 | gpio_clr (g); 114 | } else if (strstr (argv[0], "get")) { 115 | printf ("%d\n", gpio_get (g)); 116 | } 117 | } 118 | return 0; 119 | 120 | } // main 121 | 122 | 123 | // 124 | // Set up a memory region to access GPIO 125 | // 126 | volatile unsigned int *setup_io() 127 | { 128 | int mem_fd; 129 | char *gpio_mem, *gpio_map; 130 | 131 | 132 | /* open /dev/mem */ 133 | if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) { 134 | printf("can't open /dev/mem \n"); 135 | exit (-1); 136 | } 137 | 138 | /* mmap GPIO */ 139 | 140 | // Allocate MAP block 141 | if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) { 142 | printf("allocation error \n"); 143 | exit (-1); 144 | } 145 | 146 | // Make sure pointer is on 4K boundary 147 | if ((unsigned long)gpio_mem % PAGE_SIZE) 148 | gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE); 149 | 150 | // Now map it 151 | gpio_map = mmap( 152 | (caddr_t)gpio_mem, 153 | BLOCK_SIZE, 154 | PROT_READ|PROT_WRITE, 155 | MAP_SHARED|MAP_FIXED, 156 | mem_fd, 157 | GPIO_BASE 158 | ); 159 | 160 | if ((long)gpio_map < 0) { 161 | printf("mmap error %ld\n", (long)gpio_map); 162 | exit (-1); 163 | } 164 | 165 | close (mem_fd); 166 | 167 | // Always use volatile pointer! 168 | return (volatile unsigned *)gpio_map; 169 | } // setup_io 170 | 171 | 172 | --------------------------------------------------------------------------------