mirror of
https://github.com/thelsing/knx.git
synced 2025-05-07 01:15:35 +02:00
initial commit
This commit is contained in:
parent
96eea4ffe8
commit
2a169ee66b
63
.gitattributes
vendored
Normal file
63
.gitattributes
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
261
.gitignore
vendored
Normal file
261
.gitignore
vendored
Normal file
@ -0,0 +1,261 @@
|
||||
## 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/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# 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
|
||||
project.fragment.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
|
||||
*.VC.VC.opendb
|
||||
|
||||
# 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: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
#*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# 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/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
|
||||
# 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/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# 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
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
85
address_table_object.cpp
Normal file
85
address_table_object.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
#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 ntohs(_groupAddresses[0]);
|
||||
}
|
||||
|
||||
uint16_t AddressTableObject::getGa(uint16_t tsap)
|
||||
{
|
||||
if (loadState() != LS_LOADED || tsap > entryCount() )
|
||||
return 0;
|
||||
|
||||
return ntohs(_groupAddresses[tsap]);
|
||||
}
|
||||
|
||||
uint16_t AddressTableObject::getTsap(uint16_t addr)
|
||||
{
|
||||
uint16_t size = entryCount();
|
||||
for (uint16_t i = 1; i <= size; i++)
|
||||
if (ntohs(_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 (ntohs(_groupAddresses[i]) == addr)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AddressTableObject::beforeStateChange(LoadState& newState)
|
||||
{
|
||||
if (newState != LS_LOADED)
|
||||
return;
|
||||
|
||||
_groupAddresses = (uint16_t*)_data;
|
||||
}
|
20
address_table_object.h
Normal file
20
address_table_object.h
Normal 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;
|
||||
};
|
53
apdu.cpp
Normal file
53
apdu.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
#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;
|
||||
apci = getWord(_data);
|
||||
popWord(apci, _data);
|
||||
apci &= 0x3ff;
|
||||
if ((apci >> 6) < 11) //short apci
|
||||
apci &= 0x3c0;
|
||||
return (ApduType)apci;
|
||||
}
|
||||
|
||||
void APDU::type(ApduType atype)
|
||||
{
|
||||
// ApduType is in big endian so convert to host first, pushWord converts back
|
||||
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
22
apdu.h
Normal 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
792
application_layer.cpp
Normal 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 = 0; 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
102
application_layer.h
Normal 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;
|
||||
};
|
87
application_program_object.cpp
Normal file
87
application_program_object.cpp
Normal file
@ -0,0 +1,87 @@
|
||||
#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_OBJECT_TYPE:
|
||||
case PID_PEI_TYPE:
|
||||
return 1;
|
||||
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);
|
||||
}
|
20
application_program_object.h
Normal file
20
application_program_object.h
Normal 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];
|
||||
};
|
69
association_table_object.cpp
Normal file
69
association_table_object.cpp
Normal file
@ -0,0 +1,69 @@
|
||||
#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 ntohs(_tableData[0]);
|
||||
}
|
||||
|
||||
uint16_t AssociationTableObject::operator[](uint16_t idx)
|
||||
{
|
||||
if (idx < 0 || idx >= entryCount())
|
||||
return 0;
|
||||
|
||||
return ntohs(_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 = ntohs(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;
|
||||
}
|
20
association_table_object.h
Normal file
20
association_table_object.h
Normal 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
238
bau.cpp
Normal 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
110
bau.h
Normal 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);
|
||||
};
|
286
bau57B0.cpp
Normal file
286
bau57B0.cpp
Normal file
@ -0,0 +1,286 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void Bau57B0::readMemory()
|
||||
{
|
||||
_memory.readMemory();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool Bau57B0::enabled()
|
||||
{
|
||||
return _dlLayer.enabled();
|
||||
}
|
||||
|
||||
void Bau57B0::enabled(bool value)
|
||||
{
|
||||
_dlLayer.enabled(value);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
77
bau57B0.h
Normal file
77
bau57B0.h
Normal file
@ -0,0 +1,77 @@
|
||||
#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();
|
||||
bool enabled();
|
||||
void enabled(bool value);
|
||||
void readMemory();
|
||||
protected:
|
||||
void memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
|
||||
uint16_t memoryAddress, uint8_t* data) override;
|
||||
void memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
|
||||
uint16_t memoryAddress) override;
|
||||
void deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t descriptorType);
|
||||
void restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap);
|
||||
void authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, uint32_t key);
|
||||
void userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint32_t memoryAddress);
|
||||
void userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
|
||||
uint32_t memoryAddress, uint8_t* memoryData);
|
||||
void propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex,
|
||||
uint8_t propertyId, uint8_t propertyIndex);
|
||||
void propertyValueWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex,
|
||||
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length);
|
||||
void propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex,
|
||||
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex);
|
||||
void individualAddressReadIndication(HopCountType hopType);
|
||||
void individualAddressWriteIndication(HopCountType hopType, uint16_t newaddress);
|
||||
void groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType,
|
||||
uint8_t* data, uint8_t dataLength, bool status);
|
||||
void groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, bool status);
|
||||
void groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType);
|
||||
void groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType,
|
||||
uint8_t* data, uint8_t dataLength);
|
||||
void groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType,
|
||||
uint8_t* data, uint8_t dataLength);
|
||||
|
||||
InterfaceObject& getInterfaceObject(uint8_t idx);
|
||||
void sendNextGroupTelegram();
|
||||
void updateGroupObject(GroupObject& go, uint8_t* data, uint8_t length);
|
||||
private:
|
||||
DeviceObject _deviceObj;
|
||||
// pointer to first private variable as reference to memory read/write commands
|
||||
uint8_t* _memoryReference;
|
||||
Memory _memory;
|
||||
AddressTableObject _addrTable;
|
||||
AssociationTableObject _assocTable;
|
||||
GroupObjectTableObject _groupObjTable;
|
||||
ApplicationProgramObject _appProgram;
|
||||
IpParameterObject _ipParameters;
|
||||
Platform& _platform;
|
||||
ApplicationLayer _appLayer;
|
||||
TransportLayer _transLayer;
|
||||
NetworkLayer _netLayer;
|
||||
DataLinkLayer _dlLayer;
|
||||
|
||||
};
|
75
bits.cpp
Normal file
75
bits.cpp
Normal 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];
|
||||
}
|
27
bits.h
Normal file
27
bits.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include <arpa/inet.h>
|
||||
#define lowByte(val) ((val) & 255)
|
||||
#define highByte(val) (((val) >> ((sizeof(val) - 1) << 3)) & 255)
|
||||
#define bitRead(val, bitno) (((val) >> (bitno)) & 1)
|
||||
#else
|
||||
#include <Arduino.h>
|
||||
#include <user_interface.h>
|
||||
#define printf Serial.printf
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
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
195
cemi_frame.cpp
Normal 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
60
cemi_frame.h
Normal 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
199
data_link_layer.cpp
Normal 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
33
data_link_layer.h
Normal 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
63
datapoint_types.cpp
Normal 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
37
datapoint_types.h
Normal 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);
|
253
device_object.cpp
Normal file
253
device_object.cpp
Normal file
@ -0,0 +1,253 @@
|
||||
#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_OBJECT_TYPE:
|
||||
case PID_DEVICE_CONTROL:
|
||||
case PID_ROUTING_COUNT:
|
||||
case PID_PROG_MODE:
|
||||
case PID_MAX_APDU_LENGTH:
|
||||
case PID_SUBNET_ADDR:
|
||||
case PID_DEVICE_ADDR:
|
||||
return 1;
|
||||
case PID_MANUFACTURER_ID:
|
||||
case PID_VERSION:
|
||||
case PID_DEVICE_DESCRIPTOR:
|
||||
return 2;
|
||||
case PID_IO_LIST:
|
||||
return 4;
|
||||
case PID_SERIAL_NUMBER:
|
||||
case PID_HARDWARE_TYPE:
|
||||
return 6;
|
||||
case PID_ORDER_INFO:
|
||||
return 10;
|
||||
}
|
||||
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
46
device_object.h
Normal 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;
|
||||
};
|
191
group_object.cpp
Normal file
191
group_object.cpp
Normal 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(ntohs(_table->_tableData[_asap]), 15) > 0;
|
||||
}
|
||||
|
||||
bool GroupObject::transmitEnable()
|
||||
{
|
||||
if (!_table)
|
||||
return false;
|
||||
|
||||
return bitRead(ntohs(_table->_tableData[_asap]), 14) > 0 ;
|
||||
}
|
||||
|
||||
bool GroupObject::valueReadOnInit()
|
||||
{
|
||||
if (!_table)
|
||||
return false;
|
||||
|
||||
return bitRead(ntohs(_table->_tableData[_asap]), 13) > 0;
|
||||
}
|
||||
|
||||
bool GroupObject::writeEnable()
|
||||
{
|
||||
if (!_table)
|
||||
return false;
|
||||
|
||||
return bitRead(ntohs(_table->_tableData[_asap]), 12) > 0 ;
|
||||
}
|
||||
|
||||
bool GroupObject::readEnable()
|
||||
{
|
||||
if (!_table)
|
||||
return false;
|
||||
|
||||
return bitRead(ntohs(_table->_tableData[_asap]), 11) > 0;
|
||||
}
|
||||
|
||||
bool GroupObject::communicationEnable()
|
||||
{
|
||||
if (!_table)
|
||||
return false;
|
||||
|
||||
return bitRead(ntohs(_table->_tableData[_asap]), 10) > 0;
|
||||
}
|
||||
|
||||
|
||||
Priority GroupObject::priority()
|
||||
{
|
||||
if (!_table)
|
||||
return LowPriority;
|
||||
|
||||
return (Priority)((ntohs(_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 = getWord(_data);
|
||||
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(ntohs(_table->_tableData[_asap]));
|
||||
return asapValueSize(code);
|
||||
}
|
111
group_object.h
Normal file
111
group_object.h
Normal 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;
|
||||
};
|
121
group_object_table_object.cpp
Normal file
121
group_object_table_object.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
#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 ntohs(_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;
|
||||
|
||||
if (!initGroupObjects())
|
||||
{
|
||||
newState = LS_ERROR;
|
||||
TableObject::_errorCode = E_SOFTWARE_FAULT;
|
||||
}
|
||||
}
|
||||
|
||||
bool GroupObjectTableObject::initGroupObjects()
|
||||
{
|
||||
if (!_tableData)
|
||||
return false;
|
||||
|
||||
uint16_t goCount = ntohs(_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;
|
||||
}
|
27
group_object_table_object.h
Normal file
27
group_object_table_object.h
Normal 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
62
interface_object.h
Normal 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:
|
||||
|
||||
};
|
302
ip_parameter_object.cpp
Normal file
302
ip_parameter_object.cpp
Normal file
@ -0,0 +1,302 @@
|
||||
#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_IP_ASSIGNMENT_METHOD:
|
||||
case PID_LOAD_STATE_CONTROL:
|
||||
case PID_IP_CAPABILITIES:
|
||||
case PID_TTL:
|
||||
case PID_KNXNETIP_DEVICE_CAPABILITIES:
|
||||
case PID_FRIENDLY_NAME:
|
||||
return 1;
|
||||
case PID_OBJECT_TYPE:
|
||||
case PID_PROJECT_INSTALLATION_ID:
|
||||
case PID_KNX_INDIVIDUAL_ADDRESS:
|
||||
return 2;
|
||||
case PID_CURRENT_IP_ADDRESS:
|
||||
case PID_CURRENT_SUBNET_MASK:
|
||||
case PID_CURRENT_DEFAULT_GATEWAY:
|
||||
case PID_IP_ADDRESS:
|
||||
case PID_SUBNET_MASK:
|
||||
case PID_DEFAULT_GATEWAY:
|
||||
case PID_SYSTEM_SETUP_MULTICAST_ADDRESS:
|
||||
case PID_ROUTING_MULTICAST_ADDRESS:
|
||||
return 4;
|
||||
case PID_MAC_ADDRESS:
|
||||
return 6;
|
||||
}
|
||||
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
42
ip_parameter_object.h
Normal 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;
|
||||
};
|
103
knx_types.h
Normal file
103
knx_types.h
Normal 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,
|
||||
};
|
56
memory.cpp
Normal file
56
memory.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
#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);
|
||||
|
||||
if (_data[0] != 0xDE || _data[1] != 0xAD || _data[2] != 0xAF || _data[3] != 0xFE)
|
||||
return;
|
||||
|
||||
uint8_t* buffer = _data + 4;
|
||||
int size = _saveCount;
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
buffer = _saveRestores[i]->restore(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void Memory::writeMemory()
|
||||
{
|
||||
_data[0] = 0xDE;
|
||||
_data[1] = 0xAD;
|
||||
_data[2] = 0xAF;
|
||||
_data[3] = 0xFE;
|
||||
|
||||
uint8_t* buffer = _data + 4;
|
||||
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
24
memory.h
Normal 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;
|
||||
};
|
127
network_layer.cpp
Normal file
127
network_layer.cpp
Normal file
@ -0,0 +1,127 @@
|
||||
#include "network_layer.h"
|
||||
#include "tpdu.h"
|
||||
#include "cemi_frame.h"
|
||||
#include "data_link_layer.h"
|
||||
#include "bits.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
38
network_layer.h
Normal 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
44
npdu.cpp
Normal 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
24
npdu.h
Normal 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
26
platform.h
Normal 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
166
property_types.h
Normal 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
|
||||
};
|
10
save_restore.h
Normal file
10
save_restore.h
Normal 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
257
table_object.cpp
Normal 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 1;
|
||||
case PID_TABLE_REFERENCE:
|
||||
return 4;
|
||||
case PID_ERROR_CODE:
|
||||
return 1;
|
||||
}
|
||||
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
33
table_object.h
Normal 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
127
tpdu.cpp
Normal 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
32
tpdu.h
Normal 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
711
transport_layer.cpp
Normal 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
98
transport_layer.h
Normal 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;
|
||||
};
|
Loading…
Reference in New Issue
Block a user