How to use UART in custom applications
-
I am currently trying to make a simple application that gets imu data and sends it out through uart. I am using the voxl-cross-template project as a base for this application. I have tried using some of the code in the libqrb5165-io project to get the uart to work however I have been unable to compile it. I believe it might be an issue with my cmake files.
[ 50%] Linking C executable hello-cross CMakeFiles/hello-cross.dir/main.c.o: In function `_helper_cb': main.c:(.text+0xb8): undefined reference to `voxl_uart_write' main.c:(.text+0xfc): undefined reference to `ERROR' CMakeFiles/hello-cross.dir/main.c.o: In function `main': main.c:(.text.startup+0x3c): undefined reference to `voxl_uart_init' main.c:(.text.startup+0xcc): undefined reference to `voxl_uart_close' main.c:(.text.startup+0xec): undefined reference to `ERROR' main.c:(.text.startup+0x100): undefined reference to `ERROR' collect2: error: ld returned 1 exit status src/CMakeFiles/hello-cross.dir/build.make:99: recipe for target 'src/hello-cross' failed make[2]: *** [src/hello-cross] Error 1 CMakeFiles/Makefile2:97: recipe for target 'src/CMakeFiles/hello-cross.dir/all' failed make[1]: *** [src/CMakeFiles/hello-cross.dir/all] Error 2 Makefile:135: recipe for target 'all' failed make: *** [all] Error 2 starting building Debian Package mkdir: cannot create directory 'pkg/DEB': No such file or directory
Is there a better way to send data out through uart? Is there an example of something similar to what I'm trying to do out there that I can look at?
Here is my current main function and helper_cb for reference:
int main(int argc, char *const argv[]) { enable_signal_handler(); main_running = 1; int uart_res = voxl_uart_init(device, baud, 1.0, 0, 1, 0); if (uart_res < 0) { ERROR("Failed to open port"); resurn 1; } pipe_client_set_simple_helper_cb(0, _helper_cb, NULL); pipe_client_set_disconnect_cb(0, _disconnect_cb, NULL); int pipe_open_res = pipe_client_open(0, imu_name, CLIENT_NAME, EN_PIPE_CLIENT_SIMPLE_HELPER, IMU_RECOMMENDED_READ_BUF_SIZE); if (pipe_open_res < 0) { pipe_print_error(pipe_open_res); printf(ENABLE_WRAP); return -1; } // keep going until the signal handler sets the running flag to 0 while (main_running) usleep(500000); // all done, signal pipe read threads to stop printf("\nclosing and exiting\n" RESET_FONT ENABLE_WRAP); pipe_client_close_all(); int ret = voxl_uart_close(device); if (ret < 0) { ERROR("Failed to close UART device"); return 1; } } static void _helper_cb(__attribute__((unused)) int ch, char *data, int bytes, __attribute__((unused)) void *context) { const uint8_t MIN_WRITE_LEN = 32; uint8_t write_buf[MIN_WRITE_LEN]; // validate that the data makes sense int n_packets; imu_data_t *data_array = pipe_validate_imu_data_t(data, bytes, &n_packets); if (data_array == NULL) return; // print everything in one go. if (!en_newline) printf("\r" CLEAR_LINE); printf("%7.2f|%7.2f|%7.2f|%7.2f|%7.2f|%7.2f", (double)data_array[n_packets - 1].accl_ms2[0], (double)data_array[n_packets - 1].accl_ms2[1], (double)data_array[n_packets - 1].accl_ms2[2], (double)data_array[n_packets - 1].gyro_rad[0], (double)data_array[n_packets - 1].gyro_rad[1], (double)data_array[n_packets - 1].gyro_rad[2]); if (en_newline) printf("\n"); int write_res = voxl_uart_write(device, write_buf, MIN_WRITE_LEN); if (write_res < 0) { ERROR("Failed to write to UART"); return; } fflush(stdout); return; }
-
In your application, you should be including
<voxl_io.h>
and linking againstvoxl_io
library:in cmake file:
target_link_libraries(${app_name} LINK_PUBLIC voxl-io)
Both the header and library (.so) are part of
libqrb5165-io
package that is built from this project: https://gitlab.com/voxl-public/voxl-sdk/core-libs/libqrb5165-io/So, if you are building your app using cross-compiler, make sure to install the
libqrb5165-io
inside the cross compiler docker before building the application. Typically all our projects have a script for installing build deps, here it is for thelibqrb5165-io
library (which obviously does not include the library itself as a dependency, because we are actually building it here ) : https://gitlab.com/voxl-public/voxl-sdk/core-libs/libqrb5165-io/-/blob/master/install_build_deps.shYou can also just run
apt update && apt install libqrb5165-io
after you spin up your cross compile docker.You can also build your app directly on voxl2, as the
libqrb5165-io
library should already be installed as part of our SDK.Alex
-
@Alex-Kushleyev thank you for your response, however I am still unable to build the project. I have libqrb5165-io added to my install_build_deps.sh and I do have the voxl_io header included in my main file. Maybe I am placing the cmake line in the wrong spot or in the wrong cmake file altogether as I have two of them. Here are the cmake files in my src folder and root folder respectively:
// ./src/CMakeLists.txt cmake_minimum_required(VERSION 3.3) SET(TARGET hello-cross) # Build from all source files file(GLOB all_src_files *.c*) add_executable(${TARGET} ${all_src_files} ) include_directories( ../include ) find_library(MODAL_JSON modal_json HINTS /usr/lib /usr/lib64) find_library(MODAL_PIPE modal_pipe HINTS /usr/lib /usr/lib64) find_library(VOXL_CUTILS voxl_cutils HINTS /usr/lib /usr/lib64) find_library(VOXL_IO libvoxl_io HINTS /usr/lib /usr/lib64) target_link_libraries( ${TARGET} pthread ${MODAL_JSON} ${MODAL_PIPE} ${VOXL_CUTILS} ${app_name} LINK_PUBLIC voxl-io ) # make sure everything is installed where we want # LIB_INSTALL_DIR comes from the parent cmake file install( TARGETS ${TARGET} LIBRARY DESTINATION ${LIB_INSTALL_DIR} RUNTIME DESTINATION /usr/bin PUBLIC_HEADER DESTINATION /usr/include )
// ./CMakeLists.txt cmake_minimum_required(VERSION 3.3) project(voxl-hello-cross C) include_directories( "include/" ) # Strawson's list of standard list of default gcc flags. Yes, I treat # warnings as errors. Warnings exist to point out sloppy code and potential # failure points for good reason. We do not approve of sloppy code. # set(CMAKE_C_FLAGS "-std=gnu99 -Werror -Wall -Wextra -Wuninitialized \ # -Wunused-variable -Wdouble-promotion -Wmissing-prototypes \ # -Wmissing-declarations -Werror=undef -Wno-unused-function ${CMAKE_C_FLAGS}") set(CMAKE_C_FLAGS "-std=gnu99 -Wuninitialized \ -Wdouble-promotion -Wmissing-prototypes \ -Wmissing-declarations -Werror=undef ${CMAKE_C_FLAGS}") # for VOXL, install 64-bit libraries to lib64, 32-bit libs go in /usr/lib if(CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64") set(LIB_INSTALL_DIR /usr/lib64) else() set(LIB_INSTALL_DIR /usr/lib) endif() # include each subdirectory, may have others in example/ or lib/ etc add_subdirectory (src)
here is the output when I run the install and build scripts:
using qrb5165 sdk-1.0 debian repo Ign:1 http://voxl-packages.modalai.com ./dists/qrb5165/sdk-1.0/binary-arm64/ InRelease Ign:2 http://voxl-packages.modalai.com ./dists/qrb5165/sdk-1.0/binary-arm64/ Release Get:3 http://voxl-packages.modalai.com ./dists/qrb5165/sdk-1.0/binary-arm64/ Packages [23.2 kB] Fetched 23.2 kB in 0s (61.3 kB/s) Reading package lists... Done installing: libmodal-json libmodal-pipe libvoxl-cutils libqrb5165-io Reading package lists... Done Building dependency tree Reading state information... Done libmodal-json:arm64 is already the newest version (0.4.3). libvoxl-cutils:arm64 is already the newest version (0.1.1). libqrb5165-io:arm64 is already the newest version (0.4.7). libmodal-pipe:arm64 is already the newest version (2.10.4). 0 upgraded, 0 newly installed, 0 to remove and 1 not upgraded. Done installing dependencies -- The C compiler identification is GNU 7.5.0 -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Check for working C compiler: /usr/bin/aarch64-linux-gnu-gcc-7 - skipped -- Detecting C compile features -- Detecting C compile features - done CMake Error at src/CMakeLists.txt:22 (target_link_libraries): The LINK_PUBLIC or LINK_PRIVATE option must appear as the second argument, just after the target name.
Im new to cmake so I have no idea what I am doing.
-
I think you need to update the
target_link_libraries
entry to:target_link_libraries( ${TARGET} pthread ${MODAL_JSON} ${MODAL_PIPE} ${VOXL_CUTILS} voxl-io )
or
$(VOXL_IO)
instead ofvoxl-io
since you already defined it using:find_library(VOXL_IO libvoxl_io HINTS /usr/lib /usr/lib64)
Please try
Alex
-
@Alex-Kushleyev after adding $(VOXL_IO) i get:
-- Build files have been written to: /home/root/build [ 50%] Building C object src/CMakeFiles/hello-cross.dir/main.c.o /home/root/src/main.c: In function '_helper_cb': /home/root/src/main.c:88:21: warning: implicit declaration of function 'voxl_uart_write'; did you mean 'voxl_spi_write'? [-Wimplicit-function-declaration] int write_res = voxl_uart_write(device, write_buf, MIN_WRITE_LEN); ^~~~~~~~~~~~~~~ voxl_spi_write /home/root/src/main.c: In function 'main': /home/root/src/main.c:105:20: warning: implicit declaration of function 'voxl_uart_init'; did you mean 'voxl_i2c_init'? [-Wimplicit-function-declaration] int uart_res = voxl_uart_init(device, baud, 1.0, 0, 1, 0); ^~~~~~~~~~~~~~ voxl_i2c_init /home/root/src/main.c:134:15: warning: implicit declaration of function 'voxl_uart_close'; did you mean 'voxl_i2c_close'? [-Wimplicit-function-declaration] int ret = voxl_uart_close(device); ^~~~~~~~~~~~~~~ voxl_i2c_close [100%] Linking C executable hello-cross CMakeFiles/hello-cross.dir/main.c.o: In function `_helper_cb': main.c:(.text+0xb8): undefined reference to `voxl_uart_write' CMakeFiles/hello-cross.dir/main.c.o: In function `main': main.c:(.text.startup+0x44): undefined reference to `voxl_uart_init' main.c:(.text.startup+0xd0): undefined reference to `voxl_uart_close' collect2: error: ld returned 1 exit status src/CMakeFiles/hello-cross.dir/build.make:100: recipe for target 'src/hello-cross' failed make[2]: *** [src/hello-cross] Error 1 CMakeFiles/Makefile2:97: recipe for target 'src/CMakeFiles/hello-cross.dir/all' failed make[1]: *** [src/CMakeFiles/hello-cross.dir/all] Error 2 Makefile:135: recipe for target 'all' failed make: *** [all] Error 2 Package Name: voxl-cross-template version Number: 0.0.1 Consolidate compiler generated dependencies of target hello-cross [ 50%] Linking C executable hello-cross CMakeFiles/hello-cross.dir/main.c.o: In function `_helper_cb': main.c:(.text+0xb8): undefined reference to `voxl_uart_write' CMakeFiles/hello-cross.dir/main.c.o: In function `main': main.c:(.text.startup+0x44): undefined reference to `voxl_uart_init' main.c:(.text.startup+0xd0): undefined reference to `voxl_uart_close' collect2: error: ld returned 1 exit status src/CMakeFiles/hello-cross.dir/build.make:100: recipe for target 'src/hello-cross' failed make[2]: *** [src/hello-cross] Error 1
-
This is odd because the uart function definitions are here :
Are you sure that you are including <voxl_io.h> in your app?
implicit declaration of function
warning is a clear sign that the function declaration is not found (from voxl_io.h, well actually fromvoxl_io/uart.h
, latter being included from voxl_io.h.Please double check.
Alex
-
@Alex-Kushleyev I have it included, heres my full main file:
#include <stdio.h> // for fprintf #include <unistd.h> #include <getopt.h> #include <string.h> #include <modal_pipe.h> #include <voxl_cutils.h> #include <voxl_io.h> #include "hello_cross.h" #define CLIENT_NAME "hello-cross" static char en_newline = 0; static char imu_name[64]; static int opt = 0; static int device = 1; // default. /dev/ttyHS1 static int baud = 115200; void printHelloCross(void); // called whenever we disconnect from the server static void _disconnect_cb(__attribute__((unused)) int ch, __attribute__((unused)) void *context) { fprintf(stderr, "\r" CLEAR_LINE FONT_BLINK "server disconnected" RESET_FONT); return; } // called when the simple helper has data for us static void _helper_cb(__attribute__((unused)) int ch, char *data, int bytes, __attribute__((unused)) void *context) { const uint8_t MIN_WRITE_LEN = 32; uint8_t write_buf[MIN_WRITE_LEN]; // validate that the data makes sense int n_packets; imu_data_t *data_array = pipe_validate_imu_data_t(data, bytes, &n_packets); if (data_array == NULL) return; // print everything in one go. if (!en_newline) printf("\r" CLEAR_LINE); printf("%7.2f|%7.2f|%7.2f|%7.2f|%7.2f|%7.2f", (double)data_array[n_packets - 1].accl_ms2[0], (double)data_array[n_packets - 1].accl_ms2[1], (double)data_array[n_packets - 1].accl_ms2[2], (double)data_array[n_packets - 1].gyro_rad[0], (double)data_array[n_packets - 1].gyro_rad[1], (double)data_array[n_packets - 1].gyro_rad[2]); if (en_newline) printf("\n"); int write_res = voxl_uart_write(device, write_buf, MIN_WRITE_LEN); if (write_res < 0) { //ERROR("Failed to write to UART"); return; } fflush(stdout); return; } int main(int argc, char *const argv[]) { enable_signal_handler(); main_running = 1; int uart_res = voxl_uart_init(device, baud, 1.0, 0, 1, 0); if (uart_res < 0) { //ERROR("Failed to open port"); return 1; } pipe_client_set_simple_helper_cb(0, _helper_cb, NULL); pipe_client_set_disconnect_cb(0, _disconnect_cb, NULL); int pipe_open_res = pipe_client_open(0, imu_name, CLIENT_NAME, EN_PIPE_CLIENT_SIMPLE_HELPER, IMU_RECOMMENDED_READ_BUF_SIZE); if (pipe_open_res < 0) { pipe_print_error(pipe_open_res); printf(ENABLE_WRAP); return -1; } // keep going until the signal handler sets the running flag to 0 while (main_running) usleep(500000); // all done, signal pipe read threads to stop printf("\nclosing and exiting\n" RESET_FONT ENABLE_WRAP); pipe_client_close_all(); int ret = voxl_uart_close(device); if (ret < 0) { //ERROR("Failed to close UART device"); return 1; } } void printHelloCross() { printf(" Imu Acceleration and Gyro\n"); printf(" X | Y | Z | X | Y | Z\n"); }
-
@Samuel-Lehman , Not sure what is going on but i was able to build your example with the following command on VOXL2. I had to comment out
#include "hello_cross.h"
because i did not have it.voxl2:~$ gcc -O2 -Wall voxl_io_uart_test.c -o voxl_io_uart_test -lmodal_pipe -lvoxl_io -L/usr/lib64 voxl_io_uart_test.c:14:12: warning: 'opt' defined but not used [-Wunused-variable] static int opt = 0; ^~~ voxl2:~$
I am not sure what's going on, you can enable verbose CMake file to see what compile command CMake is generating and compare that to the above.
Alex