using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;


namespace WindowsFormsApplication1
{
    public partial class modbusForm : Form
    {
        int SelectPlc,ComPort,Readtrue;
        
        //串口控制函数 
        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtuComOpen", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtuComOpen(int nport, int BaudRate, int DataBits, String Parity, int StopBits, String User);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtuComClose", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtuComClose(int nport);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtuComTrue", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtuComTrue(int nport);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtuComWork", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtuComWork(int nport);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtuSetDelay", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtuSetDelay(int value);

        //标准modbus函数
        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtufcn01", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtufcn01(int nport, int node, int address, int Count, ref Int32 RxdBuffer);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtufcn02", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtufcn02(int nport, int node, int address, int Count, ref Int32 RxdBuffer);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtufcn03", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtufcn03(int nport, int node, int address, int Count, ref Int32 RxdBuffer);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtufcn04", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtufcn04(int nport, int node, int address, int Count, ref Int32 RxdBuffer);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtufcn05", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtufcn05(int nport, int node, int address, int value);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtufcn06", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtufcn06(int nport, int node, int address, int value);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtufcn15", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtufcn15(int nport, int node, int address, int Count, ref Int32 TxdBuffer);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtufcn16", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtufcn16(int nport, int node, int address, int Count, ref Int32 TxdBuffer);

        //延伸modbus函数
        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtufcn03DInt", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtufcn03DInt(int nport, int node, int regular, int address, int Count, ref Int32 RxdBuffer);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtufcn03Float", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtufcn03Float(int nport, int node, int regular, int address, int Count, ref float RxdBuffer);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtufcn04DInt", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtufcn04DInt(int nport, int node, int regular, int address, int Count, ref Int32 RxdBuffer);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtufcn04Float", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtufcn04Float(int nport, int node, int regular, int address, int Count, ref float RxdBuffer);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtufcn16DInt", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtufcn16DInt(int nport, int node, int regular, int address, int Count, ref Int32 TxdBuffer);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtufcn16Float", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtufcn16Float(int nport, int node, int regular, int address, int Count, ref float TxdBuffer);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtuWordBitWrite", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtuWordBitWrite(int nport, int node, int address, int Bit, int value);

