uses pushing box to publish to google spreadsheets with a state machine instead of a while loop

Dependents:   DCS_FINAL_CODE

Fork of GSM_PUSHING_BOX_STATE_MACHINE by DCS_TEAM

gsmqueue.cpp

Committer:
DeWayneDennis
Date:
2015-11-06
Revision:
33:2ae9a4eb6433
Parent:
32:424896b5adbe

File content as of revision 33:2ae9a4eb6433:

#include "gsmqueue.h"
#include "GSMLibrary.h"
#include <string.h>

/* gsmqueue.cpp
 * Contains functions to read from the DMA buffer in a queue fashion
 */
 
#define LAST_UNPRINTABLE_CHAR 31

//External variables
extern Serial pc;   //Print data to serial connection with computer
//Serial gsm(D3,D2);  //UART connection with GSM

//Internal variables for a queue (wrap-around implementation)
//Note that the DMA (direct memory access) stores data in this queue. Therefore, QUEUETAIL is incremented
//by the DMA and we only read its value. Our queue's purpose is to read data communicated to us 
//by the GSM without having to consume processor cycles. Unfortunately when we write data to the Serial
//port, the DMA will still write it to the buffer. For this reason, the sendCommand() function counts
//the number of characters we send over UART so we can ignore those characters in the queue.
char buffer[BUFFER_LENGTH];  //Stores the characters in the queue
char* queueHead;    //Queue head - marks where to read from next
char* queueHeadExp; //Expected location of queueHead after gsm.puts() finishes executing


//Public functions ------------------------------------------------------------------------------
//Initialize variables
void queueInit()
{
    //The buffer is initialized in GSMLibrary.cpp
    queueHead = QUEUETAIL;
    queueHeadExp = queueHead;
}

//Send gsm a command (don't forget to flush queue and increment past QUEUETAIL
//by the number of characters send)
void sendCommand(char* sPtr)
{
    flushQueue();       //This "removes" any characters remaining in the queue
    int size = strlen(sPtr);
    if (size > 0 && size <= MAX_SMS_LENGTH)   //Don't send if too long or negative size
    {
        //Send the command
        //gsm.puts(sPtr);
        //The increment part below: Effectively "removes" characters we just sent from the buffer
        // by advancing queueHead by size - 1, or size + 2 
        // size - 1 is because SMS_END_CHAR does not show up on the DMA.
        // size + 2 is for "\n\r" that gets transmitted after we send the command
        if (sPtr[size - 1] == SMS_END_CHAR[0])
        {
            queueHeadExp = incrementIndex(queueHead, size - 1);
            // Don't add "\n" because already included in string (this is when we are sending a message)
        }
        else
        {
            queueHeadExp = incrementIndex(queueHead, size + 2);
            //gsm.puts("\n"); //make there be a \r\n in what we send (this is perfect.)
            //Why not "\r\n"? Previously we had thought the extra \r was added due to \r\n coming
            // through the command line: scanf only removed the \n as whitespace. However, upon
            // further investigation we realized this behavior occurs because the gsm.puts function
            // adds a "\r" at the end of your string, independent of whether it was already present
            // in the string you sent to it. (Except if you only send "\n", in which case it does
            // not follow it with a "\r".) Thus we need to simply add "\n" because the "\r" is 
            // already added by the gsm.puts command.
        }
        //pc.printf("C:%s\r\n", sPtr); //&debug - to know we have sent this message
    }
    else    //Else: error message
    {
        //pc.printf("Error: AT command exceeded maximum length");
        gsm_reset();
    }
}

//Return true if GSM has sent complete response already
//If GSM is idle and queue is not empty, return true
//If the last command was successfully sent, advance queueHead to queueHeadExp
bool queueHasResponse()
{
    if (getGSMIdleBit())
    {   //If tail has advanced past the end of our last sent command, queue has new data
        int dataReceived = queueSize(QUEUETAIL) - queueSize(queueHeadExp);
        if (dataReceived >= 0)
            queueHead = queueHeadExp;   //Upon equality, last command was successfully sent
        return (dataReceived > 0);      //Data received only if characters present beyond "equality" point
    }
    else
        return false;   //Still busy; wait until transmission ended
}

