net.wimpi.modbus.util.BitVector Maven / Gradle / Ivy
Show all versions of jamod Show documentation
/***
* 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 net.wimpi.modbus.util;
/**
* 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
* @version 1.2 (@date@)
*/
public final class BitVector {
//instance attributes
private int m_Size;
private byte[] m_Data;
private boolean m_MSBAccess = false;
/**
* Constructs a new BitVector instance
* with a given size.
*
* @param size the number of bits the 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).
*/
public void toggleAccess() {
m_MSBAccess = !m_MSBAccess;
}//toggleAccess
/**
* 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 = b;
}//toggleAccess
/**
* Tests if this 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 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 byte[] which is used to store
* the bits of this BitVector.
*
* @return the byte[] used to store the bits.
*/
public final byte[] getBytes() {
return m_Data;
}//getBytes
/**
* Sets the byte[] which stores
* the bits of this BitVector.
*
* @param data a byte[].
*/
public final void setBytes(byte[] data) {
System.arraycopy(data, 0, m_Data, 0, data.length);
}//setBytes
/**
* Sets the byte[] which stores
* the bits of this BitVector.
*
* @param data a byte[].
*/
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
* 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);
//System.out.println("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 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);
//System.out.println("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 BitVector
* as int.
*
* @return the number of bits in this BitVector.
*/
public final int size() {
return m_Size;
}//size
/**
* Forces the number of bits in this BitVector.
*
* @param size
* @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 int.
*
* @return the number of bits in this BitVector.
*/
public final int byteSize() {
return m_Data.length;
}//byteSize
/**
* Returns a 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 String representing this BitVector.
*/
public String toString() {
StringBuffer sbuf = new StringBuffer();
for (int i = 0; i < size(); i++) {
sbuf.append(
((((m_Data[byteIndex(i)]
& (0x01 << bitIndex(i))) != 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
/**
* Factory method for creating a BitVector instance
* wrapping the given byte data.
*
* @param data a byte[] containing packed bits.
* @return the newly created 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 BitVector instance
* wrapping the given byte data.
*
* @param data a byte[] containing packed bits.
* @return the newly created BitVector instance.
*/
public static BitVector createBitVector(byte[] data) {
BitVector bv = new BitVector(data.length * 8);
bv.setBytes(data);
return bv;
}//createBitVector
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