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