Long story short.
I am trying to merge DFU master code to feed a DFU.zip to the DFU receiver code already present in the secure bootloaders (but elevated successfully into the main appliaction)
I am running into problems sending the application part of the DFU.
I trigger this exception
if ( ((p_req->create.object_size & (CODE_PAGE_SIZE - 1)) != 0) && (s_dfu_settings.progress.firmware_image_offset_last + p_req->create.object_size != m_firmware_size_req)) { NRF_LOG_ERROR("Object size must be page aligned"); p_res->result = NRF_DFU_RES_CODE_INVALID_PARAMETER; return; }
this is located in nrf_dfu_req_handler.c
when trying to create an object with size 1024 for sending DFU application binary objects.
With 4096, I don't run into this problem but I quickly overwhelm nrf_dfu_serial_on_packet_received() and on_rx_complete(). (See code below)
Is it possible to send DFU application binary objects in less than 4096 bytes? CODE_PAGE_SIZE is defined as 4096 for the 52840.
:::
I want to edit my question upon further work.
It seems given the exception code above I am hard coded to 4096 bytes DFU Tranport Data Objects. That's fine. I'll just make sure DFU receiver is given time to process incoming packets.
I have changed my sending loop to call
app_sched_execute();
after every MTU worth of data sent, to give the nrf_dfu_req_handler immediate time to process incoming data.
I notice that the
on_data_obj_write_request() (nrf_dfu_req_handler.c)
calls nrf_dfu_flash_store() with a write complete callback which frees the nrf_balloc_alloc() called for the incoming packets. It is my understanding that this is called *every* 64 bytes.
So I thought I would tie my loop to the balloc pool levels, like this as they should only decrease upon successfull completion of nrf_dfu_flash_store() in the case of write objects.
static void uart_send_application_image(uint8_t *data, uint32_t length) { in_app_send = 1; uint32_t i=length; uint32_t encoded_slip_packet_length; //Create Object payload[0]=0x01; payload[1]=0x02;//Command Object payload[2]=length; payload[3]=length>>8; payload[4]=length>>16; payload[5]=length>>24; encode_and_send(payload,6); //app_sched_execute(); while(length>0) { uint8_t pool_use = nrf_balloc_utilization_get(&m_payload_pool); app_sched_execute(); if (pool_use < 1) { encoded_slip_packet[0]=0x08;//Write object opcode if (length>=MAX_ACTUAL_PAYLOAD) { (void)slip_encode(&encoded_slip_packet[1], data, MAX_ACTUAL_PAYLOAD, &encoded_slip_packet_length); length= length-MAX_ACTUAL_PAYLOAD; data = data+MAX_ACTUAL_PAYLOAD; }else { (void)slip_encode(&encoded_slip_packet[1], data, length, &encoded_slip_packet_length); length=0; } // NRF_LOG_INFO("uart_send_application_image : %d %d %d", length,&data,MAX_ACTUAL_PAYLOAD); // send dfu_controller_send(encoded_slip_packet,encoded_slip_packet_length+1); // (void)nrf_drv_uart_tx(&p_dfu->uart_instance, encoded_slip_packet, encoded_slip_packet_length+1); // while(nrf_drv_uart_tx_in_progress(&p_dfu->uart_instance)); //Attempt to get DFU core to process it's scheduled events. } } //Ask for CRC payload[0]=0x03; encode_and_send(payload,1); //To-DO: check CRC //Execute init packet payload[0]=0x04; encode_and_send(payload,1); in_app_send = 0; }
However I am seeing flash_write_failed in my debug log.
> <debug> nrf_dfu_flash: nrf_fstorage_write(addr=0x0005A9EE, src=0x20028DF4, len=62 bytes), queue usage: 1 00> 00> <debug> nrf_dfu_flash: Flash write failed (0x3): addr=0x0005A9EE, len=0x3E bytes, pending 0
Thoughts or ideas? I haven't found what 0x3 means yet.
Here is my edit to on_rx_complete of my customized nrf_dfu_serial_uart.c to deactivate the uart and instead take data encoded by the DFU Master code provided.
static __INLINE void on_rx_complete(nrf_dfu_serial_t * p_transport, uint8_t * p_data, uint8_t len) { // NRF_LOG_INFO("on_rx_complete"); // Check if there is byte to process. Zero length transfer means that RXTO occured. for(int k = 0; k < len; k++) { ret_code_t ret_code = NRF_ERROR_TIMEOUT; if (len) { ret_code = slip_decode_add_byte(&m_slip, p_data[k]); } // (void) nrf_drv_uart_rx(&m_uart, &m_rx_byte, 1); if (ret_code == NRF_SUCCESS) { // NRF_LOG_INFO("Calling nrf_dfu_serial_on_packet_received"); nrf_dfu_serial_on_packet_received(p_transport, (uint8_t const *)m_slip.p_buffer, m_slip.current_index); uint8_t * p_rx_buf = nrf_balloc_alloc(&m_payload_pool); if (p_rx_buf == NULL) { NRF_LOG_ERROR("Failed to allocate buffer"); return; } NRF_LOG_INFO("Allocated buffer %x", p_rx_buf); // reset the slip decoding m_slip.p_buffer = &p_rx_buf[OPCODE_OFFSET]; m_slip.current_index = 0; m_slip.state = SLIP_STATE_DECODING; } } } void dfu_controller_send(uint8_t * p_data, uint8_t len) { on_rx_complete(&m_serial,p_data,len); }
The DFU master code I've essentially merged into nrf_dfu_serial_uart.c to encode an incoming, known working dfu zip's .dat and .bin.
The DFU master code I'm working with is here: Appendix 5 UART DFU Master code: DFUMaster_UART.zip
EDIT:
This solved my flash write coming back failed. Do not attempt to write 62 bytes.....writes 64. That DFU master code is seemingly wrong.
Look there for the correct answer. Made sure that my slip packets have 64 bytes of actual payload.
So, that all works and the very very last data object is in error as I'm reasoning it's NOT 4096 bytes.....:/.
EDIT2::
Never-mind, my array I was storing my application binary in had an incorrect size on the extern I was using. It seems the very very last data object write can be somewhat odd. I thought I might have to pad it to 4096 bytes and/or 4 byte aligned. App binary was
106684 bytes long with the remainder of
106684/4096 in the very last object write. Worked fine.
00> <info> app: NRF_DFU_EVT_DFU_COMPLETED
and a reboot into the new image!
Huzzah!