This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

dealing large data packet's through ble

Hi, I need to send(using BLE) large amount of data's, which are collected by the accelerometer sensor for 1 hour. I have an external NOR flash where the accelerometer data's are stored and from there data's are transmitted to the BLE stack when sync occurs. I am using nRF51822 nordic controller. Assume that, data size will be 50KB.

Regards, Balaji

Parents
  • Try something like this...

    
    static uint8_t packets=0;
    while(true)
    { 
    	err_code = ble_hrs_heart_rate_measurement_send(&m_hrs, packets, 0);
    	if (err_code == NRF_ERROR_INVALID_STATE || err_code == BLE_ERROR_GATTS_SYS_ATTR_MISSING)
    	{ 
    		break;
    	}
    	else if (err_code == BLE_ERROR_NO_TX_BUFFERS)
    	{ 
    		// We will try to maximize throughput, so we don't stop sending (quit the while loop) before we reach BLE_ERROR_NO_TX_BUFFERS state
    		break; 
    	}
    	else if (err_code != NRF_SUCCESS) 
    	{
    		APP_ERROR_HANDLER(err_code);
    	}
    	// At this point the packet handed to the "ble_hrs_heart_rate_measurement_send" is considered sent
    	// Prepare the next
    	packet++
    }
    
    
Reply
  • Try something like this...

    
    static uint8_t packets=0;
    while(true)
    { 
    	err_code = ble_hrs_heart_rate_measurement_send(&m_hrs, packets, 0);
    	if (err_code == NRF_ERROR_INVALID_STATE || err_code == BLE_ERROR_GATTS_SYS_ATTR_MISSING)
    	{ 
    		break;
    	}
    	else if (err_code == BLE_ERROR_NO_TX_BUFFERS)
    	{ 
    		// We will try to maximize throughput, so we don't stop sending (quit the while loop) before we reach BLE_ERROR_NO_TX_BUFFERS state
    		break; 
    	}
    	else if (err_code != NRF_SUCCESS) 
    	{
    		APP_ERROR_HANDLER(err_code);
    	}
    	// At this point the packet handed to the "ble_hrs_heart_rate_measurement_send" is considered sent
    	// Prepare the next
    	packet++
    }
    
    
