Skip to content

Commit 4d7b659

Browse files
committed
Allow high level api to specify custom endian for each address
1 parent 0ce52f3 commit 4d7b659

File tree

8 files changed

+325
-34
lines changed

8 files changed

+325
-34
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
55
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [2.2.0] - 2021-05-04
8+
9+
### Added
10+
11+
* Allow high level API setting custom endian for each address with `ReadRegistersBuilder` and `ReadRegisterAddress` classes.
12+
713
## [2.1.1] - 2021-01-26
814

915
### Fixed

README.md

+10-2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ Library supports following byte and word orders:
5353
* Little endian (DCBA - word1 = 0x3412, word2 = 0x7856)
5454
* Little endian low word first (BADC - word1 = 0x7856, word2 = 0x3412)
5555

56+
Default (global) endianess used for parsing can be changed with:
57+
```php
58+
Endian::$defaultEndian = Endian::BIG_ENDIAN_LOW_WORD_FIRST;
59+
```
60+
61+
For non-global cases see API methods argument list if method support using custom endianess.
62+
5663
See [Endian.php](src/Utils/Endian.php) for additional info and [Types.php](src/Utils/Types.php) for supported data types.
5764

5865
## Example of Modbus TCP (fc3 - read holding registers)
@@ -90,8 +97,9 @@ $fc3 = ReadRegistersBuilder::newReadHoldingRegisters($address, $unitID)
9097
->build(); // returns array of 3 ReadHoldingRegistersRequest requests
9198

9299
// this will use PHP non-blocking stream io to recieve responses
93-
$responses = (new NonBlockingClient(['readTimeoutSec' => 0.2]))->sendRequests($fc3);
94-
print_r($responses);
100+
$responseContainer = (new NonBlockingClient(['readTimeoutSec' => 0.2]))->sendRequests($fc3);
101+
print_r($responseContainer->getData()); // array of assoc. arrays (keyed by address name)
102+
print_r($responseContainer->getErrors());
95103
```
96104
Response structure
97105
```php

examples/example_parallel_requests.php

+6-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
use ModbusTcpClient\Composer\Address;
66
use ModbusTcpClient\Composer\Read\ReadRegistersBuilder;
77
use ModbusTcpClient\Network\NonBlockingClient;
8+
use ModbusTcpClient\Utils\Endian;
9+
10+
Endian::$defaultEndian = Endian::BIG_ENDIAN_LOW_WORD_FIRST; // set default (global) endian used for parsing data
811

