Subversion Repositories factorylink.mb_plus

Rev

Blame | Last modification | View Log | Download

/* name readnode.c */

/* Copyright (C) Modicon, Inc. 1989,  All Rights Reserved. */

/*
readnode.c


This test program uses the SA85.SYS device driver to read input or
output coils, and input or output registers from a specified modbus plus
node.  The format for the command line is as follows:

    READNODE <routing path> <reference> <length> <count>

where <routing path> is a modbus plus routing address from 1 to 5 bytes,
and <reference> is a 0X, 1X, 3X, or 4X reference, and length is the number
of items of the specified reference to read.  The last parameter <count>
indicates the number of times to read the data, a value of 0 indicates
read continously until control-c is struck at the keyboard.
*/


/*
include


*/
#define STRICT
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <signal.h>
#include "netbios.h"
#include "netlib.h"


/*
prototypes

*/
int main(int argc, char *argv[] );
void dump(int qty, unsigned int *buff);
void control_c(int sig);
void show_values(unsigned int reference, int length, PUSHORT buffer);

/*
global variables

*/
char mbuffer[ 256 ];                    /* modbus message buffer        */
char path[ 80 ];                        /* modbus plus path             */
int completed;                          /* infinite loop variable       */

/*
main()


Parse the command line request, and issue the appropriate command to
the proper path.  The format of the command line is as follows:

    READNODE <routing path> <reference> <length> <count>

Examples:

    READNODE 1 40001 10 0    (node 1, register 40001, length 10, infinite)
    READNODE 1.2 30010 20 1  (node 1.2, register 30010, length 20, once)

*/
int main( argc, argv )
int argc;
char *argv[];
{
    NCB *nd;                            /* netbios control block ptr    */
    int i;                              /* general purpose              */
    int ret_val;                        /* general purpose              */
    unsigned int reference;             /* reference to read            */
    unsigned int offset;                /* offset of reference          */
    int length;                         /* amount to read               */
    int loopcount;                      /* iteration counter            */
    int route[ 5 ];                     /* routing path                 */

    printf( "READNODE Modbus Plus access program. Version 1.0\n" );
    printf( "Copyright(C) 1989, Modicon, Inc.  All Rights Reserved.\n\n" );

    if( argc < 5 ) {                    /* display help info.           */
        puts( "Usage is:" );
        puts( "    READNODE <routing path> <reference> <length> <count>" );
        puts( "Examples:" );
        puts( "    READNODE 34 40001 10 1" );
        puts( "    READNODE 13.34 30001 20 1" );
        puts( "    READNODE 1 10001 128 100" );
        puts( "    READNODE 25.1.34.16 1 5 0" );
        exit( 1 );
    }
    
    for( i = 0; i < 5; i++ )
        route[ i ] = 0;                 /* clear routing path           */

    ret_val = sscanf( argv[ 1 ], "%d.%d.%d.%d.%d",
        &route[ 0 ],
        &route[ 1 ],
        &route[ 2 ],
        &route[ 3 ],
        &route[ 4 ] );                  /* parse routing path argument  */
    if( ret_val < 1 ) {                 /* verify routing assigned      */
        puts( "ERROR, Unable to assign routing path." );
        exit( 1 );
    }
    for( i = 0; i < ret_val; i++ )      /* validate routing path        */
        if( route[ i ] < 1 || route[ i ] > 64 ) {
            puts( "ERROR, Routing value out of range." );
            exit( 1 );
        }
                                        /* get reference value          */
    if( sscanf( argv[ 2 ], "%u", &reference ) != 1 ) {
        puts( "ERROR, Invalid reference." );
        exit( 1 );
    }
                                        /* get length                   */
    if( sscanf( argv[ 3 ], "%d", &length ) != 1 ) {
        puts( "ERROR, Invalid length." );
        exit( 1 );
    }

    if( sscanf( argv[ 4 ], "%d", &loopcount ) != 1 ) {
        puts( "ERROR, Invalid loop count." );
        exit( 1 );
    }
                                        
    sprintf( path, "DM.%d.%d.%d.%d.%d", /* set up path string           */
        route[ 0 ],
        route[ 1 ],
        route[ 2 ],
        route[ 3 ],
        route[ 4 ] );
                                        /* redirect control_c           */
    if( signal( SIGINT, control_c ) == SIG_ERR ) {
        printf( "Unable to redirect Control-C." );
        exit( 1 );
    }
                                        /* open "path" on board 0       */
    if( ( nd = ncb_open( path, 0 ) ) == NULL ) {
        printf( "Unable to open DATA MASTER path.\n" );
        exit( 1 );
    }

    printf("Path %c%c.%d.%d.%d.%d.%d opened.\n",
        nd->NCB_CALLNAME[0],
        nd->NCB_CALLNAME[1],
        nd->NCB_CALLNAME[2],
        nd->NCB_CALLNAME[3],
        nd->NCB_CALLNAME[4],
        nd->NCB_CALLNAME[5],
        nd->NCB_CALLNAME[6] );

    completed = 0;   
    while( !completed ) {               /* loop until control-c struck  */
        mbuffer[ 0 ] = 0;               /* modbus slave address         */
                                        /* Note: 5 byte routing code    */
                                        /* replaces slave address       */
        switch( reference / 10000 ) {        
            case 0:                     /* discrete output              */
                mbuffer[ 1 ] = 1;       /* modbus function code         */
                offset = reference - 1;          
                break;                       
            case 1:                     /* discrete input               */
                mbuffer[ 1 ] = 2;       /* modbus function code         */
                offset = reference - 10001;
                break;                       
            case 3:                     /* input register               */
                mbuffer[ 1 ] = 4;       /* modbus function code         */
                offset = reference - 30001;
                break;                       
            case 4:                     /* output register              */
                mbuffer[ 1 ] = 3;       /* modbus function code         */
                offset = reference - (unsigned int) 40001;
                break;                       
        }                                    
                                        
        mbuffer[ 2 ] = (char) ( offset >> 8 );  /* offset high byte     */
        mbuffer[ 3 ] = (char) (offset & 0xff);  /* offset low byte      */
        mbuffer[ 4 ] = (char) (length >> 8);    /* length high byte     */
        mbuffer[ 5 ] = (char) (length & 0xff);  /* length low byte      */

        if( ncb_send( nd, 6, mbuffer, 10) != 0 ) {
            printf( "Send error: %d occurred.\n", nd->NCB_RETCODE );
            ret_val = ncb_close( nd );
            exit( 1 );                  /* close path, exit on error    */
        }
                                        /* try to receive response      */
        if( ncb_receive_wait( nd, mbuffer, 10 ) != 0 ) {
            printf( "Receive error: %d occurred.\n", nd->NCB_RETCODE );
            ret_val = ncb_close( nd );
            exit( 1 );                  /* close path, exit on error    */
        }
        if( mbuffer[ 1 ] & 0x80 ) {     /* check for modbus error       */
            printf( "Modbus error: %d occurred.\n", mbuffer[ 2 ] );
            ret_val = ncb_close( nd );
            exit( 1 );                  /* close path, exit on error    */
        }
        show_values( reference, length, (PUSHORT)&mbuffer[ 3 ] );
        printf( "\n" );
        if( loopcount != 0 ) {          /* count of 0, means continous  */
            loopcount--;                /* else decrement to zero       */
            if( loopcount == 0 )
                completed = 1;          /* set complete flag when zero  */
        }
    }
    ncb_close( nd );                    /* close the path               */
    exit( 0 );                          /* good exit                    */
    return( 0 );
}



/*
show_values()


Display the values read in both decimal and hexadecimal format.
*/
void show_values( reference, length, buffer )
unsigned reference;
int length;
PUSHORT buffer;
{
    int offset;
    int count;
    unsigned value;
    int bits;

    offset = 0;
    switch( reference / 10000 ) {
        case 0:                         /* output coil                  */
        case 1:                         /* input coil                   */
            bits = 0;
            for( count = 0; count < length; count++ ) {
                if( (count % 10 ) == 0 ) {/* display 10 values per line */
                    printf( "\n%05u:", reference + count );
                }

                if( buffer[ offset ] & ( 1 << bits ) ) {
                    printf( " ON  " );  /* show coil on                 */
                }
                else {
                    printf( " OFF " );  /* show coil off                */
                }
                if( bits == 15 ) {      /* increment to next word       */
                    bits = 0;
                    offset++;
                }    
                else {
                    bits++;             /* just increment test value    */
                }
            }
            printf( "\n" );
            break;
        case 3:                         /* input register               */
        case 4:                         /* output register              */
            for( offset = 0; offset < length; offset++ ) {
                if( (offset % 5 ) == 0 ) { /* display 5 values per line */
                    printf( "\n%05u:", reference + offset );
                }
                value = ((buffer[ offset ] << 8) & 0xff00) |    /* swap */
                        ((buffer[ offset ] >> 8) & 0xff);
                printf( "%04X (%05u)  ",     /* show in hex and decimal */
                    value, value );
            }
            printf( "\n" );
            break;
    }
}


/*
control_c()


This routine replaces the control-C handler supplied by DOS.  When you
type a control_C, the program will vector to this routine, which will
set the completed flag to non-zero.  In this test program, this will cause
the infinite loop within main to terminate.
*/
void control_c(int sig)
{
    signal( SIGINT, SIG_IGN );          /* disable control-c            */
    completed = 1;                      /* break infinite loop          */
    signal( SIGINT, control_c );        /* reset control-c handler      */
}