LCOV - code coverage report
Current view: top level - daphnemodules/src - DaphneV2Interface.cpp (source / functions) Coverage Total Hit
Test: code.result Lines: 6.8 % 146 10
Test Date: 2026-10-11 15:05:20 Functions: 7.1 % 14 1

            Line data    Source code
       1              : /**
       2              :  *
       3              :  * Implementations of DaphneV2Interface's functions
       4              :  *
       5              :  * This is part of the DUNE DAQ Software Suite, copyright 2020.
       6              :  * Licensing/copyright details are in the COPYING file that you should have
       7              :  */
       8              : 
       9              : #include "DaphneV2Interface.hpp"
      10              : #include "logging/Logging.hpp"
      11              : #include <sys/time.h>
      12              : 
      13              : using namespace dunedaq::daphnemodules;
      14              : 
      15            1 : DaphneV2Interface::DaphneV2Interface(const char* ipaddr, int port, std::chrono::milliseconds timeout)
      16            1 :   : m_timeout(timeout)
      17              : {
      18              : 
      19            1 :   m_connection_id = socket(AF_INET, SOCK_DGRAM, 0);
      20              : 
      21            1 :   if (m_connection_id < 0)
      22            0 :     throw SocketCreationError(ERS_HERE);
      23              : 
      24            1 :   m_target.sin_family = AF_INET;
      25            1 :   m_target.sin_port = htons(port);
      26            1 :   auto ret = inet_pton(AF_INET, ipaddr, &(m_target.sin_addr));
      27            1 :   if (ret <= 0)
      28            1 :     throw InvalidIPAddress(ERS_HERE, ipaddr);
      29              : 
      30            0 :   m_ip = ipaddr;
      31              : 
      32            0 :   if (!validate_connection())
      33            0 :     throw FailedPing(ERS_HERE, ipaddr, port);
      34            1 : }
      35              : 
      36              : void
      37            0 : DaphneV2Interface::close()
      38              : {
      39              : 
      40            0 :   ::close(m_connection_id);
      41            0 : }
      42              : 
      43              : bool
      44            0 : DaphneV2Interface::validate_connection() const
      45              : {
      46              : 
      47            0 :   auto ret = read_register(0xaa55, 1);
      48              : 
      49            0 :   static const uint64_t good_value = 0xdeadbeef;
      50            0 :   return ret[0] == good_value;
      51            0 : }
      52              : 
      53              : command_result
      54            0 : DaphneV2Interface::send_command_retry(std::string cmd, size_t retry) const
      55              : {
      56              : 
      57            0 :   do {
      58            0 :     try {
      59            0 :       auto ret = send_command(cmd);
      60            0 :       return ret;
      61            0 :     } catch (const CommandTimeout& e) {
      62            0 :       ers::warning(e);
      63            0 :       --retry;
      64            0 :     } catch (const ers::Issue& e) {
      65            0 :       throw FailedSocketInteraction(ERS_HERE, cmd, e);
      66            0 :     }
      67              : 
      68            0 :   } while (retry > 0);
      69              : 
      70            0 :   throw FailedSocketInteraction(ERS_HERE, cmd);
      71              : }
      72              : 
      73              : command_result
      74            0 : DaphneV2Interface::send_command_interruptible(std::string cmd, std::function<bool()> can_retry) const
      75              : {
      76              : 
      77            0 :   do {
      78            0 :     try {
      79            0 :       auto ret = send_command(cmd);
      80            0 :       return ret;
      81            0 :     } catch (const CommandTimeout& e) {
      82            0 :       ers::warning(e);
      83            0 :     } catch (const ers::Issue& e) {
      84            0 :       throw FailedSocketInteraction(ERS_HERE, cmd, e);
      85            0 :     }
      86              : 
      87            0 :   } while (can_retry());
      88              : }
      89              : 
      90              : command_result
      91            0 : DaphneV2Interface::send_command(std::string cmd) const
      92              : {
      93              : 
      94            0 :   TLOG() << "Board: " << m_ip << ", sending command " << cmd;
      95            0 :   std::vector<uint64_t> bytes;
      96            0 :   for (char ch : cmd) {
      97            0 :     bytes.push_back(static_cast<uint64_t>(ch));
      98              :   }
      99            0 :   bytes.push_back(0x0d); // dedicated command flag
     100              : 
     101            0 :   const std::lock_guard<std::mutex> lock(m_command_mutex);
     102              : 
     103              :   // we send the bytes in chunks of 50 words
     104            0 :   for (size_t i = 0; i < (bytes.size() + 49) / 50; ++i) {
     105            0 :     std::vector<uint64_t> part(bytes.begin() + i * 50, bytes.begin() + std::min((i + 1) * 50, bytes.size()));
     106            0 :     write_buffer(0x90000000, std::move(part));
     107            0 :   }
     108              : 
     109            0 :   TLOG() << "Board: " << m_ip << ", Command sent, waiting for result";
     110              : 
     111            0 :   command_result res;
     112            0 :   std::string* writing_pointer = nullptr;
     113              : 
     114            0 :   auto start_time = std::chrono::high_resolution_clock::now();
     115              : 
     116            0 :   int more = 40;
     117            0 :   while (more > 0) {
     118            0 :     auto data_block = read_buffer(0x90000000, 50);
     119            0 :     for (size_t i = 0; i < data_block.size(); ++i) {
     120            0 :       if (data_block[i] == 255) {
     121              :         break;
     122            0 :       } else if (data_block[i] == 1) {
     123              :         // the following data are returning the command that was issued
     124            0 :         writing_pointer = &res.command;
     125            0 :       } else if (data_block[i] == 2) {
     126              :         // the following data are the immediate command response
     127            0 :         writing_pointer = &res.result;
     128            0 :       } else if (data_block[i] == 3) {
     129              :         // this is the message end
     130              :         writing_pointer = nullptr;
     131            0 :       } else if (isprint(static_cast<int>(data_block[i]))) {
     132            0 :         more = 40;
     133            0 :         char c = static_cast<char>(data_block[i]);
     134            0 :         if (writing_pointer) {
     135            0 :           *writing_pointer += static_cast<char>(data_block[i]);
     136              :         } else {
     137            0 :           TLOG() << "Failed adding charachter " << c;
     138              :         }
     139              :       }
     140              :     }
     141            0 :     auto now = std::chrono::high_resolution_clock::now();
     142              : 
     143            0 :     auto delay = now - start_time;
     144              : 
     145            0 :     if (delay > m_timeout) {
     146            0 :       TLOG() << "Details of timeout";
     147            0 :       for (size_t i = 0; i < data_block.size(); ++i) {
     148            0 :         TLOG() << i << "\t" << std::hex << data_block[i] << std::dec;
     149              :       }
     150            0 :       TLOG() << "Received so far: " << res.result;
     151            0 :       auto delay_us = std::chrono::duration_cast<std::chrono::microseconds>(delay);
     152            0 :       throw CommandTimeout(ERS_HERE, cmd, delay_us.count());
     153              :     }
     154              : 
     155            0 :     std::this_thread::sleep_for(std::chrono::milliseconds(1));
     156            0 :     --more;
     157            0 :   }
     158              : 
     159            0 :   return res;
     160            0 : }
     161              : 
     162              : std::vector<uint64_t>
     163            0 : DaphneV2Interface::read(uint8_t command_id, uint64_t addr, uint8_t size) const
     164              : {
     165              : 
     166            0 :   const std::lock_guard<std::mutex> lock(m_access_mutex);
     167              : 
     168            0 :   uint8_t cmd[10];
     169            0 :   cmd[0] = command_id;
     170            0 :   cmd[1] = size;
     171            0 :   memcpy(cmd + 2, &addr, sizeof(uint64_t));
     172            0 :   auto result = sendto(m_connection_id, cmd, sizeof(cmd), 0, (struct sockaddr*)&m_target, sizeof(m_target));
     173              : 
     174            0 :   if (result < 0)
     175            0 :     throw FailedSocketInteraction(ERS_HERE, "sendto");
     176              : 
     177            0 :   struct timeval timeout;
     178            0 :   timeout.tv_sec = m_timeout.count() / 1000;
     179            0 :   timeout.tv_usec = (m_timeout.count() % 1000) * 1000;
     180            0 :   fd_set readfds, masterfds;
     181              : 
     182            0 :   FD_ZERO(&masterfds);
     183            0 :   FD_SET(m_connection_id, &masterfds);
     184              : 
     185            0 :   memcpy(&readfds, &masterfds, sizeof(fd_set));
     186              : 
     187            0 :   auto start_time = std::chrono::high_resolution_clock::now();
     188              : 
     189            0 :   if (select(m_connection_id + 1, &readfds, NULL, NULL, &timeout) < 0) {
     190            0 :     throw FailedSocketInteraction(ERS_HERE, "select");
     191              :   }
     192              : 
     193            0 :   std::vector<uint64_t> ret_value;
     194              : 
     195            0 :   if (FD_ISSET(m_connection_id, &readfds)) {
     196            0 :     uint8_t buffer[2 + (8 * size)];
     197            0 :     socklen_t addrlen = sizeof(m_target);
     198            0 :     result = recvfrom(m_connection_id, buffer, sizeof(buffer), 0, (struct sockaddr*)&m_target, &addrlen);
     199              : 
     200            0 :     if (result <= 0)
     201            0 :       throw FailedSocketInteraction(ERS_HERE, "recvfrom");
     202              : 
     203            0 :     uint8_t fmt[4 + size];
     204            0 :     fmt[0] = '<';
     205            0 :     fmt[1] = 'B';
     206            0 :     fmt[2] = 'B';
     207            0 :     fmt[3] = size;
     208            0 :     for (int i = 0; i < size; i++) {
     209            0 :       fmt[4 + i] = 'Q';
     210              :     }
     211              : 
     212            0 :     for (int i = 0; i < size; i++) {
     213            0 :       uint64_t value;
     214            0 :       memcpy(&value, buffer + 2 + (8 * i), sizeof(uint64_t));
     215            0 :       ret_value.push_back(value);
     216              :     }
     217              : 
     218            0 :   } else {
     219              :     // the socket timedout
     220            0 :     auto end_time = std::chrono::high_resolution_clock::now();
     221            0 :     auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end_time - start_time);
     222              : 
     223            0 :     throw SocketTimeout(ERS_HERE, duration.count());
     224              :   }
     225              : 
     226            0 :   return ret_value;
     227            0 : }
     228              : 
     229              : void
     230            0 : DaphneV2Interface::write(uint8_t command_id, uint64_t addr, std::vector<uint64_t>&& data) const
     231              : {
     232              : 
     233            0 :   const std::lock_guard<std::mutex> lock(m_access_mutex);
     234              : 
     235            0 :   uint8_t cmd[10 + (8 * data.size())];
     236            0 :   cmd[0] = command_id;
     237            0 :   cmd[1] = data.size();
     238            0 :   memcpy(cmd + 2, &addr, sizeof(uint64_t));
     239            0 :   for (size_t i = 0; i < data.size(); i++) {
     240            0 :     memcpy(cmd + 10 + (8 * i), &(data[i]), sizeof(uint64_t));
     241              :   }
     242              : 
     243            0 :   auto result = sendto(m_connection_id, cmd, sizeof(cmd), 0, (struct sockaddr*)&m_target, sizeof(m_target));
     244            0 :   if (result < 0)
     245            0 :     throw FailedSocketInteraction(ERS_HERE, "sendto");
     246            0 : }
        

Generated by: LCOV version 2.0-1