A metronome using the FRDM K64F board

Committer:
ram54288
Date:
Sun May 14 18:40:18 2017 +0000
Revision:
0:a7a43371b306
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ram54288 0:a7a43371b306 1 # The Device Management and Service Enabler feature
ram54288 0:a7a43371b306 2
ram54288 0:a7a43371b306 3 mbed Device Server uses the Device Management and Service Enabler to access Object Instances and Resources available on the client. The interface provides this access through the following operations:
ram54288 0:a7a43371b306 4
ram54288 0:a7a43371b306 5 - [Create](#the-create-operation)
ram54288 0:a7a43371b306 6 - Delete
ram54288 0:a7a43371b306 7 - [Read](#the-read-operation)
ram54288 0:a7a43371b306 8 - [Write](#the-write-operation)
ram54288 0:a7a43371b306 9 - [Write Attributes](#the-write-attributes-operation)
ram54288 0:a7a43371b306 10 - [Execute](#the-execute-operation)
ram54288 0:a7a43371b306 11
ram54288 0:a7a43371b306 12 Currently, support for the Create and Delete actions is limited to Object Instances.
ram54288 0:a7a43371b306 13
ram54288 0:a7a43371b306 14 The Device Management and Service Enabler Interface supports the following data types:
ram54288 0:a7a43371b306 15
ram54288 0:a7a43371b306 16 - Text: for Resources.
ram54288 0:a7a43371b306 17 - TLV: for Object and Object Instances.
ram54288 0:a7a43371b306 18
ram54288 0:a7a43371b306 19 ## The Create operation
ram54288 0:a7a43371b306 20
ram54288 0:a7a43371b306 21 There are two types of resources you can create:
ram54288 0:a7a43371b306 22
ram54288 0:a7a43371b306 23 - Static: you set the value of the resource once and it does not change during the course of operations.
ram54288 0:a7a43371b306 24 - Dynamic: the value is expected to change during the course of operations. Therefore, the value is fetched from setter APIs every time the server requests a read operation.
ram54288 0:a7a43371b306 25
ram54288 0:a7a43371b306 26 Here is an example of creating a custom static Resource:
ram54288 0:a7a43371b306 27
ram54288 0:a7a43371b306 28 ```
ram54288 0:a7a43371b306 29 #include "mbed-client/m2mobject.h"
ram54288 0:a7a43371b306 30 #include "mbed-client/m2mobjectinstance.h"
ram54288 0:a7a43371b306 31 #include "mbed-client/m2mresource.h"
ram54288 0:a7a43371b306 32 _object = M2MInterfaceFactory::create_object("Test");
ram54288 0:a7a43371b306 33 if(_object) {
ram54288 0:a7a43371b306 34 M2MObjectInstance* inst = _object->create_object_instance();
ram54288 0:a7a43371b306 35 if(inst) {
ram54288 0:a7a43371b306 36 inst->create_static_resource("S",
ram54288 0:a7a43371b306 37 "ResourceTest",
ram54288 0:a7a43371b306 38 STATIC_VALUE,
ram54288 0:a7a43371b306 39 sizeof(STATIC_VALUE)-1);
ram54288 0:a7a43371b306 40 ```
ram54288 0:a7a43371b306 41
ram54288 0:a7a43371b306 42 And here is an example of creating a custom dynamic Resource:
ram54288 0:a7a43371b306 43
ram54288 0:a7a43371b306 44 ```
ram54288 0:a7a43371b306 45 #include "mbed-client/m2mobject.h"
ram54288 0:a7a43371b306 46 #include "mbed-client/m2mobjectinstance.h"
ram54288 0:a7a43371b306 47 #include "mbed-client/m2mresource.h"
ram54288 0:a7a43371b306 48 _object = M2MInterfaceFactory::create_object("Test");
ram54288 0:a7a43371b306 49 if(_object) {
ram54288 0:a7a43371b306 50 M2MObjectInstance* inst = _object->create_object_instance();
ram54288 0:a7a43371b306 51 if(inst) {
ram54288 0:a7a43371b306 52 M2MResource* res = inst->create_dynamic_resource("D","ResourceTest",true);
ram54288 0:a7a43371b306 53 char buffer[20];
ram54288 0:a7a43371b306 54 int size = sprintf(buffer,"%d",_value);
ram54288 0:a7a43371b306 55 res->set_operation(M2MBase::GET_PUT_ALLOWED);
ram54288 0:a7a43371b306 56 res->set_value((const uint8_t*)buffer,
ram54288 0:a7a43371b306 57 (const uint32_t)size);
ram54288 0:a7a43371b306 58 ```
ram54288 0:a7a43371b306 59
ram54288 0:a7a43371b306 60 For more information on different resource functionalities, please check the [API documentation](https://docs.mbed.com/docs/mbed-client-guide/en/latest/api/annotated.html) for the M2MObject, M2MObjectInstance and M2MResource classes.
ram54288 0:a7a43371b306 61
ram54288 0:a7a43371b306 62 ## The Read operation
ram54288 0:a7a43371b306 63
ram54288 0:a7a43371b306 64 The Client API allows setting values to Resources, an array of Resource Instances, an Object Instance or all the Object Instances of an Object (TLV format supported). mbed Device Server can then read these values using the **Read** operation.
ram54288 0:a7a43371b306 65
ram54288 0:a7a43371b306 66 ## The Write operation
ram54288 0:a7a43371b306 67
ram54288 0:a7a43371b306 68 The **Write** operation is used to overwrite the value of a Resource, an array of Resource Instances or multiple Resources from an Object Instance.
ram54288 0:a7a43371b306 69
ram54288 0:a7a43371b306 70 Whenever there is a valid `PUT` operation for any of the resources, the application will receive a callback:
ram54288 0:a7a43371b306 71
ram54288 0:a7a43371b306 72 ```
ram54288 0:a7a43371b306 73 void value_updated(M2MBase *base, M2MBase::BaseType type)
ram54288 0:a7a43371b306 74 ```
ram54288 0:a7a43371b306 75 Where `M2MBase` is the Object whose value has been updated and `M2MBase::BaseType` is the object type.
ram54288 0:a7a43371b306 76
ram54288 0:a7a43371b306 77 Check the code snippet below for usage.
ram54288 0:a7a43371b306 78 ```
ram54288 0:a7a43371b306 79 void value_updated(M2MBase *base, M2MBase::BaseType type) {
ram54288 0:a7a43371b306 80 M2MResource* resource = NULL;
ram54288 0:a7a43371b306 81 M2MResourceInstance* res_instance = NULL;
ram54288 0:a7a43371b306 82 M2MObjectInstance* obj_instance = NULL;
ram54288 0:a7a43371b306 83 M2MObject* obj = NULL;
ram54288 0:a7a43371b306 84 String object_name = "";
ram54288 0:a7a43371b306 85 String resource_name = "";
ram54288 0:a7a43371b306 86 uint16_t object_instance_id = 0;
ram54288 0:a7a43371b306 87 uint16_t resource_instance_id = 0;
ram54288 0:a7a43371b306 88 if(base) {
ram54288 0:a7a43371b306 89 switch(base->base_type()) {
ram54288 0:a7a43371b306 90 case M2MBase::Object:
ram54288 0:a7a43371b306 91 obj = (M2MObject *)base;
ram54288 0:a7a43371b306 92 object_name = obj->name();
ram54288 0:a7a43371b306 93 break;
ram54288 0:a7a43371b306 94 case M2MBase::ObjectInstance:
ram54288 0:a7a43371b306 95 obj_instance = (M2MObjectInstance *)base;
ram54288 0:a7a43371b306 96 object_name = obj_instance->name();
ram54288 0:a7a43371b306 97 object_instance_id = obj_instance->instance_id();
ram54288 0:a7a43371b306 98 break;
ram54288 0:a7a43371b306 99 case M2MBase::Resource: {
ram54288 0:a7a43371b306 100 resource = (M2MResource*)base;
ram54288 0:a7a43371b306 101 object_name = resource->object_name();
ram54288 0:a7a43371b306 102 object_instance_id = resource->object_instance_id();
ram54288 0:a7a43371b306 103 resource_name = resource->name();
ram54288 0:a7a43371b306 104 printf("Value updated, object name %s, object instance id %d, resource name %s\r\n",
ram54288 0:a7a43371b306 105 resource->object_name().c_str(), resource->object_instance_id(), resource->name().c_str());
ram54288 0:a7a43371b306 106 }
ram54288 0:a7a43371b306 107 break;
ram54288 0:a7a43371b306 108 case M2MBase::ResourceInstance: {
ram54288 0:a7a43371b306 109 res_instance = (M2MResourceInstance*)base;
ram54288 0:a7a43371b306 110 object_name = res_instance->object_name();
ram54288 0:a7a43371b306 111 object_instance_id = res_instance->object_instance_id();
ram54288 0:a7a43371b306 112 resource_name = res_instance->name();
ram54288 0:a7a43371b306 113 resource_instance_id = res_instance->instance_id();
ram54288 0:a7a43371b306 114 }
ram54288 0:a7a43371b306 115 break;
ram54288 0:a7a43371b306 116 default:
ram54288 0:a7a43371b306 117 break;
ram54288 0:a7a43371b306 118 }
ram54288 0:a7a43371b306 119 }
ram54288 0:a7a43371b306 120 }
ram54288 0:a7a43371b306 121 ```
ram54288 0:a7a43371b306 122 By default, callbacks are handled in the `value_updated()` function but the application can also define a callback function for an individual resource.
ram54288 0:a7a43371b306 123
ram54288 0:a7a43371b306 124 Check the code snippet below for usage.
ram54288 0:a7a43371b306 125
ram54288 0:a7a43371b306 126 ```
ram54288 0:a7a43371b306 127 static void value_updated_global(const char *name) {
ram54288 0:a7a43371b306 128 if(name) {
ram54288 0:a7a43371b306 129 ...
ram54288 0:a7a43371b306 130 }
ram54288 0:a7a43371b306 131 }
ram54288 0:a7a43371b306 132
ram54288 0:a7a43371b306 133 void M2MLWClient::value_updated_function(const char* name) {
ram54288 0:a7a43371b306 134 if (name) {
ram54288 0:a7a43371b306 135 ...
ram54288 0:a7a43371b306 136 }
ram54288 0:a7a43371b306 137 }
ram54288 0:a7a43371b306 138
ram54288 0:a7a43371b306 139 M2MResource* res = inst->create_dynamic_resource("D", "ResourceTest", true);
ram54288 0:a7a43371b306 140 char buffer[20];
ram54288 0:a7a43371b306 141 int size = sprintf(buffer,"%d",_value);
ram54288 0:a7a43371b306 142 res->set_operation(M2MBase::GET_PUT_POST_DELETE_ALLOWED);
ram54288 0:a7a43371b306 143 res->set_value((const uint8_t*)buffer, (const uint32_t)size);
ram54288 0:a7a43371b306 144 res->set_value_updated_function(value_updated_callback(this,&MbedClient::value_updated_function));
ram54288 0:a7a43371b306 145 /* Overloaded function can be used If callback function is not in class scope.
ram54288 0:a7a43371b306 146 res2->set_value_updated_function(value_updated_callback2(&value_updated_global));
ram54288 0:a7a43371b306 147 */
ram54288 0:a7a43371b306 148
ram54288 0:a7a43371b306 149 ```
ram54288 0:a7a43371b306 150
ram54288 0:a7a43371b306 151 ## The Write Attributes operation
ram54288 0:a7a43371b306 152
ram54288 0:a7a43371b306 153 Any readable Resource can have attributes that are considered during the [**Observe** operation](info_reporting.md#the-observe-feature). The following attributes are used:
ram54288 0:a7a43371b306 154
ram54288 0:a7a43371b306 155 - Minimum Period (pmin)
ram54288 0:a7a43371b306 156 - Maximum Period (pmax)
ram54288 0:a7a43371b306 157 - Greater Than (gt)
ram54288 0:a7a43371b306 158 - Less Than (lt)
ram54288 0:a7a43371b306 159 - Step (st)
ram54288 0:a7a43371b306 160
ram54288 0:a7a43371b306 161 mbed Device Server sets the endpoint attribute values that are used to determine when the endpoint sends the Resource value to the server.
ram54288 0:a7a43371b306 162
ram54288 0:a7a43371b306 163 Check the [LWM2M Specification](http://technical.openmobilealliance.org/Technical/technical-information/release-program/current-releases/oma-lightweightm2m-v1-0) for details of all the possible **Write Attributes** defined for different types of Objects and Resources.
ram54288 0:a7a43371b306 164
ram54288 0:a7a43371b306 165 ## The Execute operation
ram54288 0:a7a43371b306 166
ram54288 0:a7a43371b306 167 mbed Device Server uses the **Execute** operation to perform an action. This operation can only be performed on individual Resources.
ram54288 0:a7a43371b306 168
ram54288 0:a7a43371b306 169 <span class="notes">**Note:** mbed Client returns an error when the **Execute** operation is received for Object Instances or Resource Instances.</span>
ram54288 0:a7a43371b306 170
ram54288 0:a7a43371b306 171 If you want to execute a piece of code in your application, you can pass a `POST` request from mbed Device Server.
ram54288 0:a7a43371b306 172 When your Resource receives the `POST` request, mbed Client parses the payload from the request and wraps it in the `M2MResource::M2MExecuteParameter` class. The class object is passed through the execute callback function.
ram54288 0:a7a43371b306 173 You can then typecast the `void*` argument into the corresponding `M2MResource::M2MExecuteParameter` and access the passed payload and its length through the given API. M2MResource::M2MExecuteParameter contains also information which object and object instance resource belongs to. Make sure that the payload sent through POST request is in `plain/text` format and that the content-type is set as “plain/text” on the POST request call.
ram54288 0:a7a43371b306 174
ram54288 0:a7a43371b306 175 Check the code snippet below for usage.
ram54288 0:a7a43371b306 176
ram54288 0:a7a43371b306 177 ```
ram54288 0:a7a43371b306 178 #include "mbed-client/m2mobject.h"
ram54288 0:a7a43371b306 179 #include "mbed-client/m2mobjectinstance.h"
ram54288 0:a7a43371b306 180 #include "mbed-client/m2mresource.h"
ram54288 0:a7a43371b306 181 static void execute_function_2(void *argument) {
ram54288 0:a7a43371b306 182 if(argument) {
ram54288 0:a7a43371b306 183 M2MResource::M2MExecuteParameter* param = (M2MResource::M2MExecuteParameter*)argument;
ram54288 0:a7a43371b306 184 int payload_length = param->get_argument_value_length();
ram54288 0:a7a43371b306 185 uint8_t* payload = param->get_argument_value();
ram54288 0:a7a43371b306 186 String object_name = param->get_argument_object_name();
ram54288 0:a7a43371b306 187 uint16_t object_instance_id = param->get_argument_object_instance_id();
ram54288 0:a7a43371b306 188 String resource_name = param->get_argument_resource_name();
ram54288 0:a7a43371b306 189 }
ram54288 0:a7a43371b306 190
ram54288 0:a7a43371b306 191 void M2MLWClient::execute_function(void *argument) {
ram54288 0:a7a43371b306 192 if(argument) {
ram54288 0:a7a43371b306 193 M2MResource::M2MExecuteParameter* param = (M2MResource::M2MExecuteParameter*)argument;
ram54288 0:a7a43371b306 194 int payload_length = param->get_argument_value_length();
ram54288 0:a7a43371b306 195 uint8_t* payload = param->get_argument_value();
ram54288 0:a7a43371b306 196 String object_name = param->get_argument_object_name();
ram54288 0:a7a43371b306 197 uint16_t object_instance_id = param->get_argument_object_instance_id();
ram54288 0:a7a43371b306 198 String resource_name = param->get_argument_resource_name();
ram54288 0:a7a43371b306 199 }
ram54288 0:a7a43371b306 200
ram54288 0:a7a43371b306 201 _object = M2MInterfaceFactory::create_object("Test");
ram54288 0:a7a43371b306 202 if(_object) {
ram54288 0:a7a43371b306 203 M2MObjectInstance* inst = _object->create_object_instance();
ram54288 0:a7a43371b306 204 if(inst) {
ram54288 0:a7a43371b306 205 M2MResource* res = inst->create_dynamic_resource("D","ResourceTest",true);
ram54288 0:a7a43371b306 206 char buffer[20];
ram54288 0:a7a43371b306 207 int size = sprintf(buffer,"%d",_value);
ram54288 0:a7a43371b306 208 res->set_operation(M2MBase::GET_PUT_POST_ALLOWED);
ram54288 0:a7a43371b306 209 res->set_value((const uint8_t*)buffer,
ram54288 0:a7a43371b306 210 (const uint32_t)size);
ram54288 0:a7a43371b306 211 res->set_execute_function(execute_callback(this,&M2MLWClient::execute_function));
ram54288 0:a7a43371b306 212 /* Overloaded function can be used If callback function is not in class scope.
ram54288 0:a7a43371b306 213 res->set_execute_function(execute_callback_2(&execute_function_2));
ram54288 0:a7a43371b306 214 */
ram54288 0:a7a43371b306 215 ```
ram54288 0:a7a43371b306 216
ram54288 0:a7a43371b306 217 The POST method allows the client to respond immediately with the updated payload value as a piggyback response. If you want to send the payload response to the server later (because the Execute operation may take longer time on device to complete), you can handle this through the API.
ram54288 0:a7a43371b306 218
ram54288 0:a7a43371b306 219 You can set the resource API `void set_delayed_response(bool)` to `true`. In this case, the POST request response to the server is an empty acknowledgment. When your resource is ready with the response, you can simply call `send_delayed_post_response()` on that resource and the client sends the latest resource value to the server as part of a separate response to the POST request. By default, `void set_delayed_response(bool)` is `false`, which means that the POST response returns the resource value as a piggyback payload immediately.