Recursive Calls to app_sched_execute()

Hi,

I am coming across an issue with app_scheduler and FDS.

While waiting for an event in FDS to complete (write, read, init, gc, etc) I go into a while loop calling app_sched_execute() until the event handler is invoked and I can continue. However, I am running into an issue where I am calling an fds Write from a scheduler event. The repeated call to app_sched_execute() means the same command is executed over and over again until the FDS runs out of Queue Space and I hit the Error Handler.

Is there a way to safely wait for the FDS to complete a task without causing this recursion?

Thanks

Parents
  • Hi,

    It is not possible to call app_sched_execute() from a scheduled event, as the event is first popped from the queue first after the event is done, as the event data pointer needs to be kept throughout the event.

    I'm not sure I fully understand how you use the scheduler to wait for completion of FDS operations, can you give a code example showing how this works?

    Do you have to wait for the completion of the operation by calling app_sched_execute(), or could you wait for a flag from the FDS event handler instead?

    Best regards,
    Jørgen

  • Hi Jørgen,

    Sorry for my slow reply.

    I am waiting for a flag from the FDS event handler. I have put partial code below showing my initialisation, event handler and wait function. If I replace line 70 with anything other than app_sched_execute, the event handler is not invoked and I am stuck in the while loop forever. I am looking for a way to make FDS blocking and this was the only way I could get it to work with the scheduler. However, recursive calls are now causing havoc with this.

    Thanks,

    #define MAX_EVENT_SIZE 128
    #define QUEUE_SIZE	   180
    
    static uint32_t _eventBuffer[CEIL_DIV( APP_SCHED_BUF_SIZE( MAX_EVENT_SIZE, QUEUE_SIZE ), sizeof( uint32_t ) )] __ALIGN( 4 );
    
    #define TEST_FILE ( 0xBFFE )
    #define TEST_KEY  ( 0x0001 )
    
    static bool volatile _fdsBusy = false;
    static bool volatile m_fds_initialised = false;
    
    static char const* fds_evt_str[] = {
    	"FDS_EVT_INIT", "FDS_EVT_WRITE", "FDS_EVT_UPDATE", "FDS_EVT_DEL_RECORD", "FDS_EVT_DEL_FILE", "FDS_EVT_GC",
    };
    
    static void fds_evt_handler( fds_evt_t const* p_evt );
    static void Storage_Wait( void );
    const char* fds_err_str( ret_code_t ret );
    
    const char* fds_err_str( ret_code_t ret )
    {
    	// Array to map FDS return values to strings.
    	static char const* err_str[] = {
    		"FDS_ERR_OPERATION_TIMEOUT", "FDS_ERR_NOT_INITIALIZED",
    		"FDS_ERR_UNALIGNED_ADDR",	 "FDS_ERR_INVALID_ARG",
    		"FDS_ERR_NULL_ARG",			 "FDS_ERR_NO_OPEN_RECORDS",
    		"FDS_ERR_NO_SPACE_IN_FLASH", "FDS_ERR_NO_SPACE_IN_QUEUES",
    		"FDS_ERR_RECORD_TOO_LARGE",	 "FDS_ERR_NOT_FOUND",
    		"FDS_ERR_NO_PAGES",			 "FDS_ERR_USER_LIMIT_REACHED",
    		"FDS_ERR_CRC_CHECK_FAILED",	 "FDS_ERR_BUSY",
    		"FDS_ERR_INTERNAL",
    	};
    
    	return err_str[ret - NRF_ERROR_FDS_ERR_BASE];
    }
    
    static void fds_evt_handler( fds_evt_t const* p_evt )
    {
    	if( p_evt->result == NRF_SUCCESS )
    	{
    		Log_Info( "Event: %s received (NRF_SUCCESS)", fds_evt_str[p_evt->id] );
    	}
    	else
    	{
    		Log_Info( "Event: %s received (%s)", fds_evt_str[p_evt->id], fds_err_str( p_evt->result ) );
    	}
    
    	switch( p_evt->id )
    	{
    		case FDS_EVT_INIT:
    			if( p_evt->result == NRF_SUCCESS )
    			{
    				m_fds_initialised = true;
    			}
    			break;
    		default:
    			break;
    	}
    
    	_fdsBusy = false;
    
    	while( nrf_log_frontend_dequeue( ) )
    		;
    }
    
    static void Storage_Wait( void )
    {
    	while( _fdsBusy )
    	{
    		sd_app_sched_execute( );
    	}
    }
    
    int main( void )
    {
    	// Initialise clocks and power
    	ret_code_t rc = nrf_drv_clock_init( );
    	APP_ERROR_CHECK( rc );
    
    	if( !nrf_drv_power_init_check( ) )
    	{
    		nrf_drv_power_init( NULL );
    	}
    
    	// Initialise Scheduler
    	rc = nrf_pwr_mgmt_init( );
    	APP_ERROR_CHECK( rc );
    
    	rc = app_sched_init( MAX_EVENT_SIZE, QUEUE_SIZE, ( void* )_eventBuffer );
    	APP_ERROR_CHECK( rc );
    
    	uint32_t   ram_start;
    
    	// Enable the SoftDevice
    	rc = nrf_sdh_enable_request( );
    	APP_ERROR_CHECK( rc );
    
    	rc = nrf_sdh_ble_default_cfg_set( 1, &ram_start );
    	APP_ERROR_CHECK( rc );
    
    	rc = nrf_sdh_ble_enable( &ram_start );
    	APP_ERROR_CHECK( rc );
    
    	// Initialise Logging
    	rc = NRF_LOG_INIT( NULL );
    	APP_ERROR_CHECK( rc );
    
    	// Initialise the default backends as enabled in the configuration
    	NRF_LOG_DEFAULT_BACKENDS_INIT( );
    
    	NRF_LOG_INFO( "Application Started" );
    
    	// Initialise Storage
    
    	rc = fds_register( fds_evt_handler );
    	APP_ERROR_CHECK( rc );
    
    	rc = fds_init( );
    	APP_ERROR_CHECK( rc );
    
    	while( !m_fds_initialised )
    	{
    		sd_app_evt_wait();
    	}
    
    	Log_Info( "FDS Initialised" );
    
    	fds_stat_t stat = { 0 };
    
    	rc = fds_stat( &stat );
    	APP_ERROR_CHECK( rc );
    
    	NRF_LOG_INFO( "Found %d valid records.", stat.valid_records );
    	NRF_LOG_INFO( "Found %d dirty records (ready to be garbage collected).", stat.dirty_records );
    
    	if( stat.dirty_records > 0 )
    	{
    		_fdsBusy = true;
    
    		rc = fds_gc( );
    		APP_ERROR_CHECK( rc );
    
    		Storage_Wait( );
    	}
    
    	fds_record_desc_t desc = { 0 };
    	fds_find_token_t  tok  = { 0 };
    
    
    	// Test Write
    
    	static uint32_t const m_deadbeef = 0xDEADBEEF;
    
    	fds_record_t	  record;
    	fds_record_desc_t record_desc;
    
    	record.file_id			 = TEST_FILE;
    	record.key				 = TEST_KEY;
    	record.data.p_data		 = &m_deadbeef;
    	record.data.length_words = 1;
    
    	_fdsBusy = true;
    	rc = fds_record_write( &record_desc, &record );
    	APP_ERROR_CHECK( rc );
    	
    	Storage_Wait( );
    
    	while(1)
    	{
    		app_sched_execute( );
    
    		if( nrf_log_frontend_dequeue( ) == false )
    		{
    			nrf_pwr_mgmt_run( );
    		}
    	}
    }

