bacnetget, a command line tool to read binary objects from a BACnet controller
/******************************************************************************/
/* */
/* FILE: bacnetget.cpp */
/* Command line tool to read a bacnet object */
/* ========================================= */
/* */
/* V1.00 01-JUN-2010 Peter Tellenbach, http://www.heimetli.ch */
/* */
/* Built with Microsoft C++ V15.00.21022.08 with the following command line */
/* cl bacnetget.cpp ws2_32.lib */
/* */
/* This program can read the following types of objects: */
/* - binary-input */
/* - binary-output */
/* - binary-value */
/* */
/* To read the status of the binary input instance 0 from a controller */
/* at IP adress 192.168.1.60, use the following command line: */
/* */
/* bacnetget 192.168.1.60 binary-input 0 */
/* */
/* The program will print the status to the standard otput, either "active" */
/* or "inactive". */
/* */
/* When the controller does not respond, the output will be "timeout". */
/* Error messages from the controller are not decoded, the program just */
/* prints "error". */
/* */
/******************************************************************************/
#include <stdio.h>
#include <winsock2.h>
#define BACNET_IP 0x81
#define UNICAST 0x0A
#define BACNET_VERSION 0x01
#define READ_PROPERTY 0x0C
#define COMPLEX_ACK 0x30
#define PROPERTY_TAG 0x19
#define PRESENT_VALUE 0x55
#define ENUMERATION 0x91
#define BACNET_ERROR 0x50
#define REQUEST_LENGTH 17
#define TIMEOUT 10
unsigned char id = 13 ;
unsigned long ip ;
unsigned long object ;
/********************************************/
void GetParameters( int argc, char *argv[] )
/********************************************/
{
if( argc != 4 )
{
fprintf( stderr, "usage: bacnetget ip type instance\n" ) ;
exit( 1 ) ;
}
ip = inet_addr( argv[1] ) ;
if( ip == INADDR_NONE )
{
fprintf( stderr, "invalid ip address\n" ) ;
exit( 2 ) ;
}
if( _stricmp(argv[2],"binary-input") == 0 )
object = 0x0C00000 ;
else if( _stricmp(argv[2],"binary-output") == 0 )
object = 0x1000000 ;
else if( _stricmp(argv[2],"binary-value") == 0 )
object = 0x1400000 ;
else
{
fprintf( stderr, "invalid type\n" ) ;
exit( 3 ) ;
}
int instance = atoi( argv[3] ) ;
if( instance < 0 )
{
fprintf( stderr, "invalid instance\n" ) ;
exit( 4 ) ;
}
object |= instance ;
}
/**************/
void Startup()
/**************/
{
WSADATA data ;
if( WSAStartup( MAKEWORD(2,2), &data ) != 0 )
{
fprintf( stderr, "Error: can't use socket library\n" ) ;
exit( 5 ) ;
}
}
/**************/
void Cleanup()
/**************/
{
WSACleanup() ;
}
/******************************************/
SOCKET CreateSocket( unsigned short port )
/******************************************/
{
SOCKET sock = socket( AF_INET, SOCK_DGRAM, 0 ) ;
if( sock == INVALID_SOCKET )
return sock ;
SOCKADDR_IN addr ;
addr.sin_family = AF_INET ;
addr.sin_port = htons( port ) ;
addr.sin_addr.s_addr = htonl( INADDR_ANY ) ;
if( bind(sock,(SOCKADDR *)&addr,sizeof(addr)) == SOCKET_ERROR )
{
closesocket( sock ) ;
return INVALID_SOCKET ;
}
return sock ;
}
/*********************************/
bool SendRequest( SOCKET socket )
/*********************************/
{
unsigned char frame[REQUEST_LENGTH] ;
frame[ 0] = BACNET_IP ;
frame[ 1] = UNICAST ;
frame[ 2] = REQUEST_LENGTH >> 8 ;
frame[ 3] = REQUEST_LENGTH ;
frame[ 4] = BACNET_VERSION ;
frame[ 5] = 0x04 ; // No DNET, no SNET, reply expected
frame[ 6] = 0x00 ; // Confirmed request
frame[ 7] = 0x00 ; // Response size 50 bytes
frame[ 8] = id ; // Invoke id
frame[ 9] = READ_PROPERTY ;
frame[10] = 0x0C ; // Object id tag
frame[11] = object >> 24 ;
frame[12] = object >> 16 ;
frame[13] = object >> 8 ;
frame[14] = object ;
frame[15] = PROPERTY_TAG ;
frame[16] = PRESENT_VALUE ;
SOCKADDR_IN addr ;
addr.sin_family = AF_INET ;
addr.sin_port = htons( 0xBAC0 ) ;
addr.sin_addr.s_addr = ip ;
return (sendto(socket,(const char *)frame,REQUEST_LENGTH,0,(SOCKADDR *)&addr,sizeof(addr)) == REQUEST_LENGTH) ;
}
/**************************************************/
bool WaitForResponse( SOCKET socket, int timeout )
/**************************************************/
{
struct timeval tv ;
tv.tv_sec = timeout ;
tv.tv_usec = 0 ;
fd_set fdset ;
FD_ZERO( &fdset ) ;
FD_SET( socket, &fdset ) ;
return (select(socket+1,&fdset,NULL,NULL,&tv) > 0 ) ;
}
/*************************************/
void ReceiveResponse( SOCKET socket )
/*************************************/
{
unsigned char frame[64] ;
SOCKADDR_IN addr ;
int len = sizeof( addr ) ;
int size = recvfrom( socket, (char *)frame, sizeof(frame), 0, (SOCKADDR *)&addr, &len ) ;
// Check the header
if( (size > 8) && (frame[0] == BACNET_IP) && (frame[1] == UNICAST) && (frame[4] == BACNET_VERSION) )
{
if( (((frame[2] << 8) | frame[3]) == size) && (frame[7] == id) && (frame[8] == READ_PROPERTY) )
{
if( frame[6] == BACNET_ERROR )
printf( "error\n" ) ;
if( (size > 18) && (frame[6] == COMPLEX_ACK) && (frame[14] == PROPERTY_TAG) && (frame[15] == PRESENT_VALUE) && (frame[17] == ENUMERATION) )
{
if( frame[18] != 0 )
printf( "active\n" ) ;
else
printf( "inactive\n" ) ;
}
}
}
else
printf( "invalid response\n" ) ;
}
/**********************************/
int main( int argc, char *argv[] )
/**********************************/
{
GetParameters( argc, argv ) ;
Startup() ;
SOCKET socket = CreateSocket( 0xBAC0 ) ;
if( socket == INVALID_SOCKET )
{
Cleanup() ;
fprintf( stderr, "Error: can't create socket\n" ) ;
return 6 ;
}
if( !SendRequest(socket) )
{
closesocket( socket ) ;
Cleanup() ;
fprintf( stderr, "Error: can't send request\n" ) ;
return 7 ;
}
if( WaitForResponse(socket,TIMEOUT) )
{
ReceiveResponse( socket ) ;
}
else
printf( "timeout\n" ) ;
closesocket( socket ) ;
Cleanup() ;
return 0 ;
}