Example #1
0
/**@brief Flash operation success callback handler.
 *
 * @details     This function updates read/write pointers.
 *              This function resets retry count.
 */
static void on_operation_success(fs_cmd_t const * const p_cmd)
{
    m_retry_count = 0;

    switch (p_cmd->op_code)
    {
        case FS_OP_STORE:
            // If offset is equal to or larger than length, then the operation has finished.
            if (p_cmd->store.offset >= p_cmd->store.length_words)
            {
                app_notify(p_cmd, NRF_SUCCESS);
                queue_advance();
            }
            break;

        case FS_OP_ERASE:
            if (p_cmd->erase.pages_erased == p_cmd->erase.pages_to_erase)
            {
                app_notify(p_cmd, NRF_SUCCESS);
                queue_advance();
            }
            break;

        default:
            break;
    }
}
Example #2
0
/**
 * @brief Function for handling of system events from SoftDevice.
 *
 * @param[in] sys_evt System event received.
 */
void pstorage_sys_event_handler(uint32_t sys_evt)
{
    uint32_t retval = NRF_SUCCESS;

    // The event shall only be processed if requested by this module.
    if (m_cmd_queue.flash_access == true)
    {
        cmd_queue_element_t * p_cmd;
        m_cmd_queue.flash_access = false;
        switch (sys_evt)
        {
            case NRF_EVT_FLASH_OPERATION_SUCCESS:
            {
                p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
                m_round_val++;
            
                bool command_finished = ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size);

                if (command_finished)
                {
                    uint8_t queue_rp = m_cmd_queue.rp;
                    
                    m_round_val = 0;
                    m_cmd_queue.count--;
                    m_cmd_queue.rp++;

                    if (m_cmd_queue.rp >= PSTORAGE_CMD_QUEUE_SIZE)
                    {
                        m_cmd_queue.rp -= PSTORAGE_CMD_QUEUE_SIZE;
                    }

                    app_notify(retval, &m_cmd_queue.cmd[queue_rp]);

                    // Initialize/free the element as it is now processed.
                    cmd_queue_element_init(queue_rp);
                }
                // Schedule any queued flash access operations.
                retval = cmd_queue_dequeue();
                if (retval != NRF_SUCCESS)
                {
                    app_notify(retval, &m_cmd_queue.cmd[m_cmd_queue.rp]);
                }
            }
            break;
                
            case NRF_EVT_FLASH_OPERATION_ERROR:
                app_notify(NRF_ERROR_TIMEOUT, &m_cmd_queue.cmd[m_cmd_queue.rp]);
                break;
            
            default:
                // No implementation needed.
                break;
        }
    }
}
Example #3
0
uint32_t pstorage_clear(pstorage_handle_t * p_dest, pstorage_size_t size)
{
    uint32_t page_addr;
    uint32_t retval;
    uint16_t page_count;

    VERIFY_MODULE_INITIALIZED();
    NULL_PARAM_CHECK(p_dest);
    MODULE_ID_RANGE_CHECK(p_dest);

    page_addr = p_dest->block_id / BLE_FLASH_PAGE_SIZE;

    retval = NRF_SUCCESS;

    for (page_count = 0; page_count < m_app_table[p_dest->module_id].no_of_pages; page_count++)
    {
        retval = ble_flash_page_erase(page_addr);
        page_addr++;
        if (retval != NRF_SUCCESS)
        {
            break;
        }
    }
    app_notify(p_dest, NULL, PSTORAGE_CLEAR_OP_CODE, size, retval);
    return retval;
}
Example #4
0
uint32_t pstorage_load(uint8_t *           p_dest,
                       pstorage_handle_t * p_src,
                       pstorage_size_t     size,
                       pstorage_size_t     offset)
{
    VERIFY_MODULE_INITIALIZED();
    NULL_PARAM_CHECK(p_src);
    NULL_PARAM_CHECK(p_dest);
    MODULE_ID_RANGE_CHECK (p_src);
    BLOCK_ID_RANGE_CHECK(p_src);
    SIZE_CHECK(p_src,size);
    OFFSET_CHECK(p_src,offset,size);

    // Verify word alignment.
    if ((!is_word_aligned(p_dest)) || (!is_word_aligned((void *)(uint32_t)offset)))
    {
        return NRF_ERROR_INVALID_ADDR;
    }

    memcpy(p_dest, (((uint8_t *)p_src->block_id) + offset), size);

    app_notify(p_src, p_dest, PSTORAGE_LOAD_OP_CODE, size, NRF_SUCCESS);

    return NRF_SUCCESS;
}
Example #5
0
uint32_t pstorage_store(pstorage_handle_t * p_dest,
                        uint8_t           * p_src,
                        pstorage_size_t     size,
                        pstorage_size_t     offset)
{
    VERIFY_MODULE_INITIALIZED();
    NULL_PARAM_CHECK(p_src);
    NULL_PARAM_CHECK(p_dest);
    MODULE_ID_RANGE_CHECK(p_dest);
    BLOCK_ID_RANGE_CHECK(p_dest);
    SIZE_CHECK(p_dest, size);
    OFFSET_CHECK(p_dest, offset, size);

    // Verify word alignment.
    if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset)))
    {
        return NRF_ERROR_INVALID_ADDR;
    }

    uint32_t storage_addr = p_dest->block_id + offset;

    uint32_t retval = ble_flash_block_write((uint32_t *)storage_addr,
                                            (uint32_t *)p_src,
                                            (size /sizeof(uint32_t)));

    app_notify(p_dest, p_src, PSTORAGE_STORE_OP_CODE, size, retval);
    
    return retval;
}
Example #6
0
/**@brief Starts processing the queue if there are no pending flash operations
 *        for which we are awaiting a callback.
 */
