knx/src/knxold/application_layer.cpp
OnlineCaveman 6c4a10e189 Fault in change tracking
Renaming subdir knx to force changes
2022-10-17 19:51:31 +02:00

1287 lines
52 KiB
C++

#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>
const SecurityControl ApplicationLayer::noSecurity {.toolAccess=false, .dataSecurity=DataSecurity::None};
ApplicationLayer::ApplicationLayer(BusAccessUnit& bau) : _bau(bau)
{
}
void ApplicationLayer::transportLayer(TransportLayer& layer)
{
_transportLayer = &layer;
}
void ApplicationLayer::associationTableObject(AssociationTableObject& assocTable)
{
_assocTable = &assocTable;
}
#pragma region TL Callbacks
void ApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu)
{
dataGroupIndication(hopType, priority, tsap, apdu, noSecurity);
}
void ApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl)
{
if (_assocTable == nullptr)
return;
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;
}
uint16_t startIdx = 0;
int32_t asap = _assocTable->nextAsap(tsap, startIdx);
for (; asap != -1; asap = _assocTable->nextAsap(tsap, startIdx))
{
switch (apdu.type())
{
case GroupValueRead:
_bau.groupValueReadIndication(asap, priority, hopType, secCtrl);
break;
case GroupValueResponse:
_bau.groupValueReadAppLayerConfirm(asap, priority, hopType, secCtrl, data, len);
break;
case GroupValueWrite:
_bau.groupValueWriteIndication(asap, priority, hopType, secCtrl, data, len);
default:
/* other apdutypes are not valid here. If they appear do nothing */
break;
}
}
}
void ApplicationLayer::dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status)
{
dataGroupConfirm(ack, hopType, priority, tsap, apdu, noSecurity, status);
}
void ApplicationLayer::dataGroupConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl &secCtrl, bool status)
{
switch (apdu.type())
{
case GroupValueRead:
_bau.groupValueReadLocalConfirm(ack, _savedAsapReadRequest, priority, hopType, secCtrl, status);
break;
case GroupValueResponse:
_bau.groupValueReadResponseConfirm(ack, _savedAsapResponse, priority, hopType, secCtrl, apdu.data(), apdu.length() - 1, status);
break;
case GroupValueWrite:
_bau.groupValueWriteLocalConfirm(ack, _savedAsapWriteRequest, priority, hopType, secCtrl, apdu.data(), apdu.length() - 1, status);
break;
default:
print("datagroup-confirm: unhandled APDU-Type: ");
println(apdu.type());
}
}
void ApplicationLayer::dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu)
{
dataBroadcastIndication(hopType, priority, source, apdu, noSecurity);
}
void ApplicationLayer::dataBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl& secCtrl)
{
uint8_t* data = apdu.data();
switch (apdu.type())
{
case IndividualAddressWrite:
{
uint16_t newAddress;
popWord(newAddress, data + 1);
_bau.individualAddressWriteIndication(hopType, secCtrl, newAddress);
break;
}
case IndividualAddressRead:
_bau.individualAddressReadIndication(hopType, secCtrl);
break;
case IndividualAddressResponse:
_bau.individualAddressReadAppLayerConfirm(hopType, secCtrl, apdu.frame().sourceAddress());
break;
case IndividualAddressSerialNumberRead:
{
uint8_t* knxSerialNumber = &data[1];
_bau.individualAddressSerialNumberReadIndication(priority, hopType, secCtrl, knxSerialNumber);
break;
}
case IndividualAddressSerialNumberResponse:
{
uint16_t domainAddress;
popWord(domainAddress, data + 7);
_bau.individualAddressSerialNumberReadAppLayerConfirm(hopType, secCtrl, data + 1, apdu.frame().sourceAddress(),
domainAddress);
break;
}
case IndividualAddressSerialNumberWrite:
{
uint8_t* knxSerialNumber = &data[1];
uint16_t newIndividualAddress;
popWord(newIndividualAddress, &data[7]);
_bau.individualAddressSerialNumberWriteIndication(priority, hopType, secCtrl, newIndividualAddress, knxSerialNumber);
break;
}
default:
print("Broadcast-indication: unhandled APDU-Type: ");
println(apdu.type());
break;
}
}
void ApplicationLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, bool status)
{
dataBroadcastConfirm(ack, hopType, priority, apdu, noSecurity, status);
}
void ApplicationLayer::dataBroadcastConfirm(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl, bool status)
{
uint8_t* data = apdu.data();
switch (apdu.type())
{
case IndividualAddressWrite:
{
uint16_t newAddress;
popWord(newAddress, data + 1);
_bau.individualAddressWriteLocalConfirm(ack, hopType, secCtrl, newAddress, status);
break;
}
case IndividualAddressRead:
_bau.individualAddressReadLocalConfirm(ack, hopType, secCtrl, status);
break;
case IndividualAddressResponse:
_bau.individualAddressReadResponseConfirm(ack, hopType, secCtrl, status);
break;
case IndividualAddressSerialNumberRead:
_bau.individualAddressSerialNumberReadLocalConfirm(ack, hopType, secCtrl, data + 1, status);
break;
case IndividualAddressSerialNumberResponse:
{
uint16_t domainAddress;
popWord(domainAddress, data + 7);
_bau.individualAddressSerialNumberReadResponseConfirm(ack, hopType, secCtrl, data + 1, domainAddress, status);
break;
}
case IndividualAddressSerialNumberWrite:
{
uint16_t newAddress;
popWord(newAddress, data + 7);
_bau.individualAddressSerialNumberWriteLocalConfirm(ack, hopType, secCtrl, data + 1, newAddress, status);
break;
}
default:
print("Broadcast-confirm: unhandled APDU-Type: ");
println(apdu.type());
break;
}
}
void ApplicationLayer::dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu)
{
dataSystemBroadcastIndication(hopType, priority, source, apdu, noSecurity);
}
void ApplicationLayer::dataSystemBroadcastIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu, const SecurityControl &secCtrl)
{
const uint8_t* data = apdu.data();
switch (apdu.type())
{
// TODO: testInfo could be of any length
case SystemNetworkParameterRead:
{
uint16_t objectType;
uint16_t propertyId;
uint8_t testInfo[2];
popWord(objectType, data + 1);
popWord(propertyId, data + 3);
popByte(testInfo[0], data + 4);
popByte(testInfo[1], data + 5);
propertyId = (propertyId >> 4) & 0x0FFF;;
testInfo[0] &= 0x0F;
_bau.systemNetworkParameterReadIndication(priority, hopType, secCtrl, objectType, propertyId, testInfo, sizeof(testInfo));
break;
}
case DomainAddressSerialNumberWrite:
{
const uint8_t* knxSerialNumber = &data[1];
const uint8_t* domainAddress = &data[7];
_bau.domainAddressSerialNumberWriteIndication(priority, hopType, secCtrl, domainAddress, knxSerialNumber);
break;
}
case DomainAddressSerialNumberRead:
{
const uint8_t* knxSerialNumber = &data[1];
_bau.domainAddressSerialNumberReadIndication(priority, hopType, secCtrl, knxSerialNumber);
break;
}
default:
print("SystemBroadcast-indication: unhandled APDU-Type: ");
println(apdu.type());
break;
}
}
void ApplicationLayer::dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, bool status) {
dataSystemBroadcastConfirm(hopType, priority, apdu, noSecurity, status);
}
void ApplicationLayer::dataSystemBroadcastConfirm(HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl, bool status)
{
const uint8_t* data = apdu.data();
switch (apdu.type())
{
// TODO: testInfo could be of any length
case SystemNetworkParameterRead:
{
uint16_t objectType;
uint16_t propertyId;
uint8_t testInfo[2];
popWord(objectType, data + 1);
popWord(propertyId, data + 3);
popByte(testInfo[0], data + 4);
popByte(testInfo[1], data + 5);
propertyId = (propertyId >> 4) & 0x0FFF;;
testInfo[0] &= 0x0F;
_bau.systemNetworkParameterReadLocalConfirm(priority, hopType, secCtrl, objectType, propertyId, testInfo, sizeof(testInfo), status);
break;
}
case DomainAddressSerialNumberWrite:
{
const uint8_t* knxSerialNumber = &data[1];
const uint8_t* domainAddress = &data[7];
_bau.domainAddressSerialNumberWriteLocalConfirm(priority, hopType, secCtrl, domainAddress, knxSerialNumber, status);
break;
}
case DomainAddressSerialNumberRead:
{
const uint8_t* knxSerialNumber = &data[1];
_bau.domainAddressSerialNumberReadLocalConfirm(priority, hopType, secCtrl, knxSerialNumber, status);
break;
}
default:
print("SystemBroadcast-confirm: unhandled APDU-Type: ");
println(apdu.type());
break;
}
}
void ApplicationLayer::dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t source, APDU& apdu)
{
dataIndividualIndication(hopType, priority, source, apdu, noSecurity);
}
void ApplicationLayer::dataIndividualIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl)
{
individualIndication(hopType, priority, tsap, apdu, secCtrl);
}
void ApplicationLayer::dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, bool status)
{
dataIndividualConfirm(ack, hopType, priority, tsap, apdu, noSecurity, status);
}
void ApplicationLayer::dataIndividualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl &secCtrl, bool status)
{
individualConfirm(ack, hopType, priority, tsap, apdu, secCtrl, status);
}
void ApplicationLayer::connectIndication(uint16_t tsap)
{
_connectedTsap = tsap;
}
void ApplicationLayer::connectConfirm(uint16_t destination, uint16_t tsap, bool status)
{
if (status)
{
_connectedTsap = tsap;
_bau.connectConfirm(tsap);
}
else
_connectedTsap = -1;
}
void ApplicationLayer::disconnectIndication(uint16_t tsap)
{
_connectedTsap = -1;
}
void ApplicationLayer::disconnectConfirm(Priority priority, uint16_t tsap, bool status)
{
_connectedTsap = -1;
}
void ApplicationLayer::dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu)
{
dataConnectedIndication(priority, tsap, apdu, noSecurity);
}
void ApplicationLayer::dataConnectedIndication(Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl)
{
individualIndication(NetworkLayerParameter, priority, tsap, apdu, secCtrl);
}
void ApplicationLayer::dataConnectedConfirm(uint16_t tsap)
{
dataConnectedConfirm(tsap, noSecurity);
}
void ApplicationLayer::dataConnectedConfirm(uint16_t tsap, const SecurityControl& secCtrl)
{
//FIXME: implement dataConnectedConfirm DataSecurity
}
#pragma endregion
void ApplicationLayer::groupValueReadRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl)
{
if (_assocTable == nullptr)
return;
_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
dataGroupRequest(ack, hopType, priority, tsap, apdu, secCtrl);
dataGroupIndication(hopType, priority, tsap, apdu, secCtrl);
}
void ApplicationLayer::groupValueReadResponse(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t * data, uint8_t dataLength)
{
_savedAsapResponse = asap;
groupValueSend(GroupValueResponse, ack, asap, priority, hopType, secCtrl, data, dataLength);
}
void ApplicationLayer::groupValueWriteRequest(AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t * data, uint8_t dataLength)
{
_savedAsapWriteRequest = asap;
groupValueSend(GroupValueWrite, ack, asap, priority, hopType, secCtrl, data, dataLength);
}
void ApplicationLayer::individualAddressWriteRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl, uint16_t newaddress)
{
CemiFrame frame(3);
APDU& apdu = frame.apdu();
apdu.type(IndividualAddressWrite);
uint8_t* apduData = apdu.data();
pushWord(newaddress, apduData + 1);
dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl);
}
void ApplicationLayer::individualAddressReadRequest(AckType ack, HopCountType hopType, const SecurityControl& secCtrl)
{
CemiFrame frame(1);
APDU& apdu = frame.apdu();
apdu.type(IndividualAddressRead);
dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl);
}
void ApplicationLayer::individualAddressReadResponse(AckType ack, HopCountType hopType, const SecurityControl &secCtrl)
{
CemiFrame frame(1);
APDU& apdu = frame.apdu();
apdu.type(IndividualAddressResponse);
dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl);
}
void ApplicationLayer::individualAddressSerialNumberReadRequest(AckType ack, HopCountType hopType, const SecurityControl &secCtrl, uint8_t * serialNumber)
{
CemiFrame frame(7);
APDU& apdu = frame.apdu();
apdu.type(IndividualAddressSerialNumberRead);
uint8_t* data = apdu.data() + 1;
memcpy(data, serialNumber, 6);
dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl);
}
void ApplicationLayer::individualAddressSerialNumberReadResponse(AckType ack, HopCountType hopType, const SecurityControl& secCtrl,
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);
dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl);
}
void ApplicationLayer::individualAddressSerialNumberWriteRequest(AckType ack, HopCountType hopType, const SecurityControl &secCtrl, 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);
dataBroadcastRequest(ack, hopType, SystemPriority, apdu, secCtrl);
}
void ApplicationLayer::deviceDescriptorReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
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, secCtrl);
}
void ApplicationLayer::deviceDescriptorReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
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, secCtrl);
}
void ApplicationLayer::connectRequest(uint16_t destination, Priority priority)
{
_transportLayer->connectRequest(destination, priority);
}
void ApplicationLayer::disconnectRequest(Priority priority)
{
_transportLayer->disconnectRequest(_connectedTsap, priority);
}
void ApplicationLayer::restartRequest(AckType ack, Priority priority, HopCountType hopType, const SecurityControl& secCtrl)
{
CemiFrame frame(1);
APDU& apdu = frame.apdu();
apdu.type(Restart);
individualSend(ack, hopType, priority, _connectedTsap, apdu, secCtrl);
}
void ApplicationLayer::restartResponse(AckType ack, Priority priority, HopCountType hopType, const SecurityControl& secCtrl, uint8_t errorCode, uint16_t processTime)
{
CemiFrame frame(4);
APDU& apdu = frame.apdu();
apdu.type(Restart);
uint8_t* data = apdu.data();
data[0] |= (1 << 5) | 1; // Set response bit and a restart type of "master reset". Only the master reset sends a response.
data[1] = errorCode;
data[2] = processTime >> 8;
data[3] = processTime & 0xFF;
individualSend(ack, hopType, priority, _connectedTsap, apdu, secCtrl);
}
//TODO: ApplicationLayer::systemNetworkParameterReadRequest()
void ApplicationLayer::systemNetworkParameterReadResponse(Priority priority, HopCountType hopType, const SecurityControl &secCtrl,
uint16_t objectType, uint16_t propertyId,
uint8_t* testInfo, uint16_t testInfoLength,
uint8_t* testResult, uint16_t testResultLength)
{
CemiFrame frame(testInfoLength + testResultLength + 3 + 1); // PID and testInfo share an octet (+3) and +1 for APCI byte(?)
APDU& apdu = frame.apdu();
apdu.type(SystemNetworkParameterResponse);
uint8_t* data = apdu.data() + 1;
pushWord(objectType, data);
pushWord((propertyId << 4) & 0xFFF0, data + 2); // Reserved bits for test_info are always 0
uint8_t* pData = pushByteArray(&testInfo[1], testInfoLength - 1, data + 4); // TODO: upper reserved bits (testInfo + 0) have to put into the lower bits of data + 3
memcpy(pData, testResult, testResultLength);
//apdu.printPDU();
dataSystemBroadcastRequest(AckDontCare, hopType, SystemPriority, apdu, secCtrl);
}
//TODO: ApplicationLayer::domainAddressSerialNumberWriteRequest()
//TODO: ApplicationLayer::domainAddressSerialNumberReadRequest()
void ApplicationLayer::domainAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const SecurityControl &secCtrl, const uint8_t* rfDoA,
const uint8_t* knxSerialNumber)
{
CemiFrame frame(13);
APDU& apdu = frame.apdu();
apdu.type(DomainAddressSerialNumberResponse);
uint8_t* data = apdu.data() + 1;
memcpy(data, knxSerialNumber, 6);
memcpy(data + 6, rfDoA, 6);
//apdu.printPDU();
dataSystemBroadcastRequest(AckDontCare, hopType, SystemPriority, apdu, secCtrl);
}
//TODO: ApplicationLayer::IndividualAddressSerialNumberWriteRequest()
//TODO: ApplicationLayer::IndividualAddressSerialNumberReadRequest()
void ApplicationLayer::IndividualAddressSerialNumberReadResponse(Priority priority, HopCountType hopType, const SecurityControl &secCtrl, const uint8_t* rfDoA,
const uint8_t* knxSerialNumber)
{
CemiFrame frame(13);
APDU& apdu = frame.apdu();
apdu.type(IndividualAddressSerialNumberResponse);
uint8_t* data = apdu.data() + 1;
memcpy(data, knxSerialNumber, 6);
memcpy(data + 6, rfDoA, 6);
//apdu.printPDU();
dataBroadcastRequest(AckDontCare, hopType, SystemPriority, apdu, secCtrl);
}
void ApplicationLayer::propertyValueReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
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, secCtrl);
}
void ApplicationLayer::propertyValueReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl,
uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length)
{
propertyDataSend(PropertyValueResponse, ack, priority, hopType, asap, secCtrl, objectIndex, propertyId, numberOfElements,
startIndex, data, length);
}
void ApplicationLayer::propertyValueExtReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl,
uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length)
{
propertyExtDataSend(PropertyValueExtResponse, ack, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, numberOfElements,
startIndex, data, length);
}
void ApplicationLayer::propertyValueExtWriteConResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl,
uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t returnCode)
{
uint8_t noOfElem = (returnCode != ReturnCodes::Success) ? 0 : numberOfElements;
propertyExtDataSend(PropertyValueExtWriteConResponse, ack, priority, hopType, asap, secCtrl, objectType, objectInstance, propertyId, noOfElem,
startIndex, &returnCode, 1);
}
void ApplicationLayer::propertyValueWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
uint8_t objectIndex, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t * data, uint8_t length)
{
propertyDataSend(PropertyValueWrite, ack, priority, hopType, asap, secCtrl, objectIndex, propertyId, numberOfElements,
startIndex, data, length);
}
void ApplicationLayer::functionPropertyStateResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
uint8_t objectIndex, uint8_t propertyId, uint8_t* resultData, uint8_t resultLength)
{
CemiFrame frame(3 + resultLength + 1);
APDU& apdu = frame.apdu();
apdu.type(FunctionPropertyStateResponse);
uint8_t* data = apdu.data() + 1;
data[0] = objectIndex;
data[1] = propertyId;
if (resultLength > 0)
memcpy(&data[2], resultData, resultLength);
if (asap == _connectedTsap)
dataConnectedRequest(asap, priority, apdu, secCtrl);
else
dataIndividualRequest(ack, hopType, priority, asap, apdu, secCtrl);
}
void ApplicationLayer::functionPropertyExtStateResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
uint16_t objectType, uint8_t objectInstance, uint16_t propertyId, uint8_t* resultData, uint8_t resultLength)
{
CemiFrame frame(5 + resultLength + 1);
APDU& apdu = frame.apdu();
apdu.type(FunctionPropertyExtStateResponse);
uint8_t* data = apdu.data() + 1;
data[0] = ((uint16_t)objectType) >> 8;
data[1] = ((uint16_t)objectType) & 0xFF;
data[2] = objectInstance >> 4;
data[3] = ((objectInstance&0x0F) << 4) | (propertyId >> 8);
data[4] = (propertyId & 0xFF);
// data[5] must contain the return code
if (resultLength > 0)
memcpy(&data[5], resultData, resultLength);
if (asap == _connectedTsap)
dataConnectedRequest(asap, priority, apdu, secCtrl);
else
dataIndividualRequest(ack, hopType, priority, asap, apdu, secCtrl);
}
void ApplicationLayer::propertyDescriptionReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl &secCtrl,
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, secCtrl);
}
void ApplicationLayer::propertyDescriptionReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
uint8_t objectIndex, uint8_t propertyId, uint8_t propertyIndex, bool writeEnable, uint8_t type,
uint16_t maxNumberOfElements, uint8_t access)
{
CemiFrame frame(8);
APDU& apdu = frame.apdu();
apdu.type(PropertyDescriptionResponse);
uint8_t* data = apdu.data();
data[1] = objectIndex;
data[2] = propertyId;
data[3] = propertyIndex;
if (writeEnable)
data[4] |= 0x80;
data[4] |= (type & 0x3f);
pushWord(maxNumberOfElements & 0xfff, data + 5);
data[7] = access;
individualSend(ack, hopType, priority, asap, apdu, secCtrl);
}
void ApplicationLayer::memoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, 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, secCtrl);
}
void ApplicationLayer::memoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, uint8_t number,
uint16_t memoryAddress, uint8_t * memoryData)
{
memorySend(MemoryResponse, ack, priority, hopType, asap, secCtrl, number, memoryAddress, memoryData);
}
void ApplicationLayer::memoryExtReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ReturnCodes code,
uint8_t number, uint32_t memoryAddress, uint8_t * memoryData)
{
CemiFrame frame(5 + number);
APDU& apdu = frame.apdu();
apdu.type(MemoryExtReadResponse);
uint8_t* data = apdu.data();
data[1] = code;
data[2] = (memoryAddress >> 16);
data[3] = (memoryAddress >> 8);
data[4] = (memoryAddress & 0xFF);
memcpy(&data[5], memoryData, number);
individualSend(ack, hopType, priority, asap, apdu, secCtrl);
}
void ApplicationLayer::memoryExtWriteResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, ReturnCodes code,
uint8_t number, uint32_t memoryAddress, uint8_t * memoryData)
{
bool withCrc = code == ReturnCodes::SuccessWithCrc;
CemiFrame frame(5 + (withCrc ? 2 : 0));
APDU& apdu = frame.apdu();
apdu.type(MemoryExtWriteResponse);
uint8_t* data = apdu.data();
data[1] = code;
data[2] = (memoryAddress >> 16);
data[3] = (memoryAddress >> 8);
data[4] = (memoryAddress & 0xFF);
if (withCrc)
{
uint16_t crc = crc16Ccitt(memoryData, number);
data[5] = crc >> 8;
data[6] = crc & 0xFF;
}
individualSend(ack, hopType, priority, asap, apdu, secCtrl);
}
void ApplicationLayer::memoryWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
uint8_t number, uint16_t memoryAddress, uint8_t * data)
{
memorySend(MemoryWrite, ack, priority, hopType, asap, secCtrl, number, memoryAddress, data);
}
void ApplicationLayer::userMemoryReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
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, secCtrl);
}
void ApplicationLayer::userMemoryReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
uint8_t number, uint32_t memoryAddress, uint8_t * memoryData)
{
userMemorySend(UserMemoryResponse, ack, priority, hopType, asap, secCtrl, number, memoryAddress, memoryData);
}
void ApplicationLayer::userMemoryWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
uint8_t number, uint32_t memoryAddress, uint8_t * memoryData)
{
userMemorySend(UserMemoryWrite, ack, priority, hopType, asap, secCtrl, number, memoryAddress, memoryData);
}
void ApplicationLayer::userManufacturerInfoReadRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl)
{
CemiFrame frame(1);
APDU& apdu = frame.apdu();
apdu.type(UserManufacturerInfoRead);
individualSend(ack, hopType, priority, asap, apdu, secCtrl);
}
void ApplicationLayer::userManufacturerInfoReadResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
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, secCtrl);
}
void ApplicationLayer::authorizeRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, 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, secCtrl);
}
void ApplicationLayer::authorizeResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, 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, secCtrl);
}
void ApplicationLayer::keyWriteRequest(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, 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, secCtrl);
}
void ApplicationLayer::keyWriteResponse(AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, 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, secCtrl);
}
void ApplicationLayer::propertyDataSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
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)
dataConnectedRequest(asap, priority, apdu, secCtrl);
else
dataIndividualRequest(ack, hopType, priority, asap, apdu, secCtrl);
}
void ApplicationLayer::propertyExtDataSend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl,
uint16_t objectType, uint8_t objectInstance, uint8_t propertyId, uint8_t numberOfElements, uint16_t startIndex, uint8_t* data, uint8_t length)
{
CemiFrame frame(9 + length);
APDU& apdu = frame.apdu();
apdu.type(type);
uint8_t* apduData = apdu.data();
apduData += 1;
apduData[0] = ((uint16_t)objectType) >> 8;
apduData[1] = ((uint16_t)objectType) & 0xFF;
apduData[2] = objectInstance >> 4;
apduData[3] = ((objectInstance&0x0F) << 4) | (propertyId >> 8);
apduData[4] = (propertyId & 0xFF);
apduData[5] = numberOfElements;
apduData[6] = (startIndex & 0x0FFF)>> 8;
apduData[7] = startIndex & 0xFF;
if (length > 0)
memcpy(apduData+8, data, length);
if (asap == _connectedTsap)
dataConnectedRequest(asap, priority, apdu, secCtrl);
else
dataIndividualRequest(ack, hopType, priority, asap, apdu, secCtrl);
}
void ApplicationLayer::groupValueSend(ApduType type, AckType ack, uint16_t asap, Priority priority, HopCountType hopType, const SecurityControl &secCtrl,
uint8_t* data, uint8_t& dataLength)
{
if (_assocTable == nullptr)
return;
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 in 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 through
uint16_t tsap = (uint16_t)_assocTable->translateAsap(asap);
dataGroupRequest(ack, hopType, priority, tsap, apdu, secCtrl);
dataGroupIndication(hopType, priority, tsap, apdu, secCtrl);
}
void ApplicationLayer::memorySend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, 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, secCtrl);
}
void ApplicationLayer::userMemorySend(ApduType type, AckType ack, Priority priority, HopCountType hopType, uint16_t asap, const SecurityControl& secCtrl, 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, secCtrl);
}
void ApplicationLayer::individualIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU & apdu, const SecurityControl& secCtrl)
{
uint8_t* data = apdu.data();
switch (apdu.type())
{
case DeviceDescriptorRead:
_bau.deviceDescriptorReadIndication(priority, hopType, tsap, secCtrl, *data & 0x3f);
break;
case DeviceDescriptorResponse:
_bau.deviceDescriptorReadAppLayerConfirm(priority, hopType, tsap, secCtrl, *data & 0x3f, data + 1);
break;
case Restart:
case RestartMasterReset:
{
// These reserved bits must be 0
uint8_t reservedBits = data[0] & 0x1e;
if (reservedBits != 0)
return;
// handle erase code for factory reset (setting FDSK again as toolkey, etc.)
RestartType restartType = (RestartType) (data[0] & 0x3f);
EraseCode eraseCode = EraseCode::Void;
uint8_t channel = 0;
if (restartType == RestartType::MasterReset)
{
eraseCode = (EraseCode) data[1];
channel = data[2];
}
_bau.restartRequestIndication(priority, hopType, tsap, secCtrl, restartType, eraseCode, channel);
break;
}
case PropertyValueRead:
{
uint16_t startIndex;
popWord(startIndex, data + 3);
startIndex &= 0xfff;
_bau.propertyValueReadIndication(priority, hopType, tsap, secCtrl, 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, secCtrl, 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, secCtrl, data[1], data[2], data[3] >> 4,
startIndex, data + 5, apdu.length() - 5);
break;
}
case PropertyValueExtRead:
{
ObjectType objectType = (ObjectType)(((data[1] & 0xff) << 8) | (data[2] & 0xff));
uint8_t objectInstance = ((data[3] & 0xff) << 4) | ((data[4] & 0xff) >> 4);
uint16_t propertyId = ((data[4] & 0xf) << 8) | (data[5] & 0xff);
uint8_t numberOfElements = data[6];
uint16_t startIndex = ((data[7] & 0xf) << 8) | (data[8] & 0xff);
_bau.propertyValueExtReadIndication(priority, hopType, tsap, secCtrl, objectType, objectInstance, propertyId, numberOfElements, startIndex);
break;
}
case PropertyValueExtWriteCon:
case PropertyValueExtWriteUnCon:
{
ObjectType objectType = (ObjectType)(((data[1] & 0xff) << 8) | (data[2] & 0xff));
uint8_t objectInstance = ((data[3] & 0xff) << 4) | ((data[4] & 0xff) >> 4);
uint16_t propertyId = ((data[4] & 0xf) << 8) | (data[5] & 0xff);
uint8_t numberOfElements = data[6];
uint16_t startIndex = ((data[7] & 0xf) << 8) | (data[8] & 0xff);
bool confirmed = (apdu.type() == PropertyValueExtWriteCon);
_bau.propertyValueExtWriteIndication(priority, hopType, tsap, secCtrl, objectType, objectInstance, propertyId, numberOfElements, startIndex,
data + 9, apdu.length() - 9, confirmed);
break;
}
case FunctionPropertyCommand:
_bau.functionPropertyCommandIndication(priority, hopType, tsap, secCtrl, data[1], data[2], &data[3], apdu.length() - 4); //TODO: check length
break;
case FunctionPropertyState:
_bau.functionPropertyStateIndication(priority, hopType, tsap, secCtrl, data[1], data[2], &data[3], apdu.length() - 4); //TODO: check length
break;
case FunctionPropertyExtCommand:
{
ObjectType objectType = (ObjectType)(((data[1] & 0xff) << 8) | (data[2] & 0xff));
uint8_t objectInstance = ((data[3] & 0xff) << 4) | ((data[4] & 0xff) >> 4);
uint16_t propertyId = ((data[4] & 0xf) << 8) | (data[5] & 0xff);
uint8_t* functionInput = &data[6];
_bau.functionPropertyExtCommandIndication(priority, hopType, tsap, secCtrl, objectType, objectInstance, propertyId, functionInput, apdu.length() - 6);
break;
}
case FunctionPropertyExtState:
{
ObjectType objectType = (ObjectType)(((data[1] & 0xff) << 8) | (data[2] & 0xff));
uint8_t objectInstance = ((data[3] & 0xff) << 4) | ((data[4] & 0xff) >> 4);
uint16_t propertyId = ((data[4] & 0xf) << 8) | (data[5] & 0xff);
uint8_t* functionInput = &data[6];
_bau.functionPropertyExtStateIndication(priority, hopType, tsap, secCtrl, objectType, objectInstance, propertyId, functionInput, apdu.length() - 6);
break;
}
case PropertyDescriptionRead:
_bau.propertyDescriptionReadIndication(priority, hopType, tsap, secCtrl, data[1], data[2], data[3]);
break;
case PropertyDescriptionResponse:
_bau.propertyDescriptionReadAppLayerConfirm(priority, hopType, tsap, secCtrl, 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, secCtrl, data[0] & 0x3f, getWord(data + 1));
break;
case MemoryResponse:
_bau.memoryReadAppLayerConfirm(priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3);
break;
case MemoryWrite:
_bau.memoryWriteIndication(priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3);
break;
case MemoryExtRead:
{
uint8_t number = data[1];
uint32_t memoryAddress = ((data[2] & 0xff) << 16) | ((data[3] & 0xff) << 8) | (data[4] & 0xff);
_bau.memoryExtReadIndication(priority, hopType, tsap, secCtrl, number, memoryAddress);
break;
}
//case MemoryExtReadResponse:
// _bau.memoryExtReadAppLayerConfirm(priority, hopType, tsap, secCtrl, data[0], getInt(data + 1), data + 4); // TODO return code
// break;
case MemoryExtWrite:
{
uint8_t number = data[1];
uint32_t memoryAddress = ((data[2] & 0xff) << 16) | ((data[3] & 0xff) << 8) | (data[4] & 0xff);
_bau.memoryExtWriteIndication(priority, hopType, tsap, secCtrl, number, memoryAddress, data + 5);
break;
}
//case MemoryExtWriteResponse:
// _bau.memoryExtWriteAppLayerConfirm(priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3); // TODO return code
// break;
case UserMemoryRead:
{
uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3];
_bau.userMemoryReadIndication(priority, hopType, tsap, secCtrl, data[1] & 0xf, address);
break;
}
case UserMemoryResponse:
{
uint32_t address = ((data[1] & 0xf0) << 12) + (data[2] << 8) + data[3];
_bau.userMemoryReadAppLayerConfirm(priority, hopType, tsap, secCtrl, 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, secCtrl, data[1] & 0xf, address, data + 4);
break;
}
case UserManufacturerInfoRead:
_bau.userManufacturerInfoIndication(priority, hopType, tsap, secCtrl);
break;
case UserManufacturerInfoResponse:
_bau.userManufacturerInfoAppLayerConfirm(priority, hopType, tsap, secCtrl, data + 1);
break;
case AuthorizeRequest:
_bau.authorizeIndication(priority, hopType, tsap, secCtrl, getInt(data + 2));
break;
case AuthorizeResponse:
_bau.authorizeAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1]);
break;
case KeyWrite:
_bau.keyWriteIndication(priority, hopType, tsap, secCtrl, data[1], getInt(data + 2));
break;
case KeyResponse:
_bau.keyWriteAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1]);
break;
default:
print("Individual-indication: unhandled APDU-Type: ");
println(apdu.type());
}
}
void ApplicationLayer::individualConfirm(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU & apdu, const SecurityControl &secCtrl, bool status)
{
uint8_t* data = apdu.data();
switch (apdu.type())
{
case DeviceDescriptorRead:
_bau.deviceDescriptorReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, *data & 0x3f, status);
break;
case DeviceDescriptorResponse:
_bau.deviceDescriptorReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, *data & 0x3f, data + 1, status);
break;
case Restart:
_bau.restartRequestLocalConfirm(ack, priority, hopType, tsap, secCtrl, status);
break;
case PropertyValueRead:
{
uint16_t startIndex;
popWord(startIndex, data + 3);
startIndex &= 0xfff;
_bau.propertyValueReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, 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, secCtrl, 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, secCtrl, data[1], data[2], data[3] >> 4,
startIndex, data + 5, apdu.length() - 5, status);
break;
}
case PropertyDescriptionRead:
_bau.propertyDescriptionReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[1], data[2], data[3], status);
break;
case PropertyDescriptionResponse:
_bau.propertyDescriptionReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, 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, secCtrl, data[0] & 0x3f, getWord(data + 1), status);
break;
case MemoryResponse:
_bau.memoryReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3, status);
break;
case MemoryWrite:
_bau.memoryWriteLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3, status);
break;
case MemoryExtRead:
_bau.memoryExtReadLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), status);
break;
case MemoryExtReadResponse:
_bau.memoryExtReadResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3, status);
break;
case MemoryExtWrite:
_bau.memoryExtWriteLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[0] & 0x3f, getWord(data + 1), data + 3, status);
break;
case MemoryExtWriteResponse:
_bau.memoryExtWriteResponseConfirm(ack, priority, hopType, tsap, secCtrl, 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, secCtrl, 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, secCtrl, 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, secCtrl, data[1] & 0xf, address, data + 4, status);
break;
}
case UserManufacturerInfoRead:
_bau.userManufacturerInfoLocalConfirm(ack, priority, hopType, tsap, secCtrl, status);
break;
case UserManufacturerInfoResponse:
_bau.userManufacturerInfoResponseConfirm(ack, priority, hopType, tsap, secCtrl, data + 1, status);
break;
case AuthorizeRequest:
_bau.authorizeLocalConfirm(ack, priority, hopType, tsap, secCtrl, getInt(data + 2), status);
break;
case AuthorizeResponse:
_bau.authorizeResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[1], status);
break;
case KeyWrite:
_bau.keyWriteLocalConfirm(ack, priority, hopType, tsap, secCtrl, data[1], getInt(data + 2), status);
break;
case KeyResponse:
_bau.keyWriteResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[1], status);
break;
default:
print("Individual-confirm: unhandled APDU-Type: ");
println(apdu.type());
}
}
void ApplicationLayer::individualSend(AckType ack, HopCountType hopType, Priority priority, uint16_t asap, APDU& apdu, const SecurityControl& secCtrl)
{
if (asap == _connectedTsap)
dataConnectedRequest(asap, priority, apdu, secCtrl);
else
dataIndividualRequest(ack, hopType, priority, asap, apdu, secCtrl);
}
bool ApplicationLayer::isConnected()
{
return (_connectedTsap >= 0);
}
void ApplicationLayer::dataGroupRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu, const SecurityControl& secCtrl)
{
(void)secCtrl; // We do not need security related information in the plain application layer
_transportLayer->dataGroupRequest(ack, hopType, priority, tsap, apdu);
}
void ApplicationLayer::dataBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl &secCtrl)
{
(void)secCtrl; // We do not need security related information in the plain application layer
_transportLayer->dataBroadcastRequest(ack, hopType, SystemPriority, apdu);
}
void ApplicationLayer::dataSystemBroadcastRequest(AckType ack, HopCountType hopType, Priority priority, APDU& apdu, const SecurityControl& secCtrl)
{
(void)secCtrl; // We do not need security related information in the plain application layer
_transportLayer->dataSystemBroadcastRequest(ack, hopType, SystemPriority, apdu);
}
void ApplicationLayer::dataIndividualRequest(AckType ack, HopCountType hopType, Priority priority, uint16_t destination, APDU& apdu, const SecurityControl& secCtrl)
{
(void)secCtrl; // We do not need security related information in the plain application layer
_transportLayer->dataIndividualRequest(ack, hopType, priority, destination, apdu);
}
void ApplicationLayer::dataConnectedRequest(uint16_t tsap, Priority priority, APDU& apdu, const SecurityControl &secCtrl)
{
(void)secCtrl; // We do not need security related information in the plain application layer
// apdu must be valid until it was confirmed
_transportLayer->dataConnectedRequest(tsap, priority, apdu);
}