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