initial checkin

This commit is contained in:
Thomas Kunze 2018-03-16 00:48:39 +01:00
commit a7a48b4a7b
55 changed files with 6450 additions and 0 deletions

247
.gitignore vendored Normal file
View File

@ -0,0 +1,247 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
[Xx]64/
[Xx]86/
[Bb]uild/
bld/
[Bb]in/
[Oo]bj/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Un-comment the next line if you do not want to checkin
# your web deploy settings because they may include unencrypted
# passwords
#*.pubxml
*.publishproj
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Microsoft Azure ApplicationInsights config file
ApplicationInsights.config
# Windows Store app package directory
AppPackages/
BundleArtifacts/
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# LightSwitch generated files
GeneratedArtifacts/
ModelManifest.xml
# Paket dependency manager
.paket/paket.exe
# FAKE - F# Make
.fake/
/CodeDB
/VisualGDBCache

90
address_table_object.cpp Normal file
View File

@ -0,0 +1,90 @@
#include <cstring>
#include "address_table_object.h"
#include "bits.h"
using namespace std;
AddressTableObject::AddressTableObject(uint8_t* memoryReference): TableObject(memoryReference)
{
}
void AddressTableObject::readProperty(PropertyID id, uint32_t start, uint32_t count, uint8_t* data)
{
switch (id)
{
case PID_OBJECT_TYPE:
pushWord(OT_ADDR_TABLE, data);
break;
default:
TableObject::readProperty(id, start, count, data);
}
}
uint16_t AddressTableObject::entryCount()
{
if (loadState() != LS_LOADED)
return 0;
return _groupAddresses[0];
}
uint16_t AddressTableObject::getGa(uint16_t tsap)
{
if (loadState() != LS_LOADED || tsap > entryCount() )
return 0;
return _groupAddresses[tsap];
}
uint16_t AddressTableObject::getTsap(uint16_t addr)
{
uint16_t size = entryCount();
for (uint16_t i = 1; i <= size; i++)
if (_groupAddresses[i] == addr)
return i;
return 1;
}
#pragma region SaveRestore
uint8_t* AddressTableObject::save(uint8_t* buffer)
{
return TableObject::save(buffer);
}
uint8_t* AddressTableObject::restore(uint8_t* buffer)
{
buffer = TableObject::restore(buffer);
_groupAddresses = (uint16_t*)_data;
return buffer;
}
#pragma endregion
bool AddressTableObject::contains(uint16_t addr)
{
uint16_t size = entryCount();
for (uint16_t i = 1; i <= size; i++)
if (_groupAddresses[i] == addr)
return true;
return false;
}
void AddressTableObject::beforeStateChange(LoadState& newState)
{
if (newState != LS_LOADED)
return;
_groupAddresses = (uint16_t*)_data;
uint16_t count = reverseByteOrder(_groupAddresses[0]);
// big endian -> little endian
for (size_t i = 0; i <= count; i++)
_groupAddresses[i] = reverseByteOrder(_groupAddresses[i]);
}

20
address_table_object.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#include "table_object.h"
class AddressTableObject: public TableObject
{
public:
AddressTableObject(uint8_t* memoryReference);
void readProperty(PropertyID id, uint32_t start, uint32_t count, uint8_t* data);
uint16_t entryCount();
uint16_t getGa(uint16_t tsap);
uint16_t getTsap(uint16_t ga);
uint8_t* save(uint8_t* buffer);
uint8_t* restore(uint8_t* buffer);
bool contains(uint16_t addr);
protected:
virtual void beforeStateChange(LoadState& newState);
private:
uint16_t* _groupAddresses;
};

51
apdu.cpp Normal file
View File

@ -0,0 +1,51 @@
#include "apdu.h"
#include "cemi_frame.h"
#include "bits.h"
APDU::APDU(uint8_t* data, CemiFrame& frame): _data(data), _frame(frame)
{
}
ApduType APDU::type()
{
uint16_t apci;
popWord(apci, _data);
apci &= 0x3ff;
if ((apci >> 6) < 11) //short apci
apci &= 0x3c0;
return (ApduType)apci;
}
void APDU::type(ApduType atype)
{
pushWord((uint16_t)atype, _data);
}
uint8_t* APDU::data()
{
return _data + 1;
}
CemiFrame& APDU::frame()
{
return _frame;
}
uint8_t APDU::length() const
{
return _frame.npdu().octetCount();
}
void APDU::printPDU()
{
//Print.print("APDU: ");
//print.print(type(), HEX, 4);
//print.print(" ");
//print.print(_data[0] & 0x3, HEX, 2);
//for (uint8_t i = 1; i < length() + 1; ++i)
//{
// if (i) print.print(" ");
// print.print(_data[i], HEX, 2);
//}
//print.println();
}

22
apdu.h Normal file
View File

@ -0,0 +1,22 @@
#pragma once
#include <stdint.h>
#include "knx_types.h"
class CemiFrame;
class APDU
{
friend class CemiFrame;
public:
APDU(uint8_t* data, CemiFrame& frame);
ApduType type();
void type(ApduType atype);
uint8_t* data();
CemiFrame& frame();
uint8_t length() const;
void printPDU();
private:
uint8_t* _data;
CemiFrame& _frame;
};

792
application_layer.cpp Normal file
View File

@ -0,0 +1,792 @@
#include "application_layer.h"
#include "transport_layer.h"
#include "cemi_frame.h"
#include "association_table_object.h"
#include "apdu.h"
#include "bau.h"
#include "string.h"
#include "bits.h"
#include <stdio.h>
ApplicationLayer::ApplicationLayer(AssociationTableObject& assocTable, BusAccessUnit& bau):
_assocTable(assocTable), _bau(bau)
{
}
void ApplicationLayer::transportLayer(TransportLayer& layer)
{
_transportLayer = &layer;
}
#pragma region TL Callbacks
void ApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu)
{
uint16_t entries = _assocTable.entryCount();
uint8_t len = apdu.length();
uint8_t dataArray[len];
uint8_t* data = dataArray;
memcpy(data, apdu.data(), len);
if (len == 1)
{
//less than six bit are encoded in first byte
*data &= 0x3f;
}
else
{
data += 1;
len -= 1;
}
for (uint16_t i; i < entries; i++)
{
uint16_t entry = _assocTable[i];
if (highByte(entry) == tsap)
{
uint16_t asap = lowByte(entry);
switch (apdu.type())
{
case GroupValueRead:
_bau.groupValueReadIndication(asap, priority, hopType);
break;
case GroupValueResponse:
_bau.groupValueReadAppLayerConfirm(asap, priority, hopType, data, len);
break;
case GroupValueWrite:
_bau.groupValueWriteIndication(asap, priority, hopType, data, len);
}
}
}
}
void ApplicationLayer::dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status)
{
switch (apdu.type())
{
case GroupValueRead:
_bau.groupValueReadLocalConfirm(ack, _savedAsapReadRequest, priority, hopType, status);
break;
case GroupValueResponse:
_bau.groupValueReadResponseConfirm(ack, _savedAsapResponse, priority, hopType, apdu.data(), apdu.length() - 1, status);
break;
case GroupValueWrite:
_bau.groupValueWriteLocalConfirm(ack, _savedAsapWriteRequest, priority, hopType, apdu.data(), apdu.length() - 1, status);
break;
}
}
void ApplicationLayer::dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu)
{
uint8_t* data = apdu.data();
switch (apdu.type())
{
case IndividualAddressWrite:
{
uint16_t newAddress;
popWord(newAddress, data + 1);
_bau.individualAddressWriteIndication(hopType, newAddress);
break;
}
case IndividualAddressRead:
_bau.individualAddressReadIndication(hopType);
break;
case IndividualAddressResponse:
_bau.individualAddressReadAppLayerConfirm(hopType, apdu.frame().sourceAddress());
break;
case IndividualAddressSerialNumberRead:
_bau.individualAddressSerialNumberReadIndication(hopType, data + 1);
break;
case IndividualAddressSerialNumberResponse:
{
uint16_t domainAddress;
popWord(domainAddress, data + 7);
_bau.individualAddressSerialNumberReadAppLayerConfirm(hopType, data + 1, apdu.frame().sourceAddress(),
domainAddress);
break;
}
case IndividualAddressSerialNumberWrite:
{
uint16_t newAddress;
popWord(newAddress, data + 7);
_bau.individualAddressSerialNumberWriteIndication(hopType, data + 1, newAddress);
break;
}
}
}
void ApplicationLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, bool status)
{
uint8_t* data = apdu.data();
switch (apdu.type())
{
case IndividualAddressWrite:
{
uint16_t newAddress;
popWord(newAddress, data + 1);
_bau.individualAddressWriteLocalConfirm(ack, hopType, newAddress, status);
break;
}
case IndividualAddressRead:
_bau.individualAddressReadLocalConfirm(ack, hopType, status);
break;
case IndividualAddressResponse:
_bau.individualAddressReadResponseConfirm(ack, hopType, status);
break;
case IndividualAddressSerialNumberRead:
_bau.individualAddressSerialNumberReadLocalConfirm(ack, hopType, data + 1, status);
break;
case IndividualAddressSerialNumberResponse:
{
uint16_t domainAddress;
popWord(domainAddress, data + 7);
_bau.individualAddressSerialNumberReadResponseConfirm(ack, hopType, data + 1, domainAddress, status);
break;
}
case IndividualAddressSerialNumberWrite:
{
uint16_t newAddress;
popWord(newAddress, data + 7);
_bau.individualAddressSerialNumberWriteLocalConfirm(ack, hopType, data + 1, newAddress, status);
break;
}
}
}
void ApplicationLayer::dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu)
{
}
void ApplicationLayer::dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, bool status)
{
}
void ApplicationLayer::dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu)
{
individualIndication(hopType, priority, tsap, apdu);
}
void ApplicationLayer::dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status)
{
individualConfirm(ack, hopType, priority, tsap, apdu, status);
}
void ApplicationLayer::connectIndication(uint16_t tsap)
{
_connectedTsap = tsap;
}
void ApplicationLayer::connectConfirm(uint16_t destination, uint16_t tsap, bool status)
{
}
void ApplicationLayer::disconnectIndication(uint16_t tsap)
{
_connectedTsap = -1;
}
void ApplicationLayer::disconnectConfirm(Priority priority, uint16_t tsap, bool status)
{
}
void ApplicationLayer::dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu)
{
individualIndication(NetworkLayerParameter, priority, tsap, apdu);
}
void ApplicationLayer::dataConnectedConfirm(uint16_t tsap)
{
}
#pragma endregion
void ApplicationLayer::groupValueReadRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType)
{
_savedAsapReadRequest = asap;
CemiFrame frame(1);
APDU& apdu = frame.apdu();
apdu.type(GroupValueRead);
int32_t value = _assocTable.translateAsap(asap);
if (value < 0)
return; // there is no tsap in association table for this asap
uint16_t tsap = (uint16_t)value;
// first to bus then to itself
_transportLayer->dataGroupRequest(ack, hopType, priority, tsap, apdu);
dataGroupIndication(hopType, priority, tsap, apdu);
}
void ApplicationLayer::groupValueReadResponse(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, uint8_t * data, uint8_t dataLength)
{
_savedAsapResponse = asap;
groupValueSend(GroupValueResponse, ack, asap, priority, hopType, data, dataLength);
}
void ApplicationLayer::groupValueWriteRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, uint8_t * data, uint8_t dataLength)
{
_savedAsapWriteRequest = asap;
groupValueSend(GroupValueWrite, ack, asap, priority, hopType, data, dataLength);
}
void ApplicationLayer::individualAddressWriteRequest(AckType ack, HopCountType hopType, uint16_t newaddress)
{
CemiFrame frame(3);
APDU& apdu = frame.apdu();
apdu.type(IndividualAddressWrite);
uint8_t* apduData = apdu.data();
pushWord(newaddress, apduData + 1);
_transportLayer->dataBroadcastRequest(ack, hopType, SystemPriority, apdu);
}
void ApplicationLayer::individualAddressReadRequest(AckType ack, HopCountType hopType)
{
CemiFrame frame(1);
APDU& apdu = frame.apdu();
apdu.type(IndividualAddressRead);
_transportLayer->dataBroadcastRequest(ack, hopType, SystemPriority, apdu);
}
void ApplicationLayer::individualAddressReadResponse(AckType ack, HopCountType hopType)
{
CemiFrame frame(1);
APDU& apdu = frame.apdu();
apdu.type(IndividualAddressResponse);
_transportLayer->dataBroadcastRequest(ack, hopType, SystemPriority, apdu);
}
void ApplicationLayer::individualAddressSerialNumberReadRequest(AckType ack, HopCountType hopType, uint8_t * serialNumber)
{
CemiFrame frame(7);
APDU& apdu = frame.apdu();
apdu.type(IndividualAddressSerialNumberRead);
uint8_t* data = apdu.data() + 1;
memcpy(data, serialNumber, 6);
_transportLayer->dataBroadcastRequest(ack, hopType, SystemPriority, apdu);
}
void ApplicationLayer::individualAddressSerialNumberReadResponse(AckType ack, HopCountType hopType,
uint8_t * serialNumber, uint16_t domainAddress)
{
CemiFrame frame(7);
APDU& apdu = frame.apdu();
apdu.type(IndividualAddressSerialNumberResponse);
uint8_t* data = apdu.data() + 1;
memcpy(data, serialNumber, 6);
data += 6;
pushWord(domainAddress, data);
_transportLayer->dataBroadcastRequest(ack, hopType, SystemPriority, apdu);
}
void ApplicationLayer::individualAddressSerialNumberWriteRequest(AckType ack, HopCountType hopType, uint8_t * serialNumber,
uint16_t newaddress)
{
CemiFrame frame(13);
APDU& apdu = frame.apdu();
apdu.type(IndividualAddressSerialNumberWrite);
uint8_t* data = apdu.data() + 1;
memcpy(data, serialNumber, 6);
data += 6;
pushWord(newaddress, data);
_transportLayer->dataBroadcastRequest(ack, hopType, SystemPriority, apdu);
}
void ApplicationLayer::deviceDescriptorReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t descriptorType)
{
CemiFrame frame(1);
APDU& apdu = frame.apdu();
apdu.type(DeviceDescriptorRead);
uint8_t* data = apdu.data();
*data |= (descriptorType & 0x3f);
individualSend(ack, hopType, priority, asap, apdu);
}
void ApplicationLayer::deviceDescriptorReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t descriptorType, uint8_t* deviceDescriptor)
{
uint8_t length = 0;
switch (descriptorType)
{
case 0:
length = 3;
break;
case 2:
length = 14;
break;
default:
length = 1;
descriptorType = 0x3f;
break;
}
CemiFrame frame(length);
APDU& apdu = frame.apdu();
apdu.type(DeviceDescriptorResponse);
uint8_t* data = apdu.data();
*data |= (descriptorType & 0x3f);
if (length > 1)
memcpy(data + 1, deviceDescriptor, length - 1);
individualSend(ack, hopType, priority, asap, apdu);
}
void ApplicationLayer::restartRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap)
{
CemiFrame frame(1);
APDU& apdu = frame.apdu();
apdu.type(Restart);
individualSend(ack, hopType, priority, asap, apdu);
}
void ApplicationLayer::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 ApplicationLayer::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 ApplicationLayer::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 ApplicationLayer::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 ApplicationLayer::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(PropertyDescriptionRead);
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 ApplicationLayer::memoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint16_t memoryAddress)
{
CemiFrame frame(3);
APDU& apdu = frame.apdu();
apdu.type(MemoryRead);
uint8_t* data = apdu.data();
*data |= (number & 0x3f);
pushWord(memoryAddress, data + 1);
individualSend(ack, hopType, priority, asap, apdu);
}
void ApplicationLayer::memoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint16_t memoryAddress, uint8_t * memoryData)
{
memorySend(MemoryResponse, ack, priority, hopType, asap, number, memoryAddress, memoryData);
}
void ApplicationLayer::memoryWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t number, uint16_t memoryAddress, uint8_t * data)
{
memorySend(MemoryWrite, ack, priority, hopType, asap, number, memoryAddress, data);
}
void ApplicationLayer::userMemoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t number, uint32_t memoryAddress)
{
CemiFrame frame(4);
APDU& apdu = frame.apdu();
apdu.type(UserMemoryRead);
uint8_t* data = apdu.data();
data[1] |= (number & 0xf);
data[1] |= ((memoryAddress >> 12) & 0xf0);
pushWord(memoryAddress & 0xff, data + 2);
individualSend(ack, hopType, priority, asap, apdu);
}
void ApplicationLayer::userMemoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t number, uint32_t memoryAddress, uint8_t * memoryData)
{
userMemorySend(UserMemoryResponse, ack, priority, hopType, asap, number, memoryAddress, memoryData);
}
void ApplicationLayer::userMemoryWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t number, uint32_t memoryAddress, uint8_t * memoryData)
{
userMemorySend(UserMemoryWrite, ack, priority, hopType, asap, number, memoryAddress, memoryData);
}
void ApplicationLayer::userManufacturerInfoReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap)
{
CemiFrame frame(1);
APDU& apdu = frame.apdu();
apdu.type(UserManufacturerInfoRead);
individualSend(ack, hopType, priority, asap, apdu);
}
void ApplicationLayer::userManufacturerInfoReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t* info)
{
CemiFrame frame(4);
APDU& apdu = frame.apdu();
apdu.type(UserMemoryRead);
uint8_t* data = apdu.data();
memcpy(data + 1, info, 3);
individualSend(ack, hopType, priority, asap, apdu);
}
void ApplicationLayer::authorizeRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint32_t key)
{
CemiFrame frame(6);
APDU& apdu = frame.apdu();
apdu.type(AuthorizeRequest);
uint8_t* data = apdu.data();
pushInt(key, data + 2);
individualSend(ack, hopType, priority, asap, apdu);
}
void ApplicationLayer::authorizeResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t level)
{
CemiFrame frame(2);
APDU& apdu = frame.apdu();
apdu.type(AuthorizeResponse);
uint8_t* data = apdu.data();
data[1] = level;
individualSend(ack, hopType, priority, asap, apdu);
}
void ApplicationLayer::keyWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t level, uint32_t key)
{
CemiFrame frame(6);
APDU& apdu = frame.apdu();
apdu.type(KeyWrite);
uint8_t* data = apdu.data();
data[1] = level;
pushInt(key, data + 2);
individualSend(ack, hopType, priority, asap, apdu);
}
void ApplicationLayer::keyWriteResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t level)
{
CemiFrame frame(6);
APDU& apdu = frame.apdu();
apdu.type(KeyResponse);
uint8_t* data = apdu.data();
data[1] = level;
individualSend(ack, hopType, priority, asap, apdu);
}
void ApplicationLayer::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);
if (asap == _connectedTsap)
_transportLayer->dataConnectedRequest(asap, priority, apdu);
else
_transportLayer->dataIndividualRequest(ack, hopType, priority, asap, apdu);
}
void ApplicationLayer::groupValueSend(ApduType type, AckType ack, uint16_t asap, Priority priority, HopCountType hopType,
uint8_t* data, uint8_t& dataLength)
{
CemiFrame frame(dataLength + 1);
APDU& apdu = frame.apdu();
apdu.type(type);
uint8_t* apdudata = apdu.data();
if (dataLength == 0)
{
// data size is six bit or less. So store int first byte
*apdudata &= ~0x3f;
*apdudata |= (*data & 0x3f);
}
else
{
memcpy(apdudata + 1, data, dataLength);
}
// no need to check if there is a tsap. This is a response, so the read got trough
uint16_t tsap = (uint16_t)_assocTable.translateAsap(asap);
_transportLayer->dataGroupRequest(ack, hopType, priority, tsap, apdu);
dataGroupIndication(hopType, priority, tsap, apdu);
}
void ApplicationLayer::memorySend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint16_t memoryAddress, uint8_t * memoryData)
{
CemiFrame frame(3 + number);
APDU& apdu = frame.apdu();
apdu.type(type);
uint8_t* data = apdu.data();
*data |= (number & 0x3f);
pushWord(memoryAddress, data + 1);
if (number > 0)
memcpy(data + 3, memoryData, number);
individualSend(ack, hopType, priority, asap, apdu);
}
void ApplicationLayer::userMemorySend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint32_t memoryAddress, uint8_t * memoryData)
{
CemiFrame frame(4 + number);
APDU& apdu = frame.apdu();
apdu.type(type);
uint8_t* data = apdu.data();
data[1] |= (number & 0xf);
data[1] |= ((memoryAddress >> 12) & 0xf0);
pushWord(memoryAddress & 0xffff, data + 2);
if (number > 0)
memcpy(data + 4, memoryData, number);
individualSend(ack, hopType, priority, asap, apdu);
}
void ApplicationLayer::individualIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU & apdu)
{
uint8_t* data = apdu.data();
switch (apdu.type())
{
case DeviceDescriptorRead:
_bau.deviceDescriptorReadIndication(priority, hopType, tsap, *data & 0x3f);
break;
case DeviceDescriptorResponse:
_bau.deviceDescriptorReadAppLayerConfirm(priority, hopType, tsap, *data & 0x3f, data + 1);
break;
case Restart:
if ((*data & 0x3f) == 0)
_bau.restartRequestIndication(priority, hopType, tsap);
break;
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;
case MemoryRead:
_bau.memoryReadIndication(priority, hopType, tsap, data[0] & 0x3f, getWord(data + 1));
break;
case MemoryResponse:
_bau.memoryReadAppLayerConfirm(priority, hopType, tsap, data[0] & 0x3f, getWord(data + 1), data + 3);
break;
case MemoryWrite:
_bau.memoryWriteIndication(priority, hopType, tsap, data[0] & 0x3f, getWord(data + 1), data + 3);
break;
case UserMemoryRead:
{
uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3];
_bau.userMemoryReadIndication(priority, hopType, tsap, data[1] & 0xf, address);
break;
}
case UserMemoryResponse:
{
uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3];
_bau.userMemoryReadAppLayerConfirm(priority, hopType, tsap, data[1] & 0xf, address, data + 4);
break;
}
case UserMemoryWrite:
{
uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3];
_bau.userMemoryWriteIndication(priority, hopType, tsap, data[1] & 0xf, address, data + 4);
break;
}
case UserManufacturerInfoRead:
_bau.userManufacturerInfoIndication(priority, hopType, tsap);
break;
case UserManufacturerInfoResponse:
_bau.userManufacturerInfoAppLayerConfirm(priority, hopType, tsap, data + 1);
break;
case AuthorizeRequest:
_bau.authorizeIndication(priority, hopType, tsap, getInt(data + 2));
break;
case AuthorizeResponse:
_bau.authorizeAppLayerConfirm(priority, hopType, tsap, data[1]);
break;
case KeyWrite:
_bau.keyWriteIndication(priority, hopType, tsap, data[1], getInt(data + 2));
break;
case KeyResponse:
_bau.keyWriteAppLayerConfirm(priority, hopType, tsap, data[1]);
break;
}
}
void ApplicationLayer::individualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU & apdu, bool status)
{
uint8_t* data = apdu.data();
switch (apdu.type())
{
case DeviceDescriptorRead:
_bau.deviceDescriptorReadLocalConfirm(ack, priority, hopType, tsap, *data & 0x3f, status);
break;
case DeviceDescriptorResponse:
_bau.deviceDescriptorReadResponseConfirm(ack, priority, hopType, tsap, *data & 0x3f, data + 1, status);
break;
case Restart:
_bau.restartRequestLocalConfirm(ack, priority, hopType, tsap, status);
break;
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;
case MemoryRead:
_bau.memoryReadLocalConfirm(ack, priority, hopType, tsap, data[0] & 0x3f, getWord(data + 1), status);
break;
case MemoryResponse:
_bau.memoryReadResponseConfirm(ack, priority, hopType, tsap, data[0] & 0x3f, getWord(data + 1), data + 3, status);
break;
case MemoryWrite:
_bau.memoryWriteLocalConfirm(ack, priority, hopType, tsap, data[0] & 0x3f, getWord(data + 1), data + 3, status);
break;
case UserMemoryRead:
{
uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3];
_bau.memoryReadLocalConfirm(ack, priority, hopType, tsap, data[1] & 0xf, address, status);
break;
}
case UserMemoryResponse:
{
uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3];
_bau.memoryReadResponseConfirm(ack, priority, hopType, tsap, data[1] & 0xf, address, data + 4, status);
break;
}
case UserMemoryWrite:
{
uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3];
_bau.memoryWriteLocalConfirm(ack, priority, hopType, tsap, data[1] & 0xf, address, data + 4, status);
break;
}
case UserManufacturerInfoRead:
_bau.userManufacturerInfoLocalConfirm(ack, priority, hopType, tsap, status);
break;
case UserManufacturerInfoResponse:
_bau.userManufacturerInfoResponseConfirm(ack, priority, hopType, tsap, data + 1, status);
break;
case AuthorizeRequest:
_bau.authorizeLocalConfirm(ack, priority, hopType, tsap, getInt(data + 2), status);
break;
case AuthorizeResponse:
_bau.authorizeResponseConfirm(ack, priority, hopType, tsap, data[1], status);
break;
case KeyWrite:
_bau.keyWriteLocalConfirm(ack, priority, hopType, tsap, data[1], getInt(data + 2), status);
break;
case KeyResponse:
_bau.keyWriteResponseConfirm(ack, priority, hopType, tsap, data[1], status);
break;
}
}
void ApplicationLayer::individualSend(AckType ack, HopCountType hopType, Priority priority, uint16_t asap, APDU& apdu)
{
if (asap == _connectedTsap)
_transportLayer->dataConnectedRequest(asap, priority, apdu);
else
_transportLayer->dataIndividualRequest(ack, hopType, priority, asap, apdu);
}

