Message Layer (7Fh)

OSI: Session and Presentation Layers

Keywords: structured data presentation, data entry, host side processing, heterogeneous devices, profile-less, dynamic content, interoperability, rapid development, self-binding, very low communication overhead, sensors, internet of things, embedded systems, sensor networks

Scope

The scope of this document is to define the Isotropic Sensor Network Protocol Message Layer for broadcast and peer to peer connections in a distributed sensor area network, wired or wireless, low and high data rate devices, battery powered devices, short-range devices with short operational space, low-cost devices to support trivial sensors, besides the fully featured devices and rapid development of embedded hardware. The Message layer defines simple but powerful communication protocol for compact implementation designed to meet requirements of the next generation distributed Internet of Things (IoT) devices.

Purpose

The purpose of this specifications is to provide a standard for low complexity, low cost, and low power (aware) consumption devices (sensors).

Key features

  • Rapid Sensor Development

  • Rich Data Structures with very Low Transmission Overhead

  • Self Describing (Dynamic Content) Human Readable Output

  • Direct Mapping to rich Web JSON API

  • High Level Pre/Post-Processing (Math) Support

  • Advanced Value Presentation with Precision, Accuracy and Unit

  • Hand-Shaking for Transfer Reliability

  • Low-Cost and Compact Implementation

Overview

This document provides specifications of the Message Layer for use in information exchange between IoT devices themselves and devices and presentation sides. Applications cover sensors, sensor networks, development and debugging of embedded systems via simple UART interfaces to monitor and configure the application, in production environments used for testing, calibration and adjustments, and more. Whenever rapid development, low footprint implementation and dynamic message content is desired.

It provides a straight forward approach of data presentation, reduces CPU complexity and allows transfer of the measured values in their native format, without introducing rounding and other numerical errors. It represents a bi-directional communication where communication over-head and complexity is reduced to the minimum by:

  • splitting the description (the static part) from the arguments (the dynamic part) of the message, which need to be send only once, or on update.

  • description can also be loaded by presentation software, in which case, the device is only sending useful (arguments) data in its raw form,

  • contents is split among messages, where device can update multiple message at once,

  • and receive update in its natural format which means, that a math inverse is computed on the presentation, host side.

Definitions, Acronyms and Abbreviations

arguments

device specific parameter in raw (typically native) form

device

An entity containing this protocol implementation. Also referred as sensor device or just sensor or device.

descriptor

holds a Sensor Message Layer typical format to describe a device and arguments

frame

The format of aggregated bits that are transmitted together in time.

identification descriptor, message

Zero-th message holds a so called global unique descriptor identifying one device only globally

IoT

Internet of Things, and also as Isotel of Things

host

typically referred to a presentation side of the information received from the sensor, and as user input to the sensor

message

holding either descriptors or arguments

packet

The format of aggregated bits that are transmitted together in time across the physical medium.

LSB

least significant bit

MSB

most significant bit

Packet Format

Frame Format

Fields

Protocol ID

Description Flag

Message Number

Message Body

Bits

8

1

7

length

Value

0x7F

ARGS: 0, DESC: 1

MSGNUM: 0-127

Args or Description

A 16-bit header is followed by an arbitrary length of payload, limited by encapsulating protocol. Header provides unique Protocol ID, followed by a Message Designation.

Message Designation is split into two parts:

  • Description Flag, which defines the content of the Message Body,

  • Message Number, with the first message starting from 0 ending at 127.

Based on Descriptor Flag, Message Body carries either:

  • ARGS: Raw Arguments,

  • DESC: Message Descriptor.

Arguments are specified by the Message descriptor, and when they’re send are encoded as described under section below Arguments Encoding.

The first message MSGNUM=0 is also called a Device Identification Descriptor. It must uniquely define a device by specifying product name, vendor, and version. Serial number and product specific numbers may be passed as arguments, however not the version or any other value that would mean a change in other message descriptors (MSGNUM>0) that would disallow unique and non-ambitious identification of a device. Based on this message hosts may cache the remaining message descriptors.

Hand-Shaking

Description Flag

Message Body Length

Command

