#include "TCP.h" #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_(); } ); } //////////////////////////////////////////////////////////////// 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)")); return CONNECT_SUCCESS; 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) { _sock = i; Serial.print("SOCK <- "); Serial.println(_sock); break; } } if (_sock == MAX_SOCK_NUM) { Serial.println(F("connectNonBlock(): CONNECT_FAIL (No available socket)")); 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; return CONNECT_FAIL; } Serial.println(F("connectNonBlock(): CONNECT_CONNECTING (Connection initiated)")); 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_(){ if(_sock != MAX_SOCK_NUM && connectStatus!=CONNECT_CONNECTED && connectStatus!=CONNECT_STOP_WAITING&&connectStatus!=CONNECT_CONNECTING){ Serial.print("tick_() sock = "); Serial.println(_sock); } switch (connectStatus) { case CONNECT_START: Serial.println("CONNECT_START"); startConnectionTime = millis(); connectStatus = CONNECT_CONNECTING; 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 0x00: state = "CLOSED"; break; case 0x13: state = "INIT"; break; case 0x14: state = "LISTEN"; break; case 0x15: state = "SYNSENT"; break; case 0x16: state = "SYNRECV"; break; case 0x17: state = "ESTABLISHED"; break; case 0x18: state = "FIN_WAIT"; break; case 0x1A: state = "CLOSING"; break; case 0x1B: state = "TIME_WAIT"; break; case 0x1C: state = "CLOSE_WAIT"; break; case 0x1D: state = "LAST_ACK"; break; case 0x22: state = "UDP"; break; case 0x32: state = "IPRAW"; break; case 0x42: state = "MACRAW"; break; case 0x5F: state = "PPPOE"; break; default: state = "UNKNOWN"; break; } Serial.print("SOCK <- "); Serial.print(i); Serial.print(" State: "); Serial.println(state); } } break; case CONNECT_CONNECTING: if (millis() - startConnectionTime >= connectionTimeout) { connectStatus = CONNECT_FAIL; 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; break; case CONNECT_SUCCESS: Serial.println("CONNECT_SUCCESS"); Serial.print("Connected to server in "); Serial.println(isNonBlocking ? "non-blocking mode" : "blocking mode"); lastActivityTime = millis(); connectStatus = CONNECT_CONNECTED; lastActivityTime = millis(); // Обновляем время последней активности break; case CONNECT_CONNECTED: //! Передача пакетов dataWrite(); //! Передача завершена if (!connected()) { Serial.println("Client disconnected"); connectStatus = CONNECT_STOP_START; } // Закрытие соединения по таймеру неактивности if (connected() && (millis() - lastActivityTime > timeout)) { Serial.println("Connection closed due to inactivity"); connectStatus = CONNECT_STOP_START; } break; case CONNECT_STOP_START: Serial.println("CONNECT_STOP_START"); dstIP = IPAddress(0,0,0,0); dstPort = 0; disconnect(); stopStartTime = millis(); connectStatus = CONNECT_STOP_WAITING; Serial.println("CONNECT_STOP_WAITING"); 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; } } if(connectStatus == CONNECT_IDLE) { Serial.println("CONNECT_IDLE\n\n"); } break; case CONNECT_IDLE: // if(dataSize){ // connectStatus = CONNECT_START; // } 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 (available() > 0) // { // } // //? ------------------------------------------------- } bool EthernetMaketClient::dataWrite(){ bool ret = false; if(dataSize) { lastActivityTime = millis(); if(write(dataPtr, dataSize)){ clearData(); ret = true; } lastActivityTime = millis(); } if(ret){ onSendSuccess(); } return ret; } void EthernetMaketClient::clearData(){ this->dataPtr = nullptr; this->dataSize = 0; } bool EthernetMaketClient::isDataEmpty() const{ return this->dataPtr == nullptr; } void EthernetMaketClient::dataWrite(uint8_t* data, uint16_t dataSize, bool override) { if (this->dataPtr == nullptr || override) { 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."); } } // bool EthernetMaketClient::send(uint8_t* data, uint16_t dataSize, IPAddress ip, uint16_t port) { // this->dataPtr = data; // this->dataSize = dataSize; // dstIP = ip; // dstPort = port; // 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; // Пока ждём подключения // } // return false; // } void EthernetMaketClient::setOnSendSuccess(const std::function& callback) { onSendSuccess = callback; } void EthernetMaketClient::resetOnSendSuccess() { onSendSuccess = []() {}; } 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; // if (nonBlock) // { // connectNonBlock(dstIP, dstPort); // } // else // { // (ConnectionStatusSimple)connect(dstIP, dstPort); // } }; 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; // Отключаем исполнение старого клиента const_cast(other).connectStatus = CONNECT_IDLE; return *this; } ConnectionStatusSimple EthernetMaketClient::getConnectionStatus() const { return connectStatus; }