diff --git a/bau07B0.cpp b/bau07B0.cpp new file mode 100644 index 0000000..76c4b0c --- /dev/null +++ b/bau07B0.cpp @@ -0,0 +1,303 @@ +#include "bau07B0.h" +#include +#include + + +using namespace std; + +Bau07B0::Bau07B0(Platform& platform): _memoryReference((uint8_t*)&_deviceObj), _memory(platform), _addrTable(_memoryReference), + _assocTable(_memoryReference), _groupObjTable(_memoryReference), _appProgram(_memoryReference), + _platform(platform), _appLayer(_assocTable, *this), + _transLayer(_appLayer, _addrTable, _platform), _netLayer(_transLayer), + _dlLayer(_deviceObj, _addrTable, _netLayer, _platform) +{ + _appLayer.transportLayer(_transLayer); + _transLayer.networkLayer(_netLayer); + _netLayer.dataLinkLayer(_dlLayer); + _memory.addSaveRestore(&_deviceObj); + _memory.addSaveRestore(&_appProgram); + _memory.addSaveRestore(&_addrTable); + _memory.addSaveRestore(&_assocTable); + _memory.addSaveRestore(&_groupObjTable); +} + +void Bau07B0::loop() +{ + _dlLayer.loop(); + _transLayer.loop(); + sendNextGroupTelegram(); +} + +void Bau07B0::sendNextGroupTelegram() +{ + static uint16_t startIdx = 1; + + GroupObjectTableObject& table = _groupObjTable; + uint16_t objCount = table.entryCount(); + + for (uint16_t asap = startIdx; asap < objCount; asap++) + { + GroupObject& go = table.get(asap); + + ComFlag flag = go.commFlag(); + if (flag != ReadRequest && flag != WriteRequest) + continue; + + if(!go.communicationEnable() || ! go.transmitEnable()) + continue; + + if (flag == WriteRequest) + { + uint8_t* data = go.valueRef(); + _appLayer.groupValueWriteRequest(AckRequested, asap, go.priority(), NetworkLayerParameter, data, + go.sizeInTelegram()); + } + else + { + _appLayer.groupValueReadRequest(AckRequested, asap, go.priority(), NetworkLayerParameter); + } + + go.commFlag(Transmitting); + + startIdx = asap + 1; + return; + } + + startIdx = 1; +} + +void Bau07B0::updateGroupObject(GroupObject & go, uint8_t * data, uint8_t length) +{ + uint8_t* goData = go.valueRef(); + if (length != go.valueSize()) + { + go.commFlag(Error); + return; + } + + memcpy(goData, data, length); + + go.commFlag(cfUpdate); + if (go.updateHandler) + go.updateHandler(go); +} + +void Bau07B0::readMemory() +{ + _memory.readMemory(); +} + +DeviceObject& Bau07B0::deviceObject() +{ + return _deviceObj; +} + +GroupObjectTableObject& Bau07B0::groupObjectTable() +{ + return _groupObjTable; +} + +ApplicationProgramObject& Bau07B0::parameters() +{ + return _appProgram; +} + +bool Bau07B0::configured() +{ + return _groupObjTable.loadState() == LS_LOADED + && _addrTable.loadState() == LS_LOADED + && _assocTable.loadState() == LS_LOADED + && _appProgram.loadState() == LS_LOADED; +} + +bool Bau07B0::enabled() +{ + return _dlLayer.enabled(); +} + +void Bau07B0::enabled(bool value) +{ + _dlLayer.enabled(value); +} + +void Bau07B0::memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, + uint16_t memoryAddress, uint8_t * data) +{ + memcpy(_memoryReference + memoryAddress, data, number); + _memory.memoryModified(); + + if (_deviceObj.verifyMode()) + memoryReadIndication(priority, hopType, asap, number, memoryAddress); +} + +void Bau07B0::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, + uint16_t memoryAddress) +{ + _appLayer.memoryReadResponse(AckRequested, priority, hopType, asap, number, memoryAddress, + _memoryReference + memoryAddress); +} + +void Bau07B0::deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t descriptorType) +{ + if (descriptorType != 0) + descriptorType = 0x3f; + + uint8_t descriptor[] = { 0x07, 0xb0 }; + + _appLayer.deviceDescriptorReadResponse(AckRequested, priority, hopType, asap, descriptorType, descriptor); +} + +void Bau07B0::restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap) +{ + // for platforms that don't really restart + _deviceObj.progMode(false); + + // Flush the EEPROM before resetting + _memory.writeMemory(); + _platform.restart(); +} + +void Bau07B0::authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, uint32_t key) +{ + _appLayer.authorizeResponse(AckRequested, priority, hopType, asap, 0); +} + +void Bau07B0::userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint32_t memoryAddress) +{ + _appLayer.userMemoryReadResponse(AckRequested, priority, hopType, asap, number, memoryAddress, + _memoryReference + memoryAddress); +} + +void Bau07B0::userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint32_t memoryAddress, uint8_t* data) +{ + memcpy(_memoryReference + memoryAddress, data, number); + _memory.memoryModified(); + + if (_deviceObj.verifyMode()) + userMemoryReadIndication(priority, hopType, asap, number, memoryAddress); +} + +void Bau07B0::propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex, + uint8_t propertyId, uint8_t propertyIndex) +{ + uint8_t pid = propertyId; + bool writeEnable = false; + uint8_t type = 0; + uint16_t numberOfElements = 0; + uint8_t access = 0; + InterfaceObject* obj = getInterfaceObject(objectIndex); + if (obj) + obj->readPropertyDescription(pid, propertyIndex, writeEnable, type, numberOfElements, access); + + _appLayer.propertyDescriptionReadResponse(AckRequested, priority, hopType, asap, objectIndex, pid, propertyIndex, + writeEnable, type, numberOfElements, access); +} + +void Bau07B0::propertyValueWriteIndication(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) +{ + InterfaceObject* obj = getInterfaceObject(objectIndex); + if(obj) + obj->writeProperty((PropertyID)propertyId, startIndex, data, numberOfElements); + propertyValueReadIndication(priority, hopType, asap, objectIndex, propertyId, numberOfElements, startIndex); +} + +void Bau07B0::propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex) +{ + uint8_t size = 0; + uint32_t elementCount = numberOfElements; + InterfaceObject* obj = getInterfaceObject(objectIndex); + if (obj) + { + uint8_t elementSize = obj->propertySize((PropertyID)propertyId); + size = elementSize * numberOfElements; + } + else + elementCount = 0; + + uint8_t data[size]; + if(obj) + obj->readProperty((PropertyID)propertyId, startIndex, elementCount, data); + _appLayer.propertyValueReadResponse(AckRequested, priority, hopType, asap, objectIndex, propertyId, elementCount, + startIndex, data, size); +} + +void Bau07B0::individualAddressReadIndication(HopCountType hopType) +{ + if (_deviceObj.progMode()) + _appLayer.individualAddressReadResponse(AckRequested, hopType); +} + +void Bau07B0::individualAddressWriteIndication(HopCountType hopType, uint16_t newaddress) +{ + if (_deviceObj.progMode()) + _deviceObj.induvidualAddress(newaddress); +} + +void Bau07B0::groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, uint8_t * data, uint8_t dataLength, bool status) +{ + GroupObject& go = _groupObjTable.get(asap); + if (status) + go.commFlag(Ok); + else + go.commFlag(Error); +} + +void Bau07B0::groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, bool status) +{ + GroupObject& go = _groupObjTable.get(asap); + if (status) + go.commFlag(Ok); + else + go.commFlag(Error); +} + +void Bau07B0::groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType) +{ + GroupObject& go = _groupObjTable.get(asap); + uint8_t* data = go.valueRef(); + _appLayer.groupValueReadResponse(AckRequested, asap, priority, hopType, data, go.sizeInTelegram()); +} + +void Bau07B0::groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, uint8_t* data, + uint8_t dataLength) +{ + GroupObject& go = _groupObjTable.get(asap); + + if (!go.communicationEnable() || !go.responseUpdateEnable()) + return; + + updateGroupObject(go, data, dataLength); +} + +void Bau07B0::groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType, uint8_t * data, uint8_t dataLength) +{ + GroupObject& go = _groupObjTable.get(asap); + + if (!go.communicationEnable() || !go.writeEnable()) + return; + + updateGroupObject(go, data, dataLength); +} + +InterfaceObject* Bau07B0::getInterfaceObject(uint8_t idx) +{ + switch (idx) + { + case 0: + return &_deviceObj; + case 1: + return &_addrTable; + case 2: + return &_assocTable; + case 3: + return &_groupObjTable; + case 4: + return &_appProgram; + case 5: // would be app_program 2 + return nullptr; + default: + return nullptr; + } +} \ No newline at end of file diff --git a/bau07B0.h b/bau07B0.h new file mode 100644 index 0000000..b9dd7b5 --- /dev/null +++ b/bau07B0.h @@ -0,0 +1,75 @@ +#pragma once + +#include "bau.h" +#include "device_object.h" +#include "address_table_object.h" +#include "association_table_object.h" +#include "group_object_table_object.h" +#include "application_program_object.h" +#include "application_layer.h" +#include "transport_layer.h" +#include "network_layer.h" +#include "tpuart_data_link_layer.h" +#include "platform.h" +#include "memory.h" + +class Bau07B0: protected BusAccessUnit +{ + using BusAccessUnit::memoryReadIndication; +public: + Bau07B0(Platform& platform); + void loop(); + DeviceObject& deviceObject(); + GroupObjectTableObject& groupObjectTable(); + ApplicationProgramObject& parameters(); + bool configured(); + bool enabled(); + void enabled(bool value); + void readMemory(); +protected: + void memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, + uint16_t memoryAddress, uint8_t* data) override; + void memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, + uint16_t memoryAddress) override; + void deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t descriptorType); + void restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap); + void authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, uint32_t key); + void userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint32_t memoryAddress); + void userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, + uint32_t memoryAddress, uint8_t* memoryData); + void propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex, + uint8_t propertyId, uint8_t propertyIndex); + void propertyValueWriteIndication(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); + void propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex, + uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex); + void individualAddressReadIndication(HopCountType hopType); + void individualAddressWriteIndication(HopCountType hopType, uint16_t newaddress); + void groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, + uint8_t* data, uint8_t dataLength, bool status); + void groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, bool status); + void groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType); + void groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, + uint8_t* data, uint8_t dataLength); + void groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType, + uint8_t* data, uint8_t dataLength); + + InterfaceObject* getInterfaceObject(uint8_t idx); + void sendNextGroupTelegram(); + void updateGroupObject(GroupObject& go, uint8_t* data, uint8_t length); +private: + DeviceObject _deviceObj; + // pointer to first private variable as reference to memory read/write commands + uint8_t* _memoryReference; + Memory _memory; + AddressTableObject _addrTable; + AssociationTableObject _assocTable; + GroupObjectTableObject _groupObjTable; + ApplicationProgramObject _appProgram; + Platform& _platform; + ApplicationLayer _appLayer; + TransportLayer _transLayer; + NetworkLayer _netLayer; + TpUartDataLinkLayer _dlLayer; + +}; \ No newline at end of file diff --git a/bau57B0.h b/bau57B0.h index 9fd39ad..58e02c1 100644 --- a/bau57B0.h +++ b/bau57B0.h @@ -10,7 +10,7 @@ #include "application_layer.h" #include "transport_layer.h" #include "network_layer.h" -#include "data_link_layer.h" +#include "ip_data_link_layer.h" #include "platform.h" #include "memory.h" @@ -72,6 +72,6 @@ private: ApplicationLayer _appLayer; TransportLayer _transLayer; NetworkLayer _netLayer; - DataLinkLayer _dlLayer; + IpDataLinkLayer _dlLayer; }; \ No newline at end of file diff --git a/bits.h b/bits.h index 11b3375..acf1cb1 100644 --- a/bits.h +++ b/bits.h @@ -16,7 +16,8 @@ ((x)>> 8 & 0x0000FF00UL) | \ ((x)>>24 & 0x000000FFUL) ) #define ntohl(x) htonl(x) -#define printf +#define println SerialUSB.println +#define print SerialUSB.print #else #include #include diff --git a/data_link_layer.cpp b/data_link_layer.cpp index f021ce8..d7b0f81 100644 --- a/data_link_layer.cpp +++ b/data_link_layer.cpp @@ -1,128 +1,31 @@ -/* - * bus.cpp - Low level EIB bus access. - * - * Copyright (c) 2014 Stefan Taferner - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 3 as - * published by the Free Software Foundation. - */ - #include "data_link_layer.h" #include "bits.h" #include "platform.h" #include "device_object.h" #include "address_table_object.h" -#include "cemi_frame.h" -#include -#include -#define KNXIP_HEADER_LEN 0x6 -#define KNXIP_PROTOCOL_VERSION 0x10 - -#define ROUTING_INDICATION 0x0530 - -#define KNXIP_MULTICAST_PORT 3671 -#define MIN_LEN_CEMI 10 - -#ifdef DUMP_TELEGRAMS -unsigned char telBuffer[32]; -uint32_t telLength = 0; -#endif - -DataLinkLayer::DataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, IpParameterObject& ipParam, +DataLinkLayer::DataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, NetworkLayer& layer, Platform& platform) : - _deviceObject(devObj), _groupAddressTable(addrTab), _ipParameters(ipParam), _networkLayer(layer), _platform(platform) + _deviceObject(devObj), _groupAddressTable(addrTab), _networkLayer(layer), _platform(platform) { } void DataLinkLayer::dataRequest(AckType ack, AddressType addrType, uint16_t destinationAddr, FrameFormat format, Priority priority, NPDU& npdu) { - bool success = sendPacket(npdu, ack, destinationAddr, addrType, format, priority); + bool success = sendTelegram(npdu, ack, destinationAddr, addrType, format, priority); _networkLayer.dataConfirm(ack, addrType, destinationAddr, format, priority, npdu.frame().sourceAddress(), npdu, success); } void DataLinkLayer::systemBroadcastRequest(AckType ack, FrameFormat format, Priority priority, NPDU& npdu) { - bool success = sendPacket(npdu, ack, 0, GroupAddress, format, priority); + bool success = sendTelegram(npdu, ack, 0, GroupAddress, format, priority); _networkLayer.systemBroadcastConfirm(ack, format, priority, npdu.frame().sourceAddress(), npdu, success); } -bool DataLinkLayer::sendPacket(NPDU &npdu, AckType ack, uint16_t destinationAddr, AddressType addrType, FrameFormat format, Priority priority) +void DataLinkLayer::frameRecieved(CemiFrame & frame) { - CemiFrame& frame = npdu.frame(); - frame.messageCode(L_data_ind); - frame.destinationAddress(destinationAddr); - frame.sourceAddress(_deviceObject.induvidualAddress()); - frame.addressType(addrType); - frame.priority(priority); - frame.repetition(RepititionAllowed); - - if (npdu.octetCount() <= 15) - frame.frameType(StandardFrame); - else - frame.frameType(format); - - - if (!frame.valid()) - { - printf("invalid frame\n"); - return false; - } - - - //if (frame.npdu().octetCount() > 0) - //{ - // print.print("-> DLL "); - // frame.apdu().printPDU(); - //} - - - uint16_t length = frame.totalLenght() + KNXIP_HEADER_LEN; - uint8_t* buffer = new uint8_t[length]; - buffer[0] = KNXIP_HEADER_LEN; - buffer[1] = KNXIP_PROTOCOL_VERSION; - pushWord(ROUTING_INDICATION, buffer + 2); - pushWord(length, buffer + 4); - - memcpy(buffer + KNXIP_HEADER_LEN, frame._data, frame.totalLenght()); - - bool success = sendBytes(buffer, length); - // only send 50 packet per second: see KNX 3.2.6 p.6 - _platform.mdelay(20); - delete[] buffer; - return success; -} - -void DataLinkLayer::loop() -{ - if (!_enabled) - return; - - uint8_t buffer[512]; - int len = _platform.readBytes(buffer, 512); - if (len <= 0) - return; - - if (len < KNXIP_HEADER_LEN) - return; - - if (buffer[0] != KNXIP_HEADER_LEN - || buffer[1] != KNXIP_PROTOCOL_VERSION) - return; - - uint16_t code; - popWord(code, buffer + 2); - if (code != ROUTING_INDICATION) // only routing indication for now - return; - - if (len < MIN_LEN_CEMI) - return; - - //TODO: Check correct length (additions Info + apdu length) - CemiFrame frame(buffer + KNXIP_HEADER_LEN, len - KNXIP_HEADER_LEN); AckType ack = frame.ack(); AddressType addrType = frame.addressType(); uint16_t destination = frame.destinationAddress(); @@ -134,7 +37,7 @@ void DataLinkLayer::loop() if (source == ownAddr) _deviceObject.induvidualAddressDuplication(true); - + if (addrType == GroupAddress && destination == 0) _networkLayer.systemBroadcastIndication(ack, type, npdu, priority, source); else @@ -155,45 +58,38 @@ void DataLinkLayer::loop() } } -void DataLinkLayer::enabled(bool value) +bool DataLinkLayer::sendTelegram(NPDU & npdu, AckType ack, uint16_t destinationAddr, AddressType addrType, FrameFormat format, Priority priority) { - if (value && !_enabled) + CemiFrame& frame = npdu.frame(); + frame.messageCode(L_data_ind); + frame.destinationAddress(destinationAddr); + frame.sourceAddress(_deviceObject.induvidualAddress()); + frame.addressType(addrType); + frame.priority(priority); + frame.repetition(RepititionAllowed); + + if (npdu.octetCount() <= 15) + frame.frameType(StandardFrame); + else + frame.frameType(format); + + + if (!frame.valid()) { - _platform.setupMultiCast(_ipParameters.multicastAddress(), KNXIP_MULTICAST_PORT); - _enabled = true; - return; - } - - if(!value && _enabled) - { - _platform.closeMultiCast(); - _enabled = false; - return; - } -} - -bool DataLinkLayer::enabled() const -{ - return _enabled; -} - - -bool DataLinkLayer::sendBytes(uint8_t* bytes, uint16_t length) -{ - if (!_enabled) + println("invalid frame\n"); return false; - -#ifdef DUMP_TELEGRAMS_ - { - print.print("QSD: "); - for (uint32_t i = 0; i <= length; ++i) - { - if (i) print.print(" "); - print.print(bytes[i], HEX, 2); - } - print.println(); } -#endif - return _platform.sendBytes(bytes, length); -} \ No newline at end of file + //if (frame.npdu().octetCount() > 0) + //{ + // print.print("-> DLL "); + // frame.apdu().printPDU(); + //} + + return sendFrame(frame); +} + +uint8_t* DataLinkLayer::frameData(CemiFrame& frame) +{ + return frame._data; +} diff --git a/data_link_layer.h b/data_link_layer.h index ce1ae3a..6dfc389 100644 --- a/data_link_layer.h +++ b/data_link_layer.h @@ -3,31 +3,29 @@ #include #include "device_object.h" #include "address_table_object.h" -#include "ip_parameter_object.h" #include "knx_types.h" #include "network_layer.h" class DataLinkLayer { public: - DataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, IpParameterObject& ipParam, NetworkLayer& layer, + DataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, NetworkLayer& layer, Platform& platform); // from network layer void dataRequest(AckType ack, AddressType addrType, uint16_t destinationAddr, FrameFormat format, Priority priority, NPDU& npdu); void systemBroadcastRequest(AckType ack, FrameFormat format, Priority priority, NPDU& npdu); - void loop(); - void enabled(bool value); - bool enabled() const; -private: - bool _enabled = false; - bool sendPacket(NPDU &npdu, AckType ack, uint16_t destinationAddr, AddressType addrType, FrameFormat format, Priority priority); - bool sendBytes(uint8_t* buffer, uint16_t length); - + virtual void loop() = 0; + virtual void enabled(bool value) = 0; + virtual bool enabled() const = 0; +protected: + void frameRecieved(CemiFrame& frame); + bool sendTelegram(NPDU &npdu, AckType ack, uint16_t destinationAddr, AddressType addrType, FrameFormat format, Priority priority); + virtual bool sendFrame(CemiFrame& frame) = 0; + uint8_t* frameData(CemiFrame& frame); DeviceObject& _deviceObject; AddressTableObject& _groupAddressTable; - IpParameterObject& _ipParameters; NetworkLayer& _networkLayer; Platform& _platform; }; \ No newline at end of file diff --git a/ip_data_link_layer.cpp b/ip_data_link_layer.cpp new file mode 100644 index 0000000..f5a261c --- /dev/null +++ b/ip_data_link_layer.cpp @@ -0,0 +1,102 @@ +#include "ip_data_link_layer.h" + +#include "bits.h" +#include "platform.h" +#include "device_object.h" +#include "address_table_object.h" +#include "cemi_frame.h" + +#include +#include + +#define KNXIP_HEADER_LEN 0x6 +#define KNXIP_PROTOCOL_VERSION 0x10 + +#define ROUTING_INDICATION 0x0530 + +#define KNXIP_MULTICAST_PORT 3671 +#define MIN_LEN_CEMI 10 + +IpDataLinkLayer::IpDataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, IpParameterObject& ipParam, + NetworkLayer& layer, Platform& platform) : DataLinkLayer(devObj, addrTab, layer, platform), _ipParameters(ipParam) +{ +} + +bool IpDataLinkLayer::sendFrame(CemiFrame& frame) +{ + uint16_t length = frame.totalLenght() + KNXIP_HEADER_LEN; + uint8_t* buffer = new uint8_t[length]; + buffer[0] = KNXIP_HEADER_LEN; + buffer[1] = KNXIP_PROTOCOL_VERSION; + pushWord(ROUTING_INDICATION, buffer + 2); + pushWord(length, buffer + 4); + + memcpy(buffer + KNXIP_HEADER_LEN, frameData(frame), frame.totalLenght()); + + bool success = sendBytes(buffer, length); + // only send 50 packet per second: see KNX 3.2.6 p.6 + _platform.mdelay(20); + delete[] buffer; + return success; +} + +void IpDataLinkLayer::loop() +{ + if (!_enabled) + return; + + uint8_t buffer[512]; + int len = _platform.readBytes(buffer, 512); + if (len <= 0) + return; + + if (len < KNXIP_HEADER_LEN) + return; + + if (buffer[0] != KNXIP_HEADER_LEN + || buffer[1] != KNXIP_PROTOCOL_VERSION) + return; + + uint16_t code; + popWord(code, buffer + 2); + if (code != ROUTING_INDICATION) // only routing indication for now + return; + + if (len < MIN_LEN_CEMI) + return; + + //TODO: Check correct length (additions Info + apdu length) + CemiFrame frame(buffer + KNXIP_HEADER_LEN, len - KNXIP_HEADER_LEN); + frameRecieved(frame); +} + +void IpDataLinkLayer::enabled(bool value) +{ + if (value && !_enabled) + { + _platform.setupMultiCast(_ipParameters.multicastAddress(), KNXIP_MULTICAST_PORT); + _enabled = true; + return; + } + + if(!value && _enabled) + { + _platform.closeMultiCast(); + _enabled = false; + return; + } +} + +bool IpDataLinkLayer::enabled() const +{ + return _enabled; +} + + +bool IpDataLinkLayer::sendBytes(uint8_t* bytes, uint16_t length) +{ + if (!_enabled) + return false; + + return _platform.sendBytes(bytes, length); +} \ No newline at end of file diff --git a/ip_data_link_layer.h b/ip_data_link_layer.h new file mode 100644 index 0000000..4ad86af --- /dev/null +++ b/ip_data_link_layer.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include "data_link_layer.h" +#include "ip_parameter_object.h" + +class IpDataLinkLayer: public DataLinkLayer +{ + using DataLinkLayer::_deviceObject; +public: + IpDataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, IpParameterObject& ipParam, NetworkLayer& layer, + Platform& platform); + + void loop(); + void enabled(bool value); + bool enabled() const; +private: + bool _enabled = false; + bool sendFrame(CemiFrame& frame); + bool sendBytes(uint8_t* buffer, uint16_t length); + + IpParameterObject& _ipParameters; +}; \ No newline at end of file diff --git a/tpuart_data_link_layer.cpp b/tpuart_data_link_layer.cpp new file mode 100644 index 0000000..94f48f1 --- /dev/null +++ b/tpuart_data_link_layer.cpp @@ -0,0 +1,74 @@ +#include "tpuart_data_link_layer.h" + +#include "bits.h" +#include "platform.h" +#include "device_object.h" +#include "address_table_object.h" +#include "cemi_frame.h" + +#include +#include + +TpUartDataLinkLayer::TpUartDataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, + NetworkLayer& layer, Platform& platform) : DataLinkLayer(devObj, addrTab, layer, platform) +{ +} + + +bool TpUartDataLinkLayer::sendFrame(CemiFrame& frame) +{ + uint16_t length = frame.totalLenght(); + uint8_t* buffer = new uint8_t[length]; + + //TODO: Create TP standard frame or extended frame from cemi frame into buffer + + bool success = sendBytes(buffer, length); + + delete[] buffer; + return success; +} + +void TpUartDataLinkLayer::loop() +{ + if (!_enabled) + return; + + uint8_t buffer[512]; + int len = 0; + // TODO: implement receiving of frames + + CemiFrame frame(buffer, len); + frameRecieved(frame); +} + +void TpUartDataLinkLayer::enabled(bool value) +{ + if (value && !_enabled) + { + //TODO: implement setup of Serial + TPUART + _enabled = true; + return; + } + + if(!value && _enabled) + { + //TODO: implement disable of TPUART + _enabled = false; + return; + } +} + +bool TpUartDataLinkLayer::enabled() const +{ + return _enabled; +} + + +bool TpUartDataLinkLayer::sendBytes(uint8_t* bytes, uint16_t length) +{ + if (!_enabled) + return false; + + //TODO: implement + return false; +} \ No newline at end of file diff --git a/tpuart_data_link_layer.h b/tpuart_data_link_layer.h new file mode 100644 index 0000000..8bd1a60 --- /dev/null +++ b/tpuart_data_link_layer.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include "data_link_layer.h" + +class TpUartDataLinkLayer: public DataLinkLayer +{ + using DataLinkLayer::_deviceObject; +public: + TpUartDataLinkLayer(DeviceObject& devObj, AddressTableObject& addrTab, NetworkLayer& layer, + Platform& platform); + + void loop(); + void enabled(bool value); + bool enabled() const; +private: + bool _enabled = false; + bool sendFrame(CemiFrame& frame); + bool sendBytes(uint8_t* buffer, uint16_t length); +}; \ No newline at end of file