From 985e493445dff4a7dafab4fdaedf559d6f2b8493 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Thu, 25 Feb 2016 15:46:44 +1300 Subject: [PATCH 01/40] Minor edit --- doc/userguide.md | 430 +++++++++++++++++++++-------------------------- 1 file changed, 193 insertions(+), 237 deletions(-) diff --git a/doc/userguide.md b/doc/userguide.md index 2c192e7..c9dde78 100644 --- a/doc/userguide.md +++ b/doc/userguide.md @@ -89,7 +89,6 @@ Currently the IPC interface is implemented as a simple UDP channel, with an asso ### The Awa server daemon. - Usage: ````awa_serverd [options] ```` | options | description | @@ -195,373 +194,330 @@ Example on how to interconnect all the daemons locally... ---- -## LWM2M Client Usage. - -### Connecting the Gateway client to the Gateway LWM2M server. - - $ build/core/src/bootstrap/awa_bootstrapd --verbose --port 15685 - $ build/core/src/server/awa_serverd --verbose - $ build/core/src/client/awa_clientd --endPointName client1 --bootstrap coap://127.0.0.1:15685 - -## Awa_API. - - The Awa API provides a method for applications to communicate with the LWM2M Client and Server daemons via the IPC interface. - - The Client API header file can be found in "include/Awa/client.h". - - The Server API header file can be found in "include/Awa/server.h". - - Both server and client APIs are implemented within the libawa library. Applications can be linked against the either the static library "libawa.a" or shared library "libawa.so". - - The api/example directory contains a number of usage examples. - - The tools directory contains a number of useful tools. These are built with the daemons, by default. - -## Awa Client API tools. - - A number of command-line tools are provided for user interaction with the LWM2M daemon. These tools provide simple operations such as defining a custom object type, setting a resource value, retrieving a resource value, and waiting for a resource to change or be executed. They interact with the LWM2M daemon via the SDK and IPC channel, and are applications that interact with the daemon locally. - - Note that these are *not* LWM2M Protocol tools - they do not issue LWM2M operations. - -### Common Options. - - Each tool accepts the --help option to display all supported options. Common options include: - - -h, --help Print help and exit - -V, --version Print version and exit - -v, --verbose Increase program verbosity (shows more run-time information) - -d, --debug Increase program verbosity (shows a lot of run-time information) - -a, --ipcAddress=ADDRESS Connect to client daemon at address (default=`127.0.0.1') - -p, --ipcPort=PORT Connect to IPC port (default=`12345') - - --ipcAddress is used to specify the IP address of the client daemon to connect to. - - --ipcPort is used to specify the IPC port that the tool uses to communicate with the daemon. Both the daemon and the tool must use the same port. Changing the port allows users to run multiple instances of the client daemon on the same host. - - Most tools take one or more PATH parameters, specified in the format: - - /O - specifies the object ID for operations on entire object types. - /O/I - specifies the object ID and object instance ID for operations on specific object instances. - /O/I/R - specifies the object ID, object instance ID, and resource ID for operations on specific resources. - /O/I/R/i - specifies the object ID, object instance ID, resource ID and resource instance ID for operations on specific resource instances. - - For tools that write data, values can be specified with the format: - - PATH=VALUE - -## Defining a New Object definition. - - To create a custom object, the object definition must be registered with the daemon. The *add-definition* tool can be used to perform this operation. - - **NOTE: Any custom objects must be defined for both the Client and Server daemon - use the awa-server-add-definition tool to define a custom object with the server** - - First, the object itself is defined by providing an ID, descriptive name, mandatory or optional flag (to determine whether the device must provide at least one instance), and whether the object supports single or multiple instances. - - -o, --objectID=ID Object ID - -j, --objectName=NAME Object name - -m, --objectMandatory Object is required or optional (default=off) - -y, --objectInstances=TYPE Object supports single or multiple instances - (possible values="single", "multiple" - default=`single') +### How to use the LWM2M client. - Then each resource is specified by a sequence of resource options: - - -r, --resourceID=ID Resource ID - -n, --resourceName=NAME Resource Name - -t, --resourceType=TYPE Resource Type (possible values="opaque", - "integer", "float", "boolean", - "string", "time", "objectlink", - "none") - -u, --resourceInstances=VALUE Resource supports single or multiple instances - (possible values="single", "multiple") - -q, --resourceRequired=VALUE Resource is required or optional (possible - values="optional", "mandatory") - -k, --resourceOperations=VALUE - Resource Operation (possible values="r", - "w", "e", "rw", "rwe") +### Connecting the gateway client to the gateway LWM2M server. +```` +$ build/core/src/bootstrap/awa_bootstrapd --verbose --port 15685 +$ build/core/src/server/awa_serverd --verbose +$ build/core/src/client/awa_clientd --endPointName client1 --bootstrap coap://127.0.0.1:15685 +```` - For each --resourceID option, all other resource options must be specified. +### Awa_API. - For example, to define TestObject2 as ObjectID 1000, with a single mandatory instance, and three resources: +The Awa API provides a way for applications to communicate with the LWM2M client and server daemons via the IPC interface. +The client API header file can be found in "include/Awa/client.h". +The server API header file can be found in "include/Awa/server.h". +Both server and client APIs are implemented in the *libawa* library. Applications may be linked against the either the static library *libawa.a* or the shared library *libawa.so*. - ./awa-client-define \ - --objectID=1000 --objectName=TestObject2 --objectMandatory --objectInstances=single \ - --resourceID=0 --resourceName=Resource0 --resourceType=string --resourceInstances=single --resourceRequired=mandatory --resourceOperations=rw \ - --resourceID=1 --resourceName=Resource1 --resourceType=integer --resourceInstances=single --resourceRequired=mandatory --resourceOperations=rw \ - --resourceID=2 --resourceName=Resource2 --resourceType=none --resourceInstances=single --resourceRequired=optiona --resourceOperations=e +Useful examples can be found in the *api/example* folder. The tools directory contains a number of useful tools. These are built with the daemons, by default. - Alternatively, an XML Definition file can be used to define a custom object - however this is not yet supported. +## Awa client API tools. -## Discovering a Device's Object and Resource Definitions. +Several command-line tools are available for user interaction with the LWM2M daemon. These tools support simple operations, such as defining a custom object type, setting a resource value, retrieving a resource value, and waiting for a resource to change or be executed. They interact with the LWM2M daemon via the SDK and IPC channel, and are applications that interact with the daemon locally. -You can discover the objects and resources that have been defined on the LWM2M server. The *awa-client-explore* tool can be used to perform this operation. The tool will list the objects and object-resources that are currently defined within the client daemon. +Note that these are *not* LWM2M Protocol tools - they do not issue LWM2M operations. -For example: +### Common options. - ./awa-client-explore +Common options include: -## Set a Resource Value. +| options | description | +|-----|-----| +| -h, --help | Print help and exit | +| -V, --version | Print version and exit | +| -v, --verbose | Increase program verbosity (shows more run-time information) | +| -d, --debug | Increase program verbosity (shows a lot of run-time information) | +| -a, --ipcAddress=ADDRESS | Connect to client daemon at address (default=`127.0.0.1') | +| -p, --ipcPort=PORT | Connect to IPC port (default=`12345') | - To set the value of a resource, the *awa-client-set* tool can be used. +*--ipcAddress* is used to specify the IP address of the client daemon to connect to. +*--ipcPort* is used to specify the IPC port that the tool uses to communicate with the daemon. Both the daemon and the tool must use the same port. Changing the port allows users to run multiple instances of the client daemon on the same host. - Mandatory resources should always exist provided the object instance exists. However before the value of any resource can be set, the object instance must first be created. And before an optional resource can be set, this resource must first be created. +Most tools take one or more PATH parameters, specified in the format: - For example, consider the case where object /1000 has been defined but no instances have been created. The following - command can be used to create instance 0 of object 1000: +| parameter | description | +|-----|-----| +| /O | specifies the object ID for operations on entire object types. | +| /O/I | specifies the object ID and object instance ID for operations on specific object instances. | +| /O/I/R | specifies the object ID, object instance ID, and resource ID for operations on specific resources. | +| /O/I/R/i | specifies the object ID, object instance ID, resource ID and resource instance ID for operations on specific resource instances. | - ./awa-client-set --create /1000/0 +For tools that write data, values can be specified with the format: ````PATH=VALUE```` - Any resources defined as optional must also be created before they can be set. +## Creating a new object definition. - For example: +An *object* is a collection of individual *resources* bundled together under a single identifier, along with some extra attributes that describe the nature of the object (listed below). Numerous standard objects are pre-defined within the LWM2M model but additional custom objects may also be defined as needed. Custom objects are created by registering the new object definition with the daemon. The *add-definition* tool is used to perform this operation. Note that an object definition does not result in an object instance. Creation of an object instance is a separate process. Resource manipulation is only possible on object instances. - ./awa-client-set --create /1000/0/0 +**NOTE: A custom object must be defined for both the client *and* server daemons. Use the *awa-server-add-definition* tool to define a custom object with the server.** - In the case where no value is specified the resource will be created and populated with the default values. +Firstly the object itself is defined by providing an ID, descriptive name, mandatory or optional flag (to determine whether the device must provide at least one instance), and whether the object supports single or multiple instances. - Once the resource has been created, the value of the resource can be set. +| object attribute | description | +|-----|-----| +| -o, --objectID=ID | Object ID | +| -j, --objectName=NAME | Object name | +| -m, --objectMandatory | Object is required or optional (default=off) | +| -y, --objectInstances=TYPE | Object supports single or multiple instances (possible values: *single* (default) or *multiple*) | - For example, to set the value of resource 0 (of type string), within object instance 0 of object 1000, to the value "Happy": +Secondly, each resource in the object is specified by a sequence of resource options: - ./awa-client-set /1000/0/0=Happy +| resource option | description | +|-----|-----| +| -r, --resourceID=ID | Resource ID | +| -n, --resourceName=NAME | Resource name | +| -t, --resourceType=TYPE | Resource type ( possible values: *opaque, integer, float, boolean, string, time, objectlink, none*) | +| -u, --resourceInstances=VALUE | Resource supports single or multiple instances (possible values: *single, multiple*) | +| -q, --resourceRequired=VALUE | Resource is required or optional (possible values: *optional, mandatory*) | +| -k, --resourceOperations=VALUE | Resource operation (possible values: *r, w, e, rw, rwe*) | - Note that it is not possible to set the value of a resource that is of type None. +**Note. For each *--resourceID* option, all other resource options must be specified.** - A specific resource instance of a multi-instance resource can be set with: +Example. Define TestObject2 as ObjectID 1000, with a single mandatory instance, and three resources: +```` +./awa-client-define \ + --objectID=1000 --objectName=TestObject2 --objectMandatory --objectInstances=single \ + --resourceID=0 --resourceName=Resource0 --resourceType=string --resourceInstances=single --resourceRequired=mandatory --resourceOperations=rw \ + --resourceID=1 --resourceName=Resource1 --resourceType=integer --resourceInstances=single --resourceRequired=mandatory --resourceOperations=rw \ + --resourceID=2 --resourceName=Resource2 --resourceType=none --resourceInstances=single --resourceRequired=optiona --resourceOperations=e +```` - ./awa-client-set /1000/0/1/7=Seventh +### Discovering a device's object and resource definitions. - Multiple set operations can be combined on the command line: +The *awa-client-explore* tool can be used to discover the objects and resources that have been defined on the LWM2M server. The tool will also list the objects and object-resources that are currently defined within the client daemon. - ./awa-client-set --create /1000/0 /1000/0/0=Happy /1000/0/1/7=Seventh +Example: ````./awa-client-explore ```` -## Get a Resource Value. +### Setting resource values. - To retrieve the value of a resource and display it on the console, the *awa-client-get* tool can be used. +The *awa-client-set* tool can be used to set the value of a resource. - For example, to fetch and display the value of resource 0, within instance 0 of object 1000: +Mandatory resources always exist provided that the parent *object instance* exists, thus before the value of any resource can be set, the object instance must first be created. Before an *optional resource* can be set, this resource must first be created. - ./awa-client-get /1000/0/0 +Example. Consider the case where object /1000 has been defined but no instances have been created. The following can be used to create instance 0 of object 1000: ````./awa-client-set --create /1000/0 ```` - Multiple resources can be fetched: +Any mandatory resources associated with the object instance will also be instantiated with default values, but any resources defined as optional must be created explicitly before they can be set. - ./awa-client-get /1000/0/1 /1000/0/5 +For example, to create an instance of the optional resource 0 within instance 0 of object 1000: ````./awa-client-set --create /1000/0/0 ```` - Entire object instances can be fetched: +Because no value is specified for the new resource instance, it will be created and populated with its default value. - ./awa-client-get /1000/0 +Once the resource has been created, its value can be set. - All object instances for an object ID can be fetched: +For example, to set the value of resource 0 (which is of type string), within object instance 0 of object 1000, to the value *Happy*: - ./awa-client-get /1000 +````./awa-client-set /1000/0/0=Happy ```` - If the resource specified is a multiple-instance resource, all instances will be retrieved. Individual instances can be displayed by specifying the resource instance index: +**Note that it is not possible to set the value of a resource that is of type *None*.** - ./awa-client-get /1000/0/5/1 /1000/0/5/2 +A specific resource instance of a multi-instance resource can be set with: ````./awa-client-set /1000/0/1/7=Seventh ```` - The --quiet/-q option can be used to suppress the extra information displayed. +Multiple set operations can be combined on the command line: + + ````./awa-client-set --create /1000/0 /1000/0/0=Happy /1000/0/1/7=Seventh ```` -## Subscribe to a Change to a Resource. +### Retrieving a resource value. - It may be important for a script to block until the value of a resource changes, or an LWM2M Execute operation is performed on an resource that supports the execute operation. For this purpose, the *awa-client-subscribe* tool can be used. +The *awa-client-get* tool is used to retrieve the value of a client object resource and display it on the console. - This tool will display notifications whenever the target resource or object instance changes, or a target resource receives an Execute operation. When such a notification arrives, it will print details in the console. +For example, to retrieve and display the value of resource 0, within instance 0 of object 1000: ````./awa-client-get /1000/0/0 ```` - Note that this is **not** equivalent to a LWM2M Observe operation. This tool is observing the local resource hosted by the client daemon. +Multiple resources can be retrieved: ````./awa-client-get /1000/0/1 /1000/0/5 ```` - For example, to wait for a change to resource 200 within instance 0 of object 1000: +Entire object instances can be retrieved: ````./awa-client-get /1000/0 ```` - ./awa-client-subscribe /1000/0/200 +All object instances for an object ID can also be retrieved: ````./awa-client-get /1000 ```` - To wait for a change to any resource within instance 0 of object 1000: +If the resource specified is a multiple-instance resource, all instances will be retrieved. Individual instances can be displayed by specifying the resource instance index: ````./awa-client-get /1000/0/5/1 /1000/0/5/2 ```` - ./awa-client-subscribe /1000/0 +The *--quiet/-q* option can be used to suppress the display of any extra information. - Waiting for an LWM2M Execute operation is also possible, however a specific object instance and resource must be specified. For example, to wait on resource 4, which is an executable resource of instance 0 of object 3: +## Subscribing to a change of resource value. - ./awa-client-subscribe /3/0/4 +In some cases it may be important for a script to block until the value of a resource changes, or for an LWM2M resource execute operation to complete. The *awa-client-subscribe* tool can be used to act as a listener. - By default, *awa-client-subscribe* will wait indefinitely, displaying each notification as it arrives. With the time and count options, *awaclient-subscribe* can terminate after a number of notifications, or an elapsed period of time. +The *awa-client-subscribe* tool will display notifications whenever the value of the target resource or object instance changes, or when a target resource receives an execute operation. When a notification arrives, the details will be printed to the console. - -t, --waitTime=SECONDS Time to wait for notification (default=`0') - -c, --waitCount=NUMBER Number of notifications to wait for (default=`0') +Note that *awa-client-subscribe* is *not* the same a LWM2M *Observe* operation. This tool is listening to the local resource hosted by the client daemon. - For example, to wait for no longer than 60 seconds for a single notification: +For example, to listen for a change to resource 200 within instance 0 of object 1000: ````./awa-client-subscribe /1000/0/200 ```` - ./awa-client-subscribe /3/0/4 --waitTime=60 --waitCount=1 +To listen for a change to any resource within instance 0 of object 1000: ````./awa-client-subscribe /1000/0 ```` - Multiple paths can be combined on the command line: +Listening for an LWM2M Execute operation is also possible, however the target object instance and resource must be fully specified. For example, to wait on resource 4, which is an executable resource of instance 0 of object 3: ````./awa-client-subscribe /3/0/4 ```` - ./awa-client-subscribe /3/0/4 /3/0/5 /4 +By default, *awa-client-subscribe* will wait indefinitely, displaying each notification as it arrives. With the time and count options, *awaclient-subscribe* can terminate after a number of notifications, or an elapsed period of time. -## Delete a Resource. +| option | description | +|-----|-----| +| -t, --waitTime=SECONDS | Time to wait for notification (default=`0') | +| -c, --waitCount=NUMBER | Number of notifications to wait for (default=`0') | - To delete a resource from the client, the *awa-client-delete* tool can be used. - For example, to delete all object instances of object type 1000: +For example, to wait for no longer than 60 seconds for a single notification: ````./awa-client-subscribe /3/0/4 --waitTime=60 --waitCount=1 ```` - ./awa-client-delete /1000 +Multiple paths can be combined on the command line: ````./awa-client-subscribe /3/0/4 /3/0/5 /4 ```` - To delete the object instance of object type 1000 with ID 0: +### Deleting a resource. - ./awa-client-delete /1000/0 +To delete an object or resource instance from the client, use the *awa-client-delete* tool. +For example, to delete all object instances of object type 1000: ````./awa-client-delete /1000 ```` - To delete the resource with ID 5 from instance 0 of object ID 1000: +To delete the object instance of object type 1000 with ID 0: ````./awa-client-delete /1000/0 ```` - ./awa-client-delete /1000/0/5 +To delete the resource with ID 5 from instance 0 of object ID 1000: ````./awa-client-delete /1000/0/5 ```` - Unlike the *awa-server-delete* tool, this tool can modify the client's data structures directly, so is not limited by LWM2M Delete rules. +Unlike the *awa-server-delete* tool, this tool can modify the client's data structures directly, so is not limited by LWM2M Delete rules. -## Awa Server API Tools. +### Awa Server API tools. - Server tools are used to communicate with the LWM2M Server daemon and typically issue one or more LWM2M operations to a connected client. +Server tools are used to communicate with the LWM2M Server daemon and typically issue one or more LWM2M operations to a connected client. - Server tools often require a target client ID to be specified: +Server tools often require a target client ID to be specified: - -c, --clientID=ID ClientID +| option | description | +|-----|-----| +| -c, --clientID=ID | ClientID is the client endpoint name used by the client when registering with the LWM2M server. | - This ID is the client endpoint name used by the client when registering with the LWM2M server. -## List Registered Clients. +### Listing registered clients. The *awa-server-list-clients* tool can be used to list all clients currently registered with the LWM2M server daemon: - ./awa-server-list-clients - - The --clientID/-c option is not required. Each client endpoint name is displayed, one per line. +````./awa-server-list-clients ```` - If --verbose/-v is specified, the output shows the number of registered clients, and their client endpoint names: +The *--clientID/-c* option is not required. Each client endpoint name is displayed, one per line. - ./awa-server-list-clients --verbose - 2 Registered Clients: +If *--verbose/-v* is specified, the output shows the number of registered clients, and their client endpoint names: - 1 imagination1 - 2 chris - - The option --objects/-o can be specified to retrieve and display the objects and object instances currently registered with the LWM2M server, for example: - - ./awa-server-list-clients --objects - 1 imagination1 <2/0>,<4/0>,<7>,<3/0>,<5>,<6>,<0/1>,<1/1> - - The syntax is or . - - -## Define a New Object Definition. - - To use a custom object, the object definition must be registered with the server daemon. The *awa-server-define* tool can be used to perform this operation. +For eaxmple: ````./awa-server-list-clients --verbose ```` + +Returns: +```` +1 imagination1 +2 chris +```` - The *awa-server-define* tool has identical functionality to the *awa-client-define* tool, outlined in the section above. +The option *--objects/-o* can be specified to retrieve and display the objects and object instances currently registered with the LWM2M server in the format ```````` or ````````. -## Write a Resource Value on a Registered Client. +For example: ````./awa-server-list-clients --objects ```` +Returns +```` +1 imagination1 <2/0>,<4/0>,<7>,<3/0>,<5>,<6>,<0/1>,<1/1> +```` - To write the value of a resource on a registered client, the *awa-server-write* tool can be used. +### Creating a new object definition on the server. - For example, to set the value of resource 0 (of type string) on the client "imagination1", within instance 0 of object 1000, to the value "Happy": +The *awa-server-define* tool is used to define custom objects on the server. To use a custom object, the object definition must be registered with the server daemon. The *awa-server-define* tool has identical functionality to *awa-client-define*, described earlier. - ./awa-server-write --clientID=imagination1 /1000/0/0=Happy +### Writing a value to a resource on a registered client. - Note that it is not possible to set the value of a resource that is of type None. +The *awa-server-write* tool is used to write the value of a resource on a registered client. - A multi-instance resource can be set by specifying the resource instances: +For example, to set the value of resource 0 (of type string) on the client "imagination1", within instance 0 of object 1000, to the value *Happy*: - ./awa-server-write --clientID=imagination1 /1000/0/5/1=123 /1000/0/5/2=456 +````./awa-server-write --clientID=imagination1 /1000/0/0=Happy ```` - To create a new instance of an object on a connected client, the --create option can be used. When an instance is created, any default values provided in the object definition are used. +Note that it is not possible to set the value of a resource that is of type *None*. - For example, to create instance 1 of object 1000 on the client "imagination1": +A multi-instance resource can be set by specifying the resource instances: - ./awa-server-write --clientID=imagination1 --create /1000/1 +````./awa-server-write --clientID=imagination1 /1000/0/5/1=123 /1000/0/5/2=456```` - To create a new instance with the next available object instance ID: +To create a new instance of an object on a connected client, the *--create* option can be used. +When an instance is created, any default values provided in the object definition are used. - ./awa-server-write --clientID=imagination1 --create /1000 +For example, to create instance 1 of object 1000 on the client *imagination1*: - The ID of the newly created object instance is displayed. +````./awa-server-write --clientID=imagination1 --create /1000/1 ```` - **Note: Create functionality is not yet supported** +To create a new instance with the next available object instance ID: -## Read a Resource Value from a Registered Client. +````./awa-server-write --clientID=imagination1 --create /1000 ```` - To retrieve the value of a resource and display it on the console, the *awa-server-read* tool can be used. +The ID of the newly created object instance is displayed. - For example, to display the value of resource 0, within instance 0 of object 1000: + **Note: Create functionality is not yet supported.** - ./awa-server-read --clientID=imagination1 /1000/0/0 +### Reading a resource value from a registered client. - Multiple resources and object instances can be read: +The *awa-server-read* tool is used to retrieve the value of a resource and display it on the console. For example, to display the value of resource 0, within instance 0 of object 1000: - ./awa-server-read -c imagination1 /1000/0/2 /1000/0/3 /1000/1 /1001 +````./awa-server-read --clientID=imagination1 /1000/0/0 ```` -## Delete an Object Instance from a Registered Client. +Multiple resources and object instances can be read using: - To delete an instance of an object from a connected client, the *awa-server-delete* tool can be used. +````./awa-server-read -c imagination1 /1000/0/2 /1000/0/3 /1000/1 /1001 ```` - For example, to delete object 1000, instance 0 from the client "imagination1": +### Deleting an object instance from a registered client. - ./awa-server-delete --clientID=imagination1 /1000/0 +The *awa-server-delete* tool is used to delete an instance of an object from a connected client. For example, to delete object 1000, instance 0 from the client "imagination1": - It is not possible to delete individual resources, resource instances, or entire objects due to LWM2M protocol restrictions. +````./awa-server-delete --clientID=imagination1 /1000/0 ```` -## Observe a Resource on a Registered Client. +**Note.** Due to LWM2M protocol restrictions it is not possible to delete individual resources, resource instances, or entire objects. - It may be important for a script to block until the value of a resource changes on a specific client. For this purpose, the *awa-server-observe* tool can be used. +### Observing a resource on a registered client. - This tool will display notifications whenever the target resource or object instance changes. When such a notification arrives, it will print details in the console. +In some cases a script may be required to block until the value of a resource changes on a specific client. For this purpose, the *awa-server-observe* tool is provided to display notifications whenever the target resource or object instance changes. - This is equivalent to a LWM2M Observe operation. This tool is observing the resources stored by a remote client. +When a notification arrives, the details will be printed to the console, which is the functional equivalent of a LWM2M *Observe* operation. - For example, to wait for a change to resource 200 within instance 0 of object 1000: +For example, to wait for a change to resource 200 within instance 0 of object 1000: - ./awa-server-observe --clientID imagination1 /1000/0/200 +````./awa-server-observe --clientID imagination1 /1000/0/200 ```` - To wait for a change to any resource within instance 0 of object 1000: +To wait for a change to any resource within instance 0 of object 1000: - ./awa-server-observe --clientID imagination1 /1000/0 +````./awa-server-observe --clientID imagination1 /1000/0 ```` - By default, *awa-server-observe* will wait indefinitely, displaying each notification as it arrives. With the time and count options, *awa-server-observe* can terminate after a number of notifications, or an elapsed period of time. +By default, *awa-server-observe* will wait indefinitely, displaying each notification as it arrives, but by using the time and count options, *awa-server-observe* can terminate after a number of notifications, or an elapsed period of time. - -t, --waitTime=SECONDS Time to wait for notification (default=`0') - -c, --waitCount=NUMBER Number of notifications to wait for (default=`0') +| option | description | +|-----|-----| +| -t, --waitTime=SECONDS | Time to wait for notification (default=`0') | +| -c, --waitCount=NUMBER | Number of notifications to wait for (default=`0') | - For example, to wait for no longer than 60 seconds for a single notification: +For example, to wait for no longer than 60 seconds for a single notification: - ./awa-server-observe --clientID imagination1 --waitTime=60 --waitCount=1 /1000/0/200 +````./awa-server-observe --clientID imagination1 --waitTime=60 --waitCount=1 /1000/0/200 ```` - Observe attributes that affect the way notifications are generated can be changed with the *awa-server-write-attributes* tool. +Observe attributes that affect the way notifications are generated can be changed with the *awa-server-write-attributes* tool. -## Execute a Resource on a Registered Client. +### Executing a resource on a registered client. - To initiate an Execute operation on a resource that supports the execute operation, the *awa-server-execute* tool can be used. +The *awa-server-execute* tool is used to initiate an *execute* operation on a resource that supports it. - For example, to initiate execution of object 1000, instance 0, resource 4 on the client "imagination1": +For example, to initiate execution of object 1000, instance 0, resource 4 on the client "imagination1": - ./awa-server-execute --clientID imagination1 /1000/0/4 +````./awa-server-execute --clientID imagination1 /1000/0/4 ```` - Multiple operations can be initiated with multiple paths: +Multiple operations can be initiated by applying multiple paths: - ./awa-server-execute --clientID imagination1 /1000/0/4 /1000/0/5 +````./awa-server-execute --clientID imagination1 /1000/0/4 /1000/0/5 ```` - Opaque data can be supplied as an argument to the execute operation by piping into the process via the --stdin option: +Opaque data can be supplied as an argument to the execute operation by piping into the process via the *--stdin* option: - ./awa-server-execute --stdin --clientID imagination1 /1000/0/4 < mydata +````./awa-server-execute --stdin --clientID imagination1 /1000/0/4 < mydata ```` - Note that data supplied is provided to all execute targets. +**Note that data supplied will be piped to all of the stated execute targets.** - It is not possible to initiate an execute operation on an object, an object instance or a resource instance. +Execute operations on an object, an object instance or a resource instance are not possible. - It is not possible to initiate an execute operation on a resource that does not support the execute operation. +### Write attribute values of a resource or object instance on a registered client. -## Write Attributes of a Resource or Object Instance on a Registered Client. +The *awa-server-write-attributes* tool is used to change the value of attributes associated with a client's resource or object instance. - To change the value of attributes associated with a client's resource or object instance, the *awa-server-write-attributes* tool can be used. +For example, to set the *pmin* value of object 1000, instance 0, resource 4 on the client "imagination1" to 5 seconds: - For example, to set the pmin value of object 1000, instance 0, resource 4 on the client "imagination1" to 5 seconds: +````./awa-server-write_attributes --clientID imagination1 /1000/0/4\?pmin=5 ```` - ./awa-server-write_attributes --clientID imagination1 /1000/0/4\?pmin=5 +Multiple attribute values can be set with the same call. For example, to set the *pmin* attribute of object 1000, instance 0 on the client "imagination1" to 5 seconds, and *pmax* to 100 for the same object instance: - For example, to set the pmin attribute of object 1000, instance 0 on the client "imagination1" to 5 seconds, and pmax to 100 for the same object instance: +````./awa-server-write_attributes --clientID imagination1 /1000/0\?pmin=5\&pmax=100 ```` - ./awa-server-write_attributes --clientID imagination1 /1000/0\?pmin=5\&pmax=100 +Note that the *?* and *&* characters will need to be escaped for most shells. - Note that the ? and & characters need to be escaped for most shells. +---- +---- From f740c803591bed4d05c0e327deb8ffa93b1852d5 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Thu, 25 Feb 2016 15:55:26 +1300 Subject: [PATCH 02/40] Added intro paragraph --- doc/coding_style.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/doc/coding_style.md b/doc/coding_style.md index 4361c39..a4e4335 100644 --- a/doc/coding_style.md +++ b/doc/coding_style.md @@ -1,5 +1,5 @@ -![](doc/img.png) +![](img.png) ---- @@ -9,6 +9,11 @@ ## Coding style guide. +It's important to that coding style remains consistent throughout the project to ensure that all contributors and project administrators are able to easily decipher code blocks, comments, syntax etc. +always consider that another contributor may one day continue to build on your submissions. Make it easy for them by adopting the style outlined below. + +### General layout. + The sample code below illustrates the preferred use of indentation, bracing and white space: ```` @@ -88,11 +93,11 @@ Bitfields also have a code size and performance overhead due to the need to be p Structure field names should use Pascal casing (e.g. ThisPerson.Age). -### Header Files. +### Header files. All public functions, variables and definitions must be declared in a header file. Most .c modules should have a corresponding .h file to be included (both within the module and elsewhere). It is poor form to make the compiler try to guess how to resolve undeclared function calls in other modules. -## Commenting. +### Code commenting. Single line comments should use *//*. For example: ```` void MyFunction(void) @@ -137,7 +142,7 @@ AwaString GetNextEntryFromProcessingQueue() } ```` -### Good/Bad Coding Practise. +### Good/Bad coding Practise. * Ideally functions should have a single exit point. The use of multiple return points is dangerous and makes it harder to read the code. Always consider what will happen if someone needs to append code to your function. * Where possible definitions should be used rather than raw values, e.g. use *AllocMessageBuf(MAX_MESSAGE_SIZE)* rather than *AllocMessagBuf(1024)*. This ensures that all code sharing the same defined value will still work if the 'magic' value is updated. From ee540dd6a1ee7587de7634f75aa4061f5ae10e2a Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Thu, 25 Feb 2016 15:57:05 +1300 Subject: [PATCH 03/40] typo correction --- doc/coding_style.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/coding_style.md b/doc/coding_style.md index a4e4335..4fb2907 100644 --- a/doc/coding_style.md +++ b/doc/coding_style.md @@ -10,7 +10,7 @@ ## Coding style guide. It's important to that coding style remains consistent throughout the project to ensure that all contributors and project administrators are able to easily decipher code blocks, comments, syntax etc. -always consider that another contributor may one day continue to build on your submissions. Make it easy for them by adopting the style outlined below. +Always consider that another contributor may one day continue to build on your submissions. Make it easy for them by adopting the style outlined below. ### General layout. From 40167ec260a7d16e441717de9ae9b9058deab56d Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Thu, 25 Feb 2016 16:01:28 +1300 Subject: [PATCH 04/40] minor edit --- doc/coding_style.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/coding_style.md b/doc/coding_style.md index 4fb2907..c6ee04c 100644 --- a/doc/coding_style.md +++ b/doc/coding_style.md @@ -65,7 +65,7 @@ typedef struct **Notes.** * A structure type definition doesn't usually need both a structure name and typedef name (a struct name is not given in the above example). One possible exception to this rule is where the typedef name is declaring a structure-pointer type. -* The use of suffix *_e* in enums is not preferred. +* The use of suffix *_e* in enums is discouraged. * To avoid namespace problems in 'C' each value should be prefixed by the enum name. For example: ```` typedef enum @@ -142,7 +142,7 @@ AwaString GetNextEntryFromProcessingQueue() } ```` -### Good/Bad coding Practise. +### Good coding practise. * Ideally functions should have a single exit point. The use of multiple return points is dangerous and makes it harder to read the code. Always consider what will happen if someone needs to append code to your function. * Where possible definitions should be used rather than raw values, e.g. use *AllocMessageBuf(MAX_MESSAGE_SIZE)* rather than *AllocMessagBuf(1024)*. This ensures that all code sharing the same defined value will still work if the 'magic' value is updated. From b5972ad39d929141ebe4a82156954ed1e608e2dd Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Thu, 25 Feb 2016 16:03:32 +1300 Subject: [PATCH 05/40] Image reference changed --- doc/userguide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/userguide.md b/doc/userguide.md index c9dde78..2306a58 100644 --- a/doc/userguide.md +++ b/doc/userguide.md @@ -1,5 +1,5 @@ -![](doc/img.png) +![](img.png) ---- # Awa LightweightM2M. From 47f9231d96858f3918718961ce93c6cf0c8ba5eb Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Thu, 25 Feb 2016 16:19:25 +1300 Subject: [PATCH 06/40] Target audience added --- doc/userguide.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/userguide.md b/doc/userguide.md index 2306a58..24844c5 100644 --- a/doc/userguide.md +++ b/doc/userguide.md @@ -6,6 +6,11 @@ ## User guide. +This document is aimed at application developers who are using the Awa LightweightM2M libraries and tools as a foundation or enhancement to, their own M2M applications. + +Developers who aim to contribute to the Awa LightweightM2M project are referred to the [developer guide](developer_guide.md). + + ### Contents. * [Introduction.](userguide.md#introduction) From e55f08b46aa57bb6a892f06a28fa5ea5d83726d4 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Thu, 25 Feb 2016 16:20:43 +1300 Subject: [PATCH 07/40] minor edit --- doc/userguide.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/userguide.md b/doc/userguide.md index 24844c5..2fe6957 100644 --- a/doc/userguide.md +++ b/doc/userguide.md @@ -10,6 +10,9 @@ This document is aimed at application developers who are using the Awa Lightweig Developers who aim to contribute to the Awa LightweightM2M project are referred to the [developer guide](developer_guide.md). +---- + + ### Contents. From d83039a2e968da0d46a805b75f96bfa3a1bda936 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Thu, 25 Feb 2016 17:33:32 +1300 Subject: [PATCH 08/40] minor edit --- doc/userguide.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/userguide.md b/doc/userguide.md index 2fe6957..2054fe6 100644 --- a/doc/userguide.md +++ b/doc/userguide.md @@ -6,9 +6,9 @@ ## User guide. -This document is aimed at application developers who are using the Awa LightweightM2M libraries and tools as a foundation or enhancement to, their own M2M applications. +This document is aimed at application developers who are using the Awa LightweightM2M libraries and tools as a foundation, or enhancement of their own M2M applications. -Developers who aim to contribute to the Awa LightweightM2M project are referred to the [developer guide](developer_guide.md). +Developers who aim to contribute to the Awa LightweightM2M project are referred to the [contributor guide](../CONTRIBUTING.md) and the [developer guide](developer_guide.md). ---- @@ -196,13 +196,14 @@ Example on how to interconnect all the daemons locally... ### Awa client tools examples. -### Awa server tools examples. +### Awa server tools examples. +---- ---- +## Using the LWM2M client. -### How to use the LWM2M client. ### Connecting the gateway client to the gateway LWM2M server. ```` @@ -211,7 +212,7 @@ $ build/core/src/server/awa_serverd --verbose $ build/core/src/client/awa_clientd --endPointName client1 --bootstrap coap://127.0.0.1:15685 ```` -### Awa_API. +### The Awa_API. The Awa API provides a way for applications to communicate with the LWM2M client and server daemons via the IPC interface. The client API header file can be found in "include/Awa/client.h". @@ -253,7 +254,7 @@ Most tools take one or more PATH parameters, specified in the format: For tools that write data, values can be specified with the format: ````PATH=VALUE```` -## Creating a new object definition. +### Creating a new object definition. An *object* is a collection of individual *resources* bundled together under a single identifier, along with some extra attributes that describe the nature of the object (listed below). Numerous standard objects are pre-defined within the LWM2M model but additional custom objects may also be defined as needed. Custom objects are created by registering the new object definition with the daemon. The *add-definition* tool is used to perform this operation. Note that an object definition does not result in an object instance. Creation of an object instance is a separate process. Resource manipulation is only possible on object instances. @@ -292,7 +293,7 @@ Example. Define TestObject2 as ObjectID 1000, with a single mandatory instance, ### Discovering a device's object and resource definitions. -The *awa-client-explore* tool can be used to discover the objects and resources that have been defined on the LWM2M server. The tool will also list the objects and object-resources that are currently defined within the client daemon. +The *awa-client-explore* tool is used to discover the objects and resources that have been defined on the LWM2M server. The tool will also list the objects and object-resources that are currently defined within the client daemon. Example: ````./awa-client-explore ```` @@ -528,4 +529,3 @@ Note that the *?* and *&* characters will need to be escaped for most shells. ---- ---- - From 74b316502b6018cab08360ec1d1a2769058ee6e7 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 09:33:40 +1300 Subject: [PATCH 09/40] no message --- api/.gitignore | 0 api/python/ipc.py | 0 lib/jsmn/apply_patches | 0 lib/libcoap/apply_patches | 0 tools/tests/run_tests | 0 5 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 api/.gitignore mode change 100755 => 100644 api/python/ipc.py mode change 100755 => 100644 lib/jsmn/apply_patches mode change 100755 => 100644 lib/libcoap/apply_patches mode change 100755 => 100644 tools/tests/run_tests diff --git a/api/.gitignore b/api/.gitignore old mode 100755 new mode 100644 diff --git a/api/python/ipc.py b/api/python/ipc.py old mode 100755 new mode 100644 diff --git a/lib/jsmn/apply_patches b/lib/jsmn/apply_patches old mode 100755 new mode 100644 diff --git a/lib/libcoap/apply_patches b/lib/libcoap/apply_patches old mode 100755 new mode 100644 diff --git a/tools/tests/run_tests b/tools/tests/run_tests old mode 100755 new mode 100644 From 40121a8b36a049f047e24f12e59818cf1adca58f Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 10:40:26 +1300 Subject: [PATCH 10/40] Image links and numbered list updated --- README.md | 18 +++++++----------- doc/userguide.md | 6 +++--- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 18e9e68..9a663d3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -![Imagination Technologies Limited logo](doc/img.png) +![Imagination Technologies Limited logo](img.png) ---- @@ -28,20 +28,16 @@ The easiest way to get started with Awa LWM2M is on a Linux PC. The following i Firstly, to obtain a copy of the Awa LWM2M source code: - 1. Sign up for a Github account + * Sign up for a Github account - 2. Install Git -``` - sudo apt-get install git -``` + * Install Git ```` sudo apt-get install git ```` + + + * Clone the repository ```` git clone https://github.com/FlowM2M/AwaLWM2M.git ```` - 3. Clone the repository -``` - git clone https://github.com/FlowM2M/AwaLWM2M.git -``` -Further instructions can be found in the [Getting started guide](doc/starters_guide.md). +Further instructions can be found in the [Getting started guide](starters_guide.md). ---- diff --git a/doc/userguide.md b/doc/userguide.md index 2054fe6..efb95a0 100644 --- a/doc/userguide.md +++ b/doc/userguide.md @@ -50,7 +50,7 @@ The client provides two interfaces: * An IPC interface which provides a mechanism for applications to talk to the daemon. -![Awa LWM2M client interfaces](doc/awa_client_interfaces.png) +![Awa LWM2M client interfaces](awa_client_interfaces.png) The IPC interface allows the end user application to define new objects and to perform Get/Set/Delete/Subscribe operations on the client. @@ -89,7 +89,7 @@ should this be here? The LWM2M server runs as a daemon which provides an interface to perform LWM2M operations on connected LWM2M clients. -![Awa LWM2M server interfaces](doc/Awa_LWM2M_server_interfaces.png) +![Awa LWM2M server interfaces](Awa_LWM2M_server_interfaces.png) The IPC interface allows the end user application to define new objects, list registered clients and perform Read/Write/Delete/Observe operations for a given LWM2M client registered with the server. Currently the IPC interface is implemented as a simple UDP channel, with an associated UDP port. It is recommended that only a single user application connect to the daemon's IPC interface at any time. @@ -123,7 +123,7 @@ For examples of how to use the LWM2M server with the LWM2M client see the *LWM2M The LWM2M Bootstrap server runs as a daemon which provides a mechanism to bootstrap LWM2M clients. -![](doc/Awa_LWM2M_bootstrap_server-interfaces.png) +![](Awa_LWM2M_bootstrap_server-interfaces.png) ### The Awa Bootstrap server daemon. From f9a0faa1af46d87e85e57e34ffd5c8e6592eb770 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 10:48:58 +1300 Subject: [PATCH 11/40] minor edit --- README.md | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 9a663d3..05aa91b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -![Imagination Technologies Limited logo](img.png) +![Imagination Technologies Limited logo](doc/img.png) ---- @@ -31,10 +31,10 @@ Firstly, to obtain a copy of the Awa LWM2M source code: * Sign up for a Github account - * Install Git ```` sudo apt-get install git ```` + * Install Git: ```` sudo apt-get install git ```` - * Clone the repository ```` git clone https://github.com/FlowM2M/AwaLWM2M.git ```` + * Clone the repository: ```` git clone https://github.com/FlowM2M/AwaLWM2M.git ```` Further instructions can be found in the [Getting started guide](starters_guide.md). @@ -56,17 +56,11 @@ Awa LWM2M documentation is available both at a general level (project informatio The Awa API documentation is available as a Doxygen presentation which is generated via the following process. - 1. Install [Doxygen ](http://www.stack.nl/~dimitri/doxygen/download.html) + 1. Install [Doxygen ](http://www.stack.nl/~dimitri/doxygen/download.html): ```` sudo apt-get install doxygen```` -``` - sudo apt-get install doxygen -``` + 2. Generate the documentation: ```` make docs```` - 2. Generate the documentation -``` - make docs -``` - The output can be found in the api/doc/html directory and viewed by opening index.html with your web browser. +The output can be found in the api/doc/html directory and viewed by opening index.html with your web browser. For convenience you can also find the latest version of this documentation [here]() From aa9c3b980fec0f33dfaee1f722af390119ee1711 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 11:51:14 +1300 Subject: [PATCH 12/40] Minor edit. --- CONTRIBUTING.md | 62 ++++++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c32f36f..cb78542 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,36 +5,41 @@ ## Contributing Guide -### Reporting a bug. +### Reporting issues and bugs. -So you have found a bug, or just generally an area which can be improved and wish to report it. +If you discover a bug, or find an issue or area that you feel needs improvement: -Navigate to the "Issues" tab on the project github page https://github.com/FlowM2M/AwaLWM2M/issues and click the "New Issue" button. +* Navigate to the "Issues" tab on the project github page https://github.com/FlowM2M/AwaLWM2M/issues -When reporting your bug, please try and be as descriptive as possible. consider adding the following information. +* Click the "New Issue" button. -``` -Description of the problem: -Awa LWM2M Version or commit id: +When making your report, be as clear and concise as possible. Ude the following list as a guide: -Environment details (OS/Distribution etc): -Reproduciblity/Frequency: -Steps to Reproduce/What you were doing when the bug occured: +* Describe the problem. -Excepted Result: +* Awa LWM2M Version or commit id. -Actual Result: +* Environment details (OS/distribution etc). + +* Reproduciblity or issue frequency. + +* Steps taken to uncover or reproduce the issue (if any). + +* Expected behaviour. + +* Actual behaviour. + +* Any addition Infomation, log output etc. -Addition Infomation (log output etc) -``` ### Branching model. All Awa LWM2M development occurs on the master branch. Developers should only submit patches against the master branch. + ### Setting up your development machine. Configure your user name to be used by git: @@ -42,17 +47,22 @@ Configure your user name to be used by git: $ git config --global user.name "FirstName LastName" $ git config --global user.email "email@email.com" + ### Coding style. -The Awa LWM2M coding style guidelines can be found in the [Coding style guide](doc/coding_style.md) +The Awa LWM2M coding style guidelines can be found in the [Coding style guide](doc/coding_style.md). + ### Signing your work. -Awa LWM2M requires contributors to accept the Developer Certificate of Origin (DCO) (from developercertificate.org) +Awa LWM2M requires contributors to accept the Developer Certificate of Origin (DCO) (from developercertificate.org). + +The sign-off is a single line at the end of your commit comment which certifies that you either wrote the supplied code or otherwise have the right to pass on the code as open source. + + +Certifying your contribution verifies that for your current submission the following statement is true: -The sign-off is a single line at the end of your commit comment which certifies that you wrote the supplied code or otherwise have the right to pass it on the code as open-source. -It's pretty simple: if you can certify the following: ``` Developer Certificate of Origin @@ -92,17 +102,21 @@ By making a contribution to this project, I certify that: this project or the open source license(s) involved. ``` -Then you just add the following line to every git commit message to indicate that you accept the DCO: -``` +To certify your submission just add the following line to *every* git commit message to indicate that you accept the above DCO: + + +```` Signed-off-by: User Name -``` -If you set-up your user.name and user.email via git config, you can sign your commit automatically with git commit like so: +```` -``` +If you set-up your user.name and user.email via git config, you can sign your commit automatically with git commit: + +```` git commit --signoff -``` +```` + ### Commit messages. From 216b07ad69062100b358520247ddde5971382a67 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 11:54:34 +1300 Subject: [PATCH 13/40] Minor rephrase of certification requirements --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cb78542..f7f1ce8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -60,7 +60,7 @@ Awa LWM2M requires contributors to accept the Developer Certificate of Origin (D The sign-off is a single line at the end of your commit comment which certifies that you either wrote the supplied code or otherwise have the right to pass on the code as open source. -Certifying your contribution verifies that for your current submission the following statement is true: +Certifying your contribution asserts that for your current submission the following statement is true: From 6419ec8db97c2349f55c77d7d5351028d0b22f9e Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 12:04:54 +1300 Subject: [PATCH 14/40] Addition to issue description requirements --- CONTRIBUTING.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f7f1ce8..93cfa9f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,7 @@ ---- -## Contributing Guide +## Contributing guide. ### Reporting issues and bugs. @@ -14,19 +14,19 @@ If you discover a bug, or find an issue or area that you feel needs improvement: * Click the "New Issue" button. -When making your report, be as clear and concise as possible. Ude the following list as a guide: +When making your report, be as clear and concise as possible. Use the following list as a guide: -* Describe the problem. +* Describe the issue, and why you believe it's a problem. -* Awa LWM2M Version or commit id. +* Include the Awa LWM2M version or commit id. -* Environment details (OS/distribution etc). +* Describe environment details (OS/distribution etc). -* Reproduciblity or issue frequency. +* How often the issue occurs. -* Steps taken to uncover or reproduce the issue (if any). +* Steps to take to uncover or reproduce the issue (if any). * Expected behaviour. From 2056021347ac7296cf7c7280dbf32f2c8f6541f7 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 12:07:57 +1300 Subject: [PATCH 15/40] minor edit --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 93cfa9f..679a206 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,15 +24,15 @@ When making your report, be as clear and concise as possible. Use the following * Describe environment details (OS/distribution etc). -* How often the issue occurs. +* State how often the issue has occurred. -* Steps to take to uncover or reproduce the issue (if any). +* Describe the steps to take to uncover or reproduce the issue (if any). * Expected behaviour. * Actual behaviour. -* Any addition Infomation, log output etc. +* Any additional infomation, log output etc. ### Branching model. From 50c24e5036d8ec7316f359aa6fb64f2eb9cbc043 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 12:16:31 +1300 Subject: [PATCH 16/40] Rearranged - no additions. --- CONTRIBUTING.md | 69 ++++++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 679a206..3d0428b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,9 +3,10 @@ ---- -## Contributing guide. +## Contributor guide. -### Reporting issues and bugs. + +## Reporting issues and bugs. If you discover a bug, or find an issue or area that you feel needs improvement: @@ -35,6 +36,12 @@ When making your report, be as clear and concise as possible. Use the following * Any additional infomation, log output etc. +---- + + +## Developer submissions. + + ### Branching model. All Awa LWM2M development occurs on the master branch. Developers should only submit patches against the master branch. @@ -53,6 +60,34 @@ Configure your user name to be used by git: The Awa LWM2M coding style guidelines can be found in the [Coding style guide](doc/coding_style.md). + +### Commit messages. + +For the commit message, the following rules apply: + + * The first line should be a brief summary of the patch. + * Leave a blank line after the summary. + * Provide a detailed description of the change. + * Leave a blank line after the description. + * If the patch relates to an issue, add a line with 'Ref: ISSUE_ID'. + * Add a Gerrit 'Change-id' line. + * Add a Git 'Signed-off-by' line using ````git commit -s```` or ````git commit --sign-off```` (see *Signing your work* below). + + Example: + + Adds a new example feature xyz + + This patch adds example feature xyz. This feature merely acts + as an example of how to commit something to the project. + For real features this would contain some text + describing in detail what the new feature actually does. + + Ref: AWA-2131 + Change-Id: Id564ab1230913abf88123dff193b1231b1 + Signed-off-by: User Name + + + ### Signing your work. Awa LWM2M requires contributors to accept the Developer Certificate of Origin (DCO) (from developercertificate.org). @@ -60,7 +95,7 @@ Awa LWM2M requires contributors to accept the Developer Certificate of Origin (D The sign-off is a single line at the end of your commit comment which certifies that you either wrote the supplied code or otherwise have the right to pass on the code as open source. -Certifying your contribution asserts that for your current submission the following statement is true: +Certifying your contribution asserts that *for the current submission* the following statement is true: @@ -117,32 +152,8 @@ If you set-up your user.name and user.email via git config, you can sign your co git commit --signoff ```` +---- -### Commit messages. - -For the commit message, the following rules apply: - - * The first line should be a brief summary of the patch. - * Leave a blank line after the summary. - * Provide a detailed description of the change. - * Leave a blank line after the description. - * If the patch relates to an issue, add a line with 'Ref: ISSUE_ID'. - * Add a Gerrit 'Change-id' line. - * Add a Git 'Signed-off-by' line (using `git commit -s` or `git commit --sign-off`). - - Example: - - Adds a new example feature xyz - - This patch adds example feature xyz. This feature merely acts - as an example of how to commit something to the project. - For real features this would contain some text - describing in detail what the new feature actually does. - - Ref: AWA-2131 - Change-Id: Id564ab1230913abf88123dff193b1231b1 - Signed-off-by: User Name - - +---- From b8cabad01b74a1b09a2f5de7f51c5f5ef80bab22 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 15:13:51 +1300 Subject: [PATCH 17/40] added image to userguide --- doc/LWM2M_object_referencing.png | Bin 0 -> 72372 bytes doc/userguide.md | 504 +------------------------------ 2 files changed, 15 insertions(+), 489 deletions(-) create mode 100644 doc/LWM2M_object_referencing.png diff --git a/doc/LWM2M_object_referencing.png b/doc/LWM2M_object_referencing.png new file mode 100644 index 0000000000000000000000000000000000000000..3ce76790d759e8d79ce760cf7a39c1f7aab97ace GIT binary patch literal 72372 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 z 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 rNBbqK0<5s%+17=fhM*+% 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 S>3oFzQIc1atCBGb`TqctC!rt! literal 0 HcmV?d00001 diff --git a/doc/userguide.md b/doc/userguide.md index efb95a0..d258019 100644 --- a/doc/userguide.md +++ b/doc/userguide.md @@ -33,499 +33,25 @@ A suite of tools is provided to exercise the main functionality of the API for b A bootstrap server daemon is also provided that implements the LWM2M bootstrapping protocol which instructs LWM2M clients which LWM2M server to connect to. Later sections describe the configuration of the Awa bootstrap server. ----- - -### The LWM2M client. - -The LWM2M Client runs as a daemon and provides the core LWM2M functionality for: - -* Bootstrapping -* Registration -* Device management and service enablement -* Information reporting - -The client provides two interfaces: - -* A CoAP interface to talk to the LWM2M server -* An IPC interface which provides a mechanism for applications to talk to the daemon. - - -![Awa LWM2M client interfaces](awa_client_interfaces.png) - - -The IPC interface allows the end user application to define new objects and to perform Get/Set/Delete/Subscribe operations on the client. -Currently the IPC interface is implemented as a simple UDP channel, with an associated UDP port. It is recommended that only a single user application connect to the daemon's IPC interface at any time. - - -### The Awa client daemon. - -Usage: ````awa_clientd [options] [--bootstrap [URI] | --factoryBootstrap [filename]] ```` - - -| options | description | -|-----|-----| -| --port, -p | port number for CoAP communications | -| --ipcPort, -i | port number for IPC communications | -| --endPointName, -e | client end point name | -| --bootstrap, -b | bootstrap server URI | -| --factoryBootstrap, -f | factory bootstrap information file | -| --logFile, -l | log filename | -| --daemonise, -d | run as daemon | -| --verbose, -v | enable verbose output | -| --help | show usage | - -Example: - -```` awa_clientd --port 6000 --endPointName client1 --bootstrap coap://0.0.0.0:2134 ```` - - -### Awa client daemon tools. - -should this be here? - ----- - -### The LWM2M server. - -The LWM2M server runs as a daemon which provides an interface to perform LWM2M operations on connected LWM2M clients. - -![Awa LWM2M server interfaces](Awa_LWM2M_server_interfaces.png) - -The IPC interface allows the end user application to define new objects, list registered clients and perform Read/Write/Delete/Observe operations for a given LWM2M client registered with the server. -Currently the IPC interface is implemented as a simple UDP channel, with an associated UDP port. It is recommended that only a single user application connect to the daemon's IPC interface at any time. - - -### The Awa server daemon. - -Usage: ````awa_serverd [options] ```` - -| options | description | -|-----|-----| -| --ip | IP address for server | -| --interface | Network interface for server | -| --addressFamily | Address family for network interface. 4 for IPv4, 6 for IPv6 | -| --port, -p | port number for CoAP communications | -| --ipcPort, -i | port number for IPC communications | -| --contentType, -m | Content Type ID (default 1542 - TLV) | -| --logFile | log filename | -| --daemonise, -d | run as daemon | -| --verbose, -v | enable verbose output | -| --help | show usage | - - -Example: ````awa_serverd --interface eth0 --addressFamily 4 --port 5683 ```` - -For examples of how to use the LWM2M server with the LWM2M client see the *LWM2M client usage* section below. - - -### The LWM2M Bootstrap server. - -The LWM2M Bootstrap server runs as a daemon which provides a mechanism to bootstrap LWM2M clients. - - -![](Awa_LWM2M_bootstrap_server-interfaces.png) - - -### The Awa Bootstrap server daemon. - -**Command line options.** - -A basic bootstrap server is supplied in the development suite which can be run on a local machine and used to re-direct the LWM2M client to any LWM2M server: - -Usage: ````awa_bootstrapd [options] ```` - -| options | description | -|-----|-----| -| --ip | IP address for bootstrap server | -| --interface | Network interface for bootstrap server | -| --addressFamily | Address family for network interface. 4 for IPv4, 6 for IPv6 | -| --port, -p | port number for CoAP communications | -| --config, -c | config file (server list) | -| --daemonize, -d | daemonize | -| --verbose, -v | verbose debug output | -| --logfile | logfile name | -| --help | show usage | - - -Example: ````awa_bootstrapd --port 15685 --config bootstrap.conf ```` - - -**The configuration file.** - -The configuration file must have the following format: -```` -ServerURI=coap://127.0.0.2:5683 -SecurityMode=0 -PublicKey=[PublicKey] -SecretKey=[SecretKey] -ServerID=1 -HoldOffTime=30 -ShortServerID=1 -Binding=U -LifeTime=30 -DefaultMinimumPeriod=1 -DefaultMaximumPeriod=-1 -DisableTimeout=86400 -NotificationStoringWhenDisabledOrOffline=true -```` - - * ServerURI specifies the address and port of the LWM2M server to which clients will be directed. - * SecurityMode is not yet supported. - * PublicKey is not supported. - * SecretKey is not supported. - * ServerID specifies the numerical ID of the LWM2M server used to associate security and server objects on the LWM2M client. - * HoldOffTime is not yet supported. - * ShortServerID specifies the numerical ID of the LWM2M server used to associate Security and Server objects on the LWM2M client. - * Binding specifies the supported LWM2M binding modes for this server. Only "U" (UDP, non-queuing) is currently supported. - * LifeTime specifies the minimum time (in seconds) that the server will wait after receiving a registration or update from the client before terminating that registration. - * DefaultMinimumPeriod specifies the default minimum period of observations. - * DefaultMaximumPeriod specifies the default maximum period of observations, -1 represents an indefinite period. - * DisableTimeout is not supported. - * NotificationStoringWhenDisabledOrOffline is not supported. - ----- - - -### Awa client, server and bootstrap example. - -### Daemon setup. - -Example on how to interconnect all the daemons locally... - - -### Awa client tools examples. - - -### Awa server tools examples. - - ----- ----- - -## Using the LWM2M client. - - -### Connecting the gateway client to the gateway LWM2M server. -```` -$ build/core/src/bootstrap/awa_bootstrapd --verbose --port 15685 -$ build/core/src/server/awa_serverd --verbose -$ build/core/src/client/awa_clientd --endPointName client1 --bootstrap coap://127.0.0.1:15685 -```` - -### The Awa_API. - -The Awa API provides a way for applications to communicate with the LWM2M client and server daemons via the IPC interface. -The client API header file can be found in "include/Awa/client.h". -The server API header file can be found in "include/Awa/server.h". -Both server and client APIs are implemented in the *libawa* library. Applications may be linked against the either the static library *libawa.a* or the shared library *libawa.so*. - -Useful examples can be found in the *api/example* folder. The tools directory contains a number of useful tools. These are built with the daemons, by default. - -## Awa client API tools. - -Several command-line tools are available for user interaction with the LWM2M daemon. These tools support simple operations, such as defining a custom object type, setting a resource value, retrieving a resource value, and waiting for a resource to change or be executed. They interact with the LWM2M daemon via the SDK and IPC channel, and are applications that interact with the daemon locally. - -Note that these are *not* LWM2M Protocol tools - they do not issue LWM2M operations. - -### Common options. - -Common options include: - -| options | description | -|-----|-----| -| -h, --help | Print help and exit | -| -V, --version | Print version and exit | -| -v, --verbose | Increase program verbosity (shows more run-time information) | -| -d, --debug | Increase program verbosity (shows a lot of run-time information) | -| -a, --ipcAddress=ADDRESS | Connect to client daemon at address (default=`127.0.0.1') | -| -p, --ipcPort=PORT | Connect to IPC port (default=`12345') | - -*--ipcAddress* is used to specify the IP address of the client daemon to connect to. -*--ipcPort* is used to specify the IPC port that the tool uses to communicate with the daemon. Both the daemon and the tool must use the same port. Changing the port allows users to run multiple instances of the client daemon on the same host. - -Most tools take one or more PATH parameters, specified in the format: - -| parameter | description | -|-----|-----| -| /O | specifies the object ID for operations on entire object types. | -| /O/I | specifies the object ID and object instance ID for operations on specific object instances. | -| /O/I/R | specifies the object ID, object instance ID, and resource ID for operations on specific resources. | -| /O/I/R/i | specifies the object ID, object instance ID, resource ID and resource instance ID for operations on specific resource instances. | - -For tools that write data, values can be specified with the format: ````PATH=VALUE```` - -### Creating a new object definition. - -An *object* is a collection of individual *resources* bundled together under a single identifier, along with some extra attributes that describe the nature of the object (listed below). Numerous standard objects are pre-defined within the LWM2M model but additional custom objects may also be defined as needed. Custom objects are created by registering the new object definition with the daemon. The *add-definition* tool is used to perform this operation. Note that an object definition does not result in an object instance. Creation of an object instance is a separate process. Resource manipulation is only possible on object instances. - -**NOTE: A custom object must be defined for both the client *and* server daemons. Use the *awa-server-add-definition* tool to define a custom object with the server.** - -Firstly the object itself is defined by providing an ID, descriptive name, mandatory or optional flag (to determine whether the device must provide at least one instance), and whether the object supports single or multiple instances. - -| object attribute | description | -|-----|-----| -| -o, --objectID=ID | Object ID | -| -j, --objectName=NAME | Object name | -| -m, --objectMandatory | Object is required or optional (default=off) | -| -y, --objectInstances=TYPE | Object supports single or multiple instances (possible values: *single* (default) or *multiple*) | - -Secondly, each resource in the object is specified by a sequence of resource options: - -| resource option | description | -|-----|-----| -| -r, --resourceID=ID | Resource ID | -| -n, --resourceName=NAME | Resource name | -| -t, --resourceType=TYPE | Resource type ( possible values: *opaque, integer, float, boolean, string, time, objectlink, none*) | -| -u, --resourceInstances=VALUE | Resource supports single or multiple instances (possible values: *single, multiple*) | -| -q, --resourceRequired=VALUE | Resource is required or optional (possible values: *optional, mandatory*) | -| -k, --resourceOperations=VALUE | Resource operation (possible values: *r, w, e, rw, rwe*) | - -**Note. For each *--resourceID* option, all other resource options must be specified.** - -Example. Define TestObject2 as ObjectID 1000, with a single mandatory instance, and three resources: -```` -./awa-client-define \ - --objectID=1000 --objectName=TestObject2 --objectMandatory --objectInstances=single \ - --resourceID=0 --resourceName=Resource0 --resourceType=string --resourceInstances=single --resourceRequired=mandatory --resourceOperations=rw \ - --resourceID=1 --resourceName=Resource1 --resourceType=integer --resourceInstances=single --resourceRequired=mandatory --resourceOperations=rw \ - --resourceID=2 --resourceName=Resource2 --resourceType=none --resourceInstances=single --resourceRequired=optiona --resourceOperations=e -```` - -### Discovering a device's object and resource definitions. - -The *awa-client-explore* tool is used to discover the objects and resources that have been defined on the LWM2M server. The tool will also list the objects and object-resources that are currently defined within the client daemon. - -Example: ````./awa-client-explore ```` - -### Setting resource values. - -The *awa-client-set* tool can be used to set the value of a resource. - -Mandatory resources always exist provided that the parent *object instance* exists, thus before the value of any resource can be set, the object instance must first be created. Before an *optional resource* can be set, this resource must first be created. - -Example. Consider the case where object /1000 has been defined but no instances have been created. The following can be used to create instance 0 of object 1000: ````./awa-client-set --create /1000/0 ```` - -Any mandatory resources associated with the object instance will also be instantiated with default values, but any resources defined as optional must be created explicitly before they can be set. +### The LWM2M object model. -For example, to create an instance of the optional resource 0 within instance 0 of object 1000: ````./awa-client-set --create /1000/0/0 ```` +![LWM2M object model](doc/LWM2M_object_referencing.png) -Because no value is specified for the new resource instance, it will be created and populated with its default value. +LWM2M is based on an object model such that: +* An object is defined to reresent a device or client application (the LWM2M client), or a LWM2M device management function. +* Each object is defined on both the client and the server. +* The client hosted object holds the current status of the device. The server hosted object holds the device's status on the server. +* One or more instances of an object may exist simultaneously but each will have a unique instance identifier. +* An object is composed of one or more resources, grouped under a single object identifier. +* Each resource is fully described and is uniquely addressable within the object. +* One or more instances of a resource may exist simultaneously within an object but each will have a unique instance identifier. -Once the resource has been created, its value can be set. +Object and resource identifiers are 16 bit integers. Object and resource *instance* identifiers are 8 bit integers. -For example, to set the value of resource 0 (which is of type string), within object instance 0 of object 1000, to the value *Happy*: +A resource instance is accessed via its parent object instance using a semantic approach: -````./awa-client-set /1000/0/0=Happy ```` +````{objectID}/{object instance}/{resource ID}/{resource instance}```` -**Note that it is not possible to set the value of a resource that is of type *None*.** +In the case where a single instance of an object and resource exists the address resolves to ````{objectID}/{ResourceID}```` -A specific resource instance of a multi-instance resource can be set with: ````./awa-client-set /1000/0/1/7=Seventh ```` - -Multiple set operations can be combined on the command line: - - ````./awa-client-set --create /1000/0 /1000/0/0=Happy /1000/0/1/7=Seventh ```` - -### Retrieving a resource value. - -The *awa-client-get* tool is used to retrieve the value of a client object resource and display it on the console. - -For example, to retrieve and display the value of resource 0, within instance 0 of object 1000: ````./awa-client-get /1000/0/0 ```` - -Multiple resources can be retrieved: ````./awa-client-get /1000/0/1 /1000/0/5 ```` - -Entire object instances can be retrieved: ````./awa-client-get /1000/0 ```` - -All object instances for an object ID can also be retrieved: ````./awa-client-get /1000 ```` - -If the resource specified is a multiple-instance resource, all instances will be retrieved. Individual instances can be displayed by specifying the resource instance index: ````./awa-client-get /1000/0/5/1 /1000/0/5/2 ```` - -The *--quiet/-q* option can be used to suppress the display of any extra information. - -## Subscribing to a change of resource value. - -In some cases it may be important for a script to block until the value of a resource changes, or for an LWM2M resource execute operation to complete. The *awa-client-subscribe* tool can be used to act as a listener. - -The *awa-client-subscribe* tool will display notifications whenever the value of the target resource or object instance changes, or when a target resource receives an execute operation. When a notification arrives, the details will be printed to the console. - -Note that *awa-client-subscribe* is *not* the same a LWM2M *Observe* operation. This tool is listening to the local resource hosted by the client daemon. - -For example, to listen for a change to resource 200 within instance 0 of object 1000: ````./awa-client-subscribe /1000/0/200 ```` - -To listen for a change to any resource within instance 0 of object 1000: ````./awa-client-subscribe /1000/0 ```` - -Listening for an LWM2M Execute operation is also possible, however the target object instance and resource must be fully specified. For example, to wait on resource 4, which is an executable resource of instance 0 of object 3: ````./awa-client-subscribe /3/0/4 ```` - -By default, *awa-client-subscribe* will wait indefinitely, displaying each notification as it arrives. With the time and count options, *awaclient-subscribe* can terminate after a number of notifications, or an elapsed period of time. - -| option | description | -|-----|-----| -| -t, --waitTime=SECONDS | Time to wait for notification (default=`0') | -| -c, --waitCount=NUMBER | Number of notifications to wait for (default=`0') | - - -For example, to wait for no longer than 60 seconds for a single notification: ````./awa-client-subscribe /3/0/4 --waitTime=60 --waitCount=1 ```` - -Multiple paths can be combined on the command line: ````./awa-client-subscribe /3/0/4 /3/0/5 /4 ```` - -### Deleting a resource. - -To delete an object or resource instance from the client, use the *awa-client-delete* tool. -For example, to delete all object instances of object type 1000: ````./awa-client-delete /1000 ```` - -To delete the object instance of object type 1000 with ID 0: ````./awa-client-delete /1000/0 ```` - -To delete the resource with ID 5 from instance 0 of object ID 1000: ````./awa-client-delete /1000/0/5 ```` - -Unlike the *awa-server-delete* tool, this tool can modify the client's data structures directly, so is not limited by LWM2M Delete rules. - -### Awa Server API tools. - -Server tools are used to communicate with the LWM2M Server daemon and typically issue one or more LWM2M operations to a connected client. - -Server tools often require a target client ID to be specified: - -| option | description | -|-----|-----| -| -c, --clientID=ID | ClientID is the client endpoint name used by the client when registering with the LWM2M server. | - - -### Listing registered clients. - - The *awa-server-list-clients* tool can be used to list all clients currently registered with the LWM2M server daemon: - -````./awa-server-list-clients ```` - -The *--clientID/-c* option is not required. Each client endpoint name is displayed, one per line. - -If *--verbose/-v* is specified, the output shows the number of registered clients, and their client endpoint names: - -For eaxmple: ````./awa-server-list-clients --verbose ```` - -Returns: -```` -1 imagination1 -2 chris -```` - -The option *--objects/-o* can be specified to retrieve and display the objects and object instances currently registered with the LWM2M server in the format ```````` or ````````. - -For example: ````./awa-server-list-clients --objects ```` -Returns -```` -1 imagination1 <2/0>,<4/0>,<7>,<3/0>,<5>,<6>,<0/1>,<1/1> -```` - -### Creating a new object definition on the server. - -The *awa-server-define* tool is used to define custom objects on the server. To use a custom object, the object definition must be registered with the server daemon. The *awa-server-define* tool has identical functionality to *awa-client-define*, described earlier. - -### Writing a value to a resource on a registered client. - -The *awa-server-write* tool is used to write the value of a resource on a registered client. - -For example, to set the value of resource 0 (of type string) on the client "imagination1", within instance 0 of object 1000, to the value *Happy*: - -````./awa-server-write --clientID=imagination1 /1000/0/0=Happy ```` - -Note that it is not possible to set the value of a resource that is of type *None*. - -A multi-instance resource can be set by specifying the resource instances: - -````./awa-server-write --clientID=imagination1 /1000/0/5/1=123 /1000/0/5/2=456```` - -To create a new instance of an object on a connected client, the *--create* option can be used. -When an instance is created, any default values provided in the object definition are used. - -For example, to create instance 1 of object 1000 on the client *imagination1*: - -````./awa-server-write --clientID=imagination1 --create /1000/1 ```` - -To create a new instance with the next available object instance ID: - -````./awa-server-write --clientID=imagination1 --create /1000 ```` - -The ID of the newly created object instance is displayed. - - **Note: Create functionality is not yet supported.** - -### Reading a resource value from a registered client. - -The *awa-server-read* tool is used to retrieve the value of a resource and display it on the console. For example, to display the value of resource 0, within instance 0 of object 1000: - -````./awa-server-read --clientID=imagination1 /1000/0/0 ```` - -Multiple resources and object instances can be read using: - -````./awa-server-read -c imagination1 /1000/0/2 /1000/0/3 /1000/1 /1001 ```` - -### Deleting an object instance from a registered client. - -The *awa-server-delete* tool is used to delete an instance of an object from a connected client. For example, to delete object 1000, instance 0 from the client "imagination1": - -````./awa-server-delete --clientID=imagination1 /1000/0 ```` - -**Note.** Due to LWM2M protocol restrictions it is not possible to delete individual resources, resource instances, or entire objects. - -### Observing a resource on a registered client. - -In some cases a script may be required to block until the value of a resource changes on a specific client. For this purpose, the *awa-server-observe* tool is provided to display notifications whenever the target resource or object instance changes. - -When a notification arrives, the details will be printed to the console, which is the functional equivalent of a LWM2M *Observe* operation. - -For example, to wait for a change to resource 200 within instance 0 of object 1000: - -````./awa-server-observe --clientID imagination1 /1000/0/200 ```` - -To wait for a change to any resource within instance 0 of object 1000: - -````./awa-server-observe --clientID imagination1 /1000/0 ```` - -By default, *awa-server-observe* will wait indefinitely, displaying each notification as it arrives, but by using the time and count options, *awa-server-observe* can terminate after a number of notifications, or an elapsed period of time. - -| option | description | -|-----|-----| -| -t, --waitTime=SECONDS | Time to wait for notification (default=`0') | -| -c, --waitCount=NUMBER | Number of notifications to wait for (default=`0') | - -For example, to wait for no longer than 60 seconds for a single notification: - -````./awa-server-observe --clientID imagination1 --waitTime=60 --waitCount=1 /1000/0/200 ```` - -Observe attributes that affect the way notifications are generated can be changed with the *awa-server-write-attributes* tool. - -### Executing a resource on a registered client. - -The *awa-server-execute* tool is used to initiate an *execute* operation on a resource that supports it. - -For example, to initiate execution of object 1000, instance 0, resource 4 on the client "imagination1": - -````./awa-server-execute --clientID imagination1 /1000/0/4 ```` - -Multiple operations can be initiated by applying multiple paths: - -````./awa-server-execute --clientID imagination1 /1000/0/4 /1000/0/5 ```` - -Opaque data can be supplied as an argument to the execute operation by piping into the process via the *--stdin* option: - -````./awa-server-execute --stdin --clientID imagination1 /1000/0/4 < mydata ```` - -**Note that data supplied will be piped to all of the stated execute targets.** - -Execute operations on an object, an object instance or a resource instance are not possible. - -### Write attribute values of a resource or object instance on a registered client. - -The *awa-server-write-attributes* tool is used to change the value of attributes associated with a client's resource or object instance. - -For example, to set the *pmin* value of object 1000, instance 0, resource 4 on the client "imagination1" to 5 seconds: - -````./awa-server-write_attributes --clientID imagination1 /1000/0/4\?pmin=5 ```` - -Multiple attribute values can be set with the same call. For example, to set the *pmin* attribute of object 1000, instance 0 on the client "imagination1" to 5 seconds, and *pmax* to 100 for the same object instance: - -````./awa-server-write_attributes --clientID imagination1 /1000/0\?pmin=5\&pmax=100 ```` - -Note that the *?* and *&* characters will need to be escaped for most shells. - ----- ----- +The semantic approach allows resources to be written to directly: ````1000/0/1/2='this value"```` From 9c6d719e05e43a4bbb7396e44dbf998df58bbc5d Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 15:15:22 +1300 Subject: [PATCH 18/40] image link fixed --- doc/userguide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/userguide.md b/doc/userguide.md index d258019..7c8f915 100644 --- a/doc/userguide.md +++ b/doc/userguide.md @@ -35,7 +35,7 @@ A bootstrap server daemon is also provided that implements the LWM2M bootstrappi ### The LWM2M object model. -![LWM2M object model](doc/LWM2M_object_referencing.png) +![LWM2M object model](LWM2M_object_referencing.png) LWM2M is based on an object model such that: * An object is defined to reresent a device or client application (the LWM2M client), or a LWM2M device management function. From d0bdfba8d645ebc523f21da0e9e363a89f4b1eeb Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 15:18:39 +1300 Subject: [PATCH 19/40] minor edit --- doc/userguide.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/userguide.md b/doc/userguide.md index 7c8f915..b78080f 100644 --- a/doc/userguide.md +++ b/doc/userguide.md @@ -35,8 +35,13 @@ A bootstrap server daemon is also provided that implements the LWM2M bootstrappi ### The LWM2M object model. +---- + ![LWM2M object model](LWM2M_object_referencing.png) +---- + + LWM2M is based on an object model such that: * An object is defined to reresent a device or client application (the LWM2M client), or a LWM2M device management function. * Each object is defined on both the client and the server. From f6e85d5a0c18b03e068352c6bf5af6973e9ec9ae Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 15:38:12 +1300 Subject: [PATCH 20/40] minor edit --- doc/userguide.md | 505 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 502 insertions(+), 3 deletions(-) diff --git a/doc/userguide.md b/doc/userguide.md index b78080f..887630a 100644 --- a/doc/userguide.md +++ b/doc/userguide.md @@ -43,12 +43,14 @@ A bootstrap server daemon is also provided that implements the LWM2M bootstrappi LWM2M is based on an object model such that: -* An object is defined to reresent a device or client application (the LWM2M client), or a LWM2M device management function. +* An object is defined to represent a device or client application, or a LWM2M device management function. * Each object is defined on both the client and the server. -* The client hosted object holds the current status of the device. The server hosted object holds the device's status on the server. +* The client hosted object holds the current status of the device and resources are mapped directly to device functions (e.g. temperature sensor or tilt switch). +* The server hosted object reflects a device's status on the server. The server has the tools to query resource values for any client directly. * One or more instances of an object may exist simultaneously but each will have a unique instance identifier. * An object is composed of one or more resources, grouped under a single object identifier. * Each resource is fully described and is uniquely addressable within the object. +* The OMA has pre-defined objects suitable for most cases, but custom objects may still be defined for local use. * One or more instances of a resource may exist simultaneously within an object but each will have a unique instance identifier. Object and resource identifiers are 16 bit integers. Object and resource *instance* identifiers are 8 bit integers. @@ -59,4 +61,501 @@ A resource instance is accessed via its parent object instance using a semantic In the case where a single instance of an object and resource exists the address resolves to ````{objectID}/{ResourceID}```` -The semantic approach allows resources to be written to directly: ````1000/0/1/2='this value"```` +Semantic addressing allows resources to be written to directly: ````1000/0/1/2='this value"```` + + +### The LWM2M client. + +The LWM2M Client runs as a daemon and provides the core LWM2M functionality for: + +* Bootstrapping +* Registration +* Device management and service enablement +* Information reporting + +The client provides two interfaces: + +* A CoAP interface to talk to the LWM2M server +* An IPC interface which provides a mechanism for applications to talk to the daemon. + + +![Awa LWM2M client interfaces](doc/awa_client_interfaces.png) + + +The IPC interface allows the end user application to define new objects and to perform Get/Set/Delete/Subscribe operations on the client. +Currently the IPC interface is implemented as a simple UDP channel, with an associated UDP port. It is recommended that only a single user application connect to the daemon's IPC interface at any time. + + +### The Awa client daemon. + +Usage: ````awa_clientd [options] [--bootstrap [URI] | --factoryBootstrap [filename]] ```` + + +| options | description | +|-----|-----| +| --port, -p | port number for CoAP communications | +| --ipcPort, -i | port number for IPC communications | +| --endPointName, -e | client end point name | +| --bootstrap, -b | bootstrap server URI | +| --factoryBootstrap, -f | factory bootstrap information file | +| --logFile, -l | log filename | +| --daemonise, -d | run as daemon | +| --verbose, -v | enable verbose output | +| --help | show usage | + +Example: + +```` awa_clientd --port 6000 --endPointName client1 --bootstrap coap://0.0.0.0:2134 ```` + + +### Awa client daemon tools. + +should this be here? + +---- + +### The LWM2M server. + +The LWM2M server runs as a daemon which provides an interface to perform LWM2M operations on connected LWM2M clients. + +![Awa LWM2M server interfaces](doc/Awa_LWM2M_server_interfaces.png) + +The IPC interface allows the end user application to define new objects, list registered clients and perform Read/Write/Delete/Observe operations for a given LWM2M client registered with the server. +Currently the IPC interface is implemented as a simple UDP channel, with an associated UDP port. It is recommended that only a single user application connect to the daemon's IPC interface at any time. + + +### The Awa server daemon. + +Usage: ````awa_serverd [options] ```` + +| options | description | +|-----|-----| +| --ip | IP address for server | +| --interface | Network interface for server | +| --addressFamily | Address family for network interface. 4 for IPv4, 6 for IPv6 | +| --port, -p | port number for CoAP communications | +| --ipcPort, -i | port number for IPC communications | +| --contentType, -m | Content Type ID (default 1542 - TLV) | +| --logFile | log filename | +| --daemonise, -d | run as daemon | +| --verbose, -v | enable verbose output | +| --help | show usage | + + +Example: ````awa_serverd --interface eth0 --addressFamily 4 --port 5683 ```` + +For examples of how to use the LWM2M server with the LWM2M client see the *LWM2M client usage* section below. + + +### The LWM2M Bootstrap server. + +The LWM2M Bootstrap server runs as a daemon which provides a mechanism to bootstrap LWM2M clients. + + +![](doc/Awa_LWM2M_bootstrap_server-interfaces.png) + + +### The Awa Bootstrap server daemon. + +**Command line options.** + +A basic bootstrap server is supplied in the development suite which can be run on a local machine and used to re-direct the LWM2M client to any LWM2M server: + +Usage: ````awa_bootstrapd [options] ```` + +| options | description | +|-----|-----| +| --ip | IP address for bootstrap server | +| --interface | Network interface for bootstrap server | +| --addressFamily | Address family for network interface. 4 for IPv4, 6 for IPv6 | +| --port, -p | port number for CoAP communications | +| --config, -c | config file (server list) | +| --daemonize, -d | daemonize | +| --verbose, -v | verbose debug output | +| --logfile | logfile name | +| --help | show usage | + + +Example: ````awa_bootstrapd --port 15685 --config bootstrap.conf ```` + + +**The configuration file.** + +The configuration file must have the following format: +```` +ServerURI=coap://127.0.0.2:5683 +SecurityMode=0 +PublicKey=[PublicKey] +SecretKey=[SecretKey] +ServerID=1 +HoldOffTime=30 +ShortServerID=1 +Binding=U +LifeTime=30 +DefaultMinimumPeriod=1 +DefaultMaximumPeriod=-1 +DisableTimeout=86400 +NotificationStoringWhenDisabledOrOffline=true +```` + + * ServerURI specifies the address and port of the LWM2M server to which clients will be directed. + * SecurityMode is not yet supported. + * PublicKey is not supported. + * SecretKey is not supported. + * ServerID specifies the numerical ID of the LWM2M server used to associate security and server objects on the LWM2M client. + * HoldOffTime is not yet supported. + * ShortServerID specifies the numerical ID of the LWM2M server used to associate Security and Server objects on the LWM2M client. + * Binding specifies the supported LWM2M binding modes for this server. Only "U" (UDP, non-queuing) is currently supported. + * LifeTime specifies the minimum time (in seconds) that the server will wait after receiving a registration or update from the client before terminating that registration. + * DefaultMinimumPeriod specifies the default minimum period of observations. + * DefaultMaximumPeriod specifies the default maximum period of observations, -1 represents an indefinite period. + * DisableTimeout is not supported. + * NotificationStoringWhenDisabledOrOffline is not supported. + +---- + + +### Awa client, server and bootstrap example. + +### Daemon setup. + +Example on how to interconnect all the daemons locally... + + +### Awa client tools examples. + + +### Awa server tools examples. + + +---- +---- + +## Using the LWM2M client. + + +### Connecting the gateway client to the gateway LWM2M server. +```` +$ build/core/src/bootstrap/awa_bootstrapd --verbose --port 15685 +$ build/core/src/server/awa_serverd --verbose +$ build/core/src/client/awa_clientd --endPointName client1 --bootstrap coap://127.0.0.1:15685 +```` + +### The Awa_API. + +The Awa API provides a way for applications to communicate with the LWM2M client and server daemons via the IPC interface. +The client API header file can be found in "include/Awa/client.h". +The server API header file can be found in "include/Awa/server.h". +Both server and client APIs are implemented in the *libawa* library. Applications may be linked against the either the static library *libawa.a* or the shared library *libawa.so*. + +Useful examples can be found in the *api/example* folder. The tools directory contains a number of useful tools. These are built with the daemons, by default. + +## Awa client API tools. + +Several command-line tools are available for user interaction with the LWM2M daemon. These tools support simple operations, such as defining a custom object type, setting a resource value, retrieving a resource value, and waiting for a resource to change or be executed. They interact with the LWM2M daemon via the SDK and IPC channel, and are applications that interact with the daemon locally. + +Note that these are *not* LWM2M Protocol tools - they do not issue LWM2M operations. + +### Common options. + +Common options include: + +| options | description | +|-----|-----| +| -h, --help | Print help and exit | +| -V, --version | Print version and exit | +| -v, --verbose | Increase program verbosity (shows more run-time information) | +| -d, --debug | Increase program verbosity (shows a lot of run-time information) | +| -a, --ipcAddress=ADDRESS | Connect to client daemon at address (default=`127.0.0.1') | +| -p, --ipcPort=PORT | Connect to IPC port (default=`12345') | + +*--ipcAddress* is used to specify the IP address of the client daemon to connect to. +*--ipcPort* is used to specify the IPC port that the tool uses to communicate with the daemon. Both the daemon and the tool must use the same port. Changing the port allows users to run multiple instances of the client daemon on the same host. + +Most tools take one or more PATH parameters, specified in the format: + +| parameter | description | +|-----|-----| +| /O | specifies the object ID for operations on entire object types. | +| /O/I | specifies the object ID and object instance ID for operations on specific object instances. | +| /O/I/R | specifies the object ID, object instance ID, and resource ID for operations on specific resources. | +| /O/I/R/i | specifies the object ID, object instance ID, resource ID and resource instance ID for operations on specific resource instances. | + +For tools that write data, values can be specified with the format: ````PATH=VALUE```` + +### Creating a new object definition. + +An *object* is a collection of individual *resources* bundled together under a single identifier, along with some extra attributes that describe the nature of the object (listed below). Numerous standard objects are pre-defined within the LWM2M model but additional custom objects may also be defined as needed. Custom objects are created by registering the new object definition with the daemon. The *add-definition* tool is used to perform this operation. Note that an object definition does not result in an object instance. Creation of an object instance is a separate process. Resource manipulation is only possible on object instances. + +**NOTE: A custom object must be defined for both the client *and* server daemons. Use the *awa-server-add-definition* tool to define a custom object with the server.** + +Firstly the object itself is defined by providing an ID, descriptive name, mandatory or optional flag (to determine whether the device must provide at least one instance), and whether the object supports single or multiple instances. + +| object attribute | description | +|-----|-----| +| -o, --objectID=ID | Object ID | +| -j, --objectName=NAME | Object name | +| -m, --objectMandatory | Object is required or optional (default=off) | +| -y, --objectInstances=TYPE | Object supports single or multiple instances (possible values: *single* (default) or *multiple*) | + +Secondly, each resource in the object is specified by a sequence of resource options: + +| resource option | description | +|-----|-----| +| -r, --resourceID=ID | Resource ID | +| -n, --resourceName=NAME | Resource name | +| -t, --resourceType=TYPE | Resource type ( possible values: *opaque, integer, float, boolean, string, time, objectlink, none*) | +| -u, --resourceInstances=VALUE | Resource supports single or multiple instances (possible values: *single, multiple*) | +| -q, --resourceRequired=VALUE | Resource is required or optional (possible values: *optional, mandatory*) | +| -k, --resourceOperations=VALUE | Resource operation (possible values: *r, w, e, rw, rwe*) | + +**Note. For each *--resourceID* option, all other resource options must be specified.** + +Example. Define TestObject2 as ObjectID 1000, with a single mandatory instance, and three resources: +```` +./awa-client-define \ + --objectID=1000 --objectName=TestObject2 --objectMandatory --objectInstances=single \ + --resourceID=0 --resourceName=Resource0 --resourceType=string --resourceInstances=single --resourceRequired=mandatory --resourceOperations=rw \ + --resourceID=1 --resourceName=Resource1 --resourceType=integer --resourceInstances=single --resourceRequired=mandatory --resourceOperations=rw \ + --resourceID=2 --resourceName=Resource2 --resourceType=none --resourceInstances=single --resourceRequired=optiona --resourceOperations=e +```` + +### Discovering a device's object and resource definitions. + +The *awa-client-explore* tool is used to discover the objects and resources that have been defined on the LWM2M server. The tool will also list the objects and object-resources that are currently defined within the client daemon. + +Example: ````./awa-client-explore ```` + +### Setting resource values. + +The *awa-client-set* tool can be used to set the value of a resource. + +Mandatory resources always exist provided that the parent *object instance* exists, thus before the value of any resource can be set, the object instance must first be created. Before an *optional resource* can be set, this resource must first be created. + +Example. Consider the case where object /1000 has been defined but no instances have been created. The following can be used to create instance 0 of object 1000: ````./awa-client-set --create /1000/0 ```` + +Any mandatory resources associated with the object instance will also be instantiated with default values, but any resources defined as optional must be created explicitly before they can be set. + +For example, to create an instance of the optional resource 0 within instance 0 of object 1000: ````./awa-client-set --create /1000/0/0 ```` + +Because no value is specified for the new resource instance, it will be created and populated with its default value. + +Once the resource has been created, its value can be set. + +For example, to set the value of resource 0 (which is of type string), within object instance 0 of object 1000, to the value *Happy*: + +````./awa-client-set /1000/0/0=Happy ```` + +**Note that it is not possible to set the value of a resource that is of type *None*.** + +A specific resource instance of a multi-instance resource can be set with: ````./awa-client-set /1000/0/1/7=Seventh ```` + +Multiple set operations can be combined on the command line: + + ````./awa-client-set --create /1000/0 /1000/0/0=Happy /1000/0/1/7=Seventh ```` + +### Retrieving a resource value. + +The *awa-client-get* tool is used to retrieve the value of a client object resource and display it on the console. + +For example, to retrieve and display the value of resource 0, within instance 0 of object 1000: ````./awa-client-get /1000/0/0 ```` + +Multiple resources can be retrieved: ````./awa-client-get /1000/0/1 /1000/0/5 ```` + +Entire object instances can be retrieved: ````./awa-client-get /1000/0 ```` + +All object instances for an object ID can also be retrieved: ````./awa-client-get /1000 ```` + +If the resource specified is a multiple-instance resource, all instances will be retrieved. Individual instances can be displayed by specifying the resource instance index: ````./awa-client-get /1000/0/5/1 /1000/0/5/2 ```` + +The *--quiet/-q* option can be used to suppress the display of any extra information. + +## Subscribing to a change of resource value. + +In some cases it may be important for a script to block until the value of a resource changes, or for an LWM2M resource execute operation to complete. The *awa-client-subscribe* tool can be used to act as a listener. + +The *awa-client-subscribe* tool will display notifications whenever the value of the target resource or object instance changes, or when a target resource receives an execute operation. When a notification arrives, the details will be printed to the console. + +Note that *awa-client-subscribe* is *not* the same a LWM2M *Observe* operation. This tool is listening to the local resource hosted by the client daemon. + +For example, to listen for a change to resource 200 within instance 0 of object 1000: ````./awa-client-subscribe /1000/0/200 ```` + +To listen for a change to any resource within instance 0 of object 1000: ````./awa-client-subscribe /1000/0 ```` + +Listening for an LWM2M Execute operation is also possible, however the target object instance and resource must be fully specified. For example, to wait on resource 4, which is an executable resource of instance 0 of object 3: ````./awa-client-subscribe /3/0/4 ```` + +By default, *awa-client-subscribe* will wait indefinitely, displaying each notification as it arrives. With the time and count options, *awaclient-subscribe* can terminate after a number of notifications, or an elapsed period of time. + +| option | description | +|-----|-----| +| -t, --waitTime=SECONDS | Time to wait for notification (default=`0') | +| -c, --waitCount=NUMBER | Number of notifications to wait for (default=`0') | + + +For example, to wait for no longer than 60 seconds for a single notification: ````./awa-client-subscribe /3/0/4 --waitTime=60 --waitCount=1 ```` + +Multiple paths can be combined on the command line: ````./awa-client-subscribe /3/0/4 /3/0/5 /4 ```` + +### Deleting a resource. + +To delete an object or resource instance from the client, use the *awa-client-delete* tool. +For example, to delete all object instances of object type 1000: ````./awa-client-delete /1000 ```` + +To delete the object instance of object type 1000 with ID 0: ````./awa-client-delete /1000/0 ```` + +To delete the resource with ID 5 from instance 0 of object ID 1000: ````./awa-client-delete /1000/0/5 ```` + +Unlike the *awa-server-delete* tool, this tool can modify the client's data structures directly, so is not limited by LWM2M Delete rules. + +### Awa Server API tools. + +Server tools are used to communicate with the LWM2M Server daemon and typically issue one or more LWM2M operations to a connected client. + +Server tools often require a target client ID to be specified: + +| option | description | +|-----|-----| +| -c, --clientID=ID | ClientID is the client endpoint name used by the client when registering with the LWM2M server. | + + +### Listing registered clients. + + The *awa-server-list-clients* tool can be used to list all clients currently registered with the LWM2M server daemon: + +````./awa-server-list-clients ```` + +The *--clientID/-c* option is not required. Each client endpoint name is displayed, one per line. + +If *--verbose/-v* is specified, the output shows the number of registered clients, and their client endpoint names: + +For eaxmple: ````./awa-server-list-clients --verbose ```` + +Returns: +```` +1 imagination1 +2 chris +```` + +The option *--objects/-o* can be specified to retrieve and display the objects and object instances currently registered with the LWM2M server in the format ```````` or ````````. + +For example: ````./awa-server-list-clients --objects ```` +Returns +```` +1 imagination1 <2/0>,<4/0>,<7>,<3/0>,<5>,<6>,<0/1>,<1/1> +```` + +### Creating a new object definition on the server. + +The *awa-server-define* tool is used to define custom objects on the server. To use a custom object, the object definition must be registered with the server daemon. The *awa-server-define* tool has identical functionality to *awa-client-define*, described earlier. + +### Writing a value to a resource on a registered client. + +The *awa-server-write* tool is used to write the value of a resource on a registered client. + +For example, to set the value of resource 0 (of type string) on the client "imagination1", within instance 0 of object 1000, to the value *Happy*: + +````./awa-server-write --clientID=imagination1 /1000/0/0=Happy ```` + +Note that it is not possible to set the value of a resource that is of type *None*. + +A multi-instance resource can be set by specifying the resource instances: + +````./awa-server-write --clientID=imagination1 /1000/0/5/1=123 /1000/0/5/2=456```` + +To create a new instance of an object on a connected client, the *--create* option can be used. +When an instance is created, any default values provided in the object definition are used. + +For example, to create instance 1 of object 1000 on the client *imagination1*: + +````./awa-server-write --clientID=imagination1 --create /1000/1 ```` + +To create a new instance with the next available object instance ID: + +````./awa-server-write --clientID=imagination1 --create /1000 ```` + +The ID of the newly created object instance is displayed. + + **Note: Create functionality is not yet supported.** + +### Reading a resource value from a registered client. + +The *awa-server-read* tool is used to retrieve the value of a resource and display it on the console. For example, to display the value of resource 0, within instance 0 of object 1000: + +````./awa-server-read --clientID=imagination1 /1000/0/0 ```` + +Multiple resources and object instances can be read using: + +````./awa-server-read -c imagination1 /1000/0/2 /1000/0/3 /1000/1 /1001 ```` + +### Deleting an object instance from a registered client. + +The *awa-server-delete* tool is used to delete an instance of an object from a connected client. For example, to delete object 1000, instance 0 from the client "imagination1": + +````./awa-server-delete --clientID=imagination1 /1000/0 ```` + +**Note.** Due to LWM2M protocol restrictions it is not possible to delete individual resources, resource instances, or entire objects. + +### Observing a resource on a registered client. + +In some cases a script may be required to block until the value of a resource changes on a specific client. For this purpose, the *awa-server-observe* tool is provided to display notifications whenever the target resource or object instance changes. + +When a notification arrives, the details will be printed to the console, which is the functional equivalent of a LWM2M *Observe* operation. + +For example, to wait for a change to resource 200 within instance 0 of object 1000: + +````./awa-server-observe --clientID imagination1 /1000/0/200 ```` + +To wait for a change to any resource within instance 0 of object 1000: + +````./awa-server-observe --clientID imagination1 /1000/0 ```` + +By default, *awa-server-observe* will wait indefinitely, displaying each notification as it arrives, but by using the time and count options, *awa-server-observe* can terminate after a number of notifications, or an elapsed period of time. + +| option | description | +|-----|-----| +| -t, --waitTime=SECONDS | Time to wait for notification (default=`0') | +| -c, --waitCount=NUMBER | Number of notifications to wait for (default=`0') | + +For example, to wait for no longer than 60 seconds for a single notification: + +````./awa-server-observe --clientID imagination1 --waitTime=60 --waitCount=1 /1000/0/200 ```` + +Observe attributes that affect the way notifications are generated can be changed with the *awa-server-write-attributes* tool. + +### Executing a resource on a registered client. + +The *awa-server-execute* tool is used to initiate an *execute* operation on a resource that supports it. + +For example, to initiate execution of object 1000, instance 0, resource 4 on the client "imagination1": + +````./awa-server-execute --clientID imagination1 /1000/0/4 ```` + +Multiple operations can be initiated by applying multiple paths: + +````./awa-server-execute --clientID imagination1 /1000/0/4 /1000/0/5 ```` + +Opaque data can be supplied as an argument to the execute operation by piping into the process via the *--stdin* option: + +````./awa-server-execute --stdin --clientID imagination1 /1000/0/4 < mydata ```` + +**Note that data supplied will be piped to all of the stated execute targets.** + +Execute operations on an object, an object instance or a resource instance are not possible. + +### Write attribute values of a resource or object instance on a registered client. + +The *awa-server-write-attributes* tool is used to change the value of attributes associated with a client's resource or object instance. + +For example, to set the *pmin* value of object 1000, instance 0, resource 4 on the client "imagination1" to 5 seconds: + +````./awa-server-write_attributes --clientID imagination1 /1000/0/4\?pmin=5 ```` + +Multiple attribute values can be set with the same call. For example, to set the *pmin* attribute of object 1000, instance 0 on the client "imagination1" to 5 seconds, and *pmax* to 100 for the same object instance: + +````./awa-server-write_attributes --clientID imagination1 /1000/0\?pmin=5\&pmax=100 ```` + +Note that the *?* and *&* characters will need to be escaped for most shells. + +---- +---- + From 452407afe9ce7f629f3da081c6ddd651a59108da Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 15:41:08 +1300 Subject: [PATCH 21/40] minor edit --- doc/userguide.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/userguide.md b/doc/userguide.md index 887630a..e3d1ba4 100644 --- a/doc/userguide.md +++ b/doc/userguide.md @@ -63,6 +63,8 @@ In the case where a single instance of an object and resource exists the address Semantic addressing allows resources to be written to directly: ````1000/0/1/2='this value"```` +---- + ### The LWM2M client. @@ -108,12 +110,9 @@ Example: ```` awa_clientd --port 6000 --endPointName client1 --bootstrap coap://0.0.0.0:2134 ```` -### Awa client daemon tools. - -should this be here? - ---- + ### The LWM2M server. The LWM2M server runs as a daemon which provides an interface to perform LWM2M operations on connected LWM2M clients. @@ -147,6 +146,9 @@ Example: ````awa_serverd --interface eth0 --addressFamily 4 --port 5683 ```` For examples of how to use the LWM2M server with the LWM2M client see the *LWM2M client usage* section below. +---- + + ### The LWM2M Bootstrap server. The LWM2M Bootstrap server runs as a daemon which provides a mechanism to bootstrap LWM2M clients. From 4655984b87134e58604186694061eec8656f59f2 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 16:25:02 +1300 Subject: [PATCH 22/40] Added images to README and userguide --- README.md | 5 +++++ doc/Awa_application_overview.png | Bin 0 -> 32636 bytes doc/userguide.md | 11 ++++++++--- 3 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 doc/Awa_application_overview.png diff --git a/README.md b/README.md index 05aa91b..dc90ce0 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,13 @@ The LWM2M protocol has been designed to be highly efficient in terms of data tra Awa LWM2M is an implementation of the OMA Lightweight M2M protocol that provides a secure and standards compliant device management solution to simplify the development of M2M applications by providing an intuitive API that enables customization without the need for an intimate knowledge of M2M protocols. + +![Awa application overview](doc/Awa_application_overview.png) + + Awa LWM2M is a development suite that provides a number of components and tools which can be combined in various ways depending on requirement. For example: + * When running on a larger Linux based device, Awa LWM2M can be deployed as a series of daemons that interact with your application via the libawa library and associated API. * For more constrained devices, your application code can be built against the constrained device centric API and compiled along with the Awa LWM2M client code into a binary to be deployed on your device. diff --git a/doc/Awa_application_overview.png b/doc/Awa_application_overview.png new file mode 100644 index 0000000000000000000000000000000000000000..b7d2cb2b5805eb706ee6d8c54f727b4a91200576 GIT binary patch literal 32636 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 Date: Fri, 26 Feb 2016 16:30:34 +1300 Subject: [PATCH 23/40] minor edits --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index dc90ce0..c5e6c00 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Further instructions can be found in the [Getting started guide](starters_guide. ### Documentation. -Awa LWM2M documentation is available both at a general level (project information, user and developer guides), and a techinical level (the API guide). All documentation is available in this repository. The *doc* directory contains information relating the project in general, and the *api/doc* directory contains the lower level documentation for the Awa API. +Awa LWM2M documentation is available both at a general level (project information, user and developer guides), and a techinical level (the API guide). All documentation is available in this repository. The *doc* directory contains information relating to the project in general, and the *api/doc* directory contains the lower level documentation for the Awa API. #### General documentation. @@ -67,7 +67,7 @@ The Awa API documentation is available as a Doxygen presentation which is genera The output can be found in the api/doc/html directory and viewed by opening index.html with your web browser. -For convenience you can also find the latest version of this documentation [here]() +For convenience you can also find the latest version of this documentation [here](). ---- @@ -75,7 +75,7 @@ For convenience you can also find the latest version of this documentation [here We welcome all contributions to this project and we give credit where it's due. Anything from enhancing functionality, to improving documentation and bug reporting - it's all good. -Find out more in the [Contributing guide](CONTRIBUTING.md). +Find out more in the [contributing guide](CONTRIBUTING.md). ### Credits. From c7e54d2b364a62348312a1471a2deba9b285eace Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 16:49:48 +1300 Subject: [PATCH 24/40] Changed link descriptions --- CONTRIBUTING.md | 4 ++++ README.md | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3d0428b..542d5ef 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -75,6 +75,8 @@ For the commit message, the following rules apply: Example: +```` + Adds a new example feature xyz This patch adds example feature xyz. This feature merely acts @@ -86,6 +88,8 @@ For the commit message, the following rules apply: Change-Id: Id564ab1230913abf88123dff193b1231b1 Signed-off-by: User Name +```` + ### Signing your work. diff --git a/README.md b/README.md index c5e6c00..2a74fed 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ For convenience you can also find the latest version of this documentation [here We welcome all contributions to this project and we give credit where it's due. Anything from enhancing functionality, to improving documentation and bug reporting - it's all good. -Find out more in the [contributing guide](CONTRIBUTING.md). +Find out more in the [contributor guide](CONTRIBUTING.md). ### Credits. From 759812f67060bc1b16ef055ac05123d31bb38f5e Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 16:52:15 +1300 Subject: [PATCH 25/40] minor edit --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 542d5ef..b59e8af 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -94,9 +94,9 @@ For the commit message, the following rules apply: ### Signing your work. -Awa LWM2M requires contributors to accept the Developer Certificate of Origin (DCO) (from developercertificate.org). +Awa LWM2M requires contributors to accept the Developer Certificate of Origin (DCO) from developercertificate.org. -The sign-off is a single line at the end of your commit comment which certifies that you either wrote the supplied code or otherwise have the right to pass on the code as open source. +The sign-off is a single line at the end of your commit comment to certify that you either wrote the supplied code or otherwise have the right to pass on the code as open source. Certifying your contribution asserts that *for the current submission* the following statement is true: From 8cafb073bae9cfd0e4c3a5df7f35c0d0c96ee72f Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 16:55:22 +1300 Subject: [PATCH 26/40] minor edit --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b59e8af..f9f8079 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -57,7 +57,7 @@ Configure your user name to be used by git: ### Coding style. -The Awa LWM2M coding style guidelines can be found in the [Coding style guide](doc/coding_style.md). +The Awa LWM2M coding style guidelines can be found in the [coding style guide](doc/coding_style.md). From c6124a5945f393383223d03d73f3080f5f949ced Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 17:01:12 +1300 Subject: [PATCH 27/40] minor edits --- README.md | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 2a74fed..754dbd6 100644 --- a/README.md +++ b/README.md @@ -33,13 +33,11 @@ The easiest way to get started with Awa LWM2M is on a Linux PC. The following i Firstly, to obtain a copy of the Awa LWM2M source code: - * Sign up for a Github account + * Sign up for a Github account + * Install Git: ```` sudo apt-get install git ```` - * Install Git: ```` sudo apt-get install git ```` - - - * Clone the repository: ```` git clone https://github.com/FlowM2M/AwaLWM2M.git ```` + * Clone the repository: ```` git clone https://github.com/FlowM2M/AwaLWM2M.git ```` Further instructions can be found in the [Getting started guide](starters_guide.md). @@ -52,10 +50,10 @@ Awa LWM2M documentation is available both at a general level (project informatio #### General documentation. -* For build instructions see the [Getting started guide](doc/starters_guide.md) -* Examples of how to use the tools can be found in the [User guide](doc/userguide.md) -* For developers, an overview of the system can be found in the [Developer guide](doc/developer_guide.md) -* Information regarding the testing framework, can be found in the [Testing](doc/testing.md) guide. +* For build instructions see the [Getting started guide](doc/starters_guide.md). +* Examples of how to use the tools can be found in the [User guide](doc/userguide.md). +* For developers, an overview of the system can be found in the [Developer guide](doc/developer_guide.md). +* Information regarding the testing framework, can be found in the [Testing](doc/testing.md) guide. #### API guide. @@ -73,7 +71,7 @@ For convenience you can also find the latest version of this documentation [here ### Contributing. -We welcome all contributions to this project and we give credit where it's due. Anything from enhancing functionality, to improving documentation and bug reporting - it's all good. +We welcome all contributions to this project and we give credit where it's due. Anything from enhancing functionality to improving documentation and bug reporting - it's all good. Find out more in the [contributor guide](CONTRIBUTING.md). @@ -91,9 +89,9 @@ We would also like to acknowledge and thank the authors of the following project ### License information. -* All code and documentation developed by Imagination Technologies Limited is licensed under the [BSD 3-clause license](LICENSE) -* LibCoAP by Olaf Bergmann is licensed under the GNU General Public License (GPL), Version 2 or higher, OR the simplified BSD license -* Jsmn by Serge A. Zaitsev is licensed under the MIT license +* All code and documentation developed by Imagination Technologies Limited is licensed under the [BSD 3-clause license](LICENSE). +* LibCoAP by Olaf Bergmann is licensed under the GNU General Public License (GPL), Version 2 or higher, OR the simplified BSD license. +* Jsmn by Serge A. Zaitsev is licensed under the MIT license. ---- From f92799342b52ba0cf36231260bf27928be8e6987 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 17:05:38 +1300 Subject: [PATCH 28/40] Added to ToC --- doc/userguide.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/userguide.md b/doc/userguide.md index 22595b6..36efc08 100644 --- a/doc/userguide.md +++ b/doc/userguide.md @@ -16,7 +16,8 @@ Developers who aim to contribute to the Awa LightweightM2M project are referred ### Contents. -* [Introduction.](userguide.md#introduction) +* [Introduction.](userguide.md#introduction) +* [The LWM2M object model.](userguide.md#the-lwm2m-object-model) * [The LWM2M client.](userguide.md#the-lwm2m-client) * [The Awa client daemon](userguide.md#the-awa-client-daemon) * [The LWM2M server.](userguide.md#the-lwm2m-server) From 062b93d64ebccdaf9109a9f5f0a3c136c4fd21d8 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Fri, 26 Feb 2016 17:12:45 +1300 Subject: [PATCH 29/40] Minor edit --- doc/userguide.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/doc/userguide.md b/doc/userguide.md index 36efc08..c4b87c0 100644 --- a/doc/userguide.md +++ b/doc/userguide.md @@ -206,19 +206,19 @@ DisableTimeout=86400 NotificationStoringWhenDisabledOrOffline=true ```` - * ServerURI specifies the address and port of the LWM2M server to which clients will be directed. - * SecurityMode is not yet supported. - * PublicKey is not supported. - * SecretKey is not supported. - * ServerID specifies the numerical ID of the LWM2M server used to associate security and server objects on the LWM2M client. - * HoldOffTime is not yet supported. - * ShortServerID specifies the numerical ID of the LWM2M server used to associate Security and Server objects on the LWM2M client. + * *ServerURI* specifies the address and port of the LWM2M server to which clients will be directed. + * *SecurityMode* is not yet supported. + * *PublicKey* is not supported. + * *SecretKey* is not supported. + * *ServerID* specifies the numerical ID of the LWM2M server used to associate security and server objects on the LWM2M client. + * *HoldOffTime* is not yet supported. + * *ShortServerID* specifies the numerical ID of the LWM2M server used to associate Security and Server objects on the LWM2M client. * Binding specifies the supported LWM2M binding modes for this server. Only "U" (UDP, non-queuing) is currently supported. - * LifeTime specifies the minimum time (in seconds) that the server will wait after receiving a registration or update from the client before terminating that registration. - * DefaultMinimumPeriod specifies the default minimum period of observations. - * DefaultMaximumPeriod specifies the default maximum period of observations, -1 represents an indefinite period. - * DisableTimeout is not supported. - * NotificationStoringWhenDisabledOrOffline is not supported. + * *LifeTime* specifies the minimum time (in seconds) that the server will wait after receiving a registration or update from the client before terminating that registration. + * *DefaultMinimumPeriod* specifies the default minimum period of observations. + * *DefaultMaximumPeriod* specifies the default maximum period of observations, -1 represents an indefinite period. + * *DisableTimeout* is not supported. + * *NotificationStoringWhenDisabledOrOffline* is not supported. ---- From c31be7b3c3a2aa9b7e4eb7cc7bcd5183324eee60 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Mon, 29 Feb 2016 10:17:57 +1300 Subject: [PATCH 30/40] Unused section deleted - ToC updated + minor edits. --- doc/userguide.md | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/doc/userguide.md b/doc/userguide.md index c4b87c0..8723104 100644 --- a/doc/userguide.md +++ b/doc/userguide.md @@ -1,4 +1,5 @@ + ![](img.png) ---- @@ -20,8 +21,11 @@ Developers who aim to contribute to the Awa LightweightM2M project are referred * [The LWM2M object model.](userguide.md#the-lwm2m-object-model) * [The LWM2M client.](userguide.md#the-lwm2m-client) * [The Awa client daemon](userguide.md#the-awa-client-daemon) + * [Using the LWM2M client.](userguide.md#using-the-LWM2M-client) + * [Awa client API tools.](userguide.md#awa-client-api-tools) * [The LWM2M server.](userguide.md#the-lwm2m-server) - * [The Awa server daemon](userguide.md#the-awa-server-daemon) + * [The Awa server daemon](userguide.md#the-awa-server-daemon) + * [Awa Server API tools.](userguide.md#awa-server-api-tools) * [The LWM2M Bootstrap server.](userguide.md#the-lwm2m-bootstrap-server) * [The Awa bootstrap server daemon](userguide.md#the-awa-bootstrap-server-daemon) @@ -223,21 +227,6 @@ NotificationStoringWhenDisabledOrOffline=true ---- -### Awa client, server and bootstrap example. - -### Daemon setup. - -Example on how to interconnect all the daemons locally... - - -### Awa client tools examples. - - -### Awa server tools examples. - - ----- ----- ## Using the LWM2M client. @@ -378,7 +367,7 @@ If the resource specified is a multiple-instance resource, all instances will be The *--quiet/-q* option can be used to suppress the display of any extra information. -## Subscribing to a change of resource value. +### Subscribing to a change of resource value. In some cases it may be important for a script to block until the value of a resource changes, or for an LWM2M resource execute operation to complete. The *awa-client-subscribe* tool can be used to act as a listener. @@ -392,7 +381,7 @@ To listen for a change to any resource within instance 0 of object 1000: ````./a Listening for an LWM2M Execute operation is also possible, however the target object instance and resource must be fully specified. For example, to wait on resource 4, which is an executable resource of instance 0 of object 3: ````./awa-client-subscribe /3/0/4 ```` -By default, *awa-client-subscribe* will wait indefinitely, displaying each notification as it arrives. With the time and count options, *awaclient-subscribe* can terminate after a number of notifications, or an elapsed period of time. +By default, *awa-client-subscribe* will wait indefinitely, displaying each notification as it arrives. With the time and count options, *awa_client-subscribe* can terminate after a number of notifications, or an elapsed period of time. | option | description | |-----|-----| @@ -415,7 +404,7 @@ To delete the resource with ID 5 from instance 0 of object ID 1000: ````./awa-cl Unlike the *awa-server-delete* tool, this tool can modify the client's data structures directly, so is not limited by LWM2M Delete rules. -### Awa Server API tools. +## Awa Server API tools. Server tools are used to communicate with the LWM2M Server daemon and typically issue one or more LWM2M operations to a connected client. @@ -546,7 +535,7 @@ Opaque data can be supplied as an argument to the execute operation by piping in ````./awa-server-execute --stdin --clientID imagination1 /1000/0/4 < mydata ```` -**Note that data supplied will be piped to all of the stated execute targets.** +**Note that the data supplied will be piped to all of the stated execute targets.** Execute operations on an object, an object instance or a resource instance are not possible. @@ -566,4 +555,3 @@ Note that the *?* and *&* characters will need to be escaped for most shells. ---- ---- - From 499aacec6bc74a2d61ce9498682d6bda253df8ad Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Mon, 29 Feb 2016 10:54:24 +1300 Subject: [PATCH 31/40] ToC updated to bookmark client and server tools --- doc/userguide.md | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/doc/userguide.md b/doc/userguide.md index 8723104..3507f89 100644 --- a/doc/userguide.md +++ b/doc/userguide.md @@ -20,16 +20,30 @@ Developers who aim to contribute to the Awa LightweightM2M project are referred * [Introduction.](userguide.md#introduction) * [The LWM2M object model.](userguide.md#the-lwm2m-object-model) * [The LWM2M client.](userguide.md#the-lwm2m-client) - * [The Awa client daemon](userguide.md#the-awa-client-daemon) + * [The Awa client daemon.](userguide.md#the-awa-client-daemon) * [Using the LWM2M client.](userguide.md#using-the-LWM2M-client) - * [Awa client API tools.](userguide.md#awa-client-api-tools) + * [The Awa_API.](userguide.md#the-awa-api) + * [API options.](userguide.md#common-options) + * [Creating a new object definition.](userguide.md#creating-a-new-object-definition) + * [Discovering a device's object and resource definitions.](userguide.md#discovering-a-device's-object-and-resource-definitions) + * [Setting resource values.](userguide.md#setting-resource-values) + * [Retrieving a resource value.](userguide.md#retrieving-a-resource-value) + * [Subscribing to a change of resource value.](userguide.md#subscribing-to-a-change-of-resource-value) + * [Deleting a resource.](userguide.md#deleting-a-resource) * [The LWM2M server.](userguide.md#the-lwm2m-server) - * [The Awa server daemon](userguide.md#the-awa-server-daemon) - * [Awa Server API tools.](userguide.md#awa-server-api-tools) + * [The Awa server daemon.](userguide.md#the-awa-server-daemon) + * [Awa server API tools.](userguide.md#awa-server-api-tools) + * [Listing registered clients.](userguide.md#listing-registered-clients) + * [Creating a server object definition.](userguide.md#creating-a-server-object-definition) + * [Writing a value to a resource on a registered client.](userguide.md#writing-a-value-to-a-resource-on-a-registered-client) + * [Reading a resource value from a registered client.](userguide.md#reading-a-resource-value-from-a-registered-client) + * [Deleting an object instance from a registered client.](userguide.md#deleting-an-object-instance-from-a-registered-client) + * [Observing a resource on a registered client.](userguide.md#observing-a-resource-on-a-registered-client) + * [Executing a resource on a registered client.](userguide.md#executing-a-resource-on-a-registered-client) + * [Write attribute values of a resource or object instance on a registered client.](userguide.md#write-attribute-values-of-a-resource-or-object-instance-on-a-registered-client) * [The LWM2M Bootstrap server.](userguide.md#the-lwm2m-bootstrap-server) * [The Awa bootstrap server daemon](userguide.md#the-awa-bootstrap-server-daemon) - ---- ### Introduction. @@ -441,7 +455,7 @@ Returns 1 imagination1 <2/0>,<4/0>,<7>,<3/0>,<5>,<6>,<0/1>,<1/1> ```` -### Creating a new object definition on the server. +### Creating a server object definition. The *awa-server-define* tool is used to define custom objects on the server. To use a custom object, the object definition must be registered with the server daemon. The *awa-server-define* tool has identical functionality to *awa-client-define*, described earlier. @@ -555,3 +569,4 @@ Note that the *?* and *&* characters will need to be escaped for most shells. ---- ---- + From 5ae5aae661b088ca21326f99ad7d76fe77ab68b7 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Mon, 29 Feb 2016 15:28:25 +1300 Subject: [PATCH 32/40] Added client API structure image for developer_guide.md. Minor edits on userguide.md and coding_style.md --- doc/Awa_client_API_structure.png | Bin 0 -> 15877 bytes doc/coding_style.md | 2 +- doc/developer_guide.md | 79 ++++++++++++------------------- doc/userguide.md | 4 +- 4 files changed, 32 insertions(+), 53 deletions(-) create mode 100644 doc/Awa_client_API_structure.png diff --git a/doc/Awa_client_API_structure.png b/doc/Awa_client_API_structure.png new file mode 100644 index 0000000000000000000000000000000000000000..23cc99560d921e8893d3bc41cc31e3179ba31e5c GIT binary patch literal 15877 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 literal 0 HcmV?d00001 diff --git a/doc/coding_style.md b/doc/coding_style.md index c6ee04c..374f0df 100644 --- a/doc/coding_style.md +++ b/doc/coding_style.md @@ -112,7 +112,7 @@ void MyFunction(void) } ```` -Similarly multi-line comments within a function should be formatted like this: +Similarly, multi-line comments within a function should be formatted like this: ```` void AwaTask(void *parameters) { diff --git a/doc/developer_guide.md b/doc/developer_guide.md index 9f0d9b1..d105001 100644 --- a/doc/developer_guide.md +++ b/doc/developer_guide.md @@ -7,34 +7,38 @@ ## Developer guide. +This guide is intended for developers who aim to contribute to the Awa LightweightM2M project. Developers who intend only to use the Awa LightweightM2M tools in their own M2M applications are referred to the [Awa LightweightM2M user guide](userguide.md). - -## Introduction. +### Introduction. OMA LightweightM2M (LWM2M) facilitates standardised communication between devices and management applications. LWM2M is built on a request/response protocol called Constrained Application Protocol (CoAP), which is similar to HTTP. A CoAP server hosts a number of resources that can be read from and written to by a CoAP client. LWM2M makes use of CoAP resources to group information into instances of standard and registry-defined objects which are defined to provide common device management functions such as location, software upgrades, and network configuration. As LWM2M operations are carried via CoAP requests, each request specifies an **endpoint** that corresponds to a particular resource. -LWM2M also provides a "bootstrap" mechanism, which helps a client to locate and connect to a management server in a secure manner. A trusted Bootstrap server may be configured with appropriate security credentials for one or more management servers. Clients connecting to the Bootstrap server are then provided with these credentials to enable registration with the relevant management server. +LWM2M also provides a *bootstrap* mechanism, which helps a client to locate and connect to a management server in a secure manner. A trusted bootstrap server may be configured with appropriate security credentials for one or more management servers. Clients connecting to the bootstrap server are then provided with these credentials to enable registration with the relevant management server. -LWM2M makes use of an *Object/Object Instance/Resource* (OIR) model to represent information. Objects are constructed from individual resource definitions, and each instance of an object is called an *Object Instance*. Refer to section 6.1 of the LWM2M technical specification for details http://technical.openmobilealliance.org/Technical/technical-information/release-program/current-releases/oma-lightweightm2m-v1-0 +LWM2M makes use of an *Object/Object Instance/Resource* (OIR) model to represent information. Objects are constructed from individual resource definitions, and each instance of an object is called an *Object Instance*. + +![OIR model](LWM2M_object_referencing.png) + +Refer to section 6.1 of the LWM2M technical specification for details http://technical.openmobilealliance.org/Technical/technical-information/release-program/current-releases/oma-lightweightm2m-v1-0 Awa LightWeightM2M is an implementation of OMA LWM2M written in C. It incorporates both server and client functionality and provides APIs for both. Typically, the client or server runs as a standalone Linux process (a "daemon") and an application uses the API library to access and modify resources across an inter-process communication (IPC) interface. This decoupling of the API from the main functionality allows other languages to make use of the daemons by implementing the IPC protocol. **ADD DIAGRAM** -## License. -Awa LightWeightM2M source code is made available by Imagination Technologies Limited under the standard 3-clause BSD license. Please see [LICENSE](../LICENSE) for details. +### License. +Awa LightWeightM2M source code is made available by Imagination Technologies Limited under the standard 3-clause BSD license described [here.](https://www.tldrlegal.com/l/bsd3) -## Contributing to Awa LightWeightM2M. +### Contributing to Awa LightWeightM2M. Contributions to the Awa project are welcome and there are many ways to help, by submitting bug reports for example, or making feature requests, code changes or documentation edits. -To ensure that the codebase remains easy to understand, maintain and improve, all contributions should adhere to the [Coding Style guidelines](doc/coding_style.md). -A comprehensive collection of unit tests is being developed and maintained to ensure that new contributions do not break existing functionality. All code submissions should be accompanied by one or more relevant unit tests, implemented within the existing unit test framework as described in the *Testing* section below. +To ensure that the codebase remains easy to understand, maintain and improve, all contributions should adhere to the [coding style guide](doc/coding_style.md). +A comprehensive collection of unit tests is being developed and maintained to ensure that new contributions do not break existing functionality. All code submissions should be accompanied by one or more relevant unit tests, implemented within the existing unit test framework as described in the [*Testing*](developer_guide.md#testing) section below. For further details on contributing go [here](../CONTRIBUTING.md). -## Design overview. -This section provides information about the structure of the codebase, and how the components interact. +### Design overview. +This section provides information about the structure of the codebase and how the components interact. The codebase is divided into the following parts: @@ -43,7 +47,7 @@ The codebase is divided into the following parts: * Bootstrap server * API -The Client, Server and Bootstrap server are implemented as Linux processes. Typically these run as *daemons*, detached from a parent console, which may be configured to automatically run when the host starts up. For example, a Linux gateway may automatically start the Server so that constrained devices are able to register as soon as the gateway becomes available. +The Client, Server and Bootstrap server are implemented as Linux processes. Typically these run as *daemons*, detached from a parent console, which may be configured to automatically run when the host starts up. For example, a Linux gateway may automatically start the server so that constrained devices are able to register as soon as the gateway becomes available. The API is provided as a linkable library, to be incorporated into a user program. The API has three parts: @@ -57,34 +61,11 @@ The Static client API is designed for cases where the configuration will not cha ### The client API. -The client API consists of the *client core*, which coordinates the IPC layer (for communication with the Client API), static API, serialiser/deserialiser (*serdes*), CoAP, definition registry, data storage (*object tree*) and observer registry. -```` - CoAP static API IPC -----------------> API - | | | - libcoap | | - |---coap abstraction | xml handlers, xml serdes - | | | - |---lwm2m client core---| - | - |---- serdes - | |---- tlv - | |---- plain text - | |---- opaque - | |---- json - | - |---- endpoints - |---- object tree - |---- definition registry - | |---- security object - | |---- server object - | |---- object store - | - |---- observers - |---- attributes -```` - - -**The client core.** +The client API consists of the *client core*, which coordinates the IPC layer (for communication with the client API), the static API, serialiser/deserialiser (*serdes*), CoAP, definition registry, data storage (*object tree*) and observer registry. + +![Awa client API structure](Awa_client_API_structure.png) + +#### The client core. The core is the layer that pulls all of the components together. It defines a number of functions called to handle requests from the CoAP layer, static API and the IPC interface. @@ -98,22 +79,22 @@ Additionally, an access control check is made to ensure that the requested opera Most resource read/write handlers are handled by the object store which acts as a generic storage mechanism. The standard server and security objects each have their own specialised handlers. -**The definition registry.** +#### The definition registry. The definition registry stores definitions for all objects and resources within the system. -There are two kinds of definitions: -* Resource definitions, which define a single resource that acts as a container for a LWM2M data type. -* Object definitions, which may contain one or more resource definitions, hold information such as whether multiple instances of the object can be created, or whether an object instance is *mandatory* or *optional*, and contain various function pointers which map its operations (Write/Read etc) onto the appropriate handlers. +There are two types of definition: +* **The resource definition**, which defines a single resource that acts as a container for a LWM2M data type. +* **The object definition**, which may contain one or more resource definitions, holds information such as whether multiple instances of the object can be created, or whether an object instance is *mandatory* or *optional*, and may contain various function pointers which map its operations (Write/Read etc) onto the appropriate handlers. -*Note that the resources themselves do not exist until the object is instantiated.* +*Note that defining a resource does not instantiate it. A resource does not exist until its parent object is instantiated.* -### The CoAP abstraction layer. +#### The CoAP abstraction layer. The CoAP abstraction layer hides the specifics of a CoAP library's interface and provides a common interface that can be used by the core. -### Serdes. +#### Serdes. There is a serialiser and deserialiser (serdes) for each of the data formats supported by the LWM2M protocol and implemented by Awa LightweightM2M. The supported data formats are: * Plain Text @@ -178,7 +159,7 @@ TODO ## Testing. - Awa LWM2M was developed alongside a comprehensive test suite, implemented within the Google Test framework. Tests are written in C++ and compile as part of one of several "test runner" applications: +Awa LWM2M was developed alongside a comprehensive test suite, implemented within the Google Test framework. Tests are written in C++ and compile as part of one of several "test runner" applications: * test_core_runner executes tests related to Client and Server daemon components. * test_api_runner executes tests related to Client and Server API components, including top-level tests involving multiple daemons. @@ -187,5 +168,3 @@ TODO - - diff --git a/doc/userguide.md b/doc/userguide.md index 3507f89..f55d346 100644 --- a/doc/userguide.md +++ b/doc/userguide.md @@ -22,7 +22,7 @@ Developers who aim to contribute to the Awa LightweightM2M project are referred * [The LWM2M client.](userguide.md#the-lwm2m-client) * [The Awa client daemon.](userguide.md#the-awa-client-daemon) * [Using the LWM2M client.](userguide.md#using-the-LWM2M-client) - * [The Awa_API.](userguide.md#the-awa-api) + * [The Awa API.](userguide.md#the-awa-api) * [API options.](userguide.md#common-options) * [Creating a new object definition.](userguide.md#creating-a-new-object-definition) * [Discovering a device's object and resource definitions.](userguide.md#discovering-a-device's-object-and-resource-definitions) @@ -42,7 +42,7 @@ Developers who aim to contribute to the Awa LightweightM2M project are referred * [Executing a resource on a registered client.](userguide.md#executing-a-resource-on-a-registered-client) * [Write attribute values of a resource or object instance on a registered client.](userguide.md#write-attribute-values-of-a-resource-or-object-instance-on-a-registered-client) * [The LWM2M Bootstrap server.](userguide.md#the-lwm2m-bootstrap-server) - * [The Awa bootstrap server daemon](userguide.md#the-awa-bootstrap-server-daemon) + * [The Awa bootstrap server daemon.](userguide.md#the-awa-bootstrap-server-daemon) ---- From d370a4fe8a68acaa0119b796fb97d5196a8e00e2 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Mon, 29 Feb 2016 15:30:28 +1300 Subject: [PATCH 33/40] IMG header image link fixed. --- doc/developer_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/developer_guide.md b/doc/developer_guide.md index d105001..788f7a9 100644 --- a/doc/developer_guide.md +++ b/doc/developer_guide.md @@ -1,5 +1,5 @@ -![](doc/img.png) +![](img.png) ---- From ba694470da88dfa208af274e44085f861661d15e Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Mon, 29 Feb 2016 15:33:34 +1300 Subject: [PATCH 34/40] External link tidied up. --- doc/developer_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/developer_guide.md b/doc/developer_guide.md index 788f7a9..3c51e3c 100644 --- a/doc/developer_guide.md +++ b/doc/developer_guide.md @@ -19,7 +19,7 @@ LWM2M makes use of an *Object/Object Instance/Resource* (OIR) model to represent ![OIR model](LWM2M_object_referencing.png) -Refer to section 6.1 of the LWM2M technical specification for details http://technical.openmobilealliance.org/Technical/technical-information/release-program/current-releases/oma-lightweightm2m-v1-0 +Refer to section [6.1 of the LWM2M technical specification](http://technical.openmobilealliance.org/Technical/technical-information/release-program/current-releases/oma-lightweightm2m-v1-0) for details. Awa LightWeightM2M is an implementation of OMA LWM2M written in C. It incorporates both server and client functionality and provides APIs for both. Typically, the client or server runs as a standalone Linux process (a "daemon") and an application uses the API library to access and modify resources across an inter-process communication (IPC) interface. This decoupling of the API from the main functionality allows other languages to make use of the daemons by implementing the IPC protocol. From fd278b3c19c6c8a5f4b22785f5d88161c192afc8 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Mon, 29 Feb 2016 15:35:51 +1300 Subject: [PATCH 35/40] Title edited. --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f9f8079..5b79d5a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,7 +3,7 @@ ---- -## Contributor guide. +# Awa LightweightM2M contributor guide. ## Reporting issues and bugs. From a5df686cce0fd95fa6a83686c671599b67d0d89a Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Mon, 29 Feb 2016 15:46:36 +1300 Subject: [PATCH 36/40] Quick start guide link fixed. Quick start file edited for style. --- README.md | 2 +- doc/starters_guide.md | 70 ++++++++++++++++++++++++++++++------------- 2 files changed, 51 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 754dbd6..060f2d7 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Firstly, to obtain a copy of the Awa LWM2M source code: * Clone the repository: ```` git clone https://github.com/FlowM2M/AwaLWM2M.git ```` -Further instructions can be found in the [Getting started guide](starters_guide.md). +Further information can be found in the [Getting started guide](doc/starters_guide.md). ---- diff --git a/doc/starters_guide.md b/doc/starters_guide.md index 1386f8c..1d2fcb8 100644 --- a/doc/starters_guide.md +++ b/doc/starters_guide.md @@ -1,50 +1,80 @@ -![](doc/img.png) +![Imagination Technologies Limited logo](img.png) ---- -## Getting Started Guide. + +# Awa LightweightM2M. + + + +---- + +## Quick start guide. + ### Building the code. + #### Building under Linux. - Install the dependencies + Install the dependencies: + ``` sudo apt-get update - sudo apt-get install build-essential gcc git mercurial python cmake python-nose python-lxml + sudo apt-get install build-essential gcc git mercurial python cmake python-nose python-lxml ``` - Run make in the root directory of the Awa LWM2M repository +Run make in the root directory of the Awa LWM2M repository + + +````$ make```` + + +This will produce the following executable files: - $ make +* build/core/src/client/awa_clientd +* build/core/src/client/awa_serverd +* build/core/src/client/awa_bootstrapd - This will produce the following executable files: + +For usage information see the [User guide](userguide.md) - build/core/src/client/awa_clientd - build/core/src/client/awa_serverd - build/core/src/client/awa_bootstrapd - For usage information see the [User guide](doc/userguide.md) +#### The cmake build. -#### The cmake Build. - The build can be created out-of-source, such that all build artefacts are placed in a dedicated directory. +The build can be created out-of-source, such that all build artefacts are placed in a dedicated directory. - First, create a suitable directory for the build output: - $ mkdir build +First, create a suitable directory for the build output: - From this directory, run cmake, passing the path to the root directory of the repository as a parameter: + +````$ mkdir build ```` + + +From this directory, run cmake, passing the path to the root directory of the repository as a parameter: +```` $ cd build $ cmake .. +```` + + +This generates a Makefile in the build directory, which can be run to generate the build artefacts: + + +````$ make ```` - This generates a Makefile in the build directory, which can be run to generate the build artefacts: - $ make +Once the build is complete you may optionally *install* the resulting binaries to a specified directory, for example: - Once the build is complete you may optionally "install" the resulting binaries to a specified directory, for example: - $ make DESTDIR=./install install +````$ make DESTDIR=./install install ```` + + +---- + +---- + From 090e032f0c10b44065a43c4749e7c09e4d294c8e Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Mon, 29 Feb 2016 15:49:23 +1300 Subject: [PATCH 37/40] quick start links fixed. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 060f2d7..90eaeef 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ Firstly, to obtain a copy of the Awa LWM2M source code: * Clone the repository: ```` git clone https://github.com/FlowM2M/AwaLWM2M.git ```` -Further information can be found in the [Getting started guide](doc/starters_guide.md). +Further information can be found in the [Quick start guide](doc/starters_guide.md). ---- @@ -50,7 +50,7 @@ Awa LWM2M documentation is available both at a general level (project informatio #### General documentation. -* For build instructions see the [Getting started guide](doc/starters_guide.md). +* For build instructions see the [Quick start guide](doc/starters_guide.md). * Examples of how to use the tools can be found in the [User guide](doc/userguide.md). * For developers, an overview of the system can be found in the [Developer guide](doc/developer_guide.md). * Information regarding the testing framework, can be found in the [Testing](doc/testing.md) guide. From 66bf486b0b75a4f17a01ca183597cadf5384b799 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Mon, 29 Feb 2016 16:04:15 +1300 Subject: [PATCH 38/40] 'Documentation' section of README.md updated --- README.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 90eaeef..794ea15 100644 --- a/README.md +++ b/README.md @@ -48,12 +48,20 @@ Further information can be found in the [Quick start guide](doc/starters_guide.m Awa LWM2M documentation is available both at a general level (project information, user and developer guides), and a techinical level (the API guide). All documentation is available in this repository. The *doc* directory contains information relating to the project in general, and the *api/doc* directory contains the lower level documentation for the Awa API. -#### General documentation. +Note that for our purposes the terms *user* and *developer* have the following definitions: + +* *User* - An M2M application developer who uses the tools and libraries supplied by this project as the foundation of, or enhancement to, their own M2M application. +* *Developer* - A developer who develops for and contributes to the Awa LightweightM2M project. -* For build instructions see the [Quick start guide](doc/starters_guide.md). -* Examples of how to use the tools can be found in the [User guide](doc/userguide.md). -* For developers, an overview of the system can be found in the [Developer guide](doc/developer_guide.md). -* Information regarding the testing framework, can be found in the [Testing](doc/testing.md) guide. + +#### General documentation. + +* For project users: + * For build instructions, see the [Quick start guide](doc/starters_guide.md). + * Examples of how to use the tools can be found in the [User guide](doc/userguide.md). +* For contributing developers: + * An overview of the system can be found in the [Developer guide](doc/developer_guide.md). + * Information regarding the testing framework, can be found in the [Testing](doc/testing.md) guide. #### API guide. From a5d8273ea39108ea1360d9cac9021470aa5ffddf Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Mon, 29 Feb 2016 16:53:39 +1300 Subject: [PATCH 39/40] testing.md edited for style --- doc/starters_guide.md | 2 +- doc/testing.md | 137 ++++++++++++++++++++++++------------------ 2 files changed, 80 insertions(+), 59 deletions(-) diff --git a/doc/starters_guide.md b/doc/starters_guide.md index 1d2fcb8..6add5c3 100644 --- a/doc/starters_guide.md +++ b/doc/starters_guide.md @@ -18,7 +18,7 @@ #### Building under Linux. - Install the dependencies: +Install the dependencies: ``` diff --git a/doc/testing.md b/doc/testing.md index 2f922c2..771971f 100644 --- a/doc/testing.md +++ b/doc/testing.md @@ -1,92 +1,113 @@ -![](doc/img.png) +![](img.png) ---- # Awa LightweightM2M. +---- -## Testing - -### Awa API Testing - - The Awa API is covered by a comprehensive test suite based on Google Test. - - It is possible to run individual tests for debugging purposes, using the --gtest_filter flag. Wildcards (*) can be passed in order to run multiple tests/suits that match the filter. (eg. --gtest_filter=TestGet.\* to run all tests in the TestGet suite). Refer to the gtest advanced guide for further details. - - Additional output can be displayed by enabling a high log level. The option --logLevel can be passed a value between 1 and 4, where 4 is the most verbose. - - Running the tests with Valgrind is highly recommended to ensure no memory leaks are introduced. - -Examples: +## Testing. - Note: replace TestSuite.TestName with the test suite and test you wish to run. +### Awa API testing. - To run a single test: +The Awa API is covered by a comprehensive test suite based on Google Test. - $ (cd build && make test_api_runner VERBOSE=1 && valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes apiv2/tests/test_api_runner --logLevel 1 --gtest_filter=TestSuite.TestName) +It is possible to run individual tests for debugging purposes, using the *--gtest_filter* flag. Wildcards (*) can be passed in order to run multiple tests/suits that match the filter. - To run a single test specifying an already-running client: +For example: ```` --gtest_filter=TestGet.\* ```` runs all tests in the TestGet suite. - $ (cd build && make test_api_runner VERBOSE=1 && valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes apiv2/tests/test_api_runner --logLevel 1 --gtest_filter=TestSuite.TestName --clientIpcPort 12345) +Refer to the gtest advanced guide for further details. - To run a test specifying an already-running server: +Additional output can be displayed by enabling a high log level. The option *--logLevel* can be passed a value between 1 and 4, where 4 is the most verbose. - # a custom debug bootstrap file is used so the client daemons connect to the correct server port, refer to api/tests/bootstrap-debug.config. - $ (cd build && make test_api_runner VERBOSE=1 && valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes api/tests/test_api_runner --logLevel 1 --gtest_filter=TestSuite.TestName --serverIpcPort 54321 --bootstrapConfig ../api/tests/bootstrap-debug.config) +Running the tests with [*Valgrind*](http://valgrind.org/docs/manual/quick-start.html) is highly recommended to ensure that no memory leaks are introduced. -### Awa Core Testing +Examples: - To run a test specifying an already-running server: +**Note:** replace *TestSuite.TestName* with the test suite and test you wish to run. - $ (cd build && make test_src_runner VERBOSE=1 && valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes src/tests/test_src_runner --logLevel 1 --gtest_filter=TestSuite.TestName) +To run a single test: +```` +$ (cd build && make test_api_runner VERBOSE=1 && valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes apiv2/tests/test_api_runner --logLevel 1 --gtest_filter=TestSuite.TestName) +```` -### Awa Tools Testing +To run a single test specifying an already-running client: +```` +$ (cd build && make test_api_runner VERBOSE=1 && valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes apiv2/tests/test_api_runner --logLevel 1 --gtest_filter=TestSuite.TestName --clientIpcPort 12345) +```` - Tests are provided that run against the supplied LWM2M tools. These tests help ensure that the tools perform correctly and produce the expected output, including error codes. These tests are written in Python and depend on the nosetests package. +To run a test specifying an already-running server: +```` +# a custom debug bootstrap file is used so the client daemons connect to the correct server port, refer to api/tests/bootstrap-debug.config. +$ (cd build && make test_api_runner VERBOSE=1 && valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes api/tests/test_api_runner --logLevel 1 --gtest_filter=TestSuite.TestName --serverIpcPort 54321 --bootstrapConfig ../api/tests/bootstrap-debug.config) +```` - For debian-based systems run: +### Awa core testing. - $ sudo apt-get install python-nose +To run a test specifying an already-running server: +```` +$ (cd build && make test_src_runner VERBOSE=1 && valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes src/tests/test_src_runner --logLevel 1 --gtest_filter=TestSuite.TestName) +```` - Then, run the tests using: +### Awa tools testing. - $ cd tools/tests - $ ./run_tests +Tests are provided that run against the supplied LWM2M tools. These tests help ensure that the tools perform correctly and produce the expected output, including error codes. These tests are written in Python and depend on the [*nosetests*](http://pythontesting.net/framework/nose/nose-introduction/) package. -### SDK Testing +For debian-based systems run: +```` +$ sudo apt-get install python-nose +```` - Awa LWM2M contains a number of unit test cases. These can be executed by running the following command from the root of the repository: +Then, run the tests using: +```` +$ cd tools/tests +$ ./run_tests +```` - $ make tests +### SDK testing. - Google Test (gtest) is used to write C++ tests against Core and API code. These can be run separately with: +Awa LWM2M contains a number of unit test cases. These can be executed by running the following command from the root of the repository: +```` +$ make tests +```` +Google Test (gtest) is used to write C++ tests against core and API code. These can be run separately with: +```` $ make gtest_tests +```` - Individual tests can be run by specifying them on the command line as an argument to TEST_FILTER: - - $ make gtest_tests TEST_FILTER=ObjectStoreInterfaceTestSuite.test_WriteAndReadSingleResource - - Multiple tests can be run by separating them with a colon character: - - $ make gtest_tests TEST_FILTER=ObjectStoreInterfaceTestSuite.test_WriteAndReadSingleResource:TlvTestSuite.test_serialise_float32 +Individual tests can be run by specifying them on the command line as an argument to TEST_FILTER: +```` +$ make gtest_tests TEST_FILTER=ObjectStoreInterfaceTestSuite.test_WriteAndReadSingleResource +```` +Multiple tests can be run by separating them with a colon: +```` +$ make gtest_tests TEST_FILTER=ObjectStoreInterfaceTestSuite.test_WriteAndReadSingleResource:TlvTestSuite.test_serialise_float32 +```` Groups of tests can be run with a wildcard (asterisk) character: +```` +$ make gtest_tests TEST_FILTER=FlowDmLowBasicTestSuite.test_encode_and_extract_* # runs all tests in this suite beginning with "test_encode_and_extract_" +$ make gtest_tests TEST_FILTER=FlowDmLowBasicTestSuite.* # runs all tests in this suite +```` + +Debugging tests can be run with the *gdb_tests* target. This invokes *gdb* when a test fails, to assist with debugging: +```` +$ make gdb_tests +```` + +Memory-leak tests can be run with the valgrind_tests target. This invokes *Valgrind* to discover and report memory leaks: +```` +$ make valgrind_tests +```` + +Some tests spawn and tear down instances of the LWM2M client and/or server daemon. Sometimes it is useful to run the tests against a standalone daemon, for example when debugging the daemon. Note that the standalone daemon is not torn down between tests, so some tests may not behave properly as daemon state is retained between tests. +```` +$ build/core/src/client/awa_clientd --ipcPort=22222 +$ make tests TEST_OPTIONS=--clientIpcPort=22222 +```` - $ make gtest_tests TEST_FILTER=FlowDmLowBasicTestSuite.test_encode_and_extract_* # runs all tests in this suite beginning with "test_encode_and_extract_" - - $ make gtest_tests TEST_FILTER=FlowDmLowBasicTestSuite.* # runs all tests in this suite - - Debugging tests can be run with the gdb_tests target. This invokes gdb when a test fails, to assist with debugging: - - $ make gdb_tests - - Memory-leak tests can be run with the valgrind_tests target. This invokes valgrind to discover and report memory leaks: - - $ make valgrind_tests - - Some tests spawn and tear down instances of the LWM2M client and/or server daemon. Sometimes it is useful to run the tests against a standalone daemon, for example when debugging the daemon. Note that the standalone daemon is not torn down between tests, so some tests may not behave properly as daemon state is retained between tests. +---- +---- - $ build/core/src/client/awa_clientd --ipcPort=22222 - $ make tests TEST_OPTIONS=--clientIpcPort=22222 From 7ba5365b403472f4bd25bea17f5e801d6bc071b0 Mon Sep 17 00:00:00 2001 From: Tony Walsworth Date: Mon, 29 Feb 2016 17:04:08 +1300 Subject: [PATCH 40/40] Minor edit in testing.md --- doc/testing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/testing.md b/doc/testing.md index 771971f..39fff6d 100644 --- a/doc/testing.md +++ b/doc/testing.md @@ -24,7 +24,7 @@ Running the tests with [*Valgrind*](http://valgrind.org/docs/manual/quick-start. Examples: -**Note:** replace *TestSuite.TestName* with the test suite and test you wish to run. +**Note.** Replace *TestSuite.TestName* with the test suite and test you want to run. To run a single test: ```` @@ -73,7 +73,7 @@ $ make tests Google Test (gtest) is used to write C++ tests against core and API code. These can be run separately with: ```` - $ make gtest_tests +$ make gtest_tests ```` Individual tests can be run by specifying them on the command line as an argument to TEST_FILTER: