Pages: 1 [2]   Go Down
Author Topic: How to attach software serial to a library  (Read 1178 times)
0 Members and 1 Guest are viewing this topic.
Central MN, USA
Offline Offline
Tesla Member
***
Karma: 74
Posts: 7255
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset


Thanks! Weird though, because I only get an error when I try to do that with the softserial. The regular serial doesn't complain.

But that suggestion worked...

So back to trying to figure out how to redirect the output. I am hoping for an example somewhere...

Which IDE version are you using? I wrote that post for 1.0 and things may have been changed. I'll check the core code and provide an update.
Logged


Central MN, USA
Offline Offline
Tesla Member
***
Karma: 74
Posts: 7255
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I am just beginning, so I could go either way. But I plan to use class based for the simplicity of using it. I have written only one library so far and I started with a "close-enough" example and modified it heavily. It was for a custom 3 wire interface to an IC. I modified a softwareTWI library for that (3rd pin was just chip select.)

So, that is the extent of my experience so far. Doing anything advanced, I would need to see some examples because I am not familiar with what the code looks like.

Let's see your code.
Logged


UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Personally I prefer the class-based approach, since it results in a cleaner isolation IMO.

In that case you can pass in the serial object to the constructor for your library's main class. Provide two constructors, one accepting a HardwareSerial and the other accepting a SoftwareSerial. Have a member variables to hold a pointer to each of them, set the unused one to null. Provide a method to read from the input stream which tests which serial object is set, and reads from it. Similarly provide a method to write to whichever serial object was set. It's a bit messy, but I think this is the best you can reasonably get given the existing HardwareSerial and SoftwareSerial implementations. (No kudos for the people who designed this part of the Arduino API.)
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
God Member
*****
Karma: 27
Posts: 829
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Let's see your code.

Which code? My modified TWI library (for a different chip) or what code I have for the MP3 module already? Right now, it is just a sketch directly using the softserial library. I haven't started to assemble it into a library yet because this part (redirecting output) seemed like the most important part.
Logged

Offline Offline
God Member
*****
Karma: 27
Posts: 829
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Personally I prefer the class-based approach, since it results in a cleaner isolation IMO.

In that case you can pass in the serial object to the constructor for your library's main class. Provide two constructors, one accepting a HardwareSerial and the other accepting a SoftwareSerial. Have a member variables to hold a pointer to each of them, set the unused one to null. Provide a method to read from the input stream which tests which serial object is set, and reads from it. Similarly provide a method to write to whichever serial object was set. It's a bit messy, but I think this is the best you can reasonably get given the existing HardwareSerial and SoftwareSerial implementations. (No kudos for the people who designed this part of the Arduino API.)

You're right, that is probably the best I can do. Of course, I would need to go further and provide a way to use the other hardware serial ports on a Mega. I am beginning to think the simplest and cleanest way may be to pull over chunks of the softwareserial library and just hardwire it into my own code. Since the module will only work at 4800bps and only realistically need a write() routine, I don't really need many of the extras in the library anyway.
Logged

Central MN, USA
Offline Offline
Tesla Member
***
Karma: 74
Posts: 7255
Phi_prompt, phi_interfaces, phi-2 shields, phi-panels
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Some investigations:

Arduino 1.5

Hardware serial
Code:
   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
Code:
   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
Code:
   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
Code:
   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
Code:
   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
Code:
   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++);
}
« Last Edit: February 13, 2013, 12:25:44 pm by liudr » Logged


UK
Offline Offline
Shannon Member
****
Karma: 223
Posts: 12630
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
God Member
*****
Karma: 27
Posts: 829
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 - downloaded 13 times.)
* serMP3.h (1.19 KB - downloaded 12 times.)
Logged

Offline Offline
God Member
*****
Karma: 27
Posts: 829
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
« Last Edit: February 13, 2013, 01:42:37 pm by Retroplayer » Logged

Offline Offline
God Member
*****
Karma: 27
Posts: 829
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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 - downloaded 7 times.)
Logged

Pages: 1 [2]   Go Up
Jump to: