using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using IPS7Lnk;


namespace CsIPS7LnkDemo
{

  struct xMyDataType
  {
    // 0 = byte, 1 = Word, 2 = Real,3 = DWord
    public const int Byte  = 0;
    public const int Word = 1;
    public const int Real = 2;
    public const int DWord = 3;
    public const int Bit = 4;
    public const int String = 5;
  }

  enum MyDataType
  {
    Byte,
    Word, 
    Real,
    DWord,
    Bit,
    String,
  }


  public partial class Form1 : Form
  {
    IPS7 Plc = new IPS7();
    bool m_bConnected;
    bool m_bOpened;
    uint m_uStartAt;
    char m_DataArea;
    uint m_uCount;
    uint m_uDBNo;
    uint m_uRackNr;
    uint m_uSlotNr;
    uint m_uPlcType;
    uint m_uChannel;
    uint m_uAccessMode;
    uint m_KeepAliveInterval;
    uint m_KeepAliveTime;
    bool m_bUseKeepAlive;

    ushort[] m_WordBuf = new ushort[2048];
    double[] m_DoubleBuf = new double[2048];
    uint[] m_DWordBuf = new uint[2048];
    byte[] m_ByteBuf = new byte[2048];

    string[] m_StrBuf = new string[256];

    int m_Err;
    char[] m_DataAreas = { 'E', 'A', 'M', 'D', 'T', 'Z' };


