TIA SPS-Forum gemeinschaftsprojekt? DB im Ladespeicher sichern um Reinit zu verhindern

vollmi

Level-3
Beiträge
5.447
Reaktionspunkte
1.413
Zuviel Werbung?
-> Hier kostenlos registrieren
Hi zusammen

Viele hier nerven sich ja bestimmt auch über die unmotivierten Reinits von TIA wenn man das Programm in die Steuerung läd.
ich dachte mir, vielleicht besteht ja interesse gemeinsam an einem guten Baustein zu schreiben der uns einen ArbeitsspeicherDB in einen LadespeicherDB auf der Memorycard sichert und automatisch wiederherstellt.

Ich hab da mal was angefangen das grundsätzlich auch schon funktioniert. Aber er hat noch keine richtige Fehlerbehandlung und bestimmt einiges an Verbesserungspotential. Besteht interesse darin diesen Baustein offen weiterzuentwickeln und zu verbessern. Er soll aber weiterhin frei zugänglich bleiben (ggf erlauben das ja nicht alle Arbeitgeber mit Werksentwicklungslizenzen)

Hier was ich schon habe:
Code:
FUNCTION_BLOCK "SaveDatablock"
{ S7_Optimized_Access := 'FALSE' }
AUTHOR : VoR
VERSION : 0.1
//Baustein soll einen kompletten DB im Ladespeicher sichern. Um TIA Reinitialisationen zu begrenzen.
//Der zu sichernde DB darf nicht optimiert sein.
//Die Sicherung muss durch SaveDB getriggert. SaveDB wird vom Baustein zurückgesetzt.
   VAR_INPUT 
      DB_TO_SAVE : Any;   // Welcher DB soll gesichert werden
      DB_NR_Loadmem { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : UInt := 60000;   // DBNR_Ab 60000 im Ladespeicher
   END_VAR


   VAR_IN_OUT 
      SaveDB : Bool;
      RecoverDB : Bool;
   END_VAR


   VAR 
      DeleteDB : Bool;
      CreateDB : Bool;
      DelBusy : Bool;
      Attrib : Byte;
      Attr_DB_Lenght : UDInt;
      Create_DB_Busy : Bool;
      Create_DB_Num : UInt;
      Busy_Write : Bool;
      Busy_Read : Bool;
      Status_BLKMOV_Save_1 : Int;
      Status_BLKMOV_Recover_1 : Int;
      speicherbereich : Word;
      testpointer : "ANY_POINTER";
      trueval { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool := true;
      FN_Busy {OriginalPartName := 'F_TRIG_1500'; LibVersion := '1.0'} : F_TRIG;
   END_VAR


   VAR_TEMP 
      pSourceDB : Any;
      ptSourceDB AT pSourceDB : "ANY_POINTER";
      pSaveDB : Any;
      ptSaveDB AT pSaveDB : "ANY_POINTER";
      Status : Int;
      Status_attr : Int;
      Status_crea : Int;
      Status_Attr_DB : Int;
      Status_BLKMOV_Save : Int;
      Status_BLKMOV_Recover : Int;
      DB_Lenght : UDInt;
      Attrib_RCV : UDInt;
      Anzahl_Werte : Word;
      InitBool : Bool;
      DB_save_Length : UDInt;
      DB_save_Attrib : Byte;
      Attr_status : Int;
      Attr_status_st : Struct
         Ladespeicher : Bool;
         writeprotect : Bool;
         remanent : Bool;
         ladeundarbeitspeicher : Bool;
      END_STRUCT;
   END_VAR




BEGIN
	#pSourceDB := #DB_TO_SAVE;
	
	#speicherbereich := DWORD_TO_WORD(ROR(IN := #ptSourceDB.Startadresse, N := 24));
	
	(*Pointer aufbereiten für kompletten DB*)
	    #ptSourceDB.SyntaxID := B#16#10;
	    #ptSourceDB.Bereichstyp := 2;
	    #Status_Attr_DB := ATTR_DB(REQ := True,
	                               DB_NUMBER := #ptSourceDB.DB_Nr,
	                               DB_LENGTH => #DB_Lenght,
	                               ATTRIB => #Attrib_RCV);
	    #Anzahl_Werte := UDINT_TO_WORD(#DB_Lenght);
	    #ptSourceDB.Anzahl_Werte := UDINT_TO_UINT(#Anzahl_Werte);
	    #ptSourceDB.Startadresse := DW#16#84000000;
	    
	    
	#ptSaveDB := #ptSourceDB; //Source/Save Pointer abgleichen
	#ptSaveDB.DB_Nr := #DB_NR_Loadmem;
	#Attr_status := ATTR_DB(REQ:=True, DB_NUMBER:=#ptSaveDB.DB_Nr, DB_LENGTH=>#DB_save_Length, ATTRIB=>#DB_save_Attrib);
	#Attr_status_st.Ladespeicher := #DB_save_Attrib.%X0; // Nachsehen ob DB zur Sicherung existiert.
	#Attr_status_st.writeprotect := #DB_save_Attrib.%X1;
	#Attr_status_st.remanent := #DB_save_Attrib.%X2;
	#Attr_status_st.ladeundarbeitspeicher := #DB_save_Attrib.%X3;
	
	// Vielleicht will man den DB mal aus dem Programm gesteuert löschen.
	#Status := DELETE_DB(REQ := #DeleteDB, DB_NUMBER := LINT_TO_UINT(60000), BUSY => #DelBusy);
	#DeleteDB := false;
	
	(* Wenn DB nicht im Ladespeicher und auch keine DB Generierung im Gang
	Dann Einen DB auf der Karte erstellen um ihn als Sicherung zu nutzen *)
	IF NOT #Attr_status_st.Ladespeicher AND NOT #Create_DB_Busy THEN
	    #CreateDB := true;
	ELSIF #Create_DB_Busy THEN // Generierung im Gang Init Bool setzen da dieser DB nicht zurückgesichert werden soll
	    #CreateDB := false;
	    POKE_BOOL(area := 16#84,
	              dbNumber := #ptSourceDB.DB_Nr,
	              byteOffset := 0,
	              bitOffset := 0,
	              value := TRUE);
	END_IF;
	
	// Erstes Bit im zu sichernden DB überprüfen, wenn 0 dann soll DB restored werden.
	#InitBool := PEEK_BOOL(area := 16#84, dbNumber := #ptSourceDB.DB_Nr, byteOffset := 0, bitOffset := 0);
	
	#Status_crea := CREATE_DB(REQ := #CreateDB,
	                          LOW_LIMIT := #ptSaveDB.DB_Nr,
	                          UP_LIMIT := #ptSaveDB.DB_Nr,
	                          COUNT := 65534, // DB in maximaler Grösse. SD Karten kosten nix und es muss nicht neu generiert werden bei Grössenänderung
	                          ATTRIB := b#8#1,
	                          SRCBLK:=#pSourceDB, BUSY => #Create_DB_Busy,
	                          DB_NUM => #Create_DB_Num);
	
	#testpointer := #ptSaveDB; // Nur für Testzwecke. Kann am Schluss gelöscht werden.
	
	#Status_BLKMOV_Save := WRIT_DBL(REQ := #SaveDB AND NOT #Create_DB_Busy, // DB inhalt sichern
	                                SRCBLK := #pSourceDB,
	                                BUSY => #Busy_Write,
	                                DSTBLK => #pSaveDB);
	
	IF #Status_BLKMOV_Save <> w#16#7000 THEN
	    #Status_BLKMOV_Save_1 := #Status_BLKMOV_Save;
	END_IF;
	
	IF NOT (#Busy_Write OR #Create_DB_Busy) THEN
	    #SaveDB := FALSE;
	END_IF;
	
	// DB wurde initialisiert Daten aus Sicherungsdb wiederherstellen.
	IF NOT #InitBool THEN
	    #RecoverDB := true;
	END_IF;
	
	#Status_BLKMOV_Recover := READ_DBL(REQ := #RecoverDB AND NOT #Create_DB_Busy,
	                                   SRCBLK := #pSaveDB,
	                                   BUSY => #Busy_Read,
	                                   DSTBLK =>#pSourceDB);
	
	IF #Status_BLKMOV_Recover <> w#16#7000 THEN
	    #Status_BLKMOV_Recover_1 := #Status_BLKMOV_Recover;
	END_IF;
	
	#FN_Busy(CLK:=#Busy_Read);
	
	
	IF #FN_Busy.Q THEN
	    #RecoverDB := FALSE;
	POKE_BOOL(area := 16#84,
	                           dbNumber := #ptSourceDB.DB_Nr,
	                           byteOffset := 0,
	                           bitOffset := 0,
	                           value:=TRUE);
	END_IF;
	
	
	
END_FUNCTION_BLOCK

Ich hab ihn schon auf CPUs mit diversen 1.8er Firmwares und 2.0er Firmware ausprobiert.

Der DB der Gesichert werden soll muss an erster Speicherstelle ein Bool haben das nicht verwendet wird. Dieses wird durch den Baustein auf FALSE überprüft. Wenn es FALSE (z.B. durch einen Reinit von TIA) ist, wird falls vorhanden der Inhalt des LadespeicherDBs zurückgelesen.

mfG René
 
Der Datentyp für den Anypointer noch:
Code:
TYPE "ANY_POINTER"
VERSION : 0.1
   STRUCT
      SyntaxID : Byte;
      Bereichstyp : Byte;
      Anzahl_Werte : UInt;
      DB_Nr : UInt;
      Startadresse : DWord;
   END_STRUCT;


END_TYPE

Ich denke das wäre halt n nettes Projekt um das Not invented here Syndrom etwas zu umschiffen. Viele brauchen das ja doch, und basteln sich so wie ich was zusammen dass ein bisschen funktioniert. stattdessen könnte man gemeinschaftlich wohl was zuverlässiges entwickeln das jedem dient.

mfG René
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Vielleicht noch zu erwähnen.
Zum Testen nutze ich einen 30kb grossen DB der sowohl im Lade wie auch im Arbeitsspeicher abgelegt ist.
Das sichern dauert auf einer 1512SP CPU zwischen 20 und 30 Zyklen.

den Aufruf hab ich mal so gemacht.
mit "SaveDB" kann man die Sicherung auslösen
mit "RecoverDB" kann man einen Restore der Daten auslösen (auch wenn der DB nicht initialisiert wurde, ein Init löst aber immer einen Restore aus)

Code:
"SaveEnergyData_DB"(DB_TO_SAVE := "EnergysaveDB",
                    DB_NR_Loadmem := 60000,
                    SaveDB := "SaveDB",
                    RecoverDB := "RecoverDB");

Kleine Anmerkung. Ab und zu lässt sich der erstellte DB nicht per TIA (V14) löschen, obwohl die CPU in Stop ist. Ein neustart von TIA löst das Problem vorübergehend.

mfG René
 
Das finde ich mal eine sehr coole Idee!

Habe zwar dafür keine Anwendung - da alles was bei mir in irgend einer Form Remanent sein müsste in der Rezeptur líegt, aber ich sehe den Nutzen deiner Funktion.

Grüße

Marcel
 
Idee ist es auf jeden Fall eine gute. Das Problem haben alle in irgendeiner Form.

@vollmi: Kurze Frage noch zum Ziel des Bausteins. Ist dein Ziel ein "Stoßfreies reinitialisieren" oder nur ein "Sichern der Werte".
Bei dem Baustein löst du vor dem Laden das "SaveDB" aus, lädst rein und der Baustein lädt dann automatisch zurück.
Dazwischen vergeht aber einige Zeit. Das Ergebnis wäre also ähnlich wenn man vor dem reinladen nochmal alle Momentanwerte als Startwerte setzt.
Vorteil hier dass die Startwerte des Offline-DB sauber bleiben. Oder versteh ich das falsch?

Wäre nicht eine Herangehensweise wo man zyklisch wegkopiert, glaube ducati hatte sie mal irgendwo vorgeschlagen, besser? Also:
  • Per Startbefehl einmal eine Kopie (in Länge) des gewünschten Dbs erzeugen (hier würde im Arbeitspeicher alleine auch reichen oder?)
  • Danach werden zyklisch am OB1-Beginn der Quell-Db auf den Save-Db kopiert (UBLKMOV oder sowas in der Art)
  • Dann lädt man den DB nach
  • Am OB1-Beginn wird dann an dem Flag erkannt dass initialisiert wurde.
  • Rückkopieren der Daten und Save-Db löschen.
  • Ende.
Das wäre bedeutend stoßfreier.
Frage am Rande: Braucht das "Erzeugen im RAM" mehr/weniger/gleich viele Zyklen als wenn auch im Ladespeicher erzeugt wird?

Für die optimierten DBs lässt sich leider schwer eine Lösung finden. Man kann die Dinger nicht im Gesamten anfassen, Länge nicht bestimmen, etc.
Hat da einer ne Idee?
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Das sichern dauert auf einer 1512SP CPU zwischen 20 und 30 Zyklen.

@vollmi: Kurze Frage noch zum Ziel des Bausteins. Ist dein Ziel ein "Stoßfreies reinitialisieren" oder nur ein "Sichern der Werte".

Wäre nicht eine Herangehensweise wo man zyklisch wegkopiert, glaube ducati hatte sie mal irgendwo vorgeschlagen, besser?

Jo, also wir brauchen es stoßfrei und machen es so:
TIA Portal DB Laden ohne reinitialisieren Beitrag 22

n bissl unschön ist es aber trotzdem, da man bei Erweiterungen des DB bzw. bei zusätzlichen neuen DBs immer auch den Sicherungs-DB und den Sicherungsmechanismus anpassen muss.

Gruß.
F
 
@vollmi: Kurze Frage noch zum Ziel des Bausteins. Ist dein Ziel ein "Stoßfreies reinitialisieren" oder nur ein "Sichern der Werte".

Mein Ziel war erstmal nur ein Sichern der Aktualdaten. z.B. Betriebsstunden, Parameter, Energiezählung. So das z.B. maximal ein Tag verloren geht.
Anders müsste man den Download durch TIA irgendwie abfangen. Ginge zwar auch. indem man den DB zyklisch in den Arbeitsspeicher sichert und sobald init aus dem arbeitsspeicher wieder zurücksichert. Das Problem ist dabei aber Arbeitsspeicher ist begrenzt.

Bei dem Baustein löst du vor dem Laden das "SaveDB" aus, lädst rein und der Baustein lädt dann automatisch zurück.
Dazwischen vergeht aber einige Zeit. Das Ergebnis wäre also ähnlich wenn man vor dem reinladen nochmal alle Momentanwerte als Startwerte setzt.
Vorteil hier dass die Startwerte des Offline-DB sauber bleiben. Oder versteh ich das falsch?

Hm ich sehe da eigentlich nicht wo ich den DB zurücklade wenn ich den SaveDB auslöse. der dürfte nur durch recoverdb zurückgeladen werden.
Kannst du mir die Stelle zeigen wo du das vermutest?

Ein DB im Ladespeicher zu erzeugen ist relativ unproblematisch IMHO weil der sehr gross sein kann.
Ein DB im Arbeitsspeicher zu erzeugen kann einem recht viel Speicherplatz fürs Programm nehmen. Vor allem wenn man recht grosse DBs sichern will.
Natürlich kann man das auch machen. Hinzukommt dann noch UBLOCKMOVE. Ich hab den noch nicht genutzt, aber könnte der nicht die Zykluszeit stark beeiflussen?

mfG René
 
Ja, ich denke die Anforderungen sind unterschiedlich... von daher benötigt man 2 Lösungen für die 2 unterschiedlichen Probleme. Wenn es um Verlust von Betriebsdaten geht, bzw. um das Ändern im laufenden Betrieb...

Gruß.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ja, ich denke die Anforderungen sind unterschiedlich... von daher benötigt man 2 Lösungen für die 2 unterschiedlichen Probleme. Wenn es um Verlust von Betriebsdaten geht, bzw. um das Ändern im laufenden Betrieb...

Ausserdem denke ich, dass die Sicherung über den Arbeitsspeicher nichts nützt wenn TIA upgedatet wird. Da wollte er mir schon DBs reinitialisieren die nirgends im Programm verwendet werden. Das könnte man mit deiner Methode auch abfangen, müsste den DB allerdings auch zur Laufzeit erzeugen.
Also beide Probleme zu erschlagen dürfte nicht trivial werden.
Aber an einem guten Baustein der auch stossfrei kann und trotzdem dynamisch arbeitet wäre ich also auch interessiert.

mfG René
 
Mein Ziel war erstmal nur ein Sichern der Aktualdaten. z.B. Betriebsstunden, Parameter, Energiezählung. So das z.B. maximal ein Tag verloren geht.
Ah, OK. Bei der 300/400 haben wir sowas auch. Da aber bei der 1500 nicht auf den selben DB im Ladespeicher gesichert werden kann ohne Zeitstempeländerung bzw. den opt. DBs ist dort mau.

Hm ich sehe da eigentlich nicht wo ich den DB zurücklade wenn ich den SaveDB auslöse.
Tust du auch nirgens. War nur schlecht/faul von mir ausgedrückt. Wir reden schon vom selben.

Ja, ich denke die Anforderungen sind unterschiedlich... von daher benötigt man 2 Lösungen für die 2 unterschiedlichen Probleme.
Daher die Frage. Sind tatsächlich 2 verschiedene Dinge.
 
n bissl unschön ist es aber trotzdem, da man bei Erweiterungen des DB bzw. bei zusätzlichen neuen DBs immer auch den Sicherungs-DB und den Sicherungsmechanismus anpassen muss.

Könnte man deine Vorgehensweise nicht auch in den Automatismus einbinden?
Also CREA_DB DB im Arbeitsspeicher generieren in der Grösse des zu sichernden DBs. Dann Zyklisch draufsichern.
Der zu sichernde DB dürfte dann einfach nicht remanent sein. Der Sicherungsdb wird aber remanent erstellt (nur um Remanenzspeicher zu sparen)
Mit Ublockmove wird dann zyklisch gesichert und rückgesichert mit recover.

Da müsste man sich dann aber wieder an den Step7 Speichervorhaltestil halten. Also der zu sichernde DB darf sich in Absoluter Grösse nicht verändern. UDTs müssen genügend Reserven für erweiterungen beinhalten.

Ich hab mir das ungefähr so vorgestellt. Aber Funktion noch nicht getestet da noch anderes Projekt in progress.
Code:
FUNCTION_BLOCK "SaveDatablock"
{ S7_Optimized_Access := 'FALSE' }
AUTHOR : VoR
VERSION : 0.2
//Baustein soll einen kompletten DB im Ladespeicher sichern. Um TIA Reinitialisationen zu begrenzen.
//Der zu sichernde DB darf nicht optimiert sein.
//Die Sicherung muss durch SaveDB getriggert. SaveDB wird vom Baustein zurückgesetzt.
// V0.2 Erweiterung für Zyklisches sichern in Arbeitsspeicher
   VAR_INPUT 
      DB_TO_SAVE : Any;   // Welcher DB soll gesichert werden
      DB_NR_Loadmem { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : UInt := 60000;   // DBNR_Ab 60000 im Ladespeicher
      Cycl_Save : Bool;   // DB Zyklisch in remanenz Lade und Arbeitspeicher sichern
   END_VAR


   VAR_IN_OUT 
      SaveDB : Bool;
      RecoverDB : Bool;
   END_VAR


   VAR 
      DeleteDB : Bool;
      CreateDB : Bool;
      DelBusy : Bool;
      Attrib : Byte;
      Attr_DB_Lenght : UDInt;
      Create_DB_Busy : Bool;
      Create_DB_Num : UInt;
      Busy_Write : Bool;
      Busy_Read : Bool;
      Status_BLKMOV_Save_1 : Int;
      Status_BLKMOV_Recover_1 : Int;
      speicherbereich : Word;
      testpointer : "ANY_POINTER";
      trueval { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool := true;
      FN_Busy {OriginalPartName := 'F_TRIG_1500'; LibVersion := '1.0'} : F_TRIG;
   END_VAR


   VAR_TEMP 
      pSourceDB : Any;
      ptSourceDB AT pSourceDB : "ANY_POINTER";
      pSaveDB : Any;
      ptSaveDB AT pSaveDB : "ANY_POINTER";
      Status : Int;
      Status_attr : Int;
      Status_crea : Int;
      Status_Attr_DB : Int;
      Status_BLKMOV_Save : Int;
      Status_BLKMOV_Recover : Int;
      DB_Lenght : UDInt;
      Attrib_RCV : UDInt;
      Anzahl_Werte : Word;
      InitBool : Bool;
      DB_save_Length : UDInt;
      DB_save_Attrib : Byte;
      Attr_status : Int;
      Attr_status_st : Struct
         Ladespeicher : Bool;
         writeprotect : Bool;
         remanent : Bool;
         ladeundarbeitspeicher : Bool;
      END_STRUCT;
   END_VAR




BEGIN
    #pSourceDB := #DB_TO_SAVE;
    
    #speicherbereich := DWORD_TO_WORD(ROR(IN := #ptSourceDB.Startadresse, N := 24));
    
    (*Pointer aufbereiten für kompletten DB*)
        #ptSourceDB.SyntaxID := B#16#10;
        #ptSourceDB.Bereichstyp := 2;
        #Status_Attr_DB := ATTR_DB(REQ := True,
                                   DB_NUMBER := #ptSourceDB.DB_Nr,
                                   DB_LENGTH => #DB_Lenght,
                                   ATTRIB => #Attrib_RCV);
        #Anzahl_Werte := UDINT_TO_WORD(#DB_Lenght);
        #ptSourceDB.Anzahl_Werte := UDINT_TO_UINT(#Anzahl_Werte);
        #ptSourceDB.Startadresse := DW#16#84000000;
        
        
    #ptSaveDB := #ptSourceDB; //Source/Save Pointer abgleichen
    #ptSaveDB.DB_Nr := #DB_NR_Loadmem;
    #Attr_status := ATTR_DB(REQ:=True, DB_NUMBER:=#ptSaveDB.DB_Nr, DB_LENGTH=>#DB_save_Length, ATTRIB=>#DB_save_Attrib);
    #Attr_status_st.Ladespeicher := #DB_save_Attrib.%X0; // Nachsehen ob DB zur Sicherung existiert.
    #Attr_status_st.writeprotect := #DB_save_Attrib.%X1;
    #Attr_status_st.remanent := #DB_save_Attrib.%X2;
    #Attr_status_st.ladeundarbeitspeicher := #DB_save_Attrib.%X3;
    
    // Vielleicht will man den DB mal aus dem Programm gesteuert löschen.
    #Status := DELETE_DB(REQ := #DeleteDB, DB_NUMBER := LINT_TO_UINT(60000), BUSY => #DelBusy);
    #DeleteDB := false;
    
    (* Wenn DB nicht im Ladespeicher und auch keine DB Generierung im Gang
    Dann Einen DB auf der Karte erstellen um ihn als Sicherung zu nutzen *)
    IF NOT #Attr_status_st.Ladespeicher AND NOT #Create_DB_Busy THEN
        #CreateDB := true;
    ELSIF #Create_DB_Busy THEN // Generierung im Gang Init Bool setzen da dieser DB nicht zurückgesichert werden soll
        #CreateDB := false;
        POKE_BOOL(area := 16#84,
                  dbNumber := #ptSourceDB.DB_Nr,
                  byteOffset := 0,
                  bitOffset := 0,
                  value := TRUE);
    END_IF;
    
    // Erstes Bit im zu sichernden DB überprüfen, wenn 0 dann soll DB restored werden.
    #InitBool := PEEK_BOOL(area := 16#84, dbNumber := #ptSourceDB.DB_Nr, byteOffset := 0, bitOffset := 0);
    
    IF NOT #Cycl_Save THEN
        #Status_crea := CREATE_DB(REQ := #CreateDB,
                                  LOW_LIMIT := #ptSaveDB.DB_Nr,
                                  UP_LIMIT := #ptSaveDB.DB_Nr,
                                  COUNT := 65534, // DB in maximaler Grösse. SD Karten kosten nix und es muss nicht neu generiert werden bei Grössenänderung
                                  ATTRIB := b#2#1,
                                  SRCBLK := #pSourceDB, BUSY => #Create_DB_Busy,
                                  DB_NUM => #Create_DB_Num);
    ELSE
        #Status_crea := CREATE_DB(REQ := #CreateDB,
                                  LOW_LIMIT := #ptSaveDB.DB_Nr,
                                  UP_LIMIT := #ptSaveDB.DB_Nr,
                                  COUNT := #DB_save_Length, // DB in Sicherungsgrösse da Remanenz und Arbeitspeicher gespart werden soll
                                  ATTRIB := B#2#1000, // in Arbeits und Ladespeicher remanent
                                  SRCBLK := #pSourceDB, BUSY => #Create_DB_Busy,
                                  DB_NUM => #Create_DB_Num);
    END_IF;
    
    #testpointer := #ptSaveDB; // Nur für Testzwecke. Kann am Schluss gelöscht werden.
    
    IF #Cycl_Save THEN
        IF NOT #Create_DB_Busy AND #InitBool THEN
            #Status_BLKMOV_Save := UBLKMOV(SRCBLK := #pSourceDB, DSTBLK => #pSaveDB);
        END_IF;
    ELSE
        #Status_BLKMOV_Save := WRIT_DBL(REQ := #SaveDB AND NOT #Create_DB_Busy, // DB inhalt sichern
                                        SRCBLK := #pSourceDB,
                                        BUSY => #Busy_Write,
                                        DSTBLK => #pSaveDB);
    END_IF;
    
    IF #Status_BLKMOV_Save <> w#16#7000 THEN
        #Status_BLKMOV_Save_1 := #Status_BLKMOV_Save;
    END_IF;
    
    IF NOT (#Busy_Write OR #Create_DB_Busy) THEN
        #SaveDB := FALSE;
    END_IF;
    
    // DB wurde initialisiert Daten aus Sicherungsdb wiederherstellen.
    IF NOT #InitBool THEN
        #RecoverDB := true;
    END_IF;
    
    IF #Cycl_Save THEN
        IF #RecoverDB AND NOT #Create_DB_Busy THEN
            #Status_BLKMOV_Recover := UBLKMOV(SRCBLK := #pSaveDB, DSTBLK => #pSourceDB);
            "RecoverDB" := false;
            POKE_BOOL(area := 16#84,
                      dbNumber := #ptSourceDB.DB_Nr,
                      byteOffset := 0,
                      bitOffset := 0,
                      value := TRUE);
        END_IF;
    ELSE
        #Status_BLKMOV_Recover := READ_DBL(REQ := #RecoverDB AND NOT #Create_DB_Busy,
                                           SRCBLK := #pSaveDB,
                                           BUSY => #Busy_Read,
                                           DSTBLK => #pSourceDB);
    END_IF;
    
    IF #Status_BLKMOV_Recover <> w#16#7000 THEN
        #Status_BLKMOV_Recover_1 := #Status_BLKMOV_Recover;
    END_IF;
    
    #FN_Busy(CLK:=#Busy_Read);
    
    
    IF #FN_Busy.Q THEN
        #RecoverDB := FALSE;
        POKE_BOOL(area := 16#84,
                  dbNumber := #ptSourceDB.DB_Nr,
                  byteOffset := 0,
                  bitOffset := 0,
                  value := TRUE);
    END_IF;
    
    
    
END_FUNCTION_BLOCK

mfG René
 
Zuletzt bearbeitet:
Zurück
Oben