refactor all packet related or socket related code to separate classes

pull/2/head
toimtoimtoim 8 years ago
parent 5e8b3159a3
commit c7c4431b1c
  1. 884
      src/ModbusMaster.php
  2. 325
      src/ModbusSocket.php
  3. 65
      src/Packet/MaskWriteRegisterPacket.php
  4. 88
      src/Packet/ReadCoilsPacket.php
  5. 64
      src/Packet/ReadInputDiscretesPacket.php
  6. 68
      src/Packet/ReadMultipleInputRegistersPacket.php
  7. 67
      src/Packet/ReadMultipleRegistersPacket.php
  8. 102
      src/Packet/ReadWriteRegistersPacket.php
  9. 89
      src/Packet/WriteMultipleCoilsPacket.php
  10. 85
      src/Packet/WriteMultipleRegisterPacket.php
  11. 70
      src/Packet/WriteSingleCoilPacket.php
  12. 68
      src/Packet/WriteSingleRegisterPacket.php
  13. 2
      tests/ModbusMaster/UdpFc1ReadCoilsTest.php

File diff suppressed because it is too large Load Diff

@ -0,0 +1,325 @@
<?php
/**
* Phpmodbus Copyright (c) 2004, 2013 Jan Krakora
*
* This source file is subject to the "PhpModbus license" that is bundled
* with this package in the file license.txt.
*
* @copyright Copyright (c) 2004, 2013 Jan Krakora
* @license PhpModbus license
* @category Phpmodbus
* @tutorial Phpmodbus.pkg
* @package Phpmodbus
* @version $id$
*/
namespace PHPModbus;
use InvalidArgumentException;
class ModbusSocket
{
/**
* @var string (optional) client IP address when binding client
*/
protected $client = '';
/**
* @var string client port set when binding client to local ip&port
*/
protected $client_port = 502;
/**
* @var float Total response timeout (seconds, decimals allowed)
*/
protected $timeout_sec = 5;
/**
* @var float Socket read timeout (seconds, decimals allowed)
*/
protected $socket_read_timeout_sec = 0.3;
/**
* @var float Socket write timeout (seconds, decimals allowed)
*/
protected $socket_write_timeout_sec = 1; // 300 ms
/**
* @var string Socket protocol (TCP, UDP)
*/
protected $socket_protocol = 'UDP';
/**
* @var string Modbus device IP address
*/
protected $host = '192.168.1.1';
/**
* @var string gateway port
*/
protected $port = 502;
/**
* @var resource Communication socket
*/
protected $sock;
/**
* @var array status messages
*/
protected $statusMessages = [];
public static function getBuilder() {
return new ModbusSocketBuilder();
}
/**
* connect
*
* Connect the socket
*
* @return bool
* @throws \InvalidArgumentException
* @throws \PHPModbus\IOException
*/
public function connect()
{
// Create a protocol specific socket
if ($this->socket_protocol === 'TCP') {
// TCP socket
$this->sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
} elseif ($this->socket_protocol === 'UDP') {
// UDP socket
$this->sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
} else {
throw new InvalidArgumentException("Unknown socket protocol, should be 'TCP' or 'UDP'");
}
// Bind the client socket to a specific local port
if (strlen($this->client) > 0) {
$result = socket_bind($this->sock, $this->client, $this->client_port);
if ($result === false) {
throw new IOException(
"socket_bind() failed. Reason: ($result)" .
socket_strerror(socket_last_error($this->sock))
);
} else {
$this->statusMessages[] = 'Bound';
}
}
// Socket settings (send/write timeout)
$writeTimeout = $this->secsToSecUsecArray($this->socket_write_timeout_sec);
socket_set_option($this->sock, SOL_SOCKET, SO_SNDTIMEO, $writeTimeout);
// Connect the socket
$result = @socket_connect($this->sock, $this->host, $this->port);
if ($result === false) {
throw new IOException(
"socket_connect() failed. Reason: ($result)" .
socket_strerror(socket_last_error($this->sock))
);
} else {
$this->statusMessages[] = 'Connected';
return true;
}
}
/**
* receive
*
* Receive data from the socket
*
* @return bool
* @throws \Exception
*/
public function receive()
{
socket_set_nonblock($this->sock);
$readsocks[] = $this->sock;
$writesocks = null;
$exceptsocks = null;
$rec = '';
$totalReadTimeout = $this->timeout_sec;
$lastAccess = microtime(true);
$readTout = $this->secsToSecUsecArray($this->socket_read_timeout_sec);
while (false !== socket_select($readsocks, $writesocks, $exceptsocks, $readTout['sec'], $readTout['usec'])) {
$this->statusMessages[] = 'Wait data ... ';
if (in_array($this->sock, $readsocks, false)) {
if (@socket_recv($this->sock, $rec, 2000, 0)) { // read max 2000 bytes
$this->statusMessages[] = 'Data received';
return $rec;
}
$lastAccess = microtime(true);
} else {
$timeSpentWaiting = microtime(true) - $lastAccess;
if ($timeSpentWaiting >= $totalReadTimeout) {
throw new IOException(
"Watchdog time expired [ $totalReadTimeout sec ]!!! " .
"Connection to $this->host:$this->port is not established."
);
}
}
$readsocks[] = $this->sock;
}
return null;
}
/**
* send
*
* Send the packet via Modbus
*
* @param string $packet
*/
public function send($packet)
{
socket_write($this->sock, $packet, strlen($packet));
$this->statusMessages[] = 'Send';
}
/**
* close
*
* Close the socket
*/
public function close()
{
if (is_resource($this->sock)) {
socket_close($this->sock);
$this->statusMessages[] = 'Disconnected';
}
}
/**
* Close socket it still open
*/
public function __destruct()
{
$this->close();
}
/**
* Convert float in seconds to array
*
* @param float $secs
* @return array {sec: ..., usec: ...}
*/
private function secsToSecUsecArray($secs)
{
$remainder = $secs - floor($secs);
return [
'sec' => round($secs - $remainder),
'usec' => round($remainder * 1e6),
];
}
/**
* @return array
*/
public function getStatusMessages()
{
return $this->statusMessages;
}
}
class ModbusSocketBuilder extends ModbusSocket
{
/**
* @var ModbusSocket instance to be built
*/
private $modbusSocket;
public function __construct()
{
$this->modbusSocket = new ModbusSocket();
}
/**
* Return built instance of ModbusSocket
*
* @return ModbusSocket built instance
*/
public function build()
{
return $this->modbusSocket;
}
/**
* @param string $client
* @return ModbusSocketBuilder
*/
public function setClient($client)
{
$this->modbusSocket->client = $client;
return $this;
}
/**
* @param string $client_port
* @return ModbusSocketBuilder
*/
public function setClientPort($client_port)
{
$this->modbusSocket->client_port = $client_port;
return $this;
}
/**
* @param float $timeout_sec
* @return ModbusSocketBuilder
*/
public function setTimeoutSec($timeout_sec)
{
$this->modbusSocket->timeout_sec = $timeout_sec;
return $this;
}
/**
* @param float $socket_read_timeout_sec
* @return ModbusSocketBuilder
*/
public function setSocketReadTimeoutSec($socket_read_timeout_sec)
{
$this->modbusSocket->socket_read_timeout_sec = $socket_read_timeout_sec;
return $this;
}
/**
* @param float $socket_write_timeout_sec
* @return ModbusSocketBuilder
*/
public function setSocketWriteTimeoutSec($socket_write_timeout_sec)
{
$this->modbusSocket->socket_write_timeout_sec = $socket_write_timeout_sec;
return $this;
}
/**
* @param string $socket_protocol
* @return ModbusSocketBuilder
*/
public function setSocketProtocol($socket_protocol)
{
$this->modbusSocket->socket_protocol = $socket_protocol;
return $this;
}
/**
* @param string $host
* @return ModbusSocketBuilder
*/
public function setHost($host)
{
$this->modbusSocket->host = $host;
return $this;
}
/**
* @param string $port
* @return ModbusSocketBuilder
*/
public function setPort($port)
{
$this->modbusSocket->port = $port;
return $this;
}
}

