Step 5: Create a PolyPacket Service
Now That we have a working device driver, lets create a messaging protocol so we can ask the device for data over the com port.
first we will need to add in some more MrT modules to support polypacket. back out to your projects root directory and open mrt-config again:
cd /path/to/project/root
mrt-config MrT
Select the following modules to import :
Utilities/PolyPacket
Utilities/JSON
Utilities/COBS
Once they are imported, create your protocol template:
poly-make -t my_protocol
There should now be a file named my_protocol.yml
in the root of your project. You can keep this wherever you want, but I find it handy to have it in the root of the project when debugging.
now modify the file to match the my_protocol.yml in the doc folder. For a detailed eplanation of the document reference PolyPacket.wiki/Defining-a-protocol
Once the descriptor is filled out, create a directory for your service, and then generate your service with an application layer:
mkdir MrT/Modules/my_service
poly-make -i my_protocol.yml -a -o MrT/Modules/my_service/
Add “-d doc “ to create an ICD in the doc folder
This will generate 4 files:
my_protocolService.h - header for service, you should never need to edit this
my_protocolService.c - source for service, you should never need to edit this
app_my_protocol.h - header for application layer
app_my_protocol.c - source for application layer, this is where you will fill out packet handlers
First include the service:
main.c:28:
#include "my_service/app_my_protocol.h"
Next intialize the app layer
main.c:118:
/* OR we could use the configuration we created with: HTS_LOAD_CONFIG_AUTO_1HZ(&hts) */
app_my_protocol_init(&huart1); /* initialize the app layer and give it a uart interface */
/* For the UART RX, we are going to use some low level tricks for the stm32, because their HAL layer is not great at receiving
* unkown lengths of data. This will set us up with an interrupt everytime a new byte comes in. its just cleaner and less hassle
*/
UART_MASK_COMPUTATION(&huart1); /* Sets Uart1's internal data mask based on STMCUBE configuration*/
SET_BIT(huart1.Instance->CR1, USART_CR1_PEIE | USART_CR1_RXNEIE); /* Enable the interrupts for STM32 UART receive */
/* USER CODE END 2 */
Then add a call to process our service in the main loop
main.c:118:
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* Every 500 ms see if new data is ready, and read it */
MRT_EVERY( 100, ticks) /* convenience macro for systick timing*/
{
if(hts_check_flag(&hts, &hts.mStatus, ( HTS_STATUS_TEMP_READY | HTS_STATUS_HUM_READY ) )) /*wait until both flags are set */
{
temperature = hts_read_temp(&hts);
humidity = hts_read_humidity(&hts);
}
}
app_my_protocol_process(); /* process our service*/
ticks++;
MRT_DELAY_MS(10);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
Now lets use the uart interrupt to feed our service
stm32l4xx_it.c:26
#include "my_service/app_my_protocol.h"
stm32l4xx_it.c:201
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
/* If RX-Not-Empty flag is set, then we have a byte of data */
if(huart1.Instance->ISR & UART_FLAG_RXNE)
{
uint8_t data = (uint8_t)(huart1.Instance->RDR & (uint8_t)huart1.Mask); /* Mask Off Data */
mp_service_feed(0, &data ,1); /* feed the byte to our service */
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
Since we are using the interrupt we can disable the uart_read in our application layer:
app_my_protocol.c:66 - comment out iface0_read()
void app_my_protocol_process()
{
/* read in new data from iface 0*/
// iface0_read();
/* process the actual service */
mp_service_process();
}
Before we add anything else, lets test our service. Find the com port that the device is on in device manager. in my case it is COM3
for WSL, COM ports are mapped to /dev/ttyS<Port Number>
open the poly-packet interpretter:
poly-packet -i my_protocol.yml
inside of poly-packet connect over serial with a baud of 115200
connect serial:/dev/ttyS3:115200
Ping
note: every protocol is built with a ping and ack packet
You should see your ‘Ping packet go out, and an ack returned’
______ _ ______ _ _
| ___ \ | | | ___ \ | | | |
| |_/ /__ | |_ _| |_/ /_ _ ___| | _____| |_
| __/ _ \| | | | | __/ _` |/ __| |/ / _ \ __|
| | | (_) | | |_| | | | (_| | (__| < __/ |_
\_| \___/|_|\__, \_| \__,_|\___|_|\_\___|\__| [my_protocol protocol]
__/ |
|___/
Port Opened : /dev/ttyS3
--> { "packetType" : "Ping", "icd" : 3174876862}
<-- { "packetType" : "Ack"}
tip: inside poly-packet, you can press tab to see available packets to send