I managed to compile a library in this thread. I then modified that code to use a . a virtual function which is, b . called by derived classes (shown below) - to avoid the complications with the 'type' parameter from the original. For the sake of clarity the derived classes are presently omitted .
/*
Basic timer converted to polymorphic/inherited form.
Utilizes virtual function to effect timer reset.
reference Arduino.cc thread http://forum.arduino.cc/index.php?topic=567010.new#new
*/
// debounce disabled for users without the library
//#include <Bounce2.h>
#define BUTTON_PIN 6 // to enable the timer DIO6
#define RESET_PIN 8 // to reset a timer DIO8
#define externalLED1 7 // +5--/\/\/-->|--DIO7
byte LED_PIN = 13; // on board LED
// Instantiate a Bounce object
//Bounce debouncer = Bounce();
// create a class called 'PLCtimer'
class PLCtimer {
/*
This is the base class - All types:
> produce a positive-going one-scan pulse 'os' upon reaching
preset value.
> respond to a reset command by setting accumulated value to
zero and resetting done and tt.
> set the done bit upon reaching preset.
*/
public:
unsigned long _Accumulator = 0;
bool _Reset: 1;
bool _Enable: 1;
bool _Done: 1;
bool _OSRise: 1;
bool _Control: 1;
private:
unsigned long _Preset;
unsigned long _CurrentMillis;
unsigned long _LastMillis = 0;
bool _TimerRunning: 1;
bool _OSFall: 1;
bool _OSRSetup: 1;
bool _OSFSetup: 1;
public:
// constructor - permits setting of variables upon instantiation
// Timers are instantiated with enable false by default
PLCtimer::PLCtimer(unsigned long pre, boolean en = 0)
{
_Preset = pre;
negativePresetWarning(pre); // preset validation
}; // end constructor
/*
User-added error handler from pert @ Arduino.cc, post #13
thread http://forum.arduino.cc/index.php?topic=559655.new#new
Timers may not have a negative preset value.
*/
void negativeError( void ) __attribute__((error("Negative PLCtimer preset! Check instantiations!")));
void negativePresetWarning(unsigned long number) {
if (number < 0) {
negativeError();
}
}
/*
===== Access functions for timer status/controls
*/
// Allows to start/stop a timer
void setEN(bool en) {
_Enable = en;
}
// Allows to reset a timer
void setres(bool res) {
_Reset = res;
}
// Returns enable state of timer
byte getEN() {
return _Enable;
}
// Returns reset state of timer
bool getres() {
return _Reset;
}
// Returns done status of timer
bool getDn() {
return _Done;
}
// Returns timer timing state of timer
bool getTt() {
return _TimerRunning;
}
// Returns timer timing state of timer
bool getIntv() {
return _TimerRunning;
}
// Returns state of timer done rising one-shot
bool getOSRise() {
return _OSRise;
}
// Returns state of timer done falling one-shot
bool getOSFall() {
return _OSFall;
}
private:
/*
Virtual timer Reset function
Reset conditions to be determined by descendants
*/
virtual bool Reset();
public:
// Function to operate timers created under PLCtimer
// ----------------------------------------
// Update timer accumulated value & condition
// flags 'tt' (timer timing) and 'dn' (done) based
// on timer type.
// Function returns boolean status of done, 'dn'
// ===========================
boolean update() {
_CurrentMillis = millis(); // Get system clock ticks
if (_Enable or _Control) { // timer is enabled to run
_Accumulator = _Accumulator + _CurrentMillis - _LastMillis;
if (_Accumulator >= _Preset) { // timer done?
_Accumulator = _Preset; // Don't let accumulator run away
_Done = true;
}
}
_LastMillis = _CurrentMillis;
// 9/25/18 - Modified the virtual function Reset() to return
// a boolean. The derived classes now only return a yes/no
// to the base class to handle resetting of done and clearing
// of accumulator.
// This saves 50+ bytes versus resetting in the derived classes.
if ( Reset()) { // Find out if reset needed based on derived class' criteria.
_Done = false;
_Accumulator = 0;
}
/*
----- Generate a positive going one-shot pulse on timer done f-t transition
*/
_OSRise = (_Done and _OSRSetup);
_OSRSetup = !_Done;
/*
----- and another positive going one-shot pulse on timer done t-f transition
*/
_OSFall = (!_Done and _OSFSetup);
_OSFSetup = _Done;
/*
----- condition the timer timing status
*/
if ((_Enable or _Control) and !_Done and !_Reset) {
_TimerRunning = true;
}
else _TimerRunning = false;
return _Done;
}; // end of base class update Timer operation
} ; // end of class PLCtimer
void setup() {
}
void loop() {
} //end of loop
This does compile and I’m now trying to produce a library from this new code. I have used the working library files from the other thread as a guide to producing the current one. I am now getting this error:
mkdir C:\Users\Owner\AppData\Local\Temp\arduino_build_132568\sketch: Access is denied.
Error compiling for board Arduino/Genuino Uno.
No other Arduino sketches give this error so I’ve bollixed something up but don’t have a clue - no lines are highlighted to indicate the error. My idea was to get the base class to compile then incrementally add the derived classes. The three files .ino, .cpp, .h are in separate tabs, attached below. I put in what looks right but, I don’t know.
I’m asking for some direction to find the cause of this error.
OK, after restarting the IDE a new list of real errors appeared – these are resolved and the code compiled until I added the implementation for the first of the derived classes.
Multi_Timer.cpp:94: error: expected unqualified-id before ')' token
OnDelay_tmr()::Multi_timer() {
^
Multi_Timer.cpp:97: error: expected unqualified-id before ')' token
OnDelay_tmr() {
^
exit status 1
expected unqualified-id before ')' token
#include "Multi_Timer.h"
#define BUTTON_PIN 6 // to enable the timer DIO6
#define RESET_PIN 8 // to reset a timer DIO8
#define externalLED1 7 // +5--/\/\/-->|--DIO7
byte LED_PIN = 13; // on board LED
//Multi_timer wdt_01(1000UL);
void setup() {
}
void loop() {
}
.cpp file
#include "Multi_Timer.h"
#include "Arduino.h"
Multi_timer::Multi_timer(unsigned long pre)
{
_Preset = pre;
negativePresetWarning(pre); // preset validation
}; // end constructor
// ===== Access functions for timer status/controls
void Multi_timer::setEN(bool en) {
_Enable = en;
}
void Multi_timer::setres(bool res) {
_Reset = res;
}
byte Multi_timer::getEN() {
return _Enable;
}
bool Multi_timer::getres() {
return _Reset;
}
bool Multi_timer::getDn() {
return _Done;
}
bool Multi_timer::getTt() {
return _TimerRunning;
}
bool Multi_timer::getIntv() {
return _TimerRunning;
}
bool Multi_timer::getOSRise() {
return _OSRise;
}
bool Multi_timer::getOSFall() {
return _OSFall;
}
bool Multi_timer::Reset();
boolean Multi_timer::update() {
_CurrentMillis = millis(); // Get system clock ticks
if (_Enable or _Control) { // timer is enabled to run
_Accumulator = _Accumulator + _CurrentMillis - _LastMillis;
if (_Accumulator >= _Preset) { // timer done?
_Accumulator = _Preset; // Don't let accumulator run away
_Done = true;
}
}
_LastMillis = _CurrentMillis;
// if ( Multi_timer::Reset()) { // Find out if reset needed based on derived class' criteria.
// _Done = false;
// _Accumulator = 0;
// }
_OSRise = (_Done and _OSRSetup);
_OSRSetup = !_Done;
_OSFall = (!_Done and _OSFSetup);
_OSFSetup = _Done;
if ((_Enable or _Control) and !_Done and !_Reset) {
_TimerRunning = true;
}
else _TimerRunning = false;
return _Done;
/*
unsigned long _Accumulator = 0;
bool _Reset = false;
bool _Enable = false;
bool _Done = false;
bool _OSRise = false;
bool _Control = false;
unsigned long _Preset;
unsigned long _CurrentMillis;
unsigned long _LastMillis = 0;
bool _TimerRunning = false;
bool _OSFall = false;
bool _OSRSetup = false;
bool _OSFSetup = false;
*/
}
OnDelay_tmr()::Multi_timer() {
}
OnDelay_tmr() {
Reset() {
return (_Reset or !_Enable);
}
}
.h file
#ifndef MULTI_TIMER_H
#define MULTI_TIMER_H
#include "Arduino.h"
class Multi_timer {
public:
Multi_timer(unsigned long);
void setEN(bool);
void setres(bool);
byte getEN();
bool getres();
bool getDn();
bool getTt();
bool getIntv();
bool getOSRise();
bool getOSFall();
protected:
virtual bool Reset();
public:
// Function to operate timers created under Multi_timer
boolean update();
private:
void negativeError( void ) __attribute__((error("Negative Multi_timer preset! Check instantiations!")));
void negativePresetWarning(unsigned long number) {
if (number < 0) {
negativeError();
}
}
public:
unsigned long _Accumulator;
bool _Reset: 1;
bool _Enable: 1;
bool _Done: 1;
bool _OSRise: 1;
bool _Control: 1;
private:
unsigned long _Preset;
unsigned long _CurrentMillis;
unsigned long _LastMillis;
bool _TimerRunning: 1;
bool _OSFall: 1;
bool _OSRSetup: 1;
bool _OSFSetup: 1;
}; //end of base class Multi_timer declarations
class OnDelay_tmr: public Multi_timer
{
public:
bool Reset();
}; // End of class OnDelay_tmr
#endif
What exactly is “expected unqualified-id before ')' token“ telling me? I removed nearly all the comments in the attached code to get under the 9K limit.
Already is all the inheritance. If you make an object of OnDelay_tmr it has all the functions of Multi_timer including the basic constructor. If you want to also call the Multi_timer(unsigned long) constructor when you construct the OnDelay_tmr you need to tell it just that:
OnDelay_tmr::OnDelay_tmr(unsigned long x) : Multi_timer(x){
}
PS Very weird to use Multi_Timer but OnDelay_tmr...
PPS I think it's even neater to give each class it's on files.
septillion:
PPS I think it's even neater to give each class it's on files.
That had not occurred to me. I got on this virtual function track and got stuck. After no real progress in a week my frustration level is such that I am ready to look at other means.
My understanding then is that there could be one folder, say 'timer.x', which would in turn contain the .h/.cpp files for each flavor of timer. The main file has an #include "timer.h" and then one or more instantiations of the form
In Timer.h you include al real classed (here TimerSomething.h and TimerSomethingElse.h) which will contain equally named classed.
And in each instance you include the base class.
BUT, I would not go for the name Timer for the library. It's so damn common it's very easy to come across a similar named library and break it... So 'DougpTimer' or 'WickedTimer' or something.
septillion:
That's possible. This this would make the most sense, especially if you only want to use the TimerBaseClass as prototype.
In Timer.h you include al real classed (here TimerSomething.h and TimerSomethingElse.h) which will contain equally named classed.
And in each instance you include the base class.
I'm unclear on this. My thought was to make the folder and place in it only complete, standalone .h/.cpp files for each variant - no base class or other files involved. If prototypes are still in use doesn't that imply inheritance/polymorphism?
septillion:
BUT, I would not go for the name Timer for the library. It's so damn common it's very easy to come across a similar named library and break it... So 'DougpTimer' or 'WickedTimer' or something.
No, 'timer' is just for this conversation. Final name will be more unique/descriptive.
Still stuck. Back to the virtual Reset function. The separate files is not a rabbit hole I want to go down – I’m in three levels already from where I started. I have modified the code and tried to make it look like Savitch’s - see post #4 - example ( he shows .h/.cpp files for base and derived classes ) but I’m getting these errors:
Multi_Timer.cpp:80: error: definition of implicitly-declared 'OnDelay_tmr::OnDelay_tmr()'
OnDelay_tmr::OnDelay_tmr(): Multi_timer(pre)
^
C:\Users\Owner\AppData\Local\Temp\arduino_build_456117\sketch\Multi_Timer.cpp: In function 'int Reset()':
Multi_Timer.cpp:85: error: '_Reset' was not declared in this scope
return (_Reset or !_Enable);
^
Multi_Timer.cpp:85: error: '_Enable' was not declared in this scope
return (_Reset or !_Enable);
^
exit status 1
definition of implicitly-declared 'OnDelay_tmr::OnDelay_tmr()'
I appreciate @septillion’s aid but the responses are too cryptic for this ossified brain.
This line, the constructor: OnDelay_tmr::OnDelay_tmr(): Multi_timer(pre) is structured like in the book yet it gives an error. Bafflement.
main file:
#include "Multi_Timer.h"
#define BUTTON_PIN 6 // to enable the timer DIO6
#define RESET_PIN 8 // to reset a timer DIO8
#define externalLED1 7 // +5--/\/\/-->|--DIO7
byte LED_PIN = 13; // on board LED
Multi_timer wdt_01(1000UL);
void setup() {
}
void loop() {
}
.cpp file
#include "Multi_Timer.h"
#include "Arduino.h"
Multi_timer::Multi_timer(unsigned long pre)
{
_Preset = pre;
negativePresetWarning(pre); // preset validation
}; // end constructor
// ===== Access functions for timer status/controls
void Multi_timer::setEN(bool en) {
_Enable = en;
}
void Multi_timer::setres(bool res) {
_Reset = res;
}
byte Multi_timer::getEN() {
return _Enable;
}
bool Multi_timer::getres() {
return _Reset;
}
bool Multi_timer::getDn() {
return _Done;
}
bool Multi_timer::getTt() {
return _TimerRunning;
}
bool Multi_timer::getIntv() {
return _TimerRunning;
}
bool Multi_timer::getOSRise() {
return _OSRise;
}
bool Multi_timer::getOSFall() {
return _OSFall;
}
bool Multi_timer::Reset();
boolean Multi_timer::update() {
_CurrentMillis = millis(); // Get system clock ticks
if (_Enable or _Control) { // timer is enabled to run
_Accumulator = _Accumulator + _CurrentMillis - _LastMillis;
if (_Accumulator >= _Preset) { // timer done?
_Accumulator = _Preset; // Don't let accumulator run away
_Done = true;
}
}
_LastMillis = _CurrentMillis;
if ( Multi_timer::Reset()) { // Find out if reset needed based on derived class' criteria.
_Done = false;
_Accumulator = 0;
}
_OSRise = (_Done and _OSRSetup);
_OSRSetup = !_Done;
_OSFall = (!_Done and _OSFSetup);
_OSFSetup = _Done;
if ((_Enable or _Control) and !_Done and !_Reset) {
_TimerRunning = true;
}
else _TimerRunning = false;
return _Done;
}// end update
OnDelay_tmr::OnDelay_tmr(): Multi_timer(pre)
{
}
Reset() {
return (_Reset or !_Enable);
}
.h file
#ifndef MULTI_TIMER_H
#define MULTI_TIMER_H
#include "Arduino.h"
class Multi_timer {
public:
Multi_timer(unsigned long pre);
void setEN(bool);
void setres(bool);
byte getEN();
bool getres();
bool getDn();
bool getTt();
bool getIntv();
bool getOSRise();
bool getOSFall();
protected:
virtual bool Reset();
public:
// Function to operate timers created under Multi_timer
boolean update();
private:
void negativeError( void ) __attribute__((error("Negative Multi_timer preset! Check instantiations!")));
void negativePresetWarning(unsigned long number) {
if (number < 0) {
negativeError();
}
}
public:
unsigned long _Accumulator;
bool _Reset: 1;
bool _Enable: 1;
bool _Done: 1;
bool _OSRise: 1;
bool _Control: 1;
private:
unsigned long _Preset;
unsigned long _CurrentMillis;
unsigned long _LastMillis;
bool _TimerRunning: 1;
bool _OSFall: 1;
bool _OSRSetup: 1;
bool _OSFSetup: 1;
}; //end of base class Multi_timer declarations
class OnDelay_tmr: public Multi_timer
{
public:
bool Reset();
}; // End of class OnDelay_tmr
#endif
The three files are together on separate IDE tabs. Board = UNO
Why did you add "Multi_timer::" all of a sudden? Just smashing the keyboard like a mad monkey isn't going to help...
Multi_timer has one constructor: Multi_timer::Multi_timer(unsigned long pre) aka one that expects an unsigned long. But it's a CALL to that method so just pass a variable, don't try to declare it. The that value needs to come from somewhere. I think it would be logical to make it a parameter of the OnDelay_tmr constructor:
OnDelay_tmr::OnDelay_tmr(unsigned long p): Multi_timer(p)
It's the declaration of the OnDelay constructor which expects an unsinged long which causes the constructor of Multi_timer() to be called with that same (previous declared) parameter.