LibNoDave + S7Online

Lazarus™

Level-2
Beiträge
434
Reaktionspunkte
52
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

ich habe folgende Routine:

Code:
procedure TfrmMain.ConnectPlc;
begin
  sbMain.Panels[0].Text := 'Verbindung wird hergestellt';
  sbMain.Update;
  DaveOsSerialType.RFD := {OpenSocket(7777, '10.90.0.243');} OpenS7Online('S7ONLINE', Self.Handle);
  DaveOsSerialType.WFD := DaveOsSerialType.RFD;
  if (DaveOsSerialType.RFD > 0) then begin
    DaveInterface := DaveNewInterface(DaveOsSerialType, 'IF1', LocalMPI, {DaveProtoNlPro} DaveProtoS7Online, DaveSpeed187K);
    DaveInterface^.Timeout := 20000;
    if (DaveInitAdapter(DaveInterface) = 0) then begin
      DaveConnection := DaveNewConnection(DaveInterface, PlcMPI, Rack, Slot);
      if (DaveConnectPLC(DaveConnection) = 0) then begin
        btnConnection.Caption := 'Von SPS trennen';
        sbMain.Panels[0].Text := 'Verbindung hergestellt';
        Connected := True;
       end else
        Disconnect;
    end else
      Disconnect;
  end;
end;

Mit der Ausgeklammerten Version (NLPro) geht es einwandfrei, aber mit der
S7Online Version nicht. Funktioniert das S7Online generell ???
Ich würde gerne das S7Online nehmen, damit das Tool dann allgemeingültig ist und immer zu verwenden, egal ob TCP/IP oder Adapter etc.

Wenn dieses problem gelöst ist, wird es bald ein DB-Backup :TOOL: hier zum Download geben, ich denke das kann man ab und an mal brauchen. :confused:
 
Hier mal meine Routine zum Connect und Disconnect. Vielleicht kannst du da ja was rauslesen. ;) S7Online funktioniert bei mir. Step7 muß installiert sein. Allerdings hab ich das bisher immer nur mit einer SPS gleichzeitig hinbekiommen. Wollte ich 2 oder 3 SPS mit S7Online öffnen, bekam ich für jede SPS immer die Werte der ersten SPS, die Verbindung hergestellt hatte.

Code:
procedure Connect;
var
  Address: string;
  I, FIPPort: Integer;
begin
  //MPI libnodaveS7

  for I := 1 to SimDatenListe.SimN do
  begin
    if ((NOT DaveInterface.Remote[I].IsOpen) AND SimDatenListe.SimEintrag[I].ComSimState AND NOT (SimDatenListe.SimEintrag[I].Driver = AS511_DLL)) then
    begin
      Case SimDatenListe.SimEintrag[I].Protocol of
        Ord(daveProtoMPI), Ord(daveProtoMPI2), Ord(daveProtoMPI3), Ord(daveProtoMPI4), Ord(daveProtoPPI):
          begin
            Address:= ComPort_to_Str(SimDatenListe.SimEintrag[I].ComPort) + #0;
            DaveInterface.Remote[I].DaveFDS.rfd:=SetPort(@Address[1], '38400', 'O');
          end;
        Ord(daveProtoAS511):
          begin
            Address:= ComPort_to_Str(SimDatenListe.SimEintrag[I].ComPort) + #0;
            DaveInterface.Remote[I].DaveFDS.rfd:=SetPort(@Address[1], '9600', 'E');
            DaveInterface.Remote[I].CpuRack := 0;
            DaveInterface.Remote[I].CpuSlot := 0;
          end;
        Ord(daveProtoISOTCP), Ord(daveProtoISOTCP243), Ord(daveProtoIBH), Ord(daveProtoIBH_PPI), Ord(daveProtoNLPro):
          begin
            Address:= SimDatenListe.SimEintrag[I].IPAddress + #0;
            FIPPort := SetIPPort(SimDatenListe.SimEintrag[I].Protocol);
            DaveInterface.Remote[I].IPPort := FIPPort;
            DaveInterface.Remote[I].DaveFDS.rfd:=OpenSocket(FIPPort, @Address[1]);
          end;
       [COLOR="Red"] Ord(daveProtoS7Online):
          begin
            Address:= 'S7ONLINE'+ #0;
            DaveInterface.Remote[I].DaveFDS.rfd:=OpenS7Online(@Address[1], Application.MainForm.Handle);[/COLOR]
          end;
      end;
    end;

    if ((NOT DaveInterface.Remote[I].IsOpen) AND SimDatenListe.SimEintrag[I].ComSimState AND NOT (SimDatenListe.SimEintrag[I].Driver = AS511_DLL)) then
    begin
      DaveInterface.Remote[I].DaveFDS.wfd := DaveInterface.Remote[I].DaveFDS.rfd;
      if DaveInterface.Remote[I].DaveFDS.rfd >= 0 then
      begin
        Address:='IFS'+IntToStr(I) + #0;
        DaveInterface.MPIlocal := SimDatenListe.SimEintrag[I].MPILocal;
        DaveInterface.Remote[I].Protocol := TNodaveProtocol(SimDatenListe.SimEintrag[I].Protocol);
        DaveInterface.MPISpeed := TNodaveSpeed(SimDatenListe.SimEintrag[I].MPISpeed);
        DaveInterface.Remote[I].DaveIntf:=daveNewInterface(DaveInterface.Remote[I].DaveFDS, @Address[1], DaveInterface.MPILocal, ProtCode(DaveInterface.Remote[I].Protocol), Ord(DaveInterface.MPISpeed));
        DaveInterface.Remote[I].DaveIntf^.timeout:=SimDatenListe.SimEintrag[I].Timeout;
        DaveInterface.Remote[I].IntfError:=daveInitAdapter(DaveInterface.Remote[I].DaveIntf);
        if DaveInterface.Remote[I].IntfError = 0 then
        begin
          if ((not DaveInterface.Remote[I].RemoteActive) AND SimDatenListe.SimEintrag[I].ComSimState) then
          begin
            DaveInterface.Remote[I].DaveConn:=daveNewConnection(DaveInterface.Remote[I].DaveIntf, DaveInterface.Remote[I].MPIRemote, DaveInterface.Remote[I].CpuRack, DaveInterface.Remote[I].CpuSlot);
            DaveInterface.Remote[I].LastError:=daveConnectPLC(DaveInterface.Remote[I].DaveConn);
            DaveInterface.Remote[I].RemoteActive:=(DaveInterface.Remote[I].LastError = 0);
//            If DaveInterface.Remote[I].Active then
//              ReadBytes
//            else
//              DoOnError(daveStrerror(FLastError));
            Last_DaveError_Str := daveStrerror(DaveInterface.Remote[I].LastError);
            InitPG1Fehler := DaveInterface.Remote[I].LastError;
            DaveInterface.Remote[I].IntfActive := True;
          end;
        end;
      end
      else
      begin
        InitPG1Fehler := 1001;//DaveInterface.Remote[I].DaveFDS.rfd;
        DaveInterface.Remote[I].LastError := 1001;//DaveInterface.Remote[I].DaveFDS.rfd;
        Last_DaveError_Str := 'kein Interface';
      end;
    end
    else
    begin
//      InitPG1Fehler := DaveInterface.Remote[I].DaveFDS.rfd;
//      DaveInterface.Remote[I].LastError := DaveInterface.Remote[I].DaveFDS.rfd;
//      Last_DaveError_Str := daveStrerror(DaveInterface.Remote[I].LastError);
    end;
  end;
end;

//Close the connection to the PLC.
procedure Disconnect;
var
  I: Integer;
begin
  for I := 1 to SimDatenListe.SimN do
  begin
    if DaveInterface.Remote[I].IntfActive then
    begin
//      if DaveInterface.Remote[I].IntfError <> 0 then
      begin
        try
//          if DaveInterface.Remote[I].LastError = 0 then   //wurde mit der neuen Version von Axel mit Timout für TCP beseitigt!!!!!
            DaveInterface.Remote[I].IntfError := daveDisconnectPLC(DaveInterface.Remote[I].DaveConn);
          daveFree(DaveInterface.Remote[I].DaveConn);
          DaveInterface.Remote[I].IntfError := daveDisconnectAdapter(DaveInterface.Remote[I].DaveIntf);
          daveFree(DaveInterface.Remote[I].DaveIntf);
          if DaveInterface.Remote[I].Protocol <> daveProtoS7Online then
          begin
            if ((DaveInterface.Remote[I].Protocol = daveProtoISOTCP)
               or (DaveInterface.Remote[I].Protocol = daveProtoISOTCP243)
               or (DaveInterface.Remote[I].Protocol = daveProtoIBH)
               or (DaveInterface.Remote[I].Protocol = daveProtoIBH_PPI)
               or (DaveInterface.Remote[I].Protocol = daveProtoNLPro)) then
              closeSocket(DaveInterface.Remote[I].DaveFDS.rfd)
            else
              closePort(DaveInterface.Remote[I].DaveFDS.rfd);
          end
          else
          begin
            [COLOR="Red"]closeS7online(DaveInterface.Remote[I].DaveFDS.rfd);[/COLOR]
          end;
        except
//        On E: Exception do DoOnError('Error in function TNoDave.Disconnect: ' + E.Message);
        end;
        DaveInterface.Remote[I].IntfActive := False;
        DaveInterface.Remote[I].RemoteActive := False;
      end;
    end;
  end;
end;
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@Ralle: Yepp, das funktioniert. Meine Version war ja in etwa genau so gemacht ... Das Problem lag woanders ...

@Zottel: Schlechte Nachrichten ... Ich glaube mit Delphi 2009 funktioniert die Library nicht mehr. Ein Connect war absolut unmöglich.
Die selbe Applikation unter Delphi 2007 compiliert rennt :!:
Warum das so ist, kann ich nicht sagen, aber scheinbar ist der Compiler soweit verändert, das eben die LibNoDave nicht mehr geht.
Eventuell hat das damit zu tun, das einiges verändert wurde betreffend Unicode. Vielleicht haut das mit den Strings und PChars so nicht mehr hin...
Ist aber nur ein Verdacht :confused:
 
Hallo QM,

das du meinen Verdacht mit mir teilst, finde ich ja irgendwie doof :ROFLMAO:

Ich hoffte wirklich das es wie sonst auch an mir liegt, aber ich glaube diesmal eben auch nicht ... Sehr schlecht ...

Werde dann wohl umsteigen/downgraden auf ein altes Delphi ...

Vielleicht gibt es ja bald mal eine neue Version von LibNoDave :D
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Vielleicht gibt es ja bald mal eine neue Version von LibNoDave :D
Habe kein Delphi, kann daher nicht nachprüfen.
Und was mache ich dann?
Umstellen auf neu und alle mit alt ärgern sich?
Oder 2 Versionen?
Es müßte meiner Meinung nach reichen, daß der Anwender nodave.pas neu kompiliert. Falls Pchars jetzt auf Unicode zeigen müßte man halt ein PByte definieren.
 
Unicode

Hallo,

Zottel schrieb:
Falls Pchars jetzt auf Unicode zeigen müßte man halt ein PByte definieren.

Naja, diese Auffassung kann ich nicht so richtig teilen. Unicode heisst zwei Byte pro Zeichen, im Gegensatz zum altbekannten Ansicode mit 1 Char = 1 Byte.
Viele Delphianer haben lautstark die Einführung von Unicode zur Internationalisierung Ihrer Anwendungen von Embarcadero (früher Borland und auch GodeGear) in den entsprechenden Foren eingefordert. Das ist mit D2009 nun endlich geschehen, als Folge davon darf ich nochmal einige tausend Euronen in aktualisierte Fremdkomponenten von Kassl, DevArt, Steema Software, TMS und Konsorten investieren...

Lazarus schrieb:
Ich hoffte wirklich das es wie sonst auch an mir liegt, aber ich glaube diesmal eben auch nicht

Nee, liegt nicht an Dir, die Umstellung von Delphi auf Unicode hat wirklich interessante Effekte :ROFLMAO:

Gruß

Question_mark
 
Zottel: Danke, du hast recht. *ACK*

Ich habe in der NoDave.pas:

- ALLE pChar gegen pAnsiChar
- ALLE String gegen AnsiString
- ALLE Char gegen AnsiChar

getauscht und funzt ...

Das Selbe auch in der NoDaveComponent und alles rennt wieder ...


Danke dir ... :ROFLMAO:
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
@Zottel: Ich habe das alles jetzt etwas genauer getestet. Mit den o.g. Änderungen läuft alles korrekt, soweit ich das getestet habe.
Eine Übersetzung mit einem "älteren" Delphi 2007 war genauso möglich.

Eventuell könnte man die Änderungen ja direkt mit in dein Librarypaket stecken. Zumindest habe ich die Dateien mal mit angehängt ...
 

Anhänge

  • NoDave_D2K9.zip
    21,9 KB · Aufrufe: 48
Hallo,

ich hänge mich hier einfach mal an.
Hab der Komponente auch noch 3 Kleinigkeiten hinzugefügt.

