let modbus add send packet to status message, clean a little WriteMultipleCoilsPacket methods

pull/2/head
toimtoimtoim 8 years ago
parent 6561e406a1
commit f6818a21c4
  1. 5
      src/ModbusMaster.php
  2. 87
      src/Packet/WriteMultipleCoilsPacket.php
  3. 20
      tests/ModbusMaster/Fc15WriteMultipleCoilsTest.php

@ -179,7 +179,7 @@ class ModbusMaster
*/
private function printPacket($packet)
{
return 'Packet: ' . unpack('H*', $packet)[1] . "\n";
return 'packet: ' . unpack('H*', $packet)[1] . "\n";
}
/**
@ -480,11 +480,12 @@ class ModbusMaster
$socket->connect();
$packet = $buildRequest();
$this->status .= 'Sending ' . $this->printPacket($packet);
$socket->send($packet);
$data = $socket->receive();
$this->status .= $this->printPacket($data);
$this->status .= 'Received ' . $this->printPacket($data);
$this->validateResponseCode($data);
return $parseResponse($data);

@ -17,6 +17,9 @@ namespace PHPModbus\Packet;
use PHPModbus\IecType;
/**
* Builds/parses packet in Modbus TCP/IP format (http://www.simplymodbus.ca/TCP.htm)
*/
class WriteMultipleCoilsPacket
{
/**
@ -30,49 +33,25 @@ class WriteMultipleCoilsPacket
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;
}
list($pduData, $wordCount) = self::getDataConvertedToIecWords($data);
$dataLen += $wordCount;
// 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
$pduHeader = '';
$pduHeader .= IecType::iecBYTE(15); // FC 15 = 15(0x0f)
$pduHeader .= IecType::iecINT($reference); // refnumber = 12288
$pduHeader .= IecType::iecINT(count($data)); // bit count
$pduHeader .= 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;
$mbapHeader = '';
$mbapHeader .= IecType::iecINT(mt_rand(0, 65000)); // transaction ID
$mbapHeader .= IecType::iecINT(0); // protocol ID
$mbapHeader .= IecType::iecINT($dataLen + 1); // length
$mbapHeader .= IecType::iecBYTE($unitId); // unit ID
return $mbapHeader . $pduHeader . $pduData;
}
/**
@ -86,4 +65,32 @@ class WriteMultipleCoilsPacket
return true;
}
/**
* @param array $data
* @return array
*/
private static function getDataConvertedToIecWords(array $data)
{
$data_word_stream = array();
$data_word = 0;
$shift = 0;
for ($i = 0, $len = count($data); $i < $len; $i++) {
if ((($i % 8) === 0) && ($i > 0)) {
//shift to next word
$data_word_stream[] = $data_word;
$shift = 0;
$data_word = 0;
}
$data_word |= (0x01 && $data[$i]) << $shift;
$shift++;
}
$data_word_stream[] = $data_word;
$pduData = '';
foreach ($data_word_stream as $key => $dataitem) {
$pduData .= IecType::iecBYTE($dataitem);
}
return array($pduData, count($data_word_stream));
}
}

@ -18,4 +18,24 @@ class Fc15WriteMultipleCoilsTest extends MockServerTestCase
$packetWithoutTransactionId = substr($clientData[0], 4);
$this->assertEquals('00000008000f300000030105', $packetWithoutTransactionId);
}
public function testFc15WriteMultipleCoilsWithMultiWordPacket()
{
$mockResponse = 'a51100000006000f00000020';
$clientData = static::executeWithMockServer($mockResponse, function ($port) {
$modbus = new ModbusMaster('127.0.0.1', 'TCP');
$modbus->port = $port;
$this->assertTrue($modbus->fc15(0, 0,
[
1, 0, 1, 1, 0, 1, 1, 1,
1, 1, 1, 1, 0, 0, 0, 0,
0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
]));
});
$packetWithoutTransactionId = substr($clientData[0], 4);
$this->assertEquals('0000000b000f0000002004ed0ff0ff', $packetWithoutTransactionId);
}
}
Loading…
Cancel
Save