Skip to content

5. Reading from the SDI 12 Object.

Sara Damiano edited this page Aug 13, 2024 · 3 revisions

5.1 available()

available() is a public function that returns the number of characters available in the buffer.

To understand how: _rxBufferTail +_BUFFER_SIZE -_rxBufferHead) % _BUFFER_SIZE; accomplishes this task, we will use a few examples.

To start take the buffer below that has _BUFFER_SIZE = 10. The message "abc" has been wrapped around (circular buffer).

_rxBufferTail = 1 // points to the '-' after c
_rxBufferHead = 8 // points to 'a'

[ c ] [ - ] [ - ] [ - ] [ - ] [ - ] [ - ] [ - ] [ a ] [ b ]

The number of available characters is (1 + 10 - 8) % 10 = 3

The '%' or modulo operator finds the remainder of division of one number by another. In integer arithmetic 3 / 10 = 0, but has a remainder of 3. We can only get the remainder by using the the modulo '%'. 3 % 10 = 3. This next case demonstrates more clearly why the modulo is used.

_rxBufferTail = 4 // points to the '-' after c
_rxBufferHead = 1 // points to 'a'

[ a ] [ b ] [ c ] [ - ] [ - ] [ - ] [ - ] [ - ] [ - ] [ - ]

The number of available characters is (4 + 10 - 1) % 10 = 3

If we did not use the modulo we would get either ( 4 + 10 - 1 ) = 13 characters or ( 4 + 10 - 1 ) / 10 = 1 character. Obviously neither is correct.

If there has been a buffer overflow, available() will return -1.

int SDI12::available()
{
  if(_bufferOverflow) return -1;
  return (_rxBufferTail + _BUFFER_SIZE - _rxBufferHead) % _BUFFER_SIZE;
}

5.2 peek()

peek() is a public function that allows the user to look at the character that is at the head of the buffer. Unlike read() it does not consume the character (i.e. the index addressed by _rxBufferHead is not changed). peek() returns -1 if there are no characters to show.

int SDI12::peek()
{
  if (_rxBufferHead == _rxBufferTail) return -1;  // Empty buffer? If yes, -1
  return _rxBuffer[_rxBufferHead];     // Otherwise, read from "head"
}

5.3 flush()

flush() is a public function that clears the buffers contents by setting the index for both head and tail back to zero.

void SDI12::flush()
{
  _rxBufferHead = _rxBufferTail = 0;
  _bufferOverflow = false;
}

5.4 read()

read() returns the character at the current head in the buffer after incrementing the index of the buffer head. This action 'consumes' the character, meaning it can not be read from the buffer again. If you would rather see the character, but leave the index to head intact, you should use peek().

int SDI12::read()
{
  _bufferOverflow = false;    //reading makes room in the buffer
  if (_rxBufferHead == _rxBufferTail) return -1;  // Empty buffer? If yes, -1
  uint8_t nextChar = _rxBuffer[_rxBufferHead];  // Otherwise, grab char at head
  _rxBufferHead = (_rxBufferHead + 1) % _BUFFER_SIZE;   // increment head
  return nextChar;           // return the char
}

5.5 peakNextDigit()

peekNextDigit() is called by the Stream class. It is overridden here to allow for a custom TIMEOUT value. The default value for the Stream class is to return 0. This makes distinguishing timeouts from true zero readings impossible. Therefore the default value has been set to -9999 in section 0 of the code. It is a public variable and can be changed dynamically within a program by calling: mySDI12.TIMEOUT = (int) newValue

int SDI12::peekNextDigit()
{
  int c;
  while (1) {
    c = timedPeek();
    if (c < 0) return TIMEOUT; // timeout
    if (c == '-') return c;
    if (c >= '0' && c <= '9') return c;
    read(); // discard non-numeric
  }
}