Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Revision 0:ed0152b5c495, committed 2016-09-19
- Comitter:
 - roywant
 - Date:
 - Mon Sep 19 00:59:11 2016 +0000
 - Commit message:
 - Initial commit
 
Changed in this revision
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright {yyyy} {name of copyright owner}
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.md Mon Sep 19 00:59:11 2016 +0000 @@ -0,0 +1,2 @@ +# EddystoneBeacon +Google Open Source image for Eddystone Beacon supporting UID / URL / TLM / EID frames and GATT service
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config.json	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,20 @@
+{
+  "nordic": {
+    "softdevice": "S130"
+  },
+  "nrf51822": {
+      "ram_size": "32K"
+  },
+  "mbed": {
+    "max-filehandles": 4
+  },
+  "platform" : {
+    "reset_button" : "p17",
+    "config_led" : "p13",
+    "shutdown_led" : "p14",
+    "led_off" : 0
+  },
+  "mbedtls": {
+    "user-config-file": "\"source/mbedtls_config.h\""
+  }
+}
Binary file img/app_start.png has changed
Binary file img/edit_url.png has changed
Binary file img/open_configuration.png has changed
Binary file img/result.png has changed
Binary file img/save_url.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os.lib Mon Sep 19 00:59:11 2016 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/mbed-os/#bdab10dc0f90748b6989c8b577771bb403ca6bd8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_app.json	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,6 @@
+{
+    "macros": [
+        "NDEBUG=1",
+        "MBEDTLS_USER_CONFIG_FILE=\"mbedtls_config.h\""
+    ]
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/readme.md Mon Sep 19 00:59:11 2016 +0000 @@ -0,0 +1,90 @@ +Eddystone beacons broadcast a small amount of information, like URLs, to nearby BLE devices. + +The Eddystone Beacon sample application runs in two stages: + +1. On startup, the Configuration Service (which allows [modification of the beacon](https://github.com/google/eddystone/blob/master/eddystone-url/docs/config-service-spec.md)) runs for a user-defined period (default - 30 seconds). + +1. When the Configuration Service period ends, the Eddystone Service broadcasts advertisement packets. + + + +# Running the application + +## Requirements + +You should install the *Physical Web* application on your phone: + +- [Android version](https://play.google.com/store/apps/details?id=physical_web.org.physicalweb) + +- [iOS version](https://itunes.apple.com/us/app/physical-web/id927653608?mt=8) + + +**Note:** It is also possible to use a regular scanner to interract with your Eddystone beacon but it requires +knowledge about BLE and Eddystone beacon specification out of the scope of this document. + + +Hardware requirements are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). + +## Building instructions + +Building instructions for all samples are in the [main readme](https://github.com/ARMmbed/ble-examples/blob/master/README.md). + +### Working with nRF51-based 16K targets + +Because of memory constraints, you can't use the SoftDevice 130 (S130) to build for nRF51-based 16K targets. If you are using these targets, then before building: + +1. Open the ``config.json`` file in this sample. +1. Change ``soft device`` to ``S110``. +1. Save. + +You can now build for nRF51-based 16K targets. + +## Setting up the beacon + +By default, the beacon directs to the url ``http://mbed.org``. You can change this to your own URL in two ways: + +1. Manually edit the code in ``main.cpp`` in your copy of the sample. + +1. Build and run the application's default code as explained in the building instructions. When the beacon starts up, the Configuration Service runs for 30 seconds (this is the default value; you can change it in ``main.cpp``). While the Configuration Service runs, you can use a BLE scanner on your phone to edit the values the service presents. + +## Checking for success + +1. Build the application and install it on your board as explained in the building instructions. + +1. Open the *Physical Web* application on your phone. It will start to search for nearby beacons. + +  + + **figure 1** Start of the *Physical Web* application version 0.1.856 on Android + +1. When the beacon starts up, the Configuration Service runs for 30 seconds. +During this time it is possible to change the URL advertised by the beacon. +It is also important to note that during these 30 seconds, your device will not advertise any URL. + +  + + **figure 2** How to open the beacon configuration view using the *Physical Web* application version 0.1.856 on Android + + +1. Edit the URL advertised by your beacon. + +  + + **figure 3** How to edit the URL advertised by your beacon using the *Physical Web* application version 0.1.856 on Android + + +1. Save the URL which will be advertised by your beacon. + +  + + **figure 4** How to save your beacon configuration and start advertising URL using the *Physical Web* application version 0.1.856 on Android. + + +1. Find your device; it should advertise the URL you have set. + +  + + **figure 5** Display of URL advertised by your beacon using the *Physical Web* application version 0.1.856 on Android. + + +**Note:** You can use the [Eddystone Observer](https://github.com/ARMmbed/ble-examples/tree/master/BLE_EddystoneObserver) sample instead of a phone application.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EIDFrame.cpp	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2016, Google Inc, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EIDFrame.h"
+#include "EddystoneService.h"
+#include "EntropySource/EntropySource.h"
+
+EIDFrame::EIDFrame()
+{
+    mbedtls_entropy_init(&entropy);
+    // init entropy source
+    eddystoneRegisterEntropySource(&entropy);
+    // init Random
+    mbedtls_ctr_drbg_init(&ctr_drbg);
+}
+
+void EIDFrame::clearFrame(uint8_t* frame) {
+    frame[FRAME_LEN_OFFSET] = 0; // Set frame length to zero to clear it
+}
+
+
+void EIDFrame::setData(uint8_t *rawFrame, int8_t advTxPower, const uint8_t* eidData)
+{
+    size_t index = 0;
+    rawFrame[index++] = EDDYSTONE_UUID_SIZE + EID_FRAME_LEN;   // EID length + overhead of four bytes below
+    rawFrame[index++] = EDDYSTONE_UUID[0];                      // 16-bit Eddystone UUID
+    rawFrame[index++] = EDDYSTONE_UUID[1];
+    rawFrame[index++] = FRAME_TYPE_EID;                         // 1B  Type
+    rawFrame[index++] = advTxPower;                             // 1B  Power @ 0meter
+
+    memcpy(rawFrame + index, eidData, EID_LENGTH);              // EID = 8 BYTE ID
+}
+
+uint8_t* EIDFrame::getData(uint8_t* rawFrame)
+{
+        return &(rawFrame[EID_DATA_OFFSET]);
+}
+
+uint8_t  EIDFrame::getDataLength(uint8_t* rawFrame)
+{
+     return rawFrame[FRAME_LEN_OFFSET] - EDDYSTONE_UUID_LEN;
+}
+
+uint8_t* EIDFrame::getAdvFrame(uint8_t* rawFrame)
+{
+    return &(rawFrame[ADV_FRAME_OFFSET]);
+}
+
+uint8_t EIDFrame::getAdvFrameLength(uint8_t* rawFrame)
+{
+    return rawFrame[FRAME_LEN_OFFSET];
+}
+
+uint8_t* EIDFrame::getEid(uint8_t* rawFrame)
+{
+    return &(rawFrame[EID_VALUE_OFFSET]);
+}
+
+uint8_t EIDFrame::getEidLength(uint8_t* rawFrame)
+{
+    return rawFrame[FRAME_LEN_OFFSET] - EID_HEADER_LEN;
+}
+
+void EIDFrame::setAdvTxPower(uint8_t* rawFrame, int8_t advTxPower)
+{
+    rawFrame[EID_TXPOWER_OFFSET] = advTxPower;
+}
+
+// Mote: This is only called after the rotation period is due, or on writing/creating a new eidIdentityKey
+void EIDFrame::update(uint8_t* rawFrame, uint8_t* eidIdentityKey, uint8_t rotationPeriodExp,  uint32_t timeSecs)
+{  
+    // Calculate the temporary key datastructure 1
+    uint8_t ts[4]; // big endian representation of time
+    ts[0] = (timeSecs  >> 24) & 0xff;
+    ts[1] = (timeSecs >> 16) & 0xff;
+
+    uint8_t tmpEidDS1[16] = { 0,0,0,0,0,0,0,0,0,0,0, SALT, 0, 0, ts[0], ts[1] };
+    
+    // Perform the aes encryption to generate the final temporary key.
+    uint8_t tmpKey[16];
+    aes128Encrypt(eidIdentityKey, tmpEidDS1, tmpKey);
+    
+    // Compute the EID 
+    uint8_t eid[16];
+    uint32_t scaledTime = (timeSecs >> rotationPeriodExp) << rotationPeriodExp;
+    ts[0] = (scaledTime  >> 24) & 0xff;
+    ts[1] = (scaledTime >> 16) & 0xff;
+    ts[2] = (scaledTime >> 8) & 0xff;
+    ts[3] = scaledTime & 0xff;
+    uint8_t tmpEidDS2[16] = { 0,0,0,0,0,0,0,0,0,0,0, rotationPeriodExp, ts[0], ts[1], ts[2], ts[3] };
+    aes128Encrypt(tmpKey, tmpEidDS2, eid);
+    
+    // copy the leading 8 bytes of the eid result (full result length = 16) into the ADV frame
+    memcpy(rawFrame + 5, eid, EID_LENGTH); 
+    
+}
+
+/** AES128 encrypts a 16-byte input array with a key, resulting in a 16-byte output array */
+void EIDFrame::aes128Encrypt(uint8_t key[], uint8_t input[], uint8_t output[]) {
+    mbedtls_aes_context ctx;
+    mbedtls_aes_init(&ctx); 
+    mbedtls_aes_setkey_enc(&ctx, key, 8 * sizeof(Lock_t));
+    mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, input, output);
+    mbedtls_aes_free(&ctx);
+}
+
+int EIDFrame::genBeaconKeys(PrivateEcdhKey_t beaconPrivateEcdhKey, PublicEcdhKey_t beaconPublicEcdhKey) {
+    mbedtls_ecdh_init( &ecdh_ctx );
+    
+    int i = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
+    if (i != 0) {
+        return i; // return EID_RND_FAIL;
+    }
+ 
+    if (mbedtls_ecp_group_load(&ecdh_ctx.grp, MBEDTLS_ECP_DP_CURVE25519) != 0) {
+        return EID_GRP_FAIL;
+    }
+    if (mbedtls_ecdh_gen_public(&ecdh_ctx.grp, &ecdh_ctx.d, &ecdh_ctx.Q, mbedtls_ctr_drbg_random, &ctr_drbg) != 0) {
+        return EID_GENKEY_FAIL;
+    }
+    
+    mbedtls_mpi_write_binary(&ecdh_ctx.d, beaconPrivateEcdhKey, sizeof(PrivateEcdhKey_t));
+    mbedtls_mpi_write_binary(&ecdh_ctx.Q.X, beaconPublicEcdhKey, sizeof(PublicEcdhKey_t));
+    
+    mbedtls_ecdh_free( &ecdh_ctx );
+    return EID_SUCCESS;
+}
+
+int EIDFrame::genEcdhSharedKey(PrivateEcdhKey_t beaconPrivateEcdhKey, PublicEcdhKey_t beaconPublicEcdhKey, PublicEcdhKey_t serverPublicEcdhKey, EidIdentityKey_t eidIdentityKey) {
+  int16_t ret = 0;
+  uint8_t tmp[32];
+  // initialize context
+  mbedtls_ecdh_init( &ecdh_ctx );
+  mbedtls_ecp_group_load( &ecdh_ctx.grp, MBEDTLS_ECP_DP_CURVE25519 );
+
+  // copy binary beacon private key (previously generated!) into context 
+  // Note: As the PrivateKey is generated locally, it is Big Endian
+  ret = mbedtls_mpi_read_binary( &ecdh_ctx.d, beaconPrivateEcdhKey, sizeof(PrivateEcdhKey_t) );
+  
+  // copy server-public-key (received through GATT characteristic 10) into context
+  ret = mbedtls_mpi_lset( &ecdh_ctx.Qp.Z, 1 );
+  EddystoneService::swapEndianArray(serverPublicEcdhKey, tmp, 32); // To make it Big Endian
+  ret = mbedtls_mpi_read_binary( &ecdh_ctx.Qp.X, tmp , sizeof(PublicEcdhKey_t) ); 
+
+  // ECDH point multiplication
+  size_t olen; // actual size of shared secret 
+  uint8_t sharedSecret[32]; // shared ECDH secret
+  memset(sharedSecret, 0, 32);
+  ret = mbedtls_ecdh_calc_secret( &ecdh_ctx, &olen, sharedSecret, sizeof(sharedSecret), NULL, NULL );
+  LOG(("size of olen= %d  ret=%x\r\n", olen, ret));
+  EddystoneService::swapEndianArray(sharedSecret, tmp, 32);
+  memcpy(sharedSecret, tmp, 32);
+  LOG(("Shared secret=")); EddystoneService::logPrintHex(sharedSecret, 32);
+  if (olen != sizeof(sharedSecret)) {
+      return EID_GENKEY_FAIL;
+  }
+  if (ret == MBEDTLS_ERR_ECP_BAD_INPUT_DATA) {
+      return EID_RC_SS_IS_ZERO;
+  }
+
+  // Convert the shared secret to key material using HKDF-SHA256. HKDF is used with 
+  // the salt set to a concatenation of the resolver's public key and beacon's
+  // public key, with a null context. 
+
+  // build HKDF key
+  unsigned char k[ 64 ];
+  EddystoneService::swapEndianArray(beaconPublicEcdhKey, tmp, 32);
+  memcpy( &k[0], serverPublicEcdhKey, sizeof(PublicEcdhKey_t) );
+  memcpy( &k[32], tmp, sizeof(PublicEcdhKey_t) );
+
+  // compute HKDF: see https://tools.ietf.org/html/rfc5869
+  // mbedtls_md_context_t md_ctx;
+  mbedtls_md_init( &md_ctx );
+  mbedtls_md_setup( &md_ctx, mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ), 1 );
+  mbedtls_md_hmac_starts( &md_ctx, k, sizeof( k ) );
+  mbedtls_md_hmac_update( &md_ctx, sharedSecret, sizeof(sharedSecret) );
+  unsigned char prk[ 32 ];
+  mbedtls_md_hmac_finish( &md_ctx, prk );
+  mbedtls_md_hmac_starts( &md_ctx, prk, sizeof( prk ) );
+  const unsigned char const1[] = { 0x01 };
+  mbedtls_md_hmac_update( &md_ctx, const1, sizeof( const1 ) );
+  unsigned char t[ 32 ];
+  mbedtls_md_hmac_finish( &md_ctx, t );
+
+  //Truncate the key material to 16 bytes (128 bits) to convert it to an AES-128 secret key.
+  memcpy( eidIdentityKey, t, sizeof(EidIdentityKey_t) );
+  LOG(("\r\nEIDIdentityKey=")); EddystoneService::logPrintHex(t, 32); LOG(("\r\n"));
+
+  mbedtls_md_free( &md_ctx );
+  mbedtls_ecdh_free( &ecdh_ctx );
+  return EID_SUCCESS;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EIDFrame.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2016, Google Inc, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __EIDFRAME_H__
+#define __EIDFRAME_H__
+
+#include <string.h>
+#include "EddystoneTypes.h"
+#include "mbedtls/aes.h"
+#include "mbedtls/ecdh.h"
+#include "mbedtls/md.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+#include "aes_eax.h"
+
+/**
+ * Class that encapsulates data that belongs to the Eddystone-EID frame. For
+ * more information refer to https://github.com/google/eddystone/tree/master/eddystone-EID.
+ */
+class EIDFrame
+{
+public:
+    static const uint8_t SALT = 0xff;
+    static const uint8_t EID_LENGTH = 8;
+    static const int EID_SUCCESS = 0;
+    static const int EID_RC_SS_IS_ZERO = -1;
+    static const int EID_RND_FAIL = -2;
+    static const int EID_GRP_FAIL = -3;
+    static const int EID_GENKEY_FAIL = -4;
+
+    /**
+     * Construct a new instance of this class.
+     */
+    EIDFrame();
+    
+    /**
+     * Clear frame (intervally indicated by length = 0 )
+     */
+    void clearFrame(uint8_t* frame);
+    
+    /**
+     * Construct the raw bytes of the Eddystone-EID frame that will be directly
+     * used in the advertising packets.
+     *
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     * @param[in] advPowerLevel
+     *              Power level value included in the raw frame.
+     * @param[in] eidData
+     *              The actual 16-byte EID data in the raw frame.
+     */
+    void setData(uint8_t* rawFrame, int8_t advTxPower, const uint8_t* eidData);
+    
+    /**
+     * Get the EID frame data from the Eddystone-EID frame.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return A pointer to the bytes of the Eddystone-EID frame data.
+     */
+    uint8_t* getData(uint8_t* rawFrame);
+    
+    /**
+     * Get the length of the EID frame data from the Eddystone-EID frame.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return The size in bytes of the Eddystone-EID frame.
+     */
+    uint8_t  getDataLength(uint8_t* rawFrame);
+    
+    /**
+     * Get the EID Adv data from the Eddystone-EID frame.
+     * This is the full service data included in the BLE service data params
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return A pointer to the bytes of the Eddystone-EID Adv frame data.
+     */
+    uint8_t* getAdvFrame(uint8_t* rawFrame);
+    
+    /**
+     * Get the length of the EID Adv data from the Eddystone-EID frame.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return The size in bytes of the Eddystone-EID Adv frame data.
+     */
+    uint8_t getAdvFrameLength(uint8_t* rawFrame);
+
+    /**
+     * Get just the EID data from the Eddystone-EID frame.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return A pointer to the bytes of the EID in the Eddystone-EID frame.
+     */
+    uint8_t* getEid(uint8_t* rawFrame);
+    
+    /**
+     * Get the length of just the EID data from the Eddystone-EID frame.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return The size in bytes of the EID in the Eddystone-EID frame.
+     */
+    uint8_t getEidLength(uint8_t* rawFrame);
+    
+    /**
+     * Set the Adv TX Power in the frame. This is necessary because the adv
+     * Tx Power might be updated independent of the data bytes
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     * @param[in] advPowerLevel
+     *              Power level value included in the raw frame.
+     *
+     */
+    void setAdvTxPower(uint8_t* rawFrame, int8_t advTxPower);
+    
+
+    /**
+     * Generate the beacon private and public keys. This should be called on
+     * every restart of the beacon.
+     * 
+     * @param[out] beaconPrivateEcdhKey
+     *              Pointer to the beacon private key array.
+     * @param[out] beaconPublicEcdhKey
+     *              Pointer to the beacon public key array.
+     *
+     */
+    int genBeaconKeys(PrivateEcdhKey_t beaconPrivateEcdhKey, PublicEcdhKey_t beaconPublicEcdhKey);
+
+    /**
+     * Update the EID frame. Tests if its time to rotate the EID payload, and if due, calculates and establishes the new value
+     * 
+     * @param[in] *rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     * @param[in] *eidIdentityKey
+     *              Eid key used to regenerate the EID id.
+     * @param[in] rotationPeriodExp
+     *              EID rotation time as an exponent k : 2^k seconds
+     * @param[in] timeSecs
+     *              time in seconds
+     *
+     */
+    void update(uint8_t* rawFrame, uint8_t* eidIdentityKey, uint8_t rotationPeriodExp,  uint32_t timeSecs);
+    
+    /**
+     * genEcdhSharedKey generates the eik value for inclusion in the EID ADV packet
+     *
+     * @param[in] beaconPrivateEcdhKey
+     *              The beacon's private ECDH key, generated by genBeaconKeys()
+     * @param[in] beaconPublicEcdhKey
+     *              The beacon's public ECDH key, generated by genBeaconKeys()
+     * @param[in] serverPublicEcdhKey
+     *              The server's public ECDH key
+     * @param[out] eidIdentityKey
+     *              Identity key for this beacon and server combination
+     */
+    int genEcdhSharedKey(PrivateEcdhKey_t beaconPrivateEcdhKey, PublicEcdhKey_t beaconPublicEcdhKey, PublicEcdhKey_t serverPublicEcdhKey, EidIdentityKey_t eidIdentityKey);
+    
+    /**
+     *  The byte ID of an Eddystone-EID frame.
+     */
+    static const uint8_t FRAME_TYPE_EID = 0x30;
+
+private:
+    
+    // Declare context for crypto functions
+    mbedtls_entropy_context entropy;
+    mbedtls_ctr_drbg_context ctr_drbg;
+    mbedtls_ecdh_context ecdh_ctx;
+    mbedtls_md_context_t md_ctx;
+
+    /**
+     * The size (in bytes) of an Eddystone-EID frame.
+     * This is the some of the Eddystone UUID(2 bytes), FrameType, AdvTxPower,
+     * EID Value
+     */
+    static const uint8_t EID_FRAME_LEN = 18;
+    static const uint8_t FRAME_LEN_OFFSET = 0;
+    static const uint8_t EDDYSTONE_UUID_LEN = 2;
+    static const uint8_t EID_DATA_OFFSET = 3;
+    static const uint8_t ADV_FRAME_OFFSET = 1;
+    static const uint8_t EID_VALUE_OFFSET = 5;
+    static const uint8_t EID_HEADER_LEN = 4;
+    static const uint8_t EID_TXPOWER_OFFSET = 4;
+    
+    /**
+     * AES128 ECB Encrypts a 16-byte input array with a key, to an output array
+     *
+     * @param[in] *key
+     *              The encryption key
+     * @param[in] *input
+     *              The input array
+     * @param[in] *output
+     *              The output array (contains the encrypted data)
+     */
+    void aes128Encrypt(uint8_t *key, uint8_t *input, uint8_t *output);
+ 
+};
+
+#endif  /* __EIDFRAME_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EddystoneService.cpp	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,1240 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EddystoneService.h"
+#include "EntropySource/EntropySource.h"
+
+/* Use define zero for production, 1 for testing to allow connection at any time */
+#define DEFAULT_REMAIN_CONNECTABLE 0x01
+
+const char * const EddystoneService::slotDefaultUrls[] = EDDYSTONE_DEFAULT_SLOT_URLS;
+
+// Static timer used as time since boot
+Timer        EddystoneService::timeSinceBootTimer;
+
+/*
+ * CONSTRUCTOR #1 Used on 1st boot (after reflash)
+ */
+EddystoneService::EddystoneService(BLE                 &bleIn,
+                                   const PowerLevels_t &advTxPowerLevelsIn,
+                                   const PowerLevels_t &radioTxPowerLevelsIn,
+                                   event_queue_t       &evQ,
+                                   uint32_t            advConfigIntervalIn) :
+    ble(bleIn),
+    operationMode(EDDYSTONE_MODE_NONE),
+    uidFrame(),
+    urlFrame(),
+    tlmFrame(),
+    eidFrame(),
+    tlmBatteryVoltageCallback(NULL),
+    tlmBeaconTemperatureCallback(NULL),
+    radioManagerCallbackHandle(NULL),
+    deviceName(DEFAULT_DEVICE_NAME),
+    eventQueue(evQ),
+    nextEidSlot(0)
+{
+    LOG(("1st Boot: ")); 
+    LOG((BUILD_VERSION_STR));
+    if (advConfigIntervalIn != 0) {
+        if (advConfigIntervalIn < ble.gap().getMinAdvertisingInterval()) {
+            advConfigInterval = ble.gap().getMinAdvertisingInterval();
+        } else if (advConfigIntervalIn > ble.gap().getMaxAdvertisingInterval()) {
+            advConfigInterval = ble.gap().getMaxAdvertisingInterval();
+        } else {
+            advConfigInterval = advConfigIntervalIn;
+        }
+    }
+    memcpy(radioTxPowerLevels, radioTxPowerLevelsIn, sizeof(PowerLevels_t));
+    memcpy(advTxPowerLevels,   advTxPowerLevelsIn,   sizeof(PowerLevels_t));
+
+    // 1st Boot so reset everything to factory values
+    doFactoryReset();  // includes genBeaconKeys
+    
+    LOG(("After FactoryReset in 1st Boot Init: genBeaconKeyRC=%d\r\n", genBeaconKeyRC));
+    /* TODO: Note that this timer is started from the time EddystoneService
+     * is initialised and NOT from when the device is booted.
+     */
+    timeSinceBootTimer.start();
+
+    /* Set the device name at startup */
+    ble.gap().setDeviceName(reinterpret_cast<const uint8_t *>(deviceName));
+
+}
+
+/*
+ * Constuctor #2:  Used on 2nd+ boot: EddystoneService parameters derived from persistent storage
+ */
+EddystoneService::EddystoneService(BLE                 &bleIn,
+                                   EddystoneParams_t   ¶msIn,
+                                   const PowerLevels_t &radioTxPowerLevelsIn,
+                                   event_queue_t       &evQ,
+                                   uint32_t            advConfigIntervalIn) :
+    ble(bleIn),
+    operationMode(EDDYSTONE_MODE_NONE),
+    uidFrame(),
+    urlFrame(),
+    tlmFrame(),
+    eidFrame(),
+    tlmBatteryVoltageCallback(NULL),
+    tlmBeaconTemperatureCallback(NULL),
+    radioManagerCallbackHandle(NULL),
+    deviceName(DEFAULT_DEVICE_NAME),
+    eventQueue(evQ),
+    nextEidSlot(0)
+{
+    LOG(("2nd (>=) Boot: "));
+    LOG((BUILD_VERSION_STR));
+    memcpy(capabilities, paramsIn.capabilities, sizeof(Capability_t));
+    activeSlot          = paramsIn.activeSlot;
+    memcpy(radioTxPowerLevels, radioTxPowerLevelsIn, sizeof(PowerLevels_t));
+    memcpy(slotRadioTxPowerLevels, paramsIn.slotRadioTxPowerLevels, sizeof(SlotTxPowerLevels_t));
+    memcpy(advTxPowerLevels,   paramsIn.advTxPowerLevels,   sizeof(PowerLevels_t));
+    memcpy(slotAdvTxPowerLevels, paramsIn.slotAdvTxPowerLevels, sizeof(SlotTxPowerLevels_t));
+    memcpy(slotAdvIntervals,   paramsIn.slotAdvIntervals,   sizeof(SlotAdvIntervals_t));
+    lockState           = paramsIn.lockState;
+    memcpy(unlockKey,   paramsIn.unlockKey,   sizeof(Lock_t));
+    memcpy(unlockToken, paramsIn.unlockToken, sizeof(Lock_t));
+    memcpy(challenge, paramsIn.challenge, sizeof(Lock_t));
+    memset(slotCallbackHandles, 0, sizeof(SlotCallbackHandles_t));
+    memcpy(slotStorage, paramsIn.slotStorage, sizeof(SlotStorage_t));
+    memcpy(slotFrameTypes, paramsIn.slotFrameTypes, sizeof(SlotFrameTypes_t));
+    memcpy(slotEidRotationPeriodExps, paramsIn.slotEidRotationPeriodExps, sizeof(SlotEidRotationPeriodExps_t));
+    memcpy(slotEidIdentityKeys, paramsIn.slotEidIdentityKeys, sizeof(SlotEidIdentityKeys_t));
+    remainConnectable   = paramsIn.remainConnectable;
+
+    if (advConfigIntervalIn != 0) {
+        if (advConfigIntervalIn < ble.gap().getMinAdvertisingInterval()) {
+            advConfigInterval = ble.gap().getMinAdvertisingInterval();
+        } else if (advConfigIntervalIn > ble.gap().getMaxAdvertisingInterval()) {
+            advConfigInterval = ble.gap().getMaxAdvertisingInterval();
+        } else {
+            advConfigInterval = advConfigIntervalIn;
+        }
+    }
+    
+    // Generate fresh private and public ECDH keys for EID
+    genEIDBeaconKeys();
+
+    // Recompute EID Slot Data
+    for (int slot = 0; slot < MAX_ADV_SLOTS; slot++) {
+        uint8_t* frame = slotToFrame(slot);
+        switch (slotFrameTypes[slot]) {
+            case EDDYSTONE_FRAME_EID:
+               eidFrame.update(frame, slotEidIdentityKeys[slot], slotEidRotationPeriodExps[slot], timeSinceBootTimer.read_ms() / 1000);
+               eidFrame.setAdvTxPower(frame, slotAdvTxPowerLevels[slot]);
+               break;
+            default: ;
+        }
+    }
+
+
+    /* TODO: Note that this timer is started from the time EddystoneService
+     * is initialised and NOT from when the device is booted.
+     */
+    timeSinceBootTimer.start();
+
+    /* Set the device name at startup */
+    ble.gap().setDeviceName(reinterpret_cast<const uint8_t *>(deviceName));
+}
+
+// Regenerate the beacon keys
+void EddystoneService::genEIDBeaconKeys(void) {
+    genBeaconKeyRC = -1;
+#ifdef GEN_BEACON_KEYS_AT_INIT
+    memset(privateEcdhKey, 0, 32);
+    memset(publicEcdhKey, 0, 32);
+    genBeaconKeyRC = eidFrame.genBeaconKeys(privateEcdhKey, publicEcdhKey);
+    swapEndianArray(publicEcdhKey, publicEcdhKeyLE, 32);
+#endif
+}
+
+/**
+ * Factory reset all parmeters: used at initial boot, and activated from Char 11
+ */
+void EddystoneService::doFactoryReset(void)
+{    
+    memset(slotCallbackHandles, 0, sizeof(SlotCallbackHandles_t));
+    radioManagerCallbackHandle = NULL;
+    memcpy(capabilities, CAPABILITIES_DEFAULT, CAP_HDR_LEN);
+    // Line above leaves powerlevels blank; Line below fills them in
+    memcpy(capabilities + CAP_HDR_LEN, radioTxPowerLevels, sizeof(PowerLevels_t));
+    activeSlot = DEFAULT_SLOT;
+    // Intervals
+    uint16_t buf1[] = EDDYSTONE_DEFAULT_SLOT_INTERVALS;
+    for (int i = 0; i < MAX_ADV_SLOTS; i++) {
+            // Ensure all slot periods are in range
+            buf1[i] = correctAdvertisementPeriod(buf1[i]);
+    }
+    memcpy(slotAdvIntervals, buf1, sizeof(SlotAdvIntervals_t));
+    // Radio and Adv TX Power
+    int8_t buf2[] = EDDYSTONE_DEFAULT_SLOT_TX_POWERS;
+    for (int i = 0; i< MAX_ADV_SLOTS; i++) {
+      slotRadioTxPowerLevels[i] = buf2[i];
+      slotAdvTxPowerLevels[i] = advTxPowerLevels[radioTxPowerToIndex(buf2[i])];
+    }
+    // Lock
+    lockState      = UNLOCKED;
+    uint8_t defKeyBuf[] = EDDYSTONE_DEFAULT_UNLOCK_KEY;
+    memcpy(unlockKey,        defKeyBuf,     sizeof(Lock_t));
+    memset(unlockToken,      0,     sizeof(Lock_t));
+    memset(challenge,        0,     sizeof(Lock_t)); // NOTE: challenge is randomized on first unlockChar read;
+
+    // Generate ECDH Beacon Key Pair (Private/Public)
+    genEIDBeaconKeys();
+    
+    memcpy(slotEidIdentityKeys, slotDefaultEidIdentityKeys, sizeof(SlotEidIdentityKeys_t));
+    uint8_t buf4[] = EDDYSTONE_DEFAULT_SLOT_EID_ROTATION_PERIOD_EXPS;
+    memcpy(slotEidRotationPeriodExps, buf4, sizeof(SlotEidRotationPeriodExps_t));
+    memset(slotEidNextRotationTimes, 0, sizeof(SlotEidNextRotationTimes_t));
+    //  Slot Data Type Defaults
+    uint8_t buf3[] = EDDYSTONE_DEFAULT_SLOT_TYPES;
+    memcpy(slotFrameTypes, buf3, sizeof(SlotFrameTypes_t));
+    // Initialize Slot Data Defaults
+    int eidSlot;
+    for (int slot = 0; slot < MAX_ADV_SLOTS; slot++) {
+        uint8_t* frame = slotToFrame(slot);
+        switch (slotFrameTypes[slot]) {
+            case EDDYSTONE_FRAME_UID:
+               uidFrame.setData(frame, slotAdvTxPowerLevels[slot], reinterpret_cast<const uint8_t*>(slotDefaultUids[slot]));
+               break;
+            case EDDYSTONE_FRAME_URL:
+               urlFrame.setUnencodedUrlData(frame, slotAdvTxPowerLevels[slot], slotDefaultUrls[slot]);
+               break;
+            case EDDYSTONE_FRAME_TLM:
+               tlmFrame.setTLMData(TLMFrame::DEFAULT_TLM_VERSION);
+               tlmFrame.setData(frame);
+               eidSlot = getEidSlot();
+               if (eidSlot != NO_EID_SLOT_SET) {
+                   LOG(("EID slot Set in FactoryReset\r\n"));
+                   tlmFrame.encryptData(frame, slotEidIdentityKeys[eidSlot], slotEidRotationPeriodExps[eidSlot], timeSinceBootTimer.read_ms() / 1000);
+               }
+               break;
+            case EDDYSTONE_FRAME_EID:
+               nextEidSlot = slot;
+               eidFrame.setData(frame, slotAdvTxPowerLevels[slot], reinterpret_cast<const uint8_t*>(allSlotsDefaultEid));
+               eidFrame.update(frame, slotEidIdentityKeys[slot], slotEidRotationPeriodExps[slot], timeSinceBootTimer.read_ms() / 1000);
+               break;
+        }
+    }
+#ifdef DONT_REMAIN_CONNECTABLE
+    remainConnectable = REMAIN_CONNECTABLE_UNSET;  
+#else
+    remainConnectable = REMAIN_CONNECTABLE_SET; 
+#endif
+    factoryReset = false;
+}
+
+/* Setup callback to update BatteryVoltage in TLM frame */
+void EddystoneService::onTLMBatteryVoltageUpdate(TlmUpdateCallback_t tlmBatteryVoltageCallbackIn)
+{
+    tlmBatteryVoltageCallback = tlmBatteryVoltageCallbackIn;
+}
+
+/* Setup callback to update BeaconTemperature in TLM frame */
+void EddystoneService::onTLMBeaconTemperatureUpdate(TlmUpdateCallback_t tlmBeaconTemperatureCallbackIn)
+{
+    tlmBeaconTemperatureCallback = tlmBeaconTemperatureCallbackIn;
+}
+
+EddystoneService::EddystoneError_t EddystoneService::startEddystoneBeaconAdvertisements(void)
+{
+    stopEddystoneBeaconAdvertisements();
+
+    bool intervalValidFlag = false;
+    for (int i = 0; i < MAX_ADV_SLOTS; i++) {
+        if (slotAdvIntervals[i] != 0) {
+            intervalValidFlag = true;
+        }
+    }
+
+    if (!intervalValidFlag) {
+        /* Nothing to do, the period is 0 for all frames */
+        return EDDYSTONE_ERROR_INVALID_ADVERTISING_INTERVAL;
+    }
+
+    // In case left over from Config Adv Mode
+    ble.gap().clearScanResponse();
+
+    operationMode = EDDYSTONE_MODE_BEACON;
+
+    /* Configure advertisements initially at power of active slot*/
+    ble.gap().setTxPower(slotRadioTxPowerLevels[activeSlot]);
+
+    if (remainConnectable) {
+        ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+    } else {
+         ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
+    }
+    ble.gap().setAdvertisingInterval(ble.gap().getMaxAdvertisingInterval());
+
+    /* Make sure the queue is currently empty */
+    advFrameQueue.reset();
+    /* Setup callbacks to periodically add frames to be advertised to the queue and
+     * add initial frame so that we have something to advertise on startup */
+    for (int slot = 0; slot < MAX_ADV_SLOTS; slot++) {
+        uint8_t* frame = slotToFrame(slot);
+        if (slotAdvIntervals[slot] && testValidFrame(frame)) {
+            advFrameQueue.push(slot);
+            slotCallbackHandles[slot] = eventQueue.post_every(
+                &EddystoneService::enqueueFrame, this, slot,
+                slotAdvIntervals[slot] /* ms */
+            );
+        }
+    }
+    /* Start advertising */
+    manageRadio();
+
+    return EDDYSTONE_ERROR_NONE;
+}
+
+ble_error_t EddystoneService::setCompleteDeviceName(const char *deviceNameIn)
+{
+    /* Make sure the device name is safe */
+    ble_error_t error = ble.gap().setDeviceName(reinterpret_cast<const uint8_t *>(deviceNameIn));
+    if (error == BLE_ERROR_NONE) {
+        deviceName = deviceNameIn;
+        if (operationMode == EDDYSTONE_MODE_CONFIG) {
+            /* Need to update the advertising packets to the new name */
+            setupEddystoneConfigScanResponse();
+        }
+    }
+
+    return error;
+}
+
+/* It is not the responsibility of the Eddystone implementation to store
+ * the configured parameters in persistent storage since this is
+ * platform-specific. So we provide this function that returns the
+ * configured values that need to be stored and the main application
+ * takes care of storing them.
+ */
+void EddystoneService::getEddystoneParams(EddystoneParams_t ¶ms)
+{
+    // Capabilities
+    memcpy(params.capabilities,     capabilities,           sizeof(Capability_t));
+    // Active Slot
+    params.activeSlot                = activeSlot;
+    // Intervals
+    memcpy(params.slotAdvIntervals, slotAdvIntervals,       sizeof(SlotAdvIntervals_t));
+    // Power Levels
+    memcpy(params.radioTxPowerLevels, radioTxPowerLevels,   sizeof(PowerLevels_t));
+    memcpy(params.advTxPowerLevels,   advTxPowerLevels,     sizeof(PowerLevels_t));
+    // Slot Power Levels
+    memcpy(params.slotRadioTxPowerLevels, slotRadioTxPowerLevels,   sizeof(MAX_ADV_SLOTS));
+    memcpy(params.slotAdvTxPowerLevels,   slotAdvTxPowerLevels,     sizeof(MAX_ADV_SLOTS));
+    // Lock
+    params.lockState                = lockState;
+    memcpy(params.unlockKey,        unlockKey,              sizeof(Lock_t));
+    memcpy(params.unlockToken,      unlockToken,            sizeof(Lock_t));
+    memcpy(params.challenge,        challenge,              sizeof(Lock_t));
+    // Slots
+    memcpy(params.slotFrameTypes,   slotFrameTypes,         sizeof(SlotFrameTypes_t));
+    memcpy(params.slotStorage,      slotStorage,            sizeof(SlotStorage_t));
+    memcpy(params.slotEidRotationPeriodExps, slotEidRotationPeriodExps, sizeof(SlotEidRotationPeriodExps_t));
+    memcpy(params.slotEidIdentityKeys, slotEidIdentityKeys, sizeof(SlotEidIdentityKeys_t));
+    // Testing and Management
+    params.remainConnectable        = remainConnectable;
+}
+
+void EddystoneService::swapAdvertisedFrame(int slot)
+{
+    uint8_t* frame = slotToFrame(slot);
+    uint8_t frameType = slotFrameTypes[slot];
+    uint32_t timeSecs = timeSinceBootTimer.read_ms() / 1000;
+    switch (frameType) {
+        case EDDYSTONE_FRAME_UID:
+            updateAdvertisementPacket(uidFrame.getAdvFrame(frame), uidFrame.getAdvFrameLength(frame));
+            break;
+        case EDDYSTONE_FRAME_URL:
+            updateAdvertisementPacket(urlFrame.getAdvFrame(frame), urlFrame.getAdvFrameLength(frame));
+            break;
+        case EDDYSTONE_FRAME_TLM:
+            updateRawTLMFrame(frame);
+            updateAdvertisementPacket(tlmFrame.getAdvFrame(frame), tlmFrame.getAdvFrameLength(frame));
+            break;
+        case EDDYSTONE_FRAME_EID:
+            // only update the frame if the rotation period is due
+            if (timeSecs >= slotEidNextRotationTimes[slot]) {
+                eidFrame.update(frame, slotEidIdentityKeys[slot], slotEidRotationPeriodExps[slot], timeSecs);
+                slotEidNextRotationTimes[slot] = timeSecs + (1 << slotEidRotationPeriodExps[slot]);
+                setRandomMacAddress(); // selects a new MAC address so the beacon is not trackable 
+                LOG(("EID ROTATED: Time=%lu\r\n", timeSecs));
+            }
+            updateAdvertisementPacket(eidFrame.getAdvFrame(frame), eidFrame.getAdvFrameLength(frame));
+            break;
+        default:
+            //Some error occurred
+            error("Frame to swap in does not specify a valid type");
+            break;
+    }
+    ble.gap().setTxPower(slotRadioTxPowerLevels[slot]);
+}
+
+
+/* Helper function that calls user-defined functions to update Battery Voltage and Temperature (if available),
+ * then updates the raw frame data and finally updates the actual advertised packet. This operation must be
+ * done fairly often because the TLM frame TimeSinceBoot must have a 0.1 secs resolution according to the
+ * Eddystone specification.
+ */
+void EddystoneService::updateRawTLMFrame(uint8_t* frame)
+{
+    if (tlmBeaconTemperatureCallback != NULL) {
+        tlmFrame.updateBeaconTemperature((*tlmBeaconTemperatureCallback)(tlmFrame.getBeaconTemperature()));
+    }
+    if (tlmBatteryVoltageCallback != NULL) {
+        tlmFrame.updateBatteryVoltage((*tlmBatteryVoltageCallback)(tlmFrame.getBatteryVoltage()));
+    }
+    tlmFrame.updateTimeSinceBoot(timeSinceBootTimer.read_ms());
+    tlmFrame.setData(frame);
+    int slot = getEidSlot();
+    LOG(("TLMHelper Method slot=%d\r\n", slot));
+    if (slot != NO_EID_SLOT_SET) {
+        LOG(("TLMHelper: Before Encrypting TLM\r\n"));
+        tlmFrame.encryptData(frame, slotEidIdentityKeys[slot], slotEidRotationPeriodExps[slot], timeSinceBootTimer.read_ms() / 1000);
+        LOG(("TLMHelper: Before Encrypting TLM\r\n"));
+    }
+}
+
+void EddystoneService::updateAdvertisementPacket(const uint8_t* rawFrame, size_t rawFrameLength)
+{
+    ble.gap().clearAdvertisingPayload();
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, EDDYSTONE_UUID, sizeof(EDDYSTONE_UUID));
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, rawFrame, rawFrameLength);
+}
+
+uint8_t* EddystoneService::slotToFrame(int slot)
+{
+   return reinterpret_cast<uint8_t *>(&slotStorage[slot * sizeof(Slot_t)]);
+}
+
+void EddystoneService::enqueueFrame(int slot)
+{
+    advFrameQueue.push(slot);
+    if (!radioManagerCallbackHandle) {
+        /* Advertising stopped and there is not callback posted in the event queue. Just
+         * execute the manager to resume advertising */
+        manageRadio();
+    }
+}
+
+void EddystoneService::manageRadio(void)
+{
+    uint8_t slot;
+    uint32_t  startTimeManageRadio = timeSinceBootTimer.read_ms();
+
+    /* Signal that there is currently no callback posted */
+    radioManagerCallbackHandle = NULL;
+
+    if (advFrameQueue.pop(slot)) {
+        /* We have something to advertise */
+        if (ble.gap().getState().advertising) {
+            ble.gap().stopAdvertising();
+        }
+        swapAdvertisedFrame(slot);
+        ble.gap().startAdvertising();
+
+        /* Increase the advertised packet count in TLM frame */
+        tlmFrame.updatePduCount();
+
+        /* Post a callback to itself to stop the advertisement or pop the next
+         * frame from the queue. However, take into account the time taken to
+         * swap in this frame. */
+        radioManagerCallbackHandle = eventQueue.post_in(
+            &EddystoneService::manageRadio, this,
+            ble.gap().getMinNonConnectableAdvertisingInterval() - (timeSinceBootTimer.read_ms() - startTimeManageRadio) /* ms */
+        );
+    } else if (ble.gap().getState().advertising) {
+        /* Nothing else to advertise, stop advertising and do not schedule any callbacks */
+        ble.gap().stopAdvertising();
+    }
+}
+
+void EddystoneService::startEddystoneConfigService(void)
+{
+    uint16_t beAdvInterval = swapEndian(slotAdvIntervals[activeSlot]);
+    int8_t radioTxPower = slotRadioTxPowerLevels[activeSlot];
+    int8_t advTxPower = slotAdvTxPowerLevels[activeSlot];
+    uint8_t* slotData = slotToFrame(activeSlot) + 1;
+    aes128Encrypt(unlockKey, slotEidIdentityKeys[activeSlot], encryptedEidIdentityKey);
+
+    capabilitiesChar      = new ReadOnlyArrayGattCharacteristic<uint8_t, sizeof(Capability_t)>(UUID_CAPABILITIES_CHAR, capabilities);
+    activeSlotChar        = new ReadWriteGattCharacteristic<uint8_t>(UUID_ACTIVE_SLOT_CHAR, &activeSlot);
+    advIntervalChar       = new ReadWriteGattCharacteristic<uint16_t>(UUID_ADV_INTERVAL_CHAR, &beAdvInterval);
+    radioTxPowerChar      = new ReadWriteGattCharacteristic<int8_t>(UUID_RADIO_TX_POWER_CHAR, &radioTxPower);
+    advTxPowerChar        = new ReadWriteGattCharacteristic<int8_t>(UUID_ADV_TX_POWER_CHAR, &advTxPower);
+    lockStateChar         = new GattCharacteristic(UUID_LOCK_STATE_CHAR, &lockState, sizeof(uint8_t), sizeof(LockState_t), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
+    unlockChar            = new ReadWriteArrayGattCharacteristic<uint8_t, sizeof(Lock_t)>(UUID_UNLOCK_CHAR, unlockToken);
+    publicEcdhKeyChar     = new GattCharacteristic(UUID_PUBLIC_ECDH_KEY_CHAR, publicEcdhKey, 0, sizeof(PublicEcdhKey_t), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
+    eidIdentityKeyChar    = new GattCharacteristic(UUID_EID_IDENTITY_KEY_CHAR, encryptedEidIdentityKey, 0, sizeof(EidIdentityKey_t), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
+    advSlotDataChar       = new GattCharacteristic(UUID_ADV_SLOT_DATA_CHAR, slotData, 0, 34, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
+    factoryResetChar      = new WriteOnlyGattCharacteristic<uint8_t>(UUID_FACTORY_RESET_CHAR, &factoryReset);
+    remainConnectableChar = new ReadWriteGattCharacteristic<uint8_t>(UUID_REMAIN_CONNECTABLE_CHAR, &remainConnectable);
+
+    // CHAR-1 capabilities (READ ONLY)
+    capabilitiesChar->setReadAuthorizationCallback(this, &EddystoneService::readBasicTestLockAuthorizationCallback);
+    // CHAR-2 Active Slot
+    activeSlotChar->setReadAuthorizationCallback(this, &EddystoneService::readBasicTestLockAuthorizationCallback);
+    activeSlotChar->setWriteAuthorizationCallback(this, &EddystoneService::writeActiveSlotAuthorizationCallback<uint8_t>);
+    // CHAR-3 Adv Interval
+    advIntervalChar->setReadAuthorizationCallback(this, &EddystoneService::readAdvIntervalAuthorizationCallback);
+    advIntervalChar->setWriteAuthorizationCallback(this, &EddystoneService::writeBasicAuthorizationCallback<uint16_t>);
+    // CHAR-4  Radio TX Power
+    radioTxPowerChar->setReadAuthorizationCallback(this, &EddystoneService::readRadioTxPowerAuthorizationCallback);
+    radioTxPowerChar->setWriteAuthorizationCallback(this, &EddystoneService::writeBasicAuthorizationCallback<uint8_t>);
+    // CHAR-5
+    advTxPowerChar->setReadAuthorizationCallback(this, &EddystoneService::readAdvTxPowerAuthorizationCallback);
+    advTxPowerChar->setWriteAuthorizationCallback(this, &EddystoneService::writeBasicAuthorizationCallback<uint8_t>);
+    // CHAR-6 Lock State
+    lockStateChar->setWriteAuthorizationCallback(this, &EddystoneService::writeLockStateAuthorizationCallback);
+    // CHAR-7 Unlock
+    unlockChar->setReadAuthorizationCallback(this, &EddystoneService::readUnlockAuthorizationCallback);
+    unlockChar->setWriteAuthorizationCallback(this, &EddystoneService::writeUnlockAuthorizationCallback);
+    // CHAR-8 Public Ecdh Key (READ ONLY)
+    publicEcdhKeyChar->setReadAuthorizationCallback(this, &EddystoneService::readPublicEcdhKeyAuthorizationCallback);
+    // CHAR-9 EID Identity Key (READ ONLY)
+    eidIdentityKeyChar->setReadAuthorizationCallback(this, &EddystoneService::readEidIdentityAuthorizationCallback);
+    // CHAR-10 Adv Slot Data
+    advSlotDataChar->setReadAuthorizationCallback(this, &EddystoneService::readDataAuthorizationCallback);  
+    advSlotDataChar->setWriteAuthorizationCallback(this, &EddystoneService::writeVarLengthDataAuthorizationCallback);
+    // CHAR-11 Factory Reset
+    factoryResetChar->setReadAuthorizationCallback(this, &EddystoneService::readBasicTestLockAuthorizationCallback);
+    factoryResetChar->setWriteAuthorizationCallback(this, &EddystoneService::writeBasicAuthorizationCallback<bool>);
+    // CHAR-12 Remain Connectable
+    remainConnectableChar->setReadAuthorizationCallback(this, &EddystoneService::readBasicTestLockAuthorizationCallback);
+    remainConnectableChar->setWriteAuthorizationCallback(this, &EddystoneService::writeBasicAuthorizationCallback<bool>);
+
+    // Create pointers to all characteristics in the GATT service
+    charTable[0] = capabilitiesChar;
+    charTable[1] = activeSlotChar;
+    charTable[2] = advIntervalChar;
+    charTable[3] = radioTxPowerChar;
+    charTable[4] = advTxPowerChar;
+    charTable[5] = lockStateChar;
+    charTable[6] = unlockChar;
+    charTable[7] = publicEcdhKeyChar;
+    charTable[8] = eidIdentityKeyChar;
+    charTable[9] = advSlotDataChar;
+    charTable[10] = factoryResetChar;
+    charTable[11] = remainConnectableChar;
+
+    GattService configService(UUID_ES_BEACON_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
+
+    ble.gattServer().addService(configService);
+    ble.gattServer().onDataWritten(this, &EddystoneService::onDataWrittenCallback);
+    updateCharacteristicValues();
+}
+
+
+void EddystoneService::freeConfigCharacteristics(void)
+{
+    delete capabilitiesChar;
+    delete activeSlotChar;
+    delete advIntervalChar;
+    delete radioTxPowerChar;
+    delete advTxPowerChar;
+    delete lockStateChar;
+    delete unlockChar;
+    delete publicEcdhKeyChar;
+    delete eidIdentityKeyChar;
+    delete advSlotDataChar;
+    delete factoryResetChar;
+    delete remainConnectableChar;
+}
+
+void EddystoneService::stopEddystoneBeaconAdvertisements(void)
+{
+    /* Unschedule callbacks */
+
+    for (int slot = 0; slot < MAX_ADV_SLOTS; slot++) {
+        if (slotCallbackHandles[slot]) {
+            eventQueue.cancel(slotCallbackHandles[slot]);
+            slotCallbackHandles[slot] = NULL;
+        }
+    }
+
+    if (radioManagerCallbackHandle) {
+        eventQueue.cancel(radioManagerCallbackHandle);
+        radioManagerCallbackHandle = NULL;
+    }
+
+    /* Stop any current Advs (ES Config or Beacon) */
+    BLE::Instance().gap().stopAdvertising();
+}
+
+/*
+ * Internal helper function used to update the GATT database following any
+ * change to the internal state of the service object.
+ */
+void EddystoneService::updateCharacteristicValues(void)
+{
+    // Init variables for update
+    uint16_t beAdvInterval = swapEndian(slotAdvIntervals[activeSlot]);
+    int8_t radioTxPower = slotRadioTxPowerLevels[activeSlot];
+    int8_t advTxPower = slotAdvTxPowerLevels[activeSlot];
+    uint8_t* frame = slotToFrame(activeSlot);
+    uint8_t slotLength = 0;
+    uint8_t* slotData = NULL;
+    memset(encryptedEidIdentityKey, 0, sizeof(encryptedEidIdentityKey));
+
+    switch(slotFrameTypes[activeSlot]) {
+        case EDDYSTONE_FRAME_UID:
+          slotLength = uidFrame.getDataLength(frame);
+          slotData = uidFrame.getData(frame);
+          break;
+        case EDDYSTONE_FRAME_URL:
+          slotLength = urlFrame.getDataLength(frame);
+          slotData = urlFrame.getData(frame);
+          break;
+        case EDDYSTONE_FRAME_TLM:
+          updateRawTLMFrame(frame);
+          slotLength = tlmFrame.getDataLength(frame);
+          slotData = tlmFrame.getData(frame);
+          break;
+        case EDDYSTONE_FRAME_EID:
+          slotLength = eidFrame.getDataLength(frame);
+          slotData = eidFrame.getData(frame);
+          aes128Encrypt(unlockKey, slotEidIdentityKeys[activeSlot], encryptedEidIdentityKey);
+          break;
+    }
+
+    ble.gattServer().write(capabilitiesChar->getValueHandle(), reinterpret_cast<uint8_t *>(capabilities), sizeof(Capability_t));
+    ble.gattServer().write(activeSlotChar->getValueHandle(), &activeSlot, sizeof(uint8_t));
+    ble.gattServer().write(advIntervalChar->getValueHandle(), reinterpret_cast<uint8_t *>(&beAdvInterval), sizeof(uint16_t));
+    ble.gattServer().write(radioTxPowerChar->getValueHandle(), reinterpret_cast<uint8_t *>(&radioTxPower), sizeof(int8_t));
+    ble.gattServer().write(advTxPowerChar->getValueHandle(), reinterpret_cast<uint8_t *>(&advTxPower), sizeof(int8_t));
+    ble.gattServer().write(lockStateChar->getValueHandle(), &lockState, sizeof(uint8_t));
+    ble.gattServer().write(unlockChar->getValueHandle(), unlockToken, sizeof(Lock_t));
+    ble.gattServer().write(publicEcdhKeyChar->getValueHandle(), reinterpret_cast<uint8_t *>(publicEcdhKey), sizeof(PublicEcdhKey_t));
+    ble.gattServer().write(eidIdentityKeyChar->getValueHandle(), reinterpret_cast<uint8_t *>(encryptedEidIdentityKey), sizeof(EidIdentityKey_t));
+    ble.gattServer().write(advSlotDataChar->getValueHandle(), slotData, slotLength);
+    ble.gattServer().write(factoryResetChar->getValueHandle(), &factoryReset, sizeof(uint8_t));
+    ble.gattServer().write(remainConnectableChar->getValueHandle(), &remainConnectable, sizeof(uint8_t));
+}
+
+EddystoneService::EddystoneError_t EddystoneService::startEddystoneConfigAdvertisements(void)
+{
+    stopEddystoneBeaconAdvertisements();
+
+    if (advConfigInterval == 0) {
+        // Nothing to do, the advertisement interval is 0
+        return EDDYSTONE_ERROR_INVALID_ADVERTISING_INTERVAL;
+    }
+
+    operationMode = EDDYSTONE_MODE_CONFIG;
+
+    ble.gap().clearAdvertisingPayload();
+
+    /* Accumulate the new payload */
+    ble.gap().accumulateAdvertisingPayload(
+        GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE
+    );
+    /* UUID is in different order in the ADV frame (!) */
+    uint8_t reversedServiceUUID[sizeof(UUID_ES_BEACON_SERVICE)];
+    for (size_t i = 0; i < sizeof(UUID_ES_BEACON_SERVICE); i++) {
+        reversedServiceUUID[i] = UUID_ES_BEACON_SERVICE[sizeof(UUID_ES_BEACON_SERVICE) - i - 1];
+    }
+    ble.gap().accumulateAdvertisingPayload(
+        GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
+        reversedServiceUUID,
+        sizeof(reversedServiceUUID)
+    );
+    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_TAG);
+    setupEddystoneConfigScanResponse();
+
+    ble.gap().setTxPower(radioTxPowerLevels[sizeof(PowerLevels_t)-1]); // Max Power for Config
+    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+    ble.gap().setAdvertisingInterval(advConfigInterval);
+    ble.gap().startAdvertising();
+
+    return EDDYSTONE_ERROR_NONE;
+}
+
+void EddystoneService::setupEddystoneConfigScanResponse(void)
+{
+    ble.gap().clearScanResponse();
+    ble.gap().accumulateScanResponse(
+        GapAdvertisingData::COMPLETE_LOCAL_NAME,
+        reinterpret_cast<const uint8_t *>(deviceName),
+        strlen(deviceName)
+    );
+    ble.gap().accumulateScanResponse(
+        GapAdvertisingData::TX_POWER_LEVEL,
+        reinterpret_cast<uint8_t *>(&advTxPowerLevels[sizeof(PowerLevels_t)-1]),
+        sizeof(uint8_t)
+    );
+}
+
+/* WRITE AUTHORIZATION */
+
+void EddystoneService::writeUnlockAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
+{
+    if (lockState == UNLOCKED) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED;
+    } else if (authParams->len != sizeof(Lock_t)) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
+    } else if (authParams->offset != 0) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
+    } else if (memcmp(authParams->data, unlockToken, sizeof(Lock_t)) != 0) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED;
+    } else {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+    }
+}
+
+void EddystoneService::writeVarLengthDataAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
+{
+   if (lockState == LOCKED) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED;
+    } else if ((authParams->len > 34) || (authParams->len == 0)) {  
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
+    } else {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+    }
+}
+
+
+void EddystoneService::writeLockStateAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
+{
+   if (lockState == LOCKED) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED;
+    } else if ((authParams->len != sizeof(uint8_t)) && (authParams->len != (sizeof(uint8_t) + sizeof(Lock_t)))) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
+    } else if (authParams->offset != 0) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
+    } else {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+    }
+}
+
+template <typename T>
+void EddystoneService::writeBasicAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
+{
+    if (lockState == LOCKED) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED;
+    } else if (authParams->len != sizeof(T)) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
+    } else if (authParams->offset != 0) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
+    } else {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+    }
+}
+
+template <typename T>
+void EddystoneService::writeActiveSlotAuthorizationCallback(GattWriteAuthCallbackParams *authParams)
+{
+    if (lockState == LOCKED) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED;
+    } else if (authParams->len != sizeof(T)) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
+    } else if (*(authParams->data) > MAX_ADV_SLOTS -1) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
+    } else if (authParams->offset != 0) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
+    } else {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+    }
+}
+
+/* READ AUTHORIZTION */
+
+void EddystoneService::readBasicTestLockAuthorizationCallback(GattReadAuthCallbackParams *authParams)
+{
+    LOG(("\r\nDO READ BASIC TEST LOCK slot=%d\r\n", activeSlot));
+    if (lockState == LOCKED) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_READ_NOT_PERMITTED;
+    } else {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+    }
+}
+
+void EddystoneService::readEidIdentityAuthorizationCallback(GattReadAuthCallbackParams *authParams)
+{
+    LOG(("\r\nDO READ EID IDENTITY slot=%d\r\n", activeSlot));
+    aes128Encrypt(unlockKey, slotEidIdentityKeys[activeSlot], encryptedEidIdentityKey);
+    int sum = 0;
+    // Test if the IdentityKey is all zeros for this slot
+    for (uint8_t i = 0; i < sizeof(EidIdentityKey_t); i++) {
+        sum = sum + slotEidIdentityKeys[activeSlot][i];
+    }
+    ble.gattServer().write(eidIdentityKeyChar->getValueHandle(), encryptedEidIdentityKey, sizeof(EidIdentityKey_t));
+
+    // When the array is all zeros, the key has not been set, so return fault
+    if ((lockState == LOCKED) || (sum == 0)) { 
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_READ_NOT_PERMITTED;
+    } else {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+    }
+}
+
+void EddystoneService::readPublicEcdhKeyAuthorizationCallback(GattReadAuthCallbackParams *authParams)
+{
+    LOG(("\r\nDO READ BEACON PUBLIC ECDH KEY (LE) slot=%d\r\n", activeSlot));
+
+    ble.gattServer().write(publicEcdhKeyChar->getValueHandle(), publicEcdhKeyLE, sizeof(PublicEcdhKey_t));
+    
+    // When the array is all zeros, the key has not been set, so return fault
+    if (lockState == LOCKED) { 
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_READ_NOT_PERMITTED;
+    } else {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+    }
+}
+
+void EddystoneService::readDataAuthorizationCallback(GattReadAuthCallbackParams *authParams)
+{
+    LOG(("\r\nDO READ ADV-DATA : slot=%d\r\n", activeSlot));
+    uint8_t frameType = slotFrameTypes[activeSlot];
+    uint8_t* frame = slotToFrame(activeSlot);
+    uint8_t slotLength = 1;
+    uint8_t buf[14] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+    uint8_t* slotData = buf;
+ 
+    if (lockState == LOCKED) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_READ_NOT_PERMITTED;
+        return;
+    }
+    LOG(("IN READ ADV-DATA AFTER LOCK TEST frameType=%d\r\n", frameType));
+    if (testValidFrame(frame) ) { // Check the frame has valid data before proceeding
+        switch(frameType) {
+            case EDDYSTONE_FRAME_UID:
+                LOG(("READ ADV-DATA UID SLOT DATA slot=%d\r\n", activeSlot));
+                slotLength = uidFrame.getDataLength(frame);
+                slotData = uidFrame.getData(frame);
+                break;
+            case EDDYSTONE_FRAME_URL:
+                LOG(("READ ADV-DATA URL SLOT DATA slot=%d\r\n", activeSlot));
+                slotLength = urlFrame.getDataLength(frame);
+                slotData = urlFrame.getData(frame);
+                break;
+            case EDDYSTONE_FRAME_TLM:
+                LOG(("READ ADV-DATA TLM SLOT DATA slot=%d\r\n", activeSlot));
+                updateRawTLMFrame(frame);
+                slotLength = tlmFrame.getDataLength(frame);
+                slotData = tlmFrame.getData(frame);
+                LOG(("READ ADV-DATA AFTER T/E TLM length=%d\r\n", slotLength)); 
+                LOG(("Data=")); logPrintHex(slotData, 18);
+                break;
+            case EDDYSTONE_FRAME_EID:
+                LOG(("READ ADV-DATA EID SLOT DATA slot=%d\r\n", activeSlot));
+                slotLength = 14;
+                buf[0] = EIDFrame::FRAME_TYPE_EID;
+                buf[1] = slotEidRotationPeriodExps[activeSlot];
+                // Add time as a big endian 32 bit number
+                uint32_t timeSecs = timeSinceBootTimer.read_ms() / 1000;
+                buf[2] = (timeSecs  >> 24) & 0xff;
+                buf[3] = (timeSecs >> 16) & 0xff;
+                buf[4] = (timeSecs >> 8) & 0xff;
+                buf[5] = timeSecs & 0xff;
+                memcpy(buf + 6, eidFrame.getEid(frame), 8);
+                slotData = buf;
+                break;
+        }
+    }
+    LOG(("IN READ ADV-DATA AFTER FRAME PROCESSING slot=%d\r\n", activeSlot));
+    ble.gattServer().write(advSlotDataChar->getValueHandle(), slotData, slotLength);
+    authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+}
+
+bool EddystoneService::testValidFrame(uint8_t* frame) {
+    return (frame[0] != 0 ) ? true : false; 
+}
+
+void EddystoneService::readUnlockAuthorizationCallback(GattReadAuthCallbackParams *authParams)
+{
+    LOG(("\r\nDO READ UNLOCK slot=%d\r\n", activeSlot));
+    if (lockState == UNLOCKED) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_READ_NOT_PERMITTED;
+        return;
+    }
+    // Update the challenge ready for the characteristic read
+    generateRandom(challenge, sizeof(Lock_t));
+    aes128Encrypt(unlockKey, challenge, unlockToken);
+    ble.gattServer().write(unlockChar->getValueHandle(), reinterpret_cast<uint8_t *>(challenge), sizeof(Lock_t));     
+    authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+}
+
+void EddystoneService::readAdvIntervalAuthorizationCallback(GattReadAuthCallbackParams *authParams)
+{
+    LOG(("\r\nDO READ ADV INTERVAL slot=%d\r\n", activeSlot));
+    if (lockState == LOCKED) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_READ_NOT_PERMITTED;
+        return;
+    }
+    uint16_t beAdvInterval = swapEndian(slotAdvIntervals[activeSlot]);
+    ble.gattServer().write(advIntervalChar->getValueHandle(), reinterpret_cast<uint8_t *>(&beAdvInterval), sizeof(uint16_t));
+    authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+}
+
+void EddystoneService::readRadioTxPowerAuthorizationCallback(GattReadAuthCallbackParams *authParams)
+{
+    LOG(("\r\nDO READ RADIO TXPOWER slot=%d\r\n", activeSlot));
+    if (lockState == LOCKED) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_READ_NOT_PERMITTED;
+        return;
+    }
+    int8_t radioTxPower = slotRadioTxPowerLevels[activeSlot];
+    ble.gattServer().write(radioTxPowerChar->getValueHandle(), reinterpret_cast<uint8_t *>(&radioTxPower), sizeof(int8_t));
+    authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+}
+
+void EddystoneService::readAdvTxPowerAuthorizationCallback(GattReadAuthCallbackParams *authParams)
+{
+    LOG(("\r\nDO READ ADV TXPOWER slot=%d\r\n", activeSlot));
+    if (lockState == LOCKED) {
+        authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_READ_NOT_PERMITTED;
+        return;
+    }
+    int8_t advTxPower = slotAdvTxPowerLevels[activeSlot];
+    ble.gattServer().write(advTxPowerChar->getValueHandle(), reinterpret_cast<uint8_t *>(&advTxPower), sizeof(int8_t));
+    authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
+}
+
+/*
+ * This callback is invoked when a GATT client attempts to modify any of the
+ * characteristics of this service. Attempts to do so are also applied to
+ * the internal state of this service object.
+ */
+void EddystoneService::onDataWrittenCallback(const GattWriteCallbackParams *writeParams)
+{
+    uint16_t handle = writeParams->handle;
+    LOG(("\r\nDO WRITE: Handle=%d Len=%d\r\n", handle, writeParams->len));
+    // CHAR-1 CAPABILITIES
+            /* capabilitySlotChar is READ ONLY */
+    // CHAR-2 ACTIVE SLOT
+    if (handle == activeSlotChar->getValueHandle()) {
+        LOG(("Write: Active Slot Handle=%d\r\n", handle));
+        uint8_t slot = *(writeParams->data);
+        LOG(("Active Slot=%d\r\n", slot));
+        // Ensure slot does not exceed limit, or set highest slot
+        if (slot < MAX_ADV_SLOTS) {
+            activeSlot = slot;
+        }
+        ble.gattServer().write(activeSlotChar->getValueHandle(), &activeSlot, sizeof(uint8_t));
+    // CHAR-3 ADV INTERVAL
+    } else if (handle == advIntervalChar->getValueHandle()) {
+        LOG(("Write: Interval Handle=%d\r\n", handle));
+        uint16_t interval = correctAdvertisementPeriod(swapEndian(*((uint16_t *)(writeParams->data))));
+        slotAdvIntervals[activeSlot] = interval; // Store this value for reading
+        uint16_t beAdvInterval = swapEndian(slotAdvIntervals[activeSlot]);
+        ble.gattServer().write(advIntervalChar->getValueHandle(), reinterpret_cast<uint8_t *>(&beAdvInterval), sizeof(uint16_t));
+    // CHAR-4 RADIO TX POWER
+    } else if (handle == radioTxPowerChar->getValueHandle()) {
+        LOG(("Write: RADIO Power Handle=%d\r\n", handle));
+        int8_t radioTxPower = *(writeParams->data);
+        uint8_t index = radioTxPowerToIndex(radioTxPower);
+        radioTxPower = radioTxPowerLevels[index]; // Power now corrected to nearest allowed power
+        slotRadioTxPowerLevels[activeSlot] = radioTxPower; // Store by slot number
+        int8_t advTxPower = advTxPowerLevels[index]; // Determine adv power equivalent
+        slotAdvTxPowerLevels[activeSlot] = advTxPower;
+        setFrameTxPower(activeSlot, advTxPower); // Set the actual frame radio TxPower for this slot
+        ble.gattServer().write(radioTxPowerChar->getValueHandle(), reinterpret_cast<uint8_t *>(&radioTxPower), sizeof(int8_t));
+    // CHAR-5 ADV TX POWER
+    } else if (handle == advTxPowerChar->getValueHandle()) {
+        LOG(("Write: ADV Power Handle=%d\r\n", handle));
+        int8_t advTxPower = *(writeParams->data);
+        slotAdvTxPowerLevels[activeSlot] = advTxPower;
+        setFrameTxPower(activeSlot, advTxPower); // Update the actual frame Adv TxPower for this slot
+        ble.gattServer().write(advTxPowerChar->getValueHandle(), reinterpret_cast<uint8_t *>(&advTxPower), sizeof(int8_t));
+    // CHAR-6 LOCK STATE
+    } else if (handle == lockStateChar->getValueHandle()) {
+        LOG(("Write: Lock State Handle=%d\r\n", handle));
+        uint8_t newLockState = *(writeParams->data);
+        if ((writeParams->len == sizeof(uint8_t)) || (writeParams->len == sizeof(uint8_t) + sizeof(Lock_t))) {
+            if ((newLockState == LOCKED) || (newLockState == UNLOCKED) || (newLockState == UNLOCKED_AUTO_RELOCK_DISABLED)) {
+                lockState = newLockState;
+            }
+        }
+        if ((newLockState == LOCKED) && (writeParams->len == (sizeof(uint8_t) + sizeof(Lock_t))) ) {
+            // And sets the new secret lock code if present
+            uint8_t encryptedNewKey[sizeof(Lock_t)];
+            uint8_t newKey[sizeof(Lock_t)];
+            memcpy(encryptedNewKey, (writeParams->data)+1, sizeof(Lock_t));
+            // Decrypt the new key
+            aes128Decrypt(unlockKey, encryptedNewKey, newKey);
+            memcpy(unlockKey, newKey, sizeof(Lock_t));
+        }
+        ble.gattServer().write(lockStateChar->getValueHandle(), reinterpret_cast<uint8_t *>(&lockState), sizeof(uint8_t));
+    // CHAR-7 UNLOCK
+    } else if (handle == unlockChar->getValueHandle()) {
+       LOG(("Write: Unlock Handle=%d\r\n", handle));
+       // NOTE: Actual comparison with unlock code is done in:
+       // writeUnlockAuthorizationCallback(...)  which is executed before this method call.
+       lockState = UNLOCKED;
+       // Regenerate challenge and expected unlockToken for Next unlock operation
+       generateRandom(challenge, sizeof(Lock_t));
+       aes128Encrypt(unlockKey, challenge, unlockToken);
+       // Update Chars
+       ble.gattServer().write(unlockChar->getValueHandle(), reinterpret_cast<uint8_t *>(challenge), sizeof(Lock_t));      // Update the challenge
+       ble.gattServer().write(lockStateChar->getValueHandle(), reinterpret_cast<uint8_t *>(&lockState), sizeof(uint8_t)); // Update the lock
+    // CHAR-8 PUBLIC ECDH KEY
+        /* PublicEchdChar is READ ONLY */
+    // CHAR-9 EID INDENTITY KEY
+        /* EidIdentityChar is READ ONLY */
+    // CHAR-10 ADV DATA
+    } else if (handle == advSlotDataChar->getValueHandle()) {
+        LOG(("Write: Adv Slot DATA Handle=%d\r\n", handle));
+        uint8_t* frame = slotToFrame(activeSlot);
+        int8_t advTxPower = slotAdvTxPowerLevels[activeSlot];
+        uint8_t writeFrameFormat = *(writeParams->data);
+        uint8_t writeFrameLen = (writeParams->len);
+        uint8_t writeData[34];
+        uint8_t serverPublicEcdhKey[32];
+        
+        if (writeFrameLen != 0) {
+            writeFrameLen--; // Remove the Format byte from the count
+        } else {
+            writeFrameFormat = UNDEFINED_FRAME_FORMAT; // Undefined format
+        }
+        
+        memcpy(writeData, (writeParams->data) + 1, writeFrameLen);
+        LOG(("ADV Data Write=%d,%d\r\n", writeFrameFormat, writeFrameLen));
+        switch(writeFrameFormat) {
+            case UIDFrame::FRAME_TYPE_UID:
+                if (writeFrameLen == 16) {
+                    uidFrame.setData(frame, advTxPower,reinterpret_cast<const uint8_t *>((writeParams->data) + 1));
+                    slotFrameTypes[activeSlot] = EDDYSTONE_FRAME_UID;
+                } else if (writeFrameLen == 0) {
+                    uidFrame.clearFrame(frame);
+                }
+                break;
+            case URLFrame::FRAME_TYPE_URL:
+               if (writeFrameLen <= 18) {
+                    urlFrame.setData(frame, advTxPower, reinterpret_cast<const uint8_t*>((writeParams->data) + 1), writeFrameLen );
+                    slotFrameTypes[activeSlot] = EDDYSTONE_FRAME_URL;
+                } else if (writeFrameLen == 0) {
+                    urlFrame.clearFrame(frame);
+                }
+                break;
+            case TLMFrame::FRAME_TYPE_TLM:
+                if (writeFrameLen == 0) {
+                    updateRawTLMFrame(frame);
+                    tlmFrame.setData(frame);
+                    int slot = getEidSlot();
+                    LOG(("WRITE: Testing if TLM or ETLM=%d\r\n", slot));
+                    if (slot != NO_EID_SLOT_SET) {
+                        LOG(("WRITE: Configuring ETLM Slot time=%d\r\n", timeSinceBootTimer.read_ms() / 1000));
+                        tlmFrame.encryptData(frame, slotEidIdentityKeys[slot], slotEidRotationPeriodExps[slot], timeSinceBootTimer.read_ms() / 1000);
+                    }
+                    slotFrameTypes[activeSlot] = EDDYSTONE_FRAME_TLM;
+                }
+                break;
+            case EIDFrame::FRAME_TYPE_EID:
+                LOG(("EID Len=%d\r\n", writeFrameLen));
+                if (writeFrameLen == 17) {
+                    // Least secure
+                    LOG(("EID Insecure branch\r\n"));
+                    aes128Decrypt(unlockKey, writeData, slotEidIdentityKeys[activeSlot]);
+                    slotEidRotationPeriodExps[activeSlot] = writeData[16]; // index 16 is the exponent
+                    ble.gattServer().write(eidIdentityKeyChar->getValueHandle(), reinterpret_cast<uint8_t *>(&writeData), sizeof(EidIdentityKey_t));
+                } else if (writeFrameLen == 33 ) {  
+                    // Most secure
+                    memcpy(serverPublicEcdhKey, writeData, 32);
+                    ble.gattServer().write(publicEcdhKeyChar->getValueHandle(), reinterpret_cast<uint8_t *>(&serverPublicEcdhKey), sizeof(PublicEcdhKey_t));
+                    LOG(("ServerPublicEcdhKey=")); logPrintHex(serverPublicEcdhKey, 32);
+                    slotEidRotationPeriodExps[activeSlot] = writeData[32]; // index 32 is the exponent
+                    LOG(("Exponent=%i\r\n", writeData[32]));
+                    LOG(("genBeaconKeyRC=%x\r\n", genBeaconKeyRC));
+                    LOG(("BeaconPrivateEcdhKey=")); logPrintHex(privateEcdhKey, 32);
+                    LOG(("BeaconPublicEcdhKey=")); logPrintHex(publicEcdhKey, 32);
+                    LOG(("genECDHShareKey\r\n"));
+                    int rc = eidFrame.genEcdhSharedKey(privateEcdhKey, publicEcdhKey, serverPublicEcdhKey, slotEidIdentityKeys[activeSlot]);
+                    LOG(("Gen Keys RC = %x\r\n", rc));
+                    LOG(("Generated eidIdentityKey=")); logPrintHex(slotEidIdentityKeys[activeSlot], 16);
+                    aes128Encrypt(unlockKey, slotEidIdentityKeys[activeSlot], encryptedEidIdentityKey);
+                    LOG(("encryptedEidIdentityKey=")); logPrintHex(encryptedEidIdentityKey, 16);      
+                    ble.gattServer().write(eidIdentityKeyChar->getValueHandle(), reinterpret_cast<uint8_t *>(&encryptedEidIdentityKey), sizeof(EidIdentityKey_t));
+                } else if (writeFrameLen == 0) {
+                    // Reset eidFrame
+                    eidFrame.clearFrame(frame);
+                    break;
+                } else {
+                    break; // Do nothing, this is not a recognized Frame length
+                }
+                // Establish the new frame type
+                slotFrameTypes[activeSlot] = EDDYSTONE_FRAME_EID;
+                nextEidSlot = activeSlot; // This was the last one updated
+                LOG(("update Eid Frame\r\n"));
+                // Generate ADV frame packet from EidIdentity Key
+                eidFrame.update(frame, slotEidIdentityKeys[activeSlot], slotEidRotationPeriodExps[activeSlot], timeSinceBootTimer.read_ms() / 1000);
+                LOG(("END update Eid Frame\r\n"));
+                break;
+            default:
+                frame[0] = 0; // Frame format unknown so clear the entire frame by writing 0 to its length
+                break;
+        }
+        // Read takes care of setting the Characteristic  Value
+    // CHAR-11 FACTORY RESET
+    } else if (handle == factoryResetChar->getValueHandle() && (*((uint8_t *)writeParams->data) != 0)) {
+        LOG(("Write: Factory Reset: Handle=%d\r\n", handle));
+        // Reset params to default values
+        doFactoryReset();
+        // Update all characteristics based on params
+        updateCharacteristicValues();
+    // CHAR-12 REMAIN CONNECTABLE
+    } else if (handle == remainConnectableChar->getValueHandle()) {
+        LOG(("Write: Remain Connectable Handle=%d\r\n", handle));
+        remainConnectable = *(writeParams->data);
+        ble.gattServer().write(remainConnectableChar->getValueHandle(), &remainConnectable, sizeof(uint8_t));
+    }
+
+}
+
+void EddystoneService::setFrameTxPower(uint8_t slot, int8_t advTxPower) {
+    uint8_t* frame = slotToFrame(slot);
+    uint8_t frameType = slotFrameTypes[slot];
+    switch (frameType) {
+        case UIDFrame::FRAME_TYPE_UID:
+           uidFrame.setAdvTxPower(frame, advTxPower);
+           break;
+        case URLFrame::FRAME_TYPE_URL:
+           urlFrame.setAdvTxPower(frame, advTxPower);
+           break;
+        case EIDFrame::FRAME_TYPE_EID:
+           eidFrame.setAdvTxPower(frame, advTxPower);
+           break;
+    }
+}
+
+uint8_t EddystoneService::radioTxPowerToIndex(int8_t txPower) {
+    // NOTE: txPower is an 8-bit signed number
+    uint8_t size = sizeof(PowerLevels_t);
+    // Look for the value in range (or next biggest value)
+    for (uint8_t i = 0; i < size; i++) {
+      if (txPower <= radioTxPowerLevels[i]) {
+          return i;
+      }
+    }
+    return size - 1;
+}
+
+/** AES128 encrypts a 16-byte input array with a key, resulting in a 16-byte output array */
+void EddystoneService::aes128Encrypt(uint8_t key[], uint8_t input[], uint8_t output[]) {
+    mbedtls_aes_context ctx;
+    mbedtls_aes_init(&ctx);
+    mbedtls_aes_setkey_enc(&ctx, key, 8 * sizeof(Lock_t));
+    mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_ENCRYPT, input, output);
+    mbedtls_aes_free(&ctx);
+}
+
+/** AES128 decrypts a 16-byte input array with a key, resulting in a 16-byte output array */
+void EddystoneService::aes128Decrypt(uint8_t key[], uint8_t input[], uint8_t output[]) {
+    mbedtls_aes_context ctx;
+    mbedtls_aes_init(&ctx);
+    mbedtls_aes_setkey_dec(&ctx, key, 8 * sizeof(Lock_t));
+    mbedtls_aes_crypt_ecb(&ctx, MBEDTLS_AES_DECRYPT, input, output);
+    mbedtls_aes_free(&ctx);
+}
+
+
+
+#ifdef HARDWARE_RANDOM_NUM_GENERATOR
+// Generates a set of random values in byte array[size] based on hardware source
+void EddystoneService::generateRandom(uint8_t ain[], int size) {
+    mbedtls_entropy_context entropy;
+    mbedtls_entropy_init(&entropy);
+    // init entropy source
+    eddystoneRegisterEntropySource(&entropy);
+    mbedtls_ctr_drbg_context ctr_drbg;
+    mbedtls_ctr_drbg_init(&ctr_drbg);
+    mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
+    mbedtls_ctr_drbg_random(&ctr_drbg, ain, size);
+    mbedtls_ctr_drbg_free(&ctr_drbg);
+    mbedtls_entropy_free(&entropy);
+    return;
+}
+#else
+// Generates a set of random values in byte array[size] seeded by the clock(ms)
+void EddystoneService::generateRandom(uint8_t ain[], int size) {
+    int i;
+    // Random seed based on boot time in milliseconds
+    srand(timeSinceBootTimer.read_ms());
+    for (i = 0; i < size; i++) {
+        ain[i] = rand() % 256;
+    }
+    return;
+}
+#endif
+
+/*
+// ALTERNATE Better Random number generator (but has Memory usage issues)
+// Generates a set of random values in byte array[size]
+
+*/
+
+/** Reverse Even sized Array endianess: Big to Little or Little to Big */
+void EddystoneService::swapEndianArray(uint8_t ptrIn[], uint8_t ptrOut[], int size) {
+    int i;
+    for (i = 0; i < size; i++) {
+        ptrOut[i] = ptrIn[size - i - 1];
+    }
+    return;
+}
+
+/** Reverse endianess: Big to Little or Little to Big */
+uint16_t EddystoneService::swapEndian(uint16_t arg) {
+    return (arg / 256) + (arg % 256) * 256;
+}
+
+uint16_t EddystoneService::correctAdvertisementPeriod(uint16_t beaconPeriodIn) const
+{
+    /* Re-map beaconPeriod to within permissible bounds if necessary. */
+    if (beaconPeriodIn != 0) {
+        if (beaconPeriodIn < ble.gap().getMinNonConnectableAdvertisingInterval()) {
+            return ble.gap().getMinNonConnectableAdvertisingInterval();
+        } else if (beaconPeriodIn > ble.gap().getMaxAdvertisingInterval()) {
+            return ble.gap().getMaxAdvertisingInterval();
+        }
+    }
+    return beaconPeriodIn;
+}
+
+void EddystoneService::logPrintHex(uint8_t* a, int len) {
+    for (int i = 0; i < len; i++) {
+        LOG(("%x%x", a[i] >> 4, a[i] & 0x0f ));
+    }
+    LOG(("\r\n"));
+}
+
+void EddystoneService::setRandomMacAddress(void) {
+#ifdef EID_RANDOM_MAC
+    uint8_t macAddress[6]; // 48 bit Mac Address
+    generateRandom(macAddress, 6);
+    macAddress[5] |= 0xc0; // Ensure upper two bits are 11's for Random Add
+    ble.setAddress(BLEProtocol::AddressType::RANDOM_STATIC, macAddress);
+#endif
+}
+
+int EddystoneService::getEidSlot(void) {
+    int eidSlot = NO_EID_SLOT_SET; // by default;
+    for (int i = 0; i < MAX_ADV_SLOTS; i++) {
+        if (slotFrameTypes[nextEidSlot] == EDDYSTONE_FRAME_EID) {
+             eidSlot = nextEidSlot;
+             nextEidSlot = (nextEidSlot-1) % MAX_ADV_SLOTS;
+             break;
+        }
+        nextEidSlot = (nextEidSlot-1) % MAX_ADV_SLOTS; // ensure the slot numbers wrap
+    }
+    return eidSlot;
+}
+    
+
+const uint8_t EddystoneService::slotDefaultUids[MAX_ADV_SLOTS][16] = EDDYSTONE_DEFAULT_SLOT_UIDS;
+
+const uint8_t EddystoneService::slotDefaultEidIdentityKeys[MAX_ADV_SLOTS][16] = EDDYSTONE_DEFAULT_SLOT_EID_IDENTITY_KEYS;
+
+const uint8_t EddystoneService::allSlotsDefaultEid[8] = {0,0,0,0,0,0,0,0};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EddystoneService.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,1170 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __EDDYSTONESERVICE_H__
+#define __EDDYSTONESERVICE_H__
+//
+// 2016-03 Eddystone Unified GATT
+//
+#include "EventQueue/EventQueue.h"
+#include "ble/BLE.h"
+#include "EddystoneTypes.h"
+#include "UIDFrame.h"
+#include "URLFrame.h"
+#include "TLMFrame.h"
+#include "EIDFrame.h"
+#include <string.h>
+#include "mbedtls/aes.h"
+#include "mbedtls/entropy.h"
+#include "mbedtls/ctr_drbg.h"
+
+#ifdef YOTTA_CFG_MBED_OS
+    #include "mbed-drivers/mbed.h"
+    #include "mbed-drivers/CircularBuffer.h"
+#else
+    #include "mbed.h"
+    #include "CircularBuffer.h"
+#endif
+
+#include "stdio.h"
+#include "Eddystone_config.h"
+
+/**
+ * This class implements the Eddystone-URL Config Service and the Eddystone
+ * Protocol Specification as defined in the publicly available specification at
+ * https://github.com/google/eddystone/blob/master/protocol-specification.md.
+ */
+class EddystoneService
+{
+public:
+    /**
+     * Total number of GATT Characteristics in the Eddystonei-URL Configuration
+     * Service.
+     */
+    static const uint16_t TOTAL_CHARACTERISTICS = 12;
+    
+    /**
+     * Max data that can be written to the data characteristic
+     */
+    static const uint8_t MAX_DATA_WRITE = 34; // FrameType+32B(IdentityKey)+Exp
+
+    /**
+     * Default interval for advertising packets for the Eddystone-URL
+     * Configuration Service.
+     */
+    static const uint32_t DEFAULT_CONFIG_PERIOD_MSEC    = EDDYSTONE_DEFAULT_CONFIG_ADV_INTERVAL;
+
+    /**
+     * Enumeration that defines the various operation modes of the
+     * EddystoneService.
+     *
+     * @note The main app can change the mode of EddystoneService at any point
+     *       of time by calling startConfigService() or startBeaconService().
+     *       Resources from the previous mode will be freed.
+     *
+     * @note It is currently NOT possible to force EddystoneService back into
+     *       EDDYSTONE_MODE_NONE.
+     */
+    enum OperationModes {
+        /**
+         * NONE: EddystoneService has been initialized but no memory has been
+         * dynamically allocated. Additionally, no services are running
+         * nothing is being advertised.
+         */
+        EDDYSTONE_MODE_NONE,
+        /**
+         * CONFIG: EddystoneService has been initialized, the configuration
+         *         service started and memory has been allocated for BLE
+         *         characteristics. Memory consumption peaks during CONFIG
+         *         mode.
+         */
+        EDDYSTONE_MODE_CONFIG,
+        /**
+         * BEACON: Eddystone service is running as a beacon advertising URL,
+         *         UID and/or TLM frames depending on how it is configured.
+         */
+        EDDYSTONE_MODE_BEACON
+    };
+
+    /**
+     * Structure that encapsulates the Eddystone configuration parameters. This
+     * structure is particularly useful when storing the parameters to
+     * persistent storage.
+     */
+    struct EddystoneParams_t {
+        /**
+         * A buffer describing the capabilities of the beacon
+         */
+        Capability_t            capabilities;
+
+         /**
+         * Defines the slot that advInterval, radioPower, advPower, advSlotData operate on
+         */
+        uint8_t                 activeSlot;
+
+        /**
+         * The Beacon interval for each beacon slot
+         *
+         * @note A value of zero disables Eddystone-URL frame trasmissions.
+         */
+        SlotAdvIntervals_t      slotAdvIntervals;
+
+         /**
+         * The Radio TX Powers supported by this beacon
+         */
+        PowerLevels_t           radioTxPowerLevels;
+
+         /**
+         * The Radio TX Power set for each slot
+         */
+        SlotTxPowerLevels_t     slotRadioTxPowerLevels;
+
+        /**
+         * The Calibrated Adv TX Powers supported by this beacon (one for each radio power)
+         */
+        PowerLevels_t           advTxPowerLevels;
+
+        /**
+         * The Adv TX Power set for each slot
+         */
+        SlotTxPowerLevels_t     slotAdvTxPowerLevels;
+
+        /**
+         * The value of the Eddystone-URL Configuration Service Lock State
+         * characteristic.
+         */
+        uint8_t                 lockState;
+
+        /**
+         * The value of the Eddystone-URL Configuration Service Unlock
+         * characteristic that can be used to unlock the beacon and clear the
+         * single-use lock-code.
+         */
+        Lock_t                  unlockToken;
+
+        /**
+         * An array holding the 128-bit unlockKey (big endian)
+         */
+        Lock_t                  unlockKey;
+
+        /**
+         * An array holding the 128-bit challenge (big endian) in the
+         * challenge/response unlock protocol
+         */
+        Lock_t                  challenge;
+
+        /**
+         * EID: An array holding the 256-bit private Ecdh Key (big endian)
+         */
+        //PrivateEcdhKey_t        privateEcdhKey;
+
+        /**
+         * EID: An array holding the 256-bit public Ecdh Key (big endian)
+         */
+        //PublicEcdhKey_t         publicEcdhKey;
+
+        /**
+         * EID: An array holding the slot next rotation times
+         */
+        //SlotEidNextRotationTimes_t      slotEidNextRotationTimes;
+
+        /**
+         * EID: An array holding the slot rotation period exponents
+         */
+        SlotEidRotationPeriodExps_t     slotEidRotationPeriodExps;
+
+        /**
+         * EID: An array holding the slot 128-bit EID Identity Key (big endian)
+         */
+        SlotEidIdentityKeys_t           slotEidIdentityKeys;
+
+        /**
+         * Specifies the type of each frame indexed by slot
+         */
+        SlotFrameTypes_t    slotFrameTypes;
+
+        /**
+         * A buffer that contains all slot frames, 32-bytes allocated to each frame
+         */
+        SlotStorage_t       slotStorage;
+
+         /**
+         * The state of the recently invoked Factory Reset characteristic
+         */
+        uint8_t          factoryReset;
+
+        /**
+         * The state of the recently invoked Remain Connectable characteristic
+         */
+        uint8_t          remainConnectable;
+    };
+
+    /**
+     * Enumeration that defines the various error codes for EddystoneService.
+     */
+    enum EddystoneError_t {
+        /**
+         * No error occurred.
+         */
+        EDDYSTONE_ERROR_NONE,
+        /**
+         * The supplied advertising interval is invalid. The interval may be
+         * too short/long for the type of advertising packets being broadcast.
+         *
+         * @note For the acceptable range of advertising interval refer to the
+         *       following functions in mbed BLE API:
+         *       - Gap::getMinNonConnectableAdvertisingInterval()
+         *       - Gap::getMinAdvertisingInterval()
+         *       - Gap::getMaxAdvertisingInterval()
+         */
+        EDDYSTONE_ERROR_INVALID_ADVERTISING_INTERVAL,
+        /**
+         * The result of executing a call when the the EddystoneService is in
+         * the incorrect operation mode.
+         */
+        EDDYSTONE_ERROR_INVALID_STATE
+    };
+
+    /**
+     * Enumeration that defines the available frame types within Eddystone
+     * advertising packets.
+     */
+    enum FrameType {
+        /**
+         * The Eddystone-UID frame. Refer to
+         * https://github.com/google/eddystone/tree/master/eddystone-uid.
+         */
+        EDDYSTONE_FRAME_UID,
+        /**
+         * The Eddystone-URL frame. Refer to
+         * https://github.com/google/eddystone/tree/master/eddystone-url.
+         */
+        EDDYSTONE_FRAME_URL,
+        /**
+         * The Eddystone-TLM frame. Refer to
+         * https://github.com/google/eddystone/tree/master/eddystone-tlm.
+         */
+        EDDYSTONE_FRAME_TLM,
+        /**
+         * The Eddystone-EID frame. Refer to
+         * https://github.com/google/eddystone/tree/master/eddystone-eid.
+         */
+        EDDYSTONE_FRAME_EID,
+        /**
+         * The total number Eddystone frame types.
+         */
+        NUM_EDDYSTONE_FRAMES
+    };
+
+    typedef eq::EventQueue event_queue_t;
+
+    /**
+     * Constructor that Initializes the EddystoneService using parameters from
+     * the supplied EddystoneParams_t. This constructor is particularly useful
+     * for configuring the EddystoneService with parameters fetched from
+     * persistent storage.
+     *
+     * @param[in] bleIn
+     *              The BLE instance.
+     * @param[in] paramIn
+     *              The input Eddystone configuration parameters.
+     * @param[in] radioPowerLevelsIn
+     *              The value set internally into the radion tx power.
+     * @param[in] eventQueue
+     *              The event queue used by the service to schedule tasks.
+     * @param[in] advConfigIntervalIn
+     *              The advertising interval for advertising packets of the
+     *              Eddystone-URL Configuration Service.
+     */
+    EddystoneService(BLE                 &bleIn,
+                     EddystoneParams_t   ¶msIn,
+                     const PowerLevels_t &radioPowerLevelsIn,
+                     event_queue_t       &eventQueue,
+                     uint32_t            advConfigIntervalIn = DEFAULT_CONFIG_PERIOD_MSEC);
+
+    /**
+     * Constructor to initialize the EddystoneService to default values.
+     *
+     * @param[in] bleIn
+     *              The BLE instance.
+     * @param[in] advPowerLevelsIn
+     *              The value of the Eddystone-URL Configuration Service TX
+     *              Power Mode characteristic.
+     * @param[in] radioPowerLevelsIn
+     *              The value set internally into the radion tx power.
+     * @param[in] eventQueue
+     *              The event queue used by the service to schedule tasks.
+     * @param[in] advConfigIntervalIn
+     *              The advertising interval for advertising packets of the
+     *              Eddystone-URL Configuration Service.
+     *
+     * @note When using this constructor the setURLData(), setTMLData() and
+     *       setUIDData() and setEIDData() functions must be called to initialize
+     *       EddystoneService manually.
+     */
+    EddystoneService(BLE                 &bleIn,
+                     const PowerLevels_t &advPowerLevelsIn,
+                     const PowerLevels_t &radioPowerLevelsIn,
+                     event_queue_t       &eventQueue,
+                     uint32_t            advConfigIntervalIn = DEFAULT_CONFIG_PERIOD_MSEC);
+                     
+          
+    /**
+     * Generate the EID Beacon Random ECHD Keys (private and Public)
+     */                  
+    void genEIDBeaconKeys(void);                
+
+    /**
+     * Factory Reset all parameters in the beacon
+     */
+    void doFactoryReset(void);
+
+    /**
+     * Setup callback to update BatteryVoltage in Eddystone-TLM frames
+     *
+     * @param[in] tlmBatteryVoltageCallbackIn
+     *              The callback being registered.
+     */
+    void onTLMBatteryVoltageUpdate(TlmUpdateCallback_t tlmBatteryVoltageCallbackIn);
+
+    /**
+     * Setup callback to update BeaconTemperature in Eddystone-TLM frames
+     *
+     * @param[in] tlmBeaconTemperatureCallbackIn
+     *              The callback being registered.
+     */
+    void onTLMBeaconTemperatureUpdate(TlmUpdateCallback_t tlmBeaconTemperatureCallbackIn);
+
+    /**
+     * Change the EddystoneService OperationMode to EDDYSTONE_MODE_CONFIG.
+     *
+     * @retval EDDYSTONE_ERROR_NONE if the operation succeeded.
+     * @retval EDDYSONE_ERROR_INVALID_ADVERTISING_INTERVAL if the configured
+     *         advertising interval is zero.
+     *
+     * @note If EddystoneService was previously in EDDYSTONE_MODE_BEACON, then
+     *       the resources allocated to that mode of operation such as memory
+     *       are freed and the BLE instance shutdown before the new operation
+     *       mode is configured.
+     */
+    EddystoneError_t startConfigService(void);
+
+    /**
+     * Change the EddystoneService to start transmitting Eddystone beacons
+     * operationMode = EDDYSTONE_MODE_BEACON
+     *
+     * @retval EDDYSTONE_ERROR_NONE if the operation succeeded.
+     * @retval EDDYSONE_ERROR_INVALID_ADVERTISING_INTERVAL if the configured
+     *         advertising interval is zero.
+     *
+     * @note If EddystoneService was previously in EDDYSTONE_MODE_CONFIG, then
+     *       the resources allocated to that mode of operation such as memory
+     *       are freed and the BLE instance shutdown before the new operation
+     *       mode is configured.
+     */
+    EddystoneError_t startEddystoneBeaconAdvertisements(void);
+
+    /**
+     * Set the Comple Local Name for the BLE device. This not only updates
+     * the value of the Device Name Characteristic, it also updates the scan
+     * response payload if the EddystoneService is currently in
+     * EDDYSTONE_MODE_CONFIG.
+     *
+     * @param[in] deviceNameIn
+     *              A pointer to a null terminated string containing the new
+     *              device name.
+     *
+     * @return BLE_ERROR_NONE if the name was successfully set. Otherwise an
+     *         appropriate error.
+     *
+     * @note EddystoneService does not make an internal copy of the string
+     *       pointed to by @p deviceNameIn. Therefore, the user is responsible
+     *       for ensuring that the string persists in memory as long as it is
+     *       in use by the EddystoneService.
+     *
+     * @note The device name is not considered an Eddystone configuration
+     *       parameter; therefore, it is not contained within the
+     *       EddystoneParams_t structure and must be stored to persistent
+     *       storage separately.
+     */
+    ble_error_t setCompleteDeviceName(const char *deviceNameIn);
+
+    /**
+     * Get the Eddystone Configuration parameters. This is particularly useful
+     * for storing the configuration parameters in persistent storage.
+     * It is not the responsibility of the Eddystone implementation to store
+     * the configured parameters in persistent storage since this is
+     * platform-specific.
+     *
+     * @param[out] params
+     *              A reference to an EddystoneParams_t structure with the
+     *              configured parameters of the EddystoneService.
+     */
+    void getEddystoneParams(EddystoneParams_t ¶ms);
+
+    /**
+     * Start advertising packets indicating the Eddystone Configuration state
+     * operationMode = EDDYSTONE_MODE_CONFIG
+     */
+    EddystoneService::EddystoneError_t startEddystoneConfigAdvertisements(void);
+
+    /**
+     * Free the resources acquired by a call to setupBeaconService() and
+     * cancel all pending callbacks that operate the radio and frame queue.
+     *
+     * @note This call will not modify the current state of the BLE device.
+     *       EddystoneService::stopBeaconService should only be called after
+     *       a call to BLE::shutdown().
+     */
+    void stopEddystoneBeaconAdvertisements(void);
+
+    /**
+     * Initialize and start the BLE Eddystone Configuration Service
+     * This will create the 12-characteristics of the service and make them
+     * available when a client connects
+     */
+    void startEddystoneConfigService();
+
+    /**
+     * Stops the Eddystone Configuration Service and frees its resources
+     * and cancels all pending callbacks that operate the radio and frame queue.
+     *
+     * @note This call will not modify the current state of the BLE device.
+     *       EddystoneService::stopBeaconService should only be called after
+     *       a call to BLE::shutdown().
+     */
+    void stopEddystoneConfigService();
+    
+    /**
+     * Print an array as a set of hex values 
+     *
+     * @param[in] a
+     *              The array to be printed.
+     * 
+     * @param[in] len
+     *              The length of the array.
+     *
+     * @return void
+     *
+     */
+    static void logPrintHex(uint8_t* a, int len);
+    
+    /**
+     * Swaps the endianess of an array ptrIn[size] to ptrOut[size]
+     *
+     * @param[in] *ptrIn
+     *              The input array
+     * @param[in] *ptrOut
+     *              The output array
+     * @param[in] size
+     *              The sizes of the arrays (num bytes to be reversed)
+     */
+    static void swapEndianArray(uint8_t *ptrIn, uint8_t *ptrOut, int size);
+    
+    /**
+     * Generate a random array of bytes of length size
+     *
+     * @param[in] *ain
+     *              The input/output array
+     * @param[in] size
+     *              The size of the array in bytes
+     */
+    static void generateRandom(uint8_t *ain, int size);
+    
+    /**
+     * Timer that keeps track of the time since boot.
+     */
+
+    static Timer        timeSinceBootTimer;
+    
+private:
+
+    static const uint8_t NO_EID_SLOT_SET = 0xff;
+     
+    static const uint8_t UNDEFINED_FRAME_FORMAT = 0xff;
+     
+    static const uint8_t REMAIN_CONNECTABLE_SET = 0x01;
+          
+    static const uint8_t REMAIN_CONNECTABLE_UNSET = 0x00;
+     
+    /**
+     * Helper funtion that will be registered as an initialization complete
+     * callback when BLE::shutdown() is called. This is necessary when changing
+     * Eddystone OperationModes. Once the BLE initialization is complete, this
+     * callback will initialize all the necessary resource to operate
+     * Eddystone service in the selected mode.
+     *
+     * @param[in] initContext
+     *              The context provided by BLE API when initialization
+     *              completes.
+     */
+    void bleInitComplete(BLE::InitializationCompleteCallbackContext* initContext);
+
+    /**
+     * When in EDDYSTONE_MODE_BEACON this function is called to update the
+     * advertising payload to contain the information related to the specified
+     * FrameType.
+     *
+     * @param[in] slot
+     *              The slot to populate the advertising payload with.
+     */
+    void swapAdvertisedFrame(int slot);
+
+    /**
+     * Helper function that manages the BLE radio that is used to broadcast
+     * advertising packets. To advertise frames at the configured intervals
+     * the actual advertising interval of the BLE instance is set to the value
+     * returned by Gap::getMaxAdvertisingInterval() from the BLE API. When a
+     * frame needs to be advertised, the enqueueFrame() callbacks add the frame
+     * type to the advFrameQueue and post a manageRadio() callback. When the
+     * callback is executed, the frame is dequeued and advertised using the
+     * radio (by updating the advertising payload). manageRadio() also posts a
+     * callback to itself Gap::getMinNonConnectableAdvertisingInterval()
+     * milliseconds later. In this callback, manageRadio() will advertise the
+     * next frame in the queue, yet if there is none it calls
+     * Gap::stopAdvertising() and does not post any further callbacks.
+     */
+    void manageRadio(void);
+
+    /**
+     * Regular callbacks posted at the rate of slotAdvPeriod[slot] milliseconds
+     * enqueue frames to be advertised. If the
+     * frame queue is currently empty, then this function directly calls
+     * manageRadio() to broadcast the required FrameType.
+     *
+     * @param[in] frameType
+     *              The FrameType to enqueue for broadcasting.
+     */
+    void enqueueFrame(int slot);
+
+    /**
+     * Helper function that updates the advertising payload when in
+     * EDDYSTONE_MODE_BEACON to contain a new frame.
+     *
+     * @param[in] rawFrame
+     *              The raw bytes of the frame to advertise.
+     * @param[in] rawFrameLength
+     *              The length in bytes of the array pointed to by @p rawFrame.
+     */
+    void updateAdvertisementPacket(const uint8_t* rawFrame, size_t rawFrameLength);
+
+    /**
+     * Helper function that updates the information in the Eddystone-TLM frames
+     * Internally, this function executes the registered callbacks to update
+     * beacon Battery Voltage and Temperature (if available). Furthermore, this
+     * function updates the raw frame data. This operation must be done fairly
+     * often because the Eddystone-TLM frame Time Since Boot must have a 0.1
+     * seconds resolution according to the Eddystone specification.
+     */
+    void updateRawTLMFrame(uint8_t* frame);
+
+    /**
+     * Calculate the Frame pointer from the slot number
+     */
+    uint8_t* slotToFrame(int slot);
+
+    /**
+     * Free the characteric resources acquired by a call to
+     * startEddystoneConfigService().
+     */
+    void freeConfigCharacteristics(void);
+
+    /**
+     * Helper function used to update the GATT database following any
+     * change to the internal state of the service object.
+     */
+    void updateCharacteristicValues(void);
+
+    /**
+     * Helper function to setup the payload of scan response packets for
+     * Eddystone-URL Configuration Service.
+     */
+    void setupEddystoneConfigScanResponse(void);
+
+    /**
+     * Callback registered to the BLE API to authorize write operations to the
+     * Eddystone Configuration Service Lock characteristic.
+     *
+     * @param[in] authParams
+     *              Write authentication information.
+     */
+    void writeLockAuthorizationCallback(GattWriteAuthCallbackParams *authParams);
+
+    /**
+     * Callback registered to the BLE API to authorize write operations to the
+     * Eddystone Configuration Service Unlock characteristic.
+     *
+     * @param[in] authParams
+     *              Write authentication information.
+     */
+    void writeUnlockAuthorizationCallback(GattWriteAuthCallbackParams *authParams);
+
+    /**
+     * Callback registered to the BLE API to authorize write operations to the
+     * Eddystone Configuration Service advSlotData characteristic.
+     *
+     * @param[in] authParams
+     *              Write authentication information.
+     */
+    void writeVarLengthDataAuthorizationCallback(GattWriteAuthCallbackParams *authParams);
+
+    /**
+     * Callback registered to the BLE API to authorize write operations to the
+     * lockState characteristic which can be 1 byte or 17 bytes long.
+     *
+     * @param[in] authParams
+     *              Write authentication information.
+     */
+    void writeLockStateAuthorizationCallback(GattWriteAuthCallbackParams *authParams);
+
+    /**
+     * Callback registered to the BLE API to authorize write operations to simple fixed length
+     * value characteristic types.
+     *
+     * @param[in] authParams
+     *              Write authentication information.
+     */
+    template <typename T>
+    void writeBasicAuthorizationCallback(GattWriteAuthCallbackParams *authParams);
+
+    /**
+     * This callback is invoked when a GATT client attempts to write to the
+     * Active Slot characteristic of the service.
+     *
+     * @param[in] authParams
+     *              Information about the values that are being read.
+     */
+    template <typename T>
+    void writeActiveSlotAuthorizationCallback(GattWriteAuthCallbackParams *authParams);
+
+    /**
+     * READ AUTHORIZATIONS
+     */
+
+    /**
+     * This callback is invoked when a GATT client attempts to read from a
+     * basic characteristic of the Eddystone Configuration Service, which
+     * is blocked if the beacon lock is set to LOCKED.
+     *
+     * @param[in] authParams
+     *              Information about the values that are being read.
+     */
+    void readBasicTestLockAuthorizationCallback(GattReadAuthCallbackParams *authParams);
+    
+    /**
+     * This callback is invoked when a GATT client attempts to read from the
+     * EidIdentityKey characteristic of the Eddystone Configuration Service,
+     * which is blocked if the beacon lock is set to LOCKED, or the key has not
+     * been set/initialized.
+     *
+     * @param[in] authParams
+     *              Information about the values that are being read.
+     */
+    void readEidIdentityAuthorizationCallback(GattReadAuthCallbackParams *authParams);
+    
+    /**
+     * This callback is invoked when a GATT client attempts to read from the
+     * PublicEcdhKey characteristic of the Eddystone Configuration Service,
+     * which is blocked if the beacon lock is set to LOCKED, or the key has not
+     * been set/initialized.
+     *
+     * @param[in] authParams
+     *              Information about the values that are being read.
+     */
+    void readPublicEcdhKeyAuthorizationCallback(GattReadAuthCallbackParams *authParams);
+    
+
+    /**
+     * This callback is invoked when a GATT client attempts to read from the
+     * Adv Slot Data characteristic of the Eddystone Configuration Service,
+     * which isblocked if the beacon lock is set to LOCKED.
+     *
+     * @param[in] authParams
+     *              Information about the values that are being read.
+     */
+    void readDataAuthorizationCallback(GattReadAuthCallbackParams *authParams);
+    
+    /**
+     * Checks if this is valid frame data (i.e. length > 0)
+     *
+     * @param[in] frame
+     *              The frame being tested
+     * @returns   frame is valid or not.
+     */
+    bool testValidFrame(uint8_t* frame);
+
+    /**
+     * This callback is invoked when a GATT client attempts to read the challenge
+     * from the Unlock characteristic of the Eddystone Configuration Service,
+     * which is blocked if the beacon lock is set to UNLOCKED.
+     *
+     * @param[in] authParams
+     *              Information about the values that are being read.
+     */
+    void readUnlockAuthorizationCallback(GattReadAuthCallbackParams *authParams);
+
+    /**
+     * This callback is invoked when a GATT client attempts to read from the
+     * Radio Tx Power characteristic of the Eddystone Configuration Service,
+     * which is blocked if the beacon lock is set to LOCKED.
+     *
+     * @param[in] authParams
+     *              Information about the values that are being read.
+     */
+    void readRadioTxPowerAuthorizationCallback(GattReadAuthCallbackParams *authParams);
+
+    /**
+     * This callback is invoked when a GATT client attempts to read from the
+     * Radio Tx Power characteristic of the Eddystone Configuration Service,
+     * which is blocked if the beacon lock is set to LOCKED.
+     *
+     * @param[in] authParams
+     *              Information about the values that are being read.
+     */
+    void readAdvTxPowerAuthorizationCallback(GattReadAuthCallbackParams *authParams);
+
+    /**
+     * This callback is invoked when a GATT client attempts to read from the
+     * Adv Interval characteristic of the Eddystone Configuration Service,
+     * which is blocked if the beacon lock is set to LOCKED.
+     *
+     * @param[in] authParams
+     *              Information about the values that are being read.
+     */
+    void readAdvIntervalAuthorizationCallback(GattReadAuthCallbackParams *authParams);
+
+    /**
+     * Calculates the index in the radio power levels array which can be used
+     * to index into the adv power levels array to find the calibrated adv power
+     * used in the adv frame.
+     */
+    uint8_t radioTxPowerToIndex(int8_t txPower);
+
+    /**
+     * This callback is invoked when a GATT client attempts to modify any of the
+     * characteristics of this service. Attempts to do so are also applied to
+     * the internal state of this service object.
+     *
+     * @param[in] writeParams
+     *              Information about the values that are being written.
+     */
+    void onDataWrittenCallback(const GattWriteCallbackParams *writeParams);
+
+    /**
+     * Sets the power for the frame in a particular slot using the
+     * adv tx power parmeter
+     *
+     * @param[in] slot
+     *              The the current slot number being considered
+     * @param[in] advTxPower
+     *              The adv power required in a frame
+     */
+    void setFrameTxPower(uint8_t slot, int8_t advTxPower);
+
+    /**
+     * AES128 ECB Encrypts a 16-byte input array with a key, to an output array
+     *
+     * @param[in] *key
+     *              The encryption key
+     * @param[in] *input
+     *              The input array
+     * @param[in] *output
+     *              The output array (contains the encrypted data)
+     */
+    void aes128Encrypt(uint8_t *key, uint8_t *input, uint8_t *output);
+
+    /**
+     * AES128 ECB Deccrypts a 16-byte input array with a key, to an output array
+     *
+     * @param[in] *key
+     *              The decryption key
+     * @param[in] *input
+     *              The input array
+     * @param[in] *output
+     *              The output array (containing the decrypted data)
+     */
+    void aes128Decrypt(uint8_t *key, uint8_t *input, uint8_t *output);
+
+
+
+    /**
+     * Swaps the endianess of a 16-bit unsigned int
+     *
+     * @param[in] arg
+     *              The value with the byte order to be reversed
+     *
+     * @return The resulting 16-bit value with byte order reversed
+     */
+    uint16_t swapEndian(uint16_t arg);
+
+    /**
+     * Correct the advertising interval for non-connectable packets.
+     *
+     * @param[in] beaconPeriodIn
+     *              The input interval in milliseconds.
+     *
+     * @return The corrected interval in milliseconds.
+     *
+     * @note For the acceptable range of advertising interval refer to the
+     *       following functions in mbed BLE API:
+     *       - Gap::getMinNonConnectableAdvertisingInterval()
+     *       - Gap::getMaxAdvertisingInterval()
+     */
+    uint16_t correctAdvertisementPeriod(uint16_t beaconPeriodIn) const;
+    
+    /**
+     * Swaps the endianess of a 16-bit unsigned int
+     *
+     * @param[in] arg
+     *              The value with the byte order to be reversed
+     *
+     * @return The resulting 16-bit value with byte order reversed
+     */
+    void setRandomMacAddress(void);     
+    
+    /**
+     * Finds the first EID slot set
+     *
+     * @return slot number (and if not, returns NO_EID_SLOT_SET = -1)
+     */
+    int getEidSlot(void);
+
+    /**
+     * BLE instance that EddystoneService will operate on.
+     */
+    BLE                                                             &ble;
+
+    /**
+     * The advertising interval for Eddystone-URL Config Service advertising
+     * packets.
+     */
+    uint32_t                                                        advConfigInterval;
+    /**
+     * Current EddystoneServce operation mode.
+     */
+    uint8_t                                                         operationMode;
+    
+    int                                                             genBeaconKeyRC;
+
+    /**
+     * GATT Service Variables
+     */
+
+    /**
+     * An array describing the capabilites of the beacon.
+     */
+    Capability_t                                                    capabilities;
+
+    /**
+     * The currenty defined active slot.
+     */
+    uint8_t                                                         activeSlot;
+
+    /**
+     * An array containing all the adv intervals for each slot index
+     */
+    SlotAdvIntervals_t                                              slotAdvIntervals;
+
+    /**
+     * The value of the Eddystone Configuration Service radioTX Power
+     * characteristic.
+     */
+    SlotTxPowerLevels_t                                             slotRadioTxPowerLevels;
+
+    /**
+     * An array containing the supported radio tx power levels for this beacon
+     */
+    PowerLevels_t                                                   radioTxPowerLevels;
+
+    /**
+     * An array containing all possible values for advertised tx power in Eddystone
+     * slots.
+     */
+    SlotTxPowerLevels_t                                             slotAdvTxPowerLevels;
+
+    /**
+     * An array containing the supported adv tx power levels for this beacon
+     */
+    PowerLevels_t                                                   advTxPowerLevels;
+
+    /**
+     * The value of the Eddystone Configuration Service Lock State
+     * characteristic.
+     */
+    uint8_t                                                         lockState;
+
+
+    /**
+     * The value of the Eddystone Configuration Service Lock State
+     * buffer
+     */
+    LockState_t                                                     lockStateBuf;
+
+    /**
+     * The value of the Eddystone Configuration Service unlock key
+     */
+    Lock_t                                                          unlockKey;
+
+    /**
+     * The value of the Eddystone Configuration Service unlock challenge
+     */
+    Lock_t                                                          challenge;
+
+   /**
+     * The value of the Eddystone Configuration Service unlock token. A write
+     * to the unlock characteristic must contain this token to unlock the beacon
+     */
+    Lock_t                                                          unlockToken;
+
+
+    /**
+     * EID: An array holding the 256-bit private Ecdh Key (big endian)
+     */
+    PrivateEcdhKey_t                                                privateEcdhKey;
+
+    /**
+     * EID: An array holding the 256-bit public Ecdh Key (big endian)
+     */
+    PublicEcdhKey_t                                                 publicEcdhKey;
+    
+    /**
+     * EID: An array holding the 256-bit public Ecdh Key (little endian)
+     */
+    PublicEcdhKey_t                                                 publicEcdhKeyLE;
+
+    /**
+     * EID: An array holding the slot rotation period exponents
+     */
+    SlotEidRotationPeriodExps_t                                     slotEidRotationPeriodExps;
+
+    /**
+     * EID: An array holding the slot Eid Identity Keys
+     */
+    SlotEidIdentityKeys_t                                           slotEidIdentityKeys;
+
+    /**
+     * EID: An array holding the slot Eid Public Ecdh Keys
+     */
+    //SlotEidPublicEcdhKeys_t                                         slotEidPublicEcdhKeys;
+
+    /**
+     * Instance of the UID frame.
+     */
+    UIDFrame                                                        uidFrame;
+
+    /**
+     * Instance of the URL frame.
+     */
+    URLFrame                                                        urlFrame;
+
+    /**
+     * Instance of the TLM frame.
+     */
+    TLMFrame                                                        tlmFrame;
+
+    /**
+     * Instance of the EID frame.
+     */
+    EIDFrame                                                        eidFrame;
+
+    /**
+     * The value of the Eddystone Configuration Service reset
+     * characteristic.
+     */
+    uint8_t                                                         factoryReset;
+
+    /**
+     * The value of the Eddystone Configuration Service Remain Connectable
+     * characteristic.
+     */
+    uint8_t                                                         remainConnectable;
+
+    /**
+     * CHARACTERISTIC STORAGE
+     */
+
+    /**
+     * Pointer to the BLE API characteristic encapsulation for the Eddystone
+     * Configuration Service Capabilities characteristic.
+     */
+    ReadOnlyArrayGattCharacteristic<uint8_t, sizeof(Capability_t)>  *capabilitiesChar;
+
+    /**
+     * Pointer to the BLE API characteristic encapsulation for the Eddystone
+     * Configuration Service Active Slot characteristic.
+     */
+    ReadWriteGattCharacteristic<uint8_t>                            *activeSlotChar;
+
+    /**
+     * Pointer to the BLE API characteristic encapsulation for the Eddystone
+     * Configuration Service Adv Interval characteristic.
+     */
+    ReadWriteGattCharacteristic<uint16_t>                           *advIntervalChar;
+
+    /**
+     * Pointer to the BLE API characteristic encapsulation for the Eddystone
+     * Configuration Service Radio Tx Power characteristic.
+     */
+    ReadWriteGattCharacteristic<int8_t>                             *radioTxPowerChar;
+
+    /**
+     * Pointer to the BLE API characteristic encapsulation for the Eddystone
+     * Configuration Service Adv Tx Power characteristic.
+     */
+    ReadWriteGattCharacteristic<int8_t>                             *advTxPowerChar;
+
+    /**
+     * Pointer to the BLE API characteristic encapsulation for the Eddystone
+     * Configuration Service Lock State characteristic.
+     */
+    GattCharacteristic                                               *lockStateChar;
+
+    /**
+     * Pointer to the BLE API characteristic encapsulation for the Eddystone
+     * Configuration Service Unlock characteristic.
+     */
+    ReadWriteArrayGattCharacteristic<uint8_t, sizeof(Lock_t)>       *unlockChar;
+
+    /**
+     * Pointer to the BLE API characteristic encapsulation for the Eddystone
+     * Configuration Service Public ECDH Key characteristic.
+     */
+    GattCharacteristic                                              *publicEcdhKeyChar;
+
+    /**
+     * Pointer to the BLE API characteristic encapsulation for the Eddystone-URL
+     * Configuration Service EID Identity Key characteristic.
+     */
+    GattCharacteristic                                              *eidIdentityKeyChar;
+
+    /**
+     * Pointer to the BLE API characteristic encapsulation for the Eddystone-URL
+     * Configuration Service Adv Slot Data characteristic.
+     */
+    GattCharacteristic                                              *advSlotDataChar;
+
+    /**
+     * Pointer to the BLE API characteristic encapsulation for the Eddystone-URL
+     * Configuration Service Factory Reset characteristic.
+     */
+    WriteOnlyGattCharacteristic<uint8_t>                            *factoryResetChar;
+
+    /**
+     * Pointer to the BLE API characteristic encapsulation for the Eddystone-GATT
+     * Configuration Service Remain Connectable characteristic.
+     */
+    ReadWriteGattCharacteristic<uint8_t>                            *remainConnectableChar;
+
+    /**
+     * END OF GATT CHARACTERISTICS
+     */
+
+    /**
+     * EID: An array holding the slot next rotation times
+     */
+    SlotEidNextRotationTimes_t                                      slotEidNextRotationTimes;
+
+    /**
+     * EID: Storage for the current slot encrypted EID Identity Key
+     */
+    EidIdentityKey_t                                                encryptedEidIdentityKey;
+
+    /*
+     * Storage for all the slots / frames
+     */
+    SlotStorage_t                                                   slotStorage;
+
+    /**
+     * An array that defines the frame type of each slot using the slot number
+     * as an index.
+     */
+    SlotFrameTypes_t                                                slotFrameTypes;
+
+    /**
+     * Circular buffer that represents of Eddystone frames to be advertised.
+     */
+    CircularBuffer<uint8_t, MAX_ADV_SLOTS>                          advFrameQueue;
+
+    /**
+     * The registered callback to update the Eddystone-TLM frame Battery
+     * Voltage.
+     */
+    TlmUpdateCallback_t                                             tlmBatteryVoltageCallback;
+
+    /**
+     * The registered callback to update the Eddystone-TLM frame Beacon
+     * Temperature.
+     */
+    TlmUpdateCallback_t                                             tlmBeaconTemperatureCallback;
+
+    /**
+     * Type for the array of callback handles for all the slot timers
+     */
+    typedef event_queue_t::event_handle_t SlotCallbackHandles_t[MAX_ADV_SLOTS];
+
+    /**
+     * An array of all the slot timer callbacks handles
+     */
+    SlotCallbackHandles_t                                           slotCallbackHandles;
+
+    /**
+     * Callback handle to keep track of manageRadio() callbacks.
+     */
+    event_queue_t::event_handle_t                                   radioManagerCallbackHandle;
+
+    /**
+     * GattCharacteristic table used to populate the BLE ATT table in the
+     * GATT Server.
+     */
+    GattCharacteristic                                              *charTable[TOTAL_CHARACTERISTICS];
+
+    /**
+     * Pointer to the device name currently being used.
+     */
+    const char                                                      *deviceName;
+
+    /**
+     * Defines an array of string constants (a container) used to initialise any URL slots
+     */
+    static const char* const slotDefaultUrls[];
+
+    /**
+     * Defines an array of UIDs to initialize UID slots
+     */
+    static const uint8_t slotDefaultUids[MAX_ADV_SLOTS][16];
+
+    /**
+     * Defines an array of EID (Identity keys) to initialize EID slots
+     */
+    static const uint8_t slotDefaultEidIdentityKeys[MAX_ADV_SLOTS][16];
+
+    /**
+     * Defines default EID payload before being updated with the first EID rotation value
+     */
+    static const uint8_t allSlotsDefaultEid[8];
+
+    /**
+     * Reference to the event queue used to post tasks
+     */
+    event_queue_t&                  eventQueue;
+    
+    /**
+     * Next EID slot frame that will be transmitted
+     */
+    uint8_t                         nextEidSlot;                     
+};
+
+#endif  /* __EDDYSTONESERVICE_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EddystoneTypes.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,233 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __EDDYSTONETYPES_H__
+#define __EDDYSTONETYPES_H__
+
+#include <stdint.h>
+#include <stddef.h>
+#include "Eddystone_config.h"
+
+/**
+ * Macro to expand a 16-bit Eddystone UUID to 128-bit UUID.
+ */
+#define UUID_ES_BEACON(FIRST, SECOND) {                          \
+        0xa3, 0x0c8, FIRST, SECOND, 0x8e, 0xd3, 0x4b, 0xdf,      \
+        0x8a, 0x39, 0xa0, 0x1b, 0xeb, 0xed, 0xe2, 0x95,          \
+}
+
+/**
+ * Eddystone 16-bit UUID.
+ */
+const uint8_t EDDYSTONE_UUID[] = {0xAA, 0xFE};
+
+/**
+ * Size of Eddystone UID. Needed to construct all frames raw bytes.
+ */
+const uint16_t EDDYSTONE_UUID_SIZE = sizeof(EDDYSTONE_UUID);
+
+/** BEGINING OF CHARACTERISTICS */
+
+/**
+ * 128-bit UUID for Eddystone-GATT Configuration Service.
+ */
+const uint8_t UUID_ES_BEACON_SERVICE[]         = UUID_ES_BEACON(0x75, 0x00);
+
+/**
+ * 128-bit UUID for Eddystone-URL Configuration Service Capabilities
+ * characteristic.
+ */
+const uint8_t UUID_CAPABILITIES_CHAR[]          = UUID_ES_BEACON(0x75, 0x01);
+
+/**
+ * 128-bit UUID for Eddystone-URL Configuration Service Active Slot
+ * characteristic.
+ */
+const uint8_t UUID_ACTIVE_SLOT_CHAR[]           = UUID_ES_BEACON(0x75, 0x02);
+
+/**
+ * 128-bit UUID for Eddystone-URL Configuration Service Advertising Interval
+ * characteristic.
+ */
+const uint8_t UUID_ADV_INTERVAL_CHAR[]          = UUID_ES_BEACON(0x75, 0x03);
+
+/**
+ * 128-bit UUID for Eddystone-URL Configuration Service Radio Tx Power
+ * characteristic.
+ */
+const uint8_t UUID_RADIO_TX_POWER_CHAR[]        = UUID_ES_BEACON(0x75, 0x04);
+
+/**
+ * 128-bit UUID for Eddystone-URL Configuration Service Adv Tx Power
+ * characteristic.
+ */
+const uint8_t UUID_ADV_TX_POWER_CHAR[]          = UUID_ES_BEACON(0x75, 0x05);
+
+/**
+ * 128-bit UUID for Eddystone-URL Configuration Service Lock State
+ * characteristic.
+ */
+const uint8_t UUID_LOCK_STATE_CHAR[]            = UUID_ES_BEACON(0x75, 0x06);
+
+/**
+ * 128-bit UUID for Eddystone-URL Configuration Service Unlock
+ * characteristic.
+ */
+const uint8_t UUID_UNLOCK_CHAR[]                = UUID_ES_BEACON(0x75, 0x07);
+
+/**
+ * 128-bit UUID for Eddystone-URL Configuration Service Public ECDH Key
+ * characteristic.
+ */
+const uint8_t UUID_PUBLIC_ECDH_KEY_CHAR[]       = UUID_ES_BEACON(0x75, 0x08);
+
+/**
+ * 128-bit UUID for Eddystone-URL Configuration Service EID Identity Key
+ * characteristic.
+ */
+const uint8_t UUID_EID_IDENTITY_KEY_CHAR[]      = UUID_ES_BEACON(0x75, 0x09);
+
+/**
+ * 128-bit UUID for Eddystone-URL Configuration Service Adv Slot Data
+ * characteristic.
+ */
+const uint8_t UUID_ADV_SLOT_DATA_CHAR[]         = UUID_ES_BEACON(0x75, 0x0a);
+
+/**
+ * 128-bit UUID for Eddystone-URL Configuration Service Reset
+ * characteristic.
+ */
+const uint8_t UUID_FACTORY_RESET_CHAR[]         = UUID_ES_BEACON(0x75, 0x0b);
+
+/**
+ * 128-bit UUID for Eddystone-URL Configuration Service Remain Connectable
+ * characteristic.
+ */
+const uint8_t UUID_REMAIN_CONNECTABLE_CHAR[]    = UUID_ES_BEACON(0x75, 0x0c);
+
+/** END OF CHARACTERISTICS  */
+
+/**
+ * Default Lock State used  by EddystoneService.
+ */
+const uint8_t DEFAULT_LOCK_STATE_DATA[] = {DEFAULT_LOCK_STATE};
+
+/**
+ * A type defining the size of the READ ONLY capability characteristic
+ */
+typedef uint8_t Capability_t[CAP_HDR_LEN + NUM_POWER_MODES];
+
+/**
+ * Type for the 128-bit for Eddystone-URL Configuration Service Lock and Unlock
+ * characteristic value.
+ */
+typedef uint8_t Lock_t[16];
+
+/**
+ * Type for the 128-bit for Eddystone-URL Configuration Service Advertised TX
+ * Power Levels characteristic value.
+ */
+typedef int8_t PowerLevels_t[NUM_POWER_MODES];
+
+/**
+ * Type representing the power level set for each slot
+ */
+typedef int8_t SlotTxPowerLevels_t[MAX_ADV_SLOTS];
+
+/**
+ * Type representing the adv interval set for each slot
+ */
+typedef uint16_t SlotAdvIntervals_t[MAX_ADV_SLOTS];
+
+/**
+ * Type representing the buffer used to represent the LockState and potentially
+ * an updated key
+ */
+typedef uint8_t LockState_t[17];
+
+/**
+ * Type representing the EID private ECDH Key
+ */
+typedef uint8_t PrivateEcdhKey_t[32];
+
+/**
+ * Type representing the EID public ECDH Key
+ */
+typedef uint8_t PublicEcdhKey_t[32];
+
+/**
+ * Type representing the EID Identity Key
+ */
+typedef uint8_t EidIdentityKey_t[16];
+
+/**
+ * Type representing the storage for a single slot
+ */
+typedef uint8_t Slot_t[32]; 
+
+/**
+ * Type representing the storage for all slots given MAX_ADV_SLOTS
+ */
+typedef uint8_t SlotStorage_t[MAX_ADV_SLOTS * sizeof(Slot_t)];
+
+/**
+ * Type representing the current frame types if each slot
+ */
+typedef uint8_t SlotFrameTypes_t[MAX_ADV_SLOTS];
+
+/**
+ * Type representing the EID rotation period exp for each slot
+ */
+typedef uint8_t SlotEidRotationPeriodExps_t[MAX_ADV_SLOTS];
+
+/**
+ * Type representing the EID next rotation time for each slot
+ */
+typedef uint32_t SlotEidNextRotationTimes_t[MAX_ADV_SLOTS];
+
+/**
+ * Type representing the EID identity keys for each slot
+ */
+typedef EidIdentityKey_t SlotEidIdentityKeys_t[MAX_ADV_SLOTS];
+
+/**
+ * Size in bytes of UID namespace ID.
+ */
+const size_t UID_NAMESPACEID_SIZE = 10;
+
+/**
+ * Type for the UID namespace ID.
+ */
+typedef uint8_t UIDNamespaceID_t[UID_NAMESPACEID_SIZE];
+
+/**
+ * Size in bytes of UID instance ID.
+ */
+const size_t UID_INSTANCEID_SIZE = 6;
+
+/**
+ * Type for the UID instance ID.
+ */
+typedef uint8_t UIDInstanceID_t[UID_INSTANCEID_SIZE];
+
+/**
+ * Type for callbacks to update Eddystone-TLM frame Batery Voltage and Beacon
+ * Temperature.
+ */
+typedef uint16_t (*TlmUpdateCallback_t) (uint16_t);
+
+
+#endif /* __EDDYSTONETYPES_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/Eddystone_config.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef EDDYSTONE_CONFIG_H_
+#define EDDYSTONE_CONFIG_H_
+
+/**
+ * Platform Target (if not set, default is nRF51-DK or nRF51-dongle)
+ * NOTE: All targets are assumed to be 32K (in target.json) and S110 (in config.h)
+ */
+// #define MinewTech
+
+// Version printed out on virtual terminal (independent of logging flag below)
+#define BUILD_VERSION_STR "EID Version 1.00 2016-08-31:20:00\r\n"
+
+/** 
+ * DEBUG OPTIONS
+ * For production: all defines below should be UNCOMMENTED
+ */ 
+#define GEN_BEACON_KEYS_AT_INIT
+#define HARDWARE_RANDOM_NUM_GENERATOR
+// #define EID_RANDOM_MAC
+// #define DONT_REMAIN_CONNECTABLE
+// #define NO_4SEC_START_DELAY
+#define NO_LOGGING
+
+/* Default enable printf logging, unless explicitly NO_LOGGING */
+#ifdef NO_LOGGING
+  #define LOG_PRINT 0
+#else
+  #define LOG_PRINT 1
+#endif
+
+#define LOG(x) do { if (LOG_PRINT) printf x; } while (0)
+
+/**
+ * NOTE1: If you don't define RESET_BUTTON, it won't compile the button handler in main.cpp
+ * This also doesn't declare or use the SHUTDOWN_LED
+ */
+#ifdef MinewTech
+  // *** MinewTech PIN defines *** 
+  #define LED_OFF 0
+  #define CONFIG_LED p15
+  #define SHUTDOWN_LED p16
+  #define RESET_BUTTON p18
+#else
+  // *** NRF51-DK or USB Dongle PIN defines ***
+  #define LED_OFF 1
+  #define CONFIG_LED LED3
+#endif
+
+/*
+ * BEACON BEHAVIOR DEFINED BELOW
+ */
+ 
+#define EDDYSTONE_CFG_DEFAULT_DEVICE_NAME "ES G-EID"
+
+#define EDDYSTONE_DEFAULT_MAX_ADV_SLOTS 3
+
+#define EDDYSTONE_DEFAULT_CONFIG_ADV_INTERVAL 1000
+
+#define EDDYSTONE_DEFAULT_CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS 30
+
+#define EDDYSTONE_DEFAULT_UNLOCK_KEY { \
+    0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF \
+}
+
+#define EDDYSTONE_DEFAULT_RADIO_TX_POWER_LEVELS { -30, -16, -4, 4 }
+
+#define EDDYSTONE_DEFAULT_ADV_TX_POWER_LEVELS { -42, -30, -25, -13 }
+
+#define EDDYSTONE_DEFAULT_SLOT_URLS { \
+    "http://cf.physical-web.org", \
+    "http://www.mbed.com/", \
+    "http://www.gap.com/" \
+}
+
+#define EDDYSTONE_DEFAULT_SLOT_UIDS { \
+    { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F }, \
+    { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0 }, \
+    { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF } \
+}
+
+#define EDDYSTONE_DEFAULT_SLOT_EID_IDENTITY_KEYS { \
+    { 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF }, \
+    { 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF }, \
+    { 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF } \
+}
+
+#define EDDYSTONE_DEFAULT_SLOT_EID_ROTATION_PERIOD_EXPS { 4, 10, 10 }
+
+#define EDDYSTONE_DEFAULT_SLOT_TYPES { \
+    EDDYSTONE_FRAME_EID, \
+    EDDYSTONE_FRAME_URL, \
+    EDDYSTONE_FRAME_UID \
+}
+
+#define EDDYSTONE_DEFAULT_SLOT_INTERVALS { 500, 0, 0 }
+
+#define EDDYSTONE_DEFAULT_SLOT_TX_POWERS { 4, 4, 4 }
+
+/**
+ * Lock constants
+ */
+#define LOCKED 0
+#define UNLOCKED 1
+#define UNLOCKED_AUTO_RELOCK_DISABLED 2
+
+#define DEFAULT_LOCK_STATE UNLOCKED
+
+/**
+ * Set default number of adv slots
+ */
+const uint8_t MAX_ADV_SLOTS = EDDYSTONE_DEFAULT_MAX_ADV_SLOTS;
+
+/**
+ * Slot and Power and Interval Constants
+ */
+const uint8_t DEFAULT_SLOT = 0;
+
+/**
+ * Number of radio power modes supported
+ */
+const uint8_t NUM_POWER_MODES = 4;
+
+/**
+ * Default name for the BLE Device Name characteristic.
+ */
+const char DEFAULT_DEVICE_NAME[] = EDDYSTONE_CFG_DEFAULT_DEVICE_NAME;
+
+/**
+ * ES GATT Capability Constants (6 values)
+ */
+const uint8_t CAP_HDR_LEN = 6;  // The six constants below
+
+const uint8_t ES_GATT_VERSION = 0;
+
+const uint8_t MAX_EIDS = MAX_ADV_SLOTS;
+
+
+const uint8_t CAPABILITIES = 0x03; // Per slot variable interval and variable Power
+
+const uint8_t SUPPORTED_FRAMES_H = 0x00;
+
+const uint8_t SUPPORTED_FRAMES_L = 0x0F;
+
+/**
+ * ES GATT Capability Constant Array storing the capability constants
+ */
+const uint8_t CAPABILITIES_DEFAULT[] = {ES_GATT_VERSION, MAX_ADV_SLOTS, MAX_EIDS, CAPABILITIES, \
+                                        SUPPORTED_FRAMES_H, SUPPORTED_FRAMES_L};
+
+#endif /* EDDYSTONE_CONFIG_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EntropySource/EntropySource.cpp	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,33 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "EntropySource.h"
+
+#if !defined(TARGET_NRF51822) && !defined(TARGET_MCU_NRF52832) /* Persistent storage supported on nrf51 platforms */
+    /**
+     * When not using an nRF51-based target then entropy source is currently unimplemented.
+     */
+    #error "INSECURE CONFIGURATION - YOU MUST IMPLEMENT AN ENTROPY SOURCE"
+
+    int eddystoneRegisterEntropySource(	mbedtls_entropy_context* ctx) { 
+      return 1;
+    }
+
+    int eddystoneEntropyPoll( void *data,
+                        unsigned char *output, size_t len, size_t *olen )
+    {
+        return( 1 );
+    }
+#endif /* #ifdef TARGET_NRF51822 */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/EntropySource/EntropySource.h Mon Sep 19 00:59:11 2016 +0000 @@ -0,0 +1,11 @@ +#ifndef __ENTROPY_SOURCE_H__ +#define __ENTROPY_SOURCE_H__ +#include <stddef.h> +#include <mbedtls/entropy.h> + +int eddystoneRegisterEntropySource( mbedtls_entropy_context* ctx); + +int eddystoneEntropyPoll( void *data, + unsigned char *output, size_t len, size_t *olen ); + +#endif // __ENTROPY_SOURCE_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EntropySource/nRFEntropySource/nRFEntropySource.cpp	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,67 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "../EntropySource.h"
+
+#if defined(TARGET_NRF51822) || defined(TARGET_MCU_NRF52832) /* Persistent storage supported on nrf51 platforms */
+
+#include "nrf_soc.h"
+#include "nrf_error.h"
+#include "mbed.h"
+#include <mbedtls/entropy.h>
+
+/*
+ * nRF51 has a TRNG that we can access using SoftDevice.
+ */
+int eddystoneEntropyPoll(void *data, unsigned char *output, size_t len, size_t *olen)
+{
+    uint8_t bytes_available = 0;
+
+    // get the number of random bytes available
+    if (sd_rand_application_bytes_available_get(&bytes_available) != NRF_SUCCESS) {
+        return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
+    }
+
+    // if there is more bytes available that what is requested,
+    // truncate the number of bytes in output to len, otherwise use the total
+    // of bytes available.
+    const uint8_t output_len = bytes_available > len ? len : bytes_available;
+
+    if (output_len) {
+        // transfer "output_len" random bytes to output.
+        if (sd_rand_application_vector_get(output, output_len) != NRF_SUCCESS) {
+            return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
+        }
+    }
+
+    // Everything went fine, commit the output_len to the output parameter
+    *olen = output_len;
+    return 0;
+}
+
+int eddystoneRegisterEntropySource(	mbedtls_entropy_context* ctx) {
+    uint8_t pool_capacity;
+    sd_rand_application_pool_capacity_get(&pool_capacity);
+
+    return mbedtls_entropy_add_source(
+        ctx,
+        eddystoneEntropyPoll, // entropy source function
+        NULL,                 // entropy source data, NULL in this case
+        pool_capacity,        //  minimum number of bytes the entropy pool should wait on from this callback before releasing entropy
+        MBEDTLS_ENTROPY_SOURCE_STRONG
+    );
+}
+
+#endif /* #ifdef TARGET_NRF51822 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EventQueue/AlignedStorage.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef EVENTQUEUE_DETAIL_ALIGNEDSTORAGE_H_
+#define EVENTQUEUE_DETAIL_ALIGNEDSTORAGE_H_
+
+#include <cstddef>
+
+namespace eq {
+
+class AnonymousDeclaration;
+
+/**
+ * Provide aligned raw storage for holding a type T.
+ * This class is useful to delay the construction of objects while reserving
+ * space in memory for them.
+ * For instance, it can be use with static or global variable which can not
+ * be constructed before main. It can also be used in class member which
+ * do not have or can't be constructed at parent construction time.
+ *
+ * Once the storage has been reserved, it is possible explicitly construct the
+ * object of T by using placement new syntax.
+ * @code
+ * AlignedStorage<Foo> foo;
+ * new (foo.get_storage()) Foo(...);
+ * @endcode
+ * Then it is possible to get a reference to the object by calling the member
+ * function get.
+ * @code
+ * foo.get().doSomething();
+ * @endcode
+ * Once the object needs to be destroyed it is possible to call the destructor
+ * directly
+ * @code
+ * foo.get().~Foo();
+ * @endcode
+ * After this point, their is no instance of T in the storage and the function
+ * get remains unusable until an object is again initialised  in the storage.
+ */
+template<typename T>
+class AlignedStorage {
+public:
+	/**
+	 * Initialisation of the storage, does **not** zeroed its memory.
+	 */
+	AlignedStorage() {}
+	/**
+	 * Provide the raw pointer to the address of the storage.
+	 */
+    void* get_storage() {
+    	return data;
+    }
+
+	/**
+	 * Provide the raw pointer to the const address of the storage.
+	 */
+    const void* get_storage() const {
+    	return data;
+    }
+
+    /**
+     * Return a reference to the element T in this storage.
+     */
+    T& get() {
+    	return *static_cast<T*>(get_storage());
+    }
+
+    /**
+     * Return a reference to the const element of T in this storage.
+     */
+    const T& get() const {
+    	return *static_cast<const T*>(get_storage());
+    }
+
+private:
+    // it doesn't make sense to allow copy construction of copy assignement for
+    // this kind of object.
+    AlignedStorage(const AlignedStorage&);
+    AlignedStorage& operator=(const AlignedStorage&);
+    // storage. Can be improved by metaprogramming to be the best fit.
+	union {
+        char char_storage;
+        short int short_int_storage;
+        int int_storage;
+        long int long_int_storage;
+        float float_storage;
+        double double_storage;
+        long double long_double_storage;
+		void* pointer_storage;
+        AnonymousDeclaration (*function_pointer_storage)(AnonymousDeclaration);
+        AnonymousDeclaration* AnonymousDeclaration::*data_member_storage ;
+        AnonymousDeclaration (AnonymousDeclaration::*function_member_storage)(AnonymousDeclaration);
+		char data[sizeof(T)];
+	};
+};
+
+/**
+ * Provide aligned raw storage for holding an array of type T.
+ * This is a specialisation of AlignedStorage for arrays of T.
+ * With this class, it is possible to reserve space for a given number of
+ * elements of type T and delay their construction to a latter point. This
+ * feature can be really useful when building generic container which
+ * embed memory for their elements. Instead of default constructing them,
+ * the construction of an element can be made when it is really needed, by
+ * copy. It is the same for the destruction, only objects which have been
+ * constructed needs to be destructed.
+ * Those properties improve generic containers because only the operations
+ * which have to be made are made. It also allow generic container to hold
+ * types which are not DefaultConstructible.
+ *
+ * Once the storage has been reserved, it is possible explicitly construct an
+ * object of T at a given index by using placement new syntax.
+ * @code
+ * AlignedStorage<Foo[10]> foo;
+ * //construct object at index 0 then at index 1.
+ * new (foo.get_storage(0)) Foo(...);
+ * new (foo.get_storage(1)) Foo(...);
+ * @endcode
+ * Then it is possible to get a reference to an object at a given index by
+ * calling the member function get.
+ * @code
+ * // do something with object at index 1
+ * foo.get(1).doSomething();
+ * @endcode
+ * Once the object needs to be destroyed it is possible to call the destructor
+ * directly
+ * @code
+ * // destroy object at index 1.
+ * foo.get(1).~Foo();
+ * @endcode
+ * After this point, their is no instance of T at index 1 in the storage and
+ * trying to use the object at this index will lead to undefined behavior until
+ * an object is again initialised at this index.
+ */
+template<typename T, std::size_t ArraySize>
+struct AlignedStorage<T[ArraySize]> {
+	/**
+	 * Initialisation of the storage, does **not** zeroed its memory.
+	 */
+	AlignedStorage() {}
+
+	/**
+	 * Return raw pointer to the address of element at a given index
+	 */
+    void* get_storage(std::size_t index) {
+    	return &get(index);
+    }
+
+	/**
+	 * const version of void* get_storage(std::size_t).
+	 */
+    const void* get_storage(std::size_t index) const {
+    	return &get(index);
+    }
+
+	/**
+	 * Return reference to the element stored atindex.
+	 */
+    T& get(std::size_t index) {
+    	return reinterpret_cast<T*>(data)[index];
+    }
+
+	/**
+	 * const version of T& get(std::size_t).
+	 */
+    const T& get(std::size_t index) const {
+    	return reinterpret_cast<const T*>(data)[index];
+    }
+
+private:
+    // it doesn't make sense to allow copy construction of copy assignement for
+    // this kind of object.
+    AlignedStorage(const AlignedStorage&);
+    AlignedStorage& operator=(const AlignedStorage&);
+    // storage. Can be improved by metaprogramming to be the best fit.
+	union {
+        char char_storage;
+        short int short_int_storage;
+        int int_storage;
+        long int long_int_storage;
+        float float_storage;
+        double double_storage;
+        long double long_double_storage;
+		void* pointer_storage;
+        AnonymousDeclaration (*function_pointer_storage)(AnonymousDeclaration);
+        AnonymousDeclaration* AnonymousDeclaration::*data_member_storage ;
+        AnonymousDeclaration (AnonymousDeclaration::*function_member_storage)(AnonymousDeclaration);
+		char data[sizeof(T[ArraySize])];
+	};
+};
+
+} // namespace eq
+
+#endif /* EVENTQUEUE_DETAIL_ALIGNEDSTORAGE_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EventQueue/EventQueue.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef EVENTQUEUE_EVENTQUEUE_H_
+#define EVENTQUEUE_EVENTQUEUE_H_
+
+#include <stdio.h>
+#include "Thunk.h"
+#include "MakeThunk.h"
+
+namespace eq {
+
+class EventQueue {
+
+public:
+	/// typedef for callable type.
+	/// the callable type used should support the same operations
+	/// supported by a void(*)() function pointer.
+	typedef Thunk function_t;
+
+	/// handle to a posted event which will be executed later.
+	/// model after a void* pointer.
+	typedef void* event_handle_t;
+
+	/// type used for time
+	typedef std::size_t ms_time_t;
+
+	/// Construct an empty event queue
+	EventQueue() { }
+
+	virtual ~EventQueue() { }
+
+	/**
+	 * Post a callable to the event queue.
+	 * It will be executed during the next dispatch cycle.
+	 * @param f The callbable to be executed by the event queue.
+	 * @return the handle to the event.
+	 */
+	template<typename F>
+	event_handle_t post(const F& fn) {
+		return do_post(fn);
+	}
+
+	/**
+	 * Bind a callable and an argument then post a callable to the event queue.
+	 * It will be executed during the next dispatch cycle.
+	 * @param f The callbable to be bound with arg0.
+	 * @param arg0 The first argument to bind to f.
+	 * @return the handle to the event.
+	 */
+	template<typename F, typename Arg0>
+	event_handle_t post(const F& fn, const Arg0& arg0) {
+		return do_post(make_thunk(fn, arg0));
+	}
+
+	template<typename F, typename Arg0, typename Arg1>
+	event_handle_t post(const F& fn, const Arg0& arg0, const Arg1& arg1) {
+		return do_post(make_thunk(fn, arg0, arg1));
+	}
+
+	template<typename F, typename Arg0, typename Arg1, typename Arg2>
+	event_handle_t post(const F& fn, const Arg0& arg0, const Arg1& arg1, const Arg2& arg2) {
+		return do_post(make_thunk(fn, arg0, arg1, arg2));
+	}
+
+	template<typename F>
+	event_handle_t post_in(const F& fn, ms_time_t ms_delay) {
+		return do_post(fn, ms_delay);
+	}
+
+	template<typename F, typename Arg0>
+	event_handle_t post_in(const F& fn, const Arg0& arg0, ms_time_t ms_delay) {
+		return do_post(make_thunk(fn, arg0), ms_delay);
+	}
+
+	template<typename F, typename Arg0, typename Arg1>
+	event_handle_t post_in(const F& fn, const Arg0& arg0, const Arg1& arg1, ms_time_t ms_delay) {
+		return do_post(make_thunk(fn, arg0, arg1), ms_delay);
+	}
+
+	template<typename F, typename Arg0, typename Arg1, typename Arg2>
+	event_handle_t post_in(const F& fn, const Arg0& arg0, const Arg1& arg1, const Arg2& arg2, ms_time_t ms_delay) {
+		return do_post(make_thunk(fn, arg0, arg1, arg2), ms_delay);
+	}
+
+	template<typename F>
+	event_handle_t post_every(const F& fn, ms_time_t ms_delay) {
+		return do_post(fn, ms_delay, true);
+	}
+
+	template<typename F, typename Arg0>
+	event_handle_t post_every(const F& fn, const Arg0& arg0, ms_time_t ms_delay) {
+		return do_post(make_thunk(fn, arg0), ms_delay, true);
+	}
+
+	template<typename F, typename Arg0, typename Arg1>
+	event_handle_t post_every(const F& fn, const Arg0& arg0, const Arg1& arg1, ms_time_t ms_delay) {
+		return do_post(make_thunk(fn, arg0, arg1), ms_delay, true);
+	}
+
+	template<typename F, typename Arg0, typename Arg1, typename Arg2>
+	event_handle_t post_every(const F& fn, const Arg0& arg0, const Arg1& arg1, const Arg2& arg2, ms_time_t ms_delay) {
+		return do_post(make_thunk(fn, arg0, arg1, arg2), ms_delay, true);
+	}
+
+	virtual bool cancel(event_handle_t event_handle) = 0;
+
+private:
+	virtual event_handle_t do_post(const function_t& fn, ms_time_t ms_delay = 0, bool repeat = false) = 0;
+};
+
+} // namespace eq
+
+#endif /* EVENTQUEUE_EVENTQUEUE_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EventQueue/EventQueueClassic.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef BLE_API_SOURCE_MBEDCLASSICEVENTQUEUE_H_
+#define BLE_API_SOURCE_MBEDCLASSICEVENTQUEUE_H_
+
+#include <cmsis.h>
+#include "PriorityQueue.h"
+#include "Ticker.h"
+#include "Timer.h"
+#include <stdio.h>
+#include "Thunk.h"
+#include "MakeThunk.h"
+#include "EventQueue.h"
+
+#ifdef TARGET_NORDIC
+#include "util/NordicCriticalSectionLock.h"
+typedef ::util::NordicCriticalSectionLock CriticalSection;
+#else
+#include <util/CriticalSectionLock.h>
+typedef ::mbed::util::CriticalSectionLock CriticalSection;
+#endif
+
+namespace eq {
+
+template<std::size_t EventCount>
+class EventQueueClassic: public EventQueue {
+
+	/// Describe an event.
+	/// An event is composed of a function f to execute after a a time t.
+	/// Optionnaly, the event can be periodic and in this case the function f
+	/// is executed after each period p.
+	struct Event {
+		/// construct an event
+		/// @param f The function to execute when this event occur
+		/// @param ms_remaining_time remaining time before this event occurence
+		/// @param ms_repeat_period If the event is periodic, this parameter is the
+		/// period between to occurence of this event.
+		Event(const function_t& f, ms_time_t ms_remaining_time, ms_time_t ms_repeat_period = 0) :
+			_f(f),
+			_ms_remaining_time(ms_remaining_time),
+			_ms_repeat_period(ms_repeat_period) {
+		}
+
+		/// call the inner function within an event
+		void operator()() {
+			_f();
+		}
+
+		/// return a reference to the inner function
+		const function_t& get_function() const {
+			return _f;
+		}
+
+		/// comparison operator used by the priority queue.
+		/// comaprare remaining time between two events
+		friend bool operator<(const Event& lhs, const Event& rhs) {
+			return lhs._ms_remaining_time < rhs._ms_remaining_time;
+		}
+
+		/// return the time remaining when this event was inserted into the priority queue.
+		ms_time_t get_ms_remaining_time() const {
+			return _ms_remaining_time;
+		}
+
+		/// update the remaining time for this event
+		void set_ms_remaining_time(ms_time_t new_remaining_time) {
+			_ms_remaining_time = new_remaining_time;
+		}
+
+		/// If an event is periodic, return the time between two occurence
+		ms_time_t get_ms_repeat_period() const {
+			return _ms_repeat_period;
+		}
+
+	private:
+		function_t _f;
+		ms_time_t _ms_remaining_time;
+		const ms_time_t _ms_repeat_period;
+	};
+
+	/// type of the internal queue
+	typedef PriorityQueue<Event, EventCount> priority_queue_t;
+
+	/// iterator for the queue type
+	typedef typename priority_queue_t::iterator q_iterator_t;
+
+	/// node type in the queue
+	typedef typename priority_queue_t::Node q_node_t;
+
+public:
+	/// Construct an empty event queue
+	EventQueueClassic() :
+		_events_queue(), _ticker(), _timer(), _timed_event_pending(false) {
+	}
+
+	virtual ~EventQueueClassic() { }
+
+	virtual bool cancel(event_handle_t event_handle) {
+		CriticalSection critical_section;
+		bool success = _events_queue.erase(static_cast<q_node_t*>(event_handle));
+		if (success) {
+			// update the timers and events remaining time
+			updateTime();
+		}
+		return success;
+	}
+
+	void dispatch() {
+		while(true) {
+			function_t f;
+			// pick a task from the queue/ or leave
+			{
+				CriticalSection cs;
+				q_iterator_t event_it = _events_queue.begin();
+				if(event_it != _events_queue.end() && event_it->get_ms_remaining_time() == 0) {
+					f = event_it->get_function();
+					// if the event_it should be repeated, reschedule it
+					if (event_it->get_ms_repeat_period()) {
+						reschedule_event(event_it);
+					} else {
+						_events_queue.pop();
+					}
+				} else {
+					break;
+				}
+			}
+			f();
+		}
+	}
+
+private:
+
+	void update_ticker(ms_time_t ms_delay) {
+		_timed_event_pending = true;
+		_ticker.detach();
+		_ticker.attach(this, &EventQueueClassic::updateTime, ((float) ms_delay / 1000));
+	}
+
+	void update_ticker(q_node_t* ref, ms_time_t ms_delay) {
+		// look if the node inserted is the first node with a delay
+		for (q_iterator_t it = _events_queue.begin(); it != _events_queue.end(); ++it) {
+			if(it->get_ms_remaining_time()) {
+				if (it.get_node() == ref) {
+					// update the ticker to ms_delay if the first event
+					// with a delay is the one inserted
+					update_ticker(ms_delay);
+				}
+				break;
+			}
+		}
+	}
+
+	void update_events_remaining_time(ms_time_t elapsed_time) {
+		bool ticker_updated = false;
+
+		for (q_iterator_t it = _events_queue.begin();
+		     it != _events_queue.end(); ++it) {
+			ms_time_t remaining_time = it->get_ms_remaining_time();
+			if(remaining_time) {
+				if(remaining_time <= elapsed_time) {
+					it->set_ms_remaining_time(0);
+				} else {
+					it->set_ms_remaining_time(remaining_time - elapsed_time);
+					if (!ticker_updated) {
+						update_ticker(it->get_ms_remaining_time());
+						_timer.start();
+						ticker_updated = true;
+					}
+				}
+			}
+		}
+	}
+
+	void updateTime() {
+		CriticalSection critical_section;
+		ms_time_t elapsed_time = _timer.read_ms();
+		_timed_event_pending = false;
+		_timer.stop();
+		_timer.reset();
+		_ticker.detach();
+		update_events_remaining_time(elapsed_time);
+	}
+
+	void reschedule_event(q_iterator_t& event_it) {
+		ms_time_t ms_period = event_it->get_ms_repeat_period();
+
+		if (_timed_event_pending ==  false) {
+			update_ticker(ms_period);
+			_timer.start();
+			event_it->set_ms_remaining_time(ms_period);
+			_events_queue.update(event_it);
+		} else {
+			int elapsed_time = _timer.read_ms();
+			event_it->set_ms_remaining_time(elapsed_time + ms_period);
+			_events_queue.update(event_it);
+			update_ticker(event_it.get_node(), ms_period);
+		}
+	}
+
+	virtual event_handle_t do_post(const function_t& fn, ms_time_t ms_delay = 0, bool repeat = false) {
+		if(repeat && (ms_delay == 0)) {
+			return NULL;
+		}
+
+		Event event(fn, ms_delay, repeat ? ms_delay : 0);
+
+		CriticalSection critical_section;
+		if (_events_queue.full()) {
+			return NULL;
+		}
+
+		// there is no need to update timings if ms_delay == 0
+		if (!ms_delay) {
+			return _events_queue.push(event).get_node();
+		}
+
+		// if there is no pending timed event, just add this one and start timers
+		if (_timed_event_pending ==  false) {
+			update_ticker(ms_delay);
+			_timer.start();
+			return _events_queue.push(event).get_node();
+		}
+
+		int elapsed_time = _timer.read_ms();
+
+		// update remaining time and post the event
+		event.set_ms_remaining_time(ms_delay + elapsed_time);
+		event_handle_t handle = _events_queue.push(event).get_node();
+		update_ticker(static_cast<q_node_t*>(handle), ms_delay);
+
+		return handle;
+	}
+
+	priority_queue_t _events_queue;
+	mbed::Ticker _ticker;
+	mbed::Timer _timer;
+	bool _timed_event_pending;
+};
+
+} // namespace eq
+
+#endif /* BLE_API_SOURCE_MBEDCLASSICEVENTQUEUE_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EventQueue/EventQueueMinar.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef EVENTQUEUE_EVENTQUEUEMINAR_H_
+#define EVENTQUEUE_EVENTQUEUEMINAR_H_
+
+#include <minar/minar.h>
+#include "EventQueue.h"
+
+namespace eq {
+
+class EventQueueMinar: public EventQueue {
+
+public:
+	/// Construct an empty event queue
+	EventQueueMinar()  { }
+
+	virtual ~EventQueueMinar() { }
+
+	virtual bool cancel(event_handle_t event_handle) {
+        return minar::Scheduler::cancelCallback(event_handle);
+	}
+
+private:
+
+	virtual event_handle_t do_post(const function_t& fn, ms_time_t ms_delay = 0, bool repeat = false) {
+        // convert ms to minar time
+        minar::tick_t tick = minar::milliseconds(ms_delay);
+
+        // convert thunk to minar FunctionPointerBind
+        mbed::util::Event func(
+            mbed::util::FunctionPointer1<void, function_t>(
+                free_func_thunk_call
+            ).bind(fn)
+        );
+
+        if (ms_delay == 0) {
+            return minar::Scheduler::postCallback(func).getHandle();
+        }
+
+        if (repeat == false) {
+            return minar::Scheduler::postCallback(func).delay(tick).tolerance(0).getHandle();
+        } else {
+            return minar::Scheduler::postCallback(func).period(tick).tolerance(0).getHandle();
+        }
+	}
+
+	// due to design limitations in function pointer classes, it is not possible
+	// to use reference here ... 
+    static void free_func_thunk_call(function_t fn) {
+        fn();
+    }
+};
+
+} // namespace eq
+
+#endif /* EVENTQUEUE_EVENTQUEUEMINAR_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EventQueue/MakeThunk.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef EVENTQUEUE_MAKETHUNK_H
+#define EVENTQUEUE_MAKETHUNK_H
+
+#include "detail/MemberFunctionAdaptor.h"
+#include "detail/FunctionAdaptor.h"
+#include "detail/Thunks.h"
+
+namespace eq {
+
+/**
+ * Make a thunk from an F.
+ * When this function only takes an F then F it is expected that F is already
+ * a callable and therefore a kind of thunk.
+ * @tparam F The type of callable in input.
+ * @param fn the function to turn into a thunk.
+ * @return fn
+ */
+template<typename F>
+const F& make_thunk(const F& fn) {
+	return fn;
+}
+
+/**
+ * Bind fn and arg0 into a thunk.
+ * @tparam F the type of the function to bind. It can be a function pointer,
+ * a function like object or a pointer to a member function.
+ * @tparam Arg0 The type of the first argument of F.
+ * @param fn the function to bind.
+ * @param arg0 the first argument to bind.
+ * @return a thunk binding F and arg0.
+ */
+template<typename F, typename Arg0>
+detail::Thunk_1<typename detail::FunctionAdaptor<F>::type, Arg0>
+make_thunk(const F& fn, const Arg0& arg0) {
+	typedef typename detail::FunctionAdaptor<F>::type fn_adaptor_t;
+	return detail::Thunk_1<fn_adaptor_t, Arg0>(
+		fn_adaptor_t(fn),
+		arg0
+	);
+}
+
+/**
+ * Bind fn, arg0 and arg1 into a thunk.
+ * @tparam F the type of the function to bind. It can be a function pointer,
+ * a function like object or a pointer to a member function.
+ * @tparam Arg0 The type of the first argument of F.
+ * @tparam Arg1 The type of the second argument of F.
+ * @param fn the function to bind.
+ * @param arg0 the first argument to bind.
+ * @param arg1 the second argument to bind.
+ * @return a thunk binding F, arg0 and arg1.
+ */
+template<typename F, typename Arg0, typename Arg1>
+detail::Thunk_2<typename detail::FunctionAdaptor<F>::type, Arg0, Arg1>
+make_thunk(const F& fn, const Arg0& arg0, const Arg1& arg1) {
+	typedef typename detail::FunctionAdaptor<F>::type fn_adaptor_t;
+	return detail::Thunk_2<fn_adaptor_t, Arg0, Arg1>(
+		fn_adaptor_t(fn),
+		arg0,
+		arg1
+	);
+}
+
+/**
+ * Bind fn, arg0, arg1 and arg2 into a thunk.
+ * @tparam F the type of the function to bind. It can be a function pointer,
+ * a function like object or a pointer to a member function.
+ * @tparam Arg0 The type of the first argument of F.
+ * @tparam Arg1 The type of the second argument of F.
+ * @tparam Arg2 The type of the third argument of F.
+ * @param fn the function to bind.
+ * @param arg0 the first argument to bind.
+ * @param arg1 the second argument to bind.
+ * @param arg1 the third argument to bind.
+ * @return a thunk binding F, arg0, arg1 and arg2.
+ */
+template<typename F, typename Arg0, typename Arg1, typename Arg2>
+detail::Thunk_3<typename detail::FunctionAdaptor<F>::type, Arg0, Arg1, Arg2>
+make_thunk(const F& fn, const Arg0& arg0, const Arg1& arg1, const Arg2& arg2) {
+	typedef typename detail::FunctionAdaptor<F>::type fn_adaptor_t;
+	return detail::Thunk_3<fn_adaptor_t, Arg0, Arg1, Arg2>(
+		fn_adaptor_t(fn),
+		arg0,
+		arg1,
+		arg2
+	);
+}
+
+} // namespace eq
+
+#endif /* EVENTQUEUE_MAKETHUNK_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EventQueue/PriorityQueue.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef EVENTQUEUE_STACKPRIORITYQUEUE_H_
+#define EVENTQUEUE_STACKPRIORITYQUEUE_H_
+
+#include <cstddef>
+#include "AlignedStorage.h"
+
+namespace eq {
+
+/**
+ * Priority queue of Ts.
+ * Ts are ordered from the smaller to the bigger ( < ).
+ * Elements in the queue are mutable (this is a design choice).
+ * After a mutation the function update should be called to ensure that the
+ * queue is still properly sorted.
+ * @tparam T type of elements in this queue
+ * @param capacity Number of elements that this queue can contain
+ */
+template<typename T, std::size_t Capacity>
+class PriorityQueue {
+
+public:
+	/**
+	 * Type of the nodes in this queue.
+	 */
+	struct Node {
+		AlignedStorage<T> storage;		/// storage for the T
+		Node* next;						/// pointer to the next node
+	};
+
+	/**
+	 * Iterator for elements of the queue.
+	 */
+	class Iterator {
+		friend PriorityQueue;
+
+		/// Construct an iterator from a Node.
+		/// This constructor is private and can only be invoked from the PriorityQueue.
+		Iterator(Node* current) :
+			_current(current) {
+		}
+
+	public:
+
+		/// Indirection operator.
+		/// return a reference to the inner T
+		T& operator*() {
+			return _current->storage.get();
+		}
+
+		/// Const version of indirection operator.
+		/// return a reference to the inner T
+		const T& operator*() const {
+			return _current->storage.get();
+		}
+
+		/// dereference operator.
+		/// Will invoke the operation on the inner T
+		T* operator->() {
+			return &(_current->storage.get());
+		}
+
+		/// const dereference operator.
+		/// Will invoke the operation on the inner T
+		const T* operator->() const {
+			return &(_current->storage.get());
+		}
+
+		/// pre incrementation to the next T in the list
+		Iterator& operator++() {
+			_current = _current->next;
+			return *this;
+		}
+
+		/// post incrementation to the next T in the list
+		Iterator operator++(int) {
+			Iterator tmp(*this);
+			_current = _current->next;
+			return tmp;
+		}
+
+		/// Equality operator
+		friend bool operator==(const Iterator& lhs, const Iterator& rhs) {
+			return lhs._current == rhs._current;
+		}
+
+		/// Unequality operator
+		friend bool operator!=(const Iterator& lhs, const Iterator& rhs) {
+			return !(lhs == rhs);
+		}
+
+		/// return the internal node.
+		Node* get_node() {
+			return _current;
+		}
+
+	private:
+		Node* _current;
+	};
+
+	typedef Iterator iterator;
+
+	/// Construct an empty priority queue.
+	PriorityQueue() : nodes(), free_nodes(NULL), head(NULL), used_nodes_count(0) {
+		initialize();
+	}
+
+	/// Copy construct a priority queue.
+	/// The queue will have the same content has other.
+	PriorityQueue(const PriorityQueue& other) :
+		nodes(), free_nodes(NULL), head(NULL), used_nodes_count(0) {
+		initialize();
+		copy(other);
+	}
+
+	/// destroy a priority queue.
+	~PriorityQueue() {
+		clear();
+	}
+
+	/// Copy assignemnent from another priority queue.
+	/// The content of the queue will be destroyed then the content from
+	/// other will be copied.
+	PriorityQueue& operator=(const PriorityQueue& other) {
+		if (&other == this) {
+			return *this;
+		}
+		copy(other);
+		return *this;
+	}
+
+	/// Push a new element to the queue.
+	/// It will be added before the first element p in the queue where
+	/// element < p == true.
+	/// @return An iterator to the inserted element.
+	iterator push(const T& element) {
+		if (full()) {
+			return NULL;
+		}
+
+		// get a free node
+		Node* new_node = free_nodes;
+		free_nodes = free_nodes->next;
+		new_node->next = NULL;
+
+		++used_nodes_count;
+
+		// copy content
+		new (new_node->storage.get_storage()) T(element);
+
+		// if there is no node in the queue, just link the head
+		// to the new node and return
+		if (head == NULL) {
+			head = new_node;
+			return new_node;
+		}
+
+		// if the new node has an higher priority than the node in head
+		// just link it as the head
+		if (element < head->storage.get()) {
+			new_node->next = head;
+			head = new_node;
+			return new_node;
+		}
+
+		// insert the node after head
+		insert_after(head, new_node);
+
+		return new_node;
+	}
+
+	/// pop the head of the queue.
+	bool pop() {
+		if (!head) {
+			return false;
+		}
+
+		Node* target = head;
+		target->storage.get().~T();
+		head = target->next;
+		target->next = free_nodes;
+		free_nodes = target;
+		--used_nodes_count;
+		return true;
+	}
+
+	/// If the content of an element is updated is updated after the insertion
+	/// then, the list can be in an unordered state.
+	/// This function help; it update the position of an iterator in the list.
+	void update(iterator it) {
+		Node* target = it.get_node();
+		Node* hint = head;
+
+		if (target == NULL) {
+			return;
+		}
+
+		// remove the node from the list
+		if (target == head) {
+			// if it is the only node in the list, just return
+			// it is not needed to update its position
+			if (target->next == NULL) {
+				return;
+			}
+
+			// if the order is already correct, just return
+			if (target->storage.get() < target->next->storage.get()) {
+				return;
+			}
+
+			// otherwise remove the node from the list
+			// and update the hint
+			head = target->next;
+			hint = head;
+		} else {
+			bool node_found = false;
+			for (Node* current = head; current != NULL; current = current->next) {
+				if (current->next == target) {
+					// check if it is needed to move the node
+					if (current->storage.get() < target->storage.get()) {
+						if (target->next == NULL) {
+							return;
+						}
+
+						if (target->storage.get() < target->next->storage.get()) {
+							return;
+						}
+
+						// there is no need to iterate again the whole list
+						// just mark the hint has the current node
+						hint = current;
+					}
+
+					// remove the node from the list and break out of the loop
+					current->next = target->next;
+					node_found = true;
+					break;
+				}
+			}
+
+			// the node in parameter doesn't belong to this queue
+			if (!node_found) {
+				return;
+			}
+		}
+
+		// insert the node after hint
+		insert_after(hint, target);
+	}
+
+	/// return an iterator to the begining of the queue.
+	iterator begin() {
+		return head;
+	}
+
+	/// return an iterator to the end of the queue.
+	/// @note can't be dereferenced
+	iterator end() {
+		return NULL;
+	}
+
+	/// erase an iterator from the list
+	bool erase(iterator it) {
+		return erase(it.get_node());
+	}
+
+	/// erase a node from the list
+	bool erase(Node* n) {
+		if (n == NULL) {
+			return false;
+		}
+
+		if (head == n) {
+			return pop();
+		}
+
+		Node* current = head;
+		while (current->next) {
+			if (current->next == n) {
+				current->next = n->next;
+				n->storage.get().~T();
+				n->next = free_nodes;
+				free_nodes = n;
+				--used_nodes_count;
+				return true;
+			}
+			current = current->next;
+		}
+		return false;
+	}
+
+	/**
+	 * Indicate if the queue is empty or not.
+	 * @return true if the queue is empty and false otherwise.
+	 * @invariant the queue remains untouched.
+	 */
+	bool empty() const {
+		return head == NULL;
+	}
+
+	/**
+	 * Indicate if the true is full or not.
+	 * @return true if the queue is full and false otherwise.
+	 * @invariant the queue remains untouched.
+	 */
+	bool full() const {
+		return free_nodes == NULL;
+	}
+
+	/**
+	 * Indicate the number of elements in the queue.
+	 * @return the number of elements currently held by the queue.
+	 * @invariant the queue remains untouched.
+	 */
+	std::size_t size() const {
+		return used_nodes_count;
+	}
+
+	/**
+	 * Expose the capacity of the queue in terms of number of elements the
+	 * queue can hold.
+	 * @return the capacity of the queue.
+	 * @invariant this function should always return Capacity.
+	 */
+	std::size_t capacity() const {
+		return Capacity;
+	}
+
+	/**
+	 * Clear the queue from all its elements.
+	 */
+	void clear() {
+		while (head) {
+			head->storage.get().~T();
+			Node* tmp = head;
+			head = head->next;
+			tmp->next = free_nodes;
+			free_nodes = tmp;
+		}
+		used_nodes_count = 0;
+	}
+
+private:
+	void initialize() {
+		/// link all the nodes together
+		for (std::size_t i = 0; i < (Capacity - 1); ++i) {
+			nodes[i].next = &nodes[i + 1];
+		}
+		/// the last node does not have a next node
+		nodes[Capacity - 1].next = NULL;
+		/// set all the nodes as free
+		free_nodes = nodes;
+	}
+
+	void copy(const PriorityQueue& other) {
+		if (empty() == false) {
+			clear();
+		}
+
+		Node *to_copy = other.head;
+		Node *previous = NULL;
+		while (to_copy) {
+			// pick a free node
+			Node* new_node = free_nodes;
+			free_nodes = free_nodes->next;
+			new_node->next = NULL;
+
+			// copy content
+			new (new_node->storage.get_storage()) T(to_copy->storage.get());
+
+			// link into the queue or update head then update previous pointer
+			if (previous) {
+				previous->next = new_node;
+			} else {
+				head = new_node;
+			}
+			previous = new_node;
+
+			// update the node to copy
+			to_copy = to_copy->next;
+		}
+		used_nodes_count = other.used_nodes_count;
+	}
+
+	void insert_after(Node* prev, Node* to_insert) {
+		for (; prev != NULL; prev = prev->next) {
+			if (prev->next == NULL || to_insert->storage.get() < prev->next->storage.get()) {
+				to_insert->next = prev->next;
+				prev->next = to_insert;
+				break;
+			}
+		}
+	}
+
+	Node nodes[Capacity];         //< Nodes of the queue
+	Node *free_nodes;             //< entry point for the list of free nodes
+	Node *head;                   //< head of the queue
+	std::size_t used_nodes_count; // number of nodes used
+};
+
+} // namespace eq
+
+#endif /* EVENTQUEUE_STACKPRIORITYQUEUE_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EventQueue/Thunk.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef EVENTQUEUE_THUNK_H_
+#define EVENTQUEUE_THUNK_H_
+
+#include "AlignedStorage.h"
+#include "detail/ThunkVTable.h"
+
+namespace eq {
+
+// forward declaration of ThunkVTableGenerator
+namespace detail {
+template<typename T>
+class ThunkVTableGenerator;
+}
+
+/**
+ * A Thunk is a container holding any kind of nullary callable.
+ * It wrap value semantic and function call operations of the inner callable
+ * held.
+ * \note Thunk of callable bound to arguments should be generated by the
+ * function make_thunk.
+ */
+class Thunk {
+	// Size for the internal buffer of the Thunk
+	static const std::size_t BufferSize = 24;
+
+	template<typename T>
+	friend class detail::ThunkVTableGenerator;
+
+public:
+
+	/**
+	 * Thunk Empty constructor.
+	 * When this thunk is called, if does nothing.
+	 */
+	Thunk();
+
+	/**
+	 * Construct a Thunk from a nullary callable of type F.
+	 * When the call operator is invoked, it call a copy of f ( f() ).
+	 */
+	template<typename F>
+	Thunk(const F& f);
+
+	/**
+	 * Special constructor for pointer to function.
+	 * Allow references to functions to gracefully decay into pointer to function.
+	 * Otherwise, reference to function are not copy constructible (their is no
+	 * constructible function type in C++).
+	 * When the call operator is invoked, it call a copy of f ( f() ).
+	 */
+	Thunk(void (*f)());
+
+	/**
+	 * Copy construction of a thunk.
+	 * Take care that the inner F is correctly copied.
+	 */
+	Thunk(const Thunk& other) : _storage(), _vtable() {
+		other._vtable->copy(*this, other);
+	}
+
+	/**
+	 * Destruction of the Thunk correctly call the destructor of the
+	 * inner callable.
+	 */
+	~Thunk() {
+		_vtable->destroy(*this);
+	}
+
+	/**
+	 * Copy assignement from another thunk.
+	 * Ensure that the callable held is correctly destroyed then copy
+	 * the correctly copy the new one.
+	 */
+	Thunk& operator=(const Thunk& other) {
+		if (this == &other) {
+			return *this;
+		}
+		_vtable->destroy(*this);
+		other._vtable->copy(*this, other);
+		return *this;
+	}
+
+	/**
+	 * Call operator. Invoke the inner callable.
+	 */
+	void operator()() const {
+		_vtable->call(*this);
+	}
+
+private:
+	static void empty_thunk() { }
+
+	AlignedStorage<char[BufferSize]> _storage;
+	const detail::ThunkVTable* _vtable;
+};
+
+} // namespace eq
+
+#include "detail/Thunk.impl.h"
+
+#endif  /* EVENTQUEUE_THUNK_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EventQueue/detail/FunctionAdaptor.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef EVENTQUEUE_DETAIL_FUNCTIONADAPTOR_H_
+#define EVENTQUEUE_DETAIL_FUNCTIONADAPTOR_H_
+
+#include "MemberFunctionAdaptor.h"
+
+namespace eq {
+namespace detail {
+
+/**
+ * In C++, several types can be used as function:
+ *   - function pointer
+ *   - member functions
+ *   - function like object
+ * While function pointer and function like object can be used with the function
+ * call syntax, the function call syntax can't be applied for function pointers.
+ * This meta function yield takes a callable type F in input and as a result
+ * return a type which can be constructed from F and used with the function call
+ * syntax.
+ *
+ * \code
+ * class Foo;
+ *
+ * Foo foo;
+ * typedef void (Foo::*foo_function_t)();
+ * foo_function_t foo_function = &Foo::some_function;
+ *
+ * //The following will fail:
+ * //foo_function(foo)
+ *
+ * typedef FunctionAdaptor<foo_function_t>::type foo_function_adaptor_t;
+ * foo_function_adaptor_t foo_function_adapted(foo_function);
+ * foo_function_adapted(foo);
+ *
+ * \endcode
+ *
+ * \tparam F The type of the object to adapt.
+ */
+template<typename F>
+struct FunctionAdaptor {
+	/**
+	 * Common case (function pointer and function like object).
+	 * Yield itself, no addaptation needed.
+	 */
+	typedef F type;
+};
+
+/**
+ * Partial specializetion for member function with no arguments
+ */
+template<typename T>
+struct FunctionAdaptor<void(T::*)()> {
+	/**
+	 * Yield a member function adaptor.
+	 */
+	typedef MemberFunctionAdaptor0<T> type;
+};
+
+/**
+ * Partial specializetion for member function with one argument
+ */
+template<typename T, typename Arg0>
+struct FunctionAdaptor<void(T::*)(Arg0)> {
+	/**
+	 * Yield a member function adaptor.
+	 */
+	typedef MemberFunctionAdaptor1<T, Arg0> type;
+};
+
+/**
+ * Partial specializetion for member function with two arguments
+ */
+template<typename T, typename Arg0, typename Arg1>
+struct FunctionAdaptor<void(T::*)(Arg0, Arg1)> {
+	/**
+	 * Yield a member function adaptor.
+	 */
+	typedef MemberFunctionAdaptor2<T, Arg0, Arg1> type;
+};
+
+} // namespace detail
+} // namespace eq
+
+#endif /* EVENTQUEUE_DETAIL_FUNCTIONADAPTOR_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EventQueue/detail/MemberFunctionAdaptor.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef EVENTQUEUE_DETAIL_MEMBERFUNCTIONADAPTOR_H_
+#define EVENTQUEUE_DETAIL_MEMBERFUNCTIONADAPTOR_H_
+
+namespace eq {
+namespace detail {
+
+/**
+ * Adaptor for member function without argument.
+ * It wrap member function into a function like object to make it usable like
+ * a regular function.
+ * \tparam T the type the class/struct holding the member function.
+ * \code
+ * struct Foo {
+ * 	void fn();
+ * };
+ *
+ * Foo foo;
+ * MemberFunctionAdaptor0<Foo> fn_adapted(&Foo::fn);
+ *
+ *  fn_adapted(foo); // work
+ *  fn_adapted(&foo); // work
+ * \endcode
+ */
+template<typename T>
+struct MemberFunctionAdaptor0 {
+	/**
+	 * Construct a member function adaptor.
+	 * \param fn The member function to addapt.
+	 */
+	MemberFunctionAdaptor0(void (T::*fn)()) :
+		_fn(fn) {
+	}
+
+	/**
+	 * Call operator for pointer of T
+	 */
+	void operator()(T* self) const {
+		(self->*_fn)();
+	}
+
+	/**
+	 * Call operator for reference of T
+	 */
+	void operator()(T& self) const {
+		(self.*_fn)();
+	}
+
+private:
+	void (T::* const _fn)();
+};
+
+
+/**
+ * Adaptor for member function with one argument.
+ * It wrap member function into a function like object to make it usable like
+ * a regular function.
+ * \tparam T the type the class/struct holding the member function.
+ * \code
+ * struct Foo {
+ * 	void fn(int);
+ * };
+ *
+ * Foo foo;
+ * MemberFunctionAdaptor1<Foo> fn_adapted(&Foo::fn);
+ *
+ *  fn_adapted(foo, 42); // work
+ *  fn_adapted(&foo, 42); // work
+ * \endcode
+ */
+template<typename T, typename Arg0>
+struct MemberFunctionAdaptor1 {
+	/**
+	 * Construct a member function adaptor.
+	 * \param fn The member function to addapt.
+	 */
+	MemberFunctionAdaptor1(void (T::*fn)(Arg0)) :
+		_fn(fn) {
+	}
+
+	/**
+	 * Call operator for pointer of T
+	 */
+	void operator()(T* self, Arg0 arg0) const {
+		(self->*_fn)(arg0);
+	}
+
+	/**
+	 * Call operator for reference of T
+	 */
+	void operator()(T& self, Arg0 arg0) const {
+		(self.*_fn)(arg0);
+	}
+
+private:
+	void (T::* const _fn)(Arg0);
+};
+
+
+/**
+ * Adaptor for member function with two arguments.
+ * It wrap member function into a function like object to make it usable like
+ * a regular function.
+ * \tparam T the type the class/struct holding the member function.
+ * \code
+ * struct Foo {
+ * 	void fn(int, const char*);
+ * };
+ *
+ * Foo foo;
+ * MemberFunctionAdaptor2<Foo> fn_adapted(&Foo::fn);
+ *
+ *  fn_adapted(foo, 42, "toto"); // work
+ *  fn_adapted(&foo, 42, "toto"); // work
+ * \endcode
+ */
+template<typename T, typename Arg0, typename Arg1>
+struct MemberFunctionAdaptor2 {
+	/**
+	 * Construct a member function adaptor.
+	 * \param fn The member function to addapt.
+	 */
+	MemberFunctionAdaptor2(void (T::*fn)(Arg0, Arg1)) : _fn(fn) { }
+
+	/**
+	 * Call operator for pointer of T
+	 */
+	void operator()(T* self, Arg0 arg0, Arg1 arg1) const {
+		(self->*_fn)(arg0, arg1);
+	}
+
+	/**
+	 * Call operator for reference of T
+	 */
+	void operator()(T& self, Arg0 arg0, Arg1 arg1) const {
+		(self.*_fn)(arg0, arg1);
+	}
+
+private:
+	void (T::* const _fn)(Arg0, Arg1);
+};
+
+} // namespace detail
+} // namespace eq
+
+#endif /* EVENTQUEUE_DETAIL_MEMBERFUNCTIONADAPTOR_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EventQueue/detail/Thunk.impl.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef EVENTQUEUE_DETAIL_THUNK_IMPL_H_
+#define EVENTQUEUE_DETAIL_THUNK_IMPL_H_
+
+#include <new>
+#include "ThunkVTableGenerator.h"
+
+namespace eq {
+
+/**
+ * Thunk constructor Implementation.
+ * Due to the way templates and forwarding work in C++, it was not possible to
+ * provide this implementation in Thunk.h
+ */
+template<typename F>
+Thunk::Thunk(const F& f) :
+	_storage(),
+	_vtable(&detail::ThunkVTableGenerator<F>::vtable) {
+	typedef  __attribute__((unused)) char F_is_too_big_for_the_Thunk[sizeof(F) <= sizeof(_storage) ? 1 : -1];
+	new(_storage.get_storage(0)) F(f);
+}
+
+/**
+ * Specialization for function pointers.
+ * This overload will be chosen when the tyope in input is a reference to a function.
+ * @param  f The function to transform in Thunk.
+ */
+inline Thunk::Thunk(void (*f)()) :
+	_storage(),
+	_vtable(&detail::ThunkVTableGenerator<void(*)()>::vtable) {
+	typedef void(*F)();
+	typedef  __attribute__((unused)) char F_is_too_big_for_the_Thunk[sizeof(F) <= sizeof(_storage) ? 1 : -1];
+	new(_storage.get_storage(0)) F(f);
+}
+
+/**
+ * Thunk empty constructor Implementation.
+ * Due to the way templates and forwarding work in C++, it was not possible to
+ * provide this implementation in Thunk.h
+ */
+inline Thunk::Thunk() :
+	_storage(),
+	_vtable(&detail::ThunkVTableGenerator<void(*)()>::vtable) {
+	typedef void(*F)();
+	typedef  __attribute__((unused)) char F_is_too_big_for_the_Thunk[sizeof(F) <= sizeof(_storage) ? 1 : -1];
+	new(_storage.get_storage(0)) F(empty_thunk);
+}
+
+} // namespace eq
+
+#endif /* EVENTQUEUE_DETAIL_THUNK_IMPL_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EventQueue/detail/ThunkVTable.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef EVENTQUEUE_DETAIL_THUNKVTABLE_H_
+#define EVENTQUEUE_DETAIL_THUNKVTABLE_H_
+
+namespace eq {
+
+// forward declaration of the Thunk class
+class Thunk;
+
+namespace detail {
+
+/**
+ * This POD is used as a vtable by Thunk implementation.
+ * Thunk is a value type for all type nullary callable and therefore standard
+ * polymorphism is not suitable for that use case.
+ * Instead, the vtable is generated for each type contained in a thunk.
+ * This structure is the prototype of such vtable.
+ * \note see ThunkVTableGenerator for implementation and the generation of
+ * Thunk vtables.
+ */
+struct ThunkVTable {
+	typedef Thunk thunk_t;
+
+	/**
+	 * destroy a thunk (act like a destructor).
+	 */
+	void (* const destroy)(thunk_t& self);
+
+	/**
+	 * Copy self into dest.
+	 * It is expected that dest is empty.
+	 */
+	void (* const copy)(thunk_t& dest, const thunk_t& self);
+
+	/**
+	 * Synthetized call for the inner object of the thunk_t.
+	 */
+	void (* const call)(const thunk_t& self);
+};
+
+} // namespace detail
+} // namespace eq
+
+#endif /* EVENTQUEUE_DETAIL_THUNKVTABLE_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EventQueue/detail/ThunkVTableGenerator.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef EVENTQUEUE_DETAIL_THUNKVTABLEGENERATOR_H_
+#define EVENTQUEUE_DETAIL_THUNKVTABLEGENERATOR_H_
+
+// imported from Thunk.h
+
+namespace eq {
+namespace detail {
+
+/**
+ * Thunk VTable Generator.
+ * This class generate the vtable of a type F for a Thunk.
+ * \tparam F The type of the callable for which the Thunk vtable should be
+ * generated.
+ */
+template<typename F>
+struct ThunkVTableGenerator {
+	typedef Thunk thunk_t;
+
+	/**
+	 * Implementation of destructor for Thunk holding an F.
+	 * @param self The thunk to destroy
+	 */
+	static void destroy(thunk_t& self) {
+		get_ptr(self)->~F();
+	}
+
+	/**
+	 * Implementation of copy (used by copy constructor and copy assignment)
+	 * for a Thunk holding an F.
+	 * @param dest The thunk receiving the copy.
+	 * @param self The thunk to copy.
+	 */
+	static void copy(thunk_t& dest, const thunk_t& self) {
+		new (get_ptr(dest)) F(*get_ptr(self));
+		dest._vtable = self._vtable;
+	}
+
+	/**
+	 * Implementation of call operator for a Thunk holding an F.
+	 * @param self The thunk containing the F to call.
+	 */
+	static void call(const thunk_t& self) {
+		(*get_ptr(self))();
+	}
+
+	/**
+	 * The Thunk vtable for an F.
+	 */
+	static const ThunkVTable vtable;
+
+private:
+	/**
+	 * Accessor to the pointer to F contained in the Thunk.
+	 */
+	static F* get_ptr(thunk_t& thunk) {
+		return static_cast<F*>(thunk._storage.get_storage(0));
+	}
+
+	/**
+	 * Accessor to the const pointer to F contained in the const Thunk.
+	 */
+	static const F* get_ptr(const thunk_t& thunk) {
+		return static_cast<const F*>(thunk._storage.get_storage(0));
+	}
+};
+
+/**
+ * Instantiation of the Thunk vtable of F.
+ */
+template<typename F>
+const ThunkVTable ThunkVTableGenerator<F>::vtable = {
+		ThunkVTableGenerator<F>::destroy,
+		ThunkVTableGenerator<F>::copy,
+		ThunkVTableGenerator<F>::call
+};
+
+} // namespace detail
+} // namespace eq
+
+#endif /* EVENTQUEUE_DETAIL_THUNKVTABLEGENERATOR_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EventQueue/detail/Thunks.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2016, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef EVENTQUEUE_DETAIL_THUNKS_H_
+#define EVENTQUEUE_DETAIL_THUNKS_H_
+
+namespace eq {
+namespace detail {
+
+/**
+ * Generate a Thunk for a callable of type F with one argument.
+ * This class is a function like object containing the function to call and
+ * its argument. When it is invoked, F is invoked with the argument passed
+ * at construction time.
+ * \tparam F the type of the callable.
+ * \tparam Arg0 type of the first parameter of F to pass to F.
+ */
+template<typename F, typename Arg0>
+struct Thunk_1 {
+	/**
+	 * Construct the Thunk and bind its arguments.
+	 * \param fn the callable, it will be invoked with arg0.
+	 * \param arg0 The first argument to pass to fn when this object is called.
+	 * \note member function should be adapted by using FunctionAdaptor
+	 */
+	Thunk_1(const F& fn, const Arg0& arg0) :
+		_fn(fn), _arg0(arg0) {
+	}
+
+	/**
+	 * Apply arg0 to fn.
+	 */
+	void operator()() const {
+		_fn(_arg0);
+	}
+
+private:
+	mutable F _fn;
+	mutable Arg0 _arg0;
+};
+
+/**
+ * Generate a Thunk for a callable of type F with two arguments.
+ * This class is a function like object containing the function to call and
+ * its arguments. When it is invoked, F is invoked with the arguments passed
+ * at construction time.
+ * \tparam F the type of the callable.
+ * \tparam Arg0 type of the first parameter to pass to F.
+ * \tparam Arg1 type of the second parameter to pass to F.
+ */
+template<typename F, typename Arg0, typename Arg1>
+struct Thunk_2 {
+	/**
+	 * Construct the Thunk and bind its arguments.
+	 * \param fn the callable, it will be invoked with arg0 and arg1.
+	 * \param arg0 The first argument to pass to fn when this object is called.
+	 * \param arg1 The second argument to pass to fn when this object is called.
+	 * \note member function should be adapted by using FunctionAdaptor
+	 */
+	Thunk_2(const F& fn, const Arg0& arg0, const Arg1& arg1) :
+		_fn(fn),
+		_arg0(arg0),
+		_arg1(arg1) {
+	}
+
+	/**
+	 * Apply arg0 and arg1 to fn.
+	 */
+	void operator()() const {
+		_fn(_arg0, _arg1);
+	}
+
+private:
+	mutable F _fn;
+	mutable Arg0 _arg0;
+	mutable Arg1 _arg1;
+};
+
+/**
+ * Generate a Thunk for a callable of type F with three arguments.
+ * This class is a function like object containing the function to call and
+ * its arguments. When it is invoked, F is invoked with the arguments passed
+ * at construction time.
+ * \tparam F the type of the callable.
+ * \tparam Arg0 type of the first parameter to pass to F.
+ * \tparam Arg1 type of the second parameter to pass to F.
+ * \tparam Arg2 type of the third parameter to pass to F.
+ */
+template<typename F, typename Arg0, typename Arg1, typename Arg2>
+struct Thunk_3 {
+	/**
+	 * Construct the Thunk and bind its arguments.
+	 * \param fn the callable, it will be invoked with arg0, arg1 and arg2.
+	 * \param arg0 The first argument to pass to fn when this object is called.
+	 * \param arg1 The second argument to pass to fn when this object is called.
+	 * \param arg2 The third argument to pass to fn when this object is called.
+	 * \note member function should be adapted by using FunctionAdaptor
+	 */
+	Thunk_3(const F& fn, const Arg0& arg0, const Arg1& arg1, const Arg2& arg2) :
+		_fn(fn),
+		_arg0(arg0),
+		_arg1(arg1),
+		_arg2(arg2){
+	}
+
+	/**
+	 * Apply arg0, arg1 and arg2 to fn.
+	 */
+	void operator()() const {
+		_fn(_arg0, _arg1, _arg2);
+	}
+
+private:
+	mutable F _fn;
+	mutable Arg0 _arg0;
+	mutable Arg1 _arg1;
+	mutable Arg2 _arg2;
+};
+
+} // namespace detail
+} // namespace eq
+
+#endif /* EVENTQUEUE_DETAIL_THUNKS_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EventQueue/util/CriticalSectionLock.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,59 @@
+/*
+ * PackageLicenseDeclared: Apache-2.0
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MBED_UTIL_CRITICAL_SECTION_LOCK_H__
+#define __MBED_UTIL_CRITICAL_SECTION_LOCK_H__
+
+#include <stdint.h>
+#include "cmsis.h"
+
+namespace mbed {
+namespace util {
+
+/** RAII object for disabling, then restoring, interrupt state
+  * Usage:
+  * @code
+  *
+  * void f() {
+  *     // some code here
+  *     {
+  *         CriticalSectionLock lock;
+  *         // Code in this block will run with interrupts disabled
+  *     }
+  *     // interrupts will be restored to their previous state
+  * }
+  * @endcode
+  */
+class CriticalSectionLock {
+public:
+    CriticalSectionLock() {
+        _state = __get_PRIMASK();
+        __disable_irq();
+    }
+
+    ~CriticalSectionLock() {
+        __set_PRIMASK(_state);
+    }
+
+private:
+    uint32_t _state;
+};
+
+} // namespace util
+} // namespace mbed
+
+#endif // #ifndef __MBED_UTIL_CRITICAL_SECTION_LOCK_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EventQueue/util/NordicCriticalSectionLock.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,99 @@
+/*
+ * PackageLicenseDeclared: Apache-2.0
+ * Copyright (c) 2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * NOTE: THIS FILE IS A WORKAROUND FOR mbed::util::CriticalSectionLock implementation
+ * it should be removed as soon as https://github.com/ARMmbed/core-util/pull/50 is
+ * accepted and published.
+ */
+
+#ifndef BLE_CLIAPP_UTIL_NORDIC_CRITICAL_SECTION_LOCK_H__
+#define BLE_CLIAPP_UTIL_NORDIC_CRITICAL_SECTION_LOCK_H__
+
+#include <stdint.h>
+#include "cmsis.h"
+#include "nrf_soc.h"
+#include "nrf_sdm.h"
+#include "nrf_nvic.h"
+extern "C" {
+#include "softdevice_handler.h"
+}
+namespace util {
+
+/** RAII object for disabling, then restoring, interrupt state
+  * Usage:
+  * @code
+  *
+  * void f() {
+  *     // some code here
+  *     {
+  *         NordicCriticalSectionLock lock;
+  *         // Code in this block will run with interrupts disabled
+  *     }
+  *     // interrupts will be restored to their previous state
+  * }
+  * @endcode
+  */
+class NordicCriticalSectionLock {
+public:
+
+    /**
+     * Start a critical section, the critical section will end when the
+     * destructor is invoked.
+     */
+    NordicCriticalSectionLock() {
+        // get the state of exceptions for the CPU
+        _PRIMASK_state = __get_PRIMASK();
+
+        // if exceptions are not enabled, there is nothing more to do
+        if(_PRIMASK_state == 1) {
+          _use_softdevice_routine = false;
+        } else {
+          // otherwise, use soft device routine if softdevice is running or disable
+          // the irq if softdevice is not running
+          if(softdevice_handler_isEnabled()) {
+            _use_softdevice_routine = true;
+            sd_nvic_critical_region_enter(&_sd_state);
+          } else {
+            _use_softdevice_routine = false;
+            __disable_irq();
+          }
+        }
+    }
+
+    /**
+     * eqnd a critical section
+     */
+    ~NordicCriticalSectionLock() {
+        if(_use_softdevice_routine) {
+          sd_nvic_critical_region_exit(_sd_state);
+        } else {
+          __set_PRIMASK(_PRIMASK_state);
+        }
+    }
+
+private:
+    union {
+      uint32_t _PRIMASK_state;
+      uint8_t  _sd_state;
+    };
+    bool _use_softdevice_routine;
+};
+
+} // namespace util
+
+#endif // #ifndef BLE_CLIAPP_UTIL_NORDIC_CRITICAL_SECTION_LOCK_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/PersistentStorageHelper/ConfigParamsPersistence.cpp	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,45 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ConfigParamsPersistence.h"
+
+#ifndef TARGET_NRF51822 /* Persistent storage supported on nrf51 platforms */
+    /**
+     * When not using an nRF51-based target then persistent storage is not available.
+     */
+    #warning "EddystoneService is not configured to store configuration data in non-volatile memory"
+
+    bool loadEddystoneServiceConfigParams(EddystoneService::EddystoneParams_t *paramsP)
+    {
+        /* Avoid compiler warnings */
+        (void) paramsP;
+
+        /*
+         * Do nothing and let the main program set Eddystone params to
+         * defaults
+         */
+        return false;
+    }
+
+    void saveEddystoneServiceConfigParams(const EddystoneService::EddystoneParams_t *paramsP)
+    {
+        /* Avoid compiler warnings */
+        (void) paramsP;
+
+        /* Do nothing... */
+        return;
+    }
+#endif /* #ifdef TARGET_NRF51822 */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/PersistentStorageHelper/ConfigParamsPersistence.h Mon Sep 19 00:59:11 2016 +0000 @@ -0,0 +1,53 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2015 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __BLE_CONFIG_PARAMS_PERSISTENCE_H__ +#define __BLE_CONFIG_PARAMS_PERSISTENCE_H__ + +#include "../EddystoneService.h" + +/** + * Generic API to load the Eddystone Service configuration parameters from persistent + * storage. If persistent storage isn't available, the persistenceSignature + * member of params may be left un-initialized to the MAGIC, and this will cause + * a reset to default values. + * + * @param[out] paramsP + * The parameters to be filled in from persistence storage. This + * argument can be NULL if the caller is only interested in + * discovering the persistence status of params. + * + * @return true if params were loaded from persistent storage and have usefully + * initialized fields. + */ +bool loadEddystoneServiceConfigParams(EddystoneService::EddystoneParams_t *paramsP); + +/** + * Generic API to store the Eddystone Service configuration parameters to persistent + * storage. It typically initializes the persistenceSignature member of the + * params to the MAGIC value to indicate persistence. + * + * @param[in,out] paramsP + * The params to be saved; persistenceSignature member gets + * updated if persistence is successful. + * + * @note The save operation may be asynchronous. It may be a short while before + * the request takes affect. Reading back saved configParams may not yield + * correct behaviour if attempted soon after a store. + */ +void saveEddystoneServiceConfigParams(const EddystoneService::EddystoneParams_t *paramsP); + +#endif /* #ifndef __BLE_CONFIG_PARAMS_PERSISTENCE_H__*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/PersistentStorageHelper/nrfPersistentStorageHelper/nrfConfigParamsPersistence.cpp	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,117 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef TARGET_NRF51822 /* Persistent storage supported on nrf51 platforms */
+
+extern "C" {
+    #include "pstorage.h"
+}
+
+#include "nrf_error.h"
+#include "../../EddystoneService.h"
+
+/**
+ * Nordic specific structure used to store params persistently.
+ * It extends EddystoneService::EddystoneParams_t with a persistence signature.
+ */
+struct PersistentParams_t {
+    EddystoneService::EddystoneParams_t params;
+    uint32_t                         persistenceSignature; /* This isn't really a parameter, but having the expected
+                                                            * magic value in this field indicates persistence. */
+
+    static const uint32_t MAGIC = 0x1BEAC000;              /* Magic that identifies persistence */
+};
+
+/**
+ * The following is a module-local variable to hold configuration parameters for
+ * short periods during flash access. This is necessary because the pstorage
+ * APIs don't copy in the memory provided as data source. The memory cannot be
+ * freed or reused by the application until this flash access is complete. The
+ * load and store operations in this module initialize persistentParams and then
+ * pass it on to the 'pstorage' APIs.
+ */
+static PersistentParams_t persistentParams;
+
+static pstorage_handle_t pstorageHandle;
+
+/**
+ * Dummy callback handler needed by Nordic's pstorage module. This is called
+ * after every flash access.
+ */
+static void pstorageNotificationCallback(pstorage_handle_t *p_handle,
+                                         uint8_t            op_code,
+                                         uint32_t           result,
+                                         uint8_t           *p_data,
+                                         uint32_t           data_len)
+{
+    /* Supress compiler warnings */
+    (void) p_handle;
+    (void) op_code;
+    (void) result;
+    (void) p_data;
+    (void) data_len;
+
+    /* APP_ERROR_CHECK(result); */
+}
+
+/* Platform-specific implementation for persistence on the nRF5x. Based on the
+ * pstorage module provided by the Nordic SDK. */
+bool loadEddystoneServiceConfigParams(EddystoneService::EddystoneParams_t *paramsP)
+{
+    static bool pstorageInitied = false;
+    if (!pstorageInitied) {
+        pstorage_init();
+
+        static pstorage_module_param_t pstorageParams = {
+            .cb          = pstorageNotificationCallback,
+            .block_size  = sizeof(PersistentParams_t),
+            .block_count = 1
+        };
+        pstorage_register(&pstorageParams, &pstorageHandle);
+        pstorageInitied = true;
+    }
+
+    if ((pstorage_load(reinterpret_cast<uint8_t *>(&persistentParams), &pstorageHandle, sizeof(PersistentParams_t), 0) != NRF_SUCCESS) ||
+        (persistentParams.persistenceSignature != PersistentParams_t::MAGIC)) {
+        // On failure zero out and let the service reset to defaults
+        memset(paramsP, 0, sizeof(EddystoneService::EddystoneParams_t));
+        return false;
+    }
+
+    memcpy(paramsP, &persistentParams.params, sizeof(EddystoneService::EddystoneParams_t));
+    return true;
+}
+
+/* Platform-specific implementation for persistence on the nRF5x. Based on the
+ * pstorage module provided by the Nordic SDK. */
+void saveEddystoneServiceConfigParams(const EddystoneService::EddystoneParams_t *paramsP)
+{
+    memcpy(&persistentParams.params, paramsP, sizeof(EddystoneService::EddystoneParams_t));
+    if (persistentParams.persistenceSignature != PersistentParams_t::MAGIC) {
+        persistentParams.persistenceSignature = PersistentParams_t::MAGIC;
+        pstorage_store(&pstorageHandle,
+                       reinterpret_cast<uint8_t *>(&persistentParams),
+                       sizeof(PersistentParams_t),
+                       0 /* offset */);
+    } else {
+        pstorage_update(&pstorageHandle,
+                        reinterpret_cast<uint8_t *>(&persistentParams),
+                        sizeof(PersistentParams_t),
+                        0 /* offset */);
+    }
+}
+
+#endif /* #ifdef TARGET_NRF51822 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/TLMFrame.cpp	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,192 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TLMFrame.h"
+#include "EddystoneService.h"
+
+TLMFrame::TLMFrame(uint8_t  tlmVersionIn,
+                   uint16_t tlmBatteryVoltageIn,
+                   uint16_t tlmBeaconTemperatureIn,
+                   uint32_t tlmPduCountIn,
+                   uint32_t tlmTimeSinceBootIn) :
+    tlmVersion(tlmVersionIn),
+    lastTimeSinceBootRead(0),
+    tlmBatteryVoltage(tlmBatteryVoltageIn),
+    tlmBeaconTemperature(tlmBeaconTemperatureIn),
+    tlmPduCount(tlmPduCountIn),
+    tlmTimeSinceBoot(tlmTimeSinceBootIn)
+{
+}
+
+void TLMFrame::setTLMData(uint8_t tlmVersionIn)
+{
+    /* According to the Eddystone spec BatteryVoltage is 0 and
+     * BeaconTemperature is 0x8000 if not supported
+     */
+    tlmVersion           = tlmVersionIn;
+    tlmBatteryVoltage    = 0;
+    tlmBeaconTemperature = 0x8000;
+    tlmPduCount          = 0;
+    tlmTimeSinceBoot     = 0;
+}
+
+void TLMFrame::setData(uint8_t *rawFrame)  // add eidTime - a 4 byte quantity
+{
+    size_t index = 0;
+    rawFrame[index++] = EDDYSTONE_UUID_SIZE + FRAME_SIZE_TLM; // Length of Frame
+    rawFrame[index++] = EDDYSTONE_UUID[0];                    // 16-bit Eddystone UUID
+    rawFrame[index++] = EDDYSTONE_UUID[1];
+    rawFrame[index++] = FRAME_TYPE_TLM;                       // Eddystone frame type = Telemetry
+    rawFrame[index++] = tlmVersion;                           // TLM Version Number
+    rawFrame[index++] = (uint8_t)(tlmBatteryVoltage >> 8);    // Battery Voltage[0]
+    rawFrame[index++] = (uint8_t)(tlmBatteryVoltage >> 0);    // Battery Voltage[1]
+    rawFrame[index++] = (uint8_t)(tlmBeaconTemperature >> 8); // Beacon Temp[0]
+    rawFrame[index++] = (uint8_t)(tlmBeaconTemperature >> 0); // Beacon Temp[1]
+    rawFrame[index++] = (uint8_t)(tlmPduCount >> 24);         // PDU Count [0]
+    rawFrame[index++] = (uint8_t)(tlmPduCount >> 16);         // PDU Count [1]
+    rawFrame[index++] = (uint8_t)(tlmPduCount >> 8);          // PDU Count [2]
+    rawFrame[index++] = (uint8_t)(tlmPduCount >> 0);          // PDU Count [3]
+    rawFrame[index++] = (uint8_t)(tlmTimeSinceBoot >> 24);    // Time Since Boot [0]
+    rawFrame[index++] = (uint8_t)(tlmTimeSinceBoot >> 16);    // Time Since Boot [1]
+    rawFrame[index++] = (uint8_t)(tlmTimeSinceBoot >> 8);     // Time Since Boot [2]
+    rawFrame[index++] = (uint8_t)(tlmTimeSinceBoot >> 0);     // Time Since Boot [3]
+}
+
+void TLMFrame::encryptData(uint8_t* rawFrame, uint8_t* eidIdentityKey, uint8_t rotationPeriodExp, uint32_t beaconTimeSecs) {
+    // uint8_t newinput[ETLM_DATA_LEN];        // DEBUG ONLY
+        
+    // Initialize AES data
+    mbedtls_aes_context ctx;
+    mbedtls_aes_init(&ctx); 
+    mbedtls_aes_setkey_enc(&ctx, eidIdentityKey, sizeof(EidIdentityKey_t) *8 );
+    // Change the TLM version number to the encrypted version
+    rawFrame[VERSION_OFFSET] = ETLM_VERSION; // Encrypted TLM Version number
+    // Create EAX Params
+    uint8_t nonce[ETLM_NONCE_LEN];
+    // Calculate the 48-bit nonce
+    generateEtlmNonce(nonce, rotationPeriodExp, beaconTimeSecs);
+ 
+    uint8_t* input = rawFrame + DATA_OFFSET;  // array size 12
+    uint8_t output[ETLM_DATA_LEN]; // array size 16 (4 bytes are added: SALT[2], MIC[2])
+    memset(output, 0, ETLM_DATA_LEN);
+    uint8_t emptyHeader[1]; // Empty header
+    LOG(("EIDIdentityKey=\r\n")); EddystoneService::logPrintHex(eidIdentityKey, 16);
+    LOG(("TLM input=\r\n")); EddystoneService::logPrintHex(input, 12);
+    LOG(("ETLM SALT=\r\n")); EddystoneService::logPrintHex(nonce+4, 2);
+    LOG(("ETLM Nonce=\r\n")); EddystoneService::logPrintHex(nonce, 6);
+    // Encrypt the TLM to ETLM
+    eddy_aes_authcrypt_eax(&ctx, MBEDTLS_AES_ENCRYPT, nonce, sizeof(nonce), emptyHeader, 0, TLM_DATA_LEN, input, output, output + MIC_OFFSET, MIC_LEN);
+    // memcpy(newinput, output, ETLM_DATA_LEN); // DEBUG ONLY
+    // Only use first 2 bytes of Nonce
+    output[SALT_OFFSET] = nonce[4]; // Nonce MSB
+    output[SALT_OFFSET+1] = nonce[5]; // Nonce LSB
+    LOG(("ETLM output+SALT=\r\n")); EddystoneService::logPrintHex(output, 16);
+    // copy the encrypted payload to the output
+    memcpy((rawFrame + DATA_OFFSET), output, ETLM_DATA_LEN);
+        
+    /* 
+    // DEBUG ONLY TO CHECK DECRYPT==ENCRYPT
+    uint8_t buf[ETLM_DATA_LEN];
+    memset(buf, 0, ETLM_DATA_LEN);
+    int ret = eddy_aes_authcrypt_eax(&ctx, MBEDTLS_AES_DECRYPT, nonce, sizeof(nonce), emptyHeader, 0, TLM_DATA_LEN, newinput, buf, buf + MIC_OFFSET, MIC_LEN);
+    LOG(("ETLM Decoder ret=%d buf=\r\n", ret)); EddystoneService::logPrintHex(buf, 16);
+    */
+        
+    // fix the frame length to the encrypted length
+    rawFrame[FRAME_LEN_OFFSET] = FRAME_SIZE_ETLM + EDDYSTONE_UUID_SIZE; 
+    // Free the AES data struture
+    mbedtls_aes_free(&ctx);
+}
+    
+
+size_t TLMFrame::getRawFrameSize(uint8_t* rawFrame)
+{
+    return rawFrame[FRAME_LEN_OFFSET];
+}
+
+uint8_t* TLMFrame::getData(uint8_t* rawFrame) 
+{
+    if (rawFrame[VERSION_OFFSET] == TLM_VERSION) {
+        setData(rawFrame);
+    }
+    return &(rawFrame[TLM_DATA_OFFSET]);
+}
+
+uint8_t TLMFrame::getDataLength(uint8_t* rawFrame)
+{
+    return rawFrame[FRAME_LEN_OFFSET] - EDDYSTONE_UUID_LEN;
+}
+
+uint8_t* TLMFrame::getAdvFrame(uint8_t* rawFrame){
+    return &(rawFrame[ADV_FRAME_OFFSET]);
+}
+
+uint8_t TLMFrame::getAdvFrameLength(uint8_t* rawFrame){
+    return rawFrame[FRAME_LEN_OFFSET];
+}
+
+void TLMFrame::updateTimeSinceBoot(uint32_t nowInMillis)
+{
+    // Measured in tenths of a second
+    tlmTimeSinceBoot      += (nowInMillis - lastTimeSinceBootRead) / 100;
+    lastTimeSinceBootRead  = nowInMillis;
+}
+
+void TLMFrame::updateBatteryVoltage(uint16_t tlmBatteryVoltageIn)
+{
+    tlmBatteryVoltage = tlmBatteryVoltageIn;
+}
+
+void TLMFrame::updateBeaconTemperature(uint16_t tlmBeaconTemperatureIn)
+{
+    tlmBeaconTemperature = tlmBeaconTemperatureIn;
+}
+
+void TLMFrame::updatePduCount(void)
+{
+    tlmPduCount++;
+}
+
+uint16_t TLMFrame::getBatteryVoltage(void) const
+{
+    return tlmBatteryVoltage;
+}
+
+uint16_t TLMFrame::getBeaconTemperature(void) const
+{
+    return tlmBeaconTemperature;
+}
+
+uint8_t TLMFrame::getTLMVersion(void) const
+{
+    return tlmVersion;
+}
+
+int TLMFrame::generateEtlmNonce(uint8_t* nonce, uint8_t rotationPeriodExp, uint32_t beaconTimeSecs) {
+    int rc = 0;
+    if (sizeof(nonce) != ETLM_NONCE_LEN) {
+      rc = ETLM_NONCE_INVALID_LEN; 
+    }
+    uint32_t scaledTime = (beaconTimeSecs >> rotationPeriodExp) << rotationPeriodExp;
+    int index = 0;
+    nonce[index++] = (scaledTime  >> 24) & 0xff;
+    nonce[index++] = (scaledTime >> 16) & 0xff;
+    nonce[index++] = (scaledTime >> 8) & 0xff;
+    nonce[index++] = scaledTime & 0xff;
+    EddystoneService::generateRandom(nonce + index, SALT_LEN);
+    return rc;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/TLMFrame.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,276 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TLMFRAME_H__
+#define __TLMFRAME_H__
+
+#include "EddystoneTypes.h"
+#include "aes_eax.h"
+
+/**
+ * Class that encapsulates data that belongs to the Eddystone-TLM frame. For
+ * more information refer to https://github.com/google/eddystone/tree/master/eddystone-tlm.
+ */
+class TLMFrame
+{
+public:
+    /**
+     * Construct a new instance of this class.
+     *
+     * @param[in] tlmVersionIn
+     *              Eddystone-TLM version number to use.
+     * @param[in] tlmBatteryVoltageIn
+     *              Initial value for the Eddystone-TLM Battery Voltage.
+     * @param[in] tlmBeaconTemperatureIn
+     *              Initial value for the Eddystone-TLM Beacon Temperature.
+     * @param[in] tlmPduCountIn
+     *              Initial value for the Eddystone-TLM Advertising PDU Count.
+     * @param[in] tlmTimeSinceBootIn
+     *              Intitial value for the Eddystone-TLM time since boot timer.
+     8              This timer has a 0.1 second resolution.
+     */
+    TLMFrame(uint8_t  tlmVersionIn           = 0,
+             uint16_t tlmBatteryVoltageIn    = 0,
+             uint16_t tlmBeaconTemperatureIn = 0x8000,
+             uint32_t tlmPduCountIn          = 0,
+             uint32_t tlmTimeSinceBootIn     = 0);
+
+    /**
+     * Set the Eddystone-TLM version number.
+     */
+    void setTLMData(uint8_t tlmVersionIn = 0);
+
+    /**
+     * Construct the raw bytes of the Eddystone-TLM frame that will be directly
+     * used in the advertising packets.
+     *
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     */
+    void setData(uint8_t *rawFrame);
+    
+    /**
+     * Construct the encrypted bytes of the Eddystone-ETLM frame that will be directly
+     * used in the advertising packets.
+     *
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     * @param[in] eidIdentityKey
+     *              Pointer to the eidIdentityKey in use
+     * @param[in] rotationPeriodExp
+     *              Rotation exponent for EID
+     * @param[in] beaconTimeSecs
+     *              Time in seconds since beacon boot.
+     */
+    void encryptData(uint8_t* rawFrame, uint8_t* eidIdentityKey, uint8_t rotationPeriodExp, uint32_t beaconTimeSecs);
+
+    /**
+     * Get the size of the Eddystone-TLM frame constructed with the
+     * current state of the TLMFrame object.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return The size in bytes of the Eddystone-TLM frame.
+     */
+    size_t getRawFrameSize(uint8_t* rawFrame);
+    
+    
+    /**
+     * Get the TLM frame data from the Eddystone-TLM frame.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return A pointer to the bytes of the Eddystone-TLM frame data.
+     */
+    uint8_t* getData(uint8_t* rawFrame);
+    
+    /**
+     * Get the length of the TLM frame data from the Eddystone-TLM frame.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return The size in bytes of the Eddystone-TLM frame.
+     */
+    uint8_t  getDataLength(uint8_t* rawFrame);
+    
+    /**
+     * Get the TLM Adv data from the Eddystone-TLMframe.
+     * This is the full service data included in the BLE service data params
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return A pointer to the bytes of the Eddystone-TLM Adv frame data.
+     */
+    uint8_t* getAdvFrame(uint8_t* rawFrame);
+    
+    /**
+     * Get the length of the TLM Adv data from the Eddystone-TLMframe.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return The size in bytes of the Eddystone-TLM Adv frame data.
+     */
+    uint8_t getAdvFrameLength(uint8_t* rawFrame);
+
+    /**
+     * Update the time since boot.
+     *
+     * @param[in] nowInMillis
+     *              The time since boot in milliseconds.
+     */
+    void updateTimeSinceBoot(uint32_t nowInMillis);
+
+    /**
+     * Update the Battery Voltage.
+     *
+     * @param[in] tlmBatteryVoltageIn
+     *              The new Battery Voltage value.
+     */
+    void updateBatteryVoltage(uint16_t tlmBatteryVoltageIn);
+
+    /**
+     * Update the Beacon Temperature.
+     *
+     * @param[in] tlmBeaconTemperatureIn
+     *              The new Beacon Temperature value.
+     */
+    void updateBeaconTemperature(uint16_t tlmBeaconTemperatureIn);
+
+    /**
+     * Increment the current PDU counter by 1.
+     */
+    void updatePduCount(void);
+
+    /**
+     * Get the current Battery Voltage.
+     *
+     * @return The Battery Voltage.
+     */
+    uint16_t getBatteryVoltage(void) const;
+
+    /**
+     * Get the current Beacon Temperature.
+     *
+     * @return The Beacon Temperature.
+     */
+    uint16_t getBeaconTemperature(void) const;
+
+    /**
+     * Get the current TLM Version number.
+     *
+     * @return The TLM Version number.
+     */
+    uint8_t getTLMVersion(void) const;
+    
+    /**
+     * The byte ID of an Eddystone-TLM frame.
+     */
+    static const uint8_t FRAME_TYPE_TLM = 0x20;
+    
+    /**
+    * The verison number of the Telemetry packets being used
+    */
+    static const uint8_t DEFAULT_TLM_VERSION = 0;
+
+    /**
+     * The size of an Eddystone-TLM frame.
+     */
+    static const uint8_t FRAME_SIZE_TLM = 14;
+    /**
+     * The size of an Eddystone-ETLM frame.
+     */
+    static const uint8_t FRAME_SIZE_ETLM = (FRAME_SIZE_TLM + 4);
+
+    // Nonce
+    static const uint8_t ETLM_NONCE_LEN = 6;
+    // Version
+    static const uint8_t VERSION_OFFSET = 4;
+    static const uint8_t TLM_VERSION = 0x00;
+    static const uint8_t ETLM_VERSION = 0x01;
+    // Data
+    static const uint8_t DATA_OFFSET = 5;
+    static const uint8_t TLM_DATA_LEN = 12;
+    static const uint8_t ETLM_DATA_LEN = 16;
+    // Salt
+    static const uint8_t SALT_OFFSET = 12;
+    static const uint8_t SALT_LEN = 2;
+    // Message Integrity Check
+    static const uint8_t MIC_OFFSET = 14;
+    static const uint8_t MIC_LEN = 2;
+    // Return codes
+    static const int ETLM_NONCE_INVALID_LEN = -1;
+
+    /**
+     * Constructs 6 byte (48-bit) Nonce from an empty array, rotationExp and beacon time (secs) 
+     *
+     * @param[in] nonce
+     *              the input and target nonce[] array
+     * @param[in] rotationPeriodExp
+     *              Rotation exponent for EID
+     * @param[in] beaconTimeSecs
+     *              Time in seconds since beacon boot.
+     * @return[out] return code (success = 0)
+     */
+    int generateEtlmNonce(uint8_t* nonce, uint8_t rotatePeriodExp, uint32_t beaconTimeSecs);
+
+
+private:
+
+    /**
+     * The size (in bytes) of an Eddystone-EID frame.
+     * This is the some of the Eddystone UUID(2 bytes), FrameType, AdvTxPower,
+     * EID Value
+     */
+    // static const uint8_t TLM_FRAME_LEN = 16;
+    // static const uint8_t ETLM_FRAME_LEN = 20;
+    static const uint8_t FRAME_LEN_OFFSET = 0;
+    static const uint8_t EDDYSTONE_UUID_LEN = 2; 
+    static const uint8_t TLM_DATA_OFFSET = 3;
+    static const uint8_t ADV_FRAME_OFFSET = 1;
+
+    /**
+     * Eddystone-TLM version value.
+     */
+    uint8_t              tlmVersion;
+    /**
+     * Time since boot in milliseconds.
+     */
+    uint32_t             lastTimeSinceBootRead;
+    /**
+     * Eddystone-TLM Battery Voltage value.
+     */
+    uint16_t             tlmBatteryVoltage;
+    /**
+     * Eddystone-TLM Beacon temperature value.
+     */
+    uint16_t             tlmBeaconTemperature;
+    /**
+     * Eddystone-TLM Advertising PDU Count.
+     */
+    uint32_t             tlmPduCount;
+    /**
+     * Eddystone-TLM time since boot with 0.1 second resolution.
+     */
+    uint32_t             tlmTimeSinceBoot;
+
+
+};
+#endif  /* __TLMFRAME_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/UIDFrame.cpp	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,69 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "UIDFrame.h"
+
+UIDFrame::UIDFrame(void) {
+}
+
+void UIDFrame::clearFrame(uint8_t* frame) {
+    frame[FRAME_LEN_OFFSET] = 0; // Set frame length to zero to clear it
+}
+
+void UIDFrame::setData(uint8_t *rawFrame, int8_t advTxPower, const uint8_t* uidData) {
+    size_t index = 0;
+    rawFrame[index++] = UID_HEADER_LEN + UID_LENGTH;            // UID length + overhead of four bytes below
+    rawFrame[index++] = EDDYSTONE_UUID[0];                      // LSB 16-bit Eddystone UUID (little endian)
+    rawFrame[index++] = EDDYSTONE_UUID[1];                      // MSB
+    rawFrame[index++] = FRAME_TYPE_UID;                         // 1B  Type
+    rawFrame[index++] = advTxPower;                             // 1B  Power @ 0meter
+
+    memcpy(rawFrame + index, uidData, UID_LENGTH);              // UID = 10B NamespaceID + 6B InstanceID
+}
+
+uint8_t* UIDFrame::getData(uint8_t* rawFrame) {
+    return &(rawFrame[UID_DATA_OFFSET]);
+}
+
+uint8_t  UIDFrame::getDataLength(uint8_t* rawFrame)
+{
+    return rawFrame[FRAME_LEN_OFFSET] - EDDYSTONE_UUID_LEN;
+}
+
+uint8_t* UIDFrame::getAdvFrame(uint8_t* rawFrame)
+{
+    return &(rawFrame[ADV_FRAME_OFFSET]);
+}
+
+uint8_t UIDFrame::getAdvFrameLength(uint8_t* rawFrame)
+{
+    return rawFrame[FRAME_LEN_OFFSET];
+}
+
+uint8_t* UIDFrame::getUid(uint8_t* rawFrame)
+{
+    return &(rawFrame[UID_VALUE_OFFSET]);
+}
+
+uint8_t UIDFrame::getUidLength(uint8_t* rawFrame)
+{
+    return rawFrame[FRAME_LEN_OFFSET] - UID_HEADER_LEN;
+}
+
+void UIDFrame::setAdvTxPower(uint8_t* rawFrame, int8_t advTxPower)
+{
+    rawFrame[UID_TXPOWER_OFFSET] = advTxPower;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/UIDFrame.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,156 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UIDFRAME_H__
+#define __UIDFRAME_H__
+
+#include <string.h>
+#include "EddystoneTypes.h"
+
+/**
+ * Class that encapsulates data that belongs to the Eddystone-UID frame. For
+ * more information refer to https://github.com/google/eddystone/tree/master/eddystone-uid.
+ */
+class UIDFrame
+{
+public:
+    static const uint8_t UID_LENGTH = 16;
+
+    /**
+     * Construct a new instance of this class.
+     */
+    UIDFrame(void);
+    
+    /**
+     * Clear frame (intervally indicated by length = 0 )
+     */
+    void clearFrame(uint8_t* frame);
+    
+    /**
+     * Construct the raw bytes of the Eddystone-UID frame that will be directly
+     * used in the advertising packets.
+     *
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     * @param[in] advPowerLevel
+     *              Power level value included in the raw frame.
+     * @param[in] uidData
+     *              The actual 16-byte UID data in the raw frame.
+     */
+    void setData(uint8_t* rawFrame, int8_t advTxPower, const uint8_t* uidData);
+    
+    /**
+     * Get the UID frame data from the Eddystone-UID frame.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return A pointer to the bytes of the Eddystone-UID frame data.
+     */
+    uint8_t* getData(uint8_t* rawFrame);
+    
+    /**
+     * Get the length of the UID frame data from the Eddystone-UID frame.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return The size in bytes of the Eddystone-UID frame.
+     */
+    uint8_t  getDataLength(uint8_t* rawFrame);
+    
+    /**
+     * Get the UID Adv data from the Eddystone-UID frame.
+     * This is the full service data included in the BLE service data params
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return A pointer to the bytes of the Eddystone-UID Adv frame data.
+     */
+    uint8_t* getAdvFrame(uint8_t* rawFrame);
+    
+    /**
+     * Get the length of the UID Adv data from the Eddystone-UID frame.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return The size in bytes of the Eddystone-UID Adv frame data.
+     */
+    uint8_t getAdvFrameLength(uint8_t* rawFrame);
+
+    /**
+     * Get just the UID data from the Eddystone-UID frame.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return A pointer to the bytes of the UID in the Eddystone-UID frame.
+     */
+    uint8_t* getUid(uint8_t* rawFrame);
+    
+    /**
+     * Get the length of just the UID data from the Eddystone-UID frame.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return The size in bytes of the UID in the Eddystone-UID frame.
+     */
+    uint8_t getUidLength(uint8_t* rawFrame);
+    
+    /**
+     * Set the Adv TX Power in the frame. This is necessary because the adv
+     * Tx Power might be updated independent of the data bytes
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     * @param[in] advPowerLevel
+     *              Power level value included in the raw frame.
+     *
+     */
+    void setAdvTxPower(uint8_t* rawFrame, int8_t advTxPower);
+    
+    /**
+     *  The byte ID of an Eddystone-UID frame.
+     */
+    static const uint8_t FRAME_TYPE_UID = 0x00;
+
+private:
+    static const uint8_t UID_FRAME_LEN = 20; 
+    static const uint8_t FRAME_LEN_OFFSET = 0;
+    static const uint8_t EDDYSTONE_UUID_LEN = 2;
+    static const uint8_t UID_DATA_OFFSET = 3;
+    static const uint8_t ADV_FRAME_OFFSET = 1;
+    static const uint8_t UID_VALUE_OFFSET = 5;
+    static const uint8_t UID_HEADER_LEN = 4;
+    static const uint8_t UID_TXPOWER_OFFSET = 4;
+    /**
+     * The size (in bytes) of an Eddystone-UID frame.
+     * This is the some of the Eddystone UUID(2 bytes), FrameType, AdvTxPower,
+     * UID Name Length, and UID Instance Length
+     */
+    static const uint8_t FRAME_SIZE_UID = 20;
+    /**
+     * The size (in bytes) of an Eddystone-UID frame.
+     */
+    static const uint8_t UID_NAMESPACEID_LENGTH = 10;
+    static const uint8_t UID_INSTANCEID_LENGTH = 6;
+ 
+};
+
+#endif  /* __UIDFRAME_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/URLFrame.cpp	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,151 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "URLFrame.h"
+
+/* CONSTRUCTOR */ 
+URLFrame::URLFrame(void)
+{
+}
+    
+void URLFrame::setUnencodedUrlData(uint8_t* rawFrame, int8_t advTxPower, const char *rawUrl)
+{    
+    uint8_t encodedUrl[ENCODED_BUF_SIZE];
+    int encodedUrlLen = encodeURL(encodedUrl, rawUrl);
+    encodedUrlLen = (encodedUrlLen > MAX_URL_DATA) ? MAX_URL_DATA : encodedUrlLen;
+    setData(rawFrame, advTxPower, reinterpret_cast<const uint8_t*>(encodedUrl), encodedUrlLen);
+}
+
+void URLFrame::clearFrame(uint8_t* frame) {
+    frame[FRAME_LEN_OFFSET] = 0; // Set frame length to zero to clear it
+}
+
+void URLFrame::setData(uint8_t* rawFrame, int8_t advTxPower, const uint8_t* encodedUrlData, uint8_t encodedUrlLen)
+{
+    uint8_t index = 0;
+    rawFrame[index++] = URL_HEADER_LEN + encodedUrlLen; // INDEX=0 = Frame Length = encodedURL size + 4 bytes of header below
+    rawFrame[index++] = EDDYSTONE_UUID[0];              // FRAME 16-bit Eddystone UUID Low Byte (little endian)
+    rawFrame[index++] = EDDYSTONE_UUID[1];              // FRAME 16-bit Eddystone UUID High Byte
+    rawFrame[index++] = FRAME_TYPE_URL;                 // URL Frame Type
+    rawFrame[index++] = advTxPower;                     // Power @ 0meter 
+    
+    memcpy(rawFrame + index, encodedUrlData, encodedUrlLen); 
+}
+
+uint8_t*  URLFrame::getData(uint8_t* rawFrame) {
+    return &(rawFrame[URL_DATA_OFFSET]);
+}
+
+
+uint8_t  URLFrame::getDataLength(uint8_t* rawFrame) {
+    return rawFrame[FRAME_LEN_OFFSET] - EDDYSTONE_UUID_LEN;
+}
+
+uint8_t* URLFrame::getAdvFrame(uint8_t* rawFrame) 
+{
+    return &(rawFrame[ADV_FRAME_OFFSET]);
+}
+
+uint8_t URLFrame::getAdvFrameLength(uint8_t* rawFrame) 
+{
+    return rawFrame[FRAME_LEN_OFFSET];
+}
+
+uint8_t* URLFrame::getEncodedUrl(uint8_t* rawFrame)
+{
+    return &(rawFrame[URL_VALUE_OFFSET]);
+}
+
+uint8_t URLFrame::getEncodedUrlLength(uint8_t* rawFrame) 
+{
+    return rawFrame[ADV_FRAME_OFFSET] - URL_HEADER_LEN;
+}
+
+
+uint8_t URLFrame::encodeURL(uint8_t* encodedUrl, const char *rawUrl)
+{
+    uint8_t urlDataLength = 0;
+    
+    const char  *prefixes[] = {
+        "http://www.",
+        "https://www.",
+        "http://",
+        "https://",
+    };
+    const size_t NUM_PREFIXES = sizeof(prefixes) / sizeof(char *);
+    const char  *suffixes[]   = {
+        ".com/",
+        ".org/",
+        ".edu/",
+        ".net/",
+        ".info/",
+        ".biz/",
+        ".gov/",
+        ".com",
+        ".org",
+        ".edu",
+        ".net",
+        ".info",
+        ".biz",
+        ".gov"
+    };
+    const size_t NUM_SUFFIXES = sizeof(suffixes) / sizeof(char *);
+
+    memset(encodedUrl, 0, ENCODED_BUF_SIZE);
+
+    if ((rawUrl == NULL) || (strlen(rawUrl) == 0)) {
+        return urlDataLength;
+    }
+
+    /*
+     * handle prefix
+     */
+    for (size_t i = 0; i < NUM_PREFIXES; i++) {
+        size_t prefixLen = strlen(prefixes[i]);
+        if (strncmp(rawUrl, prefixes[i], prefixLen) == 0) {
+            encodedUrl[urlDataLength++]  = i;
+            rawUrl                      += prefixLen;
+            break;
+        }
+    }
+
+    /*
+     * handle suffixes
+     */
+    while (*rawUrl && (urlDataLength <= MAX_URL_DATA)) {
+        /* check for suffix match */
+        size_t i;
+        for (i = 0; i < NUM_SUFFIXES; i++) {
+            size_t suffixLen = strlen(suffixes[i]);
+            if (strncmp(rawUrl, suffixes[i], suffixLen) == 0) {
+                encodedUrl[urlDataLength++]  = i;
+                rawUrl                      += suffixLen;
+                break; /* from the for loop for checking against suffixes */
+            }
+        }
+        /* This is the default case where we've got an ordinary character which doesn't match a suffix. */
+        if (i == NUM_SUFFIXES) {
+            encodedUrl[urlDataLength++] = *rawUrl;
+            ++rawUrl;
+        }
+    }
+    return urlDataLength;
+}
+
+void URLFrame::setAdvTxPower(uint8_t* rawFrame, int8_t advTxPower)
+{
+    rawFrame[URL_TXPOWER_OFFSET] = advTxPower;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/URLFrame.h	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,186 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2015 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __URLFRAME_H__
+#define __URLFRAME_H__
+
+#include "EddystoneTypes.h"
+#include <string.h>
+
+/**
+ * Class that encapsulates data that belongs to the Eddystone-URL frame. For
+ * more information refer to https://github.com/google/eddystone/tree/master/eddystone-url.
+ */
+class URLFrame
+{
+public:
+    /**
+     * Construct a new instance of this class.
+     */
+    URLFrame(void);
+    
+    /**
+     * Construct the raw bytes of the Eddystone-URL frame from an unencoded URL
+     * (a null terminated string) that will be directly used in the advertising
+     * packets.
+     *
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     * @param[in] advPowerLevel
+     *              Power level value included in the raw frame.
+     * @param[in] rawURL
+     *              A null terminated string containing the URL
+     */
+    void setUnencodedUrlData(uint8_t* rawFrame, int8_t advTxPower, const char *rawUrl);
+    
+    /**
+     * Clear frame (intervally indicated by length = 0 )
+     */
+    void clearFrame(uint8_t* frame);
+    
+    /**
+     * Construct the raw bytes of the Eddystone-URL frame from an encoded URL 
+     * plus length information
+     *
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     * @param[in] advPowerLevel
+     *              Power level value included in the raw frame.
+     * @param[in] encodedUrlData
+     *              A pointer to the encoded URL bytes.
+     * @param[in] encodedUrlLen
+     *              The length in bytes of the encoded URL
+     */
+    void setData(uint8_t* rawFrame, int8_t advPowerLevel, const uint8_t* encodedUrlData, uint8_t encodedUrlLen);
+    
+    /**
+     * Get the URL frame data from the Eddystone-URL frame.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return A pointer to the bytes of the Eddystone-URL frame data.
+     */
+    uint8_t* getData(uint8_t* rawFrame);
+    
+    /**
+     * Get the length of the URL frame data from the Eddystone-UID frame.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return The size in bytes of the Eddystone-URL frame.
+     */
+    uint8_t getDataLength(uint8_t* rawFrame);
+
+    /**
+     * Get the URL Adv data from the Eddystone-URLframe.
+     * This is the full service data included in the BLE service data params
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return A pointer to the bytes of the Eddystone-URLAdv frame data.
+     */
+    uint8_t* getAdvFrame(uint8_t* rawFrame);
+    
+    /**
+     * Get the length of the URLAdv data from the Eddystone-URL frame.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return The size in bytes of the Eddystone-URL Adv frame data.
+     */
+    uint8_t getAdvFrameLength(uint8_t* rawFrame);
+
+    /**
+     * Get just the encoded URL data from the Eddystone-URL frame.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return A pointer to the bytes of the encoded URL in the Eddystone-URL
+     * frame.
+     */
+    uint8_t* getEncodedUrl(uint8_t* rawFrame);
+    
+    /**
+     * Get the length of just the encoded URL data from the Eddystone-URL frame.
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     *
+     * @return The size in bytes of the encoded URL in the Eddystone-URL frame.
+     */
+    uint8_t getEncodedUrlLength(uint8_t* rawFrame);
+    
+    /**
+     * Set the Adv TX Power in the frame. This is necessary because the adv
+     * Tx Power might be updated independent of the data bytes
+     * 
+     * @param[in] rawFrame
+     *              Pointer to the location where the raw frame will be stored.
+     * @param[in] advPowerLevel
+     *              Power level value included in the raw frame.
+     *
+     */
+    void setAdvTxPower(uint8_t* rawFrame, int8_t advTxPower);
+
+    /**
+     *  The byte ID of an Eddystone-URL frame.
+     */
+    static const uint8_t FRAME_TYPE_URL     = 0x10;
+
+private:
+    static const uint8_t FRAME_LEN_OFFSET = 0;
+    static const uint8_t EDDYSTONE_UUID_LEN = 2;
+    static const uint8_t URL_DATA_OFFSET = 3;
+    static const uint8_t ADV_FRAME_OFFSET = 1;
+    static const uint8_t URL_VALUE_OFFSET = 5;
+    static const uint8_t URL_HEADER_LEN = 4;
+    static const uint8_t URL_TXPOWER_OFFSET = 4;
+
+    /**
+     * Helper function that encodes a URL null terminated string into the HTTP
+     * URL Encoding required in Eddystone-URL frames. Refer to
+     * https://github.com/google/eddystone/blob/master/eddystone-url/README.md#eddystone-url-http-url-encoding.
+     *
+     * @param[in] encodedUrlData
+     *              The encoded bytes of the URL
+     * @param[in] rawUrl
+     *              The null terminated string containing a URL to encode.
+     * @return Length of the encodedData in bytes
+     */
+    uint8_t encodeURL(uint8_t* encodedUrlData, const char* rawUrl);
+
+    /**
+     * The minimum size (in bytes) of an Eddystone-URL frame.
+     */
+    static const uint8_t FRAME_MIN_SIZE_URL = 2;
+    
+    /**
+     * The max size (in bytes) of an Eddystone-URL frame.
+     */
+    static const uint8_t ENCODED_BUF_SIZE = 32;
+    
+    /**
+    * Offset for playload in a rawFrame UID
+    */
+    static const uint8_t MAX_URL_DATA = 18;
+};
+
+#endif /* __URLFRAME_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/aes_eax.cpp	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2016, Google Inc, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+#include <string.h>
+
+// #include "aes_eax.h"
+// set defines before loading aes.h
+#define MBEDTLS_CIPHER_MODE_CBC
+#define MBEDTLS_CIPHER_MODE_CTR
+#include "aes.h"
+
+#define EDDY_ERR_EAX_AUTH_FAILED    -0x000F /**< Authenticated decryption failed. */
+
+void gf128_double_( unsigned char val[16] )
+{
+	int i;
+	int carry = val[0] >> 7;
+	int xv = (-carry) & 0x87;
+	for (i = 15; i >= 0; i--) {
+		carry = val[i] >> 7;
+		val[i] = (val[i] << 1) ^ xv;
+		xv = carry;
+	}
+}
+
+int compute_cmac_( mbedtls_aes_context *ctx,
+		          const unsigned char *input,
+		          size_t length,
+		          unsigned char param,
+		          unsigned char mac[16] )
+{
+	unsigned char buf[16], iv[16];
+	memset(buf, 0, sizeof(buf));
+	buf[15] = param;
+	memset(iv, 0, sizeof(iv));
+	length += 16;
+
+	unsigned char pad[16];
+	memset(pad, 0, sizeof(pad));
+	mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, pad, pad);
+	gf128_double_(pad);
+	if (length & 15) {
+		gf128_double_(pad);
+		pad[length & 15] ^= 0x80;
+	}
+
+	const unsigned char *tmp_input = buf;
+	while (length > 16) {
+		mbedtls_aes_crypt_cbc(ctx, MBEDTLS_AES_ENCRYPT, 16, iv, tmp_input, buf);
+		if (tmp_input == buf) {
+			tmp_input = input;
+		} else {
+			tmp_input += 16;
+		}
+		length -= 16;
+	}
+
+	size_t i;
+	for (i = 0; i < length; i++)
+		pad[i] ^= tmp_input[i];
+
+	mbedtls_aes_crypt_cbc(ctx, MBEDTLS_AES_ENCRYPT, 16, iv, pad, mac);
+	return 0;
+}
+
+int eddy_aes_authcrypt_eax( mbedtls_aes_context *ctx,
+                            int mode,                   
+                            const unsigned char *nonce, 
+                            size_t nonce_length,        
+                            const unsigned char *header,
+                            size_t header_length, 
+                            size_t message_length,
+                            const unsigned char *input,
+                            unsigned char *output,
+                            unsigned char *tag,
+                            size_t tag_length )
+{
+	unsigned char header_mac[16];
+	unsigned char nonce_mac[16];
+	unsigned char ciphertext_mac[16];
+	uint8_t i;
+	compute_cmac_(ctx, header, header_length, 1, header_mac);
+	compute_cmac_(ctx, nonce, nonce_length, 0, nonce_mac);
+	if (mode == MBEDTLS_AES_DECRYPT) {
+		compute_cmac_(ctx, input, message_length, 2, ciphertext_mac);
+		unsigned char n_ok = 0;
+		for (i = 0; i < tag_length; i++) {
+			ciphertext_mac[i] ^= header_mac[i];
+			ciphertext_mac[i] ^= nonce_mac[i];
+			ciphertext_mac[i] ^= tag[i];
+			n_ok |= ciphertext_mac[i];
+		}
+		if (n_ok)
+			return EDDY_ERR_EAX_AUTH_FAILED;
+	}
+	size_t nc_off = 0;
+	unsigned char nonce_copy[16];
+	memcpy(nonce_copy, nonce_mac, sizeof(nonce_mac));
+	unsigned char sb[16];
+	mbedtls_aes_crypt_ctr(ctx, message_length, &nc_off, nonce_copy, sb, input, output);
+	if (mode == MBEDTLS_AES_ENCRYPT) {
+		compute_cmac_(ctx, output, message_length, 2, ciphertext_mac); 
+		for (i = 0; i < tag_length; i++)
+			tag[i] = header_mac[i] ^ nonce_mac[i] ^ ciphertext_mac[i];
+	}
+	return 0;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/aes_eax.h Mon Sep 19 00:59:11 2016 +0000 @@ -0,0 +1,47 @@ +#if !defined(AES_EAX_H__INCLUDED__) +#define AES_EAX_H__INCLUDED__ + +#define MBEDTLS_CIPHER_MODE_CBC +/* + * Copyright (c) 2016, Google Inc, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define MBEDTLS_CIPHER_MODE_CTR +#include "mbedtls/aes.h" + +int compute_cmac_( mbedtls_aes_context *ctx, + const unsigned char *input, + size_t length, + unsigned char param, + unsigned char mac[16] ); + +void gf128_double_( unsigned char val[16] ); + +int eddy_aes_authcrypt_eax( mbedtls_aes_context *ctx, + int mode, /* ENCRYPT/DECRYPT */ + const unsigned char *nonce, /* 48-bit nonce */ + size_t nonce_length, /* = 6 */ + const unsigned char *header, /* Empty buffer */ + size_t header_length, /* = 0 */ + size_t message_length, /* Length of input & output buffers 12 */ + const unsigned char *input, + unsigned char *output, + unsigned char *tag, + size_t tag_length ); /* = 2 */ + + + +#endif /* defined(AES_EAX_H__INCLUDED__) */ \ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/main.cpp	Mon Sep 19 00:59:11 2016 +0000
@@ -0,0 +1,308 @@
+/* mbed Microcontroller Library
+ * Copyright (c) 2006-2013 ARM Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifdef YOTTA_CFG_MBED_OS  // use minar on mbed OS
+#   include "mbed-drivers/mbed.h"
+#else
+#   include "mbed.h"
+#endif
+
+#include "ble/BLE.h"
+#include "EddystoneService.h"
+
+#include "PersistentStorageHelper/ConfigParamsPersistence.h"
+#include "stdio.h"
+
+// Instantiation of the main event loop for this program
+
+#ifdef YOTTA_CFG_MBED_OS  // use minar on mbed OS
+#   include "EventQueue/EventQueueMinar.h"
+    typedef eq::EventQueueMinar event_queue_t;
+
+#else      // otherwise use the event classic queue
+#   include "EventQueue/EventQueueClassic.h"
+    typedef eq::EventQueueClassic<
+        /* event count */ 10
+    > event_queue_t;
+
+#endif
+
+static event_queue_t eventQueue;
+
+EddystoneService *eddyServicePtr;
+
+/* Duration after power-on that config service is available. */
+static const int CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS = EDDYSTONE_DEFAULT_CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS;
+
+/* Values for ADV packets related to firmware levels, calibrated based on measured values at 1m */
+static const PowerLevels_t advTxPowerLevels = EDDYSTONE_DEFAULT_ADV_TX_POWER_LEVELS;
+/* Values for radio power levels, provided by manufacturer. */
+static const PowerLevels_t radioTxPowerLevels = EDDYSTONE_DEFAULT_RADIO_TX_POWER_LEVELS;
+
+DigitalOut configLED(CONFIG_LED, LED_OFF);
+
+static const int BLINKY_MSEC = 500;                       // How long to cycle config LED on/off
+static event_queue_t::event_handle_t handle = 0;         // For the config mode timeout
+static event_queue_t::event_handle_t BlinkyHandle = 0;   // For the blinking LED when in config mode
+
+static void blinky(void)  { configLED = !configLED; }
+
+static void configLED_on(void) {
+    configLED = !LED_OFF;
+    BlinkyHandle = eventQueue.post_every(blinky, BLINKY_MSEC);
+}
+
+static void configLED_off(void) {
+    configLED = LED_OFF;
+    if (BlinkyHandle) {
+        eventQueue.cancel(BlinkyHandle);
+        BlinkyHandle = NULL;
+    }
+}
+
+/**
+ * Callback triggered some time after application started to switch to beacon mode.
+ */
+static void timeoutToStartEddystoneBeaconAdvertisements(void)
+{
+    Gap::GapState_t state;
+    state = BLE::Instance().gap().getState();
+    if (!state.connected) { /* don't switch if we're in a connected state. */
+        eddyServicePtr->startEddystoneBeaconAdvertisements();
+        configLED_off();
+    }
+}
+
+/**
+ * Callback triggered for a connection event.
+ */
+static void connectionCallback(const Gap::ConnectionCallbackParams_t *cbParams)
+{
+    (void) cbParams;
+    // Stop advertising whatever the current mode
+    eddyServicePtr->stopEddystoneBeaconAdvertisements();
+}
+
+/**
+ * Callback triggered for a disconnection event.
+ */
+static void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *cbParams)
+{
+    (void) cbParams;
+    BLE::Instance().gap().startAdvertising();
+    // Save params in persistent storage
+    EddystoneService::EddystoneParams_t params;
+    eddyServicePtr->getEddystoneParams(params);
+    saveEddystoneServiceConfigParams(¶ms);
+    // Ensure LED is off at the end of Config Mode or during a connection
+    configLED_off();
+    // 0.5 Second callback to rapidly re-establish Beaconing Service
+    // (because it needs to be executed outside of disconnect callback)
+    eventQueue.post_in(timeoutToStartEddystoneBeaconAdvertisements, 500 /* ms */);
+}
+
+// This section defines a simple push button handler to enter config or shutdown the beacon
+// Only compiles if "reset_button" is set in config.json in the "platform" section
+//
+#ifdef RESET_BUTTON
+
+InterruptIn button(RESET_BUTTON);
+DigitalOut shutdownLED(SHUTDOWN_LED, LED_OFF);
+
+static void shutdownLED_on(void) { shutdownLED = !LED_OFF; }
+static void shutdownLED_off(void) { shutdownLED = LED_OFF; }
+
+static int beaconIsOn = 1;                          // Button handler boolean to switch on or off
+static int buttonBusy;                              // semaphore to make prevent switch bounce problems
+
+static void freeButtonBusy(void) { buttonBusy = false; }
+
+// Callback used to handle button presses from thread mode (not IRQ)
+static void button_task(void) {
+    eventQueue.cancel(handle);   // kill any pending callback tasks
+
+    if (beaconIsOn) {
+        beaconIsOn = 0;
+        eddyServicePtr->stopEddystoneBeaconAdvertisements();
+        configLED_off();    // just in case it's still running...
+        shutdownLED_on();   // Flash shutdownLED to let user know we're turning off
+        eventQueue.post_in(shutdownLED_off, 1000);
+    } else {
+
+        beaconIsOn = 1;
+        eddyServicePtr->startEddystoneConfigAdvertisements();
+        configLED_on();
+        handle = eventQueue.post_in(
+            timeoutToStartEddystoneBeaconAdvertisements,
+            CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS * 1000 /* ms */
+        );
+    }
+    eventQueue.post_in(freeButtonBusy, 750 /* ms */);
+}
+
+/**
+ * Raw IRQ handler for the reset button. We don't want to actually do any work here.
+ * Instead, we queue work to happen later using an event queue, by posting a callback.
+ * This has the added avantage of serialising actions, so if the button press happens
+ * during the config->beacon mode transition timeout, the button_task won't happen
+ * until the previous task has finished.
+ *
+ * If your buttons aren't debounced, you should do this in software, or button_task
+ * might get queued multiple times.
+ */
+static void reset_rise(void)
+{
+    if (!buttonBusy) {
+        buttonBusy = true;
+        eventQueue.post(button_task);
+    }
+}
+#endif
+
+static void onBleInitError(BLE::InitializationCompleteCallbackContext* initContext)
+{
+    /* Initialization error handling goes here... */
+    (void) initContext;
+}
+
+
+static void bleInitComplete(BLE::InitializationCompleteCallbackContext* initContext)
+{
+    BLE         &ble  = initContext->ble;
+    ble_error_t error = initContext->error;
+
+    if (error != BLE_ERROR_NONE) {
+        onBleInitError(initContext);
+        return;
+    }
+
+    ble.gap().onDisconnection(disconnectionCallback);
+
+    ble.gap().onConnection(connectionCallback);
+
+    EddystoneService::EddystoneParams_t params;
+    
+    wait_ms(35); // Allow the RNG number generator to collect data
+
+    // Determine if booting directly after re-Flash or not
+    if (loadEddystoneServiceConfigParams(¶ms)) {
+        // 2+ Boot after reflash, so get parms from Persistent Storage
+        eddyServicePtr = new EddystoneService(ble, params, radioTxPowerLevels, eventQueue);
+    } else {
+        // 1st Boot after reflash, so reset everything to defaults
+        /* NOTE: slots are initialized in the constructor from the config.json file */
+        eddyServicePtr = new EddystoneService(ble, advTxPowerLevels, radioTxPowerLevels, eventQueue);
+    }
+
+    // Save Default params in persistent storage ready for next boot event
+    eddyServicePtr->getEddystoneParams(params);
+    saveEddystoneServiceConfigParams(¶ms);
+    // Start the Eddystone Config service - This will never stop (only connectability will change)
+    eddyServicePtr->startEddystoneConfigService();
+
+    /* Start Eddystone config Advertizements (to initialize everything properly) */
+    configLED_on();
+    eddyServicePtr->startEddystoneConfigAdvertisements();
+    handle = eventQueue.post_in(
+        timeoutToStartEddystoneBeaconAdvertisements,
+        CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS * 1000 /* ms */
+    );
+
+   // now shut everything off (used for final beacon that ships w/ battery)
+#ifdef RESET_BUTTON
+   eventQueue.post_in(button_task, 2000 /* ms */);
+#endif
+}
+
+void app_start(int, char *[])
+{
+
+#ifdef NO_LOGGING
+    /* Tell standard C library to not allocate large buffers for these streams */
+    setbuf(stdout, NULL);
+    setbuf(stderr, NULL);
+    setbuf(stdin, NULL);
+#endif
+
+#ifndef NO_4SEC_START_DELAY
+    // delay ~4secs before starting to allow time the nRF51 hardware to settle
+    // Also allows time to attach a virtual terimal to read logging output during init
+    wait_ms(4000);
+#endif
+    
+#ifdef RESET_BUTTON
+    beaconIsOn = 1;             // Booting up, initialize for button handler
+    buttonBusy = false;         // software debouncing of the reset button
+    button.rise(&reset_rise);   // setup reset button
+#endif
+
+    BLE &ble = BLE::Instance();
+    ble.init(bleInitComplete);
+}
+
+#if !defined(YOTTA_CFG_MBED_OS)
+
+void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
+    eventQueue.post(&BLE::processEvents, &context->ble);
+    }
+
+int main() {
+
+    BLE &ble = BLE::Instance();
+    ble.onEventsToProcess(scheduleBleEventsProcessing);
+
+    app_start(0, NULL);
+
+    while (true) {
+       eventQueue.dispatch();
+    }
+
+    return 0;
+}
+
+// *WARNING* HACK
+// avoid unecessary code to be pulled in,
+// should be fixed by mbed-os latter
+extern "C" {
+
+#if defined(TOOLCHAIN_GCC_ARM) || defined(TOOLCHAIN_GCC_CR)
+void exit(int) {
+    while(true) {
+    }
+}
+#endif
+
+int __aeabi_atexit(void *object, void (*dtor)(void* /*this*/), void *handle) {
+    return 0;
+}
+
+int __cxa_atexit(void (*dtor)(void* /*this*/), void *object, void *handle) {
+    return 0;
+}
+
+void __register_exitproc() {
+}
+
+void __call_exitprocs(int, void *f) {
+}
+
+void __cxa_finalize(void *handle) {
+}
+
+}
+
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/source/mbedtls_config.h Mon Sep 19 00:59:11 2016 +0000 @@ -0,0 +1,112 @@ +#ifndef MBEDTLS_EDDYSTONE_CONFIG_H +#define MBEDTLS_EDDYSTONE_CONFIG_H + +/* System support */ +//#define MBEDTLS_HAVE_ASM +#undef MBEDTLS_HAVE_ASM +#define MBEDTLS_HAVE_TIME +#undef MBEDTLS_HAVE_TIME_DATE + +// #define MBEDTLS_CIPHER_MODE_CBC +#undef MBEDTLS_CIPHER_PADDING_PKCS7 +#undef MBEDTLS_REMOVE_ARC4_CIPHERSUITES +#define MBEDTLS_CIPHER_MODE_CTR + +/* mbed TLS feature support */ +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#undef MBEDTLS_ECP_DP_SECP384R1_ENABLED +#define MBEDTLS_ECP_DP_CURVE25519_ENABLED + +#undef MBEDTLS_ECP_NIST_OPTIM +#undef MBEDTLS_ECDSA_DETERMINISTIC +#undef MBEDTLS_KEY_EXCHANGE_PSK_ENABLED +#undef MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED +#undef MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#undef MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#undef MBEDTLS_ERROR_STRERROR_DUMMY +#undef MBEDTLS_PK_RSA_ALT_SUPPORT +#undef MBEDTLS_PKCS1_V15 +#undef MBEDTLS_PKCS1_V21 +#undef MBEDTLS_SELF_TEST +#undef MBEDTLS_SSL_ALL_ALERT_MESSAGES +#undef MBEDTLS_SSL_ENCRYPT_THEN_MAC +#undef MBEDTLS_SSL_EXTENDED_MASTER_SECRET +#undef MBEDTLS_SSL_RENEGOTIATION +#undef MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#undef MBEDTLS_SSL_PROTO_TLS1_2 +#undef MBEDTLS_SSL_PROTO_DTLS +#undef MBEDTLS_SSL_ALPN +#undef MBEDTLS_SSL_DTLS_ANTI_REPLAY +#undef MBEDTLS_SSL_DTLS_HELLO_VERIFY +#undef MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE +#undef MBEDTLS_SSL_DTLS_BADMAC_LIMIT +#undef MBEDTLS_SSL_SESSION_TICKETS +#undef MBEDTLS_SSL_EXPORT_KEYS +#undef MBEDTLS_SSL_SESSION_TICKETS +#undef MBEDTLS_SSL_EXPORT_KEYS +#undef MBEDTLS_SSL_SERVER_NAME_INDICATION +#undef MBEDTLS_VERSION_FEATURES +#undef MBEDTLS_X509_CHECK_KEY_USAGE +#undef MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +/* mbed TLS modules */ +#define MBEDTLS_AES_C +#undef MBEDTLS_ASN1_PARSE_C +#undef MBEDTLS_ASN1_WRITE_C +#undef MBEDTLS_BASE64_C +#define MBEDTLS_BIGNUM_C +#undef MBEDTLS_CCM_C +#undef MBEDTLS_CERTS_C +#undef MBEDTLS_CIPHER_C +#define MBEDTLS_CTR_DRBG_C +#undef MBEDTLS_DEBUG_C +#define MBEDTLS_ECDH_C +#undef MBEDTLS_ECDSA_C +#define MBEDTLS_ECP_C +#define MBEDTLS_ENTROPY_C +#undef MBEDTLS_ERROR_C +#undef MBEDTLS_GCM_C +#undef MBEDTLS_HMAC_DRBG_C +#define MBEDTLS_MD_C +#undef MBEDTLS_OID_C +#undef MBEDTLS_PEM_PARSE_C +#undef MBEDTLS_PK_C +#undef MBEDTLS_PK_PARSE_C +#undef MBEDTLS_PK_WRITE_C +#undef MBEDTLS_PLATFORM_C +#undef MBEDTLS_RSA_C +#define MBEDTLS_SHA256_C +#undef MBEDTLS_SHA512_C +#undef MBEDTLS_SSL_CACHE_C +#undef MBEDTLS_SSL_COOKIE_C +#undef MBEDTLS_SSL_TICKET_C +#undef MBEDTLS_SSL_CLI_C +#undef MBEDTLS_SSL_SRV_C +#undef MBEDTLS_SSL_TLS_C +#undef MBEDTLS_VERSION_C +#undef MBEDTLS_X509_USE_C +#undef MBEDTLS_X509_CRT_PARSE_C +#undef MBEDTLS_X509_CRL_PARSE_C + +/* Save RAM at the expense of ROM */ +#define MBEDTLS_AES_ROM_TABLES + +/* Save RAM by adjusting to our exact needs */ +#define MBEDTLS_ECP_MAX_BITS 256 +#define MBEDTLS_MPI_MAX_SIZE 32 + +/* Save RAM at the expense of speed, see ecp.h */ +#define MBEDTLS_ECP_WINDOW_SIZE 2 +#define MBEDTLS_ECP_FIXED_POINT_OPTIM 0 + +/* Significant speed benefit at the expense of some ROM */ +#define MBEDTLS_ECP_NIST_OPTIM +/* +* You should adjust this to the exact number of sources you're using: default +* is the "mbedtls_platform_entropy_poll" source, but you may want to add other ones. +* Minimum is 2 for the entropy test suite. +*/ +#define MBEDTLS_ENTROPY_MAX_SOURCES 2 +#define MBEDTLS_NO_PLATFORM_ENTROPY + +#endif /* MBEDTLS_EDDYSTONE_CONFIG_H */