Part 2: Send a message from a button service
1. Introduction
There are two ways to receive a message, but what about sending one?
Don't worry, we will see how to do it step by step.
2. Set up your hardware
Begin by setting up the MCU pins for your button in the file button.c:
- Arduino
- Nucleo
#include <Arduino.h>
#include "button.h"
/*******************************************************************************
* Definitions
******************************************************************************/
// the new line to copy and paste
#define BTN_PIN 8
Set the pin as an input:
void Button_Init(void)
{
revision_t revision = {1, 0, 0};
button_service = Luos_CreateService(0, STATE_TYPE, "button", revision);
// the new line to copy and paste
pinMode(BTN_PIN, INPUT);
}
For Nucleo boards, the initialization of your pins as an input is done in the main file (C) inside the following function:
MX_GPIO_Init();
You must only remember the names of the pins: BTNGPIO_Port and BTN_Pin (see _main.h).
Now everything is ready to send back the button's value in a message.
3. Send back the button's value
By learning how to catch messages from the previous page of this tutorial, we already know that they contain some interesting information allowing you to understand the meaning of the transmitted data.
Any message contains two main parts:
The Data is the actual transmitted data.
The Header contains some contextual information allowing the receiver to get the purpose of the Data.
For more information about the messages, you can refer to the related documentation page.
To send a message, you will need to fill in some header information regarding the target and the data of you message:
Message target
In this button service, we want to reply to a request coming from another service. So we will target this specific service and be sure that it gets the answer.
To do that, we will need to configure the following information:
target_mode
asIDACK
⇒ because we target only one service and want to be sure it gets the messagetarget
as the requested source message ⇒ because we want to target the service sending the request.
Message data meaning
To send the message, we also need to explain the meaning of the data.
In this button service, we want to send an IO_STATE
, so data size
will be a byte because it just needs to send 1
or 0
.
To do that, we will need to configure the following information:
cmd
asIO_STATE
⇒ to define the type of transmited datasize
as1
⇒ because only 1 byte is sentdata
as the button's state ⇒ this will be the actual data.
On the message request filtering you previously made, we did not look at the message size. This is because a request does not need any data. most of the time, a message where size = 0
is equivalent to a “get” command. If size != 0
, it means that you want to set something by sending a value.
4. Send back the button's value
After filling in all this information, we are now able to send it using the Luos_SendMsg
function.
This function needs to know which service wants to send this message, so you will need to provide it with your service and the message you want to send in arguments.
Luos_SendMsg
function returns an error_return_t
information allowing you to know if the message transmission FAILED or SUCCEED.
error_return_t Luos_SendMsg(service_t *service, msg_t *msg)
The only reason why this function sends back a FAILED status is because there is not enough RAM in your device.
Write it in the code
Let's fill in the information of the structure:
- Arduino
- Nucleo
void Button_Loop(void)
{
msg_t* msg;
while (Luos_ReadMsg(button_service, &msg) == SUCCEED)
{
if ((msg->header.cmd == IO_STATE)||(msg->header.cmd == UNKNOW)
{
// the new block to copy and paste
// fill the message infos
msg_t pub_msg;
pub_msg.header.cmd = IO_STATE;
pub_msg.header.target_mode = IDACK;
pub_msg.header.target = msg->header.source;
pub_msg.header.size = sizeof(char); // 1 byte
pub_msg.data[0] = digitalRead(BTN_PIN);
Luos_SendMsg(service, &pub_msg);
}
}
}
void Button_Loop(void)
{
msg_t* msg;
while (Luos_ReadMsg(button_service, &msg) == SUCCEED)
{
if ((msg->header.cmd == IO_STATE)||(msg->header.cmd == UNKNOW)
{
// the new block to copy and paste
// fill the message infos
msg_t pub_msg;
pub_msg.header.cmd = IO_STATE;
pub_msg.header.target_mode = IDACK;
pub_msg.header.target = msg->header.source;
pub_msg.header.size = sizeof(char); // 1 byte
pub_msg.data[0] = HAL_GPIO_ReadPin(BTN_GPIO_Port, BTN_Pin);
Luos_SendMsg(service, &pub_msg);
}
}
}
The STATE button service now returns an IO_STATE value when a service asks for it! Let's see if our service reacts as expected.
5. Test the response
- Compile and upload the project to the board.
- Using the command
pyluos-shell
in a terminal, you should see the following routing table:
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ ╭node 1 /!\ Not certified ┃
┃ │ Type Alias ID ┃
┃ ├> Pipe Pipe 2 ┃
┃ ├> Gate gate 1 ┃
┃ ╰> State button 3 ┃
╔>┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Typing device.button.state
, you should see the pin's value:
In [1]: device.button.state
Out[1]: False
- Arduino
- STM32F072RB Nucleo/STM32F401RE Nucleo/STM32F410RB Nucleo
- STM32G431KB Nucleo/STM32L432KC Nucleo
Typing device.button.state
, you should see the new pin's value:
In [2]: device.button.state
Out[2]: True
6. Exercise: control a LED depending on your button's state
Let's try a small exercise:
Make a LED turn on when the button's state is TRUE and off when it's FALSE.
Add the led package created on the previous tutorial on your board.
Compile and flash your board again.
Type
pyluos-shell
in the terminal again, you should see:┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ ╭node 1 /!\ Not certified ┃
┃ │ Type Alias ID ┃
┃ ├> Pipe Pipe 2 ┃
┃ ├> Gate gate 1 ┃
┃ ├> State button 3 ┃
┃ ╰> State led 4 ┃
╔>┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛Then still in
Pyluos-shell
type:while True :
device.led.state = device.button.stateRun this while-loop and try to push on the button to see the LED turning on and off.