//Find an occurrence of the given string in the buffer.
//If advanceQueueHead is true, advance queueHead just until a matching string is found.
//The given string terminates in NULL (\0)
bool findInQueue(char* str, bool advanceQueueHead)
{
    //Check that string to find is not empty
    if (*str == NULL) return false;
    
    char* head = queueHead;
    while (head != QUEUETAIL)
    {
        //Does the character match the begin char?
        if (*head == *str){
            //Check the remaining characters
            char* sPos = str;
            char* qPos = 0;
            for (qPos = head; qPos != QUEUETAIL; qPos = incrementIndex(qPos)){
                //Compare the next char
                if (*qPos == *sPos)
                {
                    ++sPos; //Increment index (prefix incrementation).
                    if (*sPos == NULL)   //If finished, update head, return true.
                    {
                        head = incrementIndex(qPos);
                        if (advanceQueueHead)
                            queueHead = head;
                        return true;
                    }
                }
                else    //Not equal, so exit for loop and try again at a different location
                    break;
            }
        }
        //Increment queue index for next iteration
        head = incrementIndex(head);
    }
    //We never succeeded, so return false
    if (advanceQueueHead)
        queueHead = head;
    return false;
}

//Parse through characters until first integer is found
//Advance qHead until you reach the next non-numeric character
//Does not read negative integers; returns -1 if unsuccessful
int parseInt()
{
    //Check if queue is empty first
    if (queueHead == QUEUETAIL) return -1;
    
    //Advance to first numeric character
    while (!isNumeric(queueHead))
    {
        queueHead = incrementIndex(queueHead);
        if (queueHead == QUEUETAIL) return -1;
    }
    
    //Continue until first non-numeric character
    int val = 0;
    while (queueHead != QUEUETAIL && isNumeric(queueHead))
    {
        val *= 10;
        val += (int)(*queueHead - '0');
        queueHead = incrementIndex(queueHead);
    }
    return val;
}

//$debug - print queue elements
void printQueue()
{
    char* qPos = queueHead;
    pc.printf("Q:");
    while (qPos != QUEUETAIL)
    {
        //Print the current character
        if (*qPos <= LAST_UNPRINTABLE_CHAR)
        {
            if (*qPos == '\n')
                pc.printf("\\n");
            else if (*qPos == '\r')
                pc.printf("\\r");
            else
                pc.printf("\0%x", *qPos);
        }
        else    
            pc.printf("%C",*qPos);
        
        
        //Increment index
        qPos = incrementIndex(qPos);
    }
}


//Internal functions ---------------------------------------------------------------------------------

//Get the GSM DMA idle bit (if 1, indicates we already received a response)
bool getGSMIdleBit()
{
    return (UART_S1_IDLE_MASK & UART_S1_REG(UART3)) >> UART_S1_IDLE_SHIFT;
}

//Returns true if the character is numeric
bool isNumeric(char* qPos)
{
    return ('0' <= *qPos && *qPos <= '9');
}

//Increment queue position by 1 (Note: this function is only used by gsmqueue.cpp)
char* incrementIndex(char* pointerToIncrement)
{
    if((pointerToIncrement + 1) < (buffer + BUFFER_LENGTH))
        return (pointerToIncrement + 1);
    else
        return buffer;
}

//Increment queue position by n (Note: this function is only used by gsmqueue.cpp)
char* incrementIndex(char* pointerToIncrement, int n)
{
    int initialIndex = pointerToIncrement - buffer;
    int incrementedIndex = (initialIndex + n) % BUFFER_LENGTH;
    return incrementedIndex + buffer;
}

//Get size of the queue from reference point of tail parameter
int queueSize(char* tail)
{
    int headDiff = queueHead - buffer;
    int tailDiff = tail - buffer;
    return (tailDiff + BUFFER_LENGTH - headDiff) % BUFFER_LENGTH;
}

//Clear queue (Note: this function is only used by gsmqueue.cpp)
void flushQueue()
{
    queueHead = QUEUETAIL;   
}