@ -0,0 +1,65 @@
<?php
/**
* Phpmodbus Copyright (c) 2004, 2013 Jan Krakora
*
* This source file is subject to the "PhpModbus license" that is bundled
* with this package in the file license.txt.
*
* @copyright Copyright (c) 2004, 2013 Jan Krakora
* @license PhpModbus license
* @category Phpmodbus
* @tutorial Phpmodbus.pkg
* @package Phpmodbus
* @version $id$
*/
namespace PHPModbus\Packet;
use PHPModbus\IecType;
class MaskWriteRegisterPacket
{
/**
* Packet builder FC22 - MASK WRITE register
*
* @param int $unitId
* @param int $reference
* @param int $andMask
* @param int $orMask
* @return string
*/
public static function build($unitId, $reference, $andMask, $orMask)
{
$dataLen = 0;
// build data section
$buffer1 = '';
// build body
$buffer2 = '';
$buffer2 .= IecType::iecBYTE(22); // FC 22 = 22(0x16)
$buffer2 .= IecType::iecINT($reference); // refnumber = 12288
$buffer2 .= IecType::iecINT($andMask); // AND mask
$buffer2 .= IecType::iecINT($orMask); // OR mask
$dataLen += 7;
// build header
$buffer3 = '';
$buffer3 .= IecType::iecINT(mt_rand(0, 65000)); // transaction ID
$buffer3 .= IecType::iecINT(0); // protocol ID
$buffer3 .= IecType::iecINT($dataLen + 1); // lenght
$buffer3 .= IecType::iecBYTE($unitId); //unit ID
return $buffer3 . $buffer2 . $buffer1;
}
/**
* FC22 response parser
*
* @param string $packet
* @return bool
* @throws \Exception
*/
public static function parse($packet)
{
return true;
}
}

