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