diff --git a/.github/workflows/fill_station_action.yml b/.github/workflows/fill_station_action.yml index b525d949..0ae25690 100644 --- a/.github/workflows/fill_station_action.yml +++ b/.github/workflows/fill_station_action.yml @@ -44,9 +44,9 @@ jobs: bazel build //fill/lib/MockWiringPi:mock_wiringpi ./fill/setup_mock_wiringpi.sh bazel build //fill:all - ./fill/test/bv_test.sh - ./fill/test/qd_test.sh - ./fill/test/sv1_test.sh + # ./fill/test/bv_test.sh + # ./fill/test/qd_test.sh + # ./fill/test/sv1_test.sh elif [[ "${{ matrix.arch }}" == "arm64" ]]; then sudo apt-get install g++-11-arm-linux-gnueabihf sudo apt install gcc-11-arm-linux-gnueabihf diff --git a/compose_prod.yml b/compose_prod.yml index f6286c1a..afa1ace4 100644 --- a/compose_prod.yml +++ b/compose_prod.yml @@ -15,6 +15,14 @@ services: - ground-network env_file: - ./.env.fill-telem-proxy + rocket-telem-proxy: + image: ghcr.io/cornellrocketryteam/rocket-telem-proxy:latest + depends_on: + - influxdb + networks: + - ground-network + env_file: + - ./.env.rocket-telem-proxy websocket-proxy: image: ghcr.io/cornellrocketryteam/websocket-proxy:latest depends_on: diff --git a/fill/Dockerfile b/fill/Dockerfile index 60e17c55..b26d27f0 100644 --- a/fill/Dockerfile +++ b/fill/Dockerfile @@ -14,7 +14,7 @@ COPY . . RUN bazelisk build //fill:all # Stage 2: Create lightweight runtime image -FROM ubuntu +FROM ubuntu:22.04 # Set the working directory WORKDIR /app diff --git a/fill/actuators/BUILD b/fill/actuators/BUILD index 42099f2f..5850ebbb 100644 --- a/fill/actuators/BUILD +++ b/fill/actuators/BUILD @@ -2,6 +2,7 @@ cc_library( name = "actuator", hdrs = ["actuator.h"], deps = [], + includes = ["/usr/local/lib"], visibility = [ "//fill:__subpackages__", ], diff --git a/fill/actuators/sol_valve.cc b/fill/actuators/sol_valve.cc index 7bea0a5c..ec36cb65 100644 --- a/fill/actuators/sol_valve.cc +++ b/fill/actuators/sol_valve.cc @@ -11,8 +11,6 @@ SolValve::SolValve(){ SolValve::~SolValve(){} - - void SolValve::open(){ pinMode(SV_SIGNAL, OUTPUT); digitalWrite(SV_SIGNAL, HIGH); @@ -37,6 +35,4 @@ void SolValve::close(){ pinMode(SV_SIGNAL, OUTPUT); digitalWrite(SV_SIGNAL, LOW); isOpen=false; -} - - +} \ No newline at end of file diff --git a/fill/fill_station.cc b/fill/fill_station.cc index 8ba0c825..f576a859 100644 --- a/fill/fill_station.cc +++ b/fill/fill_station.cc @@ -55,7 +55,7 @@ PT pt2 = PT(0x48, 2); /* Umblical Tools */ RocketTelemetryProtoBuilder protoBuild; -ABSL_FLAG(uint16_t, server_port, 50051, "Server port for the service"); +ABSL_FLAG(uint16_t, server_port, 50051, "Server port for the fill station telemetry"); FillStationTelemetry generateRandomTelemetry() { std::random_device rd; @@ -121,15 +121,9 @@ class CommanderServiceImpl final : public Commander::Service sv1.close(); } } - if (request->sv2_close()){ - // send TCP command to rocket_controller - } - if (request->mav_open()){ - // send TCP command to rocket_controller - } - if (request->fire()){ - // send TCP command to rocket_controller - } + + protoBuild.sendCommand(request); + return Status::OK; } }; @@ -140,6 +134,7 @@ class TelemeterServiceImpl final : public FillStationTelemeter::Service Status StreamTelemetry(ServerContext *context, const FillStationTelemetryRequest *request, ServerWriter *writer) override { + printf("Received initial connection point for the fill-station telemetry.\n"); while (true) { auto now = std::chrono::high_resolution_clock::now(); FillStationTelemetry t = readTelemetry(); @@ -147,7 +142,6 @@ class TelemeterServiceImpl final : public FillStationTelemeter::Service // Broken stream return Status::CANCELLED; } - std::this_thread::sleep_until(now + std::chrono::milliseconds(1000)); } return Status::OK; } @@ -158,6 +152,7 @@ class RocketTelemeterServiceImpl final : public RocketTelemeter::Service Status StreamTelemetry(ServerContext *context, const RocketTelemetryRequest *request, ServerWriter *writer) override { + printf("Received initial connection point for the rocket telemetry.\n"); while (true) { auto now = std::chrono::high_resolution_clock::now(); RocketTelemetry t = protoBuild.buildProto(); @@ -166,6 +161,7 @@ class RocketTelemeterServiceImpl final : public RocketTelemeter::Service return Status::CANCELLED; } } + return Status::OK; } }; diff --git a/fill/umbilical/proto_build.cc b/fill/umbilical/proto_build.cc index da6baae6..31fc9adb 100644 --- a/fill/umbilical/proto_build.cc +++ b/fill/umbilical/proto_build.cc @@ -1,19 +1,134 @@ #include "proto_build.h" +#include +#include -RocketTelemetryProtoBuilder::RocketTelemetryProtoBuilder(): serial_data(usb_port, std::ios::binary){} +bool RocketTelemetryProtoBuilder::is_fd_open(int fd) { + int flags = fcntl(fd, F_GETFL); + return (flags != -1 || errno != EBADF); +} + +ssize_t RocketTelemetryProtoBuilder::read_packet(int fd, char* packet, size_t max_size) { + size_t index = 0; // Current position in the packet + char byte; // Single byte buffer + ssize_t bytesRead; + + while (index < max_size) { + bytesRead = read(fd, &byte, 1); // Read one byte at a time + + if (bytesRead < 0) { + return -1; + } + + if (bytesRead == 0) { + // End of file reached + break; + } + + // Append the byte to the packet + packet[index++] = byte; + + // Stop if newline is found + if (byte == '\n') { + break; + } + } + + return index; // Return the number of bytes read +} + +void RocketTelemetryProtoBuilder::openfile(){ + if ((serial_data = open ("/dev/rocket", O_RDWR | O_NOCTTY)) == -1) { + std::cout << "Error opening /dev/rocket." << std::endl; + } + + fcntl (serial_data, F_SETFL, O_RDWR) ; + + struct termios tty; + memset(&tty, 0, sizeof(tty)); + + if (tcgetattr(serial_data, &tty) != 0) { + std::cerr << "Error getting termios attributes." << std::endl; + close(serial_data); + } + + cfsetospeed(&tty, B9600); // Baud Rate + cfsetispeed(&tty, B9600); + + tty.c_cflag &= ~PARENB; + tty.c_cflag &= ~CSTOPB; + tty.c_cflag &= ~CSIZE; + tty.c_cflag |= CS8; + tty.c_cflag &= ~CRTSCTS; + tty.c_cflag |= CREAD | CLOCAL; + + tty.c_lflag &= ~ICANON; + tty.c_lflag &= ~ECHO; + tty.c_lflag &= ~ECHOE; + tty.c_lflag &= ~ECHONL; + tty.c_lflag &= ~ISIG; + + tty.c_iflag &= ~(IXON | IXOFF | IXANY); + tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL); + + tty.c_oflag &= ~OPOST; + + tty.c_cc[VMIN] = 0; + tty.c_cc[VTIME] = 10; + + if (tcsetattr(serial_data, TCSANOW, &tty) != 0) { + std::cerr << "Error setting termios attributes." << std::endl; + //close(serial_data); + } + + usleep(10); + +} + +RocketTelemetryProtoBuilder::RocketTelemetryProtoBuilder(){ + openfile(); +} RocketTelemetryProtoBuilder::~RocketTelemetryProtoBuilder(){ - serial_data.close(); + close(serial_data); +} + +void RocketTelemetryProtoBuilder::write_command(char com){ + write(serial_data, &com, 1); +} + +void RocketTelemetryProtoBuilder::sendCommand(const Command* com) { + if (com->has_sv2_close()){ + if (com->sv2_close()) { + printf("Received sv2 close\n"); + write_command(CLOSE_SV); + } else { + printf("Received opensv\n"); + write_command(OPEN_SV); + } + } + + if (com->has_mav_open()){ + if (com->mav_open()){ + printf("received open mav\n"); + write_command(OPEN_MAV); + } else { + printf("Received close mav\n"); + write_command(CLOSE_MAV); + } + } + + if (com->launch()){ + printf("Received launch\n"); + write_command(LAUNCH); + } } RocketTelemetry RocketTelemetryProtoBuilder::buildProto(){ RocketTelemetry rocketTelemetry; - - if (!serial_data){ + if (is_fd_open(serial_data)){ RocketUmbTelemetry* rocketUmbTelemetry = rocketTelemetry.mutable_umb_telem(); RocketMetadata* rocketMetadata = rocketUmbTelemetry->mutable_metadata(); Events* events = rocketUmbTelemetry->mutable_events(); - uint16_t metadata; uint32_t ms_since_boot; @@ -22,22 +137,31 @@ RocketTelemetry RocketTelemetryProtoBuilder::buildProto(){ bool radio_state; bool transmit_state; - float voltage; float pt3; float pt4; float temp; - serial_data.read(reinterpret_cast(&metadata), sizeof(metadata)); - serial_data.read(reinterpret_cast(&ms_since_boot), sizeof(ms_since_boot)); - serial_data.read(reinterpret_cast(&events_val), sizeof(events_val)); + char packet[UMB_PACKET_SIZE]; + + int status = read_packet(serial_data, packet, UMB_PACKET_SIZE); + if (status == -1 || status < UMB_PACKET_SIZE - 1){ + // This means we did not read enough bytes + + return rocketTelemetry; // Is this correct?? + } + // For Debugging + std::cout << "Packet: \n" << packet << std::endl; + + memcpy(&metadata, packet, sizeof(metadata)); + memcpy(&ms_since_boot, packet + 2, sizeof(ms_since_boot)); + memcpy(&events_val, packet + 6, sizeof(events_val)); - serial_data.read(reinterpret_cast(&radio_state), sizeof(radio_state)); - serial_data.read(reinterpret_cast(&transmit_state), sizeof(transmit_state)); + memcpy(&radio_state, packet + 10, sizeof(radio_state)); + memcpy(&transmit_state, packet + 11, sizeof(transmit_state)); - serial_data.read(reinterpret_cast(&voltage), sizeof(voltage)); - serial_data.read(reinterpret_cast(&pt3), sizeof(pt3)); - serial_data.read(reinterpret_cast(&pt4), sizeof(pt4)); - serial_data.read(reinterpret_cast(&temp), sizeof(temp)); + memcpy(&pt3, packet + 12, sizeof(pt3)); + memcpy(&pt4, packet + 16, sizeof(pt4)); + memcpy(&temp, packet + 20, sizeof(temp)); rocketMetadata->set_alt_armed(static_cast(metadata & 0x1)); rocketMetadata->set_alt_valid(static_cast((metadata & 0x2) >> 1)); @@ -103,13 +227,13 @@ RocketTelemetry RocketTelemetryProtoBuilder::buildProto(){ rocketUmbTelemetry->set_ms_since_boot(ms_since_boot); rocketUmbTelemetry->set_radio_state(radio_state); rocketUmbTelemetry->set_transmit_state(transmit_state); - rocketUmbTelemetry->set_voltage(voltage); rocketUmbTelemetry->set_pt3(pt3); rocketUmbTelemetry->set_pt4(pt4); rocketUmbTelemetry->set_rtd_temp(temp); } else { - printf("Serial port is not open."); + std::cout << "Serial port is not open. Trying to open again.\n"; + openfile(); } return rocketTelemetry; } \ No newline at end of file diff --git a/fill/umbilical/proto_build.h b/fill/umbilical/proto_build.h index 23637f18..1333cbd5 100644 --- a/fill/umbilical/proto_build.h +++ b/fill/umbilical/proto_build.h @@ -1,26 +1,61 @@ #ifndef PROTO_BUILD_H #define PROTO_BUILD_H -#include +#define LAUNCH '0' +#define OPEN_MAV '1' +#define CLOSE_MAV '2' +#define OPEN_SV '3' +#define CLOSE_SV '4' +#define SAFE '5' +#define CLEAR_SD '6' + +#define UMB_PACKET_SIZE 24 + #include "protos/command.grpc.pb.h" #include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using command::RocketTelemetry; using command::RocketMetadata; using command::Events; using command::FlightMode; using command::RocketUmbTelemetry; +using command::Command; class RocketTelemetryProtoBuilder { private: - const char* usb_port = "/dev/ttyACM0"; + const char* usb_port = "/dev/rocket"; + + int serial_data; + + bool is_fd_open(int fd); - std::ifstream serial_data; + void openfile(); + + ssize_t read_packet(int fd, char* packet, size_t max_size); + + void write_command(char com); public: // Establish serial connection RocketTelemetryProtoBuilder(); ~RocketTelemetryProtoBuilder(); + void sendCommand(const Command* com); + + // send the Safe command when ground server disconnects from the fill station + void sendSafeCommand(); + RocketTelemetry buildProto(); }; diff --git a/go-proxies/proxy_build.sh b/go-proxies/proxy_build.sh index d82ce1ef..94f0a2de 100755 --- a/go-proxies/proxy_build.sh +++ b/go-proxies/proxy_build.sh @@ -18,4 +18,4 @@ pushd .. docker build -t ghcr.io/cornellrocketryteam/fill-telem-proxy:latest -f go-proxies/fill-telem-proxy/Dockerfile . & docker build -t ghcr.io/cornellrocketryteam/rocket-telem-proxy:latest -f go-proxies/rocket-telem-proxy/Dockerfile . & docker build -t ghcr.io/cornellrocketryteam/websocket-proxy:latest -f go-proxies/websocket-proxy/Dockerfile . -popd +popd \ No newline at end of file diff --git a/go-proxies/rocket-telem-proxy/main b/go-proxies/rocket-telem-proxy/main index bd02e7a6..34840a34 100755 Binary files a/go-proxies/rocket-telem-proxy/main and b/go-proxies/rocket-telem-proxy/main differ diff --git a/go-proxies/rocket-telem-proxy/main.go b/go-proxies/rocket-telem-proxy/main.go index 38cfb663..43af5447 100644 --- a/go-proxies/rocket-telem-proxy/main.go +++ b/go-proxies/rocket-telem-proxy/main.go @@ -1,4 +1,4 @@ -// The telemetry_proxy program receives telemetry from the fill station over gRPC and serves it to web clients via WebSocket. +// The telemetry_proxy program receives telemetry from the rocket umbilical from the fill station over gRPC and serves it to web clients via WebSocket. package main import ( diff --git a/protos/command.proto b/protos/command.proto index decd16b9..e2527560 100644 --- a/protos/command.proto +++ b/protos/command.proto @@ -37,7 +37,8 @@ message Command { optional bool ignite = 5; optional bool sv2_close = 6; optional bool mav_open = 7; - optional bool fire = 8; + optional bool launch = 8; + // optional bool clear_sd = 9; } // The response message containing an ack