1 package net.sf.mbus4j.decoder;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 import java.util.Calendar;
31 import java.util.Date;
32 import net.sf.mbus4j.MBusUtils;
33
34
35
36
37
38
39 public class Stack {
40
41 private int stackPos;
42 private byte[] data;
43
44 public void clear() {
45 data = null;
46 stackPos = -1;
47 }
48
49 public void init(int i) {
50 data = new byte[i];
51 stackPos = 0;
52 }
53
54 public boolean isFull() {
55 return data.length == stackPos;
56 }
57
58 public boolean peekIsTimestampRes1() {
59 return (data[stackPos - 4] & 0x40) == 0x40;
60 }
61
62 public boolean peekIsTimestampRes2() {
63 return (data[stackPos - 3] & 0x40) == 0x40;
64 }
65
66 public boolean peekIsTimestampRes3() {
67 return (data[stackPos - 3] & 0x20) == 0x20;
68 }
69
70 public boolean peekIsTimestampSummertime() {
71 return (data[stackPos - 3] & 0x80) == 0x80;
72 }
73
74 public boolean peekIsTimestampValid() {
75 return (data[stackPos - 4] & 0x80) != 0x80;
76 }
77
78 public byte popBcdByte() {
79 return (byte) popBcdLong(2);
80 }
81
82
83 public char toLcdDigit(int bcdDigit) {
84 switch (bcdDigit) {
85 case 0x00:
86 return '0';
87 case 0x01:
88 return '1';
89 case 0x02:
90 return '2';
91 case 0x03:
92 return '3';
93 case 0x04:
94 return '4';
95 case 0x05:
96 return '5';
97 case 0x06:
98 return '6';
99 case 0x07:
100 return '7';
101 case 0x08:
102 return '8';
103 case 0x09:
104 return '9';
105 case 0x0A:
106 return 'A';
107 case 0x0B:
108 return 'b';
109 case 0x0C:
110 return 'C';
111 case 0x0D:
112 return ' ';
113 case 0x0E:
114 return 'E';
115 case 0x0F:
116 return '-';
117 default:
118 throw new RuntimeException("Should never ever happend!");
119 }
120 }
121
122
123 public String peekBcdError(int digits) {
124 char[] result = new char[digits];
125 int resultPos = 0;
126 final int floorPos = stackPos - (digits / 2);
127 boolean isError = false;
128
129 for (int i = stackPos - 1; i >= floorPos; i--) {
130 result[resultPos++] = toLcdDigit((data[i] >> 4) & 0x0F);
131 isError |= ((i == (stackPos - 1)) && ((data[i] & 0x0F) == 0x0F));
132 result[resultPos++] += toLcdDigit(data[i] & 0x0F);
133 isError |= ((data[i] & 0x0F) > 0x09);
134 }
135
136 if (isError) {
137 return new String(result);
138 } else {
139 return null;
140 }
141 }
142
143 public int popBcdInteger(int digits) {
144 return (int) popBcdLong(digits);
145 }
146
147 public short popBcdShort(int digits) {
148 return (short) popBcdLong(digits);
149 }
150
151 public long popBcdLong(int digits) {
152 long result = 0;
153 final int floorPos = stackPos - (digits / 2);
154 boolean isNegative = false;
155
156 for (int i = stackPos - 1; i >= floorPos; i--) {
157 result *= 10;
158
159 if ((i == (stackPos - 1)) && (((data[i] >> 4) & 0x0F) == 0x0F)) {
160 isNegative = true;
161 } else {
162 result += ((data[i] >> 4) & 0x0F);
163 }
164
165 result *= 10;
166 result += (data[i] & 0x0F);
167 }
168
169 stackPos -= (digits / 2);
170
171 if (isNegative) {
172 return -result;
173 } else {
174 return result;
175 }
176 }
177
178 public byte popByte() {
179 return data[--stackPos];
180 }
181
182 public byte[] popBytes() {
183 stackPos = 0;
184
185 return data;
186 }
187
188 public Date popDate() {
189 int val = popShort();
190 Calendar cal = Calendar.getInstance();
191 cal.set(Calendar.MILLISECOND, 0);
192 cal.set(Calendar.SECOND, 0);
193 cal.set(Calendar.MINUTE, 0);
194 cal.set(Calendar.HOUR_OF_DAY, 0);
195 cal.set(Calendar.DAY_OF_MONTH, val & 0x1F);
196 cal.set(Calendar.YEAR, 2000 + ((val >> 5) & 0x07) + ((val >> 9) & 0x78));
197 cal.set(Calendar.MONTH, ((val >> 8) & 0x0F) - 1);
198
199 return cal.getTime();
200 }
201
202 public float popFloat() {
203 return Float.intBitsToFloat(popInteger());
204 }
205
206 public int popInteger() {
207 return ((data[--stackPos] << 24) & 0xFF000000) | ((data[--stackPos] << 16) & 0x00FF0000)
208 | ((data[--stackPos] << 8) & 0x0000FF00) | (data[--stackPos] & 0x000000FF);
209 }
210
211 public int popInteger(int bytes) {
212 int result = 0;
213
214 for (int i = stackPos - 1; i >= (stackPos - bytes); i--) {
215 result <<= 8;
216 result += (data[i] & 0xFF);
217 }
218
219 stackPos -= bytes;
220
221 return result;
222 }
223
224 public long popLong() {
225 return popLong(8);
226 }
227
228 public long popLong(int bytes) {
229 long result = 0;
230
231 for (int i = stackPos - 1; i >= (stackPos - bytes); i--) {
232 result <<= 8;
233 result += (data[i] & 0xFF);
234 }
235
236 stackPos -= bytes;
237
238 return result;
239 }
240
241 public String popMan() {
242 return MBusUtils.short2Man(popShort());
243 }
244
245 public short popShort() {
246 return (short) (((data[--stackPos] << 8) & 0xFF00) | (data[--stackPos] & 0x00FF));
247 }
248
249 public String popString() {
250 StringBuilder sb = new StringBuilder();
251
252 for (byte b1 : data) {
253 sb.insert(0, (char) b1);
254 }
255
256 stackPos = 0;
257
258 return sb.toString();
259 }
260
261 public Date popTimeStamp() {
262 int val = popInteger(4);
263 Calendar cal = Calendar.getInstance();
264
265 cal.set(Calendar.MILLISECOND, 0);
266 cal.set(Calendar.SECOND, 0);
267 cal.set(Calendar.MINUTE, val & 0x3F);
268 cal.set(Calendar.HOUR_OF_DAY, (val >> 8) & 0x1F);
269 cal.set(Calendar.DAY_OF_MONTH, (val >> 16) & 0x1F);
270 cal.set(Calendar.MONTH, ((val >> 24) & 0x0F) - 1);
271 cal.set(Calendar.YEAR, 2000 + ((val >> 21) & 0x07) + ((val >> 25) & 0x78));
272
273 return cal.getTime();
274 }
275
276 public void push(byte b) {
277 data[stackPos++] = b;
278 }
279 }