<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://devzone.nordicsemi.com/cfs-file/__key/system/syndication/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Background DFU postvalidation</title><link>https://devzone.nordicsemi.com/f/nordic-q-a/52246/background-dfu-postvalidation</link><description>Hello all, 
 We are trying to use Background DFU. 
 We are able to trigger using &amp;quot;background_dfu_validate_trigger&amp;quot; and &amp;quot;background_dfu_process_trigger&amp;quot;. Process the init packet block. Receive all the firmware blocks. 
 After calling &amp;quot;background_dfu_process_block</description><dc:language>en-US</dc:language><generator>Telligent Community 13</generator><lastBuildDate>Thu, 19 Sep 2019 12:30:47 GMT</lastBuildDate><atom:link rel="self" type="application/rss+xml" href="https://devzone.nordicsemi.com/f/nordic-q-a/52246/background-dfu-postvalidation" /><item><title>RE: Background DFU postvalidation</title><link>https://devzone.nordicsemi.com/thread/210700?ContentTypeID=1</link><pubDate>Thu, 19 Sep 2019 12:30:47 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:e1b6f3c0-a277-4074-bdc8-26dcfcc30212</guid><dc:creator>fhfs</dc:creator><description>&lt;p&gt;Nevermind, I should not have called &amp;quot;background_dfu_handle_event(&amp;amp;dfu.bg_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE);&amp;quot; and run app_sched_execute in my main loop.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Background DFU postvalidation</title><link>https://devzone.nordicsemi.com/thread/210699?ContentTypeID=1</link><pubDate>Thu, 19 Sep 2019 12:27:07 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:5ee243f8-8c7e-491a-8e66-3999815c70e0</guid><dc:creator>Einar Thorsrud</dc:creator><description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;I see. I need some time to look into this, but I will update you as soon as possible.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Background DFU postvalidation</title><link>https://devzone.nordicsemi.com/thread/210442?ContentTypeID=1</link><pubDate>Wed, 18 Sep 2019 13:43:04 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:0eaf3ed3-c8e0-442b-b0ee-7c237f089586</guid><dc:creator>fhfs</dc:creator><description>&lt;p&gt;Yes, nrf_dfu_validation_post_data_execute is never called which is why there is no firmware to validate. I should be seeing rtt message &amp;quot;Whole firmware image received. Postvalidating.&amp;quot; from function &amp;quot;on_data_obj_execute_request_sched&amp;quot; in nrf_dfu_req_handler&lt;/p&gt;
&lt;p&gt;SDK version 15.3.0&lt;/p&gt;
&lt;p&gt;This is how we use the Background DFU from the application.&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="c_cpp"&gt;
#include &amp;quot;string.h&amp;quot;

#include &amp;quot;app_scheduler.h&amp;quot;
#include &amp;quot;crc32.h&amp;quot;

#include &amp;quot;background_dfu_transport.h&amp;quot;
#include &amp;quot;background_dfu_block.h&amp;quot;
#include &amp;quot;background_dfu_transport.h&amp;quot;

#include &amp;quot;nrf_delay.h&amp;quot;
#include &amp;quot;nrf_log.h&amp;quot;
#include &amp;quot;nrf_log_ctrl.h&amp;quot;
#include &amp;quot;nrf_dfu_settings.h&amp;quot;

#include &amp;quot;DFU.h&amp;quot;
#include &amp;quot;ANT.h&amp;quot;
#include &amp;quot;ANT_message_response_types.h&amp;quot;

#define DFU_BLOCK_SIZE 4096
#define DFU_MAX_PACKET_SIZE 29
#define DFU_BLOCK_REMAINDER (DFU_BLOCK_SIZE % DFU_MAX_PACKET_SIZE)
#define SCHED_QUEUE_SIZE				(192)
#define SCHED_MAX_EVENT_DATA_SIZE		(sizeof(nrf_dfu_request_t))                       /**&amp;lt; Maximum size of scheduler events. */

typedef struct
{
	uint8_t *buffer;
	uint16_t size;
	uint32_t crc;
	uint16_t index;
} dfu_init_packet_t;

