/** * Sends a TimeSync message to a specific destination * * @param dest - #BACNET_ADDRESS - the specific destination * @param bdate - #BACNET_DATE * @param btime - #BACNET_TIME */ void Send_TimeSync_Remote( BACNET_ADDRESS * dest, BACNET_DATE * bdate, BACNET_TIME * btime) { int len = 0; int pdu_len = 0; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; BACNET_ADDRESS my_address; if (!dcc_communication_enabled()) return; datalink_get_my_address(&my_address); /* encode the NPDU portion of the packet */ npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], dest, &my_address, &npdu_data); /* encode the APDU portion of the packet */ len = timesync_encode_apdu(&Handler_Transmit_Buffer[pdu_len], bdate, btime); pdu_len += len; /* send it out the datalink */ bytes_sent = datalink_send_pdu(dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) fprintf(stderr, "Failed to Send Time-Synchronization Request (%s)!\n", strerror(errno)); #endif }
/** Send a Who-Is request to a remote network for a specific device, a range, * or any device. * If low_limit and high_limit both are -1, then the range is unlimited. * If low_limit and high_limit have the same non-negative value, then only * that device will respond. * Otherwise, low_limit must be less than high_limit. * @param target_address [in] BACnet address of target router * @param low_limit [in] Device Instance Low Range, 0 - 4,194,303 or -1 * @param high_limit [in] Device Instance High Range, 0 - 4,194,303 or -1 */ void Send_WhoIs_To_Network( BACNET_ADDRESS * target_address, int32_t low_limit, int32_t high_limit) { int len = 0; int pdu_len = 0; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; BACNET_ADDRESS my_address; datalink_get_my_address(&my_address); /* encode the NPDU portion of the packet */ npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], target_address, &my_address, &npdu_data); /* encode the APDU portion of the packet */ len = whois_encode_apdu(&Handler_Transmit_Buffer[pdu_len], low_limit, high_limit); pdu_len += len; bytes_sent = datalink_send_pdu(target_address, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) fprintf(stderr, "Failed to Send Who-Is Request (%s)!\n", strerror(errno)); #endif }
void Send_UnconfirmedPrivateTransfer( BACNET_ADDRESS * dest, BACNET_PRIVATE_TRANSFER_DATA * private_data) { int len = 0; int pdu_len = 0; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; BACNET_ADDRESS my_address; if (!dcc_communication_enabled()) return; datalink_get_my_address(&my_address); /* encode the NPDU portion of the packet */ npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], dest, &my_address, &npdu_data); /* encode the APDU portion of the packet */ len = ptransfer_ack_encode_apdu(&Handler_Transmit_Buffer[pdu_len],invoke_id, private_data); pdu_len += len; bytes_sent = datalink_send_pdu(dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) fprintf(stderr, "Failed to Send UnconfirmedPrivateTransfer Request (%s)!\n", strerror(errno)); #endif }
void Send_Initialize_Routing_Table_Ack( BACNET_ROUTER_PORT * router_port_list) { int pdu_len = 0; BACNET_ADDRESS dest; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; /* FIXME: is this parameter needed? */ router_port_list = router_port_list; /* setup packet for sending */ npdu_encode_npdu_network(&npdu_data, NETWORK_MESSAGE_INIT_RT_TABLE_ACK, false, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], NULL, NULL, &npdu_data); /* encode the optional DNET list portion of the packet */ datalink_get_broadcast_address(&dest); bytes_sent = datalink_send_pdu(&dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) fprintf(stderr, "Failed to Send Initialize-Routing-Table-Ack message (%s)!\n", strerror(errno)); #endif }
void Send_TimeSyncUTC( BACNET_DATE * bdate, BACNET_TIME * btime) { int pdu_len = 0; BACNET_ADDRESS dest; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; if (!dcc_communication_enabled()) return; /* we could use unicast or broadcast */ datalink_get_broadcast_address(&dest); /* encode the NPDU portion of the packet */ npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest, NULL, &npdu_data); /* encode the APDU portion of the packet */ pdu_len = timesync_utc_encode_apdu(&Handler_Transmit_Buffer[0], bdate, btime); bytes_sent = datalink_send_pdu(&dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) fprintf(stderr, "Failed to Send UTC-Time-Synchronization Request (%s)!\n", strerror(errno)); #endif }
/* called once a millisecond or slower */ void tsm_timer_milliseconds( uint16_t milliseconds) { unsigned i = 0; /* counter */ for (i = 0; i < MAX_TSM_TRANSACTIONS; i++) { if (TSM_List[i].state == TSM_STATE_AWAIT_CONFIRMATION) { if (TSM_List[i].RequestTimer > milliseconds) TSM_List[i].RequestTimer -= milliseconds; else TSM_List[i].RequestTimer = 0; /* AWAIT_CONFIRMATION */ if (TSM_List[i].RequestTimer == 0) { if (TSM_List[i].RetryCount < apdu_retries()) { TSM_List[i].RequestTimer = apdu_timeout(); TSM_List[i].RetryCount++; datalink_send_pdu(&TSM_List[i].dest, &TSM_List[i].npdu_data, &TSM_List[i].apdu[0], TSM_List[i].apdu_len); } else { /* note: the invoke id has not been cleared yet and this indicates a failed message: IDLE and a valid invoke id */ TSM_List[i].state = TSM_STATE_IDLE; } } } } }
void Send_Initialize_Routing_Table( BACNET_ADDRESS * dst, BACNET_ROUTER_PORT * router_port_list) { int len = 0; int pdu_len = 0; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; uint8_t number_of_ports = 0; BACNET_ROUTER_PORT *router_port; uint8_t i = 0; /* counter */ npdu_encode_npdu_network(&npdu_data, NETWORK_MESSAGE_INIT_RT_TABLE, true, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], NULL, NULL, &npdu_data); /* encode the optional port_info list portion of the packet */ router_port = router_port_list; while (router_port) { number_of_ports++; router_port = router_port->next; } Handler_Transmit_Buffer[pdu_len++] = number_of_ports; if (number_of_ports) { router_port = router_port_list; while (router_port) { len = encode_unsigned16(&Handler_Transmit_Buffer[pdu_len], router_port->dnet); pdu_len += len; Handler_Transmit_Buffer[pdu_len++] = router_port->id; Handler_Transmit_Buffer[pdu_len++] = router_port->info_len; for (i = 0; i < router_port->info_len; i++) { Handler_Transmit_Buffer[pdu_len++] = router_port->info[i]; } router_port = router_port->next; } } #if PRINT_ENABLED fprintf(stderr, "Send Initialize-Routing-Table message\n"); #endif bytes_sent = datalink_send_pdu(dst, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) fprintf(stderr, "Failed to send Initialize-Routing-Table message (%s)!\n", strerror(errno)); #endif }
/** Sends an Unconfirmed COV Notification. * @ingroup DSCOV * * @param buffer [in,out] The buffer to build the message in for sending. * @param cov_data [in] The COV update information to be encoded. * @return Size of the message sent (bytes), or a negative value on error. */ int Send_UCOV_Notify( uint8_t * buffer, BACNET_COV_DATA * cov_data) { int pdu_len = 0; BACNET_ADDRESS dest; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; pdu_len = ucov_notify_encode_pdu(buffer, &dest, &npdu_data, cov_data); bytes_sent = datalink_send_pdu(&dest, &npdu_data, &buffer[0], pdu_len); return bytes_sent; }
int Send_ConfirmedPrivateTransfer( BACNET_ADDRESS * dest, BACNET_PRIVATE_TRANSFER_DATA * private_data) { int len = 0; int pdu_len = 0; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; BACNET_ADDRESS my_address; int invoke_id = 0; if (!dcc_communication_enabled()) return -1; datalink_get_my_address(&my_address); /* encode the NPDU portion of the packet */ // npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); //Fance npdu_encode_npdu_data(&npdu_data, true, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], dest, &my_address, &npdu_data); /* encode the APDU portion of the packet */ invoke_id = tsm_next_free_invokeID(); if(invoke_id==0)//这里是当没有可用的调用ID的时候将所有ID都清零;变为可用; tsm_free_all_invoke_id(); len = ptransfer_encode_apdu(&Handler_Transmit_Buffer[pdu_len],invoke_id,private_data); //这里的还需要完善 Invoke ID // uptransfer_encode_apdu(&Handler_Transmit_Buffer[pdu_len], //Fance // private_data); pdu_len += len; bytes_sent = datalink_send_pdu(dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) fprintf(stderr, "Failed to Send UnconfirmedPrivateTransfer Request (%s)!\n", strerror(errno)); #endif if(bytes_sent>0) return invoke_id; else return -2; }
/** Send a Who-Has request for a device which has a specific Object type and ID. * @ingroup DMDOB * If low_limit and high_limit both are -1, then the device ID range is unlimited. * If low_limit and high_limit have the same non-negative value, then only * that device will respond. * Otherwise, low_limit must be less than high_limit for a range. * @param low_limit [in] Device Instance Low Range, 0 - 4,194,303 or -1 * @param high_limit [in] Device Instance High Range, 0 - 4,194,303 or -1 * @param object_type [in] The BACNET_OBJECT_TYPE of the desired Object. * @param object_instance [in] The ID of the desired Object. */ void Send_WhoHas_Object( int32_t low_limit, int32_t high_limit, BACNET_OBJECT_TYPE object_type, uint32_t object_instance) { int len = 0; int pdu_len = 0; BACNET_ADDRESS dest; int bytes_sent = 0; BACNET_WHO_HAS_DATA data; BACNET_NPDU_DATA npdu_data; BACNET_ADDRESS my_address; /* if we are forbidden to send, don't send! */ if (!dcc_communication_enabled()) return; /* Who-Has is a global broadcast */ datalink_get_broadcast_address(&dest); datalink_get_my_address(&my_address); /* encode the NPDU portion of the packet */ npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest, &my_address, &npdu_data); /* encode the APDU portion of the packet */ data.low_limit = low_limit; data.high_limit = high_limit; data.is_object_name = false; data.object.identifier.type = object_type; data.object.identifier.instance = object_instance; len = whohas_encode_apdu(&Handler_Transmit_Buffer[pdu_len], &data); pdu_len += len; bytes_sent = datalink_send_pdu(&dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) fprintf(stderr, "Failed to Send Who-Has Request (%s)!\n", strerror(errno)); #endif }
/* pDNET_list: list of networks for which I am a router, terminated with -1 */ void Send_I_Am_Router_To_Network( const int DNET_list[]) { int len = 0; int pdu_len = 0; BACNET_ADDRESS dest; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; uint16_t dnet = 0; unsigned index = 0; npdu_encode_npdu_network(&npdu_data, NETWORK_MESSAGE_I_AM_ROUTER_TO_NETWORK, false, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], NULL, NULL, &npdu_data); /* encode the optional DNET list portion of the packet */ #if PRINT_ENABLED fprintf(stderr, "Send I-Am-Router-To-Network message to:\n"); #endif while (DNET_list[index] != -1) { dnet = DNET_list[index]; len = encode_unsigned16(&Handler_Transmit_Buffer[pdu_len], dnet); pdu_len += len; index++; #if PRINT_ENABLED fprintf(stderr, "%u\n", dnet); #endif } /* I-Am-Router-To-Network shall always be transmitted with a broadcast MAC address. */ datalink_get_broadcast_address(&dest); bytes_sent = datalink_send_pdu(&dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) fprintf(stderr, "Failed to send I-Am-Router-To-Network message (%s)!\n", strerror(errno)); #endif }
/** Sends an Abort message * @param buffer The buffer to build the message for sending. * @param dest - Destination address to send the message * @param invoke_id - use to match up a reply * @param reason - #BACNET_ABORT_REASON enumeration * @param server - true or false * * @return Size of the message sent (bytes), or a negative value on error. */ int Send_Error_To_Network( uint8_t * buffer, BACNET_ADDRESS *dest, uint8_t invoke_id, BACNET_CONFIRMED_SERVICE service, BACNET_ERROR_CLASS error_class, BACNET_ERROR_CODE error_code) { int pdu_len = 0; BACNET_ADDRESS src; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; datalink_get_my_address(&src); pdu_len = error_encode_pdu(buffer, dest, &src, &npdu_data, invoke_id, service, error_class, error_code); bytes_sent = datalink_send_pdu(dest, &npdu_data, &buffer[0], pdu_len); return bytes_sent; }
/* find a specific device, or use -1 for limit if you want unlimited */ void Send_I_Have( uint32_t device_id, BACNET_OBJECT_TYPE object_type, uint32_t object_instance, char *object_name) { int len = 0; int pdu_len = 0; BACNET_ADDRESS dest; int bytes_sent = 0; BACNET_I_HAVE_DATA data; BACNET_NPDU_DATA npdu_data; /* if we are forbidden to send, don't send! */ if (!dcc_communication_enabled()) return; /* Who-Has is a global broadcast */ datalink_get_broadcast_address(&dest); /* encode the NPDU portion of the packet */ npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest, NULL, &npdu_data); /* encode the APDU portion of the packet */ data.device_id.type = OBJECT_DEVICE; data.device_id.instance = device_id; data.object_id.type = object_type; data.object_id.instance = object_instance; characterstring_init_ansi(&data.object_name, object_name); len = ihave_encode_apdu(&Handler_Transmit_Buffer[pdu_len], &data); pdu_len += len; /* send the data */ bytes_sent = datalink_send_pdu(&dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) fprintf(stderr, "Failed to Send I-Have Reply (%s)!\n", strerror(errno)); #endif }
/* find a specific router, or use -1 for limit if you want unlimited */ void Send_Who_Is_Router_To_Network( BACNET_ADDRESS * dst, int dnet) { int len = 0; int pdu_len = 0; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; npdu_encode_npdu_network(&npdu_data, NETWORK_MESSAGE_WHO_IS_ROUTER_TO_NETWORK, false, MESSAGE_PRIORITY_NORMAL); /* fixme: should dnet/dlen/dadr be set in NPDU? */ pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], NULL, NULL, &npdu_data); /* encode the optional DNET portion of the packet */ if (dnet >= 0) { len = encode_unsigned16(&Handler_Transmit_Buffer[pdu_len], dnet); pdu_len += len; #if PRINT_ENABLED fprintf(stderr, "Send Who-Is-Router-To-Network message to %u\n", dnet); #endif } else { #if PRINT_ENABLED fprintf(stderr, "Send Who-Is-Router-To-Network message\n"); #endif } bytes_sent = datalink_send_pdu(dst, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) fprintf(stderr, "Failed to Send Who-Is-Router-To-Network Request (%s)!\n", strerror(errno)); #endif }
/** Handler for a Reinitialize Device (RD) request. * @ingroup DMRD * This handler will be invoked by apdu_handler() if it has been enabled * by a call to apdu_set_confirmed_handler(). * This handler builds a response packet, which is * - an Abort if * - the message is segmented * - if decoding fails * - an Error if * - the RD password is incorrect * - the Reinitialize Device operation fails * - a Reject if the request state is invalid * - else tries to send a simple ACK for the RD on success. * * @param service_request [in] The contents of the service request. * @param service_len [in] The length of the service_request. * @param src [in] BACNET_ADDRESS of the source of the message * @param service_data [in] The BACNET_CONFIRMED_SERVICE_DATA information * decoded from the APDU header of this message. */ void handler_reinitialize_device( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) { BACNET_REINITIALIZE_DEVICE_DATA rd_data; int len = 0; int pdu_len = 0; BACNET_NPDU_DATA npdu_data; BACNET_ADDRESS my_address; /* 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(&Handler_Transmit_Buffer[0], src, &my_address, &npdu_data); #if PRINT_ENABLED fprintf(stderr, "ReinitializeDevice!\n"); #endif if (service_data->segmented_message) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); #if PRINT_ENABLED fprintf(stderr, "ReinitializeDevice: Sending Abort - segmented message.\n"); #endif goto RD_ABORT; } /* decode the service request only */ len = rd_decode_service_request(service_request, service_len, &rd_data.state, &rd_data.password); #if PRINT_ENABLED if (len > 0) { fprintf(stderr, "ReinitializeDevice: state=%u password=%s\n", (unsigned) rd_data.state, characterstring_value(&rd_data.password)); } else { fprintf(stderr, "ReinitializeDevice: Unable to decode request!\n"); } #endif /* bad decoding or something we didn't understand - send an abort */ if (len < 0) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_OTHER, true); #if PRINT_ENABLED fprintf(stderr, "ReinitializeDevice: Sending Abort - could not decode.\n"); #endif goto RD_ABORT; } /* check the data from the request */ if (rd_data.state >= MAX_BACNET_REINITIALIZED_STATE) { len = reject_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, REJECT_REASON_UNDEFINED_ENUMERATION); #if PRINT_ENABLED fprintf(stderr, "ReinitializeDevice: Sending Reject - undefined enumeration\n"); #endif } else { #if BAC_ROUTING /* Check to see if the current Device supports this service. */ len = Routed_Device_Service_Approval (SERVICE_CONFIRMED_REINITIALIZE_DEVICE, (int) rd_data.state, &Handler_Transmit_Buffer[pdu_len], service_data->invoke_id); if (len > 0) goto RD_ABORT; #endif if (Device_Reinitialize(&rd_data)) { len = encode_simple_ack(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_REINITIALIZE_DEVICE); #if PRINT_ENABLED fprintf(stderr, "ReinitializeDevice: Sending Simple Ack!\n"); #endif } else { len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_REINITIALIZE_DEVICE, rd_data.error_class, rd_data.error_code); #if PRINT_ENABLED fprintf(stderr, "ReinitializeDevice: Sending Error.\n"); #endif } } RD_ABORT: pdu_len += len; len = datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); if (len <= 0) { #if PRINT_ENABLED fprintf(stderr, "ReinitializeDevice: Failed to send PDU (%s)!\n", strerror(errno)); #endif } return; }
/* returns invoke id of 0 if device is not bound or no tsm available */ uint8_t Send_ReadRange_Request( uint32_t device_id, /* destination device */ BACNET_READ_RANGE_DATA * read_access_data) { BACNET_ADDRESS dest; BACNET_ADDRESS my_address; unsigned max_apdu = 0; uint8_t invoke_id = 0; bool status = false; int len = 0; int pdu_len = 0; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; if (!dcc_communication_enabled()) return 0; /* is the device bound? */ status = address_get_by_device(device_id, &max_apdu, &dest); /* is there a tsm available? */ if (status) invoke_id = tsm_next_free_invokeID(); if (invoke_id) { /* encode the NPDU portion of the packet */ datalink_get_my_address(&my_address); npdu_encode_npdu_data(&npdu_data, true, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest, &my_address, &npdu_data); /* encode the APDU portion of the packet */ len = rr_encode_apdu(&Handler_Transmit_Buffer[pdu_len], invoke_id, read_access_data); if (len <= 0) { return 0; } pdu_len += len; /* is it small enough for the the destination to receive? 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 ((unsigned) pdu_len < max_apdu) { tsm_set_confirmed_unsegmented_transaction(invoke_id, &dest, &npdu_data, &Handler_Transmit_Buffer[0], (uint16_t) pdu_len); bytes_sent = datalink_send_pdu(&dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) fprintf(stderr, "Failed to Send ReadRange Request (%s)!\n", strerror(errno)); #endif } else { tsm_free_invoke_id(invoke_id); invoke_id = 0; #if PRINT_ENABLED fprintf(stderr, "Failed to Send ReadRange Request (exceeds destination maximum APDU)!\n"); #endif } } return invoke_id; }
/** Handler for a COV Subscribe Service request. * @ingroup DSCOV * This handler will be invoked by apdu_handler() if it has been enabled * by a call to apdu_set_confirmed_handler(). * This handler builds a response packet, which is * - an Abort if * - the message is segmented * - if decoding fails * - an ACK, if cov_subscribe() succeeds * - an Error if cov_subscribe() fails * * @param service_request [in] The contents of the service request. * @param service_len [in] The length of the service_request. * @param src [in] BACNET_ADDRESS of the source of the message * @param service_data [in] The BACNET_CONFIRMED_SERVICE_DATA information * decoded from the APDU header of this message. */ void handler_cov_subscribe( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) { BACNET_SUBSCRIBE_COV_DATA cov_data; int len = 0; int pdu_len = 0; int npdu_len = 0; int apdu_len = 0; BACNET_NPDU_DATA npdu_data; bool success = false; int bytes_sent = 0; BACNET_ADDRESS my_address; bool error = false; /* initialize a common abort code */ cov_data.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; /* encode the NPDU portion of the packet */ datalink_get_my_address(&my_address); npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); npdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address, &npdu_data); if (service_data->segmented_message) { /* we don't support segmentation - send an abort */ len = BACNET_STATUS_ABORT; #if PRINT_ENABLED fprintf(stderr, "SubscribeCOV: Segmented message. Sending Abort!\n"); #endif error = true; goto COV_ABORT; } len = cov_subscribe_decode_service_request(service_request, service_len, &cov_data); #if PRINT_ENABLED if (len <= 0) fprintf(stderr, "SubscribeCOV: Unable to decode Request!\n"); #endif if (len < 0) { error = true; goto COV_ABORT; } cov_data.error_class = ERROR_CLASS_OBJECT; cov_data.error_code = ERROR_CODE_UNKNOWN_OBJECT; success = cov_subscribe(src, &cov_data, &cov_data.error_class, &cov_data.error_code); if (success) { apdu_len = encode_simple_ack(&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id, SERVICE_CONFIRMED_SUBSCRIBE_COV); #if PRINT_ENABLED fprintf(stderr, "SubscribeCOV: Sending Simple Ack!\n"); #endif } else { len = BACNET_STATUS_ERROR; error = true; #if PRINT_ENABLED fprintf(stderr, "SubscribeCOV: Sending Error!\n"); #endif } COV_ABORT: if (error) { if (len == BACNET_STATUS_ABORT) { apdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id, abort_convert_error_code(cov_data.error_code), true); #if PRINT_ENABLED fprintf(stderr, "SubscribeCOV: Sending Abort!\n"); #endif } else if (len == BACNET_STATUS_ERROR) { apdu_len = bacerror_encode_apdu(&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id, SERVICE_CONFIRMED_SUBSCRIBE_COV, cov_data.error_class, cov_data.error_code); #if PRINT_ENABLED fprintf(stderr, "SubscribeCOV: Sending Error!\n"); #endif } else if (len == BACNET_STATUS_REJECT) { apdu_len = reject_encode_apdu(&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id, reject_convert_error_code(cov_data.error_code)); #if PRINT_ENABLED fprintf(stderr, "SubscribeCOV: Sending Reject!\n"); #endif } } pdu_len = npdu_len + apdu_len; bytes_sent = datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) fprintf(stderr, "SubscribeCOV: Failed to send PDU (%s)!\n", strerror(errno)); #else bytes_sent = bytes_sent; #endif return; }
void handler_atomic_read_file( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) { BACNET_ATOMIC_READ_FILE_DATA data; int len = 0; int pdu_len = 0; bool error = false; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; BACNET_ADDRESS my_address; BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT; BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT; #if PRINT_ENABLED fprintf(stderr, "Received Atomic-Read-File Request!\n"); #endif /* 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(&Handler_Transmit_Buffer[0], src, &my_address, &npdu_data); if (service_data->segmented_message) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); #if PRINT_ENABLED fprintf(stderr, "ARF: Segmented Message. Sending Abort!\n"); #endif goto ARF_ABORT; } len = arf_decode_service_request(service_request, service_len, &data); /* bad decoding - send an abort */ if (len < 0) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_OTHER, true); #if PRINT_ENABLED fprintf(stderr, "Bad Encoding. Sending Abort!\n"); #endif goto ARF_ABORT; } if (data.object_type == OBJECT_FILE) { if (!bacfile_valid_instance(data.object_instance)) { error = true; } else if (data.access == FILE_STREAM_ACCESS) { if (data.type.stream.requestedOctetCount < octetstring_capacity(&data.fileData[0])) { if (bacfile_read_stream_data(&data)) { #if PRINT_ENABLED fprintf(stderr, "ARF: Stream offset %d, %d octets.\n", data.type.stream.fileStartPosition, data.type.stream.requestedOctetCount); #endif len = arf_ack_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, &data); } else { error = true; error_class = ERROR_CLASS_OBJECT; error_code = ERROR_CODE_FILE_ACCESS_DENIED; } } else { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); #if PRINT_ENABLED fprintf(stderr, "Too Big To Send (%d >= %d). Sending Abort!\n", data.type.stream.requestedOctetCount, octetstring_capacity(&data.fileData[0])); #endif } } else if (data.access == FILE_RECORD_ACCESS) { if (data.type.record.fileStartRecord >= BACNET_READ_FILE_RECORD_COUNT) { error_class = ERROR_CLASS_SERVICES; error_code = ERROR_CODE_INVALID_FILE_START_POSITION; error = true; } else if (bacfile_read_stream_data(&data)) { #if PRINT_ENABLED fprintf(stderr, "ARF: fileStartRecord %d, %u RecordCount.\n", data.type.record.fileStartRecord, data.type.record.RecordCount); #endif len = arf_ack_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, &data); } else { error = true; error_class = ERROR_CLASS_OBJECT; error_code = ERROR_CODE_FILE_ACCESS_DENIED; } } else { error = true; error_class = ERROR_CLASS_SERVICES; error_code = ERROR_CODE_INVALID_FILE_ACCESS_METHOD; #if PRINT_ENABLED fprintf(stderr, "Record Access Requested. Sending Error!\n"); #endif } } else { error = true; error_class = ERROR_CLASS_SERVICES; error_code = ERROR_CODE_INCONSISTENT_OBJECT_TYPE; } if (error) { len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_ATOMIC_READ_FILE, error_class, error_code); } ARF_ABORT: pdu_len += len; bytes_sent = datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) { fprintf(stderr, "Failed to send PDU (%s)!\n", strerror(errno)); } #endif return; }
/** returns the invoke ID for confirmed request, or zero on failure */ uint8_t Send_Write_Property_Request_Data( BACNET_ADDRESS * dest, uint16_t max_apdu, BACNET_OBJECT_TYPE object_type, uint32_t object_instance, BACNET_PROPERTY_ID object_property, uint8_t * application_data, int application_data_len, uint8_t priority, uint32_t array_index) { BACNET_ADDRESS my_address; uint8_t invoke_id = 0; int len = 0; int pdu_len = 0; int bytes_sent = 0; BACNET_WRITE_PROPERTY_DATA data; BACNET_NPDU_DATA npdu_data; if (!dcc_communication_enabled()) return 0; /* is there a tsm available? */ invoke_id = tsm_next_free_invokeID(); if (invoke_id) { /* encode the NPDU portion of the packet */ datalink_get_my_address(&my_address); npdu_encode_npdu_data(&npdu_data, true, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], dest, &my_address, &npdu_data); /* encode the APDU portion of the packet */ data.object_type = object_type; data.object_instance = object_instance; data.object_property = object_property; data.array_index = array_index; data.application_data_len = application_data_len; memcpy(&data.application_data[0], &application_data[0], application_data_len); data.priority = priority; len = wp_encode_apdu(&Handler_Transmit_Buffer[pdu_len], invoke_id, &data); pdu_len += len; /* 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 (pdu_len < max_apdu) { tsm_set_confirmed_unsegmented_transaction(invoke_id, dest, &npdu_data, &Handler_Transmit_Buffer[0], (uint16_t) pdu_len); bytes_sent = datalink_send_pdu(dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) fprintf(stderr, "Failed to Send WriteProperty Request (%s)!\n", strerror(errno)); #endif } else { tsm_free_invoke_id(invoke_id); invoke_id = 0; #if PRINT_ENABLED fprintf(stderr, "Failed to Send WriteProperty Request " "(exceeds destination maximum APDU)!\n"); #endif } } else { #if PRINT_ENABLED fprintf(stderr, "Ran out of invoke ids!\n"); #endif } return invoke_id; }
void handler_read_property( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) { BACNET_READ_PROPERTY_DATA data; int len = 0; int pdu_len = 0; BACNET_NPDU_DATA npdu_data; bool error = false; int bytes_sent = 0; BACNET_ERROR_CLASS error_class = ERROR_CLASS_OBJECT; BACNET_ERROR_CODE error_code = ERROR_CODE_UNKNOWN_OBJECT; BACNET_ADDRESS my_address; /* 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(&Handler_Transmit_Buffer[0], src, &my_address, &npdu_data); if (service_data->segmented_message) { /* we don't support segmentation - send an abort */ len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); goto RP_ABORT; } len = rp_decode_service_request(service_request, service_len, &data); if (len < 0) { /* bad decoding - send an abort */ len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_OTHER, true); goto RP_ABORT; } /* most cases will be error */ error = true; len = Encode_Property_APDU(&Temp_Buf[0], data.object_type, data.object_instance, data.object_property, data.array_index, &error_class, &error_code); if (len >= 0) { /* encode the APDU portion of the packet */ data.application_data = &Temp_Buf[0]; data.application_data_len = len; /* FIXME: probably need a length limitation sent with encode */ len = rp_ack_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, &data); error = false; } if (error) { if (len == -2) { /* BACnet APDU too small to fit data, so proper response is Abort */ len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); goto RP_ABORT; } len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_READ_PROPERTY, error_class, error_code); } RP_ABORT: pdu_len += len; bytes_sent = datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); return; }
void handler_read_range( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) { BACNET_READ_RANGE_DATA data; int len = 0; int pdu_len = 0; BACNET_NPDU_DATA npdu_data; bool error = false; int bytes_sent = 0; BACNET_ADDRESS my_address; data.error_class = ERROR_CLASS_OBJECT; data.error_code = ERROR_CODE_UNKNOWN_OBJECT; /* 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(&Handler_Transmit_Buffer[0], src, &my_address, &npdu_data); if (service_data->segmented_message) { /* we don't support segmentation - send an abort */ len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); #if PRINT_ENABLED fprintf(stderr, "RR: Segmented message. Sending Abort!\n"); #endif goto RR_ABORT; } memset(&data, 0, sizeof(data)); /* start with blank canvas */ len = rr_decode_service_request(service_request, service_len, &data); #if PRINT_ENABLED if (len <= 0) fprintf(stderr, "RR: Unable to decode Request!\n"); #endif if (len < 0) { /* bad decoding - send an abort */ len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_OTHER, true); #if PRINT_ENABLED fprintf(stderr, "RR: Bad Encoding. Sending Abort!\n"); #endif goto RR_ABORT; } /* assume that there is an error */ error = true; len = Encode_RR_payload(&Temp_Buf[0], &data); if (len >= 0) { /* encode the APDU portion of the packet */ data.application_data = &Temp_Buf[0]; data.application_data_len = len; /* FIXME: probably need a length limitation sent with encode */ len = rr_ack_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, &data); #if PRINT_ENABLED fprintf(stderr, "RR: Sending Ack!\n"); #endif error = false; } if (error) { if (len == -2) { /* BACnet APDU too small to fit data, so proper response is Abort */ len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); #if PRINT_ENABLED fprintf(stderr, "RR: Reply too big to fit into APDU!\n"); #endif } else { len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_READ_RANGE, data.error_class, data.error_code); #if PRINT_ENABLED fprintf(stderr, "RR: Sending Error!\n"); #endif } } RR_ABORT: pdu_len += len; bytes_sent = datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) fprintf(stderr, "Failed to send PDU (%s)!\n", strerror(errno)); #endif return; }
void handler_lso( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) { BACNET_LSO_DATA data; int len = 0; int pdu_len = 0; BACNET_NPDU_DATA npdu_data; int bytes_sent = 0; BACNET_ADDRESS my_address; /* 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(&Handler_Transmit_Buffer[0], src, &my_address, &npdu_data); if (service_data->segmented_message) { /* we don't support segmentation - send an abort */ len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); #if PRINT_ENABLED fprintf(stderr, "LSO: Segmented message. Sending Abort!\n"); #endif goto LSO_ABORT; } len = lso_decode_service_request(service_request, service_len, &data); #if PRINT_ENABLED if (len <= 0) fprintf(stderr, "LSO: Unable to decode Request!\n"); #endif if (len < 0) { /* bad decoding - send an abort */ len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_OTHER, true); #if PRINT_ENABLED fprintf(stderr, "LSO: Bad Encoding. Sending Abort!\n"); #endif goto LSO_ABORT; } /* ** Process Life Safety Operation Here */ #if PRINT_ENABLED fprintf(stderr, "Life Safety Operation: Received operation %d from process id %d for object %id\n", data.operation, data.processId, data.targetObject.instance); #endif len = encode_simple_ack(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_LIFE_SAFETY_OPERATION); #if PRINT_ENABLED fprintf(stderr, "Life Safety Operation: " "Sending Simple Ack!\n"); #endif LSO_ABORT: pdu_len += len; bytes_sent = datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) fprintf(stderr, "Life Safety Operation: " "Failed to send PDU (%s)!\n", strerror(errno)); #endif return; }
/** Handler for a ReadProperty Service request. * @ingroup DSRP * This handler will be invoked by apdu_handler() if it has been enabled * by a call to apdu_set_confirmed_handler(). * This handler builds a response packet, which is * - an Abort if * - the message is segmented * - if decoding fails * - if the response would be too large * - the result from Device_Read_Property(), if it succeeds * - an Error if Device_Read_Property() fails * or there isn't enough room in the APDU to fit the data. * * @param service_request [in] The contents of the service request. * @param service_len [in] The length of the service_request. * @param src [in] BACNET_ADDRESS of the source of the message * @param service_data [in] The BACNET_CONFIRMED_SERVICE_DATA information * decoded from the APDU header of this message. */ void handler_read_property( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) { BACNET_READ_PROPERTY_DATA rpdata; int len = 0; int pdu_len = 0; int apdu_len = -1; int npdu_len = -1; BACNET_NPDU_DATA npdu_data; bool error = true; /* assume that there is an error */ int bytes_sent = 0; BACNET_ADDRESS my_address; /* configure default error code as an abort since it is common */ rpdata.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; /* encode the NPDU portion of the packet */ datalink_get_my_address(&my_address); npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); npdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address, &npdu_data); if (service_data->segmented_message) { /* we don't support segmentation - send an abort */ len = BACNET_STATUS_ABORT; #if PRINT_ENABLED fprintf(stderr, "RP: Segmented message. Sending Abort!\n"); #endif goto RP_FAILURE; } len = rp_decode_service_request(service_request, service_len, &rpdata); #if PRINT_ENABLED if (len <= 0) { fprintf(stderr, "RP: Unable to decode Request!\n"); } #endif if (len < 0) { /* bad decoding - skip to error/reject/abort handling */ error = true; #if PRINT_ENABLED fprintf(stderr, "RP: Bad Encoding.\n"); #endif goto RP_FAILURE; } /* Test for case of indefinite Device object instance */ if ((rpdata.object_type == OBJECT_DEVICE) && (rpdata.object_instance == BACNET_MAX_INSTANCE)) { rpdata.object_instance = Device_Object_Instance_Number(); } apdu_len = rp_ack_encode_apdu_init(&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id, &rpdata); /* configure our storage */ rpdata.application_data = &Handler_Transmit_Buffer[npdu_len + apdu_len]; rpdata.application_data_len = sizeof(Handler_Transmit_Buffer) - (npdu_len + apdu_len); len = Device_Read_Property(&rpdata); if (len >= 0) { apdu_len += len; len = rp_ack_encode_apdu_object_property_end(&Handler_Transmit_Buffer [npdu_len + apdu_len]); apdu_len += len; if (apdu_len > service_data->max_resp) { /* too big for the sender - send an abort * Setting of error code needed here as read property processing may * have overriden the default set at start */ rpdata.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; len = BACNET_STATUS_ABORT; #if PRINT_ENABLED fprintf(stderr, "RP: Message too large.\n"); #endif } else { #if PRINT_ENABLED fprintf(stderr, "RP: Sending Ack!\n"); #endif error = false; } } else { #if PRINT_ENABLED fprintf(stderr, "RP: Device_Read_Property: "); if (len == BACNET_STATUS_ABORT) { fprintf(stderr, "Abort!\n"); } else if (len == BACNET_STATUS_ERROR) { fprintf(stderr, "Error!\n"); } else if (len == BACNET_STATUS_REJECT) { fprintf(stderr, "Reject!\n"); } else { fprintf(stderr, "Unknown Len=%d\n", len); } #endif } RP_FAILURE: if (error) { if (len == BACNET_STATUS_ABORT) { apdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id, abort_convert_error_code(rpdata.error_code), true); #if PRINT_ENABLED fprintf(stderr, "RP: Sending Abort!\n"); #endif } else if (len == BACNET_STATUS_ERROR) { apdu_len = bacerror_encode_apdu(&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id, SERVICE_CONFIRMED_READ_PROPERTY, rpdata.error_class, rpdata.error_code); #if PRINT_ENABLED fprintf(stderr, "RP: Sending Error!\n"); #endif } else if (len == BACNET_STATUS_REJECT) { apdu_len = reject_encode_apdu(&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id, reject_convert_error_code(rpdata.error_code)); #if PRINT_ENABLED fprintf(stderr, "RP: Sending Reject!\n"); #endif } } pdu_len = npdu_len + apdu_len; bytes_sent = datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) { fprintf(stderr, "Failed to send PDU (%s)!\n", strerror(errno)); } #else bytes_sent = bytes_sent; #endif return; }
/** Handler for a WriteProperty Service request. * @ingroup DSWP * This handler will be invoked by apdu_handler() if it has been enabled * by a call to apdu_set_confirmed_handler(). * This handler builds a response packet, which is * - an Abort if * - the message is segmented * - if decoding fails * - an ACK if Device_Write_Property() succeeds * - an Error if Device_Write_Property() fails * or there isn't enough room in the APDU to fit the data. * * @param service_request [in] The contents of the service request. * @param service_len [in] The length of the service_request. * @param src [in] BACNET_ADDRESS of the source of the message * @param service_data [in] The BACNET_CONFIRMED_SERVICE_DATA information * decoded from the APDU header of this message. */ void handler_write_property( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) { BACNET_WRITE_PROPERTY_DATA wp_data; int len = 0; int pdu_len = 0; BACNET_NPDU_DATA npdu_data; int bytes_sent = 0; BACNET_ADDRESS my_address; /* 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(&Handler_Transmit_Buffer[0], src, &my_address, &npdu_data); #if PRINT_ENABLED fprintf(stderr, "WP: Received Request!\n"); #endif if (service_data->segmented_message) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); #if PRINT_ENABLED fprintf(stderr, "WP: Segmented message. Sending Abort!\n"); #endif goto WP_ABORT; } /* decode the service request only */ len = wp_decode_service_request(service_request, service_len, &wp_data); #if PRINT_ENABLED if (len > 0) fprintf(stderr, "WP: type=%lu instance=%lu property=%lu priority=%lu index=%ld\n", (unsigned long) wp_data.object_type, (unsigned long) wp_data.object_instance, (unsigned long) wp_data.object_property, (unsigned long) wp_data.priority, (long) wp_data.array_index); else fprintf(stderr, "WP: Unable to decode Request!\n"); #endif /* bad decoding or something we didn't understand - send an abort */ if (len <= 0) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_OTHER, true); #if PRINT_ENABLED fprintf(stderr, "WP: Bad Encoding. Sending Abort!\n"); #endif goto WP_ABORT; } if (Device_Write_Property(&wp_data)) { len = encode_simple_ack(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY); #if PRINT_ENABLED fprintf(stderr, "WP: Sending Simple Ack!\n"); #endif } else { len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_WRITE_PROPERTY, wp_data.error_class, wp_data.error_code); #if PRINT_ENABLED fprintf(stderr, "WP: Sending Error!\n"); #endif } WP_ABORT: pdu_len += len; bytes_sent = datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) { fprintf(stderr, "WP: Failed to send PDU (%s)!\n", strerror(errno)); } #else bytes_sent = bytes_sent; #endif return; }
void handler_conf_private_trans( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) { BACNET_PRIVATE_TRANSFER_DATA data; int len; int pdu_len; bool error; int bytes_sent; BACNET_NPDU_DATA npdu_data; BACNET_ADDRESS my_address; BACNET_ERROR_CLASS error_class; BACNET_ERROR_CODE error_code; len = 0; pdu_len = 0; error = false; bytes_sent = 0; error_class = ERROR_CLASS_OBJECT; error_code = ERROR_CODE_UNKNOWN_OBJECT; #if PRINT_ENABLED fprintf(stderr, "Received Confirmed Private Transfer Request!\n"); #endif /* encode the NPDU portion of the response packet as it will be needed */ /* no matter what the outcome. */ datalink_get_my_address(&my_address); npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address, &npdu_data); if (service_data->segmented_message) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); #if PRINT_ENABLED fprintf(stderr, "CPT: Segmented Message. Sending Abort!\n"); #endif goto CPT_ABORT; } len = ptransfer_decode_service_request(service_request, service_len, &data); /* bad decoding - send an abort */ if (len < 0) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_OTHER, true); #if PRINT_ENABLED fprintf(stderr, "CPT: Bad Encoding. Sending Abort!\n"); #endif goto CPT_ABORT; } /* Simple example with service number of 0 for read block and 1 for write block We also only support our own vendor ID. In theory we could support others for compatability purposes but these interfaces are rarely documented... */ if ((data.vendorID == BACNET_VENDOR_ID) && (data.serviceNumber <= MY_SVC_WRITE)) { /* We only try to understand our own IDs and service numbers */ /* Will either return a result block or an app level status block */ ProcessPT(&data); if (data.serviceParametersLen == 0) { /* No respopnse means fatal error */ error = true; error_class = ERROR_CLASS_SERVICES; error_code = ERROR_CODE_OTHER; #if PRINT_ENABLED fprintf(stderr, "CPT: Error servicing request!\n"); #endif } len = ptransfer_ack_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, &data); } else { /* Not our vendor ID or bad service parameter */ error = true; error_class = ERROR_CLASS_SERVICES; error_code = ERROR_CODE_OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED; #if PRINT_ENABLED fprintf(stderr, "CPT: Not our Vendor ID or invalid service code!\n"); #endif } if (error) { len = ptransfer_error_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, error_class, error_code, &data); } CPT_ABORT: pdu_len += len; bytes_sent = datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) { fprintf(stderr, "Failed to send PDU (%s)!\n", strerror(errno)); } #endif return; }
static bool cov_send_request( BACNET_COV_SUBSCRIPTION * cov_subscription, BACNET_PROPERTY_VALUE * value_list) { int len = 0; int pdu_len = 0; BACNET_NPDU_DATA npdu_data; BACNET_ADDRESS my_address; int bytes_sent = 0; uint8_t invoke_id = 0; bool status = false; /* return value */ BACNET_COV_DATA cov_data; if (!dcc_communication_enabled()) { return status; } #if PRINT_ENABLED fprintf(stderr, "COVnotification: requested\n"); #endif datalink_get_my_address(&my_address); npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], &cov_subscription->dest, &my_address, &npdu_data); /* load the COV data structure for outgoing message */ cov_data.subscriberProcessIdentifier = cov_subscription->subscriberProcessIdentifier; cov_data.initiatingDeviceIdentifier = Device_Object_Instance_Number(); cov_data.monitoredObjectIdentifier.type = cov_subscription->monitoredObjectIdentifier.type; cov_data.monitoredObjectIdentifier.instance = cov_subscription->monitoredObjectIdentifier.instance; cov_data.timeRemaining = cov_subscription->lifetime; cov_data.listOfValues = value_list; if (cov_subscription->flag.issueConfirmedNotifications) { invoke_id = tsm_next_free_invokeID(); if (invoke_id) { cov_subscription->invokeID = invoke_id; len = ccov_notify_encode_apdu(&Handler_Transmit_Buffer[pdu_len], invoke_id, &cov_data); } else { goto COV_FAILED; } } else { len = ucov_notify_encode_apdu(&Handler_Transmit_Buffer[pdu_len], &cov_data); } pdu_len += len; if (cov_subscription->flag.issueConfirmedNotifications) { tsm_set_confirmed_unsegmented_transaction(invoke_id, &cov_subscription->dest, &npdu_data, &Handler_Transmit_Buffer[0], (uint16_t) pdu_len); } bytes_sent = datalink_send_pdu(&cov_subscription->dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); if (bytes_sent > 0) { status = true; } COV_FAILED: return status; }
/** Handler for a ReadPropertyMultiple Service request. * @ingroup DSRPM * This handler will be invoked by apdu_handler() if it has been enabled * by a call to apdu_set_confirmed_handler(). * This handler builds a response packet, which is * - an Abort if * - the message is segmented * - if decoding fails * - if the response would be too large * - the result from each included read request, if it succeeds * - an Error if processing fails for all, or individual errors if only some fail, * or there isn't enough room in the APDU to fit the data. * * @param service_request [in] The contents of the service request. * @param service_len [in] The length of the service_request. * @param src [in] BACNET_ADDRESS of the source of the message * @param service_data [in] The BACNET_CONFIRMED_SERVICE_DATA information * decoded from the APDU header of this message. */ void handler_read_property_multiple( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) { int len = 0; uint16_t copy_len = 0; uint16_t decode_len = 0; int pdu_len = 0; BACNET_NPDU_DATA npdu_data; int bytes_sent; BACNET_ADDRESS my_address; BACNET_RPM_DATA rpmdata; int apdu_len = 0; int npdu_len = 0; int error = 0; /* jps_debug - see if we are utilizing all the buffer */ /* memset(&Handler_Transmit_Buffer[0], 0xff, sizeof(Handler_Transmit_Buffer)); */ /* encode the NPDU portion of the packet */ datalink_get_my_address(&my_address); npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); npdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address, &npdu_data); if (service_data->segmented_message) { rpmdata.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; error = BACNET_STATUS_ABORT; #if PRINT_ENABLED fprintf(stderr, "RPM: Segmented message. Sending Abort!\r\n"); #endif goto RPM_FAILURE; } /* decode apdu request & encode apdu reply encode complex ack, invoke id, service choice */ apdu_len = rpm_ack_encode_apdu_init(&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id); for (;;) { /* Start by looking for an object ID */ len = rpm_decode_object_id(&service_request[decode_len], service_len - decode_len, &rpmdata); if (len >= 0) { /* Got one so skip to next stage */ decode_len += len; } else { /* bad encoding - skip to error/reject/abort handling */ #if PRINT_ENABLED fprintf(stderr, "RPM: Bad Encoding.\n"); #endif error = len; goto RPM_FAILURE; } /* Test for case of indefinite Device object instance */ if ((rpmdata.object_type == OBJECT_DEVICE) && (rpmdata.object_instance == BACNET_MAX_INSTANCE)) { rpmdata.object_instance = Device_Object_Instance_Number(); } /* Stick this object id into the reply - if it will fit */ len = rpm_ack_encode_apdu_object_begin(&Temp_Buf[0], &rpmdata); copy_len = memcopy(&Handler_Transmit_Buffer[npdu_len], &Temp_Buf[0], apdu_len, len, MAX_APDU); if (copy_len == 0) { #if PRINT_ENABLED fprintf(stderr, "RPM: Response too big!\r\n"); #endif rpmdata.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; error = BACNET_STATUS_ABORT; goto RPM_FAILURE; } apdu_len += copy_len; /* do each property of this object of the RPM request */ for (;;) { /* Fetch a property */ len = rpm_decode_object_property(&service_request[decode_len], service_len - decode_len, &rpmdata); if (len < 0) { /* bad encoding - skip to error/reject/abort handling */ #if PRINT_ENABLED fprintf(stderr, "RPM: Bad Encoding.\n"); #endif error = len; goto RPM_FAILURE; } decode_len += len; /* handle the special properties */ if ((rpmdata.object_property == PROP_ALL) || (rpmdata.object_property == PROP_REQUIRED) || (rpmdata.object_property == PROP_OPTIONAL)) { struct special_property_list_t property_list; unsigned property_count = 0; unsigned index = 0; BACNET_PROPERTY_ID special_object_property; if (rpmdata.array_index != BACNET_ARRAY_ALL) { /* No array index options for this special property. Encode error for this object property response */ len = rpm_ack_encode_apdu_object_property(&Temp_Buf[0], rpmdata.object_property, rpmdata.array_index); copy_len = memcopy(&Handler_Transmit_Buffer[npdu_len], &Temp_Buf[0], apdu_len, len, MAX_APDU); if (copy_len == 0) { #if PRINT_ENABLED fprintf(stderr, "RPM: Too full to encode property!\r\n"); #endif rpmdata.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; error = BACNET_STATUS_ABORT; goto RPM_FAILURE; } apdu_len += len; len = rpm_ack_encode_apdu_object_property_error(&Temp_Buf[0], ERROR_CLASS_PROPERTY, ERROR_CODE_PROPERTY_IS_NOT_AN_ARRAY); copy_len = memcopy(&Handler_Transmit_Buffer[npdu_len], &Temp_Buf[0], apdu_len, len, MAX_APDU); if (copy_len == 0) { #if PRINT_ENABLED fprintf(stderr, "RPM: Too full to encode error!\r\n"); #endif rpmdata.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; error = BACNET_STATUS_ABORT; goto RPM_FAILURE; } apdu_len += len; } else { special_object_property = rpmdata.object_property; Device_Objects_Property_List(rpmdata.object_type, &property_list); property_count = RPM_Object_Property_Count(&property_list, special_object_property); if (property_count == 0) { /* handle the error code - but use the special property */ len = RPM_Encode_Property(&Handler_Transmit_Buffer [npdu_len], (uint16_t) apdu_len, MAX_APDU, &rpmdata); if (len > 0) { apdu_len += len; } else { #if PRINT_ENABLED fprintf(stderr, "RPM: Too full for special property!\r\n"); #endif error = len; goto RPM_FAILURE; } } else { for (index = 0; index < property_count; index++) { rpmdata.object_property = RPM_Object_Property(&property_list, special_object_property, index); len = RPM_Encode_Property(&Handler_Transmit_Buffer [npdu_len], (uint16_t) apdu_len, MAX_APDU, &rpmdata); if (len > 0) { apdu_len += len; } else { #if PRINT_ENABLED fprintf(stderr, "RPM: Too full for property!\r\n"); #endif error = len; goto RPM_FAILURE; } } } } } else { /* handle an individual property */ len = RPM_Encode_Property(&Handler_Transmit_Buffer[npdu_len], (uint16_t) apdu_len, MAX_APDU, &rpmdata); if (len > 0) { apdu_len += len; } else { #if PRINT_ENABLED fprintf(stderr, "RPM: Too full for individual property!\r\n"); #endif error = len; goto RPM_FAILURE; } } if (decode_is_closing_tag_number(&service_request[decode_len], 1)) { /* Reached end of property list so cap the result list */ decode_len++; len = rpm_ack_encode_apdu_object_end(&Temp_Buf[0]); copy_len = memcopy(&Handler_Transmit_Buffer[npdu_len], &Temp_Buf[0], apdu_len, len, MAX_APDU); if (copy_len == 0) { #if PRINT_ENABLED fprintf(stderr, "RPM: Too full to encode object end!\r\n"); #endif rpmdata.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; error = BACNET_STATUS_ABORT; goto RPM_FAILURE; } else { apdu_len += copy_len; } break; /* finished with this property list */ } } if (decode_len >= service_len) { /* Reached the end so finish up */ break; } } if (apdu_len > service_data->max_resp) { /* too big for the sender - send an abort */ rpmdata.error_code = ERROR_CODE_ABORT_SEGMENTATION_NOT_SUPPORTED; error = BACNET_STATUS_ABORT; #if PRINT_ENABLED fprintf(stderr, "RPM: Message too large. Sending Abort!\n"); #endif goto RPM_FAILURE; } RPM_FAILURE: if (error) { if (error == BACNET_STATUS_ABORT) { apdu_len = abort_encode_apdu(&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id, abort_convert_error_code(rpmdata.error_code), true); #if PRINT_ENABLED fprintf(stderr, "RPM: Sending Abort!\n"); #endif } else if (error == BACNET_STATUS_ERROR) { apdu_len = bacerror_encode_apdu(&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id, SERVICE_CONFIRMED_READ_PROP_MULTIPLE, rpmdata.error_class, rpmdata.error_code); #if PRINT_ENABLED fprintf(stderr, "RPM: Sending Error!\n"); #endif } else if (error == BACNET_STATUS_REJECT) { apdu_len = reject_encode_apdu(&Handler_Transmit_Buffer[npdu_len], service_data->invoke_id, reject_convert_error_code(rpmdata.error_code)); #if PRINT_ENABLED fprintf(stderr, "RPM: Sending Reject!\n"); #endif } } pdu_len = apdu_len + npdu_len; bytes_sent = datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) { fprintf(stderr, "RPM: Failed to send PDU (%s)!\n", strerror(errno)); } #else bytes_sent = bytes_sent; #endif }
/** Handler for a Device Communication Control (DCC) request. * @ingroup DMDCC * This handler will be invoked by apdu_handler() if it has been enabled * by a call to apdu_set_confirmed_handler(). * This handler builds a response packet, which is * - an Abort if * - the message is segmented * - if decoding fails * - if not a known DCC state * - an Error if the DCC password is incorrect * - else tries to send a simple ACK for the DCC on success, * and sets the DCC state requested. * * @param service_request [in] The contents of the service request. * @param service_len [in] The length of the service_request. * @param src [in] BACNET_ADDRESS of the source of the message * @param service_data [in] The BACNET_CONFIRMED_SERVICE_DATA information * decoded from the APDU header of this message. */ void handler_device_communication_control( uint8_t * service_request, uint16_t service_len, BACNET_ADDRESS * src, BACNET_CONFIRMED_SERVICE_DATA * service_data) { uint16_t timeDuration = 0; BACNET_COMMUNICATION_ENABLE_DISABLE state = COMMUNICATION_ENABLE; BACNET_CHARACTER_STRING password; int len = 0; int pdu_len = 0; BACNET_NPDU_DATA npdu_data; BACNET_ADDRESS my_address; /* encode the NPDU portion of the reply packet */ datalink_get_my_address(&my_address); npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], src, &my_address, &npdu_data); #if PRINT_ENABLED fprintf(stderr, "DeviceCommunicationControl!\n"); #endif if (service_data->segmented_message) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_SEGMENTATION_NOT_SUPPORTED, true); #if PRINT_ENABLED fprintf(stderr, "DeviceCommunicationControl: " "Sending Abort - segmented message.\n"); #endif goto DCC_ABORT; } /* decode the service request only */ len = dcc_decode_service_request(service_request, service_len, &timeDuration, &state, &password); #if PRINT_ENABLED if (len > 0) fprintf(stderr, "DeviceCommunicationControl: " "timeout=%u state=%u password=%s\n", (unsigned) timeDuration, (unsigned) state, characterstring_value(&password)); #endif /* bad decoding or something we didn't understand - send an abort */ if (len < 0) { len = abort_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, ABORT_REASON_OTHER, true); #if PRINT_ENABLED fprintf(stderr, "DeviceCommunicationControl: " "Sending Abort - could not decode.\n"); #endif goto DCC_ABORT; } if (state >= MAX_BACNET_COMMUNICATION_ENABLE_DISABLE) { len = reject_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, REJECT_REASON_UNDEFINED_ENUMERATION); #if PRINT_ENABLED fprintf(stderr, "DeviceCommunicationControl: " "Sending Reject - undefined enumeration\n"); #endif } else { #if BAC_ROUTING /* Check to see if the current Device supports this service. */ len = Routed_Device_Service_Approval (SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL, (int) state, &Handler_Transmit_Buffer[pdu_len], service_data->invoke_id); if (len > 0) goto DCC_ABORT; #endif if (characterstring_ansi_same(&password, My_Password)) { len = encode_simple_ack(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL); #if PRINT_ENABLED fprintf(stderr, "DeviceCommunicationControl: " "Sending Simple Ack!\n"); #endif dcc_set_status_duration(state, timeDuration); } else { len = bacerror_encode_apdu(&Handler_Transmit_Buffer[pdu_len], service_data->invoke_id, SERVICE_CONFIRMED_DEVICE_COMMUNICATION_CONTROL, ERROR_CLASS_SECURITY, ERROR_CODE_PASSWORD_FAILURE); #if PRINT_ENABLED fprintf(stderr, "DeviceCommunicationControl: " "Sending Error - password failure.\n"); #endif } } DCC_ABORT: pdu_len += len; len = datalink_send_pdu(src, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); if (len <= 0) { #if PRINT_ENABLED fprintf(stderr, "DeviceCommunicationControl: " "Failed to send PDU (%s)!\n", strerror(errno)); #endif } return; }
/** Sends a Write Property Multiple request. * @param device_id [in] ID of the destination device * @param write_access_data [in] Ptr to structure with the linked list of * objects and properties to be written. * @return invoke id of outgoing message, or 0 if device is not bound or no tsm available */ uint8_t Send_Write_Property_Multiple_Request_Data( uint32_t device_id, BACNET_WRITE_ACCESS_DATA * write_access_data) { BACNET_ADDRESS dest; BACNET_ADDRESS my_address; unsigned max_apdu = 0; uint8_t invoke_id = 0; bool status = false; int len = 0; int pdu_len = 0; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; /* is the device bound? */ status = address_get_by_device(device_id, &max_apdu, &dest); /* is there a tsm available? */ if (status) invoke_id = tsm_next_free_invokeID(); if (invoke_id) { /* encode the NPDU portion of the packet */ datalink_get_my_address(&my_address); npdu_encode_npdu_data(&npdu_data, true, MESSAGE_PRIORITY_NORMAL); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], &dest, &my_address, &npdu_data); len = wpm_encode_apdu(&Handler_Transmit_Buffer[pdu_len], max_apdu, invoke_id, write_access_data); pdu_len += len; /* 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 ((unsigned) pdu_len < max_apdu) { tsm_set_confirmed_unsegmented_transaction(invoke_id, &dest, &npdu_data, &Handler_Transmit_Buffer[0], (uint16_t) pdu_len); bytes_sent = datalink_send_pdu(&dest, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); #if PRINT_ENABLED if (bytes_sent <= 0) fprintf(stderr, "Failed to Send WriteProperty Request (%s)!\n", strerror(errno)); #endif } else { tsm_free_invoke_id(invoke_id); invoke_id = 0; #if PRINT_ENABLED fprintf(stderr, "Failed to Send WriteProperty Request " "(exceeds destination maximum APDU)!\n"); #endif } } return invoke_id; }
int BacnetTimeSync( int deviceInstanceNumber, int year, int month, int day, int hour, int minute, int second, int isUTC, int UTCOffset) { BACNET_DATE bdate; BACNET_TIME btime; struct tm my_time; time_t aTime; struct tm *newTime; my_time.tm_sec = second; my_time.tm_min = minute; my_time.tm_hour = hour; my_time.tm_mday = day; my_time.tm_mon = month - 1; my_time.tm_year = year - 1900; my_time.tm_wday = 0; /* does not matter */ my_time.tm_yday = 0; /* does not matter */ my_time.tm_isdst = 0; /* does not matter */ aTime = mktime(&my_time); newTime = localtime(&aTime); bdate.year = newTime->tm_year; bdate.month = newTime->tm_mon + 1; bdate.day = newTime->tm_mday; bdate.wday = newTime->tm_wday ? newTime->tm_wday : 7; btime.hour = newTime->tm_hour; btime.min = newTime->tm_min; btime.sec = newTime->tm_sec; btime.hundredths = 0; int len = 0; int pdu_len = 0; int bytes_sent = 0; BACNET_NPDU_DATA npdu_data; BACNET_ADDRESS my_address; uint8_t Handler_Transmit_Buffer[MAX_PDU] = { 0 }; /* Loop for eary exit */ do { if (!dcc_communication_enabled()) { LogError("DCC communicaiton is not enabled"); break; } /* encode the NPDU portion of the packet */ npdu_encode_npdu_data(&npdu_data, false, MESSAGE_PRIORITY_NORMAL); datalink_get_my_address(&my_address); pdu_len = npdu_encode_pdu(&Handler_Transmit_Buffer[0], &Target_Address, &my_address, &npdu_data); /* encode the APDU portion of the packet */ len = timesync_encode_apdu(&Handler_Transmit_Buffer[pdu_len], &bdate, &btime); pdu_len += len; /* send it out the datalink */ bytes_sent = datalink_send_pdu(&Target_Address, &npdu_data, &Handler_Transmit_Buffer[0], pdu_len); if (bytes_sent <= 0) { char errorMsg[64]; sprintf(errorMsg, "Failed to Send Time-Synchronization Request (%s)!", strerror(errno)); LogError(errorMsg); break; } Wait_For_Answer_Or_Timeout(100, waitAnswer); } while (false); int isFailure = Error_Detected; Error_Detected = 0; return isFailure; }