Device Management Protocol
DMP Message format
All DMP messages relate to DMP addresses within a component and so all specify one or more addresses in a standard address format.
Certain messages must also specify data relating to each address which is either a value for the property at that address (e.g. set-property, get-property-reply), or a reason code specifying why a command for that address has failed. The presence of data and whether it is a value or a reason code is fixed for each specific message code.
In the standard PDU format of ACN the DMP message fields are defined as
|vector||One octet message code.|
|header||One octet address encoding, determines single vs range address, field size, single vs multiple data, absolute or relative (to previously used) address.|
|data||One or more fields of address only, address + data, or address + reason-code as determined by the message code. The number of fields is determined by the PDU length.|
DMP messages divide into two clear sets. Support for these is compiled according to whether CF_DMPCOMP_C_ (controller only), CF_DMPCOMP__D (device only) or CF_DMPCOMP_CD (both) is configured.
Devices must correctly receive and handle these and it is an error for a controller-only component to receive any of them. The address field in these messages refers to the receiving component.
Controllers must receive and handle these and it is an error for a device-only component to receive any of them. The address field refers to the transmitting component.
Macros for address types
|IS_RANGE(header)||True if the header value specifies a range address|
|IS_RELADDR(header)||True if the header specifies a relative address|
|IS_MULTIDATA(header)||True if there is a data value for each address in the range|
|IS_RANGECOMMON(header)||True if there is just one value applying to all addresses in the range|
Combined message code and address modes
For many purposes Acacian combines the message code with the address type (header) field. These macros define all the combined message/address codes required by Acacian’s transmit code - there are other permitted values but they mostly have arcane use-cases or duplicate functionality.
Note: the choice of relative/absolute addressing is made automatically as PDUs are constructed.
Note: dmp_openpdu() will substitute the single address version whenever count == 1 so multiple address versions can normally be used
Getting Property Values
|PDU_GETPROP_ONE||Get Property, single address (no values)|
|PDU_GETPROP_MANY||Get Property, range address (no values)|
|PDU_GPREPLY_ONE||Get property reply, single address + value|
|PDU_GPREPLY_MANY||Get property reply, range address + one value per address|
|PDU_GPFAIL_ONE||Get Property Fail, single address + reason|
|PDU_GPFAIL_MANY||Get Property Fail, range address + one reason per address|
|PDU_GPFAIL_COMMON||Get Property Fail, range address + common reason|
Setting Property Values
|PDU_SETPROP_ONE||Set Property, single address + value|
|PDU_SETPROP_MANY||Set Property, range address + one value per address|
|PDU_SETPROP_COMMON||Set property, range address + common value|
|PDU_SPFAIL_ONE||Set Property Fail, single address + reason|
|PDU_SPFAIL_MANY||Set Property Fail, range address + one reason per address|
|PDU_SPFAIL_COMMON||Set Property Fail, range address + common reason|
|PDU_EVENT_ONE||Event, single address + value|
|PDU_EVENT_MANY||Event, range address + one value per address|
|PDU_SYNCEV_ONE||Sync Event, single address + value|
|PDU_SYNCEV_MANY||Sync Event, range address + one value per address|
|PDU_SUBS_ONE||Subscribe, single address (no values)|
|PDU_SUBS_MANY||Subscribe, range address (no values)|
|PDU_SUBOK_ONE||Subscribe Accept, single address (no values)|
|PDU_SUBOK_MANY||Subscribe Accept, range address (no values)|
|PDU_SUBREJ_ONE||Subscribe Reject, single address + reason|
|PDU_SUBREJ_MANY||Subscribe Reject, range address + one reason per address|
|PDU_SUBREJ_COMMON||Subscribe Reject, range address + common reason|
|PDU_USUBS_ONE||Unsubscribe, single address (no values)|
|PDU_USUBS_MANY||Unsubscribe, range address (no values)|
DMP related data for local or remote components (see component.h).
|dmp_Lcomp_s||Local component DMP layer structure|
|dmp_Rcomp_s||Remote component DMP layer structure|
If we are a device the local component must include an address map to enable decoding of addresses. Similarly for a controller, remote must include an address map.
DMP is concerned with connections – these structures maintain the transport protocol relevant information including state and context data, details of remote and local components etc.
On transmission it is possible to be accumulating transmit data in multiple transmit contexts at the same time. For example while handling a multi-address set-property message or series of messages a device may accumulate set-property-fail responses for some properties in the context of the controller’s session whilst generating event messages in it’s own event session for properties whose value has been successfully changed.
|int dmp_register(||ifMC(struct Lcomponent_s *Lcomp)||)|
Register a local component for DMP access.
|Lcomp||the component being registered.|
DMP Transmit Functions
Within an SDT wrapper it is possible to send multiple DMP blocks. The usual reaason for this is to combine messages to different session members, or to all members, into a single wrapper. Each block can therefore have a different destination provided each is within the same channel. The destination is embedded in the transmit context structure.
Within a block there may be multiple DMP PDUs. Each PDU contains a message code and address format, then multiple address, or address + data fields.
|int dmp_newblock(||struct ||dmptcxt_s ||*||tcxt,|
Allocate and open a new DMP PDU block for the given transmit context. If a block is already open it is first closed.
|void dmp_closeblock(||struct ||dmptcxt_s ||*||tcxt||)|
Close the accumulated PDU block for the transmit context. Any opened PDU will be closed first.
|void dmp_flushpdus(||struct ||dmptcxt_s ||*||tcxt||)|
Flush (transmit) the transmit context. Any open block is closed first then transmitted.
|void dmp_abortblock(||struct ||dmptcxt_s ||*||tcxt||)|
Reset the pointers for the block and forget any accumulated data.
|uint8_t *dmp_openpdu(||struct ||dmptcxt_s ||*||tcxt,|
|struct ||adspec_s ||*||ads,|
Open a new PDU with the message type and address format given by vecnrange. The ads structure indicates the number of addresses etc. and size, the space needed.
A new block is opened if necessary.
|void dmp_closepdu(||struct ||dmptcxt_s ||*||tcxt,|
Close and finalize the previously opened PDU
|void dmp_closeflush(||struct ||dmptcxt_s ||*||tcxt,|
Close the current PDU then close and flush all accumulated blocks.
|void dmp_truncatepdu(||struct ||dmptcxt_s ||*||tcxt,|
Truncate and close the current PDU at a smaller size/count than specified when it was opened. This is useful when errors are encountered whilst accumulating responses for example.
count specifies the number of items successfully accumulated and nxtp the end of the accumulated data.
Receive is handled by callback functions. Application level callbacks are specified either in the rxvec field of dmp_Lcomp_s, or for devices may be specified on a per-property basis using DDL property extensions.
|void dmp_sdtRx(||struct ||member_s ||*||memb,|
|const ||uint8_t ||*||pdus,|
This is a callback function which must be passed to SDT to have Acacian’s DMP code parse and handle incoming DMP. DMP is split into individual messages and addresses matched to properties and decoded before calling the application provided message handlers.