/******************************************************************************
 *
 *                                   Io
 *
 * This module contains the routines which control CMON's I/O. 
 * They initialize the I/O communication, read and write to it.
 * This driver uses the appropriate Serial I/O or LAN driver.
 *
 * History:
 *   +----------+------------+------------------------------------------------+
 *   |   Date   |     by     |     Description                                |
 *   +----------+------------+------------------------------------------------+
 *   |          | Coby       | Written                                        |
 *   +----------+------------+------------------------------------------------+
 *
 *****************************************************************************/


#include "cc_def.h"
#include "global_f.h"
#include "io.h"
#include "lan_d.h"
#include "sio_d.h"

/*-----------------------------------------------------------------------------
 *                                 
 *                                 Variable definitions
 * 
 *---------------------------------------------------------------------------*/

/*
 * The default values for the communication byte of the operation mode (OM) 
 * command.
 */

#define DEFAULT_STAND_COM_BYTE   0
#define DEFAULT_TRANSP_COM_BYTE  0x3c

/*
 * Length of the parts of a protected command.
 */

#define LEN_SIZE   2
#define CRC_SIZE   4

/*
 * The communication modes available.
 */

#ifndef public

typedef enum {
        LAN,
        RS232
} com_mode_type;

#endif

/* 
 * The communication protocols available.
 */

typedef enum {
        OLD,
        PROTECTED
} com_protocol_type;

/*
 * The flags allowed in an operation mode command.
 */

typedef enum {
        B_CHAR,
        H_CHAR,
        Q_CHAR,
        S_CHAR,
        COM_PORT,
        PROTOCOL,
        OM_SWITCH_ARRAY_LEN
} om_flag_type;

typedef flag_entry_type   om_flag_array[(int) OM_SWITCH_ARRAY_LEN];

private const flag_info_type om_flag_struct[] = {
        {"B", (int) B_CHAR  , FALSE, 0},
        {"H", (int) H_CHAR  , FALSE, 0},
        {"Q", (int) Q_CHAR  , FALSE, 0},
        {"S", (int) S_CHAR  , FALSE, 0},
        {"C", (int) COM_PORT, FALSE, 0},
        {"P", (int) PROTOCOL, FALSE, 0}
};

/*
 * The parts of a protected protocol command.
 */

typedef struct {
        char     frame;
        unsigned len;
        l_str    cmd;
        unsigned crc;
} prot_cmd_type;


public op_mode_type       cur_op_mode__ = STAND_ASIDE;
public com_mode_type      cur_com_mode__ ;
private com_protocol_type  cur_com_protocol,next_line_protocol;

private byte  com_byte = DEFAULT_STAND_COM_BYTE;
		              /* The communication byte of the OM command */
private char  cur_ctrl_B = CTRL_B;
private char  cur_ctrl_H = CTRL_H;
private char  cur_ctrl_Q = CTRL_Q;
private char  cur_ctrl_S = CTRL_S;
private char  prev_frame = '\0';
 
/*
 * Define local functions
 */

private void break_prot_cmd( /* line, frame, len, response */);
private unsigned trans_prot_cmd_len(/* hex_len, cmd_start, line, response */);
private void check_prot_cmd_crc(/* hex_crc, line, len, response */);
private unsigned serial_read_bl__ (/* buf, response */);
private boolean break_bl_cmd(/* line, addr, len, frame, response */);
private void build_prot_line(/* line, prot_line, len */);
private void check_com_byte(/* temp_com_byte, hex_com_byte, response */);
private void exec_om(/* op_mode, temp_com_byte, om_flags, response */);





/*-----------------------------------------------------------------------------
 *
 *                                Init_io__()
 *
 * This function initializes the I/O variables.
 *
 *---------------------------------------------------------------------------*/

public void init_io__()
{

    /* Select communication mode (using dip_switch read macro) */
    cur_com_mode__ = BOARD_COM_MODE;

    if (cur_com_mode__ == LAN) {
	cur_com_protocol = PROTECTED;
	next_line_protocol = PROTECTED;
    }
    else {
	cur_com_protocol = OLD;
	next_line_protocol = OLD;
    }

    /*
     * Initialize the I/O drivers.
     */

    set_sio_operation_mode__(com_byte, cur_ctrl_B, cur_ctrl_H,
                           cur_ctrl_Q, cur_ctrl_S);

#ifdef LAN_EXIST
    /* Initialize lan driver using dip-switch to determine ethernet type */
    if (cur_com_mode__ == LAN) {
	init_lan__(ETHERNET_TYPE);
#ifndef DEBUG
	serial_write_line__(CUR_PORT, ether_reset_message__ , L_SIZE);
#endif
    }
#endif
} /* init_io__ */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *                     Read_message__(line, prev_response)
 *
 * This function reads a message from the current I/O device.
 * The previous response is used in case we are in protected protocol and 
 * receive a new line with the same frame as the previous line. In this case
 * the previous response is resent.
 * Note that if an error occured durring read, the appropriate message is
 * sent by this function. 
 *
 *---------------------------------------------------------------------------*/

public void read_message__(line, prev_response)
    str      line, prev_response;
{
    boolean  line_ok, time_out;
    unsigned len;
    char     frame, *chp;
    com_mode_type com_mode;
    int             port;


    /*
     * Loop until we get a good line
     */

    line_ok = FALSE;

    while (NOT line_ok) {
	/*
	 * catch errors 
	 */
	if (setjmp(return_env__) == 0) {
	    len = 0;
	    if (cur_com_mode__ == RS232) {
		/*
		 * On serial ports don't wait after read of first char 
		 * in protected protocol 
		 */ 
		time_out = (cur_com_protocol == PROTECTED);
		port = CUR_PORT;
		len = serial_read_line__(&port, line, L_SIZE, time_out);
		line[len] = '\0';
	    }
#ifdef LAN_EXIST
	    else {
		read_line_from_lan__(line);
	    }
#endif
	    /*
	     * if line begins with <ctrl B> skip it and  continue processing
	     */
	    if (line[0] == cur_ctrl_B) {
		line[0] = ' ';
		chp = &line[1];
	    }
	    else
		chp = line;

	    /*
	     * In protected protocol, break the command and check its length
	     * and crc. After that, If the frame number is the same as the
	     * previous frame number, resend the previous answer.
	     */

	    if (cur_com_protocol == PROTECTED) {
		frame = prev_frame;
		break_prot_cmd(chp, &prev_frame);
		if (cur_com_mode__ != LAN && frame == prev_frame) {
		    /* Lior, Sometimes prev_response is Empty */
		    if (prev_response != NULL && *prev_response != '\0') {
		         write_message__( prev_response);
		    }
		    write_message__(ready_prompt__);
		    continue;
		}
	    }
	    line_ok = TRUE;
	    remove_space__(line);
	    upper_case__(line);
	}    
	else {
	    /*
	     * Catch all errors here
	     */
	    write_message__( response__);
	    write_message__(ready_prompt__);
	}
    } /* while (NOT line_ok) */

} /* read_message__ */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *                  Break_prot_cmd(line, frame)
 *
 * This function receives a protected command and breaks it down to its
 * components. It also checks if the lenght and crc fields are ok and correct.
 * The line is returned without its "cover", and the frame is also returned.
 *
 *---------------------------------------------------------------------------*/

