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

main.cpp

Committer:
tumaku
Date:
2015-03-05
Revision:
1:b8cefa34f89d
Parent:
0:49d5cce77458

File content as of revision 1:b8cefa34f89d:

// 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
    }
}