Skip to content

feat: use cpp version of common drivers - #5

Open
wispl wants to merge 2 commits into
mainfrom
cpp-commondrivers
Open

feat: use cpp version of common drivers#5
wispl wants to merge 2 commits into
mainfrom
cpp-commondrivers

Conversation

@wispl

@wispl wispl commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Very very messy, there are a lot of things which I think can be done better.

Comment thread Core/Src/device-init.cpp
@wispl

wispl commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

This is temporary, and is a temporary way to test the cpp changes in Common in a quick and dirty way. Hence why I piggybacked off your cpp commits and stuff everything in a class.

I would like to move Tasks into Common personally, but this needs more design and discussion.

@ncorrea210

Copy link
Copy Markdown
Collaborator

I agree with moving tasks into common, even if they are only used on one device. It just makes things easier to share. It may make sense though to have some kind of interface or functions that are not defined on the platform side that can be easily defined on the device side. For example, if we have a buzzer task, the pin and timer we want to use may change so that implementation may be on the device side.

@wispl
wispl force-pushed the cpp-commondrivers branch 2 times, most recently from ce9e4a2 to ccc187e Compare August 23, 2026 23:55
@ncorrea210

ncorrea210 commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

make sure to commit the bumped submodule version, that is causing the build fail.

Comment thread Core/Inc/device-init.h
#include "hal.h"

/**
* @brief device init

@ncorrea210 ncorrea210 Aug 24, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

really? 💀

Comment thread Core/Src/device-init.cpp
Comment on lines +27 to +104
class TEST_CLASS {
private:
CRC_HandleTypeDef &hcrc;

// Peripherals
Platform::SPI accel;
Platform::SPI gyro;
Platform::SPI bmp;
Platform::SPI flash;

// Sensors and Flash
Platform::GD5F1GQ5XE flash_dev;
Platform::BMP581 bmp581_dev;
Platform::BMI088 bmi088_dev;
std::array<Platform::Sensor*, NUM_SENSORS> sensors;

// Runtime State
SemaphoreHandle_t packet_mutex = xSemaphoreCreateMutex();
Platform::Packet packet = Platform::Packet();
volatile bool save_to_flash = false;
lfs_file_t packet_file;

int32_t fs_size = 0;
uint32_t boot_count = 0;
uint32_t file_size = 0;

// Task attributes
TaskHandle_t sensor_task_handle = NULL;
TaskHandle_t flash_task_handle = NULL;
// Tasks
static void sensor_task(void *argument) {
auto *self = static_cast<TEST_CLASS*>(argument);
self->sensor_loop();
}

static void flash_task(void *argument) {
auto *self = static_cast<TEST_CLASS*>(argument);
self->flash_loop();
}
public:
TEST_CLASS(SPI_HandleTypeDef &hspi1, SPI_HandleTypeDef &hspi2, SPI_HandleTypeDef &hspi3, CRC_HandleTypeDef &hcrc)
: hcrc(hcrc),
accel(&hspi1, IMU2_ACC_CS_GPIO_Port, IMU2_ACC_CS_Pin),
gyro(&hspi1, IMU2_GYRO_CS_GPIO_Port, IMU2_GYRO_CS_Pin),
bmp(&hspi2, BAR1_CS_GPIO_Port, BAR1_CS_Pin),
flash(&hspi3, FLASH_CS_GPIO_Port, FLASH_CS_Pin),

flash_dev(flash),
bmp581_dev(bmp),
bmi088_dev(accel, gyro),
sensors{&bmp581_dev, &bmi088_dev}
{
// Initialize sensors
for (auto& sensor : sensors) {
bool ready = 0;
for (int c = 0; c < 10; ++c) {
ready = sensor->init();
if (ready) break;
HAL_Delay(20000);
}
if (!ready) sensor = nullptr;
}

// Initialize flash
for (int c = 0; c < 3; ++c) {
if (flash_dev.init()) {
fs_size = flash_dev.mount();
if (fs_size >= 0) {
save_to_flash = true;
boot_count = flash_dev.bootcount(false);
file_size = flash_dev.open(&packet_file, "packets");
}
break;
}
HAL_Delay(5000);
}
Platform::log("Flash: %u (size), %u (boot), %u (packet_size)\r\n", fs_size, boot_count, file_size);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I still don't really like this method of setting things up. I'd rather see tasks completely isolated rather than share a class for initialization. This is kinda the setup I have in mind:
In platform:
sensor task and init high level is written here. Shouldn't really have device specific code, can assume FreeRTOS and STM32 is used though.
In Hephaestus:
Any device specific functions needed for the task. This might be where we do stuff with specific pins for example, you use an LED for the sensor loop.

In the actual device_init function we would then have FlashTask::Init() which would handle the scheduling of the task. The idea here is to keep device-init.cpp clean, and to keep applications compartmentalized.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Lets get the cpp-migration merged first for this and common-drivers, then work on the task abstraction. Mahir is gonna yell at me if I stuff more abstractions in...

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

fair enough, that's fine with me

@dmanslick dmanslick Aug 24, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I agree with most of Nathan's proposal here, I also think tasks should be isolated units. However, I disagree with moving the Sensor Task into common. The sensors that each board is polling will be different, so a common Sensor Task will basically become a become a god class/object, not ideal.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

How does that look though? If we made an individual sensor task for every sensor, we'd have a lot of boilerplate. Additionally we want to read all sensors at the same time to ensure the timestamp is accurate for everything. I think we can make a truly general sensor task by making it take the list of sensors on init and having a couple functions that are defined for each device? Some of those might be things like NotifyFlashTask and GetTimestamp.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The current sensor task just does this

        for (auto *sensor : sensors)
          if (sensor != nullptr) sensor->read(packet);

It takes a list of the sensors it wants and just loop over it. It doesn't really care about what sensors are available, just what sensors is currently in the array

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Of course it also does a bit of other stuff like semaphores, checksums, and notifying the flash task. Anyways, I did want more discussion on task abstractions which is why I wanted to punt this to another PR.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@ncorrea210 You misunderstood what I wrote. I was not saying to have a task for each sensor. Doesn't matter anyways since the way I was thinking the task would've been implemented was a bit foolish anyways, what Ivan just wrote makes sense so I can see how it can be in common,

Comment thread Core/Src/device-init.cpp
Comment on lines +162 to +167
void disable_flash() {
if (save_to_flash) {
save_to_flash = false;
vTaskNotifyGiveFromISR(flash_task_handle, NULL);
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

is this function guaranteed to only be called in an ISR context? It can be dangerous to use FromISR functions in a non-ISR context. See this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, this is guaranteed to only be called from ISR, similarly non-ISR functions should not be called in ISR-context so it goes both ways.

Comment thread Core/Src/device-init.cpp
Comment on lines +171 to +172
xTaskCreate(flash_task, "flash task", 512, this, 1, &flash_task_handle);
xTaskCreate(sensor_task, "sensor task", 256, this, 2, &sensor_task_handle);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Might be good to look into using xTaskCreateStatic so there aren't any heap allocations. Probably not super important though.

Note that this requires the cpp branch of CommonDrivers to be merged
@wispl
wispl force-pushed the cpp-commondrivers branch from ccc187e to 60fd547 Compare August 25, 2026 13:21
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.

3 participants