typedef struct
{
	uint32_t firmware_size,  					// size in bytes
		firmware_crc,
		index,     								// bytes of update succesfully written to flash
		packet_count,
		block_number,
		block_crc;
	uint8_t *block;  			// malloced block, to be written to flash
	background_dfu_trigger_t trigger;
	background_dfu_context_t bg_dfu_ctx;  	// Background DFU context
	dfu_init_packet_t init_packet;
}background_device_firmware_update_t;

static background_device_firmware_update_t dfu;

extern response_t on_enter_bootloader(uint8_t* buffer, uint8_t len);

static int dfu_start(uint8_t *buffer, uint8_t len)
{
	uint32_t dfu_packet_address = ((buffer[0] &amp;lt;&amp;lt; 16) + (buffer[1] &amp;lt;&amp;lt; 8) + buffer[2]),      // first 3 bytes contain address
			init_packet_size = 0, 	// next two bytes (max 0x1000)
			init_packet_crc = 0, 	// next 4 bytes	(crc32, 4 bytes)
			firmware_size = 0, 		// next 3 bytes (firmware size max 0x100000)
			firmware_crc = 0; 		// next 4 bytes	(crc32, 4 bytes)
	
	init_packet_size = (buffer[3] &amp;lt;&amp;lt; 8) + buffer[4];
	init_packet_crc = ((buffer[5] &amp;lt;&amp;lt; 24) + (buffer[6] &amp;lt;&amp;lt; 16) + (buffer[7] &amp;lt;&amp;lt; 8) + buffer[8]);
	firmware_size = ((buffer[9] &amp;lt;&amp;lt; 16) + (buffer[10] &amp;lt;&amp;lt; 8) + buffer[11]);
	firmware_crc = ((buffer[12] &amp;lt;&amp;lt; 24) + (buffer[13] &amp;lt;&amp;lt; 16) + (buffer[14] &amp;lt;&amp;lt; 8) + buffer[15]);
	
	// null check
	if(init_packet_size == 0 || init_packet_crc == 0 || firmware_size == 0 || firmware_crc == 0)
		return RESPONSE_ERROR;
	
	// initialize dfu struct to 0
	memset(&amp;amp;dfu, 0, sizeof(dfu));
	dfu.firmware_size = firmware_size;
	dfu.firmware_crc = firmware_crc;
	
	// set init packet struct to 0
	dfu.init_packet.size = init_packet_size;
	dfu.init_packet.buffer = malloc(init_packet_size);
	dfu.init_packet.crc = init_packet_crc;
	
	APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
	
	return RESPONSE_SUCCESS;
}

static int dfu_init_packet(uint8_t *buffer, uint8_t len)
{
	uint16_t dfu_packet_address = ((buffer[1] &amp;lt;&amp;lt; 8) + buffer[2]);      // first byte signals init packet, next 2 bytes contain address
	
	// if address + remainder is larger or equal to init packet size
	if((dfu_packet_address + (dfu.init_packet.size % DFU_MAX_PACKET_SIZE)) &amp;gt;= (dfu.init_packet.size))
	{
		uint8_t last_packet_remainder = dfu.init_packet.size % DFU_MAX_PACKET_SIZE;
		memcpy(dfu.init_packet.buffer + dfu.init_packet.index, buffer + 3, last_packet_remainder);
		dfu.init_packet.index += last_packet_remainder;
	}
	else //if((dfu_packet_address / DFU_MAX_PACKET_SIZE) &amp;lt; (dfu.init_packet.size / DFU_MAX_PACKET_SIZE))
	{
		memcpy(dfu.init_packet.buffer + dfu.init_packet.index, buffer+3, DFU_MAX_PACKET_SIZE);
		dfu.init_packet.index += DFU_MAX_PACKET_SIZE;
	}
	
	// if init packet completed 
	if (dfu.init_packet.index == dfu.init_packet.size)
	{
		dfu_init_packet_complete();
	}
}


