%endoflist
%include "inc:fs.imp"
%include "inc:util.imp"
%include "frame"

%begin; !Ethernet monitor station (FEB 84)

%constinteger peakwidth=10
%constinteger colour monitor = 0, v200 = 1, packet matrix = 2,
              data matrix = 3, utilisation = 4
%constinteger a second = 1000
%integer Ox,Oy,i,lastn
%integer xscale,yscale
%integer xaxis,yaxis
%integer maxdisplay
%integer mode,sub mode

@16_3724 %integer Exempt Mask
@16_1070 %integer EV;             ! ether interrupt vector
@16_1078 %integer CV;             ! level 6 interrupt vector for the clock
%constinteger tbe=8,rd=4,rc=2,rbf=1

%constinteger maxreadings = 10000, bandwidth = 2000 {in bits/millisecond
%constinteger adjusted rate = 400   {800 * 1000 /2000
%constinteger firstcli=16_11
%constinteger maxint = 16_7FFFEFFF
%constinteger maxshort = 16_7FEF
%constinteger maxclis = 16_3F
%constinteger oldfs = 16_70
%constinteger vax = 16_72
%constinteger filebeg=16_1000
%integer sym,fileend,j
%integer hours,minutes
%string(31) start date,finish date,out file

%recordformat intf(%integer top,bot,put,get)
%record(intf)intbuf
%constinteger pktsiz=16
%constinteger bufsize=2500*pktsiz
%shortintegerarray utilisations(0:1,1:maxreadings+4)
%integerarray packet distributions(0:532)
%bytearray monitor(0:bufsize-1)

%recordformat port to port(%integer size,data,acks,
                           %short redata,reacks,fromto,
                           %byte asq,dsq,
                           %record(port to port)%name next)
%constinteger maxdata= 5000
%record(port to port)%array port data(0:maxdata-1)
%record(port to port)%name %array mch to mch(firstcli:maxclis+2,
                                             firstcli-1:maxclis+2)
%record(port to port)%name free
%recordformat matrix fill(%integer data,packets,
                          %byte dcol,pcol)
%record(matrix fill)%array fill matrix(firstcli:maxclis+2,firstcli:maxclis+2)
%constinteger clock period = 100
%owninteger starttime=0,starthrs=0,startmins=0
%owninteger ticks=0,tick=0,mins=0,displayrow=0,displaytime=0
%owninteger nextfree=0
%owninteger ethervector=0,clockvector=0,diags=0
%owninteger address errors=0
%owninteger autostart=0
%owninteger initial =0
%owninteger size errors=0
%owninteger period=0,interval=0
%owninteger mean utilisation=0
%owninteger bad size=0, good size=0, total data=0, total size=0,
            percent utilisation=0, peak utilisation=0, last utilisation=0,
            peak so far=0, min so far=0, min this period=0

%longinteger crc,col,dov,fov,ict,pak,acks,dret,aret
%constinteger cr=13,esc=27,nopage=8

%include "e_mon:time.inc"
%include "e_mon:matrix.inc"

%routine %spec initialise
%routine %spec connect to file store(%integer default)

%routine preload(%bytearrayname buffer(0:bufsize-1));
                           !Read Z80 object file into an array
%integer sym
  %onevent 3,9 %start
    closeinput; selectinput(0); %return
  %finish
  selectinput(1)
  fileend = filebeg
  %cycle
    readsymbol(sym); buffer(fileend) = sym; fileend = fileend+1
  %repeat
%end

%routine load(%bytearrayname buffer(0:bufsize-1));
%integer sym,ad
  sym = 0; ETHS = sym; ! Disable station interrupts
  ETHC = 16_03
  %cycle
  %repeatuntil ETHS&tbe#0
  ad = 16_1000
  %while ad<fileend %cycle
    sym = buffer(ad)
    ETHD = sym
    %cycle
    %repeatuntil ETHS&tbe#0
    ad = ad+1
  %repeat
  ETHC = 16_0b
  %cycle
  %repeatuntil ETHS&tbe#0
%end

%routine dialup(%integer port,server)
! Establish a connection between local port PORT and
! network server SERVER providing facility 2 (Filestore)
%string(126)reply
%integer i,bit
%byte facility
%constinteger fs=2
  facility = fs
  bit = 1<<port
  etheropen(port,server<<8)
  etherwrite(port,facility,1)
  %cycle
  %repeatuntil ack&bit#0
  %if nak&bit#0 %start
    nak = nak!!bit
    etherclose(port)
    printstring("Filestore not acknowledging")
    newline
    connect to filestore(0)
    %return
  %finish
  i = cputime+3000
  %cycle
  %repeatuntil dtx&bit#0 %or cputime>i
  %if dtx&bit=0 %start
    etherclose(port)
    printstring("Filestore not responding")
    newline
    connect to filestore(0)
    %return
  %finish
  length(reply) = etherread(port,charno(reply,1),126)
  i = charno(reply,length(reply))
  %unless length(reply)=2 %and i=nl %and charno(reply,1)>'0' %start
    etherclose(port)
    printstring("Filestore: ".reply)
    newline %unless i=nl; 
    connect to filestore(0)
    %return
  %finish
  i = charno(reply,1)-'0'
  etheropen(port,server<<8+i)
  printstring("Connected: "); write(i,0); newline
%end

%routine connect to filestore(%integer default)
%integer fstore
  userno=0
  %if default = 0 %start
     prompt("Filestore(Address):") 
     %cycle
        rhex(fstore)
        skipsymbol %if fstore = 0
     %repeat %until fstore = 16_14 %or fstore = 16_15 %or fstore = 16_3F
  %else 
     fstore = RDTE
  %finish
  printstring("Attempting connection to filestore ");phex2(fstore);newline
  dialup(LSAP,fstore)
%end

%routine reset ether station
%integer i
  printstring("Resetting ether Station...")
  ETHS = 16_40;                      !This resets the hardware
  %for i = 1,1,100 %cycle; %repeat;  !Keep hands round throat for a while
  CV = clockvector
  EV = ethervector
  eths = 6;                          !Back to normal now
  %for i = 1,1,1000 %cycle; %repeat
  printline("Done")
%end

%routine clock tick
%label clock,newclk
   *lea clock,a0;              !  load the address the new vector for the clock
   *move.l CV,2(a0);           !  fill in the address of the old vector
   *lea newclk,a0;             !  put the new address in the old vector
   *move.l a0,CV
   *rts

newclk:
   *move.b #128,ETHC;       ! send the clock tick to the Z80
clock:
   *jmp 16_12345678;            ! jmp to address in the old vector
%end

%routine ether interrupt handler(%record(*)%name r)
%label intadr,intret,notctl,loop,newput
   *lea intadr,a1;             !  load the address of intadr into a1
   *move.l a1,EV;              !  overwrite  interrupt vector with new address
   *move.l a0,6(a1);           !  address of record r passed in a0
   *rts
intadr:
   *movem.l d0/d1/a0/a1/a6,-(sp)
   *move.l #16_000600a1,a0;    !  overwriten with A0
   *move.b 16_7fffc,d0;        !  read status register
   *btst #1,d0;                !  is the first byte from the control register?
   *beq notctl;                !  no; so go to data:
   *move.l 8(a0),a1;           !  get intbuf_put into a1
                               !  put contains address of next slot in buffer
   *moveq #14,d1
   *move.b 16_7ffff,(a1)+;     !  read the control character
loop: 
   *move.b 16_7fffc,d0
   *btst #2,d0
   *beq loop;                  !  wait for the next data byte
   *move.b 16_7fffd,(a1)+
   *dbra d1,loop;              !  read the 14 header + 1 data bytes
   *cmp.l 4(a0),a1;            !  compare with bottom of buffer
   *bne newput
   *move.l (a0),a1;            !  equal so put address of top in a1
newput:
   *move.l a1,8(a0);           !  put a1 into intbuf_put

intret:
   *movem.l (sp)+,d0/d1/a0/a1/a6
   *rte
notctl:
   *move.b 16_7fffd,d0
   *bra intret
%end

%routine date time(%string(31)%name s)
  length(s) = fcommr('G'<<8,"",charno(s,1),31)
  printstring(s)
%end


%recordformat rawf(%byte st,ds,dp,msl,msh,unl,unh,ss,sp,dsl,dsh,psl,psh,
                         ty,sq,d1,d2,d3,d4,d5)   {d1 .. d5 are unnassigned.}
%record(rawf)%array bad(0:3)
%record(rawf)%name raw
%record(rawf) copy

%routine reboot fstore(%integer default)
%owninteger ext=1
%integer i,j,from,to,fromto,sym
%string(2) pt
%integer hours,minutes,tick
%integer units,tenths
%integer mean,peak
%integer data total, redata total, acks total, reacks total, size total
%record(port to port)%name next,out,in

  %realfunction aspercent(%integer num,den)
  %real x,y

     %result=0.0 %if num=0 %or den=0
     x=num;y=den
     %result = x/y * 100
  %end

  %onevent 3,9  %start
    closeoutput; selectoutput(0);
    print String ("Error :")
    Write (Event_Sub,0); Print Symbol (',')
    Write (Event_Extra,0); Print Symbol (':')
    print string (Event_Message)
    New Line
    %stop
  %finish
  printsymbol(esc);printsymbol('v')
  reset ether station
  connect to filestore(default)
  printline("Writing to PUB:".out file.itos(ext,0))
  openoutput(1,"PUB:".out file.itos(ext,0));  selectoutput(1)
  ext = ext + 1
  printstring(start date);space;date time(finish date);newline
  printstring("From  To         ")
  printstring("Data   Redata         Acks   Reacks        Size")
  newline
  %for i = firstcli,1,maxclis+2 %cycle
    %for j = firstcli-1,1,maxclis+2 %cycle
      next == mch to mch(i,j)
      %if next ## nil %start
        data total = 0; redata total = 0
        acks total = 0; reacks total = 0
        size total  = 0
        newline
        %if i <= maxclis %then from = i<<8 %c
        %elseif i = maxclis + 1 %then from = oldfs<<8 %C
        %else from = vax<<8
        %if j <= maxclis %then to = j<<8 %c
        %elseif j = maxclis + 1 %then to = oldfs<<8 %C
        %else to = vax<<8
        phex4(from);printstring(" -> ");phex4(to);newline
        %cycle
          fromto = next_fromto
!          phex4(from + (fromto>>8));printsymbol('.')
!          phex4(to   + (fromto&16_00ff));space
!          write(next_data,12);write(next_redata,8)
!          write(next_acks,12);write(next_reacks,8)
!          write(next_size,12);newline
          data total = data total + next_data
          redata total = redata total + next_redata
          acks total = acks total + next_acks
          reacks total = reacks total + next_reacks
          size total = size total + next_size
          next == next_next
        %repeat %until next == nil
      printstring(" Totals:  ");write(data total,12);write(redata total,8)
        write(acks total,12);write(reacks total,8);write(size total,12);newline
      %finish
    %repeat
  %repeat
  newline
  printstring(start date);space;date time(finish date);newline
  printstring(" PAK    = ");write(pak,12) ;space
  printstring(" RET    = ");write(dret,12)
  printstring(" = ");print(aspercent(dret,pak),5,3)
  printline("% of Data Packets")
  printstring(" ACK    = ");write(acks,12);space
  printstring(" REACKS = ");write(aret,12)
  printstring(" = ");print(aspercent(aret,acks),5,3)
  printline("% of Acknowledgements")
  printstring(" TOTAL TRAFFIC = ");write(total size,12);newline 
  newline
  printstring(" Over ");write(period,4);printstring(" ms sampling period")
  printstring(" and an interval of ");write(interval,2);printline(" minutes:")
  printstring(" The maximum peak was ");print((peak so far//100),8,3);newline
  printstring(" The minimum during the same period was")
  print((min so far//100),8,3);newline
  printline("************************************")
  printline("Breakdown of faulty packets received")
  newline
  i = ICT+FOV+COL+CRC+DOV
  printstring("Total Incorrect Packets ");write(i,12)
  printstring(" = ");print(aspercent(i,pak+acks),5,3)
  printline("% of Total Correct Packets")
  printline("Of which:- ")
  printstring("   Bad Addresses  = ");write(address errors,12) ;newline
  printstring("   Size Faults    = ");write(size errors,12);newline
  printstring("   CRC Errors     = ");write(crc,12);newline
  printstring("   Collisions     = ");write(col,12);newline
  printstring("   DMA over runs  = ");write(dov,12);newline
  printstring("   FIFO overflows = ");write(fov,12);newline
  printstring("   Undetermined   = ");write(ICT-address errors-size errors,12)
  newline
  newline
  printline("**********************************")
  printline("Packet size and data distributions")
  newline
  printline("size     packets   % of total         data   % of total")
  newline
  %for i = 0,1,532 %cycle
     %if packet distributions(i) # 0 %start
        write(i,3);write(packet distributions(i),12)
        print(aspercent(packet distributions(i),pak+acks),8,3)
        write(packet distributions(i)*i,12)
        print(aspercent(packet distributions(i)*i,total data),8,3)
        newline
     %finish
  %repeat
{ian mods}
!
!  newline
!  printline("*************************")
!  printline("Traffic Connection Matrix")
!  newline
!  printline("   To         18      20      28      30      38        FS Vax")
!  printline(" From  +=======+=======+=======+=======+=======+=======..+..+")
  %for i = firstcli,1,maxclis+2 %cycle
!     %if i > maxclis %start
!        spaces(7);printline(".")
!        spaces(7);printline(".")
!        %if i = maxclis + 1 %then printstring("     FS+") %C
!        %else printstring("    Vax+")
!     %else
!        spaces(5)
!        %if rem(i,8) = 0 %then phex2(i) %and printsymbol('+') %C
!        %else spaces(2) %and printsymbol('|')
!     %finish
     %for j = firstcli,1,maxclis+2 %cycle
        out == mch to mch(i,j)
        %cycle
           %exit %if out_data # 0 %or out == nil
           out == out_next
        %repeat
        in == mch to mch(i,j)
        %cycle
           %exit %if in_acks # 0 %or in == nil
           in == in_next
        %repeat
!            %if out == nil %and in == nil %then sym = ' ' %C
!        %elseif out == nil %and in ## nil %then sym = '|' %C
!        %elseif out ## nil %and in ## nil %then sym = '+' %C
!        %else sym = '-'
!        spaces(2) %if j > maxclis
!        printsymbol(sym)
     %repeat
!     newline
  %repeat
!  printline(" From  +=======+=======+=======+=======+=======+=======..+..+")
!  printline("   To         18      20      28      30      38        FS Vax")
{ian again }
  newline
  hours = starthrs; minutes = startmins
  tick = 0
  spaces(20);printline("              % Utilisation Vs. Time")
  spaces(20);printline("0   10   20   30   40   50   60   70   80   90   100")
  spaces(20);printline("+----+----+----+----+----+----+----+----+----+----+")
  %for i = 1,1,mins-1 %cycle
     units = utilisations(0,i)//100; tenths = rem(utilisations(0,i),100)
     pt = "."; pt = pt."0" %if tenths < 10 
     write(units,3);printstring(pt);write(tenths,0)
     units = utilisations(1,i)//100; tenths = rem(utilisations(1,i),100)
     pt = "."; pt = pt."0" %if tenths < 10 
     write(units,3);printstring(pt);write(tenths,0)
     %if tick = 0 %then space %and update and print time(hours,minutes) %C
     %else spaces(6)
     minutes = minutes + interval
     tick = tick + 1; tick = 0 %if tick = 5
     mean = utilisations(0,i)//200
     mean = mean + 1 %if rem(utilisations(0,i),200) >= 100
     mean = mean - 1 
     peak = utilisations(1,i)//200
     peak = peak + 1 %if rem(utilisations(1,i),200) >= 100
     peak = peak - 1 
     printsymbol('|') %and spaces(mean) %if mean >= 0
     printsymbol('*')
     j = peak -1
     j = j - mean %if mean > 0
     spaces(j) %and printsymbol('>') %if j >= 0
     newline
  %repeat
  closeoutput
  selectoutput(0)
  initialise
%end

%routine update utilisation
%owninteger do matrix = 0
%integer test
%constinteger a second = 1000

   mean utilisation = mean utilisation + goodsize + badsize
   percent utilisation = ((goodsize+badsize)*adjusted rate)//period
   percent utilisation = percent utilisation + 10 %C
                         %if rem(percent utilisation,10) >= 5
   percent utilisation = percent utilisation//10
   goodsize = 0; badsize = 0
   tick = tick + 1
   %if percent utilisation < min this period %C
                           %then min this period = percent utilisation
   %if percent utilisation >= peak utilisation %C
                           %then peak utilisation = percent utilisation
   %if sub mode = utilisation %or mode = v200 %start
      led bar(last utilisation,percent utilisation,peak utilisation) %C
                                                 %if peak utilisation # 0
   %else %if sub mode = packet matrix %or sub mode = data matrix
      do matrix = do matrix + 1
      show traffic(fill matrix) %and do matrix = 0 %if do matrix = 10
   %finish
   last utilisation = percent utilisation
   %if tick * period >= 60 * a second * interval %start
      total size = total size + mean utilisation
      mean utilisation =(mean utilisation*adjusted rate)//(period*tick*interval)
      mean utilisation = mean utilisation + 10 %if rem(mean utilisation,10) >= 5
      mean utilisation = mean utilisation//10
      utilisations(0,mins) = mean utilisation
      utilisations(1,mins) = peak utilisation
      reset led bar(0)
      minutes = minutes + interval
      hours = hours + 1 %and minutes = rem(minutes,60) %if minutes >= 60
      hours = 0 %if hours = 24
      %if sub mode = utilisation %or mode = v200 %start
         show mean bars(utilisations(0,i),utilisations(1,i),mins+1-i) %C
                              %for i = mins,-1,mins-maxdisplay+displaytime
      %finish
      show time (hours,minutes)
      displaytime = displaytime - 1 %if displaytime # 0
      reboot fstore(RDTE) %if mins = maxreadings
      tick = 0; mins = mins + 1
      %if peak utilisation > peak so far %start
         peak so far = peak utilisation
         min so far = min this period
      %finish
      mean utilisation = 0
      peak utilisation = 0
      percent utilisation = 0
      last utilisation = 0
      min this period = 10000
   %finish
%end

%routine idle
%integer old mode
%integer sym,n,i,j

   n = intbuf_put-intbuf_get
   n = n+intbuf_bot-intbuf_top %if n<0
   %if n>>4 # lastn %start
      lastn = n>>4
      gotoxy(0,35); phex4(lastn) 
   %finish
   %if (n>>4) > 16_0400 %then diags=0 %C
   %else %if (n>>4) <= 16_0100 %then diags=1
   sym=testsymbol
   %return %if sym=-1
   sym = 'R' %if sym = 'Y'&31
   sym='_' %unless ' ' <= sym <= 126
   gotoxy(4,39); printsymbol(sym)

   %if sym = 'R' %start
      autostart = 0; reboot fstore(RDTE)

   %elseif sym = 'D'
      diags = diags!!1

   %elseif (sym = 'M' %or sym = 'm') %and mode = colour monitor
      old mode = sub mode
      %if sym = 'M' %then sub mode = packet matrix %else sub mode = data matrix 
      %if old mode # sub mode %start
         traffic matrix
         show traffic(fill matrix)
         show time(hours,minutes)
         %for i = firstcli,1,maxclis+2 %cycle
            %for j = firstcli,1,maxclis+2 %cycle
               %if sub mode = packet matrix %start
                 show station(fill matrix(i,j)_pcol,i,j) %C
                                    %if fill matrix(i,j)_pcol # 0
               %else %if sub mode = data matrix
                  show station(fill matrix(i,j)_dcol,i,j) %C
                                    %if fill matrix(i,j)_dcol # 0
               %finish
            %repeat
         %repeat
      %finish

   %elseif sym = 'U' %and mode = colour monitor %and sub mode # utilisation
      sub mode = utilisation
      monitor display
      %if mins > 1 %start
         show mean bars(utilisations(0,i),utilisations(1,i),mins-i) %C
                           %for i = mins-1,-1,mins-maxdisplay+displaytime
      %finish
      clear led bar(peak utilisation)
      led bar(last utilisation,percent utilisation,peak utilisation) %C
                                                    %if peak utilisation # 0
      show time(hours,minutes)
   %finish
%end

%routine log(%longintegername err)
  err = err+1
  %if err=1 %start
        %if err==pak  %then gotoxy(2, 5) %and printstring("Pak=") %c
    %elseif err==dret %then gotoxy(2,19) %and printstring("Ret=") %c
    %elseif err==acks %then gotoxy(2,33) %and printstring("Ack=") %c
    %elseif err==aret %then gotoxy(2,47) %and printstring("Reacks=") %c
    %elseif err==crc  %then gotoxy(1, 0) %and printstring("CRC=") %c
    %elseif err==col  %then gotoxy(1,14) %and printstring("COL=") %c
    %elseif err==dov  %then gotoxy(1,28) %and printstring("DOV=") %c
    %elseif err==fov  %then gotoxy(1,42) %and printstring("FOV=") %c
    %elseif err==ict  %then gotoxy(1,56) %and printstring("ICT=")
  %finish
  %if diags = 1 %or err = 1 %start
        %if err==pak  %then gotoxy(2,10) %c
    %elseif err==dret %then gotoxy(2,24) %c
    %elseif err==acks %then gotoxy(2,38) %c
    %elseif err==aret %then gotoxy(2,55) %c
    %elseif err==crc  %then gotoxy(1, 5) %c
    %elseif err==col  %then gotoxy(1,19) %c
    %elseif err==dov  %then gotoxy(1,33) %c
    %elseif err==fov  %then gotoxy(1,47) %c
    %elseif err==ict  %then gotoxy(1,61)
    phex(err)
  %finish
%end


%routine process packet(%record(rawf)%name rawrec)
%integer data size
%integer inserted=0
%owninteger bpak=0,back=0
%integer size,misses ;!JHB changed from %short

   %routine printrec(%record(rawf)%name badrec)
   %owninteger nextfree=0
   %integer i,j
 
      bad(nextfree) = badrec
      %for i = 0,1,3 %cycle
         j = (nextfree - i)&3
         gotoxy(5+i,4)
         space
         phex2(bad(j)_st);spaces(2)
         phex2(bad(j)_ds);spaces(2)
         phex2(bad(j)_dp);spaces(2)
         phex2(bad(j)_msl);spaces(2)
         phex2(bad(j)_msh);spaces(2)
         phex2(bad(j)_unl);spaces(2)
         phex2(bad(j)_unh);spaces(2)
         phex2(bad(j)_ss);spaces(2)
         phex2(bad(j)_sp);spaces(2)
         phex2(bad(j)_dsl);spaces(2)
         phex2(bad(j)_dsh);spaces(2)
         phex2(bad(j)_psl);spaces(2)
         phex2(bad(j)_psh);spaces(2)
         phex2(bad(j)_ty);spaces(2)
         phex2(bad(j)_sq);spaces(2)
         phex2(bad(j)_d1);space
      %repeat
      nextfree = (nextfree+1)&3
   %end ;!of printrec (in process packet)

   %record(port to port)%map insert(%record(port to port)%name list)
   %record(port to port)%name where
   %integer i

      %if list ## nil %start
         %if free_fromto < list_fromto %start
            free_next == list
            list == free
            inserted = 1
         %else %if free_fromto > list_fromto 
            where == list
            %while where_next ## nil %cycle
               %exit %if free_fromto <= where_next_fromto
               where == where_next
            %repeat
            %if where_next == nil %start
               where_next == free
               inserted = 1
            %else %if free_fromto < where_next_fromto
               free_next == where_next
               where_next == free
               inserted = 1
            %else
               %if where_next_size > maxint %or where_next_data   > maxshort %C
                                  %or where_next_redata > maxshort %C
                                  %or where_next_acks   > maxshort %C
                                  %or where_next_reacks > maxshort %start
                  free_next == where_next
                  where_next == free
                  inserted = 1
               %else
                  free == where_next
               %finish
            %finish
         %else
            free == list
         %finish
      %else
         list == free
         inserted = 1
      %finish
      %result == list
   %end ;!of insert (in process packet)

   %if rawrec_st&32 # 0  %start
      ticks = ticks + clock period      
      idle
      update utilisation %and ticks = 0 %if ticks >= period
   %finish
   size = (rawrec_dsh<<8 + rawrec_dsl)+5  { 5= 1 extra source byte +4 trailer
   %if rawrec_st&1 # 0 %start
      log(fov)
!      printrec(rawrec) %if diags = 1
   %else %if rawrec_st&2 # 0
      log(dov)
!      printrec(rawrec) %if diags = 1
   %else %if rawrec_st&16 # 0
      log(ict)
!      printrec(rawrec) %if diags = 1
      badsize = badsize + size 
   %else %if rawrec_st&4 # 0
      log(col)
!      printrec(rawrec) %if diags = 1
       badsize = badsize + size
   %else %if rawrec_st&8 # 0
      log(crc)
!      printrec(rawrec) %if diags = 1
      badsize = badsize + size
   %else %if rawrec_ty&32 = 0 
      misses = rawrec_msh<<8 + rawrec_msl
!      gotoxy(3,20) %and write(misses,3) %if misses # 0
      %if ((firstcli <= rawrec_ss <= maxclis) %or rawrec_ss = oldfs %C
                                           %or rawrec_ss = vax)  %and %C
          ((firstcli <= rawrec_ds <= maxclis) %or rawrec_ds = oldfs %C
                                           %or rawrec_ds = vax %C
                                           %or rawrec_ds = 0) %start
         rawrec_ss = maxclis+1 %if rawrec_ss = oldfs
         rawrec_ss = maxclis+2 %if rawrec_ss = vax
         rawrec_ds = maxclis+1 %if rawrec_ds = oldfs
         rawrec_ds = maxclis+2 %if rawrec_ds = vax
         rawrec_ds = firstcli-1 %if rawrec_ds = 0
         %if rawrec_psl+rawrec_psh<<8 # size-5 %start
            log(ict)
!            printrec(rawrec) %if diags = 1
            size errors = size errors + 1 
            badsize = badsize + size
         %else
            free_next == nil
            free_fromto = rawrec_sp<<8 + rawrec_dp
            mch to mch(rawrec_ss,rawrec_ds) == %C
                       insert(mch to mch(rawrec_ss,rawrec_ds))
            free_size = free_size + size
            good size = good size + size
            data size = size - 19
            total data = total data + data size
            %if rawrec_ds # firstcli -1 %start
               fill matrix(rawrec_ss,rawrec_ds)_data = %C
                  fill matrix(rawrec_ss,rawrec_ds)_data + data size
               fill matrix(rawrec_ss,rawrec_ds)_packets = %C
                  fill matrix(rawrec_ss,rawrec_ds)_packets + 1
            %finish
            packet distributions(data size) = %C
                        packet distributions(data size) + 1
            %if rawrec_ty&128=0 %start
               log(pak)
               %if rawrec_sq=0 %or rawrec_sq#free_dsq %start
                  free_dsq = rawrec_sq; free_data = free_data+1
               %else
                  free_redata = free_redata+1; log(dret)
               %finish
            %else
               log(acks)
               %if rawrec_sq=0 %or rawrec_sq#free_asq %start
                  free_asq = rawrec_sq; free_acks = free_acks+1
               %else
                  free_reacks = free_reacks+1; log(aret)
               %finish
            %finish
            %if inserted = 1 %start
               inserted = 0
               i = 0
               %cycle
                  nextfree = nextfree + 1
                  nextfree = 0 %if nextfree = maxdata
                  i = i + 1
               %repeat %until port data(nextfree)_next == nil %or i = maxdata-1
               reboot fstore(RDTE) %if i = maxdata-1
            %finish
            free == port data(nextfree)
         %finish
      %else
         log(ict)
!         printrec(rawrec) %if diags = 1
         address errors = address errors + 1
         badsize = badsize + size
      %finish
   %finish
%end


%routine initialise
%integer i,j
  openinput(1,"e_mon:monitor.bin"); preload(monitor)
  sym = ' '
  %if autostart = 0 %start
    prompt ("Start Monitor Y/N ? ")
    %cycle
      Read symbol (sym) %until sym # nl %and sym # ' '
      sym = sym - ' ' %if 'a' <= sym <= 'z'
    %repeat %until sym = 'Y' %or sym = 'N'
    %if Sym = 'N' %start
       Exempt Mask = 0 
       newline 
       %stop
    %finish
  %finish
  autostart = 1
  nextfree = 0; diags=1; initial=0
  size errors = 0; address errors = 0
  good size =  0; bad size = 0; total data = 0; total size = 0
  mean utilisation = 0; last utilisation = 0 
  percent utilisation = 0; peak utilisation = 0
  min so far = 10000; peak so far = 0; min this period = 10000
  ticks = 0; tick = 0; mins = 1; displayrow = 1
  crc=0; col=0; dov=0; fov=0;ict=0; pak=0; acks=0; dret=0; aret=0
  %for i= 0,1,maxdata-1 %cycle
    port data(i) = 0
    port data(i)_next == nil
  %repeat
  %for i = firstcli,1,maxclis+2 %cycle
     mch to mch(i,j)==nil %for j = firstcli-1,1,maxclis+2
     fill matrix(i,j) = 0 %for j = firstcli,1,maxclis+2
  %repeat
  bad(i) = 0 %for i = 0,1,3
  utilisations(0,i) = 0 %and utilisations(1,i) = 0 %for i = 1,1,maxreadings
  packet distributions(i) = 0 %for i = 0,1,532
  free == port data(0)
  intbuf_top = addr(monitor(0))
  intbuf_bot = intbuf_top+bufsize
  intbuf_put = intbuf_top; intbuf_get = intbuf_top
  printsymbol(esc);printsymbol('v')
  printstring("Ethernet Monitor Station V1.4")
  printstring("                        Up since ")
  date time(start date);newline
  gotoxy(4,14); printstring("Type <SHIFT> R to reboot: ")
  monitor display
  displaytime = maxdisplay
  Exempt Mask = Exempt Mask ! 1 << ('Y'-'@')
  Exempt Mask = 16_FFFFFFFF
  get real time(hours,minutes)
  starthrs = hours
  startmins = minutes
  show time(hours,minutes)
  load(monitor)
  clock tick
  ether interrupt handler(intbuf)
  ETHS = 6; ! Re-enable station interrupts (receive-only)
%end ;!of initialise
!*   I N I T I A L I S E

  set terminal mode(nopage)
  ethervector = EV
  clockvector = CV
  printsymbol(esc);printsymbol('v')
  printline("Data will be output to pub:Si")
  printline("please supply S part; i will be appended by the program")
  out file = cli param
  %if out file = "" %start
     prompt ("Output file = ")
     Read line(out file)
  %finish
  out file = ("monitor.dt") %if out file = "" %or outfile = " "
  period = 2000
  prompt("Sample Period/milliseconds [default 2000]:")
  %if nextsymbol = nl %then skipsymbol %else read(period)
  interval = 1
  prompt("Sample Interval/mins [default 1]:")
  %if nextsymbol = nl %then skipsymbol %else read(interval)
  prompt("Is there a colour monitor available(Y/N): ")
  sym = ' '
  %cycle
     Read symbol (sym) %until sym # nl %and sym # ' '
     sym = sym - ' ' %if 'a' <= sym <= 'z'
  %repeat %until sym = 'Y' %or sym = 'N'
  mode = colour monitor
  sub mode = utilisation
  mode = v200 %and sub mode = v200 %if sym = 'N'
  setup %and readfont %if sym = 'Y'
  initialise

!** Main Program Loop

lastn = 0
%cycle
  %while intbuf_get#intbuf_put %cycle; ! Update Loop
    raw == record(intbuf_get)
    copy = raw
    intbuf_get = intbuf_get+pktsiz
    intbuf_get = intbuf_top %if intbuf_get=intbuf_bot
    process packet(copy)
  %repeat
  idle %while intbuf_get=intbuf_put
%repeat

%endofprogram
 
