refactor socket send and receive to separate method to reduce code duplication

pull/2/head
toimtoimtoim 8 years ago
parent dea30f53b4
commit 1e1c8ee5ce
  1. 401
      src/ModbusMaster.php

@ -43,64 +43,64 @@ use Exception;
class ModbusMaster class ModbusMaster
{ {
/** /**
*
* *
* @var string Modbus device IP address *
*/ * @var string Modbus device IP address
*/
public $host = '192.168.1.1'; public $host = '192.168.1.1';
/** /**
*
* *
* @var string gateway port *
*/ * @var string gateway port
*/
public $port = 502; public $port = 502;
/** /**
* @var string (optional) client IP address when binding client * @var string (optional) client IP address when binding client
*/ */
public $client = ''; public $client = '';
/** /**
*
* *
* @var string client port set when binding client to local ip&port *
*/ * @var string client port set when binding client to local ip&port
*/
public $client_port = 502; public $client_port = 502;
/** /**
*
* *
* @var string ModbusMaster status messages (echo for debugging) *
*/ * @var string ModbusMaster status messages (echo for debugging)
*/
public $status; public $status;
/** /**
*
* *
* @var float Total response timeout (seconds, decimals allowed) *
*/ * @var float Total response timeout (seconds, decimals allowed)
*/
public $timeout_sec = 5; public $timeout_sec = 5;
/** /**
* @var float Socket read timeout (seconds, decimals allowed) * @var float Socket read timeout (seconds, decimals allowed)
*/ */
public $socket_read_timeout_sec = 0.3; public $socket_read_timeout_sec = 0.3;
/** /**
*
* *
* @var float Socket write timeout (seconds, decimals allowed) *
*/ * @var float Socket write timeout (seconds, decimals allowed)
*/
public $socket_write_timeout_sec = 1; // 300 ms public $socket_write_timeout_sec = 1; // 300 ms
/** /**
* @var int Endianness codding (0 = little endian = 0, 1 = big endian) * @var int Endianness codding (0 = little endian = 0, 1 = big endian)
*/ */
public $endianness = 0; public $endianness = 0;
/** /**
*
* *
* @var string Socket protocol (TCP, UDP) *
*/ * @var string Socket protocol (TCP, UDP)
*/
public $socket_protocol = 'UDP'; // public $socket_protocol = 'UDP'; //
/** /**
*
* *
* @var resource Communication socket *
*/ * @var resource Communication socket
*/
private $sock; private $sock;
/** /**
@ -108,7 +108,7 @@ class ModbusMaster
* *
* This is the constructor that defines {@link $host} IP address of the object. * This is the constructor that defines {@link $host} IP address of the object.
* *
* @param String $host An IP address of a Modbus TCP device. E.g. "192.168.1.1" * @param String $host An IP address of a Modbus TCP device. E.g. "192.168.1.1"
* @param String $protocol Socket protocol (TCP, UDP) * @param String $protocol Socket protocol (TCP, UDP)
*/ */
public function __construct($host, $protocol) public function __construct($host, $protocol)
@ -161,21 +161,17 @@ class ModbusMaster
public function readCoils($unitId, $reference, $quantity) public function readCoils($unitId, $reference, $quantity)
{ {
$this->status .= "readCoils: START\n"; $this->status .= "readCoils: START\n";
// connect
$this->connect(); $receivedData = $this->sendAndReceive(
// send FC 1 function () use ($unitId, $reference, $quantity) {
$packet = $this->readCoilsPacketBuilder($unitId, $reference, $quantity); return $this->readCoilsPacketBuilder($unitId, $reference, $quantity);
$this->status .= $this->printPacket($packet); },
$this->send($packet); function ($data) use ($quantity) {
// receive response return $this->readCoilsParser($data, $quantity);
$rpacket = $this->rec(); }
$this->status .= $this->printPacket($rpacket); );
// parse packet
$receivedData = $this->readCoilsParser($rpacket, $quantity);
// disconnect
$this->disconnect();
$this->status .= "readCoils: DONE\n"; $this->status .= "readCoils: DONE\n";
// return
return $receivedData; return $receivedData;
} }
@ -337,7 +333,7 @@ class ModbusMaster
$readsocks[] = $this->sock; $readsocks[] = $this->sock;
$writesocks = null; $writesocks = null;
$exceptsocks = null; $exceptsocks = null;
$rec = ""; $rec = '';
$totalReadTimeout = $this->timeout_sec; $totalReadTimeout = $this->timeout_sec;
$lastAccess = microtime(true); $lastAccess = microtime(true);
$readTout = $this->secsToSecUsecArray($this->socket_read_timeout_sec); $readTout = $this->secsToSecUsecArray($this->socket_read_timeout_sec);
@ -451,10 +447,21 @@ class ModbusMaster
* *
* Disconnect the socket * Disconnect the socket
*/ */
private function disconnect() protected function disconnect()
{
if (is_resource($this->sock)) {
socket_close($this->sock);
$this->status .= "Disconnected\n";
}
}
/**
* Close socket it still open
*/
public function __destruct()
{ {
socket_close($this->sock); $this->disconnect();
$this->status .= "Disconnected\n";
} }
/** /**
@ -491,21 +498,17 @@ class ModbusMaster
public function readInputDiscretes($unitId, $reference, $quantity) public function readInputDiscretes($unitId, $reference, $quantity)
{ {
$this->status .= "readInputDiscretes: START\n"; $this->status .= "readInputDiscretes: START\n";
// connect
$this->connect(); $receivedData = $this->sendAndReceive(
// send FC 2 function () use ($unitId, $reference, $quantity) {
$packet = $this->readInputDiscretesPacketBuilder($unitId, $reference, $quantity); return $this->readInputDiscretesPacketBuilder($unitId, $reference, $quantity);
$this->status .= $this->printPacket($packet); },
$this->send($packet); function ($data) use ($quantity) {
// receive response return $this->readInputDiscretesParser($data, $quantity);
$rpacket = $this->rec(); }
$this->status .= $this->printPacket($rpacket); );
// parse packet
$receivedData = $this->readInputDiscretesParser($rpacket, $quantity);
// disconnect
$this->disconnect();
$this->status .= "readInputDiscretes: DONE\n"; $this->status .= "readInputDiscretes: DONE\n";
// return
return $receivedData; return $receivedData;
} }
@ -591,21 +594,17 @@ class ModbusMaster
public function readMultipleRegisters($unitId, $reference, $quantity) public function readMultipleRegisters($unitId, $reference, $quantity)
{ {
$this->status .= "readMultipleRegisters: START\n"; $this->status .= "readMultipleRegisters: START\n";
// connect
$this->connect(); $receivedData = $this->sendAndReceive(
// send FC 3 function () use ($unitId, $reference, $quantity) {
$packet = $this->readMultipleRegistersPacketBuilder($unitId, $reference, $quantity); return $this->readMultipleRegistersPacketBuilder($unitId, $reference, $quantity);
$this->status .= $this->printPacket($packet); },
$this->send($packet); function ($data) {
// receive response return $this->readMultipleRegistersParser($data);
$rpacket = $this->rec(); }
$this->status .= $this->printPacket($rpacket); );
// parse packet
$receivedData = $this->readMultipleRegistersParser($rpacket);
// disconnect
$this->disconnect();
$this->status .= "readMultipleRegisters: DONE\n"; $this->status .= "readMultipleRegisters: DONE\n";
// return
return $receivedData; return $receivedData;
} }
@ -696,21 +695,17 @@ class ModbusMaster
public function readMultipleInputRegisters($unitId, $reference, $quantity) public function readMultipleInputRegisters($unitId, $reference, $quantity)
{ {
$this->status .= "readMultipleInputRegisters: START\n"; $this->status .= "readMultipleInputRegisters: START\n";
// connect
$this->connect(); $receivedData = $this->sendAndReceive(
// send FC 4 function () use ($unitId, $reference, $quantity) {
$packet = $this->readMultipleInputRegistersPacketBuilder($unitId, $reference, $quantity); return $this->readMultipleInputRegistersPacketBuilder($unitId, $reference, $quantity);
$this->status .= $this->printPacket($packet); },
$this->send($packet); function ($data) {
// receive response return $this->readMultipleInputRegistersParser($data);
$rpacket = $this->rec(); }
$this->status .= $this->printPacket($rpacket); );
// parse packet
$receivedData = $this->readMultipleInputRegistersParser($rpacket);
// disconnect
$this->disconnect();
$this->status .= "readMultipleInputRegisters: DONE\n"; $this->status .= "readMultipleInputRegisters: DONE\n";
// return
return $receivedData; return $receivedData;
} }
@ -778,7 +773,7 @@ class ModbusMaster
* @return bool * @return bool
* @throws \Exception * @throws \Exception
*/ */
public function fc5($unitId, $reference, $data) public function fc5($unitId, $reference, array $data)
{ {
return $this->writeSingleCoil($unitId, $reference, $data); return $this->writeSingleCoil($unitId, $reference, $data);
} }
@ -798,24 +793,21 @@ class ModbusMaster
* @return bool Success flag * @return bool Success flag
* @throws \Exception * @throws \Exception
*/ */
public function writeSingleCoil($unitId, $reference, $data) public function writeSingleCoil($unitId, $reference, array $data)
{ {
$this->status .= "writeSingleCoil: START\n"; $this->status .= "writeSingleCoil: START\n";
// connect
$this->connect(); $receivedData = $this->sendAndReceive(
// send FC5 function () use ($unitId, $reference, $data) {
$packet = $this->writeSingleCoilPacketBuilder($unitId, $reference, $data); return $this->writeSingleCoilPacketBuilder($unitId, $reference, $data);
$this->status .= $this->printPacket($packet); },
$this->send($packet); function ($data) {
// receive response return $this->writeSingleCoilParser($data);
$rpacket = $this->rec(); }
$this->status .= $this->printPacket($rpacket); );
// parse packet
$this->writeSingleCoilParser($rpacket);
// disconnect
$this->disconnect();
$this->status .= "writeSingleCoil: DONE\n"; $this->status .= "writeSingleCoil: DONE\n";
return true; return $receivedData;
} }
/** /**
@ -823,12 +815,12 @@ class ModbusMaster
* *
* Packet builder FC5 - WRITE single register * Packet builder FC5 - WRITE single register
* *
* @param int $unitId * @param int $unitId
* @param int $reference * @param int $reference
* @param array $data * @param array $data
* @return string * @return string
*/ */
private function writeSingleCoilPacketBuilder($unitId, $reference, $data) private function writeSingleCoilPacketBuilder($unitId, $reference, array $data)
{ {
$dataLen = 0; $dataLen = 0;
// build data section // build data section
@ -883,7 +875,7 @@ class ModbusMaster
* @return bool * @return bool
* @throws \Exception * @throws \Exception
*/ */
public function fc6($unitId, $reference, $data) public function fc6($unitId, $reference, array $data)
{ {
return $this->writeSingleRegister($unitId, $reference, $data); return $this->writeSingleRegister($unitId, $reference, $data);
} }
@ -903,24 +895,36 @@ class ModbusMaster
* @return bool Success flag * @return bool Success flag
* @throws \Exception * @throws \Exception
*/ */
public function writeSingleRegister($unitId, $reference, $data) public function writeSingleRegister($unitId, $reference, array $data)
{ {
$this->status .= "writeSingleRegister: START\n"; $this->status .= "writeSingleRegister: START\n";
// connect $result = $this->sendAndReceive(
$this->connect(); function () use ($unitId, $reference, $data) {
// send FC6 return $this->writeSingleRegisterPacketBuilder($unitId, $reference, $data);
$packet = $this->writeSingleRegisterPacketBuilder($unitId, $reference, $data); },
$this->status .= $this->printPacket($packet); function ($data) {
$this->send($packet); return $this->writeSingleRegisterParser($data);
// receive response }
$rpacket = $this->rec(); );
$this->status .= $this->printPacket($rpacket);
// parse packet
$this->writeSingleRegisterParser($rpacket);
// disconnect
$this->disconnect();
$this->status .= "writeSingleRegister: DONE\n"; $this->status .= "writeSingleRegister: DONE\n";
return true; return $result;
}
public function sendAndReceive(callable $buildRequest, callable $parseResponse)
{
try {
$this->connect();
$packet = $buildRequest();
$this->send($packet);
$data = $this->rec();
$this->status .= $this->printPacket($data);
return $parseResponse($data);
} finally {
$this->disconnect();
}
} }
/** /**
@ -928,8 +932,8 @@ class ModbusMaster
* *
* Packet builder FC6 - WRITE single register * Packet builder FC6 - WRITE single register
* *
* @param int $unitId * @param int $unitId
* @param int $reference * @param int $reference
* @param array $data * @param array $data
* @return string * @return string
*/ */
@ -985,7 +989,7 @@ class ModbusMaster
* @return bool * @return bool
* @throws \Exception * @throws \Exception
*/ */
public function fc15($unitId, $reference, $data) public function fc15($unitId, $reference, array $data)
{ {
return $this->writeMultipleCoils($unitId, $reference, $data); return $this->writeMultipleCoils($unitId, $reference, $data);
} }
@ -1004,24 +1008,21 @@ class ModbusMaster
* @return bool * @return bool
* @throws \Exception * @throws \Exception
*/ */
public function writeMultipleCoils($unitId, $reference, $data) public function writeMultipleCoils($unitId, $reference, array $data)
{ {
$this->status .= "writeMultipleCoils: START\n"; $this->status .= "writeMultipleCoils: START\n";
// connect
$this->connect(); $receivedData = $this->sendAndReceive(
// send FC15 function () use ($unitId, $reference, $data) {
$packet = $this->writeMultipleCoilsPacketBuilder($unitId, $reference, $data); return $this->writeMultipleCoilsPacketBuilder($unitId, $reference, $data);
$this->status .= $this->printPacket($packet); },
$this->send($packet); function ($data) {
// receive response return $this->writeMultipleCoilsParser($data);
$rpacket = $this->rec(); }
$this->status .= $this->printPacket($rpacket); );
// parse packet
$this->writeMultipleCoilsParser($rpacket);
// disconnect
$this->disconnect();
$this->status .= "writeMultipleCoils: DONE\n"; $this->status .= "writeMultipleCoils: DONE\n";
return true; return $receivedData;
} }
/** /**
@ -1029,8 +1030,8 @@ class ModbusMaster
* *
* Packet builder FC15 - Write multiple coils * Packet builder FC15 - Write multiple coils
* *
* @param int $unitId * @param int $unitId
* @param int $reference * @param int $reference
* @param array $data * @param array $data
* @return string * @return string
*/ */
@ -1109,7 +1110,7 @@ class ModbusMaster
* @return bool * @return bool
* @throws \Exception * @throws \Exception
*/ */
public function fc16($unitId, $reference, $data, $dataTypes) public function fc16($unitId, $reference, array $data, array $dataTypes)
{ {
return $this->writeMultipleRegister($unitId, $reference, $data, $dataTypes); return $this->writeMultipleRegister($unitId, $reference, $data, $dataTypes);
} }
@ -1131,24 +1132,21 @@ class ModbusMaster
* @return bool Success flag * @return bool Success flag
* @throws \Exception * @throws \Exception
*/ */
public function writeMultipleRegister($unitId, $reference, $data, $dataTypes) public function writeMultipleRegister($unitId, $reference, array $data, array $dataTypes)
{ {
$this->status .= "writeMultipleRegister: START\n"; $this->status .= "writeMultipleRegister: START\n";
// connect
$this->connect(); $receivedData = $this->sendAndReceive(
// send FC16 function () use ($unitId, $reference, $data, $dataTypes) {
$packet = $this->writeMultipleRegisterPacketBuilder($unitId, $reference, $data, $dataTypes); return $this->writeMultipleRegisterPacketBuilder($unitId, $reference, $data, $dataTypes);
$this->status .= $this->printPacket($packet); },
$this->send($packet); function ($data) {
// receive response return $this->writeMultipleRegisterParser($data);
$rpacket = $this->rec(); }
$this->status .= $this->printPacket($rpacket); );
// parse packet
$this->writeMultipleRegisterParser($rpacket);
// disconnect
$this->disconnect();
$this->status .= "writeMultipleRegister: DONE\n"; $this->status .= "writeMultipleRegister: DONE\n";
return true; return $receivedData;
} }
/** /**
@ -1157,13 +1155,13 @@ class ModbusMaster
* Packet builder FC16 - WRITE multiple register * Packet builder FC16 - WRITE multiple register
* e.g.: 4dd90000000d0010300000030603e807d00bb8 * e.g.: 4dd90000000d0010300000030603e807d00bb8
* *
* @param int $unitId * @param int $unitId
* @param int $reference * @param int $reference
* @param array $data * @param array $data
* @param array $dataTypes * @param array $dataTypes
* @return string * @return string
*/ */
private function writeMultipleRegisterPacketBuilder($unitId, $reference, $data, $dataTypes) private function writeMultipleRegisterPacketBuilder($unitId, $reference, array $data, array $dataTypes)
{ {
$dataLen = 0; $dataLen = 0;
// build data section // build data section
@ -1254,21 +1252,18 @@ class ModbusMaster
public function maskWriteRegister($unitId, $reference, $andMask, $orMask) public function maskWriteRegister($unitId, $reference, $andMask, $orMask)
{ {
$this->status .= "maskWriteRegister: START\n"; $this->status .= "maskWriteRegister: START\n";
// connect
$this->connect(); $receivedData = $this->sendAndReceive(
// send FC22 function () use ($unitId, $reference, $andMask, $orMask) {
$packet = $this->maskWriteRegisterPacketBuilder($unitId, $reference, $andMask, $orMask); return $this->maskWriteRegisterPacketBuilder($unitId, $reference, $andMask, $orMask);
$this->status .= $this->printPacket($packet); },
$this->send($packet); function ($data) {
// receive response return $this->maskWriteRegisterParser($data);
$rpacket = $this->rec(); }
$this->status .= $this->printPacket($rpacket); );
// parse packet
$this->maskWriteRegisterParser($rpacket);
// disconnect
$this->disconnect();
$this->status .= "maskWriteRegister: DONE\n"; $this->status .= "maskWriteRegister: DONE\n";
return true; return $receivedData;
} }
/** /**
@ -1333,7 +1328,7 @@ class ModbusMaster
* @return false|array * @return false|array
* @throws \Exception * @throws \Exception
*/ */
public function fc23($unitId, $referenceRead, $quantity, $referenceWrite, $data, $dataTypes) public function fc23($unitId, $referenceRead, $quantity, $referenceWrite, array $data, array $dataTypes)
{ {
return $this->readWriteRegisters($unitId, $referenceRead, $quantity, $referenceWrite, $data, $dataTypes); return $this->readWriteRegisters($unitId, $referenceRead, $quantity, $referenceWrite, $data, $dataTypes);
} }
@ -1358,27 +1353,22 @@ class ModbusMaster
* @return false|array Success flag or array of data. * @return false|array Success flag or array of data.
* @throws \Exception * @throws \Exception
*/ */
public function readWriteRegisters($unitId, $referenceRead, $quantity, $referenceWrite, $data, $dataTypes) public function readWriteRegisters($unitId, $referenceRead, $quantity, $referenceWrite, array $data, array $dataTypes)
{ {
$this->status .= "readWriteRegisters: START\n"; $this->status .= "readWriteRegisters: START\n";
// connect
$this->connect(); $receivedData = $this->sendAndReceive(
// send FC23 function () use ($unitId, $referenceRead, $quantity, $referenceWrite, $data, $dataTypes) {
$packet = $this->readWriteRegistersPacketBuilder( return $this->readWriteRegistersPacketBuilder(
$unitId, $referenceRead, $quantity, $referenceWrite, $data, $unitId, $referenceRead, $quantity, $referenceWrite, $data, $dataTypes
$dataTypes );
},
function ($data) {
return $this->readWriteRegistersParser($data);
}
); );
$this->status .= $this->printPacket($packet);
$this->send($packet);
// receive response
$rpacket = $this->rec();
$this->status .= $this->printPacket($rpacket);
// parse packet
$receivedData = $this->readWriteRegistersParser($rpacket);
// disconnect
$this->disconnect();
$this->status .= "writeMultipleRegister: DONE\n"; $this->status .= "writeMultipleRegister: DONE\n";
// return
return $receivedData; return $receivedData;
} }
@ -1387,10 +1377,10 @@ class ModbusMaster
* *
* Packet FC23 builder - READ WRITE registers * Packet FC23 builder - READ WRITE registers
* *
* @param int $unitId * @param int $unitId
* @param int $referenceRead * @param int $referenceRead
* @param int $quantity * @param int $quantity
* @param int $referenceWrite * @param int $referenceWrite
* @param array $data * @param array $data
* @param array $dataTypes * @param array $dataTypes
* @return string * @return string
@ -1400,9 +1390,10 @@ class ModbusMaster
$referenceRead, $referenceRead,
$quantity, $quantity,
$referenceWrite, $referenceWrite,
$data, array $data,
$dataTypes array $dataTypes
) { )
{
$dataLen = 0; $dataLen = 0;
// build data section // build data section
@ -1481,7 +1472,7 @@ class ModbusMaster
/** /**
* Set socket read/write timeout. Null = no change. * Set socket read/write timeout. Null = no change.
* *
* @param float|null $read_timeout_sec data read timeout (seconds, default 0.3) * @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) * @param float|null $write_timeout_sec data write timeout (seconds, default 1.0)
* @internal param float $seconds seconds * @internal param float $seconds seconds
*/ */

Loading…
Cancel
Save