/*
 * The MySensors Arduino library handles the wireless radio link and protocol
 * between your home built sensors/actuators and HA controller of choice.
 * The sensors forms a self healing radio network with optional repeaters. Each
 * repeater and gateway builds a routing tables in EEPROM which keeps track of the
 * network topology allowing messages to be routed to nodes.
 *
 * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
 * Copyright (C) 2013-2018 Sensnology AB
 * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
 *
 * Documentation: http://www.mysensors.org
 * Support Forum: http://forum.mysensors.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 */

/**
 * @file MyMessage.h
 *
 * @brief API and type declarations for MySensors messages
 * @defgroup MyMessagegrp MyMessage
 * @ingroup publics
 * @{
 *
 * @brief Here you can find all message types used by the MySensors protocol as well as macros for
 * parsing and manipulating messages.
 */
#ifndef MyMessage_h
#define MyMessage_h

#ifdef __cplusplus
#include <Arduino.h>
#include <stdint.h>
#endif

#define PROTOCOL_VERSION	(2u)	//!< The version of the protocol
#define MAX_MESSAGE_LENGTH	(32u)	//!< The maximum size of a message (including header)
#define HEADER_SIZE			(7u)	//!< The size of the header
#define MAX_PAYLOAD (MAX_MESSAGE_LENGTH - HEADER_SIZE) //!< The maximum size of a payload depends on #MAX_MESSAGE_LENGTH and #HEADER_SIZE

/// @brief The command field (message-type) defines the overall properties of a message
typedef enum {
	C_PRESENTATION = 0,	//!< Sent by a node when they present attached sensors. This is usually done in presentation() at startup.
	C_SET          = 1,	//!< This message is sent from or to a sensor when a sensor value should be updated.
	C_REQ          = 2,	//!< Requests a variable value (usually from an actuator destined for controller).
	C_INTERNAL     = 3,	//!< Internal MySensors messages (also include common messages provided/generated by the library).
	C_STREAM       = 4	//!< For firmware and other larger chunks of data that need to be divided into pieces.
} mysensors_command_t;

#if !DOXYGEN // Hide until we migrate
/// @brief Type of sensor (used when presenting sensors)
typedef enum {
	S_DOOR					= 0,	//!< Door sensor, V_TRIPPED, V_ARMED
	S_MOTION				= 1,	//!< Motion sensor, V_TRIPPED, V_ARMED
	S_SMOKE					= 2,	//!< Smoke sensor, V_TRIPPED, V_ARMED
	S_BINARY				= 3,	//!< Binary light or relay, V_STATUS, V_WATT
	S_LIGHT					= 3,	//!< \deprecated Same as S_BINARY
	S_DIMMER				= 4,	//!< Dimmable light or fan device, V_STATUS (on/off), V_PERCENTAGE (dimmer level 0-100), V_WATT
	S_COVER					= 5,	//!< Blinds or window cover, V_UP, V_DOWN, V_STOP, V_PERCENTAGE (open/close to a percentage)
	S_TEMP					= 6,	//!< Temperature sensor, V_TEMP
	S_HUM					= 7,	//!< Humidity sensor, V_HUM
	S_BARO					= 8,	//!< Barometer sensor, V_PRESSURE, V_FORECAST
	S_WIND					= 9,	//!< Wind sensor, V_WIND, V_GUST
	S_RAIN					= 10,	//!< Rain sensor, V_RAIN, V_RAINRATE
	S_UV					= 11,	//!< Uv sensor, V_UV
	S_WEIGHT				= 12,	//!< Personal scale sensor, V_WEIGHT, V_IMPEDANCE
	S_POWER					= 13,	//!< Power meter, V_WATT, V_KWH, V_VAR, V_VA, V_POWER_FACTOR
	S_HEATER				= 14,	//!< Header device, V_HVAC_SETPOINT_HEAT, V_HVAC_FLOW_STATE, V_TEMP
	S_DISTANCE				= 15,	//!< Distance sensor, V_DISTANCE
	S_LIGHT_LEVEL			= 16,	//!< Light level sensor, V_LIGHT_LEVEL (uncalibrated in percentage),  V_LEVEL (light level in lux)
	S_ARDUINO_NODE			= 17,	//!< Used (internally) for presenting a non-repeating Arduino node
	S_ARDUINO_REPEATER_NODE	= 18,	//!< Used (internally) for presenting a repeating Arduino node
	S_LOCK					= 19,	//!< Lock device, V_LOCK_STATUS
	S_IR					= 20,	//!< IR device, V_IR_SEND, V_IR_RECEIVE
	S_WATER					= 21,	//!< Water meter, V_FLOW, V_VOLUME
	S_AIR_QUALITY			= 22,	//!< Air quality sensor, V_LEVEL
	S_CUSTOM				= 23,	//!< Custom sensor
	S_DUST					= 24,	//!< Dust sensor, V_LEVEL
	S_SCENE_CONTROLLER		= 25,	//!< Scene controller device, V_SCENE_ON, V_SCENE_OFF.
	S_RGB_LIGHT				= 26,	//!< RGB light. Send color component data using V_RGB. Also supports V_WATT
	S_RGBW_LIGHT			= 27,	//!< RGB light with an additional White component. Send data using V_RGBW. Also supports V_WATT
	S_COLOR_SENSOR			= 28,	//!< Color sensor, send color information using V_RGB
	S_HVAC					= 29,	//!< Thermostat/HVAC device. V_HVAC_SETPOINT_HEAT, V_HVAC_SETPOINT_COLD, V_HVAC_FLOW_STATE, V_HVAC_FLOW_MODE, V_TEMP
	S_MULTIMETER			= 30,	//!< Multimeter device, V_VOLTAGE, V_CURRENT, V_IMPEDANCE
	S_SPRINKLER				= 31,	//!< Sprinkler, V_STATUS (turn on/off), V_TRIPPED (if fire detecting device)
	S_WATER_LEAK			= 32,	//!< Water leak sensor, V_TRIPPED, V_ARMED
	S_SOUND					= 33,	//!< Sound sensor, V_TRIPPED, V_ARMED, V_LEVEL (sound level in dB)
	S_VIBRATION				= 34,	//!< Vibration sensor, V_TRIPPED, V_ARMED, V_LEVEL (vibration in Hz)
	S_MOISTURE				= 35,	//!< Moisture sensor, V_TRIPPED, V_ARMED, V_LEVEL (water content or moisture in percentage?)
	S_INFO					= 36,	//!< LCD text device / Simple information device on controller, V_TEXT
	S_GAS					= 37,	//!< Gas meter, V_FLOW, V_VOLUME
	S_GPS					= 38,	//!< GPS Sensor, V_POSITION
	S_WATER_QUALITY			= 39	//!< V_TEMP, V_PH, V_ORP, V_EC, V_STATUS
} mysensors_sensor_t;