Reply
  • Hi Jørgen,

    Sorry for my slow reply.

    I am waiting for a flag from the FDS event handler. I have put partial code below showing my initialisation, event handler and wait function. If I replace line 70 with anything other than app_sched_execute, the event handler is not invoked and I am stuck in the while loop forever. I am looking for a way to make FDS blocking and this was the only way I could get it to work with the scheduler. However, recursive calls are now causing havoc with this.

    Thanks,

    #define MAX_EVENT_SIZE 128
    #define QUEUE_SIZE	   180
    
    static uint32_t _eventBuffer[CEIL_DIV( APP_SCHED_BUF_SIZE( MAX_EVENT_SIZE, QUEUE_SIZE ), sizeof( uint32_t ) )] __ALIGN( 4 );
    
    #define TEST_FILE ( 0xBFFE )
    #define TEST_KEY  ( 0x0001 )
    
    static bool volatile _fdsBusy = false;
    static bool volatile m_fds_initialised = false;
    
    static char const* fds_evt_str[] = {
    	"FDS_EVT_INIT", "FDS_EVT_WRITE", "FDS_EVT_UPDATE", "FDS_EVT_DEL_RECORD", "FDS_EVT_DEL_FILE", "FDS_EVT_GC",
    };
    
    static void fds_evt_handler( fds_evt_t const* p_evt );
    static void Storage_Wait( void );
    const char* fds_err_str( ret_code_t ret );
    
    const char* fds_err_str( ret_code_t ret )
    {
    	// Array to map FDS return values to strings.
    	static char const* err_str[] = {
    		"FDS_ERR_OPERATION_TIMEOUT", "FDS_ERR_NOT_INITIALIZED",
    		"FDS_ERR_UNALIGNED_ADDR",	 "FDS_ERR_INVALID_ARG",
    		"FDS_ERR_NULL_ARG",			 "FDS_ERR_NO_OPEN_RECORDS",
    		"FDS_ERR_NO_SPACE_IN_FLASH", "FDS_ERR_NO_SPACE_IN_QUEUES",
    		"FDS_ERR_RECORD_TOO_LARGE",	 "FDS_ERR_NOT_FOUND",
    		"FDS_ERR_NO_PAGES",			 "FDS_ERR_USER_LIMIT_REACHED",
    		"FDS_ERR_CRC_CHECK_FAILED",	 "FDS_ERR_BUSY",
    		"FDS_ERR_INTERNAL",
    	};
    
    	return err_str[ret - NRF_ERROR_FDS_ERR_BASE];
    }
    
    static void fds_evt_handler( fds_evt_t const* p_evt )
    {
    	if( p_evt->result == NRF_SUCCESS )
    	{
    		Log_Info( "Event: %s received (NRF_SUCCESS)", fds_evt_str[p_evt->id] );
    	}
    	else
    	{
    		Log_Info( "Event: %s received (%s)", fds_evt_str[p_evt->id], fds_err_str( p_evt->result ) );
    	}
    
    	switch( p_evt->id )
    	{
    		case FDS_EVT_INIT:
    			if( p_evt->result == NRF_SUCCESS )
    			{
    				m_fds_initialised = true;
    			}
    			break;
    		default:
    			break;
    	}
    
    	_fdsBusy = false;
    
    	while( nrf_log_frontend_dequeue( ) )
    		;
    }
    
    static void Storage_Wait( void )
    {
    	while( _fdsBusy )
    	{
    		sd_app_sched_execute( );
    	}
    }
    
    int main( void )
    {
    	// Initialise clocks and power
    	ret_code_t rc = nrf_drv_clock_init( );
    	APP_ERROR_CHECK( rc );
    
    	if( !nrf_drv_power_init_check( ) )
    	{
    		nrf_drv_power_init( NULL );
    	}
    
    	// Initialise Scheduler
    	rc = nrf_pwr_mgmt_init( );
    	APP_ERROR_CHECK( rc );
    
    	rc = app_sched_init( MAX_EVENT_SIZE, QUEUE_SIZE, ( void* )_eventBuffer );
    	APP_ERROR_CHECK( rc );
    
    	uint32_t   ram_start;
    
    	// Enable the SoftDevice
    	rc = nrf_sdh_enable_request( );
    	APP_ERROR_CHECK( rc );
    
    	rc = nrf_sdh_ble_default_cfg_set( 1, &ram_start );
    	APP_ERROR_CHECK( rc );
    
    	rc = nrf_sdh_ble_enable( &ram_start );
    	APP_ERROR_CHECK( rc );
    
    	// Initialise Logging
    	rc = NRF_LOG_INIT( NULL );
    	APP_ERROR_CHECK( rc );
    
    	// Initialise the default backends as enabled in the configuration
    	NRF_LOG_DEFAULT_BACKENDS_INIT( );
    
    	NRF_LOG_INFO( "Application Started" );
    
    	// Initialise Storage
    
    	rc = fds_register( fds_evt_handler );
    	APP_ERROR_CHECK( rc );
    
    	rc = fds_init( );
    	APP_ERROR_CHECK( rc );
    
    	while( !m_fds_initialised )
    	{
    		sd_app_evt_wait();
    	}
    
    	Log_Info( "FDS Initialised" );
    
    	fds_stat_t stat = { 0 };
    
    	rc = fds_stat( &stat );
    	APP_ERROR_CHECK( rc );
    
    	NRF_LOG_INFO( "Found %d valid records.", stat.valid_records );
    	NRF_LOG_INFO( "Found %d dirty records (ready to be garbage collected).", stat.dirty_records );
    
    	if( stat.dirty_records > 0 )
    	{
    		_fdsBusy = true;
    
    		rc = fds_gc( );
    		APP_ERROR_CHECK( rc );
    
    		Storage_Wait( );
    	}
    
    	fds_record_desc_t desc = { 0 };
    	fds_find_token_t  tok  = { 0 };
    
    
    	// Test Write
    
    	static uint32_t const m_deadbeef = 0xDEADBEEF;
    
    	fds_record_t	  record;
    	fds_record_desc_t record_desc;
    
    	record.file_id			 = TEST_FILE;
    	record.key				 = TEST_KEY;
    	record.data.p_data		 = &m_deadbeef;
    	record.data.length_words = 1;
    
    	_fdsBusy = true;
    	rc = fds_record_write( &record_desc, &record );
    	APP_ERROR_CHECK( rc );
    	
    	Storage_Wait( );
    
    	while(1)
    	{
    		app_sched_execute( );
    
    		if( nrf_log_frontend_dequeue( ) == false )
    		{
    			nrf_pwr_mgmt_run( );
    		}
    	}
    }

Children
No Data
Related