I've broken print .

Good evening.

I've been working on a circular buffer library that's based on the HardwareSerial library. When I say based, I mean copied and then hacked around a bit to remove functions I don't need. As far as the buffer is concerned, it's actually doing exactly what I wanted, but somewhere along the way, I appear to have stopped it printing text.

Code like this works as expected and prints out to the terminal program (PuTTY).

mySerial.print(Byte[i], HEX);

Code like this prints nothing, but the cursor does move to the next line. It looks like any characters enclosed in quotes don't print, but printing the contents of a variable or array print fine.

mySerial.println("--This doesn't print any more--");

This is the chopped down HardwareSerial.h and HardwareSerial.cpp files (renamed CircularBuffer.h and CircularBuffer.cpp) . If someone can have a look and possibly identify what I've done wrong, I'd appreciate it. I've been comparing these modified files with the originals for hours, but can't find what I've done wrong.

/*
  CircularBuffer.h - Circular Buffer library
  
*/

#ifndef CircularBuffer_h
#define CircularBuffer_h
#endif

#include <inttypes.h>
#include "Stream.h"

struct ring_buffer;

class CircularBuffer : public Stream
{
  private:
    ring_buffer *_ibus_buffer;
    
  public:
    CircularBuffer(ring_buffer *ibus_buffer);
    virtual int available(void);
    virtual int peek(void);
	virtual int peekn(int a);
	virtual void remove(uint8_t);
    virtual int read(void);
	virtual void flush(void);
    virtual size_t write(uint8_t);
    inline size_t write(unsigned long n) { return write((uint8_t)n); }
    inline size_t write(long n) { return write((uint8_t)n); }
    inline size_t write(unsigned int n) { return write((uint8_t)n); }
    inline size_t write(int n) { return write((uint8_t)n); }
	using Print::write; // pull in write(str) and write(buf, size) from Print
	operator bool();
};


extern CircularBuffer Buffer;
/*
  CircularBuffer.cpp - Circular Buffer library.

*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "Arduino.h"
#include "wiring_private.h"
#include "CircularBuffer.h"


#define BUFFER_SIZE 256


struct ring_buffer
{
  unsigned char buffer[BUFFER_SIZE];
  volatile unsigned int head;
  volatile unsigned int tail;
};


  ring_buffer ibus_buffer = { { 0 }, 0, 0};

inline void store_char(unsigned char c, ring_buffer *buffer)
{
  int i = (unsigned int)(buffer->head + 1) % BUFFER_SIZE;

  // if we should be storing the received character into the location
  // just before the tail (meaning that the head would advance to the
  // current location of the tail), we're about to overflow the buffer
  // and so we don't write the character or advance the head.
  if (i != buffer->tail) {
    buffer->buffer[buffer->head] = c;
    buffer->head = i;
  }
}


// Constructors ////////////////////////////////////////////////////////////////

CircularBuffer::CircularBuffer(ring_buffer *ibus_buffer)
{
  _ibus_buffer = ibus_buffer;
  
}

// Public Methods //////////////////////////////////////////////////////////////



  // clear any received data
  //_ibus_buffer->head = _ibus_buffer->tail;


int CircularBuffer::available(void)
{
  return (unsigned int)(BUFFER_SIZE + _ibus_buffer->head - _ibus_buffer->tail) % BUFFER_SIZE;
}

int CircularBuffer::peek(void)
{
  if (_ibus_buffer->head == _ibus_buffer->tail) {
    return -1;
  } else {
    return _ibus_buffer->buffer[_ibus_buffer->tail];
  }
}

int CircularBuffer::read(void)
{
  // if the head isn't ahead of the tail, we don't have any characters
  if (_ibus_buffer->head == _ibus_buffer->tail) {
    return -1;
  } else {
    unsigned char c = _ibus_buffer->buffer[_ibus_buffer->tail];
    _ibus_buffer->tail = (unsigned int)(_ibus_buffer->tail + 1) % BUFFER_SIZE;
    return c;
  }
}

void CircularBuffer::flush()
{
  // UDR is kept full while the buffer is not empty, so TXC triggers when EMPTY && SENT
  
}

size_t CircularBuffer::write(uint8_t c)
{
  int i = (_ibus_buffer->head + 1) % BUFFER_SIZE;
	
  // If the output buffer is full, there's nothing for it other than to 
  // wait for the interrupt handler to empty it a bit
  // ???: return 0 here instead?
  while (i == _ibus_buffer->tail)
    ;
	
  _ibus_buffer->buffer[_ibus_buffer->head] = c;
  _ibus_buffer->head = i;
	
  
  return 1;
}

CircularBuffer::operator bool() {
	return true;
}

// Preinstantiate Objects //////////////////////////////////////////////////////


  CircularBuffer Buffer(&ibus_buffer);

Quick update.

It's just the SoftwareSerial that's stopped printing text. I tried the HardwareSerial as a test, and that prints text to the Serial Monitor just fine.

I'm still no closer to finding my mistake though :blush:

Post ALL your code it may be a problem with your test code!

Mark

Are you trying to make a modified version of the Hardware Serial library to use in place of the standard version or are you trying to make a version of Software Serial derived from the Hardware Serial code?

I posted "yet another software serial" here - partly based on what I learned from your IBUS explorations.

...R

If you have problems printing string literals, my first thought is always whether you may be running out of SRAM. How much do you have free?

I've only skimmed the code but I think you may have an off-by-one error on your circular buffer. In order to differentiate between the full and empty conditions your queue capacity would need to be one less than the size, and I don't see that offset implemented anywhere.

Can you post a complete sketch and any supporting files necessary to demonstrate the problem?

holmes4:
Post ALL your code it may be a problem with your test code!

Mark

It's too big to post all of it. I'll see if I can cut it down a bit and post a section that will demonstrate the problem.

Ian.

Robin2:
Are you trying to make a modified version of the Hardware Serial library to use in place of the standard version or are you trying to make a version of Software Serial derived from the Hardware Serial code?

I posted "yet another software serial" here - partly based on what I learned from your IBUS explorations.

...R

Hi Robin,

I'm not actually trying to make a serial library as such. I'm trying to extract the ring buffer portion of the HardwareSerial library to use in my ibus project.

I want a ring buffer to store bytes that I want to send out onto the ibus. A ring buffer seems a good way to store the bytes until the ibus is clear to send. My main program can save the bytes into the buffer and when the loop detects the ibus is clear, it can read them from the buffer and send them out.

It all works quite nicely apart from this printing problem.

Ian.

The SoftwareSerial code I wrote (and linked to above) has a simple ring buffer - feel free to "borrow" it.

Basically it has head and tail pointers. It writes at the head and reads at the tail.

...R

Thanks Robin.

I think I can work with that.

I noticed there's two sssWrite functions. Are they just to allow you to pass different data types ?

Ian.

ian332isport:
I noticed there's two sssWrite functions. Are they just to allow you to pass different data types ?

Hi, Ian,

Yes one of them writes a single byte and the other writes an array of bytes. You can have as many different versions as you need. The compiler picks the correct one to match the parameters in the function call.

...R

ian332isport:

holmes4:
Post ALL your code it may be a problem with your test code!

Mark

It's too big to post all of it. I'll see if I can cut it down a bit and post a section that will demonstrate the problem.

Ian.

Which tends to support the suggestion that you may be running out of RAM, especially if you're printing lots of constant strings.

You can attach the code if it is too large to embed.

And the prize goes to PeterH and AWOL XD

I was indeed running out of SRAM.

I had a number of byte arrays defined that were way too big. Adding the CircularBuffer library added another array that tipped it over the edge.

I've reduced the size of the arrays, and moved some others to PROGMEM. Printing is back to normal now.

Thanks to all.

Ian.

ian332isport:
And the prize goes to PeterH and AWOL XD

Sh*t :slight_smile:

...R

Robin2:

ian332isport:
And the prize goes to PeterH and AWOL XD

Sh*t :slight_smile:

...R

You do get the (dubious) honour of providing an excellent circular buffer though :smiley:

It took a bit of fiddling with the head & tail pointers to get it to function as a proper circular buffer, but it does exactly what I wanted.

Just going back to storing byte arrays in PROGMEM for a minute.

Before moving my byte arrays out of SRAM, I used commands like this and it worked just fine.

byte DSP_STATUS_REPLY_RST [6] = { 0x6A , 0x04 , 0xFF , 0x02 , 0x01 , 0x92 }; // DSP status ready after reset
sssWrite(sizeof (DSP_STATUS_REPLY_RST));
sssWrite(DSP_STATUS_REPLY_RST, sizeof (DSP_STATUS_REPLY_RST));

After moving the array to PROGMEM..

byte DSP_STATUS_REPLY_RST [6]  PROGMEM = { 0x6A , 0x04 , 0xFF , 0x02 , 0x01 , 0x92 }; // DSP status ready after reset

I can modify the first sssWrite line to:

sssWrite(pgm_read_byte(sizeof (DSP_STATUS_REPLY_RST)));

This compiles OK, but I can't figure out the correct syntax for the second sssWrite command. I've tried a number of variations like the code below, but get errors like this.

invalid conversion from 'uint8_t' to 'byte*'

sssWrite(pgm_read_byte(DSP_STATUS_REPLY_RST), pgm_read_byte(sizeof (DSP_STATUS_REPLY_RST)));

Any suggestions ?

Regarding Reply #13 ...

I'm not good on the PROGMEM stuff

I was going to make a suggestion but it would be too much like a blind guess so I will leave it to someone else.

I wonder what pgm_read_byte() returns? It doesn't sound like an array.
Also, while the way you have the first version of sssWrite may compile, but does it give the correct answer?

...R

Robin2:
while the way you have the first version of sssWrite may compile, but does it give the correct answer?

I hadn't actually tested it before. I was still trying to get the rest of it to compile.

Just tested, and no, it doesn't work. It should return 6, but returns 2.

It's not a huge issue, but it would be nice to understand how to do it - assuming it's possible.

Ian.

Hi Ian,

One of us will need to learn the proper way to use PROGMEM. I am happy to leave it to you.

...R

#ifndef CircularBuffer_h
#define CircularBuffer_h
#endif

This is wrong. The endif here belongs at the end of the header file.

  ring_buffer ibus_buffer = { { 0 }, 0, 0};

When I learned C, this would have been an error without the keyword struct or a typedef for it.

michinyon:
When I learned C, this would have been an error without the keyword struct or a typedef for it.

It should still be the case if you wrote it in a .c file.

@OP, you are using pgm_read_byte wrong.

byte DSP_STATUS_REPLY_RST [6]  PROGMEM = { 0x6A , 0x04 , 0xFF , 0x02 , 0x01 , 0x92 };

To read the first byte of the array you could do this:

byte b = pgm_read_byte( DSP_STATUS_REPLY_RST );

To read the whole array in a loop, you could do this:

for( char i = 0 ; i < sizeof( DSP_STATUS_REPLY_RST ) ; ++i ){
    byte b = pgm_read_byte( DSP_STATUS_REPLY_RST + i );
    Serial.println( b, HEX );
}

Note: sizeof works in this instance cos the array is an array of single bytes, anything larger needs help: http://arduino.land/FAQ/content/6/29/en/how-to-get-the-size-of-an-array.html

You can also rewrite the access code to use array syntax rather than pointer arithmetic:

pgm_read_byte( DSP_STATUS_REPLY_RST + i );
//Or
pgm_read_byte( &DSP_STATUS_REPLY_RST[ i ] );