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 ST

Files at this revision

API Documentation at this revision

Comitter:
hux
Date:
Sat May 19 14:10:17 2018 +0000
Parent:
25:339931243be4
Commit message:
Published

Changed in this revision

bricks/advertise.h Show annotated file Show diff for this revision Revisions of this file
bricks/blob.h Show annotated file Show diff for this revision Revisions of this file
bricks/bricks.h Show annotated file Show diff for this revision Revisions of this file
bricks/callback.cpp Show annotated file Show diff for this revision Revisions of this file
bricks/callback.h Show annotated file Show diff for this revision Revisions of this file
bricks/characteristic.cpp Show annotated file Show diff for this revision Revisions of this file
bricks/characteristic.h Show annotated file Show diff for this revision Revisions of this file
bricks/collection.h Show annotated file Show diff for this revision Revisions of this file
bricks/descriptor.h Show annotated file Show diff for this revision Revisions of this file
bricks/enroll.h Show annotated file Show diff for this revision Revisions of this file
bricks/get.h Show annotated file Show diff for this revision Revisions of this file
bricks/init.cpp Show annotated file Show diff for this revision Revisions of this file
bricks/init.h Show annotated file Show diff for this revision Revisions of this file
bricks/o.h Show annotated file Show diff for this revision Revisions of this file
bricks/print.h Show annotated file Show diff for this revision Revisions of this file
bricks/service.h Show annotated file Show diff for this revision Revisions of this file
bricks/set.h Show annotated file Show diff for this revision Revisions of this file
bricks/sleep.h Show annotated file Show diff for this revision Revisions of this file
bricks/target.h Show annotated file Show diff for this revision Revisions of this file
bricks/trace.cpp Show annotated file Show diff for this revision Revisions of this file
bricks/trace.h Show annotated file Show diff for this revision Revisions of this file
bricks/types.h Show annotated file Show diff for this revision Revisions of this file
bricks/updated.h Show annotated file Show diff for this revision Revisions of this file
diff -r 339931243be4 -r dce30a5341bb bricks/advertise.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/advertise.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,114 @@
+// advertise.h - begin peripheral role and start advertising
+//
+// Synopsis:
+//
+//    advertise(O&o);           
+//    advertise(O&o, const char *mode, int ms = 100);
+//
+//    payload(O&o,const char *mode)       // set advertising payload
+//
+// Arguments:
+//
+//    o:     Blob object (to avoid name clashes)
+//    mode:  String containing a sequence of mode characters defining both
+//           advertising type (upper case characters) and advertising flags 
+//           (lower case characters), some of which have meaning, all others
+//           are ignored and can be used for spacing (e.g. ':', ' ', '-', ...)
+//    ms:    Advertising interval in mili seconds (default 100 ms)
+//
+// Advertising Type 
+//
+//    C:    ADV_CONNECTABLE_UNDIRECTED
+//    D:    ADV_CONNECTABLE_DIRECTED
+//    S:    ADV_SCANNABLE_UNDIRECTED
+//    N:    ADV_NON_CONNECTABLE_UNDIRECTED
+//
+// Advertising Flags:
+//
+//    l:   LE Limited Discoverable Mode           (value: 0x01)
+//    g:   LE General Discoverable Mode           (value: 0x02)
+//    n:   BR/EDR Not Supported                   (value: 0x04)
+//    c:   Controller: simultaneous LE & BR/EDR   (value: 0x08)
+//    h:   Host: Simultaneous LE & BR/EDR         (value: 0x10)
+//    
+// Examples 1: Start advertising in peripheral role with type 'connectable, uni-
+// directed, and flags 'BR/EDR Not Supported', 'LE General Discoverable Mode'
+//
+//    advertise(o,"C:ng",100);   // start advertising @ 100 msec interval
+//    advertise(o,"Cng",100);    // same as above
+//    advertise(o,"gCn",100);    // same as above
+//
+// Examples 2: Start advertising in peripheral role with type 'connectable,
+// directed, and flags 'LE Limited Discoverable Mode'
+//
+//    advertise("D:l",100)       // Connectable Directed, limited discoverable
+//
+// Examples 3: A typical peripheral advertising session starts with setup of
+// device name, advertising name and advertising data.
+//
+//    device(o,"Smart Button");        // setup device name
+//    name(o,"Smart Button #1");       // setup advertising name
+//    data(o,"My Home");               // setup advertising data
+//    advertise(o,"C:ng",100);         // start advertising @ 100 msec interval
+//
+// Example 4: restart advertising based on pre-defined advertising payload
+//
+//
+// See also: SERVICE
+//
+#ifndef _ADVERTISE_H_
+#define _ADVERTISE_H_
+
+#include "bricks/blob.h"
+#include "bricks/trace.h"
+
+#define _GADAT GapAdvertisingData
+#define _GAPAR GapAdvertisingParams
+
+
+   inline void payload(O&o,const char *p)   // Set advertising type and flags
+   {
+      _GAPAR::AdvertisingType_t typ = _GAPAR::ADV_CONNECTABLE_UNDIRECTED;
+      uint8_t mask = 0x00;
+      
+      for (;*p; p++)
+      {
+          switch (*p)
+          {
+             case 'l':  mask = mask | _GADAT::LE_LIMITED_DISCOVERABLE;  break;
+             case 'g':  mask = mask | _GADAT::LE_GENERAL_DISCOVERABLE;  break;
+             case 'n':  mask = mask | _GADAT::BREDR_NOT_SUPPORTED;      break;
+             case 'c':  mask = mask | _GADAT::SIMULTANEOUS_LE_BREDR_C;  break;
+             case 'h':  mask = mask | _GADAT::SIMULTANEOUS_LE_BREDR_H;  break;
+                
+             case 'C':  typ = _GAPAR::ADV_CONNECTABLE_UNDIRECTED;       break;
+             case 'D':  typ = _GAPAR::ADV_CONNECTABLE_DIRECTED;         break;
+             case 'S':  typ = _GAPAR::ADV_SCANNABLE_UNDIRECTED;         break;
+             case 'N':  typ = _GAPAR::ADV_NON_CONNECTABLE_UNDIRECTED;   break;
+          }
+      }
+      
+      o.gap().setAdvertisingType(typ);
+      o.gap().accumulateAdvertisingPayload(mask);
+   }
+
+
+   inline void advertise(O&o)          // start advertising
+   {
+      o.gap().startAdvertising();      // start advertising
+      trace(o,2,"<advertising>\n");
+   }
+
+   inline void advertise(O&o, int ms)  // start advertising (msec: periode)
+   {
+      o.gap().setAdvertisingInterval(ms);
+      advertise(o);                    // start advertising
+   }
+
+   inline void advertise(Blob &o, const char *mode, int ms = 100)
+   {
+      payload(o,mode);                 // set advertising payload type & mask
+      advertise(o,ms);                 // start advertising
+   }
+
+#endif // _ADVERTISE_H_
\ No newline at end of file
diff -r 339931243be4 -r dce30a5341bb bricks/blob.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/blob.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,59 @@
+// blob.h - 'BLOBs' are BLuetooth OBjects
+#ifndef _BLOB_H_
+#define _BLOB_H_
+
+#include "ble/BLE.h"
+#include "ble/Gap.h"
+
+#define _ICCC BLE::InitializationCompleteCallbackContext   // pure short hand
+#define _GDCP Gap::DisconnectionCallbackParams_t           // pure short hand
+#define _GCCP Gap::ConnectionCallbackParams_t              // pure short hand
+#define _GWCP GattWriteCallbackParams                      // pure short hand
+
+   class Blob : public BLE
+   {
+      public:
+         const _ICCC *pComplete;              // params to _ICCC context
+         const _GCCP *pConnect;               // params to _GCCP context
+         const _GDCP *pDisconnect;            // params to _GDPC context
+         const _GWCP *pWritten;               // params to _GWCP context
+         
+      public: // construction
+         Blob() : BLE() // standard constructor
+         {
+            pComplete = 0;  pDisconnect = 0;
+         }
+   };
+
+
+// Setup Advertising Name (syntactic sugar)
+
+   inline void name(Blob &o, const char *str)
+   {
+      o.gap().accumulateAdvertisingPayload(
+        GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)str, strlen(str)+1);
+   }
+
+
+// Setup Device Name (syntactic sugar)
+
+   inline void device(Blob &o, const char *text)
+   {
+      o.gap().setDeviceName((const uint8_t *)text);
+   }
+
+
+// Setup Advertising Data (syntactic sugar)
+
+   inline void data(Blob &o, const uint8_t *buf, size_t buflen)
+   {
+      o.gap().accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, buf, buflen);
+   }
+
+   inline void data(Blob &o, const char *text)
+   {
+      size_t len = strlen(text);
+      data(o,(const uint8_t*)text,len);
+   }
+   
+#endif // _BLOB_H_
\ No newline at end of file
diff -r 339931243be4 -r dce30a5341bb bricks/bricks.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/bricks.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,32 @@
+// bricks.h - single header for inclusion of BLE stuff
+// and most common brick headers
+
+#ifndef _BRICKS_H_
+#define _BRICKS_H_
+
+#include <mbed.h>
+#include "ble/BLE.h"
+
+   // include o.h before any other includes of bricks headers
+   
+#include "bricks/o.h"          
+
+   // include other bricks headers in any order (we use alphabetical order)
+   
+#include "bricks/advertise.h"
+#include "bricks/blinker.h"
+#include "bricks/callback.h"
+#include "bricks/characteristic.h"
+#include "bricks/collection.h"
+#include "bricks/enroll.h"
+#include "bricks/get.h"
+#include "bricks/init.h"
+#include "bricks/print.h"
+#include "bricks/service.h"
+#include "bricks/set.h"
+#include "bricks/sleep.h"
+#include "bricks/trace.h"
+#include "bricks/types.h"
+#include "bricks/updated.h"
+
+#endif // _BRICKS_H_
\ No newline at end of file
diff -r 339931243be4 -r dce30a5341bb bricks/callback.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/callback.cpp	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,83 @@
+// callback.cpp - deal with callbacks
+
+#include "bricks/blob.h"
+#include "bricks/callback.h"
+#include "bricks/trace.h" 
+   
+//==============================================================================
+// Setup Data Written Callback
+//==============================================================================
+   
+   static void (*cbWritten)(O&o) = 0;       // where we have to follow up 
+
+      // default onDataWritten callback
+
+   static void dfWritten(const GattWriteCallbackParams *params)
+   {
+      O o;                                  // setup a blob
+      o.pWritten = params;                  // store to provide access
+
+      trace(o,2,"<data written>\n");
+
+      if (cbWritten)
+         (*cbWritten)(o);                   // user callback follow-up
+   }
+
+
+   void onWritten(O&o, void (*fptr)(O&o))   // setup data written callback
+   {
+      cbWritten = fptr;                     // remember function to follow-up
+      o.gattServer().onDataWritten(dfWritten);// actual calback setup in GATT
+   }
+
+//==============================================================================
+// Setup Connection Callback
+//==============================================================================
+
+   static void (*cbConnect)(Blob&) = 0;// where we have to follow up 
+
+      // default connection callback
+      
+   static void dfConnect(const Gap::ConnectionCallbackParams_t *params)
+   {
+      O o;                                    // setup a blob object
+      o.pConnect = params;                    // store to provide access
+      
+      trace(o,2,"<connect>\n");
+      
+      if (cbConnect)
+         (*cbConnect)(o);                     // user callback follow-up
+   }
+
+   void onConnect(O&o,void(*fptr)(O&))        // setup connection callback
+   {
+      cbConnect = fptr;                       // remember function to follow-up
+      o.gap().onConnection(dfConnect);        // actual callback setup in GAP
+   }
+   
+//==============================================================================
+// Setup Disconnection Callback
+//==============================================================================
+
+   static void (*cbDisconnect)(O&o) = 0;    // where we have to follow up 
+
+      // default disconnection callback
+      
+   static void dfDisconnect(const Gap::DisconnectionCallbackParams_t *params)
+   {
+      Blob o;                               // setup a blob
+      o.pDisconnect = params;               // store to provide access
+      
+      trace(o,2,"<disconnected>\n");
+
+      if (cbDisconnect)
+         (*cbDisconnect)(o);                // user callback follow-up
+   }
+
+   void onDisconnect(O&o,void(*fptr)(O&o))  // setup disconnection callback
+   {
+      cbDisconnect = fptr;                  // remember function to follow-up
+      
+      o.gap().onDisconnection(dfDisconnect);// actualcallback setup in GAP
+   }
+   
diff -r 339931243be4 -r dce30a5341bb bricks/callback.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/callback.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,13 @@
+// callback.h - deal with callbacks
+//
+//
+#ifndef _CALLBACK_H_
+#define _CALLBACK_H_
+
+#include "bricks/o.h"
+
+   void onConnect   (O&o, void(*fptr)(O&o));   // setup connection callback
+   void onDisconnect(O&o, void(*fptr)(O&o));   // setup disconnect callback
+   void onWritten   (O&o, void (*fptr)(O&));   // setup data written callback
+
+#endif // _CALLBACK_H_
\ No newline at end of file
diff -r 339931243be4 -r dce30a5341bb bricks/characteristic.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/characteristic.cpp	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,7 @@
+// characteristic.cpp - an easy to use overloaded characteristic class
+
+#include "bricks/characteristic.h"
+
+   IniBuffer characteristicInidata;   // to initialize a characteristic
+
+// eof
\ No newline at end of file
diff -r 339931243be4 -r dce30a5341bb bricks/characteristic.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/characteristic.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,247 @@
+// characteristic.h - an easy to use overloaded characteristic class
+//
+// Synopsis:
+//
+//    Characteristic<type>   myCharacteristic(col,uuid,mode);
+//    Characteristic<type>   myCharacteristic(col,uuid,mode,name);
+//    Characteristic<type>   myCharacteristic(col,uuid,mode,name,inidata);
+//    Characteristic<type>   myCharacteristic(col,uuid,mode,inidata);
+//
+// Declaration of a characteristic, specifying value type, UUID and access mode,
+// optionally providing a name (user descriptor) and initial data.
+//
+//    col:     Collection, to which the constructed characteristic is automati-
+//             cally added. After construction and adding all characteristics to 
+//             a collection this collection is passed to a service constructor,
+//             which gets thus knowledge about all characteristics which have to
+//             be involved in the service
+//
+//    uuid:    A unique universal ID which identifies the characteristic
+//
+//    mode:    A string comprising zero or more mode characters which 
+//             define possible properties of the characteristic.  
+//
+//                ""       no properties
+//                "b"      broadcast
+//                "r"      read access
+//                "s"      send & pray (write without response)
+//                "w"      write access (with feedback)
+//                "n"      notification (no client confirmation)
+//                "i"      indication (with client confirmation)
+//                "a"      authentication signed write
+//                "x"      extended access
+//
+//    name:    An optional name provided in terms of a user descriptor. If this
+//             argument is omitted the user descriptor is not created.
+//
+//    inidata: A pointer to a variable containing initializing data for the
+//             characteristic. If the inidata argument is not provided, an
+//             implicit initialization is performed which clears the characte-
+//             ristic (all bytes set to 0). As a concluding remark it needs to
+//             be noted that the implicite initialozation works only for 
+//             sizeof(Type) <= SIZE_INIBUFFER (defined in "bricks/types.h")
+//
+//
+// Example 1: A protocol might be declared as a class as follows
+//
+//    Collection col;                            // collection used during setup
+//
+//    Characteristic<ObjectId>   id(col,0x2AC3,"rw","ID");
+//    Characteristic<ObjectName> name(col,0x2ABE,"rw","Name");
+//    Characteristic<Digital>    presence(col,0x2A56,"r","Presence");
+//
+//    Service presenceDetection(col,0xA001);     // instantiate service
+//
+//    onSetup(Blob &blue)
+//    {
+//       blue.service(presenceDetection);        // add service    
+//    }
+//
+// Example 2: service definition by means of a service definition class
+//
+//   class PresenceDetector
+//   {
+//      public:
+//         Collection col;                       // collection used during setup 
+//
+//         Characteristic<ObjectId> id;          // ID of presence detector
+//         Characteristic<ObjectName> name;      // name of presence detector
+//         Characteristic<Digital> presence;     // digital presence value
+//         Characteristic<DateTime> timestamp;   // last detection change's time
+//         Characteristic<ObjectName> layout;    // name of model railway layout
+//
+//         Service presenceDetection;            // the service
+//
+//      public:
+//         PresenceDetector(Blob &blue, cost UUID uuid) :
+//            list;                              // init service list
+//            id(list,0x2AC3,"rw","ID"),         // instantiate characteristic
+//            name(list,0x2ABE,"rw","Name"),     // instantiate characteristic
+//            presence(list,0x2A56,"r","Presence"),// instantiate characteristic
+//            timestamp(list,0x2A08,"r","Timestamp"),// instantiate characteristic
+//            layout(list,0x2ABE,"rw","Layout"), // instantiate characteristic
+//            presenceDetection(list,uuid)       // instantiate service
+//         {
+//            blue.service(presenceDetection);   // add service    
+//         }
+//   };       
+//
+#ifndef _CHARACTERISTIC_H_
+#define _CHARACTERISTIC_H_
+
+#include "ble/BLE.h"
+#include "ble/Gap.h"
+#include "bricks/types.h"
+#include "bricks/collection.h"
+#include "bricks/descriptor.h"
+
+      // the following #define is helpful if characteristics are defined on base
+      // of the BLE API (the tedious way)
+   
+#define UserDescriptor(name,attribute,descriptor,text) \
+   static char *name = text; \
+   static GattAttribute attribute(0x2901,(uint8_t*)name,strlen(name),strlen(name)); \
+   static GattAttribute *descriptor[] = {&attribute}; 
+
+      // the declaration of Characteristics needs the availability of an 
+      // initializing buffer in the default case
+      
+   extern IniBuffer characteristicInidata;   // to initialize a characteristic
+
+      // class definition of a characteristic initializer
+      
+   class CharacteristicInitializer     // provides pointers to initialized data
+   {
+      private:
+         IniBuffer inibuf;             // initialized data
+         
+      public:
+         ObjectId *pObjectId() { return (ObjectId*) &inibuf; } 
+         ObjectName *pObjectName() { return (ObjectName*) &inibuf; } 
+         Bool *pBool() { return (Bool*) &inibuf; } 
+         Digital *pDigital() { return (Digital*) &inibuf; } 
+         DateTime *pDateTime() { return (DateTime*) &inibuf; } 
+         Buffer *pBuffer() { return (Buffer*) &inibuf; } 
+
+      public:
+         CharacteristicInitializer()   // constructor
+         {
+            memset(inibuf,0,sizeof(IniBuffer));
+            
+               // besides of the local inibuf also initialize the global
+               // init buffer characteristicInidata;
+               
+            memset(characteristicInidata,0,sizeof(IniBuffer));   
+         }
+   }; 
+
+      // definition of class Characteristic
+      
+   class Service;
+
+   template <typename Type>
+   class Characteristic : public GattCharacteristic
+   {
+      private:
+         void init()                     // initialize inibuffer
+         {
+            static int initialized = 0;
+      
+            if (!initialized)                  // clear init data buffer
+            {  initialized = 1;
+               memset(characteristicInidata,0,sizeof(IniBuffer));
+            }
+         }
+         
+      private:
+         UserDescriptor descriptor;      // characteristic's user descriptor
+         
+         uint8_t getmask(const char *pmask)
+         {
+            uint8_t mask = 0;
+            
+            for(;*pmask;pmask++)
+            {  switch (*pmask)
+               {
+                  case 'b':  // broad cast
+                     mask = mask | BLE_GATT_CHAR_PROPERTIES_BROADCAST;
+                     break;
+                  case 'r':  // read
+                     mask = mask | BLE_GATT_CHAR_PROPERTIES_READ;
+                     break; 
+                  case 's':  // send (& pray)
+                     mask = mask | BLE_GATT_CHAR_PROPERTIES_WRITE_WITHOUT_RESPONSE;
+                     break; 
+                  case 'w':  // write
+                     mask = mask | BLE_GATT_CHAR_PROPERTIES_WRITE;
+                     break; 
+                  case 'n':  // notify
+                     mask = mask | BLE_GATT_CHAR_PROPERTIES_NOTIFY;
+                     break; 
+                  case 'i':  // indicate
+                     mask = mask | BLE_GATT_CHAR_PROPERTIES_INDICATE;
+                     break; 
+                  case 'a':  // authenticated signed write
+                     mask = mask | BLE_GATT_CHAR_PROPERTIES_AUTHENTICATED_SIGNED_WRITES;
+                     break; 
+                  case 'x':  // extended properties
+                     mask = mask | BLE_GATT_CHAR_PROPERTIES_EXTENDED_PROPERTIES;
+                     break;
+               } 
+            }
+            return mask;
+         }
+/*         
+      public:
+         Characteristic<Type> (Service &service, UUID uuid, const char *mode,
+               Type *valuePtr = (Type*)&characteristicInidata) : 
+            GattCharacteristic(uuid, 
+                               reinterpret_cast<uint8_t*> (valuePtr),
+                               sizeof(Type),
+                               sizeof(Type),
+                               getmask(mode),
+                               NULL,             // descriptor list
+                               0,                // number of descriptors
+                               false),
+            descriptor("")                       // construct descriptor
+         {
+            init();                              // assure initializing
+            
+               // there is a potential danger that we use implicite initializing
+               // with sizeof(Type) > sizeof(inibuffer). This must be prevented!
+               
+            int feasible = (sizeof(Type) <= sizeof(IniBuffer)); 
+            if (feasible || valuePtr != (Type*)&characteristicInidata)
+            {
+               service.add(this);                // add to service
+            }                                    // otherwise just ignore!
+         }
+*/
+      public:
+         Characteristic<Type> (Service &service, UUID uuid, const char *mode,
+                const char *name, Type *valuePtr = (Type*)&characteristicInidata) : 
+            GattCharacteristic(uuid, 
+                               reinterpret_cast<uint8_t*> (valuePtr),
+                               sizeof(Type),
+                               sizeof(Type),
+                               getmask(mode),
+                               descriptor.plist, // descriptor list
+                               1,                // number of descriptors
+                               false),
+            descriptor(name)                     // construct descriptor
+         {
+            init();                              // assure initializing
+            
+               // there is a potential danger that we use implicite initializing
+               // with sizeof(Type) > sizeof(inibuffer). This must be prevented!
+               
+            int feasible = (sizeof(Type) <= sizeof(IniBuffer)); 
+            if (feasible || valuePtr != (Type*)&characteristicInidata)
+            {
+               service.add(this);                // add to service
+            }                                    // otherwise just ignore!
+         }
+   };
+
+
+#endif // _CHARACTERISTIC_H_
\ No newline at end of file
diff -r 339931243be4 -r dce30a5341bb bricks/collection.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/collection.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,93 @@
+// collection.h - used to setup a collection of characteristics in order to
+//                setup a service.
+//
+// Description:
+//    Collections are used to setup a service comprising a collection of
+//    characteristics. The setup sequence starts with declaring a collection
+//    (this constructs an empty collection) while passing the collection in-
+//    stance repeatedly to a constructor of a characteristic, which auto-adds
+//    the new constructed characteristics to the collection. Finally, when the
+//    collection instance is passed to a service constructor, the service con-
+//    structor is able to access all characteristics which have been collected
+//    previously.  
+//
+// Example 1: A protocol might be declared as a class as follows
+//
+//    Collection col;                            // collection used during setup
+//
+//    Characteristic<ObjectId>   id(col,0x2AC3,"rw","ID");
+//    Characteristic<ObjectName> name(col,0x2ABE,"rw","Name");
+//    Characteristic<Digital>    presence(col,0x2A56,"r","Presence");
+//
+//    Service presenceDetection(col,0xA001);     // instantiate service
+//
+//    onSetup(Blob &blue)
+//    {
+//       blue.service(presenceDetection);        // add service    
+//    }
+//
+// Example 2: service definition by means of a service definition class
+//
+//   class PresenceDetector
+//   {
+//      public:
+//         Collection col;                       // collection used during setup 
+//
+//         Characteristic<ObjectId> id;          // ID of presence detector
+//         Characteristic<ObjectName> name;      // name of presence detector
+//         Characteristic<Digital> presence;     // digital presence value
+//         Characteristic<DateTime> timestamp;   // last detection change's time
+//         Characteristic<ObjectName> layout;    // name of model railway layout
+//
+//         Service presenceDetection;            // the service
+//
+//      public:
+//         PresenceDetector(Blob &blue, cost UUID uuid) :
+//            list;                              // init service list
+//            id(list,0x2AC3,"rw","ID"),         // instantiate characteristic
+//            name(list,0x2ABE,"rw","Name"),     // instantiate characteristic
+//            presence(list,0x2A56,"r","Presence"),// instantiate characteristic
+//            timestamp(list,0x2A08,"r","Timestamp"),// instantiate characteristic
+//            layout(list,0x2ABE,"rw","Layout"), // instantiate characteristic
+//            presenceDetection(list,uuid)       // instantiate service
+//         {
+//            blue.service(presenceDetection);   // add service    
+//         }
+//   };       
+//
+#ifndef _COLLECTION_H_
+#define _COLLECTION_H_
+
+#include "ble/BLE.h"
+#include "ble/Gap.h"
+
+   class Collection
+   {
+      private:
+         typedef GattCharacteristic *GattCharPtr;
+         
+      public:
+         GattCharacteristic **plist;
+         int count; 
+         
+         Collection()                  // construct empty collection
+         {
+             plist = 0;  count = 0;    // init properties
+         } 
+         
+         void add(GattCharPtr p)
+         {
+             GattCharPtr *pnew = new GattCharPtr[count+1];
+             pnew[count] = p;          // add new characteristic
+
+             if (count > 0)
+             {  for (int i=0; i < count; i++)
+                   pnew[i] = plist[i];
+                delete plist;  
+             }
+             plist = pnew;             // update list pointer
+             count++;
+         }
+   };
+
+#endif // _COLLECTION_H_
diff -r 339931243be4 -r dce30a5341bb bricks/descriptor.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/descriptor.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,50 @@
+// descriptor.h - a description list, containing a single descriptor
+//
+// Synopsis:
+//
+//    Descriptor user(0x2901,"User");
+//    Descriptor client(0x2902,"Client");
+//
+//    UserDescriptor    status("Status");      // user descriptor   0x2901
+//    ClientDescriptor  client("Client");      // client descriptor 0x2902
+//
+#ifndef _DESCRIPTOR_H_
+#define _DESCRIPTOR_H_
+
+#include "ble/BLE.h"
+#include "ble/Gap.h"
+
+   class Descriptor : public GattAttribute
+   {
+       private:
+          typedef GattAttribute *GattAttributePtr;
+       
+       public:
+          GattAttributePtr plist[1];
+          
+          Descriptor(UUID uuid, const char *name) :
+             GattAttribute(uuid,(uint8_t*)name,strlen(name),strlen(name))
+          {
+              plist[0] = this;
+          }
+   };
+
+   class UserDescriptor : public Descriptor
+   {
+       public:
+          UserDescriptor(const char *name) :  Descriptor(0x2901,name)
+          {
+              // empty
+          }
+   };
+
+   class ClientDescriptor : public Descriptor
+   {
+       public:
+          ClientDescriptor(const char *name) :  Descriptor(0x2902,name)
+          {
+              // empty
+          }
+   };
+
+#endif // _DESCRIPTOR_H_
\ No newline at end of file
diff -r 339931243be4 -r dce30a5341bb bricks/enroll.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/enroll.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,83 @@
+// enroll.h - enroll a service
+//
+// Synopsis:
+//
+//    void enroll(Blob &o, GattService &gservice);
+//    void enroll(Blob &o, uint16_t bcid = 0xFFFF);
+//
+//    void enroll(Blob &o, Service &service, uint16_t bcid = 0xFFFF);
+//
+// Arguments:
+//
+//    o:        Blob object (to avoid name clashes)
+//    gservice: The GattService to be enrolled
+//    service:  The Service to be enrolled
+//    bcid:     Broadcast ID (optional); if not provided the default value
+//              0xFFFF will be used
+//
+// Description
+//
+//    There are three ways to call enrollment.
+// 
+//    In the first case the service has been setup via a GattService class.
+//    The service is enrolled by registering the service @ GAP. On advertising
+//    the provided broadcast ID is used (otherwise default ID 0xFFFF).
+//
+//    The second case is based on a Service class object which has been setup
+//    by having added a set of characteristics to the internal collection. Upon
+//    enrollment a GattService instance will be created internally and enroll-
+//    ment of this GattService will be performed according to the first case.  
+//
+//    The third way is to enroll only the service id. This calling syntax is
+//    used, if a Gatt servive is pre-enrolled without enrolling the service ID.
+//
+// Example 1: enrollment of GattService
+//
+//    enroll(o,gservice);
+//    enroll(o,0xFFFF);
+// 
+// See also: SERVICE
+//
+#ifndef _ENROLL_H_
+#define _ENROLL_H_
+
+#include "bricks/blob.h"
+#include "bricks/service.h"
+
+
+   inline void enroll(Blob &o, uint16_t bcid = 0xFFFF)
+   {
+      static uint16_t list[1];
+      
+         // Custom UUID, FFFF is reserved for development
+         // Used for UUID's broadcast in advertising packet 
+
+      list[0] = bcid;            // set broadcast ID
+
+//    o.pble->gap().accumulateAdvertisingPayload(
+      o.gap().accumulateAdvertisingPayload(
+         GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS,
+         (uint8_t *)list, sizeof(list));
+   }
+
+
+   inline void enroll(Blob &o, GattService &gservice, uint16_t bcid = 0xFFFF)
+   {
+//    o.pble->addService(gservice);    // add service to GATT attributes
+      o.addService(gservice);          // add service to GATT attributes
+      enroll(o,bcid);                  // enroll GattService (without BCID)
+   }
+
+
+   inline void enroll(Blob &o, Service &service, uint16_t bcid = 0)
+   {
+      Collection &collection = service.collection;
+      GattService gservice(service.uuid, collection.plist, collection.count);
+
+      if (bcid == 0)
+         bcid = service.uuid;
+
+      enroll(o,gservice,bcid);         // enroll GattService (with BCID)
+   }
+
+#endif // _ENROLL_H_
\ No newline at end of file
diff -r 339931243be4 -r dce30a5341bb bricks/get.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/get.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,52 @@
+// get.h - get data from a characteristics
+//
+// Synopsis:
+//
+//    Get data from a 'characteristic' into a 'data' variable
+//
+//       get(characteristic,data)
+//
+//    The 'get' function (overloaded function family) is implemented for all
+//    types defined in "bricks/types.h".
+//
+//    See also: CHARACTERISTIC, SET
+//
+#ifndef _GET_H_
+#define _GET_H_
+
+#include "ble/BLE.h"
+#include "ble/Gap.h"
+#include "ble/GattClient.h"
+#include "bricks/o.h"
+#include "bricks/types.h"
+#include "bricks/characteristic.h"
+
+   inline void get(O&o, Characteristic<Bool> &chr, Bool &data)
+   {
+      uint16_t size = sizeof(Bool)/sizeof(uint8_t);
+      o.gattServer().read(chr.getValueHandle(), (uint8_t*)&data,&size);
+   }
+
+   inline void get(O&o, Characteristic<ObjectId> &chr, ObjectId &data)
+   {
+      uint16_t size = sizeof(ObjectId)/sizeof(uint8_t);
+      o.gattServer().read(chr.getValueHandle(), (uint8_t*)&data,&size);
+   }
+
+   inline void get(O&o, Characteristic<Buffer> &chr, Buffer &data)
+   {
+      uint16_t size = sizeof(Buffer)/sizeof(uint8_t);
+      o.gattServer().read(chr.getValueHandle(), (uint8_t*)&data,&size);
+   }
+
+// we provide also some GET methods for GattCharacteristics. However the use
+// of these methods are more dangerous, because a GattCharacteristics can be 
+// of any type and the compiler cannot help us to check !!!
+
+   inline void get(O&o,GattCharacteristic &chr, Bool &data)
+   {
+      uint16_t size = sizeof(Bool)/sizeof(uint8_t);
+      o.gattServer().read(chr.getValueHandle(), (uint8_t*)&data, &size);
+   }
+
+#endif // _GET_H_
\ No newline at end of file
diff -r 339931243be4 -r dce30a5341bb bricks/init.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/init.cpp	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,71 @@
+// init.cpp - initialize BLE system
+
+#include "bricks/init.h"
+#include "bricks/blinker.h"
+#include "bricks/trace.h"
+
+   static void (*cbSetup)(O&o) = 0;    // setup callback 
+   static void (*cbError)(O&o) = 0;    // error callback 
+
+   static void cbDefaultError(O&o)     // default error handler
+   {
+      Blinker blink;
+      blink.error();                   // 'error' blink sequence
+   }
+
+   static void cbDefaultComplete(O&o)  // default error handler
+   {
+       // empty
+   }
+   
+   static void initComplete(BLE::InitializationCompleteCallbackContext *params)
+   {
+      Blob o;                          // setup a blob
+      o.pComplete = params;            // store to provide access
+ 
+      // params->error = (ble_error_t)((int)BLE_ERROR_NONE+1);  // uncomment for debug
+      
+      trace(o,2,"<initialized>\n");
+
+      if (params->error != BLE_ERROR_NONE)
+      {
+         trace(o,0,"error\n");
+         if (cbError)
+            (*cbError)(o);             // handle error in follow-up
+            
+         return;
+      }
+
+         // Ensure that it is the default instance of BLE
+      
+      if(o.getInstanceID() != BLE::DEFAULT_INSTANCE)
+      {
+         return;
+      }
+    
+      (*cbSetup)(o);                   // followup with setup
+   }
+
+
+   void init(O&o, void (*scb)(O&o),void (*ecb)(O&o))   // init BLE system
+   {
+      cbSetup = scb;                   // store setup callback
+      cbError = ecb;                   // store error callback
+      o.init(initComplete);
+   }
+
+
+   void init(O&o, void (*scb)(O&o))    // initialize BLE system
+   {
+      init(o,scb,cbDefaultError);      // continue with default error callback
+   }
+
+   void init(O&o)                      // initialize BLE system
+   {
+      init(o,cbDefaultComplete,cbDefaultError); 
+      while (!o.hasInitialized())
+      {
+         trace(o,1,"waiting for initialized BLE!\n");
+         wait_ms(200);
+      }
+   }
diff -r 339931243be4 -r dce30a5341bb bricks/init.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/init.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,90 @@
+// init.h - initialize BLE system
+//
+// Synopsis:
+//
+//    void init(Blob &o, void (*scb)(Blob&),void (*ecb)(Blob&))  // init BLE
+//    void init(Blob &o, void (*scb)(Blob&))                     // init BLE
+//
+// Arguments:
+//
+//    o:        Blob object (to avoid name clashes)
+//    scb:      setup callback
+//    ecb:      error callback
+//
+// Description:
+//
+//    Initialize BLE system, providing a setup callback and optionally an error
+//    callback. The actual initializing happens in the setup callback. If an
+//    error occurs during initializin, the error callback will be consulted. If
+//    no error callback is provided an implicit error callback will be called.
+//
+// Example 1: simple BLE system setup
+//
+//    void cbSetup(Blob &o)
+//    {
+//       device(o,"IoT node");         // setup device name
+//       name(o,"Node #1");            // setup advertising name
+//       advertise("C:ng");            // start advertising
+//    }
+//
+//    main(void)
+//    {
+//       Blob o;                       // our Blob object
+//       init(o,cbSetup);              // init BLE base layer, always do first
+//       while (true)                  // Infinite loop waiting for BLE events
+//          sleep(o);                  // low energy waiting
+//    }
+//
+// Example 2: Provide also error handler
+//
+//    void cbError(Blob &o)
+//    {
+//       trace(0,"init error!");    
+//    }
+//
+//    void cbSetup(Blob &o)
+//    {
+//       device(o,"IoT node");         // setup device name
+//       name(o,"Node #1");            // setup advertising name
+//       advertise("C:ng");            // start advertising
+//    }
+//
+//    main(void)
+//    {
+//       Blob o;                       // our Blob object
+//       init(o,cbSetup,cbError);      // init BLE base layer, always do first
+//       while (true)                  // Infinite loop waiting for BLE events
+//          sleep(o);                  // low energy waiting
+//    }
+//
+// Example 3: Without Callbacks (busy waiting until initialized)
+//
+//    main(void)
+//    {
+//       Blob o;                       // our Blob object
+//       init(o);                      // init BLE base layer, always do first
+//
+//       device(o,"IoT node");         // setup device name
+//       name(o,"Node #1");            // setup advertising name
+//       advertise("C:ng");            // start advertising
+//
+//       while (true)                  // Infinite loop waiting for BLE events
+//          sleep(o);                  // low energy waiting
+//    }
+//
+// See also: BLOB, INIT
+//
+#ifndef _INIT_H_
+#define _INIT_H_
+
+#include "bricks/o.h"
+
+//==============================================================================
+// Initializing
+//==============================================================================
+
+   void init(O&o, void (*scb)(O&o),void (*ecb)(O&o));  // init BLE system
+   void init(O&o, void (*scb)(O&o));                   // init BLE system
+   void init(O&o);                                     // init BLE system
+
+#endif // _INIT_H_
\ No newline at end of file
diff -r 339931243be4 -r dce30a5341bb bricks/o.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/o.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,9 @@
+// o.h - dealing with THE object 'O'
+#ifndef _O_H_
+#define _O_H_
+   
+#define O     Blob
+
+#include "bricks/blob.h"
+   
+#endif // _O_H_
\ No newline at end of file
diff -r 339931243be4 -r dce30a5341bb bricks/print.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/print.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,49 @@
+// print.h - print value of a characteristic
+//
+// Synopsis:
+//
+//    See also: CHARACTERISTIC, GET, SET
+//
+#ifndef _PRINT_H_
+#define _PRINT_H_
+
+#include <stdio.h>
+#include "ble/Gap.h"
+#include "bricks/o.h"
+#include "bricks/types.h"
+#include "bricks/characteristic.h"
+
+//==============================================================================
+// Some Callbacks
+//==============================================================================
+
+   inline void print(O&o, Characteristic<Buffer> &chr, const char *name)
+   {
+      //Serial out(USBTX, USBRX);           // serial port to PC terminal
+       
+      Buffer data;  uint8_t *p = data;
+      get(o,chr,data);
+
+      printf("%s: %02x-%02x-%02x-%02x-%02x-",name,(int)(p[0]),(int)(p[1]),(int)(p[2]),(int)(p[3]),(int)(p[4]));
+      printf("%02x-%02x-%02x-%02x-%02x\r\n",(int)(p[5]),(int)(p[6]),(int)(p[7]),(int)(p[8]),(int)(p[9]));
+   }    
+
+   inline void print(O&o, Characteristic<Bool> &chr, const char *name)
+   {
+      //Serial out(USBTX, USBRX);           // serial port to PC terminal
+      Bool data;
+
+      get(o,chr,data);
+      printf("%s: %02x\r\n",name,data);
+   }    
+
+// we provide also some PRINT methods for non Characteristics. If the value of
+// a characteristic needs to be printed the value must be fetched before with
+// the GET function.
+
+   inline void print(O&o, Bool data, const char *name)
+   {
+      printf("%s: %02x\r\n",name,(int)data);
+   }    
+
+#endif // _PRINT_H_
\ No newline at end of file
diff -r 339931243be4 -r dce30a5341bb bricks/service.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/service.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,85 @@
+// service.h - declaring services and definitions
+//
+// Synopsis
+//
+// Example 1: A protocol might be declared as a class as follows
+//
+//    Collection col;                            // collection used during setup
+//
+//    Characteristic<ObjectId>   id(col,0x2AC3,"rw","ID");
+//    Characteristic<ObjectName> name(col,0x2ABE,"rw","Name");
+//    Characteristic<Digital>    presence(col,0x2A56,"r","Presence");
+//
+//    Service presenceDetection(col,0xA001);     // instantiate service
+//
+//    onSetup(Blob &blue)
+//    {
+//       blue.service(presenceDetection);        // use service    
+//    }
+//
+// Example 2: service definition by means of a service definition class
+//
+//   class PresenceDetector
+//   {
+//      public:
+//         Collection col;                       // collection used during setup 
+//
+//         Characteristic<ObjectId> id;          // ID of presence detector
+//         Characteristic<ObjectName> name;      // name of presence detector
+//         Characteristic<Digital> presence;     // digital presence value
+//         Characteristic<DateTime> timestamp;   // last detection change's time
+//         Characteristic<ObjectName> layout;    // name of model railway layout
+//
+//         Service presenceDetection;            // the service
+//
+//      public:
+//         PresenceDetector(Blob &blue, cost UUID uuid) :
+//            list;                              // init service list
+//            id(list,0x2AC3,"rw","ID"),         // instantiate characteristic
+//            name(list,0x2ABE,"rw","Name"),     // instantiate characteristic
+//            presence(list,0x2A56,"r","Presence"),// instantiate characteristic
+//            timestamp(list,0x2A08,"r","Timestamp"),// instantiate characteristic
+//            layout(list,0x2ABE,"rw","Layout"), // instantiate characteristic
+//            presenceDetection(list,uuid)       // instantiate service
+//         {
+//            Blob blue;    
+//            blue.service(presenceDetection);   // use service    
+//         }
+//   };       
+//
+#ifndef _SERVICE_H_
+#define _SERVICE_H_
+
+#include "ble/BLE.h"
+#include "ble/Gap.h"
+#include "bricks/blob.h"
+#include "bricks/collection.h"
+
+      // the following #define is helpful if a service is defined on base of the
+      // BLE API (the tedios way)
+   
+#define GattListLength(list) (sizeof(list)/sizeof(GattCharacteristic*))
+
+      // Service classs definition
+      
+   class Service
+   {
+      public:                               // public properties
+         Collection collection;             // collection of characteristics
+         uint16_t uuid;                     // UUID of service
+         const char *name;                  // name of service
+         
+      public:                               // public methods
+         Service(uint16_t _uuid, const char* _name = NULL) : collection()
+         {
+             uuid = _uuid;
+             name = _name;
+         }
+         
+         void add(GattCharacteristic *pChr) // add a characteristic to collection
+         {
+             collection.add(pChr);
+         }
+   };
+
+#endif // _SERVICE_H_
\ No newline at end of file
diff -r 339931243be4 -r dce30a5341bb bricks/set.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/set.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,46 @@
+// set.h - set data from a characteristics
+//
+// Synopsis:
+//
+//    Set data from a 'characteristic' based on 'data' variable
+//
+//       set(characteristic,data)
+//
+//    The 'set' function (overloaded function family) is implemented for all
+//    types defined in "bricks/types.h".
+//
+//    See also: CHARACTERISTIC, GET
+//
+#ifndef _SET_H_
+#define _SET_H_
+
+#include "ble/BLE.h"
+#include "ble/Gap.h"
+#include "ble/GattServer.h"
+#include "bricks/o.h"
+#include "bricks/types.h"
+#include "bricks/characteristic.h"
+
+   inline void set(O&o, Characteristic<Bool> &chr, const Bool &data)
+   {
+      uint16_t size = sizeof(Bool)/sizeof(uint8_t);
+      o.gattServer().write(chr.getValueHandle(), (uint8_t*)&data,size);
+   }
+
+   inline void set(O&o, Characteristic<ObjectId> &chr, const ObjectId &data)
+   {
+      uint16_t size = sizeof(ObjectId)/sizeof(uint8_t);
+      o.gattServer().write(chr.getValueHandle(), (uint8_t*)&data,size);
+   }
+
+// we provide also some SET methods for GattCharacteristics. However the use
+// of these methods are more dangerous, because a GattCharacteristics can be 
+// of any type and the compiler cannot help us to check !!!
+
+   inline void set(O&o,GattCharacteristic &chr,Bool data)
+   {
+      uint16_t size = sizeof(Bool)/sizeof(uint8_t);
+      o.gattServer().write(chr.getValueHandle(), (uint8_t*)&data,size);
+   }
+
+#endif // _SET_H_
\ No newline at end of file
diff -r 339931243be4 -r dce30a5341bb bricks/sleep.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/sleep.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,50 @@
+// sleep.h - sleep for some time
+//
+// Synopsis:
+//
+//    void sleep(Blob &o)              // low energy sleep for some mili seconds
+//    void sleep(Blob &o, int ms)      // low enery sleep, handle BLE events
+//
+// Arguments:
+//
+//    o:        Blob object (to avoid name clashes)
+//    msec:     sleeping interval in miliseconds
+//
+// Description:
+//
+//
+// Example 1: main function body to setup BLE functionality
+//
+//    main(void)
+//    {
+//       Blob o;                       // our Blob object
+//       init(o,onSetup,onError);      // init BLE base layer, always do first
+//      
+//       while (true)                  // Infinite loop waiting for BLE events
+//          sleep(o);                  // low power waiting for BLE events 
+//    }
+//
+// Example 2: Turn LED on for 2 seconds miliseconds
+//
+//    led = 1;                         // turn LED on
+//    sleep(o,2000);                   // wait 2000 miliseconds (in LE mode) 
+//    led = 0;                         // turn LED off
+//
+// See also: BLOB, INIT
+//
+#ifndef _SLEEP_H_
+#define _SLEEP_H_
+
+#include "bricks/blob.h"
+
+   inline void sleep(Blob &o)          // low power waiting for BLE events 
+   {
+      o.waitForEvent();                // low power waiting for BLE events 
+   }
+   
+   inline void sleep(Blob &o, int ms)  // low power waiting for BLE events 
+   {
+      wait_ms(ms);                     // low power waiting for some miliseconds 
+   }
+
+#endif // _SLEEP_H_
\ No newline at end of file
diff -r 339931243be4 -r dce30a5341bb bricks/target.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/target.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,25 @@
+// bricks/target.h - define target specifics
+
+#ifndef _BRICKS_TARGET_H_
+#define _BRICKS_TARGET_H_
+
+//#define MTCONNECT04                    // MtM nRF51822 module MtConnect04
+
+// platform specific defines - comment out platforms which are not used
+// We work only with two kinds of platform:
+//
+//    a) a NUCLEO platform from STMicroelectronics
+//    b) a nRF51 platform from Nordic Semiconductor
+//
+// If we have not a nRF51 target then we coclude it is a NUCLEO target. This is
+// not really clean, but under above assumptions it works so far!
+
+#ifdef TARGET_NRF51822 
+#   define LED_INVERTED          // inverted LED for nRF51 targets
+#endif
+
+#ifdef MTCONNECT04
+#  define BLINK_LED p16
+#endif
+
+#endif // _BRICKS_TARGET_H_
diff -r 339931243be4 -r dce30a5341bb bricks/trace.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/trace.cpp	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,54 @@
+// trace.cpp - trace a message depending on verbose level
+//
+
+#include <stdio.h>
+#include "bricks/trace.h"
+
+   static Serial pc(USBTX, USBRX);     // serial port to PC terminal
+
+//==============================================================================
+// Managing the Verbose Lewvel
+//==============================================================================
+
+   static int threshold = 0;           // verbose threshold, no verbose messages
+  
+   void verbose(O&o, int level)        // setup verbose level               
+   {
+      threshold = level;               // update verbose threshold
+   }
+   
+//==============================================================================
+// Printing Trace Messages
+//==============================================================================
+
+   void trace(O&o, int level, const char *msg) // trace a message
+   {
+      if (level <= threshold)          // update verbose threshold
+      {  char buf[2] = " ";            // must be terminated
+         
+         for (; *msg; msg++)
+         {  buf[0] = *msg;  
+            printf(buf);
+            if (*msg == '\n')
+            {  buf[0] = '\r';          // auto adding carriage return
+               printf(buf);
+            }
+         }
+      }
+   }
+   
+   void trace(O&o, int level, const char*format, int value)
+   {
+       char buf[80];
+       if (strlen(format) > 70)
+          trace(o,level," *** buffer overflow *** ");
+       else
+       {  sprintf(buf,format,value);
+          trace(o,level,buf);
+       }
+   }
+
+   void traceln(O&o, int level, const char*msg)  // trace with CR & LF
+   {
+       trace(o,level,msg);  trace(o,level,"\r\n");
+   }
diff -r 339931243be4 -r dce30a5341bb bricks/trace.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/trace.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,15 @@
+// trace.h - tracing
+#ifndef _TRACE_H_
+#define _TRACE_H_
+
+#include <mbed.h>
+#include "bricks/o.h"
+
+   void trace(O&o, int level, const char *msg);  // trace a message
+   void trace(O&o, int level, const char*, int); // trace an int value
+
+   void traceln(O&o, int level, const char*msg); // trace with CR & LF
+   
+   void verbose(O&o, int level = 9999);          // setup verbose level               
+   
+#endif // _TRACE_H_
\ No newline at end of file
diff -r 339931243be4 -r dce30a5341bb bricks/types.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/types.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,24 @@
+// types.h - declaring some common types
+//
+// The type identifiers are all begining with capital letter in order to leave
+// the lower capital identifiers free for 'overloaded' variable or characteristic
+// identifiers.  
+//
+
+#ifndef _TYPES_H_
+#define _TYPES_H_
+
+#define SIZE_OBJECTNAME 40   
+#define SIZE_INIBUFFER SIZE_OBJECTNAME   
+
+   typedef uint8_t ObjectId[6];
+   typedef char    ObjectName[SIZE_OBJECTNAME];  // use UTF8S coded characters
+   typedef uint8_t Bool;
+   typedef uint8_t Digital;
+   typedef uint8_t DateTime[10];
+   typedef uint8_t Buffer[10];
+   
+   typedef uint8_t IniBuffer[SIZE_INIBUFFER];
+
+
+#endif // _TYPES_H_
\ No newline at end of file
diff -r 339931243be4 -r dce30a5341bb bricks/updated.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bricks/updated.h	Sat May 19 14:10:17 2018 +0000
@@ -0,0 +1,25 @@
+// updated.h - check whether a characteristic has been updated
+//             note: can only used within 'onWritten' callback
+//
+// Synopsis:
+//
+//    See also: CHARACTERISTIC, GET, SET, ONWRITTEN
+//
+#ifndef _UPDATED_H_
+#define _UPDATED_H_
+
+#include "ble/Gap.h"
+#include "bricks/blob.h"
+
+   inline int updated(Blob &o,GattCharacteristic &chr)  // has char. been updated?
+   {
+      const GattWriteCallbackParams *p = o.pWritten;
+      if (!p)
+         return 0;                               // no update!
+      else if(p->handle == chr.getValueHandle())
+         return 1;
+      else
+         return 0;   
+   }
+
+#endif // _SET_H_
\ No newline at end of file