Merge branch 'thelsing:master' into master

This commit is contained in:
SirSydom 2022-02-05 13:47:41 +01:00 committed by GitHub
commit 6f9efca2fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 424 additions and 280 deletions

View File

@ -53,6 +53,10 @@ void setup(void)
wifiManager.autoConnect("knx-bme680"); wifiManager.autoConnect("knx-bme680");
#endif #endif
// set save and restore callbacks
knx.setSaveCallback(saveBme680State);
knx.setRestoreCallback(loadBme680State);
// read adress table, association table, groupobject table and parameters from eeprom // read adress table, association table, groupobject table and parameters from eeprom
knx.readMemory(); knx.readMemory();
@ -60,7 +64,6 @@ void setup(void)
if(knx.configured()) if(knx.configured())
goTriggerSample.callback(triggerCallback); goTriggerSample.callback(triggerCallback);
// Configure Wire pins before this call if needed. // Configure Wire pins before this call if needed.
Wire.begin(); Wire.begin();
// depends on sensor board. Try BME680_I2C_ADDR_PRIMARY if it doen't work. // depends on sensor board. Try BME680_I2C_ADDR_PRIMARY if it doen't work.
@ -87,9 +90,6 @@ void setup(void)
BSEC_OUTPUT_GAS_PERCENTAGE BSEC_OUTPUT_GAS_PERCENTAGE
}; };
knx.setSaveCallback(saveBme680State);
knx.setRestoreCallback(loadBme680State);
if (knx.configured()) if (knx.configured())
{ {
cyclSend = knx.paramInt(0); cyclSend = knx.paramInt(0);

View File

@ -82,7 +82,7 @@ int FdskCalculator::toBase32(uint8_t* in, long length, uint8_t*& out, bool usePa
int next = 1; int next = 1;
int bitsLeft = 8; int bitsLeft = 8;
while (count < bufSize && (bitsLeft > 0 || next < length)) while (bitsLeft > 0 || next < length)
{ {
if (bitsLeft < 5) if (bitsLeft < 5)
{ {

View File

@ -82,7 +82,7 @@ int FdskCalculator::toBase32(uint8_t* in, long length, uint8_t*& out, bool usePa
int next = 1; int next = 1;
int bitsLeft = 8; int bitsLeft = 8;
while (count < bufSize && (bitsLeft > 0 || next < length)) while (bitsLeft > 0 || next < length)
{ {
if (bitsLeft < 5) if (bitsLeft < 5)
{ {

View File

@ -25,7 +25,7 @@ uint16_t AssociationTableObject::entryCount()
uint16_t AssociationTableObject::getTSAP(uint16_t idx) uint16_t AssociationTableObject::getTSAP(uint16_t idx)
{ {
if (idx < 0 || idx >= entryCount()) if (idx >= entryCount())
return 0; return 0;
return ntohs(_tableData[2 * idx + 1]); return ntohs(_tableData[2 * idx + 1]);
@ -33,7 +33,7 @@ uint16_t AssociationTableObject::getTSAP(uint16_t idx)
uint16_t AssociationTableObject::getASAP(uint16_t idx) uint16_t AssociationTableObject::getASAP(uint16_t idx)
{ {
if (idx < 0 || idx >= entryCount()) if (idx >= entryCount())
return 0; return 0;
return ntohs(_tableData[2 * idx + 2]); return ntohs(_tableData[2 * idx + 2]);

View File

@ -483,7 +483,7 @@ bool BauSystemB::restartRequest(uint16_t asap, const SecurityControl secCtrl)
void BauSystemB::connectConfirm(uint16_t tsap) void BauSystemB::connectConfirm(uint16_t tsap)
{ {
if (_restartState == Connecting && tsap >= 0) if (_restartState == Connecting)
{ {
/* restart connection is confirmed, go to the next state */ /* restart connection is confirmed, go to the next state */
_restartState = Connected; _restartState = Connected;

View File

@ -357,6 +357,7 @@
#define DPT_FlaggedScaling Dpt(239, 1) #define DPT_FlaggedScaling Dpt(239, 1)
#define DPT_CombinedPosition Dpt(240, 800) #define DPT_CombinedPosition Dpt(240, 800)
#define DPT_StatusSAB Dpt(241, 800) #define DPT_StatusSAB Dpt(241, 800)
#define DPT_Colour_RGBW Dpt(251, 600)
class Dpt class Dpt
{ {

View File

@ -22,12 +22,6 @@ int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatyp
if (datatype.mainGroup == 2 && datatype.subGroup >= 1 && datatype.subGroup <= 12 && datatype.index <= 1) if (datatype.mainGroup == 2 && datatype.subGroup >= 1 && datatype.subGroup <= 12 && datatype.index <= 1)
return busValueToBinaryControl(payload, payload_length, datatype, value); return busValueToBinaryControl(payload, payload_length, datatype, value);
// DPT 3.* - Step Control // DPT 3.* - Step Control
if (datatype.mainGroup == 3 && datatype.subGroup >= 7 && datatype.subGroup <= 8 && datatype.index <= 1)
return busValueToStepControl(payload, payload_length, datatype, value);
// DPT 4.* - Character// DPT 2.* - Binary Control
if (datatype.mainGroup == 2 && datatype.subGroup >= 1 && datatype.subGroup <= 12 && datatype.index <= 1)
return busValueToBinaryControl(payload, payload_length, datatype, value);
// DPT 3.* - Step Control
if (datatype.mainGroup == 3 && datatype.subGroup >= 7 && datatype.subGroup <= 8 && datatype.index <= 1) if (datatype.mainGroup == 3 && datatype.subGroup >= 7 && datatype.subGroup <= 8 && datatype.index <= 1)
return busValueToStepControl(payload, payload_length, datatype, value); return busValueToStepControl(payload, payload_length, datatype, value);
// DPT 4.* - Character // DPT 4.* - Character
@ -42,8 +36,8 @@ int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatyp
// DPT 6.020 - Status with Mode // DPT 6.020 - Status with Mode
if (datatype.mainGroup == 6 && datatype.subGroup == 20 && datatype.index <= 5) if (datatype.mainGroup == 6 && datatype.subGroup == 20 && datatype.index <= 5)
return busValueToStatusAndMode(payload, payload_length, datatype, value); return busValueToStatusAndMode(payload, payload_length, datatype, value);
// DPT 7.001/7.010/7.011/7.012/7.013 - Unsigned 16 Bit Integer // DPT 7.001/7.010/7.011/7.012/7.013/7.600 - Unsigned 16 Bit Integer
if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13)) && !datatype.index) if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13) || (datatype.subGroup == 600)) && !datatype.index)
return busValueToUnsigned16(payload, payload_length, datatype, value); return busValueToUnsigned16(payload, payload_length, datatype, value);
// DPT 7.002-DPT 7.007 - Time Period // DPT 7.002-DPT 7.007 - Time Period
if (datatype.mainGroup == 7 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index) if (datatype.mainGroup == 7 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
@ -132,6 +126,9 @@ int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatyp
// DPT 239.* - Flagged Scaling // DPT 239.* - Flagged Scaling
if (datatype.mainGroup == 239 && datatype.subGroup == 1 && datatype.index <= 1) if (datatype.mainGroup == 239 && datatype.subGroup == 1 && datatype.index <= 1)
return busValueToFlaggedScaling(payload, payload_length, datatype, value); return busValueToFlaggedScaling(payload, payload_length, datatype, value);
// DPT 251.600 - RGBW
if (datatype.mainGroup == 251 && datatype.subGroup == 600 && datatype.index <= 1)
return busValueToRGBW(payload, payload_length, datatype, value);
} }
return false; return false;
} }
@ -159,8 +156,8 @@ int KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_len
// DPT 6.020 - Status with Mode // DPT 6.020 - Status with Mode
if (datatype.mainGroup == 6 && datatype.subGroup == 20 && datatype.index <= 5) if (datatype.mainGroup == 6 && datatype.subGroup == 20 && datatype.index <= 5)
return valueToBusValueStatusAndMode(value, payload, payload_length, datatype); return valueToBusValueStatusAndMode(value, payload, payload_length, datatype);
// DPT 7.001/7.010/7.011/7.012/7.013 - Unsigned 16 Bit Integer // DPT 7.001/7.010/7.011/7.012/7.013/7.600 - Unsigned 16 Bit Integer
if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13)) && !datatype.index) if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13) || datatype.subGroup == 600) && !datatype.index)
return valueToBusValueUnsigned16(value, payload, payload_length, datatype); return valueToBusValueUnsigned16(value, payload, payload_length, datatype);
// DPT 7.002-DPT 7.007 - Time Period // DPT 7.002-DPT 7.007 - Time Period
if (datatype.mainGroup == 7 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index) if (datatype.mainGroup == 7 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
@ -249,6 +246,9 @@ int KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_len
// DPT 239.* - Flagged Scaling // DPT 239.* - Flagged Scaling
if (datatype.mainGroup == 239 && datatype.subGroup == 1 && datatype.index <= 1) if (datatype.mainGroup == 239 && datatype.subGroup == 1 && datatype.index <= 1)
return valueToBusValueFlaggedScaling(value, payload, payload_length, datatype); return valueToBusValueFlaggedScaling(value, payload, payload_length, datatype);
// DPT 251.600 - RGBW
if (datatype.mainGroup == 251 && datatype.subGroup == 600 && datatype.index <= 1)
return valueToBusValueRGBW(value, payload, payload_length, datatype);
return false; return false;
} }
@ -803,12 +803,27 @@ int busValueToRGB(const uint8_t* payload, size_t payload_length, const Dpt& data
{ {
ASSERT_PAYLOAD(3); ASSERT_PAYLOAD(3);
uint32_t rgb = unsigned16FromPayload(payload, 0) * 256 + unsigned8FromPayload(payload, 2); uint32_t rgb = unsigned16FromPayload(payload, 0) * 256 + unsigned8FromPayload(payload, 2);
if (rgb > 16777215)
return false;
value = rgb; value = rgb;
return true; return true;
} }
int busValueToRGBW(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(6);
switch (datatype.index) {
case 0: // The RGBW value
{
uint32_t rgbw = unsigned32FromPayload(payload, 0);
value = rgbw;
}
return true;
case 1: // The mask bits only
value = unsigned8FromPayload(payload,5);
return true;
}
return false;
}
int busValueToFlaggedScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value) int busValueToFlaggedScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{ {
ASSERT_PAYLOAD(2); ASSERT_PAYLOAD(2);
@ -892,7 +907,7 @@ int valueToBusValueStepControl(const KNXValue& value, uint8_t* payload, size_t p
int valueToBusValueCharacter(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) int valueToBusValueCharacter(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{ {
if ((uint64_t)value < INT64_C(0) || (uint64_t)value > INT64_C(255) || (datatype.subGroup == 1 && (uint64_t)value > INT64_C(127))) if ((uint64_t)value > INT64_C(255) || (datatype.subGroup == 1 && (uint64_t)value > INT64_C(127)))
return false; return false;
unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF); unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF);
return true; return true;
@ -1159,7 +1174,7 @@ int valueToBusValueAccess(const KNXValue& value, uint8_t* payload, size_t payloa
break; break;
case 5: case 5:
{ {
if ((uint64_t)value < INT64_C(0) || (uint64_t)value > INT64_C(15)) if ((uint64_t)value > INT64_C(15))
return false; return false;
bcdToPayload(payload, payload_length, 7, (uint64_t)value); bcdToPayload(payload, payload_length, 7, (uint64_t)value);
break; break;
@ -1450,7 +1465,7 @@ int valueToBusValueScaling(const KNXValue& value, uint8_t* payload, size_t paylo
{ {
uint32_t duration = value; uint32_t duration = value;
if (duration < INT64_C(0) || duration > INT64_C(65535)) if (duration > INT64_C(65535))
return false; return false;
ENSURE_PAYLOAD(3); ENSURE_PAYLOAD(3);
@ -1477,7 +1492,7 @@ int valueToBusValueTariff(const KNXValue& value, uint8_t* payload, size_t payloa
{ {
uint32_t duration = value; uint32_t duration = value;
if (duration < INT64_C(0) || duration > INT64_C(65535)) if (duration > INT64_C(65535))
return false; return false;
ENSURE_PAYLOAD(3); ENSURE_PAYLOAD(3);
@ -1525,6 +1540,24 @@ int valueToBusValueRGB(const KNXValue& value, uint8_t* payload, size_t payload_l
return true; return true;
} }
int valueToBusValueRGBW(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch(datatype.index)
{
case 0: // RGBW
{
uint32_t rgbw = (uint32_t)value;
unsigned32ToPayload(payload, payload_length, 0, rgbw, 0xffffffff); // RGBW
}
break;
case 1: // Mask bits
unsigned8ToPayload(payload, payload_length, 5, (uint8_t)value, 0x0f);
break;
}
return true;
}
int valueToBusValueFlaggedScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype) int valueToBusValueFlaggedScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{ {
switch (datatype.index) switch (datatype.index)
@ -1553,7 +1586,6 @@ int valueToBusValueActiveEnergy(const KNXValue& value, uint8_t* payload, size_t
{ {
case 0: case 0:
{ {
if ((int64_t)value < INT64_C(-2147483648) || (int64_t)value > INT64_C(2147483647)) if ((int64_t)value < INT64_C(-2147483648) || (int64_t)value > INT64_C(2147483647))
return false; return false;
ENSURE_PAYLOAD(6); ENSURE_PAYLOAD(6);

View File

@ -78,6 +78,7 @@ int busValueToScaling(const uint8_t* payload, size_t payload_length, const Dpt&
int busValueToTariff(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); int busValueToTariff(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
int busValueToLocale(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); int busValueToLocale(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
int busValueToRGB(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); int busValueToRGB(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
int busValueToRGBW(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
int busValueToFlaggedScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); int busValueToFlaggedScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
int busValueToActiveEnergy(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value); int busValueToActiveEnergy(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
@ -116,6 +117,7 @@ int valueToBusValueScaling(const KNXValue& value, uint8_t* payload, size_t paylo
int valueToBusValueTariff(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); int valueToBusValueTariff(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
int valueToBusValueLocale(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); int valueToBusValueLocale(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
int valueToBusValueRGB(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); int valueToBusValueRGB(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
int valueToBusValueRGBW(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
int valueToBusValueFlaggedScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); int valueToBusValueFlaggedScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
int valueToBusValueActiveEnergy(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype); int valueToBusValueActiveEnergy(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);

View File

@ -318,7 +318,7 @@ uint64_t KNXValue::ulongValue() const
switch (_type) switch (_type)
{ {
case ULongType: case ULongType:
return _value.uintValue; return _value.ulongValue;
case BoolType: case BoolType:
return _value.boolValue ? 1 : 0; return _value.boolValue ? 1 : 0;
case UCharType: case UCharType:

View File

@ -11,6 +11,9 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
// Activate trace output
//#define DBG_TRACE
// NCN5120 // NCN5120
//#define NCN5120 //#define NCN5120
@ -75,25 +78,28 @@
#define U_STOP_MODE_IND 0x2B #define U_STOP_MODE_IND 0x2B
#define U_SYSTEM_STAT_IND 0x4B #define U_SYSTEM_STAT_IND 0x4B
//loop states //tx states
#define IDLE 0 enum {
#define RX_FIRST_BYTE 1 TX_IDLE,
#define RX_L_DATA 2 TX_FRAME,
#define RX_WAIT_DATA_CON 3 TX_WAIT_ECHO,
#define TX_FRAME 4 TX_WAIT_CONN
};
#define BYTE_TIMEOUT 10 //milli seconds //rx states
enum {
RX_WAIT_START,
RX_L_DATA,
RX_WAIT_EOP
};
#define EOP_TIMEOUT 2 //milli seconds; end of layer-2 packet gap
#define CONFIRM_TIMEOUT 500 //milli seconds #define CONFIRM_TIMEOUT 500 //milli seconds
#define RESET_TIMEOUT 100 //milli seconds #define RESET_TIMEOUT 100 //milli seconds
void TpUartDataLinkLayer::loop() void TpUartDataLinkLayer::loop()
{ {
_receiveBuffer[0] = 0x29;
_receiveBuffer[1] = 0;
uint8_t* buffer = _receiveBuffer + 2;
uint8_t rxByte;
if (!_enabled) if (!_enabled)
{ {
if (millis() - _lastResetChipTime > 1000) if (millis() - _lastResetChipTime > 1000)
@ -107,265 +113,317 @@ void TpUartDataLinkLayer::loop()
if (!_enabled) if (!_enabled)
return; return;
switch (_loopState) // Signals to communicate from rx part with the tx part
{ bool isEchoComplete = false; // Flag that a complete echo is received
case IDLE: uint8_t dataConnMsg = 0; // The DATA_CONN message just seen or 0
if (_platform.uartAvailable()) do {
{ _receiveBuffer[0] = 0x29;
_loopState = RX_FIRST_BYTE; _receiveBuffer[1] = 0;
} uint8_t* buffer = _receiveBuffer + 2;
else uint8_t rxByte;
{ bool isEOP = (millis() - _lastByteRxTime > EOP_TIMEOUT); // Flag that an EOP gap is seen
if (!_waitConfirm && !isTxQueueEmpty()) switch (_rxState)
{
case RX_WAIT_START:
if (_platform.uartAvailable())
{ {
loadNextTxFrame(); rxByte = _platform.readUart();
_loopState = TX_FRAME; #ifdef DBG_TRACE
print(rxByte, HEX);
#endif
_lastByteRxTime = millis();
// Check for layer-2 packets
_RxByteCnt = 0;
_xorSum = 0;
if ((rxByte & L_DATA_MASK) == L_DATA_STANDARD_IND)
{
buffer[_RxByteCnt++] = rxByte;
_xorSum ^= rxByte;
_RxByteCnt++; //convert to L_DATA_EXTENDED
_convert = true;
_rxState = RX_L_DATA;
#ifdef DBG_TRACE
println("RLS");
#endif
break;
}
else if ((rxByte & L_DATA_MASK) == L_DATA_EXTENDED_IND)
{
buffer[_RxByteCnt++] = rxByte;
_xorSum ^= rxByte;
_convert = false;
_rxState = RX_L_DATA;
#ifdef DBG_TRACE
println("RLX");
#endif
break;
}
// Handle all single byte packets here
else if ((rxByte & L_DATA_CON_MASK) == L_DATA_CON)
{
dataConnMsg = rxByte;
}
else if (rxByte == L_POLL_DATA_IND)
{
// not sure if this can happen
println("got L_POLL_DATA_IND");
}
else if ((rxByte & L_ACKN_MASK) == L_ACKN_IND)
{
// this can only happen in bus monitor mode
println("got L_ACKN_IND");
}
else if (rxByte == U_RESET_IND)
{
println("got U_RESET_IND");
}
else if ((rxByte & U_STATE_IND) == U_STATE_IND)
{
print("got U_STATE_IND:");
if (rxByte & 0x80) print (" SC");
if (rxByte & 0x40) print (" RE");
if (rxByte & 0x20) print (" TE");
if (rxByte & 0x10) print (" PE");
if (rxByte & 0x08) print (" TW");
println();
}
else if ((rxByte & U_FRAME_STATE_MASK) == U_FRAME_STATE_IND)
{
print("got U_FRAME_STATE_IND: 0x");
print(rxByte, HEX);
println();
}
else if ((rxByte & U_CONFIGURE_MASK) == U_CONFIGURE_IND)
{
print("got U_CONFIGURE_IND: 0x");
print(rxByte, HEX);
println();
}
else if (rxByte == U_FRAME_END_IND)
{
println("got U_FRAME_END_IND");
}
else if (rxByte == U_STOP_MODE_IND)
{
println("got U_STOP_MODE_IND");
}
else if (rxByte == U_SYSTEM_STAT_IND)
{
print("got U_SYSTEM_STAT_IND: 0x");
while (true)
{
int tmp = _platform.readUart();
if (tmp < 0)
continue;
print(tmp, HEX);
break;
}
println();
}
else
{
print("got UNEXPECTED: 0x");
print(rxByte, HEX);
println();
}
} }
break;
case RX_L_DATA:
if (isEOP)
{
_rxState = RX_WAIT_START;
print("EOP inside RX_L_DATA");
printHex(" => ", buffer, _RxByteCnt);
break;
}
if (!_platform.uartAvailable())
break;
_lastByteRxTime = millis();
rxByte = _platform.readUart();
#ifdef DBG_TRACE
print(rxByte, HEX);
#endif
if (_RxByteCnt == MAX_KNX_TELEGRAM_SIZE)
{
_rxState = RX_WAIT_EOP;
println("invalid telegram size");
}
else
{
buffer[_RxByteCnt++] = rxByte;
}
if (_RxByteCnt == 7)
{
//Destination Address + payload available
_xorSum ^= rxByte;
//check if echo
if (_sendBuffer != nullptr && (!((buffer[0] ^ _sendBuffer[0]) & ~0x20) && !memcmp(buffer + _convert + 1, _sendBuffer + 1, 5)))
{ //ignore repeated bit of control byte
_isEcho = true;
}
else
{
_isEcho = false;
}
//convert into Extended.ind
if (_convert)
{
uint8_t payloadLength = buffer[6] & 0x0F;
buffer[1] = buffer[6] & 0xF0;
buffer[6] = payloadLength;
}
if (!_isEcho)
{
uint8_t c = 0x10;
// The bau knows everything and could either check the address table object (normal device)
// or any filter tables (coupler) to see if we are addressed.
//check if individual or group address
bool isGroupAddress = (buffer[1] & 0x80) != 0;
uint16_t addr = getWord(buffer + 4);
if (_cb.isAckRequired(addr, isGroupAddress))
{
c |= 0x01;
}
// Hint: We can send directly here, this doesn't disturb other transmissions
_platform.writeUart(c);
}
}
else if (_RxByteCnt == buffer[6] + 7 + 2)
{
//complete Frame received, payloadLength+1 for TCPI +1 for CRC
if (rxByte == (uint8_t)(~_xorSum))
{
//check if crc is correct
if (_isEcho && _sendBuffer != NULL)
{
//check if it is realy an echo, rx_crc = tx_crc
if (rxByte == _sendBuffer[_sendBufferLength - 1])
_isEcho = true;
else
_isEcho = false;
}
if (_isEcho)
{
isEchoComplete = true;
}
else
{
frameBytesReceived(_receiveBuffer, _RxByteCnt + 2);
}
_rxState = RX_WAIT_START;
#ifdef DBG_TRACE
println("RX_WAIT_START");
#endif
}
else
{
println("frame with invalid crc ignored");
_rxState = RX_WAIT_EOP;
}
}
else
{
_xorSum ^= rxByte;
}
break;
case RX_WAIT_EOP:
if (isEOP)
{
_RxByteCnt = 0;
_rxState = RX_WAIT_START;
#ifdef DBG_TRACE
println("RX_WAIT_START");
#endif
break;
}
if (!_platform.uartAvailable())
break;
_lastByteRxTime = millis();
rxByte = _platform.readUart();
#ifdef DBG_TRACE
print(rxByte, HEX);
#endif
break;
default:
break;
}
} while (_rxState == RX_L_DATA);
// Check for spurios DATA_CONN message
if (dataConnMsg && _txState != TX_WAIT_CONN && _txState != TX_WAIT_ECHO) {
println("got unexpected L_DATA_CON");
}
switch (_txState)
{
case TX_IDLE:
if (!isTxQueueEmpty())
{
loadNextTxFrame();
_txState = TX_FRAME;
#ifdef DBG_TRACE
println("TX_FRAME");
#endif
} }
break; break;
case TX_FRAME: case TX_FRAME:
if (sendSingleFrameByte() == false) if (sendSingleFrameByte() == false)
{ {
_waitConfirm = true;
_waitConfirmStartTime = millis(); _waitConfirmStartTime = millis();
_loopState = IDLE; _txState = TX_WAIT_ECHO;
#ifdef DBG_TRACE
println("TX_WAIT_ECHO");
#endif
} }
break; break;
case RX_FIRST_BYTE: case TX_WAIT_ECHO:
rxByte = _platform.readUart(); case TX_WAIT_CONN:
_lastByteRxTime = millis(); if (isEchoComplete)
_RxByteCnt = 0;
_xorSum = 0;
if ((rxByte & L_DATA_MASK) == L_DATA_STANDARD_IND)
{ {
buffer[_RxByteCnt++] = rxByte; _txState = TX_WAIT_CONN;
_xorSum ^= rxByte; #ifdef DBG_TRACE
_RxByteCnt++; //convert to L_DATA_EXTENDED println("TX_WAIT_CONN");
_convert = true; #endif
_loopState = RX_L_DATA;
break;
} }
else if ((rxByte & L_DATA_MASK) == L_DATA_EXTENDED_IND) else if (dataConnMsg)
{ {
buffer[_RxByteCnt++] = rxByte; bool waitEcho = (_txState == TX_WAIT_ECHO);
_xorSum ^= rxByte; if (waitEcho) {
_convert = false; println("L_DATA_CON without echo");
_loopState = RX_L_DATA;
break;
}
else if ((rxByte & L_DATA_CON_MASK) == L_DATA_CON)
{
println("got unexpected L_DATA_CON");
}
else if (rxByte == L_POLL_DATA_IND)
{
// not sure if this can happen
println("got L_POLL_DATA_IND");
}
else if ((rxByte & L_ACKN_MASK) == L_ACKN_IND)
{
// this can only happen in bus monitor mode
println("got L_ACKN_IND");
}
else if (rxByte == U_RESET_IND)
{
println("got U_RESET_IND");
}
else if ((rxByte & U_STATE_IND) == U_STATE_IND)
{
print("got U_STATE_IND: 0x");
print(rxByte, HEX);
println();
}
else if ((rxByte & U_FRAME_STATE_MASK) == U_FRAME_STATE_IND)
{
print("got U_FRAME_STATE_IND: 0x");
print(rxByte, HEX);
println();
}
else if ((rxByte & U_CONFIGURE_MASK) == U_CONFIGURE_IND)
{
print("got U_CONFIGURE_IND: 0x");
print(rxByte, HEX);
println();
}
else if (rxByte == U_FRAME_END_IND)
{
println("got U_FRAME_END_IND");
}
else if (rxByte == U_STOP_MODE_IND)
{
println("got U_STOP_MODE_IND");
}
else if (rxByte == U_SYSTEM_STAT_IND)
{
print("got U_SYSTEM_STAT_IND: 0x");
while (true)
{
int tmp = _platform.readUart();
if (tmp < 0)
continue;
print(tmp, HEX);
break;
} }
println(); dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, !waitEcho && ((dataConnMsg & SUCCESS) > 0));
}
else
{
print("got UNEXPECTED: 0x");
print(rxByte, HEX);
println();
}
_loopState = IDLE;
break;
case RX_L_DATA:
if (millis() - _lastByteRxTime > BYTE_TIMEOUT)
{
_RxByteCnt = 0;
_loopState = IDLE;
println("Timeout during RX_L_DATA");
break;
}
if (!_platform.uartAvailable())
break;
_lastByteRxTime = millis();
rxByte = _platform.readUart();
if (_RxByteCnt == MAX_KNX_TELEGRAM_SIZE)
{
_loopState = IDLE;
println("invalid telegram size");
}
else
{
buffer[_RxByteCnt++] = rxByte;
}
if (_RxByteCnt == 7)
{
//Destination Address + payload available
_xorSum ^= rxByte;
//check if echo
if (_sendBuffer != nullptr && (!((buffer[0] ^ _sendBuffer[0]) & ~0x20) && !memcmp(buffer + _convert + 1, _sendBuffer + 1, 5)))
{ //ignore repeated bit of control byte
_isEcho = true;
}
else
{
_isEcho = false;
}
//convert into Extended.ind
if (_convert)
{
uint8_t payloadLength = buffer[6] & 0x0F;
buffer[1] = buffer[6] & 0xF0;
buffer[6] = payloadLength;
}
if (!_isEcho)
{
uint8_t c = 0x10;
// The bau knows everything and could either check the address table object (normal device)
// or any filter tables (coupler) to see if we are addressed.
//check if individual or group address
bool isGroupAddress = (buffer[1] & 0x80) != 0;
uint16_t addr = getWord(buffer + 4);
if (_cb.isAckRequired(addr, isGroupAddress))
{
c |= 0x01;
}
_platform.writeUart(c);
}
}
else if (_RxByteCnt == buffer[6] + 7 + 2)
{
//complete Frame received, payloadLength+1 for TCPI +1 for CRC
if (rxByte == (uint8_t)(~_xorSum))
{
//check if crc is correct
if (_isEcho && _sendBuffer != NULL)
{
//check if it is realy an echo, rx_crc = tx_crc
if (rxByte == _sendBuffer[_sendBufferLength - 1])
_isEcho = true;
else
_isEcho = false;
}
if (_isEcho)
{
_loopState = RX_WAIT_DATA_CON;
}
else
{
frameBytesReceived(_receiveBuffer, _RxByteCnt + 2);
_loopState = IDLE;
}
}
else
{
println("frame with invalid crc ignored");
_loopState = IDLE;
}
}
else
{
_xorSum ^= rxByte;
}
break;
case RX_WAIT_DATA_CON:
if (!_platform.uartAvailable())
break;
rxByte = _platform.readUart();
_lastByteRxTime = millis();
if ((rxByte & L_DATA_CON_MASK) == L_DATA_CON)
{
//println("L_DATA_CON received");
dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, ((rxByte & SUCCESS) > 0));
_waitConfirm = false;
delete[] _sendBuffer; delete[] _sendBuffer;
_sendBuffer = 0; _sendBuffer = 0;
_sendBufferLength = 0; _sendBufferLength = 0;
_loopState = IDLE; _txState = TX_IDLE;
} }
else else if (millis() - _waitConfirmStartTime > CONFIRM_TIMEOUT)
{ {
//should not happen println("L_DATA_CON not received within expected time");
println("expected L_DATA_CON not received"); uint8_t cemiBuffer[MAX_KNX_TELEGRAM_SIZE];
dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, false); cemiBuffer[0] = 0x29;
_waitConfirm = false; cemiBuffer[1] = 0;
memcpy((cemiBuffer + 2), _sendBuffer, _sendBufferLength);
dataConBytesReceived(cemiBuffer, _sendBufferLength + 2, false);
delete[] _sendBuffer; delete[] _sendBuffer;
_sendBuffer = 0; _sendBuffer = 0;
_sendBufferLength = 0; _sendBufferLength = 0;
_loopState = IDLE; _txState = TX_IDLE;
#ifdef DBG_TRACE
println("TX_IDLE");
#endif
} }
break; break;
default:
break;
}
if (_waitConfirm)
{
if (millis() - _waitConfirmStartTime > CONFIRM_TIMEOUT)
{
println("L_DATA_CON not received within expected time");
uint8_t cemiBuffer[MAX_KNX_TELEGRAM_SIZE];
cemiBuffer[0] = 0x29;
cemiBuffer[1] = 0;
memcpy((cemiBuffer + 2), _sendBuffer, _sendBufferLength);
dataConBytesReceived(cemiBuffer, _sendBufferLength + 2, false);
_waitConfirm = false;
delete[] _sendBuffer;
_sendBuffer = 0;
_sendBufferLength = 0;
if (_loopState == RX_WAIT_DATA_CON)
_loopState = IDLE;
}
} }
} }
@ -496,16 +554,21 @@ bool TpUartDataLinkLayer::sendSingleFrameByte()
cmd[0] = U_L_DATA_END_REQ | _TxByteCnt; cmd[0] = U_L_DATA_END_REQ | _TxByteCnt;
cmd[1] = _sendBuffer[_TxByteCnt]; cmd[1] = _sendBuffer[_TxByteCnt];
#ifdef DBG_TRACE
print(cmd[1], HEX);
#endif
_platform.writeUart(cmd, 2); _platform.writeUart(cmd, 2);
_TxByteCnt++; _TxByteCnt++;
return true;
} }
else
// Check for last byte send
if (_TxByteCnt >= _sendBufferLength)
{ {
_TxByteCnt = 0; _TxByteCnt = 0;
return false; return false;
} }
return true;
} }
void TpUartDataLinkLayer::addFrameTxQueue(CemiFrame& frame) void TpUartDataLinkLayer::addFrameTxQueue(CemiFrame& frame)

View File

@ -31,16 +31,15 @@ class TpUartDataLinkLayer : public DataLinkLayer
private: private:
bool _enabled = false; bool _enabled = false;
bool _waitConfirm = false;
uint8_t* _sendBuffer = 0; uint8_t* _sendBuffer = 0;
uint16_t _sendBufferLength = 0; uint16_t _sendBufferLength = 0;
uint8_t _receiveBuffer[MAX_KNX_TELEGRAM_SIZE]; uint8_t _receiveBuffer[MAX_KNX_TELEGRAM_SIZE];
uint8_t _loopState = 0; uint8_t _txState = 0;
uint8_t _rxState = 0;
uint16_t _RxByteCnt = 0; uint16_t _RxByteCnt = 0;
uint16_t _TxByteCnt = 0; uint16_t _TxByteCnt = 0;
uint8_t _oldIdx = 0; uint8_t _oldIdx = 0;
bool _isEcho = false; bool _isEcho = false;
bool _isAddressed = false;
bool _convert = false; bool _convert = false;
uint8_t _xorSum = 0; uint8_t _xorSum = 0;
uint32_t _lastByteRxTime; uint32_t _lastByteRxTime;

View File

@ -294,6 +294,40 @@ template <class P, class B> class KnxFacade : private SaveRestore
return _bau.parameters().data(addr); return _bau.parameters().data(addr);
} }
// paramBit(address, shift)
// get state of a parameter as a boolean like "enable/disable", ...
// Declaration in XML file:
// ...
// <ParameterType Id="M-00FA_A-0066-EA-0001_PT-toggle" Name="toggle">
// <TypeRestriction Base="Value" SizeInBit="1">
// <Enumeration Text="Désactivé" Value="0" Id="M-00FA_A-0066-EA-0001_PT-toggle_EN-0"/>
// <Enumeration Text="Activé" Value="1" Id="M-00FA_A-0066-EA-0001_PT-toggle_EN-1"/>
// </TypeRestriction>
// </ParameterType>
// ...
// <Parameter Id="M-00FA_A-0066-EA-0001_P-2" Name="Input 1" ParameterType="M-00FA_A-0066-EA-0001_PT-toggle" Text="Input 1" Value="1">
// <Memory CodeSegment="M-00FA_A-0066-EA-0001_RS-04-00000" Offset="1" BitOffset="0"/>
// </Parameter>
// <Parameter Id="M-00FA_A-0066-EA-0001_P-3" Name="Input 2" ParameterType="M-00FA_A-0066-EA-0001_PT-toggle" Text="Input 2" Value="1">
// <Memory CodeSegment="M-00FA_A-0066-EA-0001_RS-04-00000" Offset="1" BitOffset="1"/>
// </Parameter>
// <Parameter Id="M-00FA_A-0066-EA-0001_P-4" Name="Inout 3" ParameterType="M-00FA_A-0066-EA-0001_PT-toggle" Text="Input 3" Value="1">
// <Memory CodeSegment="M-00FA_A-0066-EA-0001_RS-04-00000" Offset="1" BitOffset="2"/>
// </Parameter>
// ...
// Usage in code :
// if ( knx.paramBit(1,1))
// {
// //do somthings ....
// }
bool paramBit(uint32_t addr, uint8_t shift)
{
if (!_bau.configured())
return 0;
return (bool) ((_bau.parameters().getByte(addr) >> (7-shift)) & 0x01);
}
uint8_t paramByte(uint32_t addr) uint8_t paramByte(uint32_t addr)
{ {
if (!_bau.configured()) if (!_bau.configured())
@ -301,7 +335,20 @@ template <class P, class B> class KnxFacade : private SaveRestore
return _bau.parameters().getByte(addr); return _bau.parameters().getByte(addr);
} }
// Same usage than paramByte(addresse) for signed parameters
// Declaration in XML file
// <ParameterType Id="M-00FA_A-0066-EA-0001_PT-delta" Name="delta">
// <TypeNumber SizeInBit="8" Type="signedInt" minInclusive="-10" maxInclusive="10"/>
// </ParameterType>
int8_t paramSignedByte(uint32_t addr)
{
if (!_bau.configured())
return 0;
return (int8_t) _bau.parameters().getByte(addr);
}
uint16_t paramWord(uint32_t addr) uint16_t paramWord(uint32_t addr)
{ {
if (!_bau.configured()) if (!_bau.configured())

View File

@ -1,7 +1,7 @@
#include "stm32_platform.h" #include "stm32_platform.h"
#ifdef ARDUINO_ARCH_STM32 #ifdef ARDUINO_ARCH_STM32
#include <stm32_eeprom.h> #include <EEPROM.h>
#include "knx/bits.h" #include "knx/bits.h"
Stm32Platform::Stm32Platform() Stm32Platform::Stm32Platform()