]> git.basschouten.com Git - openhab-addons.git/blob
c4533a720bb70989611891a18be64b9dfdbe65ab
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.binding.souliss.internal.protocol;
14
15 import java.net.DatagramPacket;
16 import java.net.InetAddress;
17 import java.net.UnknownHostException;
18 import java.util.ArrayList;
19 import java.util.Iterator;
20 import java.util.List;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.openhab.binding.souliss.internal.SoulissBindingConstants;
25 import org.openhab.binding.souliss.internal.SoulissProtocolConstants;
26 import org.openhab.binding.souliss.internal.SoulissUDPConstants;
27 import org.openhab.binding.souliss.internal.discovery.DiscoverResult;
28 import org.openhab.binding.souliss.internal.handler.SoulissGatewayHandler;
29 import org.openhab.binding.souliss.internal.handler.SoulissGenericHandler;
30 import org.openhab.binding.souliss.internal.handler.SoulissT11Handler;
31 import org.openhab.binding.souliss.internal.handler.SoulissT12Handler;
32 import org.openhab.binding.souliss.internal.handler.SoulissT13Handler;
33 import org.openhab.binding.souliss.internal.handler.SoulissT14Handler;
34 import org.openhab.binding.souliss.internal.handler.SoulissT16Handler;
35 import org.openhab.binding.souliss.internal.handler.SoulissT18Handler;
36 import org.openhab.binding.souliss.internal.handler.SoulissT19Handler;
37 import org.openhab.binding.souliss.internal.handler.SoulissT1AHandler;
38 import org.openhab.binding.souliss.internal.handler.SoulissT22Handler;
39 import org.openhab.binding.souliss.internal.handler.SoulissT31Handler;
40 import org.openhab.binding.souliss.internal.handler.SoulissT41Handler;
41 import org.openhab.binding.souliss.internal.handler.SoulissT42Handler;
42 import org.openhab.binding.souliss.internal.handler.SoulissT5nHandler;
43 import org.openhab.binding.souliss.internal.handler.SoulissT61Handler;
44 import org.openhab.binding.souliss.internal.handler.SoulissT62Handler;
45 import org.openhab.binding.souliss.internal.handler.SoulissT63Handler;
46 import org.openhab.binding.souliss.internal.handler.SoulissT64Handler;
47 import org.openhab.binding.souliss.internal.handler.SoulissT65Handler;
48 import org.openhab.binding.souliss.internal.handler.SoulissT66Handler;
49 import org.openhab.binding.souliss.internal.handler.SoulissT67Handler;
50 import org.openhab.binding.souliss.internal.handler.SoulissT68Handler;
51 import org.openhab.binding.souliss.internal.handler.SoulissTopicsHandler;
52 import org.openhab.core.library.types.DecimalType;
53 import org.openhab.core.library.types.StringType;
54 import org.openhab.core.thing.Bridge;
55 import org.openhab.core.thing.Thing;
56 import org.openhab.core.thing.binding.ThingHandler;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 /**
61  * This class decodes incoming Souliss packets, starting from decodevNet
62  *
63  * @author Tonino Fazio - Initial contribution
64  * @author Luca Calcaterra - Refactor for OH3
65  * @author Alessandro Del Pex - Souliss App
66  */
67 @NonNullByDefault
68 public class UDPDecoder {
69
70     private final Logger logger = LoggerFactory.getLogger(UDPDecoder.class);
71     private @Nullable DiscoverResult discoverResult;
72     private @Nullable SoulissGatewayHandler gwHandler;
73
74     private @Nullable Byte lastByteGatewayIp = null;
75
76     public UDPDecoder(Bridge bridge, @Nullable DiscoverResult pDiscoverResult) {
77         this.gwHandler = (SoulissGatewayHandler) bridge.getHandler();
78         this.discoverResult = pDiscoverResult;
79         var localGwHandler = this.gwHandler;
80         if (localGwHandler != null) {
81             this.lastByteGatewayIp = (byte) Integer
82                     .parseInt(localGwHandler.getGwConfig().gatewayLanAddress.split("\\.")[3]);
83         }
84     }
85
86     /**
87      * Get packet from VNET Frame
88      *
89      * @param packet
90      *            incoming datagram
91      */
92     public void decodeVNetDatagram(DatagramPacket packet) {
93         int checklen = packet.getLength();
94         ArrayList<Byte> mac = new ArrayList<>();
95         for (var ig = 7; ig < checklen; ig++) {
96             mac.add((byte) (packet.getData()[ig] & 0xFF));
97         }
98
99         // Check if decoded Gw equal to ip of bridge handler or 1 (action messages)
100         Byte gwCheck = (byte) (packet.getData()[5] & 0xFF);
101         if ((gwCheck == 1) || (gwCheck.equals(this.lastByteGatewayIp))) {
102             decodeMacaco((byte) (packet.getData()[5] & 0xFF), mac);
103         }
104     }
105
106     /**
107      * Decodes lower level MaCaCo packet
108      *
109      * @param lastByteGatewayIP
110      *
111      * @param macacoPck
112      */
113     private void decodeMacaco(byte lastByteGatewayIP, ArrayList<Byte> macacoPck) {
114         int functionalCode = macacoPck.get(0);
115         switch (functionalCode) {
116             case SoulissUDPConstants.SOULISS_UDP_FUNCTION_PING_RESP:
117                 logger.debug("Received functional code: 0x{}- Ping answer", Integer.toHexString(functionalCode));
118                 decodePing(macacoPck);
119                 break;
120
121             case SoulissUDPConstants.SOULISS_UDP_FUNCTION_DISCOVER_GW_NODE_BCAST_RESP:
122                 logger.debug("Received functional code: 0x{} - Discover a gateway node answer (broadcast)",
123                         Integer.toHexString(functionalCode));
124                 try {
125                     decodePingBroadcast(macacoPck);
126                 } catch (UnknownHostException e) {
127                     logger.warn("Error: {}", e.getLocalizedMessage());
128                 }
129                 break;
130
131             case SoulissUDPConstants.SOULISS_UDP_FUNCTION_POLL_RESP:
132                 logger.debug("Received functional code: 0x{} - subscribe response",
133                         Integer.toHexString(functionalCode));
134                 decodeStateRequest(macacoPck);
135                 break;
136             case SoulissUDPConstants.SOULISS_UDP_FUNCTION_SUBSCRIBE_RESP:
137                 logger.debug("Received functional code: 0x{} - Read state answer", Integer.toHexString(functionalCode));
138                 decodeStateRequest(macacoPck);
139                 break;
140
141             // Answer for assigned typical logic
142             case SoulissUDPConstants.SOULISS_UDP_FUNCTION_TYP_RESP:
143                 logger.debug("Received functional code: 0x{}- Read typical logic answer",
144                         Integer.toHexString(functionalCode));
145                 decodeTypRequest(lastByteGatewayIP, macacoPck);
146                 break;
147             // Answer
148             case SoulissUDPConstants.SOULISS_UDP_FUNCTION_HEALTHY_RESP:
149                 // nodes healthy
150                 logger.debug("Received functional code: 0x{} - Nodes Healthy", Integer.toHexString(functionalCode));
151                 decodeHealthyRequest(macacoPck);
152                 break;
153
154             case (byte) SoulissUDPConstants.SOULISS_UDP_FUNCTION_DBSTRUCT_RESP:
155                 logger.debug("Received functional code: 0x{} - Database structure answer",
156                         Integer.toHexString(functionalCode));
157                 decodeDBStructRequest(macacoPck);
158                 break;
159             case 0x83:
160                 logger.debug("Functional code not supported");
161                 break;
162             case 0x84:
163                 logger.debug("Data out of range");
164                 break;
165             case 0x85:
166                 logger.debug("Subscription refused");
167                 break;
168             case (byte) SoulissUDPConstants.SOULISS_UDP_FUNCTION_ACTION_MESSAGE:
169                 logger.debug("Received functional code: 0x{} - Action Message (Topic)",
170                         Integer.toHexString(functionalCode));
171                 decodeActionMessages(macacoPck);
172                 break;
173             default:
174                 logger.debug("Received functional code: 0x{} - unused by OH Binding",
175                         Integer.toHexString(functionalCode));
176         }
177     }
178
179     /**
180      * @param mac
181      */
182     private void decodePing(ArrayList<Byte> mac) {
183         // not used
184         int putIn1 = mac.get(1);
185         // not used
186         int putIn2 = mac.get(2);
187         logger.debug("decodePing: putIn code: {}, {}", putIn1, putIn2);
188         var localGwHandler = this.gwHandler;
189         if (localGwHandler != null) {
190             localGwHandler.gatewayDetected();
191         }
192     }
193
194     private void decodePingBroadcast(ArrayList<Byte> macaco) throws UnknownHostException {
195         String ip = macaco.get(5) + "." + macaco.get(6) + "." + macaco.get(7) + "." + macaco.get(8);
196         byte[] addr = { (macaco.get(5)).byteValue(), (macaco.get(6)).byteValue(), (macaco.get(7)).byteValue(),
197                 (macaco.get(8)).byteValue() };
198         logger.debug("decodePingBroadcast. Gateway Discovery. IP: {}", ip);
199
200         var localDiscoverResult = this.discoverResult;
201         if (localDiscoverResult != null) {
202             localDiscoverResult.gatewayDetected(InetAddress.getByAddress(addr), macaco.get(8).toString());
203         } else {
204             logger.debug("decodePingBroadcast aborted. 'discoverResult' is null");
205         }
206     }
207
208     /**
209      * decode Typicals Request Packet
210      * It read Souliss Network and create OH items
211      *
212      * @param lastByteGatewayIP
213      *
214      * @param mac
215      */
216     private void decodeTypRequest(byte lastByteGatewayIP, ArrayList<Byte> mac) {
217         var localGwHandler = this.gwHandler;
218         if (localGwHandler != null) {
219             int typXnodo = localGwHandler.getMaxTypicalXnode();
220
221             byte tgtnode = mac.get(3);
222             int numberOf = mac.get(4);
223
224             // creates Souliss nodes
225             for (var j = 0; j < numberOf; j++) {
226                 // create only not-empty typicals
227                 if ((mac.get(5 + j) != 0) && (mac.get(5 + j) != SoulissProtocolConstants.SOULISS_T_RELATED)) {
228                     byte typical = mac.get(5 + j);
229                     byte slot = (byte) (j % typXnodo);
230                     byte node = (byte) (j / typXnodo + tgtnode);
231                     logger.debug("Thing Detected. IP (last byte): {}, Typical: 0x{}, Node: {}, Slot: {} ",
232                             lastByteGatewayIP, Integer.toHexString(typical), node, slot);
233
234                     var localDiscoverResult = this.discoverResult;
235                     if (localDiscoverResult != null) {
236                         localDiscoverResult.thingDetectedTypicals(lastByteGatewayIP, typical, node, slot);
237                     } else {
238                         logger.debug("decodeTypRequest aborted. 'discoverResult' is null");
239                     }
240                 }
241             }
242         }
243     }
244
245     /**
246      * decode Typicals Request Packet
247      * It read Action Messages on Souliss Network and create items
248      *
249      * @param lastByteGatewayIP
250      *
251      * @param mac
252      */
253     private void decodeActionMessages(ArrayList<Byte> mac) {
254         String sTopicNumber;
255         String sTopicVariant;
256         float fRet = 0;
257
258         try {
259             // A 16-bit Topic Number: Define the topic itself
260             // A 8-bit Topic Variant : Define a variant for the topic
261
262             String[] sTopicNumberArray = { Integer.toHexString(mac.get(2)).toUpperCase(),
263                     Integer.toHexString(mac.get(1)).toUpperCase() };
264             if (sTopicNumberArray[0].length() == 1) {
265                 sTopicNumberArray[0] = "0" + sTopicNumberArray[0];
266             }
267             if (sTopicNumberArray[1].length() == 1) {
268                 sTopicNumberArray[1] = "0" + sTopicNumberArray[1];
269             }
270             sTopicNumber = sTopicNumberArray[0] + sTopicNumberArray[1];
271             logger.debug("Topic Number: 0x{}", sTopicNumber);
272
273             sTopicVariant = Integer.toHexString(mac.get(3)).toUpperCase();
274             if (sTopicVariant.length() == 1) {
275                 sTopicVariant = "0" + sTopicVariant;
276             }
277             logger.debug("Topic Variant: 0x{}", sTopicVariant);
278             if (mac.get(4) == 1) {
279                 fRet = mac.get(5);
280                 logger.debug("Topic Value (Payload one byte): {} ", Integer.toHexString(mac.get(5)).toUpperCase());
281             } else if (mac.get(4) == 2) {
282                 byte[] value = { mac.get(5), mac.get(6) };
283
284                 int shifted = value[1] << 8;
285                 fRet = HalfFloatUtils.toFloat(shifted + value[0]);
286                 logger.debug("Topic Value (Payload 2 bytes): {}", fRet);
287             }
288             var localGwHandler = this.gwHandler;
289             if (localGwHandler != null) {
290                 var listThings = localGwHandler.getThing().getThings();
291
292                 Boolean bIsPresent = false;
293
294                 for (Thing t : listThings) {
295                     if (t.getUID().toString().split(":")[2]
296                             .equals(sTopicNumber + SoulissBindingConstants.UUID_NODE_SLOT_SEPARATOR + sTopicVariant)) {
297                         var topicHandler = (SoulissTopicsHandler) (t.getHandler());
298                         if (topicHandler != null) {
299                             topicHandler.setState(DecimalType.valueOf(Float.toString(fRet)));
300                             bIsPresent = true;
301                         }
302                     }
303                 }
304                 var localDiscoverResult = this.discoverResult;
305                 if (localDiscoverResult != null && !bIsPresent) {
306                     localDiscoverResult.thingDetectedActionMessages(sTopicNumber, sTopicVariant);
307                 }
308             }
309         } catch (Exception uy) {
310             logger.warn("decodeActionMessages ERROR");
311         }
312     }
313
314     /**
315      * decode DB Struct Request Packet
316      * It return Souliss Network:
317      * node number
318      * max supported number of nodes
319      * max typical per node
320      * max requests
321      * See Souliss wiki for details
322      *
323      * @param lastByteGatewayIP
324      *
325      * @param mac
326      */
327     private void decodeDBStructRequest(ArrayList<Byte> mac) {
328         int nodes = mac.get(5);
329         int maxTypicalXnode = mac.get(7);
330
331         SoulissGatewayHandler localGwHandler = this.gwHandler;
332         if (localGwHandler != null) {
333             localGwHandler.setNodes(nodes);
334             localGwHandler.setMaxTypicalXnode(maxTypicalXnode);
335             localGwHandler.dbStructAnswerReceived();
336         }
337     }
338
339     /**
340      * Decodes a souliss nodes health request
341      *
342      * @param macaco
343      *            packet
344      */
345     private void decodeHealthyRequest(ArrayList<Byte> mac) {
346         int numberOf = mac.get(4);
347
348         for (var i = 5; i < 5 + numberOf; i++) {
349             var localGwHandler = this.gwHandler;
350             if (localGwHandler != null) {
351                 // build an array containing healths
352                 List<Thing> listaThings = localGwHandler.getThing().getThings();
353
354                 ThingHandler handler = null;
355                 for (Thing thing : listaThings) {
356                     if (thing.getThingTypeUID().equals(SoulissBindingConstants.TOPICS_THING_TYPE)) {
357                         continue;
358                     }
359                     handler = thing.getHandler();
360                     if (handler != null) {
361                         int tgtnode = i - 5;
362                         if (((SoulissGenericHandler) handler).getNode() == tgtnode) {
363                             ((SoulissGenericHandler) handler).setHealthy((mac.get(i)));
364                         }
365                     } else {
366                         logger.debug("decode Healthy Request Warning. Thing handler is null");
367                     }
368                 }
369             }
370         }
371     }
372
373     private void decodeStateRequest(ArrayList<Byte> mac) {
374         int tgtnode = mac.get(3);
375
376         Iterator<Thing> thingsIterator = null;
377         var localGwHandler = this.gwHandler;
378         if (localGwHandler != null) {
379             thingsIterator = localGwHandler.getThing().getThings().iterator();
380
381             var bFound = false;
382             Thing typ = null;
383             while (thingsIterator.hasNext() && !bFound) {
384                 typ = thingsIterator.next();
385                 // if a topic continue
386                 // ignoring it
387                 if (typ.getThingTypeUID().equals(SoulissBindingConstants.TOPICS_THING_TYPE)) {
388                     continue;
389                 }
390                 String[] sUIDArray = typ.getUID().getAsString().split(":");
391                 ThingHandler handler = typ.getHandler();
392                 // execute it only if binding is Souliss and update is for my
393                 // Gateway
394                 if (handler != null) {
395                     // execute it
396                     // only
397                     // if it is
398                     // node
399                     // to update
400                     if (((SoulissGenericHandler) handler).getNode() == tgtnode) {
401                         // ...now check slot
402                         int slot = ((SoulissGenericHandler) handler).getSlot();
403                         // get typical value
404                         var sVal = getByteAtSlot(mac, slot);
405                         var decodingLiteralLabel = "Decoding {}{}";
406                         var packetLabel = " packet";
407                         // update Txx
408                         switch (sUIDArray[1]) {
409                             case SoulissBindingConstants.T11:
410                                 logger.debug(decodingLiteralLabel, SoulissBindingConstants.T11, packetLabel);
411                                 ((SoulissT11Handler) handler).setRawState(sVal);
412                                 break;
413                             case SoulissBindingConstants.T12:
414                                 logger.debug(decodingLiteralLabel, SoulissBindingConstants.T12, packetLabel);
415                                 ((SoulissT12Handler) handler).setRawState(sVal);
416                                 break;
417                             case SoulissBindingConstants.T13:
418                                 logger.debug(decodingLiteralLabel, SoulissBindingConstants.T13, packetLabel);
419                                 ((SoulissT13Handler) handler).setRawState(sVal);
420                                 break;
421                             case SoulissBindingConstants.T14:
422                                 logger.debug(decodingLiteralLabel, SoulissBindingConstants.T14, packetLabel);
423                                 ((SoulissT14Handler) handler).setRawState(sVal);
424                                 break;
425                             case SoulissBindingConstants.T16:
426                                 logger.debug(decodingLiteralLabel, SoulissBindingConstants.T16, packetLabel);
427                                 ((SoulissT16Handler) handler).setRawStateCommand(sVal);
428                                 ((SoulissT16Handler) handler).setRawStateRgb(getByteAtSlot(mac, slot + 1),
429                                         getByteAtSlot(mac, slot + 2), getByteAtSlot(mac, slot + 3));
430                                 break;
431
432                             case SoulissBindingConstants.T18:
433                                 logger.debug(decodingLiteralLabel, SoulissBindingConstants.T18, packetLabel);
434                                 ((SoulissT18Handler) handler).setRawState(sVal);
435                                 break;
436
437                             case SoulissBindingConstants.T19:
438                                 logger.debug(decodingLiteralLabel, SoulissBindingConstants.T19, packetLabel);
439                                 ((SoulissT19Handler) handler).setRawState(sVal);
440                                 ((SoulissT19Handler) handler).setRawStateDimmerValue(getByteAtSlot(mac, slot + 1));
441                                 break;
442
443                             case SoulissBindingConstants.T1A:
444                                 logger.debug(decodingLiteralLabel, SoulissBindingConstants.T1A, packetLabel);
445                                 ((SoulissT1AHandler) handler).setRawState(sVal);
446                                 break;
447                             case SoulissBindingConstants.T21:
448                             case SoulissBindingConstants.T22:
449                                 logger.debug(decodingLiteralLabel,
450                                         SoulissBindingConstants.T21 + "/" + SoulissBindingConstants.T22, packetLabel);
451                                 ((SoulissT22Handler) handler).setRawState(sVal);
452                                 break;
453                             case SoulissBindingConstants.T31:
454                                 logger.debug("Decoding {}/{}", SoulissBindingConstants.T31,
455                                         SoulissBindingConstants.T31);
456                                 logger.debug("packet: ");
457                                 logger.debug("- bit0 (system on-off): {}", getBitState(sVal, 0));
458                                 logger.debug("- bit1 (heating on-off): {}", getBitState(sVal, 1));
459                                 logger.debug("- bit2 (cooling on-off): {}", getBitState(sVal, 2));
460                                 logger.debug("- bit3 (fan1 on-off): {}", getBitState(sVal, 3));
461                                 logger.debug("- bit4 (fan2 on-off): {}", getBitState(sVal, 4));
462                                 logger.debug("- bit5 (fan3 on-off): {}", getBitState(sVal, 5));
463                                 logger.debug("- bit6 (Manual/automatic fan mode): {}", getBitState(sVal, 6));
464                                 logger.debug("- bit7 (heating/cooling mode): {}", getBitState(sVal, 7));
465
466                                 ((SoulissT31Handler) handler).setRawStateValues(sVal, getFloatAtSlot(mac, slot + 1),
467                                         getFloatAtSlot(mac, slot + 3));
468
469                                 break;
470                             case SoulissBindingConstants.T41:
471                                 ((SoulissT41Handler) handler).setRawState(sVal);
472                                 break;
473                             case SoulissBindingConstants.T42:
474                                 ((SoulissT42Handler) handler).setRawState(sVal);
475                                 switch (sVal) {
476                                     case SoulissProtocolConstants.SOULISS_T4N_NO_ANTITHEFT:
477                                         ((SoulissT42Handler) handler).setState(StringType
478                                                 .valueOf(SoulissBindingConstants.T4N_ALARMOFF_MESSAGE_CHANNEL));
479                                         break;
480                                     case SoulissProtocolConstants.SOULISS_T4N_ALARM:
481                                         ((SoulissT42Handler) handler).setState(StringType
482                                                 .valueOf(SoulissBindingConstants.T4N_ALARMON_MESSAGE_CHANNEL));
483                                         break;
484                                     default:
485                                         break;
486                                 }
487                                 break;
488                             case SoulissBindingConstants.T51:
489                             case SoulissBindingConstants.T52:
490                             case SoulissBindingConstants.T53:
491                             case SoulissBindingConstants.T54:
492                             case SoulissBindingConstants.T55:
493                             case SoulissBindingConstants.T56:
494                             case SoulissBindingConstants.T57:
495                             case SoulissBindingConstants.T58:
496                                 logger.debug("Decoding T5n packet");
497                                 if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
498                                     ((SoulissT5nHandler) handler).setFloatValue(getFloatAtSlot(mac, slot));
499                                 }
500                                 break;
501                             case SoulissBindingConstants.T61:
502                                 logger.debug(decodingLiteralLabel, SoulissBindingConstants.T61, packetLabel);
503                                 if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
504                                     ((SoulissT61Handler) handler).setFloatValue(getFloatAtSlot(mac, slot));
505                                 }
506                                 break;
507                             case SoulissBindingConstants.T62:
508                                 logger.debug(decodingLiteralLabel, SoulissBindingConstants.T62, packetLabel);
509                                 if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
510                                     ((SoulissT62Handler) handler).setFloatValue(getFloatAtSlot(mac, slot));
511                                 }
512                                 break;
513                             case SoulissBindingConstants.T63:
514                                 logger.debug(decodingLiteralLabel, SoulissBindingConstants.T63, packetLabel);
515                                 if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
516                                     ((SoulissT63Handler) handler).setFloatValue(getFloatAtSlot(mac, slot));
517                                 }
518                                 break;
519                             case SoulissBindingConstants.T64:
520                                 logger.debug(decodingLiteralLabel, SoulissBindingConstants.T64, packetLabel);
521                                 if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
522                                     ((SoulissT64Handler) handler).setFloatValue(getFloatAtSlot(mac, slot));
523                                 }
524                                 break;
525                             case SoulissBindingConstants.T65:
526                                 logger.debug(decodingLiteralLabel, SoulissBindingConstants.T65, packetLabel);
527                                 if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
528                                     ((SoulissT65Handler) handler).setFloatValue(getFloatAtSlot(mac, slot));
529                                 }
530                                 break;
531                             case SoulissBindingConstants.T66:
532                                 logger.debug(decodingLiteralLabel, SoulissBindingConstants.T66, packetLabel);
533                                 if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
534                                     ((SoulissT66Handler) handler).setFloatValue(getFloatAtSlot(mac, slot));
535                                 }
536                                 break;
537                             case SoulissBindingConstants.T67:
538                                 logger.debug(decodingLiteralLabel, SoulissBindingConstants.T67, packetLabel);
539                                 if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
540                                     ((SoulissT67Handler) handler).setFloatValue(getFloatAtSlot(mac, slot));
541                                 }
542                                 break;
543                             case SoulissBindingConstants.T68:
544                                 logger.debug(decodingLiteralLabel, SoulissBindingConstants.T68, packetLabel);
545                                 if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
546                                     ((SoulissT68Handler) handler).setFloatValue(getFloatAtSlot(mac, slot));
547                                 }
548                                 break;
549
550                             case SoulissBindingConstants.TOPICS:
551                                 logger.debug(decodingLiteralLabel, SoulissBindingConstants.TOPICS, packetLabel);
552                                 if (!Float.isNaN(getFloatAtSlot(mac, slot))) {
553                                     ((SoulissTopicsHandler) handler).setFloatValue(getFloatAtSlot(mac, slot));
554                                 }
555                                 break;
556                             default:
557                                 logger.debug("Unsupported typical");
558                         }
559                     }
560                 }
561             }
562         }
563     }
564
565     private byte getByteAtSlot(ArrayList<Byte> mac, int slot) {
566         return mac.get(5 + slot);
567     }
568
569     private float getFloatAtSlot(ArrayList<Byte> mac, int slot) {
570         int iOutput = mac.get(5 + slot) & 0xFF;
571         int iOutput2 = mac.get(5 + slot + 1) & 0xFF;
572         // we have two bytes, convert them...
573         int shifted = iOutput2 << 8;
574         return HalfFloatUtils.toFloat(shifted + iOutput);
575     }
576
577     public byte getBitState(byte vRaw, int iBit) {
578         final var maskBit1 = 0x1;
579
580         if (((vRaw >>> iBit) & maskBit1) == 0) {
581             return 0;
582         } else {
583             return 1;
584         }
585     }
586 }