コード例 #1
0
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);
}
コード例 #2
0
void bootloader_packet_set_local_fields(mesh_packet_t* p_packet, uint8_t dfu_packet_len)
{
    mesh_packet_set_local_addr(p_packet);
    p_packet->header.type = BLE_PACKET_TYPE_ADV_NONCONN_IND;
    p_packet->header.length = DFU_PACKET_OVERHEAD + dfu_packet_len;
    ((ble_ad_t*) p_packet->payload)->adv_data_type = MESH_ADV_DATA_TYPE;
    ((ble_ad_t*) p_packet->payload)->data[0] = (MESH_UUID & 0xFF);
    ((ble_ad_t*) p_packet->payload)->data[1] = (MESH_UUID >> 8) & 0xFF;
    ((ble_ad_t*) p_packet->payload)->adv_data_length = DFU_PACKET_ADV_OVERHEAD + dfu_packet_len;
}
コード例 #3
0
void mesh_packet_take_ownership(mesh_packet_t* p_packet)
{
    /* some packets may come with additional advertisement fields. These must be
       removed. */
    if (mesh_packet_has_additional_data(p_packet))
    {
        mesh_packet_adv_data_sanitize(p_packet);
    }

    mesh_packet_set_local_addr(p_packet);
}
コード例 #4
0
uint32_t mesh_packet_build(mesh_packet_t* p_packet,
        rbc_mesh_value_handle_t handle,
        uint16_t version,
        uint8_t* data,
        uint8_t length)
{
    if (p_packet == NULL)
    {
        return NRF_ERROR_NULL;
    }
    /* place mesh adv data at beginning of adv payload */
    mesh_adv_data_t* p_mesh_adv_data = (mesh_adv_data_t*) &p_packet->payload[0];

    if (length > RBC_MESH_VALUE_MAX_LEN)
    {
        return NRF_ERROR_INVALID_LENGTH;
    }

    mesh_packet_set_local_addr(p_packet);

    p_packet->header.length = MESH_PACKET_OVERHEAD + length;
    p_packet->header.type = BLE_PACKET_TYPE_ADV_NONCONN_IND;

    /* fill mesh adv data header fields */
    p_mesh_adv_data->adv_data_length = MESH_PACKET_ADV_OVERHEAD + length;
    p_mesh_adv_data->adv_data_type = MESH_ADV_DATA_TYPE;
    p_mesh_adv_data->mesh_uuid = MESH_UUID;

    p_mesh_adv_data->handle = handle;
    p_mesh_adv_data->version = version;
    if (length > 0 && data != NULL && length <= RBC_MESH_VALUE_MAX_LEN)
    {
        memcpy(p_mesh_adv_data->data, data, length);
    }

    return NRF_SUCCESS;
}
コード例 #5
0
static uint32_t bl_evt_handler(bl_evt_t* p_evt)
{
    static bl_cmd_t rsp_cmd;
    bool respond = false;
    switch (p_evt->type)
    {
        case BL_EVT_TYPE_DFU_ABORT:
            bootloader_abort(p_evt->params.dfu.abort.reason);

            /* If bootloader abort returned, it means that the application
             * doesn't work, and we should return to the dfu operation. */
            dfu_mesh_start();
            break;
        case BL_EVT_TYPE_TX_RADIO:
        {
            mesh_packet_t* p_packet = NULL;
            if (!mesh_packet_acquire(&p_packet))
            {
                return NRF_ERROR_NO_MEM;
            }

            mesh_packet_set_local_addr(p_packet);
            p_packet->header.type = BLE_PACKET_TYPE_ADV_NONCONN_IND;
            p_packet->header.length = DFU_PACKET_OVERHEAD + p_evt->params.tx.radio.length;
            ((ble_ad_t*) p_packet->payload)->adv_data_type = MESH_ADV_DATA_TYPE;
            ((ble_ad_t*) p_packet->payload)->data[0] = (MESH_UUID & 0xFF);
            ((ble_ad_t*) p_packet->payload)->data[1] = (MESH_UUID >> 8) & 0xFF;
            ((ble_ad_t*) p_packet->payload)->adv_data_length = DFU_PACKET_ADV_OVERHEAD + p_evt->params.tx.radio.length;
            memcpy(&p_packet->payload[4], p_evt->params.tx.radio.p_dfu_packet, p_evt->params.tx.radio.length);

            bool success = transport_tx(p_packet,
                                        p_evt->params.tx.radio.tx_slot,
                                        p_evt->params.tx.radio.tx_count,
                                        (tx_interval_type_t) p_evt->params.tx.radio.interval_type);
            mesh_packet_ref_count_dec(p_packet);

            if (!success)
            {
                return NRF_ERROR_INTERNAL;
            }
            break;
        }
        case BL_EVT_TYPE_TX_ABORT:
            transport_tx_abort(p_evt->params.tx.abort.tx_slot);
            break;
        case BL_EVT_TYPE_TX_SERIAL:
        {
#ifdef RBC_MESH_SERIAL
            serial_evt_t serial_evt;
            serial_evt.opcode = SERIAL_EVT_OPCODE_DFU;
            memcpy(&serial_evt.params.dfu.packet,
                    p_evt->params.tx.serial.p_dfu_packet,
                    p_evt->params.tx.serial.length);
            serial_evt.length = SERIAL_PACKET_OVERHEAD + p_evt->params.tx.serial.length;
            if (!serial_handler_event_send(&serial_evt))
            {
                return NRF_ERROR_INTERNAL;
            }
            break;
#endif
        }
        case BL_EVT_TYPE_TIMER_SET:
            set_timeout(US_TO_RTC_TICKS(p_evt->params.timer.set.delay_us), TIMEOUT_ACTION_DFU_TIMEOUT);
            break;

        case BL_EVT_TYPE_DFU_NEW_FW:
            {
                stop_timeout();
                __LOG("New FW event\n");
                switch (p_evt->params.dfu.new_fw.fw_type)
                {
                    case DFU_TYPE_APP:
                        __LOG("\tAPP: %08x.%04x:%08x\n",
                                (uint32_t) p_evt->params.dfu.new_fw.fwid.app.company_id,
                                (uint32_t) p_evt->params.dfu.new_fw.fwid.app.app_id,
                                (uint32_t) p_evt->params.dfu.new_fw.fwid.app.app_version);
                        break;
                    case DFU_TYPE_SD:
                        __LOG("\tSD: %04x\n",
                                (uint32_t) p_evt->params.dfu.new_fw.fwid.sd);
                        break;
                    case DFU_TYPE_BOOTLOADER:
                        __LOG("\tBL: %02x:%02x\n",
                                (uint32_t) p_evt->params.dfu.new_fw.fwid.bootloader.id,
                                (uint32_t) p_evt->params.dfu.new_fw.fwid.bootloader.ver);
                        break;
                    default: break;
                }
                /* accept all new firmware, as the bootloader wouldn't run
                   unless there's an actual reason for it. */
                rsp_cmd.type = BL_CMD_TYPE_DFU_START_TARGET;
                rsp_cmd.params.dfu.start.target.p_bank_start = (uint32_t*) 0xFFFFFFFF; /* no banking */
                rsp_cmd.params.dfu.start.target.type = p_evt->params.dfu.new_fw.fw_type;
                rsp_cmd.params.dfu.start.target.fwid = p_evt->params.dfu.new_fw.fwid;
                respond = true;
            }
            break;

        case BL_EVT_TYPE_BANK_AVAILABLE:
            __LOG("Bank:\n");
            switch (p_evt->params.bank_available.bank_dfu_type)
            {
                case DFU_TYPE_APP:
                    __LOG("\tAPP: %08x.%04x:%08x\n",
                            (uint32_t) p_evt->params.bank_available.bank_fwid.app.company_id,
                            (uint32_t) p_evt->params.bank_available.bank_fwid.app.app_id,
                            (uint32_t) p_evt->params.bank_available.bank_fwid.app.app_version);
                    break;
                case DFU_TYPE_SD:
                    __LOG("\tSD: %04x\n",
                            (uint32_t) p_evt->params.bank_available.bank_fwid.sd);
                    break;
                case DFU_TYPE_BOOTLOADER:
                    __LOG("\tBL: %02x:%02x\n",
                            (uint32_t) p_evt->params.bank_available.bank_fwid.bootloader.id,
                            (uint32_t) p_evt->params.bank_available.bank_fwid.bootloader.ver);
                    break;
                default: break;
            }
            __LOG("\tLocation: 0x%x\n", p_evt->params.bank_available.p_bank_addr);
            __LOG("\tLength: 0x%x\n", p_evt->params.bank_available.bank_length);
            if (p_evt->params.bank_available.bank_dfu_type == DFU_TYPE_BOOTLOADER)
            {
                if (!dfu_mesh_app_is_valid())
                {
                    dfu_bank_flash(DFU_TYPE_BOOTLOADER);
                }
            }
            break;

        case BL_EVT_TYPE_DFU_REQ:
            {
                /* Always attempt to relay incoming transfers in BL mode. Will
                   not abort ongoing transfers. */
                if (p_evt->params.dfu.req.role == DFU_ROLE_RELAY)
                {
                    stop_timeout();
                    bl_cmd_t relay_cmd;
                    relay_cmd.type = BL_CMD_TYPE_DFU_START_RELAY;
                    relay_cmd.params.dfu.start.relay.fwid = p_evt->params.dfu.req.fwid;
                    relay_cmd.params.dfu.start.relay.type = p_evt->params.dfu.req.dfu_type;
                    relay_cmd.params.dfu.start.relay.transaction_id = p_evt->params.dfu.req.transaction_id;
                    bootloader_cmd_send(&relay_cmd);
                }
            }
            break;

        case BL_EVT_TYPE_DFU_START:
            set_timeout(TIMER_START_TIMEOUT, TIMEOUT_ACTION_DFU_ABORT);
            break;
        case BL_EVT_TYPE_DFU_DATA_SEGMENT_RX:
            __LOG("RX %u/%u\n",
                    p_evt->params.dfu.data_segment.received_segment,
                    p_evt->params.dfu.data_segment.total_segments);
            set_timeout(TIMER_DATA_TIMEOUT, TIMEOUT_ACTION_DFU_ABORT);
            break;

        case BL_EVT_TYPE_DFU_END:
            if (p_evt->params.dfu.end.dfu_type == DFU_TYPE_APP ||
                p_evt->params.dfu.end.dfu_type == DFU_TYPE_SD)
            {
                /* attempt to reboot to app */
                bootloader_abort(DFU_END_SUCCESS);
            }
            break;

        /* Defer the flash operations to an asynchronous handler. Doing it
           inline causes stack overflow, as the bootloader continues in the
           response callback. */
        case BL_EVT_TYPE_FLASH_WRITE:
            {
                if (!IS_WORD_ALIGNED(p_evt->params.flash.write.start_addr) ||
                    !IS_WORD_ALIGNED(p_evt->params.flash.write.p_data))
                {
                    return NRF_ERROR_INVALID_ADDR;
                }
                if (!IS_WORD_ALIGNED(p_evt->params.flash.write.length))
                {
                    return NRF_ERROR_INVALID_LENGTH;
                }
                if ((p_evt->params.flash.write.start_addr + p_evt->params.flash.write.length) > NRF_UICR->BOOTLOADERADDR &&
                    p_evt->params.flash.write.start_addr < 0x3f800)
                {
                    APP_ERROR_CHECK(NRF_ERROR_INVALID_ADDR);
                }
                flash_queue_entry_t queue_entry;
                queue_entry.type = FLASH_OP_TYPE_WRITE;
                memcpy(&queue_entry.op, &p_evt->params.flash, sizeof(flash_op_t));
                if (fifo_push(&m_flash_fifo, &queue_entry) != NRF_SUCCESS)
                {
                    __LOG(RTT_CTRL_TEXT_RED "FLASH FIFO FULL :( Increase the fifo size.\n");
                    return NRF_ERROR_NO_MEM;
                }
                NVIC_SetPendingIRQ(FLASH_HANDLER_IRQn);
            }
            break;
        case BL_EVT_TYPE_FLASH_ERASE:
            {
                flash_queue_entry_t queue_entry;
                queue_entry.type = FLASH_OP_TYPE_ERASE;
                memcpy(&queue_entry.op, &p_evt->params.flash, sizeof(flash_op_t));
                if (fifo_push(&m_flash_fifo, &queue_entry) != NRF_SUCCESS)
                {
                    __LOG(RTT_CTRL_TEXT_RED "FLASH FIFO FULL :( Increase the fifo size.\n");
                    return NRF_ERROR_NO_MEM;
                }
                NVIC_SetPendingIRQ(FLASH_HANDLER_IRQn);
            }
            break;
        default:
            return NRF_ERROR_NOT_SUPPORTED;
    }
    if (respond)
    {
        /* tail recursion */
        return bl_cmd_handler(&rsp_cmd);
    }
    else
    {
        return NRF_SUCCESS;
    }
}
コード例 #6
0
uint32_t dfu_evt_handler(bl_evt_t* p_evt)
{
    __LOG("BL EVT (0x%x)\n", p_evt->type);
    switch (p_evt->type)
    {
        case BL_EVT_TYPE_ECHO:
            __LOG("\tEcho: %s\n", p_evt->params.echo.str);
            break;
        case BL_EVT_TYPE_DFU_ABORT:
            {
                __LOG("\tAbort event. Reason: 0x%x\n", p_evt->params.dfu.abort.reason);
                rbc_mesh_event_t evt;
                evt.type = RBC_MESH_EVENT_TYPE_DFU_END;
                evt.params.dfu.end.dfu_type = m_transfer_state.type;
                evt.params.dfu.end.role = m_transfer_state.role;
                evt.params.dfu.end.fwid = m_transfer_state.fwid;
                evt.params.dfu.end.end_reason = p_evt->params.dfu.abort.reason;
                memset(&m_transfer_state, 0, sizeof(dfu_transfer_state_t));
                rbc_mesh_event_push(&evt);
            }
            break;

        case BL_EVT_TYPE_DFU_NEW_FW:
            {
                __LOG("\tNew firmware!\n");
                rbc_mesh_event_t evt;
                evt.type = RBC_MESH_EVENT_TYPE_DFU_NEW_FW_AVAILABLE;
                evt.params.dfu.new_fw.dfu_type = p_evt->params.dfu.new_fw.fw_type;
                evt.params.dfu.new_fw.new_fwid = p_evt->params.dfu.new_fw.fwid;
                if (get_curr_fwid(
                            p_evt->params.dfu.new_fw.fw_type,
                            &evt.params.dfu.new_fw.current_fwid) == NRF_SUCCESS)
                {
                    rbc_mesh_event_push(&evt);
                }
            }
            break;

        case BL_EVT_TYPE_DFU_REQ:
            {
                __LOG("\tSource/relay request!\n");
                /* Forward to application */
                rbc_mesh_event_t evt;
                switch (p_evt->params.dfu.req.role)
                {
                    case DFU_ROLE_RELAY:
                        evt.type = RBC_MESH_EVENT_TYPE_DFU_RELAY_REQ;
                        evt.params.dfu.relay_req.dfu_type = p_evt->params.dfu.req.dfu_type;
                        evt.params.dfu.relay_req.fwid = p_evt->params.dfu.req.fwid;
                        evt.params.dfu.relay_req.authority = p_evt->params.dfu.req.dfu_type;
                        break;
                    case DFU_ROLE_SOURCE:
                        evt.type = RBC_MESH_EVENT_TYPE_DFU_SOURCE_REQ;
                        evt.params.dfu.source_req.dfu_type = p_evt->params.dfu.req.dfu_type;
                        break;
                    default:
                        return NRF_ERROR_NOT_SUPPORTED;
                }
                rbc_mesh_event_push(&evt);
            }
            break;

        case BL_EVT_TYPE_DFU_START:
            {
                __LOG("\tDFU start\n");
                if (p_evt->params.dfu.start.role == DFU_ROLE_TARGET)
                {
                    m_transfer_state.state = DFU_STATE_TARGET;
                }
                else if (p_evt->params.dfu.start.role == DFU_ROLE_RELAY)
                {
                    m_transfer_state.state = DFU_STATE_RELAY;
                }
                rbc_mesh_event_t evt;
                evt.type = RBC_MESH_EVENT_TYPE_DFU_START;
                evt.params.dfu.start.dfu_type = p_evt->params.dfu.start.dfu_type;
                evt.params.dfu.start.fwid = p_evt->params.dfu.start.fwid;
                evt.params.dfu.start.role = p_evt->params.dfu.start.role;
                rbc_mesh_event_push(&evt);
                m_timer_evt.cb = abort_timeout;
                return timer_sch_reschedule(&m_timer_evt, timer_now() + TIMER_START_TIMEOUT);
            }


        case BL_EVT_TYPE_DFU_DATA_SEGMENT_RX:
            m_transfer_state.data_progress = (uint8_t) (
                    ((uint32_t) p_evt->params.dfu.data_segment.received_segment * 100) /
                    ((uint32_t) p_evt->params.dfu.data_segment.total_segments));
            m_timer_evt.cb = abort_timeout;
            return timer_sch_reschedule(&m_timer_evt, timer_now() + TIMER_DATA_TIMEOUT);

        case BL_EVT_TYPE_DFU_END:
            {
                __LOG("\tDFU END!\n");
                rbc_mesh_event_t evt;
                evt.type = RBC_MESH_EVENT_TYPE_DFU_END;
                evt.params.dfu.end.dfu_type = p_evt->params.dfu.end.dfu_type;
                evt.params.dfu.end.fwid = p_evt->params.dfu.end.fwid;
                evt.params.dfu.end.end_reason = DFU_END_SUCCESS;
                evt.params.dfu.end.role = p_evt->params.dfu.end.role;
                rbc_mesh_event_push(&evt);
                timer_sch_abort(&m_timer_evt);
            }
            break;

        case BL_EVT_TYPE_BANK_AVAILABLE:
            {
                __LOG("\tDFU BANK AVAILABLE\n");
                rbc_mesh_event_t evt;
                evt.type = RBC_MESH_EVENT_TYPE_DFU_BANK_AVAILABLE;
                evt.params.dfu.bank.dfu_type     = p_evt->params.bank_available.bank_dfu_type;
                evt.params.dfu.bank.fwid         = p_evt->params.bank_available.bank_fwid;
                evt.params.dfu.bank.is_signed    = p_evt->params.bank_available.is_signed;
                evt.params.dfu.bank.p_start_addr = p_evt->params.bank_available.p_bank_addr;
                rbc_mesh_event_push(&evt);
            }
            break;

        case BL_EVT_TYPE_FLASH_ERASE:
            {

                if (p_evt->params.flash.erase.start_addr & (NRF_FICR->CODEPAGESIZE - 1))
                {
                    return NRF_ERROR_INVALID_ADDR;
                }
                if (p_evt->params.flash.erase.length & (NRF_FICR->CODEPAGESIZE - 1))
                {
                    return NRF_ERROR_INVALID_LENGTH;
                }

                uint32_t error_code = mesh_flash_op_push(FLASH_OP_TYPE_ERASE, &p_evt->params.flash);
                if (error_code == NRF_SUCCESS)
                {
                    __LOG("\tErase flash at: 0x%x (length %d)\n", p_evt->params.flash.erase.start_addr, p_evt->params.flash.erase.length);
                }
                return error_code;
            }

        case BL_EVT_TYPE_FLASH_WRITE:
            {
                if (!IS_WORD_ALIGNED(p_evt->params.flash.write.start_addr))
                {
                    return NRF_ERROR_INVALID_ADDR;
                }
                if (!IS_WORD_ALIGNED(p_evt->params.flash.write.length))
                {
                    return NRF_ERROR_INVALID_LENGTH;
                }
                uint32_t error_code = mesh_flash_op_push(FLASH_OP_TYPE_WRITE, &p_evt->params.flash);
                if (error_code == NRF_SUCCESS)
                {
                    __LOG("\tWrite flash at: 0x%x (length %d)\n", p_evt->params.flash.write.start_addr, p_evt->params.flash.write.length);
                }
                return error_code;
            }

        case BL_EVT_TYPE_TX_RADIO:
            __LOG("\tRADIO TX! SLOT %d, count %d, interval: %s, handle: %x\n",
                p_evt->params.tx.radio.tx_slot,
                p_evt->params.tx.radio.tx_count,
                p_evt->params.tx.radio.interval_type == BL_RADIO_INTERVAL_TYPE_EXPONENTIAL ? "exponential" : "periodic",
                p_evt->params.tx.radio.p_dfu_packet->packet_type
            );

            if (m_tx_slots[p_evt->params.tx.radio.tx_slot].p_packet)
            {
                mesh_packet_ref_count_dec(m_tx_slots[p_evt->params.tx.radio.tx_slot].p_packet);
                m_tx_slots[p_evt->params.tx.radio.tx_slot].p_packet = NULL;
            }
            if (mesh_packet_acquire(&m_tx_slots[p_evt->params.tx.radio.tx_slot].p_packet))
            {
                uint32_t time_now = timer_now();
                /* build packet */
                mesh_packet_set_local_addr(m_tx_slots[p_evt->params.tx.radio.tx_slot].p_packet);
                m_tx_slots[p_evt->params.tx.radio.tx_slot].p_packet->header.type = BLE_PACKET_TYPE_ADV_NONCONN_IND;
                m_tx_slots[p_evt->params.tx.radio.tx_slot].p_packet->header.length = DFU_PACKET_OVERHEAD + p_evt->params.tx.radio.length;
                ((ble_ad_t*) m_tx_slots[p_evt->params.tx.radio.tx_slot].p_packet->payload)->adv_data_type = MESH_ADV_DATA_TYPE;
                ((ble_ad_t*) m_tx_slots[p_evt->params.tx.radio.tx_slot].p_packet->payload)->data[0] = (MESH_UUID & 0xFF);
                ((ble_ad_t*) m_tx_slots[p_evt->params.tx.radio.tx_slot].p_packet->payload)->data[1] = (MESH_UUID >> 8) & 0xFF;
                ((ble_ad_t*) m_tx_slots[p_evt->params.tx.radio.tx_slot].p_packet->payload)->adv_data_length = DFU_PACKET_ADV_OVERHEAD + p_evt->params.tx.radio.length;
                memcpy(&m_tx_slots[p_evt->params.tx.radio.tx_slot].p_packet->payload[4], p_evt->params.tx.radio.p_dfu_packet, p_evt->params.tx.radio.length);

                /* fill other fields in the TX slot. */
                m_tx_slots[p_evt->params.tx.radio.tx_slot].interval_type = p_evt->params.tx.radio.interval_type;
                m_tx_slots[p_evt->params.tx.radio.tx_slot].repeats = p_evt->params.tx.radio.tx_count;
                m_tx_slots[p_evt->params.tx.radio.tx_slot].tx_count = 0;
                m_tx_slots[p_evt->params.tx.radio.tx_slot].order_time = time_now + DFU_TX_TIMER_MARGIN_US + (rand_prng_get(&m_prng) & (DFU_TX_START_DELAY_MASK_US));

                /* Fire away */
                if (!m_tx_scheduled || TIMER_DIFF(m_tx_slots[p_evt->params.tx.radio.tx_slot].order_time, time_now) < TIMER_DIFF(m_tx_timer_evt.timestamp, time_now))
                {
                    m_tx_scheduled = true;
                    timer_sch_reschedule(&m_tx_timer_evt,
                            m_tx_slots[p_evt->params.tx.radio.tx_slot].order_time);
                }
            }
            else
            {
                return NRF_ERROR_NO_MEM;