diff U3 IntByRef.java IntByRef.java --- IntByRef.java Thu Mar 23 15:34:52 2017 +++ IntByRef.java Tue Aug 08 18:53:37 2017 @@ -1,40 +1,40 @@ -/*=============================================================================| -| PROJECT Moka7 1.0.2 | -|==============================================================================| -| Copyright (C) 2013, 2016 Davide Nardella | -| All rights reserved. | -|==============================================================================| -| SNAP7 is free software: you can redistribute it and/or modify | -| it under the terms of the Lesser GNU General Public License as published by | -| the Free Software Foundation, either version 3 of the License, or under | -| EPL Eclipse Public License 1.0. | -| | -| This means that you have to chose in advance which take before you import | -| the library into your project. | -| | -| SNAP7 is distributed in the hope that it will be useful, | -| but WITHOUT ANY WARRANTY; without even the implied warranty of | -| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | -| decide to adopt. | -| | -|=============================================================================*/ - -package Moka7; - -/** - * Quick class to pass an integer by reference - * @author Davide - */ - -public class IntByRef { - - public IntByRef(int Val) - { - this.Value=Val; - } - public IntByRef() - { - this.Value=0; - } - public int Value; -} +/*=============================================================================| +| PROJECT Moka7 1.0.2 | +|==============================================================================| +| Copyright (C) 2013, 2016 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or under | +| EPL Eclipse Public License 1.0. | +| | +| This means that you have to chose in advance which take before you import | +| the library into your project. | +| | +| SNAP7 is distributed in the hope that it will be useful, | +| but WITHOUT ANY WARRANTY; without even the implied warranty of | +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | +| decide to adopt. | +| | +|=============================================================================*/ + +package Moka7; + +/** + * Quick class to pass an integer by reference + * @author Davide Nardella + */ + +public class IntByRef { + + public IntByRef(int Val) + { + this.Value=Val; + } + public IntByRef() + { + this.Value=0; + } + public int Value; +} diff U3 S7.java S7.java --- S7.java Thu Mar 23 15:34:52 2017 +++ S7.java Tue Aug 08 18:53:37 2017 @@ -1,287 +1,287 @@ -/*=============================================================================| -| PROJECT Moka7 1.0.2 | -|==============================================================================| -| Copyright (C) 2013, 2016 Davide Nardella | -| All rights reserved. | -|==============================================================================| -| SNAP7 is free software: you can redistribute it and/or modify | -| it under the terms of the Lesser GNU General Public License as published by | -| the Free Software Foundation, either version 3 of the License, or under | -| EPL Eclipse Public License 1.0. | -| | -| This means that you have to chose in advance which take before you import | -| the library into your project. | -| | -| SNAP7 is distributed in the hope that it will be useful, | -| but WITHOUT ANY WARRANTY; without even the implied warranty of | -| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | -| decide to adopt. | -| | -|=============================================================================*/ -package Moka7; - -import java.io.UnsupportedEncodingException; -import java.util.Date; -import java.util.Calendar; - -/** - * - * @author Davide - */ - - -// Step 7 Constants and Conversion helper class -public class S7 { - // S7 ID Area (Area that we want to read/write) - public static final int S7AreaPE = 0x81; - public static final int S7AreaPA = 0x82; - public static final int S7AreaMK = 0x83; - public static final int S7AreaDB = 0x84; - public static final int S7AreaCT = 0x1C; - public static final int S7AreaTM = 0x1D; - // Connection types - public static final byte PG = 0x01; - public static final byte OP = 0x02; - public static final byte S7_BASIC = 0x03; - // Block type - public static final int Block_OB = 0x38; - public static final int Block_DB = 0x41; - public static final int Block_SDB = 0x42; - public static final int Block_FC = 0x43; - public static final int Block_SFC = 0x44; - public static final int Block_FB = 0x45; - public static final int Block_SFB = 0x46; - // Sub Block Type - public static final int SubBlk_OB = 0x08; - public static final int SubBlk_DB = 0x0A; - public static final int SubBlk_SDB = 0x0B; - public static final int SubBlk_FC = 0x0C; - public static final int SubBlk_SFC = 0x0D; - public static final int SubBlk_FB = 0x0E; - public static final int SubBlk_SFB = 0x0F; - // Block languages - public static final int BlockLangAWL = 0x01; - public static final int BlockLangKOP = 0x02; - public static final int BlockLangFUP = 0x03; - public static final int BlockLangSCL = 0x04; - public static final int BlockLangDB = 0x05; - public static final int BlockLangGRAPH = 0x06; - // PLC Status - public static final int S7CpuStatusUnknown = 0x00; - public static final int S7CpuStatusRun = 0x08; - public static final int S7CpuStatusStop = 0x04; - // Type Var - public static final int S7TypeBool = 1; - public static final int S7TypeInt = 1; - - // Returns the bit at Pos.Bit - public static boolean GetBitAt(byte[] Buffer, int Pos, int Bit) - { - int Value = Buffer[Pos] & 0x0FF; - byte[] Mask = { - (byte)0x01,(byte)0x02,(byte)0x04,(byte)0x08, - (byte)0x10,(byte)0x20,(byte)0x40,(byte)0x80 - }; - if (Bit<0) Bit=0; - if (Bit>7) Bit=7; - - return (Value & Mask[Bit])!=0; - } - /** - * Returns a 16 bit unsigned value : from 0 to 65535 (2^16-1) - * @param Buffer - * @param Pos start position - * @return - */ - public static int GetWordAt(byte[] Buffer, int Pos) - { - int hi = (Buffer[Pos] & 0x00FF); - int lo = (Buffer[Pos+1] & 0x00FF); - return (hi<<8)+lo; - } - - // Returns a 16 bit signed value : from -32768 to 32767 - public static int GetShortAt(byte[] Buffer, int Pos) - { - int hi = (Buffer[Pos]); - int lo = (Buffer[Pos+1] & 0x00FF); - return ((hi<<8)+lo); - } - - // Returns a 32 bit unsigned value : from 0 to 4294967295 (2^32-1) - public static long GetDWordAt(byte[] Buffer, int Pos) - { - long Result; - Result=(long)(Buffer[Pos] & 0x0FF); - Result<<=8; - Result+=(long)(Buffer[Pos+1] & 0x0FF); - Result<<=8; - Result+=(long)(Buffer[Pos+2] & 0x0FF); - Result<<=8; - Result+=(long)(Buffer[Pos+3] & 0x0FF); - return Result; - } - - // Returns a 32 bit signed value : from 0 to 4294967295 (2^32-1) - public static int GetDIntAt(byte[] Buffer, int Pos) - { - int Result; - Result= Buffer[Pos]; - Result<<=8; - Result+=(Buffer[Pos+1] & 0x0FF); - Result<<=8; - Result+=(Buffer[Pos+2] & 0x0FF); - Result<<=8; - Result+=(Buffer[Pos+3] & 0x0FF); - return Result; - } - - // Returns a 32 bit floating point - public static float GetFloatAt(byte[] Buffer, int Pos) - { - int IntFloat = GetDIntAt(Buffer, Pos); - return Float.intBitsToFloat(IntFloat); - } - - // Returns an ASCII string - public static String GetStringAt(byte[] Buffer, int Pos, int MaxLen) - { - byte[] StrBuffer = new byte[MaxLen]; - System.arraycopy(Buffer, Pos, StrBuffer, 0, MaxLen); - String S; - try { - S = new String(StrBuffer, "UTF-8"); // the charset is UTF-8 - } catch (UnsupportedEncodingException ex) { - S = ""; - } - return S; - } - - public static String GetPrintableStringAt(byte[] Buffer, int Pos, int MaxLen) - { - byte[] StrBuffer = new byte[MaxLen]; - System.arraycopy(Buffer, Pos, StrBuffer, 0, MaxLen); - for (int c = 0; c < MaxLen; c++) - { - if ((StrBuffer[c]<31) || (StrBuffer[c]>126)) - StrBuffer[c]=46; // '.' - } - String S; - try { - S = new String(StrBuffer, "UTF-8"); // the charset is UTF-8 - } catch (UnsupportedEncodingException ex) { - S = ""; - } - return S; - } - - public static Date GetDateAt(byte[] Buffer, int Pos) - { - int Year, Month, Day, Hour, Min, Sec; - Calendar S7Date = Calendar.getInstance(); - - Year = S7.BCDtoByte(Buffer[Pos]); - if (Year<90) - Year+=2000; - else - Year+=1900; - - Month=S7.BCDtoByte(Buffer[Pos+1])-1; - Day =S7.BCDtoByte(Buffer[Pos+2]); - Hour =S7.BCDtoByte(Buffer[Pos+3]); - Min =S7.BCDtoByte(Buffer[Pos+4]); - Sec =S7.BCDtoByte(Buffer[Pos+5]); - - S7Date.set(Year, Month, Day, Hour, Min, Sec); - - return S7Date.getTime(); - } - - public static void SetBitAt(byte[] Buffer, int Pos, int Bit, boolean Value) - { - byte[] Mask = { - (byte)0x01,(byte)0x02,(byte)0x04,(byte)0x08, - (byte)0x10,(byte)0x20,(byte)0x40,(byte)0x80 - }; - if (Bit<0) Bit=0; - if (Bit>7) Bit=7; - - if (Value) - Buffer[Pos]= (byte) (Buffer[Pos] | Mask[Bit]); - else - Buffer[Pos]= (byte) (Buffer[Pos] & ~Mask[Bit]); - } - - public static void SetWordAt(byte[] Buffer, int Pos, int Value) - { - int Word = Value & 0x0FFFF; - Buffer[Pos] = (byte) (Word >> 8); - Buffer[Pos+1] = (byte) (Word & 0x00FF); - } - - public static void SetShortAt(byte[] Buffer, int Pos, int Value) - { - Buffer[Pos] = (byte) (Value >> 8); - Buffer[Pos+1] = (byte) (Value & 0x00FF); - } - public static void SetDWordAt(byte[] Buffer, int Pos, long Value) - { - long DWord = Value &0x0FFFFFFFF; - Buffer[Pos+3] = (byte) (DWord &0xFF); - Buffer[Pos+2] = (byte) ((DWord >> 8) &0xFF); - Buffer[Pos+1] = (byte) ((DWord >> 16) &0xFF); - Buffer[Pos] = (byte) ((DWord >> 24) &0xFF); - } - - public static void SetDIntAt(byte[] Buffer, int Pos, int Value) - { - Buffer[Pos+3] = (byte) (Value &0xFF); - Buffer[Pos+2] = (byte) ((Value >> 8) &0xFF); - Buffer[Pos+1] = (byte) ((Value >> 16) &0xFF); - Buffer[Pos] = (byte) ((Value >> 24) &0xFF); - } - - public static void SetFloatAt(byte[] Buffer, int Pos, float Value) - { - int DInt = Float.floatToIntBits(Value); - SetDIntAt(Buffer, Pos, DInt); - } - - public static void SetDateAt(byte[] Buffer, int Pos, Date DateTime) - { - int Year, Month, Day, Hour, Min, Sec, Dow; - Calendar S7Date = Calendar.getInstance(); - S7Date.setTime(DateTime); - - Year = S7Date.get(Calendar.YEAR); - Month = S7Date.get(Calendar.MONTH)+1; - Day = S7Date.get(Calendar.DAY_OF_MONTH); - Hour = S7Date.get(Calendar.HOUR_OF_DAY); - Min = S7Date.get(Calendar.MINUTE); - Sec = S7Date.get(Calendar.SECOND); - Dow = S7Date.get(Calendar.DAY_OF_WEEK); - - if (Year>1999) - Year-=2000; - - Buffer[Pos] =ByteToBCD(Year); - Buffer[Pos+1]=ByteToBCD(Month); - Buffer[Pos+2]=ByteToBCD(Day); - Buffer[Pos+3]=ByteToBCD(Hour); - Buffer[Pos+4]=ByteToBCD(Min); - Buffer[Pos+5]=ByteToBCD(Sec); - Buffer[Pos+6]=0; - Buffer[Pos+7]=ByteToBCD(Dow); - } - - public static int BCDtoByte(byte B) - { - return ((B >> 4) * 10) + (B & 0x0F); - } - - public static byte ByteToBCD(int Value) - { - return (byte) (((Value / 10) << 4) | (Value % 10)); - } - -} +/*=============================================================================| +| PROJECT Moka7 1.0.2 | +|==============================================================================| +| Copyright (C) 2013, 2016 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or under | +| EPL Eclipse Public License 1.0. | +| | +| This means that you have to chose in advance which take before you import | +| the library into your project. | +| | +| SNAP7 is distributed in the hope that it will be useful, | +| but WITHOUT ANY WARRANTY; without even the implied warranty of | +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | +| decide to adopt. | +| | +|=============================================================================*/ +package Moka7; + +import java.io.UnsupportedEncodingException; +import java.util.Date; +import java.util.Calendar; + +/** + * + * @author Davide Nardella + */ + + +// Step 7 Constants and Conversion helper class +public class S7 { + // S7 ID Area (Area that we want to read/write) + public static final int S7AreaPE = 0x81; + public static final int S7AreaPA = 0x82; + public static final int S7AreaMK = 0x83; + public static final int S7AreaDB = 0x84; + public static final int S7AreaCT = 0x1C; + public static final int S7AreaTM = 0x1D; + // Connection types + public static final byte PG = 0x01; + public static final byte OP = 0x02; + public static final byte S7_BASIC = 0x03; + // Block type + public static final int Block_OB = 0x38; + public static final int Block_DB = 0x41; + public static final int Block_SDB = 0x42; + public static final int Block_FC = 0x43; + public static final int Block_SFC = 0x44; + public static final int Block_FB = 0x45; + public static final int Block_SFB = 0x46; + // Sub Block Type + public static final int SubBlk_OB = 0x08; + public static final int SubBlk_DB = 0x0A; + public static final int SubBlk_SDB = 0x0B; + public static final int SubBlk_FC = 0x0C; + public static final int SubBlk_SFC = 0x0D; + public static final int SubBlk_FB = 0x0E; + public static final int SubBlk_SFB = 0x0F; + // Block languages + public static final int BlockLangAWL = 0x01; + public static final int BlockLangKOP = 0x02; + public static final int BlockLangFUP = 0x03; + public static final int BlockLangSCL = 0x04; + public static final int BlockLangDB = 0x05; + public static final int BlockLangGRAPH = 0x06; + // PLC Status + public static final int S7CpuStatusUnknown = 0x00; + public static final int S7CpuStatusRun = 0x08; + public static final int S7CpuStatusStop = 0x04; + // Type Var + public static final int S7TypeBool = 1; + public static final int S7TypeInt = 1; + + // Returns the bit at Pos.Bit + public static boolean GetBitAt(byte[] Buffer, int Pos, int Bit) + { + int Value = Buffer[Pos] & 0x0FF; + byte[] Mask = { + (byte)0x01,(byte)0x02,(byte)0x04,(byte)0x08, + (byte)0x10,(byte)0x20,(byte)0x40,(byte)0x80 + }; + if (Bit<0) Bit=0; + if (Bit>7) Bit=7; + + return (Value & Mask[Bit])!=0; + } + /** + * Returns a 16 bit unsigned value : from 0 to 65535 (2^16-1) + * @param Buffer + * @param Pos start position + * @return + */ + public static int GetWordAt(byte[] Buffer, int Pos) + { + int hi = (Buffer[Pos] & 0x00FF); + int lo = (Buffer[Pos+1] & 0x00FF); + return (hi<<8)+lo; + } + + // Returns a 16 bit signed value : from -32768 to 32767 + public static int GetShortAt(byte[] Buffer, int Pos) + { + int hi = (Buffer[Pos]); + int lo = (Buffer[Pos+1] & 0x00FF); + return ((hi<<8)+lo); + } + + // Returns a 32 bit unsigned value : from 0 to 4294967295 (2^32-1) + public static long GetDWordAt(byte[] Buffer, int Pos) + { + long Result; + Result=(long)(Buffer[Pos] & 0x0FF); + Result<<=8; + Result+=(long)(Buffer[Pos+1] & 0x0FF); + Result<<=8; + Result+=(long)(Buffer[Pos+2] & 0x0FF); + Result<<=8; + Result+=(long)(Buffer[Pos+3] & 0x0FF); + return Result; + } + + // Returns a 32 bit signed value : from 0 to 4294967295 (2^32-1) + public static int GetDIntAt(byte[] Buffer, int Pos) + { + int Result; + Result= Buffer[Pos]; + Result<<=8; + Result+=(Buffer[Pos+1] & 0x0FF); + Result<<=8; + Result+=(Buffer[Pos+2] & 0x0FF); + Result<<=8; + Result+=(Buffer[Pos+3] & 0x0FF); + return Result; + } + + // Returns a 32 bit floating point + public static float GetFloatAt(byte[] Buffer, int Pos) + { + int IntFloat = GetDIntAt(Buffer, Pos); + return Float.intBitsToFloat(IntFloat); + } + + // Returns an ASCII string + public static String GetStringAt(byte[] Buffer, int Pos, int MaxLen) + { + byte[] StrBuffer = new byte[MaxLen]; + System.arraycopy(Buffer, Pos, StrBuffer, 0, MaxLen); + String S; + try { + S = new String(StrBuffer, "UTF-8"); // the charset is UTF-8 + } catch (UnsupportedEncodingException ex) { + S = ""; + } + return S; + } + + public static String GetPrintableStringAt(byte[] Buffer, int Pos, int MaxLen) + { + byte[] StrBuffer = new byte[MaxLen]; + System.arraycopy(Buffer, Pos, StrBuffer, 0, MaxLen); + for (int c = 0; c < MaxLen; c++) + { + if ((StrBuffer[c]<31) || (StrBuffer[c]>126)) + StrBuffer[c]=46; // '.' + } + String S; + try { + S = new String(StrBuffer, "UTF-8"); // the charset is UTF-8 + } catch (UnsupportedEncodingException ex) { + S = ""; + } + return S; + } + + public static Date GetDateAt(byte[] Buffer, int Pos) + { + int Year, Month, Day, Hour, Min, Sec; + Calendar S7Date = Calendar.getInstance(); + + Year = S7.BCDtoByte(Buffer[Pos]); + if (Year<90) + Year+=2000; + else + Year+=1900; + + Month=S7.BCDtoByte(Buffer[Pos+1])-1; + Day =S7.BCDtoByte(Buffer[Pos+2]); + Hour =S7.BCDtoByte(Buffer[Pos+3]); + Min =S7.BCDtoByte(Buffer[Pos+4]); + Sec =S7.BCDtoByte(Buffer[Pos+5]); + + S7Date.set(Year, Month, Day, Hour, Min, Sec); + + return S7Date.getTime(); + } + + public static void SetBitAt(byte[] Buffer, int Pos, int Bit, boolean Value) + { + byte[] Mask = { + (byte)0x01,(byte)0x02,(byte)0x04,(byte)0x08, + (byte)0x10,(byte)0x20,(byte)0x40,(byte)0x80 + }; + if (Bit<0) Bit=0; + if (Bit>7) Bit=7; + + if (Value) + Buffer[Pos]= (byte) (Buffer[Pos] | Mask[Bit]); + else + Buffer[Pos]= (byte) (Buffer[Pos] & ~Mask[Bit]); + } + + public static void SetWordAt(byte[] Buffer, int Pos, int Value) + { + int Word = Value & 0x0FFFF; + Buffer[Pos] = (byte) (Word >> 8); + Buffer[Pos+1] = (byte) (Word & 0x00FF); + } + + public static void SetShortAt(byte[] Buffer, int Pos, int Value) + { + Buffer[Pos] = (byte) (Value >> 8); + Buffer[Pos+1] = (byte) (Value & 0x00FF); + } + public static void SetDWordAt(byte[] Buffer, int Pos, long Value) + { + long DWord = Value &0x0FFFFFFFF; + Buffer[Pos+3] = (byte) (DWord &0xFF); + Buffer[Pos+2] = (byte) ((DWord >> 8) &0xFF); + Buffer[Pos+1] = (byte) ((DWord >> 16) &0xFF); + Buffer[Pos] = (byte) ((DWord >> 24) &0xFF); + } + + public static void SetDIntAt(byte[] Buffer, int Pos, int Value) + { + Buffer[Pos+3] = (byte) (Value &0xFF); + Buffer[Pos+2] = (byte) ((Value >> 8) &0xFF); + Buffer[Pos+1] = (byte) ((Value >> 16) &0xFF); + Buffer[Pos] = (byte) ((Value >> 24) &0xFF); + } + + public static void SetFloatAt(byte[] Buffer, int Pos, float Value) + { + int DInt = Float.floatToIntBits(Value); + SetDIntAt(Buffer, Pos, DInt); + } + + public static void SetDateAt(byte[] Buffer, int Pos, Date DateTime) + { + int Year, Month, Day, Hour, Min, Sec, Dow; + Calendar S7Date = Calendar.getInstance(); + S7Date.setTime(DateTime); + + Year = S7Date.get(Calendar.YEAR); + Month = S7Date.get(Calendar.MONTH)+1; + Day = S7Date.get(Calendar.DAY_OF_MONTH); + Hour = S7Date.get(Calendar.HOUR_OF_DAY); + Min = S7Date.get(Calendar.MINUTE); + Sec = S7Date.get(Calendar.SECOND); + Dow = S7Date.get(Calendar.DAY_OF_WEEK); + + if (Year>1999) + Year-=2000; + + Buffer[Pos] =ByteToBCD(Year); + Buffer[Pos+1]=ByteToBCD(Month); + Buffer[Pos+2]=ByteToBCD(Day); + Buffer[Pos+3]=ByteToBCD(Hour); + Buffer[Pos+4]=ByteToBCD(Min); + Buffer[Pos+5]=ByteToBCD(Sec); + Buffer[Pos+6]=0; + Buffer[Pos+7]=ByteToBCD(Dow); + } + + public static int BCDtoByte(byte B) + { + return ((B >> 4) * 10) + (B & 0x0F); + } + + public static byte ByteToBCD(int Value) + { + return (byte) (((Value / 10) << 4) | (Value % 10)); + } + +} diff U3 S7BlockInfo.java S7BlockInfo.java --- S7BlockInfo.java Thu Mar 23 15:34:52 2017 +++ S7BlockInfo.java Tue Aug 08 18:53:37 2017 @@ -1,101 +1,101 @@ -/*=============================================================================| -| PROJECT Moka7 1.0.2 | -|==============================================================================| -| Copyright (C) 2013, 2016 Davide Nardella | -| All rights reserved. | -|==============================================================================| -| SNAP7 is free software: you can redistribute it and/or modify | -| it under the terms of the Lesser GNU General Public License as published by | -| the Free Software Foundation, either version 3 of the License, or under | -| EPL Eclipse Public License 1.0. | -| | -| This means that you have to chose in advance which take before you import | -| the library into your project. | -| | -| SNAP7 is distributed in the hope that it will be useful, | -| but WITHOUT ANY WARRANTY; without even the implied warranty of | -| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | -| decide to adopt. | -| | -|=============================================================================*/ -package Moka7; -import java.util.Date; -/** - * - * @author Davide - */ -public class S7BlockInfo { - - private final int BufSize = 96; - // MilliSeconds between 1970/1/1 (Java time base) and 1984/1/1 (Siemens base) - private final long DeltaMilliSecs = 441763200000L; - protected byte[] Buffer = new byte[BufSize]; - - protected void Update(byte[] Src, int Pos) - { - System.arraycopy(Src, Pos, Buffer, 0, BufSize); - } - public int BlkType() - { - return Buffer[2]; - } - public int BlkNumber() - { - return S7.GetWordAt(Buffer, 3); - } - public int BlkLang() - { - return Buffer[1]; - } - public int BlkFlags() - { - return Buffer[0]; - } - public int MC7Size() // The real size in bytes - { - return S7.GetWordAt(Buffer, 31); - } - public int LoadSize() - { - return S7.GetDIntAt(Buffer, 5); - } - public int LocalData() - { - return S7.GetWordAt(Buffer, 29); - } - public int SBBLength() - { - return S7.GetWordAt(Buffer, 25); - } - public int Checksum() - { - return S7.GetWordAt(Buffer, 59); - } - public int Version() - { - return Buffer[57]; - } - public Date CodeDate() - { - long BlockDate = ((long)S7.GetWordAt(Buffer, 17))*86400000L+DeltaMilliSecs; - return new Date(BlockDate); - } - public Date IntfDate() - { - long BlockDate = ((long)S7.GetWordAt(Buffer, 23))*86400000L+DeltaMilliSecs; - return new Date(BlockDate); - } - public String Author() - { - return S7.GetStringAt(Buffer,33,8); - } - public String Family() - { - return S7.GetStringAt(Buffer,41,8); - } - public String Header() - { - return S7.GetStringAt(Buffer,49,8); - } - -} +/*=============================================================================| +| PROJECT Moka7 1.0.2 | +|==============================================================================| +| Copyright (C) 2013, 2016 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or under | +| EPL Eclipse Public License 1.0. | +| | +| This means that you have to chose in advance which take before you import | +| the library into your project. | +| | +| SNAP7 is distributed in the hope that it will be useful, | +| but WITHOUT ANY WARRANTY; without even the implied warranty of | +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | +| decide to adopt. | +| | +|=============================================================================*/ +package Moka7; +import java.util.Date; +/** + * + * @author Davide Nardella + */ +public class S7BlockInfo { + + private final int BufSize = 96; + // MilliSeconds between 1970/1/1 (Java time base) and 1984/1/1 (Siemens base) + private final long DeltaMilliSecs = 441763200000L; + protected byte[] Buffer = new byte[BufSize]; + + protected void Update(byte[] Src, int Pos) + { + System.arraycopy(Src, Pos, Buffer, 0, BufSize); + } + public int BlkType() + { + return Buffer[2]; + } + public int BlkNumber() + { + return S7.GetWordAt(Buffer, 3); + } + public int BlkLang() + { + return Buffer[1]; + } + public int BlkFlags() + { + return Buffer[0]; + } + public int MC7Size() // The real size in bytes + { + return S7.GetWordAt(Buffer, 31); + } + public int LoadSize() + { + return S7.GetDIntAt(Buffer, 5); + } + public int LocalData() + { + return S7.GetWordAt(Buffer, 29); + } + public int SBBLength() + { + return S7.GetWordAt(Buffer, 25); + } + public int Checksum() + { + return S7.GetWordAt(Buffer, 59); + } + public int Version() + { + return Buffer[57]; + } + public Date CodeDate() + { + long BlockDate = ((long)S7.GetWordAt(Buffer, 17))*86400000L+DeltaMilliSecs; + return new Date(BlockDate); + } + public Date IntfDate() + { + long BlockDate = ((long)S7.GetWordAt(Buffer, 23))*86400000L+DeltaMilliSecs; + return new Date(BlockDate); + } + public String Author() + { + return S7.GetStringAt(Buffer,33,8); + } + public String Family() + { + return S7.GetStringAt(Buffer,41,8); + } + public String Header() + { + return S7.GetStringAt(Buffer,49,8); + } + +} diff U3 S7Client.java S7Client.java --- S7Client.java Thu Mar 23 15:34:52 2017 +++ S7Client.java Tue Aug 08 18:53:37 2017 @@ -1,1214 +1,1233 @@ -/*=============================================================================| -| PROJECT Moka7 1.0.2 | -|==============================================================================| -| Copyright (C) 2013, 2016 Davide Nardella | -| All rights reserved. | -|==============================================================================| -| SNAP7 is free software: you can redistribute it and/or modify | -| it under the terms of the Lesser GNU General Public License as published by | -| the Free Software Foundation, either version 3 of the License, or under | -| EPL Eclipse Public License 1.0. | -| | -| This means that you have to chose in advance which take before you import | -| the library into your project. | -| | -| SNAP7 is distributed in the hope that it will be useful, | -| but WITHOUT ANY WARRANTY; without even the implied warranty of | -| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | -| decide to adopt. | -| | -|=============================================================================*/ -package Moka7; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketAddress; -import java.util.Date; - - -/** - * - * @author Dave Nardella - */ -public class S7Client -{ - // WordLength - private static final byte S7WLByte =0x02; - private static final byte S7WLCounter =0x1C; - private static final byte S7WLTimer =0x1D; - // Error Codes - public static final int errTCPConnectionFailed = 0x0001; - public static final int errTCPDataSend = 0x0002; - public static final int errTCPDataRecv = 0x0003; - public static final int errTCPDataRecvTout = 0x0004; - public static final int errTCPConnectionReset = 0x0005; - public static final int errISOInvalidPDU = 0x0006; - public static final int errISOConnectionFailed = 0x0007; - public static final int errISONegotiatingPDU = 0x0008; - public static final int errS7InvalidPDU = 0x0009; - public static final int errS7DataRead = 0x000A; - public static final int errS7DataWrite = 0x000B; - public static final int errS7BufferTooSmall = 0x000C; - public static final int errS7FunctionError = 0x000D; - public static final int errS7InvalidParams = 0x000E; - - // Public fields - public boolean Connected = false; - public int LastError = 0; - public int RecvTimeout = 2000; - - // Privates - private static final int ISOTCP = 102; // ISOTCP Port - private static final int MinPduSize = 16; - private static final int DefaultPduSizeRequested = 480; - private static final int IsoHSize = 7; // TPKT+COTP Header Size - private static final int MaxPduSize = DefaultPduSizeRequested+IsoHSize; - - - private Socket TCPSocket; - private final byte[] PDU = new byte[2048]; - - private DataInputStream InStream = null; - private DataOutputStream OutStream = null; - - private String IPAddress; - - private byte LocalTSAP_HI; - private byte LocalTSAP_LO; - private byte RemoteTSAP_HI; - private byte RemoteTSAP_LO; - private byte LastPDUType; - - private short ConnType = S7.PG; - private int _PDULength = 0; - - // Telegrams - // ISO Connection Request telegram (contains also ISO Header and COTP Header) - private static final byte ISO_CR[] = { - // TPKT (RFC1006 Header) - (byte)0x03, // RFC 1006 ID (3) - (byte)0x00, // Reserved, always 0 - (byte)0x00, // High part of packet lenght (entire frame, payload and TPDU included) - (byte)0x16, // Low part of packet lenght (entire frame, payload and TPDU included) - // COTP (ISO 8073 Header) - (byte)0x11, // PDU Size Length - (byte)0xE0, // CR - Connection Request ID - (byte)0x00, // Dst Reference HI - (byte)0x00, // Dst Reference LO - (byte)0x00, // Src Reference HI - (byte)0x01, // Src Reference LO - (byte)0x00, // Class + Options Flags - (byte)0xC0, // PDU Max Length ID - (byte)0x01, // PDU Max Length HI - (byte)0x0A, // PDU Max Length LO - (byte)0xC1, // Src TSAP Identifier - (byte)0x02, // Src TSAP Length (2 bytes) - (byte)0x01, // Src TSAP HI (will be overwritten) - (byte)0x00, // Src TSAP LO (will be overwritten) - (byte)0xC2, // Dst TSAP Identifier - (byte)0x02, // Dst TSAP Length (2 bytes) - (byte)0x01, // Dst TSAP HI (will be overwritten) - (byte)0x02 // Dst TSAP LO (will be overwritten) - }; - - // S7 PDU Negotiation Telegram (contains also ISO Header and COTP Header) - private static final byte S7_PN[] = { - (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x19, - (byte)0x02, (byte)0xf0, (byte)0x80, // TPKT + COTP (see above for info) - (byte)0x32, (byte)0x01, (byte)0x00, (byte)0x00, - (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x08, - (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0x00, - (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x01, - (byte)0x00, (byte)0x1e // PDU Length Requested = HI-LO 480 bytes - }; - - // S7 Read/Write Request Header (contains also ISO Header and COTP Header) - private static final byte S7_RW[] = { // 31-35 bytes - (byte)0x03,(byte)0x00, - (byte)0x00,(byte)0x1f, // Telegram Length (Data Size + 31 or 35) - (byte)0x02,(byte)0xf0, (byte)0x80, // COTP (see above for info) - (byte)0x32, // S7 Protocol ID - (byte)0x01, // Job Type - (byte)0x00,(byte)0x00, // Redundancy identification - (byte)0x05,(byte)0x00, // PDU Reference - (byte)0x00,(byte)0x0e, // Parameters Length - (byte)0x00,(byte)0x00, // Data Length = Size(bytes) + 4 - (byte)0x04, // Function 4 Read Var, 5 Write Var - (byte)0x01, // Items count - (byte)0x12, // Var spec. - (byte)0x0a, // Length of remaining bytes - (byte)0x10, // Syntax ID - S7WLByte, // Transport Size - (byte)0x00,(byte)0x00, // Num Elements - (byte)0x00,(byte)0x00, // DB Number (if any, else 0) - (byte)0x84, // Area Type - (byte)0x00,(byte)0x00,(byte)0x00, // Area Offset - // WR area - (byte)0x00, // Reserved - (byte)0x04, // Transport size - (byte)0x00,(byte)0x00, // Data Length * 8 (if not timer or counter) - }; - private static final int Size_RD = 31; - private static final int Size_WR = 35; - - // S7 Get Block Info Request Header (contains also ISO Header and COTP Header) - private static final byte S7_BI[] = { - (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x25, - (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, - (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x05, - (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, - (byte)0x0c, (byte)0x00, (byte)0x01, (byte)0x12, - (byte)0x04, (byte)0x11, (byte)0x43, (byte)0x03, - (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00, - (byte)0x08, (byte)0x30, - (byte)0x41, // Block Type - (byte)0x30, (byte)0x30, (byte)0x30, (byte)0x30, (byte)0x30, // ASCII Block Number - (byte)0x41 - }; - - // SZL First telegram request - private static final byte S7_SZL_FIRST[] = { - (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x21, - (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, - (byte)0x07, (byte)0x00, (byte)0x00, - (byte)0x05, (byte)0x00, // Sequence out - (byte)0x00, (byte)0x08, (byte)0x00, - (byte)0x08, (byte)0x00, (byte)0x01, (byte)0x12, - (byte)0x04, (byte)0x11, (byte)0x44, (byte)0x01, - (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00, - (byte)0x04, - (byte)0x00, (byte)0x00, // ID (29) - (byte)0x00, (byte)0x00 // Index (31) - }; - - // SZL Next telegram request - private static final byte S7_SZL_NEXT[] = { - (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x21, - (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, - (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x06, - (byte)0x00, (byte)0x00, (byte)0x0c, (byte)0x00, - (byte)0x04, (byte)0x00, (byte)0x01, (byte)0x12, - (byte)0x08, (byte)0x12, (byte)0x44, (byte)0x01, - (byte)0x01, // Sequence - (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, - (byte)0x0a, (byte)0x00, (byte)0x00, (byte)0x00 - }; - - // Get Date/Time request - private static final byte S7_GET_DT[] = { - (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x1d, - (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, - (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x38, - (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, - (byte)0x04, (byte)0x00, (byte)0x01, (byte)0x12, - (byte)0x04, (byte)0x11, (byte)0x47, (byte)0x01, - (byte)0x00, (byte)0x0a, (byte)0x00, (byte)0x00, - (byte)0x00 - }; - - // Set Date/Time command - private static final byte S7_SET_DT[] = { - (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x27, - (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, - (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x89, - (byte)0x03, (byte)0x00, (byte)0x08, (byte)0x00, - (byte)0x0e, (byte)0x00, (byte)0x01, (byte)0x12, - (byte)0x04, (byte)0x11, (byte)0x47, (byte)0x02, - (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00, - (byte)0x0a, (byte)0x00, (byte)0x19, // Hi part of Year - (byte)0x13, // Lo part of Year - (byte)0x12, // Month - (byte)0x06, // Day - (byte)0x17, // Hour - (byte)0x37, // Min - (byte)0x13, // Sec - (byte)0x00, (byte)0x01 // ms + Day of week - }; - - // S7 STOP request - private static final byte S7_STOP[] = { - (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x21, - (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, - (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x0e, - (byte)0x00, (byte)0x00, (byte)0x10, (byte)0x00, - (byte)0x00, (byte)0x29, (byte)0x00, (byte)0x00, - (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x09, - (byte)0x50, (byte)0x5f, (byte)0x50, (byte)0x52, - (byte)0x4f, (byte)0x47, (byte)0x52, (byte)0x41, - (byte)0x4d - }; - - // S7 HOT Start request - private static final byte S7_HOT_START[] = { - (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x25, - (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, - (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x0c, - (byte)0x00, (byte)0x00, (byte)0x14, (byte)0x00, - (byte)0x00, (byte)0x28, (byte)0x00, (byte)0x00, - (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, - (byte)0xfd, (byte)0x00, (byte)0x00, (byte)0x09, - (byte)0x50, (byte)0x5f, (byte)0x50, (byte)0x52, - (byte)0x4f, (byte)0x47, (byte)0x52, (byte)0x41, - (byte)0x4d - }; - - // S7 COLD Start request - private static final byte S7_COLD_START[] = { - (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x27, - (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, - (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x0f, - (byte)0x00, (byte)0x00, (byte)0x16, (byte)0x00, - (byte)0x00, (byte)0x28, (byte)0x00, (byte)0x00, - (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, - (byte)0xfd, (byte)0x00, (byte)0x02, (byte)0x43, - (byte)0x20, (byte)0x09, (byte)0x50, (byte)0x5f, - (byte)0x50, (byte)0x52, (byte)0x4f, (byte)0x47, - (byte)0x52, (byte)0x41, (byte)0x4d - }; - - // S7 Get PLC Status - private static final byte S7_GET_STAT[] = { - (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x21, - (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, - (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x2c, - (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, - (byte)0x08, (byte)0x00, (byte)0x01, (byte)0x12, - (byte)0x04, (byte)0x11, (byte)0x44, (byte)0x01, - (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00, - (byte)0x04, (byte)0x04, (byte)0x24, (byte)0x00, - (byte)0x00 - }; - - // S7 Set Session Password - private static final byte S7_SET_PWD[] = { - (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x25, - (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, - (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x27, - (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, - (byte)0x0c, (byte)0x00, (byte)0x01, (byte)0x12, - (byte)0x04, (byte)0x11, (byte)0x45, (byte)0x01, - (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00, - (byte)0x08, - // 8 Char Encoded Password - (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, - (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 - }; - - // S7 Clear Session Password - private static final byte S7_CLR_PWD[] = { - (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x1d, - (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, - (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x29, - (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, - (byte)0x04, (byte)0x00, (byte)0x01, (byte)0x12, - (byte)0x04, (byte)0x11, (byte)0x45, (byte)0x02, - (byte)0x00, (byte)0x0a, (byte)0x00, (byte)0x00, - (byte)0x00 - }; - - public S7Client() - { - // Placeholder for future implementations - } - - public static String ErrorText(int Error) - { - switch (Error) - { - case errTCPConnectionFailed : - return "TCP Connection failed."; - case errTCPDataSend : - return "TCP Sending error."; - case errTCPDataRecv : - return "TCP Receiving error."; - case errTCPDataRecvTout : - return "Data Receiving timeout."; - case errTCPConnectionReset : - return "Connection reset by the peer."; - case errISOInvalidPDU : - return "Invalid ISO PDU received."; - case errISOConnectionFailed : - return "ISO connection refused by the CPU."; - case errISONegotiatingPDU : - return "ISO error negotiating the PDU length."; - case errS7InvalidPDU : - return "Invalid S7 PDU received."; - case errS7DataRead : - return "S7 Error reading data from the CPU."; - case errS7DataWrite : - return "S7 Error writing data to the CPU."; - case errS7BufferTooSmall : - return "The Buffer supplied to the function is too small."; - case errS7FunctionError : - return "S7 function refused by the CPU."; - case errS7InvalidParams : - return "Invalid parameters supplied to the function."; - default : - return "Unknown error : 0x"+Integer.toHexString(Error); - } - } - - private int TCPConnect() - { - SocketAddress sockaddr = new InetSocketAddress(IPAddress, ISOTCP); - LastError=0; - try { - TCPSocket = new Socket(); - TCPSocket.connect(sockaddr ,5000); - TCPSocket.setTcpNoDelay(true); - InStream = new DataInputStream(TCPSocket.getInputStream()); - OutStream = new DataOutputStream(TCPSocket.getOutputStream()); - } - catch (IOException e) { - LastError=errTCPConnectionFailed; - } - return LastError; - } - - private int WaitForData(int Size, int Timeout) - { - int cnt = 0; - LastError=0; - int SizeAvail; - boolean Expired = false; - try - { - SizeAvail=InStream.available(); - while ((SizeAvailTimeout; - // If timeout we clean the buffer - if (Expired && (SizeAvail>0) && (LastError==0)) - InStream.read(PDU, 0, SizeAvail); - } - } - catch (IOException ex) - { - LastError=errTCPDataRecvTout; - } - if (cnt>=Timeout) - { - LastError=errTCPDataRecvTout; - } - return LastError; - } - - private int RecvPacket(byte[] Buffer, int Start, int Size) - { - int BytesRead=0; - LastError=WaitForData(Size,RecvTimeout); - if (LastError==0) - { - try { - BytesRead = InStream.read(Buffer, Start, Size); - } catch (IOException ex) { - LastError=errTCPDataRecv; - } - if (BytesRead==0) - LastError=errTCPConnectionReset; - } - return LastError; - } - - private void SendPacket(byte[] Buffer, int Len) - { - LastError = 0; - try { - OutStream.write(Buffer,0,Len); - OutStream.flush(); - } catch (IOException ex) { - LastError = errTCPDataSend; - } - } - private void SendPacket(byte[] Buffer) - { - SendPacket(Buffer,Buffer.length); - } - - private int RecvIsoPacket() - { - Boolean Done = false; - int Size = 0; - while ((LastError==0) && !Done) - { - // Get TPKT (4 bytes) - RecvPacket(PDU, 0, 4); - if (LastError==0) - { - Size=S7.GetWordAt(PDU,2); - // Check 0 bytes Data Packet (only TPKT+COTP = 7 bytes) - if (Size==IsoHSize) - RecvPacket(PDU,4, 3); // Skip remaining 3 bytes and Done is still false - else - { - if ((Size>MaxPduSize) || (Size16 && <247 - } - } - } - if (LastError==0) - { - RecvPacket(PDU,4, 3); // Skip remaining 3 COTP bytes - LastPDUType=PDU[5]; // Stores PDU Type, we need it - // Receives the S7 Payload - RecvPacket(PDU, 7, Size-IsoHSize); - } - if (LastError==0) - return Size; - else - return 0; - } - - private int ISOConnect() - { - int Size; - ISO_CR[16]=LocalTSAP_HI; - ISO_CR[17]=LocalTSAP_LO; - ISO_CR[20]=RemoteTSAP_HI; - ISO_CR[21]=RemoteTSAP_LO; - - // Sends the connection request telegram - SendPacket(ISO_CR); - if (LastError==0) - { - // Gets the reply (if any) - Size=RecvIsoPacket(); - if (LastError==0) - { - if (Size==22) - { - if (LastPDUType!=(byte)0xD0) // 0xD0 = CC Connection confirm - LastError=errISOConnectionFailed; - } - else - LastError=errISOInvalidPDU; - } - } - return LastError; - } - - private int NegotiatePduLength() - { - int Length; - // Set PDU Size Requested - S7.SetWordAt(S7_PN,23,DefaultPduSizeRequested); - // Sends the connection request telegram - SendPacket(S7_PN); - if (LastError==0) - { - Length=RecvIsoPacket(); - if (LastError==0) - { - // check S7 Error - if ((Length==27) && (PDU[17]==0) && (PDU[18]==0)) // 20 = size of Negotiate Answer - { - // Get PDU Size Negotiated - _PDULength = S7.GetWordAt(PDU,25); - if (_PDULength>0) - return 0; - else - LastError=errISONegotiatingPDU; - } - else - LastError=errISONegotiatingPDU; - } - } - return LastError; - } - - public void SetConnectionType(short ConnectionType) - { - ConnType=ConnectionType; - } - - public int Connect() - { - LastError=0; - if (!Connected) - { - TCPConnect(); - if (LastError==0) // First stage : TCP Connection - { - ISOConnect(); - if (LastError==0) // Second stage : ISOTCP (ISO 8073) Connection - { - LastError=NegotiatePduLength(); // Third stage : S7 PDU negotiation - } - } - } - Connected=LastError==0; - - // In case the connection is not completely established (TCP connection + ISO connection + PDU negotiation) - // we close the socket and its IO streams to revert the object back to pre-Connect() state - if (!Connected) - { - if (TCPSocket != null) { - try { - TCPSocket.close(); - } catch (IOException ex) { - } - } - if (InStream != null) { - try { - InStream.close(); - } catch (IOException ex) { - } - } - if (OutStream != null) { - try { - OutStream.close(); - } catch (IOException ex) { - } - } - _PDULength = 0; - } - - return LastError; - } - - public void Disconnect() - { - if (Connected) - { - try { - OutStream.close(); - InStream.close(); - TCPSocket.close(); - _PDULength=0; - } catch (IOException ex) { - } - Connected=false; - } - } - - public int ConnectTo(String Address, int Rack, int Slot) - { - int RemoteTSAP=(ConnType<<8)+ (Rack * 0x20) + Slot; - SetConnectionParams(Address, 0x0100, RemoteTSAP); - return Connect(); - } - - public int PDULength() - { - return _PDULength; - } - - public void SetConnectionParams(String Address, int LocalTSAP, int RemoteTSAP) - { - int LocTSAP = LocalTSAP & 0x0000FFFF; - int RemTSAP = RemoteTSAP & 0x0000FFFF; - IPAddress = Address; - LocalTSAP_HI = (byte) (LocTSAP>>8); - LocalTSAP_LO = (byte) (LocTSAP & 0x00FF); - RemoteTSAP_HI= (byte) (RemTSAP>>8); - RemoteTSAP_LO= (byte) (RemTSAP & 0x00FF); - } - - public int ReadArea(int Area, int DBNumber, int Start, int Amount, byte[] Data) - { - int Address; - int NumElements; - int MaxElements; - int TotElements; - int SizeRequested; - int Length; - int Offset = 0; - int WordSize = 1; - - LastError=0; - - // If we are addressing Timers or counters the element size is 2 - if ((Area==S7.S7AreaCT) || (Area==S7.S7AreaTM)) - WordSize = 2; - - MaxElements=(_PDULength-18) / WordSize; // 18 = Reply telegram header - TotElements=Amount; - - while ((TotElements>0) && (LastError==0)) - { - NumElements=TotElements; - if (NumElements>MaxElements) - NumElements=MaxElements; - - SizeRequested = NumElements * WordSize; - - // Setup the telegram - System.arraycopy(S7_RW, 0, PDU, 0, Size_RD); - // Set DB Number - PDU[27] = (byte) Area; - // Set Area - if (Area==S7.S7AreaDB) - S7.SetWordAt(PDU,25,DBNumber); - - // Adjusts Start and word length - if ((Area==S7.S7AreaCT) || (Area==S7.S7AreaTM)) - { - Address = Start; - if (Area==S7.S7AreaCT) - PDU[22]=S7WLCounter; - else - PDU[22]=S7WLTimer; - } - else - Address = Start<<3; - - // Num elements - S7.SetWordAt(PDU,23,NumElements); - - // Address into the PLC (only 3 bytes) - PDU[30] = (byte) (Address & 0x0FF); - Address = Address >> 8; - PDU[29] = (byte) (Address & 0x0FF); - Address = Address >> 8; - PDU[28] = (byte) (Address & 0x0FF); - - SendPacket(PDU, Size_RD); - if (LastError==0) - { - Length=RecvIsoPacket(); - if (LastError==0) - { - if (Length>=25) - { - if ((Length-25==SizeRequested) && (PDU[21]==(byte)0xFF)) - { - System.arraycopy(PDU, 25, Data, Offset, SizeRequested); - Offset+=SizeRequested; - } - else - LastError = errS7DataRead; - } - else - LastError = errS7InvalidPDU; - } - } - - TotElements -= NumElements; - Start += NumElements*WordSize; - } - return LastError; - } - - public int WriteArea(int Area, int DBNumber, int Start, int Amount, byte[] Data) - { - int Address; - int NumElements; - int MaxElements; - int TotElements; - int DataSize; - int IsoSize; - int Length; - int Offset = 0; - int WordSize = 1; - - LastError=0; - - // If we are addressing Timers or counters the element size is 2 - if ((Area==S7.S7AreaCT) || (Area==S7.S7AreaTM)) - WordSize = 2; - - MaxElements=(_PDULength-35) / WordSize; // 18 = Reply telegram header - TotElements=Amount; - - while ((TotElements>0) && (LastError==0)) - { - NumElements=TotElements; - if (NumElements>MaxElements) - NumElements=MaxElements; - - DataSize = NumElements * WordSize; - IsoSize = Size_WR + DataSize; - - // Setup the telegram - System.arraycopy(S7_RW, 0, PDU, 0, Size_WR); - // Whole telegram Size - S7.SetWordAt(PDU,2,IsoSize); - // Data Length - Length=DataSize+4; - S7.SetWordAt(PDU,15,Length); - // Function - PDU[17]= (byte) 0x05; - // Set DB Number - PDU[27] = (byte) Area; - if (Area==S7.S7AreaDB) - S7.SetWordAt(PDU,25,DBNumber); - - // Adjusts Start and word length - if ((Area==S7.S7AreaCT) || (Area==S7.S7AreaTM)) - { - Address = Start; - Length = DataSize; - if (Area==S7.S7AreaCT) - PDU[22]=S7WLCounter; - else - PDU[22]=S7WLTimer; - } - else - { - Address = Start<<3; - Length = DataSize<<3; - } - // Num elements - S7.SetWordAt(PDU,23,NumElements); - // Address into the PLC - PDU[30] = (byte) (Address & 0x0FF); - Address = Address >> 8; - PDU[29] = (byte) (Address & 0x0FF); - Address = Address >> 8; - PDU[28] = (byte) (Address & 0x0FF); - // Length - S7.SetWordAt(PDU,33,Length); - - // Copies the Data - System.arraycopy(Data, Offset, PDU, 35, DataSize); - - SendPacket(PDU, IsoSize); - if (LastError==0) - { - Length=RecvIsoPacket(); - if (LastError==0) - { - if (Length==22) - { - if ((S7.GetWordAt(PDU,17)!=0) || (PDU[21]!=(byte)0xFF)) - LastError = errS7DataWrite; - } - else - LastError = errS7InvalidPDU; - } - } - - Offset+=DataSize; - TotElements -= NumElements; - Start += NumElements*WordSize; - } - return LastError; - } - - public int GetAgBlockInfo(int BlockType, int BlockNumber, S7BlockInfo Block) - { - int Length; - LastError=0; - // Block Type - S7_BI[30] = (byte) BlockType; - // Block Number - S7_BI[31]=(byte) ((BlockNumber / 10000)+0x30); - BlockNumber=BlockNumber % 10000; - S7_BI[32]=(byte) ((BlockNumber / 1000)+0x30); - BlockNumber=BlockNumber % 1000; - S7_BI[33]=(byte) ((BlockNumber / 100)+0x30); - BlockNumber=BlockNumber % 100; - S7_BI[34]=(byte) ((BlockNumber / 10)+0x30); - BlockNumber=BlockNumber % 10; - S7_BI[35]=(byte) ((BlockNumber / 1)+0x30); - - SendPacket(S7_BI); - if (LastError==0) - { - Length=RecvIsoPacket(); - if (Length > 32) // the minimum expected - { - if ((S7.GetWordAt(PDU,27)==0) && (PDU[29]==(byte)0xFF)) - { - Block.Update(PDU, 42); - } - else - LastError = errS7FunctionError; - } - else - LastError = errS7InvalidPDU; - } - - return LastError; - } - /** - * - * @param DBNumber DB Number - * @param Buffer Destination buffer - * @param SizeRead How many bytes were read - * @return - */ - public int DBGet(int DBNumber, byte[] Buffer, IntByRef SizeRead) - { - S7BlockInfo Block = new S7BlockInfo(); - // Query the DB Length - LastError = GetAgBlockInfo(S7.Block_DB, DBNumber, Block); - if (LastError==0) - { - int SizeToRead = Block.MC7Size(); - // Checks the room - if (SizeToRead<=Buffer.length) - { - LastError=ReadArea(S7.S7AreaDB, DBNumber, 0, SizeToRead, Buffer); - if (LastError==0) - SizeRead.Value=SizeToRead; - } - else - LastError=errS7BufferTooSmall; - } - return LastError; - } - - public int ReadSZL(int ID, int Index, S7Szl SZL) - { - int Length; - int DataSZL; - int Offset = 0; - boolean Done = false; - boolean First = true; - byte Seq_in =0x00; - int Seq_out =0x0000; - - LastError=0; - SZL.DataSize=0; - do - { - if (First) - { - S7.SetWordAt(S7_SZL_FIRST, 11, ++Seq_out); - S7.SetWordAt(S7_SZL_FIRST, 29, ID); - S7.SetWordAt(S7_SZL_FIRST, 31, Index); - SendPacket(S7_SZL_FIRST); - } - else - { - S7.SetWordAt(S7_SZL_NEXT, 11, ++Seq_out); - PDU[24] = (byte)Seq_in; - SendPacket(S7_SZL_NEXT); - } - if (LastError!=0) - return LastError; - - Length=RecvIsoPacket(); - if (LastError==0) - { - if (First) - { - if (Length > 32) // the minimum expected - { - if ((S7.GetWordAt(PDU,27)==0) && (PDU[29]==(byte)0xFF)) - { - // Gets Amount of this slice - DataSZL=S7.GetWordAt(PDU,31)-8; // Skips extra params (ID, Index ...) - Done=PDU[26]==0x00; - Seq_in=(byte)PDU[24]; // Slice sequence - - SZL.LENTHDR=S7.GetWordAt(PDU, 37); - SZL.N_DR=S7.GetWordAt(PDU, 39); - SZL.Copy(PDU, 41, Offset, DataSZL); - Offset+=DataSZL; - SZL.DataSize+=DataSZL; - } - else - LastError = errS7FunctionError; - } - else - LastError = errS7InvalidPDU; - } - else - { - if (Length > 32) // the minimum expected - { - if ((S7.GetWordAt(PDU,27)==0) && (PDU[29]==(byte)0xFF)) - { - // Gets Amount of this slice - DataSZL=S7.GetWordAt(PDU,31); - Done=PDU[26]==0x00; - Seq_in=(byte)PDU[24]; // Slice sequence - SZL.Copy(PDU, 37, Offset, DataSZL); - Offset+=DataSZL; - SZL.DataSize+=DataSZL; - } - else - LastError = errS7FunctionError; - } - else - LastError = errS7InvalidPDU; - } - } - First=false; - } - while(!Done && (LastError==0)); - - return LastError; - } - - - public int GetCpuInfo(S7CpuInfo Info) - { - S7Szl SZL = new S7Szl(1024); - - LastError = ReadSZL(0x001C, 0x0000, SZL); - if (LastError==0) - { - Info.Update(SZL.Data, 0); - } - return LastError; - } - - public int GetCpInfo(S7CpInfo Info) - { - S7Szl SZL = new S7Szl(1024); - - LastError = ReadSZL(0x0131, 0x0001, SZL); - if (LastError==0) - { - Info.Update(SZL.Data, 0); - } - return LastError; - } - - public int GetOrderCode(S7OrderCode Code) - { - S7Szl SZL = new S7Szl(1024); - - LastError = ReadSZL(0x0011, 0x0000, SZL); - if (LastError==0) - { - Code.Update(SZL.Data, 0, SZL.DataSize); - } - return LastError; - } - - public int GetPlcDateTime(Date DateTime) - { - int Length; - - LastError = 0; - SendPacket(S7_GET_DT); - if (LastError==0) - { - Length=RecvIsoPacket(); - if (Length > 30) // the minimum expected - { - if ((S7.GetWordAt(PDU,27)==0) && (PDU[29]==(byte)0xFF)) - { - DateTime=S7.GetDateAt(PDU, 34); - } - else - LastError = errS7FunctionError; - } - else - LastError = errS7InvalidPDU; - } - - return LastError; - } - - public int SetPlcDateTime(Date DateTime) - { - int Length; - - LastError = 0; - S7.SetDateAt(S7_SET_DT, 31, DateTime); - - SendPacket(S7_SET_DT); - if (LastError==0) - { - Length=RecvIsoPacket(); - if (Length > 30) // the minimum expected - { - if (S7.GetWordAt(PDU,27)!=0) - LastError = errS7FunctionError; - } - else - LastError = errS7InvalidPDU; - } - - return LastError; - } - - public int SetPlcSystemDateTime() - { - return SetPlcDateTime(new Date()); - } - - public int PlcStop() - { - int Length; - - LastError = 0; - SendPacket(S7_STOP); - if (LastError==0) - { - Length=RecvIsoPacket(); - if (Length > 18) // 18 is the minimum expected - { - if (S7.GetWordAt(PDU,17)!=0) - LastError = errS7FunctionError; - } - else - LastError = errS7InvalidPDU; - } - return LastError; - } - - public int PlcHotStart() - { - int Length; - - LastError = 0; - SendPacket(S7_HOT_START); - if (LastError==0) - { - Length=RecvIsoPacket(); - if (Length > 18) // the minimum expected - { - if (S7.GetWordAt(PDU,17)!=0) - LastError = errS7FunctionError; - } - else - LastError = errS7InvalidPDU; - } - return LastError; - } - - public int PlcColdStart() - { - int Length; - - LastError = 0; - SendPacket(S7_COLD_START); - if (LastError==0) - { - Length=RecvIsoPacket(); - if (Length > 18) // the minimum expected - { - if (S7.GetWordAt(PDU,17)!=0) - LastError = errS7FunctionError; - } - else - LastError = errS7InvalidPDU; - } - return LastError; - } - - public int GetPlcStatus(IntByRef Status) - { - int Length; - - LastError = 0; - SendPacket(S7_GET_STAT); - if (LastError==0) - { - Length=RecvIsoPacket(); - if (Length > 30) // the minimum expected - { - if (S7.GetWordAt(PDU,27)==0) - { - switch (PDU[44]) - { - case S7.S7CpuStatusUnknown : - case S7.S7CpuStatusRun : - case S7.S7CpuStatusStop : Status.Value=PDU[44]; - break; - default : - // Since RUN status is always 0x08 for all CPUs and CPs, STOP status - // sometime can be coded as 0x03 (especially for old cpu...) - Status.Value=S7.S7CpuStatusStop; - } - } - else - LastError = errS7FunctionError; - } - else - LastError = errS7InvalidPDU; - } - return LastError; - } - - public int SetSessionPassword(String Password) - { - byte[] pwd = {0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20}; - int Length; - - LastError = 0; - // Adjusts the Password length to 8 - if (Password.length()>8) - Password=Password.substring(0, 8); - else - { - while (Password.length()<8) - Password=Password+" "; - } - - try { - pwd = Password.getBytes("UTF-8"); - } catch (UnsupportedEncodingException ex) { - LastError = errS7InvalidParams; - } - if (LastError==0) - { - // Encodes the password - pwd[0]=(byte) (pwd[0] ^ 0x55); - pwd[1]=(byte) (pwd[1] ^ 0x55); - for (int c = 2; c < 8; c++) - { - pwd[c]=(byte) (pwd[c] ^ 0x55 ^ pwd[c-2]); - } - System.arraycopy(pwd, 0, S7_SET_PWD, 29, 8); - // Sends the telegrem - SendPacket(S7_SET_PWD); - if (LastError==0) - { - Length=RecvIsoPacket(); - if (Length > 32) // the minimum expected - { - if (S7.GetWordAt(PDU,27)!=0) - LastError = errS7FunctionError; - } - else - LastError = errS7InvalidPDU; - } - } - return LastError; - } - - public int ClearSessionPassword() - { - int Length; - - LastError = 0; - SendPacket(S7_CLR_PWD); - if (LastError==0) - { - Length=RecvIsoPacket(); - if (Length > 30) // the minimum expected - { - if (S7.GetWordAt(PDU,27)!=0) - LastError = errS7FunctionError; - } - else - LastError = errS7InvalidPDU; - } - return LastError; - } - - public int GetProtection(S7Protection Protection) - { - S7Szl SZL = new S7Szl(256); - - LastError = ReadSZL(0x0232, 0x0004, SZL); - if (LastError==0) - { - Protection.Update(SZL.Data); - } - return LastError; - } - -} +/*=============================================================================| +| PROJECT Moka7 1.0.2 | +|==============================================================================| +| Copyright (C) 2013, 2016 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or under | +| EPL Eclipse Public License 1.0. | +| | +| This means that you have to chose in advance which take before you import | +| the library into your project. | +| | +| SNAP7 is distributed in the hope that it will be useful, | +| but WITHOUT ANY WARRANTY; without even the implied warranty of | +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | +| decide to adopt. | +| | +|=============================================================================*/ +package Moka7; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.util.Date; + + +/** + * + * @author Davide Nardella + */ +public class S7Client +{ + // WordLength + public static final int S7WLBit = 0x01; + public static final int S7WLByte = 0x02; + public static final int S7WLCounter = 0x1C; + public static final int S7WLTimer = 0x1D; + + // Error Codes + public static final int errTCPConnectionFailed = 0x0001; + public static final int errTCPDataSend = 0x0002; + public static final int errTCPDataRecv = 0x0003; + public static final int errTCPDataRecvTout = 0x0004; + public static final int errTCPConnectionReset = 0x0005; + public static final int errISOInvalidPDU = 0x0006; + public static final int errISOConnectionFailed = 0x0007; + public static final int errISONegotiatingPDU = 0x0008; + public static final int errS7InvalidPDU = 0x0009; + public static final int errS7DataRead = 0x000A; + public static final int errS7DataWrite = 0x000B; + public static final int errS7BufferTooSmall = 0x000C; + public static final int errS7FunctionError = 0x000D; + public static final int errS7InvalidParams = 0x000E; + + // Public fields + public boolean Connected = false; + public int LastError = 0; + public int RecvTimeout = 2000; + + // Privates + private static final int ISOTCP = 102; // ISOTCP Port + private static final int MinPduSize = 16; + private static final int DefaultPduSizeRequested = 480; + private static final int IsoHSize = 7; // TPKT+COTP Header Size + private static final int MaxPduSize = DefaultPduSizeRequested+IsoHSize; + + private Socket TCPSocket; + private final byte[] PDU = new byte[2048]; + + private DataInputStream InStream = null; + private DataOutputStream OutStream = null; + + private String IPAddress; + + private byte LocalTSAP_HI; + private byte LocalTSAP_LO; + private byte RemoteTSAP_HI; + private byte RemoteTSAP_LO; + private byte LastPDUType; + + private short ConnType = S7.PG; + private int _PDULength = 0; + + // Telegrams + // ISO Connection Request telegram (contains also ISO Header and COTP Header) + private static final byte ISO_CR[] = { + // TPKT (RFC1006 Header) + (byte)0x03, // RFC 1006 ID (3) + (byte)0x00, // Reserved, always 0 + (byte)0x00, // High part of packet lenght (entire frame, payload and TPDU included) + (byte)0x16, // Low part of packet lenght (entire frame, payload and TPDU included) + // COTP (ISO 8073 Header) + (byte)0x11, // PDU Size Length + (byte)0xE0, // CR - Connection Request ID + (byte)0x00, // Dst Reference HI + (byte)0x00, // Dst Reference LO + (byte)0x00, // Src Reference HI + (byte)0x01, // Src Reference LO + (byte)0x00, // Class + Options Flags + (byte)0xC0, // PDU Max Length ID + (byte)0x01, // PDU Max Length HI + (byte)0x0A, // PDU Max Length LO + (byte)0xC1, // Src TSAP Identifier + (byte)0x02, // Src TSAP Length (2 bytes) + (byte)0x01, // Src TSAP HI (will be overwritten) + (byte)0x00, // Src TSAP LO (will be overwritten) + (byte)0xC2, // Dst TSAP Identifier + (byte)0x02, // Dst TSAP Length (2 bytes) + (byte)0x01, // Dst TSAP HI (will be overwritten) + (byte)0x02 // Dst TSAP LO (will be overwritten) + }; + + // S7 PDU Negotiation Telegram (contains also ISO Header and COTP Header) + private static final byte S7_PN[] = { + (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x19, + (byte)0x02, (byte)0xf0, (byte)0x80, // TPKT + COTP (see above for info) + (byte)0x32, (byte)0x01, (byte)0x00, (byte)0x00, + (byte)0x04, (byte)0x00, (byte)0x00, (byte)0x08, + (byte)0x00, (byte)0x00, (byte)0xf0, (byte)0x00, + (byte)0x00, (byte)0x01, (byte)0x00, (byte)0x01, + (byte)0x00, (byte)0x1e // PDU Length Requested = HI-LO 480 bytes + }; + + // S7 Read/Write Request Header (contains also ISO Header and COTP Header) + private static final byte S7_RW[] = { // 31-35 bytes + (byte)0x03,(byte)0x00, + (byte)0x00,(byte)0x1f, // Telegram Length (Data Size + 31 or 35) + (byte)0x02,(byte)0xf0, (byte)0x80, // COTP (see above for info) + (byte)0x32, // S7 Protocol ID + (byte)0x01, // Job Type + (byte)0x00,(byte)0x00, // Redundancy identification + (byte)0x05,(byte)0x00, // PDU Reference + (byte)0x00,(byte)0x0e, // Parameters Length + (byte)0x00,(byte)0x00, // Data Length = Size(bytes) + 4 + (byte)0x04, // Function 4 Read Var, 5 Write Var + (byte)0x01, // Items count + (byte)0x12, // Var spec. + (byte)0x0a, // Length of remaining bytes + (byte)0x10, // Syntax ID + S7WLByte, // Transport Size + (byte)0x00,(byte)0x00, // Num Elements + (byte)0x00,(byte)0x00, // DB Number (if any, else 0) + (byte)0x84, // Area Type + (byte)0x00,(byte)0x00,(byte)0x00, // Area Offset + // WR area + (byte)0x00, // Reserved + (byte)0x04, // Transport size + (byte)0x00,(byte)0x00, // Data Length * 8 (if not timer or counter) + }; + private static final int Size_RD = 31; + private static final int Size_WR = 35; + + // S7 Get Block Info Request Header (contains also ISO Header and COTP Header) + private static final byte S7_BI[] = { + (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x25, + (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, + (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x05, + (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, + (byte)0x0c, (byte)0x00, (byte)0x01, (byte)0x12, + (byte)0x04, (byte)0x11, (byte)0x43, (byte)0x03, + (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00, + (byte)0x08, (byte)0x30, + (byte)0x41, // Block Type + (byte)0x30, (byte)0x30, (byte)0x30, (byte)0x30, (byte)0x30, // ASCII Block Number + (byte)0x41 + }; + + // SZL First telegram request + private static final byte S7_SZL_FIRST[] = { + (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x21, + (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, + (byte)0x07, (byte)0x00, (byte)0x00, + (byte)0x05, (byte)0x00, // Sequence out + (byte)0x00, (byte)0x08, (byte)0x00, + (byte)0x08, (byte)0x00, (byte)0x01, (byte)0x12, + (byte)0x04, (byte)0x11, (byte)0x44, (byte)0x01, + (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00, + (byte)0x04, + (byte)0x00, (byte)0x00, // ID (29) + (byte)0x00, (byte)0x00 // Index (31) + }; + + // SZL Next telegram request + private static final byte S7_SZL_NEXT[] = { + (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x21, + (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, + (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x06, + (byte)0x00, (byte)0x00, (byte)0x0c, (byte)0x00, + (byte)0x04, (byte)0x00, (byte)0x01, (byte)0x12, + (byte)0x08, (byte)0x12, (byte)0x44, (byte)0x01, + (byte)0x01, // Sequence + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x0a, (byte)0x00, (byte)0x00, (byte)0x00 + }; + + // Get Date/Time request + private static final byte S7_GET_DT[] = { + (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x1d, + (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, + (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x38, + (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, + (byte)0x04, (byte)0x00, (byte)0x01, (byte)0x12, + (byte)0x04, (byte)0x11, (byte)0x47, (byte)0x01, + (byte)0x00, (byte)0x0a, (byte)0x00, (byte)0x00, + (byte)0x00 + }; + + // Set Date/Time command + private static final byte S7_SET_DT[] = { + (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x27, + (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, + (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x89, + (byte)0x03, (byte)0x00, (byte)0x08, (byte)0x00, + (byte)0x0e, (byte)0x00, (byte)0x01, (byte)0x12, + (byte)0x04, (byte)0x11, (byte)0x47, (byte)0x02, + (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00, + (byte)0x0a, (byte)0x00, (byte)0x19, // Hi part of Year + (byte)0x13, // Lo part of Year + (byte)0x12, // Month + (byte)0x06, // Day + (byte)0x17, // Hour + (byte)0x37, // Min + (byte)0x13, // Sec + (byte)0x00, (byte)0x01 // ms + Day of week + }; + + // S7 STOP request + private static final byte S7_STOP[] = { + (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x21, + (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, + (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x0e, + (byte)0x00, (byte)0x00, (byte)0x10, (byte)0x00, + (byte)0x00, (byte)0x29, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x09, + (byte)0x50, (byte)0x5f, (byte)0x50, (byte)0x52, + (byte)0x4f, (byte)0x47, (byte)0x52, (byte)0x41, + (byte)0x4d + }; + + // S7 HOT Start request + private static final byte S7_HOT_START[] = { + (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x25, + (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, + (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x0c, + (byte)0x00, (byte)0x00, (byte)0x14, (byte)0x00, + (byte)0x00, (byte)0x28, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0xfd, (byte)0x00, (byte)0x00, (byte)0x09, + (byte)0x50, (byte)0x5f, (byte)0x50, (byte)0x52, + (byte)0x4f, (byte)0x47, (byte)0x52, (byte)0x41, + (byte)0x4d + }; + + // S7 COLD Start request + private static final byte S7_COLD_START[] = { + (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x27, + (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, + (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x0f, + (byte)0x00, (byte)0x00, (byte)0x16, (byte)0x00, + (byte)0x00, (byte)0x28, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0xfd, (byte)0x00, (byte)0x02, (byte)0x43, + (byte)0x20, (byte)0x09, (byte)0x50, (byte)0x5f, + (byte)0x50, (byte)0x52, (byte)0x4f, (byte)0x47, + (byte)0x52, (byte)0x41, (byte)0x4d + }; + + // S7 Get PLC Status + private static final byte S7_GET_STAT[] = { + (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x21, + (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, + (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x2c, + (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, + (byte)0x08, (byte)0x00, (byte)0x01, (byte)0x12, + (byte)0x04, (byte)0x11, (byte)0x44, (byte)0x01, + (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00, + (byte)0x04, (byte)0x04, (byte)0x24, (byte)0x00, + (byte)0x00 + }; + + // S7 Set Session Password + private static final byte S7_SET_PWD[] = { + (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x25, + (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, + (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x27, + (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, + (byte)0x0c, (byte)0x00, (byte)0x01, (byte)0x12, + (byte)0x04, (byte)0x11, (byte)0x45, (byte)0x01, + (byte)0x00, (byte)0xff, (byte)0x09, (byte)0x00, + (byte)0x08, + // 8 Char Encoded Password + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, + (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00 + }; + + // S7 Clear Session Password + private static final byte S7_CLR_PWD[] = { + (byte)0x03, (byte)0x00, (byte)0x00, (byte)0x1d, + (byte)0x02, (byte)0xf0, (byte)0x80, (byte)0x32, + (byte)0x07, (byte)0x00, (byte)0x00, (byte)0x29, + (byte)0x00, (byte)0x00, (byte)0x08, (byte)0x00, + (byte)0x04, (byte)0x00, (byte)0x01, (byte)0x12, + (byte)0x04, (byte)0x11, (byte)0x45, (byte)0x02, + (byte)0x00, (byte)0x0a, (byte)0x00, (byte)0x00, + (byte)0x00 + }; + + public S7Client() + { + // Placeholder for future implementations + } + + public static String ErrorText(int Error) + { + switch (Error) + { + case errTCPConnectionFailed : + return "TCP Connection failed."; + case errTCPDataSend : + return "TCP Sending error."; + case errTCPDataRecv : + return "TCP Receiving error."; + case errTCPDataRecvTout : + return "Data Receiving timeout."; + case errTCPConnectionReset : + return "Connection reset by the peer."; + case errISOInvalidPDU : + return "Invalid ISO PDU received."; + case errISOConnectionFailed : + return "ISO connection refused by the CPU."; + case errISONegotiatingPDU : + return "ISO error negotiating the PDU length."; + case errS7InvalidPDU : + return "Invalid S7 PDU received."; + case errS7DataRead : + return "S7 Error reading data from the CPU."; + case errS7DataWrite : + return "S7 Error writing data to the CPU."; + case errS7BufferTooSmall : + return "The Buffer supplied to the function is too small."; + case errS7FunctionError : + return "S7 function refused by the CPU."; + case errS7InvalidParams : + return "Invalid parameters supplied to the function."; + default : + return "Unknown error : 0x"+Integer.toHexString(Error); + } + } + + private int TCPConnect() + { + SocketAddress sockaddr = new InetSocketAddress(IPAddress, ISOTCP); + LastError=0; + try { + TCPSocket = new Socket(); + TCPSocket.connect(sockaddr ,5000); + TCPSocket.setTcpNoDelay(true); + InStream = new DataInputStream(TCPSocket.getInputStream()); + OutStream = new DataOutputStream(TCPSocket.getOutputStream()); + } + catch (IOException e) { + LastError=errTCPConnectionFailed; + } + return LastError; + } + + private int WaitForData(int Size, int Timeout) + { + int cnt = 0; + LastError=0; + int SizeAvail; + boolean Expired = false; + try + { + SizeAvail=InStream.available(); + while ((SizeAvailTimeout; + // If timeout we clean the buffer + if (Expired && (SizeAvail>0) && (LastError==0)) + InStream.read(PDU, 0, SizeAvail); + } + } + catch (IOException ex) + { + LastError=errTCPDataRecvTout; + } + if (cnt>=Timeout) + { + LastError=errTCPDataRecvTout; + } + return LastError; + } + + private int RecvPacket(byte[] Buffer, int Start, int Size) + { + int BytesRead=0; + LastError=WaitForData(Size,RecvTimeout); + if (LastError==0) + { + try { + BytesRead = InStream.read(Buffer, Start, Size); + } catch (IOException ex) { + LastError=errTCPDataRecv; + } + if (BytesRead==0) + LastError=errTCPConnectionReset; + } + return LastError; + } + + private void SendPacket(byte[] Buffer, int Len) + { + LastError = 0; + try { + OutStream.write(Buffer,0,Len); + OutStream.flush(); + } catch (IOException ex) { + LastError = errTCPDataSend; + } + } + private void SendPacket(byte[] Buffer) + { + SendPacket(Buffer,Buffer.length); + } + + private int RecvIsoPacket() + { + Boolean Done = false; + int Size = 0; + while ((LastError==0) && !Done) + { + // Get TPKT (4 bytes) + RecvPacket(PDU, 0, 4); + if (LastError==0) + { + Size=S7.GetWordAt(PDU,2); + // Check 0 bytes Data Packet (only TPKT+COTP = 7 bytes) + if (Size==IsoHSize) + RecvPacket(PDU,4, 3); // Skip remaining 3 bytes and Done is still false + else + { + if ((Size>MaxPduSize) || (Size16 && <247 + } + } + } + if (LastError==0) + { + RecvPacket(PDU,4, 3); // Skip remaining 3 COTP bytes + LastPDUType=PDU[5]; // Stores PDU Type, we need it + // Receives the S7 Payload + RecvPacket(PDU, 7, Size-IsoHSize); + } + if (LastError==0) + return Size; + else + return 0; + } + + private int ISOConnect() + { + int Size; + ISO_CR[16]=LocalTSAP_HI; + ISO_CR[17]=LocalTSAP_LO; + ISO_CR[20]=RemoteTSAP_HI; + ISO_CR[21]=RemoteTSAP_LO; + + // Sends the connection request telegram + SendPacket(ISO_CR); + if (LastError==0) + { + // Gets the reply (if any) + Size=RecvIsoPacket(); + if (LastError==0) + { + if (Size==22) + { + if (LastPDUType!=(byte)0xD0) // 0xD0 = CC Connection confirm + LastError=errISOConnectionFailed; + } + else + LastError=errISOInvalidPDU; + } + } + return LastError; + } + + private int NegotiatePduLength() + { + int Length; + // Set PDU Size Requested + S7.SetWordAt(S7_PN,23,DefaultPduSizeRequested); + // Sends the connection request telegram + SendPacket(S7_PN); + if (LastError==0) + { + Length=RecvIsoPacket(); + if (LastError==0) + { + // check S7 Error + if ((Length==27) && (PDU[17]==0) && (PDU[18]==0)) // 20 = size of Negotiate Answer + { + // Get PDU Size Negotiated + _PDULength = S7.GetWordAt(PDU,25); + if (_PDULength>0) + return 0; + else + LastError=errISONegotiatingPDU; + } + else + LastError=errISONegotiatingPDU; + } + } + return LastError; + } + + public void SetConnectionType(short ConnectionType) + { + ConnType=ConnectionType; + } + + public int Connect() + { + LastError=0; + if (!Connected) + { + TCPConnect(); + if (LastError==0) // First stage : TCP Connection + { + ISOConnect(); + if (LastError==0) // Second stage : ISOTCP (ISO 8073) Connection + { + LastError=NegotiatePduLength(); // Third stage : S7 PDU negotiation + } + } + } + Connected=LastError==0; + + // In case the connection is not completely established (TCP connection + ISO connection + PDU negotiation) + // we close the socket and its IO streams to revert the object back to pre-Connect() state + if (!Connected) + { + if (TCPSocket != null) { + try { + TCPSocket.close(); + } catch (IOException ex) { + } + } + if (InStream != null) { + try { + InStream.close(); + } catch (IOException ex) { + } + } + if (OutStream != null) { + try { + OutStream.close(); + } catch (IOException ex) { + } + } + _PDULength = 0; + } + + return LastError; + } + + public void Disconnect() + { + if (Connected) + { + try { + OutStream.close(); + InStream.close(); + TCPSocket.close(); + _PDULength=0; + } catch (IOException ex) { + } + Connected=false; + } + } + + public int ConnectTo(String Address, int Rack, int Slot) + { + int RemoteTSAP=(ConnType<<8)+ (Rack * 0x20) + Slot; + SetConnectionParams(Address, 0x0100, RemoteTSAP); + return Connect(); + } + + public int PDULength() + { + return _PDULength; + } + + public void SetConnectionParams(String Address, int LocalTSAP, int RemoteTSAP) + { + int LocTSAP = LocalTSAP & 0x0000FFFF; + int RemTSAP = RemoteTSAP & 0x0000FFFF; + IPAddress = Address; + LocalTSAP_HI = (byte) (LocTSAP>>8); + LocalTSAP_LO = (byte) (LocTSAP & 0x00FF); + RemoteTSAP_HI= (byte) (RemTSAP>>8); + RemoteTSAP_LO= (byte) (RemTSAP & 0x00FF); + } + + public int ReadArea(int Area, int DBNumber, int Start, int Amount, int WordLength, byte[] Data) + { + int Address; + int NumElements; + int MaxElements; + int TotElements; + int SizeRequested; + int Length; + int Offset = 0; + byte WordSize = 1; + + LastError=0; + + // If we are addressing Timers or counters the element size is 2 + if ((Area==S7.S7AreaCT) || (Area==S7.S7AreaTM)) + WordSize = 2; + + MaxElements=(_PDULength-18) / WordSize; // 18 = Reply telegram header + TotElements=Amount; + + while ((TotElements>0) && (LastError==0)) + { + NumElements=TotElements; + if (NumElements>MaxElements) + NumElements=MaxElements; + + SizeRequested = NumElements * WordSize; + + // Setup the telegram + System.arraycopy(S7_RW, 0, PDU, 0, Size_RD); + // Set DB Number + PDU[27] = (byte) Area; + // Set Area + if (Area==S7.S7AreaDB) + S7.SetWordAt(PDU,25,DBNumber); + + PDU[22] = (byte) WordLength; + // Adjusts Start and word length + if ((WordLength==S7WLBit) || (WordLength==S7WLTimer) || (WordLength==S7WLCounter)) + { + Address = Start; + } + else + { + Address = Start<<3; + } + + // Num elements + S7.SetWordAt(PDU,23,NumElements); + + // Address into the PLC (only 3 bytes) + PDU[30] = (byte) (Address & 0x0FF); + Address = Address >> 8; + PDU[29] = (byte) (Address & 0x0FF); + Address = Address >> 8; + PDU[28] = (byte) (Address & 0x0FF); + + // Transport Size + PDU[32] = 0x04; + if (WordLength==S7WLBit) + { + PDU[32] = 0x03; + } + else if ((WordLength==S7WLTimer) || (WordLength==S7WLCounter)) + { + PDU[32] = 0x09; + } + + SendPacket(PDU, Size_RD); + if (LastError==0) + { + Length=RecvIsoPacket(); + if (LastError==0) + { + if (Length>=25) + { + if ((Length-25==SizeRequested) && (PDU[21]==(byte)0xFF)) + { + System.arraycopy(PDU, 25, Data, Offset, SizeRequested); + Offset+=SizeRequested; + } + else + LastError = errS7DataRead; + } + else + LastError = errS7InvalidPDU; + } + } + + TotElements -= NumElements; + Start += NumElements*WordSize; + } + return LastError; + } + + public int WriteArea(int Area, int DBNumber, int Start, int Amount, int WordLength, byte[] Data) + { + int Address; + int NumElements; + int MaxElements; + int TotElements; + int DataSize; + int IsoSize; + int Length; + int Offset = 0; + byte WordSize = 1; + + LastError=0; + + // If we are addressing Timers or counters the element size is 2 + if ((Area==S7.S7AreaCT) || (Area==S7.S7AreaTM)) + WordSize = 2; + + MaxElements=(_PDULength-35) / WordSize; // 35 = Reply telegram header + TotElements=Amount; + + while ((TotElements>0) && (LastError==0)) + { + NumElements=TotElements; + if (NumElements>MaxElements) + NumElements=MaxElements; + + DataSize = NumElements * WordSize; + IsoSize = Size_WR + DataSize; + + // Setup the telegram + System.arraycopy(S7_RW, 0, PDU, 0, Size_WR); + // Whole telegram Size + S7.SetWordAt(PDU,2,IsoSize); + // Data Length + Length=DataSize+4; + S7.SetWordAt(PDU,15,Length); + // Function + PDU[17]= (byte) 0x05; + // Set DB Number + PDU[27] = (byte) Area; + if (Area==S7.S7AreaDB) + S7.SetWordAt(PDU,25,DBNumber); + + PDU[22] = (byte) WordLength; + // Adjusts Start and word length + if ((WordLength==S7WLBit) || (WordLength==S7WLTimer) || (WordLength==S7WLCounter)) + { + Address = Start; + Length = DataSize; + } + else + { + Address = Start<<3; + Length = DataSize<<3; + } + + // Num elements + S7.SetWordAt(PDU,23,NumElements); + // Address into the PLC + PDU[30] = (byte) (Address & 0x0FF); + Address = Address >> 8; + PDU[29] = (byte) (Address & 0x0FF); + Address = Address >> 8; + PDU[28] = (byte) (Address & 0x0FF); + + // Transport Size + PDU[32] = 0x04; + if (WordLength==S7WLBit) + { + PDU[32] = 0x03; + } + else if ((WordLength==S7WLTimer) || (WordLength==S7WLCounter)) + { + PDU[32] = 0x09; + } + + // Length + S7.SetWordAt(PDU,33,Length); + + // Copies the Data + System.arraycopy(Data, Offset, PDU, 35, DataSize); + + SendPacket(PDU, IsoSize); + if (LastError==0) + { + Length=RecvIsoPacket(); + if (LastError==0) + { + if (Length==22) + { + if ((S7.GetWordAt(PDU,17)!=0) || (PDU[21]!=(byte)0xFF)) + LastError = errS7DataWrite; + } + else + LastError = errS7InvalidPDU; + } + } + + Offset+=DataSize; + TotElements -= NumElements; + Start += NumElements*WordSize; + } + return LastError; + } + + public int GetAgBlockInfo(int BlockType, int BlockNumber, S7BlockInfo Block) + { + int Length; + LastError=0; + // Block Type + S7_BI[30] = (byte) BlockType; + // Block Number + S7_BI[31]=(byte) ((BlockNumber / 10000)+0x30); + BlockNumber=BlockNumber % 10000; + S7_BI[32]=(byte) ((BlockNumber / 1000)+0x30); + BlockNumber=BlockNumber % 1000; + S7_BI[33]=(byte) ((BlockNumber / 100)+0x30); + BlockNumber=BlockNumber % 100; + S7_BI[34]=(byte) ((BlockNumber / 10)+0x30); + BlockNumber=BlockNumber % 10; + S7_BI[35]=(byte) ((BlockNumber / 1)+0x30); + + SendPacket(S7_BI); + if (LastError==0) + { + Length=RecvIsoPacket(); + if (Length > 32) // the minimum expected + { + if ((S7.GetWordAt(PDU,27)==0) && (PDU[29]==(byte)0xFF)) + { + Block.Update(PDU, 42); + } + else + LastError = errS7FunctionError; + } + else + LastError = errS7InvalidPDU; + } + + return LastError; + } + /** + * + * @param DBNumber DB Number + * @param Buffer Destination buffer + * @param SizeRead How many bytes were read + * @return + */ + public int DBGet(int DBNumber, byte[] Buffer, IntByRef SizeRead) + { + S7BlockInfo Block = new S7BlockInfo(); + // Query the DB Length + LastError = GetAgBlockInfo(S7.Block_DB, DBNumber, Block); + if (LastError==0) + { + int SizeToRead = Block.MC7Size(); + // Checks the room + if (SizeToRead<=Buffer.length) + { + LastError=ReadArea(S7.S7AreaDB, DBNumber, 0, SizeToRead, S7WLByte, Buffer); + if (LastError==0) + SizeRead.Value=SizeToRead; + } + else + LastError=errS7BufferTooSmall; + } + return LastError; + } + + public int ReadSZL(int ID, int Index, S7Szl SZL) + { + int Length; + int DataSZL; + int Offset = 0; + boolean Done = false; + boolean First = true; + byte Seq_in =0x00; + int Seq_out =0x0000; + + LastError=0; + SZL.DataSize=0; + do + { + if (First) + { + S7.SetWordAt(S7_SZL_FIRST, 11, ++Seq_out); + S7.SetWordAt(S7_SZL_FIRST, 29, ID); + S7.SetWordAt(S7_SZL_FIRST, 31, Index); + SendPacket(S7_SZL_FIRST); + } + else + { + S7.SetWordAt(S7_SZL_NEXT, 11, ++Seq_out); + PDU[24] = (byte)Seq_in; + SendPacket(S7_SZL_NEXT); + } + if (LastError!=0) + return LastError; + + Length=RecvIsoPacket(); + if (LastError==0) + { + if (First) + { + if (Length > 32) // the minimum expected + { + if ((S7.GetWordAt(PDU,27)==0) && (PDU[29]==(byte)0xFF)) + { + // Gets Amount of this slice + DataSZL=S7.GetWordAt(PDU,31)-8; // Skips extra params (ID, Index ...) + Done=PDU[26]==0x00; + Seq_in=(byte)PDU[24]; // Slice sequence + + SZL.LENTHDR=S7.GetWordAt(PDU, 37); + SZL.N_DR=S7.GetWordAt(PDU, 39); + SZL.Copy(PDU, 41, Offset, DataSZL); + Offset+=DataSZL; + SZL.DataSize+=DataSZL; + } + else + LastError = errS7FunctionError; + } + else + LastError = errS7InvalidPDU; + } + else + { + if (Length > 32) // the minimum expected + { + if ((S7.GetWordAt(PDU,27)==0) && (PDU[29]==(byte)0xFF)) + { + // Gets Amount of this slice + DataSZL=S7.GetWordAt(PDU,31); + Done=PDU[26]==0x00; + Seq_in=(byte)PDU[24]; // Slice sequence + SZL.Copy(PDU, 37, Offset, DataSZL); + Offset+=DataSZL; + SZL.DataSize+=DataSZL; + } + else + LastError = errS7FunctionError; + } + else + LastError = errS7InvalidPDU; + } + } + First=false; + } + while(!Done && (LastError==0)); + + return LastError; + } + + public int GetCpuInfo(S7CpuInfo Info) + { + S7Szl SZL = new S7Szl(1024); + + LastError = ReadSZL(0x001C, 0x0000, SZL); + if (LastError==0) + { + Info.Update(SZL.Data, 0); + } + return LastError; + } + + public int GetCpInfo(S7CpInfo Info) + { + S7Szl SZL = new S7Szl(1024); + + LastError = ReadSZL(0x0131, 0x0001, SZL); + if (LastError==0) + { + Info.Update(SZL.Data, 0); + } + return LastError; + } + + public int GetOrderCode(S7OrderCode Code) + { + S7Szl SZL = new S7Szl(1024); + + LastError = ReadSZL(0x0011, 0x0000, SZL); + if (LastError==0) + { + Code.Update(SZL.Data, 0, SZL.DataSize); + } + return LastError; + } + + public int GetPlcDateTime(Date DateTime) + { + int Length; + + LastError = 0; + SendPacket(S7_GET_DT); + if (LastError==0) + { + Length=RecvIsoPacket(); + if (Length > 30) // the minimum expected + { + if ((S7.GetWordAt(PDU,27)==0) && (PDU[29]==(byte)0xFF)) + { + DateTime=S7.GetDateAt(PDU, 34); + } + else + LastError = errS7FunctionError; + } + else + LastError = errS7InvalidPDU; + } + + return LastError; + } + + public int SetPlcDateTime(Date DateTime) + { + int Length; + + LastError = 0; + S7.SetDateAt(S7_SET_DT, 31, DateTime); + + SendPacket(S7_SET_DT); + if (LastError==0) + { + Length=RecvIsoPacket(); + if (Length > 30) // the minimum expected + { + if (S7.GetWordAt(PDU,27)!=0) + LastError = errS7FunctionError; + } + else + LastError = errS7InvalidPDU; + } + + return LastError; + } + + public int SetPlcSystemDateTime() + { + return SetPlcDateTime(new Date()); + } + + public int PlcStop() + { + int Length; + + LastError = 0; + SendPacket(S7_STOP); + if (LastError==0) + { + Length=RecvIsoPacket(); + if (Length > 18) // 18 is the minimum expected + { + if (S7.GetWordAt(PDU,17)!=0) + LastError = errS7FunctionError; + } + else + LastError = errS7InvalidPDU; + } + return LastError; + } + + public int PlcHotStart() + { + int Length; + + LastError = 0; + SendPacket(S7_HOT_START); + if (LastError==0) + { + Length=RecvIsoPacket(); + if (Length > 18) // the minimum expected + { + if (S7.GetWordAt(PDU,17)!=0) + LastError = errS7FunctionError; + } + else + LastError = errS7InvalidPDU; + } + return LastError; + } + + public int PlcColdStart() + { + int Length; + + LastError = 0; + SendPacket(S7_COLD_START); + if (LastError==0) + { + Length=RecvIsoPacket(); + if (Length > 18) // the minimum expected + { + if (S7.GetWordAt(PDU,17)!=0) + LastError = errS7FunctionError; + } + else + LastError = errS7InvalidPDU; + } + return LastError; + } + + public int GetPlcStatus(IntByRef Status) + { + int Length; + + LastError = 0; + SendPacket(S7_GET_STAT); + if (LastError==0) + { + Length=RecvIsoPacket(); + if (Length > 30) // the minimum expected + { + if (S7.GetWordAt(PDU,27)==0) + { + switch (PDU[44]) + { + case S7.S7CpuStatusUnknown : + case S7.S7CpuStatusRun : + case S7.S7CpuStatusStop : Status.Value=PDU[44]; + break; + default : + // Since RUN status is always 0x08 for all CPUs and CPs, STOP status + // sometime can be coded as 0x03 (especially for old cpu...) + Status.Value=S7.S7CpuStatusStop; + } + } + else + LastError = errS7FunctionError; + } + else + LastError = errS7InvalidPDU; + } + return LastError; + } + + public int SetSessionPassword(String Password) + { + byte[] pwd = {0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20}; + int Length; + + LastError = 0; + // Adjusts the Password length to 8 + if (Password.length()>8) + Password=Password.substring(0, 8); + else + { + while (Password.length()<8) + Password=Password+" "; + } + + try { + pwd = Password.getBytes("UTF-8"); + } catch (UnsupportedEncodingException ex) { + LastError = errS7InvalidParams; + } + if (LastError==0) + { + // Encodes the password + pwd[0]=(byte) (pwd[0] ^ 0x55); + pwd[1]=(byte) (pwd[1] ^ 0x55); + for (int c = 2; c < 8; c++) + { + pwd[c]=(byte) (pwd[c] ^ 0x55 ^ pwd[c-2]); + } + System.arraycopy(pwd, 0, S7_SET_PWD, 29, 8); + // Sends the telegrem + SendPacket(S7_SET_PWD); + if (LastError==0) + { + Length=RecvIsoPacket(); + if (Length > 32) // the minimum expected + { + if (S7.GetWordAt(PDU,27)!=0) + LastError = errS7FunctionError; + } + else + LastError = errS7InvalidPDU; + } + } + return LastError; + } + + public int ClearSessionPassword() + { + int Length; + + LastError = 0; + SendPacket(S7_CLR_PWD); + if (LastError==0) + { + Length=RecvIsoPacket(); + if (Length > 30) // the minimum expected + { + if (S7.GetWordAt(PDU,27)!=0) + LastError = errS7FunctionError; + } + else + LastError = errS7InvalidPDU; + } + return LastError; + } + + public int GetProtection(S7Protection Protection) + { + S7Szl SZL = new S7Szl(256); + + LastError = ReadSZL(0x0232, 0x0004, SZL); + if (LastError==0) + { + Protection.Update(SZL.Data); + } + return LastError; + } + +} diff U3 S7CpInfo.java S7CpInfo.java --- S7CpInfo.java Thu Mar 23 15:34:52 2017 +++ S7CpInfo.java Tue Aug 08 18:53:37 2017 @@ -1,41 +1,41 @@ -/*=============================================================================| -| PROJECT Moka7 1.0.2 | -|==============================================================================| -| Copyright (C) 2013, 2016 Davide Nardella | -| All rights reserved. | -|==============================================================================| -| SNAP7 is free software: you can redistribute it and/or modify | -| it under the terms of the Lesser GNU General Public License as published by | -| the Free Software Foundation, either version 3 of the License, or under | -| EPL Eclipse Public License 1.0. | -| | -| This means that you have to chose in advance which take before you import | -| the library into your project. | -| | -| SNAP7 is distributed in the hope that it will be useful, | -| but WITHOUT ANY WARRANTY; without even the implied warranty of | -| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | -| decide to adopt. | -| | -|=============================================================================*/ -package Moka7; - -/** - * - * @author Davide - */ -public class S7CpInfo { - - public int MaxPduLength; - public int MaxConnections; - public int MaxMpiRate; - public int MaxBusRate; - - protected void Update(byte[] Src, int Pos) - { - MaxPduLength = S7.GetShortAt(Src, 2); - MaxConnections = S7.GetShortAt(Src, 4); - MaxMpiRate = S7.GetDIntAt(Src, 6); - MaxBusRate = S7.GetDIntAt(Src, 10); - } -} +/*=============================================================================| +| PROJECT Moka7 1.0.2 | +|==============================================================================| +| Copyright (C) 2013, 2016 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or under | +| EPL Eclipse Public License 1.0. | +| | +| This means that you have to chose in advance which take before you import | +| the library into your project. | +| | +| SNAP7 is distributed in the hope that it will be useful, | +| but WITHOUT ANY WARRANTY; without even the implied warranty of | +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | +| decide to adopt. | +| | +|=============================================================================*/ +package Moka7; + +/** + * + * @author Davide Nardella + */ +public class S7CpInfo { + + public int MaxPduLength; + public int MaxConnections; + public int MaxMpiRate; + public int MaxBusRate; + + protected void Update(byte[] Src, int Pos) + { + MaxPduLength = S7.GetShortAt(Src, 2); + MaxConnections = S7.GetShortAt(Src, 4); + MaxMpiRate = S7.GetDIntAt(Src, 6); + MaxBusRate = S7.GetDIntAt(Src, 10); + } +} diff U3 S7CpuInfo.java S7CpuInfo.java --- S7CpuInfo.java Thu Mar 23 15:34:52 2017 +++ S7CpuInfo.java Tue Aug 08 18:53:37 2017 @@ -1,57 +1,57 @@ -/*=============================================================================| -| PROJECT Moka7 1.0.2 | -|==============================================================================| -| Copyright (C) 2013, 2016 Davide Nardella | -| All rights reserved. | -|==============================================================================| -| SNAP7 is free software: you can redistribute it and/or modify | -| it under the terms of the Lesser GNU General Public License as published by | -| the Free Software Foundation, either version 3 of the License, or under | -| EPL Eclipse Public License 1.0. | -| | -| This means that you have to chose in advance which take before you import | -| the library into your project. | -| | -| SNAP7 is distributed in the hope that it will be useful, | -| but WITHOUT ANY WARRANTY; without even the implied warranty of | -| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | -| decide to adopt. | -| | -|=============================================================================*/ -package Moka7; - -/** - * - * @author Davide - */ -public class S7CpuInfo { - - private final int BufSize = 256; - protected byte[] Buffer = new byte[BufSize]; - - protected void Update(byte[] Src, int Pos) - { - System.arraycopy(Src, Pos, Buffer, 0, BufSize); - } - - public String ModuleTypeName() - { - return S7.GetStringAt(Buffer,172,32); - } - public String SerialNumber() - { - return S7.GetStringAt(Buffer,138,24); - } - public String ASName() - { - return S7.GetStringAt(Buffer,2,24); - } - public String Copyright() - { - return S7.GetStringAt(Buffer,104,26); - } - public String ModuleName() - { - return S7.GetStringAt(Buffer,36,24); - } -} +/*=============================================================================| +| PROJECT Moka7 1.0.2 | +|==============================================================================| +| Copyright (C) 2013, 2016 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or under | +| EPL Eclipse Public License 1.0. | +| | +| This means that you have to chose in advance which take before you import | +| the library into your project. | +| | +| SNAP7 is distributed in the hope that it will be useful, | +| but WITHOUT ANY WARRANTY; without even the implied warranty of | +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | +| decide to adopt. | +| | +|=============================================================================*/ +package Moka7; + +/** + * + * @author Davide Nardella + */ +public class S7CpuInfo { + + private final int BufSize = 256; + protected byte[] Buffer = new byte[BufSize]; + + protected void Update(byte[] Src, int Pos) + { + System.arraycopy(Src, Pos, Buffer, 0, BufSize); + } + + public String ModuleTypeName() + { + return S7.GetStringAt(Buffer,172,32); + } + public String SerialNumber() + { + return S7.GetStringAt(Buffer,138,24); + } + public String ASName() + { + return S7.GetStringAt(Buffer,2,24); + } + public String Copyright() + { + return S7.GetStringAt(Buffer,104,26); + } + public String ModuleName() + { + return S7.GetStringAt(Buffer,36,24); + } +} diff U3 S7OrderCode.java S7OrderCode.java --- S7OrderCode.java Thu Mar 23 15:34:52 2017 +++ S7OrderCode.java Tue Aug 08 18:53:37 2017 @@ -1,46 +1,46 @@ -/*=============================================================================| -| PROJECT Moka7 1.0.2 | -|==============================================================================| -| Copyright (C) 2013, 2016 Davide Nardella | -| All rights reserved. | -|==============================================================================| -| SNAP7 is free software: you can redistribute it and/or modify | -| it under the terms of the Lesser GNU General Public License as published by | -| the Free Software Foundation, either version 3 of the License, or under | -| EPL Eclipse Public License 1.0. | -| | -| This means that you have to chose in advance which take before you import | -| the library into your project. | -| | -| SNAP7 is distributed in the hope that it will be useful, | -| but WITHOUT ANY WARRANTY; without even the implied warranty of | -| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | -| decide to adopt. | -| | -|=============================================================================*/ -package Moka7; - -/** - * - * @author Davide - */ -public class S7OrderCode { - - public int V1; - public int V2; - public int V3; - protected byte[] Buffer = new byte[1024]; - - protected void Update(byte[] Src, int Pos, int Size) - { - System.arraycopy(Src, Pos, Buffer, 0, Size); - V1 = (byte) Src[Size-3]; - V2 = (byte) Src[Size-2]; - V3 = (byte) Src[Size-1]; - } - - public String Code() - { - return S7.GetStringAt(Buffer, 2, 20); - } -} +/*=============================================================================| +| PROJECT Moka7 1.0.2 | +|==============================================================================| +| Copyright (C) 2013, 2016 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or under | +| EPL Eclipse Public License 1.0. | +| | +| This means that you have to chose in advance which take before you import | +| the library into your project. | +| | +| SNAP7 is distributed in the hope that it will be useful, | +| but WITHOUT ANY WARRANTY; without even the implied warranty of | +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | +| decide to adopt. | +| | +|=============================================================================*/ +package Moka7; + +/** + * + * @author Davide Nardella + */ +public class S7OrderCode { + + public int V1; + public int V2; + public int V3; + protected byte[] Buffer = new byte[1024]; + + protected void Update(byte[] Src, int Pos, int Size) + { + System.arraycopy(Src, Pos, Buffer, 0, Size); + V1 = (byte) Src[Size-3]; + V2 = (byte) Src[Size-2]; + V3 = (byte) Src[Size-1]; + } + + public String Code() + { + return S7.GetStringAt(Buffer, 2, 20); + } +} diff U3 S7Protection.java S7Protection.java --- S7Protection.java Thu Mar 23 15:34:52 2017 +++ S7Protection.java Tue Aug 08 18:53:37 2017 @@ -1,38 +1,43 @@ -/*=============================================================================| -| PROJECT Moka7 1.0.2 | -|==============================================================================| -| Copyright (C) 2013, 2016 Davide Nardella | -| All rights reserved. | -|==============================================================================| -| SNAP7 is free software: you can redistribute it and/or modify | -| it under the terms of the Lesser GNU General Public License as published by | -| the Free Software Foundation, either version 3 of the License, or under | -| EPL Eclipse Public License 1.0. | -| | -| This means that you have to chose in advance which take before you import | -| the library into your project. | -| | -| SNAP7 is distributed in the hope that it will be useful, | -| but WITHOUT ANY WARRANTY; without even the implied warranty of | -| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | -| decide to adopt. | -| | -|=============================================================================*/ -package Moka7; - -// See §33.19 of "System Software for S7-300/400 System and Standard Functions" -public class S7Protection { - public int sch_schal; - public int sch_par; - public int sch_rel; - public int bart_sch; - public int anl_sch; - protected void Update(byte[] Src) - { - sch_schal = S7.GetWordAt(Src,2); - sch_par = S7.GetWordAt(Src,4); - sch_rel = S7.GetWordAt(Src,6); - bart_sch = S7.GetWordAt(Src,8); - anl_sch = S7.GetWordAt(Src,10); - } -} +/*=============================================================================| +| PROJECT Moka7 1.0.2 | +|==============================================================================| +| Copyright (C) 2013, 2016 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or under | +| EPL Eclipse Public License 1.0. | +| | +| This means that you have to chose in advance which take before you import | +| the library into your project. | +| | +| SNAP7 is distributed in the hope that it will be useful, | +| but WITHOUT ANY WARRANTY; without even the implied warranty of | +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | +| decide to adopt. | +| | +|=============================================================================*/ +package Moka7; + +/** + * + * @author Davide Nardella + */ + +// See §33.19 of "System Software for S7-300/400 System and Standard Functions" +public class S7Protection { + public int sch_schal; + public int sch_par; + public int sch_rel; + public int bart_sch; + public int anl_sch; + protected void Update(byte[] Src) + { + sch_schal = S7.GetWordAt(Src,2); + sch_par = S7.GetWordAt(Src,4); + sch_rel = S7.GetWordAt(Src,6); + bart_sch = S7.GetWordAt(Src,8); + anl_sch = S7.GetWordAt(Src,10); + } +} diff U3 S7Szl.java S7Szl.java --- S7Szl.java Thu Mar 23 15:34:52 2017 +++ S7Szl.java Tue Aug 08 18:53:37 2017 @@ -1,42 +1,42 @@ -/*=============================================================================| -| PROJECT Moka7 1.0.2 | -|==============================================================================| -| Copyright (C) 2013, 2016 Davide Nardella | -| All rights reserved. | -|==============================================================================| -| SNAP7 is free software: you can redistribute it and/or modify | -| it under the terms of the Lesser GNU General Public License as published by | -| the Free Software Foundation, either version 3 of the License, or under | -| EPL Eclipse Public License 1.0. | -| | -| This means that you have to chose in advance which take before you import | -| the library into your project. | -| | -| SNAP7 is distributed in the hope that it will be useful, | -| but WITHOUT ANY WARRANTY; without even the implied warranty of | -| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | -| decide to adopt. | -| | -|=============================================================================*/ -package Moka7; - -/** - * - * @author Davide - */ -public class S7Szl { - - public int LENTHDR; - public int N_DR; - public int DataSize; - public byte Data[]; - - public S7Szl(int BufferSize) - { - Data = new byte[BufferSize]; - } - protected void Copy(byte[] Src, int SrcPos, int DestPos, int Size) - { - System.arraycopy(Src, SrcPos, Data, DestPos, Size); - } -} +/*=============================================================================| +| PROJECT Moka7 1.0.2 | +|==============================================================================| +| Copyright (C) 2013, 2016 Davide Nardella | +| All rights reserved. | +|==============================================================================| +| SNAP7 is free software: you can redistribute it and/or modify | +| it under the terms of the Lesser GNU General Public License as published by | +| the Free Software Foundation, either version 3 of the License, or under | +| EPL Eclipse Public License 1.0. | +| | +| This means that you have to chose in advance which take before you import | +| the library into your project. | +| | +| SNAP7 is distributed in the hope that it will be useful, | +| but WITHOUT ANY WARRANTY; without even the implied warranty of | +| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE whatever license you | +| decide to adopt. | +| | +|=============================================================================*/ +package Moka7; + +/** + * + * @author Davide Nardella + */ +public class S7Szl { + + public int LENTHDR; + public int N_DR; + public int DataSize; + public byte Data[]; + + public S7Szl(int BufferSize) + { + Data = new byte[BufferSize]; + } + protected void Copy(byte[] Src, int SrcPos, int DestPos, int Size) + { + System.arraycopy(Src, SrcPos, Data, DestPos, Size); + } +}