Minor cleanup, removed duplicate timeout vars & replaced with float [sec], added socket Tout setter

pull/2/merge
Ondřej Hruška 8 years ago
parent 7365700b72
commit 61e7a690eb
  1. 115
      src/ModbusMaster.php

@ -45,31 +45,38 @@ use Exception;
*/ */
class ModbusMaster class ModbusMaster
{ {
/** @var resource Communication socket */
private $sock; private $sock;
/** @var string Modbus device IP address */
public $host = "192.168.1.1"; public $host = "192.168.1.1";
public $port = "502"; /** @var string gateway port */
public $port = 502;
public $client = ""; /** @var string (optional) client IP address */
public $client = ""; // TODO explanation?
public $client_port = "502"; /** @var string client port */
public $client_port = 502;
/** @var string ModbusMaster status messages (echo for debugging) */
public $status; public $status;
public $timeout_sec = 5; // Timeout 5 sec /** @var float Total response timeout (seconds, decimals allowed) */
public $timeout_sec = 5;
public $timeout_msec = 0; // milliseconds. is added to $timeout_sec when calculating real read timeout /** @var float Socket read timeout (seconds, decimals allowed) */
public $socket_read_timeout_sec = 0.3; // 300 ms
public $socket_read_timeout_usec = 300000; // socket read timeout 300 ms /** @var float Socket write timeout (seconds, decimals allowed) */
public $socket_write_timeout_sec = 1;
public $socket_write_timeout_sec = 1; // socket write timeout 1 sec /** @var int Endianness codding (0 = little endian = 0, 1 = big endian) */
public $endianness = 0; //
public $socket_write_timeout_usec = 0; // socket write timeout microseconds (must be lower than 1 sec e.g. 1000000) /** @var string Socket protocol (TCP, UDP) */
public $socket_protocol = "UDP";
public $endianness = 0; // Endianness codding (little endian == 0, big endian == 1)
public $socket_protocol = "UDP"; // Socket protocol (TCP, UDP)
/** /**
* ModbusMaster * ModbusMaster
@ -95,6 +102,22 @@ class ModbusMaster
return "<pre>" . $this->status . "</pre>"; return "<pre>" . $this->status . "</pre>";
} }
/**
* 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),
];
}
/** /**
* connect * connect
* *
@ -119,20 +142,21 @@ class ModbusMaster
if (strlen($this->client) > 0) { if (strlen($this->client) > 0) {
$result = socket_bind($this->sock, $this->client, $this->client_port); $result = socket_bind($this->sock, $this->client, $this->client_port);
if ($result === false) { if ($result === false) {
throw new Exception("socket_bind() failed.</br>Reason: ($result)" . throw new Exception("socket_bind() failed. Reason: ($result)" .
socket_strerror(socket_last_error($this->sock))); socket_strerror(socket_last_error($this->sock)));
} else { } else {
$this->status .= "Bound\n"; $this->status .= "Bound\n";
} }
} }
// Socket settings (send/write timeout) // Socket settings (send/write timeout)
socket_set_option($this->sock, SOL_SOCKET, SO_SNDTIMEO, $writeTimeout = $this->secsToSecUsecArray($this->socket_write_timeout_sec);
array('sec' => $this->socket_write_timeout_sec, 'usec' => $this->socket_write_timeout_usec) socket_set_option($this->sock, SOL_SOCKET, SO_SNDTIMEO, $writeTimeout);
);
// Connect the socket // Connect the socket
$result = @socket_connect($this->sock, $this->host, $this->port); $result = @socket_connect($this->sock, $this->host, $this->port);
if ($result === false) { if ($result === false) {
throw new Exception("socket_connect() failed.</br>Reason: ($result)" . throw new Exception("socket_connect() failed. Reason: ($result)" .
socket_strerror(socket_last_error($this->sock))); socket_strerror(socket_last_error($this->sock)));
} else { } else {
$this->status .= "Connected\n"; $this->status .= "Connected\n";
@ -179,22 +203,24 @@ class ModbusMaster
$writesocks = null; $writesocks = null;
$exceptsocks = null; $exceptsocks = null;
$rec = ""; $rec = "";
$timeoutInSeconds = $this->timeout_sec + ($this->timeout_msec / 1000); $totalReadTimeout = $this->timeout_sec;
$lastAccess = microtime(true); $lastAccess = microtime(true);
while (socket_select($readsocks, $writesocks, $exceptsocks, 0, $this->socket_read_timeout_usec) !== false) { $readTout = $this->secsToSecUsecArray($this->socket_read_timeout_sec);
$this->status .= "Wait data ... " . PHP_EOL;
while (false !== socket_select($readsocks, $writesocks, $exceptsocks, $readTout['sec'], $readTout['usec'])) {
$this->status .= "Wait data ... \n";
if (in_array($this->sock, $readsocks)) { if (in_array($this->sock, $readsocks)) {
while (@socket_recv($this->sock, $rec, 2000, 0)) { if (@socket_recv($this->sock, $rec, 2000, 0)) { // read max 2000 bytes
$this->status .= "Data received" . PHP_EOL; $this->status .= "Data received \n";
return $rec; return $rec;
} }
$lastAccess = microtime(true); $lastAccess = microtime(true);
} else { } else {
$timeSpentWaiting = microtime(true) - $lastAccess; $timeSpentWaiting = microtime(true) - $lastAccess;
if ($timeSpentWaiting >= $timeoutInSeconds) { if ($timeSpentWaiting >= $totalReadTimeout) {
throw new Exception("Watchdog time expired [ " . throw new Exception(
$timeoutInSeconds . " sec]!!! Connection to " . "Watchdog time expired [ $totalReadTimeout sec ]!!! " .
$this->host . " is not established."); "Connection to $this->host:$this->port is not established.");
} }
} }
$readsocks[] = $this->sock; $readsocks[] = $this->sock;
@ -227,7 +253,7 @@ class ModbusMaster
0x06 => "SLAVE DEVICE BUSY", 0x06 => "SLAVE DEVICE BUSY",
0x08 => "MEMORY PARITY ERROR", 0x08 => "MEMORY PARITY ERROR",
0x0A => "GATEWAY PATH UNAVAILABLE", 0x0A => "GATEWAY PATH UNAVAILABLE",
0x0B => "GATEWAY TARGET DEVICE FAILED TO RESPOND" 0x0B => "GATEWAY TARGET DEVICE FAILED TO RESPOND",
); );
// get failure string // get failure string
if (key_exists($failure_code, $failures)) { if (key_exists($failure_code, $failures)) {
@ -1289,7 +1315,8 @@ class ModbusMaster
$referenceWrite, $referenceWrite,
$data, $data,
$dataTypes $dataTypes
) { )
{
$dataLen = 0; $dataLen = 0;
// build data section // build data section
$buffer1 = ""; $buffer1 = "";
@ -1336,7 +1363,7 @@ class ModbusMaster
* FC23 response parser * FC23 response parser
* *
* @param string $packet * @param string $packet
* @return array * @return array|false
*/ */
private function readWriteRegistersParser($packet) private function readWriteRegistersParser($packet)
{ {
@ -1387,15 +1414,33 @@ class ModbusMaster
} }
/** /**
* setTimeoutMs * Set data receive timeout.
* Writes property timeout_sec
* *
* Set timeout used when receiving data in milliseconds. NB: Method overrides $timeout_sec variable value. * @param float $seconds seconds
*/
public function setTimeout($seconds)
{
$this->timeout_sec = $seconds;
}
/**
* Set socket read/write timeout. Null = no change.
* *
* @param integer $milliseconds milliseconds * @param float|null $read_timeout_sec data read timeout (seconds, default 0.3)
* @param float|null $write_timeout_sec data write timeout (seconds, default 1.0)
* @internal param float $seconds seconds
*/ */
public function setTimeoutMs($milliseconds) public function setSocketTimeout($read_timeout_sec, $write_timeout_sec)
{ {
$this->timeout_sec = 0; // Set read timeout if given
$this->timeout_msec = $milliseconds; if ($read_timeout_sec !== null) {
$this->socket_read_timeout_sec = $read_timeout_sec;
}
// Set write timeout if given
if ($write_timeout_sec !== null) {
$this->socket_write_timeout_sec = $write_timeout_sec;
}
} }
} }

Loading…
Cancel
Save