102
application_layer.h Normal file
View File

@ -0,0 +1,102 @@
#pragma once
#include <stdint.h>
#include "knx_types.h"
#include "apdu.h"
class AssociationTableObject;
class BusAccessUnit;
class TransportLayer;
class ApplicationLayer
{
public:
ApplicationLayer(AssociationTableObject& assocTable, BusAccessUnit& bau);
void transportLayer(TransportLayer& layer);
// from transport layer
#pragma region Transport-Layer-Callbacks
void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu);
void dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap,
APDU& apdu, bool status);
void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu);
void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, bool status);
void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu);
void dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, bool status);
void dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu);
void dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status);
void connectIndication(uint16_t tsap);
void connectConfirm(uint16_t destination, uint16_t tsap, bool status);
void disconnectIndication(uint16_t tsap);
void disconnectConfirm(Priority priority, uint16_t tsap, bool status);
void dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu);
void dataConnectedConfirm(uint16_t tsap);
#pragma endregion
void groupValueReadRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType);
void groupValueReadResponse(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, uint8_t* data, uint8_t dataLength);
void groupValueWriteRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, uint8_t* data, uint8_t dataLength);
void individualAddressWriteRequest(AckType ack, HopCountType hopType, uint16_t newaddress);
void individualAddressReadRequest(AckType ack, HopCountType hopType);
void individualAddressReadResponse(AckType ack, HopCountType hopType);
void individualAddressSerialNumberReadRequest(AckType ack, HopCountType hopType, uint8_t* serialNumber);
void individualAddressSerialNumberReadResponse(AckType ack, HopCountType hopType, uint8_t* serialNumber,
uint16_t domainAddress);
void individualAddressSerialNumberWriteRequest(AckType ack, HopCountType hopType, uint8_t* serialNumber,
uint16_t newaddress);
void deviceDescriptorReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t descriptorType);
void deviceDescriptorReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t descriptorType, uint8_t* deviceDescriptor);
void restartRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap);
void propertyValueReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex);
void 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);
void 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);
void propertyDescriptionReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex);
void 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);
void memoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint16_t memoryAddress);
void memoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint16_t memoryAddress, uint8_t* data);
void memoryWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint16_t memoryAddress, uint8_t* data);
void userMemoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint32_t memoryAddress);
void userMemoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint32_t memoryAddress, uint8_t* memoryData);
void userMemoryWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint32_t memoryAddress, uint8_t* memoryData);
void userManufacturerInfoReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap);
void userManufacturerInfoReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t* info);
void authorizeRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint32_t key);
void authorizeResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t level);
void keyWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t level, uint32_t key);
void keyWriteResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t level);
private:
void 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);
void memorySend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint16_t memoryAddress, uint8_t * memoryData);
void userMemorySend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t number, uint32_t memoryAddress, uint8_t* memoryData);
void groupValueSend(ApduType type, AckType ack, uint16_t asap, Priority priority, HopCountType hopType, uint8_t* data, uint8_t& dataLength);
void individualIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu);
void individualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status);
void individualSend(AckType ack, HopCountType hopType, Priority priority, uint16_t asap, APDU& apdu);
uint16_t _savedAsapReadRequest;
uint16_t _savedAsapWriteRequest;
uint16_t _savedAsapResponse;
AssociationTableObject& _assocTable;
BusAccessUnit& _bau;
TransportLayer* _transportLayer;
int32_t _connectedTsap;
};

View File

@ -0,0 +1,84 @@
#include "application_program_object.h"
#include "bits.h"
ApplicationProgramObject::ApplicationProgramObject(uint8_t* memoryReference): TableObject(memoryReference)
{
}
void ApplicationProgramObject::readProperty(PropertyID id, uint32_t start, uint32_t count, uint8_t* data)
{
switch (id)
{
case PID_OBJECT_TYPE:
pushWord(OT_APPLICATION_PROG, data);
break;
case PID_PROG_VERSION:
pushByteArray(_programVersion, 5, data);
break;
case PID_PEI_TYPE:
pushByte(0x0, data);
break;
default:
TableObject::readProperty(id, start, count, data);
}
}
void ApplicationProgramObject::writeProperty(PropertyID id, uint8_t start, uint8_t* data, uint8_t count)
{
switch (id)
{
case PID_PROG_VERSION:
for (uint32_t i = 0; i < 5; i++)
{
_programVersion[i] = data[i];
}
break;
default:
TableObject::writeProperty(id, start, data, count);
}
}
uint8_t ApplicationProgramObject::propertySize(PropertyID id)
{
switch (id)
{
case PID_PROG_VERSION:
return 5;
}
return TableObject::propertySize(id);
}
uint8_t * ApplicationProgramObject::data(uint32_t addr)
{
return _data + addr;
}
uint8_t ApplicationProgramObject::getByte(uint32_t addr)
{
return *(_data + addr);
}
uint16_t ApplicationProgramObject::getWord(uint32_t addr)
{
return ::getWord(_data + addr);
}
uint32_t ApplicationProgramObject::getInt(uint32_t addr)
{
return ::getInt(_data + addr);
}
uint8_t* ApplicationProgramObject::save(uint8_t* buffer)
{
buffer = pushByteArray(_programVersion, 5, buffer);
return TableObject::save(buffer);
}
uint8_t* ApplicationProgramObject::restore(uint8_t* buffer)
{
buffer = popByteArray(_programVersion, 5, buffer);
return TableObject::restore(buffer);
}

View File

@ -0,0 +1,20 @@
#pragma once
#include "table_object.h"
class ApplicationProgramObject: public TableObject
{
public:
ApplicationProgramObject(uint8_t* memoryReference);
void readProperty(PropertyID id, uint32_t start, uint32_t count, uint8_t* data);
void writeProperty(PropertyID id, uint8_t start, uint8_t* data, uint8_t count);
uint8_t propertySize(PropertyID id);
uint8_t* data(uint32_t addr);
uint8_t getByte(uint32_t addr);
uint16_t getWord(uint32_t addr);
uint32_t getInt(uint32_t addr);
uint8_t* save(uint8_t* buffer);
uint8_t* restore(uint8_t* buffer);
private:
uint8_t _programVersion[5];
};

View File

@ -0,0 +1,74 @@
#include <cstring>
#include "association_table_object.h"
#include "bits.h"
using namespace std;
AssociationTableObject::AssociationTableObject(uint8_t* memoryReference): TableObject(memoryReference)
{
}
void AssociationTableObject::readProperty(PropertyID id, uint32_t start, uint32_t count, uint8_t* data)
{
switch (id)
{
case PID_OBJECT_TYPE:
pushWord(OT_ASSOC_TABLE, data);
break;
default:
TableObject::readProperty(id, start, count, data);
}
}
uint16_t AssociationTableObject::entryCount()
{
return _tableData[0];
}
uint16_t AssociationTableObject::operator[](uint16_t idx)
{
if (idx < 0 || idx >= entryCount())
return 0;
return _tableData[idx + 1];
}
uint8_t* AssociationTableObject::save(uint8_t* buffer)
{
return TableObject::save(buffer);
}
uint8_t* AssociationTableObject::restore(uint8_t* buffer)
{
buffer = TableObject::restore(buffer);
_tableData = (uint16_t*)_data;
return buffer;
}
int32_t AssociationTableObject::translateAsap(uint16_t asap)
{
uint16_t entries = entryCount();
for (uint16_t i = 0; i < entries; i++)
{
uint16_t entry = operator[](i);
if (lowByte(entry) == asap)
return highByte(entry);
}
return -1;
}
void AssociationTableObject::beforeStateChange(LoadState& newState)
{
if (newState != LS_LOADED)
return;
_tableData = (uint16_t*)_data;
uint16_t count = reverseByteOrder(_tableData[0]);
// big endian -> little endian
for (size_t i = 0; i <= count; i++)
_tableData[i] = reverseByteOrder(_tableData[i]);
}

View File

@ -0,0 +1,20 @@
#pragma once
#include "table_object.h"
class AssociationTableObject: public TableObject
{
public:
AssociationTableObject(uint8_t* memoryReference);
void readProperty(PropertyID id, uint32_t start, uint32_t count, uint8_t* data);
uint16_t entryCount();
uint16_t operator[](uint16_t idx);
uint8_t* save(uint8_t* buffer);
uint8_t* restore(uint8_t* buffer);
int32_t translateAsap(uint16_t asap);
protected:
void beforeStateChange(LoadState& newState);
private:
uint16_t* _tableData;
};

238
bau.cpp Normal file
View File

@ -0,0 +1,238 @@
#include "bau.h"
void BusAccessUnit::groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, bool status)
{
}
void BusAccessUnit::groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType)
{
}
void BusAccessUnit::groupValueReadResponseConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopTtype, uint8_t * data, uint8_t dataLength, bool status)
{
}
void BusAccessUnit::groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, uint8_t * data, uint8_t dataLength)
{
}
void BusAccessUnit::groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, uint8_t * data, uint8_t dataLength, bool status)
{
}
void BusAccessUnit::groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType, uint8_t * data, uint8_t dataLength)
{
}
void BusAccessUnit::individualAddressWriteLocalConfirm(AckType ack, HopCountType hopType, uint16_t newaddress, bool status)
{
}
void BusAccessUnit::individualAddressWriteIndication(HopCountType hopType, uint16_t newaddress)
{
}
void BusAccessUnit::individualAddressReadLocalConfirm(AckType ack, HopCountType hopType, bool status)
{
}
void BusAccessUnit::individualAddressReadIndication(HopCountType hopType)
{
}
void BusAccessUnit::individualAddressReadResponseConfirm(AckType ack, HopCountType hopType, bool status)
{
}
void BusAccessUnit::individualAddressReadAppLayerConfirm(HopCountType hopType, uint16_t individualAddress)
{
}
void BusAccessUnit::individualAddressSerialNumberReadLocalConfirm(AckType ack, HopCountType hopType, uint8_t * serialNumber, bool status)
{
}
void BusAccessUnit::individualAddressSerialNumberReadIndication(HopCountType hopType, uint8_t * serialNumber)
{
}
void BusAccessUnit::individualAddressSerialNumberReadResponseConfirm(AckType ack, HopCountType hopType, uint8_t * serialNumber, uint16_t domainAddress, bool status)
{
}
void BusAccessUnit::individualAddressSerialNumberReadAppLayerConfirm(HopCountType hopType, uint8_t * serialNumber, uint16_t individualAddress, uint16_t domainAddress)
{
}
void BusAccessUnit::individualAddressSerialNumberWriteLocalConfirm(AckType ack, HopCountType hopType, uint8_t* serialNumber, uint16_t newaddress, bool status)
{
}
void BusAccessUnit::individualAddressSerialNumberWriteIndication(HopCountType hopType, uint8_t * serialNumber, uint16_t newaddress)
{
}
void BusAccessUnit::deviceDescriptorReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t descriptorType, bool status)
{
}
void BusAccessUnit::deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t descriptorType)
{
}
void BusAccessUnit::deviceDescriptorReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t descriptor_type,
uint8_t * device_descriptor, bool status)
{
}
void BusAccessUnit::deviceDescriptorReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, uint8_t descriptortype, uint8_t * deviceDescriptor)
{
}
void BusAccessUnit::restartRequestLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, bool status)
{
}
void BusAccessUnit::restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap)
{
}
void BusAccessUnit::propertyValueReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, bool status)
{
}
void BusAccessUnit::propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex)
{
}
void BusAccessUnit::propertyValueReadResponseConfirm(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, bool status)
{
}
void BusAccessUnit::propertyValueReadAppLayerConfirm(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 BusAccessUnit::propertyValueWriteLocalConfirm(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, bool status)
{
}
void BusAccessUnit::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 BusAccessUnit::propertyDescriptionReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool status)
{
}
void BusAccessUnit::propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex)
{
}
void BusAccessUnit::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)
{
}
void BusAccessUnit::propertyDescriptionReadResponseConfirm(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, bool status)
{
}
void BusAccessUnit::propertyDescriptionReadAppLayerConfirm(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)
{
}
void BusAccessUnit::memoryReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint16_t memoryAddress, bool status)
{
}
void BusAccessUnit::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint16_t memoryAddress)
{
}
void BusAccessUnit::memoryReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint16_t memoryAddress, uint8_t * data, bool status)
{
}
void BusAccessUnit::memoryReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint16_t memoryAddress, uint8_t * data)
{
}
void BusAccessUnit::memoryWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint16_t memoryAddress, uint8_t * data, bool status)
{
}
void BusAccessUnit::memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint16_t memoryAddress, uint8_t * data)
{
}
void BusAccessUnit::userMemoryReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint32_t memoryAddress, bool status)
{
}
void BusAccessUnit::userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint32_t memoryAddress)
{
}
void BusAccessUnit::userMemoryReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint32_t memoryAddress, uint8_t * memoryData, bool status)
{
}
void BusAccessUnit::userMemoryReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint32_t memoryAddress, uint8_t * memoryData)
{
}
void BusAccessUnit::userMemoryWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint32_t memoryAddress, uint8_t * memoryData, bool status)
{
}
void BusAccessUnit::userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint32_t memoryAddress, uint8_t * memoryData)
{
}
void BusAccessUnit::userManufacturerInfoLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, bool status)
{
}
void BusAccessUnit::userManufacturerInfoIndication(Priority priority, HopCountType hopType, uint16_t asap)
{
}
void BusAccessUnit::userManufacturerInfoResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t * info, bool status)
{
}
void BusAccessUnit::userManufacturerInfoAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, uint8_t * info)
{
}
void BusAccessUnit::authorizeLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint32_t key, bool status)
{
}
void BusAccessUnit::authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, uint32_t key)
{
}
void BusAccessUnit::authorizeResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t level, bool status)
{
}
void BusAccessUnit::authorizeAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, uint8_t level)
{
}
void BusAccessUnit::keyWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t level, uint32_t key, bool status)
{
}
void BusAccessUnit::keyWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t level, uint32_t key)
{
}
void BusAccessUnit::keyWriteResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t level, bool status)
{
}
void BusAccessUnit::keyWriteAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, uint8_t level)
{
}

