-
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
base: develop
Are you sure you want to change the base?
Implement Cell Data Logging with Timestamping #176
Conversation
Core/Src/cell_data_logging.c
Outdated
|
||
void cell_data_logger_init(void) | ||
{ | ||
rb_init(&cell_log_ring_buff, cell_data_storage, NUM_OF_READINGS, |
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.
Can all of this be wrapped in a ptr that the user controls? So the arg to this func (and all other funcs) would be like struct *bms_logger. If you don't want them modifying it, you can use C stuff to make a struct that is defined in the header but its fields are defined in the source file and the fields cannot be accessed from outside the source.
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.
Also this struct needs a mutex, and all the getters and setters will need mutexes as well.
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.
Yes, I can wrap this in a pointer-controlled struct, and that approach makes sense. I will do it that way and add the mutex as well.
Core/Src/cell_data_logging.c
Outdated
new_entry.cell_temperatures[chip_num][cell] = | ||
bms_data->chip_data[chip_num].cell_temp[cell]; | ||
|
||
new_entry.timestamp[chip_num][cell] = |
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.
Can the source of this timestamp be right after the measurement is taken, rather than when it is logged?
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.
We may want to log the data much later than the reading happened.
Core/Src/cell_data_logging.c
Outdated
|
||
CellDataEntry_t *cell_data_log_get_last(void) | ||
{ | ||
return (CellDataEntry_t *)rb_get_head(&cell_log_ring_buff); |
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.
Can you protect against getting a NULLPTR from this? or say in docs that NULL PTR can be returned and should be checked and that a NULL ptr return means the rb has not been initted / populated with data yet?
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.
I will add protection against returning a nullptr and will likely include a message.
…hem' of https://github.com/Northeastern-Electric-Racing/Shepherd-BMS into 166-24a---storing-cell-data-readings-and-timestamping-them
Core/Src/cell_data_logging.c
Outdated
osMutexId_t mutex; | ||
}; | ||
|
||
static BMSLogger bms_logger = { .is_initialized = false }; |
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.
We don't want this. The user should be creating the logger. They will make the struct, and then pass it to an init function.
Core/Src/cell_data_logging.c
Outdated
|
||
static BMSLogger bms_logger = { .is_initialized = false }; | ||
|
||
BMSLogger *get_logger(void) |
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.
Get rid of this with the static global variable
Core/Inc/cell_data_logging.h
Outdated
* @param logger Pointer to the logger instance. | ||
* @return false on success, true on failure. | ||
*/ | ||
bool cell_data_logger_init(BMSLogger *logger); |
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 standard in C is that the return type is an int. Make every error code return an int.
Core/Src/cell_data_logging.c
Outdated
extern TIM_HandleTypeDef htim2; | ||
|
||
struct BMSLogger { | ||
bool is_initialized; |
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.
This is unnecessary. You will know if the logger is uninitialized if a NULLPTR is passed into a func in the interface.
Core/Src/cell_data_logging.c
Outdated
return __HAL_TIM_GET_COUNTER(&htim2); | ||
} | ||
|
||
static bool get_logger_status(const BMSLogger *logger) |
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.
Add doc comment and put private functions before all public functions.
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.
Since you are also checking if acc_data_t is null in other functions, make this function able to determine if any pointer is a nullptr, not just loggers.
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.
Tbh you can just get rid of this entirely and use asserts. Just at the beginning of every function call assert(ptr) for every ptr.
#include "cmsis_os.h" | ||
|
||
// Number of stored cell data readings in ring buffer. | ||
#define NUM_OF_READINGS 10 |
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.
Core/Inc/cell_data_logging.h
Outdated
* @brief Serial prints the most recent data log. | ||
* @param logger Pointer to the logger instance. | ||
*/ | ||
void print_latest_cell_data_log(const BMSLogger *logger); |
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.
This function is not needed since the user can just call print last n cell data logs with an n of 1.
Core/Src/cell_data_logging.c
Outdated
log_entries[entry_idx].cell_temperature_timestamp); | ||
|
||
for (int chip_num = 0; chip_num < NUM_CHIPS; chip_num++) { | ||
int cell_count = (chip_num % 2 == 0) ? NUM_CELLS_ALPHA : |
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.
This should be broken out into a helper function. Triple nested for loops is going too far lolz.
Core/Inc/datastructs.h
Outdated
@@ -142,6 +142,10 @@ typedef struct { | |||
|
|||
bool is_charger_connected; | |||
|
|||
/* Cell Data Logging Timestamps */ | |||
uint32_t voltage_timestamp; |
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.
My mistake on the previous review. Lets limit the scope of this to just the interface. Application will come later, so get rid of these. Everything should be in cell data logging.
Core/Src/cell_data_logging.c
Outdated
* @brief Assigns a timestamp to the voltage measurement field of a cell data entry. | ||
* @param entry Pointer to the CellDataEntry_t structure to update. | ||
*/ | ||
void cell_data_set_voltage_timestamp(CellDataEntry_t *entry) |
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.
When we timestamp something, we should just timestamp the next log entry, cuz that is where the next reading will be written to. Do some auto incrementing here so the user simply calls timestamp_next_reading and passes in the logger.
Core/Inc/cell_data_logging.h
Outdated
* @param entry Pointer to a CellDataEntry_t structure that holds the measurement data. | ||
* @return 0 on success, -1 on failure. | ||
*/ | ||
int cell_data_log_measurement(struct BMSLogger *logger, acc_data_t *bms_data, |
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.
Make this not take an entry as an argument. Just a logger and data to insert.
Changes
Notes
The buffer size can be adjusted in the header file to store more readings.
Test Cases
The logging functionality was first tested on an STM32 Nucleo board using fake BMS data. Simulated cell voltages and temperatures were logged, retrieved, and verified using serial printouts.
The logging functionality was tested on the Shepherd BMS Master Board, configured with one chip Alpha. The inputs were connected to a PSU to simulate real cell voltages.
To Do
Checklist
It can be helpful to check the
Checks
andFiles changed
tabs.Please reach out to your Project Lead if anything is unclear.
Please request reviewers and ping on slack only after you've gone through this whole checklist.
Closes # (issue #175 )