Children
  • Hi all,

    I just seen this post and it seems to be useful to me. In my application I want to send 1000 samples in 1 second using 84 packets each of 12 samples(18 bytes + 2bytes for sequencing). How can I implement this using UART profile. I am trying it but i am not getting 84 packets in one second(getting only 7 packets). Please help me in this regards.I am using APP_timer to sample SAADC. following is the complete code

    		#include <stdint.h>
    	#include <string.h>
    	#include "nordic_common.h"
    	#include "nrf.h"
    	#include "ble_hci.h"
    	#include "ble_advdata.h"
    	#include "ble_advertising.h"
    	#include "ble_conn_params.h"
    	#include "softdevice_handler.h"
    	#include "app_timer.h"
    	#include "app_button.h"
    	#include "ble_nus.h"
    	#include "app_uart.h"
    	#include "app_util_platform.h"
    	#include "bsp.h"
    	#include "bsp_btn_ble.h"
    
    	#include "nrf_drv_saadc.h"
    
    	#define IS_SRVC_CHANGED_CHARACT_PRESENT 0                                           /**< Include the service_changed characteristic. If not enabled, the server's database cannot be changed for the lifetime of the device. */
    
    	#define CENTRAL_LINK_COUNT              0                                           /**< Number of central links used by the application. When changing this number remember to adjust the RAM settings*/
    	#define PERIPHERAL_LINK_COUNT           1                                           /**< Number of peripheral links used by the application. When changing this number remember to adjust the RAM settings*/
    
    	#define DEVICE_NAME                     "Nordic_UART"                               /**< Name of device. Will be included in the advertising data. */
    	#define NUS_SERVICE_UUID_TYPE           BLE_UUID_TYPE_VENDOR_BEGIN                  /**< UUID type for the Nordic UART Service (vendor specific). */
    
    	#define APP_ADV_INTERVAL                300                                          /**< The advertising interval (in units of 0.625 ms. This value corresponds to 40 ms). */
    	#define APP_ADV_TIMEOUT_IN_SECONDS      180                                         /**< The advertising timeout (in units of seconds). */
    
    	#define APP_TIMER_PRESCALER             0                                           /**< Value of the RTC1 PRESCALER register. */
    	#define APP_TIMER_OP_QUEUE_SIZE         4                                           /**< Size of timer operation queues. */
    
    	#define MIN_CONN_INTERVAL               MSEC_TO_UNITS(50, UNIT_1_25_MS)             /**< Minimum acceptable connection interval (20 ms), Connection interval uses 1.25 ms units. */
    	#define MAX_CONN_INTERVAL               MSEC_TO_UNITS(100, UNIT_1_25_MS)             /**< Maximum acceptable connection interval (75 ms), Connection interval uses 1.25 ms units. */
    	#define SLAVE_LATENCY                   0                                           /**< Slave latency. */
    	#define CONN_SUP_TIMEOUT                MSEC_TO_UNITS(4000, UNIT_10_MS)             /**< Connection supervisory timeout (4 seconds), Supervision Timeout uses 10 ms units. */
    	#define FIRST_CONN_PARAMS_UPDATE_DELAY  APP_TIMER_TICKS(5000, APP_TIMER_PRESCALER)  /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (5 seconds). */
    	#define NEXT_CONN_PARAMS_UPDATE_DELAY   APP_TIMER_TICKS(30000, APP_TIMER_PRESCALER) /**< Time between each call to sd_ble_gap_conn_param_update after the first call (30 seconds). */
    	#define MAX_CONN_PARAMS_UPDATE_COUNT    3                                           /**< Number of attempts before giving up the connection parameter negotiation. */
    
    	#define DEAD_BEEF                       0xDEADBEEF                                  /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */
    
    	#define UART_TX_BUF_SIZE                256                                         /**< UART TX buffer size. */
    	#define UART_RX_BUF_SIZE                256                                         /**< UART RX buffer size. */
    
    	static ble_nus_t                        m_nus;                                      /**< Structure to identify the Nordic UART Service. */
    	static uint16_t                         m_conn_handle = BLE_CONN_HANDLE_INVALID;    /**< Handle of the current connection. */
    	static ble_uuid_t                       m_adv_uuids[] = {{BLE_UUID_NUS_SERVICE, NUS_SERVICE_UUID_TYPE}};  /**< Universally unique service identifier. */
    
    	#define BATTERY_LEVEL_MEAS_INTERVAL    	APP_TIMER_TICKS(10, APP_TIMER_PRESCALER) /**< Battery level measurement interval (ticks). */
    	APP_TIMER_DEF(m_battery_timer_id); 
    
    	bool send_data_flag = false;
    
    	//========================================================SAADC and BATTERY===============================================
    	#define SAADC_CALIBRATION_INTERVAL 100              //Determines how often the SAADC should be calibrated relative to NRF_DRV_SAADC_EVT_DONE event. E.g. value 5 will make the SAADC calibrate every fifth time the NRF_DRV_SAADC_EVT_DONE is received.
    	#define SAADC_SAMPLES_IN_BUFFER 12                //Number of SAADC samples in RAM before returning a SAADC event. For low power SAADC set this constant to 1. Otherwise the EasyDMA will be enabled for an extended time which consumes high current.
    	#define SAADC_OVERSAMPLE NRF_SAADC_OVERSAMPLE_4X  //Oversampling setting for the SAADC. Setting oversample to 4x This will make the SAADC output a single averaged value when the SAMPLE task is triggered 4 times. Enable BURST mode to make the SAADC sample 4 times when triggering SAMPLE task once.
    	#define SAADC_BURST_MODE 1                        //Set to 1 to enable BURST mode, otherwise set to 0.
    
    	void saadc_init(void);
    
    	static nrf_saadc_value_t       m_buffer_pool[2][SAADC_SAMPLES_IN_BUFFER];
    	static uint32_t                m_adc_evt_counter = 0;
    	uint8_t seq_num = 0;
    	static bool                    m_saadc_initialized = false;    
    	nrf_saadc_value_t *      data_buffer;
    
    	void send_to_app(uint8_t *buff)
    	{
    
    			uint32_t    err_code;
    
    					buff[0] = seq_num;
    					err_code = ble_nus_string_send(&m_nus, buff, 20);
    					if (err_code != NRF_ERROR_INVALID_STATE)
    					{
    						APP_ERROR_CHECK(err_code);
    					}	
    
    			seq_num++;
    	}
    
    	void packet_form(nrf_drv_saadc_evt_t const * p_event)
    	{
    			uint32_t test = 0x0FFFFFF0,temp=0;
    			uint8_t buff[20]={0},i=0;
    			nrf_saadc_value_t *      ADC_values;
    			ADC_values = p_event->data.done.p_buffer;
    			for(i=0;i<=30;i=i+6)
    			{ 
    			temp = ((((uint32_t)((ADC_values[i/3]<<16) | (ADC_values[(i/3)+1]<<4)))) & test);
    			//printf("%x\r\n",temp);
    			buff[(i/2)+1] = (uint8_t)(temp >> 20);
    			buff[(i/2)+2] = (uint8_t)(temp >> 12);
    			buff[(i/2)+3] = (uint8_t)(temp >> 4);
    			}
    			send_to_app(buff);
    			//printf("buff[]=\n\r%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\t%x\n\r",buff[0],buff[1],buff[2],buff[3],buff[4],buff[5],buff[6],buff[7],buff[8],buff[9],buff[10],buff[11],buff[12],buff[13],buff[14],buff[15],buff[16],buff[17],buff[18],buff[19]);
    	}
    	void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
    	{
    			if (p_event->type == NRF_DRV_SAADC_EVT_DONE)                                                        //Capture offset calibration complete event
    			{
    					ret_code_t err_code;
    					nrf_saadc_value_t *      ADC_values;
    				
    					LEDS_INVERT(BSP_LED_1_MASK);   
    					 //printf("Event Done")     ;                                                   //Toggle LED2 to indicate SAADC buffer full		
    
    					if((m_adc_evt_counter % SAADC_CALIBRATION_INTERVAL) == 0)                                       //Evaluate if offset calibration should be performed. Configure the SAADC_CALIBRATION_INTERVAL constant to change the calibration frequency
    					{
    
    							//printf("SAADC calibration starting...  \r\n");                                              //Print on UART
    						
    							NRF_SAADC->EVENTS_CALIBRATEDONE = 0;                                                        //Clear the calibration event flag
    							nrf_saadc_task_trigger(NRF_SAADC_TASK_CALIBRATEOFFSET);                                     //Trigger calibration task
    							while(!NRF_SAADC->EVENTS_CALIBRATEDONE);                                                    //Wait until calibration task is completed. The calibration tasks takes about 1000us with 10us acquisition time. Configuring shorter or longer acquisition time will make the calibration take shorter or longer respectively.
    							while(NRF_SAADC->STATUS == (SAADC_STATUS_STATUS_Busy << SAADC_STATUS_STATUS_Pos));          //Additional wait for busy flag to clear. Without this wait, calibration is actually not completed. This may take additional 100us - 300us
    							LEDS_INVERT(BSP_LED_2_MASK);                                                                //Toggle LED3 to indicate SAADC calibration complete
    
    							//printf("SAADC calibration complete ! \r\n");                                                //Print on UART
    
    					}  
    					err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAADC_SAMPLES_IN_BUFFER);  //Set buffer so the SAADC can write to it again. This is either "buffer 1" or "buffer 2"
    					APP_ERROR_CHECK(err_code);
    					
    					ADC_values = p_event->data.done.p_buffer;
    					packet_form(p_event);
    					//printf("ADC event number: %d\r\n",(int)m_adc_evt_counter);                                      //Print the event number on UART
    				 /*for (int i = 0; i < SAADC_SAMPLES_IN_BUFFER; i++)
    					{
    						 printf("%x\r\n", ADC_values[i]);                                           //Print the SAADC result on UART
    					}*/
    					data_buffer = p_event->data.done.p_buffer;
    					m_adc_evt_counter++;
    				
    					nrf_drv_saadc_uninit();                                                                   //Unintialize SAADC to disable EasyDMA and save power
    					NRF_SAADC->INTENCLR = (SAADC_INTENCLR_END_Clear << SAADC_INTENCLR_END_Pos);               //Disable the SAADC interrupt
    					NVIC_ClearPendingIRQ(SAADC_IRQn);                                                         //Clear the SAADC interrupt if set
    					m_saadc_initialized = false;                                                              //Set SAADC as uninitialized
    			}
    	}
    
    	void saadc_init(void)
    	{
    			ret_code_t err_code;
    			nrf_drv_saadc_config_t saadc_config;
    			nrf_saadc_channel_config_t channel_config;
    		
    			//Configure SAADC
    			saadc_config.resolution = NRF_SAADC_RESOLUTION_12BIT;                                 //Set SAADC resolution to 12-bit. This will make the SAADC output values from 0 (when input voltage is 0V) to 2^12=2048 (when input voltage is 3.6V for channel gain setting of 1/6).
    			saadc_config.oversample = SAADC_OVERSAMPLE;                                           //Set oversample to 4x. This will make the SAADC output a single averaged value when the SAMPLE task is triggered 4 times.
    			saadc_config.interrupt_priority = APP_IRQ_PRIORITY_LOW;                               //Set SAADC interrupt to low priority.
    		
    			//Initialize SAADC
    			err_code = nrf_drv_saadc_init(&saadc_config, saadc_callback);                         //Initialize the SAADC with configuration and callback function. The application must then implement the saadc_callback function, which will be called when SAADC interrupt is triggered
    			APP_ERROR_CHECK(err_code);
    			
    			//Configure SAADC channel
    			channel_config.reference = NRF_SAADC_REFERENCE_VDD4;                               //Set internal reference of fixed 0.6 volts
    			channel_config.gain = NRF_SAADC_GAIN1_6;                                              //Set input gain to 1/6. The maximum SAADC input voltage is then 0.6V/(1/6)=3.6V. The single ended input range is then 0V-3.6V
    			channel_config.acq_time = NRF_SAADC_ACQTIME_10US;                                     //Set acquisition time. Set low acquisition time to enable maximum sampling frequency of 200kHz. Set high acquisition time to allow maximum source resistance up to 800 kohm, see the SAADC electrical specification in the PS. 
    			channel_config.mode = NRF_SAADC_MODE_SINGLE_ENDED;                                    //Set SAADC as single ended. This means it will only have the positive pin as input, and the negative pin is shorted to ground (0V) internally.
    			channel_config.pin_p = NRF_SAADC_INPUT_AIN0;                                          //Select the input pin for the channel. AIN0 pin maps to physical pin P0.02.
    			channel_config.pin_n = NRF_SAADC_INPUT_DISABLED;                                      //Since the SAADC is single ended, the negative pin is disabled. The negative pin is shorted to ground internally.
    			channel_config.resistor_p = NRF_SAADC_RESISTOR_DISABLED;                              //Disable pullup resistor on the input pin
    			channel_config.resistor_n = NRF_SAADC_RESISTOR_DISABLED;                              //Disable pulldown resistor on the input pin
    
    		
    			//Initialize SAADC channel
    			err_code = nrf_drv_saadc_channel_init(0, &channel_config);                            //Initialize SAADC channel 0 with the channel configuration
    			APP_ERROR_CHECK(err_code);
    			
    			if(SAADC_BURST_MODE)
    			{
    					NRF_SAADC->CH[0].CONFIG |= 0x01000000;                                            //Configure burst mode for channel 0. Burst is useful together with oversampling. When triggering the SAMPLE task in burst mode, the SAADC will sample "Oversample" number of times as fast as it can and then output a single averaged value to the RAM buffer. If burst mode is not enabled, the SAMPLE task needs to be triggered "Oversample" number of times to output a single averaged value to the RAM buffer.		
    			}
    
    			err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0],SAADC_SAMPLES_IN_BUFFER);    //Set SAADC buffer 1. The SAADC will start to write to this buffer
    			APP_ERROR_CHECK(err_code);
    			
    			err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1],SAADC_SAMPLES_IN_BUFFER);    //Set SAADC buffer 2. The SAADC will write to this buffer when buffer 1 is full. This will give the applicaiton time to process data in buffer 1.
    			APP_ERROR_CHECK(err_code);
    
    	}
    
    
    
    
    	/**@brief Function for handling the Battery measurement timer timeout.
    	 *
    	 * @details This function will be called each time the battery level measurement timer expires.
    	 *
    	 * @param[in] p_context  Pointer used for passing some arbitrary information (context) from the
    	 *                       app_start_timer() call to the timeout handler.
    	 */
    	static void battery_level_meas_timeout_handler(void * p_context)
    	{
    
    			UNUSED_PARAMETER(p_context);
    			LEDS_INVERT(BSP_LED_2_MASK);                                   //Toggle LED1 to indicate SAADC sampling start
    		
    			if(!m_saadc_initialized)
    			{
    					saadc_init();                                              //Initialize the SAADC. In the case when SAADC_SAMPLES_IN_BUFFER > 1 then we only need to initialize the SAADC when the the buffer is empty.
    			}
    			m_saadc_initialized = true;                                    //Set SAADC as initialized
    			nrf_drv_saadc_sample();                                    //Trigger the SAADC SAMPLE task		
    
    	}
    	//========================================================SAADC and BATTERY END===========================================
    	//========================================================TIMER start ===========================================
    
    	static void timers_init(void)
    	{
    			uint32_t err_code;
    
    			// Initialize timer module.
    			APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false);
    
    			// Create timers.
    			err_code = app_timer_create(&m_battery_timer_id,
    																	APP_TIMER_MODE_REPEATED,
    																	battery_level_meas_timeout_handler);
    			APP_ERROR_CHECK(err_code);
    
    	}
    	static void application_timers_start(void)
    	{
    			uint32_t err_code;
    
    			// Start application timers.
    			err_code = app_timer_start(m_battery_timer_id, BATTERY_LEVEL_MEAS_INTERVAL, NULL);
    			APP_ERROR_CHECK(err_code);
    
    	}
    	//========================================================TIMER Stop ===========================================
    
    
    	/**@brief Function for assert macro callback.
    	 *
    	 * @details This function will be called in case of an assert in the SoftDevice.
    	 *
    	 * @warning This handler is an example only and does not fit a final product. You need to analyse 
    	 *          how your product is supposed to react in case of Assert.
    	 * @warning On assert from the SoftDevice, the system can only recover on reset.
    	 *
    	 * @param[in] line_num    Line number of the failing ASSERT call.
    	 * @param[in] p_file_name File name of the failing ASSERT call.
    	 */
    	void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
    	{
    			app_error_handler(DEAD_BEEF, line_num, p_file_name);
    	}
    
    
    	/**@brief Function for the GAP initialization.
    	 *
    	 * @details This function will set up all the necessary GAP (Generic Access Profile) parameters of 
    	 *          the device. It also sets the permissions and appearance.
    	 */
    	static void gap_params_init(void)
    	{
    			uint32_t                err_code;
    			ble_gap_conn_params_t   gap_conn_params;
    			ble_gap_conn_sec_mode_t sec_mode;
    
    			BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
    			
    			err_code = sd_ble_gap_device_name_set(&sec_mode,
    																						(const uint8_t *) DEVICE_NAME,
    																						strlen(DEVICE_NAME));
    			APP_ERROR_CHECK(err_code);
    
    			memset(&gap_conn_params, 0, sizeof(gap_conn_params));
    
    			gap_conn_params.min_conn_interval = MIN_CONN_INTERVAL;
    			gap_conn_params.max_conn_interval = MAX_CONN_INTERVAL;
    			gap_conn_params.slave_latency     = SLAVE_LATENCY;
    			gap_conn_params.conn_sup_timeout  = CONN_SUP_TIMEOUT;
    
    			err_code = sd_ble_gap_ppcp_set(&gap_conn_params);
    			APP_ERROR_CHECK(err_code);
    	}
    
    
    	/**@brief Function for handling the data from the Nordic UART Service.
    	 *
    	 * @details This function will process the data received from the Nordic UART BLE Service and send
    	 *          it to the UART module.
    	 *
    	 * @param[in] p_nus    Nordic UART Service structure.
    	 * @param[in] p_data   Data to be send to UART module.
    	 * @param[in] length   Length of the data.
    	 */
    	/**@snippet [Handling the data received over BLE] */
    	static void nus_data_handler(ble_nus_t * p_nus, uint8_t * p_data, uint16_t length)
    		{
    				if(p_data[0] == 0x31)	
    				{
    						printf("Sending data over APP\r\n");
    						send_data_flag = true;
    				}
    				else if(p_data[0] == 0x32)
    				{
    						printf("Stop sending data\r\n");
    						send_data_flag = false;
    				}
    				else
    					printf("Invalid input\r\n");
    		}
    	/**@snippet [Handling the data received over BLE] */
    
    
    	/**@brief Function for initializing services that will be used by the application.
    	 */
    	static void services_init(void)
    	{
    			uint32_t       err_code;
    			ble_nus_init_t nus_init;
    			
    			memset(&nus_init, 0, sizeof(nus_init));
    
    			nus_init.data_handler = nus_data_handler;
    			
    			err_code = ble_nus_init(&m_nus, &nus_init);
    			APP_ERROR_CHECK(err_code);
    	}
    
    
    	/**@brief Function for handling an event from the Connection Parameters Module.
    	 *
    	 * @details This function will be called for all events in the Connection Parameters Module
    	 *          which are passed to the application.
    	 *
    	 * @note All this function does is to disconnect. This could have been done by simply setting
    	 *       the disconnect_on_fail config parameter, but instead we use the event handler
    	 *       mechanism to demonstrate its use.
    	 *
    	 * @param[in] p_evt  Event received from the Connection Parameters Module.
    	 */
    	static void on_conn_params_evt(ble_conn_params_evt_t * p_evt)
    	{
    			uint32_t err_code;
    			
    			if(p_evt->evt_type == BLE_CONN_PARAMS_EVT_FAILED)
    			{
    					err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
    					APP_ERROR_CHECK(err_code);
    			}
    	}
    
    
    	/**@brief Function for handling errors from the Connection Parameters module.
    	 *
    	 * @param[in] nrf_error  Error code containing information about what went wrong.
    	 */
    	static void conn_params_error_handler(uint32_t nrf_error)
    	{
    			APP_ERROR_HANDLER(nrf_error);
    	}
    
    
    	/**@brief Function for initializing the Connection Parameters module.
    	 */
    	static void conn_params_init(void)
    	{
    			uint32_t               err_code;
    			ble_conn_params_init_t cp_init;
    			
    			memset(&cp_init, 0, sizeof(cp_init));
    
    			cp_init.p_conn_params                  = NULL;
    			cp_init.first_conn_params_update_delay = FIRST_CONN_PARAMS_UPDATE_DELAY;
    			cp_init.next_conn_params_update_delay  = NEXT_CONN_PARAMS_UPDATE_DELAY;
    			cp_init.max_conn_params_update_count   = MAX_CONN_PARAMS_UPDATE_COUNT;
    			cp_init.start_on_notify_cccd_handle    = BLE_GATT_HANDLE_INVALID;
    			cp_init.disconnect_on_fail             = false;
    			cp_init.evt_handler                    = on_conn_params_evt;
    			cp_init.error_handler                  = conn_params_error_handler;
    			
    			err_code = ble_conn_params_init(&cp_init);
    			APP_ERROR_CHECK(err_code);
    	}
    
    
    	/**@brief Function for putting the chip into sleep mode.
    	 *
    	 * @note This function will not return.
    	 */
    	static void sleep_mode_enter(void)
    	{
    			uint32_t err_code = bsp_indication_set(BSP_INDICATE_IDLE);
    			APP_ERROR_CHECK(err_code);
    
    			// Prepare wakeup buttons.
    			err_code = bsp_btn_ble_sleep_mode_prepare();
    			APP_ERROR_CHECK(err_code);
    
    			// Go to system-off mode (this function will not return; wakeup will cause a reset).
    			err_code = sd_power_system_off();
    			APP_ERROR_CHECK(err_code);
    	}
    
    
    	/**@brief Function for handling advertising events.
    	 *
    	 * @details This function will be called for advertising events which are passed to the application.
    	 *
    	 * @param[in] ble_adv_evt  Advertising event.
    	 */
    	static void on_adv_evt(ble_adv_evt_t ble_adv_evt)
    	{
    			uint32_t err_code;
    
    			switch (ble_adv_evt)
    			{
    					case BLE_ADV_EVT_FAST:
    							err_code = bsp_indication_set(BSP_INDICATE_ADVERTISING);
    							APP_ERROR_CHECK(err_code);
    							break;
    					case BLE_ADV_EVT_IDLE:
    							sleep_mode_enter();
    							break;
    					default:
    							break;
    			}
    	}
    
    
    	/**@brief Function for the application's SoftDevice event handler.
    	 *
    	 * @param[in] p_ble_evt SoftDevice event.
    	 */
    	static void on_ble_evt(ble_evt_t * p_ble_evt)
    	{
    			uint32_t                         err_code;
    			
    			switch (p_ble_evt->header.evt_id)
    			{
    					case BLE_GAP_EVT_CONNECTED:
    							err_code = bsp_indication_set(BSP_INDICATE_CONNECTED);
    							APP_ERROR_CHECK(err_code);
    							m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
    							break;
    							
    					case BLE_GAP_EVT_DISCONNECTED:
    							err_code = bsp_indication_set(BSP_INDICATE_IDLE);
    							APP_ERROR_CHECK(err_code);
    							m_conn_handle = BLE_CONN_HANDLE_INVALID;
    							break;
    
    					case BLE_GAP_EVT_SEC_PARAMS_REQUEST:
    							// Pairing not supported
    							err_code = sd_ble_gap_sec_params_reply(m_conn_handle, BLE_GAP_SEC_STATUS_PAIRING_NOT_SUPP, NULL, NULL);
    							APP_ERROR_CHECK(err_code);
    							break;
    
    					case BLE_GATTS_EVT_SYS_ATTR_MISSING:
    							// No system attributes have been stored.
    							err_code = sd_ble_gatts_sys_attr_set(m_conn_handle, NULL, 0, 0);
    							APP_ERROR_CHECK(err_code);
    							break;
    
    					default:
    							// No implementation needed.
    							break;
    			}
    	}
    
    
    	/**@brief Function for dispatching a SoftDevice event to all modules with a SoftDevice 
    	 *        event handler.
    	 *
    	 * @details This function is called from the SoftDevice event interrupt handler after a 
    	 *          SoftDevice event has been received.
    	 *
    	 * @param[in] p_ble_evt  SoftDevice event.
    	 */
    	static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
    	{
    			ble_conn_params_on_ble_evt(p_ble_evt);
    			ble_nus_on_ble_evt(&m_nus, p_ble_evt);
    			on_ble_evt(p_ble_evt);
    			ble_advertising_on_ble_evt(p_ble_evt);
    			bsp_btn_ble_on_ble_evt(p_ble_evt);
    			
    	}
    
    
    	/**@brief Function for the SoftDevice initialization.
    	 *
    	 * @details This function initializes the SoftDevice and the BLE event interrupt.
    	 */
    	static void ble_stack_init(void)
    	{
    			uint32_t err_code;
    			
    			nrf_clock_lf_cfg_t clock_lf_cfg = NRF_CLOCK_LFCLKSRC;
    			
    			// Initialize SoftDevice.
    			SOFTDEVICE_HANDLER_INIT(&clock_lf_cfg, NULL);
    			
    			ble_enable_params_t ble_enable_params;
    			err_code = softdevice_enable_get_default_config(CENTRAL_LINK_COUNT,
    																											PERIPHERAL_LINK_COUNT,
    																											&ble_enable_params);
    			APP_ERROR_CHECK(err_code);
    					
    			//Check the ram settings against the used number of links
    			CHECK_RAM_START_ADDR(CENTRAL_LINK_COUNT,PERIPHERAL_LINK_COUNT);
    			// Enable BLE stack.
    			err_code = softdevice_enable(&ble_enable_params);
    			APP_ERROR_CHECK(err_code);
    			
    			// Subscribe for BLE events.
    			err_code = softdevice_ble_evt_handler_set(ble_evt_dispatch);
    			APP_ERROR_CHECK(err_code);
    	}
    
    
    	/**@brief Function for handling events from the BSP module.
    	 *
    	 * @param[in]   event   Event generated by button press.
    	 */
    	void bsp_event_handler(bsp_event_t event)
    	{
    			uint32_t err_code;
    			switch (event)
    			{
    					case BSP_EVENT_SLEEP:
    							sleep_mode_enter();
    							break;
    
    					case BSP_EVENT_DISCONNECT:
    							err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION);
    							if (err_code != NRF_ERROR_INVALID_STATE)
    							{
    									APP_ERROR_CHECK(err_code);
    							}
    							break;
    
    					case BSP_EVENT_WHITELIST_OFF:
    							err_code = ble_advertising_restart_without_whitelist();
    							if (err_code != NRF_ERROR_INVALID_STATE)
    							{
    									APP_ERROR_CHECK(err_code);
    							}
    							break;
    
    					default:
    							break;
    			}
    	}
    
    
    	/**@brief   Function for handling app_uart events.
    	 *
    	 * @details This function will receive a single character from the app_uart module and append it to 
    	 *          a string. The string will be be sent over BLE when the last character received was a 
    	 *          'new line' i.e '\n' (hex 0x0D) or if the string has reached a length of 
    	 *          @ref NUS_MAX_DATA_LENGTH.
    	 */
    	/**@snippet [Handling the data received over UART] */
    	void uart_event_handle(app_uart_evt_t * p_event)
    	{
    			//static uint8_t data_array[BLE_NUS_MAX_DATA_LEN];		// length = 20 bytes
    			//static uint8_t index = 0;
    			//uint32_t       err_code;
    
    			switch (p_event->evt_type)
    			{
    					case APP_UART_DATA_READY:
    						 /* UNUSED_VARIABLE(app_uart_get(&data_array[index]));
    							index++;
    
    							if ((data_array[index - 1] == '\r') || (index >= (BLE_NUS_MAX_DATA_LEN)))
    							{
    									err_code = ble_nus_string_send(&m_nus, data_array, index);
    									if (err_code != NRF_ERROR_INVALID_STATE)
    									{
    											APP_ERROR_CHECK(err_code);
    									}
    									
    									index = 0;
    							}*/
    					
    							break;
    
    					case APP_UART_COMMUNICATION_ERROR:
    							APP_ERROR_HANDLER(p_event->data.error_communication);
    							break;
    
    					case APP_UART_FIFO_ERROR:
    							APP_ERROR_HANDLER(p_event->data.error_code);
    							break;
    
    					default:
    							break;
    			}
    	}
    	/**@snippet [Handling the data received over UART] */
    
    	void uart_error_handle(app_uart_evt_t * p_event)
    	{
    			if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR)
    			{
    					APP_ERROR_HANDLER(p_event->data.error_communication);
    			}
    			else if (p_event->evt_type == APP_UART_FIFO_ERROR)
    			{
    					APP_ERROR_HANDLER(p_event->data.error_code);
    			}
    	}
    
    
    	/**@brief  Function for initializing the UART module.
    	 */
    	/**@snippet [UART Initialization] */
    	static void uart_init(void)
    	{
    			uint32_t                     err_code;
    			const app_uart_comm_params_t comm_params =
    			{
    					RX_PIN_NUMBER,
    					TX_PIN_NUMBER,
    					RTS_PIN_NUMBER,
    					CTS_PIN_NUMBER,
    					APP_UART_FLOW_CONTROL_ENABLED,
    					false,
    					UART_BAUDRATE_BAUDRATE_Baud115200
    			};
    
    			APP_UART_FIFO_INIT( &comm_params,
    												 UART_RX_BUF_SIZE,
    												 UART_TX_BUF_SIZE,
    												 uart_event_handle,
    												 APP_IRQ_PRIORITY_LOW,
    												 err_code);
    			APP_ERROR_CHECK(err_code);
    	}
    	/**@snippet [UART Initialization] */
    
    
    	/**@brief Function for initializing the Advertising functionality.
    	 */
    	static void advertising_init(void)
    	{
    			uint32_t      err_code;
    			ble_advdata_t advdata;
    			ble_advdata_t scanrsp;
    
    			// Build advertising data struct to pass into @ref ble_advertising_init.
    			memset(&advdata, 0, sizeof(advdata));
    			advdata.name_type          = BLE_ADVDATA_FULL_NAME;
    			advdata.include_appearance = false;
    			advdata.flags              = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
    
    			memset(&scanrsp, 0, sizeof(scanrsp));
    			scanrsp.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
    			scanrsp.uuids_complete.p_uuids  = m_adv_uuids;
    
    			ble_adv_modes_config_t options = {0};
    			options.ble_adv_fast_enabled  = BLE_ADV_FAST_ENABLED;
    			options.ble_adv_fast_interval = APP_ADV_INTERVAL;
    			options.ble_adv_fast_timeout  = APP_ADV_TIMEOUT_IN_SECONDS;
    
    			err_code = ble_advertising_init(&advdata, &scanrsp, &options, on_adv_evt, NULL);
    			APP_ERROR_CHECK(err_code);
    	}
    
    
    	/**@brief Function for initializing buttons and leds.
    	 *
    	 * @param[out] p_erase_bonds  Will be true if the clear bonding button was pressed to wake the application up.
    	 */
    	static void buttons_leds_init(bool * p_erase_bonds)
    	{
    			bsp_event_t startup_event;
    
    			uint32_t err_code = bsp_init(BSP_INIT_LED | BSP_INIT_BUTTONS,
    																	 APP_TIMER_TICKS(100, APP_TIMER_PRESCALER), 
    																	 bsp_event_handler);
    			APP_ERROR_CHECK(err_code);
    
    			err_code = bsp_btn_ble_init(NULL, &startup_event);
    			APP_ERROR_CHECK(err_code);
    
    			*p_erase_bonds = (startup_event == BSP_EVENT_CLEAR_BONDING_DATA);
    	}
    
    
    	/**@brief Function for placing the application in low power state while waiting for events.
    	 */
    	static void power_manage(void)
    	{
    			uint32_t err_code = sd_app_evt_wait();
    			APP_ERROR_CHECK(err_code);
    	}
    
    
    
    
    	/**@brief Application main function.
    	 */
    	int main(void)
    	{
    			uint32_t err_code;
    			bool erase_bonds;
    
    			// Initialize.
    			timers_init();
    			APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false);
    			uart_init();
    			
    			
    			buttons_leds_init(&erase_bonds);
    			ble_stack_init();
    			gap_params_init();
    			services_init();
    			advertising_init();
    			conn_params_init();
    
    			printf("\r\nUART Start!\r\n");
    			application_timers_start();
    			err_code = ble_advertising_start(BLE_ADV_MODE_FAST);
    			APP_ERROR_CHECK(err_code);
    
    			// Enter main loop.
    			for (;;)
    			{      
    				if (send_data_flag == true)
    				{
    									send_data_flag = false;
    												
    				}		
    				power_manage();							
    			}
    	}
    
    
    	/** 
    	 * @}
    	 */
    
Related