rllib  1
Public Types | Public Member Functions | Public Attributes | Private Member Functions | Private Attributes
rlModbus Class Reference

#include <rlmodbus.h>

Collaboration diagram for rlModbus:
Collaboration graph
[legend]

List of all members.

Public Types

enum  Modbus {
  MODBUS_CHECKSUM_ERROR = -2, MODBUS_ERROR = -1, MODBUS_SUCCESS = 0, MODBUS_RTU = 1,
  MODBUS_ASCII = 2
}
enum  ModbusFunctionCodes {
  ReadCoilStatus = 1, ReadInputStatus = 2, ReadHoldingRegisters = 3, ReadInputRegisters = 4,
  ForceSingleCoil = 5, PresetSingleRegister = 6, ReadExceptionStatus = 7, FetchCommEventCtr = 11,
  FetchCommEventLog = 12, ForceMultipleCoils = 15, PresetMultipleRegs = 16, ReportSlaveID = 17,
  ReadGeneralReference = 20, WriteGeneralReference = 21, MaskWrite4XRegisters = 22, ReadWrite4XRegisters = 23,
  ReadFifoQueue = 24
}

Public Member Functions

 rlModbus (long max_telegram_length=1024, int mode=MODBUS_RTU, char end_delimitor=0x0a)
virtual ~rlModbus ()
int write (int slave, int function, const unsigned char *data, int len, int *transactionID=NULL)
int request (int slave, int function, int start_adr, int num_register)
int response (int *slave, int *function, unsigned char *data, int timeout=1000)
int readRequest (int *slave, int *function, unsigned char *data, int timeout=1000, int *transactionID=NULL)
void registerSocket (rlSocket *socket)
void registerSerial (rlSerial *serial)
int data2int (const unsigned char *data)
int int2data (int val, unsigned char *data)
int intsize ()

Public Attributes

int autoreconnectSocket

Private Member Functions

int buf2int_rtu (unsigned char *buf)
void int2buf_rtu (int i, unsigned char *buf)
int buf2int_ascii (unsigned char *buf)
void int2buf_ascii (int i, unsigned char *buf)
void insertLRC (int len)
void insertCRC (int len)
int LRCerror (int len)
int CRCerror (int len)

Private Attributes

rlSockets
rlSerialtty
unsigned char * tel
long maxtel
int mode
char delimitor

Detailed Description

This class implements the modbus protocol.
You can use serial interfaces or TCP/IP.
Modbus RTU and ASCII are available.

Definition at line 28 of file rlmodbus.h.


Member Enumeration Documentation

Enumerator:
MODBUS_CHECKSUM_ERROR 
MODBUS_ERROR 
MODBUS_SUCCESS 
MODBUS_RTU 
MODBUS_ASCII 

Definition at line 31 of file rlmodbus.h.

Enumerator:
ReadCoilStatus 
ReadInputStatus 
ReadHoldingRegisters 
ReadInputRegisters 
ForceSingleCoil 
PresetSingleRegister 
ReadExceptionStatus 
FetchCommEventCtr 
FetchCommEventLog 
ForceMultipleCoils 
PresetMultipleRegs 
ReportSlaveID 
ReadGeneralReference 
WriteGeneralReference 
MaskWrite4XRegisters 
ReadWrite4XRegisters 
ReadFifoQueue 

Definition at line 40 of file rlmodbus.h.


Constructor & Destructor Documentation

rlModbus::rlModbus ( long  max_telegram_length = 1024,
int  mode = MODBUS_RTU,
char  end_delimitor = 0x0a 
)

Definition at line 20 of file rlmodbus.cpp.

{
  if(max_telegram_length < 256) max_telegram_length = 256;
  tel = new unsigned char[max_telegram_length];
  maxtel = max_telegram_length;
  mode = _mode;
  delimitor = end_delimitor;
  s = NULL;
  tty = NULL;
  autoreconnectSocket = 1;
}
rlModbus::~rlModbus ( ) [virtual]

Definition at line 32 of file rlmodbus.cpp.

