From 2194a05ea3f71238c0ecab4b5b459cc206b9b930 Mon Sep 17 00:00:00 2001 From: bitkylin Date: Thu, 20 Jul 2017 16:28:57 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E5=AE=8C=E5=96=84=20README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e658d64..bdd19c7 100644 --- a/README.md +++ b/README.md @@ -43,23 +43,34 @@ Java 后端项目,大规模集群设备的管理平台,使用 Spring 作为 - 采用 Redis 作为数据库的缓存,极大提升数据库的使用效率,并将服务器对帧的处理效率提升2个数量级以上。 +### Netty 服务器设计方案 + +本节内容总结为以下文章,点击查看: + +[基于 Netty 的自定义帧高可靠性读取方案](http://www.jianshu.com/p/7b1010e7e293) + ### 帧调度算法概述 >本节介绍 Java 服务器中,Netty 模块使用的帧调度算法,由于众多硬件设备的**数据帧处理能力较差**,**可靠性较差**,服务器大规模下发数据帧时,需进行有效的**拥塞控制、超时重发**,可有效提升集群设备的可靠性,降低集群设备的研发难度。 内容较多,这部分内容被放在了独立博文中,请使用如下链接查看: -|来源|网址| -|---|---| -|简书|http://www.jianshu.com/p/c5da14855515| -|主页|http://bitky.cc/2017/07/19/java/| +[基于 Netty 的帧调度策略,自行实现流量控制及可靠性通信](http://www.jianshu.com/p/c5da14855515) -**「注」**本部分为源码「Netty服务器」部分的解释说明,需结合源码进行阅读。 +「注」本部分为源码「Netty服务器」部分的解释说明,需结合源码进行阅读。 ## JavaFX 设备模拟客户端 基于 JavaFX 开发 GUI 客户端,模拟集群设备的行为,并可对服务器进行压力测试。 +本程序开发时,相关技巧和填坑总结为以下文章: + +[JavaFX 8 下简化自定义控件的外部调用以及流式布局示例](http://www.jianshu.com/p/9b5300b44f39) + +[Maven 集成 JavaFX 8 以及 问题探讨](http://www.jianshu.com/p/fce816babefc) + + + ### 模拟客户端主界面 ![模拟客户端主界面](./mdphoto/main21.jpg) From 32897c1f7e57922d0e2420c6fe46efca822cdc87 Mon Sep 17 00:00:00 2001 From: bitkylin Date: Thu, 20 Jul 2017 16:32:29 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E7=BB=86=E8=8A=82=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- clustermanage-server/.gitignore | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bdd19c7..256e4ae 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Java 后端项目,大规模集群设备的管理平台,使用 Spring 作为 [JavaFX 8 下简化自定义控件的外部调用以及流式布局示例](http://www.jianshu.com/p/9b5300b44f39) -[Maven 集成 JavaFX 8 以及 问题探讨](http://www.jianshu.com/p/fce816babefc) +[Maven 集成 JavaFX 8 以及 fx:root 问题探讨](http://www.jianshu.com/p/fce816babefc) diff --git a/clustermanage-server/.gitignore b/clustermanage-server/.gitignore index 9acd70e..d31078f 100644 --- a/clustermanage-server/.gitignore +++ b/clustermanage-server/.gitignore @@ -1,3 +1,6 @@ +运行/ + + target/ .mvn/ From be7e6fac9708f00880d46c582c3b80aab69f4d8a Mon Sep 17 00:00:00 2001 From: bitkylin Date: Mon, 24 Jul 2017 22:00:13 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E4=BC=98=E5=8C=96=E3=80=8C=E5=89=A9?= =?UTF-8?q?=E4=BD=99=E5=85=85=E7=94=B5=E6=AC=A1=E6=95=B0=E3=80=8D=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../db/presenter/DbDevicePresenter.java | 6 +- .../db/presenter/KyDbPresenter.java | 2 +- .../server/bean/KyServerCenterHandler.java | 4 ++ .../server/bean/ServerTcpMessageHandler.java | 8 ++- .../server/bean/ServerWebMessageHandler.java | 51 +++++++++------ .../web/OperateRestController.java | 5 +- .../clustermanage/web/bean/QueueDevice.java | 64 +++++++++++++++++++ 7 files changed, 112 insertions(+), 28 deletions(-) create mode 100644 clustermanage-server/src/main/java/cc/bitky/clustermanage/web/bean/QueueDevice.java diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/db/presenter/DbDevicePresenter.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/db/presenter/DbDevicePresenter.java index 02e7a85..4bcc873 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/db/presenter/DbDevicePresenter.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/db/presenter/DbDevicePresenter.java @@ -64,7 +64,7 @@ Device handleMsgDeviceStatus(TcpMsgResponseStatus msgStatus) { return device; } - if (rawStatus == 2 && newStatus == 3) { + if (rawStatus == 2 && newStatus == 3 && device.getRemainChargeTime() > 0) { device.setRemainChargeTime(device.getRemainChargeTime() - 1); } device.setStatus(newStatus); @@ -78,8 +78,8 @@ Device handleMsgDeviceStatus(TcpMsgResponseStatus msgStatus) { /** * 获取设备的集合 * - * @param groupId 组 Id - * @param deviceId 设备 Id + * @param groupId 组 Id + * @param deviceId 设备 Id * @return 设备的集合 */ List getDevices(int groupId, int deviceId) { diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/db/presenter/KyDbPresenter.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/db/presenter/KyDbPresenter.java index c738327..f9d9f50 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/db/presenter/KyDbPresenter.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/db/presenter/KyDbPresenter.java @@ -135,7 +135,7 @@ public Device handleMsgDeviceStatus(TcpMsgResponseStatus tcpMsgResponseStatus, b logger.info("无指定设备对应的员工和考勤表,且无法自动创建"); } long l5 = System.currentTimeMillis(); - logger.info("时间耗费:" + (l2 - l1) + "ms; " + (l3 - l2) + "ms; " + (l4 - l3) + "ms; " + (l5 - l4) + "ms"); + logger.info("时间耗费:" + (l2 - l1) + "ms; " + (l3 - l2) + "ms; " + (l4 - l3) + "ms; " + (l5 - l4) + "ms"); return device; } diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/bean/KyServerCenterHandler.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/bean/KyServerCenterHandler.java index b76d6dc..4003174 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/bean/KyServerCenterHandler.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/bean/KyServerCenterHandler.java @@ -135,6 +135,10 @@ boolean marchConfirmCard(String cardNumber) { return kyDbPresenter.marchConfirmCard(cardNumber); } + /** + * 获取 CAN 帧发送队列的信息 + * @return CAN帧发送队列信息集合 + */ QueueInfo obtainQueueFrame() { int size = getSendingMsgRepo().getLinkedBlockingDeque().size(); int capacity = ServerSetting.LINKED_DEQUE_LIMIT_CAPACITY; diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/bean/ServerTcpMessageHandler.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/bean/ServerTcpMessageHandler.java index 874153d..7e8e591 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/bean/ServerTcpMessageHandler.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/bean/ServerTcpMessageHandler.java @@ -54,6 +54,7 @@ public void handleResDeviceStatus(TcpMsgResponseStatus message) { logger.info("收到:设备状态请求的回复"); long l1 = System.currentTimeMillis(); Device device = kyDbPresenter.handleMsgDeviceStatus(message, ServerSetting.AUTO_CREATE_DEVICE_EMPLOYEE); + //部署剩余充电次数 if (device != null) { deployRemainChargeTimes(device); } @@ -63,7 +64,6 @@ public void handleResDeviceStatus(TcpMsgResponseStatus message) { /** * 其他功能消息处理方法 - * */ public void handleTcpMsg() { @@ -74,11 +74,13 @@ public void handleTcpMsg() { * * @param device 处理后的 Device */ - private void deployRemainChargeTimes(Device device) { - if (device.getRemainChargeTime() <= ServerSetting.DEPLOY_REMAIN_CHARGE_TIMES) { + + //当当前充电状态为「充满」,并且剩余充电次数小于或等于阈值时,部署剩余充电次数 + if (device.getStatus() == 3 && device.getRemainChargeTime() <= ServerSetting.DEPLOY_REMAIN_CHARGE_TIMES) { int remainTimes = device.getRemainChargeTime(); remainTimes = remainTimes > 0 ? remainTimes : 0; + remainTimes = remainTimes <= 100 ? remainTimes : 100; sendMsgToTcpSpecial(new WebMsgDeployRemainChargeTimes(device.getGroupId(), device.getDeviceId(), remainTimes), true, true); } } diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/bean/ServerWebMessageHandler.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/bean/ServerWebMessageHandler.java index eb09c59..772c3d2 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/bean/ServerWebMessageHandler.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/bean/ServerWebMessageHandler.java @@ -14,6 +14,8 @@ import cc.bitky.clustermanage.server.message.web.WebMsgDeployEmployeeCardNumber; import cc.bitky.clustermanage.server.message.web.WebMsgDeployEmployeeDepartment; import cc.bitky.clustermanage.server.message.web.WebMsgDeployEmployeeName; +import cc.bitky.clustermanage.server.message.web.WebMsgDeployRemainChargeTimes; +import cc.bitky.clustermanage.web.bean.QueueDevice; import cc.bitky.clustermanage.web.bean.QueueInfo; @Service @@ -94,62 +96,72 @@ public boolean saveCardNumber(String[] freeCards, CardType card) { /** * 从数据库中获取并更新设备的信息 * - * @param groupId 设备组 ID - * @param deviceId 设备 ID - * @param name 是否更新姓名 - * @param department 是否更新部门 - * @param cardNumber 是否更新卡号 - * @param maxGroupId 若更新多个设备组,可指定更新设备组的 ID 范围为: 1 - maxgroupId + * @param groupId 设备组 ID + * @param deviceId 设备 ID + * @param queueDevice 需要部署的设备信息 + * @param maxGroupId 若更新多个设备组,可指定更新设备组的 ID 范围为: 1 - maxGroupId * @return 更新是否成功 */ - public boolean obtainDeployDeviceMsg(int groupId, int deviceId, boolean name, boolean department, boolean cardNumber, int maxGroupId) { + public boolean obtainDeployDeviceMsg(int groupId, int deviceId, QueueDevice queueDevice, int maxGroupId) { if (groupId == 255 || groupId == 0) { if (maxGroupId == 0) maxGroupId = kyDbPresenter.obtainDeviceGroupCount(); if (maxGroupId == 0) return false; for (int i = 1; i <= maxGroupId; i++) { - getDeviceInfo(i, deviceId).forEach(device -> deployEmployeeMsg(name, department, cardNumber, device)); + getDeviceInfo(i, deviceId).forEach(device -> deployEmployeeMsg(queueDevice, device)); } } else getDeviceInfo(groupId, deviceId) - .forEach(device -> deployEmployeeMsg(name, department, cardNumber, device)); + .forEach(device -> deployEmployeeMsg(queueDevice, device)); return true; } /** * 部署员工的姓名,单位,卡号 * - * @param name 员工的姓名 - * @param department 员工的部门 - * @param cardNumber 员工的卡号 - * @param device 员工对应的设备 + * @param device 员工对应的设备 + * @param queueDevice 需要部署的设备信息 */ - private void deployEmployeeMsg(boolean name, boolean department, boolean cardNumber, Device device) { + private void deployEmployeeMsg(QueueDevice queueDevice, Device device) { + boolean name = queueDevice.isPostName(); + boolean department = queueDevice.isPostDepartment(); + boolean cardNumber = queueDevice.isPostCardNumber(); + boolean remainChargeTime = queueDevice.isPostRemainChargeTime(); - boolean autoInit = ServerSetting.DEPLOY_DEVICES_INIT; + boolean AUTO_INIT = ServerSetting.DEPLOY_DEVICES_INIT; if (device == null) return; + //部署卡号 if (cardNumber && device.getCardNumber() != null) kyServerCenterHandler.sendMsgTrafficControl(new WebMsgDeployEmployeeCardNumber(device.getGroupId(), device.getDeviceId(), device.getCardNumber())); - else if (cardNumber && autoInit) + else if (cardNumber && AUTO_INIT) kyServerCenterHandler.sendMsgTrafficControl(new WebMsgDeployEmployeeCardNumber(device.getGroupId(), device.getDeviceId(), ServerSetting.DEFAULT_EMPLOYEE_CARD_NUMBER)); + //部署剩余充电次数 + if (remainChargeTime) { + int remainTimes = device.getRemainChargeTime(); + remainTimes = remainTimes > 0 ? remainTimes : 0; + remainTimes = remainTimes <= 100 ? remainTimes : 100; + kyServerCenterHandler.sendMsgTrafficControl(new WebMsgDeployRemainChargeTimes(device.getGroupId(), device.getDeviceId(), remainTimes)); + } + //部署姓名和单位 if (!(name || department)) return; Employee employee = kyDbPresenter.obtainEmployeeByEmployeeObjectId(device.getEmployeeObjectId()); if (employee != null) { if (name && employee.getName() != null) kyServerCenterHandler.sendMsgTrafficControl(new WebMsgDeployEmployeeName(device.getGroupId(), device.getDeviceId(), employee.getName())); - else if (name && autoInit) + else if (name && AUTO_INIT) kyServerCenterHandler.sendMsgTrafficControl(new WebMsgDeployEmployeeName(device.getGroupId(), device.getDeviceId(), ServerSetting.DEFAULT_EMPLOYEE_NAME)); + if (department && employee.getDepartment() != null) kyServerCenterHandler.sendMsgTrafficControl(new WebMsgDeployEmployeeDepartment(device.getGroupId(), device.getDeviceId(), employee.getDepartment())); - else if (department && autoInit) + else if (department && AUTO_INIT) kyServerCenterHandler.sendMsgTrafficControl(new WebMsgDeployEmployeeDepartment(device.getGroupId(), device.getDeviceId(), ServerSetting.DEFAULT_EMPLOYEE_DEPARTMENT)); - } else if (autoInit) { + } else if (AUTO_INIT) { if (name) kyServerCenterHandler.sendMsgTrafficControl(new WebMsgDeployEmployeeName(device.getGroupId(), device.getDeviceId(), ServerSetting.DEFAULT_EMPLOYEE_NAME)); if (department) @@ -159,6 +171,5 @@ else if (department && autoInit) public QueueInfo obtainQueueFrame() { return kyServerCenterHandler.obtainQueueFrame(); - } } diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/web/OperateRestController.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/web/OperateRestController.java index 6dece74..aaf367a 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/web/OperateRestController.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/web/OperateRestController.java @@ -12,6 +12,7 @@ import cc.bitky.clustermanage.server.message.CardType; import cc.bitky.clustermanage.server.message.web.WebMsgInitClearDeviceStatus; import cc.bitky.clustermanage.server.message.web.WebMsgOperateBoxUnlock; +import cc.bitky.clustermanage.web.bean.QueueDevice; @RestController @RequestMapping(value = "/operate") @@ -32,6 +33,7 @@ public OperateRestController(ServerWebMessageHandler serverWebMessageHandler) { * @param name 是否更新姓名 * @param department 是否更新部门 * @param cardnumber 是否更新卡号 + * @param remainchargetime 是否更新剩余充电次数 * @param maxgroupid 若更新多个设备组,可指定更新设备组的 ID 范围为: 1 - maxgroupId * @return 更新是否成功 */ @@ -41,8 +43,9 @@ public String updateDevices(@PathVariable int groupId, @RequestParam(required = false) boolean name, @RequestParam(required = false) boolean department, @RequestParam(required = false) boolean cardnumber, + @RequestParam(required = false) boolean remainchargetime, @RequestParam(defaultValue = "0") int maxgroupid) { - if (serverWebMessageHandler.obtainDeployDeviceMsg(groupId, deviceId, name, department, cardnumber, maxgroupid)) + if (serverWebMessageHandler.obtainDeployDeviceMsg(groupId, deviceId, new QueueDevice(name, department, cardnumber, remainchargetime), maxgroupid)) return "success"; else return "error"; } diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/web/bean/QueueDevice.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/web/bean/QueueDevice.java new file mode 100644 index 0000000..1a295a8 --- /dev/null +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/web/bean/QueueDevice.java @@ -0,0 +1,64 @@ +package cc.bitky.clustermanage.web.bean; + +/** + * 选择是否部署设备中的信息 + */ +public class QueueDevice { + + /** + * 部署姓名 + */ + private boolean postName; + /** + * 部署单位 + */ + private boolean postDepartment; + /** + * 部署卡号 + */ + private boolean postCardNumber; + /** + * 部署剩余充电次数 + */ + private boolean postRemainChargeTime; + + public QueueDevice(boolean postName, boolean postDepartment, boolean postCardNumber, boolean postRemainChargeTime) { + this.postName = postName; + this.postDepartment = postDepartment; + this.postCardNumber = postCardNumber; + this.postRemainChargeTime = postRemainChargeTime; + } + + + public boolean isPostName() { + return postName; + } + + public void setPostName(boolean postName) { + this.postName = postName; + } + + public boolean isPostDepartment() { + return postDepartment; + } + + public void setPostDepartment(boolean postDepartment) { + this.postDepartment = postDepartment; + } + + public boolean isPostCardNumber() { + return postCardNumber; + } + + public void setPostCardNumber(boolean postCardNumber) { + this.postCardNumber = postCardNumber; + } + + public boolean isPostRemainChargeTime() { + return postRemainChargeTime; + } + + public void setPostRemainChargeTime(boolean postRemainChargeTime) { + this.postRemainChargeTime = postRemainChargeTime; + } +} From 910440a4045b5a6f7ac4b99b8efc4a9aba4de13f Mon Sep 17 00:00:00 2001 From: bitkylin Date: Wed, 26 Jul 2017 14:21:47 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=A1=AC=E4=BB=B6?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E5=8D=95=E6=9D=BF=E6=B5=8B=E8=AF=95=E8=BD=AF?= =?UTF-8?q?=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hardware/SingleDeviceTestNET/.gitignore | 275 ++++++++ .../SingleDeviceTestNET/SingleDeviceTest.sln | 22 + .../SingleDeviceTestNET/App.config | 6 + .../SingleDeviceTestNET/Form1.Designer.cs | 600 ++++++++++++++++++ .../SingleDeviceTestNET/Form1.cs | 271 ++++++++ .../SingleDeviceTestNET/Form1.resx | 123 ++++ .../SingleDeviceTestNET/Program.cs | 19 + .../Properties/AssemblyInfo.cs | 35 + .../Properties/Resources.Designer.cs | 63 ++ .../Properties/Resources.resx | 117 ++++ .../Properties/Settings.Designer.cs | 26 + .../Properties/Settings.settings | 7 + .../SingleDeviceTestNET.csproj | 144 +++++ .../message/WebMsgOperateBoxUnlock.cs | 13 + .../message/base/BaseMessage.cs | 51 ++ .../message/base/IMessage.cs | 15 + .../SingleDeviceTestNET/utils/CanBuilder.cs | 70 ++ .../SingleDeviceTestNET/utils/MsgType.cs | 126 ++++ .../utils/TcpMsgBuilder.cs | 272 ++++++++ 19 files changed, 2255 insertions(+) create mode 100644 hardware/SingleDeviceTestNET/.gitignore create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTest.sln create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTestNET/App.config create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTestNET/Form1.Designer.cs create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTestNET/Form1.cs create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTestNET/Form1.resx create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTestNET/Program.cs create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/AssemblyInfo.cs create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/Resources.Designer.cs create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/Resources.resx create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/Settings.Designer.cs create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/Settings.settings create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTestNET/SingleDeviceTestNET.csproj create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTestNET/message/WebMsgOperateBoxUnlock.cs create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTestNET/message/base/BaseMessage.cs create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTestNET/message/base/IMessage.cs create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTestNET/utils/CanBuilder.cs create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTestNET/utils/MsgType.cs create mode 100644 hardware/SingleDeviceTestNET/SingleDeviceTestNET/utils/TcpMsgBuilder.cs diff --git a/hardware/SingleDeviceTestNET/.gitignore b/hardware/SingleDeviceTestNET/.gitignore new file mode 100644 index 0000000..cc49c60 --- /dev/null +++ b/hardware/SingleDeviceTestNET/.gitignore @@ -0,0 +1,275 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates +*.vcxproj.filters + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ +**/Properties/launchSettings.json + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/ \ No newline at end of file diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTest.sln b/hardware/SingleDeviceTestNET/SingleDeviceTest.sln new file mode 100644 index 0000000..ee87fdc --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTest.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SingleDeviceTestNET", "SingleDeviceTestNET\SingleDeviceTestNET.csproj", "{5E0C4B0F-13FF-47E3-B951-A2457DF0BC25}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {5E0C4B0F-13FF-47E3-B951-A2457DF0BC25}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5E0C4B0F-13FF-47E3-B951-A2457DF0BC25}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5E0C4B0F-13FF-47E3-B951-A2457DF0BC25}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5E0C4B0F-13FF-47E3-B951-A2457DF0BC25}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTestNET/App.config b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/App.config new file mode 100644 index 0000000..72a71af --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Form1.Designer.cs b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Form1.Designer.cs new file mode 100644 index 0000000..990ad70 --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Form1.Designer.cs @@ -0,0 +1,600 @@ +namespace SocketServer +{ + partial class FormSocketServer + { + /// + /// 必需的设计器变量。 + /// + private System.ComponentModel.IContainer components = null; + + /// + /// 清理所有正在使用的资源。 + /// + /// 如果应释放托管资源,为 true;否则为 false。 + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows 窗体设计器生成的代码 + + /// + /// 设计器支持所需的方法 - 不要修改 + /// 使用代码编辑器修改此方法的内容。 + /// + private void InitializeComponent() + { + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.groupBox8 = new System.Windows.Forms.GroupBox(); + this.btnClearControlText = new System.Windows.Forms.Button(); + this.btnClearCommunicateText = new System.Windows.Forms.Button(); + this.groupBox7 = new System.Windows.Forms.GroupBox(); + this.label3 = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.comboBaudrate = new System.Windows.Forms.ComboBox(); + this.comboPortName = new System.Windows.Forms.ComboBox(); + this.btnSerialPortOpenClose = new System.Windows.Forms.Button(); + this.groupBox5 = new System.Windows.Forms.GroupBox(); + this.label4 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.labelServerStartOrEnd = new System.Windows.Forms.Label(); + this.MessageIPAndPort = new System.Windows.Forms.Label(); + this.groupBox6 = new System.Windows.Forms.GroupBox(); + this.lstControlText = new System.Windows.Forms.ListBox(); + this.lstServerCommunicationText = new System.Windows.Forms.ListBox(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.btnUpdateDeviceId = new System.Windows.Forms.Button(); + this.LabelUpdateDeviceId = new System.Windows.Forms.Label(); + this.labelUpdateChargeStatus = new System.Windows.Forms.Label(); + this.btnUpdateChargeStatus = new System.Windows.Forms.Button(); + this.labelUpdateUnLock = new System.Windows.Forms.Label(); + this.btnUpdateUnLock = new System.Windows.Forms.Button(); + this.labelUpdateName = new System.Windows.Forms.Label(); + this.btnUpdateName = new System.Windows.Forms.Button(); + this.labelUpdateDepartment = new System.Windows.Forms.Label(); + this.btnUpdateDepartment = new System.Windows.Forms.Button(); + this.labelUpdateCardNumber = new System.Windows.Forms.Label(); + this.btnUpdateCardNumber = new System.Windows.Forms.Button(); + this.labelUpdateFreeCard = new System.Windows.Forms.Label(); + this.btnUpdateFreeCard = new System.Windows.Forms.Button(); + this.labelUpdateDepartment2 = new System.Windows.Forms.Label(); + this.btnUpdateDepartment2 = new System.Windows.Forms.Button(); + this.labelRemainTimes = new System.Windows.Forms.Label(); + this.btnRemainTimes = new System.Windows.Forms.Button(); + this.labelRemainTimes2 = new System.Windows.Forms.Label(); + this.btnRemainTimes2 = new System.Windows.Forms.Button(); + this.groupBox1.SuspendLayout(); + this.groupBox8.SuspendLayout(); + this.groupBox7.SuspendLayout(); + this.groupBox5.SuspendLayout(); + this.groupBox6.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.SuspendLayout(); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.groupBox8); + this.groupBox1.Controls.Add(this.groupBox7); + this.groupBox1.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.groupBox1.Location = new System.Drawing.Point(12, 12); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(224, 398); + this.groupBox1.TabIndex = 2; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "功能区"; + // + // groupBox8 + // + this.groupBox8.Controls.Add(this.btnClearControlText); + this.groupBox8.Controls.Add(this.btnClearCommunicateText); + this.groupBox8.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.groupBox8.Location = new System.Drawing.Point(6, 172); + this.groupBox8.Name = "groupBox8"; + this.groupBox8.Size = new System.Drawing.Size(209, 112); + this.groupBox8.TabIndex = 4; + this.groupBox8.TabStop = false; + this.groupBox8.Text = "信息清空"; + // + // btnClearControlText + // + this.btnClearControlText.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnClearControlText.Location = new System.Drawing.Point(82, 66); + this.btnClearControlText.Name = "btnClearControlText"; + this.btnClearControlText.Size = new System.Drawing.Size(110, 35); + this.btnClearControlText.TabIndex = 1; + this.btnClearControlText.Text = "清空控制信息"; + this.btnClearControlText.UseVisualStyleBackColor = true; + this.btnClearControlText.Click += new System.EventHandler(this.btnClearControlText_Click); + // + // btnClearCommunicateText + // + this.btnClearCommunicateText.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnClearCommunicateText.Location = new System.Drawing.Point(82, 25); + this.btnClearCommunicateText.Name = "btnClearCommunicateText"; + this.btnClearCommunicateText.Size = new System.Drawing.Size(110, 35); + this.btnClearCommunicateText.TabIndex = 2; + this.btnClearCommunicateText.Text = "清空通信信息"; + this.btnClearCommunicateText.UseVisualStyleBackColor = true; + this.btnClearCommunicateText.Click += new System.EventHandler(this.btnClearText_Click); + // + // groupBox7 + // + this.groupBox7.Controls.Add(this.label3); + this.groupBox7.Controls.Add(this.label1); + this.groupBox7.Controls.Add(this.comboBaudrate); + this.groupBox7.Controls.Add(this.comboPortName); + this.groupBox7.Controls.Add(this.btnSerialPortOpenClose); + this.groupBox7.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.groupBox7.Location = new System.Drawing.Point(6, 26); + this.groupBox7.Name = "groupBox7"; + this.groupBox7.Size = new System.Drawing.Size(209, 140); + this.groupBox7.TabIndex = 4; + this.groupBox7.TabStop = false; + this.groupBox7.Text = "串口控制"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.label3.Location = new System.Drawing.Point(5, 64); + this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(69, 20); + this.label3.TabIndex = 8; + this.label3.Text = "波特率:"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.label1.Location = new System.Drawing.Point(5, 28); + this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(69, 20); + this.label1.TabIndex = 7; + this.label1.Text = "串口名:"; + // + // comboBaudrate + // + this.comboBaudrate.BackColor = System.Drawing.Color.White; + this.comboBaudrate.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboBaudrate.FlatStyle = System.Windows.Forms.FlatStyle.Popup; + this.comboBaudrate.FormattingEnabled = true; + this.comboBaudrate.Items.AddRange(new object[] { + "2400", + "4800", + "9600", + "19200", + "38400", + "57600", + "115200"}); + this.comboBaudrate.Location = new System.Drawing.Point(82, 61); + this.comboBaudrate.Margin = new System.Windows.Forms.Padding(4); + this.comboBaudrate.Name = "comboBaudrate"; + this.comboBaudrate.Size = new System.Drawing.Size(110, 28); + this.comboBaudrate.TabIndex = 6; + // + // comboPortName + // + this.comboPortName.BackColor = System.Drawing.Color.White; + this.comboPortName.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.comboPortName.FlatStyle = System.Windows.Forms.FlatStyle.Popup; + this.comboPortName.FormattingEnabled = true; + this.comboPortName.Location = new System.Drawing.Point(82, 25); + this.comboPortName.Margin = new System.Windows.Forms.Padding(4); + this.comboPortName.Name = "comboPortName"; + this.comboPortName.Size = new System.Drawing.Size(110, 28); + this.comboPortName.TabIndex = 5; + // + // btnSerialPortOpenClose + // + this.btnSerialPortOpenClose.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnSerialPortOpenClose.Location = new System.Drawing.Point(95, 99); + this.btnSerialPortOpenClose.Name = "btnSerialPortOpenClose"; + this.btnSerialPortOpenClose.Size = new System.Drawing.Size(97, 35); + this.btnSerialPortOpenClose.TabIndex = 1; + this.btnSerialPortOpenClose.Text = "打开串口"; + this.btnSerialPortOpenClose.UseVisualStyleBackColor = true; + this.btnSerialPortOpenClose.Click += new System.EventHandler(this.buttonOpenClose_Click); + // + // groupBox5 + // + this.groupBox5.Controls.Add(this.label4); + this.groupBox5.Controls.Add(this.label2); + this.groupBox5.Controls.Add(this.labelServerStartOrEnd); + this.groupBox5.Controls.Add(this.MessageIPAndPort); + this.groupBox5.Location = new System.Drawing.Point(12, 313); + this.groupBox5.Name = "groupBox5"; + this.groupBox5.Size = new System.Drawing.Size(215, 90); + this.groupBox5.TabIndex = 4; + this.groupBox5.TabStop = false; + this.groupBox5.Text = "信息"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.label4.Location = new System.Drawing.Point(6, 23); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(84, 20); + this.label4.TabIndex = 3; + this.label4.Text = "服务状态:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.label2.Location = new System.Drawing.Point(8, 53); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(69, 20); + this.label2.TabIndex = 1; + this.label2.Text = "客户端:"; + // + // labelServerStartOrEnd + // + this.labelServerStartOrEnd.AutoSize = true; + this.labelServerStartOrEnd.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.labelServerStartOrEnd.Location = new System.Drawing.Point(96, 23); + this.labelServerStartOrEnd.Name = "labelServerStartOrEnd"; + this.labelServerStartOrEnd.Size = new System.Drawing.Size(84, 20); + this.labelServerStartOrEnd.TabIndex = 2; + this.labelServerStartOrEnd.Text = "服务未开启"; + // + // MessageIPAndPort + // + this.MessageIPAndPort.AutoSize = true; + this.MessageIPAndPort.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.MessageIPAndPort.Location = new System.Drawing.Point(96, 53); + this.MessageIPAndPort.Name = "MessageIPAndPort"; + this.MessageIPAndPort.Size = new System.Drawing.Size(84, 20); + this.MessageIPAndPort.TabIndex = 0; + this.MessageIPAndPort.Text = "无状态信息"; + // + // groupBox6 + // + this.groupBox6.Controls.Add(this.lstControlText); + this.groupBox6.Location = new System.Drawing.Point(12, 416); + this.groupBox6.Name = "groupBox6"; + this.groupBox6.Size = new System.Drawing.Size(345, 125); + this.groupBox6.TabIndex = 4; + this.groupBox6.TabStop = false; + this.groupBox6.Text = "控制信息"; + // + // lstControlText + // + this.lstControlText.FormattingEnabled = true; + this.lstControlText.HorizontalScrollbar = true; + this.lstControlText.ItemHeight = 20; + this.lstControlText.Location = new System.Drawing.Point(6, 26); + this.lstControlText.Name = "lstControlText"; + this.lstControlText.Size = new System.Drawing.Size(333, 124); + this.lstControlText.TabIndex = 0; + // + // lstServerCommunicationText + // + this.lstServerCommunicationText.FormattingEnabled = true; + this.lstServerCommunicationText.HorizontalScrollbar = true; + this.lstServerCommunicationText.ItemHeight = 20; + this.lstServerCommunicationText.Location = new System.Drawing.Point(6, 26); + this.lstServerCommunicationText.Name = "lstServerCommunicationText"; + this.lstServerCommunicationText.Size = new System.Drawing.Size(365, 624); + this.lstServerCommunicationText.TabIndex = 0; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.lstServerCommunicationText); + this.groupBox2.Location = new System.Drawing.Point(443, 12); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(377, 529); + this.groupBox2.TabIndex = 3; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "通信信息"; + // + // btnUpdateDeviceId + // + this.btnUpdateDeviceId.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnUpdateDeviceId.Location = new System.Drawing.Point(242, 26); + this.btnUpdateDeviceId.Name = "btnUpdateDeviceId"; + this.btnUpdateDeviceId.Size = new System.Drawing.Size(115, 33); + this.btnUpdateDeviceId.TabIndex = 1; + this.btnUpdateDeviceId.Text = "更换柜号"; + this.btnUpdateDeviceId.UseVisualStyleBackColor = true; + this.btnUpdateDeviceId.Click += new System.EventHandler(this.btnUpdateDeviceId_Click); + // + // LabelUpdateDeviceId + // + this.LabelUpdateDeviceId.AutoSize = true; + this.LabelUpdateDeviceId.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.LabelUpdateDeviceId.Location = new System.Drawing.Point(363, 32); + this.LabelUpdateDeviceId.Name = "LabelUpdateDeviceId"; + this.LabelUpdateDeviceId.Size = new System.Drawing.Size(33, 20); + this.LabelUpdateDeviceId.TabIndex = 2; + this.LabelUpdateDeviceId.Text = " "; + // + // labelUpdateChargeStatus + // + this.labelUpdateChargeStatus.AutoSize = true; + this.labelUpdateChargeStatus.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.labelUpdateChargeStatus.Location = new System.Drawing.Point(363, 383); + this.labelUpdateChargeStatus.Name = "labelUpdateChargeStatus"; + this.labelUpdateChargeStatus.Size = new System.Drawing.Size(33, 20); + this.labelUpdateChargeStatus.TabIndex = 2; + this.labelUpdateChargeStatus.Text = " "; + // + // btnUpdateChargeStatus + // + this.btnUpdateChargeStatus.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnUpdateChargeStatus.Location = new System.Drawing.Point(242, 377); + this.btnUpdateChargeStatus.Name = "btnUpdateChargeStatus"; + this.btnUpdateChargeStatus.Size = new System.Drawing.Size(115, 33); + this.btnUpdateChargeStatus.TabIndex = 1; + this.btnUpdateChargeStatus.Text = "获取充电状态"; + this.btnUpdateChargeStatus.UseVisualStyleBackColor = true; + this.btnUpdateChargeStatus.Click += new System.EventHandler(this.btnUpdateChargeStatus_Click); + // + // labelUpdateUnLock + // + this.labelUpdateUnLock.AutoSize = true; + this.labelUpdateUnLock.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.labelUpdateUnLock.Location = new System.Drawing.Point(363, 344); + this.labelUpdateUnLock.Name = "labelUpdateUnLock"; + this.labelUpdateUnLock.Size = new System.Drawing.Size(33, 20); + this.labelUpdateUnLock.TabIndex = 2; + this.labelUpdateUnLock.Text = " "; + // + // btnUpdateUnLock + // + this.btnUpdateUnLock.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnUpdateUnLock.Location = new System.Drawing.Point(242, 338); + this.btnUpdateUnLock.Name = "btnUpdateUnLock"; + this.btnUpdateUnLock.Size = new System.Drawing.Size(115, 33); + this.btnUpdateUnLock.TabIndex = 1; + this.btnUpdateUnLock.Text = "远程开锁"; + this.btnUpdateUnLock.UseVisualStyleBackColor = true; + this.btnUpdateUnLock.Click += new System.EventHandler(this.btnUpdateUnLock_Click); + // + // labelUpdateName + // + this.labelUpdateName.AutoSize = true; + this.labelUpdateName.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.labelUpdateName.Location = new System.Drawing.Point(363, 71); + this.labelUpdateName.Name = "labelUpdateName"; + this.labelUpdateName.Size = new System.Drawing.Size(33, 20); + this.labelUpdateName.TabIndex = 2; + this.labelUpdateName.Text = " "; + // + // btnUpdateName + // + this.btnUpdateName.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnUpdateName.Location = new System.Drawing.Point(242, 65); + this.btnUpdateName.Name = "btnUpdateName"; + this.btnUpdateName.Size = new System.Drawing.Size(115, 33); + this.btnUpdateName.TabIndex = 1; + this.btnUpdateName.Text = "更新姓名"; + this.btnUpdateName.UseVisualStyleBackColor = true; + this.btnUpdateName.Click += new System.EventHandler(this.btnUpdateName_Click); + // + // labelUpdateDepartment + // + this.labelUpdateDepartment.AutoSize = true; + this.labelUpdateDepartment.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.labelUpdateDepartment.Location = new System.Drawing.Point(363, 110); + this.labelUpdateDepartment.Name = "labelUpdateDepartment"; + this.labelUpdateDepartment.Size = new System.Drawing.Size(33, 20); + this.labelUpdateDepartment.TabIndex = 2; + this.labelUpdateDepartment.Text = " "; + // + // btnUpdateDepartment + // + this.btnUpdateDepartment.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnUpdateDepartment.Location = new System.Drawing.Point(242, 104); + this.btnUpdateDepartment.Name = "btnUpdateDepartment"; + this.btnUpdateDepartment.Size = new System.Drawing.Size(115, 33); + this.btnUpdateDepartment.TabIndex = 1; + this.btnUpdateDepartment.Text = "更新单位1"; + this.btnUpdateDepartment.UseVisualStyleBackColor = true; + this.btnUpdateDepartment.Click += new System.EventHandler(this.btnUpdateDepartment_Click); + // + // labelUpdateCardNumber + // + this.labelUpdateCardNumber.AutoSize = true; + this.labelUpdateCardNumber.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.labelUpdateCardNumber.Location = new System.Drawing.Point(363, 188); + this.labelUpdateCardNumber.Name = "labelUpdateCardNumber"; + this.labelUpdateCardNumber.Size = new System.Drawing.Size(33, 20); + this.labelUpdateCardNumber.TabIndex = 2; + this.labelUpdateCardNumber.Text = " "; + // + // btnUpdateCardNumber + // + this.btnUpdateCardNumber.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnUpdateCardNumber.Location = new System.Drawing.Point(242, 182); + this.btnUpdateCardNumber.Name = "btnUpdateCardNumber"; + this.btnUpdateCardNumber.Size = new System.Drawing.Size(115, 33); + this.btnUpdateCardNumber.TabIndex = 1; + this.btnUpdateCardNumber.Text = "更新卡号"; + this.btnUpdateCardNumber.UseVisualStyleBackColor = true; + this.btnUpdateCardNumber.Click += new System.EventHandler(this.btnUpdateCardNumber_Click); + // + // labelUpdateFreeCard + // + this.labelUpdateFreeCard.AutoSize = true; + this.labelUpdateFreeCard.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.labelUpdateFreeCard.Location = new System.Drawing.Point(363, 227); + this.labelUpdateFreeCard.Name = "labelUpdateFreeCard"; + this.labelUpdateFreeCard.Size = new System.Drawing.Size(33, 20); + this.labelUpdateFreeCard.TabIndex = 2; + this.labelUpdateFreeCard.Text = " "; + // + // btnUpdateFreeCard + // + this.btnUpdateFreeCard.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnUpdateFreeCard.Location = new System.Drawing.Point(242, 221); + this.btnUpdateFreeCard.Name = "btnUpdateFreeCard"; + this.btnUpdateFreeCard.Size = new System.Drawing.Size(115, 33); + this.btnUpdateFreeCard.TabIndex = 1; + this.btnUpdateFreeCard.Text = "更新万能卡号"; + this.btnUpdateFreeCard.UseVisualStyleBackColor = true; + this.btnUpdateFreeCard.Click += new System.EventHandler(this.btnUpdateFreeCard_Click); + // + // labelUpdateDepartment2 + // + this.labelUpdateDepartment2.AutoSize = true; + this.labelUpdateDepartment2.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.labelUpdateDepartment2.Location = new System.Drawing.Point(363, 149); + this.labelUpdateDepartment2.Name = "labelUpdateDepartment2"; + this.labelUpdateDepartment2.Size = new System.Drawing.Size(33, 20); + this.labelUpdateDepartment2.TabIndex = 2; + this.labelUpdateDepartment2.Text = " "; + // + // btnUpdateDepartment2 + // + this.btnUpdateDepartment2.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnUpdateDepartment2.Location = new System.Drawing.Point(242, 143); + this.btnUpdateDepartment2.Name = "btnUpdateDepartment2"; + this.btnUpdateDepartment2.Size = new System.Drawing.Size(115, 33); + this.btnUpdateDepartment2.TabIndex = 1; + this.btnUpdateDepartment2.Text = "更新单位2"; + this.btnUpdateDepartment2.UseVisualStyleBackColor = true; + this.btnUpdateDepartment2.Click += new System.EventHandler(this.btnUpdateDepartment2_Click); + // + // labelRemainTimes + // + this.labelRemainTimes.AutoSize = true; + this.labelRemainTimes.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.labelRemainTimes.Location = new System.Drawing.Point(363, 266); + this.labelRemainTimes.Name = "labelRemainTimes"; + this.labelRemainTimes.Size = new System.Drawing.Size(33, 20); + this.labelRemainTimes.TabIndex = 2; + this.labelRemainTimes.Text = " "; + // + // btnRemainTimes + // + this.btnRemainTimes.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnRemainTimes.Location = new System.Drawing.Point(242, 260); + this.btnRemainTimes.Name = "btnRemainTimes"; + this.btnRemainTimes.Size = new System.Drawing.Size(115, 33); + this.btnRemainTimes.TabIndex = 1; + this.btnRemainTimes.Text = "充电次数17"; + this.btnRemainTimes.UseVisualStyleBackColor = true; + this.btnRemainTimes.Click += new System.EventHandler(this.btnRemainTimes_Click); + // + // labelRemainTimes2 + // + this.labelRemainTimes2.AutoSize = true; + this.labelRemainTimes2.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.labelRemainTimes2.Location = new System.Drawing.Point(363, 305); + this.labelRemainTimes2.Name = "labelRemainTimes2"; + this.labelRemainTimes2.Size = new System.Drawing.Size(33, 20); + this.labelRemainTimes2.TabIndex = 2; + this.labelRemainTimes2.Text = " "; + // + // btnRemainTimes2 + // + this.btnRemainTimes2.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.btnRemainTimes2.Location = new System.Drawing.Point(242, 299); + this.btnRemainTimes2.Name = "btnRemainTimes2"; + this.btnRemainTimes2.Size = new System.Drawing.Size(115, 33); + this.btnRemainTimes2.TabIndex = 1; + this.btnRemainTimes2.Text = "充电次数88"; + this.btnRemainTimes2.UseVisualStyleBackColor = true; + this.btnRemainTimes2.Click += new System.EventHandler(this.btnRemainTimes2_Click); + // + // FormSocketServer + // + this.AutoScaleDimensions = new System.Drawing.SizeF(120F, 120F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; + this.AutoSize = true; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.ClientSize = new System.Drawing.Size(832, 553); + this.Controls.Add(this.groupBox6); + this.Controls.Add(this.btnUpdateUnLock); + this.Controls.Add(this.groupBox5); + this.Controls.Add(this.labelUpdateUnLock); + this.Controls.Add(this.btnUpdateName); + this.Controls.Add(this.labelUpdateName); + this.Controls.Add(this.btnRemainTimes2); + this.Controls.Add(this.labelRemainTimes2); + this.Controls.Add(this.btnRemainTimes); + this.Controls.Add(this.labelRemainTimes); + this.Controls.Add(this.btnUpdateFreeCard); + this.Controls.Add(this.labelUpdateFreeCard); + this.Controls.Add(this.btnUpdateCardNumber); + this.Controls.Add(this.labelUpdateCardNumber); + this.Controls.Add(this.btnUpdateDepartment2); + this.Controls.Add(this.labelUpdateDepartment2); + this.Controls.Add(this.btnUpdateDepartment); + this.Controls.Add(this.labelUpdateDepartment); + this.Controls.Add(this.btnUpdateChargeStatus); + this.Controls.Add(this.labelUpdateChargeStatus); + this.Controls.Add(this.btnUpdateDeviceId); + this.Controls.Add(this.LabelUpdateDeviceId); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox1); + this.Font = new System.Drawing.Font("微软雅黑", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.MaximizeBox = false; + this.Name = "FormSocketServer"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "充电柜单板测试"; + this.Load += new System.EventHandler(this.Form1_Load); + this.groupBox1.ResumeLayout(false); + this.groupBox8.ResumeLayout(false); + this.groupBox7.ResumeLayout(false); + this.groupBox7.PerformLayout(); + this.groupBox5.ResumeLayout(false); + this.groupBox5.PerformLayout(); + this.groupBox6.ResumeLayout(false); + this.groupBox2.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Label labelServerStartOrEnd; + private System.Windows.Forms.GroupBox groupBox5; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Label MessageIPAndPort; + private System.Windows.Forms.GroupBox groupBox6; + private System.Windows.Forms.ListBox lstControlText; + private System.Windows.Forms.GroupBox groupBox7; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.ComboBox comboBaudrate; + private System.Windows.Forms.ComboBox comboPortName; + private System.Windows.Forms.Button btnSerialPortOpenClose; + private System.Windows.Forms.Button btnClearCommunicateText; + private System.Windows.Forms.ListBox lstServerCommunicationText; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.GroupBox groupBox8; + private System.Windows.Forms.Button btnClearControlText; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Button btnUpdateDeviceId; + private System.Windows.Forms.Label LabelUpdateDeviceId; + private System.Windows.Forms.Label labelUpdateChargeStatus; + private System.Windows.Forms.Button btnUpdateChargeStatus; + private System.Windows.Forms.Label labelUpdateUnLock; + private System.Windows.Forms.Button btnUpdateUnLock; + private System.Windows.Forms.Label labelUpdateName; + private System.Windows.Forms.Button btnUpdateName; + private System.Windows.Forms.Label labelUpdateDepartment; + private System.Windows.Forms.Button btnUpdateDepartment; + private System.Windows.Forms.Label labelUpdateCardNumber; + private System.Windows.Forms.Button btnUpdateCardNumber; + private System.Windows.Forms.Label labelUpdateFreeCard; + private System.Windows.Forms.Button btnUpdateFreeCard; + private System.Windows.Forms.Label labelUpdateDepartment2; + private System.Windows.Forms.Button btnUpdateDepartment2; + private System.Windows.Forms.Label labelRemainTimes; + private System.Windows.Forms.Button btnRemainTimes; + private System.Windows.Forms.Label labelRemainTimes2; + private System.Windows.Forms.Button btnRemainTimes2; + } +} + diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Form1.cs b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Form1.cs new file mode 100644 index 0000000..5a34a1d --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Form1.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections.Generic; +using System.IO.Ports; +using System.Text; +using System.Threading; +using System.Windows.Forms; + +namespace SocketServer +{ + public partial class FormSocketServer : Form + { + //串口设置 + private SerialPort _comm = new SerialPort(); + + private readonly StringBuilder _builder = new StringBuilder(); //避免在事件处理方法中反复的创建,定义到外面。 + + public FormSocketServer() + { + InitializeComponent(); + } + + private void Form1_Load(object sender, EventArgs e) + { + CheckForIllegalCrossThreadCalls = false; + //初始化下拉串口名称列表框 + var ports = SerialPort.GetPortNames(); + Array.Sort(ports); + comboPortName.Items.AddRange(ports); + comboPortName.SelectedIndex = comboPortName.Items.Count > 0 ? 0 : -1; + comboBaudrate.SelectedIndex = comboBaudrate.Items.IndexOf("115200"); + //初始化SerialPort对象 + _comm.NewLine = "\r\n"; + _comm.RtsEnable = true; //根据实际情况吧。 + + //添加事件注册 + _comm.DataReceived += comm_DataReceived; + } + + private void comm_DataReceived(object sender, SerialDataReceivedEventArgs e) + { + Thread.Sleep(10); + var n = _comm.BytesToRead; //先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致 + var buf = new byte[n]; //声明一个临时数组存储当前来的串口数据 + _comm.Read(buf, 0, n); //读取缓冲数据 + _builder.Clear(); //清除字符串构造器的内容 + //因为要访问ui资源,所以需要使用invoke方式同步ui。 + Invoke((EventHandler) (delegate + { + var strings = new string[13]; + for (int i = 0; i < buf.Length; i++) + { + var s = Convert.ToString(buf[i], 16); + if (s.Length == 1) s = "0" + s; + if (i < 13) + { + strings[i] = s; + } + _builder.Append(s + " "); + } + //追加的形式添加到文本框末端,并滚动到最后。 + communicateMessageShow(_builder.ToString()); + + successReceiveFrame(strings); + })); + } + + private int _countDeviceId; + private int _countName; + private int _countDepartment; + private int _countDepartment2; + private int _countCardNumber; + private int _countFreeCard; + private int _countRemainTimes; + private int _countRemainTimes2; + private int _countUnLock; + private int _countChargeStatus; + + private void successReceiveFrame(IList strs) + { + var frameType = strs[1]; + + if ("45".Equals(frameType)) updateLabel(LabelUpdateDeviceId, ref _countDeviceId); + if ("46".Equals(frameType)) updateLabel(labelUpdateName, ref _countName); + if ("47".Equals(frameType)) updateLabel(labelUpdateDepartment, ref _countDepartment); + if ("48".Equals(frameType)) updateLabel(labelUpdateDepartment2, ref _countDepartment2); + if ("49".Equals(frameType)) updateLabel(labelUpdateCardNumber, ref _countCardNumber); + if ("80".Equals(frameType)) updateLabel(labelUpdateFreeCard, ref _countFreeCard); + if ("41".Equals(frameType)) + { + if (_countRemainTimes <= _countRemainTimes2) + updateLabel(labelRemainTimes, ref _countRemainTimes); + else + updateLabel(labelRemainTimes2, ref _countRemainTimes2); + } + if ("4a".Equals(frameType)) updateLabel(labelUpdateUnLock, ref _countUnLock); + + if ("40".Equals(frameType)) + { + var type = strs[3]; + if ("01".Equals(type)) updateLabel(labelUpdateChargeStatus, ref _countChargeStatus, "使用中"); + if ("02".Equals(type)) updateLabel(labelUpdateChargeStatus, ref _countChargeStatus, "充电中"); + if ("03".Equals(type)) updateLabel(labelUpdateChargeStatus, ref _countChargeStatus, "已充满"); + if ("04".Equals(type)) updateLabel(labelUpdateChargeStatus, ref _countChargeStatus, "已过流"); + if ("06".Equals(type)) updateLabel(labelUpdateChargeStatus, ref _countChargeStatus, "未放好"); + if ("50".Equals(type)) updateLabel(labelUpdateChargeStatus, ref _countChargeStatus, "严重故障"); + } + } + + + private void updateLabel(Control label, ref int value, string extra = null) + { + if (extra == null) + { + label.Text = @"成功「" + ++value + @"」"; + } + else + { + label.Text = @"成功「" + ++value + @"」" +"\r\n"+ extra; + } + } + + private void buttonOpenClose_Click(object sender, EventArgs e) + { + //根据当前串口对象,来判断操作 + if (_comm.IsOpen) + { + //打开时点击,则关闭串口 + _comm.Close(); + labelServerStartOrEnd.Text = @"串口已关闭"; + controlMessageShow(@"串口已关闭"); + MessageIPAndPort.Text = @"无状态信息"; + } + else + { + //关闭时点击,则设置好端口,波特率后打开 + _comm.PortName = comboPortName.Text; + _comm.BaudRate = int.Parse(comboBaudrate.Text); + try + { + _comm.Open(); + labelServerStartOrEnd.Text = @"串口已打开"; + controlMessageShow(@"串口已打开"); + MessageIPAndPort.Text = comboPortName.SelectedItem.ToString(); + } + catch (Exception ex) + { + //捕获到异常信息,创建一个新的comm对象,之前的不能用了。 + _comm = new SerialPort(); + //现实异常信息给客户。 + MessageBox.Show(ex.Message); + } + } + //设置按钮的状态 + btnSerialPortOpenClose.Text = _comm.IsOpen ? @"关闭串口" : @"打开串口"; + } + + private void controlMessageShow(string message) + { + lstControlText.Items.Add(message); + lstControlText.SetSelected(lstControlText.Items.Count - 1, true); + } + + private void communicateMessageShow(string message) + { + lstServerCommunicationText.Items.Add(message); + lstServerCommunicationText.SetSelected(lstServerCommunicationText.Items.Count - 1, true); + } + + private void btnClearText_Click(object sender, EventArgs e) + { + _countDeviceId = 0; + _countName = 0; + _countDepartment = 0; + _countDepartment2 = 0; + _countCardNumber = 0; + _countFreeCard = 0; + _countRemainTimes = 0; + _countRemainTimes2 = 0; + _countUnLock = 0; + _countChargeStatus = 0; + + lstServerCommunicationText.Items.Clear(); + LabelUpdateDeviceId.Text = ""; + labelUpdateName.Text = ""; + labelUpdateDepartment.Text = ""; + labelUpdateDepartment2.Text = ""; + labelUpdateCardNumber.Text = ""; + labelUpdateFreeCard.Text = ""; + labelRemainTimes.Text = ""; + labelRemainTimes2.Text = ""; + labelUpdateUnLock.Text = ""; + labelUpdateChargeStatus.Text = ""; + } + + private void btnClearControlText_Click(object sender, EventArgs e) + { + lstControlText.Items.Clear(); + } + + private void btnUpdateUnLock_Click(object sender, EventArgs e) + { + const string str = "fc 12 1a 00 00 00 00 00 00 00 00 00 b9"; + sendFrame(str); + } + + private void btnUpdateDeviceId_Click(object sender, EventArgs e) + { + const string str = "fc 01 15 00 12 00 00 00 00 00 00 00 3c"; + sendFrame(str); + } + + private void sendFrame(string str) + { + string[] strs = str.Split(' '); + byte[] bytes = new byte[13]; + for (var i = 0; i < 13; i++) + { + bytes[i] = Convert.ToByte(strs[i], 16); + } + _comm.Write(bytes, 0, 13); + } + + private void btnUpdateName_Click(object sender, EventArgs e) + { + const string str = "fc 12 16 00 d0 d5 c3 fb 00 00 00 00 71"; + sendFrame(str); + } + + private void btnUpdateDepartment_Click(object sender, EventArgs e) + { + const string str = "fc 12 17 00 b5 a5 ce bb 00 00 00 00 78"; + sendFrame(str); + } + + private void btnUpdateDepartment2_Click(object sender, EventArgs e) + { + const string str = "fc 12 18 00 00 00 00 00 00 00 00 00 3c"; + sendFrame(str); + } + + private void btnUpdateCardNumber_Click(object sender, EventArgs e) + { + const string str = "fc 12 19 08 01 00 00 01 5F 91 9D 55 4e"; + sendFrame(str); + } + + private void btnUpdateFreeCard_Click(object sender, EventArgs e) + { + const string str = "fc 12 70 08 01 00 00 01 83 40 8C B9 d4"; + sendFrame(str); + } + + private void btnRemainTimes_Click(object sender, EventArgs e) + { + const string str = "fc 12 11 01 11 00 00 00 00 00 00 00 67"; + sendFrame(str); + } + + private void btnRemainTimes2_Click(object sender, EventArgs e) + { + const string str = "fc 12 11 01 58 00 00 00 00 00 00 00 47"; + sendFrame(str); + } + + private void btnUpdateChargeStatus_Click(object sender, EventArgs e) + { + const string str = "fc 12 10 00 00 00 00 00 00 00 00 00 1a"; + sendFrame(str); + } + } +} \ No newline at end of file diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Form1.resx b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Form1.resx new file mode 100644 index 0000000..61bc649 --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Form1.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + \ No newline at end of file diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Program.cs b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Program.cs new file mode 100644 index 0000000..74f4b68 --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Program.cs @@ -0,0 +1,19 @@ +using System; +using System.Windows.Forms; + +namespace SocketServer +{ + static class Program + { + /// + /// 应用程序的主入口点。 + /// + [STAThread] + private static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new FormSocketServer()); + } + } +} diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/AssemblyInfo.cs b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..bfbcec8 --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("SocketSever")] +[assembly: AssemblyDescription("SocketSever for .net3.5")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SocketSever")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +//将 ComVisible 设置为 false 将使此程序集中的类型 +//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("5e0c4b0f-13ff-47e3-b951-a2457df0bc25")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, +// 方法是按如下所示使用“*”: : +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/Resources.Designer.cs b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/Resources.Designer.cs new file mode 100644 index 0000000..93c6880 --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace SingleDeviceTest.Properties { + using System; + + + /// + /// 一个强类型的资源类,用于查找本地化的字符串等。 + /// + // 此类是由 StronglyTypedResourceBuilder + // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。 + // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen + // (以 /str 作为命令选项),或重新生成 VS 项目。 + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// 返回此类使用的缓存的 ResourceManager 实例。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SingleDeviceTest.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// 使用此强类型资源类,为所有资源查找 + /// 重写当前线程的 CurrentUICulture 属性。 + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/Resources.resx b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/Settings.Designer.cs b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/Settings.Designer.cs new file mode 100644 index 0000000..cc17860 --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +namespace SingleDeviceTest.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/Settings.settings b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTestNET/SingleDeviceTestNET.csproj b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/SingleDeviceTestNET.csproj new file mode 100644 index 0000000..0300659 --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/SingleDeviceTestNET.csproj @@ -0,0 +1,144 @@ + + + + + Debug + AnyCPU + {5E0C4B0F-13FF-47E3-B951-A2457DF0BC25} + WinExe + Properties + SingleDeviceTest + SingleDeviceTest + v4.0 + 512 + true + false + + C:\Users\lml08\Desktop\SocketServer\4.5\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 2 + 1.0.0.%2a + false + true + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + 679A5D77139F31B18BCA379843E2751A3DDAF5B0 + + + SocketSeverDotnet4.5_TemporaryKey.pfx + + + true + + + false + + + + + + + + + + + + + + + + + + + + Form + + + Form1.cs + + + + + + + + + + + Form1.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + + False + Microsoft .NET Framework 4.5.2 %28x86 和 x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + + \ No newline at end of file diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTestNET/message/WebMsgOperateBoxUnlock.cs b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/message/WebMsgOperateBoxUnlock.cs new file mode 100644 index 0000000..e3b1815 --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/message/WebMsgOperateBoxUnlock.cs @@ -0,0 +1,13 @@ +using SocketServer.message.@base; +using SocketServer.utils; + +namespace SocketServer.message +{ + public class WebMsgOperateBoxUnlock : BaseMessage + { + public WebMsgOperateBoxUnlock(int groupId, int boxId) : base(groupId, boxId) + { + setMsgId(MsgType.ServerRemoteUnlock); + } + } +} \ No newline at end of file diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTestNET/message/base/BaseMessage.cs b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/message/base/BaseMessage.cs new file mode 100644 index 0000000..d27aa4d --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/message/base/BaseMessage.cs @@ -0,0 +1,51 @@ +namespace SocketServer.message.@base +{ + public class BaseMessage : IMessage + { + private int _msgId = -1; + private int _groupId = -1; + private int _deviceId = -1; + + protected BaseMessage(int groupId) + { + this._groupId = groupId; + } + + protected BaseMessage(int groupId, int deviceId) : this(groupId) + { + this._deviceId = deviceId; + } + + public int getMsgId() + { + return _msgId; + } + + protected void setMsgId(int msgId) + { + this._msgId = msgId; + } + + public int getGroupId() + { + return _groupId; + } + + public void setGroupId(int groupId) + { + this._groupId = groupId; + } + + + public int getDeviceId() + { + return _deviceId; + } + + + public void setDeviceId(int deviceId) + { + this._deviceId = deviceId; + } + } +} \ No newline at end of file diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTestNET/message/base/IMessage.cs b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/message/base/IMessage.cs new file mode 100644 index 0000000..c1ff5ba --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/message/base/IMessage.cs @@ -0,0 +1,15 @@ +namespace SocketServer.message.@base +{ + public interface IMessage + { + int getMsgId(); + + int getDeviceId(); + + void setDeviceId(int deviceId); + + int getGroupId(); + + void setGroupId(int groupId); + } +} \ No newline at end of file diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTestNET/utils/CanBuilder.cs b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/utils/CanBuilder.cs new file mode 100644 index 0000000..b9904e7 --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/utils/CanBuilder.cs @@ -0,0 +1,70 @@ +using System; +using SocketServer.message; +using SocketServer.message.@base; + +namespace SocketServer.utils +{ + class CanBuilder + { + private static TcpMsgBuilder _tcpMsgBuilder=new TcpMsgBuilder(); + + public static byte[] buildByMessage(IMessage message) + { + switch (message.getMsgId()) + { +// case MsgType.SERVER_REQUSET_STATUS: +// WebMsgObtainDeviceStatus obtainDeviceStatus = (WebMsgObtainDeviceStatus) message; +// Console.WriteLine("生成帧:请求设备当前状态"); +// return tcpMsgBuilder.buildRequestDeviceStatus(obtainDeviceStatus); +// +// case MsgType.SERVER_SET_REMAIN_CHARGE_TIMES: +// WebMsgDeployRemainChargeTimes remainChargeTimes = (WebMsgDeployRemainChargeTimes) message; +// Console.WriteLine("生成帧:设置设备剩余充电次数: " + remainChargeTimes.getTimes()); +// return tcpMsgBuilder.buildRemainChargeTimes(remainChargeTimes); +// +// case MsgType.SERVER_SET_DEVICE_ID: +// WebMsgDeployEmployeeDeviceId deployEmployeeDeviceId = (WebMsgDeployEmployeeDeviceId) message; +// Console.WriteLine("生成帧:设置设备 ID: " + deployEmployeeDeviceId.getUpdatedDeviceId()); +// return tcpMsgBuilder.buildDeviceId(deployEmployeeDeviceId); +// +// case MsgType.SERVER_SET_EMPLOYEE_NAME: +// WebMsgDeployEmployeeName deployEmployeeName = (WebMsgDeployEmployeeName) message; +// Console.WriteLine("生成帧:设置员工姓名: " + deployEmployeeName.getValue()); +// return tcpMsgBuilder.buildEmployeeName(deployEmployeeName); +// +// case MsgType.SERVER_SET_EMPLOYEE_DEPARTMENT_1: +// WebMsgDeployEmployeeDepartment deployEmployeeDepartment = (WebMsgDeployEmployeeDepartment) message; +// Console.WriteLine("生成帧:设置员工单位: " + deployEmployeeDepartment.getValue()); +// return tcpMsgBuilder.buildEmployeeDepartment(deployEmployeeDepartment); +// +// case MsgType.SERVER_SET_EMPLOYEE_CARD_NUMBER: +// WebMsgDeployEmployeeCardNumber deployEmployeeCardNumber = (WebMsgDeployEmployeeCardNumber) message; +// Console.WriteLine("生成帧:设置员工卡号: " + deployEmployeeCardNumber.getCardNumber()); +// return tcpMsgBuilder.buildEmployeeCardNumber(deployEmployeeCardNumber); + + case MsgType.ServerRemoteUnlock: + Console.WriteLine("生成帧:解锁单个设备"); + return _tcpMsgBuilder.buildWebUnlock((WebMsgOperateBoxUnlock) message); + +// case MsgType.SERVER_SET_FREE_CARD_NUMBER: +// Console.WriteLine("生成帧:设置万能卡号"); +// return tcpMsgBuilder.buildFreeCardNumber((WebMsgDeployFreeCardNumber) message); +// +// case MsgType.INITIALIZE_SERVER_MARCH_CONFIRM_CARD_RESPONSE: +// WebMsgInitMarchConfirmCardResponse marchConfirmCard = (WebMsgInitMarchConfirmCardResponse) message; +// Console.WriteLine("生成初始化帧:匹配确认卡号状态:" + marchConfirmCard.isSuccessful()); +// return tcpMsgBuilder.buildInitMarchConfirmCardSuccessful(marchConfirmCard); +// +// case MsgType.INITIALIZE_SERVER_CLEAR_INITIALIZE_MESSAGE: +// WebMsgInitClearDeviceStatus clearDeviceStatus = (WebMsgInitClearDeviceStatus) message; +// Console.WriteLine("生成帧:清除设备的初始化状态"); +// return tcpMsgBuilder.buildClearDeviceStatus(clearDeviceStatus); + + default: + Console.WriteLine("未匹配功能位「" + message.getMsgId() + "」,无法生成 CAN 帧"); + break; + } + return new byte[0]; + } + } +} \ No newline at end of file diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTestNET/utils/MsgType.cs b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/utils/MsgType.cs new file mode 100644 index 0000000..cd63b35 --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/utils/MsgType.cs @@ -0,0 +1,126 @@ +namespace SocketServer.utils +{ + class MsgType + { + public const byte HeartBeat = 0x01; + + public const byte Error = 0x05; + + /** + * 成组地发送消息 + */ + public const byte ServerSendGrouped = 0x0A; + + /** + * 紧急发送该消息 + */ + public const byte ServerSendSpecial = 0x0B; + + + //-------------------服务器下发----------------------- + + /** + * 获取充电状态 + */ + public const byte ServerRequsetStatus = 0x10; + + /** + * 设置剩余充电次数 + */ + public const byte ServerSetRemainChargeTimes = 0x11; + + /** + * 设置设备ID + */ + public const byte ServerSetDeviceId = 0x15; + + /** + * 设置员工姓名 + */ + public const byte ServerSetEmployeeName = 0x16; + + /** + * 设置员工单位第一帧 + */ + public const byte ServerSetEmployeeDepartment1 = 0x17; + + /** + * 设置员工卡号 + */ + public const byte ServerSetEmployeeCardNumber = 0x19; + + /** + * 服务器远程开锁 + */ + public const byte ServerRemoteUnlock = 0x1A; + + /** + * 万能卡号设置 + */ + public const byte ServerSetFreeCardNumber = 0x70; + + //-------------------设备回复----------------------- + + /** + * 设备回复自己的状态 + */ + public const byte DeviceResponseStatus = 0x40; + + /** + * 设置剩余充电次数的回复 + */ + public const byte DeviceResponseRemainChargeTimes = 0x41; + + /** + * 设置设备ID的回复 + */ + public const byte DeviceResponseDeviceId = 0x45; + + /** + * 设置员工姓名的回复 + */ + public const byte DeviceResponseEmployeeName = 0x46; + + /** + * 设置员工单位的回复「1」 + */ + public const byte DeviceResponseEmployeeDepartment1 = 0x47; + + /** + * 设置员工单位的回复「2」 + */ + public const byte DeviceResponseEmployeeDepartment2 = 0x48; + + /** + * 设置员工卡号的回复 + */ + public const byte DeviceResponseEmployeeCardNumber = 0x49; + + /** + * 服务器远程开锁的回复 + */ + public const byte DeviceResponseRemoteUnlock = 0x4A; + + /** + * 万能卡号设置的回复 + */ + public const byte DeviceResponseFreeCardNumber = (byte) 0x80; + + //-------------------初始化流程信息----------------------- + + /** + * 设备主动发送卡号,包括员工卡号和确认卡号 + */ + public const byte InitializeDeviceResponseCard = (byte) 0xAA; + + /** + * 服务器匹配确认卡号回复 + */ + public const byte InitializeServerMarchConfirmCardResponse = (byte) 0xAB; + + /** + * 服务器清除设备的初始化状态 + */ + public const byte InitializeServerClearInitializeMessage = (byte) 0xAD; + } +} \ No newline at end of file diff --git a/hardware/SingleDeviceTestNET/SingleDeviceTestNET/utils/TcpMsgBuilder.cs b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/utils/TcpMsgBuilder.cs new file mode 100644 index 0000000..a48e737 --- /dev/null +++ b/hardware/SingleDeviceTestNET/SingleDeviceTestNET/utils/TcpMsgBuilder.cs @@ -0,0 +1,272 @@ +using System; +using System.Text; +using SocketServer.message; +using SocketServer.message.@base; + +namespace SocketServer.utils +{ + public class TcpMsgBuilder + { +// public static string byteArrayToString(byte[] cards) +// { +// var builder = new StringBuilder(); +// +// foreach (var b in cards) +// { +// var s =Integer.toHexString(b & 0xFF).toUpperCase(); +// if (s.Length == 1) +// { +// builder.Append('0').Append(s); +// } +// else builder.Append(s); +// } +// return builder.ToString(); +// } + + public static byte[] stringToByteArray(string cards) + { + if (cards.Length > 16) cards = cards.Substring(0, 16); + if (cards.Length < 16) + { + var count = 16 - cards.Length; + var builder = new StringBuilder(); + for (var i = 0; i < count; i++) + { + builder.Append("0"); + } + builder.Append(cards); + cards = builder.ToString(); + } + + var bytes = new byte[8]; + cards = cards.ToUpper(); + var hexChars = cards.ToCharArray(); + for (var i = 0; i < 8; i++) + { + var pos = i * 2; + bytes[i] = (byte)(charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1])); + } + return bytes; + } + + private static byte charToByte(char c) + { + return (byte)"0123456789ABCDEF".IndexOf(c); + } + +// /** +// * 构建获取设备状态的 CAN 帧 +// * +// * @param webMsgObtainDeviceStatus 获取设备状态 bean +// * @return 获取设备状态的 CAN 帧 +// */ +// public byte[] buildRequestDeviceStatus(WebMsgObtainDeviceStatus webMsgObtainDeviceStatus) +// { +// return buildMsgOutline(webMsgObtainDeviceStatus); +// } +// +// /** +// * 构建剩余充电次数的 CAN 帧 +// * +// * @param webMsgDeployRemainChargeTimes 剩余充电次数 bean +// * @return 剩余充电次数的 CAN 帧 +// */ +// public byte[] buildRemainChargeTimes(WebMsgDeployRemainChargeTimes webMsgDeployRemainChargeTimes) +// { +// byte[] bytes = buildMsgOutline(webMsgDeployRemainChargeTimes); +// bytes[0] += 1; +// bytes[5] = (byte)webMsgDeployRemainChargeTimes.getTimes(); +// return bytes; +// } +// +// /** +// * 构建设备 ID 的CAN帧 +// * +// * @param webMsgDeployEmployeeDeviceId 设备ID bean +// * @return 设备ID的 CAN 帧 +// */ +// public byte[] buildDeviceId(WebMsgDeployEmployeeDeviceId webMsgDeployEmployeeDeviceId) +// { +// byte[] bytes = buildMsgOutline(webMsgDeployEmployeeDeviceId); +// bytes[0] += 1; +// bytes[5] = (byte)webMsgDeployEmployeeDeviceId.getUpdatedDeviceId(); +// return bytes; +// } +// +// /** +// * 构建员工姓名的 CAN 帧 +// * +// * @param webMsgDeployEmployeeName 员工姓名 bean +// * @return 员工姓名的 CAN 帧 +// */ +// public byte[] buildEmployeeName(WebMsgDeployEmployeeName webMsgDeployEmployeeName) +// { +// byte[] bytes = buildMsgOutline(webMsgDeployEmployeeName); +// +// byte[] bytesBody = webMsgDeployEmployeeName.getValue().getBytes(charset_GB2312); +// bytes[0] += bytesBody.length > 8 ? 8 : bytesBody.length; +// addMessageBody(bytes, bytesBody, 0); +// return bytes; +// } +// +// /** +// * 构建员工单位的 CAN 帧 +// * +// * @param webMsgDeployEmployeeDepartment 员工单位 bean +// * @return 员工单位的 CAN 帧 +// */ +// public byte[] buildEmployeeDepartment(WebMsgDeployEmployeeDepartment webMsgDeployEmployeeDepartment) +// { +// byte[] bytes = buildMsgOutline(webMsgDeployEmployeeDepartment); +// byte[] bytesBody = webMsgDeployEmployeeDepartment.getValue().getBytes(charset_GB2312); +// +// byte[] bytes2 = bytes.clone(); +// bytes2[2] += 1; +// addMessageBody(bytes, bytesBody, 0); +// addMessageBody(bytes2, bytesBody, 8); +// +// if (bytesBody.length > 8) +// { +// bytes[0] += 8; +// bytes2[0] += (bytesBody.length - 8) > 8 ? 8 : (bytesBody.length - 8); +// } +// else +// { +// bytes[0] += bytesBody.length; +// } +// +// byte[] bytes3 = new byte[13 * 2]; +// System.arraycopy(bytes, 0, bytes3, 0, 13); +// System.arraycopy(bytes2, 0, bytes3, 13, 13); +// return bytes3; +// } +// +// /** +// * 构建员工卡号的 CAN 帧 +// * +// * @param webMsgDeployEmployeeCardNumber 员工卡号 bean +// * @return 员工卡号的 CAN 帧 +// */ +// public byte[] buildEmployeeCardNumber(WebMsgDeployEmployeeCardNumber webMsgDeployEmployeeCardNumber) +// { +// byte[] bytes = buildMsgOutline(webMsgDeployEmployeeCardNumber); +// bytes[0] += 8; +// byte[] byteCardNum = stringToByteArray(webMsgDeployEmployeeCardNumber.getCardNumber()); +// addMessageBody(bytes, byteCardNum, 0); +// return bytes; +// } + + /** + * 构建开锁用的 CAN 帧 + * + * @param webMsgOperateBoxUnlock 开锁 bean + * @return 开锁用的 CAN 帧 + */ + public byte[] buildWebUnlock(WebMsgOperateBoxUnlock webMsgOperateBoxUnlock) + { + return buildMsgOutline(webMsgOperateBoxUnlock); + } + +// /** +// * 构建万能卡号 CAN 帧 +// * +// * @param webMsgDeployFreeCardNumber 万能卡号 bean +// * @return 万能卡号的 CAN 帧 +// */ +// public byte[] buildFreeCardNumber(WebMsgDeployFreeCardNumber webMsgDeployFreeCardNumber) +// { +// string[] cards = webMsgDeployFreeCardNumber.getCardNumbers(); +// int count = cards.length < 16 ? cards.length : 16; +// byte[] bytesSend = new byte[13 * count]; +// +// for (int i = 0; i < count; i++) +// { +// byte[] bytes = buildMsgOutline(webMsgDeployFreeCardNumber); +// bytes[2] += i; +// addMessageBody(bytes, stringToByteArray(cards[i]), 0); +// System.arraycopy(bytes, 0, bytesSend, 13 * i, 13); +// } +// return bytesSend; +// } +// +// /** +// * 「初始化」服务器匹配确认卡号成功 +// * +// * @param marchConfirmCardSuccessful 匹配确认卡号成功 bean +// * @return 「匹配确认卡号成功」的 CAN 帧 +// */ +// public byte[] buildInitMarchConfirmCardSuccessful(WebMsgInitMarchConfirmCardResponse marchConfirmCardSuccessful) +// { +// byte[] bytes = buildMsgOutline(marchConfirmCardSuccessful); +// bytes[0] += 1; +// bytes[5] = (byte)(marchConfirmCardSuccessful.isSuccessful() ? 1 : 0); +// return bytes; +// } +// +// +// /** +// * 构建清除设备初始化状态的 CAN 帧 +// * +// * @param clearDeviceStatus 清除设备初始化状态 bean +// * @return 清除设备初始化状态的 CAN 帧 +// */ +// public byte[] buildClearDeviceStatus(WebMsgInitClearDeviceStatus clearDeviceStatus) +// { +// return buildMsgOutline(clearDeviceStatus); +// } + + /** + * 构建 CAN 帧的轮廓,只需再填入数据位即可 + * + * @param message 欲构建为 CAN 帧的 bean + * @return 轮廓 CAN 帧 + */ + private byte[] buildMsgOutline(BaseMessage message) + { + byte[] bytes = new byte[13]; + bytes[0] = (byte)0x80; + bytes[2] = (byte)message.getMsgId(); + bytes[3] = (byte)message.getDeviceId(); + bytes[4] = (byte)message.getGroupId(); + return bytes; + } + + /** + * 在轮廓CAN帧中添加数据位 + * + * @param bytes 轮廓CAN帧 + * @param bytesBody 数据位 + * @param offset 数据位的偏移量,offset位开始操作8个字节 + */ + private void addMessageBody(byte[] bytes, byte[] bytesBody, int offset) + { + int max = (bytesBody.Length - offset) > 8 ? 8 : (bytesBody.Length - offset); + for (int i = 0; i < max; i++) + { + bytes[i + 5] = bytesBody[i + offset]; + } + } + + private long byteArrayToLong(byte[] bytes) + { + long num = 0; + for (int i = 0; i <= 7; i++) + { + num += (bytes[i] & 0xffL) << ((7 - i) * 8); + } + return num; + } + + private byte[] longToByteArray(long num) + { + byte[] bytes = new byte[8]; + for (int i = 0; i <= 7; i++) + { + bytes[i] = (byte)((num >> ((7 - i) * 8)) & 0xff); + } + return bytes; + } + + + } +} \ No newline at end of file From c9d9b7549cdabc989318d30ac8ebd6e8ab4d9bcc Mon Sep 17 00:00:00 2001 From: bitkylin Date: Wed, 26 Jul 2017 14:23:42 +0800 Subject: [PATCH 5/5] =?UTF-8?q?Netty=20=E9=83=A8=E5=88=86=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=95=B4=E4=BD=93=E4=BC=98=E5=8C=96=EF=BC=8C=E9=87=87?= =?UTF-8?q?=E7=94=A8=E4=B8=AD=E4=BB=8B=E8=80=85=E6=A8=A1=E5=BC=8F=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E6=98=8E=E6=98=BE=E5=88=86=E5=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- clustermanage-server/pom.xml | 2 +- .../ClustermanageServerApplication.java | 1 + .../db/presenter/DbDevicePresenter.java | 5 +- .../bitky/clustermanage/global/ExSetting.java | 1 + .../clustermanage/global/ServerSetting.java | 7 +- .../server/bean/ServerTcpMessageHandler.java | 28 ++----- .../server/message/ChargeStatus.java | 44 +++++++++++ .../server/schedule/SendingMsgRepo.java | 6 +- .../bitky/clustermanage/tcp/TcpMediator.java | 77 +++++++++++++++++++ ...tBoundHandler.java => MsgToCanParser.java} | 37 +++++---- ...Handler.java => PolicyCanTransmitter.java} | 54 +++++++------ ...InBoundHandler.java => ConfigHandler.java} | 15 ++-- .../ParsedMessageInBoundHandler.java | 23 +++--- .../ServerChannelInitializer.java | 42 +--------- .../clustermanage/tcp/util/TcpMsgBuilder.java | 2 +- 15 files changed, 213 insertions(+), 131 deletions(-) create mode 100644 clustermanage-server/src/main/java/cc/bitky/clustermanage/server/message/ChargeStatus.java create mode 100644 clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/TcpMediator.java rename clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/{channelhandler/WebMsgOutBoundHandler.java => MsgToCanParser.java} (87%) rename clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/{channelhandler/QueuingOutBoundHandler.java => PolicyCanTransmitter.java} (63%) rename clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/{ConfigInBoundHandler.java => ConfigHandler.java} (67%) diff --git a/clustermanage-server/pom.xml b/clustermanage-server/pom.xml index 1eb18a6..6de990c 100644 --- a/clustermanage-server/pom.xml +++ b/clustermanage-server/pom.xml @@ -6,7 +6,7 @@ cc.bitky.clustermanage clustermanage-server - 0.9.2-release + 0.9.3-release jar clustermanage-server diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/ClustermanageServerApplication.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/ClustermanageServerApplication.java index 127043f..3c7f183 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/ClustermanageServerApplication.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/ClustermanageServerApplication.java @@ -52,6 +52,7 @@ private static void initSetting() { ServerSetting.DEFAULT_EMPLOYEE_CARD_NUMBER = exSetting.员工默认卡号; ServerSetting.DEFAULT_EMPLOYEE_NAME = exSetting.员工默认姓名; ServerSetting.DEFAULT_EMPLOYEE_DEPARTMENT = exSetting.员工默认部门; + ServerSetting.AUTO_REPEAT_REQUEST_TIMES = exSetting.检错重发最大重复次数; } } } diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/db/presenter/DbDevicePresenter.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/db/presenter/DbDevicePresenter.java index 4bcc873..e1e33f4 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/db/presenter/DbDevicePresenter.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/db/presenter/DbDevicePresenter.java @@ -11,6 +11,7 @@ import cc.bitky.clustermanage.db.bean.Device; import cc.bitky.clustermanage.db.repository.DeviceRepository; +import cc.bitky.clustermanage.server.message.ChargeStatus; import cc.bitky.clustermanage.server.message.tcp.TcpMsgResponseStatus; @Service @@ -48,7 +49,7 @@ Device handleMsgDeviceStatus(TcpMsgResponseStatus msgStatus) { if (device == null) return null; int rawStatus = device.getStatus(); int newStatus = msgStatus.getStatus(); - if (newStatus > 6 || newStatus < 0) newStatus = 50; + if (newStatus > 6 || newStatus < 0) newStatus = ChargeStatus.CRASH; // if (rawStatus >= 5) { // logger.info("设备「" + msgStatus.getGroupId() + ", " + msgStatus.getDeviceId() + "」『" @@ -64,7 +65,7 @@ Device handleMsgDeviceStatus(TcpMsgResponseStatus msgStatus) { return device; } - if (rawStatus == 2 && newStatus == 3 && device.getRemainChargeTime() > 0) { + if (rawStatus == ChargeStatus.CHARGING && newStatus == ChargeStatus.FULL && device.getRemainChargeTime() > 0) { device.setRemainChargeTime(device.getRemainChargeTime() - 1); } device.setStatus(newStatus); diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/global/ExSetting.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/global/ExSetting.java index ea5a368..6761018 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/global/ExSetting.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/global/ExSetting.java @@ -7,4 +7,5 @@ public class ExSetting { public String 员工默认部门; public int 部署剩余充电次数阈值; public int 帧发送间隔; + public int 检错重发最大重复次数; } diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/global/ServerSetting.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/global/ServerSetting.java index b4c27dc..03537ae 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/global/ServerSetting.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/global/ServerSetting.java @@ -48,11 +48,16 @@ public class ServerSetting { */ public static final int COMMAND_DELAY_WAITING_TIME = 30; + /** + * 检错重发最大次数,服务器向 TCP 通道发送 CAN 帧,最大重复发送次数 + */ + public static int AUTO_REPEAT_REQUEST_TIMES = 5; + //-----------------------接收到充电状态帧时的处理策略---------------------------- /** * 项目版本号 */ - public static final String VERSION = "0.9.2"; + public static final String VERSION = "0.9.3"; /** * 主机名 */ diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/bean/ServerTcpMessageHandler.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/bean/ServerTcpMessageHandler.java index 7e8e591..9c0ac45 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/bean/ServerTcpMessageHandler.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/bean/ServerTcpMessageHandler.java @@ -20,19 +20,21 @@ import cc.bitky.clustermanage.server.message.web.WebMsgInitMarchConfirmCardResponse; import cc.bitky.clustermanage.server.schedule.MsgKey; import cc.bitky.clustermanage.server.schedule.SendingMsgRepo; -import cc.bitky.clustermanage.tcp.server.netty.SendWebMessagesListener; +import cc.bitky.clustermanage.tcp.TcpMediator; import io.netty.util.internal.StringUtil; @Service public class ServerTcpMessageHandler { private final KyDbPresenter kyDbPresenter; + private final TcpMediator tcpMediator; private Logger logger = LoggerFactory.getLogger(getClass()); - private SendWebMessagesListener sendWebMessagesListener; private KyServerCenterHandler kyServerCenterHandler; @Autowired - public ServerTcpMessageHandler(KyDbPresenter kyDbPresenter) { + public ServerTcpMessageHandler(KyDbPresenter kyDbPresenter, TcpMediator tcpMediator) { this.kyDbPresenter = kyDbPresenter; + this.tcpMediator = tcpMediator; + tcpMediator.setServerTcpMessageHandler(this); } public SendingMsgRepo getSendingMsgRepo() { @@ -200,10 +202,6 @@ private void handleReceivedCard(IMessage message) { } } - public void setSendWebMessagesListener(SendWebMessagesListener sendWebMessagesListener) { - this.sendWebMessagesListener = sendWebMessagesListener; - } - /** * 「特殊的」将特殊的 Message 发送至 Netty 的处理通道 * @@ -230,21 +228,7 @@ boolean sendMsgTrafficControl(IMessage message) { .newTimeout(timeout -> sendMsgTrafficControl(message), ServerSetting.COMMAND_DELAY_WAITING_TIME, TimeUnit.SECONDS); return true; } - return sendMsgToTcp(message); - } - - /** - * 直接将 Message 发送至 Netty 的处理通道 - * - * @param message 普通消息 Message - * @return 是否发送成功 - */ - private boolean sendMsgToTcp(IMessage message) { - if (sendWebMessagesListener == null) { - logger.warn("Server 模块未能与 Netty 模块建立连接,故不能发送消息集合"); - return false; - } - return sendWebMessagesListener.sendMessagesToTcp(message); + return tcpMediator.sendMsgToNetty(message); } void setKyServerCenterHandler(KyServerCenterHandler kyServerCenterHandler) { diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/message/ChargeStatus.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/message/ChargeStatus.java new file mode 100644 index 0000000..8fc2ef9 --- /dev/null +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/message/ChargeStatus.java @@ -0,0 +1,44 @@ +package cc.bitky.clustermanage.server.message; + +public interface ChargeStatus { + + /** + * 未初始化 + */ + int UNINIT = 0; + + /** + * 使用中 + */ + int USING = 1; + + /** + * 充电中 + */ + int CHARGING = 2; + + /** + * 已充满 + */ + int FULL = 3; + + /** + * 通信故障 + */ + int TRAFFIC_ERROR = 4; + + /** + * 充电故障 + */ + int CHARGE_ERROR = 5; + + /** + * 矿灯未挂好 + */ + int HUNG_ERROR = 6; + + /** + * 多种故障 + */ + int CRASH = 50; +} diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/schedule/SendingMsgRepo.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/schedule/SendingMsgRepo.java index df69f3c..f3fa813 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/schedule/SendingMsgRepo.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/server/schedule/SendingMsgRepo.java @@ -3,8 +3,8 @@ import org.springframework.stereotype.Repository; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingDeque; import cc.bitky.clustermanage.server.message.send.SendableMsg; @@ -14,7 +14,7 @@ @Repository public class SendingMsgRepo { private final List channelPipelines = new ArrayList<>(); - private final HashMap MsgHashMap = new HashMap<>(65536); + private final ConcurrentHashMap MsgHashMap = new ConcurrentHashMap<>(65536); private final HashedWheelTimer hashedWheelTimer = new HashedWheelTimer(); private final LinkedBlockingDeque linkedBlockingDeque = new LinkedBlockingDeque<>(655360); @@ -22,7 +22,7 @@ public List getChannelPipelines() { return channelPipelines; } - public HashMap getMsgHashMap() { + public ConcurrentHashMap getMsgHashMap() { return MsgHashMap; } diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/TcpMediator.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/TcpMediator.java new file mode 100644 index 0000000..67c1e45 --- /dev/null +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/TcpMediator.java @@ -0,0 +1,77 @@ +package cc.bitky.clustermanage.tcp; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.util.List; + +import cc.bitky.clustermanage.server.bean.ServerTcpMessageHandler; +import cc.bitky.clustermanage.server.message.base.BaseTcpResponseMsg; +import cc.bitky.clustermanage.server.message.base.IMessage; +import cc.bitky.clustermanage.server.message.send.SendableMsg; +import cc.bitky.clustermanage.server.message.tcp.TcpMsgResponseStatus; +import cc.bitky.clustermanage.server.schedule.SendingMsgRepo; +import cc.bitky.clustermanage.tcp.server.MsgToCanParser; +import io.netty.channel.ChannelPipeline; + +/** + * Netty 模块和上层服务器的中介者 + */ +@Service +public class TcpMediator { + + private Logger logger = LoggerFactory.getLogger(getClass()); + private ServerTcpMessageHandler serverTcpMessageHandler; + private MsgToCanParser msgToCanParser; + + public void setMsgToCanParser(MsgToCanParser msgToCanParser) { + this.msgToCanParser = msgToCanParser; + } + + + public SendingMsgRepo getSendingMsgRepo() { + return serverTcpMessageHandler.getSendingMsgRepo(); + } + + public void writeCanToTcp(SendableMsg sendableMsg) { + List channelPipelines = getSendingMsgRepo().getChannelPipelines(); + if (channelPipelines.size() == 0) return; + channelPipelines.forEach(pipe -> pipe.writeAndFlush(sendableMsg)); + } + + /** + * 直接将 Message 发送至 Netty 的处理通道 + * + * @param message 普通消息 Message + * @return 是否发送成功 + */ + public boolean sendMsgToNetty(IMessage message) { + if (getSendingMsgRepo().getChannelPipelines().size() > 0) { + msgToCanParser.write(message); + return true; + } + logger.warn("没有可用的 TCP 连接,故该信息无法发送"); + return false; + } + + public void setServerTcpMessageHandler(ServerTcpMessageHandler serverTcpMessageHandler) { + this.serverTcpMessageHandler = serverTcpMessageHandler; + } + + public void handleTcpResponseMsg(BaseTcpResponseMsg msg) { + serverTcpMessageHandler.handleTcpResponseMsg(msg); + } + + public void handleResDeviceStatus(TcpMsgResponseStatus msg) { + serverTcpMessageHandler.handleResDeviceStatus(msg); + } + + public void handleTcpInitMsg(IMessage msg) { + serverTcpMessageHandler.handleTcpInitMsg(msg); + } + + public void handleTcpMsg() { + serverTcpMessageHandler.handleTcpMsg(); + } +} diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/WebMsgOutBoundHandler.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/MsgToCanParser.java similarity index 87% rename from clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/WebMsgOutBoundHandler.java rename to clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/MsgToCanParser.java index 7975f68..4a03679 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/WebMsgOutBoundHandler.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/MsgToCanParser.java @@ -1,4 +1,4 @@ -package cc.bitky.clustermanage.tcp.server.channelhandler; +package cc.bitky.clustermanage.tcp.server; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,24 +19,27 @@ import cc.bitky.clustermanage.server.message.web.WebMsgInitMarchConfirmCardResponse; import cc.bitky.clustermanage.server.message.web.WebMsgObtainDeviceStatus; import cc.bitky.clustermanage.server.message.web.WebMsgOperateBoxUnlock; +import cc.bitky.clustermanage.tcp.TcpMediator; import cc.bitky.clustermanage.tcp.util.TcpMsgBuilder; -import io.netty.channel.ChannelHandler; +/** + * 服务器 Message 消息解析为 TCP 通道的 CAN 帧 + */ @Service -@ChannelHandler.Sharable -public class WebMsgOutBoundHandler { +public class MsgToCanParser { private final TcpMsgBuilder tcpMsgBuilder; - private final QueuingOutBoundHandler queuingOutBoundHandler; + private final PolicyCanTransmitter policyCanTransmitter; private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired - public WebMsgOutBoundHandler(TcpMsgBuilder tcpMsgBuilder, QueuingOutBoundHandler queuingOutBoundHandler) { + public MsgToCanParser(TcpMsgBuilder tcpMsgBuilder, PolicyCanTransmitter policyCanTransmitter, TcpMediator tcpMediator) { this.tcpMsgBuilder = tcpMsgBuilder; - this.queuingOutBoundHandler = queuingOutBoundHandler; + this.policyCanTransmitter = policyCanTransmitter; + tcpMediator.setMsgToCanParser(this); } - void write(IMessage message) { + public void write(IMessage message) { logger.info("Netty 通道获取 Message「" + message.getGroupId() + ", " + message.getDeviceId() + ", " + message.getMsgId() + "」"); if (message.getMsgId() == MsgType.SERVER_SEND_SPECIAL) { @@ -49,7 +52,7 @@ void write(IMessage message) { for (int k = 1; k <= msgSpecial.getMaxGroupId(); k++) { baseMsgSpecial.setDeviceId(j); baseMsgSpecial.setGroupId(k); - unpackComplexMsgToTcp( baseMsgSpecial, msgSpecial.isUrgent(), msgSpecial.isResponsive()); + unpackComplexMsgToTcp(baseMsgSpecial, msgSpecial.isUrgent(), msgSpecial.isResponsive()); } } } else { @@ -59,10 +62,10 @@ void write(IMessage message) { } } } else { - unpackComplexMsgToTcp( baseMsgSpecial, msgSpecial.isUrgent(), msgSpecial.isResponsive()); + unpackComplexMsgToTcp(baseMsgSpecial, msgSpecial.isUrgent(), msgSpecial.isResponsive()); } } else { - unpackComplexMsgToTcp( message, false, true); + unpackComplexMsgToTcp(message, false, true); } } @@ -71,7 +74,7 @@ void write(IMessage message) { * * @param message 信息 bean */ - private void unpackComplexMsgToTcp( IMessage message, boolean urgent, boolean responsive) { + private void unpackComplexMsgToTcp(IMessage message, boolean urgent, boolean responsive) { switch (message.getMsgId()) { case MsgType.SERVER_SET_EMPLOYEE_DEPARTMENT_1: byte[] bytesDepartment = buildByMessage(message); @@ -79,8 +82,8 @@ private void unpackComplexMsgToTcp( IMessage message, boolean urgent, boolean re byte[] bytesD2 = new byte[13]; System.arraycopy(bytesDepartment, 0, bytesD1, 0, 13); System.arraycopy(bytesDepartment, 13, bytesD2, 0, 13); - deployWriteTcpSpecial( bytesD1, urgent, responsive); - deployWriteTcpSpecial( bytesD2, urgent, responsive); + deployWriteTcpSpecial(bytesD1, urgent, responsive); + deployWriteTcpSpecial(bytesD2, urgent, responsive); return; case MsgType.SERVER_SET_FREE_CARD_NUMBER: @@ -90,7 +93,7 @@ private void unpackComplexMsgToTcp( IMessage message, boolean urgent, boolean re byte[] bytesF = new byte[13]; System.arraycopy(bytesFree, 13 * i, bytesF, 0, 13); bytesF[0] += 8; - deployWriteTcpSpecial( bytesF, urgent, responsive); + deployWriteTcpSpecial(bytesF, urgent, responsive); } return; } @@ -99,7 +102,6 @@ private void unpackComplexMsgToTcp( IMessage message, boolean urgent, boolean re /** * 「特殊的的」将 byte[] 转化为 SendableMsg 并传入下一级写出通道 - * */ private void deployWriteTcpSpecial(byte[] bytes, boolean urgent, boolean responsive) { if (bytes == null || bytes.length == 0) { @@ -109,7 +111,7 @@ private void deployWriteTcpSpecial(byte[] bytes, boolean urgent, boolean respons SendableMsg sendableMsg = new SendableMsg(bytes); sendableMsg.setUrgent(urgent); sendableMsg.setResponsive(responsive); - queuingOutBoundHandler.write(sendableMsg); + policyCanTransmitter.write(sendableMsg); } private byte[] buildByMessage(IMessage message) { @@ -161,6 +163,7 @@ private byte[] buildByMessage(IMessage message) { WebMsgInitClearDeviceStatus clearDeviceStatus = (WebMsgInitClearDeviceStatus) message; logger.info("生成帧:清除设备的初始化状态"); return tcpMsgBuilder.buildClearDeviceStatus(clearDeviceStatus); + default: logger.info("未匹配功能位「" + message.getMsgId() + "」,无法生成 CAN 帧"); break; diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/QueuingOutBoundHandler.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/PolicyCanTransmitter.java similarity index 63% rename from clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/QueuingOutBoundHandler.java rename to clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/PolicyCanTransmitter.java index fb61ce0..e308297 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/QueuingOutBoundHandler.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/PolicyCanTransmitter.java @@ -1,37 +1,35 @@ -package cc.bitky.clustermanage.tcp.server.channelhandler; +package cc.bitky.clustermanage.tcp.server; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import cc.bitky.clustermanage.global.ServerSetting; -import cc.bitky.clustermanage.server.bean.ServerTcpMessageHandler; import cc.bitky.clustermanage.server.message.send.SendableMsg; import cc.bitky.clustermanage.server.message.tcp.TcpMsgResponseStatus; import cc.bitky.clustermanage.server.schedule.MsgKey; -import io.netty.channel.ChannelHandler; +import cc.bitky.clustermanage.tcp.TcpMediator; import io.netty.util.HashedWheelTimer; +/** + * 包含检错重发策略的 CAN 帧发送器 + */ @Service -@ChannelHandler.Sharable -public class QueuingOutBoundHandler { - private ServerChannelInitializer serverChannelInitializer; +public class PolicyCanTransmitter { + private final TcpMediator tcpMediator; private ScheduledExecutorService scheduledExecutorService; - private Logger logger = LoggerFactory.getLogger(getClass()); - void setServerChannelInitializer(ServerChannelInitializer serverChannelInitializer) { - this.serverChannelInitializer = serverChannelInitializer; - } - - private ServerTcpMessageHandler getServerTcpMessageHandler() { - return serverChannelInitializer.getServerTcpMessageHandler(); + @Autowired + public PolicyCanTransmitter(TcpMediator tcpMediator) { + this.tcpMediator = tcpMediator; } void write(SendableMsg message) { @@ -47,14 +45,14 @@ private void initTimer() { if (scheduledExecutorService == null) { scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); scheduledExecutorService.scheduleWithFixedDelay(() -> { - if (!getLinkedBlockingDeque().isEmpty()) { - SendableMsg message = getLinkedBlockingDeque().poll(); - getMsgHashMap().put(message.getMsgKey(), message.getBytes()); - serverChannelInitializer.writeToTcp(message); - if (message.isResponsive()) - setWheelTask(message); - } - }, 0, ServerSetting.FRAME_SEND_INTERVAL, TimeUnit.MILLISECONDS); + if (!getLinkedBlockingDeque().isEmpty()) { + SendableMsg message = getLinkedBlockingDeque().poll(); + getMsgHashMap().put(message.getMsgKey(), message.getBytes()); + tcpMediator.writeCanToTcp(message); + if (message.isResponsive()) + setWheelTask(message); + } + }, 0, ServerSetting.FRAME_SEND_INTERVAL, TimeUnit.MILLISECONDS); } } @@ -66,10 +64,10 @@ private void setWheelTask(SendableMsg message) { if (getMsgHashMap().get(msgKey) != null) { logger.info("时间轮「3」:出错"); message.increaseSendTimes(); - if (message.getSendTimes() >= 3) { + if (message.getSendTimes() >= ServerSetting.AUTO_REPEAT_REQUEST_TIMES) { getMsgHashMap().remove(msgKey); logger.info("时间轮「4」:记录"); - getServerTcpMessageHandler().handleResDeviceStatus( + tcpMediator.handleResDeviceStatus( new TcpMsgResponseStatus(msgKey.getGroupId(), msgKey.getDeviceId(), 5, TcpMsgResponseStatus.ResSource.SERVER)); } else { logger.info("时间轮「4」:重新设置"); @@ -85,14 +83,14 @@ private void setWheelTask(SendableMsg message) { } private HashedWheelTimer getHashedWheelTimer() { - return getServerTcpMessageHandler().getSendingMsgRepo().getHashedWheelTimer(); + return tcpMediator.getSendingMsgRepo().getHashedWheelTimer(); } - private HashMap getMsgHashMap() { - return getServerTcpMessageHandler().getSendingMsgRepo().getMsgHashMap(); + private ConcurrentHashMap getMsgHashMap() { + return tcpMediator.getSendingMsgRepo().getMsgHashMap(); } private LinkedBlockingDeque getLinkedBlockingDeque() { - return getServerTcpMessageHandler().getSendingMsgRepo().getLinkedBlockingDeque(); + return tcpMediator.getSendingMsgRepo().getLinkedBlockingDeque(); } } diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/ConfigInBoundHandler.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/ConfigHandler.java similarity index 67% rename from clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/ConfigInBoundHandler.java rename to clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/ConfigHandler.java index 46fc24f..6d26d93 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/ConfigInBoundHandler.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/ConfigHandler.java @@ -2,10 +2,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; +import cc.bitky.clustermanage.tcp.TcpMediator; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; @@ -13,20 +15,21 @@ @Service @ChannelHandler.Sharable -public class ConfigInBoundHandler extends ChannelInboundHandlerAdapter { - private ServerChannelInitializer serverChannelInitializer; - private Logger logger = LoggerFactory.getLogger(ConfigInBoundHandler.class); +public class ConfigHandler extends ChannelInboundHandlerAdapter { + private final TcpMediator tcpMediator; + private Logger logger = LoggerFactory.getLogger(ConfigHandler.class); private int i = 0; - void setServerChannelInitializer(ServerChannelInitializer serverChannelInitializer) { - this.serverChannelInitializer = serverChannelInitializer; + @Autowired + public ConfigHandler(TcpMediator tcpMediator) { + this.tcpMediator = tcpMediator; } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { super.channelActive(ctx); logger.info("通道重置"); - List channelPipelines = serverChannelInitializer.getServerTcpMessageHandler().getSendingMsgRepo().getChannelPipelines(); + List channelPipelines = tcpMediator.getSendingMsgRepo().getChannelPipelines(); channelPipelines.add(ctx.pipeline()); channelPipelines.removeIf(channel -> { i++; diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/ParsedMessageInBoundHandler.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/ParsedMessageInBoundHandler.java index 834f612..f8feabe 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/ParsedMessageInBoundHandler.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/ParsedMessageInBoundHandler.java @@ -1,11 +1,12 @@ package cc.bitky.clustermanage.tcp.server.channelhandler; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import cc.bitky.clustermanage.server.bean.ServerTcpMessageHandler; import cc.bitky.clustermanage.server.message.base.BaseTcpResponseMsg; import cc.bitky.clustermanage.server.message.base.IMessage; import cc.bitky.clustermanage.server.message.tcp.TcpMsgResponseStatus; +import cc.bitky.clustermanage.tcp.TcpMediator; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; @@ -13,14 +14,12 @@ @Service @ChannelHandler.Sharable public class ParsedMessageInBoundHandler extends SimpleChannelInboundHandler { - private ServerChannelInitializer serverChannelInitializer; - void setServerChannelInitializer(ServerChannelInitializer serverChannelInitializer) { - this.serverChannelInitializer = serverChannelInitializer; - } + private final TcpMediator tcpMediator; - private ServerTcpMessageHandler getServerTcpMessageHandler() { - return serverChannelInitializer.getServerTcpMessageHandler(); + @Autowired + public ParsedMessageInBoundHandler(TcpMediator tcpMediator) { + this.tcpMediator = tcpMediator; } @Override @@ -31,17 +30,17 @@ protected void channelRead0(ChannelHandlerContext ctx, IMessage msg) { //将常规回复帧信息传入「常规回复信息处理方法」 if (msg.getMsgId() > 0x40 && msg.getMsgId() <= 0x4F) { - getServerTcpMessageHandler().handleTcpResponseMsg((BaseTcpResponseMsg) msg); + tcpMediator.handleTcpResponseMsg((BaseTcpResponseMsg) msg); return; } if (msg.getMsgId() >= ((byte) 0x80) && msg.getMsgId() <= ((byte) 0x8F)) { - getServerTcpMessageHandler().handleTcpResponseMsg((BaseTcpResponseMsg) msg); + tcpMediator.handleTcpResponseMsg((BaseTcpResponseMsg) msg); return; } if (msg.getMsgId() == 0x40) { - getServerTcpMessageHandler().handleResDeviceStatus((TcpMsgResponseStatus) msg); + tcpMediator.handleResDeviceStatus((TcpMsgResponseStatus) msg); return; } @@ -49,11 +48,11 @@ protected void channelRead0(ChannelHandlerContext ctx, IMessage msg) { byte a0 = (byte) 0xA0; byte af = (byte) 0xAF; if (msg.getMsgId() >= a0 && msg.getMsgId() <= af) { - getServerTcpMessageHandler().handleTcpInitMsg(msg); + tcpMediator.handleTcpInitMsg(msg); return; } //将其余功能帧信息传入「功能信息处理方法」 - getServerTcpMessageHandler().handleTcpMsg(); + tcpMediator.handleTcpMsg(); } } diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/ServerChannelInitializer.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/ServerChannelInitializer.java index d05ae7c..e2e2c1f 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/ServerChannelInitializer.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/server/channelhandler/ServerChannelInitializer.java @@ -3,71 +3,37 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.List; - -import cc.bitky.clustermanage.server.bean.ServerTcpMessageHandler; -import cc.bitky.clustermanage.server.message.send.SendableMsg; import io.netty.channel.ChannelInitializer; -import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.logging.LogLevel; import io.netty.handler.logging.LoggingHandler; @Service public class ServerChannelInitializer extends ChannelInitializer { - private final ConfigInBoundHandler configInBoundHandler; + private final ConfigHandler configHandler; private final CanFrameChannelInboundHandler canFrameChannelInboundHandler; private final ParsedMessageInBoundHandler parsedMessageInBoundHandler; - private final WebMsgOutBoundHandler webMsgOutBoundHandler; private final SendingOutBoundHandler sendingOutBoundHandler; - private final ServerTcpMessageHandler serverTcpMessageHandler; @Autowired - public ServerChannelInitializer(ServerTcpMessageHandler serverTcpMessageHandler, - ConfigInBoundHandler configInBoundHandler, + public ServerChannelInitializer(ConfigHandler configHandler, CanFrameChannelInboundHandler canFrameChannelInboundHandler, ParsedMessageInBoundHandler parsedMessageInBoundHandler, - WebMsgOutBoundHandler webMsgOutBoundHandler, - QueuingOutBoundHandler queuingOutBoundHandler, SendingOutBoundHandler sendingOutBoundHandler) { - this.serverTcpMessageHandler = serverTcpMessageHandler; - this.configInBoundHandler = configInBoundHandler; + this.configHandler = configHandler; this.canFrameChannelInboundHandler = canFrameChannelInboundHandler; this.parsedMessageInBoundHandler = parsedMessageInBoundHandler; - this.webMsgOutBoundHandler = webMsgOutBoundHandler; this.sendingOutBoundHandler = sendingOutBoundHandler; - - queuingOutBoundHandler.setServerChannelInitializer(this); - parsedMessageInBoundHandler.setServerChannelInitializer(this); - configInBoundHandler.setServerChannelInitializer(this); - } - - ServerTcpMessageHandler getServerTcpMessageHandler() { - return serverTcpMessageHandler; } - void writeToTcp(SendableMsg sendableMsg) { - List channelPipelines = getServerTcpMessageHandler().getSendingMsgRepo().getChannelPipelines(); - if (channelPipelines.size() == 0) return; - channelPipelines.forEach(pipe -> pipe.writeAndFlush(sendableMsg)); - } @Override protected void initChannel(NioSocketChannel ch) { ch.pipeline().addLast(new LoggingHandler("kyOutlineLogger", LogLevel.INFO)); - ch.pipeline().addLast(configInBoundHandler); + ch.pipeline().addLast(configHandler); ch.pipeline().addLast(canFrameChannelInboundHandler); ch.pipeline().addLast(parsedMessageInBoundHandler); ch.pipeline().addLast(sendingOutBoundHandler); - - getServerTcpMessageHandler().setSendWebMessagesListener(iMessages -> { - if (getServerTcpMessageHandler().getSendingMsgRepo().getChannelPipelines().size() > 0) { - webMsgOutBoundHandler.write(iMessages); - return true; - } - return false; - } - ); } } diff --git a/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/util/TcpMsgBuilder.java b/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/util/TcpMsgBuilder.java index 5ff1387..56ade99 100644 --- a/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/util/TcpMsgBuilder.java +++ b/clustermanage-server/src/main/java/cc/bitky/clustermanage/tcp/util/TcpMsgBuilder.java @@ -18,7 +18,7 @@ @Component public class TcpMsgBuilder { - private Charset charset_GB2312 = Charset.forName("EUC-CN"); + private Charset charset_GB2312 = Charset.forName("EUC-CN"); public static String byteArrayToString(byte[] cards) { StringBuilder builder = new StringBuilder();