1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

drivers/ltc4150: Allow tracking last minute charge

Implemented an example `ltc4150_recorder_t` implementation as a proof of concept
for the recorder API.
This commit is contained in:
Marian Buschsieweke 2019-01-08 23:23:43 +01:00
parent fa0d08a08b
commit db0c66e07f
No known key found for this signature in database
GPG Key ID: 61F64C6599B1539F
3 changed files with 166 additions and 16 deletions

View File

@ -185,7 +185,7 @@ typedef struct {
* @brief `NULL` or a `NULL`-terminated array of data recorders
* @pre If not `NULL`, the last element of the array must be `NULL`
*/
ltc4150_recorder_t **recorders;
const ltc4150_recorder_t **recorders;
/**
* @brief `NULL` or an array of the user defined data for each recorder
* @pre If @see ltc4150_params_t::recorders is not `NULL`, this must point
@ -207,6 +207,35 @@ struct ltc4150_dev {
uint32_t discharged; /**< # of pulses for discharging (POL=low) */
};
/**
* @brief Data structure used by @ref ltc4150_last_minute
*/
typedef struct {
uint32_t last_rotate_sec; /**< Time stamp of the last ring "rotation" */
/**
* @brief Pulses in charging direction recorded in the last minute
*/
uint16_t charged;
/**
* @brief Pulses in discharging direction recorded in the last minute
*/
uint16_t discharged;
/**
* @brief Ring-buffer to store charge information in 10 sec resolution
*/
uint8_t buf_charged[7];
/**
* @brief As above, but in discharging direction
*/
uint8_t buf_discharged[7];
uint8_t ring_pos; /**< Position in the ring buffer */
} ltc4150_last_minute_data_t;
/**
* @brief Records the charge transferred within the last minute using
*/
extern const ltc4150_recorder_t ltc4150_last_minute;
/**
* @brief Initialize the LTC4150 driver
*
@ -275,6 +304,42 @@ int ltc4150_charge(ltc4150_dev_t *dev, uint32_t *charged, uint32_t *discharged);
*/
int ltc4150_avg_current(ltc4150_dev_t *dev, int16_t *dest);
/**
* @brief Get the measured charge in the last minute
*
* @param dev The LTC4150 device to read data from
* @param data The data recorded by @ref ltc4150_last_minute
* @param[out] charged The charge transferred in charging direction
* @param[out] discharged The charge transferred in discharging direction
*
* @retval 0 Success
* @retval -EINVAL Called with an invalid argument
*
* @warning The returned data may be outdated up to ten seconds
*
* Passing `NULL` for `charged` or `discharged` is allowed, if only one
* information is of interest.
*/
int ltc4150_last_minute_charge(ltc4150_dev_t *dev,
ltc4150_last_minute_data_t *data,
uint32_t *charged, uint32_t *discharged);
/**
* @brief Convert the raw data (# pulses) acquired by the LTC4150 device to
* charge information in millicoulomb
* @note This function will make writing data recorders (see
* @ref ltc4150_recorder_t) easier, but is not intended for end users
*
* @param dev LTC4150 device the data was received from
* @param[out] charged Charge in charging direction is stored here
* @param[out] discharged Charge in discharging direction is stored here
* @param[in] raw_charged Number of pulses in charging direction
* @param[in] raw_discharged Number of pulses in discharging direction
*/
void ltc4150_pulses2c(const ltc4150_dev_t *dev,
uint32_t *charged, uint32_t *discharged,
uint32_t raw_charged,
uint32_t raw_discharged);
#ifdef __cplusplus
}
#endif

View File

@ -139,20 +139,10 @@ int ltc4150_shutdown(ltc4150_dev_t *dev)
return 0;
}
/**
* @brief Convert the raw data (# pulses) acquired by the LTC4150 device to
* charge information in millicoulomb
*
* @param dev LTC4150 device the data was received from
* @param[out] charged Charge in charging direction is stored here
* @param[out] discharged Charge in discharging direction is stored here
* @param[in] raw_charged Number of pulses in charging direction
* @param[in] raw_discharged Number of pulses in discharging direction
*/
static void get_coulomb(const ltc4150_dev_t *dev,
uint32_t *charged, uint32_t *discharged,
uint32_t raw_charged,
uint32_t raw_discharged)
void ltc4150_pulses2c(const ltc4150_dev_t *dev,
uint32_t *charged, uint32_t *discharged,
uint32_t raw_charged,
uint32_t raw_discharged)
{
uint64_t tmp;
@ -180,7 +170,7 @@ int ltc4150_charge(ltc4150_dev_t *dev, uint32_t *charged, uint32_t *discharged)
}
gpio_irq_disable(dev->params.interrupt);
get_coulomb(dev, charged, discharged, dev->charged, dev->discharged);
ltc4150_pulses2c(dev, charged, discharged, dev->charged, dev->discharged);
gpio_irq_enable(dev->params.interrupt);
return 0;
}

View File

@ -0,0 +1,95 @@
/*
* Copyright 2019 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_ltc4150
* @{
*
* @file
* @brief Track the drawn charged of the last minute
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
* @}
*/
#include <errno.h>
#include <string.h>
#include "ltc4150.h"
#include "xtimer.h"
static void init_or_reset(ltc4150_dev_t *dev, uint64_t now_usec, void *arg);
static void pulse(ltc4150_dev_t *dev, ltc4150_dir_t dir, uint64_t now_usec,
void *arg);
const ltc4150_recorder_t ltc4150_last_minute = {
.reset = init_or_reset,
.pulse = pulse,
};
static void init_or_reset(ltc4150_dev_t *dev, uint64_t now_usec, void *arg)
{
(void)dev;
ltc4150_last_minute_data_t *data = arg;
memset(data, 0, sizeof(ltc4150_last_minute_data_t));
data->last_rotate_sec = now_usec / US_PER_SEC;
}
static void update_ringbuffer(ltc4150_last_minute_data_t *data,
uint64_t now_usec)
{
uint32_t now_sec = (now_usec / US_PER_SEC);
/* Note: This expression should be correct even when time overflows */
while (now_sec - data->last_rotate_sec > 10) {
data->last_rotate_sec += 10;
data->charged += data->buf_charged[data->ring_pos];
data->discharged += data->buf_discharged[data->ring_pos];
if (++data->ring_pos >= sizeof(data->buf_charged)/sizeof(data->buf_charged[0])) {
data->ring_pos = 0;
}
data->charged -= data->buf_charged[data->ring_pos];
data->discharged -= data->buf_discharged[data->ring_pos];
data->buf_charged[data->ring_pos] = 0;
data->buf_discharged[data->ring_pos] = 0;
}
}
static void pulse(ltc4150_dev_t *dev, ltc4150_dir_t dir, uint64_t now_usec,
void *arg)
{
(void)dev;
ltc4150_last_minute_data_t *data = arg;
update_ringbuffer(data, now_usec);
switch (dir) {
case LTC4150_CHARGE:
data->buf_charged[data->ring_pos]++;
break;
default:
case LTC4150_DISCHARGE:
data->buf_discharged[data->ring_pos]++;
break;
}
}
int ltc4150_last_minute_charge(ltc4150_dev_t *dev,
ltc4150_last_minute_data_t *d,
uint32_t *charged, uint32_t *discharged)
{
if (!dev || !d) {
return -EINVAL;
}
gpio_irq_disable(dev->params.interrupt);
update_ringbuffer(d, xtimer_now_usec64());
ltc4150_pulses2c(dev, charged, discharged, d->charged, d->discharged);
gpio_irq_enable(dev->params.interrupt);
return 0;
}