110
bau.h Normal file
View File

@ -0,0 +1,110 @@
#pragma once
#include <stdint.h>
#include "knx_types.h"
class BusAccessUnit
{
public:
virtual void groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, bool status);
virtual void groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType);
virtual void groupValueReadResponseConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopTtype,
uint8_t* data, uint8_t dataLength, bool status);
virtual void groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType,
uint8_t* data, uint8_t dataLength);
virtual void groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType,
uint8_t* data, uint8_t dataLength, bool status);
virtual void groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType,
uint8_t* data, uint8_t dataLength);
virtual void individualAddressWriteLocalConfirm(AckType ack, HopCountType hopType,
uint16_t newaddress, bool status);
virtual void individualAddressWriteIndication(HopCountType hopType, uint16_t newaddress);
virtual void individualAddressReadLocalConfirm(AckType ack, HopCountType hopType, bool status);
virtual void individualAddressReadIndication(HopCountType hopType);
virtual void individualAddressReadResponseConfirm(AckType ack, HopCountType hopType, bool status);
virtual void individualAddressReadAppLayerConfirm(HopCountType hopType, uint16_t individualAddress);
virtual void individualAddressSerialNumberReadLocalConfirm(AckType ack, HopCountType hopType,
uint8_t* serialNumber, bool status);
virtual void individualAddressSerialNumberReadIndication(HopCountType hopType, uint8_t* serialNumber);
virtual void individualAddressSerialNumberReadResponseConfirm(AckType ack, HopCountType hopType,
uint8_t* serialNumber, uint16_t domainAddress, bool status);
virtual void individualAddressSerialNumberReadAppLayerConfirm(HopCountType hopType, uint8_t* serialNumber,
uint16_t individualAddress, uint16_t domainAddress);
virtual void individualAddressSerialNumberWriteLocalConfirm(AckType ack, HopCountType hopType, uint8_t* serialNumber,
uint16_t newaddress, bool status);
virtual void individualAddressSerialNumberWriteIndication(HopCountType hopType, uint8_t* serialNumber, uint16_t newaddress);
virtual void deviceDescriptorReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t descriptorType, bool status);
virtual void deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t descriptorType);
virtual void deviceDescriptorReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t descriptor_type, uint8_t* device_descriptor, bool status);
virtual void deviceDescriptorReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap,
uint8_t descriptortype, uint8_t* deviceDescriptor);
virtual void restartRequestLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, bool status);
virtual void restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap);
virtual void propertyValueReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, bool status);
virtual void propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex,
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex);
virtual void propertyValueReadResponseConfirm(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, bool status);
virtual void propertyValueReadAppLayerConfirm(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);
virtual void propertyValueWriteLocalConfirm(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, bool status);
virtual 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);
virtual void propertyDescriptionReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool status);
virtual void propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap,
uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex);
virtual void 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);
virtual void propertyDescriptionReadResponseConfirm(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, bool status);
virtual void propertyDescriptionReadAppLayerConfirm(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);
virtual void memoryReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint16_t memoryAddress, bool status);
virtual void memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint16_t memoryAddress);
virtual void memoryReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint16_t memoryAddress, uint8_t* data, bool status);
virtual void memoryReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint16_t memoryAddress, uint8_t* data);
virtual void memoryWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint16_t memoryAddress, uint8_t* data, bool status);
virtual void memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint16_t memoryAddress, uint8_t* data);
virtual void userMemoryReadLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint32_t memoryAddress, bool status);
virtual void userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint32_t memoryAddress);
virtual void userMemoryReadResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint32_t memoryAddress, uint8_t* memoryData, bool status);
virtual void userMemoryReadAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint32_t memoryAddress, uint8_t* memoryData);
virtual void userMemoryWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint32_t memoryAddress, uint8_t* memoryData, bool status);
virtual void userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
uint32_t memoryAddress, uint8_t* memoryData);
virtual void userManufacturerInfoLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, bool status);
virtual void userManufacturerInfoIndication(Priority priority, HopCountType hopType, uint16_t asap);
virtual void userManufacturerInfoResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap,
uint8_t* info, bool status);
virtual void userManufacturerInfoAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap,
uint8_t* info);
virtual void authorizeLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint32_t key, bool status);
virtual void authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, uint32_t key);
virtual void authorizeResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t level,
bool status);
virtual void authorizeAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, uint8_t level);
virtual void keyWriteLocalConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t level,
uint32_t key, bool status);
virtual void keyWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t level,
uint32_t key);
virtual void keyWriteResponseConfirm(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, uint8_t level,
bool status);
virtual void keyWriteAppLayerConfirm(Priority priority, HopCountType hopType, uint16_t asap, uint8_t level);
};

272
bau57B0.cpp Normal file
View File

@ -0,0 +1,272 @@
#include "bau57B0.h"
#include <string.h>
#include <stdio.h>
using namespace std;
Bau57B0::Bau57B0(Platform& platform): _memoryReference((uint8_t*)&_deviceObj), _memory(platform), _addrTable(_memoryReference),
_assocTable(_memoryReference), _groupObjTable(_memoryReference), _appProgram(_memoryReference),
_ipParameters(_deviceObj, _platform), _platform(platform), _appLayer(_assocTable, *this),
_transLayer(_appLayer, _addrTable, _platform), _netLayer(_transLayer),
_dlLayer(_deviceObj, _addrTable, _ipParameters, _netLayer, _platform)
{
_appLayer.transportLayer(_transLayer);
_transLayer.networkLayer(_netLayer);
_netLayer.dataLinkLayer(_dlLayer);
_memory.addSaveRestore(&_deviceObj);
_memory.addSaveRestore(&_ipParameters);
_memory.addSaveRestore(&_appProgram);
_memory.addSaveRestore(&_addrTable);
_memory.addSaveRestore(&_assocTable);
_memory.addSaveRestore(&_groupObjTable);
_memory.readMemory();
_dlLayer.enabled(true);
}
void Bau57B0::loop()
{
_dlLayer.loop();
_transLayer.loop();
sendNextGroupTelegram();
}
void Bau57B0::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 Bau57B0::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);
}
DeviceObject& Bau57B0::deviceObject()
{
return _deviceObj;
}
GroupObjectTableObject& Bau57B0::groupObjectTable()
{
return _groupObjTable;
}
ApplicationProgramObject& Bau57B0::parameters()
{
return _appProgram;
}
bool Bau57B0::configured()
{
return _groupObjTable.loadState() == LS_LOADED
&& _addrTable.loadState() == LS_LOADED
&& _assocTable.loadState() == LS_LOADED
&& _appProgram.loadState() == LS_LOADED;
}
void Bau57B0::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 Bau57B0::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 Bau57B0::deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t descriptorType)
{
if (descriptorType != 0)
descriptorType = 0x3f;
uint8_t descriptor[] = { 0x57, 0xb0 };
_appLayer.deviceDescriptorReadResponse(AckRequested, priority, hopType, asap, descriptorType, descriptor);
}
void Bau57B0::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 Bau57B0::authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, uint32_t key)
{
_appLayer.authorizeResponse(AckRequested, priority, hopType, asap, 0);
}
void Bau57B0::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 Bau57B0::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 Bau57B0::propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex,
uint8_t propertyId, uint8_t propertyIndex)
{
// TODO: reply correctly
_appLayer.propertyDescriptionReadResponse(AckRequested, priority, hopType, asap, objectIndex, propertyId, propertyIndex,
false, 0, 0, 0);
}
void Bau57B0::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);
obj.writeProperty((PropertyID)propertyId, startIndex, data, numberOfElements);
propertyValueReadIndication(priority, hopType, asap, objectIndex, propertyId, numberOfElements, startIndex);
}
void Bau57B0::propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex,
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex)
{
InterfaceObject& obj = getInterfaceObject(objectIndex);
uint8_t elementSize = obj.propertySize((PropertyID)propertyId);
uint8_t size = elementSize * numberOfElements;
uint8_t data[size];
obj.readProperty((PropertyID)propertyId, startIndex, numberOfElements, data);
_appLayer.propertyValueReadResponse(AckRequested, priority, hopType, asap, objectIndex, propertyId, numberOfElements,
startIndex, data, size);
}
void Bau57B0::individualAddressReadIndication(HopCountType hopType)
{
if (_deviceObj.progMode())
_appLayer.individualAddressReadResponse(AckRequested, hopType);
}
void Bau57B0::individualAddressWriteIndication(HopCountType hopType, uint16_t newaddress)
{
if (_deviceObj.progMode())
_deviceObj.induvidualAddress(newaddress);
}
void Bau57B0::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 Bau57B0::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 Bau57B0::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 Bau57B0::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 Bau57B0::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& Bau57B0::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:
return _ipParameters;
default:
return _deviceObj;
}
}

74
bau57B0.h Normal file
View File

@ -0,0 +1,74 @@
#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 "ip_parameter_object.h"
#include "application_layer.h"
#include "transport_layer.h"
#include "network_layer.h"
#include "data_link_layer.h"
#include "platform.h"
#include "memory.h"
class Bau57B0: protected BusAccessUnit
{
using BusAccessUnit::memoryReadIndication;
public:
Bau57B0(Platform& platform);
void loop();
DeviceObject& deviceObject();
GroupObjectTableObject& groupObjectTable();
ApplicationProgramObject& parameters();
bool configured();
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;
IpParameterObject _ipParameters;
Platform& _platform;
ApplicationLayer _appLayer;
TransportLayer _transLayer;
NetworkLayer _netLayer;
DataLinkLayer _dlLayer;
};

75
bits.cpp Normal file
View File

@ -0,0 +1,75 @@
#include "bits.h"
uint8_t* popByte(uint8_t& b, uint8_t* data)
{
b = *data;
data += 1;
return data;
}
uint8_t* popWord(uint16_t& w, uint8_t* data)
{
w = getWord(data);
data += 2;
return data;
}
uint8_t* popInt(uint32_t& i, uint8_t* data)
{
i = getInt(data);
data += 4;
return data;
}
uint8_t* popByteArray(uint8_t* dst, uint32_t size, uint8_t* data)
{
for (uint32_t i = 0; i < size; i++)
dst[i] = data[i];
data += size;
return data;
}
uint8_t* pushByte(uint8_t b, uint8_t* data)
{
data[0] = b;
data += 1;
return data;
}
uint8_t* pushWord(uint16_t w, uint8_t* data)
{
data[0] = ((w >> 8) & 0xff);
data[1] = (w & 0xff);
data += 2;
return data;
}
uint8_t* pushInt(uint32_t i, uint8_t* data)
{
data[0] = ((i >> 24) & 0xff);
data[1] = ((i >> 16) & 0xff);
data[2] = ((i >> 8) & 0xff);
data[3] = (i & 0xff);
data += 4;
return data;
}
uint8_t* pushByteArray(const uint8_t* src, uint32_t size, uint8_t* data)
{
for (uint32_t i = 0; i < size; i++)
data[i] = src[i];
data += size;
return data;
}
uint16_t getWord(uint8_t* data)
{
return (data[0] << 8) + data[1];;
}
uint32_t getInt(uint8_t * data)
{
return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3];;
}

133
bits.h Normal file
View File

@ -0,0 +1,133 @@
/*
* bits.h - Bit and uint8_t manipulation functions.
*
* Copyright (c) 2014 Stefan Taferner <stefan.taferner@gmx.at>
*
* 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.
*/
#pragma once
#include <stdint.h>
/**
* Compute the value of the specified bit.
*
* @param bitno - the number of the bit (0, 1, 2... 31)
*/
#define bit(bitno) (1UL << (bitno))
/**
* Clear the bit of a number. The number can be
* any integer (uint8_t, short, uint32_t, long).
*
* @param val - the number from which to clear the bit
* @param bitno - the number of the bit (0, 1, 2... 31)
*/
#define bitClear(val, bitno) ((val) &= ~(1UL << (bitno)))
/**
* Set the bit of a number. The number can be
* any integer (uint8_t, short, uint32_t, long).
*
* @param val - the number from which to set the bit
* @param bitno - the number of the bit (0, 1, 2... 31)
*/
#define bitSet(val, bitno) ((val) |= 1UL << (bitno))
/**
* Write the value of a bit of a number.
*
* @param val - the number from which to write the bit
* @param bitno - the number of the bit (0, 1, 2... 31)
* @param b - the bit value (0 or 1)
*/
#define bitWrite(val, bitno, b) ((b) ? bitSet(val, bitno) : bitClear(val, bitno))
/**
* Read the value of a bit of a number. The number can be
* any integer (uint8_t, short, uint32_t, long).
*
* @param val - the number from which to get the bit
* @param bitno - the number of the bit (0, 1, 2... 31)
* @return The value of the bit (0 or 1).
*/
#define bitRead(val, bitno) (((val) >> (bitno)) & 1)
/**
* Extract the lowest (rightmost) uint8_t of a number. The number can be
* any integer (uint8_t, short, uint32_t, long).
*
* @param val - the value to extract the lowest uint8_t.
* @return The extracted uint8_t (0..255)
*/
#define lowByte(val) ((val) & 255)
/**
* Extract the highest (leftmost) uint8_t of a number. The number can be
* any integer (uint8_t, short, uint32_t, long).
*
* @param val - the value to extract the highest uint8_t.
* @return The extracted uint8_t (0..255)
*/
#define highByte(val) (((val) >> ((sizeof(val) - 1) << 3)) & 255)
/**
* Combine two bytes to a 16 bit uint16_t.
*
* @param high - the high uint8_t.
* @param low - the low uint8_t.
* @return The bytes combined as uint16_t.
*/
uint16_t makeWord(uint8_t high, uint8_t low);
/**
* Reverse the uint8_t order of an integer.
*
* @param val - the value to reverse.
* @return The value with reversed uint8_t order.
*/
uint32_t reverseByteOrder(uint32_t val);
/**
* Reverse the uint8_t order of a short integer.
*
* @param val - the value to reverse.
* @return The value with reversed uint8_t order.
*/
uint16_t reverseByteOrder(uint16_t val);
//
// Inline functions
//
inline uint16_t makeWord(uint8_t high, uint8_t low)
{
return (high << 8) | low;
}
inline uint32_t reverseByteOrder(uint32_t val)
{
uint32_t swapped = ((val >> 24) & 0xff) | // move uint8_t 3 to uint8_t 0
((val << 8) & 0xff0000) | // move uint8_t 1 to uint8_t 2
((val >> 8) & 0xff00) | // move uint8_t 2 to uint8_t 1
((val << 24) & 0xff000000); // uint8_t 0 to uint8_t 3
return swapped;//__REV(val);
}
inline uint16_t reverseByteOrder(uint16_t val)
{
uint16_t swapped = (val >> 8) | (val << 8);
return swapped;
}
uint8_t* popByte(uint8_t& b, uint8_t* data);
uint8_t* popWord(uint16_t& w, uint8_t* data);
uint8_t* popInt(uint32_t& i, uint8_t* data);
uint8_t* popByteArray(uint8_t* dst, uint32_t size, uint8_t* data);
uint8_t* pushByte(uint8_t b, uint8_t* data);
uint8_t* pushWord(uint16_t w, uint8_t* data);
uint8_t* pushInt(uint32_t i, uint8_t* data);
uint8_t* pushByteArray(const uint8_t* src, uint32_t size, uint8_t* data);
uint16_t getWord(uint8_t* data);
uint32_t getInt(uint8_t* data);

195
cemi_frame.cpp Normal file
View File

