Openwear requires RC oscillator to be used

Fork of nRF51822 by Nordic Semiconductor

Files at this revision

API Documentation at this revision

Comitter:
Rohit Grover
Date:
Tue Sep 02 15:50:05 2014 +0100
Parent:
53:1e5c300cec7f
Child:
57:2aa01a5008ac
Commit message:
Release 0.1.0
=============

We've achieved significant gains in power consumption: the BLE_Beacon demo now
runs at around 35uA of average current broadcasting once a second at 0dB; when
not using the radio, this demo consumes around 7uA.

Features
~~~~~~~~

- Replace initialization of high-frequency external crystal clock-source with
the use of low-frequency clock. This brings in significant gains in power
consumption.

- Re-implement the micro-second timer on nRF51 using the app_timer module
(which internally uses RTC). This limits the precision of the us_Timer to
30uS; but brings in significant gains in power consumption.

- Reduce the number of available app_timers and the event depths for app-timer
events; this will reduce memory consumption for zero-initialized data by
around 1K.

- Remove the call to conn_params_init() at startup. This is not mandatory; and
was causing an unnecessary re-negotiation of connection parameters a few
seconds into every connection.

- Reduce default transmission power level to 0dbB (was 4dbB before).

- Reduce min connection interval to 50ms and max to 500ms (previous values
were much larger).

- Replace a few instances of use of wait() with nrf_delay_us().

- onConnection() callback now receives connection-parameters applicable to the
new connection.

- onDataSent() callback now receives a count parameter containing the number of
times notifications were sent out since the last callback.

- A 'reason' parameter has been added to Gap::disconnect() to indicate the
reason for disconnection; and also to the onDisconnection callback to
receive a reason from the remote host.

- disable the app_gpiote module by default.

Bugfixes
~~~~~~~~

- onDataWritten() callback now passes an additional parameter
(GattServer::WriteEventCallback_t) encapsulating the update. This avoids
having to re-fetch the updated characteristic's value attribute. It also
fixes a bug where multiple updates to the characteristic's value-attribute
could get clobbered if they occurred in quick succession before the
callbacks could be processed.


Compatibility
~~~~~~~~~~~~~

Compatible with revision 0.1.0 of the BLE_API.

Changed in this revision

btle/btle.cpp Show annotated file Show diff for this revision Revisions of this file
btle/btle_gap.cpp Show annotated file Show diff for this revision Revisions of this file
btle/custom/custom_helper.cpp Show annotated file Show diff for this revision Revisions of this file
nRF51822n.cpp Show annotated file Show diff for this revision Revisions of this file
nRF51Gap.cpp Show annotated file Show diff for this revision Revisions of this file
nRF51Gap.h Show annotated file Show diff for this revision Revisions of this file
nRF51GattServer.cpp Show annotated file Show diff for this revision Revisions of this file
nRF51GattServer.h Show annotated file Show diff for this revision Revisions of this file
nordic/app_common/app_button.c Show annotated file Show diff for this revision Revisions of this file
nordic/app_common/app_gpiote.c Show annotated file Show diff for this revision Revisions of this file
nordic/app_common/app_timer.cpp Show annotated file Show diff for this revision Revisions of this file
nordic/app_common/pstorage.cpp Show annotated file Show diff for this revision Revisions of this file
nordic/nrf-sdk/app_common/app_timer.h Show annotated file Show diff for this revision Revisions of this file
nordic/nrf-sdk/s110/ble.h Show annotated file Show diff for this revision Revisions of this file
nordic/nrf-sdk/s110/ble_hci.h Show annotated file Show diff for this revision Revisions of this file
nordic/nrf-sdk/sd_common/softdevice_handler.h Show annotated file Show diff for this revision Revisions of this file
nordic/softdevice_handler.cpp Show annotated file Show diff for this revision Revisions of this file
projectconfig.h Show annotated file Show diff for this revision Revisions of this file
--- a/btle/btle.cpp	Fri Jul 25 10:33:52 2014 +0100
+++ b/btle/btle.cpp	Tue Sep 02 15:50:05 2014 +0100
@@ -39,13 +39,13 @@
 #include "nRF51Gap.h"
 #include "nRF51GattServer.h"
 
+#include "ble_hci.h"
+
 #if NEED_BOND_MANAGER /* disabled by default */
 static void service_error_callback(uint32_t nrf_error);
 #endif
-extern "C" void        assert_nrf_callback(uint16_t line_num, const uint8_t *p_file_name);
-void        app_error_handler(uint32_t       error_code,
-                              uint32_t       line_num,
-                              const uint8_t *p_file_name);
+extern "C" void assert_nrf_callback(uint16_t line_num, const uint8_t *p_file_name);
+void            app_error_handler(uint32_t error_code, uint32_t line_num, const uint8_t *p_file_name);
 
 #if NEED_BOND_MANAGER /* disabled by default */
 static error_t bond_manager_init(void);
@@ -62,8 +62,40 @@
 
 error_t btle_init(void)
 {
-    APP_TIMER_INIT(0, 8, 5, false);
-    SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, false);
+    const bool useScheduler = false;
+    SOFTDEVICE_HANDLER_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, useScheduler);
+
+    // Enable BLE stack
+    /**
+     * Using this call, the application can select whether to include the
+     * Service Changed characteristic in the GATT Server. The default in all
+     * previous releases has been to include the Service Changed characteristic,
+     * but this affects how GATT clients behave. Specifically, it requires
+     * clients to subscribe to this attribute and not to cache attribute handles
+     * between connections unless the devices are bonded. If the application
+     * does not need to change the structure of the GATT server attributes at
+     * runtime this adds unnecessary complexity to the interaction with peer
+     * clients. If the SoftDevice is enabled with the Service Changed
+     * Characteristics turned off, then clients are allowed to cache attribute
+     * handles making applications simpler on both sides.
+     */
+    static const bool IS_SRVC_CHANGED_CHARACT_PRESENT = false;
+    ble_enable_params_t enableParams = {
+        .gatts_enable_params = {
+            .service_changed = IS_SRVC_CHANGED_CHARACT_PRESENT
+        }
+    };
+    if (sd_ble_enable(&enableParams) != NRF_SUCCESS) {
+        return ERROR_INVALID_PARAM;
+    }
+
+    ble_gap_addr_t addr;
+    if (sd_ble_gap_address_get(&addr) != NRF_SUCCESS) {
+        return ERROR_INVALID_PARAM;
+    }
+    if (sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &addr) != NRF_SUCCESS) {
+        return ERROR_INVALID_PARAM;
+    }
 
     ASSERT_STATUS( softdevice_ble_evt_handler_set(btle_handler));
     ASSERT_STATUS( softdevice_sys_evt_handler_set(sys_evt_dispatch));
@@ -82,14 +114,17 @@
 #if NEED_BOND_MANAGER /* disabled by default */
     ble_bondmngr_on_ble_evt(p_ble_evt);
 #endif
+#if SDK_CONN_PARAMS_MODULE_ENABLE
     ble_conn_params_on_ble_evt(p_ble_evt);
+#endif
 
     /* Custom event handler */
     switch (p_ble_evt->header.evt_id) {
         case BLE_GAP_EVT_CONNECTED: {
             Gap::Handle_t handle = p_ble_evt->evt.gap_evt.conn_handle;
             nRF51Gap::getInstance().setConnectionHandle(handle);
-            nRF51Gap::getInstance().processHandleSpecificEvent(GapEvents::GAP_EVENT_CONNECTED, handle);
+            const Gap::ConnectionParams_t *params = reinterpret_cast<Gap::ConnectionParams_t *>(&(p_ble_evt->evt.gap_evt.params.connected.conn_params));
+            nRF51Gap::getInstance().processConnectionEvent(handle, params);
             break;
         }
 
@@ -101,7 +136,10 @@
 #if NEED_BOND_MANAGER /* disabled by default */
             ASSERT_STATUS_RET_VOID ( ble_bondmngr_bonded_centrals_store());
 #endif
-            nRF51Gap::getInstance().processHandleSpecificEvent(GapEvents::GAP_EVENT_DISCONNECTED, handle);
+
+            if (p_ble_evt->evt.gap_evt.params.disconnected.reason == BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION) {
+                nRF51Gap::getInstance().processDisconnectionEvent(handle, Gap::LOCAL_HOST_TERMINATED_CONNECTION);
+            }
             break;
         }
 
@@ -117,11 +155,8 @@
             sec_params.min_key_size = CFG_BLE_SEC_PARAM_MIN_KEY_SIZE;
             sec_params.max_key_size = CFG_BLE_SEC_PARAM_MAX_KEY_SIZE;
 
-            ASSERT_STATUS_RET_VOID(
-                sd_ble_gap_sec_params_reply(nRF51Gap::getInstance().
-                                            getConnectionHandle(),
-                                            BLE_GAP_SEC_STATUS_SUCCESS,
-                                            &sec_params));
+            ASSERT_STATUS_RET_VOID(sd_ble_gap_sec_params_reply(nRF51Gap::getInstance().getConnectionHandle(),
+                                                               BLE_GAP_SEC_STATUS_SUCCESS, &sec_params));
         }
         break;
 
--- a/btle/btle_gap.cpp	Fri Jul 25 10:33:52 2014 +0100
+++ b/btle/btle_gap.cpp	Tue Sep 02 15:50:05 2014 +0100
@@ -20,7 +20,9 @@
 #include "ble_conn_params.h"
 
 static inline uint32_t msec_to_1_25msec(uint32_t interval_ms) ATTR_ALWAYS_INLINE ATTR_CONST;
+#if SDK_CONN_PARAMS_MODULE_ENABLE
 static void   error_callback(uint32_t nrf_error);
+#endif // SDK_CONN_PARAMS_MODULE_ENABLE
 
 /**************************************************************************/
 /*!
@@ -46,6 +48,11 @@
     ASSERT_STATUS( sd_ble_gap_ppcp_set(&gap_conn_params));
     ASSERT_STATUS( sd_ble_gap_tx_power_set(CFG_BLE_TX_POWER_LEVEL));
 
+    /**
+     * Call to conn_params_init() is not necessary; and so is disabled by default.
+     * This API should be exposed to the user to be invoked when necessary.
+     */
+#if SDK_CONN_PARAMS_MODULE_ENABLE
     /* Connection Parameters */
     enum {
         FIRST_UPDATE_DELAY = APP_TIMER_TICKS(5000, CFG_TIMER_PRESCALER),
@@ -65,6 +72,7 @@
     cp_init.error_handler                  = error_callback;
 
     ASSERT_STATUS ( ble_conn_params_init(&cp_init));
+#endif // SDK_CONN_PARAMS_MODULE_ENABLE
 
     return ERROR_NONE;
 }
@@ -84,7 +92,9 @@
     return (interval_ms * 4) / 5;
 }
 
+#if SDK_CONN_PARAMS_MODULE_ENABLE
 static void error_callback(uint32_t nrf_error)
 {
     ASSERT_STATUS_RET_VOID( nrf_error );
 }
+#endif // SDK_CONN_PARAMS_MODULE_ENABLE
--- a/btle/custom/custom_helper.cpp	Fri Jul 25 10:33:52 2014 +0100
+++ b/btle/custom/custom_helper.cpp	Tue Sep 02 15:50:05 2014 +0100
@@ -23,8 +23,8 @@
  * structures involved in maintaining a local cache of 128-bit UUIDs.
  */
 typedef struct {
-    LongUUID_t uuid;
-    uint8_t    type;
+    LongUUIDBytes_t uuid;
+    uint8_t         type;
 } converted_uuid_table_entry_t;
 static const unsigned UUID_TABLE_MAX_ENTRIES = 8; /* This is the maximum number
                                     * of 128-bit UUIDs with distinct bases that
@@ -40,7 +40,7 @@
  * @return               true if a match is found.
  */
 static bool
