enum {UNDEF, BOOL, I8, I16, I32, U8, U16, U32, FLOAT, CSTRING};
template<typename T> struct type_id
{
    static uint16_t id() { return UNDEF; }
    static size_t size() { return -1; }
};

template<> struct type_id<bool> { 
  static uint16_t id() { return BOOL; } 
  static size_t size() { return 1; }
};
template<> struct type_id<int8_t> { 
  static uint16_t id() { return I8; }
  static size_t size() { return 1; }
};
template<> struct type_id<int16_t> { 
  static uint16_t id() { return I16; } 
  static size_t size() { return 2; }

};
template<> struct type_id<int32_t> { 
  static uint16_t id() { return I32; } 
  static size_t size() { return 4; }
};
template<> struct type_id<uint8_t> { 
  static uint16_t id() { return U8; } 
  static size_t size() { return 1; }
};
template<> struct type_id<uint16_t> { 
  static uint16_t id() { return U16; } 
  static size_t size() { return 2; }
};
template<> struct type_id<uint32_t> { 
  static uint16_t id() { return U32; } 
  static size_t size() { return 4; }
};
template<> struct type_id<float> { 
  static uint16_t id() {return FLOAT;} 
  static size_t size() { return 4; }
};
template<> struct type_id<char*> { 
  static uint16_t id() { return CSTRING; } 
  static size_t size() { return 2; }
};
//template<> struct type_id<String> {static int id() {return STRING;} };

#define type_id_v(x)  type_id<decltype(x)>::id()
#define type_size_v(x)  type_id<decltype(x)>::size()

auto xVar = 25.5F;
bool bVar = true;
int8_t i8Var = -8;
int iVar = 100;
int32_t i32Var = -32;
uint32_t lVar = millis();
char* strVar = "Hellp world";

int t = type_id_v(bVar);

float uni_val = 0;
typedef struct Range Range;

class UniVal {
  public:
  UniVal() : type(UNDEF) { }
  void set(bool v)    { uni = v; type = BOOL; }
  void set(int8_t v)  { uni = v; type = I8; }
  void set(int16_t v) { uni = v; type = I16; }
  void set(int32_t v) { uni = v; type = I32; }
  void set(uint8_t v)   { uni = v; type = U8; }
  void set(uint16_t v)  { uni = v; type = U16; }
  void set(uint32_t v)  { uni = v; type = U32; }
  void set(float v)     { uni = v; type = FLOAT; }
  void get(bool *p) { *p = (bool)uni; }
  void get(int8_t *p) { *p = (int8_t)uni; }
  void get(int16_t *p) { *p = (int16_t)uni; }
  void get(int32_t *p) { *p = (int32_t)uni; }
  void get(uint8_t *p) { *p = (uint8_t)uni; }
  void get(uint16_t *p) { *p = (uint16_t)uni; }
  void get(uint32_t *p) { *p = (uint32_t)uni; }
  void get(float *p) { *p = uni; }

  void inc() { 
    if (type == FLOAT)
      uni += 0.1;
    else 
      uni++; 
  }
  void inc(float step) {
    if (step < 0.0 && (type == U8 
                    || type == U16 
                    || type == U32))
        return;
    uni += step;
  }
  void setRange(Range *range) {


  }
  float val() { return uni; }
  private:
  uint16_t type;
  float uni;
};

/*class UT;
struct bridge {
  UniVal &unival;
  UT &ut;
};*/
class UT;
struct Range {
    
};

class UT {
  public:
  UT(bool &b) : ref(&b), type(1) {}
  UT(int8_t &i8) : ref(&i8), type(2) {}
  UT(int16_t &i16) : ref(&i16), type(3) {}
  void setUniVal(UniVal &uv) { m_unival = &uv; }
  void toUni() {
    if (m_unival == nullptr)
        return;
    if (type == 1) {
      //uni_val = *(bool*)ref;
      m_unival->set(*(bool*)ref);
    } else if (type == 2) {
      //uni_val = *(int8_t*)ref;
      m_unival->set(*(int8_t*)ref);
    } else if (type == 3) {
      //uni_val = *(int16_t*)ref;
      m_unival->set(*(int16_t*)ref);
    }
  }
  void fromUni() {
    if (type == 1) {
      //*(bool*)ref = (bool)uni_val;
      m_unival->get((bool*)ref);
    } else if (type == 2) {
      //*(int8_t*)ref = (int8_t)uni_val;
      m_unival->get((int8_t*)ref);
    } else if (type == 3) {
      //*(int16_t*)ref = (int16_t)uni_val;
      m_unival->get((int16_t*)ref);
    }
  }
  private:
  UniVal *m_unival;
  const uint16_t type;
  const void *ref;
};

UniVal uv;

UT ubVar(bVar);

UT uiVar(iVar);

typedef struct {

    const char *namepar;
    const UT   *datapar;
    const UT   *datapar_min;
    const UT   *datapar_max;

} parameter_p_t;


void setup() {
  Serial.begin(115200);  
  Serial.println("-------------");
  //Serial.println(var_type_id(bVar));
  Serial.println(type_id_v(bVar));
  Serial.println(type_size_v(bVar));
  Serial.println(type_id_v(iVar));
  Serial.println(type_size_v(i8Var));
  
  Serial.println(type_id_v(i8Var));
  Serial.println(type_size_v(i8Var));
  Serial.println(type_id_v(i32Var));
  uiVar.setUniVal(uv);
  //ubVar.toUni();
  uiVar.toUni();
  Serial.println(uv.val(), 0);
  uv.inc();
  uiVar.fromUni();
  Serial.println(iVar);

  //Serial.println(uni_v);

  /*printType(varType(bVar));  
  printType(varType(iVar));
  printType(varType(xVar));
  printType(varType(lVar));
  printType(varType(strVar));*/
}

void loop() {
  // put your main code here, to run repeatedly:

}