From 1f3a5fe5a9855e8a0f4722abaab25583f130f12f Mon Sep 17 00:00:00 2001 From: Ing-Dom Date: Fri, 26 May 2023 11:26:33 +0200 Subject: [PATCH 1/3] improve the implementation of the 50 packet / second limit delay knx.loop by 20ms has ugly side effects. count the frames in 100ms chunks to allow more than 5 packets per 100ms drop packet if over the limit. --- src/knx/ip_data_link_layer.cpp | 56 ++++++++++++++++++++++++++++++++-- src/knx/ip_data_link_layer.h | 4 +++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/knx/ip_data_link_layer.cpp b/src/knx/ip_data_link_layer.cpp index d599187..1ef87d6 100644 --- a/src/knx/ip_data_link_layer.cpp +++ b/src/knx/ip_data_link_layer.cpp @@ -26,10 +26,11 @@ IpDataLinkLayer::IpDataLinkLayer(DeviceObject& devObj, IpParameterObject& ipPara bool IpDataLinkLayer::sendFrame(CemiFrame& frame) { KnxIpRoutingIndication packet(frame); - + if(countFrames()) + return false; bool success = sendBytes(packet.data(), packet.totalLength()); // only send 50 packet per second: see KNX 3.2.6 p.6 - delay(20); + //delay(20); dataConReceived(frame, success); return success; } @@ -112,4 +113,55 @@ bool IpDataLinkLayer::sendBytes(uint8_t* bytes, uint16_t length) return _platform.sendBytesMultiCast(bytes, length); } + +bool IpDataLinkLayer::countFrames() +{ + // _frameCount[_frameCountBase] => frames sent since now and millis() % 100 + // _frameCount[(_frameCountBase - 1) % 10] => frames sent since millis() % 100 and millis() % 100 - 100 + // _frameCount[(_frameCountBase - 2) % 10] => frames sent since millis() % 100 - 100 and millis() % 100 - 200 + // ... => information about the number of frames sent in the last 1000 ms + + uint32_t curTime = millis() / 100; + + // check if the countbuffer must be adjusted + if(_frameCountTimeBase >= curTime) + { + uint32_t timeBaseDiff = _frameCountTimeBase - curTime; + if(timeBaseDiff > 10) + timeBaseDiff = 10; + for(int i = 0; i < timeBaseDiff ; i++) + { + _frameCountBase++; + _frameCountBase = _frameCountBase % 10; + _frameCount[_frameCountBase] = 0; + } + _frameCountTimeBase = curTime; + } + else // _frameCountTimeBase < curTime => millis overflow, reset + { + for(int i = 0; i < 10 ; i++) + _frameCount[i] = 0; + _frameCountBase = 0; + _frameCountTimeBase = curTime; + } + + //check if we are over the limit + uint16_t sum = 0; + for(int i = 0; i < 10 ; i++) + sum += _frameCount[i]; + if(sum > 50) + { + println("Dropping packet due to 50p/s limit"); + return false; // drop packet + } + else + { + _frameCount[_frameCountBase]++; + print("go for it: "); + print(sum); + print(" curTime: "); + println(curTime); + return true; + } +} #endif diff --git a/src/knx/ip_data_link_layer.h b/src/knx/ip_data_link_layer.h index f8acae5..c952b7e 100644 --- a/src/knx/ip_data_link_layer.h +++ b/src/knx/ip_data_link_layer.h @@ -22,8 +22,12 @@ class IpDataLinkLayer : public DataLinkLayer private: bool _enabled = false; + uint8_t _frameCount[10] = {0,0,0,0,0,0,0,0,0,0}; + uint8_t _frameCountBase = 0; + uint32_t _frameCountTimeBase = 0; bool sendFrame(CemiFrame& frame); bool sendBytes(uint8_t* buffer, uint16_t length); + bool countFrames(); IpParameterObject& _ipParameters; }; From 49ae48eacb23747636099da97a474976459087f0 Mon Sep 17 00:00:00 2001 From: Ing-Dom Date: Fri, 26 May 2023 12:48:50 +0200 Subject: [PATCH 2/3] some minor improvements from first code review --- src/knx/ip_data_link_layer.cpp | 20 +++++++------------- src/knx/ip_data_link_layer.h | 2 +- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/knx/ip_data_link_layer.cpp b/src/knx/ip_data_link_layer.cpp index 1ef87d6..dd91f62 100644 --- a/src/knx/ip_data_link_layer.cpp +++ b/src/knx/ip_data_link_layer.cpp @@ -26,11 +26,10 @@ IpDataLinkLayer::IpDataLinkLayer(DeviceObject& devObj, IpParameterObject& ipPara bool IpDataLinkLayer::sendFrame(CemiFrame& frame) { KnxIpRoutingIndication packet(frame); - if(countFrames()) + // only send 50 packet per second: see KNX 3.2.6 p.6 + if(CheckSendLimit()) return false; bool success = sendBytes(packet.data(), packet.totalLength()); - // only send 50 packet per second: see KNX 3.2.6 p.6 - //delay(20); dataConReceived(frame, success); return success; } @@ -114,13 +113,8 @@ bool IpDataLinkLayer::sendBytes(uint8_t* bytes, uint16_t length) return _platform.sendBytesMultiCast(bytes, length); } -bool IpDataLinkLayer::countFrames() +bool IpDataLinkLayer::CheckSendLimit() { - // _frameCount[_frameCountBase] => frames sent since now and millis() % 100 - // _frameCount[(_frameCountBase - 1) % 10] => frames sent since millis() % 100 and millis() % 100 - 100 - // _frameCount[(_frameCountBase - 2) % 10] => frames sent since millis() % 100 - 100 and millis() % 100 - 200 - // ... => information about the number of frames sent in the last 1000 ms - uint32_t curTime = millis() / 100; // check if the countbuffer must be adjusted @@ -157,10 +151,10 @@ bool IpDataLinkLayer::countFrames() else { _frameCount[_frameCountBase]++; - print("go for it: "); - print(sum); - print(" curTime: "); - println(curTime); + //print("sent packages in last 1000ms: "); + //print(sum); + //print(" curTime: "); + //println(curTime); return true; } } diff --git a/src/knx/ip_data_link_layer.h b/src/knx/ip_data_link_layer.h index c952b7e..d10a3ad 100644 --- a/src/knx/ip_data_link_layer.h +++ b/src/knx/ip_data_link_layer.h @@ -27,7 +27,7 @@ class IpDataLinkLayer : public DataLinkLayer uint32_t _frameCountTimeBase = 0; bool sendFrame(CemiFrame& frame); bool sendBytes(uint8_t* buffer, uint16_t length); - bool countFrames(); + bool CheckSendLimit(); IpParameterObject& _ipParameters; }; From b088ffe10d8cfd637ec00c1143746ca92967d82f Mon Sep 17 00:00:00 2001 From: Ing-Dom Date: Sat, 27 May 2023 13:55:11 +0200 Subject: [PATCH 3/3] Rename function for better understanding, fix inverse logic --- src/knx/ip_data_link_layer.cpp | 8 ++++---- src/knx/ip_data_link_layer.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/knx/ip_data_link_layer.cpp b/src/knx/ip_data_link_layer.cpp index dd91f62..43a7a59 100644 --- a/src/knx/ip_data_link_layer.cpp +++ b/src/knx/ip_data_link_layer.cpp @@ -27,7 +27,7 @@ bool IpDataLinkLayer::sendFrame(CemiFrame& frame) { KnxIpRoutingIndication packet(frame); // only send 50 packet per second: see KNX 3.2.6 p.6 - if(CheckSendLimit()) + if(isSendLimitReached()) return false; bool success = sendBytes(packet.data(), packet.totalLength()); dataConReceived(frame, success); @@ -113,7 +113,7 @@ bool IpDataLinkLayer::sendBytes(uint8_t* bytes, uint16_t length) return _platform.sendBytesMultiCast(bytes, length); } -bool IpDataLinkLayer::CheckSendLimit() +bool IpDataLinkLayer::isSendLimitReached() { uint32_t curTime = millis() / 100; @@ -146,7 +146,7 @@ bool IpDataLinkLayer::CheckSendLimit() if(sum > 50) { println("Dropping packet due to 50p/s limit"); - return false; // drop packet + return true; // drop packet } else { @@ -155,7 +155,7 @@ bool IpDataLinkLayer::CheckSendLimit() //print(sum); //print(" curTime: "); //println(curTime); - return true; + return false; } } #endif diff --git a/src/knx/ip_data_link_layer.h b/src/knx/ip_data_link_layer.h index d10a3ad..5f2d996 100644 --- a/src/knx/ip_data_link_layer.h +++ b/src/knx/ip_data_link_layer.h @@ -27,7 +27,7 @@ class IpDataLinkLayer : public DataLinkLayer uint32_t _frameCountTimeBase = 0; bool sendFrame(CemiFrame& frame); bool sendBytes(uint8_t* buffer, uint16_t length); - bool CheckSendLimit(); + bool isSendLimitReached(); IpParameterObject& _ipParameters; };