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

📄 uniprotocol_cutehouse.pas

📁 很好用的串口通信工具软件。Comport目录下是用到的通信控件。
💻 PAS
📖 第 1 页 / 共 2 页
字号:
unit UniProtocol_CuteHouse;

{----------------------------------------------
         UniProtocol_CuteHouse

      无人值守野外机房协议插件
          Ver 1.02

  Copyright 1999-2001 AT Corp.Ltd
-----------------------------------------------}

interface

uses
  UniCommX, SysUtils, Classes, Windows;

type
  TEnvData = record
    dtTime: TdateTime;
    VoltageAC: Integer;     // 交流电压
    VoltageDC: Integer;     // 直流电压
    Humidity: Integer;      // 湿度
    DoorState: Integer;     // 门禁状态
    FanState: Integer;      // 风扇状态   0-关 1-开
    AirConditionState: Integer;  // 空调状态   0-关 1-开
    LightState: Integer;    // 有无雷击   0-有 1-无
    WaterState: Integer;    // 是否进水   0-否 1-是
    SmogState: Integer;     // 有无烟雾   0-无 1-有
    Temperatures: array[1..7] of Integer; // 温度
  end;

  TDoorData = record
    dtTime: tdateTime;
    CardSerial: string;
    ReaderNO: Integer;
    DoorState: Integer;
    Reserved: array[1..4] of Integer;
  end;

  TAlertData = record
    VoltageAC: Integer;
    VoltageDC: Integer;
    Humidity: Integer;
    DoorState: Integer;
    FanState: Integer;
    AirConditionState: Integer;
    CableState: array[1..8] of Integer;
    Temperatures: array[1..7] of Integer;
    Reserved: array[1..4] of Integer;
  end;

  TCableData = record
    CableLength: array[1..8] of Integer;
  end;

  TCuteHouse = class(TCustomProtocolExecutor)
  private
    FSenderSerialNO: string;
    FHostCmd: THostCommand;
    FFrameNo: Integer;
    FDataCount: Integer;
    function AdjustTimeCommand: string;
  public
    class function ProtocolImplemented(ProtocolType: Integer; ProtocolVersion: Integer; isCommander: Boolean): Boolean; override;
    class function SaveUncompletedData: Boolean; override;
    class function ParseEnvData(Data: string): TEnvData;
    class function ParseDoorData(Data: string): TDoorData;
    class function ParseAlertData(Data: string): TAlertData;
    class function ParseCableData(Data: string): TCableData;
    function ProcessProtocol(var FPacketCommState: Integer; SendResult: Integer; Packet: string; Parameters: TStrings): THostCommand; override;
  published
    property Datas;
  end;

implementation

const
  
  csACK = #$A5#$A5; // ACK: 确认
  csNAK = #$5A#$5A; // NAK: 否定回应

{-------------------  TCuteHouse   -----------------------------}

{--------------------------------------------------------------------------
class function TCuteHouse.ProtocolImplemented
功能: 判断是否实现了特定协议类型以及协议版本的通信协议。
输入: ProtocolType: Integer;   协议类型,即发送者标识
       ProtocolVersion: Integer 协议版本
输出: boolean 是否实现协议
---------------------------------------------------------------------------}

class function TCuteHouse.ProtocolImplemented(ProtocolType: Integer; ProtocolVersion: Integer; isCommander: Boolean): Boolean;
begin
  Result := (ProtocolType = cnCuteHouseID) and (ProtocolVersion = 1) and isCommander;
end;

{--------------------------------------------------------------------------
class function TCuteHouse.SaveUncompletedData
功能: 判断是否要保存通讯没有完全成功时接收到的数据
输入: 无
输出: boolean 是否保存
说明: 对于智能机房,应当保存
---------------------------------------------------------------------------}

class function TCuteHouse.SaveUncompletedData: Boolean;
begin
  Result := True;
end;

{--------------------------------------------------------------------------
function TCuteHouse.AdjustTimeCommand: string;
功能: 生成调节时间的命令
输入: 无
输出: string 命令
---------------------------------------------------------------------------}


function TCuteHouse.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] := #$F1;
  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;

