I'm developing an application to communicate with a serialport device. The device itself is developed according to HART protocol.
Some documentation that I found related to this:
Packed ASCII is a subset of full ASCII and uses only 64 of the 256 possible characters. These 64 characters are the capitalized alphabet, numbers 0 through 9, and a few punctuation marks. Many HART parameters need only this limited ASCII set, which means that data can be compressed to 3/4 of normal.
The rule for converting from ASCII to Packed ASCII is just to remove bits 6 and 7 (two most significant).
The rules for conversion from packed ASCII back to ASCII are (1) set bit 7 = 0 and (2) set bit 6 = complement of packed ASCII bit 5.
So what I'm trying to do is get a value from the device, and later send it back, that is 6 bytes long and contains 8 characters and numbers. The value I get from unpacking is obviously incorrect. Don't know if the issue in this test is in the packing or unpacking. I'm not that familiar working with bytes so there might be some very obvious errors.
import java.nio.ByteBuffer;
import java.util.Arrays;
public class AsciiTest{
public static void main(String []args){
String text = "ABCDEF12";
byte[] bytesFromText = text.getBytes();
byte[] packed = packAscii(bytesFromText);
byte[] unpacked = unpackAscii(packed);
}
//Function to pack bytes from 8 byte to 6 byte
private static byte[] packAscii(byte[] bytes) {
byte[] shorten = new byte[6];
ByteBuffer packedAscii = ByteBuffer.wrap(shorten);
int index = 0;
for (int i = 0; i < bytes.length; i = i + 8) {
int result = (int)(
((bytes[index] & 0x3F) << 42) +
((bytes[index + 1] & 0x3F) << 36) +
((bytes[index + 2] & 0x3F) << 30) +
((bytes[index + 3] & 0x3F) << 24) +
((bytes[index + 4] & 0x3F) << 18) +
((bytes[index + 5] & 0x3F) << 12) +
((bytes[index + 6] & 0x3F) << 6) +
(bytes[index + 7] & 0x3F)
);
byte[] packedTemp = ByteBuffer.allocate(6).putInt(result).array();
for (int j = 0; j < 6; j++)
{
packedAscii.put(packedTemp[j]);
}
index += 8;
}
byte[] combined = packedAscii.array();
System.out.println(bytesToHex(combined)); // As hex string: "C41470920000"
return combined;
}
// Function to pack bytes from 8 byte to 6 byte
private static byte[] unpackAscii(byte[] bytes) {
byte[] slice = bytes;
byte[] nbytes = new byte[8];
byte[] first = new byte[1];
ByteBuffer buffer = ByteBuffer.wrap(nbytes);
buffer.put(first);
byte second = slice[0];
second = (byte)~second;
buffer.put(second);
buffer.put(slice);
byte[] combined = buffer.array();
String hex = bytesToHex(combined2);
System.out.println(hex); // As hex string: "003BC41470920000"
StringBuilder output = new StringBuilder();
for (int i = 0; i < hex.length(); i+=2) {
String str = hex.substring(i, i+2);
output.append((char)Integer.parseInt(str, 16));
}
System.out.println(output); // Output of string builder: ";Äp’"
return combined;
}
private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
}
EDIT: Should have started with this, but here's the data from device. From device packed
01001000
01010000
11001001
01000000
01011000
00110001
By hand, unpacked the bits and then checked what the characters are.
543210 7654 3210
010010 | 0101 0010 R
000101 | 0100 0101 E
000011 | 0100 0011 C
001001 | 0100 1001 I
010000 | 0101 0000 P
000101 | 0100 0101 E
100000 | 0010 0000 Space
110001 | 0011 0001 1
Byte array from the packed bytes [72, 80, -55, 64, 88, 49]
So assuming that I got the binary representation correct (which the actual word suggests), then at least I have correct idea what to do. I'll update the code when I get progress there.
And the application is made for Android phones.