![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
A cute tiny piece of code implementing an IoT NAND device, demonstrating how to setup and advertise a cute GATT (NAND) service. The code has been tested on a Nordic nRF51822-DK.
Dependencies: BLE_API mbed nRF51822
Fork of BLE_HeartRate_IDB0XA1 by
bricks/characteristic.h@26:dce30a5341bb, 2018-05-19 (annotated)
- Committer:
- hux
- Date:
- Sat May 19 14:10:17 2018 +0000
- Revision:
- 26:dce30a5341bb
Published
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
hux | 26:dce30a5341bb | 1 | // characteristic.h - an easy to use overloaded characteristic class |
hux | 26:dce30a5341bb | 2 | // |
hux | 26:dce30a5341bb | 3 | // Synopsis: |
hux | 26:dce30a5341bb | 4 | // |
hux | 26:dce30a5341bb | 5 | // Characteristic<type> myCharacteristic(col,uuid,mode); |
hux | 26:dce30a5341bb | 6 | // Characteristic<type> myCharacteristic(col,uuid,mode,name); |
hux | 26:dce30a5341bb | 7 | // Characteristic<type> myCharacteristic(col,uuid,mode,name,inidata); |
hux | 26:dce30a5341bb | 8 | // Characteristic<type> myCharacteristic(col,uuid,mode,inidata); |
hux | 26:dce30a5341bb | 9 | // |
hux | 26:dce30a5341bb | 10 | // Declaration of a characteristic, specifying value type, UUID and access mode, |
hux | 26:dce30a5341bb | 11 | // optionally providing a name (user descriptor) and initial data. |
hux | 26:dce30a5341bb | 12 | // |
hux | 26:dce30a5341bb | 13 | // col: Collection, to which the constructed characteristic is automati- |
hux | 26:dce30a5341bb | 14 | // cally added. After construction and adding all characteristics to |
hux | 26:dce30a5341bb | 15 | // a collection this collection is passed to a service constructor, |
hux | 26:dce30a5341bb | 16 | // which gets thus knowledge about all characteristics which have to |
hux | 26:dce30a5341bb | 17 | // be involved in the service |
hux | 26:dce30a5341bb | 18 | // |
hux | 26:dce30a5341bb | 19 | // uuid: A unique universal ID which identifies the characteristic |
hux | 26:dce30a5341bb | 20 | // |
hux | 26:dce30a5341bb | 21 | // mode: A string comprising zero or more mode characters which |
hux | 26:dce30a5341bb | 22 | // define possible properties of the characteristic. |
hux | 26:dce30a5341bb | 23 | // |
hux | 26:dce30a5341bb | 24 | // "" no properties |
hux | 26:dce30a5341bb | 25 | // "b" broadcast |
hux | 26:dce30a5341bb | 26 | // "r" read access |
hux | 26:dce30a5341bb | 27 | // "s" send & pray (write without response) |
hux | 26:dce30a5341bb | 28 | // "w" write access (with feedback) |
hux | 26:dce30a5341bb | 29 | // "n" notification (no client confirmation) |
hux | 26:dce30a5341bb | 30 | // "i" indication (with client confirmation) |
hux | 26:dce30a5341bb | 31 | // "a" authentication signed write |
hux | 26:dce30a5341bb | 32 | // "x" extended access |
hux | 26:dce30a5341bb | 33 | // |
hux | 26:dce30a5341bb | 34 | // name: An optional name provided in terms of a user descriptor. If this |
hux | 26:dce30a5341bb | 35 | // argument is omitted the user descriptor is not created. |
hux | 26:dce30a5341bb | 36 | // |
hux | 26:dce30a5341bb | 37 | // inidata: A pointer to a variable containing initializing data for the |
hux | 26:dce30a5341bb | 38 | // characteristic. If the inidata argument is not provided, an |
hux | 26:dce30a5341bb | 39 | // implicit initialization is performed which clears the characte- |
hux | 26:dce30a5341bb | 40 | // ristic (all bytes set to 0). As a concluding remark it needs to |
hux | 26:dce30a5341bb | 41 | // be noted that the implicite initialozation works only for |
hux | 26:dce30a5341bb | 42 | // sizeof(Type) <= SIZE_INIBUFFER (defined in "bricks/types.h") |
hux | 26:dce30a5341bb | 43 | // |
hux | 26:dce30a5341bb | 44 | // |
hux | 26:dce30a5341bb | 45 | // Example 1: A protocol might be declared as a class as follows |
hux | 26:dce30a5341bb | 46 | // |
hux | 26:dce30a5341bb | 47 | // Collection col; // collection used during setup |
hux | 26:dce30a5341bb | 48 | // |
hux | 26:dce30a5341bb | 49 | // Characteristic<ObjectId> id(col,0x2AC3,"rw","ID"); |
hux | 26:dce30a5341bb | 50 | // Characteristic<ObjectName> name(col,0x2ABE,"rw","Name"); |
hux | 26:dce30a5341bb | 51 | // Characteristic<Digital> presence(col,0x2A56,"r","Presence"); |
hux | 26:dce30a5341bb | 52 | // |
hux | 26:dce30a5341bb | 53 | // Service presenceDetection(col,0xA001); // instantiate service |
hux | 26:dce30a5341bb | 54 | // |
hux | 26:dce30a5341bb | 55 | // onSetup(Blob &blue) |
hux | 26:dce30a5341bb | 56 | // { |
hux | 26:dce30a5341bb | 57 | // blue.service(presenceDetection); // add service |
hux | 26:dce30a5341bb | 58 | // } |
hux | 26:dce30a5341bb | 59 | // |
hux | 26:dce30a5341bb | 60 | // Example 2: service definition by means of a service definition class |
hux | 26:dce30a5341bb | 61 | // |
hux | 26:dce30a5341bb | 62 | // class PresenceDetector |
hux | 26:dce30a5341bb | 63 | // { |
hux | 26:dce30a5341bb | 64 | // public: |
hux | 26:dce30a5341bb | 65 | // Collection col; // collection used during setup |
hux | 26:dce30a5341bb | 66 | // |
hux | 26:dce30a5341bb | 67 | // Characteristic<ObjectId> id; // ID of presence detector |
hux | 26:dce30a5341bb | 68 | // Characteristic<ObjectName> name; // name of presence detector |
hux | 26:dce30a5341bb | 69 | // Characteristic<Digital> presence; // digital presence value |
hux | 26:dce30a5341bb | 70 | // Characteristic<DateTime> timestamp; // last detection change's time |
hux | 26:dce30a5341bb | 71 | // Characteristic<ObjectName> layout; // name of model railway layout |
hux | 26:dce30a5341bb | 72 | // |
hux | 26:dce30a5341bb | 73 | // Service presenceDetection; // the service |
hux | 26:dce30a5341bb | 74 | // |
hux | 26:dce30a5341bb | 75 | // public: |
hux | 26:dce30a5341bb | 76 | // PresenceDetector(Blob &blue, cost UUID uuid) : |
hux | 26:dce30a5341bb | 77 | // list; // init service list |
hux | 26:dce30a5341bb | 78 | // id(list,0x2AC3,"rw","ID"), // instantiate characteristic |
hux | 26:dce30a5341bb | 79 | // name(list,0x2ABE,"rw","Name"), // instantiate characteristic |
hux | 26:dce30a5341bb | 80 | // presence(list,0x2A56,"r","Presence"),// instantiate characteristic |
hux | 26:dce30a5341bb | 81 | // timestamp(list,0x2A08,"r","Timestamp"),// instantiate characteristic |
hux | 26:dce30a5341bb | 82 | // layout(list,0x2ABE,"rw","Layout"), // instantiate characteristic |
hux | 26:dce30a5341bb | 83 | // presenceDetection(list,uuid) // instantiate service |
hux | 26:dce30a5341bb | 84 | // { |
hux | 26:dce30a5341bb | 85 | // blue.service(presenceDetection); // add service |
hux | 26:dce30a5341bb | 86 | // } |
hux | 26:dce30a5341bb | 87 | // }; |
hux | 26:dce30a5341bb | 88 | // |
hux | 26:dce30a5341bb | 89 | #ifndef _CHARACTERISTIC_H_ |
hux | 26:dce30a5341bb | 90 | #define _CHARACTERISTIC_H_ |
hux | 26:dce30a5341bb | 91 | |
hux | 26:dce30a5341bb | 92 | #include "ble/BLE.h" |
hux | 26:dce30a5341bb | 93 | #include "ble/Gap.h" |
hux | 26:dce30a5341bb | 94 | #include "bricks/types.h" |
hux | 26:dce30a5341bb | 95 | #include "bricks/collection.h" |
hux | 26:dce30a5341bb | 96 | #include "bricks/descriptor.h" |
hux | 26:dce30a5341bb | 97 | |
hux | 26:dce30a5341bb | 98 | // the following #define is helpful if characteristics are defined on base |
hux | 26:dce30a5341bb | 99 | // of the BLE API (the tedious way) |
hux | 26:dce30a5341bb | 100 | |
hux | 26:dce30a5341bb | 101 | #define UserDescriptor(name,attribute,descriptor,text) \ |
hux | 26:dce30a5341bb | 102 | static char *name = text; \ |
hux | 26:dce30a5341bb | 103 | static GattAttribute attribute(0x2901,(uint8_t*)name,strlen(name),strlen(name)); \ |
hux | 26:dce30a5341bb | 104 | static GattAttribute *descriptor[] = {&attribute}; |
hux | 26:dce30a5341bb | 105 | |
hux | 26:dce30a5341bb | 106 | // the declaration of Characteristics needs the availability of an |
hux | 26:dce30a5341bb | 107 | // initializing buffer in the default case |
hux | 26:dce30a5341bb | 108 | |
hux | 26:dce30a5341bb | 109 | extern IniBuffer characteristicInidata; // to initialize a characteristic |
hux | 26:dce30a5341bb | 110 | |
hux | 26:dce30a5341bb | 111 | // class definition of a characteristic initializer |
hux | 26:dce30a5341bb | 112 | |
hux | 26:dce30a5341bb | 113 | class CharacteristicInitializer // provides pointers to initialized data |
hux | 26:dce30a5341bb | 114 | { |
hux | 26:dce30a5341bb | 115 | private: |
hux | 26:dce30a5341bb | 116 | IniBuffer inibuf; // initialized data |
hux | 26:dce30a5341bb | 117 | |
hux | 26:dce30a5341bb | 118 | public: |
hux | 26:dce30a5341bb | 119 | ObjectId *pObjectId() { return (ObjectId*) &inibuf; } |
hux | 26:dce30a5341bb | 120 | ObjectName *pObjectName() { return (ObjectName*) &inibuf; } |
hux | 26:dce30a5341bb | 121 | Bool *pBool() { return (Bool*) &inibuf; } |
hux | 26:dce30a5341bb | 122 | Digital *pDigital() { return (Digital*) &inibuf; } |
hux | 26:dce30a5341bb | 123 | DateTime *pDateTime() { return (DateTime*) &inibuf; } |
hux | 26:dce30a5341bb | 124 | Buffer *pBuffer() { return (Buffer*) &inibuf; } |
hux | 26:dce30a5341bb | 125 | |
hux | 26:dce30a5341bb | 126 | public: |
hux | 26:dce30a5341bb | 127 | CharacteristicInitializer() // constructor |
hux | 26:dce30a5341bb | 128 | { |
hux | 26:dce30a5341bb | 129 | memset(inibuf,0,sizeof(IniBuffer)); |
hux | 26:dce30a5341bb | 130 | |
hux | 26:dce30a5341bb | 131 | // besides of the local inibuf also initialize the global |
hux | 26:dce30a5341bb | 132 | // init buffer characteristicInidata; |
hux | 26:dce30a5341bb | 133 | |
hux | 26:dce30a5341bb | 134 | memset(characteristicInidata,0,sizeof(IniBuffer)); |
hux | 26:dce30a5341bb | 135 | } |
hux | 26:dce30a5341bb | 136 | }; |
hux | 26:dce30a5341bb | 137 | |
hux | 26:dce30a5341bb | 138 | // definition of class Characteristic |
hux | 26:dce30a5341bb | 139 | |
hux | 26:dce30a5341bb | 140 | class Service; |
hux | 26:dce30a5341bb | 141 | |
hux | 26:dce30a5341bb | 142 | template <typename Type> |
hux | 26:dce30a5341bb | 143 | class Characteristic : public GattCharacteristic |
hux | 26:dce30a5341bb | 144 | { |
hux | 26:dce30a5341bb | 145 | private: |
hux | 26:dce30a5341bb | 146 | void init() // initialize inibuffer |
hux | 26:dce30a5341bb | 147 | { |
hux | 26:dce30a5341bb | 148 | static int initialized = 0; |
hux | 26:dce30a5341bb | 149 | |
hux | 26:dce30a5341bb | 150 | if (!initialized) // clear init data buffer |
hux | 26:dce30a5341bb | 151 | { initialized = 1; |
hux | 26:dce30a5341bb | 152 | memset(characteristicInidata,0,sizeof(IniBuffer)); |
hux | 26:dce30a5341bb | 153 | } |
hux | 26:dce30a5341bb | 154 | } |
hux | 26:dce30a5341bb | 155 | |
hux | 26:dce30a5341bb | 156 | private: |
hux | 26:dce30a5341bb | 157 | UserDescriptor descriptor; // characteristic's user descriptor |
hux | 26:dce30a5341bb | 158 | |
hux | 26:dce30a5341bb | 159 | uint8_t getmask(const char *pmask) |
hux | 26:dce30a5341bb | 160 | { |
hux | 26:dce30a5341bb | 161 | uint8_t mask = 0; |
hux | 26:dce30a5341bb | 162 | |
hux | 26:dce30a5341bb | 163 | for(;*pmask;pmask++) |
hux | 26:dce30a5341bb | 164 | { switch (*pmask) |
hux | 26:dce30a5341bb | 165 | { |
hux | 26:dce30a5341bb | 166 | case 'b': // broad cast |
hux | 26:dce30a5341bb | 167 | mask = mask | BLE_GATT_CHAR_PROPERTIES_BROADCAST; |
hux | 26:dce30a5341bb | 168 | break; |
hux | 26:dce30a5341bb | 169 | case 'r': // read |
hux | 26:dce30a5341bb | 170 | mask = mask | BLE_GATT_CHAR_PROPERTIES_READ; |
hux | 26:dce30a5341bb | 171 | break; |
hux | 26:dce30a5341bb | 172 | case 's': // send (& pray) |
hux | 26:dce30a5341bb | 173 | mask = mask | BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE; |
hux | 26:dce30a5341bb | 174 | break; |
hux | 26:dce30a5341bb | 175 | case 'w': // write |
hux | 26:dce30a5341bb | 176 | mask = mask | BLE_GATT_CHAR_PROPERTIES_WRITE; |
hux | 26:dce30a5341bb | 177 | break; |
hux | 26:dce30a5341bb | 178 | case 'n': // notify |
hux | 26:dce30a5341bb | 179 | mask = mask | BLE_GATT_CHAR_PROPERTIES_NOTIFY; |
hux | 26:dce30a5341bb | 180 | break; |
hux | 26:dce30a5341bb | 181 | case 'i': // indicate |
hux | 26:dce30a5341bb | 182 | mask = mask | BLE_GATT_CHAR_PROPERTIES_INDICATE; |
hux | 26:dce30a5341bb | 183 | break; |
hux | 26:dce30a5341bb | 184 | case 'a': // authenticated signed write |
hux | 26:dce30a5341bb | 185 | mask = mask | BLE_GATT_CHAR_PROPERTIES_AUTHENTICATED_SIGNED_WRITES; |
hux | 26:dce30a5341bb | 186 | break; |
hux | 26:dce30a5341bb | 187 | case 'x': // extended properties |
hux | 26:dce30a5341bb | 188 | mask = mask | BLE_GATT_CHAR_PROPERTIES_EXTENDED_PROPERTIES; |
hux | 26:dce30a5341bb | 189 | break; |
hux | 26:dce30a5341bb | 190 | } |
hux | 26:dce30a5341bb | 191 | } |
hux | 26:dce30a5341bb | 192 | return mask; |
hux | 26:dce30a5341bb | 193 | } |
hux | 26:dce30a5341bb | 194 | /* |
hux | 26:dce30a5341bb | 195 | public: |
hux | 26:dce30a5341bb | 196 | Characteristic<Type> (Service &service, UUID uuid, const char *mode, |
hux | 26:dce30a5341bb | 197 | Type *valuePtr = (Type*)&characteristicInidata) : |
hux | 26:dce30a5341bb | 198 | GattCharacteristic(uuid, |
hux | 26:dce30a5341bb | 199 | reinterpret_cast<uint8_t*> (valuePtr), |
hux | 26:dce30a5341bb | 200 | sizeof(Type), |
hux | 26:dce30a5341bb | 201 | sizeof(Type), |
hux | 26:dce30a5341bb | 202 | getmask(mode), |
hux | 26:dce30a5341bb | 203 | NULL, // descriptor list |
hux | 26:dce30a5341bb | 204 | 0, // number of descriptors |
hux | 26:dce30a5341bb | 205 | false), |
hux | 26:dce30a5341bb | 206 | descriptor("") // construct descriptor |
hux | 26:dce30a5341bb | 207 | { |
hux | 26:dce30a5341bb | 208 | init(); // assure initializing |
hux | 26:dce30a5341bb | 209 | |
hux | 26:dce30a5341bb | 210 | // there is a potential danger that we use implicite initializing |
hux | 26:dce30a5341bb | 211 | // with sizeof(Type) > sizeof(inibuffer). This must be prevented! |
hux | 26:dce30a5341bb | 212 | |
hux | 26:dce30a5341bb | 213 | int feasible = (sizeof(Type) <= sizeof(IniBuffer)); |
hux | 26:dce30a5341bb | 214 | if (feasible || valuePtr != (Type*)&characteristicInidata) |
hux | 26:dce30a5341bb | 215 | { |
hux | 26:dce30a5341bb | 216 | service.add(this); // add to service |
hux | 26:dce30a5341bb | 217 | } // otherwise just ignore! |
hux | 26:dce30a5341bb | 218 | } |
hux | 26:dce30a5341bb | 219 | */ |
hux | 26:dce30a5341bb | 220 | public: |
hux | 26:dce30a5341bb | 221 | Characteristic<Type> (Service &service, UUID uuid, const char *mode, |
hux | 26:dce30a5341bb | 222 | const char *name, Type *valuePtr = (Type*)&characteristicInidata) : |
hux | 26:dce30a5341bb | 223 | GattCharacteristic(uuid, |
hux | 26:dce30a5341bb | 224 | reinterpret_cast<uint8_t*> (valuePtr), |
hux | 26:dce30a5341bb | 225 | sizeof(Type), |
hux | 26:dce30a5341bb | 226 | sizeof(Type), |
hux | 26:dce30a5341bb | 227 | getmask(mode), |
hux | 26:dce30a5341bb | 228 | descriptor.plist, // descriptor list |
hux | 26:dce30a5341bb | 229 | 1, // number of descriptors |
hux | 26:dce30a5341bb | 230 | false), |
hux | 26:dce30a5341bb | 231 | descriptor(name) // construct descriptor |
hux | 26:dce30a5341bb | 232 | { |
hux | 26:dce30a5341bb | 233 | init(); // assure initializing |
hux | 26:dce30a5341bb | 234 | |
hux | 26:dce30a5341bb | 235 | // there is a potential danger that we use implicite initializing |
hux | 26:dce30a5341bb | 236 | // with sizeof(Type) > sizeof(inibuffer). This must be prevented! |
hux | 26:dce30a5341bb | 237 | |
hux | 26:dce30a5341bb | 238 | int feasible = (sizeof(Type) <= sizeof(IniBuffer)); |
hux | 26:dce30a5341bb | 239 | if (feasible || valuePtr != (Type*)&characteristicInidata) |
hux | 26:dce30a5341bb | 240 | { |
hux | 26:dce30a5341bb | 241 | service.add(this); // add to service |
hux | 26:dce30a5341bb | 242 | } // otherwise just ignore! |
hux | 26:dce30a5341bb | 243 | } |
hux | 26:dce30a5341bb | 244 | }; |
hux | 26:dce30a5341bb | 245 | |
hux | 26:dce30a5341bb | 246 | |
hux | 26:dce30a5341bb | 247 | #endif // _CHARACTERISTIC_H_ |