using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.Runtime.InteropServices;

 

using TMW;

using TMW.SCL;

using TMW.SCL.ProtocolAnalyzer;

 

using TMW.SCL.DNP;

using TMW.SCL.DNP.Master;

 

namespace DNPmasterGUI

{

  public partial class MasterForm : Form

  {

    private const int WM_VSCROLL = 0x115;

    private const int SB_BOTTOM = 7;

    private int _OldEventMask = 0;

    private const int WM_SETREDRAW = 0x000B;

    private const int EM_SETEVENTMASK = 0x0431;

 

    [DllImport("user32", CharSet = CharSet.Auto)]

    private static extern int SendMessage(HandleRef hWnd, int msg, int wParam, int lParam);

 

    static TMWApplication pAppl;

 

    private ProtocolBuffer protocolBuffer;

    private MDNPSimDatabase db;

    private MDNPSession masterSesn;

    private DNPChannel masterChan;

    private bool pauseAnalyzer;

 

    // Timer values

    private decimal integrityPollInterval;

    private decimal integrityPollCount;

    private decimal eventPollInterval;

    private decimal eventPollCount;

 

    public MasterForm()

    {

      TMWApplicationBuilder applBuilder = new TMWApplicationBuilder();

      pAppl = TMWApplicationBuilder.getAppl();

      pAppl.InitEventProcessor();

      pAppl.EnableEventProcessor = true;

 

      protocolBuffer = TMWApplicationBuilder.getProtocolBuffer();

      protocolBuffer.ProtocolDataReadyEvent += new ProtocolBuffer.ProtocolDataReadyEventDelegate(ProtocolEvent);

      protocolBuffer.EnableCheckForDataTimer = true;

      InitializeComponent();

 

      masterChan = new DNPChannel(TMW_CHANNEL_OR_SESSION_TYPE.MASTER);

 

      masterChan.Type = WINIO_TYPE.TCP;

      masterChan.Name = ".NET DNP Master"/* name displayed in analyzer window */

      masterChan.WinTCPipAddress = "127.0.0.1";

      masterChan.WinTCPipPort = 20000;

      masterChan.WinTCPmode = TCP_MODE.CLIENT;

      masterChan.OpenChannel();

 

      masterSesn = new MDNPSession(masterChan);

      masterSesn.AuthenticationEnabled = false;

 

      masterSesn.OpenSession();

      masterSesn.SessionStatisticsEvent += new TMWSession.SessionStatisticsEventDelegate(masterSesn_SessionStatisticsEvent);

 

      db = (MDNPSimDatabase)masterSesn.SimDatabase;

      // Register to receive notification of database changes

      db.UpdateDBEvent += new TMWSimDataBase.UpdateDBEventDelegate(UpdateDBEvent);

             

      customizeDatabase();

 

      // Set up integrity poll timer

      integrityPollCount = 0;

      integrityPollInterval = 3600;  // Once per hour

      IntegrityProgressBar.Value = 0;

      IntegrityProgressBar.Maximum = (int)integrityPollInterval;

      IntegrityPollTimer.Start();

 

      // Set up event poll timer

      eventPollCount = 0;

      eventPollInterval = 5;

      EventProgressBar.Value = 0;

      EventProgressBar.Maximum = (int)eventPollInterval;

      EventPollTimer.Start();

    }

 

    int masterSesn_SessionStatisticsEvent(TMWSession session)

    {

      return 0;

    }

 

    private delegate void UpdatePointDelegate(TMWSimPoint simPoint);

 

    private void customizeDatabase()

    {

      ushort i;

 

      db.Clear();

 

      /* Add 3 of each of the following types:

       *  Binary Input

       *    Value = False, Flags = onLine, class = 1

       *  Binary Output

       *    Value = False, Flags = onLine, class = 3, ControlMask = 0x3ff (allow all control operations)

       *  Analog Input

       *    Value = 0, Flags = 0, classMask = 2, Deadband = 5

       *  Analog Output

       *    Value = 0, Flags = onLine; classMask = 3

       *  Binary Counter

       *    Value = 0, Flags = onLIne, classMask = 2, frozenClassMask = 2

       */

      for (i = 0; i < 3; i++)

      {

        db.AddBinIn(i);

        db.AddBinOut(i);

        db.AddAnlgIn(i);

        db.AddAnlgOut(i);

        db.AddBinCntr(i);

      }

 

      /* Don't add any of the following data types:

       *   Double Bit Input

       *   String

       *   Vterm

       */

    }

 

    private void ScrollToBottom()

