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);
}
Beispiel #2
0
/* 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);
}
Beispiel #4
0
// 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);
}