mirror of
https://github.com/thelsing/knx.git
synced 2025-08-17 13:47:28 +02:00
Save work
This commit is contained in:
parent
478f5c569a
commit
619c6383d2
@ -259,6 +259,17 @@ void CemiFrame::ack(AckType value)
|
|||||||
_ctrl1[0] |= value;
|
_ctrl1[0] |= value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Confirm CemiFrame::confirm() const
|
||||||
|
{
|
||||||
|
return (Confirm)(_ctrl1[0] & ConfirmError);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiFrame::confirm(Confirm value)
|
||||||
|
{
|
||||||
|
_ctrl1[0] &= ~ConfirmError;
|
||||||
|
_ctrl1[0] |= value;
|
||||||
|
}
|
||||||
|
|
||||||
AddressType CemiFrame::addressType() const
|
AddressType CemiFrame::addressType() const
|
||||||
{
|
{
|
||||||
return (AddressType)(_ctrl1[1] & GroupAddress);
|
return (AddressType)(_ctrl1[1] & GroupAddress);
|
||||||
|
@ -45,6 +45,8 @@ class CemiFrame
|
|||||||
void priority(Priority value);
|
void priority(Priority value);
|
||||||
AckType ack() const;
|
AckType ack() const;
|
||||||
void ack(AckType value);
|
void ack(AckType value);
|
||||||
|
Confirm confirm() const;
|
||||||
|
void confirm(Confirm value);
|
||||||
AddressType addressType() const;
|
AddressType addressType() const;
|
||||||
void addressType(AddressType value);
|
void addressType(AddressType value);
|
||||||
uint8_t hopCount() const;
|
uint8_t hopCount() const;
|
||||||
|
@ -13,6 +13,9 @@ CemiServer::CemiServer(BauSystemB& bau)
|
|||||||
_bau.deviceObject().maskVersion(),
|
_bau.deviceObject().maskVersion(),
|
||||||
_bau.deviceObject().manufacturerId())
|
_bau.deviceObject().manufacturerId())
|
||||||
{
|
{
|
||||||
|
// The cEMI server will hand out the device address + 1 to the cEMI client (e.g. ETS),
|
||||||
|
// so that the device and the cEMI client/server connection(tunnel) can operate simultaneously.
|
||||||
|
_clientAddress = _bau.deviceObject().induvidualAddress() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CemiServer::dataLinkLayer(DataLinkLayer& layer)
|
void CemiServer::dataLinkLayer(DataLinkLayer& layer)
|
||||||
@ -20,10 +23,52 @@ void CemiServer::dataLinkLayer(DataLinkLayer& layer)
|
|||||||
_dataLinkLayer = &layer;
|
_dataLinkLayer = &layer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t CemiServer::clientAddress() const
|
||||||
|
{
|
||||||
|
return _clientAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiServer::clientAddress(uint16_t value)
|
||||||
|
{
|
||||||
|
_clientAddress = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CemiServer::dataConfirmationToTunnel(CemiFrame& frame)
|
||||||
|
{
|
||||||
|
print("L_data_con: src: ");
|
||||||
|
print(frame.sourceAddress(), HEX);
|
||||||
|
print(" dst: ");
|
||||||
|
print(frame.destinationAddress(), HEX);
|
||||||
|
|
||||||
|
printHex(" frame: ", frame.data(), frame.dataLength());
|
||||||
|
|
||||||
|
_usbTunnelInterface.sendCemiFrame(frame);
|
||||||
|
}
|
||||||
|
|
||||||
void CemiServer::dataIndicationToTunnel(CemiFrame& frame)
|
void CemiServer::dataIndicationToTunnel(CemiFrame& frame)
|
||||||
{
|
{
|
||||||
println("L_data_ind: ");
|
static uint8_t lfn = 0;
|
||||||
_usbTunnelInterface.sendCemiFrame(frame);
|
uint8_t data[frame.dataLength() + 10];
|
||||||
|
data[0] = L_data_ind;
|
||||||
|
data[1] = 10;
|
||||||
|
data[2] = 0x02; // RF Info add. info
|
||||||
|
data[3] = 0x08; // RF info length
|
||||||
|
data[4] = 0x02; // RF info field (batt ok)
|
||||||
|
pushByteArray(_bau.deviceObject().rfDomainAddress(), 6, &data[5]);
|
||||||
|
data[11] = lfn;
|
||||||
|
lfn = (lfn + 1) & 0x7;
|
||||||
|
memcpy(&data[12], &frame.data()[2], frame.dataLength() - 2);
|
||||||
|
|
||||||
|
CemiFrame tmpFrame(data, sizeof(data));
|
||||||
|
|
||||||
|
print("L_data_ind: src: ");
|
||||||
|
print(tmpFrame.sourceAddress(), HEX);
|
||||||
|
print(" dst: ");
|
||||||
|
print(tmpFrame.destinationAddress(), HEX);
|
||||||
|
|
||||||
|
printHex(" frame: ", tmpFrame.data(), tmpFrame.dataLength());
|
||||||
|
|
||||||
|
_usbTunnelInterface.sendCemiFrame(tmpFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -42,15 +87,21 @@ void CemiServer::frameReceived(CemiFrame& frame)
|
|||||||
{
|
{
|
||||||
case L_data_req:
|
case L_data_req:
|
||||||
{
|
{
|
||||||
println("L_data_req: ");
|
// Fill in the cEMI client address if the client sets
|
||||||
|
// source address to 0.
|
||||||
|
if(frame.sourceAddress() == 0x0000)
|
||||||
|
{
|
||||||
|
frame.sourceAddress(_clientAddress);
|
||||||
|
}
|
||||||
|
|
||||||
// Send as indication to data link layer
|
print("L_data_req: src: ");
|
||||||
frame.messageCode(L_data_ind);
|
print(frame.sourceAddress(), HEX);
|
||||||
_dataLinkLayer->dataIndicationFromTunnel(frame);
|
print(" dst: ");
|
||||||
|
print(frame.destinationAddress(), HEX);
|
||||||
|
|
||||||
// Send local reply to tunnel
|
printHex(" frame: ", frame.data(), frame.dataLength());
|
||||||
frame.messageCode(L_data_con);
|
|
||||||
_usbTunnelInterface.sendCemiFrame(frame);
|
_dataLinkLayer->dataRequestFromTunnel(frame);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +132,24 @@ void CemiServer::frameReceived(CemiFrame& frame)
|
|||||||
// propertyValueRead() allocates memory for the data! Needs to be deleted again!
|
// propertyValueRead() allocates memory for the data! Needs to be deleted again!
|
||||||
_bau.propertyValueRead((ObjectType)objectType, objectInstance, propertyId, numberOfElements, startIndex, &data, dataSize);
|
_bau.propertyValueRead((ObjectType)objectType, objectInstance, propertyId, numberOfElements, startIndex, &data, dataSize);
|
||||||
|
|
||||||
|
// Patch result for device address in device object
|
||||||
|
// The cEMI server will hand out the device address + 1 to the cEMI client (e.g. ETS),
|
||||||
|
// so that the device and the cEMI client/server connection(tunnel) can operate simultaneously.
|
||||||
|
// KNX IP Interfaces which offer multiple simultaneous tunnel connections seem to operate the same way.
|
||||||
|
// Each tunnel has its own cEMI client address which is based on the main device address.
|
||||||
|
if (((ObjectType) objectType == OT_DEVICE) &&
|
||||||
|
(propertyId == PID_DEVICE_ADDR) &&
|
||||||
|
(numberOfElements == 1))
|
||||||
|
{
|
||||||
|
data[0] = (uint8_t) (_clientAddress & 0xFF);
|
||||||
|
}
|
||||||
|
else if (((ObjectType) objectType == OT_DEVICE) &&
|
||||||
|
(propertyId == PID_SUBNET_ADDR) &&
|
||||||
|
(numberOfElements == 1))
|
||||||
|
{
|
||||||
|
data[0] = (uint8_t) ((_clientAddress >> 8) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
if (data && dataSize && numberOfElements)
|
if (data && dataSize && numberOfElements)
|
||||||
{
|
{
|
||||||
printHex(" <- data: ", data, dataSize);
|
printHex(" <- data: ", data, dataSize);
|
||||||
@ -95,7 +164,7 @@ void CemiServer::frameReceived(CemiFrame& frame)
|
|||||||
responseFrame.messageCode(M_PropRead_con);
|
responseFrame.messageCode(M_PropRead_con);
|
||||||
_usbTunnelInterface.sendCemiFrame(responseFrame);
|
_usbTunnelInterface.sendCemiFrame(responseFrame);
|
||||||
|
|
||||||
delete data;
|
delete[] data;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -141,7 +210,31 @@ void CemiServer::frameReceived(CemiFrame& frame)
|
|||||||
|
|
||||||
printHex(" -> data: ", requestData, requestDataSize);
|
printHex(" -> data: ", requestData, requestDataSize);
|
||||||
|
|
||||||
_bau.propertyValueWrite((ObjectType)objectType, objectInstance, propertyId, numberOfElements, startIndex, requestData, requestDataSize);
|
// Patch request for device address in device object
|
||||||
|
if (((ObjectType) objectType == OT_DEVICE) &&
|
||||||
|
(propertyId == PID_DEVICE_ADDR) &&
|
||||||
|
(numberOfElements == 1))
|
||||||
|
{
|
||||||
|
// Temporarily store new cEMI client address in memory
|
||||||
|
// We also be sent back if the client requests it again
|
||||||
|
_clientAddress = (_clientAddress & 0xFF00) | requestData[0];
|
||||||
|
print("cEMI client address: ");
|
||||||
|
println(_clientAddress, HEX);
|
||||||
|
}
|
||||||
|
else if (((ObjectType) objectType == OT_DEVICE) &&
|
||||||
|
(propertyId == PID_SUBNET_ADDR) &&
|
||||||
|
(numberOfElements == 1))
|
||||||
|
{
|
||||||
|
// Temporarily store new cEMI client address in memory
|
||||||
|
// We also be sent back if the client requests it again
|
||||||
|
_clientAddress = (_clientAddress & 0x00FF) | (requestData[0] << 8);
|
||||||
|
print("cEMI client address: ");
|
||||||
|
println(_clientAddress, HEX);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_bau.propertyValueWrite((ObjectType)objectType, objectInstance, propertyId, numberOfElements, startIndex, requestData, requestDataSize);
|
||||||
|
}
|
||||||
|
|
||||||
if (numberOfElements)
|
if (numberOfElements)
|
||||||
{
|
{
|
||||||
@ -214,169 +307,3 @@ void CemiServer::loop()
|
|||||||
{
|
{
|
||||||
_usbTunnelInterface.loop();
|
_usbTunnelInterface.loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
void CemiServer::propertyValueReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
|
|
||||||
uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex)
|
|
||||||
{
|
|
||||||
CemiFrame frame(5);
|
|
||||||
APDU& apdu = frame.apdu();
|
|
||||||
apdu.type(PropertyValueRead);
|
|
||||||
uint8_t* data = apdu.data();
|
|
||||||
data += 1;
|
|
||||||
data = pushByte(objectIndex, data);
|
|
||||||
data = pushByte(propertyId, data);
|
|
||||||
pushWord(startIndex & 0xfff, data);
|
|
||||||
*data &= ((numberOfElements & 0xf) << 4);
|
|
||||||
|
|
||||||
individualSend(ack, hopType, priority, asap, apdu);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CemiServer::propertyValueReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
|
|
||||||
uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length)
|
|
||||||
{
|
|
||||||
propertyDataSend(PropertyValueResponse, ack, priority, hopType, asap, objectIndex, propertyId, numberOfElements,
|
|
||||||
startIndex, data, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CemiServer::propertyValueWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
|
|
||||||
uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t * data, uint8_t length)
|
|
||||||
{
|
|
||||||
propertyDataSend(PropertyValueWrite, ack, priority, hopType, asap, objectIndex, propertyId, numberOfElements,
|
|
||||||
startIndex, data, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CemiServer::propertyDescriptionReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
|
|
||||||
uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex)
|
|
||||||
{
|
|
||||||
CemiFrame frame(4);
|
|
||||||
APDU& apdu = frame.apdu();
|
|
||||||
apdu.type(PropertyDescriptionRead);
|
|
||||||
uint8_t* data = apdu.data();
|
|
||||||
data[1] = objectIndex;
|
|
||||||
data[2] = propertyId;
|
|
||||||
data[3] = propertyIndex;
|
|
||||||
individualSend(ack, hopType, priority, asap, apdu);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CemiServer::propertyDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
|
|
||||||
uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type,
|
|
||||||
uint16_t maxNumberOfElements, uint8_t access)
|
|
||||||
{
|
|
||||||
CemiFrame frame(8);
|
|
||||||
APDU& apdu = frame.apdu();
|
|
||||||
apdu.type(PropertyDescriptionResponse);
|
|
||||||
uint8_t* data = apdu.data();
|
|
||||||
data[1] = objectIndex;
|
|
||||||
data[2] = propertyId;
|
|
||||||
data[3] = propertyIndex;
|
|
||||||
if (writeEnable)
|
|
||||||
data[4] |= 0x80;
|
|
||||||
data[4] |= (type & 0x3f);
|
|
||||||
pushWord(maxNumberOfElements & 0xfff, data + 5);
|
|
||||||
data[7] = access;
|
|
||||||
individualSend(ack, hopType, priority, asap, apdu);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void CemiServer::propertyDataSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
|
|
||||||
uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length)
|
|
||||||
{
|
|
||||||
CemiFrame frame(5 + length);
|
|
||||||
APDU& apdu = frame.apdu();
|
|
||||||
apdu.type(type);
|
|
||||||
uint8_t* apduData = apdu.data();
|
|
||||||
apduData += 1;
|
|
||||||
apduData = pushByte(objectIndex, apduData);
|
|
||||||
apduData = pushByte(propertyId, apduData);
|
|
||||||
pushWord(startIndex & 0xfff, apduData);
|
|
||||||
*apduData |= ((numberOfElements & 0xf) << 4);
|
|
||||||
apduData += 2;
|
|
||||||
if (length > 0)
|
|
||||||
memcpy(apduData, data, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CemiServer::individualIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU & apdu)
|
|
||||||
{
|
|
||||||
uint8_t* data = apdu.data();
|
|
||||||
switch (apdu.type())
|
|
||||||
{
|
|
||||||
case PropertyValueRead:
|
|
||||||
{
|
|
||||||
uint16_t startIndex;
|
|
||||||
popWord(startIndex, data + 3);
|
|
||||||
startIndex &= 0xfff;
|
|
||||||
_bau.propertyValueReadIndication(priority, hopType, tsap, data[1], data[2], data[3] >> 4, startIndex);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PropertyValueResponse:
|
|
||||||
{
|
|
||||||
uint16_t startIndex;
|
|
||||||
popWord(startIndex, data + 3);
|
|
||||||
startIndex &= 0xfff;
|
|
||||||
_bau.propertyValueReadAppLayerConfirm(priority, hopType, tsap, data[1], data[2], data[3] >> 4,
|
|
||||||
startIndex, data + 5, apdu.length() - 5);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PropertyValueWrite:
|
|
||||||
{
|
|
||||||
uint16_t startIndex;
|
|
||||||
popWord(startIndex, data + 3);
|
|
||||||
startIndex &= 0xfff;
|
|
||||||
_bau.propertyValueWriteIndication(priority, hopType, tsap, data[1], data[2], data[3] >> 4,
|
|
||||||
startIndex, data + 5, apdu.length() - 5);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PropertyDescriptionRead:
|
|
||||||
_bau.propertyDescriptionReadIndication(priority, hopType, tsap, data[1], data[2], data[3]);
|
|
||||||
break;
|
|
||||||
case PropertyDescriptionResponse:
|
|
||||||
_bau.propertyDescriptionReadAppLayerConfirm(priority, hopType, tsap, data[1], data[2], data[3],
|
|
||||||
(data[4] & 0x80) > 0, data[4] & 0x3f, getWord(data + 5) & 0xfff, data[7]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CemiServer::individualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU & apdu, bool status)
|
|
||||||
{
|
|
||||||
uint8_t* data = apdu.data();
|
|
||||||
switch (apdu.type())
|
|
||||||
{
|
|
||||||
case PropertyValueRead:
|
|
||||||
{
|
|
||||||
uint16_t startIndex;
|
|
||||||
popWord(startIndex, data + 3);
|
|
||||||
startIndex &= 0xfff;
|
|
||||||
_bau.propertyValueReadLocalConfirm(ack, priority, hopType, tsap, data[1], data[2], data[3] >> 4,
|
|
||||||
startIndex, status);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PropertyValueResponse:
|
|
||||||
{
|
|
||||||
uint16_t startIndex;
|
|
||||||
popWord(startIndex, data + 3);
|
|
||||||
startIndex &= 0xfff;
|
|
||||||
_bau.propertyValueReadResponseConfirm(ack, priority, hopType, tsap, data[1], data[2], data[3] >> 4,
|
|
||||||
startIndex, data + 5, apdu.length() - 5, status);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PropertyValueWrite:
|
|
||||||
{
|
|
||||||
uint16_t startIndex;
|
|
||||||
popWord(startIndex, data + 3);
|
|
||||||
startIndex &= 0xfff;
|
|
||||||
_bau.propertyValueWriteLocalConfirm(ack, priority, hopType, tsap, data[1], data[2], data[3] >> 4,
|
|
||||||
startIndex, data + 5, apdu.length() - 5, status);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PropertyDescriptionRead:
|
|
||||||
_bau.propertyDescriptionReadLocalConfirm(ack, priority, hopType, tsap, data[1], data[2], data[3], status);
|
|
||||||
break;
|
|
||||||
case PropertyDescriptionResponse:
|
|
||||||
_bau.propertyDescriptionReadResponseConfirm(ack, priority, hopType, tsap, data[1], data[2], data[3],
|
|
||||||
(data[4] & 0x80) > 0, data[4] & 0x3f, getWord(data + 5) & 0xfff, data[7], status);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
@ -31,13 +31,19 @@ class CemiServer
|
|||||||
// from data link layer
|
// from data link layer
|
||||||
// Only L_Data service
|
// Only L_Data service
|
||||||
void dataIndicationToTunnel(CemiFrame& frame);
|
void dataIndicationToTunnel(CemiFrame& frame);
|
||||||
|
void dataConfirmationToTunnel(CemiFrame& frame);
|
||||||
|
|
||||||
// From tunnel interface
|
// From tunnel interface
|
||||||
void frameReceived(CemiFrame& frame);
|
void frameReceived(CemiFrame& frame);
|
||||||
|
|
||||||
|
uint16_t clientAddress() const;
|
||||||
|
void clientAddress(uint16_t value);
|
||||||
|
|
||||||
void loop();
|
void loop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
uint16_t _clientAddress;
|
||||||
|
|
||||||
DataLinkLayer* _dataLinkLayer;
|
DataLinkLayer* _dataLinkLayer;
|
||||||
BauSystemB& _bau;
|
BauSystemB& _bau;
|
||||||
UsbDataLinkLayer _usbTunnelInterface;
|
UsbDataLinkLayer _usbTunnelInterface;
|
||||||
|
@ -17,21 +17,27 @@ void DataLinkLayer::cemiServer(CemiServer& cemiServer)
|
|||||||
_cemiServer = &cemiServer;
|
_cemiServer = &cemiServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataLinkLayer::dataIndicationFromTunnel(CemiFrame& frame)
|
void DataLinkLayer::dataRequestFromTunnel(CemiFrame& frame)
|
||||||
{
|
{
|
||||||
uint16_t destination = frame.destinationAddress();
|
uint16_t destination = frame.destinationAddress();
|
||||||
uint16_t ownAddr = _deviceObject.induvidualAddress();
|
uint16_t ownAddr = _deviceObject.induvidualAddress();
|
||||||
AddressType addrType = frame.addressType();
|
AddressType addrType = frame.addressType();
|
||||||
|
|
||||||
|
frame.messageCode(L_data_con);
|
||||||
|
_cemiServer->dataConfirmationToTunnel(frame);
|
||||||
|
|
||||||
|
frame.messageCode(L_data_ind);
|
||||||
|
|
||||||
if (addrType == InduvidualAddress)
|
if (addrType == InduvidualAddress)
|
||||||
{
|
{
|
||||||
// TODO: check if this is correct: shall we send a frame to the bus too if it was intended for us?
|
|
||||||
if (destination == ownAddr)
|
if (destination == ownAddr)
|
||||||
{
|
{
|
||||||
// Send to local stack
|
// Send to local stack
|
||||||
frameRecieved(frame);
|
frameRecieved(frame);
|
||||||
|
// Send back a confirmation
|
||||||
|
//dataConReceived(frame, true);
|
||||||
}
|
}
|
||||||
else
|
else // TODO: check if this is correct: shall we send a frame to the bus too if it was intended for us?
|
||||||
{
|
{
|
||||||
// Send to KNX medium
|
// Send to KNX medium
|
||||||
sendFrame(frame);
|
sendFrame(frame);
|
||||||
@ -63,6 +69,8 @@ void DataLinkLayer::systemBroadcastRequest(AckType ack, FrameFormat format, Prio
|
|||||||
|
|
||||||
void DataLinkLayer::dataConReceived(CemiFrame& frame, bool success)
|
void DataLinkLayer::dataConReceived(CemiFrame& frame, bool success)
|
||||||
{
|
{
|
||||||
|
frame.messageCode(L_data_con);
|
||||||
|
frame.confirm(success ? ConfirmNoError : ConfirmError);
|
||||||
AckType ack = frame.ack();
|
AckType ack = frame.ack();
|
||||||
AddressType addrType = frame.addressType();
|
AddressType addrType = frame.addressType();
|
||||||
uint16_t destination = frame.destinationAddress();
|
uint16_t destination = frame.destinationAddress();
|
||||||
@ -72,6 +80,17 @@ void DataLinkLayer::dataConReceived(CemiFrame& frame, bool success)
|
|||||||
NPDU& npdu = frame.npdu();
|
NPDU& npdu = frame.npdu();
|
||||||
SystemBroadcast systemBroadcast = frame.systemBroadcast();
|
SystemBroadcast systemBroadcast = frame.systemBroadcast();
|
||||||
|
|
||||||
|
if (_cemiServer)
|
||||||
|
{
|
||||||
|
// Only send our own confirmation messages to the tunnel
|
||||||
|
if (frame.sourceAddress() == _cemiServer->clientAddress())
|
||||||
|
{
|
||||||
|
//_cemiServer->dataConfirmationToTunnel(frame);
|
||||||
|
// Stop processing here and do NOT send it the local network layer
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (addrType == GroupAddress && destination == 0)
|
if (addrType == GroupAddress && destination == 0)
|
||||||
if (systemBroadcast == SysBroadcast)
|
if (systemBroadcast == SysBroadcast)
|
||||||
_networkLayer.systemBroadcastConfirm(ack, type, priority, source, npdu, success);
|
_networkLayer.systemBroadcastConfirm(ack, type, priority, source, npdu, success);
|
||||||
@ -79,9 +98,8 @@ void DataLinkLayer::dataConReceived(CemiFrame& frame, bool success)
|
|||||||
_networkLayer.broadcastConfirm(ack, type, priority, source, npdu, success);
|
_networkLayer.broadcastConfirm(ack, type, priority, source, npdu, success);
|
||||||
else
|
else
|
||||||
_networkLayer.dataConfirm(ack, addrType, destination, type, priority, source, npdu, success);
|
_networkLayer.dataConfirm(ack, addrType, destination, type, priority, source, npdu, success);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataLinkLayer::frameRecieved(CemiFrame& frame)
|
void DataLinkLayer::frameRecieved(CemiFrame& frame)
|
||||||
{
|
{
|
||||||
AckType ack = frame.ack();
|
AckType ack = frame.ack();
|
||||||
@ -96,8 +114,11 @@ void DataLinkLayer::frameRecieved(CemiFrame& frame)
|
|||||||
|
|
||||||
if (_cemiServer)
|
if (_cemiServer)
|
||||||
{
|
{
|
||||||
// if (source != _cemiServerObj.tunnelAddress)
|
// Do not send our own message back to the tunnel
|
||||||
_cemiServer->dataIndicationToTunnel(frame);
|
if (frame.sourceAddress() != _cemiServer->clientAddress())
|
||||||
|
{
|
||||||
|
_cemiServer->dataIndicationToTunnel(frame);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source == ownAddr)
|
if (source == ownAddr)
|
||||||
@ -157,6 +178,12 @@ bool DataLinkLayer::sendTelegram(NPDU & npdu, AckType ack, uint16_t destinationA
|
|||||||
// frame.apdu().printPDU();
|
// frame.apdu().printPDU();
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
if (_cemiServer)
|
||||||
|
{
|
||||||
|
CemiFrame tmpFrame(frame.data(), frame.totalLenght());
|
||||||
|
_cemiServer->dataIndicationToTunnel(tmpFrame);
|
||||||
|
}
|
||||||
|
|
||||||
return sendFrame(frame);
|
return sendFrame(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,9 +13,9 @@ class DataLinkLayer
|
|||||||
DataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, NetworkLayer& layer,
|
DataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, NetworkLayer& layer,
|
||||||
Platform& platform);
|
Platform& platform);
|
||||||
|
|
||||||
|
// from tunnel
|
||||||
void cemiServer(CemiServer& cemiServer);
|
void cemiServer(CemiServer& cemiServer);
|
||||||
|
void dataRequestFromTunnel(CemiFrame& frame);
|
||||||
void dataIndicationFromTunnel(CemiFrame& frame);
|
|
||||||
|
|
||||||
// from network layer
|
// from network layer
|
||||||
void dataRequest(AckType ack, AddressType addrType, uint16_t destinationAddr, FrameFormat format,
|
void dataRequest(AckType ack, AddressType addrType, uint16_t destinationAddr, FrameFormat format,
|
||||||
|
@ -24,7 +24,10 @@ void RfDataLinkLayer::loop()
|
|||||||
bool RfDataLinkLayer::sendFrame(CemiFrame& frame)
|
bool RfDataLinkLayer::sendFrame(CemiFrame& frame)
|
||||||
{
|
{
|
||||||
if (!_enabled)
|
if (!_enabled)
|
||||||
|
{
|
||||||
|
dataConReceived(frame, false);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Depending on this flag, use either KNX Serial Number
|
// Depending on this flag, use either KNX Serial Number
|
||||||
// or the RF domain address that was programmed by ETS
|
// or the RF domain address that was programmed by ETS
|
||||||
@ -166,7 +169,7 @@ void RfDataLinkLayer::frameBytesReceived(uint8_t* rfPacketBuf, uint16_t length)
|
|||||||
// Prepare CEMI by writing/overwriting certain fields in the buffer (contiguous frame without CRC checksums)
|
// Prepare CEMI by writing/overwriting certain fields in the buffer (contiguous frame without CRC checksums)
|
||||||
// See 3.6.3 p.79: L_Data services for KNX RF asynchronous frames
|
// See 3.6.3 p.79: L_Data services for KNX RF asynchronous frames
|
||||||
// For now we do not use additional info, but use normal method arguments for CEMI
|
// For now we do not use additional info, but use normal method arguments for CEMI
|
||||||
_buffer[0] = 0x29; // L_data.ind
|
_buffer[0] = (uint8_t) L_data_ind; // L_data.ind
|
||||||
_buffer[1] = 0; // Additional info length (spec. says that local dev management is not required to use AddInfo internally)
|
_buffer[1] = 0; // Additional info length (spec. says that local dev management is not required to use AddInfo internally)
|
||||||
_buffer[2] = 0; // CTRL1 field (will be set later, this is the field we reserved space for)
|
_buffer[2] = 0; // CTRL1 field (will be set later, this is the field we reserved space for)
|
||||||
_buffer[3] &= 0x0F; // CTRL2 field (take only RFCtrl.b3..0, b7..4 shall always be 0 for asynchronous KNX RF)
|
_buffer[3] &= 0x0F; // CTRL2 field (take only RFCtrl.b3..0, b7..4 shall always be 0 for asynchronous KNX RF)
|
||||||
|
@ -364,7 +364,10 @@ void TpUartDataLinkLayer::loop()
|
|||||||
bool TpUartDataLinkLayer::sendFrame(CemiFrame& frame)
|
bool TpUartDataLinkLayer::sendFrame(CemiFrame& frame)
|
||||||
{
|
{
|
||||||
if (!_enabled)
|
if (!_enabled)
|
||||||
|
{
|
||||||
|
dataConReceived(frame, false);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
addFrameTxQueue(frame);
|
addFrameTxQueue(frame);
|
||||||
return true;
|
return true;
|
||||||
|
@ -207,7 +207,7 @@ static void handleBusAccessServerProtocol(const uint8_t* requestData, uint16_t p
|
|||||||
{
|
{
|
||||||
data[2] += respDataSize; // HID Report Header: Packet Length
|
data[2] += respDataSize; // HID Report Header: Packet Length
|
||||||
data[6] += respDataSize; // USB KNX Transfer Protocol Header: Body Length
|
data[6] += respDataSize; // USB KNX Transfer Protocol Header: Body Length
|
||||||
|
/*
|
||||||
Serial1.print("TX HID report: len: ");
|
Serial1.print("TX HID report: len: ");
|
||||||
Serial1.println((packetLength) + respDataSize, DEC);
|
Serial1.println((packetLength) + respDataSize, DEC);
|
||||||
|
|
||||||
@ -219,7 +219,7 @@ static void handleBusAccessServerProtocol(const uint8_t* requestData, uint16_t p
|
|||||||
Serial1.print(" ");
|
Serial1.print(" ");
|
||||||
}
|
}
|
||||||
Serial1.println("");
|
Serial1.println("");
|
||||||
|
*/
|
||||||
usb_hid.sendReport(0, data, MAX_EP_SIZE);
|
usb_hid.sendReport(0, data, MAX_EP_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user