Commit 8c6b29bb authored by Micha Mueller's avatar Micha Mueller
Browse files

More bugfixes and changes to BACnet plugin. Does now compile.

Next step: check correctness
parent 1d7f7d8e
......@@ -19,7 +19,7 @@ devices {
instance 1234
mqttPart FF
object {
object o1 {
type 1
instance 1
mqttPart FF
......@@ -33,7 +33,7 @@ devices {
}
}
object {
object o2 {
type 1
instance 2
mqttPart FF
......@@ -47,10 +47,11 @@ devices {
minValues 1
mqttsuffix 0003
}
}
}
device jklo {
...
}
; device jklo {
; ...
; }
}
......@@ -29,9 +29,9 @@ plugins {
config
}
; plugin bacnet {
; path ./
; config
; }
plugin bacnet {
path ./
config
}
}
......@@ -53,4 +53,4 @@ libdcdbplugin_bacnet.so.1.0:
$(CXX) $(PLUGINFLAGS) sensors/bacnet/BACnetSensor.cpp
$(CXX) $(PLUGINFLAGS) sensors/bacnet/BACnetClient.cpp
$(CXX) $(PLUGINFLAGS) sensors/bacnet/BACnetConfigurator.cpp
$(CXX) -shared -Wl,-soname,libdcdbplugin_bacnet.so.1 -o libdcdbplugin_bacnet.so.1.0 BACnetSensor.o BACnetClient.o BACnetConfigurator.o -lbacnet
$(CXX) -shared -Wl,-soname,libdcdbplugin_bacnet.so.1 -o libdcdbplugin_bacnet.so.1.0 BACnetSensor.o BACnetClient.o BACnetConfigurator.o -L$(DCDBDEPLOYPATH)/lib/ -lbacnet
......@@ -18,7 +18,8 @@
#include "bacnetTEMP/rp.h"
#include "bacnetTEMP/tsm.h"
#include <functional>
uint64_t BACnetClient::_presentValue;
uint8_t BACnetClient::_handlerTransmitBuffer[MAX_PDU];
BACnetClient::BACnetClient() {
_strand = NULL;
......@@ -57,8 +58,7 @@ void BACnetClient::init(std::string interface, unsigned port, unsigned timeout,
/* set the handler for all the services we don't implement
It is required to send the proper reject message... */
//TODO make it accept the method. but i would like to avoid just making it static...
apdu_set_unrecognized_service_handler_handler(std::bind(&BACnetClient::unrecognizedServiceHandler, this, _1, _2, _3, _4));
apdu_set_unrecognized_service_handler_handler(unrecognizedServiceHandler);
//NOTE: no handler for read property set even though it is required. We are no real BACnet device
......@@ -138,7 +138,7 @@ uint64_t BACnetClient::readProperty(uint32_t deviceObjInstance, uint32_t objInst
}
// returns 0 on timeout
pdu_lenRec = datalink_receive(&src, &RecBuf[0], MAX_MPDU, _timeout);
pdu_lenRec = datalink_receive(&src, &RecBuf[0], MAX_MPDU, _timeout); //TODO use bip_receive?
if (pdu_lenRec) {
int apdu_offset = 0;
......@@ -184,6 +184,7 @@ void BACnetClient::initializeStrand(boost::asio::io_service& io) {
}
void BACnetClient::unrecognizedServiceHandler(uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) {
boost::log::sources::severity_logger<boost::log::trivial::severity_level> lg;
int pdu_len = 0;
int bytes_sent = 0;
BACNET_NPDU_DATA npdu_data;
......@@ -209,6 +210,7 @@ void BACnetClient::unrecognizedServiceHandler(uint8_t * service_request, uint16_
void BACnetClient::readPropertyAckHandler(uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data)
{
boost::log::sources::severity_logger<boost::log::trivial::severity_level> lg;
int serviceLen = 0;
int appDataLen = 0;
uint8_t *application_data;
......@@ -216,9 +218,9 @@ void BACnetClient::readPropertyAckHandler(uint8_t * service_request, uint16_t se
BACNET_READ_PROPERTY_DATA data;
BACNET_APPLICATION_DATA_VALUE value; /* for decode value data */
if (!(address_match(&_targetAddress, src) && (service_data->invoke_id == _invokeId))) {
/*if (!(address_match(&_targetAddress, src) && (service_data->invoke_id == _invokeId))) {
throw std::runtime_error("Message not determined for us");
}
}*/
serviceLen = rp_ack_decode_service_request(service_request, service_len, &data);
if (serviceLen <= 0) {
......@@ -226,61 +228,56 @@ void BACnetClient::readPropertyAckHandler(uint8_t * service_request, uint16_t se
}
// rp_ack_print_data(&data);
if (data) {
application_data = data.application_data;
application_data_len = data.application_data_len;
appDataLen = bacapp_decode_application_data(application_data, (uint8_t) application_data_len, &value);
//bacapp_print_value(stdout, &object_value);
//TODO what kind of data is returned? which cases do we need to handle? fit they into uint64_t at all??
switch (value.tag) {
case BACNET_APPLICATION_TAG_NULL:
LOG(trace) << "TAG_NULL";
_presentValue = 0;
break;
case BACNET_APPLICATION_TAG_BOOLEAN:
LOG(trace) << "TAG_BOOLEAN";
_presentValue = (value.type.Boolean) ? 1 : 0;
break;
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
LOG(trace) << "TAG_UNSIGNED_INT";
_presentValue = (unsigned long) value.type.Unsigned_Int;
break;
case BACNET_APPLICATION_TAG_SIGNED_INT:
LOG(trace) << "TAG_SIGNED_INT";
_presentValue = (long) value.type.Signed_Int;
break;
case BACNET_APPLICATION_TAG_REAL:
LOG(trace) << "TAG_REAL";
_presentValue = (double) value.type.Real;
break;
case BACNET_APPLICATION_TAG_DOUBLE:
LOG(trace) << "TAG_DOUBLE";
_presentValue = value.type.Double;
break;
default:
throw std::runtime_error("Value tag not supported");
break;
}
application_data = data.application_data;
application_data_len = data.application_data_len;
appDataLen = bacapp_decode_application_data(application_data, (uint8_t) application_data_len, &value);
//bacapp_print_value(stdout, &object_value);
//TODO what kind of data is returned? which cases do we need to handle? fit they into uint64_t at all??
switch (value.tag) {
case BACNET_APPLICATION_TAG_NULL:
LOG(trace) << "TAG_NULL";
_presentValue = 0;
break;
case BACNET_APPLICATION_TAG_BOOLEAN:
LOG(trace) << "TAG_BOOLEAN";
_presentValue = (value.type.Boolean) ? 1 : 0;
break;
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
LOG(trace) << "TAG_UNSIGNED_INT";
_presentValue = (unsigned long) value.type.Unsigned_Int;
break;
case BACNET_APPLICATION_TAG_SIGNED_INT:
LOG(trace) << "TAG_SIGNED_INT";
_presentValue = (long) value.type.Signed_Int;
break;
case BACNET_APPLICATION_TAG_REAL:
LOG(trace) << "TAG_REAL";
_presentValue = (double) value.type.Real;
break;
case BACNET_APPLICATION_TAG_DOUBLE:
LOG(trace) << "TAG_DOUBLE";
_presentValue = value.type.Double;
break;
default:
throw std::runtime_error("Value tag not supported");
break;
}
}
void BACnetClient::errorHandler(BACNET_ADDRESS * src, uint8_t invokeId, BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code) {
if (address_match(&_targetAddress, src) && (invokeId == _invokeId)) {
LOG(error) << "BACnet Error: " << bactext_error_class_name((int) error_class) << bactext_error_code_name((int) error_code);
}
boost::log::sources::severity_logger<boost::log::trivial::severity_level> lg;
LOG(error) << "BACnet Error: " << bactext_error_class_name((int) error_class) << bactext_error_code_name((int) error_code);
}
void BACnetClient::abortHandler(BACNET_ADDRESS * src, uint8_t invokeId, uint8_t abort_reason, bool server) {
if (address_match(&_targetAddress, src) && (invokeId == _invokeId)) {
LOG(error) << "BACnet Abort: " << bactext_abort_reason_name((int) abort_reason);
}
boost::log::sources::severity_logger<boost::log::trivial::severity_level> lg;
LOG(error) << "BACnet Abort: " << bactext_abort_reason_name((int) abort_reason);
}
void BACnetClient::rejectHandler(BACNET_ADDRESS * src, uint8_t invokeId, uint8_t reject_reason) {
if (address_match(&_targetAddress, src) && (invokeId == _invokeId)) {
LOG(error) << "BACnet Reject: " << bactext_reject_reason_name((int) reject_reason);
}
boost::log::sources::severity_logger<boost::log::trivial::severity_level> lg;
LOG(error) << "BACnet Reject: " << bactext_reject_reason_name((int) reject_reason);
}
......@@ -16,6 +16,12 @@
#include "bacnetTEMP/datalink.h"
#include <boost/asio.hpp>
/*
* NOTE
* Had to make some member variables static because of BACnet Stack handler function requirements.
* This should be no problem as we are using only one instance of BACnetClient with serialized access (_strand).
* One should ensure to keep the single instance property in the future.
*/
class BACnetClient {
public:
BACnetClient();
......@@ -54,7 +60,7 @@ public:
private:
/* Handler to process incoming BACnet data */
void unrecognizedServiceHandler(uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data);
static void unrecognizedServiceHandler(uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data);
/**
* Handler for a ReadProperty ACK.
......@@ -65,16 +71,17 @@ private:
* @param src BACNET_ADDRESS of the source of the message
* @param service_data The BACNET_CONFIRMED_SERVICE_DATA information decoded from the APDU header of this message.
*/
void readPropertyAckHandler(uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data);
static void readPropertyAckHandler(uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_ACK_DATA * service_data);
void errorHandler(BACNET_ADDRESS * src, uint8_t invokeId, BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code);
void abortHandler(BACNET_ADDRESS * src, uint8_t invokeId, uint8_t abort_reason, bool server);
void rejectHandler(BACNET_ADDRESS * src, uint8_t invokeId, uint8_t reject_reason);
static void errorHandler(BACNET_ADDRESS * src, uint8_t invokeId, BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code);
static void abortHandler(BACNET_ADDRESS * src, uint8_t invokeId, uint8_t abort_reason, bool server);
static void rejectHandler(BACNET_ADDRESS * src, uint8_t invokeId, uint8_t reject_reason);
uint8_t _invokeId; //store as member variable to enable access in handler methods
unsigned _timeout;
uint64_t _presentValue;
uint8_t _handlerTransmitBuffer[MAX_PDU];
// static because of handler functions
static uint64_t _presentValue;
static uint8_t _handlerTransmitBuffer[MAX_PDU];
BACNET_ADDRESS _targetAddress; //store as member variable to enable access in handler methods
boost::asio::io_service::strand* _strand;
......
......@@ -31,8 +31,8 @@ std::vector<Sensor*>& BACnetConfigurator::readConfig(std::string cfgPath) {
_bacClient = new BACnetClient();
std::string interface, mqttPartDevice, mqttPartObject;
unsigned port = 47808, apdu_timeout = 200, apdu_retries = 0;
unsigned deviceInstance, objInstance;
BACNET_OBJECT_TYPE objType;
unsigned deviceInstance = 0, objInstance = 0;
BACNET_OBJECT_TYPE objType = OBJECT_DEVICE; /* = 8 */
//read global variables (if present overwrite those from global.conf)
BOOST_FOREACH(boost::property_tree::iptree::value_type &global, cfg.get_child("global")) {
......@@ -60,7 +60,7 @@ std::vector<Sensor*>& BACnetConfigurator::readConfig(std::string cfgPath) {
_bacClient->init(interface, port, apdu_timeout, apdu_retries);
} catch (const std::exception& e) {
LOG(error) << "Could not initialize BACnetClient!";
return NULL;
return _sensors;
}
//read template sensors
......@@ -100,35 +100,33 @@ std::vector<Sensor*>& BACnetConfigurator::readConfig(std::string cfgPath) {
} else if (boost::iequals(object.first, "property")) {
LOG(debug) << "Property \"" << object.second.data() << "\"";
if (!object.second.empty()) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &property, object.second) {
BACnetSensor * bacSensor = new BACnetSensor(property.second.data());
//first check if default sensor is given
boost::optional<boost::property_tree::iptree&> defaultC = property.second.get_child_optional("default");
if(defaultC) {
LOG(debug) << " Using \"" << defaultC.get().data() << "\" as default.";
sensorMap_t::iterator it = _templateSensors.find(defaultC.get().data());
if(it != _templateSensors.end()) {
*bacSensor = it->second;
bacSensor->setName(property.second.data());
} else {
LOG(warning) << " Template sensor \"" << defaultC.get().data() << "\" not found! Using standard values.";
}
}
//set object and device related data
//assume property aka sensors are read at last
bacSensor->setDeviceInstance(deviceInstance);
bacSensor->setObjectInstance(objInstance);
bacSensor->setObjectType(objType);
bacSensor->setMqtt(_mqttPrefix + mqttPartDevice + mqttPartObject);
//read remaining values
if(readSensor(*bacSensor, property.second)) {
_sensors.push_back(bacSensor);
BACnetSensor * bacSensor = new BACnetSensor(object.second.data());
//first check if default sensor is given
boost::optional<boost::property_tree::iptree&> defaultC = object.second.get_child_optional("default");
if(defaultC) {
LOG(debug) << " Using \"" << defaultC.get().data() << "\" as default.";
sensorMap_t::iterator it = _templateSensors.find(defaultC.get().data());
if(it != _templateSensors.end()) {
*bacSensor = it->second;
bacSensor->setName(object.second.data());
} else {
LOG(warning) << " Sensor \"" << property.second.data() << "\" has bad values! Ignoring..." << std::endl;
LOG(warning) << " Template sensor \"" << defaultC.get().data() << "\" not found! Using standard values.";
}
}
//set object and device related data as well as BACnetClient instance
//assume property aka sensors are read at last
bacSensor->setDeviceInstance(deviceInstance);
bacSensor->setObjectInstance(objInstance);
bacSensor->setObjectType(objType);
bacSensor->setMqtt(_mqttPrefix + mqttPartDevice + mqttPartObject);
bacSensor->setBACnetClient(_bacClient);
//read remaining values
if(readSensor(*bacSensor, object.second)) {
_sensors.push_back(bacSensor);
} else {
LOG(warning) << " Sensor \"" << object.second.data() << "\" has bad values! Ignoring..." << std::endl;
}
}
}
......@@ -142,7 +140,7 @@ std::vector<Sensor*>& BACnetConfigurator::readConfig(std::string cfgPath) {
return _sensors;
}
void BACnetConfigurator::readSensor(BACnetSensor& sensor, boost::property_tree::iptree& config) {
bool BACnetConfigurator::readSensor(BACnetSensor& sensor, boost::property_tree::iptree& config) {
BOOST_FOREACH(boost::property_tree::iptree::value_type &val, config) {
if (boost::iequals(val.first, "interval")) {
sensor.setInterval(stoull(val.second.data()));
......@@ -168,5 +166,5 @@ void BACnetConfigurator::readSensor(BACnetSensor& sensor, boost::property_tree::
LOG(debug) << " objType : " << sensor.getObjectType();
LOG(debug) << " Property : " << sensor.getPropertyId();
return;
return true;
}
......@@ -38,8 +38,10 @@ private:
* Set the variables of sensor according to the values specified in config.
* @param sensor The sensor to be configured
* @param config A property(sub)tree containing the values
*
* @return True on success, false otherwise
*/
void readSensor(BACnetSensor& sensor, boost::property_tree::iptree& config);
bool readSensor(BACnetSensor& sensor, boost::property_tree::iptree& config);
BACnetClient* _bacClient;
std::vector<Sensor*> _sensors;
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment