After a deep dive into the code I understand a few things and found a solution for my problem.
First thought was to modify the function block DLOG_STORE_FILE_CSV, but if the OSCAT library will be changed in the future, the function block will differ (I would like to prevent that scenario).
Second thought was to modify the call of the function block. To do so I did:
- Previous to the call of DLOG_STORE_FILE_CSV, a separate FILE_SERVER is used to try to open the file. When there is no error code, the file exist. Then only the DLOG_SAVE.FN_REM has to be manipulated by copying the filename to it. Then the function block DLOG_STORE_FILE_CSV is called and thinks that it was already written to this filename and therefore only append the additional entries. Thats like the filename was stored in the retained variable.
When there is an error while trying to open the file, the DLOG_SAVE.FN_REM will be erased and the enabled will be set to FALSE for some cycles/time. Therefore the function DLOG_STORE_FILE_CSV thinks, that there it wasn't written to that filename in the past. Therefore a new file will be created with new header line.
Sounds complicated and it is ;-) But it's (just) a preconfiguration for a non existent feature of DLOG_STORE_FILE_CSV. It would be nice if some can switch the functionality in the interface of the function call. To either use retained variables or directly check if the file exist at write request.
But I also would understand that this will complex the code to much by adding a feature select.
This is my code to preconfigure the implementation to add this feature.
Declaration:
Code:
First thought was to modify the function block DLOG_STORE_FILE_CSV, but if the OSCAT library will be changed in the future, the function block will differ (I would like to prevent that scenario).
Second thought was to modify the call of the function block. To do so I did:
- Previous to the call of DLOG_STORE_FILE_CSV, a separate FILE_SERVER is used to try to open the file. When there is no error code, the file exist. Then only the DLOG_SAVE.FN_REM has to be manipulated by copying the filename to it. Then the function block DLOG_STORE_FILE_CSV is called and thinks that it was already written to this filename and therefore only append the additional entries. Thats like the filename was stored in the retained variable.
When there is an error while trying to open the file, the DLOG_SAVE.FN_REM will be erased and the enabled will be set to FALSE for some cycles/time. Therefore the function DLOG_STORE_FILE_CSV thinks, that there it wasn't written to that filename in the past. Therefore a new file will be created with new header line.
Sounds complicated and it is ;-) But it's (just) a preconfiguration for a non existent feature of DLOG_STORE_FILE_CSV. It would be nice if some can switch the functionality in the interface of the function call. To either use retained variables or directly check if the file exist at write request.
But I also would understand that this will complex the code to much by adding a feature select.
This is my code to preconfigure the implementation to add this feature.
Declaration:
Code Auswählen
VAR
R_TRIG_LogExportRequest: R_TRIG;
xFileExistChecked: BOOL;
xFileExist: BOOL;
usiStep1: USINT := 1;
usiStep2: USINT := 1;
FS : OSCAT_NETWORK.FILE_SERVER;
FSD : OSCAT_NETWORK.FILE_SERVER_DATA;
PT : OSCAT_NETWORK.NETWORK_BUFFER;
trig_m : BOOL; // Manual trigger (for storage of values to new line of file)
trig_m_last : BOOL; // Last manual trigger (for storage of values to new line of file)
filename: STRING := 'Log'; // Name of file 'Log#A-#D-#H'
error_c: DWORD; // Corresponding error code
error_t: BYTE; // Corresponding error type
tonEnable: STANDARD.TON := (PT:=T#1000MS);
x1 : OSCAT_NETWORK.DLOG_DT := (COLUMN:='Time stamp'); // Logger input for STRING, used for Time stamp
x2 : OSCAT_NETWORK.DLOG_STRING := (COLUMN:='Event type'); // Logger input for STRING, used for Event type
x3 : OSCAT_NETWORK.DLOG_STRING := (COLUMN:='Description'); // Logger input for STRING, used for Description
x : OSCAT_NETWORK.DLOG_DATA; // Data exchange for logging and file storage
RTC_2: OSCAT_NETWORK.OSCAT_BASIC.RTC_2; // Clock needed for (tsv) file write
DLOG_STORE_FILE_TSV : DLOG_STORE_FILE_CSV; // File storage (tsv)
END_VAR
VAR RETAIN
save_data : OSCAT_NETWORK.DLOG_SAVE;
END_VAR
Code:
Code Auswählen
R_TRIG_LogExportRequest(CLK:=(LogExport.uiTxBufferCount > 0));
IF R_TRIG_LogExportRequest.Q THEN
xFileExistChecked := FALSE;
xFileExist := FALSE;
usiStep1 := 1;
usiStep2 := 1;
END_IF
IF NOT xFileExistChecked THEN
CASE usiStep1 OF
01: FSD.MODE := 5; // Close the possibly opened file
FSD.FILENAME:='Log'; // with filename "Log"
usiStep1 := 2;
02: IF FSD.MODE = 0 THEN // Close operation finished
usiStep1 := 3;
END_IF
03: FSD.MODE := 1; // Open+read file
usiStep1 := 4;
04: IF FSD.MODE = 0 THEN // Open+read operation finished
usiStep1 := 5;
END_IF
05: IF FSD.ERROR = 0 THEN // Open+read w/o error = file exist
xFileExist := TRUE;
ELSIF FSD.ERROR = 5 THEN // Open+read w error = file not exist
xFileExist := FALSE;
END_IF
xFileExistChecked := TRUE;
END_CASE;
FS(FSD:=FSD,PT:=PT); // File server operation
END_IF
IF xFileExistChecked THEN
CASE usiStep2 OF
01: IF xFileExistChecked AND xFileExist THEN // File exist = enable (to only open+write)
enable := TRUE;
save_data.FN_REM := 'Log'; // copy the file name to remanent variable to prevent "create+write"
ELSIF xFileExistChecked AND NOT xFileExist THEN // File not exist = not enable -> enable (to create new file with header)
enable := FALSE;
save_data.FN_REM := ''; // delete file name in remanetn variable to allow "create+write"
END_IF
usiStep2 := 2;
02: IF NOT enable THEN // Reenable when preveiously disabled
enable := TRUE;
END_IF
usiStep2 := 3;
03: IF LogExport.uiTxBufferCount > 0 AND trig_m = trig_m_last AND tonEnable.Q THEN
trig_m := TRUE; // Set the trigger
END_IF
trig_m_last := trig_m;
tonEnable(IN:=enable);
END_CASE
x1(X:=x); // Logger input for STRING, used for Time stamp
x2(X:=x, STR:=LogExport.asTxContent[1].sLogExportText2); // Logger input for STRING, used for Event type
x3(X:=x, STR:=LogExport.asTxContent[1].sLogExportText3); // Logger input for STRING, used for Description
DLOG_STORE_FILE_TSV(X:=x, SAVE_DATA:=save_data, ENABLE:=enable, TRIG_M:=trig_m, FILENAME:=filename, DTI:=RTC_2.UDT, SEP:=9, AUTO_CLOSE:=TIME#10S, ERROR_C=>error_c, ERROR_T=>error_t); // File storage (tsv)
IF trig_m THEN
trig_m := FALSE; // Reset the trigger
FOR iI := 1 TO TO_INT(LogExport.uiTxBufferCount) - 1 DO // Shift every entry one index up
LogExport.asTxContent[iI].sLogExportText2 := LogExport.asTxContent[iI+1].sLogExportText2;
LogExport.asTxContent[iI].sLogExportText3 := LogExport.asTxContent[iI+1].sLogExportText3;;
END_FOR
LogExport.asTxContent[iI].sLogExportText2 := '';
LogExport.asTxContent[iI].sLogExportText3 := ''; // And fill the last one with an empty entry
LogExport.uiTxBufferCount := LogExport.uiTxBufferCount - 1; // And decrement the buffer counter
END_IF
END_IF