1.
Code:
procedure TNoDave.ReadManyBytes(Area: TNoDaveArea; DB, Start, Size: Integer; Buffer: Pointer);
2.
Code:
function TNoDave.GetString(Address: Integer; Buffer: Pointer; BufOffs: Integer; BufLen: Integer): AnsiString;
3.
Code:
procedure TNoDave.WriteString(Address: Integer; Value: AnsiString; Count: Byte);
 

Anhänge

  • nodavecomponent.rar
    9,8 KB · Aufrufe: 19
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo ...

schön, das sich was tut. Gibt es denn eventuell demnächst eine
Aktualisierung der Komponente ????

Ein paar "neue" funktionen fehlen inzwischen in der Komponente.
Von daher wäre eine Überarbeitung schön. Wenn du (AFK) eventuell
etwas unterstützung brauchen kannst, dann sag bescheid... Ich kann sicher
etwas Zeit freischaufeln dafür :)

Und vielen Dank für diese schöne Komponente... Dieser Dank geht natürlich
auch an Zottel für die hervorragende Arbeit ...
 
Zuletzt bearbeitet:
- ALLE pChar gegen pAnsiChar
- ALLE String gegen AnsiString
- ALLE Char gegen AnsiChar
Habe ich in meiner Version nachgezogen, danke für die Suche nach der Lösung.

Code:
procedure TNoDave.ReadManyBytes(Area: TNoDaveArea; DB, Start, Size: Integer; Buffer: Pointer);
function TNoDave.GetString(Address: Integer; Buffer: Pointer; BufOffs: Integer; BufLen: Integer): AnsiString;
procedure TNoDave.WriteString(Address: Integer; Value: AnsiString; Count: Byte);
Der Aufruf von daveReadManyBytes in der der Methode DoReadManyBytes hat eigentlich keinen Sinn gemacht, da in der Methode DoReadManyBytes schon immer bei Bedarf in mehrere Blöcke geteilt wurde. Darum habe ich die Methoden vor geraumer Zeit wieder rausgeschmissen, ReadManyBytes macht daher auch keinen Sinn mehr.

GetString und WriteString hab ich mir angeschaut, habe mich dann aber entschlossen, das etwas anders zu implementieren:
Code:
function TNoDave.GetString(Address: Integer; Buffer: Pointer; BufOffs, BufLen: Integer): AnsiString;
var
  BufPtr: Pointer;
  MaxLen: Integer;
  ActLen: Integer;
  BufIdx: Integer;
begin
  Result:='';
  If BufOffs = -1 then BufOffs:=FBufOffs;
  If BufLen = -1 then BufLen:=FBufLen;
  BufPtr:=BufferAt(Address, 1, Buffer, BufOffs, BufLen);
  If Assigned(BufPtr) then MaxLen:=daveGetU8From(BufPtr) else MaxLen:=0;
  If MaxLen > 0 then
  begin
    BufPtr:=BufferAt(Address + 1, 1, Buffer, BufOffs, BufLen);
    If Assigned(BufPtr) then ActLen:=daveGetU8From(BufPtr) else ActLen:=0;
    If ActLen > MaxLen then Exit;
    BufIdx:=0;
    While BufIdx < ActLen do
    begin
      BufPtr:=BufferAt(Address + 2 + BufIdx, 1, Buffer, BufOffs, BufLen);
      If Assigned(BufPtr) then Result:=Result + Chr(daveGetU8From(BufPtr)) else
      begin
        Result:='';
        Exit;
      end;
      Inc(BufIdx);
    end;
  end;
end;

procedure TNoDave.WriteString(Address: Integer; Value: AnsiString);
var
  MaxLen: Byte;
  ActLen: Byte;
  Dummy: AnsiString;
begin
  MaxLen:=0;
  ReadBytes(FArea, FDBNumber, Address, 1, @MaxLen);
  ActLen:=Length(Value);
  If ActLen > MaxLen then ActLen:=MaxLen;
  Dummy:=Chr(ActLen) + Copy(Value, 1, ActLen);
  DoWriteValue(Address + 1, MaxLen + 1, @Dummy);
end;
Dadurch ist bei WriteString zwar ein zusätzlicher Lesezugriff erforderlich (langsamer), allerdings wird dafür verhindert, daß die Struktur eines Datenbausteins vom PC aus "kaputtgeschrieben" wird.

Ich hoffe, daß sich da kein Fehler eingeschlichen hat, da ich es bei mir hier nicht so auf die Schnelle testen kann.


Gruß Axel
 
Zurück
Oben