Shop OBEX P1 Docs P2 Docs Learn Events
Anyone have a simple method to write a string to EEPROM location using I2C object? — Parallax Forums

Anyone have a simple method to write a string to EEPROM location using I2C object?

Need a way to store 16 characters.

Comments

  • Don MDon M Posts: 1,652
    I'm going to try this taken from Full Duplex Serial:
    PUB str(stringptr)
    
    '' Send string                    
    
      repeat strsize(stringptr)
        putbyte(byte[stringptr++])
    
  • Don MDon M Posts: 1,652
    Maybe this makes more sense...
    PUB str(id, addr, stringptr)
    
    '' Send string                    
    
      repeat strsize(stringptr)
        putbyte(id, addr, byte[stringptr++])
    
        
    
  • AribaAriba Posts: 2,690
    And this makes even more sense...
    PUB str(id, addr, stringptr)
    
      repeat strsize(stringptr)
        putbyte(id, addr++, byte[stringptr++])
    
      putbyte(id, addr, 0)  'write ending zero
    

    Andy
  • ElectrodudeElectrodude Posts: 1,657
    edited 2016-05-26 17:25
    If you're using "i2c driver.spin", you can just do:
    PUB wrstr(id, addr, stringptr)
    
      i2c.write_page(id, addr, stringptr, strsize(stringptr) + 1) ' +1 to also save the null terminator
    

    To read it back, you can do:
    PUB rdstr(id, addr, stringptr, maxlen) | currptr, c
    '' read up to maxlen characters from device id starting at addr into stringptr
    '' always adds null terminator, even if string is longer than maxlen
    '' returns string length
    
      currptr := stringptr      ' set current pointer to start of string
    
      maxlen += stringptr -1    ' now maxlen is a pointer to the last usable byte in the destination array
    
      c := i2c.read(id, addr)   ' read first byte
    
      byte[currptr++] := c      ' and save it
    
      repeat while c and currptr =< maxlen
        c := i2c.read_next(id)  ' read next byte
        byte[currptr++] := c    ' and save it
    
      ifnot c           ' if the loop quit before the null terminator because the string was too long
        byte[maxlen]~   ' then set null terminator
        return -1       ' return -1 to signal that the string is too long
    
      return currptr - stringptr - 1  ' return length of string (-1 to not count null terminator)
    

    This code is untested, and might have some off-by-one errors.

    Note all of the extra logic in rdstr to not read more bytes than available. If the extra checking wasn't there, rdstr could overwrite all of your RAM if the string was bad and was too long or was missing its null terminator. The random resets that this would likely cause aren't fun. If the string is too long, it will read as much as fits but the last byte will still be a null, and it will return -1 to indicate that it didn't fit instead of returning the length of the string it read.


    You might also try storing the length of the string as a byte in front of the string, instead of implicitly as a 0 byte at the end. The maximum length checking for that wouldn't be nearly as complicated.




    EDIT:

    Wait, you only need 16 characters? Then just do this to write:
    i2c.write_page(id, addr, stringptr, 16)
    
    and this to read:
    i2c.read_page(id, addr, stringptr, 16)
    

    And make sure you make your array 17 bytes so you can store the null terminator at the end if the string takes up all 16 bytes, and make sure you actually put a null terminator there. Also, you can put the null terminator there once at compile time in a DAT block and never overwrite it, and it will always be there.
  • My EEPROM object has methods for writing and reading strings from an EEPROM.
  • I use the Propeller EEPROM.spin code as explained in this thread. The object is still missing from the OBEX, etc, but the full zip file of code is in the first post.

    I am using the code in my GPS Scavenger Hunt Box, but I have not completed the project yet. However, if you need to see another example of the Propeller EEPROM object, I will post the code that does have a working EEPROM stored variable section. Made it very easy for me to have my project remember where it last left off each time it boots.
  • Note all of the extra logic in rdstr to not read more bytes than available. If the extra checking wasn't there, rdstr could overwrite all of your RAM if the string was bad and was too long or was missing its null terminator. The random resets that this would likely cause aren't fun. If the string is too long, it will read as much as fits but the last byte will still be a null, and it will return -1 to indicate that it didn't fit instead of returning the length of the string it read.
    Good point. 'Til now I've been using:
    PUB writeString(deviceID,registerAddress,strPtr)
      return writeBytes(deviceID,registerAddress,strPtr,strsize(strPtr) + 1)
    ' identical to Electrodude's solution
    
    PUB readString(deviceID,registerAddress,dataAddress)
      byte[dataAddress++] := readByte(deviceID,registerAddress)
      repeat until (byte[dataAddress++] := readNext(deviceID)) == 0
    ' absolutely requires a null-terminator
    
  • ElectrodudeElectrodude Posts: 1,657
    edited 2016-05-27 14:26
    In C, there's this wonderful little function called gets(). It reads a line of input and puts it in a buffer at a pointer you supply to it. The only problem, though, is that there's no way to tell it how long your buffer is. An attacker (or buggy script) can take advantage of this by sending special data that overruns the buffer and writes certains things to the memory after the buffer to take over the program.

    One way the Morris Internet Worm of 1988 spread was by abusing the Unix finger daemon, which used gets() to read data coming in over a network socket.

    Fortunately, gets has been marked as a security problem in the manual page ever since the Worm, and it was removed from the C standard in C11.
Sign In or Register to comment.