[LIBRARY] SoftwareSerial to HardwareSerial

I'm trying to change the original SoftwareSerial library from VR3 Voice Recognition Module to a HardwareSerial one... I don't have any knowlodge of how libraries works... I Tried to make some these changes, but without sucess.

I changed VoiceRecognitionV3.H file from this

#if ARDUINO >= 100
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif

#include "wiring_private.h"

#include "SoftwareSerial.h"
#include <avr/pgmspace.h>

#define DEBUG

#ifdef DEBUG
#define DBGSTR(message)     Serial.print(message)
#define DBGBUF(buf, len)	Serial.write(buf, len)
#define DBGLN(message)		Serial.println(message)
#define DBGFMT(msg, fmt)	Serial.print(msg, fmt)
#define DBGCHAR(c)			Serial.write(c)
#else
#define DBG(message)
#endif // DEBUG

to this

#if ARDUINO >= 100
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif

#include "wiring_private.h"

//#include "SoftwareSerial.h" // Commented this #include
#include <avr/pgmspace.h>

#define DEBUG

#ifdef DEBUG
#define DBGSTR(message)     Serial3.print(message) // Change to Serial3.*
#define DBGBUF(buf, len)	Serial3.write(buf, len) // Change to Serial3.*
#define DBGLN(message)		Serial3.println(message) // Change to Serial3.*
#define DBGFMT(msg, fmt)	Serial3.print(msg, fmt) // Change to Serial3.*
#define DBGCHAR(c)			Serial3.write(c) // Change to Serial3.*
#else
#define DBG(message)
#endif // DEBUG

I changed VoiceRecognitionV3.CPP file from this

#include "VoiceRecognitionV3.h"
#include <string.h>

VR* VR::instance;

/** temp data buffer */
uint8_t vr_buf[32];
uint8_t hextab[17]="0123456789ABCDEF";

/**
	@brief VR class constructor.
	@param receivePin --> software serial RX
		   transmitPin --> software serial TX
*/
VR::VR(uint8_t receivePin, uint8_t transmitPin) : SoftwareSerial(receivePin, transmitPin)
{
	instance = this;
	SoftwareSerial::begin(38400);
}

to this

#include "VoiceRecognitionV3.h"
#include <string.h>

VR* VR::instance;

/** temp data buffer */
uint8_t vr_buf[32];
uint8_t hextab[17]="0123456789ABCDEF";

/**
	@brief VR class constructor.
	@param receivePin --> software serial RX
		   transmitPin --> software serial TX
*/
VR::VR(uint8_t receivePin, uint8_t transmitPin) : HardwareSerial(receivePin, transmitPin) // Changed to HardwareSerial
{
	instance = this;
	HardwareSerial::begin(38400); // Changed to HardwareSerial
}

My ino code is basicly

#include "VoiceRecognitionV3.h"
VR myVR(15, 14); // (COMANDO DE VOZ) Hardware pins in Arduino MEGA Board

void Setup()
{
myVR.begin(9600); // Start module serial
  myVR.clear(); // Start the module
}

void loop()
{
 // my code
}

I'm getting this small error output from Arduino IDE

D:\...\VoiceRecognitionV3.cpp: In constructor 'VR::VR(uint8_t, uint8_t)':

D:\...\VoiceRecognitionV3.cpp:43:89: error: no matching function for call to 'HardwareSerial::HardwareSerial(uint8_t&, uint8_t&)'

 VR::VR(uint8_t receivePin, uint8_t transmitPin) : HardwareSerial(receivePin, transmitPin)

                                                                                         ^

D:\...\VoiceRecognitionV3.cpp:43:89: note: candidates are:

In file included from C:\.../Arduino.h:232:0,

                 from D:\...\VoiceRecognitionV3.h:31,

                 from D:\...\VoiceRecognitionV3.cpp:29:

