ro.ciprianpascu.sbus.util.BitVector Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of j2sbus Show documentation
Show all versions of j2sbus Show documentation
jamod is an object oriented implementation of the S-Bus protocol,
realized 100% in Java. It allows to quickly
realize master and slave applications in various transport flavors (IP
and serial).
The newest version!
/**
* Copyright 2002-2010 jamod development team
*
* 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 ro.ciprianpascu.sbus.util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class that implements a collection for
* bits, storing them packed into bytes.
* Per default the access operations will index from
* the LSB (rightmost) bit.
*
* @author Dieter Wimberger
* @author Ciprian Pascu
* @version %I% (%G%)
*/
public final class BitVector {
private static final Logger logger = LoggerFactory.getLogger(BitVector.class);
// instance attributes
private int m_Size;
private byte[] m_Data;
private boolean m_MSBAccess = false;
/**
* Constructs a new {@link BitVector} instance
* with a given size.
*
*
* @param size the number of bits the {@link BitVector}
* should be able to hold.
*/
public BitVector(int size) {
// store bits
m_Size = size;
// calculate size in bytes
if ((size % 8) > 0) {
size = (size / 8) + 1;
} else {
size = (size / 8);
}
m_Data = new byte[size];
}// constructor
/**
* Toggles the flag deciding whether the LSB
* or the MSB of the byte corresponds to the
* first bit (index=0).
*
* @param b true if LSB=0 up to MSB=7, false otherwise.
*/
public void toggleAccess(boolean b) {
m_MSBAccess = !m_MSBAccess;
}// toggleAccess
/**
* Tests if this {@link BitVector} has
* the LSB (rightmost) as the first bit
* (i.e. at index 0).
*
* @return true if LSB=0 up to MSB=7, false otherwise.
*/
public boolean isLSBAccess() {
return !m_MSBAccess;
}// isLSBAccess
/**
* Tests if this {@link BitVector} has
* the MSB (leftmost) as the first bit
* (i.e. at index 0).
*
* @return true if LSB=0 up to MSB=7, false otherwise.
*/
public boolean isMSBAccess() {
return m_MSBAccess;
}// isMSBAccess
/**
* Returns the {@link byte[]} which is used to store
* the bits of this {@link BitVector}.
*
*
* @return the {@link byte[]} used to store the bits.
*/
public final byte[] getBytes() {
return m_Data;
}// getBytes
/**
* Sets the {@link byte[]} which stores
* the bits of this {@link BitVector}.
*
*
* @param data a {@link byte[]}.
*/
public final void setBytes(byte[] data) {
System.arraycopy(data, 0, m_Data, 0, data.length);
}// setBytes
/**
* Sets the {@link byte[]} which stores
* the bits of this {@link BitVector}.
*
* @param data a byte[].
* @param size the number of bits to copy.
*/
public final void setBytes(byte[] data, int size) {
System.arraycopy(data, 0, m_Data, 0, data.length);
m_Size = size;
}// setBytes
/**
* Returns the state of the bit at the given index of this
* {@link BitVector}.
*
*
* @param index the index of the bit to be returned.
*
* @return true if the bit at the specified index is set,
* false otherwise.
*
* @throws IndexOutOfBoundsException if the index is out of bounds.
*/
public final boolean getBit(int index) throws IndexOutOfBoundsException {
index = translateIndex(index);
logger.trace("Get bit #{}", index);
return ((m_Data[byteIndex(index)] & (0x01 << bitIndex(index))) != 0) ? true : false;
}// getBit
/**
* Sets the state of the bit at the given index of
* this {@link BitVector}.
*
*
* @param index the index of the bit to be set.
* @param b true if the bit should be set, false if it should be reset.
*
* @throws IndexOutOfBoundsException if the index is out of bounds.
*/
public final void setBit(int index, boolean b) throws IndexOutOfBoundsException {
index = translateIndex(index);
logger.trace("Set bit #{}", index);
int value = ((b) ? 1 : 0);
int byteNum = byteIndex(index);
int bitNum = bitIndex(index);
m_Data[byteNum] = (byte) ((m_Data[byteNum] & ~(0x01 << bitNum)) | ((value & 0x01) << bitNum));
}// setBit
/**
* Returns the number of bits in this {@link BitVector}
* as {@link int}.
*
*
* @return the number of bits in this {@link BitVector}.
*/
public final int size() {
return m_Size;
}// size
/**
* Forces the number of bits in this {@link BitVector}.
*
* @param size the number of bits in this {@link BitVector}.
* @throws IllegalArgumentException if the size exceeds
* the byte[] store size multiplied by 8.
*/
public final void forceSize(int size) {
if (size > m_Data.length * 8) {
throw new IllegalArgumentException("Size exceeds byte[] store.");
} else {
m_Size = size;
}
}// forceSize
/**
* Returns the number of bytes used to store the
* collection of bits as {@link int}.
*
*
* @return the number of bits in this {@link BitVector}.
*/
public final int byteSize() {
return m_Data.length;
}// byteSize
/**
* Returns a {@link String} representing the
* contents of the bit collection in a way that
* can be printed to a screen or log.
*
* Note that this representation will ALLWAYS
* show the MSB to the left and the LSB to the right
* in each byte.
*
* @return a {@link String} representing this {@link BitVector}.
*/
@Override
public String toString() {
StringBuffer sbuf = new StringBuffer();
for (int i = 0; i < size(); i++) {
int idx = doTranslateIndex(i);
sbuf.append(((((m_Data[byteIndex(idx)] & (0x01 << bitIndex(idx))) != 0) ? true : false) ? '1' : '0'));
if (((i + 1) % 8) == 0) {
sbuf.append(" ");
}
}
return sbuf.toString();
}// toString
/**
* Returns the index of the byte in the the byte array
* that contains the given bit.
*
*
* @param index the index of the bit.
*
* @return the index of the byte where the given bit is stored.
*
* @throws IndexOutOfBoundsException if index is
* out of bounds.
*/
private final int byteIndex(int index) throws IndexOutOfBoundsException {
if (index < 0 || index >= m_Data.length * 8) {
throw new IndexOutOfBoundsException();
} else {
return index / 8;
}
}// byteIndex
/**
* Returns the index of the given bit in the byte
* where it it stored.
*
*
* @param index the index of the bit.
*
* @return the bit index relative to the position in the byte
* that stores the specified bit.
*
* @throws IndexOutOfBoundsException if index is
* out of bounds.
*/
private final int bitIndex(int index) throws IndexOutOfBoundsException {
if (index < 0 || index >= m_Data.length * 8) {
throw new IndexOutOfBoundsException();
} else {
return index % 8;
}
}// bitIndex
private final int translateIndex(int idx) {
if (m_MSBAccess) {
int mod4 = idx % 4;
int div4 = idx / 4;
if ((div4 % 2) != 0) {
// odd
return (idx + ODD_OFFSETS[mod4]);
} else {
// straight
return (idx + STRAIGHT_OFFSETS[mod4]);
}
} else {
return idx;
}
}// translateIndex
private static final int doTranslateIndex(int idx) {
int mod4 = idx % 4;
int div4 = idx / 4;
if ((div4 % 2) != 0) {
// odd
return (idx + ODD_OFFSETS[mod4]);
} else {
// straight
return (idx + STRAIGHT_OFFSETS[mod4]);
}
}// translateIndex
/**
* Factory method for creating a {@link BitVector} instance
* wrapping the given byte data.
*
* @param data a byte[] containing packed bits.
* @param size the number of bits in this {@link BitVector}.
* @return the newly created {@link BitVector} instance.
*/
public static BitVector createBitVector(byte[] data, int size) {
BitVector bv = new BitVector(data.length * 8);
bv.setBytes(data);
bv.m_Size = size;
return bv;
}// createBitVector
/**
* Factory method for creating a {@link BitVector} instance
* wrapping the given byte data.
*
* @param data a byte[] containing packed bits.
* @return the newly created {@link BitVector} instance.
*/
public static BitVector createBitVector(byte[] data) {
BitVector bv = new BitVector(data.length * 8);
bv.setBytes(data);
return bv;
}// createBitVector
/**
* Main method.
* @param args input arguments
*/
public static void main(String[] args) {
BitVector test = new BitVector(24);
System.out.println(test.isLSBAccess());
test.setBit(7, true);
System.out.println(test.getBit(7));
test.toggleAccess(true);
System.out.println(test.getBit(7));
test.toggleAccess(true);
test.setBit(6, true);
test.setBit(3, true);
test.setBit(2, true);
test.setBit(0, true);
test.setBit(8, true);
test.setBit(10, true);
System.out.println(test);
test.toggleAccess(true);
System.out.println(test);
test.toggleAccess(true);
System.out.println(test);
System.out.println(ModbusUtil.toHex(test.getBytes()));
}
private static final int[] ODD_OFFSETS = { -1, -3, -5, -7 };
private static final int[] STRAIGHT_OFFSETS = { 7, 5, 3, 1 };
}// class BitVector