int basic_client( const wpan_envelope_t FAR *envelope, void FAR *context) { zcl_command_t zcl; if (zcl_command_build( &zcl, envelope, context) == 0 && zcl.command == ZCL_CMD_READ_ATTRIB_RESP && ZCL_CMD_MATCH( &zcl.frame_control, GENERAL, SERVER_TO_CLIENT, PROFILE)) { // response to our read basic attr return basic_parse( &zcl); } return zcl_general_command( envelope, context); }
/* START _FUNCTION DESCRIPTION ******************************************* _zcl_basic_server <zcl_basic.c> SYNTAX: int _zcl_basic_server( const wpan_envelope_t FAR *envelope, void FAR *context) DESCRIPTION: Handles commands for the Basic Server Cluster. Currently supports the only command ID in the spec, 0x00 - Reset to Factory Defaults. NOTE: You must define the macro ZCL_FACTORY_RESET_FN in your program, and have it point to a function to be called when a factory reset command is sent. **************************************************************************/ int _zcl_basic_server( const wpan_envelope_t FAR *envelope, void FAR *context) { zcl_command_t zcl; if (zcl_command_build( &zcl, envelope, context) == 0 && ZCL_CMD_MATCH( &zcl.frame_control, GENERAL, CLIENT_TO_SERVER, CLUSTER)) { // This function only handles command 0x00, reset to factory defaults. if (zcl.command == ZCL_BASIC_CMD_FACTORY_DEFAULTS) { #ifdef ZCL_BASIC_VERBOSE printf( "%s: resetting to factory defaults\n", __FUNCTION__); #endif ZCL_FACTORY_RESET_FN(); return zcl_default_response( &zcl, ZCL_STATUS_SUCCESS); } } return zcl_general_command( envelope, context); }
int zcl_comm_clust_handler( const wpan_envelope_t FAR *envelope, void FAR *context) { // Make sure frame is not manufacturer-specific, client-to-server and // a cluster command (not "profile-wide"). if (envelope != NULL && ZCL_CMD_MATCH( envelope->payload, GENERAL, CLIENT_TO_SERVER, CLUSTER)) { const struct { zcl_header_nomfg_t zcl; union { zcl_comm_restart_device_cmd_t restart_dev; zcl_comm_save_startup_param_t save_startup; zcl_comm_restore_startup_param_t restore_startup; zcl_comm_reset_startup_param_t reset_startup; } cmd; } FAR *request = envelope->payload; const zcl_attribute_tree_t FAR *tree = context; zcl_comm_state_t FAR *comm; uint32_t delay; // Context points to the attribute tree for this cluster. First // server attribute is the first element of the zcl_comm_startup_param_t // structure. Note that we intentionally cast away const on 'value' // since it is actually non-const. comm = (zcl_comm_state_t FAR *)tree[0].server->value; switch (request->zcl.command) { case ZCL_COMM_CMD_RESTART_DEVICE: // validate the statup configuration if (! zcl_comm_sas_is_valid( comm)) { #ifdef ZCL_COMMISSIONING_VERBOSE printf( "%s: ignoring restart cmd due to inconsistent SAS\n", __FUNCTION__); #endif return zcl_comm_response( envelope, ZCL_STATUS_INCONSISTENT_STARTUP_STATE); } // Set a timer for when we should perform the restart. delay = request->cmd.restart_dev.delay * UINT32_C(1000) + rand_range( request->cmd.restart_dev.jitter * 80); #ifdef ZCL_COMMISSIONING_VERBOSE printf( "%s: restart scheduled in %" PRIu32 "ms\n", __FUNCTION__, delay); #endif comm->restart_ms = (xbee_millisecond_timer() + delay); comm->flags |= ZCL_COMM_FLAG_DELAYED_RESTART; if ((request->cmd.restart_dev.options & ZCL_COMM_RESTART_OPT_MODE_MASK) == ZCL_COMM_RESTART_OPT_MODE_SAVE_CHANGES) { comm->flags |= ZCL_COMM_FLAG_INSTALL; } else { // client changed its mind and we need to clear the install flag comm->flags &= ~ZCL_COMM_FLAG_INSTALL; } return zcl_comm_response( envelope, ZCL_STATUS_SUCCESS); case ZCL_COMM_CMD_RESET_STARTUP_PARAM: if (request->cmd.reset_startup.options & ZCL_COMM_RESET_OPT_CURRENT) { #ifdef ZCL_COMMISSIONING_VERBOSE printf( "%s: resetting to factory defaults\n", __FUNCTION__); #endif // reset and install factory defaults comm->flags |= ZCL_COMM_FLAG_DELAYED_RESTART | ZCL_COMM_FLAG_FACTORY_RESET | ZCL_COMM_FLAG_INSTALL; comm->restart_ms = xbee_millisecond_timer(); } // if we implemented saved startup parameters, we would need // to process other options here return zcl_comm_response( envelope, ZCL_STATUS_SUCCESS); case ZCL_COMM_CMD_SAVE_STARTUP_PARAM: case ZCL_COMM_CMD_RESTORE_STARTUP_PARAM: // this implementation does not handle these optional commands break; } } // Allow General Command handler to process general // commands and send errors out for unsupported commands. return zcl_general_command( envelope, context); }
// TODO: make use of zcl_process_read_attr_response() in zcl_client.c to parse // Read Attributes Response and populate a temporary attribute list with the // values. _zcl_time_debug int zcl_time_client( const wpan_envelope_t FAR *envelope, void FAR *context) { zcl_command_t zcl; // We're only expecting Read Attribute Responses. // Make sure frame is server-to-client, not manufacturer-specific and // a profile (not cluster) command. if (zcl_command_build( &zcl, envelope, context) == 0 && zcl.command == ZCL_CMD_READ_ATTRIB_RESP && ZCL_CMD_MATCH( &zcl.frame_control, GENERAL, SERVER_TO_CLIENT, PROFILE)) { const zcl_header_t FAR *header = envelope->payload; union { const uint8_t FAR *u8; const uint16_t FAR *u16_le; const uint32_t FAR *u32_le; } walk; // used to walk the payload uint8_t FAR *payload_end; uint16_t attribute_id; uint8_t attribute_type; zcl_utctime_t time = 0; uint8_t time_status = 0; uint8_t response = ZCL_STATUS_SUCCESS; #ifdef ZCL_TIME_VERBOSE printf( "%s: %d-byte payload to time client\n", __FUNCTION__, envelope->length); hex_dump( envelope->payload, envelope->length, HEX_DUMP_FLAG_TAB); #endif payload_end = ((uint8_t FAR *)envelope->payload) + envelope->length; walk.u8 = header->type.std.common.payload; while (response == ZCL_STATUS_SUCCESS && walk.u8 < payload_end) { attribute_id = le16toh( *walk.u16_le++); if (*walk.u8++ == ZCL_STATUS_SUCCESS) { attribute_type = *walk.u8++; if (attribute_id == ZCL_TIME_ATTR_TIME) { if (attribute_type != ZCL_TYPE_TIME_UTCTIME) { response = ZCL_STATUS_INVALID_DATA_TYPE; } else { time = le32toh( *walk.u32_le++); } } else if (attribute_id == ZCL_TIME_ATTR_TIME_STATUS) { if (attribute_type != ZCL_TYPE_BITMAP_8BIT) { response = ZCL_STATUS_INVALID_DATA_TYPE; } else { time_status = *walk.u8++; } } else { // unexpected attribute in response response = ZCL_STATUS_UNSUPPORTED_ATTRIBUTE; } } } // didn't get a valid time in response if (response == ZCL_STATUS_SUCCESS && ! time) { #ifdef ZCL_TIME_VERBOSE printf( "%s: response did not contain a valid time\n", __FUNCTION__); #endif response = ZCL_STATUS_FAILURE; } if (response == ZCL_STATUS_SUCCESS) { #ifdef ZCL_TIME_VERBOSE printf( "%s: the time is %" PRIu32 "\n", __FUNCTION__, time); #endif // only set the clock if the response has a valid time if (time != ZCL_UTCTIME_INVALID && (time_status & (ZCL_TIME_STATUS_MASTER | ZCL_TIME_STATUS_SYNCHRONIZED)) != 0) { zcl_time_time = time; _zcl_time_time_set( NULL, NULL); // set Synchronized bit of our TimeStatus zcl_time_timestatus |= ZCL_TIME_STATUS_SYNCHRONIZED; } } return zcl_default_response( &zcl, response); } // command not handled by this function, try general command handler return zcl_general_command( envelope, context); }