0

0

Request for Argument Update

0

>0

Reply: Argument Update

1

0

Request for Descriptor Update

1

>0

Reply: Descriptor Update

Hand-shaking is unidirectional with two requests for which only one possible reply exists, the content updates. Typically a device contains messages, transmits measurements and a host is a receiver, and user or machine input. However with the reverse direction hosts can serve as remote storage and can be asked by devices to serve input or stored data, configurations, passwords, etc.

Size of the message arguments and descriptors is limited by underlying layers as well as the number of concurrent requests.

Identifying and Setting up a Device

  1. If a device receives an Argument Update for an unknown message then it sends back a Requests for Descriptor for the same message.

  2. If a Descriptor Update is received but arguments are unknown then it sends back a Request for Argument Update for the same message.

  3. For an unknown device, the first request issued is Request for Descriptor for Message Number, MSGNUM=0, to obtain Device Identification Descriptor and possibly re-use the cached content; if device is unknown to a host, then continues as follows:

  4. Content is loaded by starting with the highest message number, sending Request for Descriptor with MSGNUM=0x7F Device replies by returning an Descriptor Update with the last possible message number.

  5. Loading continues with last MSGNUM-1, MSGNUM-2, and stops at MSGNUM=1.

Information Directions and Acknowledging Changes

The message descriptor defines the I/O relations of some parameter, whether it is an output from a sensor only (Output only), can it be changed (I/O), or is it an input driven (Input Only) parameter.

These types define how an originator of a parameter, typically a device, manages and replies to a host.

Output Only Parameters

These cannot be changed, and a device receiving an update to a non-changeable parameter can be ignored without issuing a reply. However if network throughput permits a reply it is advisable that it resends the old value back to the host.

Host should disallow sending updates to such parameters to remove unwanted network traffic and loss of energy.

Input Only Parameters

These can be changed and are controlled by the host, however for this types of parameters host does not expect a reply. It is meant to enter information which does not need a reverse feedback, as password, streaming data to a speaker, etc.

Input and Output Parameters

These fall into the group of full acknowledgment cycle, which requires that a device replies with an updated value, in one of the following two methods:

  1. same as input, or

  2. not-same but different as before

to the host issuing a request. Which type of acknowledgment method is used is selected by the host input. It should follow the following specifications:

  1. when user, or some machine requests to change a value by providing its exact value, or mnemonics, then the acknowledgment procedure selects method 1,

  2. when input is prefixed by a ~ character, like “~1”, or “~Off”, then the 2nd method is selected.

Host must identify the correctness of the reply to give accurate report to a user or machine. It follows this procedure:

  • Sends Argument (Value Change) Request to a Device

  • Waits for a Message with the Desired Value Change:

    • If value received is OK (as per 1st or 2nd method), it reports Success.

    • otherwise it retries N times, before it reports an Error.

    • if no reply is received within a time frame, it retries N times, before it reports: Timeout

  • If device doesn’t send any kind of messages within some time period, device is declared as: Inactive

Device engaged in the above procedure should first serve requests, and then continue with the rest of the updates. This minimizes the number of retries in the network, and increases reaction time.

Device and hosts may send messages concurrently. It may happen that just after sending a request to change a value, a message with an argument update is received from the same device. Above procedure should handle such scenarios by sending a 2nd retry. If underlying protocol provides time synchronization then the message sequence becomes clear to remove redundant retries.

Message Descriptor Specification

Each of 128 available messages is described by a description. It is called a Message Descriptor and provides rich elements as structured text, parameters, data structures, simple expressions, rich math with cross-referencing between parameters, unit and accuracy specifiers, lists / enumerations, view modes and sections.

Text Elements

Typically interaction with a device is done on the variable - value pairs (parameters), however the text elements are used to provide basic descriptions of the device and help on parameters, in human understanding readable way for direct representation by a host.

General Rules

