CODESYS - the IEC 61131-3 automation software

Welcome to the official CODESYS Forum by 3S-Smart Software Solutions GmbH | A member of the CODESYS Group
Deutsche Version English version russian version 
It is currently Thu Sep 19, 2019 8:36 pm

All times are UTC+01:00




Post new topic  Reply to topic  [ 9 posts ] 
Author Message
PostPosted: Wed Apr 04, 2018 10:40 am 
Offline

Joined: Mon Jan 22, 2018 10:07 am
Posts: 47
Hi,
I'm trying to read strings from file.
The file is organized in this way:
Code:
[CONFIG FILE]
Value A=xxxxx
Value B=xxxxx
Value C=xxxxx
Value D=xxxxx
Value E=xxxxx
Value F=xxxxx
and so on...

The total length of the file is about 600 bytes.
The file is written by part of the same application in CODESYS. The writing process goes right.
The issue happens when the reading routine starts.
The code I used is the following:
Code:
PROGRAM ConfigFileLoad
VAR
   sFileName       : CAA.FILENAME;
   FileOpen       : File.Open;
   FileClose      : File.Close;
   FileRead      : File.Read;
   iState         : UINT;   
   hfile         : CAA.HANDLE;
   sReadLine      : STRING(1000);   
END_VAR
VAR_INPUT
   xInit         : BOOL;
END_VAR
VAR_OUTPUT
   xError         : BOOL;
   xDone         : BOOL;   
END_VAR

   CASE iState OF
     0:
      sFileName := '/configfile.cfg';
      xDone := FALSE;
      xError := FALSE;
      iState:= 3;
   
   3: // Open the file with read access.
      FileOpen(xExecute:= TRUE, sFileName:= sFileName, xExclusive:= FALSE, eFileMode:= File.MODE.MREAD);
      IF FileOpen.xDone = TRUE THEN
         hfile := FileOpen.hFile;
         FileOpen(xExecute:= FALSE);
         iState := 4;
      ELSIF FileOpen.xError = TRUE THEN
         iState:= 32767;
         FileOpen(xExecute:= FALSE);
      END_IF

   
   4: // Read the string from the file.
      FileRead(xExecute:= TRUE, hFile:= hfile, pBuffer:= ADR(sReadLine), szBuffer:= SIZEOF(sReadLine));
      IF FileRead.xDone = TRUE THEN
         iState := 5;
         // Cut off the unused characters.
         //sReadLine := MID(sReadLine, ANY_TO_INT(FileRead.szSize), 1);
         FileRead(xExecute:= FALSE);
      ELSIF FileRead.xError = TRUE THEN
         iState:= 32767;
         FileRead(xExecute:= FALSE);
      END_IF
      
   5: // Close that file.
      FileClose(xExecute:= TRUE, hFile:= hfile);
      IF FileClose.xDone = TRUE THEN
         iState:= 6;
         FileClose(xExecute:= FALSE);
      ELSIF FileClose.xError = TRUE THEN
         iState:= 32767;
         FileClose(xExecute:= FALSE);
      END_IF
   
   6: // extract values
   
   [......]

At the step 4:
Code:
   4: // Read the string from the file.
      FileRead(xExecute:= TRUE, hFile:= hfile, pBuffer:= ADR(sReadLine), szBuffer:= SIZEOF(sReadLine));

the function FileRead seems to return into sReadLine a string 266 bytes long and no other. All the remaining bytes are lost. The string sReadline is defined like
Code:
sReadLine      : STRING(1000);   

I expect to read a total bytes of 1000.
Could someone help me to solve the reading issue?
Many thanks.


Top
   
PostPosted: Wed Apr 04, 2018 6:03 pm 
Offline
Frequent User
Frequent User

Joined: Tue Dec 03, 2013 11:52 pm
Posts: 120
Nothing sticks out based off the information you have here. I see you have MID commented out which is only a string of 255 and you should look at using StrMidA in the StringUtils library.

What does the buffer equal after read is complete? Have you tried increasing sReadLine to STRING(2000) and see if you get more back?


Top
   
PostPosted: Wed Apr 04, 2018 8:04 pm 
Offline

Joined: Mon Jan 22, 2018 10:07 am
Posts: 47
The issue is around FileRead function: the function does not return a string longer than 255 bytes.

