Új hozzászólás Aktív témák

  • P.H.

    senior tag

    válasz csewe #1478 üzenetére

    Valóban megáll LPT portnál, ha nincs rádugva semmi, illetve ha a ''az én cuccom pedig nem válaszol csak végrehajt'' azt jelenti, hogy nem billenti meg az ACK vonalat sem, akkor megoldás az overlapped (magyarul aszinkron) I/O.
    Kérdés: azt nem írtad, hogy a jel kiment azért?

    Az overlapped I/O-t inkább ide írom, még hasznos lehet. 4 kis rutin, ezek mennek LPT-re és COM-ra is, illetve a COM-ra lesz még egy kis toldalék.

    ..uses Windows;
    ..type
    ....TCOMM = record
    ........Handle: THANDLE;
    ........TimeOut: DWORD;
    ........Overlap: OVERLAPPED;
    ........State: DCB; end;
    ..const
    ....COMM_SUCCESS = 0;
    ....COMM_OPEN_FAILED = 1;
    ....EVENT_CREATION_FAILED = 2;
    ....COMM_STATE_SET_FAILED = 3;
    {===================================================================}
    ..function _OPENCOMM(PortName:PCHAR; var Com:TCOMM): byte;
    ....begin
    ......result:=COMM_SUCCESS;
    ......ZEROMEMORY(@com,sizeof(com));
    ......com.handle:=CREATEFILE(portname,
    ..........(GENERIC_READ or GENERIC_WRITE),
    ..........0,
    ..........nil,
    ..........OPEN_EXISTING,
    ..........(FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED),
    ..........0);
    ......if com.handle = INVALID_HANDLE_VALUE then
    ........result:=COMM_OPEN_FAILED
    ......else begin
    ........com.overlap.hevent:=CREATEEVENT(nil,true,false,nil);
    ........if com.overlap.hevent = 0 then begin
    ..........result:=EVENT_CREATION_FAILED;
    ..........CLOSEHANDLE(com.handle); end; end; end;
    {===================================================================}
    ..procedure _CLOSECOMM(var Com:TCOMM);
    ....begin
    ......CLOSEHANDLE(com.overlap.hevent);
    ......CLOSEHANDLE(com.handle); end;
    {===================================================================}
    ..function _READCOMM(var Com:TCOMM; var Size:DWORD; var Dest): boolean;
    ....var Moved: DWORD;
    ....begin
    ......RESETEVENT(com.overlap.hevent);
    ......result:=READFILE(com.handle,dest,size,moved,@com.overlap);
    ......if not result and (GETLASTERROR = ERROR_IO_PENDING) then
    ........begin

    ........WAITFORSINGLEOBJECT(com.overlap.hevent,com.timeout);
    ........result:=GETOVERLAPPEDRESULT(com.handle,com.overlap,moved,false);
    ........end;
    ......if result then size:=moved; end;
    {===================================================================}
    ..function _WRITECOMM(var Com:TCOMM; var Size:DWORD; var Src): boolean;
    .....var Moved: DWORD;
    .....begin
    ......RESETEVENT(com.overlap.hevent);
    ......result:=WRITEFILE(com.handle,src,size,moved,@com.overlap);
    ......if not result and (GETLASTERROR = ERROR_IO_PENDING) then
    ........begin

    ........WAITFORSINGLEOBJECT(com.overlap.hevent,com.timeout);
    ........result:=GETOVERLAPPEDRESULT(com.handle,com.overlap,moved,FALSE);
    ........end;
    ......if result then size:=moved; end;
    {===================================================================}


    Kell egy struktúra, ami tartalmaz minden struktúrát és változót, amit kell: TCOMM
    Kell egy eljárás, ami megnyitja a portot (megkapja a nevét string-ként - 'LPT1', 'LPT2', ..., 'COM1',COM2', ...), és a struktúrát és megnyitja: _OPENCOMM. Ha a megnyitás sikertelen, akkor visszaadja, hogy miért (a port foglalt vagy nem létezik, illetve segédváltozó kreálása sikertelen).
    Kell egy eljárás, ami bezárja a portot: _CLOSECOMM
    Kell egy-egy író és olvasó eljárás: _WRITECOMM és _READCOMM. Ezek megkapják, hogy honnan/hova és hány byte-ot olvassanak be vagy írjanak ki, illetve közvetve a struktúrában a kísérleti időt millisecundum-ban: TimeOut mező (hogy ne kelljen minden egyes alkalommal megadni). Vissza boolean, hogy sikerült-e a teljes transfer, illetve ha nem, akkor a méretváltozóban visszadja, hogy ténylegesen mennyi sikerült a megadott idő alatt.

    Ezekkel egy egyszerű rutin:
    ..procedure TForm1.StartClick(Sender:TObject);
    ....var
    ......Data:byte;
    ......Bytes: DWORD;
    ......lpt2: TCOMM;
    ....begin
    ......data:=1;
    ......if _OPENCOMM('LPT2',lpt2) = COMM_SUCCESS then begin
    ........lpt2.timeout:=5000;
    ........bytes:=sizeof(data);
    ........_WRITECOMM(lpt2,bytes,data);
    ........_CLOSECOMM(lpt2); end; end;

    A megnyitás után beállítja a timeout-ot (most 5000 ms), majd kiír a portra (jelen esetben, ha minden igaz, tartja a byte-ot a kimeneten, mivel ACK nem érkezik), majd lezárja. Gondolom, sejthető, hogy neked akkor nem is kell timer így, mivel a _WRITECOMM-ot kell egy ciklusba tenni, mivel az 5 másodpercenként fog visszatérni, FALSE-szal ugyan, de az nem érdekes.

    A fentiek hasonlóan működnek 'COMx' portnév megadásával is, de ott az _OPENCOMM után lehetőség van a paraméterek beállítására, pl. így (most legyen com1 a struktúra neve):
    ..GETCOMMSTATE(com1,com1.state);
    ....with com1.state do begin
    ......baudrate:=9600;
    ......bytesize:=8;
    ......parity:=EVENPARITY;
    ......stopbits:=ONESTOPBIT; end;
    ....SETCOMMSTATE(com1,com1.state);

    Gondolom, kommentálni nem kell, hogy mit jelent a jelenlegi beállítások lekérése, egyes paraméterek átírása, majd beállítás.

    A progamozási stílus remélet átlátható, az API-hívások, a belsőeljárás-nevek és a konstansok nagybetűsek, és igyekeztem a lehető legkevesebb utasítást egy sorban hagyni.


    [Szerkesztve]

Új hozzászólás Aktív témák

Hirdetés