LCOV - code coverage report
Current view: top level - tdemodules/src - AMCProtocolClient.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 66 0
Test Date: 2025-12-21 13:07:08 Functions: 0.0 % 5 0

            Line data    Source code
       1              : #include "tdemodules/AMCProtocolClient.hpp"
       2              : 
       3              : #include <boost/lexical_cast.hpp>
       4              : #include <fmt/ranges.h>
       5              : #include "utilities.hpp"
       6              : 
       7              : #include "logging/Logging.hpp"
       8              : 
       9              : namespace dunedaq {
      10              : namespace tdemodules {
      11              : 
      12              : 
      13            0 : AMCProtocolClient::AMCProtocolClient(const std::string& server_ip, uint16_t port) :
      14            0 :     m_host(server_ip),
      15            0 :     m_port(port),
      16            0 :     m_timeout(50),
      17            0 :     m_io_context(),
      18            0 :     m_socket(m_io_context)
      19              : {
      20              : 
      21            0 :     using boost::asio::ip::udp;
      22            0 :     udp::resolver resolver(m_io_context);
      23            0 :     m_server_endpoint= *resolver.resolve(udp::v4(), m_host, std::to_string(m_port)).begin();
      24              : 
      25            0 :     m_socket.open(udp::v4());
      26            0 :     m_socket.non_blocking(true);
      27              : 
      28            0 : }
      29              : 
      30              : std::vector<uint8_t>
      31            0 : AMCProtocolClient::send_request(TFTPOpCode opcode, const std::vector<uint8_t>& payload) {
      32              : 
      33              :     // Build TFTP RRQ or WRQ packet
      34              :     // Switch to uin8_t
      35            0 :     std::vector<uint8_t> request;
      36              :     // request.push_back(static_cast<char>(opcode >> 8));
      37              :     // request.push_back(static_cast<char>(opcode & 0xFF));
      38              :     // append_bigendian(request, opcode);
      39            0 :     append_big_uint16(request, opcode);
      40            0 :     request.insert( request.end(), payload.begin(), payload.end());
      41              : 
      42            0 :     std::stringstream request_str;
      43            0 :     for (size_t i = 0; i < request.size(); ++i) {
      44            0 :         request_str << std::setfill('0') << std::setw(2) << std::hex << +request[i] << " ";
      45              :     }
      46            0 :     TLOG() << "sending request to AMC: " << request_str.str();
      47              : 
      48            0 :     m_socket.send_to(boost::asio::buffer(request), m_server_endpoint);
      49              : 
      50            0 :     std::vector<uint8_t> reply(516); // TFTP packets max ~516 bytes
      51              : 
      52            0 :     boost::asio::ip::udp::endpoint sender_endpoint;
      53            0 :     boost::system::error_code ec;
      54              : 
      55            0 :     size_t len = 0;
      56            0 :     for (int i = 0; i < m_timeout; ++i) { // wait up to ~5 seconds total
      57            0 :         std::this_thread::sleep_for(std::chrono::milliseconds(100));
      58            0 :         len = m_socket.receive_from(boost::asio::buffer(reply), sender_endpoint, 0, ec);
      59            0 :         if (!ec) break;
      60              :     }
      61              : 
      62            0 :     if (ec) {
      63            0 :         throw AMCProtocolIssue(ERS_HERE, m_log_prefix, "TFTP receive error: " + ec.message());
      64              :     }
      65              : 
      66            0 :     if (len < 4) {
      67            0 :         throw AMCProtocolIssue(ERS_HERE, m_log_prefix, "Invalid TFTP reply: too short");
      68              :     }
      69            0 :     if (reply.size() < 4)
      70            0 :         throw std::runtime_error("Packet too short to be valid");
      71              : 
      72              :     // Parse returin code
      73            0 :     boost::endian::big_uint16_t rpl_opcode_be;
      74            0 :     std::memcpy(&rpl_opcode_be, reply.data(), sizeof(rpl_opcode_be));
      75              : 
      76              :     // A bit of overcasting here?
      77            0 :     TFTPOpCode rpl_opcode = static_cast<TFTPOpCode>(static_cast<uint16_t>(rpl_opcode_be));
      78              : 
      79            0 :     switch (rpl_opcode) {
      80            0 :         case TFTPOpCode::DAT: {
      81            0 :             if (reply.size() < sizeof(TFTP_Data_Header))
      82              :                 throw AMCProtocolIssue(ERS_HERE, m_log_prefix, "Incomplete DATA packet");
      83              : 
      84            0 :             TFTP_Data_Header header;
      85            0 :             std::memcpy(&header, reply.data(), sizeof(header));
      86              : 
      87            0 :             TLOG() << "Received DATA packet:\n" <<
      88            0 :                         "  Block #: "<< static_cast<uint16_t>(header.block) << "\n" <<
      89            0 :                         "  Payload size: "<< reply.size() - sizeof(header) <<" bytes\n"; 
      90              : 
      91              :             // Data starts at byte 3
      92            0 :             reply.resize(len);
      93              :             // Remove opcode
      94            0 :             reply.erase(reply.begin(), reply.begin() + 2);
      95              : 
      96            0 :             return reply;
      97              :         }
      98              : 
      99            0 :         case TFTPOpCode::ACK: {
     100            0 :             TFTP_Ack_Header header;
     101            0 :             std::memcpy(&header, reply.data(), sizeof(header));
     102              : 
     103            0 :             TLOG() << m_log_prefix << "Recieved Ack packet:\n" << static_cast<uint16_t>(header.block);
     104            0 :             return {};
     105              :         }
     106              : 
     107            0 :         case TFTPOpCode::ERR: {
     108            0 :             TFTP_Error_Header header;
     109            0 :             std::memcpy(&header, reply.data(), sizeof(header));
     110              : 
     111            0 :             std::string error_msg(reinterpret_cast<const char*>(reply.data() + sizeof(header)),
     112            0 :                                   reply.size() - sizeof(header));
     113              : 
     114            0 :             ers::error(AMCResponseErr(ERS_HERE, m_log_prefix, static_cast<uint16_t>(header.error_code), error_msg));
     115            0 :             return {};
     116            0 :         }
     117              : 
     118            0 :         default:
     119            0 :             ers::error(AMCUnknownOpCode(ERS_HERE, m_log_prefix, static_cast<uint16_t>(opcode)));
     120              : 
     121            0 :         return {};
     122              :     }
     123            0 : }
     124              : 
     125              : 
     126              : 
     127              : 
     128              : } // namespace tdemodules
     129              : } // namespace dunedaq
     130              : 
        

Generated by: LCOV version 2.0-1