Skip to content

Conversation

@zizz-0
Copy link

@zizz-0 zizz-0 commented Dec 9, 2025

Description

Code to test solids motors using Grim Reefer

  • Measure ADC data in 10 second test runs
  • Store test data (up to 30 tests) in flash storage
  • Dump either specific test number or all tests to serial
  • Trigger tests either using terminal command or meep
  • Set test calibration names

Type of change

  • New feature (non-breaking change which adds functionality)

How Has This Been Tested?

Terminal test commands tested on Grim Reefer using minicom. Solids members tested motors using meep connected to TX. Key switch functionality has only been tested by pulling RX, not with an actual key switch

Checklist:

  • New functionality is documented in the necessary spots (i.e new functions documented in the header)
  • The CI checks are passing
  • I reviewed my own code in the GitHub diff and am sure that each change is intentional
  • I feel comfortable about this code flying in a rocket

zizz-0 and others added 30 commits October 19, 2025 11:59
buzzer
accidentally auto formatted (sorrry)
@zizz-0 zizz-0 requested a review from a team as a code owner December 9, 2025 01:50
@@ -0,0 +1,9 @@
sample:
description:
name: grim_reefer
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you change the name to solids board here

/**
* @brief Waits for ADC reading event to start, then reads ADC samples for 10 seconds
*/
void adc_reading_task();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what i failed to say in the other comment was that adc_reading_task need not be exposed. i think this can be safely kep private in adc_reading.c

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after further pondering and the comments about the SYS_INIT. do not follow the comment above. i think this should be exposed so that all the K_THREAD_DEFINEs can be in main. so main looks something like

#include<a bunch of thigns.h>

SYS_INIT(adc_init)
SYS_INIT(buzzer_init)
...

K_THREAD_DEFINE(adc_reading_task)
K_THREAD_DEFINE(storage_task)
K_THREAD_DEFINE(buzzer_task)

kinda for the same reason you mentioned for sys_inits - its good to see them all in one place

and then if you do that it would be nice to put a comment on *_init and *_task saying like these init and run the subsystem. only call them once and all that jazz

address = <1>;
analog-clock-prescaler = <0>;
boost-current-bias = <0>;
spi-max-frequency = <DT_FREQ_M(18)>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking the datasheet, MCP3561 is capable of 20 mhz


