Keresés

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

  • P.H.

    senior tag

    válasz Zso113 #1640 üzenetére

    type f=packed record
    nev: string[255];
    lakcim: string[255];
    eletkor: integer;
    end;
    var
    adatfile: file of f;

    Delphi-ben a string[255] az, ami Pascal-ban a string volt.

  • P.H.

    senior tag

    válasz P.H. #1479 üzenetére

    _READCOMM-ban és _WRITECOMM-ban:

    result:=GETOVERLAPPEDRESULT(com.handle,com.overlap,moved,false);
    (nem látszik a vége), és az utolsó sor mindkettőben:
    if not result then size:=moved; end;
    (not kimaradt).

  • 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]

  • P.H.

    senior tag

    válasz csewe #1475 üzenetére

    Ok, az viszont benn van a munkahelyemen, holnap elhozom. Nem akarok itt és most improvizálni, mert az olvasás, ha minőségi, akkor overlapped kell legyen. Írásnál még elviselhető, hogy addig megáll a program, amíg ki nem írja a teljes adatot, de az olvasás már csak ne működjön úgy, hogy megmondod, hogy mondjuk 1 KB-ot vársz a port-ról, aztán a program 'lefagy', amíg be nem jött a teljes mennyiség. Már ha egyáltalán pontosan tudható, hogy mikor fog jönni.

  • P.H.

    senior tag

    válasz csewe #1473 üzenetére

    Kiírja a portra a megadott adatokat, nem kell visszajelzés. Olvasni vissza a readfile-lal lehet, paraméterei megegyeznek a writefile-lal.

    Egyszerű példa, hogy mennyire alacsony szintű ez: az első próbálkozásom portokkal az volt, hogy megírtam szinte a fenti kódot, hogy olvasson be a COM1-ről 512 byte-ot. ('COM1', és readfile), fogtam egy soros golyós egeret, menet közben rányomtam a COM1-re, persze semmi driver, észre se vette a Windows, elindítottam a programot. Kb. 5 másodpercig húzkodtam az egeret, aztán kiírta a program, hogy megvan az 512 beolvasott byte. Ennyi.

    [mod]: Igazából kiírásnál nem is kell, hogy legyen valami rádugva a port-ra, úgy is sikeres az írás. Csak kinyomja a register-ekbe, mintha OUT-tal írnád.

    [Szerkesztve]

  • P.H.

    senior tag

    válasz csewe #1470 üzenetére

    A writefile írja ki valójában az adatot, de az egész a file-kezelés analógiájára épül (megnyitás-transfer-lezárás), és mivel kizárólagosan nyitja meg a portot (más nem férhet hozzá, amíg nyitva van), legjobb egy egységként kezelni az egész folyamatot.

    A writefile amúgy akármilyen hosszú adatot ki tud küldeni egyszerre, nem kell byte-ozni (paraméterei: handle, a kiírandó buffer címe, a buffer hossza, mutató egy DWORD-re (most Moved), illetve egy nil itt most, visszatérési értéke egy boolean. Akkor sikeres a transfer, ha TRUE-val jön vissza, és a megadott DWORD (Moved) értéke megegyezik a paraméterként megadott buffermérettel.)

    [mod]: az oldal ''The only step you are required to do is call LoadIODLL somewhere at the beginning of your program. Make sure you do this or you will find yourself faced with all sorts of interesting crashes.''
    Az egyetlen lépés, ami szükséges, a LoadIODLL meghívása valahol a program elején. Csináld meg, vagy érdekes/érthetetlen dolgokat fogsz tapasztalni. (Az enyémhez term. nem kell majd. Illetve vagy egy olyan érzésem, hogy az IO.DLL a program teljes ideje alatt fogja a portot. Vagy mindet. De nem ismerem, csak nézegetem az oldalát.)

    [Szerkesztve]

  • P.H.

    senior tag

    válasz csewe #1468 üzenetére

    A createfile első paraméterét 'LPT1'-ról átírod 'LPT2'-re.

  • P.H.

    senior tag

    válasz csewe #1466 üzenetére

    Szerintem feleslegesen bonyolítod a dolgot ezzel a IO.DLL-lel, meg azzal a szemlélettel, hogy kézzel megadott port-ra írsz. Az összes Windows tudja a fenti kódomat, ami persze működik is, kipróbáltam.

    Első ránézésre az IO.DLL link-jére és a kódodra, a LoadIODLL() hívás hiányozik. Az IO.H szerint:
    function LoadIODLL: longint; stdcall; external 'io.dll'.


    [Szerkesztve]

  • P.H.

    senior tag

    válasz csewe #1461 üzenetére

    Az API portkezelő általános portkezelésre van kihegyezve, a kódod valahogy így nézne ki legegyszerűbben, NT alapú Windows-okban (9x alatt már a CreateFile első paramétere):

    var
    ..Data: byte;
    ..Moved: DWORD;
    ..hPort: THANDLE;
    begin
    ..hport:=createfile('LPT1',
    ......(GENERIC_READ or GENERIC_WRITE),
    ......0,
    ......nil,
    ......OPEN_EXISTING,
    ......FILE_ATTRIBUTE_NORMAL,
    ......0);
    ..if hport <> INVALID_HANDLE_VALUE then begin
    ....writefile(hport,data,sizeof(data),moved,nil);
    ....closehandle(hport); end;
    end;


    Ez megnyitja az LPT1 portot írásra-olvasásra, kizárólagos használattal. Ha a kapott handle érvényes (= a megnyitás sikeres), akkor a Data változó tartalmát kiírja a portra, majd lezárja a handle-t.
    Ehhez csak uses Windows; kell a program vagy unit elejére, bár az alapból ott van.

  • P.H.

    senior tag

    válasz csewe #1459 üzenetére

    Gondolom vannak pl. IN és OUT utasítások az assembly részben, ezek Windows alatt nem lehetnek benne felhasználói programokban, csak a kernelben és driver-ekben, azaz privilégizált utasítások (privilege instruction, DOS-ban nincs ilyen megkötés, azért ment Pascal-ban). Tehát a programmal semmi gond, biztosan helyes, csak ez az út járhatatlan.

    Inkább Windows-on (API) keresztül csináld az LPT-vezérlést.

    [Szerkesztve]

  • P.H.

    senior tag

    válasz Bandus99 #1456 üzenetére

    A Thn egy típus.
    Írd be a teljes forrást, úgy könnyebb lesz. (A fentit Delphi4 alatt írtam, ment).

    [mod]: Vagy arról van szó, betű szerint? Hányas Delphi?

    [Szerkesztve]

  • P.H.

    senior tag

    válasz Bandus99 #1453 üzenetére

    Azért nem fordul le, mert a c1 char típusú, a pred(cs) pedig nem. (affene, már mondatot is ;-vel zárok alapban :D )

    esetleg így:

    type Thn = (he, ke, sz, cs, pe, szo, va);
    var
    ..Ch1: Thn;
    begin
    ..ch1:=pred(cs);
    ..writeln(ord(ch1));
    ..readln;
    ..end.


    Azért writeln(ord(ch1)), mert alapban a writeln nem ismeri a Thn típust, így ki lehet íratni az elem index-ét (0-6 között lesz.)

    Ez biztos, hogy Delphi-s, nem sima Pascal? Vagy console-os Delphi program lesz? Csak a readln/writeln miatt kérdem.

    [Szerkesztve]

  • P.H.

    senior tag

    válasz P.H. #1444 üzenetére

    Csak elferült valamiért dőlt betűsre... Na mindegy.
    Még annyi, hogy
    - ha tényleg '0.0' formában jönnek az adatok, akkor magyar Windows alatt mindenképp kell a második, try-except-es rész, az StrToFloat-hoz (default a vesszős elválasztás)
    - a második kódban term. else if áll, 'else of' helyett.
    - a második except-be után akkor is bele fog futni, ha a string végén kevesebb, mint 3 szám van, amellett, hogy ha 1-nél több tizedes-elválasztó van. (a '.1' és a '1.' string-eket nem tudom hirtelen, hogy kezeli-e az StrToFloat helyesen, de talán igen)


    [Szerkesztve]

  • P.H.

    senior tag

    válasz Rolly #1441 üzenetére

    Ha mindenképp a string végén van a 3 lebegőpontos, space-szel elválaszva, akkor haladj hátulról.

    var
    ..I,J,Pos: longint;
    ..Szam: array [1..3] of double;
    ..Data,Temp: string;
    ..begin
    ....data:='szin bela 0,0 0,0 0,0';
    ....for pos:=3 downto 1 do begin i:=length(data);
    ......while (i > 1) and (data <> ' ') do dec(i);
    ......temp:=copy(data,i+1,MAXLONGINT);
    ......szam[pos]:=strtofloat(temp);
    ......delete(data,i,MAXLONGINT); end; end;

    (ha a copy() vagy a delete() utolsó paramétere MAXLONGINT, akkor a string végéig fog másolni/törölni).

    Ha az sem igaz, hogy biztosan space-ekkel vannak elválasztva, akkor
    (data <> ' ') helyett mehet (datain ['0'..'9','.',',' ] ), akkor is törölni fogja az elválasztó karaktert.

    Arra viszont figyelj, hogy ha StrToFloat-tal konvertálod számmá, akkor angol Windows alatt . (pont) a tizedes-elválasztó, magyar alatt pedig ',' (vessző), különben leáll exception-nal. Érdemes így írni, amit írtam fentebb:
    ......try..szam[pos]:=strtofloat(temp);
    ......except for j:=1 to length(temp) do
    ........if temp[j] = '.' then temp[j]:=','
    ........else of temp = ',' then temp[j]:='.';
    ........try szam[pos]:=strtofloat(temp);
    ........except { ekkor hiba van, 2 pont vagy 2 vessző } end; end;

    Ekkor a pontokat lecseréli vesszőre és a vesszőket pontokra, és lemegy, mindegy, milyen nyelvű a Windows. Illetve nem teljesen, mert ha a Vezérlőpontban a tizedes-elválasztót átírták valami másra, akkor így jártak :)

    [mod]: csak normális kinézetű lesz lesz lassan...

    [Szerkesztve]

  • P.H.

    senior tag

    válasz Rolly #1430 üzenetére

    Legegyszerűbben a pos függvénnyel.
    Pl.: i:=pos('amit keresel','amiben keresel').

    Longint típust ad vissza, ha ez nulla, akkor a keresett szöveg nincs a sztringben, nemnulla esetén annak első előfordulási pozíciója.

    [mod]: a kis- és nagybetűk között különbséget tesz.

    [Szerkesztve]

  • P.H.

    senior tag

    válasz Rolly #1423 üzenetére

    A TColorDialog-ot kiteszed a form-ra, majd a programban:

    if ColorDialog1.Execute then xxx:=ColorDialog1.Color;

    Ha az .Execute TRUE-val tér vissza, akkor az OK-ra kattintottak rajta, a .Color-ból olvasható az utolsó kiválsztott szín.

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

Hirdetés