marklincan: use async tcp connect the prevent "hanging", see #150

Dieser Commit ist enthalten in:
Reinder Feenstra 2024-06-25 22:46:54 +02:00
Ursprung ea027d8d3f
Commit 0adf0584dd
7 geänderte Dateien mit 66 neuen und 31 gelöschten Zeilen

Datei anzeigen

@ -3,7 +3,7 @@
* *
* This file is part of the traintastic source code. * This file is part of the traintastic source code.
* *
* Copyright (C) 2023 Reinder Feenstra * Copyright (C) 2023-2024 Reinder Feenstra
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -21,6 +21,7 @@
*/ */
#include "networkiohandler.hpp" #include "networkiohandler.hpp"
#include "../kernel.hpp"
#include "../../../../utils/endian.hpp" #include "../../../../utils/endian.hpp"
namespace MarklinCAN { namespace MarklinCAN {
@ -28,6 +29,7 @@ namespace MarklinCAN {
void NetworkIOHandler::start() void NetworkIOHandler::start()
{ {
read(); read();
m_kernel.started();
} }
bool NetworkIOHandler::send(const Message& message) bool NetworkIOHandler::send(const Message& message)

Datei anzeigen

@ -3,7 +3,7 @@
* *
* This file is part of the traintastic source code. * This file is part of the traintastic source code.
* *
* Copyright (C) 2023 Reinder Feenstra * Copyright (C) 2023-2024 Reinder Feenstra
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -42,6 +42,7 @@ void SimulationIOHandler::start()
auto expireAfter = std::chrono::milliseconds(Random::value<int>(0, bootstrapCANInterval.count())); auto expireAfter = std::chrono::milliseconds(Random::value<int>(0, bootstrapCANInterval.count()));
startBootloaderCANTimer(expireAfter); startBootloaderCANTimer(expireAfter);
startPingTimer(expireAfter + 1s); startPingTimer(expireAfter + 1s);
m_kernel.started();
} }
void SimulationIOHandler::startBootloaderCANTimer(std::chrono::milliseconds expireAfter) void SimulationIOHandler::startBootloaderCANTimer(std::chrono::milliseconds expireAfter)

Datei anzeigen

@ -3,7 +3,7 @@
* *
* This file is part of the traintastic source code. * This file is part of the traintastic source code.
* *
* Copyright (C) 2023 Reinder Feenstra * Copyright (C) 2023-2024 Reinder Feenstra
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -67,6 +67,7 @@ SocketCANIOHandler::SocketCANIOHandler(Kernel& kernel, const std::string& interf
void SocketCANIOHandler::start() void SocketCANIOHandler::start()
{ {
read(); read();
m_kernel.started();
} }
void SocketCANIOHandler::stop() void SocketCANIOHandler::stop()

Datei anzeigen

@ -3,7 +3,7 @@
* *
* This file is part of the traintastic source code. * This file is part of the traintastic source code.
* *
* Copyright (C) 2023 Reinder Feenstra * Copyright (C) 2023-2024 Reinder Feenstra
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -46,20 +46,37 @@ void TCPIOHandler::start()
if(ec) if(ec)
throw LogMessageException(LogMessage::E2003_MAKE_ADDRESS_FAILED_X, ec); throw LogMessageException(LogMessage::E2003_MAKE_ADDRESS_FAILED_X, ec);
m_socket.connect(m_endpoint, ec); m_socket.async_connect(m_endpoint,
if(ec) [this](const boost::system::error_code& err)
throw LogMessageException(LogMessage::E2005_SOCKET_CONNECT_FAILED_X, ec); {
if(!err)
{
m_socket.set_option(boost::asio::socket_base::linger(true, 0));
m_socket.set_option(boost::asio::ip::tcp::no_delay(true));
m_socket.set_option(boost::asio::socket_base::linger(true, 0)); m_connected = true;
m_socket.set_option(boost::asio::ip::tcp::no_delay(true));
NetworkIOHandler::start(); write();
NetworkIOHandler::start();
}
else if(err != boost::asio::error::operation_aborted)
{
EventLoop::call(
[this, err]()
{
Log::log(m_kernel.logId, LogMessage::E2005_SOCKET_CONNECT_FAILED_X, err);
m_kernel.error();
});
}
});
} }
void TCPIOHandler::stop() void TCPIOHandler::stop()
{ {
m_socket.cancel(); m_socket.cancel();
m_socket.close(); m_socket.close();
m_connected = false;
} }
void TCPIOHandler::read() void TCPIOHandler::read()
@ -99,6 +116,11 @@ void TCPIOHandler::read()
void TCPIOHandler::write() void TCPIOHandler::write()
{ {
if(m_writeBufferOffset == 0 || !m_connected)
{
return;
}
m_socket.async_write_some(boost::asio::buffer(m_writeBuffer.data(), m_writeBufferOffset), m_socket.async_write_some(boost::asio::buffer(m_writeBuffer.data(), m_writeBufferOffset),
[this](const boost::system::error_code& ec, std::size_t bytesTransferred) [this](const boost::system::error_code& ec, std::size_t bytesTransferred)
{ {

Datei anzeigen

@ -3,7 +3,7 @@
* *
* This file is part of the traintastic source code. * This file is part of the traintastic source code.
* *
* Copyright (C) 2023 Reinder Feenstra * Copyright (C) 2023-2024 Reinder Feenstra
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -38,6 +38,7 @@ class TCPIOHandler final : public NetworkIOHandler
boost::asio::ip::tcp::endpoint m_endpoint; boost::asio::ip::tcp::endpoint m_endpoint;
std::array<std::byte, 1500> m_readBuffer; std::array<std::byte, 1500> m_readBuffer;
size_t m_readBufferOffset; size_t m_readBufferOffset;
bool m_connected = false;
void read() final; void read() final;
void write() final; void write() final;

Datei anzeigen

@ -159,26 +159,7 @@ void Kernel::start()
Log::log(logId, e.message(), e.args()); Log::log(logId, e.message(), e.args());
error(); error();
}); });
return;
} }
// add Traintastic to the node list
{
Node node;
node.uid = m_config.nodeUID;
node.deviceName = nodeDeviceName;
node.articleNumber = nodeArticleNumber;
node.serialNumber = m_config.nodeSerialNumber;
node.softwareVersionMajor = TRAINTASTIC_VERSION_MAJOR;
node.softwareVersionMinor = TRAINTASTIC_VERSION_MINOR;
node.deviceId = DeviceId::Traintastic;
nodeChanged(node);
m_nodes.emplace(m_config.nodeUID, node);
}
nextState();
}); });
#ifndef NDEBUG #ifndef NDEBUG
@ -205,6 +186,27 @@ void Kernel::stop()
#endif #endif
} }
void Kernel::started()
{
// add Traintastic to the node list
{
Node node;
node.uid = m_config.nodeUID;
node.deviceName = nodeDeviceName;
node.articleNumber = nodeArticleNumber;
node.serialNumber = m_config.nodeSerialNumber;
node.softwareVersionMajor = TRAINTASTIC_VERSION_MAJOR;
node.softwareVersionMinor = TRAINTASTIC_VERSION_MINOR;
node.deviceId = DeviceId::Traintastic;
nodeChanged(node);
m_nodes.emplace(m_config.nodeUID, node);
}
nextState();
}
void Kernel::receive(const Message& message) void Kernel::receive(const Message& message)
{ {
assert(isKernelThread()); assert(isKernelThread());
@ -957,7 +959,7 @@ void Kernel::changeState(State value)
break; break;
case State::Started: case State::Started:
started(); KernelBase::started();
break; break;
} }
} }

Datei anzeigen

@ -226,6 +226,12 @@ class Kernel : public ::KernelBase
*/ */
void stop(); void stop();
/**
* \brief Notify kernel the IO handler is started.
* \note This function must run in the kernel's IO context
*/
void started() final;
/** /**
* \brief ... * \brief ...
* *