Shop OBEX P1 Docs P2 Docs Learn Events
fsrw pread strange behavior — Parallax Forums

fsrw pread strange behavior

gianallengianallen Posts: 16
edited 2012-07-20 11:42 in Propeller 1
Hi there,

I am trying to read bytes from an SD card into a data block. It seems as though a fsrw.pread command is not correctly reading bytes and placing them into the desired array, whereas a fsrw.pgetc will read them correctly directly from the SD file. Just one more bit of background: the DAT block array I want to fill with the bytes from the SD card ("v4data.spin") is in a separate object than the code calling the fsrw.pread method ("MT_config.spin"). Here is a code example:
' "v4data.spin" (Object with DAT block where I want to store data from SDcard):

PUB GetMTConfigFileStart
  return @MTConfigFileStart



DAT                                                      
  MTConfigFileStart                   'store config data starting here


  apnServTitle          byte "ApnServ",0
  colon1                byte ":"
  apnservVal            byte 34,"WWW.XXXXX.COM",34,0[10] 
  cr1                   byte 13

  MTConfigFileEnd       byte $3    'end of config data block


A user can change the values of the apnservVal to preset values via a pwrite command (not shown) in MT_Config.spin. Judging from the outcome of the pgetc command illustrated below, it appears the pwrite method is working correctly.
'"MT_config.spin" (Object I am calling to read data from SD card.  The UARTS object has previously been initialized and started a port 0 to talk on pins p30 & p31 to the terminal):

CON
 DEBUG = 0

OBJ
  SD : "fsrw"
  UARTS : "FullDuplexSerial4portPlus_0v3"
  v4data : "v4data"

PUB Main: sd_err       'called from the main program startup object
  sd_err := \sd.mount(sd_do)
  ReadConfigFile

PUB ReadConfigFile : sd_err | startPtr,fileSize,char,idx,numBytes
  uarts.str(debug,string("read config",13))
  sd_err := \SD.popen(string("MT_config.txt"), "r")
  if sd_err == -1
    uarts.str(debug,string("no MTconfig file",13))
    WriteConfigFile     '<---- go create a MT_config file if none exists
    return
  elseif sd_err < -1
    uarts.str(debug,string("read error",13))
    return
  fileSize := sd.get_filesize


  if fileSize > 500   'limit max size to prevent overrun
    filesize := 500

'try using pgetc to retrieve and print data from MT_config file


  repeat filesize    
    char := sd.pgetc
    PrintChar(char)
  newline

'now close the file and reopen so we can try reading out of the file directly into the v4data DAT block using fsrw's pread method
  sd.pclose   
  uarts.str(debug,string("read config",13))
  sd_err := \SD.popen(string("MT_config.txt"), "r")


  startPtr := v4data.GetMTConfigFileStart     'set buffer pointer to the location where we want data to be placed from the fsrw pread method
  numBytes := doSDread(startPtr,fileSize)    'read fileSize number of bytes out of MT_config SD card file into bytes starting at location set by startPtr


  uarts.str(debug,string(13,"numBytes "))  'print number of bytes read by doSDread method
  PrintDec(numBytes)
  newline


  sd.pclose
  repeat idx from 0 to fileSize   'Print all non-zero characters just transferred from SDcard to Prop memory
    char := byte[startPtr+idx]
    if char <> 0
      uarts.tx(debug,char)


PRI DoSDread(bufpnt,Nchars) : numBytes | sd_err  'reads N characters into the bufPoint buffer.
  ifnot SD_err                                                                 
    numBytes := SD.pread(bufpnt, Nchars)

'Debugging routines

PRI PrintChar(char)
  uarts.tx(debug,char)


Pri NewLine
  uarts.tx(debug, 13)


Pri PrintSpace
  uarts.tx(debug,32)


PRI PrintDec(val)
  uarts.dec(debug,val)


PRI PrintStr(strPtr)
  uarts.str(debug,strPtr)


PRI delay(ms)
  waitcnt(clkfreq/1000*ms+cnt)


So, the bottom line is this: the pgetc code returns the expected, user-changed values from the MT_config file, even after resetting the Propeller. However, after resetting the propeller, the pread returns the pre-defined values set at compile time from the Propeller memory that should be updated with the new values.

Here is what is displayed in a terminal (via the uarts debug calls above):
-- output directly from pgetc method debug --
read config
ApnServ?:"WWW.CDEFG.COM"?????????? <---- New, user-changed value apparently correctly written and read out from the SD card file


read config

-- output from memory after pread debug --
numBytes 0 <--- note 0 bytes read
ApnServ:"WWW.XXXXX.COM" <---- Note that data block starting at v4data MTConfigFileStart has not been updated


Any insights are appreciated. Thank you.

Comments

  • MagIO2MagIO2 Posts: 2,243
    edited 2012-07-20 04:37
    What you can learn from this lesson is how stack and function-calls work ;o)
    PRI DoSDread(bufpnt,Nchars) : numBytes | sd_err  'reads N characters into the bufPoint buffer.
      ifnot SD_err                                                                 
        numBytes := SD.pread(bufpnt, Nchars)
    

    Here you define SD_err as a local variable. Local variables are never initialized and ... they are local! So, it is actually another variable than the sd_err defined elsewhere in your code.

    So, how does function-call works?
    There is some place reserved on stack to store the return-address, the return-value and all the local variables. Reserve means that the stack pointer is moved behind the end of the needed memory.
    There is no initialization which would set the values of local variables to 0! These local variables will have a value that is from the functions point of view unpredictable, as it depends on the code that ran before.

    Anyway ... in your case I guess it is simply not zero and your ifnot will simply return false which skips the SD.pread!

    This needs to be fixed.
  • gianallengianallen Posts: 16
    edited 2012-07-20 11:42
    Thank you MaglO2! I fixed it and it works now. That had been driving me crazy for a while now. The problem was I copied methods from another object I have, but in the other object sd_err is a global var. When I copied the methods over, I just created a local var for sd_err per method versus creating a global variable in my new object (MTconfig.spin).

    I fixed the code by moving the ifnot sd_err call up into the calling method:

    PUB ReadConfigFile : sd_err | startPtr,fileSize,char,idx,numBytes[LEFT][COLOR=#333333][FONT=Parallax]
    [/FONT][/COLOR][/LEFT]
    
    .
    .
    .
      ifnot sd_err
        numBytes := doSDread(startptr,fileSize)
    .
    .
    .
    
    
    [LEFT][COLOR=#333333][FONT=Parallax]
    [/FONT][/COLOR][/LEFT]
    
    PRI doSDread(bufpnt,Nchars) : numBytes  'writes N characters to the SD buffer.                                                               
      numBytes := SD.pread(bufpnt, Nchars)
    

    I use the sd_err variable a lot in the object, so I could also reasonably make it a global variable, I suppose. But, as it stands, "sd_err" is taking the place of the standard "result" variable for the (in this case) PUB ReadConfigFile method, so I figure that takes less program space than assigning a new, dedicated variable.
Sign In or Register to comment.