{
  if(tel != NULL) delete [] tel;
}

Member Function Documentation

int rlModbus::buf2int_ascii ( unsigned char *  buf) [private]

Definition at line 612 of file rlmodbus.cpp.

{
  int val;

  sscanf((char *) buf,"%04X",&val);
  return val;
}
int rlModbus::buf2int_rtu ( unsigned char *  buf) [private]

Definition at line 597 of file rlmodbus.cpp.

{
  return (buf[0]*256 + buf[1]);
}
int rlModbus::CRCerror ( int  len) [private]

Definition at line 746 of file rlmodbus.cpp.

{
  unsigned char crc_high, crc_low;
  unsigned index;
  int i;

  if(len < 2) return 1;
  crc_high = crc_low = 0xff;
  for(i=0; i<len-2; i++)
  {
    index = crc_low ^ tel[i];
    crc_low  = crc_high ^ array_crc_low[index];
    crc_high = array_crc_high[index];
  }
  if(crc_low  != tel[len-2]) return 1;
  if(crc_high != tel[len-1]) return 1;
  return 0;
}
int rlModbus::data2int ( const unsigned char *  data)

Definition at line 37 of file rlmodbus.cpp.

{
  return (data[0]*256)+data[1];
}
void rlModbus::insertCRC ( int  len) [private]

Definition at line 728 of file rlmodbus.cpp.

{
  unsigned char crc_high, crc_low;
  unsigned index;
  int i;

  if(len < 0) return;
  crc_high = crc_low = 0xff;
  for(i=0; i<len; i++)
  {
    index = crc_low ^ tel[i];
    crc_low  = crc_high ^ array_crc_low[index];
    crc_high = array_crc_high[index];
  }
  tel[len]   = crc_low;
  tel[len+1] = crc_high;
}
void rlModbus::insertLRC ( int  len) [private]

Definition at line 625 of file rlmodbus.cpp.

{
  unsigned char lrc;
  int i,high,low,val;

  if(len < 0) return;
  lrc = 0;
  for(i=1; i<len; i+=2) // exclude starting ':' and trailing <CR><LF>
  {
    sscanf((const char *) &tel[i],   "%1X", &high);
    sscanf((const char *) &tel[i+1], "%1X", &low);
    val = high*16 + low;
    lrc += val;
  }
  lrc = ((unsigned char)(-((char) lrc)));
  sprintf((char *) &tel[len],"%02X",(unsigned int) lrc);
}
void rlModbus::int2buf_ascii ( int  i,
unsigned char *  buf 
) [private]

Definition at line 620 of file rlmodbus.cpp.

{
  sprintf((char *) buf,"%04X",i);
}
void rlModbus::int2buf_rtu ( int  i,
unsigned char *  buf 
) [private]

Definition at line 602 of file rlmodbus.cpp.

{
  int high, low;

  high = i / 256;
  low  = i & 0x0ff;
  buf[0] = (unsigned char) high;
  buf[1] = (unsigned char) low;
}
int rlModbus::int2data ( int  val,
unsigned char *  data 
)

Definition at line 42 of file rlmodbus.cpp.

{
  data[0] = (unsigned char) val / 256;
  data[1] = (unsigned char) val & 0x0ff;
  return 0;
}
int rlModbus::intsize ( )

Definition at line 49 of file rlmodbus.cpp.

{
  return 2;
}
int rlModbus::LRCerror ( int  len) [private]

Definition at line 643 of file rlmodbus.cpp.

{
  unsigned char *cptr;
  unsigned char lrc;
  int i,high,low,val;

  if(len < 0) return 1;
  tel[maxtel-1] = '\0';
  cptr = (unsigned char *) strchr((char *)tel,':');
  if(cptr == NULL) return 1;
  cptr++;
  lrc = 0;
  for(i=1; i<len+2; i+=2) // exclude starting ':' and trailing <CR><LF>
  {                       // len is without lrc -> len+2
    sscanf((const char *) cptr++, "%1X", &high);
    sscanf((const char *) cptr++, "%1X", &low);
    val = high*16 + low;
    lrc += val;
  }
  if(lrc == 0) return 0; // lrc ok
  return 1;              // lrc error
}
int rlModbus::readRequest ( int *  slave,
int *  function,
unsigned char *  data,
int  timeout = 1000,
int *  transactionID = NULL 
)

Definition at line 350 of file rlmodbus.cpp.

{
  unsigned char *telptr;
  int ret,len,byte_count,i,itel,val;

  len = 0;
  if(mode != MODBUS_ASCII && mode != MODBUS_RTU) return MODBUS_ERROR;
  if(s != NULL)
  {
    if(s->isConnected() == 0) return MODBUS_ERROR;
    if(mode == MODBUS_RTU)
    {
      if(s->read((char *) tel, 6, timeout) <= 0) return MODBUS_ERROR;
      if(transactionID != NULL) *transactionID = tel[0] * 256 + tel[1]; // return transactionID
      // bytes 0,1 Transaction ID faithfully copied from the request message
      // bytes 2,3 Protocol number always zero
      // byte 4 Response length (upper byte) Always zero
      // byte 5 Response length (lower byte). Equal to the number of bytes which follow
      // Here comes the normal Modus telegram
      if(s->read((char *) tel, 2, timeout) <= 0) return MODBUS_ERROR;
      *slave     = tel[0];
      *function  = tel[1];
      switch(*function)
      {
        case ReadCoilStatus:
        case ReadInputStatus:
        case ReadHoldingRegisters:
        case ReadInputRegisters:
        case ForceSingleCoil:
        case PresetSingleRegister:
          if(s->read((char *) data, 4, timeout) <= 0)              return MODBUS_ERROR;
          return 4;
        case ReadExceptionStatus:
        case FetchCommEventCtr:
        case FetchCommEventLog:
        case ReportSlaveID:
          return 0;
        case ForceMultipleCoils:
        case PresetMultipleRegs:
          if(s->read((char *) data, 5, timeout) <= 0)              return MODBUS_ERROR;
          byte_count = data[4];
          if(s->read((char *) &data[4], byte_count, timeout) <= 0) return MODBUS_ERROR;
          return 4+byte_count;
        case ReadGeneralReference:
        case WriteGeneralReference:
          if(s->read((char *) data, 1, timeout) <= 0)              return MODBUS_ERROR;
          byte_count = data[0];
          if(s->read((char *) data, byte_count, timeout) <= 0)     return MODBUS_ERROR;
          return byte_count;
        case MaskWrite4XRegisters:
          if(s->read((char *) data, 6, timeout) <= 0)              return MODBUS_ERROR;
          return 6;
        case ReadWrite4XRegisters:
          if(s->read((char *) data, 9, timeout) <= 0)              return MODBUS_ERROR;
          byte_count = data[8];
          if(s->read((char *) &data[8], byte_count, timeout) <= 0) return MODBUS_ERROR;
          return 8+byte_count;
        case ReadFifoQueue:
          if(s->read((char *) data, 2, timeout) <= 0)              return MODBUS_ERROR;
          return 2;
        default:
          return MODBUS_ERROR;
      }
    }
  }
  else if(tty != NULL)
  {
    if(mode == MODBUS_ASCII)
    {
      //printf("modbus ascii\n");
      for(i=0; i<maxtel; i++)
      {
        ret = tty->select(timeout);
        if(ret == 0) return MODBUS_ERROR;
        //printf("readChar\n");
        itel = tty->readChar();
        if(itel < 0) return MODBUS_ERROR;
        tel[i] = (unsigned char) itel;
        if(tel[i] == 0x0d && delimitor != 0x0a) break;
        if(tel[i] == 0x0a)                      break;
      }
      tel[i] = '\0';
      telptr = (unsigned char *) strchr((const char *) tel,':');
      if(telptr == NULL) return MODBUS_ERROR;
      len++;
      sscanf((char *) &telptr[len],"%02X",slave);       len += 2;
      sscanf((char *) &telptr[len],"%02X",function);    len += 2;
      switch(*function)
      {
        case ReadCoilStatus:
        case ReadInputStatus:
        case ReadHoldingRegisters:
        case ReadInputRegisters:
        case ForceSingleCoil:
        case PresetSingleRegister:
          sscanf((char *) &telptr[len],"%02X",&val); data[0] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[1] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[2] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[3] = (unsigned char) val; len += 2;
          if(LRCerror(len) == 1) return MODBUS_CHECKSUM_ERROR;
          return 4;
        case ReadExceptionStatus:
        case FetchCommEventCtr:
        case FetchCommEventLog:
        case ReportSlaveID:
          if(LRCerror(len) == 1) return MODBUS_CHECKSUM_ERROR;
          return 0;
        case ForceMultipleCoils:
        case PresetMultipleRegs:
          sscanf((char *) &telptr[len],"%02X",&val); data[0] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[1] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[2] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[3] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&byte_count);                         len += 2;
          for(i=0; i<byte_count; i++)
          {
            sscanf((char *) &telptr[len],"%02X",&val); data[4+i] = (unsigned char) val; len += 2;
          }
          if(LRCerror(len) == 1) return MODBUS_CHECKSUM_ERROR;
          return 4+byte_count;
        case ReadGeneralReference:
        case WriteGeneralReference:
          sscanf((char *) &telptr[len],"%02X",&byte_count);                           len += 2;
          for(i=0; i<byte_count; i++)
          {
            sscanf((char *) &telptr[len],"%02X",&val); data[i] = (unsigned char) val; len += 2;
          }
          if(LRCerror(len) == 1) return MODBUS_CHECKSUM_ERROR;
          return byte_count;
        case MaskWrite4XRegisters:
          sscanf((char *) &telptr[len],"%02X",&val); data[0] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[1] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[2] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[3] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[4] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[5] = (unsigned char) val; len += 2;
          if(LRCerror(len) == 1) return MODBUS_CHECKSUM_ERROR;
          return 6;
        case ReadWrite4XRegisters:
          sscanf((char *) &telptr[len],"%02X",&val); data[0] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[1] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[2] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[3] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[4] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[5] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[6] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[7] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&byte_count);                         len += 2;
          for(i=0; i<byte_count; i++)
          {
            sscanf((char *) &telptr[len],"%02X",&val); data[8+i] = (unsigned char) val; len += 2;
          }
          if(LRCerror(len) == 1) return MODBUS_CHECKSUM_ERROR;
          return 8+byte_count;
        case ReadFifoQueue:
          sscanf((char *) &telptr[len],"%02X",&val); data[0] = (unsigned char) val; len += 2;
          sscanf((char *) &telptr[len],"%02X",&val); data[1] = (unsigned char) val; len += 2;
          if(LRCerror(len) == 1) return MODBUS_CHECKSUM_ERROR;
          return 2;
        default:
          return MODBUS_ERROR;
      }
    }
    else if(mode == MODBUS_RTU)
    {
      ret = tty->select(timeout);
      if(ret == 0)                    return MODBUS_ERROR;
      if(tty->readBlock(tel, 2) <= 0) return MODBUS_ERROR;
      *slave     = tel[len++];
      *function  = tel[len++];
      ret = tty->select(timeout);
      if(ret == 0)                    return MODBUS_ERROR;
      switch(*function)
      {
        case ReadCoilStatus:
        case ReadInputStatus:
        case ReadHoldingRegisters:
        case ReadInputRegisters:
        case ForceSingleCoil:
        case PresetSingleRegister:
          if(tty->readBlock(data, 4+2) <= 0)              return MODBUS_ERROR;
          memcpy(&tel[len],data,4+2); len += 4+2;
          if(CRCerror(len) == 1)                          return MODBUS_CHECKSUM_ERROR;
          return 4;
        case ReadExceptionStatus:
        case FetchCommEventCtr:
        case FetchCommEventLog:
        case ReportSlaveID:
          if(CRCerror(len) == 1)                          return MODBUS_CHECKSUM_ERROR;
          return 0;
        case ForceMultipleCoils:
        case PresetMultipleRegs:
          if(tty->readBlock(data, 5) <= 0)                return MODBUS_ERROR;
          memcpy(&tel[len],data,5); len += 5;
          byte_count = data[4];
          if(tty->readBlock(&data[4], byte_count+2) <= 0) return MODBUS_ERROR;
          memcpy(&tel[len],data,byte_count+2); len += byte_count+2;
          if(CRCerror(len) == 1)                          return MODBUS_CHECKSUM_ERROR;
          return 4+byte_count;
        case ReadGeneralReference:
        case WriteGeneralReference:
          if(tty->readBlock(data, 1) <= 0)                return MODBUS_ERROR;
          memcpy(&tel[len],data,1); len++;
          byte_count = data[0];
          if(tty->readBlock(data, byte_count+2) <= 0)     return MODBUS_ERROR;
          memcpy(&tel[len],data,byte_count+2); len += byte_count+2;
          if(CRCerror(len) == 1)                          return MODBUS_CHECKSUM_ERROR;
          return byte_count;
        case MaskWrite4XRegisters:
          if(tty->readBlock(data, 6+2) <= 0)              return MODBUS_ERROR;
          memcpy(&tel[len],data,6+2); len += 6+2;
          if(CRCerror(len) == 1)                          return MODBUS_CHECKSUM_ERROR;
          return 6;
        case ReadWrite4XRegisters:
          if(tty->readBlock(data, 9) <= 0)                return MODBUS_ERROR;
          memcpy(&tel[len],data,9); len += 9;
          byte_count = data[8];
          if(tty->readBlock(&data[8], byte_count+2) <= 0) return MODBUS_ERROR;
          memcpy(&tel[len],data,byte_count+2); len += byte_count+2;
          if(CRCerror(len) == 1)                          return MODBUS_CHECKSUM_ERROR;
          return 8+byte_count;
        case ReadFifoQueue:
          if(tty->readBlock(data, 2+2) <= 0)              return MODBUS_ERROR;
          memcpy(&tel[len],data,2+2); len += 2+2;
          if(CRCerror(len) == 1)                          return MODBUS_CHECKSUM_ERROR;
          return 2;
        default:
          return MODBUS_ERROR;
      }
    }
  }
  else return MODBUS_ERROR;
  return MODBUS_SUCCESS;
}
void rlModbus::registerSerial ( rlSerial serial)

