Following on my previous blog “Datalogging in IEC 61131-3: The basic principle”, I want to show you something extra.
To read and write data, you only need to implement some basic commands.
In this blog, we are going to create the following methods:
- Create a file
- Create a file and directly write a header line
- Delete a file
- Read a line
- Write a line
Please note that some extra error handling is needed for real life applications.
If you are interested in the complete PLCnext Engineer project, just let me know. (slemmens@phoenixcontact.be)
First, we are going to create one custom datatype, for reading and writing data. (arr_Byte_1_500 : Array[1..500] Of Byte)
Then, we need the implementation of our methods. In fact they only transfer some data towards the function block. We don’t use a return type because the complete process takes more than one program cycle.
// *** Method code: ***
/* Create a file */
sRequestedFileName:= sFileName;
IF iFileManager = 0 THEN
iFileManager:= 20;
END_IF;
/* Create a file and directly write a header line */
sRequestedFileName:= sFileName;
sRequestedText:= sHeader;
IF iFileManager = 0 THEN
iFileManager:= 10;
END_IF;
/* Delete a file */
sRequestedFileName:= sFileName;
IF iFileManager = 0 THEN
iFileManager:= 30;
END_IF;
/* Read a line */
sRequestedFileName:= sFileName;
IF xFirstLine THEN
diMemoryCursor:= DINT#0;
END_IF;
IF iFileManager = 0 THEN
iFileManager:= 40;
END_IF;
/* Write a line */
sRequestedFileName:= sFileName;
sRequestedText:= sText;
IF iFileManager = 0 THEN
iFileManager:= 10;
END_IF;
The following function block implements the real program behavior.
// *** Function block code: ***
xIdle:= iFileManager = 0;
CASE iFileManager OF
10: // Determine the length of the string and convert it to a byte array
diLengthTempText:= TO_DINT(LEN(sRequestedText));
sTempText:= sRequestedText;
xConvert:= TRUE;
iFileManager:= 11;
11: IF xDoneConvert THEN
xConvert:= FALSE;
iTempPointer:= TO_INT(diLengthTempText) + 1;
arrBuffer_FW[iTempPointer]:= BYTE#16#0D; /* Carriage return */
iTempPointer:= iTempPointer + 1;
arrBuffer_FW[iTempPointer]:= BYTE#16#0A; /* Line feed */
udiLength_FW:= TO_UDINT(iTempPointer);
iFileManager:= 150; // Open file
iReturnStep:= 12;
END_IF;
12: // Move the current file pointer to a new position, in our case the end of the file
xExecute_FS:= TRUE;
uiHandle_FS:= uiHandleMemory;
diPosition_FS:= DINT#0;
uiMode_FS:= UINT#2;
iFileManager:= 13;
13: IF xDone_FS THEN
xExecute_FS:= FALSE;
iFileManager:= 14;
END_IF;
14: // Write data in the file
xExecute_FW:= TRUE;
uiHandle_FW:= uiHandleMemory;
iFileManager:= 15;
15: IF xDone_FW THEN
xExecute_FW:= FALSE;
iFileManager:= 100; // Close file
END_IF;
20: iFileManager:= 150; // Open file
iReturnStep:= 100; // Close file
30: // Delete a file
sName_FRe:= sRequestedFileName;
xExecute_FRe:= TRUE;
iFileManager:= 31;
31: IF xDone_Fre THEN
xExecute_FRe:= FALSE;
iFileManager:= 0;
END_IF;
40: iFileManager:= 150; // Open file
iReturnStep:= 42;
42: // Move the current file pointer to a new position
xExecute_FS:= TRUE;
uiHandle_FS:= uiHandleMemory;
diPosition_FS:= diMemoryCursor;
uiMode_FS:= UINT#0;
iFileManager:= 43;
43: IF xDone_FS THEN
xExecute_FS:= FALSE;
iFileManager:= 44;
END_IF;
44: // Read data
xExecute_FR:= TRUE;
uiHandle_FR:= uiHandleMemory;
udiMaxLength_FR:= UDINT#100; // We expect a line with a maximum length of 80 char
iFileManager:= 45;
45: IF xDone_FR OR (xError_FR & uiErrorID_FR = UINT#10) THEN
xExecute_FR:= FALSE;
iAmountOfData:= TO_INT(udiLengthRead_FR);
IF iAmountOfData > 0 THEN
FOR iLoop:= 1 TO iAmountOfData
DO
IF arrBuffer_FR[iLoop] = BYTE#16#0D THEN /* Carriage return */
iLengtLine:= iLoop - 1;
diLengtLine:= TO_DINT(iLengtLine);
diMemoryCursor:= diMemoryCursor + diLengtLine + DINT#2;
EXIT;
END_IF;
END_FOR;
iFileManager:= 46;
ELSE
diMemoryCursor:= DINT#0;
sData:= '';
iFileManager:= 100; // Close file
END_IF;
END_IF;
46: xConvertRead:= TRUE;
iFileManager:= 47;
47: IF xDoneConvertRead THEN
xConvertRead:= FALSE;
iFileManager:= 100; // Close file
END_IF;
// Close file
100: xExecute_FC:= TRUE;
uiHandle_FC:= uiHandleMemory;
iFileManager:= 101;
101: IF xDone_FC THEN
xExecute_FC:= FALSE;
iFileManager:= 0;
END_IF;
// Open file
150: sName_FO:= sRequestedFileName;
xExecute_FO:= TRUE;
iFileManager:= 151;
151: IF xDone_FO THEN
uiHandleMemory:= uiHandle_FO;
xExecute_FO:= FALSE;
iFileManager:= iReturnStep;
END_IF;
END_CASE;
// Converts the string variable to a byte array
ConvertString_To_Buf(Req := xConvert,
Buf_Format := FALSE,
Buf_Offs := DINT#0,
Buf_Cnt := diLengthTempText,
Done => xDoneConvert,
Error => xErrorConvert,
Status => iStatusConvert,
SRC := sTempText,
BUFFER := arrBuffer_FW);
// Converts a byte array to a string variable
ConvertBuf_To_String(REQ := xConvertRead,
BUF_FORMAT := FALSE,
BUF_OFFS := DINT#0,
BUF_CNT := diLengtLine,
DONE => xDoneConvertRead,
ERROR => xErrorConvertRead,
STATUS => iStatusConvertRead,
BUFFER := arrBuffer_FR,
DST := sData);
// Opens an existing file in the parameterization memory with a specific name or creates a new file.
FileOpenLogging(Execute := xExecute_FO,
Name := sName_FO,
Done => xDone_FO,
Handle => uiHandle_FO,
Error => xError_FO,
ErrorID => uiErrorID_FO);
// Moves the current file pointer to a new position.
FileSeekLogging(Execute := xExecute_FS,
Handle := uiHandle_FS,
Position := diPosition_FS,
Mode := uiMode_FS,
Done => xDone_FS,
Error => xError_FS,
ErrorID => uiErrorID_FS);
// Writes data to a file that was opened previously.
FileWriteLogging(Execute := xExecute_FW,
Handle := uiHandle_FW,
Done => xDone_FW,
LengthWritten => udiLengthWritten_FW,
Buffer := arrBuffer_FW,
Length := udiLength_FW,
Error => xError_FW,
ErrorID => uiErrorID_FW);
// Reads data from a file that has been opened using the FILE_OPEN function block.
FileReadLogging(Execute := xExecute_FR,
Handle := uiHandle_FR,
Done => xDone_FR,
LengthRead => udiLengthRead_FR,
Buffer := arrBuffer_FR,
MaxLength := udiMaxLength_FR,
Error => xError_FR,
ErrorID => uiErrorID_FR);
// Closes a file in the parameterization memory that has been opened using the FILE_OPEN function block.
FileCloseLogging(Execute := xExecute_FC,
Handle := uiHandle_FC,
Done => xDone_FC,
Error => xError_FC,
ErrorID => uiErrorID_FC);
// Deletes a file with a specific name.
FileRemoveLogging(Execute := xExecute_FRe,
Name := sName_FRe,
Done => xDone_FRe,
Error => xError_FRe,
ErrorID => uiErrorID_FRe);
The following program gives you an overview how you can access our ‘file manager’. Please note that we don’t have a buffer implemented. This means that you cannot give multiple commands at once.
// *** Program code: ***
FileManager(xIdle => xFileManagerReady,
sData => sResult);
IF xCreateFileWithHeader & xFileManagerReady THEN
xCreateFileWithHeader:= FALSE;
FileManager.CreateFileWithHeader('ThisIsMyFirstFile.txt','Timestamp;Value_1;Value_2');
END_IF;
IF xCreateFile & xFileManagerReady THEN
xCreateFile:= FALSE;
FileManager.CreateFile('ThisIsMySecondFile.txt');
END_IF;
IF xDeleteFile & xFileManagerReady THEN
xDeleteFile:= FALSE;
FileManager.DeleteFile('ThisIsMySecondFile.txt');
END_IF;
IF xWriteLine & xFileManagerReady THEN
xWriteLine:= FALSE;
FileManager.WriteLine('ThisIsMyFirstFile.txt','19/12/2019 09:34:12;78.3;1285');
END_IF;
CASE iWriteMultipleLine OF
0: IF xWriteMultiLine THEN
xWriteMultiLine:= FALSE;
iWriteMultipleLine:= 1;
END_IF;
1: IF xFileManagerReady THEN
FileManager.WriteLine('ThisIsMyFirstFile.txt','19/12/2019 10:34:12;78.3;1285');
iWriteMultipleLine:= 2;
END_IF;
2: IF xFileManagerReady THEN
FileManager.WriteLine('ThisIsMyFirstFile.txt','19/12/2019 11:45:12;7.3;185');
iWriteMultipleLine:= 3;
END_IF;
3: IF xFileManagerReady THEN
FileManager.WriteLine('ThisIsMyFirstFile.txt','19/12/2019 12:04:08;35.8;17777');
iWriteMultipleLine:= 0;
END_IF;
END_CASE;
IF xReadFirstLine & xFileManagerReady THEN // Output is written to variable 'sResult'
xReadFirstLine:= FALSE;
// Read the first line from this file, the cursor position is set to zero
FileManager.ReadLine('ThisIsMyFirstFile.txt',TRUE);
END_IF;
IF xReadNextLine & xFileManagerReady THEN // Output is written to variable 'sResult'
xReadNextLine:= FALSE;
// Read the next line from this file, the cursor position is shifted by the program
// When the end of the file is reached, you will receive an empty string
// The next attempt, you will receive the first line again
FileManager.ReadLine('ThisIsMyFirstFile.txt',FALSE);
END_IF;
Leave a Reply
You must be logged in to post a comment.