{--------------------------------------------------------------------------
function TCuteHouse.ProcessProtocol
功能: 处理当前通信状态,并生成新的命令
输入: var FPacketCommState: Integer;  当前的通信状态
       SendResult: Integer;            上一次的发送结果
       Packet: string;                 上一次的数据
       Parameters: TStrings            通信参数
输出: THostCommand 存放新的命令
       var FPacketCommState: Integer;  存放下一步的通信状态
---------------------------------------------------------------------------}
{ 智能机房通信协议
一、握手:
●握手信号:
◆ "SWAT"
⊙ ACK+0003(监控仪标识)+0001(协议版本号) +CRC  	【ACK】
二、参数设置:
● 校正监控仪时间
◆ 0Xf1+SSMMHHDDMMYY+CRC
⊙ ACK+0xF1+CRC        				【ACK】
●设定主机及负责人电话号码
◆ 0xF2+1B(号码序号)+1B(号码长度)+电话号码+CRC	 【1-4号为中心电话号码,5-8 为  负责人电话号码】
⊙ ACK+0xF2+1B(号码序号)+CRC 	      		【ACK】
●设定密钥
◆ 0xF3+2B(帧号)+8B(数据)+CRC  			【帧号为密钥位置,6B数据为4B密钥+1B权限(仅55H可开门1,AAH可开门2,5AH可开门1门2)+ 3B预留】
⊙ ACK+0xF3+2B(帧号)+CRC 			【ACK】
●设定报警条件
◆ 0xF4+9B(报警范围)+1B(检测周期)+1B(重复报警周期)+CRC  【报警范围: 2B交流电压上下限(0-255),2B直流电压上下限(0-255),2B温度上下限(-128-+127),2B湿度上下限(0-100),1B开门报警(低四位为门0,高四位为门1;仅0x55H报警)。检测周期:1B(1-255分钟)重复报警周期:1B(1-255分钟)】
⊙ ACK+0xF4+CRC        				【ACK】
三、数据传输:
●读取机号
◆0xF0+0x10+CRC
⊙ACK+0xF0+4B(机号)+2B(数据条数)+CRC	 	【ACK】
●历史数据传输
◆ 0xF5+2B(帧号)+ CRC
⊙ ACK+0xF5+2B(帧号)+1B(数据类型)+16B(记录数据)+CRC  【ACK】
●记录数据传输
⊙ ACK+0xF5+2B(帧号)+0x01+16B(记录数据)+CRC
 【16B记录      MMHHDDMMYY(日期时间5B),
  门磁空调风扇雷击浸水烟雾状态1B
  (1B16进制数据,从高到低位为
      第1位为1时门1开,
      第2位为1时门2开,
      第3位为1时空调开,
      第4位为1时风扇开,
      第5位为0时有雷击,
      第6位为1时有浸水,
      第7位为1时有烟雾),
  交流电压1B,直流电压1B,湿度1B,温度7B。数据类型同上】
●门禁数据传输
⊙ ACK+0xF5+2B(帧号)+0x02+16B(记录数据)+CRC 	【16B记录:SSMMHHDDMMYY(日期时间6B),卡号(4B),读卡器号(1B),门磁状态(1B),预留(4B)】
●报警数据传输
⊙ ACK+0xF5+2B(帧号)+0x03+16B(报警数据)+CRC 	【16B报警:交流电压1B,直流电压1B,湿度1B,门磁状态1B,电缆断合1B,温度7B,预留(4B)】
●报警电缆长度
⊙ ACK+0xF5+2B(帧号)+0x04+16B(电缆长度)+CRC 	【16B电缆长度:2B(前一字节为整数,后一字节为小数;电缆未断为0xFFFF)*8(8对电缆)】没数据后发16B0X00.
●实时电缆长度传输
◆ 0xF8+0x10+CRC
⊙ 'WAIT'(电缆长度未测出前每500豪秒发送一次)
⊙ ACK+0xF5+2B(0x0000)+0x05+16B(电缆长度)+CRC  【16B电缆长度:2B(前一字节为整数,后一字节为小数;电缆未断为0xFFFF)*8(8对电缆)】
四、控制数据:
● 空调风扇开门控制:
◆ 0xF9+3B(空调风扇开门控制)+CRC  		【3B控制字节:空调1B,风扇1B,开门1B。(空调、风扇:仅为0x55时开,0xAA为关,其它都无关;开门:5A开门1,A5开门2,55开门1和2)】
⊙ ACK+0xF9+CRC                   		【ACK】
● 挂机命令:
◆ 0xFA+0x10+CRC
⊙ ACK+0xFA+CRC                   		【ACK】
● 命令接收错误应答:
⊙ NCK+4B(监控仪机号)+CRC                   	【NCK】
注:
1、固定数据取CRC只是为延长命令长度,减少"正确误码"或为处理方便。
2、当主机没有收到应答时,要求重发都由主机来执行。
3、当收到下一条命令,校验正确,就屏蔽上条命令,以次类推。
}

