diff --git a/src/EthernetOverride/TCP.cpp b/src/EthernetOverride/TCP.cpp index 8f9084d..3374820 100644 --- a/src/EthernetOverride/TCP.cpp +++ b/src/EthernetOverride/TCP.cpp @@ -2,335 +2,165 @@ #include "utility/w5500.h" #include "utility/socket.h" -//////////////////////////////////////////////////////////////// - - EthernetMaketClient::EthernetMaketClient() { _sock = MAX_SOCK_NUM; - // Serial.print("SOCK ?? "); Serial.println(_sock); } EthernetMaketClient::EthernetMaketClient(uint8_t sock) { _sock = sock; } + EthernetMaketClient::EthernetMaketClient(EthernetClient &client) { _sock = client.getSocketNumber(); } -void EthernetMaketClient::tick() - { - forEach( - [](EthernetMaketClient& obj) { - obj.tick_(); - } - ); +EthernetMaketClient& EthernetMaketClient::operator=(const EthernetMaketClient& other) { + if (this == &other) { + return *this; // Защита от самоприсваивания + } - } + this->lastActivityTime = other.lastActivityTime; + this->startConnectionTime = other.startConnectionTime; + this->stopStartTime = other.stopStartTime; + this->isNonBlocking = other.isNonBlocking; + this->connectStatus = other.connectStatus; + this->dstIP = other.dstIP; + this->dstPort = other.dstPort; + this->dataPtr = other.dataPtr; + this->dataSize = other.dataSize; + this->onSendSuccess = other.onSendSuccess; + this->_sock = other._sock; -//////////////////////////////////////////////////////////////// + const_cast(other).connectStatus = CONNECT_IDLE; + + return *this; +} ConnectionStatusSimple EthernetMaketClient::connectNonBlock(IPAddress ip, uint16_t port) { dstIP = ip; dstPort = port; - // if(connectStatus == CONNECT_IDLE){ - // connectStatus = CONNECT_START; - // } - if (_sock != MAX_SOCK_NUM) { uint8_t status_ = status(); switch (status_) { - case SnSR::CLOSED: - Serial.println(F("connectNonBlock(): CONNECT_FAIL (CLOSED)")); - _sock = MAX_SOCK_NUM; - return CONNECT_FAIL; - break; case SnSR::ESTABLISHED: - Serial.println(F("connectNonBlock(): CONNECT_SUCCESS (ESTABLISHED)")); + connectStatus = CONNECT_SUCCESS; return CONNECT_SUCCESS; + case SnSR::CLOSED: + case SnSR::CLOSE_WAIT: + close(); // Освобождаем сокет перед попыткой нового подключения break; default: - // Serial.println(F("connectNonBlock(): CONNECT_CONNECTING (Default)")); return CONNECT_CONNECTING; - break; } } for (int i = 0; i < MAX_SOCK_NUM; i++) { uint8_t s = w5500.readSnSR(i); - if (s == SnSR::CLOSED || s == SnSR::FIN_WAIT || s == SnSR::CLOSE_WAIT) { + if (s == SnSR::CLOSED || s == SnSR::CLOSE_WAIT) { _sock = i; - Serial.print("SOCK <- "); Serial.println(_sock); break; - - //todo if (s == SnSR::LISTEN){ выполнить приём и занять на время отправки сокет прослушивания } } } if (_sock == MAX_SOCK_NUM) { - Serial.println(F("connectNonBlock(): CONNECT_FAIL (No available socket)")); + connectStatus = CONNECT_FAIL; return CONNECT_FAIL; } - Serial.print("sock: "); - Serial.println(_sock); - _srcport++; if (_srcport == 0) _srcport = 1024; socket(_sock, SnMR::TCP, _srcport, 0); if (!::connect(_sock, rawIPAddress(ip), port)) { - Serial.println(F("connectNonBlock(): CONNECT_FAIL (Connect failed)")); _sock = MAX_SOCK_NUM; + connectStatus = CONNECT_FAIL; return CONNECT_FAIL; } - Serial.println(F("connectNonBlock(): CONNECT_CONNECTING (Connection initiated)")); + connectStatus = CONNECT_CONNECTING; return CONNECT_CONNECTING; } - -bool EthernetMaketClient::canWriteIntoConnection(size_t size) const { - return connectStatus == CONNECT_CONNECTED /* && w5500.getTXFreeSize(_sock) >= size */; -} - -void EthernetMaketClient::disconnect(){ - if (_sock == MAX_SOCK_NUM) - return; - ::disconnect(_sock); -} - -void EthernetMaketClient::close(){ - if (_sock == MAX_SOCK_NUM) - return; - ::close(_sock); - _sock = MAX_SOCK_NUM; -} - -void EthernetMaketClient::tick_(){ - // todo Переделать на нативные статусы. Избавиться от костылей - if(_sock != MAX_SOCK_NUM && connectStatus!=CONNECT_CONNECTED && connectStatus!=CONNECT_STOP_WAITING&&connectStatus!=CONNECT_CONNECTING){ - Serial.print("tick_() sock = "); Serial.print(_sock); - - uint8_t s = w5500.readSnSR(_sock); - String state = ""; - switch (s) { - //! костыли ^~^ - case SnSR::CLOSED : state = "CLOSED"; connectStatus = CONNECT_STOP_WAITING; break; - case SnSR::INIT : state = "INIT"; break; - case SnSR::LISTEN : state = "LISTEN"; break; - case SnSR::SYNSENT : state = "SYNSENT"; break; - case SnSR::SYNRECV : state = "SYNRECV"; break; - case SnSR::ESTABLISHED : state = "ESTABLISHED"; connectStatus = CONNECT_CONNECTED; break; - case SnSR::FIN_WAIT : state = "FIN_WAIT"; /* goto STOP_START_LABEL; */ break; - case SnSR::CLOSING : state = "CLOSING"; break; - case SnSR::TIME_WAIT : state = "TIME_WAIT"; break; - case SnSR::CLOSE_WAIT : state = "CLOSE_WAIT"; connectStatus = CONNECT_STOP_START; break; - case SnSR::LAST_ACK : state = "LAST_ACK"; break; - case SnSR::UDP : state = "UDP"; break; - case SnSR::IPRAW : state = "IPRAW"; break; - case SnSR::MACRAW : state = "MACRAW"; break; - case SnSR::PPPOE : state = "PPPOE"; break; - default : state = "UNKNOWN"; break; - } - String connectStatusStr = ""; - switch (connectStatus) { - case CONNECT_FAIL: connectStatusStr = "CONNECT_FAIL"; break; - case CONNECT_SUCCESS: connectStatusStr = "CONNECT_SUCCESS"; break; - case CONNECT_CONNECTING: connectStatusStr = "CONNECT_CONNECTING"; break; - case CONNECT_START: connectStatusStr = "CONNECT_START"; break; - case CONNECT_IDLE: connectStatusStr = "CONNECT_IDLE"; break; - case CONNECT_CONNECTED: connectStatusStr = "CONNECT_CONNECTED"; break; - case CONNECT_STOP_START: connectStatusStr = "CONNECT_STOP_START"; break; - case CONNECT_STOP_WAITING: connectStatusStr = "CONNECT_STOP_WAITING"; break; - default: connectStatusStr = "UNKNOWN"; break; - } - Serial.print(" state = "); - Serial.print(state); - Serial.print(" connectStatus = "); - Serial.print(connectStatusStr); - Serial.println(); +void EthernetMaketClient::tick_() { + if (_sock == MAX_SOCK_NUM) { + connectStatus = CONNECT_IDLE; + return; } -//todo [] Пересмотреть стейт машину перевести на нативные статусы - SWITCHLOOP: - switch (connectStatus) - { - case CONNECT_START: - { - Serial.println("CONNECT_START"); - startConnectionTime = millis(); - connectStatus = CONNECT_CONNECTING; + uint8_t s = w5500.readSnSR(_sock); + + switch (s) { + case SnSR::CLOSED: + connectStatus = (connectStatus == CONNECT_CONNECTING) ? CONNECT_FAIL : CONNECT_STOP_WAITING; close(); - Serial.println("CONNECT_CONNECTING..."); - for (int i = 0; i < MAX_SOCK_NUM; i++) { - uint8_t s = w5500.readSnSR(i); - String state = ""; - switch (s) { - case SnSR::CLOSED : state = "CLOSED"; break; - case SnSR::INIT : state = "INIT"; break; - case SnSR::LISTEN : state = "LISTEN"; break; - case SnSR::SYNSENT : state = "SYNSENT"; break; - case SnSR::SYNRECV : state = "SYNRECV"; break; - case SnSR::ESTABLISHED : state = "ESTABLISHED"; break; - case SnSR::FIN_WAIT : state = "FIN_WAIT"; break; - case SnSR::CLOSING : state = "CLOSING"; break; - case SnSR::TIME_WAIT : state = "TIME_WAIT"; break; - case SnSR::CLOSE_WAIT : state = "CLOSE_WAIT"; break; - case SnSR::LAST_ACK : state = "LAST_ACK"; break; - case SnSR::UDP : state = "UDP"; break; - case SnSR::IPRAW : state = "IPRAW"; break; - case SnSR::MACRAW : state = "MACRAW"; break; - case SnSR::PPPOE : state = "PPPOE"; break; - default: state = "UNKNOWN"; break; - } - - Serial.print("SOCK <- "); - Serial.print(i); - Serial.print(" State: "); - Serial.println(state); - } - goto SWITCHLOOP; - } - break; - case CONNECT_CONNECTING: - if (millis() - startConnectionTime >= connectionTimeout) - { - connectStatus = CONNECT_FAIL; - goto SWITCHLOOP; break; - } - break; - case CONNECT_FAIL: - Serial.println("CONNECT_FAIL"); - Serial.print("Failed to connect to server in "); - Serial.println(isNonBlocking ? "non-blocking mode" : "blocking mode"); - Serial.println("\n"); - connectStatus = CONNECT_STOP_START; - goto SWITCHLOOP; - break; - case CONNECT_SUCCESS: - Serial.println("CONNECT_SUCCESS"); - Serial.print("Connected to server in "); - Serial.println(isNonBlocking ? "non-blocking mode" : "blocking mode"); - activityUpdate(); - connectStatus = CONNECT_CONNECTED; - goto SWITCHLOOP; - break; - case CONNECT_CONNECTED: - - //! Передача пакетов - dataWrite(); - //! Передача завершена - - if (!connected()) - { - Serial.println("Client disconnected"); - connectStatus = CONNECT_STOP_START; - goto SWITCHLOOP; - } - - // Закрытие соединения по таймеру неактивности - if (connected() && (millis() - lastActivityTime > timeout)) - { - Serial.println("Connection closed due to inactivity"); - connectStatus = CONNECT_STOP_START; - goto SWITCHLOOP; - } - break; - - case CONNECT_STOP_START: - disconnect(); - STOP_START_LABEL: - Serial.println("CONNECT_STOP_START"); - dstIP = IPAddress(0,0,0,0); - dstPort = 0; - stopStartTime = millis(); - connectStatus = CONNECT_STOP_WAITING; - Serial.println("CONNECT_STOP_WAITING"); - goto SWITCHLOOP; - break; - - case CONNECT_STOP_WAITING: - if (millis() - stopStartTime >= stopTimeout) { - close(); // Окончательное закрытие сокета после таймаута - connectStatus = CONNECT_IDLE; - } else { - // Проверяем состояние сокета для завершения разрыва - uint8_t status_ = status(); - if (status_ == SnSR::CLOSED || status_ == SnSR::CLOSE_WAIT) { - close(); // Закрываем при достижении состояния - connectStatus = CONNECT_IDLE; + case SnSR::ESTABLISHED: + if (connectStatus != CONNECT_CONNECTED) { + connectStatus = CONNECT_SUCCESS; } - } - if(connectStatus == CONNECT_IDLE) { - Serial.println("CONNECT_IDLE\n\n"); - goto SWITCHLOOP; - } - // //! Костыль, блокирует на время ожидания стопа подобно while(millis() - stopStartTime < stopTimeout) - goto SWITCHLOOP; - break; - - case CONNECT_IDLE: - // if(dataSize){ - // connectStatus = CONNECT_START; - // } - break; - - default: - break; + break; + case SnSR::CLOSE_WAIT: + connectStatus = CONNECT_STOP_START; + disconnect(); + break; + case SnSR::FIN_WAIT: + case SnSR::CLOSING: + case SnSR::TIME_WAIT: + case SnSR::LAST_ACK: + close(); + connectStatus = CONNECT_STOP_WAITING; + break; + default: + break; } -//******************************************************** - switch (connectStatus) - { - case CONNECT_START: - case CONNECT_CONNECTING: - if (isNonBlocking) - { - connectStatus = connectNonBlock(dstIP, dstPort); - } - else - { - connectStatus = (ConnectionStatusSimple)connect(dstIP, dstPort); - } - break; - default: - break; + // Проверка активности и таймаутов + if (connectStatus == CONNECT_CONNECTED) { + if (millis() - lastActivityTime > timeout) { + connectStatus = CONNECT_STOP_START; + disconnect(); + } + } else if (connectStatus == CONNECT_CONNECTING) { + if (millis() - startConnectionTime >= connectionTimeout) { + connectStatus = CONNECT_FAIL; + close(); + } } -//******************************************************** - - // //? [*] Проверка наличия доступных данных от сервера - // //? проверяется во вне - // if (available() > 0) - // { - - // } - // //? ------------------------------------------------- } -bool EthernetMaketClient::dataWrite(){ - bool ret = false; - if(dataSize) { - lastActivityTime = millis(); - if(write(dataPtr, dataSize)){ - clearData(); - ret = true; - } - lastActivityTime = millis(); +void EthernetMaketClient::disconnect() { + if (_sock != MAX_SOCK_NUM) { + ::disconnect(_sock); } - if(ret){ +} + +void EthernetMaketClient::close() { + if (_sock != MAX_SOCK_NUM) { + ::close(_sock); + _sock = MAX_SOCK_NUM; + } +} + +void EthernetMaketClient::startConnection(IPAddress ip, uint16_t port, bool nonBlock) { + dstIP = ip; + dstPort = port; + isNonBlocking = nonBlock; + connectStatus = CONNECT_START; + startConnectionTime = millis(); +} + +bool EthernetMaketClient::dataWrite() { + if (!canWriteIntoConnection(dataSize)) return false; + + if (write(dataPtr, dataSize)) { + clearData(); + lastActivityTime = millis(); onSendSuccess(); + return true; } - return ret; -} -void EthernetMaketClient::clearData(){ - this->dataPtr = nullptr; - this->dataSize = 0; -} -bool EthernetMaketClient::isDataEmpty() const{ - return this->dataPtr == nullptr; + return false; } void EthernetMaketClient::dataWrite(uint8_t* data, uint16_t dataSize, bool override) { @@ -338,17 +168,30 @@ void EthernetMaketClient::dataWrite(uint8_t* data, uint16_t dataSize, bool overr this->dataPtr = data; this->dataSize = dataSize; activityUpdate(); - Serial.println("Data buffer Saved."); - // if(canWrite(dataSize)){ - // dataWrite(); - // } else { - // Serial.println("W5500 Buffer is full. Write operation is ignored."); - // } } else { Serial.println("Data buffer is not empty. Write operation is ignored."); } } +void EthernetMaketClient::clearData() { + this->dataPtr = nullptr; + this->dataSize = 0; +} + +bool EthernetMaketClient::isDataEmpty() const { + return this->dataPtr == nullptr; +} + +bool EthernetMaketClient::canWriteIntoConnection(size_t size) const { + return (connectStatus == CONNECT_CONNECTED) && (w5500.getTXFreeSize(_sock) >= size); +} + +void EthernetMaketClient::tick() { + forEach([](EthernetMaketClient &client) { + client.tick_(); + }); +} + void EthernetMaketClient::setOnSendSuccess(const std::function& callback) { onSendSuccess = callback; } @@ -357,50 +200,14 @@ void EthernetMaketClient::resetOnSendSuccess() { onSendSuccess = []() {}; } -void EthernetMaketClient::stop(){ - // if(connectStatus!=CONNECT_STOP_WAITING) +void EthernetMaketClient::stop() { connectStatus = CONNECT_STOP_START; } -void EthernetMaketClient::startConnection(IPAddress ip, uint16_t port, bool nonBlock){ - dstIP = ip; - dstPort = port; - isNonBlocking = nonBlock; - connectStatus = CONNECT_START; -}; - -void EthernetMaketClient::activityUpdate(){ - lastActivityTime = millis(); -} - -EthernetMaketClient& EthernetMaketClient::operator=(const EthernetMaketClient& other) { - if (this == &other) { - return *this; // Защита от самоприсваивания - } - - // Копируем все данные - this->lastActivityTime = other.lastActivityTime; - this->startConnectionTime = other.startConnectionTime; - this->stopStartTime = other.stopStartTime; - this->isNonBlocking = other.isNonBlocking; - this->connectStatus = other.connectStatus; - // this->timeout = other.timeout; - // this->connectionTimeout = other.connectionTimeout; - // this->stopTimeout = other.stopTimeout; - this->dstIP = other.dstIP; - this->dstPort = other.dstPort; - this->dataPtr = other.dataPtr; - this->dataSize = other.dataSize; - this->onSendSuccess = other.onSendSuccess; - - this->_sock = other._sock; - - // Отключаем исполнение старого клиента - const_cast(other).connectStatus = CONNECT_IDLE; - - return *this; -} - ConnectionStatusSimple EthernetMaketClient::getConnectionStatus() const { return connectStatus; } + +void EthernetMaketClient::activityUpdate() { + lastActivityTime = millis(); +}