Page 1 of 1

Trouble understanding the use of OpenFileAppend in NXC

Posted: 03 Apr 2011, 15:57
by tedsluis
Hi,

I do not understand how OpenFileAppend() in NXC should work.
My goal is to open file and write data to it. If a file with the specified name allready exist, I want to append to that file. Otherwise I want to create a new file.
Here is how I think to accomplish that:

Code: Select all

string FILE_NAME="test.csv";
byte file_handle;
unsigned int loader_result_code;
const int file_size=1024;

loader_result_code=CreateFile(FILE_NAME,file_size,file_handle);
if (loader_result_code  == LDR_FILEEXISTS)
    loader_result_code=OpenFileAppend(FILE_NAME,file_size,file_handle);
if (loader_result_code == LDR_SUCCESS)
    loader_result_code=Write(file_handle,"succesfull"); 
Unfortunate I get a wrong response from the OpenFileAppend(FILE_NAME,file_size,file_handle) back (I think): 8E00, FILEISFULL

What am I doing wrong?

I use Bricxcc 3.3.8.9 and NXT enhanced firmware 1.31 (2011-03-15)

I have created an other piece of code (down here) that illustrates the operation:

Code: Select all

string FILE_NAME="test.csv";
byte file_handle;
unsigned int loader_result_code;
const int file_size=1024;

task main()
{
     loader_result_code=CreateFile(FILE_NAME,file_size,file_handle);

     switch (loader_result_code)
        {
         case LDR_SUCCESS:
              TextOut(0,LCD_LINE1,"created succesfull!");
              loader_result_code=Write(file_handle,"succesfull");
              break;
         case LDR_FILEISFULL:
              TextOut(0,LCD_LINE1,"file is full!");
              break;
         case LDR_FILEEXISTS:
              TextOut(0,LCD_LINE1,"file exist.");
              break;
         case LDR_INPROGRESS:
              TextOut(0,LCD_LINE1,"not yet completed.");
              break;
         case LDR_FILEISBUSY:
              TextOut(0,LCD_LINE1,"file already used.");
              break;
         default:
              TextOut(0,LCD_LINE1,"create failed!");
              break;
         }

     TextOut(0,LCD_LINE2,"filesize="+NumToStr(file_size));
     TextOut(0,LCD_LINE3,"result code="+FormatNum("%04x", loader_result_code));
     TextOut(0,LCD_LINE4,"file_handle="+NumToStr(file_handle));
     
     loader_result_code=OpenFileAppend(FILE_NAME,file_size,file_handle);
     
     switch (loader_result_code)
        {
         case LDR_SUCCESS:
              TextOut(0,LCD_LINE5,"append succesfull!");
              loader_result_code=Write(file_handle,"succesfull");
              break;
         case LDR_FILEISFULL:
              TextOut(0,LCD_LINE5,"file is full!");
              break;
         case LDR_INPROGRESS:
              TextOut(0,LCD_LINE5,"not yet completed.");
              break;
         case LDR_FILEISBUSY:
              TextOut(0,LCD_LINE5,"file already used.");
              break;
         default:
              TextOut(0,LCD_LINE5,"append failed!");
              break;
         }

     TextOut(0,LCD_LINE6,"filesize="+NumToStr(file_size));
     TextOut(0,LCD_LINE7,"result code="+FormatNum("%04x", loader_result_code));
     TextOut(0,LCD_LINE8,"file_handle="+NumToStr(file_handle));

     Wait(80000);
CloseFile(FILE_NAME);
}
After the first run a new file called test.csv is created. This is the output on the NXT screen:

Code: Select all

created succesfu
filesize=1024
result code=0000
filehandle=1
file allready use
filesize=1024
result code=8b00
filehandle=2
When I look with the Bricxcc File Explore I can see that after the first run that the file was create succesfully and that the string "succesfull" was written to the file.
The loader module error that were returned when the file was created (0000, LDR_SUCCESS) and when OpenFileAppend() was executed (8b00, LDR_FILEISBUSY) are as expected.

The next time I run the code this is the output on the NXT screen:

Code: Select all

file exist.
filesize=1024
result code=8f00
filehandle=1
file=full!
filesize=1024
result code=8e00
filehandle=1
After the second run there isn't any data added to the file.
Attempting to create the file will of course returns error 8f00, LDR_FILEEXISTS. When attempting to execute OpenFileAppend() the loader module returns error 8e00, LDR_FILEISFULL. That is not what I would expected. I would expected that it returns 0000, LDR_SUCCESS.

The link http://bricxcc.sourceforge.net/nbc/nxcd ... rrors.html gives an explanation of the loader module error codes, but they are not always clear to me.

I hope someone can help me out.

Best regards,

Ted Sluis

Re: Trouble understanding the use of OpenFileAppend in NXC

Posted: 04 Apr 2011, 02:12
by afanofosc
With the NXT firmware you can only append to a file that is not already full. If you create the file as 8kb and only write 1kb to the file before closing it then you could reopen it with OpenFileAppend and write another 7kb to it before it was full. If the file is already full when you open it then you will get the error status code you are seeing. If you get this error then you could use ResizeFile to make it targer.

If you are getting the file is full status when the file should definitely not be full then it may be that I have broken something in the enhanced NBC/NXC firmware that you have installed on your brick. I have been making some changes in the loader module to support seeking and telling the current file position. If you think it might be a problem with the enhanced firmware then try your program with the standard firmware and see if it behaves the same.

John Hansen

Re: Trouble understanding the use of OpenFileAppend in NXC

Posted: 04 Apr 2011, 02:23
by afanofosc
Doh!

I forgot that in the latest standard and enhanced firmware versions any files that you had opened are cropped when the program ends.

Code: Select all

  //Close any files we had opened programatically
  for (i = 0; i < MAX_HANDLES; i++)
  {
    //Copy i to tmp, because we pass a pointer to it to pFunc
    tmp = i;
    //Close file
    if (*(VarsCmd.FileHandleTable[i]) != 0)
      pMapLoader->pFunc(CROPDATAFILE, &tmp, NULL, NULL);
  }
I had once upon a time kept the enhanced firmware doing things the "old" way which was to just close the files without cropping them but for the sake of compatibility I eventually changed the enhanced firmware to also use CROPDATAFILE instead of CLOSE. The 1.0x firmwares just used CLOSE.

What this means is existing files cannot just be opened using OpenFileAppend since they have been cropped. Instead, existing files will need to be resized at program startup before you can then use OpenFileAppend to open the newly resized file and write data to it.

John Hansen

Solved: Trouble understanding the use of OpenFileAppend in N

Posted: 04 Apr 2011, 18:25
by tedsluis
Dear John,

Problem solved!
John Hansen Wrote:
If you think it might be a problem with the enhanced firmware then try your program with the standard firmware and see if it behaves the same.
John Hansen Wrote:
I had once upon a time kept the enhanced firmware doing things the "old" way which was to just close the files without cropping them but for the sake of compatibility I eventually changed the enhanced firmware to also use CROPDATAFILE instead of CLOSE. The 1.0x firmwares just used CLOSE.

What this means is existing files cannot just be opened using OpenFileAppend since they have been cropped. Instead, existing files will need to be resized at program startup before you can then use OpenFileAppend to open the newly resized file and write data to it.
So the crop function removes the empty space from files when a program ends. That's handy! It is new in the 2.x firmware? I didn't know that. I couldn't find anything about it in the documentation on http://bricxcc.sourceforge.net/nbc/nxcdoc/nxcapi or in your book, but maybe I didn't looked good enough.

I tried the program with the 1.05 standard firmware and the OpenFileappend() worked OKAY, just as you said it would!

You showed a piece of code in your post that is apparently responsible for cropping all files:
Written by John Hansen:
I forgot that in the latest standard and enhanced firmware versions any files that you had opened are cropped when the program ends.

Code: Select all

//Close any files we had opened programatically
  for (i = 0; i < MAX_HANDLES; i++)
  {
    //Copy i to tmp, because we pass a pointer to it to pFunc
    tmp = i;
    //Close file
    if (*(VarsCmd.FileHandleTable[i]) != 0)
      pMapLoader->pFunc(CROPDATAFILE, &tmp, NULL, NULL);
  }
The only thing I found out about this code is that LDR_CMD_CROPDATAFILE is a loader module function constants that is used for crop a data file to its used space.
Is this piece of code compiled along with my program? How does that works?

Anyway, when I resize the file before I use the OpenFileAppend() it works OKAY with the 1.2x firmware:

Code: Select all

string FILE_NAME="test.csv";
byte file_handle;
unsigned int loader_result_code;
const int file_size=1024;

loader_result_code=CreateFile(FILE_NAME,file_size,file_handle);
if (loader_result_code  == LDR_FILEEXISTS)
    {
    loader_result_code=ResizeFile(FILE_NAME,file_size);
    loader_result_code=OpenFileAppend(FILE_NAME,file_size,file_handle);
    }
if (loader_result_code == LDR_SUCCESS)
    loader_result_code=Write(file_handle,"succesfull"); 
Thanks for helping to solve the problem John!

Ted Sluis