static void relay_packet(dfu_packet_t* p_packet, uint16_t length) { mesh_packet_t* p_mesh_packet = mesh_packet_get_aligned(p_packet); if (!p_mesh_packet) { if (!mesh_packet_acquire(&p_mesh_packet)) { APP_ERROR_CHECK(NRF_ERROR_NO_MEM); } mesh_packet_build( p_mesh_packet, p_packet->packet_type, p_packet->payload.data.segment, (uint8_t*) &p_packet->payload.data.transaction_id, length - 4); } else { mesh_packet_ref_count_inc(p_mesh_packet); } mesh_packet_set_local_addr(p_mesh_packet); if (transport_tx(p_mesh_packet, TX_REPEATS_DATA, TX_INTERVAL_TYPE_DATA, packet_release_callback)) { mp_sent_packets[(m_sent_packet_index++) & (SENT_PACKET_COUNT - 1)] = p_mesh_packet; } mesh_packet_ref_count_dec(p_mesh_packet); }
uint32_t handle_storage_flag_set(uint16_t handle, handle_flag_t flag, bool value) { if (flag >= HANDLE_FLAG__MAX) { return NRF_ERROR_INVALID_PARAM; } if (handle == RBC_MESH_INVALID_HANDLE) { return NRF_ERROR_INVALID_ADDR; } uint16_t handle_index = handle_entry_get(handle, true); switch (flag) { case HANDLE_FLAG_PERSISTENT: if (handle_index == HANDLE_CACHE_ENTRY_INVALID) { handle_index = handle_entry_to_head(handle); if (handle_index == HANDLE_CACHE_ENTRY_INVALID) { return NRF_ERROR_NO_MEM; } } m_handle_cache[handle_index].persistent = value; break; case HANDLE_FLAG_TX_EVENT: if (handle_index == HANDLE_CACHE_ENTRY_INVALID) { handle_index = handle_entry_to_head(handle); if (handle_index == HANDLE_CACHE_ENTRY_INVALID) { return NRF_ERROR_NO_MEM; } } m_handle_cache[handle_index].tx_event = value; break; case HANDLE_FLAG_DISABLED: if (value) { if (handle_index == HANDLE_CACHE_ENTRY_INVALID) { return NRF_SUCCESS; /* the value is already disabled */ } if (m_handle_cache[handle_index].data_entry == DATA_CACHE_ENTRY_INVALID) { return NRF_SUCCESS; /* the value is already disabled */ } trickle_disable(&m_data_cache[m_handle_cache[handle_index].data_entry].trickle); } else { uint32_t error_code; mesh_packet_t* p_packet = NULL; if (!mesh_packet_acquire(&p_packet)) { return NRF_ERROR_NO_MEM; } error_code = mesh_packet_build(p_packet, handle, 0, NULL, 0); if (error_code != NRF_SUCCESS) { mesh_packet_ref_count_dec(p_packet); return error_code; } if (handle_index == HANDLE_CACHE_ENTRY_INVALID) { /* may safely run this function inline, as we're already in event handler */ local_packet_push(p_packet); return NRF_SUCCESS; } else { if (m_handle_cache[handle_index].data_entry == DATA_CACHE_ENTRY_INVALID) { m_handle_cache[handle_index].data_entry = data_entry_allocate(); if (m_handle_cache[handle_index].data_entry == DATA_CACHE_ENTRY_INVALID) { return NRF_ERROR_NO_MEM; } } if (m_data_cache[m_handle_cache[handle_index].data_entry].p_packet != NULL) { /* someone set the packet already, let's not overwrite it. */ mesh_packet_ref_count_dec(p_packet); } else { m_data_cache[m_handle_cache[handle_index].data_entry].p_packet = p_packet; } trickle_enable(&m_data_cache[m_handle_cache[handle_index].data_entry].trickle); } } break; default: return NRF_ERROR_INVALID_PARAM; } return NRF_SUCCESS; }
static void handle_data_packet(dfu_packet_t* p_packet, uint16_t length) { mesh_packet_t* p_cache_packet = packet_cache_entry_get(p_packet); if (p_cache_packet) { transport_tx_skip(p_cache_packet); } bool do_relay = false; if (p_packet->payload.data.transaction_id == m_transaction.transaction_id) { /* check and add to cache */ if (data_packet_in_cache(p_packet)) { return; } m_data_cache[(m_data_index++) & (DATA_CACHE_SIZE - 1)] = p_packet->payload.data.segment; if (m_state == BL_STATE_DFU_READY) { if (p_packet->payload.start.segment == 0) { bl_info_segment_t* p_segment = NULL; switch (m_transaction.type) { case DFU_TYPE_APP: p_segment = m_bl_info_pointers.p_segment_app; break; case DFU_TYPE_SD: p_segment = m_bl_info_pointers.p_segment_sd; break; case DFU_TYPE_BOOTLOADER: p_segment = m_bl_info_pointers.p_segment_bl; break; default: APP_ERROR_CHECK(NRF_ERROR_NOT_SUPPORTED); } m_transaction.p_indicated_start_addr = (uint32_t*) p_packet->payload.start.start_address; uint32_t start_address = p_packet->payload.start.start_address; /* if the host doesn't know the start address, we use start of segment: */ if (start_address == START_ADDRESS_UNKNOWN) { start_address = p_segment->start; } uint32_t segment_count = ((p_packet->payload.start.length * 4) + (start_address & 0x0F) - 1) / 16 + 1; if (p_packet->payload.start.signature_length != 0) { segment_count += p_packet->payload.start.signature_length / SEGMENT_LENGTH; } if (segment_count > 0xFFFF) { /* can't have more than 65536 segments in a transmission */ segment_count = 0xFFFF; } m_transaction.segments_remaining = segment_count; m_transaction.segment_count = segment_count; m_transaction.p_start_addr = (uint32_t*) start_address; m_transaction.length = p_packet->payload.start.length * 4; m_transaction.signature_length = p_packet->payload.start.signature_length; m_transaction.segment_is_valid_after_transfer = p_packet->payload.start.last; m_transaction.p_last_requested_entry = NULL; m_transaction.signature_bitmap = 0; if (m_transaction.type == DFU_TYPE_BOOTLOADER) { m_transaction.p_bank_addr = (uint32_t*) ( (m_bl_info_pointers.p_segment_app->start) + (m_bl_info_pointers.p_segment_app->length) - (m_transaction.length & ((uint32_t) ~(PAGE_SIZE - 1))) - (PAGE_SIZE) ); } else { m_transaction.p_bank_addr = m_transaction.p_start_addr; } if ((uint32_t) m_transaction.p_start_addr >= p_segment->start && (uint32_t) m_transaction.p_start_addr + m_transaction.length <= p_segment->start + p_segment->length) { start_target(); do_relay = true; } } else { m_tid_cache[(m_tid_index++) & (TRANSACTION_ID_CACHE_SIZE - 1)] = m_transaction.transaction_id; start_req(m_transaction.type, true); /* go back to req, we've missed packet 0 */ } } else if (m_state == BL_STATE_DFU_TARGET) { if (p_packet->payload.data.segment > 0 && p_packet->payload.data.segment <= m_transaction.segment_count) { uint32_t* p_addr = NULL; uint32_t error_code = NRF_ERROR_NULL; if (p_packet->payload.data.segment <= m_transaction.segment_count - m_transaction.signature_length / SEGMENT_LENGTH) { p_addr = addr_from_seg(p_packet->payload.data.segment); error_code = dfu_data((uint32_t) p_addr, p_packet->payload.data.data, length - (DFU_PACKET_LEN_DATA - SEGMENT_LENGTH)); } else /* treat signature packets at the end */ { uint32_t index = p_packet->payload.data.segment - (m_transaction.segment_count - m_transaction.signature_length / SEGMENT_LENGTH) - 1; if (index >= m_transaction.signature_length / SEGMENT_LENGTH || m_transaction.signature_bitmap & (1 << index)) { error_code = NRF_ERROR_INVALID_STATE; } else { memcpy(&m_transaction.signature[index * SEGMENT_LENGTH], p_packet->payload.data.data, length - (DFU_PACKET_LEN_DATA - SEGMENT_LENGTH)); m_transaction.signature_bitmap |= (1 << index); error_code = NRF_SUCCESS; } } if (error_code == NRF_SUCCESS) { set_timeout(STATE_TIMEOUT_TARGET); m_transaction.segments_remaining--; do_relay = true; /* check whether we've lost any entries, and request them */ uint32_t* p_req_entry = NULL; uint32_t req_entry_len = 0; mesh_packet_t* p_req_packet; if (dfu_get_oldest_missing_entry( m_transaction.p_last_requested_entry, &p_req_entry, &req_entry_len) && ( /* don't request the previous packet yet */ ADDR_SEGMENT(p_req_entry, m_transaction.p_start_addr) < p_packet->payload.data.segment - 1 || m_transaction.segment_count == p_packet->payload.data.segment ) ) { if(!mesh_packet_acquire(&p_req_packet)) { return; } if (mesh_packet_build(p_req_packet, DFU_PACKET_TYPE_DATA_REQ, ADDR_SEGMENT(p_req_entry, m_transaction.p_start_addr), (uint8_t*) &m_transaction.transaction_id, 4) == NRF_SUCCESS && transport_tx(p_req_packet, TX_REPEATS_REQ, TX_INTERVAL_TYPE_REQ, NULL)) { m_transaction.p_last_requested_entry = (uint32_t*) p_req_entry; } mesh_packet_ref_count_dec(p_req_packet); } } } /* ending the DFU */ if (m_transaction.segments_remaining == 0) { dfu_end(); start_rampdown(); } } else if (m_state == BL_STATE_RELAY_CANDIDATE || m_state == BL_STATE_RELAY) { m_state = BL_STATE_RELAY; transport_tx_abort(mp_beacon); set_timeout(STATE_TIMEOUT_RELAY); do_relay = true; } } if (do_relay) { relay_packet(p_packet, length); } }