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

            Line data    Source code
       1              : #include "wibmod/WIB1/BNL_UDP.hh"
       2              : #include "wibmod/WIB1/BNL_UDP_Exception.hh"
       3              : #include <sys/socket.h>
       4              : #include <string.h> //memset, strerror
       5              : #include <errno.h>
       6              : #include <string>
       7              : #include <fcntl.h> //fcntl
       8              : 
       9              : #include <sstream>
      10              : #include <iomanip>
      11              : 
      12              : #include <netdb.h>
      13              : 
      14              : #include <errno.h>
      15              : #include <algorithm> //STD::COUNT
      16              : 
      17              : #define WIB_WR_BASE_PORT 32000
      18              : #define WIB_RD_BASE_PORT 32001
      19              : #define WIB_RPLY_BASE_PORT 32002
      20              : 
      21              : #define WIB_PACKET_KEY 0xDEADBEEF
      22              : //#define WIB_REQUEST_PACKET_SIZE (4+2+4+2)
      23              : #define WIB_REQUEST_PACKET_TRAILER 0xFFFF
      24              : 
      25              : #define WIB_RPLY_PACKET_SIZE 12
      26              : 
      27              : #define TIMEOUT_SECONDS 2
      28              : #define TIMEOUT_MICROSECONDS 0
      29              : struct WIB_packet_t{
      30              :   uint32_t key;
      31              :   uint32_t reg_addr : 16;
      32              :   uint32_t data_MSW : 16;
      33              :   uint32_t data_LSW : 16;
      34              :   uint32_t trailer  : 16;
      35              : };
      36              : 
      37            0 : static std::string dump_packet(uint8_t * data, size_t size){
      38              :   //  printf("Err: %p %zu\n",data,size);
      39            0 :   std::stringstream ss;
      40            0 :   for(size_t iWord = 0; iWord < size;iWord++){
      41            0 :     ss << "0x" << std::hex << std::setfill('0') << std::setw(4) << iWord;
      42            0 :     ss << ": 0x" << std::hex << std::setfill('0') << std::setw(2) << int(data[iWord]);
      43            0 :     iWord++;
      44            0 :     if(iWord < size){
      45            0 :       ss << std::hex << std::setfill('0') << std::setw(2) << int(data[iWord]);
      46              :     }
      47            0 :     ss << std::endl;
      48              :   }
      49              :   //  printf("%s",ss.str().c_str());
      50            0 :   return ss.str();
      51            0 : }
      52              : 
      53            0 : void BNL_UDP::FlushSocket(int sock){
      54              :   //turn on non-blocking
      55            0 :   fcntl(sock, F_SETFL, fcntl(sock, F_GETFL)| O_NONBLOCK);
      56            0 :   int ret;
      57            0 :   do{
      58            0 :     ret = recv(sock,buffer,buffer_size,0);      
      59            0 :   }while(ret != -1);
      60            0 :   fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) & (~O_NONBLOCK));
      61            0 : }
      62              :   
      63            0 : void BNL_UDP::Clear(){
      64              :   //close sockets
      65            0 :   if(readSocketFD != -1){
      66            0 :     close(readSocketFD);
      67            0 :     readSocketFD = -1;
      68              :   }
      69            0 :   if(writeSocketFD != -1){
      70            0 :     close(writeSocketFD);
      71            0 :     writeSocketFD = -1;
      72              :   }
      73              :   //Clear packet buffer
      74            0 :   if(buffer != NULL){
      75            0 :     delete [] buffer;
      76            0 :     buffer_size = 0;
      77              :   }  
      78            0 :   writeAck  = false;
      79            0 :   connected = false;
      80              : 
      81              :   //Reset send/recv addr structures
      82            0 :   memset(&readAddr,0,sizeof(readAddr));
      83            0 :   memset(&writeAddr,0,sizeof(writeAddr));
      84            0 : }
      85              : 
      86              : //static void printaddress(struct sockaddr_in const * addr){
      87              : //  printf("%u: %u.%u.%u.%u : %u\n",
      88              : //       addr->sin_family,
      89              : //       (addr->sin_addr.s_addr >> 0)&0xFF,
      90              : //       (addr->sin_addr.s_addr >> 8)&0xFF,
      91              : //       (addr->sin_addr.s_addr >> 16)&0xFF,
      92              : //       (addr->sin_addr.s_addr >> 24)&0xFF,
      93              : //       ntohs(addr->sin_port));
      94              : //}
      95              : 
      96            0 : void BNL_UDP::Setup(std::string const & address,uint16_t port_offset){
      97              :   //Reset the network structures
      98            0 :   Clear();
      99              : 
     100              :   //Allocate the recv buffer
     101            0 :   ResizeBuffer();
     102              : 
     103              :   //Check port_offset range
     104            0 :   if(port_offset > 128){
     105            0 :     BUException::BNL_UDP_PORT_OUT_OF_RANGE e;
     106            0 :     throw e;    
     107            0 :   }
     108              : 
     109              :   //Set the ports for this device (FEMBs are iFEMB*0x10 above the base)
     110            0 :   readPort  = WIB_RD_BASE_PORT   + port_offset;
     111            0 :   writePort = WIB_WR_BASE_PORT   + port_offset;
     112              :   //  replyPort = WIB_RPLY_BASE_PORT + port_offset;
     113              : 
     114            0 :   remoteAddress = address;
     115              :   //Get the sockaddr for the address
     116            0 :   struct addrinfo * res;
     117            0 :   if(getaddrinfo(address.c_str(),NULL,NULL,&res)){
     118              :     //Check if we have just one "." character and is less than 5 characters
     119            0 :     if(address.size() <= 5 && 1 == std::count(address.begin(),address.end(),'.')){
     120            0 :       std::string strCrate = address.substr(0,address.find('.'));
     121            0 :       std::string strSlot  = address.substr(address.find('.')+1);
     122            0 :       if(strCrate.size() != 0 && strSlot.size() != 0){
     123            0 :         uint8_t crate = strtoul(strCrate.c_str(),NULL,0);
     124            0 :         uint8_t slot  = strtoul(strSlot.c_str(), NULL,0);
     125            0 :         if( (((crate > 0) && (crate < 7)) || 0xF == crate) &&
     126            0 :             (((slot > 0) && (slot < 7)) || 0xF == slot)){
     127            0 :           remoteAddress = std::string("192.168.");
     128              :           //Add the crate part of the address (200 + crate number)
     129            0 :           if(crate == 0xF){
     130            0 :             remoteAddress += "200.";
     131              :           }else{
     132              :             //generate the crate number which is 200 + crate number
     133            0 :             remoteAddress += "20";
     134            0 :             remoteAddress += ('0' + crate);
     135            0 :             remoteAddress += '.';
     136              :           }
     137            0 :           if(slot == 0xF){
     138            0 :             remoteAddress += "50";
     139              :           }else{
     140              :             //crate last IP octet that is slot number
     141            0 :             remoteAddress += ('0' + slot);
     142              :           }
     143              :         }
     144              :       }
     145            0 :     }
     146              :     //try a second time assumin gthis is a crate.slot address, fail if this still doesn't work
     147            0 :     if(getaddrinfo(address.c_str(),NULL,NULL,&res)){
     148            0 :       BUException::BAD_REMOTE_IP e;
     149            0 :       e.Append("Addr: ");
     150            0 :       e.Append(address.c_str());
     151            0 :       e.Append(" could not be resolved.\n");
     152            0 :       throw e;
     153            0 :     }
     154              :   }
     155              :   //  readAddr = *((struct sockaddr_in *) res->ai_addr);
     156              :   //  printaddress(&readAddr);
     157              : 
     158              :   //Generate the sockets for read and write
     159            0 :   if((readSocketFD = socket(AF_INET,SOCK_DGRAM,0)) < 0){
     160            0 :     BUException::BAD_SOCKET e;
     161            0 :     e.Append("read socket\n");    
     162            0 :     throw e;
     163            0 :   }      
     164            0 :   if((writeSocketFD = socket(AF_INET,SOCK_DGRAM,0)) < 0){
     165            0 :     BUException::BAD_SOCKET e;
     166            0 :     e.Append("write socket\n");
     167            0 :     throw e;
     168            0 :   }      
     169              :   //Set a timeout for the recv socket so we don't hang on a reply
     170            0 :   struct timeval tv; tv.tv_sec=TIMEOUT_SECONDS; tv.tv_usec=TIMEOUT_MICROSECONDS;
     171            0 :   setsockopt(readSocketFD, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv,sizeof(struct timeval));
     172            0 :   setsockopt(writeSocketFD, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv,sizeof(struct timeval));
     173              : 
     174              :   //connect the read socket
     175            0 :   readAddr = *((struct sockaddr_in *) res->ai_addr);
     176            0 :   readAddr.sin_port = htons(readPort); 
     177            0 :   if(connect(readSocketFD,(struct sockaddr *) &readAddr,sizeof(readAddr)) < 0){
     178            0 :     BUException::CONNECTION_FAILED e;
     179            0 :     e.Append("read socket connect\n");
     180            0 :     e.Append(strerror(errno));
     181            0 :     throw e;
     182            0 :   }
     183              :   //connect the write socket
     184            0 :   writeAddr = *((struct sockaddr_in *) res->ai_addr);
     185            0 :   writeAddr.sin_port = htons(writePort); 
     186            0 :   if(connect(writeSocketFD,(struct sockaddr *) &writeAddr,sizeof(writeAddr)) < 0){
     187            0 :     BUException::CONNECTION_FAILED e;
     188            0 :     e.Append("write socket connect\n");
     189            0 :     e.Append(strerror(errno));
     190            0 :     throw e;
     191            0 :   }
     192              : 
     193              :   //Allocate the receive buffer to default size
     194            0 :   ResizeBuffer();
     195            0 : }
     196              : 
     197            0 : void BNL_UDP::WriteWithRetry(uint16_t address, uint32_t value, uint8_t retry_count){
     198            0 :   while(retry_count > 1){
     199            0 :     try{
     200              :       //Do the write
     201            0 :       Write(address,value);
     202            0 :       usleep(10);
     203              :       //if everything goes well, return
     204              :       return;
     205            0 :     }catch(BUException::BAD_REPLY &e){
     206              :       //eat the exception
     207            0 :     }
     208            0 :     total_retry_count++;
     209            0 :     retry_count--;
     210            0 :     usleep(10);
     211              :   }
     212              :   //Last chance we don't catch the exception and let it fall down the stack
     213              :   //Do the write
     214            0 :   Write(address,value);
     215            0 :   usleep(10);
     216              : }
     217            0 : void BNL_UDP::Write(uint16_t address, uint32_t value){
     218              : 
     219              :   //Flush this socket
     220            0 :   FlushSocket(writeSocketFD);
     221              : 
     222              :   //Build the packet to send
     223              :   //build the send packet
     224            0 :   WIB_packet_t packet;
     225            0 :   packet.key = htonl(WIB_PACKET_KEY);
     226            0 :   packet.reg_addr = htons(address);
     227            0 :   packet.data_MSW = htons(uint16_t((value >> 16) & 0xFFFF));
     228            0 :   packet.data_LSW = htons(uint16_t((value >>  0) & 0xFFFF));
     229            0 :   packet.trailer = htons(WIB_REQUEST_PACKET_TRAILER);
     230              : 
     231              :   //send the packet
     232            0 :   ssize_t send_size = sizeof(packet);
     233            0 :   ssize_t sent_size = 0;
     234            0 :   if( send_size != (sent_size = send(writeSocketFD,
     235              :                                      &packet,send_size,0))){
     236              :     //bad send
     237            0 :     BUException::SEND_FAILED e;
     238            0 :     if(sent_size == -1){
     239            0 :       e.Append("BNL_UDP::Write(uint16_t,uint32_t)\n");
     240            0 :       e.Append("Errnum: ");
     241            0 :       e.Append(strerror(errno));
     242              :     } 
     243            0 :     throw e;
     244            0 :   }
     245              : 
     246              :   //If configured, capture confirmation packet
     247            0 :   if(writeAck ){
     248            0 :     ssize_t reply_size = recv(writeSocketFD,
     249            0 :                               buffer,buffer_size,0);
     250              : 
     251            0 :     if(-1 == reply_size){
     252            0 :       BUException::BAD_REPLY e;
     253            0 :       std::stringstream ss;
     254            0 :       e.Append("BNL_UDP::Write(uint16_t,uint32_t)\n");
     255            0 :       ss << "Errnum(" << errno << "): " << strerror(errno) << "\n";
     256            0 :       e.Append(ss.str().c_str());
     257            0 :       e.Append(dump_packet((uint8_t*) &packet,send_size).c_str());
     258            0 :       throw e;
     259            0 :     }else if( reply_size < WIB_RPLY_PACKET_SIZE){
     260            0 :       BUException::BAD_REPLY e;
     261            0 :       std::stringstream ss;
     262            0 :       ss << "Bad Size: " << reply_size << "\n";
     263            0 :       e.Append("BNL_UDP::Write(uint16_t,uint32_t)\n");
     264            0 :       e.Append(ss.str().c_str());
     265            0 :       e.Append(dump_packet(buffer,reply_size).c_str());
     266            0 :       throw e;
     267            0 :     }
     268            0 :     uint16_t reply_address =  uint16_t(buffer[0] << 8 | buffer[1]);
     269            0 :     if( reply_address != address){
     270            0 :       BUException::BAD_REPLY e;
     271            0 :       std::stringstream ss;
     272            0 :       ss << "Bad address: " << uint32_t(address) << " != " << uint32_t(reply_address) << "\n";
     273            0 :       e.Append("BNL_UDP::Write(uint16_t,uint32_t)\n");
     274            0 :       e.Append(ss.str().c_str());
     275            0 :       e.Append(dump_packet(buffer,reply_size).c_str());
     276            0 :       throw e;    
     277            0 :     }    
     278              :   }  
     279            0 : }
     280            0 : void BNL_UDP::Write(uint16_t address, std::vector<uint32_t> const & values){
     281            0 :   Write(address,values.data(),values.size());
     282            0 : }
     283            0 : void BNL_UDP::Write(uint16_t address, uint32_t const * values, size_t word_count){
     284            0 :   for(size_t iWrite = 0; iWrite < word_count;iWrite++){
     285            0 :     WriteWithRetry(address,values[iWrite]);
     286            0 :     address++;
     287              :   }
     288              : 
     289              : ////////  //Flush the socket
     290              : ////////  FlushSocket(writeSocketFD);
     291              : ////////
     292              : ////////  //Compute the size of this multi-write packet
     293              : ////////  // values.size() - 1 gets the number of address and MSW/LSW groups that aren't already in the packet
     294              : ////////  size_t packetSize = sizeof(WIB_packet_t) + (word_count-1)*6; 
     295              : ////////  //resize the buffer if needed  
     296              : ////////  ResizeBuffer(packetSize);
     297              : ////////  
     298              : ////////  //Set the packet key
     299              : ////////  (*((uint32_t*) buffer)) = htonl(WIB_PACKET_KEY);
     300              : ////////  //Create a pointer to 16bit words that points to the parts of buffer that are after the first 32bit word (WIB key)
     301              : ////////  uint16_t * packet = (uint16_t*) (buffer + sizeof(uint32_t));
     302              : ////////  for(size_t iWord = 0; iWord < word_count;iWord++){
     303              : ////////    //Set the word address
     304              : ////////    packet[0] = htons(address);
     305              : ////////    //Set the MS 16bit part of the 32bit word
     306              : ////////    packet[1] = htons(uint16_t((values[iWord] >> 16) & 0xFFFF));
     307              : ////////    //Set the LS 16bit part of the 32bit word
     308              : ////////    packet[2] = htons(uint16_t((values[iWord] >>  0) & 0xFFFF));
     309              : ////////    //move the write address forward 1 word
     310              : ////////    address++;
     311              : ////////    //move the packet pointer forward to the next word block
     312              : ////////    packet+=3;
     313              : ////////  }
     314              : ////////  //Set the packet trailer
     315              : ////////  (*packet) = htons(WIB_REQUEST_PACKET_TRAILER);
     316              : ////////
     317              : ////////  //send the packet
     318              : ////////  ssize_t send_size = packetSize;
     319              : ////////  ssize_t sent_size = 0;
     320              : ////////  if( send_size != (sent_size = send(writeSocketFD,
     321              : ////////                                     buffer,send_size,0))){
     322              : ////////    //bad send
     323              : ////////    BUException::SEND_FAILED e;
     324              : ////////    if(sent_size == -1){
     325              : ////////      e.Append("BNL_UDP::Write(uint16_t,uint32_t*,size_t)\n");
     326              : ////////      e.Append("Errnum: ");
     327              : ////////      e.Append(strerror(errno));
     328              : ////////    } 
     329              : ////////    throw e;
     330              : ////////  }
     331              : ////////  //If configured, capture confirmation packet
     332              : ////////  if(writeAck ){
     333              : ////////    ssize_t reply_size = recv(writeSocketFD,
     334              : ////////                              buffer,buffer_size,0);
     335              : ////////
     336              : ////////
     337              : ////////    //    writeAddr = readAddr;
     338              : ////////    //    writeAddr.sin_port = htons(replyPort);
     339              : ////////
     340              : ////////    //    sockaddr_len = sizeof(writeAddr);
     341              : ////////    //    ssize_t reply_size = recvfrom(recvSocketFD,
     342              : //////////    recvfrom(recvSocketFD,
     343              : //////////           buffer,buffer_size,0,
     344              : //////////           (struct sockaddr*)&writeAddr,&sockaddr_len);    
     345              : ////////    if(-1 == reply_size){
     346              : ////////      BUException::BAD_REPLY e;
     347              : ////////      e.Append("BNL_UDP::Write(uint16_t,uint32_t*,size_t)\n");
     348              : ////////      e.Append(strerror(errno));
     349              : ////////      throw e;
     350              : ////////    }else if( reply_size < WIB_RPLY_PACKET_SIZE){
     351              : ////////      BUException::BAD_REPLY e;
     352              : ////////      std::stringstream ss;
     353              : ////////      ss << "Bad Size: " << reply_size << "\n";
     354              : ////////      e.Append("BNL_UDP::Write(uint16_t,uint32_t*,size_t)\n");
     355              : ////////      e.Append(ss.str().c_str());
     356              : ////////      e.Append(dump_packet(buffer,reply_size).c_str());
     357              : ////////      throw e;
     358              : ////////    }
     359              : //////////    uint16_t reply_address =  uint16_t(buffer[0] << 8 | buffer[1]);
     360              : //////////    if( reply_address != address){
     361              : //////////      BUException::BAD_REPLY e;
     362              : //////////      std::stringstream ss;
     363              : //////////      ss << "Bad address: " << address << " != " << reply_address << "\n";
     364              : //////////      e.Append(ss.str().c_str());
     365              : //////////      throw e;    
     366              : //////////    }    
     367              : ////////  }  
     368            0 : }
     369              : 
     370            0 : uint32_t BNL_UDP::ReadWithRetry(uint16_t address,uint8_t retry_count){
     371            0 :   uint32_t val;
     372            0 :   while(retry_count > 1){
     373            0 :     try{
     374              :       //Do the write
     375            0 :       val = Read(address);
     376            0 :       usleep(10);
     377              :       //if everything goes well, return
     378              :       return val;
     379            0 :     }catch(BUException::BAD_REPLY &e){
     380              :       //eat the exception
     381            0 :     }
     382            0 :     usleep(10);
     383            0 :     total_retry_count++;
     384            0 :     retry_count--;
     385              :   }
     386              :   //Last chance we don't catch the exception and let it fall down the stack
     387            0 :   val = Read(address);  
     388            0 :   usleep(10);
     389            0 :   return val;
     390              : }
     391            0 : uint32_t BNL_UDP::Read(uint16_t address){
     392              :   //Flush the socket
     393            0 :   FlushSocket(readSocketFD);
     394              : 
     395              :   //build the send packet
     396            0 :   WIB_packet_t packet;
     397            0 :   packet.key = htonl(WIB_PACKET_KEY);
     398            0 :   packet.reg_addr = htons(address);
     399            0 :   packet.data_MSW = packet.data_LSW = 0;
     400            0 :   packet.trailer = htons(WIB_REQUEST_PACKET_TRAILER);
     401              : 
     402              :   //send the packet
     403            0 :   ssize_t send_size = sizeof(packet);
     404            0 :   ssize_t sent_size = 0;
     405            0 :   if( send_size != (sent_size = send(readSocketFD,
     406              :                                      &packet,send_size,0))){
     407              :     //bad send
     408            0 :     BUException::SEND_FAILED e;
     409            0 :     if(sent_size == -1){
     410            0 :       e.Append("BNL_UDP::Read(uint16_t)\n");
     411            0 :       e.Append("Errnum: ");
     412            0 :       e.Append(strerror(errno));
     413              :     } 
     414            0 :     throw e;
     415            0 :   }
     416              : 
     417              :   //Get the reply packet with the register data in it.   
     418            0 :   ssize_t reply_size = recv(readSocketFD,
     419            0 :                             buffer,buffer_size,0);
     420              :                             
     421            0 :   if(ssize_t(-1) == reply_size){
     422            0 :     BUException::BAD_REPLY e;
     423            0 :     std::stringstream ss;
     424            0 :     e.Append("BNL_UDP::Read(uint16_t)\n");
     425            0 :     ss << "Errnum(" << errno << "): " << strerror(errno) << "\n";
     426            0 :     e.Append(ss.str().c_str());
     427            0 :     e.Append(dump_packet((uint8_t *)&packet,send_size).c_str());
     428            0 :     throw e;
     429            0 :   }else if( reply_size < WIB_RPLY_PACKET_SIZE){
     430            0 :     BUException::BAD_REPLY e;
     431            0 :     std::stringstream ss;
     432            0 :     ss << "Bad Size: " << reply_size << "\n";
     433            0 :     e.Append("BNL_UDP::Read(uint16_t)\n");
     434            0 :     e.Append(ss.str().c_str());
     435            0 :     e.Append(dump_packet(buffer,reply_size).c_str());
     436            0 :     throw e;
     437            0 :   }
     438            0 :   uint16_t reply_address =  uint16_t(buffer[0] << 8 | buffer[1]);
     439            0 :   if( reply_address != address){
     440            0 :     BUException::BAD_REPLY e;
     441            0 :     std::stringstream ss;
     442            0 :     ss << "Bad address: " << uint32_t(address) << " != " << uint32_t(reply_address) << "\n";
     443            0 :     e.Append("BNL_UDP::Read(uint16_t)\n");
     444            0 :     e.Append(ss.str().c_str());
     445            0 :     e.Append(dump_packet(buffer,reply_size).c_str());
     446            0 :     throw e;    
     447            0 :   }
     448              :   
     449              : 
     450              :     //  }
     451            0 :   uint32_t ret = ( (uint32_t(buffer[2]) << 24) | 
     452            0 :                    (uint32_t(buffer[3]) << 16) | 
     453            0 :                    (uint32_t(buffer[4]) <<  8) | 
     454            0 :                    (uint32_t(buffer[5]) <<  0));
     455            0 :   return ret;
     456              : }
     457              : 
     458              : 
     459            0 : BNL_UDP::~BNL_UDP(){
     460            0 :   Clear();
     461            0 : }
     462              : 
     463              : 
     464            0 : void BNL_UDP::ResizeBuffer(size_t size){
     465              :   //CHeck if the requested size is larger than the already allocated size
     466              :   //  printf("before %p %zu %zd\n",buffer,buffer_size,buffer_size);
     467            0 :   if(buffer_size < size){
     468              :     //We need to re-allocate
     469            0 :     if(buffer != NULL){
     470            0 :       delete [] buffer;
     471              :     }
     472            0 :     buffer = new uint8_t[size];
     473            0 :     buffer_size = size;
     474              :   }
     475              :   //  printf("after %p %zu %zd\n",buffer,buffer_size,buffer_size);
     476            0 : }
        

Generated by: LCOV version 2.0-1