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.JSONObject;
31  
32  import net.sf.mbus4j.dataframes.datablocks.DataBlock;
33  import net.sf.mbus4j.json.JsonSerializeType;
34  
35  import java.util.ArrayList;
36  import java.util.Iterator;
37  import java.util.List;
38  import net.sf.mbus4j.MBusUtils;
39  
40  /**
41   * @TODO implement masked FabricationNumber as last fallback
42   *
43   * @author arnep@users.sourceforge.net
44   * @version $Id: SelectionOfSlaves.java 150 2015-06-17 12:54:01Z arnep $
45   */
46  public class SelectionOfSlaves implements LongFrame {
47  
48      public enum WildcardNibbles {
49  
50          ID_0 {
51                      @Override
52                      public boolean isFirst() {
53                          return true;
54                      }
55                  },
56          ID_1,
57          ID_2,
58          ID_3,
59          ID_4,
60          ID_5,
61          ID_6,
62          ID_7,
63          MAN_0,
64          MAN_1,
65          MAN_2,
66          MAN_3,
67          MEDIUM_0,
68          MEDIUM_1,
69          VERSION_0,
70          VERSION_1 {
71                      @Override
72                      public boolean isLast() {
73                          return true;
74                      }
75                  };
76  
77          public WildcardNibbles next() {
78              return WildcardNibbles.values()[this.ordinal() + 1];
79          }
80  
81          public WildcardNibbles prev() {
82              return WildcardNibbles.values()[this.ordinal() - 1];
83          }
84  
85          public boolean isLast() {
86              return false;
87          }
88  
89          public boolean isFirst() {
90              return false;
91          }
92  
93      }
94  
95      private byte address;
96      private int bcdMaskedId;
97      private byte maskedVersion;
98      private short maskedMan;
99      private byte maskedMedium;
100     private final List<DataBlock> datablocks = new ArrayList<>();
101 
102     public SelectionOfSlaves(byte address) {
103         this.address = address;
104     }
105 
106     public SelectionOfSlaves(SendUserData old) {
107         this.address = old.getAddress();
108     }
109 
110     @Override
111     public boolean addDataBlock(DataBlock dataBlock) {
112         return datablocks.add(dataBlock);
113     }
114 
115     @Override
116     public byte getAddress() {
117         return address;
118     }
119 
120     @Override
121     public ControlCode getControlCode() {
122         return ControlCode.SND_UD;
123     }
124 
125     @Override
126     public DataBlock getLastDataBlock() {
127         return datablocks.get(datablocks.size() - 1);
128     }
129 
130     /**
131      * @return the bcdMaskedId
132      */
133     public int getBcdMaskedId() {
134         return bcdMaskedId;
135     }
136 
137     /**
138      * @return the maskedMan
139      */
140     public short getMaskedMan() {
141         return maskedMan;
142     }
143 
144     /**
145      * @return the maskedMedium
146      */
147     public int getMaskedMedium() {
148         return maskedMedium;
149     }
150 
151     /**
152      * @return the maskedVersion
153      */
154     public int getMaskedVersion() {
155         return maskedVersion;
156     }
157 
158     /**
159      * @return the fcb
160      */
161     public boolean isFcb() {
162         return false;
163     }
164 
165     @Override
166     public Iterator<DataBlock> iterator() {
167         return datablocks.iterator();
168     }
169 
170     @Override
171     public void replaceDataBlock(DataBlock oldDataBlock, DataBlock newDataBlock) {
172         final int pos = datablocks.indexOf(oldDataBlock);
173         datablocks.remove(pos);
174         datablocks.add(pos, newDataBlock);
175     }
176 
177     @Override
178     public void setAddress(byte address) {
179         this.address = address;
180     }
181 
182     /**
183      * @param bcdMaskedId the bcdMaskedId to set
184      */
185     public void setBcdMaskedId(int bcdMaskedId) {
186         this.bcdMaskedId = bcdMaskedId;
187     }
188 
189     /**
190      * @param maskedMan the maskedMan to set
191      */
192     public void setMaskedMan(short maskedMan) {
193         this.maskedMan = maskedMan;
194     }
195 
196     /**
197      * @param maskedMedium the maskedMedium to set
198      */
199     public void setMaskedMedium(byte maskedMedium) {
200         this.maskedMedium = maskedMedium;
201     }
202 
203     /**
204      * @param maskedVersion the maskedVersion to set
205      */
206     public void setMaskedVersion(byte maskedVersion) {
207         this.maskedVersion = maskedVersion;
208     }
209 
210     @Override
211     public String toString() {
212         StringBuilder sb = new StringBuilder();
213         sb.append("control code = ").append(getControlCode()).append('\n');
214         sb.append(String.format("address = 0x%02X\n", address));
215         sb.append(String.format("bcdMaskedId = 0x%08X\n", bcdMaskedId));
216         sb.append(String.format("maskedMan = 0x%04X\n", maskedMan));
217         sb.append(String.format("maskedVersion = 0x%02X\n", maskedVersion));
218         sb.append(String.format("maskedMedium = 0x%02X\n", maskedMedium));
219 
220         return sb.toString();
221     }
222 
223     public boolean matchId(int id) {
224         int hexBcdId = MBusUtils.int2Bcd(id);
225         int hexMask = bcdMaskedId;
226 
227         for (int i = 0; i < 8; i++) {
228             if (((hexMask & 0x0F) == 0x0F) || ((hexMask & 0x0F) == (hexBcdId & 0x0F))) {
229                 hexMask >>= 4;
230                 hexBcdId >>= 4;
231             } else {
232                 return false;
233             }
234         }
235 
236         return true;
237     }
238 
239     public boolean matchAll(int id, String man, MBusMedium medium, int version) {
240         return matchId(id) && matchMan(man) && matchMedium(medium) && matchVersion(version);
241     }
242 
243     private boolean matchMan(String man) {
244         int hexMan = MBusUtils.man2Short(man);
245         int hexMask = maskedMan;
246 
247         for (int i = 0; i < 8; i++) {
248             if (((hexMask & 0x0F) != 0x0F) && ((hexMask & 0x0F) != (hexMan & 0x0F))) {
249                 return false;
250             }
251 
252             hexMask >>= 4;
253             hexMan >>= 4;
254         }
255 
256         return true;
257     }
258 
259     private boolean matchMedium(MBusMedium medium) {
260         int hexMedium = medium.getId();
261         int hexMask = maskedMedium;
262 
263         for (int i = 0; i < 8; i++) {
264             if (((hexMask & 0x0F) != 0x0F) && ((hexMask & 0x0F) != (hexMedium & 0x0F))) {
265                 return false;
266             }
267 
268             hexMask >>= 4;
269             hexMedium >>= 4;
270         }
271 
272         return true;
273     }
274 
275     private boolean matchVersion(int version) {
276         int hexVersion = version;
277         int hexMask = maskedVersion;
278 
279         for (int i = 0; i < 8; i++) {
280             if (((hexMask & 0x0F) != 0x0F) && ((hexMask & 0x0F) != (hexVersion & 0x0F))) {
281                 return false;
282             }
283 
284             hexMask >>= 4;
285             hexVersion >>= 4;
286         }
287 
288         return true;
289     }
290 
291     @Override
292     public JSONObject toJSON(JsonSerializeType jsonSerializeType) {
293         throw new UnsupportedOperationException("Not supported yet.");
294     }
295 
296     @Override
297     public void fromJSON(JSONObject json) {
298         throw new UnsupportedOperationException("Not supported yet.");
299     }
300 
301     public byte getWildcardNibble(WildcardNibbles wildcardNibbles) {
302         switch (wildcardNibbles) {
303             case ID_0:
304                 return (byte) (bcdMaskedId & 0x0F);
305             case ID_1:
306                 return (byte) ((bcdMaskedId >>> 4) & 0x0F);
307             case ID_2:
308                 return (byte) ((bcdMaskedId >>> 8) & 0x0F);
309             case ID_3:
310                 return (byte) ((bcdMaskedId >>> 12) & 0x0F);
311             case ID_4:
312                 return (byte) ((bcdMaskedId >>> 16) & 0x0F);
313             case ID_5:
314                 return (byte) ((bcdMaskedId >>> 20) & 0x0F);
315             case ID_6:
316                 return (byte) ((bcdMaskedId >>> 24) & 0x0F);
317             case ID_7:
318                 return (byte) ((bcdMaskedId >>> 28) & 0x0F);
319             case MAN_0:
320                 return (byte) (maskedMan & 0x0F);
321             case MAN_1:
322                 return (byte) ((maskedMan >>> 4) & 0x0F);
323             case MAN_2:
324                 return (byte) ((maskedMan >>> 8) & 0x0F);
325             case MAN_3:
326                 return (byte) ((maskedMan >>> 12) & 0x0F);
327             case MEDIUM_0:
328                 return (byte) (maskedMedium & 0x0F);
329             case MEDIUM_1:
330                 return (byte) ((maskedMedium >>> 4) & 0x0F);
331             case VERSION_0:
332                 return (byte) (maskedVersion & 0x0F);
333             case VERSION_1:
334                 return (byte) ((maskedVersion >>> 4) & 0x0F);
335             default:
336                 throw new RuntimeException("Cant handle " + wildcardNibbles);
337         }
338     }
339 
340     public void maskWildcardNibble(WildcardNibbles wildcardNibbles) {
341         setWildcardNibble(wildcardNibbles, (byte)0x0F);
342     }
343     
344     public void setWildcardNibble(WildcardNibbles wildcardNibbles, byte value) {
345         if ((value & 0xF0) != 0) {
346             throw new RuntimeException("Upper nibble must be 0");
347         }
348         switch (wildcardNibbles) {
349             case ID_0:
350                 bcdMaskedId = (bcdMaskedId & 0xFFFFFFF0) | value;
351                 break;
352             case ID_1:
353                 bcdMaskedId = (bcdMaskedId & 0xFFFFFF0F) | value << 4;
354                 break;
355             case ID_2:
356                 bcdMaskedId = (bcdMaskedId & 0xFFFFF0FF) | value << 8;
357                 break;
358             case ID_3:
359                 bcdMaskedId = (bcdMaskedId & 0xFFFF0FFF) | value << 12;
360                 break;
361             case ID_4:
362                 bcdMaskedId = (bcdMaskedId & 0xFFF0FFFF) | value << 16;
363                 break;
364             case ID_5:
365                 bcdMaskedId = (bcdMaskedId & 0xFF0FFFFF) | value << 20;
366                 break;
367             case ID_6:
368                 bcdMaskedId = (bcdMaskedId & 0xF0FFFFFF) | value << 24;
369                 break;
370             case ID_7:
371                 bcdMaskedId = (bcdMaskedId & 0x0FFFFFFF) | value << 28;
372                 break;
373             case MAN_0:
374                 maskedMan = (short) ((maskedMan & 0xFFF0) | value);
375                 break;
376             case MAN_1:
377                 maskedMan = (short) ((maskedMan & 0xFF0F) | value << 4);
378                 break;
379             case MAN_2:
380                 maskedMan = (short) ((maskedMan & 0xF0FF) | value << 8);
381                 break;
382             case MAN_3:
383                 maskedMan = (short) ((maskedMan & 0x0FFF) | value << 12);
384                 break;
385             case MEDIUM_0:
386                 maskedMedium = (byte) ((maskedMedium & 0xF0) | value);
387                 break;
388             case MEDIUM_1:
389                 maskedMedium = (byte) ((maskedMedium & 0xF0) | value << 4);
390                 break;
391             case VERSION_0:
392                 maskedVersion = (byte) ((maskedVersion & 0xF0) | value);
393                 break;
394             case VERSION_1:
395                 maskedVersion = (byte) ((maskedVersion & 0xF0) | value << 4);
396                 break;
397             default:
398                 throw new RuntimeException("Cant handle " + wildcardNibbles);
399         }
400     }
401 
402     public boolean isWildcardNibble(WildcardNibbles wildcardNibbles) {
403         switch (wildcardNibbles) {
404             case ID_0:
405                 return (bcdMaskedId & 0x0000000F) == 0x0000000F;
406             case ID_1:
407                 return (bcdMaskedId & 0x000000F0) == 0x000000F0;
408             case ID_2:
409                 return (bcdMaskedId & 0x00000F00) == 0x00000F00;
410             case ID_3:
411                 return (bcdMaskedId & 0x0000F000) == 0x0000F000;
412             case ID_4:
413                 return (bcdMaskedId & 0x000F0000) == 0x000F0000;
414             case ID_5:
415                 return (bcdMaskedId & 0x00F00000) == 0x00F00000;
416             case ID_6:
417                 return (bcdMaskedId & 0x0F000000) == 0x0F000000;
418             case ID_7:
419                 return (bcdMaskedId & 0xF0000000) == 0xF0000000;
420             case MAN_0:
421                 return (maskedMan & 0x000F) == 0x000F;
422             case MAN_1:
423                 return (maskedMan & 0x00F0) == 0x00F0;
424             case MAN_2:
425                 return (maskedMan & 0x0F00) == 0x0F00;
426             case MAN_3:
427                 return (maskedMan & 0xF000) == 0xF000;
428             case MEDIUM_0:
429                 return (maskedMedium & 0x0F) == 0x0F;
430             case MEDIUM_1:
431                 return (maskedMedium & 0xF0) == 0xF0;
432             case VERSION_0:
433                 return (maskedVersion & 0x0F) == 0x0F;
434             case VERSION_1:
435                 return (maskedVersion & 0xF0) == 0xF0;
436             default:
437                 throw new RuntimeException("Cant handle " + wildcardNibbles);
438         }
439     }
440 }