From 1565d0fbe63649cddb4c3acf4fa277e097cb0d2f Mon Sep 17 00:00:00 2001 From: Aleksei Dynda Date: Thu, 3 Sep 2020 08:59:10 +1000 Subject: [PATCH] Added multithread example --- CMakeLists.txt | 1 + examples/linux/hdlc_demo/hdlc_demo.cpp | 1 - .../hdlc_demo_multithread/CMakeLists.txt | 27 +++ .../hdlc_demo_multithread.cpp | 190 ++++++++++++++++++ 4 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 examples/linux/hdlc_demo_multithread/CMakeLists.txt create mode 100644 examples/linux/hdlc_demo_multithread/hdlc_demo_multithread.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 54cd0337..d4578492 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,7 @@ if (NOT DEFINED COMPONENT_DIR) if (EXAMPLES) add_subdirectory(examples/linux/loopback) add_subdirectory(examples/linux/hdlc_demo) + add_subdirectory(examples/linux/hdlc_demo_multithread) endif() else() diff --git a/examples/linux/hdlc_demo/hdlc_demo.cpp b/examples/linux/hdlc_demo/hdlc_demo.cpp index 01f9447d..aa3575f6 100644 --- a/examples/linux/hdlc_demo/hdlc_demo.cpp +++ b/examples/linux/hdlc_demo/hdlc_demo.cpp @@ -87,7 +87,6 @@ static void protocol_thread(tiny_serial_handle_t serial) int tx_len = 0; int tx_pos = 0; int rx_pos = 0; - int error = 0; // Init hdlc protocol hdlc_struct_t conf{}; diff --git a/examples/linux/hdlc_demo_multithread/CMakeLists.txt b/examples/linux/hdlc_demo_multithread/CMakeLists.txt new file mode 100644 index 00000000..f6ccce52 --- /dev/null +++ b/examples/linux/hdlc_demo_multithread/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required (VERSION 3.5) + +file(GLOB_RECURSE SOURCE_FILES *.cpp *.c) + +if (NOT DEFINED COMPONENT_DIR) + + project (hdlc_demo_multithread) + + add_executable(hdlc_demo_multithread ${SOURCE_FILES}) + + target_link_libraries(hdlc_demo_multithread tinyproto) + + if (WIN32) + find_package(Threads REQUIRED) + target_link_libraries(${PROJECT_NAME} Threads::Threads) + + elseif (UNIX) + find_package(Threads REQUIRED) + target_link_libraries(${PROJECT_NAME} Threads::Threads) + endif() + +else() + + idf_component_register(SRCS ${SOURCE_FILES} + INCLUDE_DIRS ".") + +endif() diff --git a/examples/linux/hdlc_demo_multithread/hdlc_demo_multithread.cpp b/examples/linux/hdlc_demo_multithread/hdlc_demo_multithread.cpp new file mode 100644 index 00000000..9c11b3f2 --- /dev/null +++ b/examples/linux/hdlc_demo_multithread/hdlc_demo_multithread.cpp @@ -0,0 +1,190 @@ +/* + Copyright 2019-2020 (C) Alexey Dynda + + This file is part of Tiny Protocol Library. + + Protocol Library is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Protocol Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with Protocol Library. If not, see . +*/ + +/** + * This is example with single hdlc thread, which shows how to work with TinyProto + * library in mutilthread mode. This example is suitable for heavy OS like Linux and + * Windows. + */ + +#include "proto/hal/tiny_serial.h" +#include "proto/hdlc/tiny_hdlc.h" +#include "TinyProtocol.h" +#include +#include +#include +#include +#include + +static tiny_mutex_t queue_mutex; +static std::queue queue{}; +static bool peek_next; + +static void send_message( const char *message ) +{ + tiny_mutex_lock( &queue_mutex ); + char *msg = strdup( message ); + queue.push( msg ); + tiny_mutex_unlock( &queue_mutex ); +} + +static char *peek_message() +{ + tiny_mutex_lock( &queue_mutex ); + char *msg = nullptr; + if ( queue.size() ) + { + msg = queue.front(); + queue.pop(); + } + tiny_mutex_unlock( &queue_mutex ); + return msg; +} + +static int on_frame_read(void *user_data, void *data, int len) +{ + // Process all incoming data here + fprintf(stderr, "Received message '%.*s'\n", len, (char *)data); + return 0; +} + +static int on_frame_sent(void *user_data, const void *data, int len) +{ + // This callback is called, when frame is sent + fprintf(stderr, "Sent message '%.*s'\n", len, (char *)data); + peek_next = true; + return 0; +} + +static void protocol_tx_thread(tiny_serial_handle_t serial, hdlc_handle_t handle) +{ + uint8_t tx[4]; + int tx_len = 0; + int tx_pos = 0; + + // run infinite loop + char * message = nullptr; + peek_next = true; + for(;;) + { + if ( peek_next ) + { + if ( message ) free( message ); + message = peek_message(); + if ( message ) + { + hdlc_send( handle, message, strlen(message), 0 ); + peek_next = false; + } + } + if ( !tx_len ) + { + tx_pos = 0; + tx_len = hdlc_get_tx_data(handle, tx, sizeof(tx)); + } + if ( tx_len ) + { + int result = tiny_serial_send_timeout( serial, tx + tx_pos, tx_len, 100); + if ( result < 0 ) + { + break; + } + tx_pos += result; + tx_len -= result; + } + } +} + +static void protocol_rx_thread(tiny_serial_handle_t serial, hdlc_handle_t handle) +{ + uint8_t rx[4]; + int rx_len = 0; + int rx_pos = 0; + + for(;;) + { + if ( rx_len == 0 ) + { + int result = tiny_serial_read_timeout(serial, rx, sizeof(rx), 100); + if ( result < 0 ) + { + break; + } + rx_len = result; + rx_pos = 0; + } + int result = hdlc_run_rx(handle, rx + rx_pos, rx_len, nullptr); + rx_pos += result; + rx_len -= result; + } +} + +int main(int argc, char *argv[]) +{ +#if defined(__linux__) + tiny_serial_handle_t serial = tiny_serial_open("/dev/ttyS8", 115200); +#elif defined(_WIN32) + tiny_serial_handle_t serial = tiny_serial_open("COM8", 115200); +#endif + + if ( serial == TINY_SERIAL_INVALID ) + { + fprintf(stderr, "Error opening serial port\n"); + return 1; + } + + // Init hdlc protocol + hdlc_struct_t conf{}; + conf.send_tx = nullptr; + conf.on_frame_read = on_frame_read; + conf.on_frame_sent = on_frame_sent; + conf.rx_buf = malloc( 1024 ); + conf.rx_buf_size = 1024; + conf.crc_type = HDLC_CRC_16; + conf.user_data = nullptr; + conf.multithread_mode = 1; + + hdlc_handle_t handle = hdlc_init( &conf ); + if ( !handle ) + { + tiny_serial_close( serial ); + fprintf(stderr, "Error initializing hdlc protocol\n"); + return 1; + } + + tiny_mutex_create( &queue_mutex ); + std::thread tx_thread( protocol_tx_thread, serial, handle ); + std::thread rx_thread( protocol_rx_thread, serial, handle ); + // Main program cycle + for(;;) + { + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + send_message("Hello message"); + } + + tx_thread.join(); + rx_thread.join(); + + hdlc_close( handle ); + free( conf.rx_buf ); + + tiny_mutex_destroy( &queue_mutex ); + tiny_serial_close(serial); + return 0; +}