I have an char array containing hex value. It contains 6 bytes. I have calculated the crc of these 6 bytes and the function returns int value.
This is the code.
char buffer[] = {0x01,0x05,0x00,0x06,0x00,0x00};
byte[] bufferbyte = new String(buffer).getBytes();
for (byte bb : bufferbyte){
System.out.format("0X%x ", bb);
}
int crcresult;
crcresult = CRC16(buffer,6); //crc calculation
byte[] crc_bytes = ByteBuffer.allocate(4).putInt(crcresult).array();
for (byte b : crc_bytes){
System.out.format("0X%x ", b);
}
My question are
I have used bytebuffer to convert crc obtained as int into byte. But the calculated crc are stored in 4 byte instead of 2 byte. I have calculated CRC 16 but the resulting crc is 32 bit . I think it is because i have returned "int" in the crc calculation and it is written that in java an int is 32 bits.
So How to extract only two bytes from the byte buffer (crc_bytes) or the calculated int crc (crcresult).
I have put the bytes of the "char buffer[]" and two bytes of calculated crc in single byte array. How can we append
char buffer[] and crcresult
in one byte array.
The output of above code is
0X1 0X5 0X0 0X6 0X0 0X0 0X0 0X0 0X2d 0Xcb
Where first 6 bytes are bytes converted from char array and last 4 bytes are crc.
The two bytes of the crc in big endian order can be fetched with
byte[] crc_result = new byte[2];
crc_bytes[0] = (byte)(crcresult >> 8); // this are the high order 8 bits
crc_bytes[1] = (byte)crcresult; // this are the low order 8 bits
If you need it in little endian order just adapt the assignments accordingly.
It is not clear to me why you use a char array to represent bytes.
Yes, crcresult is 32 bits because it is of type int. If you want a 16bit data type, use short instead.
But, using int type does not do any harm. Although it is 32 bit, only last 16 bits will contain CRC16 value. You can extract those two bytes with following bitwise operations.
byte byte1 = (byte)((crcresult >> 8) & 0xFF); // first 8 bits of last 16 bits
byte byte0 = (byte)(crcresult & 0xFF); // last 8 bits
To merge the results.
byte[] merged = new byte[bufferbyte.length + 2];
System.arrayCopy(bufferbyte, 0, merged, 0, bufferbyte.length); // copy original data buffer
merged[bufferbyte.length ] = byte1; // append crc16 byte 1
merged[bufferbyte.length + 1] = byte0; // append crc16 byte 2
Refer System.arrayCopy for more details.
Related
For my LZW compression code. I chose to store the codes in 9-bit codes, dictionary size will be 512, so there will be room for only 256 new
symbols. Now I feel like I didn't choose the right buffer for the job:
byte[] buffer = new byte[3];
This buffer is more suited to store for 12 bits, what is the equivalent for 9 bits and how can I store the 9 bits in the buffer correctly?
I used this to store 8 bits in buffer[0] and 4 bits in buffer[1]. What is the equivalent for 9 bits?
buffer[0] = (byte) (code & 255);
buffer[1] = (byte) ((code >> 8) << 4);
Nine is a hard bit count to work with. First question would be: Can you work in 8 bits?
Assuming not, I'd look at allocating at the dictionary level and packing your 9-bit words in without paying attention to byte boundaries. A 512 byte dictionary = 4096 bits = 455 9-bit symbols. You just need some math to access those symbols from your bitstream:
byte[] buffer = new byte[512];
function getWord(int wordOfs) {
// Gets wordOfs'th 9-bit symbol from buffer, For buffer of 512 bytes, wordOfs = 0 -> 454
if (wordOfs<0 || wordOfs>454) throw InvalidArgumentException;
int bitsOfs = wordOfs * 9; // Offset (in bits) of the desired 9 bit word
int idx = bitsOfs / 8; // buffer[idx] contains bit 0 of the desired word
int ofs = bitsOfs % 8; // ... shifted this many places to the right
// Grab at least 8 bits beyond the calculated starting point
unsigned word val = buffer[idx] | (buffer[idx+1]>>8);
// Shift and mask it down to the desired 9 bits for return
return (val << ofs) & 0x01FF;
}
Caveat: I don't have access to a Java compiler right now, syntax may need work.
How can I convert an integer between 0 and 65k to fixed length of two bytes? as an example
2 would be 00000000 00000010
~65k would be 11111111 11111111
and all that in a byte array
java has the short data type, this is a 2 bytes integer. You cast the integer to short.
int a = 1;
short b = (short)a;
If you want the bytes of the integer you can use ByteBuffer
byte[] bytes = ByteBuffer.allocate(2).putShort((short)intnumber).array();
Or if you want the binary format you can just use toBinaryString method of the Integer.
int x = 2;
System.out.println(Integer.toBinaryString(x));
When x is your number between 0 and 65,535 just use
new byte[] { (byte) (x >> 8), (byte) x }
to create a byte array containing the value as two bytes in big-endian format.
In my C++ code, I need to convert an int and put it inside a byte. I represent a byte using a char.
In my java code, I should read this byte (it is sent over the network), and I should get the appropriate int from that byte (the one that I sent).
I should mention that this byte is less than 15, so one byte would be sufficient for it
However, the Java code is reading negative numbers in some attempts, and when I tried other ways it gave me totally different numbers. I suspect it is a problem of big/little endian.
What I've tried:
// C++
char bytes[255];
bytes[0] = myInt; // attempt 1
bytes[0] = myInt & 0xFF; // attempt 2
// ... send the byte array over the network
// JAVA
// receive the byte
int readInt = bytes[0]; //attempt 1
int readInt = bytes[0] & 0xFF; // attempt2
How should I properly do this, given that the two applications (C++ side and JAVA side) will run on the same ubuntu machine?
Note: it's never an endian issue. Only if you work low level or make your own arrays of bytes to represent one number, it may be an endian issue.
It is only one byte now, so no endian issue.
Try to use unsigned int.
Further edit: int readInt = bytes[0] & 0xFF should work.
for (int i = 0; i < 256; i++) {
byte b = (byte) i;
int j = b & 0xFF;
System.out.println("The byte is " + b + " and the int is " + j);
}
Gives:
The byte is 0 and the int is 0
The byte is 1 and the int is 1
...
The byte is 126 and the int is 126
The byte is 127 and the int is 127
The byte is -128 and the int is 128
The byte is -127 and the int is 129
...
The byte is -2 and the int is 254
The byte is -1 and the int is 255
Edit (after comment above): 7 = 0000 0111 and -32 = 1110 0000 (= 224 as int) The issue appears to be some kind of mirroring flip.
and 170 = 1010 1010 (= -86 as Java byte) which doesn't make sense to me because how did 3 on bits turn into 4 and spread out.
I have to do following things
append 2 bytes in hex at the end of the char array containing 4 bytes , so the resultant is 6 byte.
Convert the above 6 byte byte array to char array to pass it to function crcresult. (the function only accept char array).
Finally merge the crc 2 byte at the end of the 6 byte.
I have tested the following program in separate java class and it worked.
public class CharBytetest
{
public static void main(String[] args)
{
char charbuffer1[] = {0x01,0x05,0x00,0x03};
byte[] bufferbyte1 = new String(charbuffer1).getBytes();// converts chararray to byte array
byte byte4 = (byte)0xFF;
byte byte5 = (byte)0x00;
byte[] bufferbytemerge1 = new byte[bufferbyte1.length+2];
System.arraycopy(bufferbyte1, 0, bufferbytemerge1, 0, bufferbyte1.length);
bufferbytemerge1[bufferbyte1.length]= byte4;
bufferbytemerge1[bufferbyte1.length +1 ]= byte5;
//bufferbytemerge1 contains 6 byte (charbuffer1 + byte4 + byte5 )
String str = new String(bufferbytemerge1);
//bufferbytemerge1 converted to char array
char[] charbuffer2 = str.toCharArray();
byte[] bufferbyte2 = new String(charbuffer2).getBytes();
int crcresult;
//char array sent to crc function
crcresult = CalculateCRC.CRC16(charbuffer2,6);
byte byte1 = (byte)((crcresult >> 8) & 0xFF); // first 8 bits of last 16 bits
byte byte0 = (byte)(crcresult & 0xFF); // last 8 bits
byte[] bufferbytemerge2 = new byte[bufferbyte2.length + 2];
System.arraycopy(bufferbyte2, 0, bufferbytemerge2, 0, bufferbyte2.length);// copy original data stored in bytebuffer
bufferbytemerge2[bufferbyte2.length] = byte1; // append crc16 byte 1
bufferbytemerge2[bufferbyte2.length + 1] = byte0; // append crc16 byte 2
//bufferbytemerge2 contains total 8 bytes
for (byte b : bufferbytemerge2){
System.out.format("0X%x ", b);
}
}
}
The output seen is
0X1 0X5 0X0 0X3 0Xff 0X0 0X7c 0X3a
But my problem when i implemented the above thing to send "bufferbytemerge2" in the serial port specifically modbus, conversion error is seen as
java.lang.ArraIndexOutOfBoundsException : 65454
at com.wexsnet.wesModbus.comm.req.CalculateCRC.crc16 <CalculateCRC.java:59>
I tried to analyse byte obtained at each step and it seemed that problem is at step2. ie when bufferbytemerge1 is converted to char array.
As per the above code , "bufferbyte2" should contain 01 05 00 03 FF 00 but when i try to send "bufferbyte2" it is sending 01 05 00 03 ef bf bf 00
So is it because conversion of "bufferbytemerge1" byte array to char array "charbuffer2" is not correct . or conversion of "charbuffer2" char array to byte array "bufferbyte2" is not correct. Please help how can we convert it correctly.
Do not use char to hold a byte value in Java. I realize that is standard practice in C, but in Java bytes belong in byte arrays only.
Every time you convert bytes to a String or convert a String to bytes, you are using the encoder or decoder of a Charset. In many Charsets (including UTF-8, which is what your system apparently uses), not every byte value can be converted to a character; such bytes will be discarded or replaced with some default number. And in many Charsets, some characters do not correspond to a single byte, but rather to multiple bytes, which is where your ef bf bf is coming from.
That is why your use of new String(byte[]) and String.getByes() is corrupting your data.
Do not use char arrays. Do not convert bytes to or from Strings. Use only byte arrays to hold bytes.
If you want to convert a byte array to an array of 16-bit values, use ByteBuffer to convert it to a short array:
short[] sixteenBitValues = new short[byteArray.length / 2];
ByteBuffer.wrap(byteArray).asShortBuffer().get(sixteenBitValues);
In general, if you want to append bytes to a byte array, you should use a ByteBuffer:
ByteBuffer buffer = ByteBuffer.allocate(oldByteArray.length + 2);
buffer.put(oldByteArray);
buffer.asShortBuffer().put(crcresult);
byte[] newByteArray = buffer.array();
If your CRC16 method will only operate on a char array, you need to avoid using String, or any other method that will invoke a Charset encoding, and force the bytes to char values yourself:
char[] charBuffer2 = new char[byteBuffer.length];
for (int i = 0; i < byteBuffer.length; i++) {
charBuffer2[i] = (char) (byteBuffer[i] & 0xff);
}
It sounds like your CRC16 method is making the C-based assumption that char holds a single byte, so if you have any control over that class, you should change it to accept a byte[] argument.
I have binary string String A = "1000000110101110". I want to convert this string into byte array of length 2 in java
I have taken the help of this link
I have tried to convert it into byte by various ways
I have converted that string into decimal first and then apply the code to store into the byte array
int aInt = Integer.parseInt(A, 2);
byte[] xByte = new byte[2];
xByte[0] = (byte) ((aInt >> 8) & 0XFF);
xByte[1] = (byte) (aInt & 0XFF);
System.arraycopy(xByte, 0, record, 0,
xByte.length);
But the values get store into the byte array are negative
xByte[0] :-127
xByte[1] :-82
Which are wrong values.
2.I have also tried using
byte[] xByte = ByteBuffer.allocate(2).order(ByteOrder.BIG_ENDIAN).putInt(aInt).array();
But it throws the exception at the above line like
java.nio.Buffer.nextPutIndex(Buffer.java:519) at
java.nio.HeapByteBuffer.putInt(HeapByteBuffer.java:366) at
org.com.app.convert.generateTemplate(convert.java:266)
What should i do now to convert the binary string to byte array of 2 bytes?Is there any inbuilt function in java to get the byte array
The answer you are getting
xByte[0] :-127
xByte[1] :-82
is right.
This is called 2's compliment Represantation.
1st bit is used as signed bit.
0 for +ve
1 for -ve
if 1st bit is 0 than it calculates as regular.
but if 1st bit is 1 than it deduct the values of 7 bit from 128 and what ever the answer is presented in -ve form.
In your case
1st value is10000001
so 1(1st bit) for -ve and 128 - 1(last seven bits) = 127
so value is -127
For more detail read 2's complement representation.
Use putShort for putting a two byte value. int has four bytes.
// big endian is the default order
byte[] xByte = ByteBuffer.allocate(2).putShort((short)aInt).array();
By the way, your first attempt is perfect. You can’t change the negative sign of the bytes as the most significant bit of these bytes is set. That’s always interpreted as negative value.
10000001₂ == -127
10101110₂ == -82
try this
String s = "1000000110101110";
int i = Integer.parseInt(s, 2);
byte[] a = {(byte) ( i >> 8), (byte) i};
System.out.println(Arrays.toString(a));
System.out.print(Integer.toBinaryString(0xFF & a[0]) + " " + Integer.toBinaryString(0xFF & a[1]));
output
[-127, -82]
10000001 10101110
that is -127 == 0xb10000001 and -82 == 0xb10101110
Bytes are signed 8 bit integers. As such your result is completely correct.
That is: 01111111 is 127, but 10000000 is -128. If you want to get numbers in 0-255 range you need to use a bigger variable type like short.
You can print byte as unsigned like this:
public static String toString(byte b) {
return String.valueOf(((short)b) & 0xFF);
}