/*
    SPYBW.C

Written by SteveT
Started on 20/7/92

Part of Spy to monitor CPU band width usage.
*/

#include <plib.h>
#include <hwif.h>

#define DLG_WIDTH 190
#define DLG_HEIGHT 49
#define DLG_LINE 13
#define STACK_SIZE 500

GLREF_D TEXT *DatCommandPtr;
GLREF_D VOID *winHandle;
GLREF_D TEXT *DatProcessNamePtr;

LOCAL_D UINT TaskCount;

LOCAL_D INT Debug=FALSE;
LOCAL_D UINT oldPri;
LOCAL_D INT winId;
LOCAL_D HANDLE bwPid;
LOCAL_D HANDLE spyPid;
LOCAL_D VOID *TimCB;
LOCAL_D ULONG bwTotal;
LOCAL_D UINT bwCount;
LOCAL_D ULONG bwCabTotal;
LOCAL_D UINT bwCabCount;
LOCAL_D UINT bwCabBase;
LOCAL_D ULONG bwCabDisplayTotal;
LOCAL_D UINT bwCabDisplayCount;
LOCAL_D UINT bwCabDisplayBase;
LOCAL_D UWORD LastCount;
LOCAL_D UWORD SampleCount;

LOCAL_D UBYTE TaskStack[STACK_SIZE];

/***********************************************************/
/* This section of code is used by the task to measure the */
/* available band width.                                   */
/***********************************************************/

LOCAL_C VOID MonitorLoop(VOID)
    {
    UINT i;

    p_unmarka();
    FOREVER
        {
        for(i=0;i<500;i++);
        TaskCount++;
        }
    }

/*********************/
/* Main body of code */
/*********************/

LOCAL_C VOID DebugInfo(VOID)
    {
    TEXT buf[80];

    p_atos(&buf[0],"%u/%u",LastCount,SampleCount);
    wInfoMsg(&buf[0]);
    }

GLDEF_C VOID DisableReads(UINT flag)
    {
    UINT tmp;

    tmp=P_SCR_DISABLE_READS;
    p_iow(winHandle,P_FSET,&tmp,&flag);
    }

LOCAL_C INT CreateDialog(VOID)
    {
    W_WINDATA windata;
    INT w_id;

    windata.extent.width=DLG_WIDTH;
    windata.extent.height=DLG_HEIGHT;
    windata.extent.tl.x=(240-DLG_WIDTH)>>1;
    windata.extent.tl.y=(80-DLG_HEIGHT)>>1;
    w_id=wCreateWindow(0,W_WIN_EXTENT,&windata,1);
    wInitialiseWindowTree(w_id);
    return(w_id);
    }

LOCAL_C VOID pTxt(UINT line,TEXT *txt,ULONG *pTotal,INT count,INT count2)
    {
    P_RECT rect;
    TEXT buf[20];
    ULONG Percentage,lCount;

    rect.tl.x=4;
    rect.br.x=96;
    rect.tl.y=DLG_LINE+3+line*10;
    rect.br.y=rect.tl.y+8;
    gPrintBoxText(&rect,7,G_TEXT_ALIGN_LEFT,0,txt,p_slen(txt));
    buf[0]=0;
    if (bwCount>0 && count!=0)
        {
        lCount=(ULONG)(count==-1?1:count);
        Percentage=(*pTotal)*100l;
        Percentage/=lCount;
        Percentage/=(ULONG)SampleCount;
        if (count!=0)
            {
            if (count2>=0)
                p_atos(&buf[0],"%U%% [%u-%u]",Percentage,count2,count+count2);
            else
                p_atos(&buf[0],count>0?"%U%% [%u]":"%U%%",Percentage,count);
            }
        }
    rect.tl.x=rect.br.x;
    rect.br.x=DLG_WIDTH-6;
    gPrintBoxText(&rect,7,G_TEXT_ALIGN_LEFT,0,&buf[0],p_slen(&buf[0]));
    }

LOCAL_C VOID redrawWin(UINT update)
    {
    P_RECT rect;
    ULONG tmp;

    if (update)
        gCreateTempGC0(winId);
    else
        {
        wBeginRedrawWinGC0(winId);
        gBorder(W_BORD_CORNER_4|W_BORD_SHADOW_D|W_BORD_SHADOW_ON);
        rect.tl.x=4;
        rect.br.x=DLG_WIDTH-6;
        rect.tl.y=3;
        rect.br.y=11;
        gPrintBoxText(&rect,7,G_TEXT_ALIGN_CENTRE,0,"Available CPU band width",24);
        gDrawLine(1,DLG_LINE,DLG_WIDTH-2,DLG_LINE);
        }
    pTxt(0,"Average",&bwTotal,bwCount,-1);
    tmp=LastCount;
    pTxt(1,"Last",&tmp,-1,-1);
    pTxt(2,"<Cntrl>\002B",&bwCabDisplayTotal,bwCabDisplayCount,bwCabDisplayBase);
    if (update)
        gFreeTempGC();
    else
        wEndRedraw();
    }

LOCAL_C VOID GetCount(UWORD *pCount)
    {
    LONG time;
    WORD tstat;

    p_presume(bwPid);
    time=10l;
    TaskCount=0;
    p_ioc(TimCB,P_FREAD,&tstat,&time);
    p_waitstat(&tstat);
    *pCount=TaskCount;
    if (TaskCount>SampleCount)
        SampleCount=TaskCount;
    p_psuspend(bwPid);
    p_allowoff();
    }

LOCAL_C VOID InitBW(VOID)
    {
    UWORD oldSample,Count2;
    INT i;

    f_leave(bwPid=p_ptask("SYS$SPY",E_MAX_PRIORITY-1,MonitorLoop,&TaskStack[STACK_SIZE-1]));
    f_open(&TimCB,"TIM:",-1);
    spyPid=p_getpid();
    oldPri=p_getpri(spyPid);
    p_setpri(spyPid,E_MAX_PRIORITY);
    if (SampleCount==0)
        for(i=0;i<5;i++)
            {    /* If no matching samples in 5 then just take the best so far */
            oldSample=SampleCount;
            GetCount(&Count2);
            if (Count2==oldSample || (Count2+1)==oldSample || Count2==(oldSample+1))
                break; /* Two matching samples, must be good! */
            }
    p_setpri(bwPid,E_MIN_PRIORITY);
    p_setpri(spyPid,E_PRIORITY_WSERV-1);
    }

#ifdef JPIC
#pragma save,ENTER_CALL
#endif
LOCAL_C INT xMonitorBandWidth(VOID)
    {
    WS_EV event;

    bwCabDisplayCount=bwCabCount=bwCount=bwCabDisplayBase=bwCabBase=LastCount=0;
    bwCabDisplayTotal=bwCabTotal=bwTotal=0;
    DisableReads(TRUE);
    winId=CreateDialog();
    redrawWin(FALSE);
    wFlush();
    InitBW();
    wGetEvent(&event);
    FOREVER
        {
        p_ioyield();
        if (event.type!=E_FILE_PENDING)
            {
            p_iowait();
            if (event.type==WM_KEY)
                {
                if (event.p.key.keycode==27)
                    break;
                if (event.p.key.keycode==(W_SPECIAL_KEY|'p'))
                    wClientPosition(0,0);
                else if (event.p.key.keycode==(W_SPECIAL_KEY|'b'))
                    {
                    p_sound(-5,320);
                    bwCabDisplayTotal=bwCabTotal;
                    bwCabDisplayCount=bwCabCount;
                    bwCabDisplayBase=bwCabBase;
                    bwCabTotal=0;
                    bwCabCount=0;
                    bwCabBase=bwCount;
                    redrawWin(TRUE);
                    }
                else if (event.p.key.keycode=='d')
                    Debug=!Debug;
                }
            else switch (event.type)
                {
                case WM_REDRAW:
                    if (event.handle!=1)
                        wInfoMsg("Redraw to unknown window!");
                    else
                        redrawWin(FALSE);
                    break;
                case WM_FOREGROUND:
                case WM_BACKGROUND:
                    p_setpri(spyPid,E_PRIORITY_WSERV-1);
                    break;
                }
            wGetEvent(&event);
            }
        else
            {
            GetCount(&LastCount);
            if (Debug)
                DebugInfo();
            bwTotal+=LastCount;
            if (bwCount++==9999)
                bwCount=1;
            bwCabTotal+=LastCount;
            bwCabCount++;
            redrawWin(TRUE);
            wFlush();
            }
        }
    return(0);
    }
#ifdef JPIC
#pragma restore
#endif

GLDEF_C VOID MonitorBandWidth(VOID)
    {
    INT err;
    TEXT *name;

    name=DatProcessNamePtr;
    bwPid=spyPid=0;
    DatProcessNamePtr=0;
    if (wCaptureKey(W_SPECIAL_KEY|'b',W_PSION_MODIFIER|W_CTRL_MODIFIER,W_PSION_MODIFIER|W_CTRL_MODIFIER)<0)
        wInfoMsg("'b' key capture failed");
    wDisableLeaves(FALSE);
    err=p_enter1(xMonitorBandWidth);
    wDisableLeaves(TRUE);
    p_close(TimCB);
    wCancelCaptureKey(W_SPECIAL_KEY|'b',W_PSION_MODIFIER|W_CTRL_MODIFIER,W_PSION_MODIFIER|W_CTRL_MODIFIER);
    if (bwPid>0)
        p_pkill(bwPid,0);
    wCloseWindowTree(winId);
    DisableReads(FALSE);
    if (spyPid>0)
        p_setpri(spyPid,oldPri);
    if (err<0)
        p_notifyerr(err,"Band width monitor failed",NULL,NULL,NULL);
    DatProcessNamePtr=name;
    wDisableLeaves(FALSE);
    }
