Tài liệu hướng dẫn tự làm thiết bị USB (Phần 3)
Viết chương trình C# giao tiếp với thiết bị USB
Bạn đang xem nội dung tài liệu Tài liệu hướng dẫn tự làm thiết bị USB (Phần 3), để tải tài liệu về máy bạn click vào nút DOWNLOAD ở trên
NguyӉn Ngӑc Hѭng Lӟp TKTL 40 HVKTQS
- 1 -
Phҫn 3:
ViӃt Chѭѫng Trình C# giao tiӃp vӟi thiӃt bӏ USB
1. Tҥo Driver cho thiӃt bӏ và tҥo các thѭ viӋn hàm giao tiӃp USB:
Công viӋc ÿҫu tiên mà bҥn phҧi làm vӟi WinDriver ÿӇ tҥo Driver và các
thѭ viӋn phҫn mӅm cho chѭѫng trình PC cӫa bҥn. Các bѭӟc tiӃn hành bao gӗm:
1. *ҳn thiӃt bӏ cӫa bҥn vào cәng USB trên máy tính computer:
2. Chҥy DriverWizard và chӑn thiӃt bӏ cӫa bҥn:
hình 1: Mӣ hoһc tҥo mӝt WinDriver Project
Chӑn thiӃt bӏ cӫa bҥn trong list cӫa WinDriver:
NguyӉn Ngӑc Hѭng Lӟp TKTL 40 HVKTQS
- 2 -
Chӑn phát ra file Driver và ÿánh tên cho thiӃt bӏ cӫa bҥn:
TiӃp tөc chӑn next ta ÿѭӧc:
7ҥi ÿây bҥn có thӇ kiӇm tra viӋc truyӅn nhұn qua USB xem thiӃt bӏ cӫa bҥn ÿã
hoҥt ÿӝng chѭa. ViӋc tiӃp theo là tҥo ra giao diӋn ban ÿҫu và thѭ viӋn trên C#.
Click và biӇu tѭӧng Generate Code và chӑn ngôn ngӳ mà bҥn sӱ dөng, hiӋn nay
ngôn ngӳ C# thông dөng vӟi nhiӅu ngѭӡi và có nhiӅu tiӋn ích hѫn so vӟi VB
nên ӣÿây tôi chӑn nhѭ sau:
Công viӋc còn lҥi chӍ là OK và chӡ máy chҥy hihi.
NguyӉn Ngӑc Hѭng Lӟp TKTL 40 HVKTQS
- 3 -
Chҥy Project trên Visual Studio 2005 bҥn có thӇ thҩy WinDriver ÿã tҥo cho ta
Pӝt giao diӋn ban ÿҫu ÿӫÿӇ sӱ dөng các giao tiӃp USB, bҥn có thӇ sӱ dөng luôn
giao diӋn này ÿӇ thӵc hiӋn theo Project cӫa bҥn:
Chú ý rҵng bҥn phҧi Project/ Set as Startup Project trѭӟc ÿã.
Nhѭng ÿӇ giúp cho ngѭӡi mӟi hӑc có thӇ hiӇu ÿѭӧc mӝt cách nhanh chóng tôi
xin tӵ tҥo mӝt giao diӋn khác ÿѫn giҧn ngҳn gӑn hѫn bҵng viӋc sӱ dөng các thѭ
viӋn mà WinDriver vӯa tҥo ra cho chúng ta. Ĉó là hai thѭ viӋn
project_usb_4550_lib.dll (thѭ viӋn này do ta ÿһt nó cùng vӟi tên Project khi tҥo
ra) và wdapi_dotnet921.dll hai thѭ viên này chӭa các lӟp và các ӫy quyӅn rҩt
Kӳu ích giúp cho viӋc quҧn lý và thӵc hiên giao tiӃp bҵng USB.
Công viӋc tiӃp theo cӫa chúng ta là hãy tam quên ÿi cái giao diӋn mà WinDriver
Yӯa tҥo ra ӣ trên, và bҳt tay vào tҥo mӝt giao diӋn cӫa chính chúng ta. Vӟi
phѭѫng châm càng ÿѫn giҧn càng tӕt nên hѭӟng dүn này tôi chӍ tҥo mӝt giao
diӋn chӍ vӟi 2 Button và 2 textBox dùng ÿӇÿLӅu khiӇn nhѭ sau:
NguyӉn Ngӑc Hѭng Lӟp TKTL 40 HVKTQS
- 4 -
9ұy là song bѭӟc ÿҫu tiên, bѭӟc tiӃp theo là add 2 thѭ viӋn ӣ trên vào trong
project cӫa mình và nghiên cӭu cách sӱ dөng chúng. NӃu bҥn add thành công thì
Eҥn sӁ thҩy chúng nhѭ sau:
Ta hãy xem chúng có nhӳng gì ( viӋc sӱ dөng chӫ yӃu trên thѭ viӋn
project_usb_4550_lib.dll):
Thѭ viӋn này chӭa 4 uӹ quyӅn (delegates) dành ÿӇ tҥo các sӵ kiӋn quan trӑng
Yӟi bus USB và 4 lӟp, trong ÿó 3 lӟp ÿӇÿLӅu khiӇn thiӃt bӏ USB và mӝt lӟp ÿӇ
NguyӉn Ngӑc Hѭng Lӟp TKTL 40 HVKTQS
- 5 -
quҧn lý danh sách các thiӃt bӏ USB khác nhau ÿѭӧc gán vào PC. Chúng ta hãy
quan sát cө thӇ hѫn vӟi các uӹ quyӅn và các lӟp này:
- 8ӹ quyӅn D_USER_ATTACH_CALLBACK Vӱ dөng ÿӇ gán sӵ kiӋn có
thiӃt bӏ USB thích hӧp gҳn vào bus USB vӟi mӝt hàm callback do bҥn tҥo ra
thѭӡng là khӣi tҥo viӋc truyӅn nhұn dӳ liӋu.
- 8ӹ quyӅn D_USER_DETACH_CALLBACK Ĉѭӧc sӱ dөng ÿӇ gán sӵ
kiӋn thiӃt bӏ USB ÿã ÿѭӧc tháo ra vӟi mӝt hàm gӑi lҥi do bҥn xây dӵng thѭӡng
là thông báo cho nguӡi sӱ dөng vӅ viӋc Disconnect và kӃt thúc viӋc truyӅn nhұn
- 8ӹ quyӅn D_USER_TRANSFER_COMPLETION khá hӳu ích vì nó sӁ
gán sӵ kiӋn truyӅn nhұn kӃt thúc vào mӝt hàm xӱ lý ÿӑc viӃt dӳ liӋu usb do bҥn
xây dӵng.
- 8ӹ quyӅn D_USER_POWER_CHANGE_CALLBACK ít ÿѭӧc sӱ dөng
Kѫn vì nó liên quan ÿӃn viӋc báo ÿӝng thay ÿәi nguӗn trên bus USB, bҥn có thӇ
Wұn dөng ÿӇ thӵc hiӋn các biӋn pháp bҧo ÿҧm cҳt nguӗn bus USB khi có sӵ cӕ.
- /ӟp KEY_USB_Device chӭa các hàm ÿӇ thӵc hiӋn viӋc cài ÿһt cҩu hình
khác nhau cho thiӃt bӏ USB hay hàm ÿӑc các sӕ hiӋu VP, IP và hàm theo dõi
trҥng thái truyӅn nhұn cӫa thiӃt bӏ:
- /ӟp KEY_USB_DeviceManager thӵc hiӋn viӋc quҧn lý thiӃt bӏ USB và
YӅ sӕ lѭӧng thiӃt bӏ USB ÿѭӧc gҳn vào:
- /ӟp KEY_USB_Pipe có sӕ lѭӧng hàm tѭѫng ÿӕi lӟn và chuyên dөng ÿӇ
ÿӑc viӃt dӳ liӋu kiӇm tra trҥng thái truyӅn nhұn, kiӇm soát viӋc khӣi ÿӝng và
Gӯng các ÿѭӡng ӕng…
- Lӟp Pipe_list thӵc hiӋn quҧn lý các ÿѭӡng ӕng vào ra cӫa thiӃt bӏ.
7ұp các hàm này khá linh hoҥt và ÿҫy ÿӫ cho mӑi ӭng dөng USB và bҥn cNJng
không cҫn phҧi tìm hiӇu kƭ tҩt cҧ các hàm ÿó vì chúng ta chӍ cҫn làm viӋc vӟi
Pӝt sӕ hàm nhҩt ÿӏnh là ÿӫÿӇ giao tiӃp.
Bây giӡ là ÿӃn công viӋc khó nhҩt ÿây, ta phҧi viӃt code làm sao cho khi gҳn
thiӃt bӏ vào thì nó phҧi nhұn ÿѭӧc và thӵc hiӋn truyӅn phát dӳ liӋu.
NguyӉn Ngӑc Hѭng Lӟp TKTL 40 HVKTQS
- 6 -
Ý tѭӣng cӫa tôi là dùng Button1(tên là btwrite) ÿӇ thӵc hiӋn viӋc truyӅn dӳ liӋu
ÿѭӧc lҩy trong textBox1(tên là txttrans) tӯ PC xuӕng VĈK, Button2(btread)
dùng ÿӇ lҩy dӳ liӋu tӯ VĈK lên PC hiӇn thӏӣ textBox2(txtLog).
9Ӆ thuұt toán thӵc hiӋn chѭѫng trình chúng ta chӍ hҥn chӃ 3 chӭc năng cѫ bҧn
là ÿӑc, viӃt dӳ liӋu và phát hiӋn thiӃt bӏ gán vào hay tháo ra (hai sӵ kiӋn nhұn
biӃt thiӃt bӏÿӅu ÿѭӧc hiӇn thӏ trên txtLog).
Phҫn khai báo USING cӫa chѭѫng trình chúng ta cҫn mӝt sӕ khai báo nhѭ sau:
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 System.Runtime.CompilerServices;
using Jungo.wdapi_dotnet; //sӯ dӧng thѬ viӉn wdapi_dotnet
using Jungo.project_usb_4550_lib; //sӯ dӧng thѬ viӉn project_usb_4550_lib
using wdu_err=Jungo.wdapi_dotnet.WD_ERROR_CODES;//sӯ dӧng viӉc khai báo lәi
using DWORD = System.UInt32;
using WORD = System.UInt16;
using UCHAR = System.Byte;
phҫn khai báo các biӃn cӫa form chính chúng ta thӵc hiӋn mӝt sӕ khai báo hàng
biӃn và tҥo các ÿӕi tѭӧng sau:
private const string DEFAULT_LICENSE_STRING =
"6C3CC2CFE89E7AD04238DF2EF24449E848CDC187.NguyenNgocHung";
// TODO: If you have renamed the WinDriver kernel module (windrvr6.sys),
// change the driver name below accordingly
private const string DEFAULT_DRIVER_NAME = "windrvr6";
private const WORD DEFAULT_VENDOR_ID = 0x04D8;
private const WORD DEFAULT_PRODUCT_ID = 0x0101;
public const DWORD TIME_OUT = 30000;
private PROJECT_USB_4550_DeviceManager uDevManager; //khai báo khӡi tңo
viӉc quҥn lý ÿӓi tѬӥng USB
private PROJECT_USB_4550_Device usb_device; //khai báo ÿӓi tѬӥng USB
private PROJECT_USB_4550_Pipe usb_pipe_trs; //khai báo ÿӓi tѬӥng ӓng truyӃn
private PROJECT_USB_4550_Pipe usb_pipe_rev; //khai báo ÿӓi tѬӥng ӓng nhүn
private delegate void D_ATTACH_GUI_CALLBACK(PROJECT_USB_4550_Device pDev);
//khai báo өy quyӃn thông báo thiӁt bӍ gұn vào
private delegate void D_DETACH_GUI_CALLBACK(PROJECT_USB_4550_Device pDev);
//khai báo өy quyӃn thông báo thiӁt bӍ tháo ra
delegate void safeLogTextCallBack(string sMsg); //khai báo өy quyӃn phӧc vӧ
hiӅn thӍ
Chúng ta ÿã có 1 ÿӕi tѭӧng quҧn lý USB, 1 ÿӕi tѭӧng thiӃt bӏ USB, 2 ÿӕi tѭӧng
ÿѭӡng ӕng TRANSFER và RECEIVER, các kӃt nӕi, khai báo driver ÿLӅu khiӇn
và các uӹ quyӅn cҫn thiӃt. TiӃp theo chúng ta sӁ xây dӵng các hàm cӫa form
theo các sӵ kiӋn chính. Sӵ kiӋn ÿҫu tiên chúng ta cҫn quan tâm là “form load”
vì nó xҭy ra ÿҫu tiên trong chuӛi sӵ kiӋn vì vұy có thӇ tұn dөng ÿӇ khӣi tҥo mӝt
Vӕ biӃn, ÿӕi tѭӧng cho chѭѫng trình.
private void form_main_Load(object sender, EventArgs e)
{
// ÿăng ký hai hàm sӳ kiӉn ATTACH_CALLBACK & DETACH_CALLBACK
NguyӉn Ngӑc Hѭng Lӟp TKTL 40 HVKTQS
- 7 -
D_USER_ATTACH_CALLBACK dDeviceAttachCb = new
D_USER_ATTACH_CALLBACK(UserDeviceAttach);
D_USER_DETACH_CALLBACK dDeviceDetachCb = new
D_USER_DETACH_CALLBACK(UserDeviceDetach);
//khӡi tңo ÿӓi tѬӥng quҥn lý thiӁt bӍ USB
uDevManager = new
PROJECT_USB_4550_DeviceManager(dDeviceAttachCb, dDeviceDetachCb,
DEFAULT_VENDOR_ID, DEFAULT_PRODUCT_ID, DEFAULT_DRIVER_NAME,
DEFAULT_LICENSE_STRING);
}
Hàm 2 callback xӱ lý 2 sӵ kiӋn Attacth và Detach theo cѫ cҩu trung gian ÿѭӧc
Jӑi ÿӃn 2 hàm UserDeviceAttach & UserDeviceDetach ÿӇ khӣi tҥo các ÿӕi
Wѭӧng AttachCb và DetachCb . Trong hàm này còn thӵc hiӋn viӋc khӣi tҥo thiӃt bӏ
USB và hai ÿѭӡng ӕng TRANSFER & RECEIVER.
private void UserDeviceAttach(PROJECT_USB_4550_Device pDev)
{
D_ATTACH_GUI_CALLBACK AttachCb = new
D_ATTACH_GUI_CALLBACK(DeviceAttachGuiCb);
// khӡi tңo thiӁt bӍ USB
usb_device = pDev;
// khӡi tңo ÿѬӟng ӓng nhүn và truyӃn
usb_pipe_rev =
(PROJECT_USB_4550_Pipe)usb_device.GetpPipesList()[1];
usb_pipe_trs =
(PROJECT_USB_4550_Pipe)usb_device.GetpPipesList()[2];
Invoke(AttachCb, new object[] {pDev});
}
Và:
private void UserDeviceDetach(PROJECT_USB_4550_Device pDev)
{
D_DETACH_GUI_CALLBACK DetachCb = new
D_DETACH_GUI_CALLBACK(DeviceDetachGuiCb);
Invoke(DetachCb, new object[] { pDev });
}
Các hàm DeviceAttachGuiCb & DeviceDetachGuiCb chӍ là các hàm hiӇn thӏ trҥng
thái thiӃt bӏ gҳn vào hay tháo ra.
private void DeviceAttachGuiCb(PROJECT_USB_4550_Device pDev)
{
TraceMsg("Found new device\r\n");
TraceMsg("Your new device is installed and ready to use\r\n");
}
private void DeviceDetachGuiCb(PROJECT_USB_4550_Device pDev)
{
TraceMsg("Your device has detached\r\n");
}
ĈӇ thuұn lӧi cho viӋc hiӇn thӏ trҥng thái chѭѫng trình chúng ta nên bә xung mӝt
Vӕ hàm ÿLӅu khiӇn viӋc xuҩt thông báo ví dө 3 hàm dѭӟi ÿây:
private void SafeLogText(string sMsg)
{
// InvokeRequired compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (txtLog.InvokeRequired)
{
NguyӉn Ngӑc Hѭng Lӟp TKTL 40 HVKTQS
- 8 -
safeLogTextCallBack cb = new
safeLogTextCallBack(SafeLogText);
this.Invoke(cb, new object[] { sMsg });
}
else
{
txtLog.AppendText(sMsg);
}
}
public void TraceMsg(string sMsg)
{
SafeLogText(sMsg);
}
Bây giӡ ta bҳt tay vào viӋc xây dӵng hàm dùng ÿӇ truyӅn nhұn dӳ liӋu. Khi nhҩn
vào button write thì thӵc hiӋn truyӅn mӝt byte xuӕng VĈK:
private void btwrite_Click(object sender, EventArgs e)
{
SingleTransfer();
}
Hàm SingleTransfer();ÿӇ thӵc hiӋn viӃt sӁ lҩy 1 byte ÿã nhұp vào txttrans và
chuyӇn sang dҥng byte ÿӇӣ trong buffer sau ÿó gӑi hàm truyӅn không ÿӗng bӝ:
usb_pipe_trs.UsbPipeTransferAsync(false, 0, buffer,
dwBuffSize, TIME_OUT, new
D_USER_TRANSFER_COMPLETION(Transfer_trs_Completion));
Khi nhҩn vào button read thì thӵc hiӋn nhұn mӝt byte tӯ VĈK lên PC và hiӇn
thӏ ra txtLog.
private void btread_Click(object sender, EventArgs e)
{
SingleReceiver();
}
Hàm SingleReceiver(); tѭѫng tӵ nhѭ hàm SingleTransfer();ÿӇ thӵc hiӋn viӋc
nhұn dӳ liӋu vào bӝÿӋm:
usb_pipe_rev.UsbPipeTransferAsync(true, 0, buffer,
dwBuffSize, TIME_OUT, new
D_USER_TRANSFER_COMPLETION(Transfer_rev_Completion));
Các hàm Transfer_trs_Completion & Transfer_rev_Completion thӵc hiӋn viӋc
thông báo hoàn thành truyӅn hoһc nhұn. Hàm DisplayHexBuffer ÿӇ hӛ trӧ viӋc
hiӇn thӏ giá trӏ thâp lөc phân.
Sau ÿây là toàn bӝ mã cӫa chѭѫng trình:
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 System.Runtime.CompilerServices;
using Jungo.wdapi_dotnet;
using Jungo.project_usb_4550_lib;
using wdu_err = Jungo.wdapi_dotnet.WD_ERROR_CODES;
using DWORD = System.UInt32;
NguyӉn Ngӑc Hѭng Lӟp TKTL 40 HVKTQS
- 9 -
using WORD = System.UInt16;
using UCHAR = System.Byte;
namespace project_usb_4550
{
public partial class form_main : Form
{
private const string DEFAULT_LICENSE_STRING =
"6C3CC2CFE89E7AD04238DF2EF24449E848CDC187.NguyenNgocHung";
private const string DEFAULT_DRIVER_NAME = "windrvr6";
private const WORD DEFAULT_VENDOR_ID = 0x04D8;
private const WORD DEFAULT_PRODUCT_ID = 0x0101;
public const DWORD TIME_OUT = 30000;
private PROJECT_USB_4550_DeviceManager uDevManager;
private PROJECT_USB_4550_Device usb_device
private PROJECT_USB_4550_Pipe usb_pipe_trs;
private PROJECT_USB_4550_Pipe usb_pipe_rev;
private delegate void D_ATTACH_GUI_CALLBACK(PROJECT_USB_4550_Device
pDev);
private delegate void D_DETACH_GUI_CALLBACK(PROJECT_USB_4550_Device
pDev);
delegate void safeLogTextCallBack(string sMsg);
public form_main()
{
InitializeComponent();
}
private void form_main_Load(object sender, EventArgs e)
{
D_USER_ATTACH_CALLBACK dDeviceAttachCb = new
D_USER_ATTACH_CALLBACK(UserDeviceAttach);
D_USER_DETACH_CALLBACK dDeviceDetachCb = new
D_USER_DETACH_CALLBACK(UserDeviceDetach);
uDevManager = new
PROJECT_USB_4550_DeviceManager(dDeviceAttachCb, dDeviceDetachCb,
DEFAULT_VENDOR_ID, DEFAULT_PRODUCT_ID, DEFAULT_DRIVER_NAME,
DEFAULT_LICENSE_STRING);
}
private void UserDeviceAttach(PROJECT_USB_4550_Device pDev)
{
D_ATTACH_GUI_CALLBACK AttachCb = new
D_ATTACH_GUI_CALLBACK(DeviceAttachGuiCb);
usb_device = pDev;
usb_pipe_rev =
(PROJECT_USB_4550_Pipe)usb_device.GetpPipesList()[1];
usb_pipe_trs =
(PROJECT_USB_4550_Pipe)usb_device.GetpPipesList()[2];
Invoke(AttachCb, new object[] {pDev});
}
private void DeviceAttachGuiCb(PROJECT_USB_4550_Device pDev)
{
TraceMsg("Found new device\r\n");
TraceMsg("Your new device is installed and ready to use\r\n");
}
private void UserDeviceDetach(PROJECT_USB_4550_Device pDev)
{
D_DETACH_GUI_CALLBACK DetachCb = new
D_DETACH_GUI_CALLBACK(DeviceDetachGuiCb);
Invoke(DetachCb, new object[] { pDev });
}
NguyӉn Ngӑc Hѭng Lӟp TKTL 40 HVKTQS
- 10 -
private void DeviceDetachGuiCb(PROJECT_USB_4550_Device pDev)
{
TraceMsg("Your device has detached\r\n");
}
private void SafeLogText(string sMsg)
{
// InvokeRequired compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (txtLog.InvokeRequired)
{
safeLogTextCallBack cb = new
safeLogTextCallBack(SafeLogText);
this.Invoke(cb, new object[] { sMsg });
}
else
{
txtLog.AppendText(sMsg);
}
}
public void TraceMsg(string sMsg)
{
SafeLogText(sMsg);
}
private void btwrite_Click(object sender, EventArgs e)
{
SingleTransfer();
}
private void SingleTransfer()
{
DWORD dwBuffSize = 1;
byte[] buffer = new byte[1];
string txt = txttrans.Text;
buffer[0] = Convert.ToByte(txt[0]);
usb_pipe_trs.UsbPipeTransferAsync(false, 0, buffer,
dwBuffSize, TIME_OUT, new
D_USER_TRANSFER_COMPLETION(Transfer_trs_Completion));
}
private void Transfer_trs_Completion(PROJECT_USB_4550_Pipe pipe)
{
if (pipe.GetTransferStatus() ==
(DWORD)wdu_err.WD_STATUS_SUCCESS)
{
TraceMsg("Transfer completed successfully!\r\n ");
}
else
{
TraceMsg("tranfer fail\r\n");
}
}
private void btread_Click(object sender, EventArgs e)
{
SingleReceiver();
}
private void SingleReceiver()
{
DWORD dwBuffSize = 1;
byte[] buffer = new byte[1];
usb_pipe_rev.UsbPipeTransferAsync(true, 0, buffer,
NguyӉn Ngӑc Hѭng Lӟp TKTL 40 HVKTQS
- 11 -
dwBuffSize, TIME_OUT, new
D_USER_TRANSFER_COMPLETION(Transfer_rev_Completion));
}
private void Transfer_rev_Completion(PROJECT_USB_4550_Pipe pipe)
{
if (pipe.GetTransferStatus() ==
(DWORD)wdu_err.WD_STATUS_SUCCESS)
{
TraceMsg(DisplayHexBuffer(pipe.GetBuffer(),1));
}
else
{
TraceMsg("receiver failure!\r\n");
}
}
private string DisplayHexBuffer(byte[] buff, DWORD dwBuffSize)
{
string display = "";
for (DWORD i = 0; i < dwBuffSize; i++)
display = string.Concat(display, buff[i].ToString("X")," ");
display = string.Concat(display, Environment.NewLine);
return display;
}
}
}