]> git.basschouten.com Git - openhab-addons.git/blob
e5b0819b5fc402f0b7867177d0c38e6077f2b19a
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.io.transport.modbus.test;
14
15 import static org.hamcrest.CoreMatchers.*;
16 import static org.hamcrest.MatcherAssert.assertThat;
17 import static org.junit.jupiter.api.Assertions.assertThrows;
18
19 import java.util.Collection;
20 import java.util.Collections;
21 import java.util.stream.Collectors;
22 import java.util.stream.Stream;
23
24 import org.apache.commons.lang.NotImplementedException;
25 import org.junit.jupiter.params.ParameterizedTest;
26 import org.junit.jupiter.params.provider.MethodSource;
27 import org.openhab.core.library.types.DecimalType;
28 import org.openhab.core.library.types.IncreaseDecreaseType;
29 import org.openhab.core.library.types.OnOffType;
30 import org.openhab.core.library.types.OpenClosedType;
31 import org.openhab.core.types.Command;
32 import org.openhab.io.transport.modbus.ModbusBitUtilities;
33 import org.openhab.io.transport.modbus.ModbusConstants.ValueType;
34 import org.openhab.io.transport.modbus.ModbusRegisterArray;
35
36 /**
37  * @author Sami Salonen - Initial contribution
38  */
39 public class BitUtilitiesCommandToRegistersTest {
40
41     private static short[] shorts(int... ints) {
42         short[] shorts = new short[ints.length];
43         for (int i = 0; i < ints.length; i++) {
44             short s = (short) ints[i];
45             shorts[i] = s;
46         }
47         return shorts;
48     }
49
50     public static Collection<Object[]> data() {
51         return Collections.unmodifiableList(Stream
52                 .of(new Object[] { new DecimalType("1.0"), ValueType.BIT, IllegalArgumentException.class },
53                         new Object[] { new DecimalType("1.0"), ValueType.INT8, IllegalArgumentException.class },
54                         //
55                         // INT16
56                         //
57                         new Object[] { new DecimalType("1.0"), ValueType.INT16, shorts(1) },
58                         new Object[] { new DecimalType("1.6"), ValueType.INT16, shorts(1) },
59                         new Object[] { new DecimalType("2.6"), ValueType.INT16, shorts(2) },
60                         new Object[] { new DecimalType("-1004.4"), ValueType.INT16, shorts(-1004), },
61                         // within bounds for signed int16
62                         new Object[] { new DecimalType("32000"), ValueType.INT16, shorts(32000), },
63                         new Object[] { new DecimalType("-32000"), ValueType.INT16, shorts(-32000), },
64                         // out bounds for signed int16, but not for uint16
65                         new Object[] { new DecimalType("60000"), ValueType.INT16, shorts(60000), },
66                         new Object[] { new DecimalType("64000"), ValueType.INT16, shorts(64000), }, //
67                         new Object[] {
68                                 // out of bounds of unsigned 16bit (0 to 65,535)
69                                 new DecimalType("70004.4"),
70                                 // 70004 -> 0x00011174 (int) -> 0x1174 (short) = 4468
71                                 ValueType.INT16, shorts(4468), },
72                         //
73                         // UINT16 (same as INT16)
74                         //
75                         new Object[] { new DecimalType("1.0"), ValueType.UINT16, shorts(1) },
76                         new Object[] { new DecimalType("1.6"), ValueType.UINT16, shorts(1) },
77                         new Object[] { new DecimalType("2.6"), ValueType.UINT16, shorts(2) },
78                         new Object[] { new DecimalType("-1004.4"), ValueType.UINT16, shorts(-1004), },
79                         // within bounds for signed int16
80                         new Object[] { new DecimalType("32000"), ValueType.UINT16, shorts(32000), },
81                         new Object[] { new DecimalType("-32000"), ValueType.UINT16, shorts(-32000), },
82                         // out bounds for signed int16, but not for uint16
83                         new Object[] { new DecimalType("60000"), ValueType.UINT16, shorts(60000), },
84                         new Object[] { new DecimalType("64000"), ValueType.UINT16, shorts(64000), }, //
85                         new Object[] {
86                                 // out of bounds of unsigned 16bit (0 to 65,535)
87                                 new DecimalType("70004.4"),
88                                 // 70004 -> 0x00011174 (32bit) -> 0x1174 (16bit)
89                                 ValueType.UINT16, shorts(0x1174), },
90                         //
91                         // INT32
92                         //
93                         new Object[] { new DecimalType("1.0"), ValueType.INT32, shorts(0, 1) },
94                         new Object[] { new DecimalType("1.6"), ValueType.INT32, shorts(0, 1) },
95                         new Object[] { new DecimalType("2.6"), ValueType.INT32, shorts(0, 2) },
96                         new Object[] { new DecimalType("-1004.4"), ValueType.INT32,
97                                 // -1004 = 0xFFFFFC14 (32bit) =
98                                 shorts(0xFFFF, 0xFC14), },
99                         new Object[] { new DecimalType("64000"), ValueType.INT32, shorts(0, 64000), }, //
100                         // within signed int32 range: +-2,000,000,00
101                         new Object[] { new DecimalType("-2000000000"), ValueType.INT32, shorts(0x88CA, 0x6C00), },
102                         new Object[] { new DecimalType("2000000000"), ValueType.INT32, shorts(0x7735, 0x9400), },
103                         // out bounds for signed int32, but not for uint32
104                         new Object[] { new DecimalType("3000000000"), ValueType.INT32, shorts(0xB2D0, 0x5E00), }, //
105                         new Object[] {
106                                 // out of bounds of unsigned 32bit (0 to 4,294,967,295)
107                                 new DecimalType("5000000000"),
108                                 // 5000000000 -> 0x12a05f200 () -> 0x1174 (16bit)
109                                 ValueType.INT32, shorts(0x2a05, 0xf200), },
110                         //
111                         // UINT32 (same as INT32)
112                         //
113                         new Object[] { new DecimalType("1.0"), ValueType.UINT32, shorts(0, 1) },
114                         new Object[] { new DecimalType("1.6"), ValueType.UINT32, shorts(0, 1) },
115                         new Object[] { new DecimalType("2.6"), ValueType.UINT32, shorts(0, 2) },
116                         new Object[] { new DecimalType("-1004.4"), ValueType.UINT32,
117                                 // -1004 = 0xFFFFFC14 (32bit) =
118                                 shorts(0xFFFF, 0xFC14), },
119                         new Object[] { new DecimalType("64000"), ValueType.UINT32, shorts(0, 64000), }, //
120                         // within signed int32 range: +-2,000,000,00
121                         new Object[] { new DecimalType("-2000000000"), ValueType.UINT32, shorts(0x88CA, 0x6C00), },
122                         new Object[] { new DecimalType("2000000000"), ValueType.UINT32, shorts(0x7735, 0x9400), },
123                         // out bounds for signed int32, but not for uint32
124                         new Object[] { new DecimalType("3000000000"), ValueType.UINT32, shorts(0xB2D0, 0x5E00), }, //
125                         new Object[] {
126                                 // out of bounds of unsigned 32bit (0 to 4,294,967,295)
127                                 new DecimalType("5000000000"),
128                                 // 5000000000 -> 0x12a05f200 () -> 0x1174 (16bit)
129                                 ValueType.UINT32, shorts(0x2a05, 0xf200), },
130                         //
131                         // INT32_SWAP
132                         //
133                         new Object[] { new DecimalType("1.0"), ValueType.INT32_SWAP, shorts(1, 0) },
134                         new Object[] { new DecimalType("1.6"), ValueType.INT32_SWAP, shorts(1, 0) },
135                         new Object[] { new DecimalType("2.6"), ValueType.INT32_SWAP, shorts(2, 0) },
136                         new Object[] { new DecimalType("-1004.4"), ValueType.INT32_SWAP,
137                                 // -1004 = 0xFFFFFC14 (32bit)
138                                 shorts(0xFC14, 0xFFFF), },
139                         new Object[] { new DecimalType("64000"), ValueType.INT32_SWAP, shorts(64000, 0), },
140                         // within signed int32 range: +-2,000,000,00
141                         new Object[] { new DecimalType("-2000000000"), ValueType.INT32_SWAP, shorts(0x6C00, 0x88CA), },
142                         new Object[] { new DecimalType("2000000000"), ValueType.INT32_SWAP, shorts(0x9400, 0x7735), },
143                         // out bounds for signed int32, but not for uint32
144                         new Object[] { new DecimalType("3000000000"), ValueType.INT32_SWAP, shorts(0x5E00, 0xB2D0), }, //
145                         new Object[] {
146                                 // out of bounds of unsigned 32bit (0 to 4,294,967,295)
147                                 new DecimalType("5000000000"),
148                                 // 5000000000 -> 0x12a05f200
149                                 ValueType.INT32_SWAP, shorts(0xf200, 0x2a05), },
150                         //
151                         // UINT32_SWAP (same as INT32_SWAP)
152                         //
153                         new Object[] { new DecimalType("1.0"), ValueType.UINT32_SWAP, shorts(1, 0) },
154                         new Object[] { new DecimalType("1.6"), ValueType.UINT32_SWAP, shorts(1, 0) },
155                         new Object[] { new DecimalType("2.6"), ValueType.UINT32_SWAP, shorts(2, 0) },
156                         new Object[] { new DecimalType("-1004.4"), ValueType.UINT32_SWAP,
157                                 // -1004 = 0xFFFFFC14 (32bit)
158                                 shorts(0xFC14, 0xFFFF), },
159                         new Object[] { new DecimalType("64000"), ValueType.UINT32_SWAP, shorts(64000, 0), },
160                         // within signed int32 range: +-2,000,000,00
161                         new Object[] { new DecimalType("-2000000000"), ValueType.UINT32_SWAP, shorts(0x6C00, 0x88CA), },
162                         new Object[] { new DecimalType("2000000000"), ValueType.UINT32_SWAP, shorts(0x9400, 0x7735), },
163                         // out bounds for signed int32, but not for uint32
164                         new Object[] { new DecimalType("3000000000"), ValueType.UINT32_SWAP, shorts(0x5E00, 0xB2D0), }, //
165                         new Object[] {
166                                 // out of bounds of unsigned 32bit (0 to 4,294,967,295)
167                                 new DecimalType("5000000000"),
168                                 // 5000000000 -> 0x12a05f200
169                                 ValueType.UINT32_SWAP, shorts(0xf200, 0x2a05), },
170                         //
171                         // FLOAT32
172                         //
173                         new Object[] { new DecimalType("1.0"), ValueType.FLOAT32, shorts(0x3F80, 0x0000) },
174                         new Object[] { new DecimalType("1.6"), ValueType.FLOAT32, shorts(0x3FCC, 0xCCCD) },
175                         new Object[] { new DecimalType("2.6"), ValueType.FLOAT32, shorts(0x4026, 0x6666) },
176                         new Object[] { new DecimalType("-1004.4"), ValueType.FLOAT32, shorts(0xC47B, 0x199A), },
177                         new Object[] { new DecimalType("64000"), ValueType.FLOAT32, shorts(0x477A, 0x0000), },
178                         new Object[] {
179                                 // out of bounds of unsigned 16bit (0 to 65,535)
180                                 new DecimalType("70004.4"), ValueType.FLOAT32, shorts(0x4788, 0xBA33), },
181                         new Object[] {
182                                 // out of bounds of unsigned 32bit (0 to 4,294,967,295)
183                                 new DecimalType("5000000000"), ValueType.FLOAT32, shorts(0x4F95, 0x02F9), },
184                         //
185                         // FLOAT32_SWAP
186                         //
187                         new Object[] { new DecimalType("1.0"), ValueType.FLOAT32_SWAP, shorts(0x0000, 0x3F80) },
188                         new Object[] { new DecimalType("1.6"), ValueType.FLOAT32_SWAP, shorts(0xCCCD, 0x3FCC) },
189                         new Object[] { new DecimalType("2.6"), ValueType.FLOAT32_SWAP, shorts(0x6666, 0x4026) },
190                         new Object[] { new DecimalType("-1004.4"), ValueType.FLOAT32_SWAP, shorts(0x199A, 0xC47B), },
191                         new Object[] { new DecimalType("64000"), ValueType.FLOAT32_SWAP, shorts(0x0000, 0x477A), },
192                         new Object[] {
193                                 // out of bounds of unsigned 16bit (0 to 65,535)
194                                 new DecimalType("70004.4"), ValueType.FLOAT32_SWAP, shorts(0xBA33, 0x4788), },
195                         new Object[] {
196                                 // out of bounds of unsigned 32bit (0 to 4,294,967,295)
197                                 new DecimalType("5000000000"), ValueType.FLOAT32_SWAP, shorts(0x02F9, 0x4F95) },
198                         // ON/OFF
199                         new Object[] { OnOffType.ON, ValueType.FLOAT32_SWAP, shorts(0x0000, 0x3F80) },
200                         new Object[] { OnOffType.OFF, ValueType.FLOAT32_SWAP, shorts(0x0000, 0x0000) },
201                         // OPEN
202                         new Object[] { OpenClosedType.OPEN, ValueType.FLOAT32_SWAP, shorts(0x0000, 0x3F80) },
203                         new Object[] { OpenClosedType.OPEN, ValueType.INT16, shorts(1) },
204                         // CLOSED
205                         new Object[] { OpenClosedType.CLOSED, ValueType.FLOAT32_SWAP, shorts(0x0000, 0x0000) },
206                         new Object[] { OpenClosedType.CLOSED, ValueType.INT16, shorts(0x0000) },
207                         // Unsupported command
208                         new Object[] { IncreaseDecreaseType.INCREASE, ValueType.FLOAT32_SWAP,
209                                 NotImplementedException.class },
210
211                         //
212                         // INT64
213                         //
214                         new Object[] { new DecimalType("1.0"), ValueType.INT64, shorts(0, 0, 0, 1) },
215                         new Object[] { new DecimalType("1.6"), ValueType.INT64, shorts(0, 0, 0, 1) },
216                         new Object[] { new DecimalType("2.6"), ValueType.INT64, shorts(0, 0, 0, 2) },
217                         new Object[] { new DecimalType("-1004.4"), ValueType.INT64,
218                                 shorts(0xFFFF, 0xFFFF, 0xFFFF, 0xFC14), },
219                         new Object[] { new DecimalType("64000"), ValueType.INT64, shorts(0, 0, 0, 64000), },
220                         new Object[] {
221                                 // out of bounds of unsigned 32bit
222                                 new DecimalType("34359738368"),
223                                 // 70004 -> 0x00011174 (32bit) -> 0x1174 (16bit)
224                                 ValueType.INT64, shorts(0x0, 0x8, 0x0, 0x0), },
225                         // within signed int64 range: +-9,200,000,000,000,000,000
226                         new Object[] { new DecimalType("-9200000000000000000"), ValueType.INT64,
227                                 shorts(0x8053, 0x08BE, 0x6268, 0x0000), },
228                         new Object[] { new DecimalType("9200000000000000000"), ValueType.INT64,
229                                 shorts(0x7FAC, 0xF741, 0x9D98, 0x0000), },
230                         // within unsigned int64 range (but out of range for signed int64)
231                         new Object[] { new DecimalType("18200000000000000000"), ValueType.INT64,
232                                 shorts(0xFC93, 0x6392, 0x801C, 0x0000), },
233                         new Object[] {
234                                 // out of bounds of unsigned 64bit
235                                 new DecimalType("3498348904359085439088905"),
236                                 // should pick the low 64 bits
237                                 ValueType.INT64, shorts(0xDFC5, 0xBBB7, 0x772E, 0x7909), },
238
239                         //
240                         // UINT64 (same as INT64)
241                         //
242                         new Object[] { new DecimalType("1.0"), ValueType.UINT64, shorts(0, 0, 0, 1) },
243                         new Object[] { new DecimalType("1.6"), ValueType.UINT64, shorts(0, 0, 0, 1) },
244                         new Object[] { new DecimalType("2.6"), ValueType.UINT64, shorts(0, 0, 0, 2) },
245                         new Object[] { new DecimalType("-1004.4"), ValueType.UINT64,
246                                 shorts(0xFFFF, 0xFFFF, 0xFFFF, 0xFC14), },
247                         new Object[] { new DecimalType("64000"), ValueType.UINT64, shorts(0, 0, 0, 64000), },
248                         new Object[] {
249                                 // out of bounds of unsigned 32bit
250                                 new DecimalType("34359738368"),
251                                 // 70004 -> 0x00011174 (32bit) -> 0x1174 (16bit)
252                                 ValueType.UINT64, shorts(0x0, 0x8, 0x0, 0x0), },
253                         // within signed int64 range: +-9,200,000,000,000,000,000
254                         new Object[] { new DecimalType("-9200000000000000000"), ValueType.UINT64,
255                                 shorts(0x8053, 0x08BE, 0x6268, 0x0000), },
256                         new Object[] { new DecimalType("9200000000000000000"), ValueType.UINT64,
257                                 shorts(0x7FAC, 0xF741, 0x9D98, 0x0000), },
258                         // within unsigned int64 range (but out of range for signed int64)
259                         new Object[] { new DecimalType("18200000000000000000"), ValueType.UINT64,
260                                 shorts(0xFC93, 0x6392, 0x801C, 0x0000), },
261                         new Object[] {
262                                 // out of bounds of unsigned 64bit
263                                 new DecimalType("3498348904359085439088905"),
264                                 // should pick the low 64 bits
265                                 ValueType.UINT64, shorts(0xDFC5, 0xBBB7, 0x772E, 0x7909), },
266
267                         //
268                         // INT64_SWAP
269                         //
270                         new Object[] { new DecimalType("1.0"), ValueType.INT64_SWAP, shorts(1, 0, 0, 0) },
271                         new Object[] { new DecimalType("1.6"), ValueType.INT64_SWAP, shorts(1, 0, 0, 0) },
272                         new Object[] { new DecimalType("2.6"), ValueType.INT64_SWAP, shorts(2, 0, 0, 0) },
273                         new Object[] { new DecimalType("-1004.4"), ValueType.INT64_SWAP,
274                                 shorts(0xFC14, 0xFFFF, 0xFFFF, 0xFFFF), },
275                         new Object[] { new DecimalType("64000"), ValueType.INT64_SWAP, shorts(64000, 0, 0, 0), },
276                         new Object[] {
277                                 // out of bounds of unsigned 32bit
278                                 new DecimalType("34359738368"),
279                                 // 70004 -> 0x00011174 (32bit) -> 0x1174 (16bit)
280                                 ValueType.INT64_SWAP, shorts(0x0, 0x0, 0x8, 0x0), },
281                         new Object[] {
282                                 // out of bounds of unsigned 64bit
283                                 new DecimalType("3498348904359085439088905"),
284                                 // should pick the low 64 bits
285                                 ValueType.INT64_SWAP, shorts(0x7909, 0x772E, 0xBBB7, 0xDFC5), },
286
287                         //
288                         // UINT64_SWAP (same as INT64_SWAP)
289                         //
290                         new Object[] { new DecimalType("1.0"), ValueType.UINT64_SWAP, shorts(1, 0, 0, 0) },
291                         new Object[] { new DecimalType("1.6"), ValueType.UINT64_SWAP, shorts(1, 0, 0, 0) },
292                         new Object[] { new DecimalType("2.6"), ValueType.UINT64_SWAP, shorts(2, 0, 0, 0) },
293                         new Object[] { new DecimalType("-1004.4"), ValueType.UINT64_SWAP,
294                                 shorts(0xFC14, 0xFFFF, 0xFFFF, 0xFFFF), },
295                         new Object[] { new DecimalType("64000"), ValueType.UINT64_SWAP, shorts(64000, 0, 0, 0), },
296                         new Object[] {
297                                 // out of bounds of unsigned 32bit
298                                 new DecimalType("34359738368"),
299                                 // 70004 -> 0x00011174 (32bit) -> 0x1174 (16bit)
300                                 ValueType.UINT64_SWAP, shorts(0x0, 0x0, 0x8, 0x0), },
301                         new Object[] {
302                                 // out of bounds of unsigned 64bit
303                                 new DecimalType("3498348904359085439088905"),
304                                 // should pick the low 64 bits
305                                 ValueType.UINT64_SWAP, shorts(0x7909, 0x772E, 0xBBB7, 0xDFC5), })
306                 .collect(Collectors.toList()));
307     }
308
309     @SuppressWarnings({ "unchecked", "rawtypes" })
310     @ParameterizedTest
311     @MethodSource("data")
312     public void testCommandToRegisters(Command command, ValueType type, Object expectedResult) {
313         if (expectedResult instanceof Class && Exception.class.isAssignableFrom((Class) expectedResult)) {
314             assertThrows((Class) expectedResult, () -> ModbusBitUtilities.commandToRegisters(command, type));
315             return;
316         }
317
318         ModbusRegisterArray registers = ModbusBitUtilities.commandToRegisters(command, type);
319         short[] expectedRegisters = (short[]) expectedResult;
320
321         assertThat(String.format("register index command=%s, type=%s", command, type), registers.size(),
322                 is(equalTo(expectedRegisters.length)));
323         for (int i = 0; i < expectedRegisters.length; i++) {
324             int expectedRegisterDataUnsigned = expectedRegisters[i] & 0xffff;
325             int actual = registers.getRegister(i).getValue();
326
327             assertThat(String.format("register index i=%d, command=%s, type=%s", i, command, type), actual,
328                     is(equalTo(expectedRegisterDataUnsigned)));
329         }
330     }
331 }