]> git.basschouten.com Git - openhab-addons.git/blob
e9f5a2609586f71dcbd04374159003a94499e0e1
[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.upb.internal.message;
14
15 import static java.nio.charset.StandardCharsets.US_ASCII;
16
17 import java.util.Arrays;
18
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.openhab.core.util.HexUtils;
21
22 /**
23  * Model for a message sent or received from a UPB modem.
24  *
25  * @author cvanorman - Initial contribution
26  */
27 @NonNullByDefault
28 public class UPBMessage {
29
30     /**
31      * An enum of possible modem response types.
32      */
33     public enum Type {
34         ACCEPT("PA"),
35         BUSY("PB"),
36         ERROR("PE"),
37         ACK("PK"),
38         NAK("PN"),
39         MESSAGE_REPORT("PU"),
40         NONE("");
41
42         private final byte[] prefix;
43
44         Type(final String prefix) {
45             this.prefix = prefix.getBytes(US_ASCII);
46         }
47
48         /**
49          * Returns the message type for a message buffer.
50          *
51          * @param buf the byte array to check for a matching type prefix
52          * @return the matching message type, or {@code NONE}
53          */
54         public static Type forPrefix(final byte[] buf) {
55             if (buf.length >= 2) {
56                 for (final Type t : values()) {
57                     if (t.prefix.length >= 2 && buf[0] == t.prefix[0] && buf[1] == t.prefix[1]) {
58                         return t;
59                     }
60                 }
61             }
62             return NONE;
63         }
64     }
65
66     private final Type type;
67
68     private ControlWord controlWord = new ControlWord();
69     private byte network;
70     private byte destination;
71     private byte source;
72
73     private Command command = Command.NULL;
74     private byte[] arguments = new byte[0];
75
76     private UPBMessage(final Type type) {
77         this.type = type;
78     }
79
80     /**
81      * Converts a hex string into a {@link UPBMessage}.
82      *
83      * @param buf
84      *            the string as returned by the modem.
85      * @return a new UPBMessage.
86      */
87     public static UPBMessage parse(final byte[] buf) {
88         if (buf.length < 2) {
89             throw new MessageParseException("message too short");
90         }
91         final UPBMessage msg = new UPBMessage(Type.forPrefix(buf));
92
93         try {
94             if (buf.length >= 15) {
95                 byte[] data = unhex(buf, 2, buf.length - 1);
96                 msg.getControlWord().setBytes(data[0], data[1]);
97                 int index = 2;
98                 msg.setNetwork(data[index++]);
99                 msg.setDestination(data[index++]);
100                 msg.setSource(data[index++]);
101
102                 byte commandCode = data[index++];
103                 msg.setCommand(Command.valueOf(commandCode));
104
105                 if (index <= data.length - 1) {
106                     msg.setArguments(Arrays.copyOfRange(data, index, data.length - 1));
107                 }
108             }
109         } catch (final RuntimeException e) {
110             throw new MessageParseException("failed to parse message", e);
111         }
112
113         return msg;
114     }
115
116     private static byte[] unhex(final byte[] buf, final int start, final int end) {
117         final byte[] res = new byte[(end - start) / 2];
118         int i = start;
119         int j = 0;
120         while (i < end - 1) {
121             res[j++] = HexUtils.hexToByte(buf[i++], buf[i++]);
122         }
123         return res;
124     }
125
126     /**
127      * @return the type
128      */
129     public Type getType() {
130         return type;
131     }
132
133     /**
134      * @return the controlWord
135      */
136     public ControlWord getControlWord() {
137         return controlWord;
138     }
139
140     /**
141      * @param controlWord
142      *            the controlWord to set
143      */
144     public void setControlWord(ControlWord controlWord) {
145         this.controlWord = controlWord;
146     }
147
148     /**
149      * @return the network
150      */
151     public byte getNetwork() {
152         return network;
153     }
154
155     /**
156      * @param network
157      *            the network to set
158      */
159     public void setNetwork(byte network) {
160         this.network = network;
161     }
162
163     /**
164      * @return the destination
165      */
166     public byte getDestination() {
167         return destination;
168     }
169
170     /**
171      * @param destination
172      *            the destination to set
173      */
174     public void setDestination(byte destination) {
175         this.destination = destination;
176     }
177
178     /**
179      * @return the source
180      */
181     public byte getSource() {
182         return source;
183     }
184
185     /**
186      * @param source
187      *            the source to set
188      */
189     public void setSource(byte source) {
190         this.source = source;
191     }
192
193     /**
194      * @return the command
195      */
196     public Command getCommand() {
197         return command;
198     }
199
200     /**
201      * @param command
202      *            the command to set
203      */
204     public void setCommand(Command command) {
205         this.command = command;
206     }
207
208     /**
209      * @return the arguments
210      */
211     public byte[] getArguments() {
212         return arguments;
213     }
214
215     /**
216      * @param arguments
217      *            the arguments to set
218      */
219     public void setArguments(byte[] arguments) {
220         this.arguments = arguments;
221     }
222 }