Типы тегов

Формат записи в mtr-файле

%EXTERNAL=1E6C
%EXTMAIN=01E3
%EXTREQ=0995
%EXTIRR=12F4

Таблица вшешних тэгов имеет структуру:

typesize
periodic EXTMAIN
requested EXTREQ
irregular EXTIRR

Irregular tags

Все теги в rpsvrtcp и его клиентах имеют свойства:

TWorkRecTagProp = (tpNormal, tpIrregular);
TWorkRecTagFlag = (tfNone, tfInUse, tfUpdated);

Теги типа tpIrregular запрашиваются из конечного устройства (ПЛК) только тогда, когда этого требует клиент, подключенный к rpsvrtcp. Делается это так.

Пусть клиентом будет приложение visscada. При использовании тега внутри приложения выполняется проверка на тип tpIrregular и, если да, то тегу устанавливается флаг tfInUse:

// D:\promauto-src\VisScada\Common\TagStorage.pas 
function GetTagValue(idx: integer): integer;
begin
  result := 0;
  if not DataClient.Connected then exit;
 
  if (idx >= 0) and (idx < DataClient.client.TagCount) then begin
 
    if DataClient.client.Tags[idx].TagProp = tpIrregular then
      DataClient.client.Tags[idx].TagFlag := tfInUse;
 
    result := DataClient.client.Tags[idx].ValIn;
  end else
    result := -1;
end;

После этого в самом ближайшем будущем этот флаг будет прочитан модулем, отвечающем за связь с rpsvrtcp, и передан серверу при помощи команды SETFLAG:

// D:\promauto-src\Lib\delphi\rpTcpLib\TcpImportClient.pas 
// Передача флага для irregular тегов
if (Tags[i].TagProp = tpIrregular) and (Tags[i].TagFlag <> tfNone) then begin
  s := IntToHex(i, 1) + ' ' + IntToHex(integer(Tags[i].TagFlag), 1);
  clnt.IOHandler.WriteLn( 'SETFLAG ' + s + ' ' + IntToHex(CRC16($FFFF, s), 1) );
  if not GetAnswer('117 !', false, s, c) then raise Exception.Create('');
  Tags[i].TagFlag := tfNone;
end;

Комманда SETFLAG принимается сервером rpsvrtcp, после чего флаг соответсвующего тега становится tfInUse:

// D:\promauto-src\Work_shd\rpsvrtcp\sources\TcpExpSvr.pas 
procedure TTcpExportSvr.OnCommandSETFLAG(ASender: TIdCommand);
var
  i: Integer;
  clnt: TTcpExportClient;
  s: string;
label
  M;
begin
  clnt := FindModuleByContext( ASender.Context );
  if clnt<>nil then with clnt do begin
 
    ASender.Reply.Text.Text := '?';
 
    if ASender.Params.Count>=3 then begin
 
      s := ASender.Params[0] + ' ' + ASender.Params[1];
      if (ASender.Params[2]='****') then goto M;
      if CRC16($FFFF, s) = HexToInt(uppercase(ASender.Params[2])) then
  M:  begin
        if SetFlagByNum(
                HexToInt(uppercase(ASender.Params[0])),
                HexToInt(uppercase(ASender.Params[1]))
              )
        then
          ASender.Reply.Text.Text := '!';
      end;
    end;
 
    inc(CntRequest);
  end;
end;
 
 
// D:\promauto-src\Work_shd\rpsvrtcp\sources\ExpSvr.pas 
function TCustomExportClient.SetFlagByNum(item_num, value: integer):
        Boolean;
begin
  result := false;
  if (item_num<0) or (item_num >= TagCount) then exit;
  Tags[item_num].ptrTag^.TagFlag := TWorkRecTagFlag( value );
  result := true;
end;

А в это время в том же rpsvrtcp живет своей жизнью модуль robo - обменивается данными с ПЛК, посылая ему запросы чтения тегов типа requested. При этом он следит и за тегами irregular - если у тега флаг tfInUse, то посылется запрос на одиночное чтение данного тега.

// D:\promauto-src\Work_shd\rpsvrtcp\sources\Robo.pas 
      // Прием irrgular тега
      if (Tags[i].TagProp = tpIrregular)  then begin
        if Tags[i].TagFlag = tfUpdated then
          Tags[i].TagFlag := tfNone;
 
        if Tags[i].TagFlag = tfInUse then begin
          inc(irrCnt);
          Tags[i].TagFlag := tfUpdated;
 
          newCmdDollarFlag := cmdDollarSupported;
          if (cmdDollarSupported) then begin
            TransStr := '$' + Tags[i].Address;
            w := GetCRC8(TransStr);
            TransStr := TransStr + DecHexB(w and $FF) + #13;
          end else
            TransStr := '!' + Tags[i].Address + #13;
 
          Attemp := 0;
          repeat
 
            sio_sendstring( PortHolder_Port, TransStr);
            flag := sio_getstring( PortHolder_Port, s);
 
            if (cmdDollarSupported) then begin
              if (not flag) and (s='') then begin
                sio_sendstring( PortHolder_Port, '!' + Tags[i].Address + #13);
                newCmdDollarFlag := not (sio_getstring( PortHolder_Port, s) and (copy(s,1,1) = '!'));
              end else
                newCmdDollarFlag := True;
            end;
 
            if (flag) and (copy(s,1,1) = '!') then begin
              k := pos('=', s);
              sum1 := HexDec(copy(s,k+1,length(s)-k));
              sum2 := GetCRC8(copy(s,1,k));
 
              if sum1 = sum2 then begin
                s := copy(s,2,k-2);
                v := HexDec(s);
 
                if Tags[i].ValIn <> v then begin
                  Tags[i].ValIn := v;
                  Tags[i].Changed := true;
                end;
                break;
              end;
            end;
            sleep(50);
            sio_flush( PortHolder_Port, 2 );
            inc(Attemp);
            if Attemp > AttempMax then err := true;
          until Attemp > AttempMax;
 
          cmdDollarSupported := newCmdDollarFlag;
        end;
      end;

При установке значеня тега в ПЛК модуль robo также уделяет irr-тегам немного больше внимания, чем другим: после каждой записи robo сам устанавливает тегу флаг tfInUse, чтобы новое значение обновилось:

// D:\promauto-src\Work_shd\rpsvrtcp\sources\Robo.pas 
 
    // Передача тэгов
    // writing all tags (per, req, irr)
    for i:=0 to TagCount-1 do
    begin
 
      // Передача тега
      if Tags[i].GotOut then begin
        if Tags[i].ValOut > $FFFF then
          TransStr := '^'
        else
          TransStr := '@';
        TransStr := TransStr + Tags[i].Address + DecHexW(Tags[i].ValOut and $FFFF);
 
        w:=0;
        if UseCRC8 then
          w := GetCRC8(TransStr)
        else
          for k:=1 to 11 do w :=w + ord(TransStr[k]);
 
        TransStr := TransStr + DecHexB(w and $FF) + #13;
        Tags[i].GotOut := false;
 
        Attemp := 0;
        repeat
          sio_sendstring( PortHolder_Port, TransStr);
          flag := sio_getstring( PortHolder_Port, s);
 
          if (Tags[i].TagProp = tpIrregular) then
            Tags[i].TagFlag := tfInUse;
 
 
          if UseLogging then
            LoggerSaveDayMessage(
                  inttostr(Attemp) + ': ' +
                  copy(TransStr,1,13) + '|' + s + ' ' +
                  iif(copy(TransStr,1,13) = copy(s,2,13), 'ok', 'TAG_WRITE_ERROR') );
 
          if (flag) and (copy(s,1,1) = '!') then
            break;
 
          sleep(50);
          sio_flush( PortHolder_Port, 2 );
          inc(Attemp);
          if Attemp > AttempMax then err := true;
        until Attemp > AttempMax;
      end;
    end;

Подводный камень

Очень редко случается доселе не локализованный баг - после записи в irr-теги ПЛК значения не обновляются в rpsvrtcp, но сами значения уходят в ПЛК нормально. Помогает перезапуск rpsvrtcp.

doc/rpsvrtcp/irregular.txt · Последние изменения: 2013/09/09 13:46 — denis
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0