FreeRTOS – Part 2

In this post we’ll look at how to perform inter-task communications.  There are several methods that could be used, but we’ll look at the most advanced one; sending messages via message queues.

Sample Code

The code for this example is stored on my GitHub account : https://github.com/smachin1000/freertos_ipc

FreeRTOS Configuration

The most important settings are shown below. Note that heap use is enabled, as it is needed by queues..

// Enable heap usage for queues
#define configSUPPORT_DYNAMIC_ALLOCATION        1
#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 5 * 1024 ) )

#define configMAX_TASK_NAME_LEN        ( 16 )
#define configUSE_TRACE_FACILITY    0
#define configUSE_16_BIT_TICKS        1
#define configIDLE_SHOULD_YIELD        1
#define configUSE_MUTEXES            0

#define configUSE_COUNTING_SEMAPHORES 0

/* Co-routine definitions. */
#define configUSE_CO_ROUTINES         0
#define configMAX_CO_ROUTINE_PRIORITIES ( 0 )

/* Set the following definitions to 1 to include the API function, or zero
to exclude the API function. */

#define INCLUDE_vTaskPrioritySet        1
#define INCLUDE_uxTaskPriorityGet        1
#define INCLUDE_vTaskDelete                0
#define INCLUDE_vTaskCleanUpResources    1
#define INCLUDE_vTaskSuspend            1
#define INCLUDE_vTaskDelayUntil            1
#define INCLUDE_vTaskDelay                1

Tasks

In this example there will be two tasks, an analog read task that reads voltages from the on-board potentiometer, and an LED display task, which will read those analog values (via a message queue) and display the value bar graph style on the 8 LEDs on the board.

Queue Definitions

To simplify things, we define a struct that holds a queue “handle” (basically a pointer to a created queue) and a queue length (constant).  We set the queue length to 10 for this example (a fairly arbitrary value chosen that’s >= 1).

typedef struct {
    xQueueHandle queue_h;
    uint16_t QUEUE_LENGTH;
} task_arg_t;

The queue itself is defined in main():

 ta.queue_h = xQueueCreate((unsigned portBASE_TYPE)ta.QUEUE_LENGTH,
                           sizeof(uint16_t));

The call to xQueueCreate specifies the queue length, and the size in bytes of each item in the queue.  We will be sending values from the A/D converter as 16 bit unsigned values, hence each value in the queue is 2 bytes long.

Task Creation

First, the LED task is created, for displaying the values read from the queue:

 c = xTaskCreate( led_task, // task "run" function
                  ( signed portCHAR * ) "led_task", // task name
                  configMINIMAL_STACK_SIZE, // task stack size in 32 bit words (not bytes)
                  &ta, // param to pass to run function
                  tskIDLE_PRIORITY + 1, // task priority
                  NULL ); // task handle

The only thing noteworthy here is that we pass in a pointer to “ta” as the task argument.  ta is the task_arg_t stuct we described earlier.

The second, analog read task is then defined:

 c = xTaskCreate( analog_read_task, // task "run" function
                  ( signed portCHAR * ) "analog_read_task", // task name
                  configMINIMAL_STACK_SIZE, // task stack size in 32 bit words (not bytes)
                  &ta, // param to pass to run function
                  tskIDLE_PRIORITY + 1, // task priority
                  NULL ); // task handle

Note it is also passed in a pointer to ta, so it has a reference to the queue length and queue handle.

Analog Reading & Posting to the Queue

The body of the analog read task is shown below.  Note that it checks the queue is not full before sending.

void analog_read_task(task_arg_t* ta)
{
	const xQueueHandle queue_h = ta->queue_h;

      while (1) {
        const ace_channel_handle_t current_channel = ACE_get_first_channel();
        const uint16_t adc_result = ACE_get_ppe_sample(current_channel);
        const uint16_t value_to_send = median_filter(adc_result);

        if (uxQueueMessagesWaiting(queue_h) < ta->QUEUE_LENGTH) {
            const int xStatus = xQueueSendToBack(queue_h, &value_to_send, 0);
            if (xStatus != pdPASS) {
                /* The send operation could not complete because the queue was full -
                   this must be an error as the queue should never contain more than
                   one item! */
                printf( "Could not send to the queue, error code %d.\r\n", xStatus );
                break;
            }
        }
        else {
            // no space in transmit queue, so don't hog the CPU
            taskYIELD();
        }
    }
}

Also note that the analog value read is passed through a median filter. This is because reading from the potentiometer was quite noisy at it’s lower range.

Reading From The Queue

Queue reading is done by the led_task function shown below:

void led_task(task_arg_t* ta)
{
	const xQueueHandle queue_h = ta->queue_h;

    while (1) {
    	// wait until there's at least one message in the queue
        while (uxQueueMessagesWaiting(queue_h) == 0) {
            taskYIELD();
        }
        // queue should now definitely have at least one value in it, so read the value
        // from the queue
        uint16_t received_value;
        const int xStatus = xQueueReceive(queue_h, &received_value, 0);
        if (xStatus == pdPASS) {
            // value received should be will be 650 to 3800, so threshold and scale it as 0-255 now
            if (received_value < MIN_ANALOG_VALUE) {                 received_value = MIN_ANALOG_VALUE;             }             if (received_value > MAX_ANALOG_VALUE) {
                received_value = MAX_ANALOG_VALUE;
            }
            uint32_t scaled_value = round((received_value - MIN_ANALOG_VALUE) * 255.0 /
                                          (MAX_ANALOG_VALUE - MIN_ANALOG_VALUE));
            // now determine which of the 8 LEDs to light, remembering they
            // are opposite polarity.
            uint8_t v = 0;
            int x;
            for (x = 7;x >= 0;x--) {
                if (scaled_value >= (1 << x)) {
                    v |= (1 << x);
                    scaled_value = scaled_value / 2;
                }
            }
            MSS_GPIO_set_outputs(0xffffffff - v);
        }
        else {
            printf("\r\nError %d reading from queue\r\n", xStatus);
            break;
        }
    }
}

Again, note that it waits for the queue to be non-empty before trying to read a value. Once the 16 bit value is read, it is scaled to display on the 8 LEDs on the board.

Please leave any feedback below:

Advertisements

FreeRTOS – Part 1

This post will take a look at FreeRTOS, the popular open source RTOS.  I will show sample code and projects that run on an Actel Smartfusion 1 Eval. board, using Actel Softconsole 3.2.  Hopefully these examples can be easily adapted to your hardware if needed.  The SmartFusion board is shown below:

smartfusion 1 eval board

Why Look at FreeRTOS?

Linux is great for complex embedded systems requiring high performance networking, filesystems & perhaps a GUI.  But a lot of embedded systems are much simpler requiring reading from a few inputs, performing some algorithims and driving some outputs.  For a system like this you wouldn’t want to drag in all the complexity of the Linux kernel.  Plus the RTOS should be able to give much faster and more deterministic timing (something we’ll look at in detail in a future post).

Example #1 : LED Flashing

This will be a simple example with one task, which will strobe the 8 LEDs on the eval. board “cylon” style.

Configuration

FreeRTOS is very flexible in it’s configuration, features can be included or excluded based on #define symbols in port_config/FreeRTOSConfig.h.  Here is an example snippet below:

#define INCLUDE_vTaskPrioritySet		1
#define INCLUDE_uxTaskPriorityGet		1
#define INCLUDE_vTaskDelete			0
#define INCLUDE_vTaskCleanUpResources	        1
#define INCLUDE_vTaskSuspend			1
#define INCLUDE_vTaskDelayUntil			1
#define INCLUDE_vTaskDelay			1

These defines show that we don’t want to include the vTaskDelete function, but do want to include the other task related functions listed.

Task Creation

Tasks are created with the xTaskCreate function, here’s an example:

    c = xTaskCreate( led_task,                          // task "run" function
                     ( signed portCHAR * ) "led_task",  // task name
                     configMINIMAL_STACK_SIZE,          // task stack size in 32 bit words (not bytes)
                     NULL,                              // params to pass to run function
                     tskIDLE_PRIORITY + 1,              // task priority
                     NULL );                            // task handleTasks are created with the xTask

A call to

vTaskStartScheduler();

then starts the FreeRTOS scheduler.  Here is the entire main.c file that shows the complete task initialization and running: main.c

The LED Flash Task

This task will run forever, and turn on and off the 8 LEDs on a GPIO port in Cylon style (back and forth).  The code is quite short, so here is the contents of the entire file led_task.c:

#include "../drivers/mss_gpio/mss_gpio.h"

#include "FreeRTOS.h"
#include "task.h"

void led_initialization()
{
    /* Configuration of GPIO's */
    MSS_GPIO_config(MSS_GPIO_0 , MSS_GPIO_OUTPUT_MODE );
    MSS_GPIO_config(MSS_GPIO_1 , MSS_GPIO_OUTPUT_MODE );
    MSS_GPIO_config(MSS_GPIO_2 , MSS_GPIO_OUTPUT_MODE );
    MSS_GPIO_config(MSS_GPIO_3 , MSS_GPIO_OUTPUT_MODE );
    MSS_GPIO_config(MSS_GPIO_4 , MSS_GPIO_OUTPUT_MODE );
    MSS_GPIO_config(MSS_GPIO_5 , MSS_GPIO_OUTPUT_MODE );
    MSS_GPIO_config(MSS_GPIO_6 , MSS_GPIO_OUTPUT_MODE );
    MSS_GPIO_config(MSS_GPIO_7 , MSS_GPIO_OUTPUT_MODE );
}

void led_task(void *para)
{
    uint8_t b = 1;
    uint8_t dir = 1;
    while (1) {
    	const uint8_t v = 0xff & ~b;
        MSS_GPIO_set_outputs( v );
        if (dir) {
            b = b << 1;
        }
        else {
            b = b >> 1;
        }
        if (b == 128 || b == 1) {
            dir = !dir;
        }
        vTaskDelay(configTICK_RATE_HZ / 16);
    }
}

The run function called by FreeRTOS is led_task(), which sits in an infinite loop and flashes the LEDs as desired, putting a 1/16 second delay between each LED update.  That’s pretty much all there is to it for creating a single task.  In the next post we’ll create multiple tasks and look at passing some data between them.  The entire source code for this posting is on my GitHub page at freertos_ledflash.  SoftConsole 3.2 for Windows can also be downloaded from here if needed.

One Essential Linux Kernel Setting

When building a new kernel, be sure to enable CONFIG_IKCONFIG=y.  This will cause the file /proc/config.gz to be generated on the running system.  This is a gzipped version of the original .config file used to build the kernel.  It can be easily viewed on the running system with “zcat /proc/config.gz”.

This can be very handy for trying to figure out what features were built into a kernel running on a test device, especially one you did not build yourself.

Experimenting with the Thread Protocol

This post will be the first of a short series where I will configure Thread networks using platforms from various vendors.  First up is the Thread release 0.6.0 from Freescale.  This is an older version, but I had access to all the source from the Freescale beta website, and it works, so is worth looking at.  Future posts will explore the latest Thread releases from NXP and SiLabs.

Setup

Hardware

I am using two Freescale Tower boards (twrkw24d512).  It should also be possible to use the USB dongle (usbkw24d512), but I believe that needs a separate JTAG adapter to program it, so the tower boards are easier to use.

Image result for twrkw24d512

Software

First, check out my thread_nxp repository from GitHub : https://github.com/smachin1000/thread_nxp

This should create a top-level thread_nxp directory, and an “FSL_Thread_Stack_0.6.0” subdirectory, which is what we’ll be using for this set of tests.

You will also need a copy of the IAR compiler for ARM.  Eval. versions are available.

Simple Network Setup

Thread network

In this test, we’ll create a Thread end device (white circle in above diagram) and a Thread router (blue circle), which will act as the leader.  We’ll test network connectivity between the two boards and explore the commands available from the serial console CLI.

End Device

Plugging in the Tower board should have created an additional virtual COM port, so connect to that now (115N81) with a serial console (e.g. putty) in preparation for seeing the output from when we run the project.

Open the end device project “C:\thread_nxp\FSL_Thread_Stack_0.6.0\Thread\app\thread\thread_end_device\iar\twrkw24d512\thread_end_device_twrkw24d512.eww” in IAR.

Thread device configuration is specified in the file thread_end_device_config.h for each of these examples.

Go ahead and build the project and download it to the Tower board.  If you have connected the serial console you will see this startup message when the application has started running:

SHELL build: Jan 6 2017
Copyright (c) 2014 Freescale
End Device Application Demo
Press a board switch or enter 'startnwk' to create or join a Thread network!
Note that a "help" command is available.

Before experimenting too much here, let’s get the router node (the leader) running:

Thread Router

First, locate the virtual COM port created by the 2nd Tower board inserted.  Connect a serial console (115N81) to this COM port.

Locate and open the project “C:\thread_nxp\FSL_Thread_Stack_0.6.0\Thread\app\thread\thread_router\iar\twrkw24d512\thread_router_twrkw24d512.eww”.  As with the end node project, Thread defines are in the file thread_end_device_config.h (no adjustments are necessary, but you may want to look).

Compile  and run the Thread Router application, and you should see this appear on the serial terminal:

SHELL build: Jan 21 2017
Copyright (c) 2014 Freescale
Router Application Demo
Press a board switch or enter 'startnwk' to create or join a Thread network!
Starting network...
Attaching to Thread network on channel 26
Cannot find an existing network

Created a new Thread network on channel 26 and PAN ID:0xface
Interface 0: 6LoWPAN
 Mesh local address (ML16): fd00:db8::ff:fe00:0
 Mesh local address (ML64): fd00:db8::204:9f03:1841:0f
Node has taken the Leader role

 

You will notice that the router node has gone ahead and created a new network, and recognized there are no leaders on that network, so has made itself the leader.

Adding the End Node to the Network

We now need to start the network on the end node with the “startnwk” command, you should see output in the terminal as below:

$ startnwk

Starting network...
Attaching to Thread network on channel 26
Attached to network with PAN ID: 0xface
Node started as Polling End Device
Interface 0: 6LoWPAN
 Mesh local address (ML16): fd00:db8::ff:fe00:01

OK, so at this point we have both nodes joined to the same network.  Let’s use the ifconfig command to see what IP addresses have been assigned to each node.

On the router board, run “ifconfig all”.  On my  board, this gives the output below:

$ ifconfig all
THREAD Configuration

Interface 0: 6LoWPAN
 Link local address: fe80::204:9f03:1841:0f
 Link local address: fe80::ff:fe00:0
 Mesh local address (ML16): fd00:db8::ff:fe00:0
 Mesh local address (ML64): fd00:db8::204:9f03:1841:0f

Running the same command on my end node board gives this:

$ ifconfig all
THREAD Configuration

Interface 0: 6LoWPAN
 Link local address: fe80::204:9f0e:7061:1c
 Link local address: fe80::ff:fe00:01
 Mesh local address (ML16): fd00:db8::ff:fe00:01

Why so many addresses?  Let’s try to explain.

Link Local vs. Mesh Local Addresses

Link local addresses are used if you want to connect to a node only 1 hop away.  Mesh local addresses are used if you want to reach a node more than 1 hop away, however mesh local addresses are never routed beyond the Thread network (i.e. can never make it to the outside Internet).  Link local addresses here are like the “192.168.x.x” addresses in IPV4.

Ping Testing

Since our network is super-simple, trying to ping one board from another should work with either the link local or mesh local addresses.  Let’s try it.  On the router node, run “ping6 -c 5 <end node link local addr>.  On my setup, I see these results:

$ ping6 -c 5 fe80::ff:fe00:01
Pinging fe80::ff:fe00:01 with 32 bytes of data:
Request timed out
Reply sequence number not matching
Reply from fe80::ff:fe00:01: bytes=32 time=451ms
Request timed out
Reply sequence number not matching
Reply from fe80::ff:fe00:01: bytes=32 time=496ms
Request timed out

$ Reply from fe80::ff:fe00:01: bytes=32 time=2480ms

OK, we are getting some connectivity, but not the exact results we expect.  I’ll need to spend some time investigating this and will hopefully post the answer in a future post.

Similarly, you should be able to ping the router node from the end node.  This worked on my system, but did have the sequence number problem shown above that needs to be investigated.

Socket Communication

Let’s now try sending data from one board to another using sockets and UDP.  Fortunately the router application has already set up a socket to listen on (see APP_InitSocketServer in router_app.c).  This is setup to receive UDP datagrams on port 1234.  The receive callback handler interprets the data as plain text commands (see APP_SocketClientRxCallback in router_app.c).

With both the router and end device running, and the network joined, run these commands on the end device to create a socket and send the “Temp” command.

$ socket open udp fd00:db8::ff:fe00:0 1234 6
Opening Socket... OK
Socket id is: 0
$ socket send 0 Temp
Command was sent

The leader should receive the Temp command, and display the IP address it came from:

Temp From IPv6 Address: fd00:db8::ff:fe00:01

 

 

 

IoT Protocols CoAP – Part 3

In this post we extend the existing temperature server to support being an observable resource.  In this scheme the resource sends out a new value whenever required, the server does not need to poll for new messages.  The message sent could be periodic (sensor reading every second), or if a sensor state has changed.  Combined with the efficiency of the CoAP protocol, this would be a very streamlined way to collect data from sensors.

Making a Resource Observable

This is quite easy using the TxThings library we’ve been using.  Just create the resource as usual, and set the observable property to True.  Then, each time you want to broadcast a new state, just call self.notify().

Here’s a basic example of an observable temperature sensor, based on the temperature sensor code we’ve been developing.  It derives from our previous TempResource class we’ve developed earlier.  Full code is at https://github.com/smachin1000/coap_examples.

class ObservableTempResource(TempResource):
 """
 Example CoAP server that implements an observable resource (temperature).
 """
 def __init__(self):
    TempResource.__init__(self)
    self.visible = True
    self.observable = True
    self.notify()

def notify(self):
    self.updatedState()
    # send a response every second
    reactor.callLater(1, self.notify)

Observing the Resource

Unfortunately the TxThings library does not yet have support for being an observer, so the above code can be tested by installing the Copper Plug-in for FireFox.

copper plugin screenshot

Browse to the observable temperature resource (e.g. coap://192.168.1.100:5683/observable_temperature) and press the observe button, and you should see new temperature values coming in every one second.

Have any readers been using observable resources in real projects?  If so, how’d they work out?

IoT Protocols – CoAP – Part 2

In the previous posting we designed code for a simple CoAP client and server.  In this post we’ll extend on that code.

Discovery

In terms of communications protocols, discovery is the process whereby clients can “discover” the various properties provided by the server.  Discovery is absent from some of the older telemetry protocols (e.g. MODBUS), and it’s a very desirable feature.  Without automated discovery, the client will have to be informed of the server’s capabilities by some other means, e.g. manual provisioning or reading in a configuration file for the device etc.  Automatic provisioning by discovery is much quicker and reliable.

CoAP Support For Discovery

A client can discover properties about a server by issuing a CoAP GET to the URL:

 .well-known/core

Example

If we now switch to the files under the 01_discovery directory of the GitHub Project and run the new temperature_server.py on one machine, then from another machine, run the CoAP GET client with args to query resources, we see:

C:\Users\smachin\coap_examples\01_discovery>python coap_client.py 192.168.1.100
.well-known/core
2016-06-13 06:15:39+0000 [-] Log opened.
2016-06-13 06:15:39+0000 [-] Coap starting on 5683
2016-06-13 06:15:39+0000 [-] Starting protocol <txthings.coap.Coap instance at 0x966940>
2016-06-13 06:15:57+0000 [Coap (UDP)] Received 'T\x01\x8f\xe5\x00\x00:\x94\xbb.well-known\x04core' from 192.168.1.13:61616
2016-06-13 06:15:57+0000 [Coap (UDP)] Incoming Message ID: 36837
2016-06-13 06:15:57+0000 [Coap (UDP)] New unique CON or NON message received
2016-06-13 06:15:57+0000 [Coap (UDP)] Request doesn't pertain to earlier blockwise requests.
2016-06-13 06:15:57+0000 [-] </temperature>;title="Temperature Resource";units="degrees C"
2016-06-13 06:15:57+0000 [Coap (UDP)] Preparing response...
2016-06-13 06:15:57+0000 [Coap (UDP)] Token: 00:00:3a:94
2016-06-13 06:15:57+0000 [Coap (UDP)] Sending response, type = NON (request type = NON)
2016-06-13 06:15:57+0000 [Coap (UDP)] Sending message to 192.168.1.13:61616
2016-06-13 06:15:57+0000 [Coap (UDP)] Message 'TE5\xf0\x00\x00:\x94\xc1(\xff</temperature>;title="Temperature Resource";units="degrees C"' sent successfully

This shows that the CoAP server supports the single resource /temperature and a human readable representation “Temperature resource”.  Additionally some metadata is returned by the discovery:

units="degrees C"

Metadata like this can be added with calls addParam() member of a resource class in the TxThings Python CoAP library.

Resource Details

The above example for the data on the resource discovered is very minimal; what else does CoAP support?

According to the CoAP spec, servers should support the CoRE link format.  The CoRE link format is described in this RFC and we may examine it in detail in a later post.

Next Post

Next time we’ll look at observable resources, which are resources that notify clients when their data changes.

Got any feedback?  Are you using CoAP in practice?  Pls. leave a comment.

 

Special thanks to Maciej Wasilak for answering some of my questions about his TxThings library.

 

IoT Protocols – CoAP – Part 1

In this article I’ll look at the CoAP protocol, with sample code for a server and a client.  CoAP is designed to run on small devices; by default it uses UDP and has efficient binary headers, so most data can be contained in a single packet without fragmentation.

It is also designed to follow the REST model, so supports verbs such as GET, POST, DELETE etc.

To further reduce traffic, messages can either be confirmable (an ACK must be sent by the recipient), or non-confirmable (fire and forget).  The combination of UDP and non-confirmable messages sounds ideal for time vartying sensor readsings in system with a cell modem, where you pay per byte transferred.  Using this combination, a sensor reading could be transmitted in as little as a single UDP message.

Additional features of CoAP include discovery, observable messages and security via DTLS (examined in future posts).

Sample CoAP Request

The “on the wire” bytes for a CoAP GET of reading the value “temperature” from a remote node is shown below:

CoAP request

The header contains:

  • Two bits for version number (01 in this case)
  • Two bits for message type (non-confirmable in this case).  Possible message types are Confirmable (0), Non-confirmable (1), Acknowledgement (2), or Reset (3)
  • Four bits for the token length (4 in this case).  The token is described below.
  • One byte for the “code”.  This is like the HTTP verb (GET in this case)
  • Two bytes for the message ID.  The message ID is used to detect duplicate messages

After the header we have:

  • A token 0x0000ef8e, used to correlate requests and responses.  In this example the token is 4 bytes long.  The token can be 0 to 8 bytes in length
  • Four bits containing an option delta – the difference between this option and the last.  In this example the option is 11 decimal = a Uri path.  Possible values for the option are listed in https://tools.ietf.org/html/rfc7252#section-12.2
  • Four bits for the length of the option (1011 = 11 bytes in this case)
  • The option itself.  In this case the option is a Uri path, and the 11 byte value is “temperature”

Sample CoAP Response

The “on the wire” bytes for the response to the above GET is:

CoAP response

The header contains:

  • Two bits for version number (01 in this case)
  • Two bits for message type (non-confirmable in this case)
  • Four bits for the token length (4 in this case)
  • One byte for the “code”.  This is like the HTTP response code, and is 0x54 in this case (see that broken up into nibbles this is 02 05 (== HTTP response code “content”).  The full range of values for this field is listed at https://tools.ietf.org/html/rfc7252#section-12.1.2
  • Two bytes for the message ID
  • Four bytes for the token 0x0000ef8e.  Note this value matches the token in the request
  • A single byte 0xff to indicate end of options
  • The payload itself, ASCII bytes “33.8” to indicate 33.8 degrees C

Sample Code

This code is all stored at my GitHub page under https://github.com/smachin1000/coap_examples

Code below is from the 00_simple_example directory.

Here is an example server written in Python.  I am using the txThings Python CoAP library.  This server will return the ambient temperature in degrees C.

import sys

from twisted.internet import defer
from twisted.internet import reactor
from twisted.python import log

import txthings.resource as resource
import txthings.coap as coap

import platform
import os
import random


class TempResource(resource.CoAPResource):
    """
    Example CoAP server to return the current ambient temperature.
    No 01_discovery or any other advanced features are supported in
    this example.
    """

    def __init__(self):
        resource.CoAPResource.__init__(self)
        self.addParam(resource.LinkParam("title", "Temperature resource"))

        # Disable 01_discovery for now, we'll cover that next
        # self.visible = True

    # noinspection PyUnusedLocal
    def render_GET(self, request):
        temp = self._get_temperature()
        response = coap.Message(code=coap.CONTENT, payload='%.1f' % temp)

        return defer.succeed(response)

    @staticmethod
    def _get_temperature():
        """
        Temperature is obtained via the embedded board's tshwctl utility, it outputs both
        CPU & ambient temperature in this format:
        
        external_temp=32.1648
        internal_temp=62.985

        this function returns the ambient temperature as a float.
        """

        # If running on real hardware, read from onboard temperature sensor
        # otherwise return a simulated value.
        if platform.machine() == 'armv5tejl':
            return float(os.popen("tshwctl --cputemp|grep external|cut -f2 -d'='").read().rstrip())
        else:
            return 30 + random.uniform(0, 5)

if __name__ == '__main__':
    log.startLogging(sys.stdout)
    root = resource.CoAPResource()

    temperature_resouce = TempResource()
    root.putChild('temperature', temperature_resouce)

    endpoint = resource.Endpoint(root)

    # Listen on default CoAP port 5683
    reactor.listenUDP(coap.COAP_PORT, coap.Coap(endpoint))

    # Run Twister'd event loop
    reactor.run()

Here is the corresponding client code:

import sys

from twisted.internet import reactor
from twisted.python import log

import txthings.coap as coap
import txthings.resource as resource

from ipaddress import ip_address


class CoapClient:
    """
    Sample general purpose CoAP client that performs a GET to the specified IP address and path.

    Example:
        python coap_client 127.0.0.1 temperatures
    """
    def __init__(self, ip_addr, url):
        self._ip_addr = ip_addr
        self._url = url
        # The reactor is Twisted's main event loop
        # Request that requestReource is called 1 second from now
        reactor.callLater(1, self.requestResource)

    def requestResource(self):
        # Create a non confirmable CoAP request.  To keep as
        # simple as possible we don't specify any observer
        # callbacks either.
        request = coap.Message(code=coap.GET, mtype=coap.NON)
        url_tokens = self._url.split('/')
        request.opt.uri_path = tuple(url_tokens)

        # COAP_PORT is 5683, the default UDP port for CoAP
        request.remote = (ip_address(self._ip_addr), coap.COAP_PORT)
        d = protocol.request(request)
        d.addCallback(self.printResponse)
        d.addErrback(self.noResponse)

    @staticmethod
    def printResponse(response):
        print 'CoAP result: ' + response.payload

    def noResponse(self, failure):
        print 'Failed to fetch resource:%s' % failure

if __name__ == '__main__':
    if len(sys.argv) == 3:
        addr = sys.argv[1]
        url = sys.argv[2]
    else:
        print 'Usage : %s <IP address> <url>' % sys.argv[0]
        print 'The url argument should not start with a "/", but use'
        print '"/" characters to separate later portions'
        sys.exit(1)

    log.startLogging(sys.stdout)

    endpoint = resource.Endpoint(None)
    protocol = coap.Coap(endpoint)
    client = CoapClient(addr, url)

    reactor.listenUDP(61616, protocol)

    # Run the Twisted event loop
    reactor.run()
Sample Run (connecting to server running on 192.168.1.100):

C:\Users\smachin\coap_examples\01_discovery>python coap_client.py 192.168.1.100
temperature
2016-06-12 20:24:27-0700 [-] Log opened.
2016-06-12 20:24:27-0700 [-] Coap starting on 61616
2016-06-12 20:24:27-0700 [-] Starting protocol <txthings.coap.Coap instance at 0
x02DD3CB0>
2016-06-12 20:24:28-0700 [-] Sending message to 192.168.1.100:5683
2016-06-12 20:24:28-0700 [-] Message 'T\x01\xd2\x1f\x00\x00m\xfb\xbbtemperature'
 sent successfully
2016-06-12 20:24:28-0700 [-] Sending request - Token: 00006dfb, Host: 192.168.1.
100, Port: 5683
2016-06-12 20:24:28-0700 [Coap (UDP)] Received 'TEe\xa6\x00\x00m\xfb\xff37.7' fr
om 192.168.1.100:5683
2016-06-12 20:24:28-0700 [Coap (UDP)] Incoming Message ID: 26022
2016-06-12 20:24:28-0700 [Coap (UDP)] New unique CON or NON message received
2016-06-12 20:24:28-0700 [Coap (UDP)] Received Response, token: 00006dfb, host:
192.168.1.100, port: 5683
2016-06-12 20:24:28-0700 [-] CoAP result: 37.7

 

Conclusion

CoAP is an efficient messaging protocol for IoT applications.  Have you used it in practice?   If so, what limitations did you encounter?  Leave some feedback here: