Commit 5419fa5f authored by Micha Mueller's avatar Micha Mueller
Browse files

First half of readProperty logic in BACnetClient

parent 353f9e1d
......@@ -7,8 +7,17 @@
#include "BACnetClient.h"
//#include "client.h"
#include "bacnetTEMP/address.h"
#include "bacnetTEMP/apdu.h"
#include "bacnetTEMP/datalink.h"
#include "bacnetTEMP/npdu.h"
#include "bacnetTEMP/rp.h"
#include "bacnetTEMP/tsm.h"
BACnetClient::BACnetClient() {
_strand = NULL;
_timeout = 1000;
//TODO setup datalink
}
......@@ -17,8 +26,88 @@ BACnetClient::~BACnetClient() {
// TODO teardown datalink
}
uint64_t BACnetClient::readProperty(uint32_t deviceObjectInstance, uint32_t objectInstance, BACNET_OBJECT_TYPE objectType, BACNET_PROPERTY_ID objectIndex, int32_t objectIndex) {
//TODO
void BACnetClient::init() {/*
apdu_set_confirmed_ack_handler(SERVICE_CONFIRMED_READ_PROPERTY,
My_Read_Property_Ack_Handler);
//TODO setup address cache
apdu_set_error_handler(SERVICE_CONFIRMED_READ_PROPERTY, MyErrorHandler);
apdu_set_abort_handler(MyAbortHandler);
apdu_set_reject_handler(MyRejectHandler);*/
}
uint64_t BACnetClient::readProperty(uint32_t deviceObjInstance, uint32_t objInstance, BACNET_OBJECT_TYPE objType, BACNET_PROPERTY_ID objProperty, int32_t objIndex) {
uint8_t invoke_id = 0;
uint16_t pdu_lenRec = 0;
int pdu_lenSent = 0;
int bytes_sent = 0;
unsigned max_apdu = 0;
BACNET_ADDRESS dest = {0}; //where message goes to
BACNET_ADDRESS src = {0}; //where response came from
BACNET_ADDRESS myAddr = {0};//our address
BACNET_READ_PROPERTY_DATA data;
BACNET_NPDU_DATA npdu_data;
uint8_t RecBuf[MAX_MPDU] = {0};
if (!address_get_by_device(deviceObjInstance, &max_apdu, &dest)) {
throw std::runtime_error("Address not found");
}
/*
if (!dest) {
throw std::runtime_error("Destination address empty");
}
*/
/*
if (!dcc_communication_enabled()) {
throw std::runtime_error("Communication Control disabled");
}
*/
if (!(invoke_id = tsm_next_free_invokeID())) {
throw std::runtime_error("No TSM available");
}
/* encode the NPDU portion of the packet */
datalink_get_my_address(&my_address);
npdu_encode_npdu_data(&npdu_data, true, MESSAGE_PRIORITY_NORMAL);
pdu_lenSent = npdu_encode_pdu(&_handlerTransmitBuffer[0], &dest, &my_address, &npdu_data);
/* encode the APDU portion of the packet */
data.object_type = objType;
data.object_instance = objInstance;
data.object_property = objProperty;
data.array_index = objIndex;
pdu_lenSent += rp_encode_apdu(&_handlerTransmitBuffer[pdu_lenSent], invoke_id, &data);
/* will it fit in the sender?
note: if there is a bottleneck router in between
us and the destination, we won't know unless
we have a way to check for that and update the
max_apdu in the address binding table. */
if ((uint16_t) pdu_lenSent < max_apdu) {
tsm_set_confirmed_unsegmented_transaction(invoke_id, &dest, &npdu_data, &_handlerTransmitBuffer[0], (uint16_t) pdu_lenSent);
bytes_sent = datalink_send_pdu(&dest, &npdu_data, &_handlerTransmitBuffer[0], pdu_lenSent);
if (bytes_sent <= 0) {
throw std::runtime_error("Failed to Send ReadProperty Request (%s)", strerror(errno));
}
} else {
tsm_free_invoke_id(invoke_id);
invoke_id = 0;
throw std::runtime_error("Failed to Send ReadProperty Request (exceeds destination maximum APDU)");
}
// returns 0 on timeout
pdu_lenRec = datalink_receive(&src, &RecBuf[0], MAX_MPDU, _timeout);
if (pdu_lenRec && tsm_invoke_id_free(invoke_id)) { //where is invoke_id freed on success?!
npdu_handler(&src, &RecBuf[0], pdu_lenRec);
} else {
tsm_free_invoke_id(invoke_id);
throw std::runtime_error("Timeout while waiting for response");
}
return 0;
}
......
......@@ -10,7 +10,9 @@
#include "../../Sensor.h" //only for logging
#include "bacenum.h"
//TODO where to put bacnet?
#include "bacnetTEMP/bacenum.h"
#include "bacnetTEMP/datalink.h"
#include <boost/asio.hpp>
class BACnetClient {
......@@ -24,10 +26,29 @@ public:
return _strand;
}
uint64_t readProperty(uint32_t deviceObjectInstance, uint32_t objectInstance = 0, BACNET_OBJECT_TYPE objectType = OBJECT_DEVICE, BACNET_PROPERTY_ID objectIndex = PROP_PRESENT_VALUE, int32_t objectIndex = BACNET_ARRAY_ALL);
void init();
/**
* Sends a READ_PROPERTY request for PROP_PRESENT_VALUE to specified device and decodes the response (READ_PROPERTY_ACK).
*
* @param deviceObjectInstance Number of device from which to request the current value.
* @param objectInstance
* @param objectType
* @param objectProperty
* @param objectIndex
*
* @return The value sent as response from the device. If an error occurs a runtime exception is thrown.
*
* @throws Runtime error
*/
uint64_t readProperty(uint32_t deviceObjInstance, uint32_t objInstance = 0, BACNET_OBJECT_TYPE objType = OBJECT_DEVICE, BACNET_PROPERTY_ID objProperty = PROP_PRESENT_VALUE, int32_t objIndex = BACNET_ARRAY_ALL);
private:
unsigned _timeout;
BACNET_READ_PROPERTY_DATA _propertyData;
uint8_t _handlerTransmitBuffer[MAX_PDU];
boost::asio::io_service::strand* _strand;
boost::log::sources::severity_logger<boost::log::trivial::severity_level> lg;
......
......@@ -35,7 +35,7 @@ void BACnetSensor::read() {
_latestValue.value = reading.value;
_latestValue.timestamp = reading.timestamp;
#ifdef DEBUG
LOG(debug) << _pdu->getHost() << "::" << _name << ": \"" << reading.value << "\"";
LOG(debug) << _name << ": \"" << reading.value << "\"";
#endif
} catch (const std::exception& e) {
LOG(error) << _name << " could not read value: " << e.what();
......
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