将压缩的ascii转换为ascii并返回



我正在开发一个与串行端口设备通信的应用程序。设备本身是根据HART协议开发的。

我发现的一些与此相关的文档:

压缩ASCII是完整ASCII的子集,仅使用256个可能字符中的64个。这64个字符是大写字母表、数字0到9以及一些标点符号。许多HART参数只需要这个有限的ASCII集,这意味着数据可以压缩到正常值的3/4。

从ASCII转换为压缩ASCII的规则只是删除位6和7(两个最高有效位(
从压缩ASCII转换回ASCII的规则是(1(设置位7=0和(2(设置位6=压缩ASCII位5的补码。

所以我要做的是从设备中获取一个值,然后将其发送回,该值长6字节,包含8个字符和数字。我从开箱中得到的值显然不正确。不知道这次测试的问题是在包装还是开箱方面。我不太熟悉处理字节,所以可能会有一些非常明显的错误。

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);
}
}

编辑:应该从这个开始,但这是来自设备的数据。来自设备包装

01001000
01010000
11001001
01000000
01011000
00110001

用手打开这些位,然后检查字符是什么。

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

压缩字节[72,80,-55,64,88,49]的字节数组

因此,假设我得到了正确的二进制表示(实际单词表明了这一点(,那么至少我对该做什么有正确的想法。当我在那里取得进展时,我会更新代码。

该应用程序是为安卓手机制作的。

我并没有检查代码中的实际问题,而是决定从头开始实现。溶液有效,但可能不太干净。

因此,在打包模式中,得到的第一个字节包含第一个未打包字节的6位+第二个未打包的字节的2个低位(因此左移6(
第二个结果字节包含第二个未封装字节的4个高位(因此向右移动2(加上第三个未封装的字节的4位低位(因此向左移动4(
最后,第三个结果字节包括第三个已封装字节的2个高位(向右移动6(加上向左移动2的第四个已封装的字节。

在拆包模式下,过程相反。

对于打包模式,可以从每个字节中减去32,并且在拆包时,将该常数加回来,从而使AB。。CCD_ 3可以适当地适合于6个比特。

更新
可以省略32的减法,并且有另一种方法可以恢复";丢失";当通过添加CCD_ 5来对低于CCD_。

因此,包装方法如下:

private static byte[] packAscii(byte[] unpacked) {
for (int i = 0; i < unpacked.length; i++) {
// unpacked[i] = (byte)((unpacked[i] - 32) &0x3F);
unpacked[i] = (byte)(unpacked[i] & 0x3F); // keep 6 lower bits as is
}
int size = (int) Math.ceil(unpacked.length * 3.0 / 4.0);
byte[] result = new byte[size];
// i - index of input unpacked array, r - index of result packed array 
for (int i = 0, r = 0; i < unpacked.length;) {
for (int j = 0; j < 4 && i < unpacked.length; j++, i++, r++) {
int rightShift = j * 2;
int leftShift = (8 - rightShift) % 8;
switch(j) {
case 0:
result[r]  = unpacked[i];
break;
case 1:
case 2:
result[r-1] |= (byte)(unpacked[i] << leftShift);
result[r]  = (byte)(unpacked[i] >> rightShift);
break;
case 3:
result[r-1] |= (byte)(unpacked[i] << leftShift);
break;
}
}
r--; // correction for the last packed byte
}
System.out.println("packed =" + printArr(result));
return result;
}

开箱方法如下:

final static int[][] masks = {
{0x3F, 0x3F},
{0x03, 0x3C},
{0x0F, 0x30},
{0x3F, 0x3F}
};
private static byte[] unpackAscii(byte[] packed) {
int size = (int) Math.floor(packed.length * 4.0 / 3.0);
byte[] result = new byte[size];
System.out.println("unpacked size=" + size);
for (int i = 0, r = 0; i < packed.length;) { // r index of unpacked array, i - packed
for (int j = 0, rightShift = 6; j < 3 && i < packed.length; i++, j++, r++, rightShift -= 2) {
int mask = masks[j][1];
int leftShift = j * 2;

if (j == 0) {
result[r]  = (byte)(packed[i] & mask);
} else {
result[r] |= (byte)((packed[i] << leftShift) & mask);
}

if (r < size - 1) {
mask = masks[j + 1][0];
result[r + 1] = (byte)((packed[i] >> rightShift) & mask);
}
}
r++; // correction for the last packed byte
}    
for (int i = 0; i < result.length; i++) {
// result[i] += 32;  // restore after unpacking // previous implementation
if (result[i] < 0x20) {
result[i] += 0x40; // restore 6 bit for letters
}
}
return result;
}
static String printArr(byte[] arr) {
return IntStream.range(0, arr.length)
.mapToObj(i -> "0x" + Integer.toHexString(arr[i] & 0xFF).toUpperCase())
.collect(Collectors.joining(" "));
}

测试:

String text = "ABCDEFGH12";
System.out.println(text);
byte[] bytesFromText = text.getBytes();
byte[] packed = packAscii(bytesFromText);
byte[] unpacked = unpackAscii(packed);
System.out.println(new String(unpacked));

输出

ABCDEFGH12
packed =[-95, 56, -110, -91, 121, -94, -111, 4]
unpacked size=10
ABCDEFGH12

更新
对新模式使用测试字RECIPE 1

RECIPE 1
packed =0x52 0x31 0x24 0x50 0x1 0xC6
unpacked size=8
RECIPE 1

update2
以下实现支持问题中提到的格式(但是,未针对8以外的其他大小的未打包数据进行测试(

private static byte[] packAscii(byte[] unpacked) {
long tmp = 0;
for (int i = 0, shift = (unpacked.length - 1) * 6; i < unpacked.length; i++, shift -= 6) {
tmp += ((long)unpacked[i] & 0x3F) << shift;
}

int size = (int) Math.ceil(unpacked.length * 3.0 / 4.0);
byte[] result = new byte[size];
for (int i = size - 1; i >= 0; i--) {
result[i] = (byte) (tmp & 0xFF);
tmp >>= 8;
}
System.out.println("packed =" + printArr(result));
return result;
}
private static byte[] unpackAscii(byte[] packed) {
int size = (int) Math.floor(packed.length * 4.0 / 3.0);
byte[] result = new byte[size];
System.out.println("unpacked size=" + size);
long tmp = 0;
for (int i = 0; i < packed.length; i++) {
tmp <<= 8;
tmp |= ((int)packed[i]) & 0xFF;    
}
for (int i = size - 1; i >= 0; i--) {
result[i] = (byte)(tmp & 0x3F);
if (result[i] < 0x20)
result[i] += 0x40;
tmp >>= 6;
}

return result;
}

测试成功

String text = "RECIPE 1";
System.out.println(text);
byte[] bytesFromText = text.getBytes();
byte[] packed = packAscii(bytesFromText);
byte[] unpacked = unpackAscii(packed);
System.out.println(new String(unpacked));

输出

RECIPE 1
packed =0x48 0x50 0xC9 0x40 0x58 0x31
unpacked size=8
RECIPE 1

相关内容

  • 没有找到相关文章

最新更新