912
$fc3 = ReadRegistersBuilder::newReadHoldingRegisters('tcp://127.0.0.1:5022')
1013
->bit(256, 15, 'pump2_feedbackalarm_do')
@@ -14,7 +17,7 @@
1417
->int16(657, 'battery3_voltage_wo')
1518
->uint16(658, 'wind_angle_wo')
1619
->int32(659, 'gps_speed')
17-
->uint32(661, 'distance_total_wo')
20+
->uint32(661, 'distance_total_wo', null, null, Endian::BIG_ENDIAN) // use custom endianess
1821
->uint64(663, 'gen2_energyw0_wo')
1922
->float(667, 'longitude')
2023
->string(669, 10, 'username')
@@ -35,4 +38,5 @@ function (\Exception $exception, Address $address, $response) {
3538
->build(); // returns array of 3 requests
3639

3740
$responseContainer = (new NonBlockingClient(['readTimeoutSec' => 0.2]))->sendRequests($fc3);
38-
print_r($responseContainer);
41+
print_r($responseContainer->getData()); // array of assoc. arrays (keyed by address name)
42+
print_r($responseContainer->getErrors());

examples/fc3.php

+3
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
use ModbusTcpClient\Packet\ModbusFunction\ReadHoldingRegistersRequest;
55
use ModbusTcpClient\Packet\ModbusFunction\ReadHoldingRegistersResponse;
66
use ModbusTcpClient\Packet\ResponseFactory;
7+
use ModbusTcpClient\Utils\Endian;
78

89
require __DIR__ . '/../vendor/autoload.php';
910
require __DIR__ . '/logger.php';
1011

12+
Endian::$defaultEndian = Endian::BIG_ENDIAN_LOW_WORD_FIRST; // set default (global) endian used for parsing data
13+
1114
$connection = BinaryStreamConnection::getBuilder()
1215
->setPort(5020)
1316
->setHost('127.0.0.1')

src/Composer/Read/ReadRegistersBuilder.php

+125-21
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use ModbusTcpClient\Exception\InvalidArgumentException;
1515
use ModbusTcpClient\Packet\ModbusFunction\ReadHoldingRegistersRequest;
1616
use ModbusTcpClient\Packet\ModbusFunction\ReadInputRegistersRequest;
17+
use ModbusTcpClient\Utils\Endian;
1718

1819
class ReadRegistersBuilder
1920
{
@@ -109,6 +110,11 @@ public function fromArray(array $register): ReadRegistersBuilder
109110
throw new InvalidArgumentException('empty or unknown type for address given');
110111
}
111112

113+
$endian = $register['endian'] ?? null;
114+
if ($endian === null) {
115+
$endian = Endian::$defaultEndian;
116+
}
117+
112118
switch ($addressType) {
113119
case Address::TYPE_BIT:
114120
$this->bit($address, $register['bit'] ?? 0, $register['name'] ?? null, $callback, $errorCallback);
@@ -117,25 +123,25 @@ public function fromArray(array $register): ReadRegistersBuilder
117123
$this->byte($address, (bool)($register['firstByte'] ?? true), $register['name'] ?? null, $callback, $errorCallback);
118124
break;
119125
case Address::TYPE_INT16:
120-
$this->int16($address, $register['name'] ?? null, $callback, $errorCallback);
126+
$this->int16($address, $register['name'] ?? null, $callback, $errorCallback, $endian);
121127
break;
122128
case Address::TYPE_UINT16:
123-
$this->uint16($address, $register['name'] ?? null, $callback, $errorCallback);
129+
$this->uint16($address, $register['name'] ?? null, $callback, $errorCallback, $endian);
124130
break;
125131
case Address::TYPE_INT32:
126-
$this->int32($address, $register['name'] ?? null, $callback, $errorCallback);
132+
$this->int32($address, $register['name'] ?? null, $callback, $errorCallback, $endian);
127133
break;
128134
case Address::TYPE_UINT32:
129-
$this->uint32($address, $register['name'] ?? null, $callback, $errorCallback);
135+
$this->uint32($address, $register['name'] ?? null, $callback, $errorCallback, $endian);
130136
break;
131137
case Address::TYPE_INT64:
132-
$this->int64($address, $register['name'] ?? null, $callback, $errorCallback);
138+
$this->int64($address, $register['name'] ?? null, $callback, $errorCallback, $endian);
133139
break;
134140
case Address::TYPE_UINT64:
135-
$this->uint64($address, $register['name'] ?? null, $callback, $errorCallback);
141+
$this->uint64($address, $register['name'] ?? null, $callback, $errorCallback, $endian);
136142
break;
137143
case Address::TYPE_FLOAT:
138-
$this->float($address, $register['name'] ?? null, $callback, $errorCallback);
144+
$this->float($address, $register['name'] ?? null, $callback, $errorCallback, $endian);
139145
break;
140146
case Address::TYPE_STRING:
141147
$byteLength = $register['length'] ?? null;
@@ -161,39 +167,137 @@ public function byte(int $address, bool $firstByte = true, string $name = null,
161167
return $this->addAddress(new ByteReadRegisterAddress($address, $firstByte, $name, $callback, $errorCallback));
162168
}
163169

164-
public function int16(int $address, string $name = null, callable $callback = null, callable $errorCallback = null): ReadRegistersBuilder
170+
public function int16(
171+
int $address,
172+
string $name = null,
173+
callable $callback = null,
174+
callable $errorCallback = null,
175+
int $endian = null
176+
): ReadRegistersBuilder
165177
{
166-
return $this->addAddress(new ReadRegisterAddress($address, ReadRegisterAddress::TYPE_INT16, $name, $callback, $errorCallback));
178+
$r = new ReadRegisterAddress(
179+
$address,
180+
ReadRegisterAddress::TYPE_INT16,
181+
$name,
182+
$callback,
183+
$errorCallback,
184+
$endian
185+
);
186+
return $this->addAddress($r);
167187
}
168188

169-
public function uint16(int $address, string $name = null, callable $callback = null, callable $errorCallback = null): ReadRegistersBuilder
189+
public function uint16(
190+
int $address,
191+
string $name = null,
192+
callable $callback = null,
193+
callable $errorCallback = null,
194+
int $endian = null
195+
): ReadRegistersBuilder
170196
{
171-
return $this->addAddress(new ReadRegisterAddress($address, ReadRegisterAddress::TYPE_UINT16, $name, $callback, $errorCallback));
197+
$r = new ReadRegisterAddress(
198+
$address,
199+
ReadRegisterAddress::TYPE_UINT16,
200+
$name,
201+
$callback,
202+
$errorCallback,
203+
$endian
204+
);
205+
return $this->addAddress($r);
172206
}
173207

174-
public function int32(int $address, string $name = null, callable $callback = null, callable $errorCallback = null): ReadRegistersBuilder
208+
public function int32(
209+
int $address,
210+
string $name = null,
211+
callable $callback = null,
212+
callable $errorCallback = null,
213+
int $endian = null
214+
): ReadRegistersBuilder
175215
{
176-
return $this->addAddress(new ReadRegisterAddress($address, ReadRegisterAddress::TYPE_INT32, $name, $callback, $errorCallback));
216+
$r = new ReadRegisterAddress(
217+
$address,
218+
ReadRegisterAddress::TYPE_INT32,
219+
$name,
220+
$callback,
221+
$errorCallback,
222+
$endian
223+
);
224+
return $this->addAddress($r);
177225
}
178226

179-
public function uint32(int $address, string $name = null, callable $callback = null, callable $errorCallback = null): ReadRegistersBuilder
227+
public function uint32(
228+
int $address,
229+
string $name = null,
230+
callable $callback = null,
231+
callable $errorCallback = null,
232+
int $endian = null
233+
): ReadRegistersBuilder
180234
{
181-
return $this->addAddress(new ReadRegisterAddress($address, ReadRegisterAddress::TYPE_UINT32, $name, $callback, $errorCallback));
235+
$r = new ReadRegisterAddress(
236+
$address,
237+
ReadRegisterAddress::TYPE_UINT32,
238+
$name,
239+
$callback,
240+
$errorCallback,
241+
$endian
242+
);
243+
return $this->addAddress($r);
182244
}
183245

184-
public function uint64(int $address, string $name = null, callable $callback = null, callable $errorCallback = null): ReadRegistersBuilder
246+
public function uint64(
247+
int $address,
248+
string $name = null,
249+
callable $callback = null,
250+
callable $errorCallback = null,
251+
int $endian = null
252+
): ReadRegistersBuilder
185253
{
186-
return $this->addAddress(new ReadRegisterAddress($address, ReadRegisterAddress::TYPE_UINT64, $name, $callback, $errorCallback));
254+
$r = new ReadRegisterAddress(
255+
$address,
256+
ReadRegisterAddress::TYPE_UINT64,
257+
$name,
258+
$callback,
259+
$errorCallback,
260+
$endian
261+
);
262+
return $this->addAddress($r);
187263
}
188264

189-
public function int64(int $address, string $name = null, callable $callback = null, callable $errorCallback = null): ReadRegistersBuilder
265+
public function int64(
266+
int $address,
267+
string $name = null,
268+
callable $callback = null,
269+
callable $errorCallback = null,
270+
int $endian = null
271+
): ReadRegistersBuilder
190272
{
191-
return $this->addAddress(new ReadRegisterAddress($address, ReadRegisterAddress::TYPE_INT64, $name, $callback, $errorCallback));
273+
$r = new ReadRegisterAddress(
274+
$address,
275+
ReadRegisterAddress::TYPE_INT64,
276+
$name,
277+
$callback,
278+
$errorCallback,
279+
$endian
280+
);
281+
return $this->addAddress($r);
192282
}
193283

194-
public function float(int $address, string $name = null, callable $callback = null, callable $errorCallback = null): ReadRegistersBuilder
284+
public function float(
285+
int $address,
286+
string $name = null,
287+
callable $callback = null,
288+
callable $errorCallback = null,
289+
int $endian = null
290+
): ReadRegistersBuilder
195291
{
196-
return $this->addAddress(new ReadRegisterAddress($address, ReadRegisterAddress::TYPE_FLOAT, $name, $callback, $errorCallback));
292+
$r = new ReadRegisterAddress(
293+
$address,
294+
ReadRegisterAddress::TYPE_FLOAT,
295+
$name,
296+
$callback,
297+
$errorCallback,
298+
$endian
299+
);
300+
return $this->addAddress($r);
197301
}
198302

199303
public function string(int $address, int $byteLength, string $name = null, callable $callback = null, callable $errorCallback = null): ReadRegistersBuilder

src/Composer/Read/Register/ReadRegisterAddress.php

+25-8
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use ModbusTcpClient\Composer\Address;
77
use ModbusTcpClient\Composer\RegisterAddress;
88
use ModbusTcpClient\Packet\ModbusResponse;
9+
use ModbusTcpClient\Utils\Endian;
910

1011
class ReadRegisterAddress extends RegisterAddress
1112
{
@@ -18,10 +19,21 @@ class ReadRegisterAddress extends RegisterAddress
1819
/** @var callable */
1920
private $errorCallback;
2021

21-
public function __construct(int $address, string $type, string $name = null, callable $callback = null, callable $errorCallback = null)
22+
/** @var int */
23+
private $endian;
24+
25+
public function __construct(
26+
int $address,
27+
string $type,
28+
string $name = null,
29+
callable $callback = null,
30+
callable $errorCallback = null,
31+
int $endian = null
32+
)
2233
{
2334
parent::__construct($address, $type);
2435

36+
$this->endian = $endian === null ? Endian::$defaultEndian : $endian;
2537
$this->name = $name ?: "{$type}_{$address}";
2638
$this->callback = $callback;
2739
$this->errorCallback = $errorCallback;
@@ -45,25 +57,25 @@ protected function extractInternal(ModbusResponse $response)
4557
$result = null;
4658
switch ($this->type) {
4759
case Address::TYPE_INT16:
48-
$result = $response->getWordAt($this->address)->getInt16();
60+
$result = $response->getWordAt($this->address)->getInt16($this->endian);
4961
break;
5062
case Address::TYPE_UINT16:
51-
$result = $response->getWordAt($this->address)->getUInt16();
63+
$result = $response->getWordAt($this->address)->getUInt16($this->endian);
5264
break;
5365
case Address::TYPE_INT32:
54-
$result = $response->getDoubleWordAt($this->address)->getInt32();
66+
$result = $response->getDoubleWordAt($this->address)->getInt32($this->endian);
5567
break;
5668
case Address::TYPE_UINT32:
57-
$result = $response->getDoubleWordAt($this->address)->getUInt32();
69+
$result = $response->getDoubleWordAt($this->address)->getUInt32($this->endian);
5870
break;
5971
case Address::TYPE_FLOAT:
60-
$result = $response->getDoubleWordAt($this->address)->getFloat();
72+
$result = $response->getDoubleWordAt($this->address)->getFloat($this->endian);
6173
break;
6274
case Address::TYPE_INT64:
63-
$result = $response->getQuadWordAt($this->address)->getInt64();
75+
$result = $response->getQuadWordAt($this->address)->getInt64($this->endian);
6476
break;
6577
case Address::TYPE_UINT64:
66-
$result = $response->getQuadWordAt($this->address)->getUInt64();
78+
$result = $response->getQuadWordAt($this->address)->getUInt64($this->endian);
6779
break;
6880
}
6981
return $result;
@@ -96,4 +108,9 @@ public function getName(): string
96108
{
97109
return $this->name;
98110
}
111+
112+
public function getEndian(): int
113+
{
114+
return $this->endian;
115+
}
99116
}

0 commit comments

Comments
 (0)