void packet_transmitted(hw_radio_packet_t* packet) { #if HW_NUM_LEDS > 0 led_toggle(0); #endif DPRINT("%d tx ok\n", counter); timer_post_task(&transmit_packet, 1000); hw_watchdog_feed(); }
void led_on_callback() { led_on(0); timer_post_task_delay(&led_on_callback, TIMER_TICKS_PER_SEC); timer_post_task_delay(&led_off_callback, TIMER_TICKS_PER_SEC*0.050); log_print_string("Toggled on %d", 0); hw_watchdog_feed(); }
void led_on_callback() { led_toggle(0); timer_post_task_delay(&led_on_callback, TIMER_TICKS_PER_SEC * 70); //timer_post_task_delay(&led_off_callback, TIMER_TICKS_PER_SEC*0.050); log_print_string("Toggled on %d", 0); console_print("Toggle led 0\r\n"); hw_watchdog_feed(); }
void read_rssi() { timestamped_rssi_t rssi_measurement; rssi_measurement.tick = timer_get_counter_value(); char rssi_samples_str[5 * RSSI_SAMPLES_PER_MEASUREMENT] = ""; int16_t max_rssi_sample = -200; for(int i = 0; i < RSSI_SAMPLES_PER_MEASUREMENT; i++) { rssi_measurement.rssi[i] = hw_radio_get_rssi(); if(rssi_measurement.rssi[i] > max_rssi_sample) max_rssi_sample = rssi_measurement.rssi[i]; sprintf(rssi_samples_str + (i * 5), ",%04i", rssi_measurement.rssi[i]); // TODO delay? } char str[80]; char channel_str[8] = ""; channel_id_to_string(&rx_cfg.channel_id, channel_str, sizeof(channel_str)); lcd_write_string(channel_str); sprintf(str, "%7s,%i%s\n", channel_str, rssi_measurement.tick, rssi_samples_str); console_print(str); #ifdef PLATFORM_EFM32GG_STK3700 //lcd_all_on(); lcd_write_number(max_rssi_sample); #elif defined HAS_LCD sprintf(str, "%7s,%d\n", channel_str, max_rssi_sample); lcd_write_string(str); #endif if(!use_manual_channel_switching) { switch_next_channel(); sched_post_task(&start_rx); } else { sched_post_task(&process_uart_rx_fifo); // check for UART commands first uint16_t delay = rand() % 5000; timer_post_task_delay(&read_rssi, delay); } hw_watchdog_feed(); }
void packet_received(hw_radio_packet_t* packet) { DPRINT("packet received @ %i , RSSI = %i\n", packet->rx_meta.timestamp, packet->rx_meta.rssi); #ifdef HAL_RADIO_USE_HW_CRC int cmp = memcmp(data, packet->data, packet->length-2); #else int cmp = memcmp(data, packet->data, packet->length); #endif if(cmp != 0) { DPRINT("Unexpected data received! %d\n", cmp); } else { DPRINT("RX OK!\n"); } hw_watchdog_feed(); }
// TODO we assume a fifo contains only ALP commands, but according to spec this can be any kind of "Request" // we will see later what this means. For instance how to add a request which starts D7AAdvP etc d7asp_queue_result_t d7asp_queue_alp_actions(d7asp_master_session_t* session, uint8_t* alp_payload_buffer, uint8_t alp_payload_length) { DPRINT("Queuing ALP actions"); // TODO can be called in all session states? assert(session == ¤t_master_session); // TODO tmp assert(session->request_buffer_tail_idx + alp_payload_length < MODULE_D7AP_FIFO_COMMAND_BUFFER_SIZE); assert(session->next_request_id < MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT); // TODO do not assert but let upper layer handle this single_request_retry_limit = 3; // TODO read from SEL config file // add request to buffer // TODO request can contain 1 or more ALP commands, find a way to group commands in requests instead of dumping all requests in one buffer uint8_t request_id = session->next_request_id; session->requests_indices[request_id] = session->request_buffer_tail_idx; session->requests_lengths[request_id] = alp_payload_length; memcpy(session->request_buffer + session->request_buffer_tail_idx, alp_payload_buffer, alp_payload_length); session->request_buffer_tail_idx += alp_payload_length + 1; session->next_request_id++; // TODO for master only set to pending when asked by upper layer (ie new function call) if(d7asp_state == D7ASP_STATE_IDLE) switch_state(D7ASP_STATE_MASTER); else if(d7asp_state == D7ASP_STATE_SLAVE) switch_state(D7ASP_STATE_SLAVE_PENDING_MASTER); return (d7asp_queue_result_t){ .fifo_token = session->token, .request_id = request_id }; } bool d7asp_process_received_packet(packet_t* packet, bool extension) { hw_watchdog_feed(); // TODO do here? d7asp_result_t result = { .channel = packet->hw_radio_packet.rx_meta.rx_cfg.channel_id, .rx_level = - packet->hw_radio_packet.rx_meta.rssi, .link_budget = (packet->dll_header.control_eirp_index + 32) - packet->hw_radio_packet.rx_meta.rssi, .target_rx_level = 80, // TODO not implemented yet, use default for now .status = { .ucast = 0, // TODO .nls = packet->d7anp_ctrl.origin_addressee_ctrl_nls_enabled, .retry = false, // TODO .missed = false, // TODO }, .response_to = packet->d7atp_tc, .addressee = packet->d7anp_addressee // .fifo_token and .seqnr filled below }; if(d7asp_state == D7ASP_STATE_MASTER) { assert(packet->d7atp_dialog_id == current_master_session.token); assert(packet->d7atp_transaction_id == current_request_id); // received ack DPRINT("Received ACK"); if(current_master_session.config.qos.qos_resp_mode != SESSION_RESP_MODE_NO && current_master_session.config.qos.qos_resp_mode != SESSION_RESP_MODE_NO_RPT) { // for SESSION_RESP_MODE_NO and SESSION_RESP_MODE_NO_RPT the request was already marked as done // upon successfull CSMA insertion. We don't care about response in these cases. result.fifo_token = current_master_session.token; result.seqnr = current_request_id; bitmap_set(current_master_session.success_bitmap, current_request_id); mark_current_request_done(); assert(packet != current_request_packet); } alp_d7asp_request_completed(result, packet->payload, packet->payload_length); // if(d7asp_init_args != NULL && d7asp_init_args->d7asp_fifo_request_completed_cb != NULL) // d7asp_init_args->d7asp_fifo_request_completed_cb(result, packet->payload, packet->payload_length); // TODO ALP should notify app if needed, refactor packet_queue_free_packet(packet); // ACK can be cleaned // switch to the state slave when the D7ATP Dialog Extension Procedure is initiated and all request are handled if ((extension) && (current_request_id == current_master_session.next_request_id - 1)) { DPRINT("Dialog Extension Procedure is initiated, mark the FIFO flush" " completed before switching to a responder state"); alp_d7asp_fifo_flush_completed(current_master_session.token, current_master_session.progress_bitmap, current_master_session.success_bitmap, REQUESTS_BITMAP_BYTE_COUNT); current_master_session.state = D7ASP_MASTER_SESSION_IDLE; d7atp_signal_dialog_termination(); switch_state(D7ASP_STATE_SLAVE); } return true; } else if(d7asp_state == D7ASP_STATE_IDLE || d7asp_state == D7ASP_STATE_SLAVE) { // received a request, start slave session, process and respond if(d7asp_state == D7ASP_STATE_IDLE) switch_state(D7ASP_STATE_SLAVE); // don't switch when already in slave state result.fifo_token = packet->d7atp_dialog_id; result.seqnr = packet->d7atp_transaction_id; // TODO move to ALP if(packet->payload_length > 0) { if(alp_get_operation(packet->payload) == ALP_OP_RETURN_FILE_DATA) { // received unsollicited data, notify appl DPRINT("Received unsollicited data"); if(d7asp_init_args != NULL && d7asp_init_args->d7asp_received_unsollicited_data_cb != NULL) d7asp_init_args->d7asp_received_unsollicited_data_cb(result, packet->payload, packet->payload_length); packet->payload_length = 0; // no response payload } else { // build response, we will reuse the same packet for this // we will first try to process the command against the local FS // if the FS handler cannot process this, and a status response is requested, a status operand will be present in the response payload bool handled = alp_process_command(packet->payload, packet->payload_length, packet->payload, &packet->payload_length, ALP_CMD_ORIGIN_D7ASP); // ... and if not handled we'll give the application a chance to handle this by returning an ALP response. // if the application fails to handle the request as well the ALP status operand supplied by alp_process_command_fs_itf() will be transmitted (if requested) if(!handled) { DPRINT("ALP command could not be processed by local FS"); if(d7asp_init_args != NULL && d7asp_init_args->d7asp_received_unhandled_alp_command_cb != NULL) { DPRINT("ALP command passed to application for processing"); d7asp_init_args->d7asp_received_unhandled_alp_command_cb(packet->payload, packet->payload_length, packet->payload, &packet->payload_length); } } } } // TODO notify upper layer? // execute slave transaction if(packet->payload_length == 0 && !packet->d7atp_ctrl.ctrl_is_ack_requested) goto discard_request; // no need to respond, clean up DPRINT("Sending response"); current_response_packet = packet; /* * activate the dialog extension procedure in the unicast response if the dialog is terminated * and a master session is pending */ if((packet->dll_header.control_target_address_set) && (packet->d7atp_ctrl.ctrl_is_stop) && (d7asp_state == D7ASP_STATE_SLAVE_PENDING_MASTER)) { packet->d7atp_ctrl.ctrl_is_start = true; // TODO set packet->d7anp_listen_timeout according the time remaining in the current transaction // + the maximum time to send the first request of the pending session. } else packet->d7atp_ctrl.ctrl_is_start = 0; d7atp_respond_dialog(packet); return true; } else assert(false); discard_request: packet_queue_free_packet(packet); return false; }
static void flush_fifos() { assert(d7asp_state == D7ASP_STATE_MASTER); DPRINT("Flushing FIFOs"); hw_watchdog_feed(); // TODO do here? if(current_request_id == NO_ACTIVE_REQUEST_ID) { // find first request which is not acked or dropped int8_t found_next_req_index = bitmap_search(current_master_session.progress_bitmap, false, MODULE_D7AP_FIFO_MAX_REQUESTS_COUNT); if(found_next_req_index == -1 || found_next_req_index == current_master_session.next_request_id) { // we handled all requests ... flush_completed(); // TODO move callback to ALP? // if(d7asp_init_args != NULL && d7asp_init_args->d7asp_fifo_flush_completed_cb != NULL) // d7asp_init_args->d7asp_fifo_flush_completed_cb(fifo.token, fifo.progress_bitmap, fifo.success_bitmap, REQUESTS_BITMAP_BYTE_COUNT); return; } current_request_id = found_next_req_index; current_request_retry_count = 0; current_request_packet = packet_queue_alloc_packet(); packet_queue_mark_processing(current_request_packet); current_request_packet->d7anp_addressee = &(current_master_session.config.addressee); // TODO explicitly pass addressee down the stack layers? memcpy(current_request_packet->payload, current_master_session.request_buffer + current_master_session.requests_indices[current_request_id], current_master_session.requests_lengths[current_request_id]); current_request_packet->payload_length = current_master_session.requests_lengths[current_request_id]; // TODO calculate Tl and Tc // Tc(NB, LEN, CH) = (SFC * NB + 1) * TTX(CH, LEN) + TG with NB the number of concurrent devices and SF the collision Avoidance Spreading Factor // Tl should correspond to the maximum time needed to send the remaining requests in the FIFO including the RETRY parameter // For now, set Tc and Tl according the transmission_timeout_period set in the access profile dae_access_profile_t active_addressee_access_profile; fs_read_access_class(current_request_packet->d7anp_addressee->ctrl.access_class, &active_addressee_access_profile); current_request_packet->d7atp_tc = active_addressee_access_profile.transmission_timeout_period; current_request_packet->d7anp_listen_timeout = active_addressee_access_profile.transmission_timeout_period; } else { // retrying request ... DPRINT("Current request retry count: %i", current_request_retry_count); if(current_request_retry_count == single_request_retry_limit) { // mark request as failed and pop mark_current_request_done(); DPRINT("Request reached single request retry limit (%i), skipping request", single_request_retry_limit); packet_queue_free_packet(current_request_packet); current_request_id = NO_ACTIVE_REQUEST_ID; sched_post_task(&flush_fifos); // continue flushing until all request handled ... return; } // TODO stop on error } // TODO calculate D7ANP timeout (and update during transaction lifetime) (based on Tc, channel, cs, payload size, # msgs, # retries) d7atp_start_dialog(current_master_session.token, current_request_id, (current_request_id == current_master_session.next_request_id - 1), current_request_packet, ¤t_master_session.config.qos); }