int dfu_packet(uint8_t* buffer, uint8_t len)
{
	uint32_t dfu_packet_address = ((buffer[0] &amp;lt;&amp;lt; 16) + (buffer[1] &amp;lt;&amp;lt; 8) + buffer[2]),     // first 3 bytes contain address
		block_index = dfu_packet_address % DFU_BLOCK_SIZE;
	uint8_t dfu_packet_length = len - 3;
	uint32_t err_code = NRF_SUCCESS;
	
	dfu.packet_count++;     // just keeping count, may be removed
	
	// Handle init packets
	if(dfu_packet_address == 0xffffff)
	{
		dfu_start(buffer, len);
		return RESPONSE_SUCCESS;
	}
	else if(dfu_packet_address &amp;gt; 0xf00000 - 1)
	{
		dfu_init_packet(buffer, len);
		return RESPONSE_SUCCESS;
	}
	
	// if this is the block remainder
	if((block_index / DFU_MAX_PACKET_SIZE) == (DFU_BLOCK_SIZE / DFU_MAX_PACKET_SIZE))
	{
		// dfu_packet_address should be the same as dfu_block + block_index
		memcpy(dfu.block + block_index, buffer + 3, DFU_BLOCK_REMAINDER);
		block_index += DFU_BLOCK_REMAINDER;
		NRF_LOG_INFO(&amp;quot;Block Remainder packet(%d) coppied to buffer at %04X&amp;quot;, DFU_BLOCK_REMAINDER, block_index);
	}
	// Last packet of last block remainder Check
	else if(((dfu.index + block_index) / DFU_MAX_PACKET_SIZE) == (dfu.firmware_size / DFU_MAX_PACKET_SIZE))
	{
		uint8_t last_packet_remainder = (dfu.firmware_size % DFU_BLOCK_SIZE) % DFU_MAX_PACKET_SIZE;
		// dfu_packet_address should be the same as dfu_block + block_index
		memcpy(dfu.block + block_index, buffer + 3, last_packet_remainder);
		block_index += last_packet_remainder;
		NRF_LOG_INFO(&amp;quot;Last packet(%d) coppied to buffer at %04X&amp;quot;, last_packet_remainder, block_index);
	}
	else
	{
		// dfu_packet_address should be the same as dfu_block + block_index
		memcpy(dfu.block + block_index, buffer + 3, dfu_packet_length);
		block_index += dfu_packet_length;
	}
	
	// End of block check
	if(block_index == DFU_BLOCK_SIZE || 
		((dfu.index + block_index) == dfu.firmware_size))
	{
		// Calculate and send CRC32
		dfu.block_crc = crc32_compute(dfu.block, block_index, &amp;amp;dfu.block_crc);
		send_acknowledge_crc_to_beast(dfu.block_crc, (dfu_packet_address &amp;gt;&amp;gt; 12));
		
		// put block in scheduler to be written to flash
		if((err_code = dfu_process_block(dfu.block)) != BACKGROUND_DFU_BLOCK_SUCCESS)
		{
			NRF_LOG_ERROR(&amp;quot;dfu_process_block failed (0x%X)&amp;quot;, err_code);
			return RESPONSE_ERROR;
		}
		
		// Add processed bytes to total index
		dfu.index += block_index;
		// Reset block index
		block_index = 0;
		
		// Clear processed block
		memset(dfu.block, 0, DFU_BLOCK_SIZE);
		
		NRF_LOG_INFO(&amp;quot;app_sched_execute %06X&amp;quot;, dfu.index);
		// Process event 
		app_sched_execute();
		
		// flush rtt log
		NRF_LOG_FLUSH();
		if (dfu.index == dfu.firmware_size)
		{
			NRF_LOG_INFO(&amp;quot;app_sched_execute dfu.index == dfu.firmware_size&amp;quot;);
			// Process event 
			app_sched_execute();
			err_code = background_dfu_handle_event(&amp;amp;dfu.bg_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE);
			if (err_code != NRF_SUCCESS)
				return err_code;		
			NRF_LOG_FLUSH();
		}
	}
	
	return RESPONSE_SUCCESS;
}

static int dfu_init_packet_complete()
{
	uint32_t err_code = NRF_SUCCESS;
	
	// Initialize and set trigger struct
	uint32_t little = dfu.init_packet.size;
	uint32_t big = uint32_big_decode((uint8_t*)&amp;amp;little);
	dfu.trigger.init_length = big;       										// Initpacket size
	
	// calculate received crc32 init packet
	little = crc32_compute(dfu.init_packet.buffer, dfu.init_packet.size, NULL);
	// check calculated crc
	if (little != dfu.init_packet.crc)
	{
		NRF_LOG_ERROR(&amp;quot;Init Packet CRC(%08X) does not match calculated CRC(%08X)&amp;quot;, dfu.init_packet.crc, little);
		return NRF_ERROR_INVALID_DATA;
	}
	big = uint32_big_decode((uint8_t*)&amp;amp;little);
	dfu.trigger.init_crc = big;     											// Initpacket crc
	
	little = dfu.firmware_size;
	big = uint32_big_decode((uint8_t*)&amp;amp;little);
	dfu.trigger.image_length = big;      										// Firmware size
	
	little = dfu.firmware_crc;     
	big = uint32_big_decode((uint8_t*)&amp;amp;little);
	dfu.trigger.image_crc = big;          										// Firmware crc
	dfu.trigger.flags = 0;      												// Trigger version(1 or 0 lsh 4) and dfu flag(bit 3)
	
	// allocate block in memory
	dfu.block = malloc(DFU_BLOCK_SIZE);
	memset(dfu.block, 0, DFU_BLOCK_SIZE);
	// NULL check on malloc
	if (dfu.block == NULL)
		return NRF_ERROR_NO_MEM;
		
	// Initialize dfu settings from flash if present
	err_code = nrf_dfu_settings_init(true);
	if (err_code != NRF_SUCCESS)
		return err_code;
	
	// Initialize dfu request handler
	err_code = nrf_dfu_req_handler_init(dfu_observer);
	if (err_code != NRF_SUCCESS)
		return err_code;
	
	// Init background dfu state machine
	background_dfu_state_init(&amp;amp;dfu.bg_dfu_ctx);
	if (dfu.bg_dfu_ctx.dfu_state != BACKGROUND_DFU_IDLE)
	{
		NRF_LOG_WARNING(&amp;quot;Invalid state&amp;quot;);
		return NRF_ERROR_INVALID_STATE;
	}
	
	// Transition from DFU_IDLE to DFU_DOWNLOAD_TRIG.
	err_code = background_dfu_handle_event(&amp;amp;dfu.bg_dfu_ctx, BACKGROUND_DFU_EVENT_TRANSFER_COMPLETE);
	if (err_code != NRF_SUCCESS)
		return err_code;
	
	// Process events
	app_sched_execute();
				
	// Process Trigger
	if (background_dfu_validate_trigger(&amp;amp;dfu.bg_dfu_ctx, (uint8_t *)&amp;amp;dfu.trigger, sizeof(dfu.trigger)))
	{
		if (!background_dfu_process_trigger(&amp;amp;dfu.bg_dfu_ctx, (uint8_t *)&amp;amp;dfu.trigger, sizeof(dfu.trigger)))
		{
			NRF_LOG_ERROR(&amp;quot;NRF_ERROR_INTERNAL&amp;quot;);
			return (err_code = NRF_ERROR_INTERNAL);
		}
	}
	
	// Process events
	app_sched_execute();
	
	// Set init packet data
	memcpy(dfu.block, dfu.init_packet.buffer, dfu.init_packet.size);
	dfu_process_block(dfu.block);
	
	// reset block count for firmware
	dfu.block_number = 0;
	
	// report back CRC32
	send_acknowledge_crc_to_beast(dfu.init_packet.crc, 0);
	
	// Process events
	app_sched_execute();
	
	return err_code;
}

/**
 * @brief Pass block of retrieved data to background DFU module.
 *
 * @param[in]  p_block  Pointer to block of retrieved data.
 */
static int dfu_process_block(uint8_t *p_block)
{
	background_dfu_block_t block;
	background_dfu_block_result_t result;

	block.number = dfu.block_number;
	block.size = DFU_BLOCK_SIZE;
	block.p_payload = p_block;

	NRF_LOG_INFO(&amp;quot;Process block %d&amp;quot;, block.number);
	dfu.block_number++;

	result = background_dfu_process_block(&amp;amp;dfu.bg_dfu_ctx, &amp;amp;block);
	if (result != BACKGROUND_DFU_BLOCK_SUCCESS)
	{
		NRF_LOG_ERROR(&amp;quot;Error in background_dfu_process_block (%d)&amp;quot;, result);
	}
	return result;
}

// Background DFU required callbacks

static void dfu_observer(nrf_dfu_evt_type_t evt_type)
{
	switch (evt_type)
	{
	case NRF_DFU_EVT_DFU_COMPLETED:
        NRF_LOG_INFO(&amp;quot;NRF_DFU_EVT_DFU_COMPLETED&amp;quot;);
		break;

	default:
		break;
	}
}

uint32_t background_dfu_random(void)
{
	// Intentionally empty: multicast DFU not implemented.
	return 0;
}

void background_dfu_transport_block_request_send(background_dfu_context_t *p_dfu_ctx,
	background_dfu_request_bitmap_t *p_req_bmp)
{
	// Intentionally empty: multicast DFU not implemented.
}

void background_dfu_handle_error(void)
{
	NRF_LOG_ERROR(&amp;quot;background_dfu_handle_error&amp;quot;);
}

void background_dfu_transport_state_update(background_dfu_context_t *p_dfu_ctx)
{
	switch (p_dfu_ctx-&amp;gt;dfu_state)
	{
	case BACKGROUND_DFU_DOWNLOAD_TRIG:
		NRF_LOG_INFO(&amp;quot;state_update BACKGROUND_DFU_DOWNLOAD_TRIG&amp;quot;);
		break;

	case BACKGROUND_DFU_DOWNLOAD_INIT_CMD:
		NRF_LOG_INFO(&amp;quot;state_update BACKGROUND_DFU_DOWNLOAD_INIT_CMD&amp;quot;);
		break;

	case BACKGROUND_DFU_DOWNLOAD_FIRMWARE:
		NRF_LOG_INFO(&amp;quot;state_update BACKGROUND_DFU_DOWNLOAD_FIRMWARE&amp;quot;);
		break;

	case BACKGROUND_DFU_WAIT_FOR_RESET:
	case BACKGROUND_DFU_IDLE:
		NRF_LOG_INFO(&amp;quot;state_update BACKGROUND_DFU_WAIT_FOR_RESET or IDLE&amp;quot;);
		break;

	default:
		NRF_LOG_WARNING(&amp;quot;Unhandled state in background_dfu_transport_state_update (s: %s).&amp;quot;,
			(uint32_t)background_dfu_state_to_string(p_dfu_ctx-&amp;gt;dfu_state));
	}
}

void background_dfu_transport_send_request(background_dfu_context_t *p_dfu_ctx)
{
	switch (dfu.bg_dfu_ctx.dfu_state)
	{
	case BACKGROUND_DFU_DOWNLOAD_TRIG:
		NRF_LOG_INFO(&amp;quot;send_request BACKGROUND_DFU_DOWNLOAD_TRIG&amp;quot;);
		break;

	default:
		// In other states download operation is triggered by state_update() notification.
		break;
	}
}
&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;The bootloader has no transport and is very basic just like &amp;quot;nRF5_SDK_15.3.0_59ac345/examples/iot/bootloader/main.c&amp;quot;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item><item><title>RE: Background DFU postvalidation</title><link>https://devzone.nordicsemi.com/thread/210414?ContentTypeID=1</link><pubDate>Wed, 18 Sep 2019 13:03:13 GMT</pubDate><guid isPermaLink="false">137ad170-7792-4731-bb38-c0d22fbe4515:da2703ad-688f-4e30-aeac-3ce868a35a5e</guid><dc:creator>Einar Thorsrud</dc:creator><description>&lt;p&gt;Hi,&lt;/p&gt;
&lt;p&gt;&amp;quot;No firmware to activate&amp;quot; is printed from&amp;nbsp;nrf_bootloader_fw_activate() when there is no firmware to activate in bank 1, according to the bootloader settings. So for some reason, the bootloader settings do not indicate a valid app.&lt;/p&gt;
&lt;p&gt;Can you elaborate more on how your application implements DFU and how the bootloader does it? Can you share details about SDK version, examples, your code etc to show what you are doing?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;</description></item></channel></rss>