ArduinoField.java
/*******************************************************************************
* jArduino: Arduino C++ Code Generation From Java
* Copyright 2020 Tony Washer
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package net.sourceforge.jarduino.util;
/**
* Field Parse/Set methods.
*/
public final class ArduinoField {
/**
* Byte mask.
*/
private static final int BYTEMASK = 0xFF;
/**
* Private constructor.
*/
private ArduinoField() {
}
/**
* Parse a littleEndian field.
* @param pBuffer the buffer to parse
* @param pStart the start bit
* @param pLength the bit length
* @param pSigned is the field signed?
* @return the parsed value
*/
public static long parseLEField(final byte[] pBuffer,
final int pStart,
final int pLength,
final boolean pSigned) {
/* Create the signing mask */
final long mySignMask = pSigned && (pLength < Long.SIZE) ? -(1L << pLength) : 0;
final long myTestMask = 1L << (pLength - 1);
/* Determine the byte that contains the most significant bit and the number of relevant bits */
final int myMSB = pStart + pLength - 1;
final int myBits = 1 + (myMSB % Byte.SIZE);
int myPos = myMSB / Byte.SIZE;
/* If we have a short value */
if (myBits >= pLength) {
final int bitsToShift = pStart % Byte.SIZE;
final long myValue = ((pBuffer[myPos] & BYTEMASK) >> bitsToShift) & ((1 << pLength) - 1);
return (myValue & myTestMask) == 0 ? myValue : myValue | mySignMask;
}
/* Access starting value */
long myValue = pBuffer[myPos] & ((1 << myBits) - 1);
/* Look at remaining bits */
int myRemaining = pLength - myBits;
/* Process whole bytes */
while (myRemaining >= Byte.SIZE) {
myValue <<= Byte.SIZE;
myValue += pBuffer[--myPos] & BYTEMASK;
myRemaining -= Byte.SIZE;
}
/* If we have remaining bits */
if (myRemaining > 0) {
myValue <<= myRemaining;
myValue += (pBuffer[--myPos] >> (Byte.SIZE - myRemaining)) & ((1 << myRemaining) - 1);
}
/* return the value */
return (myValue & myTestMask) == 0 ? myValue : myValue | mySignMask;
}
/**
* Parse a bigEndian field.
* @param pBuffer the buffer to parse
* @param pStart the start bit
* @param pLength the bit length
* @param pSigned is the field signed?
* @return the parsed value
*/
public static long parseBEField(final byte[] pBuffer,
final int pStart,
final int pLength,
final boolean pSigned) {
/* Create the signing mask */
final long mySignMask = pSigned && (pLength < Long.SIZE) ? -(1L << pLength) : 0;
final long myTestMask = 1L << (pLength - 1);
/* Determine the byte that contains the most significant bit and the number of relevant bits */
final int myBits = 1 + (pStart % Byte.SIZE);
int myPos = pStart / Byte.SIZE;
/* If we have a short value */
if (myBits >= pLength) {
final long myValue = ((pBuffer[myPos] & BYTEMASK) >> (myBits - pLength)) & ((1 << pLength) - 1);
return (myValue & myTestMask) == 0 ? myValue : myValue | mySignMask;
}
/* Access starting value */
long myValue = pBuffer[myPos] & ((1 << myBits) - 1);
/* Look at remaining bits */
int myRemaining = pLength - myBits;
/* Process whole bytes */
while (myRemaining >= Byte.SIZE) {
myValue <<= Byte.SIZE;
myValue += pBuffer[++myPos] & BYTEMASK;
myRemaining -= Byte.SIZE;
}
/* If we have remaining bits */
if (myRemaining > 0) {
myValue <<= myRemaining;
myValue += (pBuffer[++myPos] >> (Byte.SIZE - myRemaining)) & ((1 << myRemaining) - 1);
}
/* return the value */
return (myValue & myTestMask) == 0 ? myValue : myValue | mySignMask;
}
/**
* Set a littleEndian field.
* @param pBuffer the buffer to set
* @param pStart the start bit
* @param pLength the bit length
* @param pValue the value to set
*/
public static void setLEField(final byte[] pBuffer,
final int pStart,
final int pLength,
final long pValue) {
/* Determine the byte that contains the least significant bit and the number of relevant bits */
final int myBits = Byte.SIZE - (pStart % Byte.SIZE);
int myPos = pStart / Byte.SIZE;
/* If we have a short value */
if (myBits >= pLength) {
final int bitsToShift = pStart % Byte.SIZE;
final int myMask = ((1 << pLength) - 1) << bitsToShift;
pBuffer[myPos] &= ~myMask;
pBuffer[myPos] |= (pValue << bitsToShift) & myMask;
return;
}
/* Set starting value */
final int bitsToShift = Byte.SIZE - myBits;
int myMask = BYTEMASK << bitsToShift;
pBuffer[myPos] &= ~myMask;
pBuffer[myPos] |= (pValue << bitsToShift) & myMask;
/* Look at remaining bits */
int myRemaining = pLength - myBits;
long myValue = pValue >> myBits;
/* Process whole bytes */
while (myRemaining >= Byte.SIZE) {
pBuffer[++myPos] = (byte) myValue;
myRemaining -= Byte.SIZE;
myValue >>= Byte.SIZE;
}
/* If we have remaining bits */
if (myRemaining > 0) {
myMask = (1 << myRemaining) - 1;
pBuffer[++myPos] &= ~myMask;
pBuffer[myPos] |= myValue & myMask;
}
}
/**
* Set a bigEndian field.
* @param pBuffer the buffer to set
* @param pStart the start bit
* @param pLength the bit length
* @param pValue the value to set
*/
public static void setBEField(final byte[] pBuffer,
final int pStart,
final int pLength,
final long pValue) {
/* Determine the byte that contains the most significant bit and the number of relevant bits */
int myBits = 1 + (pStart % Byte.SIZE);
int myPos = pStart / Byte.SIZE;
/* If we have a short value */
if (myBits >= pLength) {
final int bitsToShift = myBits - pLength;
final int myMask = ((1 << pLength) - 1) << bitsToShift;
pBuffer[myPos] &= ~myMask;
pBuffer[myPos] |= (pValue << bitsToShift) & myMask;
return;
}
/* Now look for the least significant bit */
final int myXtra = pLength - myBits - 1;
myPos += 1 + myXtra / Byte.SIZE;
myBits = 1 + myXtra % Byte.SIZE;
/* Set starting value */
final int bitsToShift = Byte.SIZE - myBits;
int myMask = BYTEMASK << bitsToShift;
pBuffer[myPos] &= ~myMask;
pBuffer[myPos] |= (pValue << bitsToShift) & myMask;
/* Look at remaining bits */
int myRemaining = pLength - myBits;
long myValue = pValue >> myBits;
/* Process whole bytes */
while (myRemaining >= Byte.SIZE) {
pBuffer[--myPos] = (byte) myValue;
myRemaining -= Byte.SIZE;
myValue >>= Byte.SIZE;
}
/* If we have remaining bits */
if (myRemaining > 0) {
myMask = (1 << myRemaining) - 1;
pBuffer[--myPos] &= ~myMask;
pBuffer[myPos] |= myValue & myMask;
}
}
/**
* Set a littleEndian bitMap for field.
* @param pBuffer the buffer to set
* @param pStart the start bit
* @param pLength the bit length
*/
public static void setLEFieldBits(final byte[] pBuffer,
final int pStart,
final int pLength) {
/* Determine the byte that contains the least significant bit and the number of relevant bits */
final int myBits = Byte.SIZE - (pStart % Byte.SIZE);
int myPos = pStart / Byte.SIZE;
/* If we have a short value */
if (myBits >= pLength) {
final int bitsToShift = pStart % Byte.SIZE;
final int myMask = ((1 << pLength) - 1) << bitsToShift;
pBuffer[myPos] |= myMask;
return;
}
/* Set starting value */
final int bitsToShift = Byte.SIZE - myBits;
int myMask = BYTEMASK << bitsToShift;
pBuffer[myPos] |= myMask;
/* Look at remaining bits */
int myRemaining = pLength - myBits;
/* Process whole bytes */
while (myRemaining >= Byte.SIZE) {
pBuffer[++myPos] = (byte) -1;
myRemaining -= Byte.SIZE;
}
/* If we have remaining bits */
if (myRemaining > 0) {
myMask = (1 << myRemaining) - 1;
pBuffer[++myPos] |= myMask;
}
}
/**
* Set a bigEndian bitMap for field.
* @param pBuffer the buffer to set
* @param pStart the start bit
* @param pLength the bit length
*/
public static void setBEFieldBits(final byte[] pBuffer,
final int pStart,
final int pLength) {
/* Determine the byte that contains the most significant bit and the number of relevant bits */
int myBits = 1 + (pStart % Byte.SIZE);
int myPos = pStart / Byte.SIZE;
/* If we have a short value */
if (myBits >= pLength) {
final int bitsToShift = myBits - pLength;
final int myMask = ((1 << pLength) - 1) << bitsToShift;
pBuffer[myPos] |= myMask;
return;
}
/* Now look for the least significant bit */
final int myXtra = pLength - myBits - 1;
myPos += 1 + myXtra / Byte.SIZE;
myBits = 1 + myXtra % Byte.SIZE;
/* Set starting value */
final int bitsToShift = Byte.SIZE - myBits;
int myMask = BYTEMASK << bitsToShift;
pBuffer[myPos] |= myMask;
/* Look at remaining bits */
int myRemaining = pLength - myBits;
/* Process whole bytes */
while (myRemaining >= Byte.SIZE) {
pBuffer[--myPos] = (byte) -1;
myRemaining -= Byte.SIZE;
}
/* If we have remaining bits */
if (myRemaining > 0) {
myMask = (1 << myRemaining) - 1;
pBuffer[--myPos] |= myMask;
}
}
}