-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Cell Data Logging with Timestamping #176
Open
KSMehta11
wants to merge
30
commits into
develop
Choose a base branch
from
166-24a---storing-cell-data-readings-and-timestamping-them
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+366
−1
Open
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
001d630
Added cell data logging header with function prototypes.
4efa3ac
Added cell data logger initialization and updated Makefile.
932fcb8
Implemented function to log cell voltage and temperature data.
81838cd
Implemented functions to retrieve logged cell data.
2ddecdc
Implemented serial debugging functions.
5202ac7
Initialized the data logging ring buffer and enabled logging.
d7c9364
Feature: Add BMSLogger struct.
e311d8d
Refactor: Encapsulate BMSLogger
6e58239
Add separate timestamps for voltage and temperature measurements.
84adf2a
Feat: Capture timestamps at measurement instead of storage.
36117e1
Add error messages for user diagnostics.
30e9c2b
Fix: prevent multiple initializations of BMSLogger.
01f4922
Add Mutex and Error Handling.
01d0110
Refactor: Mutex wait time.
70a66a1
Refactor: Mutex
d7e576f
Merge branch '166-24a---storing-cell-data-readings-and-timestamping-t…
05d5e7b
Refactor: Remove static global logger and use getLogger.
04e7ba5
Refactor: Use int return type and remove is_initialized flag.
7cfa7bb
Refactor: Replace manual NULL checks with assert.
6b656cc
Implement single return point using goto.
dcd5678
Refactor: Mutex wait time.
30f2846
Add print_cell_data helper func.
2010a5d
Add Doc Comments
ead1d0a
Add global bms logger instance.
da715db
Remove: Timestamp during measurement.
0822ce1
Refactor: Made bms logger public.
eb059c8
Add: Timestamp set functions.
fc12135
Refactor: CellDataEntry struct.
6f7ae82
Refactored: Data Insertion and Timestamping Functions.
56d2fd6
Refactor: Centralized Timestamping and Logging.
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
/** | ||
* @file cell_data_logging.h | ||
* @brief Functionality for logging and retrieving cell voltage and temperature data. | ||
* | ||
* This module provides an interface for logging cell voltage and temperature | ||
* data using a ring buffer. Users must ensure proper synchronization when | ||
* handling logging operations, as well as setting timestamps before logging. | ||
* | ||
* @warning The `BMSLogger` structure is *managed internally by the logging system. | ||
* Users should *only pass its address to logging functions and must not modify | ||
* its contents directly. | ||
*/ | ||
|
||
#ifndef CELL_DATA_LOGGING_H | ||
#define CELL_DATA_LOGGING_H | ||
|
||
#include <stdint.h> | ||
#include <stddef.h> | ||
#include <stdbool.h> | ||
#include "datastructs.h" | ||
#include "ringbuffer.h" | ||
#include "cmsis_os.h" | ||
|
||
// Number of stored cell data readings in ring buffer. | ||
#define NUM_OF_READINGS 10 | ||
|
||
/** | ||
* @struct CellDataEntry_t | ||
* @brief Structure to store logged cell voltage and temperature data. | ||
* | ||
* This structure is used to store the timestamp, cell voltages, | ||
* and cell temperatures for each measurement cycle. Each entry | ||
* contains data for all chips and their respective cells. | ||
*/ | ||
typedef struct { | ||
uint32_t cell_voltage_timestamp; | ||
uint32_t cell_temperature_timestamp; | ||
float cell_voltages[NUM_CHIPS][NUM_CELLS_ALPHA]; | ||
float cell_temperatures[NUM_CHIPS][NUM_CELLS_ALPHA]; | ||
} CellDataEntry_t; | ||
|
||
/** | ||
* @struct BMSLogger | ||
* @brief Structure to manage logging system | ||
* | ||
* @warning The `BMSLogger` structure is *managed internally by the logging system. | ||
* Users should *only pass its address to logging functions and must not modify | ||
* its contents directly. | ||
*/ | ||
struct BMSLogger { | ||
ringbuf_t ring_buff; | ||
CellDataEntry_t cell_data_storage[NUM_OF_READINGS]; | ||
osMutexId_t mutex; | ||
}; | ||
|
||
/** | ||
* @brief Initializes a BMSLogger instance. | ||
* @param logger Pointer to the logger instance. | ||
* @return 0 on success, -1 on failure. | ||
*/ | ||
int cell_data_logger_init(struct BMSLogger *logger); | ||
|
||
/** | ||
* @brief Assigns a voltage timestamp to the current log entry. | ||
* @param logger Pointer to the BMSLogger instance. | ||
* @return 0 on success, -1 on failure. | ||
*/ | ||
int cell_data_logger_timestamp_voltage(struct BMSLogger *logger); | ||
|
||
/** | ||
* @brief Assigns a temperature timestamp to the current log entry. | ||
* @param logger Pointer to the BMSLogger instance. | ||
* @return 0 on success, -1 on failure. | ||
*/ | ||
int cell_data_logger_timestamp_therms(struct BMSLogger *logger); | ||
|
||
/** | ||
* @brief Logs a new measurement and inserts it into the ring buffer. | ||
* | ||
* @note The user must ensure timestamps are set before calling this function. | ||
* | ||
* @param logger Pointer to the BMSLogger instance managing the ring buffer. | ||
* @param bms_data Pointer to the BMS data structure containing cell voltages and temperatures. | ||
* @return 0 on success, -1 on failure. | ||
*/ | ||
int cell_data_log_measurement(struct BMSLogger *logger, acc_data_t *bms_data); | ||
|
||
/** | ||
* @brief Retrieves the last n cell data logs from the buffer. | ||
* @param logger Pointer to the logger instance. | ||
* @param n Number of previous logs to retrieve. | ||
* @param out_buffer Pointer to the buffer where the readings will be stored. | ||
* @return 0 on success, -1 on failure. | ||
*/ | ||
int cell_data_log_get_last_n(const struct BMSLogger *logger, size_t n, | ||
CellDataEntry_t *out_buffer); | ||
|
||
/** | ||
* @brief Serial prints the last n cell data logs. | ||
* @param logger Pointer to the logger instance. | ||
* @param n Number of previous logs to print. | ||
* @return 0 on success, -1 on failure. | ||
*/ | ||
int print_last_n_cell_data_logs(const struct BMSLogger *logger, size_t n); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,257 @@ | ||
/** | ||
* @file cell_data_logging.c | ||
* @brief Implementation of cell voltage and temperature data logging. | ||
*/ | ||
|
||
#include "cell_data_logging.h" | ||
Sabramz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#include "analyzer.h" | ||
#include "bmsConfig.h" | ||
#include "stm32f4xx_hal.h" | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <assert.h> | ||
|
||
// Used to get microsecond timestamps. | ||
extern TIM_HandleTypeDef htim2; | ||
|
||
/** | ||
* @brief Retrieves the current timestamp in microseconds from TIM2. | ||
* @return The current timestamp in microseconds. | ||
*/ | ||
static inline uint32_t get_us_timestamp(void) | ||
{ | ||
return __HAL_TIM_GET_COUNTER(&htim2); | ||
} | ||
|
||
/** | ||
* @brief Retrieves the next writable log entry from the buffer. | ||
* @param logger Pointer to the BMSLogger instance. | ||
* @return Pointer to the writable log entry. | ||
*/ | ||
static CellDataEntry_t *get_writable_log_entry(struct BMSLogger *logger) | ||
{ | ||
assert(logger != NULL); | ||
|
||
size_t next_idx = logger->ring_buff.head_idx; | ||
|
||
CellDataEntry_t *entry = &logger->cell_data_storage[next_idx]; | ||
|
||
return entry; | ||
} | ||
|
||
/** | ||
* @brief Prints a single cell data entry. | ||
* @param entry Pointer to the cell data entry to print. | ||
* @param entry_idx Index of the entry. | ||
*/ | ||
static void print_cell_data(const CellDataEntry_t *entry, size_t entry_idx) | ||
{ | ||
assert(entry != NULL); | ||
|
||
printf("\r\n--- Log Entry %u ---\r\n", entry_idx + 1); | ||
printf("Voltage Measurement Timestamp: %lu µs\r\n", | ||
entry->cell_voltage_timestamp); | ||
printf("Temperature Measurement Timestamp: %lu µs\r\n", | ||
entry->cell_temperature_timestamp); | ||
|
||
for (int chip_num = 0; chip_num < NUM_CHIPS; chip_num++) { | ||
int cell_count = (chip_num % 2 == 0) ? NUM_CELLS_ALPHA : | ||
NUM_CELLS_BETA; | ||
printf("\r\nChip %d (%s):\r\n", chip_num, | ||
(chip_num % 2 == 0) ? "Alpha" : "Beta"); | ||
|
||
for (int cell = 0; cell < cell_count; cell++) { | ||
printf(" Cell %d: Voltage: %.3f V, Temperature: %.2f C\r\n", | ||
cell + 1, entry->cell_voltages[chip_num][cell], | ||
entry->cell_temperatures[chip_num][cell]); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* @brief Initializes a BMSLogger instance. | ||
* @param logger Pointer to the logger instance. | ||
* @return 0 on success, -1 on failure. | ||
*/ | ||
int cell_data_logger_init(struct BMSLogger *logger) | ||
{ | ||
assert(logger != NULL); | ||
|
||
memset(logger, 0, sizeof(struct BMSLogger)); | ||
|
||
rb_init(&logger->ring_buff, logger->cell_data_storage, NUM_OF_READINGS, | ||
sizeof(CellDataEntry_t)); | ||
|
||
logger->mutex = osMutexNew(NULL); | ||
|
||
if (logger->mutex == NULL) { | ||
printf("ERROR: Data Logger Mutex initialization failed!\r\n"); | ||
return -1; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
/** | ||
* @brief Assigns a voltage timestamp to the current log entry. | ||
* @param logger Pointer to the BMSLogger instance. | ||
* @return 0 on success, -1 on failure. | ||
*/ | ||
int cell_data_logger_timestamp_voltage(struct BMSLogger *logger) | ||
{ | ||
assert(logger != NULL); | ||
|
||
if (osMutexAcquire(logger->mutex, osWaitForever) != osOK) { | ||
printf("ERROR: Failed to acquire data logging mutex!\r\n"); | ||
return -1; | ||
} | ||
|
||
CellDataEntry_t *entry = get_writable_log_entry(logger); | ||
|
||
if (!entry) | ||
return -1; | ||
|
||
entry->cell_voltage_timestamp = get_us_timestamp(); | ||
|
||
osMutexRelease(logger->mutex); | ||
|
||
return 0; | ||
} | ||
|
||
/** | ||
* @brief Assigns a temperature timestamp to the current log entry. | ||
* @param logger Pointer to the BMSLogger instance. | ||
* @return 0 on success, -1 on failure. | ||
*/ | ||
int cell_data_logger_timestamp_therms(struct BMSLogger *logger) | ||
{ | ||
assert(logger != NULL); | ||
|
||
if (osMutexAcquire(logger->mutex, osWaitForever) != osOK) { | ||
printf("ERROR: Failed to acquire data logging mutex!\r\n"); | ||
return -1; | ||
} | ||
|
||
CellDataEntry_t *entry = get_writable_log_entry(logger); | ||
|
||
if (!entry) | ||
return -1; | ||
|
||
entry->cell_temperature_timestamp = get_us_timestamp(); | ||
|
||
osMutexRelease(logger->mutex); | ||
|
||
return 0; | ||
} | ||
|
||
/** | ||
* @brief Logs a new measurement and inserts it into the ring buffer. | ||
* | ||
* @note The user must ensure timestamps are set before calling this function. | ||
* | ||
* @param logger Pointer to the BMSLogger instance managing the ring buffer. | ||
* @param bms_data Pointer to the BMS data structure containing cell voltages and temperatures. | ||
* @return 0 on success, -1 on failure. | ||
*/ | ||
int cell_data_log_measurement(struct BMSLogger *logger, acc_data_t *bms_data) | ||
{ | ||
int status = -1; | ||
assert(logger != NULL); | ||
assert(bms_data != NULL); | ||
|
||
if (osMutexAcquire(logger->mutex, osWaitForever) != osOK) { | ||
printf("ERROR: Failed to acquire data logging mutex!\r\n"); | ||
goto exit; | ||
} | ||
|
||
CellDataEntry_t *entry = get_writable_log_entry(logger); | ||
if (!entry) { | ||
printf("ERROR: No writable log entry available!\r\n"); | ||
goto exit; | ||
} | ||
|
||
for (int chip_num = 0; chip_num < NUM_CHIPS; chip_num++) { | ||
int cell_count = get_num_cells(&bms_data->chip_data[chip_num]); | ||
|
||
for (int cell = 0; cell < cell_count; cell++) { | ||
entry->cell_voltages[chip_num][cell] = | ||
bms_data->chip_data[chip_num] | ||
.cell_voltages[cell]; | ||
entry->cell_temperatures[chip_num][cell] = | ||
bms_data->chip_data[chip_num].cell_temp[cell]; | ||
} | ||
} | ||
|
||
rb_insert(&logger->ring_buff, entry); | ||
|
||
status = 0; | ||
|
||
osMutexRelease(logger->mutex); | ||
|
||
return status; | ||
|
||
exit: | ||
return status; | ||
} | ||
|
||
/** | ||
* @brief Retrieves the last n cell data logs from the buffer. | ||
* @param logger Pointer to the logger instance. | ||
* @param n Number of previous logs to retrieve. | ||
* @param out_buffer Pointer to the buffer where the readings will be stored. | ||
* @return 0 on success, -1 on failure. | ||
*/ | ||
int cell_data_log_get_last_n(const struct BMSLogger *logger, size_t n, | ||
CellDataEntry_t *out_buffer) | ||
{ | ||
int status = -1; | ||
assert(logger != NULL); | ||
|
||
if (n > logger->ring_buff.curr_elements) { | ||
printf("ERROR: Not enough logs available!\r\n"); | ||
goto exit; | ||
} | ||
|
||
if (osMutexAcquire(logger->mutex, osWaitForever) != osOK) { | ||
printf("ERROR: Failed to acquire data logging mutex!\r\n"); | ||
goto exit; | ||
} | ||
|
||
rb_get_last_n(&logger->ring_buff, out_buffer, n); | ||
|
||
status = 0; | ||
|
||
osMutexRelease(logger->mutex); | ||
|
||
exit: | ||
return status; | ||
} | ||
|
||
/** | ||
* @brief Serial prints the last n cell data logs. | ||
* @param logger Pointer to the logger instance. | ||
* @param n Number of previous logs to print. | ||
* @return 0 on success, -1 on failure. | ||
*/ | ||
int print_last_n_cell_data_logs(const struct BMSLogger *logger, size_t n) | ||
{ | ||
int status = -1; | ||
assert(logger != NULL); | ||
|
||
CellDataEntry_t log_entries[n]; | ||
|
||
if (cell_data_log_get_last_n(logger, n, log_entries)) { | ||
printf("Error retrieving log entries!\r\n"); | ||
goto exit; | ||
} | ||
|
||
printf("\r\nPrinting Last %u Cell Data Logs:\r\n", n); | ||
for (size_t entry_idx = 0; entry_idx < n; entry_idx++) { | ||
print_cell_data(&log_entries[entry_idx], entry_idx); | ||
} | ||
|
||
status = 0; | ||
|
||
exit: | ||
return status; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Submodule Embedded-Base
updated
47 files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The user should decide how many readings will be logged, and should be able to do this when initializing the logger.