3 * Copyright (c) 2020 Project CHIP Authors
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
20 * Copyright (c) 2020 Silicon Labs
22 * Licensed under the Apache License, Version 2.0 (the "License");
23 * you may not use this file except in compliance with the License.
24 * You may obtain a copy of the License at
26 * http://www.apache.org/licenses/LICENSE-2.0
28 * Unless required by applicable law or agreed to in writing, software
29 * distributed under the License is distributed on an "AS IS" BASIS,
30 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31 * See the License for the specific language governing permissions and
32 * limitations under the License.
34 /***************************************************************************
36 * @brief Routines for the Messaging Server plugin,
37 *which implements the server side of the Messaging
39 *******************************************************************************
40 ******************************************************************************/
42 #include "messaging-server.h"
43 #include "../../include/af.h"
47 // The internal message is stored in the same structure type that is defined
48 // publicly. The internal state of the message is stored in the
49 // messageStatusControl field
50 static EmberAfPluginMessagingServerMessage msgTable[EMBER_AF_MESSAGING_CLUSTER_SERVER_ENDPOINT_COUNT];
52 // These bits are used by the messageStatusControl to indicate whether or not
53 // a message is valid, active, or if it is a "send now" message
54 #define VALID EMBER_BIT(0)
55 #define ACTIVE EMBER_BIT(1)
56 #define NOW EMBER_BIT(2)
58 #define messageIsValid(ep) (msgTable[ep].messageStatusControl & VALID)
59 #define messageIsActive(ep) (msgTable[ep].messageStatusControl & ACTIVE)
60 #define messageIsNow(ep) (msgTable[ep].messageStatusControl & NOW)
61 #define messageIsForever(ep) (msgTable[ep].durationInMinutes == ZCL_MESSAGING_CLUSTER_DURATION_UNTIL_CHANGED)
62 static bool messageIsCurrentOrScheduled(EndpointId endpoint)
64 uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_MESSAGING_CLUSTER_ID);
71 return (messageIsValid(ep) && messageIsActive(ep) &&
72 (messageIsForever(ep) ||
73 (emberAfGetCurrentTime() < msgTable[ep].startTime + (uint32_t) msgTable[ep].durationInMinutes * 60)));
76 void emberAfMessagingClusterServerInitCallback(EndpointId endpoint)
78 uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_MESSAGING_CLUSTER_ID);
85 msgTable[ep].messageStatusControl &= ~VALID;
88 bool emberAfMessagingClusterGetLastMessageCallback(void)
90 EndpointId endpoint = emberAfCurrentEndpoint();
91 EmberAfPluginMessagingServerMessage message;
92 emberAfMessagingClusterPrintln("RX: GetLastMessage");
93 if (emberAfPluginMessagingServerGetMessage(endpoint, &message))
95 emberAfFillExternalBuffer((ZCL_CLUSTER_SPECIFIC_COMMAND | ZCL_FRAME_CONTROL_SERVER_TO_CLIENT), ZCL_MESSAGING_CLUSTER_ID,
96 ZCL_DISPLAY_MESSAGE_COMMAND_ID, "wuwvsu", message.messageId, message.messageControl,
97 message.startTime, message.durationInMinutes, message.message, message.extendedMessageControl);
98 emberAfGetCommandApsFrame()->options |= EMBER_APS_OPTION_SOURCE_EUI64;
99 emberAfSendResponse();
103 emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_NOT_FOUND);
108 #if defined(EMBER_AF_HAS_SPEC_VERSIONS_SE_1_0) || defined(EMBER_AF_HAS_SPEC_VERSIONS_SE_1_1B) || \
109 defined(EMBER_AF_HAS_SPEC_VERSIONS_SE_1_0) || defined(EMBER_AF_HAS_SPEC_VERSIONS_SE_1_1) || \
110 defined(EMBER_AF_HAS_SPEC_VERSIONS_SE_1_1A)
111 bool emberAfMessagingClusterMessageConfirmationCallback(uint32_t messageId, uint32_t confirmationTime)
113 bool emberAfMessagingClusterMessageConfirmationCallback(uint32_t messageId, uint32_t confirmationTime,
114 uint8_t messageConfirmationControl, uint8_t * messageResponse)
117 emberAfMessagingClusterPrintln("RX: MessageConfirmation 0x%4x, 0x%4x", messageId, confirmationTime);
118 emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
122 bool emberAfPluginMessagingServerGetMessage(EndpointId endpoint, EmberAfPluginMessagingServerMessage * message)
124 uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_MESSAGING_CLUSTER_ID);
131 MEMMOVE(message, &msgTable[ep], sizeof(EmberAfPluginMessagingServerMessage));
133 // Clear out our internal bits from the message control.
134 message->messageStatusControl &= ~ZCL_MESSAGING_CLUSTER_RESERVED_MASK;
136 // If the message is expired or it has an absolute time, set the start time
137 // and duration to the original start time and duration. For "start now"
138 // messages that are current or scheduled, set the start time to the special
139 // value for "now" and set the duration to the remaining time, if it is not
140 // already the special value for "until changed."
141 if (messageIsCurrentOrScheduled(endpoint) && messageIsNow(ep))
143 message->startTime = ZCL_MESSAGING_CLUSTER_START_TIME_NOW;
144 if (!messageIsForever(ep))
146 message->durationInMinutes -= ((emberAfGetCurrentTime() - msgTable[ep].startTime) / 60);
149 return messageIsCurrentOrScheduled(endpoint);
152 void emberAfPluginMessagingServerSetMessage(EndpointId endpoint, const EmberAfPluginMessagingServerMessage * message)
154 uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_MESSAGING_CLUSTER_ID);
163 msgTable[ep].messageStatusControl &= ~ACTIVE;
167 MEMMOVE(&msgTable[ep], message, sizeof(EmberAfPluginMessagingServerMessage));
169 // Rember if this is a "start now" message, but store the start time as the
170 // current time so the duration can be adjusted.
171 if (msgTable[ep].startTime == ZCL_MESSAGING_CLUSTER_START_TIME_NOW)
173 msgTable[ep].messageStatusControl |= NOW;
174 msgTable[ep].startTime = emberAfGetCurrentTime();
178 msgTable[ep].messageStatusControl &= ~NOW;
181 msgTable[ep].messageStatusControl |= (VALID | ACTIVE);
184 void emAfPluginMessagingServerPrintInfo(EndpointId endpoint)
186 uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_MESSAGING_CLUSTER_ID);
193 emberAfMessagingClusterPrintln("= Server Message =");
194 emberAfMessagingClusterFlush();
196 emberAfMessagingClusterPrintln(" vld: %s", (messageIsValid(ep) ? "YES" : "NO"));
197 emberAfMessagingClusterPrintln(" act: %s", (messageIsCurrentOrScheduled(endpoint) ? "YES" : "NO"));
198 emberAfMessagingClusterPrintln(" id: 0x%4x", msgTable[ep].messageId);
199 emberAfMessagingClusterPrintln(" mc: 0x%x", (msgTable[ep].messageControl & ~ZCL_MESSAGING_CLUSTER_RESERVED_MASK));
200 emberAfMessagingClusterPrintln(" st: 0x%4x", msgTable[ep].startTime);
201 emberAfMessagingClusterPrintln(" now: %s", (messageIsNow(ep) ? "YES" : "NO"));
202 emberAfMessagingClusterPrintln("time: 0x%4x", emberAfGetCurrentTime());
203 emberAfMessagingClusterPrintln(" dur: 0x%2x", msgTable[ep].durationInMinutes);
204 emberAfMessagingClusterFlush();
205 emberAfMessagingClusterPrint(" mes: \"");
206 emberAfMessagingClusterPrintString(msgTable[ep].message);
207 emberAfMessagingClusterPrintln("\"");
208 emberAfMessagingClusterFlush();
211 void emberAfPluginMessagingServerDisplayMessage(EmberNodeId nodeId, uint8_t srcEndpoint, uint8_t dstEndpoint)
214 EmberAfPluginMessagingServerMessage message;
215 if (!emberAfPluginMessagingServerGetMessage(srcEndpoint, &message))
217 emberAfMessagingClusterPrintln("invalid msg");
221 emberAfFillExternalBuffer((ZCL_CLUSTER_SPECIFIC_COMMAND | ZCL_FRAME_CONTROL_SERVER_TO_CLIENT), ZCL_MESSAGING_CLUSTER_ID,
222 ZCL_DISPLAY_MESSAGE_COMMAND_ID, "wuwvsu", message.messageId, message.messageControl,
223 message.startTime, message.durationInMinutes, message.message, message.extendedMessageControl);
224 emberAfSetCommandEndpoints(srcEndpoint, dstEndpoint);
225 emberAfGetCommandApsFrame()->options |= EMBER_APS_OPTION_SOURCE_EUI64;
226 status = emberAfSendCommandUnicast(EMBER_OUTGOING_DIRECT, nodeId);
227 if (status != EMBER_SUCCESS)
229 emberAfMessagingClusterPrintln("Error in display %x", status);
233 void emberAfPluginMessagingServerCancelMessage(EmberNodeId nodeId, uint8_t srcEndpoint, uint8_t dstEndpoint)
236 EmberAfPluginMessagingServerMessage message;
238 // Nullify the current message before sending the cancellation.
239 emberAfPluginMessagingServerSetMessage(srcEndpoint, NULL);
241 // Then send the response
242 emberAfPluginMessagingServerGetMessage(srcEndpoint, &message);
244 emberAfFillExternalBuffer((ZCL_CLUSTER_SPECIFIC_COMMAND | ZCL_FRAME_CONTROL_SERVER_TO_CLIENT), ZCL_MESSAGING_CLUSTER_ID,
245 ZCL_CANCEL_MESSAGE_COMMAND_ID, "wu", message.messageId, message.messageControl);
246 emberAfSetCommandEndpoints(srcEndpoint, dstEndpoint);
247 emberAfGetCommandApsFrame()->options |= EMBER_APS_OPTION_SOURCE_EUI64;
248 status = emberAfSendCommandUnicast(EMBER_OUTGOING_DIRECT, nodeId);
249 if (status != EMBER_SUCCESS)
251 emberAfMessagingClusterPrintln("Error in cancel %x", status);