Using the BLEPeripheral library, my Arduino Zero (TinyScreen+) smartwatch successfully retrieves Notification Source characteristics, but I wanted to take it a step further to retrieve some of the Notification Attributes (in this case the title). I know I'm getting the Data Source response, but I suspect that I'm not "parsing" the data correctly because my output is truncated severely: the output only contains the 5th to 12th characters (out of a possible 14). I hope to get the TS+ to display the title to a max of 20 characters (including the null termination). Here is the relevant code:
char notificationLine2[20] = ""; //declaration of global variable for the output
struct AncsAttributes { //for the Data Source response
unsigned char commandId;
unsigned long notificationUid;
unsigned char attributeId;
unsigned short attributeLen;
char attributeValue[20];
};
void ancsNotificationSourceCharacteristicValueUpdated(BLECentral& central, BLERemoteCharacteristic& characteristic) {
//...
unsigned long uid = notification.notificationUid; //construction of Control Point request
byte buffer[8];
buffer[0] = 0;
buffer[4] = (uid >> 24) & 0xFF;
buffer[3] = (uid >> 16) & 0xFF;
buffer[2] = (uid >> 8) & 0xFF;
buffer[1] = uid & 0xFF;
buffer[5] = 1;//ANCS_NOTIFICATION_ATTRIBUTE_TITLE;
buffer[6] = 19; //ANCS_NOTIFICATION_ATTRIBUTE_TITLE;
buffer[7] = 0; //ANCS_NOTIFICATION_ATTRIBUTE_TITLE;
ancsControlPointCharacteristic.write((const unsigned char*)buffer, 8);
}
void ancsDataSourceCharacteristicCharacteristicValueUpdated(BLECentral& central, BLERemoteCharacteristic& characteristic) {
struct AncsAttributes attributeList;
memcpy(&attributeList, characteristic.value(), sizeof(attributeList));
strcpy(notificationLine2, attributeList.attributeValue);
notificationLine2[19] = '\0';
}
Suggestion:
Not sure if this is what bites you but when dealing with structures, the standard does not guarantee the compiler won't move attributes around to gain better byte boundary alignement (architecture dependent) to optimize data access for example.
So when you use memcpy() with data organized the way you think it is (maybe coming from somewhere else through BT) and force fill in the data, if the compiler played tricks on you, you are toast!
Luckily C++ offers an option to inform the compiler to not mess around with what you have done.
Sometimes you can coerce your compiler into not using the processor’s normal alignment rules by using a pragma, usually #pragma pack. GCC and clang have an attributepacked you can attach to individual structure declarations; GCC has an -fpack-struct option for entire compilations.
Do not do this casually, as it forces the generation of more expensive and slower code.
Thanks for the quick response! characteristic.value holds the response from the Data source. I don't think I could rework the struct to account for padding because the attributes from the DS are given in a particular order. Your suggestion worked in that the first few chars are no longer cut off. It still outputs only 12 chars though. That's something I'll leave for another day