@ -0,0 +1,195 @@
#include "cemi_frame.h"
#include "bits.h"
#include "string.h"
#include <stdio.h>
CemiFrame::CemiFrame(uint8_t* data, uint16_t length): _npdu(data + NPDU_LPDU_DIFF, *this),
_tpdu(data + TPDU_LPDU_DIFF, *this), _apdu(data + APDU_LPDU_DIFF, *this)
{
_data = data;
_ctrl1 = data + data[1] + 2;
_length = length;
}
CemiFrame::CemiFrame(uint8_t apduLength): _data(buffer),
_npdu(_data + NPDU_LPDU_DIFF, *this), _tpdu(_data + TPDU_LPDU_DIFF, *this), _apdu(_data + APDU_LPDU_DIFF, *this)
{
_ctrl1 = _data + 2;
_length = 0;
memset(_data, 0, apduLength + APDU_LPDU_DIFF);
_ctrl1[0] |= Broadcast;
_npdu.octetCount(apduLength);
}
CemiFrame::CemiFrame(const CemiFrame & other): _data(buffer),
_npdu(_data + NPDU_LPDU_DIFF, *this), _tpdu(_data + TPDU_LPDU_DIFF, *this), _apdu(_data + APDU_LPDU_DIFF, *this)
{
_ctrl1 = _data + 2;
_length = other._length;
memcpy(_data, other._data, other.totalLenght());
}
CemiFrame& CemiFrame::operator=(CemiFrame other)
{
_length = other._length;
_data = buffer;
_ctrl1 = _data + 2;
memcpy(_data, other._data, other.totalLenght());
_npdu._data = _data + NPDU_LPDU_DIFF;
_tpdu._data = _data + TPDU_LPDU_DIFF;
_apdu._data = _data + APDU_LPDU_DIFF;
return *this;
}
MessageCode CemiFrame::messageCode() const
{
return (MessageCode)_data[0];
}
void CemiFrame::messageCode(MessageCode msgCode)
{
_data[0] = msgCode;
}
uint16_t CemiFrame::totalLenght() const
{
uint16_t tmp =
_npdu.length() + NPDU_LPDU_DIFF;
return tmp;
}
FrameFormat CemiFrame::frameType() const
{
return (FrameFormat)(_ctrl1[0] & StandardFrame);
}
void CemiFrame::frameType(FrameFormat type)
{
_ctrl1[0] &= ~StandardFrame;
_ctrl1[0] |= type;
}
Repetition CemiFrame::repetition() const
{
return (Repetition)(_ctrl1[0] & RepititionAllowed);
}
void CemiFrame::repetition(Repetition rep)
{
_ctrl1[0] &= ~RepititionAllowed;
_ctrl1[0] |= rep;
}
SystemBroadcast CemiFrame::systemBroadcast() const
{
return (SystemBroadcast)(_ctrl1[0] & Broadcast);
}
void CemiFrame::systemBroadcast(SystemBroadcast value)
{
_ctrl1[0] &= ~Broadcast;
_ctrl1[0] |= value;
}
Priority CemiFrame::priority() const
{
return (Priority)(_ctrl1[0] & LowPriority);
}
void CemiFrame::priority(Priority value)
{
_ctrl1[0] &= ~LowPriority;
_ctrl1[0] |= value;
}
AckType CemiFrame::ack() const
{
return (AckType)(_ctrl1[0] & AckRequested);
}
void CemiFrame::ack(AckType value)
{
_ctrl1[0] &= ~AckRequested;
_ctrl1[0] |= value;
}
AddressType CemiFrame::addressType() const
{
return (AddressType)(_ctrl1[1] & GroupAddress);
}
void CemiFrame::addressType(AddressType value)
{
_ctrl1[1] &= ~GroupAddress;
_ctrl1[1] |= value;
}
uint8_t CemiFrame::hopCount() const
{
return ((_ctrl1[1] >> 4) & 0x7);
}
void CemiFrame::hopCount(uint8_t value)
{
_ctrl1[1] &= ~(0x7 << 4);
_ctrl1[1] |= ((value & 0x7) << 4);
}
uint16_t CemiFrame::sourceAddress() const
{
uint16_t addr;
popWord(addr, _ctrl1 + 2);
return addr;
}
void CemiFrame::sourceAddress(uint16_t value)
{
pushWord(value, _ctrl1 + 2);
}
uint16_t CemiFrame::destinationAddress() const
{
uint16_t addr;
popWord(addr, _ctrl1 + 4);
return addr;
}
void CemiFrame::destinationAddress(uint16_t value)
{
pushWord(value, _ctrl1 + 4);
}
NPDU& CemiFrame::npdu()
{
return _npdu;
}
TPDU& CemiFrame::tpdu()
{
return _tpdu;
}
APDU& CemiFrame::apdu()
{
return _apdu;
}
bool CemiFrame::valid() const
{
uint8_t addInfoLen = _data[1];
uint8_t apduLen = _data[1 + _data[1] + NPDU_LPDU_DIFF];
if (_length != 0 && _length != (addInfoLen + apduLen + NPDU_LPDU_DIFF + 2))
return false;
if ((_ctrl1[0] & 0x40) > 0 // Bit 6 has do be 0
|| (_ctrl1[1] & 0xF) > 0 // only standard or extended frames
|| _npdu.octetCount() == 0xFF // not allowed
|| (_npdu.octetCount() > 15 && frameType() == StandardFrame)
)
return false;
return true;
}

60
cemi_frame.h Normal file
View File

@ -0,0 +1,60 @@
#pragma once
#include "knx_types.h"
#include "stdint.h"
#include "npdu.h"
#include "tpdu.h"
#include "apdu.h"
#define NPDU_LPDU_DIFF 8
#define TPDU_NPDU_DIFF 1
#define APDU_TPDU_DIFF 0
#define TPDU_LPDU_DIFF (TPDU_NPDU_DIFF + NPDU_LPDU_DIFF)
#define APDU_LPDU_DIFF (APDU_TPDU_DIFF + TPDU_NPDU_DIFF + NPDU_LPDU_DIFF)
class CemiFrame
{
friend class DataLinkLayer;
public:
CemiFrame(uint8_t* data, uint16_t length);
CemiFrame(uint8_t apduLength);
CemiFrame(const CemiFrame& other);
CemiFrame& operator= (CemiFrame other);
MessageCode messageCode() const;
void messageCode(MessageCode value);
uint16_t totalLenght() const;
FrameFormat frameType() const;
void frameType(FrameFormat value);
Repetition repetition() const;
void repetition(Repetition value);
SystemBroadcast systemBroadcast() const;
void systemBroadcast(SystemBroadcast value);
Priority priority() const;
void priority(Priority value);
AckType ack() const;
void ack(AckType value);
AddressType addressType() const;
void addressType(AddressType value);
uint8_t hopCount() const;
void hopCount(uint8_t value);
uint16_t sourceAddress() const;
void sourceAddress(uint16_t value);
uint16_t destinationAddress() const;
void destinationAddress(uint16_t value);
NPDU& npdu();
TPDU& tpdu();
APDU& apdu();
bool valid() const;
private:
uint8_t buffer[0xff + NPDU_LPDU_DIFF]; //only valid of add info is zero
uint8_t* _data;
uint8_t* _ctrl1;
NPDU _npdu;
TPDU _tpdu;
APDU _apdu;
uint16_t _length; // only set if created from byte array
};

199
data_link_layer.cpp Normal file
View File

@ -0,0 +1,199 @@
/*
* bus.cpp - Low level EIB bus access.
*
* Copyright (c) 2014 Stefan Taferner <stefan.taferner@gmx.at>
*
* 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 <stdio.h>
#include <string.h>
#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,
NetworkLayer& layer, Platform& platform) :
_deviceObject(devObj), _groupAddressTable(addrTab), _ipParameters(ipParam), _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);
_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);
_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)
{
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();
uint16_t source = frame.sourceAddress();
FrameFormat type = frame.frameType();
Priority priority = frame.priority();
NPDU& npdu = frame.npdu();
uint16_t ownAddr = _deviceObject.induvidualAddress();
if (source == ownAddr)
_deviceObject.induvidualAddressDuplication(true);
if (addrType == GroupAddress && destination == 0)
_networkLayer.systemBroadcastIndication(ack, type, npdu, priority, source);
else
{
if (addrType == InduvidualAddress && destination != _deviceObject.induvidualAddress())
return;
if (addrType == GroupAddress && !_groupAddressTable.contains(destination))
return;
//if (frame.npdu().octetCount() > 0)
//{
// print.print("<- DLL ");
// frame.apdu().printPDU();
//}
_networkLayer.dataIndication(ack, addrType, destination, type, npdu, priority, source);
}
}
void DataLinkLayer::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 DataLinkLayer::enabled() const
{
return _enabled;
}
bool DataLinkLayer::sendBytes(uint8_t* bytes, uint16_t length)
{
if (!_enabled)
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);
}

33
data_link_layer.h Normal file
View File

@ -0,0 +1,33 @@
#pragma once
#include <stdint.h>
#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,
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);
DeviceObject& _deviceObject;
AddressTableObject& _groupAddressTable;
IpParameterObject& _ipParameters;
NetworkLayer& _networkLayer;
Platform& _platform;
};

63
datapoint_types.cpp Normal file
View File

@ -0,0 +1,63 @@
/*
* datapoint_types.h - Conversion functions for datapoint types.
*
* Copyright (c) 2014 Stefan Taferner <stefan.taferner@gmx.at>
*
* 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 "datapoint_types.h"
#include <stdint.h>
// Sign for a negative DPT9 float value
#define DPT_FLOAT_NEG_SIGN 0x8000
uint16_t dptToFloat(int32_t value)
{
uint16_t exp = 0;
if (value < -67108864 || value > 67076096)
return 0x7fff;
if (value < 0)
{
while (value < -2048)
{
value >>= 1;
++exp;
}
return DPT_FLOAT_NEG_SIGN | (((int32_t) value) & 2047) | (exp << 11);
}
else
{
while (value > 2047)
{
value >>= 1;
++exp;
}
return value | (exp << 11);
}
}
int32_t dptFromFloat(uint16_t dptValue)
{
uint16_t exp = (dptValue >> 11) & 15;
int32_t value;
if (dptValue == 0x7fff)
return INVALID_DPT_FLOAT;
if (dptValue >= 0x8000)
value = dptValue | (-1L & ~2047);
else value = dptValue & 2047;
for (; exp; --exp)
value <<= 1;
return value;
}

37
datapoint_types.h Normal file
View File

@ -0,0 +1,37 @@
/*
* datapoint_types.h - Conversion functions for datapoint types.
*
* Copyright (c) 2014 Stefan Taferner <stefan.taferner@gmx.at>
*
* 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.
*/
#pragma once
#include <stdint.h>
/**
* An invalid 2 uint8_t float (DPT9/EIS5).
* To be used for dptToFloat() and dptFromFloat().
*/
#define INVALID_DPT_FLOAT 2147483647U
/**
* Convert a value from uint32_t to 2 uint8_t float (DPT9/EIS5). The possible range
* of the values is -67108864 to 67076096.
*
* @param value - the value to convert.
* Use INVALID_DPT_FLOAT for the DPT9 "invalid data" value.
* @return The 2 uint8_t float (DPT9/EIS5).
*/
uint16_t dptToFloat(int32_t value);
/**
* Convert a value from 2 uint8_t float (DPT9/EIS5) to integer.
*
* @param dptValue - the 2 uint8_t float (DPT9/EIS5) to convert
* @return The value as integer, or INVALID_DPT_FLOAT for the
* DPT9 "invalid data" value.
*/
int32_t dptFromFloat(uint16_t dptValue);

240
device_object.cpp Normal file
View File

@ -0,0 +1,240 @@
#include <cstring>
#include "device_object.h"
#include "bits.h"
void DeviceObject::readProperty(PropertyID propertyId, uint32_t start, uint32_t count, uint8_t* data)
{
switch (propertyId)
{
case PID_OBJECT_TYPE:
pushWord(OT_DEVICE, data);
break;
case PID_SERIAL_NUMBER:
pushWord(_manufacturerId, data);
pushInt(_bauNumber, data);
break;
case PID_MANUFACTURER_ID:
pushWord(_manufacturerId, data);
break;
case PID_DEVICE_CONTROL:
*data = _deviceControl;
break;
case PID_ORDER_INFO:
pushByteArray((uint8_t*)_orderNumber, 10, data);
break;
case PID_HARDWARE_TYPE:
pushByteArray((uint8_t*)_hardwareType, 6, data);
break;
case PID_VERSION:
pushWord(_version, data);
break;
case PID_ROUTING_COUNT:
*data = _routingCount;
break;
case PID_PROG_MODE:
*data = _prgMode;
break;
case PID_MAX_APDU_LENGTH:
*data = 15;
break;
case PID_SUBNET_ADDR:
*data = ((_ownAddress >> 8) & 0xff);
break;
case PID_DEVICE_ADDR:
*data = (_ownAddress & 0xff);
break;
case PID_IO_LIST:
{
uint32_t ifObjs[] = {
6, // length
OT_DEVICE, OT_ADDR_TABLE, OT_ASSOC_TABLE, OT_GRP_OBJ_TABLE, OT_APPLICATION_PROG, OT_IP_PARAMETER};
for (uint32_t i = start; i < (ifObjs[0] + 1) && i < count; i++)
pushInt(ifObjs[i], data);
break;
}
case PID_DEVICE_DESCRIPTOR:
data[0] = 0x57;
data[1] = 0xB0;
break;
}
}
void DeviceObject::writeProperty(PropertyID id, uint8_t start, uint8_t* data, uint8_t count)
{
switch (id)
{
case PID_DEVICE_CONTROL:
_deviceControl = data[0];
break;
case PID_ROUTING_COUNT:
_routingCount = data[0];
break;
case PID_PROG_MODE:
_prgMode = data[0];
break;
}
}
uint8_t DeviceObject::propertySize(PropertyID id)
{
switch (id)
{
case PID_DEVICE_CONTROL:
return 1;
case PID_ROUTING_COUNT:
return 1;
case PID_PROG_MODE:
return 1;
}
return 0;
}
uint8_t* DeviceObject::save(uint8_t* buffer)
{
buffer = pushByte(_deviceControl, buffer);
buffer = pushByte(_routingCount, buffer);
buffer = pushWord(_ownAddress, buffer);
return buffer;
}
uint8_t* DeviceObject::restore(uint8_t* buffer)
{
buffer = popByte(_deviceControl, buffer);
buffer = popByte(_routingCount, buffer);
buffer = popWord(_ownAddress, buffer);
_prgMode = 0;
return buffer;
}
uint16_t DeviceObject::induvidualAddress()
{
return _ownAddress;
}
void DeviceObject::induvidualAddress(uint16_t value)
{
_ownAddress = value;
}
#define USER_STOPPED 0x1
#define OWN_ADDR_DUPL 0x2
#define VERIFY_MODE 0x4
#define SAFE_STATE 0x8
bool DeviceObject::userStopped()
{
return (_deviceControl & USER_STOPPED) > 0;
}
void DeviceObject::userStopped(bool value)
{
if (value)
_deviceControl |= USER_STOPPED;
else
_deviceControl &= ~USER_STOPPED;
}
bool DeviceObject::induvidualAddressDuplication()
{
return (_deviceControl & OWN_ADDR_DUPL) > 0;
}
void DeviceObject::induvidualAddressDuplication(bool value)
{
if (value)
_deviceControl |= OWN_ADDR_DUPL;
else
_deviceControl &= ~OWN_ADDR_DUPL;
}
bool DeviceObject::verifyMode()
{
return (_deviceControl & VERIFY_MODE) > 0;
}
void DeviceObject::verifyMode(bool value)
{
if (value)
_deviceControl |= VERIFY_MODE;
else
_deviceControl &= ~VERIFY_MODE;
}
bool DeviceObject::safeState()
{
return (_deviceControl & SAFE_STATE) > 0;
}
void DeviceObject::safeState(bool value)
{
if (value)
_deviceControl |= SAFE_STATE;
else
_deviceControl &= ~SAFE_STATE;
}
bool DeviceObject::progMode()
{
return _prgMode == 1;
}
void DeviceObject::progMode(bool value)
{
if (value)
_prgMode = 1;
else
_prgMode = 0;
}
uint16_t DeviceObject::manufacturerId()
{
return _manufacturerId;
}
void DeviceObject::manufacturerId(uint16_t value)
{
_manufacturerId = value;
}
uint32_t DeviceObject::bauNumber()
{
return _bauNumber;
}
void DeviceObject::bauNumber(uint32_t value)
{
_bauNumber = value;
}
const char* DeviceObject::orderNumber()
{
return _orderNumber;
}
void DeviceObject::orderNumber(const char* value)
{
strncpy(_orderNumber, value, 10);
}
const uint8_t* DeviceObject::hardwareType()
{
return _hardwareType;
}
void DeviceObject::hardwareType(const uint8_t* value)
{
pushByteArray(value, 6, _hardwareType);
}
uint16_t DeviceObject::version()
{
return _version;
}
void DeviceObject::version(uint16_t value)
{
_version = value;
}

46
device_object.h Normal file
View File

@ -0,0 +1,46 @@
#pragma once
#include "interface_object.h"
class DeviceObject: public InterfaceObject
{
public:
void readProperty(PropertyID id, uint32_t start, uint32_t count, uint8_t* data);
void writeProperty(PropertyID id, uint8_t start, uint8_t* data, uint8_t count);
uint8_t propertySize(PropertyID id);
uint8_t* save(uint8_t* buffer);
uint8_t* restore(uint8_t* buffer);
uint16_t induvidualAddress();
void induvidualAddress(uint16_t value);
bool userStopped();
void userStopped(bool value);
bool induvidualAddressDuplication();
void induvidualAddressDuplication(bool value);
bool verifyMode();
void verifyMode(bool value);
bool safeState();
void safeState(bool value);
bool progMode();
void progMode(bool value);
uint16_t manufacturerId();
void manufacturerId(uint16_t value);
uint32_t bauNumber();
void bauNumber(uint32_t value);
const char* orderNumber();
void orderNumber(const char* value);
const uint8_t* hardwareType();
void hardwareType(const uint8_t* value);
uint16_t version();
void version(uint16_t value);
private:
uint8_t _deviceControl;
uint8_t _routingCount;
uint8_t _prgMode;
uint16_t _ownAddress;
uint16_t _manufacturerId;
uint32_t _bauNumber;
char _orderNumber[10];
uint8_t _hardwareType[6];
uint16_t _version;
};

102
esp_platform.cpp Normal file
View File

@ -0,0 +1,102 @@
#include "esp_platform.h"
#include <user_interface.h>
#include <Arduino.h>
#include <EEPROM.h>
EspPlatform::EspPlatform()
{
}
uint32_t EspPlatform::currentIpAddress()
{
return WiFi.localIP();
}
uint32_t EspPlatform::currentSubnetMask()
{
return WiFi.subnetMask();
}
uint32_t EspPlatform::currentDefaultGateway()
{
return WiFi.gatewayIP();
}
void EspPlatform::macAddress(uint8_t * addr)
{
wifi_get_macaddr(STATION_IF, addr);
}
uint32_t EspPlatform::millis()
{
return millis();
}
void EspPlatform::mdelay(uint32_t millis)
{
delay(millis);
}
void EspPlatform::restart()
{
ESP.restart();
}
void EspPlatform::fatalError()
{
const int period = 200;
while (true)
{
if ((millis() % period) > (period / 2))
digitalWrite(LED_BUILTIN, HIGH);
else
digitalWrite(LED_BUILTIN, LOW);
}
}
void EspPlatform::setupMultiCast(uint32_t addr, uint16_t port)
{
_mulitcastAddr = addr;
_mulitcastPort = port;
_udp.beginMulticast(WiFi.localIP(), addr, port);
}
void EspPlatform::closeMultiCast()
{
_udp.stop();
}
bool EspPlatform::sendBytes(uint8_t * buffer, uint16_t len)
{
_udp.beginPacketMulticast(_mulitcastAddr, _mulitcastPort, WiFi.localIP());
_udp.write(buffer, len);
_udp.endPacket();
return true;
}
int EspPlatform::readBytes(uint8_t * buffer, uint16_t maxLen)
{
int len = _udp.parsePacket();
if (len == 0)
return 0;
if (len > maxLen)
{
printf("udp buffer to small. was %d, needed %d\n", maxLen, len);
fatalError();
}
_udp.read(buffer, len);
return len;
}
uint8_t * EspPlatform::getEepromBuffer(uint16_t size)
{
EEPROM.begin(size);
return EEPROM.getDataPtr();
}
void EspPlatform::commitToEeprom()
{
EEPROM.commit();
}

36
esp_platform.h Normal file
View File

@ -0,0 +1,36 @@
#include "platform.h"
#include <ESP8266WiFi.h>
#include <WifiUDP.h>
class EspPlatform : public Platform
{
public:
EspPlatform();
// ip stuff
uint32_t currentIpAddress();
uint32_t currentSubnetMask();
uint32_t currentDefaultGateway();
void macAddress(uint8_t* addr);
// basic stuff
uint32_t millis();
void mdelay(uint32_t millis);
void restart();
void fatalError();
//multicast
void setupMultiCast(uint32_t addr, uint16_t port);
void closeMultiCast();
bool sendBytes(uint8_t* buffer, uint16_t len);
int readBytes(uint8_t* buffer, uint16_t maxLen);
//memory
uint8_t* getEepromBuffer(uint16_t size);
void commitToEeprom();
private:
uint32_t _mulitcastAddr;
uint16_t _mulitcastPort;
WiFiUDP _udp;
};

191
group_object.cpp Normal file
View File

@ -0,0 +1,191 @@
#include "group_object.h"
#include "bits.h"
#include "string.h"
#include "datapoint_types.h"
#include "group_object_table_object.h"
GroupObject::GroupObject(uint8_t size)
{
_data = new uint8_t[size];
_commFlag = Ok;
_table = 0;
_dataLength = size;
updateHandler = 0;
}
GroupObject::~GroupObject()
{
delete[] _data;
}
bool GroupObject::responseUpdateEnable()
{
if (!_table)
return false;
return bitRead(_table->_tableData[_asap], 15) > 0;
}
bool GroupObject::transmitEnable()
{
if (!_table)
return false;
return bitRead(_table->_tableData[_asap], 14) > 0;
}
bool GroupObject::valueReadOnInit()
{
if (!_table)
return false;
return bitRead(_table->_tableData[_asap], 13) > 0;
}
bool GroupObject::writeEnable()
{
if (!_table)
return false;
return bitRead(_table->_tableData[_asap], 12) > 0;
}
bool GroupObject::readEnable()
{
if (!_table)
return false;
return bitRead(_table->_tableData[_asap], 11) > 0;
}
bool GroupObject::communicationEnable()
{
if (!_table)
return false;
return bitRead(_table->_tableData[_asap], 10) > 0;
}
Priority GroupObject::priority()
{
if (!_table)
return LowPriority;
return (Priority)((_table->_tableData[_asap] >> 6) & (3 << 2)) ;
}
uint8_t* GroupObject::valueRef()
{
return _data;
}
uint16_t GroupObject::asap()
{
return _asap;
}
size_t GroupObject::goSize()
{
size_t size = sizeInTelegram();
if (size == 0)
return 1;
return size;
}
// see knxspec 3.5.1 p. 178
size_t GroupObject::asapValueSize(uint8_t code)
{
if (code < 7)
return 0;
if (code < 8)
return 1;
if (code < 11 || (code > 20 && code < 255))
return code - 6;
switch (code)
{
case 11:
return 6;
case 12:
return 8;
case 13:
return 10;
case 14:
return 14;
case 15:
return 5;
case 16:
return 7;
case 17:
return 9;
case 18:
return 11;
case 19:
return 12;
case 20:
return 13;
case 255:
return 252;
}
return -1;
}
ComFlag GroupObject::commFlag()
{
return _commFlag;
}
void GroupObject::commFlag(ComFlag value)
{
_commFlag = value;
}
int32_t GroupObject::objectReadFloat()
{
uint16_t dptValue = makeWord(_data[0], _data[1]);
return dptFromFloat(dptValue);
}
bool GroupObject::objectReadBool()
{
return _data[0] > 0;
}
void GroupObject::requestObjectRead()
{
_commFlag = ReadRequest;
}
void GroupObject::objectWritten()
{
_commFlag = WriteRequest;
}
void GroupObject::objectWriteFloat(int32_t value)
{
uint16_t dptValue = dptToFloat(value);
pushWord(dptValue, _data);
objectWritten();
}
void GroupObject::objectUpdateFloat(int32_t value)
{
uint16_t dptValue = dptToFloat(value);
pushWord(dptValue, _data);
_commFlag = cfUpdate;
}
size_t GroupObject::valueSize()
{
return _dataLength;
}
size_t GroupObject::sizeInTelegram()
{
uint8_t code = lowByte(_table->_tableData[_asap]);
return asapValueSize(code);
}

111
group_object.h Normal file
View File

@ -0,0 +1,111 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
#include "knx_types.h"
class GroupObjectTableObject;
enum ComFlag
{
cfUpdate = 0,
ReadRequest = 1,
WriteRequest = 2,
Transmitting = 3,
Ok = 4,
Error = 5
};
class GroupObject;
typedef void (*GroupObjectUpdatedHandler)(GroupObject& go);
class GroupObject
{
friend class GroupObjectTableObject;
public:
GroupObject(uint8_t size);
virtual ~GroupObject();
// config flags from ETS
bool responseUpdateEnable();
bool transmitEnable();
bool valueReadOnInit();
bool writeEnable();
bool readEnable();
bool communicationEnable();
Priority priority();
ComFlag commFlag();
void commFlag(ComFlag value);
/**
* Get the float value from a communication object. Can be used for
* communication objects of type 2 uint8_t float (EIS5 / DPT9). The value is in
* 1/100 - a DPT9 value of 21.01 is returned as 2101.
*
* @return The value of the com-object in 1/100. INVALID_DPT_FLOAT is returned
* for the DPT9 "invalid data" value.
*/
int32_t objectReadFloat();
bool objectReadBool();
/**
* Request the read of a communication object. Calling this function triggers the
* sending of a read-group-value telegram, to read the value of the communication
* object from the bus.
*
* When the answer is received, the communication object's value will be updated.
* You can cycle through all updated communication objects with nextUpdatedObject().
*
*
* @see objectWritten()
*/
void requestObjectRead();
/**
* Mark a communication object as written. Use this function if you directly change
* the value of a communication object without using objectWrite(). Calling this
* function triggers the sending of a write-group-value telegram.
*
* @see requestObjectRead()
*/
void objectWritten();
/**
* Set the value of a communication object. Calling this function triggers the
* sending of a write-group-value telegram.
*
* The communication object is a 2 uint8_t float (EIS5 / DPT9) object. The value is
* in 1/100, so a value of 2101 would set a DPT9 float value of 21.01. The valid
* range of the values is -671088.64 to 670760.96.
*
* @param value - the new value of the communication object in 1/100.
* Use INVALID_DPT_FLOAT for the DPT9 "invalid data" value.
*/
void objectWriteFloat(int32_t value);
/**
* Set the value of a communication object and mark the communication object
* as updated. This does not trigger a write-group-value telegram.
*
* The communication object is a 2 uint8_t float (EIS5 / DPT9) object. The value
* is in 1/100, so a value of 2101 would set a DPT9 float value of 21.01.
* The possible range of the values is -671088.64 to 670760.96.
*
* @param objno - the ID of the communication object.
* @param value - the new value of the communication object in 1/100.
* Use INVALID_DPT_FLOAT for the DPT9 "invalid data" value.
*/
void objectUpdateFloat(int32_t value);
size_t valueSize();
size_t asapValueSize(uint8_t code);
size_t sizeInTelegram();
uint8_t* valueRef();
uint16_t asap();
GroupObjectUpdatedHandler updateHandler;
private:
size_t goSize();
uint16_t _asap;
ComFlag _commFlag;
uint8_t* _data;
uint8_t _dataLength;
GroupObjectTableObject* _table;
};

View File

@ -0,0 +1,125 @@
#include <cstring>
#include "group_object_table_object.h"
#include "group_object.h"
#include "bits.h"
GroupObjectTableObject::GroupObjectTableObject(uint8_t* memoryReference): TableObject(memoryReference)
{
_groupObjects = 0;
_groupObjectCount = 0;
}
void GroupObjectTableObject::readProperty(PropertyID id, uint32_t start, uint32_t count, uint8_t* data)
{
switch (id)
{
case PID_OBJECT_TYPE:
pushWord(OT_GRP_OBJ_TABLE, data);
break;
default:
TableObject::readProperty(id, start, count, data);
}
}
uint16_t GroupObjectTableObject::entryCount()
{
if (loadState() != LS_LOADED)
return 0;
return _tableData[0];
}
GroupObject& GroupObjectTableObject::get(uint16_t asap)
{
return _groupObjects[asap - 1];
}
uint8_t* GroupObjectTableObject::save(uint8_t* buffer)
{
return TableObject::save(buffer);
}
uint8_t* GroupObjectTableObject::restore(uint8_t* buffer)
{
buffer = TableObject::restore(buffer);
_tableData = (uint16_t*)_data;
initGroupObjects();
return buffer;
}
GroupObject& GroupObjectTableObject::nextUpdatedObject(bool& valid)
{
static uint16_t startIdx = 1;
uint16_t objCount = entryCount();
for (uint16_t asap = startIdx; asap <= objCount; asap++)
{
GroupObject& go = get(asap);
if (go.commFlag() == cfUpdate)
{
go.commFlag(Ok);
startIdx = asap + 1;
valid = true;
return go;
}
}
startIdx = 1;
valid = false;
return get(1);
}
void GroupObjectTableObject::groupObjects(GroupObject * objs, uint16_t size)
{
_groupObjects = objs;
_groupObjectCount = size;
initGroupObjects();
}
void GroupObjectTableObject::beforeStateChange(LoadState& newState)
{
if (newState != LS_LOADED)
return;
_tableData = (uint16_t*)_data;
uint16_t goCount = reverseByteOrder(_tableData[0]);
// big endian -> little endian
for (size_t i = 0; i <= goCount; i++)
_tableData[i] = reverseByteOrder(_tableData[i]);
if (!initGroupObjects())
{
newState = LS_ERROR;
TableObject::_errorCode = E_SOFTWARE_FAULT;
}
}
bool GroupObjectTableObject::initGroupObjects()
{
if (!_tableData)
return false;
uint16_t goCount = _tableData[0];
if (goCount != _groupObjectCount)
return false;
for (uint16_t asap = 1; asap <= goCount; asap++)
{
GroupObject& go = _groupObjects[asap - 1];
go._asap = asap;
go._table = this;
if (go._dataLength != go.goSize())
return false;
}
return true;
}

View File

@ -0,0 +1,27 @@
#pragma once
#include "table_object.h"
#include "group_object.h"
class GroupObjectTableObject: public TableObject
{
friend class GroupObject;
public:
GroupObjectTableObject(uint8_t* memoryReference);
void readProperty(PropertyID id, uint32_t start, uint32_t count, uint8_t* data);
uint16_t entryCount();
GroupObject& get(uint16_t asap);
GroupObject& nextUpdatedObject(bool& valid);
void groupObjects(GroupObject* objs, uint16_t size);
virtual uint8_t* save(uint8_t* buffer);
virtual uint8_t* restore(uint8_t* buffer);
protected:
virtual void beforeStateChange(LoadState& newState);
private:
bool initGroupObjects();
uint16_t* _tableData = 0;
GroupObject* _groupObjects;
uint16_t _groupObjectCount;
};

62
interface_object.h Normal file
View File

@ -0,0 +1,62 @@
#pragma once
#include <stddef.h>
#include "property_types.h"
#include "save_restore.h"
enum ObjectType
{
/** Device object. */
OT_DEVICE = 0,
/** Address table object. */
OT_ADDR_TABLE = 1,
/** Association table object. */
OT_ASSOC_TABLE = 2,
/** Application program object. */
OT_APPLICATION_PROG = 3,
/** Interface program object. */
OT_INTERFACE_PROG = 4,
/** KNX - Object Associationtable. */
OT_OJB_ASSOC_TABLE = 5,
/** Router Object */
OT_ROUTER = 6,
/** LTE Address Routing Table Object */
OT_LTE_ADDR_ROUTING_TABLE = 7,
/** cEMI Server Object */
OT_CEMI_SERVER = 8,
/** Group Object Table Object */
OT_GRP_OBJ_TABLE = 9,
/** Polling Master */
OT_POLLING_MASTER = 10,
/** KNXnet/IP Parameter Object */
OT_IP_PARAMETER = 11,
/** Reserved. Shall not be used. */
OT_RESERVED = 12,
/** File Server Object */
OT_FILE_SERVER = 13
};
class InterfaceObject: public SaveRestore
{
public:
virtual ~InterfaceObject() {}
virtual void readProperty(PropertyID id, uint32_t start, uint32_t count, uint8_t* data) = 0;
virtual void writeProperty(PropertyID id, uint8_t start, uint8_t* data, uint8_t count) = 0;
virtual uint8_t propertySize(PropertyID id) = 0;
protected:
};

298
ip_parameter_object.cpp Normal file
View File

@ -0,0 +1,298 @@
#include "ip_parameter_object.h"
#include "device_object.h"
#include "platform.h"
#include "bits.h"
//224.0.23.12
#define DEFAULT_MULTICAST_ADDR 0xE000170C
IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platform): _deviceObject(deviceObject),
_platform(platform)
{}
void IpParameterObject::readProperty(PropertyID propertyId, uint32_t start, uint32_t count, uint8_t* data)
{
switch (propertyId)
{
case PID_LOAD_STATE_CONTROL:
data[0] = _state;
break;
case PID_OBJECT_TYPE:
pushWord(OT_IP_PARAMETER, data);
break;
case PID_PROJECT_INSTALLATION_ID:
pushWord(_projectInstallationId, data);
break;
case PID_KNX_INDIVIDUAL_ADDRESS:
pushWord(_deviceObject.induvidualAddress(), data);
break;
case PID_IP_ASSIGNMENT_METHOD:
data[0] = _ipAssignmentMethod;
break;
case PID_IP_CAPABILITIES:
data[0] = _ipCapabilities;
break;
case PID_CURRENT_IP_ADDRESS:
pushInt(_platform.currentIpAddress(), data);
break;
case PID_CURRENT_SUBNET_MASK:
pushInt(_platform.currentSubnetMask(), data);
break;
case PID_CURRENT_DEFAULT_GATEWAY:
pushInt(_platform.currentDefaultGateway(), data);
break;
case PID_IP_ADDRESS:
pushInt(_ipAddress, data);
break;
case PID_SUBNET_MASK:
pushInt(_subnetMask, data);
break;
case PID_DEFAULT_GATEWAY:
pushInt(_defaultGateway, data);
break;
case PID_MAC_ADDRESS:
{
uint8_t macAddr[6];
_platform.macAddress(macAddr);
pushByteArray(macAddr, 6, data);
break;
}
case PID_SYSTEM_SETUP_MULTICAST_ADDRESS:
pushInt(DEFAULT_MULTICAST_ADDR, data);
break;
case PID_ROUTING_MULTICAST_ADDRESS:
pushInt(_multicastAddress, data);
break;
case PID_TTL:
data[0] = ttl();
break;
case PID_KNXNETIP_DEVICE_CAPABILITIES:
data[0] = 0x1;
break;
case PID_FRIENDLY_NAME:
for (uint8_t i = start; i < start + count; i++)
data[i-start] = _friendlyName[i-1];
break;
}
}
void IpParameterObject::writeProperty(PropertyID id, uint8_t start, uint8_t* data, uint8_t count)
{
switch (id)
{
case PID_LOAD_STATE_CONTROL:
loadEvent(data);
break;
case PID_PROJECT_INSTALLATION_ID:
_projectInstallationId = getWord(data);
break;
case PID_KNX_INDIVIDUAL_ADDRESS:
_deviceObject.induvidualAddress(getWord(data));
break;
case PID_IP_ASSIGNMENT_METHOD:
_ipAssignmentMethod = data[0];
break;
case PID_IP_ADDRESS:
_ipAddress = getInt(data);
break;
case PID_SUBNET_MASK:
_subnetMask = getInt(data);
break;
case PID_DEFAULT_GATEWAY:
_defaultGateway = getInt(data);
break;
case PID_ROUTING_MULTICAST_ADDRESS:
_multicastAddress = getInt(data);
break;
case PID_TTL:
_ttl = data[0];
break;
case PID_FRIENDLY_NAME:
for (uint8_t i = start; i < start + count; i++)
_friendlyName[i-1] = data[i - start];
break;
}
}
uint8_t IpParameterObject::propertySize(PropertyID id)
{
switch (id)
{
case PID_PROJECT_INSTALLATION_ID:
return 2;
case PID_KNX_INDIVIDUAL_ADDRESS:
return 2;
case PID_IP_ASSIGNMENT_METHOD:
return 1;
case PID_IP_ADDRESS:
return 4;
case PID_SUBNET_MASK:
return 4;
case PID_DEFAULT_GATEWAY:
return 4;
case PID_ROUTING_MULTICAST_ADDRESS:
return 4;
case PID_TTL:
return 1;
case PID_FRIENDLY_NAME:
return 1;
}
return 0;
}
uint8_t* IpParameterObject::save(uint8_t* buffer)
{
buffer = pushWord(_projectInstallationId, buffer);
buffer = pushByte(_ipAssignmentMethod, buffer);
buffer = pushByte(_ipCapabilities, buffer);
buffer = pushInt(_ipAddress, buffer);
buffer = pushInt(_subnetMask, buffer);
buffer = pushInt(_defaultGateway, buffer);
buffer = pushInt(_multicastAddress, buffer);
buffer = pushByte(_ttl, buffer);
buffer = pushByteArray((uint8_t*)_friendlyName, 30, buffer);
return buffer;
}
uint8_t* IpParameterObject::restore(uint8_t* buffer)
{
buffer = popWord(_projectInstallationId, buffer);
buffer = popByte(_ipAssignmentMethod, buffer);
buffer = popByte(_ipCapabilities, buffer);
buffer = popInt(_ipAddress, buffer);
buffer = popInt(_subnetMask, buffer);
buffer = popInt(_defaultGateway, buffer);
buffer = popInt(_multicastAddress, buffer);
buffer = popByte(_ttl, buffer);
buffer = popByteArray((uint8_t*)_friendlyName, 30, buffer);
return buffer;
}
uint32_t IpParameterObject::multicastAddress() const
{
if (_multicastAddress == 0)
return DEFAULT_MULTICAST_ADDR;
return _multicastAddress;
}
void IpParameterObject::loadEvent(uint8_t* data)
{
switch (_state)
{
case LS_UNLOADED:
loadEventUnloaded(data);
break;
case LS_LOADING:
loadEventLoading(data);
break;
case LS_LOADED:
loadEventLoaded(data);
break;
case LS_ERROR:
loadEventError(data);
break;
}
}
void IpParameterObject::loadState(LoadState newState)
{
if (newState == _state)
return;
//beforeStateChange(newState);
_state = newState;
}
void IpParameterObject::loadEventUnloaded(uint8_t* data)
{
uint8_t event = data[0];
switch (event)
{
case LE_NOOP:
case LE_LOAD_COMPLETED:
case LE_ADDITIONAL_LOAD_CONTROLS:
case LE_UNLOAD:
break;
case LE_START_LOADING:
loadState(LS_LOADING);
break;
default:
loadState(LS_ERROR);
_errorCode = E_GOT_UNDEF_LOAD_CMD;
}
}
void IpParameterObject::loadEventLoading(uint8_t* data)
{
uint8_t event = data[0];
switch (event)
{
case LE_NOOP:
case LE_START_LOADING:
break;
case LE_LOAD_COMPLETED:
loadState(LS_LOADED);
break;
case LE_UNLOAD:
loadState(LS_UNLOADED);
break;
case LE_ADDITIONAL_LOAD_CONTROLS:
additionalLoadControls(data);
break;
default:
loadState(LS_ERROR);
_errorCode = E_GOT_UNDEF_LOAD_CMD;
}
}
void IpParameterObject::loadEventLoaded(uint8_t* data)
{
uint8_t event = data[0];
switch (event)
{
case LE_NOOP:
case LE_LOAD_COMPLETED:
break;
case LE_START_LOADING:
loadState(LS_LOADING);
break;
case LE_UNLOAD:
loadState(LS_UNLOADED);
break;
case LE_ADDITIONAL_LOAD_CONTROLS:
loadState(LS_ERROR);
_errorCode = E_INVALID_OPCODE;
break;
default:
loadState(LS_ERROR);
_errorCode = E_GOT_UNDEF_LOAD_CMD;
}
}
void IpParameterObject::loadEventError(uint8_t* data)
{
uint8_t event = data[0];
switch (event)
{
case LE_NOOP:
case LE_LOAD_COMPLETED:
case LE_ADDITIONAL_LOAD_CONTROLS:
case LE_START_LOADING:
break;
case LE_UNLOAD:
loadState(LS_UNLOADED);
break;
default:
loadState(LS_ERROR);
_errorCode = E_GOT_UNDEF_LOAD_CMD;
}
}
void IpParameterObject::additionalLoadControls(uint8_t* data)
{
loadState(LS_ERROR);
_errorCode = E_INVALID_OPCODE;
return;
}

