/* * config file: * - i2c device * - i2c address * - email-address * - reporting config (when logging / mailing) * - thresholds for do shutdown * * parameters: * -d run as daemon * -f foreground * -v debug * -c [idle|charge|test|poweroff] command (not with -d) * --config * --help * * in command mode try to use daemon first (via unix-socket) * then fallback to i2c */ #include #include #include #include #include #include #include #include #include #include #include struct read_data { uint8_t sys_state; int16_t adc_current; int16_t adc_ubat; int16_t adc_uin; int16_t uin_loss; int16_t uin_restore; int16_t ubat_full; int16_t ubat_low; int16_t ubat_critical; int16_t ibat_full; uint16_t crc16; } __attribute__((__packed__)); struct write_data { uint8_t sys_state; int16_t uin_loss; int16_t uin_restore; int16_t ubat_full; int16_t ubat_low; int16_t ubat_critical; int16_t ibat_full; uint16_t crc16; } __attribute__((__packed__)); enum { STATE_IDLE = 0x01, STATE_TEST = 0x02, STATE_CHARGE = 0x04, STATE_DISCHARGE = 0x08, STATE_POWEROFF = 0x10, }; static char * state2str(uint8_t state) { switch (state) { case STATE_IDLE: return "STATE_IDLE"; case STATE_TEST: return "STATE_TEST"; case STATE_CHARGE: return "STATE_CHARGE"; case STATE_DISCHARGE: return "STATE_DISCHARGE"; case STATE_POWEROFF: return "STATE_POWEROFF"; default: return ""; } } static int i2c_open(const char *path) { int fd = open(path, O_RDWR); if (fd < 0) { perror("open()"); return -1; } unsigned long funcs; if (ioctl(fd, I2C_FUNCS, &funcs)) { perror("ioctl(I2C_FUNCS)"); close(fd); return -1; } if (!(funcs & I2C_FUNC_I2C)) { fprintf(stderr, "I2C_FUNC_I2C not supported!\n"); close(fd); return -1; } return fd; } static int i2c_setaddress(int fd, int address) { if (ioctl(fd, I2C_SLAVE, address) < 0) { perror("ioctl(I2C_SLAVE)"); close(fd); return -1; } return 0; } int main(int argc, char *argv[]) { int fd = i2c_open("/dev/i2c-0"); if (fd < 0) exit(-1); if (i2c_setaddress(fd, 0x10) < 0) exit(-1); int cnt = 0; while (1) { struct read_data rdbuf; memset(&rdbuf, 0, sizeof(rdbuf)); int ret = read(fd, &rdbuf, sizeof(rdbuf)); if (ret <= 0) perror("read()"); printf("state:0x%02x I:%5dmA Ubat:%5dmV Usup:%5dmV (%s) [%5d,%5d,%5d,%5d,%5d,%5d,0x%04x]\n", rdbuf.sys_state, rdbuf.adc_current, rdbuf.adc_ubat, rdbuf.adc_uin, state2str(rdbuf.sys_state), rdbuf.uin_loss, rdbuf.uin_restore, rdbuf.ubat_full, rdbuf.ubat_low, rdbuf.ubat_critical, rdbuf.ibat_full, rdbuf.crc16); sleep(1); cnt++; if (cnt == 5) { struct write_data wrbuf = { .sys_state = STATE_CHARGE, .uin_loss = 12000, .uin_restore = 14000, .ubat_full = 13300, .ubat_low = 12000, .ubat_critical = 10800, .ibat_full = 150, .crc16 = 0x0000, }; // write (fd, &wrbuf, sizeof(wrbuf)); write (fd, &wrbuf, 1); } } close(fd); return 0; }