private void break_prot_cmd(line, frame)
    str      line;
    char     *frame;
{
    unsigned cur_char, len;
    s_str    hex_len, hex_crc;
    l_str    temp_string, cmd;

    /*
     * Get the frame number.
     */

    *frame   = line[0];
    cur_char = 1;

    /*
     * Get the length. If it contains illegal characters or the command
     * is shorter than specified, an error is signaled.
     */

    strncpy(hex_len, &line[cur_char], LEN_SIZE);
    hex_len[LEN_SIZE] = '\0';
    cur_char += LEN_SIZE;
    len = trans_prot_cmd_len(hex_len, cur_char, line);
    /*
     * Get the command.
     */

    strncpy(cmd, &line[cur_char], (int) len);
    cmd[len] = '\0';
    cur_char += len;

    /*
     * Check if the command ends with a CR
     */

    if (line[cur_char+CRC_SIZE] == CR)
	line[cur_char+CRC_SIZE] = '\0';
    else if (line[cur_char+CRC_SIZE] != '\0') {
        ERROR( e_pol_cr_missing__);
    }

    /*
     * Get the crc. If it contains illegal characters or is wrong,
     * an error is signaled.
     */

    strncpy(hex_crc, &line[cur_char], CRC_SIZE);
    hex_crc[CRC_SIZE] = '\0';
    strncpy(temp_string, line, (int) cur_char);
    temp_string[cur_char] = '\0';
    if (cur_com_mode__ != LAN)
	/* Do not check crc for LAN messages. It looks like protocol B crc
	   was not used in LAN communication mode.
	*/
	check_prot_cmd_crc(hex_crc, temp_string, cur_char);

    strcpy(line, cmd);

} /* break_prot_cmd */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *           Trans_prot_cmd_len(hex_len, cmd_start, line)
 *
 * This function receives a protected command in line, the position in which 
 * the command part starts in line, and the length field of the command.
 * It checks if the length field contains legal hexa decimal characters.
 * If so, it translates it to binary, and checks that the command part in
 * line is what it is claimed to be.
 * The return value of this function is the binary length.
 *
 *---------------------------------------------------------------------------*/

private unsigned trans_prot_cmd_len(hex_len, cmd_start, line)
    str      hex_len, line;
    unsigned cmd_start;
{
    unsigned bin_len;
    boolean  err;

    /*
     * Translate to binary
     */

    hex_to_bin__( hex_len, &bin_len, 'D');

    /*
     * Check the command length
     */

    if (strlen(line) < (bin_len + cmd_start + CRC_SIZE)) {
        ERROR( e_pol_short_cmd__);
    }

    return(bin_len);

} /* trans_prot_cmd_len */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *                Check_prot_cmd_crc(hex_crc, line)
 *
 * This function receives a string (line) and the crc field of a protected 
 * command that is supposed to match this strings crc. 
 * It checks if the crc field contains legal hexa decimal characters.
 * If so, it translates it to binary, and checks that the crc of the string
 * is what it is claimed to be.
 *
 *---------------------------------------------------------------------------*/

private void check_prot_cmd_crc(hex_crc, line, len)
    str      hex_crc, line;
    int      len;
{
    unsigned bin_crc;
    boolean  err;

    /*
     * Translate to binary
     */

    hex_to_bin__( hex_crc, &bin_crc, 'D');

    /*
     * Check the command crc
     */

    if (calc_crc__(line, len) != bin_crc) {
        ERROR( e_pol_crc_error__);
    }

} /* check_prot_cmd_crc */





/*-----------------------------------------------------------------------------
 *
 *                                Calc_crc__(line, count)
 *
 * This function receives a string (line) and a string length length
 * and returnes its crc.
 *
 *---------------------------------------------------------------------------*/

public unsigned calc_crc__(line, count)
    str      line;
    unsigned count;
{
    char     *temp;
    int      crc;
    unsigned i, c, q;

    crc   = 0;
    temp  = line;
    for (i = 0; i < count; i++) {
        c   = *temp++;
        q   = (crc ^ c) & 0xf;
        crc = (crc >> 4) ^ (q * 0x1081);
        q   = (crc ^ (c >> 4)) & 0xf;
        crc = (crc >> 4) ^ (q*0x1081);
    }

    return(crc & 0xffff);

} /* calc_crc__ */

/*^L*/

/*-----------------------------------------------------------------------------
 *
 *                    Serial_read_bl__(buf)
 *
 * This routine reads from the serial line the special format of protocol B
 * binary data command.
 *
 * The routine use a port variable which is set at the first time actual read
 * is perform it latter uses this port to continue the read.
 *---------------------------------------------------------------------------*/
 
private unsigned serial_read_bl__ (line)
        str            line;
{
    int                port, cur_char, len;
    short                bin_len, com_bin_len;
    
    /*
     * Try and read first charcter to skip <ctrl B>
     */
    port = CUR_PORT;
    serial_read_line__(&port, line, 1, TRUE /*time_out*/);
    /*
     * complete read of 3 characters (frame charcter and two length characters)
     */
    if (line[0] == cur_ctrl_B){
        serial_read_line__(&port, line, 3, TRUE /*time_out*/);
    }
    else{
        serial_read_line__(&port, &line[1], 2, TRUE /*time_out*/);
    }
    cur_char = 3;
    /*
     * Check the length field of the protocol B if diffrent from 0 then
     * accept ascii command (most probably EL)
     */
    if (NOT STRINGS_N_EQUAL (&line[1], "00",2)) {
        len = serial_read_line__(&port, &line[cur_char], L_SIZE - 3, TRUE);
	line[cur_char + len] = '\0';
        return;
    }
    /*
     * Read double word of binary data (addrerss field) into the line
     */
    cur_char += serial_read_buffer__(&port, &line[cur_char], sizeof(address), 
                                      TRUE);
    /*
     * Read two short bin_len and com_bin_len
     */
    serial_read_buffer__(&port, &bin_len, sizeof(short), TRUE);
    serial_read_buffer__(&port, &com_bin_len, sizeof(short), TRUE);
    bcopy(&bin_len, &line[cur_char], sizeof(short));
    cur_char += sizeof(short);
    bcopy(&com_bin_len, &line[cur_char], sizeof(short));
    cur_char += sizeof(short);
    /*
     * If error occure in the blen/~blen field set length to maximum and wait
     * for time out;
     */
    if (bin_len != ~com_bin_len) {
        bin_len = L_SIZE - (4 + sizeof(address) + 2 * sizeof(short));
    }
    cur_char += serial_read_buffer__(&port, &line[cur_char], bin_len, TRUE);
    /*
     * Read protocol B checksum 
     */
    len = serial_read_line__(&port, &line[cur_char], VL_SIZE - cur_char, TRUE);
    line[cur_char + len] = '\0';
}

/*^L*/

/*-----------------------------------------------------------------------------
 *
 *                       Read_bl_line__(line, addr, count)
 *
 * This function reads a line for the binary load command, from the current 
 * I/O device. It returns the data (in line), address and length.
 * Note that if an error occured durring read, the appropriate message is
 * sent by this function. 
 * It returns TRUE if the line was load command and FALSE if end load command
 *                
 *
 *---------------------------------------------------------------------------*/

public boolean read_bl_line__(line, addr, count)
    str      line;
    unsigned *addr, *count;
{
    boolean  line_ok;
    unsigned len;
    char     frame, *chp;
    boolean  is_data;


    if (cur_com_mode__ == RS232) {
        len = serial_read_bl__(line);
    }
#ifdef LAN_EXIST
    else {
        read_line_from_lan__(line);
    }
#endif

    /*
     * Brak the command to its parts, while checking the length field.
     * In protected protocol, the "wrapping" is taken off.
     * After that, if in protected protocol and the frame number is the 
     * same as the previous one, resend the "*".
     */

    is_data = break_bl_cmd(line, addr, count, &frame);

    /*
     * We have a good line. Save its frame and initialize the response.
     */

    prev_frame = frame;
    return (is_data);

} /* read_bl_line__ */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *                  Break_bl_cmd(line, addr, len, frame)
 *
 * This function receives either a binary load line or end binary load command
 * in protected format and breaks it down to its components.
 * It also checks if the lenght and crc fields are ok and correct.
 * The "wrapping" is taken off and the crc is checked.
 * The data to be loaded is returned in line. The address and length are also
 * returned, and so is the frame.
 * It returns TRUE if the line received is binary data FALSE if the line is
 * END BINARY LOAD command.
 *
 *---------------------------------------------------------------------------*/

private boolean break_bl_cmd(line, addr, len, frame)
    str      line;
    address  *addr;
    unsigned *len;
    char     *frame;
{
    unsigned cur_char;
    s_str    hex_crc;
    short    blen, com_blen;
    boolean  err;
    unsigned dummy;

    /*
     *  Get the frame number, and "protected" length. 
     * The length should contain only zeroes on binary data line
     * if that not the case check if EL command
     */

    *frame = line[0];
    /*
     * Look for end load command
     */
    if (NOT STRINGS_N_EQUAL(&line[1], "00", 2)) {
        break_prot_cmd(line, &frame);
        remove_space__(line);
        upper_case__(line);
        if (STRINGS_N_EQUAL(line, "EL", 2)){
            return FALSE; 
        }
        ERROR( e_pol_invalid_len__);
    }
    cur_char = 3;

    /*
     * Get the address and the length. Check the length.
     */
    
    bcopy(&line[cur_char], addr, 4);
    cur_char  += 4;
    bcopy( &line[cur_char], &blen ,2);
    *len = (unsigned) blen;
    cur_char += 2;
    bcopy(&line[cur_char], &com_blen, 2);
    cur_char += 2;
    if (blen != ~ com_blen) {
        ERROR( e_pol_invalid_len__);
    }

    /*
     *  Check if the command ends with a CR
     */

   cur_char += blen;
    if (line[cur_char+CRC_SIZE] == CR)
	line[cur_char+CRC_SIZE] = '\0';
    if (line[cur_char+CRC_SIZE] != '\0') {
        ERROR( e_pol_cr_missing__);
    }

    /*
     *  Get the crc. If it contains illegal 
     * characters or is wrong, an error is signaled.
     */

    strncpy(hex_crc, &line[cur_char], CRC_SIZE);
    hex_crc[CRC_SIZE] = '\0';
    if (cur_com_mode__ != LAN)
	/* Do not check crc for LAN messages. It looks like protocol B crc
	   was not used in LAN communication mode.
	*/
	check_prot_cmd_crc(hex_crc, line, cur_char);

    /*
     * Get the data skip protocol B and data headers
     */
    
    bcopy(&line[11], line, (unsigned) blen);
    
    return TRUE;

} /* break_bl_cmd */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *                        Write_message__(line)
 *
 * This function writes a message to the host.
 * If we are useing protected protocol, the line is wrapped with frame, 
 * length and crc .
 * Note that error messages have no meaning here, since if we can't write
 * the line, we can't write an error message either.
 *
 *---------------------------------------------------------------------------*/

public void write_message__(line)
    str line;
{
    l_str   prot_line;
    char    *chp;

    /*
     * In protected protocol, wrap the line with frame, length and crc.
     */

    if (cur_com_protocol == PROTECTED) {
        build_prot_line(line, prot_line, strlen(line));
        chp = prot_line;
    } 
    else {
        chp = line;
    }

    /*
     * Write the line
     */

    if (cur_com_mode__ == RS232) {
        serial_write_line__(CUR_PORT, chp, L_SIZE);
    }
#ifdef LAN_EXIST
    else {
        write_line_to_lan__(chp);
    }
#endif
    cur_com_protocol = next_line_protocol;

} /* write_message__ */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *                         Build_prot_line(line, len)
 *
 * This function receives a line and returns it wrapped with the frame, 
 * length and crc.
 *
 *---------------------------------------------------------------------------*/

private void build_prot_line(line, prot_line, len)
    str      line, prot_line;
    unsigned len;
{
    s_str    hex_len, hex_crc;
    unsigned crc, line_pos;

    prot_line[0] = prev_frame;

    /* 
     * Add the length
     */

    bin_to_hex__( len, &prot_line[1], '2');
    line_pos = LEN_SIZE + 1;

    /*
     * Add the command
     */

    bcopy(line, &prot_line[line_pos], (int) len);
    line_pos += len;

    /*
     * Add the crc
     */

    crc = calc_crc__(prot_line, line_pos);
    bin_to_hex__( crc, &prot_line[line_pos], '4');
    line_pos += CRC_SIZE;
    
    prot_line[line_pos] = '\0';

} /* build_prot_line */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *             Write_multi_line__(port, line, last_line, abort)
 *
 * This function writes a line to the requested port. The line is part of a
 * multi line output. The function writes the line and processes the answer.
 * Port = CUR_PORT means that the current I/O device should be used.
 * Last_line is an indication if this is the last line in the output.
 * If we are useing protected protocol, the line is wrapped with frame, 
 * length and crc.
 * The function returns an indication if the user requested an abort of the 
 * command.
 * Note that error messages have no meaning here, since if we can't write
 * the line, we can't write an error message either.
 *
 *---------------------------------------------------------------------------*/

public void write_multi_line__(port, line, last_line, abort)
    int     port;
    str     line;
    boolean last_line;
    boolean *abort;
{
    com_mode_type com_mode;
    l_str        prot_line;
    char        *chp;

 
    /*
     * In protected protocol, wrap the line with frame, length and crc.
     */

    if (cur_com_protocol == PROTECTED) {
        build_prot_line(line,prot_line,strlen(line));
        chp = prot_line;
    }
    else {
        chp =line;
    }

    /*
     * Write the line
     */

    if (com_mode == RS232) {
        serial_write_line__(CUR_PORT, chp);
    }
#ifdef LAN_EXIST
    else {
        write_line_to_lan__(chp);
    }
#endif
    /*
     * If this isn't the last line, write the continuation prompt, read the 
     * acknowledge and process acordingly.
     */

    if (last_line) {
        write_message__( ready_prompt__);
        *abort = TRUE;
        return;
    }

    write_cont_prompt__(port, abort);

} /* write_multi_line__ */





/*-----------------------------------------------------------------------------
 *
 *                  Write_cont_prompt__(port, abort)
 *
 * This function writes the continuation prompt to the port requested. It
 * returns an indication if the user responded with an abort request.
 *
 *---------------------------------------------------------------------------*/

public void write_cont_prompt__(port, abort)
    int     port;
    boolean *abort;
{
    l_str   ack, line;

    /*
     * Write the continuation prompt and read the response.
     */
    
    line[0] = '\0';
    write_message__(cont_prompt__);
    read_message__ (ack, line);

    /*
     * Check if the user wants to abort the command or continue.
     */

    *abort = STRINGS_EQUAL(ack, "NMI");

} /* write_cont_prompt__ */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *                    Write_dump_line__(port, line)
 *
 * This function write a dump hex or dump binary line
 *
 *---------------------------------------------------------------------------*/
public void write_dump_line__(port, line)
    int port;
    str line;
{
    vl_str   prot_line;
    char    *chp;

    /*
     * In protected protocol, wrap the line with frame, length and crc.
     */

    if (cur_com_protocol == PROTECTED) {
        build_prot_line(line, prot_line, strlen(line));
        chp = prot_line;
    } 
    else {
        chp = line;
    }

    /*
     * Write the line
     */
    if (port == CUR_PORT) {
    	if (cur_com_mode__ == RS232) {
            serial_write_line__(CUR_PORT, chp, L_SIZE);
    	}
#ifdef LAN_EXIST
    	else {
            write_line_to_lan__(chp);
    	}
#endif
    }
    else {
        if (port != LAN_PORT) {
	    serial_write_line__(port,  chp,  VL_SIZE);
        }
#ifdef LAN_EXIST
        else {
	    write_line_to_lan__(chp);
        }
#endif
    }

} /* write_dump_line__ */


/*^L*/
/*-----------------------------------------------------------------------------
 *
 *                    Om_decode__(cmd, response)
 *
 * This function decodes the operation mode command.
 *
 *---------------------------------------------------------------------------*/