42
ip_parameter_object.h Normal file
View File

@ -0,0 +1,42 @@
#pragma once
#include "interface_object.h"
#include "device_object.h"
#include "platform.h"
class IpParameterObject: public InterfaceObject
{
public:
IpParameterObject(DeviceObject& deviceObject, Platform& platform);
void readProperty(PropertyID id, uint32_t start, uint32_t count, uint8_t* data);
void writeProperty(PropertyID id, uint8_t start, uint8_t* data, uint8_t count);
uint8_t propertySize(PropertyID id);
uint8_t* save(uint8_t* buffer);
uint8_t* restore(uint8_t* buffer);
uint32_t multicastAddress() const;
uint8_t ttl() const { return _ttl; }
private:
uint16_t _projectInstallationId = 0;
uint8_t _ipAssignmentMethod = 0;
uint8_t _ipCapabilities = 0;
uint32_t _ipAddress = 0;
uint32_t _subnetMask = 0;
uint32_t _defaultGateway = 0;
uint32_t _multicastAddress = 0;
uint8_t _ttl = 60;
char _friendlyName[30] = { 0 };
DeviceObject& _deviceObject;
Platform& _platform;
void loadEvent(uint8_t* data);
void loadEventUnloaded(uint8_t* data);
void loadEventLoading(uint8_t* data);
void loadEventLoaded(uint8_t* data);
void loadEventError(uint8_t* data);
void additionalLoadControls(uint8_t* data);
void loadState(LoadState newState);
LoadState _state = LS_UNLOADED;
ErrorCode _errorCode = E_NO_FAULT;
};

75
knx-esp.vcxitems Normal file
View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<ItemsProjectGuid>{83464ca3-e0d0-4486-82f4-f658f31ddc69}</ItemsProjectGuid>
</PropertyGroup>
<ItemDefinitionGroup>
<ClCompile>
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)</AdditionalIncludeDirectories>
</ClCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ProjectCapability Include="SourceItemsFromImports" />
</ItemGroup>
<ItemGroup>
<Text Include="$(MSBuildThisFileDirectory)readme.txt" />
<Text Include="$(MSBuildThisFileDirectory)library.properties" />
<Text Include="$(MSBuildThisFileDirectory)knx_esp.h" />
</ItemGroup>
<ItemGroup>
<!-- <ClInclude Include="$(MSBuildThisFileDirectory)knx_esp.h" /> -->
<ClInclude Include="$(MSBuildThisFileDirectory)address_table_object.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)apdu.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)application_layer.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)application_program_object.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)association_table_object.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)bau.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)bau57B0.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)bits.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)cemi_frame.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)datapoint_types.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)data_link_layer.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)device_object.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)esp_platform.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)group_object.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)group_object_table_object.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)interface_object.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)ip_parameter_object.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)knx_types.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)memory.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)network_layer.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)npdu.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)platform.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)property_types.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)save_restore.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)table_object.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)tpdu.h" />
<ClInclude Include="$(MSBuildThisFileDirectory)transport_layer.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)address_table_object.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)apdu.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)application_layer.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)application_program_object.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)association_table_object.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)bau.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)bau57B0.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)bits.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)cemi_frame.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)datapoint_types.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)data_link_layer.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)device_object.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)esp_platform.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)group_object.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)group_object_table_object.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)ip_parameter_object.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)memory.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)network_layer.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)npdu.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)table_object.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)tpdu.cpp" />
<ClCompile Include="$(MSBuildThisFileDirectory)transport_layer.cpp" />
</ItemGroup>
</Project>

171
knx-esp.vcxitems.filters Normal file
View File

@ -0,0 +1,171 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;s</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(MSBuildThisFileDirectory)address_table_object.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)apdu.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)application_layer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)application_program_object.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)association_table_object.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)bau.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)bau57B0.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)bits.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)cemi_frame.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)data_link_layer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)datapoint_types.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)device_object.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)esp_platform.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)group_object.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)group_object_table_object.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)ip_parameter_object.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)memory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)network_layer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)npdu.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)table_object.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)tpdu.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(MSBuildThisFileDirectory)transport_layer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Text Include="$(MSBuildThisFileDirectory)readme.txt" />
<Text Include="$(MSBuildThisFileDirectory)library.properties" />
<Text Include="$(MSBuildThisFileDirectory)knx_esp.h">
<Filter>Header Files</Filter>
</Text>
</ItemGroup>
<ItemGroup>
<ClInclude Include="$(MSBuildThisFileDirectory)address_table_object.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)apdu.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)application_layer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)application_program_object.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)association_table_object.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)bau.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)bau57B0.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)bits.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)cemi_frame.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)data_link_layer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)datapoint_types.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)device_object.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)esp_platform.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)group_object.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)group_object_table_object.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)interface_object.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)ip_parameter_object.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)knx_types.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)memory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)network_layer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)npdu.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)platform.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)property_types.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)save_restore.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)table_object.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)tpdu.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="$(MSBuildThisFileDirectory)transport_layer.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

19
knx_esp.h Normal file
View File

@ -0,0 +1,19 @@
/*
Name: knx_esp.h
Created: 01.03.2018 21:14:55
Author: tkunze
Editor: http://www.visualmicro.com
*/
#ifndef _knx_esp_h
#define _knx_esp_h
#if defined(ARDUINO) && ARDUINO >= 100
#include "arduino.h"
#else
#include "WProgram.h"
#endif
#endif

103
knx_types.h Normal file
View File

@ -0,0 +1,103 @@
#pragma once
enum FrameFormat
{
ExtendedFrame = 0,
StandardFrame = 0x80
};
enum Priority
{
LowPriority = 0xC,
NormalPriority = 0x4,
UrgentPriority = 0x8,
SystemPriority = 0x0
};
enum AckType
{
AckDontCare = 0,
AckRequested = 0x2,
};
enum AddressType
{
InduvidualAddress = 0,
GroupAddress = 0x80,
};
enum MessageCode
{
L_data_ind = 0x29,
};
enum Repetition
{
NoRepitiion = 0,
WasRepeated = 0,
RepititionAllowed = 0x20,
WasNotRepeated = 0x20,
};
enum SystemBroadcast
{
SysBroadcast = 0,
Broadcast = 0x10,
};
enum Confirm
{
ConfirmNoError = 0,
ConfirmError = 1,
};
enum HopCountType
{
UnlimitedRouting,
NetworkLayerParameter
};
enum TpduType
{
DataBroadcast,
DataGroup,
DataInduvidual,
DataConnected,
Connect,
Disconnect,
Ack,
Nack,
};
enum ApduType
{
GroupValueRead = 0x000,
GroupValueResponse = 0x040,
GroupValueWrite = 0x080,
IndividualAddressWrite = 0x0c0,
IndividualAddressRead = 0x100,
IndividualAddressResponse = 0x140,
MemoryRead = 0x200,
MemoryResponse = 0x240,
MemoryWrite = 0x280,
UserMemoryRead = 0x2C0,
UserMemoryResponse = 0x2C1,
UserMemoryWrite = 0x2C2,
UserManufacturerInfoRead = 0x2C5,
UserManufacturerInfoResponse = 0x2C6,
DeviceDescriptorRead = 0x300,
DeviceDescriptorResponse = 0x340,
Restart = 0x380,
AuthorizeRequest = 0x3d1,
AuthorizeResponse = 0x3d2,
KeyWrite = 0x3d3,
KeyResponse = 0x3d4,
PropertyValueRead = 0x3d5,
PropertyValueResponse = 0x3d6,
PropertyValueWrite = 0x3d7,
PropertyDescriptionRead = 0x3d8,
PropertyDescriptionResponse = 0x3d9,
IndividualAddressSerialNumberRead = 0x3dc,
IndividualAddressSerialNumberResponse = 0x3dd,
IndividualAddressSerialNumberWrite = 0x3de,
};

9
library.properties Normal file
View File

@ -0,0 +1,9 @@
name=knx_esp
version=1.0.0
author=tkunze
maintainer=tkunze
sentence=knx_esp Library
paragraph=
category=Uncategorized
url=https://github/knx_esp
architectures=*

47
memory.cpp Normal file
View File

@ -0,0 +1,47 @@
#include "memory.h"
Memory::Memory(Platform & platform): _platform(platform)
{
}
void Memory::memoryModified()
{
_modified = true;
}
bool Memory::isMemoryModified()
{
return _modified;
}
void Memory::readMemory()
{
//_data = _platform.getEepromBuffer(512);
//uint8_t* buffer = _data;
//int size = _saveCount;
//for (int i = 0; i < size; i++)
//{
// buffer = _saveRestores[i]->restore(buffer);
//}
}
void Memory::writeMemory()
{
//uint8_t* buffer = _data;
//int size = _saveCount;
//for (int i = 0; i < size; i++)
//{
// buffer = _saveRestores[i]->save(buffer);
//}
//_platform.commitToEeprom();
//_modified = false;
}
void Memory::addSaveRestore(SaveRestore * obj)
{
if (_saveCount >= MAXSAVE - 1)
return;
_saveRestores[_saveCount] = obj;
_saveCount += 1;
}

24
memory.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include <stdint.h>
#include "save_restore.h"
#include "platform.h"
#define MAXSAVE 10
class Memory
{
public:
Memory(Platform& platform);
void memoryModified();
bool isMemoryModified();
void readMemory();
void writeMemory();
void addSaveRestore(SaveRestore* obj);
private:
Platform& _platform;
bool _modified = false;
SaveRestore* _saveRestores[MAXSAVE];
int _saveCount = 0;
uint8_t* _data = 0;
};

126
network_layer.cpp Normal file
View File

@ -0,0 +1,126 @@
#include "network_layer.h"
#include "tpdu.h"
#include "cemi_frame.h"
#include "data_link_layer.h"
NetworkLayer::NetworkLayer(TransportLayer& layer): _transportLayer(layer)
{
}
void NetworkLayer::dataLinkLayer(DataLinkLayer& layer)
{
_dataLinkLayer = &layer;
}
uint8_t NetworkLayer::hopCount() const
{
return _hopCount;
}
void NetworkLayer::hopCount(uint8_t value)
{
_hopCount = value & 0x7;
}
void NetworkLayer::dataIndication(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source)
{
HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter;
if (addrType == InduvidualAddress)
{
//if (npdu.octetCount() > 0)
//{
// print.print("<- NL ");
// npdu.frame().apdu().printPDU();
//}
_transportLayer.dataIndividualIndication(destination, hopType, priority, source, npdu.tpdu());
return;
}
// group-address type
if (destination != 0)
{
_transportLayer.dataGroupIndication(destination, hopType, priority, source, npdu.tpdu());
return;
}
// destination == 0
_transportLayer.dataBroadcastIndication(hopType, priority, source, npdu.tpdu());
}
void NetworkLayer::dataConfirm(AckType ack, AddressType addressType, uint16_t destination, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status)
{
HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter;
if (addressType == InduvidualAddress)
{
_transportLayer.dataIndividualConfirm(ack, destination, hopType, priority, npdu.tpdu(), status);
return;
}
// group-address type
if (destination != 0)
{
_transportLayer.dataGroupConfirm(ack, source, destination, hopType, priority, npdu.tpdu(), status);
return;
}
// destination == 0
_transportLayer.dataBroadcastConfirm(ack, hopType, priority, npdu.tpdu(), status);
}
void NetworkLayer::systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source)
{
HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter;
_transportLayer.dataBroadcastIndication(hopType, priority, source, npdu.tpdu());
}
void NetworkLayer::systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status)
{
HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter;
_transportLayer.dataBroadcastConfirm(ack, hopType, priority, npdu.tpdu(), status);
}
void NetworkLayer::dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu)
{
//if (tpdu.apdu().length() > 0)
//{
// print.print("-> NL ");
// tpdu.apdu().printPDU();
//}
sendDataRequest(tpdu, hopType, ack, destination, priority, InduvidualAddress);
}
void NetworkLayer::sendDataRequest(TPDU &tpdu, HopCountType hopType, AckType ack, uint16_t destination, Priority priority, AddressType addrType)
{
NPDU& npdu = tpdu.frame().npdu();
if (hopType == UnlimitedRouting)
npdu.hopCount(7);
else
npdu.hopCount(_hopCount);
FrameFormat frameFormat = npdu.octetCount() > 15 ? ExtendedFrame : StandardFrame;
_dataLinkLayer->dataRequest(ack, addrType, destination, frameFormat, priority, npdu);
}
void NetworkLayer::dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu)
{
sendDataRequest(tpdu, hopType, ack, destination, priority, GroupAddress);
}
void NetworkLayer::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu)
{
sendDataRequest(tpdu, hopType, ack, 0, priority, GroupAddress);
}
void NetworkLayer::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu)
{
NPDU& npdu = tpdu.frame().npdu();
if (hopType == UnlimitedRouting)
npdu.hopCount(7);
else
npdu.hopCount(_hopCount);
FrameFormat frameFormat = npdu.octetCount() > 15 ? ExtendedFrame : StandardFrame;
_dataLinkLayer->systemBroadcastRequest(ack, frameFormat, priority, npdu);
}

38
network_layer.h Normal file
View File

@ -0,0 +1,38 @@
#pragma once
#include <stdint.h>
#include "knx_types.h"
#include "npdu.h"
#include "transport_layer.h"
class DataLinkLayer;
class NetworkLayer
{
public:
NetworkLayer(TransportLayer& layer);
void dataLinkLayer(DataLinkLayer& layer);
uint8_t hopCount() const;
void hopCount(uint8_t value);
// from data link layer
void dataIndication(AckType ack, AddressType addType, uint16_t destination, FrameFormat format, NPDU& npdu,
Priority priority, uint16_t source);
void dataConfirm(AckType ack, AddressType addressType, uint16_t destination, FrameFormat format, Priority priority,
uint16_t source, NPDU& npdu, bool status);
void systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu,
Priority priority, uint16_t source);
void systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status);
// from transport layer
void dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu);
void dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu);
void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu);
void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu);
private:
void sendDataRequest(TPDU &tpdu, HopCountType hopType, AckType ack, uint16_t destination, Priority priority, AddressType addrType);
uint8_t _hopCount = 6;
DataLinkLayer* _dataLinkLayer;
TransportLayer& _transportLayer;
};

44
npdu.cpp Normal file
View File

@ -0,0 +1,44 @@
#include "npdu.h"
#include "cemi_frame.h"
#include <string.h>
NPDU::NPDU(uint8_t* data, CemiFrame& frame): _data(data), _frame(frame)
{
}
uint8_t NPDU::octetCount() const
{
return _data[0];
}
void NPDU::octetCount(uint8_t value)
{
_data[0] = value;
}
uint8_t NPDU::length() const
{
return _data[0] + 2; // +1 for length field, +1 for TCPI
}
uint8_t NPDU::hopCount() const
{
return _frame.hopCount();
}
void NPDU::hopCount(uint8_t value)
{
_frame.hopCount(value);
}
CemiFrame& NPDU::frame()
{
return _frame;
}
TPDU& NPDU::tpdu()
{
return _frame.tpdu();
}

24
npdu.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include <stdint.h>
class CemiFrame;
class TPDU;
class NPDU
{
friend class CemiFrame;
public:
NPDU(uint8_t* data, CemiFrame& frame);
uint8_t octetCount() const;
void octetCount(uint8_t value);
uint8_t length() const;
uint8_t hopCount() const;
void hopCount(uint8_t value);
CemiFrame& frame();
TPDU& tpdu();
private:
uint8_t* _data;
CemiFrame& _frame;
};

26
platform.h Normal file
View File

@ -0,0 +1,26 @@
#pragma once
#include <stdint.h>
#include "save_restore.h"
class Platform
{
public:
virtual uint32_t currentIpAddress() = 0;
virtual uint32_t currentSubnetMask() = 0;
virtual uint32_t currentDefaultGateway() = 0;
virtual void macAddress(uint8_t* data) = 0;
virtual uint32_t millis() = 0;
virtual void restart() = 0;
virtual void fatalError() = 0;
virtual void mdelay(uint32_t millis) = 0;
virtual void setupMultiCast(uint32_t addr, uint16_t port) = 0;
virtual void closeMultiCast() = 0;
virtual bool sendBytes(uint8_t* buffer, uint16_t len) = 0;
virtual int readBytes(uint8_t* buffer, uint16_t maxLen) = 0;
virtual uint8_t* getEepromBuffer(uint16_t size) = 0;
virtual void commitToEeprom() = 0;
};

166
property_types.h Normal file
View File

@ -0,0 +1,166 @@
/*
* property_types.h - BCU 2 property types of EIB objects.
*
* Copyright (c) 2014 Stefan Taferner <stefan.taferner@gmx.at>
*
* 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.
*/
#pragma once
enum PropertyDataType
{
PDT_CONTROL = 0x00, //!< length: 1 read, 10 write
PDT_CHAR = 0x01, //!< length: 1
PDT_UNSIGNED_CHAR = 0x02, //!< length: 1
PDT_INT = 0x03, //!< length: 2
PDT_UNSIGNED_INT = 0x04, //!< length: 2
PDT_KNX_FLOAT = 0x05, //!< length: 2
PDT_DATE = 0x06, //!< length: 3
PDT_TIME = 0x07, //!< length: 3
PDT_LONG = 0x08, //!< length: 4
PDT_UNSIGNED_LONG = 0x09, //!< length: 4
PDT_FLOAT = 0x0a, //!< length: 4
PDT_DOUBLE = 0x0b, //!< length: 8
PDT_CHAR_BLOCK = 0x0c, //!< length: 10
PDT_POLL_GROUP_SETTING = 0x0d, //!< length: 3
PDT_SHORT_CHAR_BLOCK = 0x0e, //!< length: 5
PDT_DATE_TIME = 0x0f, //!< length: 8
PDT_VARIABLE_LENGTH = 0x10,
PDT_GENERIC_01 = 0x11, //!< length: 1
PDT_GENERIC_02 = 0x12, //!< length: 2
PDT_GENERIC_03 = 0x13, //!< length: 3
PDT_GENERIC_04 = 0x14, //!< length: 4
PDT_GENERIC_05 = 0x15, //!< length: 5
PDT_GENERIC_06 = 0x16, //!< length: 6
PDT_GENERIC_07 = 0x17, //!< length: 7
PDT_GENERIC_08 = 0x18, //!< length: 8
PDT_GENERIC_09 = 0x19, //!< length: 9
PDT_GENERIC_10 = 0x1a, //!< length: 10
PDT_GENERIC_11 = 0x1b, //!< length: 11
PDT_GENERIC_12 = 0x1c, //!< length: 12
PDT_GENERIC_13 = 0x1d, //!< length: 13
PDT_GENERIC_14 = 0x1e, //!< length: 14
PDT_GENERIC_15 = 0x1f, //!< length: 15
PDT_GENERIC_16 = 0x20, //!< length: 16
PDT_GENERIC_17 = 0x21, //!< length: 17
PDT_GENERIC_18 = 0x22, //!< length: 18
PDT_GENERIC_19 = 0x23, //!< length: 19
PDT_GENERIC_20 = 0x24, //!< length: 20
PDT_UTF8 = 0x2f, //!< length: 3
PDT_VERSION = 0x30, //!< length: 3
PDT_ALARM_INFO = 0x31, //!< length: 3
PDT_BINARY_INFORMATION = 0x32, //!< length: 3
PDT_BITSET8 = 0x33, //!< length: 3
PDT_BITSET16 = 0x34, //!< length: 3
PDT_ENUM8 = 0x35, //!< length: 3
PDT_SCALING = 0x36, //!< length: 3
PDT_NE_VL = 0x3c, //!< length: 3
PDT_NE_FL = 0x3d, //!< length: 3
PDT_FUNCTION = 0x3e, //!< length: 3
PDT_ESCAPE = 0x3f, //!< length: 3
};
enum PropertyID
{
/** Interface Object Type independent Properties */
PID_OBJECT_TYPE = 1,
PID_LOAD_STATE_CONTROL = 5,
PID_RUN_STATE_CONTROL = 6,
PID_TABLE_REFERENCE = 7,
PID_SERVICE_CONTROL = 8,
PID_FIRMWARE_REVISION = 9,
PID_SERIAL_NUMBER = 11,
PID_MANUFACTURER_ID = 12,
PID_PROG_VERSION = 13,
PID_DEVICE_CONTROL = 14,
PID_ORDER_INFO = 15,
PID_PEI_TYPE = 16,
PID_PORT_CONFIGURATION = 17,
PID_VERSION = 25,
PID_MCB_TABLE = 27,
PID_ERROR_CODE = 28,
/** Properties in the Device Object */
PID_ROUTING_COUNT = 51,
PID_PROG_MODE = 54,
PID_MAX_APDU_LENGTH = 56,
PID_SUBNET_ADDR = 57,
PID_DEVICE_ADDR = 58,
PID_IO_LIST = 71,
PID_HARDWARE_TYPE = 78,
PID_DEVICE_DESCRIPTOR = 83,
/** KNXnet/IP Parameter Object */
PID_PROJECT_INSTALLATION_ID = 51,
PID_KNX_INDIVIDUAL_ADDRESS = 52,
PID_ADDITIONAL_INDIVIDUAL_ADDRESSES = 53,
PID_CURRENT_IP_ASSIGNMENT_METHOD = 54,
PID_IP_ASSIGNMENT_METHOD = 55,
PID_IP_CAPABILITIES = 56,
PID_CURRENT_IP_ADDRESS = 57,
PID_CURRENT_SUBNET_MASK = 58,
PID_CURRENT_DEFAULT_GATEWAY = 59,
PID_IP_ADDRESS = 60,
PID_SUBNET_MASK = 61,
PID_DEFAULT_GATEWAY = 62,
PID_DHCP_BOOTP_SERVER = 63,
PID_MAC_ADDRESS = 64,
PID_SYSTEM_SETUP_MULTICAST_ADDRESS = 65,
PID_ROUTING_MULTICAST_ADDRESS = 66,
PID_TTL = 67,
PID_KNXNETIP_DEVICE_CAPABILITIES = 68,
PID_KNXNETIP_DEVICE_STATE = 69,
PID_KNXNETIP_ROUTING_CAPABILITIES = 70,
PID_PRIORITY_FIFO_ENABLED = 71,
PID_QUEUE_OVERFLOW_TO_IP = 72,
PID_QUEUE_OVERFLOW_TO_KNX = 73,
PID_MSG_TRANSMIT_TO_IP = 74,
PID_MSG_TRANSMIT_TO_KNX = 75,
PID_FRIENDLY_NAME = 76,
PID_ROUTING_BUSY_WAIT_TIME = 78,
};
enum LoadState
{
LS_UNLOADED = 0,
LS_LOADED = 1,
LS_LOADING = 2,
LS_ERROR = 3,
LS_UNLOADING = 4,
LS_LOADCOMPLETING = 5
};
enum LoadEvents
{
LE_NOOP = 0,
LE_START_LOADING = 1,
LE_LOAD_COMPLETED = 2,
LE_ADDITIONAL_LOAD_CONTROLS = 3,
LE_UNLOAD = 4
};
// 20.011 DPT_ErrorClass_System
enum ErrorCode
{
E_NO_FAULT = 0,
E_GENERAL_DEVICE_FAULT = 1,
E_COMMUNICATION_FAULT = 2,
E_CONFIGURATION_FAULT = 3,
E_HARDWARE_FAULT = 4,
E_SOFTWARE_FAULT = 5,
E_INSUFFICIENT_NON_VOLATILE_MEMORY = 6,
E_INSUFFICIENT_VOLATILE_MEMORY = 7,
E_GOT_MEM_ALLOC_ZERO = 8,
E_CRC_ERROR = 9,
E_WATCHDOG_RESET = 10,
E_INVALID_OPCODE = 11,
E_GENERAL_PROTECTION_FAULT = 12,
E_MAX_TABLE_LENGTH_EXEEDED = 13,
E_GOT_UNDEF_LOAD_CMD = 14,
E_GAT_NOT_SORTED = 15,
E_INVALID_CONNECTION_NUMBER = 16,
E_INVALID_GO_NUMBER = 17,
E_GO_TYPE_TOO_BIG = 18
};

19
readme.txt Normal file
View File

@ -0,0 +1,19 @@
Arduino Compatible Cross Platform C++ Library Project : For more information see http://www.visualmicro.com
This project works exactly the same way as an Arduino library.
Add this project to any solution that contains an Arduino project and #include <headers.h> in code as you would any normal Arduino library headers.
To enable intellisense and to support live build discovery outside of the "standard" Arduino library locations, ensure that the library is added as a shared project reference to the master Arduino project. To do this, right click the master project "References" node and then click "Add Reference". A window will open and the library will appear on the "Shared Projects" tab. Click the checkbox next to the library name to add the reference. If this library is moved the shared referencemust be removed and re-added.
VS2017 has a bug, workround: After moving existing source code within a "library or shared project", close and re-open the solution.
Visual Studio will display intellisense for libraries based on the platform/board that has been specified for the currently active "Startup Project" of the current solution.
IMPORTANT: The arduino.cc Library Rules must be followed when adding code or restructing libraries.
blog: http://www.visualmicro.com/post/2017/01/16/Arduino-Cross-Platform-Library-Development.aspx

10
save_restore.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#include <stdint.h>
class SaveRestore
{
public:
virtual uint8_t* save(uint8_t* buffer) = 0;
virtual uint8_t* restore(uint8_t* buffer) = 0;
};

257
table_object.cpp Normal file
View File

@ -0,0 +1,257 @@
#include <stdlib.h>
#include <string.h>
#include "table_object.h"
#include "bits.h"
TableObject::TableObject(uint8_t* memoryReference): _memoryReference(memoryReference)
{
}
void TableObject::readProperty(PropertyID id, uint32_t start, uint32_t count, uint8_t* data)
{
switch (id)
{
case PID_LOAD_STATE_CONTROL:
data[0] = _state;
break;
case PID_TABLE_REFERENCE:
if (_state == LS_UNLOADED)
pushInt(0, data);
else
pushInt(tableReference(), data);
break;
case PID_ERROR_CODE:
data[0] = _errorCode;
break;
}
}
void TableObject::writeProperty(PropertyID id, uint8_t start, uint8_t* data, uint8_t count)
{
switch (id)
{
case PID_LOAD_STATE_CONTROL:
loadEvent(data);
break;
//case PID_MCB_TABLE:
// TODO
// break;
}
}
uint8_t TableObject::propertySize(PropertyID id)
{
switch (id)
{
case PID_LOAD_STATE_CONTROL:
return 10;
//case PID_MCB_TABLE:
// TODO
// break;
}
return 0;
}
TableObject::~TableObject()
{
if (_data != 0)
free(_data);
}
LoadState TableObject::loadState()
{
return _state;
}
void TableObject::loadState(LoadState newState)
{
if (newState == _state)
return;
beforeStateChange(newState);
_state = newState;
}
uint8_t* TableObject::save(uint8_t* buffer)
{
buffer = pushByte(_state, buffer);
buffer = pushByte(_errorCode, buffer);
buffer = pushInt(_size, buffer);
buffer = pushByteArray(_data, _size, buffer);
return buffer;
}
uint8_t* TableObject::restore(uint8_t* buffer)
{
uint8_t state = 0;
uint8_t errorCode = 0;
buffer = popByte(state, buffer);
buffer = popByte(errorCode, buffer);
_state = (LoadState)state;
_errorCode = (ErrorCode)errorCode;
buffer = popInt(_size, buffer);
if (_data)
free(_data);
_data = (uint8_t*) malloc(_size);
buffer = popByteArray(_data, _size, buffer);
return buffer;
}
uint32_t TableObject::tableReference()
{
return (uint32_t)(_data - _memoryReference);
}
bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte)
{
if (_data)
{
free(_data);
_size = 0;
}
_data = (uint8_t*)malloc(size);
if (!_data)
return false;
_size = size;
if (doFill)
memset(_data, fillByte, size);
return true;
}
void TableObject::loadEvent(uint8_t* data)
{
switch (_state)
{
case LS_UNLOADED:
loadEventUnloaded(data);
break;
case LS_LOADING:
loadEventLoading(data);
break;
case LS_LOADED:
loadEventLoaded(data);
break;
case LS_ERROR:
loadEventError(data);
break;
}
}
void TableObject::loadEventUnloaded(uint8_t* data)
{
uint8_t event = data[0];
switch (event)
{
case LE_NOOP:
case LE_LOAD_COMPLETED:
case LE_ADDITIONAL_LOAD_CONTROLS:
case LE_UNLOAD:
break;
case LE_START_LOADING:
loadState(LS_LOADING);
break;
default:
loadState(LS_ERROR);
_errorCode = E_GOT_UNDEF_LOAD_CMD;
}
}
void TableObject::loadEventLoading(uint8_t* data)
{
uint8_t event = data[0];
switch (event)
{
case LE_NOOP:
case LE_START_LOADING:
break;
case LE_LOAD_COMPLETED:
loadState(LS_LOADED);
break;
case LE_UNLOAD:
loadState(LS_UNLOADED);
break;
case LE_ADDITIONAL_LOAD_CONTROLS:
additionalLoadControls(data);
break;
default:
loadState(LS_ERROR);
_errorCode = E_GOT_UNDEF_LOAD_CMD;
}
}
void TableObject::loadEventLoaded(uint8_t* data)
{
uint8_t event = data[0];
switch (event)
{
case LE_NOOP:
case LE_LOAD_COMPLETED:
break;
case LE_START_LOADING:
loadState(LS_LOADING);
break;
case LE_UNLOAD:
loadState(LS_UNLOADED);
break;
case LE_ADDITIONAL_LOAD_CONTROLS:
loadState(LS_ERROR);
_errorCode = E_INVALID_OPCODE;
break;
default:
loadState(LS_ERROR);
_errorCode = E_GOT_UNDEF_LOAD_CMD;
}
}
void TableObject::loadEventError(uint8_t* data)
{
uint8_t event = data[0];
switch (event)
{
case LE_NOOP:
case LE_LOAD_COMPLETED:
case LE_ADDITIONAL_LOAD_CONTROLS:
case LE_START_LOADING:
break;
case LE_UNLOAD:
loadState(LS_UNLOADED);
break;
default:
loadState(LS_ERROR);
_errorCode = E_GOT_UNDEF_LOAD_CMD;
}
}
void TableObject::additionalLoadControls(uint8_t* data)
{
if (data[1] != 0x0B) // Data Relative Allocation
{
loadState(LS_ERROR);
_errorCode = E_INVALID_OPCODE;
return;
}
size_t size = ((data[2] << 24) | (data[3] << 16) | (data[4] << 8) | data[5]);
bool doFill = data[6] == 0x1;
uint8_t fillByte = data[7];
if (!allocTable(size, doFill, fillByte))
{
loadState(LS_ERROR);
_errorCode = E_MAX_TABLE_LENGTH_EXEEDED;
}
}

33
table_object.h Normal file
View File

@ -0,0 +1,33 @@
#pragma once
#include "interface_object.h"
class TableObject: public InterfaceObject
{
public:
TableObject(uint8_t* memoryReference);
virtual void readProperty(PropertyID id, uint32_t start, uint32_t count, uint8_t* data);
virtual void writeProperty(PropertyID id, uint8_t start, uint8_t* data, uint8_t count);
virtual uint8_t propertySize(PropertyID id);
virtual ~TableObject();
LoadState loadState();
virtual uint8_t* save(uint8_t* buffer);
virtual uint8_t* restore(uint8_t* buffer);
protected:
virtual void beforeStateChange(LoadState& newState) {}
uint8_t* _data = 0;
uint32_t _size = 0;
ErrorCode _errorCode = E_NO_FAULT;
private:
uint32_t tableReference();
bool allocTable(uint32_t size, bool doFill, uint8_t fillByte);
void loadEvent(uint8_t* data);
void loadEventUnloaded(uint8_t* data);
void loadEventLoading(uint8_t* data);
void loadEventLoaded(uint8_t* data);
void loadEventError(uint8_t* data);
void additionalLoadControls(uint8_t* data);
void loadState(LoadState newState);
LoadState _state = LS_UNLOADED;
uint8_t* _memoryReference;
};

127
tpdu.cpp Normal file
View File

@ -0,0 +1,127 @@
#include "tpdu.h"
#include "cemi_frame.h"
TPDU::TPDU(uint8_t* data, CemiFrame& frame): _data(data), _frame(frame)
{
}
TpduType TPDU::type() const
{
if (control())
{
if (numbered())
{
if ((_data[0] & 1) == 0)
return Ack;
else
return Nack;
}
else if ((_data[0] & 1) == 0)
return Connect;
else
return Disconnect;
}
else
{
if (_frame.addressType() == GroupAddress)
{
if (_frame.destinationAddress() == 0)
return DataBroadcast;
else
return DataGroup;
}
else if (numbered())
return DataConnected;
else
return DataInduvidual;
}
}
void TPDU::type(TpduType type)
{
switch (type)
{
case DataBroadcast:
case DataGroup:
case DataInduvidual:
_data[0] &= 0x3;
break;
case DataConnected:
_data[0] &= 0xC3;
_data[0] |= 0x40;
break;
case Connect:
_data[0] = 0x80;
break;
case Disconnect:
_data[0] = 0x81;
break;
case Ack:
_data[0] &= ~0xC3;
_data[0] |= 0xC2;
break;
case Nack:
_data[0] |= 0xC3;
break;
}
}
bool TPDU::numbered() const
{
return (_data[0] & 0x40) > 0;
}
void TPDU::numbered(bool value)
{
if (value)
_data[0] |= 0x40;
else
_data[0] &= ~0x40;
}
bool TPDU::control() const
{
return (_data[0] & 0x80) > 0;
}
void TPDU::control(bool value)
{
if (value)
_data[0] |= 0x80;
else
_data[0] &= ~0x80;
}
uint8_t TPDU::sequenceNumber() const
{
return ((_data[0] >> 2) & 0xF);
}
void TPDU::sequenceNumber(uint8_t value)
{
_data[0] &= ~(0xF << 2);
_data[0] |= ((value & 0xF) << 2);
}
APDU& TPDU::apdu()
{
return _frame.apdu();
}
CemiFrame& TPDU::frame()
{
return _frame;
}
void TPDU::printPDU()
{
/* print.print("TPDU: ");
print.print(type(), HEX, 2);
print.print(" ");
for (uint8_t i = 0; i < apdu().length() + 1; ++i)
{
if (i) print.print(" ");
print.print(_data[i], HEX, 2);
}
print.println()*/;
}

