Skip to content

refactor: sensors abstraction - #4

Open
wispl wants to merge 1 commit into
mainfrom
sensors-abstraction
Open

refactor: sensors abstraction#4
wispl wants to merge 1 commit into
mainfrom
sensors-abstraction

Conversation

@wispl

@wispl wispl commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

@wispl
wispl force-pushed the sensors-abstraction branch 2 times, most recently from bb87256 to 5f87fa0 Compare August 2, 2026 21:39
@wispl
wispl force-pushed the sensors-abstraction branch from 5f87fa0 to d437135 Compare August 2, 2026 21:52
@wispl

wispl commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator Author

Don't merge yet, just putting it here for early review

@dmanslick

Copy link
Copy Markdown

Looks good, assuming you just need to test this? Also, I feel like the "handle_as" functions would be better named "handle_get_as"

@ncorrea210

Copy link
Copy Markdown
Contributor

I guess I am just not 100% convinced yet that we need this level of abstraction for our sensors? Do we get a lot out of it in terms of maintainability and ease of understanding code? I wonder if it would be easier to just make specific implementations for each sensor, and let it be up to the device to determine how they want to use all that.

Comment thread include/defs.h
} uart;
struct handle_uart { UART_HandleTypeDef *handle; };

#define HANDLE_QSPI(handle) \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

HANDLE_UART?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch, should be handle QSPI

Comment thread include/defs.h
Comment on lines +52 to +66
#define HANDLE_SPI(in_handle, in_port, in_pin) \
(struct handle) { \
.protocol = SPI, \
.serial = { \
.spi = { \
.pin = (in_pin), \
.port = (in_port), \
.handle = (in_handle), \
} \
} \
};
#else
struct handle_spi { int placeholder; };
#define HANDLE_SPI(handle, port, pin) assert(0 & "SPI is not enabled!");
#endif

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not sure if I really love this HANDLE_SPI macro stuff. I think I see where you're coming from with having the stub implementation that would fail if someone in the device if struct handle_spi x = HANDLE_SPI(y,z,a), but unless a spi is explicitly configured from the .ioc file, there wouldn't be a well defined handle, or cs pin to add, to setup anyways? I think we are covering a case that is essentially impossible to run into.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I am still back and forth with the macro, you are right that compilation will not be allowed if we have an illdefined handle, but at the same time there is no error message shown indicating why. With the macro you get a clear message on why. I am willing to drop this if we think that is not an issue.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't really think it will be an issue because you would not be able to put the periphal as the handle like you would be expected to. If someone tried to do struct handle_spi bmi088 = { .... , .handle = &hspi1} there would be several failures, one of them being that there isn't even an spi1 to be a handle in the first place.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes, that is true. But the reason why you know that the compilation failed is due to missing modules is because you have worked on this before. For a new member they might assume that all modules are pulled in, or they might question why there isn't a SPI handle definition. That is not to say I am opposed to removing the macros.

Comment thread include/defs.h
Comment on lines +128 to +133
//// To create a handle, you MUST use the following methods
//// struct handle spi = HANDLE_SPI(&hspi1, port, pin);
//// struct handle i2c = HANDLE_I2C(&hi2c1, address);
//// struct handle uart = HANDLE_UART(&huart1);
//// struct handle qspi = HANDLE_QSPI(&hqspi);
//// Then you may pass the handle to the initialization function of a device.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I am not certain that this abstraction is needed.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

See previous comment.

Comment thread include/defs.h
Comment on lines +166 to +181
//// | Serial API Abstractions |
//// All serial protocols implement an API with the same write and read
//// functions, with differing implmentations of course. The serial api contains
//// the handle and is requested by a device in its initialization function.
////
//// See the currently provided drivers for an example. But the gist is
//// int8_t sensor_init(struct sensor_ctx *ctx, struct sensor *sensor, struct handle *handle)
//// {
//// assert(handle->protocol == SPI);
//// sensor->ctx = ctx;
//// sensor->read = sensor_read;
//// serial_api_spi(ctx->api, handle);
//// }
//// Of course you may decide to support multiple protocols if you wish, which
//// this abstraction makes really simple. You would pass `api` around and call
//// `api->write(...)` and `api->read(...)` for writing and reading respectively.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I appreciate the comments, they are very helpful (nothing to resolve I just want to say that I like them)

@ncorrea210

Copy link
Copy Markdown
Contributor

Just to be clear, I am by no means the architect of this code and you should talk to Dhruv about anything major with regard to that

@wispl

wispl commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator Author

The main pro of abstracting them to this thin api class is that we keep all the #ifdefs in one place. The sensors don't (and shouldn't) care about what protocol is used. With previous approaches one of the big issues was how to handle

  1. compilation error due to missing protocol (no SPI, or no UART)
  2. choosing between protocols (this is especially more difficult with flash)

This abstraction, to some degree, resolves 1. by collecting all #ifdefs and protocol definitions in one file, and 2. by allowing to simply use the api->read and api->write, which are defined by the protocol_api which you can just switch with another such struct to change which protocol is used.

On the point of maintainability and readability, we concretely defined three actions that every sensor/device has to do

  1. writes: for flash this is writing data or for a sensor this could be writing a register value
  2. reads: for both flash and sensor, this is reading values, either from a register or from the NAND
  3. command: this is usually for flash, which is to send a single command without expecting any further writes or reads

This means every implementation after can simply think of writes, reads, and commands rather than the actual HAL commands. Bosch has already done something similar with their own read and write callbacks, albeit it was mandatory on their part.

On maintainability, since this is the way every device/sensor communicates, we can have the implementation in a single place, with much more eyes on it, rather than the same implementation scattered across the codebase. Sorry for the long reply and rambling.

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