-lookupConvertedUUIDTable(const LongUUID_t uuid, uint8_t *recoveredType)
+lookupConvertedUUIDTable(const LongUUIDBytes_t uuid, uint8_t *recoveredType)
 {
     unsigned i;
     for (i = 0; i < uuidTableEntries; i++) {
@@ -56,7 +56,7 @@
 }
 
 static void
-addToConvertedUUIDTable(const LongUUID_t uuid, uint8_t type)
+addToConvertedUUIDTable(const LongUUIDBytes_t uuid, uint8_t type)
 {
     if (uuidTableEntries == UUID_TABLE_MAX_ENTRIES) {
         return; /* recovery needed; or at least the user should be
@@ -157,7 +157,7 @@
 error_t custom_decode_uuid_base(uint8_t const *const p_uuid_base,
                                 ble_uuid_t          *p_uuid)
 {
-    LongUUID_t uuid_base_le;
+    LongUUIDBytes_t uuid_base_le;
 
     /* Reverse the bytes since ble_uuid128_t is LSB */
     for (uint8_t i = 0; i<16; i++) {
--- a/nRF51822n.cpp	Fri Jul 25 10:33:52 2014 +0100
+++ b/nRF51822n.cpp	Tue Sep 02 15:50:05 2014 +0100
@@ -19,6 +19,7 @@
 #include "nrf_soc.h"
 
 #include "btle/btle.h"
+#include "nrf_delay.h"
 
 /**
  * The singleton which represents the nRF51822 transport for the BLEDevice.
@@ -133,10 +134,10 @@
 /**************************************************************************/
 ble_error_t nRF51822n::reset(void)
 {
-    wait(0.5);
+    nrf_delay_us(500000);
 
     /* Wait for the radio to come back up */
-    wait(1);
+    nrf_delay_us(1000000);
 
     return BLE_ERROR_NONE;
 }
--- a/nRF51Gap.cpp	Fri Jul 25 10:33:52 2014 +0100
+++ b/nRF51Gap.cpp	Tue Sep 02 15:50:05 2014 +0100
@@ -168,8 +168,7 @@
     adv_para.interval    = params.getInterval();         // advertising interval (in units of 0.625 ms)
     adv_para.timeout     = params.getTimeout();
 
-    ASSERT(ERROR_NONE == sd_ble_gap_adv_start(&adv_para),
-           BLE_ERROR_PARAM_OUT_OF_RANGE);
+    ASSERT(ERROR_NONE == sd_ble_gap_adv_start(&adv_para), BLE_ERROR_PARAM_OUT_OF_RANGE);
 
     state.advertising = 1;
 
@@ -218,14 +217,23 @@
     @endcode
 */
 /**************************************************************************/
-ble_error_t nRF51Gap::disconnect(void)
+ble_error_t nRF51Gap::disconnect(DisconnectionReason_t reason)
 {
     state.advertising = 0;
     state.connected   = 0;
 
+    uint8_t code = BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION;
+    switch (reason) {
+        case REMOTE_USER_TERMINATED_CONNECTION:
+            code = BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION;
+            break;
+        case CONN_INTERVAL_UNACCEPTABLE:
+            code = BLE_HCI_CONN_INTERVAL_UNACCEPTABLE;
+            break;
+    }
+
     /* Disconnect if we are connected to a central device */
-    ASSERT_INT(ERROR_NONE,
-        sd_ble_gap_disconnect(m_connectionHandle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION), BLE_ERROR_PARAM_OUT_OF_RANGE);
+    ASSERT_INT(ERROR_NONE, sd_ble_gap_disconnect(m_connectionHandle, code), BLE_ERROR_PARAM_OUT_OF_RANGE);
 
     return BLE_ERROR_NONE;
 }
@@ -252,8 +260,7 @@
 {
     uint32_t rc;
 
-    rc = sd_ble_gap_conn_param_update(handle,
-                                      reinterpret_cast<ble_gap_conn_params_t *>(const_cast<ConnectionParams_t*>(newParams)));
+    rc = sd_ble_gap_conn_param_update(handle, reinterpret_cast<ble_gap_conn_params_t *>(const_cast<ConnectionParams_t*>(newParams)));
     if (rc == NRF_SUCCESS) {
         return BLE_ERROR_NONE;
     } else {
@@ -314,3 +321,42 @@
 
     return BLE_ERROR_NONE;
 }
+
+ble_error_t nRF51Gap::setDeviceName(const uint8_t *deviceName)
+{
+    ble_gap_conn_sec_mode_t sec_mode;
+    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); // no security is needed
+
+    if (sd_ble_gap_device_name_set(&sec_mode, deviceName, strlen((const char *)deviceName)) == NRF_SUCCESS) {
+        return BLE_ERROR_NONE;
+    } else {
+        return BLE_ERROR_PARAM_OUT_OF_RANGE;
+    }
+}
+
+ble_error_t nRF51Gap::getDeviceName(uint8_t *deviceName, unsigned *lengthP)
+{
+    if (sd_ble_gap_device_name_get(deviceName, (uint16_t *)lengthP) == NRF_SUCCESS) {
+        return BLE_ERROR_NONE;
+    } else {
+        return BLE_ERROR_PARAM_OUT_OF_RANGE;
+    }
+}
+
+ble_error_t nRF51Gap::setAppearance(uint16_t appearance)
+{
+    if (sd_ble_gap_appearance_set(appearance) == NRF_SUCCESS) {
+        return BLE_ERROR_NONE;
+    } else {
+        return BLE_ERROR_PARAM_OUT_OF_RANGE;
+    }
+}
+
+ble_error_t nRF51Gap::getAppearance(uint16_t *appearanceP)
+{
+    if (sd_ble_gap_appearance_get(appearanceP)) {
+        return BLE_ERROR_NONE;
+    } else {
+        return BLE_ERROR_PARAM_OUT_OF_RANGE;
+    }
+}
--- a/nRF51Gap.h	Fri Jul 25 10:33:52 2014 +0100
+++ b/nRF51Gap.h	Tue Sep 02 15:50:05 2014 +0100
@@ -45,7 +45,12 @@
                                            const GapAdvertisingData &);
     virtual ble_error_t startAdvertising(const GapAdvertisingParams &);
     virtual ble_error_t stopAdvertising(void);
-    virtual ble_error_t disconnect(void);
+    virtual ble_error_t disconnect(DisconnectionReason_t reason);
+
+    virtual ble_error_t setDeviceName(const uint8_t *deviceName);
+    virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP);
+    virtual ble_error_t setAppearance(uint16_t appearance);
+    virtual ble_error_t getAppearance(uint16_t *appearanceP);
 
     void     setConnectionHandle(uint16_t con_handle);
     uint16_t getConnectionHandle(void);
--- a/nRF51GattServer.cpp	Fri Jul 25 10:33:52 2014 +0100
+++ b/nRF51GattServer.cpp	Tue Sep 02 15:50:05 2014 +0100
@@ -60,15 +60,15 @@
     for (uint8_t i = 0; i < service.getCharacteristicCount(); i++) {
         GattCharacteristic *p_char = service.getCharacteristic(i);
 
-        nordicUUID = custom_convert_to_nordic_uuid(p_char->getUUID());
+        nordicUUID = custom_convert_to_nordic_uuid(p_char->getValueAttribute().getUUID());
 
         ASSERT ( ERROR_NONE ==
-                 custom_add_in_characteristic(service.getHandle(),
+                 custom_add_in_characteristic(BLE_GATT_HANDLE_INVALID,
                                               &nordicUUID,
                                               p_char->getProperties(),
-                                              NULL,
-                                              p_char->getInitialLength(),
-                                              p_char->getMaxLength(),
+                                              p_char->getValueAttribute().getValuePtr(),
+                                              p_char->getValueAttribute().getInitialLength(),
+                                              p_char->getValueAttribute().getMaxLength(),
                                               &nrfCharacteristicHandles[characteristicCount]),
                  BLE_ERROR_PARAM_OUT_OF_RANGE );
 
@@ -76,9 +76,27 @@
         uint16_t charHandle = characteristicCount;
         p_characteristics[characteristicCount++] = p_char;
 
-        p_char->setHandle(charHandle);
-        if ((p_char->getValuePtr() != NULL) && (p_char->getInitialLength() > 0)) {
-            updateValue(charHandle, p_char->getValuePtr(), p_char->getInitialLength(), false /* localOnly */);
+        p_char->getValueAttribute().setHandle(charHandle);
+
+        /* Add optional descriptors if any */
+        /* ToDo: Make sure we don't overflow the array */
+        for (uint8_t j = 0; j < p_char->getDescriptorCount(); j++) {
+             GattAttribute *p_desc = p_char->getDescriptor(j);
+
+             nordicUUID = custom_convert_to_nordic_uuid(p_desc->getUUID());
+
+             ASSERT ( ERROR_NONE ==
+                      custom_add_in_descriptor(BLE_GATT_HANDLE_INVALID,
+                                               &nordicUUID,
+                                               p_desc->getValuePtr(),
+                                               p_desc->getInitialLength(),
+                                               p_desc->getMaxLength(),
+                                               &nrfDescriptorHandles[descriptorCount]),
+                 BLE_ERROR_PARAM_OUT_OF_RANGE );
+
+            uint16_t descHandle = descriptorCount;
+            p_descriptors[descriptorCount++] = p_desc;
+            p_desc->setHandle(descHandle);
         }
     }
 
@@ -194,45 +212,6 @@
     return BLE_ERROR_NONE;
 }
 
-ble_error_t nRF51GattServer::setDeviceName(const uint8_t *deviceName)
-{
-    ble_gap_conn_sec_mode_t sec_mode;
-    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode); // no security is needed
-
-    if (sd_ble_gap_device_name_set(&sec_mode, deviceName, strlen((const char *)deviceName)) == NRF_SUCCESS) {
-        return BLE_ERROR_NONE;
-    } else {
-        return BLE_ERROR_PARAM_OUT_OF_RANGE;
-    }
-}
-
-ble_error_t nRF51GattServer::getDeviceName(uint8_t *deviceName, unsigned *lengthP)
-{
-    if (sd_ble_gap_device_name_get(deviceName, (uint16_t *)lengthP) == NRF_SUCCESS) {
-        return BLE_ERROR_NONE;
-    } else {
-        return BLE_ERROR_PARAM_OUT_OF_RANGE;
-    }
-}
-
-ble_error_t nRF51GattServer::setAppearance(uint16_t appearance)
-{
-    if (sd_ble_gap_appearance_set(appearance) == NRF_SUCCESS) {
-        return BLE_ERROR_NONE;
-    } else {
-        return BLE_ERROR_PARAM_OUT_OF_RANGE;
-    }
-}
-
-ble_error_t nRF51GattServer::getAppearance(uint16_t *appearanceP)
-{
-    if (sd_ble_gap_appearance_get(appearanceP)) {
-        return BLE_ERROR_NONE;
-    } else {
-        return BLE_ERROR_PARAM_OUT_OF_RANGE;
-    }
-}
-
 /**************************************************************************/
 /*!
     @brief  Callback handler for events getting pushed up from the SD
@@ -240,50 +219,52 @@
 /**************************************************************************/
 void nRF51GattServer::hwCallback(ble_evt_t *p_ble_evt)
 {
-    uint16_t                      handle_value;
-    GattServerEvents::gattEvent_t event;
+    uint16_t                       handle_value;
+    GattServerEvents::gattEvent_t  eventType;
+    const ble_gatts_evt_t         *gattsEventP = &p_ble_evt->evt.gatts_evt;
 
     switch (p_ble_evt->header.evt_id) {
         case BLE_GATTS_EVT_WRITE:
             /* There are 2 use case here: Values being updated & CCCD (indicate/notify) enabled */
 
             /* 1.) Handle CCCD changes */
-            handle_value = p_ble_evt->evt.gatts_evt.params.write.handle;
+            handle_value = gattsEventP->params.write.handle;
             for (uint8_t i = 0; i<characteristicCount; i++) {
                 if ((p_characteristics[i]->getProperties() & (GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY)) &&
                     (nrfCharacteristicHandles[i].cccd_handle == handle_value)) {
                     uint16_t cccd_value =
-                        (p_ble_evt->evt.gatts_evt.params.write.data[1] << 8) |
-                        p_ble_evt->evt.gatts_evt.params.write.data[0]; /* Little Endian but M0 may be mis-aligned */
+                        (gattsEventP->params.write.data[1] << 8) |
+                        gattsEventP->params.write.data[0]; /* Little Endian but M0 may be mis-aligned */
 
                     if (((p_characteristics[i]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE) && (cccd_value & BLE_GATT_HVX_INDICATION)) ||
                         ((p_characteristics[i]->getProperties() & GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY) && (cccd_value & BLE_GATT_HVX_NOTIFICATION))) {
-                        event = GattServerEvents::GATT_EVENT_UPDATES_ENABLED;
+                        eventType = GattServerEvents::GATT_EVENT_UPDATES_ENABLED;
                     } else {
-                        event = GattServerEvents::GATT_EVENT_UPDATES_DISABLED;
+                        eventType = GattServerEvents::GATT_EVENT_UPDATES_DISABLED;
                     }
 
-                    handleEvent(event, i);
+                    handleEvent(eventType, i);
                     return;
                 }
             }
 
             /* 2.) Changes to the characteristic value will be handled with other events below */
-            event = GattServerEvents::GATT_EVENT_DATA_WRITTEN;
+            eventType = GattServerEvents::GATT_EVENT_DATA_WRITTEN;
             break;
 
-        case BLE_EVT_TX_COMPLETE:
-            handleEvent(GattServerEvents::GATT_EVENT_DATA_SENT);
-            return;
-
         case BLE_GATTS_EVT_HVC:
             /* Indication confirmation received */
-            event        = GattServerEvents::GATT_EVENT_CONFIRMATION_RECEIVED;
-            handle_value = p_ble_evt->evt.gatts_evt.params.hvc.handle;
+            eventType    = GattServerEvents::GATT_EVENT_CONFIRMATION_RECEIVED;
+            handle_value = gattsEventP->params.hvc.handle;
             break;
 
+        case BLE_EVT_TX_COMPLETE: {
+            handleDataSentEvent(p_ble_evt->evt.common_evt.params.tx_complete.count);
+            return;
+        }
+
         case BLE_GATTS_EVT_SYS_ATTR_MISSING:
-            sd_ble_gatts_sys_attr_set(p_ble_evt->evt.gatts_evt.conn_handle, NULL, 0);
+            sd_ble_gatts_sys_attr_set(gattsEventP->conn_handle, NULL, 0);
             return;
 
         default:
@@ -293,8 +274,21 @@
     /* Find index (charHandle) in the pool */
     for (uint8_t i = 0; i<characteristicCount; i++) {
         if (nrfCharacteristicHandles[i].value_handle == handle_value) {
-            handleEvent(event, i);
-            break;
+            switch (eventType) {
+                case GattServerEvents::GATT_EVENT_DATA_WRITTEN: {
+                    GattCharacteristicWriteCBParams cbParams = {
+                        .op     = static_cast<GattCharacteristicWriteCBParams::Type>(gattsEventP->params.write.op),
+                        .offset = gattsEventP->params.write.offset,
+                        .len    = gattsEventP->params.write.len,
+                        .data   = gattsEventP->params.write.data
+                    };
+                    handleDataWrittenEvent(i, &cbParams);
+                    break;
+                }
+                default:
+                    handleEvent(eventType, i);
+                    break;
+            }
         }
     }
 }
--- a/nRF51GattServer.h	Fri Jul 25 10:33:52 2014 +0100
+++ b/nRF51GattServer.h	Tue Sep 02 15:50:05 2014 +0100
@@ -24,6 +24,7 @@
 #include "public/GattServer.h"
 
 #define BLE_TOTAL_CHARACTERISTICS 10
+#define BLE_TOTAL_DESCRIPTORS     10
 
 class nRF51GattServer : public GattServer
 {
@@ -38,11 +39,6 @@
     virtual ble_error_t readValue(uint16_t handle, uint8_t buffer[], uint16_t *const lengthP);
     virtual ble_error_t updateValue(uint16_t, uint8_t[], uint16_t, bool localOnly = false);
 
-    virtual ble_error_t setDeviceName(const uint8_t *deviceName);
-    virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP);
-    virtual ble_error_t setAppearance(uint16_t appearance);
-    virtual ble_error_t getAppearance(uint16_t *appearanceP);
-
     /* nRF51 Functions */
     void eventCallback(void);
     void hwCallback(ble_evt_t *p_ble_evt);
@@ -50,10 +46,13 @@
 private:
     GattCharacteristic *p_characteristics[BLE_TOTAL_CHARACTERISTICS];
     ble_gatts_char_handles_t nrfCharacteristicHandles[BLE_TOTAL_CHARACTERISTICS];
+    GattAttribute *p_descriptors[BLE_TOTAL_DESCRIPTORS];
+    uint16_t nrfDescriptorHandles[BLE_TOTAL_DESCRIPTORS];
 
     nRF51GattServer() {
         serviceCount = 0;
         characteristicCount = 0;
+        descriptorCount = 0;
     };
 
     nRF51GattServer(nRF51GattServer const &);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nordic/app_common/app_button.c	Tue Sep 02 15:50:05 2014 +0100
@@ -0,0 +1,284 @@
+/* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved.
+ *
+ * The information contained herein is property of Nordic Semiconductor ASA.
+ * Terms and conditions of usage are described in detail in NORDIC
+ * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
+ *
+ * Licensees are granted free, non-transferable use of the information. NO
+ * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
+ * the file.
+ *
+ */
+
+#include "app_button.h"
+#include <string.h>
+#include "nordic_common.h"
+#include "app_util.h"
+#include "app_gpiote.h"
+#include "app_timer.h"
+#include "app_error.h"
+
+
+static app_button_cfg_t *             mp_buttons = NULL;           /**< Button configuration. */
+static uint8_t                        m_button_count;              /**< Number of configured buttons. */
+static uint32_t                       m_detection_delay;           /**< Delay before a button is reported as pushed. */
+static app_button_evt_schedule_func_t m_evt_schedule_func;         /**< Pointer to function for propagating button events to the scheduler. */
+static app_gpiote_user_id_t           m_gpiote_user_id;            /**< GPIOTE user id for buttons module. */
+static app_timer_id_t                 m_detection_delay_timer_id;  /**< Polling timer id. */
+static pin_transition_t               m_pin_transition;            /**< pin transaction direction. */
+
+
+/**@brief Function for executing the application button handler for specified button.
+ *
+ * @param[in]  p_btn   Button that has been pushed.
+ */
+static void button_handler_execute(app_button_cfg_t * p_btn, uint32_t transition)
+{
+    if (m_evt_schedule_func != NULL)
+    {
+        uint32_t err_code = m_evt_schedule_func(p_btn->button_handler, p_btn->pin_no,transition);
+        APP_ERROR_CHECK(err_code);
+    }
+    else
+    {
+        if(transition == APP_BUTTON_PUSH)
+        {
+            p_btn->button_handler(p_btn->pin_no, APP_BUTTON_PUSH);
+        }
+        else if(transition == APP_BUTTON_RELEASE)
+        {
+            p_btn->button_handler(p_btn->pin_no, APP_BUTTON_RELEASE);
+        }
+    }
+}
+
+
+/**@brief Function for handling the timeout that delays reporting buttons as pushed.
+ *
+ * @details    The detection_delay_timeout_handler(...) is a call-back issued from the app_timer
+ *             module. It is called with the p_context parameter. The p_context parameter is
+ *             provided to the app_timer module when a timer is started, using the call
+ *             @ref app_timer_start. On @ref app_timer_start the p_context will be holding the
+ *             currently pressed buttons.
+ *
+ * @param[in]  p_context   Pointer used for passing information app_start_timer() was called.
+ *                         In the app_button module the p_context holds information on pressed
+ *                         buttons.
+ */
+static void detection_delay_timeout_handler(void * p_context)
+{
+    uint32_t err_code;
+    uint32_t current_state_pins;
+
+    // Get current state of pins.
+    err_code = app_gpiote_pins_state_get(m_gpiote_user_id, &current_state_pins);
+
+    if (err_code != NRF_SUCCESS)
+    {
+        return;
+    }
+
+    uint8_t i;
+    
+    // Pushed button(s) detected, execute button handler(s).
+    for (i = 0; i < m_button_count; i++)
+    {
+        app_button_cfg_t * p_btn = &mp_buttons[i];
+
+        if (((m_pin_transition.high_to_low & (1 << p_btn->pin_no)) != 0) && (p_btn->button_handler != NULL))
+        {
+            //If it's active high then going from high to low was a release of the button.
+            if(p_btn->active_state == APP_BUTTON_ACTIVE_HIGH)
+            {
+                button_handler_execute(p_btn, APP_BUTTON_RELEASE);
+            }
+            //If it's active low then going from high to low was a push of the button.
+            else
+            {
+                button_handler_execute(p_btn, APP_BUTTON_PUSH);
+            }
+        }
+        else if (((m_pin_transition.low_to_high & (1 << p_btn->pin_no)) != 0) && (p_btn->button_handler != NULL))
+        {
+            //If it's active high then going from low to high was a push of the button.
+            if(p_btn->active_state == APP_BUTTON_ACTIVE_HIGH)
+            {
+                button_handler_execute(p_btn,APP_BUTTON_PUSH);
+            }
+            //If it's active low then going from low to high was a release of the button.
+            else
+            {
+                button_handler_execute(p_btn,APP_BUTTON_RELEASE);
+            }
+        }
+    }
+}
+
+
+/**@brief Function for handling the GPIOTE event.
+ *
+ * @details Saves the current status of the button pins, and starts a timer. If the timer is already
+ *          running, it will be restarted.
+ *
+ * @param[in]  event_pins_low_to_high   Mask telling which pin(s) had a low to high transition.
+ * @param[in]  event_pins_high_to_low   Mask telling which pin(s) had a high to low transition.
+ */
+static void gpiote_event_handler(uint32_t event_pins_low_to_high, uint32_t event_pins_high_to_low)
+{
+    uint32_t err_code;
+ 
+    // Start detection timer. If timer is already running, the detection period is restarted.
+    // NOTE: Using the p_context parameter of app_timer_start() to transfer the pin states to the
+    //       timeout handler (by casting event_pins_mask into the equally sized void * p_context
+    //       parameter).
+    STATIC_ASSERT(sizeof(void *) == sizeof(uint32_t));
+
+    err_code = app_timer_stop(m_detection_delay_timer_id);
+    if (err_code != NRF_SUCCESS)
+    {
+        // The impact in app_button of the app_timer queue running full is losing a button press.
+        // The current implementation ensures that the system will continue working as normal. 
+        return;
+    }
+
+    m_pin_transition.low_to_high = event_pins_low_to_high;
+    m_pin_transition.high_to_low = event_pins_high_to_low;
+    
+    err_code = app_timer_start(m_detection_delay_timer_id,
+                               m_detection_delay,
+                               (void *)(event_pins_low_to_high | event_pins_high_to_low));
+    if (err_code != NRF_SUCCESS)
+    {
+        // The impact in app_button of the app_timer queue running full is losing a button press.
+        // The current implementation ensures that the system will continue working as normal. 
+    }
+}
+
+
+uint32_t app_button_init(app_button_cfg_t *             p_buttons,
+                         uint8_t                        button_count,
+                         uint32_t                       detection_delay,
+                         app_button_evt_schedule_func_t evt_schedule_func)
+{
+    uint32_t err_code;
+    
+    if (detection_delay < APP_TIMER_MIN_TIMEOUT_TICKS)
+    {
+        return NRF_ERROR_INVALID_PARAM;
+    }
+
+    // Save configuration.
+    mp_buttons          = p_buttons;
+    m_button_count      = button_count;
+    m_detection_delay   = detection_delay;
+    m_evt_schedule_func = evt_schedule_func;
+  
+    // Configure pins.
+    uint32_t pins_transition_mask = 0;
+    
+    while (button_count--)
+    {
+        app_button_cfg_t * p_btn = &p_buttons[button_count];
+
+        // Configure pin.
+        nrf_gpio_cfg_input(p_btn->pin_no, p_btn->pull_cfg);
+        
+        // Build GPIOTE user registration masks.
+        pins_transition_mask |= (1 << p_btn->pin_no);
+    }
+    
+    // Register button module as a GPIOTE user.
+    err_code = app_gpiote_user_register(&m_gpiote_user_id,
+                                        pins_transition_mask,
+                                        pins_transition_mask,
+                                        gpiote_event_handler);
+    if (err_code != NRF_SUCCESS)
+    {
+        return err_code;
+    }
+
+    // Create polling timer.
+    return app_timer_create(&m_detection_delay_timer_id,
+                            APP_TIMER_MODE_SINGLE_SHOT,
+                            detection_delay_timeout_handler);
+}
+
+
+uint32_t app_button_enable(void)
+{
+    if (mp_buttons == NULL)
+    {
+        return NRF_ERROR_INVALID_STATE;
+    }
+
+    return app_gpiote_user_enable(m_gpiote_user_id);
+}
+
+
+uint32_t app_button_disable(void)
+{
+    uint32_t err_code;
+    
+    if (mp_buttons == NULL)
+    {
+        return NRF_ERROR_INVALID_STATE;
+    }
+
+    err_code = app_gpiote_user_disable(m_gpiote_user_id);
+
+    if (err_code != NRF_SUCCESS)
+    {
+        return err_code;
+    }
+
+    // Make sure polling timer is not running.
+    return app_timer_stop(m_detection_delay_timer_id);
+}
+
+
+uint32_t app_button_is_pushed(uint8_t pin_no, bool * p_is_pushed)
+{
+    uint32_t err_code;
+    uint32_t active_pins;
+    
+    app_button_cfg_t * p_btn = &mp_buttons[pin_no];
+
+    if (mp_buttons == NULL)
+    {
+        return NRF_ERROR_INVALID_STATE;
+    }
+
+    err_code = app_gpiote_pins_state_get(m_gpiote_user_id, &active_pins);
+    
+    if (err_code != NRF_SUCCESS)
+    {
+        return err_code;
+    }
+
+    if(p_btn->active_state == APP_BUTTON_ACTIVE_LOW)
+    {
+        // If the pin is active low, then the pin being high means it is not pushed.
+        if(((active_pins >> pin_no) & 0x01))
+        {
+            *p_is_pushed = false;
+        }
+        else
+        {
+            *p_is_pushed = true;  
+        }            
+    }
+    else if(p_btn->active_state == APP_BUTTON_ACTIVE_HIGH)
+    {
+        // If the pin is active high, then the pin being high means it is pushed.
+        if(((active_pins >> pin_no) & 0x01))
+        {
+            *p_is_pushed = true;
+        }
+        else
+        {
+            *p_is_pushed = false;   
+        }
+    }
+    
+    return NRF_SUCCESS;
+}
--- a/nordic/app_common/app_gpiote.c	Fri Jul 25 10:33:52 2014 +0100
+++ b/nordic/app_common/app_gpiote.c	Tue Sep 02 15:50:05 2014 +0100
@@ -10,6 +10,8 @@
  *
  */
 
+#if NEED_APP_GPIOTE /* disabled by default */
+
 #include "app_gpiote.h"
 #include <stdlib.h>
 #include <string.h>
@@ -358,3 +360,5 @@
     return NRF_ERROR_NOT_SUPPORTED;
 }
 #endif // SVCALL_AS_NORMAL_FUNCTION || SER_CONNECTIVITY
+
+#endif // #if NEED_APP_GPIOTE
--- a/nordic/app_common/app_timer.cpp	Fri Jul 25 10:33:52 2014 +0100
+++ b/nordic/app_common/app_timer.cpp	Tue Sep 02 15:50:05 2014 +0100
@@ -16,8 +16,7 @@
 #include "nrf51_bitfields.h"
 #include "nrf_soc.h"
 #include "app_error.h"
-//#include "nrf_delay.h"
-#include "mbed.h"
+#include "nrf_delay.h"
 #include "app_util.h"
 #include "app_util_platform.h"
 
@@ -30,8 +29,6 @@
 // (e.g. by using guard/trigger flags).
 STATIC_ASSERT(RTC1_IRQ_PRI == SWI0_IRQ_PRI);
 
-#define MAX_RTC_COUNTER_VAL     0x00FFFFFF                                  /**< Maximum value of the RTC counter. */
-
 #define APP_HIGH_USER_ID        0                                           /**< User Id for the Application High "user". */
 #define APP_LOW_USER_ID         1                                           /**< User Id for the Application Low "user". */
 #define THREAD_MODE_USER_ID     2                                           /**< User Id for the Thread Mode "user". */
@@ -125,7 +122,6 @@
  */
 typedef uint32_t timer_user_id_t;
 
-#define TIMER_NULL                  ((app_timer_id_t)(0 - 1))                   /**< Invalid timer id. */
 #define CONTEXT_QUEUE_SIZE_MAX      (2)                                         /**< Timer internal elapsed ticks queue size. */
 
 static uint8_t                       m_node_array_size;                         /**< Size of timer node array. */
@@ -138,6 +134,8 @@
 static uint8_t                       m_ticks_elapsed_q_read_ind;                /**< Timer internal elapsed ticks queue read index. */
 static uint8_t                       m_ticks_elapsed_q_write_ind;               /**< Timer internal elapsed ticks queue write index. */
 static app_timer_evt_schedule_func_t m_evt_schedule_func;                       /**< Pointer to function for propagating timeout events to the scheduler. */
+static bool                          m_rtc1_running;                            /**< Boolean indicating if RTC1 is running. */
+static volatile uint64_t             overflowBits;                              /**< The upper 40 bits of the 64-bit value returned by cnt_get() */
 
 
 /**@brief Function for initializing the RTC1 counter.
@@ -155,14 +153,20 @@
  */
 static void rtc1_start(void)
 {
+    if (m_rtc1_running) {
+        return;
+    }
+
     NRF_RTC1->EVTENSET = RTC_EVTEN_COMPARE0_Msk;
-    NRF_RTC1->INTENSET = RTC_INTENSET_COMPARE0_Msk;
+    NRF_RTC1->INTENSET = RTC_INTENSET_COMPARE0_Msk | RTC_INTENSET_OVRFLW_Msk;
 
     NVIC_ClearPendingIRQ(RTC1_IRQn);
     NVIC_EnableIRQ(RTC1_IRQn);
 
     NRF_RTC1->TASKS_START = 1;
-    wait(0.0000001 * MAX_RTC_TASKS_DELAY);
+    nrf_delay_us(MAX_RTC_TASKS_DELAY);
+
+    m_rtc1_running = true;
 }
 
 
@@ -170,13 +174,23 @@
  */
 static void rtc1_stop(void)
 {
+    if (!m_rtc1_running) {
+        return;
+    }
+
     NVIC_DisableIRQ(RTC1_IRQn);
 
     NRF_RTC1->EVTENCLR = RTC_EVTEN_COMPARE0_Msk;
-    NRF_RTC1->INTENCLR = RTC_INTENSET_COMPARE0_Msk;
+    NRF_RTC1->INTENCLR = RTC_INTENSET_COMPARE0_Msk | RTC_INTENSET_OVRFLW_Msk;
 
     NRF_RTC1->TASKS_STOP = 1;
-    wait(0.0000001 * MAX_RTC_TASKS_DELAY);
+    nrf_delay_us(MAX_RTC_TASKS_DELAY);
+
+    NRF_RTC1->TASKS_CLEAR = 1;
+    m_ticks_latest        = 0;
+    nrf_delay_us(MAX_RTC_TASKS_DELAY);
+
+    m_rtc1_running = false;
 }
 
 
@@ -296,6 +310,12 @@
     if (previous == current)
     {
         m_timer_id_head = mp_nodes[m_timer_id_head].next;
+
+        // No more timers in the list. Disable RTC1.
+        if (m_timer_id_head == TIMER_NULL)
+        {
+            rtc1_stop();
+        }
     }
 
     // Remaining timeout between next timeout
@@ -673,7 +693,7 @@
         uint32_t cc              = m_ticks_latest;
         uint32_t ticks_elapsed   = ticks_diff_get(pre_counter_val, cc) + RTC_COMPARE_OFFSET_MIN;
 
-        if (timer_id_head_old == TIMER_NULL)
+        if (!m_rtc1_running)
         {
             // No timers were already running, start RTC
             rtc1_start();
@@ -686,11 +706,7 @@
 
         uint32_t post_counter_val = rtc1_counter_get();
 
-        if (
-            (ticks_diff_get(post_counter_val, pre_counter_val) + RTC_COMPARE_OFFSET_MIN)
-            >
-            ticks_diff_get(cc, pre_counter_val)
-           )
+        if ((ticks_diff_get(post_counter_val, pre_counter_val) + RTC_COMPARE_OFFSET_MIN) > ticks_diff_get(cc, pre_counter_val))
         {
             // When this happens the COMPARE event may not be triggered by the RTC.
             // The nRF51 Series User Specification states that if the COUNTER value is N
@@ -897,6 +913,9 @@
     NRF_RTC1->EVENTS_COMPARE[2] = 0;
     NRF_RTC1->EVENTS_COMPARE[3] = 0;
     NRF_RTC1->EVENTS_TICK       = 0;
+    if (NRF_RTC1->EVENTS_OVRFLW) {
+        overflowBits += (1 << 24);
+    }
     NRF_RTC1->EVENTS_OVRFLW     = 0;
 
     // Check for expired timers
@@ -979,6 +998,7 @@
     NVIC_EnableIRQ(SWI0_IRQn);
 
     rtc1_init(prescaler);
+    rtc1_start();
 
     m_ticks_latest = rtc1_counter_get();
 
@@ -1115,9 +1135,9 @@
 }
 
 
-uint32_t app_timer_cnt_get(uint32_t * p_ticks)
+uint32_t app_timer_cnt_get(uint64_t * p_ticks)
 {
-    *p_ticks = rtc1_counter_get();
+    *p_ticks = overflowBits | rtc1_counter_get();
     return NRF_SUCCESS;
 }
 
--- a/nordic/app_common/pstorage.cpp	Fri Jul 25 10:33:52 2014 +0100
+++ b/nordic/app_common/pstorage.cpp	Tue Sep 02 15:50:05 2014 +0100
@@ -12,20 +12,20 @@
 
 #if NEED_PSTORAGE /* disabled by default */
 
+#include "pstorage.h"
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
 #include "nordic_common.h"
 #include "nrf_error.h"
 #include "nrf_assert.h"
-//#include "nrf.h"
+#include "nrf.h"
 #include "nrf_soc.h"
 #include "app_util.h"
-#include "pstorage.h"
 
-
-#define INVALID_OPCODE              0x00                       /**< Invalid op code identifier. */
-#define SOC_MAX_WRITE_SIZE          1024                       /**< Maximum write size allowed for a single call to \ref sd_flash_write as specified in the SoC API. */
+#define INVALID_OPCODE     0x00                            /**< Invalid op code identifier. */
+#define SOC_MAX_WRITE_SIZE 1024                            /**< Maximum write size allowed for a single call to \ref sd_flash_write as specified in the SoC API. */
+#define RAW_MODE_APP_ID    (PSTORAGE_MAX_APPLICATIONS + 1) /**< Application id for raw mode. */
 
 /**
  * @defgroup api_param_check API Parameters check macros.
@@ -35,6 +35,7 @@
  *
  * @{
  */
+
 /**
  * @brief Check if the input pointer is NULL, if it is returns NRF_ERROR_NULL.
  */
@@ -66,9 +67,8 @@
             return NRF_ERROR_INVALID_PARAM;                                                       \
         }
 
-
 /**
- * @brief Verifies the block size requested by the application can be supported by the module. 
+ * @brief Verifies the block size requested by the application can be supported by the module.
  */
 #define BLOCK_SIZE_CHECK(X)                                                                       \
         if (((X) > PSTORAGE_MAX_BLOCK_SIZE) || ((X) < PSTORAGE_MIN_BLOCK_SIZE))                   \
@@ -80,7 +80,7 @@
  * @brief Verifies block size requested by Application in registration API.
  */
 #define BLOCK_COUNT_CHECK(COUNT, SIZE)                                                            \
-        if (((COUNT) == 0) || ((m_next_page_addr + ((COUNT) *(SIZE)) > PSTORAGE_DATA_END_ADDR)))  \
+        if (((COUNT) == 0) || ((m_next_page_addr + ((COUNT) *(SIZE)) > PSTORAGE_SWAP_ADDR)))      \
         {                                                                                         \
             return NRF_ERROR_INVALID_PARAM;                                                       \
         }
@@ -119,6 +119,7 @@
 
 /**@} */
 
+
 /**@brief    Verify module's initialization status.
  *
  * @details   Verify module's initialization status. Returns NRF_ERROR_INVALID_STATE in case a
@@ -136,7 +137,21 @@
 /**@brief Macro to fetch the block size registered for the module. */
 #define MODULE_BLOCK_SIZE(ID) (m_app_table[(ID)->module_id].block_size)
 
-/**@} */
+
+/** @brief States for the Update/Clear swap backup state machine. */
+typedef enum
+{
+    STATE_INIT,                /**< State for indicating that swap can be used when using update/clear API. */
+    STATE_DATA_TO_SWAP_WRITE,  /**< State for doing backup of data page into the swap page when using update/clear API. */
+    STATE_DATA_ERASE,          /**< State for erasing data page when using update/clear API. */
+    STATE_HEAD_RESTORE,        /**< State for restoring head (beginning) of backed up data from swap to data page when using update/clear API. */
+    STATE_TAIL_RESTORE,        /**< State for restoring tail (end) of backed up data from swap to data page when using update/clear API. */
+    STATE_NEW_BODY_WRITE,      /**< State for writing body (middle) data to the data page when using update/clear API. */
+    STATE_SWAP_ERASE,          /**< State for erasing the swap page when using the update/clear API. */
+    STATE_COMPLETE,            /**< State for indicating that update/clear sequence is completed internal in the module when using the update/clear API. */
+    STATE_SWAP_DIRTY           /**< State for initializing the swap region on module initialization. */
+} swap_backup_state_t;
+
 
 /**
  * @brief Application registration information.
@@ -146,13 +161,14 @@
  */
 typedef struct
 {
-    pstorage_ntf_cb_t      cb;             /**< Callback registered with the module to be notified of result of flash access.  */
-    pstorage_block_t       base_id;        /**< Base block id assigned to the module */
-    pstorage_size_t        block_size;     /**< Size of block for the module */
-    pstorage_size_t        block_count;    /**< Number of block requested by application */
-    pstorage_size_t        no_of_pages;    /**< Variable to remember how many pages have been allocated for this module. This information is used for clearing of block, so that application does not need to have knowledge of number of pages its using. */    
+    pstorage_ntf_cb_t    cb;             /**< Callback registered with the module to be notified of result of flash access.  */
+    pstorage_block_t     base_id;        /**< Base block id assigned to the module. */
+    pstorage_size_t      block_size;     /**< Size of block for the module. */
+    pstorage_size_t      block_count;    /**< Number of block requested by application. */
+    pstorage_size_t      num_of_pages;   /**< Variable to remember how many pages have been allocated for this module. This information is used for clearing of block, so that application does not need to have knowledge of number of pages its using. */
 } pstorage_module_table_t;
 
+
 #ifdef PSTORAGE_RAW_MODE_ENABLE
 /**
  * @brief Application registration information.
@@ -162,13 +178,11 @@
 typedef struct
 {
     pstorage_ntf_cb_t      cb;             /**< Callback registered with the module to be notified of result of flash access.  */
-    uint16_t               no_of_pages;    /**< Variable to remember how many pages have been allocated for this module. This information is used for clearing of block, so that application does not need to have knowledge of number of pages its using. */
+    uint16_t               num_of_pages;   /**< Variable to remember how many pages have been allocated for this module. This information is used for clearing of block, so that application does not need to have knowledge of number of pages its using. */
 } pstorage_raw_module_table_t;
 #endif // PSTORAGE_RAW_MODE_ENABLE
 
 
-
-
 /**
  * @brief Defines command queue element.
  *
@@ -177,16 +191,16 @@
  */
 typedef struct
 {
-    uint8_t              op_code;          /**< Identifies flash access operation being queued. Element is free is op-code is INVALID_OPCODE */
-    pstorage_size_t      size;             /**< Identifies size in bytes requested for the operation. */
-    pstorage_size_t      offset;           /**< Offset requested by the application for access operation. */    
-    pstorage_handle_t    storage_addr;     /**< Address/Identifier for persistent memory. */
-    uint8_t              * p_data_addr;    /**< Address/Identifier for data memory. This is assumed to be resident memory. */    
+    uint8_t              op_code;       /**< Identifies flash access operation being queued. Element is free if op-code is INVALID_OPCODE. */
+    pstorage_size_t      size;          /**< Identifies size in bytes requested for the operation. */
+    pstorage_size_t      offset;        /**< Offset requested by the application for access operation. */
+    pstorage_handle_t    storage_addr;  /**< Address/Identifier for persistent memory. */
+    uint8_t *            p_data_addr;   /**< Address/Identifier for data memory. This is assumed to be resident memory. */
 } cmd_queue_element_t;
 
 
 /**
- * @brief Defines command queue, an element is free is op_code field is not invalid.
+ * @brief Defines command queue, an element is free if op_code field is not invalid.
  *
  * @details Defines commands enqueued for flash access. At any point of time, this queue has one or
  *          more flash access operation pending if the count field is not zero. When the queue is
@@ -196,26 +210,43 @@
  */
 typedef struct
 {
-    uint8_t              rp;                              /**< Read pointer, pointing to flash access that is ongoing or to be requested next. */
-    uint8_t              count;                           /**< Number of elements in the queue.  */
-    bool                 flash_access;                    /**< Flag to ensure an flash event received is for an request issued by the module. */
-    cmd_queue_element_t  cmd[PSTORAGE_CMD_QUEUE_SIZE];    /**< Array to maintain flash access operation details */
-}cmd_queue_t;
+    uint8_t              rp;                           /**< Read pointer, pointing to flash access that is ongoing or to be requested next. */
+    uint8_t              count;                        /**< Number of elements in the queue.  */
+    bool                 flash_access;                 /**< Flag to ensure an flash event received is for an request issued by the module. */
+    cmd_queue_element_t  cmd[PSTORAGE_CMD_QUEUE_SIZE]; /**< Array to maintain flash access operation details. */
+} cmd_queue_t;
+
 
-static cmd_queue_t             m_cmd_queue;                               /**< Flash operation request queue. */
-static pstorage_module_table_t m_app_table[PSTORAGE_MAX_APPLICATIONS];    /**< Registered application information table. */
+static cmd_queue_t         m_cmd_queue;                  /**< Flash operation request queue. */
+static pstorage_size_t     m_next_app_instance;          /**< Points to the application module instance that can be allocated next. */
+static uint32_t            m_next_page_addr;             /**< Points to the flash address that can be allocated to a module next, this is needed as blocks of a module can span across flash pages. */
+static pstorage_size_t     m_round_val;                  /**< Round value for multiple round operations. For erase operations, the round value will contain current round counter which is identical to number of pages erased. For store operations, the round value contains current round of operation * SOC_MAX_WRITE_SIZE to ensure each store to the SoC Flash API is within the SoC limit. */
+static bool                m_module_initialized = false; /**< Flag for checking if module has been initialized. */
+static swap_backup_state_t m_swap_state;                 /**< Swap page state. */
+
+
+static pstorage_module_table_t m_app_table[PSTORAGE_MAX_APPLICATIONS]; /**< Registered application information table. */
 
 #ifdef PSTORAGE_RAW_MODE_ENABLE
-static pstorage_raw_module_table_t m_raw_app_table;      /**< Registered application information table for raw mode. */
+static pstorage_raw_module_table_t m_raw_app_table;                    /**< Registered application information table for raw mode. */
 #endif // PSTORAGE_RAW_MODE_ENABLE
 
