/* (c) MAXON Computer GmbH 1989
	 KICKSTART 1989
	 Autor: Dirk Urbanek
	 Prg: UCOUNT
*/

#define UCOUNT_C			Dirk Urbanek 1988
#define K					/* Kommentar an */

#include <Exec/Types.h>
#include <Exec/Memory.h>
#include <Exec/Ports.h>
#include <Exec/Tasks.h>
#include <Devices/Timer.h>
#include <Intuition/Intuition.h>
#include <Functions.h>
#include "Useful_Routines.c"

#define	MAX(a,b) 		 ((a)>(b)?(a):(b))
#define NO_ERR  0l
#define NO_INT  1l
#define NO_GFX  2l
#define NO_MEM  3l
#define NO_PRT  4l
#define NO_TSK  5l
#define NO_WIN  6l
#define NO_EIO  7l
#define NO_TDV  8l

#ifdef  K
char TFehler[][30] =
  {
	"Kein Fehler"					  ,
	"Keine intuition.library"	  ,
	"Keine graphics.library"	  ,
	"Kein Speicher"				  ,
	"Kein MsgPort" 				  ,
	"Keine neue Task" 			  ,
	"Kein Fenster" 				  ,
	"Kein Extended IORequest"	  ,
	"Kein Timer   Device" ,
  };
#endif  K

#define MOTHER 			"UTP DU 88"
#define DAUGHTER			"UTC DU 88"
#define STACKSIZE 		150l
#define BREITE 			400
#define HOEHE				100
#define XOFFS				33
#define YOFFS				17

struct Gadget SysG = {	NULL,0,0,BREITE+50,HOEHE+46,
								GADGHNONE,GADGIMMEDIATE,WDRAGGING,
								NULL,NULL, NULL, NULL, NULL,0, 0 } ;

 struct NewWindow nw = { 0,11,BREITE+50,HOEHE+46,1,2,
								CLOSEWINDOW,
 WINDOWCLOSE|WINDOWDRAG|BACKDROP|SMART_REFRESH|NOCAREREFRESH,
								&SysG,NULL,NULL,NULL,NULL,
								0,0,0,0,WBENCHSCREEN 		  } ;

char WTitle[] = "CPU   Utilisations   Zähler"	  ;
char STitle[] = "UCOUNT            (D.Urbanek '88)" ;

intern void SubTask(),Raster() ;

intern struct	IntuitionBase	 *IntuitionBase  ;
intern struct	GfxBase			 *GfxBase		  ;
intern struct	Window			 *SysF			  = NULL  ;
intern struct	RastPort 		 *rp				  = NULL  ;
intern struct	IntuiMessage	 *IMsg			  = NULL  ;
intern struct	Task				 *Daughter		  = NULL  ;
intern struct	timerequest 	 *TIOReq 		  = NULL  ;
intern struct	MsgPort			 *MPort,*TPort ;
intern struct	Message			 *MMsg			  = NULL  ;
intern			 char 			  *OldName			= NULL  ;
intern			 ULONG			  LCount,MaxCount ;
intern			 BYTE 			  Break,OldPri ;
intern			 LONG 	TError= NO_ERR ,
SError= NO_ERR ;

 void main()
  {
	register UWORD  y = 0 , x = 0 ;
				UWORD  oldy = 0 ;
	struct MsgPort *DPort ;
	struct Message *msg	 ;

	  if(FindTask(MOTHER)) exit(100) ;
	  OldName = ChangeTaskName(MOTHER) ;

 /* Bibliotheken auf, Fenster auf und den Rastport festhalten. */
	  if(!(IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0l)))
		  { TError = NO_INT ; goto no_int ; }
	  if(!(GfxBase =(struct GfxBase *)OpenLibrary("graphics.library",0l)))
		  { TError = NO_GFX ; goto no_gfx ; }
	  if(!(SysF=OpenWindow(&nw)))
		  { TError = NO_WIN ; goto no_win ; }
	  rp = SysF >RPort ;

 /* Fenster  und Schirmtitel setzen, Gitter zeichnen. */
		 SetWindowTitles(SysF ,WTitle , STitle) ;
		 Raster() ;

 /* Speicher für Botschaften und Briefkästen festlegen */
	  if(!(MMsg=(struct Message *)
		  AllocMem(sizeof(struct Message),MEMF_PUBLIC|MEMF_CLEAR)))
		  { TError = NO_MEM ; goto no_mem ; }
	  if(!(MPort = CreatePort(MOTHER , 0l)))
		  { TError = NO_PRT ; goto no_prt1 ; }
	  if(!(TPort = CreatePort(NULL , 0l)))
		  { TError = NO_PRT ; goto no_prt2 ; }

 /* und die Kommunikation mit dem Timerdevice aufnehmen. */
	  if(!(TIOReq=(struct timerequest *)
				  CreateExtIO(TPort,sizeof(struct timerequest))))
		  { TError = NO_EIO ; goto no_eio ; }
	  if(OpenDevice(TIMERNAME,UNIT_VBLANK,TIOReq,0l))
		  { TError = NO_TDV ; goto no_tdv ; }

  /* Jetzt tritt Muttern zurück */
		OldPri = SetTaskPri(FindTask(0l) , 0l) ;
  /* und erzeugt einen SubTask, */
	  if(!(Daughter=CreateTask(DAUGHTER,1L,SubTask,NULL,STACKSIZE)))
		  { TError = NO_TSK ; goto no_tsk ; }

  /* stellt seinen Briefkasten fest, */
	  if(!(DPort=FindPort(DAUGHTER)))
		  { DeleteTask(Daughter);TError = NO_TSK;goto no_tsk; }

  /* initialisiert die Botschaft für die Beendigung */
		  MMsg >mn_Node.ln_Type   = NT_MESSAGE 	;
		  MMsg >mn_ReplyPort 	  = MPort			;
		  MMsg >mn_Length 		  = 0l				;

  /* und die Befehle an die Uhr, */
	  TIOReq >tr_node.io_Command = TR_ADDREQUEST ;
	  TIOReq >tr_time.tv_secs	= 1l ;
	  TIOReq >tr_time.tv_micro = 0l ;

  /* setzt des Subtasks Zähler auf Null und läßt ihn zählen. */
		SetTaskPri(FindTask(0l),12l) ;
		SetTaskPri(Daughter , 11l) ;
		LCount = 0 ;				  /* Probezählen, 			*/
		DoIO(TIOReq) ; 			  /* um MaxCount zu setzen */
		SetTaskPri(Daughter ,  10l) ;
		SetTaskPri(FindTask(0l) , 10l) ;
		MaxCount = LCount ;

  /* Den Stift ansetzen */
		y = HOEHE ; SetAPen(rp,1) ;
		Move(rp, x + XOFFS , y + YOFFS) ;

  /* ARBEITSSCHLEIFE   (Wecker stellen, Ergebnis auswerten	  */
  /* und darstellen (ev. scrollen), Abbruchbedingungen prüfen */
	for(;;)
	 {
	  Break = 0 ;

  /* Zeitgeber initialisieren, Zähler nullen und zählen. */
		 TIOReq >tr_time.tv_secs  = 1l ;
		 TIOReq >tr_time.tv_micro = 0l ;
	  LCount = 0 ;
	  DoIO(TIOReq) ;
	  MaxCount = MAX(LCount,MaxCount) ;
	  y = HOEHE   (MaxCount   LCount) / (MaxCount/HOEHE) ;

	/* Ergebnis darstellen. */
		 if(x == (BREITE 1)) /* rechts am Rand?	dann schieben */
		  {
			ScrollRaster(rp,10,0,XOFFS,YOFFS,BREITE+XOFFS, HOEHE+YOFFS) ;
			SetAPen(rp, 2) ;
			  for(x = 0 ; x <= HOEHE ; x+= 5)
				{
				 Move(rp,BREITE 10 + XOFFS,x + YOFFS) ;
				 Draw(rp,BREITE + XOFFS,x + YOFFS) ;
				}
			 Move(rp,BREITE + XOFFS,YOFFS) ;
			 Draw(rp,BREITE + XOFFS,HOEHE + YOFFS) ;
			SetAPen(rp , 1) ;
			x = BREITE	 10 ;
			Move(rp,x 1 + XOFFS,oldy + YOFFS) ;
		  }
		 else { x++ ; } /* sonst inkrementieren. */

  /* Den eigentlichen Eintrag vornehmen. */
		 Draw(rp,x+XOFFS,y+YOFFS); oldy = y;

  /* Sollen wir schon aufhören? */
	  while(IMsg = (struct IntuiMessage *)GetMsg(SysF >UserPort))
		{ ReplyMsg(IMsg) ; Break = 1 ; }
	  if(Break) break ;
	 }  /* ARBEITSSCHLEIFE, Aufräumarbeiten beginnen. */

  /* Priorität normalisieren, Subtask das Ende mitteilen. */
		SetTaskPri(FindTask(0l),1);
		PutMsg(DPort , MMsg);
		SetTaskPri(FindTask(DAUGHTER) , 10);

  /* Das Ende des Subtasks feststellen und selbst aufhören. */
		  WaitPort(MPort);
		  msg = GetMsg(MPort);
		  SetTaskPri(FindTask(0l) , OldPri);
