TYPE "ANY_POINTER"
VERSION : 0.1
STRUCT
SyntaxID : Byte;
Bereichstyp : Byte;
Anzahl_Werte : UInt;
DB_Nr : UInt;
Startadresse : DWord;
END_STRUCT;
END_TYPE
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
Cycl_Save : Bool; // DB Zyklisch in remanenz Lade und Arbeitspeicher sichern
Cycl_Time : Time := T#1H; // cycle time to save datablock on SD Card
END_VAR
VAR_IN_OUT
SaveDB : Bool;
RecoverDB : Bool;
END_VAR
VAR
init : Bool := TRUE; // true. Instance is reinitialized
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 {InstructionName := 'F_TRIG'; LibVersion := '1.0'} : F_TRIG;
Status { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
Status_attr { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
Status_crea { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
Status_Attr_DB { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
Status_BLKMOV_Save { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
Status_BLKMOV_Recover { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
acttime {InstructionName := 'DTL'; LibVersion := '1.0'; ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : DTL;
oldtime {InstructionName := 'DTL'; LibVersion := '1.0'; ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : DTL;
time_status : Int;
timeflanke : Bool;
GetSMCinfo_Instance {InstructionName := 'GetSMCinfo'; LibVersion := '1.1'} : GetSMCinfo;
SD_Info : UDInt;
SD_Info_Req : Bool;
Anz_Restores : UDInt;
Anz_Sicherungen : UDInt;
Anz_creates : UDInt;
Trigger {InstructionName := 'R_TRIG'; LibVersion := '1.0'} : Array[0..5] of R_TRIG;
tpINIT {InstructionName := 'TP_TIME'; LibVersion := '1.0'} : TP_TIME;
tonCycl {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
END_VAR
VAR_TEMP
pSourceDB : Any;
ptSourceDB AT pSourceDB : "ANY_POINTER";
pSaveDB : Any;
ptSaveDB AT pSaveDB : "ANY_POINTER";
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
#time_status := RD_SYS_T(#acttime); // Reads the Actual Systemtime
#tpINIT(IN := #init, // When init is set then there is a 10s pulse witch prevents that zero data will be written because of wrong readings
PT := t#10s);
// read actual Lifestatus of the SD Card
#GetSMCinfo_Instance(REQ := #SD_Info_Req,
Mode := 2,
Info := #SD_Info);
IF #SD_Info_Req AND (#GetSMCinfo_Instance.Done OR #GetSMCinfo_Instance.Error) THEN
#SD_Info_Req := false;
END_IF;
// Jede Zeiteinstellung eine Sicherung durchführen
#tonCycl(IN := NOT (#tpINIT.Q OR #timeflanke OR #RecoverDB OR #SaveDB),
PT := #Cycl_Time);
#timeflanke := #tonCycl.Q;
IF #Cycl_Save THEN // If Cycl_Time active save at Cycle_time
IF #timeflanke THEN
#SaveDB := true;
END_IF;
END_IF;
#pSourceDB := #DB_TO_SAVE;
#speicherbereich := DWORD_TO_WORD(ROR(IN := #ptSourceDB.Startadresse, N := 24));
(*Pointer for DB to save from*)
#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;
(*Pointer for DB to save to*)
#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;
// To Delete DB if needed.
#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 #tpINIT.Q THEN
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;
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 := #ptSourceDB.Anzahl_Werte, // 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);
#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;
// Zähler der Lese und Schreibvorgänge
#Trigger[0].CLK := (#Status_BLKMOV_Recover = W#16#7001);
IF #Trigger[0].Q THEN
#Anz_Restores := #Anz_Restores + 1;
END_IF;
#Trigger[1].CLK := (#Status_BLKMOV_Save = W#16#7001);
IF #Trigger[1].Q THEN
#Anz_Sicherungen := #Anz_Sicherungen + 1;
END_IF;
#Trigger[2].CLK := (#Status_crea = W#16#7001);
IF #Trigger[2].Q THEN
#Anz_creates := #Anz_creates + 1;
END_IF;
// Init reset
#init := false;
END_FUNCTION_BLOCK