#include <types.h>
#include <modes.h>
#include <strings.h>
#include <errno.h>

#define MAX_LEN    1500
#define MAX_CHAN      6
#define ERR          -1
#define OK            1
#define READY         1
#define NOT_READY     0
#define SIG_V24     417
#define SIG_ETH     418

#define max(x,y)  ((x) > (y) ? (x) : (y))
#define min(x,y)  ((x) < (y) ? (x) : (y))

typedef unsigned char uchar;
typedef enum {seven_bit, seven_plus, eight_bit}  traffic_type;

int vpath[MAX_CHAN];
char *term[MAX_CHAN] = {"/term","/t1","/t2","/t3","/t4","/t5"};

char sys_com[220];
char com[220];
extern int dataready;

extern void rpc_os9_init();

/*	Initialise a V24 channel				    v24_open()
**
*/
v24_open(chan,baud, traffic_bits, trace)
int chan, baud;
traffic_type traffic_bits;
char trace;
{
/*
 *  tsmon for correct channel must be disabled before setup.
 *  However, never disable /term !!
 *  Set-up the port here, i.e. baud rate ...
*/
   int istat;

   rpc_os9_init();    /* Set up intercept handler */

   if (chan <=0 || chan > (MAX_CHAN -1) ) {
        printf(" FATAL ERROR: addressing unsupported port number %d\n",chan);
        return( ERR);
        }

   istat = check_tsmon(term[chan]);
   if (istat != OK) 
       return ERR;
   istat = setup_port(term[chan],baud,traffic_bits);
   if (istat != OK) 
       return ERR;
   
   dataready = NOT_READY;        /* set the flag   */

   vpath[chan] = open(term[chan], S_IREAD | S_IWRITE);
   if (vpath[chan] >=3 ){
       if (trace)
           printf(" OPEN vpath %d\n",vpath[chan]);
       istat = _ss_ssig(vpath[chan],SIG_V24);
       return OK;
       }
   if (trace)
       printf(" V24_OPEN  ERROR\n");
   return ERR;
}

v24_close(chan)
int chan;
{

   close(vpath[chan]);
   enable_tsmon(term[chan]);
   return OK;
}

v24_get(buf,len,timeout,chan,trace)
uchar *buf;
int len, timeout, chan;
char trace;
{
   int nch,n_byte, n_loop, istat, mod_time;


       if (dataready == NOT_READY) {
           if (timeout != -1) {
                mod_time = abs(timeout);
                tsleep((mod_time | 0x80000000));   /* 100/256th of a second */
                }
            else 
               sleep(0);
            }
          
       if (dataready == READY ) {
          if  ((n_byte = _gs_rdy(vpath[chan])) != ERR) {
               nch = read(vpath[chan],buf,len);
               if (trace) 
                   printf(" V24_GET  %2x  %d\n",(*buf), (*buf));
               return OK;
              }
          else {
              printf(" NO DATA \n");
              return ERR;
              }
           }

/*
    printf(" V24_GET ERROR in reading from path %d\n",vpath[chan]);
*/

      return ERR;
}

v24_send(buf,len,chan,trace)
uchar *buf;
int len, chan;
char trace;
{
   int stat, istat;
   
/* GET READY FOR ACCEPTING DATA */
   dataready = NOT_READY;
   if (setsigmask(1) == -1 )
      printf(" Can't set signal mask error= %d\n", errno);
   stat = _ss_ssig(vpath[chan],SIG_V24);

   if (trace) 
      for (stat =0; stat < len && stat < 40; stat++) 
           printf(" V24_SEND  %2x  %d\n", *(buf+stat), *(buf+stat));

   stat = write(vpath[chan],buf,len);
   if (stat == len) {
      istat = _ss_ssig(vpath[chan],SIG_V24);
      return OK;
      }
/*
    printf(" V24_SEND ERROR in sending to path %d\n",vpath[chan]);
*/
    return ERR;
}

void v24_clear(chan)
int chan;
{
/*
**    clear the output
*/
    uchar buf[MAX_LEN];
    int i, nch;

    while ((nch = _gs_rdy(vpath[chan])) != ERR) {
/*
**       printf(" V24_CLEAR  path %d  bytes %d\n",vpath[chan],nch);
*/
         i = read(vpath[chan],buf,nch);
    }
}   