32
tpdu.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
#include "stdint.h"
#include "knx_types.h"
class CemiFrame;
class APDU;
class TPDU
{
friend class CemiFrame;
public:
TPDU(uint8_t* data, CemiFrame& frame);
TpduType type() const;
void type(TpduType type);
bool numbered() const;
void numbered(bool value);
bool control() const;
void control(bool value);
uint8_t sequenceNumber() const;
void sequenceNumber(uint8_t value);
APDU& apdu();
CemiFrame& frame();
void printPDU();
private:
uint8_t* _data;
CemiFrame& _frame;
};

711
transport_layer.cpp Normal file
View File

@ -0,0 +1,711 @@
#include "transport_layer.h"
#include "apdu.h"
#include "cemi_frame.h"
#include "network_layer.h"
#include "application_layer.h"
#include "platform.h"
#include <stdio.h>
TransportLayer::TransportLayer(ApplicationLayer& layer, AddressTableObject& gat, Platform& platform): _savedFrame(0),
_savedFrameConnecting(0), _applicationLayer(layer), _groupAddressTable(gat), _platform(platform)
{
_currentState = Closed;
}
void TransportLayer::networkLayer(NetworkLayer& layer)
{
_networkLayer = &layer;
}
void TransportLayer::dataIndividualIndication(uint16_t destination, HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu)
{
//if (tpdu.apdu().length() > 0)
//{
// print.print("<- TL ");
// tpdu.printPDU();
// print.print("<- TL ");
// tpdu.apdu().printPDU();
//}
uint8_t sequenceNo = tpdu.sequenceNumber();
switch (tpdu.type())
{
case DataInduvidual:
_applicationLayer.dataIndividualIndication(hopType, priority, source, tpdu.apdu());
return;
case DataConnected:
if (source == _connectionAddress)
{
if (sequenceNo == _seqNoRecv)
{
//E4
switch (_currentState)
{
case Closed:
//A0 nothing
break;
case OpenIdle:
case OpenWait:
A2(source, priority, tpdu.apdu());
break;
case Connecting:
_currentState = Closed;
A6(destination);
break;
}
}
else if(sequenceNo == ((_seqNoRecv -1) & 0xF))
{
//E5
switch (_currentState)
{
case Closed:
//A0
break;
case OpenIdle:
case OpenWait:
case Connecting:
A3(source, priority, tpdu);
break;
}
}
else
{
//E6
switch (_currentState)
{
case Closed:
//A0
break;
case OpenIdle:
case OpenWait:
A4(source, priority, tpdu);
break;
case Connecting:
A6(destination);
break;
}
}
}
else
{
//E7
switch (_currentState)
{
case Closed:
case OpenIdle:
case OpenWait:
//A0
break;
case Connecting:
A10(source);
break;
}
}
break;
case Connect:
if (source == _connectionAddress)
{
//E0
switch (_currentState)
{
case Closed:
_currentState = OpenIdle;
A1(source);
break;
case OpenWait:
case OpenIdle:
case Connecting:
//A0: do nothing
break;
}
}
else
{
//E1
switch (_currentState)
{
case Closed:
_currentState = OpenIdle;
A1(source);
break;
case OpenIdle:
case OpenWait:
case Connecting:
A10(source);
break;
}
}
break;
case Disconnect:
if (source == _connectionAddress)
{
//E2
switch (_currentState)
{
case Closed:
//A0 do nothing
break;
case OpenIdle:
case OpenWait:
case Connecting:
_currentState = Closed;
A5(source);
break;
default:
break;
}
}
else
{
//E3
//A0: do nothing
}
break;
case Ack:
if (source == _connectionAddress)
{
if (sequenceNo == _seqNoSend)
{
//E8
switch (_currentState)
{
case Closed:
case OpenIdle:
//A0
break;
case OpenWait:
_currentState = OpenIdle;
A8();
break;
case Connecting:
_currentState = Closed;
A6(source);
break;
}
}
else
{
//E9
switch (_currentState)
{
case Closed:
case OpenIdle:
//A0
break;
case OpenWait:
case Connecting:
_currentState = Closed;
A6(source);
break;
}
}
}
else
{
//E10
switch (_currentState)
{
case Connecting:
A10(source);
break;
}
}
break;
case Nack:
if (source == _connectionAddress)
{
if (sequenceNo != _seqNoSend)
{
//E11
switch (_currentState)
{
case Closed:
case OpenIdle:
case OpenWait:
//A0
break;
case Connecting:
_currentState = Closed;
A6(source);
break;
}
}
else
{
if (_repCount < _maxRepCount)
{
//E12
switch (_currentState)
{
case Closed:
//A0
break;
case Connecting:
case OpenIdle:
_currentState = Closed;
A6(source);
break;
case OpenWait:
A9();
break;
}
}
else
{
//E13
switch (_currentState)
{
case Closed:
//A0
break;
case OpenIdle:
case OpenWait:
case Connecting:
_currentState = Closed;
A6(source);
break;
}
}
}
}
else
{
//E14
switch (_currentState)
{
case Closed:
case OpenIdle:
case OpenWait:
//A0
break;
case Connecting:
A10(source);
break;
default:
break;
}
}
break;
default:
break;
}
}
void TransportLayer::dataIndividualConfirm(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu, bool status)
{
TpduType type = tpdu.type();
switch (type)
{
case DataInduvidual:
_applicationLayer.dataIndividualConfirm(ack, hopType, priority, destination, tpdu.apdu(), status);
break;
case DataConnected:
//E22
//A0: do nothing
break;
case Connect:
if (status)
{
//E19
switch (_currentState)
{
case Closed:
case OpenIdle:
case OpenWait:
//A0: do nothing
break;
case Connecting:
_currentState = OpenIdle;
A13(destination);
break;
}
}
else
{
//E20
switch (_currentState)
{
case Closed:
case OpenIdle:
case OpenWait:
//A0: do nothing
break;
case Connecting:
A5(destination);
break;
}
}
break;
case Disconnect:
//E21
//A0: do nothing
break;
case Ack:
//E23
//A0: do nothing
break;
case Nack:
//E24
//A0: do nothing
break;
}
}
void TransportLayer::dataGroupIndication(uint16_t destination, HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu)
{
uint16_t tsap = _groupAddressTable.getTsap(destination);
_applicationLayer.dataGroupIndication(hopType, priority, tsap, tpdu.apdu());
}
void TransportLayer::dataGroupConfirm(AckType ack, uint16_t source, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu, bool status)
{
_applicationLayer.dataGroupConfirm(ack, hopType, priority, destination, tpdu.apdu(), status);
}
void TransportLayer::dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu)
{
_applicationLayer.dataBroadcastIndication(hopType, priority, source, tpdu.apdu());
}
void TransportLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu, bool status)
{
_applicationLayer.dataBroadcastConfirm(ack, hopType, priority, tpdu.apdu(), status);
}
void TransportLayer::dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu)
{
_applicationLayer.dataSystemBroadcastIndication(hopType, priority, source, tpdu.apdu());
}
void TransportLayer::dataSystemBroadcastConfirm(AckType ack, HopCountType hopType, TPDU& tpdu, Priority priority, bool status)
{
_applicationLayer.dataSystemBroadcastConfirm(hopType, priority, tpdu.apdu(), status);
}
void TransportLayer::dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu)
{
uint16_t groupAdress = _groupAddressTable.getGa(tsap);
TPDU& tpdu = apdu.frame().tpdu();
_networkLayer->dataGroupRequest(ack, groupAdress, hopType, priority, tpdu);
}
void TransportLayer::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu)
{
TPDU& tpdu = apdu.frame().tpdu();
_networkLayer->dataBroadcastRequest(ack, hopType, priority, tpdu);
}
void TransportLayer::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu)
{
TPDU& tpdu = apdu.frame().tpdu();
return _networkLayer->dataSystemBroadcastRequest(ack, hopType, priority, tpdu);
}
void TransportLayer::dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu)
{
//print.print("-> TL ");
//apdu.printPDU();
TPDU& tpdu = apdu.frame().tpdu();
_networkLayer->dataIndividualRequest(ack, destination, hopType, priority, tpdu);
}
void TransportLayer::connectRequest(uint16_t destination, Priority priority)
{
//E25
switch (_currentState)
{
case Closed:
_currentState = Connecting;
A12(destination, priority);
break;
case OpenIdle:
case OpenWait:
case Connecting:
_currentState = Closed;
A6(destination);
break;
}
}
void TransportLayer::disconnectRequest(uint16_t tsap, Priority priority)
{
//E26
switch (_currentState)
{
case Closed:
A15(priority, tsap);
break;
case OpenIdle:
case OpenWait:
case Connecting:
_currentState = Closed;
A14(tsap, priority);
break;
}
}
void TransportLayer::dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu)
{
//print.print("-> TL ");
//apdu.printPDU();
//E15
switch (_currentState)
{
case Closed:
//A0
break;
case OpenIdle:
_currentState = OpenWait;
A7(priority, apdu);
break;
case OpenWait:
case Connecting:
A11(tsap, priority, apdu);
break;
default:
break;
}
}
void TransportLayer::connectionTimeoutIndication()
{
//E16
switch (_currentState)
{
case Closed:
//A0: do nothing
break;
case OpenIdle:
case OpenWait:
case Connecting:
_currentState = Closed;
A6(_connectionAddress);
break;
}
}
void TransportLayer::ackTimeoutIndication()
{
if (_repCount < _maxRepCount)
{
//E17
switch (_currentState)
{
case Closed:
case OpenIdle:
case Connecting:
//A0: do nothing
break;
case OpenWait:
A9();
break;
}
}
else
{
//E18
switch (_currentState)
{
case Closed:
case OpenIdle:
case Connecting:
//A0: do nothing
break;
case OpenWait:
_currentState = Closed;
A6(_connectionAddress);
break;
}
}
}
void TransportLayer::loop()
{
uint32_t millis = _platform.millis();
if (_connectionTimeoutEnabled
&& (millis - _connectionTimeoutStartMillis) > _connectionTimeoutMillis)
connectionTimeoutIndication();
if (_ackTimeoutEnabled
&& (millis - _ackTimeoutStartMillis) > _ackTimeoutMillis)
ackTimeoutIndication();
if (_savedConnectingValid)
{
//retry saved event
_savedConnectingValid = false;
dataConnectedRequest(_savedTsapConnecting, _savedPriorityConnecting, _savedFrameConnecting.apdu());
}
}
void TransportLayer::sendControlTelegram(TpduType pduType, uint8_t seqNo)
{
CemiFrame frame(0);
TPDU& tpdu = frame.tpdu();
tpdu.type(pduType);
tpdu.sequenceNumber(seqNo);
_networkLayer->dataIndividualRequest(AckRequested, _connectionAddress, NetworkLayerParameter,
SystemPriority, tpdu);
}
void TransportLayer::A0()
{
/* do nothing */
}
void TransportLayer::A1(uint16_t source)
{
_connectionAddress = source;
_applicationLayer.connectIndication(source);
_seqNoSend = 0;
_seqNoRecv = 0;
}
void incSeqNr(uint8_t& seqNr)
{
seqNr += 1;
if (seqNr > 0xf)
seqNr = 0;
}
void TransportLayer::A2(uint16_t source, Priority priority, APDU& apdu)
{
sendControlTelegram(Ack, _seqNoRecv);
incSeqNr(_seqNoRecv);
_applicationLayer.dataConnectedIndication(priority, source, apdu);
enableConnectionTimeout();
}
void TransportLayer::A3(uint16_t source, Priority priority, TPDU& recTpdu)
{
sendControlTelegram(Ack, recTpdu.sequenceNumber());
enableConnectionTimeout();
}
void TransportLayer::A4(uint16_t source, Priority priority, TPDU& recTpdu)
{
sendControlTelegram(Nack, recTpdu.sequenceNumber());
enableConnectionTimeout();
}
void TransportLayer::A5(uint16_t tsap)
{
_applicationLayer.disconnectIndication(tsap);
disableConnectionTimeout();
disableAckTimeout();
}
void TransportLayer::A6(uint16_t tsap)
{
sendControlTelegram(Disconnect, 0);
_applicationLayer.disconnectIndication(tsap);
disableConnectionTimeout();
disableAckTimeout();
}
void TransportLayer::A7(Priority priority, APDU& apdu)
{
_savedPriority = priority;
_savedFrame = apdu.frame();
TPDU& tpdu = apdu.frame().tpdu();
tpdu.type(DataConnected);
tpdu.sequenceNumber(_seqNoSend);
_networkLayer->dataIndividualRequest(AckRequested, _connectionAddress, NetworkLayerParameter, priority, tpdu);
_repCount = 0;
enableAckTimeout();
enableConnectionTimeout();
}
void TransportLayer::A8()
{
disableAckTimeout();
incSeqNr(_seqNoSend);
_applicationLayer.dataConnectedConfirm(0);
enableConnectionTimeout();
}
void TransportLayer::A9()
{
TPDU& tpdu = _savedFrame.tpdu();
// tpdu is still initialized from last send
_networkLayer->dataIndividualRequest(AckRequested, _connectionAddress, NetworkLayerParameter, _savedPriority, tpdu);
_repCount += 1;
enableAckTimeout();
enableConnectionTimeout();
}
void TransportLayer::A10(uint16_t source)
{
CemiFrame frame(0);
TPDU& tpdu = frame.tpdu();
tpdu.type(Disconnect);
tpdu.sequenceNumber(0);
_networkLayer->dataIndividualRequest(AckRequested, source, NetworkLayerParameter, SystemPriority, tpdu);
}
void TransportLayer::A11(uint16_t tsap, Priority priority, APDU& apdu)
{
_savedTsapConnecting = tsap;
_savedPriorityConnecting = priority;
_savedFrameConnecting = apdu.frame();
_savedConnectingValid = true;
}
void TransportLayer::A12(uint16_t destination, Priority priority)
{
_connectionAddress = destination;
CemiFrame frame(0);
TPDU& tpdu = frame.tpdu();
tpdu.type(Connect);
_seqNoRecv = 0;
_seqNoSend = 0;
enableConnectionTimeout();
}
void TransportLayer::A13(uint16_t destination)
{
_applicationLayer.connectConfirm(destination, 0, true);
}
void TransportLayer::A14(uint16_t tsap, Priority priority)
{
CemiFrame frame(0);
TPDU& tpdu = frame.tpdu();
tpdu.type(Disconnect);
tpdu.sequenceNumber(0);
_networkLayer->dataIndividualRequest(AckRequested, _connectionAddress, NetworkLayerParameter, SystemPriority, tpdu);
_applicationLayer.disconnectConfirm(priority, tsap, true);
}
void TransportLayer::A15(Priority priority, uint16_t tsap)
{
_applicationLayer.disconnectConfirm(priority, tsap, true);
disableConnectionTimeout();
disableAckTimeout();
}
void TransportLayer::enableConnectionTimeout()
{
_connectionTimeoutStartMillis = _platform.millis();
_connectionTimeoutEnabled = true;
}
void TransportLayer::disableConnectionTimeout()
{
_connectionTimeoutEnabled = false;
}
void TransportLayer::enableAckTimeout()
{
_ackTimeoutStartMillis = _platform.millis();
_ackTimeoutEnabled = true;
}
void TransportLayer::disableAckTimeout()
{
_ackTimeoutEnabled = false;
}

98
transport_layer.h Normal file
View File

@ -0,0 +1,98 @@
#pragma once
#include <stdint.h>
#include "knx_types.h"
#include "tpdu.h"
#include "address_table_object.h"
#include "cemi_frame.h"
class ApplicationLayer;
class APDU;
class NetworkLayer;
class Platform;
enum StateType { Closed, OpenIdle, OpenWait, Connecting };
class TransportLayer
{
public:
TransportLayer(ApplicationLayer& layer, AddressTableObject& gat, Platform& platform);
void networkLayer(NetworkLayer& layer);
// from network layer
void dataIndividualIndication(uint16_t destination, HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu);
void dataIndividualConfirm(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu, bool status);
void dataGroupIndication(uint16_t destination, HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu);
void dataGroupConfirm(AckType ack, uint16_t source, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu, bool status);
void dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu);
void dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu, bool status);
void dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, TPDU& tpdu);
void dataSystemBroadcastConfirm(AckType ack, HopCountType hopType, TPDU& tpdu, Priority priority, bool status);
// fromp application layer
void dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu);
void dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu);
void dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu);
void dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu);
void connectRequest(uint16_t destination, Priority priority);
void disconnectRequest(uint16_t tsap, Priority priority);
// apdu must be valid until it was confirmed
void dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu);
// other
void connectionTimeoutIndication();
void ackTimeoutIndication();
void loop();
private:
#pragma region States
Priority _savedPriority = LowPriority;
CemiFrame _savedFrame;
Priority _savedPriorityConnecting;
CemiFrame _savedFrameConnecting;
uint16_t _savedTsapConnecting;
bool _savedConnectingValid = false;
enum StateEvent
{
E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13, E14,
E15, E16, E17, E18, E19, E20, E21, E22, E23, E24, E25, E26, E27
};
StateType _currentState = Closed;
void sendControlTelegram(TpduType pduType, uint8_t seqNo);
void A0();
void A1(uint16_t source);
void A2(uint16_t source, Priority priority, APDU& apdu);
void A3(uint16_t source, Priority priority, TPDU& recTpdu);
void A4(uint16_t source, Priority priority, TPDU& recTpdu);
void A5(uint16_t source);
void A6(uint16_t source);
void A7(Priority priority, APDU& apdu);
void A8();
void A9();
void A10(uint16_t source);
void A11(uint16_t tsap, Priority priority, APDU& apdu);
void A12(uint16_t destination, Priority priority);
void A13(uint16_t destination);
void A14(uint16_t destination, Priority priority);
void A15(Priority priority, uint16_t tsap);
void enableConnectionTimeout();
void disableConnectionTimeout();
void enableAckTimeout();
void disableAckTimeout();
uint16_t _connectionAddress = 0;
uint8_t _seqNoSend = 0;
uint8_t _seqNoRecv = 0;
bool _connectionTimeoutEnabled = false;
uint32_t _connectionTimeoutStartMillis = 0;
uint16_t _connectionTimeoutMillis = 6000;
bool _ackTimeoutEnabled = false;
uint32_t _ackTimeoutStartMillis = 0;
uint16_t _ackTimeoutMillis = 3000;
uint8_t _repCount = 0;
uint8_t _maxRepCount = 3;
#pragma endregion
ApplicationLayer& _applicationLayer;
AddressTableObject& _groupAddressTable;
NetworkLayer* _networkLayer;
Platform& _platform;
};