@ -0,0 +1,88 @@
<?php
/**
* Phpmodbus Copyright (c) 2004, 2013 Jan Krakora
*
* This source file is subject to the "PhpModbus license" that is bundled
* with this package in the file license.txt.
*
* @copyright Copyright (c) 2004, 2013 Jan Krakora
* @license PhpModbus license
* @category Phpmodbus
* @tutorial Phpmodbus.pkg
* @package Phpmodbus
* @version $id$
*/
namespace PHPModbus\Packet;
use PHPModbus\IecType;
class ReadCoilsPacket
{
/**
* FC1 packet builder - read coils
*
* @param int $unitId
* @param int $reference
* @param int $quantity
* @return string
*/
public static function build($unitId, $reference, $quantity)
{
$dataLen = 0;
// build data section
$buffer1 = '';
// build body
$buffer2 = '';
$buffer2 .= IecType::iecBYTE(1); // FC 1 = 1(0x01)
// build body - read section
$buffer2 .= IecType::iecINT($reference); // refnumber = 12288
$buffer2 .= IecType::iecINT($quantity); // quantity
$dataLen += 5;
// build header
$buffer3 = '';
$buffer3 .= IecType::iecINT(mt_rand(0, 65000)); // transaction ID
$buffer3 .= IecType::iecINT(0); // protocol ID
$buffer3 .= IecType::iecINT($dataLen + 1); // length
$buffer3 .= IecType::iecBYTE($unitId); //unit ID
return $buffer3 . $buffer2 . $buffer1;
}
/**
* FC 1 response parser
*
* @param string $packet
* @param int $quantity
* @return bool[]
* @throws \Exception
*/
public static function parse($packet, $quantity)
{
$data = array();
for ($i = 0, $len = ord($packet[8]); $i < $len; $i++) {
$data[$i] = ord($packet[9 + $i]);
}
// get bool values to array
$data_boolean_array = array();
$di = 0;
foreach ($data as $value) {
for ($i = 0; $i < 8; $i++) {
if ($di == $quantity) {
continue;
}
// get boolean value
$v = ($value >> $i) & 0x01;
// build boolean array
if ($v == 0) {
$data_boolean_array[] = false;
} else {
$data_boolean_array[] = true;
}
$di++;
}
}
return $data_boolean_array;
}
}

