diff --git a/wcs/src/main/java/org/wcs/business/etag/EtagAtopOperation.java b/wcs/src/main/java/org/wcs/business/etag/EtagAtopOperation.java new file mode 100644 index 0000000..392a324 --- /dev/null +++ b/wcs/src/main/java/org/wcs/business/etag/EtagAtopOperation.java @@ -0,0 +1,214 @@ +package org.wcs.business.etag; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.wcs.business.redis.EtagRedis; +import org.wcs.constant.enums.database.ETagTypeEnum; +import org.wcs.constant.enums.etag.LedBlinkingEnum; +import org.wcs.constant.enums.etag.LedColorEnum; +import org.wcs.model.bo.etag.EtagLightParams; +import org.wcs.model.po.app.AppEtagTagInfo; + +/** + * 上尚电子标签操作类 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class EtagAtopOperation { + + // 电子标签 redis 操作类 + private final EtagRedis etagRedis; + + /** + * 点亮标签 + * @param params 点亮标签参数 + * @return 结果 + */ + public String lightTag(EtagLightParams params) { + if(params == null || params.getTagName() == null) { + return "参数错误"; + } + if(EtagCommon.socketClient == null) { + return "电子标签控制器尚未初始化"; + } + AppEtagTagInfo etagTag = etagRedis.getEtagTag(params.getTagName()); + if(etagTag == null) { + return "未找到标签"; + } + Integer tagId = etagTag.getTagId(); + if(tagId == null || tagId < 0 || tagId > 127) { + return "标签ID格式不正确"; + } + params.setTagId(tagId.byteValue()); // 设置标签ID进参数 + Integer controllerId = etagTag.getControllerId(); // 控制器ID,也是 Socket 连接的 ID + ETagTypeEnum eTagTypeEnum = ETagTypeEnum.getByCode(etagTag.getTagType()); + if(eTagTypeEnum == null) { + return "未知标签种类"; + } + switch (eTagTypeEnum) { + case ETagTypeEnum.NUMBER_BUTTON_3 -> { + return lightNumberButton3(controllerId, params); + } + case ETagTypeEnum.NUMBER_BUTTON_7 -> { + return lightNumberButton7(controllerId, params); + } + case ETagTypeEnum.NUMBER_ENGLISH_BUTTON_12 -> { + return lightNumberEnglishButton12(controllerId, params); + } + case ETagTypeEnum.NUMBER_CHINESE_BUTTON_6 -> { + return lightNumberChineseButton12(controllerId, params); + } + case ETagTypeEnum.LIGHT -> { + return lightTunnelLight(controllerId, params); + } + default -> { + return "不支持的标签种类"; + } + } + } + + /** + * 点亮带按钮3位数字标签 + * @param controllerId 控制器ID + * @param params 点亮标签参数 + * @return 结果 + */ + public String lightNumberButton3(Integer controllerId, EtagLightParams params) { + // 检查这次标签颜色是否与上次发送相同,若不同则重新发送标签颜色 + LedColorEnum etagTagColor = etagRedis.getEtagTagColor(params.getTagName()); + if(etagTagColor == null || etagTagColor != params.getLedColor()) { + byte[] ledColorBytes = EtagInstruction.setLedColor(params.getTagId(), params.getLedColor()); + String sendLedColorBytes = EtagCommon.socketClient.sendBytes(controllerId.toString(), ledColorBytes); + if(sendLedColorBytes != null) { + // 发送成功,设置标签颜色,防止下次重复发送 + etagRedis.setEtagTagColor(params.getTagName(), params.getLedColor()); + } + } + // 检查这次闪烁要求是否和上次相同,若不同则重新发送闪烁颜色 + LedBlinkingEnum etagTagBlinking = etagRedis.getEtagTagBlinking(params.getTagName()); + if(etagTagBlinking == null || etagTagBlinking != params.getLedBlinking()) { + byte[] ledBlinkingBytes = EtagInstruction.setLedBlinking(params.getTagId(), params.getLedBlinking()); + String sendLedBlinkingBytes = EtagCommon.socketClient.sendBytes(controllerId.toString(), ledBlinkingBytes); + if(sendLedBlinkingBytes != null) { + // 发送成功,设置标签闪烁,防止下次重复发送 + etagRedis.setEtagTagBlinking(params.getTagName(), params.getLedBlinking()); + } + } + // 发送标签值 + byte[] tagValueBytes = EtagInstruction.showNumber6(params.getTagId(), params.getTagValue()); + String sendResult = EtagCommon.socketClient.sendBytes(controllerId.toString(), tagValueBytes); + if(sendResult != null) { + log.info("发送电子标签信息失败,标签名称:{},发送数据:{},结果:{}", params.getTagName(), params, sendResult); + } + return sendResult; + } + + /** + * 点亮带按钮7位数字标签 + * @param controllerId 控制器ID + * @param params 点亮标签参数 + * @return 结果 + */ + public String lightNumberButton7(Integer controllerId, EtagLightParams params) { + // 等遇到这种标签在看,文档里面有点乱 + return "不支持"; + } + + /** + * 点亮带按钮12位数字英文标签 + * @param controllerId 控制器ID + * @param params 点亮标签参数 + * @return 结果 + */ + public String lightNumberEnglishButton12(Integer controllerId, EtagLightParams params) { + // 检查这次标签颜色是否与上次发送相同,若不同则重新发送标签颜色 + LedColorEnum etagTagColor = etagRedis.getEtagTagColor(params.getTagName()); + if(etagTagColor == null || etagTagColor != params.getLedColor()) { + byte[] ledColorBytes = EtagInstruction.setLedColor(params.getTagId(), params.getLedColor()); + String sendLedColorBytes = EtagCommon.socketClient.sendBytes(controllerId.toString(), ledColorBytes); + if(sendLedColorBytes != null) { + // 发送成功,设置标签颜色,防止下次重复发送 + etagRedis.setEtagTagColor(params.getTagName(), params.getLedColor()); + } + } + // 检查这次闪烁要求是否和上次相同,若不同则重新发送闪烁颜色 + LedBlinkingEnum etagTagBlinking = etagRedis.getEtagTagBlinking(params.getTagName()); + if(etagTagBlinking == null || etagTagBlinking != params.getLedBlinking()) { + byte[] ledBlinkingBytes = EtagInstruction.setLedBlinking(params.getTagId(), params.getLedBlinking()); + String sendLedBlinkingBytes = EtagCommon.socketClient.sendBytes(controllerId.toString(), ledBlinkingBytes); + if(sendLedBlinkingBytes != null) { + // 发送成功,设置标签闪烁,防止下次重复发送 + etagRedis.setEtagTagBlinking(params.getTagName(), params.getLedBlinking()); + } + } + // 发送标签值 + byte[] tagValueBytes = EtagInstruction.showEnglishString12(params.getTagId(), params.getTagValue()); + String sendResult = EtagCommon.socketClient.sendBytes(controllerId.toString(), tagValueBytes); + if(sendResult != null) { + log.info("发送电子标签信息失败,标签名称:{},发送数据:{},结果:{}", params.getTagName(), params, sendResult); + } + return sendResult; + } + + /** + * 点亮带按钮6位数字中文标签 + * @param controllerId 控制器ID + * @param params 点亮标签参数 + * @return 结果 + */ + public String lightNumberChineseButton12(Integer controllerId, EtagLightParams params) { + // 检查这次标签颜色是否与上次发送相同,若不同则重新发送标签颜色 + LedColorEnum etagTagColor = etagRedis.getEtagTagColor(params.getTagName()); + if(etagTagColor == null || etagTagColor != params.getLedColor()) { + byte[] ledColorBytes = EtagInstruction.setLedColor(params.getTagId(), params.getLedColor()); + String sendLedColorBytes = EtagCommon.socketClient.sendBytes(controllerId.toString(), ledColorBytes); + if(sendLedColorBytes != null) { + // 发送成功,设置标签颜色,防止下次重复发送 + etagRedis.setEtagTagColor(params.getTagName(), params.getLedColor()); + } + } + // 检查这次闪烁要求是否和上次相同,若不同则重新发送闪烁颜色 + LedBlinkingEnum etagTagBlinking = etagRedis.getEtagTagBlinking(params.getTagName()); + if(etagTagBlinking == null || etagTagBlinking != params.getLedBlinking()) { + byte[] ledBlinkingBytes = EtagInstruction.setLedBlinking(params.getTagId(), params.getLedBlinking()); + String sendLedBlinkingBytes = EtagCommon.socketClient.sendBytes(controllerId.toString(), ledBlinkingBytes); + if(sendLedBlinkingBytes != null) { + // 发送成功,设置标签闪烁,防止下次重复发送 + etagRedis.setEtagTagBlinking(params.getTagName(), params.getLedBlinking()); + } + } + String sendResult = ""; + // 发送标签中文 + byte[] tagStringBytes = EtagInstruction.setChineseString(params.getTagId(), params.getTagString()); + sendResult += EtagCommon.socketClient.sendBytes(controllerId.toString(), tagStringBytes); + // 发送标签值 + byte[] tagValueBytes = EtagInstruction.showChineseNumber6(params.getTagId(), params.getTagValue()); + sendResult += EtagCommon.socketClient.sendBytes(controllerId.toString(), tagValueBytes); + if(!sendResult.isEmpty()) { + log.info("发送电子标签信息失败,标签名称:{},发送数据:{},结果:{}", params.getTagName(), params, sendResult); + } + return sendResult; + + } + + /** + * 点亮通道灯 + * @param controllerId 控制器ID + * @param params 点亮标签参数 + * @return 结果 + */ + public String lightTunnelLight(Integer controllerId, EtagLightParams params) { + String lightValueBit = "0" + LedBlinkingEnum.getBlinkingBitString(params.getLedBlinking()) + + "0" + LedColorEnum.getLightColorBitString(params.getLedColor()); + byte[] lightBytes = EtagInstruction.light(params.getTagId(), lightValueBit); + String sendResult = EtagCommon.socketClient.sendBytes(controllerId.toString(), lightBytes); + if(sendResult != null) { + log.info("发送电子标签信息失败,标签名称:{},发送数据:{},结果:{}", params.getTagName(), params, sendResult); + } + return sendResult; + } + + +} diff --git a/wcs/src/main/java/org/wcs/business/etag/EtagCommon.java b/wcs/src/main/java/org/wcs/business/etag/EtagCommon.java new file mode 100644 index 0000000..7714a95 --- /dev/null +++ b/wcs/src/main/java/org/wcs/business/etag/EtagCommon.java @@ -0,0 +1,16 @@ +package org.wcs.business.etag; + +import org.wcs.plugin.tcp.SocketClient; + +/** + * 电子标签通用类 + */ +public class EtagCommon { + + /** + * Socket 客户端 + */ + public static SocketClient socketClient; + + +} diff --git a/wcs/src/main/java/org/wcs/business/etag/EtagDataHandler.java b/wcs/src/main/java/org/wcs/business/etag/EtagDataHandler.java new file mode 100644 index 0000000..ab9c371 --- /dev/null +++ b/wcs/src/main/java/org/wcs/business/etag/EtagDataHandler.java @@ -0,0 +1,112 @@ +package org.wcs.business.etag; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.wcs.business.redis.EtagRedis; +import org.wcs.constant.enums.database.ETagTypeEnum; +import org.wcs.model.bo.etag.EtagReturnInfo; +import org.wcs.model.po.app.AppEtagTagInfo; +import org.wcs.plugin.tcp.model.SocketDataItem; +import org.wcs.utils.AppThreadUtils; + +import java.util.Objects; + +/** + * 电子标签数据处理类 + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class EtagDataHandler { + + // 电子标签 redis 操作类 + private final EtagRedis etagRedis; + + /** + * 接收字节数据并解析,主要是解析电子标签扫码器扫描的数据和标签按下确认的数据 + * @param socketDataItem Socket 数据项 + * @param bytes 字节数据 + * @remark 此为参照供应商C#版本的程序的数据解析方法所写,看不懂请不要问我,谢谢 + */ + public void receiveBytes(SocketDataItem socketDataItem, byte[] bytes) { + AppThreadUtils.startNewThread(() -> { + EtagReturnInfo etagReturnInfo = new EtagReturnInfo(); + etagReturnInfo.setControllerId(socketDataItem.getSocketId()); + etagReturnInfo.setIp(socketDataItem.getSocketIp()); + etagReturnInfo.setEtagPort(bytes[2] == 0x60 ? 1 : 2); + etagReturnInfo.setSubCommand((int)bytes[6]); + etagReturnInfo.setTagId(bytes.length > 7 ? (int)bytes[7] : 0); + if(etagReturnInfo.getSubCommand() == 6 || etagReturnInfo.getSubCommand() == 7) { + StringBuilder returnData = new StringBuilder(); + for(int i = 8; i < bytes.length; i++) { + if (bytes[i] > 0) { + returnData.append((char) bytes[i]); + } + } + etagReturnInfo.setData(returnData.toString().replaceAll("\\W", "")); + } + if(etagReturnInfo.getSubCommand() == 9) { + byte[] ccb_data = new byte[250]; + for (int k = 8; k < bytes.length && k < 258; k++) { + ccb_data[k - 8] = bytes[k]; + } + int tmp = 0; + int mixId = 0; + StringBuilder tagStr = new StringBuilder(); + for(int i = 0; i <= 250; i++) { + if ((i - 1) % 8 == 0) { + tmp = ccb_data[3 + (i - 1) / 8]; + } + if (tmp % 2 != 1) { + mixId = i; + tagStr.append("1"); + } else { + tagStr.append("0"); + } + tmp /= 2; + } + etagReturnInfo.setData(tagStr.substring(0, mixId).replaceAll("\\W", "")); + } + try { + etagDataHandler(etagReturnInfo); // 数据处理 + } catch (Exception e) { + log.error("电子标签 {} 收到信息:{}, 数据处理异常:{}", etagReturnInfo.getControllerId(), etagReturnInfo, e.getMessage()); + } + }); + } + + /** + * 处理电子标签数据 + * @param etagReturnInfo 电子标签返回信息 + */ + private void etagDataHandler(EtagReturnInfo etagReturnInfo) { + log.info("电子标签 {} 收到信息:{}", etagReturnInfo.getControllerId(), etagReturnInfo); + Integer tagId = etagReturnInfo.getTagId(); // 标签号 + String controllerId = etagReturnInfo.getControllerId(); // 控制器ID + AppEtagTagInfo appEtagTagInfo = etagRedis.getEtagTag(controllerId, tagId); + if(appEtagTagInfo == null) { + log.warn("电子标签信息:{},未找到标签信息,无法处理事件", etagReturnInfo); + return; // 找不到标签信息 + } + Integer tagType = appEtagTagInfo.getTagType(); + if(Objects.equals(tagType, ETagTypeEnum.SCAN.getCode())) { + handScanCode(etagReturnInfo); + return; + } + if(ETagTypeEnum.buttonTagList().contains(ETagTypeEnum.getByCode(tagType))) { + handleTagConfirm(etagReturnInfo); + return; + } + } + + + private void handScanCode(EtagReturnInfo etagReturnInfo) { + } + + + private void handleTagConfirm(EtagReturnInfo etagReturnInfo) { + + } + +} diff --git a/wcs/src/main/java/org/wcs/business/etag/EtagInstruction.java b/wcs/src/main/java/org/wcs/business/etag/EtagInstruction.java new file mode 100644 index 0000000..7259802 --- /dev/null +++ b/wcs/src/main/java/org/wcs/business/etag/EtagInstruction.java @@ -0,0 +1,305 @@ +package org.wcs.business.etag; + + +import org.wcs.constant.enums.etag.LedBlinkingEnum; +import org.wcs.constant.enums.etag.LedColorEnum; +import org.wcs.utils.AppStringUtils; +import org.wcs.utils.Converter; + +import java.util.Arrays; + +/** + * 电子标签的指令集 + */ +public class EtagInstruction { + + /** + * 标签自检 + * @return 命令字节数组 + * @remark 向控制器发送此命令将强制标签自检(测试通过) + */ + public static byte[] checkAllTag() { + byte[] data = new byte[7]; + data[0] = 7; + data[1] = 0; + data[2] = 0x60; + data[6] = 0x09; + return data; + } + + /** + * 显示标签ID + * @param tagId 标签号 + * @return 命令字节数组 + * @remark 向控制器的某一个标签发送此命令将显示标签ID(测试通过) + */ + public static byte[] showTagId(byte tagId) { + byte[] data = new byte[8]; + data[0] = 8; + data[1] = 0; + data[2] = 0x60; + data[6] = 0x13; + data[7] = tagId; + return data; + } + + /** + * 重启标签 + * @param tagId 标签号 + * @return 命令字节数组 + * @remark 向控制器的某一个标签发送此命令将重启标签(未测试) + */ + public static byte[] restartTag(byte tagId) { + byte[] data = new byte[8]; + data[0] = 8; + data[1] = 0; + data[2] = 0x60; + data[6] = 0x14; + data[7] = tagId; + return data; + } + + /** + * 关闭标签 + * @param tagId 标签号 + * @return 命令字节数组 + * @remark 向控制器的某一个标签发送此命令将关闭标签(测试通过) + */ + public static byte[] turnOffTag(byte tagId) { + byte[] data = new byte[8]; + data[0] = 8; + data[1] = 0; + data[2] = 0x60; + data[6] = 1; + data[7] = tagId; + return data; + } + + /** + * 设置标签颜色 + * @param tagId 标签号 + * @param ledColor 颜色 + * @return 命令字节数组 + * @remark 向控制器的某一个标签发送此命令将设置标签颜色(测试通过) + */ + public static byte[] setLedColor(byte tagId, LedColorEnum ledColor) { + byte[] data = new byte[10]; + data[0] = 0x0A; + data[1] = 0; + data[2] = 0x60; + data[6] = 0x1F; + data[7] = tagId; + data[8] = 0; + data[9] = ledColor.getCode().byteValue(); + return data; + } + + /** + * 设置LED闪烁模式 + * @param tagId 标签号 + * @param ledBlinkingEnum 闪烁模式 + * @return 命令字节数组 + * @remark 向控制器的某一个标签发送此命令将设置LED闪烁模式(测试通过) + */ + public static byte[] setLedBlinking(byte tagId, LedBlinkingEnum ledBlinkingEnum) { + byte[] data = new byte[10]; + data[0] = 0x0A; + data[1] = 0; + data[2] = 0x60; + data[6] = 0x1F; + data[7] = tagId; + data[8] = 4; + data[9] = ledBlinkingEnum.getCode().byteValue(); + return data; + } + + /** + * 显示数字 + * @param tagId 标签号 + * @param number 显示的数字 + * @return 命令字节数组 + * @remark 向控制器的某一个标签发送此命令将显示数字(三位标签测试通过,其他未测试) + */ + public static byte[] showNumber6(byte tagId, String number) { + if(AppStringUtils.isEmpty(number.trim())) { + return turnOffTag(tagId); + } + if(!AppStringUtils.isNumber(number.trim())) { + number = "ERR"; + } + if(number.length() < 6) { + number = AppStringUtils.padLeft(number, " ", 6); + } + else { + number = number.substring(0, 6); + } + byte[] data = new byte[15]; + data[0] = 0x0f; + data[1] = 0; + data[2] = 0x60; + data[6] = 0x00; + data[7] = tagId; + for (int i = 0; i < number.length(); i++) { + char c = number.charAt(i); + if(c == ' ') { + continue; + } + data[8 + i] = (byte)c; + } + data[14] = 0x00; + return data; + } + + /** + * 点亮巷道灯 + * @param tagId 标签号 + * @param value 显示的数字 + * @return 命令字节数组 + * @remark (测试通过) + */ + public static byte[] light(byte tagId, String value) { + byte[] data = new byte[17]; + data[0] = 0x11; + data[1] = 0; + data[2] = 0x61; + data[3] = 0; + data[4] = 0; + data[5] = 0; + data[6] = 0x41; + data[7] = tagId; + data[8] = 0; + data[9] = 0; + String lightStatus = "00010001"; // 默认常亮绿色 + if(AppStringUtils.isNotEmpty(value)) { + lightStatus = value; + } + //data[9] = Converter.toByte(lightStatus); + data[10] = Converter.toByte(lightStatus); + data[11] = 0; + data[12] = 0; + data[13] = 0; + data[14] = 0; + data[15] = 0; + data[16] = 0; + return data; + } + + /** + * 点亮英文数字标签 + * @param tagId 标签号 + * @param value 显示的字符串 + * @return 消息字节 + */ + public static byte[] showEnglishString12(byte tagId, String value) { + if(AppStringUtils.isEmpty(value.trim())) { + return turnOffTag(tagId); + } + byte[] data = new byte[20]; + data[0] = 0x0f; + data[1] = 0; + data[2] = 0x60; + data[3] = 0x0f; + data[4] = 0; + data[5] = 0; + data[6] = 0; + data[7] = tagId; + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + if(c == ' ') { + continue; + } + data[8 + i] = (byte)c; + } + return data; + } + + + /** + * 设置中文数字标签的中文 ---- 调用 showChineseNumber6 显示数字才会显示 + * @param tagId 标签ID + * @param chinese 中文 + * @return 消息字节 + * @remark (测试通过) + */ + public static byte[] setChineseString(byte tagId, String chinese) { + if(AppStringUtils.isEmpty(chinese.trim())) { + return turnOffTag(tagId); + } + byte[] result = AppStringUtils.toByteArrayGBK(chinese); + if (result != null && result.length > 48) { + result = Arrays.copyOf(result, 48); + } + if(result != null) { + byte[] data = new byte[0x0a + (byte)result.length]; + data[0] = (byte) (0x0a + (byte)result.length); + data[1] = 0; + data[2] = 0x60; + data[3] = 0; + data[4] = 0; + data[5] = 0; + data[6] = 0x39; + data[7] = tagId; + data[8] = 0x0c; + System.arraycopy(result, 0, data, 9, result.length); + return data; + } + return new byte[0]; + } + + /** + * 清理中文标签缓存 + * @param tagId 标签ID + * @return 结果 + */ + public static byte[] cleanChineseString(byte tagId) { + byte[] data = new byte[8]; + data[0] = (byte)8; + data[1] = 0; + data[2] = 0x60; + data[3] = 0; + data[4] = 0; + data[5] = 0; + data[6] = 0x01; + data[7] = tagId; + return data; + } + + /** + * 显示中文标签的数字 ---- 调用此方法才会显示 + * @param tagId 标签ID + * @param number 数字 + * @return 命令字节 + * @remark (测试通过) + */ + public static byte[] showChineseNumber6(byte tagId, String number) { + if(AppStringUtils.isEmpty(number.trim())) { + return turnOffTag(tagId); + } + if(!AppStringUtils.isNumber(number.trim())) { + number = "ERR"; + } + if(number.length() < 6) { + number = AppStringUtils.padLeft(number, "0", 6); + } + else { + number = number.substring(0, 6); + } + byte[] data = new byte[14]; + data[0] = 0x0e; + data[1] = 0; + data[2] = 0x60; + data[3] = 0; + data[4] = 0; + data[5] = 0; + data[6] = 0x00; + data[7] = tagId; + for (int i = 0; i < number.length(); i++) { + char c = number.charAt(i); + if(c == ' ') { + continue; + } + data[8 + i] = (byte)c; + } + return data; + } +} diff --git a/wcs/src/main/java/org/wcs/business/etag/EtagTaskExecute.java b/wcs/src/main/java/org/wcs/business/etag/EtagTaskExecute.java new file mode 100644 index 0000000..302bcc7 --- /dev/null +++ b/wcs/src/main/java/org/wcs/business/etag/EtagTaskExecute.java @@ -0,0 +1,31 @@ +package org.wcs.business.etag; + +import org.springframework.stereotype.Component; + +/** + * 电子标签任务执行类 + */ +@Component +public class EtagTaskExecute { + + /** + * 点亮汇总标签 + */ + public void lightSummaryTag() { + + } + + /** + * 点亮小标签 + */ + public void lightSmallTag() { + } + + /** + * 点亮通道灯 + */ + public void lightTunnelLight() { + } + + +} diff --git a/wcs/src/main/java/org/wcs/business/redis/EtagRedis.java b/wcs/src/main/java/org/wcs/business/redis/EtagRedis.java new file mode 100644 index 0000000..c801fe2 --- /dev/null +++ b/wcs/src/main/java/org/wcs/business/redis/EtagRedis.java @@ -0,0 +1,259 @@ +package org.wcs.business.redis; + +import com.alibaba.fastjson2.JSONObject; +import lombok.RequiredArgsConstructor; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; +import org.wcs.constant.ConstantData; +import org.wcs.constant.enums.etag.LedBlinkingEnum; +import org.wcs.constant.enums.etag.LedColorEnum; +import org.wcs.model.po.app.AppEtagTagInfo; +import org.wcs.model.po.app.AppEtagTagLocation; +import org.wcs.model.po.app.AppEtagTask; +import org.wcs.utils.AppStringUtils; + +import java.util.Set; + +/** + * 电子标签Redis操作类 + */ +@Component +@RequiredArgsConstructor +public class EtagRedis { + + /** + * Redis操作类 + */ + private final StringRedisTemplate stringRedisTemplate; + + + // 电子标签小标签信息 + private static final String ETAG_TAG_KEY = ConstantData.SYSTEM_NAME + ":Etag:Tag"; + // 电子标签小标签ID信息,key 是用控制器编号拼接而成 + private static final String ETAG_TAG_ID_KEY = ConstantData.SYSTEM_NAME + ":Etag:TagId"; + // 电子标签位置信息 + private static final String ETAG_LOCATION_KEY = ConstantData.SYSTEM_NAME + ":Etag:Location"; + // 电子标签小标签绑定的任务信息 + private static final String ETAG_TAG_TASK_KEY = ConstantData.SYSTEM_NAME + ":Etag:TagTask"; + // 电子标签区域绑定的用户信息 + private static final String ETAG_AREA_USER_KEY = ConstantData.SYSTEM_NAME + ":Etag:AreaUser"; + // 电子标签小标签颜色信息 ---- 存储上次的颜色,防止重复发送颜色命令 + private static final String ETAG_TAG_COLOR_KEY = ConstantData.SYSTEM_NAME + ":Etag:TagColor"; + // 电子标签小标签闪烁信息 ---- 存储上次的闪烁信息,防止重复发送闪烁命令 + private static final String ETAG_TAG_BLINKING_KEY = ConstantData.SYSTEM_NAME + ":Etag:TagBlinking"; + + + /* ******************** 电子标签小标签信息 *********************** */ + + /** + * 清空电子标签小标签信息 + */ + public void clearEtagTag() { + Set keys = stringRedisTemplate.keys(ETAG_TAG_KEY + ":*"); + stringRedisTemplate.delete(keys); + Set idKeys = stringRedisTemplate.keys(ETAG_TAG_ID_KEY + ":*"); + stringRedisTemplate.delete(keys); + } + + /** + * 设置电子标签小标签信息 + * @param tagName 标签名称 + * @param tagInfo 标签信息 + */ + public void setEtagTag(String tagName, AppEtagTagInfo tagInfo) { + stringRedisTemplate.opsForValue().set(ETAG_TAG_KEY + ":" + tagName, AppStringUtils.objectToString(tagInfo)); + stringRedisTemplate.opsForValue().set(ETAG_TAG_ID_KEY + ":" + tagInfo.getControllerId() + "@" + tagInfo.getTagId(), tagName); + } + + /** + * 获取电子标签小标签信息 + * @param tagName 标签名称 + * @return 电子标签小标签信息 + */ + public AppEtagTagInfo getEtagTag(String tagName) { + String tagInfo = stringRedisTemplate.opsForValue().get(ETAG_TAG_KEY + ":" + tagName); + if(AppStringUtils.isEmpty(tagInfo)) { + return null; + } + return JSONObject.parseObject(tagInfo, AppEtagTagInfo.class); + } + + /** + * 获取电子标签小标签信息 + * @param controllerId 控制器编号 + * @param tagId 标签编号 + * @return 电子标签小标签信息 + */ + public AppEtagTagInfo getEtagTag(String controllerId, Integer tagId) { + String tagInfo = stringRedisTemplate.opsForValue().get(ETAG_TAG_ID_KEY + ":" + controllerId + "@" + tagId); + if(AppStringUtils.isEmpty(tagInfo)) { + return null; + } + return JSONObject.parseObject(tagInfo, AppEtagTagInfo.class); + } + + + + /* ******************** 电子标签货位信息 *********************** */ + + /** + * 清空电子标签货位信息 + */ + public void clearEtagLocation() { + Set keys = stringRedisTemplate.keys(ETAG_LOCATION_KEY + ":*"); + stringRedisTemplate.delete(keys); + } + + /** + * 设置电子标签货位信息 + * @param locationId 货位ID + * @param locationInfo 货位信息 + */ + public void setEtagLocation(String locationId, AppEtagTagLocation locationInfo) { + stringRedisTemplate.opsForValue().set(ETAG_LOCATION_KEY + ":" + locationId, AppStringUtils.objectToString(locationInfo)); + } + + /** + * 获取电子标签货位信息 + * @param locationId 货位ID + * @return 货位信息 + */ + public AppEtagTagLocation getEtagLocation(String locationId) { + String locationInfo = stringRedisTemplate.opsForValue().get(ETAG_LOCATION_KEY + ":" + locationId); + if(AppStringUtils.isEmpty(locationInfo)) { + return null; + } + return JSONObject.parseObject(locationInfo, AppEtagTagLocation.class); + } + + /* ******************** 电子标签绑定的任务信息 *********************** */ + + /** + * 设置电子标签绑定的任务信息 + * @param tagName 标签名称 + * @param task 任务信息 + */ + public void setEtagTagTask(String tagName, AppEtagTask task) { + stringRedisTemplate.opsForValue().set(ETAG_TAG_TASK_KEY + ":" + tagName, AppStringUtils.objectToString(task)); + } + + /** + * 获取电子标签绑定的任务信息 + * @param tagName 标签名称 + * @return 任务信息 + */ + public AppEtagTask getEtagTagTask(String tagName) { + String task = stringRedisTemplate.opsForValue().get(ETAG_TAG_TASK_KEY + ":" + tagName); + if(AppStringUtils.isEmpty(task)) { + return null; + } + return JSONObject.parseObject(task, AppEtagTask.class); + } + + /** + * 删除电子标签绑定的任务信息 + * @param tagName 标签名称 + */ + public void removeEtagTagTask(String tagName) { + stringRedisTemplate.delete(ETAG_TAG_TASK_KEY + ":" + tagName); + } + + /** + * 清空电子标签绑定的任务信息 + */ + public void clearEtagTagTask() { + Set keys = stringRedisTemplate.keys(ETAG_TAG_TASK_KEY + ":*"); + stringRedisTemplate.delete(keys); + } + + /** + * 判断电子标签绑定的任务信息是否存在 + * @param tagName 标签名称 + * @return 是否存在 + */ + public boolean existsEtagTagTask(String tagName) { + return stringRedisTemplate.hasKey(ETAG_TAG_TASK_KEY + ":" + tagName); + } + + /* ******************** 电子标签区域绑定的用户信息 *********************** */ + + /** + * 清空电子标签区域绑定的用户信息 + */ + public void clearEtagAreaUser() { + Set keys = stringRedisTemplate.keys(ETAG_AREA_USER_KEY + ":*"); + stringRedisTemplate.delete(keys); + } + + /** + * 获取电子标签区域绑定的用户信息 + * @param areaId 区域ID + * @return 区域用户信息 + */ + public String getEtagAreaUser(String areaId) { + String areaUser = stringRedisTemplate.opsForValue().get(ETAG_AREA_USER_KEY + ":" + areaId); + if(AppStringUtils.isEmpty(areaUser)) { + return null; + } + return areaUser; + } + + /** + * 设置电子标签区域绑定的用户信息 + * @param areaId 区域ID + * @param userId 用户ID + */ + public void setEtagAreaUser(String areaId, String userId) { + stringRedisTemplate.opsForValue().set(ETAG_AREA_USER_KEY + ":" + areaId, userId); + } + + /* ******************** 电子标签颜色信息 *********************** */ + + /** + * 设置电子标签颜色信息 + * @param tagName 标签名称 + * @param ledColor 颜色 + */ + public void setEtagTagColor(String tagName, LedColorEnum ledColor) { + stringRedisTemplate.opsForValue().set(ETAG_TAG_COLOR_KEY + ":" + tagName, String.valueOf(ledColor.getCode())); + } + + /** + * 获取电子标签颜色信息 + * @param tagName 标签名称 + * @return 颜色 + */ + public LedColorEnum getEtagTagColor(String tagName) { + String ledColor = stringRedisTemplate.opsForValue().get(ETAG_TAG_COLOR_KEY + ":" + tagName); + if(AppStringUtils.isEmpty(ledColor)) { + return null; + } + return LedColorEnum.getByCode(Integer.valueOf(ledColor)); + } + + /* ******************** 电子标签闪烁信息 *********************** */ + + /** + * 设置电子标签闪烁信息 + * @param tagName 标签名称 + * @param ledBlinkingEnum 闪烁模式 + */ + public void setEtagTagBlinking(String tagName, LedBlinkingEnum ledBlinkingEnum) { + stringRedisTemplate.opsForValue().set(ETAG_TAG_BLINKING_KEY + ":" + tagName, String.valueOf(ledBlinkingEnum.getCode())); + } + + /** + * 获取电子标签闪烁信息 + * @param tagName 标签名称 + * @return 闪烁模式 + */ + public LedBlinkingEnum getEtagTagBlinking(String tagName) { + String ledBlinking = stringRedisTemplate.opsForValue().get(ETAG_TAG_BLINKING_KEY + ":" + tagName); + if(AppStringUtils.isEmpty(ledBlinking)) { + return null; + } + return LedBlinkingEnum.getByCode(Integer.valueOf(ledBlinking)); + } + + +} diff --git a/wcs/src/main/java/org/wcs/constant/enums/database/ETagTypeEnum.java b/wcs/src/main/java/org/wcs/constant/enums/database/ETagTypeEnum.java index 9acd89d..fae39a1 100644 --- a/wcs/src/main/java/org/wcs/constant/enums/database/ETagTypeEnum.java +++ b/wcs/src/main/java/org/wcs/constant/enums/database/ETagTypeEnum.java @@ -2,6 +2,8 @@ package org.wcs.constant.enums.database; import lombok.Getter; +import java.util.List; + /** * 电子标签种类 */ @@ -13,7 +15,7 @@ public enum ETagTypeEnum { SCAN(3, "扫描枪"), LIGHT(4, "单色灯"), NUMBER_ENGLISH_BUTTON_12(5, "12位数字英文带按钮"), - NUMBER_CHINESE_BUTTON_12(6, "12位数字中文带按钮"); + NUMBER_CHINESE_BUTTON_6(6, "6位数字中文带按钮"); private final Integer code; private final String desc; @@ -23,4 +25,21 @@ public enum ETagTypeEnum { this.desc = desc; } + public static ETagTypeEnum getByCode(Integer code) { + for (ETagTypeEnum value : values()) { + if (value.code.equals(code)) { + return value; + } + } + return null; + } + + /** + * 按钮标签列表 + * @return 按钮标签列表 + */ + public static List buttonTagList() { + return List.of(NUMBER_BUTTON_3, NUMBER_BUTTON_7, NUMBER_ENGLISH_BUTTON_12, NUMBER_CHINESE_BUTTON_6); + } + } diff --git a/wcs/src/main/java/org/wcs/constant/enums/etag/EtagSubCommandEnum.java b/wcs/src/main/java/org/wcs/constant/enums/etag/EtagSubCommandEnum.java new file mode 100644 index 0000000..aa7bc6d --- /dev/null +++ b/wcs/src/main/java/org/wcs/constant/enums/etag/EtagSubCommandEnum.java @@ -0,0 +1,25 @@ +package org.wcs.constant.enums.etag; + +import lombok.Getter; + +/** + * 电子标签数据提交的类型枚举 + */ +@Getter +public enum EtagSubCommandEnum { + + CONFIRM_COMMAND(6, "确认键按下提交"), + OUT_STOCK(7, "缺货"), // 注意:当用户修改数据低于发送的数据时,会返回此状态 + CONNECT_TIMEOUT(10, "通讯超时"), + BUTTON_STUCK(13, "按键卡死"), + ERR_INSTRUCTION(12, "指令错误"); + + private Integer code; + private String desc; + + EtagSubCommandEnum(Integer code, String desc) { + this.code = code; + this.desc = desc; + } + +} diff --git a/wcs/src/main/java/org/wcs/constant/enums/etag/LedBlinkingEnum.java b/wcs/src/main/java/org/wcs/constant/enums/etag/LedBlinkingEnum.java new file mode 100644 index 0000000..b1ed4b6 --- /dev/null +++ b/wcs/src/main/java/org/wcs/constant/enums/etag/LedBlinkingEnum.java @@ -0,0 +1,50 @@ +package org.wcs.constant.enums.etag; + +import lombok.Getter; + +/** + * 标签闪烁频率 + */ +@Getter +public enum LedBlinkingEnum { + + LED_OFF(0, "关闭"), + LED_ON(1, "打开,常亮"), + BLINKING_2(2, "2秒闪烁一次"), + BLINKING_1(3, "1秒闪烁一次"), + BLINKING_0_5(4, "0.5秒闪烁一次"), + BLINKING_0_25(5, "0.25秒闪烁一次"); + + private final Integer code; + private final String desc; + + LedBlinkingEnum(Integer code, String desc) { + this.code = code; + this.desc = desc; + } + + public static LedBlinkingEnum getByCode(Integer code) { + for (LedBlinkingEnum value : LedBlinkingEnum.values()) { + if (value.code.equals(code)) { + return value; + } + } + return null; + } + + /** + * 获取闪烁频率对应的二进制字符串 + * @param ledBlinking 闪烁频率 + * @return 二进制字符串 + */ + public static String getBlinkingBitString(LedBlinkingEnum ledBlinking) { + return switch (ledBlinking) { + case LED_OFF -> "000"; + case LED_ON -> "001"; + case BLINKING_2 -> "010"; + case BLINKING_1 -> "011"; + case BLINKING_0_5 -> "100"; + case BLINKING_0_25 -> "101"; + }; + } +} diff --git a/wcs/src/main/java/org/wcs/constant/enums/etag/LedColorEnum.java b/wcs/src/main/java/org/wcs/constant/enums/etag/LedColorEnum.java new file mode 100644 index 0000000..83096a5 --- /dev/null +++ b/wcs/src/main/java/org/wcs/constant/enums/etag/LedColorEnum.java @@ -0,0 +1,54 @@ +package org.wcs.constant.enums.etag; + +import lombok.Getter; + +/** + * 电子标签灯(按钮)颜色 + */ +@Getter +public enum LedColorEnum { + + RED(0, "红色"), + GREEN(1, "绿色"), + ORANGE(2, "橙色"), + BLUE(3, "蓝色"), + PINK(4, "粉色"), + CYAN(5, "青色"); + + private final Integer code; + private final String desc; + + LedColorEnum(Integer code, String desc) { + this.code = code; + this.desc = desc; + } + + + public static LedColorEnum getByCode(Integer code) { + for (LedColorEnum value : LedColorEnum.values()) { + if (value.code.equals(code)) { + return value; + } + } + return null; + } + + /** + * 获取灯颜色对应的二进制字符串 ---- 仅适用于单色灯,需要和其他字符串拼接使用 + * @param ledColor 灯颜色 + * @return 二进制字符串 + */ + public static String getLightColorBitString(LedColorEnum ledColor) { + return switch (ledColor) { + case RED -> "000"; + case GREEN -> "001"; + case ORANGE -> "010"; + case BLUE -> "011"; + case PINK -> "100"; + case CYAN -> "101"; + }; + + } + + +} diff --git a/wcs/src/main/java/org/wcs/mapper/impl/AppEtagControllerInfoDao.java b/wcs/src/main/java/org/wcs/mapper/impl/AppEtagControllerInfoDao.java index 85410c7..896437c 100755 --- a/wcs/src/main/java/org/wcs/mapper/impl/AppEtagControllerInfoDao.java +++ b/wcs/src/main/java/org/wcs/mapper/impl/AppEtagControllerInfoDao.java @@ -65,6 +65,23 @@ public class AppEtagControllerInfoDao extends ServiceImpl queryEtagControllerInfoByStatus(Integer status) { + try { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(AppEtagControllerInfo::getControllerStatus, status); + queryWrapper.orderByAsc(AppEtagControllerInfo::getControllerId); + return baseMapper.selectList(queryWrapper); + } catch (Exception e) { + return null; + } + } + /** * 添加电子标签控制器基础数据 * @param appEtagControllerInfo 添加参数 diff --git a/wcs/src/main/java/org/wcs/mapper/impl/AppEtagTagInfoDao.java b/wcs/src/main/java/org/wcs/mapper/impl/AppEtagTagInfoDao.java index d89bc84..cba5e85 100755 --- a/wcs/src/main/java/org/wcs/mapper/impl/AppEtagTagInfoDao.java +++ b/wcs/src/main/java/org/wcs/mapper/impl/AppEtagTagInfoDao.java @@ -67,6 +67,19 @@ public class AppEtagTagInfoDao extends ServiceImpl queryAll() { + try { + return super.list(); + } catch (Exception e) { + return null; + } + } + /** * 添加电子标签小标签信息 * @param appEtagTagInfo 添加参数 diff --git a/wcs/src/main/java/org/wcs/mapper/impl/AppEtagTagLocationDao.java b/wcs/src/main/java/org/wcs/mapper/impl/AppEtagTagLocationDao.java index afe7ff1..17a7a60 100755 --- a/wcs/src/main/java/org/wcs/mapper/impl/AppEtagTagLocationDao.java +++ b/wcs/src/main/java/org/wcs/mapper/impl/AppEtagTagLocationDao.java @@ -103,6 +103,19 @@ public class AppEtagTagLocationDao extends ServiceImpl queryAll() { + try { + return super.list(); + } catch (Exception e) { + return null; + } + } + /** * 修改电子标签库位信息 * @param appEtagTagLocation 修改参数 diff --git a/wcs/src/main/java/org/wcs/mapper/intf/AppEtagControllerInfoService.java b/wcs/src/main/java/org/wcs/mapper/intf/AppEtagControllerInfoService.java index 97a2c1d..f14f944 100755 --- a/wcs/src/main/java/org/wcs/mapper/intf/AppEtagControllerInfoService.java +++ b/wcs/src/main/java/org/wcs/mapper/intf/AppEtagControllerInfoService.java @@ -11,6 +11,7 @@ public interface AppEtagControllerInfoService extends IService> queryEtagControllerInfo(EtagControllerQueryReq request, Integer pageSize, Integer pageIndex); List queryEtagControllerInfoById(Integer etagControllerId); + List queryEtagControllerInfoByStatus(Integer status); int insertEtagControllerInfo(AppEtagControllerInfo appEtagControllerInfo); // 添加电子标签控制器基础数据 int updateEtagControllerInfo(AppEtagControllerInfo appEtagControllerInfo); // 修改电子标签控制器基础数据 int deleteEtagControllerInfoById(Integer etagControllerId); // 删除电子标签控制器基础数据 diff --git a/wcs/src/main/java/org/wcs/mapper/intf/AppEtagTagInfoService.java b/wcs/src/main/java/org/wcs/mapper/intf/AppEtagTagInfoService.java index f3b0e62..9478154 100755 --- a/wcs/src/main/java/org/wcs/mapper/intf/AppEtagTagInfoService.java +++ b/wcs/src/main/java/org/wcs/mapper/intf/AppEtagTagInfoService.java @@ -15,6 +15,7 @@ public interface AppEtagTagInfoService extends IService { Tuple2> queryEtagTagInfo(EtagTagInfoQueryReq request, Integer pageSize, Integer pageIndex); List queryEtagTagInfoByTagName(String tagName); // 通过标签名称查询 + List queryAll(); // 查询所有 DataBaseActionResult insert(AppEtagTagInfo appEtagTagInfo); // 添加电子标签小标签基础信息 DataBaseActionResult update(AppEtagTagInfo appEtagTagInfo); // 修改电子标签小标签基础信息 DataBaseActionResult deleteByTagName(String tagName); // 删除电子标签小标签基础信息 diff --git a/wcs/src/main/java/org/wcs/mapper/intf/AppEtagTagLocationService.java b/wcs/src/main/java/org/wcs/mapper/intf/AppEtagTagLocationService.java index ba54c93..9f8620b 100755 --- a/wcs/src/main/java/org/wcs/mapper/intf/AppEtagTagLocationService.java +++ b/wcs/src/main/java/org/wcs/mapper/intf/AppEtagTagLocationService.java @@ -14,6 +14,7 @@ public interface AppEtagTagLocationService extends IService List queryWithLocationAndType(String location, Integer locationType); // 查询指定货位和货位类型的数据 DataBaseActionResult insert(AppEtagTagLocation appEtagTagLocation); // 插入一条数据 List queryWithRecordId(String recordId); // 查询指定记录ID的数据 + List queryAll(); // 查询所有数据 DataBaseActionResult updateAll(AppEtagTagLocation appEtagTagLocation); // 更新一条数据 DataBaseActionResult deleteWithRecordId(String recordId); // 删除指定记录ID的数据 } diff --git a/wcs/src/main/java/org/wcs/model/bo/etag/EtagLightParams.java b/wcs/src/main/java/org/wcs/model/bo/etag/EtagLightParams.java new file mode 100644 index 0000000..b05f2b7 --- /dev/null +++ b/wcs/src/main/java/org/wcs/model/bo/etag/EtagLightParams.java @@ -0,0 +1,137 @@ +package org.wcs.model.bo.etag; + +import lombok.Getter; +import lombok.Setter; +import org.wcs.constant.enums.etag.LedBlinkingEnum; +import org.wcs.constant.enums.etag.LedColorEnum; + +/** + * 点亮标签参数 + */ +@Getter +public class EtagLightParams { + + /** + * 标签种类 + */ + private String tagName; + + /** + * 标签ID + */ + @Setter + private byte tagId; + + /** + * 标签值 + */ + private String tagValue; + + /** + * 显示标签字符串 + */ + private String tagString; + + /** + * 闪烁频率 + */ + private LedBlinkingEnum ledBlinking; + + /** + * 灯颜色 + */ + private LedColorEnum ledColor; + + /** + * 构建开始 + * @return 新实例 + */ + public static EtagLightParams buildStart() { + return new EtagLightParams(); + } + + /** + * 设置标签名称 + * @param tagName 标签名称 + * @return 设置结果 + */ + public EtagLightParams tagName(String tagName) { + this.tagName = tagName; + return this; + } + + /** + * 设置标签值 + * @param tagValue 标签值 + * @return 设置结果 + */ + public EtagLightParams tagValue(String tagValue) { + this.tagValue = tagValue; + return this; + } + + /** + * 显示标签字符串 + * @param tagString 标签字符串 + * @return 设置结果 + */ + public EtagLightParams tagString(String tagString) { + this.tagString = tagString; + return this; + } + + /** + * 闪烁频率 + * @param ledBlinking 闪烁频率 + * @return 设置结果 + */ + public EtagLightParams ledBlinking(LedBlinkingEnum ledBlinking) { + this.ledBlinking = ledBlinking; + return this; + } + + /** + * 灯颜色 + * @param ledColor led颜色 + * @return 设置结果 + */ + public EtagLightParams ledColor(LedColorEnum ledColor) { + this.ledColor = ledColor; + return this; + } + + /** + * 构建结束 + * @return 构建结果 + */ + public EtagLightParams buildEnd() { + if(this.tagValue == null) { + this.tagValue = "888"; + } + if(this.tagString == null) { + this.tagString = "未设置文本"; + } + if(this.ledBlinking == null) { + this.ledBlinking = LedBlinkingEnum.BLINKING_0_25; + } + if(this.ledColor == null) { + this.ledColor = LedColorEnum.GREEN; + } + return this; + } + + + @Override + public String toString() { + return "EtagLightParams{" + + "tagName='" + tagName + '\'' + + ", tagId=" + tagId + + ", tagValue='" + tagValue + '\'' + + ", tagString='" + tagString + '\'' + + ", ledBlinking=" + ledBlinking + + ", ledColor=" + ledColor + + '}'; + } + + +} diff --git a/wcs/src/main/java/org/wcs/model/bo/etag/EtagReturnInfo.java b/wcs/src/main/java/org/wcs/model/bo/etag/EtagReturnInfo.java new file mode 100644 index 0000000..67b8658 --- /dev/null +++ b/wcs/src/main/java/org/wcs/model/bo/etag/EtagReturnInfo.java @@ -0,0 +1,73 @@ +package org.wcs.model.bo.etag; + +import lombok.Data; + +/** + * 电子标签数据返回类 + */ +@Data +public class EtagReturnInfo { + + /** + * 控制器 id + */ + private String controllerId; + + + /** + * 按键类型 + * @remark Data(1)= 16H “confirmatin key “ pressed + * /// 43H “shotage button/down-count button” pressed + * /// 25H “function button/up-count button” pressed. + */ + private Integer keyType; + + /** + * 消息类型 + * @remark 01H:Tag busy,04H 功能键 + */ + private Integer msgType; + + /** + * 提交命令 + * @remark 13卡键 + * /// 10 通讯超时 + */ + private Integer subCommand; + + /** + * ip + */ + private String ip; + + /** + * 标签 id + */ + private Integer tagId; + + /** + * 端口,注意这里端口使标签提交的端口,不是控制器的ip端口 + */ + private Integer etagPort; + + /** + * 返回的数据 + */ + private String data; + + + @Override + public String toString() { + return "EtagReturnInfo{" + + "controllerId=" + controllerId + + ", keyType=" + keyType + + ", msgType=" + msgType + + ", subCommand=" + subCommand + + ", ip='" + ip + '\'' + + ", tagId=" + tagId + + ", etagPort=" + etagPort + + ", data='" + data + '\'' + + '}'; + } + +} diff --git a/wcs/src/main/java/org/wcs/plugin/tcp/SocketClient.java b/wcs/src/main/java/org/wcs/plugin/tcp/SocketClient.java index e17965a..3a4670a 100644 --- a/wcs/src/main/java/org/wcs/plugin/tcp/SocketClient.java +++ b/wcs/src/main/java/org/wcs/plugin/tcp/SocketClient.java @@ -46,7 +46,7 @@ public class SocketClient { */ public synchronized void addSocketDataItem(SocketDataItem socketDataItem) { if (socketDataItemList == null) { - socketDataItemList = new java.util.ArrayList<>(); + socketDataItemList = new ArrayList<>(); } List checkExist = socketDataItemList.stream().filter(item -> item.getSocketId().equals(socketDataItem.getSocketId())).toList(); if (!checkExist.isEmpty()) { @@ -113,7 +113,7 @@ public class SocketClient { * 连接Socket * @param socketDataItemList Socket数据项列表 */ - public void connect(List socketDataItemList) { + private void connect(List socketDataItemList) { for (SocketDataItem socketDataItem : socketDataItemList) { Thread thread = new Thread(() -> { connect(socketDataItem); @@ -126,7 +126,7 @@ public class SocketClient { * 连接Socket * @param socketDataItem Socket数据项 */ - public void connect(SocketDataItem socketDataItem) { + private void connect(SocketDataItem socketDataItem) { Socket socket = socketDataItem.getSocket(); if(socket != null) { try { @@ -150,10 +150,11 @@ public class SocketClient { while (true) { try { InputStream inputStream = socket.getInputStream(); - byte[] bytes =inputStream.readAllBytes(); - String message = new String(bytes, StandardCharsets.US_ASCII); + byte[] bytes = inputStream.readAllBytes(); socketDataItem.setLastReceiveMessageTime(LocalDateTime.now()); if(socketClientEvent != null) { + socketClientEvent.onBytes(socketDataItem, bytes); + String message = new String(bytes, StandardCharsets.US_ASCII); socketClientEvent.onMessage(socketDataItem, message); // 触发收到数据事件 } } catch (Exception e) { @@ -178,11 +179,22 @@ public class SocketClient { } } + /** + * 检查并重新连接 + */ + public void checkAndReconnect() { + List disConnectSocketDataItems = getDisConnectSocket(); + if (disConnectSocketDataItems != null) { + connect(disConnectSocketDataItems); + } + } + + /** * 获取断开的Socket数据项 * @return 断开的Socket数据项 */ - public synchronized List getDisConnectSocket() { + private synchronized List getDisConnectSocket() { if(socketDataItemList == null) { return null; } @@ -205,7 +217,10 @@ public class SocketClient { * @param socketDataItem Socket数据项 * @return 是否连接 */ - public boolean isConnected(SocketDataItem socketDataItem) { + private boolean isConnected(SocketDataItem socketDataItem) { + if(socketDataItem.getSocketStatus() == SocketStatusEnum.CONNECTING || socketDataItem.getSocketStatus() == SocketStatusEnum.CREATE) { + return true; // 正在连接或者新创建的视为已连接 + } if(socketDataItem.getSocketStatus() != SocketStatusEnum.CONNECTED || socketDataItem.getSocket() == null) { socketDataItem.setSocketStatus(SocketStatusEnum.DISCONNECTED); return false; @@ -287,14 +302,21 @@ public class SocketClient { if(socketDataItem == null || socketDataItem.getSocket() == null) { return "Socket连接不存在或者未连接"; } - try { - byte[] bytes = message.getBytes(StandardCharsets.US_ASCII); - OutputStream outputStream = socketDataItem.getSocket().getOutputStream(); - outputStream.write(bytes); - outputStream.flush(); - return null; - } catch (Exception e) { - return "发送失败,异常信息:" + e.getMessage(); + Socket socket = socketDataItem.getSocket(); + synchronized (socket) { + try(OutputStream outputStream = socket.getOutputStream()) { + try { + byte[] bytes = message.getBytes(StandardCharsets.US_ASCII); + + outputStream.write(bytes); + outputStream.flush(); + return null; + } catch (Exception e) { + return "发送失败,异常信息:" + e.getMessage(); + } + } catch (IOException e) { + return "发送失败,异常信息:" + e.getMessage(); + } } } @@ -326,13 +348,19 @@ public class SocketClient { if(socketDataItem == null || socketDataItem.getSocket() == null) { return "Socket连接不存在或者未连接"; } - try { - OutputStream outputStream = socketDataItem.getSocket().getOutputStream(); - outputStream.write(bytes); - outputStream.flush(); - return null; - } catch (Exception e) { - return "发送失败,异常信息:" + e.getMessage(); + Socket socket = socketDataItem.getSocket(); + synchronized (socket) { + try (OutputStream outputStream = socket.getOutputStream()) { + try { + outputStream.write(bytes); + outputStream.flush(); + return null; + } catch (Exception e) { + return "发送失败,异常信息:" + e.getMessage(); + } + } catch (Exception e) { + return "发送失败,异常信息:" + e.getMessage(); + } } } diff --git a/wcs/src/main/java/org/wcs/plugin/tcp/intf/ISocketClientEvent.java b/wcs/src/main/java/org/wcs/plugin/tcp/intf/ISocketClientEvent.java index c420528..12ecb6e 100644 --- a/wcs/src/main/java/org/wcs/plugin/tcp/intf/ISocketClientEvent.java +++ b/wcs/src/main/java/org/wcs/plugin/tcp/intf/ISocketClientEvent.java @@ -23,6 +23,13 @@ public interface ISocketClientEvent { */ void onMessage(SocketDataItem socketDataItem, String message); + /** + * 接收到字节 + * @param socketDataItem SocketDataItem + * @param bytes 字节 + */ + void onBytes(SocketDataItem socketDataItem, byte[] bytes); + /** * 错误 * @param socketDataItem SocketDataItem diff --git a/wcs/src/main/java/org/wcs/plugin/tcp/model/SocketDataItem.java b/wcs/src/main/java/org/wcs/plugin/tcp/model/SocketDataItem.java index d2542ce..bb83716 100644 --- a/wcs/src/main/java/org/wcs/plugin/tcp/model/SocketDataItem.java +++ b/wcs/src/main/java/org/wcs/plugin/tcp/model/SocketDataItem.java @@ -76,6 +76,68 @@ public class SocketDataItem { return socketDataItem; } + /** + * 设置SocketId + * @param socketId SocketId + * @return SocketDataItem + */ + public SocketDataItem setSocketId(String socketId) { + this.socketId = socketId; + return this; + } + + /** + * 设置Socket IP + * @param ip Socket IP + * @return SocketDataItem + */ + public SocketDataItem setIp(String ip) { + this.socketIp = ip; + return this; + } + + /** + * 端口 + * @param port 端口 + * @return SocketDataItem + */ + public SocketDataItem setPort(int port) { + this.socketPort = port; + return this; + } + + /** + * 标记 + * @param tag 标记 + * @return SocketDataItem + */ + public SocketDataItem setTag(String tag) { + this.socketTag = tag; + return this; + } + + /** + * 心跳包内容 + * @param heartBeatString 心跳包内容 + * @return SocketDataItem + */ + public SocketDataItem setHeartBeatString(String heartBeatString) { + this.heartBeatString = heartBeatString; + return this; + } + + /** + * 自动重连 + * @param autoReconnect 自动重连 + * @return SocketDataItem + */ + public SocketDataItem setAutoReconnect(boolean autoReconnect) { + this.autoReconnect = autoReconnect; + return this; + } + + + /** * 构建结束 * @return SocketDataItem diff --git a/wcs/src/main/java/org/wcs/quartzJob/EtagJob.java b/wcs/src/main/java/org/wcs/quartzJob/EtagJob.java new file mode 100644 index 0000000..445ce0a --- /dev/null +++ b/wcs/src/main/java/org/wcs/quartzJob/EtagJob.java @@ -0,0 +1,146 @@ +package org.wcs.quartzJob; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.quartz.DisallowConcurrentExecution; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.wcs.business.etag.EtagCommon; +import org.wcs.business.etag.EtagDataHandler; +import org.wcs.business.redis.EtagRedis; +import org.wcs.constant.enums.common.OnOrOffEnum; +import org.wcs.constant.enums.common.TrueOrFalseEnum; +import org.wcs.mapper.intf.AppEtagControllerInfoService; +import org.wcs.mapper.intf.AppEtagTagInfoService; +import org.wcs.mapper.intf.AppEtagTagLocationService; +import org.wcs.model.po.app.AppEtagControllerInfo; +import org.wcs.model.po.app.AppEtagTagInfo; +import org.wcs.model.po.app.AppEtagTagLocation; +import org.wcs.plugin.tcp.SocketClient; +import org.wcs.plugin.tcp.intf.ISocketClientEvent; +import org.wcs.plugin.tcp.model.SocketDataItem; + +import java.util.List; + +/** + * 电子标签定时任务类 + */ +@Slf4j +@DisallowConcurrentExecution +@RequiredArgsConstructor +public class EtagJob implements Job { + + private final EtagRedis etagRedis; // 电子标签 redis 操作类 + private final EtagDataHandler etagDataHandler; // 电子标签数据处理类 + private final AppEtagControllerInfoService etagControllerInfoService; // 控制器信息数据表操作类 + private final AppEtagTagInfoService etagTagInfoService; // 电子标签小标信息数据表操作类 + private final AppEtagTagLocationService etagTagLocationService; // 电子标签位置信息数据表操作类 + + + // 是否正在加载基础数据 + private static boolean isLoadingBaseData = false; + + + @Override + public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { + loadBaseData(); // 加载基础资料 + connectController(); // 连接电子标签控制器 + if(EtagCommon.socketClient == null || !isLoadingBaseData) { + return; + } + + } + + /** + * 点亮小标签 + */ + private void lightSmallTag() { + + } + + + /** + * 加载基础资料 + */ + private void loadBaseData() { + if(isLoadingBaseData) { + return; + } + // 加载基础小标签信息 + List etagTagInfos = etagTagInfoService.queryAll(); + if(etagTagInfos == null) { + return; + } + etagRedis.clearEtagTag(); + for (AppEtagTagInfo etagTagInfo : etagTagInfos) { + etagRedis.setEtagTag(etagTagInfo.getTagName(), etagTagInfo); + } + // 加载基础标签位置信息 + List etagTagLocations = etagTagLocationService.queryAll(); + if(etagTagLocations == null) { + return; + } + etagRedis.clearEtagLocation(); + for (AppEtagTagLocation etagTagLocation : etagTagLocations) { + etagRedis.setEtagLocation(etagTagLocation.getLocation(), etagTagLocation); + } + isLoadingBaseData = true; + } + + /** + * 连接电子标签控制器 + */ + private void connectController() { + if(EtagCommon.socketClient != null) { + EtagCommon.socketClient.checkAndReconnect(); + return; + } + List etagControllerInfoList = etagControllerInfoService.queryEtagControllerInfoByStatus(OnOrOffEnum.TRUE.getCode()); + if(etagControllerInfoList == null) { + return; + } + EtagCommon.socketClient = new SocketClient(); + EtagCommon.socketClient.setSocketClientEvent(new ISocketClientEvent() { + @Override + public void onConnect(SocketDataItem socketDataItem) { + log.info("电子标签控制器:{} 连接成功,IP:{},端口:{}", socketDataItem.getSocketId(), socketDataItem.getSocketIp(), socketDataItem.getSocketPort()); + // TODO 连接成功后应当重新点亮这个控制器下的标签 + } + + @Override + public void onDisconnect(SocketDataItem socketDataItem) { + log.info("电子标签控制器:{} 断开连接,IP:{},端口:{}", socketDataItem.getSocketId(), socketDataItem.getSocketIp(), socketDataItem.getSocketPort()); + } + + @Override + public void onMessage(SocketDataItem socketDataItem, String message) { + } + + @Override + public void onBytes(SocketDataItem socketDataItem, byte[] bytes) { + etagDataHandler.receiveBytes(socketDataItem, bytes); + } + + @Override + public void onError(SocketDataItem socketDataItem, Throwable throwable) { + log.error("电子标签控制器:{} 连接异常,IP:{},端口:{}", socketDataItem.getSocketId(), socketDataItem.getSocketIp(), socketDataItem.getSocketPort(), throwable); + } + }); + for (AppEtagControllerInfo etagControllerInfo : etagControllerInfoList) { + + EtagCommon.socketClient.addSocketDataItem(SocketDataItem.buildStart() + .setSocketId(etagControllerInfo.getControllerId().toString()) + .setIp(etagControllerInfo.getIp()) + .setPort(etagControllerInfo.getPort()) + .setTag(etagControllerInfo.getControllerName()) + .setHeartBeatString("") + .buildEnd()); + } + EtagCommon.socketClient.connectAll(); + } + + + + +} diff --git a/wcs/src/main/java/org/wcs/utils/AppStringUtils.java b/wcs/src/main/java/org/wcs/utils/AppStringUtils.java index d6c7dc4..52ae034 100644 --- a/wcs/src/main/java/org/wcs/utils/AppStringUtils.java +++ b/wcs/src/main/java/org/wcs/utils/AppStringUtils.java @@ -5,6 +5,7 @@ import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.TypeReference; import org.wcs.model.bo.tuple.Tuple2; +import java.io.UnsupportedEncodingException; import java.util.Base64; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -217,4 +218,45 @@ public class AppStringUtils { } + /** + * 将字符串以GBK方式转换 + * @param string 字符串 + * @return 转换结果 + */ + public static byte[] toByteArrayGBK(String string) { + try { + return string.getBytes("GBK"); + } catch (UnsupportedEncodingException e) { + return null; + } + } + + /** + * 在左边补充字符到指定长度 + * @param str 要补充的字符串 + * @param c 补充的字符 + * @param length 长度 + * @return 结果 + */ + public static String padLeft(String str, String c, int length) { + if(isEmpty(str)) { + return c.repeat(length); + } + return c.repeat(Math.max(0, length - str.length())) + str; + } + + /** + * 在右边补充字符到指定长度 + * @param str 要补充的字符串 + * @param c 补充的字符 + * @param length 长度 + * @return 结果 + */ + public static String padRight(String str, String c, int length) { + if(isEmpty(str)) { + return c.repeat(length); + } + return str + c.repeat(Math.max(0, length - str.length())); + } + } diff --git a/wcs/src/main/java/org/wcs/utils/Converter.java b/wcs/src/main/java/org/wcs/utils/Converter.java new file mode 100644 index 0000000..e4ef7af --- /dev/null +++ b/wcs/src/main/java/org/wcs/utils/Converter.java @@ -0,0 +1,39 @@ +package org.wcs.utils; + +/** + * 数据转换类 + */ +public class Converter { + + /** + * int转byte + * @param value int值 + * @return byte值 + */ + public static byte toByte(int value) { + if(value < Byte.MIN_VALUE || value > Byte.MAX_VALUE){ + throw new IllegalArgumentException("value is not in byte range"); + } + return (byte) value; + } + + /** + * 二进制字符串转 byte + * @param value 二进制字符串 + * @return byte值 + */ + public static byte toByte(String value) { + int intValue = Integer.parseInt(value, 2); + return toByte(intValue); + } + + /** + * byte转二进制字符串 + * @param value byte值 + * @return 转换过后的二进制字符串 + */ + public static String toBinaryString(byte value) { + String binaryString = Integer.toBinaryString(value & 0xFF); + return String.format("%8s", binaryString).replace(' ', '0'); + } +}