20 changed files with 808 additions and 356 deletions
-
8src/main/java/com/iflytop/gd/app/service/DeviceParamConfigService.java
-
6src/main/java/com/iflytop/gd/hardware/command/CommandHandler.java
-
19src/main/java/com/iflytop/gd/hardware/command/command_handler/FanHandler.java
-
2src/main/java/com/iflytop/gd/hardware/device/ServoMotor.java
-
2src/main/java/com/iflytop/gd/hardware/device/StepMotor.java
-
1src/main/java/com/iflytop/gd/hardware/drivers/WebSocketCommandBusImpl.java
-
53src/main/java/com/iflytop/gd/hardware/factory/A8kPacketFactory.java
-
227src/main/java/com/iflytop/gd/hardware/type/A8kPacket.java
-
2src/main/java/com/iflytop/gd/hardware/type/AppErrorCode.java
-
44src/main/java/com/iflytop/gd/hardware/type/CmdId.java
-
2src/main/java/com/iflytop/gd/hardware/type/CommandBus.java
-
18src/main/java/com/iflytop/gd/hardware/type/MId.java
-
2src/main/java/com/iflytop/gd/hardware/type/RegIndex.java
-
124src/main/java/com/iflytop/gd/hardware/utils/ByteArray.java
-
6src/test/java/com/iflytop/gd/infrastructure/drivers/WebSocketCommandBusImplTest.java
@ -0,0 +1,53 @@ |
|||||
|
package com.iflytop.gd.hardware.factory; |
||||
|
|
||||
|
|
||||
|
|
||||
|
import com.iflytop.gd.hardware.type.A8kPacket; |
||||
|
import com.iflytop.gd.hardware.type.CmdId; |
||||
|
|
||||
|
import java.util.List; |
||||
|
|
||||
|
public class A8kPacketFactory { |
||||
|
|
||||
|
//typedef struct { |
||||
|
// uint8_t packetType; |
||||
|
// uint16_t cmdid; |
||||
|
// uint8_t moduleId; |
||||
|
// uint8_t index; |
||||
|
// uint8_t datalen; |
||||
|
// uint8_t data[]; |
||||
|
// /* int8_t checksum;*/ |
||||
|
//} zcr_cmd_header_t; |
||||
|
|
||||
|
static public A8kPacket buildPacket(Integer moduleId, int packetType, Integer cmdId, Integer[] params) { |
||||
|
return A8kPacket.createPacket(moduleId, packetType, cmdId, params); |
||||
|
} |
||||
|
|
||||
|
static public A8kPacket buildCMDPacket(Integer moduleId, Integer cmdId, Integer[] params) { |
||||
|
return buildPacket(moduleId, (byte) 0, cmdId, params); |
||||
|
} |
||||
|
|
||||
|
static public A8kPacket buildCMDPacket(Integer moduleId, Integer cmdId, List<Integer> params) { |
||||
|
Integer[] array = new Integer[params.size()]; |
||||
|
params.toArray(array); |
||||
|
return buildPacket(moduleId, A8kPacket.PACKET_TYPE_CMD, cmdId, array); |
||||
|
} |
||||
|
|
||||
|
static public A8kPacket buildReportPacket(Integer moduleId, Integer cmdId, Integer[] params) { |
||||
|
return buildPacket(moduleId, (byte) 3, cmdId, params); |
||||
|
} |
||||
|
|
||||
|
// static public A8kPacket build_event_a8000_idcard_online() { |
||||
|
// return buildReportPacket(MId.A8kIdCardReader.toInt(), CmdId.event_a8000_idcard_online.index, new Integer[0]); |
||||
|
// } |
||||
|
// |
||||
|
// static public A8kPacket build_event_a8000_idcard_offline() { |
||||
|
// return buildReportPacket(MId.A8kIdCardReader.toInt(), CmdId.event_a8000_idcard_offline.index, new Integer[0]); |
||||
|
// } |
||||
|
|
||||
|
public static void main(String[] args) { |
||||
|
var packet = buildCMDPacket(1, CmdId.module_get_reg.toInt(), List.of(1, 2, 3)); |
||||
|
System.out.println(packet.toByteString()); |
||||
|
} |
||||
|
} |
||||
|
|
@ -0,0 +1,227 @@ |
|||||
|
package com.iflytop.gd.hardware.type; |
||||
|
|
||||
|
import com.iflytop.gd.hardware.utils.ByteArray; |
||||
|
import org.slf4j.Logger; |
||||
|
import org.slf4j.LoggerFactory; |
||||
|
import org.springframework.util.Assert; |
||||
|
|
||||
|
import java.nio.ByteBuffer; |
||||
|
import java.nio.ByteOrder; |
||||
|
|
||||
|
public class A8kPacket { |
||||
|
|
||||
|
//#pragma pack(push, 1) |
||||
|
//typedef struct { |
||||
|
// uint8_t packetType; |
||||
|
// uint16_t cmdid; |
||||
|
// uint8_t moduleId; |
||||
|
// uint16_t index; |
||||
|
// uint8_t datalen; |
||||
|
// uint8_t data[]; |
||||
|
// /* int8_t checksum;*/ |
||||
|
//} zcr_cmd_header_t; |
||||
|
// |
||||
|
//#pragma pack(pop) |
||||
|
//typedef enum { |
||||
|
// kptv2_cmd = 0xA0, |
||||
|
// kptv2_ack = 0xA1, |
||||
|
// kptv2_error_ack = 0xA2, |
||||
|
// kptv2_event = 0xA3, |
||||
|
//} zcan_cmd_packet_type_t; |
||||
|
// |
||||
|
|
||||
|
/** |
||||
|
* |
||||
|
* @WARNING |
||||
|
* 1. 修改这里时,需要注意连同createPacket一起修改 |
||||
|
* 2. PACKET_MIN_LEN 比Header多一个字节,是因为还有一个字节的校验位 |
||||
|
*/ |
||||
|
|
||||
|
public static final int PACKET_TYPE_OFFSET = 0; |
||||
|
public static final int CMDID_OFFSET = 1; |
||||
|
public static final int MODULE_ID_OFFSET = 3; |
||||
|
public static final int INDEX_OFFSET = 4; |
||||
|
public static final int DATA_LEN_OFFSET = 6; |
||||
|
public static final int DATA_OFFSET = 7; |
||||
|
|
||||
|
public static final int PACKET_MIN_LEN = 8;// |
||||
|
|
||||
|
public static final int CMD_OVERTIME = 1500; |
||||
|
|
||||
|
|
||||
|
public static final int PACKET_TYPE_CMD = 0xA0; |
||||
|
public static final int PACKET_TYPE_ACK = 0xA1; |
||||
|
public static final int PACKET_TYPE_ERROR_ACK = 0xA2; |
||||
|
public static final int PACKET_TYPE_EVENT = 0xA3; |
||||
|
|
||||
|
public static final Logger logger = LoggerFactory.getLogger(A8kPacket.class); |
||||
|
|
||||
|
byte[] raw; |
||||
|
|
||||
|
public A8kPacket(byte[] cmd) { |
||||
|
raw = new byte[cmd.length]; |
||||
|
System.arraycopy(cmd, 0, raw, 0, cmd.length); |
||||
|
} |
||||
|
|
||||
|
public void setPacketIndex(int packetIndex) { |
||||
|
ByteArray.setU16bit(raw, INDEX_OFFSET, packetIndex); |
||||
|
int checkcode = computeCheckcode(); |
||||
|
ByteArray.setU8(raw, raw.length - 1, checkcode); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public int getPacketIndex() { |
||||
|
return ByteArray.readU16bit(raw, INDEX_OFFSET); |
||||
|
} |
||||
|
|
||||
|
public int getCmdId() { |
||||
|
return ByteArray.readU16bit(raw, CMDID_OFFSET); |
||||
|
} |
||||
|
|
||||
|
public int getPacketType() { |
||||
|
return ByteArray.readU8bit(raw, PACKET_TYPE_OFFSET); |
||||
|
} |
||||
|
|
||||
|
public int getModuleId() { |
||||
|
return ByteArray.readU8bit(raw, MODULE_ID_OFFSET); |
||||
|
} |
||||
|
|
||||
|
public int getDataLen() { |
||||
|
return ByteArray.readU8bit(raw, DATA_LEN_OFFSET); |
||||
|
} |
||||
|
|
||||
|
public byte[] getCmdContent() { |
||||
|
if (raw.length < PACKET_MIN_LEN) { |
||||
|
return new byte[0]; |
||||
|
} |
||||
|
byte[] cmdcontent = new byte[getDataLen()]; |
||||
|
System.arraycopy(raw, DATA_OFFSET, cmdcontent, 0, getDataLen()); |
||||
|
return cmdcontent; |
||||
|
} |
||||
|
|
||||
|
public int getContentI32(int index) { |
||||
|
return ByteArray.read32bit(raw, DATA_OFFSET + index * 4); |
||||
|
} |
||||
|
|
||||
|
public int getCheckcode() { |
||||
|
return ByteArray.readU8bit(raw, raw.length - 1); |
||||
|
} |
||||
|
|
||||
|
public int computeCheckcode() { |
||||
|
int checkcode = 0; |
||||
|
for (int i = 0; i < raw.length - 1; i++) { |
||||
|
checkcode += raw[i]; |
||||
|
} |
||||
|
return checkcode & 0xFF; |
||||
|
} |
||||
|
|
||||
|
public String toByteString() { |
||||
|
return ByteArray.toByteString(raw); |
||||
|
} |
||||
|
|
||||
|
public String toString() { |
||||
|
int packetType = getPacketType(); |
||||
|
String ret = ""; |
||||
|
|
||||
|
CmdId cmdId = CmdId.valueOf(getCmdId()); |
||||
|
Assert.isTrue(cmdId != null, "cmdId is null"); |
||||
|
if (packetType == PACKET_TYPE_CMD) { |
||||
|
|
||||
|
if (cmdId.equals(CmdId.module_get_reg) || cmdId.equals(CmdId.module_set_reg)) { |
||||
|
RegIndex regIndex = RegIndex.valueOf(getContentI32(0)); |
||||
|
if (regIndex != null) { |
||||
|
ret = String.format("[CMD ] index:[%d] %s %s %s(%d) %d", getPacketIndex(), cmdId, |
||||
|
MId.valueOf(getModuleId()), regIndex, regIndex.index, getContentI32(1)); |
||||
|
} else { |
||||
|
ret = String.format("[CMD ] index:[%d] %s unkown_index(%d) %d", getPacketIndex(), cmdId, |
||||
|
getContentI32(0), getContentI32(1)); |
||||
|
} |
||||
|
} else { |
||||
|
if (cmdId.getCmdAttachType() == CmdId.ATTACH_IS_INT32) { |
||||
|
ret = String.format("[CMD ] index:[%d] (%s %s(%d) :param:[%s])", getPacketIndex(), cmdId, |
||||
|
MId.valueOf(getModuleId()), getModuleId(), formatInt32ATTACH(getCmdContent())); |
||||
|
} else { |
||||
|
ret = String.format("[CMD ] index:[%d] (%s %s(%d) :param:[%s])", getPacketIndex(), cmdId, |
||||
|
MId.valueOf(getModuleId()), getModuleId(), ByteArray.toByteString(getCmdContent())); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} else if (packetType == PACKET_TYPE_ACK) { |
||||
|
if (cmdId.getReceiptAttachType() == CmdId.ATTACH_IS_INT32) { |
||||
|
ret = String.format("[ACK ] index:[%d] (%s :[%s])", getPacketIndex(), cmdId, |
||||
|
formatInt32ATTACH(getCmdContent())); |
||||
|
} else { |
||||
|
ret = String.format("[ACK ] index:[%d] (%s :[%s])", getPacketIndex(), cmdId, |
||||
|
ByteArray.toByteString(getCmdContent())); |
||||
|
} |
||||
|
} else if (packetType == PACKET_TYPE_ERROR_ACK) { |
||||
|
ret = String.format("[EACK ] index:[%d] (%s :[%s])", getPacketIndex(), cmdId, (getContentI32(0))); |
||||
|
} else if (packetType == PACKET_TYPE_EVENT) { |
||||
|
if (cmdId.getCmdAttachType() == CmdId.ATTACH_IS_INT32) { |
||||
|
ret = String.format("[EVENT] index:[%d] (%s %s(%d) :[%s])", getPacketIndex(), cmdId, |
||||
|
MId.valueOf(getModuleId()), getModuleId(), formatInt32ATTACH(getCmdContent())); |
||||
|
} else { |
||||
|
ret = String.format("[EVENT] index:[%d] (%s %s(%d) :[%s])", getPacketIndex(), cmdId, |
||||
|
MId.valueOf(getModuleId()), getModuleId(), ByteArray.toByteString(getCmdContent())); |
||||
|
} |
||||
|
} else { |
||||
|
ret = String.format("Unknown packet type: %d", packetType); |
||||
|
} |
||||
|
return ret; |
||||
|
} |
||||
|
|
||||
|
private String formatInt32ATTACH(byte[] attach) { |
||||
|
StringBuilder ret = new StringBuilder(); |
||||
|
for (int i = 0; i < attach.length; i += 4) { |
||||
|
if (i + 3 >= attach.length) |
||||
|
break; |
||||
|
if (i != 0) |
||||
|
ret.append(","); |
||||
|
ret.append(String.format("%d", ByteArray.read32bit(attach, i))); |
||||
|
} |
||||
|
return ret.toString(); |
||||
|
} |
||||
|
|
||||
|
public Boolean isSupportPacket() { |
||||
|
CmdId cmdid = CmdId.valueOf(getCmdId()); |
||||
|
if (cmdid == null) { |
||||
|
return false; |
||||
|
} |
||||
|
if (CmdId.module_get_reg.equals(cmdid) || CmdId.module_set_reg.equals(cmdid)) { |
||||
|
if (getPacketType() == PACKET_TYPE_CMD) { |
||||
|
RegIndex regIndex = RegIndex.valueOf(getContentI32(0)); |
||||
|
return regIndex != null; |
||||
|
} |
||||
|
} |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
static public A8kPacket createPacket(Integer moduleId, int packetType, Integer cmdId, Integer[] params) { |
||||
|
int bufferSize = A8kPacket.PACKET_MIN_LEN + 4 * params.length; |
||||
|
ByteBuffer buffer = ByteBuffer.allocate(bufferSize); |
||||
|
buffer.order(ByteOrder.LITTLE_ENDIAN); |
||||
|
buffer.put((byte) (packetType & 0xff)); // packetType |
||||
|
buffer.putShort((short) (cmdId & 0xffff)); // cmdid |
||||
|
buffer.put((byte) (moduleId & 0xFF)); // moduleId |
||||
|
buffer.put((byte) 0x4C); // index |
||||
|
buffer.put((byte) 0x00); // index |
||||
|
buffer.put((byte) (params.length * 4)); // datalen |
||||
|
for (int value : params) { |
||||
|
buffer.putInt(value); |
||||
|
} |
||||
|
// int8_t checksum; |
||||
|
int checksum = 0; |
||||
|
for (int i = 0; i < bufferSize - 1; i++) { |
||||
|
checksum += buffer.get(i); |
||||
|
} |
||||
|
buffer.put((byte) checksum); |
||||
|
return new A8kPacket(buffer.array()); |
||||
|
} |
||||
|
|
||||
|
public static void main(String[] args) { |
||||
|
var packet = createPacket(41, A8kPacket.PACKET_TYPE_CMD, CmdId.module_stop.index, new Integer[]{}); |
||||
|
logger.info("{}", packet.toByteString()); |
||||
|
} |
||||
|
|
||||
|
} |
@ -1,4 +1,4 @@ |
|||||
package com.iflytop.gd.hardware.drivers; |
|
||||
|
package com.iflytop.gd.hardware.type; |
||||
|
|
||||
public enum AppErrorCode { |
public enum AppErrorCode { |
||||
APP_OK(200, "操作成功"), |
APP_OK(200, "操作成功"), |
@ -1,4 +1,4 @@ |
|||||
package com.iflytop.gd.hardware.drivers; |
|
||||
|
package com.iflytop.gd.hardware.type; |
||||
|
|
||||
import com.iflytop.gd.common.exception.CommandExecTimeoutException; |
import com.iflytop.gd.common.exception.CommandExecTimeoutException; |
||||
import com.iflytop.gd.common.exception.HardwareErrorException; |
import com.iflytop.gd.common.exception.HardwareErrorException; |
@ -1,4 +1,4 @@ |
|||||
package com.iflytop.gd.hardware.drivers; |
|
||||
|
package com.iflytop.gd.hardware.type; |
||||
|
|
||||
/** |
/** |
||||
* @brief 寄存器索引 |
* @brief 寄存器索引 |
@ -0,0 +1,124 @@ |
|||||
|
package com.iflytop.gd.hardware.utils; |
||||
|
|
||||
|
import org.springframework.lang.NonNull; |
||||
|
|
||||
|
public class ByteArray { |
||||
|
public ByteArray() { |
||||
|
} |
||||
|
|
||||
|
public static int readU8bit(byte[] code, int index) { |
||||
|
if (index >= code.length) |
||||
|
return 0; |
||||
|
return code[index] & 255; |
||||
|
} |
||||
|
|
||||
|
public static int readS8bit(byte[] code, int index) { |
||||
|
if (index >= code.length) |
||||
|
return 0; |
||||
|
|
||||
|
return code[index]; |
||||
|
} |
||||
|
|
||||
|
public static int readU16bit(byte[] code, int index) { |
||||
|
if (index + 1 >= code.length) |
||||
|
return 0; |
||||
|
return (code[index + 1] & 255) << 8 | code[index] & 255; |
||||
|
} |
||||
|
|
||||
|
public static void setU16bit(byte[] code, int index, int value) { |
||||
|
code[index + 1] = (byte) (value >> 8); |
||||
|
code[index] = (byte) value; |
||||
|
} |
||||
|
|
||||
|
public static void setU8(byte[] code, int off, int value) { |
||||
|
code[off] = (byte) value; |
||||
|
} |
||||
|
|
||||
|
public static int readS16bit(byte[] code, int index) { |
||||
|
if (index + 1 >= code.length) |
||||
|
return 0; |
||||
|
|
||||
|
return code[index + 1] << 8 | code[index] & 255; |
||||
|
} |
||||
|
|
||||
|
public static int read32bit(byte[] code, int index) { |
||||
|
if (index + 3 >= code.length) |
||||
|
return 0; |
||||
|
return code[index + 3] << 24 | (code[index + 2] & 255) << 16 | (code[index + 1] & 255) << 8 | code[index] & 255; |
||||
|
} |
||||
|
|
||||
|
public static Integer[] read32bitArray(byte[] code) { |
||||
|
int count = code.length / 4; |
||||
|
Integer[] array = new Integer[count]; |
||||
|
for (int i = 0; i < count; i++) { |
||||
|
array[i] = read32bit(code, i * 4); |
||||
|
} |
||||
|
return array; |
||||
|
} |
||||
|
|
||||
|
public static Integer[] read16bitArray(byte[] code) { |
||||
|
int count = code.length / 2; |
||||
|
Integer[] array = new Integer[count]; |
||||
|
for (int i = 0; i < count; i++) { |
||||
|
array[i] = readS16bit(code, i * 2); |
||||
|
} |
||||
|
return array; |
||||
|
} |
||||
|
|
||||
|
public static Integer[] readU16bitArray(byte[] code) { |
||||
|
int count = code.length / 2; |
||||
|
Integer[] array = new Integer[count]; |
||||
|
for (int i = 0; i < count; i++) { |
||||
|
array[i] = readU16bit(code, i * 2); |
||||
|
} |
||||
|
return array; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public static String toByteString(byte[] arrary) { |
||||
|
StringBuilder sb = new StringBuilder(); |
||||
|
for (byte b : arrary) { |
||||
|
sb.append(String.format("%02X", b)); |
||||
|
} |
||||
|
return sb.toString(); |
||||
|
} |
||||
|
|
||||
|
public static byte[] hexStringToBytes(@NonNull String str) { |
||||
|
if (str.isEmpty()) { |
||||
|
return new byte[0]; |
||||
|
} else { |
||||
|
byte[] byteArray = new byte[str.length() / 2]; |
||||
|
for (int i = 0; i < byteArray.length; i++) { |
||||
|
int high = Character.digit(str.charAt(i * 2), 16); |
||||
|
int low = Character.digit(str.charAt(i * 2 + 1), 16); |
||||
|
if (high == -1 || low == -1) { |
||||
|
return null; |
||||
|
} |
||||
|
byteArray[i] = (byte) (high * 16 + low); |
||||
|
} |
||||
|
return byteArray; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public static byte[] concat(byte[]... arrays) { |
||||
|
int length = 0; |
||||
|
for (byte[] array : arrays) { |
||||
|
length += array.length; |
||||
|
} |
||||
|
|
||||
|
byte[] result = new byte[length]; |
||||
|
int destPos = 0; |
||||
|
for (byte[] array : arrays) { |
||||
|
System.arraycopy(array, 0, result, destPos, array.length); |
||||
|
destPos += array.length; |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
// public static void main(String[] args) { |
||||
|
// byte[] bytes = new byte[]{0x01, 0x02, 0x03, 0x04}; |
||||
|
// System.out.println(toByteString(bytes)); |
||||
|
// } |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue