Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members

dataset.cc

00001 
00003 
00017 #include <iostream>
00018 #ifdef SOLARIS
00019 #include <stdio.h>
00020 #endif
00021 #include <cstring>
00022 #include <unistd.h>
00023 #include <sys/time.h>
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #include <sys/socket.h>
00027 #include <netinet/tcp.h>
00028 #include <arpa/inet.h>
00029 #include <netdb.h>
00030 #include <fcntl.h>
00031 #include <termios.h>
00032 #include <errno.h>
00033 #include <time.h>
00034 #include <assert.h>
00035 
00036 #include "dataset.h"
00037 #include "error_desc.h"
00038 
00039 using namespace std;
00040 
00041 bool Dataset::debugAll = false;
00042 
00043 // First 8 are for ttyS[0-7], the rest (32) are for network sockets.
00044 Dataset::PortAccessData Dataset::pDat[40];
00045 
00046 // Error descriptions
00047 const char* Dataset::errTable[] = 
00048     {  "None",
00049        "Dataset: timeout",
00050        "Dataset: offline",
00051        "Dataset: write",
00052        "Dataset: read",
00053        "Dataset: NAK rcvd",
00054        "Dataset: nRead",
00055        "Dataset: nWrit",
00056        "Dataset: rd-wr-comp",
00057        "Dataset: port not open",
00058        "Dataset: lost socket",
00059        "Dataset: unknown"
00060     };
00061 
00062 // Warning descriptions 
00063 const char* Dataset::warnTable[] = 
00064     {  "None",
00065        "Dataset: BEL rcvd",
00066        "Dataset: reset" };
00067 
00068 
00069 Dataset::Dataset(const char* id, int port, int baud) : CommsDevice(id),
00070                                                       defaultBus(port), baud(baud),
00071                                                       altBus(-1), currBus(-1)
00072 {
00073     assert(defaultBus >= 0 && defaultBus <= 8); 
00074     if (pDat[defaultBus].open == false) 
00075     {
00076         pDat[defaultBus].fd = openSerial(defaultBus);
00077         pDat[defaultBus].open = pDat[defaultBus].fd > 0;     
00078     }
00079     if (pDat[defaultBus].open == true)
00080         ++pDat[defaultBus].useCount;
00081     if (debug || debugAll)        
00082         cout << "Dataset:" << id << ":constructor: ttyS" << port
00083              << " opened with fd = " << pDat[defaultBus].fd << endl;
00084     currBus = defaultBus;
00085     analogScalingFn = stdAnalogScalingFn;
00086     portType = TTY;
00087     cmdTimeout = LONG_TIMEOUT;
00088     monTimeout = SHORT_TIMEOUT;
00089     debug = false;
00090 }
00091 
00092 Dataset::Dataset(const char* id, int port, int baud, int altPort) : CommsDevice(id),
00093                                                       defaultBus(port), baud(baud),
00094                                                       altBus(altPort), currBus(-1)
00095 {
00096     assert(defaultBus >= 0 && defaultBus <= 8); 
00097     assert(altBus >= 0 && altBus <= 8);
00098     if (pDat[defaultBus].open == false) 
00099     {
00100         pDat[defaultBus].fd = openSerial(defaultBus);
00101         pDat[defaultBus].open = pDat[defaultBus].fd > 0;    
00102     }
00103     if (pDat[defaultBus].open == true) ++pDat[defaultBus].useCount;
00104     if (pDat[altBus].open == false) 
00105     {
00106         pDat[altBus].fd = openSerial(altBus);
00107         pDat[altBus].open = pDat[altBus].fd > 0;   
00108     }
00109     if (pDat[altBus].open == true) ++pDat[altBus].useCount;
00110     if (debug || debugAll)        
00111         cout << "Dataset:" << id << ":constructor: ttyS" << port
00112              << " opened with fd = " << pDat[defaultBus].fd << endl;
00113     currBus = defaultBus;
00114     analogScalingFn = stdAnalogScalingFn;
00115     portType = TTY;
00116     cmdTimeout = LONG_TIMEOUT;
00117     monTimeout = SHORT_TIMEOUT;
00118     debug = false;
00119 }
00120 
00121 Dataset::Dataset(const char* id, char* host, int port) : 
00122                                           CommsDevice(id),
00123                                           defaultBus(-1),
00124                                           altBus(-1), currBus(-1)
00125 {   
00126     // Check if there is already an open socket connection
00127     // to the host's port - if so use it.
00128     for (int i=8; i < 40; ++i)
00129     {
00130         if (pDat[i].open == true && pDat[i].portNum == port)
00131         {
00132             if (strcmp(host, pDat[i].host) == 0)
00133             {
00134                 defaultBus = i;
00135                 ++pDat[i].useCount;
00136                 break;
00137             }
00138         }
00139     }
00140     if (defaultBus < 0) // No existing socket found - open a new one. 
00141     {
00142         for (int i=8; i < 40; ++i)
00143         {
00144             if (pDat[i].open == false)
00145             {
00146                 defaultBus = i;
00147                 pDat[i].portNum = port;
00148                 pDat[i].host = new char[strlen(host)+1];
00149                 strcpy(pDat[i].host, host);
00150                 pDat[i].fd = openSocket(port, host);
00151                 pDat[i].open = pDat[i].fd > 0;
00152                 if (pDat[i].open) ++pDat[i].useCount;
00153                 break;
00154             }
00155         }     
00156     }
00157     if (debug || debugAll)        
00158         cout << "Dataset:" << id << ":constructor: socket port " << port
00159              << "on host " << host << " opened with fd = " 
00160              << pDat[defaultBus].fd << endl; 
00161     currBus = defaultBus;
00162     analogScalingFn = stdAnalogScalingFn;
00163     portType = NET;
00164     cmdTimeout = VERY_LONG_TIMEOUT;
00165     monTimeout = VERY_LONG_TIMEOUT;
00166     debug = false;
00167 }
00168 
00169 int Dataset::init(int ds_addr, Op_t op, int pt_addr)
00170 {
00171     int addr = MONITOR | (ds_addr << 25) | ((op + pt_addr) << 16);
00172     return init(addr);   
00173 }
00174 
00175 int Dataset::init(int addr)
00176 {
00177     int res, data; 
00178 
00179     if (currBus < 0 || pDat[currBus].open == false) return E_PORT;
00180     clear();
00181     state = ONLINE; // assume online for now
00182     res = mon(addr, &data);
00183     // Op failed, try alternate bus if there is one.
00184     if (res < 0 && altBus > 0)
00185     {
00186         // Toggle value of currBus
00187         if (currBus == defaultBus) currBus = altBus;
00188         else currBus = defaultBus;
00189         clear();
00190         state = ONLINE;
00191         res = mon(addr, &data);   
00192     }
00193     if (res < 0) state = OFFLINE;
00194     if (debug || debugAll)
00195     {
00196         cout << "Dataset:" << id << ":init: defaultBus=" << defaultBus 
00197         << " altBus=" << altBus << " currBus=" << currBus << endl;
00198         if (res != 0)
00199             cout << "Dataset:" << id << ":init: " << getErrMsg(res) << endl;
00200     }          
00201     return res;
00202 }
00203 
00204 void Dataset::clear()
00205 {
00206     // Clear comms buffers of any remaining bytes.
00207     if (pthread_mutex_lock(&pDat[currBus].mutex) == 0)
00208     {
00209         if (portType == TTY) tcflush(pDat[currBus].fd, TCIOFLUSH);
00210         int nRead = comRd(pDat[currBus].fd, junkBuff, 3, VERY_SHORT_TIMEOUT);
00211         if (debug || debugAll)
00212             cout << "Dataset:" << id << ":clear: " << nRead << " junk bytes discarded" << endl;
00213         int status = pthread_mutex_unlock(&pDat[currBus].mutex);
00214         if (status != 0) 
00215             throw SysLibErrorDesc(status, "Dataset::clear", "pthread_mutex_unlock");
00216     }
00217 }
00218 
00219 void Dataset::close()
00220 {
00221 //  NB: Fall-through is deliberate
00222     switch (portType)
00223     {
00224         case TTY:
00225           if (altBus > 0 && --pDat[altBus].useCount == 0)
00226           {
00227               ::close(pDat[altBus].fd);
00228               pDat[altBus].fd = -1;
00229               pDat[altBus].open = false;
00230           } 
00231         case NET:
00232       if (defaultBus > 0 && --pDat[defaultBus].useCount == 0)
00233           {
00234               ::close(pDat[defaultBus].fd);
00235               pDat[defaultBus].fd = -1;
00236               pDat[defaultBus].open = false;
00237           }  
00238     }
00239 }
00240 
00241 int Dataset::cmd(int ds_addr, Op_t op, int pt_addr, int data)
00242 {
00243     int addr = CONTROL | (ds_addr << 25) | ((op + pt_addr) << 16);
00244     return cmd(addr, data);
00245 }
00246 
00247 int Dataset::cmd(int addr, int data)
00248 {
00249     int status, res;
00250     static char reply[3] = { 0 };
00251 
00252     int message = addr | (data & 0xffff);
00253     status =  pthread_mutex_lock(&pDat[currBus].mutex);
00254     if (status != 0) 
00255         throw SysLibErrorDesc(status, "Dataset::cmd", "pthread_mutex_lock");
00256     if ((res = sendMessage(pDat[currBus].fd, message)) < 0) 
00257     {    
00258     status = pthread_mutex_unlock(&pDat[currBus].mutex);
00259         if (status != 0) 
00260             throw SysLibErrorDesc(status, "Dataset::cmd", "pthread_mutex_unlock");
00261     return res;
00262     }
00263     reply[0] = 0;
00264     res = comRd(pDat[currBus].fd, reply, 3, cmdTimeout);
00265     nRead = res;
00266     status = pthread_mutex_unlock(&pDat[currBus].mutex);
00267     if (status != 0) 
00268         throw SysLibErrorDesc(status, "Dataset::cmd", "pthread_mutex_unlock");
00269     if (res == 3)
00270     {       
00271         if (reply[0] == ACK) return 0;
00272         if (reply[0] == BEL) return W_BEL;
00273         if (reply[0] == DC1) return W_RESET; 
00274         if (portType == TTY) tcflush(pDat[currBus].fd, TCIOFLUSH);
00275         //clear();
00276         if (debug || debugAll)
00277         {
00278             cout << "Dataset:" << id << ":cmd: Unrecognised reply: " 
00279             << reply[0] << ' ' << reply[1] << ' ' << reply[2] << endl;
00280         }   
00281     return E_UNKNOWN;
00282     }
00283     if (res == 0) return E_READ_TIMEOUT;
00284     if (res < 0) return res;
00285     if (reply[0] == NAK) return E_NAK;
00286 
00287     if (portType == TTY) tcflush(pDat[currBus].fd, TCIFLUSH); // only 1 or 2 bytes received
00288     //clear();
00289 
00290     return E_NREAD;
00291 
00292 }
00293 
00294 int Dataset::mon(int ds_addr, Op_t op, int pt_addr, int* data)
00295 {
00296     int addr = MONITOR | (ds_addr << 25) | ((op + pt_addr) << 16);
00297     return mon(addr, data);
00298 }
00299 
00300 int Dataset::mon(int addr, int* data)
00301 {
00302     int res, status;
00303     int response = 0;
00304 
00305     if (state == OFFLINE) return E_OFFLINE;
00306     status = pthread_mutex_lock(&pDat[currBus].mutex);
00307     if (status != 0) 
00308         throw SysLibErrorDesc(status, "Dataset::mon", "pthread_mutex_lock");
00309     if ((res = sendMessage(pDat[currBus].fd, addr)) < 0) 
00310     {    
00311         status = pthread_mutex_unlock(&pDat[currBus].mutex);
00312         if (status != 0) 
00313             throw SysLibErrorDesc(status, "Dataset::mon", "pthread_mutex_unlock");        
00314         return res;
00315     }
00316     if ((res = readResponse(pDat[currBus].fd, &response, monTimeout)) < 0)
00317     {
00318     status = pthread_mutex_unlock(&pDat[currBus].mutex);
00319         if (status != 0) 
00320             throw SysLibErrorDesc(status, "Dataset::mon", "pthread_mutex_unlock");
00321         return res;
00322     }
00323     status = pthread_mutex_unlock(&pDat[currBus].mutex);
00324     if (status != 0) 
00325         throw SysLibErrorDesc(status, "Dataset::mon", "pthread_mutex_unlock");
00326     *data = response & 0xFFFF;
00327     return 0;
00328 }
00329 
00330 int Dataset::mon(int addr, int* data, int timeOut)
00331 {
00332     int res, status;
00333     int response = 0;
00334 
00335     if (state == OFFLINE) return E_OFFLINE;
00336     status = pthread_mutex_lock(&pDat[currBus].mutex);
00337     if (status != 0) 
00338         throw SysLibErrorDesc(status, "Dataset::mon", "pthread_mutex_lock");
00339     if ((res = sendMessage(pDat[currBus].fd, addr)) < 0) 
00340     {    
00341         status = pthread_mutex_unlock(&pDat[currBus].mutex);
00342         if (status != 0) 
00343             throw SysLibErrorDesc(status, "Dataset::mon", "pthread_mutex_unlock");        
00344         return res;
00345     }
00346     if ((res = readResponse(pDat[currBus].fd, &response, timeOut)) < 0)
00347     {
00348     status = pthread_mutex_unlock(&pDat[currBus].mutex);
00349         if (status != 0) 
00350             throw SysLibErrorDesc(status, "Dataset::mon", "pthread_mutex_unlock");
00351         return res;
00352     }
00353     status = pthread_mutex_unlock(&pDat[currBus].mutex);
00354     if (status != 0) 
00355         throw SysLibErrorDesc(status, "Dataset::mon", "pthread_mutex_unlock");
00356     *data = response & 0xFFFF;
00357     return 0;
00358 }
00359 
00360 int Dataset::mon(int ds_addr, Op_t op, int pt_addr, float* volts)
00361 {
00362     int addr = MONITOR | (ds_addr << 25) | ((op + pt_addr) << 16);
00363     return mon(addr, volts);
00364 }
00365 
00366 int Dataset::mon(int addr, float* volts)
00367 {
00368     int res, status;
00369     int response = 0;
00370 
00371     if (state == OFFLINE) return E_OFFLINE;    
00372     status = pthread_mutex_lock(&pDat[currBus].mutex);
00373     if (status != 0) 
00374         throw SysLibErrorDesc(status, "Dataset::mon", "pthread_mutex_lock");       
00375     if ((res = sendMessage(pDat[currBus].fd, addr)) < 0) 
00376     {    
00377         status = pthread_mutex_unlock(&pDat[currBus].mutex);
00378         if (status != 0) 
00379             throw SysLibErrorDesc(status, "Dataset::mon", "pthread_mutex_unlock");        
00380     return res;
00381     }
00382     if ((res = readResponse(pDat[currBus].fd, &response, monTimeout)) < 0)
00383     {
00384     status = pthread_mutex_unlock(&pDat[currBus].mutex);
00385         if (status != 0) 
00386             throw SysLibErrorDesc(status, "Dataset::mon", "pthread_mutex_unlock");
00387     return res;
00388     }
00389     status = pthread_mutex_unlock(&pDat[currBus].mutex);
00390     if (status != 0) 
00391         throw SysLibErrorDesc(status, "Dataset::mon", "pthread_mutex_unlock");
00392       *volts = (*analogScalingFn)(response);
00393 
00394     return 0;
00395 }
00396 
00397 int Dataset::transact(char sendBuf[10], char respBuf[5], int timeout)
00398 {
00399     memset(respBuf, 0, 5);
00400     pthread_mutex_lock(&pDat[currBus].mutex);
00401     write(pDat[currBus].fd, sendBuf, 10);
00402     if (debug)
00403     {
00404         cout << "Dataset::transact: wrote: ";
00405         printSendMessage(sendBuf, 10);
00406     }   
00407     nRead = comRd(pDat[currBus].fd, respBuf, timeout);
00408     if (debug)
00409     {
00410         cout << "Dataset::transact: read " << nRead << " bytes: ";
00411         printResponseMessage(respBuf, nRead);
00412     }
00413     pthread_mutex_unlock(&pDat[currBus].mutex);
00414     return nRead; 
00415 }
00416 
00417 int Dataset::composeAddress(Mode_t mode, int ds_addr, Op_t op, int pt_addr)
00418 {
00419     return mode | (ds_addr << 25) | ((op + pt_addr) << 16);
00420 }
00421 
00422 void Dataset::setStdAnalogScaling()
00423 {
00424     analogScalingFn = stdAnalogScalingFn;
00425 }
00426 
00427 void Dataset::setF93AnalogScaling()
00428 {
00429     analogScalingFn = f93AnalogScalingFn;
00430 }
00431 
00432 const char* Dataset::getErrMsg(int code)
00433 {
00434     if (code <= 0) 
00435     {
00436     if (code > E_END) 
00437             return errTable[-code];
00438     else
00439             return "Invalid Error Code";
00440     }
00441     if (code < W_END)
00442     return warnTable[code];
00443     else
00444     return "Invalid Warning Code";
00445 }
00446 
00447 inline int Dataset::compare(int cmdVal, int monVal, Op_t op)
00448 {
00449     int mask = 0;
00450 
00451     switch (op) {
00452         case N8:case A8:case S8:
00453             mask = 0xFF;
00454             break;
00455         case A16:case S16:case W:
00456             mask = 0xFFFF;
00457             break;
00458         case SB:
00459             mask = 0x1;
00460             break;
00461         default: break;
00462     }
00463     if ((cmdVal & mask) != (monVal & mask))
00464         return E_COMPARE;
00465 
00466     return 0;
00467 }
00468 
00469 const char* Dataset::opToStr(Op_t op, Cat_t cat)
00470 {
00471     switch (op) {
00472         case DA: if (cat == ANALOG) return "DA";  
00473                  if (cat == REG8)   return "N8";
00474     case SEA: return "SEA";
00475     case SB:  return "SB";
00476     case A8:  return "A8";
00477     case A16: return "A16";
00478     case S8:  return "S8";
00479     case S16: return "S16";
00480     case W:   return "W";
00481         case MXA: return "MXA";
00482         default:  return "unknown";
00483     } 
00484 }
00485 
00486 Dataset::Op_t Dataset::strToOp(const char* str)
00487 {
00488     if (strncmp(str, "W", 1) == 0)   return W;
00489     if (strncmp(str, "N8", 2) == 0)  return N8;
00490     if (strncmp(str, "DA", 2) == 0)  return DA;
00491     if (strncmp(str, "SB", 2) == 0)  return SB;   
00492     if (strncmp(str, "A8", 2) == 0)  return A8;
00493     if (strncmp(str, "S8", 2) == 0)  return S8; 
00494     if (strncmp(str, "SEA", 3) == 0) return SEA;
00495     if (strncmp(str, "A16", 3) == 0) return A16;
00496     if (strncmp(str, "S16", 3) == 0) return S16;
00497     if (strncmp(str, "MXA", 3) == 0) return MXA;
00498     return OP_ERR;
00499 }
00500 
00501 Dataset::Cat_t Dataset::strToCat(const char* str)
00502 {
00503     if (strncmp(str, "W", 1) == 0)   return REG8;
00504     if (strncmp(str, "N8", 2) == 0)  return REG8;
00505     if (strncmp(str, "DA", 2) == 0)  return ANALOG;
00506     if (strncmp(str, "SB", 2) == 0)  return BIT1;   
00507     if (strncmp(str, "A8", 2) == 0)  return REG8;
00508     if (strncmp(str, "S8", 2) == 0)  return REG8; 
00509     if (strncmp(str, "SEA", 3) == 0) return ANALOG;
00510     if (strncmp(str, "A16", 3) == 0) return REG16;
00511     if (strncmp(str, "S16", 3) == 0) return REG16;
00512     if (strncmp(str, "MXA", 3) == 0) return ANALOG;
00513     return CAT_ERR;
00514 }
00515 
00516 const char* const Dataset::getSendMessage()
00517 {
00518     static char msg[80];
00519     int count = 0;
00520 
00521     memset(msg, 0, 80);
00522     if (sendBuff[0] == SYN) 
00523         count = sprintf(msg, "SYN ");
00524     else
00525         count = sprintf(msg, "0x%x", sendBuff[0]);
00526     if (sendBuff[1] & 0x80)
00527         count += sprintf(&msg[count], "CTL+0x%x ", (sendBuff[1] & ~0x80));
00528     else
00529         count += sprintf(&msg[count], "MON+0x%x ", (sendBuff[1] & ~0x80));
00530     for (int i=2; i<10; ++i)
00531     {
00532         if (sendBuff[i] == ESC) 
00533             count += sprintf(&msg[count], "ESC ");
00534         else
00535             count += sprintf(&msg[count], "0x%x ", sendBuff[i] & 0xFF);
00536     } 
00537     return msg; 
00538 }
00539 
00540 const char* const Dataset::getResponseMessage()
00541 {
00542     static char msg[80];
00543     int count = 0;
00544 
00545     memset(msg, 0, 80);
00546     switch (receiveBuff[0]) {
00547         case ACK: 
00548             count = sprintf(msg, "ACK "); break;
00549         case ESC: 
00550             count = sprintf(msg, "ESC "); break;
00551         case BEL: 
00552             count = sprintf(msg, "BEL "); break;
00553         case DC1: 
00554             count = sprintf(msg, "DC1 "); break;
00555         case NAK: 
00556             count = sprintf(msg, "NAK "); break;
00557         default:  
00558             count = sprintf(msg, "0x%x ", receiveBuff[0]);
00559     } 
00560     for (int i=1; i < nRead; ++i)
00561     {
00562         if (receiveBuff[i] == ESC)
00563             count += sprintf(&msg[count], "ESC ");
00564         else
00565             count += sprintf(&msg[count], "0x%x ", receiveBuff[i] & 0xFF);
00566     } 
00567     return msg;  
00568 }
00569    
00570 int Dataset::openSerial(int bus)
00571 {
00572     char serDev[12];
00573     int res, fd;
00574     struct termios tios;
00575 
00576     sprintf(serDev, "/dev/ttyS%d", bus);
00577     // Open serial port to dataset and configure
00578     res = open(serDev, O_RDWR | O_NOCTTY);
00579     if (res < 0)       
00580         throw SysLibErrorDesc(errno, "Dataset::openSerial", "open");
00581     fd = res;
00582     tcflush(fd, TCIOFLUSH);
00583     tcgetattr(fd, &tios);
00584 #ifdef SOLARIS
00585     // turn off canonical mode, extended input, signals,
00586     tios.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); 
00587     // input flags:-
00588     // turn off the input processing as well.
00589     tios.c_iflag &=  ~( INPCK | BRKINT | ISTRIP | ICRNL | IXON); 
00590     // control flags:-
00591     // set up the global values
00592     tios.c_cflag &= ~(CSIZE | PARENB);
00593     tios.c_cflag |= CS8;
00594     tios.c_cflag |= CLOCAL;
00595     tios.c_cflag |= CREAD;   
00596     // output flags:-
00597     // Turn off the output processing
00598     tios.c_oflag &= ~(OPOST);  
00599     // set up 0 character minimum with no timeout
00600     tios.c_cc[VMIN] = 0;
00601     tios.c_cc[VTIME] = 0;
00602 #else
00603     cfmakeraw(&tios);
00604 #endif
00605     tios.c_cflag |= PARENB | PARODD; // Odd parity
00606     tios.c_cflag &= ~CSTOPB;         // One stop bit
00607     if (baud == LOBAUD)
00608     {
00609         cfsetospeed(&tios, B4800);
00610         cfsetispeed(&tios, B4800);      
00611     }
00612     else // HIBAUD
00613     {
00614         cfsetospeed(&tios, B38400);
00615         cfsetispeed(&tios, B38400);
00616     }
00617     res = tcsetattr(fd, TCSANOW, &tios);
00618     if (res < 0)
00619         throw SysLibErrorDesc(errno, "Dataset::openSerial", "tcsetattr");
00620 
00621     if (debug || debugAll)        
00622         cout << "Dataset:" << id << ":openSerial: " << serDev
00623              << " opened with baud = " << baud << endl;
00624 
00625     return fd;
00626 }
00627 
00628 int Dataset::openSocket(int port, char* host)
00629 {
00630     int res, fd;
00631     struct sockaddr_in sa;
00632     struct hostent* phost;
00633 
00634     res = socket(AF_INET, SOCK_STREAM, 0);
00635     if (res < 0)       
00636         throw SysLibErrorDesc(errno, "Dataset::openSocket", "socket");
00637     fd = res;
00638     int on = 1;
00639     res = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
00640     if (res < 0)
00641         throw SysLibErrorDesc(errno, "Dataset::openSocket", "setsockopt");    
00642     sa.sin_family = AF_INET;
00643     sa.sin_port = htons(port);
00644     phost = gethostbyname(host);
00645     if (host == NULL)
00646         throw SysLibErrorDesc(h_errno, "Dataset::openSocket", "gethostbyname");
00647     bcopy(phost->h_addr, &sa.sin_addr, phost->h_length);    
00648     if (debug || debugAll)    
00649         cout << "Dataset:" << id << ": Waiting to connect to socket port " 
00650              << port << " on host " << host << endl;
00651     res = connect(fd, (struct sockaddr*)&sa, sizeof(struct sockaddr));
00652     if (res < 0)
00653         throw SysLibErrorDesc(errno, "Dataset::openSocket", "connect");
00654     if (debug || debugAll)
00655         cout << "Dataset:" << id << ": Socket port "
00656              << port << " connect OK" << endl;
00657 
00658     return fd;
00659 }
00660 
00661 inline int Dataset::sendMessage(int fd, int message)
00662 {
00663     static char byte[4];
00664     int index = 0, count = 3;
00665 
00666     memset(sendBuff, 0, 10);
00667     memset(byte, 0, 4); 
00668     sendBuff[index++] = SYN;
00669     intToBytes(message, byte);
00670     while (count >= 0)
00671     {
00672     switch (char curr = byte[count--])
00673     {
00674             case ESC:  sendBuff[index++] = ESC;
00675                sendBuff[index++] = '0';         
00676                break;           
00677             case SYN:  sendBuff[index++] = ESC;
00678                sendBuff[index++] = '1';
00679                break;
00680         default:   sendBuff[index++] = curr;
00681                break;
00682     }
00683     }
00684     int nWrit = write(fd, sendBuff, 10);
00685     if (nWrit < 0)
00686     {
00687         if (debug || debugAll)
00688             cerr << "Dataset:" << id << ":sendMessage:write failed:"
00689             << strerror(errno) << endl;
00690     return E_WRITE;
00691     }
00692     if (nWrit < 10)
00693     {
00694         if (portType == TTY) tcflush(fd, TCOFLUSH);
00695         if (debug || debugAll)
00696             cerr << "Dataset:" << id << ":sendMessage: write failed: "
00697             << "Wrote only " << nWrit << " bytes out of 10" << endl;
00698     return E_NWRIT;
00699     }
00700     if (debug)
00701     {
00702         cout << "Dataset:" << id << ":sendMessage:" << endl << '\t';
00703         printSendMessage(sendBuff, 10); 
00704     }
00705     return 0; 
00706 }
00707 
00708 inline int Dataset::readResponse(int fd, int* response, int timeOut)
00709 {  
00710     memset(receiveBuff, 0, 5);
00711     nRead = comRd(fd, receiveBuff, timeOut);
00712     if (debug && nRead > 0)
00713     {
00714         cout << "Dataset:" << id << ":readResponse: " 
00715         << nRead << " bytes read" << endl << '\t';
00716         printResponseMessage(receiveBuff, nRead);
00717     }
00718     if (nRead >= 3 && receiveBuff[0] == ACK || receiveBuff[0] == BEL || receiveBuff[0] == DC1)
00719     {
00720         if (receiveBuff[1] == ESC)
00721         {
00722             decode(&receiveBuff[1]);
00723             receiveBuff[2] = receiveBuff[3];
00724             receiveBuff[3] = receiveBuff[4];
00725             receiveBuff[4] = 0;
00726         }   
00727         if (receiveBuff[2] == ESC)
00728         {
00729             decode(&receiveBuff[2]);
00730             receiveBuff[3] = receiveBuff[4] = 0;
00731         }
00732         *response = bytesToInt(&receiveBuff[1], 2);
00733     if (receiveBuff[0] == ACK) { clearTimeoutErr(); return 0; }
00734     if (receiveBuff[0] == BEL) { clearTimeoutErr(); return W_BEL; }
00735         if (receiveBuff[0] == DC1) { clearTimeoutErr(); return W_RESET; }
00736     }
00737     if (nRead == 0)
00738     { flagTimeoutErr(); return E_READ_TIMEOUT; }
00739     if (nRead < 0) return E_READ;
00740     if (receiveBuff[0] == NAK) return E_NAK;
00741     if (portType == TTY) tcflush(fd, TCIFLUSH);
00742     //clear();
00743     if (nRead < 3) return E_NREAD;
00744 
00745     return E_UNKNOWN;
00746 }
00747 
00748 
00749 inline int Dataset::comRd(int fd, char* rdBuf, int nBytes, int timeOut)
00750 {
00751     int nRead = 0;
00752     fd_set readFds;
00753     struct timeval tout;
00754     pthread_t tid;
00755 
00756     while (nRead < nBytes)
00757     {
00758     FD_ZERO(&readFds);
00759         FD_SET(fd, &readFds);
00760         tout.tv_sec = 0;
00761         tout.tv_usec = ((nBytes - nRead) * timeOut)/nBytes;
00762     int status = select(FD_SETSIZE, &readFds, NULL, NULL, &tout);   
00763     if (status < 0)
00764             throw SysLibErrorDesc(errno, "Dataset::comRd(int,char*,int,int)", "select");
00765     if (FD_ISSET(fd, &readFds))
00766     {
00767             int n = read(fd, &rdBuf[nRead], nBytes - nRead);
00768         if (n < 0)  // read error
00769         {
00770         if (errno == EINTR) continue;
00771                 if (debug || debugAll)
00772                 cerr << "Dataset:" << id << ":comRd(int,char*,int,int): read failed: "
00773                     << strerror(errno) << endl;
00774             return E_READ; 
00775             }
00776             nRead += n;
00777             if (nRead == 0 && portType == NET)
00778             {
00779 // TBF      // Lost connection to socket - close fd and start task to reconnect
00780                 Arg* arg = new Arg(this, &pDat[currBus]);
00781                 pthread_create(&tid, NULL, socketReconnectThread, arg);
00782                 return E_SOCKET;
00783             }
00784         if (n == 0) break;
00785     }
00786     else    // timeout
00787         {
00788             if (debug || debugAll)
00789                 cerr << "Dataset:" << id << ":comRd(int,char*,int,int): timeout after reading "
00790                 << nRead << " bytes" << endl;
00791         break;
00792     }
00793     }  
00794     return nRead;
00795 }
00796 
00797 inline int Dataset::comRd(int fd, char* rdBuf, int timeOut)
00798 {
00799     fd_set readFds;
00800     struct timeval tout;
00801     tout.tv_sec = 0;
00802     tout.tv_usec = timeOut;
00803     int nRead = 0, nBytes = 1;
00804     pthread_t tid;
00805 
00806     while (nBytes > 0)
00807     {
00808         FD_ZERO(&readFds);
00809         FD_SET(fd, &readFds);
00810         int status = select(FD_SETSIZE, &readFds, NULL, NULL, &tout);
00811         if (status < 0)
00812             throw SysLibErrorDesc(errno, "Dataset::comRd(int,char*,int)", "select");
00813         if (FD_ISSET(fd, &readFds))
00814         {
00815             int n = read(fd, &rdBuf[nRead], nBytes);
00816         if (n > 0)
00817             {
00818             nRead += n;
00819         switch (nRead) {
00820                     case 1:
00821                         if (rdBuf[0] == ACK || rdBuf[0] == DC1 || rdBuf[0] == BEL) 
00822                              nBytes = 2;
00823             //else nBytes = 0;
00824                         else nBytes = 1;
00825             break;
00826                     case 2:
00827             nBytes = 1;
00828             break;
00829                     case 3:
00830             if (rdBuf[1] == ESC || rdBuf[2] == ESC) 
00831                             nBytes = 1;
00832             else nBytes = 0;
00833             break;
00834                     case 4:
00835                         if (rdBuf[3] == ESC) nBytes = 1;
00836             else nBytes = 0;
00837             break;
00838                     default:
00839                         nBytes = 0;
00840                         break;
00841         }    
00842                 tout.tv_sec = 0;
00843         tout.tv_usec = (5 - nRead)*(timeOut/5);
00844         continue;
00845         }
00846             if (nRead == 0 && portType == NET)
00847             {
00848 // TBF      // Lost connection to socket - close fd and start task to reconnect
00849                 Arg* arg = new Arg(this, &pDat[currBus]);
00850                 pthread_create(&tid, NULL, socketReconnectThread, arg);
00851                 return E_SOCKET;
00852             }
00853         if (n == 0) break;
00854         if (errno == EINTR) continue;
00855             if (debug || debugAll)
00856             cerr << "Dataset:" << id << ":comRd(int,char*,int): read failed: "
00857                 << strerror(errno) << endl;
00858             return E_READ;
00859     }
00860     else    // timeout
00861     {
00862             if (debug || debugAll)
00863                 cerr << "Dataset:" << id << ":comRd(int,char*,int): timeout after reading "
00864                 << nRead << " bytes" << endl;
00865         break; 
00866         }
00867     }   
00868     return nRead;
00869 }
00870 
00871 bool Dataset::isReplyProtocolChar(char c)
00872 {
00873     switch (c) {
00874         case ACK: return true;
00875         case BEL: return true;
00876         case DC1: return true;
00877         case NAK: return true;
00878         default:  return false;
00879     }
00880 }
00881 
00882 void Dataset::printSendMessage(char* bytes, int len)
00883 {
00884     static char msg[21];
00885 
00886     int n = 0;
00887     for (int i=0; i<len; ++i)
00888     {
00889         switch (bytes[i]) {
00890             case SYN: n += sprintf(&msg[n], "SYN ");
00891                       break;
00892             case ESC: n += sprintf(&msg[n], "ESC ");
00893                       break;
00894             default:  n += sprintf(&msg[n], "0x%02x ", unsigned(bytes[i]) & 0xff);
00895         }
00896     }
00897     cout << msg << endl;
00898 }
00899 
00900 void Dataset::printResponseMessage(char* bytes, int len)
00901 {
00902     static char msg[21];
00903 
00904     int n = 0;
00905     for (int i=0; i<len; ++i)
00906     {
00907         switch (bytes[i]) {
00908             case ACK: n += sprintf(&msg[n], "ACK ");
00909                       break;
00910             case ESC: n += sprintf(&msg[n], "ESC ");
00911                       break;
00912             case BEL: n += sprintf(&msg[n], "BEL ");
00913                       break;
00914             case DC1: n += sprintf(&msg[n], "DC1 ");
00915                       break;
00916             case NAK: n += sprintf(&msg[n], "NAK ");
00917                       break;
00918             default:  n += sprintf(&msg[n], "0x%02x ", unsigned(bytes[i]) & 0xff);
00919 
00920         }
00921     }
00922     cout << msg << endl;
00923 }
00924 
00925 void* Dataset::socketReconnectThread(void* arg)
00926 {
00927     Dataset* obj = ((Arg*)arg)->obj;
00928     PortAccessData* pDat = ((Arg*)arg)->pDat;
00929 
00930     pthread_detach(pthread_self());
00931     ::close(pDat->fd);
00932     pDat->fd = -1;
00933     while (1)
00934     {
00935         pthread_mutex_lock(&pDat->mutex);
00936         try {
00937         pDat->fd = obj->openSocket(pDat->portNum, pDat->host);
00938         } catch(const std::exception& e) { ;}
00939         pthread_mutex_unlock(&pDat->mutex);
00940         if (pDat->fd > 0)
00941         {
00942             obj->clear();
00943             break;
00944         }
00945         sleep(5);
00946     }
00947     return NULL;
00948 }
00949 

Generated on Mon Apr 30 13:32:34 2007 for Parkes M & C - PKMC C++ library API by  doxygen 1.4.4