-static pstorage_size_t  m_next_app_instance;             /**< Points to the application module instance that can be allocated next */
-static uint32_t         m_next_page_addr;                /**< Points to the flash address that can be allocated to a module next, this is needed as blocks of a module can span across flash pages. */
-static bool             m_module_initialized = false;    /**< Flag for checking if module has been initialized. */
-static pstorage_size_t  m_round_val;                     /**< Round value for multiple round operations. For erase operations, the round value will contain current round counter which is identical to number of pages erased. For store operations, the round value contains current round of operation * SOC_MAX_WRITE_SIZE to ensure each store to the SoC Flash API is within the SoC limit. */
+
+/**
+ * @brief Routine called to actually issue the flash access request to the SoftDevice.
+ *
+ * @retval    NRF_SUCCESS    on success, else an error code indicating reason for failure.
+ */
+static uint32_t cmd_process(void);
 
-static uint32_t process_cmd(void);
-static void app_notify (uint32_t reason);
+
+/**
+ * @brief Routine to notify application of any errors.
+ *
+ * @param[in] result Result of event being notified.
+ */
+static void app_notify(uint32_t result);
+
 
 /**
  * @defgroup utility_functions Utility internal functions.
@@ -226,13 +257,16 @@
  * @note Only one flash access operation is permitted at a time by SoC. Hence a queue is
  * maintained by this module.
  */
