rs232 - gotowość do odbioru danych

0

Witajcie.
Proszę o drobną pomoc(podpowiedź), bo sam już sobie nie radzę.
Temat jest taki: Drukarka PosnetThermal i odczyt danych z Delphi przez rs232.
Z większością problemów sobie poradziłem, natomiast mam problem z odczytem danych.

Jednym buttonem naciskam "wyślij" - jest OK.
Drugim buttonem naciskam "odbierz" - też jest OK
ALE jeżeli w jednej procedurze dam wyślij i odbierz to bufor jest pusty i muszę dawać sleep(100) że by odczytać dane.

oto mój kod.

Tego chyba nie trzeba opisywać.

procedure TForm1.Button3Click(Sender: TObject);
var
  S : string;
begin
  SetLength(S,2048);
  PosNet.Port_Open(PortNr,PortSpeed);
  PosNet.SendSequence(Trim(Edit1.Text),False);
  PosNet.ReadSequence(S,2048);
  memo1.Lines.Add(S);
end;

Otwieranie portu.

function TComPortClass.Open(iPort:byte; aBaudRate: DWORD): Integer;
var
  aPortName   : PChar;
begin
	if not (iPort in [1..99]) then begin
    Result := SERROR;
    exit;
  end;

  aPortName := pchar('COM'+IntToStr(iPort));

{
	Transmisja synchroniczna (czyli z czekaniem na zakończenie operacji zapisu czy też odczytu)
}

	hCom := CreateFile( aPortName, GENERIC_READ or GENERIC_WRITE, 0, Nil, OPEN_EXISTING, 0, 0);

	if( hCom = INVALID_HANDLE_VALUE )	then begin
	  	Result := ERR_CREATE_FILE_COM;
      exit;
  end;

  GetCommState(hCom,aDCB);
	aDcb.DCBlength        := sizeof( aDCB );
	aDcb.BaudRate					:= aBaudRate;		  //* Baud Rate */
//	Dcb.fBinary						:= TRUE;
//	Dcb.fParity						:= FALSE;
//	Dcb.fOutxCtsFlow			:= FALSE;
//	Dcb.fOutxDsrFlow			:= FALSE;
//	Dcb.fDtrControl				:= DTR_CONTROL_DISABLE;
//	Dcb.fDsrSensitivity		:= FALSE;
//	Dcb.fTXContinueOnXoff	:= FALSE;
//	Dcb.fOutX							:= TRUE;					//* Xon/Xoff używane tylko podczas nadawania */
//	Dcb.fInX							:= FALSE;
//	Dcb.fErrorChar				:= FALSE;
//	Dcb.fNull							:= FALSE;
//	Dcb.fRtsControl				:= RTS_CONTROL_DISABLE;
//	Dcb.fAbortOnError			:= FALSE;				  //* w przypadku wystąpienia błędu kolejne dostępy nie będą blokowane */
	aDcb.XonLim						:= 1900;
	aDcb.XoffLim					:= 1024;
	aDcb.XonChar					:= chr(17);
	aDcb.XoffChar					:= chr(19);
	aDcb.ByteSize					:= 8;						  //* 8 bitów */
	aDcb.Parity						:= NOPARITY;			//* bez bitu kontroli parzystości */
	aDcb.StopBits					:= ONESTOPBIT;		//* jeden bit stopu */
	aDcb.Flags					  := dcb_fBinary or dcb_fParity or dcb_fOutX;		//* flagi  */

	if not ( SetCommState(hCom, aDcb) ) then begin
		CleanUp;
		Result := ERR_COMM_SETTINGS;
    exit;
  end;


{
	Timeout na:
	- całość ( RD_INTERV_TOUT * (1 + nr_of_bytes) )
	- interwał międzybajtowy
}
  GetCommTimeouts(hCom,aTimeouts);
	aTimeouts.ReadIntervalTimeout					:= 1;
	aTimeouts.ReadTotalTimeoutConstant		:= 300;
	aTimeouts.ReadTotalTimeoutMultiplier	:= 0;
	aTimeouts.WriteTotalTimeoutConstant		:= 300;
	aTimeouts.WriteTotalTimeoutMultiplier	:= 0;

	if not ( SetCommTimeouts( hCom, aTimeouts ) ) then begin
		CleanUp;
		Result := ERR_COMM_SETTINGS;
    exit;
  end;

// 	Żadne zdarzenia związane z portem nie będą generowane !!!

	if not ( SetCommMask( hCom, EV_RXCHAR ) ) then begin
		CleanUp;
		Result := ERR_COMM_SETTINGS;
    exit;
  end;

//* 	Tak na dobry początek - czyścimy co się da (kolejki...) */

	PurgeComm( hCom, PURGE_TXABORT OR PURGE_RXABORT OR PURGE_RXCLEAR OR PURGE_TXCLEAR );
	//_ASSERTE( RetB ); // nie wiem po co to jest


{/*
	Ustawiamy długości kolejek: wejściowej i wyjściowej.
	Wejściowa - postaramy się ustawić jakąś sensowną wartość.
	Wyjściowa - zero (brak kolejkowania danych wychodzących).
*/}
  //aCommProp.dwProvSpec1:=COMMPROP_INITIALIZED;
	if not GetCommProperties(hCom, aCommProp) then begin
		CleanUp;
		Result := ERR_COMM_SETTINGS;
    exit;
  end else begin

  aCommProp.dwCurrentRxQueue := 2048;
  aCommProp.dwCurrentTxQueue := 1024;
	aCommProp.dwMaxRxQueue := min( PORT_RX_QUEUE_LEN, aCommProp.dwMaxRxQueue );

	if not ( SetupComm(hCom, aCommProp.dwCurrentRxQueue, 0) ) then begin
  	CleanUp();
		Result := ERR_COMM_SETTINGS;
    exit;
    end;
  end;

	Result := SOK;
end;

Zapis do portu - wysyłanie.


function TComPortClass.Write(Buffer:string;Len:DWORD): Integer;
var
  RetB          : Boolean;
  BytesWritten  : DWORD;
begin
	if ( hCom = INVALID_HANDLE_VALUE ) then begin
		Result := SERROR;
    exit;
  end;

	RetB := WriteFile( hCom, pchar(Buffer)^, Len , BytesWritten, Nil );	//* wysyłamy */
	if( (not RetB) or (BytesWritten <> Len) ) then begin
    Result := ERR_WRITE_FILE_COM;
    exit;
  end;

	Result := SOK;

end;

Odczyt z portu <= Tu mam problem

function TComPortClass.Read(var Buffer:string; var iReaded:DWORD; const Len:integer=PORT_OUTPUT_BUFFER_LEN):Integer;
var
  Stat      : TComStat;
  Errors    : DWORD;
  toRead    : DWORD;
  B         : byte;
  S : string;
begin
	if (hCom = INVALID_HANDLE_VALUE) then begin
		Result := SERROR;
    exit;
    end;
  ClearCommError(hCom, Errors, @Stat);
  S := IntToStr(Stat.cbInQue)+'|'+IntToStr(Stat.cbOutQue);  ///  <=  TUTAJ cbInQue ma wartość 0
  if WaitForAnyByte(SHORT_RESPONSE_TIME,B)=SOK then begin
//    sleep(SHORT_RESPONSE_TIME);
    Sleep(10);
    ClearCommError(hCom, Errors, @Stat); ///  <=  TUTAJ przy sleep(10) cbInQue ma wartość 15
                                                               ///  <=  przy sleep(100) odczytuje cały komunikat 35zanków
    S := S+#13+IntToStr(Stat.cbInQue)+'|'+IntToStr(Stat.cbOutQue);
    Application.MessageBox(pchar(s),'Test kolejki',0);

    SetLength(Buffer, Stat.cbInQue);

    toRead := min(Stat.cbInQue,Len);

   	if not( ReadFile(hCom, pchar(Buffer)^, Stat.cbInQue,  iReaded, NiL) ) then begin  //* odczytujemy */
      Result := ERR_READ_FILE_COM;
      exit;
    end;
    Buffer := chr(B)+Buffer;
  	Result := SOK;
  end else
    Result := ERR_RESPONSE_TOUT;

end;

Co robię źle ?
złe ustawienia timeoutów ? / flag ? czy może jest jakiś znacznik że dane w buforze są gotowe do odczytu ??

0

drukarka nie odpowiada natychmiast - musisz chwilę poczekać. Zazwyczaj robi się to tak, że ustalasz jakiś czas po którym zwrócisz userowi błąd - np. 60 sekund. I teraz czekasz albo ten czas upłynie i wtedy error albo aż dostaniesz cały komunikat - wtedy OK

0

Hmm... ale co ma zrobić w/g Ciebie ?

myślałem nad daniem jakiegoś repeat until i sprawdzać czy rośnie wartość cbInQue w pętli.

Ale sądziłem że może jest jakieś prostsze rozwiązanie.
Coś typu if stat.BufferReadyToRead :D

0
  if WaitForAnyByte(SHORT_RESPONSE_TIME,B)=SOK then begin

    ClearCommError(hCom, Errors, @Stat);
    repeat
      toRead := Stat.cbInQue;
      sleep(10);
      ClearCommError(hCom, Errors, @Stat);
    until toRead=Stat.cbInQue;

    SetLength(Buffer, Stat.cbInQue);
  end;

Teoretycznie to załatwia sprawę,ale nie zauważyłem w żadnych przykładach aby ktokolwiek coś takiego stosował, dlatego zastanawiam się czy to jednak nie jest wina ustawień :(

1 użytkowników online, w tym zalogowanych: 0, gości: 1