parent
5e8b3159a3
commit
c7c4431b1c
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; |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue