//*****************************************************************************
//
// Open a file and return a handle to the file, if found.  Otherwise, return
// NULL.
//
//*****************************************************************************
struct fs_file *
fs_open(char *name)
{
    const struct fsdata_file *ptTree;
    struct fs_file *ptFile = NULL;

    //
    // Allocate memory for the file system structure.
    //
    ptFile = mem_malloc(sizeof(struct fs_file));
    if(ptFile == NULL)
    {
        //
        // If we can't allocate the memory, return.
        //
        return(NULL);
    }

    //
    // See if the maze data file has been requested.
    //
    if(strncmp(name, "/maze.dat", 9) == 0)
    {
        //
        // Setup the file structure to return the maze data.
        //
        ptFile->data = (char *)g_ppcMaze;
        ptFile->len = sizeof(g_ppcMaze);
        ptFile->index = 0;
        ptFile->pextension = 0;

        //
        // Return the file system pointer.
        //
        return(ptFile);
    }

    //
    // See if the player position file has been requested.
    //
    if(strncmp(name, "/player.dat", 11) == 0)
    {
        //
        // Fill in the buffer containing the player position.
        //
        g_pucPlayer[0] = g_usPlayerX % 256;
        g_pucPlayer[1] = g_usPlayerX / 256;
        g_pucPlayer[2] = g_usPlayerY % 256;
        g_pucPlayer[3] = g_usPlayerY / 256;

        //
        // Setup the file structure to return the player position data.
        //
        ptFile->data = (char *)g_pucPlayer;
        ptFile->len = 4;
        ptFile->index = 0;
        ptFile->pextension = 0;

        //
        // Return the file system pointer.
        //
        return(ptFile);
    }

    //
    // See if the monster position file has been requested.
    //
    if(strncmp(name, "/monster.dat", 12) == 0)
    {
        unsigned long ulIdx;

        //
        // Loop through the monsters, filling in the buffer containing the
        // monster positions.
        //
        for(ulIdx = 0; ulIdx < 100; ulIdx++)
        {
            g_pucMonsters[(ulIdx * 4) + 0] = g_pusMonsterX[ulIdx] % 256;
            g_pucMonsters[(ulIdx * 4) + 1] = g_pusMonsterX[ulIdx] / 256;
            g_pucMonsters[(ulIdx * 4) + 2] = g_pusMonsterY[ulIdx] % 256;
            g_pucMonsters[(ulIdx * 4) + 3] = g_pusMonsterY[ulIdx] / 256;
        }

        //
        // Setup the file structure to return the monster position data.
        //
        ptFile->data = (char *)g_pucMonsters;
        ptFile->len = 400;
        ptFile->index = 0;
        ptFile->pextension = 0;

        //
        // Return the file system pointer.
        //
        return(ptFile);
    }

    //
    // See if the volume up file has been requested.
    //
    if(strncmp(name, "/volume_up.html", 15) == 0)
    {
        //
        // Turn up the volume.
        //
        AudioVolumeUp(10);

        //
        // Setup the file structure to return the volume page.
        //
        ptFile->data = NULL;
        ptFile->len = 0;
        ptFile->index = 0;
        ptFile->pextension = (void *)1;

        //
        // Return the file system pointer.
        //
        return(ptFile);
    }

    //
    // See if the volume down file has been requested.
    //
    if(strncmp(name, "/volume_down.html", 17) == 0)
    {
        //
        // Turn down the volume.
        //
        AudioVolumeDown(10);

        //
        // Setup the file structure to return the volume page.
        //
        ptFile->data = NULL;
        ptFile->len = 0;
        ptFile->index = 0;
        ptFile->pextension = (void *)1;

        //
        // Return the file system pointer.
        //
        return(ptFile);
    }

    //
    // See if the volume file has been requested.
    //
    if(strncmp(name, "/volume_get.html", 16) == 0)
    {
        //
        // Setup the file structure to return the volume page.
        //
        ptFile->data = NULL;
        ptFile->len = 0;
        ptFile->index = 0;
        ptFile->pextension = (void *)1;

        //
        // Return the file system pointer.
        //
        return(ptFile);
    }

    //
    // Initialize the file system tree pointer to the root of the linked list.
    //
    ptTree = FS_ROOT;

    //
    // Begin processing the linked list, looking for the requested file name.
    //
    while(ptTree != NULL)
    {
        //
        // Compare the requested file "name" to the file name in the
        // current node.
        //
        if(strncmp(name, (char *)ptTree->name, ptTree->len) == 0)
        {
            //
            // Fill in the data pointer and length values from the
            // linked list node.
            //
            ptFile->data = (char *)ptTree->data;
            ptFile->len = ptTree->len;

            //
            // For now, we setup the read index to the end of the file,
            // indicating that all data has been read.
            //
            ptFile->index = ptTree->len;

            //
            // We are not using any file system extensions in this
            // application, so set the pointer to NULL.
            //
            ptFile->pextension = NULL;

            //
            // Exit the loop and return the file system pointer.
            //
            break;
        }

        //
        // If we get here, we did not find the file at this node of the linked
        // list.  Get the next element in the list.
        //
        ptTree = ptTree->next;
    }

    //
    // Check to see if we actually find a file.  If we did not, free up the
    // file system structure.
    //
    if(ptTree == NULL)
    {
        mem_free(ptFile);
        ptFile = NULL;
    }

    //
    // Return the file system pointer.
    //
    return(ptFile);
}
//*****************************************************************************
//
// The CAN controller Interrupt handler.
//
//*****************************************************************************
void
CANHandler(void)
{
    unsigned long ulStatus;

    //
    // Find the cause of the interrupt, if it is a status interrupt then just
    // acknowledge the interrupt by reading the status register.
    //
    ulStatus = CANIntStatus(CAN0_BASE, CAN_INT_STS_CAUSE);

    switch(ulStatus)
    {
        //
        // Let the forground loop handle sending this, just set a flag to
        // indicate that the data should be sent.
        //
        case MSGOBJ_NUM_BUTTON:
        {
            //
            // Read the Button Message.
            //
            CANMessageGet(CAN0_BASE, MSGOBJ_NUM_BUTTON,
                &g_MsgObjectButton, 1);

            //
            // Only respond to buttons being release.
            //
            if(g_MsgObjectButton.pucMsgData[0] == EVENT_BUTTON_RELEASED)
            {
                //
                // Check if the up button was released.
                //
                if(g_MsgObjectButton.pucMsgData[1] == TARGET_BUTTON_UP)
                {
                    //
                    // Adjust the volume up by 10.
                    //
                    AudioVolumeUp(10);
                }

                //
                // Check if the down button was released.
                //
                if(g_MsgObjectButton.pucMsgData[1] == TARGET_BUTTON_DN)
                {
                    //
                    // Adjust the volume down by 10.
                    //
                    AudioVolumeDown(10);
                }
            }
            break;
        }

        //
        // When the LED message object interrupts, just clear the flag so that
        // more LED messages are allowed to transfer.
        //
        case MSGOBJ_NUM_LED:
        {
            g_ulFlags &= (~FLAG_LED_TX_PEND);
            break;
        }

        //
        // When the transmit data message object interrupts, clear the
        // flag so that more data can be trasferred.
        //
        case MSGOBJ_NUM_DATA_TX:
        {
            g_ulFlags &= (~FLAG_DATA_TX_PEND);
            break;
        }

        //
        // When a receive data message object interrupts, set the flag to
        // indicate that new data is ready.
        //
        case MSGOBJ_NUM_DATA_RX:
        {
            g_ulFlags |= FLAG_DATA_RECV;
            break;
        }

        //
        // This was a status interrupt so read the current status to
        // clear the interrupt and return.
        //
        default:
        {
            //
            // Read the controller status to acknowledge this interrupt.
            //
            CANStatusGet(CAN0_BASE, CAN_STS_CONTROL);

            //
            // If there was a LED transmission pending, then stop it and
            // clear the flag.
            //
            if(g_ulFlags & FLAG_LED_TX_PEND)
            {
                //
                // Disable this message object until we retry it later.
                //
                CANMessageClear(CAN0_BASE, MSGOBJ_NUM_LED);

                //
                // Clear the transmit pending flag.
                //
                g_ulFlags &= (~FLAG_LED_TX_PEND);
            }

            //
            // If there was a Data transmission pending, then stop it and
            // clear the flag.
            //
            if(g_ulFlags & FLAG_DATA_TX_PEND)
            {
                //
                // Disable this message object until we retry it later.
                //
                CANMessageClear(CAN0_BASE, MSGOBJ_NUM_DATA_TX);

                //
                // Clear the transmit pending flag.
                //
                g_ulFlags &= (~FLAG_DATA_TX_PEND);
            }
            return;
        }
    }

    //
    // Acknowledge the CAN controller interrupt has been handled.
    //
    CANIntClear(CAN0_BASE, ulStatus);
}