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 }
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 }
/** Send a local Who-Is request 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 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_Local( int32_t low_limit, int32_t high_limit) { BACNET_ADDRESS dest; char temp[6]; int loop; if (!dcc_communication_enabled()) return; /* Who-Is is a global broadcast */ datalink_get_broadcast_address(&dest); /* encode the NPDU portion of the packet */ /* I added this to make it a local broadcast */ dest.net = 0; /* Not sure why this happens but values are backwards so they need to be reversed */ temp[0] = dest.mac[3]; temp[1] = dest.mac[2]; temp[2] = dest.mac[1]; temp[3] = dest.mac[0]; temp[4] = dest.mac[5]; temp[5] = dest.mac[4]; for (loop = 0; loop < 6; loop++) { dest.mac[loop] = temp[loop]; } Send_WhoIs_To_Network(&dest, low_limit, high_limit); }
/** * Sends a TimeSync message as a broadcast * * @param bdate - #BACNET_DATE * @param btime - #BACNET_TIME */ void Send_TimeSync( BACNET_DATE * bdate, BACNET_TIME * btime) { BACNET_ADDRESS dest; datalink_get_broadcast_address(&dest); Send_TimeSync_Remote(&dest, bdate, btime); }
int main( int argc, char *argv[]) { BACNET_ADDRESS src = { 0 }; /* address where message came from */ uint16_t pdu_len = 0; unsigned timeout = 100; /* milliseconds */ BACNET_ADDRESS my_address, broadcast_address; (void) argc; (void) argv; Device_Set_Object_Instance_Number(4194300); address_init(); Init_Service_Handlers(); dlenv_init(); datalink_get_broadcast_address(&broadcast_address); print_address("Broadcast", &broadcast_address); datalink_get_my_address(&my_address); print_address("Address", &my_address); printf("BACnet stack running...\n"); /* loop forever */ for (;;) { /* input */ /* returns 0 bytes on timeout */ pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout); /* process */ if (pdu_len) { npdu_handler(&src, &Rx_Buf[0], pdu_len); } if (I_Am_Request) { I_Am_Request = false; Send_I_Am(&Handler_Transmit_Buffer[0]); } else if (Who_Is_Request) { Who_Is_Request = false; Send_WhoIs(-1, -1); } else { Read_Properties(); } /* output */ /* blink LEDs, Turn on or off outputs, etc */ /* wait for ESC from keyboard before quitting */ if (kbhit() && (getch() == 0x1B)) break; } print_address_cache(); return 0; }
/** Send a global Who-Is request 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 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_Global( int32_t low_limit, int32_t high_limit) { BACNET_ADDRESS dest; if (!dcc_communication_enabled()) return; /* Who-Is is a global broadcast */ datalink_get_broadcast_address(&dest); Send_WhoIs_To_Network(&dest, low_limit, high_limit); }
/** 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 }
/* 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 }
int ucov_notify_encode_pdu( uint8_t * buffer, BACNET_ADDRESS * dest, BACNET_NPDU_DATA * npdu_data, BACNET_COV_DATA * cov_data) { int len = 0; int pdu_len = 0; BACNET_ADDRESS my_address; datalink_get_my_address(&my_address); /* unconfirmed is a 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(&buffer[0], dest, &my_address, npdu_data); /* encode the APDU portion of the packet */ len = ucov_notify_encode_apdu(&buffer[pdu_len], cov_data); pdu_len += len; return pdu_len; }
int main( int argc, char *argv[]) { BACNET_ADDRESS src = { 0 }; /* address where message came from */ uint16_t pdu_len = 0; unsigned timeout = 10; /* milliseconds */ unsigned max_apdu = 0; time_t elapsed_seconds = 0; time_t last_seconds = 0; time_t current_seconds = 0; time_t timeout_seconds = 0; time_t delta_seconds = 0; bool found = false; char *filename = NULL; char *value_string = NULL; bool status = false; int args_remaining = 0, tag_value_arg = 0, i = 0; BACNET_APPLICATION_TAG property_tag; uint8_t context_tag = 0; BACNET_PRIVATE_TRANSFER_DATA private_data = { 0 }; int len = 0; bool sent_message = false; if (argc < 6) { filename = filename_remove_path(argv[0]); printf("Usage: %s <device-instance|broadcast|dnet=> vendor-id" " service-number tag value [tag value...]\r\n", filename); if ((argc > 1) && (strcmp(argv[1], "--help") == 0)) { printf("device-instance:\r\n" "BACnet Device Object Instance number that you are\r\n" "trying to communicate to. This number will be used\r\n" "to try and bind with the device using Who-Is and\r\n" "I-Am services. For example, if you were transferring to\r\n" "Device Object 123, the device-instance would be 123.\r\n" "For Global Broadcast, use the word 'broadcast'.\r\n" "For Local Broadcast to a particular DNET n, use 'dnet=n'.\r\n" "\r\n" "vendor_id:\r\n" "the unique vendor identification code for the type of\r\n" "vendor proprietary service to be performed.\r\n" "\r\n" "service-number (Unsigned32):\r\n" "the desired proprietary service to be performed.\r\n" "\r\n" "tag:\r\n" "Tag is the integer value of the enumeration \r\n" "BACNET_APPLICATION_TAG in bacenum.h.\r\n" "It is the data type of the value that you are sending.\r\n" "For example, if you were transfering a REAL value, you would \r\n" "use a tag of 4.\r\n" "Context tags are created using two tags in a row.\r\n" "The context tag is preceded by a C. Ctag tag.\r\n" "C2 4 creates a context 2 tagged REAL.\r\n" "\r\n" "value:\r\n" "The value is an ASCII representation of some type of data\r\n" "that you are transfering.\r\n" "It is encoded using the tag information provided.\r\n" "For example, if you were transferring a REAL value of 100.0,\r\n" "you would use 100.0 as the value.\r\n" "If you were transferring an object identifier for Device 123,\r\n" "you would use 8:123 as the value.\r\n" "\r\n" "Example:\r\n" "If you want to transfer a REAL value of 1.1 to service 23 of \r\n" "vendor 260 in Device 99, you could send the following command:\r\n" "%s 99 260 23 4 1.1\r\n", filename); } return 0; } /* decode the command line parameters */ if (strcmp(argv[1], "broadcast") == 0) { Target_Broadcast = true; Target_DNET = BACNET_BROADCAST_NETWORK; } else if (strncmp(argv[1], "dnet=", 5) == 0) { Target_Broadcast = true; Target_DNET = strtol(&argv[1][5], NULL, 0); } else { Target_Device_Object_Instance = strtol(argv[1], NULL, 0); } Target_Vendor_Identifier = strtol(argv[2], NULL, 0); Target_Service_Number = strtol(argv[3], NULL, 0); if ((!Target_Broadcast) && (Target_Device_Object_Instance > BACNET_MAX_INSTANCE)) { fprintf(stderr, "device-instance=%u - it must be less than %u\r\n", Target_Device_Object_Instance, BACNET_MAX_INSTANCE); return 1; } args_remaining = (argc - (6 - 2)); for (i = 0; i < MAX_PROPERTY_VALUES; i++) { tag_value_arg = (6 - 2) + (i * 2); /* special case for context tagged values */ if (toupper(argv[tag_value_arg][0]) == 'C') { context_tag = strtol(&argv[tag_value_arg][1], NULL, 0); tag_value_arg++; args_remaining--; Target_Object_Property_Value[i].context_tag = context_tag; Target_Object_Property_Value[i].context_specific = true; } else { Target_Object_Property_Value[i].context_specific = false; } property_tag = strtol(argv[tag_value_arg], NULL, 0); args_remaining--; if (args_remaining <= 0) { fprintf(stderr, "Error: not enough tag-value pairs\r\n"); return 1; } value_string = argv[tag_value_arg + 1]; args_remaining--; /* printf("tag[%d]=%u value[%d]=%s\r\n", i, property_tag, i, value_string); */ if (property_tag >= MAX_BACNET_APPLICATION_TAG) { fprintf(stderr, "Error: tag=%u - it must be less than %u\r\n", property_tag, MAX_BACNET_APPLICATION_TAG); return 1; } status = bacapp_parse_application_data(property_tag, value_string, &Target_Object_Property_Value[i]); if (!status) { /* FIXME: show the expected entry format for the tag */ fprintf(stderr, "Error: unable to parse the tag value\r\n"); return 1; } Target_Object_Property_Value[i].next = NULL; if (i > 0) { Target_Object_Property_Value[i - 1].next = &Target_Object_Property_Value[i]; } if (args_remaining <= 0) { break; } } if (args_remaining > 0) { fprintf(stderr, "Error: Exceeded %d tag-value pairs.\r\n", MAX_PROPERTY_VALUES); return 1; } /* setup my info */ Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); address_init(); Init_Service_Handlers(); dlenv_init(); atexit(datalink_cleanup); /* configure the timeout values */ last_seconds = time(NULL); if (Target_Broadcast) { datalink_get_broadcast_address(&Target_Address); Target_Address.net = Target_DNET; found = true; timeout_seconds = 0; } else { timeout_seconds = (apdu_timeout() / 1000) * apdu_retries(); /* try to bind with the device */ found = address_bind_request(Target_Device_Object_Instance, &max_apdu, &Target_Address); if (!found) { Send_WhoIs(Target_Device_Object_Instance, Target_Device_Object_Instance); } } /* loop forever */ for (;;) { /* increment timer - exit if timed out */ current_seconds = time(NULL); /* at least one second has passed */ if (current_seconds != last_seconds) { /* increment timer - exit if timed out */ delta_seconds = current_seconds - last_seconds; elapsed_seconds += delta_seconds; tsm_timer_milliseconds(((current_seconds - last_seconds) * 1000)); } if (Error_Detected) break; /* wait until the device is bound, or timeout and quit */ if (!found) { found = address_bind_request(Target_Device_Object_Instance, &max_apdu, &Target_Address); } if (!sent_message) { if (found) { len = bacapp_encode_data(&Service_Parameters[0], &Target_Object_Property_Value[0]); private_data.serviceParameters = &Service_Parameters[0]; private_data.serviceParametersLen = len; private_data.vendorID = Target_Vendor_Identifier; private_data.serviceNumber = Target_Service_Number; Send_UnconfirmedPrivateTransfer(&Target_Address, &private_data); printf("Sent PrivateTransfer."); if (timeout_seconds) { printf(" Waiting %u seconds.\r\n", (unsigned) (timeout_seconds - elapsed_seconds)); } else { printf("\r\n"); } sent_message = true; } else { if (elapsed_seconds > timeout_seconds) { printf("\rError: APDU Timeout!\r\n"); Error_Detected = true; break; } } } /* returns 0 bytes on timeout */ pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout); /* process */ if (pdu_len) { npdu_handler(&src, &Rx_Buf[0], pdu_len); } if (Error_Detected) { break; } /* unconfirmed - so just wait until our timeout value */ if (elapsed_seconds > timeout_seconds) { break; } /* keep track of time for next check */ last_seconds = current_seconds; } if (Error_Detected) return 1; return 0; }
int main( int argc, char *argv[]) { BACNET_ADDRESS src = { 0 }; /* address where message came from */ uint16_t pdu_len = 0; unsigned timeout = 100; /* milliseconds */ time_t total_seconds = 0; time_t elapsed_seconds = 0; time_t last_seconds = 0; time_t current_seconds = 0; time_t timeout_seconds = 0; BACNET_ADDRESS dest; int argi; /* print help if requested */ for (argi = 1; argi < argc; argi++) { if (strcmp(argv[argi], "--help") == 0) { print_help(filename_remove_path(argv[0])); return 0; } } datalink_get_broadcast_address(&dest); /* decode the command line parameters */ if (argc >= 2) { char *s; long v = strtol(argv[1], &s, 0); if (*s++ == ':') { if (argv[1][0] != ':') dest.net = (uint16_t) v; dest.mac_len = 0; if (isdigit(*s)) parse_bac_address(&dest, s); } else { Target_Object_Instance_Min = Target_Object_Instance_Max = v; } } if (argc <= 2) { /* empty */ } else if (argc == 3) { if (Target_Object_Instance_Min == -1) Target_Object_Instance_Min = Target_Object_Instance_Max = strtol(argv[2], NULL, 0); else Target_Object_Instance_Max = strtol(argv[2], NULL, 0); } else if (argc == 4) { Target_Object_Instance_Min = strtol(argv[2], NULL, 0); Target_Object_Instance_Max = strtol(argv[3], NULL, 0); } else { print_usage(filename_remove_path(argv[0])); return 1; } if (Target_Object_Instance_Min > BACNET_MAX_INSTANCE) { fprintf(stderr, "device-instance-min=%u - it must be less than %u\r\n", Target_Object_Instance_Min, BACNET_MAX_INSTANCE + 1); return 1; } if (Target_Object_Instance_Max > BACNET_MAX_INSTANCE) { fprintf(stderr, "device-instance-max=%u - it must be less than %u\r\n", Target_Object_Instance_Max, BACNET_MAX_INSTANCE + 1); return 1; } /* setup my info */ Device_Set_Object_Instance_Number(BACNET_MAX_INSTANCE); init_service_handlers(); address_init(); dlenv_init(); atexit(datalink_cleanup); /* configure the timeout values */ last_seconds = time(NULL); timeout_seconds = apdu_timeout() / 1000; /* send the request */ Send_WhoIs_To_Network(&dest, Target_Object_Instance_Min, Target_Object_Instance_Max); /* loop forever */ for (;;) { /* increment timer - exit if timed out */ current_seconds = time(NULL); /* returns 0 bytes on timeout */ pdu_len = datalink_receive(&src, &Rx_Buf[0], MAX_MPDU, timeout); /* process */ if (pdu_len) { npdu_handler(&src, &Rx_Buf[0], pdu_len); } if (Error_Detected) break; /* increment timer - exit if timed out */ elapsed_seconds = current_seconds - last_seconds; if (elapsed_seconds) { #if defined(BACDL_BIP) && BBMD_ENABLED bvlc_maintenance_timer(elapsed_seconds); #endif } total_seconds += elapsed_seconds; if (total_seconds > timeout_seconds) break; /* keep track of time for next check */ last_seconds = current_seconds; } print_address_cache(); return 0; }