📄 uniprotocol_timepos.pas
字号:
unit UniProtocol_TimePos;
{----------------------------------------------
UniProtocol_TimePos
考勤机协议插件
Ver 1.04
Copyright 1999-2001 AT Corp.Ltd
-----------------------------------------------}
interface
uses
UniCommX, SysUtils, Classes, Windows;
type
TPosData = record
rtTime: TDateTime; // 日期
rtCard: string; // 卡号
rtReaderNO: string; // 读卡头号
rtVoltage: Integer; // 电压
rtTemperature: Integer; // 温度
end;
TTimePos = class(TCustomProtocolExecutor)
private
FSenderSerialNO: string;
FHostCmd: THostCommand;
FFrameNo: Integer;
FAlertData: string; // 报警数据
FDataCount: Integer;
function AdjustTimeCommand: string;
public
constructor Create(SenderID, ProtocolVersion: Integer; Hwnd: THandle); override;
destructor Destroy; override;
class function ParsePos(Data: string): TPosData;
class function ProtocolImplemented(ProtocolType: Integer; ProtocolVersion: Integer; isCommander: Boolean): Boolean; override;
class function SaveUncompletedData: Boolean; override;
function ProcessProtocol(var FCommState: Integer; SendResult: Integer; Packet: string; Parameters: TStrings): THostCommand; override;
end;
implementation
const
MonitorID = 2;
csACK = #$A5#$A5; // csACK: 确认
csNAK = #$5A#$5A; // csNAK: 否定回应
constructor TTimePos.Create(SenderID, ProtocolVersion: Integer; Hwnd: THandle);
begin
inherited;
end;
destructor TTimePos.Destroy;
begin
inherited;
end;
class function TTimePos.ParsePos(Data: string): TPosData;
var
Year, Mon, day, Hour, Min, Sec: Word;
begin
DecodeDate(Now, year, Mon, day);
Sec := 0;
Min := StrtoInt(Copy(Data, 1, 2));
Hour := StrtoInt(Copy(Data, 3, 2));
day := StrtoInt(Copy(Data, 5, 2));
Mon := StrtoInt(Copy(Data, 7, 2));
with Result do
begin
rtTime := EncodeDate(year, mon, day) + EnCodeTime(Hour, Min, Sec, 0);
rtCard := Copy(Data, 9, 8);
rtReaderNO := Copy(Data, 17, 2);
rtVoltage := StrtoInt('$' + Copy(Data, 19, 2));
rtTemperature := StrtoInt('$' + Copy(Data, 21, 2));
end;
end;
class function TTimePos.ProtocolImplemented(ProtocolType: Integer; ProtocolVersion: Integer; isCommander: Boolean): Boolean;
begin
Result := (ProtocolType = cnTimePosID) and isCommander;
end;
class function TTimePos.SaveUncompletedData: Boolean;
begin
Result := True;
end;
function TTimePos.AdjustTimeCommand: string;
var
Year, Month, day, Hour, Min, Sec, Msec: Word;
begin
decodeDate(now, Year, Month, day);
decodeTime(now, Hour, Min, Sec, msec);
Year := Year mod 100;
SetLength(Result, 8);
Result[1] := #$FD;
Result[2] := Chr(convBCDToHex(Sec));
Result[3] := Chr(convBCDToHex(Min));
Result[4] := Chr(convBCDToHex(Hour));
Result[5] := Chr(convBCDToHex(day));
Result[6] := Chr(convBCDToHex(Month));
Result[7] := Chr(convBCDToHex(Year));
Result[8] := Chr(GenerateCRC(Result[1], 7));
end;
{ (主机与考勤机)
考勤机 ?----------------------------------------------------------------------------------------à主机
等待主机呼叫
?------------------------------------------------呼叫考勤机------------------------------------定时收集考勤信息
收到并确认是呼叫本机--------------------------------应答---------------------------------------------à
?------------------------------------------------呼叫考勤机------------------------------------未收到应答(超时呼叫其它考勤机)
?------------------------------------------------发送命令---------------------------------------收到应答,确定呼叫成功
收到命令 -------------------------------------------------应答---------------------------------------------à
命令及回答:
注:◆为主机命令 ⊙考勤机应答 【】内为注解
ACK = 0xA5 + 0xA5 NAK = 0x5A + 0x5A
●握手信号:
◆ "SWAT"
⊙ ACK+0002(考勤机标识)+0001(协议版本号)+CRC 【ACK】
●读取考勤机号:
◆ 0xFE+0x10+CRC
⊙ ACK+4B(考勤机号)+2B(记录条数)+5B(报警数据)+CRC 【ACK】
● 校正考勤机时间
◆ 0xFD+SSMMHHDDMMYY+CRC
⊙ ACK+0xFD+CRC 【ACK】
● 请求数据
◆ 0xFB+2B(记录条数)+CRC 【请求记录】
⊙ 0xFB+2B(记录条数)+16B(数据)+CRC
【16B数据:分时日月(4B)+卡号(4B)+读卡头号(1B)+电压(1B)+温度补码(1B)+ [00000交流电红外入侵门磁开关](1B)+预留(4B)】
● 下传主机电话号码:
◆ 0xFA+1B(号码序号)+1B(号码长度)+电话号码+CRC
⊙ ACK+1B(号码序号)+0xFA+CRC 【ACK】
● 更新密钥:
◆ 0xF9+2B(帧号)+6B(数据)+CRC 【帧号为密钥位置,6B数据为4B密钥+1B权限(80H以上可开门)+1B预留】
⊙ ACK++2B(帧号)+CRC 【ACK】
● 追加新密钥:
◆ 0xF8+6B(数据)+CRC
⊙ ACK+0xF8+CRC 【ACK】
● 挂机命令:
◆ 0xF7+0x10+CRC
⊙ ACK+0xF7+CRC 【ACK】
● 设置报警范围:
◆ 0xF5+7B(报警范围)+CRC 【7B报警范围:2B温度上下限,2B电压上下限,1B交流,红外,门磁(低三位为1可报警),2B预留】
⊙ ACK+0xF5+CRC 【ACK】
● 命令接收错误应答:
⊙ NCK+4B(考勤机号)+CRC 【NCK】
注:
1、固定数据取CRC只是为延长命令长度,减少"正确误码"或为处理方便。
2、当主机没有收到应答时,要求重发都由主机来执行。
3、当收到下一条命令,校验正确,就屏蔽上条命令,以次类推。
}
function TTimePos.ProcessProtocol(var FCommState: Integer; SendResult: Integer; Packet: string; Parameters: TStrings): THostCommand;
const
csGetDataInfo = csUser + 1;
csAdjustTime = csUser + 2;
csGetHistoryData = csUser + 3;
csSetPhoneCode = csUser + 4;
csUpdateKey = csUser + 5;
csAppendKey = csUser + 6;
csSetAlertLimit = csUser + 7;
function FindParams(Key: string): string;
begin
Result := Parameters.Values[IntToStr(cnTimePosID) + '_' + Key];
end;
function GetSubParams(Key: string; KeyIndex: Integer): string;
var
i: Integer;
curKeyIndex: Integer;
Params: string;
begin
Result := '';
Params := FindParams(Key);
if Params = '' then Exit;
curKeyIndex := 0;
if Params[Length(Params)] <> ',' then Params := Params + ',';
while Pos(',', Params) > 0 do
begin
i := Pos(',', Params);
if curKeyIndex = KeyIndex then
begin
Result := Copy(Params, 1, i - 1);
Break;
end;
Delete(Params, 1, i);
Inc(curKeyIndex);
end;
end;
function GetAlterLimit: string;
var
i: integer;
begin
Result := '';
for i := 0 to 3 do
Result := Result + chr(StrToInt(GetSubParams(FSenderSerialNO + '_AlertLimit', i)));
Result := Result + chr(
(StrToInt(GetSubParams(FSenderSerialNO + '_AlertLimit', 4)) shl 2) or
(StrToInt(GetSubParams(FSenderSerialNO + '_AlertLimit', 5)) shl 1) or
(StrToInt(GetSubParams(FSenderSerialNO + '_AlertLimit', 6))));
Result := Result + #0#0;
end;
var
i: integer;
currentData: string;
begin
FProcessRatio := 0;
// 处理状态改变
case FCommState of
csHandShake:
begin
FFrameNo := 0;
FCommState := csGetDataInfo;
end;
csGetDataInfo:
begin
case SendResult of
srGetData:
begin
FSenderSerialNO := '';
for i := 0 to 3 do
FSenderSerialNO := FSenderSerialNO + IntToHex(ord(Packet[3 + i]), 2);
FDatas.Add('SenderSerialNo=' + FSenderSerialNO);
FDataCount := (Ord(Packet[7]) shl 8) + Ord(Packet[8]);
FAlertData := '';
for i := 0 to 4 do
FAlertData := FAlertData + IntToHex(ord(Packet[9 + i]), 2);
FCommState := csAdjustTime;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -