Skip to content

Commit

Permalink
fix setting endian before creating request will create invalid request
Browse files Browse the repository at this point in the history
  • Loading branch information
aldas committed Jun 14, 2023
1 parent 8ccb744 commit f03e44a
Show file tree
Hide file tree
Showing 27 changed files with 257 additions and 20 deletions.
6 changes: 5 additions & 1 deletion examples/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
// sudo udevadm control --reload-rules && sudo udevadm trigger
$deviceURI = '/dev/ttyUSB0'; // do not make this changeable from WEB. This could be serious security risk.
$isSerialDevice = false; // change to true to enable reading serial devices. this will disable ip/port logic and uses RTU
if (getenv('MODBUS_SERIAL_ENABLED')) { // can be set from Nginx/Apache fast-cgi conf
if (getenv('MODBUS_SERIAL_ENABLED')) {
// can be set from Nginx/Apache fast-cgi conf
// for Nginx add these lines where you PHP is configured:
// fastcgi_param MODBUS_SERIAL_ENABLED true;
// fastcgi_param MODBUS_SERIAL_DEVICE /dev/ttyUSB0;
$isSerialDevice = filter_var(getenv('MODBUS_SERIAL_ENABLED'), FILTER_VALIDATE_BOOLEAN);
if ($isSerialDevice && getenv('MODBUS_SERIAL_DEVICE')) {
$deviceURI = getenv('MODBUS_SERIAL_DEVICE');
Expand Down
5 changes: 3 additions & 2 deletions src/Packet/ModbusApplicationHeader.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use ModbusTcpClient\Exception\InvalidArgumentException;
use ModbusTcpClient\Exception\ModbusException;
use ModbusTcpClient\Utils\Endian;
use ModbusTcpClient\Utils\Types;

/**
Expand Down Expand Up @@ -100,8 +101,8 @@ public static function parse(string $binaryString): ModbusApplicationHeader
throw new ModbusException('Data length too short to be valid header!');
}

$transactionId = Types::parseUInt16($binaryString[0] . $binaryString[1]);
$length = Types::parseUInt16($binaryString[4] . $binaryString[5]);
$transactionId = Types::parseUInt16($binaryString[0] . $binaryString[1], Endian::BIG_ENDIAN);
$length = Types::parseUInt16($binaryString[4] . $binaryString[5], Endian::BIG_ENDIAN);
$unitId = Types::parseByte($binaryString[6]);

return new ModbusApplicationHeader(
Expand Down
4 changes: 2 additions & 2 deletions src/Packet/ModbusFunction/MaskWriteRegisterRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,15 @@ public function getORMask(): int
*/
public function getANDMaskAsWord(): Word
{
return new Word(Types::toInt16($this->andMask));
return new Word(Types::toInt16($this->andMask, Endian::BIG_ENDIAN));
}

/**
* @return Word
*/
public function getORMaskAsWord(): Word
{
return new Word(Types::toInt16($this->orMask));
return new Word(Types::toInt16($this->orMask, Endian::BIG_ENDIAN));
}

protected function getLengthInternal(): int
Expand Down
4 changes: 2 additions & 2 deletions src/Packet/ModbusFunction/MaskWriteRegisterResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,14 @@ public function getORMask(): int
*/
public function getANDMaskAsWord(): Word
{
return new Word(Types::toInt16($this->andMask));
return new Word(Types::toInt16($this->andMask, Endian::BIG_ENDIAN));
}

/**
* @return Word
*/
public function getORMaskAsWord(): Word
{
return new Word(Types::toInt16($this->orMask));
return new Word(Types::toInt16($this->orMask, Endian::BIG_ENDIAN));
}
}
2 changes: 1 addition & 1 deletion src/Packet/ProtocolDataUnitRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function __toString(): string
return b''
. $this->getHeader()->__toString()
. Types::toByte($this->getFunctionCode())
. Types::toUint16($this->getStartAddress());
. Types::toUint16($this->getStartAddress(), Endian::BIG_ENDIAN);
}

public function getStartAddress(): int
Expand Down
3 changes: 2 additions & 1 deletion src/Packet/ResponseFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use ModbusTcpClient\Packet\ModbusFunction\WriteMultipleRegistersResponse;
use ModbusTcpClient\Packet\ModbusFunction\WriteSingleCoilResponse;
use ModbusTcpClient\Packet\ModbusFunction\WriteSingleRegisterResponse;
use ModbusTcpClient\Utils\Endian;
use ModbusTcpClient\Utils\Types;

class ResponseFactory
Expand All @@ -40,7 +41,7 @@ public static function parseResponse(string|null $binaryString): ModbusResponse|
return new ErrorResponse(ModbusApplicationHeader::parse($binaryString), $functionCode, $exceptionCode);
}

