// msDevTest.C

// $Source: /projects/HMS/nsr/udfAncil/devsTest/msDevTst.cpp,v $
// $Revision: 1.13 $    $Author: hmgr $
// $State: Exp $        $Locker:  $
// $Date: 96/02/05 09:13:57 $

//      Unpublished Confidential Information of Hewlett-Packard
//      Company. Do not disclose.  Copyright (c) Hewlett-Packard
//      Company 1995. All rights reserved
// 
// The contents of this software are proprietary and confidential to
// the Hewlett- Packard Company, and are limited in distribution to
// those with a direct need to know.  Individuals having access to
// this software are responsible for maintaining the confidentiality
// of the content and for keeping the software secure when not in use.
// Transfer to any party is strictly forbidden other than as expressly
// permitted in writing by Hewlett-Packard Company.  Unauthorized
// transfer to or possession by any unauthorized party may be a
// criminal offense.
//
//                  RESTRICTED RIGHTS LEGEND
//
//      Use,  duplication,  or disclosure by the U. S. Government is
//      subject to restrictions as set forth in subparagraph (c) (1)
//      (ii) in the Rights in Technical Data and Computer Software
//      clause in DFARS 252.227-7013 or any other successor clause.
//
//                      HEWLETT-PACKARD COMPANY
//                      3000 Hanover St.
//                      Palo Alto, CA  94304 U.S.A.
//
//      Rights for non-DOD U.S. Government Departments and Agencies
//      are as set forth in FAR 52.227-19 (c) (1,2) or any other
//      successor clause.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
#include <assert.h>
#include <unistd.h>

#include <nsrLib.h>
#include <nsrRMSdv.h>
#include <nsrRSSdv.h>
#include "dlist.h"
#include "msACobj.h"

// Function prototypes

static void parse_error_msg(CHAR_PTR buffer);
static void help(void);

//-----------------------------------------------------------------------------
// msDevTest.C:  This program is an INTERACTIVE test to verify the 
//               functionality of the hpACDev object.  
//
// Usage:
//
// msDevTest
//
//-----------------------------------------------------------------------------
//                                 COMMANDS
//
// register [ devfile ]:       Registers a device file for use with the test.
//
// map [ slot[A|B] ]:          Maps a (slot,side) pair to an sid.
//
// unmap [ sid ]:              Removes an sid from the hpACDev map table.
//
// drive [ tgt lun devfile ]:  Maps a drive in the AC to a device file.
//
// show:                       Shows the surface and drive maps.
//
// numsectors [ sid ]:         Returns number of sectors on given surface.
//
// size [ sid ]:               Returns sectors size of given surface.
//
// read [ sid start n ]:       Reads n bytes from given surface at sector
//                             offset start
//
// write [ sid start n buf ]:  Writes n bytes to given surface at sector offset
//                             start.  Uses data buffer buf (values 1-3)
//
// wwoe [ sid start n buf ]:   Writes n bytes in write-without-erase mode to 
//                             given surface at sector offset start.  Uses 
//                             data buffer buf (values 1-3)
//
// verify [ on | off ]:        Set verify mode to on or off.
//
// erase [ sid start n ]:      Erases n sectors on given surface at sector
//                             offset start.
//
// display [ page ]:           Displays specified 256-byte page of last read
//                             to screen in hex-dump format.
//
// status:                     Displays element status information for all
//                             elements in the autochanger.
//
// help:                       Prints help information.
//
// quit:                       Quit the program.
//-----------------------------------------------------------------------------

int
main( void )
{
    AC          ac(stdout);       // This object is basically the whole test
    CHAR        buffer[MAXLINE];  // For reading user commands
    CHAR        cmd[MAXLINE];
    INT32       arg1,arg2,arg3,arg4;
    INT32       rval;

    // We enter here into a big parsing loop.  We continue until the ac
    // object gets into a state which no longer accepts commands.

    while(ac.accepting_commands()) {
        printf("msDevTest> ");          // Display a prompt string
        if(fgets(buffer,MAXLINE,stdin) == NULL) {
            ac.quit();
            continue;
        }

        // Parse the command.  This is not sophisticated.

        if(sscanf(buffer,"%s",cmd) != 1) {
            parse_error_msg(buffer);
            continue;
        }

        // REGISTER

        if(strncmp(cmd,"reg",3) == 0) { 
            if(sscanf(buffer,"%*s %s",cmd) != 1) {
                parse_error_msg(buffer);
                continue;
            }
            ac.registerAC(cmd);
            continue;
        }

        // MAP

        if(strncmp(cmd,"m",1) == 0) {
            CHAR c;
            if(sscanf(buffer,"%*s %d%c",&arg1,&c) != 2) {
                parse_error_msg(buffer);
                continue;
            }
            c = toupper(c);
            if((c != 'A') && (c != 'B')) {
                parse_error_msg(buffer);
                continue;
            }
            ac.map(arg1,(c == 'A') ? 0 : 1);
            continue;
        }

        // UNMAP

        if(strncmp(cmd,"u",1) == 0) {
            if(sscanf(buffer,"%*s %d",&arg1) != 1) {
                parse_error_msg(buffer);
                continue;
            }
            ac.unmap((sid_t) arg1);
            continue;
        }

        // DRIVE

        if(strncmp(cmd,"dr",2) == 0) {
            if(sscanf(buffer,"%*s %d %d %s",&arg1,&arg2,cmd) != 3) {
                parse_error_msg(buffer);
                continue;
            }
            ac.drivemap(arg1,arg2,cmd);
            continue;
        }

        // SHOW

        if(strncmp(cmd,"sh",2) == 0) {
            ac.show();
            continue;
        }

        // NUMBER OF SECTORS

        if(strncmp(cmd,"nu",2) == 0) {
            if(sscanf(buffer,"%*s %d",&arg1) != 1) {
                parse_error_msg(buffer);
                continue;
            }
            ac.sectors((sid_t) arg1);
            continue;
        }

        // SECTOR SIZE

        if(strncmp(cmd,"se",2) == 0) {
            if(sscanf(buffer,"%*s %d",&arg1) != 1) {
                parse_error_msg(buffer);
                continue;
            }
            ac.size((sid_t) arg1);
            continue;
        }

        // READ

        if(strncmp(cmd,"rea",3) == 0) {
            if(sscanf(buffer,"%*s %d %d %d",&arg1,&arg2,&arg3) != 3) {
                parse_error_msg(buffer);
                continue;
            }
            ac.read((sid_t) arg1,arg2,arg3);
            continue;
        }

        // WRITE

        if(strncmp(cmd,"wr",2) == 0) {
            if(sscanf(buffer,"%*s %d %d %d %d",&arg1,&arg2,&arg3,&arg4) != 4) {
                parse_error_msg(buffer);
                continue;
            }
            ac.write((sid_t) arg1,arg2,arg3,arg4);
            continue;
        }

        // WRITE WOE

        if(strncmp(cmd,"ww",2) == 0) {
            if(sscanf(buffer,"%*s %d %d %d %d",&arg1,&arg2,&arg3,&arg4) != 4) {
                parse_error_msg(buffer);
                continue;
            }
            ac.writeWOE((sid_t) arg1,arg2,arg3,arg4);
            continue;
        }

        // VERIFY

        if(strncmp(cmd,"v",1) == 0) {
            if(sscanf(buffer,"%*s %d %s",&arg1,cmd) != 2) {
                parse_error_msg(buffer);
                continue;
            }
            CHAR_PTR cptr = cmd;
            while(*cptr) {
                *cptr = toupper(*cptr);
                cptr++;
            }
            if(strncmp(cmd,"ON",2) == 0) {
                ac.verify(arg1,1);
                continue;
            }
            if(strncmp(cmd,"OF",2) == 0) {
                ac.verify(arg1,0);
                continue;
            }
            parse_error_msg(buffer);
            continue;
        }

        // ERASE

        if(strncmp(cmd,"e",1) == 0) {
            if(sscanf(buffer,"%*s %d %d %d",&arg1,&arg2,&arg3) != 3) {
                parse_error_msg(buffer);
                continue;
            }
            ac.erase((sid_t) arg1,arg2,arg3);
            continue;
        }

        // DISPLAY

        if(strncmp(cmd,"di",2) == 0) {
            if(sscanf(buffer,"%*s %d",&arg1) != 1) {
                parse_error_msg(buffer);
                continue;
            }
            ac.display(arg1);
            continue;
        }

        // STATUS

        if(strncmp(cmd,"st",2) == 0) {
            ac.status();
            continue;
        }

        // HELP

        if(strncmp(cmd,"h",1) == 0) {
            help();
            continue;
        }

        // QUIT

        if(strncmp(cmd,"q",1) == 0) {
            ac.quit();
            continue;
        }

        // If we got here, then none of the previous strncmp's matched, and
        // therefore the user typed in a weird command.

        parse_error_msg(buffer);
        continue;
    }                           // End of big while loop

    // Depending on the state of the ac object, print out a message and exit.

    switch(ac.acstate()) 
    {
    case ac_quit:
        printf("Quitting test.\n");
        rval = TEST_SUCCEEDED;
        break;
    case ac_no_memory:
        printf("Test is aborting due to memory allocation failure!\n");
        rval = TEST_FAILED;
        break;
    default:
        printf("Test is aborting due to unknown test state!\n");
        rval = TEST_FAILED;
        break;
    }

    return rval;
}

