From eee3b84b8e4892efcfe496726880d0ca90413841 Mon Sep 17 00:00:00 2001 From: DashyFox Date: Wed, 20 Nov 2024 15:22:17 +0300 Subject: [PATCH] Procedural reference --- examples/ProceduralClient/.gitignore | 1 + examples/ProceduralClient/README.md | 61 +++++ .../examples/Client/Client.ino | 216 ++++++++++++++++++ examples/ProceduralClient/library.properties | 10 + examples/ProceduralClient/src/EthernetMaket.h | 24 ++ .../src/EthernetOverride/Server.cpp | 64 ++++++ .../src/EthernetOverride/Server.h | 24 ++ .../src/EthernetOverride/TCP.cpp | 86 +++++++ .../src/EthernetOverride/TCP.h | 17 ++ .../src/EthernetOverride/UDP.cpp | 62 +++++ .../src/EthernetOverride/UDP.h | 15 ++ 11 files changed, 580 insertions(+) create mode 100644 examples/ProceduralClient/.gitignore create mode 100644 examples/ProceduralClient/README.md create mode 100644 examples/ProceduralClient/examples/Client/Client.ino create mode 100644 examples/ProceduralClient/library.properties create mode 100644 examples/ProceduralClient/src/EthernetMaket.h create mode 100644 examples/ProceduralClient/src/EthernetOverride/Server.cpp create mode 100644 examples/ProceduralClient/src/EthernetOverride/Server.h create mode 100644 examples/ProceduralClient/src/EthernetOverride/TCP.cpp create mode 100644 examples/ProceduralClient/src/EthernetOverride/TCP.h create mode 100644 examples/ProceduralClient/src/EthernetOverride/UDP.cpp create mode 100644 examples/ProceduralClient/src/EthernetOverride/UDP.h diff --git a/examples/ProceduralClient/.gitignore b/examples/ProceduralClient/.gitignore new file mode 100644 index 0000000..508d4e4 --- /dev/null +++ b/examples/ProceduralClient/.gitignore @@ -0,0 +1 @@ +**.vscode \ No newline at end of file diff --git a/examples/ProceduralClient/README.md b/examples/ProceduralClient/README.md new file mode 100644 index 0000000..3be4b5e --- /dev/null +++ b/examples/ProceduralClient/README.md @@ -0,0 +1,61 @@ +## Внесение изменений для совместимости + +Для обеспечения совместимости с библиотекой `Ethernet3` потребуется внести изменения в файлы `EthernetClient.h` и `EthernetUdp3.h`. Следуйте инструкциям ниже. + +### Изменение в `EthernetClient.h` + +В файле `EthernetClient.h` замените доступ к переменным с `private` на `protected` для следующих элементов: + +```cpp +class EthernetClient : public Client { + // ... +protected: // <--- замените 'private' на 'protected' + static uint16_t _srcport; + uint8_t _sock; +}; +``` + +### Изменение в `EthernetUdp3.h` + +В файле `EthernetUdp3.h` также замените доступ к переменным с `private` на `protected`: + +```cpp +class EthernetUDP : public UDP { +protected: // <--- замените 'private' на 'protected' + uint8_t _sock; // socket ID for Wiz5100 + // ... +}; +``` + +### Изменение в `EthernetServer.h` + +В файле `EthernetServer.h` также замените доступ к переменным с `private` на `protected`: + +```cpp +class EthernetServer : +public Server { +protected: // <--- замените 'private' на 'protected' + uint16_t _port; + void accept(); +//... +}; +``` + +Эти изменения необходимы для обеспечения доступа к соответствующим членам класса при наследовании. + +## Обратите внимание + +При работе с библиотекой `Ethernet3` версии 3 требуется отдельно указывать CS пин для инициализации. Пример кода: + +```cpp +void setup() { + // ... + Ethernet.setCsPin(W5500_CS_PIN); + Ethernet.init(); + Ethernet.begin(mac, localIP, gateway, gateway, subnet); + // ... +} +``` + +Не забудьте правильно настроить `W5500_CS_PIN` и сетевые параметры (`mac`, `localIP`, `gateway`, `subnet`) в зависимости от вашей конфигурации. +``` \ No newline at end of file diff --git a/examples/ProceduralClient/examples/Client/Client.ino b/examples/ProceduralClient/examples/Client/Client.ino new file mode 100644 index 0000000..6884020 --- /dev/null +++ b/examples/ProceduralClient/examples/Client/Client.ino @@ -0,0 +1,216 @@ +#include "EthernetMaket.h" // Предполагается, что этот файл подключает Ethernet3.h + +// Настройки для W5500 +#define W5500_CS_PIN PA2 // Пин для CS +#define SOCKET_NUMBER 0 // Используем сокет 0 +#define SERVER_PORT 1337 // Порт на сервере +#define CLIENT_PORT 1337 // Порт клиента + +#define ServerMac {0xDA, 0x7A, 0xFF, 0x00, 0x00, 0x00} +#define ServerIP {192, 168, 254, 254} + +#define IniMac {0xDA, 0x7A, 0xF0, 0x00, 0x00, 0x00} +#define IniIP {192, 168, 254, 253} + +uint8_t gateway[] = {192, 168, 0, 1}; // Шлюз +uint8_t subnet[] = {255, 255, 0, 0}; // Маска подсети + +uint8_t mac[] = IniMac; // MAC-адрес +uint8_t localIP[] = IniIP; // Локальный IP-адрес + +uint8_t serverMac[] = ServerMac; // MAC-адрес сервера +uint8_t serverIP[] = ServerIP; // IP-адрес сервера + +uint8_t buf[512]; // Буфер для передачи данных + +uint32_t previousMillis = 0; // Для хранения времени последней отправки +const long interval = 3750; // Интервал отправки данных (1.75 секунды) +uint32_t ttt; + +EthernetServer server(SERVER_PORT); +EthernetMaketClient client; + +// EthernetMaketClient c; + +uint32_t packetCounter = 0; + +uint32_t lastActivityTime = 0; // Время последней активности +const uint16_t timeout = 300; // Таймаут неактивности в миллисекундах +uint32_t startConnection = 0; +const uint16_t connectionTimeout = 350; + +uint32_t stopStartTime = 0; // Время начала состояния CONNECT_IDLE +const uint32_t stopTimeout = 300; // Таймаут для закрытия сокета в состоянии CONNECT_IDLE + +void setup() +{ + Serial.begin(115200); + pinMode(LED_BUILTIN, OUTPUT); + Ethernet.setCsPin(W5500_CS_PIN); + Ethernet.init(); + + // Настройка Ethernet с указанием статических параметров + Ethernet.begin(mac, localIP, subnet, gateway, gateway); + + // Ethernet.setRtTimeOut(1000 * 10); + // Ethernet.setRtCount(3); + + // client.setNoDelayedACK(true); // Не ждать ответа от сервера +} + +ConnectionStatusSimple connectStatus = CONNECT_IDLE; +void loop() +{ + uint32_t currentMillis = millis(); + if (currentMillis - ttt > 75) + { + digitalToggle(PC13); + ttt = currentMillis; // Обновляем время + } + + if (currentMillis - previousMillis >= interval) + { + previousMillis = currentMillis; + // client.stop(); // Завершаем предыдущее соединение + connectStatus = CONNECT_START; + } + + // Подключаемся к серверу + + bool isNonBlocking = true; // Флаг для определения режима подключения + + switch (connectStatus) + { + case CONNECT_START: + startConnection = millis(); + connectStatus = CONNECT_CONNECTING; + client.close(); + Serial.println("\n\nConnecting..."); + break; + case CONNECT_CONNECTING: + if (millis() - startConnection >= connectionTimeout) + { + connectStatus = CONNECT_FAIL; + break; + } + break; + case CONNECT_FAIL: + Serial.print("Failed to connect to server in "); + Serial.println(isNonBlocking ? "non-blocking mode" : "blocking mode"); + connectStatus = CONNECT_STOP_START; + break; + case CONNECT_SUCCESS: + Serial.print("Connected to server in "); + Serial.println(isNonBlocking ? "non-blocking mode" : "blocking mode"); + 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(); // Обновляем время последней активности для каждого пакета + } + //! Передача завершена + + break; + case CONNECT_CONNECTED: + if (!client.connected()) + { + Serial.println("Client disconnected"); + connectStatus = CONNECT_STOP_START; + } + + // Закрытие соединения по таймеру неактивности + if (client.connected() && (millis() - lastActivityTime > timeout)) + { + Serial.println("Connection closed due to inactivity"); + connectStatus = CONNECT_STOP_START; + } + break; + + case CONNECT_STOP_START: + client.disconnect(); + stopStartTime = millis(); + connectStatus = CONNECT_STOP_WAITING; + break; + + case CONNECT_STOP_WAITING: + if (millis() - stopStartTime >= stopTimeout) + { + client.close(); // Закрываем сокет после таймаута + connectStatus = CONNECT_IDLE; + } + break; + + default: + break; + } + + switch (connectStatus) + { + case CONNECT_START: + case CONNECT_CONNECTING: + if (isNonBlocking) + { + connectStatus = client.connectNonBlock(serverIP, SERVER_PORT); + } + else + { + connectStatus = (ConnectionStatusSimple)client.connect(serverIP, SERVER_PORT); + } + break; + + default: + break; + } + + //? Проверка наличия доступных данных от сервера + if (client.available() > 0) + { + byte response[16]; + int len = client.read(response, sizeof(response)); + + if (len == 16) + { + // Проверка контрольной суммы + uint8_t checksum = 0; + for (int i = 0; i < 15; i++) + { + checksum += response[i]; + } + + Serial.print("RX: "); + for (int i = 0; i < 16; i++) + { + Serial.print(response[i], HEX); + Serial.print(" "); + } + + if (response[15] == checksum) + { + Serial.println("Checksum is OK"); + } + else + { + Serial.println("Checksum is ERROR"); + } + lastActivityTime = millis(); // Обновляем время последней активности + } + else + { + Serial.println("Received an incomplete response"); + } + } + //? ------------------------------------------------- +} \ No newline at end of file diff --git a/examples/ProceduralClient/library.properties b/examples/ProceduralClient/library.properties new file mode 100644 index 0000000..16ebceb --- /dev/null +++ b/examples/ProceduralClient/library.properties @@ -0,0 +1,10 @@ +name=MaketEthernet +version=1.0.0 +author=DashyFox +maintainer=DashyFox@yandex.ru +sentence= +paragraph= +category=Other +url= +architectures=* +includes=CEthernetMaket.h diff --git a/examples/ProceduralClient/src/EthernetMaket.h b/examples/ProceduralClient/src/EthernetMaket.h new file mode 100644 index 0000000..be52b61 --- /dev/null +++ b/examples/ProceduralClient/src/EthernetMaket.h @@ -0,0 +1,24 @@ +#ifndef __ETHERNETMAKET_H__ +#define __ETHERNETMAKET_H__ + +#include "Ethernet3.h" + + + +enum ConnectionStatusSimple{ + CONNECT_FAIL = 0, + CONNECT_SUCCESS = 1, + CONNECT_CONNECTING = 2, + CONNECT_START = 3, + CONNECT_IDLE = 4, + CONNECT_CONNECTED = 5, + CONNECT_STOP_START = 6, + CONNECT_STOP_WAITING = 7, +}; + + + +#include "EthernetOverride/TCP.h" + + +#endif // __ETHERNETMAKET_H__ \ No newline at end of file diff --git a/examples/ProceduralClient/src/EthernetOverride/Server.cpp b/examples/ProceduralClient/src/EthernetOverride/Server.cpp new file mode 100644 index 0000000..adf374d --- /dev/null +++ b/examples/ProceduralClient/src/EthernetOverride/Server.cpp @@ -0,0 +1,64 @@ +#include "Server.h" +#include "utility/w5500.h" +#include "utility/socket.h" + +void EthernetMaketServer::setServerHandler(std::function handler) +{ + serverHandler = handler; +} + +void EthernetMaketServer::resetServerHandler() +{ + serverHandler = [](EthernetMaketClient sclient) {}; +} + +EthernetMaketClient EthernetMaketServer::available(int sock) +{ + accept(sock); + EthernetMaketClient client(sock); + if (EthernetClass::_server_port[sock] == _port && + (client.status() == SnSR::ESTABLISHED || + client.status() == SnSR::CLOSE_WAIT)) + { + if (client.available()) + { + return client; + } + } + return EthernetMaketClient(MAX_SOCK_NUM); +} + +void EthernetMaketServer::accept(int sock) +{ + int listening = 0; + EthernetClient client(sock); + + if (EthernetClass::_server_port[sock] == _port) + { + if (client.status() == SnSR::LISTEN) + { + listening = 1; + } + else if (client.status() == SnSR::CLOSE_WAIT && !client.available()) + { + client.stop(); + } + } + + if (!listening) + { + // begin(); + begin(sock); // added + } +} + +void EthernetMaketServer::begin(int sock) +{ + EthernetClient client(sock); + if (client.status() == SnSR::CLOSED) + { + socket(sock, SnMR::TCP, _port, 0); + listen(sock); + EthernetClass::_server_port[sock] = _port; + } +} \ No newline at end of file diff --git a/examples/ProceduralClient/src/EthernetOverride/Server.h b/examples/ProceduralClient/src/EthernetOverride/Server.h new file mode 100644 index 0000000..239d5e0 --- /dev/null +++ b/examples/ProceduralClient/src/EthernetOverride/Server.h @@ -0,0 +1,24 @@ +#ifndef __MAKET_SERVER_H__ +#define __MAKET_SERVER_H__ + +#include "Ethernet3.h" +#include "TCP.h" +#include + +class EthernetMaketServer : EthernetServer +{ +private: + EthernetClient available(); + void accept(int sock); + std::function serverHandler = [](EthernetMaketClient sclient){}; + +public: + using EthernetServer::EthernetServer; + EthernetMaketClient available(int sock); + + void setServerHandler(std::function handler); + void resetServerHandler(); + void begin(int sock); +}; + +#endif // __MAKET_SERVER_H__ diff --git a/examples/ProceduralClient/src/EthernetOverride/TCP.cpp b/examples/ProceduralClient/src/EthernetOverride/TCP.cpp new file mode 100644 index 0000000..567d5bd --- /dev/null +++ b/examples/ProceduralClient/src/EthernetOverride/TCP.cpp @@ -0,0 +1,86 @@ +#include "TCP.h" +#include "utility/w5500.h" +#include "utility/socket.h" + +ConnectionStatusSimple EthernetMaketClient::connectNonBlock(IPAddress ip, uint16_t port) { + + if (_sock != MAX_SOCK_NUM) { + // Serial.println(F("connectNonBlock")); + uint8_t status_ = status(); + switch (status_) { + case SnSR::CLOSED: + // Serial.println(F("CLOSED")); + _sock = MAX_SOCK_NUM; + return CONNECT_FAIL; + break; + case SnSR::ESTABLISHED: + // Serial.println(F("ESTABLISHED")); + return CONNECT_SUCCESS; + break; + default: + // Serial.print(F("status ")); + // Serial.println(status_,HEX); + 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; + break; + } + } + + if (_sock == MAX_SOCK_NUM) + return CONNECT_FAIL; + + _srcport++; + if (_srcport == 0) _srcport = 1024; + socket(_sock, SnMR::TCP, _srcport, 0); + + if (!::connect(_sock, rawIPAddress(ip), port)) { + _sock = MAX_SOCK_NUM; + return CONNECT_FAIL; + } + + return CONNECT_CONNECTING; +} + +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::stop() { +// if (_sock == MAX_SOCK_NUM) +// return; + +// // attempt to close the connection gracefully (send a FIN to other side) +// disconnect(_sock); +// unsigned long start = millis(); + +// // wait a second for the connection to close +// uint8_t s; +// do { +// s = status(); +// if (s == SnSR::CLOSED) +// break; // exit the loop +// delay(1); +// } while (millis() - start < 1000); + +// // if it hasn't closed, close it forcefully +// if (status() != SnSR::CLOSED) +// close(_sock); + +// EthernetClass::_server_port[_sock] = 0; +// _sock = MAX_SOCK_NUM; +// } diff --git a/examples/ProceduralClient/src/EthernetOverride/TCP.h b/examples/ProceduralClient/src/EthernetOverride/TCP.h new file mode 100644 index 0000000..9609053 --- /dev/null +++ b/examples/ProceduralClient/src/EthernetOverride/TCP.h @@ -0,0 +1,17 @@ +#ifndef __MAKET_TCP_H__ +#define __MAKET_TCP_H__ + +#include "../EthernetMaket.h" + +class EthernetMaketClient : public EthernetClient +{ +public: + using EthernetClient::EthernetClient; + + ConnectionStatusSimple connectNonBlock(IPAddress ip, uint16_t port); + // void stop() override; + void disconnect(); + void close(); + +}; +#endif // __MAKET_TCP_H__ \ No newline at end of file diff --git a/examples/ProceduralClient/src/EthernetOverride/UDP.cpp b/examples/ProceduralClient/src/EthernetOverride/UDP.cpp new file mode 100644 index 0000000..b934d47 --- /dev/null +++ b/examples/ProceduralClient/src/EthernetOverride/UDP.cpp @@ -0,0 +1,62 @@ +#include "UDP.h" + +#include "utility/w5500.h" +#include "utility/socket.h" + +void sendUDP_tick(SOCKET s, ConnectionStatusSimple &status) +{ + switch (status) + { + case CONNECT_START: + w5500.execCmdSn(s, Sock_SEND); + status = CONNECT_CONNECTING; + break; + + case CONNECT_CONNECTING: + if ((w5500.readSnIR(s) & SnIR::SEND_OK) != SnIR::SEND_OK) + { + if (w5500.readSnIR(s) & SnIR::TIMEOUT) + { + /* +2008.01 [bj]: clear interrupt */ + w5500.writeSnIR(s, (SnIR::SEND_OK | SnIR::TIMEOUT)); + status = CONNECT_FAIL; + break; + } + else + { + status = CONNECT_CONNECTING; + break; + } + } + else + { + status = CONNECT_SUCCESS; + w5500.writeSnIR(s, SnIR::SEND_OK); + break; + } + break; + + case CONNECT_FAIL: + status = CONNECT_IDLE; + break; + case CONNECT_SUCCESS: + status = CONNECT_IDLE; + break; + case CONNECT_IDLE: + break; + + default: + break; + } +} + +void EthernetMaketUDP::endPacketNonBlock() +{ + _status = CONNECT_START; + sendUDP_tick(_sock, _status); + return; +} + +void EthernetMaketUDP::tick(){ + sendUDP_tick(_sock, _status); +} diff --git a/examples/ProceduralClient/src/EthernetOverride/UDP.h b/examples/ProceduralClient/src/EthernetOverride/UDP.h new file mode 100644 index 0000000..a720f01 --- /dev/null +++ b/examples/ProceduralClient/src/EthernetOverride/UDP.h @@ -0,0 +1,15 @@ +#ifndef __MAKET_UDP_H__ +#define __MAKET_UDP_H__ + +#include "../EthernetMaket.h" +class EthernetMaketUDP : EthernetUDP +{ +private: + ConnectionStatusSimple _status; // статус соединения +public: + using EthernetUDP::EthernetUDP; + void endPacketNonBlock(); + void tick(); +}; + +#endif // __MAKET_UDP_H__ \ No newline at end of file