mirror of
https://github.com/thelsing/knx.git
synced 2025-06-17 01:17:18 +02:00
initial checkin
This commit is contained in:
commit
a7a48b4a7b
247
.gitignore
vendored
Normal file
247
.gitignore
vendored
Normal file
@ -0,0 +1,247 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
[Xx]64/
|
||||
[Xx]86/
|
||||
[Bb]uild/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# DNX
|
||||
project.lock.json
|
||||
artifacts/
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
|
||||
# TODO: Un-comment the next line if you do not want to checkin
|
||||
# your web deploy settings because they may include unencrypted
|
||||
# passwords
|
||||
#*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignoreable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Microsoft Azure ApplicationInsights config file
|
||||
ApplicationInsights.config
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# LightSwitch generated files
|
||||
GeneratedArtifacts/
|
||||
ModelManifest.xml
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
/CodeDB
|
||||
/VisualGDBCache
|
90
address_table_object.cpp
Normal file
90
address_table_object.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "address_table_object.h"
|
||||
#include "bits.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
AddressTableObject::AddressTableObject(uint8_t* memoryReference): TableObject(memoryReference)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AddressTableObject::readProperty(PropertyID id, uint32_t start, uint32_t count, uint8_t* data)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case PID_OBJECT_TYPE:
|
||||
pushWord(OT_ADDR_TABLE, data);
|
||||
break;
|
||||
default:
|
||||
TableObject::readProperty(id, start, count, data);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t AddressTableObject::entryCount()
|
||||
{
|
||||
if (loadState() != LS_LOADED)
|
||||
return 0;
|
||||
|
||||
return _groupAddresses[0];
|
||||
}
|
||||
|
||||
uint16_t AddressTableObject::getGa(uint16_t tsap)
|
||||
{
|
||||
if (loadState() != LS_LOADED || tsap > entryCount() )
|
||||
return 0;
|
||||
|
||||
return _groupAddresses[tsap];
|
||||
}
|
||||
|
||||
uint16_t AddressTableObject::getTsap(uint16_t addr)
|
||||
{
|
||||
uint16_t size = entryCount();
|
||||
for (uint16_t i = 1; i <= size; i++)
|
||||
if (_groupAddresses[i] == addr)
|
||||
return i;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#pragma region SaveRestore
|
||||
|
||||
uint8_t* AddressTableObject::save(uint8_t* buffer)
|
||||
{
|
||||
return TableObject::save(buffer);
|
||||
}
|
||||
|
||||
uint8_t* AddressTableObject::restore(uint8_t* buffer)
|
||||
{
|
||||
buffer = TableObject::restore(buffer);
|
||||
|
||||
_groupAddresses = (uint16_t*)_data;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
bool AddressTableObject::contains(uint16_t addr)
|
||||
{
|
||||
uint16_t size = entryCount();
|
||||
for (uint16_t i = 1; i <= size; i++)
|
||||
if (_groupAddresses[i] == addr)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AddressTableObject::beforeStateChange(LoadState& newState)
|
||||
{
|
||||
if (newState != LS_LOADED)
|
||||
return;
|
||||
|
||||
_groupAddresses = (uint16_t*)_data;
|
||||
|
||||
uint16_t count = reverseByteOrder(_groupAddresses[0]);
|
||||
// big endian -> little endian
|
||||
for (size_t i = 0; i <= count; i++)
|
||||
_groupAddresses[i] = reverseByteOrder(_groupAddresses[i]);
|
||||
}
|
20
address_table_object.h
Normal file
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;
|
||||
};
|
51
apdu.cpp
Normal file
51
apdu.cpp
Normal file
@ -0,0 +1,51 @@
|
||||
#include "apdu.h"
|
||||
#include "cemi_frame.h"
|
||||
#include "bits.h"
|
||||
|
||||
APDU::APDU(uint8_t* data, CemiFrame& frame): _data(data), _frame(frame)
|
||||
{
|
||||
}
|
||||
|
||||
ApduType APDU::type()
|
||||
{
|
||||
uint16_t apci;
|
||||
popWord(apci, _data);
|
||||
apci &= 0x3ff;
|
||||
if ((apci >> 6) < 11) //short apci
|
||||
apci &= 0x3c0;
|
||||
return (ApduType)apci;
|
||||
}
|
||||
|
||||
void APDU::type(ApduType atype)
|
||||
{
|
||||
pushWord((uint16_t)atype, _data);
|
||||
}
|
||||
|
||||
uint8_t* APDU::data()
|
||||
{
|
||||
return _data + 1;
|
||||
}
|
||||
|
||||
CemiFrame& APDU::frame()
|
||||
{
|
||||
return _frame;
|
||||
}
|
||||
|
||||
uint8_t APDU::length() const
|
||||
{
|
||||
return _frame.npdu().octetCount();
|
||||
}
|
||||
|
||||
void APDU::printPDU()
|
||||
{
|
||||
//Print.print("APDU: ");
|
||||
//print.print(type(), HEX, 4);
|
||||
//print.print(" ");
|
||||
//print.print(_data[0] & 0x3, HEX, 2);
|
||||
//for (uint8_t i = 1; i < length() + 1; ++i)
|
||||
//{
|
||||
// if (i) print.print(" ");
|
||||
// print.print(_data[i], HEX, 2);
|
||||
//}
|
||||
//print.println();
|
||||
}
|
22
apdu.h
Normal file
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; 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;
|
||||
};
|
84
application_program_object.cpp
Normal file
84
application_program_object.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
#include "application_program_object.h"
|
||||
#include "bits.h"
|
||||
|
||||
ApplicationProgramObject::ApplicationProgramObject(uint8_t* memoryReference): TableObject(memoryReference)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void ApplicationProgramObject::readProperty(PropertyID id, uint32_t start, uint32_t count, uint8_t* data)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case PID_OBJECT_TYPE:
|
||||
pushWord(OT_APPLICATION_PROG, data);
|
||||
break;
|
||||
case PID_PROG_VERSION:
|
||||
pushByteArray(_programVersion, 5, data);
|
||||
break;
|
||||
case PID_PEI_TYPE:
|
||||
pushByte(0x0, data);
|
||||
break;
|
||||
default:
|
||||
TableObject::readProperty(id, start, count, data);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplicationProgramObject::writeProperty(PropertyID id, uint8_t start, uint8_t* data, uint8_t count)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case PID_PROG_VERSION:
|
||||
for (uint32_t i = 0; i < 5; i++)
|
||||
{
|
||||
_programVersion[i] = data[i];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
TableObject::writeProperty(id, start, data, count);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ApplicationProgramObject::propertySize(PropertyID id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case PID_PROG_VERSION:
|
||||
return 5;
|
||||
}
|
||||
return TableObject::propertySize(id);
|
||||
}
|
||||
|
||||
uint8_t * ApplicationProgramObject::data(uint32_t addr)
|
||||
{
|
||||
return _data + addr;
|
||||
}
|
||||
|
||||
uint8_t ApplicationProgramObject::getByte(uint32_t addr)
|
||||
{
|
||||
return *(_data + addr);
|
||||
}
|
||||
|
||||
uint16_t ApplicationProgramObject::getWord(uint32_t addr)
|
||||
{
|
||||
return ::getWord(_data + addr);
|
||||
}
|
||||
|
||||
uint32_t ApplicationProgramObject::getInt(uint32_t addr)
|
||||
{
|
||||
return ::getInt(_data + addr);
|
||||
}
|
||||
|
||||
uint8_t* ApplicationProgramObject::save(uint8_t* buffer)
|
||||
{
|
||||
buffer = pushByteArray(_programVersion, 5, buffer);
|
||||
|
||||
return TableObject::save(buffer);
|
||||
}
|
||||
|
||||
uint8_t* ApplicationProgramObject::restore(uint8_t* buffer)
|
||||
{
|
||||
buffer = popByteArray(_programVersion, 5, buffer);
|
||||
|
||||
return TableObject::restore(buffer);
|
||||
}
|
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];
|
||||
};
|
74
association_table_object.cpp
Normal file
74
association_table_object.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "association_table_object.h"
|
||||
#include "bits.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
AssociationTableObject::AssociationTableObject(uint8_t* memoryReference): TableObject(memoryReference)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void AssociationTableObject::readProperty(PropertyID id, uint32_t start, uint32_t count, uint8_t* data)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case PID_OBJECT_TYPE:
|
||||
pushWord(OT_ASSOC_TABLE, data);
|
||||
break;
|
||||
default:
|
||||
TableObject::readProperty(id, start, count, data);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t AssociationTableObject::entryCount()
|
||||
{
|
||||
return _tableData[0];
|
||||
}
|
||||
|
||||
uint16_t AssociationTableObject::operator[](uint16_t idx)
|
||||
{
|
||||
if (idx < 0 || idx >= entryCount())
|
||||
return 0;
|
||||
|
||||
return _tableData[idx + 1];
|
||||
}
|
||||
|
||||
uint8_t* AssociationTableObject::save(uint8_t* buffer)
|
||||
{
|
||||
return TableObject::save(buffer);
|
||||
}
|
||||
|
||||
uint8_t* AssociationTableObject::restore(uint8_t* buffer)
|
||||
{
|
||||
buffer = TableObject::restore(buffer);
|
||||
_tableData = (uint16_t*)_data;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int32_t AssociationTableObject::translateAsap(uint16_t asap)
|
||||
{
|
||||
uint16_t entries = entryCount();
|
||||
for (uint16_t i = 0; i < entries; i++)
|
||||
{
|
||||
uint16_t entry = operator[](i);
|
||||
if (lowByte(entry) == asap)
|
||||
return highByte(entry);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void AssociationTableObject::beforeStateChange(LoadState& newState)
|
||||
{
|
||||
if (newState != LS_LOADED)
|
||||
return;
|
||||
|
||||
_tableData = (uint16_t*)_data;
|
||||
|
||||
uint16_t count = reverseByteOrder(_tableData[0]);
|
||||
// big endian -> little endian
|
||||
for (size_t i = 0; i <= count; i++)
|
||||
_tableData[i] = reverseByteOrder(_tableData[i]);
|
||||
}
|
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);
|
||||
};
|
272
bau57B0.cpp
Normal file
272
bau57B0.cpp
Normal file
@ -0,0 +1,272 @@
|
||||
#include "bau57B0.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
Bau57B0::Bau57B0(Platform& platform): _memoryReference((uint8_t*)&_deviceObj), _memory(platform), _addrTable(_memoryReference),
|
||||
_assocTable(_memoryReference), _groupObjTable(_memoryReference), _appProgram(_memoryReference),
|
||||
_ipParameters(_deviceObj, _platform), _platform(platform), _appLayer(_assocTable, *this),
|
||||
_transLayer(_appLayer, _addrTable, _platform), _netLayer(_transLayer),
|
||||
_dlLayer(_deviceObj, _addrTable, _ipParameters, _netLayer, _platform)
|
||||
{
|
||||
_appLayer.transportLayer(_transLayer);
|
||||
_transLayer.networkLayer(_netLayer);
|
||||
_netLayer.dataLinkLayer(_dlLayer);
|
||||
_memory.addSaveRestore(&_deviceObj);
|
||||
_memory.addSaveRestore(&_ipParameters);
|
||||
_memory.addSaveRestore(&_appProgram);
|
||||
_memory.addSaveRestore(&_addrTable);
|
||||
_memory.addSaveRestore(&_assocTable);
|
||||
_memory.addSaveRestore(&_groupObjTable);
|
||||
_memory.readMemory();
|
||||
_dlLayer.enabled(true);
|
||||
}
|
||||
|
||||
void Bau57B0::loop()
|
||||
{
|
||||
_dlLayer.loop();
|
||||
_transLayer.loop();
|
||||
sendNextGroupTelegram();
|
||||
}
|
||||
|
||||
void Bau57B0::sendNextGroupTelegram()
|
||||
{
|
||||
static uint16_t startIdx = 1;
|
||||
|
||||
GroupObjectTableObject& table = _groupObjTable;
|
||||
uint16_t objCount = table.entryCount();
|
||||
|
||||
for (uint16_t asap = startIdx; asap < objCount; asap++)
|
||||
{
|
||||
GroupObject& go = table.get(asap);
|
||||
|
||||
ComFlag flag = go.commFlag();
|
||||
if (flag != ReadRequest && flag != WriteRequest)
|
||||
continue;
|
||||
|
||||
if(!go.communicationEnable() || ! go.transmitEnable())
|
||||
continue;
|
||||
|
||||
if (flag == WriteRequest)
|
||||
{
|
||||
uint8_t* data = go.valueRef();
|
||||
_appLayer.groupValueWriteRequest(AckRequested, asap, go.priority(), NetworkLayerParameter, data,
|
||||
go.sizeInTelegram());
|
||||
}
|
||||
else
|
||||
{
|
||||
_appLayer.groupValueReadRequest(AckRequested, asap, go.priority(), NetworkLayerParameter);
|
||||
}
|
||||
|
||||
go.commFlag(Transmitting);
|
||||
|
||||
startIdx = asap + 1;
|
||||
return;
|
||||
}
|
||||
|
||||
startIdx = 1;
|
||||
}
|
||||
|
||||
void Bau57B0::updateGroupObject(GroupObject & go, uint8_t * data, uint8_t length)
|
||||
{
|
||||
uint8_t* goData = go.valueRef();
|
||||
if (length != go.valueSize())
|
||||
{
|
||||
go.commFlag(Error);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(goData, data, length);
|
||||
|
||||
go.commFlag(cfUpdate);
|
||||
if (go.updateHandler)
|
||||
go.updateHandler(go);
|
||||
}
|
||||
|
||||
DeviceObject& Bau57B0::deviceObject()
|
||||
{
|
||||
return _deviceObj;
|
||||
}
|
||||
|
||||
GroupObjectTableObject& Bau57B0::groupObjectTable()
|
||||
{
|
||||
return _groupObjTable;
|
||||
}
|
||||
|
||||
ApplicationProgramObject& Bau57B0::parameters()
|
||||
{
|
||||
return _appProgram;
|
||||
}
|
||||
|
||||
bool Bau57B0::configured()
|
||||
{
|
||||
return _groupObjTable.loadState() == LS_LOADED
|
||||
&& _addrTable.loadState() == LS_LOADED
|
||||
&& _assocTable.loadState() == LS_LOADED
|
||||
&& _appProgram.loadState() == LS_LOADED;
|
||||
}
|
||||
|
||||
void Bau57B0::memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
|
||||
uint16_t memoryAddress, uint8_t * data)
|
||||
{
|
||||
memcpy(_memoryReference + memoryAddress, data, number);
|
||||
_memory.memoryModified();
|
||||
|
||||
if (_deviceObj.verifyMode())
|
||||
memoryReadIndication(priority, hopType, asap, number, memoryAddress);
|
||||
}
|
||||
|
||||
void Bau57B0::memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
|
||||
uint16_t memoryAddress)
|
||||
{
|
||||
_appLayer.memoryReadResponse(AckRequested, priority, hopType, asap, number, memoryAddress,
|
||||
_memoryReference + memoryAddress);
|
||||
}
|
||||
|
||||
void Bau57B0::deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t descriptorType)
|
||||
{
|
||||
if (descriptorType != 0)
|
||||
descriptorType = 0x3f;
|
||||
|
||||
uint8_t descriptor[] = { 0x57, 0xb0 };
|
||||
|
||||
_appLayer.deviceDescriptorReadResponse(AckRequested, priority, hopType, asap, descriptorType, descriptor);
|
||||
}
|
||||
|
||||
void Bau57B0::restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap)
|
||||
{
|
||||
// for platforms that don't really restart
|
||||
_deviceObj.progMode(false);
|
||||
|
||||
// Flush the EEPROM before resetting
|
||||
_memory.writeMemory();
|
||||
_platform.restart();
|
||||
}
|
||||
|
||||
void Bau57B0::authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, uint32_t key)
|
||||
{
|
||||
_appLayer.authorizeResponse(AckRequested, priority, hopType, asap, 0);
|
||||
}
|
||||
|
||||
void Bau57B0::userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint32_t memoryAddress)
|
||||
{
|
||||
_appLayer.userMemoryReadResponse(AckRequested, priority, hopType, asap, number, memoryAddress,
|
||||
_memoryReference + memoryAddress);
|
||||
}
|
||||
|
||||
void Bau57B0::userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint32_t memoryAddress, uint8_t* data)
|
||||
{
|
||||
memcpy(_memoryReference + memoryAddress, data, number);
|
||||
_memory.memoryModified();
|
||||
|
||||
if (_deviceObj.verifyMode())
|
||||
userMemoryReadIndication(priority, hopType, asap, number, memoryAddress);
|
||||
}
|
||||
|
||||
void Bau57B0::propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex,
|
||||
uint8_t propertyId, uint8_t propertyIndex)
|
||||
{
|
||||
// TODO: reply correctly
|
||||
_appLayer.propertyDescriptionReadResponse(AckRequested, priority, hopType, asap, objectIndex, propertyId, propertyIndex,
|
||||
false, 0, 0, 0);
|
||||
}
|
||||
|
||||
void Bau57B0::propertyValueWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex,
|
||||
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length)
|
||||
{
|
||||
InterfaceObject& obj = getInterfaceObject(objectIndex);
|
||||
obj.writeProperty((PropertyID)propertyId, startIndex, data, numberOfElements);
|
||||
propertyValueReadIndication(priority, hopType, asap, objectIndex, propertyId, numberOfElements, startIndex);
|
||||
}
|
||||
|
||||
void Bau57B0::propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex,
|
||||
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex)
|
||||
{
|
||||
InterfaceObject& obj = getInterfaceObject(objectIndex);
|
||||
uint8_t elementSize = obj.propertySize((PropertyID)propertyId);
|
||||
uint8_t size = elementSize * numberOfElements;
|
||||
uint8_t data[size];
|
||||
obj.readProperty((PropertyID)propertyId, startIndex, numberOfElements, data);
|
||||
_appLayer.propertyValueReadResponse(AckRequested, priority, hopType, asap, objectIndex, propertyId, numberOfElements,
|
||||
startIndex, data, size);
|
||||
}
|
||||
|
||||
void Bau57B0::individualAddressReadIndication(HopCountType hopType)
|
||||
{
|
||||
if (_deviceObj.progMode())
|
||||
_appLayer.individualAddressReadResponse(AckRequested, hopType);
|
||||
}
|
||||
|
||||
void Bau57B0::individualAddressWriteIndication(HopCountType hopType, uint16_t newaddress)
|
||||
{
|
||||
if (_deviceObj.progMode())
|
||||
_deviceObj.induvidualAddress(newaddress);
|
||||
}
|
||||
|
||||
void Bau57B0::groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, uint8_t * data, uint8_t dataLength, bool status)
|
||||
{
|
||||
GroupObject& go = _groupObjTable.get(asap);
|
||||
if (status)
|
||||
go.commFlag(Ok);
|
||||
else
|
||||
go.commFlag(Error);
|
||||
}
|
||||
|
||||
void Bau57B0::groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, bool status)
|
||||
{
|
||||
GroupObject& go = _groupObjTable.get(asap);
|
||||
if (status)
|
||||
go.commFlag(Ok);
|
||||
else
|
||||
go.commFlag(Error);
|
||||
}
|
||||
|
||||
void Bau57B0::groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType)
|
||||
{
|
||||
GroupObject& go = _groupObjTable.get(asap);
|
||||
uint8_t* data = go.valueRef();
|
||||
_appLayer.groupValueReadResponse(AckRequested, asap, priority, hopType, data, go.sizeInTelegram());
|
||||
}
|
||||
|
||||
void Bau57B0::groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType, uint8_t* data,
|
||||
uint8_t dataLength)
|
||||
{
|
||||
GroupObject& go = _groupObjTable.get(asap);
|
||||
|
||||
if (!go.communicationEnable() || !go.responseUpdateEnable())
|
||||
return;
|
||||
|
||||
updateGroupObject(go, data, dataLength);
|
||||
}
|
||||
|
||||
void Bau57B0::groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType, uint8_t * data, uint8_t dataLength)
|
||||
{
|
||||
GroupObject& go = _groupObjTable.get(asap);
|
||||
|
||||
if (!go.communicationEnable() || !go.writeEnable())
|
||||
return;
|
||||
|
||||
updateGroupObject(go, data, dataLength);
|
||||
}
|
||||
|
||||
InterfaceObject& Bau57B0::getInterfaceObject(uint8_t idx)
|
||||
{
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
return _deviceObj;
|
||||
case 1:
|
||||
return _addrTable;
|
||||
case 2:
|
||||
return _assocTable;
|
||||
case 3:
|
||||
return _groupObjTable;
|
||||
case 4:
|
||||
return _appProgram;
|
||||
case 5:
|
||||
return _ipParameters;
|
||||
default:
|
||||
return _deviceObj;
|
||||
}
|
||||
}
|
74
bau57B0.h
Normal file
74
bau57B0.h
Normal file
@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
#include "bau.h"
|
||||
#include "device_object.h"
|
||||
#include "address_table_object.h"
|
||||
#include "association_table_object.h"
|
||||
#include "group_object_table_object.h"
|
||||
#include "application_program_object.h"
|
||||
#include "ip_parameter_object.h"
|
||||
#include "application_layer.h"
|
||||
#include "transport_layer.h"
|
||||
#include "network_layer.h"
|
||||
#include "data_link_layer.h"
|
||||
#include "platform.h"
|
||||
#include "memory.h"
|
||||
|
||||
class Bau57B0: protected BusAccessUnit
|
||||
{
|
||||
using BusAccessUnit::memoryReadIndication;
|
||||
public:
|
||||
Bau57B0(Platform& platform);
|
||||
void loop();
|
||||
DeviceObject& deviceObject();
|
||||
GroupObjectTableObject& groupObjectTable();
|
||||
ApplicationProgramObject& parameters();
|
||||
bool configured();
|
||||
protected:
|
||||
void memoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
|
||||
uint16_t memoryAddress, uint8_t* data) override;
|
||||
void memoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
|
||||
uint16_t memoryAddress) override;
|
||||
void deviceDescriptorReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t descriptorType);
|
||||
void restartRequestIndication(Priority priority, HopCountType hopType, uint16_t asap);
|
||||
void authorizeIndication(Priority priority, HopCountType hopType, uint16_t asap, uint32_t key);
|
||||
void userMemoryReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number, uint32_t memoryAddress);
|
||||
void userMemoryWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t number,
|
||||
uint32_t memoryAddress, uint8_t* memoryData);
|
||||
void propertyDescriptionReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex,
|
||||
uint8_t propertyId, uint8_t propertyIndex);
|
||||
void propertyValueWriteIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex,
|
||||
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length);
|
||||
void propertyValueReadIndication(Priority priority, HopCountType hopType, uint16_t asap, uint8_t objectIndex,
|
||||
uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex);
|
||||
void individualAddressReadIndication(HopCountType hopType);
|
||||
void individualAddressWriteIndication(HopCountType hopType, uint16_t newaddress);
|
||||
void groupValueWriteLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType,
|
||||
uint8_t* data, uint8_t dataLength, bool status);
|
||||
void groupValueReadLocalConfirm(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, bool status);
|
||||
void groupValueReadIndication(uint16_t asap, Priority priority, HopCountType hopType);
|
||||
void groupValueReadAppLayerConfirm(uint16_t asap, Priority priority, HopCountType hopType,
|
||||
uint8_t* data, uint8_t dataLength);
|
||||
void groupValueWriteIndication(uint16_t asap, Priority priority, HopCountType hopType,
|
||||
uint8_t* data, uint8_t dataLength);
|
||||
|
||||
InterfaceObject& getInterfaceObject(uint8_t idx);
|
||||
void sendNextGroupTelegram();
|
||||
void updateGroupObject(GroupObject& go, uint8_t* data, uint8_t length);
|
||||
private:
|
||||
DeviceObject _deviceObj;
|
||||
// pointer to first private variable as reference to memory read/write commands
|
||||
uint8_t* _memoryReference;
|
||||
Memory _memory;
|
||||
AddressTableObject _addrTable;
|
||||
AssociationTableObject _assocTable;
|
||||
GroupObjectTableObject _groupObjTable;
|
||||
ApplicationProgramObject _appProgram;
|
||||
IpParameterObject _ipParameters;
|
||||
Platform& _platform;
|
||||
ApplicationLayer _appLayer;
|
||||
TransportLayer _transLayer;
|
||||
NetworkLayer _netLayer;
|
||||
DataLinkLayer _dlLayer;
|
||||
|
||||
};
|
75
bits.cpp
Normal file
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];;
|
||||
}
|
133
bits.h
Normal file
133
bits.h
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* bits.h - Bit and uint8_t manipulation functions.
|
||||
*
|
||||
* Copyright (c) 2014 Stefan Taferner <stefan.taferner@gmx.at>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 3 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
/**
|
||||
* Compute the value of the specified bit.
|
||||
*
|
||||
* @param bitno - the number of the bit (0, 1, 2... 31)
|
||||
*/
|
||||
#define bit(bitno) (1UL << (bitno))
|
||||
|
||||
/**
|
||||
* Clear the bit of a number. The number can be
|
||||
* any integer (uint8_t, short, uint32_t, long).
|
||||
*
|
||||
* @param val - the number from which to clear the bit
|
||||
* @param bitno - the number of the bit (0, 1, 2... 31)
|
||||
*/
|
||||
#define bitClear(val, bitno) ((val) &= ~(1UL << (bitno)))
|
||||
|
||||
/**
|
||||
* Set the bit of a number. The number can be
|
||||
* any integer (uint8_t, short, uint32_t, long).
|
||||
*
|
||||
* @param val - the number from which to set the bit
|
||||
* @param bitno - the number of the bit (0, 1, 2... 31)
|
||||
*/
|
||||
#define bitSet(val, bitno) ((val) |= 1UL << (bitno))
|
||||
|
||||
/**
|
||||
* Write the value of a bit of a number.
|
||||
*
|
||||
* @param val - the number from which to write the bit
|
||||
* @param bitno - the number of the bit (0, 1, 2... 31)
|
||||
* @param b - the bit value (0 or 1)
|
||||
*/
|
||||
#define bitWrite(val, bitno, b) ((b) ? bitSet(val, bitno) : bitClear(val, bitno))
|
||||
|
||||
/**
|
||||
* Read the value of a bit of a number. The number can be
|
||||
* any integer (uint8_t, short, uint32_t, long).
|
||||
*
|
||||
* @param val - the number from which to get the bit
|
||||
* @param bitno - the number of the bit (0, 1, 2... 31)
|
||||
* @return The value of the bit (0 or 1).
|
||||
*/
|
||||
#define bitRead(val, bitno) (((val) >> (bitno)) & 1)
|
||||
|
||||
/**
|
||||
* Extract the lowest (rightmost) uint8_t of a number. The number can be
|
||||
* any integer (uint8_t, short, uint32_t, long).
|
||||
*
|
||||
* @param val - the value to extract the lowest uint8_t.
|
||||
* @return The extracted uint8_t (0..255)
|
||||
*/
|
||||
#define lowByte(val) ((val) & 255)
|
||||
|
||||
/**
|
||||
* Extract the highest (leftmost) uint8_t of a number. The number can be
|
||||
* any integer (uint8_t, short, uint32_t, long).
|
||||
*
|
||||
* @param val - the value to extract the highest uint8_t.
|
||||
* @return The extracted uint8_t (0..255)
|
||||
*/
|
||||
#define highByte(val) (((val) >> ((sizeof(val) - 1) << 3)) & 255)
|
||||
|
||||
/**
|
||||
* Combine two bytes to a 16 bit uint16_t.
|
||||
*
|
||||
* @param high - the high uint8_t.
|
||||
* @param low - the low uint8_t.
|
||||
* @return The bytes combined as uint16_t.
|
||||
*/
|
||||
uint16_t makeWord(uint8_t high, uint8_t low);
|
||||
|
||||
/**
|
||||
* Reverse the uint8_t order of an integer.
|
||||
*
|
||||
* @param val - the value to reverse.
|
||||
* @return The value with reversed uint8_t order.
|
||||
*/
|
||||
uint32_t reverseByteOrder(uint32_t val);
|
||||
|
||||
/**
|
||||
* Reverse the uint8_t order of a short integer.
|
||||
*
|
||||
* @param val - the value to reverse.
|
||||
* @return The value with reversed uint8_t order.
|
||||
*/
|
||||
uint16_t reverseByteOrder(uint16_t val);
|
||||
|
||||
|
||||
//
|
||||
// Inline functions
|
||||
//
|
||||
|
||||
inline uint16_t makeWord(uint8_t high, uint8_t low)
|
||||
{
|
||||
return (high << 8) | low;
|
||||
}
|
||||
|
||||
inline uint32_t reverseByteOrder(uint32_t val)
|
||||
{
|
||||
uint32_t swapped = ((val >> 24) & 0xff) | // move uint8_t 3 to uint8_t 0
|
||||
((val << 8) & 0xff0000) | // move uint8_t 1 to uint8_t 2
|
||||
((val >> 8) & 0xff00) | // move uint8_t 2 to uint8_t 1
|
||||
((val << 24) & 0xff000000); // uint8_t 0 to uint8_t 3
|
||||
return swapped;//__REV(val);
|
||||
}
|
||||
|
||||
inline uint16_t reverseByteOrder(uint16_t val)
|
||||
{
|
||||
uint16_t swapped = (val >> 8) | (val << 8);
|
||||
return swapped;
|
||||
}
|
||||
|
||||
uint8_t* popByte(uint8_t& b, uint8_t* data);
|
||||
uint8_t* popWord(uint16_t& w, uint8_t* data);
|
||||
uint8_t* popInt(uint32_t& i, uint8_t* data);
|
||||
uint8_t* popByteArray(uint8_t* dst, uint32_t size, uint8_t* data);
|
||||
uint8_t* pushByte(uint8_t b, uint8_t* data);
|
||||
uint8_t* pushWord(uint16_t w, uint8_t* data);
|
||||
uint8_t* pushInt(uint32_t i, uint8_t* data);
|
||||
uint8_t* pushByteArray(const uint8_t* src, uint32_t size, uint8_t* data);
|
||||
uint16_t getWord(uint8_t* data);
|
||||
uint32_t getInt(uint8_t* data);
|
195
cemi_frame.cpp
Normal file
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);
|
240
device_object.cpp
Normal file
240
device_object.cpp
Normal file
@ -0,0 +1,240 @@
|
||||
#include <cstring>
|
||||
#include "device_object.h"
|
||||
#include "bits.h"
|
||||
|
||||
void DeviceObject::readProperty(PropertyID propertyId, uint32_t start, uint32_t count, uint8_t* data)
|
||||
{
|
||||
switch (propertyId)
|
||||
{
|
||||
case PID_OBJECT_TYPE:
|
||||
pushWord(OT_DEVICE, data);
|
||||
break;
|
||||
case PID_SERIAL_NUMBER:
|
||||
pushWord(_manufacturerId, data);
|
||||
pushInt(_bauNumber, data);
|
||||
break;
|
||||
case PID_MANUFACTURER_ID:
|
||||
pushWord(_manufacturerId, data);
|
||||
break;
|
||||
case PID_DEVICE_CONTROL:
|
||||
*data = _deviceControl;
|
||||
break;
|
||||
case PID_ORDER_INFO:
|
||||
pushByteArray((uint8_t*)_orderNumber, 10, data);
|
||||
break;
|
||||
case PID_HARDWARE_TYPE:
|
||||
pushByteArray((uint8_t*)_hardwareType, 6, data);
|
||||
break;
|
||||
case PID_VERSION:
|
||||
pushWord(_version, data);
|
||||
break;
|
||||
case PID_ROUTING_COUNT:
|
||||
*data = _routingCount;
|
||||
break;
|
||||
case PID_PROG_MODE:
|
||||
*data = _prgMode;
|
||||
break;
|
||||
case PID_MAX_APDU_LENGTH:
|
||||
*data = 15;
|
||||
break;
|
||||
case PID_SUBNET_ADDR:
|
||||
*data = ((_ownAddress >> 8) & 0xff);
|
||||
break;
|
||||
case PID_DEVICE_ADDR:
|
||||
*data = (_ownAddress & 0xff);
|
||||
break;
|
||||
case PID_IO_LIST:
|
||||
{
|
||||
uint32_t ifObjs[] = {
|
||||
6, // length
|
||||
OT_DEVICE, OT_ADDR_TABLE, OT_ASSOC_TABLE, OT_GRP_OBJ_TABLE, OT_APPLICATION_PROG, OT_IP_PARAMETER};
|
||||
|
||||
for (uint32_t i = start; i < (ifObjs[0] + 1) && i < count; i++)
|
||||
pushInt(ifObjs[i], data);
|
||||
|
||||
break;
|
||||
}
|
||||
case PID_DEVICE_DESCRIPTOR:
|
||||
data[0] = 0x57;
|
||||
data[1] = 0xB0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceObject::writeProperty(PropertyID id, uint8_t start, uint8_t* data, uint8_t count)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case PID_DEVICE_CONTROL:
|
||||
_deviceControl = data[0];
|
||||
break;
|
||||
case PID_ROUTING_COUNT:
|
||||
_routingCount = data[0];
|
||||
break;
|
||||
case PID_PROG_MODE:
|
||||
_prgMode = data[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t DeviceObject::propertySize(PropertyID id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case PID_DEVICE_CONTROL:
|
||||
return 1;
|
||||
case PID_ROUTING_COUNT:
|
||||
return 1;
|
||||
case PID_PROG_MODE:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* DeviceObject::save(uint8_t* buffer)
|
||||
{
|
||||
buffer = pushByte(_deviceControl, buffer);
|
||||
buffer = pushByte(_routingCount, buffer);
|
||||
buffer = pushWord(_ownAddress, buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
uint8_t* DeviceObject::restore(uint8_t* buffer)
|
||||
{
|
||||
buffer = popByte(_deviceControl, buffer);
|
||||
buffer = popByte(_routingCount, buffer);
|
||||
buffer = popWord(_ownAddress, buffer);
|
||||
_prgMode = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
uint16_t DeviceObject::induvidualAddress()
|
||||
{
|
||||
return _ownAddress;
|
||||
}
|
||||
|
||||
void DeviceObject::induvidualAddress(uint16_t value)
|
||||
{
|
||||
_ownAddress = value;
|
||||
}
|
||||
|
||||
#define USER_STOPPED 0x1
|
||||
#define OWN_ADDR_DUPL 0x2
|
||||
#define VERIFY_MODE 0x4
|
||||
#define SAFE_STATE 0x8
|
||||
|
||||
|
||||
bool DeviceObject::userStopped()
|
||||
{
|
||||
return (_deviceControl & USER_STOPPED) > 0;
|
||||
}
|
||||
|
||||
void DeviceObject::userStopped(bool value)
|
||||
{
|
||||
if (value)
|
||||
_deviceControl |= USER_STOPPED;
|
||||
else
|
||||
_deviceControl &= ~USER_STOPPED;
|
||||
}
|
||||
|
||||
bool DeviceObject::induvidualAddressDuplication()
|
||||
{
|
||||
return (_deviceControl & OWN_ADDR_DUPL) > 0;
|
||||
}
|
||||
|
||||
void DeviceObject::induvidualAddressDuplication(bool value)
|
||||
{
|
||||
if (value)
|
||||
_deviceControl |= OWN_ADDR_DUPL;
|
||||
else
|
||||
_deviceControl &= ~OWN_ADDR_DUPL;
|
||||
}
|
||||
|
||||
bool DeviceObject::verifyMode()
|
||||
{
|
||||
return (_deviceControl & VERIFY_MODE) > 0;
|
||||
}
|
||||
|
||||
void DeviceObject::verifyMode(bool value)
|
||||
{
|
||||
if (value)
|
||||
_deviceControl |= VERIFY_MODE;
|
||||
else
|
||||
_deviceControl &= ~VERIFY_MODE;
|
||||
}
|
||||
|
||||
bool DeviceObject::safeState()
|
||||
{
|
||||
return (_deviceControl & SAFE_STATE) > 0;
|
||||
}
|
||||
|
||||
void DeviceObject::safeState(bool value)
|
||||
{
|
||||
if (value)
|
||||
_deviceControl |= SAFE_STATE;
|
||||
else
|
||||
_deviceControl &= ~SAFE_STATE;
|
||||
}
|
||||
|
||||
bool DeviceObject::progMode()
|
||||
{
|
||||
return _prgMode == 1;
|
||||
}
|
||||
|
||||
void DeviceObject::progMode(bool value)
|
||||
{
|
||||
if (value)
|
||||
_prgMode = 1;
|
||||
else
|
||||
_prgMode = 0;
|
||||
}
|
||||
|
||||
uint16_t DeviceObject::manufacturerId()
|
||||
{
|
||||
return _manufacturerId;
|
||||
}
|
||||
|
||||
void DeviceObject::manufacturerId(uint16_t value)
|
||||
{
|
||||
_manufacturerId = value;
|
||||
}
|
||||
|
||||
uint32_t DeviceObject::bauNumber()
|
||||
{
|
||||
return _bauNumber;
|
||||
}
|
||||
|
||||
void DeviceObject::bauNumber(uint32_t value)
|
||||
{
|
||||
_bauNumber = value;
|
||||
}
|
||||
|
||||
const char* DeviceObject::orderNumber()
|
||||
{
|
||||
return _orderNumber;
|
||||
}
|
||||
|
||||
void DeviceObject::orderNumber(const char* value)
|
||||
{
|
||||
strncpy(_orderNumber, value, 10);
|
||||
}
|
||||
|
||||
const uint8_t* DeviceObject::hardwareType()
|
||||
{
|
||||
return _hardwareType;
|
||||
}
|
||||
|
||||
void DeviceObject::hardwareType(const uint8_t* value)
|
||||
{
|
||||
pushByteArray(value, 6, _hardwareType);
|
||||
}
|
||||
|
||||
uint16_t DeviceObject::version()
|
||||
{
|
||||
return _version;
|
||||
}
|
||||
|
||||
void DeviceObject::version(uint16_t value)
|
||||
{
|
||||
_version = value;
|
||||
}
|
46
device_object.h
Normal file
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;
|
||||
};
|
102
esp_platform.cpp
Normal file
102
esp_platform.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
#include "esp_platform.h"
|
||||
#include <user_interface.h>
|
||||
#include <Arduino.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
EspPlatform::EspPlatform()
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t EspPlatform::currentIpAddress()
|
||||
{
|
||||
return WiFi.localIP();
|
||||
}
|
||||
|
||||
uint32_t EspPlatform::currentSubnetMask()
|
||||
{
|
||||
return WiFi.subnetMask();
|
||||
}
|
||||
|
||||
uint32_t EspPlatform::currentDefaultGateway()
|
||||
{
|
||||
return WiFi.gatewayIP();
|
||||
}
|
||||
|
||||
void EspPlatform::macAddress(uint8_t * addr)
|
||||
{
|
||||
wifi_get_macaddr(STATION_IF, addr);
|
||||
}
|
||||
|
||||
uint32_t EspPlatform::millis()
|
||||
{
|
||||
return millis();
|
||||
}
|
||||
|
||||
void EspPlatform::mdelay(uint32_t millis)
|
||||
{
|
||||
delay(millis);
|
||||
}
|
||||
|
||||
void EspPlatform::restart()
|
||||
{
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void EspPlatform::fatalError()
|
||||
{
|
||||
const int period = 200;
|
||||
while (true)
|
||||
{
|
||||
if ((millis() % period) > (period / 2))
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
else
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
void EspPlatform::setupMultiCast(uint32_t addr, uint16_t port)
|
||||
{
|
||||
_mulitcastAddr = addr;
|
||||
_mulitcastPort = port;
|
||||
_udp.beginMulticast(WiFi.localIP(), addr, port);
|
||||
}
|
||||
|
||||
void EspPlatform::closeMultiCast()
|
||||
{
|
||||
_udp.stop();
|
||||
}
|
||||
|
||||
bool EspPlatform::sendBytes(uint8_t * buffer, uint16_t len)
|
||||
{
|
||||
_udp.beginPacketMulticast(_mulitcastAddr, _mulitcastPort, WiFi.localIP());
|
||||
_udp.write(buffer, len);
|
||||
_udp.endPacket();
|
||||
return true;
|
||||
}
|
||||
|
||||
int EspPlatform::readBytes(uint8_t * buffer, uint16_t maxLen)
|
||||
{
|
||||
int len = _udp.parsePacket();
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
if (len > maxLen)
|
||||
{
|
||||
printf("udp buffer to small. was %d, needed %d\n", maxLen, len);
|
||||
fatalError();
|
||||
}
|
||||
|
||||
_udp.read(buffer, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
uint8_t * EspPlatform::getEepromBuffer(uint16_t size)
|
||||
{
|
||||
EEPROM.begin(size);
|
||||
return EEPROM.getDataPtr();
|
||||
}
|
||||
|
||||
void EspPlatform::commitToEeprom()
|
||||
{
|
||||
EEPROM.commit();
|
||||
}
|
36
esp_platform.h
Normal file
36
esp_platform.h
Normal file
@ -0,0 +1,36 @@
|
||||
#include "platform.h"
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <WifiUDP.h>
|
||||
|
||||
class EspPlatform : public Platform
|
||||
{
|
||||
public:
|
||||
EspPlatform();
|
||||
|
||||
// ip stuff
|
||||
uint32_t currentIpAddress();
|
||||
uint32_t currentSubnetMask();
|
||||
uint32_t currentDefaultGateway();
|
||||
void macAddress(uint8_t* addr);
|
||||
|
||||
// basic stuff
|
||||
uint32_t millis();
|
||||
void mdelay(uint32_t millis);
|
||||
void restart();
|
||||
void fatalError();
|
||||
|
||||
//multicast
|
||||
void setupMultiCast(uint32_t addr, uint16_t port);
|
||||
void closeMultiCast();
|
||||
bool sendBytes(uint8_t* buffer, uint16_t len);
|
||||
int readBytes(uint8_t* buffer, uint16_t maxLen);
|
||||
|
||||
//memory
|
||||
uint8_t* getEepromBuffer(uint16_t size);
|
||||
void commitToEeprom();
|
||||
private:
|
||||
uint32_t _mulitcastAddr;
|
||||
uint16_t _mulitcastPort;
|
||||
WiFiUDP _udp;
|
||||
};
|
||||
|
191
group_object.cpp
Normal file
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(_table->_tableData[_asap], 15) > 0;
|
||||
}
|
||||
|
||||
bool GroupObject::transmitEnable()
|
||||
{
|
||||
if (!_table)
|
||||
return false;
|
||||
|
||||
return bitRead(_table->_tableData[_asap], 14) > 0;
|
||||
}
|
||||
|
||||
bool GroupObject::valueReadOnInit()
|
||||
{
|
||||
if (!_table)
|
||||
return false;
|
||||
|
||||
return bitRead(_table->_tableData[_asap], 13) > 0;
|
||||
}
|
||||
|
||||
bool GroupObject::writeEnable()
|
||||
{
|
||||
if (!_table)
|
||||
return false;
|
||||
|
||||
return bitRead(_table->_tableData[_asap], 12) > 0;
|
||||
}
|
||||
|
||||
bool GroupObject::readEnable()
|
||||
{
|
||||
if (!_table)
|
||||
return false;
|
||||
|
||||
return bitRead(_table->_tableData[_asap], 11) > 0;
|
||||
}
|
||||
|
||||
bool GroupObject::communicationEnable()
|
||||
{
|
||||
if (!_table)
|
||||
return false;
|
||||
|
||||
return bitRead(_table->_tableData[_asap], 10) > 0;
|
||||
}
|
||||
|
||||
|
||||
Priority GroupObject::priority()
|
||||
{
|
||||
if (!_table)
|
||||
return LowPriority;
|
||||
|
||||
return (Priority)((_table->_tableData[_asap] >> 6) & (3 << 2)) ;
|
||||
}
|
||||
|
||||
uint8_t* GroupObject::valueRef()
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
uint16_t GroupObject::asap()
|
||||
{
|
||||
return _asap;
|
||||
}
|
||||
|
||||
size_t GroupObject::goSize()
|
||||
{
|
||||
size_t size = sizeInTelegram();
|
||||
if (size == 0)
|
||||
return 1;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// see knxspec 3.5.1 p. 178
|
||||
size_t GroupObject::asapValueSize(uint8_t code)
|
||||
{
|
||||
if (code < 7)
|
||||
return 0;
|
||||
if (code < 8)
|
||||
return 1;
|
||||
if (code < 11 || (code > 20 && code < 255))
|
||||
return code - 6;
|
||||
switch (code)
|
||||
{
|
||||
case 11:
|
||||
return 6;
|
||||
case 12:
|
||||
return 8;
|
||||
case 13:
|
||||
return 10;
|
||||
case 14:
|
||||
return 14;
|
||||
case 15:
|
||||
return 5;
|
||||
case 16:
|
||||
return 7;
|
||||
case 17:
|
||||
return 9;
|
||||
case 18:
|
||||
return 11;
|
||||
case 19:
|
||||
return 12;
|
||||
case 20:
|
||||
return 13;
|
||||
case 255:
|
||||
return 252;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
ComFlag GroupObject::commFlag()
|
||||
{
|
||||
return _commFlag;
|
||||
}
|
||||
|
||||
void GroupObject::commFlag(ComFlag value)
|
||||
{
|
||||
_commFlag = value;
|
||||
}
|
||||
|
||||
int32_t GroupObject::objectReadFloat()
|
||||
{
|
||||
uint16_t dptValue = makeWord(_data[0], _data[1]);
|
||||
return dptFromFloat(dptValue);
|
||||
}
|
||||
|
||||
bool GroupObject::objectReadBool()
|
||||
{
|
||||
return _data[0] > 0;
|
||||
}
|
||||
|
||||
void GroupObject::requestObjectRead()
|
||||
{
|
||||
_commFlag = ReadRequest;
|
||||
}
|
||||
|
||||
void GroupObject::objectWritten()
|
||||
{
|
||||
_commFlag = WriteRequest;
|
||||
}
|
||||
|
||||
|
||||
void GroupObject::objectWriteFloat(int32_t value)
|
||||
{
|
||||
uint16_t dptValue = dptToFloat(value);
|
||||
pushWord(dptValue, _data);
|
||||
objectWritten();
|
||||
}
|
||||
|
||||
|
||||
void GroupObject::objectUpdateFloat(int32_t value)
|
||||
{
|
||||
uint16_t dptValue = dptToFloat(value);
|
||||
pushWord(dptValue, _data);
|
||||
_commFlag = cfUpdate;
|
||||
}
|
||||
|
||||
size_t GroupObject::valueSize()
|
||||
{
|
||||
return _dataLength;
|
||||
}
|
||||
|
||||
size_t GroupObject::sizeInTelegram()
|
||||
{
|
||||
uint8_t code = lowByte(_table->_tableData[_asap]);
|
||||
return asapValueSize(code);
|
||||
}
|
111
group_object.h
Normal file
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;
|
||||
};
|
125
group_object_table_object.cpp
Normal file
125
group_object_table_object.cpp
Normal file
@ -0,0 +1,125 @@
|
||||
#include <cstring>
|
||||
|
||||
#include "group_object_table_object.h"
|
||||
#include "group_object.h"
|
||||
#include "bits.h"
|
||||
|
||||
GroupObjectTableObject::GroupObjectTableObject(uint8_t* memoryReference): TableObject(memoryReference)
|
||||
{
|
||||
_groupObjects = 0;
|
||||
_groupObjectCount = 0;
|
||||
}
|
||||
|
||||
void GroupObjectTableObject::readProperty(PropertyID id, uint32_t start, uint32_t count, uint8_t* data)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case PID_OBJECT_TYPE:
|
||||
pushWord(OT_GRP_OBJ_TABLE, data);
|
||||
break;
|
||||
default:
|
||||
TableObject::readProperty(id, start, count, data);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t GroupObjectTableObject::entryCount()
|
||||
{
|
||||
if (loadState() != LS_LOADED)
|
||||
return 0;
|
||||
|
||||
return _tableData[0];
|
||||
}
|
||||
|
||||
|
||||
|
||||
GroupObject& GroupObjectTableObject::get(uint16_t asap)
|
||||
{
|
||||
return _groupObjects[asap - 1];
|
||||
}
|
||||
|
||||
|
||||
uint8_t* GroupObjectTableObject::save(uint8_t* buffer)
|
||||
{
|
||||
return TableObject::save(buffer);
|
||||
}
|
||||
|
||||
|
||||
uint8_t* GroupObjectTableObject::restore(uint8_t* buffer)
|
||||
{
|
||||
buffer = TableObject::restore(buffer);
|
||||
|
||||
_tableData = (uint16_t*)_data;
|
||||
initGroupObjects();
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
GroupObject& GroupObjectTableObject::nextUpdatedObject(bool& valid)
|
||||
{
|
||||
static uint16_t startIdx = 1;
|
||||
|
||||
uint16_t objCount = entryCount();
|
||||
|
||||
for (uint16_t asap = startIdx; asap <= objCount; asap++)
|
||||
{
|
||||
GroupObject& go = get(asap);
|
||||
|
||||
if (go.commFlag() == cfUpdate)
|
||||
{
|
||||
go.commFlag(Ok);
|
||||
startIdx = asap + 1;
|
||||
valid = true;
|
||||
return go;
|
||||
}
|
||||
}
|
||||
|
||||
startIdx = 1;
|
||||
valid = false;
|
||||
return get(1);
|
||||
}
|
||||
|
||||
void GroupObjectTableObject::groupObjects(GroupObject * objs, uint16_t size)
|
||||
{
|
||||
_groupObjects = objs;
|
||||
_groupObjectCount = size;
|
||||
initGroupObjects();
|
||||
}
|
||||
|
||||
void GroupObjectTableObject::beforeStateChange(LoadState& newState)
|
||||
{
|
||||
if (newState != LS_LOADED)
|
||||
return;
|
||||
|
||||
_tableData = (uint16_t*)_data;
|
||||
uint16_t goCount = reverseByteOrder(_tableData[0]);
|
||||
// big endian -> little endian
|
||||
for (size_t i = 0; i <= goCount; i++)
|
||||
_tableData[i] = reverseByteOrder(_tableData[i]);
|
||||
|
||||
if (!initGroupObjects())
|
||||
{
|
||||
newState = LS_ERROR;
|
||||
TableObject::_errorCode = E_SOFTWARE_FAULT;
|
||||
}
|
||||
}
|
||||
|
||||
bool GroupObjectTableObject::initGroupObjects()
|
||||
{
|
||||
if (!_tableData)
|
||||
return false;
|
||||
|
||||
uint16_t goCount = _tableData[0];
|
||||
if (goCount != _groupObjectCount)
|
||||
return false;
|
||||
|
||||
for (uint16_t asap = 1; asap <= goCount; asap++)
|
||||
{
|
||||
GroupObject& go = _groupObjects[asap - 1];
|
||||
go._asap = asap;
|
||||
go._table = this;
|
||||
if (go._dataLength != go.goSize())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
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:
|
||||
|
||||
};
|
298
ip_parameter_object.cpp
Normal file
298
ip_parameter_object.cpp
Normal file
@ -0,0 +1,298 @@
|
||||
#include "ip_parameter_object.h"
|
||||
#include "device_object.h"
|
||||
#include "platform.h"
|
||||
#include "bits.h"
|
||||
|
||||
//224.0.23.12
|
||||
#define DEFAULT_MULTICAST_ADDR 0xE000170C
|
||||
|
||||
IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platform): _deviceObject(deviceObject),
|
||||
_platform(platform)
|
||||
{}
|
||||
|
||||
void IpParameterObject::readProperty(PropertyID propertyId, uint32_t start, uint32_t count, uint8_t* data)
|
||||
{
|
||||
switch (propertyId)
|
||||
{
|
||||
case PID_LOAD_STATE_CONTROL:
|
||||
data[0] = _state;
|
||||
break;
|
||||
case PID_OBJECT_TYPE:
|
||||
pushWord(OT_IP_PARAMETER, data);
|
||||
break;
|
||||
case PID_PROJECT_INSTALLATION_ID:
|
||||
pushWord(_projectInstallationId, data);
|
||||
break;
|
||||
case PID_KNX_INDIVIDUAL_ADDRESS:
|
||||
pushWord(_deviceObject.induvidualAddress(), data);
|
||||
break;
|
||||
case PID_IP_ASSIGNMENT_METHOD:
|
||||
data[0] = _ipAssignmentMethod;
|
||||
break;
|
||||
case PID_IP_CAPABILITIES:
|
||||
data[0] = _ipCapabilities;
|
||||
break;
|
||||
case PID_CURRENT_IP_ADDRESS:
|
||||
pushInt(_platform.currentIpAddress(), data);
|
||||
break;
|
||||
case PID_CURRENT_SUBNET_MASK:
|
||||
pushInt(_platform.currentSubnetMask(), data);
|
||||
break;
|
||||
case PID_CURRENT_DEFAULT_GATEWAY:
|
||||
pushInt(_platform.currentDefaultGateway(), data);
|
||||
break;
|
||||
case PID_IP_ADDRESS:
|
||||
pushInt(_ipAddress, data);
|
||||
break;
|
||||
case PID_SUBNET_MASK:
|
||||
pushInt(_subnetMask, data);
|
||||
break;
|
||||
case PID_DEFAULT_GATEWAY:
|
||||
pushInt(_defaultGateway, data);
|
||||
break;
|
||||
case PID_MAC_ADDRESS:
|
||||
{
|
||||
uint8_t macAddr[6];
|
||||
_platform.macAddress(macAddr);
|
||||
pushByteArray(macAddr, 6, data);
|
||||
break;
|
||||
}
|
||||
case PID_SYSTEM_SETUP_MULTICAST_ADDRESS:
|
||||
pushInt(DEFAULT_MULTICAST_ADDR, data);
|
||||
break;
|
||||
case PID_ROUTING_MULTICAST_ADDRESS:
|
||||
pushInt(_multicastAddress, data);
|
||||
break;
|
||||
case PID_TTL:
|
||||
data[0] = ttl();
|
||||
break;
|
||||
case PID_KNXNETIP_DEVICE_CAPABILITIES:
|
||||
data[0] = 0x1;
|
||||
break;
|
||||
case PID_FRIENDLY_NAME:
|
||||
for (uint8_t i = start; i < start + count; i++)
|
||||
data[i-start] = _friendlyName[i-1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void IpParameterObject::writeProperty(PropertyID id, uint8_t start, uint8_t* data, uint8_t count)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case PID_LOAD_STATE_CONTROL:
|
||||
loadEvent(data);
|
||||
break;
|
||||
case PID_PROJECT_INSTALLATION_ID:
|
||||
_projectInstallationId = getWord(data);
|
||||
break;
|
||||
case PID_KNX_INDIVIDUAL_ADDRESS:
|
||||
_deviceObject.induvidualAddress(getWord(data));
|
||||
break;
|
||||
case PID_IP_ASSIGNMENT_METHOD:
|
||||
_ipAssignmentMethod = data[0];
|
||||
break;
|
||||
case PID_IP_ADDRESS:
|
||||
_ipAddress = getInt(data);
|
||||
break;
|
||||
case PID_SUBNET_MASK:
|
||||
_subnetMask = getInt(data);
|
||||
break;
|
||||
case PID_DEFAULT_GATEWAY:
|
||||
_defaultGateway = getInt(data);
|
||||
break;
|
||||
case PID_ROUTING_MULTICAST_ADDRESS:
|
||||
_multicastAddress = getInt(data);
|
||||
break;
|
||||
case PID_TTL:
|
||||
_ttl = data[0];
|
||||
break;
|
||||
case PID_FRIENDLY_NAME:
|
||||
for (uint8_t i = start; i < start + count; i++)
|
||||
_friendlyName[i-1] = data[i - start];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t IpParameterObject::propertySize(PropertyID id)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case PID_PROJECT_INSTALLATION_ID:
|
||||
return 2;
|
||||
case PID_KNX_INDIVIDUAL_ADDRESS:
|
||||
return 2;
|
||||
case PID_IP_ASSIGNMENT_METHOD:
|
||||
return 1;
|
||||
case PID_IP_ADDRESS:
|
||||
return 4;
|
||||
case PID_SUBNET_MASK:
|
||||
return 4;
|
||||
case PID_DEFAULT_GATEWAY:
|
||||
return 4;
|
||||
case PID_ROUTING_MULTICAST_ADDRESS:
|
||||
return 4;
|
||||
case PID_TTL:
|
||||
return 1;
|
||||
case PID_FRIENDLY_NAME:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t* IpParameterObject::save(uint8_t* buffer)
|
||||
{
|
||||
buffer = pushWord(_projectInstallationId, buffer);
|
||||
buffer = pushByte(_ipAssignmentMethod, buffer);
|
||||
buffer = pushByte(_ipCapabilities, buffer);
|
||||
buffer = pushInt(_ipAddress, buffer);
|
||||
buffer = pushInt(_subnetMask, buffer);
|
||||
buffer = pushInt(_defaultGateway, buffer);
|
||||
buffer = pushInt(_multicastAddress, buffer);
|
||||
buffer = pushByte(_ttl, buffer);
|
||||
buffer = pushByteArray((uint8_t*)_friendlyName, 30, buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
uint8_t* IpParameterObject::restore(uint8_t* buffer)
|
||||
{
|
||||
buffer = popWord(_projectInstallationId, buffer);
|
||||
buffer = popByte(_ipAssignmentMethod, buffer);
|
||||
buffer = popByte(_ipCapabilities, buffer);
|
||||
buffer = popInt(_ipAddress, buffer);
|
||||
buffer = popInt(_subnetMask, buffer);
|
||||
buffer = popInt(_defaultGateway, buffer);
|
||||
buffer = popInt(_multicastAddress, buffer);
|
||||
buffer = popByte(_ttl, buffer);
|
||||
buffer = popByteArray((uint8_t*)_friendlyName, 30, buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
uint32_t IpParameterObject::multicastAddress() const
|
||||
{
|
||||
if (_multicastAddress == 0)
|
||||
return DEFAULT_MULTICAST_ADDR;
|
||||
|
||||
return _multicastAddress;
|
||||
}
|
||||
|
||||
void IpParameterObject::loadEvent(uint8_t* data)
|
||||
{
|
||||
switch (_state)
|
||||
{
|
||||
case LS_UNLOADED:
|
||||
loadEventUnloaded(data);
|
||||
break;
|
||||
case LS_LOADING:
|
||||
loadEventLoading(data);
|
||||
break;
|
||||
case LS_LOADED:
|
||||
loadEventLoaded(data);
|
||||
break;
|
||||
case LS_ERROR:
|
||||
loadEventError(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void IpParameterObject::loadState(LoadState newState)
|
||||
{
|
||||
if (newState == _state)
|
||||
return;
|
||||
//beforeStateChange(newState);
|
||||
_state = newState;
|
||||
}
|
||||
|
||||
void IpParameterObject::loadEventUnloaded(uint8_t* data)
|
||||
{
|
||||
uint8_t event = data[0];
|
||||
switch (event)
|
||||
{
|
||||
case LE_NOOP:
|
||||
case LE_LOAD_COMPLETED:
|
||||
case LE_ADDITIONAL_LOAD_CONTROLS:
|
||||
case LE_UNLOAD:
|
||||
break;
|
||||
case LE_START_LOADING:
|
||||
loadState(LS_LOADING);
|
||||
break;
|
||||
default:
|
||||
loadState(LS_ERROR);
|
||||
_errorCode = E_GOT_UNDEF_LOAD_CMD;
|
||||
}
|
||||
}
|
||||
|
||||
void IpParameterObject::loadEventLoading(uint8_t* data)
|
||||
{
|
||||
uint8_t event = data[0];
|
||||
switch (event)
|
||||
{
|
||||
case LE_NOOP:
|
||||
case LE_START_LOADING:
|
||||
break;
|
||||
case LE_LOAD_COMPLETED:
|
||||
loadState(LS_LOADED);
|
||||
break;
|
||||
case LE_UNLOAD:
|
||||
loadState(LS_UNLOADED);
|
||||
break;
|
||||
case LE_ADDITIONAL_LOAD_CONTROLS:
|
||||
additionalLoadControls(data);
|
||||
break;
|
||||
default:
|
||||
loadState(LS_ERROR);
|
||||
_errorCode = E_GOT_UNDEF_LOAD_CMD;
|
||||
}
|
||||
}
|
||||
|
||||
void IpParameterObject::loadEventLoaded(uint8_t* data)
|
||||
{
|
||||
uint8_t event = data[0];
|
||||
switch (event)
|
||||
{
|
||||
case LE_NOOP:
|
||||
case LE_LOAD_COMPLETED:
|
||||
break;
|
||||
case LE_START_LOADING:
|
||||
loadState(LS_LOADING);
|
||||
break;
|
||||
case LE_UNLOAD:
|
||||
loadState(LS_UNLOADED);
|
||||
break;
|
||||
case LE_ADDITIONAL_LOAD_CONTROLS:
|
||||
loadState(LS_ERROR);
|
||||
_errorCode = E_INVALID_OPCODE;
|
||||
break;
|
||||
default:
|
||||
loadState(LS_ERROR);
|
||||
_errorCode = E_GOT_UNDEF_LOAD_CMD;
|
||||
}
|
||||
}
|
||||
|
||||
void IpParameterObject::loadEventError(uint8_t* data)
|
||||
{
|
||||
uint8_t event = data[0];
|
||||
switch (event)
|
||||
{
|
||||
case LE_NOOP:
|
||||
case LE_LOAD_COMPLETED:
|
||||
case LE_ADDITIONAL_LOAD_CONTROLS:
|
||||
case LE_START_LOADING:
|
||||
break;
|
||||
case LE_UNLOAD:
|
||||
loadState(LS_UNLOADED);
|
||||
break;
|
||||
default:
|
||||
loadState(LS_ERROR);
|
||||
_errorCode = E_GOT_UNDEF_LOAD_CMD;
|
||||
}
|
||||
}
|
||||
|
||||
void IpParameterObject::additionalLoadControls(uint8_t* data)
|
||||
{
|
||||
loadState(LS_ERROR);
|
||||
_errorCode = E_INVALID_OPCODE;
|
||||
return;
|
||||
}
|
42
ip_parameter_object.h
Normal file
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;
|
||||
};
|
75
knx-esp.vcxitems
Normal file
75
knx-esp.vcxitems
Normal file
@ -0,0 +1,75 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Label="Globals">
|
||||
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
|
||||
<HasSharedItems>true</HasSharedItems>
|
||||
<ItemsProjectGuid>{83464ca3-e0d0-4486-82f4-f658f31ddc69}</ItemsProjectGuid>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ProjectCapability Include="SourceItemsFromImports" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="$(MSBuildThisFileDirectory)readme.txt" />
|
||||
<Text Include="$(MSBuildThisFileDirectory)library.properties" />
|
||||
<Text Include="$(MSBuildThisFileDirectory)knx_esp.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<!-- <ClInclude Include="$(MSBuildThisFileDirectory)knx_esp.h" /> -->
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)address_table_object.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)apdu.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)application_layer.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)application_program_object.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)association_table_object.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)bau.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)bau57B0.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)bits.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)cemi_frame.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)datapoint_types.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)data_link_layer.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)device_object.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)esp_platform.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)group_object.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)group_object_table_object.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)interface_object.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ip_parameter_object.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)knx_types.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)memory.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)network_layer.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)npdu.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)platform.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)property_types.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)save_restore.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)table_object.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)tpdu.h" />
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)transport_layer.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)address_table_object.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)apdu.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)application_layer.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)application_program_object.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)association_table_object.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)bau.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)bau57B0.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)bits.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)cemi_frame.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)datapoint_types.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)data_link_layer.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)device_object.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)esp_platform.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)group_object.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)group_object_table_object.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)ip_parameter_object.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)memory.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)network_layer.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)npdu.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)table_object.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)tpdu.cpp" />
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)transport_layer.cpp" />
|
||||
</ItemGroup>
|
||||
</Project>
|
171
knx-esp.vcxitems.filters
Normal file
171
knx-esp.vcxitems.filters
Normal file
@ -0,0 +1,171 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;s</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)address_table_object.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)apdu.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)application_layer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)application_program_object.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)association_table_object.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)bau.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)bau57B0.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)bits.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)cemi_frame.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)data_link_layer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)datapoint_types.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)device_object.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)esp_platform.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)group_object.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)group_object_table_object.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)ip_parameter_object.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)memory.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)network_layer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)npdu.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)table_object.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)tpdu.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(MSBuildThisFileDirectory)transport_layer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="$(MSBuildThisFileDirectory)readme.txt" />
|
||||
<Text Include="$(MSBuildThisFileDirectory)library.properties" />
|
||||
<Text Include="$(MSBuildThisFileDirectory)knx_esp.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</Text>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)address_table_object.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)apdu.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)application_layer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)application_program_object.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)association_table_object.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)bau.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)bau57B0.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)bits.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)cemi_frame.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)data_link_layer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)datapoint_types.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)device_object.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)esp_platform.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)group_object.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)group_object_table_object.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)interface_object.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)ip_parameter_object.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)knx_types.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)memory.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)network_layer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)npdu.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)platform.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)property_types.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)save_restore.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)table_object.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)tpdu.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(MSBuildThisFileDirectory)transport_layer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
19
knx_esp.h
Normal file
19
knx_esp.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
Name: knx_esp.h
|
||||
Created: 01.03.2018 21:14:55
|
||||
Author: tkunze
|
||||
Editor: http://www.visualmicro.com
|
||||
*/
|
||||
|
||||
#ifndef _knx_esp_h
|
||||
#define _knx_esp_h
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include "arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
103
knx_types.h
Normal file
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,
|
||||
};
|
9
library.properties
Normal file
9
library.properties
Normal file
@ -0,0 +1,9 @@
|
||||
name=knx_esp
|
||||
version=1.0.0
|
||||
author=tkunze
|
||||
maintainer=tkunze
|
||||
sentence=knx_esp Library
|
||||
paragraph=
|
||||
category=Uncategorized
|
||||
url=https://github/knx_esp
|
||||
architectures=*
|
47
memory.cpp
Normal file
47
memory.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
#include "memory.h"
|
||||
|
||||
Memory::Memory(Platform & platform): _platform(platform)
|
||||
{
|
||||
}
|
||||
|
||||
void Memory::memoryModified()
|
||||
{
|
||||
_modified = true;
|
||||
}
|
||||
|
||||
bool Memory::isMemoryModified()
|
||||
{
|
||||
return _modified;
|
||||
}
|
||||
|
||||
void Memory::readMemory()
|
||||
{
|
||||
//_data = _platform.getEepromBuffer(512);
|
||||
//uint8_t* buffer = _data;
|
||||
//int size = _saveCount;
|
||||
//for (int i = 0; i < size; i++)
|
||||
//{
|
||||
// buffer = _saveRestores[i]->restore(buffer);
|
||||
//}
|
||||
}
|
||||
|
||||
void Memory::writeMemory()
|
||||
{
|
||||
//uint8_t* buffer = _data;
|
||||
//int size = _saveCount;
|
||||
//for (int i = 0; i < size; i++)
|
||||
//{
|
||||
// buffer = _saveRestores[i]->save(buffer);
|
||||
//}
|
||||
//_platform.commitToEeprom();
|
||||
//_modified = false;
|
||||
}
|
||||
|
||||
void Memory::addSaveRestore(SaveRestore * obj)
|
||||
{
|
||||
if (_saveCount >= MAXSAVE - 1)
|
||||
return;
|
||||
|
||||
_saveRestores[_saveCount] = obj;
|
||||
_saveCount += 1;
|
||||
}
|
24
memory.h
Normal file
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;
|
||||
};
|
126
network_layer.cpp
Normal file
126
network_layer.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
#include "network_layer.h"
|
||||
#include "tpdu.h"
|
||||
#include "cemi_frame.h"
|
||||
#include "data_link_layer.h"
|
||||
|
||||
NetworkLayer::NetworkLayer(TransportLayer& layer): _transportLayer(layer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void NetworkLayer::dataLinkLayer(DataLinkLayer& layer)
|
||||
{
|
||||
_dataLinkLayer = &layer;
|
||||
}
|
||||
|
||||
uint8_t NetworkLayer::hopCount() const
|
||||
{
|
||||
return _hopCount;
|
||||
}
|
||||
|
||||
void NetworkLayer::hopCount(uint8_t value)
|
||||
{
|
||||
_hopCount = value & 0x7;
|
||||
}
|
||||
|
||||
void NetworkLayer::dataIndication(AckType ack, AddressType addrType, uint16_t destination, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source)
|
||||
{
|
||||
HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter;
|
||||
if (addrType == InduvidualAddress)
|
||||
{
|
||||
//if (npdu.octetCount() > 0)
|
||||
//{
|
||||
// print.print("<- NL ");
|
||||
// npdu.frame().apdu().printPDU();
|
||||
//}
|
||||
_transportLayer.dataIndividualIndication(destination, hopType, priority, source, npdu.tpdu());
|
||||
return;
|
||||
}
|
||||
// group-address type
|
||||
if (destination != 0)
|
||||
{
|
||||
_transportLayer.dataGroupIndication(destination, hopType, priority, source, npdu.tpdu());
|
||||
return;
|
||||
}
|
||||
// destination == 0
|
||||
_transportLayer.dataBroadcastIndication(hopType, priority, source, npdu.tpdu());
|
||||
|
||||
}
|
||||
|
||||
void NetworkLayer::dataConfirm(AckType ack, AddressType addressType, uint16_t destination, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status)
|
||||
{
|
||||
HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter;
|
||||
if (addressType == InduvidualAddress)
|
||||
{
|
||||
_transportLayer.dataIndividualConfirm(ack, destination, hopType, priority, npdu.tpdu(), status);
|
||||
return;
|
||||
}
|
||||
// group-address type
|
||||
if (destination != 0)
|
||||
{
|
||||
_transportLayer.dataGroupConfirm(ack, source, destination, hopType, priority, npdu.tpdu(), status);
|
||||
return;
|
||||
}
|
||||
// destination == 0
|
||||
_transportLayer.dataBroadcastConfirm(ack, hopType, priority, npdu.tpdu(), status);
|
||||
}
|
||||
|
||||
void NetworkLayer::systemBroadcastIndication(AckType ack, FrameFormat format, NPDU& npdu, Priority priority, uint16_t source)
|
||||
{
|
||||
HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter;
|
||||
_transportLayer.dataBroadcastIndication(hopType, priority, source, npdu.tpdu());
|
||||
}
|
||||
|
||||
void NetworkLayer::systemBroadcastConfirm(AckType ack, FrameFormat format, Priority priority, uint16_t source, NPDU& npdu, bool status)
|
||||
{
|
||||
HopCountType hopType = npdu.hopCount() == 7 ? UnlimitedRouting : NetworkLayerParameter;
|
||||
_transportLayer.dataBroadcastConfirm(ack, hopType, priority, npdu.tpdu(), status);
|
||||
}
|
||||
|
||||
void NetworkLayer::dataIndividualRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu)
|
||||
{
|
||||
//if (tpdu.apdu().length() > 0)
|
||||
//{
|
||||
// print.print("-> NL ");
|
||||
// tpdu.apdu().printPDU();
|
||||
//}
|
||||
sendDataRequest(tpdu, hopType, ack, destination, priority, InduvidualAddress);
|
||||
}
|
||||
|
||||
void NetworkLayer::sendDataRequest(TPDU &tpdu, HopCountType hopType, AckType ack, uint16_t destination, Priority priority, AddressType addrType)
|
||||
{
|
||||
NPDU& npdu = tpdu.frame().npdu();
|
||||
|
||||
if (hopType == UnlimitedRouting)
|
||||
npdu.hopCount(7);
|
||||
else
|
||||
npdu.hopCount(_hopCount);
|
||||
|
||||
FrameFormat frameFormat = npdu.octetCount() > 15 ? ExtendedFrame : StandardFrame;
|
||||
|
||||
_dataLinkLayer->dataRequest(ack, addrType, destination, frameFormat, priority, npdu);
|
||||
}
|
||||
|
||||
void NetworkLayer::dataGroupRequest(AckType ack, uint16_t destination, HopCountType hopType, Priority priority, TPDU& tpdu)
|
||||
{
|
||||
sendDataRequest(tpdu, hopType, ack, destination, priority, GroupAddress);
|
||||
}
|
||||
|
||||
void NetworkLayer::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu)
|
||||
{
|
||||
sendDataRequest(tpdu, hopType, ack, 0, priority, GroupAddress);
|
||||
}
|
||||
|
||||
void NetworkLayer::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, TPDU& tpdu)
|
||||
{
|
||||
NPDU& npdu = tpdu.frame().npdu();
|
||||
|
||||
if (hopType == UnlimitedRouting)
|
||||
npdu.hopCount(7);
|
||||
else
|
||||
npdu.hopCount(_hopCount);
|
||||
|
||||
FrameFormat frameFormat = npdu.octetCount() > 15 ? ExtendedFrame : StandardFrame;
|
||||
|
||||
_dataLinkLayer->systemBroadcastRequest(ack, frameFormat, priority, npdu);
|
||||
}
|
38
network_layer.h
Normal file
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
|
||||
};
|
19
readme.txt
Normal file
19
readme.txt
Normal file
@ -0,0 +1,19 @@
|
||||
Arduino Compatible Cross Platform C++ Library Project : For more information see http://www.visualmicro.com
|
||||
|
||||
This project works exactly the same way as an Arduino library.
|
||||
|
||||
Add this project to any solution that contains an Arduino project and #include <headers.h> in code as you would any normal Arduino library headers.
|
||||
|
||||
To enable intellisense and to support live build discovery outside of the "standard" Arduino library locations, ensure that the library is added as a shared project reference to the master Arduino project. To do this, right click the master project "References" node and then click "Add Reference". A window will open and the library will appear on the "Shared Projects" tab. Click the checkbox next to the library name to add the reference. If this library is moved the shared referencemust be removed and re-added.
|
||||
|
||||
VS2017 has a bug, workround: After moving existing source code within a "library or shared project", close and re-open the solution.
|
||||
|
||||
Visual Studio will display intellisense for libraries based on the platform/board that has been specified for the currently active "Startup Project" of the current solution.
|
||||
|
||||
|
||||
IMPORTANT: The arduino.cc Library Rules must be followed when adding code or restructing libraries.
|
||||
|
||||
|
||||
|
||||
|
||||
blog: http://www.visualmicro.com/post/2017/01/16/Arduino-Cross-Platform-Library-Development.aspx
|
10
save_restore.h
Normal file
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 10;
|
||||
|
||||
//case PID_MCB_TABLE:
|
||||
// TODO
|
||||
// break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
TableObject::~TableObject()
|
||||
{
|
||||
if (_data != 0)
|
||||
free(_data);
|
||||
}
|
||||
|
||||
LoadState TableObject::loadState()
|
||||
{
|
||||
return _state;
|
||||
}
|
||||
|
||||
void TableObject::loadState(LoadState newState)
|
||||
{
|
||||
if (newState == _state)
|
||||
return;
|
||||
beforeStateChange(newState);
|
||||
_state = newState;
|
||||
}
|
||||
|
||||
|
||||
uint8_t* TableObject::save(uint8_t* buffer)
|
||||
{
|
||||
buffer = pushByte(_state, buffer);
|
||||
buffer = pushByte(_errorCode, buffer);
|
||||
buffer = pushInt(_size, buffer);
|
||||
buffer = pushByteArray(_data, _size, buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
uint8_t* TableObject::restore(uint8_t* buffer)
|
||||
{
|
||||
uint8_t state = 0;
|
||||
uint8_t errorCode = 0;
|
||||
buffer = popByte(state, buffer);
|
||||
buffer = popByte(errorCode, buffer);
|
||||
_state = (LoadState)state;
|
||||
_errorCode = (ErrorCode)errorCode;
|
||||
|
||||
buffer = popInt(_size, buffer);
|
||||
|
||||
if (_data)
|
||||
free(_data);
|
||||
|
||||
_data = (uint8_t*) malloc(_size);
|
||||
|
||||
buffer = popByteArray(_data, _size, buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
uint32_t TableObject::tableReference()
|
||||
{
|
||||
return (uint32_t)(_data - _memoryReference);
|
||||
}
|
||||
|
||||
bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte)
|
||||
{
|
||||
if (_data)
|
||||
{
|
||||
free(_data);
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
_data = (uint8_t*)malloc(size);
|
||||
if (!_data)
|
||||
return false;
|
||||
|
||||
_size = size;
|
||||
|
||||
if (doFill)
|
||||
memset(_data, fillByte, size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TableObject::loadEvent(uint8_t* data)
|
||||
{
|
||||
switch (_state)
|
||||
{
|
||||
case LS_UNLOADED:
|
||||
loadEventUnloaded(data);
|
||||
break;
|
||||
case LS_LOADING:
|
||||
loadEventLoading(data);
|
||||
break;
|
||||
case LS_LOADED:
|
||||
loadEventLoaded(data);
|
||||
break;
|
||||
case LS_ERROR:
|
||||
loadEventError(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void TableObject::loadEventUnloaded(uint8_t* data)
|
||||
{
|
||||
uint8_t event = data[0];
|
||||
switch (event)
|
||||
{
|
||||
case LE_NOOP:
|
||||
case LE_LOAD_COMPLETED:
|
||||
case LE_ADDITIONAL_LOAD_CONTROLS:
|
||||
case LE_UNLOAD:
|
||||
break;
|
||||
case LE_START_LOADING:
|
||||
loadState(LS_LOADING);
|
||||
break;
|
||||
default:
|
||||
loadState(LS_ERROR);
|
||||
_errorCode = E_GOT_UNDEF_LOAD_CMD;
|
||||
}
|
||||
}
|
||||
|
||||
void TableObject::loadEventLoading(uint8_t* data)
|
||||
{
|
||||
uint8_t event = data[0];
|
||||
switch (event)
|
||||
{
|
||||
case LE_NOOP:
|
||||
case LE_START_LOADING:
|
||||
break;
|
||||
case LE_LOAD_COMPLETED:
|
||||
loadState(LS_LOADED);
|
||||
break;
|
||||
case LE_UNLOAD:
|
||||
loadState(LS_UNLOADED);
|
||||
break;
|
||||
case LE_ADDITIONAL_LOAD_CONTROLS:
|
||||
additionalLoadControls(data);
|
||||
break;
|
||||
default:
|
||||
loadState(LS_ERROR);
|
||||
_errorCode = E_GOT_UNDEF_LOAD_CMD;
|
||||
}
|
||||
}
|
||||
|
||||
void TableObject::loadEventLoaded(uint8_t* data)
|
||||
{
|
||||
uint8_t event = data[0];
|
||||
switch (event)
|
||||
{
|
||||
case LE_NOOP:
|
||||
case LE_LOAD_COMPLETED:
|
||||
break;
|
||||
case LE_START_LOADING:
|
||||
loadState(LS_LOADING);
|
||||
break;
|
||||
case LE_UNLOAD:
|
||||
loadState(LS_UNLOADED);
|
||||
break;
|
||||
case LE_ADDITIONAL_LOAD_CONTROLS:
|
||||
loadState(LS_ERROR);
|
||||
_errorCode = E_INVALID_OPCODE;
|
||||
break;
|
||||
default:
|
||||
loadState(LS_ERROR);
|
||||
_errorCode = E_GOT_UNDEF_LOAD_CMD;
|
||||
}
|
||||
}
|
||||
|
||||
void TableObject::loadEventError(uint8_t* data)
|
||||
{
|
||||
uint8_t event = data[0];
|
||||
switch (event)
|
||||
{
|
||||
case LE_NOOP:
|
||||
case LE_LOAD_COMPLETED:
|
||||
case LE_ADDITIONAL_LOAD_CONTROLS:
|
||||
case LE_START_LOADING:
|
||||
break;
|
||||
case LE_UNLOAD:
|
||||
loadState(LS_UNLOADED);
|
||||
break;
|
||||
default:
|
||||
loadState(LS_ERROR);
|
||||
_errorCode = E_GOT_UNDEF_LOAD_CMD;
|
||||
}
|
||||
}
|
||||
|
||||
void TableObject::additionalLoadControls(uint8_t* data)
|
||||
{
|
||||
if (data[1] != 0x0B) // Data Relative Allocation
|
||||
{
|
||||
loadState(LS_ERROR);
|
||||
_errorCode = E_INVALID_OPCODE;
|
||||
return;
|
||||
}
|
||||
|
||||
size_t size = ((data[2] << 24) | (data[3] << 16) | (data[4] << 8) | data[5]);
|
||||
bool doFill = data[6] == 0x1;
|
||||
uint8_t fillByte = data[7];
|
||||
if (!allocTable(size, doFill, fillByte))
|
||||
{
|
||||
loadState(LS_ERROR);
|
||||
_errorCode = E_MAX_TABLE_LENGTH_EXEEDED;
|
||||
}
|
||||
}
|
33
table_object.h
Normal file
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