/*
*       THESE ARE THE TSMON CONTROL ROUTINES 
*       OPAL SPECIFIC !!!!
*/
setup_port(term, speed, bits)
char *term;
int speed;
traffic_type bits;
{
  int path, pos, i, j, rem, next;
  char rate[6];

  static char *b7[3] = 
             {"noupc bsb nobsl noecho nolf null=0 nopause pag=0 bsp=00 del=18",
             " eor=0D eof=02 reprint=04 dup=01 psc=17 abort=03 quit=05 ",
             "bse=08 bell=07 type=00 baud=00000 xon=11 xoff=13 tabc=09 tabs=4"};
  static char *b8[3] = 
             {"noupc bsb nobsl noecho nolf null=0 nopause pag=0 bsp=00 del=00",
             " eor=00 eof=00 reprint=00 dup=00 psc=00 abort=00 quit=00 ",
             "bse=00 bell=00 type=00 baud=00000 xon=00 xoff=00 tabc=00 tabs=0"};
  
/*  setup the terminal here using XMODE commands; note device descriptor 
 *  must be in modifiable address space.
 *  Also find out whether the descriptor has turned into what we want.
*/

/* DISABLE PROGRAMS USING THE PORT */
   i = disable_tsmon(term);   


/* CHECK THAT WE HAVE A LEGAL BAUD RATE (default 9600)  */
   if (speed != 300 && speed != 600 && speed != 1200 && speed != 1800
       && speed != 2400 && speed != 3600 && speed != 4800
       && speed != 7200 && speed != 9600 && speed != 19200) 
               speed = 9600;
/* CONVERT THE BAUD RATE TO ASCII       */
   pos = 10000;
   rem = 0;
   for (i = 5; i > 0; --i) {
      next = (speed - rem) / pos;
      rate[5-i] = next + '0';
      rem  += next * pos;
      pos = pos / 10;
      }
   rate[6] = '\0';
/* MOVE THE NUMBERS TO DELETE LEADING 0'S */
   while (rate[0] == '0') {
         for (pos = 0; pos <= 3; ++pos)
             rate[pos] = rate[pos+1];
         rate[4] = 0x20;
         }
/* ASSEMBLE THE COMMAND */
   com[0]='\0';
   if (bits == eight_bit) 
      for (i=0; i<=2; ++i)
         strcat( com, b8[i]);
   else 
      for (i=0; i<=2; ++i)
         strcat( com, b7[i]);

/* PUT IN THE BAUD RATE ; SAVE THE com STRING  */
      i = findstr(130,com,"baud=");
      strncpy(&com[i+4], rate, 5);
/* GET THE RID OF THE POSSIBLE BLANKS AFTER BAUD RATE */
      while ( (i = findstr(130,com,"  ")) != 0) {
         strcpy(&com[i],&com[i+1]);
         }


/* DEINIZ THE PORT    */
   sys_command("deiniz",term);
   sys_command("deiniz",term);
   sys_command("deiniz",term);

/* SET UP THE XMODE COMMAND */
   strcpy( &sys_com[0],"xmode ");
   strcat( &sys_com[6], term);
   pos = 6 + strlen(term);
   sys_com[pos] = '\0';
   strcat(sys_com," ");

      strcat( &sys_com[pos], com);
      system(sys_com);
 
/* INITIALIZE */
   sys_command("iniz",term);

/* GET THE FINAL PORT CHARACTERISTICS (THE ONES WE JUST SET) */
   strcpy(sys_com,"xmode ");
   strcat( sys_com,term);
   strcat( sys_com," >-/queue/xm_temp");
   system(sys_com);


/* COMPARE FINAL CHARACTERISTICS WITH THOSE IN com STRING */
   path = open("/queue/xm_temp",S_IREAD);
   pos = read(path,sys_com,359);                   
   close(path);
   sys_com[pos] = '\0';
/* GET RID OF THE PORT NAME AND CARRIAGE CONTROLS */
   i = strlen(term);
   strcpy(&sys_com[0],&sys_com[i+1]);

/* GET THE STRING END RIGHT */
   i = findstr(pos-20,sys_com,"tabs=");
   pos = strlen(sys_com);
   for (j = pos; j > i; --j)
      if (sys_com[j] <= 0x0d)
          sys_com[j] = '\0';
   pos = strlen(sys_com);
   for (i = 0; i <= pos; ++i) 
      if (sys_com[i] == 0x0d) 
          sys_com[i] = 0x20;

/* COMPARE WITH WHAT WE SET UP */
   j = strlen(com);
   pos = _cmpnam(com,sys_com,j);
   if (pos != 0) {
         printf(" %d \n",pos);
         printf(" ERROR: device descriptor not changed. \n");
         return (ERR);
         }
   return OK;
}

