2473 lines
81 KiB
C
2473 lines
81 KiB
C
/* @(#)lopi_def.h 1.4 2/19/93
|
|
* Author: Betty Ann Gunther
|
|
* Date: 02-15-91
|
|
*
|
|
* Experimental Physics and Industrial Control System (EPICS)
|
|
*
|
|
* Copyright 1991, the Regents of the University of California,
|
|
* and the University of Chicago Board of Governors.
|
|
*
|
|
* This software was produced under U.S. Government contracts:
|
|
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
|
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
|
*
|
|
* Initial development by:
|
|
* The Controls and Automation Group (AT-8)
|
|
* Ground Test Accelerator
|
|
* Accelerator Technology Division
|
|
* Los Alamos National Laboratory
|
|
*
|
|
* Co-developed with
|
|
* The Controls and Computing Group
|
|
* Accelerator Systems Division
|
|
* Advanced Photon Source
|
|
* Argonne National Laboratory
|
|
*
|
|
* Modification Log:
|
|
* -----------------
|
|
* .01 02-26-91 bg Changed cursor to move only to controls.
|
|
* .02 07-03-91 rac changed to use "lopi" rather than "bw"
|
|
* .03 08-14-91 bg Added error message for no file available
|
|
for a display.
|
|
* .04 08-26-91 bg Fixed cursor so it will not try to move
|
|
with arrow keys if a screen has no controls.
|
|
* .05 09-12-91 bg Added semDelete for both keyboard and monitor
|
|
semaphores.
|
|
* .06 10-2-91 bg Fixed bug in display_monitors.
|
|
* .07 12-12-91 bg Fixed lopi so if you try to write to a monitor
|
|
* you will not crash.
|
|
* .08 6-10-91 bg Fixed allocation subroutines so they return NULL
|
|
* if they cannot get enough memory.
|
|
* .09 07-03-91 rac changed "bw" to "lopi"
|
|
* .10 08-11-93 mrk removed ifdef V5_vxWorks
|
|
*/
|
|
|
|
#include <vxWorks.h>
|
|
#include <stdioLib.h>
|
|
#include <ioLib.h>
|
|
#include <taskLib.h>
|
|
#include <semLib.h>
|
|
#include <strLib.h>
|
|
#include <os_depen.h>
|
|
#include <ctype.h>
|
|
#include <db_access.h>
|
|
#include <cadef.h>
|
|
|
|
|
|
static VOID lopi_init();
|
|
static VOID create_menu();
|
|
static VOID get_displays();
|
|
static struct mon_node *mon_alloc(); /* Allocates memory for an update.*/
|
|
static struct txt_node *txt_alloc(); /* Allocates memory for a test label. */
|
|
static struct ev_node *ev_alloc(); /* Allocates memory for an event node. */
|
|
static struct except_node *except_alloc(); /* Allocates memory for an exception node. */
|
|
static struct window_node *win_alloc(); /* Allocates memory for a window structure. */
|
|
static VOID init_monitors ();
|
|
static VOID print_menu();
|
|
static VOID mv_cursor();
|
|
static VOID get_key();
|
|
static char get_esc_seq();
|
|
static VOID make_box();
|
|
static VOID get_value();
|
|
static VOID blank_fill();
|
|
static VOID mv_cursor();
|
|
static char *skipblanks();
|
|
static int getline();
|
|
static VOID lopi_conn_handler();
|
|
static VOID lopi_exception_handler();
|
|
static VOID add_ctl();
|
|
static VOID add_mon();
|
|
static VOID add_txt();
|
|
static char *skip_to_digit();
|
|
static int int_to_short();
|
|
static VOID read_disp_lst();
|
|
static VOID display_text();
|
|
static VOID display_file();
|
|
static VOID display_monitors();
|
|
static VOID stop_monitors();
|
|
static VOID lopi_ev_handler();
|
|
static VOID lopi_exception_handler();
|
|
static VOID lopi_conn_handler();
|
|
static VOID free_mem();
|
|
static struct mon_node *find_channel();
|
|
static VOID put_value();
|
|
static int to_short();
|
|
|
|
#define FN_LEN 24
|
|
#define LIST_END -1
|
|
#define NEWLINE '\n'
|
|
#define MXMENU 34
|
|
#define ESC '\33'
|
|
#define L_BRACKET '['
|
|
#define RETURN '\15'
|
|
#define CR '\13'
|
|
#define DELETE '\177'
|
|
#define BLANK ' '
|
|
#define UNDERSC '_'
|
|
#define MINUS '-'
|
|
#define COLON ':'
|
|
#define TILDE '~'
|
|
#define ASTER '*' /* Legal text character. */
|
|
#define L_ARROW '$'
|
|
#define R_ARROW '%'
|
|
#define U_ARROW '!'
|
|
#define D_ARROW '@'
|
|
#define ILL_CHR '#'
|
|
#define F6 '^' /* Permits exit back to main menu. */
|
|
#define F7 '&'
|
|
#define DOT '.'
|
|
|
|
/* VT220 Escape secquences */
|
|
|
|
#define CLEAR_SCREEN fdprintf(lopi_fd,"%c", '\33'); \
|
|
fdprintf(lopi_fd,"%s","[2J");
|
|
#define INIT_CURSOR fdprintf(lopi_fd,"%c", '\33'); \
|
|
fdprintf(lopi_fd,"%s", "[?25h");
|
|
#define ERASE_LINE fdprintf(lopi_fd,"%c",ESC); \
|
|
fdprintf(lopi_fd,"%s","[2K");
|
|
#define ESCAPE fdprintf(lopi_fd,"%c",'\33');
|
|
#define REVERSE_VIDEO fdprintf(lopi_fd,"%s","[7;5m");
|
|
#define ATR_OFF fdprintf(lopi_fd,"%s","[0m");
|
|
|
|
#define CTL 1
|
|
#define MON 0
|
|
#define DEBUG 0
|
|
#define OFF 0
|
|
#define ON 1
|
|
#define NO_CMD "\0"
|
|
#define NEW_DATA 1
|
|
#define NO_NEW_DATA 0
|
|
#define NOTHING_SELECTED -1 /* Flag to indicate that lopi is waiting
|
|
for the user to make a selection. */
|
|
#define STRT_TTLE_ROW 1 /* Title row position. */
|
|
#define STRT_TTLE_COL 30 /* Title column position. */
|
|
#define STRT_MENU_ROW 7 /* Row position of first menu item. */
|
|
#define STRT_MENU_COL 20 /* Column position of first menu item. */
|
|
#define MAX_DISP_NUM 10 /* Maximum number of displays. */
|
|
#define MAX_LIN_LEN 80 /* Maximum number of characters in a line of a
|
|
display file. */
|
|
#define BUFF_SIZE 10
|
|
#define MAX_SCREEN_HEIGHT 24
|
|
#define MAX_SCREEN_WIDTH 78
|
|
#define CHAN_NM_SIZE 40
|
|
#define MAX_FIELD_SIZE 8
|
|
|
|
#define ERR_MSG_ROW 20
|
|
#define ERR_MSG_COL 0
|
|
#define BOX_IN_ROW 2
|
|
#define BOX_IN_COL 43
|
|
#define BEG_BOX 1
|
|
#define END_BOX 3
|
|
#define UNDEF 8
|
|
#define FOUND 1
|
|
#define NOT_FOUND 0
|
|
|
|
|
|
struct except_node{
|
|
long status; /* Channel access standard status code. */
|
|
char msg[MAX_LIN_LEN]; /* Character string containing context information. */
|
|
short flg; /* Flag to indicate the arrival of an exception. */
|
|
};
|
|
|
|
struct ev_node{
|
|
short data_flg; /* Flag to indicate that new data has been added. */
|
|
short status ; /* Status returned from function calls. */
|
|
short severity;
|
|
char str[MAX_STRING_SIZE];
|
|
short prev_size; /* Size of string. */
|
|
};
|
|
|
|
|
|
struct mon_node{ /* Structure to hold update information. */
|
|
short l_crn_row; /* Row location of upper left hand corner. */
|
|
short l_crn_col; /* Col location of upper left hand corner. */
|
|
short r_crn_row; /* Row location of lower right hand corner. */
|
|
short r_crn_col; /* Col location of lower right hand corner. */
|
|
char chan[CHAN_NM_SIZE]; /* Channel name. */
|
|
chid chan_id; /* Channel id for channel access. */
|
|
short chan_type;
|
|
short prev_size;
|
|
struct ev_node *ev_ptr; /* Pointer to event handler info. */
|
|
short conn_flg; /* Pointer to connection handler info. */
|
|
struct mon_node *next; /* Pointer to next node in the linked list. */
|
|
struct mon_node *prev; /* Pointer to previous node in the linked list. */
|
|
};
|
|
|
|
struct txt_node{ /* Structure to hold text label information. */
|
|
short l_crn_row; /* Row location of upper left hand corner. */
|
|
short l_crn_col; /* Col location of upper left hand corner. */
|
|
char txt_str[MAX_LIN_LEN]; /* Text string to be displayed. */
|
|
struct txt_node *next; /* Pointer to next node. */
|
|
};
|
|
|
|
struct window_node{ /* Structure which will hold all window information. There
|
|
will be a linked list of each kind of structure possible.
|
|
This structure will contain a pointer to the first node on
|
|
that list. */
|
|
struct mon_node *c_head;
|
|
struct mon_node *m_head;
|
|
struct txt_node *t_head;
|
|
};
|
|
|
|
static SEM_ID mon_sem,key_sem; /* Semaphores for protection of monitor and control
|
|
linked lists, the key board and screen, and the
|
|
exception handler's structure */
|
|
|
|
static struct window_node *wind_array[MAX_DISP_NUM]; /* Array of windows available. */
|
|
|
|
static char disp_lst[FN_LEN] = "lopi.dat"; /* Array for name of file containing list of display files. */
|
|
static char *d_menu[MXMENU];
|
|
static short nxt_ln = 0; /* Counter. */
|
|
static short data_flg; /* Global Flag to indicate a monitor has received data. Set in event handler.
|
|
Reset in display_monitors when data has been displayed. */
|
|
static short m_row; /* Current row number . */
|
|
static short m_col; /* Current column number. */
|
|
static int n_lines = 0; /* Number of Menu lines read in. */
|
|
|
|
static int tid1,tid2; /* Task id's */
|
|
static short screen = OFF;
|
|
static short init = TRUE; /* Flag which indicates first pass through the menu. */
|
|
static char key_buff[BUFF_SIZE],*rd_ptr,*wr_ptr; /* Buffer which will accumulate keyboard input while
|
|
waiting for a chance to update the screen. Pointers showing where
|
|
next available spot is for reading and for writing. */
|
|
static char val_in[MAX_STRING_SIZE]; /* Global buffer for user input value to be written to data base. */
|
|
static short q_num; /* Number of items waiting to be output from input queue. */
|
|
static int status;
|
|
|
|
static int err_fd; /* Fd to which logMsg will write during the course of this
|
|
subroutine. */
|
|
static int lopi_fd; /* File descriptor for serial port. */
|
|
struct except_node *except_ptr;
|
|
static int num_times = 0;;
|
|
extern shellTaskId;
|
|
|
|
|
|
shell_init()
|
|
{
|
|
ioctl(1,FIOSETOPTIONS,OPT_RAW);
|
|
}
|
|
|
|
/*
|
|
* CA_SIGNAL()
|
|
*
|
|
*
|
|
*/
|
|
|
|
lopi_signal(ca_status,message)
|
|
int ca_status;
|
|
char *message;
|
|
{
|
|
short row = ERR_MSG_ROW;
|
|
short col = ERR_MSG_COL;
|
|
char prefix[MAX_LIN_LEN];
|
|
char txt_str[MAX_LIN_LEN];
|
|
|
|
static char *severity[] =
|
|
{
|
|
"Warning",
|
|
"Success",
|
|
"Error",
|
|
"Info",
|
|
"Fatal",
|
|
"Fatal",
|
|
"Fatal",
|
|
"Fatal"
|
|
};
|
|
|
|
strcpy(txt_str, "CA.Diagnostic..........");
|
|
mv_cursor(&row,&col,txt_str);
|
|
|
|
|
|
if(message){
|
|
strcpy(prefix,"Severity:[%s] Error:[%s]Context: [%s]");
|
|
sprintf(txt_str,prefix,severity[CA_EXTRACT_SEVERITY(ca_status)],
|
|
ca_message_text[CA_EXTRACT_MSG_NO(ca_status)],message);
|
|
mv_cursor(&row,&col,txt_str);
|
|
}
|
|
else{
|
|
strcpy(prefix,"Severity:[%s],Error:[%s]");
|
|
sprintf(txt_str,prefix,severity[CA_EXTRACT_SEVERITY(ca_status)],
|
|
ca_message_text[CA_EXTRACT_MSG_NO(ca_status)]);
|
|
mv_cursor(&row,&col,txt_str);
|
|
}
|
|
/*
|
|
*
|
|
*
|
|
* Terminate execution if unsuccessful
|
|
*
|
|
*
|
|
*/
|
|
if( !(ca_status & CA_M_SUCCESS) ){
|
|
# ifdef VMS
|
|
lib$signal(0);
|
|
# endif
|
|
# ifdef vxWorks
|
|
ti(VXTHISTASKID);
|
|
tt(VXTHISTASKID);
|
|
# endif
|
|
/* abort(ca_status); */
|
|
}
|
|
|
|
}
|
|
|
|
VOID lopi()
|
|
|
|
{
|
|
|
|
/* Create and initialize semaphores protecting the keyboard and the
|
|
monitor linked list. */
|
|
mon_sem = semBCreate(SEM_Q_PRIORITY, SEM_FULL);
|
|
key_sem = semBCreate(SEM_Q_PRIORITY, SEM_FULL);
|
|
data_flg = NO_NEW_DATA;;
|
|
except_ptr = except_alloc();
|
|
|
|
/* Initialize buffer for keyboard input. */
|
|
|
|
blank_fill(key_buff,BUFF_SIZE);
|
|
|
|
/* Open file in which errrors will be recorded. */
|
|
SEVCHK(ca_task_initialize(),"Unable to initialize.");
|
|
|
|
q_num = 0;
|
|
|
|
tid1 = taskSpawn("lopi_init",210,VX_STDIO||VX_FP_TASK,20000,lopi_init,&screen,&q_num,&data_flg,
|
|
key_buff,val_in);
|
|
tid2 = taskSpawn("get_key",208,VX_STDIO||VX_FP_TASK,5000,get_key,&q_num,
|
|
key_buff,&screen,val_in);
|
|
|
|
/* Suspend shell to allow lopi the use of the keyboard. */
|
|
taskSuspend(shellTaskId);
|
|
}
|
|
|
|
/**********************************************************************************/
|
|
/* Entry point for local terminal. Reads a file called lopi.dat which contains a */
|
|
/* list of display files. Reads in the display names and the display files and */
|
|
/* makes a menu from which the user can select the display he wants to see. */
|
|
/* Display information is kept in an array of window structures. Displays the */
|
|
/* selected display.
|
|
/**********************************************************************************/
|
|
|
|
static VOID lopi_init(screen,que_num,pdata_flg,k_buff,val_in)
|
|
short *screen;
|
|
short *que_num; /* Number of items in keyboard buffer waiting to be read. */
|
|
short *pdata_flg; /* Flag to indicate that monitor had received new data. */
|
|
char k_buff[BUFF_SIZE]; /* Buffer for key board entries and pointer
|
|
to the next empty space in the buffer */
|
|
char val_in[MAX_STRING_SIZE];
|
|
{
|
|
char *read_ptr, *write_ptr; /* Pointers to next available places for reading and
|
|
writing in the keyboard input buffer. */
|
|
short selected;
|
|
char prefix[MAX_LIN_LEN];
|
|
char txt_str[MAX_LIN_LEN];
|
|
register short display = ON;
|
|
int disp_nm[FN_LEN];
|
|
short t_row, t_col = 0;
|
|
int new_fd; /* Fd to which standard error is now writing. This is the fd
|
|
to which logMsg will be reset as this subroutine terminates. */
|
|
|
|
read_ptr = k_buff;
|
|
write_ptr = k_buff;
|
|
err_fd = creat("lopi_err",0666);
|
|
if((err_fd = open("lopi_err",UPDATE,0666)) == ERROR){
|
|
printf("Aborting. Unable to open error file.\n");
|
|
taskResume(shellTaskId);
|
|
new_fd = ioGlobalStdGet(0,STD_ERR);
|
|
ca_task_exit();
|
|
semDelete(key_sem);
|
|
semDelete(mon_sem);
|
|
taskDelete(tid2);
|
|
taskDelete(tid1);
|
|
exit(1);
|
|
}
|
|
|
|
|
|
|
|
/* Build menu a from file called lopi.dat. Count the lines read in. This
|
|
is the number of display files read in. */
|
|
|
|
create_menu(d_menu,&n_lines);
|
|
get_displays(d_menu,n_lines,wind_array);
|
|
|
|
/* Gives user a chance to read error messages generated by get_displays. */
|
|
|
|
|
|
/* Open a file descriptor for the serial terminal.
|
|
Set it to raw mode. */
|
|
if ((lopi_fd = open("/tyCo/0",UPDATE,0)) == ERROR){
|
|
printf("Aborting. Unable to open serial port file.\n");
|
|
taskResume(shellTaskId);
|
|
ca_task_exit();
|
|
status = ioctl(lopi_fd,FIOSETOPTIONS,OPT_TERMINAL);
|
|
new_fd = ioGlobalStdGet(0,STD_ERR);
|
|
semDelete(key_sem);
|
|
semDelete(mon_sem);
|
|
taskDelete(tid2);
|
|
taskDelete(tid1);
|
|
exit(1);
|
|
}
|
|
|
|
logFdSet(err_fd);
|
|
|
|
if ((status = ioctl(lopi_fd,FIOSETOPTIONS,OPT_RAW)) == ERROR){
|
|
printf("Aborting. Unable to set I/O mode.\n");
|
|
taskResume(shellTaskId);
|
|
ca_task_exit();
|
|
new_fd = ioGlobalStdGet(0,STD_ERR);
|
|
status = ioctl(lopi_fd,FIOSETOPTIONS,OPT_TERMINAL);
|
|
semTake(key_sem);
|
|
semGive(key_sem);
|
|
semDelete(key_sem);
|
|
semDelete(mon_sem);
|
|
taskDelete(tid2);
|
|
taskDelete(tid1);
|
|
exit(1);
|
|
}
|
|
|
|
CLEAR_SCREEN
|
|
INIT_CURSOR
|
|
selected = NOTHING_SELECTED;
|
|
|
|
while (display == ON)
|
|
{
|
|
if (n_lines == 0)
|
|
printf("No displays to open");
|
|
else if (n_lines == 1)
|
|
{
|
|
selected = 0;
|
|
init = FALSE;
|
|
*screen = ON;
|
|
CLEAR_SCREEN
|
|
display_file(wind_array,selected,screen,que_num,pdata_flg,k_buff,val_in);
|
|
selected = NOTHING_SELECTED;
|
|
}
|
|
|
|
else if (((*screen) == OFF) && (n_lines >1))
|
|
{
|
|
|
|
/* Task delay allows display_monitors to finish writing
|
|
to screen before clearing the screen and printing the
|
|
menu. */
|
|
|
|
if (!init)
|
|
taskDelay(100);
|
|
CLEAR_SCREEN
|
|
print_menu(d_menu,n_lines);
|
|
m_row = STRT_MENU_ROW;
|
|
m_col = STRT_MENU_COL-1;
|
|
*que_num = 0;
|
|
write_ptr = k_buff;
|
|
|
|
/* Move cursor upper left hand corner of menu. */
|
|
mv_cursor(&m_row,&m_col,NO_CMD);
|
|
|
|
}
|
|
|
|
/* Get cursor movement from the screen. */
|
|
|
|
/* Move cursor only along edge of menu while menu is
|
|
being displayed. Semaphores are not necessary
|
|
no other task is competing for screen or linked lists at
|
|
this time. */
|
|
|
|
while ((selected) == NOTHING_SELECTED && (n_lines > 1) )
|
|
{
|
|
|
|
while ((*que_num) > 0)
|
|
{
|
|
switch (*write_ptr)
|
|
{
|
|
case U_ARROW:
|
|
m_row++;
|
|
if (m_row > n_lines + STRT_MENU_ROW )
|
|
m_row = STRT_MENU_ROW;
|
|
mv_cursor(&m_row,&m_col,NO_CMD);
|
|
break;
|
|
case D_ARROW:
|
|
m_row--;
|
|
if ( m_row < STRT_MENU_ROW)
|
|
m_row = n_lines + STRT_MENU_ROW;
|
|
mv_cursor(&m_row,&m_col,NO_CMD);
|
|
break;
|
|
case RETURN:
|
|
selected = m_row - STRT_MENU_ROW;
|
|
t_row++;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
|
|
} /* End switch. */
|
|
|
|
/* If a legal restart occurs reset buffer pointer
|
|
back to the first space in the buffer. and data to be
|
|
processed back to 0.*/
|
|
|
|
if ((*write_ptr == F6) || (*write_ptr == RETURN) || (*write_ptr == F7))
|
|
{
|
|
semTake(key_sem);
|
|
(*que_num) = 0;
|
|
write_ptr = k_buff;
|
|
semGive(key_sem);
|
|
}
|
|
else
|
|
{
|
|
semTake(key_sem);
|
|
write_ptr++;
|
|
(*que_num)--;
|
|
if(*write_ptr == NULL)
|
|
write_ptr = k_buff;
|
|
semGive(key_sem);
|
|
}
|
|
} /*end while *que_num > 0 */
|
|
|
|
|
|
|
|
} /* End while selected == NOTHING_SELECTED . */
|
|
|
|
|
|
/* User has chosen to exit the menu and the program. */
|
|
|
|
if (( selected == n_lines) || (n_lines == 1) )
|
|
{
|
|
display = OFF;
|
|
CLEAR_SCREEN
|
|
status = ioctl(lopi_fd,FIOSETOPTIONS,OPT_TERMINAL);
|
|
taskResume(shellTaskId);
|
|
}
|
|
|
|
else if ((selected >= 0) && (selected < n_lines))
|
|
{
|
|
init = FALSE;
|
|
*screen = ON;
|
|
CLEAR_SCREEN
|
|
display_file(wind_array,selected,screen,que_num,pdata_flg,k_buff,val_in);
|
|
selected = NOTHING_SELECTED;
|
|
semTake(key_sem);
|
|
*screen = OFF;
|
|
semGive(key_sem);
|
|
}
|
|
|
|
} /* End while display. */
|
|
|
|
/* Reset terminal to terminal mode. */
|
|
|
|
close(err_fd);
|
|
new_fd = ioGlobalStdGet(0,STD_ERR);
|
|
logFdSet(new_fd);
|
|
semTake(key_sem);
|
|
taskDelete(tid2);
|
|
taskDelete(tid1);
|
|
ca_task_exit();
|
|
semGive(key_sem);
|
|
taskDelay(100);
|
|
free_mem(wind_array,d_menu,n_lines);
|
|
semDelete(key_sem);
|
|
semDelete(mon_sem);
|
|
close(lopi_fd);
|
|
|
|
} /* End lopi. */
|
|
|
|
/******************************************************************************************/
|
|
/* Uses NFS to read in a list of displays kept in a file called lopi.dat in the application */
|
|
/* directory. */
|
|
/******************************************************************************************/
|
|
|
|
static VOID create_menu(menu,nlines)
|
|
char *menu[MXMENU];
|
|
int *nlines;
|
|
{
|
|
FILE *fp;
|
|
int ltr;
|
|
char item[40],*m_ptr;
|
|
short chr_ctr = 0; /* Counter. */
|
|
|
|
/* Open file. Return error message if that is impossible. */
|
|
|
|
if ((fp = fopen(disp_lst, "r")) == NULL)
|
|
{
|
|
printf("Can't open %s \n", disp_lst);
|
|
exit(1);
|
|
}
|
|
|
|
/* Otherwise create a menu of displays for this application. */
|
|
|
|
else
|
|
{
|
|
|
|
*nlines = 0;
|
|
|
|
/* Read in characters from display file one by one.*/
|
|
while ((ltr = getc(fp)) != EOF)
|
|
{
|
|
item[chr_ctr] = ltr;
|
|
chr_ctr++;
|
|
|
|
/* At the end of each line, enter the display title into the display
|
|
memory array. */
|
|
|
|
if ((ltr == NEWLINE) && (chr_ctr != 0))
|
|
{
|
|
item[chr_ctr-1] = NULL;
|
|
if (( m_ptr = (char *) malloc(chr_ctr + 1)) == NULL)
|
|
{
|
|
printf("Not enough memory in create_menu\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (*nlines <= MXMENU)
|
|
{
|
|
strcpy(m_ptr,item);
|
|
d_menu[nxt_ln++] = m_ptr;
|
|
(*nlines)++;
|
|
chr_ctr = 0; /* Reset the character counter. */
|
|
}
|
|
else /* Error message for too many display names. */
|
|
printf("Maximum number of displays exceeded.");
|
|
}
|
|
} /* End while. */
|
|
} /* End else. */
|
|
|
|
fclose(fp); /* Close the file. */
|
|
} /* End create_menu. */
|
|
|
|
|
|
/************************************************************************/
|
|
/* Prints to the screen the menu passed to it in the array menu as */
|
|
/* well as the instructions. Positions cursor in front of the first */
|
|
/* menu item. */
|
|
/************************************************************************/
|
|
|
|
static VOID print_menu(menu,nlines)
|
|
char *menu[MXMENU]; /* Array of menu items. */
|
|
int nlines; /* Number of items in the array. */
|
|
{
|
|
short mrow;
|
|
short mcol;
|
|
short b_ctr;
|
|
mrow = STRT_TTLE_ROW;
|
|
mcol = STRT_TTLE_COL;
|
|
mv_cursor(&mrow,&mcol,"DISPLAY MENU");
|
|
mrow++;
|
|
mcol -= 3;
|
|
mv_cursor(&mrow,&mcol,NO_CMD);
|
|
mrow++;
|
|
mv_cursor(&mrow,&mcol,"Move cursor with arrow keys.");
|
|
mrow++;
|
|
mv_cursor(&mrow,&mcol,"Select with carriage return.");
|
|
mrow = STRT_MENU_ROW;
|
|
mcol = STRT_MENU_COL;
|
|
for (b_ctr = 0; b_ctr < nlines; b_ctr++)
|
|
{
|
|
mv_cursor(&mrow,&mcol,menu[b_ctr]);
|
|
mrow++;
|
|
}
|
|
mv_cursor (&mrow,&mcol,"EXIT");
|
|
mrow++;
|
|
mrow = STRT_MENU_ROW;
|
|
mcol = STRT_MENU_COL - 1;
|
|
}
|
|
|
|
|
|
/***********************************************************************************/
|
|
/* Gets keystrokes from the screen,translates them to lopi opi commands and */
|
|
/* puts them in a buffer which is read by lopi, display_file and display_monitors. */
|
|
/* Reads up arrow,down arrow,right arrow, left arrow, F6, F7 and carriage */
|
|
/* return. When it reads an escape it calls get_esc_seq to complete the job of */
|
|
/* getting the escape sequence from the screen and translating it into a lopi */
|
|
/* command. */
|
|
/***********************************************************************************/
|
|
|
|
static VOID get_key(cue_num,k_buff,pScreen,val_in)
|
|
|
|
short *cue_num; /* Contains the number of letters in the queue ends the message
|
|
to getkey that the buffer has been read. */
|
|
char k_buff[BUFF_SIZE];
|
|
short *pScreen;
|
|
char val_in[MAX_STRING_SIZE];
|
|
{
|
|
char *in_ptr; /* Pointer to next place for in put and next place
|
|
for output. */
|
|
short ctr; /* Counter. */
|
|
char ltr;
|
|
int nmbr;
|
|
|
|
int mon_row = 0; /* For debug only. */
|
|
int mon_col = 0;
|
|
int t_row = 0; /* For debug only. */
|
|
int t_col = 0;
|
|
char txt_str[MAX_LIN_LEN];
|
|
char prefix[MAX_LIN_LEN];
|
|
|
|
semTake(key_sem);
|
|
*pScreen = OFF;
|
|
in_ptr = k_buff;
|
|
*cue_num = 0;
|
|
semGive(key_sem);
|
|
|
|
FOREVER
|
|
{
|
|
|
|
/* Read characters from keyboard and put them in a buffer until
|
|
the buffer has been read.If an escape is reached continue to read
|
|
input until one of the supported escape sequences has been completed.
|
|
Convert those keystrokes to a code and return it. */
|
|
nmbr = read(lopi_fd,<r,1);
|
|
|
|
do
|
|
{
|
|
/* If the letter is an escape sequence, do more reads to get
|
|
the rest of the sequence. Then convert it to a single character
|
|
and put it in the buffer. */
|
|
|
|
if(ltr == ESC)
|
|
{
|
|
semTake(key_sem);
|
|
ltr = get_esc_seq();
|
|
semGive(key_sem);
|
|
|
|
switch(ltr)
|
|
{
|
|
case U_ARROW:
|
|
semTake(key_sem);
|
|
(*in_ptr) = U_ARROW;
|
|
(*cue_num)++;
|
|
semGive(key_sem);
|
|
in_ptr++;
|
|
break;
|
|
|
|
case D_ARROW:
|
|
semTake(key_sem);
|
|
(*in_ptr) = D_ARROW;
|
|
(*cue_num)++;
|
|
semGive(key_sem);
|
|
in_ptr++;
|
|
break;
|
|
|
|
case F6:
|
|
semTake(key_sem);
|
|
(*in_ptr) = F6;
|
|
*pScreen = OFF;
|
|
in_ptr = k_buff;
|
|
semGive(key_sem);
|
|
break;
|
|
|
|
case F7:
|
|
if (*pScreen == ON)
|
|
{
|
|
make_box();
|
|
get_value(val_in);
|
|
taskDelay(30);
|
|
}
|
|
semTake(key_sem);
|
|
(*in_ptr) = F7;
|
|
(*cue_num)++;
|
|
in_ptr = k_buff;
|
|
semGive(key_sem);
|
|
ltr = NULL;
|
|
break;
|
|
default:
|
|
break;
|
|
|
|
} /* End switch. */
|
|
} /* End if ltr == ESC. */
|
|
if ((ltr == RETURN) || (ltr == CR))
|
|
{
|
|
semTake(key_sem);
|
|
(*in_ptr) = RETURN;
|
|
(*cue_num)++;
|
|
semGive(key_sem);
|
|
in_ptr = k_buff;
|
|
}
|
|
|
|
if ((*in_ptr) == NULL)
|
|
in_ptr = k_buff;
|
|
nmbr = read(lopi_fd,<r,1);
|
|
taskDelay(1);
|
|
} /* End do while. */
|
|
while ((*cue_num) <= (BUFF_SIZE -1) ); /* Exit this loop if buffer is filled. */
|
|
|
|
|
|
} /* End FOREVER */
|
|
|
|
} /* End get_key. */
|
|
|
|
|
|
/********************************************************************************/
|
|
/* Gets escape sequences from screen and returns their meaning to get key. */
|
|
/* Returns up arrow, down arrow, right arrow, left arrow, F6 and F7. For */
|
|
/* all other letters returns ILL_CHR . */
|
|
/********************************************************************************/
|
|
|
|
static char get_esc_seq()
|
|
{
|
|
char lttr;
|
|
int nbr;
|
|
|
|
nbr = read(lopi_fd,<tr,1);
|
|
if (lttr ==L_BRACKET)
|
|
{
|
|
nbr = read(lopi_fd,<tr,1);
|
|
switch(lttr)
|
|
{
|
|
case 'A':
|
|
return D_ARROW;
|
|
case 'B':
|
|
return U_ARROW;
|
|
case '1':
|
|
nbr = read(lopi_fd,<tr,1);
|
|
if (lttr == '7')
|
|
{
|
|
nbr = read(lopi_fd,<tr,1);
|
|
if (lttr == TILDE)
|
|
return F6;
|
|
}
|
|
if (lttr == '8')
|
|
{
|
|
nbr = read(lopi_fd,<tr,1);
|
|
if (lttr == TILDE)
|
|
return F7;
|
|
}
|
|
default:
|
|
/* If an illegal escape sequence has been read
|
|
then the legal character flag will not be set
|
|
and buffer write pointer will not be advanced. */
|
|
|
|
return ILL_CHR;
|
|
} /* End switch */
|
|
|
|
} /* End if ltter == L_BRACKET. */
|
|
else
|
|
return ILL_CHR;
|
|
} /* End get_esc_seq. */
|
|
|
|
/*****************************************************************************/
|
|
/* Draws a box on the screen for user to enter the value he wishes to write. */
|
|
/*****************************************************************************/
|
|
static VOID make_box()
|
|
{
|
|
char str[MAX_STRING_SIZE];
|
|
short row = BEG_BOX;
|
|
short col = BEG_BOX;
|
|
|
|
strcpy(str, "***************************************");
|
|
mv_cursor(&row,&col,str);
|
|
row+=2;
|
|
strcpy(str, "***************************************");
|
|
row = END_BOX;
|
|
mv_cursor(&row,&col,str);
|
|
row--;
|
|
col = BOX_IN_COL;
|
|
mv_cursor(&row,&col,NO_CMD);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Gets value from user input from screen. Echos user's input back. */
|
|
/* A null in the first location in the array indicates no value was */
|
|
/* entered. */
|
|
/************************************************************************/
|
|
|
|
static VOID get_value(val_in)
|
|
char val_in[MAX_STRING_SIZE]; /* Array into which letters will be placed as they
|
|
are read in from screen. */
|
|
{
|
|
char numb, *chr_ptr; /* Variable into which ltrs are read before putting
|
|
them into field_array. */
|
|
VOID mv_cursor();
|
|
|
|
short row = BOX_IN_ROW;
|
|
short col = BEG_BOX;
|
|
int nmbr;
|
|
short ctr;
|
|
char prefix[40];
|
|
char txt_str[MAX_STRING_SIZE];
|
|
|
|
blank_fill(val_in,MAX_STRING_SIZE);
|
|
strcpy(val_in, "* Enter value: *");
|
|
mv_cursor(&row,&col,val_in);
|
|
col = 16;
|
|
blank_fill(val_in,MAX_STRING_SIZE);
|
|
mv_cursor(&row,&col,NO_CMD);
|
|
|
|
/* Initialize pointer to first location in array. */
|
|
|
|
chr_ptr = val_in;
|
|
|
|
/* Read input from screen until a return is entered. */
|
|
nmbr = read(lopi_fd,&numb,1);
|
|
|
|
while ((numb != RETURN) && (numb != CR) && (*chr_ptr != NULL ))
|
|
{
|
|
/* If value is legal enter it in value array. */
|
|
|
|
if (( isalpha(numb)) || (isdigit(numb)) || (numb == DOT) || (numb == MINUS ))
|
|
{
|
|
*chr_ptr = numb;
|
|
chr_ptr++;
|
|
mv_cursor(&row,&col,val_in);
|
|
nmbr = read(lopi_fd,&numb,1);
|
|
} /* End if isalpha */
|
|
else if ((numb == DELETE) && (chr_ptr != val_in))
|
|
{
|
|
chr_ptr--;
|
|
*chr_ptr = BLANK;
|
|
mv_cursor(&row,&col,val_in);
|
|
nmbr = read(lopi_fd,&numb,1);
|
|
}
|
|
else if ((numb != RETURN) || (numb != CR))
|
|
{
|
|
nmbr = read(lopi_fd,&numb,1);
|
|
}
|
|
|
|
} /* End while numb != return. */
|
|
|
|
*chr_ptr = NULL;
|
|
col = BEG_BOX;
|
|
|
|
/* Erase the box and data. */
|
|
|
|
for (ctr = BEG_BOX; ctr <= END_BOX; ctr++)
|
|
{
|
|
row = ctr;
|
|
mv_cursor(&row,&col,NO_CMD);
|
|
ERASE_LINE;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************************/
|
|
/* Takes the character array passed to it and fills it with blanks and terminates it */
|
|
/* with a NULL. */
|
|
/**************************************************************************************/
|
|
|
|
static VOID blank_fill(chr_array,chr_size)
|
|
char chr_array[MAX_LIN_LEN];
|
|
short chr_size;
|
|
{
|
|
short c_ctr = 0; /* Index to array being filled. */
|
|
|
|
while(c_ctr < (chr_size - 1))
|
|
chr_array[c_ctr++] = BLANK;
|
|
chr_array[chr_size -1] = NULL;
|
|
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Moves cursor to row and column passed to it. Prints a string after the */
|
|
/* cursor if one is sent to it. */
|
|
/****************************************************************************/
|
|
|
|
|
|
static VOID mv_cursor(mrow,mcol,str)
|
|
short *mrow;
|
|
short *mcol;
|
|
char str[100]; /* String to be printed after cursor has a been
|
|
moved. */
|
|
{
|
|
char command[140];
|
|
|
|
/* Create a string containing the proper VT220 commands
|
|
to move the cursor to the location desired. */
|
|
|
|
bzero(command,sizeof(command));
|
|
sprintf(command,"[%d;%dH %s",*mrow,*mcol,str);
|
|
|
|
/* Send command to the terminal. */
|
|
|
|
semTake(mon_sem);
|
|
|
|
fdprintf(lopi_fd,"%c",ESC);
|
|
fdprintf(lopi_fd,"%s",command);
|
|
|
|
semGive(mon_sem);
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Strips away blanks from the string to which it */
|
|
/* points. Returns a pointer to the first non-blank character. */
|
|
/****************************************************************************/
|
|
|
|
|
|
static char *skipblanks(str)
|
|
char *str;
|
|
{
|
|
|
|
while ( (*str == BLANK))
|
|
str++;
|
|
|
|
return (str);
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Reads in a line from a file and puts it in an array. */
|
|
/* Strips off newline character. Terminates string with a NULL. */
|
|
/* Returns the number of characters read in or EOF. */
|
|
/****************************************************************************/
|
|
|
|
|
|
static int fgetline(disp_ln,d_fp)
|
|
|
|
FILE *d_fp; /* File pointer to the file being read in. */
|
|
char disp_ln[MAX_LIN_LEN];
|
|
{
|
|
int c;
|
|
char *lnptr;
|
|
|
|
for (lnptr = disp_ln; lnptr - disp_ln < MAX_LIN_LEN - 1 &&
|
|
(c = getc(d_fp)) != EOF && c != NEWLINE; lnptr++)
|
|
*lnptr = (char) c;
|
|
|
|
*lnptr = NULL;
|
|
|
|
if ( c == EOF)
|
|
return EOF;
|
|
else
|
|
return lnptr - disp_ln;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Reads in the files listed in disp_files one by one. It builds a */
|
|
/* structure called a window for each display file it reads in. It builds */
|
|
/* linked lists of controls, monitors and texts. These lists will later be */
|
|
/* used to display the dynamic information as it comes in. */
|
|
/****************************************************************************/
|
|
|
|
|
|
static VOID get_displays(disp_files,nfiles,disp_array)
|
|
|
|
char *disp_files[FN_LEN]; /* Array for list of filenames to be selected by the user. */
|
|
int nfiles; /* Number of files read in. */
|
|
struct window_node *disp_array[MAX_DISP_NUM]; /* Array of windows available. */
|
|
|
|
{
|
|
FILE *disp_fp;
|
|
char *lptr,dline[MAX_LIN_LEN]; /* Array to hold the contents of a line from the
|
|
display file as it is read in. */
|
|
struct mon_node *ctl_ptr;
|
|
int flg; /* Flag for EOF. */
|
|
int disp_ctr; /* Counters. */
|
|
for (disp_ctr = 0; disp_ctr < nfiles; disp_ctr++)
|
|
{
|
|
if ((disp_fp = fopen(disp_files[disp_ctr], "r")) == NULL){
|
|
printf("Can't open %s \n", disp_files[disp_ctr]);
|
|
disp_array[disp_ctr] = NULL;
|
|
}
|
|
else
|
|
{
|
|
disp_array[disp_ctr] = win_alloc();
|
|
disp_array[disp_ctr]->c_head = NULL;
|
|
disp_array[disp_ctr]->m_head = NULL;
|
|
disp_array[disp_ctr]->t_head = NULL;
|
|
flg = 0;
|
|
do
|
|
{
|
|
flg = fgetline(dline,disp_fp);
|
|
lptr = skipblanks(dline); /* Skip any leading blanks if any. */
|
|
switch (*lptr)
|
|
{
|
|
case 'c':
|
|
add_ctl(disp_array,disp_ctr,lptr);
|
|
break;
|
|
|
|
case 'm':
|
|
add_mon(disp_array,disp_ctr,lptr);
|
|
break;
|
|
|
|
case 't':
|
|
add_txt(disp_array,disp_ctr,lptr);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
} /* End switch. */
|
|
bzero(dline,sizeof(dline));
|
|
|
|
} while(flg != EOF);
|
|
|
|
status = fclose(disp_fp);
|
|
|
|
} /* End else. */
|
|
|
|
} /* End for.*/
|
|
|
|
/* it(DEBUG)
|
|
read_disp_lst(wind_array,n_lines); */
|
|
|
|
} /* End get_displays */
|
|
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Allocates memory for a monitor. */
|
|
/****************************************************************************/
|
|
|
|
static struct mon_node *mon_alloc()
|
|
{
|
|
struct mon_node *monptr;
|
|
|
|
if (( monptr = (struct mon_node *)malloc(sizeof(struct mon_node))) == NULL)
|
|
{
|
|
logMsg("Insufficient memory in mon_alloc.\n ");
|
|
close(err_fd);
|
|
abort();
|
|
return NULL;
|
|
}
|
|
else
|
|
return monptr;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Allocates memory for a text label. */
|
|
/****************************************************************************/
|
|
|
|
static struct txt_node *txt_alloc()
|
|
{
|
|
struct txt_node *txtptr;
|
|
|
|
if (( txtptr = (struct txt_node *)malloc(sizeof(struct txt_node))) == NULL)
|
|
{
|
|
logMsg("Insufficient memory in tx_alloc.\n ");
|
|
close(err_fd);
|
|
abort();
|
|
return NULL;
|
|
}
|
|
else
|
|
return txtptr;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Allocates memory for an event node. */
|
|
/****************************************************************************/
|
|
|
|
static struct ev_node *ev_alloc()
|
|
{
|
|
struct ev_node *evptr;
|
|
|
|
if (( evptr = (struct ev_node *)malloc(sizeof(struct ev_node))) == NULL)
|
|
{
|
|
logMsg("Insufficient memory in ev_alloc.\n ");
|
|
close(err_fd);
|
|
abort();
|
|
return NULL;
|
|
}
|
|
else
|
|
return evptr;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Allocates memory for an exception node. */
|
|
/****************************************************************************/
|
|
|
|
static struct except_node *except_alloc()
|
|
{
|
|
struct except_node *ex_ptr;
|
|
|
|
if (( ex_ptr = (struct except_node *)malloc(sizeof(struct except_node))) == NULL)
|
|
{
|
|
logMsg("Insufficient memory in except_alloc.\n ");
|
|
close(err_fd);
|
|
abort();
|
|
return NULL;
|
|
}
|
|
else
|
|
return ex_ptr;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/* Allocates memory for a window structure. */
|
|
/****************************************************************************/
|
|
|
|
static struct window_node *win_alloc()
|
|
{
|
|
struct window_node *winptr;
|
|
|
|
if (( winptr = (struct window_node *)malloc(sizeof(struct window_node))) == NULL)
|
|
{
|
|
logMsg("Insufficient memory in win_alloc.\n ");
|
|
close(err_fd);
|
|
abort();
|
|
return NULL;
|
|
}
|
|
else
|
|
return winptr;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* This function attaches a control node to the linked list headed by */
|
|
/* win_array->ctl. It returns the pointer to the head of the list which now */
|
|
/* points to the new node. */
|
|
/*****************************************************************************/
|
|
|
|
static void add_ctl(win_array,win_ctr,c_line)
|
|
struct window_node *win_array[MAX_DISP_NUM];
|
|
short win_ctr; /* Counters. */
|
|
char *c_line;
|
|
{
|
|
struct mon_node *c_ptr,*new_ptr;
|
|
char chan_nm[CHAN_NM_SIZE],*chan_ptr; /* Array to hold channel name as it is parsed
|
|
from line and a pointer to it. */
|
|
register short l_crn_row = 0,l_crn_col = 0;
|
|
register short r_crn_row = 0,r_crn_col = 0;
|
|
short r_loc_flg = OFF; /* Flag which is set when location is found in element file. */
|
|
short c_loc_flg = OFF; /* Flag which is set when location is found in element file. */
|
|
|
|
chan_ptr = chan_nm;
|
|
bzero(chan_nm,sizeof(chan_nm));
|
|
|
|
*chan_ptr = NULL;
|
|
|
|
/* Move past any characters at beginning of display element. */
|
|
|
|
while (isalpha(*c_line))
|
|
c_line++;
|
|
c_line = skip_to_digit(c_line);
|
|
|
|
/* If there is no channel location, omit the channel from the linked list. */
|
|
|
|
if ((*c_line) && (isdigit(*c_line)))
|
|
{
|
|
l_crn_row = to_short(c_line);
|
|
while(isdigit(*c_line))
|
|
c_line++;
|
|
r_loc_flg = ON;
|
|
c_line = skip_to_digit(c_line);
|
|
|
|
if (*c_line)
|
|
{
|
|
l_crn_col = to_short(c_line);
|
|
c_loc_flg = ON;
|
|
while (isdigit(*c_line) )
|
|
c_line++;
|
|
}
|
|
}
|
|
|
|
/* Advance pointer past the left corner location in element array. */
|
|
|
|
while ((*c_line)&& (isdigit(*c_line)))
|
|
c_line++;
|
|
|
|
/* Advance pointer to next digit or alpha character. */
|
|
|
|
while ((*c_line) && (!isdigit(*c_line)) && (!isalpha(*c_line)))
|
|
c_line ++;
|
|
|
|
/* Return a pointer to the next non-blank character in the element array. */
|
|
|
|
if ((*c_line) && (isdigit(*c_line)))
|
|
{
|
|
r_crn_row = to_short(c_line);
|
|
while(isdigit(*c_line))
|
|
c_line++;
|
|
c_line = skip_to_digit(c_line);
|
|
r_crn_col = to_short(c_line);
|
|
while ((!isalpha(*c_line)) && (*c_line))
|
|
c_line++;
|
|
}
|
|
|
|
/* If there is no channel name give appropriate error message. */
|
|
|
|
|
|
if (!(*c_line))
|
|
printf("No channel name for control. Channel omitted.\n");
|
|
|
|
/* Otherwise copy channel name to the channel name array. */
|
|
if (isalpha(*c_line))
|
|
{
|
|
while( (isalpha(*c_line)) || (isdigit(*c_line)) || (*c_line == UNDERSC) ||(*c_line == COLON)
|
|
|| (*c_line == DOT))
|
|
*chan_ptr++ = *c_line++;
|
|
*chan_ptr = NULL;
|
|
}
|
|
|
|
/* Allocate and initialize header for doubly linked list. Initialize header's
|
|
l_crn_row field to -1. */
|
|
|
|
if (win_array[win_ctr]->c_head == NULL)
|
|
{
|
|
win_array[win_ctr]->c_head = mon_alloc();
|
|
win_array[win_ctr]->c_head->next = win_array[win_ctr]->c_head;
|
|
win_array[win_ctr]->c_head->prev = win_array[win_ctr]->c_head;
|
|
strcpy(win_array[win_ctr]->c_head->chan,"head");
|
|
win_array[win_ctr]->c_head->l_crn_row = -1;
|
|
c_ptr = win_array[win_ctr]->c_head;
|
|
}
|
|
|
|
|
|
/* If the channel has a name and locations for the left corner and the right
|
|
corner, add the node immediately after the head of the list. */
|
|
|
|
c_ptr = win_array[win_ctr]->c_head->next;
|
|
|
|
if ((*chan_nm) && (r_loc_flg) && (c_loc_flg))
|
|
{
|
|
while((c_ptr->next->l_crn_row != -1) && (c_ptr->l_crn_row < l_crn_row))
|
|
{
|
|
c_ptr = c_ptr->next;
|
|
}
|
|
c_ptr = win_array[win_ctr]->c_head->next;
|
|
while((c_ptr->next->l_crn_row != -1) && (c_ptr->l_crn_row == l_crn_row) &&
|
|
(c_ptr->l_crn_col < l_crn_col))
|
|
{
|
|
c_ptr = c_ptr->next;
|
|
}
|
|
new_ptr = mon_alloc();
|
|
new_ptr->next= c_ptr->next; /* Set pointer to the head to point at the new node. */
|
|
new_ptr->prev = c_ptr;
|
|
c_ptr->next = new_ptr;
|
|
new_ptr->next->prev = new_ptr;
|
|
strcpy(new_ptr->chan,chan_nm);
|
|
new_ptr->l_crn_row = l_crn_row;
|
|
new_ptr->l_crn_col = l_crn_col;
|
|
new_ptr->r_crn_row = r_crn_row;
|
|
new_ptr->r_crn_col = r_crn_col;
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
/************************************************************************************/
|
|
/* This function attaches a monitor node to the linked list headed by win_array-> */
|
|
/* mon. It returns the pointer to the head of the list which now points to the new */
|
|
/* node. */
|
|
/************************************************************************************/
|
|
|
|
static VOID add_mon(win_array,win_ctr,m_line)
|
|
struct window_node *win_array[MAX_DISP_NUM];
|
|
short win_ctr; /* Counters. */
|
|
char *m_line;
|
|
{
|
|
struct mon_node *node_ptr;
|
|
char chan_nm[CHAN_NM_SIZE],*chan_ptr; /* Array to hold channel name as it is parsed
|
|
from line and a pointer to it. */
|
|
register short l_crn_row = 0,l_crn_col = 0;
|
|
short r_loc_flg = OFF; /* Flag which is set when location is found in element file. */
|
|
short c_loc_flg = OFF; /* Flag which is set when location is found in element file. */
|
|
|
|
chan_ptr = chan_nm;
|
|
bzero(chan_nm,sizeof(chan_nm));
|
|
|
|
*chan_ptr = NULL;
|
|
|
|
/* Move past any characters at beginning of display element. */
|
|
|
|
while (isalpha(*m_line))
|
|
m_line++;
|
|
|
|
m_line = skip_to_digit(m_line);
|
|
|
|
/* If there is no channel location, omit the channel from the linked list. */
|
|
|
|
|
|
if ((*m_line) && (isdigit(*m_line)))
|
|
{
|
|
l_crn_row = to_short(m_line);
|
|
r_loc_flg = ON;
|
|
/* Move past left row number. */
|
|
|
|
while(isdigit(*m_line))
|
|
m_line++;
|
|
|
|
/* Move to column location. */
|
|
|
|
m_line = skip_to_digit(m_line);
|
|
|
|
if ((*m_line) && (isdigit(*m_line)))
|
|
{
|
|
l_crn_col = to_short(m_line);
|
|
c_loc_flg = ON;
|
|
while (isdigit (*m_line))
|
|
m_line++;
|
|
}
|
|
|
|
}
|
|
|
|
while ( (*m_line) && (!isalpha(*m_line)))
|
|
m_line++;
|
|
|
|
if (isalpha(*m_line))
|
|
{
|
|
while( (isalpha(*m_line)) || (isdigit(*m_line)) || (*m_line == UNDERSC) || (*m_line == COLON))
|
|
*chan_ptr++ = *m_line++;
|
|
*chan_ptr = NULL;
|
|
}
|
|
chan_ptr = chan_nm;
|
|
|
|
/* Enter channel name and location for monitor in monitor linked list. */
|
|
|
|
if (win_array[win_ctr]->m_head == NULL)
|
|
{
|
|
if ((*chan_nm) && (c_loc_flg) && (r_loc_flg))
|
|
{
|
|
win_array[win_ctr]->m_head = mon_alloc();
|
|
win_array[win_ctr]->m_head->next = NULL;
|
|
if (*chan_nm)
|
|
strcpy(win_array[win_ctr]->m_head->chan,chan_nm);
|
|
win_array[win_ctr]->m_head->l_crn_row = l_crn_row;
|
|
win_array[win_ctr]->m_head->l_crn_col = l_crn_col;
|
|
}
|
|
else if (!(*chan_nm))
|
|
printf("No channel name for monitor. Channel omitted.\n");
|
|
else if ((! (c_loc_flg)) || (! (r_loc_flg)) )
|
|
printf("Incomplete location information for display.\n");
|
|
}
|
|
|
|
|
|
/* Otherwise, add the node immediately after the head of the list. */
|
|
|
|
else
|
|
{
|
|
if ((*chan_nm) && (c_loc_flg) && (r_loc_flg))
|
|
{
|
|
node_ptr = mon_alloc(); /* Set the new node's next pointer to point at
|
|
the head of the list. */
|
|
node_ptr->next= win_array[win_ctr]->m_head; /* Set pointer to the head to point at the new node. */
|
|
win_array[win_ctr]->m_head = node_ptr;
|
|
if (*chan_nm)
|
|
strcpy(win_array[win_ctr]->m_head->chan,chan_nm);
|
|
win_array[win_ctr]->m_head->l_crn_row = l_crn_row;
|
|
win_array[win_ctr]->m_head->l_crn_col = l_crn_col;
|
|
}
|
|
else if (!(*chan_nm))
|
|
printf("No channel name for monitor. Channel omitted.\n");
|
|
else if ((! (c_loc_flg)) || (! (r_loc_flg)) )
|
|
printf("Incomplete location information for display. Channel omitted.\n");
|
|
}
|
|
return;
|
|
}
|
|
|
|
/************************************************************************************/
|
|
/* This function attaches a text node to the linked list headed by win_array-> */
|
|
/* txt. It returns the pointer to the head of the list which now points to the new */
|
|
/* node. */
|
|
/************************************************************************************/
|
|
|
|
static VOID add_txt(win_array,win_ctr,t_line)
|
|
struct window_node *win_array[MAX_DISP_NUM];
|
|
short win_ctr; /* Counters. */
|
|
char *t_line;
|
|
{
|
|
struct txt_node *node_ptr;
|
|
char txt_str[MAX_LIN_LEN],*txt_ptr; /* Array to hold text string as it is parsed
|
|
from line and a pointer to it. */
|
|
|
|
register short l_crn_row = 0,l_crn_col = 0;
|
|
short r_loc_flg = OFF; /* Flag which is set when location is found in element file. */
|
|
short c_loc_flg = OFF; /* Flag which is set when location is found in element file. */
|
|
|
|
txt_ptr = txt_str;
|
|
bzero(txt_str,sizeof(txt_str));
|
|
|
|
*txt_ptr = NULL;
|
|
|
|
/* Move past any characters at beginning of display element. */
|
|
|
|
while (isalpha(*t_line))
|
|
t_line++;
|
|
|
|
/* Move to next digit in display element. */
|
|
|
|
t_line = skip_to_digit(t_line);
|
|
|
|
|
|
/* If there is no text location, omit the string from the linked list. */
|
|
|
|
if (*t_line)
|
|
{
|
|
l_crn_row = to_short(t_line);
|
|
r_loc_flg = ON;
|
|
while (isdigit(*t_line))
|
|
t_line++;
|
|
t_line = skip_to_digit(t_line);
|
|
|
|
if ((*t_line) && (isdigit (*t_line)))
|
|
{
|
|
l_crn_col = to_short(t_line);
|
|
c_loc_flg = ON;
|
|
|
|
/* Skip past digit. */
|
|
|
|
while (isdigit(*t_line))
|
|
t_line++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* Skip digits and blanks and illegal characters then read in text string. */
|
|
|
|
while ( (*t_line) && (!isalpha(*t_line)) && (!isdigit(*t_line)) && (*t_line != UNDERSC)
|
|
&& (*t_line != COLON) && (*t_line != ASTER))
|
|
t_line++;
|
|
|
|
/* Text string must begin with an alphanumeric character, and underscore,a colon, or an
|
|
asterisk. After the first character blanks will be legal for text strings. */
|
|
|
|
if ((isalpha(*t_line)) || (isdigit(*t_line)) || (*t_line == UNDERSC) || (*t_line == COLON) ||
|
|
(*t_line == ASTER))
|
|
{
|
|
while( (isalpha(*t_line)) || (isdigit(*t_line)) || (*t_line == UNDERSC) || (*t_line == BLANK)
|
|
|| (*t_line == COLON) || (*t_line == ASTER) ||(*t_line == DOT))
|
|
*txt_ptr++ = *t_line++;
|
|
*txt_ptr = NULL;
|
|
}
|
|
|
|
if (win_array[win_ctr]->t_head == NULL)
|
|
{
|
|
if ((*txt_str) && (r_loc_flg) && (c_loc_flg))
|
|
{
|
|
win_array[win_ctr]->t_head = txt_alloc();
|
|
win_array[win_ctr]->t_head->next = NULL;
|
|
if (*txt_str)
|
|
strcpy(win_array[win_ctr]->t_head->txt_str,txt_str);
|
|
win_array[win_ctr]->t_head->l_crn_row = l_crn_row;
|
|
win_array[win_ctr]->t_head->l_crn_col = l_crn_col;
|
|
}
|
|
else if (! (txt_str))
|
|
printf("No text string. Text node omitted.\n");
|
|
else if ((!(r_loc_flg)) || (! (c_loc_flg)))
|
|
printf("Incomplete location information. Text node omitted.\n");
|
|
}
|
|
|
|
|
|
/* Otherwise, add the node immediately after the head of the list. */
|
|
|
|
else
|
|
{
|
|
if ((*txt_str) && (r_loc_flg) && (c_loc_flg))
|
|
{
|
|
node_ptr = txt_alloc(); /* Set the new node's next pointer to point at
|
|
the head of the list. */
|
|
node_ptr->next= win_array[win_ctr]->t_head; /* Set pointer to the head to point at the new node. */
|
|
win_array[win_ctr]->t_head = node_ptr;
|
|
if (*txt_str)
|
|
strcpy(win_array[win_ctr]->t_head->txt_str,txt_str);
|
|
win_array[win_ctr]->t_head->l_crn_row = l_crn_row;
|
|
win_array[win_ctr]->t_head->l_crn_col = l_crn_col;
|
|
}
|
|
else if (! (txt_str))
|
|
printf("No text string. Text node omitted.\n");
|
|
else if ((!(r_loc_flg)) || (! (c_loc_flg)))
|
|
printf("Incomplete location information. Text node omitted.\n");
|
|
}
|
|
return;
|
|
}
|
|
|
|
/************************************************************************************/
|
|
/* This function throws away all characters and returns a pointer */
|
|
/* to the first digit. */
|
|
/************************************************************************************/
|
|
|
|
static char *skip_to_digit(pstr)
|
|
char *pstr;
|
|
{
|
|
|
|
while (*pstr)
|
|
{
|
|
if( (isdigit(*pstr)) )
|
|
return (pstr);
|
|
else if (pstr == NULL)
|
|
{
|
|
return (NULL);
|
|
}
|
|
else
|
|
pstr++;
|
|
}
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
/************************************************************************************/
|
|
/* Get a number from display element line, convert it to register short. */
|
|
/* This function was stolen from Bob Dalesio with a slight modification. */
|
|
/************************************************************************************/
|
|
|
|
static int to_short(pstr)
|
|
char *pstr;
|
|
{
|
|
short num;
|
|
|
|
num = 0;
|
|
while(isdigit(*pstr))
|
|
{
|
|
num = (num * 10) + (*pstr -'0');
|
|
pstr++;
|
|
}
|
|
return num;
|
|
}
|
|
|
|
|
|
/*************************************************************************************/
|
|
/* This subroutine will be used for debugging only. It reads out the linked list of */
|
|
/* control nodes. It is best to comment out print_menu when using this. */
|
|
/*************************************************************************************/
|
|
|
|
static VOID read_disp_lst(wnd_array,nfiles)
|
|
struct window_node *wnd_array[MAX_DISP_NUM];
|
|
int nfiles;
|
|
{
|
|
struct mon_node *ctl_ptr;
|
|
struct mon_node *mon_ptr;
|
|
struct txt_node *txt_ptr;
|
|
short lopi_i,lopi_j; /* Counters. */
|
|
|
|
lopi_j = 1;
|
|
for (lopi_i = 0; lopi_i < nfiles; lopi_i++)
|
|
{
|
|
if (wind_array[lopi_i] != NULL)
|
|
{
|
|
ctl_ptr = wnd_array[lopi_i]->c_head;
|
|
if ((ctl_ptr == NULL) || (ctl_ptr->next->l_crn_row == LIST_END ))
|
|
printf("Ctl list for display %d is empty.\n",lopi_i);
|
|
else
|
|
{
|
|
ctl_ptr = ctl_ptr->next;
|
|
while (ctl_ptr->l_crn_row != LIST_END)
|
|
{
|
|
printf("Display %d: Node %d\n",lopi_i,lopi_j);
|
|
printf("wnd_array[%d]->c_head->chan = %s \n",lopi_i,ctl_ptr->chan);
|
|
printf("wnd_array[%d]->c_head->l_crn_row = %d \n",lopi_i,ctl_ptr->l_crn_row);
|
|
printf("wnd_array[%d]->c_head->l_crn_col = %d \n",lopi_i,ctl_ptr->l_crn_col);
|
|
lopi_j++;
|
|
ctl_ptr = ctl_ptr->next;
|
|
}
|
|
}
|
|
|
|
lopi_j = 1;
|
|
mon_ptr = wnd_array[lopi_i]->m_head;
|
|
if (mon_ptr == NULL)
|
|
printf("Mon list for display %d is empty.\n",lopi_i);
|
|
else
|
|
{
|
|
while (mon_ptr != NULL)
|
|
{
|
|
printf("Display %d: Node %d\n",lopi_i,lopi_j);
|
|
printf("wnd_array[%d]->m_head->chan = %s \n",lopi_i,mon_ptr->chan);
|
|
printf("wnd_array[%d]->m_head->l_crn_row = %d \n",lopi_i,mon_ptr->l_crn_row);
|
|
printf("wnd_array[%d]->m_head->l_crn_col = %d \n",lopi_i,mon_ptr->l_crn_col);
|
|
lopi_j++;
|
|
mon_ptr = mon_ptr->next;
|
|
}
|
|
}
|
|
lopi_j = 1;
|
|
txt_ptr = wnd_array[lopi_i]->t_head;
|
|
if (txt_ptr == NULL)
|
|
printf("Txt list for display %d is empty.\n",lopi_i);
|
|
else
|
|
{
|
|
while (txt_ptr != NULL)
|
|
{
|
|
printf("Display %d: Node %d\n",lopi_i,lopi_j);
|
|
printf("wnd_array[%d]->t_head->txt_str = %s \n",lopi_i,txt_ptr->txt_str);
|
|
printf("wnd_array[%d]->t_head->l_crn_row = %d \n",lopi_i,txt_ptr->l_crn_row);
|
|
printf("wnd_array[%d]->t_head->l_crn_col = %d \n",lopi_i,txt_ptr->l_crn_col);
|
|
lopi_j++;
|
|
txt_ptr = txt_ptr->next;
|
|
}
|
|
}
|
|
}
|
|
lopi_j = 1;
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/***************************************************************************************/
|
|
/* This function puts text specified by the user in the display file on the screen. */
|
|
/***************************************************************************************/
|
|
|
|
static VOID display_text(disp_array,selected)
|
|
struct window_node *disp_array[MAX_DISP_NUM];
|
|
short selected;
|
|
{
|
|
short mrow,mcol;
|
|
struct txt_node *txt_ptr;
|
|
char txt_str[MAX_LIN_LEN];
|
|
mrow = 0;
|
|
mcol = 0;
|
|
mv_cursor(&mrow,&mcol,NO_CMD);
|
|
txt_ptr = disp_array[selected]->t_head;
|
|
|
|
while (txt_ptr != NULL)
|
|
{
|
|
mrow = txt_ptr->l_crn_row;
|
|
mcol = txt_ptr->l_crn_col;
|
|
strcpy(txt_str,txt_ptr->txt_str);
|
|
mv_cursor(&mrow,&mcol,txt_str);
|
|
txt_ptr = txt_ptr->next;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/***************************************************************************************/
|
|
/* Displays a file chosen by the user from the display file which was created when */
|
|
/* the program initialized. Also calls put_value() to write to controls if the user */
|
|
/* selects and F7. */
|
|
/***************************************************************************************/
|
|
|
|
static VOID display_file(disp_array,selected,screen_up,data_num,pdata_flg,k_buff,val_in)
|
|
struct window_node *disp_array[MAX_DISP_NUM];
|
|
short selected;
|
|
short *screen_up;
|
|
short *data_num; /* Flag indicating that there is data waiting to
|
|
be read from the input buffer. */
|
|
short *pdata_flg; /* Flag indicating that a monitor has brought in new data. */
|
|
char k_buff[BUFF_SIZE]; /* Buffer for characters entered. */
|
|
char val_in[MAX_STRING_SIZE];
|
|
{
|
|
char *w_ptr; /* Pointer to next available space for writing. */
|
|
struct mon_node *c_ptr = NULL;
|
|
struct mon_node *m_ptr = NULL;
|
|
struct txt_node *t_ptr = NULL;
|
|
char txt_str[MAX_LIN_LEN];
|
|
char prefix[MAX_LIN_LEN];
|
|
int nmbr;
|
|
short krow,kcol; /* Variables keeping track of where cursor is at all times. */
|
|
short trow,tcol; /* Variables keeping track of where cursor is at all times. */
|
|
short init; /* Flag to indicate display monitors whether to initialize monitors or
|
|
not. */
|
|
|
|
|
|
/* Initialize buffers into which channel names and values are
|
|
written for a put. */
|
|
pdata_flg = OFF;
|
|
k_buff[BUFF_SIZE - 1] = NULL;
|
|
w_ptr = k_buff;
|
|
*data_num = 0;
|
|
num_times = 0;
|
|
krow = 0; /*Krow and kcol store cursor position. */
|
|
kcol = 0;
|
|
|
|
trow = 0; /* trow and tcol store cursor position for diagnostic messages only. */
|
|
trow = 0;
|
|
|
|
/* If a non existant screen has been selected, print error message. */
|
|
|
|
if ( disp_array[selected] == NULL )
|
|
{
|
|
trow++;
|
|
tcol = 0;
|
|
mv_cursor(&trow,&tcol,"Found no display file for this display.");
|
|
trow++;
|
|
taskDelay(30);
|
|
selected = NOTHING_SELECTED;
|
|
*screen_up = OFF;
|
|
w_ptr = k_buff;
|
|
(*data_num) = 0;
|
|
}
|
|
else
|
|
{
|
|
trow++;
|
|
tcol = 0;
|
|
m_ptr = disp_array[selected]->m_head;
|
|
c_ptr = disp_array[selected]->c_head;
|
|
t_ptr = disp_array[selected]->t_head;
|
|
/* If a screen with no data has been selected, exit. */
|
|
|
|
if ((c_ptr == NULL) && (m_ptr == NULL)
|
|
&& ( t_ptr == NULL))
|
|
{
|
|
trow++;
|
|
tcol = 0;
|
|
mv_cursor(&trow,&tcol,"Found nothing in this file.");
|
|
taskDelay(60);
|
|
selected = NOTHING_SELECTED;
|
|
*screen_up = OFF;
|
|
w_ptr = k_buff;
|
|
(*data_num) = 0;
|
|
}
|
|
else
|
|
{
|
|
/* Otherwise put up text and initialize the monitors. */
|
|
if(t_ptr != NULL);
|
|
display_text(disp_array,selected);
|
|
init = ON;
|
|
if ((m_ptr != NULL) || (c_ptr != NULL))
|
|
{
|
|
display_monitors(disp_array,selected,screen_up,pdata_flg,&init,except_ptr);
|
|
}
|
|
init = OFF;
|
|
|
|
/* Place cursor on position of first control . */
|
|
|
|
if ((c_ptr != NULL) && (c_ptr->next->l_crn_row != LIST_END))
|
|
{
|
|
c_ptr = c_ptr->next;
|
|
krow = c_ptr->l_crn_row;
|
|
kcol = c_ptr->l_crn_col;
|
|
mv_cursor(&krow,&kcol,NO_CMD);
|
|
}
|
|
}
|
|
}
|
|
|
|
while (*screen_up == ON)
|
|
{
|
|
|
|
/* If there is something in the buffer it will lopi consumed
|
|
until it is used up. */
|
|
|
|
|
|
while (*data_num > 0)
|
|
{
|
|
switch (*w_ptr)
|
|
{
|
|
case F6: /* F6 will cause an exit. Everything else in buffer
|
|
will be lost. */
|
|
semTake(key_sem);
|
|
w_ptr = k_buff;
|
|
*data_num = 0;
|
|
*screen_up = OFF;
|
|
semGive(key_sem);
|
|
break;
|
|
case F7:
|
|
display_text(disp_array,selected);
|
|
semTake(key_sem);
|
|
w_ptr = k_buff;
|
|
*data_num = 0;
|
|
semGive(key_sem);
|
|
trow = BEG_BOX;
|
|
tcol = BEG_BOX;
|
|
if(c_ptr != NULL)
|
|
put_value(c_ptr,val_in);
|
|
break;
|
|
case U_ARROW:
|
|
if (c_ptr != NULL)
|
|
{
|
|
if (c_ptr->prev->l_crn_row != LIST_END)
|
|
{
|
|
c_ptr = c_ptr->prev;
|
|
krow = c_ptr->l_crn_row;
|
|
kcol = c_ptr->l_crn_col;
|
|
mv_cursor(&krow,&kcol,NO_CMD);
|
|
}
|
|
else
|
|
{
|
|
c_ptr = c_ptr->prev->prev;
|
|
krow = c_ptr->l_crn_row;
|
|
kcol = c_ptr->l_crn_col;
|
|
mv_cursor(&krow,&kcol,NO_CMD);
|
|
}
|
|
w_ptr++;
|
|
semTake(key_sem);
|
|
(*data_num)--;
|
|
if ((*w_ptr) == NULL)
|
|
w_ptr = k_buff;
|
|
semGive(key_sem);
|
|
}
|
|
break;
|
|
case D_ARROW:
|
|
if (c_ptr != NULL)
|
|
{
|
|
if (c_ptr->next->l_crn_row != LIST_END)
|
|
{
|
|
c_ptr = c_ptr->next;
|
|
krow = c_ptr->l_crn_row;
|
|
kcol = c_ptr->l_crn_col;
|
|
mv_cursor(&krow,&kcol,NO_CMD);
|
|
}
|
|
else
|
|
{
|
|
c_ptr = c_ptr->next->next;
|
|
krow = c_ptr->l_crn_row;
|
|
kcol = c_ptr->l_crn_col;
|
|
mv_cursor(&krow,&kcol,NO_CMD);
|
|
}
|
|
semTake(key_sem);
|
|
w_ptr++;
|
|
(*data_num)--;
|
|
if ((*w_ptr) == NULL)
|
|
w_ptr = k_buff;
|
|
semGive(key_sem);
|
|
}
|
|
break;
|
|
case RETURN:
|
|
semTake(key_sem);
|
|
(*data_num) = 0;
|
|
w_ptr = k_buff;
|
|
semGive(key_sem);
|
|
break;
|
|
default:
|
|
w_ptr++;
|
|
semTake(key_sem);
|
|
if ((*w_ptr) == NULL)
|
|
w_ptr = k_buff;
|
|
semGive(key_sem);
|
|
break;
|
|
} /* End switch. */
|
|
|
|
|
|
} /* End while data_num > 0 */
|
|
|
|
if (*pdata_flg)
|
|
{
|
|
display_monitors(disp_array,selected,screen_up,pdata_flg,&init,except_ptr);
|
|
taskDelay(5);
|
|
mv_cursor(&krow,&kcol,NO_CMD);
|
|
}
|
|
|
|
|
|
} /* end while screen up. */
|
|
|
|
if (disp_array[selected] != NULL)
|
|
{
|
|
stop_monitors(disp_array,selected);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
/********************************************************************************/
|
|
/* VOID display_monitors */
|
|
/* Uses a linked list of monitors and a doubly linked circular list of */
|
|
/* controls. Controls and monitors are treated the same as far as this */
|
|
/* subroutine is concerned. That is both are monitored. */
|
|
/********************************************************************************/
|
|
|
|
static VOID display_monitors(disp_array,m_select,screen,pdata_flg,init,except_ptr)
|
|
struct window_node *disp_array[MAX_DISP_NUM];
|
|
short m_select; /* Pointer to number of screen selected. */
|
|
short *screen; /* Pointer to variable which tells when to begin desplay. */
|
|
short *pdata_flg; /* Flag to indicate that new data had been received. */
|
|
short *init; /* Flag to indicate that monitors need to be initialized. */
|
|
struct except_node *except_ptr;
|
|
{
|
|
short mon_row,mon_col; /* Local variable used to move cursor to position where update is
|
|
required. After update, cursor will always be returned to the
|
|
esition where keyboard entry cursor is located. */
|
|
short trow = 1;short tcol = 0;
|
|
int status;
|
|
chtype type = TYPENOTCONN;
|
|
char txt_str[120];
|
|
char prefix[80];
|
|
struct mon_node *mon_ptr, *ctl_ptr;
|
|
|
|
mon_row = 0;
|
|
mon_col = 0;
|
|
mon_ptr = disp_array[m_select]->m_head;
|
|
|
|
if (*init)
|
|
{
|
|
SEVCHK(ca_task_initialize(),"Unable to initialize.");
|
|
|
|
status = ca_add_exception_event(lopi_exception_handler,except_ptr);
|
|
if (status != ECA_NORMAL)
|
|
logMsg(" Exception handler error message:%d\n",ca_message_text[CA_EXTRACT_MSG_NO(status)]);
|
|
except_ptr->flg = NO_NEW_DATA;
|
|
bzero(except_ptr->msg,(sizeof(except_ptr->msg)));
|
|
|
|
|
|
ctl_ptr = disp_array[m_select]->c_head;
|
|
if ((ctl_ptr != NULL) && (ctl_ptr->next->l_crn_row != LIST_END)){
|
|
ctl_ptr = ctl_ptr->next;
|
|
while (ctl_ptr->l_crn_row != LIST_END)
|
|
{
|
|
ctl_ptr->ev_ptr = ev_alloc();
|
|
ctl_ptr->ev_ptr->data_flg = NO_NEW_DATA;
|
|
ctl_ptr->conn_flg = CA_OP_CONN_DOWN;
|
|
mon_row = ctl_ptr->l_crn_row;
|
|
mon_col = ctl_ptr->l_crn_col;
|
|
ctl_ptr->prev_size = 4;
|
|
|
|
/* Put up a row of x's where monitor is to be displayed. */
|
|
|
|
ESCAPE
|
|
REVERSE_VIDEO
|
|
strcpy(ctl_ptr->ev_ptr->str," ");
|
|
mv_cursor(&mon_row,&mon_col,ctl_ptr->ev_ptr->str);
|
|
ESCAPE
|
|
ATR_OFF
|
|
status = ca_build_and_connect(ctl_ptr->chan,TYPENOTCONN,0,&ctl_ptr->chan_id,
|
|
NULL,lopi_conn_handler,ctl_ptr);
|
|
if (status != ECA_NORMAL)
|
|
logMsg(" ca_build_and_connect:%d\n",ca_message_text[CA_EXTRACT_MSG_NO(status)]);
|
|
ctl_ptr = ctl_ptr->next;
|
|
}
|
|
}
|
|
|
|
|
|
while (mon_ptr != NULL)
|
|
{
|
|
mon_ptr->ev_ptr = ev_alloc();
|
|
mon_ptr->ev_ptr->data_flg = NO_NEW_DATA;
|
|
mon_ptr->conn_flg = CA_OP_CONN_DOWN;
|
|
mon_row = mon_ptr->l_crn_row;
|
|
mon_col = mon_ptr->l_crn_col;
|
|
mon_ptr->prev_size = 4;
|
|
|
|
/* Put up a row of x's where monitor is to be displayed. */
|
|
|
|
ESCAPE
|
|
REVERSE_VIDEO
|
|
strcpy(mon_ptr->ev_ptr->str," ");
|
|
mv_cursor(&mon_row,&mon_col,mon_ptr->ev_ptr->str);
|
|
ESCAPE
|
|
ATR_OFF
|
|
status = ca_build_and_connect(mon_ptr->chan,TYPENOTCONN,0,&mon_ptr->chan_id,
|
|
NULL,lopi_conn_handler,mon_ptr);
|
|
if (status != ECA_NORMAL)
|
|
logMsg(" ca_build_and_connect:%d\n",ca_message_text[CA_EXTRACT_MSG_NO(status)]);
|
|
mon_ptr = mon_ptr->next;
|
|
}
|
|
|
|
|
|
mon_ptr = disp_array[m_select]->m_head;
|
|
|
|
while (mon_ptr != NULL)
|
|
{
|
|
status = ca_add_event(DBR_STS_STRING,mon_ptr->chan_id,lopi_ev_handler,mon_ptr->ev_ptr,NULL);
|
|
if (status != ECA_NORMAL)
|
|
logMsg("Message:%d\n",ca_message_text[CA_EXTRACT_MSG_NO(status)]);
|
|
type = ca_field_type(mon_ptr->chan_id);
|
|
|
|
if (DEBUG)
|
|
logMsg("Added event for %s,status = %d,type = %d\n",mon_ptr->chan,status,type);
|
|
|
|
/* If channel is found display data if channel is up. Display error messae if channel
|
|
is down. */
|
|
|
|
|
|
if ((type = (ca_field_type(mon_ptr->chan_id))) != TYPENOTCONN)
|
|
|
|
|
|
/* If channel is connected display error message if it is down.
|
|
Print data if it is up. */
|
|
{
|
|
if (mon_ptr->conn_flg == CA_OP_CONN_UP)
|
|
{
|
|
mon_row = mon_ptr->l_crn_row;
|
|
mon_col = mon_ptr->l_crn_col;
|
|
if (mon_ptr->prev_size > (strlen(mon_ptr->ev_ptr->str)))
|
|
{
|
|
blank_fill(txt_str,mon_ptr->prev_size);
|
|
mv_cursor(&mon_row,&mon_col,txt_str);
|
|
}
|
|
mon_ptr->prev_size = strlen(mon_ptr->ev_ptr->str);
|
|
mv_cursor(&mon_row,&mon_col,mon_ptr->ev_ptr->str);
|
|
}
|
|
else if (mon_ptr->conn_flg == CA_OP_CONN_DOWN)
|
|
{
|
|
ESCAPE
|
|
REVERSE_VIDEO
|
|
strcpy(txt_str,"CHAN DOWN");
|
|
mv_cursor(&mon_row,&mon_col,txt_str);
|
|
ESCAPE
|
|
ATR_OFF
|
|
}
|
|
else
|
|
{
|
|
ESCAPE
|
|
REVERSE_VIDEO
|
|
strcpy(txt_str,"UNDEF");
|
|
mv_cursor(&mon_row,&mon_col,txt_str);
|
|
ESCAPE
|
|
ATR_OFF
|
|
}
|
|
}
|
|
|
|
mon_ptr = mon_ptr->next;
|
|
|
|
}
|
|
|
|
|
|
if((ctl_ptr != NULL) && (disp_array[m_select]->c_head->next->l_crn_row != LIST_END))
|
|
{
|
|
ctl_ptr = disp_array[m_select]->c_head->next;
|
|
|
|
while (ctl_ptr->l_crn_row != LIST_END)
|
|
{
|
|
status = ca_add_event(DBR_STS_STRING,ctl_ptr->chan_id,lopi_ev_handler, ctl_ptr->ev_ptr,NULL);
|
|
if (status != ECA_NORMAL)
|
|
logMsg("Message:%s\n",ca_message_text[CA_EXTRACT_MSG_NO(status)]);
|
|
type = ca_field_type(ctl_ptr->chan_id);
|
|
if (DEBUG)
|
|
logMsg("Added event for %s,status = %d,type = %d\n",ctl_ptr->chan,status,type);
|
|
|
|
/* If channel is connected, display data if channel is up. Display error message if
|
|
channel is down. */
|
|
|
|
|
|
if ((type = (ca_field_type(ctl_ptr->chan_id))) != TYPENOTCONN)
|
|
{
|
|
if (ctl_ptr->conn_flg == CA_OP_CONN_UP)
|
|
{
|
|
mon_row = ctl_ptr->l_crn_row;
|
|
mon_col = ctl_ptr->l_crn_col;
|
|
if (ctl_ptr->prev_size > strlen(ctl_ptr->ev_ptr->str))
|
|
{
|
|
blank_fill(txt_str,ctl_ptr->prev_size);
|
|
mv_cursor(&mon_row,&mon_col,txt_str);
|
|
}
|
|
mv_cursor(&mon_row,&mon_col,ctl_ptr->ev_ptr->str);
|
|
ctl_ptr->prev_size = strlen(ctl_ptr->ev_ptr->str);
|
|
}
|
|
else if (ctl_ptr->conn_flg == CA_OP_CONN_DOWN)
|
|
{
|
|
ESCAPE
|
|
REVERSE_VIDEO
|
|
strcpy(txt_str,"CHAN DOWN");
|
|
mv_cursor(&mon_row,&mon_col,txt_str);
|
|
ESCAPE
|
|
ATR_OFF
|
|
}
|
|
else
|
|
{
|
|
ESCAPE
|
|
REVERSE_VIDEO
|
|
strcpy(txt_str,"UNDEF");
|
|
mv_cursor(&mon_row,&mon_col,txt_str);
|
|
ESCAPE
|
|
ATR_OFF
|
|
}
|
|
} /* If type is not TYPENOTCONN. */
|
|
|
|
/* If channel was never connected, display appropriate message. */
|
|
|
|
|
|
ctl_ptr = ctl_ptr->next;
|
|
} /* End while ctl_ptr not equal to LIST END */
|
|
|
|
} /* End if ctl_ptr != NULL etc. */
|
|
|
|
|
|
status = ca_flush_io();
|
|
SEVCHK(status,NULL);
|
|
|
|
if (except_ptr->flg)
|
|
{
|
|
lopi_signal(except_ptr->status,except_ptr->msg);
|
|
if (status != ECA_NORMAL)
|
|
logMsg("Status abnormal: %d\n",ca_message_text[CA_EXTRACT_MSG_NO(status)]);
|
|
else
|
|
logMsg("Normal status:%d\n",ca_message_text[CA_EXTRACT_MSG_NO(status)]);
|
|
except_ptr->flg = NO_NEW_DATA;
|
|
}
|
|
|
|
} /* End if init */
|
|
else
|
|
{
|
|
mon_ptr = disp_array[m_select]->m_head;
|
|
while (mon_ptr != NULL)
|
|
{
|
|
if ((mon_ptr->ev_ptr->data_flg) && (mon_ptr->conn_flg == CA_OP_CONN_UP))
|
|
{
|
|
mon_row = mon_ptr->l_crn_row;
|
|
mon_col = mon_ptr->l_crn_col;
|
|
mon_ptr->ev_ptr->data_flg = NO_NEW_DATA;
|
|
if (mon_ptr->prev_size > strlen(mon_ptr->ev_ptr->str))
|
|
{
|
|
blank_fill(txt_str,mon_ptr->prev_size);
|
|
mv_cursor(&mon_row,&mon_col,txt_str);
|
|
}
|
|
mon_ptr->prev_size = strlen(mon_ptr->ev_ptr->str + 2);
|
|
mv_cursor(&mon_row,&mon_col,mon_ptr->ev_ptr->str);
|
|
mon_ptr = mon_ptr->next;
|
|
}
|
|
else if (mon_ptr->conn_flg == CA_OP_CONN_DOWN)
|
|
{
|
|
mon_row = mon_ptr->l_crn_row;
|
|
mon_col = mon_ptr->l_crn_col;
|
|
ESCAPE
|
|
REVERSE_VIDEO
|
|
strcpy(txt_str,"CHAN DOWN");
|
|
mv_cursor(&mon_row,&mon_col,txt_str);
|
|
ESCAPE
|
|
ATR_OFF
|
|
mon_ptr->prev_size = 10;
|
|
mon_ptr = mon_ptr->next;
|
|
}
|
|
else
|
|
mon_ptr = mon_ptr->next;
|
|
|
|
}
|
|
ctl_ptr = disp_array[m_select]->c_head;
|
|
|
|
if ((ctl_ptr != NULL) && (disp_array[m_select]->c_head->next->l_crn_row != LIST_END))
|
|
{
|
|
ctl_ptr = disp_array[m_select]->c_head->next;
|
|
|
|
while (ctl_ptr->l_crn_row != LIST_END)
|
|
{
|
|
if ((ctl_ptr->ev_ptr->data_flg) && (ctl_ptr->conn_flg == CA_OP_CONN_UP))
|
|
{
|
|
mon_row = ctl_ptr->l_crn_row;
|
|
mon_col = ctl_ptr->l_crn_col;
|
|
ctl_ptr->ev_ptr->data_flg = NO_NEW_DATA;
|
|
if (ctl_ptr->prev_size > strlen(ctl_ptr->ev_ptr->str))
|
|
{
|
|
blank_fill(txt_str,ctl_ptr->prev_size );
|
|
mv_cursor(&mon_row,&mon_col,txt_str);
|
|
}
|
|
ctl_ptr->prev_size =(strlen(ctl_ptr->ev_ptr->str)) + 2;
|
|
mv_cursor(&mon_row,&mon_col,ctl_ptr->ev_ptr->str);
|
|
ctl_ptr = ctl_ptr->next;
|
|
}
|
|
else if (ctl_ptr->conn_flg == CA_OP_CONN_DOWN)
|
|
{
|
|
mon_row = ctl_ptr->l_crn_row;
|
|
mon_col = ctl_ptr->l_crn_col;
|
|
ESCAPE
|
|
REVERSE_VIDEO
|
|
strcpy(txt_str,"CHAN DOWN");
|
|
mv_cursor(&mon_row,&mon_col,txt_str);
|
|
ESCAPE
|
|
ATR_OFF
|
|
ctl_ptr->prev_size = 10;
|
|
ctl_ptr = ctl_ptr->next;
|
|
}
|
|
else
|
|
ctl_ptr = ctl_ptr->next;
|
|
} /* End while ctl_ptr != LIST_END. */
|
|
} /* End if ctl_ptr != NULL etc. */
|
|
|
|
semTake(mon_sem);
|
|
*pdata_flg = NO_NEW_DATA ;
|
|
semGive(mon_sem);
|
|
|
|
if (except_ptr->flg)
|
|
{
|
|
lopi_signal(except_ptr->status,except_ptr->msg);
|
|
mon_col++;
|
|
if (status != ECA_NORMAL)
|
|
logMsg("Status abnormal: %d\n",ca_message_text[CA_EXTRACT_MSG_NO(status)]);
|
|
else
|
|
logMsg("Normal status:%d\n",ca_message_text[CA_EXTRACT_MSG_NO(status)]);
|
|
except_ptr->flg = NO_NEW_DATA;
|
|
}
|
|
|
|
} /* End else */
|
|
}
|
|
|
|
/*************************************************************************************/
|
|
/* VOID stop_monitors */
|
|
/*************************************************************************************/
|
|
static VOID stop_monitors(disp_array,m_select)
|
|
struct window_node *disp_array[MAX_DISP_NUM];
|
|
short m_select; /* Pointer to number of screen selected. */
|
|
{
|
|
struct mon_node *mon_ptr, *ctl_ptr;
|
|
|
|
|
|
|
|
/* Free channel access resources. */
|
|
|
|
mon_ptr = disp_array[m_select]->m_head;
|
|
semTake(mon_sem);
|
|
|
|
while (mon_ptr != NULL)
|
|
{
|
|
ca_clear_channel(mon_ptr->chan_id);
|
|
mon_ptr = mon_ptr->next;
|
|
}
|
|
|
|
ctl_ptr = disp_array[m_select]->c_head;
|
|
|
|
if ((ctl_ptr != NULL) && (disp_array[m_select]->c_head->next->l_crn_row != LIST_END))
|
|
{
|
|
ctl_ptr = disp_array[m_select]->c_head->next;
|
|
while (ctl_ptr->l_crn_row != LIST_END)
|
|
{
|
|
ca_clear_channel(ctl_ptr->chan_id);
|
|
ctl_ptr = ctl_ptr->next;
|
|
}
|
|
}
|
|
|
|
/* Exit channel access. */
|
|
|
|
ca_flush_io();
|
|
|
|
semGive(mon_sem);
|
|
|
|
/* Initialize monitor pointer to the head of the monitor linked list
|
|
in order to move through linked list freeing memory. */
|
|
|
|
|
|
semTake(mon_sem);
|
|
mon_ptr = disp_array[m_select]->m_head;
|
|
while (mon_ptr != NULL)
|
|
{
|
|
free(mon_ptr->ev_ptr);
|
|
mon_ptr->ev_ptr = NULL;
|
|
mon_ptr = mon_ptr->next;
|
|
}
|
|
|
|
/* Initialize control pointer to the head of the control linked list
|
|
in order to move through the list freeing memory. */
|
|
|
|
|
|
ctl_ptr = disp_array[m_select]->c_head;
|
|
|
|
if ((ctl_ptr != NULL) && (disp_array[m_select]->c_head->next->l_crn_row != LIST_END)){
|
|
ctl_ptr = disp_array[m_select]->c_head->next;
|
|
|
|
while (ctl_ptr->l_crn_row != LIST_END)
|
|
{
|
|
free(ctl_ptr->ev_ptr);
|
|
ctl_ptr->ev_ptr = NULL;
|
|
ctl_ptr = ctl_ptr->next;
|
|
}
|
|
}
|
|
semGive(mon_sem);
|
|
|
|
|
|
}
|
|
|
|
/*************************************************************************************/
|
|
/* Monitor event handler. Sets the global data_flg when an event is received */
|
|
/* asynchronously. The flag is reset in display_monitors. */
|
|
/*************************************************************************************/
|
|
|
|
|
|
|
|
VOID lopi_ev_handler(lopi_arg)
|
|
struct event_handler_args lopi_arg;
|
|
{
|
|
struct dbr_sts_string *sts_str_ptr;
|
|
struct ev_node *ev_ptr;
|
|
char txt_str[40];
|
|
static short mon_row = 0;
|
|
static short mon_col = 0;
|
|
char name[15],*nm_ptr;
|
|
struct mon_node *mptr;
|
|
|
|
sts_str_ptr = (struct dbr_sts_string *)lopi_arg.dbr;
|
|
ev_ptr = ((struct ev_node *)lopi_arg.usr);
|
|
|
|
/* If new data has arrived, copy it to the data_string and
|
|
set a flag indicating new data. */
|
|
|
|
mptr = (struct mon_node *)ca_puser(lopi_arg.chid);
|
|
nm_ptr =(char *)(ca_name(lopi_arg.chid));
|
|
semTake(mon_sem);
|
|
if (DEBUG)
|
|
logMsg("Ev hand for CA:%s, BW:%s\n",nm_ptr,mptr->chan);
|
|
if ((data_flg = strncmp(ev_ptr->str,sts_str_ptr->value,12) != 0))
|
|
{
|
|
strncpy(ev_ptr->str, sts_str_ptr->value,12);
|
|
ev_ptr->str[12] = NULL;
|
|
ev_ptr->data_flg = NEW_DATA;
|
|
}
|
|
semGive(mon_sem);
|
|
}
|
|
|
|
/*************************************************************************************/
|
|
/* Exception handler. This routine is called by channel access for asychronous */
|
|
/* events in the server. */
|
|
/*************************************************************************************/
|
|
|
|
VOID lopi_exception_handler(lopi_except_arg)
|
|
struct exception_handler_args lopi_except_arg;
|
|
{
|
|
struct except_node *except_ptr;
|
|
except_ptr = (struct except_node *)lopi_except_arg.usr;
|
|
if (DEBUG)
|
|
logMsg("Exception handler got exception. \n");
|
|
strncpy(except_ptr->msg,lopi_except_arg.ctx, MAX_LIN_LEN - 2);
|
|
except_ptr->msg[MAX_LIN_LEN - 1] = NULL;
|
|
except_ptr->status = lopi_except_arg.stat;
|
|
except_ptr->flg = NEW_DATA;
|
|
}
|
|
|
|
/*************************************************************************************/
|
|
/* Monitor connection handler. This routine is called by channel access to report */
|
|
/* changes in the connection status channels. */
|
|
/*************************************************************************************/
|
|
|
|
VOID lopi_conn_handler(lopi_connect_arg)
|
|
struct connection_handler_args lopi_connect_arg;
|
|
{
|
|
struct mon_node *pmon;
|
|
int status;
|
|
char txt_str[40];
|
|
static short mon_row = 0;
|
|
static short mon_col = 0;
|
|
char name[15],*nm_ptr;
|
|
|
|
pmon = (struct mon_node *)ca_puser(lopi_connect_arg.chid);
|
|
nm_ptr = (char *)ca_name(lopi_connect_arg.chid);
|
|
if (lopi_connect_arg.op == CA_OP_CONN_DOWN)
|
|
{
|
|
pmon->conn_flg = CA_OP_CONN_DOWN;
|
|
}
|
|
else if (lopi_connect_arg.op == CA_OP_CONN_UP)
|
|
{
|
|
pmon->conn_flg = CA_OP_CONN_UP;
|
|
}
|
|
else
|
|
pmon->conn_flg = UNDEF;
|
|
|
|
if (DEBUG)
|
|
logMsg("Conn hand for CA:%s, BW:%s\n",nm_ptr,pmon->chan);
|
|
|
|
}
|
|
|
|
/*************************************************************************************/
|
|
/* Frees memory allocated by lopi.c */
|
|
/*************************************************************************************/
|
|
|
|
void free_mem(disp_array,dmenu,nlines,except_ptr)
|
|
struct window_node *disp_array[MAX_DISP_NUM];
|
|
int nlines;
|
|
char *dmenu[MXMENU];
|
|
{
|
|
struct txt_node *txt_ptr;
|
|
struct mon_node *ctl_ptr;
|
|
struct mon_node *mon_ptr;
|
|
char *mptr;
|
|
register short lopi_i;
|
|
for (lopi_i = 0; lopi_i < nlines; lopi_i++)
|
|
{
|
|
while (disp_array[lopi_i]->t_head != NULL)
|
|
{
|
|
txt_ptr = disp_array[lopi_i]->t_head;
|
|
disp_array[lopi_i]->t_head = disp_array[lopi_i]->t_head->next;
|
|
free(txt_ptr);
|
|
}
|
|
|
|
while(disp_array[lopi_i]->c_head != NULL)
|
|
{
|
|
ctl_ptr = disp_array[lopi_i]->c_head;
|
|
disp_array[lopi_i]->c_head = disp_array[lopi_i]->c_head->next;
|
|
free(ctl_ptr);
|
|
}
|
|
|
|
while(disp_array[lopi_i]->m_head != NULL)
|
|
{
|
|
mon_ptr = disp_array[lopi_i]->m_head;
|
|
disp_array[lopi_i]->m_head = disp_array[lopi_i]->m_head->next;
|
|
free(mon_ptr);
|
|
}
|
|
|
|
mptr = dmenu[lopi_i];
|
|
free(mptr);
|
|
dmenu[lopi_i] = NULL;
|
|
|
|
}
|
|
free(except_ptr);
|
|
return;
|
|
}
|
|
|
|
/********************************************************************************/
|
|
/* Puts the value passed to it as a string to the data base channel which cptr */
|
|
/* points to. */
|
|
/********************************************************************************/
|
|
|
|
void put_value(c_ptr,val_in)
|
|
char val_in[MAX_STRING_SIZE]; /* Array containing value to be put. */
|
|
struct mon_node *c_ptr; /* Pointer to record of channel to which value is to
|
|
be passes. */
|
|
{
|
|
status = ca_put(DBR_STRING,c_ptr->chan_id,((void *)val_in));
|
|
if (status != ECA_NORMAL)
|
|
logMsg("Message:%s\n",ca_message_text[CA_EXTRACT_MSG_NO(status)]);
|
|
if (DEBUG)
|
|
logMsg("Putting %s to %s\n",val_in,c_ptr->chan);
|
|
status = ca_flush_io();
|
|
if (status != ECA_NORMAL)
|
|
logMsg("Message:%s\n",ca_message_text[CA_EXTRACT_MSG_NO(status)]);
|
|
return;
|
|
}
|