bacnetget, a command line tool to read binary objects from a BACnet controller

Home|
/******************************************************************************/
/*                                                                            */
/*                                                        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 ;
}
Download Source|Download ZIP with bacnetget.exe