RobTillaart / FRAM_I2C

Arduino library for I2C FRAM
MIT License
34 stars 7 forks source link

[Wish] - read back logging #30

Closed N0ury closed 1 year ago

N0ury commented 1 year ago

In FRAM_logging.ino: // todo - read back sketch.

Can you add such example sketch?

Nice lib! I have strange behaviors on my electronic assemblies. I want to use this library to determine the causes.

N0ury commented 1 year ago

In fact a uint32_t FRAM32::readLine(uint32_t memaddr, char* &line) method would be nice Lines ending with CRLF or LF

RobTillaart commented 1 year ago

Will give it some thoughts, might take some time (days?)

RobTillaart commented 1 year ago

Created a simple proof of concept - no FRAM nearby to test.

Can you give it a try? Fill the FRAM first with the logging sketch.

//
//    FILE: FRAM_logging_read.ino
//  AUTHOR: Rob Tillaart
// PURPOSE: demo readback logging in FRAM. (FRAM_logging.ino)
//     URL: https://github.com/RobTillaart/FRAM_I2C

// experimental code
//
// read back sketch for data produced by FRAM_logging.ino
//
// last written position uint32_t at addres 0..3
// log entry: plain text separated by newlines.
//            timestamp + \t + random number +\n
// wraps around if FRAM full => might give one corrupted line.
//

#include "FRAM.h"

FRAM fram;

uint32_t sizeInBytes = 0;

char buffer[32];

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("FRAM_LIB_VERSION: ");
  Serial.println(FRAM_LIB_VERSION);

  Wire.begin();

  int rv = fram.begin(0x50);
  if (rv != 0)
  {
    Serial.print("INIT ERROR: ");
    Serial.println(rv);
  }

  //  get size in bytes
  sizeInBytes = fram.getSize() * 1024;

  //  first entry is starts at [0..3]
  uint32_t address = fram.read32(0);
  if (address == 0x04)
  {
    Serial.println("FRAM empty");
    while(1);
  }
  int len = 0;
  while ((len = readLine(address, buffer, 32, '\n')) > 0 )
  {
    Serial.println(buffer);
    address += len;
    if (address > sizeInBytes) 
    {
      Serial.println("End of FRAM");
      while(1);
    }
  }
  Serial.println("done...");
}

void loop()
{
}

//  initial reference implementation. (slow).
//  returns length of line in buffer or 0 if it does not fit.
int readLine(uint32_t address, char * buf, int buflen, char separator)
{
  uint32_t addr = address;
  for (int length = 0; length < buflen; length++)
  {
    buf[length] = (char) fram.read8(addr++);
    if (buf[length] == separator)
    {
      buf[length] = 0;    //  replace \n => \0 EndChar
      return length;
    }
  }
  //  entry does not fit in given buffer.
  return 0;
}

//  -- END OF FILE --
RobTillaart commented 1 year ago

The above implementation reads char by char which is slow. One could read and fill the buffer to max (e.g. read 32 bytes in one call) and then search the buffer for the '\n'. Would probably be faster, but depends on length of the lines.

Above implementation only checks for one line separator '\n'

RobTillaart commented 1 year ago

Some math.

LEN BYTEMODE BLOCKMODE notes
1 4 4
2 8 5
3 12 6
4 16 7
5 20 8
6 24 9
7 28 10
8 32 11 break even
9 36 12
10 40 13
15 60 18
20 80 23
25 100 28
30 120 36 (two calls in block mode)

