Thread: Modbus Protocol RTU C conversion

  1. #1
    Registered User
    Join Date
    Feb 2015
    Posts
    13

    Modbus Protocol RTU C conversion

    Dear all
    I have the code for Modbus RTU in c++. can someone give me suggestion to convert in to c programming. or is there any c programming code available for modbus RTU with implemented library. I am using Modbus library for arduino Uno.

    Code:
    int8_tModbus::query(modbus_t telegram ){
      uint8_t u8regsno, u8bytesno;
      if(u8id !=0)return-2;
      if(u8state != COM_IDLE)return-1;
    
      if((telegram.u8id ==0)||(telegram.u8id >247))return-3;
    
      au16regs = telegram.au16reg;
    
      // telegram header
      au8Buffer[ ID ]= telegram.u8id;
      au8Buffer[ FUNC ]= telegram.u8fct;
      au8Buffer[ ADD_HI ]= highByte(telegram.u16RegAdd );
      au8Buffer[ ADD_LO ]= lowByte( telegram.u16RegAdd );
    
      switch( telegram.u8fct ){
      case MB_FC_READ_COILS:
      case MB_FC_READ_DISCRETE_INPUT:
      case MB_FC_READ_REGISTERS:
      case MB_FC_READ_INPUT_REGISTER:
        au8Buffer[ NB_HI ]= highByte(telegram.u16CoilsNo );
        au8Buffer[ NB_LO ]= lowByte( telegram.u16CoilsNo );
        u8BufferSize =6;
        break;
      case MB_FC_WRITE_COIL:
        au8Buffer[ NB_HI ]=((au16regs[0]>0)?0xff:0);
        au8Buffer[ NB_LO ]=0;
        u8BufferSize =6;
        break;
      case MB_FC_WRITE_REGISTER:
        au8Buffer[ NB_HI ]= highByte(au16regs[0]);
        au8Buffer[ NB_LO ]= lowByte(au16regs[0]);
        u8BufferSize =6;
        break;
      case MB_FC_WRITE_MULTIPLE_COILS:
        u8regsno = telegram.u16CoilsNo /16;
        u8bytesno = u8regsno *2;
        if((telegram.u16CoilsNo %16)!=0){
          u8bytesno++;
          u8regsno++;
        }
    
        au8Buffer[ NB_HI ]= highByte(telegram.u16CoilsNo );
        au8Buffer[ NB_LO ]= lowByte( telegram.u16CoilsNo );
        au8Buffer[ NB_LO +1]= u8bytesno;
        u8BufferSize =7;
    
        u8regsno = u8bytesno =0;// now auxiliary registers
        for(uint16_t i =0; i < telegram.u16CoilsNo; i++){
    
    
        }
        break;
    
      case MB_FC_WRITE_MULTIPLE_REGISTERS:
        au8Buffer[ NB_HI ]= highByte(telegram.u16CoilsNo );
        au8Buffer[ NB_LO ]= lowByte( telegram.u16CoilsNo );
        au8Buffer[ NB_LO +1]=(uint8_t)( telegram.u16CoilsNo *2);
        u8BufferSize =7;
    
        for(uint16_t i =0; i < telegram.u16CoilsNo; i++){
          au8Buffer[ u8BufferSize ]= highByte( au16regs[ i ]);
          u8BufferSize++;
          au8Buffer[ u8BufferSize ]= lowByte( au16regs[ i ]);
          u8BufferSize++;
        }
        break;
      }
    
      sendTxBuffer();
      u8state = COM_WAITING;
      return0;
    }
    
    int8_tModbus::poll(){
      // check if there is any incoming frame
      uint8_t u8current = port->available();
    
      if(millis()> u32timeOut){
        u8state = COM_IDLE;
        u16errCnt++;
        return0;
      }
    
      if(u8current ==0)return0;
    
      // check T35 after frame end or still no frame end
      if(u8current != u8lastRec){
        u8lastRec = u8current;
        u32time = millis()+ T35;
        return0;
      }
      if(millis()< u32time)return0;
    
      // transfer Serial buffer frame to auBuffer
      u8lastRec =0;
      int8_t i8state = getRxBuffer();
      if(i8state <7){
        u8state = COM_IDLE;
        u16errCnt++;
        return i8state;
      }
    
      // validate message: id, CRC, FCT, exception
      uint8_t u8exception = validateAnswer();
      if(u8exception !=0){
        u8state = COM_IDLE;
        return u8exception;
      }
    
      // process answer
      switch( au8Buffer[ FUNC ]){
      case MB_FC_READ_COILS:
      case MB_FC_READ_DISCRETE_INPUT:
        // call get_FC1 to transfer the incoming message to au16regs buffer
       // get_FC1( );
        break;
      case MB_FC_READ_INPUT_REGISTER:
      case MB_FC_READ_REGISTERS :
        // call get_FC3 to transfer the incoming message to au16regs buffer
        get_FC3();
        break;
      case MB_FC_WRITE_COIL:
      case MB_FC_WRITE_REGISTER :
      case MB_FC_WRITE_MULTIPLE_COILS:
      case MB_FC_WRITE_MULTIPLE_REGISTERS :
        // nothing to do
        break;
      default:
        break;
      }
      u8state = COM_IDLE;
      return u8BufferSize;
    }
    
    
    int8_tModbus::poll(uint16_t*regs,uint8_t u8size ){
    
      au16regs = regs;
      u8regsize = u8size;
    
      // check if there is any incoming frame
      uint8_t u8current = port->available();
      if(u8current ==0)return0;
    
      // check T35 after frame end or still no frame end
      if(u8current != u8lastRec){
        u8lastRec = u8current;
        u32time = millis()+ T35;
        return0;
      }
      if(millis()< u32time)return0;
    
      u8lastRec =0;
      int8_t i8state = getRxBuffer();
      if(i8state <7)return i8state;
    
      // check slave id
      if(au8Buffer[ ID ]!= u8id)return0;
    
      // validate message: CRC, FCT, address and size
      uint8_t u8exception = validateRequest();
      if(u8exception >0){
        if(u8exception != NO_REPLY){
          buildException( u8exception );
          sendTxBuffer();
        }
        return u8exception;
      }
    
      u32timeOut = millis()+long(u16timeOut);
    
      // process message
      switch( au8Buffer[ FUNC ]){
      case MB_FC_READ_COILS:
      case MB_FC_READ_DISCRETE_INPUT:
        return process_FC1( regs, u8size );
        break;
      case MB_FC_READ_INPUT_REGISTER:
      case MB_FC_READ_REGISTERS :
        return process_FC3( regs, u8size );
        break;
      case MB_FC_WRITE_COIL:
        return process_FC5( regs, u8size );
        break;
      case MB_FC_WRITE_REGISTER :
        return process_FC6( regs, u8size );
        break;
      case MB_FC_WRITE_MULTIPLE_COILS:
        return process_FC15( regs, u8size );
        break;
      case MB_FC_WRITE_MULTIPLE_REGISTERS :
        return process_FC16( regs, u8size );
        break;
      default:
        break;
      }
    }
    
    voidModbus::init(uint8_t u8id,uint8_t u8serno,uint8_t u8txenpin){
      this->u8id = u8id;
      this->u8serno =(u8serno >3)?0: u8serno;
      this->u8txenpin = u8txenpin;
      this->u16timeOut =1000;// intially set for 1000
    }
    
    
    int8_tModbus::getRxBuffer(){
      boolean bBuffOverflow =false;
    
      if(u8txenpin >1) digitalWrite( u8txenpin, LOW );
    
      u8BufferSize =0;
      while( port->available()){
        au8Buffer[ u8BufferSize ]= port->read();
        u8BufferSize ++;
    
        if(u8BufferSize >= MAX_BUFFER) bBuffOverflow =true;
      }
      u16InCnt++;
    
      if(bBuffOverflow){
        u16errCnt++;
        return ERR_BUFF_OVERFLOW;
      }
      u32timeOut=500;
       // u32timeOut = millis() + (unsigned long) u16timeOut;
      return u8BufferSize;
    }
    
    
    voidModbus::sendTxBuffer(){
      uint8_t i =0;
    
      // append CRC to message
      uint16_t u16crc = calcCRC( u8BufferSize );
      au8Buffer[ u8BufferSize ]= u16crc >>8;
      u8BufferSize++;
      au8Buffer[ u8BufferSize ]= u16crc &0x00ff;
      u8BufferSize++;
    
      // set RS485 transceiver to transmit mode
      if(u8txenpin >1){
        switch( u8serno ){
    #if defined(UBRR1H)
        case1:
          UCSR1A = UCSR1A |(1<< TXC1);
          break;
    #endif
    
    #if defined(UBRR2H)
        case2:
          UCSR2A = UCSR2A |(1<< TXC2);
          break;
    #endif
    
    #if defined(UBRR3H)
        case3:
          UCSR3A = UCSR3A |(1<< TXC3);
          break;
    #endif
        case0:
        default:
          UCSR0A = UCSR0A |(1<< TXC0);
          break;
        }
        digitalWrite( u8txenpin, HIGH );
      }
    
      // transfer buffer to serial line
      port->write( au8Buffer, u8BufferSize );
    
      // keep RS485 transceiver in transmit mode as long as sending
      if(u8txenpin >1){
        switch( u8serno ){
    #if defined(UBRR1H)
        case1:
          while(!(UCSR1A &(1<< TXC1)));
          break;
    #endif
    
    #if defined(UBRR2H)
        case2:
          while(!(UCSR2A &(1<< TXC2)));
          break;
    #endif
    
    #if defined(UBRR3H)
        case3:
          while(!(UCSR3A &(1<< TXC3)));
          break;
    #endif
        case0:
        default:
          while(!(UCSR0A &(1<< TXC0)));
          break;
        }
    
        // return RS485 transceiver to receive mode
        digitalWrite( u8txenpin, LOW );
      }
      port->flush();
      u8BufferSize =0;
    
      // set time-out for master
    //  u32timeOut = millis() + (unsigned long) u16timeOut;
     u32timeOut=500;
      // increase message counter
      u16OutCnt++;
    }
    
    
    
    uint16_tModbus::calcCRC(uint8_t u8length){
      unsignedint temp, temp2, flag;
      temp =0xFFFF;
      for(unsignedchar i =0; i < u8length; i++){
        temp = temp ^ au8Buffer[i];
        for(unsignedchar j =1; j <=8; j++){
          flag = temp &0x0001;
          temp >>=1;
          if(flag)
            temp ^=0xA001;
        }
      }
      // Reverse byte order.
      temp2 = temp >>8;
      temp =(temp <<8)| temp2;
      temp &=0xFFFF;
      // the returned value is already swapped
      // crcLo byte is first & crcHi byte is last
      return temp;
    }
    
    uint8_tModbus::validateRequest(){
      // check message crc vs calculated crc
      uint16_t u16MsgCRC =
        ((au8Buffer[u8BufferSize -2]<<8)
        | au8Buffer[u8BufferSize -1]);// combine the crc Low & High bytes
      if( calcCRC( u8BufferSize -2)!= u16MsgCRC ){
        u16errCnt ++;
        return NO_REPLY;
      }
    
      // check fct code
      boolean isSupported =false;
      for(uint8_t i =0; i <sizeof( fctsupported ); i++){
        if(fctsupported[i]== au8Buffer[FUNC]){
          isSupported =1;
          break;
        }
      }
      if(!isSupported){
        u16errCnt ++;
        return EXC_FUNC_CODE;
      }
    
      // check start address & nb range
     // uint16_t u16regs = 4000;
     uint16_t u16regs =0;
      uint8_t u8regs;
      switch( au8Buffer[ FUNC ]){
      case MB_FC_READ_COILS:
      case MB_FC_READ_DISCRETE_INPUT:
      case MB_FC_WRITE_MULTIPLE_COILS:
        u16regs = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ])/16;
        u16regs += word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ])/16;
        u8regs =(uint8_t) u16regs;
        if(u8regs > u8regsize)return EXC_ADDR_RANGE;
        break;
      case MB_FC_WRITE_COIL:
        u16regs = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ])/16;
        u8regs =(uint8_t) u16regs;
        if(u8regs > u8regsize)return EXC_ADDR_RANGE;
        break;
      case MB_FC_WRITE_REGISTER :
        u16regs = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]);
        u8regs =(uint8_t) u16regs;
        if(u8regs > u8regsize)return EXC_ADDR_RANGE;
        break;
      case MB_FC_READ_REGISTERS :
      case MB_FC_READ_INPUT_REGISTER :
      case MB_FC_WRITE_MULTIPLE_REGISTERS :
        u16regs = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]);
        u16regs += word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ]);
        u8regs =(uint8_t) u16regs;
        if(u8regs > u8regsize)return EXC_ADDR_RANGE;
        break;
      }
      return0;// OK, no exception code thrown
    }
    
    
    uint8_tModbus::validateAnswer(){
      // check message crc vs calculated crc
      uint16_t u16MsgCRC =
        ((au8Buffer[u8BufferSize -2]<<8)
        | au8Buffer[u8BufferSize -1]);// combine the crc Low & High bytes
      if( calcCRC( u8BufferSize -2)!= u16MsgCRC ){
        u16errCnt ++;
        return NO_REPLY;
      }
    
      // check exception
      if((au8Buffer[ FUNC ]&0x80)!=0){
        u16errCnt ++;
        return ERR_EXCEPTION;
      }
    
      // check fct code
      boolean isSupported =false;
      for(uint8_t i =0; i <sizeof( fctsupported ); i++){
        if(fctsupported[i]== au8Buffer[FUNC]){
          isSupported =1;
          break;
        }
      }
      if(!isSupported){
        u16errCnt ++;
        return EXC_FUNC_CODE;
      }
    
      return0;// OK, no exception code thrown
    }
    
    
    voidModbus::buildException(uint8_t u8exception ){
      uint8_t u8func = au8Buffer[ FUNC ];// get the original FUNC code
    
      au8Buffer[ ID ]= u8id;
      au8Buffer[ FUNC ]= u8func +0x80;
      au8Buffer[2]= u8exception;
      u8BufferSize         = EXCEPTION_SIZE;
    }

    Code:
    voidModbus::get_FC3(){
      uint8_t u8byte, i;
      u8byte =3;
    
      for(i =0; i < au8Buffer[2]/2; i++){
        au16regs[ i ]= word(
        au8Buffer[ u8byte ],
        au8Buffer[ u8byte +1]);
        u8byte +=2;
      }
    }
    
    
    int8_tModbus::process_FC1(uint16_t*regs,uint8_t u8size ){
      uint8_t u8currentRegister, u8currentBit, u8bytesno, u8bitsno;
      uint8_t u8CopyBufferSize;
      uint16_t u16currentCoil, u16coil;
    
      // get the first and last coil from the message
      uint16_t u16StartCoil = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]);
      uint16_t u16Coilno = word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ]);
    
      // put the number of bytes in the outcoming message
      u8bytesno =(uint8_t)(u16Coilno /8);
      if(u16Coilno %8!=0) u8bytesno ++;
      au8Buffer[ ADD_HI ]= u8bytesno;
      u8BufferSize         = ADD_LO;
    
      // read each coil from the register map and put its value inside the outcoming message
      u8bitsno =0;
    
      for(u16currentCoil =0; u16currentCoil < u16Coilno; u16currentCoil++){
        u16coil = u16StartCoil + u16currentCoil;
        u8currentRegister =(uint8_t)(u16coil /16);
        u8currentBit =(uint8_t)(u16coil %16);
    
        bitWrite(
        au8Buffer[ u8BufferSize ],
        u8bitsno,
        bitRead( regs[ u8currentRegister ], u8currentBit ));
        u8bitsno ++;
    
        if(u8bitsno >7){
          u8bitsno =0;
          u8BufferSize++;
        }
      }
    
      // send outcoming message
      if(u16Coilno %8!=0) u8BufferSize ++;
      u8CopyBufferSize = u8BufferSize +2;
      sendTxBuffer();
      return u8CopyBufferSize;
    }
    
    int8_tModbus::process_FC3(uint16_t*regs,uint8_t u8size ){
    
      uint8_t u8StartAdd = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]);
      uint8_t u8regsno = word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ]);
      uint8_t u8CopyBufferSize;
      uint8_t i;
    
      au8Buffer[2]= u8regsno *2;
      u8BufferSize         =3;
    
      for(i = u8StartAdd; i < u8StartAdd + u8regsno; i++){
        au8Buffer[ u8BufferSize ]= highByte(regs[i]);
        u8BufferSize++;
        au8Buffer[ u8BufferSize ]= lowByte(regs[i]);
        u8BufferSize++;
      }
      u8CopyBufferSize = u8BufferSize +2;
      sendTxBuffer();
    
      return u8CopyBufferSize;
    }
    
    
    int8_tModbus::process_FC5(uint16_t*regs,uint8_t u8size ){
      uint8_t u8currentRegister, u8currentBit;
      uint8_t u8CopyBufferSize;
      uint16_t u16coil = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]);
    
      // point to the register and its bit
      u8currentRegister =(uint8_t)(u16coil /16);
      u8currentBit =(uint8_t)(u16coil %16);
    
      // write to coil
      bitWrite(
      regs[ u8currentRegister ],
      u8currentBit,
      au8Buffer[ NB_HI ]==0xff);
    
    
      // send answer to master
      u8BufferSize =6;
      u8CopyBufferSize = u8BufferSize +2;
      sendTxBuffer();
    
      return u8CopyBufferSize;
    
    }
    
    
    int8_tModbus::process_FC6(uint16_t*regs,uint8_t u8size ){
    
      uint8_t u8add = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]);
      uint8_t u8CopyBufferSize;
      uint16_t u16val = word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ]);
    
      regs[ u8add ]= u16val;
    
      // keep the same header
      u8BufferSize         = RESPONSE_SIZE;
    
      u8CopyBufferSize = u8BufferSize +2;
      sendTxBuffer();
    
      return u8CopyBufferSize;
    }
    
    
    int8_tModbus::process_FC15(uint16_t*regs,uint8_t u8size ){
      uint8_t u8currentRegister, u8currentBit, u8frameByte, u8bitsno;
      uint8_t u8CopyBufferSize;
      uint16_t u16currentCoil, u16coil;
      boolean bTemp;
    
      // get the first and last coil from the message
      uint16_t u16StartCoil = word( au8Buffer[ ADD_HI ], au8Buffer[ ADD_LO ]);
      uint16_t u16Coilno = word( au8Buffer[ NB_HI ], au8Buffer[ NB_LO ]);
    
    
      // read each coil from the register map and put its value inside the outcoming message
      u8bitsno =0;
      u8frameByte =7;
      for(u16currentCoil =0; u16currentCoil < u16Coilno; u16currentCoil++){
    
        u16coil = u16StartCoil + u16currentCoil;
        u8currentRegister =(uint8_t)(u16coil /16);
        u8currentBit =(uint8_t)(u16coil %16);
    
        bTemp = bitRead(
        au8Buffer[ u8frameByte ],
        u8bitsno );
    
        bitWrite(
        regs[ u8currentRegister ],
        u8currentBit,
        bTemp );
    
        u8bitsno ++;
    
        if(u8bitsno >7){
          u8bitsno =0;
          u8frameByte++;
        }
      }
    
      // send outcoming message
      // it's just a copy of the incomping frame until 6th byte
      u8BufferSize         =6;
      u8CopyBufferSize = u8BufferSize +2;
      sendTxBuffer();
      return u8CopyBufferSize;
    }
    
    
    int8_tModbus::process_FC16(uint16_t*regs,uint8_t u8size ){
      uint8_t u8func = au8Buffer[ FUNC ];// get the original FUNC code
      uint8_t u8StartAdd = au8Buffer[ ADD_HI ]<<8| au8Buffer[ ADD_LO ];
      uint8_t u8regsno = au8Buffer[ NB_HI ]<<8| au8Buffer[ NB_LO ];
      uint8_t u8CopyBufferSize;
      uint8_t i;
      uint16_t temp;
    
      // build header
      au8Buffer[ NB_HI ]=0;
      au8Buffer[ NB_LO ]= u8regsno;
      u8BufferSize         = RESPONSE_SIZE;
    
      // write registers
      for(i =0; i < u8regsno; i++){
        temp = word(
        au8Buffer[(BYTE_CNT +1)+ i *2],
        au8Buffer[(BYTE_CNT +2)+ i *2]);
    
        regs[ u8StartAdd + i ]= temp;
      }
      u8CopyBufferSize = u8BufferSize +2;
      sendTxBuffer();
    
      return u8CopyBufferSize;
    }

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Modbus RTU - Google Search

    If that fails, you can always do this to your code.
    Code:
    class Foo {
      private:
        int mMember;
      public:
        void method( int param );
    };
    
    void Foo::method ( int param ) {
      mMember = param;
    }
    Would become
    Code:
    struct Foo {
    //  private:
        int mMember;
    //  public:
    //    void method( int param );
    };
    
    void Foo_method ( struct Foo *this, int param ) {
      this->mMember = param;
    }
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Feb 2015
    Posts
    13

    Lightbulb

    I have decided to go with same code with minor changes in hardware.Actually i wanted to make work on 57600 baudrate and change send request has per the me.

    glob.h.pdfModbus Protocol RTU  C conversion-modbus-request-jpgModbus code.pdf

    I have attached my compete code and request format here. I am trying to send request for every 30s. The request has been send but there is no response from slave device. This will haven 1 in 10 request send for every 30S

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    You could try a lower baud rate - 60 byes every 30 seconds is hardly high bandwidth.

    Your modbus code.pdf file is empty by the way.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Modbus arduino library
    By ajitnayak87 in forum C++ Programming
    Replies: 2
    Last Post: 02-10-2015, 11:13 PM
  2. Modbus Implimentation code
    By AJITnayak in forum C Programming
    Replies: 1
    Last Post: 04-09-2014, 11:56 AM
  3. modbus rtu c programming
    By barramundi9 in forum Networking/Device Communication
    Replies: 5
    Last Post: 08-02-2012, 09:32 PM
  4. Replies: 4
    Last Post: 04-10-2012, 10:51 AM
  5. TCP IP Modbus
    By boschow in forum Networking/Device Communication
    Replies: 0
    Last Post: 03-27-2008, 12:20 PM

Tags for this Thread