- 
+
+
 /**
  * @brief Initializes command queue element.
+ *
+ * @param[in] index Element index being initialized.
  */
-static void cmd_queue_init_element(uint32_t index)
+static void cmd_queue_element_init(uint32_t index)
 {
-    // Internal function and checks on range of index can be avoided
+    // Internal function and checks on range of index can be avoided.
     m_cmd_queue.cmd[index].op_code                = INVALID_OPCODE;
     m_cmd_queue.cmd[index].size                   = 0;
     m_cmd_queue.cmd[index].storage_addr.module_id = PSTORAGE_MAX_APPLICATIONS;
@@ -245,51 +279,48 @@
 /**
  * @brief Initializes command queue.
  */
-static void cmd_queue_init (void)
+static void cmd_queue_init(void)
 {
     uint32_t cmd_index;
 
     m_round_val              = 0;
+    m_swap_state             = STATE_INIT;
     m_cmd_queue.rp           = 0;
     m_cmd_queue.count        = 0;
     m_cmd_queue.flash_access = false;
 
-    for(cmd_index = 0; cmd_index < PSTORAGE_CMD_QUEUE_SIZE; cmd_index++)
+    for (cmd_index = 0; cmd_index < PSTORAGE_CMD_QUEUE_SIZE; cmd_index++)
     {
-        cmd_queue_init_element(cmd_index);
+        cmd_queue_element_init(cmd_index);
     }
 }
 
 
 /**
  * @brief Routine to enqueue a flash access operation.
+ *
+ * @param[in] opcode         Identifies operation requested to be enqueued.
+ * @param[in] p_storage_addr Identiifes module and flash address on which operation is requested.
+ * @param[in] p_data_addr    Identifies data address for flash access.
+ * @param[in] size           Size in bytes of data requested for the access operation.
+ * @param[in] offset         Offset within the flash memory block at which operation is requested.
+ *
+ * @retval    NRF_SUCCESS    on success, else an error code indicating reason for failure.
+ *
+ * @note All paramater check should be performed before requesting in an enqueue.
  */
-static uint32_t cmd_queue_enqueue(uint8_t opcode, pstorage_handle_t * p_storage_addr,uint8_t * p_data_addr, pstorage_size_t size, pstorage_size_t offset)
+static uint32_t cmd_queue_enqueue(uint8_t             opcode,
+                                  pstorage_handle_t * p_storage_addr,
+                                  uint8_t           * p_data_addr,
+                                  pstorage_size_t     size,
+                                  pstorage_size_t     offset)
 {
     uint32_t retval;
     uint8_t  write_index = 0;
-    retval = NRF_ERROR_NO_MEM;
 
-    // Check if flash access is ongoing.
-    if ((m_cmd_queue.flash_access == false) && (m_cmd_queue.count == 0))
+    if (m_cmd_queue.count != PSTORAGE_CMD_QUEUE_SIZE)
     {
-        m_cmd_queue.rp = 0;
-        m_cmd_queue.cmd[m_cmd_queue.rp].op_code      = opcode;
-        m_cmd_queue.cmd[m_cmd_queue.rp].p_data_addr  = p_data_addr;
-        m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr = (*p_storage_addr);
-        m_cmd_queue.cmd[m_cmd_queue.rp].size         = size;
-        m_cmd_queue.cmd[m_cmd_queue.rp].offset       = offset;
-        m_cmd_queue.count++;
-        retval = process_cmd();
-        if ((retval == NRF_SUCCESS) || (retval == NRF_ERROR_BUSY))
-        {
-            // In case of busy error code, it is possible to attempt to access flash
-            retval = NRF_SUCCESS;
-        }
-    }
-    else if (m_cmd_queue.count != PSTORAGE_CMD_QUEUE_SIZE)
-    {
-        // Enqueue the command if it is queue is not full
+        // Enqueue the command if it is queue is not full.
         write_index = m_cmd_queue.rp + m_cmd_queue.count;
 
         if (write_index >= PSTORAGE_CMD_QUEUE_SIZE)
@@ -302,10 +333,21 @@
         m_cmd_queue.cmd[write_index].storage_addr = (*p_storage_addr);
         m_cmd_queue.cmd[write_index].size         = size;
         m_cmd_queue.cmd[write_index].offset       = offset;
+        retval                                    = NRF_SUCCESS;
+        if (m_cmd_queue.flash_access == false)
+        {
+            retval = cmd_process();
+            if (retval == NRF_ERROR_BUSY)
+            {
+                // In case of busy error code, it is possible to attempt to access flash.
+                retval = NRF_SUCCESS;
+            }
+        }
         m_cmd_queue.count++;
-
-        retval = NRF_SUCCESS;
-
+    }
+    else
+    {
+        retval = NRF_ERROR_NO_MEM;
     }
 
     return retval;
@@ -314,46 +356,35 @@
 
 /**
  * @brief Dequeues a command element.
+ *
+ * @retval    NRF_SUCCESS    on success, else an error code indicating reason for failure.
  */
 static uint32_t cmd_queue_dequeue(void)
 {
-    uint32_t retval;    
-
-    cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
-    // Update count and read pointer to process any queued requests
-    if(m_round_val >= p_cmd->size)
-    {
-        // Initialize/free the element as it is now processed.
-        cmd_queue_init_element(m_cmd_queue.rp);
-        m_round_val = 0;
-        m_cmd_queue.count--;
-        m_cmd_queue.rp++;
-    }
-
+    uint32_t retval;
     retval = NRF_SUCCESS;
 
-    // If any flash operation is enqueued, schedule
-    if (m_cmd_queue.count)
+    // If any flash operation is enqueued, schedule.
+    if (m_cmd_queue.count > 0)
     {
-        retval = process_cmd();
-
+        retval = cmd_process();
         if (retval != NRF_SUCCESS)
         {
             // Flash could be accessed by modules other than Bond Manager, hence a busy error is
-            // acceptable, but any other error needs to be indicated to the bond manager
+            // acceptable, but any other error needs to be indicated to the bond manager.
             if (retval != NRF_ERROR_BUSY)
             {
-                app_notify (retval);
+                app_notify(retval);
             }
             else
             {
-                // In case of busy next trigger will be a success or a failure event
+                // In case of busy next trigger will be a success or a failure event.
             }
         }
     }
     else
     {
-        // No flash access request pending
+        // No flash access request pending.
     }
 
     return retval;
@@ -362,14 +393,16 @@
 
 /**
  * @brief Routine to notify application of any errors.
+ *
+ * @param[in] result Result of event being notified.
  */
-static void app_notify (uint32_t result)
+static void app_notify(uint32_t result)
 {
-    pstorage_ntf_cb_t  ntf_cb;
-    uint8_t            op_code = m_cmd_queue.cmd[m_cmd_queue.rp].op_code;
-    
+    pstorage_ntf_cb_t ntf_cb;
+    uint8_t           op_code = m_cmd_queue.cmd[m_cmd_queue.rp].op_code;
+
 #ifdef PSTORAGE_RAW_MODE_ENABLE
-    if(m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr.module_id == (PSTORAGE_MAX_APPLICATIONS + 1))
+    if (m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr.module_id == RAW_MODE_APP_ID)
     {
         ntf_cb = m_raw_app_table.cb;
     }
@@ -380,24 +413,24 @@
     }
 
     // Indicate result to client.
-    // For PSTORAGE_CLEAR_OP_CODE no size is returned as the size field is used only internally 
+    // For PSTORAGE_CLEAR_OP_CODE no size is returned as the size field is used only internally
     // for clients registering multiple pages.
     ntf_cb(&m_cmd_queue.cmd[m_cmd_queue.rp].storage_addr,
            op_code,
            result,
            m_cmd_queue.cmd[m_cmd_queue.rp].p_data_addr,
-           op_code == PSTORAGE_CLEAR_OP_CODE ? 0 : m_cmd_queue.cmd[m_cmd_queue.rp].size);
+           m_cmd_queue.cmd[m_cmd_queue.rp].size);
 }
 
 
 /**
- * @brief Handles Flash Access Result Events.
+ * @brief Handles Flash Access Result Events declared in pstorage_platform.h.
+ *
+ * @param[in] sys_evt System event to be handled.
  */
-void pstorage_sys_event_handler (uint32_t sys_evt)
+void pstorage_sys_event_handler(uint32_t sys_evt)
 {
-    uint32_t retval;
-
-    retval = NRF_SUCCESS;
+    uint32_t retval = NRF_SUCCESS;
 
     // Its possible the flash access was not initiated by bond manager, hence
     // event is processed only if the event triggered was for an operation requested by the
@@ -405,41 +438,271 @@
     if (m_cmd_queue.flash_access == true)
     {
         cmd_queue_element_t * p_cmd;
+
         m_cmd_queue.flash_access = false;
+
+        if (m_swap_state == STATE_SWAP_DIRTY)
+        {
+            if (sys_evt == NRF_EVT_FLASH_OPERATION_SUCCESS)
+            {
+                m_swap_state = STATE_INIT;
+            }
+            else
+            {
+                // If clearing the swap fails, set the application back to un-initialized, to give
+                // the application a chance for a retry.
+                m_module_initialized = false;
+            }
+
+            // Schedule any queued flash access operations.
+            retval = cmd_queue_dequeue();
+            if (retval != NRF_SUCCESS)
+            {
+                app_notify(retval);
+            }
+            return;
+        }
+
         switch (sys_evt)
         {
             case NRF_EVT_FLASH_OPERATION_SUCCESS:
+            {
                 p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
-                if ((p_cmd->op_code != PSTORAGE_CLEAR_OP_CODE) || (m_round_val >= p_cmd->size))
+                m_round_val++;
+
+                const bool store_finished =
+                    ((p_cmd->op_code == PSTORAGE_STORE_OP_CODE) &&
+                     ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size));
+
+                const bool update_finished =
+                    ((p_cmd->op_code == PSTORAGE_UPDATE_OP_CODE) &&
+                     (m_swap_state == STATE_COMPLETE));
+
+                const bool clear_block_finished =
+                    ((p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) &&
+                     (m_swap_state == STATE_COMPLETE));
+
+                const bool clear_all_finished =
+                    ((p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) &&
+                     ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size) &&
+                     (m_swap_state == STATE_INIT));
+
+                if (update_finished ||
+                    clear_block_finished ||
+                    clear_all_finished ||
+                    store_finished)
                 {
+                    m_swap_state = STATE_INIT;
+
                     app_notify(retval);
+
+                    // Initialize/free the element as it is now processed.
+                    cmd_queue_element_init(m_cmd_queue.rp);
+                    m_round_val = 0;
+                    m_cmd_queue.count--;
+                    m_cmd_queue.rp++;
+
+                    if (m_cmd_queue.rp >= PSTORAGE_CMD_QUEUE_SIZE)
+                    {
+                        m_cmd_queue.rp -= PSTORAGE_CMD_QUEUE_SIZE;
+                    }
                 }
-                // Schedule any queued flash access operations
-                retval = cmd_queue_dequeue ();
+                // Schedule any queued flash access operations.
+                retval = cmd_queue_dequeue();
+
                 if (retval != NRF_SUCCESS)
                 {
                     app_notify(retval);
                 }
+            }
+            break;
 
-                break;
             case NRF_EVT_FLASH_OPERATION_ERROR:
                 app_notify(NRF_ERROR_TIMEOUT);
                 break;
+
             default:
                 // No implementation needed.
                 break;
+
         }
     }
 }
 
 