check_tsmon(term)
char *term;
/* CHECK THAT DESCRIPTOR IS IN PROPER PLACE, AND NO PROCESSES CONNECTED */
{
  int last, first, diff;
  int i, j , path;

/* SET UP THE mdir COMMAND */
  sys_com[0]='\0';
  strcat(sys_com,"mdir -e ");
  strcat(sys_com,(term+1));
  strcat(sys_com," >>>-/queue/mdir");
  system(sys_com);

/* READ THE mdir OUTPUT */
  j = 0;
  path = open("/queue/mdir",S_IREAD);
  while ( (i = readln(path,sys_com,100)) != 0 ) {
        sys_com[i] = '\0';
        ++j;
        if (j == 3)
            break;
        }
  close(path);
  system("del /queue/mdir");

/* DECODE THE mdir OUTPUT */
  last = first = 0;
  j = 0;
  while (last <= strlen(sys_com)) {
      if (sys_com[last] > 0x20) {
           first = last;
           while (sys_com[++last] > 0x20)
                ;
           diff = last-first;
           strcpy(com, (sys_com+first), diff);
           com[diff] = '\0';
           switch (j) {
              case 0:
                 if (findstr(1,com,"doe") == 1 || findstr(1,com,"DOE") == 1) {
                         printf(" module has been relocated \n");
                         relocate(term);
                         return OK;
                         }
                 else if (diff <= 7 && findstr(1,com,"00") == 1) {
                         printf(" module has been relocated \n");
                         relocate(term);
                         return OK;
                         }
                 break;
              case 7:
                 if ( atoi(com) > 2) {
                     printf(" ERROR: processes linked to this module\n");
                     return ERR;
                     }
                 break;
              default:
                 break;   
              }
           }
      ++last;
      }
      return OK;
}



disable_tsmon(term)
char *term;
{
     char pid[5];
     int pos,path,nch;

     nch = 0;
     sys_com[0]='\0';
     strcpy(&sys_com[0],"procs -e ! grep \">");
     strcat(sys_com, term+1);
     strcat(sys_com,"\" >/queue/k_tsmon");
     system(sys_com);
     path = open("/queue/k_tsmon", S_IREAD);
     for (pos=0; pos < 10; pos++) {
       while (_gs_rdy(path) != ERR) {
          nch = readln(path,sys_com,100);
          if (nch > 5) {
                strncpy(pid,sys_com,3);
                pid[3]='\0';
                strcpy(sys_com,"echo >+/pipe/rshell \"kill ");
                strcat(sys_com,pid);
                strcat(sys_com,"\"");
                printf(" %s \n",sys_com);
                system(sys_com); 
                }
          else 
             goto jump_out;
          }
       tsleep(20);
       }
jump_out:
     close(path);
     return (OK);
}  

enable_tsmon(term)
char *term;
{
  int i, pos;
  static char *def[3] = 
             {" noupc bsb nobsl echo lf null=0 nopause pag=24 bsp=7F del=18 ",
             "eor=0D eof=02 reprint=04 dup=01 psc=17 abort=03 quit=05 ",
             "bse=08 bell=07 type=00 baud=9600 xon=11 xoff=13 tabc=09 tabs=4"};

/* RESET THE SUCKER */
   
/* DEINIZ */
   strcpy( sys_com,"deiniz ");
   strcat( &sys_com[5], (term+1));
   system(sys_com);
/* SETUP THE DEFAULT XMODE COMMANDS */
   sys_com[0]='\0';
   strcpy(sys_com,"xmode ");
   strcat(sys_com,term);
   pos = strlen(sys_com);
   for (i = 0; i <=2; ++i) {
       strcpy(&sys_com[pos],def[i]);
       system(sys_com);
       } 
/* INIZ */
   strcpy( sys_com,"iniz ");
   strcat( &sys_com[5], (term+1));
   system(sys_com);
/* INSTALL TSMON */
   strcpy(sys_com,"tsmon ");
   strcat(sys_com,term);
   strcat(sys_com," &");
   system(sys_com);

   return (OK);
}

relocate(term)
char *term;
{
/* RELOCATE THE MODULE */
   sys_command("deiniz",term);
   sys_command("newrev",term);
   sys_command("iniz",term);
}

sys_command(pcom,term)
char *pcom;
char *term;
{
   strcpy(sys_com,"echo >+/pipe/rshell \"");
   strcat(sys_com,pcom);
   strcat(sys_com," ");
   strcat(sys_com, (term+1));
   strcat(sys_com," \"");
   system(sys_com);
}


/*	Set the OS9 Signal Mask					    setsigmask()
**	-----------------------
**
**  rpc_status setsigmask(signal_number s)
**
**  This function allows signals to be queued when the task is
**  not ready to receive them.  It is called once to set up this way of
**  working.
**
**  On entry,
**
**	The parameteter is the signal number which is to be treated
**	in this way.
**
*/
#asm
setsigmask move.l d0,d1
     clr.l d0
     os9 F$SigMask
     bcc.s nbad
bad  move.l d1,errno(a6)
     move.l #-1,d0
     bra.s done
nbad clr.l d0
done rts
#endasm