/* powercontrol -- A program to control a PCF8574 over I2C Copyright (C) 2005 Michael Hanselmann This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #define DEFAULT_I2C_DEV "/dev/i2c-0" #define DEFAULT_I2C_ADDRESS 32 #define RESET_PORT 0 #define POWER_PORT 1 #define PRINT_BIT(x) { \ for(int _s = 0; _s < (8 * sizeof((x))); ++_s) { \ printf(" %2d:%d%s", _s, ((x) & (1 << _s))?1:0, ((_s+1)%8?"":"\n")); \ }; puts(""); } typedef unsigned char bool; static int opt_verbose = 0; /* Read up to maxlen chars into result, stops at newline */ size_t read_line(char* result, size_t maxlen) { size_t len = 0; do { int c = getchar(); if(c == '\n' || c == '\r' || c == EOF) { break; }else{ result[len] = c; len++; result[len] = '\0'; } } while(len < maxlen); fflush(stdin); return len; } /* Requires the user to enter either "yes" or "no" */ bool ask_for_yes(const char* prompt) { for(;;) { printf("%s (yes/no) ", prompt); char answer[4]; size_t l = read_line(answer, sizeof(answer)); if(l) { if(!strncasecmp(answer, "yes", 3)) { return 1; }else if(!strncasecmp(answer, "no", 2)) { return 0; } } } } /* What? You don't know to use this program? Eat this! */ void usage(const char* progname) { fprintf(stderr, "Usage: %s [-f] [-r|-p]\n", progname); fprintf(stderr, " --force Force\n" " -r, --reset Reset\n" " -p, --power Power switch for n seconds\n" " -c, --powercycle Powercycle\n"); } /* Opens the I2C device and returns the file descriptor */ int open_i2c() { int fd = open(DEFAULT_I2C_DEV, O_RDWR); if(fd < 0) { perror(DEFAULT_I2C_DEV); exit(1); } int address = DEFAULT_I2C_ADDRESS; if(ioctl(fd, I2C_SLAVE, address) < 0) { perror("ioctl(I2C_SLAVE)"); close(fd); exit(1); } return fd; } /* Write one byte to a file descriptor */ int write_i2c(int fd, int value) { if(write(fd, &value, 1) < 0) { perror("write"); exit(1); } } /* Reads one byte from a file descriptor */ int read_i2c(int fd) { int value = 0; if(read(fd, &value, 1) < 0) { perror("read"); exit(1); } return value; } /* Changes one bit */ void set_i2c_bit(int fd, int bit, int on) { int value = read_i2c(fd); if(opt_verbose) { printf("read: %d\n", value); } if(!on) { value |= (1 << bit); }else{ value &= ~(1 << bit); } if(opt_verbose) { printf("write: %d\n", value); } write_i2c(fd, value); } /* Resets the computer on RESET_PORT */ void do_reset() { int fd = open_i2c(); puts("Setting reset high"); set_i2c_bit(fd, RESET_PORT, 1); usleep(1000000 / 4); puts("Setting reset low"); set_i2c_bit(fd, RESET_PORT, 0); close(fd); } /* Activate POWER_PORT for duration microseconds */ void do_power(int duration) { int fd = open_i2c(); puts("Setting power high"); set_i2c_bit(fd, POWER_PORT, 1); usleep(duration); puts("Setting power low"); set_i2c_bit(fd, POWER_PORT, 0); close(fd); } /* Power cycles the computer on POWER_PORT */ void do_powercycle() { int fd = open_i2c(); /* Power off */ do_power(1000000 * 6); /* Let the harddisks spin down */ puts("Sleep 10 seconds"); sleep(10); /* Power again */ do_power(1000000 / 2); close(fd); } int main(int argc, char* argv[]) { static struct option long_options[] = { { "force", 0, 0, 'f' }, { "verbose", 0, 0, 'v' }, { "power", 0, 0, 'p' }, { "powercycle", 0, 0, 'c' }, { "reset", 0, 0, 'r' }, { "help", 0, 0, 'h' }, { 0, 0, 0, 0 } }; int opt_force = 0, opt_powercycle = 0, opt_reset = 0, opt_power = 0; int c, actions = 0; if(argc < 2) { usage(argv[0]); return 1; } /* Parse options */ while((c = getopt_long(argc, argv, "crhvp:", long_options, NULL)) != -1) { switch(c) { case 'v': opt_verbose = 1; actions++; break; case 'r': opt_reset = 1; actions++; break; case 'c': opt_powercycle = 1; actions++; break; case 'p': opt_power = 1000000 * atof(optarg); actions++; break; case 'f': opt_force = 1; break; case 'h': default: usage(argv[0]); return 1; } } /* Do stuff */ if(actions > 1) { fprintf(stderr, "Can't do more than one thing at a time.\n"); return 1; }else if(opt_reset) { if(opt_force || ask_for_yes("Reset?")) { do_reset(); } }else if(opt_powercycle) { if(opt_force || ask_for_yes("Powercycle?")) { do_powercycle(); } }else if(opt_power) { if(opt_force || ask_for_yes("Switch the power?")) { do_power(opt_power); } } }