/**
* @brief Read one ADC sample
* @param adc_val Pointer to value where sample will be written
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add [in] and [out] for the @params in your function documentation

}
}

void adc_reading_task() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty sure you should have a (void*, void*, void*) here to avoid any warnings you get for declaring this a task.

CONFIG_ADC=y
CONFIG_ADC_LOG_LEVEL_ERR=y # Will spam annoying error at wrn level

CONFIG_ADC_MCP356XR=y # new driver: https://github.com/zephyrproject-rtos/zephyr/blob/main/drivers/adc/Kconfig.mcp356xr
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unnecessary comment

Comment on lines 48 to 55
for (int i = 0; i < 10; i++) {
printk("BEEP ");
set_buzz(1);
k_msleep(1000);
set_buzz(0);
k_msleep(1000);
}
printk("\n");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why no logger here?

Comment on lines 61 to 83
printk("BEEP ");
set_buzz(1);
k_msleep(100);
set_buzz(0);
k_msleep(100);
}
printk("\n");
}

void test_end_beep() {
test_running = false;
printk("BEEEEEP\n");
set_buzz(1);
k_msleep(100);
set_buzz(0);
k_msleep(100);
set_buzz(1);
k_msleep(1000);
set_buzz(0);
}

void continuous_beep() {
printk("BEEEEEEEEEEEEEEEEEEEEEEEP\n");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or here lol. Maybe also be a little more descriptive than just adding more Es, so people who didn't write the code have a better idea of whats going on. Or just remove the prints if these are debug prints

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hater (they were just debug prints since I had the buzzer disabled while testing, will remove)

}

void buzzer_task() {
while (1) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep it consistent and have a while (true) here

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds new functionality to test solids motors using the Grim Reefer board. The implementation collects ADC data during 10-second test runs, stores up to 30 tests in flash memory with calibration metadata, and supports triggering tests via both terminal commands and external hardware (meep) with appropriate safety indicators.

Key changes:

  • ADC data collection system with 1ms sample rate for 10-second test duration
  • Flash storage management supporting 30 test runs with calibration names and test metadata
  • Dual trigger modes: terminal commands and hardware button/key switch with buzzer feedback
  • Shell command interface for test control, data dumping, and flash management

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
app/other/solids_test/src/main.c Application entry point with SYS_INIT configuration for ADC, buzzer, and button modules
app/other/solids_test/src/shell_cmds.c Shell command interface for test control (start, stop, dump, erase, ematch)
app/other/solids_test/src/control.c Central control logic coordinating ADC reading and flash storage operations
app/other/solids_test/src/flash_storage.c Flash storage thread managing test data persistence with metadata
app/other/solids_test/src/adc_reading.c ADC sampling thread with timer-based collection and automatic 10-second duration
app/other/solids_test/src/buzzer.c GPIO control for buzzer, LDO, and ematch pins with beep notification functions
app/other/solids_test/src/button.c GPIO interrupt handlers for button (TX) and key switch (RX) with buzzer task
app/other/solids_test/include/*.h Header files with function documentation and struct definitions
app/other/solids_test/boards/grim_reefer.overlay Device tree configuration for ADC, GPIO pins, and SPI peripherals
app/other/solids_test/prj.conf Zephyr build configuration enabling ADC, flash, shell, and GPIO support
app/other/solids_test/CMakeLists.txt Build system configuration
app/other/solids_test/Kconfig Kconfig integration
app/other/solids_test/sample.yaml Test sample configuration for CI

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 225 to 233
flash_read(flash_dev, block_addr, calib_name, sizeof(calib_name));
block_addr += 32;

flash_read(flash_dev, block_addr, test_type, sizeof(test_type));
block_addr += sizeof(test_type);

shell_print(shell, "================================\nDumping Test #%d", test_index);
shell_print(shell, "CALIBRATION: %s", calib_name);
shell_print(shell, "Test triggered by %s", test_type);
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The global variable 'test_type' is read in flash_dump_one without any protection against concurrent modification. If a new test starts while flash_dump_one is executing, the test_type being displayed could be inconsistent with the actual test data being read from flash.

Suggested change
flash_read(flash_dev, block_addr, calib_name, sizeof(calib_name));
block_addr += 32;
flash_read(flash_dev, block_addr, test_type, sizeof(test_type));
block_addr += sizeof(test_type);
shell_print(shell, "================================\nDumping Test #%d", test_index);
shell_print(shell, "CALIBRATION: %s", calib_name);
shell_print(shell, "Test triggered by %s", test_type);
char local_test_type[sizeof(test_type)];
flash_read(flash_dev, block_addr, calib_name, sizeof(calib_name));
block_addr += sizeof(calib_name);
flash_read(flash_dev, block_addr, local_test_type, sizeof(local_test_type));
block_addr += sizeof(local_test_type);
shell_print(shell, "================================\nDumping Test #%d", test_index);
shell_print(shell, "CALIBRATION: %s", calib_name);
shell_print(shell, "Test triggered by %s", local_test_type);

Copilot uses AI. Check for mistakes.
LOG_ERR("Failed to conf ldo enable pin :(");
return -1;
}

Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ematch GPIO is configured but never checked for successful initialization. If gpio_pin_configure_dt fails for the ematch pin, the function returns 0 (success) without configuring this critical safety component. This should include error checking and return an error if ematch configuration fails.

Suggested change
ret = gpio_pin_configure_dt(&ematch, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
LOG_ERR("Failed to conf ematch pin :(");
return -1;
}

Copilot uses AI. Check for mistakes.

int flash_dump_one(const struct shell *shell, uint32_t test_index) {
if (test_index >= MAX_TESTS ){
shell_print(shell, "Pick a valid test [0-29]");
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message says "Pick a valid test [0-29]" but uses a hardcoded range. If MAX_TESTS is changed from 30, this error message will become incorrect. Consider using a format string that incorporates MAX_TESTS dynamically, such as "Pick a valid test [0-%d]", MAX_TESTS - 1.

Suggested change
shell_print(shell, "Pick a valid test [0-29]");
shell_print(shell, "Pick a valid test [0-%u]", MAX_TESTS - 1);

Copilot uses AI. Check for mistakes.

K_THREAD_DEFINE(storage_thread, 2048, flash_storage_thread_entry, NULL, NULL, NULL, STORAGE_THREAD_PRIORITY, 0, 1000);

static char calibration[32];
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The magic number 32 is used for the calibration name buffer size in multiple places without being defined as a constant. This appears on lines 18, 135-136, 188, 190, 224-226, and in control.c line 17. Consider defining this as a named constant (e.g., CALIB_NAME_MAX_LEN) in config.h to improve maintainability and ensure consistency.

Copilot uses AI. Check for mistakes.
Comment on lines 58 to 71
void test_start_beep() {
test_running = true;
for (int i = 0; i < 3; i++) {
printk("BEEP ");
set_buzz(1);
k_msleep(100);
set_buzz(0);
k_msleep(100);
}
printk("\n");
}

void test_end_beep() {
test_running = false;
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test_running flag is set to true in test_start_beep and false in test_end_beep, which is misleading. These are beep notification functions, not test control functions. Setting test state within buzzer notification functions creates confusing control flow and makes it unclear who owns the test_running state.

Copilot uses AI. Check for mistakes.
static const struct gpio_dt_spec buzzer = GPIO_DT_SPEC_GET(DT_ALIAS(buzzer), gpios);
static const struct gpio_dt_spec ematch = GPIO_DT_SPEC_GET(CAM_EN_NODE, gpios);

static bool test_running = false;
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable 'test_running' is defined locally in buzzer.c but is never updated by the actual test status. The test status is tracked separately in control.c. This means test_running will always be false after initialization (except during beep functions), which could cause the continuous_beep function to not work correctly. Consider removing this redundant state tracking and relying solely on control_get_test_status().

Copilot uses AI. Check for mistakes.
static const struct device *flash_dev = DEVICE_DT_GET(DT_ALIAS(storage));
static uint32_t current_test_number = 0;
static off_t current_write_addr = 0;
static char test_type[] = "terminal";
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable 'test_type' is declared as a static array with a fixed size of 9 bytes (sizeof "terminal" + null terminator), but line 194 attempts to write "meep" into it using snprintf with sizeof(test_type). While "meep" fits within the array, the array size should be defined based on the maximum expected string length to make the code more maintainable. Consider defining a constant for the test type buffer size or using a larger fixed size.

Copilot uses AI. Check for mistakes.
* @brief Struct to hold one ADC sample
*/
struct adc_sample {
uint32_t timestamp; /** Timestamp the sample was recorded in ms */
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states the timestamp is in ms (milliseconds), but the actual implementation at line 127 uses k_ticks_to_us_near32() which converts to microseconds (μs), not milliseconds. This documentation inconsistency could lead to incorrect data interpretation.

Suggested change
uint32_t timestamp; /** Timestamp the sample was recorded in ms */
uint32_t timestamp; /** Timestamp the sample was recorded in µs (microseconds) */

Copilot uses AI. Check for mistakes.
for (int i = 0; i < num; i++) {
adc_read_one(&adc_val);
uint32_t t = k_uptime_ticks() - start;
shell_print(shell, "%u, %d", k_ticks_to_us_near32(t), adc_val);
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing space after comma in the format string. Should be "%u, %d" for consistency with the output format used elsewhere in the codebase (e.g., line 247 in flash_storage.c).

Copilot uses AI. Check for mistakes.
void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins);

/**
* @brief Interrupt function that toggles ematch and does something else
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation states this function "toggles ematch and does something else", which is vague and unhelpful. The actual function sets ematch high when the key switch is active and manages the buzzing state. The documentation should clearly describe what the function does, such as "Enables ematch when key switch is activated and triggers warning beep if no test is running".

Suggested change
* @brief Interrupt function that toggles ematch and does something else
* @brief Interrupt handler that enables ematch when the key switch is active and manages the buzzer warning state

Copilot uses AI. Check for mistakes.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol I forgot to change this comment from the placeholder my bad

Comment on lines +78 to +79
int ret;
ret = flash_erase(flash_dev, FLASH_METADATA_ADDR, FLASH_METADATA_SIZE);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just simplify to one line

size_t i = 0;
size_t pages = 0;

while (1) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while (true)

int button_switch_init();

/**
* @brief Interrupt handler that starts a test when TX pin is pulled high
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think button_pressed and key_switch_state both can be internal to button.c and need not be exposed in the header.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants