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.util;
18  
19  /**
20   * Field Parse/Set methods.
21   */
22  public final class ArduinoField {
23      /**
24       * Byte mask.
25       */
26      private static final int BYTEMASK = 0xFF;
27  
28      /**
29       * Private constructor.
30       */
31      private ArduinoField() {
32      }
33  
34      /**
35       * Parse a littleEndian field.
36       * @param pBuffer the buffer to parse
37       * @param pStart the start bit
38       * @param pLength the bit length
39       * @param pSigned is the field signed?
40       * @return the parsed value
41       */
42      public static long parseLEField(final byte[] pBuffer,
43                                      final int pStart,
44                                      final int pLength,
45                                      final boolean pSigned) {
46          /* Create the signing mask */
47          final long mySignMask = pSigned && (pLength < Long.SIZE) ? -(1L << pLength) : 0;
48          final long myTestMask = 1L << (pLength - 1);
49  
50          /* Determine the byte that contains the most significant bit and the number of relevant bits */
51          final int myMSB = pStart + pLength - 1;
52          final int myBits = 1 + (myMSB % Byte.SIZE);
53          int myPos = myMSB / Byte.SIZE;
54  
55          /* If we have a short value */
56          if (myBits >= pLength) {
57              final int bitsToShift = pStart % Byte.SIZE;
58              final long myValue = ((pBuffer[myPos] & BYTEMASK) >> bitsToShift) & ((1 << pLength) - 1);
59              return (myValue & myTestMask) == 0 ? myValue : myValue | mySignMask;
60          }
61  
62          /* Access starting value */
63          long myValue = pBuffer[myPos] & ((1 << myBits) - 1);
64  
65          /* Look at remaining bits */
66          int myRemaining = pLength - myBits;
67  
68          /* Process whole bytes */
69          while (myRemaining >= Byte.SIZE) {
70              myValue <<= Byte.SIZE;
71              myValue += pBuffer[--myPos] & BYTEMASK;
72              myRemaining -= Byte.SIZE;
73          }
74  
75          /* If we have remaining bits */
76          if (myRemaining > 0) {
77              myValue <<= myRemaining;
78              myValue += (pBuffer[--myPos] >> (Byte.SIZE - myRemaining)) & ((1 << myRemaining) - 1);
79          }
80  
81          /* return the value */
82          return (myValue & myTestMask) == 0 ? myValue : myValue | mySignMask;
83      }
84  
85      /**
86       * Parse a bigEndian field.
87       * @param pBuffer the buffer to parse
88       * @param pStart the start bit
89       * @param pLength the bit length
90       * @param pSigned is the field signed?
91       * @return the parsed value
92       */
93      public static long parseBEField(final byte[] pBuffer,
94                                      final int pStart,
95                                      final int pLength,
96                                      final boolean pSigned) {
97          /* Create the signing mask */
98          final long mySignMask = pSigned && (pLength < Long.SIZE) ? -(1L << pLength) : 0;
99          final long myTestMask = 1L << (pLength - 1);
100 
101         /* Determine the byte that contains the most significant bit and the number of relevant bits */
102         final int myBits = 1 + (pStart % Byte.SIZE);
103         int myPos = pStart / Byte.SIZE;
104 
105         /* If we have a short value */
106         if (myBits >= pLength) {
107             final long myValue = ((pBuffer[myPos] & BYTEMASK) >> (myBits - pLength)) & ((1 << pLength) - 1);
108             return (myValue & myTestMask) == 0 ? myValue : myValue | mySignMask;
109         }
110 
111         /* Access starting value */
112         long myValue = pBuffer[myPos] & ((1 << myBits) - 1);
113 
114         /* Look at remaining bits */
115         int myRemaining = pLength - myBits;
116 
117         /* Process whole bytes */
118         while (myRemaining >= Byte.SIZE) {
119             myValue <<= Byte.SIZE;
120             myValue += pBuffer[++myPos] & BYTEMASK;
121             myRemaining -= Byte.SIZE;
122         }
123 
124         /* If we have remaining bits */
125         if (myRemaining > 0) {
126             myValue <<= myRemaining;
127             myValue += (pBuffer[++myPos] >> (Byte.SIZE - myRemaining)) & ((1 << myRemaining) - 1);
128         }
129 
130         /* return the value */
131         return (myValue & myTestMask) == 0 ? myValue : myValue | mySignMask;
132     }
133 
134     /**
135      * Set a littleEndian field.
136      * @param pBuffer the buffer to set
137      * @param pStart the start bit
138      * @param pLength the bit length
139      * @param pValue the value to set
140      */
141     public static void setLEField(final byte[] pBuffer,
142                                   final int pStart,
143                                   final int pLength,
144                                   final long pValue) {
145         /* Determine the byte that contains the least significant bit and the number of relevant bits */
146         final int myBits = Byte.SIZE - (pStart % Byte.SIZE);
147         int myPos = pStart / Byte.SIZE;
148 
149         /* If we have a short value */
150         if (myBits >= pLength) {
151             final int bitsToShift = pStart % Byte.SIZE;
152             final int myMask = ((1 << pLength) - 1) << bitsToShift;
153             pBuffer[myPos] &= ~myMask;
154             pBuffer[myPos] |= (pValue << bitsToShift) & myMask;
155             return;
156         }
157 
158         /* Set starting value */
159         final int bitsToShift = Byte.SIZE - myBits;
160         int myMask = BYTEMASK << bitsToShift;
161         pBuffer[myPos] &= ~myMask;
162         pBuffer[myPos] |= (pValue << bitsToShift) & myMask;
163 
164         /* Look at remaining bits */
165         int myRemaining = pLength - myBits;
166         long myValue = pValue >> myBits;
167 
168         /* Process whole bytes */
169         while (myRemaining >= Byte.SIZE) {
170             pBuffer[++myPos] = (byte) myValue;
171             myRemaining -= Byte.SIZE;
172             myValue >>= Byte.SIZE;
173         }
174 
175         /* If we have remaining bits */
176         if (myRemaining > 0) {
177             myMask = (1 << myRemaining) - 1;
178             pBuffer[++myPos] &= ~myMask;
179             pBuffer[myPos] |= myValue & myMask;
180         }
181     }
182 
183     /**
184      * Set a bigEndian field.
185      * @param pBuffer the buffer to set
186      * @param pStart the start bit
187      * @param pLength the bit length
188      * @param pValue the value to set
189      */
190     public static void setBEField(final byte[] pBuffer,
191                                   final int pStart,
192                                   final int pLength,
193                                   final long pValue) {
194         /* Determine the byte that contains the most significant bit and the number of relevant bits */
195         int myBits = 1 + (pStart % Byte.SIZE);
196         int myPos = pStart / Byte.SIZE;
197 
198         /* If we have a short value */
199         if (myBits >= pLength) {
200             final int bitsToShift = myBits - pLength;
201             final int myMask = ((1 << pLength) - 1) << bitsToShift;
202             pBuffer[myPos] &= ~myMask;
203             pBuffer[myPos] |= (pValue << bitsToShift) & myMask;
204             return;
205         }
206 
207         /* Now look for the least significant bit */
208         final int myXtra = pLength - myBits - 1;
209         myPos += 1 + myXtra / Byte.SIZE;
210         myBits = 1 + myXtra % Byte.SIZE;
211 
212         /* Set starting value */
213         final int bitsToShift = Byte.SIZE - myBits;
214         int myMask = BYTEMASK << bitsToShift;
215         pBuffer[myPos] &= ~myMask;
216         pBuffer[myPos] |= (pValue << bitsToShift) & myMask;
217 
218         /* Look at remaining bits */
219         int myRemaining = pLength - myBits;
220         long myValue = pValue >> myBits;
221 
222         /* Process whole bytes */
223         while (myRemaining >= Byte.SIZE) {
224             pBuffer[--myPos] = (byte) myValue;
225             myRemaining -= Byte.SIZE;
226             myValue >>= Byte.SIZE;
227         }
228 
229         /* If we have remaining bits */
230         if (myRemaining > 0) {
231             myMask = (1 << myRemaining) - 1;
232             pBuffer[--myPos] &= ~myMask;
233             pBuffer[myPos] |= myValue & myMask;
234         }
235     }
236 
237     /**
238      * Set a littleEndian bitMap for field.
239      * @param pBuffer the buffer to set
240      * @param pStart the start bit
241      * @param pLength the bit length
242      */
243     public static void setLEFieldBits(final byte[] pBuffer,
244                                       final int pStart,
245                                       final int pLength) {
246         /* Determine the byte that contains the least significant bit and the number of relevant bits */
247         final int myBits = Byte.SIZE - (pStart % Byte.SIZE);
248         int myPos = pStart / Byte.SIZE;
249 
250         /* If we have a short value */
251         if (myBits >= pLength) {
252             final int bitsToShift = pStart % Byte.SIZE;
253             final int myMask = ((1 << pLength) - 1) << bitsToShift;
254             pBuffer[myPos] |= myMask;
255             return;
256         }
257 
258         /* Set starting value */
259         final int bitsToShift = Byte.SIZE - myBits;
260         int myMask = BYTEMASK << bitsToShift;
261         pBuffer[myPos] |= myMask;
262 
263         /* Look at remaining bits */
264         int myRemaining = pLength - myBits;
265 
266         /* Process whole bytes */
267         while (myRemaining >= Byte.SIZE) {
268             pBuffer[++myPos] = (byte) -1;
269             myRemaining -= Byte.SIZE;
270         }
271 
272         /* If we have remaining bits */
273         if (myRemaining > 0) {
274             myMask = (1 << myRemaining) - 1;
275             pBuffer[++myPos] |= myMask;
276         }
277     }
278 
279     /**
280      * Set a bigEndian bitMap for field.
281      * @param pBuffer the buffer to set
282      * @param pStart the start bit
283      * @param pLength the bit length
284      */
285     public static void setBEFieldBits(final byte[] pBuffer,
286                                       final int pStart,
287                                       final int pLength) {
288         /* Determine the byte that contains the most significant bit and the number of relevant bits */
289         int myBits = 1 + (pStart % Byte.SIZE);
290         int myPos = pStart / Byte.SIZE;
291 
292         /* If we have a short value */
293         if (myBits >= pLength) {
294             final int bitsToShift = myBits - pLength;
295             final int myMask = ((1 << pLength) - 1) << bitsToShift;
296             pBuffer[myPos] |= myMask;
297             return;
298         }
299 
300         /* Now look for the least significant bit */
301         final int myXtra = pLength - myBits - 1;
302         myPos += 1 + myXtra / Byte.SIZE;
303         myBits = 1 + myXtra % Byte.SIZE;
304 
305         /* Set starting value */
306         final int bitsToShift = Byte.SIZE - myBits;
307         int myMask = BYTEMASK << bitsToShift;
308         pBuffer[myPos] |= myMask;
309 
310         /* Look at remaining bits */
311         int myRemaining = pLength - myBits;
312 
313         /* Process whole bytes */
314         while (myRemaining >= Byte.SIZE) {
315             pBuffer[--myPos] = (byte) -1;
316             myRemaining -= Byte.SIZE;
317         }
318 
319         /* If we have remaining bits */
320         if (myRemaining > 0) {
321             myMask = (1 << myRemaining) - 1;
322             pBuffer[--myPos] |= myMask;
323         }
324     }
325 }