]> git.basschouten.com Git - openhab-addons.git/blob
a6a0d793581e64152ee1f52f4a788e8b20ef4078
[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.herzborg.internal.dto;
14
15 import java.nio.ByteBuffer;
16 import java.nio.ByteOrder;
17
18 /**
19  * Herzborg binary protocol
20  *
21  * @author Pavel Fedin - Initial contribution
22  *
23  */
24 public class HerzborgProtocol {
25     public static class Function {
26         public static final byte READ = 0x01;
27         public static final byte WRITE = 0x02;
28         public static final byte CONTROL = 0x03;
29         public static final byte REQUEST = 0x04;
30     }
31
32     public static class ControlAddress {
33         public static final byte OPEN = 0x01;
34         public static final byte CLOSE = 0x02;
35         public static final byte STOP = 0x03;
36         public static final byte PERCENT = 0x04;
37         public static final byte DELETE_LIMIT = 0x07;
38         public static final byte DEFAULT = 0x08;
39         public static final byte SET_CONTEXT = 0x09;
40         public static final byte RUN_CONTEXT = 0x0A;
41         public static final byte DEL_CONTEXT = 0x0B;
42     }
43
44     public static class DataAddress {
45         public static final byte ID_L = 0x00;
46         public static final byte ID_H = 0x01;
47         public static final byte POSITION = 0x02;
48         public static final byte DEFAULT_DIR = 0x03;
49         public static final byte HAND_START = 0x04;
50         public static final byte MODE = 0x05;
51         public static final byte EXT_SWITCH = 0x27;
52         public static final byte EXT_HV_SWITCH = 0x28;
53     }
54
55     public static class Packet {
56         private static final int HEADER_LENGTH = 5;
57         private static final int CRC16_LENGTH = 2;
58         public static final int MIN_LENGTH = HEADER_LENGTH + CRC16_LENGTH;
59
60         private static final byte START = 0x55;
61
62         private ByteBuffer dataBuffer;
63         private int dataLength; // Packet length without CRC16
64
65         public Packet(byte[] data) {
66             dataBuffer = ByteBuffer.wrap(data);
67             dataBuffer.order(ByteOrder.LITTLE_ENDIAN);
68             dataLength = data.length - CRC16_LENGTH;
69         }
70
71         private void setHeader(short device_addr, byte function, byte data_addr, int data_length) {
72             dataLength = HEADER_LENGTH + data_length;
73
74             dataBuffer = ByteBuffer.allocate(dataLength + CRC16_LENGTH);
75             dataBuffer.order(ByteOrder.LITTLE_ENDIAN);
76
77             dataBuffer.put(START);
78             dataBuffer.putShort(device_addr);
79             dataBuffer.put(function);
80             dataBuffer.put(data_addr);
81         }
82
83         private void setCrc16() {
84             dataBuffer.putShort(crc16(dataLength));
85         }
86
87         public Packet(short device_addr, byte function, byte data_addr) {
88             setHeader(device_addr, function, data_addr, 0);
89             setCrc16();
90         }
91
92         public Packet(short device_addr, byte function, byte data_addr, byte value) {
93             int dataLength = (function == Function.WRITE) ? 2 : 1;
94
95             setHeader(device_addr, function, data_addr, dataLength);
96             if (function == Function.WRITE) {
97                 // WRITE command also requires length of data to be written
98                 dataBuffer.put((byte) 1);
99             }
100             dataBuffer.put(value);
101             setCrc16();
102         }
103
104         public byte[] getBuffer() {
105             return dataBuffer.array();
106         }
107
108         public boolean isValid() {
109             return dataBuffer.get(0) == START && crc16(dataLength) == dataBuffer.getShort(dataLength);
110         }
111
112         public byte getFunction() {
113             return dataBuffer.get(3);
114         }
115
116         public byte getDataAddress() {
117             return dataBuffer.get(4);
118         }
119
120         public byte getDataLength() {
121             return dataBuffer.get(HEADER_LENGTH);
122         }
123
124         public byte getData(int offset) {
125             return dataBuffer.get(HEADER_LENGTH + offset);
126         }
127
128         // Herzborg uses modbus variant of CRC16
129         // Code adapted from https://habr.com/ru/post/418209/
130         private short crc16(int length) {
131             int crc = 0xFFFF;
132             for (int i = 0; i < length; i++) {
133                 crc = crc ^ Byte.toUnsignedInt(dataBuffer.get(i));
134                 for (int j = 0; j < 8; j++) {
135                     int mask = ((crc & 0x1) != 0) ? 0xA001 : 0x0000;
136                     crc = ((crc >> 1) & 0x7FFF) ^ mask;
137                 }
138             }
139             return (short) crc;
140         }
141     }
142 }