Actually, I'm trying to solve the problem using file position pointer reading byte per byte and generating substring less than 255 bytes long. I will post code as soon as I tested it... could be useful for others ;-)


Top
   
PostPosted: Wed Apr 04, 2018 8:26 pm 
Offline
Frequent User
Frequent User

Joined: Tue Dec 03, 2013 11:52 pm
Posts: 120
I think you are going the wrong direction.

The File.Read doesn't have a limit besides the size of the buffer. I have multiple applications that read well over 255 (closer to 1600) and you said even yours returns over 255 (266 to be exact) so not sure why you have come up with that assumption.

Any of the string functions built into the STANDARD library (LEN, MID, FIND, REPLACE, LEFT, RIGHT, ....) have a limit of 255 and that is one reason you should use the STRING UTIL library. Also from what has been said on the forums the STRING UTIL library is much quicker.

Hope you find an answer either way but reading byte for byte sounds slow.


Top
   
PostPosted: Wed Apr 04, 2018 10:09 pm 
Offline

Joined: Mon Jan 22, 2018 10:07 am
Posts: 47
At this point, I think you are right.
Could you post some piece of code to better understand what you are saying me?


Top
   
PostPosted: Wed Apr 04, 2018 11:00 pm 
Offline
Frequent User
Frequent User

Joined: Tue Dec 03, 2013 11:52 pm
Posts: 120
Mine looks very similar to yours. I would still be interested in seeing the output of sReadLine to see if it is reading the whole file at state 5 before you hit state 6. The difference of mine is I am looking for Unicode characters (16bit) instead of ANSI characters(8bit) since the files i'm reading can be in many different languages.

To extract data from the buffer you would use something like (Not Tested but hopefully gives you the idea):
Code:
VAR
    sValueDelimiter: STRING := '=';
    sNewLineDelimiter: STRING := '$r$n';
    nBufferLength: DINT;
    nValueLocation: INT;
    nNewLineStart: INT;
    ExtractedValue: STRING;
END_VAR

//Find the length of buffer (Replaces LEN)
    nBufferLength:= StrLenA(pstData:= ADR(sReadLine));

//Locate the equals sign to separate the data from the label (Replaces FIND)
    nValueLocation:= StrFindA(pst1:= ADR(sReadLine), pst2:= (sValueDelimiter), uiSearchStart:= 1);
   
//Locate end of line to know how long the data field is (Replaces FIND) (If you have [CONFIG FILE] written in the file you will need to cycle past this first before going to StrMidA)
    nNewLineStart:= StrFindA(pst1:= ADR(sReadLine), pst2:= (sNewLineDelimiter), uiSearchStart:= 1);
   
//Extract the data from the buffer and place it in variable ExtractedValue (Replaces MID/LEFT/RIGHT)
    StrMidA(pwst:= ADR(sReadLine), uiInputBufferSize:= (SIZEOF(sReadLine), iLength:= (nNewLineStart - nValueLocation), iPosition:= nValueLocation, pwstResult:=
    ADR(ExtractedValue), uiResultBufferSize:= SIZEOF(ExtractedValue)));
   
//Delete extracted data from the buffer (Replaces Delete) (Not needed but I do this to create a loop out of the first parts)
    StrDeleteA(pwd:= ADR(sReadLine), iLength:= nNewLineStart + 1, iPosition:= 1);


Top
   
PostPosted: Thu Apr 05, 2018 1:17 pm 
Offline

Joined: Mon Jan 22, 2018 10:07 am
Posts: 47
I like your solution! It's quite similar to mine previous. Where can I found the library you used for this application? I don't found into the library repository.
Thanks


Top
   
PostPosted: Thu Apr 05, 2018 4:59 pm 
Offline
Frequent User
Frequent User

Joined: Tue Dec 03, 2013 11:52 pm
Posts: 120
I find mine in "Library Manager->Add Library->Advanced->Intern->Utils" and choose StringUtils. Or once you are on the advanced screen just search for StringUtils.


Top
   
PostPosted: Thu Apr 05, 2018 9:56 pm 
Offline

Joined: Mon Jan 22, 2018 10:07 am
Posts: 47
IT PERFECTLY WORKS!
Thank you!


Top
   
Display posts from previous:  Sort by  
Post new topic  Reply to topic  [ 9 posts ] 

All times are UTC+01:00


Who is online

Users browsing this forum: No registered users and 8 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Limited