@ -0,0 +1,64 @@
<?php
/**
* Phpmodbus Copyright (c) 2004, 2013 Jan Krakora
*
* This source file is subject to the "PhpModbus license" that is bundled
* with this package in the file license.txt.
*
* @copyright Copyright (c) 2004, 2013 Jan Krakora
* @license PhpModbus license
* @category Phpmodbus
* @tutorial Phpmodbus.pkg
* @package Phpmodbus
* @version $id$
*/
namespace PHPModbus\Packet;
use PHPModbus\IecType;
class ReadInputDiscretesPacket
{
/**
* FC2 packet builder - read coils
*
* @param int $unitId
* @param int $reference
* @param int $quantity
* @return string
*/
public static function build($unitId, $reference, $quantity)
{
$dataLen = 0;
// build data section
$buffer1 = '';
// build body
$buffer2 = '';
$buffer2 .= IecType::iecBYTE(2); // FC 2 = 2(0x02)
// build body - read section
$buffer2 .= IecType::iecINT($reference); // refnumber = 12288
$buffer2 .= IecType::iecINT($quantity); // quantity
$dataLen += 5;
// build header
$buffer3 = '';
$buffer3 .= IecType::iecINT(mt_rand(0, 65000)); // transaction ID
$buffer3 .= IecType::iecINT(0); // protocol ID
$buffer3 .= IecType::iecINT($dataLen + 1); // lenght
$buffer3 .= IecType::iecBYTE($unitId); //unit ID
return $buffer3 . $buffer2 . $buffer1;
}
/**
* FC 2 response parser, alias to FC 1 parser i.e. readCoilsParser.
*
* @param string $packet
* @param int $quantity
* @return bool[]
* @throws \Exception
*/
public static function parse($packet, $quantity)
{
return ReadCoilsPacket::parse($packet, $quantity);
}
}

@ -0,0 +1,68 @@
<?php
/**
* Phpmodbus Copyright (c) 2004, 2013 Jan Krakora
*
* This source file is subject to the "PhpModbus license" that is bundled
* with this package in the file license.txt.
*
* @copyright Copyright (c) 2004, 2013 Jan Krakora
* @license PhpModbus license
* @category Phpmodbus
* @tutorial Phpmodbus.pkg
* @package Phpmodbus
* @version $id$
*/
namespace PHPModbus\Packet;
use PHPModbus\IecType;
class ReadMultipleInputRegistersPacket
{
/**
* Packet FC 4 builder - read multiple input registers
*
* @param int $unitId
* @param int $reference
* @param int $quantity
* @return string
*/
public static function build($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(mt_rand(0, 65000)); // transaction ID
$buffer3 .= IecType::iecINT(0); // protocol ID
$buffer3 .= IecType::iecINT($dataLen + 1); // length
$buffer3 .= IecType::iecBYTE($unitId); // unit ID
return $buffer3 . $buffer2 . $buffer1;
}
/**
* FC 4 response parser
*
* @param string $packet
* @return array
* @throws \Exception
*/
public static function parse($packet)
{
$data = array();
for ($i = 0, $len = ord($packet[8]); $i < $len; $i++) {
$data[$i] = ord($packet[9 + $i]);
}
return $data;
}
}

@ -0,0 +1,67 @@
<?php
/**
* Phpmodbus Copyright (c) 2004, 2013 Jan Krakora
*
* This source file is subject to the "PhpModbus license" that is bundled
* with this package in the file license.txt.
*
* @copyright Copyright (c) 2004, 2013 Jan Krakora
* @license PhpModbus license
* @category Phpmodbus
* @tutorial Phpmodbus.pkg
* @package Phpmodbus
* @version $id$
*/
namespace PHPModbus\Packet;
use PHPModbus\IecType;
class ReadMultipleRegistersPacket
{
/**
* @param int $unitId
* @param int $reference
* @param int $quantity
* @return string
*/
public static function build($unitId, $reference, $quantity)
{
$dataLen = 0;
// build data section
$buffer1 = '';
// build body
$buffer2 = '';
$buffer2 .= IecType::iecBYTE(3); // FC 3 = 3(0x03)
// build body - read section
$buffer2 .= IecType::iecINT($reference); // refnumber = 12288
$buffer2 .= IecType::iecINT($quantity); // quantity
$dataLen += 5;
// build header
$buffer3 = '';
$buffer3 .= IecType::iecINT(mt_rand(0, 65000)); // transaction ID
$buffer3 .= IecType::iecINT(0); // protocol ID
$buffer3 .= IecType::iecINT($dataLen + 1); // length
$buffer3 .= IecType::iecBYTE($unitId); //unit ID
// return packet string
return $buffer3 . $buffer2 . $buffer1;
}
/**
* FC 3 response parser
*
* @param string $packet
* @return array
* @throws \Exception
*/
public static function parse($packet)
{
$data = array();
// get data
for ($i = 0, $len = ord($packet[8]); $i < $len; $i++) {
$data[$i] = ord($packet[9 + $i]);
}
return $data;
}
}