This table assumes optimized BLOCKMODE. It is clear that from string length 8 the BLOCKMODE (just read 32 bytes and search afterwards is faster.


Note: one could also think in terms of len = readField(address, buf, buflen, separator) If one knows how many fields there are (separator '\t' and finally a '\n'. Thinking in fields reduces the need for a large buffer that can hold a whole line. Code is roughly identical, might need multiple separators or multichar separators. Food for thought.

N0ury commented 1 year ago

I had to change somethings.

As I use non standard pins, I've added Wire.begin(PIN_SDA, PIN_SCL); and changed int rv = fram.begin(0x50); to int rv = fram.begin(PIN_SDA, PIN_SCL);

No result lines are displayed. FRAM empty is not displayed, so data are detected. In readLine I have added Serial.println("in readLine"); It appears only once I have nearly 10 lines). I'm not a C dev (that's why I've asked for this improvement), so I may have made a mistake. Furthermore, the message End of FRAM is never displayed, I only see done...

N0ury commented 1 year ago

The above implementation reads char by char which is slow. One could read and fill the buffer to max (e.g. read 32 bytes in one call) and then search the buffer for the '\n'. Would probably be faster, but depends on length of the lines.

Above implementation only checks for one line separator '\n'

Analysing a post-mortem log doesn't need to be done very fast. This point is not important in my opinion.

N0ury commented 1 year ago

Note: one could also think in terms of len = readField(address, buf, buflen, separator) If one knows how many fields there are (separator '\t' and finally a '\n'. Thinking in fields reduces the need for a large buffer that can hold a whole line. Code is roughly identical, might need multiple separators or multichar separators. Food for thought.

Why not? It's a good idea!

RobTillaart commented 1 year ago

Furthermore, the message End of FRAM is never displayed, I only see done...

End of RAM is only displayed when the whole FRAM was read and the address would be beyond the FRAM size.

RobTillaart commented 1 year ago

Found a free FRAM, did some test and rewrote the test (you may need to adjust) Main changes indicated.

//
//    FILE: FRAM_logging_read.ino
//  AUTHOR: Rob Tillaart
// PURPOSE: demo readback logging in FRAM. (FRAM_logging.ino)
//     URL: https://github.com/RobTillaart/FRAM_I2C

// experimental code
//
// read back sketch for data produced by FRAM_logging.ino
//
// last written position uint32_t at addres 0..3
// log entry: plain text separated by newlines.
//            timestamp + \t + random number +\n
// wraps around if FRAM full => might give one corrupted line.
//

#include "FRAM.h"

FRAM fram;

uint32_t sizeInBytes = 0;

char buffer[32];

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("FRAM_LIB_VERSION: ");
  Serial.println(FRAM_LIB_VERSION);

  Wire.begin();

  int rv = fram.begin(0x50);
  if (rv != 0)
  {
    Serial.print("INIT ERROR: ");
    Serial.println(rv);
  }

  //  get size in bytes
  sizeInBytes = fram.getSize() * 1024;

  //  first entry is starts at [0..3]
  uint32_t address = fram.read32(0);
  Serial.println(address, HEX);    //  <<<<<<<<<<<<<<<  show final address.
  if (address == 0x04)
  {
    Serial.println("FRAM empty");
    while(1);
  }
  int len = 0;
  address = 0x00000004;  // <<<<<<<<<<<<<<<   one must start at the start
  while ((len = readLine(address, buffer, 32, '\n')) > 0 )
  {
    Serial.print(len);   //   <<<<<<<<<<<<<<<  added length in print
    Serial.print("\t");
    Serial.println(buffer);
    address += len + 1;    // <<<<<<<<<<<<<<<<<<<<<<<<
    if (address > sizeInBytes) 
    {
      Serial.println("End of FRAM");
      while(1);
    }
  }
  Serial.println("done");
}

void loop()
{
}

//  initial reference implementation. (slow).
//  returns length of line in buffer or 0 if it does not fit.
int readLine(uint32_t address, char * buf, int buflen, char separator)
{
  uint32_t addr = address;
  for (int length = 0; length < buflen; length++)
  {
    buf[length] = (char) fram.read8(addr++);
    if (buf[length] == separator)
    {
      buf[length] = 0;    //  replace \n => \0 EndChar
      return length;
    }
  }
  //  entry does not fit in given buffer.
  return 0;
}

//  -- END OF FILE --
RobTillaart commented 1 year ago
//
//    FILE: FRAM_logging_read.ino
//  AUTHOR: Rob Tillaart
// PURPOSE: demo readback logging in FRAM. (FRAM_logging.ino)
//     URL: https://github.com/RobTillaart/FRAM_I2C

// experimental code
//
// read back sketch for data produced by FRAM_logging.ino
//
// last written position uint32_t at addres 0..3
// log entry: plain text separated by newlines.
//            timestamp + \t + random number +\n
// wraps around if FRAM full => might give one corrupted line.
//

#include "FRAM.h"

FRAM fram;

uint32_t sizeInBytes = 0;

char buffer[32];

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("FRAM_LIB_VERSION: ");
  Serial.println(FRAM_LIB_VERSION);

  Wire.begin();

  int rv = fram.begin(0x50);
  if (rv != 0)
  {
    Serial.print("INIT ERROR: ");
    Serial.println(rv);
  }

  //  get size in bytes
  sizeInBytes = fram.getSize() * 1024;

  //  first entry is starts at [0..3]
  uint32_t address = fram.read32(0);
  Serial.println(address, HEX);
  if (address == 0x04)
  {
    Serial.println("FRAM empty");
    while (1);
  }
  int len = 0;
  address = 0x00000004;
  while ((len = readLineByte(address, buffer, 32, '\n')) > 0 )
  {
    Serial.print(len);
    Serial.print("\t");
    Serial.println(buffer);
    address += len + 1;
    if (address > sizeInBytes)
    {
      Serial.println("End of FRAM");
      while (1);
    }
  }
  Serial.println("done");
  address = 0x00000004;
  while ((len = readLineBlock(address, buffer, 32, '\n')) > 0 )
  {
    Serial.print(len);
    Serial.print("\t");
    Serial.println(buffer);
    address += len + 1;
    if (address > sizeInBytes)
    {
      Serial.println("End of FRAM");
      while (1);
    }
  }
  Serial.println("done");

  delay(100);
  uint32_t start = micros();
  len = readLineByte(0x04, buffer, 32, '\n');
  uint32_t stop = micros();
  Serial.println(stop - start);

  delay(100);
  start = micros();
  len = readLineBlock(0x04, buffer, 32, '\n');
  stop = micros();
  Serial.println(stop - start);
}

void loop()
{
}

//  initial reference implementation. (slow).
//  returns length of line in buffer or 0 if it does not fit.
int readLineByte(uint32_t address, char * buf, int buflen, char separator)
{
  uint32_t addr = address;
  for (int length = 0; length < buflen; length++)
  {
    buf[length] = (char) fram.read8(addr++);
    if (buf[length] == separator)
    {
      buf[length] = 0;    //  replace \n => \0 EndChar
      return length;
    }
  }
  //  entry does not fit in given buffer.
  return 0;
}

//  initial reference implementation. (slow).
//  returns length of line in buffer or 0 if it does not fit.
int readLineBlock(uint32_t address, char * buf, int buflen, char separator)
{
  fram.read(address, (uint8_t *)buf, buflen);
  for (int length = 0; length < buflen; length++)
  {
    if (buf[length] == separator)
    {
      buf[length] = 0;    //  replace \n => \0 EndChar
      return length;
    }
  }
  //  entry does not fit in given buffer.
  return 0;
}

//  -- END OF FILE --

BYTEMODE 6764 BLOCKMODE 4112 (about 40% faster, so block-mode will be the implementation of choice.

Did also a small test with '\t' as separator. Works good with the same function wel, but the loop needs more administration.

Think the name should become *readUntil(uint32_t address, char buf, int buflen, char separator)** Then it is up to the user to decide if it is used as readLine() or readField()

RobTillaart commented 1 year ago

To match the underlying call ==> parameter int buflen ==> uint16_t buflen.

TODO

N0ury commented 1 year ago

I've tried the non block version. It works better, I have my logs displayed. For the moment some lines are missing. I need to check more precisely the results to be sure everything is ok. thanks for your great reactivity

RobTillaart commented 1 year ago

As I do not know your code It is difficult to point at the cause. Do you have empty lines in the log? Or ones that are longer than the buffer you have.

I'm preparing a readUntil() version but that will be after dinner :)

N0ury commented 1 year ago

Here's the FRAM content:

1681994531-3-3-2-9-0-8-2-6-6-9
1681994532-1-1-3-5
1681994533-8-3-0-6-9-2-7-7-2-8
1681994534-0-3-9-2-4-9-1-7-0-4
1681994535-5
1681994536-0-4-0-2-4-3-1-0-6-6
1681994537-1-9-7-5
1681994538-1-0-4-4-5
1681994539-9-0-7-6-3-4-4-0-9-0
1681994540-6-2-2-3-0-9-9-5
1681994541-5
1681994542-9-7-9-7-4-6-9-6-4-3
1681994543-5
1681994544-7-6-9-4-2-5
1681994545-3-8-1-0-0-7-5
1681994546-6-3-1-7-2-6-8-2-1-0
1681994547-0-8-1-1-4-7-4-7-5
1681994548-8-1-8-7-1-7-3-9-5
1681994549-0-0-3-2-4-3-7-1-0-0
1681994550-7-8-6-3-7-8-3-8-8-5
1681994551-3-8-0-1-6-7-0-9-7-8
1681994552-3-3-0-4-5
1681994553-3-2-0-7-2-0-5
1681994554-0-0-6-2-5
1681994555-0-7-4-1-8-6-9-0-5
1681994556-5
1681994557-2-4-1-6-2-8-5
1681994558-0-8-3-9-6-9-0-5
1681994559-2-3-4-5
1681994560-0-3-5
1681994561-0-5
1681994562-5
1681994563-5

And here's the output

37F
30      1681994531-3-3-2-9-0-8-2-6-6-9
19      8-3-0-6-9-2-7-7-2-8
11      4-9-1-7-0-4
19      3-3-2-9-0-8-2-6-6-9

Then it stops

my columns are separated by a '-' firt column is a timestamp Other columns are randomly generated. When the value "5" is reached I put a LF As you cans see the beginning is somehow good (not fully). From line 2 data are wrong. It's as if the data are interpreted, not just printed as they are.

RobTillaart commented 1 year ago

Other columns are randomly generated. When the value "5" is reached I put a LF

Can you determine how long the longest line is? can be arbitrary long, given your algorithm.

Or you call len = readLine(address, buffer, buflen, '-'); // use the - as separator.

N0ury commented 1 year ago

With a size of 100: src/readlog_rob.cpp FRAM_LIB_VERSION: 0.5.0 [ 25][I][esp32-hal-i2c.c:75] i2cInit(): Initialising I2C Master: sda=13 scl=14 freq=100000 [ 26][W][Wire.cpp:301] begin(): Bus already started in Master Mode.

37F
30  1681994531-3-3-2-9-0-8-2-6-6-9
19  8-3-0-6-9-2-7-7-2-8
11  4-9-1-7-0-4
19  3-3-2-9-0-8-2-6-6-9
30  1681994533-8-3-0-6-9-2-7-7-2-8
done...

This is full output (I use debug level=5). The line containing 37F is strange.

I haven't well understood option (2). I must add that I stop when 5 is reached (or when 10 value are used) and 5 is not reached.

RobTillaart commented 1 year ago

Please try this code. (function has been renamed to readUntil()

//
//    FILE: FRAM_readUntil.ino
//  AUTHOR: Rob Tillaart
// PURPOSE: demo to read until a separator is found.
//     URL: https://github.com/RobTillaart/FRAM_I2C
//   ISSUE: See issue #30 for some backgrounder.

//  lines := [timestamp][-d]*[-5]

#include "FRAM.h"

FRAM fram;

uint32_t sizeInBytes = 0;

char buffer[32];

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("FRAM_LIB_VERSION: ");
  Serial.println(FRAM_LIB_VERSION);

  Wire.begin();

  //  Can we find FRAM on the I2C bus?
  int rv = fram.begin(0x50);
  if (rv != 0)
  {
    Serial.print("INIT ERROR: ");
    Serial.println(rv);
  }

  //  Get size in bytes to know when to stop.
  sizeInBytes = fram.getSize() * 1024;

  //  assuming FRAM is filled with FRAM_logging.ino
  //  first entry is starts at 0x04 => address next entry is written in [0..3]
  int len = 0;
  uint32_t address = 4;

  while(true)
  {
    len = readUntil(address, buffer, 32, '-');
    if (len > 0)
    {
      Serial.print(buffer);
      Serial.print('-');     //  add the overwritten separator.
    }
    if (len == 0)
    {
      len = readUntil(address, buffer, 32, '\n');
      if (len == 0) 
      {
        Serial.println("EOF");
        break;
      }
      Serial.println(buffer);
    }
    address = address + len + 1;

    if (address >= sizeInBytes)
    {
      Serial.println("End of FRAM");
      break;
    }
  }
  Serial.println("done");
}

void loop()
{
}

//  returns length of the buffer 
//  returns or 0 if it does not fit.
uint16_t readUntil(uint32_t address, char * buf, uint16_t buflen, char separator)
{
  //  read and fill the buffer at once.
  fram.read(address, (uint8_t *)buf, buflen);
  for (uint16_t length = 0; length < buflen; length++)
  {
    if (buf[length] == separator)
    {
      buf[length] = 0;    //  replace \n => \0 EndChar
      return length;
    }
  }
  //  entry does not fit in given buffer.
  return (uint16_t)0;
}

//  -- END OF FILE --
RobTillaart commented 1 year ago

It tries to read until the separator '-' and if that succeeds it prints the field and the '-' If it not succeeds it is near the end of line so it tries to read until '\n'

RobTillaart commented 1 year ago

char buffer[32];

As the timestamp is the longest field (10 digits), it should work with a buffer[12].

N0ury commented 1 year ago

It' much better! But not correct Here's the output

src/readlog_rob.cpp
FRAM_LIB_VERSION: 0.5.0
[    25][I][esp32-hal-i2c.c:75] i2cInit(): Initialising I2C Master: sda=13 scl=14 freq=100000
[    26][W][Wire.cpp:301] begin(): Bus already started in Master Mode.
1681994531-3-3-2-9-0-8-2-6-6-9
1681994532-1-1-3-5
1681994533-8-3-0-6-9-2-7-7-2-8
1681994534-0-3-9-2-4-9-1-7-0-4
1681994531-3-3-2-9-0-8-2-6-6-9
1681994532-1-1-3-5
1681994533-8-3-0-6-9-2-7-7-2-8
1681994534-0-3-9-2-4-9-1-7-0-4
1681994535-5
1681994536-0-4-0-2-4-3-1-0-6-6
1681994537-1-9-7-5
1681994538-1-0-4-4-5
1681994539-9-0-7-6-3-4-4-0-9-0
1681994540-6-2-2-3-0-9-9-5
1681994541-5
1681994542-9-7-9-7-4-6-9-6-4-3
1681994543-5
1681994544-7-6-9-4-2-5
1681994545-3-8-1-0-0-7-5
1681994546-6-3-1-7-2-6-8-2-1-0
1681994547-0-8-1-1-4-7-4-7-5
1681994548-8-1-8-7-1-7-3-9-5
1681994549-0-0-3-2-4-3-7-1-0-0
1681994550-7-8-6-3-7-8-3-8-8-5
1681994551-3-8-0-1-6-7-0-9-7-8
1681994552-3-3-0-4-5
1681994553-3-2-0-7-2-0-5
1681994554-0-0-6-2-5
1681994555-0-7-4-1-8-6-9-0-5
1681994556-5
1681994557-2-4-1-6-2-8-5
1681994558-0-8-3-9-6-9-0-5
1681994559-2-3-4-5
1681994560-0-3-5
1681994561-0-5
1681994562-5
1681994563-5
EOF
done

As you can see lines

1681994531-3-3-2-9-0-8-2-6-6-9
1681994532-1-1-3-5
1681994533-8-3-0-6-9-2-7-7-2-8
1681994534-0-3-9-2-4-9-1-7-0-4

are duplicated...

N0ury commented 1 year ago

Just a moment... Lines are dupplicated perhaps because of a previous start with same begin datetime (converted to timestamp)

Edit: I don't use any RTC at the moment. Begin datetime is hardcoded

N0ury commented 1 year ago

I think we can say this version works. Let me try it in better conditions. From now to the end of week-end (maybe less), I think I will have checked it in many ways.

RobTillaart commented 1 year ago

Can you make a dump with this sketch. It is sort of minimalistic HEX dump of the FRAM.

You should be able to see if the data is repeating in FRAM

//
//    FILE: FRAM_dump.ino
//  AUTHOR: Rob Tillaart
// PURPOSE: dump FRAM
//     URL: https://github.com/RobTillaart/FRAM_I2C

#include "FRAM.h"

FRAM fram;

uint32_t sizeInBytes = 0;

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("FRAM_LIB_VERSION: ");
  Serial.println(FRAM_LIB_VERSION);

  Wire.begin();

  int rv = fram.begin(0x50);
  if (rv != 0)
  {
    Serial.print("INIT ERROR: ");
    Serial.println(rv);
  }

  //  get size in bytes
  sizeInBytes = fram.getSize() * 1024;
  Serial.print("BYTES  :\t");
  Serial.println(sizeInBytes);
  delay(100);

  for (uint32_t addr = 0; addr < 1024; addr++)   //  adjust the part that needs printed.
  {
    if (addr % 16 == 0)
    {
      Serial.println();
      Serial.print(addr);
      Serial.print("\t");
    }
    uint8_t b = fram.read8(addr);
    if (b < 16) Serial.print(0);
    Serial.print(b, HEX);
    Serial.print("  ");
  }
  Serial.println("\n\ndone...");
}

void loop()
{
}

//  -- END OF FILE --
RobTillaart commented 1 year ago

Updated the HEXdump to show also the ASCII

//
//    FILE: FRAM_dump.ino
//  AUTHOR: Rob Tillaart
// PURPOSE: dump FRAM
//     URL: https://github.com/RobTillaart/FRAM_I2C

#include "FRAM.h"

FRAM fram;

uint32_t sizeInBytes = 0;

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);
  Serial.print("FRAM_LIB_VERSION: ");
  Serial.println(FRAM_LIB_VERSION);

  Wire.begin();

  int rv = fram.begin(0x50);
  if (rv != 0)
  {
    Serial.print("INIT ERROR: ");
    Serial.println(rv);
  }

  //  get size in bytes
  sizeInBytes = fram.getSize() * 1024;
  Serial.print("BYTES  :\t");
  Serial.println(sizeInBytes);
  delay(100);

  for (uint32_t addr = 0; addr < 1024; addr += 16)
  {
    Serial.println();
    Serial.print(addr);
    Serial.print("\t");
    for (uint32_t i = 0; i < 16; i++)
    {
      uint8_t b = fram.read8(addr + i);
      if (b < 16) Serial.print(0);
      Serial.print(b, HEX);
      Serial.print("  ");
    }
    Serial.print("  ");
    for (uint32_t i = 0; i < 16; i++)
    {
      uint8_t b = fram.read8(addr + i);
      if (isprint(b)) Serial.print((char)b);
      else Serial.print(".");
    }
  }
  Serial.println("\n\ndone...");
}

void loop()
{
}

//  -- END OF FILE --
N0ury commented 1 year ago

First hexdump (I read hex quite easily ;-) ) shows duplicates. It's all good!

N0ury commented 1 year ago

Wouaouh! I have tried the new dump sketch, it's impressive. You should add it to the lib. It can be very useful. Thanks for all. I will wait now for the readUntil method. I will then close the issue.

RobTillaart commented 1 year ago

I found a bug in readUntil(), will work on it tomorrow.

The bug is if you print an empty string in the log, then it will return 0 as length but that indicates now that the separator is not found. Think the latter will become 65535 as error code as that will seldom be used as buffer. Alternative is to add another parameter in the function, making it I guess more complex than needed.

Saw you are from France, which part? I'm living in the south of the Netherlands near Eindhoven.

N0ury commented 1 year ago

I'll begin to use it anyway. If parameters remain the same it's not a problem. I live in the suburbs of Paris

RobTillaart commented 1 year ago

Params will not change only the return value 0 cannot be used for nomatch. Will use 65535 for that ( sort of -1).

Have to update readme.md version number etc, will be 0.5.1. i will include the hexdump sketch and the stand alone readUntil sketch in the examples.

I'm still working (not very recent) on a way to encode static multilanguage strings efficient in FRAM. The readuntil might be useful here.

RobTillaart commented 1 year ago

Goodmorning, latest thoughts are The signature will become

int32_t readUntil(...)

Alllows buffers up to 65535, And -1 as nomatch Parameters will be same as before. This seems semantically more intuitive to me.

RobTillaart commented 1 year ago

@N0ury Created develop branch and Pull Request - https://github.com/RobTillaart/FRAM_I2C/pull/31

RobTillaart commented 1 year ago

The bug is if you print an empty string in the log, then it will return 0 as length but that indicates now that the separator is not found. Think the latter will become 65535 as error code as that will seldom be used as buffer. Alternative is to add another parameter in the function, making it I guess more complex than needed.

Solved this by returning an int32_t instead of an uint16_t

RobTillaart commented 1 year ago

I'm working on int32_t readLine(uint16_t memaddr, char * buf, uint16_t buflen) which reads until but includes the '\n' character.

Looks stable, build is running, will be merged and released today.

N0ury commented 1 year ago

Nice! These are good news.

RobTillaart commented 1 year ago

Merged and released 0.5.1. The build is running, expect no problems there. This issue is closed as I had it linked to the merge of the PR.

RobTillaart commented 1 year ago

FYI, I am currently working on an experimental class to store static text in FRAM. (see develop) The idea is to put translation tables in FRAM, so applications can switch e.g. between Portugese and France and English.