        [DllImport("modbus_rtu.dll", EntryPoint = "mbrtuWordBitSetReset", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int mbrtuWordBitSetReset(int nport, int node, int address, int Bit, int value);


        //混合读写适用函数
        [DllImport("modbus_rtu.dll", EntryPoint = "DecBitBin", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int DecBitBin(int value, int Bitaddress);

        [DllImport("modbus_rtu.dll", EntryPoint = "Int32ToInt_16h", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
           CallingConvention = CallingConvention.StdCall)]
        public static extern int Int32ToInt_16h(int value);

        [DllImport("modbus_rtu.dll", EntryPoint = "Int32ToInt_16l", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
           CallingConvention = CallingConvention.StdCall)]
        public static extern int Int32ToInt_16l(int value);

        [DllImport("modbus_rtu.dll", EntryPoint = "Int16ToInt32", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern int Int16ToInt32(int valueH, int valueL);

        [DllImport("modbus_rtu.dll", EntryPoint = "Float32ToInt_16h", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
           CallingConvention = CallingConvention.StdCall)]
        public static extern int Float32ToInt_16h(float value);

        [DllImport("modbus_rtu.dll", EntryPoint = "Float32ToInt_16l", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
           CallingConvention = CallingConvention.StdCall)]
        public static extern int Float32ToInt_16l(float value);

        [DllImport("modbus_rtu.dll", EntryPoint = "Int16ToFloat32", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true,
            CallingConvention = CallingConvention.StdCall)]
        public static extern float Int16ToFloat32(int valueH, int valueL);

        public modbusForm()
        {
            InitializeComponent();             
        }
        
        private void modbusForm_Load(object sender, EventArgs e)
        {
            Comboxcom.SelectedIndex=0;
            CombBaudRate.SelectedIndex=1;
            Combonode.SelectedIndex = 0; 

            ComPort=1;
            SelectPlc = -1;
            Readtrue = -1;
        }

        private void ButtonOpen_Click(object sender, EventArgs e)
        {
           int k,BaudRate;
           string Userstr, Paritstr;

           ComPort = Comboxcom.SelectedIndex + 1;
           Userstr = Edituser.Text; 
           Paritstr = "e"; //这里是偶校验           

           if (mbrtuComTrue(ComPort) == -1)
           {
                              
               //设定DLL函数的超时参数16~80 默认值32
              mbrtuSetDelay(32);
              //将DLL用户名及端口号传入打开串口，串口设定9600,8,e,1
              
              BaudRate=Convert.ToInt32(CombBaudRate.Text);
              k = mbrtuComOpen(ComPort, BaudRate, 8, Paritstr, 1, Userstr);
              
              if (k == 1)             ////k=-1 表示串口打开失败，可能串口不存在或已被占用
              {
                this.Text = "施耐得modbus rtu协议通信DMEO----DLL已注册";
              }
              else if (k == 0)
              {
                  this.Text = "施耐得modbus rtu协议通信DMEO----DLL未注册";
              }
              if (mbrtuComTrue(ComPort) == 1)
              {
                  Combonode.Enabled = false;
                  Comboxcom.Enabled = false;                       
              }

              TimerPlc.Enabled = true;
           }            
            
        }

        private void ButtonClose_Click(object sender, EventArgs e)
        {
            if (mbrtuComTrue(ComPort)==1)
            {  
              Readtrue = -1;
              SelectPlc = -1;
              ButtonRead.Text="读元件值";
              
              if (mbrtuComClose(ComPort)==-1)
              {
                  return;            //关闭串口=-1表示失败  
              }

              Combonode.Enabled = true;
              Comboxcom.Enabled = true;

              this.Text = "施耐得modbus rtu协议通信DMEO"; 
            }
        }

        private void BtnbitWrite_Click(object sender, EventArgs e)
        {
            if ((mbrtuComTrue(ComPort) == 1) && (SelectPlc < 0))
            {
                SelectPlc = 2; //选择向设备写入命令
            }   
        }


        private void BtnSet_Click(object sender, EventArgs e)
        {
            if ((mbrtuComTrue(ComPort) == 1) && (SelectPlc < 0))
            {
                SelectPlc = 3; //选择向设备写入命令
            }  
        }

        private void BtnReset_Click(object sender, EventArgs e)
        {
            if ((mbrtuComTrue(ComPort) == 1) && (SelectPlc < 0))
            {
                SelectPlc = 4; //选择向设备写入命令
            }  
        }

        private void ButtonRead_Click(object sender, EventArgs e)
        {
            if (Readtrue == 1)
            {
                Readtrue = -1;
                ButtonRead.Text="读元件值";
            } 
            else if (mbrtuComTrue(ComPort)==1)
            {
                Readtrue = 1;
                ButtonRead.Text="停止读值";
            } 
        }

        private void ButtonWtire_Click(object sender, EventArgs e)
        {
            if ((mbrtuComTrue(ComPort) == 1) && (SelectPlc < 0))
            {
                SelectPlc = 1; //选择向设备写入命令
            }    
        }

        private void BtnbitRead_Click(object sender, EventArgs e)
        {
            if ((mbrtuComTrue(ComPort) == 1) && (SelectPlc < 0))
            {
                SelectPlc = 5; //选择向设备读取命令
            }  
        }

        private void TimerPlc_Tick(object sender, EventArgs e)
        {
            int nodeI, addrI, ReadInt;
            int[] buffer = new int[1024];
            string strreal;
            Int16 tempInt;
            int tempDInt;
            float tempFloat;

            TimerPlc.Enabled = false;
            nodeI = Convert.ToInt32(Combonode.Text);            

            try
            {
               if (SelectPlc > 0)      //选择零时的通信命令
               { 
                  switch (SelectPlc)
                  {                    
                    case 1:  //将混合的数据转换成16位整数                      
                      tempInt=Convert.ToInt16(EditWr01.Text);    //16位整数
                      buffer[0]=tempInt;
                      tempInt=Convert.ToInt16(EditWr02.Text);    //16位整数
                      buffer[1]=tempInt;
                      tempDInt=Convert.ToInt32(EditWr03.Text);   //32位整数
                      if (RadioButtonch1.Checked)
                      {
                          buffer[2]=Int32ToInt_16l(tempDInt);
                          buffer[3]=Int32ToInt_16h(tempDInt);
                      }
                      else
                      {
                         buffer[2]=Int32ToInt_16h(tempDInt);
                         buffer[3]=Int32ToInt_16l(tempDInt);
                      };        
                      tempInt=Convert.ToInt16(EditWr04.Text);    //16位整数
                      buffer[4]=tempInt;
                      tempInt=Convert.ToInt16(EditWr05.Text);    //16位整数
                      buffer[5]=tempInt;
                      tempFloat=Convert.ToSingle(EditWr06.Text);  //32位浮点数
                      if (RadioButtonch1.Checked)
                      {
                          buffer[6] = Float32ToInt_16l(tempFloat);
                          buffer[7] = Float32ToInt_16h(tempFloat);
                      }
                      else
                      {
                          buffer[6] = Float32ToInt_16h(tempFloat);
                          buffer[7] = Float32ToInt_16l(tempFloat);
                      };

                      //将混合的数据转换成16位整数后使用fcn16功能码写入设备
                      addrI = 0;                //modbus地址从40001开始，偏移地址0-7,8个存储器值
                      mbrtufcn16(ComPort, nodeI, addrI, 8, ref buffer[0]); 
                      break;
                    case 2:                      
                       addrI=Convert.ToInt32(EditbitAddr.Text);        //逻辑线圈modbus地址范围00001~0XXXX 函数调用按偏移地址从0开始        
                       tempInt=Convert.ToInt16(EditBitvalue.Text);     //只能是0或者1
                       buffer[0] = tempInt;
                       mbrtufcn15(ComPort, nodeI, addrI, 1, ref buffer[0]);  //对逻辑线圈进行多位模式写
                       //由于写一个也可以使用下面的函数
                       //mbrtufcn05(ComPort, nodeI, addrI, tempInt);
                      break;
                    case 3:
                      addrI = Convert.ToInt32(EditbitAddr.Text);        //逻辑线圈modbus地址范围00001~0XXXX 函数调用按偏移地址从0开始        
                      mbrtufcn05(ComPort, nodeI, addrI, 1);
                      break;
                    case 4:
                      addrI = Convert.ToInt32(EditbitAddr.Text);        //逻辑线圈modbus地址范围00001~0XXXX 函数调用按偏移地址从0开始        
                      mbrtufcn05(ComPort, nodeI, addrI, 0);
                      break;
                    case 5:
                      addrI = Convert.ToInt32(EditbitAddr.Text);        //逻辑线圈modbus地址范围00001~0XXXX 函数调用按偏移地址从0开始   
                      ReadInt = mbrtufcn01(ComPort, nodeI, addrI, 1, ref buffer[0]);
                      if (ReadInt == 1)
                      {
                        EditBitvalue.Text = Convert.ToString(buffer[0]);
                      };
                      break;
                  };
                  SelectPlc = -1;
               }            
               else if (Readtrue == 1)  //循环读取的通信命令
               {                  
                  addrI=0;             //modbus地址从40001开始，偏移地址0-7,8个存储器值   
                  ReadInt = mbrtufcn03(ComPort, nodeI, addrI, 8, ref buffer[0]);         //读取字元件值
                                   
                  if (ReadInt == 8)
                  {
                      EditRe01.Text = Convert.ToString(buffer[0]);
                      EditRe02.Text = Convert.ToString(buffer[1]);
                      if (RadioButtonch1.Checked)   //不同品牌的下位机在双字和浮点的数据存储上有所不同，有高位在前和低位在前之分
                      {
                          EditRe03.Text= Convert.ToString(Int16ToInt32(buffer[3],buffer[2]));
                      }
                      else
                      {
                          EditRe03.Text= Convert.ToString(Int16ToInt32(buffer[2],buffer[3]));
                      };
                      EditRe04.Text = Convert.ToString(buffer[4]);
                      EditRe05.Text = Convert.ToString(buffer[5]);
                      if (RadioButtonch1.Checked)   //不同品牌的下位机在双字和浮点的数据存储上有所不同，有高位在前和低位在前之分
                      {
                          tempFloat = Int16ToFloat32(buffer[7],buffer[6]);
                          strreal = tempFloat.ToString();
                          EditRe06.Text = strreal;
                      }  
                      else
                      {
                          tempFloat = Int16ToFloat32(buffer[6],buffer[7]);
                          strreal = tempFloat.ToString();
                          EditRe06.Text = strreal;
                      };     
                  }
               }              
            
            }
            catch (Exception ex)    // 这是一个常规的 catch 处理程序，能捕捉一切异常  
            {
                //可以提升异常如下:
                Console.WriteLine(ex); 
            }

            TimerPlc.Enabled = true;
        }

        private void modbusForm_FormClosing(object sender, FormClosingEventArgs e)
        {
           mbrtuComClose(ComPort);  
           
        }
    }
}