@ -0,0 +1,102 @@
<?php
/**
* Phpmodbus Copyright (c) 2004, 2013 Jan Krakora
*
* This source file is subject to the "PhpModbus license" that is bundled
* with this package in the file license.txt.
*
* @copyright Copyright (c) 2004, 2013 Jan Krakora
* @license PhpModbus license
* @category Phpmodbus
* @tutorial Phpmodbus.pkg
* @package Phpmodbus
* @version $id$
*/
namespace PHPModbus\Packet;
use PHPModbus\IecType;
class ReadWriteRegistersPacket
{
/**
* Packet FC23 builder - READ WRITE registers
*
* @param int $unitId
* @param int $referenceRead
* @param int $quantity
* @param int $referenceWrite
* @param array $data
* @param array $dataTypes
* @param int $endianness (0 = little endian = 0, 1 = big endian)
* @return string
*/
public static function build(
$unitId,
$referenceRead,
$quantity,
$referenceWrite,
array $data,
array $dataTypes,
$endianness
)
{
$dataLen = 0;
// build data section
$buffer1 = '';
foreach ($data as $key => $dataitem) {
if ($dataTypes[$key] === 'INT') {
$buffer1 .= IecType::iecINT($dataitem); // register values x
$dataLen += 2;
} elseif ($dataTypes[$key] === 'DINT') {
$buffer1 .= IecType::iecDINT($dataitem, $endianness); // register values x
$dataLen += 4;
} elseif ($dataTypes[$key] === 'REAL') {
$buffer1 .= IecType::iecREAL($dataitem, $endianness); // register values x
$dataLen += 4;
} else {
$buffer1 .= IecType::iecINT($dataitem); // register values x
$dataLen += 2;
}
}
// build body
$buffer2 = '';
$buffer2 .= IecType::iecBYTE(23); // FC 23 = 23(0x17)
// build body - read section
$buffer2 .= IecType::iecINT($referenceRead); // refnumber = 12288
$buffer2 .= IecType::iecINT($quantity); // quantity
// build body - write section
$buffer2 .= IecType::iecINT($referenceWrite); // refnumber = 12288
$buffer2 .= IecType::iecINT($dataLen / 2); // word count
$buffer2 .= IecType::iecBYTE($dataLen); // byte count
$dataLen += 10;
// build header
$buffer3 = '';
$buffer3 .= IecType::iecINT(mt_rand(0, 65000)); // transaction ID
$buffer3 .= IecType::iecINT(0); // protocol ID
$buffer3 .= IecType::iecINT($dataLen + 1); // length
$buffer3 .= IecType::iecBYTE($unitId); //unit ID
// return packet string
return $buffer3 . $buffer2 . $buffer1;
}
/**
* FC23 response parser
*
* @param string $packet
* @return array|false
* @throws \Exception
*/
public static function parse($packet)
{
$data = array();
// get data
for ($i = 0, $len = ord($packet[8]); $i < $len; $i++) {
$data[$i] = ord($packet[9 + $i]);
}
return $data;
}
}

@ -0,0 +1,89 @@
<?php
/**
* Phpmodbus Copyright (c) 2004, 2013 Jan Krakora
*
* This source file is subject to the "PhpModbus license" that is bundled
* with this package in the file license.txt.
*
* @copyright Copyright (c) 2004, 2013 Jan Krakora
* @license PhpModbus license
* @category Phpmodbus
* @tutorial Phpmodbus.pkg
* @package Phpmodbus
* @version $id$
*/
namespace PHPModbus\Packet;
use PHPModbus\IecType;
class WriteMultipleCoilsPacket
{
/**
* Packet builder FC15 - Write multiple coils
*
* @param int $unitId
* @param int $reference
* @param array $data
* @return string
*/
public static function build($unitId, $reference, array $data)
{
$dataLen = 0;
// build bool stream to the WORD array
$data_word_stream = array();
$data_word = 0;
$shift = 0;
for ($i = 0, $len = count($data); $i < $len; $i++) {
if ((($i % 8) === 0) && ($i > 0)) {
$data_word_stream[] = $data_word;
$shift = 0;
$data_word = 0;
$data_word |= (0x01 && $data[$i]) << $shift;
$shift++;
} else {
$data_word |= (0x01 && $data[$i]) << $shift;
$shift++;
}
}
$data_word_stream[] = $data_word;
// show binary stream to status string
// foreach ($data_word_stream as $d) {
// $this->status .= sprintf("byte=b%08b\n", $d);
// }
// build data section
$buffer1 = '';
foreach ($data_word_stream as $key => $dataitem) {
$buffer1 .= IecType::iecBYTE($dataitem); // register values x
$dataLen += 1;
}
// build body
$buffer2 = '';
$buffer2 .= IecType::iecBYTE(15); // FC 15 = 15(0x0f)
$buffer2 .= IecType::iecINT($reference); // refnumber = 12288
$buffer2 .= IecType::iecINT(count($data)); // bit count
$buffer2 .= IecType::iecBYTE((count($data) + 7) / 8); // byte count
$dataLen += 6;
// build header
$buffer3 = '';
$buffer3 .= IecType::iecINT(mt_rand(0, 65000)); // transaction ID
$buffer3 .= IecType::iecINT(0); // protocol ID
$buffer3 .= IecType::iecINT($dataLen + 1); // length
$buffer3 .= IecType::iecBYTE($unitId); // unit ID
// return packet string
return $buffer3 . $buffer2 . $buffer1;
}
/**
* FC15 response parser
*
* @return bool
* @throws \Exception
*/
public static function parse()
{
return true;
}
}

@ -0,0 +1,85 @@
<?php
/**
* Phpmodbus Copyright (c) 2004, 2013 Jan Krakora
*
* This source file is subject to the "PhpModbus license" that is bundled
* with this package in the file license.txt.
*
* @copyright Copyright (c) 2004, 2013 Jan Krakora
* @license PhpModbus license
* @category Phpmodbus
* @tutorial Phpmodbus.pkg
* @package Phpmodbus
* @version $id$
*/
namespace PHPModbus\Packet;
use PHPModbus\IecType;
class WriteMultipleRegisterPacket
{
/**
* Packet builder FC16 - WRITE multiple register
* e.g.: 4dd90000000d0010300000030603e807d00bb8
*
* @param int $unitId
* @param int $reference
* @param array $data
* @param array $dataTypes
* @param int $endianness (0 = little endian = 0, 1 = big endian)
* @return string
*/
public static function build($unitId, $reference, array $data, array $dataTypes, $endianness)
{
$dataLen = 0;
// build data section
$buffer1 = "";
foreach ($data as $key => $dataitem) {
if ($dataTypes[$key] === 'INT') {
$buffer1 .= IecType::iecINT($dataitem); // register values x
$dataLen += 2;
} elseif ($dataTypes[$key] === 'DINT') {
$buffer1 .= IecType::iecDINT($dataitem, $endianness); // register values x
$dataLen += 4;
} elseif ($dataTypes[$key] === 'REAL') {
$buffer1 .= IecType::iecREAL($dataitem, $endianness); // register values x
$dataLen += 4;
} else {
$buffer1 .= IecType::iecINT($dataitem); // register values x
$dataLen += 2;
}
}
// build body
$buffer2 = '';
$buffer2 .= IecType::iecBYTE(16); // FC 16 = 16(0x10)
$buffer2 .= IecType::iecINT($reference); // refnumber = 12288
$buffer2 .= IecType::iecINT($dataLen / 2); // word count
$buffer2 .= IecType::iecBYTE($dataLen); // byte count
$dataLen += 6;
// build header
$buffer3 = '';
$buffer3 .= IecType::iecINT(mt_rand(0, 65000)); // transaction ID
$buffer3 .= IecType::iecINT(0); // protocol ID
$buffer3 .= IecType::iecINT($dataLen + 1); // length
$buffer3 .= IecType::iecBYTE($unitId); //unit ID
// return packet string
return $buffer3 . $buffer2 . $buffer1;
}
/**
* FC16 response parser
*
* @return bool
* @throws \Exception
*/
public static function parse()
{
return true;
}
}

