⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uniprotocol_timepos.pas

📁 很好用的串口通信工具软件。Comport目录下是用到的通信控件。
💻 PAS
📖 第 1 页 / 共 2 页
字号:
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 + -