176 lines
3.0 KiB
C
176 lines
3.0 KiB
C
/*
|
|
* 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 <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
|
|
#include <linux/i2c.h>
|
|
#include <linux/i2c-dev.h>
|
|
|
|
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 "<UNKNOWN>";
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|