161 lines
2.8 KiB
C
161 lines
2.8 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 "i2c-dev.h"
|
|
|
|
enum {
|
|
REG_STATUS = 0x00,
|
|
|
|
REG_CURRENT = 0x10,
|
|
REG_UBAT = 0x11,
|
|
REG_UIN = 0x12,
|
|
|
|
REG_UIN_LOSS = 0x20,
|
|
REG_UIN_RESTORE = 0x21,
|
|
REG_UBAT_FULL = 0x22,
|
|
REG_UBAT_LOW = 0x23,
|
|
REG_UBAT_CRIT = 0x24,
|
|
REG_IBAT_FULL = 0x25,
|
|
REG_CRC = 0x26,
|
|
};
|
|
|
|
struct usv_data {
|
|
uint16_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;
|
|
};
|
|
|
|
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_SMBUS_WORD_DATA) != I2C_FUNC_SMBUS_WORD_DATA) {
|
|
fprintf(stderr, "I2C_FUNC_SMBUS_WORD_DATA 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);
|
|
|
|
while (1) {
|
|
struct usv_data usv;
|
|
memset(&usv, 0, sizeof(usv));
|
|
|
|
usv.sys_state = i2c_smbus_read_word_data(fd, REG_STATUS);
|
|
usv.adc_current = i2c_smbus_read_word_data(fd, REG_CURRENT);
|
|
usv.adc_ubat = i2c_smbus_read_word_data(fd, REG_UBAT);
|
|
usv.adc_uin = i2c_smbus_read_word_data(fd, REG_UIN);
|
|
|
|
printf("state:0x%02x I:%5dmA Ubat:%5dmV Usup:%5dmV (%s) [%5d,%5d,%5d,%5d,%5d,%5d,0x%04x]\n",
|
|
usv.sys_state, usv.adc_current, usv.adc_ubat,
|
|
usv.adc_uin, state2str(usv.sys_state),
|
|
usv.uin_loss, usv.uin_restore, usv.ubat_full,
|
|
usv.ubat_low, usv.ubat_critical, usv.ibat_full,
|
|
usv.crc16);
|
|
|
|
sleep(1);
|
|
}
|
|
close(fd);
|
|
|
|
return 0;
|
|
}
|