diff --git a/src/main/java/com/iflytop/gd/common/notification/Notification.java b/src/main/java/com/iflytop/gd/common/notification/Notification.java index baddb65..724b0ee 100644 --- a/src/main/java/com/iflytop/gd/common/notification/Notification.java +++ b/src/main/java/com/iflytop/gd/common/notification/Notification.java @@ -10,13 +10,26 @@ import lombok.Getter; @Getter public class Notification { + private final String commandId; + private final String command; private final String level; - private final String content; + private final String title; + private String content = null; private final String dateTime = DateTime.now().toString("yyyy/MM/dd HH:mm:ss"); - private Notification(String level, String content) { + private Notification(String commandId, String command, String level, String title, String content) { + this.commandId = commandId; this.level = level; + this.title = title; this.content = content; + this.command = command; + } + + private Notification(String commandId, String command, String level, String title) { + this.commandId = commandId; + this.level = level; + this.title = title; + this.command = command; } /** @@ -24,8 +37,8 @@ public class Notification { * @param content 通知内容 * @return 通知实例 */ - public static Notification infoNotification(String content) { - return new Notification("info", content); + public static Notification infoNotification(String commandId, String command, String title, String content) { + return new Notification(commandId, command, "info", title, content); } @@ -34,8 +47,8 @@ public class Notification { * @param content 通知内容 * @return 通知实例 */ - public static Notification warnNotification(String content) { - return new Notification("warn", content); + public static Notification warnNotification(String commandId, String command, String title, String content) { + return new Notification(commandId, command, "warn", title, content); } /** @@ -43,8 +56,8 @@ public class Notification { * @param content 通知内容 * @return 通知实例 */ - public static Notification errorNotification(String content) { - return new Notification("error", content); + public static Notification errorNotification(String commandId, String command, String title, String content) { + return new Notification(commandId, command, "error", title, content); } @@ -53,8 +66,8 @@ public class Notification { * @param content 通知内容 * @return 通知实例 */ - public static Notification fatalNotification(String content) { - return new Notification("fatal", content); + public static Notification fatalNotification(String commandId, String command, String title, String content) { + return new Notification(commandId, command, "fatal", title, content); } diff --git a/src/main/java/com/iflytop/gd/infrastructure/drivers/AppErrorCode.java b/src/main/java/com/iflytop/gd/infrastructure/drivers/AppErrorCode.java new file mode 100644 index 0000000..075c5c0 --- /dev/null +++ b/src/main/java/com/iflytop/gd/infrastructure/drivers/AppErrorCode.java @@ -0,0 +1,21 @@ +package com.iflytop.gd.infrastructure.drivers; + +public enum AppErrorCode { + APP_OK(200, "操作成功"), + FAIL(500, "操作失败"), + PARAM_ERROR(400, "参数错误"); + + private int code; + private String msg; + private AppErrorCode(int code, String msg) { + this.code = code; + this.msg = msg; + } + + public int getCode() { + return code; + } + public String getMsg() { + return msg; + } +} \ No newline at end of file diff --git a/src/main/java/com/iflytop/gd/infrastructure/drivers/CmdId.java b/src/main/java/com/iflytop/gd/infrastructure/drivers/CmdId.java new file mode 100644 index 0000000..d079a65 --- /dev/null +++ b/src/main/java/com/iflytop/gd/infrastructure/drivers/CmdId.java @@ -0,0 +1,122 @@ +package com.iflytop.gd.infrastructure.drivers; + + +public enum CmdId { + NotSet(0xFFFF, "NOACTION"),// + + board_reset(0x0000, "复位板子"),// + event_bus_reg_change_report(0x0064, "寄存器修改事件"),// + // + + module_ping(0x0101, "MODULE_PING"), + module_stop(0x0102, "MODULE_STOP"), + + module_get_error(0x0110, "MODULE_GET_ERROR"), + module_get_detail_error(0x0111, "MODULE_GET_DETAIL_ERROR"), + module_clear_error(0x0112, "MODULE_CLEAR_ERROR"), + + module_set_reg(0x0120, "MODULE_SET_REG"), + module_get_reg(0x0121, "MODULE_GET_REG"), + module_reset_reg(0x0123, "MODULE_RESET_REG"), + + module_get_version(0x0130, "MODULE_GET_VERSION"), + module_get_type(0x0131, "MODULE_GET_TYPE"), + module_get_status(0x0132, "MODULE_GET_STATUS"), + + // 扩展板 + extboard_read_inio(0x6701, "EXTBOARD_READ_INIO"),// + extboard_write_outio(0x6702, "EXTBOARD_WRITE_OUTIO"),// + extboard_read_muti_inio(0x6703, "EXTBOARD_READ_MUTI_INIO"),// + extboard_read_inio_index_in_stm32(0x6704, "EXTBOARD_READ_INIO_INDEX_IN_STM32"),// + extboard_read_outio_index_in_stm32(0x6705, "EXTBOARD_READ_OUTIO_INDEX_IN_STM32"),// + extboard_read_outio(0x6706, "EXTBOARD_READ_OUTIO"),// + + // 补光灯模块 + module_pwm_light_on(0x0204, "MODULE_PWM_LIGHT_ON"), // 补光灯 开启 + module_pwm_light_off(0x0205, "MODULE_PWM_LIGHT_OFF"), // 补光灯 + + // 三色灯模块 + module_tricolor_light_on(0x0206, "MODULE_TRICOLOR_LIGHT_ON"), // 三色灯开启 + module_tricolor_light_off(0x0207, "MODULE_TRICOLOR_LIGHT_OFF"), // 三色灯 + + // IO 板卡 1 + module_io1_read_heat_rod_current(0x0207, "MODULE_IO_READ_HEAT_ROD_CURRENT"), // 读取加热棒电流 + + // IO 板卡 2 + + // 电机通用控制 + step_motor_enable(0x0201, "STEP_MOTOR_ENABLE"),// + step_motor_read_pos(0x020b, "STEP_MOTOR_READ_POS"),// + step_motor_read_enc_pos(0x020c, "STEP_MOTOR_READ_ENC_POS"),// + step_motor_easy_rotate(0x0211, "STEP_MOTOR_EASY_ROTATE"),// + step_motor_easy_move_by(0x0212, "STEP_MOTOR_EASY_MOVE_BY"),// + step_motor_easy_move_to(0x0213, "STEP_MOTOR_EASY_MOVE_TO"),// + step_motor_easy_move_to_zero(0x0214, "STEP_MOTOR_EASY_MOVE_TO_ZERO"),// + step_motor_easy_set_current_pos(0x0215, "STEP_MOTOR_EASY_SET_CURRENT_POS"),// + step_motor_easy_move_to_io(0x0216, "STEP_MOTOR_EASY_MOVE_TO_IO"),// + step_motor_stop(0x0228, "STEP_MOTOR_STOP"),// + step_motor_move_by(0x021d, "STEP_MOTOR_MOVE_BY"), // (dpos,speedlevel)->null speedlevel=0,1,2,3(default,low,mid,high) + step_motor_move_to(0x021e, "STEP_MOTOR_MOVE_TO"), // (pos,speedlevel)->null speedlevel=0,1,2,3(default,low,mid,high) + step_motor_move_to_zero_point_quick(0x021f, "STEP_MOTOR_MOVE_TO_ZERO_POINT_QUICK"), // (speedlevel)->null speedlevel=0,1,2,3(default,low,mid,high) + step_motor_rotate(0x0220, "STEP_MOTOR_ROTATE"), // + + step_motor_active_cfg(0x0229, "STEP_MOTOR_ACTIVE_CFG"),// + step_motor_read_io_state(0x022a, "STEP_MOTOR_READ_IO_STATE"),// + step_motor_easy_move_to_end_point(0x022c, "STEP_MOTOR_EASY_MOVE_TO_END_POINT"),// + step_motor_read_tmc5130_status(0x0232, "STEP_MOTOR_READ_TMC5130_STATUS"),// + step_motor_read_tmc5130_state(0x0233, "STEP_MOTOR_READ_TMC5130_STATE"),// + step_motor_read_io_index_in_stm32(0x0238, "STEP_MOTOR_READ_IO_INDEX_IN_STM32"),// + step_motor_set_subdevice_reg(0x0239, "STEP_MOTOR_SET_SUBDEVICE_REG"),// + step_motor_get_subdevice_reg(0x023a, "STEP_MOTOR_GET_SUBDEVICE_REG"),// + step_motor_easy_reciprocating_motion(0x022d, "STEP_MOTOR_EASY_RECIPROCATING_MOTION"),// + step_motor_easy_move_to_zero_point_quick(0x022e, "STEP_MOTOR_EASY_MOVE_TO_ZERO_POINT_QUICK"), + + + ; + + public final static int ATTACH_IS_BYTES = 1; + public final static int ATTACH_IS_INT32 = 2; + public final int index; + public final String name; + + CmdId(int index, String chname) { + this.index = index; + this.name = chname; + } + + public int toInt() { + return index; + } + + public static CmdId valueOf(int val) { + CmdId[] values = CmdId.values(); + for (CmdId e : values) { + if (e.toInt() == val) + return e; + } + return null; + } + + public static String toString(int val) { + CmdId[] values = CmdId.values(); + for (CmdId e : values) { + if (e.toInt() == val) { + return e.toString(); + } + } + return "unknown(" + val + ")"; + } + + public String getName() { + return name; + } + + public Boolean eq(Integer index) { + return this.index == index; + } + + + public boolean isTrace() { + return true; + } +} diff --git a/src/main/java/com/iflytop/gd/infrastructure/drivers/ModuleId.java b/src/main/java/com/iflytop/gd/infrastructure/drivers/ModuleId.java new file mode 100644 index 0000000..34add60 --- /dev/null +++ b/src/main/java/com/iflytop/gd/infrastructure/drivers/ModuleId.java @@ -0,0 +1,98 @@ +package com.iflytop.gd.infrastructure.drivers; + +public enum ModuleId { + NotSet(0, "未设置"), + IO1Board(10, "台面 IO 板模块"), + PWMLight(11, "PWM 灯"), + TriColorLight(12, "三色灯"), + + IO2Board(30, "台下 IO 板模块"), + + DoorBoard(80, "门电机板模块"),// + DoorM(81, "门电机"), + + ShakeModBoard(90, "摇匀模组板"), // + ShakeModShakeM(91, "加液位摇匀电机"), // + + CapStorageBoard(100, "拍子存放板模块"), // + CapStorageM(101, "拍子存放电机"), // + + DualRobotAxis1Board(110, "双轴机械臂1轴板模块"),// + DualRobotAxis1M(111, "双轴机械臂1轴电机"), + DualRobotAxis2Board(120, "双轴机械臂2轴板模块"),// + DualRobotAxis2M(121, "双轴机械臂2轴电机"), + + HBotXBoard(130, "X轴板模块"),// + HBotXM(131, "X轴电机"), + HBotYBoard(140, "Y轴板模块"),// + HBotYM(141, "Y轴电机"), + HBotZBoard(150, "Z轴板模块"),// + HBotZM(151, "Z轴电机"), + + Heater1Board(160, "加热1板模块"),// + Heater1M(161, "加热1电机"), + Heater2Board(170, "加热2板模块"),// + Heater2M(171, "加热2电机"), + Heater3Board(180, "加热3板模块"),// + Heater3M(181, "加热3电机"), + Heater4Board(190, "加热4板模块"),// + Heater4M(191, "加热4电机"), + Heater5Board(200, "加热5板模块"),// + Heater5M(201, "加热5电机"), + Heater6Board(210, "加热6板模块"),// + Heater6M(211, "加热6电机"), + + AcidPump1Board(220, "加酸泵1板模块"),// + AcidPump1M(221, "加酸泵1电机"), + AcidPump2Board(230, "加酸泵2板模块"),// + AcidPump2M(231, "加酸泵2电机"), + AcidPump3Board(240, "加酸泵3板模块"),// + AcidPump3M(241, "加酸泵3电机"), + AcidPump4Board(250, "加酸泵4板模块"),// + AcidPump4M(251, "加酸泵4电机"), + AcidPump5Board(260, "泵5板模块"),// + AcidPump5M(261, "泵5电机"), + AcidPump6Board(270, "泵6板模块"),// + AcidPump6M(271, "泵6电机"), + AcidPump7Board(280, "泵7板模块"),// + AcidPump7M(281, "泵7电机"), + AcidPump8Board(290, "泵8板模块"),// + AcidPump8M(291, "泵8电机"), + ; + + final public String name; + final public int index; + + ModuleId(int index, String name) { + this.name = name; + this.index = index; + } + + public int toInt() { + return index; + } + + + public static ModuleId valueOf(Integer val) { + return valueOf(val.intValue()); + } + + public static ModuleId valueOf(int val) { + ModuleId[] values = ModuleId.values(); + for (ModuleId e : values) { + if (e.toInt() == val) + return e; + } + return null; + } + + public static String toString(int val) { + ModuleId[] values = ModuleId.values(); + for (ModuleId e : values) { + if (e.toInt() == val) { + return e.toString(); + } + } + return "unknown(" + val + ")"; + } +} diff --git a/src/main/java/com/iflytop/gd/infrastructure/drivers/RegIndex.java b/src/main/java/com/iflytop/gd/infrastructure/drivers/RegIndex.java new file mode 100644 index 0000000..169919a --- /dev/null +++ b/src/main/java/com/iflytop/gd/infrastructure/drivers/RegIndex.java @@ -0,0 +1,78 @@ +package com.iflytop.gd.infrastructure.drivers; + +/** + * @brief 寄存器索引 + */ +public enum RegIndex { + + /*********************************************************************************************************************** + * 步进电机控制器 * + ***********************************************************************************************************************/ + /*********************************************************************************************************************** + * step_motor start * + ***********************************************************************************************************************/ + + kreg_step_motor_pos(10101), // 机器人x坐标 + kreg_step_motor_is_enable(10102), // 是否使能 + kreg_step_motor_dpos(10103), // 执行完上一条指令后的相对位移 + kreg_step_motor_has_move_zero(10104), // 是否回零 + // kreg_step_motor_shift(10150), // x偏移 + kreg_step_motor_shaft(10151), // x轴是否反转 + kreg_step_motor_one_circle_pulse(10152), // x轴一圈脉冲数 + kreg_step_motor_one_circle_pulse_denominator(10153), // 设置一圈脉冲数的分母 + kreg_step_motor_default_velocity(10154), // 默认速度 + kreg_step_motor_low_velocity(10155), // 低速 + kreg_step_motor_mid_velocity(10156), // 中速 + kreg_step_motor_high_velocity(10157), // 高速 + kreg_step_motor_ihold(10158), // 步进电机电流配置 + kreg_step_motor_irun(10159), // 步进电机电流配置 + kreg_step_motor_iholddelay(10160), // 步进电机电流配置 + kreg_step_motor_iglobalscaler(10161), // 步进电机电流配置 + kreg_step_motor_mres(10162), // 电机细分 + kreg_step_motor_run_to_zero_speed(10173), // 回零速度 + kreg_step_motor_look_zero_edge_speed(10175), // 找零边缘速度 + kreg_step_motor_max_d(10178), // 最大限制距离 + kreg_step_motor_min_d(10179), // 最小限制距离 + kreg_step_motor_in_debug_mode(10180), // 驱动器处于调试模式 + kreg_step_motor_vstart(10181), // a1起作用的速度 + kreg_step_motor_a1(10182), // + kreg_step_motor_amax(10183), // + kreg_step_motor_v1(10184), // + kreg_step_motor_dmax(10185), // + kreg_step_motor_d1(10186), // + kreg_step_motor_vstop(10187), // + kreg_step_motor_tzerowait(10188), // + kreg_step_motor_enc_resolution(10189), // 编码器分辨率 1000,1024,4000,4096,16384 + kreg_step_motor_enable_enc(10190), // + kreg_step_motor_dzero_pos(10191), // 驱动器处于调试模式 + kret_step_motor_pos_devi_tolerance(10192), // 位置偏差容忍度 + kret_step_motor_io_trigger_append_distance(10193), // 移动到io时,附加的距离 + + /*********************************************************************************************************************** + * step_motor end * + ***********************************************************************************************************************/ + ; + + public final int index; + public final Boolean trace; + + RegIndex(int regIndex) { + this.index = regIndex; + this.trace = true; + } + + RegIndex(int regIndex, Boolean trace) { + this.index = regIndex; + this.trace = trace; + } + + public static RegIndex valueOf(int val) { + RegIndex[] values = RegIndex.values(); + for (RegIndex regindex : values) { + if (regindex.index == val) { + return regindex; + } + } + return null; + } +} diff --git a/src/main/java/com/iflytop/gd/infrastructure/drivers/WebSocketCommandBusImpl.java b/src/main/java/com/iflytop/gd/infrastructure/drivers/WebSocketCommandBusImpl.java new file mode 100644 index 0000000..6fe1a2e --- /dev/null +++ b/src/main/java/com/iflytop/gd/infrastructure/drivers/WebSocketCommandBusImpl.java @@ -0,0 +1,98 @@ +package com.iflytop.gd.infrastructure.drivers; + +import cn.hutool.core.util.ObjectUtil; +import com.iflytop.gd.common.exception.AppException; +import com.iflytop.gd.system.drivers.CommandBus; +import com.iflytop.gd.system.exceptions.CommandExecTimeoutException; +import com.iflytop.gd.system.exceptions.HardwareErrorException; +import com.iflytop.gd.system.models.DataPacket; +import com.iflytop.gd.system.utils.ByteArray; +import jakarta.websocket.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.web.socket.client.WebSocketClient; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import java.util.concurrent.locks.ReentrantLock; + + +@Slf4j +@Component +@ClientEndpoint +public class WebSocketCommandBusImpl implements CommandBus { + private Session session; + private WebSocketClient webSocketClient; + private CountDownLatch countDownLatch; + private DataPacket lastDataPacket; + + + + 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; + @Override + public synchronized DataPacket waitForCommandExec(DataPacket commandPacket, Integer timeout, TimeUnit unit) + throws CommandExecTimeoutException, HardwareErrorException, IOException, InterruptedException { + try { + this.countDownLatch = new CountDownLatch(1); + this.session.getBasicRemote().sendText(commandPacket.toByteString()); + boolean isTimeout = this.countDownLatch.await(timeout, unit); + // 命令返回或者超时了 + if (isTimeout) { + // TODO处理超时 + throw new CommandExecTimeoutException(); + } + if (this.lastDataPacket.getPacketType() == PACKET_TYPE_ERROR_ACK) { + log.error("moduleId={}执行command={}发送硬件错误", this.lastDataPacket.getModuleId(), this.lastDataPacket.getCmdId()); + throw new HardwareErrorException(); + } + return ObjectUtil.cloneByStream(this.lastDataPacket); + } catch (IOException e) { + log.error("发送指令发生异常", e); + throw e; + } catch (InterruptedException e) { + Thread.currentThread().getName(); + log.error(""); + throw e; + } + } + + + @OnOpen + public void onOpen(Session session) { + if (this.session != null) { + try { + this.session.close(); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } + this.session = session; + } + + @OnMessage + public void onMessage(String message) { + byte[] bytes = ByteArray.hexStringToBytes(message); + this.lastDataPacket = new DataPacket(bytes); + this.countDownLatch.countDown(); + } + + + @OnClose + public void onClose() { + if (this.countDownLatch != null) { + this.countDownLatch.countDown(); + } + } + + @OnError + public void onError(Session session, Throwable throwable) { + if (this.countDownLatch != null) { + this.countDownLatch.countDown(); + } + } +} diff --git a/src/main/java/com/iflytop/gd/system/constants/RotationDirection.java b/src/main/java/com/iflytop/gd/system/constants/RotationDirection.java new file mode 100644 index 0000000..f980e17 --- /dev/null +++ b/src/main/java/com/iflytop/gd/system/constants/RotationDirection.java @@ -0,0 +1,18 @@ +package com.iflytop.gd.system.constants; + +import lombok.Getter; + +/** + * 电机转动方向 + */ +@Getter +public enum RotationDirection { + Forward(1),Backward(-1); + + private Integer value; + + RotationDirection(Integer value) { + this.value = value; + } + +} diff --git a/src/main/java/com/iflytop/gd/system/devices/BaseStepStepMotor.java b/src/main/java/com/iflytop/gd/system/devices/BaseStepStepMotor.java new file mode 100644 index 0000000..13a3e24 --- /dev/null +++ b/src/main/java/com/iflytop/gd/system/devices/BaseStepStepMotor.java @@ -0,0 +1,46 @@ +package com.iflytop.gd.system.devices; + +import com.iflytop.gd.infrastructure.drivers.CmdId; +import com.iflytop.gd.infrastructure.drivers.ModuleId; +import com.iflytop.gd.system.constants.DistanceUnit; +import com.iflytop.gd.system.constants.SpeedUnit; +import com.iflytop.gd.system.drivers.CommandBus; +import com.iflytop.gd.system.exceptions.CommandExecTimeoutException; +import com.iflytop.gd.system.exceptions.HardwareErrorException; +import com.iflytop.gd.system.models.DataPacket; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +public abstract class BaseStepStepMotor implements StepMotor { + protected final ModuleId moduleId; + protected final CommandBus commandBus; + protected final Integer DEFAULT_COMMAND_EXEC_TIMEOUT_SECONDS = 10; + + protected BaseStepStepMotor(ModuleId moduleId, CommandBus commandBus) { + this.moduleId = moduleId; + this.commandBus = commandBus; + } + + + @Override + public void easyMoveTo(Integer value, DistanceUnit unit) { + DataPacket commandDataPacket = DataPacket.createCommandDataPacket(moduleId.index, CmdId.step_motor_easy_move_to.index, value); + try { + commandBus.waitForCommandExec(commandDataPacket, DEFAULT_COMMAND_EXEC_TIMEOUT_SECONDS, TimeUnit.SECONDS); + } catch (CommandExecTimeoutException e) { + throw new RuntimeException(e); + } catch (HardwareErrorException e) { + throw new RuntimeException(e); + } catch (IOException e) { + throw new RuntimeException(e); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @Override + public void easyMoveBy(Integer value, DistanceUnit unit) { + + } +} diff --git a/src/main/java/com/iflytop/gd/system/devices/BinaryDevice.java b/src/main/java/com/iflytop/gd/system/devices/BinaryDevice.java new file mode 100644 index 0000000..77f7ff9 --- /dev/null +++ b/src/main/java/com/iflytop/gd/system/devices/BinaryDevice.java @@ -0,0 +1,11 @@ +package com.iflytop.gd.system.devices; + +/** + * 开关类型设备驱动定义 + */ +public interface BinaryDevice { + void open(); + void close(); + boolean isOpen(); + boolean isClosed(); +} diff --git a/src/main/java/com/iflytop/gd/system/devices/DoorStepMotor.java b/src/main/java/com/iflytop/gd/system/devices/DoorStepMotor.java new file mode 100644 index 0000000..14fdd24 --- /dev/null +++ b/src/main/java/com/iflytop/gd/system/devices/DoorStepMotor.java @@ -0,0 +1,9 @@ +package com.iflytop.gd.system.devices; + +/** + * 步进电机 + */ +public class DoorStepMotor { + + +} diff --git a/src/main/java/com/iflytop/gd/system/drivers/Fan.java b/src/main/java/com/iflytop/gd/system/devices/Fan.java similarity index 53% rename from src/main/java/com/iflytop/gd/system/drivers/Fan.java rename to src/main/java/com/iflytop/gd/system/devices/Fan.java index 8159538..b3410fb 100644 --- a/src/main/java/com/iflytop/gd/system/drivers/Fan.java +++ b/src/main/java/com/iflytop/gd/system/devices/Fan.java @@ -1,4 +1,4 @@ -package com.iflytop.gd.system.drivers; +package com.iflytop.gd.system.devices; /** * 风扇 diff --git a/src/main/java/com/iflytop/gd/system/drivers/Heater.java b/src/main/java/com/iflytop/gd/system/devices/Heater.java similarity index 56% rename from src/main/java/com/iflytop/gd/system/drivers/Heater.java rename to src/main/java/com/iflytop/gd/system/devices/Heater.java index 1902008..31e9ee5 100644 --- a/src/main/java/com/iflytop/gd/system/drivers/Heater.java +++ b/src/main/java/com/iflytop/gd/system/devices/Heater.java @@ -1,4 +1,4 @@ -package com.iflytop.gd.system.drivers; +package com.iflytop.gd.system.devices; /** * 加热器 diff --git a/src/main/java/com/iflytop/gd/system/drivers/Relay.java b/src/main/java/com/iflytop/gd/system/devices/Relay.java similarity index 55% rename from src/main/java/com/iflytop/gd/system/drivers/Relay.java rename to src/main/java/com/iflytop/gd/system/devices/Relay.java index a9b1456..0c6d88f 100644 --- a/src/main/java/com/iflytop/gd/system/drivers/Relay.java +++ b/src/main/java/com/iflytop/gd/system/devices/Relay.java @@ -1,4 +1,4 @@ -package com.iflytop.gd.system.drivers; +package com.iflytop.gd.system.devices; /** * 继电器 diff --git a/src/main/java/com/iflytop/gd/system/drivers/ServoMotor.java b/src/main/java/com/iflytop/gd/system/devices/ServoMotor.java similarity index 59% rename from src/main/java/com/iflytop/gd/system/drivers/ServoMotor.java rename to src/main/java/com/iflytop/gd/system/devices/ServoMotor.java index e0a00a9..4eb075f 100644 --- a/src/main/java/com/iflytop/gd/system/drivers/ServoMotor.java +++ b/src/main/java/com/iflytop/gd/system/devices/ServoMotor.java @@ -1,4 +1,4 @@ -package com.iflytop.gd.system.drivers; +package com.iflytop.gd.system.devices; /** diff --git a/src/main/java/com/iflytop/gd/system/devices/StepMotor.java b/src/main/java/com/iflytop/gd/system/devices/StepMotor.java new file mode 100644 index 0000000..c534ed6 --- /dev/null +++ b/src/main/java/com/iflytop/gd/system/devices/StepMotor.java @@ -0,0 +1,77 @@ +package com.iflytop.gd.system.devices; + +import com.iflytop.gd.system.constants.DistanceUnit; +import com.iflytop.gd.system.constants.RotationDirection; + +/** + * 电机驱动类型设备 + */ +public interface StepMotor { + + /** + * 移动指定距离 + * @param value + * @param unit + */ + void easyMoveBy(Integer value, DistanceUnit unit); + + void easyMoveTo(Integer value, DistanceUnit unit); + + void easyMoveToZero(); + + void setCurrentPosition(Integer value); + + void easyMoveToZeroPointQuick(); + + void easyMoveToEndPoint(); + + /** + * 使能电机 + */ + void enable(); + + /** + * 读取当前位置 + * @return + */ + Integer readPosition(); + + /** + * 读取编码器位置 + * @return + */ + Integer readEncoderPosition(); + + void easyRotate(RotationDirection direction); + + void easyMoveByBlock(); + + void easyMoveToBlock(); + + void easyMoveToZeroBlock(); + + void readPositionByMoveToZeroBlock(); + + void easyMoveToZeroPointQuickBlock(); + + void stop(); + + void moveByBlock(); + + void moveTOBlock(); + + void rotate(); + + Boolean readIOState(); + + void easyReciprocatingMotion(); + + void easyReciprocatingMotionBlock(); + + Boolean isReturnToZero(); + + void setReg(); + + Integer readReg(); + +} diff --git a/src/main/java/com/iflytop/gd/system/drivers/CommandBus.java b/src/main/java/com/iflytop/gd/system/drivers/CommandBus.java new file mode 100644 index 0000000..98960ee --- /dev/null +++ b/src/main/java/com/iflytop/gd/system/drivers/CommandBus.java @@ -0,0 +1,22 @@ +package com.iflytop.gd.system.drivers; + +import com.iflytop.gd.common.exception.AppException; +import com.iflytop.gd.system.exceptions.CommandExecTimeoutException; +import com.iflytop.gd.system.exceptions.HardwareErrorException; +import com.iflytop.gd.system.models.DataPacket; + +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +public interface CommandBus { + + /** + * 发送命令数据包并等待响应 + * @param commandPacket 命令数据包 + * @param timeout 等待超时事件 + * @param unit 超时时间单位 + * @return 响应数据包 + * @throws Exception + */ + DataPacket waitForCommandExec(DataPacket commandPacket, Integer timeout, TimeUnit unit) throws CommandExecTimeoutException, HardwareErrorException, IOException, InterruptedException; +} diff --git a/src/main/java/com/iflytop/gd/system/drivers/StepMotor.java b/src/main/java/com/iflytop/gd/system/drivers/StepMotor.java deleted file mode 100644 index e187c08..0000000 --- a/src/main/java/com/iflytop/gd/system/drivers/StepMotor.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.iflytop.gd.system.drivers; - -import com.iflytop.gd.system.constants.DistanceUnit; -import com.iflytop.gd.system.constants.SpeedUnit; - -/** - * 步进电机 - */ -public interface StepMotor { - - /** - * 移动指定距离 - * @param value - * @param unit - */ - void move(Integer value, DistanceUnit unit); - - /** - * 停止移动 - */ - void stop(); - - /** - * 设置移动速度 - * @param value - * @param unit - */ - void setSpeed(Integer value, SpeedUnit unit); - - /** - * 复位电机 - */ - void reset(); -} diff --git a/src/main/java/com/iflytop/gd/system/exceptions/CommandExecTimeoutException.java b/src/main/java/com/iflytop/gd/system/exceptions/CommandExecTimeoutException.java new file mode 100644 index 0000000..8926964 --- /dev/null +++ b/src/main/java/com/iflytop/gd/system/exceptions/CommandExecTimeoutException.java @@ -0,0 +1,22 @@ +package com.iflytop.gd.system.exceptions; + +public class CommandExecTimeoutException extends Exception{ + public CommandExecTimeoutException() { + } + + public CommandExecTimeoutException(String message) { + super(message); + } + + public CommandExecTimeoutException(String message, Throwable cause) { + super(message, cause); + } + + public CommandExecTimeoutException(Throwable cause) { + super(cause); + } + + public CommandExecTimeoutException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/com/iflytop/gd/system/exceptions/HardwareErrorException.java b/src/main/java/com/iflytop/gd/system/exceptions/HardwareErrorException.java new file mode 100644 index 0000000..ddbe843 --- /dev/null +++ b/src/main/java/com/iflytop/gd/system/exceptions/HardwareErrorException.java @@ -0,0 +1,22 @@ +package com.iflytop.gd.system.exceptions; + +public class HardwareErrorException extends Exception{ + public HardwareErrorException() { + } + + public HardwareErrorException(String message) { + super(message); + } + + public HardwareErrorException(String message, Throwable cause) { + super(message, cause); + } + + public HardwareErrorException(Throwable cause) { + super(cause); + } + + public HardwareErrorException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/main/java/com/iflytop/gd/system/models/DataPacket.java b/src/main/java/com/iflytop/gd/system/models/DataPacket.java new file mode 100644 index 0000000..e72ac3d --- /dev/null +++ b/src/main/java/com/iflytop/gd/system/models/DataPacket.java @@ -0,0 +1,83 @@ +package com.iflytop.gd.system.models; + +import com.iflytop.gd.system.utils.ByteArray; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class DataPacket { + 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; + + byte[] raw; + + public DataPacket(byte[] cmd) { + raw = new byte[cmd.length]; + System.arraycopy(cmd, 0, raw, 0, cmd.length); + } + + public String toByteString() { + return ByteArray.toByteString(raw); + } + + static public DataPacket createPacket(Integer moduleId, int packetType, Integer cmdId, Integer[] params) { + int bufferSize = DataPacket.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 DataPacket(buffer.array()); + } + + + public static DataPacket createCommandDataPacket(Integer moduleId, Integer cmdId, Integer... params) { + return createPacket(moduleId, PACKET_TYPE_CMD, cmdId, params); + } + + 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); + } +} diff --git a/src/main/java/com/iflytop/gd/system/utils/ByteArray.java b/src/main/java/com/iflytop/gd/system/utils/ByteArray.java new file mode 100644 index 0000000..bb981b5 --- /dev/null +++ b/src/main/java/com/iflytop/gd/system/utils/ByteArray.java @@ -0,0 +1,125 @@ +// Source code is decompiled from a .class file using FernFlower decompiler. +package com.iflytop.gd.system.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)); + // } +}