/// @brief Type of sensor data (for set/req/ack messages)
typedef enum {
	V_TEMP					= 0,	//!< S_TEMP. Temperature S_TEMP, S_HEATER, S_HVAC
	V_HUM					= 1,	//!< S_HUM. Humidity
	V_STATUS				= 2,	//!< S_BINARY, S_DIMMER, S_SPRINKLER, S_HVAC, S_HEATER. Used for setting/reporting binary (on/off) status. 1=on, 0=off
	V_LIGHT					= 2,	//!< \deprecated Same as V_STATUS
	V_PERCENTAGE			= 3,	//!< S_DIMMER. Used for sending a percentage value 0-100 (%).
	V_DIMMER				= 3,	//!< \deprecated Same as V_PERCENTAGE
	V_PRESSURE				= 4,	//!< S_BARO. Atmospheric Pressure
	V_FORECAST				= 5,	//!< S_BARO. Whether forecast. string of "stable", "sunny", "cloudy", "unstable", "thunderstorm" or "unknown"
	V_RAIN					= 6,	//!< S_RAIN. Amount of rain
	V_RAINRATE				= 7,	//!< S_RAIN. Rate of rain
	V_WIND					= 8,	//!< S_WIND. Wind speed
	V_GUST					= 9,	//!< S_WIND. Gust
	V_DIRECTION				= 10,	//!< S_WIND. Wind direction 0-360 (degrees)
	V_UV					= 11,	//!< S_UV. UV light level
	V_WEIGHT				= 12,	//!< S_WEIGHT. Weight(for scales etc)
	V_DISTANCE				= 13,	//!< S_DISTANCE. Distance
	V_IMPEDANCE				= 14,	//!< S_MULTIMETER, S_WEIGHT. Impedance value
	V_ARMED					= 15,	//!< S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER. Armed status of a security sensor. 1 = Armed, 0 = Bypassed
	V_TRIPPED				= 16,	//!< S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER, S_WATER_LEAK, S_SOUND, S_VIBRATION, S_MOISTURE. Tripped status of a security sensor. 1 = Tripped, 0
	V_WATT					= 17,	//!< S_POWER, S_BINARY, S_DIMMER, S_RGB_LIGHT, S_RGBW_LIGHT. Watt value for power meters
	V_KWH					= 18,	//!< S_POWER. Accumulated number of KWH for a power meter
	V_SCENE_ON				= 19,	//!< S_SCENE_CONTROLLER. Turn on a scene
	V_SCENE_OFF				= 20,	//!< S_SCENE_CONTROLLER. Turn of a scene
	V_HVAC_FLOW_STATE		= 21,	//!< S_HEATER, S_HVAC. HVAC flow state ("Off", "HeatOn", "CoolOn", or "AutoChangeOver")
	V_HEATER				= 21,	//!< \deprecated Same as V_HVAC_FLOW_STATE
	V_HVAC_SPEED			= 22,	//!< S_HVAC, S_HEATER. HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto")
	V_LIGHT_LEVEL			= 23,	//!< S_LIGHT_LEVEL. Uncalibrated light level. 0-100%. Use V_LEVEL for light level in lux
	V_VAR1					= 24,	//!< VAR1
	V_VAR2					= 25,	//!< VAR2
	V_VAR3					= 26,	//!< VAR3
	V_VAR4					= 27,	//!< VAR4
	V_VAR5					= 28,	//!< VAR5
	V_UP					= 29,	//!< S_COVER. Window covering. Up
	V_DOWN					= 30,	//!< S_COVER. Window covering. Down
	V_STOP					= 31,	//!< S_COVER. Window covering. Stop
	V_IR_SEND				= 32,	//!< S_IR. Send out an IR-command
	V_IR_RECEIVE			= 33,	//!< S_IR. This message contains a received IR-command
	V_FLOW					= 34,	//!< S_WATER. Flow of water (in meter)
	V_VOLUME				= 35,	//!< S_WATER. Water volume
	V_LOCK_STATUS			= 36,	//!< S_LOCK. Set or get lock status. 1=Locked, 0=Unlocked
	V_LEVEL					= 37,	//!< S_DUST, S_AIR_QUALITY, S_SOUND (dB), S_VIBRATION (hz), S_LIGHT_LEVEL (lux)
	V_VOLTAGE				= 38,	//!< S_MULTIMETER
	V_CURRENT				= 39,	//!< S_MULTIMETER
	V_RGB					= 40,	//!< S_RGB_LIGHT, S_COLOR_SENSOR. Sent as ASCII hex: RRGGBB (RR=red, GG=green, BB=blue component)
	V_RGBW					= 41,	//!< S_RGBW_LIGHT. Sent as ASCII hex: RRGGBBWW (WW=white component)
	V_ID					= 42,	//!< Used for sending in sensors hardware ids (i.e. OneWire DS1820b).
	V_UNIT_PREFIX			= 43,	//!< Allows sensors to send in a string representing the unit prefix to be displayed in GUI, not parsed by controller! E.g. cm, m, km, inch.
	V_HVAC_SETPOINT_COOL	= 44,	//!< S_HVAC. HVAC cool setpoint (Integer between 0-100)
	V_HVAC_SETPOINT_HEAT	= 45,	//!< S_HEATER, S_HVAC. HVAC/Heater setpoint (Integer between 0-100)
	V_HVAC_FLOW_MODE		= 46,	//!< S_HVAC. Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn")
	V_TEXT					= 47,	//!< S_INFO. Text message to display on LCD or controller device
	V_CUSTOM				= 48,	//!< Custom messages used for controller/inter node specific commands, preferably using S_CUSTOM device type.
	V_POSITION				= 49,	//!< GPS position and altitude. Payload: latitude;longitude;altitude(m). E.g. "55.722526;13.017972;18"
	V_IR_RECORD				= 50,	//!< Record IR codes S_IR for playback
	V_PH					= 51,	//!< S_WATER_QUALITY, water PH
	V_ORP					= 52,	//!< S_WATER_QUALITY, water ORP : redox potential in mV
	V_EC					= 53,	//!< S_WATER_QUALITY, water electric conductivity μS/cm (microSiemens/cm)
	V_VAR					= 54,	//!< S_POWER, Reactive power: volt-ampere reactive (var)
	V_VA					= 55,	//!< S_POWER, Apparent power: volt-ampere (VA)
	V_POWER_FACTOR			= 56,	//!< S_POWER, Ratio of real power to apparent power: floating point value in the range [-1,..,1]
} mysensors_data_t;
#endif


