diff --git a/CMakeLists.txt b/CMakeLists.txt index a42664e..b0e7354 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,7 @@ project(eMQTT5) option(REDUCED_FOOTPRINT "Whether to enable reduced footprint for the client code" ON) option(CROSSPLATFORM_SOCKET "Whether to use cross plaftform socket code (this disable SSL)" OFF) option(ENABLE_TLS "Whether to enable TLS/SSL code (you'll need MBedTLS available)" OFF) +option(LOW_LATENCY "Whether to enable low latency code (at the cost of higher CPU usage)" OFF) if (CROSSPLATFORM_SOCKET STREQUAL OFF AND ENABLE_TLS STREQUAL ON) message(WARNING "As of 06/28/2020, MBedTLS is not correctly CMake compatible and does not generate a mbedtls-config.cmake file. You'll need to apply the patch from my branch found in pull request #3465") diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index f4cdc2a..bede6cf 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -20,7 +20,8 @@ ENDIF() target_compile_definitions(eMQTT5 PUBLIC _DEBUG=$ MinimalFootPrint=$ MQTTOnlyBSDSocket=$ - MQTTUseTLS=$,$>) + MQTTUseTLS=$,$> + MQTTLowLatency=$) IF (WIN32) ELSE() diff --git a/lib/include/Network/Clients/MQTTConfig.hpp b/lib/include/Network/Clients/MQTTConfig.hpp index 0ed65e8..32d4971 100644 --- a/lib/include/Network/Clients/MQTTConfig.hpp +++ b/lib/include/Network/Clients/MQTTConfig.hpp @@ -62,6 +62,19 @@ #define MQTTOnlyBSDSocket 1 #endif +/** Low latency mode + If set to 1, this will only wait on the receiving socket in a non blocking fashion. + You'll use this if you need to do other processing in your main application loop. It reduces latency for your + other application code at the cost of increased CPU usage since the loop time will decrease from the default + timeout set to mainly the duration of a system call. + + This allow implies you provide a BSD compatible select function for the socket implementation. + + Default: 0 */ +#ifndef MQTTLowLatency + #define MQTTLowLatency 0 +#endif + // The part below is for building only, it's made to generate a message so the configuration is visible at build time #if _DEBUG == 1 #if MQTTUseAuth == 1 @@ -95,13 +108,21 @@ #define CONF_TLS "_" #endif + #if MQTTLowLatency == 1 + #define CONF_LL "LL_" + #else + #define CONF_LL "_" + #endif + #if MQTTOnlyBSDSocket == 1 #define CONF_SOCKET "BSD" #else #define CONF_SOCKET "CP" #endif - #pragma message("Building eMQTT5 with flags: " CONF_AUTH CONF_UNSUB CONF_DUMP CONF_VALID CONF_TLS CONF_SOCKET) + + + #pragma message("Building eMQTT5 with flags: " CONF_AUTH CONF_UNSUB CONF_DUMP CONF_VALID CONF_TLS CONF_LL CONF_SOCKET) #endif #endif diff --git a/lib/src/Network/Clients/MQTTClient.cpp b/lib/src/Network/Clients/MQTTClient.cpp index 1b93529..9ad16e8 100644 --- a/lib/src/Network/Clients/MQTTClient.cpp +++ b/lib/src/Network/Clients/MQTTClient.cpp @@ -175,7 +175,7 @@ namespace Network { namespace Client { @retval 0 Protocol error, you should close the socket @retval -1 Socket error @retval -2 Timeout */ - int receiveControlPacket() + int receiveControlPacket(const bool lowLatency = false) { if (!socket) return -1; // Depending on the current state, we need to fetch as many bytes as possible within the given timeoutMs @@ -192,6 +192,11 @@ namespace Network { namespace Client { int ret = 0; Protocol::MQTT::Common::VBInt len; +#if MQTTLowLatency == 1 + // In low latency mode, return as early as possible + if (lowLatency && !socket->select(true, false, 0)) return -2; +#endif + // We want to keep track of complete timeout time over multiple operations Time::TimeOut timeout(timeoutMs); switch (recvState) @@ -618,15 +623,12 @@ namespace Network { namespace Client { } // Useful socket helpers functions here - MQTTVirtual int select(bool reading, bool writing) + MQTTVirtual int select(bool reading, bool writing, bool instantaneous = false) { -#if (_LINUX == 1) // Linux modifies the timeout when calling select struct timeval v = timeoutMs; -#else - // Other system don't - struct timeval & v = timeoutMs; -#endif + if (instantaneous) memset(&v, 0, sizeof(v)); + fd_set set; FD_ZERO(&set); FD_SET(socket, &set); @@ -866,7 +868,7 @@ namespace Network { namespace Client { @retval 0 Protocol error, you should close the socket @retval -1 Socket error @retval -2 Timeout */ - int receiveControlPacket() + int receiveControlPacket(const bool lowLatency = false) { if (!socket) return -1; // Depending on the current state, we need to fetch as many bytes as possible within the given timeoutMs @@ -883,6 +885,11 @@ namespace Network { namespace Client { int ret = 0; Protocol::MQTT::Common::VBInt len; +#if MQTTLowLatency == 1 + // In low latency mode, return as early as possible + if (lowLatency && !socket->select(true, false, true)) return -2; +#endif + // We want to keep track of complete timeout time over multiple operations switch (recvState) { @@ -1551,7 +1558,7 @@ namespace Network { namespace Client { return ret; } // Check the server for any packet... - int ret = impl->receiveControlPacket(); + int ret = impl->receiveControlPacket(true); if (ret == 0) { impl->close();