2012年5月17日 星期四

USB NetPower 8800 SDK 從 C++ 轉成 C# - Part 2

今天繼續USB NetPower 8800 SDK 從 C++ 轉成 C# - Part 1未完成的工作,先用 Google尋找一下有關PL2303的資料,結果找到了這一家萬平科技網,這家公司主要是提供 USB to(轉) Serial(UART/TTL/RS232/RS485)的應用開發工具,這家的網路上有提供PL2303 HXD原廠的4 * GPIO sample code及使用手冊,下載 sample code 並執行 PL2303 4 GPIO Test.exe,畫面如下:

PL-2303 4 GPIO Test
很順利開啟連接埠,接著試用 GP0 及 GP1 等功能,發現 Net Power 只有用到 GP1,當 GP1 的值設成是 1 時插座供電,設成0時插座斷電:

測試 GP0 及 GP1
測到這我已經大概了解 C++ 對這 NetPower 所作的動作,現在就要來把 C++ 改成 C#
,這裡我是用 CreateFile 的 方式,由於 C# 已經不像 C++ 有提供 CreateFile 所以要用 Dllimport



[DllImport("kernel32.dll")]
        private static extern IntPtr CreateFile(
        string lpFileName,
        uint dwDesiredAccess,
        int dwShareMode,
        IntPtr lpSecurityAttributes,
        int dwCreationDisposition,
        uint dwFlagsAndAttributes,
        IntPtr hTemplateFile
         );
使用如下:


 pl2303 = CreateFile("COM8",
                                    GENERIC_READ | GENERIC_WRITE,
                                    0,
                                    IntPtr.Zero,
                                    OPEN_EXISTING,
                                    FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
                                    IntPtr.Zero);


由於 C# 也沒有 define 要把原有 C++中的 define 改成:


public const uint GENERIC_READ = 0x80000000;
public const uint GENERIC_WRITE = 0x40000000;
public const int OPEN_EXISTING = 3;


在來是要改 DeviceIoControl:


[DllImport("kernel32.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
        internal static extern bool DeviceIoControl(
            IntPtr hDevice,
            uint dwIoControlCode,
            ref byte lpInBuffer,
            uint nInBufferSize,
            ref byte lpOutBuffer,
            int nOutBufferSize,
            ref uint lpBytesReturned,
            IntPtr lpOverlapped);




原有在 C++ 中定義的 CTL_CODE也要改成 function 的型態:


static uint CTL_CODE(uint DeviceType, uint Function, uint Method, uint Access)
        {
            return ((DeviceType << 16) | (Access << 14) | (Function << 2) | Method);
        }


同樣的也要宣告:


 private const uint FILE_FLAG_OVERLAPPED = 0x40000000;
 private const uint FILE_DEVICE_UNKNOWN = 0x00000022;
 private const uint FILE_ATTRIBUTE_SYSTEM = 0x00000004;
 private const uint USB2SER_IOCTL_INDEX = 0x0800;
 private const uint METHOD_BUFFERED = 0;
 private const uint FILE_ANY_ACCESS = 0;




DeviceIoControl 在 C# 中的用法如下:



 uint GP1_SET_VALUE = CTL_CODE(FILE_DEVICE_UNKNOWN, USB2SER_IOCTL_INDEX + 23, METHOD_BUFFERED, FILE_ANY_ACCESS);


bool bSuccess = DeviceIoControl(hDrv, GP1_SET_VALUE, ref val, sizeof(byte), ref dummybyte,
                            0,
                            ref nBytes,
                            IntPtr.Zero);



因為時間有限,所以我只改了設定GP1:

GP1_SetValue
GP1_GetValue
GP1_Enable


我改好的 C# 程式執行畫面如下:


C# for USB Netpower
完整的程式如下:


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 Form1 : Form
    {
        public const int FILE_ATTRIBUTE_NORMAL = 0x00000080;
        public const uint GENERIC_READ = 0x80000000;
        public const uint GENERIC_WRITE = 0x40000000;
        public const int OPEN_EXISTING = 3;
        // public const UInt32 INVALID_HANDLE_VALUE = 0xffffffff;


        private const uint FILE_FLAG_OVERLAPPED = 0x40000000;
        private const uint FILE_DEVICE_UNKNOWN = 0x00000022;
        private const uint FILE_ATTRIBUTE_SYSTEM = 0x00000004;
        private const uint USB2SER_IOCTL_INDEX = 0x0800;
        private const uint METHOD_BUFFERED = 0;
        private const uint FILE_ANY_ACCESS = 0;










        public Form1()
        {
            InitializeComponent();
        }


        IntPtr pl2303 = (IntPtr)(-1);


        static uint CTL_CODE(uint DeviceType, uint Function, uint Method, uint Access)
        {
            return ((DeviceType << 16) | (Access << 14) | (Function << 2) | Method);
        }


        private void button1_Click(object sender, EventArgs e)
        {
            if (pl2303 == (IntPtr)(-1))
            {
                pl2303 = CreateFile("COM8",
                                    GENERIC_READ | GENERIC_WRITE,
                                    0,
                                    IntPtr.Zero,
                                    OPEN_EXISTING,
                                    FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
                                    IntPtr.Zero);
                button1.Text = "關閉通訊埠";
            }
            else
            {
                CloseHandle(pl2303);
                button1.Text = "開啟通訊埠";
                pl2303 = (IntPtr)(-1);
            }


        }


        private void button2_Click(object sender, EventArgs e)
        {
            if (pl2303 != (IntPtr)(-1))
            { // pl2303 open success
                byte val = 0;
                if (PL2303_GP1_GetValue(pl2303, ref  val))
                {
                    // button2.Text = val.ToString();
                    if (val == 0)
                    {
                        if (PL2303_GP1_Enable(pl2303))
                        {
                            if (PL2303_GP1_SetValue(pl2303, 1))
                            {
                                button2.Text = "插座断電";
                            }
                        }
                        else
                        {
                            MessageBox.Show("enable fail");
                        }
                    }
                    else
                    {
                        if (PL2303_GP1_Enable(pl2303))
                        {
                            if (PL2303_GP1_SetValue(pl2303, 0))
                            {
                                button2.Text = "插座通電";
                            }
                        }
                        else
                        {
                            MessageBox.Show("enable fail");
                        }
                    }


                }
            }
            else
            {
                MessageBox.Show("通訊埠尚未開啟");
            }


        }
        private bool PL2303_GP1_SetValue(IntPtr hDrv, byte val)
        {
            uint nBytes = 0;
            byte dummybyte = 0;
            uint GP1_SET_VALUE = CTL_CODE(FILE_DEVICE_UNKNOWN, USB2SER_IOCTL_INDEX + 23, METHOD_BUFFERED, FILE_ANY_ACCESS);
            bool bSuccess = DeviceIoControl(hDrv, GP1_SET_VALUE, ref val, sizeof(byte), ref dummybyte,
                            0,
                            ref nBytes,
                            IntPtr.Zero);


            return bSuccess;
        }


        private bool PL2303_GP1_GetValue(IntPtr hDrv, ref byte val)
        {
            uint nBytes = 0;
            byte dummybyte = 0;
            uint GP1_GET_VALUE = CTL_CODE(FILE_DEVICE_UNKNOWN, USB2SER_IOCTL_INDEX + 25, METHOD_BUFFERED, FILE_ANY_ACCESS);




            bool bSuccess = DeviceIoControl(hDrv, GP1_GET_VALUE, ref dummybyte, 0, ref val,
                            sizeof(byte),
                            ref nBytes,
                            IntPtr.Zero);


            return bSuccess;
        }


        private bool PL2303_GP1_Enable(IntPtr hDrv)
        {
            uint nBytes = 0;
            byte enable = 1;
            byte dummybyte = 0;
            uint GP1_OUTPUT_ENABLE = CTL_CODE(FILE_DEVICE_UNKNOWN, USB2SER_IOCTL_INDEX + 21, METHOD_BUFFERED, FILE_ANY_ACCESS);


            bool bSuccess = DeviceIoControl(hDrv, GP1_OUTPUT_ENABLE, ref enable, sizeof(byte), ref dummybyte,
                            0,
                            ref nBytes,
                            IntPtr.Zero);




            return bSuccess;
        }


        [DllImport("kernel32.dll")]
        private static extern IntPtr CreateFile(
        string lpFileName,
        uint dwDesiredAccess,
        int dwShareMode,
        IntPtr lpSecurityAttributes,
        int dwCreationDisposition,
        uint dwFlagsAndAttributes,
        IntPtr hTemplateFile
         );


        [DllImport("kernel32.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
        internal static extern bool DeviceIoControl(
            IntPtr hDevice,
            uint dwIoControlCode,
            ref byte lpInBuffer,
            uint nInBufferSize,
            ref byte lpOutBuffer,
            int nOutBufferSize,
            ref uint lpBytesReturned,
            IntPtr lpOverlapped);


        [DllImport("kernel32.dll", SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        static extern bool CloseHandle(IntPtr hObject);
    }
}