Frame functions

The following sections show how to create frames and add sensor fields.

Setting the Waspmote Identifier

The setID() function allows the user to store the Waspmote ID in the EEPROM memory. The Waspmote ID will be used in order to set the corresponding field in the frame's header when calling the createFrame() function.

Example of use:

{
// store Waspmote ID in EEPROM memory (16-byte max)
frame.setID("Waspmote_Pro");
}

Creating new frames

The createFrame() function creates a new frame structure. It clears the frame buffer and inserts the header information: start delimiter, frame type, Serial ID, Waspmote ID and sequence number. After calling this function, the addSensor() function should be used in order to insert sensor fields within the payload. The function parameter selects the frame type:

  • ASCII

  • BINARY

Besides, it is possible to define the Waspmote ID which will be included in the frame\'s header (16 bytes maximum) instead of using the mote identifier stored in the EEPROM memory.

The function prototypes are the following:

  • Create an ASCII frame. The Waspmote ID is taken from the EEPROM memory that setID() function has previously set:

{
frame.createFrame(ASCII);
}
  • Create an ASCII frame. The Waspmote ID (i.e. "Waspmote_Pro") is set as an input parameter:

{
frame.createFrame(ASCII,\"Waspmote_Pro\");
}
  • Create a Binary frame. The Waspmote ID (i.e. "Waspmote_Pro") is set as an input parameter:

{
frame.createFrame(BINARY,\"Waspmote_Pro\");
}

Setting the frame size

The class constructor initializes the attribute _maxSize to MAX_FRAME constant, which is used to limit the maximum frame size. This constant defines a maximum default size of 255 bytes per frame. As this is the maximum possible value, it can be modified in WaspFrame.h in order to create frames with larger sizes.

On the other hand, setFrameSize() is the function which permits to set the frame size according to the user\'s consideration. Besides, it is possible to set the frame size depending on the XBee module, link encryption mode and AES encryption use. The following table defines the maximum frame size to be used for each communication protocol and several encryption possibilities:

Note: MAX_FRAME is 255 bytes but can be changed by the user

In the case that AES Encryption libraries are used to encrypt a Waspmote Frame, it is necessary to use the setFrameSize(). This function sets the maximum payload for the Waspmote Frame depending on the XBee protocol, addressing mode and link-encryption mode used.

The function prototypes are:

Set frame size depending on the protocol, addressing, link-encryption and encryption libraries used:

void setFrameSize(uint8_t protocol,
				uint8_t addressing,
				uint8_t linkEncryption,
				uint8_t AESEncryption);

Where "protocol" specifies the XBee module protocol between:

XBEE_802_15_4
ZIGBEE
DIGIMESH
XBEE_900HP 		
XBEE_868LP

"addressing" specifies the addressing mode between:

UNICAST_16B: for Unicast 16-bit addressing (only for XBee-802.15.4)

UNICAST_64B: for Unicast 64-bit addressing

BROADCAST_MODE: for Broadcast addressing

"linkEncryption" specifies the XBee encryption mode between:

ENABLED : 1

DISABLED : 0

"AESEncryption" specifies if AES encryption is used or not:

ENABLED : 1

DISABLED : 0

Set frame size depending on the protocol and encryption used (default UNICAST_64B addressing):

void setFrameSize(uint8_t protocol,
                  uint8_t linkEncryption,
			            uint8_t AESEncryption);

Examples of use:

{
    // set frame size to 125 bytes
    frame.setFrameSize(125);
    // XBee-802, unicast 16-b addressing, XBee encryption Disabled, AES encryption Disabled
    frame.setFrameSize(XBEE_802_15_4, UNICAST_16B, DISABLED, DISABLED);
    // XBee-868, unicast 64-b addressing, XBee encryption Enabled, AES encryption Enabled
    frame.setFrameSize(XBEE_868, ENABLED, ENABLED);
    // XBee-ZigBee, Broadcast addressing, XBee encryption Enabled, AES encryption Disabled
    frame.setFrameSize(ZIGBEE, BROADCAST, ENABLED, DISABLED);
    // XBee-900, unicast 64-b addressing, XBee encryption Disabled, AES encryption Enabled
    frame.setFrameSize(XBEE_900, DISABLED, ENABLED);
    // XBee-Digimesh, Broadcast addressing, XBee encryption Enabled, AES encryption Enabled
    frame.setFrameSize(DIGIMESH, BROADCAST, ENABLED, ENABLED);
}

Set frame size via parameter given by the user:

void setFrameSize(uint8_t size);

Where "size" must be less than MAX_FRAME, if not MAX_FRAME will be set as frame maximum size.

Example:

How to set the frame size depending on the protocol and encryption used:

https://development.libelium.com/frame-05-set-frame-size/

Setting the frame type

There is a function which allows the user to set the required frame type. This function must be called after calling createFrame() function. In the case it is not called, a default information frame type is chosen by createFrame(). The function that permits the setting of the frame type is setFrameType(). It is possible to select between different constants predefined in WaspFrame.h in order to set the sort of packet to be sent:

  • TIMEOUT_FRAME

  • EVENT_FRAME

  • ALARM_FRAME

  • SERVICE1_FRAME

  • SERVICE2_FRAME

These constants permit to set the Frame Type in spite of the frame mode (ascii or binary).

Example of use:

{
frame.setFrameType(TIMEOUT_FRAME); // set a TIMEOUT frame type
}

Example:

How to set the frame type:

https://development.libelium.com/frame-06-set-frame-type/

Note: Currently, this feature is not supported by Meshlium. Only default frame types are used (information and encrypted frames).

Adding sensor fields

The addSensor() function allows the user to append new sensor fields to the frame. The first parameter is the sensor tag to identify the sensor to be added (this is described in the "Sensor fields" section). The sensor identifier is followed up by the sensor values, which might be presented in various types: int, float, strings, etc. This function is defined by several prototypes so as to permit several possibilities. This function returns the current length of the frame. Each call to this function appends a new field if there is enough space for the new field. If this function attempts to insert a sensor field which exceeds the maximum frame buffer size, then the sensor field is not added and the function returns -1.

Depending on the sensor field a specific type is needed for Binary frames (described in the "Sensor fields" section). If a mismatch occurs, a message will appear through USB port. The sensor table shows the needed data type for each sensor.

Example of use:

{
// set frame fields (String - char*)
frame.addSensor(SENSOR_STR, (char*) \"STRING\");
// set frame fields (Battery sensor - uint8_t)
frame.addSensor(SENSOR_BAT, (uint8_t) PWR.getBatteryLevel());
}

The last example would create a frame payload with the following structure (depending on the frame mode):

  • ASCII frame. Payload length: 32 bytes

  • Binary frame. Payload length: 15 bytes

Examples:

Create ASCII frames with simple sensor data (1 field per sensor):

https://development.libelium.com/frame-01-ascii-simple/

Create ASCII frames with complex sensor data (more than 1 field per sensor):

https://development.libelium.com/frame-02-ascii-multiple/

Create Binary frames with simple sensor data (1 field per sensor):

https://development.libelium.com/frame-03-binary-simple/

Create Binary frames with complex sensor data (more than 1 field per sensor):

https://development.libelium.com/frame-04-binary-multiple/

Adding new sensor types

In case the user is interested in adding new sensor types, this guide explains how to do this process.

a) Define the new sensor identifier. As the rest of the sensors, it is necessary to define a unique identifier for the new sensor in WaspFrameConstantsv15.h:

#define SENSOR_GASES_CO     0
#define SENSOR_GASES_CO2    1
#define SENSOR_GASES_O2 2   2
#define SENSOR_GASES_CH4    4
...
#define NEW_SENSOR		      ?

b) Define label for the new sensor. As the rest of the sensors, it is necessary to define a unique label for the new sensor in WaspFrameConstantsv15.h:

prog_char str_frame_00[] PROGMEM = "CO";    // 0
prog_char str_frame_01[] PROGMEM = "CO2";   // 1
prog_char str_frame_02[] PROGMEM = "O2";    // 2
prog_char str_frame_03[] PROGMEM = "CH4";   // 3
...
prog_char str_NEW[] PROGMEM = "NEW_LABEL";  // ?

c) Fill the Flash Memory tables respecting the defined index in section "a". The Flash Memory tables are:

  • FRAME_SENSOR_TABLE: This is a string table in order to define the sensor labels. For ASCII frames.

  • FRAME_SENSOR_TYPE_TABLE: This is a uint8_t table which specifies the type of sensor depending on the type of value the user must put as input. Only for Binary frames.

  • FRAME_SENSOR_FIELD_TABLE: This is a uint8_t table which specifies the number of fields for each sensor.

  • FRAME_DECIMAL_TABLE: This is a uint8_t table which specifies the number of decimals a float must be set when adding each sensor to an ASCII frame.

Showing the current Frame

There is a function called showFrame() which prints the frame structure at the moment this function is called.

Example of use:

{
frame.showFrame();
}

Frame fragmentation (only binary frames)

When using binary frames, it is possible to fragment original frames into different fragments that share the same header. For that purpose, the createFragmentHeader() function allows the user to initialize a frame fragmentation. This function creates the fragment header needed for all fragments to be generated in the rest of the fragmentation process. This function needs an input parameter related to the maximum fragment size (including all bytes: header and payload).

This feature is useful in order to split large binary frames into fragments when the communication modules does not permit payloads large enough (for example, Sigfox and LoRaWAN impose severe restrictions). This function returns the number of pending sensor fields to be attached to a fragment. Thus, unless this function returns '0', it means there are still pending fields to be inserted and more fragment generation is needed.

The generateFragment() function allows the user to generate a new fragment from the original binary frame. Prior calling this function, the user must call the createFragmentHeader() function to make sure that there are pending fields to be inserted in a new fragment. This function also returns the number of pending fields.

The resulting fragments are stored in bufferFragment and lengthFragment attributes. So the user can access this data in order to send it via the communication module.

Imagine we create an original binary frame with 'n' sensor fields. We need to fragment the frames due to a maximum payload limitation. After fragmenting the original frame we will come up with two fragments as you can see in the next figures:

Example of use:

{
		frame.createFrame(BINARY);
		frame.addSensor(SENSOR_STR, “field 1”);
		frame.addSensor(SENSOR_STR, “field 2”);
		... // add numerous sensor fields into the original frame
		frame.addSensor(SENSOR_STR, “field N”);
		// proceed to create fragments from the original binary frame
		// ‘80’ is the maximum fragment size
		while (frame.createFragmentHeader(80) > 0)
		{		
				frame.generateFragment();
				USB.println(F(“Fragment frame:”));
				USB.printHexln(frame.bufferFragment, frame.lengthFragment);
		}
}

Complete example:

https://development.libelium.com/frame-08-fragment-frames/

Last updated