Sending an int16 Array via BLE Notification

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
Anonymous
Not applicable

Sorry to open a new question while I still have one open ("Did I Fry my Op Amps?"), but I have to figure out quite a few things in a relatively short period of time.

   

 

   

I want to send an array of three int16 values from my PSoC device to a GATT client via a notification. I will eventually want to update these values in the GATT DB too, for client reads, but I'm just trying to get the notifications working for now.

   

 

   

All the examples I've seen so far only send a single uint8 value over notifications (although I have seen some code for writing a uint8 array to the GATT DB), but when I try to modify these to work with my int16 array, I always get the following warning:

   

 

   

incompatible pointer types assigning to 'uint8*'  (aka 'unsigned char *') from 'int16 (*)[3]'

   

 

   

I've dug around in the BLE generated code and API docs, but I haven't yet found the solution to this issue. I'm pretty sure it has to do with my poor understanding of pointers (*), addresses (&), handles and so forth. I thought I was setting the type of data in the custom characteristic window of the BLE component, but I now see that I was only changing the data format of "New field."

   

 

   

I don't really have a project complete enough to post yet, but here is a  snippet of code where I am getting the above warning. Any thoughts on how to accomplish what I am trying to do would be most helpful.

   

 

   

Thanks,

   

Don

   

 

   

 

   

        CYBLE_GATTS_HANDLE_VALUE_NTF_T      notificationHandle;

   

    

   

        if (weightsNotification & 0x01) {

   

 

   

            // update notification with new data

   

            notificationHandle.attrHandle = WEIGHTS_CHAR_HANDLE;

   

            notificationHandle.value.val = &weightsArray;

   

            notificationHandle.value.len = WEIGHTS_CHAR_DATA_LEN;

   

 

   

            // Report data to BLE component for sending data by notifications

   

            CyBle_GattsNotification(cyBle_connHandle, &notificationHandle);

   

        }

   
        
0 Likes
1 Solution
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

You could cast your pointer to the values into a (void*), but probably the "&" is wrong in this case when weightsArray is declared as something like

   

uint8 weightsArray[number]

   

Then weightsArray is already the address of the array. So the code should be

   

notificationHandle.value.val = (void *) weightsArray;

   

 

   

Bob

View solution in original post

0 Likes
17 Replies
Anonymous
Not applicable

 Specifically, this is the line where I am getting the warning...

   

 

   

notificationHandle.value.val = &weightsArray;

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

You could cast your pointer to the values into a (void*), but probably the "&" is wrong in this case when weightsArray is declared as something like

   

uint8 weightsArray[number]

   

Then weightsArray is already the address of the array. So the code should be

   

notificationHandle.value.val = (void *) weightsArray;

   

 

   

Bob

0 Likes
HeLi_263931
Level 8
Level 8
100 solutions authored 50 solutions authored 25 solutions authored

It actually doesn#t matter whether you use '&' or not - the result is the same. Just using weightArray return the address of the first element, and using &weightArray return the address of the array - and both are the same.

   

But you still need the cast, since an int16 array and a uint8 array are something different.

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

@hli

   

I've learnt something different: take the definition

   

uint8 MyArray{7];

   

then MyArray is the same as &MyArray[0]

   

&MyArray is then equal to &&MyArray{0] which actually gives a pointer to a pointer to an uint8

   

 

   

Bob

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

Does this jive with your interpretation ?

   

 

   

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

No offending, but me and my translator are poor in idioms, what exactly do you mean to say, Dana?

   

 

   

Bob

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

That the address produced for all 3 typings are the same.

   

 

   

The statement pointer to a pointer would imply one pointer

   

occupied the element of interest location ?

   

 

   

Regards, Dana.

0 Likes
HeLi_263931
Level 8
Level 8
100 solutions authored 50 solutions authored 25 solutions authored

Actually I just learned that 'weightArray' and '&weightArray' not 100% equivalent. They differ in their data types - the former is a pinter to a single element (*int16), the latter is a pointer to an array (*int16[]). See http://publications.gbdirect.co.uk/c_book/chapter5/arrays_and_address_of.html

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

And I admit that I'm a bit dissapointed about the GNU CC:

   

instead of throwing en error "Invalid rvalue" in a line like

   

Ptr = &weightArray;

   

The actual compiler accepts this and interprets it as (verified in code) Ptr = weightArray

   

The above error should be thrown because the intermediate result for "weightArray" does not exist as a variable that can be referenced with "&".

   

 

   

OK so far:

   

§1: The compiler is always right!

   

§2: If compiler is not right, automatically §1 has to be applied

   

   

 

   

Bob

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

Just red and verified hli's post here and will agree that this is an exception of the normal use of the "&"-operator (sigh, I like exceptions)

   

 

   

Bob

0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

I like a language that is considered "strongly typed" that is not

   

strongly typed. But in ptr arithmetic the article makes it clear

   

it will work anyways.

   

 

   

Regards, Dana.

0 Likes
Anonymous
Not applicable

 After getting the rest of my code to work, I can verify that the void pointer (void*) did the trick for sending int16 arrays over BLE notifications. notificationHandle.value.val was looking for uint8 values. I guess you could go into the generated API code to edit that, but the void pointer inserted it just fine. In Little Endian, which I hear is BLE standard for values more than one byte in size, but fine nonetheless.

   

 

   

Don

0 Likes
Bob_Marlowe
Level 10
Level 10
First like given 50 questions asked 10 questions asked

I have to admit that using (void *) is a brute force method. There is no checking of the target type done by the compiler, just accept and be quite. During hot testing phase I use that and I use that too, when I want to conceil definitions (in libraries) or hinder the access to structure members.

   

I would suggest you, as you already mentioned, to change the target's declaration into a comparable type (like a pointer to an array of int16 or uint16) to get, well, "conformity". Nothing that you get money from, but just for the sake of it.

   

 

   

Bob

0 Likes
Anonymous
Not applicable

I wanted to update this because the answer may have been embarrassingly simple.

   

 

   

This threw a warning and also wrote bad values into the GATT dB

   

notificationHandle.value.val = &weightsArray;

   

 

   

This worked, but as Bob Marlowe pointed out, is a brute force method

   

notificationHandle.value.val = (void*)weightsArray;

   

 

   

Since notificationHandle.value.val wants a uint8, I tried the following and it worked

   

notificationHandle.value.val = (uint8*)weightsArray;

   

 

   

The PSoC 4 BLE obviously has way more than 256 memory addresses but maybe there is a separate, smaller area devoted to the GATT dB. Thoughts?

0 Likes
HeLi_263931
Level 8
Level 8
100 solutions authored 50 solutions authored 25 solutions authored

The cast to uint8* has nothing to do with the length of the array tha pointer is pointing to. It just denotes what is _inside_ of the array (e.g. how long is one entry).

Anonymous
Not applicable

So the BLE stack, or at least the CYBLE_GATTS_HANDLE_VALUE_NTF_T structure, wants everything reduced to a series uint8 bytes? Was I just lucky that the uint8* cast got the endianness right?

   

 

   

Thank you. I will figure this stuff out eventually. 

0 Likes
HeLi_263931
Level 8
Level 8
100 solutions authored 50 solutions authored 25 solutions authored

uint8* means byte-wise access (an uint8 is 8 bits, so its one byte). Its a way for the API to say "just give me what you have, I don't really care about what in there" (except when the data really is just uint8's).

   

Endianess doesn't play a role here - the data gets transferred from memory as it is, and the other side needs to care about how to resolve it.

   

(In my project I even transfer more than 256 bytes in a notification, but the data in there really is just uint8)

0 Likes