void emberAfPluginMessagingServerCancelMessage(EmberNodeId nodeId,
                                               uint8_t srcEndpoint,
                                               uint8_t dstEndpoint)
{
  EmberStatus status;
  EmberAfPluginMessagingServerMessage message;

  // Nullify the current message before sending the cancellation.
  emberAfPluginMessagingServerSetMessage(srcEndpoint, NULL);

  // Then send the response
  emberAfPluginMessagingServerGetMessage(srcEndpoint, &message);

  emberAfFillCommandMessagingClusterCancelMessage(message.messageId,
                                                  message.messageControl);
  emberAfSetCommandEndpoints(srcEndpoint, dstEndpoint);
  emberAfGetCommandApsFrame()->options |= EMBER_APS_OPTION_SOURCE_EUI64;
  status = emberAfSendCommandUnicast(EMBER_OUTGOING_DIRECT, nodeId);
  if(status != EMBER_SUCCESS) {
    emberAfMessagingClusterPrintln("Error in cancel %x", status);
  }
}
static CommissioningState_t BroadcastIdentifyQuery(void) {
  emberAfDebugPrintln("DEBUG: Broadcast ID Query");
  // Make Identify cluster's command to send an Identify Query
  emberAfFillCommandIdentifyClusterIdentifyQuery();
  emberAfSetCommandEndpoints(dev_comm_session.ep, EMBER_BROADCAST_ENDPOINT);
  // Broadcast Identify Query
  EmberStatus status =
      emberAfSendCommandBroadcast(EMBER_SLEEPY_BROADCAST_ADDRESS);

  if (status != EMBER_SUCCESS) {
    // Exceptional case. Stop commissioning
    SetNextEvent(SC_EZEV_UNKNOWN);
  }

  // Schedule event for awaiting for responses for 1 second
  // TODO: Set hardcoded value as plugin's option parameter as optional value
  emberEventControlSetDelayMS(StateMachineEvent,
                              SIMPLE_COMMISSIONING_IDENTIFY_RESPONSE_WAIT_TIME());
  // If Identify Query responses won't be received state machine just will call
  // Timeout handler
  SetNextEvent(SC_EZEV_TIMEOUT);

  return SC_EZ_WAIT_IDENT_RESP;
}
void emberAfPluginMessagingServerDisplayMessage(EmberNodeId nodeId,
                                                uint8_t srcEndpoint,
                                                uint8_t dstEndpoint)
{
  EmberStatus status;
  EmberAfPluginMessagingServerMessage message;
  if (!emberAfPluginMessagingServerGetMessage(srcEndpoint, &message)) {
    emberAfMessagingClusterPrintln("invalid msg");
    return;
  }

  emberAfFillCommandMessagingClusterDisplayMessage(message.messageId,
                                                   message.messageControl,
                                                   message.startTime,
                                                   message.durationInMinutes,
                                                   message.message,
                                                   message.extendedMessageControl);
  emberAfSetCommandEndpoints(srcEndpoint, dstEndpoint);
  emberAfGetCommandApsFrame()->options |= EMBER_APS_OPTION_SOURCE_EUI64;
  status = emberAfSendCommandUnicast(EMBER_OUTGOING_DIRECT, nodeId);
  if(status != EMBER_SUCCESS) {
    emberAfMessagingClusterPrintln("Error in display %x", status);
  }
}
bool emberAfPrepaymentClusterChangePaymentModeCallback(uint32_t providerId,
                                                          uint32_t issuerEventId,
                                                          uint32_t implementationDateTime,
                                                          PaymentControlConfiguration proposedPaymentControlConfiguration,
                                                          uint32_t cutOffValue){

  // The requester can be obtained with emberAfResponseDestination;
  EmberNodeId nodeId;
  uint8_t endpoint;
  uint8_t srcEndpoint, dstEndpoint;
  FriendlyCredit friendlyCredit;
  uint32_t friendlyCreditCalendarId;
  uint32_t emergencyCreditLimit;
  uint32_t emergencyCreditThreshold;
  uint8_t  dataType;
  uint8_t  i;

  emberAfPrepaymentClusterPrintln("RX: ChangePaymentMode, pid=0x%4x, eid=0x%4x, cfg=0x%2x", providerId, issuerEventId, proposedPaymentControlConfiguration);
  endpoint = emberAfCurrentEndpoint();

  if( cutOffValue != CUTOFF_UNCHANGED ){
#ifdef ZCL_USING_PREPAYMENT_CLUSTER_CUT_OFF_VALUE_ATTRIBUTE
    emberAfWriteAttribute( endpoint, ZCL_PREPAYMENT_CLUSTER_ID,
                          ZCL_CUT_OFF_VALUE_ATTRIBUTE_ID, CLUSTER_MASK_SERVER,
                          (uint8_t *)&cutOffValue, ZCL_INT32S_ATTRIBUTE_TYPE );
#endif
  }

  emberAfPrepaymentSchedulePrepaymentMode( emberAfCurrentEndpoint(), providerId, issuerEventId, implementationDateTime,
                                           proposedPaymentControlConfiguration );

  // Setup the friendly credit & emergency credit limit attributes.
#ifdef EMBER_AF_PLUGIN_CALENDAR_CLIENT
  i = emberAfPluginCalendarClientGetCalendarIndexByType( endpoint, EMBER_ZCL_CALENDAR_TYPE_FRIENDLY_CREDIT_CALENDAR );
  friendlyCredit = ( i < EMBER_AF_PLUGIN_CALENDAR_CLIENT_CALENDARS ) ? 0x01 : 0x00;
  friendlyCreditCalendarId = emberAfPluginCalendarClientGetCalendarId( endpoint, i );
#else
  friendlyCredit = 0x00;
  friendlyCreditCalendarId = EMBER_AF_PLUGIN_CALENDAR_CLIENT_INVALID_CALENDAR_ID;
#endif

#if (!defined ZCL_USING_PREPAYMENT_CLUSTER_EMERGENCY_CREDIT_LIMIT_ALLOWANCE_ATTRIBUTE) || \
    (!defined ZCL_USING_PREPAYMENT_CLUSTER_EMERGENCY_CREDIT_THRESHOLD_ATTRIBUTE)
#error "Prepayment Emergency Credit Limit/Allowance and Threshold attributes required for this plugin!"
#endif
  emberAfReadAttribute( emberAfCurrentEndpoint(), ZCL_PREPAYMENT_CLUSTER_ID,
                        ZCL_EMERGENCY_CREDIT_LIMIT_ALLOWANCE_ATTRIBUTE_ID, CLUSTER_MASK_SERVER,
                        (uint8_t *)&emergencyCreditLimit, 4, &dataType );
  emberAfReadAttribute( emberAfCurrentEndpoint(), ZCL_PREPAYMENT_CLUSTER_ID,
                        ZCL_EMERGENCY_CREDIT_THRESHOLD_ATTRIBUTE_ID, CLUSTER_MASK_SERVER,
                        (uint8_t *)&emergencyCreditThreshold, 4, &dataType );
  nodeId = emberAfCurrentCommand()->source;
  srcEndpoint = emberAfGetCommandApsFrame()->destinationEndpoint;
  dstEndpoint = emberAfGetCommandApsFrame()->sourceEndpoint;
  emberAfSetCommandEndpoints( srcEndpoint, dstEndpoint );
  
  emberAfFillCommandPrepaymentClusterChangePaymentModeResponse( friendlyCredit, friendlyCreditCalendarId, 
                                                                 emergencyCreditLimit, emergencyCreditThreshold );
  emberAfSendCommandUnicast( EMBER_OUTGOING_DIRECT, nodeId );
  return true;
}