Move to C++. Use C++14 as it adds binary literals -> HDL friendly.
This commit is contained in:
212
battery.cpp
Normal file
212
battery.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
|
||||
* battery.c
|
||||
* display pi-top battery status
|
||||
*
|
||||
* Copyright 2016, 2017 rricharz
|
||||
* MiSTer port. Copyright 2018 Sorgelig
|
||||
*
|
||||
* 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 <time.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
#include "battery.h"
|
||||
|
||||
#define MAX_COUNT 20 // Maximum number of trials
|
||||
#define SLEEP_TIME 500 // time between two i2cget in microsec
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// I2C definitions
|
||||
|
||||
#define I2C_SLAVE 0x0703
|
||||
#define I2C_SMBUS 0x0720 /* SMBus-level access */
|
||||
|
||||
#define I2C_SMBUS_READ 1
|
||||
#define I2C_SMBUS_WRITE 0
|
||||
|
||||
// SMBus transaction types
|
||||
|
||||
#define I2C_SMBUS_QUICK 0
|
||||
#define I2C_SMBUS_BYTE 1
|
||||
#define I2C_SMBUS_BYTE_DATA 2
|
||||
#define I2C_SMBUS_WORD_DATA 3
|
||||
#define I2C_SMBUS_PROC_CALL 4
|
||||
#define I2C_SMBUS_BLOCK_DATA 5
|
||||
#define I2C_SMBUS_I2C_BLOCK_BROKEN 6
|
||||
#define I2C_SMBUS_BLOCK_PROC_CALL 7 /* SMBus 2.0 */
|
||||
#define I2C_SMBUS_I2C_BLOCK_DATA 8
|
||||
|
||||
// SMBus messages
|
||||
|
||||
#define I2C_SMBUS_BLOCK_MAX 32 /* As specified in SMBus standard */
|
||||
#define I2C_SMBUS_I2C_BLOCK_MAX 32 /* Not specified but we use same structure */
|
||||
|
||||
// Structures used in the ioctl() calls
|
||||
|
||||
union i2c_smbus_data
|
||||
{
|
||||
uint8_t byte;
|
||||
int8_t sbyte;
|
||||
uint16_t word;
|
||||
int16_t sword;
|
||||
uint8_t block [I2C_SMBUS_BLOCK_MAX + 2]; // block [0] is used for length + one more for PEC
|
||||
};
|
||||
|
||||
struct i2c_smbus_ioctl_data
|
||||
{
|
||||
char read_write;
|
||||
uint8_t command;
|
||||
int size;
|
||||
union i2c_smbus_data *data;
|
||||
};
|
||||
|
||||
static int i2c_smbus_access (int fd, char rw, uint8_t command, int size, union i2c_smbus_data *data)
|
||||
{
|
||||
struct i2c_smbus_ioctl_data args;
|
||||
|
||||
args.read_write = rw;
|
||||
args.command = command;
|
||||
args.size = size;
|
||||
args.data = data;
|
||||
return ioctl (fd, I2C_SMBUS, &args);
|
||||
}
|
||||
|
||||
static int i2c_smbus_write_quick(int fd, uint8_t value)
|
||||
{
|
||||
return i2c_smbus_access(fd, value, 0, I2C_SMBUS_QUICK, NULL);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
|
||||
static int i2c_handle = -1;
|
||||
|
||||
static int smbus_open(int dev_address)
|
||||
{
|
||||
// re-entry compatible
|
||||
if(i2c_handle < 0)
|
||||
{
|
||||
int fd;
|
||||
if ((fd = open ("/dev/i2c-1", O_RDWR)) < 0)
|
||||
{
|
||||
printf("Unable to open I2C device: %s\n", strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ioctl (fd, I2C_SLAVE, dev_address) < 0)
|
||||
{
|
||||
printf("Unable to select I2C device: %s\n", strerror (errno));
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (i2c_smbus_write_quick(fd, I2C_SMBUS_WRITE) < 0)
|
||||
{
|
||||
printf("Unable to detect SMBUS device: %s\n", strerror(errno));
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
i2c_handle = fd;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void smbus_close()
|
||||
{
|
||||
if(i2c_handle > 0) close(i2c_handle);
|
||||
i2c_handle = -1;
|
||||
}
|
||||
|
||||
static int smbus_get(int address, short *data)
|
||||
{
|
||||
union i2c_smbus_data smbus_data;
|
||||
|
||||
if (i2c_smbus_access (i2c_handle, I2C_SMBUS_READ, address, I2C_SMBUS_WORD_DATA, &smbus_data)) return 0;
|
||||
|
||||
*data = smbus_data.sword;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int getReg(int reg, int min, int max)
|
||||
{
|
||||
int count = 0;
|
||||
short value = -1;
|
||||
while ((value == -1) && (count++ < MAX_COUNT))
|
||||
{
|
||||
if (smbus_get(reg, &value))
|
||||
{
|
||||
if ((value > max) || (value < min)) value = -1; // out of limits
|
||||
}
|
||||
usleep(SLEEP_TIME);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int getBattery(int quick, struct battery_data_t *data)
|
||||
{
|
||||
/*
|
||||
data->capacity = 80;
|
||||
data->load_current = -520;
|
||||
data->time = 312;
|
||||
data->current = 2510;
|
||||
data->voltage = 16200;
|
||||
data->cell[0] = 4101;
|
||||
data->cell[1] = 4102;
|
||||
data->cell[2] = 4103;
|
||||
data->cell[3] = 4104;
|
||||
return 1;
|
||||
*/
|
||||
// don't try to check if no battery device is present
|
||||
if (i2c_handle == -2) return 0;
|
||||
|
||||
if (!smbus_open(0x0b))
|
||||
{
|
||||
printf("No battery found.\n");
|
||||
i2c_handle = -2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
data->capacity = getReg(0x0D, 0, 100);
|
||||
data->load_current = getReg(0x0A, -5000, 5000);
|
||||
if (quick) return 1;
|
||||
|
||||
data->time = 0;
|
||||
if (data->load_current > 0) data->time = getReg(0x13, 1, 999);
|
||||
if (data->load_current < -1) data->time = getReg(0x12, 1, 960);
|
||||
|
||||
data->current = getReg(0x0F, 0, 5000);
|
||||
data->voltage = getReg(0x09, 5000, 20000);
|
||||
/*
|
||||
data->cell[0] = getReg(0x3F, 1000, 5000);
|
||||
data->cell[1] = getReg(0x3E, 1000, 5000);
|
||||
data->cell[2] = getReg(0x3D, 1000, 5000);
|
||||
data->cell[3] = getReg(0x3C, 1000, 5000);
|
||||
*/
|
||||
|
||||
return 1;
|
||||
}
|
||||
Reference in New Issue
Block a user