$transactionId = Types::parseUInt16($binaryString[0] . $binaryString[1]);
$transactionId = Types::parseUInt16($binaryString[0] . $binaryString[1], Endian::BIG_ENDIAN);
$unitId = Types::parseByte($binaryString[6]);

$rawData = substr($binaryString, 8);
Expand Down
3 changes: 2 additions & 1 deletion src/Packet/StartAddressResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace ModbusTcpClient\Packet;


use ModbusTcpClient\Utils\Endian;
use ModbusTcpClient\Utils\Types;

abstract class StartAddressResponse extends ProtocolDataUnit implements ModbusResponse
Expand All @@ -16,7 +17,7 @@ abstract class StartAddressResponse extends ProtocolDataUnit implements ModbusRe
public function __construct(string $rawData, int $unitId = 0, int $transactionId = null)
{
parent::__construct($unitId, $transactionId);
$this->startAddress = Types::parseUInt16(substr($rawData, 0, 2));
$this->startAddress = Types::parseUInt16(substr($rawData, 0, 2), Endian::BIG_ENDIAN);
}

public function __toString(): string
Expand Down
11 changes: 11 additions & 0 deletions tests/unit/Packet/ModbusFunction/MaskWriteRegisterRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,22 @@
use ModbusTcpClient\Packet\ModbusFunction\MaskWriteRegisterRequest;
use ModbusTcpClient\Packet\ModbusPacket;
use ModbusTcpClient\Packet\Word;
use ModbusTcpClient\Utils\Endian;
use ModbusTcpClient\Utils\Types;
use PHPUnit\Framework\TestCase;

