Sarah Marsh / Mbed OS EddystoneBeacon

Files at this revision

API Documentation at this revision

Comitter:
sarahmarshy
Date:
Tue Nov 29 06:29:10 2016 +0000
Commit message:
Initial commit

Changed in this revision

LICENSE Show annotated file Show diff for this revision Revisions of this file
README.md Show annotated file Show diff for this revision Revisions of this file
config.json Show annotated file Show diff for this revision Revisions of this file
img/app_start.png Show annotated file Show diff for this revision Revisions of this file
img/edit_url.png Show annotated file Show diff for this revision Revisions of this file
img/open_configuration.png Show annotated file Show diff for this revision Revisions of this file
img/result.png Show annotated file Show diff for this revision Revisions of this file
img/save_url.png Show annotated file Show diff for this revision Revisions of this file
mbed-os.lib Show annotated file Show diff for this revision Revisions of this file
mbed_app.json Show annotated file Show diff for this revision Revisions of this file
readme.md Show annotated file Show diff for this revision Revisions of this file
source/EIDFrame.cpp Show annotated file Show diff for this revision Revisions of this file
source/EIDFrame.h Show annotated file Show diff for this revision Revisions of this file
source/EddystoneService.cpp Show annotated file Show diff for this revision Revisions of this file
source/EddystoneService.h Show annotated file Show diff for this revision Revisions of this file
source/EddystoneTypes.h Show annotated file Show diff for this revision Revisions of this file
source/Eddystone_config.h Show annotated file Show diff for this revision Revisions of this file
source/EntropySource/EntropySource.cpp Show annotated file Show diff for this revision Revisions of this file
source/EntropySource/EntropySource.h Show annotated file Show diff for this revision Revisions of this file
source/EntropySource/nRFEntropySource/nRFEntropySource.cpp Show annotated file Show diff for this revision Revisions of this file
source/EventQueue/AlignedStorage.h Show annotated file Show diff for this revision Revisions of this file
source/EventQueue/EventQueue.h Show annotated file Show diff for this revision Revisions of this file
source/EventQueue/EventQueueClassic.h Show annotated file Show diff for this revision Revisions of this file
source/EventQueue/EventQueueMinar.h Show annotated file Show diff for this revision Revisions of this file
source/EventQueue/MakeThunk.h Show annotated file Show diff for this revision Revisions of this file
source/EventQueue/PriorityQueue.h Show annotated file Show diff for this revision Revisions of this file
source/EventQueue/Thunk.h Show annotated file Show diff for this revision Revisions of this file
source/EventQueue/detail/FunctionAdaptor.h Show annotated file Show diff for this revision Revisions of this file
source/EventQueue/detail/MemberFunctionAdaptor.h Show annotated file Show diff for this revision Revisions of this file
source/EventQueue/detail/Thunk.impl.h Show annotated file Show diff for this revision Revisions of this file
source/EventQueue/detail/ThunkVTable.h Show annotated file Show diff for this revision Revisions of this file
source/EventQueue/detail/ThunkVTableGenerator.h Show annotated file Show diff for this revision Revisions of this file
source/EventQueue/detail/Thunks.h Show annotated file Show diff for this revision Revisions of this file
source/EventQueue/util/CriticalSectionLock.h Show annotated file Show diff for this revision Revisions of this file
source/PersistentStorageHelper/ConfigParamsPersistence.cpp Show annotated file Show diff for this revision Revisions of this file
source/PersistentStorageHelper/ConfigParamsPersistence.h Show annotated file Show diff for this revision Revisions of this file
source/PersistentStorageHelper/nrfPersistentStorageHelper/nrfConfigParamsPersistence.cpp Show annotated file Show diff for this revision Revisions of this file
source/TLMFrame.cpp Show annotated file Show diff for this revision Revisions of this file
source/TLMFrame.h Show annotated file Show diff for this revision Revisions of this file
source/UIDFrame.cpp Show annotated file Show diff for this revision Revisions of this file
source/UIDFrame.h Show annotated file Show diff for this revision Revisions of this file
source/URLFrame.cpp Show annotated file Show diff for this revision Revisions of this file
source/URLFrame.h Show annotated file Show diff for this revision Revisions of this file
source/aes_eax.cpp Show annotated file Show diff for this revision Revisions of this file
source/aes_eax.h Show annotated file Show diff for this revision Revisions of this file
source/main.cpp Show annotated file Show diff for this revision Revisions of this file
source/mbedtls_config.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LICENSE	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 2016 +0000
@@ -0,0 +1,1 @@
+https://github.com/ARMmbed/mbed-os/#aeabcc947294f2a6cbe1e808c030779c7c460f10
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed_app.json	Tue Nov 29 06:29:10 2016 +0000
@@ -0,0 +1,12 @@
+{
+    "macros": [
+        "NDEBUG=1",
+        "MBEDTLS_USER_CONFIG_FILE=\"mbedtls_config.h\"",
+        "OS_MAINSTKSIZE=1024"
+    ], 
+    "target_overrides": {
+            "*": {
+                    "platform.stdio-flush-at-exit": false
+            }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/readme.md	Tue Nov 29 06:29:10 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.
+
+    ![](img/app_start.png)
+
+    **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.
+
+    ![](img/open_configuration.png)
+
+    **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.
+
+    ![](img/edit_url.png)
+
+    **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.
+
+    ![](img/save_url.png)
+
+    **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.
+
+    ![](img/result.png)
+
+    **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	Tue Nov 29 06:29:10 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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EIDFrame.h	Tue Nov 29 06:29:10 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 (internally represented 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	Tue Nov 29 06:29:10 2016 +0000
@@ -0,0 +1,1331 @@
+/* 
+ * Copyright (c) 2006-2016 Google Inc, All Rights Reserved
+ *
+ * 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 "PersistentStorageHelper/ConfigParamsPersistence.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
+    LOG(("1st BOOT: "));
+    doFactoryReset();  // includes genBeaconKeys
+    
+    LOG(("After FactoryReset: 1st Boot Init: genBeaconKeyRC=%d\r\n", genBeaconKeyRC));
+
+    /* 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   &paramsIn,
+                                   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));
+    // Init time Params
+    LOG(("Init Params\r\n"));
+    timeSinceBootTimer.start();
+    memcpy(&timeParams, &(paramsIn.timeParams), sizeof(TimeParams_t));
+    LOG(("2nd Boot: Time:"));
+    LOG(("PriorBoots=%lu, SinceBoot=%lu\r\n", timeParams.timeInPriorBoots, timeParams.timeSinceLastBoot));
+    timeParams.timeInPriorBoots = timeParams.timeInPriorBoots + timeParams.timeSinceLastBoot;
+    timeParams.timeSinceLastBoot =  getTimeSinceLastBootMs() / 1000;
+    nvmSaveTimeParams();
+    
+    // Init gneeral params
+    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));
+    // Zero next EID slot rotation times to enforce rotation of each slot on restart
+    memset(slotEidNextRotationTimes, 0, sizeof(SlotEidNextRotationTimes_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:
+               nextEidSlot = slot;
+               eidFrame.setData(frame, slotAdvTxPowerLevels[slot], nullEid);
+               eidFrame.update(frame, slotEidIdentityKeys[slot], slotEidRotationPeriodExps[slot], getTimeSinceFirstBootSecs());
+               break;
+        }
+    }
+    
+    /* 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)
+{    
+    // Init Time tracking
+    timeSinceBootTimer.start();
+    timeParams.timeInPriorBoots = 0;
+    timeParams.timeSinceLastBoot = getTimeSinceLastBootMs() / 1000;
+    nvmSaveTimeParams();
+    // Init callbacks
+    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], getTimeSinceFirstBootSecs());
+               }
+               break;
+            case EDDYSTONE_FRAME_EID:
+               nextEidSlot = slot;
+               eidFrame.setData(frame, slotAdvTxPowerLevels[slot], nullEid);
+               eidFrame.update(frame, slotEidIdentityKeys[slot], slotEidRotationPeriodExps[slot], getTimeSinceFirstBootSecs());
+               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 &params)
+{
+    // Time
+    timeParams.timeSinceLastBoot =  getTimeSinceLastBootMs() / 1000;
+    memcpy(&(params.timeParams),     &timeParams,         sizeof(TimeParams_t));
+    // 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 = getTimeSinceFirstBootSecs();
+    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]);
+                // select a new random MAC address so the beacon is not trackable 
+                setRandomMacAddress(); 
+                // Store in NVM in case the beacon loses power
+                nvmSaveTimeParams(); 
+                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.updateTimeSinceLastBoot(getTimeSinceLastBootMs());
+    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], getTimeSinceFirstBootSecs());
+        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;
+    uint64_t  startTimeManageRadio = getTimeSinceLastBootMs();
+
+    /* 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() - (getTimeSinceLastBootMs() - 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 */
+    // Add the Flags param
+    ble.gap().accumulateAdvertisingPayload(
+        GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE
+    );
+#ifdef INCLUDE_CONFIG_URL
+    // Add the Eddystone 16-bit Service ID
+    ble.gap().accumulateAdvertisingPayload(
+        GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, 
+        EDDYSTONE_UUID, 
+        sizeof(EDDYSTONE_UUID)
+    );
+#endif
+    /* 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)
+    );
+    // Add Generic Appearance Tag
+    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();
+    // Add LOCAL NAME (indicating the Eddystone Version)
+    ble.gap().accumulateScanResponse(
+        GapAdvertisingData::COMPLETE_LOCAL_NAME,
+        reinterpret_cast<const uint8_t *>(deviceName),
+        strlen(deviceName)
+    );
+#ifdef INCLUDE_CONFIG_URL 
+    // Add SERVICE DATA for a PhyWeb Config URL
+    uint8_t configFrame[URLFrame::ENCODED_BUF_SIZE];
+    int encodedUrlLen = URLFrame::encodeURL(configFrame + CONFIG_FRAME_HDR_LEN, EDDYSTONE_CONFIG_URL);
+    uint8_t advPower = advTxPowerLevels[sizeof(PowerLevels_t)-1] & 0xFF;
+    uint8_t configFrameHdr[CONFIG_FRAME_HDR_LEN] = {0, 0, URLFrame::FRAME_TYPE_URL, advPower};
+    // ++ Fill in the Eddystone Service UUID in the HDR
+    memcpy(configFrameHdr, EDDYSTONE_UUID, sizeof(EDDYSTONE_UUID));
+    // ++ Copy the HDR to the config frame 
+    memcpy(configFrame, configFrameHdr, CONFIG_FRAME_HDR_LEN);
+    ble.gap().accumulateScanResponse(
+        GapAdvertisingData::SERVICE_DATA,
+        configFrame,
+        CONFIG_FRAME_HDR_LEN + encodedUrlLen
+    );
+#else
+    // Add TRANSMIT POWER
+    ble.gap().accumulateScanResponse(
+    GapAdvertisingData::TX_POWER_LEVEL,
+    reinterpret_cast<uint8_t *>(&advTxPowerLevels[sizeof(PowerLevels_t)-1]),
+    sizeof(uint8_t)
+    );
+#endif
+}
+
+/* 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->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 = getTimeSinceFirstBootSecs();
+                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(S)=%lu\r\n", getTimeSinceFirstBootSecs() ));
+                        tlmFrame.encryptData(frame, slotEidIdentityKeys[slot], slotEidRotationPeriodExps[slot], getTimeSinceFirstBootSecs() );
+                    }
+                    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 EID ADV frame packet 
+                eidFrame.setData(frame, advTxPower, nullEid);
+                // Fill in the correct EID Value from the Identity Key/exp/clock
+                eidFrame.update(frame, slotEidIdentityKeys[activeSlot], slotEidRotationPeriodExps[activeSlot], getTimeSinceFirstBootSecs() );
+                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] << 4; // Converting the enum to an actual frame type
+    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(getTimeSinceLastBootMs());
+    for (i = 0; i < size; i++) {
+        ain[i] = rand() % 256;
+    }
+    return;
+}
+#endif
+
+/** 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;
+}
+
+bool EddystoneService::isLocked(void) {
+    if (lockState == LOCKED) {
+	return true;
+    } else {
+	return false;
+    }
+}
+
+/**
+ * Time : Stable Storage
+ */
+
+/**
+ * Returns the time since FIRST Boot (Time in Prior Boots + Time since Last Boot) in SECONDS
+ */
+uint32_t EddystoneService::getTimeSinceFirstBootSecs(void) {
+    timeParams.timeSinceLastBoot = getTimeSinceLastBootMs() / 1000;
+    uint32_t totalTimeSinceFirstBoot = timeParams.timeSinceLastBoot + timeParams.timeInPriorBoots;
+    // Timer Overflow condition = 136 years (32 bits in seconds) so no need for wrap check
+    return totalTimeSinceFirstBoot;
+}
+
+/**
+ * Returns the time since last boot in MILLISECONDS
+ * NOTE: This solution is needed as a stopgap until the Timer API is updated to 64-bit
+ */
+uint64_t EddystoneService::getTimeSinceLastBootMs(void) {
+    static uint64_t time64bit = 0;
+    time64bit += timeSinceBootTimer.read_ms();
+    timeSinceBootTimer.reset();
+    return time64bit;
+}
+
+/**
+ * Store only the time params in Pstorage(e.g. NVM), to maintain time between boots
+ * NOTE: Platform-specific implementation for persistence on the nRF5x. Based on the
+ * pstorage module provided by the Nordic SDK. 
+ */
+void EddystoneService::nvmSaveTimeParams(void) {
+    LOG(("Time NVM: "));
+    LOG(("PriorBoots=%lu, SinceBoot=%lu\r\n", timeParams.timeInPriorBoots, timeParams.timeSinceLastBoot));
+    saveEddystoneTimeParams(&timeParams);
+}
+
+/*
+ * Establish constant arrays
+ */
+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::nullEid[8] = {0,0,0,0,0,0,0,0};
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/EddystoneService.h	Tue Nov 29 06:29:10 2016 +0000
@@ -0,0 +1,1198 @@
+/* 
+ * Copyright (c) 2006-2016 Google Inc, All Rights Reserved
+ *
+ * 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"
+// #include "PersistentStorageHelper/ConfigParamsPersistence.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"
+#include "pstorage_platform.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 {
+        /**
+         * 
+         */
+        TimeParams_t            timeParams;
+        /**
+         * 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 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   &paramsIn,
+                     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 &params);
+
+    /**
+     * 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();
+
+    /**
+     * Tests if the beacon is locked or not
+     *
+     * @return bool
+     */
+    bool isLocked();
+    
+    /**
+     * 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;
+    
+    static const uint8_t CONFIG_FRAME_HDR_LEN = 4;
+     
+    /**
+     * 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);
+    
+    /**
+     * Returns the current time in Secs (Prior Time + Time since boot)
+     *
+     * @return time
+     */
+    uint32_t getTimeSinceFirstBootSecs(void);
+    
+
+    /**
+     * Returns the time since boot in Milliseconds
+     *
+     * @return time
+     */
+    static uint64_t getTimeSinceLastBootMs(void);
+    
+    /**
+     * Saves only the Time Params in pStorage (a subset of all the Eddsytone Params)
+     * This is more efficient than periodically saving all state (its just 8 bytes)
+     */
+    void nvmSaveTimeParams(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;
+    
+    /**
+     * Parameter to consistently record the return code when generating Beacon Keys
+     */
+    int                                                             genBeaconKeyRC;
+    
+    /**
+     * Keeps track of time in prior boots and current/last boot
+     */
+    TimeParams_t                                                    timeParams;
+
+    /**
+     * 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 nullEid[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	Tue Nov 29 06:29:10 2016 +0000
@@ -0,0 +1,239 @@
+/* 
+ * Copyright (c) 2006-2016 Google Inc, All Rights Reserved
+ *
+ * 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);
+
+// END OF PROTOTYPES
+
+typedef struct {
+    uint32_t timeInPriorBoots;
+    uint32_t timeSinceLastBoot;
+} TimeParams_t;
+
+#endif /* __EDDYSTONETYPES_H__ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/Eddystone_config.h	Tue Nov 29 06:29:10 2016 +0000
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2016, Google, 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_
+
+// Version printed out on virtual terminal (independent of logging flag below)
+#define BUILD_VERSION_STR "EID Version 1.00 2016-11-19:15:00\r\n"
+
+/**
+ * Platform Target (if not set, default is nRF51-DK or nRF51-dongle or nRF52-DK)
+ * NOTE1: All targets are assumed to be 32K (in target.json) and S110 (in config.h)
+ * NOTE2: Only enable one target below (default is nRF_DK).
+ */
+// #define MinewTech51
+#define MinewTech52
+// #define nRF_DK
+
+/**
+ * DECLARE YOUR TARGET'S PARAMETERS
+ * If you are adding a new target, append to end of elif chain
+ * 
+ * LED_OFF: value for an LED off state: 1 or 0
+ * CONFIG_LED: which LED to blink when in Configuration Mode
+ *     On power up will go into configuration mode and eventually time out
+ * SHUTDOWN_LED: which LED to blink when shutting down (only used if RESET_BUTTON is defined)
+ * RESET_BUTTON: Which button to use. If defined, adds code to handle button presses
+ *     Button press will toggle between configuration mode and off
+ *     Configuration mode will eventually timeout and broadcast default values
+ *     This will shutdown after initial power up! Assumes shipping with a battery in an off state
+ * EDDYSTONE_DEFAULT_RADIO_TX_POWER_LEVELS: Which power levels to offer
+ * EDDYSTONE_DEFAULT_ADV_TX_POWER_LEVELS: What to advertise these levels (as antennas always loose some power) 
+ */
+#ifdef MinewTech51
+  #define LED_OFF 0
+  #define CONFIG_LED p15
+  #define SHUTDOWN_LED p16
+  #define RESET_BUTTON p18
+  #define EDDYSTONE_DEFAULT_RADIO_TX_POWER_LEVELS { -30, -16, -4, 4 }
+  #define EDDYSTONE_DEFAULT_ADV_TX_POWER_LEVELS { -42, -30, -25, -13 }  
+
+#elif defined MinewTech52
+  #define LED_OFF 0
+  #define CONFIG_LED LED3
+  #define SHUTDOWN_LED LED2
+  #define RESET_BUTTON BUTTON1
+  #define EDDYSTONE_DEFAULT_RADIO_TX_POWER_LEVELS { -40, -20, -8, 4 }
+  #define EDDYSTONE_DEFAULT_ADV_TX_POWER_LEVELS { -50, -30, -18, -6 }
+
+#else
+  // *** nRF_DK or USB Dongle PIN defines ***
+  #define LED_OFF 1
+  #define CONFIG_LED LED3
+  // Uncomment the defines below if you want the DK board to behave like a
+  // Beacon target with shutdown on power up, and a mode button
+  // #define SHUTDOWN_LED LED2
+  // #define RESET_BUTTON BUTTON1
+  #define EDDYSTONE_DEFAULT_RADIO_TX_POWER_LEVELS { -30, -16, -4, 4 }
+  #define EDDYSTONE_DEFAULT_ADV_TX_POWER_LEVELS { -42, -30, -25, -13 } 
+#endif
+
+/** 
+ * DEBUG OPTIONS
+ * For production: all defines below should be UNCOMMENTED:
+ * Key
+ *   GEN_BEACON_KEYS_AT_INIT:  Debugging flag to help test entropy source
+ *   HARDWARE_RANDOM_NUM_GENERATOR: include if the target supports a hardware RNG
+ *   EID_RANDOM_MAC: include if you want to randomize the mac address for each eid rotation
+ *   INCLUDE_CONFIG_URL: Includes configuration url when in Configuration Mode
+ *   DONT_REMAIN_CONNECTABLE: Debugging flag; remain connectable during beaconing for easy testing
+ *   NO_4SEC_START_DELAY: Debugging flag to pause 4s before starting; allow time to connect virtual terminal
+ *   NO_EAX_TEST: Debugging flag: when not define, test will check x = EAX_DECRYPT(EAX_ENCRYPT(x)), output in LOG
+ *   NO_LOGGING: Debugging flag; controls logging to virtual terminal
+ */ 
+#define GEN_BEACON_KEYS_AT_INIT
+#define HARDWARE_RANDOM_NUM_GENERATOR
+#define EID_RANDOM_MAC
+#define INCLUDE_CONFIG_URL
+#define DONT_REMAIN_CONNECTABLE
+#define NO_4SEC_START_DELAY
+#define NO_EAX_TEST
+#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)
+
+/**
+ * GENERIC BEACON BEHAVIORS DEFINED
+ * Note: If the CONFIG_URL is enabled (DEFINE above)
+ *    The size of the DEVICE_NAME + Encoded Length of the CONFIG_URL
+ *    must be LESS THAN OR EQUAL to 23
+ */
+#define EDDYSTONE_CONFIG_URL "http://c.pw3b.com"
+#define EDDYSTONE_CFG_DEFAULT_DEVICE_NAME "Eddystone v3.0"
+#define EDDYSTONE_DEFAULT_MAX_ADV_SLOTS 3
+#define EDDYSTONE_DEFAULT_CONFIG_ADV_INTERVAL 1000
+#define EDDYSTONE_DEFAULT_CONFIG_ADVERTISEMENT_TIMEOUT_SECONDS 60
+
+#define EDDYSTONE_DEFAULT_UNLOCK_KEY { \
+    0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF \
+}
+
+#define EDDYSTONE_DEFAULT_SLOT_URLS { \
+    "http://c.pw3b.com", \
+    "https://www.mbed.com/", \
+    "https://www.github.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 { 10, 10, 10 }
+
+// The following frame/slot types are supported: URL, UID, TLM, EID. The defaults set URL x2 and EID
+#define EDDYSTONE_DEFAULT_SLOT_TYPES { \
+    EDDYSTONE_FRAME_URL, \
+    EDDYSTONE_FRAME_URL, \
+    EDDYSTONE_FRAME_EID \
+}
+
+#define EDDYSTONE_DEFAULT_SLOT_INTERVALS { 700, 0, 0 }
+
+#define EDDYSTONE_DEFAULT_SLOT_TX_POWERS { -8, -8, -8 }
+
+/**
+ * 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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 2016 +0000
@@ -0,0 +1,251 @@
+/*
+ * 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"
+
+#include <util/CriticalSectionLock.h>
+typedef ::mbed::util::CriticalSectionLock CriticalSection;
+
+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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 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/PersistentStorageHelper/ConfigParamsPersistence.cpp	Tue Nov 29 06:29:10 2016 +0000
@@ -0,0 +1,55 @@
+/* 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"
+
+#if !defined(TARGET_NRF51822) && !defined(TARGET_NRF52832) /* 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;
+    }
+
+    void saveEddystoneTimeParams(const TimeParams_t *timeP)
+    {
+        /* Avoid compiler warnings */
+        (void) timeP;
+
+        /* Do nothing... */
+        return;
+    }
+
+#endif /* #ifdef TARGET_NRF51822 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/PersistentStorageHelper/ConfigParamsPersistence.h	Tue Nov 29 06:29:10 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.
+ */
+
+#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);
+
+/**
+ * Generic API to store the Eddystone TimeParams (a subset of Config Params) for 
+ * speed/power efficiency.
+ *
+ * @param[in,out] timeP
+ *                    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 saveEddystoneTimeParams(const TimeParams_t *timeP);
+
+#endif /* #ifndef __BLE_CONFIG_PARAMS_PERSISTENCE_H__*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/PersistentStorageHelper/nrfPersistentStorageHelper/nrfConfigParamsPersistence.cpp	Tue Nov 29 06:29:10 2016 +0000
@@ -0,0 +1,140 @@
+/* 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.
+ */
+
+#if defined(TARGET_NRF51822) || defined(TARGET_NRF52832) /* Persistent storage supported on nrf51 platforms */
+
+extern "C" {
+    #include "pstorage.h"
+}
+
+#include "nrf_error.h"
+#include "../../EddystoneService.h"
+#include <cstddef>
+
+/**
+ * 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 */);
+    }
+}
+
+/* Saves only the TimeParams (a subset of Config Params) for speed/power efficiency
+ * Platform-specific implementation for persistence on the nRF5x. Based on the
+ * pstorage module provided by the Nordic SDK. */
+void saveEddystoneTimeParams(const TimeParams_t *timeP)
+{
+    // Copy the time params object to the main datastructure
+    memcpy(&persistentParams.params.timeParams, timeP, sizeof(TimeParams_t));
+    // Test if this is the first pstorage update, or an update
+    if (persistentParams.persistenceSignature != PersistentParams_t::MAGIC) {
+        persistentParams.persistenceSignature = PersistentParams_t::MAGIC;
+        pstorage_store(&pstorageHandle,
+                       reinterpret_cast<uint8_t *>(&persistentParams),
+                       sizeof(TimeParams_t),
+                       offsetof(PersistentParams_t, params.timeParams) /* offset */);  
+    } else {
+        pstorage_update(&pstorageHandle,
+                        reinterpret_cast<uint8_t *>(&persistentParams),
+                        sizeof(TimeParams_t),
+                        offsetof(PersistentParams_t, params.timeParams) /* offset */); 
+    }
+}
+
+#endif /* #ifdef TARGET_NRF51822 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/TLMFrame.cpp	Tue Nov 29 06:29:10 2016 +0000
@@ -0,0 +1,196 @@
+/* 
+ * Copyright (c) 2006-2016 Google Inc, All Rights Reserved
+ *
+ * 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) {
+    // 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(("ETLM Encoder 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);
+
+#ifndef NO_EAX_TEST
+    // Part of test code to confirm x == EAX_DECRYPT( EAX_ENCRYPT(x) )
+    uint8_t newinput[ETLM_DATA_LEN];
+    memcpy(newinput, output, ETLM_DATA_LEN);
+#endif
+
+    // 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);
+        
+#ifndef NO_EAX_TEST
+    // Perform test to confirm x == EAX_DECRYPT( EAX_ENCRYPT(x) )
+    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, newinput + MIC_OFFSET, MIC_LEN);
+    LOG(("ETLM Decoder OUTPUT ret=%d buf=\r\n", ret)); EddystoneService::logPrintHex(buf, 12);
+#endif
+        
+    // 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::updateTimeSinceLastBoot(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	Tue Nov 29 06:29:10 2016 +0000
@@ -0,0 +1,276 @@
+/* 
+ * Copyright (c) 2006-2016 Google Inc, All Rights Reserved
+ *
+ * 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 last boot.
+     *
+     * @param[in] nowInMillis
+     *              The time since boot in milliseconds.
+     */
+    void updateTimeSinceLastBoot(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	Tue Nov 29 06:29:10 2016 +0000
@@ -0,0 +1,69 @@
+/* 
+ * Copyright (c) 2006-2016 Google Inc, All Rights Reserved
+ *
+ * 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	Tue Nov 29 06:29:10 2016 +0000
@@ -0,0 +1,156 @@
+/* 
+ * Copyright (c) 2006-2016 Google Inc, All Rights Reserved
+ *
+ * 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	Tue Nov 29 06:29:10 2016 +0000
@@ -0,0 +1,155 @@
+/* 
+ * Copyright (c) 2006-2016 Google Inc, All Rights Reserved
+ *
+ * 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 *);
+
+    /*
+     * Fill with one more 0 than max url data size to ensure its null terminated
+     * And can be printed out for debug purposes
+     */ 
+    memset(encodedUrl, 0, MAX_URL_DATA + 1);
+
+    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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/URLFrame.h	Tue Nov 29 06:29:10 2016 +0000
@@ -0,0 +1,185 @@
+/* 
+ * Copyright (c) 2006-2016 Google Inc, All Rights Reserved
+ *
+ * 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);
+
+    /**
+     * 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
+     */
+    static uint8_t encodeURL(uint8_t* encodedUrlData, const char* rawUrl);
+
+    /**
+     * The max size (in bytes) of an Eddystone-URL frame.
+     */
+    static const uint8_t ENCODED_BUF_SIZE = 32;
+    /**
+     *  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;
+
+    /**
+     * The minimum size (in bytes) of an Eddystone-URL frame.
+     */
+    static const uint8_t FRAME_MIN_SIZE_URL = 2;
+    
+    /**
+    * 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	Tue Nov 29 06:29:10 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 "mbedtls/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	Tue Nov 29 06:29:10 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	Tue Nov 29 06:29:10 2016 +0000
@@ -0,0 +1,289 @@
+/* 
+ * Copyright (c) 2006-2016 Google Inc, All Rights Reserved
+ *
+ * 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"
+
+#if (defined(NRF51) || defined(NRF52))
+    #include "nrf_soc.h"
+#endif
+
+// 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(&params);
+    // 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 bool beaconIsOn = true;   // Button handler boolean to switch on or off
+static bool 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) {
+    bool locked = eddyServicePtr->isLocked();
+
+    // only shutdown if ON and unlocked
+    if (beaconIsOn && !locked) {
+	eventQueue.cancel(handle);   // kill any pending callback tasks
+	beaconIsOn = false;
+	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);
+    // only go into configMode if OFF or locked and not in configMode
+    } else if (!beaconIsOn || (locked && BlinkyHandle == NULL)) {
+	eventQueue.cancel(handle); // kill any pending callback tasks
+        beaconIsOn = true;
+        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(&params)) {
+        // 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(&params);
+    // 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 */
+    );
+
+#if (defined(NRF51) || defined(NRF52))
+	sd_power_dcdc_mode_set(NRF_POWER_DCDC_ENABLE);	// set the DCDC mode for the Nordic chip to lower power consumption
+#endif
+	
+   // 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 = true;             // 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();
+       sleep();
+    }
+
+    return 0;
+}
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/mbedtls_config.h	Tue Nov 29 06:29:10 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
+#define MBEDTLS_CIPHER_MODE_CTR
+#undef  MBEDTLS_CIPHER_PADDING_PKCS7
+#undef  MBEDTLS_REMOVE_ARC4_CIPHERSUITES
+
+/* 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 */