/* 
File: lab6app.c
Revision date: 4 November 2009
Description: Application code for EE 425 lab 6 (Message queues)
*/

#include "clib.h"
#include "yakk.h"                   /* contains kernel definitions */
#include "lab6defs.h"               /* contains definitions for this lab */

#define TASK_STACK_SIZE   512       /* stack size in words */
#define MSGQSIZE          10

struct msg MsgArray[MSGARRAYSIZE];  /* buffers for message content */

int ATaskStk[TASK_STACK_SIZE];      /* a stack for each task */
int BTaskStk[TASK_STACK_SIZE];
int STaskStk[TASK_STACK_SIZE];

int GlobalFlag;

void *MsgQ[MSGQSIZE];           /* space for message queue */
YKQ *MsgQPtr;                   /* actual name of queue */

void ATask(void)                /* processes data in messages */
{
    struct msg *tmp;
    int min, max, count;
        
    min = 100;
    max = 0;
    count = 0;
    
    while (1)
    {
        tmp = (struct msg *) YKQPend(MsgQPtr); /* get next msg */
                
        /* check sequence count in msg; were msgs dropped? */
        if (tmp->tick != count+1)
        {
            print("! Dropped msgs: tick ", 21);
            if (tmp->tick - (count+1) > 1) {
                printInt(count+1);
                printChar('-');
                printInt(tmp->tick-1);
                printNewLine();
            }
            else {
                printInt(tmp->tick-1);
                printNewLine();
            }
        }
                
        /* update sequence count */
        count = tmp->tick;
                
        /* process data; update statistics for this sample */
        if (tmp->data < min)
            min = tmp->data;
        if (tmp->data > max)
            max = tmp->data;
                
        /* output min, max, tick values */
        print("Ticks: ", 7);
        printInt(count);
        print("\t", 1);
        print("Min: ", 5);
        printInt(min);
        print("\t", 1);
        print("Max: ", 5);
        printInt(max);
        printNewLine();
    }
}

void BTask(void)                /* saturates the CPU for 5 ticks */
{
    int busycount, curval, j, flag, chcount;
    unsigned tickNum;
        
    curval = 1001;
    chcount = 0;
    
    while (1)
    {
        YKDelayTask(2);
        
        if (GlobalFlag == 1)
        {                           /* flag set -- loop for 5 ticks */
            YKEnterMutex();
            //busycount = YKTickNum;
            busycount = getYKTickNum();
            YKExitMutex();
            
            while (1)
            {
                YKEnterMutex();
                //tickNum = YKTickNum;
                tickNum = getYKTickNum();
                YKExitMutex();
                if(tickNum >= busycount + 5) break;                
                
                curval += 2;        /* evaluate next number */
                flag = 0;
                for (j = 3; (j*j) < curval; j += 2)
                {
                    if (curval % j == 0)
                    {
                        flag = 1;
                        break;
                    }
                }
                if (!flag)
                {
                    printChar('.'); /* output a marker for each prime */
                    if (++chcount > 75)
                    {
                        printNewLine();
                        chcount = 0;
                    }
                }
            }
            printNewLine();
            chcount = 0;
            GlobalFlag = 0;        /* clear flag */
        }
    }
}

void STask(void)                /* tracks statistics */
{
    unsigned max, switchCount, idleCount;
    int tmp;

    YKDelayTask(1);
    printString("Welcome to the YAK kernel\r\n");
    printString("Determining CPU capacity\r\n");
    YKDelayTask(1);
    //YKIdleCount = 0;
    setYKIdleCount(0);
    YKDelayTask(5);
    //max = YKIdleCount / 25;
    max = getYKIdleCount() / 25;
    //YKIdleCount = 0;
    setYKIdleCount(0);

    YKNewTask(BTask, (void *) &BTaskStk[TASK_STACK_SIZE], 10);
    YKNewTask(ATask, (void *) &ATaskStk[TASK_STACK_SIZE], 20);
    
    while (1)
    {
        YKDelayTask(20);
        
        YKEnterMutex();
        //switchCount = YKCtxSwCount;
        switchCount = getYKCtxSwCount();
        //idleCount = YKIdleCount;
        idleCount = getYKIdleCount();
        YKExitMutex();
        
        printString("<<<<< Context switches: ");
        printInt((int)switchCount);
        printString(", CPU usage: ");
        tmp = (int) (idleCount/max);
        printInt(100-tmp);
        printString("% >>>>>\r\n");
        
        YKEnterMutex();
        //YKCtxSwCount = 0;
        setYKCtxSwCount(0);
        //YKIdleCount = 0;
        setYKIdleCount(0);
        YKExitMutex();
    }
}   

void main(void)
{
    YKInitialize();
    
    /* create queue, at least one user task, etc. */
    GlobalFlag = 0;
    MsgQPtr = YKQCreate(MsgQ, MSGQSIZE);
    YKNewTask(STask, (void *) &STaskStk[TASK_STACK_SIZE], 30);
    
    YKRun();
}