@ -0,0 +1,70 @@
<?php
/**
* Phpmodbus Copyright (c) 2004, 2013 Jan Krakora
*
* This source file is subject to the "PhpModbus license" that is bundled
* with this package in the file license.txt.
*
* @copyright Copyright (c) 2004, 2013 Jan Krakora
* @license PhpModbus license
* @category Phpmodbus
* @tutorial Phpmodbus.pkg
* @package Phpmodbus
* @version $id$
*/
namespace PHPModbus\Packet;
use PHPModbus\IecType;
class WriteSingleCoilPacket
{
/**
* Packet builder FC5 - WRITE single register
*
* @param int $unitId
* @param int $reference
* @param array $data
* @return string
*/
public static function build($unitId, $reference, array $data)
{
$dataLen = 0;
// build data section
$buffer1 = '';
foreach ($data as $key => $dataitem) {
if ($dataitem == true) {
$buffer1 = IecType::iecINT(0xFF00);
} else {
$buffer1 = IecType::iecINT(0x0000);
}
}
$dataLen += 2;
// build body
$buffer2 = '';
$buffer2 .= IecType::iecBYTE(5); // FC5 = 5(0x05)
$buffer2 .= IecType::iecINT($reference); // refnumber = 12288
$dataLen += 3;
// build header
$buffer3 = '';
$buffer3 .= IecType::iecINT(mt_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;
}
/**
* FC5 response parser
*
* @return bool
* @throws \Exception
*/
public static function parse()
{
return true;
}
}

@ -0,0 +1,68 @@
<?php
/**
* Phpmodbus Copyright (c) 2004, 2013 Jan Krakora
*
* This source file is subject to the "PhpModbus license" that is bundled
* with this package in the file license.txt.
*
* @copyright Copyright (c) 2004, 2013 Jan Krakora
* @license PhpModbus license
* @category Phpmodbus
* @tutorial Phpmodbus.pkg
* @package Phpmodbus
* @version $id$
*/
namespace PHPModbus\Packet;
use PHPModbus\IecType;
class WriteSingleRegisterPacket
{
/**
* Packet builder FC6 - WRITE single register
*
* @param int $unitId
* @param int $reference
* @param array $data
* @return string
*/
public static function build($unitId, $reference, array $data)
{
$dataLen = 0;
// build data section
$buffer1 = '';
foreach ($data as $key => $dataitem) {
$buffer1 .= IecType::iecINT($dataitem); // register values x
$dataLen += 2;
break;
}
// build body
$buffer2 = '';
$buffer2 .= IecType::iecBYTE(6); // FC6 = 6(0x06)
$buffer2 .= IecType::iecINT($reference); // refnumber = 12288
$dataLen += 3;
// build header
$buffer3 = '';
$buffer3 .= IecType::iecINT(mt_rand(0, 65000)); // transaction ID
$buffer3 .= IecType::iecINT(0); // protocol ID
$buffer3 .= IecType::iecINT($dataLen + 1); // length
$buffer3 .= IecType::iecBYTE($unitId); //unit ID
// return packet string
return $buffer3 . $buffer2 . $buffer1;
}
/**
* FC6 response parser
*
* @return bool
* @throws \Exception
*/
public static function parse()
{
return true;
}
}

@ -13,7 +13,7 @@ class UdpFc1ReadCoilsTest extends MockServerTestCase
$modbus = new ModbusMasterUdp('127.0.0.1');
$modbus->port = $port;
usleep(50000); // no idea how to fix this. wait for server to "warm" up or modbus UDP socket will timeout. does not occur with TCP
usleep(150000); // no idea how to fix this. wait for server to "warm" up or modbus UDP socket will timeout. does not occur with TCP
$this->assertEquals([1], $modbus->readCoils(0, 256, 1));
}, 'UDP');

Loading…
Cancel
Save