Skip to content
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

Unable to use heapless Vec in macros #196

Open
lulf opened this issue Dec 15, 2024 · 4 comments
Open

Unable to use heapless Vec in macros #196

lulf opened this issue Dec 15, 2024 · 4 comments

Comments

@lulf
Copy link
Member

lulf commented Dec 15, 2024

I'm trying to use a service like this:

#[gatt_service(uuid = "FE59")]
pub struct NrfDfuService {
    #[characteristic(uuid = "8EC90001-F315-4F60-9FB8-838830DAEA50", write, notify)]
    control: Vec<u8, ATT_MTU>,

    /// The maximum size of each packet is derived from the Att MTU size of the connection.
    /// The maximum Att MTU size of the DFU Service is 256 bytes (saved in NRF_SDH_BLE_GATT_MAX_MTU_SIZE),
    /// making the maximum size of the DFU Packet characteristic 253 bytes. (3 bytes are used for opcode and handle ID upon writing.)
    #[characteristic(uuid = "8EC90002-F315-4F60-9FB8-838830DAEA50", write_without_response, notify)]
    packet: Vec<u8, ATT_MTU>,
}

And when trying to read values using server.get(handle), I'm getting an error of InvalidValue. Closer inspection reveals that macros use size_of<Vec<u8, ATT_MTU>> to calculate the storage size, which I think is wrong. It should instead store the data as the given type rather than a byte slice, and hand in the 'byte representation' to the AttributeData (at least I think that should work).

@jamessizeland
Copy link
Collaborator

I can look at this as part of my rework of the macro, I've made some improvements there to accommodate the default value option.

@jamessizeland
Copy link
Collaborator

This seems to work for heapless Vec and other types.

static #name_screaming: static_cell::StaticCell<[u8; size_of::<#ty>()]> = static_cell::StaticCell::new();
                let store = #name_screaming.init(Default::default());
                let mut val = <#ty>::default(); // constrain the type of the value here
                val = #default_value; // update the temporary value with our new default
                let bytes = GattValue::to_gatt(&val);
                store[..bytes.len()].copy_from_slice(bytes);
                let mut builder = service
                    .add_characteristic(#uuid, &[#(#properties),*], store);

@lulf
Copy link
Member Author

lulf commented Dec 16, 2024

I think one problem with that solution is that the actual number of bytes written to the Vec is forgotten, so that when you read the Vec from code, it will have the full size of the slice, and not the actual 'used' size which is what you'd get with nrf-softdevice. Ideally, the Vec would be resized based on the attribute write. I think maybe we need some way for the attribute/attribute_server to 'convert' the raw data to the appropriate type when writing.

@jamessizeland
Copy link
Collaborator

I see what you mean. I wonder if the store type itself should be a heapless Vec. I'll have another look at how softdevice solves this.

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

No branches or pull requests

2 participants