    public Form1()
    {
      InitializeComponent();
      cbDataArea.SelectedIndex = 0;
      cbPlcType.SelectedIndex = 0;
      cbChannel.SelectedIndex = 0;

      SetbOpened(false);

      listData.GridLines = true;
      listData.Columns[0].Text = "Adr / Addr";
      listData.Columns[1].Text = "Wert/Value(dec.)";
      listData.Columns[2].Text = "Wert/Value(hex)";
      listData.Columns[3].Text = "ASCII";

      listData.Columns[0].AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize);
      listData.Columns[1].AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize);
      listData.Columns[2].AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize);
      listData.Columns[3].AutoResize(ColumnHeaderAutoResizeStyle.HeaderSize);
      FileInfo Fi;
      Fi = new FileInfo(Assembly.GetExecutingAssembly().Location);
      helpProvider.HelpNamespace = Fi.DirectoryName + "\\ips7lnk.chm";
      StatusTimer.Start();
      if (File.Exists("oem.bmp"))
        Logo.Load("oem.bmp");
    }

    BindingSource bsD = new BindingSource(); // Datarows from PLC

    private void SetbOpened(bool bOpened)
    {
      m_bConnected = false;
      m_bOpened =
      Start.Enabled =
      Count.Enabled =
      DBNr.Enabled =
      btnClose.Enabled =
      btnRdB.Enabled =
      cbDataArea.Enabled =
      btnRdReal.Enabled =
      btnRdDW.Enabled =
      btnRdW.Enabled =
      btnRdMulti.Enabled =
      btnPLCInfo.Enabled =
      btnRdStr.Enabled = 

      btnConnect.Enabled = bOpened;
      
      cbChannel.Enabled =
      cbPlcType.Enabled =
      Rack.Enabled =
      Slot.Enabled =
      btnOpen.Enabled =
      IPAddress.Enabled = 
      checkUseKeepAlive.Enabled = 
      KeepAliveInterval.Enabled =
      KeepAliveTime.Enabled = !bOpened;
      ShowConnectStatus();
    }

    private void btnOpen_Click(object sender, EventArgs e)
    {
      int lRef;
      if (IPAddress.Text.Length == 0)
      {
        MessageBox.Show("Bitte IP-Adresse eingeben. / Please enter ip address.", this.Text);
        return;
      }

      m_uRackNr = uint.Parse(Rack.Text);
      m_uSlotNr = uint.Parse(Slot.Text);
      m_uChannel = (uint)cbChannel.SelectedIndex;
      m_uPlcType = (uint)cbPlcType.SelectedIndex;
      m_bUseKeepAlive = checkUseKeepAlive.Checked;

      switch (m_uPlcType)
      {
        default:
        case 0: // S7-300 / 400
          if (m_uChannel == 0) // OP
            m_uAccessMode = IPS7.AM.OP_S7300_400;
          else // PG
            m_uAccessMode = IPS7.AM.PG_S7300_400;
          break;

        case 1: // 1200
          if (m_uChannel == 0) // OP
            m_uAccessMode = IPS7.AM.OP_S7300_400;
          else // PG
            m_uAccessMode = IPS7.AM.PG_S7300_400;
          m_uRackNr = 0;
          m_uSlotNr = 1;
          Rack.Text = m_uRackNr.ToString();
          Slot.Text = m_uSlotNr.ToString();
          break;

        case 2: // S7200
          m_uAccessMode = IPS7.AM.S7200;
          break;
          
        case 3: // Logo
          m_uAccessMode = IPS7.AM.SiemensLogo;
          break;
      }
      
      lRef =  Plc.OpenEx(IPAddress.Text, m_uRackNr, m_uSlotNr, 0, 0, m_uAccessMode, 10000, 10000, 10000);
      if (lRef < 0)
        m_Err = lRef;
      else
        m_Err = 0;
      ShowStatus();
      if (m_Err == 0)
      {
        SetbOpened(true);
        if (m_bUseKeepAlive)
        {
          m_KeepAliveInterval = uint.Parse(KeepAliveInterval.Text);
          m_KeepAliveTime = uint.Parse(KeepAliveTime.Text);
          if (m_KeepAliveInterval >= 10 && m_KeepAliveTime >= 100)
          {
            Plc.SetKeepAlive(m_KeepAliveInterval, m_KeepAliveTime);
          }
        }
      }
    }

    private String GetResultString(int Err)
    {
      int SocketErr;
      String S;

      switch (Err)
      {
        case IPS7.Result.E_NOERR:
          S = "Aktion erfolgreich. / Action was successfull!";
          break;

        case IPS7.Result.E_NODATA:             // Datenbereich in der SPS nicht vorhanden
          S = "Datenbereich oder DB nicht vorhanden. / Data area DB does not exist!";
          break;

        case IPS7.Result.E_TIMEOUT:
          S = "Zeitüberlauf! / Timeout!";
          break;

        case IPS7.Result.E_SOCKERR:
          SocketErr = Plc.GetSockErr();
          S = string.Format("Socketfehler Nr: {0:D} aufgetreten. / Socket error no:{1:D} occurred!", SocketErr, SocketErr);
          break;  

        case IPS7.Result.E_TYPE_NOTSUPPORTED:
          S = "Datentyp oder Format wird nicht unterstützt! / Data type or data format not supported!";
          break;

        case IPS7.Result.E_PC_BUFSIZE:
          S = "Das übergebene Array hat zuwenig Elemente. / The Array you passed is to small.";
          break;

        case IPS7.Result.E_ALREADY_OPENED:
          S = "Die Open-Funktion wurde bereits aufgerufen. / The Open was called already.";
          break;

        case IPS7.Result.E_BADDATATYPE:
          S = "Multi-Access : Gewünschter SPS oder PC Datentyp nicht möglich / desired PLC or PC data type not available";
          break;

        case IPS7.Result.E_PC_S7_DATATYPE_BAD_REL:
          S = "Multi-Access : PC und S7-Datentyp stehen int falscher Relation / PC and S7 -datatype beeing in bad relations";
          break;

        case IPS7.Result.E_BADDATACOUNT:
          S = "Multi-Access : SPS liefert falsche Anzahl an Daten / PLC sends bad count of data";
          break;

        case IPS7.Result.E_DEMOOVER:
          S = "Demozeit ist abgelaufen (neu starten). / The demo period has expired (restart).";
          break;

        default:
          S = string.Format("Unbekannter Fehler aufgetreten. / Unknown error occured! (Nummer/Number: {0:d})", Err);
          break;
      }
      return (S);
    }

    private void ShowStatus()
    {
      String S = GetResultString(m_Err);
      Status.Text = S;
      if (m_Err != 0)
        Status.BackColor = Color.LightPink;
      else
        Status.BackColor = Color.LightGreen;
    }

    private void btnEnd_Click(object sender, EventArgs e)
    {
      Close();
    }

    private void btnRdW_Click(object sender, EventArgs e)
    {
      if (UpdateData(true))
      {
        Status.Text = "Beschäftigt ... / busy ...";
        Status.Refresh();
        this.Cursor = Cursors.WaitCursor;
        m_Err = Plc.Rd(m_DataArea, m_uDBNo, m_uStartAt, m_uCount, m_WordBuf);
        FillDataList(MyDataType.Word);
        this.Cursor = Cursors.Default;

      }
      ShowStatus();
    }

    private void btnRdReal_Click(object sender, EventArgs e)
    {
      if (UpdateData(true))
      {
        Status.Text = "Beschäftigt ... / busy ...";
        Status.Refresh();
        this.Cursor = Cursors.WaitCursor;
        m_Err = Plc.Rd(m_DataArea, m_uDBNo, m_uStartAt, m_uCount, m_DoubleBuf);
        FillDataList(MyDataType.Real);
        this.Cursor = Cursors.Default;

      }
      ShowStatus();
    }

    private void btnRdDW_Click(object sender, EventArgs e)
    {
      if (UpdateData(true))
      {
        Status.Text = "Beschäftigt ... / busy ...";
        Status.Refresh();
        this.Cursor = Cursors.WaitCursor;
        m_Err = Plc.Rd(m_DataArea, m_uDBNo, m_uStartAt, m_uCount, m_DWordBuf);
        FillDataList(MyDataType.DWord);
        this.Cursor = Cursors.Default;

      }
      ShowStatus();
    }


    private bool UpdateData(bool bGet)
    {
      if (bGet) // Daten
      {
        m_DataArea = m_DataAreas[cbDataArea.SelectedIndex];
        if (m_DataArea == 'D') // Db oder DX
        {
          if (DBNr.Text.Length == 0)
          {
            MessageBox.Show("Bitte DB-Nummer eingeben. / Please enter number of DB.", this.Text);
            return (false);
          }
          m_uDBNo = uint.Parse(DBNr.Text);

        }
        else
        {
          m_uDBNo = 0;
        }
        if (Count.Text.Length == 0)
        {
          MessageBox.Show("Bitte Anzahl eingeben. / Please enter a value for count.", this.Text);
          return (false);
        }

        m_uCount = uint.Parse(Count.Text);
        if (Start.Text.Length == 0)
        {
          MessageBox.Show("Bitte Start eingeben. / Please enter a value for start.", this.Text);
          return (false);
        }
        m_uStartAt = uint.Parse(Start.Text);
        return (true);
      }
      return (false);
    }

    private void btnRdB_Click(object sender, EventArgs e)
    {
      if (UpdateData(true))
      {
        Status.Text = "Beschäftigt ... / busy ...";
        Status.Refresh();
        this.Cursor = Cursors.WaitCursor;
        m_Err = Plc.Rd(m_DataArea, m_uDBNo, m_uStartAt, m_uCount, m_ByteBuf);
        this.Cursor = Cursors.Default;
        FillDataList(MyDataType.Byte);
      }
      ShowStatus();
    }

    private void btnClose_Click(object sender, EventArgs e)
    {
      m_Err = Plc.Close();
      SetbOpened(false);
      ShowStatus();
    }

    string GetAddrName(MyDataType DataType, char DataArea, uint DBNo)
    {
      if (DataArea == 'D')
      {
        if (DataType <= MyDataType.Word || DataType == MyDataType.String)
          return string.Format("DB{0}.DB{1}", DBNo, (DataType == MyDataType.Byte || DataType == MyDataType.String) ? "B" : "W");
        else if (DataType == MyDataType.DWord || DataType == MyDataType.Real)// 2 oder 3 = Doppelwort bzw Real
          return string.Format("DB{0}.DBD", DBNo);
        else if (DataType == MyDataType.Bit)
          return string.Format("DB{0}.DBX", DBNo);
        else
          return ("");
      }
      else if (DataArea == 'T')
        return "T ";
      else if (DataArea == 'Z')
        return "Z ";
      else
      {
        if (DataType <= MyDataType.Word || DataType == MyDataType.String)
          return string.Format("{0}{1}", DataArea, (DataType == MyDataType.Byte || DataType == MyDataType.String) ? 'B' : 'W');
        else if (DataType == MyDataType.DWord || DataType == MyDataType.Real)// 2 oder 3 = Doppelwort bzw Real
          return string.Format("{0}D", DataArea);
        else if (DataType == MyDataType.Bit)
          return string.Format("{0}", DataArea);
        else
          return ("");
      }
    }

    string GetAddrName(MyDataType DataType)
    {
      return (GetAddrName(DataType, m_DataArea, m_uDBNo));
    }


    private void FillDataList(MyDataType DataType) // 0 = byte, 1 = Word, 2 = Real,3 = DWord , 4 = String  
    {
      int i;
      int Step;
      string SAddr;

      listData.BeginUpdate();
      listData.Items.Clear();

      if (m_Err == 0)
      {
        SAddr = GetAddrName(DataType);

        if (DataType == MyDataType.Byte)
        {
          for (i = 0; i < (int)m_uCount; i++)
          {
            char C1;
            string S;
            ListViewItem liv = listData.Items.Add(SAddr + string.Format("{0}", m_uStartAt + i));

            liv.SubItems.Add(string.Format("{0:D}", m_ByteBuf[i]));
            liv.SubItems.Add(string.Format("0x{0:X2}", m_ByteBuf[i]));

            C1 = System.Convert.ToChar(m_ByteBuf[i]);
            S = string.Format("'{0}'", C1 != '\0' ? C1 : ' ');
            liv.SubItems.Add(S);
          }
        }
        else if (DataType == MyDataType.String)
        {
          ListViewItem liv = listData.Items.Add(SAddr + string.Format("{0}", m_uStartAt));
          string HexStr = null;

          char[] CArr = m_StrBuf[0].ToCharArray();
          for (i = 0; i < CArr.Length; i++)
          {
            HexStr += string.Format(" {0:X2}", (byte)CArr[i]);
          }
          liv.SubItems.Add(m_StrBuf[0]);
          liv.SubItems.Add(HexStr);
        }
        else if (DataType == MyDataType.Word)
        {
          Step = 2;
          for (i = 0; i < (int)m_uCount; i++)
          {
            char C1, C2;
            string S;
            ListViewItem liv = listData.Items.Add(SAddr + string.Format("{0}", m_uStartAt + i * Step));

            liv.SubItems.Add(string.Format("{0:D}", m_WordBuf[i]));
            liv.SubItems.Add(string.Format("0x{0:X4}", m_WordBuf[i]));

            C1 = System.Convert.ToChar(m_WordBuf[i] & 0x00ff);
            C2 = System.Convert.ToChar(m_WordBuf[i] >> 8);
            //S = "'" + C2.ToString() + C1.ToString() + "'";
            S = string.Format("'{0}{1}'", C2 != '\0' ? C2 : ' ', C1 != '\0' ? C1 : ' ');

            liv.SubItems.Add(S);
          }
        }
        else if (DataType == MyDataType.Real) // Real
        {
          if (m_DataArea == 'T')
            Step = 1;
          else
            Step = 4;
          for (i = 0; i < (int)m_uCount; i++)
          {
            ListViewItem liv = listData.Items.Add(SAddr + string.Format("{0}", m_uStartAt + i * Step));

            liv.SubItems.Add(string.Format("{0:F}", m_DoubleBuf[i]));
          }
        }
        else if (DataType == MyDataType.DWord) // DWord
        {
          if (m_DataArea == 'T')
            Step = 1;
          else
            Step = 4;
          for (i = 0; i < (int)m_uCount; i++)
          {
            char C1, C2, C3, C4;
            string S;

            ListViewItem liv = listData.Items.Add(SAddr + string.Format("{0}", m_uStartAt + i * Step));

            liv.SubItems.Add(string.Format("{0:D}", m_DWordBuf[i]));
            liv.SubItems.Add(string.Format("0x{0:X8}", m_DWordBuf[i]));

            C1 = System.Convert.ToChar(m_WordBuf[i] & 0x00ff);
            C2 = System.Convert.ToChar(m_WordBuf[i] >> 8 & 0x00ff);
            C3 = System.Convert.ToChar(m_WordBuf[i] >> 16 & 0x00ff);
            C4 = System.Convert.ToChar(m_WordBuf[i] >> 24 & 0x00ff);

            //S = "'" + C2.ToString() + C1.ToString() + "'";
            S = string.Format("'{0}{1}{2}{3}'", C4 != '\0' ? C4 : ' ', C3 != '\0' ? C3 : ' ', C2 != '\0' ? C2 : ' ', C1 != '\0' ? C1 : ' ');
            liv.SubItems.Add(S);
          }
        }
      }
      listData.EndUpdate();
    }


    private void cbDataArea_SelectedIndexChanged(object sender, EventArgs e)
    {
      m_DataArea = m_DataAreas[cbDataArea.SelectedIndex];

      btnRdReal.Enabled =
      btnRdB.Enabled =
      btnRdW.Enabled =
      DBNr.Enabled =
      btnRdDW.Enabled = false;

      if (!m_bOpened)
        return;

      if (m_DataArea == 'T')
      {
        btnRdDW.Enabled = true;
      }

      else if (m_DataArea == 'Z')
      {
        btnRdW.Enabled = true;
      }
      else
      {
        btnRdReal.Enabled =
        btnRdB.Enabled =
        btnRdW.Enabled =
        btnRdDW.Enabled = true;
      }
      if (m_DataArea == 'D')
        DBNr.Enabled = true;
    }

    private void btnHelp_Click(object sender, EventArgs e)
    {
      Help.ShowHelp(this, "ips7lnk.chm");
    }

  
  
    private void btnRdMulti_Click(object sender, EventArgs e)
    {
      int Cnt;
      Cnt = 30;
      IPS7RdMulti[] Rq = new IPS7RdMulti[Cnt];
            
      for (int i = 0; i < Cnt; i++)
      {
        Rq[i] = new IPS7RdMulti();
      }

      Cnt = 0;
        

      Rq[Cnt].Int16((char)'D', 10, 0, 2, ref m_DoubleBuf[0]); // DB10.DBB0 2 Realwerte
      Rq[Cnt].UserData0 = (int)MyDataType.Real;
      Rq[Cnt].UserData1 = 0; // StartIndex Zielspeicher
      ++Cnt;
      
      Rq[Cnt].Bit((char)'E', 0, 0, 0, 32, m_ByteBuf); // lese ab E 4.0 32 Bit
      Rq[Cnt].UserData0 = (int)MyDataType.Bit;
      Rq[Cnt].UserData1 = 0; // StartIndex Zielspeicher
      ++Cnt;
       
      Rq[Cnt].Byte((char)'E', 0, 0, 20, ref m_ByteBuf[40]); // EB0 20 Byte
      Rq[Cnt].UserData0 = (int)MyDataType.Byte;
      Rq[Cnt].UserData1 = 40; // StartIndex Zielspeicher
      ++Cnt;

      Rq[Cnt].Word((char)'D', 10, 0, 10, ref m_WordBuf[10]); // DB10.DW 0 10 Worte
      Rq[Cnt].UserData0 = (int)MyDataType.Word;
      Rq[Cnt].UserData1 = 10; // StartIndex Zielspeicher
      ++Cnt;


      Rq[Cnt].Real((char)'D', 10, 0, 10, ref m_DoubleBuf[60]); // DB10.DBB0 10 Realwerte
      Rq[Cnt].UserData0 = (int)MyDataType.Real;
      Rq[Cnt].UserData1 = 60; // StartIndex Zielspeicher
      ++Cnt;

      Rq[Cnt].Timer('T', 0, 5, 10, ref m_DWordBuf[100]); // T5 10 Timer
      Rq[Cnt].UserData0 = (int)MyDataType.DWord; //
      Rq[Cnt].UserData1 = 100; // StartIndex Zielspeicher
      ++Cnt;

     // m_Err = Plc.RdMulti(Rq, (uint)Cnt);

     // String Test

//      Cnt = 0;
      Rq[Cnt].String('D', 100, 0, 10, ref m_StrBuf[0]);
      Rq[Cnt].UserData0 = (int)MyDataType.String; //
      Rq[Cnt].UserData1 = 0; // StartIndex Zielspeicher
      ++Cnt;

      m_Err = Plc.RdMultiBuffered (Rq, (uint)Cnt);
      {
        int i = 0;

        Rq[i++].GetData(ref m_DoubleBuf[0]); // DB10.DBB0 2 Realwerte
        Rq[i++].GetData(m_ByteBuf); // lese ab E 4.0 32 Bit
        Rq[i++].GetData(ref m_ByteBuf[40]); // EB0 20 Byte
        Rq[i++].GetData(ref m_WordBuf[10]); // DB10.DW 0 10 Worte
        Rq[i++].GetData(ref m_DoubleBuf[60]); // DB10.DBB0 10 Realwerte
        Rq[i++].GetData(ref m_DWordBuf[100]); // T5 10 Timer
        Rq[i++].GetData(ref m_StrBuf[0]);

      }


      BeginDataListUpdate();
      for (int i = 0; i < Cnt; i++)
        AddDataToList(Rq[i]);
      EndDataListUpdate();
      ShowStatus();
    }

    private void BeginDataListUpdate()
    {
      listData.BeginUpdate();
      listData.Items.Clear();
    }

    private void EndDataListUpdate()
    {
      listData.EndUpdate();
    }

    private void AddDataToList(IPS7RdMulti Rq)
    {
      int i;
      int Step;
      string SAddr;
      int Count = Rq.Cnt;
      int StartAt = Rq.Start;
      int BufIdx = Rq.UserData1;
      MyDataType DataType = (MyDataType)Rq.UserData0;
      int DataArea = Rq.DataArea;

      if (m_Err >= 0)
      {
        SAddr = GetAddrName(DataType, (char)Rq.DataArea, (uint)Rq.DBNr);

        if (DataType == MyDataType.Bit)
        {
          int BitNr = Rq.StartBit;
          int ByteNr = Rq.Start;

          for (i = 0; i < (int)Count; i++, BufIdx++)
          {
            char C1;
            string S;
            ListViewItem liv = listData.Items.Add(SAddr + string.Format("{0}.{1}", ByteNr, BitNr));
            if (Rq.Result == 0)
            {
              liv.SubItems.Add(string.Format("{0:D}", m_ByteBuf[BufIdx]));
              liv.SubItems.Add(string.Format("0x{0:X2}", m_ByteBuf[BufIdx]));
              C1 = (char)m_ByteBuf[BufIdx];
              S = string.Format("'{0}'", C1 != '\0' ? C1 : ' ');
            }
            else
            {
              S = GetResultString(Rq.Result);
            }
            liv.SubItems.Add(S);
            if (++BitNr > 7)
            {
              BitNr = 0;
              ByteNr++;
            }
          }
        }
        else if (DataType == MyDataType.String)
        {
          ListViewItem liv = listData.Items.Add(SAddr + string.Format("{0}", StartAt));
//          liv.SubItems.Add(string.Format("{0:D}", CArr[i]));
          string HexStr = null;

          if (Rq.Result == 0)
          {
            char[] CArr = m_StrBuf[BufIdx].ToCharArray();
            for (i = 0; i < CArr.Length; i++)
            {
              HexStr += string.Format(" {0:X2}", (byte)CArr[i]);
                /*
                S = string.Format("'{0}'", CArr[i] != '\0' ? CArr[i] : ' ');
                liv.SubItems.Add(S);
                 */
            }
            liv.SubItems.Add (m_StrBuf[BufIdx]);
            liv.SubItems.Add (HexStr);

          }
          else
          {
            liv.SubItems.Add (GetResultString(Rq.Result));
          }
        }
        else if (DataType == MyDataType.Byte)
        {
          for (i = 0; i < (int)Count; i++, BufIdx++)
          {
            char C1;
            string S;
            ListViewItem liv = listData.Items.Add(SAddr + string.Format("{0}", StartAt + i));

            if (Rq.Result == 0)
            {
              liv.SubItems.Add(string.Format("{0:D}", m_ByteBuf[BufIdx]));
              liv.SubItems.Add(string.Format("0x{0:X2}", m_ByteBuf[BufIdx]));

              C1 = System.Convert.ToChar(m_ByteBuf[BufIdx]);
              S = string.Format("'{0}'", C1 != '\0' ? C1 : ' ');
              liv.SubItems.Add(S);
            }
            else
            {
              S = GetResultString(Rq.Result);
            }
          }
        }
        else if (DataType == MyDataType.Word) // Word
        {
          Step = 2;
          for (i = 0; i < Count; i++, BufIdx++)
          {
            char C1, C2;
            string S;
            ListViewItem liv = listData.Items.Add(SAddr + string.Format("{0}", StartAt + i * Step));

            if (Rq.Result == 0)
            {
              liv.SubItems.Add(string.Format("{0:D}", m_WordBuf[BufIdx]));
              liv.SubItems.Add(string.Format("0x{0:X4}", m_WordBuf[BufIdx]));

              C1 = System.Convert.ToChar(m_WordBuf[BufIdx] & 0x00ff);
              C2 = System.Convert.ToChar(m_WordBuf[BufIdx] >> 8);
              //S = "'" + C2.ToString() + C1.ToString() + "'";
              S = string.Format("'{0}{1}'", C2 != '\0' ? C2 : ' ', C1 != '\0' ? C1 : ' ');
            }
            else
            {
              S = GetResultString(Rq.Result);
            }

            liv.SubItems.Add(S);
          }
        }
        else if (DataType == MyDataType.Real) // Real
        {
          if (DataArea == 'T' || DataArea == 'Z')
            Step = 1;
          else
            Step = 4;
          for (i = 0; i < Count; i++, BufIdx++)
          {
            ListViewItem liv = listData.Items.Add(SAddr + string.Format("{0}", StartAt + i * Step));
            if (Rq.Result == 0)
            {
              liv.SubItems.Add(string.Format("{0:F}", m_DoubleBuf[BufIdx]));
            }
            else
            {
              liv.SubItems.Add(string.Format("{0}", GetResultString(Rq.Result)));
            }
          }
        }
        else if (DataType == MyDataType.DWord) // DWord
        {
          if (DataArea == 'T' || DataArea == 'Z')
            Step = 1;
          else
            Step = 4;
          for (i = 0; i < Count; i++, BufIdx++)
          {
            char C1, C2, C3, C4;
            string S;

            ListViewItem liv = listData.Items.Add(SAddr + string.Format("{0}", StartAt + i * Step));

            if (Rq.Result == 0)
            {
              liv.SubItems.Add(string.Format("{0:D}", m_DWordBuf[BufIdx]));
              liv.SubItems.Add(string.Format("0x{0:X8}", m_DWordBuf[BufIdx]));

              C1 = System.Convert.ToChar(m_WordBuf[BufIdx] & 0x00ff);
              C2 = System.Convert.ToChar(m_WordBuf[BufIdx] >> 8 & 0x00ff);
              C3 = System.Convert.ToChar(m_WordBuf[BufIdx] >> 16 & 0x00ff);
              C4 = System.Convert.ToChar(m_WordBuf[BufIdx] >> 24 & 0x00ff);

              //S = "'" + C2.ToString() + C1.ToString() + "'";
              S = string.Format("'{0}{1}{2}{3}'", C4 != '\0' ? C4 : ' ', C3 != '\0' ? C3 : ' ', C2 != '\0' ? C2 : ' ', C1 != '\0' ? C1 : ' ');
            }
            else
            {
              S = GetResultString(Rq.Result);
            }
            liv.SubItems.Add(S);
          }
        }
      }
    }

    private void StatusTimer_Tick(object sender, EventArgs e)
    {
      bool bConnected = false;
      if (m_bOpened && Plc.GetConnectStatus() == 1)
      {
        bConnected = true;
      }
      if (bConnected != m_bConnected)
      {
        m_bConnected = bConnected;
        ShowConnectStatus();
      }
    }

    private void ShowConnectStatus()
    {
      if (m_bConnected)
      {
        ConnectStatus.Text = "verbunden / connected";
        ConnectStatus.BackColor = Color.LightGreen;
      }
      else
      {
        ConnectStatus.Text = "nicht verbunden / not connected";
        ConnectStatus.BackColor = Color.LightPink;
      }
    }

    private void btnConnect_Click(object sender, EventArgs e)
    {
      if (m_bOpened)
      {
        if (Plc.Connect() == 1)
          m_bConnected = true;
        else
          m_bConnected = false;
      }
      ShowConnectStatus(); 
    }

    private void Form1_Load(object sender, EventArgs e)
    {

    }

    private void btnPLCInfo_Click(object sender, EventArgs e)
    {
      DateTime PlcTime = new DateTime ();
      string Msg = "";
      string strInfo = "";
      Status.Text = "Beschäftigt ... / busy ...";
      Status.Refresh();

  		m_Err = Plc.GetPLCTime(ref PlcTime);
		  if (m_Err == 0)
		  {
			  string StrTime;
			  
        StrTime = string.Format("PLC-Time: {0:d}.{1:d}.{2:d4} {3:d2}:{4:d2}:{5:d2} + {6:d}(ms)",PlcTime.Day, PlcTime.Month, PlcTime.Year, PlcTime.Hour, PlcTime.Minute, PlcTime.Second, PlcTime.Millisecond);

        if (Plc.GetPLCName(ref strInfo) == 0)
			  {
				  Msg += "SPS-Name / Name of the PLC:\n'";
				  Msg += strInfo;
          Msg += "'\n------------------------------\n";
        }

        if (Plc.GetModuleName(ref strInfo) == 0)
			  {
          Msg += "Baugruppenname / Name of the Module:\n'"; 
				  Msg += strInfo;
          Msg += "'\n------------------------------\n";
        }

        if (Plc.GetPlantIdName(ref strInfo) == 0)
			  {
          Msg += "Anlagenname  / Plant identification of PLC:\n'"; 
				  Msg += strInfo;
          Msg += "'\n------------------------------\n";
        }

  		  if (Plc.GetCopyrightEntry(ref strInfo) == 0)
			  {
          Msg += "Copyright Eintrag / entry:\n'"; 
				  Msg += strInfo;
          Msg += "'\n------------------------------\n";
        }

        if (Plc.GetModuleSNr(ref strInfo) == 0)
			  {
          Msg += "Seriennummer der Baugruppe / Serial number of the module:\n'"; 
				  Msg += strInfo;
          Msg += "'\n------------------------------\n";
        }

        if (Plc.GetModuleTypeName(ref strInfo) == 0)
			  {
          Msg += "Baugruppentyp / Module type name:\n'";
				  Msg += strInfo;
				  Msg += "'\n------------------------------\n";
			  }

        if (Plc.GetMMCSNr(ref strInfo) == 0)
			  {
          Msg += "Seriennummer der MMC / Serial number of MMC:\n'";
				  Msg += strInfo;
          Msg += "'\n------------------------------\n";
        }

        if (Plc.GetLocationDesignation(ref strInfo) == 0)
			  {
				  Msg += "Orstkennzeichen der SPS / Location designation PLC:\n'";
				  Msg += strInfo;
          Msg += "'\n------------------------------\n";
        }
			  Msg += StrTime;

        MessageBox.Show(Msg, "SPS-Info / PLC-Info");
      }
      ShowStatus();
    }

    private void cbPlcType_SelectedIndexChanged(object sender, EventArgs e)
    {
      m_uPlcType = (uint)cbPlcType.SelectedIndex;
      if (m_uPlcType == 1) // S7-1200
      {
        m_uRackNr = 0;
        m_uSlotNr = 1;

        Rack.Text = m_uRackNr.ToString();
        Slot.Text = m_uSlotNr.ToString();
      }
      else if (m_uPlcType == 2 || m_uPlcType == 3) // S7-200 Logo
      {
        m_uRackNr = 0;
        m_uSlotNr = 1;
        Rack.Text = m_uRackNr.ToString();
        Slot.Text = m_uSlotNr.ToString();
      }
    }

    private void btnRdStr_Click(object sender, EventArgs e)
    {
      if (UpdateData(true))
      {
        Status.Text = "Beschäftigt ... / busy ...";
        Status.Refresh();
        this.Cursor = Cursors.WaitCursor;
        m_Err = Plc.Rd(m_DataArea, m_uDBNo, m_uStartAt, m_uCount, ref m_StrBuf[0]);
        this.Cursor = Cursors.Default;
        FillDataList(MyDataType.String);
      }
      ShowStatus();

    }
  }
}

