All of your classes are implemented in the wrong way.
In the header you e.g. write
#pragma once
#include <Arduino.h>
#include "arduino/pins/state.h"
#include "util/observe/observable.h"
namespace pin{
class Input{
public:
Input(uint8_t pin, bool useInternalPullup, unsigned int debounce = 0);
state getState();
observe::Observable* asObservable();
void loop();
};
}
Then, you write in the .cpp
file
#include <Arduino.h>
#include "arduino/pins/state.h"
#include "util/observe/observable.h"
namespace pin{
class Input{
public:
Input(unsigned pin, bool useInternalPullup, unsigned int debounce):
pin(pin), debounce(debounce){
pinMode(this->pin, useInternalPullup ? INPUT_PULLUP : INPUT);
this->observable = observe::Observable();
this->informed = false;
}
observe::Observable* asObservable(){
return &(this->observable);
}
state getState(){
if(this->stateIsStable()){
return this->lastState;
}
return state::floating;
}
void loop(){
auto time = millis();
state state = digitalRead(this->pin) == HIGH ? state::high : state::low;
if(state != this->lastState){
this->lastState = state;
this->lastStateChange = time;
this->informed = false;
}
if(!this->informed && this->stateIsStable()){
this->observable.informObservers();
}
}
private:
uint8_t pin;
state lastState;
bool informed;
unsigned long lastStateChange;
unsigned int debounce;
observe::Observable observable;
bool stateIsStable(){
auto time = millis();
if(time < this->lastStateChange){
auto max = 0UL - 1UL;
return ((max - this->lastStateChange) + time) >= this->debounce;
}
return (time - this->lastStateChange) >= this->debounce;
}
};
}
This is wrong because of multiple reasons:
- you’re redeclaring (with the
class
keyword) what was already in the header and implementing the class. You just need to be implementing it.
- Your
.cpp
and .h
declare some functions with different types. E.g., the constructor in the .h
file starts with Input(uint8_t pin
, the .cpp
one is Input(unsigned pin
.
- Your
.h
file does not declare the private methods + fields used in the .cpp file. The .cpp simple declares its own class on the fly, completely detached from the input.h
file (it does also not #include
it)
See include https://www.cplusplus.com/doc/tutorial/classes/ and coding style - Correct way to define C++ namespace methods in .cpp file - Stack Overflow.
The correct form in tje input.h
file would be, in your case would be
#pragma once
#include <Arduino.h>
#include "arduino/pins/state.h"
#include "util/observe/observable.h"
namespace pin{
class Input{
public:
Input(uint8_t pin, bool useInternalPullup, unsigned int debounce = 0);
state getState();
observe::Observable* asObservable();
void loop();
private:
uint8_t pin;
state lastState;
bool informed;
unsigned long lastStateChange;
unsigned int debounce;
observe::Observable observable;
bool stateIsStable();
};
}
and in the input.cpp
file
#include <Arduino.h>
#include "arduino/pins/state.h"
#include "util/observe/observable.h"
#include "arduino/pins/controllers/input.h"
namespace pin
{
Input::Input(uint8_t pin, bool useInternalPullup, unsigned int debounce)
: pin(pin), debounce(debounce)
{
pinMode(this->pin, useInternalPullup ? INPUT_PULLUP : INPUT);
this->observable = observe::Observable();
this->informed = false;
}
observe::Observable *Input::asObservable()
{
return &(this->observable);
}
state Input::getState()
{
if (this->stateIsStable())
{
return this->lastState;
}
return state::floating;
}
void Input::loop()
{
auto time = millis();
state state = digitalRead(this->pin) == HIGH ? state::high : state::low;
if (state != this->lastState)
{
this->lastState = state;
this->lastStateChange = time;
this->informed = false;
}
if (!this->informed && this->stateIsStable())
{
this->observable.informObservers();
}
}
bool Input::stateIsStable()
{
auto time = millis();
if (time < this->lastStateChange)
{
auto max = 0UL - 1UL;
return ((max - this->lastStateChange) + time) >= this->debounce;
}
return (time - this->lastStateChange) >= this->debounce;
}
};
Now the recompiled firmware throws the error
Linking .pio\build\megaatmega2560\firmware.elf
C:\Users\Max\AppData\Local\Temp\cc8z5Ry3.ltrans0.ltrans.o: In function `main':
<artificial>:(.text.startup+0x4e): undefined reference to `pin::OutputTrigger::OutputTrigger(unsigned char, pin::state, unsigned long)'
<artificial>:(.text.startup+0x68): undefined reference to `kvm::Switch::Switch(pin::Input*, pin::Input*, pin::OutputTrigger*)'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\megaatmega2560\firmware.elf] Error 1
notice how the previous errors regarding the Input
class
<artificial>:(.text.startup+0x1c): undefined reference to `pin::Input::Input(unsigned char, bool, unsigned int)'
<artificial>:(.text.startup+0x2c): undefined reference to `pin::Input::Input(unsigned char, bool, unsigned int)'
are gone.
Repeat this for every one of your mis-written cpp / h files and the firmware shall compile.