How the C library issues commands
We show how the C Library issues commands to your SmartMesh device.
It uses https://github.com/dustcloud/sm_clib/blob/REL-1.0.1.4 to illustrate the concepts described.
This recipe is targeted at enthusiasts who want to understand the internals of the C Library. You do not need this level of understanding if you just want to use it.
TheĀ C LibraryĀ allows your micro-controller to issue commands to your SmartMesh device.
To illustrate, imagine you want to know the network id your SmartMesh IP manager is using, and therefore issue theĀ getNetworkConfig
Ā command.
Issuing the request
If you use theĀ C Library, all you need to do is callĀ dn_ipmg_getNetworkConfig()
, and pass a pointer to hold the reply.
dn_err_t dn_ipmg_getNetworkConfig(dn_ipmg_getNetworkConfig_rpt* reply);
The body of theĀ dn_ipmg_getNetworkConfig()
Ā is:
After a number of checks,Ā dn_ipmg_getNetworkConfig()
Ā callsĀ dn_serial_mg_sendRequest()
, which callsĀ dn_serial_sendRequestNoCheck()
:
The HDLC module of theĀ C Library implements "on-the-fly" HDLC framing, which is particularly interesting for constrained devices. Rather than having a buffer which holds the packet to be sent and calculating the CRC in one go, the HDLC module escapes characters and calculates the CRC as it is receiving bytes from the caller, and sends those onto the serial port.
To output a HDLC frame, use:
dn_hdlc_outputOpen(); // prepares the HDLC module for outputting a new frame dn_hdlc_outputWrite(byte1); // call for each character ... dn_hdlc_outputWrite(byten); dn_hdlc_outputClose(); // wraps up the calculation of the CRC
The function your code initially called,Ā dn_ipmg_getNetworkConfig()
, now returns.
This function returns as soon as the request has left the serial port. It does not mean you have received a response from the device.
Internally, theĀ C LibraryĀ is now waiting for a reply to that function, and keeps the state in the table below:
variable | value | meaning |
---|---|---|
dn_ipmg_vars.busyTx | TRUE | The C Library is busy transmitting. Any calls to issue new commands are rejected as long as:
|
dn_ipmg_vars.cmdId | integer | The identifier of the request just transmitted. Used to match the response. |
dn_ipmg_vars.replyContents | pointer | A pointer to where to write the response. |
variable | value | meaning |
dn_serial_mg_vars.replyCmdId | integer | The identifier of the reply to wait for (same value as dn_ipmg_varscmdId ). |
dn_serial_mg_vars.replyCb | pointer | A function pointer to the function to call when a reply is received. For example, dn_ipmg_getNetworkConfig_reply() . |
Handling the response
Each time a serial byte is received from the device, theĀ dn_hdlc_rxByte()
Ā function is called.
Similar to the transmission case, the HDLC module implements "on-the-fly" HDLC de-framing using the following functions:
dn_hdlc_inputOpen()
dn_hdlc_inputWrite()
dn_hdlc_inputClose()
When done receiving a correctly-formatting HDLC frame, theĀ dn_hdlc_vars.inputBuf
Ā buffer contains the un-framed response. It is handed to the "upper-layer" through the callback functionĀ dn_hdlc_vars.rxFrame_cb()
.
Note that that this callback function was installed when the HDLC module was initialized:
Which itself is installed by the dn_serial_mg
module, and points to dn_serial_mg_rxHdlcFrame()
.
When the received frame is handed toĀ dn_serial_mg_rxHdlcFrame()
, it has the following format:
control | cmdId | seqNum | length | payload |
1B | 1B | 1B | 1B | variable |
---|
The flags in the control byte allow the dn_serial_mg
module to distinguish a response from a notification. This allows notifications to be handled even when the module is waiting for a response.
The payload is handed to theĀ dn_serial_mg_dispatch_response()
Ā function:
At this point, the payload contains:
rc | payload |
1B | variable |
---|
Which only continues handling this packet if this response corresponds to the request sent earlier. TheĀ dn_serial_mg_dispatch_response()
Ā function strips the return code, and hands the payload to the reply handler, in our caseĀ dn_ipmg_getNetworkConfig_reply()
.
Finally,Ā dn_ipmg_getNetworkConfig_reply()
Ā verifies the length of the payload, and populates the fields of the reply bufferĀ dn_ipmg_vars.replyContents
.
At this point, theĀ dn_ipmg
Ā module indicates a response was received by calling theĀ dn_ipmg_vars.replyCb()
Ā callback function. The application can now read the response in theĀ dn_ipmg_getNetworkConfig_rpt
Ā buffer it passed initially when callingĀ dn_ipmg_getNetworkConfig()
.