uses pushing box to publish to google spreadsheets with a state machine instead of a while loop
Fork of GSM_PUSHING_BOX_STATE_MACHINE by
gsmqueue.cpp@27:fe1c7eaf5b88, 2015-04-14 (annotated)
- Committer:
- es_marble
- Date:
- Tue Apr 14 04:11:57 2015 +0000
- Revision:
- 27:fe1c7eaf5b88
- Parent:
- 24:7d2ff444d6d8
- Child:
- 29:bc5f53f2922a
done
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
danilob | 0:41904adca656 | 1 | #include "gsmqueue.h" |
es_marble | 24:7d2ff444d6d8 | 2 | #include "GSMLibrary.h" |
es_marble | 24:7d2ff444d6d8 | 3 | #include <string.h> |
es_marble | 24:7d2ff444d6d8 | 4 | |
es_marble | 24:7d2ff444d6d8 | 5 | /* gsmqueue.cpp |
danilob | 0:41904adca656 | 6 | * Contains functions to read from the DMA buffer in a queue fashion |
danilob | 0:41904adca656 | 7 | */ |
es_marble | 24:7d2ff444d6d8 | 8 | |
es_marble | 24:7d2ff444d6d8 | 9 | #define LAST_UNPRINTABLE_CHAR 31 |
es_marble | 24:7d2ff444d6d8 | 10 | |
es_marble | 3:dac922a18af6 | 11 | extern Serial pc; |
es_marble | 24:7d2ff444d6d8 | 12 | extern Serial gsm; |
danilob | 0:41904adca656 | 13 | |
danilob | 0:41904adca656 | 14 | char buffer[BUFFER_LENGTH]; |
danilob | 0:41904adca656 | 15 | char* queueHead; |
es_marble | 24:7d2ff444d6d8 | 16 | char* queueHeadExp; //Expected location of queueHead after gsm.puts() finishes executing |
danilob | 0:41904adca656 | 17 | |
danilob | 0:41904adca656 | 18 | |
es_marble | 24:7d2ff444d6d8 | 19 | //Public functions ------------------------------------------------------------------------------ |
es_marble | 24:7d2ff444d6d8 | 20 | //Initialize variables |
danilob | 0:41904adca656 | 21 | void queueInit() |
danilob | 0:41904adca656 | 22 | { |
es_marble | 24:7d2ff444d6d8 | 23 | //The buffer is initialized in GSMLibrary.cpp |
danilob | 0:41904adca656 | 24 | queueHead = QUEUETAIL; |
es_marble | 24:7d2ff444d6d8 | 25 | queueHeadExp = queueHead; |
es_marble | 24:7d2ff444d6d8 | 26 | } |
es_marble | 24:7d2ff444d6d8 | 27 | |
es_marble | 24:7d2ff444d6d8 | 28 | //Send gsm a command (don't forget to flush queue and increment past QUEUETAIL |
es_marble | 24:7d2ff444d6d8 | 29 | //by the number of characters send) |
es_marble | 24:7d2ff444d6d8 | 30 | void sendCommand(char* sPtr) |
es_marble | 24:7d2ff444d6d8 | 31 | { |
es_marble | 24:7d2ff444d6d8 | 32 | flushQueue(); //This "removes" any characters remaining in the queue |
es_marble | 24:7d2ff444d6d8 | 33 | int size = strlen(sPtr); |
es_marble | 24:7d2ff444d6d8 | 34 | if (size > 0 && size <= MAX_SMS_LENGTH) //Don't send if too long or negative size |
es_marble | 24:7d2ff444d6d8 | 35 | { |
es_marble | 24:7d2ff444d6d8 | 36 | //Send the command |
es_marble | 24:7d2ff444d6d8 | 37 | gsm.puts(sPtr); |
es_marble | 24:7d2ff444d6d8 | 38 | //The increment part below: Effectively "removes" characters we just sent from the buffer |
es_marble | 24:7d2ff444d6d8 | 39 | // by advancing queueHead by size - 1, or size + 2 |
es_marble | 24:7d2ff444d6d8 | 40 | // size - 1 is because SMS_END_CHAR does not show up on the DMA. |
es_marble | 24:7d2ff444d6d8 | 41 | // size + 2 is for "\n\r" that gets transmitted after we send the command |
es_marble | 24:7d2ff444d6d8 | 42 | if (sPtr[size - 1] == SMS_END_CHAR[0]) |
es_marble | 24:7d2ff444d6d8 | 43 | { |
es_marble | 24:7d2ff444d6d8 | 44 | queueHeadExp = incrementIndex(queueHead, size - 1); |
es_marble | 24:7d2ff444d6d8 | 45 | // Don't add "\n" because already included in string (this is when we are sending a message) |
es_marble | 24:7d2ff444d6d8 | 46 | } |
es_marble | 24:7d2ff444d6d8 | 47 | else |
es_marble | 24:7d2ff444d6d8 | 48 | { |
es_marble | 24:7d2ff444d6d8 | 49 | queueHeadExp = incrementIndex(queueHead, size + 2); |
es_marble | 24:7d2ff444d6d8 | 50 | gsm.puts("\n"); //make there be a \r\n in what we send (this is perfect.) |
es_marble | 24:7d2ff444d6d8 | 51 | //Why not "\r\n"? Previously we had thought the extra \r was added due to \r\n coming |
es_marble | 24:7d2ff444d6d8 | 52 | // through the command line: scanf only removed the \n as whitespace. However, upon |
es_marble | 24:7d2ff444d6d8 | 53 | // further investigation we realized this behavior occurs because the gsm.puts function |
es_marble | 24:7d2ff444d6d8 | 54 | // adds a "\r" at the end of your string, independent of whether it was already present |
es_marble | 24:7d2ff444d6d8 | 55 | // in the string you sent to it. (Except if you only send "\n", in which case it does |
es_marble | 24:7d2ff444d6d8 | 56 | // not follow it with a "\r".) Thus we need to simply add "\n" because the "\r" is |
es_marble | 24:7d2ff444d6d8 | 57 | // already added by the gsm.puts command. |
es_marble | 24:7d2ff444d6d8 | 58 | } |
es_marble | 27:fe1c7eaf5b88 | 59 | //pc.printf("C:%s\r\n", sPtr); //&debug - to know we have sent this message |
es_marble | 24:7d2ff444d6d8 | 60 | } |
es_marble | 24:7d2ff444d6d8 | 61 | else //Else: error message |
es_marble | 24:7d2ff444d6d8 | 62 | { |
es_marble | 27:fe1c7eaf5b88 | 63 | //pc.printf("Error: AT command exceeded maximum length"); |
es_marble | 24:7d2ff444d6d8 | 64 | gsm_reset(); |
es_marble | 24:7d2ff444d6d8 | 65 | } |
es_marble | 24:7d2ff444d6d8 | 66 | } |
es_marble | 24:7d2ff444d6d8 | 67 | |
es_marble | 24:7d2ff444d6d8 | 68 | //Return true if GSM has sent complete response already |
es_marble | 24:7d2ff444d6d8 | 69 | //If GSM is idle and queue is not empty, return true |
es_marble | 24:7d2ff444d6d8 | 70 | //If the last command was successfully sent, advance queueHead to queueHeadExp |
es_marble | 24:7d2ff444d6d8 | 71 | bool queueHasResponse() |
es_marble | 24:7d2ff444d6d8 | 72 | { |
es_marble | 24:7d2ff444d6d8 | 73 | if (getGSMIdleBit()) |
es_marble | 24:7d2ff444d6d8 | 74 | { //If tail has advanced past the end of our last sent command, queue has new data |
es_marble | 24:7d2ff444d6d8 | 75 | int dataReceived = queueSize(QUEUETAIL) - queueSize(queueHeadExp); |
es_marble | 24:7d2ff444d6d8 | 76 | if (dataReceived >= 0) |
es_marble | 24:7d2ff444d6d8 | 77 | queueHead = queueHeadExp; //Upon equality, last command was successfully sent |
es_marble | 24:7d2ff444d6d8 | 78 | return (dataReceived > 0); //Data received only if characters present beyond "equality" point |
es_marble | 24:7d2ff444d6d8 | 79 | } |
es_marble | 24:7d2ff444d6d8 | 80 | else |
es_marble | 24:7d2ff444d6d8 | 81 | return false; //Still busy; wait until transmission ended |
danilob | 0:41904adca656 | 82 | } |
danilob | 0:41904adca656 | 83 | |
danilob | 0:41904adca656 | 84 | //Find an occurrence of the given string in the buffer. |
es_marble | 24:7d2ff444d6d8 | 85 | //If advanceQueueHead is true, advance queueHead just until a matching string is found. |
es_marble | 3:dac922a18af6 | 86 | //The given string terminates in NULL (\0) |
es_marble | 24:7d2ff444d6d8 | 87 | bool findInQueue(char* str, bool advanceQueueHead) |
danilob | 0:41904adca656 | 88 | { |
es_marble | 3:dac922a18af6 | 89 | //Check that string to find is not empty |
es_marble | 3:dac922a18af6 | 90 | if (*str == NULL) return false; |
es_marble | 3:dac922a18af6 | 91 | |
es_marble | 24:7d2ff444d6d8 | 92 | char* head = queueHead; |
es_marble | 24:7d2ff444d6d8 | 93 | while (head != QUEUETAIL) |
danilob | 0:41904adca656 | 94 | { |
danilob | 0:41904adca656 | 95 | //Does the character match the begin char? |
es_marble | 24:7d2ff444d6d8 | 96 | if (*head == *str){ |
danilob | 0:41904adca656 | 97 | //Check the remaining characters |
danilob | 13:9ac5ff131214 | 98 | char* sPos = str; |
es_marble | 3:dac922a18af6 | 99 | char* qPos = 0; |
es_marble | 24:7d2ff444d6d8 | 100 | for (qPos = head; qPos != QUEUETAIL; qPos = incrementIndex(qPos)){ |
danilob | 0:41904adca656 | 101 | //Compare the next char |
danilob | 0:41904adca656 | 102 | if (*qPos == *sPos) |
danilob | 0:41904adca656 | 103 | { |
es_marble | 3:dac922a18af6 | 104 | ++sPos; //Increment index (prefix incrementation). |
es_marble | 24:7d2ff444d6d8 | 105 | if (*sPos == NULL) //If finished, update head, return true. |
es_marble | 8:1d8623e25fa6 | 106 | { |
es_marble | 24:7d2ff444d6d8 | 107 | head = incrementIndex(qPos); |
es_marble | 24:7d2ff444d6d8 | 108 | if (advanceQueueHead) |
es_marble | 24:7d2ff444d6d8 | 109 | queueHead = head; |
danilob | 0:41904adca656 | 110 | return true; |
es_marble | 8:1d8623e25fa6 | 111 | } |
danilob | 0:41904adca656 | 112 | } |
danilob | 0:41904adca656 | 113 | else //Not equal, so exit for loop and try again at a different location |
danilob | 0:41904adca656 | 114 | break; |
danilob | 0:41904adca656 | 115 | } |
danilob | 0:41904adca656 | 116 | } |
danilob | 0:41904adca656 | 117 | //Increment queue index for next iteration |
es_marble | 24:7d2ff444d6d8 | 118 | head = incrementIndex(head); |
danilob | 0:41904adca656 | 119 | } |
es_marble | 24:7d2ff444d6d8 | 120 | //We never succeeded, so return false |
es_marble | 24:7d2ff444d6d8 | 121 | if (advanceQueueHead) |
es_marble | 24:7d2ff444d6d8 | 122 | queueHead = head; |
danilob | 0:41904adca656 | 123 | return false; |
danilob | 0:41904adca656 | 124 | } |
danilob | 0:41904adca656 | 125 | |
danilob | 0:41904adca656 | 126 | //Parse through characters until first integer is found |
es_marble | 1:c1458b739eb6 | 127 | //Advance qHead until you reach the next non-numeric character |
es_marble | 3:dac922a18af6 | 128 | //Does not read negative integers; returns -1 if unsuccessful |
danilob | 0:41904adca656 | 129 | int parseInt() |
danilob | 0:41904adca656 | 130 | { |
danilob | 13:9ac5ff131214 | 131 | //Check if queue is empty first |
danilob | 13:9ac5ff131214 | 132 | if (queueHead == QUEUETAIL) return -1; |
danilob | 13:9ac5ff131214 | 133 | |
es_marble | 3:dac922a18af6 | 134 | //Advance to first numeric character |
danilob | 13:9ac5ff131214 | 135 | while (!isNumeric(queueHead)) |
danilob | 0:41904adca656 | 136 | { |
danilob | 13:9ac5ff131214 | 137 | queueHead = incrementIndex(queueHead); |
danilob | 13:9ac5ff131214 | 138 | if (queueHead == QUEUETAIL) return -1; |
es_marble | 3:dac922a18af6 | 139 | } |
es_marble | 3:dac922a18af6 | 140 | |
es_marble | 3:dac922a18af6 | 141 | //Continue until first non-numeric character |
es_marble | 3:dac922a18af6 | 142 | int val = 0; |
danilob | 13:9ac5ff131214 | 143 | while (queueHead != QUEUETAIL && isNumeric(queueHead)) |
es_marble | 3:dac922a18af6 | 144 | { |
es_marble | 3:dac922a18af6 | 145 | val *= 10; |
danilob | 13:9ac5ff131214 | 146 | val += (int)(*queueHead - '0'); |
danilob | 13:9ac5ff131214 | 147 | queueHead = incrementIndex(queueHead); |
danilob | 0:41904adca656 | 148 | } |
es_marble | 3:dac922a18af6 | 149 | return val; |
es_marble | 1:c1458b739eb6 | 150 | } |
es_marble | 1:c1458b739eb6 | 151 | |
es_marble | 24:7d2ff444d6d8 | 152 | //$debug - print queue elements |
es_marble | 24:7d2ff444d6d8 | 153 | void printQueue() |
es_marble | 24:7d2ff444d6d8 | 154 | { |
es_marble | 24:7d2ff444d6d8 | 155 | char* qPos = queueHead; |
es_marble | 24:7d2ff444d6d8 | 156 | pc.printf("Q:"); |
es_marble | 24:7d2ff444d6d8 | 157 | while (qPos != QUEUETAIL) |
es_marble | 24:7d2ff444d6d8 | 158 | { |
es_marble | 24:7d2ff444d6d8 | 159 | //Print the current character |
es_marble | 24:7d2ff444d6d8 | 160 | if (*qPos <= LAST_UNPRINTABLE_CHAR) |
es_marble | 24:7d2ff444d6d8 | 161 | { |
es_marble | 24:7d2ff444d6d8 | 162 | if (*qPos == '\n') |
es_marble | 24:7d2ff444d6d8 | 163 | pc.printf("\\n"); |
es_marble | 24:7d2ff444d6d8 | 164 | else if (*qPos == '\r') |
es_marble | 24:7d2ff444d6d8 | 165 | pc.printf("\\r"); |
es_marble | 24:7d2ff444d6d8 | 166 | else |
es_marble | 24:7d2ff444d6d8 | 167 | pc.printf("\0%x", *qPos); |
es_marble | 24:7d2ff444d6d8 | 168 | } |
es_marble | 24:7d2ff444d6d8 | 169 | else |
es_marble | 24:7d2ff444d6d8 | 170 | pc.printf("%C",*qPos); |
es_marble | 24:7d2ff444d6d8 | 171 | |
es_marble | 24:7d2ff444d6d8 | 172 | |
es_marble | 24:7d2ff444d6d8 | 173 | //Increment index |
es_marble | 24:7d2ff444d6d8 | 174 | qPos = incrementIndex(qPos); |
es_marble | 24:7d2ff444d6d8 | 175 | } |
es_marble | 24:7d2ff444d6d8 | 176 | } |
es_marble | 24:7d2ff444d6d8 | 177 | |
es_marble | 24:7d2ff444d6d8 | 178 | |
es_marble | 24:7d2ff444d6d8 | 179 | //Internal functions --------------------------------------------------------------------------------- |
es_marble | 24:7d2ff444d6d8 | 180 | |
es_marble | 24:7d2ff444d6d8 | 181 | //Get the GSM DMA idle bit (if 1, indicates we already received a response) |
es_marble | 24:7d2ff444d6d8 | 182 | bool getGSMIdleBit() |
es_marble | 24:7d2ff444d6d8 | 183 | { |
es_marble | 24:7d2ff444d6d8 | 184 | return (UART_S1_IDLE_MASK & UART_S1_REG(UART3)) >> UART_S1_IDLE_SHIFT; |
es_marble | 24:7d2ff444d6d8 | 185 | } |
es_marble | 24:7d2ff444d6d8 | 186 | |
es_marble | 3:dac922a18af6 | 187 | //Returns true if the character is numeric |
es_marble | 3:dac922a18af6 | 188 | bool isNumeric(char* qPos) |
es_marble | 3:dac922a18af6 | 189 | { |
danilob | 13:9ac5ff131214 | 190 | return ('0' <= *qPos && *qPos <= '9'); |
es_marble | 3:dac922a18af6 | 191 | } |
es_marble | 24:7d2ff444d6d8 | 192 | |
es_marble | 24:7d2ff444d6d8 | 193 | //Increment queue position by 1 (Note: this function is only used by gsmqueue.cpp) |
es_marble | 24:7d2ff444d6d8 | 194 | char* incrementIndex(char* pointerToIncrement) |
es_marble | 24:7d2ff444d6d8 | 195 | { |
es_marble | 24:7d2ff444d6d8 | 196 | if((pointerToIncrement + 1) < (buffer + BUFFER_LENGTH)) |
es_marble | 24:7d2ff444d6d8 | 197 | return (pointerToIncrement + 1); |
es_marble | 24:7d2ff444d6d8 | 198 | else |
es_marble | 24:7d2ff444d6d8 | 199 | return buffer; |
es_marble | 24:7d2ff444d6d8 | 200 | } |
es_marble | 24:7d2ff444d6d8 | 201 | |
es_marble | 24:7d2ff444d6d8 | 202 | //Increment queue position by n (Note: this function is only used by gsmqueue.cpp) |
es_marble | 24:7d2ff444d6d8 | 203 | char* incrementIndex(char* pointerToIncrement, int n) |
es_marble | 24:7d2ff444d6d8 | 204 | { |
es_marble | 24:7d2ff444d6d8 | 205 | int initialIndex = pointerToIncrement - buffer; |
es_marble | 24:7d2ff444d6d8 | 206 | int incrementedIndex = (initialIndex + n) % BUFFER_LENGTH; |
es_marble | 24:7d2ff444d6d8 | 207 | return incrementedIndex + buffer; |
es_marble | 24:7d2ff444d6d8 | 208 | } |
es_marble | 24:7d2ff444d6d8 | 209 | |
es_marble | 24:7d2ff444d6d8 | 210 | //Get size of the queue from reference point of tail parameter |
es_marble | 24:7d2ff444d6d8 | 211 | int queueSize(char* tail) |
es_marble | 24:7d2ff444d6d8 | 212 | { |
es_marble | 24:7d2ff444d6d8 | 213 | int headDiff = queueHead - buffer; |
es_marble | 24:7d2ff444d6d8 | 214 | int tailDiff = tail - buffer; |
es_marble | 24:7d2ff444d6d8 | 215 | return (tailDiff + BUFFER_LENGTH - headDiff) % BUFFER_LENGTH; |
es_marble | 24:7d2ff444d6d8 | 216 | } |
es_marble | 24:7d2ff444d6d8 | 217 | |
es_marble | 24:7d2ff444d6d8 | 218 | //Clear queue (Note: this function is only used by gsmqueue.cpp) |
es_marble | 24:7d2ff444d6d8 | 219 | void flushQueue() |
es_marble | 24:7d2ff444d6d8 | 220 | { |
es_marble | 24:7d2ff444d6d8 | 221 | queueHead = QUEUETAIL; |
es_marble | 24:7d2ff444d6d8 | 222 | } |
es_marble | 3:dac922a18af6 | 223 | |
es_marble | 1:c1458b739eb6 | 224 | //Reset the GSM DMA idle bit to 0 |
es_marble | 1:c1458b739eb6 | 225 | void resetGSMIdleBit() |
es_marble | 1:c1458b739eb6 | 226 | { |
es_marble | 1:c1458b739eb6 | 227 | UART_S1_REG(UART3) &= ~UART_S1_IDLE_MASK; |
es_marble | 1:c1458b739eb6 | 228 | } |
es_marble | 1:c1458b739eb6 | 229 |