void handleAllocation(const ReceivedDataStructure<Allocation>& msg) { trace(TraceAllocationActivity, msg.getSrcNodeID().get()); if (!msg.isAnonymousTransfer()) { return; // This is a response from another allocator, ignore } /* * Reset the expected stage on timeout */ if (msg.getMonotonicTimestamp() > (last_message_timestamp_ + stage_timeout_)) { UAVCAN_TRACE("AllocationRequestManager", "Stage timeout, reset"); current_unique_id_.clear(); trace(TraceAllocationFollowupTimeout, (msg.getMonotonicTimestamp() - last_message_timestamp_).toUSec()); } /* * Checking if request stage matches the expected stage */ const uint8_t request_stage = detectRequestStage(msg); if (request_stage == InvalidStage) { trace(TraceAllocationBadRequest, msg.unique_id.size()); return; // Malformed request - ignore without resetting } const uint8_t expected_stage = getExpectedStage(); if (expected_stage == InvalidStage) { UAVCAN_ASSERT(0); return; } if (request_stage != expected_stage) { trace(TraceAllocationUnexpectedStage, request_stage); return; // Ignore - stage mismatch } const uint8_t max_expected_bytes = static_cast<uint8_t>(current_unique_id_.capacity() - current_unique_id_.size()); UAVCAN_ASSERT(max_expected_bytes > 0); if (msg.unique_id.size() > max_expected_bytes) { trace(TraceAllocationBadRequest, msg.unique_id.size()); return; // Malformed request } /* * Updating the local state */ for (uint8_t i = 0; i < msg.unique_id.size(); i++) { current_unique_id_.push_back(msg.unique_id[i]); } trace(TraceAllocationRequestAccepted, current_unique_id_.size()); /* * Proceeding with allocation if possible * Note that single-frame CAN FD allocation requests will be delivered to the server even if it's not leader. */ if (current_unique_id_.size() == current_unique_id_.capacity()) { UAVCAN_TRACE("AllocationRequestManager", "Allocation request received; preferred node ID: %d", int(msg.node_id)); UniqueID unique_id; copy(current_unique_id_.begin(), current_unique_id_.end(), unique_id.begin()); current_unique_id_.clear(); { uint64_t event_agrument = 0; for (uint8_t i = 0; i < 8; i++) { event_agrument |= static_cast<uint64_t>(unique_id[i]) << (56U - i * 8U); } trace(TraceAllocationExchangeComplete, static_cast<int64_t>(event_agrument)); } handler_.handleAllocationRequest(unique_id, msg.node_id); } else { if (handler_.canPublishFollowupAllocationResponse()) { publishFollowupAllocationResponse(); } else { trace(TraceAllocationFollowupDenied, 0); current_unique_id_.clear(); } } /* * It is super important to update timestamp only if the request has been processed successfully. */ last_message_timestamp_ = msg.getMonotonicTimestamp(); }
void DynamicNodeIDClient::handleAllocation(const ReceivedDataStructure<protocol::dynamic_node_id::Allocation>& msg) { /* * TODO This method can blow the stack easily */ UAVCAN_ASSERT(preferred_node_id_.isValid()); if (isAllocationComplete()) { UAVCAN_ASSERT(0); terminate(); return; } startPeriodic(getPeriod()); // Restarting the timer - Rule C UAVCAN_TRACE("DynamicNodeIDClient", "Request timer reset because of Allocation message from %d", static_cast<int>(msg.getSrcNodeID().get())); // Rule D if (!msg.isAnonymousTransfer() && msg.unique_id.size() > 0 && msg.unique_id.size() < msg.unique_id.capacity() && equal(msg.unique_id.begin(), msg.unique_id.end(), unique_id_)) { // Filling the response message const uint8_t size_of_unique_id_in_response = min(protocol::dynamic_node_id::Allocation::MAX_LENGTH_OF_UNIQUE_ID_IN_REQUEST, static_cast<uint8_t>(msg.unique_id.capacity() - msg.unique_id.size())); protocol::dynamic_node_id::Allocation second_stage; second_stage.node_id = preferred_node_id_.get(); second_stage.first_part_of_unique_id = false; second_stage.unique_id.resize(size_of_unique_id_in_response); copy(unique_id_ + msg.unique_id.size(), unique_id_ + msg.unique_id.size() + size_of_unique_id_in_response, second_stage.unique_id.begin()); UAVCAN_ASSERT(equal(second_stage.unique_id.begin(), second_stage.unique_id.end(), unique_id_ + msg.unique_id.size())); // Broadcasting the response UAVCAN_TRACE("DynamicNodeIDClient", "Broadcasting 2nd stage: preferred ID: %d, size of unique ID: %d", static_cast<int>(preferred_node_id_.get()), static_cast<int>(second_stage.unique_id.size())); const int res = dnida_pub_.broadcast(second_stage); if (res < 0) { dnida_pub_.getNode().registerInternalFailure("DynamicNodeIDClient request failed"); } } // Rule E if (!msg.isAnonymousTransfer() && msg.unique_id.size() == msg.unique_id.capacity() && equal(msg.unique_id.begin(), msg.unique_id.end(), unique_id_) && msg.node_id > 0) { allocated_node_id_ = msg.node_id; allocator_node_id_ = msg.getSrcNodeID(); UAVCAN_TRACE("DynamicNodeIDClient", "Allocation complete, node ID %d provided by %d", static_cast<int>(allocated_node_id_.get()), static_cast<int>(allocator_node_id_.get())); terminate(); UAVCAN_ASSERT(isAllocationComplete()); } }