jecrespo / phpmodbus

Automatically exported from code.google.com/p/phpmodbus
Other
0 stars 0 forks source link

Implementing Modbus Read Input Registers 04 (0x04) #22

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
We are working with a modbus device using all kind of holding and input 
registers. (Here input register are labelled according to doc: MODBUS 
APPLICATION PROTOCOL SPECIFICATION V1.1b3). We need to read information from 
both register types and the device follows the register addressing and function 
codes to read them canonically.

Looking at the protocol there is no fundamental difference between the already 
implemented FC3 and the proposed FC4 function codes besides the function code 
used on the modbus interface.

We propose the following addition to the code to handle FC4:

    // Patch 2013-03-08 to introduce FC4 read input registers

  /**
   * readMultipleInputRegisters
   *
   * Modbus function FC 4(0x04) - Read Multiple Input Registers.
   * 
   * This function reads {@link $quantity} of Words (2 bytes) from reference 
   * {@link $referenceRead} of a memory of a Modbus device given by 
   * {@link $unitId}.
   *    
   *
   * @param int $unitId usually ID of Modbus device 
   * @param int $reference Reference in the device memory to read data.
   * @param int $quantity Amounth of the data to be read from device.
   * @return false|Array Success flag or array of received data.
   */
  function readMultipleInputRegisters($unitId, $reference, $quantity){
    $this->status .= "readMultipleInputRegisters: START\n";
    // connect
    $this->connect();
    // send FC 4    
    $packet = $this->readMultipleInputRegistersPacketBuilder($unitId, $reference, $quantity);
    $this->status .= $this->printPacket($packet);    
    $this->send($packet);
    // receive response
    $rpacket = $this->rec();
    $this->status .= $this->printPacket($rpacket);    
    // parse packet    
    $receivedData = $this->readMultipleInputRegistersParser($rpacket);
    // disconnect
    $this->disconnect();
    $this->status .= "readMultipleInputRegisters: DONE\n";
    // return
    return $receivedData;
  }

  /**
   * fc4
   *
   * Alias to {@link readMultipleInputRegisters} method.
   *
   * @param int $unitId
   * @param int $reference
   * @param int $quantity
   * @return false|Array
   */
  function fc4($unitId, $reference, $quantity){
    return $this->readMultipleInputRegisters($unitId, $reference, $quantity);
  }  

  /**
   * readMultipleInputRegistersPacketBuilder
   *
   * Packet FC 4 builder - read multiple input registers
   *
   * @param int $unitId
   * @param int $reference
   * @param int $quantity
   * @return string
   */
  private function readMultipleInputRegistersPacketBuilder($unitId, $reference, $quantity){
    $dataLen = 0;
    // build data section
    $buffer1 = "";
    // build body
    $buffer2 = "";
    $buffer2 .= iecType::iecBYTE(4);                                                // FC 4 = 4(0x04)
    // build body - read section    
    $buffer2 .= iecType::iecINT($reference);                                        // refnumber = 12288      
    $buffer2 .= iecType::iecINT($quantity);                                         // quantity
    $dataLen += 5;
    // build header
    $buffer3 = '';
    $buffer3 .= iecType::iecINT(rand(0,65000));                                     // transaction ID
    $buffer3 .= iecType::iecINT(0);                                                 // protocol ID
    $buffer3 .= iecType::iecINT($dataLen + 1);                                      // lenght
    $buffer3 .= iecType::iecBYTE($unitId);                                          // unit ID
    // return packet string
    return $buffer3. $buffer2. $buffer1;
  }

  /**
   * readMultipleInputRegistersParser
   *
   * FC 4 response parser
   *
   * @param string $packet
   * @return array
   */
  private function readMultipleInputRegistersParser($packet){    
    $data = array();
    // check Response code
    $this->responseCode($packet);
    // get data
    for($i=0;$i<ord($packet[8]);$i++){
      $data[$i] = ord($packet[9+$i]);
    }    
    return $data;
  }
    // End of patch 2013-03-08

As the original modbus document calls FC3 Read Holding Registers The proposed 
solution leaves the existing FC3 as PHP function readMultipleRegisters and 
introduces FC4 as readMultipleInputRegisters

Original issue reported on code.google.com by sardnai...@gmail.com on 8 Mar 2013 at 2:13

GoogleCodeExporter commented 9 years ago
Implementation of FC 04 to read input registers would be great. I am able to 
read and write coil, but I also need to read data from both holding registers 
0x03 and input registers 0x04. Is it even possible to read input registers (in 
0x04) range using the current readMultipleRegisters function. If it is how 
would I represent register 3594 ? 
Thanks  

Original comment by prajjw...@gmail.com on 8 Mar 2013 at 8:45

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
I am not a modbus expert, but looking at the document and the implementation of 
the modbus device I am working with allows fairly flexible implementation (from 
the eqipment vendor's side).

In the specification (Modbus Application Protocol V1_1b3 ) 4 distinct memory 
maps are defined.

Discrete Input    - Single Bit - Read Only       - FC02 Implemented in 
Phpmodbus already
Coils             - Single Bit - Read and Write  - FC01 Implemented in 
Phpmodbus already
Input Registers   - 16bit word - Read Only       - FC04 Proposal issue 22
Holding Registers - 16bit word - Read and Write  - FC03 Implemented in Phpmodbus

According to the modbus specification: "The pre-mapping between the MODBUS data 
model and the device application is totally vendor device specific."

In our implementation Iskra Elekronical Analyser we have the following maps:

                 Logical address   Command to Read Physical Address (used within the read command)
Coil              00001 - 09999    FC01            1-9999 
Discrete Input    10001 - 19999    FC02            1-9999
Input Registers   30001 - 39999    FC04            1-9999
Holding Registers 40001 - 49999    FC03            1-9999

Original comment by sardnai...@gmail.com on 10 Mar 2013 at 3:47

GoogleCodeExporter commented 9 years ago
To answer your question: correctly implemented modbus device should not allow 
reading of  an input register with the currently implemented 
readMultipleRegisters which maps to FC03 and reads (and addresses) only memory 
were holding registers are stored.

The representation of the 3594 depends on the modbus mapping implementation of 
the device. Either a detailed device document describing the modbus 
implementation of the particular device or a talk to the vendor shall clear the 
addressing issue for you.

Original comment by sardnai...@gmail.com on 10 Mar 2013 at 3:51

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
3594 is an input register so its logical address would be, 33595. When we use a 
built-in modbus master protocal of a PLC or HMI device to read a modbus slave 
device's input registers using  function 04 then that 30001 is automatically 
assumed, and 3594 was just one of the many input registers that I need to read.

The device I am dealing with has similar mapping like yours, 
                 Logical address   Command to Read Physical Address (used within the read command)
Coil              00001 - 09999    FC01            1-9999 
Discrete Input    10001 - 19999    FC02            1-9999
Input Registers   30001 - 39999    FC04            1-9999
Holding Registers 40001 - 49999    FC03            1-9999

Is the readMultipleInputRegisters function you propose functional, has it been 
tested ?

Original comment by prajjw...@gmail.com on 11 Mar 2013 at 3:41

GoogleCodeExporter commented 9 years ago
I used/tested readMultipleInputRegisters to read input registers and was 
successful in doing so. 

Original comment by prajjw...@gmail.com on 12 Mar 2013 at 1:49

GoogleCodeExporter commented 9 years ago
Added to revision r103, thanks sardnailap

Original comment by krakora....@googlemail.com on 9 Jul 2013 at 8:56