Text is sent as is to the output unless one of the following is used:

  • general escape character %… used to describe arguments and additional text elements,

  • expressions which start with { .. and end with }, immediately followed by optional unit […]

  • data structure that start with a name and followed by {, i.e. struct{ … }

Identifiers (Variable names, List elements, … ) should contain basic ASCII characters:

  • First character must be a letter or [“.”,”_”, “#”, “!”, “?”, “@”] character.

  • Other characters can also include digits and [“/”,”’”, “~”] characters.

For description elements using non-standard characters, element can be placed in quote using ` `, example:

{:quote}={%hu?%<hu:` `,val0;val1;`$#%val`;`pm1V`}

Headings

  • %T0{…}: title segment, which should be present in the first message and only once per device or unit

  • %T1{…}: page

  • %T2{…}: section

  • %T3{…}: sub-section

Text Size

  • %t0{…}: size equal to title segment,

  • %t1{…}: size equal to heading level 1,

  • %t2{…}: size equal to heading level 2 and so forth

Advanced and Development Headings - Sections

Every heading can include an identifier to denote an advanced or a development section to control the device output level.

  • %Txa{…}: advanced section, x = 0,1,2… header level

  • %Txd{…}: development section, x = 0,1,2… header level

Inheritance from parent sections apply; for example, everything after %T2a{} header would fall under the advanced sections as long as another normal section as %T2{} or %T1{} is defined.

Line Breaking

New line can be requested by:

  • \n which denotes a new paragraph, as <p> …

  • \r denotes a new line, as <br> …

Spaces

A normal space generates a space at the output, but a space is also assumed at the end of each message, so a string from two messages will be shown as joined strings with a space in-between.

Tables

HTML Table View in either horizontal or vertical layout is supported by using \t identifier

Horizontal table form (headers on the left):

\t hdr1 {:row1[X]}... \r hdr2 {:row2[X]} ... } \r hdr3 {:row[X]} ... } \n
  • here t accounts for vertical table, so each vector is a simple row and n closes. Vectors convert to a simple <td> ..</td> very straight forward.

Vertical table form (headers on the top):

\t hdr1 {:col1[X]}... \t hdr2 {:col2[X]} ... } \t hdr3 {:col3[X]} ... } \n
  • where hdr is a normal string (%Tx are not allowed).

End-Of-Messages (EOM) indicator

  • %! (EOM) denotes end of device descriptions, for loading purposes. Shold be put at the end of last message

Other

  • %% is used to display %

Argument Specifiers

Argument specifiers define how raw arguments (ARGS) are represented in their native (binary) form, just as like in standard printf().

Argument specifier starts with a % followed by direction, length, and format.

Direction

  • %<.. denotes a read-only parameter that is send from a device and cannot be written

  • %>.. denotes a write-only parameter that can only be sent but not read (as pin/password codes)

  • %… denotes a read-write parameter that can be read and modified

Length

  • h: specifies short, an 8-bit byte

  • l: specifies long, a 32-bit word

  • L: specifies long long, a 64-bit word

Format

  • i: 16-bit signed integer

  • u: 16-bit unsigned integer

  • x: 16-bit hex

  • f: 32-bit floating point as per IEEE 754, lf stands for 64-bit, %hf for 16-bit half precision float (added in 1.2.0.3)

  • i,u,x,f: denote small endian

  • I,U,X,F: denote big endian format (capital letters)

Examples:

%u     for 16-bit little endian format
%LU    for 64-bit big endian format
%<Lx   for 64-bit little endian read-only format printed in hex

Notes:

  • Floating point numbers support default %f which is 32-bit, long %lf 64-bit and half %hf 16-bit (added in 1.2.0.3)

  • Above specifiers are not limited to integers only but with the math expressions they represent also fixed-point arithmetic.

  • Omit the length specifier to preserve the default format’s length.

Variable Length

  • Maximum length for the above currently supported is 64 bit

  • Before version 1.2.0.1, variable length argument was supported only for %I and %i type arguments

  • From version 1.2.0.1 and up, variable length arguments are also supported for U,u,J,j,K,k,X,x types

  • Before version 1.2.0.1, variable length had to be byte sized len%8==0 (ie. %i16,%I24,%i40)

  • From version 1.2.0.6 and up, arbitrary variable length arguments are also supported (ie. %i5,%I27,%i55)

Non-Aligned arguments

Arbitrary length variables can cause for the argument field to shift and lose its byte alignment There are some rules regardning endianness handling in case of misaligned bit arguments:

  • Misaligned section is defined as part of argument field from the start of first non-byte aligned argument and until byte alignment is restored

  • When misaligned bit argument is detected, endianness is now calculated across entire misaligned section

  • For this reason in a given misaligned section, all arguments should have the same endianness, mixing little and big endian can produce invalid values

Example:

{:test1}={%x4}{:test2}={%x16}{:test3}={%x12}{:test4}={%x}

Here we have misaligned field of 4 bytes containing test1-3 parameters. test4 is again byte aligned. Argument field in this case is preprocessed/reordered:

[0, 1, 2, 3, 4,5] > [3, 2, 1, 0, 4, 5]

Parameters test1-3 are then processed as if they were big endian. test4 is still processed as before.

  • A convenient way to restore byte alignment is by adding padding bits described in next section

Argument padding

  • Variable length arguments support bit padding specifier, by using comma ‘,’ and padding bit length after argument length.

  • Padding is appended after the argument fields

Example:

%I5,3   5-bit argument, 3 bit padding

To prepend padding bits, zero length argument can be specified

Example

%I0,3   3-bit padding

Format with an additional Not-a-Number (NaN) state

The use of NaN has potential in sensors to denote that a measurement is yet invalid or state undefined. Unsigned and signed specifiers are provided:

  • j,J: same as signed integer i,I, but with -MAX (i.e. for %hj value of −128) value denoting the NaN value

  • k,K: same as unsigned integer u,U, but with 0 denoting NaN value

The NaN can be assigned any value, see Lists (Enumeration) below.

  • NaN value in idm output is shown as “—”

Arguments Encoding and Granularity Size

Integers:

  • 8-bit, as a single byte.

  • 16-bit, two bytes ordered either in little/big endian

  • 32-bit, 4 bytes ordered either in little/big endian

Default granularity size is 8-bit. Some CPU’s have bus widths of 16-bit thus granularity size of one word. These different encoding can be enabled by putting a specifier in a description (usually in msg 0, before the arguments)

Specifiers:

  • %e for 16-bit mode

  • %E for 32-bit mode

String Arguments

Currently supported string argument type:

%c{length} - standard 8-bit ASCII character encoding

Example:

{:test1}={%c20}
  • length denotes maximum number of characters in string

  • 0x00 byte is regarded as terminator denoting the end of string, bytes including and after terminator are excluded from output

Cross Referencing

  • %v:<msgnum>$<argnum>: where <msgnum> is message id=0,1,2.. and <argnum> is consecutive argument number 1,2,3.. in the message given by <msgnum>

  • %v:<parameter>: where <parameter> consists of <scope><parameter name>. Scope can be declared in following ways:

    • a full or partial data structure hierarchy path i.e. device.sensor.<parameter name>

    • number of dots ‘.’, representing the number of levels back in the hierarchy where parameter is searched, starting from the level where cross reference is located. i.e. .var will look for parameter var in current scope, while …var will also look two levels higher in the hierarchy

    • if scope is omitted, parameter is searched globally. The first parameter with the corresponding <parameter name> is returned

  • <parameter>: inside expressions, ‘%v:’ can be omitted. Other rules still apply

Expressions

Expressions represent math objects that are post-process after received by the host. When used in conjunction with variables (parameters) these also define the math-inverse process when changing their values.

General form is given by brackets:

{math:description}

where:

  • math elements include standard operators, arguments, and can directly reference other variables by their full name

  • description is an optional part describing the expression itself, and may provide accuracy, value descriptions (lists/enumeration), or as a set of conditions under which expression is valid or combination of above.

Math Operators and Functions

The following arithmetic/bitwise operators are supported (by descending precedence):

Operator

Symbol

Exponential

**

Multiplicative

* / %

Additive

+ -

Shift

<< >>

Bitwise AND

&

Bitwise XOR

^

Bitwise OR

|

Supported are the following standard math functions: abs, acos, asin, atan, cbrt, cos, cosh, exp, expm1, log, log10, sin, sinh, sqrt, tan, tanh, round

Example:

{:tsqrt}={sqrt(%U+1)}
{:tsin}={sin(%U*0.001)}
{:tns}={sqrt(log10(%U))}

Math Resolution / Precision

Resolution is automatically determined by the least accurate argument within the expression, i.e. an 8-bit value by itself determines 3 digits, and the decimal point is derived from the equation itself. Resolution then determines the number of digits and decimals to be displayed.

Developers may align the device readings in such a way that output bytes, words, directly denote precision of some measurement.

For instance, the following:

{%hu>>2}

does not apply reduction in resolution or precision, but is simply adding fixed point bits to the output. Word must be properly aligned in the raw arguments after the i.e. A/D reading.

Confidence Interval - Accuracy

An optional argument, besides the precision, is accuracy, which determines the interval of confidence. It can be assigned besides the argument specifier or on the expression level in the description part.

Example, both giving final accuracy of +-0.3:

{%U+-3/10}
{%U/10:+-0.3}

the character +- can be replaced by the single character according to the ASCII extended ±

{%U±3/10}
{%U/10:±0.3}

Accuracy is computed among entire expression and all arguments to derive the final accuracy, displayed as: value ± error

Accuracy can also be a dynamic expression, in which case it need to be defined in parentheses to separate from main expression

{%i:+-(%hu*0.1)}

Lists (Enumeration)

The Math Description specifies how values are translated into lists.

{%hu:item0,item1,item2}
{%hi:A=-23,B=59,C=70}

where:

  • item0, item1 are assigned default values 0,1,2,..

  • if description for given value does not exists, a value is printed out.

  • The NaN keyword is reserved for integer Not a Number, so {%hu:NaN=0} is equal to {%hk}, see also the two predefined specifiers

Enumeration elements severity can be defined using !~_ characters at the start of element

_ info
~ warning
! error

Example:

{%hu:_Info,~Warning,!Error}

Enumeration Options with Masking

A device may expose several configurations, which may sometimes be present or not. Number of number of options can be limited in the following way:

{%hu?%<hu:val1;val2;val3;...}
{%hu?%<hu:val1=1,val2=3,val3=5;...}
  • ; denotes binary counting for the next item, so Off gets 0 as before but as it is followed by ; it jumps to the next rounding value so 1, 2, 4, … so simply use ; to jump to next 2^n. The ; reduces manual assignments of numbers which can take lots of space.

  • , denotes explicitly given numeric values for enumeration elements

Data Structures

Data structure is declared as:

data{ ... }

where:

  • data{ can open the structure in any message, while } can close it in the same or any message after.

  • any degree of nesting is allowed.

Data structure limitations

  • if datastructure spans multiple descriptions, it should be defined at the end of previous descriptions and ended at the end of last containing description, so whole descriptions are contained in datastructure

Examples:

Invalid:

"{:var1}={%u}",
"struct{{:var2}={%u}",
"{:var2}={%u}} {:var4}={%u}",

Valid:

“{:var1}={%u} struct{“, “{:var2}={%u}”, “{:var3}={%u}{:var4}={%u}}”,

Variable - Value Pair Assignments (Parameters)

Variable is syntactically derived from an expression with given list description:

{:variable}=...

and can only exists in pairs with expressions, in the following form, followed by an expression, and with optional, recommended, unit specifier:

{:variable}={math:description}[unit]

where:

  • where a math object can contain one or more arguments,

  • if at least one is of Input/Output direction then variable may be changed by calculating its inverse, and sending raw arguments back to a device.

Unit specifier should comply with the International System of Units.

Examples:

{:variable}={1}[V]               // a constant
{:variable}={%<I*0.123}[mA]      // represents a read-only current in mA with some gain factor
{:variable}={%hu:off,on}         // an 8-bit value is used to display state, that may be modified by user

There should be an empty space between a text entry and an expression/assignment, for example:

"Variable description {:var1}={%U}[kWh]"  --correct

"Variable description{:var1}={%U}[kWh]" --incorrect

As on the other hand, data structures are declared without an empty space:

"data{....}"

Base Units with Scaling Prefixes

m meter

T tera 10^12

g gram

G giga 10^9

s second

M mega 10^6

A ampere

k kilo 10^3

K kelvin

d deci 10^−1

mol mole

m mili 10^−3

cd candela

μ micro 10^−6

n nano 10^-9

p piko 10^−12

f femto 10^−15

Derived Units

rad radian

sr steradian

Hz hertz

N newtoon

Pa pascal

J joule

W Watt

C coloumb

V volt

F farad

Ω Ohm

S siemens

Wb weber

T tesla

H henry

°C degree celsius

lm lumen

lx lux

Bq backuerel

Gy gray

Sv sievert

kat katal

Hidden variables

Hidden variables are declared using ‘#’ character instead of standard ‘:’, ie. {#var}={…}

Hidden variables are not displayed in output unless specified. They are still used in calculations and can be accessed with terminal console commands.

Vectors

Vectors can be defined in the following ways:

General form:

{:vector[n:m]}={...}

[n:m] defines the range of vector.

For example:

{:vec[2:5]}={%u}

which defines a vector of 3 same expressions, and 3 arguments.

Vectors can be defined also with different expressions as:

{:Ir}={%hu/2,%hu*2,%hu+2}[%]

in which case the number of columns is determined by the comas.

if vector size is defined as in:

{:Ir[3]}={%hu,%hu,%hu}[%]

It must match the number of elements, otherwise error is reported.

Vector Index References

When cross referencing vector parameters, matching indexes can be defined using notation:

- {parameter_name}[] : matching index, example G[]
- {parameter_name}[{constant}] : fixed index, example G[2]
- {parameter_name}[{offset}:] : offset index, example G[2:]

Examples:

{:G[1:16]}={%hu}
{:ad1[8]}={%lI/757760/256*G[]}
{:ad2[8]}={%lI/757760/256*G[9:]}

Multi-Message Descriptors

When underlying protocol prohibits the use of long descriptors, then multiple message numbers may be used to form a larger Message Descriptor by placing a plus character ‘+’ at the beginning of successive messages. Arguments below to the first message, and the remaining message numbers are skipped when sending/receiving arguments.

Example:

msg 1:          "First {:var11}={%hu}[kWh] in {:var12}={%hu};"
msg 2:          "+Second {:var21}={%hu}[kWh] in {:var22}={%hu};"
msg 3:          "+Third {:var31}={%hu}[kWh] in {:var32}={%hu};"

Creates a longer descriptor for MSGNUM=1, from which same message arguments are read when displaying or updating a message.

Multi-Message Updates

It is desired that messages aren’t too long with too many arguments to offer fine grained control over configuration parameters, or individual updates. However on the other side there are multi-message updates to reduce network overhead and at the same time permitting fine grained control.

Multi-message update is formed with an argument field containig arguments of several messages, starting from the given message number to which it is targeted to, say MSGNUM. The remaining arguments are passed to the following messages MSGNUM+1, MSGNUM+2, etc.

Example:

msg 1:            "MultiArg1 {:m1}={%hu+%hu}"
msg 2:            "MultiArg2 {:m2}={%hu+%hu}"
msg 3:            "MultiArg3 {:m3}={%hu+%hu}"

A 6-byte long argument update for msg 1 would in this case update all three messages.

Examples

Basic

Basic descriptors contain basic headers, data structures, expressions and text elements.

msg0: "%T0{Company Device}V1.1.08 dev{"

msg1: "%T1{First header}\r Temperature {:T}={%li/100}[oC]\r"

msg2: "Enumeration {:state}={%hu:Off,On,Error}"

msg3: "Structure str{{:I_A}={2.174*%hu}[mA] {:M_B}={%u+12}}\r"

msg4: "%T1{Second header}\r"

msg5: "{:ChA}={%u} {:ChB}={%lu}"

msg6: "Final section ending the main structure {:t}={%lU}[UTC]}}"

Advanced

Advanced descriptors contain more complex expressions, advanced headers and cross references.

msg0:  "%T0{Company Device}V1.1.08 dev{"

msg1:  "%T1{First header}\r Expression with accuracy {:T}={%li/100:+-10}[oC]\r"

msg2:  "Enumeration with defined values {:state}={%hu:Off=0,On=4,Error=8}"

msg3:  "Structure spanning two messages below\r"

msg4:  "str{{:I_A}={2.174*%hu+(12/%u)}[mA] {:M_B}={%u&%u}"

msg5:  "Variable cross reference {:ref}={%u*1.3} {:relativeRef}={2.174*ref} {:absoluteRef}={2.174*dev.str.ref}}\r"

msg6:  "%T1a{Advanced section header}\r Read only {:ChA}={%<hu} write only {:ChB}={%>hu}"

msg7:  "Hex and shift expressions {:hexVar}={%lx} {:phaseShift}={((%U<<8)+%hu)}\r

msg8:  "%T1d{Development section header}\r

msg9:  "Web Link %tu{isotel.eu}"

msg10: "Final section ending the main structure {:t}={%lU}[UTC]}}"

Complex

Complex descriptors contain multiple cross references, over multiple messages, more complex expressions, hidden variables and table.

msg0:  "%T0{Company Device with hidden serial id and 16bit endian encoding rule}V1.1.09 %e {#sid}={%Lx} dev{"

msg1:  "%T1{First header}\r Expression with changing accuracy {:T}={%li/100:+-(%u/100)}[oC]\r"

msg2:  "Enumeration with non-integer values {:state}={%hi*0.2:val1=-0.8,val2=4.2,val3=12}"

msg3:  "Structure spanning two messages below\r"

msg4:  "str{{:I_A}={2.174*%hu+(12/%u)}[mA] NaN arguments {:J_B}={%j}{:K_B}={%k}"

msg5:  "Multiple cross reference {:ref}={%u*1.3} {:relativeRef}={2.174*ref} {:absoluteRef}={2.174*dev.str.ref} {:multiRef}={1.2*ref*absoluteRef}}\r"

msg6:  "Argument cross reference {:argref}={%4:2*1.3}\r"

msg7:  "%T1a{Advanced section header}\r"

msg8:  "Read only {:ChA}={%<hu} write only {:ChB}={%>hu} continues to multi-msg description"

msg9:  "+Hex and shift expressions {:hexVar}={%<lx} {:phaseShift}={((%U<<8)+%hu)}\r

msg10: "%T1d{Development section header}\r

msg11: "String variable {:str}={%c20} Web Link %tu{isotel.eu}"

msg12: "Table \t pin{{:pin[14]}={%<u}\t"

msg13: "{:function[14]}={%u?%<u:val1;val2;val3;val4}\t

msg14: "{:value[0:6]}={%<j+-(%<k)/%<j'0} {:value[7:13]}={%<j+-(%<k)/%<j'0}\t

msg15: "{:unit[14]}={%<hu?0:``,V,mV,A,mA,oC,`mV/V`,uA,g,dps}\n

msg16: "Final section ending the main structure {:t}={%lU}[UTC]}}"

msg17: "EOM %!"

Document Changes

Date

Release

Changes

February 23, 2006

0.1

Initial Message Layer

November 23, 2006

0.2

Revised for first implementations.

July 10, 2010

0.3

Public version.

December 18,2011

0.4

Simplified version of Message Layer derived

January 23, 2012

0.5

Alignment with first IoT release

February 14, 2016

1.0

Public version of Renewed Sensor Message Layer

February 25, 2017

1.1

Added 32/64-bit floating point specifier

March 31, 2022

1.2

Updated enumeration masking, variable length, line breaking, quote strings

April 1, 2022

1.2

Added tables, updated variable length descriptions

April 6, 2022

1.2

Updated float point specs, added string args, enum severity, Nan, vector indexing, datastructure limitations

April 14, 2022

1.2

Updated examples, limitations

May 19, 2022

1.2.0.3

Updated version specific descriptions for half precision float, variable length argument for u,j,k,x types

August 12, 2022

1.2.0.6

Added arbirary length variable descriptions

References

Standards:

Documents: