SignalR on the Wire – an informal description of the SignalR protocol

I have seen the question asking about a description of the SignalR protocol come up quite a lot. Heck, when I started looking at SignalR I too was looking for something like this. Now, almost a year later, after I architecturally redesigned the SignalR C# client and wrote from scratch the SignalR C++ Client I think I can describe the protocol quite accurately. So, here we go.
In my view the protocol used by SignalR consists of two parts. The first part is related to connection management i.e. how the connection is started, stopped, reconnected etc. This part contains some quite complicated bits (especially around starting the connection) and it is mostly interesting to people who want to write their own client (which, I believe, is a minority). The second part which, I think, the vast majority of users is actually interested in is what are all these “H”s, “A”s, “I”s etc. SignalR is putting on the wire and writing to logs. I will start from the first part and then will describe the second part.
Disclaimer: In some cases I will be talking about differences among the clients. I have only worked with the SignalR .NET client, the SignalR C++ Client and the SignalR JavaScript Client (“worked” in this case is an overstatement – I just fixed a few bugs and looked at the code several times). I am aware of other SignalR clients like the Java or Objective-C one but I have not tried them nor looked at the code and I don’t know what they do, how they do it and how much they conform to the description below.

Connection Management
SignalR manages the connection by using the HTTP(S) protocol. Actions are initiated by the client which sends HTTP requests that contain the requested action and a sub-set of common parameters. The requests can be sent using the GET or (when using protocol version 1.5) POST method. Not all the requests require all the parameters. Here are the parameters used in SignalR requests with their descriptions:

  • transport – the name of the transport being used. Valid values: webSockets, longPolling, serverSentEvents, foreverFrame
  • clientProtocol – the version of protocol used by the client. The most recent version is 1.5 however it is only used by the JavaScript client since the change that mandated bumping the version of the protocol to 1.5 is only relevant for this client. The .NET and C++ clients currently use version 1.4. Note that the server is designed to support down-level clients (i.e. clients using previous versions of the protocol) and the current (2.2.0) version supports protocol versions from 1.2 to 1.5
  • connectionToken – a string that identifies the sender. It is returned in the response to the negotiate request. See this document for more details on connection token.
  • connectionData – a url-encoded JSon array containing a list of hubs the client is subscribing to. For instance if the client is subscribing to two hubs – “my_hub”, “your_hub” the array to be sent looks like this: [{"Name":"my_hub"},{"Name":"your_hub"}] and after url-encoding it becomes:
    %5B%7B%22Name%22:%22my_hub%22%7D,%7B%22Name%22:%22your_hub%22%7D%5D
  • messageId – the id of the last received message. Used for reconnecting and – when using the longPolling transport – in poll requests
  • groupsToken – a token describing what groups the connection belongs to. Used for reconnecting
  • queryString – an arbitrary query string provided by the user; appended to all requests

Starting the Connection
Starting the connection is the most complicated task related to connection management performed by a SignalR client. It requires sending three requests to the server – negotiate, connect and start. The whole sequence looks as follows:

  • the client sends the negotiate request. The response to the negotiate request contains a number of client configuration settings
  • the client starts the transport by sending the connect request. The connect request has to complete within the timeout returned by the server in the response to the negotiate request. The response to the connect request (a.k.a. init message) is sent on the newly started transport (i.e. if you use webSockets transport it will be sent on the newly opened websocket, if you use serverSentEvents it will be sent on the newly opened event stream if you use longPolling it will be sent as a response to the connect/poll request)
  • once the init message has been received the client sends the start request. The server confirms it received the start request by responding with the {Response: Started} payload

You can also find some details about the start sequence here.

Connection Management Requests
Here is a list of requests the client sends to start, stop and reconnect the connection.

» negotiate – negotiate connection parameters
Required parameters: clientProtocol, connectionData (when using hubs)
Optional parameters: queryString
Sample request:

http://host/signalr/negotiate?clientProtocol=1.5&connectionData=%5B%7B%22name%22%3A%22chat%22%7D%5D

Sample response:

{
  "Url":"/signalr",
  "ConnectionToken":"X97dw3uxW4NPPggQsYVcNcyQcuz4w2",
  "ConnectionId":"05265228-1e2c-46c5-82a1-6a5bcc3f0143",
  "KeepAliveTimeout":10.0,
  "DisconnectTimeout":5.0,
  "TryWebSockets":true,
  "ProtocolVersion":"1.5",
  "TransportConnectTimeout":30.0,
  "LongPollDelay":0.0
}

Url – path to the SignalR endpoint. Currently not used by the client.
ConnectionToken – connection token assigned by the server. See this article for more details. This value needs to be sent in each subsequent request as the value of the connectionToken parameter
ConnectionId – the id of the connection
KeepAliveTimeout – the amount of time in seconds the client should wait before attempting to reconnect if it has not received a keep alive message. If the server is configured to not send keep alive messages this value is null.
DisconnectTimeout – the amount of time within which the client should try to reconnect if the connection goes away.
TryWebSockets – whether the server supports websockets
ProtocolVersion – the version of the protocol used for communication
TransportConnectTimeout – the maximum amount of time the client should try to connect to the server using a given transport

» connect – starts a transport
Required parameters: transport, clientProtocol, connectionToken, connectionData (when using hubs)
Optional parameters: queryString
Sample request:

wss://host/signalr/connect?transport=webSockets&clientProtocol=1.5&connectionToken=LkNk&connectionData=%5B%7B%22name%22%3A%22chat%22%7D%5D

Sample response (a.k.a. init message):

{"C":"s-0,2CDDE7A|1,23ADE88|2,297B01B|3,3997404|4,33239B5","S":1,"M":[]}

Remarks:
The connect request starts a transport. If you are using the webSockets transport the client will use the ws:// or wss:// scheme to open a websocket. If you are using the serverSentEvents transport the client will open an event stream. For the longPolling transport the connect request is treated by the server as the first poll request. The response to the connect request is sent using the newly opened channel and is a JSon object containing the property "S" set to 1 (a.k.a. init messge). The server however does not guarantee this message to be the first message sent to the client (e.g. there can be a broadcast in progress which will be sent to the client before the server sends the init message. This is interesting in case of the longPolling transport because the response to the connect request will close the pending connect request even though it is not the init message. The init message will in that case be sent as a response to a subsequent poll request).

» start – informs the server that transport started successfully
Required parameters: transport, clientProtocol, connectionToken, connectionData (when using hubs)
Optional parameters: queryString
Sample request:

http://host/signalr/start?transport=webSockets&clientProtocol=1.5&connectionToken=LkNk&connectionData=%5B%7B%22name%22%3A%22chat%22%7D%5D

Sample response:

{"Response":"started"}

Remarks:
start request was added in the version 1.4 of the protocol to make some scenarios work reliably on the server side. Adding this request to the start sequence made things complicated on the client since though since there is quite a few things that can go wrong after the client received the init message but before it received a response to the start message (like the connection is lost and the client starts reconnecting, the user stops the connection etc.).

» reconnect – sent to the server when the connection is lost and the client is reconnecting
Required parameters: transport, clientProtocol, connectionToken, connectionData (when using hubs), messageId, groupsToken (if the connection belongs to a group)
Optional parameters: queryString
Sample request:

ws://host/signalr/reconnect?transport=webSockets&clientProtocol=1.4&connectionToken=Aa-
aQA&connectionData=%5B%7B%22Name%22:%22hubConnection%22%7D%5D&messageId=d-3104A0A8-H,0%7CL,0%7CM,2%7CK,0&groupsToken=AQ

Sample response: N/A
Remarks:
Similarly to the connect request the reconnect request starts (re-starts) the transport. For the longPolling transport from the client perspective it is just yet another form of poll, for the serverSentEvents transport a new event stream will opened, for the webSockets transport it will open a new websocket. The messageId tells the server what was the last message the client received and the groupsToken tells the server what groups the client belonged to before reconnecting.

» abort – stops the connection
Required parameters: transport, clientProtocol, connectionToken, connectionData (when using hubs)
Optional parameters: queryString
Sample request:

http://host/signalr/abort?transport=longPolling&clientProtocol=1.5&connectionToken=QcnlM&connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D

Sample response: empty
Remarks: The JavaScript and C++ clients send abort request in a fire and forget manner and ignore all the errors. The .NET client blocks until response is received or a timeout occurs, what apart from taking more time, causes some issues (like this bug).

» ping – pings the server
Required parameters: none
Optional parameters: queryString
Sample request:

http://host/signalr/ping

Sample response:

{ "Response": "pong" }

Remarks: The ping request is not really a “connection management request”. The sole purpose of this request is to keep the ASP.NET session alive. It is only sent by the the JavaScript client.

SignalR Messages
Before we can take a look at the messages SignalR puts on the wire we need to discuss how different transports send and receive messages. The webSockets transport is quite simple since it is creating a full-duplex communication channel used to send data from the server to the client and from the client to the server. Once the channel is setup there are no further HTTP requests until the client is stopped (the abort request) or the connection was lost and the client tries to re-establish the connection (the reconnect request). The serverSentEvents transport creates an event stream that is used to receive messages from the server. If the client wants to send a message to the server it creates a send HTTP POST request and sends the data in the request body. The longPolling transport creates a long running HTTP request which the server will respond to if it has a message for the client. If the server does not send any data within a configured timeout (calculated as the sum of the ConnectionTimeout received in the response to the negotiate request + 10 seconds – which by default is 120 seconds) the current poll request will be closed and the client will start a new poll request (this is to prevent proxies from closing the long running request which would result in unnecessary reconnects). Sending messages works in the same way as for the serverSentEvents transport – a send HTTP request containing the message in the request body is sent to the server. Here are the descriptions of the send and poll requests.

» send – sends data to the server. Used by the serverSentEvents and longPolling transports
Required parameters: transport, clientProtocol, connectionToken, connectionData (when using hubs), data (sent in the request body)
Optional parameters: queryString
Sample request:

http://host/signalr/send?transport=longPolling&clientProtocol=1.5&connectionToken=Ac5y5&connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D

Data send int the request body (url encoded, see the description below) :

data=%7B%22H%22%3A%22chathub%22%2C%22M%22%3A%22Send%22%2C%22A%22%3A%5B%22a%22%2C%22test+msg%22%5D%2C%22I%22%3A0%7D

Sample response (see the description below):

{ "I" : 0 }

» poll – starts a (potentially) long running polling request that the server will use to send data to the client. Used only by the longPolling transport
Required parameters: transport, clientProtocol, connectionToken, connectionData (when using hubs), messageId (the JavaScript client sends messageId in the request body)
Optional parameters: queryString
Sample request:

http://host/signalr/poll?transport=longPolling&clientProtocol=1.5&connectionToken=A12
-FX&connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D&messageId=d-53B8FCED-B%2C1%7CC%2C0%7CD%2C1

Sample response (see the description below):

{
  "C":"d-53B8FCED-B,4|C,0|D,1",
  "M":
  [
    {"H":"ChatHub","M":"broadcastMessage","A":["client","test msg1"]},
    {"H":"ChatHub","M":"broadcastMessage","A":["client","test msg2"]},
    {"H":"ChatHub","M":"broadcastMessage","A":["client","qwerty"]}
  ]
}

Persistent Connection Messages

The protocol used for persistent connection is quite simple. Messages sent to the server are just raw strings. There isn’t any specific format they have to be in. The C# client has a convenience Send() method that takes an object that is supposed to be sent to the server but all this method does is just converting the object to JSon and invoke the Send() overload that takes string. Messages sent to the client are more structured. They are JSon strings with a number of properties. Depending on the purpose of the message different properties can be present in the payload or the message may have no properties (KeepAlive messages). The properties you can find in the message are as follows:

C – message id, present for all non-KeepAlive messages

M – an array containing actual data.

{"C":"d-9B7A6976-B,2|C,2","M":["Welcome!"]}

S – indicates that the transport was initialized (a.k.a. init message)

{"C":"s-0,2CDDE7A|1,23ADE88|2,297B01B|3,3997404|4,33239B5","S":1,"M":[]}

G – groups token – an encrypted string representing group membership

{"C":"d-6CD4082D-B,0|C,2|D,0","G":"92OXaCStiSZGy5K83cEEt8aR2ocER=","M":[]}

T – if the value is 1 the client should transition into the reconnecting state and try to reconnect to the server (i.e. send the reconnect request). The server is sending a message with this property set to 1 if it is being shut down or restarted. Applies to the longPolling transport only.

L – the delay between re-establishing poll connections. Applies to the longPolling transport only. Used only by the JavaScript client. Configurable on the server by setting the IConfigurationManager.LongPollDelay property.

{"C":"d-E9D15DD8-B,4|C,0|D,0","L":2000,
  "M":[{"H":"ChatHub","M":"broadcastMessage","A":["C++","msg"]}]}

KeepAlive messages
KeepAlive messages are empty object JSon strings (i.e. {}) and can be used by SignalR clients to detect network problems. SignalR server will send keep alive messages at the configured time interval. If the client has not received any message (including a keep alive message) from the server within a certain period of time it will try to restart the connection. Note that not all the clients currently support restarting connection based on network activity (most notably it is not supported by the SignalR C++ Client). Sending keep alive messages by the server can be turned off by setting the KeepAlive server configuration property to null.

Hubs Messages

Hubs API makes it possible to invoke server methods from the client and client methods from the server. The protocol used for persistent connection is not rich enough to allow expressing RPC (remote procedure call) semantics. It does not mean however that the protocol used for hub connections is completely different from the protocol used for persistent connections. Rather, the protocol used for hub connections is mostly an extension of the protocol for persistent connections.
When a client invokes a server method it no longer sends a free-flow string as it was for persistent connections. Instead it sends a JSon string containing all necessary information needed to invoke the method. Here is a sample message a client would send to invoke a server method:

{"H":"chathub","M":"Send","A":["JS Client","Test message"],"I":0,
  "S":{"customProperty" : "abc"}}

The payload has the following properties:
I – invocation identifier – allows to match up responses with requests
H – the name of the hub
M – the name of the method
A – arguments (an array, can be empty if the method does not have any parameters)
S – state – a dictionary containing additional custom data (optional, currently not supported by the C++ client)

The message sent from the server to the client can be one of the following:

  • a result of a server method call
  • an invocation of a client method
  • a progress message

Server Side Hub Method Invocation Result

When a server method is invoked the server returns a confirmation that the invocation has completed by sending the invocation id to the client and – if the method returned a value – the return value, or – if invoking the method failed – the error. There are two kinds of errors – general errors and a hub errors. In case of a general error the response contains only an error message and the error is turned by the client into a generic exception – the .NET client throws an InvalidOperationException, the C++ client throws a std::runtime_error and the JavaScript client creates an Error with the Exception as the source. Hub errors contain a boolean property set to true to indicate that they are hub errors and they may contain some additional error data. Hub errors are turned into a HubException by the .NET Client, a signalr::hub_exception by the C++ client and the JavaScript client creates an Error with source set to HubException. Here are sample results of a server method call:

{"I":"0"}

A server void method whose invocation identifier was "0" completed successfully.

"{"I":"0", "R":42}

A server method returning a number whose invocation identifier was "0" completed successfully and returned the value 42.

{"I":"0", "E":"Error occurred"}

A server method whose invocation identifier was "0" failed with the error "Error occurred"

{"I":"0","E":"Hub error occurred", "H":true, "D":{"ErrorNumber":42}}

A server method whose invocation identifier was "0" failed with the hub error "Hub error occurred" and sent some additional error data.

Here is the full list of properties that can be present in the result of server method invocation:

I – invocation Id (always present)
R – the value returned by the server method (present if the method is not void)
E – error message
Htrue if this is a hub error
D – an object containing additional error data (can only be present for hub errors)
T – stack trace (if detailed error reporting (i.e. the HubConfiguration.EnableDetailedErrors property) is turned on on the server). Note that none of the clients currently propagate the stack trace to the user but if tracing is turned on it will be logged with the message
S – state – a dictionary containing additional custom data (optional, currently not supported by the C++ client)

Client Side Hub Method Invocation

To invoke a client method the server extends the protocol used for persistent connections. The difference is that instead of sending a free flow text in the message portion of the message the server sends a JSon string that contains all the details needed to invoke the method (like the hub and method names and arguments). Here is an example of a message sent by the server to invoke a hub method on the client:

{"C":"d- F430FB19", "M":[{"H":"my_hub", "M":"broadcast", "A":["Hi!", 1]}] }

As you can see the “envelope” in form of message id or message property is the same as for persistent connections. The interesting part from the hub point of view is the value of the M property:

{"H":"my_hub", "M":"broadcast", "A":["Hi!", 1]}

This structure is quite similar to what the client is using to invoke a server hub method (except there is no invocation id since the server does not expect any response to this message).
H – the name of the hub
M – the name of the hub method
A – arguments (an array, can be empty if the method does not have any parameters)
S – state – a dictionary containing additional custom data (optional, currently not supported (ignored) by the C++ client)

Progress Message

The last kind of message sent from the server to the client is a progress message. When a server method is a long running method the server can send the information about the progress of execution of the method to the client. Similarly to the client method invocation the progress information is embedded in the message portion of a persistent connection message. The entire message looks like this:

{"C":"d-5E80A020-A,1|B,0|C,15|D,0", M:[{I:"P|1", "P":{"I":"0", "D":1}}] }

but the progress message itself looks like this:

{I:"P|1", "P":{"I":"0", "D":1}}

The structure containing information about progress contains two properties:
I – kind of an invocation id but prepended with "P|". Used only by older clients.
P – an object containing actual information about progress

The object containing “real” progress information has the following properties:
I – invocation id that tells which invocation this progress message applies to
D – progress data returned by the method

Note that there might be multiple progress messages sent to the client before the server sends the actual result of the invoked method.

Recent Protocol Revisions

  • 1.4 – introduction of the start request
  • 1.5 – requests can now be sent using the POST method. This helps avoid a memory leak when using the longPolling transport in Chrome and IE browsers (bug 2953). Only used by the JS client when with the longPolling transport. Note that the only properties the server checks the request body for are the groupsToken and the messageId

That’s pretty much it. The SignalR protocol is not very complex but the little caveats and exceptions may make the implementation a bit troublesome.

C++ Async Development (not only for) for C# Developers Part IV: Exception handling

Last time we were able to run some tasks asynchronously. Things worked great and it was pretty straightforward. However real life scenarios are not as simple as the ones I used in the previous post. For instance networking environment can be quite hostile – the server you are connecting to may go down for any reason, the connection might get dropped at any time, etc. Any of this condition will typically result in an exception which, if unhandled, will crash your process and bring down your application. C++ async is no different – you can easily check it for yourself by running this code:

pplx::task_from_result()
    .then([]()
    { 
        throw std::exception("test exception"); }
    ).get();

(the “for C# Developers” part – Note that in the .NET Framework 4 UnobservedTaskExceptions would terminate the application. It was later changed in .NET Framework 4.5 where UnobservedTaskExceptions no longer terminate applications (it is still recommended to observe and handle exceptions though). The behavior in C++ async with Casablanca is more in line with the .NET Framework 4 – any unobserved exception will eventually lead to a crash).
You might think that the way to handle this exception is just to wrap this call in a try…catch block. This would work if you blocked (e.g. used .get()) since you would be executing the code synchronously. However if you start a task, it will run on a different thread and the exception will be thrown on this new thread so, not where you are trying to catch it. As a result your app would still crash. The idea is that you have to observe exceptions not where tasks are started but where they are completed (i.e. where you call .get() or .wait()). Using a continuation for exception handling seems like a great choice because continuations run only after the previous task has completed. So, let’s build on the previous code snippet and add a continuation that handles the exception. It would look like this (I am still using .get() at the very end but it is only to prevent the main thread from exiting and terminating the other thread):

pplx::task_from_result()
    .then([]()
    { 
        throw std::exception("test exception"); }
    )
    .then([](pplx::task<void> previous_task)
    {
        try
        {
            previous_task.get();
        }
        catch (const std::exception& e)
        {
            std::cout << e.what() << std::endl;
        }
    }).get();

One very important thing to notice is that the continuation I added takes pplx::task<void> as the parameter. This is a so called “task based continuation” and is different from continuations we have seen so far which took the value returned by the previous task (or did not take any parameter if the previous task was void). The continuations we had worked with before were “value based continuations” (we will come back to value based continuations in the context of exception handling shortly). With task based continuations you don’t receive the result from the previous task but the task itself. Now you are in the business of retrieving the result yielded by this task. As we know from the previous post the way to get the result returned by a task is to call .get() or .wait(). Since exceptions are in a sense also results of executing a task if the task threw calling .get()/.wati() will result in rethrowing this exception. We can then catch it and handle and thus make the exception “observed” so the process will no longer crash. When I first came across this pattern it puzzled me a bit. I thought .get() is blocking and I use async to avoid blocking so isn’t it a contradiction?’. But then I realized that we are already in a continuation so the task has already been completed and .get() is no longer blocking – it merely allows to get the result of the previous task (be it a value or an exception).
Coming back to value based continuations – let’s see what would happen if we added a value based continuation after the continuation that throws but before the continuation that handles this exception – just like this:

pplx::task_from_result()
    .then([]()
    { 
        throw std::exception("test exception"); }
    )
    .then([]()
    {
        std::cout << “calculating The Answer…” << std::endl;
        return 42;
    })
    .then([](pplx::task<int> previous_task)
    {
        try
        {
            std::cout << previous_task.get() << std::endl;
        }
        catch (const std::exception& e)
        {
            std::cout << e.what() << std::endl;
        }
    }).get();

(One thing to notice – since the continuation we inserted now returns int (or actually pplx::task<int> – there are some pretty clever C++ tricks used to allow returning just a value or (just throwing an exception) even though the .then() function ultimately returns a pplx::task<T> or pplx::task<void>) the task valued continuation now has to take a parameter of pplx::task<int> type instead of pplx::task<void> type). If you run the above code the result will be exactly as from the previous example. Why? When a task throws an exception all value based continuations are skipped until a task based continuation is encountered which will be invoked and will have a chance to handle the exception. This is a big and a very important difference between task based and value based continuations. This also makes a lot of sense – something bad happened and in value based continuations you have no way of knowing that it did or what it was since you have no access to the exception. There is also nothing to pass if the previous task would return something were there not for the exception. As a result executing value based continuations if nothing has happened would be plainly wrong.
If you have played a little bit with Casablanca or have seen some more advanced code that is using Casablanca you might have come across the pplx::task_from_exception() function. You might have been wondering why it is needed if you can just throw an exception. Typically tasks are executed on multiple threads and it is very common that an exception thrown in one thread is being observed on a different thread. As a result it is impossible to just unwind the stack when trying to find an exception handler. Rather, the exception has to be saved (which will make the task faulted) and then is re-thrown when the user calls .get() or .wait() to get the result. If you use the .then() function all this happens behind the scenes – you throw an exception from a continuation and the .then() function will catch it and turn into a faulted task which will be passed to the next available task based continuation. However consider the following function:

pplx::task<int> exception_test(bool should_throw)
{
    if (should_throw)
    {
        throw std::exception("bogus exception");
    }

    return pplx::task_from_result<int>(42);
}

If you pass true it will throw an exception, otherwise it will return a value. Note that I cannot just return 42; here because the return type of the function is pplx::task<int> and not int and there is no Casablanca magic involved which could turn my 42 into a task. Therefore I have to use pplx::task_from_result<int>() to return a completed task with the result. Now, let’s try to build a task based continuation that observes the exception we throw – something like this:

exception_test(true)
    .then([](pplx::task<int> previous_task)
    {
        try
        {
            previous_task.get();
        }
        catch (const std::exception& e)
        {
            std::cout << "exception: " << e.what() << std::endl;
        }
    }).get();

If you run this code it will crash. The reason is simple – we just synchronously throw from the exception_test function and no one is handling this exception. Note that we are not able to handle this exception in the continuation since it is never invoked – because there was no handler the exception crashed the application before it got to the .then(). To fix this the exception_test function needs to be modified as follows:

pplx::task<int> exception_test(bool should_throw)
{
    if (should_throw)
    {
        return pplx::task_from_exception<int>(std::exception("bogus exception"));
    }

    return pplx::task_from_result<int>(42);
}

Now instead of throwing an exception we return a faulted task. This task is then passed to our task based continuation which can now handle the exception.

That’s it for today. Next time we will look at cancellation.

C++ Async Development (not only for) for C# Developers Part III: Introduction to C++ async

Now that we know a bit about lambda functions in C++ we finally can take a look at C++ async programming with the C++ Rest SDK (a.k.a. cpprestsdk a.k.a. Casablanca). C++ Rest SDK is cross platform but thanks to the NuGet support for native packages using it with Visual Studio is extremely easy. If you would like to use it on non-Windows platforms in majority of cases you will have to compile the code yourself (note to Raspbery PI fans – I tried compiling it on my Raspberry Pi but unfortunately compilation failed due to a gcc internal compiler error). With Visual Studio you can create a new Win32 Console Application, right click on the project in the Solution Explorer and click the “Manage NuGet Packages” option. In the Manage NuGet Packages window type “cppresdk” in the in the search box and install the C++ REST SDK: C++ Rest SDK NuGet This is it – you are now ready to write asynchronous programs in C++. If you prefer, you can also install the package from the Package Manager Console with the Install-Package cpprestsdk command. Once the C++ Rest SDK is installed we can start playing with it. Let’s start with something really simple like displaying a textual progress bar. We will create a task that will loop 10 times. In each iteration it will sleep for a short period of time and then write an asterisk to the console. To show that it works asynchronously we will have a similar loop in the main thread where we similarly will wait and write a different character to the console. I expect the characters to be mixed which would prove that the progress task is actually running on a different thread. Here is the code:

#include "stdafx.h"
#include "pplx\pplxtasks.h"
#include <iostream>

int main()
{
    pplx::task<void>([]()
    {
        for (int i = 0; i < 10; i++)
        {
            pplx::wait(200);
            std::cout << "*";
        };

        std::cout << std::endl << "Completed" << std::endl;
    });

    for (int i = 0; i < 10; i++)
    {
        pplx::wait(300);
        std::cout << "#";
    }

    std::cout << std::endl;

    return 0;
}

And here is the result I got:

*#**#*#**#*#**#*
Completed
####
Press any key to continue . . .

From the output it appears that everything went as planned. Let’s take a closer look at what is really happening in the program. pplx::task<void> creates a new task that is scheduled to be run on a different thread. Once the task is created the loop writing # characters is being executed. In the meantime the scheduled task is being picked up and executed on a different thread. Note that the loop in the main thread will take longer to execute that the loop in the task. What would happen if the main thread did not live long enough – e.g. we would not have the loop in the main thread that runs longer than the task? You can easily check this by decreasing the timeout but basically the main thread would exit and would terminate all other threads – including the one the task is running on so the task would be killed. You can, however, block a thread and wait until a task is completed by using the .get() or the .wait() method. In general you want to avoid blocking threads but sometimes it can be helpful. (Note that this is in contrast to the managed world (e.g. C#) where the expectation is that apps using async features are async inside out and blocking oftentimes leads to bad things like deadlocks. The built-in support for async like async/await keywords and exception handling in async methods help tremendously meet this expectation.) Here is a new version of the program from above which is now using the .get() method to block execution of the main funcion until the task completes:

int main()
{
    auto task = pplx::task<void>([]()
    {
        for (int i = 0; i < 10; i++)
        {
            pplx::wait(200);
            std::cout << "*";
        };

        std::cout << std::endl << "Completed" << std::endl;
    });

    std::cout << "waiting for task to complete" << std::endl;
    task.get();
    std::cout << "task completed" << std::endl;

    return 0;
}

The program should output this:

waiting for task to complete
**********
Completed
task completed
Press any key to continue . . .

The output shows that .get() did the job – once the .get() method was reached the main thread was blocked waiting for the task to complete and then when the task finished the main thread was unblocked. This is great but can we take it to the next level – for instance – can we return a value from the task? This is actually quite easy – to do that you just need to return the value from the task. In our case we can return how much time (in nanoseconds) our task took to execute. We will use types from the std::chrono namespace so don’t forget to add #include <chrono> – I am leaving includes out for brevity.

int main()
{
    auto task = pplx::task<std::chrono::nanoseconds>([]()
    {
        auto start = std::chrono::steady_clock::now();

        for (int i = 0; i < 10; i++)
        {
            pplx::wait(200);
            std::cout << "*";
        };
        
        std::cout << std::endl << "Completed" << std::endl;

        return std::chrono::steady_clock::now() - start;
    });

    std::cout << "waiting for task to complete" << std::endl;
    auto task_duration = task.get();
    std::cout << "task completed in " << task_duration.count() << " ns." << std::endl;

    return 0;
}

If you look close at the code you will notice that I modified the type of the task – instead of being pplx::task<void> it is now pplx::task<std::chrono::nanoseconds> – and modified the lambda body so that it now returns a value. As a result the .get() method is no longer void – it now returns a value of the std::chrono::nanoseconds type which is actually the value we returned from our task. For completness this is what I got on my screen when I ran this program:

waiting for task to complete
**********
Completed
task completed in 2003210000 ns.
Press any key to continue . . .

While being able to run a task asynchronously is powerful oftentimes you would want to run another task that runs after a task has completed and that uses the result from the previous task. Both tasks should run asynchronously and should not require blocking the main thread to pass the result from one task to the other task. For instance you are working with a service that returns a list of ids and names in one request but also can return details for a given id in a different request. If you want to get details for a given name you would need to first send a request to get ids for names and then send another request to get the details for the id. From the perspective of the main thread you just want to say: “give me details for this name (and I don’t care how you do it)”. This can be achieved with task chaining. You chain tasks using the .then() method. In the simplest form it just takes the value returned by the previous task as the parameter. For example, in our case, if we wanted to get the result in milliseconds and not nanoseconds we could write a continuation that does the conversion (yes, there is no real benefit of doing such a simple conversion in a continuation especially that it isn’t an asynchronous operation and can easily be done in the first continuation or in the main thread but imagine you need to connect to a service that does the conversion for you) like this:

int main()
{
    auto task = pplx::task<std::chrono::nanoseconds>([]()
    {
        auto start = std::chrono::steady_clock::now();

        for (int i = 0; i < 10; i++)
        {
            pplx::wait(200);
            std::cout << "*";
        };

        std::cout << std::endl << "Completed" << std::endl;

        return std::chrono::steady_clock::now() - start;
    })
    .then([](std::chrono::nanoseconds duration)
    {
        std::cout << "task duration in ns: " << duration.count() << std::endl;
        return duration.count() / 1000000;
    });

    std::cout << "waiting for task to complete" << std::endl;
    auto task_duration = task.get();
    std::cout << "task completed in " << task_duration << " ms." << std::endl;

    return 0;
}

Running the program results in the following output:

waiting for task to complete
**********
Completed
task duration in ns: 2004372000
task completed in 2004 ms.
Press any key to continue . . .

That’s pretty much it for today. Next time we will look at different types of continuations, exception handling and possibly cancellation.

Arduino and the TM1637 4-digit seven-segment display

In one of my Arduino projects I needed to show some numbers. Luckily, a 4 digit display lain around on my desk. Because it had a built-in driver which would save me from all the hassle with shift registers it looked like a perfect fit. I checked the chip the display was using and it was labeled “TM1637”. I was already familiar with the TM1638 (for more details see my recent post about using a TM1638 based board with Arduino) chip so I thought making the TM1637 work should be easy. Unfortunately, while there are some similarities between the chips getting the TM1637 to work took me longer than I had expected. When I finally aligned all the moving pieces I decided to create a standalone sample which will hopefully be helpful to other people playing with TM1637 based displays. To make the sample a good demo I just took my Nokia LCD clock sample, replaced the Nokia LCD display with the TM1637 display and updated the code accordingly and ended up with a TM1637 clock:

TM1637 clock
TM1637 clock

Let’s get started from taking a closer look at the TM1637 display. The TM1637 display has four pins VCC, GND, DIO, CLK. Similarly to the TM1638 the TM1637 uses a protocol to communicate with the display. While commands themselves are very similar to the ones used by the TM1638 board sending the data is a little different. The display does not have the STB pin the TM1638 board had so separating commands and arguments works differently. A start signal needs to be sent before sending a command to the display. Once the command has been sent a stop signal needs to be used. If a command has arguments another start signal needs to be sent and then after all arguments have been sent the stop signal needs to be used. The start signal is just setting the CLK and DIO pins to HIGH and then setting them to LOW. The stop signal is setting the CLK and DIO pins to LOW and then to HIGH. The CLK pin should not change the state more frequently than 250kHz so I added a little delay between state changes. Here is how my corresponding start and stop functions look like:

void start(void) 
{ 
    digitalWrite(clock,HIGH);//send start signal to TM1637 
    digitalWrite(data,HIGH); 
    delayMicroseconds(5); 
 
    digitalWrite(data,LOW); 
    digitalWrite(clock,LOW); 
    delayMicroseconds(5); 
} 
 
void stop(void) 
{ 
    digitalWrite(clock,LOW); 
    digitalWrite(data,LOW); 
    delayMicroseconds(5); 

    digitalWrite(clock,HIGH); 
    digitalWrite(data,HIGH); 
    delayMicroseconds(5); 
} 

The display has three commands:

  • initialize the display and set brightness
  • display value at a given position
  • display values starting from a given position

The first command just initializes the display and sets the brightness. This is done by sending the %1000abbb value where the a bit activates (if set to 1) or deactivates (if set to 0) the display and the bbb bits control the brightness (with 000 being the darkest and 111 being the brightest).
The second command allows controlling a single digit of the display. It requires sending 3 bytes to the display: 0x44 %110000aa X where the aa bits in the second byte are used to select the position of the digit to control while X is the value to be displayed encoded in the standard 7 segment coding (as explained here).
Finally, the last command is used to control multiple digits and can consists of up to 6 bytes. Typically you want use all the digits in which case you send the following bytes to the display – 0x40 0xC0 W X Y Z. The first byte is the command identifier the second byte tells the display to start at the first position and W X Y Z are the values to be displayed on subsequent positions (again in the standard 7 segment encoding).
Here are is a short summary of commands:

START (0x88|%00000aaa) STOP initialize and set the brightness
START 0x44 STOP START (0xC0|%000000aa) X STOP display value X at position %000000aa
START 0x40 STOP START 0xC0 W X Y Z STOP display values W X Y Z starting from position 0

When sending data to the display timing is the tricky part. Apparently (if I understood the machine translation of the data sheet which is in Chinese correctly), the CLK pin should not change the state more frequently than 250kHz. This means that I could not use the Arduino shiftOut function because it does not allow to provide the delay after setting the DIO pin. Instead I had to come up with my own function (I called it writeValue) that emulates the shiftOut function but which uses a delay after setting the DIO pin. (Yes, it did made me think that my other projects may have some kind of issue due to writing data too fast but, hey, they worked!). Another thing is that the chip is acknowledging it received data successfully by setting the DIO pin to HIGH after each byte of data has been written. I have never seen it fail and am not even sure what I would be supposed to do if it did. Probably in my little projects this does not matter too much – I am constantly writing to the display so I hope that a subsequent write will succeed and therefore even though the writeValue function returns a result I am ignoring it. The writeValue function looks as follows:

bool writeValue(uint8_t value) 
{ 
    for(uint8_t i = 0; i < 8; i++) 
    { 
        digitalWrite(clock, LOW); 
        delayMicroseconds(5); 
        digitalWrite(data, (value & (1 << i)) >> i); 
        delayMicroseconds(5); 
        digitalWrite(clock, HIGH); 
        delayMicroseconds(5); 
    } 
 
    // wait for ACK 
    digitalWrite(clock,LOW); 
    delayMicroseconds(5); 
 
    pinMode(data,INPUT); 
 
    digitalWrite(clock,HIGH); 
    delayMicroseconds(5); 
 
    bool ack = digitalRead(data) == 0; 
    
    pinMode(data,OUTPUT); 

    return ack; 
}

Based on this information I created a TM1637 clock as shown on the photo above. I connected a TM1637 display to Arduino as follows:

Arduino              TM1637 display
PIN #7 ------------------ CLK
PIN #8 ------------------ DIO
3.3V   ------------------ VCC
GND    ------------------ GND

The code is on github - clone it and try for yourself.

Using a TM1638 based board with Arduino

At long last I set out to work on one of my Arduino projects when I realized that I didn’t have any 4-digit 7 segment LED display at home. Since it was quite important part of the project I went to ebay and started looking for something when I found this:
TM1638 module
This is an “8-Bit LED 8-Bit Digital Tube 8-Bit Key TM1638”. It seemed to be a very good fit for my project since it not only had the display but it also had some buttons – something I needed too. In addition it had only three control lines which would simplify things a lot by sparing me from dealing with shift registers on my own – something I would have to do had I used the cheapest 7 segment LED display. When I got the board I got baffled a little bit. It was just a piece of hardware without any documentation. I deciphered the symbol on the chip and went for a quest to find some information about how it worked. I found a data sheet but it was mostly in Chinese. Unfortunately 我的中文不好, so I only skimmed it and continued looking. I quickly found that there is a library I could use. However I did want to learn how the thing I bought actually worked, so I spent some time more time looking for more information about the board. Finally, I found this page which turned out to be the most helpful and allowed me to start experimenting.
As I already mentioned the board has just 3 control pins plus power and ground. The control pins are strobe, clock and data. The strobe and clock pins are only OUTPUT while the data pin can be both OUTPUT and INPUT. The strobe pin is used when sending data to the board – you set the strobe pin to LOW before you start sending data – one or more bytes – and then set the strobe pin back to HIGH. Note that there is just one data pin which means the data is being sent 1 bit at a time. This is where the clock pin comes into play. When sending data you set the clock pin to LOW then you set the data pin and set the clock pin back to HIGH to commit the bit value. You are probably already familiar with this pattern (if not take a look at this post) – it is the standard way of sending data with shift registers and therefore we can just use the standard shiftOut function to send 8 bits of data with just one line of code.
The data sent to the board follow a protocol where the first byte tells the board what we want to do (I call it ‘command’) and is followed by zero or more bytes that are arguments for the selected function. Arguments are sent separately (i.e. the strobe pin needs to be set to HIGH after sending the command and again to LOW before sending arguments). The board has 4 functions:

  • activate/deactivate board and initialize display
  • write a byte at specific address
  • write bytes starting from specific address
  • read buttons

To activate the board and set the display brightness we use the 1000abbb (0x8?) command where the bit marked as a is used to activate/deactivate the board and bits marked as bbb are used to set the brightness of the display. For example to activate the board and set the brightness of the display to the maximum value we need to send 0x8f. This function does not have any arguments.
To write a byte at specific address we send the 010000100 (0x44) command followed by the address in the form of 1100aaaa (aaaa bits denote the location we want to write to) followed by the value. For example to write the value 0x45 at address 0x0a we would have to send the following sequence of bytes: 0x44 0xca 0x45.
If we want to write values at consecutive addresses (very helpful to reset the board) we would send 01000000 (0x40) followed by the starting address (again in the form of 1100aaaa) followed by the values we want to write. For instance if we send 0x40 0xc0 0x00 0x01 0x02 0 would be written at address 0, 1 would be written at address 1 and 2 would be written at address 2. Note that we have 4 bits to select the address which means there are sixteen locations that can be written to. If you continue writing after reaching the address 0x0f it will wrap and you will start again from address 0x00.
To read buttons we send the 010000010 (0x42) command, set the data pin as INPUT and read 4 bytes containing button status.

Command Arguments Description
0x8? (1000abbb) (none) activate board (bit a), set brightness (bits b)
0x44 (01000100) 0xc? 0x?? write value 0x?? at location 0xc? (single address mode)
0x40 (01000000) 0xc? 0x?? 0x?? 0x?? write values 0x?? starting from location 0xc? (address auto increment mode)
0x42 (01000010) N/A read buttons

Now we know we can write values to one of the 16 locations. This is the way we turn LEDs on and control the display. The board has two 4 digit 7 segment LEDs displays and 8 LEDs. Each of them has a dedicated address to which a value needs to be written to control the corresponding item. For instance if to turn on the first LED we would write 1 at address 0x01. Below is a list of locations with short explanations.

Address Description
0x00 (0000) display #1
0x01 (0001) LED #1 00000001 – red, 00000010 – green
0x02 (0010) display #2
0x03 (0011) LED #2 00000001 – red, 00000010 – green
0x04 (0100) display #3
0x05 (0101) LED #3 00000001 – red, 00000010 – green
0x06 (0110) display #4
0x07 (0111) LED #4 00000001 – red, 00000010 – green
0x08 (1000) display #5
0x09 (2001) LED #5 00000001 – red, 00000010 – green
0x0a (1010) display #6
0x0b (1011) LED #6 00000001 – red, 00000010 – green
0x0c (1100) display #7
0x0d (1101) LED #7 00000001 – red, 00000010 – green
0x0e (1110) display #8
0x0f (1111) LED #8 00000001 – red, 00000010 – green

(You might have noticed that according to the chart LEDs can be either red or green. I am cheap so I got the cheapest board I could find on ebay and it turned out it had only red LEDs so I was not able to test the green color.)

We now have all the information needed to breathe some life into the board. First we need to connect the TM1638 based board to our Arduino board. This is how I did it:

Arduino              TM1638 based board
3.3V   ------------------ VCC
GND    ------------------ GND
PIN #7 ------------------ STB
PIN #8 ------------------ DIO
PIN #9 ------------------ CLK

The setup function needs to activate and reset the board. For readability I created a helper function for sending commands and a separate function for setup. Here is how the code to setup the board looks like:

const int strobe = 7;
const int clock = 9;
const int data = 8;

void sendCommand(uint8_t value)
{
  digitalWrite(strobe, LOW);
  shiftOut(data, clock, LSBFIRST, value);
  digitalWrite(strobe, HIGH);
}

void reset()
{
  sendCommand(0x40); // set auto increment mode
  digitalWrite(strobe, LOW);
  shiftOut(data, clock, LSBFIRST, 0xc0);   // set starting address to 0
  for(uint8_t i = 0; i < 16; i++)
  {
    shiftOut(data, clock, LSBFIRST, 0x00);
  }
  digitalWrite(strobe, HIGH);
}

void setup()
{
  pinMode(strobe, OUTPUT);
  pinMode(clock, OUTPUT);
  pinMode(data, OUTPUT);

  sendCommand(0x8f);  // activate and set brightness to max
  reset();
}

Here is how this works. The code starts executing from the setup function. First we set pins 7, 8, 9 as output pins. Next we activate the board and set the brightness to the maximum value by sending 0x8f. Finally we reset the board by clearing all the memory locations. We do it by setting the board to the address auto increment mode (0x40), selecting 0 as the starting address (0xc0) and sending 0 sixteen times. Now that the board is ready to work with let’s display something. An easy thing to display will be 8. in the first and last digit position on the display and light the 3rd and 6th LED. To do that we will use the single address mode since the locations we are going to write to are not consecutive. Our loop function that does this looks as follows:

void loop()
{
  sendCommand(0x44);  // set single address

  digitalWrite(strobe, LOW);
  shiftOut(data, clock, LSBFIRST, 0xc0); // 1st digit
  shiftOut(data, clock, LSBFIRST, 0xff);
  digitalWrite(strobe, HIGH);

  digitalWrite(strobe, LOW);
  shiftOut(data, clock, LSBFIRST, 0xc5); // 3rd LED
  shiftOut(data, clock, LSBFIRST, 0x01);
  digitalWrite(strobe, HIGH);

  digitalWrite(strobe, LOW);
  shiftOut(data, clock, LSBFIRST, 0xcb); // 3rd LED
  shiftOut(data, clock, LSBFIRST, 0x01);
  digitalWrite(strobe, HIGH);

  digitalWrite(strobe, LOW);
  shiftOut(data, clock, LSBFIRST, 0xce); // last digit
  shiftOut(data, clock, LSBFIRST, 0xff);
  digitalWrite(strobe, HIGH);
}

You can find the entire sample in the repo on github.
Displaying 8. is cool but it would be even cooler if we knew the relation between the value sent to the board and what will be shown. The board is using the standard 7 segment coding, so the value sent to the board is a byte with bits coded as follows: [DP]GFEDCBA. Each bit will light one segment as per the image below:
7Seg
So, for instance if you wanted to display A you would have to write 0x77 at the corresponding location.

Now we know how to control LEDs and the display. But there is one more thing the board offers – buttons. Reading what buttons are depressed works a little bit different from what we have seen so far. First we need to send the 0x42 command, then we set the data pin as an input pin. Finally we need to read 4 bytes from the board (bit by bit). The first byte contains status for buttons S1 (bit 1) and S5 (bit 4), the second byte contains status for buttons S2 (bit 2) and S6 (bit 5) and so on. If we | (i.e. logical `or`) all the bytes we will end up having a byte where each bit corresponds to one button – if a bit set to one means that the corresponding button is depressed. Here is a little program (I omitted the setup – it is identical as in the first sample) where the board will light an LED over a button that is pressed.

uint8_t readButtons(void)
{
  uint8_t buttons = 0;
  digitalWrite(strobe, LOW);
  shiftOut(data, clock, LSBFIRST, 0x42);

  pinMode(data, INPUT);

  for (uint8_t i = 0; i < 4; i++)
  {
    uint8_t v = shiftIn(data, clock, LSBFIRST) << i;
    buttons |= v;
  }

  pinMode(data, OUTPUT);
  digitalWrite(strobe, HIGH);
  return buttons;
}

void setLed(uint8_t value, uint8_t position)
{
  pinMode(data, OUTPUT);

  sendCommand(0x44);
  digitalWrite(strobe, LOW);
  shiftOut(data, clock, LSBFIRST, 0xC1 + (position << 1));
  shiftOut(data, clock, LSBFIRST, value);
  digitalWrite(strobe, HIGH);
}

void loop()
{
  uint8_t buttons = readButtons();

  for(uint8_t position = 0; position < 8; position++)
  {
    uint8_t mask = 0x1 << position;

    setLed(buttons & mask ? 1 : 0, position);
  }
}

Again, you can find the entire example in my github repo.

These are the basic building blocks and you use them to build something more useful. Here is a video of a little demo project I built:

The code for this demo is also on github.

Enjoy.