    {

      SendMessage(new HandleRef(protocolAnalyzer, protocolAnalyzer.Handle), WM_VSCROLL, SB_BOTTOM, 0);

    }

 

    private void BeginUpdate()

    {

      // Prevent the control from raising any events

      _OldEventMask = SendMessage(new HandleRef(protocolAnalyzer, protocolAnalyzer.Handle), EM_SETEVENTMASK, 0, 0);

 

      // Prevent the control from redrawing itself

      SendMessage(new HandleRef(protocolAnalyzer, protocolAnalyzer.Handle), WM_SETREDRAW, 0, 0);

    }

 

    private void EndUpdate()

    {

      // Allow the control to redraw itself

      SendMessage(new HandleRef(protocolAnalyzer, protocolAnalyzer.Handle), WM_SETREDRAW, 1, 0);

 

      // Allow the control to raise event messages

      SendMessage(new HandleRef(protocolAnalyzer, protocolAnalyzer.Handle), EM_SETEVENTMASK, 0, _OldEventMask);

    }

 

    private void RemoveTopLines(int numLines)

    {

      int lastLine = protocolAnalyzer.Lines.GetLength(0) - 1;

      if (numLines < 1)

      {

        return;

      }

      else if (numLines > lastLine)

      {

        numLines = lastLine;

      }

 

      int startChar = protocolAnalyzer.GetFirstCharIndexFromLine(0);

      int endChar = protocolAnalyzer.GetFirstCharIndexFromLine(numLines);

 

      bool b = protocolAnalyzer.ReadOnly;

      protocolAnalyzer.ReadOnly = false;

      protocolAnalyzer.Select(startChar, endChar - startChar);

      protocolAnalyzer.SelectedRtf = "";

      protocolAnalyzer.ReadOnly = b;

    }

 

    private void ProtocolEvent(ProtocolBuffer buf)

    {

      if (!pauseAnalyzer)

      {

        buf.Lock();

        for (int i = buf.LastProvidedIndex; i < buf.LastAddedIndex; i++)

        {

          protocolAnalyzer.AppendText(protocolBuffer.getPdoAtIndex(i).ProtocolText);

          SendMessage(new HandleRef(protocolAnalyzer, protocolAnalyzer.Handle), WM_VSCROLL, SB_BOTTOM, 0);

        }

        buf.UnLock();

 

        // remove lines from the text box

        if (protocolAnalyzer.Lines.Length > 1000)

        {

          BeginUpdate();

          RemoveTopLines(100);

          ScrollToBottom();

          EndUpdate();

        }

      }

    }

 

    private void updateBinaryInput(TMWSimPoint simPoint)

    {

      string strVal = (simPoint as MDNPSimBinIn).Value ? "On" : "Off";

      Color textColor = (simPoint as MDNPSimBinIn).Value ? Color.ForestGreen : Color.Red;

 

      switch (simPoint.PointNumber)

      {

        case 0:

          BinIn0.Text = strVal;

          BinIn0.ForeColor = textColor;

          break;

        case 1:

          BinIn1.Text = strVal;

          BinIn1.ForeColor = textColor;

          break;

        case 2:

          BinIn2.Text = strVal;

          BinIn2.ForeColor = textColor;

          break;

        default:

          protocolBuffer.Insert("Received update for unexpected binary input point: " + simPoint.PointNumber.ToString());

          break;

      }

    }

 

    private void updateBinaryOutput(TMWSimPoint simPoint)

    {

      string strVal = (simPoint as MDNPSimBinOut).Value ? "On" : "Off";

      Color textColor = (simPoint as MDNPSimBinOut).Value ? Color.ForestGreen : Color.Red;

 

      switch (simPoint.PointNumber)

      {

        case 0:

          BinOut0Feedback.Text = strVal;

          BinOut0Feedback.ForeColor = textColor;

          break;

        case 1:

          BinOut1Feedback.Text = strVal;

          BinOut1Feedback.ForeColor = textColor;

          break;

        case 2:

          BinOut2Feedback.Text = strVal;

          BinOut2Feedback.ForeColor = textColor;

          break;

        default:

          protocolBuffer.Insert("Received update for unexpected binary output point: " + simPoint.PointNumber.ToString());

          break;

      }

    }

 

    private void updateBinCntr(TMWSimPoint simPoint)

    {

      switch (simPoint.PointNumber)

      {

        case 0:

          BinCntr0.Text = (simPoint as MDNPSimBinCntr).Value.ToString();

          break;

        case 1:

          BinCntr1.Text = (simPoint as MDNPSimBinCntr).Value.ToString();

          break;

        case 2:

          BinCntr2.Text = (simPoint as MDNPSimBinCntr).Value.ToString();

          break;

        default:

          protocolBuffer.Insert("Received update for unexpected analog input point: " + simPoint.PointNumber.ToString());

          break;

      }

    }

 

    private void updateAnalogInput(TMWSimPoint simPoint)

    {

      switch (simPoint.PointNumber)

      {

        case 0:

          AnlgIn0.Text = (simPoint as MDNPSimAnlgIn).Value.ToString();

          break;

        case 1:

          AnlgIn1.Text = (simPoint as MDNPSimAnlgIn).Value.ToString();

          break;

        case 2:

          AnlgIn2.Text = (simPoint as MDNPSimAnlgIn).Value.ToString();

          break;

        default:

          protocolBuffer.Insert("Received update for unexpected analog input point: " + simPoint.PointNumber.ToString());

          break;

      }

    }

 

    private void updateAnalogOutput(TMWSimPoint simPoint)

    {

      switch (simPoint.PointNumber)

      {

        case 0:

          AnlgOut0Feedback.Text = (simPoint as MDNPSimAnlgOut).Value.ToString();

          break;

        case 1:

          AnlgOut1Feedback.Text = (simPoint as MDNPSimAnlgOut).Value.ToString();

          break;

        case 2:

          AnlgOut2Feedback.Text = (simPoint as MDNPSimAnlgOut).Value.ToString();

          break;

        default:

          protocolBuffer.Insert("Received update for unexpected analog output point: " + simPoint.PointNumber.ToString());

          break;

      }

    }

 

 

    private void UpdateDBEvent(TMWSimPoint simPoint)

    {

      if (InvokeRequired)

        Invoke(new UpdatePointDelegate(UpdateDBEvent), new object[] { simPoint });

      else

      {

        switch (simPoint.PointType)

        {

          case 1:

            // Binary Input

            updateBinaryInput(simPoint);

            break;

          case 10:

            // Binary Output (CROB)

            updateBinaryOutput(simPoint);

            break;

          case 20:

            // Binary Counters

            updateBinCntr(simPoint);

            break;

          case 30:

            // Analog Inputs

            updateAnalogInput(simPoint);

            break;

          case 40:

            // Analog Output

            updateAnalogOutput(simPoint);

            break;

          default:

            protocolBuffer.Insert("Unknown point type in database update routine");

            break;

        }

 

      }

 

    }

 

    private void IntegrityPollTimer_Tick(object sender, EventArgs e)

    {

      if (integrityPollCount++ < integrityPollInterval)

      {

        IntegrityProgressBar.Increment(1);

      }

      else

      {

        // time to do a poll

 

        Integrity_Click( sender, e);

 

        integrityPollCount = 0;

        IntegrityProgressBar.Value = 0;

        IntegrityProgressBar.Maximum = (int)integrityPollInterval;

        IntegrityPollTimer.Start();

      }

    }

 

    private void EventPollTimer_Tick(object sender, EventArgs e)

    {

      if (eventPollCount++ < eventPollInterval)

      {

        EventProgressBar.Increment(1);

      }

      else

      {

        // time to do a poll

        Event_Click(sender, e);

 

        eventPollCount = 0;

        EventProgressBar.Value = 0;

        EventProgressBar.Maximum = (int)eventPollInterval;

      }

    }

 

    private void Integrity_Click(object sender, EventArgs e)

    {

      protocolBuffer.Insert("\nRequested Integrity Poll\n");

      MDNPRequest request = new MDNPRequest(masterSesn);

      request.IntegrityPoll(true);

    }

 

    private void Event_Click(object sender, EventArgs e)

    {

      protocolBuffer.Insert("\nRequested Event Poll\n");

 

      MDNPRequest request = new MDNPRequest(masterSesn);

      request.ReadClass(MDNPRequest.DNP_QUALIFIER.Q_ALL_POINTS, 0, false, true, true, true);

 

    }

 

    private void AnlgOut2Val_ValueChanged(object sender, EventArgs e)

    {

 

    }

 

    private void BinOutOn_Click(object sender, EventArgs e)

