I had a brain wave, the solution is nice, however it won't work with code in the cpp. It is compiled before it sees your sketch so LiquidCrystal has to be defined to be usable.
What I had was a dummy class to add in the missing functions of the LCD class:
struct MissingType{
void setCursor( int a, int b ){}
template< typename T > size_t print( const T &t ){}
template< typename T > size_t println( const T &t ){}
template< typename T, typename U > size_t print( const T &t, const U &u ){}
template< typename T, typename U > size_t println( const T &t, const U &u ){}
};
#ifdef LiquidCrystal_I2C_h
typedef LiquidCrystal_I2C LCDTYPE;
#else
typedef MissingType LCDTYPE;
#endif
To make your library dependent on the sketch ( compiled later ) you need a template, which you've already got. So simply copy the cpp file onto the end of your .h and it works fine.
After I did this, my solution above works fine. Most importantly, you do not need the LiquidCrystal_I2C library included now!
Without the LCDTYPE fix above, you will receive errors on things like IsSameType< T, LiquidCrystal_I2C >::Value
Also as you get errors from missing functions, simply add a dummy one into the MissingType struct. These functions aren't used, they simply stop the compiler from spitting out x undefined errors. You can see this is true as the functions do not return a value, which is an error if the code was used, they don't really need the {} either.
Here is the .h ( no .cpp now ).
#ifndef OnewireKeypad_h
#define OnewireKeypad_h
#include <Arduino.h>
#define NO_KEY '\0'
#define WAITING 0
#define PRESSED 1
#define RELEASED 2
#define HELD 3
template < typename T, typename U > struct IsSameType{ enum { Value = false }; };
template < typename T > struct IsSameType< T, T > { enum { Value = true }; };
#define MAX_KEYS 16
template< typename T >
class OnewireKeyPad {
public:
OnewireKeyPad( T &port ) : port_( port ) {port_.println("asd");}
void Init(char KP[], uint8_t Rows, uint8_t Cols, uint8_t Pin);
char Getkey();
void Calc(double R1, double R2, double voltage);
void SetHoldTime(unsigned long setH_Time);
void SetDebounceTime(unsigned long setD_Time);
uint8_t Key_State();
bool Readpin();
void LatchKP();
bool checkLatchedKey(char _key);
protected:
virtual void SetCursor( int, int ) { /*Do nothing for unknown types*/ }
T &port_;
private:
double values[MAX_KEYS];
bool latchedKey[MAX_KEYS];
char _Data[MAX_KEYS];
char Out[20];
uint8_t _Rows, _Cols, _Pin;
char lastKey;
};
struct MissingType{
void setCursor( int a, int b ){}
template< typename T > size_t print( const T &t ){}
template< typename T > size_t println( const T &t ){}
template< typename T, typename U > size_t print( const T &t, const U &u ){}
template< typename T, typename U > size_t println( const T &t, const U &u ){}
};
#ifdef LiquidCrystal_I2C_h
typedef LiquidCrystal_I2C LCDTYPE;
#else
typedef MissingType LCDTYPE;
#endif
template < typename T >
class Display : public OnewireKeyPad< T >{
public:
Display(T & port) : OnewireKeyPad< T >( port ){}
};
template< >
class Display < LCDTYPE > : public OnewireKeyPad< LCDTYPE >{
public:
using OnewireKeyPad< LCDTYPE >::port_;
void SetCursor( int a, int b ) { port_.setCursor( a, b ); }
Display( LCDTYPE & lcd ) : OnewireKeyPad< LCDTYPE >( lcd ) {}
};
uint8_t SIZE = 16;
unsigned long time = 0,holdTime, startTime, debounceTime;
bool state, lastState = 0, lastRead = 0;
template< typename T >
void OnewireKeyPad< T > :: Init(char KP[], uint8_t Rows, uint8_t Cols, uint8_t Pin)
{
_Rows = Rows;
_Cols = Cols;
_Pin = Pin;
startTime = 0;
SetDebounceTime(10);
SetHoldTime(500);
SIZE = (_Rows * _Cols);
for(byte lidx = 0; lidx < SIZE; lidx++)
{
_Data[lidx] = KP[lidx];
latchedKey[lidx] = 0;
}
}
template< typename T >
char OnewireKeyPad< T > :: Getkey()
{
int Reading = analogRead(_Pin);
if(millis() - startTime > debounceTime)
{
for(byte i = 0; i < SIZE; i++)
{
if(Reading && Reading <= int(values[(SIZE-1)-i]) + 1.9)
return _Data[(SIZE-1)-i];
}
startTime = millis();
}
return NO_KEY;
}
template< typename T>
void OnewireKeyPad< T > :: Calc(double R1, double R2, double voltage)
{
uint8_t i = 0;
for(double R = 0; R < _Rows; R++)
{
for(double C = 0; C < _Cols; C++)
{
double V = (voltage * R2)/(R2+ (R1*R) + (R2*C));
values[i] = V * (1023 / voltage); //204.6 = 5V, 310 = 3V
SetCursor(0, R);
port_.print(int(values[i]));
port_.print(", ");
i++;
}
if( IsSameType< T, LCDTYPE >::Value == 0 )
port_.println( "HI" );
}
}
template< typename T >
void OnewireKeyPad< T > :: SetHoldTime(unsigned long setH_Time)
{
holdTime = setH_Time;
}
template< typename T >
void OnewireKeyPad< T > :: SetDebounceTime(unsigned long setD_Time)
{
debounceTime = setD_Time;
}
template< typename T >
uint8_t OnewireKeyPad< T > :: Key_State()
{
if((state = Readpin()) != lastState)
{
lastState = state;
return (Readpin()? PRESSED : RELEASED);
}
//else KP_Hold(500);
else if(Readpin()){
time = millis();
while(Readpin())
{
if((millis() - time) > holdTime)
{
return HELD;
}
}
lastState = 0;
return RELEASED;
}
return WAITING;
}
template< typename T >
bool OnewireKeyPad< T > :: Readpin()
{
return analogRead(_Pin)? 1 : 0;
}
template< typename T >
void OnewireKeyPad<T> :: LatchKP()
{
char output[20];
bool PRINT = false;
char _key = Getkey();
bool read = _key? 1: 0;
if(read != lastRead)
{
if(read)
{
for(int idx = 0; idx < SIZE; idx++)
{
if(_key == _Data[idx])
{
latchedKey[idx] = !latchedKey[idx];
//Serial.println(latchedKey[idx]);
if(latchedKey[idx])
{
sprintf(output, "Key %c was Latched",_key);
PRINT = true;
}
else
{
sprintf(output, "Key %c was Unlatched",_key);
PRINT = true;
}
}
}
}
lastRead = read;
if(PRINT)
port_.println(output);
}
}
template< typename T >
bool OnewireKeyPad< T > :: checkLatchedKey(char _key)
{
for(int idx = 0; idx < SIZE; idx++)
{
if(_key == _Data[idx])
return latchedKey[idx];
}
return false;
}
#endif
EDIT: also you will need to do something with the global vars that are now in the .h.
Wrap them in a struct and make them static or mark them extern and define them in a cpp file.
They are fine now, but when you include your lib into multiple locations, problems may occur.
My copy+ replace borked, if you copied my code already change:
#ifdef LCDTYPE_h
To:
#ifdef LiquidCrystal_I2C_h
fixed above now.