Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / app / clusters / messaging-server / messaging-server.cpp
1 /**
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *
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
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 /**
19  *
20  *    Copyright (c) 2020 Silicon Labs
21  *
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
25  *
26  *        http://www.apache.org/licenses/LICENSE-2.0
27  *
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.
33  */
34 /***************************************************************************
35  * @file
36  * @brief Routines for the Messaging Server plugin,
37  *which implements the server side of the Messaging
38  *cluster.
39  *******************************************************************************
40  ******************************************************************************/
41
42 #include "messaging-server.h"
43 #include "../../include/af.h"
44
45 using namespace chip;
46
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];
51
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)
57
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)
63 {
64     uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_MESSAGING_CLUSTER_ID);
65
66     if (ep == 0xFF)
67     {
68         return false;
69     }
70
71     return (messageIsValid(ep) && messageIsActive(ep) &&
72             (messageIsForever(ep) ||
73              (emberAfGetCurrentTime() < msgTable[ep].startTime + (uint32_t) msgTable[ep].durationInMinutes * 60)));
74 }
75
76 void emberAfMessagingClusterServerInitCallback(EndpointId endpoint)
77 {
78     uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_MESSAGING_CLUSTER_ID);
79
80     if (ep == 0xFF)
81     {
82         return;
83     }
84
85     msgTable[ep].messageStatusControl &= ~VALID;
86 }
87
88 bool emberAfMessagingClusterGetLastMessageCallback(void)
89 {
90     EndpointId endpoint = emberAfCurrentEndpoint();
91     EmberAfPluginMessagingServerMessage message;
92     emberAfMessagingClusterPrintln("RX: GetLastMessage");
93     if (emberAfPluginMessagingServerGetMessage(endpoint, &message))
94     {
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();
100     }
101     else
102     {
103         emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_NOT_FOUND);
104     }
105     return true;
106 }
107
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)
112 #else
113 bool emberAfMessagingClusterMessageConfirmationCallback(uint32_t messageId, uint32_t confirmationTime,
114                                                         uint8_t messageConfirmationControl, uint8_t * messageResponse)
115 #endif
116 {
117     emberAfMessagingClusterPrintln("RX: MessageConfirmation 0x%4x, 0x%4x", messageId, confirmationTime);
118     emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
119     return true;
120 }
121
122 bool emberAfPluginMessagingServerGetMessage(EndpointId endpoint, EmberAfPluginMessagingServerMessage * message)
123 {
124     uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_MESSAGING_CLUSTER_ID);
125
126     if (ep == 0xFF)
127     {
128         return false;
129     }
130
131     MEMMOVE(message, &msgTable[ep], sizeof(EmberAfPluginMessagingServerMessage));
132
133     // Clear out our internal bits from the message control.
134     message->messageStatusControl &= ~ZCL_MESSAGING_CLUSTER_RESERVED_MASK;
135
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))
142     {
143         message->startTime = ZCL_MESSAGING_CLUSTER_START_TIME_NOW;
144         if (!messageIsForever(ep))
145         {
146             message->durationInMinutes -= ((emberAfGetCurrentTime() - msgTable[ep].startTime) / 60);
147         }
148     }
149     return messageIsCurrentOrScheduled(endpoint);
150 }
151
152 void emberAfPluginMessagingServerSetMessage(EndpointId endpoint, const EmberAfPluginMessagingServerMessage * message)
153 {
154     uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_MESSAGING_CLUSTER_ID);
155
156     if (ep == 0xFF)
157     {
158         return;
159     }
160
161     if (message == NULL)
162     {
163         msgTable[ep].messageStatusControl &= ~ACTIVE;
164         return;
165     }
166
167     MEMMOVE(&msgTable[ep], message, sizeof(EmberAfPluginMessagingServerMessage));
168
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)
172     {
173         msgTable[ep].messageStatusControl |= NOW;
174         msgTable[ep].startTime = emberAfGetCurrentTime();
175     }
176     else
177     {
178         msgTable[ep].messageStatusControl &= ~NOW;
179     }
180
181     msgTable[ep].messageStatusControl |= (VALID | ACTIVE);
182 }
183
184 void emAfPluginMessagingServerPrintInfo(EndpointId endpoint)
185 {
186     uint8_t ep = emberAfFindClusterServerEndpointIndex(endpoint, ZCL_MESSAGING_CLUSTER_ID);
187
188     if (ep == 0xFF)
189     {
190         return;
191     }
192
193     emberAfMessagingClusterPrintln("= Server Message =");
194     emberAfMessagingClusterFlush();
195
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();
209 }
210
211 void emberAfPluginMessagingServerDisplayMessage(EmberNodeId nodeId, uint8_t srcEndpoint, uint8_t dstEndpoint)
212 {
213     EmberStatus status;
214     EmberAfPluginMessagingServerMessage message;
215     if (!emberAfPluginMessagingServerGetMessage(srcEndpoint, &message))
216     {
217         emberAfMessagingClusterPrintln("invalid msg");
218         return;
219     }
220
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)
228     {
229         emberAfMessagingClusterPrintln("Error in display %x", status);
230     }
231 }
232
233 void emberAfPluginMessagingServerCancelMessage(EmberNodeId nodeId, uint8_t srcEndpoint, uint8_t dstEndpoint)
234 {
235     EmberStatus status;
236     EmberAfPluginMessagingServerMessage message;
237
238     // Nullify the current message before sending the cancellation.
239     emberAfPluginMessagingServerSetMessage(srcEndpoint, NULL);
240
241     // Then send the response
242     emberAfPluginMessagingServerGetMessage(srcEndpoint, &message);
243
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)
250     {
251         emberAfMessagingClusterPrintln("Error in cancel %x", status);
252     }
253 }