static ret_code_t queue_process(void)
{
    ret_code_t ret = NRF_SUCCESS;

    /** If the queue is not being processed, and there are still
     *  some elements in it, then start processing. */
    if ( !(m_flags & FS_FLAG_PROCESSING) &&
          (m_cmd_queue.count > 0))
    {
        m_flags |= FS_FLAG_PROCESSING;

        ret = queue_process_impl();

        /** There is ongoing flash-operation which was not
         *  initiated by fstorage. */
        if (ret == NRF_ERROR_BUSY)
        {
            // Wait for a system callback.
            m_flags |= FS_FLAG_FLASH_REQ_PENDING;

            // Stop processing the queue.
            m_flags &= ~FS_FLAG_PROCESSING;

            ret = NRF_SUCCESS;
        }
        else if (ret != NRF_SUCCESS)
        {
            // Another error has occurred.
            app_notify(ret, &m_cmd_queue.cmd[m_cmd_queue.rp]);
        }
    }

    // If we are already processing the queue, return immediately.
    return ret;
}
/**
 * @brief Dequeues a command element.
 *
 * @retval    NRF_SUCCESS    on success, else an error code indicating reason for failure.
 */
static uint32_t cmd_queue_dequeue(void)
{
    uint32_t retval;
    retval = NRF_SUCCESS;

    // If any flash operation is enqueued, schedule.
    if (m_cmd_queue.count > 0)
    {
        retval = cmd_process();
        if (retval != NRF_SUCCESS)
        {
            // Flash could be accessed by modules other than Bond Manager, hence a busy error is
            // acceptable, but any other error needs to be indicated to the bond manager.
            if (retval != NRF_ERROR_BUSY)
            {
                app_notify(retval);
            }
            else
            {
                // In case of busy next trigger will be a success or a failure event.
            }
        }
    }
    else
    {
        // No flash access request pending.
    }

    return retval;
}
Example #8
0
/**@brief Flash operation failure callback handler.
 *
 * @details Function to keep track of retries and notify failures.
 */
static void on_operation_failure(fs_cmd_t const * const p_cmd)
{
    if (++m_retry_count > FS_CMD_MAX_RETRIES)
    {
        app_notify(p_cmd, NRF_ERROR_TIMEOUT);
        queue_advance();
    }
}
Example #9
0
/**
 * @brief Dequeues a command element.
 */
static uint32_t cmd_queue_dequeue(void)
{
    uint32_t retval;    

    cmd_queue_element_t * p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
    // Update count and read pointer to process any queued requests
    if(m_round_val >= p_cmd->size)
    {

				//if we finished clearing data, tell our DFU master
				if(p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) {
					lumen_set_solid_rgb(255,255,255);
					lumen_leds_show();

					//clear finished here
					finish_dfu_image_size_process();

				}
			
        // Initialize/free the element as it is now processed.
        cmd_queue_init_element(m_cmd_queue.rp);
        m_round_val = 0;
        m_cmd_queue.count--;
        m_cmd_queue.rp++;
    }

    retval = NRF_SUCCESS;

    // If any flash operation is enqueued, schedule
    if (m_cmd_queue.count)
    {
        retval = process_cmd();

        if (retval != NRF_SUCCESS)
        {
            // Flash could be accessed by modules other than Bond Manager, hence a busy error is
            // acceptable, but any other error needs to be indicated to the bond manager
            if (retval != NRF_ERROR_BUSY)
            {
                app_notify (retval);
            }
            else
            {
                // In case of busy next trigger will be a success or a failure event
            }
        }
    }
    else
    {
        // No flash access request pending
    }

    return retval;
}
Example #10
0
/**
 * @brief Handles Flash Access Result Events.
 */
