/* * Dish/Arduino IR blaster. * * Copyright (c) 2009 Alex Williamson * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation, 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * For the complete license, please see http://www.fsf.org/licenses/gpl.txt * or request a copy from the author of this program. */ #include #include #include #include #include #include #include #include #include #include int serial_fd = -1; int num_codes[] = {17, 4, 5, 6, 8, 9, 10, 12, 13, 14}; int remotes[] = {0x000, 0x000, 0x200, 0x100, 0x300, 0x080, 0x280, 0x180, 0x380, 0x040, 0x240, 0x140, 0x340, 0x0c0, 0x2c0, 0x1c0, 0x3c0}; struct button_codes_t { char *name; int code; }; struct button_codes_t button_codes[] = { {"info", 0}, {"power_on", 1}, {"power", 2}, {"menu", 11}, {"select", 16}, {"cancel", 18}, {"guide", 20}, {"view", 22}, {"tv_vcr", 23}, {"right", 24}, {"up", 26}, {"recall", 27}, {"left", 28}, {"down", 30}, {"record", 31}, {"pause", 32}, {"stop", 33}, {"sys_info", 36}, {"asterisk", 37}, {"pound", 38}, {"power_off", 39}, {"sat", 41}, {"dish_home", 52}, {"sys_info2", 54}, {"dish_home2", 56}, {"dvr", 57}, {"skip_fwd", 55}, {"skip_back", 54}, {"fwd", 50}, {"play", 3}, {"back", 49}, {"dish", 52}, {"page_up", 15}, {"page_down", 7}, {NULL, -1} }; void serial_close(void) { flock(serial_fd, LOCK_UN); close(serial_fd); } int serial_init(char *port) { struct termios t; int locktries = 60; serial_fd = open(port, O_RDWR, O_NONBLOCK); if (serial_fd < 0) { perror("Failed to open serial port"); return -1; } while (locktries && flock(serial_fd, LOCK_EX | LOCK_NB) < 0) { locktries--; if (errno == EWOULDBLOCK) sleep(1); else locktries = 0; } if (!locktries) { perror("Cannot lock serial port"); close(serial_fd); return -1; } if (tcgetattr(serial_fd, &t) < 0) goto error; t.c_cflag |= CLOCAL; /* Ignore modem control lines */ if (tcsetattr(serial_fd, TCSANOW, &t) < 0) goto error; bzero(&t, sizeof(t)); t.c_iflag = IGNBRK|IGNPAR; t.c_cflag = CS8|CREAD|CLOCAL; t.c_cc[VMIN] = 1; if (cfsetispeed(&t, B115200) == -1) goto error; if (tcsetattr(serial_fd, TCSANOW, &t) == -1) goto error; return 0; error: serial_close(); return -1; } #define terminate_code() \ { \ if (repeat != -1) \ sprintf(buf + strlen(buf), "#%d", repeat); \ if (remote != -1) \ sprintf(buf + strlen(buf), "@%d", remote); \ if (delay != -1) \ sprintf(buf + strlen(buf), "d%d", delay); \ sprintf(buf + strlen(buf), "."); \ } void usage(char *func) { fprintf(stderr, "Usage %s -d " "[-# repeat] [-r remote] [-w delay(ms) ] \n", func); } int main(int argc, char *argv[]) { int i, j, opt, repeat = -1, remote = -1, delay = -1; char *port, buf[1024]; memset(buf, 0, sizeof(buf)); while ((opt = getopt(argc, argv, "d:#:r:w:")) != -1) { switch (opt) { case 'd': port = optarg; break; case '#': repeat = atoi(optarg); break; case 'r': remote = atoi(optarg); if (remote > 16 || remote < 0) { fprintf(stderr, "Invalid remote code\n"); return -1; } remote = remotes[remote]; break; case 'w': delay = atoi(optarg); break; default: usage(argv[0]); return -1; } } if (optind >= argc) { fprintf(stderr, "No command specidied\n"); usage(argv[0]); return -1; } if (serial_init(port) || serial_fd < 0) { fprintf(stderr, "Error opening device %s\n", port); usage(argv[0]); return -1; } while (optind < argc) { i = 0; while (isdigit(argv[optind][i])) { int code = num_codes[argv[optind][i++] - '0']; sprintf(buf + strlen(buf), "%d", code); terminate_code(); } for (i = 0; button_codes[i].name; i++) { if (!strncmp(argv[optind], button_codes[i].name, strlen(button_codes[i].name))) { sprintf(buf + strlen(buf), "%d", button_codes[i].code); terminate_code(); } } optind++; } for (i = 0; i < strlen(buf); i++) i += write(serial_fd, buf + i, strlen(buf + i)); serial_close(); return 0; }