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:
parent
fa0d08a08b
commit
db0c66e07f
@ -185,7 +185,7 @@ typedef struct {
|
|||||||
* @brief `NULL` or a `NULL`-terminated array of data recorders
|
* @brief `NULL` or a `NULL`-terminated array of data recorders
|
||||||
* @pre If not `NULL`, the last element of the array must be `NULL`
|
* @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
|
* @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
|
* @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) */
|
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
|
* @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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -139,20 +139,10 @@ int ltc4150_shutdown(ltc4150_dev_t *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void ltc4150_pulses2c(const ltc4150_dev_t *dev,
|
||||||
* @brief Convert the raw data (# pulses) acquired by the LTC4150 device to
|
uint32_t *charged, uint32_t *discharged,
|
||||||
* charge information in millicoulomb
|
uint32_t raw_charged,
|
||||||
*
|
uint32_t raw_discharged)
|
||||||
* @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)
|
|
||||||
{
|
{
|
||||||
uint64_t tmp;
|
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);
|
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);
|
gpio_irq_enable(dev->params.interrupt);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
95
drivers/ltc4150/ltc4150_last_minute.c
Normal file
95
drivers/ltc4150/ltc4150_last_minute.c
Normal 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;
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user