void pstorage_sys_event_handler (uint32_t sys_evt)
{
    uint32_t retval;

    retval = NRF_SUCCESS;

    // Its possible the flash access was not initiated by bond manager, hence
    // event is processed only if the event triggered was for an operation requested by the
    // bond manager.
    if (m_cmd_queue.flash_access == true)
    {
        cmd_queue_element_t * p_cmd;
        m_cmd_queue.flash_access = false;
        switch (sys_evt)
        {
            case NRF_EVT_FLASH_OPERATION_SUCCESS:
                p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
                if ((p_cmd->op_code != PSTORAGE_CLEAR_OP_CODE) || (m_round_val >= p_cmd->size))
                {
                    app_notify(retval);
                }
                // Schedule any queued flash access operations
                retval = cmd_queue_dequeue ();
                if (retval != NRF_SUCCESS)
                {
                    app_notify(retval);
                }

                break;
            case NRF_EVT_FLASH_OPERATION_ERROR:
                app_notify(NRF_ERROR_TIMEOUT);
                break;
            default:
                // No implementation needed.
                break;
        }
    }
}
Example #11
0
/**@brief Function to process the current element in the queue and return the result.
 *
 * @retval NRF_SUCCESS          Success.
 * @retval NRF_ERROR_FORBIDDEN  Error. Undefined command.
 * @retval Any error returned by the SoftDevice flash API.
 */
static ret_code_t queue_process(void)
{
    ret_code_t       ret;
    fs_cmd_t * const p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
    
    if (m_cmd_queue.count > 0)
    {
        switch (p_cmd->op_code)
        {
            case FS_OP_STORE:
                ret = store_execute(p_cmd);
                break;

            case FS_OP_ERASE:
                ret = erase_execute(p_cmd);
                break;

            default:
                ret = NRF_ERROR_INTERNAL;
                break;
        }
    }
    else
    {
        ret = NRF_SUCCESS;
    }

    /** There is ongoing flash-operation which was not
    *  initiated by fstorage. */
    if (ret == NRF_ERROR_BUSY)
    {
        // Wait for a system callback.
        m_flags |= FS_FLAG_FLASH_REQ_PENDING;

        // Stop processing the queue.
        m_flags &= ~FS_FLAG_PROCESSING;

        ret = NRF_SUCCESS;
    }
    else if (ret != NRF_SUCCESS)
    {
        // Another error has occurred.
        app_notify(p_cmd, ret);
    }

    return ret;
}
Example #12
0
/**@brief Function to consume queue item and notify the return value of the operation.
 *
 * @details This function will report the result and remove the command from the queue after
 *          notification.
 */
static void cmd_consume(uint32_t result, const fs_cmd_t * p_cmd)
{
    // Consume the current item on the queue.
    uint8_t rp = m_cmd_queue.rp;

    m_cmd_queue.count--;
    if (m_cmd_queue.count == 0)
    {
        // There are no elements left. Stop processing the queue.
        m_flags &= ~FS_FLAG_PROCESSING;
    }

    if (++(m_cmd_queue.rp) == FS_CMD_QUEUE_SIZE)
    {
        m_cmd_queue.rp = 0;
    }

    // Notify upon successful operation.
    app_notify(result, p_cmd);

    // Reset the queue element.
    cmd_reset(rp);
}
Example #13
0
uint32_t pstorage_update(pstorage_handle_t * p_dest,
                        uint8_t           * p_src,
                        pstorage_size_t     size,
                        pstorage_size_t     offset)
{

    uint32_t *p_swap_addr = (uint32_t *)PSTORAGE_SWAP_ADDR;
    uint32_t *p_page_addr1 =  (uint32_t *) PAGE_BASE_ADDR(p_dest->block_id + offset);
#ifdef SUPPORT_MODULES_LARGER_THAN_PAGE
    uint32_t *p_page_addr2 =  (uint32_t *) PAGE_BASE_ADDR(p_dest->block_id + offset + size-1);
#endif
    uint16_t head_word_count =  offset/sizeof(uint32_t);
    uint16_t body_word_count =  size/sizeof(uint32_t);
    uint16_t tail_word_count;
    uint32_t retval;


	VERIFY_MODULE_INITIALIZED();
    NULL_PARAM_CHECK(p_src);
    NULL_PARAM_CHECK(p_dest);
    MODULE_ID_RANGE_CHECK(p_dest);
    BLOCK_ID_RANGE_CHECK(p_dest);
    SIZE_CHECK(p_dest, size);
    OFFSET_CHECK(p_dest, offset, size);

    // Verify word alignment.
    if ((!is_word_aligned(p_src)) || (!is_word_aligned((void *)(uint32_t)offset)))
    {
        return NRF_ERROR_INVALID_ADDR;
    }
    // erase swap page
    (void) ble_flash_page_erase(PSTORAGE_SWAP_ADDR / BLE_FLASH_PAGE_SIZE);
#ifdef SUPPORT_MODULES_LARGER_THAN_PAGE
    if (p_page_addr1 == p_page_addr2)
    {
#endif
    	// tail is in the same page as head
        tail_word_count = BLE_FLASH_PAGE_SIZE/sizeof(uint32_t) - head_word_count - body_word_count;
    	// copy of the head
        if (head_word_count)
        {
        	retval = ble_flash_block_write(p_swap_addr, p_page_addr1, head_word_count );
        	if (retval != NRF_SUCCESS)
        	{
        		app_notify(p_dest, p_src, PSTORAGE_UPDATE_OP_CODE, size, retval);
        		return retval;
        	}
        }
        // copy of the body
        retval = ble_flash_block_write(p_swap_addr+head_word_count, (uint32_t *)p_src, body_word_count);
    	if (retval != NRF_SUCCESS)
    	{
    		app_notify(p_dest, p_src, PSTORAGE_UPDATE_OP_CODE, size, retval);
    		return retval;
    	}
        // copy of the tail
        if (tail_word_count)
        {
        	retval = ble_flash_block_write(p_swap_addr+head_word_count+body_word_count, p_page_addr1+head_word_count+body_word_count, tail_word_count );
        	if (retval != NRF_SUCCESS)
        	{
        		app_notify(p_dest, p_src, PSTORAGE_UPDATE_OP_CODE, size, retval);
        		return retval;
        	}
        }
        // erase active page
        (void) ble_flash_page_erase((uint32_t)p_page_addr1 / BLE_FLASH_PAGE_SIZE);
        // restore updated page
        retval = ble_flash_block_write(p_page_addr1, p_swap_addr, BLE_FLASH_PAGE_SIZE/sizeof(uint32_t));
#ifdef SUPPORT_MODULES_LARGER_THAN_PAGE
    }
    else
    {
    	// tail is in NOT in the same page as head - need to swap twice
    	uint16_t body1_word_count =  BLE_FLASH_PAGE_SIZE/sizeof(uint32_t) - head_word_count;
    	uint16_t body2_word_count =  body_word_count - body1_word_count;
        tail_word_count = BLE_FLASH_PAGE_SIZE/sizeof(uint32_t) - body2_word_count;
        // copy head
        retval = ble_flash_block_write(p_swap_addr, p_page_addr1, head_word_count );
    	if (retval != NRF_SUCCESS)
    	{
    		app_notify(p_dest, p_src, PSTORAGE_UPDATE_OP_CODE, size, retval);
    		return retval;
    	}
        // copy body1
        retval = ble_flash_block_write(p_swap_addr, (uint32_t *)p_src, body1_word_count );
    	if (retval != NRF_SUCCESS)
    	{
    		app_notify(p_dest, p_src, PSTORAGE_UPDATE_OP_CODE, size, retval);
    		return retval;
    	}
        // erase active page
        (void) ble_flash_page_erase((uint32_t)p_page_addr1 / BLE_FLASH_PAGE_SIZE);
        // restore updated page1
        retval = ble_flash_block_write(p_page_addr1, p_swap_addr, BLE_FLASH_PAGE_SIZE/sizeof(uint32_t));
    	if (retval != NRF_SUCCESS)
    	{
    		app_notify(p_dest, p_src, PSTORAGE_UPDATE_OP_CODE, size, retval);
    		return retval;
    	}
        // erase swap page
        (void) ble_flash_page_erase(PSTORAGE_SWAP_ADDR / BLE_FLASH_PAGE_SIZE);
        // copy body2
        retval = ble_flash_block_write(p_swap_addr, (uint32_t *)p_src + body1_word_count, body2_word_count );
    	if (retval != NRF_SUCCESS)
    	{
    		app_notify(p_dest, p_src, PSTORAGE_UPDATE_OP_CODE, size, retval);
    		return retval;
    	}
        // copy tail
        retval = ble_flash_block_write(p_swap_addr, p_page_addr2+body2_word_count, tail_word_count );
    	if (retval != NRF_SUCCESS)
    	{
    		app_notify(p_dest, p_src, PSTORAGE_UPDATE_OP_CODE, size, retval);
    		return retval;
    	}
        // erase active page
        (void) ble_flash_page_erase((uint32_t)p_page_addr2 / BLE_FLASH_PAGE_SIZE);
        // restore updated page2
        retval = ble_flash_block_write(p_page_addr2, p_swap_addr, BLE_FLASH_PAGE_SIZE/sizeof(uint32_t));
    	if (retval != NRF_SUCCESS)
    	{
    		app_notify(p_dest, p_src, PSTORAGE_UPDATE_OP_CODE, size, retval);
    		return retval;
    	}
    }
#endif
    app_notify(p_dest, p_src, PSTORAGE_UPDATE_OP_CODE, size, retval);
    return retval;

}
Example #14
0
/**
 * @brief Handles Flash Access Result Events declared in pstorage_platform.h.
 *
 * @param[in] sys_evt System event to be handled.
 */
void pstorage_sys_event_handler(uint32_t sys_evt)
{
    uint32_t retval = NRF_SUCCESS;

    // Its possible the flash access was not initiated by bond manager, hence
    // event is processed only if the event triggered was for an operation requested by the
    // bond manager.
    if (m_cmd_queue.flash_access == true)
    {
        cmd_queue_element_t * p_cmd;

        m_cmd_queue.flash_access = false;

        if (m_swap_state == STATE_SWAP_DIRTY)
        {
            if (sys_evt == NRF_EVT_FLASH_OPERATION_SUCCESS)
            {
                m_swap_state = STATE_INIT;
            }
            else
            {
                // If clearing the swap fails, set the application back to un-initialized, to give
                // the application a chance for a retry.
                m_module_initialized = false;
            }

            // Schedule any queued flash access operations.
            retval = cmd_queue_dequeue();
            if (retval != NRF_SUCCESS)
            {
                app_notify(retval, &m_cmd_queue.cmd[m_cmd_queue.rp]);
            }
            return;
        }

        switch (sys_evt)
        {
            case NRF_EVT_FLASH_OPERATION_SUCCESS:
            {
                p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];
                m_round_val++;

                const bool store_finished =
                    ((p_cmd->op_code == PSTORAGE_STORE_OP_CODE) &&
                     ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size));

                const bool update_finished =
                    ((p_cmd->op_code == PSTORAGE_UPDATE_OP_CODE) &&
                     (m_swap_state == STATE_COMPLETE));

                const bool clear_block_finished =
                    ((p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) &&
                     (m_swap_state == STATE_COMPLETE));

                const bool clear_all_finished =
                    ((p_cmd->op_code == PSTORAGE_CLEAR_OP_CODE) &&
                     ((m_round_val * SOC_MAX_WRITE_SIZE) >= p_cmd->size) &&
                     (m_swap_state == STATE_INIT));

                if (update_finished ||
                    clear_block_finished ||
                    clear_all_finished ||
                    store_finished)
                {
                    uint8_t queue_rp = m_cmd_queue.rp;

                    m_swap_state = STATE_INIT;

                    m_round_val = 0;
                    m_cmd_queue.count--;
                    m_cmd_queue.rp++;

                    if (m_cmd_queue.rp >= PSTORAGE_CMD_QUEUE_SIZE)
                    {
                        m_cmd_queue.rp -= PSTORAGE_CMD_QUEUE_SIZE;
                    }

                    app_notify(retval, &m_cmd_queue.cmd[queue_rp]);

                    // Initialize/free the element as it is now processed.
                    cmd_queue_element_init(queue_rp);
                }
                // Schedule any queued flash access operations.
                retval = cmd_queue_dequeue();

                if (retval != NRF_SUCCESS)
                {
                    app_notify(retval, &m_cmd_queue.cmd[m_cmd_queue.rp]);
                }
            }
            break;

            case NRF_EVT_FLASH_OPERATION_ERROR:
                // Current command timed out and was not started in SoftDevice.
                p_cmd = &m_cmd_queue.cmd[m_cmd_queue.rp];

                ASSERT(p_cmd->n_tries < SD_CMD_MAX_TRIES);
                if (++p_cmd->n_tries == SD_CMD_MAX_TRIES)
                {
                    // If we have already attempted SD_CMD_MAX_TRIES times, give up.
                    app_notify(NRF_ERROR_TIMEOUT, &m_cmd_queue.cmd[m_cmd_queue.rp]);
                }
                else
                {
                    // Retry operation
                    retval = cmd_process();
                    if (retval != NRF_SUCCESS && retval != NRF_ERROR_BUSY)
                    {
                        app_notify(retval, p_cmd);
                    }
                }
                break;

            default:
                // No implementation needed.
                break;

        }
    }
}