public void om_decode__(cmd, response)
    str      cmd, response;
{ 
    om_flag_array om_flags;
    op_mode_type  op_mode;
    unsigned temp_com_byte;
    s_str    hex_com_byte;
    l_str    flags;
    boolean  err;
    unsigned cur_char, len;

    /*
     * Check the operation mode requested
     */

    if (cmd[2] == 'T') {
        op_mode = TRANSP;
        temp_com_byte = DEFAULT_TRANSP_COM_BYTE;
    }
    else if (cmd[2] == 'S') {
	op_mode = STAND_ALONE;
        temp_com_byte = DEFAULT_STAND_COM_BYTE;
    }
    else {
        op_mode = STAND_ASIDE;
        temp_com_byte = DEFAULT_STAND_COM_BYTE;
    }

    /*
     * Check if a communication byte was specified
     */

    cur_char = 3;
    if (cmd[cur_char] == ' ') {
        cur_char++;
    }
    if (cmd[cur_char] == '=') {
        cur_char ++;
        get_first_arg__(&cmd[cur_char], hex_com_byte, &len, S_SIZE,
	               /* accept null arg */ FALSE);
        if (strlen(hex_com_byte) > 2) {
            ERROR( e_syntax__);
        }
        cur_char += len;
        check_com_byte(&temp_com_byte, hex_com_byte);
    }
    
    /*
     * Get the flags and check them
     */

    get_first_arg__(&cmd[cur_char], flags, &len, L_SIZE,
                   /* accept null arg */ TRUE);
    interpret_flags__(flags, om_flags, om_flag_struct, 
                      ((unsigned) OM_SWITCH_ARRAY_LEN) - 1);

    /*
     * Update all the global variables
     */

    exec_om(op_mode, temp_com_byte, om_flags);
    
} /* om_decode__ */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *        Check_com_byte(temp_com_byte, hex_com_byte)
 *
 * This function receives the communication byte specified in the operation
 * mode command and checks if it is ok. It returns the byte in binary format.
 *
 *---------------------------------------------------------------------------*/

private void check_com_byte(temp_com_byte, hex_com_byte)
    unsigned *temp_com_byte;
    str      hex_com_byte;
{
    boolean  err;
    unsigned i;

    hex_to_bin__( hex_com_byte, temp_com_byte, 'B');

    /*
     * For each pair in the byte, check that the crlf bit is clear if the
     * echo bit was not specified.
     */

    for (i = 0; i < 8; i += 2) {
        if (BIT_OFF(i, *temp_com_byte)) {
            if (BIT_ON(i+1, *temp_com_byte)) {
                ERROR( e_syntax__);
            }
        }
    }

} /* check_com_byte */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *        Exec_om(op_mode, temp_com_byte, om_flags)
 *
 * This function receives the parameters that were specified on the operation
 * mode command and updates all the global variables accordingly.
 *
 *---------------------------------------------------------------------------*/

private void exec_om(op_mode, temp_com_byte, om_flags)
    op_mode_type  op_mode;
    unsigned      temp_com_byte;
    om_flag_array om_flags;
{

    cur_op_mode__ = op_mode;
    com_byte    = temp_com_byte;

    if (om_flags[B_CHAR].specified) {
        cur_ctrl_B = om_flags[B_CHAR].value;
    }
    else {
        cur_ctrl_B = CTRL_B;
    }
    if (om_flags[H_CHAR].specified) {
        cur_ctrl_H = om_flags[H_CHAR].value;
    }
    else {
        cur_ctrl_H = CTRL_H;
    }
    if (om_flags[Q_CHAR].specified) {
        cur_ctrl_Q = om_flags[Q_CHAR].value;
    }
    else {
        cur_ctrl_Q = CTRL_Q;
    }
    if (om_flags[S_CHAR].specified) {
        cur_ctrl_S = om_flags[S_CHAR].value;
    }
    else {
        cur_ctrl_S = CTRL_S;
    }
    if (om_flags[COM_PORT].specified) {
        cur_com_mode__ = (com_mode_type) om_flags[COM_PORT].value;
    }
    else {
        cur_com_mode__ = RS232;
    }
    if (om_flags[PROTOCOL].specified) {
        cur_com_protocol = (com_protocol_type)  om_flags[PROTOCOL].value;
    }
    else {
        cur_com_protocol = OLD;
    }

    /*
     * Update the I/O drivers.
     */

    set_sio_operation_mode__(com_byte, cur_ctrl_B, cur_ctrl_H,
                           cur_ctrl_Q, cur_ctrl_S);
} /* exec_om */

/*^L*/
/*-----------------------------------------------------------------------------
 *
 *                    Pom_decode__(cmd, response)
 *
 * This function decodes and executes the print operation mode command.
 *
 *---------------------------------------------------------------------------*/

public void pom_decode__(cmd, response)
    str cmd, response;
{ 

    /*
     * The command has no parameters. Just return the communication byte.
     */

    if (strlen(cmd) > 3) {
        ERROR( e_syntax__);
    }
    else {
        response[0] = '=';
        bin_to_hex__( com_byte, &response[1], 'B');
    }

} /* pom_decode__ */





/*-----------------------------------------------------------------------------
 *
 *                   Op_decode__ (cmd,response)
 *
 * This function decodes the "old protocol" command
 *
 *---------------------------------------------------------------------------*/
 
public void op_decode__(cmd,response)
    str        cmd, response;
{
    next_line_protocol = OLD;
}


/*-----------------------------------------------------------------------------
 *
 *                   Np_decode__ (cmd,response)
 *
 * This function decodes the "new protocol" command
 *
 *---------------------------------------------------------------------------*/
 
public void np_decode__(cmd,response)
    str        cmd, response;
{
    next_line_protocol = PROTECTED;
}

#ifdef LAN_EXIST
/*-----------------------------------------------------------------------------
 *
 *                   Get_con_parms (cmd,monport,hostport)
 *
 * This function decodes the CON command parameters 
 *
 *---------------------------------------------------------------------------*/
public void get_con_parms(cmd, monport, hostport)
    str cmd;
    unsigned short *monport, *hostport;
{
   char hexbuf[5];
   int i;
   unsigned int tmp_monport, tmp_hostport;
   char *cmdp;

    /* Decode monport */
    cmdp = cmd + 4;
    for (i = 0 ; i < 4 && *cmdp != ' ' && *cmdp != '\0' ; i++, cmdp++)
	hexbuf[i] = *cmdp;
    hexbuf[i] = '\0';
    hex_to_bin__( hexbuf, &tmp_monport, 'W');
    *monport = SWAP_S(tmp_monport);

    /* Decode hostport */
    cmdp++;
    for (i = 0 ; i < 4 && *cmdp != ' ' && *cmdp != '\0' ; i++, cmdp++)
	hexbuf[i] = *cmdp;
    hexbuf[i] = '\0';
    hex_to_bin__( hexbuf, &tmp_hostport, 'W');
    *hostport = SWAP_S(tmp_hostport);
}

/*-----------------------------------------------------------------------------
 *
 *                   Con_decode__ (cmd,response)
 *
 * This function decodes the CON command 
 *
 *---------------------------------------------------------------------------*/

public void con_decode__(cmd,response)
    str        cmd, response;
{
 
    response[0] = '\0';

    get_con_parms(cmd, &MONPORT, &HOSTPORT);

    /* Make the current channel be equal to the dbug channel */
    curr_ch.local_port = MONPORT;
    curr_ch.remote_port = HOSTPORT;

}


/*-----------------------------------------------------------------------------
 *
 *                   Lt_decode__ (cmd,response)
 *
 * This function decodes the LT command 
 *
 *---------------------------------------------------------------------------*/
public void lt_decode__(cmd,response)
    str        cmd, response;
{
    resend_lost_message__(cmd+3, &prev_frame);
}
#endif

