mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-25 11:46:31 +00:00
Add Shelly Pro 4 input interrupt support
This commit is contained in:
parent
88dd5f7f50
commit
4297fa3f3e
@ -89,10 +89,8 @@ void ButtonTouchFlag(uint32_t button_bit) {
|
|||||||
|
|
||||||
|
|
||||||
void ButtonSetVirtualPinState(uint32_t index, uint32_t state) {
|
void ButtonSetVirtualPinState(uint32_t index, uint32_t state) {
|
||||||
if (!Button.probe_mutex) {
|
|
||||||
bitWrite(Button.virtual_pin, index, state);
|
bitWrite(Button.virtual_pin, index, state);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*********************************************************************************************/
|
/*********************************************************************************************/
|
||||||
|
|
||||||
|
@ -68,21 +68,23 @@ void SwitchPulldownFlag(uint32 switch_bit) {
|
|||||||
bitSet(Switch.pulldown_mask, switch_bit);
|
bitSet(Switch.pulldown_mask, switch_bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Preffered virtual switch support since v12.3.1.4
|
||||||
void SwitchSetVirtualPinState(uint32_t index, uint32_t state) {
|
void SwitchSetVirtualPinState(uint32_t index, uint32_t state) {
|
||||||
if (!Switch.probe_mutex) {
|
|
||||||
bitWrite(Switch.virtual_pin, index, state);
|
bitWrite(Switch.virtual_pin, index, state);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// Legacy virtual switch support
|
||||||
void SwitchSetVirtual(uint32_t index, uint32_t state) {
|
void SwitchSetVirtual(uint32_t index, uint32_t state) {
|
||||||
bitSet(Switch.virtual_pin_used, index);
|
// bitSet(Switch.virtual_pin_used, index);
|
||||||
Switch.debounced_state[index] = state;
|
Switch.debounced_state[index] = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Legacy virtual switch support
|
||||||
uint8_t SwitchGetVirtual(uint32_t index) {
|
uint8_t SwitchGetVirtual(uint32_t index) {
|
||||||
return Switch.debounced_state[index];
|
return Switch.debounced_state[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Legacy virtual switch support
|
||||||
uint8_t SwitchLastState(uint32_t index) {
|
uint8_t SwitchLastState(uint32_t index) {
|
||||||
return Switch.last_state[index];
|
return Switch.last_state[index];
|
||||||
}
|
}
|
||||||
|
@ -45,8 +45,9 @@
|
|||||||
struct SPro {
|
struct SPro {
|
||||||
uint32_t last_update;
|
uint32_t last_update;
|
||||||
uint32_t probe_pin;
|
uint32_t probe_pin;
|
||||||
int switch_offset;
|
uint16_t input_state;
|
||||||
int button_offset;
|
int8_t switch_offset;
|
||||||
|
int8_t button_offset;
|
||||||
uint8_t pin_register_cs;
|
uint8_t pin_register_cs;
|
||||||
uint8_t pin_mcp23s17_int;
|
uint8_t pin_mcp23s17_int;
|
||||||
uint8_t ledlink;
|
uint8_t ledlink;
|
||||||
@ -98,33 +99,32 @@ void SP4Mcp23S17Disable(void) {
|
|||||||
digitalWrite(SPro.pin_register_cs, 1);
|
digitalWrite(SPro.pin_register_cs, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t SP4Mcp23S17ReadGpio(void) {
|
uint32_t SP4Mcp23S17Read16(uint8_t reg) {
|
||||||
// Read 16-bit gpio registers: (gpiob << 8) | gpioa
|
// Read 16-bit registers: (regb << 8) | rega
|
||||||
SP4Mcp23S17Enable();
|
|
||||||
SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1);
|
|
||||||
SPI.transfer(SP4_MCP23S17_GPIOA);
|
|
||||||
uint32_t gpio = SPI.transfer(0xFF); // SP4_MCP23S17_GPIOA
|
|
||||||
gpio |= (SPI.transfer(0xFF) << 8); // SP4_MCP23S17_GPIOB
|
|
||||||
SP4Mcp23S17Disable();
|
|
||||||
return gpio;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SP4Mcp23S17Read(uint8_t reg, uint8_t *value) {
|
|
||||||
SP4Mcp23S17Enable();
|
SP4Mcp23S17Enable();
|
||||||
SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1);
|
SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1);
|
||||||
SPI.transfer(reg);
|
SPI.transfer(reg);
|
||||||
*value = SPI.transfer(0xFF);
|
uint32_t value = SPI.transfer(0xFF); // RegA
|
||||||
|
value |= (SPI.transfer(0xFF) << 8); // RegB
|
||||||
SP4Mcp23S17Disable();
|
SP4Mcp23S17Disable();
|
||||||
return true;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SP4Mcp23S17Write(uint8_t reg, uint8_t value) {
|
uint32_t SP4Mcp23S17Read(uint8_t reg) {
|
||||||
|
SP4Mcp23S17Enable();
|
||||||
|
SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS | 1);
|
||||||
|
SPI.transfer(reg);
|
||||||
|
uint32_t value = SPI.transfer(0xFF);
|
||||||
|
SP4Mcp23S17Disable();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP4Mcp23S17Write(uint8_t reg, uint8_t value) {
|
||||||
SP4Mcp23S17Enable();
|
SP4Mcp23S17Enable();
|
||||||
SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS);
|
SPI.transfer(SHELLY_PRO_4_MCP23S17_ADDRESS);
|
||||||
SPI.transfer(reg);
|
SPI.transfer(reg);
|
||||||
SPI.transfer(value);
|
SPI.transfer(value);
|
||||||
SP4Mcp23S17Disable();
|
SP4Mcp23S17Disable();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SP4Mcp23S17Update(uint8_t pin, bool pin_value, uint8_t reg_addr) {
|
void SP4Mcp23S17Update(uint8_t pin, bool pin_value, uint8_t reg_addr) {
|
||||||
@ -135,7 +135,7 @@ void SP4Mcp23S17Update(uint8_t pin, bool pin_value, uint8_t reg_addr) {
|
|||||||
} else if (reg_addr == SP4_MCP23S17_OLATB) {
|
} else if (reg_addr == SP4_MCP23S17_OLATB) {
|
||||||
reg_value = sp4_mcp23s17_olatb;
|
reg_value = sp4_mcp23s17_olatb;
|
||||||
} else {
|
} else {
|
||||||
SP4Mcp23S17Read(reg_addr, ®_value);
|
reg_value = SP4Mcp23S17Read(reg_addr);
|
||||||
}
|
}
|
||||||
if (pin_value) {
|
if (pin_value) {
|
||||||
reg_value |= 1 << bit;
|
reg_value |= 1 << bit;
|
||||||
@ -167,8 +167,7 @@ void SP4Mcp23S17PinMode(uint8_t pin, uint8_t flags) {
|
|||||||
bool SP4Mcp23S17DigitalRead(uint8_t pin) {
|
bool SP4Mcp23S17DigitalRead(uint8_t pin) {
|
||||||
uint8_t bit = pin % 8;
|
uint8_t bit = pin % 8;
|
||||||
uint8_t reg_addr = pin < 8 ? SP4_MCP23S17_GPIOA : SP4_MCP23S17_GPIOB;
|
uint8_t reg_addr = pin < 8 ? SP4_MCP23S17_GPIOA : SP4_MCP23S17_GPIOB;
|
||||||
uint8_t value = 0;
|
uint8_t value = SP4Mcp23S17Read(reg_addr);
|
||||||
SP4Mcp23S17Read(reg_addr, &value);
|
|
||||||
return value & (1 << bit);
|
return value & (1 << bit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -210,8 +209,8 @@ void ShellyPro4Init(void) {
|
|||||||
SP4Mcp23S17Write(SP4_MCP23S17_GPINTENB, 0x80); // Enable interrupt on change
|
SP4Mcp23S17Write(SP4_MCP23S17_GPINTENB, 0x80); // Enable interrupt on change
|
||||||
|
|
||||||
// Read current output register state
|
// Read current output register state
|
||||||
SP4Mcp23S17Read(SP4_MCP23S17_OLATA, &sp4_mcp23s17_olata);
|
sp4_mcp23s17_olata = SP4Mcp23S17Read(SP4_MCP23S17_OLATA);
|
||||||
SP4Mcp23S17Read(SP4_MCP23S17_OLATB, &sp4_mcp23s17_olatb);
|
sp4_mcp23s17_olatb = SP4Mcp23S17Read(SP4_MCP23S17_OLATB);
|
||||||
|
|
||||||
for (uint32_t i = 0; i < 4; i++) {
|
for (uint32_t i = 0; i < 4; i++) {
|
||||||
SP4Mcp23S17PinMode(sp4_switch_pin[i], INPUT); // Switch1..4
|
SP4Mcp23S17PinMode(sp4_switch_pin[i], INPUT); // Switch1..4
|
||||||
@ -226,6 +225,8 @@ void ShellyPro4Init(void) {
|
|||||||
|
|
||||||
SP4Mcp23S17PinMode(4, OUTPUT); // Reset display, ADE7943
|
SP4Mcp23S17PinMode(4, OUTPUT); // Reset display, ADE7943
|
||||||
SP4Mcp23S17DigitalWrite(4, 1);
|
SP4Mcp23S17DigitalWrite(4, 1);
|
||||||
|
|
||||||
|
attachInterrupt(SPro.pin_mcp23s17_int, ShellyProUpdateIsr, CHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShellyPro4Reset(void) {
|
void ShellyPro4Reset(void) {
|
||||||
@ -239,7 +240,9 @@ bool ShellyProAddButton(void) {
|
|||||||
if (SPro.button_offset < 0) { SPro.button_offset = XdrvMailbox.index; }
|
if (SPro.button_offset < 0) { SPro.button_offset = XdrvMailbox.index; }
|
||||||
uint32_t index = XdrvMailbox.index - SPro.button_offset;
|
uint32_t index = XdrvMailbox.index - SPro.button_offset;
|
||||||
if (index > 2) { return false; } // Support three buttons
|
if (index > 2) { return false; } // Support three buttons
|
||||||
XdrvMailbox.index = SP4Mcp23S17DigitalRead(sp4_button_pin[index]);
|
uint32_t state = SP4Mcp23S17DigitalRead(sp4_button_pin[index]);
|
||||||
|
bitWrite(SPro.input_state, sp4_button_pin[index], state);
|
||||||
|
XdrvMailbox.index = state;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,29 +251,42 @@ bool ShellyProAddSwitch(void) {
|
|||||||
if (SPro.switch_offset < 0) { SPro.switch_offset = XdrvMailbox.index; }
|
if (SPro.switch_offset < 0) { SPro.switch_offset = XdrvMailbox.index; }
|
||||||
uint32_t index = XdrvMailbox.index - SPro.switch_offset;
|
uint32_t index = XdrvMailbox.index - SPro.switch_offset;
|
||||||
if (index > 3) { return false; } // Support four switches
|
if (index > 3) { return false; } // Support four switches
|
||||||
XdrvMailbox.index = SP4Mcp23S17DigitalRead(sp4_switch_pin[index]);
|
uint32_t state = SP4Mcp23S17DigitalRead(sp4_switch_pin[index]);
|
||||||
|
bitWrite(SPro.input_state, sp4_switch_pin[index], state);
|
||||||
|
XdrvMailbox.index = state ^1; // Invert
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShellyProUpdateSwitches(void) {
|
void ShellyProUpdateIsr(void) {
|
||||||
if (SPro.detected != 4) { return; } // Only support Shelly Pro 4
|
/*
|
||||||
if (digitalRead(SPro.pin_mcp23s17_int)) { return; } // Poll interrupt
|
The goal if this function is to minimize SPI and SetVirtualPinState calls
|
||||||
|
*/
|
||||||
|
|
||||||
uint32_t gpio = SP4Mcp23S17ReadGpio(); // Read gpio and clear interrupt
|
uint32_t input_state = SP4Mcp23S17Read16(SP4_MCP23S17_INTCAPA); // Read intcap and clear interrupt
|
||||||
|
input_state &= 0x806F; // Only test input bits
|
||||||
|
|
||||||
// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Input detected 0x%04X"), gpio);
|
// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Input detected %04X, was %04X"), input_state, SPro.input_state);
|
||||||
|
|
||||||
|
uint32_t mask = 1;
|
||||||
|
for (uint32_t j = 0; j < 16; j++) {
|
||||||
|
if ((input_state & mask) != (SPro.input_state & mask)) {
|
||||||
|
uint32_t state = (input_state >> j) &1;
|
||||||
|
|
||||||
|
// AddLog(LOG_LEVEL_DEBUG, PSTR("SHP: Change pin %d to %d"), j, state);
|
||||||
|
|
||||||
// Propagate state
|
|
||||||
uint32_t state;
|
|
||||||
for (uint32_t i = 0; i < 4; i++) {
|
for (uint32_t i = 0; i < 4; i++) {
|
||||||
state = (gpio >> sp4_switch_pin[i]) &1;
|
if (j == sp4_switch_pin[i]) {
|
||||||
SwitchSetVirtualPinState(SPro.switch_offset +i, state);
|
SwitchSetVirtualPinState(SPro.switch_offset +i, state ^1); // Invert
|
||||||
}
|
}
|
||||||
for (uint32_t i = 0; i < 3; i++) {
|
else if ((i < 3) && (j == sp4_button_pin[i])) {
|
||||||
state = (gpio >> sp4_button_pin[i]) &1;
|
|
||||||
ButtonSetVirtualPinState(SPro.button_offset +i, state);
|
ButtonSetVirtualPinState(SPro.button_offset +i, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
mask <<= 1;
|
||||||
|
}
|
||||||
|
SPro.input_state = input_state;
|
||||||
|
}
|
||||||
|
|
||||||
bool ShellyProButton(void) {
|
bool ShellyProButton(void) {
|
||||||
if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4
|
if (SPro.detected != 4) { return false; } // Only support Shelly Pro 4
|
||||||
@ -458,9 +474,6 @@ bool Xdrv88(uint32_t function) {
|
|||||||
ShellyProPreInit();
|
ShellyProPreInit();
|
||||||
} else if (SPro.detected) {
|
} else if (SPro.detected) {
|
||||||
switch (function) {
|
switch (function) {
|
||||||
case FUNC_EVERY_50_MSECOND:
|
|
||||||
ShellyProUpdateSwitches();
|
|
||||||
break;
|
|
||||||
/*
|
/*
|
||||||
case FUNC_BUTTON_PRESSED:
|
case FUNC_BUTTON_PRESSED:
|
||||||
result = ShellyProButton();
|
result = ShellyProButton();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user