    {

      // Determine which point this request is for

      ushort pointNumber = Convert.ToUInt16((sender as Control).Tag);

 

      // Build and send the request

      CROBInfo crobData = new CROBInfo(pointNumber, CROBInfo.CROB_CTRL.LON, 1, 0, 0);

      CROBInfo[] crobArray = { crobData };

 

      MDNPSimBinOut point = db.LookupBinOut(pointNumber);

      MDNPRequest request = new MDNPRequest(masterSesn);

      request.BinaryCommand(MDNPRequest.DNP_FUNCTION_CODE.SELECT, true, true, 100, MDNPRequest.DNP_QUALIFIER.Q_8BIT_INDEX, crobArray);

      // request.BinaryOutWrite((byte)DNP_QUALIFIER.Q_8BIT_START_STOP, pointNumber, pointNumber, val);

    }

 

    private void BinOutOff_Click(object sender, EventArgs e)

    {

      // Determine which point this request is for

      ushort pointNumber = Convert.ToUInt16((sender as Control).Tag);

 

      // Build and send the request

      CROBInfo crobData = new CROBInfo(pointNumber, CROBInfo.CROB_CTRL.LOFF, 1, 0, 0);

      CROBInfo[] crobArray = { crobData };

 

      MDNPSimBinOut point = db.LookupBinOut(pointNumber);

      MDNPRequest request = new MDNPRequest(masterSesn);

      request.BinaryCommand(MDNPRequest.DNP_FUNCTION_CODE.SELECT, true, true, 100, MDNPRequest.DNP_QUALIFIER.Q_8BIT_INDEX, crobArray);

      // request.BinaryOutWrite((byte)DNP_QUALIFIER.Q_8BIT_START_STOP, pointNumber, pointNumber, val);

    }

 

    private void AnlgOutSend_Click(object sender, EventArgs e)

    {

      double val;

      // Determine which point this request is for

      ushort pointNumber = Convert.ToUInt16((sender as Control).Tag);

 

      // Get the value to write for this point

      switch (pointNumber)

      {

        case 0:

          val = (double)AnlgOut0Val.Value;

          break;

        case 1:

          val = (double)AnlgOut1Val.Value;

          break;

        case 2:

          val = (double)AnlgOut2Val.Value;

          break;

        default:

          val = 0;

          protocolBuffer.Insert("Unexected analog output command for undefined point: " + pointNumber.ToString());

          break;

      }

 

      // Build and send the request

      AnalogInfo anlgData = new AnalogInfo(pointNumber, val);

      AnalogInfo[] anlgArray = { anlgData };

 

      MDNPSimAnlgOut point = db.LookupAnlgOut(pointNumber);

      MDNPRequest request = new MDNPRequest(masterSesn);

      request.AnalogCommand(MDNPRequest.DNP_FUNCTION_CODE.SELECT, true, true, 100, MDNPRequest.DNP_QUALIFIER.Q_8BIT_INDEX, 2, anlgArray);

    }

 

    private void IntegrityInterval_ValueChanged(object sender, EventArgs e)

    {

      IntegrityPollTimer.Stop();

      integrityPollInterval = (IntegrityIntervalHr.Value * 3600) + (IntegrityIntervalMin.Value * 60) + (IntegrityIntervalSec.Value);

      IntegrityProgressBar.Maximum = (int)integrityPollInterval;

 

      if (integrityPollInterval == 0)

      {

        IntegrityEnable.Checked = false;

      }

 

      if (IntegrityEnable.Checked)

      {

        IntegrityPollTimer.Start();

      }

      else

      {

        // if unchecked, reset the progress bar and current count

        IntegrityProgressBar.Value = 0;

        integrityPollCount = 0;

      }

    }

 

    private void EventInterval_ValueChanged(object sender, EventArgs e)

    {

      EventPollTimer.Stop();

      eventPollInterval = (EventIntervalHr.Value * 3600) + (EventIntervalMin.Value * 60) + (EventIntervalSec.Value);

      EventProgressBar.Maximum = (int)eventPollInterval;

 

      if (eventPollInterval == 0)

      {

        EventEnable.Checked = false;

      }

 

      if (EventEnable.Checked)

      {

        EventPollTimer.Start();

      }

      else

      {

        // if unchecked, reset the progress bar and current count to 0

        EventProgressBar.Value = 0;

        eventPollCount = 0;

      }

    }

 

    private void protocolAnalyzer_MouseDown(object sender, MouseEventArgs e)

    {

      if (e.Clicks == 2)

      {

        // double click toggles pausing

        if (pauseAnalyzer)

        {

          // it's paused, so unpause it

          pauseAnalyzer = false;

          protocolAnalyzer.BackColor = Color.Gainsboro;

        }

        else

        {

          // it's not paused, so pause it

          pauseAnalyzer = true;

          protocolAnalyzer.BackColor = Color.MistyRose;

        }

      }

    }

  }

}