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
{
/** @var resource Communication socket */
private $sock;
/** @var string Modbus device IP address */
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 $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)
public $endianness = 0; // Endianness codding (little endian == 0, big endian == 1)
public $socket_protocol = "UDP"; // Socket protocol (TCP, UDP)
/** @var string Socket protocol (TCP, UDP) */
public $socket_protocol = "UDP";
/**
* ModbusMaster
@ -95,6 +102,22 @@ class ModbusMaster
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
*
@ -119,20 +142,21 @@ class ModbusMaster
if (strlen($this->client) > 0) {
$result = socket_bind($this->sock, $this->client, $this->client_port);
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)));
} else {
$this->status .= "Bound\n";
}
}
// Socket settings (send/write timeout)
socket_set_option($this->sock, SOL_SOCKET, SO_SNDTIMEO,
array('sec' => $this->socket_write_timeout_sec, 'usec' => $this->socket_write_timeout_usec)
);
$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 Exception("socket_connect() failed.</br>Reason: ($result)" .
throw new Exception("socket_connect() failed. Reason: ($result)" .
socket_strerror(socket_last_error($this->sock)));
} else {
$this->status .= "Connected\n";
@ -179,22 +203,24 @@ class ModbusMaster
$writesocks = null;
$exceptsocks = null;
$rec = "";
$timeoutInSeconds = $this->timeout_sec + ($this->timeout_msec / 1000);
$totalReadTimeout = $this->timeout_sec;
$lastAccess = microtime(true);
while (socket_select($readsocks, $writesocks, $exceptsocks, 0, $this->socket_read_timeout_usec) !== false) {
$this->status .= "Wait data ... " . PHP_EOL;
$readTout = $this->secsToSecUsecArray($this->socket_read_timeout_sec);
while (false !== socket_select($readsocks, $writesocks, $exceptsocks, $readTout['sec'], $readTout['usec'])) {
$this->status .= "Wait data ... \n";
if (in_array($this->sock, $readsocks)) {
while (@socket_recv($this->sock, $rec, 2000, 0)) {
$this->status .= "Data received" . PHP_EOL;
if (@socket_recv($this->sock, $rec, 2000, 0)) { // read max 2000 bytes
$this->status .= "Data received \n";
return $rec;
}
$lastAccess = microtime(true);
} else {
$timeSpentWaiting = microtime(true) - $lastAccess;
if ($timeSpentWaiting >= $timeoutInSeconds) {
throw new Exception("Watchdog time expired [ " .
$timeoutInSeconds . " sec]!!! Connection to " .
$this->host . " is not established.");
if ($timeSpentWaiting >= $totalReadTimeout) {
throw new Exception(
"Watchdog time expired [ $totalReadTimeout sec ]!!! " .
"Connection to $this->host:$this->port is not established.");
}
}
$readsocks[] = $this->sock;
@ -227,7 +253,7 @@ class ModbusMaster
0x06 => "SLAVE DEVICE BUSY",
0x08 => "MEMORY PARITY ERROR",
0x0A => "GATEWAY PATH UNAVAILABLE",
0x0B => "GATEWAY TARGET DEVICE FAILED TO RESPOND"
0x0B => "GATEWAY TARGET DEVICE FAILED TO RESPOND",
);
// get failure string
if (key_exists($failure_code, $failures)) {
@ -1289,7 +1315,8 @@ class ModbusMaster
$referenceWrite,
$data,
$dataTypes
) {
)
{
$dataLen = 0;
// build data section
$buffer1 = "";
@ -1336,7 +1363,7 @@ class ModbusMaster
* FC23 response parser
*
* @param string $packet
* @return array
* @return array|false
*/
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;
$this->timeout_msec = $milliseconds;
// Set read timeout if given
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