/// @brief Type of internal messages (for internal messages)
typedef enum {
	I_BATTERY_LEVEL				= 0,	//!< Battery level
	I_TIME						= 1,	//!< Time (request/response)
	I_VERSION					= 2,	//!< Version
	I_ID_REQUEST				= 3,	//!< ID request
	I_ID_RESPONSE				= 4,	//!< ID response
	I_INCLUSION_MODE			= 5,	//!< Inclusion mode
	I_CONFIG					= 6,	//!< Config (request/response)
	I_FIND_PARENT_REQUEST		= 7,	//!< Find parent
	I_FIND_PARENT_RESPONSE		= 8,	//!< Find parent response
	I_LOG_MESSAGE				= 9,	//!< Log message
	I_CHILDREN					= 10,	//!< Children
	I_SKETCH_NAME				= 11,	//!< Sketch name
	I_SKETCH_VERSION			= 12,	//!< Sketch version
	I_REBOOT					= 13,	//!< Reboot request
	I_GATEWAY_READY				= 14,	//!< Gateway ready
	I_SIGNING_PRESENTATION		= 15,	//!< Provides signing related preferences (first byte is preference version)
	I_NONCE_REQUEST				= 16,	//!< Request for a nonce
	I_NONCE_RESPONSE			= 17,	//!< Payload is nonce data
	I_HEARTBEAT_REQUEST			= 18,	//!< Heartbeat request
	I_PRESENTATION				= 19,	//!< Presentation message
	I_DISCOVER_REQUEST			= 20,	//!< Discover request
	I_DISCOVER_RESPONSE			= 21,	//!< Discover response
	I_HEARTBEAT_RESPONSE		= 22,	//!< Heartbeat response
	I_LOCKED					= 23,	//!< Node is locked (reason in string-payload)
	I_PING						= 24,	//!< Ping sent to node, payload incremental hop counter
	I_PONG						= 25,	//!< In return to ping, sent back to sender, payload incremental hop counter
	I_REGISTRATION_REQUEST		= 26,	//!< Register request to GW
	I_REGISTRATION_RESPONSE		= 27,	//!< Register response from GW
	I_DEBUG						= 28,	//!< Debug message
	I_SIGNAL_REPORT_REQUEST		= 29,	//!< Device signal strength request
	I_SIGNAL_REPORT_REVERSE		= 30,	//!< Internal
	I_SIGNAL_REPORT_RESPONSE	= 31,	//!< Device signal strength response (RSSI)
	I_PRE_SLEEP_NOTIFICATION	= 32,	//!< Message sent before node is going to sleep
	I_POST_SLEEP_NOTIFICATION	= 33	//!< Message sent after node woke up (if enabled)
} mysensors_internal_t;


/// @brief Type of data stream  (for streamed message)
typedef enum {
	ST_FIRMWARE_CONFIG_REQUEST	= 0,	//!< Request new FW, payload contains current FW details
	ST_FIRMWARE_CONFIG_RESPONSE	= 1,	//!< New FW details to initiate OTA FW update
	ST_FIRMWARE_REQUEST			= 2,	//!< Request FW block
	ST_FIRMWARE_RESPONSE		= 3,	//!< Response FW block
	ST_SOUND					= 4,	//!< Sound
	ST_IMAGE					= 5,	//!< Image
	ST_FIRMWARE_CONFIRM	= 6, //!< Mark running firmware as valid (MyOTAFirmwareUpdateNVM + mcuboot)
	ST_FIRMWARE_RESPONSE_RLE = 7,	//!< Response FW block with run length encoded data
} mysensors_stream_t;

/// @brief Type of payload
typedef enum {
	P_STRING				= 0,	//!< Payload type is string
	P_BYTE					= 1,	//!< Payload type is byte
	P_INT16					= 2,	//!< Payload type is INT16
	P_UINT16				= 3,	//!< Payload type is UINT16
	P_LONG32				= 4,	//!< Payload type is INT32
	P_ULONG32				= 5,	//!< Payload type is UINT32
	P_CUSTOM				= 6,	//!< Payload type is binary
	P_FLOAT32				= 7		//!< Payload type is float32
} mysensors_payload_t;



#ifndef BIT
#define BIT(n)                  ( 1<<(n) ) //!< Bit indexing macro
#endif
#define BIT_MASK(len)           ( BIT(len)-1 ) //!< Create a bitmask of length 'len'
#define BF_MASK(start, len)     ( BIT_MASK(len)<<(start) ) //!< Create a bitfield mask of length starting at bit 'start'

#define BF_PREP(x, start, len)  ( ((x)&BIT_MASK(len)) << (start) ) //!< Prepare a bitmask for insertion or combining
#define BF_GET(y, start, len)   ( ((y)>>(start)) & BIT_MASK(len) ) //!< Extract a bitfield of length 'len' starting at bit 'start' from 'y'
#define BF_SET(y, x, start, len)    ( y= ((y) &~ BF_MASK(start, len)) | BF_PREP(x, start, len) ) //!< Insert a new bitfield value 'x' into 'y'

// Getters/setters for special bit fields in header
#define mSetVersion(_message,_version) BF_SET(_message.version_length, _version, 0, 2) //!< Set version field
#define mGetVersion(_message) ((uint8_t)BF_GET(_message.version_length, 0, 2)) //!< Get version field

#define mSetSigned(_message,_signed) BF_SET(_message.version_length, _signed, 2, 1) //!< Set signed field
#define mGetSigned(_message) ((bool)BF_GET(_message.version_length, 2, 1)) //!< Get signed field

#define mSetLength(_message,_length) BF_SET(_message.version_length, _length, 3, 5) //!< Set length field
#define mGetLength(_message) ((uint8_t)BF_GET(_message.version_length, 3, 5)) //!< Get length field

#define mSetCommand(_message,_command) BF_SET(_message.command_ack_payload, _command, 0, 3) //!< Set command field
#define mGetCommand(_message) ((uint8_t)BF_GET(_message.command_ack_payload, 0, 3)) //!< Get command field

#define mSetRequestAck(_message,_rack) BF_SET(_message.command_ack_payload, _rack, 3, 1) //!< Set ack-request field
#define mGetRequestAck(_message) ((bool)BF_GET(_message.command_ack_payload, 3, 1)) //!< Get  ack-request field

#define mSetAck(_message,_ackMsg) BF_SET(_message.command_ack_payload, _ackMsg, 4, 1) //!< Set ack field
#define mGetAck(_message) ((bool)BF_GET(_message.command_ack_payload, 4, 1)) //!< Get ack field

#define mSetPayloadType(_message, _pt) BF_SET(_message.command_ack_payload, _pt, 5, 3) //!< Set payload type field
#define mGetPayloadType(_message) ((uint8_t)BF_GET(_message.command_ack_payload, 5, 3)) //!< Get payload type field


// internal access for special fields
#define miGetCommand() ((uint8_t)BF_GET(command_ack_payload, 0, 3)) //!< Internal getter for command field

#define miSetLength(_length) BF_SET(version_length, _length, 3, 5) //!< Internal setter for length field
#define miGetLength() ((uint8_t)BF_GET(version_length, 3, 5)) //!< Internal getter for length field

#define miSetVersion(_version) BF_SET(version_length, _version, 0, 2) //!< Internal setter for version field
#define miGetVersion() ((uint8_t)BF_GET(version_length, 0, 2)) //!< Internal getter for version field

#define miSetRequestAck(_rack) BF_SET(command_ack_payload, _rack, 3, 1) //!< Internal setter for ack-request field
#define miGetRequestAck() ((bool)BF_GET(command_ack_payload, 3, 1)) //!< Internal getter for ack-request field

#define miSetAck(_ack) BF_SET(command_ack_payload, _ack, 4, 1) //!< Internal setter for ack field
#define miGetAck() ((bool)BF_GET(command_ack_payload, 4, 1)) //!< Internal getter for ack field

#define miSetPayloadType(_pt) BF_SET(command_ack_payload, _pt, 5, 3) //!< Internal setter for payload type field
#define miGetPayloadType() (uint8_t)BF_GET(command_ack_payload, 5, 3) //!< Internal getter for payload type field


#if defined(__cplusplus) || defined(DOXYGEN)
/**
 * @brief MyMessage is used to create, manipulate, send and read MySensors messages
 */
class MyMessage
{
private:
	char* getCustomString(char *buffer) const;

public:
	/**
	 * Default constructor
	 */
	MyMessage(void);

	/**
	 * Constructor
	 * @param sensor id of the child sensor for this message
	 * @param type see http://korturl.nu/stupidurl
	 */
	MyMessage(const uint8_t sensor, const uint8_t type);

	/**
	 * Single character hex (0 - 15) conversion
	 * @param i byte (only lower 4 bits will be considered)
	 * @return single char with the hex representation (0 to F) of the parameter
	 */
	char i2h(const uint8_t i) const;

	/**
	 * @brief Clear message contents.
	 */
	void clear(void);

	/**
	 * If payload is something else than P_STRING you can have the payload value converted
	 * into string representation by supplying a buffer with the minimum size of
	 * 2*MAX_PAYLOAD+1. This is to be able to fit hex-conversion of a full binary payload.
	 * @param buffer pointer to a buffer that's at least 2*MAX_PAYLOAD+1 bytes large
	 */
	char* getStream(char *buffer) const;

	/**
	 * @brief Copy the payload into the supplied buffer
	 */
	char* getString(char *buffer) const;

	/**
	 * @brief Get payload as string
	 * @return pointer to a char array storing the string
	 */
	const char* getString(void) const;

	/**
	 * @brief Get custom payload
	 * @return pointer to the raw payload
	 */
	void* getCustom(void) const;

	/**
	 * @brief Get bool payload
	 * @return a bool with the value of the payload (true/false)
	 */
	bool getBool(void) const;

	/**
	 * @brief Get unsigned 8-bit integer payload
	 * @return the value of the payload, 0 to 255
	 */
	uint8_t getByte(void) const;

	/**
	 * @brief Get float payload
	 * @return the floating-point value of the payload
	 */
	float getFloat(void) const;

	/**
	 * @brief Get signed 16-bit integer payload
	 * @return the value of the payload, –32768 to 32767
	 */
	int16_t getInt(void) const;

	/**
	 * @brief Get unsigned 16-bit integer payload
	 * @return the value of the payload, 0 to 65535
	 */
	uint16_t getUInt(void) const;

	/**
	 * @brief Get signed 32-bit integer payload
	 * @return the value of the payload, –2147483648 to 2147483647
	 */
	int32_t getLong(void) const;

	/**
	 * @brief Get unsigned 32-bit integer payload
	 * @return the value of the payload, 0 to 4294967295
	 */
	uint32_t getULong(void) const;

	/**
	 * @brief Getter for command type
	 * @return #mysensors_command_t
	 */
	uint8_t getCommand(void) const;

	/**
	 * @brief Getter for ack-flag.
	 * @return true if this is an ack message
	 */
	bool isAck(void) const;

	/**
	 * @brief Set message type
	 * @param type see http://korturl.nu/stupidurl
	 */
	MyMessage& setType(const uint8_t type);

	/**
	 * @brief Set which child sensor this message belongs to
	 * @param sensor
	 */
	MyMessage& setSensor(const uint8_t sensor);

	/**
	 * @brief Set final destination node id for this message
	 * @param destination
	 */
	MyMessage& setDestination(const uint8_t destination);

	/**
	 * @brief Set entire payload
	 * @param payload pointer to the buffer where the payload is stored
	 * @param length of the payload
	 */
	MyMessage& set(const void* payload, const uint8_t length);

	/**
	 * @brief Set payload to character array
	 * @param value pointer to the character array. The array must be null-terminated.
	 */
	MyMessage& set(const char* value);
#if !defined(__linux__)
	/**
	 * @brief Set payload to character array from flash
	 * @param value pointer to the character array. The array must be null-terminated.
	 */
	MyMessage& set(const __FlashStringHelper* value);
#endif

	/**
	 * @brief Set payload to decimal number
	 * @param value float
	 * @param decimals number of decimals to include
	 */
	MyMessage& set(const float value, const uint8_t decimals);

	/**
	 * @brief Set payload to bool value
	 * @param value true or false
	 */
	MyMessage& set(const bool value);

	/**
	 * @brief Set payload to unsigned 8-bit integer value
	 * @param value (0 to 255)
	 */
	MyMessage& set(const uint8_t value);

	/**
	 * @brief Set payload to unsigned 32-bit integer value
	 * @param value (0 to 4294967295)
	 */
	MyMessage& set(const uint32_t value);

	/**
	 * @brief Set payload to signed 32-bit integer value
	 * @param value (–2147483648 to 2147483647)
	 */
	MyMessage& set(const int32_t value);

	/**
	 * @brief Set payload to unsigned 16-bit integer value
	 * @param value (0 to 65535)
	 */
	MyMessage& set(const uint16_t value);

	/**
	 * @brief Set payload to signed 16-bit integer value
	 * @param value (–32768 to 32767)
	 */
	MyMessage& set(const int16_t value);

#else

typedef union {
	struct {

#endif
	uint8_t last;							//!< 8 bit - Id of last node this message passed
	uint8_t sender;						//!< 8 bit - Id of sender node (origin)
	uint8_t destination;			//!< 8 bit - Id of destination node

	/**
	 * 2 bit - Protocol version<br>
	 * 1 bit - Signed flag<br>
	 * 5 bit - Length of payload
	 */
	uint8_t version_length;

	/**
	 * 3 bit - Command type<br>
	 * 1 bit - Request an ack - Indicator that receiver should send an ack back<br>
	 * 1 bit - Is ack message - Indicator that this is the actual ack message<br>
	 * 3 bit - Payload data type
	 */
	uint8_t command_ack_payload;

	uint8_t type; //!< 8 bit - Type varies depending on command
	uint8_t sensor; //!< 8 bit - Id of sensor that this message concerns.

	/*
	 * Each message can transfer a payload. We add one extra byte for string
	 * terminator \0 to be "printable" this is not transferred OTA
	 * This union is used to simplify the construction of the binary data types transferred.
	 */
	union {
		uint8_t bValue; //!< unsigned byte value (8-bit)
		uint16_t uiValue; //!< unsigned integer value (16-bit)
		int16_t iValue; //!< signed integer value (16-bit)
		uint32_t ulValue; //!< unsigned long value (32-bit)
		int32_t lValue; //!< signed long value (32-bit)
		struct { //!< Float messages
			float fValue;
			uint8_t fPrecision; //!< Number of decimals when serializing
		};
		struct { //!< Presentation messages
			uint8_t version; //!< Library version
			uint8_t sensorType; //!< Sensor type hint for controller, see table above
		};
		char data[MAX_PAYLOAD + 1]; //!< Buffer for raw payload data
	} __attribute__((packed)); //!< Doxygen will complain without this comment
#if defined(__cplusplus) || defined(DOXYGEN)
} __attribute__((packed));
#else
};
uint8_t array[HEADER_SIZE + MAX_PAYLOAD + 1]; //!< buffer for entire message
} __attribute__((packed)) MyMessage;
#endif

#endif
/** @}*/