class MaskWriteRegisterRequestTest extends TestCase
{
protected function setUp(): void
{
Endian::$defaultEndian = Endian::LITTLE_ENDIAN; // packets are big endian. setting to default to little should not change output
}

protected function tearDown(): void
{
Endian::$defaultEndian = Endian::BIG_ENDIAN_LOW_WORD_FIRST;
}

public function testOnPacketToString()
{
// Field: Size in packet
Expand Down
11 changes: 11 additions & 0 deletions tests/unit/Packet/ModbusFunction/MaskWriteRegisterResponseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,21 @@
use ModbusTcpClient\Packet\ModbusFunction\MaskWriteRegisterResponse;
use ModbusTcpClient\Packet\ModbusPacket;
use ModbusTcpClient\Packet\Word;
use ModbusTcpClient\Utils\Endian;
use PHPUnit\Framework\TestCase;

class MaskWriteRegisterResponseTest extends TestCase
{
protected function setUp(): void
{
Endian::$defaultEndian = Endian::LITTLE_ENDIAN; // packets are big endian. setting to default to little should not change output
}

protected function tearDown(): void
{
Endian::$defaultEndian = Endian::BIG_ENDIAN_LOW_WORD_FIRST;
}

public function testOnPacketToString()
{
// Field: Size in packet
Expand Down
11 changes: 11 additions & 0 deletions tests/unit/Packet/ModbusFunction/ReadCoilsRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,21 @@
use ModbusTcpClient\Packet\ErrorResponse;
use ModbusTcpClient\Packet\ModbusFunction\ReadCoilsRequest;
use ModbusTcpClient\Packet\ModbusPacket;
use ModbusTcpClient\Utils\Endian;
use PHPUnit\Framework\TestCase;

class ReadCoilsRequestTest extends TestCase
{
protected function setUp(): void
{
Endian::$defaultEndian = Endian::LITTLE_ENDIAN; // packets are big endian. setting to default to little should not change output
}

protected function tearDown(): void
{
Endian::$defaultEndian = Endian::BIG_ENDIAN_LOW_WORD_FIRST;
}

public function testPacketToString()
{
$this->assertEquals(
Expand Down
12 changes: 12 additions & 0 deletions tests/unit/Packet/ModbusFunction/ReadCoilsResponseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,29 @@
use ModbusTcpClient\Exception\ParseException;
use ModbusTcpClient\Packet\ModbusFunction\ReadCoilsResponse;
use ModbusTcpClient\Packet\ModbusPacket;
use ModbusTcpClient\Utils\Endian;
use PHPUnit\Framework\TestCase;

class ReadCoilsResponseTest extends TestCase
{
protected function setUp(): void
{
Endian::$defaultEndian = Endian::LITTLE_ENDIAN; // packets are big endian. setting to default to little should not change output
}

protected function tearDown(): void
{
Endian::$defaultEndian = Endian::BIG_ENDIAN_LOW_WORD_FIRST;
}

public function testPacketToString()
{
$this->assertEquals(
"\x81\x80\x00\x00\x00\x05\x03\x01\x02\xCD\x6B",
(new ReadCoilsResponse("\x02\xCD\x6B", 3, 33152))->__toString()
);
}

public function testToHex()
{
$this->assertEquals(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use ModbusTcpClient\Packet\ErrorResponse;
use ModbusTcpClient\Packet\ModbusFunction\ReadHoldingRegistersRequest;
use ModbusTcpClient\Packet\ModbusPacket;
use ModbusTcpClient\Utils\Endian;
use PHPUnit\Framework\TestCase;

/*
Expand All @@ -25,6 +26,16 @@

class ReadHoldingRegistersRequestTest extends TestCase
{
protected function setUp(): void
{
Endian::$defaultEndian = Endian::LITTLE_ENDIAN; // packets are big endian. setting to default to little should not change output
}

protected function tearDown(): void
{
Endian::$defaultEndian = Endian::BIG_ENDIAN_LOW_WORD_FIRST;
}

public function testPacketToString()
{
$this->assertEquals(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,21 @@
use ModbusTcpClient\Exception\ParseException;
use ModbusTcpClient\Packet\ModbusFunction\ReadHoldingRegistersResponse;
use ModbusTcpClient\Packet\ModbusPacket;
use ModbusTcpClient\Utils\Endian;
use PHPUnit\Framework\TestCase;

class ReadHoldingRegistersResponseTest extends TestCase
{
protected function setUp(): void
{
Endian::$defaultEndian = Endian::LITTLE_ENDIAN; // packets are big endian. setting to default to little should not change output
}

protected function tearDown(): void
{
Endian::$defaultEndian = Endian::BIG_ENDIAN_LOW_WORD_FIRST;
}

public function testPacketToString()
{
$this->assertEquals(
Expand Down Expand Up @@ -341,7 +352,7 @@ public function testGetAsciiString()
$packet = (new ReadHoldingRegistersResponse("\x08\x01\x00\xF8\x53\x65\x72\x00\x6E", 3, 33152))->withStartAddress(50);
$this->assertCount(4, $packet->getWords());

$this->assertEquals('Søren', $packet->getAsciiStringAt(51, 5));
$this->assertEquals('Søren', $packet->getAsciiStringAt(51, 5, Endian::BIG_ENDIAN_LOW_WORD_FIRST));
}

public function testGetAsciiStringInvalidAddressLow()
Expand Down
11 changes: 11 additions & 0 deletions tests/unit/Packet/ModbusFunction/ReadInputDiscretesRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,21 @@
use ModbusTcpClient\Packet\ErrorResponse;
use ModbusTcpClient\Packet\ModbusFunction\ReadInputDiscretesRequest;
use ModbusTcpClient\Packet\ModbusPacket;
use ModbusTcpClient\Utils\Endian;
use PHPUnit\Framework\TestCase;

class ReadInputDiscretesRequestTest extends TestCase
{
protected function setUp(): void
{
Endian::$defaultEndian = Endian::LITTLE_ENDIAN; // packets are big endian. setting to default to little should not change output
}

protected function tearDown(): void
{
Endian::$defaultEndian = Endian::BIG_ENDIAN_LOW_WORD_FIRST;
}

public function testPacketToString()
{
$this->assertEquals(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,21 @@
use ModbusTcpClient\Exception\ParseException;
use ModbusTcpClient\Packet\ModbusFunction\ReadInputDiscretesResponse;
use ModbusTcpClient\Packet\ModbusPacket;
use ModbusTcpClient\Utils\Endian;
use PHPUnit\Framework\TestCase;

class ReadInputDiscretesResponseTest extends TestCase
{
protected function setUp(): void
{
Endian::$defaultEndian = Endian::LITTLE_ENDIAN; // packets are big endian. setting to default to little should not change output
}

protected function tearDown(): void
{
Endian::$defaultEndian = Endian::BIG_ENDIAN_LOW_WORD_FIRST;
}

public function testPacketToString()
{
$this->assertEquals(
Expand Down
11 changes: 11 additions & 0 deletions tests/unit/Packet/ModbusFunction/ReadInputRegistersRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,21 @@
use ModbusTcpClient\Packet\ErrorResponse;
use ModbusTcpClient\Packet\ModbusFunction\ReadInputRegistersRequest;
use ModbusTcpClient\Packet\ModbusPacket;
use ModbusTcpClient\Utils\Endian;
use PHPUnit\Framework\TestCase;

class ReadInputRegistersRequestTest extends TestCase
{
protected function setUp(): void
{
Endian::$defaultEndian = Endian::LITTLE_ENDIAN; // packets are big endian. setting to default to little should not change output
}

protected function tearDown(): void
{
Endian::$defaultEndian = Endian::BIG_ENDIAN_LOW_WORD_FIRST;
}

public function testPacketToString()
{
$this->assertEquals(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,21 @@
use ModbusTcpClient\Exception\ParseException;
use ModbusTcpClient\Packet\ModbusFunction\ReadInputRegistersResponse;
use ModbusTcpClient\Packet\ModbusPacket;
use ModbusTcpClient\Utils\Endian;
use PHPUnit\Framework\TestCase;

class ReadInputRegistersResponseTest extends TestCase
{
protected function setUp(): void
{
Endian::$defaultEndian = Endian::LITTLE_ENDIAN; // packets are big endian. setting to default to little should not change output
}

protected function tearDown(): void
{
Endian::$defaultEndian = Endian::BIG_ENDIAN_LOW_WORD_FIRST;
}

public function testPacketToString()
{
$this->assertEquals(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,22 @@
use ModbusTcpClient\Packet\ErrorResponse;
use ModbusTcpClient\Packet\ModbusFunction\ReadWriteMultipleRegistersRequest;
use ModbusTcpClient\Packet\ModbusPacket;
use ModbusTcpClient\Utils\Endian;
use ModbusTcpClient\Utils\Types;
use PHPUnit\Framework\TestCase;

class ReadWriteMultipleRegistersRequestTest extends TestCase
{
protected function setUp(): void
{
Endian::$defaultEndian = Endian::LITTLE_ENDIAN; // packets are big endian. setting to default to little should not change output
}

protected function tearDown(): void
{
Endian::$defaultEndian = Endian::BIG_ENDIAN_LOW_WORD_FIRST;
}

public function testOnPacketToString()
{
// Field: Size in packet
Expand All @@ -32,7 +43,7 @@ public function testOnPacketToString()
0x0410,
1,
0x0112,
[Types::toByte(200), Types::toInt16(130)],
[Types::toByte(200), Types::toInt16(130, Endian::BIG_ENDIAN_LOW_WORD_FIRST)],
0x11,
0x0138
))->__toString()
Expand Down Expand Up @@ -176,7 +187,7 @@ public function testParse()
0x0410,
1,
0x0112,
[Types::toByte(200), Types::toInt16(130)],
[Types::toByte(200), Types::toInt16(130, Endian::BIG_ENDIAN_LOW_WORD_FIRST)],
0x11,
0x0138
))->__toString());
Expand Down
Loading

0 comments on commit f03e44a

Please sign in to comment.