Skip to content

Commit

Permalink
Added multithread example
Browse files Browse the repository at this point in the history
  • Loading branch information
lexus2k committed Sep 2, 2020
1 parent 1de7ce7 commit 1565d0f
Show file tree
Hide file tree
Showing 4 changed files with 218 additions and 1 deletion.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
1 change: 0 additions & 1 deletion examples/linux/hdlc_demo/hdlc_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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{};
Expand Down
27 changes: 27 additions & 0 deletions examples/linux/hdlc_demo_multithread/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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()
190 changes: 190 additions & 0 deletions examples/linux/hdlc_demo_multithread/hdlc_demo_multithread.cpp
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/

/**
* 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 <stdio.h>
#include <cstring>
#include <chrono>
#include <thread>
#include <queue>

static tiny_mutex_t queue_mutex;
static std::queue<char *> 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;
}

0 comments on commit 1565d0f

Please sign in to comment.