Skip to content

Commit

Permalink
Add USB CDC transport (#89)
Browse files Browse the repository at this point in the history
* Add USB CDC transport

Signed-off-by: acuadros95 <[email protected]>

* Add missing #endif and update Readme

Signed-off-by: acuadros95 <[email protected]>

---------

Signed-off-by: acuadros95 <[email protected]>
(cherry picked from commit 3a479bc)

# Conflicts:
#	README.md
  • Loading branch information
Acuadros95 authored and mergify[bot] committed Mar 21, 2023
1 parent 1566f9a commit b3874fb
Show file tree
Hide file tree
Showing 2 changed files with 207 additions and 21 deletions.
65 changes: 44 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ This tool aims to ease the micro-ROS integration in a STM32CubeMX/IDE project.
- [Transport configuration](#transport-configuration)
- [U(S)ART with DMA](#usart-with-dma)
- [U(S)ART with Interrupts](#usart-with-interrupts)
- [USB CDC](#usb-cdc)
- [Customizing the micro-ROS library](#customizing-the-micro-ros-library)
- [Adding custom packages](#adding-custom-packages)
- [Purpose of the Project](#purpose-of-the-project)
Expand All @@ -31,53 +32,67 @@ This package support the usage of micro-ROS on top of two different middlewares:
4. Configure the transport interface on the STM32CubeMX project, check the [Transport configuration](#Transport-configuration) section for instructions on the custom transports provided.
5. Modify the generated `Makefile` to include the following code **before the `build the application` section**:

<!-- # Removing heap4 manager while being polite with STM32CubeMX
TMPVAR := $(C_SOURCES)
C_SOURCES := $(filter-out Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c, $(TMPVAR)) -->
<!-- # Removing heap4 manager while being polite with STM32CubeMX
TMPVAR := $(C_SOURCES)
C_SOURCES := $(filter-out Middlewares/Third_Party/FreeRTOS/Source/portable/MemMang/heap_4.c, $(TMPVAR)) -->

```makefile
#######################################
# micro-ROS addons
#######################################
LDFLAGS += micro_ros_stm32cubemx_utils/microros_static_library/libmicroros/libmicroros.a
C_INCLUDES += -Imicro_ros_stm32cubemx_utils/microros_static_library/libmicroros/microros_include
```makefile
#######################################
# micro-ROS addons
#######################################
LDFLAGS += micro_ros_stm32cubemx_utils/microros_static_library/libmicroros/libmicroros.a
C_INCLUDES += -Imicro_ros_stm32cubemx_utils/microros_static_library/libmicroros/microros_include

# Add micro-ROS utils
C_SOURCES += micro_ros_stm32cubemx_utils/extra_sources/custom_memory_manager.c
C_SOURCES += micro_ros_stm32cubemx_utils/extra_sources/microros_allocators.c
C_SOURCES += micro_ros_stm32cubemx_utils/extra_sources/microros_time.c
# Add micro-ROS utils
C_SOURCES += micro_ros_stm32cubemx_utils/extra_sources/custom_memory_manager.c
C_SOURCES += micro_ros_stm32cubemx_utils/extra_sources/microros_allocators.c
C_SOURCES += micro_ros_stm32cubemx_utils/extra_sources/microros_time.c

# Set here the custom transport implementation
C_SOURCES += micro_ros_stm32cubemx_utils/extra_sources/microros_transports/dma_transport.c
# Set here the custom transport implementation
C_SOURCES += micro_ros_stm32cubemx_utils/extra_sources/microros_transports/dma_transport.c

print_cflags:
@echo $(CFLAGS)
```
print_cflags:
@echo $(CFLAGS)
```

6. Execute the static library generation tool. Compiler flags will retrieved automatically from your `Makefile` and user will be prompted to check if they are correct.


<<<<<<< HEAD
```bash
docker pull microros/micro_ros_static_library_builder:rolling
docker run -it --rm -v $(pwd):/project --env MICROROS_LIBRARY_FOLDER=micro_ros_stm32cubemx_utils/microros_static_library microros/micro_ros_static_library_builder:rolling
```
=======
```bash
docker pull microros/micro_ros_static_library_builder:humble
docker run -it --rm -v $(pwd):/project --env MICROROS_LIBRARY_FOLDER=micro_ros_stm32cubemx_utils/microros_static_library microros/micro_ros_static_library_builder:humble
```
>>>>>>> 3a479bc (Add USB CDC transport (#89))
1. Modify your `main.c` to use micro-ROS. An example application can be found in `sample_main.c`.
2. Continue your usual workflow building your project and flashing the binary:

```bash
make -j$(nproc)
```
```bash
make -j$(nproc)
```

## Using this package with STM32CubeIDE

micro-ROS can be used with SMT32CubeIDE following these steps:

1. Clone this repository in your STM32CubeIDE project folder
2. Go to `Project -> Settings -> C/C++ Build -> Settings -> Build Steps Tab` and in `Pre-build steps` add:

<<<<<<< HEAD
```bash
docker pull microros/micro_ros_static_library_builder:rolling && docker run --rm -v ${workspace_loc:/${ProjName}}:/project --env MICROROS_LIBRARY_FOLDER=micro_ros_stm32cubemx_utils/microros_static_library_ide microros/micro_ros_static_library_builder:rolling
```
=======
```bash
docker pull microros/micro_ros_static_library_builder:humble && docker run --rm -v ${workspace_loc:/${ProjName}}:/project --env MICROROS_LIBRARY_FOLDER=micro_ros_stm32cubemx_utils/microros_static_library_ide microros/micro_ros_static_library_builder:humble
```
>>>>>>> 3a479bc (Add USB CDC transport (#89))
3. Add micro-ROS include directory. In `Project -> Settings -> C/C++ Build -> Settings -> Tool Settings Tab -> MCU GCC Compiler -> Include paths` add `micro_ros_stm32cubemx_utils/microros_static_library_ide/libmicroros/include`
4. Add the micro-ROS precompiled library. In `Project -> Settings -> C/C++ Build -> Settings -> MCU GCC Linker -> Libraries`
Expand Down Expand Up @@ -109,6 +124,14 @@ Steps to configure:
- Enable U(S)ART in your STM32CubeMX
- For the selected USART, enable `global interrupt` under `NVIC Settings`: [Detail](.images/Set_UART_IT.jpg)

### USB CDC

Steps to configure:
- Enable the USB in your STM32CubeMX `Connectivity` tab.
- Select the `Communication Device Class (Virtual Port Com)` mode on the `Middleware -> USB_DEVICE` configuration.

**Note: The micro-ROS transport will override the autogenerated `USB_DEVICE/App/usbd_cdc_if.c` methods.**

## Customizing the micro-ROS library

All the micro-ROS configuration can be done in `colcon.meta` file before step 3. You can find detailed information about how to tune the static memory usage of the library in the [Middleware Configuration tutorial](https://micro.ros.org/docs/tutorials/advanced/microxrcedds_rmw_configuration/).
Expand Down
163 changes: 163 additions & 0 deletions extra_sources/microros_transports/usb_cdc_transport.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
#include <rmw_microros/rmw_microros.h>

#include "main.h"
#include "cmsis_os.h"
#include "usbd_cdc_if.h"
#include "usbd_cdc.h"

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>

#ifdef RMW_UXRCE_TRANSPORT_CUSTOM

// --- USB CDC Handles ---
extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS;
extern USBD_HandleTypeDef hUsbDeviceFS;

// --- Reimplemented USB CDC callbacks ---
static int8_t CDC_TransmitCplt_FS(uint8_t *Buf, uint32_t *Len, uint8_t epnum);
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length);
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len);

// Line coding: Rate: 115200bps; CharFormat: 1 Stop bit; Parity: None; Data: 8 bits
static uint8_t line_coding[7] = {0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08};

// --- micro-ROS Transports ---
#define USB_BUFFER_SIZE 2048
#define WRITE_TIMEOUT_MS 100U

volatile uint8_t storage_buffer[USB_BUFFER_SIZE] = {0};
volatile size_t it_head = 0;
volatile size_t it_tail = 0;
volatile bool g_write_complete = false;
bool initialized = false;

// Transmission completed callback
static int8_t CDC_TransmitCplt_FS(uint8_t *Buf, uint32_t *Len, uint8_t epnum)
{
(void) Buf;
(void) Len;
(void) epnum;

g_write_complete = true;
return USBD_OK;
}

// USB CDC requests callback
static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
{
switch(cmd)
{
case CDC_SET_LINE_CODING:
memcpy(line_coding, pbuf, sizeof(line_coding));
break;

case CDC_GET_LINE_CODING:
memcpy(pbuf, line_coding, sizeof(line_coding));
break;

case CDC_SEND_ENCAPSULATED_COMMAND:
case CDC_GET_ENCAPSULATED_RESPONSE:
case CDC_SET_COMM_FEATURE:
case CDC_GET_COMM_FEATURE:
case CDC_CLEAR_COMM_FEATURE:
case CDC_SET_CONTROL_LINE_STATE:
case CDC_SEND_BREAK:
default:
break;
}

return USBD_OK;
}

// Data received callback
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);

// Circular buffer
if ((it_tail + *Len) > USB_BUFFER_SIZE)
{
size_t first_section = USB_BUFFER_SIZE - it_tail;
size_t second_section = *Len - first_section;

memcpy((void*) &storage_buffer[it_tail] , Buf, first_section);
memcpy((void*) &storage_buffer[0] , Buf, second_section);
it_tail = second_section;
}
else
{
memcpy((void*) &storage_buffer[it_tail] , Buf, *Len);
it_tail += *Len;
}

USBD_CDC_ReceivePacket(&hUsbDeviceFS);

return (USBD_OK);
}

bool cubemx_transport_open(struct uxrCustomTransport * transport){

if (!initialized)
{
// USB is initialized on generated main code: Replace default callbacks here
USBD_Interface_fops_FS.Control = CDC_Control_FS;
USBD_Interface_fops_FS.Receive = CDC_Receive_FS;
USBD_Interface_fops_FS.TransmitCplt = CDC_TransmitCplt_FS;
initialized = true;
}

return true;
}

bool cubemx_transport_close(struct uxrCustomTransport * transport){
return true;
}

size_t cubemx_transport_write(struct uxrCustomTransport* transport, uint8_t * buf, size_t len, uint8_t * err){
uint8_t ret = CDC_Transmit_FS(buf, len);

if (USBD_OK != ret)
{
return 0;
}

int64_t start = uxr_millis();
while(!g_write_complete && (uxr_millis() - start) < WRITE_TIMEOUT_MS)
{
vTaskDelay( 1 / portTICK_PERIOD_MS);
}

size_t writed = g_write_complete ? len : 0;
g_write_complete = false;

return writed;
}

size_t cubemx_transport_read(struct uxrCustomTransport* transport, uint8_t* buf, size_t len, int timeout, uint8_t* err){

int64_t start = uxr_millis();
size_t readed = 0;

do
{
if (it_head != it_tail)
{
while ((it_head != it_tail) && (readed < len)){
buf[readed] = storage_buffer[it_head];
it_head = (it_head + 1) % USB_BUFFER_SIZE;
readed++;
}

break;
}

vTaskDelay( 1 / portTICK_PERIOD_MS );
} while ((uxr_millis() - start) < timeout);

return readed;
}

#endif

0 comments on commit b3874fb

Please sign in to comment.