Treehouse Mbed Team / Mbed 2 deprecated APS_DCM1SL2

Dependencies:   mbed

src/command.cpp

Committer:
mfwic
Date:
2018-12-07
Revision:
11:01dcfb29fbc4
Parent:
10:6c3233b03658
Child:
12:fd1fd1857628

File content as of revision 11:01dcfb29fbc4:

//-------------------------------------------------------------------------------
// 
//  Treehouse Inc.
//  Colorado Springs, Colorado
// 
//  Copyright (c) 2016 by Treehouse Designs Inc. 
// 
//  This code is the property of Treehouse, Inc. (Treehouse)
//  and may not be redistributed in any form without prior written 
//  permission of the copyright holder, Treehouse.
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
// 
//   
//-------------------------------------------------------------------------------
// 
//  REVISION HISTORY:
//  
//   $Author: $
//   $Rev: $
//   $Date: $
//   $URL: $
// 
//-------------------------------------------------------------------------------

#include "mbed.h"
#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "ctype.h"
#include "serial.h"
#include "globals.h"
#include "math.h"
#include "parameters.h"
#include "all_io.h"
//#include "calibrate.h"
#include "boards.h"
#include "menu.h"
#include "command.h"

unsigned int boardsActive;
unsigned int boardMults;
unsigned int commandData;
extern unsigned short my12;

/************* FILE SCOPE VARIABLES ************************/
char setvalue = FALSE;
int endOfCommand = 0;
int commandError = 0;
int menuLevel = LEVEL_MAIN;
int readback = 0;

/************************************************************
* Routine: getDelimiter
* Input:   none
* Output:  none
* Description:
* searches for a delimiter and moves the buffer location
* to be just past it
*
**************************************************************/
void getDelimiter(void)
{
   ++bufloc;
   
   while ((rxbuf[bufloc] != ' ') &&
          (rxbuf[bufloc] != ',') &&
          (rxbuf[bufloc] != '=') &&
          (rxbuf[bufloc] != 0 ))
   {
      bufloc++;
   }
}



/************************************************************
* Routine: gethex
* Input:   hex character
* Returns: hex integer
* Description:
* Converts a hex character to a value
**************************************************************/
char gethex(char val)
{
    int retval;
    switch(val)
    {
        case '0':
            retval = 0;
            break;
        case '1':
            retval = 1;
            break;
        case '2':
            retval = 2;
            break;
        case '3':
            retval = 3;
            break;
        case '4':
            retval = 4;
            break;
        case '5':
            retval = 5;
            break;
        case '6':
            retval = 6;
            break;
        case '7':
            retval = 7;
            break;
        case '8':
            retval = 8;
            break;
        case '9':
            retval = 9;
            break;
        case 'A':
            retval = 10;
            break;
        case 'B':
            retval = 11;
            break;
        case 'C':
            retval = 12;
            break;
        case 'D':
            retval = 13;
            break;
        case 'E':
            retval = 14;
            break;
        case 'F':
            retval = 15;
            break;
        default:
            retval = 0;
            break;

    }
    return retval;
}

/************************************************************
* Routine: showfval
* Input:   setval (GET or SET)
*          value  (float value to display)
* Output:  none
* Description:
* Sends a floating point number (value) over the serial port
* if it is being retrieved (GET)
*
**************************************************************/
void showfval(char setval,float value)
{
    if(!setval)
    {
        sprintf(strbuf," %4.9f",value);
        sendSerial(strbuf);
    }
}

/************************************************************
* Routine: showival
* Input:   setval (GET or SET)
*          value  (integer value to display)
* Output:  none
* Description:
* Sends an integer (value) over the serial port
* if it is being retrieved (GET)
*
**************************************************************/
void showival(char setval, int value)
{
    if(!setval)
    {
        sprintf(strbuf," %i",value);
        sendSerial(strbuf);
    }
}
/************************************************************
* Routine: showcval
* Input:   setval (GET or SET)
*          value  (character to display)
* Output:  none
* Description:
* Sends a character over the serial port
* if it is being retrieved (GET)
*
**************************************************************/
void showcval(char setval, int value)
{
    if(!setval)
    {
        sprintf(strbuf," %c",(char)value);
        sendSerial(strbuf);
    }
}

/************************************************************
* Routine: showlval
* Input:   setval (GET or SET)
*          value  (integer value to display)
* Output:  none
* Description:
* Sends an long (value) over the serial port
* if it is being retrieved (GET)
*
**************************************************************/
void showlval(char setval, long value)
{
    if(!setval)
    {
        sprintf(strbuf," %ld",value);
        sendSerial(strbuf);
    }
}

/************************************************************
* Routine: showuival
* Input:   setval (GET or SET)
*          value  (integer value to display)
* Output:  none
* Description:
* Sends an unsigned int (value) over the serial port
* if it is being retrieved (GET)
*
**************************************************************/
void showuival(char setval, unsigned int value)
{
    if(!setval)
    {
        sprintf(strbuf," %u",value);
        sendSerial(strbuf);
    }
}

/************************************************************
* Routine: showhval
* Input:   setval (GET or SET)
*          value  (hex integeger value to display)
* Output:  none
* Description:
* Sends an integer (value) in hex over the serial port
* if it is being retrieved (GET)
*
**************************************************************/
void showhval(char setval, int value)
{
    if(!setval)
    {
        if(serialStatus.computer)
            sprintf(strbuf," %u",(unsigned int)value);
        else
            sprintf(strbuf," 0x%04x",value);
        sendSerial(strbuf);
    }
}


/************************************************************
* Routine: getival
* Input:   setval (GET or SET)
* Returns: the value if it is being SET or 0 if it is a GET
* Description:
* Gets an integer from the serial port connection.
*
**************************************************************/
int getival(char setval)
{
   if (setval)
   {
        return atoi(&rxbuf[++bufloc]);
   }

   return 0;
}

/************************************************************
* Routine: getcval
* Input:   setval (GET or SET)
* Returns: the value if it is being SET or 0 if it is a GET
* Description:
* Gets an character from the serial port connection.
*
**************************************************************/
int getcval(char setval)
{
    if(setval)
    {
        // skip one space
        ++bufloc;
        // skip spaces and the equals sign
        while((rxbuf[bufloc] == ' ') || (rxbuf[bufloc] == '='))
            bufloc++;
        return rxbuf[bufloc++];
    }
    else
        return 0;

}
/************************************************************
* Routine: getlval
* Input:   setval (GET or SET)
* Returns: the value if it is being SET or 0 if it is a GET
* Description:
* Gets an long from the serial port connection.
*
**************************************************************/
long getlval(char setval)
{
    if(setval)
        return atol(&rxbuf[++bufloc]);
    else
        return 0;

}

/************************************************************
* Routine: getfval
* Input:   setval (GET or SET)
* Returns: the value if it is being SET or 0 if it is a GET
* Description:
* Gets an float from the serial port connection.
*
**************************************************************/
float getfval(char setval)
{
    if(setval)
        return atof(&rxbuf[++bufloc]);
    else
        return 0;
}

/************************************************************
* Routine: validateEntry
* Input:   setval (GET or SET)
*          limlo -- low limit
*          limhi -- high limit
*          address -- address in eeprom to use
* Returns:  0 if entry validates and is written
*           1 if entry fails
* Description:
* Gets or sets a value in eeprom at the address but only
* if it is between the limits will it write the value to
* eeprom
*
**************************************************************/
int validateEntry(char setvalue, float limlo, float limhi, float *address)
{
   float val;

   if (setvalue)
   {
      val =  getfval(SET);

      if ((val >= limlo) && (val <= limhi))
      {
         *address = val;
      }
      else
      {
         showRangeError(0, 0, val);
         return 0;
      }
   }
   else
   {
      val = *address;
      sprintf(strbuf, " %4.3f", val);
      sendSerial(strbuf);
   }

   return 1;
}


/************************************************************
* Routine: validateEntry
* Input:   setval (GET or SET)
*          limlo -- low limit
*          limhi -- high limit
*          address -- address in eeprom to use
*
* Returns:  FALSE if entry fails
*           TRUE  if entry validates and is written
*           
* Description:
* Gets or sets a value in eeprom at the address but only
* if it is between the limits will it write the value to
* eeprom
*
**************************************************************/
int validateInt(char setvalue, int limlo, int limhi, int *address)
{
   float val;
   
   if (setvalue)
   {
      val = getfval(SET);
      
      if ((val >= limlo) && (val <= limhi))
      {
         *address = val;
      }
      else
      {
         showRangeError(1, val, 0);
         return FALSE;
      }
   }
   else
   {
      val = *address;
      sprintf(strbuf, " %4.0f", val);
      sendSerial(strbuf);
   }
   
   return TRUE;
}


/************************************************************
* Routine: parseCommand
* Input:   setvalue (GET or SET), command buffer
* Returns: none
* Description:
* parses a command and gets the commandstring
**************************************************************/
void parseCommand(char setvalue, char *commandString)
{
   int i, endofc;
   char store;

   // Ignore any white space and the optional ';' character before the start of
   // the command string (any ']' character is from the last command so skip that,
   // too)
   while ((isspace(rxbuf[bufloc])) || (rxbuf[bufloc] == ';') || (rxbuf[bufloc] == ']'))
   {
      bufloc++;
      if ((rxbuf[bufloc] == 0x0D) || (rxbuf[bufloc] == 0)) break;
   }

   if (setvalue)
   {
      // We need a value for SET so hitting the end is a problem
      if ((rxbuf[bufloc] == 0) || (rxbuf[bufloc] == 0x0D))
      {
         commandError = 1;
         return;
      }
   }

   // Find the end of the command string
   endofc = bufloc + 1;

   // White space, '[' and '?' all terminate the command string
   while ((!isspace(rxbuf[endofc])) && (rxbuf[endofc] != '[') && (rxbuf[endofc] != '?'))
   {
      endofc++;
      // (As does hitting the end of rxbuf!)
      if ((rxbuf[endofc] == 0x0D) || (rxbuf[endofc] == 0)) break;
   }

   // Save the character that marks the end of the command string
   store = rxbuf[endofc];
   
   // sprintf(strbuf, "store == %c\r\n", store);
   // sendSerial(strbuf);
   
   // Command strings ending in '?' are readbacks
   readback = ((store == '?') ? 1 : 0);
   
   // Set end to null character so string can now be copied
   rxbuf[endofc] = 0;
   
   // Copy the command string into commandString
   char commandStringBuf[80];
   char *tok;
   strcpy(commandStringBuf, &rxbuf[bufloc]);
   if(strstr(commandStringBuf, "=")){
       tok = strtok(commandStringBuf, "=");
       strcpy(commandString, tok);
       tok = strtok(NULL, "=");
       commandData = atoi(tok);
       //if(DEBUG){
       //  sprintf(strbuf, "commandStringBuf= %s, commandData= %d", commandStringBuf, commandData);
       //  sendSerial(strbuf);
       //}
    }
    else{
        strcpy(commandString, commandStringBuf);
    }

   // Convert the command string to all uppercase characters
   for (i = 0; i < strlen(commandString); i++)
   {
      commandString[i] = toupper(commandString[i]);
   }

   // Replace the character we clobbered in rxbuf
   rxbuf[endofc] = store;
   
   // Update bufloc to the end of the command string
   bufloc = endofc;
}

/************************************************************
* Routine: validateChannel
* Input:   channel
* Returns: none
* Description:
* Verifies that the channel number is a valid value between 
* 1 and MAX_BOARDS, setting commandError if the check fails
**************************************************************/
void validateChannel(int channel)
{
   if ((channel < 1) || (channel > MAX_BOARDS))
   {
      sprintf(strbuf, " Invalid channel/board: %d (range is 1 - %d)", channel, MAX_BOARDS);
      sendSerial(strbuf);
      commandError = 1;
   }
}

/************************************************************
* Routine: setPairVariable
* Input:   *avariable,*bvariable
* Returns: none
* Description:
* sets a single channel variable
**************************************************************/
void setPairVariable(float *avariable, float *bvariable, float limitlo, float limithi)
{
   if (!readback)
   {
      if (validateEntry(SET, limitlo, limithi, avariable))
      {
         *bvariable = *avariable;
      }
   }
}

/************************************************************
* Routine: testMenu
* Input:   none
* Returns: none
* Description:
* testMenu
**************************************************************/
void testMenu(void)
{
   int ival;
   int ch, dac;
   //float fval;
   unsigned int data;

   char commandString[80] = { 0 };
   

   commandError = 0;
   parseCommand(GET, commandString);
 
   if (!strcmp(commandString, "LEDS")) // duh do I have to tell you?
   {
      //testLEDs();
      return;
   }
   
   if (!strcmp(commandString, "SELFTEST"))
   {
      if ((rxbuf[bufloc] == 0x0D) || (rxbuf[bufloc] == 0))
      {
         //ival = DEFAULT_SELFTEST_BOARDS;
         ival = 0;
      }
      else
      {
         ival = getival(SET);

         if ((ival < 1) || (ival > MAX_BOARDS))
         {
            sprintf(strbuf, " Invalid number of channels/boards (range is 1 - %d)", MAX_BOARDS);
            sendSerial(strbuf);
            commandError = 1;
            return;
         }
      }
      
      //selfTest(ival);
      return;
   }
      
   if (!strcmp(commandString, "HVEN")) // high voltage enable
   {
      ival = getival(SET);
      //hv_en = ival;
      return;
   }

   if (!strcmp(commandString, "DAC"))
   {
      ch = getival(SET);
      getDelimiter();
      dac = getival(SET);
      getDelimiter();
      data = getival(SET);

      validateChannel(ch);
      if (commandError) return;
      ch--;
      
      //sendData((unsigned int)ch, (unsigned int)dac, data);
      sprintf(strbuf, " ch: %u dac: %u value: %u", ch + 1, dac, data);
      sendSerial(strbuf);
      return;
   }
   
   if (!strcmp(commandString, "DINIT"))
   {
      //initDACs();
      return;
   }

   if (!strcmp(commandString, "FINIT"))
   {
      //formatParameterSector();
      return;
   }

   if (!strcmp(commandString, "CINIT"))
   {
      //initCalParameters();
      sprintf(strbuf, " All calibration parameters set to default values");
      sendSerial(strbuf);
      return;
   }

   if (strcmp(commandString, ""))
   {
      commandError = 1;
   }
}//end void testMenu

unsigned int checkRegisterCompatibility(unsigned int reg)
{
   int i;

   unsigned int boardsEnabled = 0;
   
   for (i = 0; i < MAX_BOARDS; i++)
   {
      //if (ch[i][reg].enabled == 1)
      //{
          // Set the corresponding bit
          boardsEnabled |= (1 << i);
      //}
   }
   
   // Invert the bits because 0 == enabled on the SPI write
   boardsEnabled = ~boardsEnabled;

   return (boardsEnabled ^ boardEnableBits) & 0x000003FF;
}    

/************************************************************
* Routine: doCommand
* Input:   none
* Returns: none
* Description:
* This is the start of the command string.
**************************************************************/
void doCommand(void)
{
   int ival;
   unsigned int boardEnables;

   char commandString[80] = { 0 };

   bufloc = 0;
   commandError = 0;

   parseCommand(GET, commandString);

   if (!strcmp(commandString, "MENU"))
   {
      menuRedraw(NO_PROMPT);
   }
   else if (!strcmp(commandString, "HELP"))
   {
      menuRedraw(NO_PROMPT);
   }
   else if (!strcmp(commandString, "BRDS"))
   // BRDS is used to get/set the wr_out value. 
   // The integer value of boardsActive is used to change wr_out via setBoardEnables(boardsActive).
   // Slots 12 to 0 are activated with the wr_out signals
   // wr_out[13] = slots[12:0]
   {
      
      boardsActive = commandData;
      
      if (readback)
      {
         sprintf(strbuf, " %d", boardsActive);
         sendSerial(strbuf);
      }
      //else if (running == 1)
      //{
      //   sprintf(strbuf, " Parameters may not be updated while running!");
      //   sendSerial(strbuf);
      //}
      else
      {
         if(checkRange(boardsActive, 0, 63) == 1){
            en_out_code = setBoardWeights(boardsActive);
         }else{
            showRangeError(1, boardsActive, 0.0);
         }
      }
   }
   else if (!strcmp(commandString, "MULT"))
   // MULT is used to get/set the en_out value. 
   // The integer value of boardMults is used to change en_out via setBoardWeights(boardMults).
   // en_out are binary weighted signals that activate groups of DC-DC converters on the slot cards.
   // en_out[6] = {en32, en16, en8, en4, en2, en1}
   {
      boardMults = commandData;
      
      if (readback)
      {
         sprintf(strbuf, " %d", boardMults);
         sendSerial(strbuf);
      }
      //else if (running == 1)
      //{
      //   sprintf(strbuf, " Parameters may not be updated while running!");
      //   sendSerial(strbuf);
      //}
      else
      {
         if(checkRange(boardMults, 0, 63) == 1){
            en_out_code = setBoardWeights(boardMults);
         }else{
            showRangeError(1, boardMults, 0.0);
         }
      }
   }
   else if (!strcmp(commandString, "MY12"))
   // MULT is used to get/set the en_out value. 
   // The integer value of boardMults is used to change en_out via setBoardWeights(boardMults).
   // en_out are binary weighted signals that activate groups of DC-DC converters on the slot cards.
   // en_out[6] = {en32, en16, en8, en4, en2, en1}
   {
      my12 = commandData;
      
      //if(DEBUG){
      //  sprintf(strbuf, "my12=%d commandData=%d\r\n", my12, commandData);
      //  sendSerial(strbuf);
      //}
      
      if (readback)
      {
         sprintf(strbuf, " %d", my12);
         sendSerial(strbuf);
      }
   }
   else if (!strcmp(commandString, "ALLOFF"))
   {
      my12 = 0;
      running = FALSE;
      if(DEBUG){
        sprintf(strbuf, "wr_out_code=%d\r\n", wr_out_code);
        sendSerial(strbuf);
      }
   }
   else if (!strcmp(commandString, "ALLON"))
   {
      wr_out_code = setBoardEnables((unsigned int)ALLON);
   }
   else if (!strcmp(commandString, "RUN"))
   {
      // Skip over any white space and the optional '[' character
      while ((isspace(rxbuf[bufloc])) || (rxbuf[bufloc] == '[')) bufloc++;
      
      if(rxbuf[bufloc] == NULL){
         boardsActive = 1;
         startConverter(boardsActive);
      }
      else if (rxbuf[bufloc] == '0')
      //if (rxbuf[bufloc] == '0')
      {
         stopConverter();
         //setDacsToZeroVolts();
      }
      else if ((rxbuf[bufloc] > '0') && (rxbuf[bufloc] < '0' + MAX_BOARDS))
      {
         ival = atoi(&rxbuf[bufloc]);
         //ival--;
         
         if (running == 0)
         {
            boardsActive = ival;
            startConverter(boardsActive);
         }
         else
         {
            // Compare the board enable flags between registers
            boardEnables = checkRegisterCompatibility(ival);
            
            // If board enable flags match, change the register set
            if (boardEnables == 0)
            {
                boardsActive = ival;
            }
            else
            {
               sprintf(strbuf, " Board enable flags do not match (0x%08x)", boardEnables);
               sendSerial(strbuf);
            }
         }
      }
      else
      {
         sprintf(strbuf, " Invalid number of boards (1 - %d)", MAX_BOARDS);
         sendSerial(strbuf);
         commandError = 1;
      }
   }
   else if (!strcmp(commandString, "STOP"))
   {
      stopConverter();
      //hv_en = OFF;
   }
   else if(!strcmp(commandString, "TEST"))
   {
      if (running == 1)
      {
         sprintf(strbuf, " Parameters may not be updated while running!");
         sendSerial(strbuf);
      }
      else
      {
         testMenu();
      }
   }
   else if(!strcmp(commandString, "CAL"))
   {
      if (running == 1)
      {
         sprintf(strbuf, " Parameters may not be updated while running!");
         sendSerial(strbuf);
         commandError = 1;
      }

      if (!commandError){
          raw = TRUE;
          menuRedraw(NO_PROMPT);
      }
    }
   else if(!strcmp(commandString, "UNCAL"))
   {
      if (running == 1)
      {
         sprintf(strbuf, " Parameters may not be updated while running!");
         sendSerial(strbuf);
         commandError = 1;
      }

      if (!commandError){
          raw = FALSE;
          menuRedraw(NO_PROMPT);
      }
    }
   else 
   { 
      if (strcmp(commandString, ""))
      {
         commandError = 1;
      }
   }

   if (commandError)
   {
      sendSerial(" !");
   }

   //sendCRLF();
   menuPrompt(MENU_DCM1);
}

/************************************************************
* Routine: processCommand
* Input:   none
* Returns: none
* Description:
* This is the main serial communications routine.  Everything
* starts here as soon as a command is avaiable for processing.
**************************************************************/
void processCommand(void) 
{
   if (!serialStatus.command && !serialStatus.repeat)
   {
      return;
   }

   doCommand(); // if not computer (i.e. terminal) you can do the command as well

   bufloc = 0;
   rxbuf[bufloc] = 0;
   
   serialStatus.computer = FALSE;
   serialStatus.command  = FALSE;
   
   //sendSerial("didCommand\r\n");
}

/************************************************************
* Routine: waitCommand
* Input:   none
* Returns: none
* Description:
**************************************************************/
bool waitCommand(void) 
{
   if (!serialStatus.command && !serialStatus.repeat)
   {
      return TRUE;
   }
   
   serialStatus.computer = FALSE;
   serialStatus.command  = FALSE;
   
   return FALSE;
}

// Verify that the same boards are enabled in both the current register and
// the specified register