void fm_entry_uart(void) { qm_gpio_state_t state; /* * qda_init() implicitly initializes the HW required by XMODEM (i.e., * UART and PIC timer) and the DFU state machine. */ qda_init(); do { /* * The following function returns only when no data is received * for 10 seconds. */ qda_receive_loop(); fm_gpio_get_state(&state); } while (state == QM_GPIO_LOW); /* * Cold reboot in order to restore the default system configuration * (thus getting rid of all the changes done by the FM mode, like the * UART configuration). */ qm_soc_reset(QM_COLD_RESET); }
/** * Process QDA packet. * * Parse, process, and reply to an incoming QDA packet. * * @param[in] data The buffer containing the packet. * @param[in] len The length of packet or its upper bound (since XMODEM may * add some padding bytes). */ static void qda_process_pkt(uint8_t *data, size_t len) { qda_pkt_t *pkt; qda_dnl_req_payload_t *dnload_req; qda_upl_req_payload_t *upload_req; qda_set_alt_setting_payload_t *altset_req; size_t expected_len; dfu_dev_state_t state; dfu_dev_status_t status; uint32_t poll_timeout; pkt = (qda_pkt_t *)data; expected_len = sizeof(*pkt); switch (pkt->type) { case QDA_PKT_DEV_DESC_REQ: qda_dev_dsc_rsp(); break; case QDA_PKT_DFU_DESC_REQ: qda_dfu_dsc_rsp(); break; case QDA_PKT_DFU_SET_ALT_SETTING: altset_req = (qda_set_alt_setting_payload_t *)pkt->payload; STALL_AND_BREAK_ON_ERR( dfu_set_alt_setting(altset_req->alt_setting)); qda_ack(); break; case QDA_PKT_DFU_DNLOAD_REQ: dnload_req = (qda_dnl_req_payload_t *)pkt->payload; expected_len += sizeof(*dnload_req) + dnload_req->data_len; if ((len < expected_len) || dfu_process_dnload(dnload_req->block_num, dnload_req->data, dnload_req->data_len)) { qda_stall(); break; } qda_ack(); break; case QDA_PKT_DFU_UPLOAD_REQ: upload_req = (qda_upl_req_payload_t *)pkt->payload; /* UPLOAD requests are handled differently from the others in * order to reuse qda_buf */ handle_upload_req(upload_req); break; case QDA_PKT_DFU_GETSTATUS_REQ: STALL_AND_BREAK_ON_ERR( dfu_get_status(&status, &state, &poll_timeout)); qda_dfu_get_status_rsp(state, status, poll_timeout); break; case QDA_PKT_DFU_CLRSTATUS: STALL_AND_BREAK_ON_ERR(dfu_clr_status()); qda_ack(); break; case QDA_PKT_DFU_GETSTATE_REQ: STALL_AND_BREAK_ON_ERR(dfu_get_state(&state)); qda_dfu_get_state_rsp(state); break; case QDA_PKT_DFU_ABORT: STALL_AND_BREAK_ON_ERR(dfu_abort()); qda_ack(); break; case QDA_PKT_RESET: qda_ack(); qm_soc_reset(QM_COLD_RESET); break; /* QDA_PKT_DFU_DETACH should not be received */ default: /* NOTE: how to handle bad QDA requests? Send a QDA_STALL * message for now */ qda_stall(); break; } }