C:\.../HardwareSerial.h:117:12: note: HardwareSerial::HardwareSerial(volatile uint8_t*, volatile uint8_t*, volatile uint8_t*, volatile uint8_t*, volatile uint8_t*, volatile uint8_t*)

     inline HardwareSerial(

            ^

C:\.../HardwareSerial.h:117:12: note:   candidate expects 6 arguments, 2 provided

C:\.../HardwareSerial.h:93:7: note: constexpr HardwareSerial::HardwareSerial(const HardwareSerial&)

 class HardwareSerial : public Stream

       ^

C:\.../HardwareSerial.h:93:7: note:   candidate expects 1 argument, 2 provided

C:\.../HardwareSerial.h:93:7: note: constexpr HardwareSerial::HardwareSerial(HardwareSerial&&)

C:\.../HardwareSerial.h:93:7: note:   candidate expects 1 argument, 2 provided

Voice Recognition Library Download

Board Arduino MEGA 2560

The HardwareSerial class already takes care of creating all the required instances. Your VoiceRecognitionV3 cpp file should NOT be creating another instance of HardwareSerial.

The HardwareSerial class KNOWS which pins to use for which instance. It does NOT take pin numbers in the constructor.

PaulS:
The HardwareSerial class already takes care of creating all the required instances. Your VoiceRecognitionV3 cpp file should NOT be creating another instance of HardwareSerial.

Hmm, gotcha... So, I do have to remove this part of CPP file

VR::VR(uint8_t receivePin, uint8_t transmitPin) : HardwareSerial(receivePin, transmitPin)
{
	instance = this;
	HardwareSerial::begin(38400);
}

And I should replace it for what? :confused:

PaulS:
The HardwareSerial class KNOWS which pins to use for which instance. It does NOT take pin numbers in the constructor.

I imagined about that, because if you use Hardware Serial 3, it's obviously that you're using pins 14 and 15, as I have little knowledge of library programming I don't know how to fix that...

I was comparing with another library which have support for both Serials, the owner of the other library said

Remove the lines:

#include <SoftwareSerial.h>

SoftwareSerial nextion(2, 3);// Nextion TX to pin 2 and RX to pin 3 of Arduino

Add the following define to assign a hardware serial port to "nextion":

#define nextion Serial1

Then I tried to change in my code
from

#include "VoiceRecognitionV3.h"
VR myVR(15, 14);

to

#include "VoiceRecognitionV3.h"
#define myVR Serial3

That makes a little more sense, but I'm still getting error, maybe the error in is library.

So, I do have to remove this part of CPP file

Not remove; modify.

VR::VR()
{
	instance = this;
	Serial3.begin(38400);
}

Notice that the constructor now takes no arguments.

PaulS:
Not remove; modify.

VR::VR()

{
instance = this;
Serial3.begin(38400);
}




Notice that the constructor now takes no arguments.

Ok, I changed to

VR::VR()
{
 instance = this;
 Serial3.begin(38400);
}

I was taking a look in this part of code

#define DEBUG

#ifdef DEBUG
#define DBGSTR(message)     Serial3.print(message)
#define DBGBUF(buf, len)	Serial3.write(buf, len)
#define DBGLN(message)		Serial3.println(message)
#define DBGFMT(msg, fmt)	Serial3.print(msg, fmt)
#define DBGCHAR(c)			Serial3.write(c)
#else
#define DBG(message)
#endif // DEBUG

I don't need to change to Serial3, because that's a debug message, if I print in my VR3 module, I won't see what's going on, right? Changed it back to Serial.*

I was looking again in .h file, I saw this

class VR : public HardwareSerial{
public:
	VR(uint8_t receivePin, uint8_t transmitPin);
	
	static VR* getInstance() {
	   return instance;
	}
VR(uint8_t receivePin, uint8_t transmitPin);

I think I can remove this line above because I'm using "#define myVR Serial3" in my code, right?

Do you know any good document to understand Arduino Libraries? Thanks, Heitor.

I think what you’re trying to do might not work. As defined, the VR class inherits from the SoftwareSerial class. You’ve changed it to inherit from the HardwareSerial class. But, you want to do the I/O for your instance of VR using a different instance of HardwareSerial (i.e. Serial3). I’m still in the process of “upgrading” from C to C++, but I’m not sure you can do that.

If it were my project (and I wanted to invest the time), I’d rewrite the VR class to NOT inherit from any class. Then provide it with a begin() function where you pass in a pointer to a Stream object. Change all calls to read() and write() in the VoiceRecognitionV3.cpp file into calls to the read() and write() methods of this object (via the pointer).

Doing this would make the library much more generic. You would instantiate and initialize any kind of Stream object that you want (HardwareSerial, SoftwareSerial, etc) in you .ino file’s setup() function. Then pass the pointer to the VR object using the begin() function.

gfvalvo:
I think what you’re trying to do might not work. As defined, the VR class inherits from the SoftwareSerial class. You’ve changed it to inherit from the HardwareSerial class. But, you want to do the I/O for your instance of VR using a different instance of HardwareSerial (i.e. Serial3). I’m still in the process of “upgrading” from C to C++, but I’m not sure you can do that.

If it were my project (and I wanted to invest the time), I’d rewrite the VR class to NOT inherit from any class. Then provide it with a begin() function where you pass in a pointer to a Stream object. Change all calls to read() and write() in the VoiceRecognitionV3.cpp file into calls to the read() and write() methods of this object (via the pointer).

Doing this would make the library much more generic. You would instantiate and initialize any kind of Stream object that you want (HardwareSerial, SoftwareSerial, etc) in you .ino file’s setup() function. Then pass the pointer to the VR object using the begin() function.

That's very complex, I've no knowlodge in C++, I'll forget this project of transforming this library and start using Serial3.print and Serial3.write, I think that'll be easier...

Thanks for your attention gfvalvo and Paul.

gfvalvo:
I think what you’re trying to do might not work. As defined, the VR class inherits from the SoftwareSerial class. You’ve changed it to inherit from the HardwareSerial class. But, you want to do the I/O for your instance of VR using a different instance of HardwareSerial (i.e. Serial3). I’m still in the process of “upgrading” from C to C++, but I’m not sure you can do that.

If it were my project (and I wanted to invest the time), I’d rewrite the VR class to NOT inherit from any class. Then provide it with a begin() function where you pass in a pointer to a Stream object. Change all calls to read() and write() in the VoiceRecognitionV3.cpp file into calls to the read() and write() methods of this object (via the pointer).

Doing this would make the library much more generic. You would instantiate and initialize any kind of Stream object that you want (HardwareSerial, SoftwareSerial, etc) in you .ino file’s setup() function. Then pass the pointer to the VR object using the begin() function.

I probably would want to make it use a Print sub-Class. That would make it easy

J-M-L:
I probably would want to make it use a Print sub-Class. That would make it easy

The library needs to read() and write() -- aka Stream.

Here’s what I would try. I’ve noted the additions / changes in the library’s .h and .cpp files. Also showed how to change one of the functions in the .cpp file. But, I only included enough of the original file so this would compile. The omitted parts would need to go back in.

.ino file:

#include "VR.h"

VR myVR;

void setup() {
	Serial.begin(115200);   // For debug messages, etc.
	Serial3.begin(9600);    // Interface with VR module
	myVR.begin(&Serial3);
}

void loop() {
}

.h file:

#ifndef VR_H_
#define VR_H_

#include <Arduino.h>
#define FRAME_HEAD							(0xAA)
#define FRAME_END							(0x0A)

class VR {                       // <------- Changed
private:
	static VR *instance;
	Stream *ioStream;            // <------- NEW

public:
	VR();
	void begin(Stream *);        // <------- NEW
	void send_pkt(uint8_t *buf, uint8_t len);
};

#endif /* VR_H_ */

.cpp file:

#include "VR.h"

VR * VR::instance;

VR::VR() {
	instance = this;
	ioStream = nullptr;         // <------- NEW
}

void VR::begin(Stream *s) {     // <------- NEW
	ioStream = s;               // <------- NEW
}

void VR::send_pkt(uint8_t *buf, uint8_t len) {
	while (ioStream->available()) {                // <------ added "ioStream->"
		ioStream->read(); // replace flush();        // <------ added "ioStream->"
	}
	ioStream->write(FRAME_HEAD);                   // <------ added "ioStream->"
	ioStream->write(len + 1);                      // <------ added "ioStream->"
	ioStream->write(buf, len);                     // <------ added "ioStream->"
	ioStream->write(FRAME_END);                    // <------ added "ioStream->"
}

The library needs to read() and write() -- aka Stream.

Ah in that case yes. I had seen only mentions of print above (don’t hqve that module)

gfvalvo:
The library needs to read() and write() -- aka Stream.

Here’s what I would try. I’ve noted the additions / changes in the library’s .h and .cpp files. Also showed how to change one of the functions in the .cpp file. But, I only included enough of the original file so this would compile. The omitted parts would need to go back in.

.ino file:

#include "VR.h"

VR myVR;

void setup() {
Serial.begin(115200);  // For debug messages, etc.
Serial3.begin(9600);    // Interface with VR module
myVR.begin(&Serial3);
}

void loop() {
}




.h file:


#ifndef VR_H_
#define VR_H_

#include <Arduino.h>
#define FRAME_HEAD (0xAA)
#define FRAME_END (0x0A)

class VR {                      // <------- Changed
private:
static VR *instance;
Stream *ioStream;            // <------- NEW

public:
VR();
void begin(Stream *);        // <------- NEW
void send_pkt(uint8_t *buf, uint8_t len);
};

#endif /* VR_H_ */




.cpp file:


#include "VR.h"

VR * VR::instance;

VR::VR() {
instance = this;
ioStream = nullptr;        // <------- NEW
}

void VR::begin(Stream *s) {    // <------- NEW
ioStream = s;              // <------- NEW
}

void VR::send_pkt(uint8_t *buf, uint8_t len) {
while (ioStream->available()) {                // <------ added "ioStream->"
ioStream->read(); // replace flush();        // <------ added "ioStream->"
}
ioStream->write(FRAME_HEAD);                  // <------ added "ioStream->"
ioStream->write(len + 1);                      // <------ added "ioStream->"
ioStream->write(buf, len);                    // <------ added "ioStream->"
ioStream->write(FRAME_END);                    // <------ added "ioStream->"
}

A question, in this example that you showed to me, I can use "myVR.send_pkt(buf,len)"... What are the inputs in "buf" and "len" int? I always get confuse in this situation...

I mean, if I want to send this command (only an example)

0A 01 03 04 FF

That means my "len" (what I believe is lenght) is equal 10? And my "buf"?

The changes I proposed don't in any way effect the way you use the functions provided by the library. So, you'd call send_pkt() in the same manner and with the same arguments as previously. The example sketches that come with the library would probably provide the best guidance as I've never used this library.

gfvalvo:
The changes I proposed don't in any way effect the way you use the functions provided by the library. So, you'd call send_pkt() in the same manner and with the same arguments as previously. The example sketches that come with the library would probably provide the best guidance as I've never used this library.

I wasn't using this command, I just wanna know how do it works...

Another question, there're some other lines in original library like

typedef enum{
 LEVEL0 = 0,
 LEVEL1,
 LEVEL2, 
 LEVEL3,
 LEVEL4,
 LEVEL5,
 LEVEL6,
 LEVEL7,
 LEVEL8,
 LEVEL9,
 LEVEL10,
 LEVEL11,
 LEVEL12,
 LEVEL13,
 LEVEL14,
 LEVEL15,
 }pulse_width_level_t;
 
 typedef enum{
 GROUP0 = 0,
 GROUP1,
 GROUP2,
 GROUP3,
 GROUP4,
 GROUP5,
 GROUP6,
 GROUP7,
 GROUP_ALL = 0xFF,
 }group_t;
 
 int setBaudRate(unsigned long br);
 int setIOMode(io_mode_t mode);
 int resetIO(uint8_t *ios=0, uint8_t len=1);
 int setPulseWidth(uint8_t level);

Why did you removed them? They aren't necessary?

Hbadotti:
I wasn't using this command, I just wanna know how do it works...

As I said, the library's examples are probably the best resource.

Hbadotti:
Another question, there're some other lines in original library like
.
.
Why did you removed them? They aren't necessary?

There's LOTS of stuff I omitted. I was only providing guidance and an example of the kind of changes that need to be made. To that end, I provided a complete example the successfully compiles. I'm not going spend the time to update the whole library. Propagating those examples into the complete library is up to you. As I said:

gfvalvo:
But, I only included enough of the original file so this would compile. The omitted parts would need to go back in.

gfvalvo:
As I said, the library's examples are probably the best resource.

Their examples doesn't explores all the functions...

gfvalvo:
There's LOTS of stuff I omitted. I was only providing guidance and an example of the kind of changes that need to be made. To that end, I provided a complete example the successfully compiles. I'm not going spend the time to update the whole library. Propagating those examples into the complete library is up to you. As I said:

Gotcha! Thanks a lot mate, for the help... Heitor.