LAB 3, Lab 3 (RS232), program Nadajnik;


Treść zadania

Napisać program nadajnika i odbiornika, który będzie wysyłał plik za pomocą protokołu znakowego i za pomocą portu RS232.

Sposób rozwiązania

Ze względu na to, że dostępne były trzy komputery, podzieliliśmy rozwiązanie zadania na trzy części. Pierwszą z nich było przygotowanie fizycznej transmisji, do której zaliczyliśmy napisanie procedur obsługi portu RS232, kodowanie i dekodowanie znaków. Na drugim komputerze pisany był program nadajnik, natomiast na trzecim program odbiornik.

Uznaliśmy, że program, który był do napisania musiał składać się kilku faz: nawiązanie komunikacji, przesłanie nagłówka oraz przesłanie danych. Uzgodniliśmy, za przesyłane bloki będą miały po 128 znaków (7-bitowych), oraz że nagłówek zmieści się w pierwszym bloku i będzie zawierał nazwę kopiowanego pliku, a danymi będzie zawartość pliku. Kolejnym założeniem (program nadajnik) było to, że dane będą odczytywane z pliku i przesyłane po zakodowaniu do bufora, a po jego zapełnieniu nastąpi automatyczne „wysłanie” paczki danych wraz ze wszystkimi znakami sterującymi. Program odbiornik, wstępnie ma oczekiwać (odczytywać) port RS232 i po otrzymaniu informacji o rozpoczęciu transmisji odbierać znaki i zapamiętywać je w buforze. Tam z kolei będą one analizowane i w przypadku otrzymania znaków sterujących wykonywane odpowiednie akcje:

znak SOH - w buforze powinien znajdować się nagłówek do znaku STX,

znak ETB (lub ETX) - nastąpił koniec bloku, należy zdekodować zawartość bufora i po

sprawdzeniu z sumą kontrolną zapisać do pliku,

znak ETX - oznacza, że należy zamknąć plik, zakończyć transmisję i zakończyć działanie

programu.

Poniżej przedstawiony został kod źródłowy nadajnika:


program Nadajnik;uses Crt, Dos;const nr_Portu = 0; {stała oznaczająca port 1}

SOH=$01; {stałe znaków sterujących protokółu} STX=$02; ETX=$03; EOT=$04; ENQ=$05; ACK=$06; DLE=$10; NAK=$15; SYN=$16;

ETB=$17;

BlockLen = 126; {długość bloku}

var

Bufor: array [0..127] of Byte;

BufLen: integer;

LastH: Byte;

procedure InitData; {procedura ustawia zmienne pomocnicze}

begin

BufLen:=-1;

end;

procedure InitRS; {procedura inicjalizacji portu szeregowego}

Var

r : Registers;

Begin

r.ah:=0;

r.dx:=nr_portu;

r.al:=3+128+64+32; {ustawienia konfiguracyjne portu}

Intr($14,r);

End;

procedure SendB(zn : Byte); {procedura wysyłająca znak za pomocą portu szeregowego}

Var

r : Registers;

Begin

Delay(10);

repeat

r.ah:=3;

r.dx:=nr_portu;

Intr($14,r); {sprawdzanie statusu portu}

Until ((r.ah And 32) <> 0); {oczekiwanie na gotowość}

r.ah:=1;

r.dx:=nr_portu;

r.al:=zn;

Intr($14,r); {wysłanie znaku}

End;

function GetB(Var zn : Byte) : Boolean; {procedura odebrania znaku z portu szeregowego}

Var

r : Registers;

Begin

r.ah:=2;

r.dx:=nr_portu;

Intr($14,r);

zn:=r.al;

GetB:=(r.ah And 128 = 0);

End;

procedure Koduj(s : Byte;var res1,res2:Byte); {procedura kodująca znak s na dwa znaki 7 bitowe różne od kodów sterujących}

begin

res1:=(((s And $F0) SHR 4) +32);

res2:=((s And $0F) +32);

end;

function OdbierzPotw:Boolean; {sprawdza czy odczytano potwierdzenie transmisji}

var

ret: Boolean;

B: Byte;

begin

ret:=GetB(B);{odczyt znaku z portu}

ret:=(B=ACK);{czy jest to potwierdzenie transmisji}

OdbierzPotw:=ret;

end;

