From 46816f2f07e930011fc4470756598d75908aa53b Mon Sep 17 00:00:00 2001 From: andrethomas Date: Fri, 7 Dec 2018 00:55:44 +0200 Subject: [PATCH 1/2] MCP230xx - Add Interrupt Retain --- sonoff/settings.h | 2 +- sonoff/xsns_29_mcp230xx.ino | 84 +++++++++++++++++++++++++++++++++++-- 2 files changed, 82 insertions(+), 4 deletions(-) diff --git a/sonoff/settings.h b/sonoff/settings.h index 10e67e6a2..c773b3b86 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -156,7 +156,7 @@ typedef union { uint16_t int_report_mode : 2; // Interrupt reporting mode 0 = immediate telemetry & event, 1 = immediate event only, 2 = immediate telemetry only uint16_t int_report_defer : 4; // Number of interrupts to ignore until reporting (default 0, max 15) uint16_t int_count_en : 1; // Enable interrupt counter for this pin - uint16_t spare12 : 1; + uint16_t int_retain_flag : 1; // Report if interrupt occured for pin in next teleperiod uint16_t spare13 : 1; uint16_t spare14 : 1; uint16_t spare15 : 1; diff --git a/sonoff/xsns_29_mcp230xx.ino b/sonoff/xsns_29_mcp230xx.ino index 867fa54ec..64f3351a5 100644 --- a/sonoff/xsns_29_mcp230xx.ino +++ b/sonoff/xsns_29_mcp230xx.ino @@ -47,12 +47,15 @@ uint8_t mcp230xx_pincount = 0; uint8_t mcp230xx_int_en = 0; uint8_t mcp230xx_int_prio_counter = 0; uint8_t mcp230xx_int_counter_en = 0; +uint8_t mcp230xx_int_retainer_en = 0; uint8_t mcp230xx_int_sec_counter = 0; uint8_t mcp230xx_int_report_defer_counter[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; uint16_t mcp230xx_int_counter[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +uint8_t mcp230xx_int_retainer[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // Used to store if an interrupt occured that needs to be retained until teleperiod + unsigned long int_millis[16]; // To keep track of millis() since last interrupt const char MCP230XX_SENSOR_RESPONSE[] PROGMEM = "{\"Sensor29_D%i\":{\"MODE\":%i,\"PULL_UP\":\"%s\",\"INT_MODE\":\"%s\",\"STATE\":\"%s\"}}"; @@ -79,6 +82,20 @@ void MCP230xx_CheckForIntCounter(void) { } } +void MCP230xx_CheckForIntRetainer(void) { + uint8_t en = 0; + for (uint8_t ca=0;ca<16;ca++) { + if (Settings.mcp230xx_config[ca].int_retain_flag) { + en=1; + } + } + mcp230xx_int_retainer_en=en; + if (!mcp230xx_int_retainer_en) { // Interrupt counters are disabled, so we clear all the counters + for (uint8_t ca=0;ca<16;ca++) { + mcp230xx_int_retainer[ca] = 0; + } + } +} const char* ConvertNumTxt(uint8_t statu, uint8_t pinmod=0) { #ifdef USE_MCP230xx_OUTPUT @@ -177,7 +194,8 @@ void MCP230xx_ApplySettings(void) { int_millis[idx]=millis(); } mcp230xx_int_en = int_en; - MCP230xx_CheckForIntCounter(); // update register on whether or not we should be counting interrupts + MCP230xx_CheckForIntCounter(); // update register on whether or not we should be counting interrupts + MCP230xx_CheckForIntRetainer(); // update register on whether or not we should be retaining interrupt events for teleperiod } void MCP230xx_Detect(void) @@ -258,6 +276,13 @@ void MCP230xx_CheckForInterrupt(void) { } } } + // check if interrupt retain is used, if it is for this pin then we do not report immediately as it will be reported in teleperiod + if (report_int) { + if (Settings.mcp230xx_config[intp+(mcp230xx_port*8)].int_retain_flag) { + mcp230xx_int_retainer[intp+(mcp230xx_port*8)] = 1; + report_int = 0; // do not report for now + } + } if (Settings.mcp230xx_config[intp+(mcp230xx_port*8)].int_count_en) { // We do not want to report via tele or event if counting is enabled report_int = 0; } @@ -382,8 +407,8 @@ void MCP230xx_Reset(uint8_t pinmode) { Settings.mcp230xx_config[pinx].int_report_mode=3; // Disabled for pinmode 1, 5 and 6 (No interrupts there) } Settings.mcp230xx_config[pinx].int_report_defer=0; // Disabled - Settings.mcp230xx_config[pinx].int_count_en=0; // Disabled - Settings.mcp230xx_config[pinx].spare12=0; + Settings.mcp230xx_config[pinx].int_count_en=0; // Disabled by default + Settings.mcp230xx_config[pinx].int_retain_flag=0; // Disabled by default Settings.mcp230xx_config[pinx].spare13=0; Settings.mcp230xx_config[pinx].spare14=0; Settings.mcp230xx_config[pinx].spare15=0; @@ -544,6 +569,41 @@ bool MCP230xx_Command(void) { } } + if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"INTRETAIN")) { + if (paramcount > 1) { + uint8_t pin = atoi(subStr(sub_string, XdrvMailbox.data, ",", 2)); + if (pin < mcp230xx_pincount) { + if (pin == 0) { + if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "0")) validpin=true; + } else { + validpin = true; + } + } + if (validpin) { + if (paramcount > 2) { + uint8_t int_retain = atoi(subStr(sub_string, XdrvMailbox.data, ",", 3)); + if ((int_retain >= 0) && (int_retain <= 1)) { + Settings.mcp230xx_config[pin].int_retain_flag=int_retain; + snprintf_P(mqtt_data, sizeof(mqtt_data), MCP230XX_INTCFG_RESPONSE,"INT_RETAIN",pin,Settings.mcp230xx_config[pin].int_retain_flag); + MCP230xx_CheckForIntRetainer(); + return serviced; + } else { + serviced=false; + return serviced; + } + } else { + snprintf_P(mqtt_data, sizeof(mqtt_data), MCP230XX_INTCFG_RESPONSE,"INT_RETAIN",pin,Settings.mcp230xx_config[pin].int_retain_flag); + return serviced; + } + } + serviced = false; + return serviced; + } else { + serviced = false; + return serviced; + } + } + uint8_t pin = atoi(subStr(sub_string, XdrvMailbox.data, ",", 1)); if (pin < mcp230xx_pincount) { @@ -703,6 +763,19 @@ void MCP230xx_Interrupt_Counter_Report(void) { mcp230xx_int_sec_counter = 0; } +void MCP230xx_Interrupt_Retain_Report(void) { + uint16_t retainresult = 0; + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\",\"MCP_INTRETAIN\": {"), GetDateAndTime(DT_LOCAL).c_str()); + for (uint8_t pinx = 0;pinx < mcp230xx_pincount;pinx++) { + if (Settings.mcp230xx_config[pinx].int_retain_flag) { + snprintf_P(mqtt_data,sizeof(mqtt_data), PSTR("%s\"D%i\":%i,"),mqtt_data,pinx,mcp230xx_int_retainer[pinx]); + retainresult |= (((mcp230xx_int_retainer[pinx])&1) << pinx); + mcp230xx_int_retainer[pinx]=0; + } + } + snprintf_P(mqtt_data,sizeof(mqtt_data),PSTR("%s\"Value\":%u}}"),mqtt_data,retainresult); + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); +} /*********************************************************************************************\ Interface @@ -724,6 +797,11 @@ boolean Xsns29(byte function) MCP230xx_Interrupt_Counter_Report(); } } + if (tele_period == 0) { + if (mcp230xx_int_retainer_en) { // We have pins configured for interrupt retain reporting + MCP230xx_Interrupt_Retain_Report(); + } + } #ifdef USE_MCP230xx_OUTPUT if (tele_period == 0) { MCP230xx_OutputTelemetry(); From 99e6d7f2ffbdbb6460ad23762fcb10a44657d1e0 Mon Sep 17 00:00:00 2001 From: Andre Thomas Date: Fri, 7 Dec 2018 01:09:33 +0200 Subject: [PATCH 2/2] MCP230xx driver - add interrupt retention MCP230xx driver - add interrupt retention over teleperiod. --- sonoff/_changelog.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index b962b13de..cbad2b3c2 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,6 +1,7 @@ /* 6.3.0.16 20181201 * Add support for iFan02 Fanspeed in Domoticz using a selector (#4517) * Add Announce Switches to MQTT Discovery (#4531) + * Update MCP230xx driver to support interrupt retention over teleperiod (#4547) * * 6.3.0.15 20181201 * Removed command SetOption36 (#4497)