no_tsk:
	  CloseDevice(TIOReq);
no_tdv:
	  DeleteExtIO(TIOReq , sizeof(struct timerequest));
no_eio:
	  DeletePort(TPort);
no_prt2:
	  DeletePort(MPort);
no_prt1:
	  FreeMem(MMsg,sizeof(struct Message));
no_mem:
	  CloseWindow(SysF);
no_win:
	  CloseLibrary(GfxBase);
no_gfx:
	  CloseLibrary(IntuitionBase );
no_int:
	  ChangeTaskName(OldName);
no_ufl:
#ifdef  K
	printf("Mother:   %s\n" , TFehler[TError]);
	printf("Daughter: %s\n" , TFehler[SError]);
#endif  K
	exit(TError * SError * 10l);
  }

void SubTask()
  {
	struct Message *msg;
	struct MsgPort *ChildPort;
	 geta4() ; /* Lass uns leben! */

  /* Briefkasten anlegen und zählen */
	  if(!(ChildPort = CreatePort(DAUGHTER , 0L)))
		  { SError = NO_PRT ; while(1) ; }
	  SetTaskPri(FindTask(0l) ,  10l) ;
	  while(!(msg = GetMsg(ChildPort)))
		{
		 LCount ++ ; /* immer nur zählen */
		}
  /* Botschaft erhalten, also beenden */
Forbid();
	  ReplyMsg(msg);
	  DeletePort(ChildPort);
	 DeleteTask(FindTask(0L));
  }

char text1[][4] = {"100"," 80"," 60"," 40"," 20","  0"} ;
char text2[][4] = {" 0 ","100","200","300","400" } 	  ;
char Uti[] = "CPU   Auslastung / %  über  Zeit / s"	  ;

 void Raster()
  {
	register i,j ;
	 SetAPen(rp , 2 ) ;
	 for(i = 0 ; i <= BREITE ; i+= 10) {
		Move(rp,i+XOFFS,YOFFS) ;
		Draw(rp,i+XOFFS,HOEHE+ YOFFS) ;	}
	 for(i = 0 ; i <= HOEHE ; i+= 5)   {
		Move(rp,XOFFS,i+ YOFFS) ;
		Draw(rp,BREITE+XOFFS,i+ YOFFS) ; }
	 SetAPen(rp , 3) ;
	 for(i = 0 , j = 0 ; i <= HOEHE ; i+= 20,j++) {
		Move(rp,XOFFS 28, i+YOFFS+3)			 ;
		Text(rp, text1[j] , strlen(text1[j])) ;		}
	 for(i = 0,j = 0 ; i <= BREITE ; i+= 100,j++ ) {
		Move(rp,i+XOFFS 13, HOEHE+YOFFS+10)  ;
		Text(rp, text2[j] , strlen(text2[j])) ;		}
	  SetAPen(rp,1) ;
	 Move(rp,XOFFS,HOEHE+YOFFS+21)	 ;
	 Draw(rp,XOFFS+20,HOEHE+YOFFS+21) ;
	 SetAPen(rp,3) ;
	 Move(rp,XOFFS+28,HOEHE+YOFFS+24) ;
	 Text(rp, Uti , strlen(Uti))	 ;
  }
/* LISTING ENDE */