procedure Zakoncz(Err: String); {Wystąpił błąd transmisji}

begin

writeln(Err);

halt;

end;

procedure Rozlacz(Err: String); {rozłącznie połączenia}

begin

SendB(DLE);

SendB(EOT);

Zakoncz(Err);

end;

procedure SendBlock(EndOfData: Boolean); {wysłanie bloku danych}

var

B1, B2, LRC: Byte;

i, ile: integer;

OK: Boolean;

begin

ile:=0; {Ilość prób transmisji}

repeat

LRC:=0;

for i:=0 to BufLen do begin

LRC:=LRC xor Bufor[i]; {obliczanie sumy kontrolnej}

SendB(Bufor[i]); {wysyłanie znaku}

end;

{Koniec Danych}

if EndOfData then begin {gdy wysyłany jest ostatni pakiet danych}

LRC:=LRC xor ETX;

SendB(ETX); {wysłanie znaku końca danych}

end else begin {pozostały jeszcze dane do wysłania}

LRC:=LRC xor ETB;

SendB(ETB); {wysłanie znaku końca bloku}

end;

Koduj(LRC, B1, B2); {zakodowanie sumy kontrolnej}

SendB(B1); {wysłanie sumy kontrolnej na dwoch znakach}

SendB(B2);

ile:=ile+1;

OK := OdbierzPotw; {odebranie potwierdzenia przyjęcia danych}

until (OK) or (ile=3); {maksymalnie 3 próby transmisja}

if i=3 then Rozlacz('Blad podczas transmisji'); {wystąpł 3-krotnie błąd transmisji}

BufLen:=0;

Bufor[0]:=LastH;

end;

procedure PutB(B: Byte); {procedura wpisująca znaki do bufora}

begin if B=SOH then LastH:=SOH else if B=STX then LastH:=STX; BufLen:=BufLen+1; {zwiększenie ilości znaków w buforze}

Bufor[BufLen]:=B; {wprowadzenie kolejnego znaku do bufora}

if (BufLen=BlockLen-1) and (Bufor[0]=SOH) then SendBlock(false) else

if BufLen=BlockLen then SendBlock(false);

{wysłanie bufora gdy pełny lub gdy wysyłamy nagłówek i bufor już prawie pełny}

end;

procedure PackB(B: Byte); {wprowadzenie znaku do bufora}

var

b1, b2: Byte;

begin

Koduj(B, b1, b2); {kodowanie znaku na dwa 7 bitowe}

PutB(b1); {wprowadzenie do bufora}

PutB(b2); {wprowadzenie do bufora}

end;

function WyslijPoczatek:Boolean; {funkcja nawiązująca transmisje}

begin

