mirror of
https://github.com/anklimov/lighthub
synced 2025-12-07 12:19:49 +03:00
Analog & I2C input reading cache
New input configuration format many Discrete inputs on single analog in
This commit is contained in:
Binary file not shown.
@@ -67,6 +67,7 @@ static short counter_irq_map[54];
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
readCache inCache;
|
||||||
|
|
||||||
Input::Input(char * name) //Constructor
|
Input::Input(char * name) //Constructor
|
||||||
{
|
{
|
||||||
@@ -78,17 +79,10 @@ Input::Input(char * name) //Constructor
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Input::Input(int pin)
|
Input::Input(aJsonObject * obj, aJsonObject * parent)
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Input::Input(aJsonObject * obj)
|
|
||||||
{
|
{
|
||||||
inputObj= obj;
|
inputObj= obj;
|
||||||
Parse();
|
Parse(parent);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -97,16 +91,29 @@ boolean Input::isValid ()
|
|||||||
return (store);
|
return (store);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::Parse()
|
|
||||||
|
void Input::Parse(aJsonObject * configObj)
|
||||||
{
|
{
|
||||||
|
aJsonObject *itemBuffer;
|
||||||
store = NULL;
|
store = NULL;
|
||||||
inType = 0;
|
inType = 0;
|
||||||
pin = 0;
|
pin = 0;
|
||||||
if (inputObj && (inputObj->type == aJson_Object) && root) {
|
|
||||||
aJsonObject *itemBuffer;
|
if (!inputObj || !root) return;
|
||||||
itemBuffer = aJson.getObjectItem(inputObj, "T");
|
if (!configObj) configObj = inputObj;
|
||||||
|
|
||||||
|
if (configObj->type == aJson_Object)
|
||||||
|
{
|
||||||
|
// Retreive type and pin#
|
||||||
|
itemBuffer = aJson.getObjectItem(configObj, "T");
|
||||||
if (itemBuffer) inType = static_cast<uint8_t>(itemBuffer->valueint);
|
if (itemBuffer) inType = static_cast<uint8_t>(itemBuffer->valueint);
|
||||||
pin = static_cast<uint8_t>(atoi(inputObj->name));
|
|
||||||
|
itemBuffer = aJson.getObjectItem(configObj, "#");
|
||||||
|
if (itemBuffer) pin = static_cast<uint8_t>(itemBuffer->valueint);
|
||||||
|
else pin = static_cast<uint8_t>(atoi(configObj->name));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Persistant storage
|
||||||
itemBuffer = aJson.getObjectItem(inputObj, "S");
|
itemBuffer = aJson.getObjectItem(inputObj, "S");
|
||||||
if (!itemBuffer) {
|
if (!itemBuffer) {
|
||||||
debugSerial<<F("In: ")<<pin<<F("/")<<inType<<endl;
|
debugSerial<<F("In: ")<<pin<<F("/")<<inType<<endl;
|
||||||
@@ -114,12 +121,39 @@ void Input::Parse()
|
|||||||
itemBuffer = aJson.getObjectItem(inputObj, "S");
|
itemBuffer = aJson.getObjectItem(inputObj, "S");
|
||||||
}
|
}
|
||||||
if (itemBuffer) store = (inStore *) &itemBuffer->valueint;
|
if (itemBuffer) store = (inStore *) &itemBuffer->valueint;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanStore(aJsonObject * input)
|
||||||
|
{
|
||||||
|
if (input->type == aJson_Object) {
|
||||||
|
// Check for nested inputs
|
||||||
|
aJsonObject * inputArray = aJson.getObjectItem(input, "act");
|
||||||
|
if (inputArray && (inputArray->type == aJson_Array))
|
||||||
|
{
|
||||||
|
aJsonObject *inputObj = inputArray->child;
|
||||||
|
|
||||||
|
while(inputObj)
|
||||||
|
{
|
||||||
|
Input in(inputObj,input);
|
||||||
|
in.store->aslong = 0;
|
||||||
|
|
||||||
|
yield();
|
||||||
|
inputObj = inputObj->next;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Input in(input);
|
||||||
|
in.Poll(CHECK_INPUT);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Input::setup()
|
void Input::setup()
|
||||||
{
|
{
|
||||||
if (!isValid() || (!root)) return;
|
if (!isValid() || (!root)) return;
|
||||||
|
cleanStore(inputObj);
|
||||||
|
|
||||||
store->aslong=0;
|
store->aslong=0;
|
||||||
uint8_t inputPinMode = INPUT; //if IN_ACTIVE_HIGH
|
uint8_t inputPinMode = INPUT; //if IN_ACTIVE_HIGH
|
||||||
@@ -146,7 +180,7 @@ switch (inType)
|
|||||||
case IN_I2C | IN_PUSH_ON | IN_ACTIVE_HIGH:
|
case IN_I2C | IN_PUSH_ON | IN_ACTIVE_HIGH:
|
||||||
case IN_I2C | IN_PUSH_TOGGLE | IN_ACTIVE_HIGH:
|
case IN_I2C | IN_PUSH_TOGGLE | IN_ACTIVE_HIGH:
|
||||||
|
|
||||||
mcp.begin();
|
mcp.begin(); //TBD - multiple chip
|
||||||
mcp.pinMode(pin, INPUT);
|
mcp.pinMode(pin, INPUT);
|
||||||
if (inputPinMode == INPUT_PULLUP) mcp.pullUp(0, HIGH); // turn on a 100K pullup internally
|
if (inputPinMode == INPUT_PULLUP) mcp.pullUp(0, HIGH); // turn on a 100K pullup internally
|
||||||
|
|
||||||
@@ -676,16 +710,24 @@ void Input::contactPoll(short cause) {
|
|||||||
|
|
||||||
|
|
||||||
uint8_t inputOnLevel;
|
uint8_t inputOnLevel;
|
||||||
|
aJsonObject * mapObj;
|
||||||
if (inType & IN_ACTIVE_HIGH) inputOnLevel = HIGH;
|
if (inType & IN_ACTIVE_HIGH) inputOnLevel = HIGH;
|
||||||
else inputOnLevel = LOW;
|
else inputOnLevel = LOW;
|
||||||
|
|
||||||
|
|
||||||
#ifdef MCP23017
|
#ifdef MCP23017
|
||||||
if (inType & IN_I2C)
|
if (inType & IN_I2C)
|
||||||
currentInputState = (mcp.digitalRead(pin) == inputOnLevel);
|
currentInputState = (inCache.I2CReadBit(IN_I2C,0,pin) == inputOnLevel);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
currentInputState = (digitalRead(pin) == inputOnLevel);
|
if (isAnalogPin(pin) && (mapObj=aJson.getObjectItem(inputObj, "map")) && mapObj->type == aJson_Array)
|
||||||
|
{
|
||||||
|
int value = inCache.analogReadCached(pin);
|
||||||
|
if (value >= aJson.getArrayItem(mapObj, 0)->valueint && value <= aJson.getArrayItem(mapObj, 1)->valueint)
|
||||||
|
currentInputState = true;
|
||||||
|
else currentInputState = false;
|
||||||
|
}
|
||||||
|
else currentInputState = (digitalRead(pin) == inputOnLevel);
|
||||||
switch (store->state) //Timer based transitions
|
switch (store->state) //Timer based transitions
|
||||||
{
|
{
|
||||||
case IS_PRESSED:
|
case IS_PRESSED:
|
||||||
@@ -870,7 +912,7 @@ void Input::analogPoll(short cause) {
|
|||||||
|
|
||||||
pinMode(pin, inputPinMode);
|
pinMode(pin, inputPinMode);
|
||||||
*/
|
*/
|
||||||
inputVal = analogRead(pin);
|
inputVal = inCache.analogReadCached(pin);
|
||||||
// Mapping
|
// Mapping
|
||||||
if (inputMap && inputMap->type == aJson_Array)
|
if (inputMap && inputMap->type == aJson_Array)
|
||||||
{
|
{
|
||||||
@@ -1045,3 +1087,42 @@ char* Input::getIdxField() {
|
|||||||
return idx->valuestring;
|
return idx->valuestring;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
readCache::readCache()
|
||||||
|
{
|
||||||
|
addr=0;
|
||||||
|
type=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t readCache::analogReadCached (uint8_t _pin)
|
||||||
|
{
|
||||||
|
if ((_pin==addr) && (IN_ANALOG==type)) return cached_data;
|
||||||
|
addr = _pin;
|
||||||
|
type = IN_ANALOG;
|
||||||
|
cached_data =analogRead(_pin);
|
||||||
|
return cached_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t readCache::digitalReadCached(uint8_t _pin)
|
||||||
|
{
|
||||||
|
///TBD
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t readCache::I2CReadBit(uint8_t _type, uint8_t _addr, uint8_t _pin)
|
||||||
|
{
|
||||||
|
if (addr!=_addr || type != _type)
|
||||||
|
{
|
||||||
|
type=_type;
|
||||||
|
addr=_addr;
|
||||||
|
cached_data = mcp.readGPIOAB();
|
||||||
|
}
|
||||||
|
return (cached_data >> _pin ) & 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void readCache::invalidateInputCache()
|
||||||
|
{
|
||||||
|
addr=0;
|
||||||
|
type=0;
|
||||||
|
}
|
||||||
|
|||||||
@@ -135,10 +135,7 @@ public:
|
|||||||
uint8_t pin;
|
uint8_t pin;
|
||||||
inStore *store;
|
inStore *store;
|
||||||
|
|
||||||
Input(int pin);
|
Input(aJsonObject *obj, aJsonObject * configObj = NULL);
|
||||||
|
|
||||||
Input(aJsonObject *obj);
|
|
||||||
|
|
||||||
Input(char *name);
|
Input(char *name);
|
||||||
|
|
||||||
boolean isValid();
|
boolean isValid();
|
||||||
@@ -160,7 +157,7 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void Parse();
|
void Parse(aJsonObject * configObj = NULL);
|
||||||
|
|
||||||
void contactPoll(short cause);
|
void contactPoll(short cause);
|
||||||
void analogPoll(short cause);
|
void analogPoll(short cause);
|
||||||
@@ -184,3 +181,20 @@ protected:
|
|||||||
bool changeState(uint8_t newState, short cause);
|
bool changeState(uint8_t newState, short cause);
|
||||||
//bool executeCommand(aJsonObject* cmd, int8_t toggle = -1, char* defCmd = NULL);
|
//bool executeCommand(aJsonObject* cmd, int8_t toggle = -1, char* defCmd = NULL);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class readCache {
|
||||||
|
public:
|
||||||
|
readCache();
|
||||||
|
uint16_t analogReadCached (uint8_t pin);
|
||||||
|
uint8_t digitalReadCached(uint8_t pin);
|
||||||
|
uint8_t I2CReadBit(uint8_t type, uint8_t addr, uint8_t pin);
|
||||||
|
void invalidateInputCache();
|
||||||
|
protected:
|
||||||
|
uint8_t addr;
|
||||||
|
uint8_t type;
|
||||||
|
uint16_t cached_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern readCache inCache;
|
||||||
|
|||||||
@@ -1879,14 +1879,34 @@ configLocked++;
|
|||||||
aJsonObject *input = inputs->child;
|
aJsonObject *input = inputs->child;
|
||||||
|
|
||||||
while (input) {
|
while (input) {
|
||||||
if ((input->type == aJson_Object)) {
|
if (input->type == aJson_Object) {
|
||||||
|
// Check for nested inputs
|
||||||
|
aJsonObject * inputArray = aJson.getObjectItem(input, "act");
|
||||||
|
if (inputArray && (inputArray->type == aJson_Array))
|
||||||
|
{
|
||||||
|
aJsonObject *inputObj = inputArray->child;
|
||||||
|
|
||||||
|
while(inputObj)
|
||||||
|
{
|
||||||
|
Input in(inputObj,input);
|
||||||
|
in.Poll(CHECK_INPUT);
|
||||||
|
|
||||||
|
yield();
|
||||||
|
inputObj = inputObj->next;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Input in(input);
|
Input in(input);
|
||||||
in.Poll(CHECK_INPUT);
|
in.Poll(CHECK_INPUT);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
yield();
|
yield();
|
||||||
input = input->next;
|
input = input->next;
|
||||||
}
|
}
|
||||||
nextInputCheck = millis() + INTERVAL_CHECK_INPUT;
|
nextInputCheck = millis() + INTERVAL_CHECK_INPUT;
|
||||||
|
inCache.invalidateInputCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (millis() > nextSensorCheck) {
|
if (millis() > nextSensorCheck) {
|
||||||
|
|||||||
Reference in New Issue
Block a user