From 6f8044f74cffa981babb4bdf73107160829529ff Mon Sep 17 00:00:00 2001 From: Tyler Lentz Date: Mon, 15 Apr 2024 23:21:14 +0000 Subject: [PATCH 1/7] update airdrop protocol --- include/airdrop/packet.h | 21 ++++++++++++++------- include/network/airdrop_client.hpp | 1 + include/network/airdrop_sockets.h | 1 + protos | 2 +- src/network/airdrop_client.cpp | 14 ++++++++++++++ src/network/airdrop_sockets.c | 20 ++++++++++++++++++++ src/network/mock/airdrop_sockets.c | 5 +++++ 7 files changed, 56 insertions(+), 8 deletions(-) diff --git a/include/airdrop/packet.h b/include/airdrop/packet.h index 243fb38e..c8643a7f 100644 --- a/include/airdrop/packet.h +++ b/include/airdrop/packet.h @@ -4,7 +4,7 @@ #include /********************************************************************************************** - * LAST UPDATED: 2024/02/29 + * LAST UPDATED: 2024/04/15 by Tyler Lentz * * This file defines the packet definitions for Airdrop communications. It is used in two * separate repositories: @@ -27,18 +27,23 @@ #define AD_OBC_PORT 45906 // OBC listens on this port, so payloads send to this #define AD_PAYLOAD_PORT 45907 // Payloads listen on this port, so OBC sends to this -// All of the values in here are 1 byte long, which means we do not have to worry about -// the endianness of the information as it is sent over the wire. If we ever add values more -// than one byte long, we'll have to worry about this. - -// gcc specific packing syntax. Technically this should already be packed because it is just -// two one-byte values, but just making sure. +// Normal packet, which applies for every kind of packet that is not an ad_latlng_packet struct __attribute__((packed)) ad_packet { uint8_t hdr; uint8_t data; }; typedef struct ad_packet ad_packet_t; +// Separate kind of packet sent by OBC to Payloads to specify drop location +// for indirect drop +struct __attribute__((packed)) ad_latlng_packet { + uint8_t hdr; + uint8_t bottle; + double lat; + double lng; +}; +typedef struct ad_latlng_packet ad_latlng_packet_t; + enum ad_packet_hdr { // Continually sent by the payloads to confirm they are still operational // and can talk to the OBC @@ -56,6 +61,8 @@ enum ad_packet_hdr { ACK_SIGNAL = 201, REVOKE = 202, ACK_REVOKE = 203, + SEND_LATLNG = 204, // special packet format! + ACK_LATLNG = 205, // Direct & Indirect ABOUT_TO_RELEASE = 255, diff --git a/include/network/airdrop_client.hpp b/include/network/airdrop_client.hpp index 037d8c81..305907e0 100644 --- a/include/network/airdrop_client.hpp +++ b/include/network/airdrop_client.hpp @@ -24,6 +24,7 @@ class AirdropClient { ~AirdropClient(); bool send(ad_packet_t packet); + bool send(ad_latlng_packet_t packet); // Receives oldest packet since last receive() call, ignoring any // HEARTBEAT packets as those are parsed by the client itself // and exposed through the TODO function. diff --git a/include/network/airdrop_sockets.h b/include/network/airdrop_sockets.h index 0ebb8a3e..aa5223bc 100644 --- a/include/network/airdrop_sockets.h +++ b/include/network/airdrop_sockets.h @@ -67,6 +67,7 @@ ad_int_result_t set_socket_nonblocking(int sock_fd); // Either returns an error string or the number of bytes sent. // IMPORTANT: must have previously called set_send_thread from curr thread. ad_int_result_t send_ad_packet(ad_socket_t socket, ad_packet_t packet); +ad_int_result_t send_ad_latlng_packet(ad_socket_t socket, ad_latlng_packet_t packet); // Receive packet and place into buf, which is of length buf_len. // Either returns an error string or the number of bytes read. diff --git a/protos b/protos index b7d3e9b7..abe95730 160000 --- a/protos +++ b/protos @@ -1 +1 @@ -Subproject commit b7d3e9b74b38046602d4631072e6777b0b59b273 +Subproject commit abe95730634b146f39fb5127ee96bac511e9cbd5 diff --git a/src/network/airdrop_client.cpp b/src/network/airdrop_client.cpp index 7e444739..fcb4d385 100644 --- a/src/network/airdrop_client.cpp +++ b/src/network/airdrop_client.cpp @@ -72,6 +72,20 @@ bool AirdropClient::send(ad_packet_t packet) { return true; } +bool AirdropClient::send(ad_latlng_packet_t packet) { + set_send_thread(); + + auto res = send_ad_latlng_packet(this->socket, packet); + if (res.is_err) { + LOG_F(ERROR, "%s", res.data.err); + return false; + } + + // TODO: helper to go from packet -> str + LOG_F(INFO, "Sent airdrop latlng packet: %hhu %hhu", packet.hdr, packet.bottle); + return true; +} + std::optional AirdropClient::receive() { Lock lock(this->recv_mut); diff --git a/src/network/airdrop_sockets.c b/src/network/airdrop_sockets.c index 12a3014e..9e38829c 100644 --- a/src/network/airdrop_sockets.c +++ b/src/network/airdrop_sockets.c @@ -118,6 +118,26 @@ ad_int_result_t send_ad_packet(ad_socket_t socket, ad_packet_t packet) { AD_RETURN_SUCC_RESULT(int, bytes_sent); } +ad_int_result_t send_ad_latlng_packet(ad_socket_t socket, ad_latlng_packet_t packet) { + struct sockaddr_in SEND_ADDR = { + .sin_family = AF_INET, + .sin_port = htons(socket.send_port), + .sin_addr = INADDR_BROADCAST, + .sin_zero = {0}, + }; + + static char err[AD_ERR_LEN]; + int bytes_sent = sendto(socket.fd, (void*) &packet, sizeof(ad_latlng_packet_t), 0, + (struct sockaddr*) &SEND_ADDR, sizeof(SEND_ADDR)); + + if (bytes_sent < 0) { + snprintf(&err[0], AD_ERR_LEN, "send failed: %s", strerror_l(errno, _send_locale)); + AD_RETURN_ERR_RESULT(int, err); + } + + AD_RETURN_SUCC_RESULT(int, bytes_sent); +} + ad_int_result_t recv_ad_packet(ad_socket_t socket, void* buf, size_t buf_len) { static char err[AD_ERR_LEN]; struct sockaddr_in RECV_ADDR = { diff --git a/src/network/mock/airdrop_sockets.c b/src/network/mock/airdrop_sockets.c index e59a5c18..e29035dc 100644 --- a/src/network/mock/airdrop_sockets.c +++ b/src/network/mock/airdrop_sockets.c @@ -70,6 +70,11 @@ ad_int_result_t send_ad_packet(ad_socket_t socket, ad_packet_t packet) { AD_RETURN_SUCC_RESULT(int, sizeof(ad_packet_t)); } +ad_int_result_t send_ad_latlng_packet(ad_socket_t socket, ad_latlng_packet_t packet) { + // TODO: Mock sending ad_latlng_packets + fprintf(stderr, "ERR: haven't yet implemented sending ad latlng packets in mock"); +} + ad_int_result_t recv_ad_packet(ad_socket_t socket, void* buf, size_t buf_len) { static char err[1] = ""; From 07d091098d61537713249f06a97d3bd6d43a2b4f Mon Sep 17 00:00:00 2001 From: Tyler Lentz Date: Mon, 15 Apr 2024 23:22:39 +0000 Subject: [PATCH 2/7] fix lint --- include/airdrop/packet.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/airdrop/packet.h b/include/airdrop/packet.h index c8643a7f..ae7ac18f 100644 --- a/include/airdrop/packet.h +++ b/include/airdrop/packet.h @@ -61,7 +61,7 @@ enum ad_packet_hdr { ACK_SIGNAL = 201, REVOKE = 202, ACK_REVOKE = 203, - SEND_LATLNG = 204, // special packet format! + SEND_LATLNG = 204, // special packet format! ACK_LATLNG = 205, // Direct & Indirect From 14a9932933d41a9201120bdebd4f414c374506fa Mon Sep 17 00:00:00 2001 From: Tyler Lentz Date: Tue, 16 Apr 2024 01:02:32 +0000 Subject: [PATCH 3/7] connection fix from 4/15/24 testing w/ Cody --- .devcontainer/devcontainer.json | 7 ++++++- include/airdrop/packet.h | 3 ++- src/network/airdrop_client.cpp | 10 ++++++++++ src/ticks/mission_prep.cpp | 6 ++++++ 4 files changed, 24 insertions(+), 2 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 2f83d5b7..6a0cf67d 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,12 +1,17 @@ // See this page for reference of options: https://containers.dev/implementors/json_reference { "name": "Existing Dockerfile", - "image": "ghcr.io/tritonuas/obcpp:x86", + "image": "ghcr.io/tritonuas/obcpp:main", // enable when need to connect over USB to pixhawk // also: need to run obcpp with sudo or add tuas user to dialout group with // `sudo usermod -aG dialout tuas && newgrp && bash` // "runArgs": ["--device=/dev/ttyACM0"], + "appPort": [ "45906:45906/udp", "45907:45907/udp" ], // port forward airdrop ports for local testing + "runArgs": [ + "--network=host" + ], + "customizations": { "vscode": { "settings": { diff --git a/include/airdrop/packet.h b/include/airdrop/packet.h index ae7ac18f..0a795b36 100644 --- a/include/airdrop/packet.h +++ b/include/airdrop/packet.h @@ -52,6 +52,7 @@ enum ad_packet_hdr { // Handshake to establish connection SET_MODE = 1, ACK_MODE = 2, + RESET_MODE = 3, // TODO: // Direct Drop DROP_NOW = 100, @@ -91,7 +92,6 @@ inline int validate_packet_as(enum ad_packet_hdr hdr, ad_packet_t packet) { } switch (packet.hdr) { - case HEARTBEAT: case ACK_MODE: return 1; case SET_MODE: @@ -102,6 +102,7 @@ inline int validate_packet_as(enum ad_packet_hdr hdr, ad_packet_t packet) { case REVOKE: case ACK_REVOKE: case ABOUT_TO_RELEASE: + case HEARTBEAT: return (packet.data >= BOTTLE_A && packet.data <= BOTTLE_E); default: return 0; diff --git a/src/network/airdrop_client.cpp b/src/network/airdrop_client.cpp index fcb4d385..23127e21 100644 --- a/src/network/airdrop_client.cpp +++ b/src/network/airdrop_client.cpp @@ -55,6 +55,8 @@ void AirdropClient::_establishConnection() { LOG_F(INFO, "Payload connection established in %s mode", (this->mode == DIRECT_DROP) ? "Direct" : "Indirect"); + send_ad_packet(this->socket, make_ad_packet(ad_packet_hdr::ACK_MODE, *this->mode)); + this->worker_future = std::async(std::launch::async, &AirdropClient::_receiveWorker, this); } @@ -173,6 +175,12 @@ void AirdropClient::_receiveWorker() { continue; // heartbeat, so we should not put it in the queue } + if (packet.hdr == SET_MODE) { + send_ad_packet(this->socket, make_ad_packet(ad_packet_hdr::ACK_MODE, *this->mode)); + LOG_F(INFO, "Received extra SET_MODE, reacking"); + continue; + } + Lock lock(this->recv_mut); this->recv_queue.emplace(packet); } @@ -188,5 +196,7 @@ bool AirdropClient::_parseHeartbeats(ad_packet_t packet) { // subtract 1 to get the index into the lastHeartbeat array. this->last_heartbeat[packet.data - 1] = getUnixTime_ms(); + LOG_F(INFO, "Packet heartbeat from %d", packet.data); + return true; } diff --git a/src/ticks/mission_prep.cpp b/src/ticks/mission_prep.cpp index 08e2ed73..ebaf7629 100644 --- a/src/ticks/mission_prep.cpp +++ b/src/ticks/mission_prep.cpp @@ -15,7 +15,13 @@ std::chrono::milliseconds MissionPrepTick::getWait() const { return MISSION_PREP_TICK_WAIT; } +using namespace std::chrono_literals; + Tick* MissionPrepTick::tick() { + if (this->state->getAirdrop() != nullptr) { + LOG_F(INFO, "%ld", this->state->getAirdrop()->getLostConnections(1s).size()); + } + if (this->state->config.getCachedMission().has_value()) { LOG_F(INFO, "Valid mission configuration detected"); return new PathGenTick(this->state); From c831a6a5b8edb4ea6f0f9edcd0b7245b631eb24d Mon Sep 17 00:00:00 2001 From: Tyler Lentz Date: Wed, 17 Apr 2024 20:00:03 +0000 Subject: [PATCH 4/7] remove testing stuff --- .devcontainer/devcontainer.json | 11 ++++++----- src/ticks/mission_prep.cpp | 4 ---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 6a0cf67d..2cd7abd9 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,16 +1,17 @@ // See this page for reference of options: https://containers.dev/implementors/json_reference { "name": "Existing Dockerfile", - "image": "ghcr.io/tritonuas/obcpp:main", + "image": "ghcr.io/tritonuas/obcpp:x86", // enable when need to connect over USB to pixhawk // also: need to run obcpp with sudo or add tuas user to dialout group with // `sudo usermod -aG dialout tuas && newgrp && bash` // "runArgs": ["--device=/dev/ttyACM0"], - "appPort": [ "45906:45906/udp", "45907:45907/udp" ], // port forward airdrop ports for local testing - "runArgs": [ - "--network=host" - ], + // Enable network mode host if on Linux and testing airdrop connectivity + // "appPort": [ "45906:45906/udp", "45907:45907/udp" ], // port forward airdrop ports for local testing + // "runArgs": [ + // "--network=host" + // ], "customizations": { "vscode": { diff --git a/src/ticks/mission_prep.cpp b/src/ticks/mission_prep.cpp index ebaf7629..b85f5d84 100644 --- a/src/ticks/mission_prep.cpp +++ b/src/ticks/mission_prep.cpp @@ -18,10 +18,6 @@ std::chrono::milliseconds MissionPrepTick::getWait() const { using namespace std::chrono_literals; Tick* MissionPrepTick::tick() { - if (this->state->getAirdrop() != nullptr) { - LOG_F(INFO, "%ld", this->state->getAirdrop()->getLostConnections(1s).size()); - } - if (this->state->config.getCachedMission().has_value()) { LOG_F(INFO, "Valid mission configuration detected"); return new PathGenTick(this->state); From 3126a5a5921d77c35452a214ab835f7d9d5db5c7 Mon Sep 17 00:00:00 2001 From: Tyler Lentz Date: Wed, 17 Apr 2024 20:02:40 +0000 Subject: [PATCH 5/7] fix lint --- include/airdrop/packet.h | 2 +- src/ticks/mission_prep.cpp | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/airdrop/packet.h b/include/airdrop/packet.h index 0a795b36..71f3ad10 100644 --- a/include/airdrop/packet.h +++ b/include/airdrop/packet.h @@ -52,7 +52,7 @@ enum ad_packet_hdr { // Handshake to establish connection SET_MODE = 1, ACK_MODE = 2, - RESET_MODE = 3, // TODO: + RESET_MODE = 3, // TODO: // Direct Drop DROP_NOW = 100, diff --git a/src/ticks/mission_prep.cpp b/src/ticks/mission_prep.cpp index b85f5d84..08e2ed73 100644 --- a/src/ticks/mission_prep.cpp +++ b/src/ticks/mission_prep.cpp @@ -15,8 +15,6 @@ std::chrono::milliseconds MissionPrepTick::getWait() const { return MISSION_PREP_TICK_WAIT; } -using namespace std::chrono_literals; - Tick* MissionPrepTick::tick() { if (this->state->config.getCachedMission().has_value()) { LOG_F(INFO, "Valid mission configuration detected"); From cee70eac9d727a3c54dda83bf29d6db25faa73ed Mon Sep 17 00:00:00 2001 From: Tyler Lentz Date: Wed, 17 Apr 2024 20:58:37 +0000 Subject: [PATCH 6/7] fix unit test --- tests/unit/airdrop_client/airdrop_client_test.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/unit/airdrop_client/airdrop_client_test.cpp b/tests/unit/airdrop_client/airdrop_client_test.cpp index a28a22a1..7e276790 100644 --- a/tests/unit/airdrop_client/airdrop_client_test.cpp +++ b/tests/unit/airdrop_client/airdrop_client_test.cpp @@ -85,10 +85,12 @@ TEST(AirdropClientTest, ObcSendToPayload) { }); ad_packet_t p = { 0 }; - while (num_received < NUM_TO_SEND) { + while (num_received < NUM_TO_SEND + 1) { recv_ad_packet(payload_socket, &p, sizeof(ad_packet_t)); - ASSERT_EQ(p.hdr, SIGNAL); - ASSERT_EQ(p.data, num_received); + if (num_received != 0) { // ignore first because will be ack_mode + ASSERT_EQ(p.hdr, SIGNAL); + ASSERT_EQ(p.data, num_received - 1); + } num_received++; } } From 9f66babed55807b43ab3576a9cfcd834f3a79f5d Mon Sep 17 00:00:00 2001 From: Tyler Lentz Date: Thu, 18 Apr 2024 22:50:12 +0000 Subject: [PATCH 7/7] update protos --- protos | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protos b/protos index abe95730..c5841043 160000 --- a/protos +++ b/protos @@ -1 +1 @@ -Subproject commit abe95730634b146f39fb5127ee96bac511e9cbd5 +Subproject commit c5841043ba805c065997232b5a6ae281873d9969