Trong thuật toỏn này việc đầu tiờn trước khi truyền là phải thiết lập đường truyền và tiến hành bắt tay giữa 2 đầu thu phỏt. Việc kiểm soỏt quỏ trỡnh truyền bao giờ cũng do một phớa thực hiện, trong trường hợp này là do phớa thu. Đầu thu sẽ kiểm soỏt, điều khiển dũng cỏc gúi dữ liệu.
Đầu tiờn bờn phỏt chờ một mó NAK(15 H trong bảng mó ASCII) từ phớa thu, sau khi nhận được mó cú nghĩa là đầu thu đó sẵn sàng, bắt đầu truyền gúi dữ liệu thứ nhất và chờ phớa thu trả lời. Nếu bờn thu gửi về mó ACK (06H trong bảng mó ASCII cú nghĩa là nhận được gúi tin khụng cú lỗi), hóy truyền gúi dữ liệu tiếp theo.
Nếu là mó NAK cú nghĩa là gúi tin vừa truyền xong bị lỗi cần phải phỏt lại. Nếu là mó CAN(Cancel, 18H) cú nghĩa là yờu cầu dừng cuộc truyền. Nếu cỏc cụng việc kết thỳc bỡnh thường, phớa phỏt gửi mó EOF (04h) bỏo cho phớa thu biết đó truyền hết dữ liệu, phớa thu trả lời bằng một mó ACK, lỳc ấy cú thể tiến hành đúng file, giải phúng bộ nhớ. Thuật toỏn phỏt Xmodem tuõn theo lưu đồ hỡnh 3.1 No No Bắt đầu Đóng gói dữ liệu Thu NAK Đọc gói Kết thúc
Gói tiếp theo
Truyền gói Thu mã trả lời AC K CA N NA K Gửi EOF Thu mã trả lời Yes No Yes Yes No Yes
Hỡnh 3.1 Thuật toỏn phỏt XModem 3.1.2 Thuật toỏn thu XModem
Cụng việc ở đầu thu khụng chỉ đơn giản là thu cỏc dữ liệu mà cũn phải căn cứ vào cỏc trường phục vụ để cú những quyết định phự hợp cho quỏ trỡnh truyền.
Trong thủ tục thu Xmodem sau khi làm cỏc cụng việc chuẩn bị thu như: khởi tạo bộ đệm thu, mở cỏc file... phớa thu gửi đi mó NAK cho biết rằng đó sẵn sàng khởi động vũng thu và chờ Packet, nếu sau 10 giõy mà chưa thấy thỡ gửi tiếp mó NAK nữa. Nếu phỏt hiện cú tớn hiệu thỡ phớa thu thực hiện cỏc bước:
• Xột mó SOH là mó đỏnh dấu đầu khối dữ liệu(nếu là khối cuối cựng thỡ là mó EOF), lỳc này sẽ kết thỳc cuộc truyền.
• Kiểm tra số thứ tự của khối bằng cỏch thực hiện phộp cộng Modul 2 giữa trường thứ 2 và trường thứ 3. Nếu kết quả khỏc khụng nghĩa là cú lỗi thỡ gửi một mó NAK để yờu cầu phỏt lại Packet và quay lại từ đầu, nếu kết thỳc bằng khụng thỡ tiếp tục bước sau.
• Kiểm tra số thứ tự của khối, nếu phỏt hiện nhầm lẫn về trật tự thỡ gửi mó CAN yờu cầu kết thỳc cuộc truyền.
Nếu số thứ tự là liờn tục thỡ tiến hành thu dữ liệu bỡnh thường, tớnh tổng kiểm tra theo thuật toỏn quy định, so sỏnh với tổng kiểm tra phớa phỏt gửi sang, nếu trựng khớp là dữ liệu khụng cú lỗi thỡ gửi một mó ACK, nếu khụng trựng khớp thỡ gửi mó NAK yờu cầu phỏt lại khối dữ liệu đú.
Nếu cuộc truyền kết thỳc tốt, khi nhận được mó EOF phớa thu gửi mó trả lời ACK và thực hiện cỏc bước như đúng file, giải phúng bộ nhớ... sau đú thỡ kết thỳc liờn lạc.
Hỡnh 3.2 Thuật toỏn thu Xmodem
3.2 Chương trỡnh
Chương trỡnh điều khiển Modem được viết trờn DELPHI để chạy trờn cả hệ điều hành đơn nhiệm cũng như trờn hệ điều hành
No Yes Yes No No Yes No Yes Yes No Kết thúc Gửi mã NAK Thu Packet Packet đến ?
Quá thời gian?
EOF
Kiểm tra Packet
Có lỗi Gửi ACK Mất đường truyền Bắt đầu Gửi ACK CAN Thoát
đa nhiệm. Để xõy dựng chương trỡnh điều khiển Modem trước hết ta xõy dựng chương trỡnh Driver Comport (cú tờn là: ComDrv16) điều khiển cho cổng
COM của PC. Khi ghộp thành cụng vào hệ điều hành của mỏy tớnh thỡ xõy dựng tiếp chương trỡnh điều khiển truyền tin qua Modem. Trong tài nguyờn của hệ thống, ta sử dụng cỏc unit WinTypes, WinProcs, Messages, sysUtils ,Classes, Forms...;
Unit SysUtils khai bỏo cỏc lớp và dịch vụ ngoại lệ: classes, string, date, time và dịch vụ tiện ớch. Unit ExtCtrls khai bỏo Component trờn trang chuẩn và trang bổ sung của bảng màu Component. Unit StdCtrls khai bỏo sự xuất hiện Components trờn trang chuẩn của bảng màu Component mà cỏc objects, types và constants kết hợp.
Trong Unit ComDrv16 cú một số thủ tục và hàm quan trọng:
* Hàm SetCommState(); Hàm này đặt thiết bị truyền thụng vào trạng thỏi đặc
tả bởi DCB, khởi tạo lại phần cứng và cơ cấu điều khiển như đó định nghĩa và khụng làm rỗng vựng đệm phỏt và thu.
* Hàm GetCommState(Cid: integer; var DCB: TDCB): integer; Hàm này lấy
lại nội dung DCB của thiết bị. Cid là thiết bị phải được kiểm tra, DCB trỏ tới TDCB nơi nhận nội dung DCB hiện hành. TDCB là định nghĩa cỏc thụng số điều khiển cho thiết bị.
* Hàm KillTimer(Wnd: Hwnd; TDEvent: integer): Bool; Hàm này loại bỏ
đồng hồ ấn định, bất kỳ thụng bỏo nào cũn đợi cú kết hợp với đồng hồ đều bị loại trong hàng đợi.
* Hàm SenData(DataPtr: pointer, Datasize: integer): integer; đõy là hàm gửi
một khối của bộ nhớ. Ngắt khối dữ liệu trong cỏc khối nhỏ hơn nếu nú quỏ rộng để đủ khoảng trống rỗi ở đầu ra buffer.Giỏ trị thuộc tớnh OutputTimeout là thời gian mất cho một gúi nhỏ sẽ gửi. Trở lại DataSize
nếu tất cả OK hoặc giỏ trị nhỏ thua 0, nếu thời gian mất đó xuất hiện(abs(result)) là số của byte gửi.
* Thủ tục ApplyComSetting; là thiết lập thụng số truyền thụng cho cổng Com
của hệ truyền tin, cú nhiệm vụ là:
+ Nếu chưa kết nối thỡ thoỏt. Lấy lại cỏc trạng thỏi hiện hành như tốc độ, cổng, parity....Tốc độ truyền:= một trong những tốc độ đó được khai bỏo. Flags:=mode truyền.
+ Nếu đường yờu cầu truyền (DTR) khụng bị hở thỡ Flags:=mode truyền hoặc yờu cầu thiết bị sẵn sàng.
+ Trường hợp điều khiển dũng dữ liệu bằng phần cứng thỡ; nếu hhnone: khụng dựng. nếu hhRTSCTS: Flags:= mode truyền hoặc CTS được dựng làm cờ chỉ dẫn cho dũng dữ liệu truyền đi hoặc điều khiển dũng dữ liệu RTS ở input.
+ Trường hợp điều khiển dũng dữ liệu bằng phần mềm thỡ; nếu shnone: khụng dựng. nếu shXONXOFF: mode truyền hoặc XON/XOFF được sử dụng khi truyền tin. hoặc XON/XOFF sử dụng khi nhận tin.
+ Số byte tối thiểu được chứa trong input buffer trước khi gửi ký tự XON:= phộp chia lấy phần nguyờn của bộ đệm vào của buffer chia 4. Số byte tối đa được chứa trong input buffer trước khi gửi ký tự XOFF là=1. Số lượng byte:=5+ phần nguyờn của bit dữ liệu. Parity:= lấy phần nguyờn của Fcomportparity. Bit stop:= lấy phần nguyờn của bitstop. Giỏ trị ký tự XON sử dụng cho cả thu và phỏt:=#17. Giỏ trị ký tự XOFF sử dụng cho cả thu và phỏt:=#19.
+ Gọi hàm đặt lại thiết bị truyền thụng vào trạng thỏi đặc tả bởi DCB và thủ tục làm rỗng buffer
Bõy giờ chỳng ta xõy dựng chương trỡnh điều khiển modem (hỡnh 3.3) cũng dưới dạng một unit - unit MainFrm. Trong chương trỡnh này sử dụng chương trỡnh điều khiển driver COMdrv16 nờn trong mục uses phải ghộp thờm COMdrv16 vào.
Hỡnh 3.3. Tổ chức chương trỡnh truyền số liệu qua MODEM.
Khi chương trỡnh thu và phỏt tin qua Modem chạy, một cửa sổ giao diện được mở ra (hỡnh 3.4). Cỏc Menu chức năng cơ bản được thể hiện trờn thanh dụng cụ: connecting, connected, number, disconnect, quit, seting và tắt nằm trờn thanh dụng cụ phớa trờn. Cửa sổ con phớa trờn là cửa sổ thu tin, cửa sổ con phớa dưới là cửa phỏt tin. Mỗi khi tỏc động vào một nỳt thỡ thủ tục tương ứng với chức năng của tờn nỳt đú sẽ được kớch hoạt và đi vào thao tỏc.
Khi ấn connecting menu, tức là muốn kết nối thỡ cửa sổ tham số sẽ hiện ra (hỡnh 3.5). Trờn cửa sổ này cú cỏc nỳt chức năng cho phộp đặt chế độ truyền tin qua cổng COM như tốc độ truyền BAUDRATE, số lượng DATABIT, cơ chế chẵn lẻ PARITY, chế độ bắt tay HANDSHAKING cựng cỏc phớm điều khiển khỏc OK, QUIT.
PC 2 PC 1 Kờnh truyền số liệu trờn chuẩn RS 232C MODEM2 MODEM1
Hỡnh 3.4 Cửa sổ thu phỏt tin qua modem.
Hỡnh 3.5. Thiết lập chế độ thu phỏt cho Modem. Đõy là phiờn liờn lạc với vệ tinh địa tĩnh số 360018.
Đõy là vệ tinh địa tĩnh số 360018 đó nhận được tớn hiệu từ trỏi đất. Xin chào!
CHƯƠNG TRèNH ĐIỀU KHIỂN CỔNG COM unit ComDrv16; interface uses WinTypes, WinProcs, Messages, SysUtils, Classes, Forms; type
{ COM Port Baud Rates :cỏc tốc độ truyền}
TComPortBaudRate = ( br110, br300, br600, br1200, br2400,
br4800, br9600, br14400, br19200, br38400, br57600); { COM Port Numbers : cỏc cổng Com}
TComPortNumber = ( pnCOM1, pnCOM2, pnCOM3, pnCOM4 ); { COM Port Data bits : cỏc bit dữ liệu}
TComPortDataBits = ( db5BITS, db6BITS, db7BITS, db8BITS ); { COM Port Stop bits : cỏc bit stop}
TComPortStopBits = ( sb1BITS, sb1HALFBITS, sb2BITS ); { COM Port Parity : bit parity}
TComPortParity = ( ptNONE, ptODD, ptEVEN, ptMARK, ptSPACE ); { COM Port Hardware Handshaking: điều khiển dũng bằng phần cứng } TComPortHwHandshaking = ( hhNONE, hhRTSCTS );
{ COM Port Software Handshaing : điều khiển dũng bằng phần mềm} TComPortSwHandshaking = ( shNONE, shXONXOFF );
TComPortReceiveDataEvent = procedure( Sender:
TObject; DataPtr: pointer; DataSize: integer ) of object; TCommPortDriver = class(TComponent)
protected
FComPortID : integer; { COM Port Device ID - 0..x }
FComPortBaudRate : TComPortBaudRate; {COM Port speed (brXXXX)} FComPortDataBits : TComPortDataBits; { số lượng bit dữ liệu (5..8)} FComPortStopBits : TComPortStopBits; { số lượng bit stop(1,1.5,2)} FComPortParity : TComPortParity; { kiểu parity (none,odd,even,mark,space)} {kiểu handshaking Hw }
FComPortHwHandshaking: TComPortHwHandshaking; { kiểu handshaking sw }
FComPortSwHandshaking : TComPortSwHandshaking; FComPortInBufSize : word; { dung lượng buffer vào} FComPortOutBufSize : word; { dung lượng buffer ra} { sự kiện xuất hiện dữ liệu thu }
FComPortReceiveData : TComPortReceiveDataEvent; FComPortPollingDelay: word; { ms of delay between COM port pollings }
FEnableDTROnOpen : boolean;{ cho phộp/cấm kết nối đường DTR } FOutputTimeout : word; { output timeout - millisec }
FNotifyWnd : HWND; { sử dụng cho timer } FTempInBuffer : pointer;
{Cỏc phương thức để thực hiện}
procedure SetComPortID( Value: integer );
procedure SetComPort( Value: TComPortNumber );
procedure SetComPortBaudRate( Value: TComPortBaudRate ); procedure SetComPortDataBits( Value: TComPortDataBits ); procedure SetComPortStopBits( Value: TComPortStopBits ); procedure SetComPortParity( Value: TComPortParity );
procedure SetComPortHwHandshaking( Value: TComPortHwHandshaking ); procedure SetComPortSwHandshaking( Value: TComPortSwHandshaking ); procedure SetComPortInBufSize( Value: word );
procedure SetComPortOutBufSize( Value: word ); procedure SetComPortPollingDelay( Value: word );
procedure ApplyCOMSettings;
procedure TimerWndProc( var msg: TMessage ); public
constructor Create( AOwner: TComponent ); override;
Destructor Destroy; override; { chỉ dẫn override được sử dụng để định nghĩa lại phương thức }
function Connect: boolean; {hàm kết nối đỳng} procedure Disconnect; {thủ tục huỷ kết nối} function Connected: boolean; {hàm đó kết nối}
procedure FlushBuffers( inBuf, outBuf: boolean );{giải phúng output buffer}
function OutFreeSpace: word;
function SendData( DataPtr: pointer; DataSize: integer ): integer; {phỏt data} { phỏt ký tự}
function SendString( s: string ): boolean; function SendZString( s: pchar ): boolean;
{đặt đường DTR lờn cao (onOff=TRUE) hoặc xuống thấp(onOff=FALSE)} procedure ToggleDTR( onOff: boolean );
{đặt đường RTS lờn cao (onOff=TRUE) hoặc xuống thấp(onOff=FALSE)} procedure ToggleRTS( onOff: boolean );
property ComPortID: integer read FComPortID write SetComPortID;
published
{gỏn cổng COM }
property ComPort: TComPortNumber read FComPort
write SetComPort default pnCOM2; { gỏn tốc độ cho cổng}
property ComPortSpeed: TComPortBaudRate read FComPortBaudRate
write SetComPortBaudRate default br9600; {số bits dữ liệu (5..8, cho chip 8250) }
property ComPortDataBits: TComPortDataBits read FComPortDataBits
write SetComPortDataBits default db8BITS; { số bits Stop là (1, 1.5, 2) }
property ComPortStopBits: TComPortStopBits read FComPortStopBits
write SetComPortStopBits default sb1BITS; { bit Parity là (none, odd, even, mark, space) }
property ComPortParity: TComPortParity read FComPortParity
write SetComPortParity default ptNONE; { sử dụng kiểu Hardware Handshaking:
cdNONE no handshaking cdCTSRTS cả cdCTS và cdRTS (** thường là sử dụng phương phỏp này**) }
property ComPortHwHandshaking: TComPortHwHandshaking read FComPortHwHandshaking
write SetComPortHwHandshaking default hhNONE; { sử dụng kiểu Software Handshaking:
cdNONE no handshaking
cdXONXOFF XON/XOFF handshaking }
property ComPortSwHandshaking: TComPortSwHandshaking read FComPortSwHandshaking
write SetComPortSwHandshaking default shNONE; { kớch thước bộ đệm vào -Buffer }
property ComPortInBufSize: word
read FComPortInBufSize
write SetComPortInBufSize default 2048; { kớch thước bộ đệm ra- Buffer }
property ComPortOutBufSize: word
read FComPortOutBufSize
write SetComPortOutBufSize default 2048; {giữ chậm (ms) giữa cỏc vũng kiểm tra }
property ComPortPollingDelay: word
read FComPortPollingDelay
write SetComPortPollingDelay default 50; {Đặt TRUE để cho phộp kết nối đường DTR và huỷ khi chưa kết nối. Đặt FALSE để cấm kết nối đường DTR. }
property EnableDTROnOpen: boolean
read FEnableDTROnOpen
write FEnableDTROnOpen default true; {Output timeout (ms) }
property OutputTimeout: word
read FOutputTimeOut
write FOutputTimeout default 4000; {sự kiện cú dữ liệu vào}
property OnReceiveData: TComPortReceiveDataEvent read FComPortReceiveData write FComPortReceiveData;
end;
procedure Register;
{ phần cụng cụ của unit sử dụng cỏc procedures và functions đó khai bỏo trong phần interface }
implementation
{ constructor định nghĩa cỏc hiệu ứng liờn kết với cỏc đối tượng được tạo ra. Nú được khai bỏo dưới dạng từ khoỏ constructor}
constructor TCommPortDriver.Create( AOwner: TComponent ); begin
inherited Create( AOwner ); {khởi tạo cỏc giỏ trị mặc định}
FcomPortID := -1; { chưa kết nối } FcomPort := pnCOM2; { COM 2 } FComPortBaudRate := br9600; { 9600 bauds } FComPortDataBits := db8BITS; { 8 bits dữ liệu} FComPortStopBits := sb1BITS; { 1 bit stop } FComPortParity := ptNONE; { khụng parity }
{khụng sử dụng chế độ bắt tay cứng hardware handshaking } FComPortHwHandshaking := hhNONE;
{khụng sử dụng chế độ bắt tay mềm software handshaking } FComPortSwHandshaking := shNONE;
{ bộ đệm input buffer = 2048 bytes } FComPortInBufSize := 2048;
{ bộ đệm output buffer = 2048 bytes } FComPortOutBufSize := 2048;
FComPortReceiveData := nil; { no data handler }
FComPortPollingDelay := 50; { poll COM port every 50ms } FOutputTimeout := 4000; { output timeout - 4000ms } FEnableDTROnOpen := true; { DTR cao khi kết nối } { Tổ chức bộ đệm cho dữ liệu thu }
GetMem( FTempInBuffer, FComPortInBufSize ); if not (csDesigning in ComponentState) then
{ tạo cửa sổ quản lý để nắm bắt cỏc thụng bỏo thời gian } FNotifyWnd := AllocateHWnd( TimerWndProc );
end;
destructor TCommPortDriver.Destroy; begin
{ chắc chắn rằng COM device đó thoỏt } Disconnect;
{ giải phúng vựng buffer đệm}
{ huỷ bỏ timer's window }
DeallocateHWnd( FNotifyWnd ); inherited Destroy;
end;
{ COM port ID được dựng chung. Điều này cho phộp kết nối với cỏc cổng ngoài. ComPortID = -1--->huỷ }
{---Thủ tục thiết lập cổng dựng chung---}
procedure TCommPortDriver.SetComPortID( Value: integer ); begin
{nếu cựng cổng COM thỡ khụng làm gỡ} if FComPortID = Value then
exit;
{ nếu = 65535 thỡ dừng kiểm tra cổng COM nhưng khụng đúng nú} if Value = 65535 then begin if Connected then { dừng đồng hồ} if Connected then KillTimer( FNotifyWnd, 1 ); FComPortID := -1; end else begin
Disconnect; { huỷ liờn kết}
{nếu < 0 thỡ thoỏt, ComPortID < 0 ---->huỷ } if Value < 0 then
exit;
FComPortID := Value; { Set COM port ID } { khởi động đồng hồ (sử dụng hỏi vũng) }
SetTimer( FNotifyWnd, 1, FComPortPollingDelay, nil ); end;
{---Thủ tục thiết lập cổng Com---}
procedure TCommPortDriver.SetComPort( Value: TComPortNumber ); begin { chắc chắn rằng khụng sử dụng bất kỳ cổng COM nào } if Connected then exit; { đổi cổng COM} FComPort := Value; end;
{---Thủ tục đặt tốc độ mới cho cổng COM ---}
procedure TCommPortDriver.SetComPortBaudRate( Value:
TComPortBaudRate ); begin FComPortBaudRate := Value; if Connected then ApplyCOMSettings; end; {--- Thủ tục đặt data bits ---}
procedure TCommPortDriver.SetComPortDataBits( Value:
TComPortDataBits ); begin FComPortDataBits := Value; if Connected then ApplyCOMSettings; end;
{---Thủ tục đặt lại số lượng stop bit---}
procedure TCommPortDriver.SetComPortStopBits( Value:
TComPortStopBits ); begin FComPortStopBits := Value; if Connected then ApplyCOMSettings; end;
{--- Thủ tục đặt lại số lượng bit parity ---}
procedure TCommPortDriver.SetComPortParity( Value: TComPortParity ); begin
FComPortParity := Value; if Connected then
ApplyCOMSettings; end;
{---Thủ tục đặt lại chế độ hardware handshaking ---}
procedure TCommPortDriver.SetComPortHwHandshaking( Value: TComPortHwHandshaking ); begin FComPortHwHandshaking := Value; if Connected then ApplyCOMSettings; end;
{---Thủ tục đặt lại chế độ software handshaking ---}
procedure TCommPortDriver.SetComPortSwHandshaking( Value: TComPortSwHandshaking ); begin
{ đặt lại giỏ trị thay đổi }
FComPortSwHandshaking := Value; if Connected then
ApplyCOMSettings; end;
{---Thủ tục thiết lập bộ đệm vào Buffer---}
procedure TCommPortDriver.SetComPortInBufSize( Value: word ); begin
{ khụng làm gỡ nếu đó kết nối } if Connected then
exit;
FreeMem( FTempInBuffer, FComPortInBufSize ); { đặt lại kớch thước bộ đệm vào }
FComPortInBufSize := Value; { tổ chức bộ đệm vào}
GetMem( FTempInBuffer, FComPortInBufSize ); end;
{--- Thủ tục thiết lập bộ đệm ra Buffer ---}
procedure TCommPortDriver.SetComPortOutBufSize( Value: word ); begin
{ khụng làm gỡ nếu đó kết nối } if not Connected then
exit;
{ đặt kớch thước bộ đệm ra } FComPortOutBufSize := Value; end;
{---Thủ tục thiết lập thời gian giữ chậm---}
procedure TCommPortDriver.SetComPortPollingDelay( Value: word ); begin
{ nếu thời gian giữ chậm khụng bằng giỏ trị cũ... }