Commit b482c4fe authored by Micha Mueller's avatar Micha Mueller
Browse files

Further refine readProperty logic. Add message error handlers

parent 5419fa5f
......@@ -10,8 +10,10 @@
//#include "client.h"
#include "bacnetTEMP/address.h"
#include "bacnetTEMP/apdu.h"
#include "bacnetTEMP/bactext.h"
#include "bacnetTEMP/datalink.h"
#include "bacnetTEMP/npdu.h"
#include "bacnetTEMP/reject.h"
#include "bacnetTEMP/rp.h"
#include "bacnetTEMP/tsm.h"
......@@ -26,13 +28,26 @@ BACnetClient::~BACnetClient() {
// TODO teardown datalink
}
void BACnetClient::init() {/*
apdu_set_confirmed_ack_handler(SERVICE_CONFIRMED_READ_PROPERTY,
My_Read_Property_Ack_Handler);
void BACnetClient::init() {
//TODO setup address cache
apdu_set_error_handler(SERVICE_CONFIRMED_READ_PROPERTY, MyErrorHandler);
apdu_set_abort_handler(MyAbortHandler);
apdu_set_reject_handler(MyRejectHandler);*/
//Device_Init(NULL); // Initializes Device Object; TODO do we need this?
/* set the handler for all the services we don't implement
It is required to send the proper reject message... */
//apdu_set_unrecognized_service_handler_handler(handler_unrecognized_service); //TODO implement handler_unrecognized_service
/* we must implement read property - it's required! */
// TODO should we really implement read property just because it's required? otherwise it should be handled by handler for unrecognized services
//apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY, handler_read_property);
/* we only need to handle the data coming back from confirmed (read property) requests */
//apdu_set_confirmed_ack_handler(SERVICE_CONFIRMED_READ_PROPERTY, My_Read_Property_Ack_Handler); //TODO implement read_property_ack_handler
/* handle any errors coming back */
apdu_set_error_handler(SERVICE_CONFIRMED_READ_PROPERTY, errorHandler);
apdu_set_abort_handler(abortHandler);
apdu_set_reject_handler(rejectHandler);
}
uint64_t BACnetClient::readProperty(uint32_t deviceObjInstance, uint32_t objInstance, BACNET_OBJECT_TYPE objType, BACNET_PROPERTY_ID objProperty, int32_t objIndex) {
......@@ -101,13 +116,39 @@ uint64_t BACnetClient::readProperty(uint32_t deviceObjInstance, uint32_t objInst
// 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);
if (pdu_lenRec) {
int apdu_offset = 0;
BACNET_ADDRESS destRec = { 0 };
BACNET_NPDU_DATA npdu_dataRec = { 0 };
#ifdef DEBUG
LOG(debug) << "BACnet: Protocol Version = " << (unsigned) RecBuf[0];
#else
apdu_offset = npdu_decode(&RecBuf[0], &destRec, &src, &npdu_dataRec);
if (npdu_data.network_layer_message) {
/* network layer message received! Handle it! */
LOG(error) << "Network layer message received. Discarding";
} else if ((apdu_offset > 0) && (apdu_offset <= pdu_lenRec)) {
if ((destRec.net == 0) || (destRec.net == BACNET_BROADCAST_NETWORK)) {
/* only handle the version that we know how to handle */
/* and we are not a router, so ignore messages with
routing information cause they are not for us */
if (!(destRec.net == BACNET_BROADCAST_NETWORK) && !((RecBuf[apdu_offset] & 0xF0) == PDU_TYPE_CONFIRMED_SERVICE_REQUEST)) {
apdu_handler(&src, &RecBuf[apdu_offset], (uint16_t) (pdu_lenRec - apdu_offset));
}
}
}
} else {
tsm_free_invoke_id(invoke_id);
throw std::runtime_error("Timeout while waiting for response");
}
if (!tsm_invoke_id_free(invoke_id)) { //should be freed by apdu_handler on success
tsm_free_invoke_id(invoke_id);
throw std::runtime_error("Invoke ID was not freed");
}
return 0;
}
......@@ -118,3 +159,41 @@ void BACnetClient::initializeStrand(boost::asio::io_service& io) {
}
}
void BACnetClient::handler_unrecognized_service(uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) {
int len = 0;
int pdu_len = 0;
int bytes_sent = 0;
BACNET_NPDU_DATA npdu_data;
BACNET_ADDRESS my_address;
(void) service_request;
(void) service_len;
/* encode the NPDU portion of the packet */
datalink_get_my_address(&my_address);
npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL);
pdu_len = npdu_encode_pdu(&_handlerTransmitBuffer[0], src, &my_address, &npdu_data); //TODO any problems with using member handlerTransmitBuffer ?
/* encode the APDU portion of the packet */
len = reject_encode_apdu(&_handlerTransmitBuffer[pdu_len], service_data->invoke_id, REJECT_REASON_UNRECOGNIZED_SERVICE);
pdu_len += len;
/* send the data */
bytes_sent = datalink_send_pdu(src, &npdu_data, &_handlerTransmitBuffer[0], pdu_len);
if (bytes_sent > 0) {
LOG(info) << "BACnet: Sent Reject";
} else {
LOG(info) << "BACnet: Could not send Reject: " << strerror(errno);
}
}
void BACnetClient::errorHandler(BACNET_ADDRESS * src, uint8_t invoke_id, BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code) {
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 invoke_id, uint8_t abort_reason, bool server) {
LOG(error) << "BACnet Abort: " << bactext_abort_reason_name((int) abort_reason);
}
void BACnetClient::rejectHandler(BACNET_ADDRESS * src, uint8_t invoke_id, uint8_t reject_reason) {
LOG(error) << "BACnet Reject: " << bactext_reject_reason_name((int) reject_reason);
}
......@@ -45,6 +45,12 @@ public:
private:
/* Handler to process incoming BACnet data */
void handler_unrecognized_service(uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data);
void errorHandler(BACNET_ADDRESS * src, uint8_t invoke_id, BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code);
void abortHandler(BACNET_ADDRESS * src, uint8_t invoke_id, uint8_t abort_reason, bool server);
void rejectHandler(BACNET_ADDRESS * src, uint8_t invoke_id, uint8_t reject_reason);
unsigned _timeout;
BACNET_READ_PROPERTY_DATA _propertyData;
uint8_t _handlerTransmitBuffer[MAX_PDU];
......
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