Definition at line 591 of file rlmodbus.cpp.

{
  s = NULL;
  tty = serial;
}
void rlModbus::registerSocket ( rlSocket socket)

Definition at line 585 of file rlmodbus.cpp.

{
  tty = NULL;
  s = socket;
}
int rlModbus::request ( int  slave,
int  function,
int  start_adr,
int  num_register 
)

Definition at line 121 of file rlmodbus.cpp.

{
  unsigned char data[4];

  data[0] = (unsigned char) ( start_adr / 256 );
  data[1] = (unsigned char) ( start_adr & 0x0ff );
  data[2] = (unsigned char) ( num_register / 256 ); 
  data[3] = (unsigned char) ( num_register & 0x0ff );
  return write(slave, function, data, 4);
}
int rlModbus::response ( int *  slave,
int *  function,
unsigned char *  data,
int  timeout = 1000 
)

Definition at line 132 of file rlmodbus.cpp.

{
  unsigned char *telptr;
  int ret,len,byte_count,idata,i,itel,val;

  len = 0;
  if(mode != MODBUS_ASCII && mode != MODBUS_RTU) return MODBUS_ERROR;
  if(s != NULL)
  {
    if(s->isConnected() == 0) return MODBUS_ERROR;
    if(mode == MODBUS_RTU)
    {
      if(s->read((char *) tel, 6, timeout) <= 0) return MODBUS_ERROR;
      // bytes 0,1 Transaction ID faithfully copied from the request message
      // bytes 2,3 Protocol number always zero
      // byte 4 Response length (upper byte) Always zero
      // byte 5 Response length (lower byte). Equal to the number of bytes which follow
      // Here comes the normal Modus telegram
      if(s->read((char *) tel, 2, timeout) <= 0) return MODBUS_ERROR;
      *slave     = tel[0];
      *function  = tel[1];
      switch(*function)
      {
        case ReadCoilStatus:
        case ReadInputStatus:
        case ReadHoldingRegisters:
        case ReadInputRegisters:
        case FetchCommEventLog:
        case ReportSlaveID:
        case ReadGeneralReference:
        case WriteGeneralReference:
        case ReadWrite4XRegisters:
          if(s->read((char *) tel, 1, timeout) <= 0)            return MODBUS_ERROR;
          byte_count = tel[0];
          if(s->read((char *) data, byte_count, timeout) <= 0)  return MODBUS_ERROR;
          return byte_count;
        case ForceSingleCoil:
        case PresetSingleRegister:
        case FetchCommEventCtr:
        case ForceMultipleCoils:
        case PresetMultipleRegs:
          byte_count = 4;
          if(s->read((char *) data, byte_count, timeout) <= 0)  return MODBUS_ERROR;
          return byte_count;
        case ReadExceptionStatus:
          byte_count = 1;
          if(s->read((char *) data, byte_count, timeout) <= 0)  return MODBUS_ERROR;
          return byte_count;
        case MaskWrite4XRegisters:
          byte_count = 6;
          if(s->read((char *) data, byte_count, timeout) <= 0)  return MODBUS_ERROR;
          return byte_count;
        case ReadFifoQueue:
          if(s->read((char *) tel, 2, timeout) <= 0)            return MODBUS_ERROR;
          byte_count = tel[0]*256 + tel[1];
          if(s->read((char *) data, byte_count, timeout) <= 0)  return MODBUS_ERROR;
          return byte_count;
        default:
          return MODBUS_ERROR;
      }
    }
  }
  else if(tty != NULL)
  {
    if(mode == MODBUS_ASCII)
    {
      //printf("modbus ascii\n");
      for(i=0; i<maxtel; i++)
      {
        ret = tty->select(timeout);
        if(ret == 0) return MODBUS_ERROR;
        //printf("readChar\n");
        itel = tty->readChar();
        if(itel < 0) return MODBUS_ERROR;
        tel[i] = (unsigned char) itel;
        if(tel[i] == 0x0d && delimitor != 0x0a) break;
        if(tel[i] == 0x0a)                      break;
      }
      tel[i] = '\0';
      telptr = (unsigned char *) strchr((const char *) tel,':');
      if(telptr == NULL) return MODBUS_ERROR;
      len++;
      sscanf((char *) &telptr[len],"%02X",slave);       len += 2;
      sscanf((char *) &telptr[len],"%02X",function);    len += 2;
      switch(*function)
      {
        case ReadCoilStatus:
        case ReadInputStatus:
        case ReadHoldingRegisters:
        case ReadInputRegisters:
        case FetchCommEventLog:
        case ReportSlaveID:
        case ReadGeneralReference:
        case WriteGeneralReference:
        case ReadWrite4XRegisters:
          sscanf((char *) &telptr[len],"%02X",&byte_count);    len += 2;
          for(idata=0; idata<byte_count; idata++)
          {
            sscanf((const char *) &telptr[len], "%02X", &val); len += 2;
            data[idata] = val;
          }
          data[idata] = 0x0ff; // terminator, this data can't come over modbus
          if(LRCerror(len) == 1) return MODBUS_CHECKSUM_ERROR;
          return byte_count;
        case ForceSingleCoil:
        case PresetSingleRegister:
        case FetchCommEventCtr:
        case ForceMultipleCoils:
        case PresetMultipleRegs:
          byte_count = 8;
          for(idata=0; idata<(byte_count/2); idata++)
          {
            data[idata] = buf2int_ascii(&telptr[len]);     len += 2;
          }
          data[idata] = 0x0ff; // terminator, this data can't come over modbus
          if(LRCerror(len) == 1) return MODBUS_CHECKSUM_ERROR;
          return byte_count;
        case ReadExceptionStatus:
          byte_count = 2;
          for(idata=0; idata<(byte_count/2); idata++)
          {
            data[idata] = buf2int_ascii(&telptr[len]);     len += 2;
          }
          data[idata] = 0x0ff; // terminator, this data can't come over modbus
          if(LRCerror(len) == 1) return MODBUS_CHECKSUM_ERROR;
          return byte_count;
        case MaskWrite4XRegisters:
          byte_count = 12;
          for(idata=0; idata<(byte_count/2); idata++)
          {
            data[idata] = buf2int_ascii(&telptr[len]);     len += 2;
          }
          data[idata] = 0x0ff; // terminator, this data can't come over modbus
          if(LRCerror(len) == 1) return MODBUS_CHECKSUM_ERROR;
          return byte_count;
        case ReadFifoQueue:
          sscanf((char *) &telptr[len],"%04X",&byte_count); len += 4;
          for(idata=0; idata<(byte_count/2); idata++)
          {
            data[idata] = buf2int_ascii(&telptr[len]);     len += 2;
          }
          data[idata] = 0x0ff; // terminator, this data can't come over modbus
          if(LRCerror(len) == 1) return MODBUS_CHECKSUM_ERROR;
          return byte_count;
          break;
        default:
          return MODBUS_ERROR;
      }
    }
    else if(mode == MODBUS_RTU)
    {
      ret = tty->select(timeout);
      if(ret == 0)                    return MODBUS_ERROR;
      if(tty->readBlock(tel, 2) <= 0) return MODBUS_ERROR;
      *slave     = tel[len++];
      *function  = tel[len++];
      switch(*function)
      {
        case ReadCoilStatus:
        case ReadInputStatus:
        case ReadHoldingRegisters:
        case ReadInputRegisters:
        case FetchCommEventLog:
        case ReportSlaveID:
        case ReadGeneralReference:
        case WriteGeneralReference:
        case ReadWrite4XRegisters:
          if(tty->select(timeout) == 0)               return MODBUS_ERROR;
          if(tty->readBlock(&tel[len], 1) <= 0)       return MODBUS_ERROR;
          byte_count = tel[len++];
          if(tty->select(timeout) == 0)               return MODBUS_ERROR;
          if(tty->readBlock(data, byte_count+2) <= 0) return MODBUS_ERROR;
          memcpy(&tel[len],data,byte_count+2); len += byte_count + 2;
          if(CRCerror(len) == 1)                      return MODBUS_CHECKSUM_ERROR;
          return byte_count;
        case ForceSingleCoil:
        case PresetSingleRegister:
        case FetchCommEventCtr:
        case ForceMultipleCoils:
        case PresetMultipleRegs:
          byte_count = 4;
          if(tty->select(timeout) == 0)               return MODBUS_ERROR;
          if(tty->readBlock(data, byte_count+2) <= 0) return MODBUS_ERROR;
          memcpy(&tel[len],data,byte_count+2); len += byte_count + 2;
          if(CRCerror(len) == 1)                      return MODBUS_CHECKSUM_ERROR;
          return byte_count;
        case ReadExceptionStatus:
          byte_count = 1;
          if(tty->select(timeout) == 0)               return MODBUS_ERROR;
          if(tty->readBlock(data, byte_count+2) <= 0) return MODBUS_ERROR;
          memcpy(&tel[len],data,byte_count+2); len += byte_count + 2;
          if(CRCerror(len) == 1)                      return MODBUS_CHECKSUM_ERROR;
          return byte_count;
        case MaskWrite4XRegisters:
          byte_count = 6;
          if(tty->select(timeout) == 0)               return MODBUS_ERROR;
          if(tty->readBlock(data, byte_count+2) <= 0) return MODBUS_ERROR;
          memcpy(&tel[len],data,byte_count+2); len += byte_count + 2;
          if(CRCerror(len) == 1)                      return MODBUS_CHECKSUM_ERROR;
          return byte_count;
        case ReadFifoQueue:
          if(tty->select(timeout) == 0)               return MODBUS_ERROR;
          if(tty->readBlock(&tel[len], 2) <= 0)       return MODBUS_ERROR;
          byte_count = tel[len]*256 + tel[len+1]; len += 2;
          if(tty->select(timeout) == 0)               return MODBUS_ERROR;
          if(tty->readBlock(data, byte_count+2) <= 0) return MODBUS_ERROR;
          memcpy(&tel[len],data,byte_count+2); len += byte_count + 2;
          if(CRCerror(len) == 1)                      return MODBUS_CHECKSUM_ERROR;
          return byte_count;
        default:
          return MODBUS_ERROR;
      }
    }
  }
  else return MODBUS_ERROR;
  return MODBUS_SUCCESS;
}
int rlModbus::write ( int  slave,
int  function,
const unsigned char *  data,
int  len,
int *  transactionID = NULL 
)

Definition at line 54 of file rlmodbus.cpp.

{
  int len,i;

  if(slave < 0 || slave > 255) return MODBUS_ERROR;
  len = 0;
  if(mode == MODBUS_ASCII)
  {
    tel[len++] = ':';
    sprintf((char *) &tel[len], "%02X", slave);          len += 2;
    sprintf((char *) &tel[len], "%02X", function);       len += 2;
    for(i=0; i<datalen; i++)
    {
      sprintf((char *) &tel[len], "%02X",(int) data[i]); len += 2;
      if((len+4) > maxtel) return MODBUS_ERROR;
    }
    insertLRC(len);                                     len += 2;
    tel[len++] = 0x0d;
    if(delimitor == 0x0a) tel[len++] = 0x0a;
  }
  else if(mode == MODBUS_RTU)
  {
    if(s != NULL)
    {
      if(transactionID == NULL)
      {
        tel[len++] = 0;       // bytes 0,1 Transaction ID. Not important. Usually zero when making a request, the server will copy them faithfully into the response.
        tel[len++] = 0;
      }
      else
      {
        tel[len++] = ((*transactionID) & 0xFF00) / 256;         // bytes 0,1 Transaction ID.
        tel[len++] = (*transactionID) & 0xFF;
      }
      tel[len++] = 0;         // bytes 2,3 Protocol number. Must be zero.
      tel[len++] = 0;
      tel[len++] = 0;         // byte 4 Length (upper byte). Since all requests will be less than 256 bytes in length (!), this will always be zero.
      tel[len++] = 2+datalen; // byte 5 Length (lower byte). Equal to the number of bytes which follow
    }
    tel[len++] = (unsigned char) slave;
    tel[len++] = (unsigned char) function;
    for(i=0; i<datalen; i++)
    {
      tel[len++] = data[i];
      if((len+2) > maxtel) return MODBUS_ERROR;
    }
    insertCRC(len);                                     len += 2;
  }
  else return MODBUS_ERROR;

  if(s != NULL)
  {
    if(s->isConnected() == 0)
    {
      if(autoreconnectSocket) s->connect();
      if(s->isConnected() == 0) return MODBUS_ERROR;
    }
    if(s->write(tel,len-2) < 0) return MODBUS_ERROR; // don't send LRC or CRC
  }
  else if(tty != NULL)
  {
    if(tty->writeBlock(tel,len) < 0) return MODBUS_ERROR;
  }
  else return MODBUS_ERROR;
  return MODBUS_SUCCESS;
}

Member Data Documentation

Definition at line 72 of file rlmodbus.h.

char rlModbus::delimitor [private]

Definition at line 88 of file rlmodbus.h.

long rlModbus::maxtel [private]

Definition at line 86 of file rlmodbus.h.

int rlModbus::mode [private]

Definition at line 87 of file rlmodbus.h.

rlSocket* rlModbus::s [private]

Definition at line 83 of file rlmodbus.h.

unsigned char* rlModbus::tel [private]

Definition at line 85 of file rlmodbus.h.

rlSerial* rlModbus::tty [private]

Definition at line 84 of file rlmodbus.h.


The documentation for this class was generated from the following files: