How to attach software serial to a library

Some investigations:

Arduino 1.5

Hardware serial

    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

Print

    virtual size_t write(uint8_t) = 0;
    size_t write(const char *str) {
      if (str == NULL) return 0;
      return write((const uint8_t *)str, strlen(str));
    }
    virtual size_t write(const uint8_t *buffer, size_t size);

Arduino 1.0
Hardware serial

    virtual size_t write(uint8_t);
    using Print::write; // pull in write(str) and write(buf, size) from Print

size_t HardwareSerial::write(uint8_t c)
{
  int i = (_tx_buffer->head + 1) % SERIAL_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 == _tx_buffer->tail)
    ;
	
  _tx_buffer->buffer[_tx_buffer->head] = c;
  _tx_buffer->head = i;
	
  sbi(*_ucsrb, _udrie);
  
  return 1;
}

Print

    virtual size_t write(uint8_t) = 0;
    size_t write(const char *str) { return write((const uint8_t *)str, strlen(str)); }
    virtual size_t write(const uint8_t *buffer, size_t size);

/* default implementation: may be overridden */
size_t Print::write(const uint8_t *buffer, size_t size)
{
  size_t n = 0;
  while (size--) {
    n += write(*buffer++);
  }
  return n;
}

Arduino 0022
Hardware serial

    virtual void write(uint8_t);
    using Print::write; // pull in write(str) and write(buf, size) from Print

void HardwareSerial::write(uint8_t c)
{
  while (!((*_ucsra) & (1 << _udre)))
    ;

  *_udr = c;
}

Print

    virtual void write(uint8_t) = 0;
    virtual void write(const char *str);
    virtual void write(const uint8_t *buffer, size_t size);

/* default implementation: may be overridden */
void Print::write(const char *str)
{
  while (*str)
    write(*str++);
}

/* default implementation: may be overridden */
void Print::write(const uint8_t *buffer, size_t size)
{
  while (size--)
    write(*buffer++);
}

Retroplayer:
Of course, I would need to go further and provide a way to use the other hardware serial ports on a Mega.

This is taken care of by providing a constructor which accepts a HardwareSerial. You can pass in Serial, or Serial2 or any other hardware serial port that your Arduino has.

Here is what I have come up with. I am at work and did it all over lunch so I have not had a chance to test it. I basically just stripped the softwareserial library to only it's useful bits and threw in my code. I am attaching it because it is too large.

I kept the write() method public so that I could just write the supposedly unsupported commands. The constructor takes a tx pin and a busy pin. I am not currently using the busy pin yet, but will add that in later.

The baudrate and all values are pre-calculated for 4800 buad at 16MHz in order to get rid of all of the tables. I may go back and correct that to allow other frequencies to be used. But the baud rate will always be 4800 for this module, no matter what. I think only tx_delay and transmit_start are affected by a change in CPU frequency.

I left in #include <Stream.h> but I don't think I need it now that I ripped out all the read and print functions.

If you notice any glaring errors or anything I can remove or simplify, please let me know.

serMP3.cpp (2.11 KB)

serMP3.h (1.19 KB)

Doh... I forgot to add the serMP3:: to my functions. I am aware of that and fixing it. But, any other errors you see, let me know, please.

I also added a begin function again that accepts an initial volume level. This function also stops anything that is playing because the module has a tendency to start playing a random file from the root folder on initial power up.

Not exactly sure what I will do with the busy pin, since really the only time I would need to check it would be when it is playing a MP3 and you try to play another. I think I will just add a public funciton to check it.

Perhaps in the play function, I can check if it is busy and if so, stop the current MP3 and play the new one.

But then I need to account for when the busypin is not being used in an application.

Oh well, 2/3 of the way there, I think.

ok, got home. Got the library working the way it should. Set up a simple example program to show it off and it works. But, for some reason if I pick an MP3 that doesn't exist, it always plays the last one it was playing.... grr....

My serial commands will look like this:

P001 or p001 = Play 001.mp3
s or S = stop
V31 or v31 = set volume at 31

  • = volume up
  • = volume down
    r or R = resume
    h or H = pause
    C02 = change to 02 folder

Doing some debugging, I learned that if you point to an MP3 that doesn't exist, it switches to random play and plays whatever. Trying to figure out how I can prevent that.

Looking for a good way to handle the multibyte serial entries. Ideally, I would like P1,P01, and P001 to all be the same. Same with volume and folder commands. I know I could do a ton of OR conditions and loops, but there is an easier way, I am sure.

I have attached the finished library and my example code.

serMP3.zip (3.65 KB)