View Javadoc
1   package net.sf.mbus4j.dataframes;
2   
3   /*
4    * #%L
5    * mbus4j-core
6    * %%
7    * Copyright (C) 2009 - 2014 MBus4J
8    * %%
9    * mbus4j - Drivers for the M-Bus protocol - http://mbus4j.sourceforge.net/
10   * Copyright (C) 2009-2014, mbus4j.sf.net, and individual contributors as indicated
11   * by the @authors tag. See the copyright.txt in the distribution for a
12   * full listing of individual contributors.
13   * 
14   * This is free software; you can redistribute it and/or modify it
15   * under the terms of the GNU General Public License as
16   * published by the Free Software Foundation; either version 3 of
17   * the License, or (at your option) any later version.
18   * 
19   * This software is distributed in the hope that it will be useful,
20   * but WITHOUT ANY WARRANTY; without even the implied warranty of
21   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22   * Lesser General Public License for more details.
23   * 
24   * You should have received a copy of the GNU Lesser General Public
25   * License along with this software; if not, write to the Free
26   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
27   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
28   * #L%
29   */
30  import net.sf.json.JSONArray;
31  import net.sf.json.JSONObject;
32  
33  import net.sf.mbus4j.dataframes.datablocks.DataBlock;
34  import net.sf.mbus4j.dataframes.datablocks.dif.DataFieldCode;
35  import net.sf.mbus4j.json.JSONFactory;
36  import net.sf.mbus4j.json.JsonSerializeType;
37  
38  import java.util.ArrayList;
39  import java.util.Arrays;
40  import java.util.Iterator;
41  import java.util.List;
42  import java.util.Objects;
43  import net.sf.mbus4j.dataframes.datablocks.dif.FunctionField;
44  import net.sf.mbus4j.dataframes.datablocks.vif.UnitOfMeasurement;
45  import net.sf.mbus4j.dataframes.datablocks.vif.Vif;
46  import net.sf.mbus4j.dataframes.datablocks.vif.Vife;
47  
48  /**
49   *
50   * @author arnep@users.sourceforge.net
51   * @version $Id: UserDataResponse.java 163 2016-10-07 18:53:55Z arnep $
52   */
53  public class UserDataResponse
54          implements LongFrame,
55          PrimaryAddress,
56          Cloneable {
57  
58      @Override
59      public JSONObject toJSON(JsonSerializeType jsonSerializeType) {
60          JSONObject result = new JSONObject();
61          result.accumulate("controlCode",
62                  getControlCode());
63  
64          if (JsonSerializeType.ALL == jsonSerializeType) {
65              result.accumulate("manufacturer",
66                      getManufacturer());
67              result.accumulate("medium",
68                      getMedium().getLabel());
69              result.accumulate("version",
70                      JSONFactory.encodeHexByte(getVersion()));
71              result.accumulate("identNumber",
72                      getIdentNumber());
73              result.accumulate("address",
74                      JSONFactory.encodeHexByte(getAddress()));
75              result.accumulate("accessNumber",
76                      getAccessNumber());
77              result.accumulate("acd",
78                      isAcd());
79              result.accumulate("dfc",
80                      isDfc());
81              result.accumulate("signature",
82                      JSONFactory.encodeHexShort(getSignature()));
83  
84              JSONArray jsonStatusArray = new JSONArray();
85  
86              for (StatusCode st : getStatus()) {
87                  jsonStatusArray.add(st.getLabel());
88              }
89  
90              result.accumulate("status", jsonStatusArray);
91          }
92  
93          if ((JsonSerializeType.ALL == jsonSerializeType) || (JsonSerializeType.SLAVE_CONFIG == jsonSerializeType)) {
94              JSONArray jsonDataBlocks = new JSONArray();
95  
96              for (DataBlock db : this) {
97                  jsonDataBlocks.add(db.toJSON(jsonSerializeType));
98              }
99  
100             result.accumulate("dataBlocks", jsonDataBlocks);
101         }
102 
103         return result;
104     }
105 
106     @Override
107     public void fromJSON(JSONObject json) {
108         setManufacturer(json.containsKey("manufacturer") ? json.getString("manufacturer") : "");
109         setMedium(json.containsKey("medium") ? MBusMedium.fromLabel(json.getString("medium"))
110                 : MBusMedium.UNKNOWN_MEDIUM);
111         setVersion(JSONFactory.decodeHexByte(json, "version", (byte) 0));
112         setIdentNumber(json.containsKey("identNumber") ? json.getInt("identNumber") : 0);
113         setAddress(JSONFactory.decodeHexByte(json, "address", (byte) 0));
114         setAccessNumber(JSONFactory.getShort(json, "accessNumber", (short) 0));
115         setAcd(JSONFactory.getBoolean(json, "acd", false));
116         setDfc(JSONFactory.getBoolean(json, "dfc", false));
117         setSignature(JSONFactory.decodeHexShort(json, "signature", (short) 0));
118 
119         if (json.containsKey("status")) {
120             JSONArray statusArray = json.getJSONArray("status");
121 
122             if (statusArray.isEmpty()) {
123                 setStatus(new StatusCode[0]);
124             } else {
125                 status = new StatusCode[statusArray.size()];
126 
127                 for (int i = 0; i < status.length; i++) {
128                     status[i] = StatusCode.fromLabel(statusArray.getString(i));
129                 }
130             }
131         }
132 
133         JSONFactory.readDataBlocks(this, json);
134     }
135 
136     public static enum StatusCode { // Taken from Chapter 6.6 Fig 27
137 
138         APPLICATION_NO_ERROR(0x00, "No application error"),
139         APPLICATION_BUSY(0x01, "Application busy"),
140         APPLICATION_ANY_ERROR(0x02, "Any application error"),
141         APPLICATION_RESERVED(0x03, "Application reserved"),
142         // Taken from Chapter 6.2 Fig 16
143         POWER_LOW(0x04, "Power Low"), PERMANENT_ERROR(0x08, "Permanent error"),
144         TEMPORARY_ERROR(0x10, "Temporary error"),
145         MAN_SPEC_0X20(0x20, "Specific to manufacturer 0x20"),
146         MAN_SPEC_0X40(0x40, "Specific to manufacturer 0x40"),
147         MAN_SPEC_0X80(0x80, "Specific to manufacturer 0x80");
148 
149         public static byte toId(StatusCode[] values) {
150             byte result = 0;
151 
152             for (StatusCode sc : values) {
153                 result |= sc.id;
154             }
155 
156             return result;
157         }
158 
159         public final byte id;
160         private final String label;
161 
162         private StatusCode(int id, String description) {
163             this.id = (byte) id;
164             this.label = description;
165         }
166 
167         @Override
168         public String toString() {
169             return label;
170         }
171 
172         public String getLabel() {
173             return label;
174         }
175 
176         public static StatusCode fromLabel(String label) {
177             for (StatusCode value : values()) {
178                 if (value.getLabel().equals(label)) {
179                     return value;
180                 }
181             }
182 
183             return valueOf(label);
184         }
185     }
186 
187     private boolean acd;
188     private boolean dfc;
189     private byte version;
190     private short accessNumber;
191     private StatusCode[] status;
192     private short signature;
193     private MBusMedium medium;
194     private int identNumber;
195     private String manufacturer;
196     private List<DataBlock> dataBlocks = new ArrayList<>();
197     private byte address;
198 
199     public UserDataResponse() {
200         super();
201     }
202 
203     public UserDataResponse(boolean acd, boolean dfc) {
204         this.acd = acd;
205         this.dfc = dfc;
206     }
207 
208     @Override
209     public boolean addDataBlock(DataBlock dataBlock) {
210         return dataBlocks.add(dataBlock);
211     }
212 
213     public boolean addAllDataBlocks(List<DataBlock> list) {
214         return dataBlocks.addAll(list);
215     }
216 
217     public void addStatus(StatusCode status) {
218         if (this.status == null) {
219             this.status = new StatusCode[]{status};
220         } else {
221             this.status = Arrays.copyOf(this.status, this.status.length + 1);
222             this.status[this.status.length - 1] = status;
223         }
224     }
225 
226     public void clearDataBlocks() {
227         dataBlocks.clear();
228     }
229 
230     @Override
231     public UserDataResponse clone()
232             throws CloneNotSupportedException {
233         UserDataResponse result = (UserDataResponse) super.clone();
234         result.dataBlocks = new ArrayList<>();
235         result.dataBlocks.addAll(dataBlocks);
236 
237         return result;
238     }
239 
240     public short getAccessNumber() {
241         return accessNumber;
242     }
243 
244     /**
245      * @return the address
246      */
247     @Override
248     public byte getAddress() {
249         return address;
250     }
251 
252     @Override
253     public ControlCode getControlCode() {
254         return ControlCode.RSP_UD;
255     }
256 
257     /**
258      * @param i
259      * @return the dataBlocks
260      */
261     public DataBlock getDataBlock(int i) {
262         return dataBlocks.get(i);
263     }
264 
265     public int getDataBlockCount() {
266         return dataBlocks.size();
267     }
268 
269     public int getIdentNumber() {
270         return identNumber;
271     }
272 
273     @Override
274     public DataBlock getLastDataBlock() {
275         return (dataBlocks.isEmpty()) ? null : dataBlocks.get(dataBlocks.size() - 1);
276     }
277 
278     public String getManufacturer() {
279         return manufacturer;
280     }
281 
282     public MBusMedium getMedium() {
283         return medium;
284     }
285 
286     public short getSignature() {
287         return signature;
288     }
289 
290     public StatusCode[] getStatus() {
291         return status;
292     }
293 
294     public byte getVersion() {
295         return version;
296     }
297 
298     /**
299      * @return the acd
300      */
301     public boolean isAcd() {
302         return acd;
303     }
304 
305     /**
306      * @return the dfc
307      */
308     public boolean isDfc() {
309         return dfc;
310     }
311 
312     /**
313      * Indicates wheter there are more Packages to follow or no.
314      *
315      * @return
316      */
317     public boolean isLastPackage() {
318         return (getLastDataBlock() == null) ? true
319                 : (!DataFieldCode.SPECIAL_FUNCTION_MAN_SPEC_DATA_PACKETS_FOLLOWS.equals(getLastDataBlock()
320                         .getDataFieldCode()));
321     }
322 
323     @Override
324     public Iterator<DataBlock> iterator() {
325         return dataBlocks.iterator();
326     }
327 
328     @Override
329     public void replaceDataBlock(DataBlock oldDataBlock, DataBlock newDataBlock) {
330         final int pos = dataBlocks.indexOf(oldDataBlock);
331         dataBlocks.set(pos, newDataBlock);
332     }
333 
334     public void setAccessNumber(short accessNumber) {
335         this.accessNumber = accessNumber;
336     }
337 
338     /**
339      * @param acd the acd to set
340      */
341     public void setAcd(boolean acd) {
342         this.acd = acd;
343     }
344 
345     /**
346      * @param address the address to set
347      */
348     @Override
349     public void setAddress(byte address) {
350         this.address = address;
351     }
352 
353     /**
354      * @param dfc the dfc to set
355      */
356     public void setDfc(boolean dfc) {
357         this.dfc = dfc;
358     }
359 
360     public void setIdentNumber(int identNumber) {
361         this.identNumber = identNumber;
362     }
363 
364     public void setManufacturer(String manufacturer) {
365         this.manufacturer = manufacturer;
366     }
367 
368     public void setMedium(MBusMedium medium) {
369         this.medium = medium;
370     }
371 
372     public void setSignature(short signature) {
373         this.signature = signature;
374     }
375 
376     public void setStatus(StatusCode[] status) {
377         this.status = status;
378     }
379 
380     public void setVersion(byte version) {
381         this.version = version;
382     }
383 
384     @Override
385     public String toString() {
386         StringBuilder sb = new StringBuilder();
387         sb.append("control code = ").append(getControlCode()).append('\n');
388         sb.append("isAcd = ").append(isAcd()).append('\n');
389         sb.append("isDfc = ").append(isDfc()).append('\n');
390         sb.append(String.format("address = 0x%02X\n", address));
391         sb.append(String.format("ident number = %08d\n", identNumber));
392         sb.append("manufacturer = ").append(manufacturer).append('\n');
393         sb.append(String.format("version = 0x%02X\n", version));
394         sb.append("accessnumber = ").append(accessNumber).append('\n');
395         sb.append(String.format("status = %s\n",
396                 Arrays.toString(status)));
397         sb.append(String.format("signature = 0x%04X\n", signature));
398         sb.append("medium = ").append(medium.toString()).append('\n');
399         sb.append("lastPackage = ").append(isLastPackage()).append('\n');
400 
401         for (int i = 0; i < dataBlocks.size(); i++) {
402             sb.append(String.format("datablock[%d]:\n", i));
403             dataBlocks.get(i).toString(sb, "  ");
404         }
405 
406         return sb.toString();
407     }
408 
409     /**
410      * Find matches except DataType
411      *
412      * @param tarif
413      * @param storagenumber
414      * @param subUnit
415      * @param vif
416      * @param functionField
417      * @param vifes
418      * @return
419      */
420     public DataBlock[] getDataBlocks(int tarif, long storagenumber, short subUnit, Vif vif, FunctionField functionField, Vife[] vifes) {
421         DataBlock[] result = null;
422         for (DataBlock db : dataBlocks) {
423             if ((db.getTariff() == tarif)
424                     && (db.getStorageNumber() == storagenumber)
425                     && (db.getSubUnit() == subUnit)
426                     && (Objects.equals(db.getVif(), vif))
427                     && (db.getFunctionField() == functionField)
428                     && (Arrays.equals(db.getVifes(), vifes))) {
429                 if (result == null) {
430                     result = new DataBlock[]{db};
431                 } else {
432                     result = Arrays.copyOf(result, result.length + 1);
433                     result[result.length - 1] = db;
434                 }
435             }
436         }
437         return result;
438     }
439 
440     public DataBlock findDataBlock(final DataFieldCode difCode, final String paramDescr, final UnitOfMeasurement unitOfMeasurement, final FunctionField functionField, final long storageNumber, final short subUnit, final int tariff) {
441         DataBlock result = null;
442         for (DataBlock db : dataBlocks) {
443             if (Objects.equals(db.getDataFieldCode(), difCode)
444                     && Objects.equals(db.getParamDescr(), paramDescr)
445                     && Objects.equals(db.getUnitOfMeasurement(), unitOfMeasurement)
446                     && Objects.equals(db.getFunctionField(), functionField)
447                     && (db.getStorageNumber() == storageNumber)
448                     && (db.getSubUnit() == subUnit)
449                     && (db.getTariff() == tariff)) {
450                 if (result == null) {
451                     result = db;
452                 } else {
453                     throw new RuntimeException("Multiple db found: \n" + result + "\n\n" + db);
454                 }
455             }
456         }
457         if (result == null) {
458             throw new RuntimeException("No db found");
459         }
460         return result;
461     }
462 
463     @Deprecated
464     public boolean isDBUnique() {
465         for (DataBlock db : dataBlocks) {
466             if (getDataBlocks(db.getTariff(), db.getStorageNumber(), db.getSubUnit(), db.getVif(), db.getFunctionField(), db.getVifes()).length != 1) {
467                 return false;
468             }
469         }
470         return true;
471     }
472 
473 }