initial
This commit is contained in:
parent
e0a947f050
commit
9d75942afb
2
pom.xml
2
pom.xml
@ -16,6 +16,8 @@
|
|||||||
<module>ym-basic</module>
|
<module>ym-basic</module>
|
||||||
<module>ym-schedule-task</module>
|
<module>ym-schedule-task</module>
|
||||||
<module>ym-websocket</module>
|
<module>ym-websocket</module>
|
||||||
|
<module>ym-packing</module>
|
||||||
|
<module>ym-s7</module>
|
||||||
</modules>
|
</modules>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>ym-pass</artifactId>
|
|
||||||
<groupId>com.cnbm</groupId>
|
<groupId>com.cnbm</groupId>
|
||||||
|
<artifactId>ym-pass</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
@ -22,11 +22,31 @@
|
|||||||
<artifactId>ym-common</artifactId>
|
<artifactId>ym-common</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cnbm</groupId>
|
||||||
|
<artifactId>ym-s7</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cnbm</groupId>
|
||||||
|
<artifactId>ym-packing</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.cnbm</groupId>
|
<groupId>com.cnbm</groupId>
|
||||||
<artifactId>ym-admin</artifactId>
|
<artifactId>ym-admin</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cnbm</groupId>
|
||||||
|
<artifactId>ym-packing</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.cnbm</groupId>
|
<groupId>com.cnbm</groupId>
|
||||||
<artifactId>ym-barcode</artifactId>
|
<artifactId>ym-barcode</artifactId>
|
||||||
|
@ -54,6 +54,22 @@ public class SwaggerConfig {
|
|||||||
.securitySchemes(Arrays.asList(new ApiKey("token", "token", "header")));
|
.securitySchemes(Arrays.asList(new ApiKey("token", "token", "header")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Docket packingApi() {
|
||||||
|
return new Docket(DocumentationType.SWAGGER_2)
|
||||||
|
.groupName("ym-packing")
|
||||||
|
.apiInfo(apiInfo("包装模块", "V1"))
|
||||||
|
.useDefaultResponseMessages(true)
|
||||||
|
.forCodeGeneration(false)
|
||||||
|
.select()
|
||||||
|
.apis(RequestHandlerSelectors.basePackage("com.cnbm.packing"))
|
||||||
|
.paths(PathSelectors.any())
|
||||||
|
.build()
|
||||||
|
.securityContexts(Arrays.asList(securityContext()))
|
||||||
|
// ApiKey的name需与SecurityReference的reference保持一致
|
||||||
|
.securitySchemes(Arrays.asList(new ApiKey("token", "token", "header")));
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Docket adminApi() {
|
public Docket adminApi() {
|
||||||
return new Docket(DocumentationType.SWAGGER_2)
|
return new Docket(DocumentationType.SWAGGER_2)
|
||||||
@ -69,6 +85,21 @@ public class SwaggerConfig {
|
|||||||
// ApiKey的name需与SecurityReference的reference保持一致
|
// ApiKey的name需与SecurityReference的reference保持一致
|
||||||
.securitySchemes(Arrays.asList(new ApiKey("token", "token", "header")));
|
.securitySchemes(Arrays.asList(new ApiKey("token", "token", "header")));
|
||||||
}
|
}
|
||||||
|
@Bean
|
||||||
|
public Docket s7Api() {
|
||||||
|
return new Docket(DocumentationType.SWAGGER_2)
|
||||||
|
.groupName("ym-s7")
|
||||||
|
.apiInfo(apiInfo("基于西门子S7协议采集模块", "基于西门子S7协议采集模块"))
|
||||||
|
.useDefaultResponseMessages(true)
|
||||||
|
.forCodeGeneration(false)
|
||||||
|
.select()
|
||||||
|
.apis(RequestHandlerSelectors.basePackage("com.cnbm.s7"))
|
||||||
|
.paths(PathSelectors.any())
|
||||||
|
.build()
|
||||||
|
.securityContexts(Arrays.asList(securityContext()))
|
||||||
|
// ApiKey的name需与SecurityReference的reference保持一致
|
||||||
|
.securitySchemes(Arrays.asList(new ApiKey("token", "token", "header")));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建该API的基本信息(这些基本信息会展现在文档页面中)
|
* 创建该API的基本信息(这些基本信息会展现在文档页面中)
|
||||||
|
@ -7,7 +7,7 @@ server:
|
|||||||
min-spare: 30
|
min-spare: 30
|
||||||
port: 8080
|
port: 8080
|
||||||
servlet:
|
servlet:
|
||||||
context-path: /ym-pass
|
context-path: /ym-cigs4
|
||||||
session:
|
session:
|
||||||
cookie:
|
cookie:
|
||||||
http-only: true
|
http-only: true
|
||||||
|
27
ym-packing/pom.xml
Normal file
27
ym-packing/pom.xml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>com.cnbm</groupId>
|
||||||
|
<artifactId>ym-pass</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>ym-packing</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.cnbm</groupId>
|
||||||
|
<artifactId>ym-common</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
7
ym-packing/src/main/java/com/cnbm/packing/Main.java
Normal file
7
ym-packing/src/main/java/com/cnbm/packing/Main.java
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package com.cnbm.packing;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println("Hello world!");
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.cnbm.packing.controller;
|
||||||
|
|
||||||
|
import io.swagger.annotations.Api;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import com.cnbm.common.utils.Result;
|
||||||
|
/**
|
||||||
|
* @Author weihongyang
|
||||||
|
* @Date 2022/6/24 8:57 AM
|
||||||
|
* @Version 1.0
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/packing")
|
||||||
|
public class TestController {
|
||||||
|
|
||||||
|
@GetMapping("get")
|
||||||
|
public Result<Integer> get(){
|
||||||
|
return new Result<Integer>().ok(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("get2")
|
||||||
|
public Result<Integer> get2(){
|
||||||
|
return new Result<Integer>().ok(2);
|
||||||
|
}
|
||||||
|
}
|
40
ym-s7/pom.xml
Normal file
40
ym-s7/pom.xml
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>com.cnbm</groupId>
|
||||||
|
<artifactId>ym-pass</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>ym-s7</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>8</maven.compiler.source>
|
||||||
|
<maven.compiler.target>8</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- retry 结束 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.retry</groupId>
|
||||||
|
<artifactId>spring-retry</artifactId>
|
||||||
|
<version>1.2.2.RELEASE</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.testng</groupId>
|
||||||
|
<artifactId>testng</artifactId>
|
||||||
|
<version>6.11</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>junit</groupId>
|
||||||
|
<artifactId>junit</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- retry 结束 -->
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
7
ym-s7/src/main/java/com/cnbm/Main.java
Normal file
7
ym-s7/src/main/java/com/cnbm/Main.java
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package com.cnbm;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
System.out.println("Hello world!");
|
||||||
|
}
|
||||||
|
}
|
270
ym-s7/src/main/java/com/cnbm/s7/controller/S7DemoController.java
Normal file
270
ym-s7/src/main/java/com/cnbm/s7/controller/S7DemoController.java
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
package com.cnbm.s7.controller;
|
||||||
|
|
||||||
|
import com.cnbm.s7.entity.R;
|
||||||
|
import com.cnbm.s7.entity.AGVInfoCallBack;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.enmuc.PlcVarActual;
|
||||||
|
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.enmuc.S7Client;
|
||||||
|
import com.cnbm.s7.s7connector.type.PlcVar;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/s7")
|
||||||
|
public class S7DemoController {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(S7DemoController.class);
|
||||||
|
|
||||||
|
// @Autowired
|
||||||
|
// InfluxDBClient influxDBClient;
|
||||||
|
//
|
||||||
|
// @PostMapping("/insert")
|
||||||
|
// public void insert() throws InterruptedException {
|
||||||
|
// Event event = new Event();
|
||||||
|
// event.setTime(Instant.now());
|
||||||
|
// event.setTransationId("asasd11");
|
||||||
|
// event.setArgName("argName11");
|
||||||
|
// event.setArgValue(7d);
|
||||||
|
// Point asProcessCompleteEvent = insert(event, "ASProcessCompleteEventSSS");
|
||||||
|
// influxDBClient.makeWriteApi().writePoint(asProcessCompleteEvent);
|
||||||
|
// }
|
||||||
|
|
||||||
|
@PostMapping(value = "testFor")
|
||||||
|
private void testFor(@RequestBody AGVInfoCallBack agvInfoCallBack) {
|
||||||
|
|
||||||
|
System.out.println(agvInfoCallBack.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
//demo1
|
||||||
|
@PostMapping("/testReadAll")
|
||||||
|
public R testReadAll() throws UnsupportedEncodingException, ParseException {
|
||||||
|
for(PlcVarActual actual:PlcVarActual.values()){
|
||||||
|
System.out.println(read(S7Client.S7_1500,actual));
|
||||||
|
}
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
// public Point insert(Event event, String measurement){
|
||||||
|
// Point point = Point.measurement(measurement)
|
||||||
|
// .addTag("transationId", event.getTransationId())
|
||||||
|
// .addTag("argName", event.getArgName())
|
||||||
|
// .addField("argValue", event.getArgValue())
|
||||||
|
// .time(event.getTime().toEpochMilli(), WritePrecision.MS);
|
||||||
|
// return point;
|
||||||
|
// }
|
||||||
|
//demo2
|
||||||
|
@PostMapping("/readTest")
|
||||||
|
public R getTestForS7() throws UnsupportedEncodingException, ParseException {
|
||||||
|
Boolean heartBeat = (Boolean)read(S7Client.S7_1500,PlcVarActual.HeartBeat);
|
||||||
|
String ddtl = (String)read(S7Client.S7_1500,PlcVarActual.DTL);
|
||||||
|
List<Character> characters = (List<Character>)read(S7Client.S7_1500,PlcVarActual.CharArrays);
|
||||||
|
|
||||||
|
List<Boolean> booleans = (List<Boolean>)read(S7Client.S7_1500,PlcVarActual.BooleanArrays);
|
||||||
|
|
||||||
|
String stri = (String)read(S7Client.S7_1500,PlcVarActual.STRING1);
|
||||||
|
|
||||||
|
return R.ok().put("res",heartBeat).put("characters",characters).put("ddtl",ddtl).put("bools",booleans).put("str",stri);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/readTest2")
|
||||||
|
public R getTest2ForS7() throws Exception {
|
||||||
|
// List<Character> characters = (List<Character>)read(PlcVarActual.CharArrays,S7Client.S7_1500);
|
||||||
|
//
|
||||||
|
// List<Boolean> booleans = (List<Boolean>)read(PlcVarActual.BooleanArrays,S7Client.S7_1500);
|
||||||
|
// String stri = (String)read(PlcVarActual.STRING1,S7Client.S7_1500);
|
||||||
|
//
|
||||||
|
// return R.ok().put("res",heartBeat).put("characters",characters).put("ddtl",ddtl).put("bools",booleans).put("str",stri);
|
||||||
|
String con = "1233ADSDA";
|
||||||
|
write(S7Client.S7_1500,PlcVarActual.STRING1, con);
|
||||||
|
String read = (String)read(S7Client.S7_1500,PlcVarActual.STRING1);
|
||||||
|
String sub0 = (String)read(S7Client.S7_1500,PlcVarActual.SUBID0);
|
||||||
|
|
||||||
|
|
||||||
|
return R.ok().put("str",read).put("sub0",sub0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/testWriteBooleanArray")
|
||||||
|
public R testWriteBooleanArray() throws Exception {
|
||||||
|
|
||||||
|
List<Boolean> string = (List<Boolean>)read(S7Client.S7_1500,PlcVarActual.BooleanArrays1200);
|
||||||
|
System.out.println();
|
||||||
|
boolean[] res = new boolean[15];
|
||||||
|
res[0] = false;
|
||||||
|
res[1] = true;
|
||||||
|
res[2] = false;
|
||||||
|
res[3] = true;
|
||||||
|
res[4] = false;
|
||||||
|
res[5] = true;
|
||||||
|
res[6] = false;
|
||||||
|
res[7] = false;
|
||||||
|
res[8] = false;
|
||||||
|
res[9] = true;
|
||||||
|
res[10] = false;
|
||||||
|
res[11] = false;
|
||||||
|
res[12] = true;
|
||||||
|
res[13] = false;
|
||||||
|
res[14] = true;
|
||||||
|
write(S7Client.S7_1500,PlcVarActual.BooleanArrays1200, res);
|
||||||
|
System.out.println();
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/testForString")
|
||||||
|
public R testForStrings() throws Exception {
|
||||||
|
//测试结果 l => 66ms
|
||||||
|
long l = System.currentTimeMillis();
|
||||||
|
String[] subs = (String[])read(S7Client.S7_1500,PlcVarActual.SubIdArrays);
|
||||||
|
long l1 = System.currentTimeMillis();
|
||||||
|
|
||||||
|
long dl = System.currentTimeMillis();
|
||||||
|
String string = (String)read(S7Client.S7_1500,PlcVarActual.STRING1);
|
||||||
|
long dl1 = System.currentTimeMillis();
|
||||||
|
|
||||||
|
String[] toWrite = new String[60];
|
||||||
|
for(int i=0;i<60;i++){
|
||||||
|
int i1 = new Random().nextInt(100);
|
||||||
|
toWrite[i] = "2212"+ i1;
|
||||||
|
}
|
||||||
|
////测试结果 c => 57ms
|
||||||
|
long c1 = System.currentTimeMillis();
|
||||||
|
write(S7Client.S7_1500,PlcVarActual.SubIdArrays,toWrite);
|
||||||
|
long c2 = System.currentTimeMillis();
|
||||||
|
String s = "cai xiang";
|
||||||
|
write(S7Client.S7_1500,PlcVarActual.STRING1,s);
|
||||||
|
|
||||||
|
String string2 = (String)read(S7Client.S7_1500,PlcVarActual.STRING1);
|
||||||
|
String[] subs2 = (String[])read(S7Client.S7_1500,PlcVarActual.SubIdArrays);
|
||||||
|
|
||||||
|
return R.ok().put("l",(l1-l)).put("c",(c2-c1)).put("dl",(dl1-dl));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/testForString1200")
|
||||||
|
public R testForString1200() throws Exception {
|
||||||
|
//测试结果 l => 66ms
|
||||||
|
long l = System.currentTimeMillis();
|
||||||
|
String[] subs = (String[])read(S7Client.S7_1500,PlcVarActual.SubIdArrays1200); //65ms
|
||||||
|
long l1 = System.currentTimeMillis();
|
||||||
|
//System.out.println(Arrays.toString(subs));
|
||||||
|
|
||||||
|
String[] toWrite = new String[63];
|
||||||
|
for(int i=0;i<63;i++){
|
||||||
|
//int i1 = new Random().nextInt(100);
|
||||||
|
toWrite[i] = "abcd-"+ i;
|
||||||
|
}
|
||||||
|
////测试结果 c => 57ms
|
||||||
|
long c1 = System.currentTimeMillis();
|
||||||
|
write(S7Client.S7_1500,PlcVarActual.SubIdArrays1200,toWrite);
|
||||||
|
long c2 = System.currentTimeMillis();
|
||||||
|
|
||||||
|
String[] subs2 = (String[])read(S7Client.S7_1500,PlcVarActual.SubIdArrays1200);
|
||||||
|
logger.info("正常测试: l:"+(l1-l)+"c:"+(c2-c1)+";;read1:"+Arrays.toString(subs)+";;read2:"+Arrays.toString(subs2));
|
||||||
|
|
||||||
|
return R.ok().put("l",(l1-l)).put("c",(c2-c1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/testForString1500")
|
||||||
|
public R testForString1500() throws Exception {
|
||||||
|
//测试结果 l => 66ms
|
||||||
|
long l = System.currentTimeMillis();
|
||||||
|
String[] subs = (String[])read(S7Client.S7_1500,PlcVarActual.SubIdArrays); //25ms
|
||||||
|
long l1 = System.currentTimeMillis();
|
||||||
|
System.out.println(Arrays.toString(subs));
|
||||||
|
String[] toWrite = new String[63];
|
||||||
|
for(int i=0;i<63;i++){
|
||||||
|
//int i1 = new Random().nextInt(100);
|
||||||
|
toWrite[i] = "abcd-"+ i;
|
||||||
|
}
|
||||||
|
////测试结果 c => 57ms
|
||||||
|
long c1 = System.currentTimeMillis();
|
||||||
|
write(S7Client.S7_1500,PlcVarActual.SubIdArrays,toWrite);
|
||||||
|
long c2 = System.currentTimeMillis();
|
||||||
|
|
||||||
|
|
||||||
|
String[] subs2 = (String[])read(S7Client.S7_1500,PlcVarActual.SubIdArrays);
|
||||||
|
|
||||||
|
return R.ok().put("l",(l1-l)).put("c",(c2-c1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/testFor1200")
|
||||||
|
public R testFor1200() throws Exception {
|
||||||
|
//Object subs = read(PlcVarActual.INT1200, S7Client.S7_1500);
|
||||||
|
Object read = read(S7Client.S7_1500, PlcVarActual.SubIdArrays1200);
|
||||||
|
|
||||||
|
String[] toWrite = new String[60];
|
||||||
|
for(int i=0;i<60;i++){
|
||||||
|
int i1 = new Random().nextInt(100);
|
||||||
|
toWrite[i] = "2212"+ i1;
|
||||||
|
}
|
||||||
|
write(S7Client.S7_1500,PlcVarActual.SubIdArrays1200,toWrite);
|
||||||
|
|
||||||
|
Object read2 = read(S7Client.S7_1500, PlcVarActual.SubIdArrays1200);
|
||||||
|
return R.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//PlcVarActual 到时候改成你们的 xxxPlcToWcs 或者 xxxWcsToPlc
|
||||||
|
/**
|
||||||
|
* return
|
||||||
|
* 成功: 返回相应的object对象
|
||||||
|
* 失败: 返回null
|
||||||
|
* */
|
||||||
|
private Object read(S7Client s7Client,PlcVarActual var) throws UnsupportedEncodingException, ParseException {
|
||||||
|
try {
|
||||||
|
return s7Client.read(var.getArea(), var.getAreaNumber(), var.getByteOffset(), var.getBitOffset(), var.getLength(), var.getStrSize(), var.getType());
|
||||||
|
}catch (Exception e){
|
||||||
|
logger.error("host:"+s7Client.getHost()+" ; read 操作出现问题: "+e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void write(S7Client s7Client,PlcVarActual var,Object newValue) throws Exception {
|
||||||
|
if(var.getType().equals(PlcVar.STRING_Array)){
|
||||||
|
String[] s = (String[])newValue;
|
||||||
|
String[] ss = (String[])newValue;
|
||||||
|
if(s.length > var.getLength() ){
|
||||||
|
ss = new String[var.getLength()];
|
||||||
|
for(int i=0;i< var.getLength();i++){
|
||||||
|
ss[i] = s[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s7Client.write(var.getArea(), var.getAreaNumber(), var.getByteOffset(), var.getBitOffset(), var.getStrSize(), var.getType(),ss);
|
||||||
|
}else {
|
||||||
|
s7Client.write(var.getArea(), var.getAreaNumber(), var.getByteOffset(), var.getBitOffset(), var.getStrSize(), var.getType(),newValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// //demo3
|
||||||
|
// @PostMapping("/writeTest")
|
||||||
|
// public R writeTest() throws PlcConnectionException, UnsupportedEncodingException {
|
||||||
|
// write(S7Client.S7_1500,PlcVarActual.HeartBeat, false);
|
||||||
|
//
|
||||||
|
// char[] charArrays_content = new char[2];
|
||||||
|
// charArrays_content[0] = '1';
|
||||||
|
// charArrays_content[1] = 'c';
|
||||||
|
// write( S7Client.S7_1500,PlcVarActual.CharArrays, charArrays_content);
|
||||||
|
//
|
||||||
|
// boolean[] boolArrays_content = new boolean[2];
|
||||||
|
// boolArrays_content[0] = true;
|
||||||
|
// boolArrays_content[1] = false;
|
||||||
|
// write(S7Client.S7_1500,PlcVarActual.BooleanArrays, boolArrays_content);
|
||||||
|
//
|
||||||
|
// String str = "你好啊aa";
|
||||||
|
// //todo string 的读写有问题 待会看看
|
||||||
|
// write(S7Client.S7_1500,PlcVarActual.STRING1, str);
|
||||||
|
// return R.ok().put("res",true);
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
40
ym-s7/src/main/java/com/cnbm/s7/demo/RetryDemoTask.java
Normal file
40
ym-s7/src/main/java/com/cnbm/s7/demo/RetryDemoTask.java
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package com.cnbm.s7.demo;
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.RandomUtils;
|
||||||
|
import org.springframework.remoting.RemoteAccessException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: zgd
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class RetryDemoTask {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重试方法
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean retryTask(String param) {
|
||||||
|
log.info("收到请求参数:{}",param);
|
||||||
|
|
||||||
|
int i = RandomUtils.nextInt(0,11);
|
||||||
|
log.info("随机生成的数:{}",i);
|
||||||
|
if (i == 0) {
|
||||||
|
log.info("为0,抛出参数异常.");
|
||||||
|
throw new IllegalArgumentException("参数异常");
|
||||||
|
}else if (i == 1){
|
||||||
|
log.info("为1,返回true.");
|
||||||
|
return true;
|
||||||
|
}else if (i == 2){
|
||||||
|
log.info("为2,返回false.");
|
||||||
|
return false;
|
||||||
|
}else{
|
||||||
|
//为其他
|
||||||
|
log.info("大于2,抛出自定义异常.");
|
||||||
|
throw new RemoteAccessException("大于2,抛出远程访问异常");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
package com.cnbm.s7.demo;
|
||||||
|
|
||||||
|
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import org.springframework.remoting.RemoteAccessException;
|
||||||
|
import org.springframework.retry.backoff.FixedBackOffPolicy;
|
||||||
|
import org.springframework.retry.policy.SimpleRetryPolicy;
|
||||||
|
import org.springframework.retry.support.RetryTemplate;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Desc: ""
|
||||||
|
* @Author: caixiang
|
||||||
|
* @DATE: 2022/12/16 15:26
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class SpringRetryTemplateTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重试间隔时间ms,默认1000ms
|
||||||
|
* */
|
||||||
|
private long fixedPeriodTime = 1000L;
|
||||||
|
/**
|
||||||
|
* 最大重试次数,默认为3
|
||||||
|
*/
|
||||||
|
private int maxRetryTimes = 3;
|
||||||
|
/**
|
||||||
|
* 表示哪些异常需要重试,key表示异常的字节码,value为true表示需要重试
|
||||||
|
*/
|
||||||
|
private Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
exceptionMap.put(RemoteAccessException.class,true);
|
||||||
|
|
||||||
|
// 构建重试模板实例
|
||||||
|
RetryTemplate retryTemplate = new RetryTemplate();
|
||||||
|
|
||||||
|
// 设置重试回退操作策略,主要设置重试间隔时间
|
||||||
|
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
|
||||||
|
backOffPolicy.setBackOffPeriod(fixedPeriodTime);
|
||||||
|
|
||||||
|
// 设置重试策略,主要设置重试次数
|
||||||
|
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(maxRetryTimes, exceptionMap);
|
||||||
|
|
||||||
|
retryTemplate.setRetryPolicy(retryPolicy);
|
||||||
|
retryTemplate.setBackOffPolicy(backOffPolicy);
|
||||||
|
|
||||||
|
Boolean execute = retryTemplate.execute(
|
||||||
|
//RetryCallback
|
||||||
|
retryContext -> {
|
||||||
|
boolean b = RetryDemoTask.retryTask("abc");
|
||||||
|
log.info("调用的结果:{}", b);
|
||||||
|
return b;
|
||||||
|
},
|
||||||
|
retryContext -> {
|
||||||
|
//RecoveryCallback
|
||||||
|
log.info("已达到最大重试次数或抛出了不重试的异常~~~");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
log.info("执行结果:{}",execute);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
ym-s7/src/main/java/com/cnbm/s7/entity/AGVInfoCallBack.java
Normal file
24
ym-s7/src/main/java/com/cnbm/s7/entity/AGVInfoCallBack.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package com.cnbm.s7.entity;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 表
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author caixiang
|
||||||
|
* @since 2022-05-31
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class AGVInfoCallBack implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private String warehouseName;
|
||||||
|
private Integer status;
|
||||||
|
private String content;
|
||||||
|
}
|
66
ym-s7/src/main/java/com/cnbm/s7/entity/R.java
Normal file
66
ym-s7/src/main/java/com/cnbm/s7/entity/R.java
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2016-2019 人人开源 All rights reserved.
|
||||||
|
*
|
||||||
|
* https://www.renren.io
|
||||||
|
*
|
||||||
|
* 版权所有,侵权必究!
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.cnbm.s7.entity;
|
||||||
|
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回数据
|
||||||
|
*
|
||||||
|
* @author Mark sunlightcs@gmail.com
|
||||||
|
*/
|
||||||
|
public class R extends HashMap<String, Object> {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
//默认成功 是1
|
||||||
|
public R() {
|
||||||
|
put("code", 1);
|
||||||
|
put("msg", "success");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static R error() {
|
||||||
|
return error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "未知异常,请联系管理员");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static R error(String msg) {
|
||||||
|
return error(HttpStatus.INTERNAL_SERVER_ERROR.value(), msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static R error(int code, String msg) {
|
||||||
|
R r = new R();
|
||||||
|
r.put("code", code);
|
||||||
|
r.put("msg", msg);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static R ok(String msg) {
|
||||||
|
R r = new R();
|
||||||
|
r.put("msg", msg);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static R ok(Map<String, Object> map) {
|
||||||
|
R r = new R();
|
||||||
|
r.putAll(map);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static R ok() {
|
||||||
|
return new R();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public R put(String key, Object value) {
|
||||||
|
super.put(key, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
16
ym-s7/src/main/java/com/cnbm/s7/entity/ReadedBack.java
Normal file
16
ym-s7/src/main/java/com/cnbm/s7/entity/ReadedBack.java
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
package com.cnbm.s7.entity;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Desc: ""
|
||||||
|
* @Author: caixiang
|
||||||
|
* @DATE: 2021/12/6 13:42
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ReadedBack {
|
||||||
|
private Integer size;
|
||||||
|
private List<Object> content;
|
||||||
|
}
|
64
ym-s7/src/main/java/com/cnbm/s7/retry/S7RetryTemplate.java
Normal file
64
ym-s7/src/main/java/com/cnbm/s7/retry/S7RetryTemplate.java
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package com.cnbm.s7.retry;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.exception.S7CheckResultException;
|
||||||
|
import com.cnbm.s7.s7connector.exception.S7IOException;
|
||||||
|
import com.cnbm.s7.s7connector.exception.S7ParseDataException;
|
||||||
|
import org.springframework.remoting.RemoteAccessException;
|
||||||
|
import org.springframework.retry.backoff.FixedBackOffPolicy;
|
||||||
|
import org.springframework.retry.policy.SimpleRetryPolicy;
|
||||||
|
import org.springframework.retry.support.RetryTemplate;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author caixiang
|
||||||
|
* @description 重试模板和重试策略
|
||||||
|
*/
|
||||||
|
public class S7RetryTemplate extends RetryTemplate {
|
||||||
|
|
||||||
|
private volatile static S7RetryTemplate instance = null;
|
||||||
|
/**
|
||||||
|
* 重试间隔时间ms,默认1000ms
|
||||||
|
* */
|
||||||
|
private static long fixedPeriodTime = 500L;
|
||||||
|
/**
|
||||||
|
* 最大重试次数,默认为3
|
||||||
|
*/
|
||||||
|
private static int maxRetryTimes = 3;
|
||||||
|
/**
|
||||||
|
* 表示哪些异常需要重试,key表示异常的字节码,value为true表示需要重试
|
||||||
|
*/
|
||||||
|
private static Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();
|
||||||
|
private S7RetryTemplate() {
|
||||||
|
// 代表S7IOException 这个异常是需要重试的(true), 如果你想设置这个异常不去重试,那么可以把它设置为false。
|
||||||
|
exceptionMap.put(S7IOException.class,true);
|
||||||
|
exceptionMap.put(S7CheckResultException.class,true);
|
||||||
|
exceptionMap.put(S7ParseDataException.class,true);
|
||||||
|
//Exception
|
||||||
|
//exceptionMap.put(Exception.class,true);
|
||||||
|
|
||||||
|
}
|
||||||
|
public static int getMaxRetryTimes() {
|
||||||
|
return maxRetryTimes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static S7RetryTemplate getInstance() {
|
||||||
|
if (instance == null) {
|
||||||
|
synchronized (S7RetryTemplate.class) {
|
||||||
|
if (instance == null) {
|
||||||
|
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
|
||||||
|
// 定义重试间隔-间隔 fixedPeriodTime ms再重试,总共重试3次
|
||||||
|
backOffPolicy.setBackOffPeriod(fixedPeriodTime);
|
||||||
|
instance = new S7RetryTemplate();
|
||||||
|
// 定义重试次数- maxRetryTimes
|
||||||
|
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(maxRetryTimes, exceptionMap);
|
||||||
|
instance.setRetryPolicy(retryPolicy);
|
||||||
|
|
||||||
|
instance.setBackOffPolicy(backOffPolicy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
}
|
94
ym-s7/src/main/java/com/cnbm/s7/retrydemo/RetryDemoTask.java
Normal file
94
ym-s7/src/main/java/com/cnbm/s7/retrydemo/RetryDemoTask.java
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package com.cnbm.s7.retrydemo;
|
||||||
|
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.exception.S7CheckResultException;
|
||||||
|
import com.cnbm.s7.s7connector.impl.S7BaseConnection;
|
||||||
|
import com.cnbm.s7.s7connector.impl.nodave.Nodave;
|
||||||
|
import org.apache.commons.lang3.RandomUtils;
|
||||||
|
import org.springframework.remoting.RemoteAccessException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PipedInputStream;
|
||||||
|
import java.io.PipedOutputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: cx
|
||||||
|
* @Description:
|
||||||
|
*/
|
||||||
|
public class RetryDemoTask {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
PipedInputStream pipedInputStream=new PipedInputStream();
|
||||||
|
PipedOutputStream pipedOutputStream=new PipedOutputStream();
|
||||||
|
try {
|
||||||
|
pipedInputStream.connect(pipedOutputStream);
|
||||||
|
//默认一次最多只能写入1024字节
|
||||||
|
byte[] data=new byte[1000];
|
||||||
|
byte[] store=new byte[20];
|
||||||
|
Arrays.fill(data, (byte)1);
|
||||||
|
System.out.println("first writing data");
|
||||||
|
//每次写1000字节数据
|
||||||
|
pipedOutputStream.write(data,0,data.length);
|
||||||
|
System.out.println("finish first writing");
|
||||||
|
int count=1;
|
||||||
|
while(count<100){
|
||||||
|
System.out.println(count+" times read data");
|
||||||
|
pipedInputStream.read(store, 0, store.length); //每次读20字节数据
|
||||||
|
System.out.println(count+" times finish reading data");
|
||||||
|
System.out.println((count+1)+" times write data");
|
||||||
|
pipedOutputStream.write(data);//每次写1000字节数据
|
||||||
|
System.out.println((count+1)+" times finish writing data");
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重试方法
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public synchronized static boolean retryTask(String param) {
|
||||||
|
System.out.println("retry-task : 收到请求参数:"+param);
|
||||||
|
|
||||||
|
int i = RandomUtils.nextInt(0,11);
|
||||||
|
System.out.println("retry-task : 随机生成的数:"+i);
|
||||||
|
if (i == 0) {
|
||||||
|
System.out.println("retry-task : 为0,抛出参数异常.");
|
||||||
|
//因为Illeague这个异常我们没有在exceptionMap里面配置,所以 抛出这个异常后
|
||||||
|
//spring-retry不会进行重试,而是会直接进入recovery函数
|
||||||
|
throw new IllegalArgumentException("retry-task : 参数异常");
|
||||||
|
}else if (i == 1){
|
||||||
|
System.out.println("retry-task : 为1,返回true.");
|
||||||
|
return true;
|
||||||
|
}else if (i == 2){
|
||||||
|
System.out.println("retry-task : 为2,返回false.");
|
||||||
|
return false;
|
||||||
|
}else{
|
||||||
|
//因为RemoteAccessExcep这个异常我们在exceptionMap里面配置了,所以 抛出这个异常后
|
||||||
|
//spring-retry会进行重试
|
||||||
|
System.out.println("retry-task : 大于2,抛出自定义异常.");
|
||||||
|
throw new RemoteAccessException("retry-task : 大于2,抛出远程访问异常");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static void checkResults(final int libnodaveResult) {
|
||||||
|
if (libnodaveResult != Nodave.RESULT_OK) {
|
||||||
|
final String msg = Nodave.strerror(libnodaveResult);
|
||||||
|
// throw new IllegalArgumentException("Result: " + msg);
|
||||||
|
throw new S7CheckResultException("errMsg : "+msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized static boolean retryTask2(String param) {
|
||||||
|
System.out.println("retry-task : 收到请求参数:"+param+" hashCode:"+Thread.currentThread().hashCode());
|
||||||
|
|
||||||
|
int i = 1;
|
||||||
|
System.out.println("retry-task : 随机生成的数:"+i+" hashCode:"+Thread.currentThread().hashCode());
|
||||||
|
checkResults(i);
|
||||||
|
Integer a =1;
|
||||||
|
a=a+1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
60
ym-s7/src/main/java/com/cnbm/s7/retrydemo/RetryMain.java
Normal file
60
ym-s7/src/main/java/com/cnbm/s7/retrydemo/RetryMain.java
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package com.cnbm.s7.retrydemo;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.exception.S7CheckResultException;
|
||||||
|
import org.springframework.remoting.RemoteAccessException;
|
||||||
|
import org.springframework.retry.backoff.FixedBackOffPolicy;
|
||||||
|
import org.springframework.retry.policy.SimpleRetryPolicy;
|
||||||
|
import org.springframework.retry.support.RetryTemplate;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class RetryMain {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重试间隔时间ms,默认1000ms
|
||||||
|
* */
|
||||||
|
long fixedPeriodTime = 1000L;
|
||||||
|
/**
|
||||||
|
* 最大重试次数,默认为3
|
||||||
|
*/
|
||||||
|
int maxRetryTimes = 3;
|
||||||
|
/**
|
||||||
|
* 表示哪些异常需要重试,key表示异常的字节码,value为true表示需要重试
|
||||||
|
*/
|
||||||
|
Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
exceptionMap.put(RemoteAccessException.class,true);
|
||||||
|
exceptionMap.put(S7CheckResultException.class,true);
|
||||||
|
|
||||||
|
// 构建重试模板实例
|
||||||
|
RetryTemplate retryTemplate = new RetryTemplate();
|
||||||
|
|
||||||
|
// 设置重试回退操作策略,主要设置重试间隔时间
|
||||||
|
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
|
||||||
|
backOffPolicy.setBackOffPeriod(fixedPeriodTime);
|
||||||
|
|
||||||
|
// 设置重试策略,主要设置重试次数
|
||||||
|
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(maxRetryTimes, exceptionMap);
|
||||||
|
|
||||||
|
retryTemplate.setRetryPolicy(retryPolicy);
|
||||||
|
retryTemplate.setBackOffPolicy(backOffPolicy);
|
||||||
|
|
||||||
|
Boolean execute = retryTemplate.execute(
|
||||||
|
//RetryCallback
|
||||||
|
retryContext -> {
|
||||||
|
boolean b = RetryDemoTask.retryTask2("abc");
|
||||||
|
System.err.println("retry-main : 调用的结果:"+b+",times:"+retryContext.getRetryCount()+" hashCode:"+Thread.currentThread().hashCode());
|
||||||
|
return b;
|
||||||
|
},
|
||||||
|
retryContext -> {
|
||||||
|
//RecoveryCallback
|
||||||
|
System.err.println("retry-main : 已达到最大重试次数或抛出了不重试的异常~~~"+" hashCode:"+Thread.currentThread().hashCode());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
System.err.println("retry-main : 执行结果:"+execute);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
package com.cnbm.s7.retrydemo;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.remoting.RemoteAccessException;
|
||||||
|
import org.springframework.retry.backoff.FixedBackOffPolicy;
|
||||||
|
import org.springframework.retry.policy.SimpleRetryPolicy;
|
||||||
|
import org.springframework.retry.support.RetryTemplate;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Author: zgd
|
||||||
|
* @Description: spring-retry 重试框架
|
||||||
|
*/
|
||||||
|
public class SpringS7RetryTemplateTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重试间隔时间ms,默认1000ms
|
||||||
|
* */
|
||||||
|
private long fixedPeriodTime = 1000L;
|
||||||
|
/**
|
||||||
|
* 最大重试次数,默认为3
|
||||||
|
*/
|
||||||
|
private int maxRetryTimes = 3;
|
||||||
|
/**
|
||||||
|
* 表示哪些异常需要重试,key表示异常的字节码,value为true表示需要重试
|
||||||
|
*/
|
||||||
|
private Map<Class<? extends Throwable>, Boolean> exceptionMap = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
|
||||||
|
//文档:https://blog.csdn.net/minghao0508/article/details/123972703
|
||||||
|
exceptionMap.put(RemoteAccessException.class,true);
|
||||||
|
|
||||||
|
// 构建重试模板实例
|
||||||
|
RetryTemplate retryTemplate = new RetryTemplate();
|
||||||
|
|
||||||
|
// 设置重试回退操作策略,主要设置重试间隔时间
|
||||||
|
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
|
||||||
|
backOffPolicy.setBackOffPeriod(fixedPeriodTime);
|
||||||
|
|
||||||
|
// 设置重试策略,主要设置重试次数
|
||||||
|
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy(maxRetryTimes, exceptionMap);
|
||||||
|
|
||||||
|
retryTemplate.setRetryPolicy(retryPolicy);
|
||||||
|
retryTemplate.setBackOffPolicy(backOffPolicy);
|
||||||
|
|
||||||
|
Boolean execute = retryTemplate.execute(
|
||||||
|
//RetryCallback
|
||||||
|
retryContext -> {
|
||||||
|
boolean b = RetryDemoTask.retryTask("abc");
|
||||||
|
System.out.println("调用的结果:"+b);
|
||||||
|
return b;
|
||||||
|
},
|
||||||
|
retryContext -> {
|
||||||
|
//RecoveryCallback
|
||||||
|
System.out.println("已达到最大重试次数或抛出了不重试的异常~~~");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
System.out.println("执行结果:"+execute);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
20
ym-s7/src/main/java/com/cnbm/s7/retrydemo/TestMain.java
Normal file
20
ym-s7/src/main/java/com/cnbm/s7/retrydemo/TestMain.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package com.cnbm.s7.retrydemo;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TestMain {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Integer a = 1;
|
||||||
|
Integer a1 = 2;
|
||||||
|
Integer a2 = 3;
|
||||||
|
List<Integer> list = new ArrayList<Integer>();
|
||||||
|
list.add(a);
|
||||||
|
list.add(a1);
|
||||||
|
list.add(a2);
|
||||||
|
Integer integer = list.get(0);
|
||||||
|
list.remove(integer);
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
49
ym-s7/src/main/java/com/cnbm/s7/retrydemo/lock/LockDemo.java
Normal file
49
ym-s7/src/main/java/com/cnbm/s7/retrydemo/lock/LockDemo.java
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package com.cnbm.s7.retrydemo.lock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Desc: ""
|
||||||
|
* @Author: caixiang
|
||||||
|
* @DATE: 2022/12/23 12:08
|
||||||
|
*/
|
||||||
|
public class LockDemo {
|
||||||
|
|
||||||
|
//对象锁
|
||||||
|
public synchronized void func1() {
|
||||||
|
System.out.println("func1!");
|
||||||
|
try {
|
||||||
|
Thread.sleep(10000);
|
||||||
|
System.out.println("sleep time over!");
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void func2() {
|
||||||
|
System.out.println("func2!");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
LockDemo test2 = new LockDemo();
|
||||||
|
Thread t1 = new Thread(() -> {
|
||||||
|
// test.func1();
|
||||||
|
// try {
|
||||||
|
// S7ClientNew.S7_1500.retry1();
|
||||||
|
// } catch (InterruptedException e) {
|
||||||
|
// throw new RuntimeException(e);
|
||||||
|
// }
|
||||||
|
}, "t1");
|
||||||
|
|
||||||
|
Thread t2 = new Thread(() -> {
|
||||||
|
// test2.func2();
|
||||||
|
// try {
|
||||||
|
// S7ClientNew.S7_1500.retry1();
|
||||||
|
// } catch (InterruptedException e) {
|
||||||
|
// throw new RuntimeException(e);
|
||||||
|
// }
|
||||||
|
}, "t2");
|
||||||
|
|
||||||
|
t1.start();
|
||||||
|
t2.start();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.cnbm.s7.s7connector.Constant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Desc: ""
|
||||||
|
* @Author: caixiang
|
||||||
|
* @DATE: 2022/1/17 15:16
|
||||||
|
*/
|
||||||
|
public class S7ClientArg {
|
||||||
|
public static final Integer S7ClientPoolCore = 3;
|
||||||
|
private static final Integer pickOne = 0;
|
||||||
|
|
||||||
|
public synchronized Integer getPickOne(){
|
||||||
|
return pickOne;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
233
ym-s7/src/main/java/com/cnbm/s7/s7connector/Main2.java
Normal file
233
ym-s7/src/main/java/com/cnbm/s7/s7connector/Main2.java
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
package com.cnbm.s7.s7connector;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ByteUtil;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Desc: ""
|
||||||
|
* @Author: caixiang
|
||||||
|
* @DATE: 2021/12/10 11:22
|
||||||
|
*/
|
||||||
|
public class Main2 {
|
||||||
|
public static byte[] double2Bytes(double d) {
|
||||||
|
long value = Double.doubleToRawLongBits(d);
|
||||||
|
byte[] byteRet = new byte[8];
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
byteRet[i] = (byte) ((value >> 8 * i) & 0xff);
|
||||||
|
}
|
||||||
|
return byteRet;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 1个字节byte[] 转成有符号的short
|
||||||
|
* */
|
||||||
|
public static Integer toInt(byte bytes) {
|
||||||
|
return Integer.valueOf(Byte.toString(bytes));
|
||||||
|
}
|
||||||
|
public static Integer toUInt(byte bytes) {
|
||||||
|
return Integer.valueOf(Byte.toUnsignedInt(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
|
||||||
|
|
||||||
|
byte[] bytes = new byte[2];
|
||||||
|
bytes[0] = -1; //内部是 补码形式存在 //todo 搞清楚 补码和原码什么时候转化
|
||||||
|
bytes[1] = -111;
|
||||||
|
//-1 原码 1000 0001 ;;-1 补码 1111 1111
|
||||||
|
//1000 0001 1110 1111 //原码形式
|
||||||
|
//1111 1111 1001 0001 //补码形式,在计算机内部是以补码形式存储的,当赋值给2个字节后是无符号整形的 要强制转化成short类型后,如果之前首位是1 就会被java强制转化成补码
|
||||||
|
//1000 0000 0110 1111 //
|
||||||
|
//1+16+128+256+512+1024+2048+4096+4096*2+4096*3+4096*4
|
||||||
|
//1024*(63)
|
||||||
|
|
||||||
|
//1000 0000 0110 1111 //-111
|
||||||
|
System.out.println(toInt(bytes[0]));
|
||||||
|
System.out.println(toUInt(bytes[0]));
|
||||||
|
System.out.println(toInt(bytes[1]));
|
||||||
|
System.out.println(toUInt(bytes[1]));
|
||||||
|
|
||||||
|
System.out.println("无符号 "+(bytes[1] & 0xff | (bytes[0] & 0xff) << Byte.SIZE));
|
||||||
|
System.out.println("有符号 "+(short)(bytes[1] & 0xff | (bytes[0] & 0xff) << Byte.SIZE));
|
||||||
|
|
||||||
|
// //byte类型的数字要&0xff再赋值给int类型,其本质原因就是想保持二进制补码的一致性。 0xff 其实就是0000 0000 0000 0000 0000 0000 1111 0100
|
||||||
|
short l = 0;
|
||||||
|
l<<=8; //<<=和我们的 +=是一样的,意思就是 l = l << 8
|
||||||
|
//注意: 移位并不会增加原来字节长度,被挤掉的数据就没了,而且是以补码的形式移动的。
|
||||||
|
l |= (bytes[0] & 0xff); //和上面也是一样的 l = l | (b[i]&0xff) // 255 补码 1111 1111
|
||||||
|
|
||||||
|
l<<=7;
|
||||||
|
l<<=1;
|
||||||
|
//l<<=8; //<<=和我们的 +=是一样的,意思就是 l = l << 8
|
||||||
|
l |= (bytes[1] & 0xff); //和上面也是一样的 l = l | (b[i]&0xff)
|
||||||
|
|
||||||
|
|
||||||
|
short c = 0;
|
||||||
|
c<<=8; //<<=和我们的 +=是一样的,意思就是 l = l << 8
|
||||||
|
//注意: 移位并不会增加原来字节长度,被挤掉的数据就没了,而且是以补码的形式移动的。
|
||||||
|
c |= ((byte)1 & 0xff); //和上面也是一样的 l = l | (b[i]&0xff) // 255 补码 1111 1111
|
||||||
|
|
||||||
|
c<<=7;
|
||||||
|
c<<=1;
|
||||||
|
//l<<=8; //<<=和我们的 +=是一样的,意思就是 l = l << 8
|
||||||
|
c |= ((byte)2 & 0xff); //和上面也是一样的 l = l | (b[i]&0xff)
|
||||||
|
|
||||||
|
|
||||||
|
byte bb = -1;
|
||||||
|
bb<<=8;
|
||||||
|
System.out.println(bb);
|
||||||
|
System.out.println(l);
|
||||||
|
System.out.println(Byte.valueOf((byte) 0x81)); //有符号 因为0x81 会自动被java 转成byte,而byte会以补码 有符号的形式存在
|
||||||
|
System.out.println(0x81); //无符号
|
||||||
|
|
||||||
|
|
||||||
|
byte[] lrealBuffer = new byte[8];
|
||||||
|
Number lrealNumber = new Double(-12.1);
|
||||||
|
byte[] bytesss = ByteUtil.numberToBytes(lrealNumber);
|
||||||
|
Number intNumber = new Integer(-12);
|
||||||
|
byte[] bytessss = ByteUtil.numberToBytes(intNumber);
|
||||||
|
|
||||||
|
Integer s = new Integer(-999);
|
||||||
|
byte b = s.byteValue();
|
||||||
|
System.out.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double bytes2Double(byte[] arr) {
|
||||||
|
long value = 0;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
value |= ((long) (arr[i] & 0xff)) << (8 * i);
|
||||||
|
}
|
||||||
|
return Double.longBitsToDouble(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] short2byte(short s){
|
||||||
|
byte[] b = new byte[2];
|
||||||
|
for(int i = 0; i < 2; i++){
|
||||||
|
int offset = 16 - (i+1)*8; //因为byte占4个字节,所以要计算偏移量
|
||||||
|
b[i] = (byte)((s >> offset)&0xff); //把16位分为2个8位进行分别存储
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 将byte[]转为各种进制的字符串
|
||||||
|
* @param bytes byte[]
|
||||||
|
* @param radix 基数可以转换进制的范围,从Character.MIN_RADIX到Character.MAX_RADIX,超出范围后变为10进制
|
||||||
|
* @return 转换后的字符串
|
||||||
|
*/
|
||||||
|
public static String binary(byte[] bytes, int radix){
|
||||||
|
return new BigInteger(1, bytes).toString(radix);// 这里的1代表正数
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String byteToBit(byte b) {
|
||||||
|
return ""
|
||||||
|
+ (byte) ((b >> 7) & 0x1) + (byte) ((b >> 6) & 0x1)
|
||||||
|
+ (byte) ((b >> 5) & 0x1) + (byte) ((b >> 4) & 0x1) +","
|
||||||
|
+ (byte) ((b >> 3) & 0x1) + (byte) ((b >> 2) & 0x1)
|
||||||
|
+ (byte) ((b >> 1) & 0x1) + (byte) ((b >> 0) & 0x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static short byte2short(byte[] b){
|
||||||
|
short l = 0;
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
l<<=8; //<<=和我们的 +=是一样的,意思就是 l = l << 8
|
||||||
|
l |= (b[i] & 0xff); //和上面也是一样的 l = l | (b[i]&0xff)
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] int2byte(int s){
|
||||||
|
byte[] b = new byte[2];
|
||||||
|
for(int i = 0; i < 4; i++){
|
||||||
|
int offset = 16 - (i+1)*8; //因为byte占4个字节,所以要计算偏移量
|
||||||
|
b[i] = (byte)((s >> offset)&0xff); //把32位分为4个8位进行分别存储
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static int byte2int(byte[] b){
|
||||||
|
int l = 0;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
l<<=8; //<<=和我们的 +=是一样的,意思就是 l = l << 8
|
||||||
|
l |= (b[i] & 0xff); //和上面也是一样的 l = l | (b[i]&0xff)
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* int到byte[](byte数组4个字节)
|
||||||
|
* @param i
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static byte[] intToByteArray(int i) {
|
||||||
|
byte[] result = new byte[4];
|
||||||
|
//由高位到低位
|
||||||
|
result[0] = (byte)((i >> 24) & 0xFF);
|
||||||
|
result[1] = (byte)((i >> 16) & 0xFF); //如果查过128 那么会被java自动转成负数
|
||||||
|
result[2] = (byte)((i >> 8) & 0xFF);
|
||||||
|
result[3] = (byte)(i & 0xFF);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 4个字节的byte[]转int
|
||||||
|
* @param
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Integer byteArrayToInt(byte[] in) {
|
||||||
|
byte[] bytes = new byte[4];
|
||||||
|
|
||||||
|
//如果传进来数组不满足4个字节,自动填充
|
||||||
|
if(in.length>4){
|
||||||
|
return null;
|
||||||
|
}else if(in.length!=4){
|
||||||
|
Stack<Byte> st = new Stack<Byte>();
|
||||||
|
int c = 4-in.length;
|
||||||
|
in = invert(in);
|
||||||
|
for(int i=0;i<in.length;i++){
|
||||||
|
st.push(in[i]);
|
||||||
|
}
|
||||||
|
for(int i=0;i<c;i++){
|
||||||
|
st.push(Byte.valueOf((byte) 0));
|
||||||
|
}
|
||||||
|
for(int i=0;i<4;i++){
|
||||||
|
bytes[i] = st.pop();
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
bytes = in;
|
||||||
|
}
|
||||||
|
|
||||||
|
int value=0;
|
||||||
|
//由高位到低位
|
||||||
|
for(int i = 0; i < 4; i++) {
|
||||||
|
int shift= (4-1-i) * 8;
|
||||||
|
value +=(bytes[i] & 0x000000FF) << shift;//往高位游
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Integer byteToUSInt(byte bytes) {
|
||||||
|
int value=0;
|
||||||
|
value +=(bytes & 0xFF);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
public static Integer byteToSInt(byte bytes) {
|
||||||
|
return Byte.valueOf(bytes).intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] invert(byte[] a){
|
||||||
|
byte[] b = new byte[a.length];
|
||||||
|
Stack<Byte> st = new Stack<Byte>();
|
||||||
|
for(int i=0;i<a.length;i++){
|
||||||
|
st.push(a[i]);
|
||||||
|
}
|
||||||
|
for(int i=0;i<a.length;i++){
|
||||||
|
b[i] = st.pop();
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
294
ym-s7/src/main/java/com/cnbm/s7/s7connector/MainForRead.java
Normal file
294
ym-s7/src/main/java/com/cnbm/s7/s7connector/MainForRead.java
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
package com.cnbm.s7.s7connector;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Desc: ""
|
||||||
|
* @Author: caixiang
|
||||||
|
* @DATE: 2021/12/10 10:17
|
||||||
|
*/
|
||||||
|
public class MainForRead {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将byte转换为一个长度为8的boolean数组(每bit代表一个boolean值)
|
||||||
|
*
|
||||||
|
* @param b byte, return(将数组翻转过来)
|
||||||
|
* @return boolean数组
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static boolean[] getBooleanArray(byte b,boolean returns) {
|
||||||
|
|
||||||
|
boolean[] array = new boolean[8];
|
||||||
|
|
||||||
|
for (int i = 7; i >= 0; i--) { //对于byte的每bit进行判定
|
||||||
|
|
||||||
|
array[i] = (b & 1) == 1; //判定byte的最后一位是否为1,若为1,则是true;否则是false
|
||||||
|
|
||||||
|
b = (byte) (b >> 1); //将byte右移一位
|
||||||
|
|
||||||
|
}
|
||||||
|
if(returns){
|
||||||
|
boolean[] array1 = new boolean[8];
|
||||||
|
array1[0] = array[7];
|
||||||
|
array1[1] = array[6];
|
||||||
|
array1[2] = array[5];
|
||||||
|
array1[3] = array[4];
|
||||||
|
array1[4] = array[3];
|
||||||
|
array1[5] = array[2];
|
||||||
|
array1[6] = array[1];
|
||||||
|
array1[7] = array[0];
|
||||||
|
array = array1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws UnsupportedEncodingException {
|
||||||
|
//1000 0101
|
||||||
|
//1010 0001
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// public static void main(String[] args) throws Exception {
|
||||||
|
// //前言:
|
||||||
|
// //DB3.1.1 中间那个1是byte区,后面那个1 是bit
|
||||||
|
// //缺陷: 不支持 DB3.1.1
|
||||||
|
//
|
||||||
|
// //Create connection
|
||||||
|
//// S7Connector connector =
|
||||||
|
//// S7ConnectorFactory
|
||||||
|
//// .buildTCPConnector()
|
||||||
|
//// .withHost("192.168.0.51")
|
||||||
|
//// .withRack(0) //optional rack 是机架号
|
||||||
|
//// .withSlot(0) //optional slot 是插槽号
|
||||||
|
//// .build();
|
||||||
|
//
|
||||||
|
// S7Connector connector = S7Client.S7_1500.getConnector();
|
||||||
|
//
|
||||||
|
// // // [0]
|
||||||
|
//// byte[] bool = connector.read(DaveArea.DB, 3, 1, 3266,0);
|
||||||
|
//// byte[] bool2 = connector.read(DaveArea.DB, 3, 1, 3266,1);
|
||||||
|
//// System.out.println("DB3.0-bool : " + ByteUtils.toBoolean(bool));
|
||||||
|
//// System.out.println("DB3.0-bool2 : " + ByteUtils.toBoolean(bool2));
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// //bool3 => [1] 0000 0001 ==> 1000 0000 10.......
|
||||||
|
// //bool3 => [3] 0000 0011 ==> 1100 0000 11.......
|
||||||
|
// //bool3 => [10] 0000 1010 ==> 0101 0000 0101.....
|
||||||
|
// //bool3 => [25] 0001 1001 ==> 1001 1000 10011....
|
||||||
|
// byte[] bool3 = connector.read(DaveArea.DB, 3, 1, 3267);
|
||||||
|
// System.out.println("DB3.0-bool3 : " + ByteUtils.toBoolean(bool3));
|
||||||
|
//
|
||||||
|
// byte[] boolArrays = connector.read(DaveArea.DB, 3, 11, 3262);
|
||||||
|
// List<Boolean> booleans = ByteUtils.toBoolArray(boolArrays);
|
||||||
|
// System.out.println("DB3.830-boolArrays : " +booleans );
|
||||||
|
//
|
||||||
|
// byte[] boolArrays14 = connector.read(DaveArea.DB, 3, 16, 3264);
|
||||||
|
// List<Boolean> booleans14 = ByteUtils.toBoolArray(boolArrays14);
|
||||||
|
// System.out.println("DB3.3268-boolArrays : " +booleans14 );
|
||||||
|
//
|
||||||
|
// //
|
||||||
|
//// byte[] bool4 = connector.read(DaveArea.DB, 3, 1, 0);
|
||||||
|
//// System.out.println("DB3.0-bool3 : " + ByteUtils.toBoolean(bool3));
|
||||||
|
//
|
||||||
|
////
|
||||||
|
////
|
||||||
|
//// //非常规
|
||||||
|
//// {
|
||||||
|
//// //注意1:
|
||||||
|
//// //lreal 要小端(拿到字节流要翻转一下)
|
||||||
|
//// //参数一:读取方式,一般默认是DB区域块
|
||||||
|
//// //参数二:区域块编号
|
||||||
|
//// //参数三:区域数据类型大小,int 2字节,real 4字节
|
||||||
|
//// //参数四:区域偏移量
|
||||||
|
//// //[-64, 40, 51, 51, 51, 51, 51, 51] -64==0xc0(要翻转一下才能用)
|
||||||
|
//// //1100 0000 0010 1000 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011
|
||||||
|
////
|
||||||
|
//// byte[] lreal = connector.read(DaveArea.DB, 3, 8, 26,0);
|
||||||
|
//// System.out.println("DB3.26-lreal : "+ ByteUtils.forLReal(lreal));
|
||||||
|
////
|
||||||
|
//// byte[] real = connector.read(DaveArea.DB, 3, 4, 22,0);
|
||||||
|
//// System.out.println("DB3.22-real : "+ ByteUtils.forReal(real));
|
||||||
|
////
|
||||||
|
//// }
|
||||||
|
//
|
||||||
|
//// {
|
||||||
|
//// //data 是有符号的双字节
|
||||||
|
//// //注意2:
|
||||||
|
//// //[2, -38] 就就代表1990-1-1 因为这就是其实位置。 后续位置要1990+n的 D#1992-01-01
|
||||||
|
//// //[4, 72] 1993-1-1
|
||||||
|
//// //0000 0100 0100 1000 72+1024=1096 1990-1-1 + 1096(天) = 1993-1-1
|
||||||
|
//// byte[] date = connector.read(DaveArea.DB, 3, 2, 42);
|
||||||
|
////// System.out.println("DB3.42-DATE : "+addDate("1990-01-01",byte2short(date)));
|
||||||
|
//// Long aLong = Long.valueOf(ByteUtils.toInt(date[0], date[1]).toString());
|
||||||
|
//// System.out.println("DB3.42-DATE : "+ByteUtils.addDate("1990-01-01",aLong));
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// {
|
||||||
|
//// //[7, -78, 1, 1, 5, 0, 0, 0, 0, 0, 0, 0] DTL#1970-01-01-00:00:00 1998-1-1 星期五 0.0.0.0
|
||||||
|
//// //0000 0111 (1100 1110)=>(1011 0010 178) 178+256+512+1024=1970
|
||||||
|
//// //(注意:第二个字节是负数要转成补码形式表示(因为在通行传输中 字节是原码形式传输的,但是java中long int byte... 都是以补码形式保存的 java帮你自动保存了其实这是不对的所以你要转换一下) 参考https://blog.csdn.net/csdn_ds/article/details/79106006)
|
||||||
|
//// //[7, -68, 1, 21, 2, 0, 0, 0, 0, 0, 0, 0]
|
||||||
|
//// //0000 0111 (1100 0100)=>(1011 1100 188) 188+256+512+1024=1980
|
||||||
|
//// byte[] dtl = connector.read(DaveArea.DB, 3, 12, 44);
|
||||||
|
//// byte[] year = new byte[2];
|
||||||
|
//// year[0] = dtl[0];
|
||||||
|
//// year[1] = dtl[1];
|
||||||
|
//// byte[] month = new byte[1];
|
||||||
|
//// month[0] = dtl[2];
|
||||||
|
////// System.out.println("DB3.12-DTL : " + byteArrayByteUtils.toUInt(year)+"-"+byteArrayByteUtils.toUInt(month));
|
||||||
|
//// System.out.println("DB3.44-DTL : " + ByteUtils.toInt(year[0],year[1])+"-"+ByteUtils.toInt(month[0]));
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// {
|
||||||
|
//// //[59, -102, -55, -1] T#11D_13H_46M_39S_999MS
|
||||||
|
//// //0011 1011
|
||||||
|
//// byte[] time = connector.read(DaveArea.DB, 3, 4, 34);
|
||||||
|
//// System.out.println("DB3.34-time : " + ByteUtils.toInt(time[0],time[1],time[2],time[3]) +" ms");
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// //常规
|
||||||
|
//// {
|
||||||
|
//// // [0]
|
||||||
|
//// byte[] bool = connector.read(DaveArea.DB, 3, 1, 0);
|
||||||
|
//// System.out.println("DB3.0-bool : " + ByteUtils.toBoolean(bool));
|
||||||
|
////
|
||||||
|
//// //todo 就像这种情况的话,这个工具就无法读取了。。。。 这个后续可以改他的源码 就是addrees(Byte/Bit)那里 后续再说好了。
|
||||||
|
//// byte[] bool2 = connector.read(DaveArea.DB, 3, 1, 3266);
|
||||||
|
//// System.out.println("DB3.3266-bool : " + ByteUtils.toBoolean(bool2));
|
||||||
|
////
|
||||||
|
////
|
||||||
|
//// //byte 目前读取以 有符号的十进制
|
||||||
|
//// //[8]
|
||||||
|
//// //[-63]
|
||||||
|
//// //1011 1111
|
||||||
|
//// byte[] byteOne = connector.read(DaveArea.DB, 3, 1, 1);
|
||||||
|
//// System.out.println("DB3.1-byteOne-有符号 : " + ByteUtils.toInt(byteOne[0])); //有符号 整形
|
||||||
|
////
|
||||||
|
//// System.out.println("DB3.1-byteOne-无符号 : " + ByteUtils.toUInt(byteOne[0])); //无符号 整形
|
||||||
|
////
|
||||||
|
////
|
||||||
|
//// // [0, 5] word 可 2/8/16进制 可无符号 可有符号,就看你真没用
|
||||||
|
//// byte[] word = connector.read(DaveArea.DB, 3, 2, 2);
|
||||||
|
//// System.out.println("DB3.2-word : " + ByteUtils.toInt(word[0],word[1]));
|
||||||
|
////
|
||||||
|
//// // [-1, -1, -1, -4] 把java自动转换成byte类型 的补码形式 ,如果电控变量是这个要问下他是无符号还是有符号的。
|
||||||
|
//// // [FF, FF, FF, FC] 原码
|
||||||
|
//// byte[] dword = connector.read(DaveArea.DB, 3, 4, 4);
|
||||||
|
//// System.out.println("DB3.4-dword : " + ByteUtils.toInt(dword[0],dword[1],dword[2],dword[3])); //带符号的 整形
|
||||||
|
////
|
||||||
|
//// //[11]
|
||||||
|
//// byte[] usint = connector.read(DaveArea.DB, 3, 1, 8);
|
||||||
|
//// System.out.println("DB3.8-usint : " + ByteUtils.toUInt(usint[0]));
|
||||||
|
////
|
||||||
|
//// byte[] sint = connector.read(DaveArea.DB, 3, 1, 9);
|
||||||
|
//// System.out.println("DB3.9-sint : " + ByteUtils.toInt(sint[0]));
|
||||||
|
////
|
||||||
|
//// byte[] uint = connector.read(DaveArea.DB, 3, 2, 10);
|
||||||
|
//// System.out.println("DB3.10-uint : " + ByteUtils.toUInt(uint[0],uint[1]));
|
||||||
|
////
|
||||||
|
//// //[-1, -111] -111
|
||||||
|
//// //[-1, -64] -64
|
||||||
|
//// //[-4, 25] -999
|
||||||
|
//// byte[] ints = connector.read(DaveArea.DB, 3, 2, 12);
|
||||||
|
//// System.out.println("DB3.12-ints : " + ByteUtils.toInt(ints[0],ints[1]));
|
||||||
|
////
|
||||||
|
//// byte[] dint = connector.read(DaveArea.DB, 3, 4, 14);
|
||||||
|
//// System.out.println("DB3.14-dint : " + ByteUtils.toInt(dint[0],dint[1],dint[2],dint[3]));
|
||||||
|
////
|
||||||
|
//// byte[] udint = connector.read(DaveArea.DB, 3, 4, 18);
|
||||||
|
//// System.out.println("DB3.18-udint : " + ByteUtils.toUInt(udint[0],udint[1],udint[2],udint[3]));
|
||||||
|
////
|
||||||
|
//// //plc 中char 是1个字节 注意char 和 wchar 都是ascii码格式的。
|
||||||
|
//// byte[] chars = connector.read(DaveArea.DB, 3, 1, 58);
|
||||||
|
//// Character charss = ByteUtils.toChar(chars);
|
||||||
|
//// System.out.println("DB3.58-char : " + charss);
|
||||||
|
//// //plc 中wchar 是2个字节
|
||||||
|
//// byte[] wchar = connector.read(DaveArea.DB, 3, 2, 60);
|
||||||
|
//// Character wchars =ByteUtils.toChar(wchar);
|
||||||
|
//// System.out.println("DB3.60-wchar : " + wchars);
|
||||||
|
////
|
||||||
|
//// //n+2 个字节 (这里的n 就是实际content的字节数 如 "123"=> n=3 ;; "@123" ==> n=4)
|
||||||
|
//// //[-2, 4, 64, 65, 83, 68] @ASD 前面-2 4两个字节就是上面的2字节 是无用的
|
||||||
|
//// //-2 代表 字符串中存储最大的总字节数 ; 4代表字符数 后面跟着的 是内容(最多256个字节)
|
||||||
|
//// byte[] str = connector.read(DaveArea.DB, 3, 6, 62);
|
||||||
|
//// String string = ByteUtils.toStr(str);
|
||||||
|
//// System.out.println("DB3.62-str : " +string );
|
||||||
|
////
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// {
|
||||||
|
//// try {
|
||||||
|
//// //byte 占用一个字节,如果是数组的话,就读取2个(要事先知道,点表规定数组长度),实际就是读取 DB3.830
|
||||||
|
//// //bytes = byteLength * arrayLength 举例:1(byteLength) * 2(arrayLength) =2(bytes)
|
||||||
|
//// byte[] boolArrays = connector.read(DaveArea.DB, 3, 2, 830);
|
||||||
|
//// List<Boolean> booleans = ByteUtils.toBoolArray(boolArrays);
|
||||||
|
//// System.out.println("DB3.830-boolArrays : " +booleans );
|
||||||
|
////
|
||||||
|
//// byte[] byteArrays = connector.read(DaveArea.DB, 3, 2, 832);
|
||||||
|
//// List<Byte> bytes = ByteUtils.toByteArray(byteArrays);
|
||||||
|
//// System.out.println("DB3.832-byteArrays : " +bytes );
|
||||||
|
////
|
||||||
|
//// byte[] charArrays = connector.read(DaveArea.DB, 3, 2, 834);
|
||||||
|
//// List<Character> chars = ByteUtils.toCharArray(charArrays);
|
||||||
|
//// System.out.println("DB3.834-charArrays : " +chars );
|
||||||
|
////
|
||||||
|
//// byte[] wordArrays = connector.read(DaveArea.DB, 3, 4, 836);
|
||||||
|
//// List<Integer> words = ByteUtils.toWordArray(wordArrays);
|
||||||
|
//// System.out.println("DB3.836-wordArrays : " +words );
|
||||||
|
////
|
||||||
|
//// byte[] dwordArrays = connector.read(DaveArea.DB, 3, 8, 840);
|
||||||
|
//// List<Integer> dwords = ByteUtils.toDWordArray(dwordArrays);
|
||||||
|
//// System.out.println("DB3.840-dwordArrays : " +dwords );
|
||||||
|
////
|
||||||
|
//// byte[] sintArrays = connector.read(DaveArea.DB, 3, 2, 852);
|
||||||
|
//// List<Integer> sints = ByteUtils.toSIntArray(sintArrays);
|
||||||
|
//// System.out.println("DB3.852-sintArrays : " +sints );
|
||||||
|
////
|
||||||
|
//// byte[] intArrays = connector.read(DaveArea.DB, 3, 4, 848);
|
||||||
|
//// List<Integer> ints = ByteUtils.toIntArray(intArrays);
|
||||||
|
//// System.out.println("DB3.848-intArrays : " +ints );
|
||||||
|
////
|
||||||
|
//// byte[] dintArrays = connector.read(DaveArea.DB, 3, 8, 854);
|
||||||
|
//// List<Integer> dints = ByteUtils.toDIntArray(dintArrays);
|
||||||
|
//// System.out.println("DB3.852-dintArrays : " +dints);
|
||||||
|
////
|
||||||
|
////
|
||||||
|
//// byte[] usintArrays = connector.read(DaveArea.DB, 3, 3, 3240);
|
||||||
|
//// List<Integer> usints = ByteUtils.toUSIntArray(usintArrays);
|
||||||
|
//// System.out.println("DB3.3240-usintArrays : " +usints );
|
||||||
|
////
|
||||||
|
//// byte[] uintArrays = connector.read(DaveArea.DB, 3, 6, 3256);
|
||||||
|
//// List<Integer> uints = ByteUtils.toUIntArray(uintArrays);
|
||||||
|
//// System.out.println("DB3.3256-uintArrays : " +uints );
|
||||||
|
////
|
||||||
|
//// byte[] udintArrays = connector.read(DaveArea.DB, 3, 12, 3244);
|
||||||
|
//// List<Long> udints = ByteUtils.toUDIntArray(udintArrays);
|
||||||
|
//// System.out.println("DB3.852-udintArrays : " +udints);
|
||||||
|
//// }catch (Exception e){
|
||||||
|
//// e.printStackTrace();
|
||||||
|
//// }
|
||||||
|
////
|
||||||
|
//// };
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// //Write to DB100 10 bytes
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// //connector.write(DaveArea.DB, 3, 830, byteArrays);
|
||||||
|
//
|
||||||
|
// //Close connection
|
||||||
|
//
|
||||||
|
// //connector.close();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package com.cnbm.s7.s7connector;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.DaveArea;
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Connector;
|
||||||
|
import com.cnbm.s7.s7connector.api.utils.ByteUtils;
|
||||||
|
import com.cnbm.s7.s7connector.enmuc.S7Client;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Desc: ""
|
||||||
|
* @Author: caixiang
|
||||||
|
* @DATE: 2021/12/10 10:17
|
||||||
|
*/
|
||||||
|
public class MainForReadDemo {
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
|
||||||
|
// //1200 部分
|
||||||
|
// S7Connector connector1200 = S7Client.S7_1200.getConnector();
|
||||||
|
//
|
||||||
|
// byte[] bool3_1200 = connector1200.read(DaveArea.DB, 1, 1, 0);
|
||||||
|
// System.out.println("DB1-bool3_1200 : " + ByteUtils.toBoolean(bool3_1200));
|
||||||
|
//// byte[] bool4_1200 = connector1200.read(DaveArea.DB, 3, 1, 3267,5,PlcVar.BOOL.getTransportSize());
|
||||||
|
//// System.out.println("DB1-bool4_1200 : " + ByteUtils.toBoolean(bool4_1200));
|
||||||
|
|
||||||
|
//1500 部分
|
||||||
|
S7Connector connector1500 = S7Client.S7_1500.getConnector();
|
||||||
|
// byte[] bool11 = connector1500.read(DaveArea.DB, 3, 1, 3267);
|
||||||
|
// //30110012105301115
|
||||||
|
// //[18, 17, 51, 48, 49, 49, 48, 48, 49, 50, 49, 48, 53, 51, 48, 49, 49, 49, 53, 0]
|
||||||
|
// // 3 0
|
||||||
|
// byte[] str1500 = connector1500.read(DaveArea.DB, 3, 20, 3270);
|
||||||
|
// byte[] str15001 = connector1500.read(DaveArea.DB, 3, 20, 3290);
|
||||||
|
// byte[] bool1 = connector1500.read(DaveArea.DB, 3, 1, 3267,4, PlcVar.BOOL.getTransportSize());
|
||||||
|
// String str1500s = ByteUtils.toStr(str1500);
|
||||||
|
// System.out.println("DB3.0-str1500 : " + str1500s);
|
||||||
|
// System.out.println("DB3.0-bool1 : " + ByteUtils.toBoolean(bool1));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//String
|
||||||
|
//write
|
||||||
|
String one = "12111";
|
||||||
|
byte[] bytes1 = ByteUtils.strToBytes(one, 18);
|
||||||
|
connector1500.write(DaveArea.DB,3,3270,bytes1);
|
||||||
|
|
||||||
|
//read
|
||||||
|
byte[] str_1500 = connector1500.read(DaveArea.DB, 3, 20, 3270);
|
||||||
|
String string = ByteUtils.toStr(str_1500);
|
||||||
|
System.out.println(string);
|
||||||
|
|
||||||
|
|
||||||
|
//StringArray
|
||||||
|
//write
|
||||||
|
String[] src = new String[3];
|
||||||
|
src[0]= "1";
|
||||||
|
src[1]= "30110012105301117222";
|
||||||
|
src[2]= "3";
|
||||||
|
byte[] bytes = ByteUtils.strArrayToBytes(src, 18);
|
||||||
|
connector1500.write(DaveArea.DB,3,3270,bytes);
|
||||||
|
|
||||||
|
//read
|
||||||
|
byte[] strList_1500 = connector1500.read(DaveArea.DB, 3, 60, 3270);
|
||||||
|
String[] strings = ByteUtils.toStrArray(strList_1500, 3, 18);
|
||||||
|
System.out.println(strings);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
391
ym-s7/src/main/java/com/cnbm/s7/s7connector/MainForWrite.java
Normal file
391
ym-s7/src/main/java/com/cnbm/s7/s7connector/MainForWrite.java
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
package com.cnbm.s7.s7connector;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.DaveArea;
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Connector;
|
||||||
|
import com.cnbm.s7.s7connector.api.factory.S7ConnectorFactory;
|
||||||
|
import com.cnbm.s7.s7connector.api.utils.ByteUtils;
|
||||||
|
import com.cnbm.s7.s7connector.type.PlcVar;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Desc: ""
|
||||||
|
* @Author: caixiang
|
||||||
|
* @DATE: 2021/12/10 10:17
|
||||||
|
*/
|
||||||
|
public class MainForWrite {
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
//Create connection
|
||||||
|
S7Connector connector =
|
||||||
|
S7ConnectorFactory
|
||||||
|
.buildTCPConnector()
|
||||||
|
.withHost("192.168.0.51")
|
||||||
|
.withRack(0) //optional rack 是机架号
|
||||||
|
.withSlot(0) //optional slot 是插槽号
|
||||||
|
.build();
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
connector.write(DaveArea.DB, 3, 3266,1,ByteUtils.boolToBytes(true), PlcVar.BOOL);
|
||||||
|
// byte[] bool = connector.read(DaveArea.DB, 3, 1, 3266,1);
|
||||||
|
// Boolean b = (Boolean)PlcVar.BOOL.toObject(bool);
|
||||||
|
// System.out.println("DB3.3266.1-boolean : " + b);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//非常规
|
||||||
|
{
|
||||||
|
//注意1:
|
||||||
|
//lreal 要小端(拿到字节流要翻转一下)
|
||||||
|
//参数一:读取方式,一般默认是DB区域块
|
||||||
|
//参数二:区域块编号
|
||||||
|
//参数三:区域数据类型大小,int 2字节,real 4字节
|
||||||
|
//参数四:区域偏移量
|
||||||
|
//[-64, 40, 51, 51, 51, 51, 51, 51] -64==0xc0(要翻转一下才能用)
|
||||||
|
//1100 0000 0010 1000 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// byte[] lreal_content = ByteUtils.lrealToBytes(Double.parseDouble("-111.1"));
|
||||||
|
byte[] lreal_content = PlcVar.LREAL.toBytes(-121.1);
|
||||||
|
connector.write(DaveArea.DB, 3, 26,lreal_content);
|
||||||
|
byte[] lreal = connector.read(DaveArea.DB, 3, 8, 26);
|
||||||
|
// Double aDouble = ByteUtils.lrealbytesToDouble(lreal);
|
||||||
|
Double ad = (Double)PlcVar.LREAL.toObject(lreal);
|
||||||
|
System.out.println("DB3.26-lreal : "+ ad);
|
||||||
|
|
||||||
|
//byte[] real_content = ByteUtils.realToBytes(Float.valueOf("-11.2"));
|
||||||
|
byte[] real_content = PlcVar.REAL.toBytes(-12.1);
|
||||||
|
connector.write(DaveArea.DB, 3, 22,real_content);
|
||||||
|
byte[] real = connector.read(DaveArea.DB, 3, 4, 22);
|
||||||
|
//ByteUtils.realbytesToFloat(real)
|
||||||
|
Float o = (Float)PlcVar.REAL.toObject(real);
|
||||||
|
System.out.println("DB3.22-real : "+ o);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
//data 是有符号的双字节
|
||||||
|
//注意2:
|
||||||
|
//[2, -38] 就就代表1990-1-1 因为这就是其实位置。 后续位置要1990+n的 D#1992-01-01
|
||||||
|
//[4, 72] 1993-1-1
|
||||||
|
//0000 0100 0100 1000 72+1024=1096 1990-1-1 + 1096(天) = 1993-1-1
|
||||||
|
byte[] date = connector.read(DaveArea.DB, 3, 2, 42);
|
||||||
|
// System.out.println("DB3.42-DATE : "+addDate("1990-01-01",byte2short(date)));
|
||||||
|
// Long aLong = Long.valueOf(ByteUtils.toInt(date[0], date[1]).toString());
|
||||||
|
// String s = ByteUtils.addDate("1990-01-01", aLong);
|
||||||
|
String s = (String) PlcVar.DATE.toObject(date);
|
||||||
|
System.out.println("DB3.42-DATE : "+s);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
//[7, -78, 1, 1, 5, 0, 0, 0, 0, 0, 0, 0] DTL#1970-01-01-00:00:00 1998-1-1 星期五 0.0.0.0
|
||||||
|
//0000 0111 (1100 1110)=>(1011 0010 178) 178+256+512+1024=1970
|
||||||
|
//(注意:第二个字节是负数要转成补码形式表示(因为在通行传输中 字节是原码形式传输的,但是java中long int byte... 都是以补码形式保存的 java帮你自动保存了其实这是不对的所以你要转换一下) 参考https://blog.csdn.net/csdn_ds/article/details/79106006)
|
||||||
|
//[7, -68, 1, 21, 2, 0, 0, 0, 0, 0, 0, 0]
|
||||||
|
//0000 0111 (1100 0100)=>(1011 1100 188) 188+256+512+1024=1980
|
||||||
|
byte[] dtl = connector.read(DaveArea.DB, 3, 12, 44);
|
||||||
|
// byte[] year = new byte[2];
|
||||||
|
// year[0] = dtl[0];
|
||||||
|
// year[1] = dtl[1];
|
||||||
|
// Integer yearInt = ByteUtils.toInt(year[0], year[1]);
|
||||||
|
// Integer monthInt = ByteUtils.toInt(dtl[2]);
|
||||||
|
// Integer dayInt = ByteUtils.toInt(dtl[3]);
|
||||||
|
// Integer worddayInt = ByteUtils.toInt(dtl[4]);
|
||||||
|
// Integer hourInt = ByteUtils.toInt(dtl[5]);
|
||||||
|
// Integer minuInt = ByteUtils.toInt(dtl[6]);
|
||||||
|
// Integer secondInt = ByteUtils.toInt(dtl[7]);
|
||||||
|
|
||||||
|
|
||||||
|
// System.out.println("DB3.12-DTL : " + byteArrayByteUtils.toUInt(year)+"-"+byteArrayByteUtils.toUInt(month));
|
||||||
|
String o = (String)PlcVar.DTL.toObject(dtl);
|
||||||
|
System.out.println("DB3.44-DTL : " + o );
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
//[59, -102, -55, -1] T#11D_13H_46M_39S_999MS
|
||||||
|
//0011 1011
|
||||||
|
byte[] time = connector.read(DaveArea.DB, 3, 4, 34);
|
||||||
|
// Integer integer = ByteUtils.toInt(time[0], time[1], time[2], time[3]);
|
||||||
|
Integer i = (Integer) PlcVar.TIME.toObject(time);
|
||||||
|
System.out.println("DB3.34-time : " + i +" ms");
|
||||||
|
}
|
||||||
|
|
||||||
|
//常规
|
||||||
|
|
||||||
|
//int 相关(sint、int、dint 。。 usint、uint、udint)
|
||||||
|
{
|
||||||
|
//[11] //[9] ==>2304
|
||||||
|
// byte[] usint_content = ByteUtils.usintToBytes(9);
|
||||||
|
|
||||||
|
byte[] usint_content = PlcVar.USINT.toBytes(9);
|
||||||
|
connector.write(DaveArea.DB, 3, 8,usint_content);
|
||||||
|
byte[] usint = connector.read(DaveArea.DB, 3, 1, 8);
|
||||||
|
// Integer integer = ByteUtils.toUInt(usint[0]);
|
||||||
|
Integer integer = (Integer) PlcVar.USINT.toObject(usint);
|
||||||
|
System.out.println("DB3.8-usint : " + integer);
|
||||||
|
|
||||||
|
// byte[] bytes = ByteUtils.sintToBytes(-9);
|
||||||
|
byte[] bytes = PlcVar.SINT.toBytes(-9);
|
||||||
|
connector.write(DaveArea.DB, 3, 9,bytes);
|
||||||
|
byte[] sint = connector.read(DaveArea.DB, 3, 1, 9);
|
||||||
|
// Integer integer1 = ByteUtils.toInt(sint[0]);
|
||||||
|
Integer integer1 = (Integer) PlcVar.SINT.toObject(usint);
|
||||||
|
System.out.println("DB3.9-sint : " + integer1);
|
||||||
|
|
||||||
|
// byte[] unit_content = ByteUtils.uintToBytes(9);
|
||||||
|
byte[] unit_content = PlcVar.UINT.toBytes(9);
|
||||||
|
connector.write(DaveArea.DB, 3, 10,unit_content);
|
||||||
|
byte[] uint = connector.read(DaveArea.DB, 3, 2, 10);
|
||||||
|
System.out.println("DB3.10-uint : " + ByteUtils.toUInt(uint[0],uint[1]));
|
||||||
|
|
||||||
|
//[-1, -111] -111
|
||||||
|
//[-1, -64] -64
|
||||||
|
//[-4, 25] -999
|
||||||
|
//byte[] bytes1 = ByteUtils.intToBytes(-99);
|
||||||
|
byte[] bytes1 = PlcVar.INT.toBytes(-99);
|
||||||
|
connector.write(DaveArea.DB, 3, 12,bytes1);
|
||||||
|
byte[] ints = connector.read(DaveArea.DB, 3, 2, 12);
|
||||||
|
System.out.println("DB3.12-ints : " + ByteUtils.toInt(ints[0],ints[1]));
|
||||||
|
|
||||||
|
|
||||||
|
// byte[] bytes2 = ByteUtils.dintToBytes(-999);
|
||||||
|
byte[] bytes2 = PlcVar.DINT.toBytes(-999);
|
||||||
|
connector.write(DaveArea.DB, 3, 14,bytes2);
|
||||||
|
byte[] dint = connector.read(DaveArea.DB, 3, 4, 14);
|
||||||
|
System.out.println("DB3.14-dint : " + ByteUtils.toInt(dint[0],dint[1],dint[2],dint[3]));
|
||||||
|
|
||||||
|
// byte[] bytes3 = ByteUtils.udintToBytes(99);
|
||||||
|
|
||||||
|
byte[] bytes3 = PlcVar.UDINT.toBytes(99);
|
||||||
|
connector.write(DaveArea.DB, 3, 18,bytes3);
|
||||||
|
byte[] udint = connector.read(DaveArea.DB, 3, 4, 18);
|
||||||
|
System.out.println("DB3.18-udint : " + ByteUtils.toUInt(udint[0],udint[1],udint[2],udint[3]));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// [0]
|
||||||
|
// byte[] bytes = ByteUtils.boolToBytes(false);
|
||||||
|
byte[] bytes = PlcVar.BOOL.toBytes(false);
|
||||||
|
connector.write(DaveArea.DB, 3, 0,bytes);
|
||||||
|
byte[] bool = connector.read(DaveArea.DB, 3, 1, 0);
|
||||||
|
System.out.println("DB3.0-boolean : " + ByteUtils.toBoolean(bool));
|
||||||
|
|
||||||
|
//byte 目前读取以 有符号的十进制
|
||||||
|
//[8]
|
||||||
|
//[-63]
|
||||||
|
//1011 1111
|
||||||
|
// byte[] setbytes = ByteUtils.setbytes(Byte.valueOf((byte) 0xFF));
|
||||||
|
byte[] setbytes = PlcVar.BYTE.toBytes((byte)0xFF);
|
||||||
|
connector.write(DaveArea.DB, 3, 1,setbytes);
|
||||||
|
byte[] byteOne = connector.read(DaveArea.DB, 3, 1, 1);
|
||||||
|
System.out.println("DB3.1-byteOne-有符号 : " + ByteUtils.toInt(byteOne[0])); //有符号 整形
|
||||||
|
System.out.println("DB3.1-byteOne-无符号 : " + ByteUtils.toUInt(byteOne[0])); //无符号 整形
|
||||||
|
|
||||||
|
|
||||||
|
// [0, 5] word 可 2/8/16进制 可无符号 可有符号,就看你真没用
|
||||||
|
// byte[] bytes1 = ByteUtils.wordToBytes(Short.valueOf("-55"));
|
||||||
|
byte[] bytes1 = PlcVar.WORD.toBytes(-55);
|
||||||
|
connector.write(DaveArea.DB, 3, 2,bytes1);
|
||||||
|
byte[] word = connector.read(DaveArea.DB, 3, 2, 2);
|
||||||
|
System.out.println("DB3.2-word : " + ByteUtils.toInt(word[0],word[1]));
|
||||||
|
|
||||||
|
// [-1, -1, -1, -4] 把java自动转换成byte类型 的补码形式 ,如果电控变量是这个要问下他是无符号还是有符号的。
|
||||||
|
// [FF, FF, FF, FC] 原码
|
||||||
|
byte[] bytes2 = PlcVar.DWORD.toBytes(-99);
|
||||||
|
connector.write(DaveArea.DB, 3, 4,bytes2);
|
||||||
|
byte[] dword = connector.read(DaveArea.DB, 3, 4, 4);
|
||||||
|
System.out.println("DB3.4-dword : " + ByteUtils.toInt(dword[0],dword[1],dword[2],dword[3])); //带符号的 整形
|
||||||
|
|
||||||
|
|
||||||
|
//plc 中char 是1个字节 注意char 和 wchar 都是ascii码格式的。
|
||||||
|
// byte[] bytes3 = ByteUtils.charToBytes('b');
|
||||||
|
byte[] bytes3 = PlcVar.CHAR.toBytes('b');
|
||||||
|
connector.write(DaveArea.DB, 3, 58,bytes3);
|
||||||
|
byte[] chars = connector.read(DaveArea.DB, 3, 1, 58);
|
||||||
|
System.out.println("DB3.58-char : " + ByteUtils.toChar(chars));
|
||||||
|
|
||||||
|
//plc 中wchar 是2个字节 '菜' =》[-125, -36]
|
||||||
|
// byte[] bytes4 = ByteUtils.wcharToBytes('菜');
|
||||||
|
byte[] bytes4 = PlcVar.WCHAR.toBytes('翔');
|
||||||
|
connector.write(DaveArea.DB, 3, 60,bytes4);
|
||||||
|
byte[] wchar = connector.read(DaveArea.DB, 3, 2, 60);
|
||||||
|
System.out.println("DB3.60-wchar : " + ByteUtils.toChar(wchar));
|
||||||
|
|
||||||
|
//n+2 个字节 (这里的n 就是实际content的字节数 如 "123"=> n=3 ;; "@123" ==> n=4)
|
||||||
|
//[-2, 4, 64, 65, 83, 68] @ASD 前面-2 4两个字节就是上面的2字节 是无用的
|
||||||
|
//-2 代表 字符串中存储最大的总字节数 ; 4代表字符数 后面跟着的 是内容(最多256个字节)
|
||||||
|
|
||||||
|
//[-2, 4, 64, 65, 83, 68] @ASD
|
||||||
|
//[-2, 4, 64, 64, 64, 64] @ASD
|
||||||
|
//读取字符串 要事先知道长度,否则可能读取的字符串长度不完整
|
||||||
|
String s = "你好啊呢";
|
||||||
|
// byte[] str_content = ByteUtils.strToBytes(s);
|
||||||
|
// byte[] str_content = PlcVar.STRING.toBytes(s);
|
||||||
|
// connector.write(DaveArea.DB, 3, 62 , str_content);
|
||||||
|
//byte[] str = connector.read(DaveArea.DB, 3, str_content.length, 62);
|
||||||
|
//[-2, 6, -60, -29, -70, -61]
|
||||||
|
//[-2, 8, -53, -58, -75, -60]
|
||||||
|
byte[] str = connector.read(DaveArea.DB, 3, 10, 62);
|
||||||
|
String string = ByteUtils.toStr(str);
|
||||||
|
System.out.println("DB3.62-str : " +string );
|
||||||
|
//下面这种方式读取字符串,,是指定长度的,
|
||||||
|
//byte[] str2 = connector.read(DaveArea.DB, 3, 7, 62);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
//byte 占用一个字节,如果是数组的话,就读取2个(要事先知道,点表规定数组长度),实际就是读取 DB3.830
|
||||||
|
//bytes = byteLength * arrayLength 举例:1(byteLength) * 2(arrayLength) =2(bytes)
|
||||||
|
boolean[] booleanArray = new boolean[2];
|
||||||
|
booleanArray[0] = true;
|
||||||
|
booleanArray[1] = true;
|
||||||
|
// byte[] bytes1 = ByteUtils.booleanArrayToBytes(booleanArray);
|
||||||
|
byte[] bytes1 = PlcVar.BOOL_Array.toBytes(booleanArray);
|
||||||
|
connector.write(DaveArea.DB, 3, 830 , bytes1);
|
||||||
|
byte[] boolArrays = connector.read(DaveArea.DB, 3, 2, 830);
|
||||||
|
// List<Boolean> booleans = ByteUtils.toBoolArray(boolArrays);
|
||||||
|
List<Boolean> booleans = (List<Boolean>) PlcVar.BOOL_Array.toObject(boolArrays);
|
||||||
|
System.out.println("DB3.830-boolArrays : " +booleans );
|
||||||
|
|
||||||
|
|
||||||
|
//注意 write的长度,要和plc中定义的长度要一致
|
||||||
|
byte[] write_byteArrays = new byte[2];
|
||||||
|
write_byteArrays[0] = 1;
|
||||||
|
write_byteArrays[1] = 2;
|
||||||
|
byte[] bytes2 = PlcVar.BYTE_Array.toBytes(write_byteArrays);
|
||||||
|
connector.write(DaveArea.DB, 3, 832 , bytes2);
|
||||||
|
byte[] byteArrays = connector.read(DaveArea.DB, 3, 2, 832);
|
||||||
|
// List<Byte> bytes = ByteUtils.toByteArray(byteArrays);
|
||||||
|
List<Byte> bytes = (List<Byte>) PlcVar.BYTE_Array.toObject(boolArrays);
|
||||||
|
System.out.println("DB3.832-byteArrays : " +bytes );
|
||||||
|
|
||||||
|
|
||||||
|
short[] shortArrays_content = new short[2];
|
||||||
|
shortArrays_content[0] = 1;
|
||||||
|
shortArrays_content[1] = -1;
|
||||||
|
// byte[] bytes4 = ByteUtils.wordArrayToBytes(shortArrays_content);
|
||||||
|
byte[] bytes4 = PlcVar.WORD_Array.toBytes(shortArrays_content);
|
||||||
|
connector.write(DaveArea.DB, 3, 836 ,bytes4);
|
||||||
|
byte[] wordArrays = connector.read(DaveArea.DB, 3, 4, 836);
|
||||||
|
List<Integer> words = ByteUtils.toWordArray(wordArrays);
|
||||||
|
System.out.println("DB3.836-wordArrays : " +words );
|
||||||
|
|
||||||
|
int[] intArrays_content = new int[2];
|
||||||
|
intArrays_content[0] = 1;
|
||||||
|
intArrays_content[1] = -1;
|
||||||
|
// byte[] bytes5 = ByteUtils.dwordArrayToBytes(intArrays_content);
|
||||||
|
byte[] bytes5 = PlcVar.DWORD_Array.toBytes(intArrays_content);
|
||||||
|
connector.write(DaveArea.DB, 3, 840 ,bytes5);
|
||||||
|
byte[] dwordArrays = connector.read(DaveArea.DB, 3, 8, 840);
|
||||||
|
List<Integer> dwords = ByteUtils.toDWordArray(dwordArrays);
|
||||||
|
System.out.println("DB3.840-dwordArrays : " +dwords );
|
||||||
|
|
||||||
|
|
||||||
|
char[] charArrays_content = new char[2];
|
||||||
|
charArrays_content[0] = '1';
|
||||||
|
charArrays_content[1] = 'b';
|
||||||
|
// byte[] bytes3 = ByteUtils.charArrayToBytes(charArrays_content);
|
||||||
|
byte[] bytes3 = PlcVar.CHAR_Array.toBytes(charArrays_content);
|
||||||
|
connector.write(DaveArea.DB, 3, 834 ,bytes3);
|
||||||
|
byte[] charArrays = connector.read(DaveArea.DB, 3, 2, 834);
|
||||||
|
List<Character> chars = ByteUtils.toCharArray(charArrays);
|
||||||
|
System.out.println("DB3.834-charArrays : " +chars );
|
||||||
|
|
||||||
|
|
||||||
|
int[] sintArrays_content = new int[2];
|
||||||
|
sintArrays_content[0] = 1;
|
||||||
|
sintArrays_content[1] = -1;
|
||||||
|
// byte[] bytes6 = ByteUtils.sintArrayToBytes(sintArrays_content);
|
||||||
|
byte[] bytes6 = PlcVar.SINT_Array.toBytes(sintArrays_content);
|
||||||
|
connector.write(DaveArea.DB, 3, 852 ,bytes6);
|
||||||
|
byte[] sintArrays = connector.read(DaveArea.DB, 3, 2, 852);
|
||||||
|
List<Integer> sints = ByteUtils.toSIntArray(sintArrays);
|
||||||
|
System.out.println("DB3.852-sintArrays : " +sints );
|
||||||
|
|
||||||
|
|
||||||
|
int[] iintArrays_content = new int[2];
|
||||||
|
iintArrays_content[0] = 12;
|
||||||
|
iintArrays_content[1] = -21;
|
||||||
|
// byte[] bytes7 = ByteUtils.intArrayToBytes(iintArrays_content);
|
||||||
|
byte[] bytes7 = PlcVar.INT_Array.toBytes(iintArrays_content);
|
||||||
|
connector.write(DaveArea.DB, 3, 848 ,bytes7);
|
||||||
|
byte[] intArrays = connector.read(DaveArea.DB, 3, 4, 848);
|
||||||
|
List<Integer> ints = ByteUtils.toIntArray(intArrays);
|
||||||
|
System.out.println("DB3.848-intArrays : " +ints );
|
||||||
|
|
||||||
|
|
||||||
|
//todo here
|
||||||
|
int[] dintArrays_content = new int[2];
|
||||||
|
dintArrays_content[0] = 12;
|
||||||
|
dintArrays_content[1] = -21;
|
||||||
|
//ByteUtils.dintArrayToBytes(dintArrays_content)
|
||||||
|
byte[] bytes11 =PlcVar.DINT_Array.toBytes(dintArrays_content);
|
||||||
|
connector.write(DaveArea.DB, 3, 854 ,bytes11);
|
||||||
|
byte[] dintArrays = connector.read(DaveArea.DB, 3, 8, 854);
|
||||||
|
List<Integer> dints = ByteUtils.toDIntArray(dintArrays);
|
||||||
|
System.out.println("DB3.852-dintArrays : " +dints);
|
||||||
|
|
||||||
|
|
||||||
|
int[] uintArrays_content = new int[3];
|
||||||
|
uintArrays_content[0] = 12;
|
||||||
|
uintArrays_content[1] = 99;
|
||||||
|
uintArrays_content[2] = 1;
|
||||||
|
//byte[] bytes9 = ByteUtils.uintArrayToBytes(uintArrays_content);
|
||||||
|
byte[] bytes9 = PlcVar.UINT_Array.toBytes(uintArrays_content);
|
||||||
|
connector.write(DaveArea.DB, 3, 3256 ,bytes9);
|
||||||
|
byte[] uintArrays = connector.read(DaveArea.DB, 3, 6, 3256);
|
||||||
|
List<Integer> uints = ByteUtils.toUIntArray(uintArrays);
|
||||||
|
System.out.println("DB3.3256-uintArrays : " +uints );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int[] usintArrays_content = new int[3];
|
||||||
|
usintArrays_content[0] = 12;
|
||||||
|
usintArrays_content[1] = 99;
|
||||||
|
usintArrays_content[2] = 1;
|
||||||
|
// byte[] bytes8 = ByteUtils.usintArrayToBytes(usintArrays_content);
|
||||||
|
byte[] bytes8 = PlcVar.USINT_Array.toBytes(usintArrays_content);
|
||||||
|
connector.write(DaveArea.DB, 3, 3240 ,bytes8);
|
||||||
|
byte[] usintArrays = connector.read(DaveArea.DB, 3, 3, 3240);
|
||||||
|
List<Integer> usints = ByteUtils.toUSIntArray(usintArrays);
|
||||||
|
System.out.println("DB3.3240-usintArrays : " +usints );
|
||||||
|
|
||||||
|
|
||||||
|
int[] udintArrays_content = new int[3];
|
||||||
|
udintArrays_content[0] = 12;
|
||||||
|
udintArrays_content[1] = 99;
|
||||||
|
udintArrays_content[2] = 1;
|
||||||
|
// byte[] bytes10 = ByteUtils.udintArrayToBytes(udintArrays_content);
|
||||||
|
byte[] bytes10 = PlcVar.UDINT_Array.toBytes(udintArrays_content);
|
||||||
|
connector.write(DaveArea.DB, 3, 3244 ,bytes10);
|
||||||
|
byte[] udintArrays = connector.read(DaveArea.DB, 3, 12, 3244);
|
||||||
|
List<Long> udints = ByteUtils.toUDIntArray(udintArrays);
|
||||||
|
System.out.println("DB3.852-udintArrays : " +udints);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Write to DB100 10 bytes
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//connector.write(DaveArea.DB, 3, 830, byteArrays);
|
||||||
|
|
||||||
|
//Close connection
|
||||||
|
connector.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.api;
|
||||||
|
|
||||||
|
public enum DaveArea {
|
||||||
|
ANALOGINPUTS200(6), // System info of 200 family
|
||||||
|
ANALOGOUTPUTS200(7), // System flags of 200 family
|
||||||
|
COUNTER(28), // analog inputs of 200 family
|
||||||
|
COUNTER200(30), // analog outputs of 200 family
|
||||||
|
DB(0x84), // Peripheral I/O //DB块
|
||||||
|
DI(0x85), //DBI块
|
||||||
|
FLAGS(0x83), //M块(M块 的 areaNumber 都是0 , 只配置 byteOffset 和 bitOffset)
|
||||||
|
INPUTS(0x81), //I块
|
||||||
|
T(0x1D), //T块ed
|
||||||
|
C(0x1C), //C块
|
||||||
|
|
||||||
|
LOCAL(0x86), // data blocks //LD块
|
||||||
|
OUTPUTS(0x82), // instance data blocks //Q块
|
||||||
|
P(0x80), // not tested //D块
|
||||||
|
SYSINFO(3), // local of caller
|
||||||
|
SYSTEMFLAGS(5), // S7 counters
|
||||||
|
TIMER(29), // S7 timers
|
||||||
|
TIMER200(31), // IEC counters (200 family)
|
||||||
|
V(0x87); // IEC timers (200 family)
|
||||||
|
|
||||||
|
/** Function Code */
|
||||||
|
int code;
|
||||||
|
|
||||||
|
/** Constructor */
|
||||||
|
DaveArea(final int code) {
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the function code as associated
|
||||||
|
*/
|
||||||
|
public int getCode() {
|
||||||
|
return this.code;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.api;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.type.PlcVar;
|
||||||
|
import com.cnbm.s7.s7connector.type.TransportSize;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
|
||||||
|
public interface S7Connector extends Closeable {
|
||||||
|
/**
|
||||||
|
* Reads an area
|
||||||
|
* desc : 只要未抛出异常,都是 操作成功的 ( 锁 )
|
||||||
|
* @param area
|
||||||
|
* @param areaNumber
|
||||||
|
* @param bytes
|
||||||
|
* @param offset
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public byte[] read(DaveArea area, int areaNumber, int bytes, int offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads an area 读需要bit 位置的 变量(其实就是 read bool变量的时候调用这个方法。)
|
||||||
|
* desc : 只要未抛出异常,都是 操作成功的 ( 锁 )
|
||||||
|
* @param area
|
||||||
|
* @param areaNumber
|
||||||
|
* @param bytes
|
||||||
|
* @param offset
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public byte[] read(DaveArea area, int areaNumber, int bytes, int offset, int bitOffset, TransportSize transportSize);
|
||||||
|
/**
|
||||||
|
* Writes an area
|
||||||
|
* desc : 只要未抛出异常,都是 操作成功的 ( 锁 )
|
||||||
|
* @param area
|
||||||
|
* @param areaNumber
|
||||||
|
* @param offset
|
||||||
|
* @param buffer
|
||||||
|
*/
|
||||||
|
public void write(DaveArea area, int areaNumber, int offset, byte[] buffer);
|
||||||
|
|
||||||
|
//如果 bitOffset 没有 那么就填0 ( 锁 )
|
||||||
|
public void write(DaveArea area, int areaNumber, int byteOffset, int bitOffset, byte[] buffer, PlcVar var);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.api;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.impl.utils.S7Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Interface S7Serializable API
|
||||||
|
*/
|
||||||
|
public interface S7Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts a java type from a byte buffer.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* the generic type
|
||||||
|
* @param targetClass
|
||||||
|
* the target class
|
||||||
|
* @param buffer
|
||||||
|
* the buffer
|
||||||
|
* @param byteOffset
|
||||||
|
* the byte offset
|
||||||
|
* @param bitOffset
|
||||||
|
* the bit offset
|
||||||
|
* @return the t
|
||||||
|
*/
|
||||||
|
public <T> T extract(Class<T> targetClass, byte[] buffer, int byteOffset, int bitOffset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the S7-Type.
|
||||||
|
*
|
||||||
|
* @return the s7 type
|
||||||
|
*/
|
||||||
|
public S7Type getS7Type();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of the s7 type bytes.
|
||||||
|
*
|
||||||
|
* @return the size in bits
|
||||||
|
*/
|
||||||
|
public int getSizeInBits();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the size of the s7 type bytes.
|
||||||
|
*
|
||||||
|
* @return the size in bytes
|
||||||
|
*/
|
||||||
|
public int getSizeInBytes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts a Java Object to the byte buffer.
|
||||||
|
*
|
||||||
|
* @param javaType
|
||||||
|
* the java type
|
||||||
|
* @param buffer
|
||||||
|
* the buffer
|
||||||
|
* @param byteOffset
|
||||||
|
* the byte offset
|
||||||
|
* @param bitOffset
|
||||||
|
* the bit offset
|
||||||
|
* @param size
|
||||||
|
* the size
|
||||||
|
*/
|
||||||
|
public void insert(Object javaType, byte[] buffer, int byteOffset, int bitOffset, int size);
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.api;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.exception.S7Exception;
|
||||||
|
|
||||||
|
public interface S7Serializer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispenses an Object from the mapping of the Datablock.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* the generic type
|
||||||
|
* @param beanClass
|
||||||
|
* the bean class
|
||||||
|
* @param dbNum
|
||||||
|
* the db num
|
||||||
|
* @param byteOffset
|
||||||
|
* the byte offset
|
||||||
|
* @return the t
|
||||||
|
* @throws S7Exception
|
||||||
|
* the s7 exception
|
||||||
|
*/
|
||||||
|
<T> T dispense(Class<T> beanClass, int dbNum, int byteOffset) throws S7Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispense.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* the generic type
|
||||||
|
* @param beanClass
|
||||||
|
* the bean class
|
||||||
|
* @param dbNum
|
||||||
|
* the db num
|
||||||
|
* @param byteOffset
|
||||||
|
* the byte offset
|
||||||
|
* @param blockSize
|
||||||
|
* the block size
|
||||||
|
* @return the t
|
||||||
|
* @throws S7Exception
|
||||||
|
* the s7 exception
|
||||||
|
*/
|
||||||
|
<T> T dispense(Class<T> beanClass, int dbNum, int byteOffset, int blockSize) throws S7Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores an Object to the Datablock.
|
||||||
|
*
|
||||||
|
* @param bean
|
||||||
|
* the bean
|
||||||
|
* @param dbNum
|
||||||
|
* the db num
|
||||||
|
* @param byteOffset
|
||||||
|
* the byte offset
|
||||||
|
*/
|
||||||
|
void store(Object bean, int dbNum, int byteOffset);
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.api.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation for array-declaration
|
||||||
|
*
|
||||||
|
* @author Thomas Rudin
|
||||||
|
*/
|
||||||
|
@Target(value = { ElementType.FIELD })
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface Array {
|
||||||
|
int size();
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.api.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Annotation for a datablock
|
||||||
|
*
|
||||||
|
* @author Thomas Rudin
|
||||||
|
*/
|
||||||
|
@Target(value = { ElementType.TYPE })
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface Datablock {
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.api.annotation;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.impl.utils.S7Type;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines an Offset in a DB
|
||||||
|
*
|
||||||
|
* @author Thomas Rudin
|
||||||
|
*/
|
||||||
|
@Target(value = { ElementType.FIELD })
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface S7Variable {
|
||||||
|
/**
|
||||||
|
* The size of the array
|
||||||
|
*/
|
||||||
|
int arraySize() default 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The bit offset, if any
|
||||||
|
*/
|
||||||
|
int bitOffset() default 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Byte Offset
|
||||||
|
*/
|
||||||
|
int byteOffset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The specified size (for String)
|
||||||
|
*/
|
||||||
|
int size() default 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The corresponding S7 Type
|
||||||
|
*/
|
||||||
|
S7Type type();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.api.factory;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Connector;
|
||||||
|
import com.cnbm.s7.s7connector.impl.S7TCPConnection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* S7 connector factory, currently only for TCP connections
|
||||||
|
*
|
||||||
|
* @author Thomas Rudin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class S7ConnectorFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TCP Connection builder
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class TCPConnectionBuilder {
|
||||||
|
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
//rack 和 slot 都是指的是 remote-rack 和 remote-slot
|
||||||
|
private int rack = 0, slot = 0, port = 102;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a connection with given params
|
||||||
|
*/
|
||||||
|
public S7Connector build() {
|
||||||
|
return new S7TCPConnection(this.host, this.rack, this.slot, this.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* use hostname/ip
|
||||||
|
*/
|
||||||
|
public TCPConnectionBuilder withHost(final String host) {
|
||||||
|
this.host = host;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* use port, default is 102
|
||||||
|
*/
|
||||||
|
public TCPConnectionBuilder withPort(final int port) {
|
||||||
|
this.port = port;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* use rack, default is 0
|
||||||
|
*/
|
||||||
|
public TCPConnectionBuilder withRack(final int rack) {
|
||||||
|
this.rack = rack;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* use slot, default is 2
|
||||||
|
*/
|
||||||
|
public TCPConnectionBuilder withSlot(final int slot) {
|
||||||
|
this.slot = slot;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns a new TCP connection builder
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static TCPConnectionBuilder buildTCPConnector() {
|
||||||
|
return new TCPConnectionBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.api.factory;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Connector;
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Serializer;
|
||||||
|
import com.cnbm.s7.s7connector.impl.serializer.S7SerializerImpl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* S7 Serializer factory
|
||||||
|
*
|
||||||
|
* @author Thomas Rudin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class S7SerializerFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a new serializer with given connector
|
||||||
|
*
|
||||||
|
* @param connector
|
||||||
|
* the connector to use
|
||||||
|
* @return a serializer instance
|
||||||
|
*/
|
||||||
|
public static S7Serializer buildSerializer(final S7Connector connector) {
|
||||||
|
return new S7SerializerImpl(connector);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,328 @@
|
|||||||
|
package com.cnbm.s7.s7connector.api.utils;
|
||||||
|
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Desc: ""
|
||||||
|
* @Author: caixiang
|
||||||
|
* @DATE: 2022/4/1 17:32
|
||||||
|
*/
|
||||||
|
//对数字和字节进行转换。 假设数据存储是以大端模式存储的:
|
||||||
|
// byte: 字节类型 占8位二进制 00000000
|
||||||
|
// char: 字符类型 占2个字节 16位二进制 byte[0] byte[1]
|
||||||
|
// int : 整数类型 占4个字节 32位二进制 byte[0] byte[1] byte[2] byte[3]
|
||||||
|
// long: 长整数类型 占8个字节 64位二进制 byte[0] byte[1] byte[2] byte[3] byte[4] byte[5]
|
||||||
|
// long: 长整数类型 占8个字节 64位二进制 byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7]
|
||||||
|
// float: 浮点数(小数) 占4个字节 32位二进制 byte[0] byte[1] byte[2] byte[3]
|
||||||
|
// double: 双精度浮点数(小数) 占8个字节 64位二进制 byte[0] byte[1] byte[2] byte[3] byte[4]byte[5] byte[6] byte[7]
|
||||||
|
|
||||||
|
public class ByteUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* int转byte
|
||||||
|
*
|
||||||
|
* @param intValue int值
|
||||||
|
* @return byte值
|
||||||
|
*/
|
||||||
|
public static byte intToByte(int intValue) {
|
||||||
|
return (byte) intValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* byte转无符号int
|
||||||
|
*
|
||||||
|
* @param byteValue byte值
|
||||||
|
* @return 无符号int值
|
||||||
|
* @since 3.2.0
|
||||||
|
*/
|
||||||
|
public static int byteToUnsignedInt(byte byteValue) {
|
||||||
|
// Java 总是把 byte 当做有符处理;我们可以通过将其和 0xFF 进行二进制与得到它的无符值
|
||||||
|
return byteValue & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* byte数组转short<br>
|
||||||
|
* 默认以小端序转换
|
||||||
|
*
|
||||||
|
* @param bytes byte数组
|
||||||
|
* @return short值
|
||||||
|
*/
|
||||||
|
public static short bytesToShort(byte[] bytes) {
|
||||||
|
return bytesToShort(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* byte数组转short<br>
|
||||||
|
* 自定义端序
|
||||||
|
*
|
||||||
|
* @param bytes byte数组
|
||||||
|
* @param byteOrder 端序
|
||||||
|
* @return short值
|
||||||
|
*/
|
||||||
|
public static short bytesToShort(byte[] bytes, ByteOrder byteOrder) {
|
||||||
|
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
|
||||||
|
//小端模式,数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中
|
||||||
|
return (short) (bytes[0] & 0xff | (bytes[1] & 0xff) << Byte.SIZE);
|
||||||
|
} else {
|
||||||
|
return (short) (bytes[1] & 0xff | (bytes[0] & 0xff) << Byte.SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* short转byte数组<br>
|
||||||
|
* 默认以小端序转换
|
||||||
|
*
|
||||||
|
* @param shortValue short值
|
||||||
|
* @return byte数组
|
||||||
|
*/
|
||||||
|
public static byte[] shortToBytes(short shortValue) {
|
||||||
|
return shortToBytes(shortValue, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* short转byte数组<br>
|
||||||
|
* 自定义端序
|
||||||
|
*
|
||||||
|
* @param shortValue short值
|
||||||
|
* @param byteOrder 端序
|
||||||
|
* @return byte数组
|
||||||
|
*/
|
||||||
|
public static byte[] shortToBytes(short shortValue, ByteOrder byteOrder) {
|
||||||
|
byte[] b = new byte[Short.BYTES];
|
||||||
|
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
|
||||||
|
b[0] = (byte) (shortValue & 0xff);
|
||||||
|
b[1] = (byte) ((shortValue >> Byte.SIZE) & 0xff);
|
||||||
|
} else {
|
||||||
|
b[1] = (byte) (shortValue & 0xff);
|
||||||
|
b[0] = (byte) ((shortValue >> Byte.SIZE) & 0xff);
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* byte[]转int值<br>
|
||||||
|
* 默认以小端序转换
|
||||||
|
*
|
||||||
|
* @param bytes byte数组
|
||||||
|
* @return int值
|
||||||
|
*/
|
||||||
|
public static int bytesToInt(byte[] bytes) {
|
||||||
|
return bytesToInt(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* byte[]转int值<br>
|
||||||
|
* 自定义端序
|
||||||
|
*
|
||||||
|
* @param bytes byte数组
|
||||||
|
* @param byteOrder 端序
|
||||||
|
* @return int值
|
||||||
|
*/
|
||||||
|
public static int bytesToInt(byte[] bytes, ByteOrder byteOrder) {
|
||||||
|
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
|
||||||
|
return bytes[0] & 0xFF | //
|
||||||
|
(bytes[1] & 0xFF) << 8 | //
|
||||||
|
(bytes[2] & 0xFF) << 16 | //
|
||||||
|
(bytes[3] & 0xFF) << 24; //
|
||||||
|
} else {
|
||||||
|
return bytes[3] & 0xFF | //
|
||||||
|
(bytes[2] & 0xFF) << 8 | //
|
||||||
|
(bytes[1] & 0xFF) << 16 | //
|
||||||
|
(bytes[0] & 0xFF) << 24; //
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* int转byte数组<br>
|
||||||
|
* 默认以小端序转换
|
||||||
|
*
|
||||||
|
* @param intValue int值
|
||||||
|
* @return byte数组
|
||||||
|
*/
|
||||||
|
public static byte[] intToBytes(int intValue) {
|
||||||
|
return intToBytes(intValue, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* int转byte数组<br>
|
||||||
|
* 自定义端序
|
||||||
|
*
|
||||||
|
* @param intValue int值
|
||||||
|
* @param byteOrder 端序
|
||||||
|
* @return byte数组
|
||||||
|
*/
|
||||||
|
public static byte[] intToBytes(int intValue, ByteOrder byteOrder) {
|
||||||
|
|
||||||
|
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
|
||||||
|
return new byte[]{ //
|
||||||
|
(byte) (intValue & 0xFF), //
|
||||||
|
(byte) ((intValue >> 8) & 0xFF), //
|
||||||
|
(byte) ((intValue >> 16) & 0xFF), //
|
||||||
|
(byte) ((intValue >> 24) & 0xFF) //
|
||||||
|
};
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return new byte[]{ //
|
||||||
|
(byte) ((intValue >> 24) & 0xFF), //
|
||||||
|
(byte) ((intValue >> 16) & 0xFF), //
|
||||||
|
(byte) ((intValue >> 8) & 0xFF), //
|
||||||
|
(byte) (intValue & 0xFF) //
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* long转byte数组<br>
|
||||||
|
* 默认以小端序转换<br>
|
||||||
|
* from: https://stackoverflow.com/questions/4485128/how-do-i-convert-long-to-byte-and-back-in-java
|
||||||
|
*
|
||||||
|
* @param longValue long值
|
||||||
|
* @return byte数组
|
||||||
|
*/
|
||||||
|
public static byte[] longToBytes(long longValue) {
|
||||||
|
return longToBytes(longValue, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* long转byte数组<br>
|
||||||
|
* 自定义端序<br>
|
||||||
|
* from: https://stackoverflow.com/questions/4485128/how-do-i-convert-long-to-byte-and-back-in-java
|
||||||
|
*
|
||||||
|
* @param longValue long值
|
||||||
|
* @param byteOrder 端序
|
||||||
|
* @return byte数组
|
||||||
|
*/
|
||||||
|
public static byte[] longToBytes(long longValue, ByteOrder byteOrder) {
|
||||||
|
byte[] result = new byte[Long.BYTES];
|
||||||
|
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
|
||||||
|
for (int i = 0; i < result.length; i++) {
|
||||||
|
result[i] = (byte) (longValue & 0xFF);
|
||||||
|
longValue >>= Byte.SIZE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = (result.length - 1); i >= 0; i--) {
|
||||||
|
result[i] = (byte) (longValue & 0xFF);
|
||||||
|
longValue >>= Byte.SIZE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* byte数组转long<br>
|
||||||
|
* 默认以小端序转换<br>
|
||||||
|
* from: https://stackoverflow.com/questions/4485128/how-do-i-convert-long-to-byte-and-back-in-java
|
||||||
|
*
|
||||||
|
* @param bytes byte数组
|
||||||
|
* @return long值
|
||||||
|
*/
|
||||||
|
public static long bytesToLong(byte[] bytes) {
|
||||||
|
return bytesToLong(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* byte数组转long<br>
|
||||||
|
* 自定义端序<br>
|
||||||
|
* from: https://stackoverflow.com/questions/4485128/how-do-i-convert-long-to-byte-and-back-in-java
|
||||||
|
*
|
||||||
|
* @param bytes byte数组
|
||||||
|
* @param byteOrder 端序
|
||||||
|
* @return long值
|
||||||
|
*/
|
||||||
|
public static long bytesToLong(byte[] bytes, ByteOrder byteOrder) {
|
||||||
|
long values = 0;
|
||||||
|
if (ByteOrder.LITTLE_ENDIAN == byteOrder) {
|
||||||
|
for (int i = (Long.BYTES - 1); i >= 0; i--) {
|
||||||
|
values <<= Byte.SIZE;
|
||||||
|
values |= (bytes[i] & 0xff);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < Long.BYTES; i++) {
|
||||||
|
values <<= Byte.SIZE;
|
||||||
|
values |= (bytes[i] & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* double转byte数组<br>
|
||||||
|
* 默认以小端序转换<br>
|
||||||
|
*
|
||||||
|
* @param doubleValue double值
|
||||||
|
* @return byte数组
|
||||||
|
*/
|
||||||
|
public static byte[] doubleToBytes(double doubleValue) {
|
||||||
|
return doubleToBytes(doubleValue, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* double转byte数组<br>
|
||||||
|
* 自定义端序<br>
|
||||||
|
* from: https://stackoverflow.com/questions/4485128/how-do-i-convert-long-to-byte-and-back-in-java
|
||||||
|
*
|
||||||
|
* @param doubleValue double值
|
||||||
|
* @param byteOrder 端序
|
||||||
|
* @return byte数组
|
||||||
|
*/
|
||||||
|
public static byte[] doubleToBytes(double doubleValue, ByteOrder byteOrder) {
|
||||||
|
return longToBytes(Double.doubleToLongBits(doubleValue), byteOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* byte数组转Double<br>
|
||||||
|
* 默认以小端序转换<br>
|
||||||
|
*
|
||||||
|
* @param bytes byte数组
|
||||||
|
* @return long值
|
||||||
|
*/
|
||||||
|
public static double bytesToDouble(byte[] bytes) {
|
||||||
|
return bytesToDouble(bytes, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* byte数组转double<br>
|
||||||
|
* 自定义端序<br>
|
||||||
|
*
|
||||||
|
* @param bytes byte数组
|
||||||
|
* @param byteOrder 端序
|
||||||
|
* @return long值
|
||||||
|
*/
|
||||||
|
public static double bytesToDouble(byte[] bytes, ByteOrder byteOrder) {
|
||||||
|
return Double.longBitsToDouble(bytesToLong(bytes, byteOrder));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将{@link Number}转换为
|
||||||
|
*
|
||||||
|
* @param number 数字
|
||||||
|
* @return bytes
|
||||||
|
*/
|
||||||
|
public static byte[] numberToBytes(Number number) {
|
||||||
|
return numberToBytes(number, ByteOrder.LITTLE_ENDIAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将{@link Number}转换为
|
||||||
|
*
|
||||||
|
* @param number 数字
|
||||||
|
* @param byteOrder 端序
|
||||||
|
* @return bytes
|
||||||
|
*/
|
||||||
|
public static byte[] numberToBytes(Number number, ByteOrder byteOrder) {
|
||||||
|
if (number instanceof Double) {
|
||||||
|
return doubleToBytes((Double) number, byteOrder);
|
||||||
|
} else if (number instanceof Long) {
|
||||||
|
return longToBytes((Long) number, byteOrder);
|
||||||
|
} else if (number instanceof Integer) {
|
||||||
|
return intToBytes((Integer) number, byteOrder);
|
||||||
|
} else if (number instanceof Short) {
|
||||||
|
return shortToBytes((Short) number, byteOrder);
|
||||||
|
} else {
|
||||||
|
return doubleToBytes(number.doubleValue(), byteOrder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,933 @@
|
|||||||
|
package com.cnbm.s7.s7connector.api.utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Desc: ""
|
||||||
|
* @Author: caixiang
|
||||||
|
* @DATE: 2021/12/16 9:08
|
||||||
|
*/
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.exception.S7ParseDataException;
|
||||||
|
import com.cnbm.s7.s7connector.utils.CommonFunctions;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class ByteUtils {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static double bytes2Double(byte[] arr) {
|
||||||
|
long value = 0;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
value |= ((long) (arr[i] & 0xff)) << (8 * i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Double.longBitsToDouble(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Boolean toBoolean(byte[] bytes){
|
||||||
|
if(bytes.length ==0){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if(bytes[0] == 1){
|
||||||
|
return true;
|
||||||
|
}else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static Boolean toBoolean(byte bytes){
|
||||||
|
if(bytes == 1){
|
||||||
|
return true;
|
||||||
|
}else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String addDate(String timeParam, Long day) {
|
||||||
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); // 日期格式
|
||||||
|
Date date = null;
|
||||||
|
try {
|
||||||
|
date = dateFormat.parse(timeParam); // 指定日期
|
||||||
|
}catch (Exception e){
|
||||||
|
throw new S7ParseDataException("ByteUtils.addDate error:", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
long time = date.getTime(); // 得到指定日期的毫秒数
|
||||||
|
day = day * 24 * 60 * 60 * 1000; // 要加上的天数转换成毫秒数
|
||||||
|
time += day; // 相加得到新的毫秒数
|
||||||
|
Date newDate = new Date(time);
|
||||||
|
return dateFormat.format(newDate); // 将毫秒数转换成日期
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static byte[] invert(byte[] a){
|
||||||
|
byte[] b = new byte[a.length];
|
||||||
|
Stack<Byte> st = new Stack<Byte>();
|
||||||
|
for(int i=0;i<a.length;i++){
|
||||||
|
st.push(a[i]);
|
||||||
|
}
|
||||||
|
for(int i=0;i<a.length;i++){
|
||||||
|
b[i] = st.pop();
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1个字节byte[] 转成有符号的Integer
|
||||||
|
* */
|
||||||
|
public static Integer toInt(byte bytes) {
|
||||||
|
return Integer.valueOf(Byte.toString(bytes));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 1个字节byte[] 转成无符号的Integer
|
||||||
|
* */
|
||||||
|
public static Integer toUInt(byte bytes) {
|
||||||
|
int i = Byte.toUnsignedInt(bytes);
|
||||||
|
return Integer.valueOf(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2个字节byte[] 转成有符号的Integer
|
||||||
|
* 默认大端
|
||||||
|
* */
|
||||||
|
public static Integer toInt(byte byte1,byte byte2) {
|
||||||
|
byte[] bytes = new byte[2];
|
||||||
|
bytes[0] = byte1;
|
||||||
|
bytes[1] = byte2;
|
||||||
|
|
||||||
|
return Integer.valueOf(Short.toString(ByteUtil.bytesToShort(bytes, ByteOrder.BIG_ENDIAN)));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 2个字节byte[] 转成无符号的Integer
|
||||||
|
* 默认大端
|
||||||
|
* */
|
||||||
|
public static Integer toUInt(byte byte1,byte byte2) {
|
||||||
|
byte[] bytes = new byte[2];
|
||||||
|
bytes[0] = byte1;
|
||||||
|
bytes[1] = byte2;
|
||||||
|
short i = ByteUtil.bytesToShort(bytes, ByteOrder.BIG_ENDIAN);
|
||||||
|
return Short.toUnsignedInt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 4个字节byte[] 转成有符号的Integer
|
||||||
|
* 默认大端
|
||||||
|
* */
|
||||||
|
public static Integer toInt(byte byte1,byte byte2,byte byte3,byte byte4) {
|
||||||
|
byte[] bytes = new byte[4];
|
||||||
|
bytes[0] = byte1;
|
||||||
|
bytes[1] = byte2;
|
||||||
|
bytes[2] = byte3;
|
||||||
|
bytes[3] = byte4;
|
||||||
|
return ByteUtil.bytesToInt(bytes, ByteOrder.BIG_ENDIAN);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 4个字节byte[] 转成无符号的Long(因为如果首位为1 Integer就不满足长度了)
|
||||||
|
* 默认大端
|
||||||
|
* */
|
||||||
|
public static Long toUInt(byte byte1,byte byte2,byte byte3,byte byte4) {
|
||||||
|
byte[] bytes = new byte[8];
|
||||||
|
bytes[0] = 0;
|
||||||
|
bytes[1] = 0;
|
||||||
|
bytes[2] = 0;
|
||||||
|
bytes[3] = 0;
|
||||||
|
bytes[4] = byte1;
|
||||||
|
bytes[5] = byte2;
|
||||||
|
bytes[6] = byte3;
|
||||||
|
bytes[7] = byte4;
|
||||||
|
long l = ByteUtil.bytesToLong(bytes, ByteOrder.BIG_ENDIAN);
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 4个字节byte[] 转成有符号的Double
|
||||||
|
* 默认大端
|
||||||
|
* */
|
||||||
|
public static Float forReal(byte[] bytes) {
|
||||||
|
return Float.intBitsToFloat(toInt(bytes[0],bytes[1],bytes[2],bytes[3]));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 8个字节byte[] 转成有符号的Double
|
||||||
|
* 默认大端
|
||||||
|
* */
|
||||||
|
public static Double forLReal(byte[] bytes) {
|
||||||
|
return ByteUtil.bytesToDouble(bytes, ByteOrder.BIG_ENDIAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 8个字节byte[] 转成有符号的Double
|
||||||
|
* 默认大端
|
||||||
|
* */
|
||||||
|
public static Double lrealbytesToDouble(byte[] bytes) {
|
||||||
|
return ByteUtil.bytesToDouble(bytes, ByteOrder.BIG_ENDIAN);
|
||||||
|
}
|
||||||
|
public static byte[] lrealToBytes(double doubleValue) {
|
||||||
|
return ByteUtil.doubleToBytes(doubleValue, ByteOrder.BIG_ENDIAN);
|
||||||
|
//return double2Bytes(doubleValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static String toChar(byte[] b) throws UnsupportedEncodingException {
|
||||||
|
// String ascii = new String(b, Charset.forName("UTF-8"));
|
||||||
|
// return ascii;
|
||||||
|
// }
|
||||||
|
public static Character toChar(byte[] b) {
|
||||||
|
if(b.length==1){
|
||||||
|
return toChar(b[0]);
|
||||||
|
}
|
||||||
|
return byteToChar(b);
|
||||||
|
}
|
||||||
|
public static Character toChar(byte b){
|
||||||
|
return byteToChar(b);
|
||||||
|
}
|
||||||
|
// public static String toChar(byte b) throws UnsupportedEncodingException {
|
||||||
|
// byte[] bs = new byte[1];
|
||||||
|
// bs[0] = b;
|
||||||
|
// String ascii = new String(bs, "ascii");
|
||||||
|
// return ascii;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return null 代表返回传入参数不正确str 取的length太小
|
||||||
|
* */
|
||||||
|
public static String toStr(byte[] b) {
|
||||||
|
Integer length = Byte.toUnsignedInt(b[1]);
|
||||||
|
if(length>(b.length-2)){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
byte[] content = new byte[b.length-2];
|
||||||
|
for(int i=0;i<length;i++){
|
||||||
|
content[i] = b[i+2];
|
||||||
|
}
|
||||||
|
String ascii = new String(content, StandardCharsets.UTF_8);
|
||||||
|
// String s = new String(content);
|
||||||
|
return ascii;
|
||||||
|
}
|
||||||
|
public static String[] toStrArray(byte[] b,Integer length,Integer strSize) {
|
||||||
|
String[] res = new String[length];
|
||||||
|
strSize+=2;
|
||||||
|
for(int i=0;i<length;i++){
|
||||||
|
byte[] one = new byte[strSize];
|
||||||
|
System.arraycopy(b,i*strSize,one,0,strSize);
|
||||||
|
res[i] = toStr(one);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将byte转换为一个长度为8的boolean数组(每bit代表一个boolean值)
|
||||||
|
*
|
||||||
|
* @param b byte, return(将数组翻转过来)
|
||||||
|
* @return boolean数组
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static boolean[] getBooleanArray(byte b,boolean returns) {
|
||||||
|
|
||||||
|
boolean[] array = new boolean[8];
|
||||||
|
|
||||||
|
for (int i = 7; i >= 0; i--) { //对于byte的每bit进行判定
|
||||||
|
|
||||||
|
array[i] = (b & 1) == 1; //判定byte的最后一位是否为1,若为1,则是true;否则是false
|
||||||
|
|
||||||
|
b = (byte) (b >> 1); //将byte右移一位
|
||||||
|
|
||||||
|
}
|
||||||
|
if(returns){
|
||||||
|
boolean[] array1 = new boolean[8];
|
||||||
|
array1[0] = array[7];
|
||||||
|
array1[1] = array[6];
|
||||||
|
array1[2] = array[5];
|
||||||
|
array1[3] = array[4];
|
||||||
|
array1[4] = array[3];
|
||||||
|
array1[5] = array[2];
|
||||||
|
array1[6] = array[1];
|
||||||
|
array1[7] = array[0];
|
||||||
|
array = array1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Byte fromBooleanArray(boolean[] a) {
|
||||||
|
byte b = 0;
|
||||||
|
if (a[7])
|
||||||
|
b += 1;
|
||||||
|
if (a[6])
|
||||||
|
b += 2;
|
||||||
|
if (a[5])
|
||||||
|
b += 4;
|
||||||
|
if (a[4])
|
||||||
|
b += 8;
|
||||||
|
if (a[3])
|
||||||
|
b += 16;
|
||||||
|
if (a[2])
|
||||||
|
b += 32;
|
||||||
|
if (a[1])
|
||||||
|
b += 64;
|
||||||
|
if (a[0])
|
||||||
|
b += 128;
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Boolean> toBoolArray(byte[] b) {
|
||||||
|
List<Boolean> res = new ArrayList<>();
|
||||||
|
for(int i=0;i<b.length;i++){
|
||||||
|
boolean[] booleanArray = getBooleanArray(b[i], true);
|
||||||
|
for(int j=0;j<booleanArray.length;j++){
|
||||||
|
res.add(booleanArray[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean[] reverse(boolean[] b) {
|
||||||
|
boolean[] res = new boolean[8];
|
||||||
|
res[0] = b[7];
|
||||||
|
res[1] = b[6];
|
||||||
|
res[2] = b[5];
|
||||||
|
res[3] = b[4];
|
||||||
|
res[4] = b[3];
|
||||||
|
res[5] = b[2];
|
||||||
|
res[6] = b[1];
|
||||||
|
res[7] = b[0];
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//bool array to byte array
|
||||||
|
public static byte[] toByteArray(boolean[] b){
|
||||||
|
Integer byteLength = CommonFunctions.exactDivision(b.length, 8);
|
||||||
|
byte[] res = new byte[byteLength];
|
||||||
|
Queue<Boolean> queue = new LinkedList<Boolean>();
|
||||||
|
for(int i=0;i<b.length; i++){
|
||||||
|
queue.add(b[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo
|
||||||
|
int z = 0;
|
||||||
|
Integer boolLength = queue.size();
|
||||||
|
while (boolLength>0){
|
||||||
|
boolean[] input = new boolean[8];
|
||||||
|
|
||||||
|
if(boolLength>=8){
|
||||||
|
for(int i = 0;i<8;i++){
|
||||||
|
input[i]= queue.poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Byte aByte = fromBooleanArray(reverse(input));
|
||||||
|
res[z] = aByte;
|
||||||
|
z++;
|
||||||
|
}else {
|
||||||
|
for(int i=0;i<boolLength;i++){
|
||||||
|
input[i]= queue.poll();
|
||||||
|
}
|
||||||
|
Byte aByte = fromBooleanArray(reverse(input));
|
||||||
|
res[z] = aByte;
|
||||||
|
z++;
|
||||||
|
}
|
||||||
|
boolLength = boolLength-8;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// public st atic List<Boolean> toBoolArray(byte[] b) throws UnsupportedEncodingException {
|
||||||
|
// List<Boolean> res = new ArrayList<>();
|
||||||
|
// for(int i=0;i<b.length;i++){
|
||||||
|
// res.add(toBoolean(b[i]));
|
||||||
|
// }
|
||||||
|
// return res;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public static List<Byte> toByteArray(byte[] b) {
|
||||||
|
List<Byte> res = new ArrayList<>();
|
||||||
|
for(int i=0;i<b.length;i++){
|
||||||
|
res.add((b[i]));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<Character> toCharArray(byte[] b) {
|
||||||
|
List<Character> res = new ArrayList<>();
|
||||||
|
for(int i=0;i<b.length;i++){
|
||||||
|
res.add(toChar(b[i]));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
//toWord
|
||||||
|
/**
|
||||||
|
* 默认:word => 有符号的整形
|
||||||
|
* */
|
||||||
|
public static List<Integer> toWordArray(byte[] b) {
|
||||||
|
List<Integer> res = new ArrayList<>();
|
||||||
|
int i=0;
|
||||||
|
while ((i+2)<=b.length){
|
||||||
|
res.add(
|
||||||
|
toInt(b[i],b[i+1])
|
||||||
|
);
|
||||||
|
i+=2;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
//toDWord
|
||||||
|
/**
|
||||||
|
* 默认:dword => 有符号的整形
|
||||||
|
* */
|
||||||
|
public static List<Integer> toDWordArray(byte[] b) {
|
||||||
|
List<Integer> res = new ArrayList<>();
|
||||||
|
int i=0;
|
||||||
|
while ((i+4)<=b.length){
|
||||||
|
res.add(
|
||||||
|
toInt(b[i],b[i+1],b[i+2],b[i+3])
|
||||||
|
);
|
||||||
|
i+=4;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* 4个字节byte[] 转成有符号的Double
|
||||||
|
* 默认大端
|
||||||
|
* */
|
||||||
|
public static Float realbytesToFloat(byte[] bytes) {
|
||||||
|
|
||||||
|
return Float.intBitsToFloat(toInt(bytes[0],bytes[1],bytes[2],bytes[3]));
|
||||||
|
}
|
||||||
|
public static byte[] realToBytes(Float f) {
|
||||||
|
return invert(float2byte(f));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 浮点转换为字节
|
||||||
|
*
|
||||||
|
* @param f
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static byte[] float2byte(float f) {
|
||||||
|
|
||||||
|
// 把float转换为byte[]
|
||||||
|
int fbit = Float.floatToIntBits(f);
|
||||||
|
|
||||||
|
byte[] b = new byte[4];
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
b[i] = (byte) (fbit >> (24 - i * 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 翻转数组
|
||||||
|
int len = b.length;
|
||||||
|
// 建立一个与源数组元素类型相同的数组
|
||||||
|
byte[] dest = new byte[len];
|
||||||
|
// 为了防止修改源数组,将源数组拷贝一份副本
|
||||||
|
System.arraycopy(b, 0, dest, 0, len);
|
||||||
|
byte temp;
|
||||||
|
// 将顺位第i个与倒数第i个交换
|
||||||
|
for (int i = 0; i < len / 2; ++i) {
|
||||||
|
temp = dest[i];
|
||||||
|
dest[i] = dest[len - i - 1];
|
||||||
|
dest[len - i - 1] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//toUInt
|
||||||
|
/**
|
||||||
|
* USInt 无符号整形 1个字节 =》 Integer
|
||||||
|
* */
|
||||||
|
public static List<Integer> toUSIntArray(byte[] b) {
|
||||||
|
List<Integer> res = new ArrayList<>();
|
||||||
|
for(int i=0;i<b.length;i++){
|
||||||
|
res.add(toUInt(b[i]));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* UInt 无符号整形 2个字节 =》 Integer
|
||||||
|
* */
|
||||||
|
public static List<Integer> toUIntArray(byte[] b) {
|
||||||
|
List<Integer> res = new ArrayList<>();
|
||||||
|
int i=0;
|
||||||
|
while ((i+2)<=b.length){
|
||||||
|
res.add(
|
||||||
|
toUInt(b[i],b[i+1])
|
||||||
|
);
|
||||||
|
i+=2;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* UDInt 无符号整形 4个字节 =》 Long
|
||||||
|
* */
|
||||||
|
public static List<Long> toUDIntArray(byte[] b) {
|
||||||
|
List<Long> res = new ArrayList<>();
|
||||||
|
int i=0;
|
||||||
|
while ((i+4)<=b.length){
|
||||||
|
res.add(
|
||||||
|
toUInt(b[i],b[i+1],b[i+2],b[i+3])
|
||||||
|
);
|
||||||
|
i+=4;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SInt 无符号整形 1个字节 =》 Integer
|
||||||
|
* */
|
||||||
|
public static List<Integer> toSIntArray(byte[] b) {
|
||||||
|
List<Integer> res = new ArrayList<>();
|
||||||
|
for(int i=0;i<b.length;i++){
|
||||||
|
res.add(toInt(b[i]));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Int 无符号整形 2个字节 =》 Integer
|
||||||
|
* */
|
||||||
|
public static List<Integer> toIntArray(byte[] b) {
|
||||||
|
List<Integer> res = new ArrayList<>();
|
||||||
|
int i=0;
|
||||||
|
while ((i+2)<=b.length){
|
||||||
|
res.add(
|
||||||
|
toInt(b[i],b[i+1])
|
||||||
|
);
|
||||||
|
i+=2;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* DInt 无符号整形 4个字节 =》 Integer
|
||||||
|
* */
|
||||||
|
public static List<Integer> toDIntArray(byte[] b) {
|
||||||
|
List<Integer> res = new ArrayList<>();
|
||||||
|
int i=0;
|
||||||
|
while ((i+4)<=b.length){
|
||||||
|
res.add(
|
||||||
|
toInt(b[i],b[i+1],b[i+2],b[i+3])
|
||||||
|
);
|
||||||
|
i+=4;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sint(1个字节) =》 byte[]
|
||||||
|
* 默认大端模式
|
||||||
|
* */
|
||||||
|
public static byte[] sintToBytes(Integer i){
|
||||||
|
byte[] res = new byte[1];
|
||||||
|
res[0] = Byte.valueOf(i.toString());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* sintArray(1个字节) =》 byte[]
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
public static byte[] sintArrayToBytes(int[] sintArray) {
|
||||||
|
byte[] res = new byte[sintArray.length];
|
||||||
|
for(int i=0;i<sintArray.length;i++){
|
||||||
|
int i1 = sintArray[i];
|
||||||
|
res[i] = sintToBytes(i1)[0];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* int(2个字节) =》 byte[]
|
||||||
|
* 默认大端模式
|
||||||
|
* */
|
||||||
|
public static byte[] intToBytes(Integer i) {
|
||||||
|
Number shortNumber = Short.valueOf(i.toString());
|
||||||
|
return ByteUtil.numberToBytes(shortNumber,ByteOrder.BIG_ENDIAN);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* intArray(2个字节) =》 byte[]
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
public static byte[] intArrayToBytes(int[] intArray) {
|
||||||
|
byte[] res = new byte[intArray.length*2];
|
||||||
|
for(int i=0 ; i< intArray.length ; i++){
|
||||||
|
byte[] bytes = intToBytes(intArray[i]);
|
||||||
|
res[i*2] = bytes[0];
|
||||||
|
res[i*2+1] = bytes[1];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* int(2个字节) =》 byte[]
|
||||||
|
* 默认大端模式
|
||||||
|
* */
|
||||||
|
public static byte[] dintToBytes(Integer i) {
|
||||||
|
Number intNumber = i;
|
||||||
|
return ByteUtil.numberToBytes(intNumber,ByteOrder.BIG_ENDIAN);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* intArray(2个字节) =》 byte[]
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
public static byte[] dintArrayToBytes(int[] dintArray) {
|
||||||
|
byte[] res = new byte[dintArray.length*4];
|
||||||
|
for(int i=0 ; i< dintArray.length ; i++){
|
||||||
|
byte[] bytes = dintToBytes(dintArray[i]);
|
||||||
|
res[i*4] = bytes[0];
|
||||||
|
res[i*4+1] = bytes[1];
|
||||||
|
res[i*4+2] = bytes[2];
|
||||||
|
res[i*4+3] = bytes[3];
|
||||||
|
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sint(1个字节) =》 byte[]
|
||||||
|
* 默认大端模式
|
||||||
|
* */
|
||||||
|
public static byte[] usintToBytes(Integer i){
|
||||||
|
if(i<0){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
byte[] res = new byte[1];
|
||||||
|
res[0] = Byte.valueOf(i.toString());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* usintArrayToBytes =》 byte[]
|
||||||
|
* 默认大端模式
|
||||||
|
* */
|
||||||
|
public static byte[] usintArrayToBytes(int[] usintArray) {
|
||||||
|
byte[] res = new byte[usintArray.length];
|
||||||
|
for(int i=0 ; i< usintArray.length ; i++){
|
||||||
|
byte[] bytes = usintToBytes(usintArray[i]);
|
||||||
|
if(bytes == null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
res[i] = bytes[0];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* int(2个字节) =》 byte[]
|
||||||
|
* 默认大端模式
|
||||||
|
* */
|
||||||
|
public static byte[] uintToBytes(Integer i) {
|
||||||
|
if(i<0){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Number shortNumber = Short.valueOf(i.toString());
|
||||||
|
return ByteUtil.numberToBytes(shortNumber,ByteOrder.BIG_ENDIAN);
|
||||||
|
}
|
||||||
|
public static byte[] uintArrayToBytes(int[] uintArray) {
|
||||||
|
byte[] res = new byte[uintArray.length*2];
|
||||||
|
for(int i=0 ; i< uintArray.length ; i++){
|
||||||
|
byte[] bytes = uintToBytes(uintArray[i]);
|
||||||
|
if(bytes == null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
res[i*2] = bytes[0];
|
||||||
|
res[i*2+1] = bytes[1];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* int(2个字节) =》 byte[]
|
||||||
|
* 默认大端模式
|
||||||
|
* */
|
||||||
|
public static byte[] udintToBytes(Integer i) {
|
||||||
|
if(i<0){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Number intNumber = i;
|
||||||
|
return ByteUtil.numberToBytes(intNumber,ByteOrder.BIG_ENDIAN);
|
||||||
|
}
|
||||||
|
public static byte[] udintArrayToBytes(int[] udintArray) {
|
||||||
|
byte[] res = new byte[udintArray.length*4];
|
||||||
|
for(int i=0 ; i< udintArray.length ; i++){
|
||||||
|
byte[] bytes = udintToBytes(udintArray[i]);
|
||||||
|
if(bytes == null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
res[i*4] = bytes[0];
|
||||||
|
res[i*4+1] = bytes[1];
|
||||||
|
res[i*4+2] = bytes[2];
|
||||||
|
res[i*4+3] = bytes[3];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* boolean =》 byte[]
|
||||||
|
* 默认大端模式
|
||||||
|
* */
|
||||||
|
public static byte[] boolToBytes(Boolean bool) {
|
||||||
|
byte[] res = new byte[1];
|
||||||
|
if(bool){
|
||||||
|
res[0] = 1;
|
||||||
|
return res;
|
||||||
|
}else {
|
||||||
|
res[0] = 0;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* booleanArray =》 byte[]
|
||||||
|
* */
|
||||||
|
public static byte[] booleanArrayToBytes(boolean[] boolArray) {
|
||||||
|
byte[] res = new byte[boolArray.length];
|
||||||
|
for(int i=0 ; i<boolArray.length ; i++){
|
||||||
|
boolean b = boolArray[i];
|
||||||
|
if(b){
|
||||||
|
res[i] = 1;
|
||||||
|
}else {
|
||||||
|
res[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* charArray =》 byte[]
|
||||||
|
* */
|
||||||
|
public static byte[] charArrayToBytes(char[] charArray) {
|
||||||
|
byte[] res = new byte[charArray.length];
|
||||||
|
for(int i=0 ; i< charArray.length ; i++){
|
||||||
|
byte[] bytes = charToByte(charArray[i]);
|
||||||
|
if(bytes[0] != 0){
|
||||||
|
return null;
|
||||||
|
}else {
|
||||||
|
res[i] = bytes[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* byte =》 byte[]
|
||||||
|
* 默认大端模式
|
||||||
|
* */
|
||||||
|
public static byte[] setbytes(Byte bytes) {
|
||||||
|
byte[] res = new byte[1];
|
||||||
|
res[0] = bytes;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* word =》 byte[]
|
||||||
|
* 默认大端模式
|
||||||
|
* tip: 目前只支持 带符号的十进制 ==》 word(2个字节)
|
||||||
|
* */
|
||||||
|
public static byte[] wordToBytes(Short word) {
|
||||||
|
return ByteUtil.shortToBytes(word,ByteOrder.BIG_ENDIAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wordArray =》 byte[]
|
||||||
|
* */
|
||||||
|
public static byte[] wordArrayToBytes(short[] shortArray) {
|
||||||
|
byte[] res = new byte[shortArray.length*2];
|
||||||
|
for(int i=0 ; i< shortArray.length ; i++){
|
||||||
|
byte[] bytes = wordToBytes(shortArray[i]);
|
||||||
|
res[i*2] = bytes[0];
|
||||||
|
res[i*2+1] = bytes[1];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dword =》 byte[]
|
||||||
|
* 默认大端模式
|
||||||
|
* tip: 目前只支持 带符号的十进制 ==》 word(4个字节)
|
||||||
|
* */
|
||||||
|
public static byte[] dwordToBytes(Integer dword) {
|
||||||
|
return ByteUtil.intToBytes(dword,ByteOrder.BIG_ENDIAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dwordArray =》 byte[]
|
||||||
|
* */
|
||||||
|
public static byte[] dwordArrayToBytes(int[] intArray) {
|
||||||
|
byte[] res = new byte[intArray.length*4];
|
||||||
|
for(int i=0 ; i< intArray.length ; i++){
|
||||||
|
byte[] bytes = dwordToBytes(intArray[i]);
|
||||||
|
res[i*4] = bytes[0];
|
||||||
|
res[i*4+1] = bytes[1];
|
||||||
|
res[i*4+2] = bytes[2];
|
||||||
|
res[i*4+3] = bytes[3];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* char(1字节) =》 byte[]
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
public static byte[] charToBytes(Character c) {
|
||||||
|
return String.valueOf(c).getBytes();
|
||||||
|
}
|
||||||
|
public static byte[] wcharToBytes(Character c) {
|
||||||
|
return charToByte(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
//如果plc中没有设置 strSize,那么 这个字符串变量的 最大长度默认是 254(字节就是-2 )
|
||||||
|
/**
|
||||||
|
* 这个函数就用于 非str类型转bytes使用,string类型转bytes 用strToBytes(String s,Integer strSize) 这个方法。
|
||||||
|
* */
|
||||||
|
public static byte[] strToBytes(String s) {
|
||||||
|
byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
|
||||||
|
byte[] res = new byte[bytes.length+2];
|
||||||
|
res[0] = -2;
|
||||||
|
res[1] = Integer.valueOf(bytes.length).byteValue();
|
||||||
|
for(int i=0;i<bytes.length;i++){
|
||||||
|
res[i+2] = bytes[i];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* desc
|
||||||
|
* 入参:
|
||||||
|
* 一般来说 plc中 string变量都是会设置 长度的,如 var1 = String[18],这里的strSize就是18
|
||||||
|
* 返回:
|
||||||
|
* 返回的字节流是包含2个头字节的,也就是 strSize+2 个长度的字节流。
|
||||||
|
* */
|
||||||
|
public static byte[] strToBytes(String s,Integer strSize) {
|
||||||
|
if(s==null || (strSize<=0)){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Integer allStrSize = strSize+2;
|
||||||
|
byte[] bytes = s.getBytes(StandardCharsets.UTF_8);
|
||||||
|
byte[] res = new byte[allStrSize];
|
||||||
|
res[0] = strSize.byteValue();
|
||||||
|
if(bytes.length>strSize){
|
||||||
|
res[1] = strSize.byteValue();
|
||||||
|
for(int i=0;i<strSize;i++){
|
||||||
|
res[i+2] = bytes[i];
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
res[1] = Integer.valueOf(bytes.length).byteValue();
|
||||||
|
for(int i=0;i<bytes.length;i++){
|
||||||
|
res[i+2] = bytes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws UnsupportedEncodingException {
|
||||||
|
// //stringArray <=> bytes[]
|
||||||
|
// String[] src = new String[3];
|
||||||
|
// src[0]= "1";
|
||||||
|
// src[1]= "30110012105301117222";
|
||||||
|
// src[2]= "3";
|
||||||
|
// byte[] bytes = strArrayToBytes(src, 18);
|
||||||
|
// String[] strings = toStrArray(bytes, 3, 18);
|
||||||
|
// System.out.println(bytes);
|
||||||
|
//
|
||||||
|
// //string <=> bytes[]
|
||||||
|
// String s = "12323221";
|
||||||
|
// byte[] bytes1 = strToBytes(s, 18);
|
||||||
|
// String s1 = toStr(bytes1);
|
||||||
|
// System.out.println(s1);
|
||||||
|
|
||||||
|
boolean[] res = new boolean[22];
|
||||||
|
res[0] = false;
|
||||||
|
res[1] = true;
|
||||||
|
res[2] = false;
|
||||||
|
res[3] = true;
|
||||||
|
res[4] = false;
|
||||||
|
res[5] = true;
|
||||||
|
res[6] = false;
|
||||||
|
res[7] = false;
|
||||||
|
|
||||||
|
res[8] = false;
|
||||||
|
res[9] = true;
|
||||||
|
res[10] = false;
|
||||||
|
res[11] = false;
|
||||||
|
res[12] = true;
|
||||||
|
res[13] = false;
|
||||||
|
res[14] = true;
|
||||||
|
res[15] = false;
|
||||||
|
|
||||||
|
|
||||||
|
res[16] = true;
|
||||||
|
res[17] = false;
|
||||||
|
res[18] = false;
|
||||||
|
res[19] = false;
|
||||||
|
res[20] = true;
|
||||||
|
res[21] = false;
|
||||||
|
|
||||||
|
byte[] bytes = toByteArray(res);
|
||||||
|
|
||||||
|
Integer integer = CommonFunctions.exactDivision(7, 8);
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数
|
||||||
|
* desc : 把字符串数组 ==> byte[] [x,x,..,..,..,..,... x,x,..,..,..,..,... ...]
|
||||||
|
* array : 就是需要被写入plc的内容,, array.length 就是你要写入数组的长度。 注意array.length必须小于plc中设置的 “数组变量” length
|
||||||
|
* strSize : 就是数组中某个变量的长度 比如 String str = new String[18] 这里的18就是strSize,但是在博图偏移量地址上可以发现它已经把你+2了,就是你设置最大string长度18 但偏移量=18+2=20;;
|
||||||
|
* 而上面的array.length是 List<String> list = new ArrayList<>; 的list.length
|
||||||
|
* 返回
|
||||||
|
* byte[] 就是整个数组字符串的 总的字节流
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
public static byte[] strArrayToBytes(String[] array,Integer strSize) {
|
||||||
|
//str0 [18, 17, 51, 48, 49, 49, 48, 48, 49, 50, 49, 48, 53, 51, 48, 49, 49, 49, 53]
|
||||||
|
//str1 [18, 18, 51, 48, 49, 49, 48, 48, 49, 50, 49, 48, 53, 51, 48, 49, 49, 49, 53, 49]
|
||||||
|
//str2 [18, 18, 51, 48, 49, 49, 48, 48, 49, 50, 49, 48, 53, 51, 48, 49, 49, 49, 53, 50]
|
||||||
|
|
||||||
|
//list [18, 17, 51, 48, 49, 49, 48, 48, 49, 50, 49, 48, 53, 51, 48, 49, 49, 49, 53, 0, 18, 18, 51, 48, 49, 49, 48, 48, 49, 50, 49, 48, 53, 51, 48, 49, 49, 49, 53, 49, 18, 18, 51, 48, 49, 49, 48, 48, 49, 50, 49, 48, 53, 51, 48, 49, 49, 49, 53, 50]
|
||||||
|
//strSize+2 以后就是 实际plc 变量的字节数了。
|
||||||
|
Integer allStrSize = strSize+2;
|
||||||
|
byte[] res = new byte[array.length*allStrSize];
|
||||||
|
for(int i=0;i<array.length;i++){
|
||||||
|
byte[] bytes = strToBytes(array[i],strSize);
|
||||||
|
System.arraycopy(bytes,0,res,i*allStrSize,bytes.length);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//for private
|
||||||
|
|
||||||
|
private static byte[] charToByte(char c) {
|
||||||
|
byte[] b = new byte[2];
|
||||||
|
b[0] = (byte) ((c & 0xFF00) >> 8);
|
||||||
|
b[1] = (byte) (c & 0xFF);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
private static char byteToChar(byte[] b) {
|
||||||
|
char c = (char) (((b[0] & 0xFF) << 8) | (b[1] & 0xFF));
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
private static char byteToChar(byte b) {
|
||||||
|
char c = (char) (b & 0xFF);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.blocks;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.annotation.S7Variable;
|
||||||
|
import com.cnbm.s7.s7connector.impl.utils.S7Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PID Control block representation
|
||||||
|
*
|
||||||
|
* @author Thomas Rudin (thomas@rudin-informatik.ch)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class CONT_C {
|
||||||
|
|
||||||
|
@S7Variable(type = S7Type.BOOL, byteOffset = 0, bitOffset = 6)
|
||||||
|
public boolean D_SEL;
|
||||||
|
|
||||||
|
@S7Variable(type = S7Type.REAL, byteOffset = 20)
|
||||||
|
public double GAIN;
|
||||||
|
|
||||||
|
@S7Variable(type = S7Type.BOOL, byteOffset = 0, bitOffset = 3)
|
||||||
|
public boolean I_SEL;
|
||||||
|
|
||||||
|
@S7Variable(type = S7Type.REAL, byteOffset = 72)
|
||||||
|
public double LMN;
|
||||||
|
|
||||||
|
@S7Variable(type = S7Type.BOOL, byteOffset = 0, bitOffset = 0)
|
||||||
|
public boolean MAN_ON;
|
||||||
|
|
||||||
|
@S7Variable(type = S7Type.BOOL, byteOffset = 0, bitOffset = 2)
|
||||||
|
public boolean P_SEL;
|
||||||
|
|
||||||
|
@S7Variable(type = S7Type.REAL, byteOffset = 10)
|
||||||
|
public double PV_IN;
|
||||||
|
|
||||||
|
@S7Variable(type = S7Type.REAL, byteOffset = 6)
|
||||||
|
public double SP_INT;
|
||||||
|
|
||||||
|
@S7Variable(type = S7Type.TIME, byteOffset = 24)
|
||||||
|
public long TN;
|
||||||
|
|
||||||
|
@S7Variable(type = S7Type.TIME, byteOffset = 28)
|
||||||
|
public long TV;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "CONT_C [MAN_ON=" + this.MAN_ON + ", P_SEL=" + this.P_SEL + ", I_SEL=" + this.I_SEL + ", D_SEL="
|
||||||
|
+ this.D_SEL + ", SP_INT=" + this.SP_INT + ", PV_IN=" + this.PV_IN + ", GAIN=" + this.GAIN + ", TN="
|
||||||
|
+ this.TN + ", TV=" + this.TV + ", LMN=" + this.LMN + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
package com.cnbm.s7.s7connector.enmuc;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.DaveArea;
|
||||||
|
import com.cnbm.s7.s7connector.type.PlcVar;
|
||||||
|
|
||||||
|
//实际 Plc中的变量。。。 要实现录入到这个枚举类中。。。 为后续做准备。
|
||||||
|
//注意:
|
||||||
|
// ① 单体变量 length 都是1
|
||||||
|
// ② 数组变量 length 就是 你要read 或者write数组的长度
|
||||||
|
// ③ bitOffset 是针对Bool 来说的,其他变量bitOffset 都是0
|
||||||
|
// ④ strSize 这个字段只是给 String变量 和 String[]变量 用的, 这个字段是plc中设置的最大String长度
|
||||||
|
// ⑤ String类型 在write的时候禁止 write中文,因为plc中编码并没有采用UTF-8 而是采用ASCII
|
||||||
|
// (同理也是,当plc中有设置String类型或者StringArray那么告诉他们必须指定长度 通常他们也会指定长度的。)
|
||||||
|
public enum PlcVarActual {
|
||||||
|
//心跳变量(这个可以要求电控同事加一个,不和业务关联,只用于通讯)
|
||||||
|
HeartBeat("HeartBeat",PlcVar.BOOL,1,DaveArea.DB,3,3267,5),
|
||||||
|
HeartBeatFor1200("HeartBeatFor1200",PlcVar.BOOL,1,DaveArea.DB,1,0,0),
|
||||||
|
|
||||||
|
//单体变量
|
||||||
|
DB54("DB54",PlcVar.BYTE,1,DaveArea.DB,3,3268,0),
|
||||||
|
DTL("DTL",PlcVar.DTL,1,DaveArea.DB,3,44,0),
|
||||||
|
STRING1("STRING",PlcVar.STRING,1,DaveArea.DB,3,62,0,20),
|
||||||
|
SUBID0("SUBID0",PlcVar.STRING,1,DaveArea.DB,3,3270,0),
|
||||||
|
INT1200("INT1200",PlcVar.INT,1,DaveArea.DB,1,2,0),
|
||||||
|
|
||||||
|
//数组变量
|
||||||
|
CharArrays("CharArrays",PlcVar.CHAR_Array,2,DaveArea.DB,3,834,0),
|
||||||
|
BooleanArrays("BooleanArrays",PlcVar.BOOL_Array,2,DaveArea.DB,3,830,0),
|
||||||
|
|
||||||
|
BooleanArrays16("BooleanArrays16",PlcVar.BOOL_Array,16,DaveArea.DB,3,3268,0),
|
||||||
|
BooleanArrays8("BooleanArrays8",PlcVar.BOOL_Array,1,DaveArea.DB,3,3262,0),
|
||||||
|
|
||||||
|
|
||||||
|
SubIdArrays("SubIdArrays",PlcVar.STRING_Array,60,DaveArea.DB,3,3268,0,18),
|
||||||
|
SubIdArrays1200("SubIdArrays1200",PlcVar.STRING_Array,60,DaveArea.DB,1,20,0,18),
|
||||||
|
|
||||||
|
|
||||||
|
BooleanArrays1200("BooleanArrays1200",PlcVar.BOOL_Array,15,DaveArea.DB,3,3264,0)
|
||||||
|
|
||||||
|
;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private DaveArea area;
|
||||||
|
private Integer areaNumber;
|
||||||
|
private Integer byteOffset;
|
||||||
|
private Integer bitOffset;
|
||||||
|
private PlcVar type;
|
||||||
|
//length = 1代表 非数组;;; length > 1 代表数组 ;; 注意 length这个参数 是实际plc中 数组的长度,和read操作相关
|
||||||
|
//如果是String 类型不用填length 只需要填string类型的起始位置就行了,我会自己去取数据长度(也就是说这里的length并不是string 的长度)。
|
||||||
|
private Integer length;
|
||||||
|
|
||||||
|
//这个字段只是给 字符串变量 和 字符串数组 用, 这个字段是plc中设置的最大String长度
|
||||||
|
private Integer strSize;
|
||||||
|
|
||||||
|
PlcVarActual(String name, PlcVar type,Integer length, DaveArea area, Integer areaNumber, Integer byteOffset, Integer bitOffset){
|
||||||
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
this.length = length;
|
||||||
|
this.area = area;
|
||||||
|
this.areaNumber = areaNumber;
|
||||||
|
this.byteOffset = byteOffset;
|
||||||
|
this.bitOffset = bitOffset;
|
||||||
|
this.strSize = 0;
|
||||||
|
}
|
||||||
|
PlcVarActual(String name, PlcVar type,Integer length, DaveArea area, Integer areaNumber, Integer byteOffset, Integer bitOffset,Integer strSize){
|
||||||
|
this.name = name;
|
||||||
|
this.type = type;
|
||||||
|
this.length = length;
|
||||||
|
this.area = area;
|
||||||
|
this.areaNumber = areaNumber;
|
||||||
|
this.byteOffset = byteOffset;
|
||||||
|
this.bitOffset = bitOffset;
|
||||||
|
this.strSize = strSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getStrSize() {
|
||||||
|
return strSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStrSize(Integer strSize) {
|
||||||
|
this.strSize = strSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DaveArea getArea() {
|
||||||
|
return area;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getAreaNumber() {
|
||||||
|
return areaNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getBitOffset() {
|
||||||
|
return bitOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getByteOffset() {
|
||||||
|
return byteOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlcVar getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getLength() {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
}
|
400
ym-s7/src/main/java/com/cnbm/s7/s7connector/enmuc/S7Client.java
Normal file
400
ym-s7/src/main/java/com/cnbm/s7/s7connector/enmuc/S7Client.java
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
package com.cnbm.s7.s7connector.enmuc;
|
||||||
|
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.DaveArea;
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Connector;
|
||||||
|
import com.cnbm.s7.s7connector.api.factory.S7ConnectorFactory;
|
||||||
|
import com.cnbm.s7.s7connector.api.utils.ByteUtils;
|
||||||
|
import com.cnbm.s7.s7connector.exception.S7CheckResultException;
|
||||||
|
import com.cnbm.s7.s7connector.exception.S7Exception;
|
||||||
|
import com.cnbm.s7.s7connector.type.PlcVar;
|
||||||
|
import com.cnbm.s7.s7connector.utils.CommonFunctions;
|
||||||
|
import com.cnbm.s7.retry.S7RetryTemplate;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Desc: ""
|
||||||
|
* @Author: caixiang
|
||||||
|
* @DATE: 2022/1/15 13:01
|
||||||
|
*/
|
||||||
|
public enum S7Client {
|
||||||
|
//TODO 步骤1 这里是配置多PLC 的,,,有多个plc 就在这里配置一个枚举类
|
||||||
|
//1500 西门子200smart、1200、1500默认的 机架号=0 槽位号=1; 300/400 默认的 机架-0 插槽-2
|
||||||
|
// S7_1200("192.168.0.52",0,1,1,PlcVarActual.HeartBeatFor1200),
|
||||||
|
S7_15001("192.168.0.51",0,1,1),
|
||||||
|
S7_1500("192.168.0.51",0,1,1),
|
||||||
|
//1500 机架-0 插槽-1
|
||||||
|
//后续 在这里扩展 多PLC应用。
|
||||||
|
;
|
||||||
|
private String host;
|
||||||
|
//默认 0 机架号
|
||||||
|
private Integer rack;
|
||||||
|
//默认 0
|
||||||
|
private Integer slot;
|
||||||
|
|
||||||
|
//心跳变量,如果plc没有让电控的人加一个,这个是必填的
|
||||||
|
private PlcVarActual heartBeat;
|
||||||
|
|
||||||
|
private List<S7Connector> connections;
|
||||||
|
//coreSize 是线程池的大小
|
||||||
|
private Integer coreSize;
|
||||||
|
//pickOne 就是一个初始化 的轮询取余值
|
||||||
|
private int pickOne;
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(S7Client.class);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//coreSize 是线程池的数量
|
||||||
|
S7Client(String host, Integer rack, Integer slot, Integer coreSize){
|
||||||
|
this.host = host;
|
||||||
|
this.rack = rack;
|
||||||
|
this.slot = slot;
|
||||||
|
this.pickOne = 0;
|
||||||
|
|
||||||
|
this.coreSize = coreSize;
|
||||||
|
|
||||||
|
connections = new ArrayList<>();
|
||||||
|
connectionPool();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHost(){
|
||||||
|
return this.host;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PlcVar(byte[]) 转 java对象 对照表
|
||||||
|
* 单体变量
|
||||||
|
* Bool ===> Boolean
|
||||||
|
* LREAL ===> Double
|
||||||
|
* REAL ===> Float
|
||||||
|
* DATE ===> String(yyyy-MM-dd 这种形式的类型)
|
||||||
|
* DTL ===> String("年-月-日-工作日-时-分-秒" 这种格式)
|
||||||
|
* TIME ===> Integer(单位 ms)
|
||||||
|
* USINT ===> Integer
|
||||||
|
* SINT ===> Integer
|
||||||
|
* UINT ===> Integer
|
||||||
|
* INT ===> Integer
|
||||||
|
* DINT ===> Integer
|
||||||
|
* UINT ===> Long
|
||||||
|
* Byte ===> Integer(有符号)(默认)
|
||||||
|
* Integer(无符号)(后续扩展)
|
||||||
|
* Char ===> Character
|
||||||
|
* WChar ===> Character
|
||||||
|
* String ===> String (特殊)
|
||||||
|
|
||||||
|
|
||||||
|
* 数组变量
|
||||||
|
* BoolArray ===> List<Boolean>
|
||||||
|
* ByteArray ===> List<Byte>
|
||||||
|
* WordArray ===> List<Integer>
|
||||||
|
* DWordArray ===> List<Integer>
|
||||||
|
* CharArray ===> List<Character>
|
||||||
|
* SIntArray ===> List<Integer>
|
||||||
|
* IntArray ===> List<Integer>
|
||||||
|
* DIntArray ===> List<Integer>
|
||||||
|
* UIntArray ===> List<Integer>
|
||||||
|
* USIntArray ===> List<Integer>
|
||||||
|
* UDIntArray ===> List<Long>
|
||||||
|
* StringArray ===> String[] (特殊)
|
||||||
|
*
|
||||||
|
* 如果返回null,就代表出现了异常,并且尝试了 retryMax 次数,并且尝试重置连接
|
||||||
|
* */
|
||||||
|
public Object read(DaveArea area, Integer areaNumber, Integer byteOffset, Integer bitOffset, Integer length, Integer strSizes, PlcVar type) {
|
||||||
|
S7Connector connector = getConnector();
|
||||||
|
if(connector == null){
|
||||||
|
logger.info("read No connector found , 现在connections pool为空,并且创建connection失败 ");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return S7RetryTemplate.getInstance().execute(
|
||||||
|
context -> {
|
||||||
|
|
||||||
|
try {
|
||||||
|
//String 类型比较特殊。 String[] 也是同理,Sring数组里面的子项 也是有两个字节的 readBytes。
|
||||||
|
if(type.equals(PlcVar.STRING)){
|
||||||
|
Integer readBytes = 2;
|
||||||
|
byte[] read = connector.read(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
readBytes,
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
type.getTransportSize()
|
||||||
|
);
|
||||||
|
|
||||||
|
Integer allLength = Integer.valueOf(read[1])+2;
|
||||||
|
byte[] readF = connector.read(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
allLength,
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
type.getTransportSize()
|
||||||
|
);
|
||||||
|
return type.toObject(readF);
|
||||||
|
}else if(type.equals(PlcVar.BOOL_Array)){
|
||||||
|
byte[] read = connector.read(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
CommonFunctions.exactDivision(length,8),
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
type.getTransportSize()
|
||||||
|
);
|
||||||
|
List<Boolean> booleans = ByteUtils.toBoolArray(read);
|
||||||
|
List<Boolean> res = new ArrayList<Boolean>();
|
||||||
|
for(int i=0;i<length;i++){
|
||||||
|
res.add(i,booleans.get(i));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}else if(type.equals(PlcVar.STRING_Array)){
|
||||||
|
Integer arrayLength = length;
|
||||||
|
Integer strSize = strSizes;
|
||||||
|
|
||||||
|
byte[] read = connector.read(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
arrayLength*(strSize+2),
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
type.getTransportSize()
|
||||||
|
);
|
||||||
|
return ByteUtils.toStrArray(read, arrayLength, strSize);
|
||||||
|
}else {
|
||||||
|
Integer readBytes = type.getTransportSize().getSizeInBytes() * length;
|
||||||
|
byte[] read = connector.read(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
readBytes,
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
type.getTransportSize()
|
||||||
|
);
|
||||||
|
return type.toObject(read);
|
||||||
|
}
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new S7CheckResultException("read errMsg : "+e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
context -> {
|
||||||
|
logger.info("S7-Retry : 已达到最大重试次数: "+S7RetryTemplate.getMaxRetryTimes()+", 现在尝试重新连接;");
|
||||||
|
if(replaceConnector(connector)==1){
|
||||||
|
logger.info("S7-Retry-Read 现在恢复成功,创建新connection成功");
|
||||||
|
return null;
|
||||||
|
}else {
|
||||||
|
logger.info("S7-Retry-Read 现在恢复失败,创建新connection失败");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* eg :
|
||||||
|
* Object newValue = Boolean.FALSE
|
||||||
|
* s7Service.write(PlcVarActual.HeartBeat, newValue, S7Client.S7_1200);
|
||||||
|
*
|
||||||
|
* PlcVar(byte[]) 转 java对象 对照表
|
||||||
|
* 单体变量
|
||||||
|
* Bool ===> Object newValue = Boolean.FALSE
|
||||||
|
* LREAL ===> Object newValue = Boolean.FALSE
|
||||||
|
* REAL ===> Object newValue = Boolean.FALSE
|
||||||
|
* DATE ===> 暂时没需求(有问题找我)
|
||||||
|
* DTL ===> 暂时没需求(有问题找我)
|
||||||
|
* TIME ===> 暂时没需求(有问题找我)
|
||||||
|
* USINT ===> Object newValue = new Integer(1)
|
||||||
|
* SINT ===> Object newValue = new Integer(1)
|
||||||
|
* UINT ===> Object newValue = new Integer(1)
|
||||||
|
* INT ===> Object newValue = new Integer(1)
|
||||||
|
* DINT ===> Object newValue = new Integer(1)
|
||||||
|
* UINT ===> Object newValue = new Integer(1)
|
||||||
|
* Byte ===> Object newValue = 0x11
|
||||||
|
*
|
||||||
|
* Char ===> Object newValue = 'a'
|
||||||
|
* WChar ===> Object newValue = '菜'
|
||||||
|
* String ===> Object newValue = '你好啊' (特殊)
|
||||||
|
|
||||||
|
|
||||||
|
* 数组变量
|
||||||
|
* 注意:在write的时候,你write的数量 一定要和 plc中存在的数量一一对应
|
||||||
|
* BoolArray ===> boolean[] booleanArray = new boolean[2]; .... 赋予值
|
||||||
|
* ByteArray ===> byte[] write_byteArrays = new byte[2];
|
||||||
|
* WordArray ===> short[] shortArrays_content = new short[2];
|
||||||
|
* DWordArray ===> int[] intArrays_content = new int[2];
|
||||||
|
* CharArray ===> char[] charArrays_content = new char[2];
|
||||||
|
* SIntArray ===> int[] sintArrays_content = new int[2];
|
||||||
|
* IntArray ===> int[] iintArrays_content = new int[2];
|
||||||
|
* DIntArray ===> int[] dintArrays_content = new int[2];
|
||||||
|
* UIntArray ===> int[] uintArrays_content = new int[3];
|
||||||
|
* USIntArray ===> int[] usintArrays_content = new int[3];
|
||||||
|
* UDIntArray ===> int[] udintArrays_content = new int[3];
|
||||||
|
* StringArray ===> String[] stringArrays_content = new String[3];
|
||||||
|
* //如果有其他数据类型 这里没有找我扩展
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
public void write(DaveArea area, Integer areaNumber, Integer byteOffset, Integer bitOffset,Integer strSize, PlcVar type, Object newValue) {
|
||||||
|
S7Connector connector = getConnector();
|
||||||
|
if(connector == null){
|
||||||
|
logger.info("write No connector found , 现在connections pool为空,并且创建connection失败 ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
S7RetryTemplate.getInstance().execute(
|
||||||
|
context -> {
|
||||||
|
try {
|
||||||
|
//String 类型比较特殊。 String[] 也是同理,Sring数组里面的子项 也是有两个字节的 readBytes。
|
||||||
|
if(type.equals(PlcVar.STRING)){
|
||||||
|
connector.write(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
ByteUtils.strToBytes(newValue.toString(), strSize),
|
||||||
|
type
|
||||||
|
);
|
||||||
|
}else if(type.equals(PlcVar.BOOL_Array)){
|
||||||
|
connector.write(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
ByteUtils.toByteArray((boolean[])newValue),
|
||||||
|
type
|
||||||
|
);
|
||||||
|
}else if(type.equals(PlcVar.STRING_Array)){
|
||||||
|
//todo here 检查 read write service
|
||||||
|
connector.write(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
ByteUtils.strArrayToBytes((String[])newValue, strSize),
|
||||||
|
type
|
||||||
|
);
|
||||||
|
}else {
|
||||||
|
byte[] bytes = type.toBytes(newValue);
|
||||||
|
connector.write(
|
||||||
|
area,
|
||||||
|
areaNumber,
|
||||||
|
byteOffset,
|
||||||
|
bitOffset,
|
||||||
|
bytes,
|
||||||
|
type
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}catch (Exception e) {
|
||||||
|
throw new S7CheckResultException("write errMsg : "+e.getMessage());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
context -> {
|
||||||
|
logger.info("S7-Retry-Write : 已达到最大重试次数: "+S7RetryTemplate.getMaxRetryTimes()+", 现在尝试重新连接");
|
||||||
|
if( replaceConnector(connector) == 1 ){
|
||||||
|
logger.info("S7-Retry-Write 现在恢复成功,创建新connection成功");
|
||||||
|
return null;
|
||||||
|
}else {
|
||||||
|
logger.info("S7-Retry-Write 现在恢复失败,创建新connection失败");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// public void retry1() throws InterruptedException {
|
||||||
|
// S7RetryTemplate instance = S7RetryTemplate.getInstance();
|
||||||
|
// System.out.println(instance.hashCode()+ ", "+Thread.currentThread().getName());
|
||||||
|
// instance.execute(
|
||||||
|
// retryContext -> {
|
||||||
|
// System.out.println("retry1 : " + Thread.currentThread().getName() );
|
||||||
|
// Thread.sleep(10000);
|
||||||
|
// System.out.println("retry1 sleepdown : " + Thread.currentThread().getName() );
|
||||||
|
// return true;
|
||||||
|
// },
|
||||||
|
// retryContext -> {
|
||||||
|
// System.out.println("retry1 err: " + Thread.currentThread().getName() );
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* desc: 传入的connection 是需要被替换的
|
||||||
|
* return:
|
||||||
|
* 1 代表替换成功
|
||||||
|
* -1 代表替换失败(创建connection失败,原因:出现异常.原来的connection也被舍弃掉了)
|
||||||
|
* */
|
||||||
|
private synchronized Integer replaceConnector(S7Connector oldOne){
|
||||||
|
connections.remove(oldOne);
|
||||||
|
|
||||||
|
S7Connector connect = connect(host, rack, slot);
|
||||||
|
if(connect == null){
|
||||||
|
return -1;
|
||||||
|
}else {
|
||||||
|
connections.add(connect);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//虽然是枚举类,但这个是对象锁(不是类锁)
|
||||||
|
public synchronized S7Connector getConnector() {
|
||||||
|
int size = connections.size();
|
||||||
|
if(size == 0){
|
||||||
|
S7Connector connect = connect(host, rack, slot);
|
||||||
|
if(connect == null){
|
||||||
|
return null;
|
||||||
|
}else {
|
||||||
|
connections.add(connect);
|
||||||
|
return connect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
S7Connector s7Connector = connections.get((pickOne + size) % size);
|
||||||
|
pickOne+=1;
|
||||||
|
pickOne = (pickOne)%size;
|
||||||
|
return s7Connector;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private synchronized S7Connector connect(String host,Integer rack,Integer slot ){
|
||||||
|
try {
|
||||||
|
S7Connector connector = S7ConnectorFactory
|
||||||
|
.buildTCPConnector()
|
||||||
|
.withHost(host)
|
||||||
|
.withRack(rack) //optional rack 是机架号
|
||||||
|
.withSlot(slot) //optional slot 是插槽号
|
||||||
|
.build();
|
||||||
|
return connector;
|
||||||
|
}catch (S7Exception e){
|
||||||
|
logger.info("创建S7Connector 连接失败,原因:"+e.getMessage());
|
||||||
|
// throw new S7CheckResultException("errMsg : "+e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetConnetctions(){
|
||||||
|
this.connections = new ArrayList<S7Connector>();
|
||||||
|
connectionPool();
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void connectionPool(){
|
||||||
|
for(int i=0;i<coreSize;i++){
|
||||||
|
S7Connector connect = connect(host, rack, slot);
|
||||||
|
if(connect!=null){
|
||||||
|
connections.add(connect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//todo 在plc上新增一个 变量来解决 心跳问题 okok
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,272 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.enmuc;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author cgarcia
|
||||||
|
*/
|
||||||
|
public enum S7ParamErrorCode {
|
||||||
|
|
||||||
|
ERROR_0x0000((short) 0x0000, "No error"),
|
||||||
|
ERROR_0x0110((short) 0x0110, "Invalid block number"),
|
||||||
|
ERROR_0x0111((short) 0x0111, "Invalid request length"),
|
||||||
|
ERROR_0x0112((short) 0x0112, "Invalid parameter"),
|
||||||
|
ERROR_0x0113((short) 0x0113, "Invalid block type"),
|
||||||
|
ERROR_0x0114((short) 0x0114, "Block not found"),
|
||||||
|
ERROR_0x0115((short) 0x0115, "Block already exists"),
|
||||||
|
ERROR_0x0116((short) 0x0116, "Block is write-protected"),
|
||||||
|
ERROR_0x0117((short) 0x0117, "The block/operating system update is too large"),
|
||||||
|
ERROR_0x0118((short) 0x0118, "Invalid block number"),
|
||||||
|
ERROR_0x0119((short) 0x0119, "Incorrect password entered"),
|
||||||
|
ERROR_0x011A((short) 0x011A, "PG resource error"),
|
||||||
|
ERROR_0x011B((short) 0x011B, "PLC resource error"),
|
||||||
|
ERROR_0x011C((short) 0x011C, "Protocol error"),
|
||||||
|
ERROR_0x011D((short) 0x011D, "Too many blocks (module-related restriction)"),
|
||||||
|
ERROR_0x011E((short) 0x011E, "There is no longer a connection to the database, or S7DOS handle is invalid"),
|
||||||
|
ERROR_0x011F((short) 0x011F, "Result buffer too small"),
|
||||||
|
ERROR_0x0120((short) 0x0120, "End of block list"),
|
||||||
|
ERROR_0x0140((short) 0x0140, "Insufficient memory available"),
|
||||||
|
ERROR_0x0141((short) 0x0141, "Job cannot be processed because of a lack of resources"),
|
||||||
|
ERROR_0x8001((short) 0x8001, "The requested service cannot be performed while the block is in the current status"),
|
||||||
|
ERROR_0x8003((short) 0x8003, "S7 protocol error: Error occurred while transferring the block"),
|
||||||
|
ERROR_0x8100((short) 0x8100, "Application, general error: Service unknown to remote module"),
|
||||||
|
ERROR_0x8104((short) 0x8104, "This service is not implemented on the module or a frame error was reported"),
|
||||||
|
ERROR_0x8204((short) 0x8204, "The type specification for the object is inconsistent"),
|
||||||
|
ERROR_0x8205((short) 0x8205, "A copied block already exists and is not linked"),
|
||||||
|
ERROR_0x8301((short) 0x8301, "Insufficient memory space or work memory on the module, or specified storage medium not accessible"),
|
||||||
|
ERROR_0x8302((short) 0x8302, "Too few resources available or the processor resources are not available"),
|
||||||
|
ERROR_0x8304((short) 0x8304, "No further parallel upload possible. There is a resource bottleneck"),
|
||||||
|
ERROR_0x8305((short) 0x8305, "Function not available"),
|
||||||
|
ERROR_0x8306((short) 0x8306, "Insufficient work memory (for copying, linking, loading AWP)"),
|
||||||
|
ERROR_0x8307((short) 0x8307, "Not enough retentive work memory (for copying, linking, loading AWP)"),
|
||||||
|
ERROR_0x8401((short) 0x8401, "S7 protocol error: Invalid service sequence (for example, loading or uploading a block)"),
|
||||||
|
ERROR_0x8402((short) 0x8402, "Service cannot execute owing to status of the addressed object"),
|
||||||
|
ERROR_0x8404((short) 0x8404, "S7 protocol: The function cannot be performed"),
|
||||||
|
ERROR_0x8405((short) 0x8405, "Remote block is in DISABLE state (CFB). The function cannot be performed"),
|
||||||
|
ERROR_0x8500((short) 0x8500, "S7 protocol error: Wrong frames"),
|
||||||
|
ERROR_0x8503((short) 0x8503, "Alarm from the module: Service canceled prematurely"),
|
||||||
|
ERROR_0x8701((short) 0x8701, "Error addressing the object on the communications partner (for example, area length error)"),
|
||||||
|
ERROR_0x8702((short) 0x8702, "The requested service is not supported by the module"),
|
||||||
|
ERROR_0x8703((short) 0x8703, "Access to object refused"),
|
||||||
|
ERROR_0x8704((short) 0x8704, "Access error: Object damaged"),
|
||||||
|
ERROR_0xD001((short) 0xD001, "Protocol error: Illegal job number"),
|
||||||
|
ERROR_0xD002((short) 0xD002, "Parameter error: Illegal job variant"),
|
||||||
|
ERROR_0xD003((short) 0xD003, "Parameter error: Debugging function not supported by module"),
|
||||||
|
ERROR_0xD004((short) 0xD004, "Parameter error: Illegal job status"),
|
||||||
|
ERROR_0xD005((short) 0xD005, "Parameter error: Illegal job termination"),
|
||||||
|
ERROR_0xD006((short) 0xD006, "Parameter error: Illegal link disconnection ID"),
|
||||||
|
ERROR_0xD007((short) 0xD007, "Parameter error: Illegal number of buffer elements"),
|
||||||
|
ERROR_0xD008((short) 0xD008, "Parameter error: Illegal scan rate"),
|
||||||
|
ERROR_0xD009((short) 0xD009, "Parameter error: Illegal number of executions"),
|
||||||
|
ERROR_0xD00A((short) 0xD00A, "Parameter error: Illegal trigger event"),
|
||||||
|
ERROR_0xD00B((short) 0xD00B, "Parameter error: Illegal trigger condition"),
|
||||||
|
ERROR_0xD011((short) 0xD011, "Parameter error in path of the call environment: Block does not exist"),
|
||||||
|
ERROR_0xD012((short) 0xD012, "Parameter error: Wrong address in block"),
|
||||||
|
ERROR_0xD014((short) 0xD014, "Parameter error: Block being deleted/overwritten"),
|
||||||
|
ERROR_0xD015((short) 0xD015, "Parameter error: Illegal tag address"),
|
||||||
|
ERROR_0xD017((short) 0xD017, "Parameter error: Illegal trigger number"),
|
||||||
|
ERROR_0xD025((short) 0xD025, "Parameter error: Invalid path"),
|
||||||
|
ERROR_0xD026((short) 0xD026, "Parameter error: Illegal access type"),
|
||||||
|
ERROR_0xD027((short) 0xD027, "Parameter error: This number of data blocks is not permitted"),
|
||||||
|
ERROR_0xD031((short) 0xD031, "Internal protocol error"),
|
||||||
|
ERROR_0xD032((short) 0xD032, "Parameter error: Wrong result buffer length"),
|
||||||
|
ERROR_0xD033((short) 0xD033, "Protocol error: Wrong job length"),
|
||||||
|
ERROR_0xD03F((short) 0xD03F, "Coding error: Error in parameter section (for example, reserve bytes not equal to 0)"),
|
||||||
|
ERROR_0xD041((short) 0xD041, "Data error: Illegal status list ID"),
|
||||||
|
ERROR_0xD042((short) 0xD042, "Data error: Illegal tag address"),
|
||||||
|
ERROR_0xD043((short) 0xD043, "Data error: Referenced job not found, check job data"),
|
||||||
|
ERROR_0xD044((short) 0xD044, "Data error: Illegal tag value, check job data"),
|
||||||
|
ERROR_0xD045((short) 0xD045, "Data error: Exiting the ODIS control is not allowed in HOLD"),
|
||||||
|
ERROR_0xD046((short) 0xD046, "Data error: Illegal measuring stage during run-time measurement"),
|
||||||
|
ERROR_0xD047((short) 0xD047, "Data error: Illegal hierarchy in 'Read job list'"),
|
||||||
|
ERROR_0xD048((short) 0xD048, "Data error: Illegal deletion ID in 'Delete job'"),
|
||||||
|
ERROR_0xD049((short) 0xD049, "Invalid substitute ID in 'Replace job'"),
|
||||||
|
ERROR_0xD04A((short) 0xD04A, "Error executing 'program status'"),
|
||||||
|
ERROR_0xD05F((short) 0xD05F, "Coding error: Error in data section (for example, reserve bytes not equal to 0, ...)"),
|
||||||
|
ERROR_0xD061((short) 0xD061, "Resource error: No memory space for job"),
|
||||||
|
ERROR_0xD062((short) 0xD062, "Resource error: Job list full"),
|
||||||
|
ERROR_0xD063((short) 0xD063, "Resource error: Trigger event occupied"),
|
||||||
|
ERROR_0xD064((short) 0xD064, "Resource error: Not enough memory space for one result buffer element"),
|
||||||
|
ERROR_0xD065((short) 0xD065, "Resource error: Not enough memory space for several result buffer elements"),
|
||||||
|
ERROR_0xD066((short) 0xD066, "Resource error: The timer available for run-time measurement is occupied by another job"),
|
||||||
|
ERROR_0xD067((short) 0xD067, "Resource error: Too many 'modify tag' jobs active (in particular multi-processor operation)"),
|
||||||
|
ERROR_0xD081((short) 0xD081, "Function not permitted in current mode"),
|
||||||
|
ERROR_0xD082((short) 0xD082, "Mode error: Cannot exit HOLD mode"),
|
||||||
|
ERROR_0xD0A1((short) 0xD0A1, "Function not permitted in current protection level"),
|
||||||
|
ERROR_0xD0A2((short) 0xD0A2, "Function not possible at present, because a function is running that modifies memory"),
|
||||||
|
ERROR_0xD0A3((short) 0xD0A3, "Too many 'modify tag' jobs active on the I/O (in particular multi-processor operation)"),
|
||||||
|
ERROR_0xD0A4((short) 0xD0A4, "Forcing' has already been established"),
|
||||||
|
ERROR_0xD0A5((short) 0xD0A5, "Referenced job not found"),
|
||||||
|
ERROR_0xD0A6((short) 0xD0A6, "Job cannot be disabled/enabled"),
|
||||||
|
ERROR_0xD0A7((short) 0xD0A7, "Job cannot be deleted, for example because it is currently being read"),
|
||||||
|
ERROR_0xD0A8((short) 0xD0A8, "Job cannot be replaced, for example because it is currently being read or deleted"),
|
||||||
|
ERROR_0xD0A9((short) 0xD0A9, "Job cannot be read, for example because it is currently being deleted"),
|
||||||
|
ERROR_0xD0AA((short) 0xD0AA, "Time limit exceeded in processing operation"),
|
||||||
|
ERROR_0xD0AB((short) 0xD0AB, "Invalid job parameters in process operation"),
|
||||||
|
ERROR_0xD0AC((short) 0xD0AC, "Invalid job data in process operation"),
|
||||||
|
ERROR_0xD0AD((short) 0xD0AD, "Operating mode already set"),
|
||||||
|
ERROR_0xD0AE((short) 0xD0AE, "The job was set up over a different connection and can only be handled over this connection"),
|
||||||
|
ERROR_0xD0C1((short) 0xD0C1, "At least one error has been detected while accessing the tag(s)"),
|
||||||
|
ERROR_0xD0C2((short) 0xD0C2, "Change to STOP/HOLD mode"),
|
||||||
|
ERROR_0xD0C3((short) 0xD0C3, "At least one error was detected while accessing the tag(s). Mode change to STOP/HOLD"),
|
||||||
|
ERROR_0xD0C4((short) 0xD0C4, "Timeout during run-time measurement"),
|
||||||
|
ERROR_0xD0C5((short) 0xD0C5, "Display of block stack inconsistent, because blocks were deleted/reloaded"),
|
||||||
|
ERROR_0xD0C6((short) 0xD0C6, "Job was automatically deleted as the jobs it referenced have been deleted"),
|
||||||
|
ERROR_0xD0C7((short) 0xD0C7, "The job was automatically deleted because STOP mode was exited"),
|
||||||
|
ERROR_0xD0C8((short) 0xD0C8, "Block status' aborted because of inconsistencies between test job and running program"),
|
||||||
|
ERROR_0xD0C9((short) 0xD0C9, "Exit the status area by resetting OB90"),
|
||||||
|
ERROR_0xD0CA((short) 0xD0CA, "Exiting the status range by resetting OB90 and access error reading tags before exiting"),
|
||||||
|
ERROR_0xD0CB((short) 0xD0CB, "The output disable for the peripheral outputs has been activated again"),
|
||||||
|
ERROR_0xD0CC((short) 0xD0CC, "The amount of data for the debugging functions is restricted by the time limit"),
|
||||||
|
ERROR_0xD201((short) 0xD201, "Syntax error in block name"),
|
||||||
|
ERROR_0xD202((short) 0xD202, "Syntax error in function parameters"),
|
||||||
|
ERROR_0xD205((short) 0xD205, "Linked block already exists in RAM: Conditional copying is not possible"),
|
||||||
|
ERROR_0xD206((short) 0xD206, "Linked block already exists in EPROM: Conditional copying is not possible"),
|
||||||
|
ERROR_0xD208((short) 0xD208, "Maximum number of copied (not linked) blocks on module exceeded"),
|
||||||
|
ERROR_0xD209((short) 0xD209, "(At least) one of the given blocks not found on the module"),
|
||||||
|
ERROR_0xD20A((short) 0xD20A, "The maximum number of blocks that can be linked with one job was exceeded"),
|
||||||
|
ERROR_0xD20B((short) 0xD20B, "The maximum number of blocks that can be deleted with one job was exceeded"),
|
||||||
|
ERROR_0xD20C((short) 0xD20C, "OB cannot be copied because the associated priority class does not exist"),
|
||||||
|
ERROR_0xD20D((short) 0xD20D, "SDB cannot be interpreted (for example, unknown number)"),
|
||||||
|
ERROR_0xD20E((short) 0xD20E, "No (further) block available"),
|
||||||
|
ERROR_0xD20F((short) 0xD20F, "Module-specific maximum block size exceeded"),
|
||||||
|
ERROR_0xD210((short) 0xD210, "Invalid block number"),
|
||||||
|
ERROR_0xD212((short) 0xD212, "Incorrect header attribute (run-time relevant)"),
|
||||||
|
ERROR_0xD213((short) 0xD213, "Too many SDBs. Note the restrictions on the module being used"),
|
||||||
|
ERROR_0xD216((short) 0xD216, "Invalid user program - reset module"),
|
||||||
|
ERROR_0xD217((short) 0xD217, "Protection level specified in module properties not permitted"),
|
||||||
|
ERROR_0xD218((short) 0xD218, "Incorrect attribute (active/passive)"),
|
||||||
|
ERROR_0xD219((short) 0xD219, "Incorrect block lengths (for example, incorrect length of first section or of the whole block)"),
|
||||||
|
ERROR_0xD21A((short) 0xD21A, "Incorrect local data length or write-protection code faulty"),
|
||||||
|
ERROR_0xD21B((short) 0xD21B, "Module cannot compress or compression was interrupted early"),
|
||||||
|
ERROR_0xD21D((short) 0xD21D, "The volume of dynamic project data transferred is illegal"),
|
||||||
|
ERROR_0xD21E((short) 0xD21E, "Unable to assign parameters to a module (such as FM, CP). The system data could not be linked"),
|
||||||
|
ERROR_0xD220((short) 0xD220, "Invalid programming language. Note the restrictions on the module being used"),
|
||||||
|
ERROR_0xD221((short) 0xD221, "The system data for connections or routing are not valid"),
|
||||||
|
ERROR_0xD222((short) 0xD222, "The system data of the global data definition contain invalid parameters"),
|
||||||
|
ERROR_0xD223((short) 0xD223, "Error in instance data block for communication function block or maximum number of instance DBs exceeded"),
|
||||||
|
ERROR_0xD224((short) 0xD224, "The SCAN system data block contains invalid parameters"),
|
||||||
|
ERROR_0xD225((short) 0xD225, "The DP system data block contains invalid parameters"),
|
||||||
|
ERROR_0xD226((short) 0xD226, "A structural error occurred in a block"),
|
||||||
|
ERROR_0xD230((short) 0xD230, "A structural error occurred in a block"),
|
||||||
|
ERROR_0xD231((short) 0xD231, "At least one loaded OB cannot be copied because the associated priority class does not exist"),
|
||||||
|
ERROR_0xD232((short) 0xD232, "At least one block number of a loaded block is illegal"),
|
||||||
|
ERROR_0xD234((short) 0xD234, "Block exists twice in the specified memory medium or in the job"),
|
||||||
|
ERROR_0xD235((short) 0xD235, "The block contains an incorrect checksum"),
|
||||||
|
ERROR_0xD236((short) 0xD236, "The block does not contain a checksum"),
|
||||||
|
ERROR_0xD237((short) 0xD237, "You are about to load the block twice, i.e. a block with the same time stamp already exists on the CPU"),
|
||||||
|
ERROR_0xD238((short) 0xD238, "At least one of the blocks specified is not a DB"),
|
||||||
|
ERROR_0xD239((short) 0xD239, "At least one of the DBs specified is not available as a linked variant in the load memory"),
|
||||||
|
ERROR_0xD23A((short) 0xD23A, "At least one of the specified DBs is considerably different from the copied and linked variant"),
|
||||||
|
ERROR_0xD240((short) 0xD240, "Coordination rules violated"),
|
||||||
|
ERROR_0xD241((short) 0xD241, "The function is not permitted in the current protection level"),
|
||||||
|
ERROR_0xD242((short) 0xD242, "Protection violation while processing F blocks"),
|
||||||
|
ERROR_0xD250((short) 0xD250, "Update and module ID or version do not match"),
|
||||||
|
ERROR_0xD251((short) 0xD251, "Incorrect sequence of operating system components"),
|
||||||
|
ERROR_0xD252((short) 0xD252, "Checksum error"),
|
||||||
|
ERROR_0xD253((short) 0xD253, "No executable loader available; update only possible using a memory card"),
|
||||||
|
ERROR_0xD254((short) 0xD254, "Storage error in operating system"),
|
||||||
|
ERROR_0xD280((short) 0xD280, "Error compiling block in S7-300 CPU"),
|
||||||
|
ERROR_0xD2A1((short) 0xD2A1, "Another block function or a trigger on a block is active"),
|
||||||
|
ERROR_0xD2A2((short) 0xD2A2, "A trigger is active on a block. Complete the debugging function first"),
|
||||||
|
ERROR_0xD2A3((short) 0xD2A3, "The block is not active (linked), the block is occupied or the block is currently marked for deletion"),
|
||||||
|
ERROR_0xD2A4((short) 0xD2A4, "The block is already being processed by another block function"),
|
||||||
|
ERROR_0xD2A6((short) 0xD2A6, "It is not possible to save and change the user program simultaneously"),
|
||||||
|
ERROR_0xD2A7((short) 0xD2A7, "The block has the attribute 'unlinked' or is not processed"),
|
||||||
|
ERROR_0xD2A8((short) 0xD2A8, "An active debugging function is preventing parameters from being assigned to the CPU"),
|
||||||
|
ERROR_0xD2A9((short) 0xD2A9, "New parameters are being assigned to the CPU"),
|
||||||
|
ERROR_0xD2AA((short) 0xD2AA, "New parameters are currently being assigned to the modules"),
|
||||||
|
ERROR_0xD2AB((short) 0xD2AB, "The dynamic configuration limits are currently being changed"),
|
||||||
|
ERROR_0xD2AC((short) 0xD2AC, "A running active or deactivate assignment (SFC 12) is temporarily preventing R-KiR process"),
|
||||||
|
ERROR_0xD2B0((short) 0xD2B0, "An error occurred while configuring in RUN (CiR)"),
|
||||||
|
ERROR_0xD2C0((short) 0xD2C0, "The maximum number of technological objects has been exceeded"),
|
||||||
|
ERROR_0xD2C1((short) 0xD2C1, "The same technology data block already exists on the module"),
|
||||||
|
ERROR_0xD2C2((short) 0xD2C2, "Downloading the user program or downloading the hardware configuration is not possible"),
|
||||||
|
ERROR_0xD401((short) 0xD401, "Information function unavailable"),
|
||||||
|
ERROR_0xD402((short) 0xD402, "Information function unavailable"),
|
||||||
|
ERROR_0xD403((short) 0xD403, "Service has already been logged on/off (Diagnostics/PMC)"),
|
||||||
|
ERROR_0xD404((short) 0xD404, "Maximum number of nodes reached. No more logons possible for diagnostics/PMC"),
|
||||||
|
ERROR_0xD405((short) 0xD405, "Service not supported or syntax error in function parameters"),
|
||||||
|
ERROR_0xD406((short) 0xD406, "Required information currently unavailable"),
|
||||||
|
ERROR_0xD407((short) 0xD407, "Diagnostics error occurred"),
|
||||||
|
ERROR_0xD408((short) 0xD408, "Update aborted"),
|
||||||
|
ERROR_0xD409((short) 0xD409, "Error on DP bus"),
|
||||||
|
ERROR_0xD601((short) 0xD601, "Syntax error in function parameter"),
|
||||||
|
ERROR_0xD602((short) 0xD602, "Incorrect password entered"),
|
||||||
|
ERROR_0xD603((short) 0xD603, "The connection has already been legitimized"),
|
||||||
|
ERROR_0xD604((short) 0xD604, "The connection has already been enabled"),
|
||||||
|
ERROR_0xD605((short) 0xD605, "Legitimization not possible because password does not exist"),
|
||||||
|
ERROR_0xD801((short) 0xD801, "At least one tag address is invalid"),
|
||||||
|
ERROR_0xD802((short) 0xD802, "Specified job does not exist"),
|
||||||
|
ERROR_0xD803((short) 0xD803, "Illegal job status"),
|
||||||
|
ERROR_0xD804((short) 0xD804, "Illegal cycle time (illegal time base or multiple)"),
|
||||||
|
ERROR_0xD805((short) 0xD805, "No more cyclic read jobs can be set up"),
|
||||||
|
ERROR_0xD806((short) 0xD806, "The referenced job is in a state in which the requested function cannot be performed"),
|
||||||
|
ERROR_0xD807((short) 0xD807, "Function aborted due to overload, meaning executing the read cycle takes longer than the set scan cycle time"),
|
||||||
|
ERROR_0xDC01((short) 0xDC01, "Date and/or time invalid"),
|
||||||
|
ERROR_0xE201((short) 0xE201, "CPU is already the master"),
|
||||||
|
ERROR_0xE202((short) 0xE202, "Connect and update not possible due to different user program in flash module"),
|
||||||
|
ERROR_0xE203((short) 0xE203, "Connect and update not possible due to different firmware"),
|
||||||
|
ERROR_0xE204((short) 0xE204, "Connect and update not possible due to different memory configuration"),
|
||||||
|
ERROR_0xE205((short) 0xE205, "Connect/update aborted due to synchronization error"),
|
||||||
|
ERROR_0xE206((short) 0xE206, "Connect/update denied due to coordination violation"),
|
||||||
|
ERROR_0xEF01((short) 0xEF01, "S7 protocol error: Error at ID2; only 00H permitted in job"),
|
||||||
|
ERROR_0xEF02((short) 0xEF02, "S7 protocol error: Error at ID2; set of resources does not exist"),;
|
||||||
|
|
||||||
|
private static final Map<Short, S7ParamErrorCode> map;
|
||||||
|
|
||||||
|
static {
|
||||||
|
map = new HashMap<>();
|
||||||
|
for (S7ParamErrorCode subevent : S7ParamErrorCode .values()) {
|
||||||
|
map.put(subevent.code, subevent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final String event;
|
||||||
|
private final short code;
|
||||||
|
|
||||||
|
S7ParamErrorCode(short code, String event){
|
||||||
|
this.event = event;
|
||||||
|
this.code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEvent(){
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static S7ParamErrorCode valueOfEvent(String event) {
|
||||||
|
for (S7ParamErrorCode value : S7ParamErrorCode .values()) {
|
||||||
|
if(value.getEvent().equals(event)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public static S7ParamErrorCode valueOf(short code) {
|
||||||
|
return map.get(code);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Class S7Exception is an exception related to S7 Communication
|
||||||
|
*/
|
||||||
|
public final class S7CheckResultException extends RuntimeException {
|
||||||
|
|
||||||
|
/** The Constant serialVersionUID. */
|
||||||
|
private static final long serialVersionUID = -4761415733559374116L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*/
|
||||||
|
public S7CheckResultException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message
|
||||||
|
*/
|
||||||
|
public S7CheckResultException(final String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message
|
||||||
|
* @param cause
|
||||||
|
* the cause
|
||||||
|
*/
|
||||||
|
public S7CheckResultException(final String message, final Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param cause
|
||||||
|
* the cause
|
||||||
|
*/
|
||||||
|
public S7CheckResultException(final Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Class S7Exception is an exception related to S7 Communication
|
||||||
|
*/
|
||||||
|
public final class S7Exception extends RuntimeException {
|
||||||
|
|
||||||
|
/** The Constant serialVersionUID. */
|
||||||
|
private static final long serialVersionUID = -4761415733559374116L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*/
|
||||||
|
public S7Exception() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message
|
||||||
|
*/
|
||||||
|
public S7Exception(final String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message
|
||||||
|
* @param cause
|
||||||
|
* the cause
|
||||||
|
*/
|
||||||
|
public S7Exception(final String message, final Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param cause
|
||||||
|
* the cause
|
||||||
|
*/
|
||||||
|
public S7Exception(final Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.exception;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Class S7IOException is an exception related to S7 Communication
|
||||||
|
*/
|
||||||
|
public final class S7IOException extends RuntimeException {
|
||||||
|
|
||||||
|
/** The Constant serialVersionUID. */
|
||||||
|
private static final long serialVersionUID = -4761415733559374116L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*/
|
||||||
|
public S7IOException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message
|
||||||
|
*/
|
||||||
|
public S7IOException(final String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message
|
||||||
|
* @param cause
|
||||||
|
* the cause
|
||||||
|
*/
|
||||||
|
public S7IOException(final String message, final Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param cause
|
||||||
|
* the cause
|
||||||
|
*/
|
||||||
|
public S7IOException(final Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Class S7Exception is an exception related to S7 Communication
|
||||||
|
*/
|
||||||
|
public final class S7ParseDataException extends RuntimeException {
|
||||||
|
|
||||||
|
/** The Constant serialVersionUID. */
|
||||||
|
private static final long serialVersionUID = -4761415733559374116L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*/
|
||||||
|
public S7ParseDataException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message
|
||||||
|
*/
|
||||||
|
public S7ParseDataException(final String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* the message
|
||||||
|
* @param cause
|
||||||
|
* the cause
|
||||||
|
*/
|
||||||
|
public S7ParseDataException(final String message, final Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 exception.
|
||||||
|
*
|
||||||
|
* @param cause
|
||||||
|
* the cause
|
||||||
|
*/
|
||||||
|
public S7ParseDataException(final Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl;
|
||||||
|
|
||||||
|
import com.cnbm.s7.controller.S7DemoController;
|
||||||
|
import com.cnbm.s7.s7connector.api.DaveArea;
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Connector;
|
||||||
|
import com.cnbm.s7.s7connector.exception.S7CheckResultException;
|
||||||
|
import com.cnbm.s7.s7connector.exception.S7Exception;
|
||||||
|
import com.cnbm.s7.s7connector.impl.nodave.Nodave;
|
||||||
|
import com.cnbm.s7.s7connector.impl.nodave.S7Connection;
|
||||||
|
import com.cnbm.s7.s7connector.type.PlcVar;
|
||||||
|
import com.cnbm.s7.s7connector.type.TransportSize;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base-Connection for the S7-PLC Connection Libnodave:
|
||||||
|
* http://libnodave.sourceforge.net/
|
||||||
|
*
|
||||||
|
* @author Thomas Rudin
|
||||||
|
*/
|
||||||
|
public abstract class S7BaseConnection implements S7Connector {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(S7BaseConnection.class);
|
||||||
|
|
||||||
|
|
||||||
|
/** The Constant MAX_SIZE. */
|
||||||
|
//private static final int MAX_SIZE = 96; //原版96 ;; ioserver 127 ;;
|
||||||
|
private static final int MAX_SIZE = 212; //S7-1200-maxReadBytes = 212 ;; S7-1500-maxReadBytes = 452
|
||||||
|
|
||||||
|
/** The Constant PROPERTY_AREA. */
|
||||||
|
public static final String PROPERTY_AREA = "area";
|
||||||
|
|
||||||
|
/** The Constant PROPERTY_AREANUMBER. */
|
||||||
|
public static final String PROPERTY_AREANUMBER = "areanumber";
|
||||||
|
|
||||||
|
/** The Constant PROPERTY_BYTES. */
|
||||||
|
public static final String PROPERTY_BYTES = "bytes";
|
||||||
|
|
||||||
|
/** The Constant PROPERTY_OFFSET. */
|
||||||
|
public static final String PROPERTY_OFFSET = "offset";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks the Result.
|
||||||
|
*
|
||||||
|
* @param libnodaveResult
|
||||||
|
* the libnodave result
|
||||||
|
*/
|
||||||
|
public static void checkResult(final int libnodaveResult) {
|
||||||
|
if (libnodaveResult != Nodave.RESULT_OK) {
|
||||||
|
final String msg = Nodave.strerror(libnodaveResult);
|
||||||
|
// throw new IllegalArgumentException("Result: " + msg);
|
||||||
|
logger.info("checkResult 失败,errValue:"+libnodaveResult+", errMsg: "+msg);
|
||||||
|
throw new S7CheckResultException("errMsg : "+msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump data
|
||||||
|
*
|
||||||
|
* @param b
|
||||||
|
* the byte stream
|
||||||
|
*/
|
||||||
|
protected static void dump(final byte[] b) {
|
||||||
|
for (final byte element : b) {
|
||||||
|
System.out.print(Integer.toHexString(element & 0xFF) + ",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The dc. */
|
||||||
|
private S7Connection dc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the connection
|
||||||
|
*
|
||||||
|
* @param dc
|
||||||
|
* the connection instance
|
||||||
|
*/
|
||||||
|
protected void init(final S7Connection dc) {
|
||||||
|
this.dc = dc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public synchronized byte[] read(final DaveArea area, final int areaNumber, final int bytes, final int offset) {
|
||||||
|
if (bytes > MAX_SIZE) {
|
||||||
|
final byte[] ret = new byte[bytes];
|
||||||
|
//注意这里 嵌套了 递归,让无限递归去解决 MAX_SIZE的问题。
|
||||||
|
final byte[] currentBuffer = this.read(area, areaNumber, MAX_SIZE, offset);
|
||||||
|
System.arraycopy(currentBuffer, 0, ret, 0, currentBuffer.length);
|
||||||
|
|
||||||
|
final byte[] nextBuffer = this.read(area, areaNumber, bytes - MAX_SIZE, offset + MAX_SIZE);
|
||||||
|
System.arraycopy(nextBuffer, 0, ret, currentBuffer.length, nextBuffer.length);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
//接收结果的 容器,传进去指针
|
||||||
|
final byte[] buffer = new byte[bytes];
|
||||||
|
final int ret = this.dc.readBytes(area, areaNumber, offset, bytes, buffer);
|
||||||
|
|
||||||
|
//判断结果
|
||||||
|
|
||||||
|
if(ret == Nodave.RESULT_OK){
|
||||||
|
return buffer;
|
||||||
|
}else {
|
||||||
|
final String msg = Nodave.strerror(ret);
|
||||||
|
logger.info("read checkResult 失败,errValue:"+ret+", errMsg: "+msg);
|
||||||
|
throw new S7CheckResultException("errMsg : "+msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// private Integer checkResult(final int libnodaveResult) {
|
||||||
|
// if (libnodaveResult != Nodave.RESULT_OK) {
|
||||||
|
// final String msg = Nodave.strerror(libnodaveResult);
|
||||||
|
//// throw new IllegalArgumentException("Result: " + msg);
|
||||||
|
// logger.info("checkResult 失败,errValue:"+libnodaveResult+", errMsg: "+msg);
|
||||||
|
// throw new S7CheckResultException("errMsg : "+msg);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized byte[] read(final DaveArea area, final int areaNumber, final int bytes, final int offset, int bitOffset, TransportSize transportSize) {
|
||||||
|
if(bitOffset==0){
|
||||||
|
return read(area,areaNumber,bytes,offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes > MAX_SIZE) {
|
||||||
|
final byte[] ret = new byte[bytes];
|
||||||
|
//注意这里 嵌套了 递归,让无限递归去解决 MAX_SIZE的问题。
|
||||||
|
final byte[] currentBuffer = this.read(area, areaNumber, MAX_SIZE, offset,bitOffset,transportSize);
|
||||||
|
System.arraycopy(currentBuffer, 0, ret, 0, currentBuffer.length);
|
||||||
|
|
||||||
|
final byte[] nextBuffer = this.read(area, areaNumber, bytes - MAX_SIZE, offset + MAX_SIZE,bitOffset,transportSize);
|
||||||
|
System.arraycopy(nextBuffer, 0, ret, currentBuffer.length, nextBuffer.length);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
//接收结果的 容器,传进去指针
|
||||||
|
final byte[] buffer = new byte[bytes];
|
||||||
|
final int ret = this.dc.readBytes(area, areaNumber, offset,bitOffset, bytes, buffer,transportSize);
|
||||||
|
|
||||||
|
//thr resultException
|
||||||
|
if(ret == Nodave.RESULT_OK){
|
||||||
|
return buffer;
|
||||||
|
}else {
|
||||||
|
final String msg = Nodave.strerror(ret);
|
||||||
|
logger.info("read checkResult 失败,errValue:"+ret+", errMsg: "+msg);
|
||||||
|
throw new S7CheckResultException("errMsg : "+msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public synchronized void write(final DaveArea area, final int areaNumber, final int offset, final byte[] buffer) {
|
||||||
|
if (buffer.length > MAX_SIZE) {
|
||||||
|
// Split buffer
|
||||||
|
final byte[] subBuffer = new byte[MAX_SIZE];
|
||||||
|
final byte[] nextBuffer = new byte[buffer.length - subBuffer.length];
|
||||||
|
|
||||||
|
System.arraycopy(buffer, 0, subBuffer, 0, subBuffer.length);
|
||||||
|
System.arraycopy(buffer, MAX_SIZE, nextBuffer, 0, nextBuffer.length);
|
||||||
|
|
||||||
|
this.write(area, areaNumber, offset, subBuffer);
|
||||||
|
this.write(area, areaNumber, offset + subBuffer.length, nextBuffer);
|
||||||
|
} else {
|
||||||
|
// Size fits
|
||||||
|
final int ret = this.dc.writeBytes(area, areaNumber, offset, buffer.length, buffer);
|
||||||
|
// Check return-value
|
||||||
|
checkResult(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void write(final DaveArea area, final int areaNumber, final int byteOffset, final int bitOffset, final byte[] buffer, PlcVar var) {
|
||||||
|
if(bitOffset==0){
|
||||||
|
write(area,areaNumber,byteOffset,buffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (buffer.length > MAX_SIZE) {
|
||||||
|
// Split buffer
|
||||||
|
final byte[] subBuffer = new byte[MAX_SIZE];
|
||||||
|
final byte[] nextBuffer = new byte[buffer.length - subBuffer.length];
|
||||||
|
|
||||||
|
System.arraycopy(buffer, 0, subBuffer, 0, subBuffer.length);
|
||||||
|
System.arraycopy(buffer, MAX_SIZE, nextBuffer, 0, nextBuffer.length);
|
||||||
|
|
||||||
|
this.write(area, areaNumber, byteOffset,bitOffset, subBuffer,var);
|
||||||
|
this.write(area, areaNumber, byteOffset + subBuffer.length,bitOffset, nextBuffer,var);
|
||||||
|
} else {
|
||||||
|
// Size fits
|
||||||
|
final int ret = this.dc.writeBytes(area, areaNumber, byteOffset,bitOffset, buffer.length, buffer,var);
|
||||||
|
// Check return-value
|
||||||
|
checkResult(ret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,124 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.DaveArea;
|
||||||
|
import com.cnbm.s7.s7connector.exception.S7CheckResultException;
|
||||||
|
import com.cnbm.s7.s7connector.exception.S7Exception;
|
||||||
|
import com.cnbm.s7.s7connector.impl.nodave.Nodave;
|
||||||
|
import com.cnbm.s7.s7connector.impl.nodave.PLCinterface;
|
||||||
|
import com.cnbm.s7.s7connector.impl.nodave.TCPConnection;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.Socket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TCP_Connection to a S7 PLC
|
||||||
|
*
|
||||||
|
* @author Thomas Rudin
|
||||||
|
* @href http://libnodave.sourceforge.net/
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class S7TCPConnection extends S7BaseConnection {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Connection
|
||||||
|
*/
|
||||||
|
private TCPConnection dc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Interface
|
||||||
|
*/
|
||||||
|
private PLCinterface di;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Host to connect to
|
||||||
|
*/
|
||||||
|
private final String host;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The port to connect to
|
||||||
|
*/
|
||||||
|
private final int port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rack and slot number
|
||||||
|
*/
|
||||||
|
private final int rack, slot;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Socket
|
||||||
|
*/
|
||||||
|
private Socket socket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new Instance to the given host, rack, slot and port
|
||||||
|
*
|
||||||
|
* @param host
|
||||||
|
* @throws
|
||||||
|
*/
|
||||||
|
public S7TCPConnection(final String host, final int rack, final int slot, final int port) throws S7Exception {
|
||||||
|
this.host = host;
|
||||||
|
this.rack = rack;
|
||||||
|
this.slot = slot;
|
||||||
|
this.port = port;
|
||||||
|
this.setupSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
try {
|
||||||
|
this.socket.close();
|
||||||
|
} catch (final Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable {
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the socket
|
||||||
|
*/
|
||||||
|
private void setupSocket() {
|
||||||
|
try {
|
||||||
|
this.socket = new Socket();
|
||||||
|
this.socket.setSoTimeout(2000);
|
||||||
|
//先socket 建立好连接
|
||||||
|
this.socket.connect(new InetSocketAddress(this.host, this.port));
|
||||||
|
|
||||||
|
|
||||||
|
this.di = new PLCinterface(this.socket.getOutputStream(), this.socket.getInputStream(), "IF1",
|
||||||
|
DaveArea.LOCAL.getCode(), // TODO Local MPI-Address?
|
||||||
|
Nodave.PROTOCOL_ISOTCP);
|
||||||
|
|
||||||
|
this.dc = new TCPConnection(this.di, this.rack, this.slot);
|
||||||
|
|
||||||
|
final int res = this.dc.connectPLC();
|
||||||
|
|
||||||
|
checkResult(res);
|
||||||
|
super.init(this.dc);
|
||||||
|
|
||||||
|
} catch (final Exception e) {
|
||||||
|
throw new S7Exception("constructor", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,354 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.nodave;
|
||||||
|
|
||||||
|
public final class Nodave {
|
||||||
|
public final static int MAX_RAW_LEN = 2048;
|
||||||
|
public final static int MPIReachable = 0x30;
|
||||||
|
public final static int MPIunused = 0x10;
|
||||||
|
public final static int OrderCodeSize = 21;
|
||||||
|
|
||||||
|
public final static int PartnerListSize = 126;
|
||||||
|
|
||||||
|
public final static int PROTOCOL_ISOTCP = 4;
|
||||||
|
public final static int PROTOCOL_ISOTCP243 = 5;
|
||||||
|
public final static int PROTOCOL_MPI_IBH = 223; // MPI with IBH NetLink MPI
|
||||||
|
// to ethernet gateway
|
||||||
|
public final static int PROTOCOL_MPI_NLPRO = 230; // MPI with IBH NetLink
|
||||||
|
// MPI to ethernet
|
||||||
|
// gateway
|
||||||
|
public final static int PROTOCOL_NLPRO = 230; // MPI with IBH NetLink MPI to
|
||||||
|
// ethernet gateway
|
||||||
|
// to ethernet gateway
|
||||||
|
public final static int PROTOCOL_PPI_IBH = 224; // PPI with IBH NetLink MPI
|
||||||
|
|
||||||
|
public final static int RESULT_ADDRESS_OUT_OF_RANGE = 5;
|
||||||
|
/* means the write data size doesn't fit item size */
|
||||||
|
public final static int RESULT_CANNOT_EVALUATE_PDU = -123;
|
||||||
|
public final static int RESULT_CPU_RETURNED_NO_DATA = -124;
|
||||||
|
public final static int RESULT_EMPTY_RESULT_ERROR = -126;
|
||||||
|
|
||||||
|
public final static int RESULT_EMPTY_RESULT_SET_ERROR = -127;
|
||||||
|
|
||||||
|
public final static int RESULT_ITEM_NOT_AVAILABLE = 10;
|
||||||
|
/* means a a piece of data is not available in the CPU, e.g. */
|
||||||
|
/* when trying to read a non existing DB */
|
||||||
|
/* CPU tells it does not support to read a bit block with a */
|
||||||
|
/* length other than 1 bit. */
|
||||||
|
public final static int RESULT_ITEM_NOT_AVAILABLE200 = 3;
|
||||||
|
/* means a a piece of data is not available in the CPU, e.g. */
|
||||||
|
/* when trying to read a non existing DB or bit bloc of length<>1 */
|
||||||
|
/* This code seems to be specific to 200 family. */
|
||||||
|
/* CPU tells there is no peripheral at address */
|
||||||
|
public final static int RESULT_MULTIPLE_BITS_NOT_SUPPORTED = 6;
|
||||||
|
public final static int RESULT_NO_PERIPHERAL_AT_ADDRESS = 1;
|
||||||
|
|
||||||
|
public final static int RESULT_OK = 0; /* means all ok */
|
||||||
|
public final static int RESULT_SHORT_PACKET = -1024;
|
||||||
|
public final static int RESULT_TIMEOUT = -1025;
|
||||||
|
public final static int RESULT_UNEXPECTED_FUNC = -128;
|
||||||
|
public final static int RESULT_UNKNOWN_DATA_UNIT_SIZE = -129;
|
||||||
|
|
||||||
|
public final static int RESULT_UNKNOWN_ERROR = -125;
|
||||||
|
/* means the data address is beyond the CPUs address range */
|
||||||
|
public final static int RESULT_WRITE_DATA_SIZE_MISMATCH = 7;
|
||||||
|
|
||||||
|
public static float BEFloat(final byte[] b, final int pos) {
|
||||||
|
int i = 0;
|
||||||
|
// System.out.println("pos" + pos);
|
||||||
|
|
||||||
|
i |= Nodave.USByte(b, pos);
|
||||||
|
i <<= 8;
|
||||||
|
i |= Nodave.USByte(b, pos + 1);
|
||||||
|
i <<= 8;
|
||||||
|
i |= Nodave.USByte(b, pos + 2);
|
||||||
|
i <<= 8;
|
||||||
|
i |= Nodave.USByte(b, pos + 3);
|
||||||
|
final float f = Float.intBitsToFloat(i);
|
||||||
|
return (f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] bswap_16(int a) {
|
||||||
|
final byte[] b = new byte[2];
|
||||||
|
b[1] = (byte) (a & 0xff);
|
||||||
|
a = a >> 8;
|
||||||
|
b[0] = (byte) (a & 0xff);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] bswap_32(int a) {
|
||||||
|
final byte[] b = new byte[4];
|
||||||
|
b[3] = (byte) (a & 0xff);
|
||||||
|
a = a >> 8;
|
||||||
|
b[2] = (byte) (a & 0xff);
|
||||||
|
a = a >> 8;
|
||||||
|
b[1] = (byte) (a & 0xff);
|
||||||
|
a = a >> 8;
|
||||||
|
b[0] = (byte) (a & 0xff);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] bswap_32(long a) {
|
||||||
|
final byte[] b = new byte[4];
|
||||||
|
b[3] = (byte) (a & 0xff);
|
||||||
|
a = a >> 8;
|
||||||
|
b[2] = (byte) (a & 0xff);
|
||||||
|
a = a >> 8;
|
||||||
|
b[1] = (byte) (a & 0xff);
|
||||||
|
a = a >> 8;
|
||||||
|
b[0] = (byte) (a & 0xff);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This doesn't swap anything, but the name fits into the series
|
||||||
|
*
|
||||||
|
* @param a
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static byte[] bswap_8(final int a) {
|
||||||
|
final byte[] b = new byte[1];
|
||||||
|
b[0] = (byte) (a & 0xff);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dumps len hex codes from byte array mem beginning at index start.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static void dump(final String text, final byte[] mem, final int start, final int len) {
|
||||||
|
System.out.print(text + " ");
|
||||||
|
for (int i = start; i < (start + len); i++) {
|
||||||
|
int j = mem[i];
|
||||||
|
if (j < 0) {
|
||||||
|
j += 256;
|
||||||
|
}
|
||||||
|
String s = Integer.toHexString(j);
|
||||||
|
if (s.length() < 2) {
|
||||||
|
s = "0" + s;
|
||||||
|
}
|
||||||
|
System.out.print(s + ",");
|
||||||
|
}
|
||||||
|
System.out.println(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long SBELong(final byte[] b, final int pos) {
|
||||||
|
final int i = b[pos];
|
||||||
|
int j = b[pos + 1];
|
||||||
|
int k = b[pos + 2];
|
||||||
|
int l = b[pos + 3];
|
||||||
|
// if (i < 0)
|
||||||
|
// i += 256;
|
||||||
|
if (j < 0) {
|
||||||
|
j += 256;
|
||||||
|
}
|
||||||
|
if (k < 0) {
|
||||||
|
k += 256;
|
||||||
|
}
|
||||||
|
if (l < 0) {
|
||||||
|
l += 256;
|
||||||
|
}
|
||||||
|
return ((256 * k) + l) + (65536L * ((256 * i) + j));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int SBEWord(final byte[] b, final int pos) {
|
||||||
|
final int i = b[pos];
|
||||||
|
int k = b[pos + 1];
|
||||||
|
// if (i < 0)
|
||||||
|
// i += 256;
|
||||||
|
if (k < 0) {
|
||||||
|
k += 256;
|
||||||
|
}
|
||||||
|
return ((256 * i) + k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int SByte(final byte[] b, final int pos) {
|
||||||
|
final int i = b[pos];
|
||||||
|
return (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setBEFloat(final byte[] b, final int pos, final float f) {
|
||||||
|
int a = Float.floatToIntBits(f);
|
||||||
|
b[pos + 3] = (byte) (a & 0xff);
|
||||||
|
a = a >> 8;
|
||||||
|
b[pos + 2] = (byte) (a & 0xff);
|
||||||
|
a = a >> 8;
|
||||||
|
b[pos + 1] = (byte) (a & 0xff);
|
||||||
|
a = a >> 8;
|
||||||
|
b[pos] = (byte) (a & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setUSBELong(final byte[] b, final int pos, long a) {
|
||||||
|
b[pos + 3] = (byte) (a & 0xff);
|
||||||
|
a = a >> 8;
|
||||||
|
b[pos + 2] = (byte) (a & 0xff);
|
||||||
|
a = a >> 8;
|
||||||
|
b[pos + 1] = (byte) (a & 0xff);
|
||||||
|
a = a >> 8;
|
||||||
|
b[pos] = (byte) (a & 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setUSBEWord(final byte[] b, final int pos, final int val) {
|
||||||
|
b[pos] = ((byte) (val / 0x100));
|
||||||
|
b[pos + 1] = ((byte) (val % 0x100));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setUSByte(final byte[] b, final int pos, final int val) {
|
||||||
|
b[pos] = ((byte) (val & 0xff));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String strerror(final int code) {
|
||||||
|
switch (code) {
|
||||||
|
case RESULT_OK:
|
||||||
|
return "ok";
|
||||||
|
case RESULT_MULTIPLE_BITS_NOT_SUPPORTED:
|
||||||
|
return "the CPU does not support reading a bit block of length<>1";
|
||||||
|
case RESULT_ITEM_NOT_AVAILABLE:
|
||||||
|
return "the desired item is not available in the PLC";
|
||||||
|
case RESULT_ITEM_NOT_AVAILABLE200:
|
||||||
|
return "the desired item is not available in the PLC (200 family)";
|
||||||
|
case RESULT_ADDRESS_OUT_OF_RANGE:
|
||||||
|
return "the desired address is beyond limit for this PLC";
|
||||||
|
case RESULT_CPU_RETURNED_NO_DATA:
|
||||||
|
return "the PLC returned a packet with no result data";
|
||||||
|
case Nodave.RESULT_UNKNOWN_ERROR:
|
||||||
|
return "the PLC returned an error code not understood by this library";
|
||||||
|
case Nodave.RESULT_EMPTY_RESULT_ERROR:
|
||||||
|
return "this result contains no data";
|
||||||
|
case Nodave.RESULT_EMPTY_RESULT_SET_ERROR:
|
||||||
|
return "cannot work with an undefined result set";
|
||||||
|
case Nodave.RESULT_CANNOT_EVALUATE_PDU:
|
||||||
|
return "cannot evaluate the received PDU";
|
||||||
|
case Nodave.RESULT_WRITE_DATA_SIZE_MISMATCH:
|
||||||
|
return "Write data size error";
|
||||||
|
case Nodave.RESULT_NO_PERIPHERAL_AT_ADDRESS:
|
||||||
|
return "No data from I/O module";
|
||||||
|
case Nodave.RESULT_UNEXPECTED_FUNC:
|
||||||
|
return "Unexpected function code in answer";
|
||||||
|
case Nodave.RESULT_UNKNOWN_DATA_UNIT_SIZE:
|
||||||
|
return "PLC responds wit an unknown data type";
|
||||||
|
case Nodave.RESULT_SHORT_PACKET:
|
||||||
|
return "Short packet from PLC";
|
||||||
|
case Nodave.RESULT_TIMEOUT:
|
||||||
|
return "Timeout when waiting for PLC response";
|
||||||
|
case 0x8000:
|
||||||
|
return "function already occupied.";
|
||||||
|
case 0x8001:
|
||||||
|
return "not allowed in current operating status.";
|
||||||
|
case 0x8101:
|
||||||
|
return "hardware fault.";
|
||||||
|
case 0x8103:
|
||||||
|
return "object access not allowed.";
|
||||||
|
case 0x8104:
|
||||||
|
return "context is not supported.";
|
||||||
|
case 0x8105:
|
||||||
|
return "invalid address.";
|
||||||
|
case 0x8106:
|
||||||
|
return "data type not supported.";
|
||||||
|
case 0x8107:
|
||||||
|
return "data type not consistent.";
|
||||||
|
case 0x810A:
|
||||||
|
return "object does not exist.";
|
||||||
|
case 0x8500:
|
||||||
|
return "incorrect PDU size.";
|
||||||
|
case 0x8702:
|
||||||
|
return "address invalid.";
|
||||||
|
case 0xd201:
|
||||||
|
return "block name syntax error.";
|
||||||
|
case 0xd202:
|
||||||
|
return "syntax error function parameter.";
|
||||||
|
case 0xd203:
|
||||||
|
return "syntax error block type.";
|
||||||
|
case 0xd204:
|
||||||
|
return "no linked block in storage medium.";
|
||||||
|
case 0xd205:
|
||||||
|
return "object already exists.";
|
||||||
|
case 0xd206:
|
||||||
|
return "object already exists.";
|
||||||
|
case 0xd207:
|
||||||
|
return "block exists in EPROM.";
|
||||||
|
case 0xd209:
|
||||||
|
return "block does not exist.";
|
||||||
|
case 0xd20e:
|
||||||
|
return "no block does not exist.";
|
||||||
|
case 0xd210:
|
||||||
|
return "block number too big.";
|
||||||
|
case 0xd240:
|
||||||
|
return "unfinished block transfer in progress?";
|
||||||
|
case 0xd241:
|
||||||
|
return "protected by password.";
|
||||||
|
default:
|
||||||
|
return "no message defined for code: " + code + "!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] toPLCfloat(final double d) {
|
||||||
|
final float f = (float) d;
|
||||||
|
return toPLCfloat(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] toPLCfloat(final float f) {
|
||||||
|
final int i = Float.floatToIntBits(f);
|
||||||
|
return bswap_32(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long USBELong(final byte[] b, final int pos) {
|
||||||
|
int i = b[pos];
|
||||||
|
int j = b[pos + 1];
|
||||||
|
int k = b[pos + 2];
|
||||||
|
int l = b[pos + 3];
|
||||||
|
// System.out.println(
|
||||||
|
// pos + " 0:" + i + " 1:" + j + " 2:" + k + " 3:" + l);
|
||||||
|
if (i < 0) {
|
||||||
|
i += 256;
|
||||||
|
}
|
||||||
|
if (j < 0) {
|
||||||
|
j += 256;
|
||||||
|
}
|
||||||
|
if (k < 0) {
|
||||||
|
k += 256;
|
||||||
|
}
|
||||||
|
if (l < 0) {
|
||||||
|
l += 256;
|
||||||
|
}
|
||||||
|
return ((256 * k) + l) + (65536L * ((256 * i) + j));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int USBEWord(final byte[] b, final int pos) {
|
||||||
|
int i = b[pos];
|
||||||
|
int k = b[pos + 1];
|
||||||
|
if (i < 0) {
|
||||||
|
i += 256;
|
||||||
|
}
|
||||||
|
if (k < 0) {
|
||||||
|
k += 256;
|
||||||
|
}
|
||||||
|
return ((256 * i) + k);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int USByte(final byte[] b, final int pos) {
|
||||||
|
int i = b[pos];
|
||||||
|
if (i < 0) {
|
||||||
|
i += 256;
|
||||||
|
}
|
||||||
|
return (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Nodave() {
|
||||||
|
// Not needed because of utility class
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
622
ym-s7/src/main/java/com/cnbm/s7/s7connector/impl/nodave/PDU.java
Normal file
622
ym-s7/src/main/java/com/cnbm/s7/s7connector/impl/nodave/PDU.java
Normal file
@ -0,0 +1,622 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.nodave;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.DaveArea;
|
||||||
|
import com.cnbm.s7.s7connector.type.PlcVar;
|
||||||
|
import com.cnbm.s7.s7connector.type.TransportSize;
|
||||||
|
|
||||||
|
public final class PDU {
|
||||||
|
/**
|
||||||
|
* known function codes
|
||||||
|
*/
|
||||||
|
public final static byte FUNC_READ = 4;
|
||||||
|
|
||||||
|
public final static byte FUNC_WRITE = 5;
|
||||||
|
|
||||||
|
public int data;
|
||||||
|
|
||||||
|
int dlen;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
int header; // the position of the header;
|
||||||
|
int hlen;
|
||||||
|
byte[] mem; //msgOut 也就是 上位机==》plc 的channel
|
||||||
|
public int param; // the position of the parameters;
|
||||||
|
public int plen;
|
||||||
|
public int udata;
|
||||||
|
public int udlen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set up the PDU information
|
||||||
|
*
|
||||||
|
* mem =》 msgOut、msgIn
|
||||||
|
* pos =》 pdu在整个request请求 的起始位置(起始都是7,第7个字节)
|
||||||
|
*/
|
||||||
|
public PDU(final byte[] mem, final int pos) {
|
||||||
|
this.mem = mem;
|
||||||
|
this.header = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int addBitVarToReadRequest(final int area, final int DBnum, final int start, final int len) {
|
||||||
|
final byte pa[] = { 0x12, 0x0a, 0x10, 0x01, /* single bits */
|
||||||
|
0x00, 0x1A, /* insert length in bytes here */
|
||||||
|
0x00, 0x0B, /* insert DB number here */
|
||||||
|
(byte) 0x84, /* change this to real area code */
|
||||||
|
0x00, 0x00, (byte) 0xC0 /* insert start address in bits */
|
||||||
|
};
|
||||||
|
Nodave.setUSBEWord(pa, 4, len);
|
||||||
|
Nodave.setUSBEWord(pa, 6, DBnum);
|
||||||
|
Nodave.setUSBELong(pa, 8, start);
|
||||||
|
Nodave.setUSByte(pa, 8, area);
|
||||||
|
|
||||||
|
this.mem[this.param + 1]++;
|
||||||
|
System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
|
||||||
|
this.plen += pa.length;
|
||||||
|
Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addBitVarToWriteRequest(final DaveArea area, final int DBnum, final int start, final int byteCount,
|
||||||
|
final byte[] buffer) {
|
||||||
|
final byte da[] = { 0, 3, 0, 0, };
|
||||||
|
final byte pa[] = { 0x12, 0x0a, 0x10, 0x01, /* single bit */
|
||||||
|
0, 0, /* insert length in bytes here */
|
||||||
|
0, 0, /* insert DB number here */
|
||||||
|
0, /* change this to real area code */
|
||||||
|
0, 0, 0 /* insert start address in bits */
|
||||||
|
};
|
||||||
|
if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
|
||||||
|
|| (area == DaveArea.COUNTER200)) {
|
||||||
|
pa[3] = (byte) area.getCode();
|
||||||
|
pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
|
||||||
|
pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
|
||||||
|
} else if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
|
||||||
|
pa[3] = 4;
|
||||||
|
pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
|
||||||
|
pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
|
||||||
|
} else {
|
||||||
|
pa[4] = (byte) (byteCount / 0x100);
|
||||||
|
pa[5] = (byte) (byteCount & 0xff);
|
||||||
|
}
|
||||||
|
pa[6] = (byte) (DBnum / 256);
|
||||||
|
pa[7] = (byte) (DBnum & 0xff);
|
||||||
|
pa[8] = (byte) area.getCode();
|
||||||
|
pa[11] = (byte) (start & 0xff);
|
||||||
|
pa[10] = (byte) ((start / 0x100) & 0xff);
|
||||||
|
pa[9] = (byte) (start / 0x10000);
|
||||||
|
|
||||||
|
if ((this.dlen % 2) != 0) {
|
||||||
|
this.addData(da, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mem[this.param + 1]++;
|
||||||
|
if (this.dlen > 0) {
|
||||||
|
final byte[] saveData = new byte[this.dlen];
|
||||||
|
System.arraycopy(this.mem, this.data, saveData, 0, this.dlen);
|
||||||
|
System.arraycopy(saveData, 0, this.mem, this.data + pa.length, this.dlen);
|
||||||
|
}
|
||||||
|
System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
|
||||||
|
this.plen += pa.length;
|
||||||
|
Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
|
||||||
|
this.data = this.param + this.plen;
|
||||||
|
|
||||||
|
this.addData(da);
|
||||||
|
this.addValue(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add data after parameters, set dlen as needed. Needs valid header and
|
||||||
|
* parameters
|
||||||
|
*/
|
||||||
|
void addData(final byte[] newData) {
|
||||||
|
final int appPos = this.data + this.dlen; // append to this position
|
||||||
|
this.dlen += newData.length;
|
||||||
|
System.arraycopy(newData, 0, this.mem, appPos, newData.length);
|
||||||
|
Nodave.setUSBEWord(this.mem, this.header + 8, this.dlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add len bytes of len after parameters from a maybe longer block of bytes.
|
||||||
|
* Set dlen as needed. Needs valid header and parameters
|
||||||
|
*/
|
||||||
|
public void addData(final byte[] newData, final int len) {
|
||||||
|
final int appPos = this.data + this.dlen; // append to this position
|
||||||
|
this.dlen += len;
|
||||||
|
System.arraycopy(newData, 0, this.mem, appPos, len);
|
||||||
|
Nodave.setUSBEWord(this.mem, this.header + 8, this.dlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addParam(final byte[] pa) {
|
||||||
|
this.plen = pa.length;
|
||||||
|
System.arraycopy(pa, 0, this.mem, this.param, this.plen);
|
||||||
|
//设置S7-Header 里的Parameter Length
|
||||||
|
Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
|
||||||
|
// mem[header + 6] = (byte) (pa.length / 256);
|
||||||
|
// mem[header + 7] = (byte) (pa.length % 256);
|
||||||
|
//this.data = 17+2 = 19 ( data 其实就是item项 )
|
||||||
|
this.data = this.param + this.plen;
|
||||||
|
this.dlen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* add data in user data. Add a user data header, if not yet present.
|
||||||
|
*/
|
||||||
|
public void addUserData(final byte[] da) {
|
||||||
|
final byte udh[] = { (byte) 0xff, 9, 0, 0 };
|
||||||
|
if (this.dlen == 0) {
|
||||||
|
this.addData(udh);
|
||||||
|
}
|
||||||
|
this.addValue(da);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add values after value header in data, adjust dlen and data count. Needs
|
||||||
|
* valid header,parameters,data,dlen
|
||||||
|
*/
|
||||||
|
void addValue(final byte[] values) {
|
||||||
|
int valCount = (0x100 * this.mem[this.data + 2]) + this.mem[this.data + 3];
|
||||||
|
|
||||||
|
if (this.mem[this.data + 1] == 4) { // bit data, length is in bits
|
||||||
|
valCount += 8 * values.length;
|
||||||
|
} else if (this.mem[this.data + 1] == 9) { // byte data, length is in
|
||||||
|
// bytes
|
||||||
|
valCount += values.length;
|
||||||
|
} else if(this.mem[this.data+1] == 3){
|
||||||
|
// for bool
|
||||||
|
valCount += values.length;
|
||||||
|
}else {
|
||||||
|
// for other
|
||||||
|
}
|
||||||
|
if (this.udata == 0) {
|
||||||
|
this.udata = this.data + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.udlen += values.length;
|
||||||
|
Nodave.setUSBEWord(this.mem, this.data + 2, valCount);
|
||||||
|
this.addData(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int addVarToReadRequest(final DaveArea area, final int DBnum, int start, final int len) {
|
||||||
|
final byte[] pa = {
|
||||||
|
0x12, //结构表示,一般默认 0x12
|
||||||
|
0x0a, //此字节往后的字节数
|
||||||
|
0x10, //Syntax id:S7ANY (0X10) (决定寻址方式,0x10表示any-type)
|
||||||
|
0x02, //Transport size 数据类型 ,,看附录7 //todo 这里是有点问题的 不同的数据类型这里的参数是不同的,后续自己修改吧。
|
||||||
|
0x00, 0x1A, /* length of data in bytes ( 2 bytes ),就是读几个长度 如有些变量是数组 ,这里就是数组长度,如果是非数组变量那么这里都是1 */
|
||||||
|
0x00, 0x0B, /* DB块编号 */
|
||||||
|
(byte) 0x84, // * area code ,也就是 DaveArea.DB数据区 */
|
||||||
|
0x00, 0x00, (byte) 0xC0 /* 0-2bit 是Bit Address,3-18bit 是Byte Address */
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
|
||||||
|
pa[3] = 4;
|
||||||
|
start *= 8; /* bits */
|
||||||
|
} else if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
|
||||||
|
|| (area == DaveArea.COUNTER200)) {
|
||||||
|
pa[3] = (byte) area.getCode();
|
||||||
|
} else {
|
||||||
|
start *= 8; /* 乘以8 相当于把这个偏移量向左移动了 3位 */
|
||||||
|
}
|
||||||
|
//把len =》 2个字节 并且填充到 pa数组 对应位置(pa[4]、pa[5])。
|
||||||
|
Nodave.setUSBEWord(pa, 4, len);
|
||||||
|
Nodave.setUSBEWord(pa, 6, DBnum);
|
||||||
|
//start 是这个db块的偏移量。。。。 //todo 其实这里简单处理了 ,是分Byte address 和 Bit address的
|
||||||
|
Nodave.setUSBELong(pa, 8, start);
|
||||||
|
Nodave.setUSByte(pa, 8, area.getCode());
|
||||||
|
|
||||||
|
//因为add了 Var 所以要 ,item count ++ ;;this.param + 1 位置就是Item count位置
|
||||||
|
this.mem[this.param + 1]++;
|
||||||
|
|
||||||
|
//把 构建好的 param(Var Item) 加入到 Read Request 字节流里面去。
|
||||||
|
System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
|
||||||
|
this.plen += pa.length;
|
||||||
|
//要读的 var item 也算 参数的 所以也算在param length里面。
|
||||||
|
Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
|
||||||
|
/**
|
||||||
|
* TODO calc length of result. Do not add variable if it would exceed
|
||||||
|
* max. result length.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
public int addVarToReadRequest(final DaveArea area, final int DBnum, int byteAddress,int bitAddress, final int len,final TransportSize transportSize) {
|
||||||
|
final byte[] pa = {
|
||||||
|
0x12, //结构表示,一般默认 0x12
|
||||||
|
0x0a, //此字节往后的字节数
|
||||||
|
0x10, //Syntax id:S7ANY (0X10) (决定寻址方式,0x10表示any-type)(把这个认为是固定就行了)
|
||||||
|
0x02, //Transport size 数据类型 ,,看附录7 //todo 这里是有点问题的 不同的数据类型这里的参数是不同的,后续自己修改吧。
|
||||||
|
0x00, 0x1A, /* length of data in bytes ( 2 bytes ),就是读几个长度 如有些变量是数组 ,这里就是数组长度,如果是非数组变量那么这里都是1 */
|
||||||
|
0x00, 0x0B, /* DB块编号 */
|
||||||
|
(byte) 0x84, // * area code ,也就是 DaveArea.DB数据区 */
|
||||||
|
0x00, 0x00, (byte) 0xC0 /* 0-2bit 是Bit Address,3-18bit 是Byte Address */
|
||||||
|
};
|
||||||
|
|
||||||
|
if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
|
||||||
|
pa[3] = 4;
|
||||||
|
byteAddress *= 8; /* bits */
|
||||||
|
} else if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
|
||||||
|
|| (area == DaveArea.COUNTER200)) {
|
||||||
|
pa[3] = (byte) area.getCode();
|
||||||
|
} else {
|
||||||
|
///* 乘以8 相当于把这个偏移量向左移动了 3位,,向左移动3位的原因是为了 给bitAddress 让路 */
|
||||||
|
byteAddress *= 8;
|
||||||
|
//把 bitAddress 赋予后三位
|
||||||
|
byteAddress += bitAddress;
|
||||||
|
}
|
||||||
|
pa[3] = Byte.valueOf(Short.toString(transportSize.getCode()));
|
||||||
|
|
||||||
|
//把len =》 2个字节 并且填充到 pa数组 对应位置(pa[4]、pa[5])。
|
||||||
|
Nodave.setUSBEWord(pa, 4, len);
|
||||||
|
Nodave.setUSBEWord(pa, 6, DBnum);
|
||||||
|
//start 是这个db块的偏移量。。。。 //todo 其实这里简单处理了 ,是分Byte address 和 Bit address的
|
||||||
|
Nodave.setUSBELong(pa, 8, byteAddress);
|
||||||
|
Nodave.setUSByte(pa, 8, area.getCode());
|
||||||
|
|
||||||
|
//因为add了 Var 所以要 ,item count ++ ;;this.param + 1 位置就是Item count位置
|
||||||
|
this.mem[this.param + 1]++;
|
||||||
|
|
||||||
|
//把 构建好的 param(Var Item) 加入到 Read Request 字节流里面去。
|
||||||
|
System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
|
||||||
|
this.plen += pa.length;
|
||||||
|
//要读的 var item 也算 参数的 所以也算在param length里面。
|
||||||
|
Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
|
||||||
|
/**
|
||||||
|
* TODO calc length of result. Do not add variable if it would exceed
|
||||||
|
* max. result length.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void addVarToWriteRequest(final DaveArea area, final int DBnum, int byteOffset, int bitOffset, final int byteCount,
|
||||||
|
final byte[] buffer, PlcVar var) {
|
||||||
|
final byte da[] = { 0, 4, 0, 0, };
|
||||||
|
final byte pa[] = {
|
||||||
|
0x12,
|
||||||
|
0x0a,
|
||||||
|
0x10,
|
||||||
|
0x02, //Transport size 数据类型 ,,看附录7 //todo 这里是有点问题的 不同的数据类型这里的参数是不同的,后续自己修改吧。
|
||||||
|
/* unit (for count?, for consistency?) byte */
|
||||||
|
0, 0, /* length in bytes */
|
||||||
|
0, 0, /* DB number */
|
||||||
|
0, /* area code */
|
||||||
|
0, 0, 0 /* start address in bits */
|
||||||
|
};
|
||||||
|
if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
|
||||||
|
|| (area == DaveArea.COUNTER200)) {
|
||||||
|
pa[3] = (byte) area.getCode();
|
||||||
|
pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
|
||||||
|
pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
|
||||||
|
} else if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
|
||||||
|
pa[3] = 4;
|
||||||
|
pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
|
||||||
|
pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
|
||||||
|
} else {
|
||||||
|
pa[4] = (byte) (byteCount / 0x100);
|
||||||
|
pa[5] = (byte) (byteCount & 0xff);
|
||||||
|
}
|
||||||
|
pa[6] = (byte) (DBnum / 256);
|
||||||
|
pa[7] = (byte) (DBnum & 0xff);
|
||||||
|
pa[8] = (byte) (area.getCode());
|
||||||
|
|
||||||
|
//设置parameter item 的 transportsize
|
||||||
|
pa[3] = (byte) var.getTransportSize().getCode();
|
||||||
|
|
||||||
|
///* 乘以8 相当于把这个偏移量向左移动了 3位,,向左移动3位的原因是为了 给bitAddress 让路 */
|
||||||
|
byteOffset *= 8;
|
||||||
|
//把 bitAddress 赋予后三位
|
||||||
|
byteOffset += bitOffset;
|
||||||
|
pa[11] = (byte) (byteOffset & 0xff);
|
||||||
|
pa[10] = (byte) ((byteOffset / 0x100) & 0xff);
|
||||||
|
pa[9] = (byte) (byteOffset / 0x10000);
|
||||||
|
if ((this.dlen % 2) != 0) {
|
||||||
|
this.addData(da, 1);
|
||||||
|
}
|
||||||
|
this.mem[this.param + 1]++;
|
||||||
|
if (this.dlen > 0) {
|
||||||
|
final byte[] saveData = new byte[this.dlen];
|
||||||
|
System.arraycopy(this.mem, this.data, saveData, 0, this.dlen);
|
||||||
|
System.arraycopy(saveData, 0, this.mem, this.data + pa.length, this.dlen);
|
||||||
|
}
|
||||||
|
System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
|
||||||
|
this.plen += pa.length;
|
||||||
|
Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
|
||||||
|
this.data = this.param + this.plen;
|
||||||
|
this.addData(da);
|
||||||
|
//给 keyItem 的transportsize 赋值
|
||||||
|
this.mem[this.data + 1] = (byte) var.getTransportSize().getDataTransportSize().getValue();
|
||||||
|
this.addValue(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addVarToWriteRequest(final DaveArea area, final int DBnum, int start, final int byteCount,
|
||||||
|
final byte[] buffer) {
|
||||||
|
final byte da[] = { 0, 4, 0, 0,};
|
||||||
|
final byte pa[] = { 0x12, 0x0a, 0x10, 0x02,
|
||||||
|
/* unit (for count?, for consistency?) byte */
|
||||||
|
0, 0, /* length in bytes */
|
||||||
|
0, 0, /* DB number */
|
||||||
|
0, /* area code */
|
||||||
|
0, 0, 0 /* start address in bits */
|
||||||
|
};
|
||||||
|
if ((area == DaveArea.TIMER) || (area == DaveArea.COUNTER) || (area == DaveArea.TIMER200)
|
||||||
|
|| (area == DaveArea.COUNTER200)) {
|
||||||
|
pa[3] = (byte) area.getCode();
|
||||||
|
pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
|
||||||
|
pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
|
||||||
|
} else if ((area == DaveArea.ANALOGINPUTS200) || (area == DaveArea.ANALOGOUTPUTS200)) {
|
||||||
|
pa[3] = 4;
|
||||||
|
pa[4] = (byte) (((byteCount + 1) / 2) / 0x100);
|
||||||
|
pa[5] = (byte) (((byteCount + 1) / 2) & 0xff);
|
||||||
|
} else {
|
||||||
|
pa[4] = (byte) (byteCount / 0x100);
|
||||||
|
pa[5] = (byte) (byteCount & 0xff);
|
||||||
|
}
|
||||||
|
pa[6] = (byte) (DBnum / 256);
|
||||||
|
pa[7] = (byte) (DBnum & 0xff);
|
||||||
|
pa[8] = (byte) (area.getCode());
|
||||||
|
start *= 8; /* number of bits */
|
||||||
|
pa[11] = (byte) (start & 0xff);
|
||||||
|
pa[10] = (byte) ((start / 0x100) & 0xff);
|
||||||
|
pa[9] = (byte) (start / 0x10000);
|
||||||
|
if ((this.dlen % 2) != 0) {
|
||||||
|
this.addData(da, 1);
|
||||||
|
}
|
||||||
|
this.mem[this.param + 1]++;
|
||||||
|
if (this.dlen > 0) {
|
||||||
|
final byte[] saveData = new byte[this.dlen];
|
||||||
|
System.arraycopy(this.mem, this.data, saveData, 0, this.dlen);
|
||||||
|
System.arraycopy(saveData, 0, this.mem, this.data + pa.length, this.dlen);
|
||||||
|
}
|
||||||
|
System.arraycopy(pa, 0, this.mem, this.param + this.plen, pa.length);
|
||||||
|
this.plen += pa.length;
|
||||||
|
Nodave.setUSBEWord(this.mem, this.header + 6, this.plen);
|
||||||
|
this.data = this.param + this.plen;
|
||||||
|
|
||||||
|
//下面两个方法,是拼接 keyItem、valueItem
|
||||||
|
this.addData(da);
|
||||||
|
|
||||||
|
this.addValue(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* construct a write request for a single item in PLC memory.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* void constructWriteRequest( int area, int DBnum, int start, int len,
|
||||||
|
* byte[] buffer) { byte pa[] = new byte[14]; byte da[] = { 0, 4, 0, 0 };
|
||||||
|
* pa[0] = PDU.FUNC_WRITE; pa[1] = (byte) 0x01; pa[2] = (byte) 0x12; pa[3] =
|
||||||
|
* (byte) 0x0a; pa[4] = (byte) 0x10; pa[5] = (byte) 0x02;
|
||||||
|
*
|
||||||
|
* Nodave.setUSBEWord(pa, 6, len); Nodave.setUSBEWord(pa, 8, DBnum);
|
||||||
|
* Nodave.setUSBELong(pa, 10, 8 * start); // the bit address
|
||||||
|
* Nodave.setUSByte(pa, 10, area); initHeader(1); addParam(pa); addData(da);
|
||||||
|
* addValue(buffer); if ((Nodave.Debug & Nodave.DEBUG_PDU) != 0) { dump(); }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* display information about a PDU
|
||||||
|
*/
|
||||||
|
public void dump() {
|
||||||
|
Nodave.dump("PDU header ", this.mem, this.header, this.hlen);
|
||||||
|
System.out.println("plen: " + this.plen + " dlen: " + this.dlen);
|
||||||
|
Nodave.dump("Parameter", this.mem, this.param, this.plen);
|
||||||
|
if (this.dlen > 0) {
|
||||||
|
Nodave.dump("Data ", this.mem, this.data, this.dlen);
|
||||||
|
}
|
||||||
|
if (this.udlen > 0) {
|
||||||
|
Nodave.dump("result Data ", this.mem, this.udata, this.udlen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getError() {
|
||||||
|
return this.error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the function code of the PDU
|
||||||
|
*/
|
||||||
|
public int getFunc() {
|
||||||
|
return Nodave.USByte(this.mem, this.param + 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* typedef struct { uc P; // allways 0x32 uc type; // a type? type 2 and 3
|
||||||
|
* headers are two bytes longer. uc a,b; // currently unknown us number; //
|
||||||
|
* Number, can be used to identify answers corresponding to requests us
|
||||||
|
* plen; // length of parameters which follow this header us dlen; // length
|
||||||
|
* of data which follows the parameters uc x[2]; // only present in type 2
|
||||||
|
* and 3 headers. This may contain error information. } PDUHeader;
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* return the number of the PDU
|
||||||
|
*/
|
||||||
|
public int getNumber() {
|
||||||
|
return Nodave.USBEWord(this.mem, this.header + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* reserve space for the header of a new PDU
|
||||||
|
*/
|
||||||
|
public void initHeader(final int type) {
|
||||||
|
//注意 这里的type 就是下面的 MSG Type(消息类型)
|
||||||
|
if ((type == 2) || (type == 3)) {
|
||||||
|
this.hlen = 12;
|
||||||
|
} else {
|
||||||
|
this.hlen = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
//给S7-Header 初始化 全部初始化为0
|
||||||
|
for (int i = 0; i < this.hlen; i++) {
|
||||||
|
//mem 代表msgOut
|
||||||
|
this.mem[this.header + i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//this.param 是 param的起始位置,是在 initHeader 被初始化的,(7+10) = 17= this.param (因为数组从0开始,所以17这个位置刚好是param的起始位置)
|
||||||
|
this.param = this.header + this.hlen;
|
||||||
|
//protocol id 协议id ,默认0x32
|
||||||
|
this.mem[this.header] = (byte) 0x32;
|
||||||
|
//MSG Type(1byte): 消息类型 :
|
||||||
|
//0x01:工作请求(Job Request);
|
||||||
|
//0x02:确认(Ack),主要是由设备请求,不携带数据;
|
||||||
|
//0x03:响应数据(Ack-Data),响应0x01的请求;
|
||||||
|
//0x07:自定义数据(Userdata),扩展协议类型
|
||||||
|
this.mem[this.header + 1] = (byte) type;
|
||||||
|
|
||||||
|
|
||||||
|
//dlen = data length ( 报文中存在两个字节 )
|
||||||
|
this.dlen = 0;
|
||||||
|
//plen = param length ( 报文中存在两个字节 )
|
||||||
|
this.plen = 0;
|
||||||
|
//udlen = protocol data unit reference length
|
||||||
|
this.udlen = 0;
|
||||||
|
this.data = 0;
|
||||||
|
//udata = protocol data unit reference
|
||||||
|
this.udata = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void initReadRequest() {
|
||||||
|
final byte pa[] = new byte[2];
|
||||||
|
pa[0] = PDU.FUNC_READ;
|
||||||
|
pa[1] = (byte) 0x00;
|
||||||
|
this.initHeader(1);
|
||||||
|
this.addParam(pa);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prepare a read request with no item.
|
||||||
|
*/
|
||||||
|
public void prepareReadRequest() {
|
||||||
|
final byte pa[] = new byte[2];
|
||||||
|
pa[0] = PDU.FUNC_READ;
|
||||||
|
pa[1] = (byte) 0x00;
|
||||||
|
this.initHeader(1);
|
||||||
|
this.addParam(pa);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prepare a write request with no item.
|
||||||
|
*/
|
||||||
|
public void prepareWriteRequest() {
|
||||||
|
final byte pa[] = new byte[2];
|
||||||
|
pa[0] = PDU.FUNC_WRITE;
|
||||||
|
pa[1] = (byte) 0x00;
|
||||||
|
this.initHeader(1);
|
||||||
|
this.addParam(pa);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set the number of the PDU
|
||||||
|
*/
|
||||||
|
public void setNumber(final int n) {
|
||||||
|
Nodave.setUSBEWord(this.mem, this.header + 4, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup a PDU instance to reflect the structure of data present in the
|
||||||
|
* memory area given to initHeader. Needs valid header.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public int setupReceivedPDU() {
|
||||||
|
int res = Nodave.RESULT_CANNOT_EVALUATE_PDU; // just assume the worst
|
||||||
|
//this.mem[this.header + 1]( ROSCTR ) 就是MSG TYPE =2 (确认(Ack),主要是由设备请求,不携带数据) ;;MSG TYPE =3 (响应数据(Ack-Data),响应0x01的请求)
|
||||||
|
if ((this.mem[this.header + 1] == 2) || (this.mem[this.header + 1] == 3)) {
|
||||||
|
this.hlen = 12;
|
||||||
|
//this.header + 10 就是 Error class(看附录3)/code(看附录4)
|
||||||
|
//todo this.header + 10 其实是一个字节一个字节的 不能像下面这样读两个字节。(其实这种也行的,因为这样就能够 同时判断两个信息 是否同时为0,如果同时为0 有一个不为0 就代表都不ok)
|
||||||
|
res = Nodave.USBEWord(this.mem, this.header + 10);
|
||||||
|
} else {
|
||||||
|
this.error = 0;
|
||||||
|
this.hlen = 10;
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
//外部初始化的 header == 7(4字节TPKT + 3个字节COTP)
|
||||||
|
//this.param = 7+12 = 19;
|
||||||
|
this.param = this.header + this.hlen;
|
||||||
|
//读取S7-Header 里面的Param-length(2个字节转为word ok)
|
||||||
|
this.plen = Nodave.USBEWord(this.mem, this.header + 6);
|
||||||
|
//this.param(19 固定的如果是ACK) + this.plen(2 是固定的应为就两个参数)
|
||||||
|
this.data = this.param + this.plen;
|
||||||
|
|
||||||
|
//读取S7-Header 里面的Data-length(2个字节转为word ok)
|
||||||
|
this.dlen = Nodave.USBEWord(this.mem, this.header + 8);
|
||||||
|
this.udlen = 0;
|
||||||
|
this.udata = 0;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int testResultData() {
|
||||||
|
int res = Nodave.RESULT_CANNOT_EVALUATE_PDU; // just assume the worst
|
||||||
|
//当响应成功的情况 //todo here read
|
||||||
|
if ((this.mem[this.data] == (byte) 255) && (this.dlen > 4)) {
|
||||||
|
res = Nodave.RESULT_OK;
|
||||||
|
//udata 代表的是read response 里面 Data=>Item=>n个字节的实际数据bytes
|
||||||
|
this.udata = this.data + 4;
|
||||||
|
// udlen=data[2]*0x100+data[3];
|
||||||
|
//udlen = udata length 就是实际承载value 的byte[] 长度
|
||||||
|
this.udlen = Nodave.USBEWord(this.mem, this.data + 2);
|
||||||
|
|
||||||
|
// ==4 是走byte流,通过转义字节来 来解码真是value。。 看附录8
|
||||||
|
if (this.mem[this.data + 1] == 4) {
|
||||||
|
//注意 这里的数据响应长度 单位 是bit 不是 byte,因为 用bit 表示才准确,比如像bit类型 他并不需要一个字节
|
||||||
|
//往右移3位,就相当于 除以8 ,把 bit 转成 byte //todo 这个需要和read request关联的,后续如果要开发点位的功能 再说。
|
||||||
|
this.udlen >>= 3; /* len is in bits, adjust */
|
||||||
|
} else if (this.mem[this.data + 1] == 9) {
|
||||||
|
/* len is already in bytes, ok */
|
||||||
|
} else if (this.mem[this.data + 1] == 3) {
|
||||||
|
/* len is in bits, but there is a byte per result bit, ok */
|
||||||
|
} else {
|
||||||
|
res = Nodave.RESULT_UNKNOWN_DATA_UNIT_SIZE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//当响应不成功的情况
|
||||||
|
//this.mem[this.data] 是return code (成功或者失败)
|
||||||
|
res = this.mem[this.data];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int testPGReadResult() {
|
||||||
|
if (this.mem[this.param] != 0) {
|
||||||
|
return Nodave.RESULT_UNEXPECTED_FUNC;
|
||||||
|
}
|
||||||
|
return this.testResultData();
|
||||||
|
};
|
||||||
|
|
||||||
|
int testReadResult() {
|
||||||
|
if (this.mem[this.param] != FUNC_READ) {
|
||||||
|
return Nodave.RESULT_UNEXPECTED_FUNC;
|
||||||
|
}
|
||||||
|
return this.testResultData();
|
||||||
|
}
|
||||||
|
|
||||||
|
int testWriteResult() {
|
||||||
|
int res = Nodave.RESULT_CANNOT_EVALUATE_PDU;
|
||||||
|
if (this.mem[this.param] != FUNC_WRITE) {
|
||||||
|
return Nodave.RESULT_UNEXPECTED_FUNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((this.mem[this.data] == 255)) {
|
||||||
|
res = Nodave.RESULT_OK;
|
||||||
|
} else {
|
||||||
|
res = this.mem[this.data];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.nodave;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.exception.S7IOException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
public final class PLCinterface {
|
||||||
|
InputStream in;
|
||||||
|
int localMPI; // the adapter's MPI address
|
||||||
|
String name;
|
||||||
|
|
||||||
|
OutputStream out;
|
||||||
|
int protocol; // The kind of transport used on this interface.
|
||||||
|
int wp, rp;
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(PLCinterface.class);
|
||||||
|
public PLCinterface(final OutputStream out, final InputStream in, final String name, final int localMPI,
|
||||||
|
final int protocol) {
|
||||||
|
this.init(out, in, name, localMPI, protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(final OutputStream oStream, final InputStream iStream, final String name, final int localMPI,
|
||||||
|
final int protocol) {
|
||||||
|
this.out = oStream;
|
||||||
|
this.in = iStream;
|
||||||
|
this.name = name;
|
||||||
|
this.localMPI = localMPI;
|
||||||
|
this.protocol = protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read(final byte[] b, int start, int len){
|
||||||
|
int res;
|
||||||
|
try {
|
||||||
|
int retry = 0;
|
||||||
|
//while ((this.in.available() <= 0) && (retry < 500)) {
|
||||||
|
//如果网络延迟比较大 改下这里(如果把这个数值改大了,那么性能会降低)
|
||||||
|
while ((this.in.available() <= 0) && (retry < 1000)) {
|
||||||
|
try {
|
||||||
|
if (retry > 0) {
|
||||||
|
Thread.sleep(1);
|
||||||
|
}
|
||||||
|
retry++;
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
logger.info("Socket read wait字节流失败,in.available: "+this.in.available()+" ,retry: "+retry+" , errMsg: "+e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res = -1;
|
||||||
|
while ((this.in.available() > 0) && (len > 0)) {
|
||||||
|
res = this.in.read(b, start, len);
|
||||||
|
start += res;
|
||||||
|
len -= res;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
} catch (final IOException e) {
|
||||||
|
String errMsg = "Socket read字节流失败: "+e.getMessage();
|
||||||
|
logger.info(errMsg);
|
||||||
|
throw new S7IOException(errMsg);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return :
|
||||||
|
* 1 成功
|
||||||
|
* 0 失败
|
||||||
|
* */
|
||||||
|
public int write(final byte[] b, final int start, final int len){
|
||||||
|
try {
|
||||||
|
this.out.write(b, start, len);
|
||||||
|
return 1;
|
||||||
|
} catch (final IOException e) {
|
||||||
|
String errMsg = "Socket write字节流失败: "+e.getMessage();
|
||||||
|
logger.info(errMsg);
|
||||||
|
throw new S7IOException(errMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.nodave;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Thomas Hergenhahn
|
||||||
|
*
|
||||||
|
* To change the template for this generated type comment go to
|
||||||
|
* Window>Preferences>Java>Code Generation>Code and Comments
|
||||||
|
*/
|
||||||
|
public final class Result {
|
||||||
|
public int bufferStart;
|
||||||
|
public int error;
|
||||||
|
public int length;
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.nodave;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Thomas Hergenhahn
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class ResultSet {
|
||||||
|
private int errorState, numResults;
|
||||||
|
public Result[] results;
|
||||||
|
|
||||||
|
public int getErrorState() {
|
||||||
|
return this.errorState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNumResults() {
|
||||||
|
return this.numResults;
|
||||||
|
};
|
||||||
|
|
||||||
|
public void setErrorState(final int error) {
|
||||||
|
this.errorState = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNumResults(final int nr) {
|
||||||
|
this.numResults = nr;
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,503 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.nodave;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.DaveArea;
|
||||||
|
import com.cnbm.s7.s7connector.exception.S7IOException;
|
||||||
|
import com.cnbm.s7.s7connector.type.PlcVar;
|
||||||
|
import com.cnbm.s7.s7connector.type.TransportSize;
|
||||||
|
|
||||||
|
import java.util.concurrent.Semaphore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class comprises the variables and methods common to connections to an S7
|
||||||
|
* PLC regardless of the type of transport.
|
||||||
|
*
|
||||||
|
* @author Thomas Hergenhahn
|
||||||
|
*/
|
||||||
|
public abstract class S7Connection {
|
||||||
|
static int tmo_normal = 150;
|
||||||
|
int answLen; // length of last message
|
||||||
|
/**
|
||||||
|
* position in result data, incremented when variables are extracted without
|
||||||
|
* position
|
||||||
|
*/
|
||||||
|
int dataPointer;
|
||||||
|
PLCinterface iface; // pointer to used interface
|
||||||
|
public int maxPDUlength; //第二次握手里 的 PDU Length(2个字节)
|
||||||
|
public byte messageNumber = 0;
|
||||||
|
|
||||||
|
//msgIn 和 msgOut 同理
|
||||||
|
public byte[] msgIn;
|
||||||
|
//msgOut 确实是当前TcpConnection共用的,但不影响每次write,因为每次发送都会修改msgOut
|
||||||
|
public byte[] msgOut;
|
||||||
|
|
||||||
|
public int packetNumber = 0; // packetNumber in transport layer
|
||||||
|
public int PDUstartIn;
|
||||||
|
public int PDUstartOut;
|
||||||
|
PDU rcvdPDU;
|
||||||
|
public Semaphore semaphore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* absolute begin of result data
|
||||||
|
*/
|
||||||
|
int udata;
|
||||||
|
|
||||||
|
public S7Connection(final PLCinterface ifa) {
|
||||||
|
this.iface = ifa;
|
||||||
|
this.msgIn = new byte[Nodave.MAX_RAW_LEN];
|
||||||
|
this.msgOut = new byte[Nodave.MAX_RAW_LEN];
|
||||||
|
this.PDUstartIn = 0;
|
||||||
|
this.PDUstartOut = 0;
|
||||||
|
this.semaphore = new Semaphore(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public int exchange(PDU p1);
|
||||||
|
|
||||||
|
// int numResults;
|
||||||
|
/*
|
||||||
|
* class Result { int error; byte[] data; }
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Read a predefined set of values from the PLC. Return ok or an error state
|
||||||
|
* If a buffer pointer is provided, data will be copied into this buffer. If
|
||||||
|
* it's NULL you can get your data from the resultPointer in daveConnection
|
||||||
|
* long as you do not send further requests.
|
||||||
|
*/
|
||||||
|
public ResultSet execReadRequest(final PDU p) throws Exception {
|
||||||
|
PDU p2;
|
||||||
|
int errorState;
|
||||||
|
errorState = this.exchange(p);
|
||||||
|
|
||||||
|
p2 = new PDU(this.msgIn, this.PDUstartIn);
|
||||||
|
p2.setupReceivedPDU();
|
||||||
|
/*
|
||||||
|
* if (p2.udlen == 0) { dataPointer = 0; answLen = 0; return
|
||||||
|
* Nodave.RESULT_CPU_RETURNED_NO_DATA; }
|
||||||
|
*/
|
||||||
|
final ResultSet rs = new ResultSet();
|
||||||
|
if (p2.mem[p2.param + 0] == PDU.FUNC_READ) {
|
||||||
|
int numResults = p2.mem[p2.param + 1];
|
||||||
|
// System.out.println("Results " + numResults);
|
||||||
|
rs.results = new Result[numResults];
|
||||||
|
int pos = p2.data;
|
||||||
|
for (int i = 0; i < numResults; i++) {
|
||||||
|
final Result r = new Result();
|
||||||
|
r.error = Nodave.USByte(p2.mem, pos);
|
||||||
|
if (r.error == 255) {
|
||||||
|
|
||||||
|
final int type = Nodave.USByte(p2.mem, pos + 1);
|
||||||
|
int len = Nodave.USBEWord(p2.mem, pos + 2);
|
||||||
|
r.error = 0;
|
||||||
|
// System.out.println("Raw length " + len);
|
||||||
|
if (type == 4) {
|
||||||
|
len /= 8;
|
||||||
|
} else if (type == 3) {
|
||||||
|
; // length is ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// System.out.println("Byte length " + len);
|
||||||
|
// r.data = new byte[len];
|
||||||
|
|
||||||
|
// System.arraycopy(p2.mem, pos + 4, r.data, 0, len);
|
||||||
|
// Nodave.dump("Result " + i + ":", r.data, 0, len);
|
||||||
|
r.bufferStart = pos + 4;
|
||||||
|
pos += len;
|
||||||
|
if ((len % 2) == 1) {
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("Error " + r.error);
|
||||||
|
}
|
||||||
|
pos += 4;
|
||||||
|
rs.results[i] = r;
|
||||||
|
}
|
||||||
|
numResults = p2.mem[p2.param + 1];
|
||||||
|
rs.setNumResults(numResults);
|
||||||
|
this.dataPointer = p2.udata;
|
||||||
|
this.answLen = p2.udlen;
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
errorState |= 2048;
|
||||||
|
}
|
||||||
|
this.semaphore.release();
|
||||||
|
rs.setErrorState(errorState);
|
||||||
|
return rs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBYTE() {
|
||||||
|
this.dataPointer += 1;
|
||||||
|
return Nodave.SByte(this.msgIn, this.dataPointer - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBYTE(final int pos) {
|
||||||
|
return Nodave.SByte(this.msgIn, this.udata + pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCHAR() {
|
||||||
|
this.dataPointer += 1;
|
||||||
|
return Nodave.SByte(this.msgIn, this.dataPointer - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCHAR(final int pos) {
|
||||||
|
return Nodave.SByte(this.msgIn, this.udata + pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a signed 32bit value from the current position in result bytes
|
||||||
|
*/
|
||||||
|
public long getDINT() {
|
||||||
|
this.dataPointer += 4;
|
||||||
|
return Nodave.SBELong(this.msgIn, this.dataPointer - 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a signed 32bit value from the specified position in result bytes
|
||||||
|
*/
|
||||||
|
public long getDINT(final int pos) {
|
||||||
|
return Nodave.SBELong(this.msgIn, this.udata + pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get an unsigned 32bit value from the specified position in result bytes
|
||||||
|
*/
|
||||||
|
public long getDWORD(final int pos) {
|
||||||
|
// System.out.println("getDWORD pos " + pos);
|
||||||
|
return Nodave.USBELong(this.msgIn, this.udata + pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a float value from the current position in result bytes
|
||||||
|
*/
|
||||||
|
public float getFloat() {
|
||||||
|
this.dataPointer += 4;
|
||||||
|
return Nodave.BEFloat(this.msgIn, this.dataPointer - 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following methods are here to give Siemens users their usual data
|
||||||
|
* types:
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* get a float value from the specified position in result bytes
|
||||||
|
*/
|
||||||
|
public float getFloat(final int pos) {
|
||||||
|
// System.out.println("getFloat pos " + pos);
|
||||||
|
return Nodave.BEFloat(this.msgIn, this.udata + pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getINT() {
|
||||||
|
this.dataPointer += 2;
|
||||||
|
return Nodave.SBEWord(this.msgIn, this.dataPointer - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getINT(final int pos) {
|
||||||
|
return Nodave.SBEWord(this.msgIn, this.udata + pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPPIresponse() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* public void sendYOURTURN() { }
|
||||||
|
*/
|
||||||
|
public int getResponse() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getS16(final int pos) {
|
||||||
|
return Nodave.SBEWord(this.msgIn, this.udata + pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getS32(final int pos) {
|
||||||
|
return Nodave.SBELong(this.msgIn, this.udata + pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getS8(final int pos) {
|
||||||
|
return Nodave.SByte(this.msgIn, this.udata + pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get an unsigned 32bit value from the current position in result bytes
|
||||||
|
*/
|
||||||
|
public long getU32() {
|
||||||
|
this.dataPointer += 4;
|
||||||
|
return Nodave.USBELong(this.msgIn, this.dataPointer - 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUS16(final int pos) {
|
||||||
|
return Nodave.USBEWord(this.msgIn, this.udata + pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getUS32(final int pos) {
|
||||||
|
return Nodave.USBELong(this.msgIn, this.udata + pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUS8(final int pos) {
|
||||||
|
return Nodave.USByte(this.msgIn, this.udata + pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get an unsigned 16bit value from the current position in result bytes
|
||||||
|
*/
|
||||||
|
public int getWORD() {
|
||||||
|
this.dataPointer += 2;
|
||||||
|
return Nodave.USBEWord(this.msgIn, this.dataPointer - 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get an unsigned 16bit value from the specified position in result bytes
|
||||||
|
*/
|
||||||
|
public int getWORD(final int pos) {
|
||||||
|
return Nodave.USBEWord(this.msgIn, this.udata + pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* build the PDU for a PDU length negotiation
|
||||||
|
* 构建第二次握手
|
||||||
|
*/
|
||||||
|
public int negPDUlengthRequest() throws Exception {
|
||||||
|
int res;
|
||||||
|
final PDU p = new PDU(this.msgOut, this.PDUstartOut);
|
||||||
|
//S7-Param 构造
|
||||||
|
final byte pa[] = {
|
||||||
|
(byte) 0xF0, //Function:step Communication
|
||||||
|
0, //Reserved
|
||||||
|
0x00, //Max AmQ (parallel jobs with ack) calling,也就是说这个connection每次只能调用1次 ;;2个字节
|
||||||
|
0x01,
|
||||||
|
0x00, //Max AmQ (parallel jobs with ack) called,也就是说这个connection每次只能被调用1次 ;; 2个字节
|
||||||
|
0x01,
|
||||||
|
0x03, //PDU Length (2个字节) //这里是960 ,,一般是240/480/960 主要是和CPU型号有关的。
|
||||||
|
(byte) 0xC0,
|
||||||
|
};
|
||||||
|
//初始化 S7 Header长度
|
||||||
|
p.initHeader(1);
|
||||||
|
//加载 param 参数到 请求里面去
|
||||||
|
p.addParam(pa);
|
||||||
|
//构建第二次握手cotp 部分
|
||||||
|
res = this.exchange(p);
|
||||||
|
if (res != 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建第二次握手 S7COMM 的接收容器。
|
||||||
|
final PDU p2 = new PDU(this.msgIn, this.PDUstartIn);
|
||||||
|
res = p2.setupReceivedPDU();
|
||||||
|
if (res != 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
this.maxPDUlength = Nodave.USBEWord(this.msgIn, p2.param +6);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
//reutrn
|
||||||
|
// 0 代表成功
|
||||||
|
// 1 代表失败
|
||||||
|
// 异常 就会抛出异常
|
||||||
|
public int readBytes(final DaveArea area, final int DBnum, final int start, final int len, final byte[] buffer) {
|
||||||
|
int res = 0;
|
||||||
|
try {
|
||||||
|
//信号量 ,加锁,,防止多处并发访问
|
||||||
|
this.semaphore.acquire();
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建 request PDU
|
||||||
|
final PDU p1 = new PDU(this.msgOut, this.PDUstartOut);
|
||||||
|
p1.initReadRequest();
|
||||||
|
p1.addVarToReadRequest(area, DBnum, start, len);
|
||||||
|
//通过tcp链接 发送read var request,thr S7IOException
|
||||||
|
res = this.exchange(p1);
|
||||||
|
if (res != Nodave.RESULT_OK) {
|
||||||
|
this.semaphore.release();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建 response PDU ,, 注意这里的msgIn 就是接收到的 plc=》上位机 的字节流
|
||||||
|
final PDU p2 = new PDU(this.msgIn, this.PDUstartIn);
|
||||||
|
// 这里配置received PUD参数。
|
||||||
|
res = p2.setupReceivedPDU();
|
||||||
|
if (res != Nodave.RESULT_OK) {
|
||||||
|
this.semaphore.release();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = p2.testReadResult();
|
||||||
|
if (res != Nodave.RESULT_OK) {
|
||||||
|
this.semaphore.release();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if (p2.udlen == 0) {
|
||||||
|
this.semaphore.release();
|
||||||
|
return Nodave.RESULT_CPU_RETURNED_NO_DATA;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* copy to user buffer and setup internal buffer pointers:
|
||||||
|
* 判断外部确实 外部是否真实传 buffer 这个字节容器进来。
|
||||||
|
*/
|
||||||
|
if (buffer != null) {
|
||||||
|
// System.err.println("p1.udlen:"+p1.udlen+",,udlen:"+ p2.udlen +",,"+"bufferSize:"+buffer.length);
|
||||||
|
// if(p2.udlen>buffer.length){
|
||||||
|
// p2.udlen = buffer.length;
|
||||||
|
// }
|
||||||
|
System.arraycopy(p2.mem, p2.udata, buffer, 0, p2.udlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dataPointer = p2.udata;
|
||||||
|
this.udata = p2.udata;
|
||||||
|
this.answLen = p2.udlen;
|
||||||
|
this.semaphore.release();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
//reutrn
|
||||||
|
// 0 代表成功
|
||||||
|
// 1 代表失败
|
||||||
|
// 异常 就会抛出异常
|
||||||
|
//start == byteAddress ;; bitStart ==
|
||||||
|
public int readBytes(final DaveArea area, final int DBnum, final int byteAddress, final int bitAddress, final int len, final byte[] buffer, TransportSize transportSize) {
|
||||||
|
int res = 0;
|
||||||
|
try {
|
||||||
|
//信号量 ,加锁,,防止多处并发访问
|
||||||
|
this.semaphore.acquire();
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建 request PDU
|
||||||
|
final PDU p1 = new PDU(this.msgOut, this.PDUstartOut);
|
||||||
|
p1.initReadRequest();
|
||||||
|
p1.addVarToReadRequest(area, DBnum, byteAddress,bitAddress, len,transportSize);
|
||||||
|
//发送read var request
|
||||||
|
res = this.exchange(p1);
|
||||||
|
if (res != Nodave.RESULT_OK) {
|
||||||
|
this.semaphore.release();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
//构建 response PDU ,, 注意这里的msgIn 就是接收到的 plc=》上位机 的字节流
|
||||||
|
final PDU p2 = new PDU(this.msgIn, this.PDUstartIn);
|
||||||
|
// 这里配置received PUD参数。
|
||||||
|
res = p2.setupReceivedPDU();
|
||||||
|
if (res != Nodave.RESULT_OK) {
|
||||||
|
this.semaphore.release();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = p2.testReadResult();
|
||||||
|
if (res != Nodave.RESULT_OK) {
|
||||||
|
this.semaphore.release();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if (p2.udlen == 0) {
|
||||||
|
this.semaphore.release();
|
||||||
|
return Nodave.RESULT_CPU_RETURNED_NO_DATA;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* copy to user buffer and setup internal buffer pointers:
|
||||||
|
* 判断外部确实 外部是否真实传 buffer 这个字节容器进来。
|
||||||
|
*/
|
||||||
|
if (buffer != null) {
|
||||||
|
System.arraycopy(p2.mem, p2.udata, buffer, 0, p2.udlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dataPointer = p2.udata;
|
||||||
|
this.udata = p2.udata;
|
||||||
|
this.answLen = p2.udlen;
|
||||||
|
this.semaphore.release();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int sendMsg(final PDU p) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendRequestData(final int alt) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public int useResult(final ResultSet rs, final int number) {
|
||||||
|
System.out.println("rs.getNumResults: " + rs.getNumResults() + " number: " + number);
|
||||||
|
if (rs.getNumResults() > number) {
|
||||||
|
this.dataPointer = rs.results[number].bufferStart;
|
||||||
|
return 0;
|
||||||
|
// udata=rs.results[number].bufferStart;
|
||||||
|
}
|
||||||
|
return -33;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write len bytes to PLC memory area "area", data block DBnum.
|
||||||
|
*/
|
||||||
|
public int writeBytes(final DaveArea area, final int DBnum, final int start, final int len, final byte[] buffer) {
|
||||||
|
int errorState = 0;
|
||||||
|
this.semaphore.release();
|
||||||
|
final PDU p1 = new PDU(this.msgOut, this.PDUstartOut);
|
||||||
|
|
||||||
|
// p1.constructWriteRequest(area, DBnum, start, len, buffer);
|
||||||
|
p1.prepareWriteRequest();
|
||||||
|
p1.addVarToWriteRequest(area, DBnum, start, len, buffer);
|
||||||
|
|
||||||
|
errorState = this.exchange(p1);
|
||||||
|
|
||||||
|
if (errorState == 0) {
|
||||||
|
final PDU p2 = new PDU(this.msgIn, this.PDUstartIn);
|
||||||
|
p2.setupReceivedPDU();
|
||||||
|
|
||||||
|
if (p2.mem[p2.param + 0] == PDU.FUNC_WRITE) {
|
||||||
|
if (p2.mem[p2.data + 0] == (byte) 0xFF) {
|
||||||
|
this.semaphore.release();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errorState |= 4096;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.semaphore.release();
|
||||||
|
return errorState;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int writeBytes(final DaveArea area, final int DBnum, final int byteOffset, final int bitOffset, final int len, final byte[] buffer,final PlcVar var) {
|
||||||
|
int errorState = 0;
|
||||||
|
this.semaphore.release();
|
||||||
|
final PDU p1 = new PDU(this.msgOut, this.PDUstartOut);
|
||||||
|
|
||||||
|
// p1.constructWriteRequest(area, DBnum, start, len, buffer);
|
||||||
|
p1.prepareWriteRequest();
|
||||||
|
p1.addVarToWriteRequest(area, DBnum, byteOffset,bitOffset, len, buffer,var);
|
||||||
|
|
||||||
|
errorState = this.exchange(p1);
|
||||||
|
|
||||||
|
if (errorState == 0) {
|
||||||
|
final PDU p2 = new PDU(this.msgIn, this.PDUstartIn);
|
||||||
|
p2.setupReceivedPDU();
|
||||||
|
|
||||||
|
if (p2.mem[p2.param + 0] == PDU.FUNC_WRITE) {
|
||||||
|
if (p2.mem[p2.data + 0] == (byte) 0xFF) {
|
||||||
|
this.semaphore.release();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errorState |= 4096;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.semaphore.release();
|
||||||
|
return errorState;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,187 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.nodave;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.utils.ByteUtils;
|
||||||
|
import com.cnbm.s7.s7connector.exception.S7IOException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Class TCPConnection.
|
||||||
|
*/
|
||||||
|
public final class TCPConnection extends S7Connection {
|
||||||
|
|
||||||
|
/** The rack. */
|
||||||
|
int rack;
|
||||||
|
|
||||||
|
/** The slot. */
|
||||||
|
int slot;
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(TCPConnection.class);
|
||||||
|
/**
|
||||||
|
* Instantiates a new TCP connection.
|
||||||
|
*
|
||||||
|
* @param ifa
|
||||||
|
* the plc interface
|
||||||
|
* @param rack
|
||||||
|
* the rack
|
||||||
|
* @param slot
|
||||||
|
* the slot
|
||||||
|
*/
|
||||||
|
public TCPConnection(final PLCinterface ifa, final int rack, final int slot) {
|
||||||
|
super(ifa);
|
||||||
|
this.rack = rack;
|
||||||
|
this.slot = slot;
|
||||||
|
this.PDUstartIn = 7;
|
||||||
|
//PDUstartOut = 7 是因为在Header部分之前 还有TPKT+COTP报文,并且这两个报文长度加起来一共7个字节。
|
||||||
|
this.PDUstartOut = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We have our own connectPLC(), but no disconnect() Open connection to a
|
||||||
|
* PLC. This assumes that dc is initialized by daveNewConnection and is not
|
||||||
|
* yet used. (or reused for the same PLC ?)
|
||||||
|
*
|
||||||
|
* @return the int
|
||||||
|
*/
|
||||||
|
public int connectPLC() throws Exception {
|
||||||
|
//COTP包 字节流(是上位机 和plc进行的第一次握手)
|
||||||
|
final byte[] b4 = { //b4.length = 18
|
||||||
|
(byte) 0x11, //(16进制)当前字节以后的字节数
|
||||||
|
(byte) 0xE0, //PDU type,连接请求【附录一】
|
||||||
|
(byte) 0x00, (byte) 0x00, //DST reference
|
||||||
|
(byte) 0x00, (byte) 0x01, //SRC reference
|
||||||
|
(byte) 0x00, //固定(Class Extended formats No explilcti flow control)
|
||||||
|
|
||||||
|
(byte) 0xC1, //parameter-code:dst-tsap 上位机
|
||||||
|
(byte) 0x02, //parameter-length
|
||||||
|
(byte) 0x10, //Source TSAP: 0x01->PG; 0x02->OP; 0x03->S7单边通讯(服务端模式); 0x10->S7双边通讯;;; 这里是0x01
|
||||||
|
(byte) 0x00, //机架(rack)(前4个bit位)+ cpu槽位(slot)(后4个bit位) ,, 因为是上位机端 所以这里都是00(rack=0 slot=2)
|
||||||
|
|
||||||
|
(byte) 0xC2, //parameter-code:dst-tsap PLC
|
||||||
|
(byte) 0x02, //parameter-length
|
||||||
|
(byte) 0x03, //Destination TSAP: 0x01->PG; 0x02->OP; 0x03->S7单边通讯(服务端模式); 0x10->S7双边通讯;;; 这里是0x01
|
||||||
|
(byte) 0x01, //机架(rack)(前4个bit位)+ cpu槽位(slot)(后4个bit位),, 西门子200smart、1200、1500默认 机架号=0,槽位号=1 ;;;; 西门子300、400默认 机架号=0,槽位号=2
|
||||||
|
|
||||||
|
(byte) 0xC0, //parameter-code:tpdu-size
|
||||||
|
(byte) 0x01, //parameter-length
|
||||||
|
(byte) 0x09 //TPDU size
|
||||||
|
};
|
||||||
|
|
||||||
|
//把 b4 这个数组从0开始位置 放到 this.msgOut 这个数组 第四个位置后面,放 b4.length 个长度
|
||||||
|
//之所以目的位置4 是因为,前面4个字节是TPKT的内容(第一次握手)
|
||||||
|
// msgOut 是这个socketChannel 往外写的 bytes(上位机 => plc 写) ;msgIn 是指这个socketChanne 外部往里写的bytes(上位机 <= plc 写)
|
||||||
|
System.arraycopy(b4, 0, this.msgOut, 4, b4.length);
|
||||||
|
//this.msgOut[17] = (byte) (this.rack + 1); //这里写的不太对,这里应该是配置dst-tsap(plc)
|
||||||
|
//this.msgOut[18] = (byte) this.slot;
|
||||||
|
this.msgOut[18] = combineToByte(rack,slot);
|
||||||
|
|
||||||
|
this.sendISOPacket(b4.length);
|
||||||
|
this.readISOPacket();
|
||||||
|
/*
|
||||||
|
* PDU p = new PDU(msgOut, 7); p.initHeader(1); p.addParam(b61);
|
||||||
|
* exchange(p); return (0);
|
||||||
|
*/
|
||||||
|
return this.negPDUlengthRequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static byte combineToByte(Integer i,Integer j){
|
||||||
|
Integer cc = ((i << 4)+j);
|
||||||
|
return cc.byteValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建S7COMM 的COTP部分 3个字节(第二次握手)
|
||||||
|
*
|
||||||
|
* return
|
||||||
|
* 1 代表失败
|
||||||
|
* 0 代表成功
|
||||||
|
* */
|
||||||
|
@Override
|
||||||
|
public int exchange(final PDU p1){
|
||||||
|
this.msgOut[4] = (byte) 0x02; //当前字节以后的字节数(也就是下面两个字节)
|
||||||
|
this.msgOut[5] = (byte) 0xf0; //PDU Type
|
||||||
|
this.msgOut[6] = (byte) 0x80; //TPDU number (如果这个字节首位为1 代表就是最后一个传输单元了 如1000 0000 ;; 如果首字母不为1 就代表这个Request是比较长的要分多个unit传输,后7位就代表传输单元序号)
|
||||||
|
int writeRes = this.sendISOPacket(3 + p1.hlen + p1.plen + p1.dlen); //这里 TPKT 和 COTP字节一起发送的。。
|
||||||
|
//这里读到的 ISO_Back_Packet 是暂存在msgIn 这暂存区的,后面可以直接拿里面的数据来构建 ISO_Back_Packet 的PDU
|
||||||
|
int readRes = this.readISOPacket();
|
||||||
|
if(writeRes!=0 && readRes!=0){
|
||||||
|
return 0;
|
||||||
|
}else {
|
||||||
|
//writeRes == 1 && readRes == 0
|
||||||
|
String errMsg = "exchange 出现了问题:① writeRes:"+(writeRes!=0?"writeISOPacket成功":"writeISOPacket失败")+"② readRes:"+(readRes!=0?"readISOPacket成功":"readISOPacket失败");
|
||||||
|
logger.info(errMsg);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read iso packet.
|
||||||
|
*
|
||||||
|
* @return the int
|
||||||
|
* 0 ==> 不成功(异常)
|
||||||
|
* -1 ==> 读到一个空的字节流 (这种情况很少)
|
||||||
|
* 其他 ==> 成功
|
||||||
|
*/
|
||||||
|
protected int readISOPacket(){
|
||||||
|
//read return 为0 就是异常
|
||||||
|
try {
|
||||||
|
int res = this.iface.read(this.msgIn, 0, 4);
|
||||||
|
if (res == 4) {
|
||||||
|
final int len = (0x100 * ByteUtils.toUInt(this.msgIn[2])) + ByteUtils.toUInt(this.msgIn[3]);
|
||||||
|
res += this.iface.read(this.msgIn, 4, len);
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
|
||||||
|
}catch (Exception e){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send iso packet.
|
||||||
|
*
|
||||||
|
* @param size
|
||||||
|
* the size
|
||||||
|
* @return the int
|
||||||
|
* 1 ==> 成功
|
||||||
|
* 0 ==> 不成功(出现异常了)
|
||||||
|
*/
|
||||||
|
protected int sendISOPacket(int size){
|
||||||
|
size += 4;
|
||||||
|
//下面包装的 是TPKT 字节包(第一次握手)
|
||||||
|
this.msgOut[0] = (byte) 0x03; //Version ,默认版本3
|
||||||
|
this.msgOut[1] = (byte) 0x0; //保留字节 ,默认0
|
||||||
|
|
||||||
|
//这两个字节代表请求字节数,通常说都是固定的22,因为 TPKT字节数+COTP字节数 = 22
|
||||||
|
this.msgOut[2] = (byte) (size / 0x100);//高位字节 除以8 取整 就放在高字节
|
||||||
|
this.msgOut[3] = (byte) (size % 0x100);//低位字节 取余8 ,就放在低字节
|
||||||
|
/*
|
||||||
|
* if (messageNumber == 0) { messageNumber = 1; msgOut[11] = (byte)
|
||||||
|
* ((messageNumber + 1) & 0xff); messageNumber++; messageNumber &= 0xff;
|
||||||
|
* //!! }
|
||||||
|
*/
|
||||||
|
|
||||||
|
// System.out.println("send bytes报文: "+ Arrays.toString(this.msgOut)+";报文size:"+this.msgOut.length);
|
||||||
|
//像这种 write 和read 都是 传的是指针,里面数据消费掉了,外部就没了
|
||||||
|
int writeRes = this.iface.write(this.msgOut, 0, size);
|
||||||
|
return writeRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.serializer;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.DaveArea;
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Connector;
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Serializer;
|
||||||
|
import com.cnbm.s7.s7connector.exception.S7Exception;
|
||||||
|
import com.cnbm.s7.s7connector.impl.serializer.parser.BeanEntry;
|
||||||
|
import com.cnbm.s7.s7connector.impl.serializer.parser.BeanParseResult;
|
||||||
|
import com.cnbm.s7.s7connector.impl.serializer.parser.BeanParser;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Class S7Serializer is responsible for serializing S7 TCP Connection
|
||||||
|
*/
|
||||||
|
public final class S7SerializerImpl implements S7Serializer {
|
||||||
|
|
||||||
|
/** Local Logger. */
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(S7SerializerImpl.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts bytes from a buffer.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* the generic type
|
||||||
|
* @param beanClass
|
||||||
|
* the bean class
|
||||||
|
* @param buffer
|
||||||
|
* the buffer
|
||||||
|
* @param byteOffset
|
||||||
|
* the byte offset
|
||||||
|
* @return the t
|
||||||
|
*/
|
||||||
|
public static <T> T extractBytes(final Class<T> beanClass, final byte[] buffer, final int byteOffset) {
|
||||||
|
logger.trace("Extracting type {} from buffer with size: {} at offset {}", beanClass.getName(), buffer.length,
|
||||||
|
byteOffset);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final T obj = beanClass.newInstance();
|
||||||
|
final BeanParseResult result = BeanParser.parse(beanClass);
|
||||||
|
for (final BeanEntry entry : result.entries) {
|
||||||
|
Object value = null;
|
||||||
|
if (entry.isArray) {
|
||||||
|
value = Array.newInstance(entry.type, entry.arraySize);
|
||||||
|
for (int i = 0; i < entry.arraySize; i++) {
|
||||||
|
final Object component = entry.serializer.extract(entry.type, buffer,
|
||||||
|
entry.byteOffset + byteOffset + (i * entry.s7type.getByteSize()),
|
||||||
|
entry.bitOffset + (i * entry.s7type.getBitSize()));
|
||||||
|
Array.set(value, i, component);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = entry.serializer.extract(entry.type, buffer, entry.byteOffset + byteOffset,
|
||||||
|
entry.bitOffset);
|
||||||
|
}
|
||||||
|
entry.field.set(obj, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
} catch (final Exception e) {
|
||||||
|
throw new S7Exception("extractBytes", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inserts the bytes to the buffer.
|
||||||
|
*
|
||||||
|
* @param bean
|
||||||
|
* the bean
|
||||||
|
* @param buffer
|
||||||
|
* the buffer
|
||||||
|
* @param byteOffset
|
||||||
|
* the byte offset
|
||||||
|
*/
|
||||||
|
public static void insertBytes(final Object bean, final byte[] buffer, final int byteOffset) {
|
||||||
|
logger.trace("Inerting buffer with size: {} at offset {} into bean: {}", buffer.length, byteOffset, bean);
|
||||||
|
|
||||||
|
try {
|
||||||
|
final BeanParseResult result = BeanParser.parse(bean);
|
||||||
|
|
||||||
|
for (final BeanEntry entry : result.entries) {
|
||||||
|
final Object fieldValue = entry.field.get(bean);
|
||||||
|
|
||||||
|
if (fieldValue != null) {
|
||||||
|
if (entry.isArray) {
|
||||||
|
for (int i = 0; i < entry.arraySize; i++) {
|
||||||
|
final Object arrayItem = Array.get(fieldValue, i);
|
||||||
|
|
||||||
|
if (arrayItem != null) {
|
||||||
|
entry.serializer.insert(arrayItem, buffer,
|
||||||
|
entry.byteOffset + byteOffset + (i * entry.s7type.getByteSize()),
|
||||||
|
entry.bitOffset + (i * entry.s7type.getBitSize()), entry.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
entry.serializer.insert(fieldValue, buffer, entry.byteOffset + byteOffset, entry.bitOffset,
|
||||||
|
entry.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
|
throw new S7Exception("insertBytes", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The Connector. */
|
||||||
|
private final S7Connector connector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiates a new s7 serializer.
|
||||||
|
*
|
||||||
|
* @param connector
|
||||||
|
* the connector
|
||||||
|
*/
|
||||||
|
public S7SerializerImpl(final S7Connector connector) {
|
||||||
|
this.connector = connector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public synchronized <T> T dispense(final Class<T> beanClass, final int dbNum, final int byteOffset)
|
||||||
|
throws S7Exception {
|
||||||
|
try {
|
||||||
|
final BeanParseResult result = BeanParser.parse(beanClass);
|
||||||
|
final byte[] buffer = this.connector.read(DaveArea.DB, dbNum, result.blockSize, byteOffset);
|
||||||
|
return extractBytes(beanClass, buffer, 0);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
throw new S7Exception("dispense", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public synchronized <T> T dispense(final Class<T> beanClass, final int dbNum, final int byteOffset,
|
||||||
|
final int blockSize) throws S7Exception {
|
||||||
|
try {
|
||||||
|
final byte[] buffer = this.connector.read(DaveArea.DB, dbNum, blockSize, byteOffset);
|
||||||
|
return extractBytes(beanClass, buffer, 0);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
throw new S7Exception(
|
||||||
|
"dispense dbnum(" + dbNum + ") byteoffset(" + byteOffset + ") blocksize(" + blockSize + ")", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public synchronized void store(final Object bean, final int dbNum, final int byteOffset) {
|
||||||
|
try {
|
||||||
|
final BeanParseResult result = BeanParser.parse(bean);
|
||||||
|
|
||||||
|
final byte[] buffer = new byte[result.blockSize];
|
||||||
|
logger.trace("store-buffer-size: " + buffer.length);
|
||||||
|
|
||||||
|
insertBytes(bean, buffer, 0);
|
||||||
|
|
||||||
|
this.connector.write(DaveArea.DB, dbNum, byteOffset, buffer);
|
||||||
|
} catch (final Exception e) {
|
||||||
|
throw new S7Exception("store", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.serializer.converter;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Serializable;
|
||||||
|
import com.cnbm.s7.s7connector.impl.utils.S7Type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Class BitConverter is responsible for converting bit values
|
||||||
|
*/
|
||||||
|
public final class BitConverter implements S7Serializable {
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||||
|
final byte bufValue = buffer[byteOffset];
|
||||||
|
return targetClass.cast(bufValue == (bufValue | (0x01 << bitOffset)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public S7Type getS7Type() {
|
||||||
|
return S7Type.BOOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int getSizeInBits() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int getSizeInBytes() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||||
|
final int size) {
|
||||||
|
final Boolean value = (Boolean) javaType;
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
byte bufValue = buffer[byteOffset];
|
||||||
|
bufValue |= (0x01 << bitOffset);
|
||||||
|
buffer[byteOffset] = bufValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.serializer.converter;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Serializable;
|
||||||
|
import com.cnbm.s7.s7connector.impl.utils.S7Type;
|
||||||
|
|
||||||
|
public class ByteConverter implements S7Serializable {
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||||
|
return targetClass.cast(buffer[byteOffset]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public S7Type getS7Type() {
|
||||||
|
return S7Type.BYTE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int getSizeInBits() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int getSizeInBytes() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||||
|
final int size) {
|
||||||
|
final Byte value = (Byte) javaType;
|
||||||
|
buffer[byteOffset] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.serializer.converter;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.impl.utils.S7Type;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public final class DateAndTimeConverter extends ByteConverter {
|
||||||
|
|
||||||
|
public static final int OFFSET_DAY = 2;
|
||||||
|
public static final int OFFSET_HOUR = 3;
|
||||||
|
public static final int OFFSET_MILLIS_1_AND_DOW = 7;
|
||||||
|
public static final int OFFSET_MILLIS_100_10 = 6;
|
||||||
|
public static final int OFFSET_MINUTE = 4;
|
||||||
|
public static final int OFFSET_MONTH = 1;
|
||||||
|
public static final int OFFSET_SECOND = 5;
|
||||||
|
public static final int OFFSET_YEAR = 0;
|
||||||
|
|
||||||
|
// 18, 1,16,16, 5,80,0,3, (dec)
|
||||||
|
// 12, 1,10,10, 5,50,0,3, (hex)
|
||||||
|
// 12-01-10 10:05:50.000
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||||
|
final Calendar c = Calendar.getInstance();
|
||||||
|
c.clear();
|
||||||
|
|
||||||
|
int year = this.getFromPLC(buffer, OFFSET_YEAR + byteOffset);
|
||||||
|
|
||||||
|
if (year < 90) {
|
||||||
|
// 1900 - 1989
|
||||||
|
year += 2000;
|
||||||
|
} else {
|
||||||
|
// 2000 - 2090
|
||||||
|
year += 1900;
|
||||||
|
}
|
||||||
|
|
||||||
|
int month = this.getFromPLC(buffer, OFFSET_MONTH + byteOffset);
|
||||||
|
|
||||||
|
if (month > 0) {
|
||||||
|
month--;
|
||||||
|
}
|
||||||
|
|
||||||
|
c.set(Calendar.YEAR, year);
|
||||||
|
c.set(Calendar.MONTH, month);
|
||||||
|
c.set(Calendar.DAY_OF_MONTH, this.getFromPLC(buffer, OFFSET_DAY + byteOffset));
|
||||||
|
c.set(Calendar.HOUR_OF_DAY, this.getFromPLC(buffer, OFFSET_HOUR + byteOffset));
|
||||||
|
c.set(Calendar.MINUTE, this.getFromPLC(buffer, OFFSET_MINUTE + byteOffset));
|
||||||
|
c.set(Calendar.SECOND, this.getFromPLC(buffer, OFFSET_SECOND + byteOffset));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO byte upperMillis = super.extract(Byte.class, buffer,
|
||||||
|
* OFFSET_MILLIS_100_10+byteOffset, bitOffset); byte lowerMillis =
|
||||||
|
* super.extract(Byte.class, buffer, OFFSET_MILLIS_1_AND_DOW+byteOffset,
|
||||||
|
* bitOffset);
|
||||||
|
*
|
||||||
|
* int ms100 = ( upperMillis >> 4 ); int ms10 = ( upperMillis & 0x0F );
|
||||||
|
* int ms1 = ( lowerMillis >> 4 );
|
||||||
|
*
|
||||||
|
* int millis = ms1 + ( 10*ms10 ) + ( 100*ms100 );
|
||||||
|
* c.set(Calendar.MILLISECOND, millis);
|
||||||
|
*
|
||||||
|
* int dow = ( lowerMillis & 0x0F ); c.set(Calendar.DAY_OF_WEEK, dow);
|
||||||
|
*/
|
||||||
|
|
||||||
|
return targetClass.cast(c.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dec -> Hex 10 = 0a 16 = 0f 17 = 10
|
||||||
|
*
|
||||||
|
* @param buffer
|
||||||
|
* @param offset
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public byte getFromPLC(final byte[] buffer, final int offset) {
|
||||||
|
try {
|
||||||
|
final byte ret = super.extract(Byte.class, buffer, offset, 0);
|
||||||
|
return (byte) Integer.parseInt(Integer.toHexString(ret & 0xFF));
|
||||||
|
} catch (final NumberFormatException e) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public S7Type getS7Type() {
|
||||||
|
return S7Type.DATE_AND_TIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int getSizeInBits() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int getSizeInBytes() {
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||||
|
final int size) {
|
||||||
|
final Date date = (Date) javaType;
|
||||||
|
final Calendar c = Calendar.getInstance();
|
||||||
|
c.setTime(date);
|
||||||
|
|
||||||
|
int year = c.get(Calendar.YEAR);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if (year < 1990 || year > 2090) throw new
|
||||||
|
* S7Exception("Invalid year: " + year + " @ offset: " + byteOffset);
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (year < 2000) {
|
||||||
|
// 1990 -1999
|
||||||
|
year -= 1900;
|
||||||
|
} else {
|
||||||
|
// 2000 - 2089
|
||||||
|
year -= 2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.putToPLC(buffer, byteOffset + OFFSET_YEAR, year);
|
||||||
|
this.putToPLC(buffer, byteOffset + OFFSET_MONTH, c.get(Calendar.MONTH) + 1);
|
||||||
|
this.putToPLC(buffer, byteOffset + OFFSET_DAY, c.get(Calendar.DAY_OF_MONTH));
|
||||||
|
this.putToPLC(buffer, byteOffset + OFFSET_HOUR, c.get(Calendar.HOUR_OF_DAY));
|
||||||
|
this.putToPLC(buffer, byteOffset + OFFSET_MINUTE, c.get(Calendar.MINUTE));
|
||||||
|
this.putToPLC(buffer, byteOffset + OFFSET_SECOND, c.get(Calendar.SECOND));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO int msec1 = 0, msec10 = 0, msec100 = 0; Integer millis =
|
||||||
|
* c.get(Calendar.MILLISECOND); String mStr = millis.toString();
|
||||||
|
*
|
||||||
|
* if (mStr.length() > 2) { msec100 = Integer.parseInt(
|
||||||
|
* mStr.substring(0, 1) ); msec10 = Integer.parseInt( mStr.substring(1,
|
||||||
|
* 2) ); msec1 = Integer.parseInt( mStr.substring(2, 3) ); } else if
|
||||||
|
* (mStr.length() > 1) { msec10 = Integer.parseInt( mStr.substring(0, 1)
|
||||||
|
* ); msec1 = Integer.parseInt( mStr.substring(1, 2) ); } else { msec1 =
|
||||||
|
* Integer.parseInt( mStr.substring(0, 1) ); }
|
||||||
|
*
|
||||||
|
* super.insert( (byte)( (byte)msec10 | (byte)(msec100 << 4) ), buffer,
|
||||||
|
* OFFSET_MILLIS_100_10+byteOffset, 0, 1);
|
||||||
|
*
|
||||||
|
* int dow = c.get(Calendar.DAY_OF_WEEK);
|
||||||
|
*
|
||||||
|
* super.insert( (byte)( (byte)dow | (byte)(msec1 << 4) ), buffer,
|
||||||
|
* OFFSET_MILLIS_1_AND_DOW+byteOffset, 0, 1);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hex -> dec 0a = 10 0f = 16 10 = 17
|
||||||
|
*
|
||||||
|
* @param buffer
|
||||||
|
* @param offset
|
||||||
|
* @param i
|
||||||
|
*/
|
||||||
|
public void putToPLC(final byte[] buffer, final int offset, final int i) {
|
||||||
|
try {
|
||||||
|
final int ret = Integer.parseInt("" + i, 16);
|
||||||
|
buffer[offset] = (byte) ret;
|
||||||
|
} catch (final NumberFormatException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.serializer.converter;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.impl.utils.S7Type;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public final class DateConverter extends IntegerConverter {
|
||||||
|
|
||||||
|
private static final long MILLI_TO_DAY_FACTOR = 24 * 60 * 60 * 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1.1.1990
|
||||||
|
*/
|
||||||
|
private static final long OFFSET_1990;
|
||||||
|
|
||||||
|
static {
|
||||||
|
final Calendar c = Calendar.getInstance();
|
||||||
|
c.clear();
|
||||||
|
c.set(Calendar.HOUR_OF_DAY, 0);
|
||||||
|
c.set(Calendar.YEAR, 1990);
|
||||||
|
|
||||||
|
OFFSET_1990 = c.getTime().getTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||||
|
final long days = super.extract(Integer.class, buffer, byteOffset, bitOffset);
|
||||||
|
|
||||||
|
long millis = days * MILLI_TO_DAY_FACTOR;
|
||||||
|
|
||||||
|
millis += OFFSET_1990;
|
||||||
|
|
||||||
|
final Calendar c = Calendar.getInstance();
|
||||||
|
c.setTimeInMillis(millis);
|
||||||
|
c.set(Calendar.MILLISECOND, 0);
|
||||||
|
c.set(Calendar.SECOND, 0);
|
||||||
|
c.set(Calendar.MINUTE, 0);
|
||||||
|
c.set(Calendar.HOUR_OF_DAY, 0);
|
||||||
|
|
||||||
|
return targetClass.cast(c.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public S7Type getS7Type() {
|
||||||
|
return S7Type.DATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||||
|
final int size) {
|
||||||
|
final Date d = (Date) javaType;
|
||||||
|
|
||||||
|
long millis = d.getTime();
|
||||||
|
|
||||||
|
millis -= OFFSET_1990;
|
||||||
|
|
||||||
|
final double days = (double) millis / (double) MILLI_TO_DAY_FACTOR;
|
||||||
|
|
||||||
|
final long ROUND = 1000;
|
||||||
|
|
||||||
|
final long expected = (long) ((days * MILLI_TO_DAY_FACTOR) / ROUND);
|
||||||
|
final long actual = millis / ROUND;
|
||||||
|
|
||||||
|
if (expected != actual) {
|
||||||
|
throw new IllegalArgumentException("Expected: " + expected + " got: " + actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (millis < 0) {
|
||||||
|
super.insert(0, buffer, byteOffset, bitOffset, 2);
|
||||||
|
} else {
|
||||||
|
super.insert((int) Math.round(days), buffer, byteOffset, bitOffset, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.serializer.converter;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Serializable;
|
||||||
|
import com.cnbm.s7.s7connector.impl.utils.S7Type;
|
||||||
|
|
||||||
|
public class IntegerConverter implements S7Serializable {
|
||||||
|
|
||||||
|
private static final int OFFSET_HIGH_BYTE = 0;
|
||||||
|
private static final int OFFSET_LOW_BYTE = 1;
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||||
|
final byte lower = buffer[byteOffset + OFFSET_LOW_BYTE];
|
||||||
|
final byte higher = buffer[byteOffset + OFFSET_HIGH_BYTE];
|
||||||
|
|
||||||
|
final Integer i = (lower & 0xFF) | ((higher << 8) & 0xFF00);
|
||||||
|
|
||||||
|
return targetClass.cast(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public S7Type getS7Type() {
|
||||||
|
return S7Type.WORD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int getSizeInBits() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int getSizeInBytes() {
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||||
|
final int size) {
|
||||||
|
final Integer value = (Integer) javaType;
|
||||||
|
final byte lower = (byte) ((value >> 0) & 0xFF);
|
||||||
|
final byte higher = (byte) ((value >> 8) & 0xFF);
|
||||||
|
buffer[byteOffset + OFFSET_LOW_BYTE] = lower;
|
||||||
|
buffer[byteOffset + OFFSET_HIGH_BYTE] = higher;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.serializer.converter;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Serializable;
|
||||||
|
import com.cnbm.s7.s7connector.impl.utils.S7Type;
|
||||||
|
|
||||||
|
public final class LongConverter implements S7Serializable {
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||||
|
final byte b1 = buffer[byteOffset + 0];
|
||||||
|
final byte b2 = buffer[byteOffset + 1];
|
||||||
|
final byte b3 = buffer[byteOffset + 2];
|
||||||
|
final byte b4 = buffer[byteOffset + 3];
|
||||||
|
|
||||||
|
final Integer i = ((b1 << 0) & 0x000000FF) | ((b2 << 8) & 0x0000FF00) | ((b3 << 16) & 0x00FF0000)
|
||||||
|
| ((b4 << 24) & 0xFF000000);
|
||||||
|
|
||||||
|
return targetClass.cast(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public S7Type getS7Type() {
|
||||||
|
return S7Type.WORD;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int getSizeInBits() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int getSizeInBytes() {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||||
|
final int size) {
|
||||||
|
final Long value = (Long) javaType;
|
||||||
|
final byte b1 = (byte) ((value >> 0) & 0xFF);
|
||||||
|
final byte b2 = (byte) ((value >> 8) & 0xFF);
|
||||||
|
final byte b3 = (byte) ((value >> 16) & 0xFF);
|
||||||
|
final byte b4 = (byte) ((value >> 24) & 0xFF);
|
||||||
|
buffer[byteOffset + 0] = b1;
|
||||||
|
buffer[byteOffset + 1] = b2;
|
||||||
|
buffer[byteOffset + 2] = b3;
|
||||||
|
buffer[byteOffset + 3] = b4;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.serializer.converter;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Serializable;
|
||||||
|
import com.cnbm.s7.s7connector.impl.utils.S7Type;
|
||||||
|
|
||||||
|
public final class RealConverter implements S7Serializable {
|
||||||
|
|
||||||
|
private static final int OFFSET_POS1 = 0;
|
||||||
|
private static final int OFFSET_POS2 = 1;
|
||||||
|
private static final int OFFSET_POS3 = 2;
|
||||||
|
private static final int OFFSET_POS4 = 3;
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||||
|
final int iValue = ((buffer[byteOffset + OFFSET_POS4] & 0xFF) << 0)
|
||||||
|
| ((buffer[byteOffset + OFFSET_POS3] & 0xFF) << 8) | ((buffer[byteOffset + OFFSET_POS2] & 0xFF) << 16)
|
||||||
|
| ((buffer[byteOffset + OFFSET_POS1] & 0xFF) << 24);
|
||||||
|
|
||||||
|
final Float fValue = Float.intBitsToFloat(iValue);
|
||||||
|
|
||||||
|
Object ret = fValue;
|
||||||
|
|
||||||
|
if (targetClass == Double.class) {
|
||||||
|
ret = Double.parseDouble(fValue.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetClass.cast(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public S7Type getS7Type() {
|
||||||
|
return S7Type.REAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int getSizeInBits() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int getSizeInBytes() {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||||
|
final int size) {
|
||||||
|
final float fValue = Float.parseFloat(javaType.toString());
|
||||||
|
|
||||||
|
final int iValue = Float.floatToIntBits(fValue);
|
||||||
|
|
||||||
|
buffer[byteOffset + OFFSET_POS4] = (byte) ((iValue >> 0) & 0xFF);
|
||||||
|
buffer[byteOffset + OFFSET_POS3] = (byte) ((iValue >> 8) & 0xFF);
|
||||||
|
buffer[byteOffset + OFFSET_POS2] = (byte) ((iValue >> 16) & 0xFF);
|
||||||
|
buffer[byteOffset + OFFSET_POS1] = (byte) ((iValue >> 24) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.serializer.converter;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Serializable;
|
||||||
|
import com.cnbm.s7.s7connector.impl.utils.S7Type;
|
||||||
|
|
||||||
|
public final class StringConverter implements S7Serializable {
|
||||||
|
|
||||||
|
private static final int OFFSET_CURRENT_LENGTH = 1;
|
||||||
|
private static final int OFFSET_OVERALL_LENGTH = 0;
|
||||||
|
private static final int OFFSET_START = 2;
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||||
|
final int len = buffer[byteOffset + OFFSET_CURRENT_LENGTH];
|
||||||
|
|
||||||
|
final byte[] bytes = new byte[len];
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
bytes[i] = buffer[byteOffset + OFFSET_START + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetClass.cast(new String(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public S7Type getS7Type() {
|
||||||
|
return S7Type.STRING;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int getSizeInBits() {
|
||||||
|
// Not static
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int getSizeInBytes() {
|
||||||
|
// Not static
|
||||||
|
return 2; // 2 bytes overhead
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||||
|
final int size) {
|
||||||
|
final String value = (String) javaType;
|
||||||
|
|
||||||
|
final int len = value.length();
|
||||||
|
|
||||||
|
if (len > size) {
|
||||||
|
throw new IllegalArgumentException("String to big: " + len);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[byteOffset + OFFSET_OVERALL_LENGTH] = (byte) size;
|
||||||
|
buffer[byteOffset + OFFSET_CURRENT_LENGTH] = (byte) len;
|
||||||
|
|
||||||
|
final byte[] strBytes = value.getBytes();
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
buffer[byteOffset + OFFSET_START + i] = (byte) (strBytes[i] & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.serializer.converter;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.impl.serializer.S7SerializerImpl;
|
||||||
|
import com.cnbm.s7.s7connector.impl.utils.S7Type;
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Serializable;
|
||||||
|
|
||||||
|
public final class StructConverter implements S7Serializable {
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||||
|
return S7SerializerImpl.extractBytes(targetClass, buffer, byteOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public S7Type getS7Type() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int getSizeInBits() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int getSizeInBytes() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||||
|
final int size) {
|
||||||
|
S7SerializerImpl.insertBytes(javaType, buffer, byteOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.serializer.converter;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.impl.utils.S7Type;
|
||||||
|
|
||||||
|
public final class TimeConverter extends ByteConverter {
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public <T> T extract(final Class<T> targetClass, final byte[] buffer, final int byteOffset, final int bitOffset) {
|
||||||
|
final byte b1 = super.extract(Byte.class, buffer, byteOffset + 3, bitOffset);
|
||||||
|
final byte b2 = super.extract(Byte.class, buffer, byteOffset + 2, bitOffset);
|
||||||
|
final byte b3 = super.extract(Byte.class, buffer, byteOffset + 1, bitOffset);
|
||||||
|
final byte b4 = super.extract(Byte.class, buffer, byteOffset + 0, bitOffset);
|
||||||
|
|
||||||
|
final long l = ((long) b1 & 0xFF) << 0 | ((long) b2 & 0xFF) << 8 | ((long) b3 & 0xFF) << 16
|
||||||
|
| ((long) b4 & 0xFF) << 24;
|
||||||
|
|
||||||
|
return targetClass.cast(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public S7Type getS7Type() {
|
||||||
|
return S7Type.TIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public int getSizeInBytes() {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
@Override
|
||||||
|
public void insert(final Object javaType, final byte[] buffer, final int byteOffset, final int bitOffset,
|
||||||
|
final int size) {
|
||||||
|
final long l = (Long) javaType;
|
||||||
|
|
||||||
|
final byte b1 = (byte) ((byte) (l >> 0) & 0xFF);
|
||||||
|
final byte b2 = (byte) ((byte) (l >> 8) & 0xFF);
|
||||||
|
final byte b3 = (byte) ((byte) (l >> 16) & 0xFF);
|
||||||
|
final byte b4 = (byte) ((byte) (l >> 24) & 0xFF);
|
||||||
|
|
||||||
|
super.insert(b1, buffer, byteOffset + 3, bitOffset, 1);
|
||||||
|
super.insert(b2, buffer, byteOffset + 2, bitOffset, 1);
|
||||||
|
super.insert(b3, buffer, byteOffset + 1, bitOffset, 1);
|
||||||
|
super.insert(b4, buffer, byteOffset + 0, bitOffset, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.serializer.parser;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Serializable;
|
||||||
|
import com.cnbm.s7.s7connector.impl.utils.S7Type;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Bean-Entry
|
||||||
|
*
|
||||||
|
* @author Thomas Rudin
|
||||||
|
*/
|
||||||
|
public final class BeanEntry {
|
||||||
|
/**
|
||||||
|
* The Array size
|
||||||
|
*/
|
||||||
|
public int arraySize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offsets and size
|
||||||
|
*/
|
||||||
|
public int byteOffset, bitOffset, size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The corresponding field
|
||||||
|
*/
|
||||||
|
public Field field;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array type
|
||||||
|
*/
|
||||||
|
public boolean isArray;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The S7 Type
|
||||||
|
*/
|
||||||
|
public S7Type s7type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The corresponding serializer
|
||||||
|
*/
|
||||||
|
public S7Serializable serializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Java type
|
||||||
|
*/
|
||||||
|
public Class<?> type;
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.serializer.parser;
|
||||||
|
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
public final class BeanParseResult {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The needed blocksize
|
||||||
|
*/
|
||||||
|
public int blockSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Bean entries
|
||||||
|
*/
|
||||||
|
public Vector<BeanEntry> entries = new Vector<BeanEntry>();
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,154 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.serializer.parser;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Serializable;
|
||||||
|
import com.cnbm.s7.s7connector.api.annotation.S7Variable;
|
||||||
|
import com.cnbm.s7.s7connector.impl.utils.S7Type;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
public final class BeanParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Local Logger
|
||||||
|
*/
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(BeanParser.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the wrapper for the primitive type
|
||||||
|
*
|
||||||
|
* @param primitiveType
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static Class<?> getWrapperForPrimitiveType(final Class<?> primitiveType) {
|
||||||
|
if (primitiveType == boolean.class) {
|
||||||
|
return Boolean.class;
|
||||||
|
} else if (primitiveType == byte.class) {
|
||||||
|
return Byte.class;
|
||||||
|
} else if (primitiveType == int.class) {
|
||||||
|
return Integer.class;
|
||||||
|
} else if (primitiveType == float.class) {
|
||||||
|
return Float.class;
|
||||||
|
} else if (primitiveType == double.class) {
|
||||||
|
return Double.class;
|
||||||
|
} else if (primitiveType == long.class) {
|
||||||
|
return Long.class;
|
||||||
|
} else {
|
||||||
|
// Fallback
|
||||||
|
return primitiveType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a Class
|
||||||
|
*
|
||||||
|
* @param jclass
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static BeanParseResult parse(final Class<?> jclass) throws Exception {
|
||||||
|
final BeanParseResult res = new BeanParseResult();
|
||||||
|
logger.trace("Parsing: " + jclass.getName());
|
||||||
|
|
||||||
|
for (final Field field : jclass.getFields()) {
|
||||||
|
final S7Variable dataAnnotation = field.getAnnotation(S7Variable.class);
|
||||||
|
|
||||||
|
if (dataAnnotation != null) {
|
||||||
|
logger.trace("Parsing field: " + field.getName());
|
||||||
|
logger.trace(" type: " + dataAnnotation.type());
|
||||||
|
logger.trace(" byteOffset: " + dataAnnotation.byteOffset());
|
||||||
|
logger.trace(" bitOffset: " + dataAnnotation.bitOffset());
|
||||||
|
logger.trace(" size: " + dataAnnotation.size());
|
||||||
|
logger.trace(" arraySize: " + dataAnnotation.arraySize());
|
||||||
|
|
||||||
|
final int offset = dataAnnotation.byteOffset();
|
||||||
|
|
||||||
|
// update max offset
|
||||||
|
if (offset > res.blockSize) {
|
||||||
|
res.blockSize = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataAnnotation.type() == S7Type.STRUCT) {
|
||||||
|
// recurse
|
||||||
|
logger.trace("Recursing...");
|
||||||
|
final BeanParseResult subResult = parse(field.getType());
|
||||||
|
res.blockSize += subResult.blockSize;
|
||||||
|
logger.trace(" New blocksize: " + res.blockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.trace(" New blocksize (+offset): " + res.blockSize);
|
||||||
|
|
||||||
|
// Add dynamic size
|
||||||
|
res.blockSize += dataAnnotation.size();
|
||||||
|
|
||||||
|
// Plain element
|
||||||
|
final BeanEntry entry = new BeanEntry();
|
||||||
|
entry.byteOffset = dataAnnotation.byteOffset();
|
||||||
|
entry.bitOffset = dataAnnotation.bitOffset();
|
||||||
|
entry.field = field;
|
||||||
|
entry.type = getWrapperForPrimitiveType(field.getType());
|
||||||
|
entry.size = dataAnnotation.size();
|
||||||
|
entry.s7type = dataAnnotation.type();
|
||||||
|
entry.isArray = field.getType().isArray();
|
||||||
|
entry.arraySize = dataAnnotation.arraySize();
|
||||||
|
|
||||||
|
if (entry.isArray) {
|
||||||
|
entry.type = getWrapperForPrimitiveType(entry.type.getComponentType());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new serializer
|
||||||
|
final S7Serializable s = entry.s7type.getSerializer().newInstance();
|
||||||
|
entry.serializer = s;
|
||||||
|
|
||||||
|
res.blockSize += (s.getSizeInBytes() * dataAnnotation.arraySize());
|
||||||
|
logger.trace(" New blocksize (+array): " + res.blockSize);
|
||||||
|
|
||||||
|
if (s.getSizeInBits() > 0) {
|
||||||
|
boolean offsetOfBitAlreadyKnown = false;
|
||||||
|
for (final BeanEntry parsedEntry : res.entries) {
|
||||||
|
if (parsedEntry.byteOffset == entry.byteOffset) {
|
||||||
|
offsetOfBitAlreadyKnown = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!offsetOfBitAlreadyKnown) {
|
||||||
|
res.blockSize++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.entries.add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.trace("Parsing done, overall size: " + res.blockSize);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses an Object
|
||||||
|
*
|
||||||
|
* @param obj
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static BeanParseResult parse(final Object obj) throws Exception {
|
||||||
|
return parse(obj.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.utils;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.S7Serializable;
|
||||||
|
import com.cnbm.s7.s7connector.impl.serializer.converter.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of the Address
|
||||||
|
*
|
||||||
|
* @author Thomas Rudin Libnodave: http://libnodave.sourceforge.net/
|
||||||
|
*/
|
||||||
|
public enum S7Type {
|
||||||
|
/**
|
||||||
|
* Boolean type
|
||||||
|
*/
|
||||||
|
BOOL(BitConverter.class, 0, 1),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Byte type
|
||||||
|
*/
|
||||||
|
BYTE(ByteConverter.class, 1, 0),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple Date with 2 bytes in length
|
||||||
|
*/
|
||||||
|
DATE(DateConverter.class, 2, 0),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Full Date and time format with precision in milliseconds
|
||||||
|
*/
|
||||||
|
DATE_AND_TIME(DateAndTimeConverter.class, 8, 0),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Double word
|
||||||
|
*/
|
||||||
|
DWORD(LongConverter.class, 4, 0),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Real-type, corresponds to float or double
|
||||||
|
*/
|
||||||
|
REAL(RealConverter.class, 4, 0),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String type, size must be specified manually
|
||||||
|
*/
|
||||||
|
STRING(StringConverter.class, 2, 0),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structure type
|
||||||
|
*/
|
||||||
|
STRUCT(StructConverter.class, 0, 0),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Time-type, 4 bytes in length, number of millis
|
||||||
|
*/
|
||||||
|
TIME(TimeConverter.class, 4, 0),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Word-type (same as int-type)
|
||||||
|
*/
|
||||||
|
WORD(IntegerConverter.class, 2, 0);
|
||||||
|
|
||||||
|
private int byteSize, bitSize;
|
||||||
|
|
||||||
|
private Class<? extends S7Serializable> serializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum Constructor
|
||||||
|
*
|
||||||
|
* @param serializer
|
||||||
|
* @param byteSize
|
||||||
|
* @param bitSize
|
||||||
|
*/
|
||||||
|
S7Type(final Class<? extends S7Serializable> serializer, final int byteSize, final int bitSize) {
|
||||||
|
this.serializer = serializer;
|
||||||
|
this.bitSize = bitSize;
|
||||||
|
this.byteSize = byteSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBitSize() {
|
||||||
|
return this.bitSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getByteSize() {
|
||||||
|
return this.byteSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<? extends S7Serializable> getSerializer() {
|
||||||
|
return this.serializer;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2016 S7connector members (github.com/s7connector)
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.cnbm.s7.s7connector.impl.utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* S7-Utility class
|
||||||
|
*
|
||||||
|
* @author Thomas Rudin Libnodave: http://libnodave.sourceforge.net/
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class S7Utils {
|
||||||
|
/**
|
||||||
|
* Converts a byte to 8 bits
|
||||||
|
*
|
||||||
|
* @param buffer
|
||||||
|
* The Input-Byte
|
||||||
|
* @return The 8 bits
|
||||||
|
*/
|
||||||
|
public static boolean[] getBits(int buffer) {
|
||||||
|
if (buffer < 0) {
|
||||||
|
buffer += 256;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String binString = Integer.toBinaryString(buffer);
|
||||||
|
/*
|
||||||
|
* String-Pos: 0 1 2 3 4 5 6 7 Bit: 128 64 32 16 8 4 2 1
|
||||||
|
*/
|
||||||
|
final boolean[] ret = new boolean[8];
|
||||||
|
for (int i = binString.length() - 1; i >= 0; i--) {
|
||||||
|
// Check for the '1'-Char and mirror-set the result
|
||||||
|
final int mirrorPos = (binString.length() - 1) - i;
|
||||||
|
if (binString.charAt(i) == '1') {
|
||||||
|
ret[mirrorPos] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Constructor */
|
||||||
|
private S7Utils() {
|
||||||
|
// Not needed. Utility class.
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
package com.cnbm.s7.s7connector.type;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Desc: ""
|
||||||
|
* @Author: caixiang
|
||||||
|
* @DATE: 2022/1/7 14:41
|
||||||
|
*/
|
||||||
|
public enum DataTransportSize {
|
||||||
|
|
||||||
|
NULL((short) 0x00, (boolean) false),
|
||||||
|
BIT((short) 0x03, (boolean) true),
|
||||||
|
BYTE_WORD_DWORD((short) 0x04, (boolean) true),
|
||||||
|
INTEGER((short) 0x05, (boolean) true),
|
||||||
|
DINTEGER((short) 0x06, (boolean) false),
|
||||||
|
REAL((short) 0x07, (boolean) false),
|
||||||
|
OCTET_STRING((short) 0x09, (boolean) false);
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(DataTransportSize.class);
|
||||||
|
|
||||||
|
private static final Map<Short, DataTransportSize> map;
|
||||||
|
static {
|
||||||
|
map = new HashMap<>();
|
||||||
|
for (DataTransportSize value : DataTransportSize.values()) {
|
||||||
|
map.put((short) value.getValue(), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private short value;
|
||||||
|
private boolean sizeInBits;
|
||||||
|
|
||||||
|
DataTransportSize(short value, boolean sizeInBits) {
|
||||||
|
this.value = value;
|
||||||
|
this.sizeInBits = sizeInBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getSizeInBits() {
|
||||||
|
return sizeInBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DataTransportSize firstEnumForFieldSizeInBits(boolean fieldValue) {
|
||||||
|
for (DataTransportSize _val : DataTransportSize.values()) {
|
||||||
|
if(_val.getSizeInBits() == fieldValue) {
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<DataTransportSize> enumsForFieldSizeInBits(boolean fieldValue) {
|
||||||
|
List<DataTransportSize> _values = new ArrayList();
|
||||||
|
for (DataTransportSize _val : DataTransportSize.values()) {
|
||||||
|
if(_val.getSizeInBits() == fieldValue) {
|
||||||
|
_values.add(_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DataTransportSize enumForValue(short value) {
|
||||||
|
if (!map.containsKey(value)) {
|
||||||
|
logger.info("No DataTransportSize for value {}", value);
|
||||||
|
}
|
||||||
|
return map.get(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Boolean isDefined(short value) {
|
||||||
|
return map.containsKey(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
529
ym-s7/src/main/java/com/cnbm/s7/s7connector/type/PlcVar.java
Normal file
529
ym-s7/src/main/java/com/cnbm/s7/s7connector/type/PlcVar.java
Normal file
@ -0,0 +1,529 @@
|
|||||||
|
package com.cnbm.s7.s7connector.type;
|
||||||
|
|
||||||
|
import com.cnbm.s7.s7connector.api.DaveArea;
|
||||||
|
import com.cnbm.s7.s7connector.api.utils.ByteUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public enum PlcVar {
|
||||||
|
//单体变量
|
||||||
|
BOOL("BOOL",TransportSize.BOOL,1,false),
|
||||||
|
BYTE("BYTE",TransportSize.BYTE,2,false),
|
||||||
|
WORD("WORD",TransportSize.WORD,3,false),
|
||||||
|
DWORD("DWORD",TransportSize.DWORD,4,false),
|
||||||
|
LWORD("LWORD",TransportSize.LWORD,5,false),
|
||||||
|
INT("INT",TransportSize.INT,6,false),
|
||||||
|
UINT("UINT",TransportSize.UINT,7,false),
|
||||||
|
SINT("SINT",TransportSize.SINT,8,false),
|
||||||
|
USINT("USINT",TransportSize.USINT,9,false),
|
||||||
|
DINT("DINT",TransportSize.DINT,10,false),
|
||||||
|
UDINT("UDINT",TransportSize.UDINT,11,false),
|
||||||
|
LINT("LINT",TransportSize.LINT,12,false),
|
||||||
|
ULINT("ULINT",TransportSize.ULINT,13,false),
|
||||||
|
REAL("REAL",TransportSize.REAL,14,false),
|
||||||
|
LREAL("LREAL",TransportSize.LREAL,15,false),
|
||||||
|
CHAR("CHAR",TransportSize.CHAR,16,false),
|
||||||
|
WCHAR("WCHAR",TransportSize.WCHAR,17,false),
|
||||||
|
STRING("STRING",TransportSize.STRING,18,false),
|
||||||
|
WSTRING("WSTRING",TransportSize.WSTRING,19,false),
|
||||||
|
TIME("TIME",TransportSize.TIME,20,false),
|
||||||
|
LTIME("LTIME",TransportSize.LTIME,21,false),
|
||||||
|
DATE("DATE",TransportSize.DATE,22,false),
|
||||||
|
TIME_OF_DAY("TIME_OF_DAY",TransportSize.TIME_OF_DAY,23,false),
|
||||||
|
TOD("TOD",TransportSize.TOD,24,false),
|
||||||
|
DATE_AND_TIME("DATE_AND_TIME",TransportSize.DATE_AND_TIME,25,false),
|
||||||
|
DT("DT",TransportSize.DT,26,false),
|
||||||
|
DTL("DTL",TransportSize.DTL,27,false),
|
||||||
|
|
||||||
|
//todo Array 再搞一搞。
|
||||||
|
BOOL_Array("BOOL",TransportSize.BOOL,1,true),
|
||||||
|
BYTE_Array("BYTE",TransportSize.BYTE,2,true),
|
||||||
|
WORD_Array("WORD",TransportSize.WORD,3,true),
|
||||||
|
DWORD_Array("DWORD",TransportSize.DWORD,4,true),
|
||||||
|
CHAR_Array("CHAR",TransportSize.CHAR,5,true),
|
||||||
|
SINT_Array("SINT",TransportSize.SINT,6,true),
|
||||||
|
INT_Array("INT",TransportSize.INT,7,true),
|
||||||
|
DINT_Array("DINT",TransportSize.DINT,8,true),
|
||||||
|
UINT_Array("UINT",TransportSize.UINT,9,true),
|
||||||
|
USINT_Array("USINT",TransportSize.USINT,10,true),
|
||||||
|
UDINT_Array("UDINT",TransportSize.UDINT,11,true),
|
||||||
|
STRING_Array("STRING",TransportSize.STRING,12,true),
|
||||||
|
;
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(TransportSize.class);
|
||||||
|
|
||||||
|
private static final Map<TransportSize, PlcVar> map;
|
||||||
|
static {
|
||||||
|
map = new HashMap<>();
|
||||||
|
for (PlcVar value : PlcVar.values()) {
|
||||||
|
if(!value.isArray){
|
||||||
|
map.put(value.getTransportSize(), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public static PlcVar valueOf(TransportSize transportSize){
|
||||||
|
return map.get(transportSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private TransportSize transportSize;
|
||||||
|
private Integer dataType;
|
||||||
|
private boolean isArray;
|
||||||
|
|
||||||
|
|
||||||
|
PlcVar(String name , TransportSize transportSize, Integer dataType,Boolean isArray){
|
||||||
|
this.name = name;
|
||||||
|
this.transportSize = transportSize;
|
||||||
|
this.dataType = dataType;
|
||||||
|
this.isArray = isArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public TransportSize getTransportSize() {
|
||||||
|
return transportSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isArray() {
|
||||||
|
return isArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] toBytes(Object value){
|
||||||
|
//todo here 扩展数组 toBytes
|
||||||
|
if(!isArray){
|
||||||
|
byte[] res = null;
|
||||||
|
switch (dataType) {
|
||||||
|
case 1:
|
||||||
|
res = ByteUtils.boolToBytes((boolean)value);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
//ByteUtils.setbytes(Byte.valueOf((byte) 0xFF))
|
||||||
|
res = ByteUtils.setbytes(Byte.valueOf((byte) value));
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
//ByteUtils.wordToBytes(Short.valueOf("-55"))
|
||||||
|
res = ByteUtils.wordToBytes(Short.valueOf(value.toString()));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
//ByteUtils.dwordToBytes(99)
|
||||||
|
res = ByteUtils.dwordToBytes((int)value);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
//null
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
//ByteUtils.intToBytes(-99)
|
||||||
|
res = ByteUtils.intToBytes((int)value);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
//ByteUtils.uintToBytes(9)
|
||||||
|
res = ByteUtils.uintToBytes((int)value);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
//ByteUtils.sintToBytes(-9)
|
||||||
|
res =ByteUtils.sintToBytes((int)value);
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
//ByteUtils.usintToBytes(9);
|
||||||
|
res =ByteUtils.usintToBytes((int)value);
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
//ByteUtils.dintToBytes(-999)
|
||||||
|
res =ByteUtils.dintToBytes((int)value);
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
//ByteUtils.udintToBytes(99)
|
||||||
|
res =ByteUtils.udintToBytes((int)value);
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
//待补充
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
//待补充
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
//ByteUtils.realToBytes(Float.valueOf("-11.2"))
|
||||||
|
res =ByteUtils.realToBytes(Float.valueOf(value.toString()));
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
//ByteUtils.lrealToBytes(Double.parseDouble("-111.1"));
|
||||||
|
res =ByteUtils.lrealToBytes(Double.parseDouble(value.toString()));
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
//ByteUtils.charToBytes('b')
|
||||||
|
res =ByteUtils.charToBytes((char)value);
|
||||||
|
break;
|
||||||
|
case 17:
|
||||||
|
//ByteUtils.wcharToBytes('菜')
|
||||||
|
res =ByteUtils.wcharToBytes((char)value);
|
||||||
|
break;
|
||||||
|
case 18:
|
||||||
|
//String s = "你好啊";
|
||||||
|
//ByteUtils.strToBytes(s);
|
||||||
|
res = ByteUtils.strToBytes(value.toString());
|
||||||
|
break;
|
||||||
|
case 19:
|
||||||
|
//待补充
|
||||||
|
break;
|
||||||
|
case 20:
|
||||||
|
//不常用 待补充
|
||||||
|
break;
|
||||||
|
case 21:
|
||||||
|
//不常用
|
||||||
|
break;
|
||||||
|
case 22:
|
||||||
|
//不常用
|
||||||
|
break;
|
||||||
|
case 23:
|
||||||
|
////不常用
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
////不常用
|
||||||
|
break;
|
||||||
|
case 25:
|
||||||
|
//不常用
|
||||||
|
break;
|
||||||
|
case 26:
|
||||||
|
//不常用
|
||||||
|
break;
|
||||||
|
case 27:
|
||||||
|
//不常用
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//什么也不做
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}else {
|
||||||
|
byte[] res = null;
|
||||||
|
switch (dataType) {
|
||||||
|
case 1:
|
||||||
|
// boolean[] booleanArray = new boolean[2];
|
||||||
|
// booleanArray[0] = true;
|
||||||
|
// booleanArray[1] = true;
|
||||||
|
// ByteUtils.booleanArrayToBytes(booleanArray)
|
||||||
|
res = ByteUtils.booleanArrayToBytes((boolean[]) value);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
// byte[] write_byteArrays = new byte[2];
|
||||||
|
// write_byteArrays[0] = 1;
|
||||||
|
// write_byteArrays[1] = 2;
|
||||||
|
//
|
||||||
|
res = (byte[]) value;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
// short[] shortArrays_content = new short[2];
|
||||||
|
// shortArrays_content[0] = 1;
|
||||||
|
// shortArrays_content[1] = -1;
|
||||||
|
//
|
||||||
|
res = ByteUtils.wordArrayToBytes((short[]) value);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
// int[] intArrays_content = new int[2];
|
||||||
|
// intArrays_content[0] = 1;
|
||||||
|
// intArrays_content[1] = -1;
|
||||||
|
//
|
||||||
|
res = ByteUtils.dwordArrayToBytes((int[]) value);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
// char[] charArrays_content = new char[2];
|
||||||
|
// charArrays_content[0] = '1';
|
||||||
|
// charArrays_content[1] = 'b';
|
||||||
|
//
|
||||||
|
res = ByteUtils.charArrayToBytes((char[]) value);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
// int[] sintArrays_content = new int[2];
|
||||||
|
// sintArrays_content[0] = 1;
|
||||||
|
// sintArrays_content[1] = -1;
|
||||||
|
//
|
||||||
|
res = ByteUtils.sintArrayToBytes((int[]) value);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
// int[] iintArrays_content = new int[2];
|
||||||
|
// iintArrays_content[0] = 12;
|
||||||
|
// iintArrays_content[1] = -21;
|
||||||
|
//
|
||||||
|
res = ByteUtils.intArrayToBytes((int[]) value);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
// int[] dintArrays_content = new int[2];
|
||||||
|
// dintArrays_content[0] = 12;
|
||||||
|
// dintArrays_content[1] = -21;
|
||||||
|
//
|
||||||
|
res = ByteUtils.dintArrayToBytes((int[]) value);
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
// int[] uintArrays_content = new int[3];
|
||||||
|
// uintArrays_content[0] = 12;
|
||||||
|
// uintArrays_content[1] = 99;
|
||||||
|
// uintArrays_content[2] = 1;
|
||||||
|
res = ByteUtils.uintArrayToBytes((int[]) value);
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
// int[] usintArrays_content = new int[3];
|
||||||
|
// usintArrays_content[0] = 12;
|
||||||
|
// usintArrays_content[1] = 99;
|
||||||
|
// usintArrays_content[2] = 1;
|
||||||
|
res = ByteUtils.usintArrayToBytes((int[]) value);
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
// int[] udintArrays_content = new int[3];
|
||||||
|
// udintArrays_content[0] = 12;
|
||||||
|
// udintArrays_content[1] = 99;
|
||||||
|
// udintArrays_content[2] = 1;
|
||||||
|
res = ByteUtils.udintArrayToBytes((int[]) value);
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//什么也不做
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo here 把 read 和 write操作都封装一下 然后 和 toByte 和 toObject 整合
|
||||||
|
/**
|
||||||
|
* PlcVar(byte[]) 转 java对象 对照表
|
||||||
|
* 单体变量
|
||||||
|
* Bool ===> Boolean
|
||||||
|
* LREAL ===> Double
|
||||||
|
* REAL ===> Float
|
||||||
|
* DATE ===> String(yyyy-MM-dd 这种形式的类型)
|
||||||
|
* DTL ===> String("年-月-日-工作日-时-分-秒" 这种格式)
|
||||||
|
* TIME ===> Integer(单位 ms)
|
||||||
|
* USINT ===> Integer
|
||||||
|
* SINT ===> Integer
|
||||||
|
* UINT ===> Integer
|
||||||
|
* INT ===> Integer
|
||||||
|
* DINT ===> Integer
|
||||||
|
* UINT ===> Long
|
||||||
|
* Byte ===> Integer(有符号)(默认)
|
||||||
|
* Integer(无符号)(后续扩展)
|
||||||
|
* Char ===> Character
|
||||||
|
* WChar ===> Character
|
||||||
|
* String ===> String //注意: String类型 不能用枚举类里的 toObject() / toBytes() 的方法,具体方式看Demo
|
||||||
|
|
||||||
|
|
||||||
|
* 数组变量
|
||||||
|
* BoolArray ===> List<Boolean>
|
||||||
|
* ByteArray ===> List<Byte>
|
||||||
|
* WordArray ===> List<Integer>
|
||||||
|
* DWordArray ===> List<Integer>
|
||||||
|
* CharArray ===> List<Character>
|
||||||
|
* SIntArray ===> List<Integer>
|
||||||
|
* IntArray ===> List<Integer>
|
||||||
|
* DIntArray ===> List<Integer>
|
||||||
|
* UIntArray ===> List<Integer>
|
||||||
|
* USIntArray ===> List<Integer>
|
||||||
|
* UDIntArray ===> List<Long>
|
||||||
|
* StringArray ===> List<String> //注意: String类型 不能用枚举类里的 toObject() / toBytes() 的方法,具体方式看Demo
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* */
|
||||||
|
public Object toObject(byte[] value) {
|
||||||
|
if(!isArray){
|
||||||
|
Object res = null;
|
||||||
|
switch (dataType) {
|
||||||
|
case 1:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toBoolean(value);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toInt(value[0]);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toInt(value[0],value[1]);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toInt(value[0],value[1],value[2],value[3]);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
//null
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toUInt(value[0],value[1]);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toUInt(value[0],value[1]);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toUInt(value[0]);
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toUInt(value[0]);
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toInt(value[0],value[1],value[2],value[3]);
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toInt(value[0],value[1],value[2],value[3]);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 12:
|
||||||
|
//
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 13:
|
||||||
|
//
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 14:
|
||||||
|
//
|
||||||
|
res = ByteUtils.realbytesToFloat(value);
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
|
//ByteUtils.lrealbytesToDouble(lreal)
|
||||||
|
res = ByteUtils.lrealbytesToDouble(value);
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toChar(value);
|
||||||
|
break;
|
||||||
|
case 17:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toChar(value);
|
||||||
|
break;
|
||||||
|
case 18:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toStr(value);
|
||||||
|
break;
|
||||||
|
case 19:
|
||||||
|
//
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 20:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toInt(value[0], value[1], value[2], value[3]);
|
||||||
|
break;
|
||||||
|
case 21:
|
||||||
|
//
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 22:
|
||||||
|
//
|
||||||
|
|
||||||
|
Long aLong = Long.valueOf(ByteUtils.toInt(value[0], value[1]).toString());
|
||||||
|
String s = ByteUtils.addDate("1990-01-01", aLong);
|
||||||
|
res = s;
|
||||||
|
break;
|
||||||
|
case 23:
|
||||||
|
//
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
//
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 25:
|
||||||
|
//
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 26:
|
||||||
|
//
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 27:
|
||||||
|
//
|
||||||
|
byte[] year = new byte[2];
|
||||||
|
year[0] = value[0];
|
||||||
|
year[1] = value[1];
|
||||||
|
Integer yearInt = ByteUtils.toInt(year[0], year[1]);
|
||||||
|
Integer monthInt = ByteUtils.toInt(value[2]);
|
||||||
|
Integer dayInt = ByteUtils.toInt(value[3]);
|
||||||
|
Integer worddayInt = ByteUtils.toInt(value[4]);
|
||||||
|
Integer hourInt = ByteUtils.toInt(value[5]);
|
||||||
|
Integer minuInt = ByteUtils.toInt(value[6]);
|
||||||
|
Integer secondInt = ByteUtils.toInt(value[7]);
|
||||||
|
res = yearInt+"-"+monthInt+"-"+dayInt+"-"+worddayInt+"-"+hourInt+"-"+minuInt+"-"+secondInt;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//什么也不做
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}else {
|
||||||
|
Object res = null;
|
||||||
|
switch (dataType) {
|
||||||
|
case 1:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toBoolArray(value);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toByteArray(value);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toWordArray(value);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toDWordArray(value);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
//
|
||||||
|
res = ByteUtils.toCharArray(value);
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
//
|
||||||
|
res =ByteUtils.toSIntArray(value);
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
res = ByteUtils.toIntArray(value);
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
res = ByteUtils.toDIntArray(value);
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
res = ByteUtils.toUIntArray(value);
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
res = ByteUtils.toUSIntArray(value);
|
||||||
|
break;
|
||||||
|
case 11:
|
||||||
|
res = ByteUtils.toUDIntArray(value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 12:
|
||||||
|
//后续有其他数组类型 ,再补充好了,先列出一些常用的。
|
||||||
|
//本来这里 是吧byte[] => String[] 的,但是这里拿不到 String[] 的length 和 strSize, 所以就不在这里解析了在外面解析
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//什么也不做
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* area :DB块 或者其他块
|
||||||
|
* areaNumber :数据块编号 DB3
|
||||||
|
* byteOffset :字节偏移量
|
||||||
|
* byteOffset :比特偏移量(不填就是0 ,差不多只有读bool类型才会用到)
|
||||||
|
* length :长度(1 代表单个变量 ,2/3/4 代表读一个数组。)
|
||||||
|
* */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,350 @@
|
|||||||
|
package com.cnbm.s7.s7connector.type;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public enum TransportSize {
|
||||||
|
|
||||||
|
BOOL((byte) 0x01, (boolean) true, (boolean) true, (short) 0x01, (short) 1, (boolean) true, (boolean) true, (short) 'X', (boolean) true, DataTransportSize.BIT, null, (String) "IEC61131_BOOL"),
|
||||||
|
BYTE((byte) 0x02, (boolean) true, (boolean) true, (short) 0x02, (short) 1, (boolean) true, (boolean) true, (short) 'B', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, null, (String) "IEC61131_BYTE"),
|
||||||
|
WORD((byte) 0x03, (boolean) true, (boolean) true, (short) 0x04, (short) 2, (boolean) true, (boolean) true, (short) 'W', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, null, (String) "IEC61131_WORD"),
|
||||||
|
DWORD((byte) 0x04, (boolean) true, (boolean) true, (short) 0x06, (short) 4, (boolean) true, (boolean) true, (short) 'D', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, TransportSize.WORD, (String) "IEC61131_DWORD"),
|
||||||
|
LWORD((byte) 0x05, (boolean) false, (boolean) false, (short) 0x00, (short) 8, (boolean) false, (boolean) false, (short) 'X', (boolean) true, null, null, (String) "IEC61131_LWORD"),
|
||||||
|
INT((byte) 0x06, (boolean) true, (boolean) true, (short) 0x05, (short) 2, (boolean) true, (boolean) true, (short) 'W', (boolean) true, DataTransportSize.INTEGER, null, (String) "IEC61131_INT"),
|
||||||
|
UINT((byte) 0x07, (boolean) false, (boolean) true, (short) 0x05, (short) 2, (boolean) false, (boolean) true, (short) 'W', (boolean) true, DataTransportSize.INTEGER, TransportSize.INT, (String) "IEC61131_UINT"),
|
||||||
|
SINT((byte) 0x08, (boolean) false, (boolean) true, (short) 0x02, (short) 1, (boolean) false, (boolean) true, (short) 'B', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, TransportSize.INT, (String) "IEC61131_SINT"),
|
||||||
|
USINT((byte) 0x09, (boolean) false, (boolean) true, (short) 0x02, (short) 1, (boolean) false, (boolean) true, (short) 'B', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, TransportSize.INT, (String) "IEC61131_USINT"),
|
||||||
|
DINT((byte) 0x0A, (boolean) true, (boolean) true, (short) 0x07, (short) 4, (boolean) true, (boolean) true, (short) 'D', (boolean) true, DataTransportSize.INTEGER, TransportSize.INT, (String) "IEC61131_DINT"),
|
||||||
|
UDINT((byte) 0x0B, (boolean) false, (boolean) true, (short) 0x07, (short) 4, (boolean) false, (boolean) true, (short) 'D', (boolean) true, DataTransportSize.INTEGER, TransportSize.INT, (String) "IEC61131_UDINT"),
|
||||||
|
LINT((byte) 0x0C, (boolean) false, (boolean) false, (short) 0x00, (short) 8, (boolean) false, (boolean) false, (short) 'X', (boolean) true, null, TransportSize.INT, (String) "IEC61131_LINT"),
|
||||||
|
ULINT((byte) 0x0D, (boolean) false, (boolean) false, (short) 0x00, (short) 16, (boolean) false, (boolean) false, (short) 'X', (boolean) true, null, TransportSize.INT, (String) "IEC61131_ULINT"),
|
||||||
|
REAL((byte) 0x0E, (boolean) true, (boolean) true, (short) 0x08, (short) 4, (boolean) true, (boolean) true, (short) 'D', (boolean) true, DataTransportSize.REAL, null, (String) "IEC61131_REAL"),
|
||||||
|
LREAL((byte) 0x0F, (boolean) false, (boolean) false, (short) 0x30, (short) 8, (boolean) false, (boolean) true, (short) 'X', (boolean) true, null, TransportSize.REAL, (String) "IEC61131_LREAL"),
|
||||||
|
CHAR((byte) 0x10, (boolean) true, (boolean) true, (short) 0x03, (short) 1, (boolean) true, (boolean) true, (short) 'B', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, null, (String) "IEC61131_CHAR"),
|
||||||
|
WCHAR((byte) 0x11, (boolean) false, (boolean) true, (short) 0x13, (short) 2, (boolean) false, (boolean) true, (short) 'X', (boolean) true, null, null, (String) "IEC61131_WCHAR"),
|
||||||
|
STRING((byte) 0x12, (boolean) true, (boolean) true, (short) 0x03, (short) 1, (boolean) true, (boolean) true, (short) 'X', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, null, (String) "IEC61131_STRING"),
|
||||||
|
WSTRING((byte) 0x13, (boolean) false, (boolean) true, (short) 0x00, (short) 2, (boolean) false, (boolean) true, (short) 'X', (boolean) true, null, null, (String) "IEC61131_WSTRING"),
|
||||||
|
TIME((byte) 0x14, (boolean) true, (boolean) true, (short) 0x0B, (short) 4, (boolean) true, (boolean) true, (short) 'X', (boolean) true, null, null, (String) "IEC61131_TIME"),
|
||||||
|
LTIME((byte) 0x16, (boolean) false, (boolean) false, (short) 0x00, (short) 8, (boolean) false, (boolean) false, (short) 'X', (boolean) true, null, TransportSize.TIME, (String) "IEC61131_LTIME"),
|
||||||
|
DATE((byte) 0x17, (boolean) true, (boolean) true, (short) 0x09, (short) 2, (boolean) true, (boolean) true, (short) 'X', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, null, (String) "IEC61131_DATE"),
|
||||||
|
TIME_OF_DAY((byte) 0x18, (boolean) true, (boolean) true, (short) 0x06, (short) 4, (boolean) true, (boolean) true, (short) 'X', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, null, (String) "IEC61131_TIME_OF_DAY"),
|
||||||
|
TOD((byte) 0x19, (boolean) true, (boolean) true, (short) 0x06, (short) 4, (boolean) true, (boolean) true, (short) 'X', (boolean) true, DataTransportSize.BYTE_WORD_DWORD, null, (String) "IEC61131_TIME_OF_DAY"),
|
||||||
|
DATE_AND_TIME((byte) 0x1A, (boolean) true, (boolean) false, (short) 0x0F, (short) 12, (boolean) true, (boolean) false, (short) 'X', (boolean) true, null, null, (String) "IEC61131_DATE_AND_TIME"),
|
||||||
|
DT((byte) 0x1B, (boolean) true, (boolean) false, (short) 0x0F, (short) 12, (boolean) true, (boolean) false, (short) 'X', (boolean) true, null, null, (String) "IEC61131_DATE_AND_TIME"),
|
||||||
|
DTL((byte) 0x1C, (boolean) true, (boolean) false, (short) 0x02, (short) 12, (boolean) true, (boolean) false, (short) 'X', (boolean) true, null, null, (String) "IEC61131_DATE_AND_TIME");
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(TransportSize.class);
|
||||||
|
|
||||||
|
private static final Map<Byte, TransportSize> map;
|
||||||
|
static {
|
||||||
|
map = new HashMap<>();
|
||||||
|
for (TransportSize value : TransportSize.values()) {
|
||||||
|
map.put((byte) value.getValue(), value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//value 类似于TransportSize 的ID
|
||||||
|
private byte value;
|
||||||
|
private boolean supported_S7_300;
|
||||||
|
private boolean supported_LOGO;
|
||||||
|
private short code;
|
||||||
|
private short sizeInBytes;
|
||||||
|
private boolean supported_S7_400;
|
||||||
|
private boolean supported_S7_1200;
|
||||||
|
private short shortName;
|
||||||
|
private boolean supported_S7_1500;
|
||||||
|
private DataTransportSize dataTransportSize;
|
||||||
|
private TransportSize baseType;
|
||||||
|
private String dataProtocolId;
|
||||||
|
|
||||||
|
TransportSize(byte value, boolean supported_S7_300, boolean supported_LOGO, short code, short sizeInBytes, boolean supported_S7_400, boolean supported_S7_1200, short shortName, boolean supported_S7_1500, DataTransportSize dataTransportSize, TransportSize baseType, String dataProtocolId) {
|
||||||
|
this.value = value;
|
||||||
|
this.supported_S7_300 = supported_S7_300;
|
||||||
|
this.supported_LOGO = supported_LOGO;
|
||||||
|
//Parameter ITEM 的transportSize
|
||||||
|
this.code = code;
|
||||||
|
this.sizeInBytes = sizeInBytes;
|
||||||
|
this.supported_S7_400 = supported_S7_400;
|
||||||
|
this.supported_S7_1200 = supported_S7_1200;
|
||||||
|
this.shortName = shortName;
|
||||||
|
this.supported_S7_1500 = supported_S7_1500;
|
||||||
|
//Data ITEM 的transportSize
|
||||||
|
this.dataTransportSize = dataTransportSize;
|
||||||
|
this.baseType = baseType;
|
||||||
|
this.dataProtocolId = dataProtocolId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getSupported_S7_300() {
|
||||||
|
return supported_S7_300;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TransportSize firstEnumForFieldSupported_S7_300(boolean fieldValue) {
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getSupported_S7_300() == fieldValue) {
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<TransportSize> enumsForFieldSupported_S7_300(boolean fieldValue) {
|
||||||
|
List<TransportSize> _values = new ArrayList();
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getSupported_S7_300() == fieldValue) {
|
||||||
|
_values.add(_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getSupported_LOGO() {
|
||||||
|
return supported_LOGO;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TransportSize firstEnumForFieldSupported_LOGO(boolean fieldValue) {
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getSupported_LOGO() == fieldValue) {
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<TransportSize> enumsForFieldSupported_LOGO(boolean fieldValue) {
|
||||||
|
List<TransportSize> _values = new ArrayList();
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getSupported_LOGO() == fieldValue) {
|
||||||
|
_values.add(_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TransportSize firstEnumForFieldCode(short fieldValue) {
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getCode() == fieldValue) {
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<TransportSize> enumsForFieldCode(short fieldValue) {
|
||||||
|
List<TransportSize> _values = new ArrayList();
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getCode() == fieldValue) {
|
||||||
|
_values.add(_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getSizeInBytes() {
|
||||||
|
return sizeInBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TransportSize firstEnumForFieldSizeInBytes(short fieldValue) {
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getSizeInBytes() == fieldValue) {
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<TransportSize> enumsForFieldSizeInBytes(short fieldValue) {
|
||||||
|
List<TransportSize> _values = new ArrayList();
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getSizeInBytes() == fieldValue) {
|
||||||
|
_values.add(_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getSupported_S7_400() {
|
||||||
|
return supported_S7_400;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TransportSize firstEnumForFieldSupported_S7_400(boolean fieldValue) {
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getSupported_S7_400() == fieldValue) {
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<TransportSize> enumsForFieldSupported_S7_400(boolean fieldValue) {
|
||||||
|
List<TransportSize> _values = new ArrayList();
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getSupported_S7_400() == fieldValue) {
|
||||||
|
_values.add(_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getSupported_S7_1200() {
|
||||||
|
return supported_S7_1200;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TransportSize firstEnumForFieldSupported_S7_1200(boolean fieldValue) {
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getSupported_S7_1200() == fieldValue) {
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<TransportSize> enumsForFieldSupported_S7_1200(boolean fieldValue) {
|
||||||
|
List<TransportSize> _values = new ArrayList();
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getSupported_S7_1200() == fieldValue) {
|
||||||
|
_values.add(_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getShortName() {
|
||||||
|
return shortName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TransportSize firstEnumForFieldShortName(short fieldValue) {
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getShortName() == fieldValue) {
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<TransportSize> enumsForFieldShortName(short fieldValue) {
|
||||||
|
List<TransportSize> _values = new ArrayList();
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getShortName() == fieldValue) {
|
||||||
|
_values.add(_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getSupported_S7_1500() {
|
||||||
|
return supported_S7_1500;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TransportSize firstEnumForFieldSupported_S7_1500(boolean fieldValue) {
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getSupported_S7_1500() == fieldValue) {
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<TransportSize> enumsForFieldSupported_S7_1500(boolean fieldValue) {
|
||||||
|
List<TransportSize> _values = new ArrayList();
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getSupported_S7_1500() == fieldValue) {
|
||||||
|
_values.add(_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataTransportSize getDataTransportSize() {
|
||||||
|
return dataTransportSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TransportSize firstEnumForFieldDataTransportSize(DataTransportSize fieldValue) {
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getDataTransportSize() == fieldValue) {
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<TransportSize> enumsForFieldDataTransportSize(DataTransportSize fieldValue) {
|
||||||
|
List<TransportSize> _values = new ArrayList();
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getDataTransportSize() == fieldValue) {
|
||||||
|
_values.add(_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransportSize getBaseType() {
|
||||||
|
return baseType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TransportSize firstEnumForFieldBaseType(TransportSize fieldValue) {
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getBaseType() == fieldValue) {
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<TransportSize> enumsForFieldBaseType(TransportSize fieldValue) {
|
||||||
|
List<TransportSize> _values = new ArrayList();
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getBaseType() == fieldValue) {
|
||||||
|
_values.add(_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataProtocolId() {
|
||||||
|
return dataProtocolId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TransportSize firstEnumForFieldDataProtocolId(String fieldValue) {
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getDataProtocolId() == fieldValue) {
|
||||||
|
return _val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<TransportSize> enumsForFieldDataProtocolId(String fieldValue) {
|
||||||
|
List<TransportSize> _values = new ArrayList();
|
||||||
|
for (TransportSize _val : TransportSize.values()) {
|
||||||
|
if(_val.getDataProtocolId() == fieldValue) {
|
||||||
|
_values.add(_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TransportSize enumForValue(byte value) {
|
||||||
|
if (!map.containsKey(value)) {
|
||||||
|
logger.error("No TransportSize for value {}", value);
|
||||||
|
}
|
||||||
|
return map.get(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Boolean isDefined(byte value) {
|
||||||
|
return map.containsKey(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.cnbm.s7.s7connector.utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Desc: ""
|
||||||
|
* @Author: caixiang
|
||||||
|
* @DATE: 2022/12/5 11:11
|
||||||
|
*/
|
||||||
|
public class CommonFunctions {
|
||||||
|
/**
|
||||||
|
* a 整除 b ,如果有余数+1
|
||||||
|
* */
|
||||||
|
public static Integer exactDivision(Integer a,Integer b) {
|
||||||
|
|
||||||
|
int c = a/b;
|
||||||
|
|
||||||
|
if(a%b!=0){
|
||||||
|
c = a/b+1;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user