+/** @brief Function for handling flash accesses when using swap.
+ *
+ * __________________________________________________________
+ * |                       Page                             |
+ * |________________________________________________________|
+ * | head | affected body (to be updated or cleared) | tail |
+ * |______|__________________________________________|______|
+ *
+ * @param[in] p_cmd          Queue element being processed.
+ * @param[in] page_number    The affected page number.
+ * @param[in] head_word_size Size of the head in number of words.
+ * @param[in] tail_word_size Size of the tail in number of words.
+ *
+ * @retval    NRF_SUCCESS    on success, else an error code indicating reason for failure.
+ */
+static uint32_t swap_state_process(cmd_queue_element_t * p_cmd,
+                                   uint32_t              page_number,
+                                   uint32_t              head_word_size,
+                                   uint32_t              tail_word_size)
+{
+    uint32_t retval = NRF_ERROR_INTERNAL;
+
+    // Adjust entry point to state machine if needed. When we update has no head or tail its
+    // no need for using the swap.
+    if (m_swap_state == STATE_INIT)
+    {
+        if ((head_word_size == 0) && (tail_word_size == 0))
+        {
+            // Only skip swap usage if the new data fills a whole flash page.
+            m_swap_state = STATE_DATA_ERASE;
+        }
+        else
+        {
+            // Else start backing up application data to swap.
+            m_swap_state = STATE_DATA_TO_SWAP_WRITE;
+        }
+    }
+
+    switch (m_swap_state)
+    {
+        case STATE_DATA_TO_SWAP_WRITE:
+            // Backup previous content into swap page.
+            retval = sd_flash_write((uint32_t *)(PSTORAGE_SWAP_ADDR),
+                                    (uint32_t *)(page_number * PSTORAGE_FLASH_PAGE_SIZE),
+                                    PSTORAGE_FLASH_PAGE_SIZE / sizeof(uint32_t));
+            if (retval == NRF_SUCCESS)
+            {
+                m_swap_state = STATE_DATA_ERASE;
+            }
+            break;
+
+        case STATE_DATA_ERASE:
+            // Clear the application data page.
+            retval = sd_flash_page_erase(page_number);
+            if (retval == NRF_SUCCESS)
+            {
+                if (head_word_size == 0)
+                {
+                    if (tail_word_size == 0)
+                    {
+                        if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE)
+                        {
+                            m_swap_state = STATE_COMPLETE;
+                        }
+                        else
+                        {
+                            m_swap_state = STATE_NEW_BODY_WRITE;
+                        }
+                    }
+                    else
+                    {
+                        m_swap_state = STATE_TAIL_RESTORE;
+                    }
+                }
+                else
+                {
+                    m_swap_state = STATE_HEAD_RESTORE;
+                }
+            }
+            break;
+
+        case STATE_HEAD_RESTORE:
+            // Restore head from swap to application data page.
+            retval = sd_flash_write((uint32_t *)(page_number * PSTORAGE_FLASH_PAGE_SIZE),
+                                    (uint32_t *)PSTORAGE_SWAP_ADDR,
+                                    head_word_size);
+            if (retval == NRF_SUCCESS)
+            {
+                if (tail_word_size == 0)
+                {
+                    if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE)
+                    {
+                        m_swap_state = STATE_SWAP_ERASE;
+                    }
+                    else
+                    {
+                        m_swap_state = STATE_NEW_BODY_WRITE;
+                    }
+                }
+                else
+                {
+                    m_swap_state = STATE_TAIL_RESTORE;
+                }
+            }
+            break;
+
+        case STATE_TAIL_RESTORE:
+            // Restore tail from swap to application data page.
+            retval = sd_flash_write((uint32_t *)((page_number * PSTORAGE_FLASH_PAGE_SIZE) +
+                                                 (head_word_size * sizeof(uint32_t)) +
+                                                 p_cmd->size),
+                                    (uint32_t *)(PSTORAGE_SWAP_ADDR +
+                                                 (head_word_size * sizeof(uint32_t)) +
+                                                 p_cmd->size),
+                                    tail_word_size);
+            if (retval == NRF_SUCCESS)
+            {
+                if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE)
+                {
+                    m_swap_state = STATE_SWAP_ERASE;
+                }
+                else
+                {
+                    m_swap_state = STATE_NEW_BODY_WRITE;
+                }
+            }
+            break;
+
+        case STATE_NEW_BODY_WRITE:
+            // Write new data (body) to application data page.
+            retval = sd_flash_write((uint32_t *)((page_number * PSTORAGE_FLASH_PAGE_SIZE) +
+                                                 (head_word_size * sizeof(uint32_t))),
+                                    (uint32_t *)p_cmd->p_data_addr,
+                                    p_cmd->size / sizeof(uint32_t));
+            if (retval == NRF_SUCCESS)
+            {
+                if ((head_word_size == 0) && (tail_word_size == 0))
+                {
+                    m_swap_state = STATE_COMPLETE;
+                }
+                else
+                {
+                    m_swap_state = STATE_SWAP_ERASE;
+                }
+            }
+            break;
+
+        case STATE_SWAP_ERASE:
+            // Clear the swap page for subsequent use.
+            retval = sd_flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE);
+            if (retval == NRF_SUCCESS)
+            {
+                m_swap_state = STATE_COMPLETE;
+            }
+            break;
+
+        default:
+            break;
+    }
+
+    return retval;
+}
+
+
 /**
  * @brief Routine called to actually issue the flash access request to the SoftDevice.
+ *
+ * @retval    NRF_SUCCESS    on success, else an error code indicating reason for failure.
  */
-static uint32_t process_cmd(void)
+static uint32_t cmd_process(void)
 {
-    uint32_t             retval;
-    uint32_t             storage_addr;
+    uint32_t              retval;
+    uint32_t              storage_addr;
     cmd_queue_element_t * p_cmd;
 
     retval = NRF_ERROR_FORBIDDEN;
@@ -448,59 +711,105 @@
 
     storage_addr = p_cmd->storage_addr.block_id;
 
-    if (p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE)
-    {
-        // Calculate page number before copy.
-        uint32_t page_number;
-
-        page_number =  ((storage_addr / PSTORAGE_FLASH_PAGE_SIZE) +
-                        m_round_val);
-
-        retval = sd_flash_page_erase(page_number);
-
-        if (NRF_SUCCESS == retval)
-        {
-            m_round_val++;
-        }
-    }
-    else if (p_cmd->op_code == PSTORAGE_STORE_OP_CODE)
+    switch (p_cmd->op_code)
     {
-        uint32_t size;
-        uint8_t * p_data_addr = p_cmd->p_data_addr;
-    
-        p_data_addr += m_round_val;
-        
-        storage_addr += (p_cmd->offset + m_round_val);
-        
-        size = p_cmd->size - m_round_val;
-        
-        if (size < SOC_MAX_WRITE_SIZE)
+        case PSTORAGE_STORE_OP_CODE:
         {
-            retval = sd_flash_write(((uint32_t *)storage_addr),
-                                     (uint32_t *)p_data_addr,
-                                     size / sizeof(uint32_t));
+            uint32_t  size;
+            uint32_t  offset;
+            uint8_t * p_data_addr = p_cmd->p_data_addr;
+
+            offset        = (m_round_val * SOC_MAX_WRITE_SIZE);
+            size          = p_cmd->size - offset;
+            p_data_addr  += offset;
+            storage_addr += (p_cmd->offset + offset);
+
+            if (size < SOC_MAX_WRITE_SIZE)
+            {
+                retval = sd_flash_write(((uint32_t *)storage_addr),
+                                        (uint32_t *)p_data_addr,
+                                        size / sizeof(uint32_t));
+            }
+            else
+            {
+                retval = sd_flash_write(((uint32_t *)storage_addr),
+                                        (uint32_t *)p_data_addr,
+                                        SOC_MAX_WRITE_SIZE / sizeof(uint32_t));
+            }
         }
-        else
+        break;
+
+        case PSTORAGE_CLEAR_OP_CODE:
         {
-            retval = sd_flash_write(((uint32_t *)storage_addr),
-                                     (uint32_t *)p_data_addr,
-                                     SOC_MAX_WRITE_SIZE / sizeof(uint32_t));
+            // Calculate page number before clearing.
+            uint32_t page_number;
+
+            pstorage_size_t block_size =
+                m_app_table[p_cmd->storage_addr.module_id].block_size;
+
+            pstorage_size_t block_count =
+                m_app_table[p_cmd->storage_addr.module_id].block_count;
+
+            pstorage_block_t base_address =
+                m_app_table[p_cmd->storage_addr.module_id].base_id;
+
+            // If the whole module should be cleared.
+            if (((base_address == storage_addr) && (block_size * block_count == p_cmd->size)) ||
+                (p_cmd->storage_addr.module_id == RAW_MODE_APP_ID))
+            {
+                page_number = ((storage_addr / PSTORAGE_FLASH_PAGE_SIZE) + m_round_val);
+
+                retval = sd_flash_page_erase(page_number);
+            }
+            // If one block is to be erased.
+            else
+            {
+                page_number = (storage_addr / PSTORAGE_FLASH_PAGE_SIZE);
+
+                uint32_t head_word_size = (
+                    storage_addr -
+                    (page_number * PSTORAGE_FLASH_PAGE_SIZE)
+                    ) / sizeof(uint32_t);
+
+                uint32_t tail_word_size = (
+                    ((page_number + 1) * PSTORAGE_FLASH_PAGE_SIZE) -
+                    (storage_addr + p_cmd->size)
+                    ) / sizeof(uint32_t);
+
+                retval = swap_state_process(p_cmd,
+                                            page_number,
+                                            head_word_size,
+                                            tail_word_size);
+            }
         }
-        
+        break;
 
-        if (retval == NRF_SUCCESS)
+        case PSTORAGE_UPDATE_OP_CODE:
         {
-            m_round_val += SOC_MAX_WRITE_SIZE;
+            uint32_t page_number = (storage_addr / PSTORAGE_FLASH_PAGE_SIZE);
+
+            uint32_t head_word_size = (
+                storage_addr + p_cmd->offset -
+                (page_number * PSTORAGE_FLASH_PAGE_SIZE)
+                ) / sizeof(uint32_t);
+
+            uint32_t tail_word_size = (
+                ((page_number + 1) * PSTORAGE_FLASH_PAGE_SIZE) -
+                (storage_addr + p_cmd->offset + p_cmd->size)
+                ) / sizeof(uint32_t);
+
+            retval = swap_state_process(p_cmd, page_number, head_word_size, tail_word_size);
         }
+        break;
+
+        default:
+            // Should never reach here.
+            break;
     }
-    else
-    {
-        // Should never reach here.
-    }
-    
+
     if (retval == NRF_SUCCESS)
     {
-       m_cmd_queue.flash_access = true;
+        m_cmd_queue.flash_access = true;
     }
 
     return retval;
@@ -508,39 +817,47 @@
 /** @} */
 
 
-/**
- * @brief Module initialization routine to be called once by the application.
- */
 uint32_t pstorage_init(void)
 {
-    unsigned int index;
+    uint32_t retval;
+
     cmd_queue_init();
-    
+
     m_next_app_instance = 0;
-    m_next_page_addr    = PSTORAGE_DATA_START_ADDR;    
+    m_next_page_addr    = PSTORAGE_DATA_START_ADDR;
     m_round_val         = 0;
 
-    for(index = 0; index < PSTORAGE_MAX_APPLICATIONS; index++)
+    for (uint32_t index = 0; index < PSTORAGE_MAX_APPLICATIONS; index++)
     {
-        m_app_table[index].cb          = NULL;
-        m_app_table[index].block_size  = 0;
-        m_app_table[index].no_of_pages = 0;
-        m_app_table[index].block_count = 0;
+        m_app_table[index].cb           = NULL;
+        m_app_table[index].block_size   = 0;
+        m_app_table[index].num_of_pages = 0;
+        m_app_table[index].block_count  = 0;
     }
 
 #ifdef PSTORAGE_RAW_MODE_ENABLE
-    m_raw_app_table.cb          = NULL;
-    m_raw_app_table.no_of_pages = 0;
+    m_raw_app_table.cb           = NULL;
+    m_raw_app_table.num_of_pages = 0;
+    m_module_initialized         = true;
+    m_swap_state                 = STATE_INIT;
+
+    retval = NRF_SUCCESS;
+#else
+    m_swap_state = STATE_SWAP_DIRTY;
+
+    // Erase swap region in case it is dirty.
+    retval = sd_flash_page_erase(PSTORAGE_SWAP_ADDR / PSTORAGE_FLASH_PAGE_SIZE);
+    if (retval == NRF_SUCCESS)
+    {
+        m_cmd_queue.flash_access = true;
+        m_module_initialized     = true;
+    }
 #endif //PSTORAGE_RAW_MODE_ENABLE
-    
-    m_module_initialized = true;
-    return NRF_SUCCESS;
+
+    return retval;
 }
 
-/**
- * @brief Registration routine to request persistent memory of certain sizes based on
- *        application module requirements.
- */
+
 uint32_t pstorage_register(pstorage_module_param_t * p_module_param,
                            pstorage_handle_t       * p_block_id)
 {
@@ -554,16 +871,23 @@
     BLOCK_SIZE_CHECK(p_module_param->block_size);
     BLOCK_COUNT_CHECK(p_module_param->block_count, p_module_param->block_size);
 
+    // Block size should be a multiple of word size.
+    if (!((p_module_param->block_size % sizeof(uint32_t)) == 0))
+    {
+        return NRF_ERROR_INVALID_PARAM;
+    }
+
     if (m_next_app_instance == PSTORAGE_MAX_APPLICATIONS)
     {
         return NRF_ERROR_NO_MEM;
     }
 
     p_block_id->module_id = m_next_app_instance;
-    p_block_id->block_id = m_next_page_addr;
-    m_app_table[m_next_app_instance].base_id = p_block_id->block_id;
-    m_app_table[m_next_app_instance].cb = p_module_param->cb;
-    m_app_table[m_next_app_instance].block_size = p_module_param->block_size;
+    p_block_id->block_id  = m_next_page_addr;
+
+    m_app_table[m_next_app_instance].base_id     = p_block_id->block_id;
+    m_app_table[m_next_app_instance].cb          = p_module_param->cb;
+    m_app_table[m_next_app_instance].block_size  = p_module_param->block_size;
     m_app_table[m_next_app_instance].block_count = p_module_param->block_count;
 
     // Calculate number of flash pages allocated for the device.
@@ -581,20 +905,18 @@
             total_size = 0;
         }
         m_next_page_addr += PSTORAGE_FLASH_PAGE_SIZE;
-    }while(total_size >= PSTORAGE_FLASH_PAGE_SIZE);
+    }
+    while (total_size >= PSTORAGE_FLASH_PAGE_SIZE);
 
-    m_app_table[m_next_app_instance].no_of_pages = page_count;
+    m_app_table[m_next_app_instance].num_of_pages = page_count;
     m_next_app_instance++;
 
     return NRF_SUCCESS;
 }
 
 
-/**
- * @brief API to get the next block identifier.
- */
 uint32_t pstorage_block_identifier_get(pstorage_handle_t * p_base_id,
-                                       pstorage_size_t   block_num,
+                                       pstorage_size_t     block_num,
                                        pstorage_handle_t * p_block_id)
 {
     pstorage_handle_t temp_id;
@@ -604,18 +926,17 @@
     NULL_PARAM_CHECK(p_block_id);
     MODULE_ID_RANGE_CHECK(p_base_id);
 
-    temp_id = (*p_base_id);
+    temp_id           = (*p_base_id);
     temp_id.block_id += (block_num * MODULE_BLOCK_SIZE(p_base_id));
+
     BLOCK_ID_RANGE_CHECK(&temp_id);
+
     (*p_block_id) = temp_id;
 
     return NRF_SUCCESS;
 }
 
 
-/**
- * @brief API to store data persistently.
- */
 uint32_t pstorage_store(pstorage_handle_t * p_dest,
                         uint8_t           * p_src,
                         pstorage_size_t     size,
@@ -624,13 +945,18 @@
     VERIFY_MODULE_INITIALIZED();
     NULL_PARAM_CHECK(p_src);
     NULL_PARAM_CHECK(p_dest);
-    MODULE_ID_RANGE_CHECK (p_dest);
+    MODULE_ID_RANGE_CHECK(p_dest);
     BLOCK_ID_RANGE_CHECK(p_dest);
-    SIZE_CHECK(p_dest,size);
-    OFFSET_CHECK(p_dest,offset,size);
+    SIZE_CHECK(p_dest, size);
+    OFFSET_CHECK(p_dest, offset,size);
 
     // Verify word alignment.
-    if ((!is_word_aligned(p_src)) || (!is_word_aligned(p_src+offset)))
+    if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset)))
+    {
+        return NRF_ERROR_INVALID_ADDR;
+    }
+
+    if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
     {
         return NRF_ERROR_INVALID_ADDR;
     }
@@ -639,9 +965,34 @@
 }
 
 
-/**
- * @brief API to load data from persistent memory.
- */
+uint32_t pstorage_update(pstorage_handle_t * p_dest,
+                         uint8_t           * p_src,
+                         pstorage_size_t     size,
+                         pstorage_size_t     offset)
+{
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_src);
+    NULL_PARAM_CHECK(p_dest);
+    MODULE_ID_RANGE_CHECK(p_dest);
+    BLOCK_ID_RANGE_CHECK(p_dest);
+    SIZE_CHECK(p_dest, size);
+    OFFSET_CHECK(p_dest, offset, size);
+
+    // Verify word alignment.
+    if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset)))
+    {
+        return NRF_ERROR_INVALID_ADDR;
+    }
+
+    if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
+    {
+        return NRF_ERROR_INVALID_ADDR;
+    }
+
+    return cmd_queue_enqueue(PSTORAGE_UPDATE_OP_CODE, p_dest, p_src, size, offset);
+}
+
+
 uint32_t pstorage_load(uint8_t           * p_dest,
                        pstorage_handle_t * p_src,
                        pstorage_size_t     size,
@@ -650,50 +1001,73 @@
     VERIFY_MODULE_INITIALIZED();
     NULL_PARAM_CHECK(p_src);
     NULL_PARAM_CHECK(p_dest);
-    MODULE_ID_RANGE_CHECK (p_src);
+    MODULE_ID_RANGE_CHECK(p_src);
     BLOCK_ID_RANGE_CHECK(p_src);
-    SIZE_CHECK(p_src,size);
-    OFFSET_CHECK(p_src,offset,size);
+    SIZE_CHECK(p_src, size);
+    OFFSET_CHECK(p_src, offset, size);
 
     // Verify word alignment.
-    if ((!is_word_aligned (p_dest)) || (!is_word_aligned (p_dest + offset)))
+    if ((!is_word_aligned(p_dest)) || (!is_word_aligned((void *)(uint32_t)offset)))
     {
         return NRF_ERROR_INVALID_ADDR;
     }
 
-    memcpy (p_dest, (((uint8_t *)p_src->block_id) + offset), size);
+    if ((!is_word_aligned((uint32_t *)p_src->block_id)))
+    {
+        return NRF_ERROR_INVALID_ADDR;
+    }
+
+    memcpy(p_dest, (((uint8_t *)p_src->block_id) + offset), size);
+
+    m_app_table[p_src->module_id].cb(p_src, PSTORAGE_LOAD_OP_CODE, NRF_SUCCESS, p_dest, size);
 
     return NRF_SUCCESS;
 }
 
 
-/**
- * @brief API to clear data in blocks of persistent memory.
- */
 uint32_t pstorage_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
 {
     uint32_t retval;
-    uint32_t pages;
 
     VERIFY_MODULE_INITIALIZED();
     NULL_PARAM_CHECK(p_dest);
     MODULE_ID_RANGE_CHECK(p_dest);
     BLOCK_ID_RANGE_CHECK(p_dest);
 
-    pages = m_app_table[p_dest->module_id].no_of_pages;
+    if ((!is_word_aligned((uint32_t *)p_dest->block_id)))
+    {
+        return NRF_ERROR_INVALID_ADDR;
+    }
 
-    retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL , pages , 0);
+    if (
+        !(
+            ((p_dest->block_id - m_app_table[p_dest->module_id].base_id) %
+             m_app_table[p_dest->module_id].block_size) == 0
+            )
+        )
+    {
+        return NRF_ERROR_INVALID_PARAM;
+    }
+
+    retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0);
 
     return retval;
 }
 
 
+uint32_t pstorage_access_status_get(uint32_t * p_count)
+{
+    VERIFY_MODULE_INITIALIZED();
+    NULL_PARAM_CHECK(p_count);
+
+    (*p_count) = m_cmd_queue.count;
+
+    return NRF_SUCCESS;
+}
+
 #ifdef PSTORAGE_RAW_MODE_ENABLE
 
-/**
- * @brief Registration routine to request persistent memory of certain sizes based on 
- *        application module requirements.
- */
+
 uint32_t pstorage_raw_register(pstorage_module_param_t * p_module_param,
                                pstorage_handle_t       * p_block_id)
 {
@@ -707,20 +1081,17 @@
         return NRF_ERROR_NO_MEM;
     }
 
-    p_block_id->module_id = PSTORAGE_MAX_APPLICATIONS + 1;
+    p_block_id->module_id = RAW_MODE_APP_ID;
     m_raw_app_table.cb    = p_module_param->cb;
 
     return NRF_SUCCESS;
 }
 
 
-/**
- * @brief API to store data persistently.
- */
 uint32_t pstorage_raw_store(pstorage_handle_t * p_dest,
                             uint8_t           * p_src,
-                            uint32_t            size,
-                            uint32_t            offset)
+                            pstorage_size_t     size,
+                            pstorage_size_t     offset)
 {
     VERIFY_MODULE_INITIALIZED();
     NULL_PARAM_CHECK(p_src);
@@ -728,7 +1099,7 @@
     MODULE_RAW_ID_RANGE_CHECK(p_dest);
 
     // Verify word alignment.
-    if ((!is_word_aligned(p_src)) || (!is_word_aligned(p_src+offset)))
+    if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset)))
     {
         return NRF_ERROR_INVALID_ADDR;
     }
@@ -737,26 +1108,19 @@
 }
 
 
-/**
- * @brief API to clear data in blocks of persistent memory.
- */
-uint32_t pstorage_raw_clear(pstorage_handle_t * p_dest, uint32_t size)
+uint32_t pstorage_raw_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
 {
     uint32_t retval;
-    uint32_t pages;
 
     VERIFY_MODULE_INITIALIZED();
     NULL_PARAM_CHECK(p_dest);
     MODULE_RAW_ID_RANGE_CHECK(p_dest);
 
-    retval = NRF_SUCCESS;
-
-    pages = CEIL_DIV(size, PSTORAGE_FLASH_PAGE_SIZE);
-    
-    retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL , pages, 0);
+    retval = cmd_queue_enqueue(PSTORAGE_CLEAR_OP_CODE, p_dest, NULL, size, 0);
 
     return retval;
 }
 
 #endif // PSTORAGE_RAW_MODE_ENABLE
+
 #endif /* #if NEED_PSTORAGE */
--- a/nordic/nrf-sdk/app_common/app_timer.h	Fri Jul 25 10:33:52 2014 +0100
+++ b/nordic/nrf-sdk/app_common/app_timer.h	Tue Sep 02 15:50:05 2014 +0100
@@ -62,6 +62,8 @@
 #define APP_TIMER_USER_SIZE          8                          /**< Size of app_timer.timer_user_t (only for use inside APP_TIMER_BUF_SIZE()). */
 #define APP_TIMER_INT_LEVELS         3                          /**< Number of interrupt levels from where timer operations may be initiated (only for use inside APP_TIMER_BUF_SIZE()). */
 
+#define MAX_RTC_COUNTER_VAL     0x00FFFFFF                                  /**< Maximum value of the RTC counter. */
+
 /**@brief Compute number of bytes required to hold the application timer data structures.
  *
  * @param[in]  MAX_TIMERS      Maximum number of timers that can be created at any given time.
@@ -106,6 +108,8 @@
 /**@brief Timer id type. */
 typedef uint32_t app_timer_id_t;
 
+#define TIMER_NULL                  ((app_timer_id_t)(0 - 1))                   /**< Invalid timer id. */
+
 /**@brief Application timeout handler type. */
 typedef void (*app_timer_timeout_handler_t)(void * p_context);
 
@@ -249,13 +253,14 @@
  */
 uint32_t app_timer_stop_all(void);
 
-/**@brief Function for returning the current value of the RTC1 counter.
+/**@brief Function for returning the current value of the RTC1 counter. The
+ * value includes overflow bits to extend the range to 64-bits.
  *
  * @param[out] p_ticks   Current value of the RTC1 counter.
  *
  * @retval     NRF_SUCCESS   Counter was successfully read.
  */
-uint32_t app_timer_cnt_get(uint32_t * p_ticks);
+uint32_t app_timer_cnt_get(uint64_t * p_ticks);
 
 /**@brief Function for computing the difference between two RTC1 counter values.
  *
--- a/nordic/nrf-sdk/s110/ble.h	Fri Jul 25 10:33:52 2014 +0100
+++ b/nordic/nrf-sdk/s110/ble.h	Tue Sep 02 15:50:05 2014 +0100
@@ -164,7 +164,7 @@
  */
 typedef struct
 {
-  ble_gatts_enable_params_t  gatts_enable_params; /**< GATTS init options @ref ble_gatts_enable_params_t. */  
+  ble_gatts_enable_params_t  gatts_enable_params; /**< GATTS init options @ref ble_gatts_enable_params_t. */
 } ble_enable_params_t;
 
 /** @} */
@@ -188,16 +188,16 @@
  * @param[in] p_dest Pointer to buffer to be filled in with an event, or NULL to retrieve the event length. This buffer <b>must be 4-byte aligned in memory</b>.
  * @param[in, out] p_len Pointer the length of the buffer, on return it is filled with the event length.
  *
- * @details This call allows the application to pull a BLE event from the BLE stack. The application is signalled that an event is 
+ * @details This call allows the application to pull a BLE event from the BLE stack. The application is signalled that an event is
  * available from the BLE Stack by the triggering of the SD_EVT_IRQn interrupt (mapped to IRQ 22).
  * The application is free to choose whether to call this function from thread mode (main context) or directly from the Interrupt Service Routine
  * that maps to SD_EVT_IRQn. In any case however, and because the BLE stack runs at a higher priority than the application, this function should be called
- * in a loop (until @ref NRF_ERROR_NOT_FOUND is returned) every time SD_EVT_IRQn is raised to ensure that all available events are pulled from the stack. 
+ * in a loop (until @ref NRF_ERROR_NOT_FOUND is returned) every time SD_EVT_IRQn is raised to ensure that all available events are pulled from the stack.
  * Failure to do so could potentially leave events in the internal queue without the application being aware of this fact.
  * Sizing the p_dest buffer is equally important, since the application needs to provide all the memory necessary for the event to be copied into
  * application memory. If the buffer provided is not large enough to fit the entire contents of the event, @ref NRF_ERROR_DATA_SIZE will be returned
  * and the application can then call again with a larger buffer size.
- * Please note that because of the variable length nature of some events, sizeof(ble_evt_t) will not always be large enough to fit certain events, 
+ * Please note that because of the variable length nature of some events, sizeof(ble_evt_t) will not always be large enough to fit certain events,
  * and so it is the application's responsability to provide an amount of memory large enough so that the relevant event is copied in full.
  * The application may "peek" the event length by providing p_dest as a NULL pointer and inspecting the value of *p_len upon return.
  *
@@ -219,7 +219,7 @@
  *          The application has two options to handle its own application transmission buffers:
  *          - Use a simple arithmetic calculation: at boot time the application should use this function
  *          to find out the total amount of buffers available to it and store it in a variable.
- *          Every time a packet that consumes an application buffer is sent using any of the 
+ *          Every time a packet that consumes an application buffer is sent using any of the
  *          exposed functions in this BLE API, the application should decrement that variable.
  *          Conversely, whenever a @ref BLE_EVT_TX_COMPLETE event is received by the application
  *          it should retrieve the count field in such event and add that number to the same
@@ -228,11 +228,11 @@
  *          application packets available in the BLE stack's internal buffers, and therefore
  *          it can know with certainty whether it is possible to send more data or it has to
  *          wait for a @ref BLE_EVT_TX_COMPLETE event before it proceeds.
- *          - Choose to simply not keep track of available buffers at all, and instead handle the 
- *          @ref BLE_ERROR_NO_TX_BUFFERS error by queueing the packet to be transmitted and 
+ *          - Choose to simply not keep track of available buffers at all, and instead handle the
+ *          @ref BLE_ERROR_NO_TX_BUFFERS error by queueing the packet to be transmitted and
  *          try again as soon as a @ref BLE_EVT_TX_COMPLETE event arrives.
  *
- *          The API functions that <b>may</b> consume an application buffer depending on 
+ *          The API functions that <b>may</b> consume an application buffer depending on
  *          the parameters supplied to them can be found below:
  *
  *          - @ref sd_ble_gattc_write (write witout response only)
@@ -253,15 +253,15 @@
  * @details This call enables the application to add a vendor specific UUID to the BLE stack's table,
  *          for later use all other modules and APIs. This then allows the application to use the shorter,
  *          24-bit @ref ble_uuid_t format when dealing with both 16-bit and 128-bit UUIDs without having to
- *          check for lengths and having split code paths. The way that this is accomplished is by extending the 
- *          grouping mechanism that the Bluetooth SIG standard base UUID uses for all other 128-bit UUIDs. The 
- *          type field in the @ref ble_uuid_t structure is an index (relative to @ref BLE_UUID_TYPE_VENDOR_BEGIN) 
- *          to the table populated by multiple calls to this function, and the uuid field in the same structure 
- *          contains the 2 bytes at indices 12 and 13. The number of possible 128-bit UUIDs available to the 
- *          application is therefore the number of Vendor Specific UUIDs added with the help of this function times 65536, 
+ *          check for lengths and having split code paths. The way that this is accomplished is by extending the
+ *          grouping mechanism that the Bluetooth SIG standard base UUID uses for all other 128-bit UUIDs. The
+ *          type field in the @ref ble_uuid_t structure is an index (relative to @ref BLE_UUID_TYPE_VENDOR_BEGIN)
+ *          to the table populated by multiple calls to this function, and the uuid field in the same structure
+ *          contains the 2 bytes at indices 12 and 13. The number of possible 128-bit UUIDs available to the
+ *          application is therefore the number of Vendor Specific UUIDs added with the help of this function times 65536,
  *          although restricted to modifying bytes 12 and 13 for each of the entries in the supplied array.
  *
- * @note Bytes 12 and 13 of the provided UUID will not be used internally, since those are always replaced by 
+ * @note Bytes 12 and 13 of the provided UUID will not be used internally, since those are always replaced by
  * the 16-bit uuid field in @ref ble_uuid_t.
  *
  *
@@ -278,11 +278,11 @@
 
 
 /** @brief Decode little endian raw UUID bytes (16-bit or 128-bit) into a 24 bit @ref ble_uuid_t structure.
- * 
- * @details The raw UUID bytes excluding bytes 12 and 13 (i.e. bytes 0-11 and 14-15) of p_uuid_le are compared 
- * to the corresponding ones in each entry of the table of vendor specific UUIDs pouplated with @ref sd_ble_uuid_vs_add 
- * to look for a match. If there is such a match, bytes 12 and 13 are returned as p_uuid->uuid and the index 
- * relative to @ref BLE_UUID_TYPE_VENDOR_BEGIN as p_uuid->type. 
+ *
+ * @details The raw UUID bytes excluding bytes 12 and 13 (i.e. bytes 0-11 and 14-15) of p_uuid_le are compared
+ * to the corresponding ones in each entry of the table of vendor specific UUIDs pouplated with @ref sd_ble_uuid_vs_add
+ * to look for a match. If there is such a match, bytes 12 and 13 are returned as p_uuid->uuid and the index
+ * relative to @ref BLE_UUID_TYPE_VENDOR_BEGIN as p_uuid->type.
  *
  * @note If the UUID length supplied is 2, then the type set by this call will always be @ref BLE_UUID_TYPE_BLE.
  *
@@ -294,7 +294,7 @@
  * @return @ref NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
  * @return @ref NRF_ERROR_INVALID_LENGTH Invalid UUID length.
  * @return @ref NRF_ERROR_NOT_FOUND For a 128-bit UUID, no match in the populated table of UUIDs.
- */                                                 
+ */
 SVCALL(SD_BLE_UUID_DECODE, uint32_t, sd_ble_uuid_decode(uint8_t uuid_le_len, uint8_t const * const p_uuid_le, ble_uuid_t * const p_uuid));
 
 
--- a/nordic/nrf-sdk/s110/ble_hci.h	Fri Jul 25 10:33:52 2014 +0100
+++ b/nordic/nrf-sdk/s110/ble_hci.h	Tue Sep 02 15:50:05 2014 +0100
@@ -6,20 +6,20 @@
   agreement with Nordic Semiconductor.
  */
 /**
-  @addtogroup BLE_COMMON 
+  @addtogroup BLE_COMMON
   @{
 */
 
 
 #ifndef BLE_HCI_H__
-#define BLE_HCI_H__ 
+#define BLE_HCI_H__
 
 /** @defgroup BLE_HCI_STATUS_CODES Bluetooth status codes
  * @{ */
 
 #define BLE_HCI_STATUS_CODE_SUCCESS                        0x00
 #define BLE_HCI_STATUS_CODE_UNKNOWN_BTLE_COMMAND           0x01
-#define BLE_HCI_STATUS_CODE_UNKNOWN_CONNECTION_IDENTIFIER  0x02 
+#define BLE_HCI_STATUS_CODE_UNKNOWN_CONNECTION_IDENTIFIER  0x02
 /*0x03 Hardware Failure
 0x04 Page Timeout
 */
--- a/nordic/nrf-sdk/sd_common/softdevice_handler.h	Fri Jul 25 10:33:52 2014 +0100
+++ b/nordic/nrf-sdk/sd_common/softdevice_handler.h	Tue Sep 02 15:50:05 2014 +0100
@@ -71,21 +71,12 @@
  *            reinitialization).
  */
 /*lint -emacro(506, SOFTDEVICE_HANDLER_INIT) */ /* Suppress "Constant value Boolean */
-#define SOFTDEVICE_HANDLER_INIT(CLOCK_SOURCE,                                                      \
-                                USE_SCHEDULER)                                                     \
+#define SOFTDEVICE_HANDLER_INIT(CLOCK_SOURCE, USE_SCHEDULER)                                       \
     do                                                                                             \
     {                                                                                              \
-        static uint32_t EVT_BUFFER[CEIL_DIV(MAX(                                                   \
-                                                MAX(BLE_STACK_EVT_MSG_BUF_SIZE,                    \
-                                                    ANT_STACK_EVT_STRUCT_SIZE),                    \
-                                                SYS_EVT_MSG_BUF_SIZE                               \
-                                               ),                                                  \
-                                            sizeof(uint32_t))];                                    \
+        static uint32_t EVT_BUFFER[CEIL_DIV(MAX(MAX(BLE_STACK_EVT_MSG_BUF_SIZE, ANT_STACK_EVT_STRUCT_SIZE), SYS_EVT_MSG_BUF_SIZE), sizeof(uint32_t))]; \
         uint32_t ERR_CODE;                                                                         \
-        ERR_CODE = softdevice_handler_init((CLOCK_SOURCE),                                         \
-                                           EVT_BUFFER,                                             \
-                                           sizeof(EVT_BUFFER),                                     \
-                                           (USE_SCHEDULER) ? softdevice_evt_schedule : NULL);      \
+        ERR_CODE = softdevice_handler_init((CLOCK_SOURCE), EVT_BUFFER, sizeof(EVT_BUFFER), (USE_SCHEDULER) ? softdevice_evt_schedule : NULL); \
         APP_ERROR_CHECK(ERR_CODE);                                                                 \
     } while (0)
 
--- a/nordic/softdevice_handler.cpp	Fri Jul 25 10:33:52 2014 +0100
+++ b/nordic/softdevice_handler.cpp	Tue Sep 02 15:50:05 2014 +0100
@@ -235,36 +235,6 @@
         return err_code;
     }
 
-    /**
-     * Using this call, the application can select whether to include the
-     * Service Changed characteristic in the GATT Server. The default in all
-     * previous releases has been to include the Service Changed characteristic,
-     * but this affects how GATT clients behave. Specifically, it requires
-     * clients to subscribe to this attribute and not to cache attribute handles
-     * between connections unless the devices are bonded. If the application
-     * does not need to change the structure of the GATT server attributes at
-     * runtime this adds unnecessary complexity to the interaction with peer
-     * clients. If the SoftDevice is enabled with the Service Changed
-     * Characteristics turned off, then clients are allowed to cache attribute
-     * handles making applications simpler on both sides.
-     */
-    ble_enable_params_t enableParams = {
-        .gatts_enable_params = {
-            .service_changed = 0
-        }
-    };
-    if ((err_code = sd_ble_enable(&enableParams)) != NRF_SUCCESS) {
-        return err_code;
-    }
-
-    ble_gap_addr_t addr;
-    if ((err_code = sd_ble_gap_address_get(&addr)) != NRF_SUCCESS) {
-        return err_code;
-    }
-    if ((err_code = sd_ble_gap_address_set(BLE_GAP_ADDR_CYCLE_MODE_NONE, &addr)) != NRF_SUCCESS) {
-        return err_code;
-    }
-
     m_softdevice_enabled = true;
     // Enable BLE event interrupt (interrupt priority has already been set by the stack).
     return sd_nvic_EnableIRQ(SWI2_IRQn);
--- a/projectconfig.h	Fri Jul 25 10:33:52 2014 +0100
+++ b/projectconfig.h	Tue Sep 02 15:50:05 2014 +0100
@@ -88,8 +88,8 @@
 
     /*-------------------------------- TIMER ------------------------------*/
     #define CFG_TIMER_PRESCALER                        0                        /**< Value of the RTC1 PRESCALER register. freq = (32768/(PRESCALER+1)) */
-    #define CFG_TIMER_MAX_INSTANCE                     8                        /**< Maximum number of simultaneously created timers. */
-    #define CFG_TIMER_OPERATION_QUEUE_SIZE             5                        /**< Size of timer operation queues. */
+    #define CFG_TIMER_MAX_INSTANCE                     1                        /**< Maximum number of simultaneously created timers. */
+    #define CFG_TIMER_OPERATION_QUEUE_SIZE             1                        /**< Size of timer operation queues. */
 /*=========================================================================*/
 
 
@@ -97,7 +97,7 @@
     BTLE SETTINGS
     -----------------------------------------------------------------------*/
 
-    #define CFG_BLE_TX_POWER_LEVEL                     4                        /**< in dBm (Valid values are -40, -20, -16, -12, -8, -4, 0, 4) */
+    #define CFG_BLE_TX_POWER_LEVEL                     0                        /**< in dBm (Valid values are -40, -20, -16, -12, -8, -4, 0, 4) */
 
     /*---------------------------- BOND MANAGER ---------------------------*/
     #define CFG_BLE_BOND_FLASH_PAGE_BOND               (BLE_FLASH_PAGE_END-1)   /**< Flash page used for bond manager bonding information.*/
@@ -115,8 +115,8 @@
     #define CFG_GAP_APPEARANCE                         BLE_APPEARANCE_GENERIC_TAG
     #define CFG_GAP_LOCAL_NAME                         "nRF5x"
 
-    #define CFG_GAP_CONNECTION_MIN_INTERVAL_MS         500                      /**< Minimum acceptable connection interval */
-    #define CFG_GAP_CONNECTION_MAX_INTERVAL_MS         1000                     /**< Maximum acceptable connection interval */
+    #define CFG_GAP_CONNECTION_MIN_INTERVAL_MS           50                     /**< Minimum acceptable connection interval */
+    #define CFG_GAP_CONNECTION_MAX_INTERVAL_MS          500                     /**< Maximum acceptable connection interval */
     #define CFG_GAP_CONNECTION_SUPERVISION_TIMEOUT_MS  4000                     /**< Connection supervisory timeout */
     #define CFG_GAP_CONNECTION_SLAVE_LATENCY           0                        /**< Slave Latency in number of connection events. */