function TCuteHouse.ProcessProtocol(var FPacketCommState: Integer; SendResult: Integer; Packet: string; Parameters: TStrings): THostCommand;
const
  csGetDataInfo = csUser + 1;
  csAdjustTime = csUser + 2;
  csSetPhoneCode = csUser + 3;
  csSetSecureKey = csUser + 4;
  csSetAlertLimit = csUser + 5;
  csGetHistoryData = csUser + 6;
  csGetCableLength = csUser + 7;
  csControlDevice = csUser + 8;

var
  i: Integer;
  currentData: string;

  function FindParams(Key: string): string;
  begin
    Result := Parameters.Values[IntToStr(cnCuteHouseID) + '_' + 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;
begin

  FProcessRatio := 0;
  // 处理状态改变
  case FPacketCommState of
    csHandShake:
      begin
        FPacketCommState := csGetDataInfo;
        FFrameNo := 0;
      end;
    csGetDataInfo:
      begin
        case SendResult of
          srGetData:
            begin
              FSenderSerialNO := '';
              for i := 1 to 4 do
                FSenderSerialNO := FSenderSerialNO + IntToHex(ord(Packet[3 + i]), 2);
              FDatas.Add('SenderSerialNo=' + FSenderSerialNO);
              FDataCount := (Ord(Packet[8]) shl 8) + Ord(Packet[9]);
              if (FindParams(FSenderSerialNO + '_AirCondition') <> '') or
                (FindParams(FSenderSerialNO + '_Fan') <> '') or
                (FindParams(FSenderSerialNO + '_Door') <> '') or
                (FindParams(FSenderSerialNO + '_ClearAlert') = '1') then
                FPacketCommState := csControlDevice
              else
                FPacketCommState := csAdjustTime;
            end;
        else
          FPacketCommState := csHalt;
        end;
      end;
    csControlDevice:
      begin
        case SendResult of
          srACK:
            begin
              // 空调
              if FindParams(FSenderSerialNO + '_AirCondition') = '0' then
                FDatas.Add('AirCondition=OFF');
              if FindParams(FSenderSerialNO + '_AirCondition') = '1' then
                FDatas.Add('AirCondition=ON');
              // 风扇
              if FindParams(FSenderSerialNO + '_Fan') = '0' then
                FDatas.Add('Fan=OFF');
              if FindParams(FSenderSerialNO + '_Fan') = '1' then
                FDatas.Add('Fan=ON');
              if FindParams(FSenderSerialNO + '_Door') <> '' then
                FDatas.Add('Door=' + FindParams(FSenderSerialNO + '_Door'));
              if FindParams(FSenderSerialNO + '_ClearAlert') = '1' then
                FDatas.Add('Alert=OFF');
              FFrameNO := 0;
              FPacketCommState := csAdjustTime;
            end;
        else
          FPacketCommState := csHalt;
        end;
      end;
    csAdjustTime:
      begin
        case SendResult of
          srACK:
            begin
              FFrameNo := 0;
              if FindParams(FSenderSerialNO + '_Phone') <> '' then
                FPacketCommState := csSetPhoneCode
              else
              begin
                if (FindParams('SetSecureKey') = '1') and (GetSubParams(FSenderSerialNO + '_Key', 0) <> '') then
                  FPacketCommState := csSetSecureKey
                else
                begin
                  if FindParams(FSenderSerialNO + '_AlertLimit') <> '' then
                    FPacketCommState := csSetAlertLimit
                  else
                    FPacketCommState := csGetHistoryData;
                end;
              end;
            end;
        else
          FPacketCommState := csHalt;
        end;
      end;
    csSetPhoneCode:
      begin
        case SendResult of
          srACK:
            begin
              Inc(FFrameNo);
              //FProcessRatio := FFrameNo * 100 div 8;
              if (FFrameNo >= 8) then
              begin
                FFrameNO := 0;
                if (FindParams('SetSecureKey') = '1') and (GetSubParams(FSenderSerialNO + '_Key', 0) <> '') then
                  FPacketCommState := csSetSecureKey
                else
                begin
                  if FindParams(FSenderSerialNO + '_AlertLimit') <> '' then
                    FPacketCommState := csSetAlertLimit
                  else
                    FPacketCommState := csGetHistoryData;
                end;
              end;
            end;
        else
          FPacketCommState := csHalt;
        end;
      end;
    csSetSecureKey:
      begin
        case SendResult of
          srACK:
            begin
              Inc(FFrameNo);
              if (GetSubParams(FSenderSerialNO + '_Key', FFrameNO) = '') then
              begin
                FFrameNO := 0;
                if FindParams(FSenderSerialNO + '_AlertLimit') <> '' then
                  FPacketCommState := csSetAlertLimit
                else
                  FPacketCommState := csGetHistoryData;
              end;
            end;
        else
          FPacketCommState := csHalt;
        end;
      end;
    csSetAlertLimit:
      begin
        case SendResult of

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -