Skip to main content

Part 1: Luos service

1. Environment

Clone or download the training repository.

In PlatformIO IDE, open the folder corresponding to your board in Training/1_First_Service/Work_base from the repository you just cloned or downloaded, and connect the board to your computer with a USB cable.

  1. Check that the right environment is selected, then compile and upload the project to the board (right arrow button in the bottom left of the window).
  2. Using a terminal and the pyluos-shell command, you should see:
      ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ ╭────────────────── Node 1 ────────────────── ┃
┃ │ Type Alias ID ┃
┃ ├> Pipe Pipe 2 ┃
┃ ├> Gate gate 1 ┃
┃ ╰> Unknown blinker 3 ┃
╔>┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

You are ready to go!

2. Create your first service

Now, let's learn how to create your own service. To understand how to do it, we will create a simple LED service that you will be able to use the same way you were using it in the Get started.

tip

At any time, you can check the solution in the folder Training/1_First_Service/Solution, but no cheating! This is only for emergency situation...

A service is an encapsulated feature defining an API and allowing other services to interact with it (see the documentation).

In the case of a simple LED, your service will have one input with the state of the IO that turns the LED on or off:

luos_imgluos_img

In your service code, you will have to give the order to turn the LED on or off depending on the received IO state message. So you need a function to be called when another service sends a message, so that this function deals with the LED; this type of function is called a callback.

You can now declare your LED callback functions at the beginning of the file main file located in the /src/ folder (we will see later how to deal with this function).

info

Throughout this tutorial, you will have to locate the right lines where to copy/paste the new code line(s) we provide to you, into your C file (Nucleo) or your INO file (Arduino). It is explained below with a comment before the lines to locate for this first case, but after that we will let you locate on your own the right place to put the code. Of course we will continue providing the few lines of code situated just before the code you have to add to the files.

// the code to locate:
#include <luos_engine.h>
#include "blinker.h"
#include "pipe.h"
#include "gate.h"

// the new line to copy and paste
void Led_MsgHandler(service_t *service, const msg_t *msg){}

So that your service can be recognized by other services, you will need to expose some information about the features you want to encapsulate into it:

  • The service type, which defines the capabilities and the purpose of your service. You can find the list of all the Luos types in this page. Our new service fits with the STATE_TYPE (boolean 1 or 0).
  • The service alias, which is the default name of your service. Let's name our LED “led”.
  • The service revision, which is the firmware version of your service. Let's say our firmware has the version 1.0.0; we have to make a revision_t variable to send it.

Now that we have everything we need to create our service, we will begin by creating the LED service directly after the initialization of the other services, into the initialization of your code and using the Luos_CreateService function:

void setup()
{
Luos_Init();
Pipe_Init();
Gate_Init();
Blinker_Init();

// the two new lines to copy and paste:
revision_t revision = {1, 0, 0};
Luos_CreateService(Led_MsgHandler, STATE_TYPE, "led", revision);

}

By adding these few lines to your code, you just created your first service. For now, this service doesn't do anything because it is empty, but you still can see and access it by lauching a detection:

  1. Save the file, then compile and upload the project to the board.
  2. Using the command pyluos-shell in a terminal, you should see the following routing table:
    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ ╭────────────────── Node 1 ────────────────── ┃
┃ │ Type Alias ID ┃
┃ ├> State led 2 ┃
┃ ├> Pipe Pipe 3 ┃
┃ ├> Gate gate 1 ┃
┃ ╰> Unknown blinker 4 ┃
╔>┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
gif_khabygif_khaby
tip

The blinker service will be able to find your LED service thanks to the description information you provided. But for now, your LED doesn't react yet to the blinker service commands.

3. Manage the LED on your service

To control the LED, we now need to configure the LED's GPIO pin. To set a value to a GPIO pin on a MCU, you must configurate it as an output; this way we can switch a LED on or off.

Add your PIN configuration next to the service initialization in the same file:

void setup()
{
Luos_Init();
Pipe_Init();
Gate_Init();
Blinker_Init();

revision_t revision = {1, 0, 0};
Luos_CreateService(Led_MsgHandler, STATE_TYPE, "led", revision);

// the new line to copy and paste:
pinMode(LED_BUILTIN, OUTPUT);

}

As we mentioned previously, our LED service needs to react at the reception of an IO state message. To do that, we created earlier a callback function (Led_MsgHandler) called by Luos engine when another service sends a message. So to make the LED service work, we simply have to complete the Led_MsgHandler of our service (see below). This will allow the LED service to use the messages sent by the blinker service.

There are two arguments in the callback function Led_MsgHandler:

  • A service pointer (the LED service): We will not use it in this tutorial, but keep it in mind for later.

  • A message pointer (msg): This is the actual message you receive with all the information the other service wants to give you. You will be able to get the LED state from the data of this message.

To control the LED depending on the message data, you can fill the content of the callback function Led_MsgHandler where you pasted it at the beginning of your main file (Arduino.ino or main.c)

void Led_MsgHandler(service_t *service, const msg_t *msg)
{
// the block to copy and paste:
if (msg->data[0] == 0)
{
digitalWrite(LED_BUILTIN, false);
}
else
{
digitalWrite(LED_BUILTIN, true);
}
}

Compile and upload the project to the board. You should now see the LED blink at the frequency decided by the blinker service.

tip

The blinker service will send a message at the blink frequency you want the LED to change state (ON/OFF). When a message is sent to the LED service, Luos engine will call the message handler so that your code makes the LED react.

gif_drop_the_mic

4. Secure your input data

Thank's to our callback function Led_MsgHandler, our service is now able to react to any input message. However, we don't want it to react to any message, but only to IO state messages. To make sure we use the data appropriately, it is better to use message types that are specific to the data in the command field of the message.

To do that, let's add a filter on the message command:

void Led_MsgHandler(service_t *service, const msg_t *msg)
{
// the new line to copy and paste:
if (msg->header.cmd == IO_STATE)
{
if (msg->data[0] == 0)
{
digitalWrite(LED_BUILTIN, false);
}
else
{
digitalWrite(LED_BUILTIN, true);
}
}
}

Using conditional statements, you will also be able to manage multiple types of input messages so that the services react differently depending on the command they receive.

5. Luos Package

We successfully created a simple service in our main file. But this service doesn't look like the other one already present on your project yet.

If you want to move your service into another project, you will have to directly copy your code from one main program to another. Also, if you want to have multiple services, your code may quickly become a mess!

That is why we recommend creating Luos engine's packages to solve these issues.