├── app
├── .gitignore
├── src
│ ├── main
│ │ ├── res
│ │ │ ├── values
│ │ │ │ ├── strings.xml
│ │ │ │ ├── colors.xml
│ │ │ │ └── styles.xml
│ │ │ ├── mipmap-hdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-mdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ │ ├── ic_launcher.png
│ │ │ │ └── ic_launcher_round.png
│ │ │ ├── mipmap-anydpi-v26
│ │ │ │ ├── ic_launcher.xml
│ │ │ │ └── ic_launcher_round.xml
│ │ │ ├── menu
│ │ │ │ └── menu.xml
│ │ │ ├── layout
│ │ │ │ ├── activity_management.xml
│ │ │ │ ├── activity_main.xml
│ │ │ │ ├── activity_login.xml
│ │ │ │ ├── activity_settings.xml
│ │ │ │ ├── activity_management_user.xml
│ │ │ │ ├── activity_register.xml
│ │ │ │ ├── activity_automaton_comp.xml
│ │ │ │ └── activity_automaton_asserv.xml
│ │ │ ├── drawable-v24
│ │ │ │ └── ic_launcher_foreground.xml
│ │ │ └── drawable
│ │ │ │ └── ic_launcher_background.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── example
│ │ │ │ └── fabio
│ │ │ │ └── plcmonitor
│ │ │ │ ├── SimaticS7
│ │ │ │ ├── IntByRef.java
│ │ │ │ ├── S7Szl.java
│ │ │ │ ├── S7CpInfo.java
│ │ │ │ ├── S7Protection.java
│ │ │ │ ├── S7OrderCode.java
│ │ │ │ ├── S7CpuInfo.java
│ │ │ │ ├── S7BlockInfo.java
│ │ │ │ ├── S7.java
│ │ │ │ └── S7Client.java
│ │ │ │ ├── Configs.java
│ │ │ │ ├── Activity
│ │ │ │ ├── MainActivity.java
│ │ │ │ ├── SettingsActivity.java
│ │ │ │ ├── LoginActivity.java
│ │ │ │ ├── ManagementActivity.java
│ │ │ │ ├── RegisterActivity.java
│ │ │ │ ├── ManagementUserActivity.java
│ │ │ │ ├── AutomatonCompActivity.java
│ │ │ │ └── AutomatonAsservActivity.java
│ │ │ │ ├── BDD
│ │ │ │ ├── User.java
│ │ │ │ ├── UserBddSqlite.java
│ │ │ │ └── UserAccessDB.java
│ │ │ │ └── Automaton
│ │ │ │ ├── WriteTaskS7.java
│ │ │ │ └── ReadTaskS7.java
│ │ └── AndroidManifest.xml
│ ├── test
│ │ └── java
│ │ │ └── com
│ │ │ └── example
│ │ │ └── fabio
│ │ │ └── plcmonitor
│ │ │ └── ExampleUnitTest.java
│ └── androidTest
│ │ └── java
│ │ └── com
│ │ └── example
│ │ └── fabio
│ │ └── plcmonitor
│ │ └── ExampleInstrumentedTest.java
├── proguard-rules.pro
└── build.gradle
├── settings.gradle
├── Report.pdf
├── assets
├── screen1.jpg
├── screen2.jpg
├── screen3.jpg
├── screen4.jpg
├── screen5.jpg
├── screen6.jpg
├── screen7.jpg
└── screen8.jpg
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .idea
├── vcs.xml
├── runConfigurations.xml
├── gradle.xml
├── codeStyles
│ └── Project.xml
└── misc.xml
├── .gitignore
├── gradle.properties
├── README.md
├── gradlew.bat
└── gradlew
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/Report.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/Report.pdf
--------------------------------------------------------------------------------
/assets/screen1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/assets/screen1.jpg
--------------------------------------------------------------------------------
/assets/screen2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/assets/screen2.jpg
--------------------------------------------------------------------------------
/assets/screen3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/assets/screen3.jpg
--------------------------------------------------------------------------------
/assets/screen4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/assets/screen4.jpg
--------------------------------------------------------------------------------
/assets/screen5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/assets/screen5.jpg
--------------------------------------------------------------------------------
/assets/screen6.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/assets/screen6.jpg
--------------------------------------------------------------------------------
/assets/screen7.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/assets/screen7.jpg
--------------------------------------------------------------------------------
/assets/screen8.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/assets/screen8.jpg
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | PLCMonitor
3 |
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/l-Legacy-l/S7-PLC-Monitor/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches/build_file_checksums.ser
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | .DS_Store
9 | /build
10 | /captures
11 | .externalNativeBuild
12 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 | #00FF00
7 | #ff0000
8 | #ff7700
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/example/fabio/plcmonitor/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.example.fabio.plcmonitor;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/SimaticS7/IntByRef.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 |
7 | package com.example.fabio.plcmonitor.SimaticS7;
8 |
9 | /**
10 | * Quick class to pass an integer by reference
11 | * @author Davide
12 | */
13 |
14 | public class IntByRef {
15 |
16 | public IntByRef(int Val)
17 | {
18 | this.Value=Val;
19 | }
20 | public IntByRef()
21 | {
22 | this.Value=0;
23 | }
24 | public int Value;
25 | }
26 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/SimaticS7/S7Szl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 |
7 | package com.example.fabio.plcmonitor.SimaticS7;
8 |
9 | /**
10 | *
11 | * @author Davide
12 | */
13 | public class S7Szl {
14 |
15 | public int LENTHDR;
16 | public int N_DR;
17 | public int DataSize;
18 | public byte Data[];
19 |
20 | public S7Szl(int BufferSize)
21 | {
22 | Data = new byte[BufferSize];
23 | }
24 | protected void Copy(byte[] Src, int SrcPos, int DestPos, int Size)
25 | {
26 | System.arraycopy(Src, SrcPos, Data, DestPos, Size);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/SimaticS7/S7CpInfo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 |
7 | package com.example.fabio.plcmonitor.SimaticS7;
8 |
9 | /**
10 | *
11 | * @author Davide
12 | */
13 | public class S7CpInfo {
14 |
15 | public int MaxPduLength;
16 | public int MaxConnections;
17 | public int MaxMpiRate;
18 | public int MaxBusRate;
19 |
20 | protected void Update(byte[] Src, int Pos)
21 | {
22 | MaxPduLength = S7.GetShortAt(Src, 2);
23 | MaxConnections = S7.GetShortAt(Src, 4);
24 | MaxMpiRate = S7.GetDIntAt(Src, 6);
25 | MaxBusRate = S7.GetDIntAt(Src, 10);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/SimaticS7/S7Protection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 | package com.example.fabio.plcmonitor.SimaticS7;
7 |
8 | // See §33.19 of "System Software for S7-300/400 System and Standard Functions"
9 | public class S7Protection {
10 | public int sch_schal;
11 | public int sch_par;
12 | public int sch_rel;
13 | public int bart_sch;
14 | public int anl_sch;
15 | protected void Update(byte[] Src)
16 | {
17 | sch_schal = S7.GetWordAt(Src,2);
18 | sch_par = S7.GetWordAt(Src,4);
19 | sch_rel = S7.GetWordAt(Src,6);
20 | bart_sch = S7.GetWordAt(Src,8);
21 | anl_sch = S7.GetWordAt(Src,10);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/SimaticS7/S7OrderCode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 |
7 | package com.example.fabio.plcmonitor.SimaticS7;
8 |
9 | /**
10 | *
11 | * @author Davide
12 | */
13 | public class S7OrderCode {
14 |
15 | public int V1;
16 | public int V2;
17 | public int V3;
18 | protected byte[] Buffer = new byte[1024];
19 |
20 | protected void Update(byte[] Src, int Pos, int Size)
21 | {
22 | System.arraycopy(Src, Pos, Buffer, 0, Size);
23 | V1 = (byte) Src[Size-3];
24 | V2 = (byte) Src[Size-2];
25 | V3 = (byte) Src[Size-1];
26 | }
27 |
28 | public String Code()
29 | {
30 | return S7.GetStringAt(Buffer, 2, 20);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/example/fabio/plcmonitor/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.example.fabio.plcmonitor;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.example.fabio.plcmonitor", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | defaultConfig {
6 | applicationId "com.example.fabio.plcmonitor"
7 | minSdkVersion 21
8 | targetSdkVersion 28
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | }
20 |
21 | dependencies {
22 | implementation fileTree(dir: 'libs', include: ['*.jar'])
23 | implementation 'com.android.support:appcompat-v7:28.0.0'
24 | implementation 'com.android.support.constraint:constraint-layout:1.1.3'
25 | testImplementation 'junit:junit:4.12'
26 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
27 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_management.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/SimaticS7/S7CpuInfo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 |
7 | package com.example.fabio.plcmonitor.SimaticS7;
8 |
9 | /**
10 | *
11 | * @author Davide
12 | */
13 | public class S7CpuInfo {
14 |
15 | private final int BufSize = 256;
16 | protected byte[] Buffer = new byte[BufSize];
17 |
18 | protected void Update(byte[] Src, int Pos)
19 | {
20 | System.arraycopy(Src, Pos, Buffer, 0, BufSize);
21 | }
22 |
23 | public String ModuleTypeName()
24 | {
25 | return S7.GetStringAt(Buffer,172,32);
26 | }
27 | public String SerialNumber()
28 | {
29 | return S7.GetStringAt(Buffer,138,24);
30 | }
31 | public String ASName()
32 | {
33 | return S7.GetStringAt(Buffer,2,24);
34 | }
35 | public String Copyright()
36 | {
37 | return S7.GetStringAt(Buffer,104,26);
38 | }
39 | public String ModuleName()
40 | {
41 | return S7.GetStringAt(Buffer,36,24);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/Configs.java:
--------------------------------------------------------------------------------
1 | package com.example.fabio.plcmonitor;
2 |
3 | public class Configs
4 | {
5 | static String ip = "192.168.0.10";
6 | static int rack = 0;
7 | static int slot = 2;
8 | static int datablock = 5;
9 | static boolean isWriteAccess = false;
10 | static boolean isAdmin = false;
11 |
12 | public static String getIp() {
13 | return ip;
14 | }
15 |
16 | public static void setIp(String ip) {
17 | Configs.ip = ip;
18 | }
19 |
20 | public static int getRack() {
21 | return rack;
22 | }
23 |
24 | public static void setRack(int rack) {
25 | Configs.rack = rack;
26 | }
27 |
28 | public static int getSlot() {
29 | return slot;
30 | }
31 |
32 | public static void setSlot(int slot) {
33 | Configs.slot = slot;
34 | }
35 | public static int getDatablock() {
36 | return datablock;
37 | }
38 |
39 | public static void setDatablock(int datablock) {
40 | Configs.datablock = datablock;
41 | }
42 |
43 | public static void setIsWriteAccess(boolean writeAccess){Configs.isWriteAccess = writeAccess;}
44 |
45 | public static boolean getIsWriteAccess() {return isWriteAccess;}
46 |
47 | public static boolean getIsAdmin() {
48 | return isAdmin;
49 | }
50 |
51 | public static void setIsAdmin(boolean isAdmin) {
52 | Configs.isAdmin = isAdmin;
53 | }
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_login.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
28 |
29 |
38 |
39 |
47 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/Activity/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.fabio.plcmonitor.Activity;
2 |
3 | import android.app.AlertDialog;
4 | import android.content.DialogInterface;
5 | import android.content.Intent;
6 | import android.os.Handler;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.os.Bundle;
9 | import android.view.KeyEvent;
10 | import android.view.View;
11 | import android.widget.Toast;
12 |
13 | import com.example.fabio.plcmonitor.R;
14 |
15 | public class MainActivity extends AppCompatActivity {
16 |
17 | @Override
18 | protected void onCreate(Bundle savedInstanceState) {
19 | super.onCreate(savedInstanceState);
20 | setContentView(R.layout.activity_main);
21 | }
22 |
23 |
24 | public void btnClick(View v)
25 | {
26 | if(v.getId() == R.id.bt_main_con)
27 | {
28 | Intent intent = new Intent(getApplicationContext(),LoginActivity.class);
29 | startActivity(intent);
30 | }
31 |
32 | else
33 | {
34 | Intent intent = new Intent(getApplicationContext(),RegisterActivity.class);
35 | startActivity(intent);
36 | }
37 | }
38 |
39 | boolean doubleBackToExitPressedOnce = false;
40 |
41 | @Override
42 | public void onBackPressed() {
43 | if (doubleBackToExitPressedOnce) {
44 | super.onBackPressed();
45 | return;
46 | }
47 |
48 | this.doubleBackToExitPressedOnce = true;
49 | Toast.makeText(this, "Appuyer 2 fois pour quitter l'application", Toast.LENGTH_SHORT).show();
50 |
51 | new Handler().postDelayed(new Runnable() {
52 |
53 | @Override
54 | public void run() {
55 | doubleBackToExitPressedOnce=false;
56 | }
57 | }, 2000);
58 | }
59 | }
60 |
61 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/BDD/User.java:
--------------------------------------------------------------------------------
1 | package com.example.fabio.plcmonitor.BDD;
2 |
3 | public class User {
4 |
5 | private int id;
6 | private String firstname, lastname, email, mdp;
7 | private boolean writeAccess, isAdmin;
8 |
9 | public User() {}
10 |
11 | public User(String lastname,String firstname, String email, String mdp,boolean writeAccess, boolean isAdmin){
12 | this.lastname = lastname;
13 | this.firstname = firstname;
14 | this.email = email;
15 | this.mdp = mdp;
16 | this.writeAccess = writeAccess;
17 | this.isAdmin = isAdmin;
18 | }
19 |
20 | public int getId(){return id;}
21 | public void setId(int i){this.id = i;}
22 |
23 | public String getFirstname(){return firstname;}
24 | public void setFirstname(String firstname){this.firstname = firstname;}
25 |
26 | public String getLastname(){return lastname;}
27 | public void setLastname(String lastname){this.lastname = lastname;}
28 |
29 | public String getEmail(){return email;}
30 | public void setEmail(String email){this.email = email;}
31 |
32 | public String getMdp(){return mdp;}
33 | public void setMdp(String mdp){this.mdp = mdp;}
34 |
35 | public boolean getWriteAccess() { return writeAccess; }
36 | public void setWriteAccess(boolean writeAccess) { this.writeAccess = writeAccess; }
37 |
38 | public boolean getIsAdmin(){return isAdmin;}
39 | public void setIsAdmin(boolean isAdmin){this.isAdmin = isAdmin;}
40 |
41 | @Override
42 | public String toString(){
43 | return "ID: "+Integer.toString(id)+"\n"
44 | +"Email: "+email+"\n"
45 | +"Password: "+mdp+"\n"
46 | +"Nom: "+lastname+"\n"
47 | +"Prenom: "+firstname+"\n"
48 | +"Admin: "+isAdmin;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/BDD/UserBddSqlite.java:
--------------------------------------------------------------------------------
1 | package com.example.fabio.plcmonitor.BDD;
2 |
3 | import android.content.Context;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.database.sqlite.SQLiteOpenHelper;
6 |
7 | public class UserBddSqlite extends SQLiteOpenHelper {
8 |
9 | private static final String TABLE_USER = "table_user";
10 | private static final String COL_ID = "ID";
11 | private static final String COL_EMAIL = "EMAIL";
12 | private static final String COL_PASSWORD = "PASSWORD";
13 | private static final String COL_LASTNAME = "LASTNAME";
14 | private static final String COL_FIRSTNAME = "FIRSTNAME";
15 | private static final String COL_WRITE = "WRITE";
16 | private static final String COL_ADMIN = "ADMIN";
17 |
18 | private static final String CREATE_BDD =
19 | "CREATE TABLE "+TABLE_USER+
20 | " ("+COL_ID+" INTEGER PRIMARY KEY AUTOINCREMENT, "+COL_EMAIL+" TEXT NOT NULL, "
21 | +COL_PASSWORD+" TEXT NOT NULL, "+COL_LASTNAME+" TEXT NOT NULL, "+COL_FIRSTNAME+" TEXT NOT NULL, "+COL_WRITE+" TEXT NOT NULL, "+COL_ADMIN+" TEXT NOT NULL);";
22 |
23 | public UserBddSqlite(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
24 | super(context, name, factory, version);
25 | }
26 |
27 | @Override
28 | public void onCreate(SQLiteDatabase db) {
29 | db.execSQL(CREATE_BDD);
30 | //utilisateur admin
31 | db.execSQL("INSERT INTO table_user (EMAIL, LASTNAME, FIRSTNAME, PASSWORD, WRITE, ADMIN) VALUES ('admin@gmail.com', 'root', 'user', 'Test123*', 1, 1)");
32 |
33 | }
34 |
35 | @Override
36 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
37 | db.execSQL("DROP TABLE " + TABLE_USER);
38 | onCreate(db);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # S7-PLC-Monitor
2 |
3 | This project was carried out as part of the mobile development course at the Haute école en Hainaut. It aims to create an application on Android to supervise and remotely control 2 industrial processes.
4 |
5 | - Tablet packaging, controlled by the S7-1516 2DPPN PLC.
6 |
7 | - Liquid level control, controlled by PLC S7-1214C.
8 |
9 | ## Features
10 |
11 | The application is very easy to use and provides basic functionalities.
12 |
13 | - Reading of real-time PLC values with Thread & Handler.
14 |
15 | - Writing values in the PLC.
16 |
17 | - User management (default administrator account) with SQLite.
18 |
19 | - Access management for reading and writing in PLCs.
20 |
21 | - Basic security (regex, minimum password length, access management).
22 |
23 | - Settings for connection to the PLC (IP, rack, slot).
24 |
25 | For more information about the application and software used for the PLC, you can consult the `Report.pdf` file (in .French).
26 |
27 |
28 |
29 | ## Improvements
30 |
31 | Some interesting improvements could be made to this project to complete it.
32 |
33 | - An additional table concerning the configuration of the PLCs in the database would be interesting. Indeed, on the one hand, this would make it possible to do not redefine the access configuration each time the application is launched to the PLC. On the other hand, it would allow the user to manage several PLCs with different configurations on the application. It would therefore also be necessary to improve the UI.
34 |
35 | - The use of an encrypted database to guarantee a better security.
36 |
37 | - Store only a hash of user passwords to improve
38 | security again.
39 |
40 | ## Screenshots
41 |
42 |  
43 |
44 |  
45 |
46 |  
47 |
48 |  
49 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
19 |
20 |
29 |
30 |
39 |
40 |
49 |
50 |
58 |
59 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/SimaticS7/S7BlockInfo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 |
7 | package com.example.fabio.plcmonitor.SimaticS7;
8 | import java.util.Date;
9 | /**
10 | *
11 | * @author Davide
12 | */
13 | public class S7BlockInfo {
14 |
15 | private final int BufSize = 96;
16 | // MilliSeconds between 1970/1/1 (Java time base) and 1984/1/1 (Siemens base)
17 | private final long DeltaMilliSecs = 441763200000L;
18 | protected byte[] Buffer = new byte[BufSize];
19 |
20 | protected void Update(byte[] Src, int Pos)
21 | {
22 | System.arraycopy(Src, Pos, Buffer, 0, BufSize);
23 | }
24 | public int BlkType()
25 | {
26 | return Buffer[2];
27 | }
28 | public int BlkNumber()
29 | {
30 | return S7.GetWordAt(Buffer, 3);
31 | }
32 | public int BlkLang()
33 | {
34 | return Buffer[1];
35 | }
36 | public int BlkFlags()
37 | {
38 | return Buffer[0];
39 | }
40 | public int MC7Size() // The real size in bytes
41 | {
42 | return S7.GetWordAt(Buffer, 31);
43 | }
44 | public int LoadSize()
45 | {
46 | return S7.GetDIntAt(Buffer, 5);
47 | }
48 | public int LocalData()
49 | {
50 | return S7.GetWordAt(Buffer, 29);
51 | }
52 | public int SBBLength()
53 | {
54 | return S7.GetWordAt(Buffer, 25);
55 | }
56 | public int Checksum()
57 | {
58 | return S7.GetWordAt(Buffer, 59);
59 | }
60 | public int Version()
61 | {
62 | return Buffer[57];
63 | }
64 | public Date CodeDate()
65 | {
66 | long BlockDate = ((long)S7.GetWordAt(Buffer, 17))*86400000L+DeltaMilliSecs;
67 | return new Date(BlockDate);
68 | }
69 | public Date IntfDate()
70 | {
71 | long BlockDate = ((long)S7.GetWordAt(Buffer, 23))*86400000L+DeltaMilliSecs;
72 | return new Date(BlockDate);
73 | }
74 | public String Author()
75 | {
76 | return S7.GetStringAt(Buffer,33,8);
77 | }
78 | public String Family()
79 | {
80 | return S7.GetStringAt(Buffer,41,8);
81 | }
82 | public String Header()
83 | {
84 | return S7.GetStringAt(Buffer,49,8);
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/Activity/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.fabio.plcmonitor.Activity;
2 |
3 | import android.support.v7.app.AppCompatActivity;
4 | import android.os.Bundle;
5 | import android.view.View;
6 | import android.widget.EditText;
7 | import android.widget.Toast;
8 |
9 | import com.example.fabio.plcmonitor.Configs;
10 | import com.example.fabio.plcmonitor.R;
11 |
12 | public class SettingsActivity extends AppCompatActivity {
13 |
14 | EditText etIp;
15 | EditText etRack;
16 | EditText etSlot;
17 | EditText etDatablock;
18 |
19 | String ip;
20 | int rack;
21 | int slot;
22 | int datablock;
23 |
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | setContentView(R.layout.activity_settings);
28 |
29 | etIp = (EditText)findViewById(R.id.et_settings_ip);
30 | etRack = (EditText)findViewById(R.id.et_settings_rack);
31 | etSlot = (EditText)findViewById(R.id.et_settings_slot);
32 | etDatablock = (EditText)findViewById(R.id.et_settings_datablock);
33 |
34 | //On remplis par défaut la configuration déjà enregistré au préalable dans les champs
35 | etIp.setText(Configs.getIp());
36 | etRack.setText(String.valueOf(Configs.getRack()));
37 | etSlot.setText(String.valueOf(Configs.getSlot()));
38 | etDatablock.setText(String.valueOf(Configs.getDatablock()));
39 | }
40 |
41 | public void btnValiderClick(View v)
42 | {
43 | if(!(etIp.getText().toString().isEmpty()) && !(etRack.getText().toString().isEmpty()) && !(etSlot.getText().toString().isEmpty())
44 | && !(etDatablock.getText().toString().isEmpty()))
45 | {
46 | ip = etIp.getText().toString();
47 | rack = Integer.parseInt(etRack.getText().toString());
48 | slot = Integer.parseInt(etSlot.getText().toString());
49 | datablock = Integer.parseInt(etDatablock.getText().toString());
50 | //Enregistrement dans la classe statique (plus pratique dans ce cas pour ne pas avoir plusieurs instances)
51 | Configs.setIp(ip);
52 | Configs.setRack(rack);
53 | Configs.setSlot(slot);
54 | Configs.setDatablock(datablock);
55 |
56 | Toast.makeText(getApplicationContext(), "Enregistrement de la configuration effectué",Toast.LENGTH_SHORT).show();
57 |
58 | }
59 |
60 | else
61 | {
62 | Toast.makeText(getApplicationContext(), "Vous devez remplir tous les champs",Toast.LENGTH_SHORT).show();
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_management_user.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
27 |
28 |
40 |
41 |
50 |
51 |
60 |
61 |
69 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_register.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
17 |
18 |
19 |
26 |
27 |
36 |
37 |
46 |
47 |
56 |
57 |
66 |
67 |
76 |
77 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/Activity/LoginActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.fabio.plcmonitor.Activity;
2 |
3 | import android.content.Intent;
4 | import android.os.Parcelable;
5 | import android.support.v7.app.AppCompatActivity;
6 | import android.os.Bundle;
7 | import android.view.View;
8 | import android.widget.EditText;
9 | import android.widget.Toast;
10 |
11 | import com.example.fabio.plcmonitor.BDD.User;
12 | import com.example.fabio.plcmonitor.BDD.UserAccessDB;
13 | import com.example.fabio.plcmonitor.Configs;
14 | import com.example.fabio.plcmonitor.R;
15 |
16 | import java.io.Serializable;
17 |
18 | public class LoginActivity extends AppCompatActivity {
19 |
20 | String email;
21 | String mdp;
22 | EditText etEmail;
23 | EditText etMdp;
24 |
25 | @Override
26 | protected void onCreate(Bundle savedInstanceState) {
27 | super.onCreate(savedInstanceState);
28 | setContentView(R.layout.activity_login);
29 |
30 | etEmail = ((EditText)findViewById(R.id.et_login_email));
31 | etMdp = ((EditText)findViewById(R.id.et_login_mdp));
32 |
33 | }
34 |
35 | public void btnLoginClick(View v)
36 | {
37 | email = etEmail.getText().toString();
38 | mdp = etMdp.getText().toString();
39 |
40 | //Vérification champs remplis
41 | if(!email.isEmpty() && !mdp.isEmpty())
42 | {
43 | UserAccessDB db = new UserAccessDB(this);
44 | db.openForRead();
45 |
46 | //On recrée l'user
47 | try
48 | {
49 | User user1 = db.getUser(email);
50 | db.Close();
51 |
52 | //On vérifie si le mot de passe entrée correspond à l'user qui possède le mail
53 | if(mdp.equals(user1.getMdp()))
54 | {
55 | Toast.makeText(getApplicationContext(), "Bienvenue " + user1.getFirstname() + " "+user1.getLastname(),Toast.LENGTH_SHORT).show();
56 | if(user1.getIsAdmin())
57 | {
58 | Configs.setIsAdmin(true);
59 | }
60 | if(user1.getWriteAccess())
61 | {
62 | Configs.setIsWriteAccess(true);
63 | }
64 |
65 | //On est connecté, on passe à l'activité de management
66 | Intent intent = new Intent(getApplicationContext(), ManagementActivity.class);
67 | startActivity(intent);
68 |
69 | }
70 |
71 | else
72 | {
73 | Toast.makeText(this, "Le mot de passe est incorrect", Toast.LENGTH_LONG).show();
74 | }
75 | }
76 | catch (Exception e)
77 | {
78 | Toast.makeText(this, "L'adresse e-mail est incorrect", Toast.LENGTH_LONG).show();
79 | }
80 |
81 | }
82 |
83 | else
84 | {
85 | Toast.makeText(getApplicationContext(), "Tous les champs doivent être remplis",Toast.LENGTH_SHORT).show();
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/Activity/ManagementActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.fabio.plcmonitor.Activity;
2 |
3 | import android.app.AlertDialog;
4 | import android.content.DialogInterface;
5 | import android.content.Intent;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.os.Bundle;
8 | import android.view.KeyEvent;
9 | import android.view.Menu;
10 | import android.view.MenuItem;
11 | import android.view.View;
12 |
13 | import com.example.fabio.plcmonitor.Configs;
14 | import com.example.fabio.plcmonitor.R;
15 |
16 | public class ManagementActivity extends AppCompatActivity {
17 |
18 | MenuItem gestionItem;
19 | @Override
20 | protected void onCreate(Bundle savedInstanceState) {
21 | super.onCreate(savedInstanceState);
22 | setContentView(R.layout.activity_management);
23 |
24 | }
25 |
26 | @Override
27 | public boolean onCreateOptionsMenu(Menu menu) {
28 | //ajoute les entrées de menu.xml à l'ActionBar
29 | getMenuInflater().inflate(R.menu.menu, menu);
30 | gestionItem = menu.findItem(R.id.action_gestion);
31 |
32 | if(!Configs.getIsAdmin())
33 | {
34 | gestionItem.setVisible(false);
35 | }
36 | return true;
37 | }
38 |
39 |
40 | public void btnClick(View v)
41 | {
42 | if(v.getId() == R.id.bt_management_comprime)
43 | {
44 | Intent intent = new Intent(getApplicationContext(), AutomatonCompActivity.class);
45 | startActivity(intent);
46 | }
47 |
48 | else
49 | {
50 | Intent intent = new Intent(getApplicationContext(), AutomatonAsservActivity.class);
51 | startActivity(intent);
52 | }
53 | }
54 |
55 | @Override
56 | public boolean onOptionsItemSelected(MenuItem item) {
57 | if (item.getItemId() == R.id.action_gestion) {
58 | finish();
59 | Intent intent = new Intent(getApplicationContext(), ManagementUserActivity.class);
60 | startActivity(intent);
61 | }
62 |
63 | else
64 | {
65 | Intent intent = new Intent(getApplicationContext(), SettingsActivity.class);
66 | startActivity(intent);
67 | }
68 |
69 | return super.onOptionsItemSelected(item);
70 | }
71 |
72 | @Override
73 | public void onBackPressed()
74 | {
75 |
76 | final AlertDialog.Builder builder = new AlertDialog.Builder(ManagementActivity.this);
77 | builder.setMessage("Voulez vous vous déconnecter ?");
78 | builder.setCancelable(true);
79 | builder.setNegativeButton("Non", new DialogInterface.OnClickListener() {
80 | @Override
81 | public void onClick(DialogInterface dialogInterface, int i) {
82 | dialogInterface.cancel();
83 | }
84 | });
85 | builder.setPositiveButton("Oui", new DialogInterface.OnClickListener() {
86 | @Override
87 | public void onClick(DialogInterface dialogInterface, int i) {
88 | //on peut terminer cette activité
89 | finish();
90 | }
91 | });
92 | AlertDialog alertDialog = builder.create();
93 | alertDialog.show();
94 |
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/Activity/RegisterActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.fabio.plcmonitor.Activity;
2 |
3 | import android.content.Intent;
4 | import android.support.v7.app.AppCompatActivity;
5 | import android.os.Bundle;
6 | import android.view.View;
7 | import android.widget.EditText;
8 | import android.widget.Toast;
9 |
10 | import com.example.fabio.plcmonitor.BDD.User;
11 | import com.example.fabio.plcmonitor.BDD.UserAccessDB;
12 | import com.example.fabio.plcmonitor.R;
13 |
14 | public class RegisterActivity extends AppCompatActivity {
15 |
16 |
17 | EditText nom;
18 | EditText prenom;
19 | EditText email;
20 | EditText mdp;
21 |
22 | @Override
23 | protected void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | setContentView(R.layout.activity_register);
26 |
27 | nom = ((EditText)findViewById(R.id.et_register_nom));
28 | prenom = ((EditText)findViewById(R.id.et_register_pre));
29 | email = ((EditText)findViewById(R.id.et_register_email));
30 | mdp = ((EditText)findViewById(R.id.et_register_mdp));
31 |
32 | }
33 |
34 | public void registerClick(View v)
35 | {
36 | //Si les champs ne sont pas vide
37 | if(!nom.getText().toString().isEmpty() && !prenom.getText().toString().isEmpty() && !email.getText().toString().isEmpty() &&
38 | !mdp.getText().toString().isEmpty())
39 | {
40 | //Si le mail a un format valide
41 | if (isEmailValid(email.getText().toString()))
42 | {
43 | //Si le mot de passe contient 4 caractères au minimum
44 | if(mdp.length() >= 4)
45 | {
46 | //On peut créer l'utilisateur, par défaut accès uniquement en lecture et pas administrateur
47 | User user = new User(nom.getText().toString(),prenom.getText().toString(),email.getText().toString(),
48 | mdp.getText().toString(),false,false);
49 |
50 | UserAccessDB userDB = new UserAccessDB(this);
51 | userDB.openForWrite();
52 |
53 | //On vérifie que le mail n'a pas déja été utilisé pour éviter les doublons
54 | if(userDB.getUser(email.getText().toString()) == null)
55 | {
56 | userDB.insertUser(user);
57 | userDB.Close();
58 |
59 | Toast.makeText(getApplicationContext(), "Inscription réussie",Toast.LENGTH_SHORT).show();
60 | finish();
61 | //On affiche la page de connexion
62 | Intent intent = new Intent(getApplicationContext(), LoginActivity.class);
63 | startActivity(intent);
64 | }
65 |
66 | else
67 | {
68 | Toast.makeText(getApplicationContext(), "Cette adresse mail a déjà été utilisée",Toast.LENGTH_SHORT).show();
69 | userDB.Close();
70 | }
71 |
72 | }
73 |
74 | else
75 | {
76 | Toast.makeText(getApplicationContext(), "Le mot de passe doit contenir au minimum 4 caractères",Toast.LENGTH_SHORT).show();
77 | }
78 | }
79 |
80 | else
81 | {
82 | Toast.makeText(getApplicationContext(), "L'e-mail introduit est incorrect",Toast.LENGTH_SHORT).show();
83 | }
84 | }
85 |
86 | else
87 | {
88 | Toast.makeText(getApplicationContext(), "Vous devez compléter tous les champs !",Toast.LENGTH_SHORT).show();
89 | System.out.println("je passe "+nom);
90 | }
91 | }
92 |
93 | boolean isEmailValid(CharSequence email) {
94 | return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches();
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/Automaton/WriteTaskS7.java:
--------------------------------------------------------------------------------
1 | package com.example.fabio.plcmonitor.Automaton;
2 |
3 | import android.util.Log;
4 |
5 | import com.example.fabio.plcmonitor.Configs;
6 | import com.example.fabio.plcmonitor.SimaticS7.S7;
7 | import com.example.fabio.plcmonitor.SimaticS7.S7Client;
8 |
9 | import java.util.concurrent.atomic.AtomicBoolean;
10 |
11 | public class WriteTaskS7
12 | {
13 | private AtomicBoolean isRunning = new AtomicBoolean(false);
14 | private Thread writeThread;
15 | private AutomateS7 plcS7;
16 | private S7Client comS7;
17 | private String[] parConnexion = new String[10];
18 | private byte[] motCommande = new byte[10];
19 | private Integer databloc = Configs.getDatablock();
20 | private byte[] dbb5 = new byte[2], dbb6 = new byte[2], dbb7 = new byte[2], dbb8 = new byte[2], dbw18 = new byte[2],
21 | dbb2 = new byte[2], dbb3 = new byte[2], dbw24 = new byte[2], dbw26 = new byte[2], dbw28 = new byte[2], dbw30 = new byte[2];
22 | private int numAutomate;
23 |
24 | public WriteTaskS7(int numAutomate)
25 | {
26 | comS7 = new S7Client();
27 | plcS7 = new AutomateS7();
28 | writeThread = new Thread(plcS7);
29 | this.numAutomate = numAutomate;
30 | }
31 |
32 | public void Start(String ip, String rack, String slot){
33 | if (!writeThread.isAlive()) {
34 | parConnexion[0] = ip;
35 | parConnexion[1] = rack;
36 | parConnexion[2] = slot;
37 |
38 | writeThread.start();
39 | isRunning.set(true);
40 | }
41 | }
42 |
43 | public void Stop(){
44 | isRunning.set(false);
45 | comS7.Disconnect();
46 | writeThread.interrupt();
47 | }
48 |
49 | public class AutomateS7 implements Runnable{
50 | @Override
51 | public void run() {
52 | try {
53 | comS7.SetConnectionType(S7.S7_BASIC);
54 | Integer res = comS7.ConnectTo(parConnexion[0], Integer.valueOf(parConnexion[1]), Integer.valueOf(parConnexion[2]));
55 |
56 | while (isRunning.get() && (res.equals(0)))
57 | {
58 | if(numAutomate == 1)
59 | {
60 | comS7.WriteArea(S7.S7AreaDB, databloc, 5, 2, dbb5);
61 | comS7.WriteArea(S7.S7AreaDB, databloc, 6, 2, dbb6);
62 | comS7.WriteArea(S7.S7AreaDB, databloc, 7, 2, dbb7);
63 | comS7.WriteArea(S7.S7AreaDB, databloc, 8, 2, dbb8);
64 | comS7.WriteArea(S7.S7AreaDB, databloc, 18, 2, dbw18);
65 | }
66 | else
67 | {
68 | comS7.WriteArea(S7.S7AreaDB, databloc, 2, 2, dbb2);
69 | comS7.WriteArea(S7.S7AreaDB, databloc, 3, 2, dbb3);
70 | comS7.WriteArea(S7.S7AreaDB, databloc, 24, 2, dbw24);
71 | comS7.WriteArea(S7.S7AreaDB, databloc, 26, 2, dbw26);
72 | comS7.WriteArea(S7.S7AreaDB, databloc, 28, 2, dbw28);
73 | comS7.WriteArea(S7.S7AreaDB, databloc, 30, 2, dbw30);
74 | }
75 | }
76 | } catch (Exception e) {
77 | e.printStackTrace();
78 | }
79 | }
80 | }
81 |
82 | //Méthode pour écrire en "bool" une valeur donnée
83 | public void setWriteBool(int dbb, String value)
84 | {
85 | char[] valueInChars = value.toCharArray();
86 | int arrayLength = valueInChars.length;
87 | boolean isTrue;
88 | byte[] chosenDBB;
89 |
90 | if(dbb == 2)
91 | {
92 | chosenDBB = dbb2;
93 | }
94 | else if (dbb ==3)
95 | {
96 | chosenDBB = dbb3;
97 | }
98 | else if (dbb == 5)
99 | {
100 | chosenDBB = dbb5;
101 | }
102 | else if (dbb == 6)
103 | {
104 | chosenDBB = dbb6;
105 | }
106 | else
107 | {
108 | chosenDBB = dbb7;
109 | }
110 |
111 | for (int i = 0; i < arrayLength; i++)
112 | {
113 | if(Integer.parseInt(String.valueOf(valueInChars[arrayLength -(i+1)])) == 1)
114 | {
115 | isTrue = true;
116 | }
117 | else
118 | {
119 | isTrue = false;
120 | }
121 | S7.SetBitAt(chosenDBB, 0, i, isTrue);
122 | }
123 | }
124 |
125 | //Permet d'écrire dans l'automate une valeur en octet
126 | public void setWriteByte(String value)
127 | {
128 | dbb8[0] = S7.ByteToBCD(Integer.parseInt(value));
129 | }
130 |
131 | //Ecrit la valeur donnée sous forme d'entier dans l'automate
132 | public void setWriteInt(int dbw, String value)
133 | {
134 | byte[] chosenDBW;
135 | if(dbw == 18)
136 | {
137 | chosenDBW = dbw18;
138 | }
139 | else if (dbw == 24)
140 | {
141 | chosenDBW = dbw24;
142 | }
143 | else if(dbw == 26)
144 | {
145 | chosenDBW = dbw26;
146 | }
147 | else if(dbw == 28)
148 | {
149 | chosenDBW = dbw28;
150 | }
151 | else
152 | {
153 | chosenDBW = dbw30;
154 | }
155 |
156 | S7.SetWordAt(chosenDBW, 0, Integer.parseInt(value));
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/BDD/UserAccessDB.java:
--------------------------------------------------------------------------------
1 | package com.example.fabio.plcmonitor.BDD;
2 |
3 | import android.content.ContentValues;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 | import android.database.sqlite.SQLiteDatabase;
7 |
8 | import com.example.fabio.plcmonitor.BDD.User;
9 | import com.example.fabio.plcmonitor.BDD.UserBddSqlite;
10 |
11 | import java.util.ArrayList;
12 |
13 | public class UserAccessDB {
14 |
15 | private static final int VERSION = 1;
16 | private static final String NAME_DB = "User.db";
17 | private static final String TABLE_USER = "table_user";
18 | private static final String COL_ID = "ID";
19 | private static final int NUM_COL_ID = 0;
20 | private static final String COL_EMAIL = "EMAIL";
21 | private static final int NUM_COL_EMAIL = 1;
22 | private static final String COL_PASSWORD = "PASSWORD";
23 | private static final int NUM_COL_PASSWORD = 2;
24 | private static final String COL_LASTNAME = "LASTNAME";
25 | private static final int NUM_COL_LASTNAME = 3;
26 | private static final String COL_FIRSTNAME = "FIRSTNAME";
27 | private static final int NUM_COL_FIRSTNAME = 4;
28 | private static final String COL_WRITE = "WRITE";
29 | private static final int NUM_COL_WRITE = 5;
30 | private static final String COL_ADMIN = "ADMIN";
31 | private static final int NUM_COL_ADMIN = 6;
32 |
33 | private SQLiteDatabase db;
34 | private UserBddSqlite userDb;
35 |
36 | public UserAccessDB (Context c){userDb = new UserBddSqlite(c, NAME_DB,null,VERSION);}
37 |
38 | public void openForWrite(){db = userDb.getWritableDatabase();}
39 | public void openForRead(){db = userDb.getReadableDatabase();}
40 | public void Close(){db.close();}
41 |
42 | public long insertUser(User u){
43 |
44 | ContentValues content = new ContentValues();
45 |
46 | content.put(COL_LASTNAME, u.getLastname());
47 | content.put(COL_FIRSTNAME, u.getFirstname());
48 | content.put(COL_PASSWORD, u.getMdp());
49 | content.put(COL_EMAIL, u.getEmail());
50 | content.put(COL_WRITE, u.getWriteAccess());
51 | content.put(COL_ADMIN, u.getIsAdmin());
52 |
53 | return db.insert(TABLE_USER, null, content);
54 |
55 | }
56 |
57 | public int updateUser(int i,User u){
58 |
59 | ContentValues content = new ContentValues();
60 |
61 | content.put(COL_EMAIL, u.getEmail());
62 | content.put(COL_PASSWORD, u.getMdp());
63 | content.put(COL_LASTNAME, u.getLastname());
64 | content.put(COL_FIRSTNAME, u.getFirstname());
65 | content.put(COL_WRITE, u.getWriteAccess());
66 | content.put(COL_ADMIN, u.getIsAdmin());
67 |
68 | return db.update(TABLE_USER, content, COL_ID + " = " + i, null);
69 | }
70 |
71 | public int removeUser(int id){
72 |
73 | return db.delete(TABLE_USER, COL_ID + " = " + id, null);
74 | }
75 |
76 |
77 | public ArrayList getAllUser(){
78 | Cursor c = db.query(TABLE_USER, new String[]{
79 | COL_ID, COL_EMAIL, COL_PASSWORD, COL_LASTNAME, COL_FIRSTNAME, COL_WRITE, COL_ADMIN},
80 | null, null, null, null, null,null);
81 |
82 | ArrayList tabUser = new ArrayList();
83 |
84 | if (c.getCount() == 0) {
85 | c.close();
86 | return null;
87 | }
88 | while (c.moveToNext()) {
89 | User user1 = new User();
90 | user1.setId(c.getInt(NUM_COL_ID));
91 | user1.setEmail(c.getString(NUM_COL_EMAIL));
92 | user1.setMdp(c.getString(NUM_COL_PASSWORD));
93 | user1.setLastname(c.getString(NUM_COL_LASTNAME));
94 | user1.setFirstname(c.getString(NUM_COL_FIRSTNAME));
95 |
96 | if(c.getInt(NUM_COL_WRITE) == 1)
97 | {
98 | user1.setWriteAccess(true);
99 | }
100 | else
101 | {
102 | user1.setWriteAccess(false);
103 | }
104 |
105 | if(c.getInt(NUM_COL_ADMIN) == 1)
106 | {
107 | user1.setIsAdmin(true);
108 | }
109 | else
110 | {
111 | user1.setIsAdmin(false);
112 | }
113 |
114 | tabUser.add(user1);
115 | }
116 | c.close();
117 | return tabUser;
118 | }
119 |
120 | public User getUser (String email)
121 | {
122 | Cursor c = db.query(TABLE_USER, new String[]{COL_ID, COL_EMAIL, COL_PASSWORD, COL_LASTNAME, COL_FIRSTNAME, COL_WRITE, COL_ADMIN},
123 | COL_EMAIL + " LIKE \"" + email + "\"", null, null, null, COL_EMAIL);
124 |
125 | //Si pas de résultat
126 | if(c.getCount() == 0)
127 | {
128 | c.close();
129 | return null;
130 | }
131 | //On a un résultat, on accède à la ligne
132 | c.moveToFirst();
133 | //On recrée l'user
134 | User user1 = new User();
135 | user1.setId(c.getInt(NUM_COL_ID));
136 | user1.setEmail(c.getString(NUM_COL_EMAIL));
137 | user1.setLastname(c.getString(NUM_COL_LASTNAME));
138 | user1.setFirstname(c.getString(NUM_COL_FIRSTNAME));
139 | user1.setMdp(c.getString(NUM_COL_PASSWORD));
140 |
141 | if(c.getInt(NUM_COL_WRITE) == 1)
142 | {
143 | user1.setWriteAccess(true);
144 | }
145 | else
146 | {
147 | user1.setWriteAccess(false);
148 | }
149 |
150 | if(c.getInt(NUM_COL_ADMIN) == 1)
151 | {
152 | user1.setIsAdmin(true);
153 | }
154 | else
155 | {
156 | user1.setIsAdmin(false);
157 | }
158 | c.close();
159 |
160 | return user1;
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/Activity/ManagementUserActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.fabio.plcmonitor.Activity;
2 |
3 | import android.app.AlertDialog;
4 | import android.content.DialogInterface;
5 | import android.content.Intent;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.os.Bundle;
8 | import android.view.View;
9 | import android.widget.AdapterView;
10 | import android.widget.ArrayAdapter;
11 | import android.widget.EditText;
12 | import android.widget.Spinner;
13 | import android.widget.Switch;
14 | import android.widget.Toast;
15 |
16 | import com.example.fabio.plcmonitor.BDD.User;
17 | import com.example.fabio.plcmonitor.BDD.UserAccessDB;
18 | import com.example.fabio.plcmonitor.Configs;
19 | import com.example.fabio.plcmonitor.R;
20 |
21 | import java.util.ArrayList;
22 |
23 | public class ManagementUserActivity extends AppCompatActivity {
24 |
25 | UserAccessDB db;
26 |
27 | Spinner spin;
28 | Switch switchAdmin, switchWrite;
29 |
30 | EditText etMdp;
31 | String mdp;
32 |
33 | @Override
34 | protected void onCreate(Bundle savedInstanceState) {
35 | super.onCreate(savedInstanceState);
36 | setContentView(R.layout.activity_management_user);
37 | fillingSpin();
38 |
39 | switchAdmin = (Switch) findViewById(R.id.sw_muser_admin);
40 | switchWrite = (Switch) findViewById(R.id.sw_muser_write);
41 |
42 | db = new UserAccessDB(this);
43 |
44 | spin.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
45 | @Override
46 | public void onItemSelected(AdapterView> parentView, View selectedItemView, int position, long id) {
47 |
48 | db.openForRead();
49 | //On récupère l'user correspondant au mail qu'on a sélectionné
50 | User user1 = db.getUser(spin.getSelectedItem().toString());
51 | db.Close();
52 | //On met en ON le switch si l'utilisateur est un administrateur
53 | if (user1.getIsAdmin())
54 | {
55 | switchAdmin.setChecked(true);
56 | }
57 |
58 | else
59 | {
60 | switchAdmin.setChecked(false);
61 | }
62 |
63 | //Idem pour les droit en écriture pour l'automate
64 | if (user1.getWriteAccess())
65 | {
66 | switchWrite.setChecked(true);
67 | }
68 |
69 | else
70 | {
71 | switchWrite.setChecked(false);
72 | }
73 |
74 |
75 | // On remplis automatiquement le mot de passe de l'utilisateur dans le champ mdp
76 | etMdp = ((EditText)findViewById(R.id.et_muser_mdp));
77 | etMdp.setText(user1.getMdp().toString());
78 | }
79 | @Override
80 | public void onNothingSelected(AdapterView> parentView) {
81 | System.out.println("item nothing");
82 | }
83 | });
84 | }
85 |
86 | private void fillingSpin()
87 | {
88 | spin = (Spinner) findViewById(R.id.spi_muser_select);
89 |
90 | db = new UserAccessDB(this);
91 | db.openForRead();
92 | ArrayList users = db.getAllUser();
93 | db.Close();
94 | //Liste contenant les emails de chaque personnes inscrites
95 | ArrayList mailUsers = new ArrayList();
96 |
97 | for(int i = 0 ; i < users.size();i++)
98 | {
99 | mailUsers.add(users.get(i).getEmail());
100 | }
101 |
102 | //On configure l'adaptateur pour l'ajouter au spinner
103 | ArrayAdapter adapters = new ArrayAdapter(this, android.R.layout.simple_spinner_item,mailUsers);
104 | adapters.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
105 | spin.setAdapter(adapters);
106 | }
107 |
108 | public void muserClick(View v)
109 | {
110 | switch (v.getId())
111 | {
112 | case R.id.sw_muser_admin:
113 | db.openForRead();
114 | User user1 = db.getUser(spin.getSelectedItem().toString());
115 | db.Close();
116 | //On gère le cas où on clique sur le switch
117 | if(switchAdmin.isChecked())
118 | {
119 | user1.setIsAdmin(true);
120 | Configs.setIsAdmin(true);
121 | }
122 | else
123 | {
124 | user1.setIsAdmin(false);
125 | Configs.setIsAdmin(false);
126 | }
127 | //On met à jour l'user dans la BDD
128 | db.openForWrite();
129 | db.updateUser(user1.getId(),user1);
130 | db.Close();
131 | break;
132 |
133 | case R.id.sw_muser_write:
134 | db.openForRead();
135 | User user2 = db.getUser(spin.getSelectedItem().toString());
136 | db.Close();
137 | //On gère le cas où on clique sur le switch
138 | if(switchWrite.isChecked())
139 | {
140 | user2.setWriteAccess(true);
141 | Configs.setIsWriteAccess(true);
142 | }
143 | else
144 | {
145 | user2.setWriteAccess(false);
146 | Configs.setIsWriteAccess(false);
147 | }
148 | //On met à jour l'user dans la BDD
149 | db.openForWrite();
150 | db.updateUser(user2.getId(),user2);
151 | db.Close();
152 | break;
153 |
154 |
155 | case R.id.bt_muser_editMdp:
156 | mdp = etMdp.getText().toString();
157 | db.openForRead();
158 | User user3 = db.getUser(spin.getSelectedItem().toString());
159 | db.Close();
160 | //On met à jour le mdp
161 | user3.setMdp(mdp);
162 | db.openForWrite();
163 | db.updateUser(user3.getId(),user3);
164 | db.Close();
165 |
166 | Toast.makeText(getApplicationContext(), "Le mot de passe a bien été modifié",Toast.LENGTH_SHORT).show();
167 | break;
168 |
169 | case R.id.bt_muser_delete:
170 | final AlertDialog.Builder builder = new AlertDialog.Builder(ManagementUserActivity.this);
171 | builder.setMessage("Cette action supprimera l'utilisateur, voulez-vous continuer ?");
172 | builder.setCancelable(true);
173 | builder.setNegativeButton("Non", new DialogInterface.OnClickListener() {
174 | @Override
175 | public void onClick(DialogInterface dialogInterface, int i) {
176 | dialogInterface.cancel();
177 | }
178 | });
179 | builder.setPositiveButton("Oui", new DialogInterface.OnClickListener() {
180 | @Override
181 | public void onClick(DialogInterface dialogInterface, int i) {
182 | db.openForRead();
183 | User user4 = db.getUser(spin.getSelectedItem().toString());
184 | db.Close();
185 |
186 | db.openForWrite();
187 | db.removeUser(user4.getId());
188 | db.Close();
189 | //On reremplis le spinner sinon l'utilsateur reste selectionnable dans le spinner
190 | fillingSpin();
191 |
192 | Toast.makeText(getApplicationContext(), "L'utilisateur a bien été supprimé",Toast.LENGTH_SHORT).show();
193 | }
194 | });
195 | AlertDialog alertDialog = builder.create();
196 | alertDialog.show();
197 | }
198 | }
199 |
200 | @Override
201 | public void onBackPressed()
202 | {
203 | finish();
204 | Intent intent = new Intent(getApplicationContext(), ManagementActivity.class);
205 | startActivity(intent);
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/Activity/AutomatonCompActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.fabio.plcmonitor.Activity;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.ColorDrawable;
5 | import android.net.ConnectivityManager;
6 | import android.net.NetworkInfo;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.os.Bundle;
9 | import android.view.View;
10 | import android.widget.Button;
11 | import android.widget.CheckBox;
12 | import android.widget.EditText;
13 | import android.widget.ImageButton;
14 | import android.widget.LinearLayout;
15 | import android.widget.TextView;
16 | import android.widget.Toast;
17 |
18 | import com.example.fabio.plcmonitor.Automaton.ReadTaskS7;
19 | import com.example.fabio.plcmonitor.Automaton.WriteTaskS7;
20 | import com.example.fabio.plcmonitor.Configs;
21 | import com.example.fabio.plcmonitor.R;
22 |
23 | public class AutomatonCompActivity extends AppCompatActivity
24 | {
25 | private ReadTaskS7 readS7;
26 | private WriteTaskS7 writeS7;
27 | private NetworkInfo network;
28 | private ConnectivityManager statusConnexion;
29 |
30 | private String ip = Configs.getIp();
31 | private String rack = Integer.toString(Configs.getRack());
32 | private String slot = Integer.toString(Configs.getSlot());
33 |
34 | private TextView tv_comp_PLCnumber, tv_comp_nbBouteille, tv_comp_nbFlacon;
35 | private CheckBox cb_comp_service, cb_comp_flacon;
36 | private Button bt_comp_5, bt_comp_10, bt_comp_15, bt_comp_ecrire;
37 | private ImageButton ib_comp_connexion;
38 | private EditText et_comp_dbb5, et_comp_dbb6, et_comp_dbb7, et_comp_dbb8, et_comp_dbw18;
39 | private LinearLayout ll_comp_layoutEcriture;
40 |
41 | @Override
42 | protected void onCreate(Bundle savedInstanceState)
43 | {
44 | super.onCreate(savedInstanceState);
45 | setContentView(R.layout.activity_automaton_comp);
46 |
47 | statusConnexion = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
48 | network = statusConnexion.getActiveNetworkInfo();
49 |
50 | tv_comp_PLCnumber = (TextView)findViewById(R.id.tv_comp_PLCnumber);
51 | tv_comp_nbBouteille = (TextView)findViewById(R.id.tv_comp_nbBouteille);
52 | tv_comp_nbFlacon = (TextView)findViewById(R.id.tv_comp_nbFlacon);
53 | cb_comp_service = (CheckBox)findViewById(R.id.cb_comp_service);
54 | cb_comp_flacon = (CheckBox)findViewById(R.id.cb_comp_flacon);
55 | bt_comp_5 = (Button)findViewById(R.id.bt_comp_5);
56 | bt_comp_10 = (Button)findViewById(R.id.bt_comp_10);
57 | bt_comp_15 = (Button)findViewById(R.id.bt_comp_15);
58 | bt_comp_ecrire = (Button) findViewById(R.id.bt_comp_ecrire);
59 | ib_comp_connexion = (ImageButton)findViewById(R.id.ib_comp_connexion);
60 | ll_comp_layoutEcriture = (LinearLayout) findViewById(R.id.ll_comp_layoutEcriture);
61 | et_comp_dbb5 = (EditText) findViewById(R.id.et_comp_dbb5);
62 | et_comp_dbb6 = (EditText) findViewById(R.id.et_comp_dbb6);
63 | et_comp_dbb7 = (EditText) findViewById(R.id.et_comp_dbb7);
64 | et_comp_dbb8 = (EditText) findViewById(R.id.et_comp_dbb8);
65 | et_comp_dbw18 = (EditText) findViewById(R.id.et_comp_dbw18);
66 | }
67 |
68 | public void onMainClickManager(View v)
69 | {
70 | switch (v.getId())
71 | {
72 | case R.id.ib_comp_connexion:
73 | ColorDrawable ibBackgroundColor = (ColorDrawable) ib_comp_connexion.getBackground();
74 | int colorId = ibBackgroundColor.getColor();
75 |
76 | //On vérifie si on est déjà connecté ou non
77 | if(colorId == getResources().getColor(R.color.red) || colorId == getResources().getColor(R.color.orange))
78 | {
79 | if (network != null && network.isConnectedOrConnecting()) {
80 | Toast.makeText(getApplicationContext(), "Connecté en : " + network.getTypeName(), Toast.LENGTH_SHORT).show();
81 |
82 | try{
83 | readS7 = new ReadTaskS7(this, v, tv_comp_PLCnumber, tv_comp_nbBouteille, tv_comp_nbFlacon, cb_comp_service, cb_comp_flacon,
84 | bt_comp_5, bt_comp_10, bt_comp_15, bt_comp_ecrire, ib_comp_connexion,1);
85 | readS7.Start(ip,rack,slot);
86 |
87 | writeS7 = new WriteTaskS7(1);
88 | writeS7.Start(ip,rack,slot);
89 |
90 | }
91 | catch(Exception e){
92 | Toast.makeText(getApplicationContext(),"Une erreur s'est produite, veuillez recommencer", Toast.LENGTH_LONG).show();
93 | ib_comp_connexion.setBackgroundColor(getResources().getColor(R.color.orange));
94 | }
95 |
96 | try {
97 | Thread.sleep(1000);
98 | } catch (InterruptedException e) {
99 | e.printStackTrace();
100 | }
101 | }
102 | else
103 | {
104 | Toast.makeText(getApplicationContext(), "Impossible d'accéder au réseau, veuillez activer la connexion Wi-Fi", Toast.LENGTH_SHORT).show();
105 | }
106 | }
107 |
108 | else
109 | {
110 | //On est déjà connecté donc on veut se déconnecter
111 | ib_comp_connexion.setBackgroundColor(getResources().getColor(R.color.red));
112 | bt_comp_ecrire.setVisibility(View.GONE);
113 | ll_comp_layoutEcriture.setVisibility(View.GONE);
114 | readS7.Stop();
115 | writeS7.Stop();
116 | }
117 |
118 | break;
119 |
120 | case R.id.bt_comp_ecrire:
121 | //Si le layout n'est pas déjà affiché, on l'affiche, sinon on le cache
122 | if(ll_comp_layoutEcriture.getVisibility() == View.GONE)
123 | {
124 | ll_comp_layoutEcriture.setVisibility(View.VISIBLE);
125 | }
126 | else
127 | {
128 | ll_comp_layoutEcriture.setVisibility(View.GONE);
129 | writeS7.Stop();
130 | }
131 | break;
132 |
133 | case R.id.bt_comp_saveDBB5:
134 | if(!et_comp_dbb5.getText().toString().isEmpty())
135 | {
136 | writeS7.setWriteBool(5, et_comp_dbb5.getText().toString());
137 | Toast.makeText(getApplicationContext(), "La valeur a bien été écrite", Toast.LENGTH_SHORT).show();
138 | }
139 | else
140 | {
141 | Toast.makeText(getApplicationContext(), "Veuillez remplir le champ", Toast.LENGTH_SHORT).show();
142 | }
143 | break;
144 |
145 | case R.id.bt_comp_saveDBB6:
146 | if(!et_comp_dbb6.getText().toString().isEmpty())
147 | {
148 | writeS7.setWriteBool(6, et_comp_dbb6.getText().toString());
149 | Toast.makeText(getApplicationContext(), "La valeur a bien été écrite", Toast.LENGTH_SHORT).show();
150 | }
151 | else
152 | {
153 | Toast.makeText(getApplicationContext(), "Veuillez remplir le champ", Toast.LENGTH_SHORT).show();
154 | }
155 | break;
156 |
157 | case R.id.bt_comp_saveDBB7:
158 | if(!et_comp_dbb7.getText().toString().isEmpty())
159 | {
160 | writeS7.setWriteBool(7, et_comp_dbb7.getText().toString());
161 | Toast.makeText(getApplicationContext(), "La valeur a bien été écrite", Toast.LENGTH_SHORT).show();
162 | }
163 | else
164 | {
165 | Toast.makeText(getApplicationContext(), "Veuillez remplir le champ", Toast.LENGTH_SHORT).show();
166 | }
167 |
168 | break;
169 |
170 | case R.id.bt_comp_saveDBB8:
171 | if(!et_comp_dbb8.getText().toString().isEmpty())
172 | {
173 | writeS7.setWriteByte(et_comp_dbb8.getText().toString());
174 | Toast.makeText(getApplicationContext(), "La valeur a bien été écrite", Toast.LENGTH_SHORT).show();
175 | }
176 | else
177 | {
178 | Toast.makeText(getApplicationContext(), "Veuillez remplir le champ", Toast.LENGTH_SHORT).show();
179 | }
180 | break;
181 |
182 | case R.id.bt_comp_saveDBW18:
183 | if(!et_comp_dbw18.getText().toString().isEmpty())
184 | {
185 | writeS7.setWriteInt(18,et_comp_dbw18.getText().toString());
186 | Toast.makeText(getApplicationContext(), "La valeur a bien été écrite", Toast.LENGTH_SHORT).show();
187 | }
188 | else
189 | {
190 | Toast.makeText(getApplicationContext(), "Veuillez remplir le champ", Toast.LENGTH_SHORT).show();
191 | }
192 | break;
193 | }
194 | }
195 | }
196 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/SimaticS7/S7.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 |
7 | package com.example.fabio.plcmonitor.SimaticS7;
8 |
9 | import java.io.UnsupportedEncodingException;
10 | import java.util.Date;
11 | import java.util.Calendar;
12 |
13 | /**
14 | *
15 | * @author Davide
16 | */
17 |
18 |
19 | // Step 7 Constants and Conversion helper class
20 | public class S7 {
21 | // S7 ID Area (Area that we want to read/write)
22 | public static final int S7AreaPE = 0x81;
23 | public static final int S7AreaPA = 0x82;
24 | public static final int S7AreaMK = 0x83;
25 | public static final int S7AreaDB = 0x84;
26 | public static final int S7AreaCT = 0x1C;
27 | public static final int S7AreaTM = 0x1D;
28 | // Connection types
29 | public static final byte PG = 0x01;
30 | public static final byte OP = 0x02;
31 | public static final byte S7_BASIC = 0x03;
32 | // Block type
33 | public static final int Block_OB = 0x38;
34 | public static final int Block_DB = 0x41;
35 | public static final int Block_SDB = 0x42;
36 | public static final int Block_FC = 0x43;
37 | public static final int Block_SFC = 0x44;
38 | public static final int Block_FB = 0x45;
39 | public static final int Block_SFB = 0x46;
40 | // Sub Block Type
41 | public static final int SubBlk_OB = 0x08;
42 | public static final int SubBlk_DB = 0x0A;
43 | public static final int SubBlk_SDB = 0x0B;
44 | public static final int SubBlk_FC = 0x0C;
45 | public static final int SubBlk_SFC = 0x0D;
46 | public static final int SubBlk_FB = 0x0E;
47 | public static final int SubBlk_SFB = 0x0F;
48 | // Block languages
49 | public static final int BlockLangAWL = 0x01;
50 | public static final int BlockLangKOP = 0x02;
51 | public static final int BlockLangFUP = 0x03;
52 | public static final int BlockLangSCL = 0x04;
53 | public static final int BlockLangDB = 0x05;
54 | public static final int BlockLangGRAPH = 0x06;
55 | // PLC Status
56 | public static final int S7CpuStatusUnknown = 0x00;
57 | public static final int S7CpuStatusRun = 0x08;
58 | public static final int S7CpuStatusStop = 0x04;
59 | // Type Var
60 | public static final int S7TypeBool = 1;
61 | public static final int S7TypeInt = 1;
62 |
63 | // Returns the bit at Pos.Bit
64 | public static boolean GetBitAt(byte[] Buffer, int Pos, int Bit)
65 | {
66 | int Value = Buffer[Pos] & 0x0FF;
67 | byte[] Mask = {
68 | (byte)0x01,(byte)0x02,(byte)0x04,(byte)0x08,
69 | (byte)0x10,(byte)0x20,(byte)0x40,(byte)0x80
70 | };
71 | if (Bit<0) Bit=0;
72 | if (Bit>7) Bit=7;
73 |
74 | return (Value & Mask[Bit])!=0;
75 | }
76 | /**
77 | * Returns a 16 bit unsigned value : from 0 to 65535 (2^16-1)
78 | * @param Buffer
79 | * @param Pos start position
80 | * @return
81 | */
82 | public static int GetWordAt(byte[] Buffer, int Pos)
83 | {
84 | int hi = (Buffer[Pos] & 0x00FF);
85 | int lo = (Buffer[Pos+1] & 0x00FF);
86 | return (hi<<8)+lo;
87 | }
88 |
89 | // Returns a 16 bit signed value : from -32768 to 32767
90 | public static int GetShortAt(byte[] Buffer, int Pos)
91 | {
92 | int hi = (Buffer[Pos]);
93 | int lo = (Buffer[Pos+1] & 0x00FF);
94 | return ((hi<<8)+lo);
95 | }
96 |
97 | // Returns a 32 bit unsigned value : from 0 to 4294967295 (2^32-1)
98 | public static long GetDWordAt(byte[] Buffer, int Pos)
99 | {
100 | long Result;
101 | Result=(long)(Buffer[Pos] & 0x0FF);
102 | Result<<=8;
103 | Result+=(long)(Buffer[Pos+1] & 0x0FF);
104 | Result<<=8;
105 | Result+=(long)(Buffer[Pos+2] & 0x0FF);
106 | Result<<=8;
107 | Result+=(long)(Buffer[Pos+3] & 0x0FF);
108 | return Result;
109 | }
110 |
111 | // Returns a 32 bit signed value : from 0 to 4294967295 (2^32-1)
112 | public static int GetDIntAt(byte[] Buffer, int Pos)
113 | {
114 | int Result;
115 | Result= Buffer[Pos];
116 | Result<<=8;
117 | Result+=(Buffer[Pos+1] & 0x0FF);
118 | Result<<=8;
119 | Result+=(Buffer[Pos+2] & 0x0FF);
120 | Result<<=8;
121 | Result+=(Buffer[Pos+3] & 0x0FF);
122 | return Result;
123 | }
124 |
125 | // Returns a 32 bit floating point
126 | public static float GetFloatAt(byte[] Buffer, int Pos)
127 | {
128 | int IntFloat = GetDIntAt(Buffer, Pos);
129 | return Float.intBitsToFloat(IntFloat);
130 | }
131 |
132 | // Returns an ASCII string
133 | public static String GetStringAt(byte[] Buffer, int Pos, int MaxLen)
134 | {
135 | byte[] StrBuffer = new byte[MaxLen];
136 | System.arraycopy(Buffer, Pos, StrBuffer, 0, MaxLen);
137 | String S;
138 | try {
139 | S = new String(StrBuffer, "UTF-8"); // the charset is UTF-8
140 | } catch (UnsupportedEncodingException ex) {
141 | S = "";
142 | }
143 | return S;
144 | }
145 |
146 | public static String GetPrintableStringAt(byte[] Buffer, int Pos, int MaxLen)
147 | {
148 | byte[] StrBuffer = new byte[MaxLen];
149 | System.arraycopy(Buffer, Pos, StrBuffer, 0, MaxLen);
150 | for (int c = 0; c < MaxLen; c++)
151 | {
152 | if ((StrBuffer[c]<31) || (StrBuffer[c]>126))
153 | StrBuffer[c]=46; // '.'
154 | }
155 | String S;
156 | try {
157 | S = new String(StrBuffer, "UTF-8"); // the charset is UTF-8
158 | } catch (UnsupportedEncodingException ex) {
159 | S = "";
160 | }
161 | return S;
162 | }
163 |
164 | public static Date GetDateAt(byte[] Buffer, int Pos)
165 | {
166 | int Year, Month, Day, Hour, Min, Sec;
167 | Calendar S7Date = Calendar.getInstance();
168 |
169 | Year = S7.BCDtoByte(Buffer[Pos]);
170 | if (Year<90)
171 | Year+=2000;
172 | else
173 | Year+=1900;
174 |
175 | Month=S7.BCDtoByte(Buffer[Pos+1])-1;
176 | Day =S7.BCDtoByte(Buffer[Pos+2]);
177 | Hour =S7.BCDtoByte(Buffer[Pos+3]);
178 | Min =S7.BCDtoByte(Buffer[Pos+4]);
179 | Sec =S7.BCDtoByte(Buffer[Pos+5]);
180 |
181 | S7Date.set(Year, Month, Day, Hour, Min, Sec);
182 |
183 | return S7Date.getTime();
184 | }
185 |
186 | public static void SetBitAt(byte[] Buffer, int Pos, int Bit, boolean Value)
187 | {
188 | byte[] Mask = {
189 | (byte)0x01,(byte)0x02,(byte)0x04,(byte)0x08,
190 | (byte)0x10,(byte)0x20,(byte)0x40,(byte)0x80
191 | };
192 | if (Bit<0) Bit=0;
193 | if (Bit>7) Bit=7;
194 |
195 | if (Value)
196 | Buffer[Pos]= (byte) (Buffer[Pos] | Mask[Bit]);
197 | else
198 | Buffer[Pos]= (byte) (Buffer[Pos] & ~Mask[Bit]);
199 | }
200 |
201 | public static void SetWordAt(byte[] Buffer, int Pos, int Value)
202 | {
203 | int Word = Value & 0x0FFFF;
204 | Buffer[Pos] = (byte) (Word >> 8);
205 | Buffer[Pos+1] = (byte) (Word & 0x00FF);
206 | }
207 |
208 | public static void SetShortAt(byte[] Buffer, int Pos, int Value)
209 | {
210 | Buffer[Pos] = (byte) (Value >> 8);
211 | Buffer[Pos+1] = (byte) (Value & 0x00FF);
212 | }
213 | public static void SetDWordAt(byte[] Buffer, int Pos, long Value)
214 | {
215 | long DWord = Value &0x0FFFFFFFF;
216 | Buffer[Pos+3] = (byte) (DWord &0xFF);
217 | Buffer[Pos+2] = (byte) ((DWord >> 8) &0xFF);
218 | Buffer[Pos+1] = (byte) ((DWord >> 16) &0xFF);
219 | Buffer[Pos] = (byte) ((DWord >> 24) &0xFF);
220 | }
221 |
222 | public static void SetDIntAt(byte[] Buffer, int Pos, int Value)
223 | {
224 | Buffer[Pos+3] = (byte) (Value &0xFF);
225 | Buffer[Pos+2] = (byte) ((Value >> 8) &0xFF);
226 | Buffer[Pos+1] = (byte) ((Value >> 16) &0xFF);
227 | Buffer[Pos] = (byte) ((Value >> 24) &0xFF);
228 | }
229 |
230 | public static void SetFloatAt(byte[] Buffer, int Pos, float Value)
231 | {
232 | int DInt = Float.floatToIntBits(Value);
233 | SetDIntAt(Buffer, Pos, DInt);
234 | }
235 |
236 | public static void SetDateAt(byte[] Buffer, int Pos, Date DateTime)
237 | {
238 | int Year, Month, Day, Hour, Min, Sec, Dow;
239 | Calendar S7Date = Calendar.getInstance();
240 | S7Date.setTime(DateTime);
241 |
242 | Year = S7Date.get(Calendar.YEAR);
243 | Month = S7Date.get(Calendar.MONTH)+1;
244 | Day = S7Date.get(Calendar.DAY_OF_MONTH);
245 | Hour = S7Date.get(Calendar.HOUR_OF_DAY);
246 | Min = S7Date.get(Calendar.MINUTE);
247 | Sec = S7Date.get(Calendar.SECOND);
248 | Dow = S7Date.get(Calendar.DAY_OF_WEEK);
249 |
250 | if (Year>1999)
251 | Year-=2000;
252 |
253 | Buffer[Pos] =ByteToBCD(Year);
254 | Buffer[Pos+1]=ByteToBCD(Month);
255 | Buffer[Pos+2]=ByteToBCD(Day);
256 | Buffer[Pos+3]=ByteToBCD(Hour);
257 | Buffer[Pos+4]=ByteToBCD(Min);
258 | Buffer[Pos+5]=ByteToBCD(Sec);
259 | Buffer[Pos+6]=0;
260 | Buffer[Pos+7]=ByteToBCD(Dow);
261 | }
262 |
263 | public static int BCDtoByte(byte B)
264 | {
265 | return ((B >> 4) * 10) + (B & 0x0F);
266 | }
267 |
268 | public static byte ByteToBCD(int Value)
269 | {
270 | return (byte) (((Value / 10) << 4) | (Value % 10));
271 | }
272 |
273 | }
274 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/Activity/AutomatonAsservActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.fabio.plcmonitor.Activity;
2 |
3 | import android.content.Context;
4 | import android.graphics.drawable.ColorDrawable;
5 | import android.net.ConnectivityManager;
6 | import android.net.NetworkInfo;
7 | import android.support.v7.app.AppCompatActivity;
8 | import android.os.Bundle;
9 | import android.view.View;
10 | import android.widget.Button;
11 | import android.widget.CheckBox;
12 | import android.widget.EditText;
13 | import android.widget.ImageButton;
14 | import android.widget.LinearLayout;
15 | import android.widget.TextView;
16 | import android.widget.Toast;
17 |
18 | import com.example.fabio.plcmonitor.Automaton.ReadTaskS7;
19 | import com.example.fabio.plcmonitor.Automaton.WriteTaskS7;
20 | import com.example.fabio.plcmonitor.Configs;
21 | import com.example.fabio.plcmonitor.R;
22 |
23 | public class AutomatonAsservActivity extends AppCompatActivity {
24 |
25 | private ReadTaskS7 readS7;
26 | private WriteTaskS7 writeS7;
27 | private NetworkInfo network;
28 | private ConnectivityManager statusConnexion;
29 |
30 | private String ip = Configs.getIp();
31 | private String rack = Integer.toString(Configs.getRack());
32 | private String slot = Integer.toString(Configs.getSlot());
33 |
34 | private TextView tv_asserv_PLCnumber, tv_asserv_niveauEau, tv_asserv_consigneAuto, tv_asserv_consigneManuel, tv_asserv_motPilotageVanne;
35 | private CheckBox cb_asserv_valve1, cb_asserv_valve2, cb_asserv_valve3, cb_asserv_valve4;
36 | private Button bt_asserv_manuel, bt_asserv_auto, bt_asserv_ecrire, bt_asserv_saveDBB2, bt_asserv_saveDBB3, bt_asserv_saveDBW24,
37 | bt_asserv_saveDBW26, bt_asserv_saveDBW28, bt_asserv_saveDBW30;
38 | private EditText et_asserv_dbb2, et_asserv_dbb3, et_asserv_dbw24, et_asserv_dbw26, et_asserv_dbw28, et_asserv_dbw30;
39 | private LinearLayout ll_asserv_layoutEcriture;
40 | private ImageButton ib_asserv_connexion;
41 |
42 | @Override
43 | protected void onCreate(Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 | setContentView(R.layout.activity_automaton_asserv);
46 |
47 | statusConnexion = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);
48 | network = statusConnexion.getActiveNetworkInfo();
49 |
50 | tv_asserv_niveauEau = (TextView)findViewById(R.id.tv_asserv_niveauEau);
51 | tv_asserv_PLCnumber = (TextView)findViewById(R.id.tv_asserv_PLCnumber);
52 | tv_asserv_consigneAuto = (TextView)findViewById(R.id.tv_asserv_consAuto);
53 | tv_asserv_consigneManuel = (TextView)findViewById(R.id.tv_asserv_consManuel);
54 | tv_asserv_motPilotageVanne = (TextView) findViewById(R.id.tv_asserv_motPilotageVanne);
55 | cb_asserv_valve1 = (CheckBox)findViewById(R.id.cb_asserv_valve1);
56 | cb_asserv_valve2 = (CheckBox)findViewById(R.id.cb_asserv_valve2);
57 | cb_asserv_valve3 = (CheckBox)findViewById(R.id.cb_asserv_valve3);
58 | cb_asserv_valve4 = (CheckBox) findViewById(R.id.cb_asserv_valve4);
59 | bt_asserv_manuel= (Button)findViewById(R.id.bt_asserv_manuel);
60 | bt_asserv_auto = (Button)findViewById(R.id.bt_asserv_auto);
61 | bt_asserv_ecrire = (Button) findViewById(R.id.bt_asserv_ecrire);
62 | bt_asserv_saveDBB2 = (Button) findViewById(R.id.bt_asserv_saveDBB2);
63 | bt_asserv_saveDBB3 = (Button) findViewById(R.id.bt_asserv_saveDBB3);
64 | bt_asserv_saveDBW24 = (Button) findViewById(R.id.bt_asserv_saveDBW24);
65 | bt_asserv_saveDBW26 = (Button) findViewById(R.id.bt_asserv_saveDBW26);
66 | bt_asserv_saveDBW28 = (Button) findViewById(R.id.bt_asserv_saveDBW28);
67 | bt_asserv_saveDBW30 = (Button) findViewById(R.id.bt_asserv_saveDBW30);
68 | et_asserv_dbb2 = (EditText)findViewById(R.id.et_asserv_dbb2);
69 | et_asserv_dbb3 = (EditText)findViewById(R.id.et_asserv_dbb3);
70 | et_asserv_dbw24 = (EditText)findViewById(R.id.et_asserv_dbw24);
71 | et_asserv_dbw26 = (EditText)findViewById(R.id.et_asserv_dbw26);
72 | et_asserv_dbw28 = (EditText)findViewById(R.id.et_asserv_dbw28);
73 | et_asserv_dbw30 = (EditText)findViewById(R.id.et_asserv_dbw30);
74 | ll_asserv_layoutEcriture = (LinearLayout) findViewById(R.id.ll_asserv_layoutEcriture);
75 | ib_asserv_connexion = (ImageButton)findViewById(R.id.ib_asserv_connexion);
76 | }
77 |
78 | public void onMainClickManager(View v)
79 | {
80 | switch (v.getId())
81 | {
82 | case R.id.ib_asserv_connexion:
83 | ColorDrawable ibBackgroundColor = (ColorDrawable) ib_asserv_connexion.getBackground();
84 | int colorId = ibBackgroundColor.getColor();
85 |
86 | //On vérifie si on est déjà connecté ou non
87 | if(colorId == getResources().getColor(R.color.red) || colorId == getResources().getColor(R.color.orange))
88 | {
89 | if (network != null && network.isConnectedOrConnecting()) {
90 | Toast.makeText(getApplicationContext(), "Connecté en : " + network.getTypeName(), Toast.LENGTH_SHORT).show();
91 |
92 | try{
93 | readS7 = new ReadTaskS7(this,v, tv_asserv_PLCnumber, tv_asserv_niveauEau, tv_asserv_consigneAuto, tv_asserv_consigneManuel,
94 | tv_asserv_motPilotageVanne, cb_asserv_valve1, cb_asserv_valve2, cb_asserv_valve3, cb_asserv_valve4,
95 | bt_asserv_manuel, bt_asserv_auto, bt_asserv_ecrire, ib_asserv_connexion,2);
96 | readS7.Start(ip,rack,slot);
97 |
98 | writeS7 = new WriteTaskS7(2);
99 | writeS7.Start(ip,rack,slot);
100 | }
101 | catch(Exception e){
102 | Toast.makeText(getApplicationContext(),"Une erreur s'est produite, veuillez recommencer", Toast.LENGTH_LONG).show();
103 | ib_asserv_connexion.setBackgroundColor(getResources().getColor(R.color.orange));
104 | }
105 |
106 | try {
107 | Thread.sleep(1000);
108 | } catch (InterruptedException e) {
109 | e.printStackTrace();
110 | }
111 | }
112 | else
113 | {
114 | Toast.makeText(getApplicationContext(), "Impossible d'accéder au réseau, veuillez activer la connexion Wi-Fi", Toast.LENGTH_SHORT).show();
115 | }
116 | }
117 |
118 | else
119 | {
120 | //On est déjà connecté donc on veut se déconnecter
121 | ib_asserv_connexion.setBackgroundColor(getResources().getColor(R.color.red));
122 | bt_asserv_ecrire.setVisibility(View.GONE);
123 | ll_asserv_layoutEcriture.setVisibility(View.GONE);
124 | readS7.Stop();
125 | writeS7.Stop();
126 | }
127 | break;
128 |
129 | case R.id.bt_asserv_ecrire:
130 | //Si le layout n'est pas déjà affiché, on l'affiche, sinon on le cache
131 | if(ll_asserv_layoutEcriture.getVisibility() == View.GONE)
132 | {
133 | ll_asserv_layoutEcriture.setVisibility(View.VISIBLE);
134 | }
135 | else
136 | {
137 | ll_asserv_layoutEcriture.setVisibility(View.GONE);
138 | }
139 | break;
140 |
141 | case R.id.bt_asserv_saveDBB2:
142 | if(!et_asserv_dbb2.getText().toString().isEmpty())
143 | {
144 | writeS7.setWriteBool(2, et_asserv_dbb2.getText().toString());
145 | Toast.makeText(getApplicationContext(), "La valeur a bien été écrite", Toast.LENGTH_SHORT).show();
146 | }
147 | else
148 | {
149 | Toast.makeText(getApplicationContext(), "Veuillez remplir le champ", Toast.LENGTH_SHORT).show();
150 | }
151 | break;
152 |
153 | case R.id.bt_asserv_saveDBB3:
154 | if(!et_asserv_dbb3.getText().toString().isEmpty())
155 | {
156 | writeS7.setWriteBool(3, et_asserv_dbb3.getText().toString());
157 | Toast.makeText(getApplicationContext(), "La valeur a bien été écrite", Toast.LENGTH_SHORT).show();
158 | }
159 | else
160 | {
161 | Toast.makeText(getApplicationContext(), "Veuillez remplir le champ", Toast.LENGTH_SHORT).show();
162 | }
163 | break;
164 |
165 | case R.id.bt_asserv_saveDBW24:
166 | if(!et_asserv_dbw24.getText().toString().isEmpty())
167 | {
168 | writeS7.setWriteInt(24, et_asserv_dbw24.getText().toString());
169 | Toast.makeText(getApplicationContext(), "La valeur a bien été écrite", Toast.LENGTH_SHORT).show();
170 | }
171 | else
172 | {
173 | Toast.makeText(getApplicationContext(), "Veuillez remplir le champ", Toast.LENGTH_SHORT).show();
174 | }
175 |
176 | break;
177 |
178 | case R.id.bt_asserv_saveDBW26:
179 | if(!et_asserv_dbw26.getText().toString().isEmpty())
180 | {
181 | writeS7.setWriteInt(26,et_asserv_dbw26.getText().toString());
182 | Toast.makeText(getApplicationContext(), "La valeur a bien été écrite", Toast.LENGTH_SHORT).show();
183 | }
184 | else
185 | {
186 | Toast.makeText(getApplicationContext(), "Veuillez remplir le champ", Toast.LENGTH_SHORT).show();
187 | }
188 | break;
189 |
190 | case R.id.bt_asserv_saveDBW28:
191 | if(!et_asserv_dbw28.getText().toString().isEmpty())
192 | {
193 | writeS7.setWriteInt(28,et_asserv_dbw28.getText().toString());
194 | Toast.makeText(getApplicationContext(), "La valeur a bien été écrite", Toast.LENGTH_SHORT).show();
195 | }
196 | else
197 | {
198 | Toast.makeText(getApplicationContext(), "Veuillez remplir le champ", Toast.LENGTH_SHORT).show();
199 | }
200 | break;
201 |
202 | case R.id.bt_asserv_saveDBW30:
203 | if(!et_asserv_dbw30.getText().toString().isEmpty())
204 | {
205 | writeS7.setWriteInt(30,et_asserv_dbw30.getText().toString());
206 | Toast.makeText(getApplicationContext(), "La valeur a bien été écrite", Toast.LENGTH_SHORT).show();
207 | }
208 | else
209 | {
210 | Toast.makeText(getApplicationContext(), "Veuillez remplir le champ", Toast.LENGTH_SHORT).show();
211 | }
212 | break;
213 | }
214 | }
215 | }
216 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_automaton_comp.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
15 |
23 |
24 |
31 |
32 |
38 |
39 |
46 |
47 |
48 |
55 |
56 |
67 |
68 |
79 |
80 |
88 |
89 |
96 |
97 |
105 |
106 |
115 |
116 |
125 |
126 |
127 |
133 |
134 |
140 |
141 |
148 |
149 |
150 |
151 |
157 |
158 |
164 |
165 |
172 |
173 |
174 |
180 |
181 |
182 |
192 |
193 |
203 |
204 |
205 |
211 |
212 |
219 |
220 |
228 |
229 |
236 |
237 |
238 |
239 |
246 |
247 |
255 |
256 |
263 |
264 |
265 |
266 |
273 |
274 |
282 |
283 |
290 |
291 |
292 |
293 |
300 |
301 |
309 |
310 |
317 |
318 |
319 |
320 |
327 |
328 |
336 |
337 |
344 |
345 |
346 |
347 |
348 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_automaton_asserv.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
14 |
15 |
23 |
24 |
31 |
32 |
38 |
39 |
46 |
47 |
48 |
55 |
56 |
64 |
65 |
72 |
73 |
82 |
83 |
92 |
93 |
94 |
95 |
103 |
104 |
110 |
111 |
122 |
123 |
134 |
135 |
136 |
137 |
143 |
144 |
154 |
155 |
166 |
167 |
168 |
169 |
175 |
176 |
182 |
183 |
190 |
191 |
192 |
198 |
199 |
205 |
206 |
213 |
214 |
220 |
221 |
229 |
230 |
231 |
232 |
238 |
239 |
245 |
246 |
253 |
254 |
255 |
261 |
262 |
263 |
273 |
274 |
284 |
285 |
286 |
292 |
293 |
300 |
301 |
309 |
310 |
317 |
318 |
319 |
320 |
327 |
328 |
336 |
337 |
344 |
345 |
346 |
347 |
354 |
355 |
363 |
364 |
371 |
372 |
373 |
374 |
381 |
382 |
390 |
391 |
398 |
399 |
400 |
407 |
408 |
416 |
417 |
424 |
425 |
426 |
427 |
434 |
435 |
443 |
444 |
451 |
452 |
453 |
454 |
455 |
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/Automaton/ReadTaskS7.java:
--------------------------------------------------------------------------------
1 | package com.example.fabio.plcmonitor.Automaton;
2 |
3 | import android.graphics.Color;
4 | import android.graphics.PorterDuff;
5 | import android.os.Handler;
6 | import android.os.Message;
7 | import android.util.Log;
8 | import android.view.View;
9 | import android.widget.Button;
10 | import android.widget.CheckBox;
11 | import android.widget.ImageButton;
12 | import android.widget.TextView;
13 | import android.widget.Toast;
14 |
15 | import com.example.fabio.plcmonitor.Activity.AutomatonAsservActivity;
16 | import com.example.fabio.plcmonitor.Activity.AutomatonCompActivity;
17 | import com.example.fabio.plcmonitor.Configs;
18 | import com.example.fabio.plcmonitor.R;
19 | import com.example.fabio.plcmonitor.SimaticS7.S7;
20 | import com.example.fabio.plcmonitor.SimaticS7.S7Client;
21 | import com.example.fabio.plcmonitor.SimaticS7.S7OrderCode;
22 |
23 | import java.util.concurrent.atomic.AtomicBoolean;
24 |
25 | public class ReadTaskS7
26 | {
27 | //constantes pour la gestion du traitement activé par les message Handler
28 | private static final int MESSAGE_PRE_EXECUTE = 1;
29 | private static final int MESSAGE_PROGRESS_UPDATE = 2;
30 | private static final int MESSAGE_POST_EXECUTE = 3;
31 |
32 | private AtomicBoolean isRunning = new AtomicBoolean(false);
33 |
34 | //Pour les comprimés
35 | private TextView tv_comp_plcNumber, tv_comp_nbBouteille, tv_comp_nbFlacon;
36 | private CheckBox cb_comp_service, cb_comp_flacon;
37 | private Button bt_comp_5, bt_comp_10, bt_comp_15, bt_comp_ecrire;
38 | private ImageButton ib_comp_connexion;
39 |
40 | //Pour l'asservissement de niveau
41 | private TextView tv_asserv_PLCnumber, tv_asserv_niveauEau, tv_asserv_consigneAuto, tv_asserv_consigneManuel, tv_asserv_motPilotageVanne;
42 | private CheckBox cb_asserv_valve1, cb_asserv_valve2, cb_asserv_valve3, cb_asserv_valve4;
43 | private Button bt_asserv_manuel, bt_asserv_auto, bt_asserv_ecrire;
44 | private ImageButton ib_asserv_connexion;
45 |
46 | private View vi_ui;
47 | private AutomatonCompActivity automatonCompActivity;
48 | private AutomatonAsservActivity automatonAsservActivity;
49 |
50 | //Attribut permettant de connaitre quelle automate on contacte
51 | private int numAutomate;
52 |
53 | private Integer databloc = Configs.getDatablock();
54 |
55 | //Classe interne implémentant Runnable et Thread
56 | private AutomateS7 plcS7;
57 | private Thread readThread;
58 |
59 | //Objet S7Client nécessaire pour la connexion avec l'API
60 | private S7Client comS7;
61 |
62 | //Tableaux contenant les paramètres de connexion et permettant les échanges avec l’automate
63 | private String[] param = new String[10];
64 |
65 | private byte[] datasPLC = new byte[512], pillsPLC = new byte[2];
66 |
67 | //Constructeur ReadTaskS7 pour les comprimés
68 | public ReadTaskS7(AutomatonCompActivity automatonCompActivity,View vi_ui,TextView tv_comp_plcNumber, TextView tv_comp_nbBouteille, TextView tv_comp_nbFlacon, CheckBox cb_comp_service, CheckBox cb_comp_flacon,
69 | Button bt_comp_5, Button bt_comp_10, Button bt_comp_15, Button bt_comp_ecrire, ImageButton ib_comp_connexion, int numAutomate)
70 | {
71 | //Objets modifiés par la tâche de fond
72 | this.automatonCompActivity = automatonCompActivity;
73 | this.vi_ui = vi_ui;
74 | this.tv_comp_plcNumber = tv_comp_plcNumber;
75 | this.tv_comp_nbBouteille = tv_comp_nbBouteille;
76 | this.tv_comp_nbFlacon = tv_comp_nbFlacon;
77 | this.cb_comp_service = cb_comp_service;
78 | this.cb_comp_flacon = cb_comp_flacon;
79 | this.bt_comp_5 = bt_comp_5;
80 | this.bt_comp_10 = bt_comp_10;
81 | this.bt_comp_15 = bt_comp_15;
82 | this.bt_comp_ecrire = bt_comp_ecrire;
83 | this.ib_comp_connexion = ib_comp_connexion;
84 | this.numAutomate = numAutomate;
85 |
86 | comS7 = new S7Client();
87 | plcS7 = new AutomateS7();
88 | //Thread de lecture d'informations
89 | readThread = new Thread(plcS7);
90 | }
91 |
92 | //Constructeur pour l'asservissement
93 | public ReadTaskS7(AutomatonAsservActivity automatonAsservActivity, View vi_ui, TextView tv_asserv_PLCnumber, TextView tv_asserv_niveauEau, TextView tv_asserv_consigneAuto, TextView tv_asserv_consigneManuel,
94 | TextView tv_asserv_motPilotageVanne, CheckBox cb_asserv_valve1, CheckBox cb_asserv_valve2, CheckBox cb_asserv_valve3, CheckBox cb_asserv_valve4,
95 | Button bt_asserv_manuel, Button bt_asserv_auto, Button bt_asserv_ecrire, ImageButton ib_asserv_connexion, int numAutomate)
96 | {
97 | this.vi_ui = vi_ui;
98 | this.automatonAsservActivity = automatonAsservActivity;
99 | this.tv_asserv_PLCnumber = tv_asserv_PLCnumber;
100 | this.tv_asserv_niveauEau = tv_asserv_niveauEau;
101 | this.tv_asserv_consigneAuto = tv_asserv_consigneAuto;
102 | this.tv_asserv_consigneManuel = tv_asserv_consigneManuel;
103 | this.tv_asserv_motPilotageVanne = tv_asserv_motPilotageVanne;
104 | this.cb_asserv_valve1 = cb_asserv_valve1;
105 | this.cb_asserv_valve2 = cb_asserv_valve2;
106 | this.cb_asserv_valve3 = cb_asserv_valve3;
107 | this.cb_asserv_valve4 = cb_asserv_valve4;
108 | this.bt_asserv_manuel = bt_asserv_manuel;
109 | this.bt_asserv_auto = bt_asserv_auto;
110 | this.bt_asserv_ecrire = bt_asserv_ecrire;
111 | this.ib_asserv_connexion = ib_asserv_connexion;
112 | this.numAutomate = numAutomate;
113 |
114 | comS7 = new S7Client();
115 | plcS7 = new AutomateS7();
116 | //Thread de lecture d'informations
117 | readThread = new Thread(plcS7);
118 | }
119 |
120 | public void Start(String ip, String rack, String slot) {
121 | //Vérification si le thread n'est pas en cours
122 | if(!readThread.isAlive()){
123 | //Récupère les paramètres de connexion à l'API (IP, rack, slot)
124 | param[0] = ip;
125 | param[1] = rack;
126 | param[2] = slot;
127 |
128 | //Démare le thread et active le flag de gestion
129 | readThread.start();
130 | isRunning.set(true);
131 | }
132 | }
133 |
134 | public void Stop(){
135 | //Interruption du traitement (flag)
136 | isRunning.set(false);
137 | //Arrêt de communication avec l'API
138 | comS7.Disconnect();
139 | //interruption du Thread avant la fin de son traitement
140 | readThread.interrupt();
141 | }
142 |
143 | //Méthode exécuté avant le lancement
144 | private void downloadOnPreExecute(int t) {
145 | //Affichage du numéro de PLC + affichage du bouton écrire
146 | //Si la demande vient de l'activité pour les comprimés
147 | if(numAutomate == 1)
148 | {
149 | tv_comp_plcNumber.setText(String.valueOf(t));
150 | ib_comp_connexion.setBackgroundColor(automatonCompActivity.getResources().getColor(R.color.green));
151 | if(Configs.getIsWriteAccess())
152 | {
153 | bt_comp_ecrire.setVisibility(View.VISIBLE);
154 | }
155 | }
156 | else
157 | {
158 | tv_asserv_PLCnumber.setText(String.valueOf(t));
159 | ib_asserv_connexion.setBackgroundColor(automatonAsservActivity.getResources().getColor(R.color.green));
160 | if(Configs.getIsWriteAccess())
161 | {
162 | bt_asserv_ecrire.setVisibility(View.VISIBLE);
163 | }
164 | }
165 | //A partir de cette méthode la connexion est établie, alors on peut le signaler
166 | Toast.makeText(vi_ui.getContext(), "Connexion établie", Toast.LENGTH_LONG).show();
167 | }
168 |
169 | //Mise à jour durant le traitement
170 | private void downloadOnProgressUpdate(int nbFlacon) {
171 | //Automate comprimé
172 | if(numAutomate == 1)
173 | {
174 | //Selecteur en service
175 | if(S7.GetBitAt(datasPLC,0,0))
176 | {
177 | cb_comp_service.setChecked(true);
178 | }
179 | else
180 | {
181 | cb_comp_service.setChecked(false);
182 | }
183 |
184 | //Arrivée des flacons vides
185 | if(S7.GetBitAt(datasPLC,1,3))
186 | {
187 | cb_comp_flacon.setChecked(true);
188 | }
189 | else
190 | {
191 | cb_comp_flacon.setChecked(false);
192 | }
193 |
194 | //Demande de 5 comprimés
195 | if(S7.GetBitAt(datasPLC,4,3))
196 | {
197 | bt_comp_5.getBackground().setColorFilter(Color.GREEN, PorterDuff.Mode.MULTIPLY);
198 | bt_comp_10.getBackground().clearColorFilter();
199 | bt_comp_15.getBackground().clearColorFilter();
200 |
201 | }
202 | //Demande de 10 comprimés
203 | if (S7.GetBitAt(datasPLC,4,4))
204 | {
205 | bt_comp_10.getBackground().setColorFilter(Color.GREEN, PorterDuff.Mode.MULTIPLY);
206 | bt_comp_5.getBackground().clearColorFilter();
207 | bt_comp_15.getBackground().clearColorFilter();
208 | }
209 | //Demande de 15 comprimés
210 | if (S7.GetBitAt(datasPLC,4,5))
211 | {
212 | bt_comp_15.getBackground().setColorFilter(Color.GREEN, PorterDuff.Mode.MULTIPLY);
213 | bt_comp_10.getBackground().clearColorFilter();
214 | bt_comp_5.getBackground().clearColorFilter();
215 | }
216 |
217 | //Comprimés mis en flacon
218 | tv_comp_nbFlacon.setText(String.valueOf(nbFlacon) + "");
219 |
220 | //Bouteille remplies
221 | tv_comp_nbBouteille.setText(String.valueOf(S7.GetWordAt(datasPLC, 16) +""));
222 |
223 | }
224 | //Automate asservissement
225 | else
226 | {
227 | //Selecteur de mode manuel/auto
228 | if(S7.GetBitAt(datasPLC,0,5))
229 | {
230 | bt_asserv_auto.getBackground().setColorFilter(Color.GREEN, PorterDuff.Mode.MULTIPLY);
231 | bt_asserv_manuel.getBackground().clearColorFilter();
232 | }
233 | else
234 | {
235 | bt_asserv_manuel.getBackground().setColorFilter(Color.GREEN, PorterDuff.Mode.MULTIPLY);
236 | bt_asserv_auto.getBackground().clearColorFilter();
237 | }
238 |
239 | //Valve 1
240 | if(S7.GetBitAt(datasPLC,0,1))
241 | {
242 | cb_asserv_valve1.setChecked(true);
243 | }
244 | else
245 | {
246 | cb_asserv_valve1.setChecked(false);
247 | }
248 |
249 | //Valve 2
250 | if(S7.GetBitAt(datasPLC,0,2))
251 | {
252 | cb_asserv_valve2.setChecked(true);
253 | }
254 | else
255 | {
256 | cb_asserv_valve2.setChecked(false);
257 | }
258 |
259 | //Valve 3
260 | if(S7.GetBitAt(datasPLC,0,3))
261 | {
262 | cb_asserv_valve3.setChecked(true);
263 | }
264 | else
265 | {
266 | cb_asserv_valve3.setChecked(false);
267 | }
268 |
269 | //Valve 4
270 | if(S7.GetBitAt(datasPLC,0,4))
271 | {
272 | cb_asserv_valve4.setChecked(true);
273 | }
274 | else
275 | {
276 | cb_asserv_valve4.setChecked(false);
277 | }
278 |
279 | //Niveau d'eau
280 | tv_asserv_niveauEau.setText(S7.GetWordAt(datasPLC, 16) + "");
281 |
282 | //Consigne auto
283 | tv_asserv_consigneAuto.setText(S7.GetWordAt(datasPLC,18) + "");
284 |
285 | //Consigne manuelle
286 | tv_asserv_consigneManuel.setText(S7.GetWordAt(datasPLC,20) + "");
287 |
288 | //Mot de pilotage vanne
289 | tv_asserv_motPilotageVanne.setText(S7.GetWordAt(datasPLC,22) + "");
290 | }
291 | }
292 |
293 | //Après le traitement de la tâche de fond
294 | private void downloadOnPostExecute() {
295 | Toast.makeText(vi_ui.getContext(), "Vous avez été déconnecté de l'automate", Toast.LENGTH_LONG).show();
296 |
297 | if(numAutomate == 1)
298 | {
299 | tv_comp_nbBouteille.setText("");
300 | tv_comp_nbFlacon.setText("");
301 | tv_comp_plcNumber.setText("");
302 | cb_comp_service.setChecked(false);
303 | cb_comp_flacon.setChecked(false);
304 | bt_comp_5.getBackground().clearColorFilter();
305 | bt_comp_10.getBackground().clearColorFilter();
306 | bt_comp_15.getBackground().clearColorFilter();
307 | }
308 | else
309 | {
310 | bt_asserv_manuel.getBackground().clearColorFilter();
311 | bt_asserv_auto.getBackground().clearColorFilter();
312 | cb_asserv_valve1.setChecked(false);
313 | cb_asserv_valve2.setChecked(false);
314 | cb_asserv_valve3.setChecked(false);
315 | cb_asserv_valve4.setChecked(false);
316 | tv_asserv_niveauEau.setText("");
317 | tv_asserv_consigneAuto.setText("");
318 | tv_asserv_consigneManuel.setText("");
319 | tv_asserv_motPilotageVanne.setText("");
320 | tv_asserv_PLCnumber.setText("");
321 | }
322 | }
323 |
324 | //Handler -> gestion des différents messages envoyés au thread
325 | private Handler monHandler = new Handler() {
326 |
327 | public void handleMessage(Message msg){
328 | super.handleMessage(msg);
329 | switch (msg.what){
330 | case MESSAGE_PRE_EXECUTE:
331 | downloadOnPreExecute(msg.arg1);
332 | break;
333 | case MESSAGE_PROGRESS_UPDATE:
334 | downloadOnProgressUpdate(msg.arg1);
335 | break;
336 | case MESSAGE_POST_EXECUTE:
337 | downloadOnPostExecute();
338 | break;
339 | default:
340 | break;
341 | }
342 | }
343 | };
344 |
345 | //Classe interne pour lire les valeurs de l'automate.
346 | //Utilise l'handler pour écrire les valeurs lues
347 | private class AutomateS7 implements Runnable
348 | {
349 | //Méthode qui se connecte à l'automate et écrit les valeurs de l'automate
350 | @Override
351 | public void run()
352 | {
353 | try{
354 | //Type de connexion
355 | comS7.SetConnectionType(S7.S7_BASIC);
356 | //Retourne 0 si la connexion est réussi
357 | Integer res = comS7.ConnectTo(param[0],Integer.valueOf(param[1]),Integer.valueOf(param[2]));
358 | S7OrderCode orderCode = new S7OrderCode();
359 | //Récupère le numéro de référence de la CPU, retourné 0 si c'est réussi
360 | Integer result = comS7.GetOrderCode(orderCode);
361 | int numCPU=-1;
362 | if(res.equals(0) && result.equals(0)){
363 | numCPU = Integer.valueOf(orderCode.Code().toString().substring(5, 8));
364 | }
365 | else{
366 | numCPU = 0000;
367 | }
368 |
369 | sendPreExecuteMessage(numCPU);
370 |
371 | //Lecture de la variable API, traitement en boucle
372 | while(isRunning.get())
373 | {
374 | if(res.equals(0)){
375 | int retInfo = comS7.ReadArea(S7.S7AreaDB, databloc,0,32,datasPLC);
376 | int pillsRead = comS7.ReadArea(S7.S7AreaDB, databloc,15,2, pillsPLC);
377 | int pills;
378 | int data = 0;
379 |
380 | if( retInfo == 0){
381 | //Lecture de la donnée
382 | data = S7.GetWordAt(datasPLC,0);
383 | //On transfert la valeur à l'UI
384 | sendProgressMessage(data);
385 | }
386 |
387 | if(pillsRead == 0)
388 | {
389 | pills = S7.BCDtoByte(pillsPLC[0]);
390 | sendProgressMessage(pills);
391 | }
392 | Log.i("Variable A.P.I. ->",String.valueOf(data));
393 | }
394 | try {
395 | Thread.sleep(500);
396 | }
397 | catch(InterruptedException e){
398 | e.printStackTrace();
399 | }
400 | }
401 | //Traitement terminé
402 | sendPostExecuteMessage();
403 | }
404 | catch(Exception e){
405 | e.printStackTrace();
406 | System.out.println("je passe" + e);
407 |
408 | if(numAutomate == 1)
409 | {
410 | //Connecté en wifi mais mauvaise configuration
411 | automatonCompActivity.runOnUiThread(new Runnable() {
412 | public void run() {
413 | ib_comp_connexion.setBackgroundColor(automatonCompActivity.getResources().getColor(R.color.orange));
414 | Toast.makeText(automatonCompActivity, "Impossible de se connecter à l'automate, vérifiez la configuration", Toast.LENGTH_SHORT).show();
415 | }
416 | });
417 | }
418 |
419 | else
420 | {
421 | //On affiche un toast de cette mannière autrement, erreur
422 | automatonAsservActivity.runOnUiThread(new Runnable() {
423 | public void run() {
424 | ib_asserv_connexion.setBackgroundColor(automatonAsservActivity.getResources().getColor(R.color.orange));
425 | Toast.makeText(automatonAsservActivity, "Impossible de se connecter à l'automate, vérifiez la configuration", Toast.LENGTH_SHORT).show();
426 | }
427 | });
428 | }
429 | }
430 | }
431 |
432 | //Après le traitement principal --> définition du message: connexion stoppé
433 | private void sendPostExecuteMessage() {
434 | Message postExecuteMsg = new Message();
435 | postExecuteMsg.what = MESSAGE_POST_EXECUTE;
436 | monHandler.sendMessage(postExecuteMsg);
437 | }
438 |
439 | //Avant le traitement principal --> définition du message: connexion démarré
440 | //Transfert de la référence de l'API (PLC)
441 | private void sendPreExecuteMessage(int v) {
442 | Message preExecuteMsg = new Message();
443 | preExecuteMsg.what = MESSAGE_PRE_EXECUTE;
444 | preExecuteMsg.arg1 = v;
445 | monHandler.sendMessage(preExecuteMsg);
446 | }
447 |
448 | //Durant de traitement principal --> définition du message: automate en service
449 | //Transfert de la valeur dans la variable récupérée dans l’A.P.I.
450 | private void sendProgressMessage(int i) {
451 | Message progressMsg = new Message();
452 | progressMsg.what = MESSAGE_PROGRESS_UPDATE;
453 | progressMsg.arg1 = i;
454 | monHandler.sendMessage(progressMsg);
455 | }
456 | }
457 |
458 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/example/fabio/plcmonitor/SimaticS7/S7Client.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties.
3 | * To change this template file, choose Tools | Templates
4 | * and open the template in the editor.
5 | */
6 |
7 | package com.example.fabio.plcmonitor.SimaticS7;
8 |
9 | import java.io.DataInputStream;
10 | import java.io.DataOutputStream;
11 | import java.io.IOException;
12 | import java.io.UnsupportedEncodingException;
13 | import java.net.InetSocketAddress;
14 | import java.net.Socket;
15 | import java.net.SocketAddress;
16 | import java.util.Date;
17 |
18 |
19 | /**
20 | *
21 | * @author Dave Nardella
22 | */
23 | public class S7Client
24 | {
25 | // WordLength
26 | private static final byte S7WLByte =0x02;
27 | private static final byte S7WLCounter =0x1C;
28 | private static final byte S7WLTimer =0x1D;
29 | // Error Codes
30 | public static final int errTCPConnectionFailed = 0x0001;
31 | public static final int errTCPDataSend = 0x0002;
32 | public static final int errTCPDataRecv = 0x0003;
33 | public static final int errTCPDataRecvTout = 0x0004;
34 | public static final int errTCPConnectionReset = 0x0005;
35 | public static final int errISOInvalidPDU = 0x0006;
36 | public static final int errISOConnectionFailed = 0x0007;
37 | public static final int errISONegotiatingPDU = 0x0008;
38 | public static final int errS7InvalidPDU = 0x0009;
39 | public static final int errS7DataRead = 0x000A;
40 | public static final int errS7DataWrite = 0x000B;
41 | public static final int errS7BufferTooSmall = 0x000C;
42 | public static final int errS7FunctionError = 0x000D;
43 | public static final int errS7InvalidParams = 0x000E;
44 |
45 | // Public fields
46 | public boolean Connected = false;
47 | public int LastError = 0;
48 | public int RecvTimeout = 2000;
49 |
50 | // Privates
51 | private static final int ISOTCP = 102; // ISOTCP Port
52 | private static final int MinPduSize = 16;
53 | private static final int DefaultPduSizeRequested = 480;
54 | private static final int IsoHSize = 7; // TPKT+COTP Header Size
55 | private static final int MaxPduSize = DefaultPduSizeRequested+IsoHSize;
56 |
57 |
58 | private Socket TCPSocket;
59 | private final byte[] PDU = new byte[2048];
60 |
61 | private DataInputStream InStream = null;
62 | private DataOutputStream OutStream = null;
63 |
64 | private String IPAddress;
65 |
66 | private byte LocalTSAP_HI;
67 | private byte LocalTSAP_LO;
68 | private byte RemoteTSAP_HI;
69 | private byte RemoteTSAP_LO;
70 | private byte LastPDUType;
71 |
72 | private short ConnType = S7.PG;
73 | private int _PDULength = 0;
74 |
75 | // Telegrams
76 | // ISO Connection Request telegram (contains also ISO Header and COTP Header)
77 | private static final byte ISO_CR[] = {
78 | // TPKT (RFC1006 Header)
79 | (byte)0x03, // RFC 1006 ID (3)
80 | (byte)0x00, // Reserved, always 0
81 | (byte)0x00, // High part of packet lenght (entire frame, payload and TPDU included)
82 | (byte)0x16, // Low part of packet lenght (entire frame, payload and TPDU included)
83 | // COTP (ISO 8073 Header)
84 | (byte)0x11, // PDU Size Length
85 | (byte)0xE0, // CR - Connection Request ID
86 | (byte)0x00, // Dst Reference HI
87 | (byte)0x00, // Dst Reference LO
88 | (byte)0x00, // Src Reference HI
89 | (byte)0x01, // Src Reference LO
90 | (byte)0x00, // Class + Options Flags
91 | (byte)0xC0, // PDU Max Length ID
92 | (byte)0x01, // PDU Max Length HI
93 | (byte)0x0A, // PDU Max Length LO
94 | (byte)0xC1, // Src TSAP Identifier
95 | (byte)0x02, // Src TSAP Length (2 bytes)
96 | (byte)0x01, // Src TSAP HI (will be overwritten)
97 | (byte)0x00, // Src TSAP LO (will be overwritten)
98 | (byte)0xC2, // Dst TSAP Identifier
99 | (byte)0x02, // Dst TSAP Length (2 bytes)
100 | (byte)0x01, // Dst TSAP HI (will be overwritten)
101 | (byte)0x02 // Dst TSAP LO (will be overwritten)
102 | };
103 |
104 | // S7 PDU Negotiation Telegram (contains also ISO Header and COTP Header)
105 | private static final byte S7_PN[] = {
106 | (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x19,
107 | (byte)0x02, (byte)0xf0, (byte)0x80, // TPKT + COTP (see above for info)
108 | (byte)0x32, (byte)0x01, (byte)0x00, (byte)0x00,
109 | (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x08,
110 | (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0x00,
111 | (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x01,
112 | (byte)0x00, (byte)0x1e // PDU Length Requested = HI-LO 480 bytes
113 | };
114 |
115 | // S7 Read/Write Request Header (contains also ISO Header and COTP Header)
116 | private static final byte S7_RW[] = { // 31-35 bytes
117 | (byte)0x03,(byte)0x00,
118 | (byte)0x00,(byte)0x1f, // Telegram Length (Data Size + 31 or 35)
119 | (byte)0x02,(byte)0xf0, (byte)0x80, // COTP (see above for info)
120 | (byte)0x32, // S7 Protocol ID
121 | (byte)0x01, // Job Type
122 | (byte)0x00,(byte)0x00, // Redundancy identification
123 | (byte)0x05,(byte)0x00, // PDU Reference
124 | (byte)0x00,(byte)0x0e, // Parameters Length
125 | (byte)0x00,(byte)0x00, // Data Length = Size(bytes) + 4
126 | (byte)0x04, // Function 4 Read Var, 5 Write Var
127 | (byte)0x01, // Items count
128 | (byte)0x12, // Var spec.
129 | (byte)0x0a, // Length of remaining bytes
130 | (byte)0x10, // Syntax ID
131 | S7WLByte, // Transport Size
132 | (byte)0x00,(byte)0x00, // Num Elements
133 | (byte)0x00,(byte)0x00, // DB Number (if any, else 0)
134 | (byte)0x84, // Area Type
135 | (byte)0x00,(byte)0x00,(byte)0x00, // Area Offset
136 | // WR area
137 | (byte)0x00, // Reserved
138 | (byte)0x04, // Transport size
139 | (byte)0x00,(byte)0x00, // Data Length * 8 (if not timer or counter)
140 | };
141 | private static final int Size_RD = 31;
142 | private static final int Size_WR = 35;
143 |
144 | // S7 Get Block Info Request Header (contains also ISO Header and COTP Header)
145 | private static final byte S7_BI[] = {
146 | (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x25,
147 | (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32,
148 | (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x05,
149 | (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00,
150 | (byte)0x0c, (byte)0x00, (byte)0x01, (byte)0x12,
151 | (byte)0x04, (byte)0x11, (byte)0x43, (byte)0x03,
152 | (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00,
153 | (byte)0x08, (byte)0x30,
154 | (byte)0x41, // Block Type
155 | (byte)0x30, (byte)0x30, (byte)0x30, (byte)0x30, (byte)0x30, // ASCII Block Number
156 | (byte)0x41
157 | };
158 |
159 | // SZL First telegram request
160 | private static final byte S7_SZL_FIRST[] = {
161 | (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x21,
162 | (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32,
163 | (byte)0x07, (byte)0x00, (byte)0x00,
164 | (byte)0x05, (byte)0x00, // Sequence out
165 | (byte)0x00, (byte)0x08, (byte)0x00,
166 | (byte)0x08, (byte)0x00, (byte)0x01, (byte)0x12,
167 | (byte)0x04, (byte)0x11, (byte)0x44, (byte)0x01,
168 | (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00,
169 | (byte)0x04,
170 | (byte)0x00, (byte)0x00, // ID (29)
171 | (byte)0x00, (byte)0x00 // Index (31)
172 | };
173 |
174 | // SZL Next telegram request
175 | private static final byte S7_SZL_NEXT[] = {
176 | (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x21,
177 | (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32,
178 | (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x06,
179 | (byte)0x00, (byte)0x00, (byte)0x0c, (byte)0x00,
180 | (byte)0x04, (byte)0x00, (byte)0x01, (byte)0x12,
181 | (byte)0x08, (byte)0x12, (byte)0x44, (byte)0x01,
182 | (byte)0x01, // Sequence
183 | (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
184 | (byte)0x0a, (byte)0x00, (byte)0x00, (byte)0x00
185 | };
186 |
187 | // Get Date/Time request
188 | private static final byte S7_GET_DT[] = {
189 | (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x1d,
190 | (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32,
191 | (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x38,
192 | (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00,
193 | (byte)0x04, (byte)0x00, (byte)0x01, (byte)0x12,
194 | (byte)0x04, (byte)0x11, (byte)0x47, (byte)0x01,
195 | (byte)0x00, (byte)0x0a, (byte)0x00, (byte)0x00,
196 | (byte)0x00
197 | };
198 |
199 | // Set Date/Time command
200 | private static final byte S7_SET_DT[] = {
201 | (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x27,
202 | (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32,
203 | (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x89,
204 | (byte)0x03, (byte)0x00, (byte)0x08, (byte)0x00,
205 | (byte)0x0e, (byte)0x00, (byte)0x01, (byte)0x12,
206 | (byte)0x04, (byte)0x11, (byte)0x47, (byte)0x02,
207 | (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00,
208 | (byte)0x0a, (byte)0x00, (byte)0x19, // Hi part of Year
209 | (byte)0x13, // Lo part of Year
210 | (byte)0x12, // Month
211 | (byte)0x06, // Day
212 | (byte)0x17, // Hour
213 | (byte)0x37, // Min
214 | (byte)0x13, // Sec
215 | (byte)0x00, (byte)0x01 // ms + Day of week
216 | };
217 |
218 | // S7 STOP request
219 | private static final byte S7_STOP[] = {
220 | (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x21,
221 | (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32,
222 | (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x0e,
223 | (byte)0x00, (byte)0x00, (byte)0x10, (byte)0x00,
224 | (byte)0x00, (byte)0x29, (byte)0x00, (byte)0x00,
225 | (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x09,
226 | (byte)0x50, (byte)0x5f, (byte)0x50, (byte)0x52,
227 | (byte)0x4f, (byte)0x47, (byte)0x52, (byte)0x41,
228 | (byte)0x4d
229 | };
230 |
231 | // S7 HOT Start request
232 | private static final byte S7_HOT_START[] = {
233 | (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x25,
234 | (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32,
235 | (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x0c,
236 | (byte)0x00, (byte)0x00, (byte)0x14, (byte)0x00,
237 | (byte)0x00, (byte)0x28, (byte)0x00, (byte)0x00,
238 | (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
239 | (byte)0xfd, (byte)0x00, (byte)0x00, (byte)0x09,
240 | (byte)0x50, (byte)0x5f, (byte)0x50, (byte)0x52,
241 | (byte)0x4f, (byte)0x47, (byte)0x52, (byte)0x41,
242 | (byte)0x4d
243 | };
244 |
245 | // S7 COLD Start request
246 | private static final byte S7_COLD_START[] = {
247 | (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x27,
248 | (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32,
249 | (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x0f,
250 | (byte)0x00, (byte)0x00, (byte)0x16, (byte)0x00,
251 | (byte)0x00, (byte)0x28, (byte)0x00, (byte)0x00,
252 | (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
253 | (byte)0xfd, (byte)0x00, (byte)0x02, (byte)0x43,
254 | (byte)0x20, (byte)0x09, (byte)0x50, (byte)0x5f,
255 | (byte)0x50, (byte)0x52, (byte)0x4f, (byte)0x47,
256 | (byte)0x52, (byte)0x41, (byte)0x4d
257 | };
258 |
259 | // S7 Get PLC Status
260 | private static final byte S7_GET_STAT[] = {
261 | (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x21,
262 | (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32,
263 | (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x2c,
264 | (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00,
265 | (byte)0x08, (byte)0x00, (byte)0x01, (byte)0x12,
266 | (byte)0x04, (byte)0x11, (byte)0x44, (byte)0x01,
267 | (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00,
268 | (byte)0x04, (byte)0x04, (byte)0x24, (byte)0x00,
269 | (byte)0x00
270 | };
271 |
272 | // S7 Set Session Password
273 | private static final byte S7_SET_PWD[] = {
274 | (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x25,
275 | (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32,
276 | (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x27,
277 | (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00,
278 | (byte)0x0c, (byte)0x00, (byte)0x01, (byte)0x12,
279 | (byte)0x04, (byte)0x11, (byte)0x45, (byte)0x01,
280 | (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00,
281 | (byte)0x08,
282 | // 8 Char Encoded Password
283 | (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
284 | (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00
285 | };
286 |
287 | // S7 Clear Session Password
288 | private static final byte S7_CLR_PWD[] = {
289 | (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x1d,
290 | (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32,
291 | (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x29,
292 | (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00,
293 | (byte)0x04, (byte)0x00, (byte)0x01, (byte)0x12,
294 | (byte)0x04, (byte)0x11, (byte)0x45, (byte)0x02,
295 | (byte)0x00, (byte)0x0a, (byte)0x00, (byte)0x00,
296 | (byte)0x00
297 | };
298 |
299 | public S7Client()
300 | {
301 | // Placeholder for future implementations
302 | }
303 |
304 | public static String ErrorText(int Error)
305 | {
306 | switch (Error)
307 | {
308 | case errTCPConnectionFailed :
309 | return "TCP Connection failed.";
310 | case errTCPDataSend :
311 | return "TCP Sending error.";
312 | case errTCPDataRecv :
313 | return "TCP Receiving error.";
314 | case errTCPDataRecvTout :
315 | return "Data Receiving timeout.";
316 | case errTCPConnectionReset :
317 | return "Connection reset by the peer.";
318 | case errISOInvalidPDU :
319 | return "Invalid ISO PDU received.";
320 | case errISOConnectionFailed :
321 | return "ISO connection refused by the CPU.";
322 | case errISONegotiatingPDU :
323 | return "ISO error negotiating the PDU length.";
324 | case errS7InvalidPDU :
325 | return "Invalid S7 PDU received.";
326 | case errS7DataRead :
327 | return "S7 Error reading data from the CPU.";
328 | case errS7DataWrite :
329 | return "S7 Error writing data to the CPU.";
330 | case errS7BufferTooSmall :
331 | return "The Buffer supplied to the function is too small.";
332 | case errS7FunctionError :
333 | return "S7 function refused by the CPU.";
334 | case errS7InvalidParams :
335 | return "Invalid parameters supplied to the function.";
336 | default :
337 | return "Unknown error : 0x"+Integer.toHexString(Error);
338 | }
339 | }
340 |
341 | private int TCPConnect()
342 | {
343 | SocketAddress sockaddr = new InetSocketAddress(IPAddress, ISOTCP);
344 | LastError=0;
345 | try {
346 | TCPSocket = new Socket();
347 | TCPSocket.connect(sockaddr ,5000);
348 | TCPSocket.setTcpNoDelay(true);
349 | InStream = new DataInputStream(TCPSocket.getInputStream());
350 | OutStream = new DataOutputStream(TCPSocket.getOutputStream());
351 | }
352 | catch (IOException e) {
353 | LastError=errTCPConnectionFailed;
354 | }
355 | return LastError;
356 | }
357 |
358 | private int WaitForData(int Size, int Timeout)
359 | {
360 | int cnt = 0;
361 | LastError=0;
362 | int SizeAvail;
363 | boolean Expired = false;
364 | try
365 | {
366 | SizeAvail=InStream.available();
367 | while ((SizeAvailTimeout;
379 | // If timeout we clean the buffer
380 | if (Expired && (SizeAvail>0) && (LastError==0))
381 | InStream.read(PDU, 0, SizeAvail);
382 | }
383 | }
384 | catch (IOException ex)
385 | {
386 | LastError=errTCPDataRecvTout;
387 | }
388 | if (cnt>=Timeout)
389 | {
390 | LastError=errTCPDataRecvTout;
391 | }
392 | return LastError;
393 | }
394 |
395 | private int RecvPacket(byte[] Buffer, int Start, int Size)
396 | {
397 | int BytesRead=0;
398 | LastError=WaitForData(Size,RecvTimeout);
399 | if (LastError==0)
400 | {
401 | try {
402 | BytesRead = InStream.read(Buffer, Start, Size);
403 | } catch (IOException ex) {
404 | LastError=errTCPDataRecv;
405 | }
406 | if (BytesRead==0)
407 | LastError=errTCPConnectionReset;
408 | }
409 | return LastError;
410 | }
411 |
412 | private void SendPacket(byte[] Buffer, int Len)
413 | {
414 | LastError = 0;
415 | try {
416 | OutStream.write(Buffer,0,Len);
417 | OutStream.flush();
418 | } catch (IOException ex) {
419 | LastError = errTCPDataSend;
420 | }
421 | }
422 | private void SendPacket(byte[] Buffer)
423 | {
424 | SendPacket(Buffer,Buffer.length);
425 | }
426 |
427 | private int RecvIsoPacket()
428 | {
429 | Boolean Done = false;
430 | int Size = 0;
431 | while ((LastError==0) && !Done)
432 | {
433 | // Get TPKT (4 bytes)
434 | RecvPacket(PDU, 0, 4);
435 | if (LastError==0)
436 | {
437 | Size=S7.GetWordAt(PDU,2);
438 | // Check 0 bytes Data Packet (only TPKT+COTP = 7 bytes)
439 | if (Size==IsoHSize)
440 | RecvPacket(PDU,4, 3); // Skip remaining 3 bytes and Done is still false
441 | else
442 | {
443 | if ((Size>MaxPduSize) || (Size16 && <247
447 | }
448 | }
449 | }
450 | if (LastError==0)
451 | {
452 | RecvPacket(PDU,4, 3); // Skip remaining 3 COTP bytes
453 | LastPDUType=PDU[5]; // Stores PDU Type, we need it
454 | // Receives the S7 Payload
455 | RecvPacket(PDU, 7, Size-IsoHSize);
456 | }
457 | if (LastError==0)
458 | return Size;
459 | else
460 | return 0;
461 | }
462 |
463 | private int ISOConnect()
464 | {
465 | int Size;
466 | ISO_CR[16]=LocalTSAP_HI;
467 | ISO_CR[17]=LocalTSAP_LO;
468 | ISO_CR[20]=RemoteTSAP_HI;
469 | ISO_CR[21]=RemoteTSAP_LO;
470 |
471 | // Sends the connection request telegram
472 | SendPacket(ISO_CR);
473 | if (LastError==0)
474 | {
475 | // Gets the reply (if any)
476 | Size=RecvIsoPacket();
477 | if (LastError==0)
478 | {
479 | if (Size==22)
480 | {
481 | if (LastPDUType!=(byte)0xD0) // 0xD0 = CC Connection confirm
482 | LastError=errISOConnectionFailed;
483 | }
484 | else
485 | LastError=errISOInvalidPDU;
486 | }
487 | }
488 | return LastError;
489 | }
490 |
491 | private int NegotiatePduLength()
492 | {
493 | int Length;
494 | // Set PDU Size Requested
495 | S7.SetWordAt(S7_PN,23,DefaultPduSizeRequested);
496 | // Sends the connection request telegram
497 | SendPacket(S7_PN);
498 | if (LastError==0)
499 | {
500 | Length=RecvIsoPacket();
501 | if (LastError==0)
502 | {
503 | // check S7 Error
504 | if ((Length==27) && (PDU[17]==0) && (PDU[18]==0)) // 20 = size of Negotiate Answer
505 | {
506 | // Get PDU Size Negotiated
507 | _PDULength = S7.GetWordAt(PDU,25);
508 | if (_PDULength>0)
509 | return 0;
510 | else
511 | LastError=errISONegotiatingPDU;
512 | }
513 | else
514 | LastError=errISONegotiatingPDU;
515 | }
516 | }
517 | return LastError;
518 | }
519 |
520 | public void SetConnectionType(short ConnectionType)
521 | {
522 | ConnType=ConnectionType;
523 | }
524 |
525 | public int Connect()
526 | {
527 | LastError=0;
528 | if (!Connected)
529 | {
530 | TCPConnect();
531 | if (LastError==0) // First stage : TCP Connection
532 | {
533 | ISOConnect();
534 | if (LastError==0) // Second stage : ISOTCP (ISO 8073) Connection
535 | {
536 | LastError=NegotiatePduLength(); // Third stage : S7 PDU negotiation
537 | }
538 | }
539 | }
540 | Connected=LastError==0;
541 | return LastError;
542 | }
543 |
544 | public void Disconnect()
545 | {
546 | if (Connected)
547 | {
548 | try {
549 | OutStream.close();
550 | InStream.close();
551 | TCPSocket.close();
552 | _PDULength=0;
553 | } catch (IOException ex) {
554 | }
555 | Connected=false;
556 | }
557 | }
558 |
559 | public int ConnectTo(String Address, int Rack, int Slot)
560 | {
561 | int RemoteTSAP=(ConnType<<8)+ (Rack * 0x20) + Slot;
562 | SetConnectionParams(Address, 0x0100, RemoteTSAP);
563 | return Connect();
564 | }
565 |
566 | public int PDULength()
567 | {
568 | return _PDULength;
569 | }
570 |
571 | public void SetConnectionParams(String Address, int LocalTSAP, int RemoteTSAP)
572 | {
573 | int LocTSAP = LocalTSAP & 0x0000FFFF;
574 | int RemTSAP = RemoteTSAP & 0x0000FFFF;
575 | IPAddress = Address;
576 | LocalTSAP_HI = (byte) (LocTSAP>>8);
577 | LocalTSAP_LO = (byte) (LocTSAP & 0x00FF);
578 | RemoteTSAP_HI= (byte) (RemTSAP>>8);
579 | RemoteTSAP_LO= (byte) (RemTSAP & 0x00FF);
580 | }
581 |
582 | public int ReadArea(int Area, int DBNumber, int Start, int Amount, byte[] Data)
583 | {
584 | int Address;
585 | int NumElements;
586 | int MaxElements;
587 | int TotElements;
588 | int SizeRequested;
589 | int Length;
590 | int Offset = 0;
591 | int WordSize = 1;
592 |
593 | LastError=0;
594 |
595 | // If we are addressing Timers or counters the element size is 2
596 | if ((Area==S7.S7AreaCT) || (Area==S7.S7AreaTM))
597 | WordSize = 2;
598 |
599 | MaxElements=(_PDULength-18) / WordSize; // 18 = Reply telegram header
600 | TotElements=Amount;
601 |
602 | while ((TotElements>0) && (LastError==0))
603 | {
604 | NumElements=TotElements;
605 | if (NumElements>MaxElements)
606 | NumElements=MaxElements;
607 |
608 | SizeRequested = NumElements * WordSize;
609 |
610 | // Setup the telegram
611 | System.arraycopy(S7_RW, 0, PDU, 0, Size_RD);
612 | // Set DB Number
613 | PDU[27] = (byte) Area;
614 | // Set Area
615 | if (Area==S7.S7AreaDB)
616 | S7.SetWordAt(PDU,25,DBNumber);
617 |
618 | // Adjusts Start and word length
619 | if ((Area==S7.S7AreaCT) || (Area==S7.S7AreaTM))
620 | {
621 | Address = Start;
622 | if (Area==S7.S7AreaCT)
623 | PDU[22]=S7WLCounter;
624 | else
625 | PDU[22]=S7WLTimer;
626 | }
627 | else
628 | Address = Start<<3;
629 |
630 | // Num elements
631 | S7.SetWordAt(PDU,23,NumElements);
632 |
633 | // Address into the PLC (only 3 bytes)
634 | PDU[30] = (byte) (Address & 0x0FF);
635 | Address = Address >> 8;
636 | PDU[29] = (byte) (Address & 0x0FF);
637 | Address = Address >> 8;
638 | PDU[28] = (byte) (Address & 0x0FF);
639 |
640 | SendPacket(PDU, Size_RD);
641 | if (LastError==0)
642 | {
643 | Length=RecvIsoPacket();
644 | if (LastError==0)
645 | {
646 | if (Length>=25)
647 | {
648 | if ((Length-25==SizeRequested) && (PDU[21]==(byte)0xFF))
649 | {
650 | System.arraycopy(PDU, 25, Data, Offset, SizeRequested);
651 | Offset+=SizeRequested;
652 | }
653 | else
654 | LastError = errS7DataRead;
655 | }
656 | else
657 | LastError = errS7InvalidPDU;
658 | }
659 | }
660 |
661 | TotElements -= NumElements;
662 | Start += NumElements*WordSize;
663 | }
664 | return LastError;
665 | }
666 |
667 | public int WriteArea(int Area, int DBNumber, int Start, int Amount, byte[] Data)
668 | {
669 | int Address;
670 | int NumElements;
671 | int MaxElements;
672 | int TotElements;
673 | int DataSize;
674 | int IsoSize;
675 | int Length;
676 | int Offset = 0;
677 | int WordSize = 1;
678 |
679 | LastError=0;
680 |
681 | // If we are addressing Timers or counters the element size is 2
682 | if ((Area==S7.S7AreaCT) || (Area==S7.S7AreaTM))
683 | WordSize = 2;
684 |
685 | MaxElements=(_PDULength-35) / WordSize; // 18 = Reply telegram header
686 | TotElements=Amount;
687 |
688 | while ((TotElements>0) && (LastError==0))
689 | {
690 | NumElements=TotElements;
691 | if (NumElements>MaxElements)
692 | NumElements=MaxElements;
693 |
694 | DataSize = NumElements * WordSize;
695 | IsoSize = Size_WR + DataSize;
696 |
697 | // Setup the telegram
698 | System.arraycopy(S7_RW, 0, PDU, 0, Size_WR);
699 | // Whole telegram Size
700 | S7.SetWordAt(PDU,2,IsoSize);
701 | // Data Length
702 | Length=DataSize+4;
703 | S7.SetWordAt(PDU,15,Length);
704 | // Function
705 | PDU[17]= (byte) 0x05;
706 | // Set DB Number
707 | PDU[27] = (byte) Area;
708 | if (Area==S7.S7AreaDB)
709 | S7.SetWordAt(PDU,25,DBNumber);
710 |
711 | // Adjusts Start and word length
712 | if ((Area==S7.S7AreaCT) || (Area==S7.S7AreaTM))
713 | {
714 | Address = Start;
715 | Length = DataSize;
716 | if (Area==S7.S7AreaCT)
717 | PDU[22]=S7WLCounter;
718 | else
719 | PDU[22]=S7WLTimer;
720 | }
721 | else
722 | {
723 | Address = Start<<3;
724 | Length = DataSize<<3;
725 | }
726 | // Num elements
727 | S7.SetWordAt(PDU,23,NumElements);
728 | // Address into the PLC
729 | PDU[30] = (byte) (Address & 0x0FF);
730 | Address = Address >> 8;
731 | PDU[29] = (byte) (Address & 0x0FF);
732 | Address = Address >> 8;
733 | PDU[28] = (byte) (Address & 0x0FF);
734 | // Length
735 | S7.SetWordAt(PDU,33,Length);
736 |
737 | // Copies the Data
738 | System.arraycopy(Data, Offset, PDU, 35, DataSize);
739 |
740 | SendPacket(PDU, IsoSize);
741 | if (LastError==0)
742 | {
743 | Length=RecvIsoPacket();
744 | if (LastError==0)
745 | {
746 | if (Length==22)
747 | {
748 | if ((S7.GetWordAt(PDU,17)!=0) || (PDU[21]!=(byte)0xFF))
749 | LastError = errS7DataWrite;
750 | }
751 | else
752 | LastError = errS7InvalidPDU;
753 | }
754 | }
755 |
756 | Offset+=DataSize;
757 | TotElements -= NumElements;
758 | Start += NumElements*WordSize;
759 | }
760 | return LastError;
761 | }
762 |
763 | public int GetAgBlockInfo(int BlockType, int BlockNumber, S7BlockInfo Block)
764 | {
765 | int Length;
766 | LastError=0;
767 | // Block Type
768 | S7_BI[30] = (byte) BlockType;
769 | // Block Number
770 | S7_BI[31]=(byte) ((BlockNumber / 10000)+0x30);
771 | BlockNumber=BlockNumber % 10000;
772 | S7_BI[32]=(byte) ((BlockNumber / 1000)+0x30);
773 | BlockNumber=BlockNumber % 1000;
774 | S7_BI[33]=(byte) ((BlockNumber / 100)+0x30);
775 | BlockNumber=BlockNumber % 100;
776 | S7_BI[34]=(byte) ((BlockNumber / 10)+0x30);
777 | BlockNumber=BlockNumber % 10;
778 | S7_BI[35]=(byte) ((BlockNumber / 1)+0x30);
779 |
780 | SendPacket(S7_BI);
781 | if (LastError==0)
782 | {
783 | Length=RecvIsoPacket();
784 | if (Length > 32) // the minimum expected
785 | {
786 | if ((S7.GetWordAt(PDU,27)==0) && (PDU[29]==(byte)0xFF))
787 | {
788 | Block.Update(PDU, 42);
789 | }
790 | else
791 | LastError = errS7FunctionError;
792 | }
793 | else
794 | LastError = errS7InvalidPDU;
795 | }
796 |
797 | return LastError;
798 | }
799 | /**
800 | *
801 | * @param DBNumber DB Number
802 | * @param Buffer Destination buffer
803 | * @param SizeRead How many bytes were read
804 | * @return
805 | */
806 | public int DBGet(int DBNumber, byte[] Buffer, IntByRef SizeRead)
807 | {
808 | S7BlockInfo Block = new S7BlockInfo();
809 | // Query the DB Length
810 | LastError = GetAgBlockInfo(S7.Block_DB, DBNumber, Block);
811 | if (LastError==0)
812 | {
813 | int SizeToRead = Block.MC7Size();
814 | // Checks the room
815 | if (SizeToRead<=Buffer.length)
816 | {
817 | LastError=ReadArea(S7.S7AreaDB, DBNumber, 0, SizeToRead, Buffer);
818 | if (LastError==0)
819 | SizeRead.Value=SizeToRead;
820 | }
821 | else
822 | LastError=errS7BufferTooSmall;
823 | }
824 | return LastError;
825 | }
826 |
827 | public int ReadSZL(int ID, int Index, S7Szl SZL)
828 | {
829 | int Length;
830 | int DataSZL;
831 | int Offset = 0;
832 | boolean Done = false;
833 | boolean First = true;
834 | byte Seq_in =0x00;
835 | int Seq_out =0x0000;
836 |
837 | LastError=0;
838 | SZL.DataSize=0;
839 | do
840 | {
841 | if (First)
842 | {
843 | S7.SetWordAt(S7_SZL_FIRST, 11, ++Seq_out);
844 | S7.SetWordAt(S7_SZL_FIRST, 29, ID);
845 | S7.SetWordAt(S7_SZL_FIRST, 31, Index);
846 | SendPacket(S7_SZL_FIRST);
847 | }
848 | else
849 | {
850 | S7.SetWordAt(S7_SZL_NEXT, 11, ++Seq_out);
851 | PDU[24] = (byte)Seq_in;
852 | SendPacket(S7_SZL_NEXT);
853 | }
854 | if (LastError!=0)
855 | return LastError;
856 |
857 | Length=RecvIsoPacket();
858 | if (LastError==0)
859 | {
860 | if (First)
861 | {
862 | if (Length > 32) // the minimum expected
863 | {
864 | if ((S7.GetWordAt(PDU,27)==0) && (PDU[29]==(byte)0xFF))
865 | {
866 | // Gets Amount of this slice
867 | DataSZL=S7.GetWordAt(PDU,31)-8; // Skips extra params (ID, Index ...)
868 | Done=PDU[26]==0x00;
869 | Seq_in=(byte)PDU[24]; // Slice sequence
870 |
871 | SZL.LENTHDR=S7.GetWordAt(PDU, 37);
872 | SZL.N_DR=S7.GetWordAt(PDU, 39);
873 | SZL.Copy(PDU, 41, Offset, DataSZL);
874 | Offset+=DataSZL;
875 | SZL.DataSize+=DataSZL;
876 | }
877 | else
878 | LastError = errS7FunctionError;
879 | }
880 | else
881 | LastError = errS7InvalidPDU;
882 | }
883 | else
884 | {
885 | if (Length > 32) // the minimum expected
886 | {
887 | if ((S7.GetWordAt(PDU,27)==0) && (PDU[29]==(byte)0xFF))
888 | {
889 | // Gets Amount of this slice
890 | DataSZL=S7.GetWordAt(PDU,31);
891 | Done=PDU[26]==0x00;
892 | Seq_in=(byte)PDU[24]; // Slice sequence
893 | SZL.Copy(PDU, 37, Offset, DataSZL);
894 | Offset+=DataSZL;
895 | SZL.DataSize+=DataSZL;
896 | }
897 | else
898 | LastError = errS7FunctionError;
899 | }
900 | else
901 | LastError = errS7InvalidPDU;
902 | }
903 | }
904 | First=false;
905 | }
906 | while(!Done && (LastError==0));
907 |
908 | return LastError;
909 | }
910 |
911 |
912 | public int GetCpuInfo(S7CpuInfo Info)
913 | {
914 | S7Szl SZL = new S7Szl(1024);
915 |
916 | LastError = ReadSZL(0x001C, 0x0000, SZL);
917 | if (LastError==0)
918 | {
919 | Info.Update(SZL.Data, 0);
920 | }
921 | return LastError;
922 | }
923 |
924 | public int GetCpInfo(S7CpInfo Info)
925 | {
926 | S7Szl SZL = new S7Szl(1024);
927 |
928 | LastError = ReadSZL(0x0131, 0x0001, SZL);
929 | if (LastError==0)
930 | {
931 | Info.Update(SZL.Data, 0);
932 | }
933 | return LastError;
934 | }
935 |
936 | public int GetOrderCode(S7OrderCode Code)
937 | {
938 | S7Szl SZL = new S7Szl(1024);
939 |
940 | LastError = ReadSZL(0x0011, 0x0000, SZL);
941 | if (LastError==0)
942 | {
943 | Code.Update(SZL.Data, 0, SZL.DataSize);
944 | }
945 | return LastError;
946 | }
947 |
948 | public int GetPlcDateTime(Date DateTime)
949 | {
950 | int Length;
951 |
952 | LastError = 0;
953 | SendPacket(S7_GET_DT);
954 | if (LastError==0)
955 | {
956 | Length=RecvIsoPacket();
957 | if (Length > 30) // the minimum expected
958 | {
959 | if ((S7.GetWordAt(PDU,27)==0) && (PDU[29]==(byte)0xFF))
960 | {
961 | DateTime=S7.GetDateAt(PDU, 34);
962 | }
963 | else
964 | LastError = errS7FunctionError;
965 | }
966 | else
967 | LastError = errS7InvalidPDU;
968 | }
969 |
970 | return LastError;
971 | }
972 |
973 | public int SetPlcDateTime(Date DateTime)
974 | {
975 | int Length;
976 |
977 | LastError = 0;
978 | S7.SetDateAt(S7_SET_DT, 31, DateTime);
979 |
980 | SendPacket(S7_SET_DT);
981 | if (LastError==0)
982 | {
983 | Length=RecvIsoPacket();
984 | if (Length > 30) // the minimum expected
985 | {
986 | if (S7.GetWordAt(PDU,27)!=0)
987 | LastError = errS7FunctionError;
988 | }
989 | else
990 | LastError = errS7InvalidPDU;
991 | }
992 |
993 | return LastError;
994 | }
995 |
996 | public int SetPlcSystemDateTime()
997 | {
998 | return SetPlcDateTime(new Date());
999 | }
1000 |
1001 | public int PlcStop()
1002 | {
1003 | int Length;
1004 |
1005 | LastError = 0;
1006 | SendPacket(S7_STOP);
1007 | if (LastError==0)
1008 | {
1009 | Length=RecvIsoPacket();
1010 | if (Length > 18) // 18 is the minimum expected
1011 | {
1012 | if (S7.GetWordAt(PDU,17)!=0)
1013 | LastError = errS7FunctionError;
1014 | }
1015 | else
1016 | LastError = errS7InvalidPDU;
1017 | }
1018 | return LastError;
1019 | }
1020 |
1021 | public int PlcHotStart()
1022 | {
1023 | int Length;
1024 |
1025 | LastError = 0;
1026 | SendPacket(S7_HOT_START);
1027 | if (LastError==0)
1028 | {
1029 | Length=RecvIsoPacket();
1030 | if (Length > 18) // the minimum expected
1031 | {
1032 | if (S7.GetWordAt(PDU,17)!=0)
1033 | LastError = errS7FunctionError;
1034 | }
1035 | else
1036 | LastError = errS7InvalidPDU;
1037 | }
1038 | return LastError;
1039 | }
1040 |
1041 | public int PlcColdStart()
1042 | {
1043 | int Length;
1044 |
1045 | LastError = 0;
1046 | SendPacket(S7_COLD_START);
1047 | if (LastError==0)
1048 | {
1049 | Length=RecvIsoPacket();
1050 | if (Length > 18) // the minimum expected
1051 | {
1052 | if (S7.GetWordAt(PDU,17)!=0)
1053 | LastError = errS7FunctionError;
1054 | }
1055 | else
1056 | LastError = errS7InvalidPDU;
1057 | }
1058 | return LastError;
1059 | }
1060 |
1061 | public int GetPlcStatus(IntByRef Status)
1062 | {
1063 | int Length;
1064 |
1065 | LastError = 0;
1066 | SendPacket(S7_GET_STAT);
1067 | if (LastError==0)
1068 | {
1069 | Length=RecvIsoPacket();
1070 | if (Length > 30) // the minimum expected
1071 | {
1072 | if (S7.GetWordAt(PDU,27)==0)
1073 | {
1074 | switch (PDU[44])
1075 | {
1076 | case S7.S7CpuStatusUnknown :
1077 | case S7.S7CpuStatusRun :
1078 | case S7.S7CpuStatusStop : Status.Value=PDU[44];
1079 | break;
1080 | default :
1081 | // Since RUN status is always 0x08 for all CPUs and CPs, STOP status
1082 | // sometime can be coded as 0x03 (especially for old cpu...)
1083 | Status.Value=S7.S7CpuStatusStop;
1084 | }
1085 | }
1086 | else
1087 | LastError = errS7FunctionError;
1088 | }
1089 | else
1090 | LastError = errS7InvalidPDU;
1091 | }
1092 | return LastError;
1093 | }
1094 |
1095 | public int SetSessionPassword(String Password)
1096 | {
1097 | byte[] pwd = {0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20};
1098 | int Length;
1099 |
1100 | LastError = 0;
1101 | // Adjusts the Password length to 8
1102 | if (Password.length()>8)
1103 | Password=Password.substring(0, 8);
1104 | else
1105 | {
1106 | while (Password.length()<8)
1107 | Password=Password+" ";
1108 | }
1109 |
1110 | try {
1111 | pwd = Password.getBytes("UTF-8");
1112 | } catch (UnsupportedEncodingException ex) {
1113 | LastError = errS7InvalidParams;
1114 | }
1115 | if (LastError==0)
1116 | {
1117 | // Encodes the password
1118 | pwd[0]=(byte) (pwd[0] ^ 0x55);
1119 | pwd[1]=(byte) (pwd[1] ^ 0x55);
1120 | for (int c = 2; c < 8; c++)
1121 | {
1122 | pwd[c]=(byte) (pwd[c] ^ 0x55 ^ pwd[c-2]);
1123 | }
1124 | System.arraycopy(pwd, 0, S7_SET_PWD, 29, 8);
1125 | // Sends the telegrem
1126 | SendPacket(S7_SET_PWD);
1127 | if (LastError==0)
1128 | {
1129 | Length=RecvIsoPacket();
1130 | if (Length > 32) // the minimum expected
1131 | {
1132 | if (S7.GetWordAt(PDU,27)!=0)
1133 | LastError = errS7FunctionError;
1134 | }
1135 | else
1136 | LastError = errS7InvalidPDU;
1137 | }
1138 | }
1139 | return LastError;
1140 | }
1141 |
1142 | public int ClearSessionPassword()
1143 | {
1144 | int Length;
1145 |
1146 | LastError = 0;
1147 | SendPacket(S7_CLR_PWD);
1148 | if (LastError==0)
1149 | {
1150 | Length=RecvIsoPacket();
1151 | if (Length > 30) // the minimum expected
1152 | {
1153 | if (S7.GetWordAt(PDU,27)!=0)
1154 | LastError = errS7FunctionError;
1155 | }
1156 | else
1157 | LastError = errS7InvalidPDU;
1158 | }
1159 | return LastError;
1160 | }
1161 |
1162 | public int GetProtection(S7Protection Protection)
1163 | {
1164 | S7Szl SZL = new S7Szl(256);
1165 |
1166 | LastError = ReadSZL(0x0232, 0x0004, SZL);
1167 | if (LastError==0)
1168 | {
1169 | Protection.Update(SZL.Data);
1170 | }
1171 | return LastError;
1172 | }
1173 |
1174 | }
1175 |
--------------------------------------------------------------------------------