//-----------------------------------------------------------------------------
// parse_error_msg():  Display a brief error message to screen. --JKH
//-----------------------------------------------------------------------------

static void
parse_error_msg(CHAR_PTR buffer)
{
    fprintf(stdout,"PARSE ERROR on command:  %s",buffer);
    fprintf(stdout,"Type 'help' for a list of valid test commands.\n");
}

//-----------------------------------------------------------------------------
// METHOD:  AC::help                                            --JKH
//
// Displays help information
//-----------------------------------------------------------------------------

static void
help( void )
{
static CHAR_PTR info[] = {

"----------------------------------------------------------------------------",
"register [devfile]:      Registers an autochanger device file for use with",
"                         the test.",
"map [slot side ]:        Maps a (slot,side) pair to an sid_t.",
"unmap [sid]:             Removes a (slot,side) to sid_t mapping.",
"drive [tgt lun devfile]: Maps a drive in the AC to a device file.",
"show:                    Shows the current surface and drive maps.",
"numsectors [sid]:        Displays the number of sectors for a surface.",
"sectorsize [sid]:        Displays the sector size of a surface.",
"read [sid start n]:      Reads n bytes from sector offset start.",
"sectorsize [sid]:        Displays the sector size of a surface.",
"read [sid start n]:      Reads n bytes from sector offset start.",
"write [sid start n buf]: Writes n bytes from sector offset start using the",
"                         specified data buffer.",
"wwoe [sid start n buf]:  Writes-without-erase n bytes from sector offset",
"                         start using the specified data buffer.",
"erase [sid start n]:     Erases n sectors from sector offset start.",
"verify [sid [on | off]]: Sets verify mode for specified sid.",
"display [page]:          Displays the specified 256-byte page from the last",
"                         read operation.",
"status:                  Displays autochanger element status information.",
"help:                    Displays this help menu.",
"quit:                    Quits the program.",
"",
"You may abbreviate commands to the minimal length necessary to distinguish",
"them from other commands.  You must first register an autochanger and then",
"map surfaces.\n",
"Valid write buffer values:  [0,1,2]",
"----------------------------------------------------------------------------",
NULL
};
    int i = 0;
    while(info[i] != NULL) {
        fprintf(stdout,"%s\n",info[i]);
        i++;
    }
}
