Sample application that shows the use of persistent storage (pstorage) in Nordic nRF51822 tigether with a BLE service
Simple example that shows the use of pstorage (persistent storage) in nRF51822
The code is based on an example proposed at Nordic Developer Zone:
Diff: main.cpp
- 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(¶m, &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 + } +}