📄 synaser.pas
字号:
function TBlockSerial.RecvInteger(Timeout: Integer): Integer;
var
s: string;
begin
Result := 0;
s := RecvBufferStr(4, Timeout);
if FLastError = 0 then
Result := (ord(s[1]) + ord(s[2]) * 256) + (ord(s[3]) + ord(s[4]) * 256) * 65536;
end;
function TBlockSerial.RecvBlock(Timeout: Integer): string;
var
x: integer;
begin
Result := '';
x := RecvInteger(Timeout);
if FLastError = 0 then
Result := RecvBufferStr(x, Timeout);
end;
procedure TBlockSerial.RecvStreamRaw(const Stream: TStream; Timeout: Integer);
var
s: string;
begin
repeat
s := RecvPacket(Timeout);
if FLastError = 0 then
WriteStrToStream(Stream, s);
until FLastError <> 0;
end;
procedure TBlockSerial.RecvStreamSize(const Stream: TStream; Timeout: Integer; Size: Integer);
var
s: string;
n: integer;
begin
for n := 1 to (Size div cSerialChunk) do
begin
s := RecvBufferStr(cSerialChunk, Timeout);
if FLastError <> 0 then
Exit;
Stream.Write(Pchar(s)^, cSerialChunk);
end;
n := Size mod cSerialChunk;
if n > 0 then
begin
s := RecvBufferStr(n, Timeout);
if FLastError <> 0 then
Exit;
Stream.Write(Pchar(s)^, n);
end;
end;
procedure TBlockSerial.RecvStreamIndy(const Stream: TStream; Timeout: Integer);
var
x: integer;
begin
x := RecvInteger(Timeout);
x := SwapBytes(x);
if FLastError = 0 then
RecvStreamSize(Stream, Timeout, x);
end;
procedure TBlockSerial.RecvStream(const Stream: TStream; Timeout: Integer);
var
x: integer;
begin
x := RecvInteger(Timeout);
if FLastError = 0 then
RecvStreamSize(Stream, Timeout, x);
end;
{$IFNDEF WIN32}
function TBlockSerial.WaitingData: integer;
begin
serialcheck(ioctl(integer(FHandle), FIONREAD, @result));
if FLastError <> 0 then
Result := 0;
ExceptCheck;
end;
{$ELSE}
function TBlockSerial.WaitingData: integer;
var
stat: TComStat;
err: DWORD;
begin
if ClearCommError(FHandle, err, @stat) then
begin
SetSynaError(sOK);
Result := stat.cbInQue;
end
else
begin
SerialCheck(sErr);
Result := 0;
end;
ExceptCheck;
end;
{$ENDIF}
function TBlockSerial.WaitingDataEx: integer;
begin
if FBuffer <> '' then
Result := Length(FBuffer)
else
Result := Waitingdata;
end;
{$IFNDEF WIN32}
function TBlockSerial.SendingData: integer;
begin
SetSynaError(sOK);
Result := 0;
end;
{$ELSE}
function TBlockSerial.SendingData: integer;
var
stat: TComStat;
err: DWORD;
begin
SetSynaError(sOK);
if not ClearCommError(FHandle, err, @stat) then
serialcheck(sErr);
ExceptCheck;
result := stat.cbOutQue;
end;
{$ENDIF}
{$IFNDEF WIN32}
procedure TBlockSerial.DcbToTermios(const dcb: TDCB; var term: libc.termios);
var
n: integer;
x: cardinal;
begin
//others
libc.cfmakeraw(term);
term.c_cflag := term.c_cflag or CREAD;
term.c_cflag := term.c_cflag or CLOCAL;
term.c_cflag := term.c_cflag or HUPCL;
//hardware handshake
if (dcb.flags and dcb_RtsControlHandshake) > 0 then
term.c_cflag := term.c_cflag or CRTSCTS
else
term.c_cflag := term.c_cflag and (not CRTSCTS);
//software handshake
if (dcb.flags and dcb_OutX) > 0 then
term.c_iflag := term.c_iflag or IXON or IXOFF or IXANY
else
term.c_iflag := term.c_iflag and (not (IXON or IXOFF or IXANY));
//size of byte
term.c_cflag := term.c_cflag and (not CSIZE);
case dcb.bytesize of
5:
term.c_cflag := term.c_cflag or CS5;
6:
term.c_cflag := term.c_cflag or CS6;
7:
{$IFDEF FPC}
term.c_cflag := term.c_cflag or CS7;
{$ELSE}
term.c_cflag := term.c_cflag or CS7fix;
{$ENDIF}
8:
term.c_cflag := term.c_cflag or CS8;
end;
//parity
if (dcb.flags and dcb_ParityCheck) > 0 then
term.c_cflag := term.c_cflag or PARENB
else
term.c_cflag := term.c_cflag and (not PARENB);
case dcb.parity of
1: //'O'
term.c_cflag := term.c_cflag or PARODD;
2: //'E'
term.c_cflag := term.c_cflag and (not PARODD);
end;
//stop bits
if dcb.stopbits > 0 then
term.c_cflag := term.c_cflag or CSTOPB
else
term.c_cflag := term.c_cflag and (not CSTOPB);
//set baudrate;
x := 0;
for n := 0 to Maxrates do
if rates[n, 0] = dcb.BaudRate then
begin
x := rates[n, 1];
break;
end;
libc.cfsetospeed(term, x);
libc.cfsetispeed(term, x);
end;
procedure TBlockSerial.TermiosToDcb(const term: libc.termios; var dcb: TDCB);
var
n: integer;
x: cardinal;
begin
//set baudrate;
dcb.baudrate := 0;
x := cfgetospeed(term);
for n := 0 to Maxrates do
if rates[n, 1] = x then
begin
dcb.baudrate := rates[n, 0];
break;
end;
//hardware handshake
if (term.c_cflag and CRTSCTS) > 0 then
dcb.flags := dcb.flags or dcb_RtsControlHandshake or dcb_OutxCtsFlow
else
dcb.flags := dcb.flags and (not (dcb_RtsControlHandshake or dcb_OutxCtsFlow));
//software handshake
if (term.c_cflag and IXOFF) > 0 then
dcb.flags := dcb.flags or dcb_OutX or dcb_InX
else
dcb.flags := dcb.flags and (not (dcb_OutX or dcb_InX));
//size of byte
case term.c_cflag and CSIZE of
CS5:
dcb.bytesize := 5;
CS6:
dcb.bytesize := 6;
CS7fix:
dcb.bytesize := 7;
CS8:
dcb.bytesize := 8;
end;
//parity
if (term.c_cflag and PARENB) > 0 then
dcb.flags := dcb.flags or dcb_ParityCheck
else
dcb.flags := dcb.flags and (not dcb_ParityCheck);
dcb.parity := 0;
if (term.c_cflag and PARODD) > 0 then
dcb.parity := 1
else
dcb.parity := 2;
//stop bits
if (term.c_cflag and CSTOPB) > 0 then
dcb.stopbits := 2
else
dcb.stopbits := 0;
end;
{$ENDIF}
{$IFNDEF WIN32}
procedure TBlockSerial.SetCommState;
begin
DcbToTermios(dcb, termiosstruc);
// FPC have mysterious problem with this.
{$IFNDEF FPC}
SerialCheck(libc.tcsetattr(integer(FHandle), TCSANOW, termiosstruc));
{$ELSE}
SerialCheck(libc.tcsetattr(integer(FHandle), TCSANOW, @termiosstruc));
{$ENDIF}
ExceptCheck;
end;
{$ELSE}
procedure TBlockSerial.SetCommState;
begin
SetSynaError(sOK);
if not windows.SetCommState(Fhandle, dcb) then
SerialCheck(sErr);
ExceptCheck;
end;
{$ENDIF}
{$IFNDEF WIN32}
procedure TBlockSerial.GetCommState;
begin
SerialCheck(libc.tcgetattr(integer(FHandle), termiosstruc));
ExceptCheck;
TermiostoDCB(termiosstruc, dcb);
end;
{$ELSE}
procedure TBlockSerial.GetCommState;
begin
SetSynaError(sOK);
if not windows.GetCommState(Fhandle, dcb) then
SerialCheck(sErr);
ExceptCheck;
end;
{$ENDIF}
procedure TBlockSerial.SetSizeRecvBuffer(size: integer);
begin
{$IFDEF WIN32}
SetupComm(Fhandle, size, 0);
GetCommState;
dcb.XonLim := size div 4;
dcb.XoffLim := size div 4;
SetCommState;
{$ENDIF}
FRecvBuffer := size;
end;
function TBlockSerial.GetDSR: Boolean;
begin
ModemStatus;
{$IFNDEF WIN32}
Result := (FModemWord and TIOCM_DSR) > 0;
{$ELSE}
Result := (FModemWord and MS_DSR_ON) > 0;
{$ENDIF}
end;
procedure TBlockSerial.SetDTRF(Value: Boolean);
begin
{$IFNDEF WIN32}
ModemStatus;
if Value then
FModemWord := FModemWord or TIOCM_DTR
else
FModemWord := FModemWord and not TIOCM_DTR;
ioctl(integer(FHandle), TIOCMSET, @FModemWord);
{$ELSE}
if Value then
EscapeCommFunction(FHandle, SETDTR)
else
EscapeCommFunction(FHandle, CLRDTR);
{$ENDIF}
end;
function TBlockSerial.GetCTS: Boolean;
begin
ModemStatus;
{$IFNDEF WIN32}
Result := (FModemWord and TIOCM_CTS) > 0;
{$ELSE}
Result := (FModemWord and MS_CTS_ON) > 0;
{$ENDIF}
end;
procedure TBlockSerial.SetRTSF(Value: Boolean);
begin
{$IFNDEF WIN32}
ModemStatus;
if Value then
FModemWord := FModemWord or TIOCM_RTS
else
FModemWord := FModemWord and not TIOCM_RTS;
ioctl(integer(FHandle), TIOCMSET, @FModemWord);
{$ELSE}
if Value then
EscapeCommFunction(FHandle, SETRTS)
else
EscapeCommFunction(FHandle, CLRRTS);
{$ENDIF}
end;
function TBlockSerial.GetCarrier: Boolean;
begin
ModemStatus;
{$IFNDEF WIN32}
Result := (FModemWord and TIOCM_CAR) > 0;
{$ELSE}
Result := (FModemWord and MS_RLSD_ON) > 0;
{$ENDIF}
end;
function TBlockSerial.GetRing: Boolean;
begin
ModemStatus;
{$IFNDEF WIN32}
Result := (FModemWord and TIOCM_RNG) > 0;
{$ELSE}
Result := (FModemWord and MS_RING_ON) > 0;
{$ENDIF}
end;
{$IFDEF WIN32}
function TBlockSerial.CanEvent(Event: dword; Timeout: integer): boolean;
var
ex: DWord;
y: Integer;
Overlapped: TOverlapped;
begin
FillChar(Overlapped, Sizeof(Overlapped), 0);
Overlapped.hEvent := CreateEvent(nil, True, False, nil);
try
SetCommMask(FHandle, Event);
SetSynaError(sOK);
if (Event = EV_RXCHAR) and (Waitingdata > 0) then
Result := True
else
begin
y := 0;
if not WaitCommEvent(FHandle, ex, @Overlapped) then
y := GetLastError;
if y = ERROR_IO_PENDING then
begin
//timedout
WaitForSingleObject(Overlapped.hEvent, Timeout);
SetCommMask(FHandle, 0);
GetOverlappedResult(FHandle, Overlapped, DWord(y), True);
end;
Result := (ex and Event) = Event;
end;
finally
SetCommMask(FHandle, 0);
CloseHandle(Overlapped.hEvent);
end;
end;
{$ENDIF}
{$IFNDEF WIN32}
function TBlockSerial.CanRead(Timeout: integer): boolean;
var
FDSet: TFDSet;
TimeVal: PTimeVal;
TimeV: TTimeVal;
x: Integer;
begin
TimeV.tv_usec := (Timeout mod 1000) * 1000;
TimeV.tv_sec := Timeout div 1000;
TimeVal := @TimeV;
if Timeout = -1 then
TimeVal := nil;
FD_ZERO(FDSet);
FD_SET(integer(FHandle), FDSet);
x := Select(integer(FHandle) + 1, @FDSet, nil, nil, TimeVal);
SerialCheck(x);
if FLastError <> sOK then
x := 0;
Result := x > 0;
ExceptCheck;
if Result then
DoStatus(HR_CanRead, '');
end;
{$ELSE}
function TBlockSerial.CanRead(Timeout: integer): boolean;
begin
Result := WaitingData > 0;
if not Result then
Result := CanEvent(EV_RXCHAR, Timeout);
if Result then
DoStatus(HR_CanRead, '');
end;
{$ENDIF}
{$IFNDEF WIN32}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -