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

Fork of GSM_Library by DCS_TEAM

gsmqueue.cpp

Committer:
es_marble
Date:
2015-04-14
Revision:
27:fe1c7eaf5b88
Parent:
24:7d2ff444d6d8
Child:
29:bc5f53f2922a

File content as of revision 27:fe1c7eaf5b88:

#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

extern Serial pc;
extern Serial gsm;

char buffer[BUFFER_LENGTH];
char* queueHead;
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;   
}
    
//Reset the GSM DMA idle bit to 0
void resetGSMIdleBit()
{
    UART_S1_REG(UART3) &= ~UART_S1_IDLE_MASK;
}