From b6e2fb13560eaf30c95b1a3511d7cfae790e4703 Mon Sep 17 00:00:00 2001 From: DashyFox Date: Tue, 19 Nov 2024 17:57:04 +0300 Subject: [PATCH] tcp client --- examples/Client/Client.ino | 46 +++++++++-- src/EthernetOverride/TCP.cpp | 148 +++++++++++++++++++++++++++++------ src/EthernetOverride/TCP.h | 34 ++++++-- 3 files changed, 188 insertions(+), 40 deletions(-) diff --git a/examples/Client/Client.ino b/examples/Client/Client.ino index 1a30d49..4f57310 100644 --- a/examples/Client/Client.ino +++ b/examples/Client/Client.ino @@ -32,6 +32,10 @@ EthernetMaketClient client; uint32_t packetCounter = 0; +void onSend(){ + Serial.println("Sending Successfully"); +} + void setup() { Serial.begin(115200); @@ -46,11 +50,16 @@ void setup() // Ethernet.setRtCount(3); // client.setNoDelayedACK(true); // Не ждать ответа от сервера + + client.setOnSendSuccess(onSend); } + + void loop() { + EthernetMaketClient::tick(); uint32_t currentMillis = millis(); if (currentMillis - ttt > 75) { @@ -61,12 +70,35 @@ void loop() if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; - // client.stop(); // Завершаем предыдущее соединение - connectStatus = CONNECT_START; // функция коннекта - // client.connect(serverIP, SERVER_PORT); - client.setData(buf, sizeof(buf)); - client() - } - + // client.stop(); // Завершаем предыдущее соединение + // connectStatus = CONNECT_START; // функция коннекта + // client.connect(serverIP, SERVER_PORT); + // client.setData(buf, sizeof(buf)); + // client() + + if (client.connectNonBlock(serverIP, SERVER_PORT) == CONNECT_CONNECTED) + { + for (size_t i = 0; i < 3; i++) + { + client.dataWrite((uint8_t *)&packetCounter, sizeof(packetCounter)); + + // Print the packet being sent + Serial.print("Sending packet: "); + for (size_t j = 0; j < sizeof(packetCounter); j++) + { + Serial.print(((uint8_t *)&packetCounter)[j], HEX); + Serial.print(" "); + } + Serial.println(); + packetCounter++; + } + } + else + { + Serial.println("Failed to connect to server"); + client.stop(); + } + + } } \ No newline at end of file diff --git a/src/EthernetOverride/TCP.cpp b/src/EthernetOverride/TCP.cpp index fb4bee3..35872b3 100644 --- a/src/EthernetOverride/TCP.cpp +++ b/src/EthernetOverride/TCP.cpp @@ -2,8 +2,32 @@ #include "utility/w5500.h" #include "utility/socket.h" +std::vector EthernetMaketClient::instances; + + +EthernetMaketClient::EthernetMaketClient() { + _sock = MAX_SOCK_NUM; + instances.push_back(this); +} + +EthernetMaketClient::EthernetMaketClient(uint8_t sock) { + _sock = sock; + instances.push_back(this); +} + +EthernetMaketClient::~EthernetMaketClient() { + instances.erase(std::remove(instances.begin(), instances.end(), this), instances.end()); +} + +void EthernetMaketClient::tick() { + for (EthernetMaketClient* client : instances) { + client->tick_(); + } +} + ConnectionStatusSimple EthernetMaketClient::connectNonBlock(IPAddress ip, uint16_t port) { - + dstIP = ip; + dstPort = port; if (_sock != MAX_SOCK_NUM) { // Serial.println(F("connectNonBlock")); uint8_t status_ = status(); @@ -47,6 +71,10 @@ ConnectionStatusSimple EthernetMaketClient::connectNonBlock(IPAddress ip, uint16 return CONNECT_CONNECTING; } +bool EthernetMaketClient::isConnected() const { + return connectStatus == CONNECT_CONNECTED; +} + void EthernetMaketClient::disconnect(){ if (_sock == MAX_SOCK_NUM) return; @@ -60,7 +88,7 @@ void EthernetMaketClient::close(){ _sock = MAX_SOCK_NUM; } -void EthernetMaketClient::tick(){ +void EthernetMaketClient::tick_(){ // Подключаемся к серверу switch (connectStatus) { @@ -88,26 +116,15 @@ void EthernetMaketClient::tick(){ lastActivityTime = millis(); connectStatus = CONNECT_CONNECTED; - //! Передача пакетов - for (size_t i = 0; i < 3; i++) - { - client.write((uint8_t *)&packetCounter, sizeof(packetCounter)); - - // Печать отправленного пакета - Serial.print("Sending packet: "); - for (size_t j = 0; j < sizeof(packetCounter); j++) - { - Serial.print(((uint8_t *)&packetCounter)[j], HEX); - Serial.print(" "); - } - Serial.println(); - packetCounter++; - lastActivityTime = millis(); // Обновляем время последней активности для каждого пакета - } - //! Передача завершена + lastActivityTime = millis(); // Обновляем время последней активности break; case CONNECT_CONNECTED: + + //! Передача пакетов + dataWrite(); + //! Передача завершена + if (!connected()) { Serial.println("Client disconnected"); @@ -123,40 +140,58 @@ void EthernetMaketClient::tick(){ break; case CONNECT_STOP_START: + dstIP = IPAddress(0,0,0,0); + dstPort = 0; disconnect(); stopStartTime = millis(); connectStatus = CONNECT_STOP_WAITING; break; case CONNECT_STOP_WAITING: - if (millis() - stopStartTime >= stopTimeout) - { - close(); // Закрываем сокет после таймаута - connectStatus = CONNECT_IDLE; + if (millis() - stopStartTime >= stopTimeout) { + close(); // Окончательное закрытие сокета после таймаута + connectStatus = (dataSize > 0) ? CONNECT_START : CONNECT_IDLE; + } else { + // Проверяем состояние сокета для завершения разрыва + uint8_t status_ = status(); + if (status_ == SnSR::CLOSED || status_ == SnSR::CLOSE_WAIT) { + close(); // Закрываем при достижении состояния + connectStatus = (dataSize > 0) ? CONNECT_START : CONNECT_IDLE; } + } + break; + + case CONNECT_IDLE: + if(dataSize){ + connectStatus = CONNECT_START; + } break; default: break; } - +//******************************************************** switch (connectStatus) { case CONNECT_START: case CONNECT_CONNECTING: + if(dstIP == IPAddress(0,0,0,0) || dstPort == 0) + break; + if (isNonBlocking) { - connectStatus = connectNonBlock(serverIP, SERVER_PORT); + connectStatus = connectNonBlock(dstIP, dstPort); } else { - connectStatus = (ConnectionStatusSimple)connect(serverIP, SERVER_PORT); + connectStatus = (ConnectionStatusSimple)connect(dstIP, dstPort); } break; default: break; } +//******************************************************** //? Проверка наличия доступных данных от сервера if (available() > 0) @@ -197,3 +232,64 @@ void EthernetMaketClient::tick(){ } //? ------------------------------------------------- } + +bool EthernetMaketClient::dataWrite(){ + bool ret = false; + if(dataSize) { + lastActivityTime = millis(); + if(write((uint8_t *)&dataPtr, dataSize)){ + dataPtr = nullptr; + dataSize = 0; // Очищаем размер данных + ret = true; + } + lastActivityTime = millis(); + } + return ret; +} + +bool EthernetMaketClient::dataWrite(uint8_t* data, uint16_t dataSize, bool override) { + if (dataSize == 0 || override || (dataPtr == nullptr && this->dataSize == 0)) { + this->dataPtr = data; + this->dataSize = dataSize; + return dataWrite(); + } else { + Serial.println("Data buffer is not empty. Write operation is ignored."); + return false; + } +} + + +bool EthernetMaketClient::send(uint8_t* data, uint16_t dataSize, IPAddress ip, uint16_t port) { + this->dataPtr = data; + this->dataSize = dataSize; + + switch (connectStatus) { + case CONNECT_CONNECTED: + if(dataWrite()){ + onSendSuccess(); + } + // Если подключено, отправляем данные + return true; + + case CONNECT_STOP_WAITING: + case CONNECT_STOP_START: + return false; // Ожидаем завершения разрыва + + case CONNECT_FAIL: + case CONNECT_IDLE: + connectNonBlock(ip, port); + connectStatus = CONNECT_START; // Начинаем новое подключение + return false; // Подключение инициировано + + default: + return false; // Пока ждём подключения + } +} + +void EthernetMaketClient::setOnSendSuccess(const std::function& callback) { + onSendSuccess = callback; +} + +void EthernetMaketClient::resetOnSendSuccess() { + onSendSuccess = []() {}; +} diff --git a/src/EthernetOverride/TCP.h b/src/EthernetOverride/TCP.h index 000672f..ca81623 100644 --- a/src/EthernetOverride/TCP.h +++ b/src/EthernetOverride/TCP.h @@ -1,10 +1,11 @@ #ifndef __MAKET_TCP_H__ #define __MAKET_TCP_H__ +#include +#include #include "../util/config.h" -class EthernetMaketClient : public EthernetClient -{ +class EthernetMaketClient : public EthernetClient { protected: uint32_t lastActivityTime = 0; // Время последней активности const uint16_t timeout = 300; // Таймаут неактивности в миллисекундах @@ -13,16 +14,35 @@ protected: uint32_t stopStartTime = 0; // Время начала состояния CONNECT_IDLE const uint32_t stopTimeout = 300; // Таймаут для закрытия сокета в состоянии CONNECT_IDLE + std::function onSendSuccess = []() {}; + bool isNonBlocking = true; // Флаг для определения режима подключения ConnectionStatusSimple connectStatus = CONNECT_IDLE; -public: - using EthernetClient::EthernetClient; + uint8_t* dataPtr; + uint16_t dataSize = 0; + IPAddress dstIP; + uint16_t dstPort; + bool dataWrite(); + static std::vector instances; + void tick_(); +public: + EthernetMaketClient(); + EthernetMaketClient(uint8_t sock); + ~EthernetMaketClient(); ConnectionStatusSimple connectNonBlock(IPAddress ip, uint16_t port); - // void stop() override; void disconnect(); void close(); - void tick(); + + static void tick(); + bool send(uint8_t* data, uint16_t dataSize, IPAddress ip, uint16_t port); + + bool isConnected() const; + + void setOnSendSuccess(const std::function& callback); + void resetOnSendSuccess(); + bool dataWrite(uint8_t* data, uint16_t dataSize, bool override = false); }; -#endif // __MAKET_TCP_H__ \ No newline at end of file + +#endif // __MAKET_TCP_H__