Sample application that shows the use of persistent storage (pstorage) in Nordic nRF51822 tigether with a BLE service

Dependencies:   BLE_API mbed

Simple example that shows the use of pstorage (persistent storage) in nRF51822

The code is based on an example proposed at Nordic Developer Zone:

https://devzone.nordicsemi.com/question/15271/how-can-i-write-10kb-of-data-to-internal-flash/?answer=17300#post-id-17300

Revision:
0:49d5cce77458
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Thu Mar 05 14:46:16 2015 +0000
@@ -0,0 +1,408 @@
+// Sample app that shows the use of persistent staprage in nRF51822 (pstorage) together with BLE
+// Based on the sample code proposed at Nordic developers forum:
+// https://devzone.nordicsemi.com/question/15271/how-can-i-write-10kb-of-data-to-internal-flash/?answer=17300#post-id-17300
+// https://devzone.nordicsemi.com/attachment/9b7ebaa65cd8f4f0eeb9d8fd99937c54
+
+#include "mbed.h"
+
+#include "BLEDevice.h"
+
+#include "UARTService.h"
+
+#include "pstorage.h"
+
+#include "nrf_error.h"
+
+
+DigitalOut magnet(p15);
+
+#define MAGNET_ON 1
+#define MAGNET_OFF 0
+Ticker ticker;
+int tickerState=MAGNET_OFF;
+
+#define NEED_CONSOLE_OUTPUT 1 /* Set this if you need debug messages on the console;
+                               * it will have an impact on code-size and power consumption. */
+
+#if NEED_CONSOLE_OUTPUT
+#define DEBUG(...) { printf(__VA_ARGS__); }  //Defaults to stdio without having to wirte pcUart explicitly
+#else
+#define DEBUG(...) /* nothing */
+#endif /* #if NEED_CONSOLE_OUTPUT */
+
+Serial pcUart(USBTX, USBRX); // tx, rx Still required to read data coming from the PC
+
+BLEDevice  ble;                               // Create Bluetooth object
+
+UARTService *uartServicePtr;
+
+
+#define PS_NOT_INIT 0
+#define PS_WAITING_FOR_NEXT_COMMAND 1
+//#define PS_STATE_INIT_AND_REGISTER 2
+#define PS_CLEAR_3_BLOCKS 3
+#define PS_STORE_ALL 4
+#define PS_CLEAR_2_BLOCKS 5
+#define PS_UPDATE_1_BLCK 6
+
+uint8_t psState= PS_NOT_INIT;
+uint8_t psNextState= PS_WAITING_FOR_NEXT_COMMAND;
+
+pstorage_handle_t       handle;
+pstorage_handle_t               block_0_handle;
+pstorage_handle_t               block_1_handle;
+pstorage_handle_t               block_2_handle;
+pstorage_module_param_t param;
+uint8_t                 source_data_0[16] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F};
+uint8_t                 source_data_1[16] = {0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F};
+uint8_t                 source_data_2[16] = {0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F};
+uint8_t                 source_data_9[16] = {0x39, 0x38, 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x30, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34};
+        uint8_t                 dest_data_0[16];
+        uint8_t                 dest_data_1[16];
+        uint8_t                 dest_data_2[16];
+
+
+static void psLoadAllBlocks(void);
+
+#define PS_NOT_INIT 0
+#define PS_WAITING_FOR_NEXT_COMMAND 1
+//#define PS_STATE_INIT_AND_REGISTER 2
+#define PS_CLEAR_3_BLOCKS 3
+#define PS_STORE_ALL 4
+#define PS_CLEAR_2_BLOCKS 5
+#define PS_UPDATE_1_BLCK 6
+
+
+
+
+
+void magnetControl(void)
+{
+
+    DEBUG("Timer\r\n");
+    DEBUG("Timer State %d \r\n",tickerState);
+       
+    if (tickerState==MAGNET_ON) {
+            magnet=1; 
+            tickerState=MAGNET_OFF;
+    } else  { // (tickerState==MAGNET_OFF) 
+            magnet=0;
+            tickerState=MAGNET_OFF;
+            ticker.detach();
+    }
+}
+
+/* BLE disconnected callback */
+void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason)
+{
+    DEBUG("Disconnected!\n\r");
+    DEBUG("Restarting the advertising process\n\r");
+    ble.startAdvertising();
+}
+
+/* BLE UART data received callback */
+void onDataWritten(const GattCharacteristicWriteCBParams *params)
+{
+    if ((uartServicePtr != NULL) && (params->charHandle == uartServicePtr->getTXCharacteristicHandle())) {     //If characters received over BLE
+        uint16_t bytesRead = params->len;
+        DEBUG("received %u bytes\n\r", bytesRead);
+        DEBUG("Received string: '");
+        //Note the size of data expands to the largest string received. Need to use bytesRead to resize.
+        for (int i=0;i<bytesRead; i++) {
+          DEBUG("%c",params->data[i]);      
+        }
+        DEBUG("'\n\r");       
+       // ble.updateCharacteristicValue(uartServicePtr->getRXCharacteristicHandle(), params->data,bytesRead);   // Echo received characters back over BLE
+    }
+    ticker.detach();
+    tickerState=MAGNET_ON;
+    ticker.attach(magnetControl,0.7);
+}
+
+/* pcUART read callback */
+void rxInterrupt(void)
+{
+     while (pcUart.readable()) {
+         if (pcUart.readable()) {
+            char s[2];
+            s[1]=0;
+            s[0]=pcUart.getc();
+            if (s[0]=='0') psLoadAllBlocks();
+           if (psState==PS_WAITING_FOR_NEXT_COMMAND){
+             switch(s[0]) {
+               case '1':
+                 psNextState=PS_CLEAR_3_BLOCKS;
+                 break;    
+               case '2':
+                 psNextState=PS_STORE_ALL;
+                 break;    
+               case '3':
+                 psNextState=PS_CLEAR_2_BLOCKS;
+                 break;    
+               case '4':
+                 psNextState=PS_UPDATE_1_BLCK;
+                 break;    
+               default:
+                 break;
+              }
+            }
+             //       DEBUG("-%c_",s[0]);   
+            uartServicePtr->write(s,1);
+         }
+    }  
+}
+
+static void checkPsState(pstorage_block_t blockId) {
+ if (psState==PS_CLEAR_3_BLOCKS )  {
+     psState=PS_WAITING_FOR_NEXT_COMMAND;
+     return;
+ }
+ if ((psState==PS_STORE_ALL )&&(blockId==block_2_handle.block_id))  {
+     psState=PS_WAITING_FOR_NEXT_COMMAND;
+     return;
+ }
+ if (psState==PS_CLEAR_2_BLOCKS )  {
+     psState=PS_WAITING_FOR_NEXT_COMMAND;
+     return;
+ }
+ if (psState==PS_UPDATE_1_BLCK )  {
+     psState=PS_WAITING_FOR_NEXT_COMMAND;
+     return;
+ } 
+}
+
+static void example_cb_handler(pstorage_handle_t  * handle,
+                               uint8_t              op_code,
+                               uint32_t             result,
+                               uint8_t            * p_data,
+                               uint32_t             data_len)
+{
+        checkPsState(handle->block_id);
+        DEBUG("ps handler\r\n"); 
+        switch(op_code)
+        {
+            case PSTORAGE_LOAD_OP_CODE:
+                 if (result == NRF_SUCCESS)
+                 {
+                    DEBUG("ps LOAD ok %d \r\n",handle->block_id);
+                 }
+                 else
+                 {
+                    DEBUG("ps LOAD Failed %d %d \r\n",handle->block_id, result);                 
+                 }
+                 break;
+            case PSTORAGE_STORE_OP_CODE:
+                 if (result == NRF_SUCCESS)
+                 {
+                     DEBUG("ps STORE ok %d \r\n",handle->block_id);
+                 }
+                 else
+                 {
+                    DEBUG("ps STORE Failed %d %d \r\n",handle->block_id, result);                 
+                 }                 
+                 break;              
+            case PSTORAGE_UPDATE_OP_CODE:
+                 if (result == NRF_SUCCESS)
+                 {
+                    DEBUG("ps UPDATE ok %d \r\n",handle->block_id);
+                 }
+                 else
+                 {
+                    DEBUG("ps UPDATE Failed %d %d \r\n",handle->block_id, result);                 
+                 }
+                 break;
+            case PSTORAGE_CLEAR_OP_CODE:
+                 if (result == NRF_SUCCESS)
+                 {
+                     DEBUG("ps CLEAR ok %d \r\n",handle->block_id);
+                 }
+                 else
+                 {
+                    DEBUG("ps CLEAR Failed %d %d \r\n",handle->block_id, result);                 
+                 }
+                 break;
+            case PSTORAGE_ERROR_OP_CODE:
+                 DEBUG("ps ERROR %d \r\n",handle->block_id);                 
+                 break;              
+        }           
+}
+
+
+static void psInit(void)
+{
+        uint32_t retval;   
+        retval = pstorage_init();
+        if(retval != NRF_SUCCESS)
+        {
+            DEBUG("ps init error\r\n");
+            return;
+        }  else  {
+         DEBUG("ps init ok\r\n");
+        }
+         
+        param.block_size  = 16;                   //Select block size of 16 bytes
+        param.block_count = 10;                   //Select 10 blocks, total of 160 bytes
+        param.cb          = example_cb_handler;   //Set the pstorage callback handler
+            
+        retval = pstorage_register(&param, &handle);
+        if (retval != NRF_SUCCESS)
+        {
+            DEBUG("ps register error\r\n");
+            return;
+        }  else  {
+         DEBUG("ps register ok\r\n");
+        }        
+        //Get block identifiers
+        pstorage_block_identifier_get(&handle, 0, &block_0_handle);
+        pstorage_block_identifier_get(&handle, 1, &block_1_handle);
+        pstorage_block_identifier_get(&handle, 2, &block_2_handle);
+        
+        DEBUG("ps identifier get OK\r\n");
+        psState=PS_WAITING_FOR_NEXT_COMMAND;
+        psNextState= PS_WAITING_FOR_NEXT_COMMAND;
+}
+
+
+static void psClear3Blocks(void) {
+    uint32_t retval;   
+    psState= PS_CLEAR_3_BLOCKS;
+    retval= pstorage_clear(&block_0_handle, 48);                       //Clear 48 bytes
+    if (retval != NRF_SUCCESS)
+    {
+        DEBUG("ps clear error\r\n");
+            psState=PS_WAITING_FOR_NEXT_COMMAND;
+            return;
+        }  else  {
+         DEBUG("ps clear ok\r\n");
+        }        
+}
+
+static void psStoreAll(void) {
+    uint32_t retval;   
+    psState= PS_STORE_ALL;
+    retval= pstorage_store(&block_0_handle, source_data_0, 16, 0);     
+    if (retval != NRF_SUCCESS) {
+        DEBUG("ps store block 0 error\r\n");
+        psState=PS_WAITING_FOR_NEXT_COMMAND;
+        return;
+    }  else  {
+        DEBUG("ps store block 0 ok\r\n");
+    }     
+      
+    retval= pstorage_store(&block_1_handle, source_data_1, 16, 0);
+    if (retval != NRF_SUCCESS) {
+        DEBUG("ps store block 1 error\r\n");
+        psState=PS_WAITING_FOR_NEXT_COMMAND;
+        return;
+    }  else  {
+        DEBUG("ps store block 1 ok\r\n");
+    }       
+    
+    retval= pstorage_store(&block_2_handle, source_data_2, 16, 0);
+    if (retval != NRF_SUCCESS) {
+        DEBUG("ps store block 2 error\r\n");
+        psState=PS_WAITING_FOR_NEXT_COMMAND;
+        return;
+    }  else  {
+        DEBUG("ps store block 2 ok\r\n");
+    }  
+    
+    uint32_t    count;   
+    retval = pstorage_access_status_get(&count);
+    DEBUG("ps pending %d returncode %d\r\n", count,retval);
+}
+        
+static void psClear2Blocks(void) {
+    uint32_t  retval;   
+    psState= PS_CLEAR_2_BLOCKS;
+    retval= pstorage_clear(&block_0_handle, 32);                       //Clear 32 bytes
+    if (retval != NRF_SUCCESS) {
+        DEBUG("ps clear error\r\n");
+        psState=PS_WAITING_FOR_NEXT_COMMAND;
+        return;
+    } else {
+        DEBUG("ps clear ok\r\n");
+    }        
+}       
+
+ 
+static void psUpdate1Block(void) {
+    uint32_t  retval;   
+    psState= PS_UPDATE_1_BLCK;
+    retval=pstorage_update(&block_0_handle, source_data_9, 16, 0);
+    if (retval != NRF_SUCCESS) {
+        DEBUG("ps clear error\r\n");
+        psState=PS_WAITING_FOR_NEXT_COMMAND;
+        return;
+    } else {
+        DEBUG("ps clear ok\r\n");
+    }        
+}  
+ 
+static void psLoadAllBlocks(void) {       
+        pstorage_load(dest_data_0, &block_0_handle, 16, 0);             
+        pstorage_load(dest_data_1, &block_1_handle, 16, 0);           
+        pstorage_load(dest_data_2, &block_2_handle, 16, 0); 
+        dest_data_0[15]=0;
+        dest_data_1[15]=0;
+        dest_data_2[15]=0;                
+        DEBUG ("Zero:  %s\r\n",  dest_data_0);       
+        DEBUG ("One:  %s\r\n",  dest_data_1);       
+        DEBUG ("Two:  %s\r\n",  dest_data_2);       
+}
+
+
+int main(void)
+{
+
+    magnet=0;
+    tickerState=MAGNET_OFF;
+    
+    // Not used so not enabled
+    pcUart.attach(&rxInterrupt,Serial::RxIrq);  //interrupt for incoming data available from PC connection
+    
+    //ticker.attach(periodicCallback, 0.1);
+    
+    DEBUG("Initialising the nRF51822\n\r");
+    ble.init();
+    psInit();
+    ble.onDisconnection(disconnectionCallback);                                            // Define callback function for BLE disconnection event
+    ble.onDataWritten(onDataWritten);                                                      // Define callback function for BLE Data received event
+
+    /* setup advertising */
+    ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED);             // Indicate that Legacy Bluetooth in not supported
+    ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
+    ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME,
+                                     (const uint8_t *)"B_MAGNET", sizeof("B_MAGNET") - 1);
+    ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,
+                                     (const uint8_t *)UARTServiceUUID_reversed, sizeof(UARTServiceUUID_reversed));
+
+    ble.setAdvertisingInterval(Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(500));          // Set advertising interval to 1 second
+    ble.startAdvertising();                                                               // Start advertising
+
+    UARTService uartService(ble);                                                         // Create BLE UART service
+    uartServicePtr = &uartService;                                                        // Initalise pointer to point to UART Service
+  
+    while (true) {
+        if ((psState==PS_WAITING_FOR_NEXT_COMMAND)&&(psNextState!=PS_WAITING_FOR_NEXT_COMMAND)){
+          switch(psNextState) {
+              case PS_CLEAR_3_BLOCKS:
+                psClear3Blocks();
+                break;              
+              case PS_STORE_ALL:
+                psStoreAll();
+                break;
+              case PS_CLEAR_2_BLOCKS:
+                psClear2Blocks();                
+                break;
+              case PS_UPDATE_1_BLCK:
+                 psUpdate1Block();               
+                break;                                
+              default:
+                DEBUG ("Unexpected next pstorage state");
+          }
+          psNextState= PS_WAITING_FOR_NEXT_COMMAND;
+        }
+        ble.waitForEvent();                                                               // Wait for BLE events
+    }
+}