As I have posted somewhere in this forum, I've been working on a new Modbus library. Indeed I've posted this same topic in somewhere else, but I'm afraid that it was the wrong place.
The fact is that my new Modbus library needs to append the HardwareSerial call inside it. At this moment, it is just outside the class declaration:
HardwareSerial port = Serial; ///< Pointer to Serial class object
/* _____CLASS DEFINITIONS____________________________________________________ */
/**
* Arduino class library for communicating with Modbus devices over
* RS232/485 (via RTU protocol).
*/
class Modbus {
private:
uint8_t u8id; // 0=master, 1..247=slave number
uint8_t u8serno; // serial port: 0-Serial, 1..3-Serial1..Serial3
uint8_t u8txenpin; // 0=USB or RS-232 mode, >0=RS-485 mode
uint8_t u8state;
uint8_t au8Buffer[MAX_BUFFER];
uint8_t u8BufferSize;
uint8_t u8lastRec;
uint16_t *au16regs;
uint16_t u16InCnt, u16OutCnt, u16errCnt;
uint16_t u16timeOut;
uint32_t u32time, u32timeOut;
uint8_t u8regsize;
void init(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin);
void sendTxBuffer(); // transmit buffer to serial port
int8_t getRxBuffer(); // get serial buffer contents
uint16_t calcCRC(uint8_t u8length); // get CRC from au8Buffer until u8length
uint8_t validateAnswer();
uint8_t validateRequest(); // validate master request
void get_FC1(); // *** only master ***
void get_FC3(); // *** only master ***
int8_t process_FC1( uint16_t *regs, uint8_t u8size ); // *** only slave ***
int8_t process_FC3( uint16_t *regs, uint8_t u8size ); // *** only slave ***
int8_t process_FC5( uint16_t *regs, uint8_t u8size ); // *** only slave ***
int8_t process_FC6( uint16_t *regs, uint8_t u8size ); // *** only slave ***
int8_t process_FC15( uint16_t *regs, uint8_t u8size ); // *** only slave ***
int8_t process_FC16( uint16_t *regs, uint8_t u8size ); // *** only slave ***
void buildException( uint8_t u8exception ); // build exception message
public:
Modbus();
Modbus(uint8_t u8id, uint8_t u8serno);
Modbus(uint8_t u8id, uint8_t u8serno, uint8_t u8txenpin);
void begin(long u32speed);
void begin();
void setTimeOut( uint16_t u16timeout); // only for master
uint16_t getTimeOut(); // only for master
int8_t query( modbus_t telegram ); // only for master
int8_t poll(); // cyclic poll for master
int8_t poll( uint16_t *regs, uint8_t u8size ); // cyclic poll for slave
uint16_t getInCnt(); // number of incoming messages
uint16_t getOutCnt(); // number of outcoming messages
uint16_t getErrCnt(); // error counter
uint8_t getID();
uint8_t getState();
};
How can I implement HardwareSerial inside my class?
What I need is to declare in the object constructor that this object shall use any Serial (Serial, Serial1 or Serial3). So, all the HardwareSerial methods may refer to it. As it is done, whenever more than one object of this same library is declared, the processor stops working. I'm afraid that this is because all these objects are using the same "port" variable.
To include possible future expansion into software serial, you can use a Stream class pointer, which is the parent class of HardwareSerial class. Syntax is the same as PaulS pointed out. You define this pointer in your class and accept its value via constructor or a separate function.
Here, port IS a pointer. It points to the Serial object.
You then need to use port->, rather than port. to access the member functions.
Thanks for your useful comments!
Anyway, even if port is declared as a pointer to HardwareSerial (or to Streamer), if a project contains more than one object of my Modbus class and both refer to different ports, I cannot predict what shall happen. That's because there is only one "port" pointer.
Is it correct?
Anyway, even if port is declared as a pointer to HardwareSerial (or to Streamer), if a project contains more than one object of my Modbus class and both refer to different ports, I cannot predict what shall happen.
If you can't, you've written the code/class incorrectly.
The port variable should be a member field. It should be valued by a setPort() or begin() type of method.
I dont recommend begin methods inside your class. Demand a port that has begun. If two objects do share one port, you don't want to befin multiple times and even at different rates. A hardware serial port is a resource. It should be used not altered by your class. The caller may assume the port has not been altered after some calls to your class instance. Just my 2 cents.
Demand a port that has begun. If two objects do share one port, you don't want to begin multiple times and even at different rates.
I understand your point of view, but I assume that the application wiring wouldn't change. This means that one port would be used just one. That's why I decided to make the class do all this stuff.
OK! It's understood.
And what do you suggest to implement NewSoftwareSerial or SoftwareSerial there? In your previous topic, you have mentioned Stream class, isn't it?
NewSoftSerial was developed as a replacement for the hideously inefficient SoftwareSerial available with pre-1.0 versions of the IDE. Starting with 1,0, the old SoftwareSerial was dumped, and NewSoftSerial was adopted as its replacement, and renamed to SoftwareSerial.
Unless you need backwards compatibility, and I see no reason why you should, forget about NewSoftSerial.
SoftwareSerial and HardwareSerial are both derived classes. Look at the base class for each one. What do you know. It's the same base class. Use that as the type for port, and users of you class can supply a HardwareSerial instance or a SoftwareSerial instance.