View Javadoc
1   /*******************************************************************************
2    * jArduino: Arduino C++ Code Generation From Java
3    * Copyright 2020 Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License");
6    * you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   ******************************************************************************/
17  package net.sourceforge.jarduino.message;
18  
19  import java.util.ArrayList;
20  import java.util.HashMap;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.Objects;
24  
25  import net.sourceforge.jarduino.ArduinoException;
26  import net.sourceforge.jarduino.message.ArduinoAttribute.ArduinoAttrObject;
27  import net.sourceforge.jarduino.message.ArduinoParser.ArduinoParserException;
28  
29  /**
30   * Arduino Signal.
31   */
32  public final class ArduinoSignal
33          implements ArduinoNamedObject, ArduinoAttrObject {
34      /**
35       * The Marker.
36       */
37      static final String MARKER = "SG_";
38  
39      /**
40       * The multiplex1 character.
41       */
42      private static final char MULTI1 = 'M';
43  
44      /**
45       * The multiplex2 character.
46       */
47      private static final char MULTI2 = 'm';
48  
49      /**
50       * The null multiplexId.
51       */
52      public static final Long MULTI_NONE = -1L;
53  
54      /**
55       * the owning message.
56       */
57      private final ArduinoMessage theOwner;
58  
59      /**
60       * the name of the signal.
61       */
62      private final String theName;
63  
64      /**
65       * the units of the signal.
66       */
67      private final String theUnits;
68  
69      /**
70       * the definition of the signal.
71       */
72      private final ArduinoSignalDefinition theDefinition;
73  
74      /**
75       * the factor of the signal.
76       */
77      private final ArduinoSignalFactor theFactor;
78  
79      /**
80       * the range of the signal.
81       */
82      private final ArduinoSignalRange theRange;
83  
84      /**
85       * the list of receiving Nodes.
86       */
87      private final List<ArduinoNode> theReceivers;
88  
89      /**
90       * the Map of explicit attributes.
91       */
92      private final Map<ArduinoAttribute, Object> theAttributes;
93  
94      /**
95       * the values.
96       */
97      private ArduinoValues theValues;
98  
99      /**
100      * is this the multiplex signal.
101      */
102     private boolean isMultiplex;
103 
104     /**
105      * the multiplex id.
106      */
107     private Long theMultiplexId;
108 
109     /**
110      * Constructor.
111      * @param pOwner the owner
112      * @param pName the name
113      * @param pDef the definition
114      * @param pFactor the factor
115      * @param pRange the range
116      * @param pUnits the units
117      */
118     private ArduinoSignal(final ArduinoMessage pOwner,
119                           final String pName,
120                           final ArduinoSignalDefinition pDef,
121                           final ArduinoSignalFactor pFactor,
122                           final ArduinoSignalRange pRange,
123                           final String pUnits) {
124         /* Store parameters */
125         theOwner = pOwner;
126         theName = pName;
127         theDefinition = pDef;
128         theFactor = pFactor;
129         theRange = pRange;
130         theUnits = pUnits;
131         isMultiplex = false;
132         theMultiplexId = MULTI_NONE;
133 
134         /* Create the lists and maps */
135         theReceivers = new ArrayList<>();
136         theAttributes  = new HashMap<>();
137     }
138 
139 
140     /**
141      * Parse the receiver nodes.
142      * @param pSystem the system
143      * @param pReceivers the receivers string
144      * @throws ArduinoParserException on error
145      */
146     private void parseReceivers(final ArduinoSystem pSystem,
147                                 final String pReceivers) throws ArduinoParserException {
148         /* Loop through the tokens */
149         String myReceivers = pReceivers;
150         while (myReceivers.length() > 0) {
151             /* Split on comma separator */
152             final int myIndex = myReceivers.indexOf(ArduinoChar.COMMA);
153             if (myIndex == -1) {
154                 theReceivers.add(pSystem.findNodeByName(myReceivers.trim()));
155                 return;
156             }
157             final String myNode = myReceivers.substring(0, myIndex).trim();
158             theReceivers.add(pSystem.findNodeByName(myNode));
159             myReceivers = myReceivers.substring(myIndex + 1);
160         }
161     }
162 
163     /**
164      * Obtain the owner.
165      * @return the owner
166      */
167     public ArduinoMessage getOwner() {
168         return theOwner;
169     }
170 
171     @Override
172     public String getName() {
173         return theName;
174     }
175 
176     /**
177      * Obtain the units.
178      * @return the units
179      */
180     public String getUnits() {
181         return theUnits;
182     }
183 
184     /**
185      * Obtain the definition.
186      * @return the definition
187      */
188     public ArduinoSignalDefinition getDefinition() {
189         return theDefinition;
190     }
191 
192     /**
193      * Obtain the factor.
194      * @return the factor
195      */
196     public ArduinoSignalFactor getFactor() {
197         return theFactor;
198     }
199 
200     /**
201      * Obtain the range.
202      * @return the range
203      */
204     public ArduinoSignalRange getRange() {
205         return theRange;
206     }
207 
208     /**
209      * Does this signal use floats?
210      * @return true/false
211      */
212     public boolean isFloat() {
213         return theFactor.isFloat() || theRange.isFloat();
214     }
215 
216     /**
217      * Does this signal use signed ints?
218      * @return true/false
219      */
220     public boolean isSigned() {
221         return !isFloat() && theDefinition.getDataType().isSigned();
222     }
223 
224     /**
225      * Obtain values.
226      * @return the values
227      */
228     public ArduinoValues getValues() {
229         return theValues;
230     }
231 
232     /**
233      * set values.
234      * @param pValues the values
235      */
236     void setValues(final ArduinoValues pValues) {
237         theValues = pValues;
238     }
239 
240     /**
241      * Is this the multiplex signal.
242      * @return true/false
243      */
244     public boolean isMultiplex() {
245         return isMultiplex;
246     }
247 
248     /**
249      * set multiplex.
250      */
251     private void setMultiplex() {
252         isMultiplex = true;
253     }
254 
255     /**
256      * Obtain the multiplexId.
257      * @return the Id
258      */
259     public Long getMultiplexId() {
260         return theMultiplexId;
261     }
262 
263     /**
264      * Set the multiplexId.
265      * @param pId the multiplexId
266      */
267     public void setMultiplexId(final Long pId) {
268         theMultiplexId = pId;
269     }
270 
271     /**
272      * Obtain the receivers.
273      * @return the receivers
274      */
275     public List<ArduinoNode> getReceivers() {
276         return theReceivers;
277     }
278 
279     /**
280      * Set value for attribute.
281      * @param pAttr the attribute
282      * @param pValue the value
283      * @throws ArduinoParserException on error
284      */
285     void setAttrValue(final ArduinoAttribute pAttr,
286                       final Object pValue) throws ArduinoParserException {
287         /* Check that this is not a duplicate */
288         if (theAttributes.containsKey(pAttr)) {
289             throw new ArduinoParserException("Duplicate Attribute", pAttr.getName());
290         }
291 
292         /* Store the value */
293         theAttributes.put(pAttr, pValue);
294     }
295 
296     @Override
297     public Object getAttrValue(final ArduinoAttribute pAttr) {
298         final Object myValue = theAttributes.get(pAttr);
299         return myValue == null ? pAttr.getDefault() : myValue;
300     }
301 
302     /**
303      * Parse signal.
304      * @param pOwner the owning message
305      * @param pSignalDef the signal representation
306      * @throws ArduinoException on error
307      */
308     static void parseSignal(final ArduinoMessage pOwner,
309                             final String pSignalDef) throws ArduinoException {
310         /* Split out header/signal */
311         final int myIndex = pSignalDef.indexOf(ArduinoChar.COLON);
312         if (myIndex == -1) {
313             throw new ArduinoException("Missing " + ArduinoChar.COLON + " separator", pSignalDef);
314         }
315         String myHdr = pSignalDef.substring(0, myIndex);
316         String myLine = pSignalDef.substring(myIndex + 1).trim();
317 
318         /* Marker is first token in header */
319         final String myMarker = ArduinoParser.nextToken(myHdr);
320         myHdr = ArduinoParser.stripToken(myHdr, myMarker);
321         if (!myMarker.equals(MARKER)) {
322             throw new ArduinoException("Invalid marker", pSignalDef);
323         }
324 
325         /* Name is next token in header */
326         final String myName = ArduinoParser.nextToken(myHdr);
327         myHdr = ArduinoParser.stripToken(myHdr, myName);
328 
329         /* Protect against exceptions */
330         try {
331             /* Definition is first token in line */
332             final String myDataDef = ArduinoParser.nextToken(myLine);
333             myLine = ArduinoParser.stripToken(myLine, myDataDef);
334             final ArduinoSignalDefinition myDef = ArduinoSignalDefinition.parseDefinition(myDataDef);
335 
336             /* Factor is next token */
337             final String myFactorDef = ArduinoParser.nextToken(myLine);
338             myLine = ArduinoParser.stripToken(myLine, myFactorDef);
339             final ArduinoSignalFactor myFactor = ArduinoSignalFactor.parseFactors(myFactorDef);
340 
341             /* Range is next token */
342             final String myRangeDef = ArduinoParser.nextToken(myLine);
343             myLine = ArduinoParser.stripToken(myLine, myRangeDef);
344             final ArduinoSignalRange myRange = ArduinoSignalRange.parseRange(myRangeDef);
345 
346             /* Units is next token */
347             final String myUnits = ArduinoParser.nextQuotedToken(myLine);
348             myLine = ArduinoParser.stripQuotedToken(myLine, myUnits);
349 
350             /* Create the signal and parse the final token */
351             final ArduinoSignalinoSignal.html#ArduinoSignal">ArduinoSignal mySignal = new ArduinoSignal(pOwner, myName, myDef, myFactor, myRange, myUnits);
352             mySignal.parseReceivers(pOwner.getSystem(), myLine);
353 
354             /* If we have a multiplex details */
355             if (myHdr.length() > 0) {
356                 if (myHdr.charAt(0) == MULTI1) {
357                     mySignal.setMultiplex();
358                 } else {
359                     if (myHdr.charAt(0) != MULTI2) {
360                         throw new ArduinoParserException("Invalid multiplex", myHdr);
361                     }
362                     mySignal.setMultiplexId((long) ArduinoParser.parseNumber(myHdr.substring(1)));
363                 }
364             }
365 
366             /* Register with owner */
367             pOwner.addSignal(mySignal);
368 
369             /* Handle parser exceptions */
370         } catch (ArduinoParserException e) {
371             throw new ArduinoException(e.getMessage() + ArduinoChar.COLON + e.getDetail(), pSignalDef);
372         }
373     }
374 
375     @Override
376     public boolean equals(final Object pThat) {
377         /* Handle trivial cases */
378         if (pThat == this) {
379             return true;
380         } else if (!(pThat instanceof ArduinoSignal)) {
381             return false;
382         }
383 
384         /* Access correctly */
385         final ArduinoSignal./../net/sourceforge/jarduino/message/ArduinoSignal.html#ArduinoSignal">ArduinoSignal myThat = (ArduinoSignal) pThat;
386 
387         /* Check name and owner */
388         return theName.equals(myThat.getName())
389                 && theOwner.equals(myThat.getOwner());
390     }
391 
392     @Override
393     public int hashCode() {
394         return Objects.hash(theOwner, theName);
395     }
396 
397     @Override
398     public String toString() {
399         /* Handle headers */
400         final StringBuilder myBuilder = new StringBuilder();
401         myBuilder.append(MARKER);
402         myBuilder.append(ArduinoChar.BLANK);
403         myBuilder.append(theName);
404 
405         /* Handle multiplex */
406         if (isMultiplex) {
407             myBuilder.append(ArduinoChar.BLANK);
408             myBuilder.append(MULTI1);
409         } else if (!theMultiplexId.equals(MULTI_NONE)) {
410             myBuilder.append(ArduinoChar.BLANK);
411             myBuilder.append(MULTI2);
412             myBuilder.append(theMultiplexId);
413         }
414 
415         /* Append the detail */
416         myBuilder.append(ArduinoChar.COLON);
417         myBuilder.append(ArduinoChar.BLANK);
418         myBuilder.append(theDefinition);
419         myBuilder.append(ArduinoChar.BLANK);
420         myBuilder.append(theFactor);
421         myBuilder.append(ArduinoChar.BLANK);
422         myBuilder.append(theRange);
423         myBuilder.append(ArduinoChar.BLANK);
424         myBuilder.append(ArduinoChar.QUOTE);
425         myBuilder.append(theUnits);
426         myBuilder.append(ArduinoChar.QUOTE);
427         myBuilder.append(ArduinoChar.BLANK);
428 
429         /* Loop through the receivers */
430         for (int i = 0; i < theReceivers.size(); i++) {
431             if (i > 0) {
432                 myBuilder.append(ArduinoChar.COMMA);
433             }
434             myBuilder.append(theReceivers.get(i));
435         }
436 
437         /* return the string */
438         return myBuilder.toString();
439     }
440 }