MODULE_CALLTYPE static u16 cflie_callback() { switch (phase) { case CFLIE_INIT_SEARCH: send_search_packet(); phase = CFLIE_SEARCH; break; case CFLIE_INIT_CRTP_LOG: if (crtp_log_setup_state_machine()) { phase = CFLIE_INIT_DATA; } break; case CFLIE_INIT_DATA: send_cmd_packet(); phase = CFLIE_DATA; break; case CFLIE_SEARCH: switch (packet_ack()) { case PKT_PENDING: return PACKET_CHKTIME; // packet send not yet complete case PKT_ACKED: phase = CFLIE_DATA; PROTOCOL_SetBindState(0); MUSIC_Play(MUSIC_DONE_BINDING); break; case PKT_TIMEOUT: send_search_packet(); counter = BIND_COUNT; } break; case CFLIE_DATA: if (Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_ON_CRTPLOG) { update_telemetry_crtplog(); } else if (Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_ON_ACKPKT) { update_telemetry_ackpkt(); } if (packet_ack() == PKT_PENDING) return PACKET_CHKTIME; // packet send not yet complete send_cmd_packet(); break; } return PACKET_PERIOD; // Packet at standard protocol interval }
MODULE_CALLTYPE static u16 cflie_callback() { switch (phase) { case CFLIE_INIT_SEARCH: send_search_packet(); phase = CFLIE_SEARCH; break; case CFLIE_INIT_TELEMETRY: if (telemetry_setup_state_machine()) { phase = CFLIE_INIT_DATA; } break; case CFLIE_INIT_DATA: send_cmd_packet(); phase = CFLIE_DATA; break; case CFLIE_SEARCH: switch (packet_ack()) { case PKT_PENDING: return PACKET_CHKTIME; // packet send not yet complete case PKT_ACKED: phase = CFLIE_DATA; PROTOCOL_SetBindState(0); MUSIC_Play(MUSIC_DONE_BINDING); break; case PKT_TIMEOUT: send_search_packet(); counter = BIND_COUNT; } break; case CFLIE_DATA: update_telemetry(); if (packet_ack() == PKT_PENDING) return PACKET_CHKTIME; // packet send not yet complete send_cmd_packet(); break; } return PACKET_PERIOD; // Packet at standard protocol interval }
int hw_start(struct net_adapter *adapter) { struct wimax_cfg *g_cfg = adapter->pdata->g_cfg; if (load_wimax_image(g_cfg->wimax_mode)) return STATUS_UNSUCCESSFUL; adapter->download_complete = FALSE; if (adapter->downloading) { sdio_claim_host(adapter->func); send_cmd_packet(adapter, MSG_DRIVER_OK_REQ); sdio_release_host(adapter->func); switch (wait_event_interruptible_timeout (adapter->download_event, (adapter->download_complete == TRUE), msecs_to_jiffies(FWDOWNLOAD_TIMEOUT))) { case 0: /* timeout */ dump_debug("Error hw_start :" "F/W Download timeout failed"); adapter->halted = TRUE; return STATUS_UNSUCCESSFUL; case -ERESTARTSYS: /* Interrupted by signal */ dump_debug("Error hw_start : -ERESTARTSYS retry"); return STATUS_UNSUCCESSFUL; default: /* normal condition check */ if (adapter->removed == TRUE || adapter->halted == TRUE) { dump_debug("Error hw_start : " " F/W Download surprise removed"); return STATUS_UNSUCCESSFUL; } /*Setup hostwake interrupt*/ if (cmc732_setup_wake_irq(adapter) < 0) dump_debug("hw_start : " " Error setting up wimax_int"); break; } adapter->downloading = FALSE; } return STATUS_SUCCESS; }
int wimax_hw_start(struct net_adapter *adapter) { struct wimax732_platform_data *pdata = adapter->pdata; pdata->g_cfg->wimax_status = WIMAX_STATE_READY; adapter->download_complete = false; adapter->rx_task = kthread_create( cmc732_receive_thread, adapter, "%s", "cmc732_receive_thread"); adapter->tx_task = kthread_create( cmc732_send_thread, adapter, "%s", "cmc732_send_thread"); init_waitqueue_head(&adapter->receive_event); init_waitqueue_head(&adapter->send_event); if (adapter->rx_task && adapter->tx_task) { wake_up_process(adapter->rx_task); wake_up_process(adapter->tx_task); } else { pr_debug("Unable to create send-receive threads"); return STATUS_UNSUCCESSFUL; } if (load_wimax_image(pdata->g_cfg->wimax_mode, adapter)) return STATUS_UNSUCCESSFUL; if (adapter->downloading) { send_cmd_packet(adapter, MSG_DRIVER_OK_REQ); switch (wait_event_interruptible_timeout( adapter->download_event, (adapter->download_complete), HZ*FWDOWNLOAD_TIMEOUT)) { case 0: /* timeout */ pr_debug("Error wimax_hw_start : \ F/W Download timeout failed"); goto download_fail; case -ERESTARTSYS: /* Interrupted by signal */ pr_debug("Error wimax_hw_start :" "-ERESTARTSYS retry"); goto download_fail; default: /* normal condition check */ if (adapter->removed || adapter->halted) { pr_debug("Error wimax_hw_start : \ F/W Download surprise removed"); goto download_fail; } pr_debug("wimax_hw_start : F/W Download Complete"); unload_wimax_image(adapter); if (cmc732_setup_wake_irq(adapter) < 0) pr_debug("wimax_hw_start :" "Error setting up wimax_int"); break; }
static void process_indicate_packet(struct net_adapter *adapter, u8 *buffer) { struct wimax_msg_header *packet; struct wimax_cfg *g_cfg = adapter->pdata->g_cfg; char *tmp_byte; packet = (struct wimax_msg_header *)buffer; if (packet->type != be16_to_cpu(ETHERTYPE_DL)) { pr_warn("%s: not a download packet\n", __func__); return; } switch (be16_to_cpu(packet->id)) { case MSG_DRIVER_OK_RESP: pr_debug("%s: MSG_DRIVER_OK_RESP\n", __func__); send_image_info_packet(adapter, MSG_IMAGE_INFO_REQ); break; case MSG_IMAGE_INFO_RESP: pr_debug("%s: MSG_IMAGE_INFO_RESP\n", __func__); send_image_data_packet(adapter, MSG_IMAGE_DATA_REQ); break; case MSG_IMAGE_DATA_RESP: if (adapter->wimax_image.offset == adapter->wimax_image.size) { pr_debug("%s: Image Download Complete\n", __func__); send_cmd_packet(adapter, MSG_RUN_REQ); } else { send_image_data_packet(adapter, MSG_IMAGE_DATA_REQ); } break; case MSG_RUN_RESP: tmp_byte = (char *)(buffer + sizeof(struct wimax_msg_header)); if (*tmp_byte != 0x01) break; adapter->download_complete = true; wake_up_interruptible(&adapter->download_event); pr_debug("%s: MSG_RUN_RESP\n", __func__); if (g_cfg->wimax_mode == SDIO_MODE || g_cfg->wimax_mode == DM_MODE || g_cfg->wimax_mode == USB_MODE || g_cfg->wimax_mode == USIM_RELAY_MODE) { adapter->mac_task = kthread_create( wimax_hw_get_mac_address, adapter, "%s", "mac_request_thread"); if (adapter->mac_task) wake_up_process(adapter->mac_task); } else if (g_cfg->wimax_mode == WTM_MODE || g_cfg->wimax_mode == AUTH_MODE) { adapter->download_complete = true; wake_up_interruptible(&adapter->download_event); } break; default: pr_err("%s: Unknown packet type\n", __func__); break; } }
// State machine for setting up telemetry // returns 1 when the state machine has completed, 0 otherwise static u8 telemetry_setup_state_machine() { u8 state_machine_completed = 0; // A note on the design of this state machine: // // Responses from the crazyflie come in the form of ACK payloads. // There is no retry logic associated with ACK payloads, so it is possible // to miss a response from the crazyflie. To avoid this, the request // packet must be re-sent until the expected response is received. However, // re-sending the same request generates another response in the crazyflie // Rx queue, which can produce large backlogs of duplicate responses. // // To avoid this backlog but still guard against dropped ACK payloads, // transmit cmd packets (which don't generate responses themselves) // until an empty ACK payload is received (the crazyflie alternates between // 0xF3 and 0xF7 for empty ACK payloads) which indicates the Rx queue on the // crazyflie has been drained. If the queue has been drained and the // desired ACK has still not been received, it was likely dropped and the // request should be re-transmit. switch (telemetry_setup_state) { case CFLIE_TELEM_SETUP_STATE_INIT: toc_size = 0; next_toc_variable = 0; vbat_var_id = 0; extvbat_var_id = 0; telemetry_setup_state = CFLIE_TELEM_SETUP_STATE_SEND_CMD_GET_INFO; // fallthrough case CFLIE_TELEM_SETUP_STATE_SEND_CMD_GET_INFO: telemetry_setup_state = CFLIE_TELEM_SETUP_STATE_ACK_CMD_GET_INFO; tx_packet[0] = crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_TOC); tx_packet[1] = CRTP_LOG_TOC_CMD_INFO; tx_payload_len = 2; send_packet(); break; case CFLIE_TELEM_SETUP_STATE_ACK_CMD_GET_INFO: if (packet_ack() == PKT_ACKED) { if (rx_payload_len >= 3 && rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_TOC) && rx_packet[1] == CRTP_LOG_TOC_CMD_INFO) { // Received the ACK payload. Save the toc_size // and advance to the next state toc_size = rx_packet[2]; telemetry_setup_state = CFLIE_TELEM_SETUP_STATE_SEND_CMD_GET_ITEM; return state_machine_completed; } else if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) { // "empty" ACK packet received - likely missed the ACK // payload we are waiting for. // return to the send state and retransmit the request telemetry_setup_state = CFLIE_TELEM_SETUP_STATE_SEND_CMD_GET_INFO; return state_machine_completed; } } // Otherwise, send a cmd packet to get the next ACK in the Rx queue send_cmd_packet(); break; case CFLIE_TELEM_SETUP_STATE_SEND_CMD_GET_ITEM: telemetry_setup_state = CFLIE_TELEM_SETUP_STATE_ACK_CMD_GET_ITEM; tx_packet[0] = crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_TOC); tx_packet[1] = CRTP_LOG_TOC_CMD_ELEMENT; tx_packet[2] = next_toc_variable; tx_payload_len = 3; send_packet(); break; case CFLIE_TELEM_SETUP_STATE_ACK_CMD_GET_ITEM: if (packet_ack() == PKT_ACKED) { if (rx_payload_len >= 3 && rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_TOC) && rx_packet[1] == CRTP_LOG_TOC_CMD_ELEMENT && rx_packet[2] == next_toc_variable) { // For every element in the TOC we must compare its // type (rx_packet[3]), group and name (back to back // null terminated strings starting with the fifth byte) // and see if it matches any of the variables we need // for logging // // Currently enabled for logging: // - vbatMV (LOG_UINT16) // - extVbatMV (LOG_UINT16) if(rx_packet[3] == vbat_var_type && (0 == strcmp((char*)&rx_packet[4], pm_group_name)) && (0 == strcmp((char*)&rx_packet[4 + strlen(pm_group_name) + 1], vbat_var_name))) { // Found the vbat element - save it for later vbat_var_id = next_toc_variable; } if(rx_packet[3] == extvbat_var_type && (0 == strcmp((char*)&rx_packet[4], pm_group_name)) && (0 == strcmp((char*)&rx_packet[4 + strlen(pm_group_name) + 1], extvbat_var_name))) { // Found the extvbat element - save it for later extvbat_var_id = next_toc_variable; } // Advance the toc variable counter // If there are more variables, read them // If not, move on to the next state next_toc_variable += 1; if(next_toc_variable >= toc_size) { telemetry_setup_state = CFLIE_TELEM_SETUP_STATE_SEND_CONTROL_CREATE_BLOCK; } else { // There are more TOC elements to get telemetry_setup_state = CFLIE_TELEM_SETUP_STATE_SEND_CMD_GET_ITEM; } return state_machine_completed; } else if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) { // "empty" ACK packet received - likely missed the ACK // payload we are waiting for. // return to the send state and retransmit the request telemetry_setup_state = CFLIE_TELEM_SETUP_STATE_SEND_CMD_GET_INFO; return state_machine_completed; } } // Otherwise, send a cmd packet to get the next ACK in the Rx queue send_cmd_packet(); break; case CFLIE_TELEM_SETUP_STATE_SEND_CONTROL_CREATE_BLOCK: telemetry_setup_state = CFLIE_TELEM_SETUP_STATE_ACK_CONTROL_CREATE_BLOCK; tx_packet[0] = crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_SETTINGS); tx_packet[1] = CRTP_LOG_SETTINGS_CMD_CREATE_BLOCK; tx_packet[2] = CFLIE_TELEM_LOG_BLOCK_ID; // Log block ID tx_packet[3] = vbat_var_type; // Variable type tx_packet[4] = vbat_var_id; // ID of the VBAT variable tx_packet[5] = extvbat_var_type; // Variable type tx_packet[6] = extvbat_var_id; // ID of the ExtVBat variable tx_payload_len = 7; send_packet(); break; case CFLIE_TELEM_SETUP_STATE_ACK_CONTROL_CREATE_BLOCK: if (packet_ack() == PKT_ACKED) { if (rx_payload_len >= 2 && rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_SETTINGS) && rx_packet[1] == CRTP_LOG_SETTINGS_CMD_CREATE_BLOCK) { // Received the ACK payload. Advance to the next state telemetry_setup_state = CFLIE_TELEM_SETUP_STATE_SEND_CONTROL_START_BLOCK; return state_machine_completed; } else if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) { // "empty" ACK packet received - likely missed the ACK // payload we are waiting for. // return to the send state and retransmit the request telemetry_setup_state = CFLIE_TELEM_SETUP_STATE_SEND_CONTROL_CREATE_BLOCK; return state_machine_completed; } } // Otherwise, send a cmd packet to get the next ACK in the Rx queue send_cmd_packet(); break; case CFLIE_TELEM_SETUP_STATE_SEND_CONTROL_START_BLOCK: telemetry_setup_state = CFLIE_TELEM_SETUP_STATE_ACK_CONTROL_START_BLOCK; tx_packet[0] = crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_SETTINGS); tx_packet[1] = CRTP_LOG_SETTINGS_CMD_START_LOGGING; tx_packet[2] = CFLIE_TELEM_LOG_BLOCK_ID; // Log block ID 1 tx_packet[3] = CFLIE_TELEM_LOG_BLOCK_PERIOD_10MS; // Log frequency in 10ms units tx_payload_len = 4; send_packet(); break; case CFLIE_TELEM_SETUP_STATE_ACK_CONTROL_START_BLOCK: if (packet_ack() == PKT_ACKED) { if (rx_payload_len >= 2 && rx_packet[0] == crtp_create_header(CRTP_PORT_LOG, CRTP_LOG_CHAN_SETTINGS) && rx_packet[1] == CRTP_LOG_SETTINGS_CMD_START_LOGGING) { // Received the ACK payload. Advance to the next state telemetry_setup_state = CFLIE_TELEM_SETUP_STATE_COMPLETE; return state_machine_completed; } else if (rx_packet[0] == 0xF3 || rx_packet[0] == 0xF7) { // "empty" ACK packet received - likely missed the ACK // payload we are waiting for. // return to the send state and retransmit the request telemetry_setup_state = CFLIE_TELEM_SETUP_STATE_SEND_CONTROL_START_BLOCK; return state_machine_completed; } } // Otherwise, send a cmd packet to get the next ACK in the Rx queue send_cmd_packet(); break; case CFLIE_TELEM_SETUP_STATE_COMPLETE: state_machine_completed = 1; return state_machine_completed; break; } return state_machine_completed; }