/****************************************************************************/
/* Copyright 2010 MBARI.                                                    */
/* MBARI Proprietary Information. All rights reserved.                      */
/****************************************************************************/
#include <p24fxxxx.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sys_defs.h"
#include "actions.h"
#include "cache.h"
#include "errors.h"
#include "hash.h"
#include "parser.h"
#include "serial.h"
#include "slot.h"
#include "spi.h"

static char msg_buff[128];
int actDebug1 = 0;

void strUpper(char* s);
void strLower(char* s);
unsigned int findSelectSlot(char* s);

/****************************************************************************/
/*                               Root commands                              */
/****************************************************************************/
int actGetCmd(char* s)
{
    return prsParse(s, cmdsGet, ERR_NO_SUB_COMMAND);
}

int actSetCmd(char* s)
{
    return prsParse(s, cmdsSet, ERR_NO_SUB_COMMAND);
}

int actClrCmd(char* s)
{
    return prsParse(s, cmdsClr, ERR_NO_SUB_COMMAND);
}

int actSpiCmd(char* s)
{
    unsigned int reply;
    unsigned int bits = (unsigned int)atoi(s);
    
    spiCS(1);
    reply = spiReadWrite(bits);
    spiCS(0);


    sprintf(msg_buff, "SPI = %u\r\n", reply);
    serPutString(SER_CONSOLE, msg_buff);

    return ERR_SUCCESS;
}

int actResetCmd(char* s)
{
    asm("reset");
    return ERR_SUCCESS;
}

int actHelloKittyCmd(char* s)
{
    serPutString(SER_CONSOLE, "MEOW\r\n");
    return ERR_SUCCESS;
}

int actSlotRescanCmd(char* s)
{
    cacheClear();
    slotInit();
    return ERR_SUCCESS;
}

int actSendCmd(char* s)
{
    char* cmd;
    
    if (findSelectSlot(s))  {
        return ERR_FAILURE;
    }
    
    cmd = strtok(NULL, "");
    
    sprintf(msg_buff, "Sending: \"%s\"\r\n", cmd);
    serPutString(SER_CONSOLE, msg_buff);
        
    spiCS(1);
    spiSendRecvBytes(cmd, strlen(cmd));
    spiCS(0);
    
    return ERR_SUCCESS;
}

int actReadCmd(char* s) {
    const char* delimiters = " ,\t";
    char* varName = strtok(s, delimiters);
    unsigned int instance = atoi(strtok(NULL, delimiters));
    char* format = strtok(NULL, delimiters);
    
    unsigned char index;
    
    unsigned int value;
    unsigned char source;
    unsigned char iotype;
    
    strUpper(varName);
    index = hashCode(varName, strlen(varName)) + instance;
    
    double fmtFloat = 0.0;
    
    cacheGetEntry(index, &value, &source, &iotype);
    
    if (source == TYPE_OPEN)
    {
        sprintf(msg_buff, "No element named %s ", varName);
        serPutString(SER_CONSOLE, msg_buff);
        
        if (instance > 0)
        {
            sprintf(msg_buff, "with instance %d ", instance);
            serPutString(SER_CONSOLE, msg_buff);
        }
        
        serPutString(SER_CONSOLE, "exists.\r\n");
        
        return ERR_FAILURE;
    }
    
    if (format == NULL || prsNameMatch(format, "UINT"))
    {
        sprintf(msg_buff, "%s = %u\r\n", varName, value);
    }
    else if (prsNameMatch(format, "INT"))
    {
        sprintf(msg_buff, "%s = %d\r\n", varName, value);
    }
    else if (prsNameMatch(format, "CHAR"))
    {
        sprintf(msg_buff, "%s = %c\r\n", varName, value);
    }
    else if (prsNameMatch(format, "FLOAT"))
    {
        memcpy(&fmtFloat, &value, sizeof(double));
        sprintf(msg_buff, "%s = %f\r\n", varName, fmtFloat);
    }
    
    serPutString(SER_CONSOLE, msg_buff);
    
    return ERR_SUCCESS;
}

int actWriteCmd(char* s)
{
    const char* delimiters = " ,\t";
    char* value = strtok(s, delimiters);
    char* varName = strtok(NULL, delimiters);
    unsigned int instance = atoi(strtok(NULL, delimiters));
    char* format = strtok(NULL, delimiters);
    
    unsigned char index;
    
    unsigned char source;
    unsigned char iotype;
    
    unsigned int uintValue;
    int intValue;
    char chrValue;
    double dblValue;
    
    strUpper(varName);
    index = hashCode(varName, strlen(varName)) + instance;
    
    double fmtFloat = 0.0;
    
    cacheGetEntry(index, NULL, &source, &iotype);
    
    if (source == TYPE_OPEN)
    {
        sprintf(msg_buff, "No element named %s ", varName);
        serPutString(SER_CONSOLE, msg_buff);
        
        if (instance > 0)
        {
            sprintf(msg_buff, "with instance %d ", instance);
            serPutString(SER_CONSOLE, msg_buff);
        }
        
        serPutString(SER_CONSOLE, "exists.\r\n");
        
        return ERR_FAILURE;
    }
    
    // TODO: something's changing iotype
    if (iotype != CACHE_IO_IN)
    {
        sprintf(msg_buff, "Element %s is not an input type.\r\n", varName);
        serPutString(SER_CONSOLE, msg_buff);
        return ERR_FAILURE;
    }
    
    intValue = atoi(value);
    //cacheSetEntry(index, intValue, source, iotype);
    cacheValues[index] = intValue;
    
    sprintf(msg_buff, "%s = %d\r\n", varName, intValue);
    serPutString(SER_CONSOLE, msg_buff);
    
    return ERR_SUCCESS;
}

int actIntervalCmd(char* s) {
    slotUpdateInterval = atoi(s);
    return ERR_SUCCESS;
}

int actPlatformCmd(char* s)
{
    sprintf(msg_buff, "Platform information:\r\n");
    serPutString(SER_CONSOLE, msg_buff);
    
    sprintf(msg_buff, "\tsizeof(int) = %d\r\n", sizeof(int));
    serPutString(SER_CONSOLE, msg_buff);
    
    sprintf(msg_buff, "\tsizeof(char) = %d\r\n", sizeof(char));
    serPutString(SER_CONSOLE, msg_buff);
    
    sprintf(msg_buff, "\tsizeof(short) = %d\r\n", sizeof(short));
    serPutString(SER_CONSOLE, msg_buff);
    
    sprintf(msg_buff, "\tsizeof(long) = %d\r\n", sizeof(long));
    serPutString(SER_CONSOLE, msg_buff);
    
    sprintf(msg_buff, "\tsizeof(float) = %d\r\n", sizeof(float));
    serPutString(SER_CONSOLE, msg_buff);
    
    sprintf(msg_buff, "\tsizeof(double) = %d\r\n", sizeof(double));
    serPutString(SER_CONSOLE, msg_buff);
    
    return ERR_SUCCESS;
}

int actDumpCacheCmd(char* s)
{
    unsigned int i;
    unsigned int len;
    unsigned char index;
    
    unsigned int value;
    unsigned char source;
    unsigned char io;
    
    if ((len = strlen(s)) == 0) {
        for (i = 0; i < HASH_MAX; i++)
        {
            cacheGetEntry(i, &value, &source, &io);
            if (source < NUM_SLOTS)
            {
                sprintf(msg_buff, "cache[%u] = %u, %s, slot %u\r\n", i, value,
                    io ? "input" : "output", source);
                serPutString(SER_CONSOLE, msg_buff);
            }
        }
    }
    else
    {
        index = hashCode(s, len);
        cacheGetEntry(index, &value, &source, &io);
        sprintf(msg_buff, "cache[%s:%d] = %d (%s, slot %d)\r\n", s, index,
            value, io ? "input" : "output", source);
        serPutString(SER_CONSOLE, msg_buff);
    }
    
    return ERR_SUCCESS;
}

int actHashCmd(char* s)
{
    sprintf(msg_buff, "hash(%s) = %d\r\n", s, hashCode(s, strlen(s)));
    serPutString(SER_CONSOLE, msg_buff);
    return ERR_SUCCESS;
}

/****************************************************************************/
/*                               Get commands                               */
/****************************************************************************/

/** 
 * Prints the output of an SPI request
 * @param s address of data to print
 * @return ERR_SUCCESS
 */
int actGetSpiMemCmd(char* s)
{
    unsigned int add = (unsigned int)atoi(s);
    unsigned int dat;
    
    if ( prsNameMatch(s, "all") )
    {
        for (add = 0; add < 16; ++add)
        {
            dat = spiSlaveRead(add, READ_CMD);
            sprintf(msg_buff, "SPI MEM[%02u] = %u\r\n", add, dat);
            serPutString(SER_CONSOLE, msg_buff);
        }

    }
    else
    {
        dat = spiSlaveRead(add, READ_CMD);
        sprintf(msg_buff, "SPI MEM[%u] = %u\r\n", add, dat);
        serPutString(SER_CONSOLE, msg_buff);
    }

    return ERR_SUCCESS;
}

int actGetSpiInfoCmd(char* s)
{
    unsigned int add = (unsigned int)atoi(s);
    unsigned int dat = spiSlaveRead(add, INFO_CMD);
    
    sprintf(msg_buff, "SPI INFO[%u] = %u\r\n", add, dat);
    serPutString(SER_CONSOLE, msg_buff);

    return ERR_SUCCESS;
}

int actGetCardCmd(char* s)
{   
    char* varStr;
    int varAddr;
    unsigned int in;
    
    if (findSelectSlot(s))
    {
        return ERR_FAILURE;
    }
    
    varStr = strtok(NULL, " ,\t");
    varAddr = hashCode(varStr, strlen(varStr));
    
    in = spiSlaveRead(varAddr, READ_CMD);
    
    /* Print data */
    sprintf(msg_buff, "%s = %d\r\n", varStr, in);
    serPutString(SER_CONSOLE, msg_buff);
    
    return ERR_SUCCESS;
}

int actGetSlotsCmd(char* s)
{
    int type;
    int i;
    
    serPutString(SER_CONSOLE, "Daughtercard types:\r\n");
    
    for (i = 0; i < NUM_SLOTS; i++)
    {
        type = slotGetType(i);
        sprintf(msg_buff, "\tSlot %d: %s (%d)\r\n", i, slotDisplayName(type),
                type);
        serPutString(SER_CONSOLE, msg_buff);
    }
    
    return ERR_SUCCESS;
}

int actGetSlotInfoCmd(char* s)
{
    unsigned int slot = atoi(s);
    
    slotDumpInfo(slot);
    
    return ERR_SUCCESS;
}

/******************************************************************************
 * Test commands
 ******************************************************************************/
int actGetTestCmd(char* s)
{
    sprintf(msg_buff, "Test function 01\n");
    serPutString(SER_CONSOLE, msg_buff);
    
    return ERR_SUCCESS;
}

/****************************************************************************/
/*                               Set commands                               */
/****************************************************************************/
int actSetSpiMemCmd(char* s)
{
    unsigned int add;
    unsigned int dat;
    char *token;
    char *separator = " ,\t";
   
    /* get address */
    token = strtok(s, separator);
    add = (unsigned int)atol(token);

    /* get data */
    token = strtok(NULL, separator);
    dat = (unsigned int)atol(token);
    
    spiSlaveWrite(add, dat);

    sprintf(msg_buff, "SPI MEM[%d] = %u\r\n", add, dat);
    serPutString(SER_CONSOLE, msg_buff);

    return ERR_SUCCESS;
}

int actSetDebug1Cmd(char* s)
{
    actDebug1 = atoi(s);

    sprintf(msg_buff, "actDebug1 = %i\r\n", actDebug1);
    serPutString(SER_CONSOLE, msg_buff);

    return ERR_SUCCESS;
}

int actSetSlotCmd(char* s)
{
    unsigned int addr = atoi(s);
    
    slotSet(addr);
    
    return ERR_SUCCESS;
}

int actSetCardCmd(char* s)
{
    char* varStr;
    int varAddr;
    unsigned int out;
    
    if (findSelectSlot(s))
    {
        return ERR_FAILURE;
    }
    
    varStr = strtok(NULL, " ,\t");
    varAddr = hashCode(varStr, strlen(varStr));
    
    out = atoi(strtok(NULL, " ,\t"));

    /* Send data */
    spiSlaveWrite(varAddr, out);
    
    sprintf(msg_buff, "varAddr = %d\r\n"
                      "out = %d\r\n", varAddr, out);
    serPutString(SER_CONSOLE, msg_buff);
    
    return ERR_SUCCESS;
}


/****************************************************************************/
/*                              Clear commands                              */
/****************************************************************************/
int actClrStubCmd(char* s)
{
    int num = atoi(s);
    
    sprintf(msg_buff, "actClrStubCmd() = %d\r\n", num);
    serPutString(SER_CONSOLE, msg_buff);

    return ERR_SUCCESS;
}

void strUpper(char *s)
{   
    char *iter = s;
    
    while (*iter)
    {
        *iter = toupper(*iter);
        iter++;
    }
}

void strLower(char *s)
{
    char *iter = s;
    
    while (*iter)
    {
        *iter = tolower(*iter);
        iter++;
    }
}

unsigned int findSelectSlot(char* s)
{
    char *typeStr;
    char *addrStr;
    
    const char* delimiters = " ,\t";
    
    int slot = -1;
    unsigned int i;
    unsigned int addr;
    unsigned int addrCount = 0;
    
    typeStr = strtok(s, delimiters);
    strUpper(typeStr);

    addrStr = strtok(NULL, delimiters);
    
    addr = atoi(addrStr);
    
    /* Search for daughtercard with specified type and address */
    for (i = 0; i < NUM_SLOTS; i++)
    {
        if (strcmp(typeStr, slotGetName(i)) == 0)
        {
            addrCount++;
            if (addrCount == addr)
            {
                slot = i;
                break;
            }
        }
    }
    
    /* Error if specified card is not found */
    if (slot == -1)
    {
        sprintf(msg_buff, "Error: Card %s %d not found\r\n", typeStr, addr);
        serPutString(SER_CONSOLE, msg_buff);
        
        return ERR_FAILURE;
    }

    /* Retreive data */
    slotSet(slot);
    
    return ERR_SUCCESS;
}
