diff --git a/hardware/arduino/zunoG2/cores/ZWSupport/CommandQueue.c b/hardware/arduino/zunoG2/cores/ZWSupport/CommandQueue.c index 2de15afe..28441985 100644 --- a/hardware/arduino/zunoG2/cores/ZWSupport/CommandQueue.c +++ b/hardware/arduino/zunoG2/cores/ZWSupport/CommandQueue.c @@ -101,6 +101,19 @@ bool zunoCheckSystemQueueStatus(uint8_t channel){ #endif return b_busy; } + +static bool _ZWQSend_test(ZUNOCommandPacket_t *info, ZUNOCommandCmd_t *p, bool multi) { + if (info->report.valid == false) + return (true); + if (info->report.src_node != p->dst_node) + return (true); + if (info->report.cmd_class != p->cmd[0x0]) + return (true); + if (info->report.multi != multi) + return (true); + return (false); +} + void _ZWQSend(ZUNOCommandPacket_t *info){ ZUNOCommandCmd_t *p; @@ -114,14 +127,18 @@ void _ZWQSend(ZUNOCommandPacket_t *info){ bool b_plain_assoc = (p->dst_zw_channel == PLAIN_ASSOC_MAP); // It's a plain associtaion p->dst_zw_channel &= ~(PLAIN_ASSOC_MAP); // Remove plain assoc value if(p->src_zw_channel & ZWAVE_CHANNEL_MAPPED_BIT){ - uint8_t mapped_channel = p->src_zw_channel; - p->src_zw_channel = 0; - zunoSysCall(ZUNO_SYSFUNC_SENDPACKET, 1, p); - p->src_zw_channel = mapped_channel; + if (_ZWQSend_test(info, p, false) == true) { + uint8_t mapped_channel = p->src_zw_channel; + p->src_zw_channel = 0; + zunoSysCall(ZUNO_SYSFUNC_SENDPACKET, 1, p); + p->src_zw_channel = mapped_channel; + } } - if(b_plain_assoc && ((p->dst_zw_channel != 0) || (p->src_zw_channel != 0))) - return; // do not send association with multichannel encap to plain group - zunoSysCall(ZUNO_SYSFUNC_SENDPACKET, 1, p); + if(b_plain_assoc && ((p->dst_zw_channel != 0) || (p->src_zw_channel != 0))) + return; // do not send association with multichannel encap to plain group + if (_ZWQSend_test(info, p, true) == false) + return ; + zunoSysCall(ZUNO_SYSFUNC_SENDPACKET, 1, p); } void _ZWQRemovePkg(ZUNOCommandPacket_t *info){ ZUNOCommandCmd_t *p; diff --git a/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCSwitchBinary.cpp b/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCSwitchBinary.cpp index 46112afe..0c583fc8 100644 --- a/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCSwitchBinary.cpp +++ b/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCSwitchBinary.cpp @@ -37,7 +37,7 @@ int zuno_CCSwitchBinaryReport(byte channel, ZUNOCommandPacket_t *packet) { return (ZUNO_COMMAND_ANSWERED); } -static int _set(ZwSwitchBinarySetFrame_t *cmd, size_t len, size_t channel, ZUNOCommandPacketReport_t *frame_report, const ZUNOCommandCmd_t *packet) { +static int _set(ZwSwitchBinarySetFrame_t *cmd, size_t len, size_t channel, ZUNOCommandPacketReport_t *frame_report, const ZUNOCommandCmd_t *packet, const ZUNOCommandHandlerOption_t *options) { uint8_t targetValue; size_t duration; uint8_t currentValue; @@ -74,11 +74,11 @@ static int _set(ZwSwitchBinarySetFrame_t *cmd, size_t len, size_t channel, ZUNOC break ; } __zuno_BasicUniversalSetter1P(channel, targetValue); - zunoSendReport(channel + 0x1); + zunoSendReportSet(channel, options); return (ZUNO_COMMAND_PROCESSED); } -int zuno_CCSwitchBinaryHandler(byte channel, const ZUNOCommandCmd_t *cmd, ZUNOCommandPacketReport_t *frame_report){ +int zuno_CCSwitchBinaryHandler(byte channel, const ZUNOCommandCmd_t *cmd, ZUNOCommandPacketReport_t *frame_report, const ZUNOCommandHandlerOption_t *options) { int rs; switch(ZW_CMD) { @@ -87,7 +87,7 @@ int zuno_CCSwitchBinaryHandler(byte channel, const ZUNOCommandCmd_t *cmd, ZUNOCo _zunoMarkChannelRequested(channel); break; case SWITCH_BINARY_SET: - rs = _set((ZwSwitchBinarySetFrame_t *)cmd->cmd, cmd->len, channel, frame_report, cmd); + rs = _set((ZwSwitchBinarySetFrame_t *)cmd->cmd, cmd->len, channel, frame_report, cmd, options); break; default: rs = ZUNO_COMMAND_BLOCKED_NO_SUPPORT; diff --git a/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCSwitchBinary.h b/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCSwitchBinary.h index 598d0928..3f8409f7 100644 --- a/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCSwitchBinary.h +++ b/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCSwitchBinary.h @@ -54,7 +54,7 @@ typedef union ZwBasicBinaryReportFrame_u {//For more convenient support, ZwSwitchBinaryReportV2Frame_t v2; } ZwBasicBinaryReportFrame_t; -int zuno_CCSwitchBinaryHandler(byte channel, const ZUNOCommandCmd_t *cmd, ZUNOCommandPacketReport_t *frame_report); +int zuno_CCSwitchBinaryHandler(byte channel, const ZUNOCommandCmd_t *cmd, ZUNOCommandPacketReport_t *frame_report, const ZUNOCommandHandlerOption_t *options); int zuno_CCSwitchBinaryReport(byte channel, ZUNOCommandPacket_t *packet); void __zuno_CCSwitchBinaryGetValues(uint8_t channel, uint8_t *current_value, uint8_t *duration_table_8, uint8_t *target_value); diff --git a/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCSwitchMultilevel.cpp b/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCSwitchMultilevel.cpp index 95d46e36..ff04bbf2 100644 --- a/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCSwitchMultilevel.cpp +++ b/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCSwitchMultilevel.cpp @@ -119,7 +119,7 @@ int zuno_CCSwitchMultilevelReport(byte channel, ZUNOCommandPacket_t *packet) { return (ZUNO_COMMAND_ANSWERED); } -static int _set(SwitchMultilevelSetFrame_t *cmd, uint8_t len, uint8_t channel, ZUNOCommandPacketReport_t *frame_report, const ZUNOCommandCmd_t *packet) { +static int _set(SwitchMultilevelSetFrame_t *cmd, uint8_t len, uint8_t channel, ZUNOCommandPacketReport_t *frame_report, const ZUNOCommandCmd_t *packet, const ZUNOCommandHandlerOption_t *options) { uint32_t step; size_t duration; uint8_t value; @@ -176,7 +176,7 @@ static int _set(SwitchMultilevelSetFrame_t *cmd, uint8_t len, uint8_t channel, Z break ; } __zuno_BasicUniversalSetter1P(channel, value); - zunoSendReport(channel + 1); + zunoSendReportSet(channel, options); return (ZUNO_COMMAND_PROCESSED); } @@ -203,7 +203,7 @@ __attribute__((weak)) void zcustom_SWLStartStopHandler(uint8_t channel, bool sta (void) up; (void) cmd; } -int zuno_CCSwitchMultilevelHandler(byte channel, const ZUNOCommandCmd_t *cmd, ZUNOCommandPacketReport_t *frame_report) { +int zuno_CCSwitchMultilevelHandler(byte channel, const ZUNOCommandCmd_t *cmd, ZUNOCommandPacketReport_t *frame_report, const ZUNOCommandHandlerOption_t *options) { int rs; switch(ZW_CMD) { @@ -212,7 +212,7 @@ int zuno_CCSwitchMultilevelHandler(byte channel, const ZUNOCommandCmd_t *cmd, ZU rs = zuno_CCSwitchMultilevelReport(channel, &frame_report->info); break; case SWITCH_MULTILEVEL_SET: - rs = _set((SwitchMultilevelSetFrame_t *)cmd->cmd, cmd->len, channel, frame_report, cmd); + rs = _set((SwitchMultilevelSetFrame_t *)cmd->cmd, cmd->len, channel, frame_report, cmd, options); break ; case SWITCH_MULTILEVEL_START_LEVEL_CHANGE: { diff --git a/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCSwitchMultilevel.h b/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCSwitchMultilevel.h index 4e90fd6a..62793659 100644 --- a/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCSwitchMultilevel.h +++ b/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCSwitchMultilevel.h @@ -139,6 +139,6 @@ void __zuno_CCSwitchMultilevelTimerStop(uint8_t channel); void __zuno_CCSwitchMultilevelGetValues(uint8_t channel, uint8_t *current_value, uint8_t *duration_table_8, uint8_t *target_value); int zuno_CCSwitchMultilevelReport(byte channel, ZUNOCommandPacket_t *packet); -int zuno_CCSwitchMultilevelHandler(byte channel, const ZUNOCommandCmd_t *cmd, ZUNOCommandPacketReport_t *frame_report); +int zuno_CCSwitchMultilevelHandler(byte channel, const ZUNOCommandCmd_t *cmd, ZUNOCommandPacketReport_t *frame_report, const ZUNOCommandHandlerOption_t *options); #endif // SWITCHMULTILEVEL_CC_H \ No newline at end of file diff --git a/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCWindowCovering.c b/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCWindowCovering.c index 1a536526..a7e28c3b 100644 --- a/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCWindowCovering.c +++ b/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCWindowCovering.c @@ -85,7 +85,7 @@ static void _set_duration_0(uint8_t channel, const VG_WINDOW_COVERING_SET_VG *vg } } -static int _set(uint8_t channel, const ZW_WINDOW_COVERING_SET_1BYTE_FRAME *paket) { +static int _set(uint8_t channel, const ZW_WINDOW_COVERING_SET_1BYTE_FRAME *paket, const ZUNOCommandHandlerOption_t *options) { const VG_WINDOW_COVERING_SET_VG *vg; uint32_t mask; uint8_t count; @@ -116,7 +116,7 @@ static int _set(uint8_t channel, const ZW_WINDOW_COVERING_SET_1BYTE_FRAME *paket duration = zuno_CCTimerTicksTable7(duration_encode); if (duration == 0x0) { _set_duration_0(channel, vg, count); - zunoSendReport(channel + 1); + zunoSendReportSet(channel, options); return (ZUNO_COMMAND_PROCESSED); } while (i < count) { @@ -234,7 +234,7 @@ static int _stop_level_change(uint8_t channel, const ZW_WINDOW_COVERING_STOP_LEV } -int zuno_CCWindowCoveringHandler(uint8_t channel, const ZUNOCommandCmd_t *cmd, ZUNOCommandPacketReport_t *frame_report) { +int zuno_CCWindowCoveringHandler(uint8_t channel, const ZUNOCommandCmd_t *cmd, ZUNOCommandPacketReport_t *frame_report, const ZUNOCommandHandlerOption_t *options) { int rs; switch(ZW_CMD) { @@ -242,7 +242,7 @@ int zuno_CCWindowCoveringHandler(uint8_t channel, const ZUNOCommandCmd_t *cmd, Z rs = _supported_report(channel, frame_report); break ; case WINDOW_COVERING_SET: - rs = _set(channel, (const ZW_WINDOW_COVERING_SET_1BYTE_FRAME *)cmd->cmd); + rs = _set(channel, (const ZW_WINDOW_COVERING_SET_1BYTE_FRAME *)cmd->cmd, options); break ; case WINDOW_COVERING_GET: _zunoMarkChannelRequested(channel); @@ -280,7 +280,7 @@ int zuno_CCWindowCoveringReport(uint8_t channel, ZUNOCommandPacket_t *packet) { mask = mask >> 0x1; parameterId++; } - return (ZUNO_COMMAND_PROCESSED); + return (zuno_CCSwitchMultilevelReport(channel, packet)); } void __zunoWindowCoveringSet(uint8_t channel, uint8_t parameterId, uint8_t value) { diff --git a/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCWindowCovering.h b/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCWindowCovering.h index 2527f342..9f78d7ac 100644 --- a/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCWindowCovering.h +++ b/hardware/arduino/zunoG2/cores/ZWSupport/ZWCCWindowCovering.h @@ -281,7 +281,7 @@ void __zuno_CCWindowCoveringDimingStop(uint8_t channel); void __zuno_CCWindowCoveringTimerStop(uint8_t channel); void __zuno_CCWindowCoveringGetValues(uint8_t channel, uint8_t *current_value, uint8_t *duration_table_8, uint8_t *target_value); -int zuno_CCWindowCoveringHandler(uint8_t channel, const ZUNOCommandCmd_t *cmd, ZUNOCommandPacketReport_t *frame_report); +int zuno_CCWindowCoveringHandler(uint8_t channel, const ZUNOCommandCmd_t *cmd, ZUNOCommandPacketReport_t *frame_report, const ZUNOCommandHandlerOption_t *options); int zuno_CCWindowCoveringReport(uint8_t channel, ZUNOCommandPacket_t *packet); #endif // ZWCC_WINDOW_COVERING_H \ No newline at end of file diff --git a/hardware/arduino/zunoG2/cores/ZWSupport/ZWSupport.c b/hardware/arduino/zunoG2/cores/ZWSupport/ZWSupport.c index b28ef7be..398d6ac2 100644 --- a/hardware/arduino/zunoG2/cores/ZWSupport/ZWSupport.c +++ b/hardware/arduino/zunoG2/cores/ZWSupport/ZWSupport.c @@ -323,6 +323,7 @@ byte zuno_findTargetChannel(ZUNOCommandCmd_t * cmd) { bool fillOutgoingRawPacket(ZUNOCommandPacket_t *info, uint8_t * d, uint8_t ch, uint8_t flags, node_id_t dst){ ZUNOCommandCmd_t *p; + info->report.valid = false; p = &info->packet; bool res = true; memset(p, 0, sizeof(p[0x0])); @@ -964,9 +965,14 @@ int __zuno_CommandHandler_Out(int rs){ g_rcv_context.source_node_id = 0; return rs; } + int zuno_CommandHandler(ZUNOCommandCmd_t *cmd) { ZUNOCommandPacketReport_t frame_report; + ZUNOCommandHandlerOption_t options; int result; + bool supervision; + bool multi; + // delay(10); // TST! #ifdef LOGGING_DBG LOGGING_UART.print(millis()); @@ -994,6 +1000,7 @@ int zuno_CommandHandler(ZUNOCommandCmd_t *cmd) { _fillOutgoingPacket(cmd, &frame_report); // If we have multichannel support enabled. // Pass the data through it first + multi = false; #ifdef WITH_CC_MULTICHANNEL if(ZW_CMD_CLASS == COMMAND_CLASS_MULTI_CHANNEL){ result = zuno_CCMultichannel(cmd, &frame_report); @@ -1010,6 +1017,7 @@ int zuno_CommandHandler(ZUNOCommandCmd_t *cmd) { zuno_dbgdumpZWPacakge(cmd); #endif _fillOutgoingPacket(cmd, &frame_report); + multi = true; } } #endif @@ -1020,6 +1028,10 @@ int zuno_CommandHandler(ZUNOCommandCmd_t *cmd) { } result = zuno_CCSupervisionUnpack(result, cmd, &frame_report); if(result == ZUNO_UNKNOWN_CMD || result == ZUNO_COMMAND_UNPACKED) { + if (result == ZUNO_COMMAND_UNPACKED) + supervision = true; + else + supervision = false; if (_testMultiBroadcast(cmd->zw_rx_opts, ZW_CMD_CLASS, ZW_CMD) == false) return __zuno_CommandHandler_Out(ZUNO_COMMAND_BLOCKED); // Check if command fits to any existing channel @@ -1035,6 +1047,7 @@ int zuno_CommandHandler(ZUNOCommandCmd_t *cmd) { LOGGING_UART.print("CHANNEL WAS FOUND:"); LOGGING_UART.println(zuno_ch); #endif + options = ZUNO_COMMAND_HANDLER_DEFAULT(cmd->src_node, multi, supervision, ZW_CMD_CLASS); switch(ZW_CMD_CLASS) { #ifdef WITH_CC_BASIC case COMMAND_CLASS_BASIC: @@ -1043,7 +1056,7 @@ int zuno_CommandHandler(ZUNOCommandCmd_t *cmd) { #endif #ifdef WITH_CC_SWITCH_BINARY case COMMAND_CLASS_SWITCH_BINARY: - result = zuno_CCSwitchBinaryHandler(zuno_ch, cmd, &frame_report); + result = zuno_CCSwitchBinaryHandler(zuno_ch, cmd, &frame_report, &options); break; #endif #ifdef WITH_CC_NOTIFICATION @@ -1053,7 +1066,7 @@ int zuno_CommandHandler(ZUNOCommandCmd_t *cmd) { #endif #ifdef WITH_CC_SWITCH_MULTILEVEL case COMMAND_CLASS_SWITCH_MULTILEVEL: - result = zuno_CCSwitchMultilevelHandler(zuno_ch, cmd, &frame_report); + result = zuno_CCSwitchMultilevelHandler(zuno_ch, cmd, &frame_report, &options); break; #endif #ifdef WITH_CC_METER @@ -1083,7 +1096,7 @@ int zuno_CommandHandler(ZUNOCommandCmd_t *cmd) { #endif #ifdef WITH_CC_WINDOW_COVERING case COMMAND_CLASS_WINDOW_COVERING: - result = zuno_CCWindowCoveringHandler(zuno_ch, cmd, &frame_report); + result = zuno_CCWindowCoveringHandler(zuno_ch, cmd, &frame_report, &options); break; #endif #ifdef WITH_CC_SOUND_SWITCH @@ -1324,6 +1337,45 @@ void zunoSendWakeUpNotification(){ } bool _zunoIsWUPLocked(); bool zunoIsIclusionLatchClosed(); + +void zunoSendReportSet(byte channel, const ZUNOCommandHandlerOption_t *options) { + ZUNOCommandPacketReport_t frame_report; + int rs; + + if (options->supervision == false) { + zunoSendReport(channel + 0x1); + return ; + } + fillOutgoingReportPacketAsync(&frame_report, ZUNO_CFG_CHANNEL(channel).zw_channel); + frame_report.info.report.valid = true; + frame_report.info.report.cmd_class = options->cmd_class; + frame_report.info.report.src_node = options->src_node; + frame_report.info.report.multi = options->multi; + switch(ZUNO_CFG_CHANNEL(channel).type) { + #ifdef WITH_CC_SWITCH_BINARY + case ZUNO_SWITCH_BINARY_CHANNEL_NUMBER: + rs = zuno_CCSwitchBinaryReport(channel, &frame_report.info); + break ; + #endif + #ifdef WITH_CC_SWITCH_MULTILEVEL + case ZUNO_SWITCH_MULTILEVEL_CHANNEL_NUMBER: + rs = zuno_CCSwitchMultilevelReport(channel, &frame_report.info); + break ; + #endif + #ifdef WITH_CC_WINDOW_COVERING + case ZUNO_WINDOW_COVERING_CHANNEL_NUMBER: + rs = zuno_CCWindowCoveringReport(channel, &frame_report.info); + break ; + #endif + default: + rs = ZUNO_COMMAND_ANSWERED; + break ; + } + if (rs != ZUNO_COMMAND_ANSWERED) + return ; + zunoSendZWPackageAdd(&frame_report); +} + void zunoSendReportHandler(uint32_t ticks) { ZUNOCommandPacketReport_t frame; diff --git a/hardware/arduino/zunoG2/cores/ZWSupport/ZWSupport.h b/hardware/arduino/zunoG2/cores/ZWSupport/ZWSupport.h index d1cfb09a..c71f30bd 100644 --- a/hardware/arduino/zunoG2/cores/ZWSupport/ZWSupport.h +++ b/hardware/arduino/zunoG2/cores/ZWSupport/ZWSupport.h @@ -52,6 +52,7 @@ enum{ }; enum { + COMMAND_CLASS_UNKNOWN = 0x0, COMMAND_CLASS_BASIC = 0x20, COMMAND_CLASS_APPLICATION_STATUS = 0x22, COMMAND_CLASS_SWITCH_BINARY = 0x25, @@ -108,9 +109,35 @@ enum{ typedef void zuno_configuration_changed(uint8_t, uint32_t); + +typedef struct ZUNOCommandHandlerOption_s +{ + node_id_t src_node; + bool multi; + bool supervision; + uint8_t cmd_class; +} ZUNOCommandHandlerOption_t; + +#define ZUNO_COMMAND_HANDLER_DEFAULT(_src_node, _multi, _supervision, _cmd_class) \ +{ \ + .src_node = _src_node, \ + .multi = _multi, \ + .supervision = _supervision, \ + .cmd_class = _cmd_class, \ +} \ + +typedef struct ZUNOCommandReport_t +{ + node_id_t src_node; + bool multi; + bool valid; + uint8_t cmd_class; +} ZUNOCommandReport_s; + typedef struct ZUNOCommandPacket_t { ZUNOCommandCmd_t packet; + ZUNOCommandReport_s report; } ZUNOCommandPacket_t; typedef struct ZUNOCommandPacketReport_s @@ -125,6 +152,7 @@ byte zuno_findChannelType(byte type, ZUNOChannelCCS_t* types, byte count); //byte getMaxChannelTypes(); void fillOutgoingReportPacketAsync(ZUNOCommandPacketReport_t *frame, size_t ch); bool fillOutgoingRawPacket(ZUNOCommandPacket_t * p, uint8_t * d, uint8_t ch, uint8_t flags, node_id_t dst); +void zunoSendReportSet(byte channel, const ZUNOCommandHandlerOption_t *options); void ZWCCSetup(); void zunoRFLogger(ZUNOSysEvent_t * ev);