diff --git a/src/driver/drv_tuyaMCU.c b/src/driver/drv_tuyaMCU.c index a3e2cb30a..f5b035aee 100644 --- a/src/driver/drv_tuyaMCU.c +++ b/src/driver/drv_tuyaMCU.c @@ -67,7 +67,8 @@ static byte g_tuyaMCUConfirmationsToSend_0x08 = 0; static byte g_tuyaMCUConfirmationsToSend_0x05 = 0; static byte g_resetWiFiEvents = 0; - +#define OBKTM_FLAG_DPCACHE 1 +#define OBKTM_FLAG_NOREAD 2 //============================================================================= //dp data point type @@ -161,7 +162,7 @@ typedef struct tuyaMCUMapping_s { // data point type (one of the DP_TYPE_xxx defines) byte dpType; // true if it's supposed to be sent in dp cache - byte bDPCache; + byte obkFlags; // could be renamed to flags later? byte inv; // target channel @@ -336,7 +337,7 @@ tuyaMCUMapping_t* TuyaMCU_FindDefForChannel(int channel) { return 0; } -tuyaMCUMapping_t* TuyaMCU_MapIDToChannel(int dpId, int dpType, int channel, int bDPCache, float mul, int inv, float delta, float delta2, float delta3) { +tuyaMCUMapping_t* TuyaMCU_MapIDToChannel(int dpId, int dpType, int channel, int obkFlags, float mul, int inv, float delta, float delta2, float delta3) { tuyaMCUMapping_t* cur; cur = TuyaMCU_FindDefForID(dpId); @@ -351,7 +352,7 @@ tuyaMCUMapping_t* TuyaMCU_MapIDToChannel(int dpId, int dpType, int channel, int } cur->dpId = dpId; cur->dpType = dpType; - cur->bDPCache = bDPCache; + cur->obkFlags = obkFlags; cur->mult = mul; cur->delta = delta; cur->delta2 = delta2; @@ -873,11 +874,11 @@ commandResult_t TuyaMCU_LinkTuyaMCUOutputToChannel(const void* context, const ch byte dpType; int channelID; byte argsCount; - byte bDPCache; + byte obkFlags; float mult, delta, delta2, delta3; byte inv; - // linkTuyaMCUOutputToChannel [dpId] [varType] [channelID] [bDPCache] [mult] [inv] [delta] + // linkTuyaMCUOutputToChannel [dpId] [varType] [channelID] [obkFlags] [mult] [inv] [delta] // linkTuyaMCUOutputToChannel 1 val 1 Tokenizer_TokenizeString(args, 0); @@ -897,14 +898,14 @@ commandResult_t TuyaMCU_LinkTuyaMCUOutputToChannel(const void* context, const ch else { channelID = Tokenizer_GetArgInteger(2); } - bDPCache = Tokenizer_GetArgInteger(3); + obkFlags = Tokenizer_GetArgInteger(3); mult = Tokenizer_GetArgFloatDefault(4, 1.0f); inv = Tokenizer_GetArgInteger(5); delta = Tokenizer_GetArgFloatDefault(6, 0.0f); delta2 = Tokenizer_GetArgFloatDefault(7, 0.0f); delta3 = Tokenizer_GetArgFloatDefault(8, 0.0f); - TuyaMCU_MapIDToChannel(dpId, dpType, channelID, bDPCache, mult, inv, delta, delta2, delta3); + TuyaMCU_MapIDToChannel(dpId, dpType, channelID, obkFlags, mult, inv, delta, delta2, delta3); return CMD_RES_OK; } @@ -1141,6 +1142,10 @@ void TuyaMCU_ApplyMapping(tuyaMCUMapping_t* mapping, int dpID, int value) { if (mapping->channel < 0) { return; } + if (mapping->obkFlags & OBKTM_FLAG_NOREAD) { + // ignore + return; + } // map value depending on channel type switch (CHANNEL_GetType(mapping->channel)) @@ -1206,7 +1211,7 @@ void TuyaMCU_OnChannelChanged(int channel, int iVal) { } // dpCaches are sent when requested - TODO - is it correct? - if (mapping->bDPCache) { + if (mapping->obkFlags & OBKTM_FLAG_DPCACHE) { return; } @@ -1854,7 +1859,7 @@ void TuyaMCU_V0_SendDPCacheReply() { // dpId = 18 Len = 0004 Val V = 1 // while (map) { - if (map->bDPCache) { + if (map->obkFlags & OBKTM_FLAG_DPCACHE) { writtenCount++; // dpID *p = map->dpId; @@ -2644,8 +2649,8 @@ void TuyaMCU_Init() //cmddetail:"fn":"TuyaMCU_Send_SetTime_Current","file":"driver/drv_tuyaMCU.c","requires":"", //cmddetail:"examples":""} CMD_RegisterCommand("tuyaMcu_sendCurTime", TuyaMCU_Send_SetTime_Current, NULL); - //cmddetail:{"name":"linkTuyaMCUOutputToChannel","args":"[dpId][varType][channelID][bDPCache-Optional][mult-optional][bInverse-Optional][delta-Optional][delta2][delta3]", - //cmddetail:"descr":"Used to map between TuyaMCU dpIDs and our internal channels. Mult, inverse and delta are for calibration, they are optional. bDPCache is also optional, you can set it to 1 for battery powered devices, so a variable is set with DPCache, for example a sampling interval for humidity/temperature sensor. Mapping works both ways. DpIDs are per-device, you can get them by sniffing UART communication. Vartypes can also be sniffed from Tuya. VarTypes can be following: 0-raw, 1-bool, 2-value, 3-string, 4-enum, 5-bitmap. Please see [Tuya Docs](https://developer.tuya.com/en/docs/iot/tuya-cloud-universal-serial-port-access-protocol?id=K9hhi0xxtn9cb) for info about TuyaMCU. You can also see our [TuyaMCU Analyzer Tool](https://www.elektroda.com/rtvforum/viewtopic.php?p=20528459#20528459)", + //cmddetail:{"name":"linkTuyaMCUOutputToChannel","args":"[dpId][varType][channelID][obkFlags-Optional][mult-optional][bInverse-Optional][delta-Optional][delta2][delta3]", + //cmddetail:"descr":"Used to map between TuyaMCU dpIDs and our internal channels. Mult, inverse and delta are for calibration, they are optional. obkFlags is also optional, you can set it to 1 for battery powered devices, so a variable is set with DPCache, for example a sampling interval for humidity/temperature sensor. Mapping works both ways. DpIDs are per-device, you can get them by sniffing UART communication. Vartypes can also be sniffed from Tuya. VarTypes can be following: 0-raw, 1-bool, 2-value, 3-string, 4-enum, 5-bitmap. Please see [Tuya Docs](https://developer.tuya.com/en/docs/iot/tuya-cloud-universal-serial-port-access-protocol?id=K9hhi0xxtn9cb) for info about TuyaMCU. You can also see our [TuyaMCU Analyzer Tool](https://www.elektroda.com/rtvforum/viewtopic.php?p=20528459#20528459)", //cmddetail:"fn":"TuyaMCU_LinkTuyaMCUOutputToChannel","file":"driver/drv_tuyaMCU.c","requires":"", //cmddetail:"examples":""} CMD_RegisterCommand("linkTuyaMCUOutputToChannel", TuyaMCU_LinkTuyaMCUOutputToChannel, NULL); diff --git a/src/new_pins.c b/src/new_pins.c index 89a0824b7..71d3c562c 100644 --- a/src/new_pins.c +++ b/src/new_pins.c @@ -1643,55 +1643,58 @@ void CHANNEL_Set_Ex(int ch, int iVal, int iFlags, int ausemovingaverage) { void CHANNEL_Set(int ch, int iVal, int iFlags) { CHANNEL_Set_Ex(ch, iVal, iFlags, 0); } +char *g_channelPingPongs = 0; -void CHANNEL_AddClamped(int ch, int iVal, int min, int max, int bWrapInsteadOfClamp) { -#if 0 - int prevValue; - if (ch < 0 || ch >= CHANNEL_MAX) { - addLogAdv(LOG_ERROR, LOG_FEATURE_GENERAL, "CHANNEL_AddClamped: Channel index %i is out of range <0,%i)\n\r", ch, CHANNEL_MAX); - return; - } - prevValue = g_channelValues[ch]; - g_channelValues[ch] = g_channelValues[ch] + iVal; - - if (bWrapInsteadOfClamp) { - if (g_channelValues[ch] > max) - g_channelValues[ch] = min; - if (g_channelValues[ch] < min) - g_channelValues[ch] = max; - } - else { - if (g_channelValues[ch] > max) - g_channelValues[ch] = max; - if (g_channelValues[ch] < min) - g_channelValues[ch] = min; - } - - addLogAdv(LOG_INFO, LOG_FEATURE_GENERAL, "CHANNEL_AddClamped channel %i has changed to %i\n\r", ch, g_channelValues[ch]); - - Channel_OnChanged(ch, prevValue, 0); -#else +void CHANNEL_AddClamped(int ch, int iDelta, int min, int max, int bWrapInsteadOfClamp) { // we want to support special channel indexes, so it's better to use GET/SET interface // Special channel indexes are used to access things like dimmer, led colors, etc - iVal = CHANNEL_Get(ch) + iVal; + int newVal;; - if (bWrapInsteadOfClamp) { - if (iVal > max) - iVal = min; - if (iVal < min) - iVal = max; + if (bWrapInsteadOfClamp == 3) { + if (g_channelPingPongs) { + g_channelPingPongs[ch] *= -1; + } + return; + } else if (bWrapInsteadOfClamp == 2) { + // ping-pong logic + if (g_channelPingPongs == 0) { + g_channelPingPongs = (char*)malloc(CHANNEL_MAX); + memset(g_channelPingPongs, 1, CHANNEL_MAX); + } + int prevVal = CHANNEL_Get(ch); + newVal = prevVal + iDelta * g_channelPingPongs[ch]; + if (prevVal == min && newVal < min) { + g_channelPingPongs[ch] *= -1; + } + else if (prevVal == max && newVal > max) { + g_channelPingPongs[ch] *= -1; + } + newVal = prevVal + iDelta * g_channelPingPongs[ch]; + if (newVal > max) { + newVal = max; + } + else if (newVal < min) { + newVal = min; + } + } else if (bWrapInsteadOfClamp) { + newVal = CHANNEL_Get(ch) + iDelta; + if (newVal > max) + newVal = min; + if (newVal < min) + newVal = max; } else { - if (iVal > max) - iVal = max; - if (iVal < min) - iVal = min; + newVal = CHANNEL_Get(ch) + iDelta; + if (newVal > max) + newVal = max; + if (newVal < min) + newVal = min; } - addLogAdv(LOG_INFO, LOG_FEATURE_GENERAL, "CHANNEL_AddClamped channel %i has changed to %i\n\r", ch, iVal); + addLogAdv(LOG_INFO, LOG_FEATURE_GENERAL, + "CHANNEL_AddClamped channel %i has changed to %i\n\r", ch, newVal); - CHANNEL_Set(ch, iVal, 0); -#endif + CHANNEL_Set(ch, newVal, 0); } void CHANNEL_Add(int ch, int iVal) { #if 0 diff --git a/src/selftest/selftest_cmd_channels.c b/src/selftest/selftest_cmd_channels.c index 2b80a52e1..9b9b92fac 100644 --- a/src/selftest/selftest_cmd_channels.c +++ b/src/selftest/selftest_cmd_channels.c @@ -249,6 +249,114 @@ void Test_Commands_Channels() { SELFTEST_ASSERT_CHANNEL(10, -123); + // clamp test + CMD_ExecuteCommand("SetChannel 1 0", 0); + SELFTEST_ASSERT_CHANNEL(1, 0); + // [ChannelIndex][ValueToAdd][ClampMin][ClampMax][bWrapInsteadOfClamp] + CMD_ExecuteCommand("addChannel 1 10 0 100 0", 0); + SELFTEST_ASSERT_CHANNEL(1, 10); + CMD_ExecuteCommand("addChannel 1 10 0 100 0", 0); + SELFTEST_ASSERT_CHANNEL(1, 20); + CMD_ExecuteCommand("addChannel 1 80 0 100 0", 0); + SELFTEST_ASSERT_CHANNEL(1, 100); + CMD_ExecuteCommand("addChannel 1 80 0 100 0", 0); + SELFTEST_ASSERT_CHANNEL(1, 100); + CMD_ExecuteCommand("addChannel 1 80 0 100 0", 0); + SELFTEST_ASSERT_CHANNEL(1, 100); + CMD_ExecuteCommand("addChannel 1 -1 0 100 0", 0); + SELFTEST_ASSERT_CHANNEL(1, 99); + + // wrap test + CMD_ExecuteCommand("addChannel 1 1 0 100 1", 0); + SELFTEST_ASSERT_CHANNEL(1, 100); + CMD_ExecuteCommand("addChannel 1 1 0 100 1", 0); + SELFTEST_ASSERT_CHANNEL(1, 0); + CMD_ExecuteCommand("addChannel 1 1 0 100 1", 0); + SELFTEST_ASSERT_CHANNEL(1, 1); + CMD_ExecuteCommand("addChannel 1 1 0 100 1", 0); + SELFTEST_ASSERT_CHANNEL(1, 2); + CMD_ExecuteCommand("addChannel 1 -1 0 100 1", 0); + SELFTEST_ASSERT_CHANNEL(1, 1); + CMD_ExecuteCommand("addChannel 1 1 0 100 1", 0); + SELFTEST_ASSERT_CHANNEL(1, 2); + CMD_ExecuteCommand("addChannel 1 2 0 100 1", 0); + SELFTEST_ASSERT_CHANNEL(1, 4); + CMD_ExecuteCommand("addChannel 1 10 0 100 1", 0); + SELFTEST_ASSERT_CHANNEL(1, 14); + CMD_ExecuteCommand("addChannel 1 80 0 100 1", 0); + SELFTEST_ASSERT_CHANNEL(1, 94); + CMD_ExecuteCommand("addChannel 1 5 0 100 1", 0); + SELFTEST_ASSERT_CHANNEL(1, 99); + CMD_ExecuteCommand("addChannel 1 5 0 100 1", 0); + // TODO: stop at 100, then go to min? + SELFTEST_ASSERT_CHANNEL(1, 0); + + // pingpongtest + SELFTEST_ASSERT_CHANNEL(1, 0); + CMD_ExecuteCommand("addChannel 1 25 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 25); + CMD_ExecuteCommand("addChannel 1 25 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 50); + CMD_ExecuteCommand("addChannel 1 25 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 75); + CMD_ExecuteCommand("addChannel 1 25 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 100); + CMD_ExecuteCommand("addChannel 1 25 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 75); + CMD_ExecuteCommand("addChannel 1 25 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 50); + CMD_ExecuteCommand("addChannel 1 25 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 25); + CMD_ExecuteCommand("addChannel 1 25 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 0); + CMD_ExecuteCommand("addChannel 1 25 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 25); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 49); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 73); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 97); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + // SPECIAL - STOP AT 100 + SELFTEST_ASSERT_CHANNEL(1, 100); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 76); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 52); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 28); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 4); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 0); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 24); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 48); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 72); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 96); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 100); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 76); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 52); + // revert dir + CMD_ExecuteCommand("addChannel 1 0 0 100 3", 0); + SELFTEST_ASSERT_CHANNEL(1, 52); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 76); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 100); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 76); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 52); + CMD_ExecuteCommand("addChannel 1 24 0 100 2", 0); + SELFTEST_ASSERT_CHANNEL(1, 28); // cause error //SELFTEST_ASSERT_CHANNEL(3, 666); diff --git a/src/win_main.c b/src/win_main.c index 234c48a4a..658304516 100644 --- a/src/win_main.c +++ b/src/win_main.c @@ -168,6 +168,7 @@ void SIM_ClearOBK(const char *flashPath) { void Win_DoUnitTests() { //SELFTEST_ASSERT_EXPRESSION("sqrt(4)", 2) + Test_Commands_Channels(); Test_Driver_TCL_AC(); @@ -250,7 +251,6 @@ void Win_DoUnitTests() { Test_LEDDriver(); Test_LFS(); Test_Scripting(); - Test_Commands_Channels(); Test_Command_If(); Test_Tokenizer(); Test_Http();