Writeln(`Proba nawiązania transmisji');

SendB(EOT); {nawiązanie transmisji}

SendB(64); {adres odbiorcy}

SendB(35);

SendB(ENQ);

WyslijPoczatek:=OdbierzPotw; {sprawdzenie poprawności}

end;

procedure Polacz; {procedura nawiązująca połączenie}

var

naw: Boolean;

i: integer;

begin

i:=0;

repeat

naw:=WyslijPoczatek; {nawiązanie transmisji true-> zakończona sukcesem}

i:=i+1;

until (i=3) or (naw); {3 krotna próba nawiązania połączenia}

if naw=false then Zakoncz('Polaczenie nie zostalo nawiazane')

else Writeln(`Nawiązano połączenie');

end;

procedure WyslijPlik(path, name: string); {procedura wysyłająca plik}

var

f: File;

i, j: integer;

b: Byte;

begin

PutB(SOH); {rozpoczęcie transmisji „danych”}

for i:=1 to Length(name) do {wysłanie nazwy pliku przesyłanego}

PackB(ord(name[i]));

PutB(STX); {następny znak to „właściwe dane”}

assign(f, path+name); {otwarcie pliku}

reset(f, 1);

while not(eof(f)) do begin

BlockRead(f, b, 1, i); {odczytanie bloku danych}

PackB(b); {wysłanie do bufora 1 bajtu danych}

end;

close(f); {zamknięcie pliku}

SendBlock(true); {wysłanie danych w buforze}

end;

procedure przeslanie; {procedura realizująca transmisję danych}

begin

InitData; {inicjalizacja danych}

Polacz; {inicjalizacja połączenia}

WyslijPlik('','nazwa.txt'); {wysłanie pliku}

SendB(EOT); {wysłanie znaku końca transmisji}

Rozlacz('Plik przeslany'); {rozłączenie transmisji}

end;

begin

clrscr;

InitRS; {konfiguracja RS232}

przeslanie; {transmisja}

end.


Poniżej został przedstawiony kod źródłowy odbiornika:


Program Odbiornik;uses Crt, Dos;const nr_Portu = 1; {stała określająca numer portu RS232}

SOH=$01; {kody sterujące transmisją znakową}

STX=$02;

ETX=$03;

EOT=$04;

ENQ=$05;

ACK=$06;

DLE=$10;

NAK=$15;

SYN=$16;

ETB=$17;

BlockLen = 126; {długość danych}

var

Bufor: array [0..255] of Byte;

BufLen: integer;

LastH: Byte;

procedure InitData; {inicjalizacja daty}

begin

BufLen:=-1;

end;

procedure InitRS; {procedura inicjalizująca port RS232}

Var

r : Registers;

Begin

r.ah:=0;

r.dx:=nr_portu;

r.al:=3+128+64+32; {ustawienia transmisji}

Intr($14,r);

End;

procedure SendB(zn : Byte); {procedura wysyłająca znak na port RS232}

Var

r : Registers;

Begin

delay(10);

r.ah:=1;

r.dx:=nr_portu;

r.al:=zn; {wysłanie znaku}

Intr($14,r);

End;

procedure GetB(Var zn : Byte); {procedura odbierająca znak z portu RS232}

Var

r : Registers;

Begin

r.ah:=2;

r.dx:=nr_portu;

Intr($14,r);

zn:=r.al;

End;

Procedure Dekoduj(Var zn : byte; res1,res2 : byte); {Procedura zwracająca znak zdekodowany z dwóch znaków odebranych}

Begin

zn:=((((res1) -32) SHL 4) + ((res2) -32));

End;

procedure Odbieraj; {procedura odbierająca przesyłany plik i zapisująca go na dysk}

var

plik: file;

napis: string;

i, j: integer;

B1, B2, LRC, N_LRC, B, zn: byte;

begin

GetB(B); {odebranie znaku z portu RS232}

if (B<>ETX) and (B<>ETB) then begin {odebrano znak różny od końca transmisji lub bloku}

BufLen:=BufLen+1;

Bufor[BufLen]:=B; {zapamiętanie znaku w buforu}

end else begin {wystąpił znak końca transmisji lub bloku}

{************** obliczanie sumy kontrolnej **************}

LRC:=0; {zerowanie sumy kontrolnej}

for i:=0 to BufLen do LRC:=LRC xor Bufor[i]; {obliczenie sumy kontrolnej}

LRC:=LRC xor B; {obliczenie sumy kontrolnej dla odczytanego znaku}

GetB(B1); {odebranie dwóch znaków sumy kontrolnej}

GetB(B2);

Dekoduj(N_LRC, B1, B2); {dekodowanie sumy kontrolnej na znak 8 bitowy}

if LRC<>N_LRC then writeln('ZLE LRC'); {wystąpił błąd sumy kontrolnej}

if (N_LRC=LRC) then begin {prawidłowa suma kontrolna} SendB(ACK); {transmisja OK., wysłanie potwierdzenia poprawnej transmisji} Writeln(`Odebrano poprawnie przesyłane dane');

i:=1;

{ ***************** odczyt nahgłówka ****************************}

if Bufor[0]=SOH then begin {odczytanie nagłówka w bloku} napis:=''; while Bufor[i]<>STX do begin {nagłówek zakończony jest znakiem STX} Dekoduj(zn, Bufor[i], Bufor[i+1]); {dekodowanie znaku}

napis:=napis+chr(zn); {zamiana na nazwę pliku przesyłanego}

i:=i+2;

end; {endwhile - dopóki nie natrafi na znak STX - końca nagłówka }

assign(plik, napis); {otwarcie pliku}

rewrite(plik, 1);

i:=i+1;

end; { endif - odczytanie nagłówka w bloku }

{******************* odczyt danych ******************************} while (i<BufLen) do begin {jeżeli nie osiągnięto końca bufora} Dekoduj(zn, Bufor[i], Bufor[i+1]); {dekodowanie znaku z bufora}

i:=i+2;

BlockWrite(plik, zn, 1, j); {zapis zdekodowanego znaku do pliku}

write(chr(zn)); {zapis zdekodowanego znaku na ekran}

end; {endwhile osiągnięto koniec bufora}

if B=ETX then begin {otrzymano znak końca transmisji}

Writeln(`Zakończono prawidłowo transmisję danych');

Close(plik); {zamknięcie pliku}

halt;

end; {endif otrzymano znak końca transmisji}

end else {endif - poprawna suma kontrolna}

SendB(NAK); {wysłanie żądania powtórnego wysłania danych nieprawidłowe CRC} BufLen:=-1; end; {endif - wystąpił znak końca transmisji lub bloku}}

end;

var B:Byte;begin InitRS; {inicjacja portu szeregowego} repeat GetB(B); {oczekiwanie na nawiązanie transmisji} until B=ENQ;

Writeln(`Nawiązano transmisje...'); SendB(ACK); {wysłanie potwierdzenia nawiązania transmisji}

BufLen:=-1;

repeat

Odbieraj; {odbieranie danych}

until keypressed;

end.


Wnioski

Pierwszą rzeczą na jaką zwróciliśmy uwagę, było kodowanie znaków. Należy zapewnić takie kodowanie aby nie były używane znaki sterujące transmisją do kodowania znaków przesyłanych. Tak więc algorytm kodujący nie tylko musi być jednoznaczny (aby było możliwe dekodowanie), ale również nie może używać znaków specjalnych (sterujących).

Kolejną sprawą był transfer danych przez port RS232. Ze względu, iż dane byłe szybko obliczane należało (szczególnie przy transmisji) sprawdzać gotowość portu do wysłania kolejnego znaku. Było to głównym (i chyba jedynym) powodem dla jakiego nie udało nam się przy pierwszym uruchomieniu programu poprawnie odebrać dane. Kolejną ważną rzeczą jest ścisłe przestrzeganie protokołu, szczególnie zaś wysyłania potwierdzeń transmisji, kontroli ilości prób. Wypisywanie komunikatów o błędach podczas nawiązywania i samej transmisji jest znacznym ułatwieniem w usuwaniu problemów. Uruchomienie odbiornika, zaczęliśmy od programu wypisującego znaki, które były „wysyłane” i szukania przyczyn błędów. Umożliwiło to wykrycie błędów zarówno w nadajniku jak i odbiorniku

W rezultacie uzyskaliśmy podczas laboratorium poprawny i działający program realizujący przesył zawartości pliku między komputerami.



Wyszukiwarka

Podobne podstrony:
1 MDM lab Obsługa programu Rosette Plusid 8935
Zadania dodatkowe, studia wsiz, semestr 1 2, programowanie LAB wyklad, Programowanie, BFryc, 1IID, Z
Laboratorium nr 2 tablice, studia wsiz, semestr 1 2, programowanie LAB wyklad, Programowanie, BFryc,
Lab 04 Programowanie w jezyku powloki
Mechanika plynow - lab. pytania z programu, Inżynieria Środowiska rok2, Mechanika płynów
Podstawy Programowania Lab 1 dod
Fizyka 14b, AGH, agh, programinski, Laborki, Laborki, Lab, FIZYKA - Laboratorium, fiz lab, franko
Polarymetr Laurenta, AGH, agh, programinski, Laborki, Laborki, Lab, FIZYKA - Laboratorium, Polarymet
cw 13 - Lepkosc, AGH, agh, programinski, Laborki, Laborki, Lab, FIZYKA - Laboratorium, Struna i Krzy
FIZYKA~6, AGH, agh, programinski, Laborki, Laborki, Lab, FIZYKA - Laboratorium, lab-fizyka, Moduł sz
cwiczenie10d2013, WSTI Pawia 55, Semestr I, Podstawy programowania (wyk, lab - L.Grad, Laboratoria
lab 2, Edukacja, ZiIP, sem. I, Podstawy programowania, Laborki i inne, Podstawy Programowania
cwiczenie8d2013, WSTI Pawia 55, Semestr I, Podstawy programowania (wyk, lab - L.Grad, Laboratoria
cwiczenie13d2012, WSTI Pawia 55, Semestr I, Podstawy programowania (wyk, lab - L.Grad, Laboratoria

więcej podobnych podstron