%% ZigBee Smart Energy Frame Generation and Decoding
% This example shows how to generate and decode ZigBee(R) Smart Energy
% frames using the Communications Toolbox(TM) Library for ZigBee and UWB.

% Copyright 2017-2021 The MathWorks, Inc.

%% Background
% The ZigBee standard [ <#15 2> ] specifies network (NET or NWK) and
% application (APP or APL) layers of low-rate wireless personal area
% networks (LR-WPANs). These NET- and APP-layer specifications build upon
% the PHY and MAC specifications of IEEE(R) 802.15.4(TM) [ <#15 3> ]. ZigBee
% devices find application in home automation and sensor networking and are
% highly relevant to the Internet of Things (IoT) trend.
%
% The ZigBee application layer consists of multiple sub-layers: _(i)_ the
% Application Support Sublayer (APS), and _(ii)_ the ZigBee Cluster Library
% (ZCL). 
%
% <<zigbeeFrameFormat.png>>
%
% The APS and ZCL *headers* follow a format that is common for all
% application profiles and ZigBee clusters (see Clauses 2.2.5 in [ <#15 2>
% ] and 2.4 in [ <#15 4> ], respectively). The ZCL *payload* is used only
% by some clusters and it follows a cluster-specific format. The generic
% APS and ZCL header generation and decoding is illustrated in the
% <docid:comm_ug#example-zigbeeHomeAutomationExample ZigBee Home Automation
% Frame Generation and Decoding> example. This example illustrates the
% cluster-specific generation and decoding of *ZigBee Smart Energy ZCL
% payloads*.

%% Clusters and Commands
% Out of the 7 clusters used in the Smart Energy application profile,
% this example generates and decodes frames for the following clusters:
%
% # *Demand Response and Load Control (DRLC) cluster*: This cluster
% advertises changes to energy demand and consumption. This example
% illustrates frame generation and decoding for the *Load Control Event
% command* (described in Clause 10.3.2.3.1 of [ <#15 4> ]).
% # *Price cluster*: This cluster communicates Energy, Gas or Water pricing
% information. This example illustrates frame generation and decoding for
% the *Get Current Price* and *Publish Price* commands (described in Clause
% 10.2.2.3.1 of [ <#15 4> ]).
% # *Messaging cluster*: This cluster exchanges text messages between
% ZigBee devices. This example illustrates frame generation and decoding
% for the *Display Message command* (described in Clause 10.5.2.3.1 of [
% <#15 4> ]).
%
% In addition to the illustrated commands, the implementation offered in
% this example also generates and decodes frames of the following commands:
%
% <<zigbeeSmartEnergyTable.png>>

%% Generating and Decoding ZCL Payload of DRLC Cluster
% A <matlab:edit('zigbee.DRLCFrameConfig') zigbee.DRLCFrameConfig>
% configuration object is used both in generating and decoding ZCL payloads
% for the Demand Response and Load Control (DRLC) cluster. Such objects
% describe a DRLC cluster payload and all applicable properties. The
% <matlab:edit('zigbee.DRLCFrameGenerator')
% zigbee.DRLCFrameGenerator> function accepts a
% <matlab:edit('zigbee.DRLCFrameConfig') zigbee.DRLCFrameConfig>
% object describing the DRLC cluster payload and outputs the payload in
% bytes. The following code creates a ZCL payload for a command that sets
% the set point of heating devices to 23.5 C.

% Creation of DRLC cluster configuration object
drlcConfigTx = zigbee.DRLCFrameConfig('CommandType', 'Load Control Event', ...
                                      'EventID', '00000001', 'DeviceClass', 'Strip Heaters/Baseboard Heaters', ...
                                      'HeatingSetPoint', 23.5);

% DRLC cluster frame generation (ZCL payload)
drlcPayload = zigbee.DRLCFrameGenerator(drlcConfigTx);

%%
% The <matlab:edit('zigbee.DRLCFrameDecoder') zigbee.DRLCFrameDecoder>
% function accepts the command name and a DRLC cluster payload in bytes and
% outputs a <matlab:edit('zigbee.DRLCFrameConfig') zigbee.DRLCFrameConfig>
% object describing the DRLC cluster payload. The command name is retrieved
% from the decoding of the ZCL header. See section 'Decoding ZCL Header of
% Home Automation ZigBee Radios' in the
% <docid:comm_ug#example-zigbeeHomeAutomationExample ZigBee Home Automation
% Frame Generation and Decoding> example.

drlcConfigRx = zigbee.DRLCFrameDecoder('Load Control Event', drlcPayload)

%% Generating and Decoding ZCL Payload of Price Cluster
% A <matlab:edit('zigbee.PriceFrameConfig') zigbee.PriceFrameConfig>
% configuration object is used both in generating and decoding ZCL payloads
% for the Price cluster. Such objects describe a Price cluster payload and
% all applicable properties. The <matlab:edit('zigbee.PriceFrameGenerator')
% zigbee.PriceFrameGenerator> function accepts a
% <matlab:edit('zigbee.PriceFrameConfig') zigbee.PriceFrameConfig> object
% describing the Price cluster payload and outputs the payload in bytes.
% The following code creates a ZCL payload for a command that requests the
% current price of a commodity.

% Creation of Price cluster configuration object
priceConfigTx = zigbee.PriceFrameConfig('CommandType', 'Get Current Price');

% Price cluster frame generation (ZCL payload)
pricePayload = zigbee.PriceFrameGenerator(priceConfigTx);

%%
% The <matlab:edit('zigbee.PriceFrameDecoder') zigbee.PriceFrameDecoder>
% function accepts the command name and a Price cluster payload in bytes
% and outputs a <matlab:edit('zigbee.PriceFrameConfig')
% zigbee.PriceFrameConfig> object describing the Price cluster payload. The
% command name is retrieved from the decoding of the ZCL header. See
% section 'Decoding ZCL Header of Home Automation ZigBee Radios' in the
% <docid:comm_ug#example-zigbeeHomeAutomationExample ZigBee Home Automation
% Frame Generation and Decoding> example.

priceConfigRx = zigbee.PriceFrameDecoder('Get Current Price', pricePayload)

%%
% Upon receiving a 'Get Current Price' command, a server replies with a
% 'Publish Price' command.
priceConfigTx = zigbee.PriceFrameConfig('CommandType', 'Publish Price', 'Price', 0.4899, 'Duration', 14400);
pricePayload = zigbee.PriceFrameGenerator(priceConfigTx);

%%
% The client device can then decode the published price:
priceConfigRx = zigbee.PriceFrameDecoder('Publish Price', pricePayload)


%% Generating and Decoding ZCL Payload of Messaging Cluster
% A <matlab:edit('zigbee.MessagingFrameConfig')
% zigbee.MessagingFrameConfig> configuration object is used both in
% generating and decoding ZCL payloads for the Messaging cluster. Such
% objects describe a Messaging cluster payload and all applicable properties.
% The <matlab:edit('zigbee.MessagingFrameGenerator') zigbee.MessagingFrameGenerator>
% function accepts a <matlab:edit('zigbee.MessagingFrameConfig')
% zigbee.MessagingFrameConfig> object describing the Messaging cluster payload and
% outputs the payload in bytes. The following code creates a ZCL payload
% for a command that displays a message.

% Creation of messaging cluster configuration object
messageID = 1234;
messagingConfigTx = zigbee.MessagingFrameConfig('CommandType', 'Display Message', ...
                                      'MessageID', messageID, 'Message', 'This is a custom message', 'Duration', 90);

% Messaging cluster frame generation (ZCL payload)
displayMessagePayload = zigbee.MessagingFrameGenerator(messagingConfigTx);

%%
% The <matlab:edit('zigbee.MessagingFrameDecoder')
% zigbee.MessagingFrameDecoder> function accepts the command name and a
% Messaging cluster payload in bytes and outputs a
% <matlab:edit('zigbee.MessagingFrameConfig') zigbee.MessagingFrameConfig>
% object describing the Messagingcluster payload. The command name is
% retrieved from the decoding of the ZCL header. See section 'Decoding ZCL
% Header of Home Automation ZigBee Radios' in the
% <docid:comm_ug#example-zigbeeHomeAutomationExample ZigBee Home Automation
% Frame Generation and Decoding> example.

messagingConfigRx = zigbee.MessagingFrameDecoder('Display Message', displayMessagePayload)

%%
% A server that displays a message also has the ability to cancel the message
% using the "Cancel Message" command:

cancelMsgConfig = zigbee.MessagingFrameConfig('CommandType', 'Cancel Message', ...
                                              'MessageID', messageID);
cancelMessagePayload = zigbee.MessagingFrameGenerator(messagingConfigTx);

%%
% Clients can then decode the Cancel Message command:
messagingConfigRx = zigbee.MessagingFrameDecoder('Cancel Message', cancelMessagePayload)

%% Wireshark Decoding
% The generated Messaging frames can be converted to a PCAP-formatted file
% that can be analyzed and visualized with Wireshark [ <#15 5> ]. This
% process can serve as an additional verification step advocating that the
% Communications Toolbox Library for the ZigBee Protocol generates
% and decodes frames in a standard-compliant manner.
%
% The PCAP file needs the ZCL payloads to be enclosed with headers from all
% other layers and sublayers (MAC, NET, APS, ZCL). This task is performed
% by the following commands.

zllProfileID = zigbee.profileID('Smart Energy'); % ZLL profile ID
msgClusterID = zigbee.clusterID('Messaging'); % Messaging cluster ID

payloadsWithInfo(1) = struct('Payload', displayMessagePayload,  'ProfileID',   zllProfileID, ...
                             'ClusterSpecific', true,           'ClusterID',   msgClusterID, 'CommandType', 'Display Message', 'Direction', 'Downlink');
payloadsWithInfo(2) = struct('Payload', cancelMessagePayload,   'ProfileID',   zllProfileID, ...
                             'ClusterSpecific', true,           'ClusterID',   msgClusterID, 'CommandType', 'Cancel Message',  'Direction', 'Downlink');
                           
% Add headers from other layers/sublayers:
MPDUs = zigbeeAddProtocolHeaders(payloadsWithInfo);

% Export MPDUs to a PCAP format
zigbeeExportToPcap(MPDUs, 'zigbeeSmartEnergy.pcap');

% Open PCAP file with Wireshark

%% Further Exploration
% You can further explore the following generator and decoding functions,
% as well as the configuration object:
%
% * <matlab:edit('zigbee.DRLCFrameConfig') zigbee.DRLCFrameConfig>, <matlab:edit('zigbee.DRLCFrameGenerator') zigbee.DRLCFrameGenerator>, <matlab:edit('zigbee.DRLCFrameDecoder') zigbee.DRLCFrameDecoder>
% * <matlab:edit('zigbee.PriceFrameConfig') zigbee.PriceFrameConfig>, <matlab:edit('zigbee.PriceFrameGenerator') zigbee.PriceFrameGenerator>, <matlab:edit('zigbee.PriceFrameDecoder') zigbee.PriceFrameDecoder>
% * <matlab:edit('zigbee.MessagingFrameConfig') zigbee.MessagingFrameConfig>, <matlab:edit('zigbee.MessagingFrameGenerator') zigbee.MessagingFrameGenerator>, <matlab:edit('zigbee.MessagingFrameDecoder') zigbee.MessagingFrameDecoder>
% * <matlab:edit('zigbee.APSFrameConfig') zigbee.APSFrameConfig>, <matlab:edit('zigbee.APSFrameGenerator') zigbee.APSFrameGenerator>, <matlab:edit('zigbee.APSFrameDecoder') zigbee.APSFrameDecoder>
% * <matlab:edit('zigbee.ZCLFrameConfig') zigbee.ZCLFrameConfig>, <matlab:edit('zigbee.ZCLFrameGenerator') zigbee.ZCLFrameGenerator>, <matlab:edit('zigbee.ZCLFrameDecoder') zigbee.ZCLFrameDecoder>

%% Selected Bibliography
% # ZigBee Alliance, ZigBee Smart Energy Standard, Revision 19, Version 1.2a, December 3, 2014.
% # ZigBee Alliance, ZigBee Specification Document 053474r17, 2007
% # IEEE 802.15.4-2011 - IEEE Standard for Local and metropolitan area
% networks--Part 15.4: Low-Rate Wireless Personal Area Networks (LR-WPANs)
% # ZigBee Alliance, ZigBee Cluster Library Specification, Revision 6, Jan. 2016.
% # Wireshark software: https://www.wireshark.org/

displayEndOfDemoMessage(mfilename)
