rllib  1
rleibnetip.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                         rleibnetip.cpp  -  description
00003                              -------------------
00004     begin                : WEd Apr 04 2007
00005     copyright            : (C) 2007 by Rainer Lehrig
00006     email                : lehrig@t-online.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This library is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as        *
00013  *   published by the Free Software Foundation                             *
00014  *                                                                         *
00015  ***************************************************************************/
00016 #include "rleibnetip.h"
00017 #include "rltime.h"
00018 #include "rldataacquisitionprovider.h"
00019 #include <stdio.h>
00020 #include <string.h>
00021 #include <math.h>
00022 
00023 #define EIB_HEADERSIZE        6
00024 #define EIB_VERSION           0x10
00025 #define EIB_ADRSIZE           8
00026 //not sizeof(struct sockaddr_in)
00027 #define EIB_CRICRDSIZE        4
00028 #define TUNNEL_CONNECTION     4
00029 #define REMLOG_CONNECTION     6
00030 #define OBJSVR_CONNECTION     8
00031 #define TUNNEL_LINKLAYER      2
00032 #define E_NO_ERROR            0
00033 #define E_NO_MORE_CONNECTIONS 0x24
00034 #define E_SEQUENCE_NUMBER     0x04
00035 
00036 #define L_Data_Req 0x11
00037 #define L_Data_Con 0x2E
00038 #define L_Data_Ind 0x29
00039 
00040 enum ServiceType
00041 {
00042   SEARCH_REQUEST            = 0x0201,
00043   SEARCH_RESPONSE           = 0x0202,
00044   DESCRIPTION_REQUEST       = 0x0203,
00045   DESCRIPTION_RESPONSE      = 0x0204,
00046   CONNECT_REQUEST           = 0x0205,
00047   CONNECT_RESPONSE          = 0x0206,
00048   CONNECTIONSTATE_REQUEST   = 0x0207,
00049   CONNECTIONSTATE_RESPONSE  = 0x0208,
00050   DISCONNECT_REQUEST        = 0x0209,
00051   DISCONNECT_RESPONSE       = 0x020A,
00052   TUNNELLING_REQUEST        = 0x0420,
00053   TUNNELLING_ACK            = 0x0421
00054 };
00055 
00056 static void *eib_reader(void *arg) // thread
00057 {
00058   THREAD_PARAM *p = (THREAD_PARAM *) arg;
00059   rlEIBnetIP *eib = (rlEIBnetIP *) p->user;
00060   rlEIBnetIP::PDU pdu;
00061   rlTime now, last, diff;
00062   int ret, len;
00063   int recseq = 0;
00064   int expected_recseq = 0;
00065   unsigned char b[4];
00066 
00067   last.getLocalTime();
00068   while(eib->running)
00069   {
00070     if(eib->isConnected() == 0)
00071     {
00072       eib->connect();
00073       expected_recseq = 0;
00074       last.getLocalTime();
00075     }
00076     ret = eib->recv(&pdu, sizeof(pdu));
00077     now.getLocalTime();
00078     if(ret > 0)
00079     {
00080       switch (ntohs(pdu.servicetype))
00081       {
00082         case DISCONNECT_REQUEST:
00083           eib->disconnect();
00084           expected_recseq = 0;
00085           break;
00086         case CONNECTIONSTATE_RESPONSE:
00087           if(eib->debug) ::printf("eib_reader() CONNECTIONSTATE_RESPONSE\n");
00088           break;
00089         case TUNNELLING_REQUEST:
00090           if(eib->debug)
00091             ::printf("eib_reader() TUNNELING_REQUEST sequenzecounter=%d\n",recseq);
00092           recseq = pdu.data[2];                 // sequencecounter
00093           b[0]   = pdu.data[0];                 // remember 4 bytes of data
00094           b[1]   = pdu.data[1];
00095           b[2]   = pdu.data[2];
00096           b[3]   = pdu.data[3];
00097           len    = ntohs(pdu.totalsize) - 6;    // remember len (-headerlength)
00098           pdu.headersize  = EIB_HEADERSIZE;     // fill acknowledge
00099           pdu.version     = EIB_VERSION;
00100           pdu.servicetype = htons(TUNNELLING_ACK);
00101           pdu.totalsize   = htons(EIB_HEADERSIZE+4);
00102           pdu.data[0]     = 4;                  // structlength
00103           pdu.data[1]     = eib->channelid;     // channelid
00104           pdu.data[2]     = recseq;             // sequencecounter
00105           pdu.data[3]     = E_NO_ERROR;         // typespecific
00106           if(recseq != expected_recseq)
00107           {
00108             if(eib->debug)
00109               ::printf("eib_reader() recseq=%d expected_recseq=%d\n",recseq,expected_recseq);
00110             // we simply ignore the sequencecounter
00111             // pdu.data[4] = E_SEQUENCE_NUMBER;
00112           }
00113           expected_recseq = (expected_recseq+1) & 0x0ff;
00114           eib->rlUdpSocket::sendto(&pdu, ntohs(pdu.totalsize), eib->server);
00115           pdu.data[0] = b[0];                   // restore received data
00116           pdu.data[1] = b[1];
00117           pdu.data[2] = b[2];
00118           pdu.data[3] = b[3];
00119           eib->storeBuffer(&pdu.data[4],len-4); // +EIBNETIP_COMMON_CONNECTION_HEADER
00120           break;
00121         case TUNNELLING_ACK:
00122           if(pdu.data[3] == E_NO_ERROR)
00123           {
00124             eib->tunnel_ack = 1;
00125             if(eib->debug) ::printf("eib_reader() TUNNELLING_ACK typespecific=0x%x\n",pdu.data[3]);
00126           }
00127           else
00128           {
00129             eib->tunnel_ack = -1;
00130             if(eib->debug) ::printf("eib_reader() TUNNELLING_NACK typespecific=0x%x\n",pdu.data[3]);
00131           }
00132           break;
00133         default:
00134           ::printf("eib_reader() unknown servicetype=0x%x\n",ntohs(pdu.servicetype));
00135           break;
00136       }
00137     }
00138     diff = now - last;
00139     if(eib->isConnected() && eib->channelid != -1 && diff.second > 50)
00140     { // send heartbeat
00141       if(eib->debug) ::printf("send heartbeat\n");
00142       pdu.headersize  = EIB_HEADERSIZE;
00143       pdu.version     = EIB_VERSION;
00144       pdu.servicetype = htons(CONNECTIONSTATE_REQUEST);
00145       pdu.totalsize   = htons(EIB_HEADERSIZE+EIB_ADRSIZE*2+EIB_CRICRDSIZE);
00146       pdu.data[0]     = eib->channelid;
00147       pdu.data[1]     = 0;
00148       eib->rlUdpSocket::sendto(&pdu, ntohs(pdu.totalsize), eib->server);
00149       last.getLocalTime();
00150     }
00151   }
00152   return NULL;
00153   /*
00154   for(int i=0; i<50; i++)
00155   {
00156     p->thread->lock();
00157     //do something critical
00158     printf("this is the thread\n");
00159     p->thread->unlock();
00160   }
00161   */
00162 }
00163 
00164 rlEIBnetIP::rlEIBnetIP(int num_signals, int _debug, rlDataAcquisitionProvider *_provider) : rlUdpSocket(_debug)
00165 {
00166   debug = _debug;
00167   provider = _provider;
00168   watch_eib = 0;
00169   if(debug) ::printf("rlEIBnetIP() constructor\n");
00170   char *cptr;
00171   mem = NULL;
00172   memsize = 0;
00173   running = 0;
00174   maxvalues = 0;
00175   is_connected = 0;
00176   channelid = -1;
00177   server = NULL;
00178   send_sequencecounter = 0;
00179   //rlUdpSocket::setSockopt(SO_BROADCAST);
00180   rlUdpSocket::bind(rlEIBnetIP::PORT);
00181   if(num_signals <= 0) return;
00182   memsize = sizeof(EIB_TEL)*num_signals;
00183   maxvalues = num_signals;
00184   cptr = new char[memsize];
00185   memset(cptr,0,memsize);
00186   mem = cptr;
00187   setSourceAdr("/0/0/001");
00188 }
00189 
00190 rlEIBnetIP::~rlEIBnetIP()
00191 {
00192   if(running) stopReading();
00193   if(mem != NULL)
00194   {
00195     char *cptr = (char *) mem;
00196     delete [] cptr;
00197   }
00198   sendDisconnectRequest();
00199 }
00200 
00201 int rlEIBnetIP::storeBuffer(unsigned char *buf, int len)
00202 {
00203   EIB_TEL tel;
00204   short unsigned int *sptr;
00205   int i;
00206 
00207   if(len <= 0 || mem == NULL) return -1;
00208   if(debug)
00209   {
00210     ::printf("rlEIBnetIP::storeBuffer() buf=[0x%x",buf[0]);
00211     for(i=1; i<len; i++) ::printf(",0x%x",buf[i]);
00212     ::printf("]\n");
00213   }
00214 
00215   tel.mc = buf[0];
00216   tel.addi1       = buf[1];
00217   tel.ctrl1       = buf[2];
00218   tel.ctrl2       = buf[3];
00219   sptr            = (unsigned short *) &buf[4];
00220   tel.saddr       = ntohs(*sptr);
00221   sptr            = (unsigned short *) &buf[6];
00222   tel.daddr       = ntohs(*sptr);
00223   tel.apci_length = buf[8];
00224   tel.apci        = buf[9];
00225   tel.val[0] = buf[10];
00226   tel.val[1] = buf[10+1];
00227   tel.val[2] = buf[10+2];
00228   tel.val[3] = buf[10+3];
00229   for(i=0; i<(len-10); i++) tel.val[i] = buf[10+i];
00230   switch (tel.mc)
00231   {
00232     case L_Data_Req: //0x11:
00233       ::printf("rlEIBnetIP::storeBuffer() messagecode=0x%x L_Data_Req\n",tel.mc);
00234       break;
00235     case L_Data_Ind: //0x29:
00236       break;
00237     case L_Data_Con: //0x2E:
00238       break;
00239     default:
00240       ::printf("rlEIBnetIP::storeBuffer() unknown messagecode=0x%x L_Data_Con\n",tel.mc);
00241       return -1;
00242   }
00243   if(debug)
00244   {
00245     ::printf("\nmc=0x%x addi1=0x%x ctrl1=0x%x ctrl2=0x%x saddr=0x%x daddr=0x%x acpi_length=0x%x apci=0x%x",
00246     tel.mc,
00247     tel.addi1,
00248     tel.ctrl1,
00249     tel.ctrl2,
00250     tel.saddr,
00251     tel.daddr,
00252     tel.apci_length,
00253     tel.apci);
00254     for(i=10; i<len; i++) ::printf(" val[%d]=0x%x",i-10,tel.val[i-10]);
00255     ::printf("\n");
00256   }
00257 
00258   if(watch_eib) printTelegram(&tel);
00259   if(provider != NULL) return storeInProvider(&tel);
00260 
00261   // store EIB_TEL in *mem
00262   EIB_TEL *memptr = (EIB_TEL *) mem;
00263   for(i=0; i<maxvalues; i++)
00264   {
00265     if(memptr[i].mc == 0)
00266     {
00267       //if(debug) ::printf("rlEIBnetIP::storeBuffer() insert new value\n");
00268       thread.lock();
00269       memcpy(&memptr[i],&tel,sizeof(tel));
00270       thread.unlock();
00271       return 0;
00272     }
00273     //else if(memptr[i].saddr == tel.saddr && memptr[i].daddr == tel.daddr)
00274     else if(memptr[i].daddr == tel.daddr)
00275     {
00276       //if(debug) ::printf("rlEIBnetIP::storeBuffer() update existing value\n");
00277       thread.lock();
00278       memcpy(&memptr[i],&tel,sizeof(tel));
00279       thread.unlock();
00280       return 0;
00281     }
00282   }
00283   ::printf("rlEIBnetIP::storeBuffer() maxvalues=%d too small\n",maxvalues);
00284   return -1;
00285 }
00286 
00287 int rlEIBnetIP::printTelegram(EIB_TEL *tel)
00288 {
00289   int s1,s2,s3,d1,d2,d3,val,length;
00290 
00291   s1 = tel->saddr/(8*256);
00292   s2 = (tel->saddr/256) & 0x0ff;
00293   s3 = tel->saddr & 0x0ff;
00294   d1 = tel->daddr/(8*256);
00295   d2 = (tel->daddr/256) & 0x0ff;
00296   d3 = tel->daddr & 0x0ff;
00297   length = tel->apci_length;
00298   val = 0;
00299   if(length == 1)
00300   {
00301     val = tel->val[0];
00302   }
00303   else if(length == 2)
00304   {
00305     char *cptr = (char *) &tel->val[0];
00306     val = (((*cptr)*256)+tel->val[1]);
00307   }
00308   else if(length == 3)
00309   {
00310     char *cptr = (char *) &tel->val[0];
00311     val = (((*cptr)*256)+tel->val[1])*tel->val[2];
00312   }
00313   else if(length == 4)
00314   {
00315     char *cptr = (char *) &tel->val[0];
00316     val = ((((*cptr)*256)+tel->val[1])*(tel->val[2]*256) * tel->val[3]);
00317   }
00318   ::printf("src=/%d/%d/%03d\tdest=/%d/%d/%03d\tval=0x%x\tlen=%d\n",s1,s2,s3,d1,d2,d3,val,length);
00319   return 0;
00320 }
00321 
00322 int rlEIBnetIP::storeInProvider(EIB_TEL *tel)
00323 {
00324   if(provider == NULL || tel == NULL) return -1;
00325   int s1,s2,s3,d1,d2,d3,val,length;
00326   char name[128], value[128];
00327 
00328   s1 = tel->saddr/(8*256);
00329   s2 = (tel->saddr/256) & 0x0ff;
00330   s3 = tel->saddr & 0x0ff;
00331   d1 = tel->daddr/(8*256);
00332   d2 = (tel->daddr/256) & 0x0ff;
00333   d3 = tel->daddr & 0x0ff;
00334   length = tel->apci_length;
00335   val = 0;
00336   if(length == 1)
00337   {
00338     val = tel->val[0];
00339   }
00340   else if(length == 2)
00341   {
00342     char *cptr = (char *) &tel->val[0];
00343     val = (((*cptr)*256)+tel->val[1]);
00344   }
00345   else if(length == 3)
00346   {
00347     char *cptr = (char *) &tel->val[0];
00348     val = (((*cptr)*256)+tel->val[1])*tel->val[2];
00349   }
00350   else if(length == 4)
00351   {
00352     char *cptr = (char *) &tel->val[0];
00353     val = ((((*cptr)*256)+tel->val[1])*(tel->val[2]*256) * tel->val[3]);
00354   }
00355   //::printf("/%d/%d/%d\t/%d/%d/%d\t0x%x\t%d\n",s1,s2,s3,d1,d2,d3,val,length);
00356   sprintf(name,"/%d/%d/%03d",d1,d2,d3);
00357   sprintf(value,"%d",val);
00358   if(debug) ::printf("storeInProvicer: name=%s value=%s", name, value);
00359   provider->setStringValue(name, value);
00360   return 0;
00361 }
00362 
00363 int rlEIBnetIP::dump(FILE *fout)
00364 {
00365   if(fout == NULL) return -1;
00366   if(debug) ::printf("rlEIBnetIP::dump()\n");
00367   int s1,s2,s3,d1,d2,d3,val,length;
00368   int i = 0;
00369   EIB_TEL *tel;
00370   EIB_TEL *memptr = (EIB_TEL *) mem;
00371 
00372   val = 0;
00373   thread.lock();
00374   while(1)
00375   {
00376     tel = &memptr[i];
00377     if(tel->mc == 0)   break;
00378     if(i >= maxvalues) break;
00379     s1 = tel->saddr/(8*256);
00380     s2 = (tel->saddr/256) & 0x0ff;
00381     s3 = tel->saddr & 0x0ff;
00382     d1 = tel->daddr/(8*256);
00383     d2 = (tel->daddr/256) & 0x0ff;
00384     d3 = tel->daddr & 0x0ff;
00385     length = tel->apci_length;
00386     if(length == 1)
00387     {
00388       val = tel->val[0];
00389     }
00390     else if(length == 2)
00391     {
00392       char *cptr = (char *) &tel->val[0];
00393       val = (((*cptr)*256)+tel->val[1]);
00394     }
00395     else if(length == 3)
00396     {
00397       char *cptr = (char *) &tel->val[0];
00398       val = (((*cptr)*256)+tel->val[1])*tel->val[2];
00399     }
00400     else if(length == 4)
00401     {
00402       char *cptr = (char *) &tel->val[0];
00403       val = ((((*cptr)*256)+tel->val[1])*(tel->val[2]*256) * tel->val[3]);
00404     }
00405     fprintf(fout,"/%d/%d/%d\t/%d/%d/%d\t0x%x\t%d\n",s1,s2,s3,d1,d2,d3,val,length);
00406     i++;
00407   }
00408   thread.unlock();
00409   return i;
00410 }
00411 
00412 int rlEIBnetIP::setValuesFromCSV(const char *filename)
00413 {
00414   FILE *fin;
00415   char line[1024], *cptr;
00416   int  s1,s2,s3,d1,d2,d3,i,val,len;
00417   unsigned int uval;
00418 
00419   if(filename == NULL) return -1;
00420   fin = fopen(filename,"r");
00421   if(fin == NULL)
00422   {
00423     ::printf("rlEIBnetIP::setValuesFromCSV(%s) could not open file\n",filename);
00424     return -1;
00425   }
00426 
00427   while(fgets(line,sizeof(line)-1,fin) != NULL)
00428   {
00429     d1 = d2 = d3 = 0;
00430     cptr = strchr(line,'/');
00431     if(cptr == NULL) break;
00432     sscanf(cptr,"/%d/%d/%d",&s1,&s2,&s3);
00433     i = 0;
00434     while(line[i] != '\0')
00435     {
00436       if(line[i] == ' ' || line[i] == '\t')
00437       {
00438         while(line[i] == ' ' || line[i] == '\t') i++;
00439         if(line[i] == '/')
00440         {
00441           cptr = strstr(&line[i],"0x");
00442           if(cptr == NULL)
00443           {
00444             sscanf(&line[i],"/%d/%d/%d %d %d",&d1,&d2,&d3,&val,&len);
00445           }
00446           else
00447           {
00448             sscanf(&line[i],"/%d/%d/%d %x %d",&d1,&d2,&d3,&val,&len);
00449           }
00450         }
00451         break;
00452       }
00453       i++;
00454     }
00455     if(line[i] == '\0') return rlEIBnetIP::EIBERROR;
00456     cptr = strchr(line,'/');
00457     if(cptr != NULL)
00458     {
00459       sprintf(line,"/%d/%d/%d",d1,d2,d3);
00460       for(i=0; i<100; i++) // try setting even if hardware responds very slowly
00461       {
00462         memcpy(&uval,&val,sizeof(uval));
00463         uval = setValueUnsigned(line,uval,len);
00464         if(uval != rlEIBnetIP::EIBERROR) break;
00465       }
00466     }
00467   }
00468 
00469   fclose(fin);
00470   return 0;
00471 }
00472 
00473 int rlEIBnetIP::connect()
00474 {
00475   if(server == NULL) return rlEIBnetIP::EIBERROR;
00476   if(debug) ::printf("rlEIBnetIP()::connect()\n");
00477   PDU pdu,response;
00478   unsigned char cricrd[EIB_CRICRDSIZE];
00479   int ret = 0;
00480 
00481   if(is_connected == 1)
00482   {
00483     ::printf("rlEIBnetIP::connect() already connected\n");
00484     return 1;
00485   }
00486 
00487   channelid = -1;
00488   memset(&response,0,sizeof(response));
00489   pdu.headersize  = EIB_HEADERSIZE;
00490   pdu.version     = EIB_VERSION;
00491   pdu.servicetype = htons(CONNECT_REQUEST);
00492   pdu.totalsize   = htons(EIB_HEADERSIZE+EIB_ADRSIZE*2+EIB_CRICRDSIZE);
00493   memcpy(&pdu.data[0],&client.address,EIB_ADRSIZE);
00494   memcpy(&pdu.data[8],&client.address,EIB_ADRSIZE);
00495   cricrd[0] = EIB_CRICRDSIZE;    // structlength
00496   cricrd[1] = TUNNEL_CONNECTION; // connectiontypecode
00497   cricrd[2] = TUNNEL_LINKLAYER;  // data1
00498   cricrd[3] = 0;                 // data2
00499   memcpy(&pdu.data[8*2],cricrd,EIB_CRICRDSIZE);
00500   is_connected = 0;
00501 
00502   rlUdpSocket::sendto(&pdu, ntohs(pdu.totalsize), server);
00503   ret = recv(&response, sizeof(PDU));
00504 
00505   if(ntohs(response.servicetype) == CONNECT_RESPONSE)
00506   {
00507     if(debug)
00508     {
00509       ::printf("response.headersize  = 0x%x\n",response.headersize);
00510       ::printf("response.version     = 0x%x\n",response.version);
00511       ::printf("response.servicetype = 0x%x\n",ntohs(response.servicetype));
00512       ::printf("response.totalsize   = 0x%x\n",ntohs(response.totalsize));
00513       ::printf("response.channelid   = 0x%x\n",response.data[0]);
00514       ::printf("response.status      = 0x%x\n",response.data[1]);
00515     }
00516     if(response.data[1] == E_NO_ERROR)
00517     {
00518       channelid = response.data[0];
00519       if(debug) ::printf("CONNECT_RESPONSE == success\n");
00520       is_connected = 1;
00521       send_sequencecounter = 0;
00522       return 1;
00523     }
00524     ::printf("response == CONNECT_RESPONSE status=0x%x failed\n",response.data[1]);
00525     return -1; //
00526   }
00527   else
00528   {
00529     ::printf("response != CONNECT_RESPONSE\n");
00530     return -1;
00531   }
00532 }
00533 
00534 int rlEIBnetIP::disconnect()
00535 {
00536   if(server == NULL) return rlEIBnetIP::EIBERROR;
00537   if(debug) ::printf("rlEIBnetIP()::disconnect()\n");
00538   PDU pdu;
00539 
00540   pdu.headersize  = EIB_HEADERSIZE;
00541   pdu.version     = EIB_VERSION;
00542   pdu.servicetype = htons(DISCONNECT_RESPONSE);
00543   pdu.totalsize   = htons(EIB_HEADERSIZE+2+EIB_ADRSIZE);
00544   pdu.data[0]     = channelid; // channelid
00545   pdu.data[1]     = 0;         // reserved
00546   memcpy(&pdu.data[2],&client.address,EIB_ADRSIZE);
00547   rlUdpSocket::sendto(&pdu, ntohs(pdu.totalsize), server);
00548   is_connected = 0;
00549   channelid = -1;
00550   return rlEIBnetIP::SUCCESS;
00551 }
00552 
00553 int rlEIBnetIP::sendDisconnectRequest()
00554 {
00555   if(debug) ::printf("rlEIBnetIP()::sendDisconnectRequest()\n");
00556   if(is_connected == 0) return -1;
00557   PDU pdu;
00558 
00559   pdu.headersize  = EIB_HEADERSIZE;
00560   pdu.version     = EIB_VERSION;
00561   pdu.servicetype = htons(DISCONNECT_REQUEST);
00562   pdu.totalsize   = htons(EIB_HEADERSIZE+2+EIB_ADRSIZE);
00563   pdu.data[0]     = channelid; // channelid
00564   pdu.data[1]     = 0;         // reserved
00565   memcpy(&pdu.data[2],&client.address,EIB_ADRSIZE);
00566   rlUdpSocket::sendto(&pdu, ntohs(pdu.totalsize), server);
00567   is_connected = 0;
00568   channelid = -1;
00569   return rlEIBnetIP::SUCCESS;
00570 }
00571 
00572 int rlEIBnetIP::isConnected()
00573 {
00574   return is_connected;
00575 }
00576 
00577 int rlEIBnetIP::startReading()
00578 {
00579   running = 1;
00580   is_connected = 0;
00581   channelid = -1;
00582   thread.create(eib_reader,this);
00583   return rlEIBnetIP::SUCCESS;
00584 }
00585 
00586 int rlEIBnetIP::stopReading()
00587 {
00588   running = 0;
00589   is_connected = 0;
00590   channelid = -1;
00591   thread.cancel();
00592   return rlEIBnetIP::SUCCESS;
00593 }
00594 
00595 int rlEIBnetIP::setSourceAdr(const char *adr)
00596 {
00597   const char *cptr;
00598   int a1,a2,a3;
00599 
00600   // interpret name
00601   cptr = strchr(adr,'/');
00602   if(cptr == NULL)
00603   {
00604     ::printf("USER_ERROR: rlEIBnetIP::setSourceAdr() wrong adr=%s\n", adr);
00605     return -1;
00606   }
00607   sscanf(cptr,"/%d/%d/%d",&a1,&a2,&a3);
00608   saddr = ((a1*8)+a2)*256+a3;
00609   return 0;
00610 }
00611 
00612 int rlEIBnetIP::setValue(const char *name, int val, int length, int addi1, int ctrl, int apci)
00613 {
00614   unsigned int uval;
00615   memcpy(&uval,&val,sizeof(uval));
00616   return setValueUnsigned(name, uval, length, addi1, ctrl, apci);
00617 }
00618 
00619 int rlEIBnetIP::value(const char *name)
00620 {
00621   int val;
00622   unsigned int uval;
00623   uval = valueUnsigned(name);
00624   memcpy(&val,&uval,sizeof(val));
00625   return val;
00626 }
00627 
00628 int rlEIBnetIP::setValueFloat(const char *name, float val, int length, int addi1, int ctrl, int apci)
00629 {
00630   unsigned int uval,s,e,m;
00631   float fval,eval;
00632   if(length == -1 || length == 2)
00633   {
00634     length = 2;
00635     if(val < 0.0f) s = 0x80000000;
00636     else           s = 0;
00637     m = (unsigned int) (val*100.0f);
00638     m = m/100;
00639     // m*2^e = fabsf(val)
00640     // 2^e = fabsf(val)/m;
00641     //   e = ln(fabsf(val)/m)
00642     if(m == 0) e = 0;
00643     else
00644     {
00645       fval = fabsf(val)/(float) m;
00646       eval = logf(fval);
00647       e = ((unsigned int) eval) * 8* 256;
00648     }
00649     uval = s | e | m;
00650   }
00651   else if(length == 4)
00652   {
00653     memcpy(&uval,&val,sizeof(uval));
00654   }
00655   else
00656   {
00657     return rlEIBnetIP::EIBERROR;
00658   }
00659   return setValueUnsigned(name, uval, length, addi1, ctrl, apci);
00660 }
00661 
00662 float rlEIBnetIP::valueFloat2(const char *name)
00663 {
00664   float val,sign;
00665   unsigned int uval,e,m;
00666   uval = valueUnsigned(name);
00667   if(uval & 0x080000000) sign = 1.0f;
00668   else                   sign = -1.0f;
00669   uval = uval | 0x07fffffff; // eliminate sign
00670   m = uval & 0x07ffff;
00671   e = uval / (8*256);
00672   val = sign*(0.01f*m)*(2^e);
00673   return val;
00674 }
00675 
00676 float rlEIBnetIP::valueFloat4(const char *name)
00677 {
00678   float val;
00679   unsigned int uval;
00680   uval = valueUnsigned(name);
00681   memcpy(&val,&uval,sizeof(float));
00682   return val;
00683 }
00684 
00685 unsigned int rlEIBnetIP::valueUnsigned(const char *name)
00686 {
00687   if(name == NULL || mem == NULL) return rlEIBnetIP::EIBERROR;
00688   unsigned int val,a1,a2,a3,length;
00689   const char *cptr;
00690   EIB_TEL tel;
00691   EIB_TEL *memptr = (EIB_TEL *) mem;
00692 
00693   // interpret name
00694   memset(&tel,0xff,sizeof(EIB_TEL));
00695   cptr = strchr(name,'/');
00696   if(cptr == NULL)
00697   {
00698     ::printf("USER_ERROR: rlEIBnetIP::value() wrong name=%s\n", name);
00699     return rlEIBnetIP::EIBERROR;
00700   }
00701   sscanf(cptr,"/%d/%d/%d",&a1,&a2,&a3);
00702   tel.saddr = (short) saddr;
00703   tel.daddr = ((a1*8)+a2)*256+a3;
00704 
00705   for(int i=0; i<maxvalues; i++)
00706   {
00707     if(memptr[i].mc == 0) break;
00708     //if(memptr[i].saddr == tel.saddr && memptr[i].daddr == tel.daddr)
00709     if(memptr[i].daddr == tel.daddr)
00710     {
00711       thread.lock();
00712       val = 0;
00713       length = memptr[i].apci_length;
00714       if(length == 1)
00715       {
00716         val = memptr[i].val[0];
00717       }
00718       else if(length == 2)
00719       {
00720         char *cptr = (char *) &memptr[i].val[0];
00721         val = (((*cptr)*256)+memptr[i].val[1]);
00722       }
00723       else if(length == 3)
00724       {
00725         char *cptr = (char *) &memptr[i].val[0];
00726         val = (((*cptr)*256)+memptr[i].val[1])*memptr[i].val[2];
00727       }
00728       else if(length == 4)
00729       {
00730         char *cptr = (char *) &memptr[i].val[0];
00731         val = ((((*cptr)*256)+memptr[i].val[1])*(memptr[i].val[2]*256) * memptr[i].val[3]);
00732       }
00733       thread.unlock();
00734       if(length < 1 || length > 4 || length == 3)
00735       {
00736         ::printf("rlEIBnetIP::value(0x%x) unknown length=%d\n",val,length);
00737         return rlEIBnetIP::EIBERROR;
00738       }
00739       return val;
00740     }
00741   }
00742   return rlEIBnetIP::EIBERROR;
00743 }
00744 
00745 int rlEIBnetIP::getText(const char *name, char *text, int maxlen)
00746 {
00747   if(name == NULL || text == NULL || maxlen <= 0) return rlEIBnetIP::EIBERROR;
00748   unsigned int a1,a2,a3,length;
00749   int j;
00750   const char *cptr;
00751   char buf[16];
00752   EIB_TEL tel;
00753   EIB_TEL *memptr = (EIB_TEL *) mem;
00754 
00755   text[0] = '\0';
00756   // interpret name
00757   memset(&tel,0xff,sizeof(EIB_TEL));
00758   cptr = strchr(name,'/');
00759   if(cptr == NULL)
00760   {
00761     ::printf("USER_ERROR: rlEIBnetIP::getText() wrong name=%s\n", name);
00762     return rlEIBnetIP::EIBERROR;
00763   }
00764   sscanf(cptr,"/%d/%d/%d",&a1,&a2,&a3);
00765   tel.saddr = (short) saddr;
00766   tel.daddr = ((a1*8)+a2)*256+a3;
00767 
00768   for(int i=0; i<maxvalues; i++)
00769   {
00770     if(memptr[i].mc == 0) break;
00771     //if(memptr[i].saddr == tel.saddr && memptr[i].daddr == tel.daddr)
00772     if(memptr[i].daddr == tel.daddr)
00773     {
00774       thread.lock();
00775       length = memptr[i].apci_length;
00776       for(j=0; j<14; j++) buf[j] = memptr[i].val[j];
00777       buf[14] = '\0';
00778       j = 0;
00779       while(j<maxlen && j<14)
00780       {
00781         text[j] = buf[j];
00782         j++;
00783       }
00784       return j;
00785     }
00786   }
00787   return 0;
00788 }
00789 
00790 int rlEIBnetIP::setText(const char *name, const char *text)
00791 {
00792   if(name == NULL || text == NULL) return rlEIBnetIP::EIBERROR; 
00793   char buf[16];
00794   int length = strlen(text);
00795   unsigned int a1,a2,a3,daddr;
00796   int i,retry;
00797   const char *cptr;
00798   PDU pdu;
00799   EIB_TEL tel;
00800   EIB_TEL *memptr = (EIB_TEL *) mem;
00801 
00802   if(length > 14) length = 14;
00803   memset(buf,0,sizeof(buf));
00804   for(i=0; i<length; i++) buf[i] = text[i];
00805 
00806   // interpret name
00807   cptr = strchr(name,'/');
00808   if(cptr == NULL)
00809   {
00810     ::printf("USER_ERROR: rlEIBnetIP::setText() wrong name=%s text=%s\n", name, text);
00811     return rlEIBnetIP::EIBERROR;
00812   }
00813   sscanf(cptr,"/%d/%d/%d",&a1,&a2,&a3);
00814   daddr = ((a1*8)+a2)*256+a3;
00815 
00816   // fill EIBnet/IP PDU
00817   pdu.headersize   = EIB_HEADERSIZE;
00818   pdu.version      = EIB_VERSION;
00819   pdu.servicetype  = htons(TUNNELLING_REQUEST);
00820   pdu.totalsize    = htons(EIB_HEADERSIZE+4+10+length);
00821   pdu.data[0]      = 4;                    // structlength
00822   pdu.data[1]      = channelid;            // channelid
00823   pdu.data[2]      = send_sequencecounter; // sequencecounter
00824   pdu.data[3]      = E_NO_ERROR;           // typespecific
00825   tel.mc           = L_Data_Req; // L_Data_Req=0x11, L_Data_Con=0x2E L_Data_Ind=0x29
00826   tel.addi1        = 0x0;
00827   tel.ctrl1        = 0xbc;
00828   tel.ctrl2        = 0xe0;
00829   tel.saddr        = (unsigned short) htons((short) saddr);   //0x1);
00830   tel.daddr        = (unsigned short) htons((short) daddr);   //(0x100)
00831   tel.apci_length  = 0x1;
00832   tel.apci         = 0x0;
00833   for(i=0; i<14; i++) tel.val[i] = buf[i];
00834   memcpy(&pdu.data[4],&tel,sizeof(EIB_TEL));
00835 
00836   tunnel_ack = retry = 0;
00837   while(1)
00838   {
00839     // send value over EIBnet/IP
00840     rlUdpSocket::sendto(&pdu, ntohs(pdu.totalsize), server);
00841     rlsleep(10);
00842     if     (tunnel_ack == 1) // OK
00843     {
00844       send_sequencecounter = (send_sequencecounter+1) & 0x0ff;
00845       if(debug) ::printf("rlEIBnetIP::setText(%s) ACK\n",text);
00846       break;
00847     }
00848     else if(tunnel_ack == -1) // failure
00849     {
00850       if(debug) ::printf("rlEIBnetIP::setText(%s) NACK\n",text);
00851       retry++;
00852     }
00853     else
00854     {
00855       if(debug) ::printf("rlEIBnetIP::setText(%s) timeout\n",text);
00856       retry++;
00857     }
00858     if(retry >= 2)
00859     {
00860       is_connected = 0 ;
00861       ::printf("rlEIBnetIP::setText() connection lost\n");
00862       return rlEIBnetIP::EIBERROR;
00863     }
00864   }
00865   tunnel_ack = 0;
00866 
00867   tel.saddr = ntohs(tel.saddr); // convert network -> host byte order
00868   tel.daddr = ntohs(tel.daddr);
00869   // remember value within mem
00870   for(i=0; i< maxvalues; i++)
00871   {
00872     if(memptr[i].mc == 0)
00873     {
00874       if(debug) ::printf("rlEIBnetIP::setText() insert new value\n");
00875       thread.lock();
00876       memcpy(&memptr[i],&tel,sizeof(tel));
00877       thread.unlock();
00878       return length;
00879     }
00880     //else if(memptr[i].saddr == tel.saddr && memptr[i].daddr == tel.daddr)
00881     else if(memptr[i].daddr == tel.daddr)
00882     {
00883       if(debug) ::printf("rlEIBnetIP::setText() update existing value\n");
00884       thread.lock();
00885       memcpy(&memptr[i],&tel,sizeof(tel));
00886       thread.unlock();
00887       return length;
00888     }
00889   }
00890   ::printf("ERROR rlEIBnetIP::setText() not enough signals specified max=%d\n",maxvalues);
00891   return rlEIBnetIP::EIBERROR;
00892 }
00893 
00894 int rlEIBnetIP::setValueUnsigned(const char *name, unsigned int val, int length, int addi1, int ctrl, int apci)
00895 {
00896   if(name == NULL || mem == NULL || channelid == -1) return rlEIBnetIP::EIBERROR;
00897   unsigned int i,a1,a2,a3,daddr;
00898   int retry;
00899   const char *cptr;
00900   PDU pdu;
00901   EIB_TEL tel;
00902   EIB_TEL *memptr = (EIB_TEL *) mem;
00903 
00904   // interpret name
00905   cptr = strchr(name,'/');
00906   if(cptr == NULL)
00907   {
00908     ::printf("USER_ERROR: rlEIBnetIP::setValue() wrong name=%s val=%d\n", name, val);
00909     return rlEIBnetIP::EIBERROR;
00910   }
00911   sscanf(cptr,"/%d/%d/%d",&a1,&a2,&a3);
00912   daddr = ((a1*8)+a2)*256+a3;
00913 
00914   // fill EIBnet/IP PDU
00915   pdu.headersize   = EIB_HEADERSIZE;
00916   pdu.version      = EIB_VERSION;
00917   pdu.servicetype  = htons(TUNNELLING_REQUEST);
00918   if(length == -1)
00919     pdu.totalsize    = htons(EIB_HEADERSIZE+4+10+1);
00920   else
00921     pdu.totalsize    = htons(EIB_HEADERSIZE+4+10+length);
00922   pdu.data[0]      = 4;                    // structlength
00923   pdu.data[1]      = channelid;            // channelid
00924   pdu.data[2]      = send_sequencecounter; // sequencecounter
00925   pdu.data[3]      = E_NO_ERROR;           // typespecific
00926   tel.mc           = L_Data_Req; // L_Data_Req=0x11, L_Data_Con=0x2E L_Data_Ind=0x29
00927 
00928   tel.addi1        = 0x0;
00929   tel.ctrl1        = 0xbc;
00930   tel.ctrl2        = 0xe0;
00931   tel.saddr        = (unsigned short) htons((short) saddr);   //0x1);
00932   tel.daddr        = (unsigned short) htons((short) daddr);   //(0x100)
00933   tel.apci_length  = 0x1;
00934   tel.apci         = 0x0;
00935 
00936   if(addi1  != -1) tel.addi1 = (unsigned char) ((addi1 & 0x0ff));
00937   if(ctrl   != -1)
00938   {
00939     tel.ctrl1 = (unsigned char) ((ctrl & 0x0ff00)/256);
00940     tel.ctrl2 = (unsigned char) ((ctrl & 0x0ff));
00941   }
00942   if(length != -1) tel.apci_length = (unsigned char) length;
00943   if(apci   != -1) tel.apci = (unsigned char) apci;
00944 
00945   if(length == -1 || length == 1)
00946   {
00947     tel.val[0]       = (unsigned char) val; // 0x80; // 0x81
00948     tel.val[1]       = (unsigned char) 0x0;
00949     tel.val[2]       = (unsigned char) 0x0;
00950     tel.val[3]       = (unsigned char) 0x0;
00951   }
00952   else if(length == 2)
00953   {
00954     tel.val[0]       = (unsigned char) ((val & 0x0ff00)/256);
00955     tel.val[1]       = (unsigned char) (val & 0x0ff);
00956     tel.val[2]       = (unsigned char) 0x0;
00957     tel.val[3]       = (unsigned char) 0x0;
00958   }
00959   else if(length == 3)
00960   {
00961     tel.val[0]       = (unsigned char) ((val & 0x0ff000000)/(256*256));
00962     tel.val[1]       = (unsigned char)  (val & 0x0ff0000)/256;
00963     tel.val[2]       = (unsigned char)  (val & 0x0ff00);
00964     tel.val[3]       = (unsigned char)  (val & 0x0ff);
00965   }
00966   else if(length == 4)
00967   {
00968     tel.val[0]       = (unsigned char) ((val & 0x0ff000000)/(256*256*256));
00969     tel.val[1]       = (unsigned char) ((val & 0x0ff0000)/(256*256));
00970     tel.val[2]       = (unsigned char) ((val & 0x0ff00)/(256));
00971     tel.val[3]       = (unsigned char) (val & 0x0ff);
00972   }
00973   else
00974   {
00975     ::printf("rlEIBnetIP::setValue(0x%x) unknown length=%d\n",val,length);
00976     return rlEIBnetIP::EIBERROR;
00977   }
00978   memcpy(&pdu.data[4],&tel,sizeof(EIB_TEL));
00979 
00980   if(debug)
00981   {
00982     ::printf("rlEIBnetIP::setValue() mc          = 0x%x\n", tel.mc);
00983     ::printf("rlEIBnetIP::setValue() addi1       = 0x%x\n", tel.addi1);
00984     ::printf("rlEIBnetIP::setValue() ctrl1       = 0x%x\n", tel.ctrl1);
00985     ::printf("rlEIBnetIP::setValue() ctrl2       = 0x%x\n", tel.ctrl2);
00986     ::printf("rlEIBnetIP::setValue() saddr       = 0x%x\n", ntohs(tel.saddr));
00987     ::printf("rlEIBnetIP::setValue() daddr       = 0x%x\n", ntohs(tel.daddr));
00988     ::printf("rlEIBnetIP::setValue() apci_length = 0x%x\n", tel.apci_length);
00989     ::printf("rlEIBnetIP::setValue() apci        = 0x%x\n", tel.apci);
00990     ::printf("rlEIBnetIP::setValue() val[0]      = 0x%x\n", tel.val[0]);
00991     ::printf("rlEIBnetIP::setValue() val[1]      = 0x%x\n", tel.val[1]);
00992     ::printf("rlEIBnetIP::setValue() val[2]      = 0x%x\n", tel.val[2]);
00993     ::printf("rlEIBnetIP::setValue() val[3]      = 0x%x\n", tel.val[3]);
00994   }
00995 
00996   tunnel_ack = retry = 0;
00997   while(1)
00998   {
00999     // send value over EIBnet/IP
01000     rlUdpSocket::sendto(&pdu, ntohs(pdu.totalsize), server);
01001     rlsleep(10);
01002     if     (tunnel_ack == 1) // OK
01003     {
01004       send_sequencecounter = (send_sequencecounter+1) & 0x0ff;
01005       if(debug) ::printf("rlEIBnetIP::setValue(0x%x) ACK\n",val);
01006       break;
01007     }
01008     else if(tunnel_ack == -1) // failure
01009     {
01010       if(debug) ::printf("rlEIBnetIP::setValue(0x%x) NACK\n",val);
01011       retry++;
01012     }
01013     else
01014     {
01015       if(debug) ::printf("rlEIBnetIP::setValue(0x%x) timeout\n",val);
01016       retry++;
01017     }
01018     if(retry >= 2)
01019     {
01020       is_connected = 0 ;
01021       ::printf("rlEIBnetIP::setValue() connection lost\n");
01022       return rlEIBnetIP::EIBERROR;
01023     }
01024   }
01025   tunnel_ack = 0;
01026 
01027   tel.saddr = ntohs(tel.saddr); // convert network -> host byte order
01028   tel.daddr = ntohs(tel.daddr);
01029 
01030   if(provider != NULL) return 0;
01031 
01032   // remember value within mem
01033   for(i=0; i< (unsigned int) maxvalues; i++)
01034   {
01035     if(memptr[i].mc == 0)
01036     {
01037       if(debug) ::printf("rlEIBnetIP::setValue(0x%x) insert new value\n",val);
01038       thread.lock();
01039       memcpy(&memptr[i],&tel,sizeof(tel));
01040       thread.unlock();
01041       return 0;
01042     }
01043     //else if(memptr[i].saddr == tel.saddr && memptr[i].daddr == tel.daddr)
01044     else if(memptr[i].daddr == tel.daddr)
01045     {
01046       if(debug) ::printf("rlEIBnetIP::setValue(0x%x) update existing value\n",val);
01047       thread.lock();
01048       memcpy(&memptr[i],&tel,sizeof(tel));
01049       thread.unlock();
01050       return 0;
01051     }
01052   }
01053   ::printf("ERROR rlEIBnetIP::setValue() not enough signals specified max=%d\n",maxvalues);
01054   return rlEIBnetIP::EIBERROR;
01055 }
01056 
01057 int rlEIBnetIP::setServer(rlIpAdr *_server)
01058 {
01059   if(_server == NULL) return rlEIBnetIP::EIBERROR;
01060   server = _server;
01061   PDU pdu;
01062   int ret;
01063 
01064   ret = rlEIBnetIP::getDescription(&pdu);
01065   if(ret > 0)
01066   {
01067     if(debug) ::printf("rlEIBnetIP::setServer() found server\n");
01068     memcpy(&server->address,&from.address,sizeof(server->address));
01069     return 0;
01070   }
01071   else
01072   {
01073     ::printf("rlEIBnetIP::setServer() could not find server\n");
01074     return -1;
01075   }
01076 }
01077 
01078 int rlEIBnetIP::setClient(rlIpAdr *_client)
01079 {
01080   // eib murx
01081   unsigned char murx1[8], murx2[8];
01082   memcpy(murx1,&_client->address,sizeof(murx1));
01083   murx2[0] = murx1[0]; // sin_len
01084   murx2[1] = murx1[1]; // sin_family
01085   murx2[6] = murx1[2]; // sin_port
01086   murx2[7] = murx1[3]; // sin_port
01087   murx2[2] = murx1[4]; // sin_addr
01088   murx2[3] = murx1[5]; // sin_addr
01089   murx2[4] = murx1[6]; // sin_addr
01090   murx2[5] = murx1[7]; // sin_addr
01091   memcpy(&client.address,murx2,sizeof(murx2));
01092   return 0;
01093 }
01094 
01095 int rlEIBnetIP::recv(void *buf, int maxlen)
01096 {
01097   int ret;
01098   while(1)
01099   {
01100     ret = rlUdpSocket::recvfrom(buf, maxlen, &from, 1000);
01101     if(ret < 0)         return ret;
01102     if(*server == from) return ret;
01103   }
01104 }
01105 
01106 int rlEIBnetIP::getDescription(PDU *buf)
01107 {
01108   if(server == NULL) return rlEIBnetIP::EIBERROR;
01109   if(debug) ::printf("rlEIBnetIP()::getDescription()\n");
01110   PDU pdu;
01111   int ret;
01112 
01113   pdu.headersize  = EIB_HEADERSIZE;
01114   pdu.version     = EIB_VERSION;
01115   pdu.servicetype = htons(DESCRIPTION_REQUEST);
01116   pdu.totalsize   = htons(EIB_HEADERSIZE+EIB_ADRSIZE*2);
01117   memcpy(pdu.data,&client.address,EIB_ADRSIZE*2);
01118 
01119   rlUdpSocket::sendto(&pdu, ntohs(pdu.totalsize), server);
01120   while(1)
01121   {
01122     ret = rlUdpSocket::recvfrom(buf, sizeof(pdu), &from, 1000);
01123     if(ret < 0)
01124     {
01125       if(debug) ::printf("rlEIBnetIP()::getDescription() timeout\n");
01126       return ret;
01127     }
01128     if(ntohs(buf->servicetype) == DESCRIPTION_RESPONSE)
01129     {
01130       if(debug) ::printf("rlEIBnetIP()::getDescription() got description\n");
01131       return ret;
01132     }
01133   }
01134 }
01135 
01136 //#define TESTING
01137 #ifdef TESTING
01138 
01139 int main()
01140 {
01141   int ret, val;
01142   rlEIBnetIP eib(1000);
01143   rlIpAdr client;
01144   rlIpAdr server;
01145   char line[1024];
01146 
01147   client.setAdr("nb3lehrig",rlEIBnetIP::PORT);
01148   //server.setAdr("192.168.1.30",rlEIBnetIP::PORT);
01149   server.setAdr("eibnet1",rlEIBnetIP::PORT);
01150   ret = eib.setClient(&client);
01151   if(ret < 0) return -1;
01152   ret = eib.setServer(&server);
01153   if(ret < 0) return -1;
01154   eib.debug = 1;
01155   eib.startReading();
01156 
01157   line[0] = '\0';
01158   while(1)
01159   {
01160     scanf("%s",line);
01161     if(line[0] == 'x') break;
01162     if(line[0] == 'd')
01163     {
01164       eib.dump(stdout);
01165     }
01166     else if(line[0] == 's')
01167     {
01168       eib.setValuesFromCSV("test.csv");
01169     }
01170     else if(line[0] == 't')
01171     {
01172       eib.setText("/0/1/000","test");
01173     }
01174     else
01175     {
01176       sscanf(line,"%x",&val);
01177       eib.setValue("/0/1/000", val);
01178       printf("eib.value(/0/1/000)=0x%x\n",eib.value("/0/1/000"));
01179     }
01180     printf("x=exit d=dump s=set t=text value=\n");
01181   }
01182   return 0;
01183 }
01184 
01185 #endif