Updated Demo Who-Is to work with remote networks and report duplicate device-identifiers

This commit is contained in:
netp
2012-08-08 01:46:18 +00:00
parent 974f651c18
commit b620b33e1b
+357 -111
View File
@@ -28,6 +28,7 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h> /* for time */
#include <errno.h>
#include "bactext.h"
@@ -49,16 +50,131 @@
#include "rs485.h"
#endif
#include "dlenv.h"
#include "net.h"
/* buffer used for receive */
static uint8_t Rx_Buf[MAX_MPDU] = { 0 };
/* global variables used in this file */
static int32_t Target_Object_Instance_Min = 0;
static int32_t Target_Object_Instance_Max = BACNET_MAX_INSTANCE;
static int32_t Target_Object_Instance_Min = -1;
static int32_t Target_Object_Instance_Max = -1;
static int32_t Target_Network = BACNET_BROADCAST_NETWORK;
static char Target_Mac[7];
static uint32_t Target_MacLen = 0;
static bool verbose = true;
static bool Error_Detected = false;
#define BAC_ADDRESS_MULT 1
struct address_entry {
struct address_entry * next;
uint8_t Flags;
uint32_t device_id;
unsigned max_apdu;
BACNET_ADDRESS address;
};
static struct address_table {
struct address_entry * first;
struct address_entry * last;
} addr_tbl = {0};
struct address_entry * alloc_address_entry(void)
{
struct address_entry * rval;
rval = (struct address_entry *)calloc(1, sizeof(struct address_entry));
if(addr_tbl.first == 0)
{
addr_tbl.first = addr_tbl.last = rval;
}
else
{
addr_tbl.last->next = rval;
addr_tbl.last = rval;
}
return rval;
}
bool bacnet_address_matches(BACNET_ADDRESS * a1, BACNET_ADDRESS * a2)
{
int i = 0;
if(a1->net != a2->net) return false;
if(a1->len != a2->len) return false;
for(;i<a1->len;i++)
if(a1->adr[i]!=a2->adr[i])
return false;
return true;
}
void address_table_add(
uint32_t device_id,
unsigned max_apdu,
BACNET_ADDRESS * src)
{
struct address_entry *pMatch;
uint8_t flags = 0;
pMatch = addr_tbl.first;
while (pMatch) {
if (pMatch->device_id == device_id)
{
if (bacnet_address_matches(&pMatch->address, src))
return;
flags |= BAC_ADDRESS_MULT;
pMatch->Flags |= BAC_ADDRESS_MULT;
}
pMatch = pMatch->next;
}
pMatch = alloc_address_entry();
pMatch->Flags = flags;
pMatch->device_id = device_id;
pMatch->max_apdu = max_apdu;
pMatch->address = *src;
return;
}
void my_i_am_handler(
uint8_t * service_request,
uint16_t service_len,
BACNET_ADDRESS * src)
{
int len = 0;
uint32_t device_id = 0;
unsigned max_apdu = 0;
int segmentation = 0;
uint16_t vendor_id = 0;
(void) service_len;
len =
iam_decode_service_request(service_request, &device_id, &max_apdu,
&segmentation, &vendor_id);
#if PRINT_ENABLED
fprintf(stderr, "Received I-Am Request");
#endif
if (len != -1) {
#if PRINT_ENABLED
fprintf(stderr, " from %lu, MAC = %d.%d.%d.%d.%d.%d\n",
(unsigned long) device_id, src->mac[0], src->mac[1], src->mac[2],
src->mac[3], src->mac[4], src->mac[5]);
#endif
address_table_add(device_id, max_apdu, src);
} else {
#if PRINT_ENABLED
fprintf(stderr, ", but unable to decode it.\n");
#endif
}
return;
}
void MyAbortHandler(
BACNET_ADDRESS * src,
uint8_t invoke_id,
@@ -87,7 +203,7 @@ void MyRejectHandler(
Error_Detected = true;
}
static void Init_Service_Handlers(
static void init_service_handlers(
void)
{
Device_Init(NULL);
@@ -101,69 +217,189 @@ static void Init_Service_Handlers(
apdu_set_confirmed_handler(SERVICE_CONFIRMED_READ_PROPERTY,
handler_read_property);
/* handle the reply (request) coming back */
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM, handler_i_am_add);
apdu_set_unconfirmed_handler(SERVICE_UNCONFIRMED_I_AM, my_i_am_handler);
/* handle any errors coming back */
apdu_set_abort_handler(MyAbortHandler);
apdu_set_reject_handler(MyRejectHandler);
}
static void print_address_cache(
void)
void print_macaddr(uint8_t * addr, int len)
{
int i, j;
BACNET_ADDRESS address;
uint32_t device_id = 0;
unsigned max_apdu = 0;
unsigned total_addresses = 0;
printf(";%-7s %-20s %-5s %-20s %-4s\n", "Device", "MAC", "SNET", "SADR",
"APDU");
printf(";------- -------------------- ----- -------------------- ----\n");
for (i = 0; i < MAX_ADDRESS_CACHE; i++) {
if (address_get_by_index(i, &device_id, &max_apdu, &address)) {
total_addresses++;
printf(" %-7u ", device_id);
for (j = 0; j < MAX_MAC_LEN; j++) {
if (j < address.mac_len) {
if (j > 0) {
printf(":");
}
printf("%02X", address.mac[j]);
} else {
if (j > 0) {
printf(" ");
}
printf(" ");
}
}
printf(" %-5hu ", address.net);
if (address.net) {
for (j = 0; j < MAX_MAC_LEN; j++) {
if (j < address.len) {
if (j > 0) {
printf(":");
}
printf("%02X", address.adr[j]);
} else {
if (j > 0) {
printf(" ");
}
printf(" ");
}
}
} else {
printf("0 ");
for (j = 1; j < MAX_MAC_LEN; j++) {
printf(" ");
}
}
printf(" %-4hu ", max_apdu);
printf("\n");
}
}
printf(";\n; Total Devices: %u\n", total_addresses);
int j = 0;
if(len == 0)
{
printf("%20s", "");
return;
}
if(len == 1)
{
printf("%-6u%14s", addr[0], "");
return;
}
while(j < len)
{
if (j != 0) {
printf(":");
}
printf("%02X", addr[j++]);
}
while(j++ < MAX_MAC_LEN)
{
printf(" ");
}
}
static void print_address_cache(
void)
{
int j;
BACNET_ADDRESS address;
unsigned total_addresses = 0;
unsigned dup_addresses = 0;
struct address_entry *addr;
printf(";%-7s %-20s %-5s %-20s %-4s\n", "Device", "MAC", "SNET", "SADR",
"APDU");
printf(";-------- -------------------- ----- -------------------- ----\n");
addr = addr_tbl.first;
while (addr)
{
address = addr->address;
total_addresses++;
if(addr->Flags & BAC_ADDRESS_MULT)
{
dup_addresses++;
printf("*");
}
else
{
printf(" ");
}
printf(" %-7u ", addr->device_id);
print_macaddr(address.mac, address.mac_len);
printf(" %-5hu ", address.net);
if (address.net) {
print_macaddr(address.adr, address.len);
} else {
printf("0 ");
for (j = 1; j < MAX_MAC_LEN; j++) {
printf(" ");
}
}
printf(" %-4hu ", addr->max_apdu);
printf("\n");
addr = addr->next;
}
printf(";\n; Total Devices: %u\n", total_addresses);
if (dup_addresses)
printf("; * Duplicate Devices: %u\n", dup_addresses);
}
int print_usage(char* exe_name){
printf(
"Usage:\n"
"\n"
"%s [[network]:[address]] [device-instance-min [device-instance-max]] [--help]\n" ,
exe_name);
return 1;
}
int print_help(char* exe_name){
printf(
"Usage:\n"
"\n"
"%s [[network]:[address]] [low_devid [high_devid]] [--help]\n"
"\n"
" Send BACnet WhoIs service request to a device or multiple devices, and wait\n"
" for responses. Displays any devices found an their network information.\n"
"\n"
"device-instance:\r\n"
" BACnet Device Object Instance number that you are trying to send a Who-Is\n"
" service request. The value should be in the range of 0 to 4194303. A range\n"
" of values can also be specified by using a minimum value and a maximum value.\n"
"\n"
"network:\n"
" BACnet network number for directed requests. Valid range is from 0 to 65535\n"
" where 0 is the local connection and 65535 is network broadcast.\n"
"\n"
"address:\n"
" BACnet mac address number. Valid ranges are from 0 to 255 or a IP connection \n"
" string including port number like 10.1.2.3:47808.\n"
"\n"
"Examples:\n\n"
"To send a WhoIs request to Network 123:\n"
"%s 123:\n\n"
"To send a WhoIs request to Network 123 Address 5:\n"
"%s 123:5\n\n"
"To send a WhoIs request to Device 123:\n"
"%s 123\n\n"
"To send a WhoIs request to Devices from 1000 to 9000:\n"
"%s 1000 9000\n\n"
"To send a WhoIs request to Devices from 1000 to 9000 on Network 123:\n"
"%s 123: 1000 9000\n\n"
"To send a WhoIs request to all devices:\n"
"%s\n\n",
exe_name,exe_name,exe_name,exe_name,exe_name,exe_name,exe_name,exe_name);
return 1;
}
/* Parse a string for a bacnet-address
**
** @return length of address parsed in bytes
*/
int parse_bac_address(
BACNET_ADDRESS *dest, /* [out] BACNET Address*/
char *src /* [in] nul terminated string to parse */
)
{
int i = 0;
int z = 0;
uint16_t s;
int a[4],p;
int c = sscanf(src,"%u.%u.%u.%u:%u",&a[0],&a[1],&a[2],&a[3],&p);
dest->len = 0;
if (c==1)
{
if( a[0] < 256 ) /* mstp */
{
dest->adr[0] = a[0];
dest->len = 1;
}
else if ( a[0] < 0x0FFFF ) /* lon */
{
s = htons((uint16_t)a[0]);
memcpy(&dest->adr[0], &s, 2);
dest->len = 2;
}
else
return 0;
}
else if (c==5) /* ip address */
{
for(i=0;i<4;i++)
{
if(a[i] == 0 || a[i] > 255)
return 0;
dest->adr[i] = a[i];
}
s = htons((uint16_t)p);
memcpy(&dest->adr[i], &s, 2);
dest->len = 6;
}
return dest->len;
}
int main(
int argc,
char *argv[])
@@ -178,60 +414,70 @@ int main(
time_t last_seconds = 0;
time_t current_seconds = 0;
time_t timeout_seconds = 0;
BACNET_ADDRESS dest;
int argi;
if (argc < 2) {
printf("Usage: %s device-instance | "
"device-instance-min device-instance-max\r\n",
filename_remove_path(argv[0]));
return 0;
}
if ((argc > 1) && (strcmp(argv[1], "--help") == 0)) {
printf("Send BACnet WhoIs service request to a device or\r\n"
"multiple devices, and wait for responses. Displays\r\n"
"any devices found and their network information.\r\n"
"\r\ndevice-instance:\r\n"
"BACnet Device Object Instance number that you are trying to\r\n"
"send a Who-Is service request. The value should be in\r\n"
"the range of 0 to 4194303. A range of values can also be\r\n"
"specified by using a minimum value and a maximum value.\r\n"
"\r\nExample:\r\n" "To send a WhoIs request to Device 123\r\n"
"use the following command:\r\n" "%s 123\r\n"
"To send a WhoIs request to Devices from 1000 to 9000:\r\n"
"%s 1000 9000\r\n" "To send a WhoIs request to all devices\r\n"
"use the following command:\r\n" "%s -1\r\n",
filename_remove_path(argv[0]), filename_remove_path(argv[0]),
filename_remove_path(argv[0]));
return 0;
}
/* decode the command line parameters */
if (argc < 3) {
Target_Object_Instance_Min = strtol(argv[1], NULL, 0);
Target_Object_Instance_Max = Target_Object_Instance_Min;
if (Target_Object_Instance_Min > BACNET_MAX_INSTANCE) {
fprintf(stderr,
"object-instance-min=%u - it must be less than %u\r\n",
Target_Object_Instance_Min, BACNET_MAX_INSTANCE + 1);
return 1;
}
/* 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 = 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 {
Target_Object_Instance_Min = strtol(argv[1], NULL, 0);
Target_Object_Instance_Max = strtol(argv[2], NULL, 0);
if (Target_Object_Instance_Min > BACNET_MAX_INSTANCE) {
fprintf(stderr,
"object-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,
"object-instance-max=%u - it must be less than %u\r\n",
Target_Object_Instance_Max, BACNET_MAX_INSTANCE + 1);
return 1;
}
print_usage(filename_remove_path(argv[0]));
return 1;
}
/* setup my info */
if (Target_Object_Instance_Min > BACNET_MAX_INSTANCE) {
fprintf(stderr,
"object-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,
"object-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();
init_service_handlers();
address_init();
dlenv_init();
atexit(datalink_cleanup);
@@ -239,8 +485,8 @@ int main(
last_seconds = time(NULL);
timeout_seconds = apdu_timeout() / 1000;
/* send the request */
Send_WhoIs(Target_Object_Instance_Min, Target_Object_Instance_Max);
/* loop forever */
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);