More generic and scalable parser
Dependencies: SLCD mbed-rtos mbed
Fork of Serial_IO_test_v6 by
Serial_parser_v1.cpp@4:31207d384db0, 2015-03-23 (annotated)
- Committer:
- scohennm
- Date:
- Mon Mar 23 16:37:23 2015 +0000
- Revision:
- 4:31207d384db0
- Parent:
- serialO_v6.cpp@3:2266158bf72f
NMHU serial command parser program - more generic and scalable
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
scohennm | 2:8196b4cc681b | 1 | #include "mbed.h" |
scohennm | 2:8196b4cc681b | 2 | #include <iostream> |
scohennm | 2:8196b4cc681b | 3 | #include <stdio.h> |
scohennm | 2:8196b4cc681b | 4 | #include <ctype.h> |
scohennm | 2:8196b4cc681b | 5 | #include <string.h> |
scohennm | 2:8196b4cc681b | 6 | #include <locale.h> |
scohennm | 2:8196b4cc681b | 7 | #include "rtos.h" |
scohennm | 2:8196b4cc681b | 8 | #include "SLCD.h" |
scohennm | 3:2266158bf72f | 9 | // Debug printout control |
scohennm | 3:2266158bf72f | 10 | #define PRINTDBUG |
scohennm | 4:31207d384db0 | 11 | #define PROGNAME "Serial_parser_v1 - sc\n\r" |
scohennm | 2:8196b4cc681b | 12 | |
scohennm | 2:8196b4cc681b | 13 | #define LCDLEN 10 |
scohennm | 2:8196b4cc681b | 14 | #define MAXCHAR 4 |
scohennm | 2:8196b4cc681b | 15 | #define ALL8 "8888" |
scohennm | 2:8196b4cc681b | 16 | #define LCDUPDATE 100 //ms |
scohennm | 2:8196b4cc681b | 17 | #define LEDBLINKTIME 300 // ms *** NOTE Change of units *** |
scohennm | 2:8196b4cc681b | 18 | #define SERIALREADTIME 50 //ms |
scohennm | 2:8196b4cc681b | 19 | // ASCII constants |
scohennm | 2:8196b4cc681b | 20 | #define CR '\r' |
scohennm | 3:2266158bf72f | 21 | #define ALLNOTES "CDEFGAB" // Note only 7 unique notes. |
scohennm | 4:31207d384db0 | 22 | #define NONOTE 7 |
scohennm | 4:31207d384db0 | 23 | #define OCTAVELLEN 7 |
scohennm | 4:31207d384db0 | 24 | #define VALIDOCTAVES "45" |
scohennm | 4:31207d384db0 | 25 | #define NOOCTAVE 2 |
scohennm | 4:31207d384db0 | 26 | #define NUMTONES 14 // length of two octaves |
scohennm | 4:31207d384db0 | 27 | #define COMMANDLEN 2 //Max characters in the command |
scohennm | 4:31207d384db0 | 28 | #define NOTOK "NOK" |
scohennm | 4:31207d384db0 | 29 | |
scohennm | 3:2266158bf72f | 30 | #define NOTEOFFSET 1 |
scohennm | 4:31207d384db0 | 31 | #define NOTEINVALID 20 // length of |
scohennm | 2:8196b4cc681b | 32 | |
scohennm | 2:8196b4cc681b | 33 | |
scohennm | 2:8196b4cc681b | 34 | |
scohennm | 4:31207d384db0 | 35 | float diatonicScale[NUMTONES] = {261.63,293.66,329.63,349.23,392.00,440.00,493.88,523.25,587.33,659.25,698.46,783.99,880.00,987.77}; |
scohennm | 2:8196b4cc681b | 36 | |
scohennm | 2:8196b4cc681b | 37 | DigitalOut rLed(LED_RED); |
scohennm | 2:8196b4cc681b | 38 | |
scohennm | 2:8196b4cc681b | 39 | |
scohennm | 2:8196b4cc681b | 40 | Serial pc(USBTX, USBRX); // tx, rx |
scohennm | 2:8196b4cc681b | 41 | SLCD slcd; //define LCD display |
scohennm | 2:8196b4cc681b | 42 | char rxChar; |
scohennm | 2:8196b4cc681b | 43 | char rxString[LCDLEN]; |
scohennm | 2:8196b4cc681b | 44 | string rxRealString; |
scohennm | 4:31207d384db0 | 45 | bool commandReady = false; // This is the flag to even look at the command string |
scohennm | 2:8196b4cc681b | 46 | |
scohennm | 2:8196b4cc681b | 47 | void clearString (char * aString){ |
scohennm | 2:8196b4cc681b | 48 | int i; |
scohennm | 2:8196b4cc681b | 49 | int sSize = sizeof(aString); |
scohennm | 2:8196b4cc681b | 50 | |
scohennm | 2:8196b4cc681b | 51 | for (i=0; i< sSize; i++){ |
scohennm | 2:8196b4cc681b | 52 | aString[i] = NULL; |
scohennm | 2:8196b4cc681b | 53 | } |
scohennm | 2:8196b4cc681b | 54 | return; |
scohennm | 2:8196b4cc681b | 55 | } |
scohennm | 2:8196b4cc681b | 56 | |
scohennm | 2:8196b4cc681b | 57 | |
scohennm | 3:2266158bf72f | 58 | int isNote(char theNote){ //check for valid onte |
scohennm | 3:2266158bf72f | 59 | int noteListLen = sizeof(ALLNOTES); |
scohennm | 3:2266158bf72f | 60 | int pos = NONOTE; |
scohennm | 3:2266158bf72f | 61 | int i; |
scohennm | 3:2266158bf72f | 62 | for (i=0; i<noteListLen; i++){ |
scohennm | 3:2266158bf72f | 63 | if (ALLNOTES[i] == theNote){ |
scohennm | 3:2266158bf72f | 64 | pos = i; |
scohennm | 3:2266158bf72f | 65 | break; |
scohennm | 3:2266158bf72f | 66 | } |
scohennm | 3:2266158bf72f | 67 | } |
scohennm | 3:2266158bf72f | 68 | return (pos); |
scohennm | 3:2266158bf72f | 69 | } |
scohennm | 3:2266158bf72f | 70 | |
scohennm | 4:31207d384db0 | 71 | int isOctave(char theOct){ //check for valid onte |
scohennm | 4:31207d384db0 | 72 | int noteListLen = sizeof(VALIDOCTAVES); |
scohennm | 4:31207d384db0 | 73 | int pos = NOOCTAVE; |
scohennm | 4:31207d384db0 | 74 | int i; |
scohennm | 4:31207d384db0 | 75 | for (i=0; i<noteListLen; i++){ |
scohennm | 4:31207d384db0 | 76 | if (VALIDOCTAVES[i] == theOct){ |
scohennm | 4:31207d384db0 | 77 | pos = i; |
scohennm | 4:31207d384db0 | 78 | break; |
scohennm | 4:31207d384db0 | 79 | } |
scohennm | 4:31207d384db0 | 80 | } |
scohennm | 4:31207d384db0 | 81 | return (pos); |
scohennm | 4:31207d384db0 | 82 | } |
scohennm | 2:8196b4cc681b | 83 | |
scohennm | 4:31207d384db0 | 84 | /* one way to do the parsing ************** |
scohennm | 4:31207d384db0 | 85 | void parseCommand (char * commandChars){ |
scohennm | 4:31207d384db0 | 86 | int charPos = 0; |
scohennm | 4:31207d384db0 | 87 | int noteIndex = 0; // this is the length into the diatonic scale array |
scohennm | 4:31207d384db0 | 88 | bool validCommand = false; |
scohennm | 4:31207d384db0 | 89 | |
scohennm | 4:31207d384db0 | 90 | noteIndex = isNote(commandChars[charPos]); |
scohennm | 4:31207d384db0 | 91 | validCommand = (noteIndex != NONOTE); // First test for a good command string |
scohennm | 4:31207d384db0 | 92 | if (validCommand) { |
scohennm | 4:31207d384db0 | 93 | charPos++; |
scohennm | 4:31207d384db0 | 94 | noteIndex = noteIndex + OCTAVELLEN * isOctave(commandChars[charPos]); |
scohennm | 4:31207d384db0 | 95 | validCommand = (noteIndex < NUMTONES); // Final test for a good string |
scohennm | 4:31207d384db0 | 96 | } |
scohennm | 4:31207d384db0 | 97 | #ifdef PRINTDBUG |
scohennm | 4:31207d384db0 | 98 | if (validCommand) { |
scohennm | 4:31207d384db0 | 99 | pc.printf("%s - IsNote - %4.2f OK\n\r", rxString, diatonicScale[noteIndex]); |
scohennm | 4:31207d384db0 | 100 | sprintf(rxString,"%4.1f", diatonicScale[noteIndex]); // show frequency on LCD |
scohennm | 4:31207d384db0 | 101 | } else { |
scohennm | 4:31207d384db0 | 102 | pc.printf("%s - Not a Note NOK\n\r", rxString); |
scohennm | 4:31207d384db0 | 103 | sprintf(rxString,"%s", NOTOK ); |
scohennm | 4:31207d384db0 | 104 | } |
scohennm | 4:31207d384db0 | 105 | #endif |
scohennm | 4:31207d384db0 | 106 | return; |
scohennm | 4:31207d384db0 | 107 | } |
scohennm | 4:31207d384db0 | 108 | **************** */ |
scohennm | 4:31207d384db0 | 109 | // calculating the valid command |
scohennm | 4:31207d384db0 | 110 | void parseCommand (char * commandChars){ |
scohennm | 4:31207d384db0 | 111 | #define NOTEPOS 0 // index of note and octive tokens |
scohennm | 4:31207d384db0 | 112 | #define OCTPOS 1 |
scohennm | 4:31207d384db0 | 113 | int noteIndex; |
scohennm | 4:31207d384db0 | 114 | int octaveIndex; |
scohennm | 4:31207d384db0 | 115 | int diatonicArrayIndex = 0; // this is the length into the diatonic scale array |
scohennm | 4:31207d384db0 | 116 | bool validCommand = false; |
scohennm | 4:31207d384db0 | 117 | |
scohennm | 4:31207d384db0 | 118 | noteIndex = isNote(commandChars[NOTEPOS]); |
scohennm | 4:31207d384db0 | 119 | octaveIndex = isOctave(commandChars[OCTPOS]); |
scohennm | 4:31207d384db0 | 120 | validCommand = ((noteIndex != NONOTE)&&(octaveIndex != NOOCTAVE)); // test for good command string |
scohennm | 4:31207d384db0 | 121 | #ifdef PRINTDBUG |
scohennm | 4:31207d384db0 | 122 | if (validCommand) { |
scohennm | 4:31207d384db0 | 123 | diatonicArrayIndex = noteIndex + (OCTAVELLEN * octaveIndex); |
scohennm | 4:31207d384db0 | 124 | pc.printf("%s - IsNote - %4.2f OK\n\r", rxString, diatonicScale[diatonicArrayIndex]); |
scohennm | 4:31207d384db0 | 125 | sprintf(rxString,"%4.1f", diatonicScale[diatonicArrayIndex]); // show frequency on LCD |
scohennm | 4:31207d384db0 | 126 | } else { |
scohennm | 4:31207d384db0 | 127 | pc.printf("%s - Not a Note NOK\n\r", rxString); |
scohennm | 4:31207d384db0 | 128 | sprintf(rxString,"%s", NOTOK ); |
scohennm | 4:31207d384db0 | 129 | } |
scohennm | 4:31207d384db0 | 130 | #endif |
scohennm | 4:31207d384db0 | 131 | return; |
scohennm | 4:31207d384db0 | 132 | } |
scohennm | 2:8196b4cc681b | 133 | void LCDMessNoDwell(char *lMess){ |
scohennm | 2:8196b4cc681b | 134 | slcd.Home(); |
scohennm | 2:8196b4cc681b | 135 | slcd.clear(); |
scohennm | 2:8196b4cc681b | 136 | slcd.printf(lMess); |
scohennm | 2:8196b4cc681b | 137 | } |
scohennm | 2:8196b4cc681b | 138 | |
scohennm | 2:8196b4cc681b | 139 | // use "thread" in the name to keep things straight |
scohennm | 2:8196b4cc681b | 140 | // note the use of void constant * args - understand memory resources |
scohennm | 2:8196b4cc681b | 141 | // Thes are "forever loops" |
scohennm | 2:8196b4cc681b | 142 | void LCDdis_thread(void const *args){ |
scohennm | 2:8196b4cc681b | 143 | while(true) { |
scohennm | 2:8196b4cc681b | 144 | LCDMessNoDwell(rxString); |
scohennm | 2:8196b4cc681b | 145 | Thread::wait(LCDUPDATE); |
scohennm | 2:8196b4cc681b | 146 | } |
scohennm | 2:8196b4cc681b | 147 | } |
scohennm | 2:8196b4cc681b | 148 | |
scohennm | 4:31207d384db0 | 149 | |
scohennm | 2:8196b4cc681b | 150 | void serial_thread(void const *args){ |
scohennm | 2:8196b4cc681b | 151 | static int charIndex =0; |
scohennm | 2:8196b4cc681b | 152 | int rxStringLen; |
scohennm | 2:8196b4cc681b | 153 | while(true) { |
scohennm | 2:8196b4cc681b | 154 | if (pc.readable()) { // only read from the serial port if there is a character |
scohennm | 3:2266158bf72f | 155 | rxChar= toupper(pc.getc()); // reading clears the buffer |
scohennm | 4:31207d384db0 | 156 | // noteOK = isNote(rxChar); |
scohennm | 2:8196b4cc681b | 157 | // construct a 4-digit string for the LCD |
scohennm | 2:8196b4cc681b | 158 | // check for carriage return |
scohennm | 2:8196b4cc681b | 159 | if (rxChar == CR) { |
scohennm | 2:8196b4cc681b | 160 | rxRealString.assign(rxString); |
scohennm | 3:2266158bf72f | 161 | rxStringLen = rxRealString.length(); |
scohennm | 4:31207d384db0 | 162 | if(rxStringLen == COMMANDLEN) { // if the input string does not equal the expected |
scohennm | 4:31207d384db0 | 163 | parseCommand(rxString); // command length it's not a good command |
scohennm | 4:31207d384db0 | 164 | } else { |
scohennm | 4:31207d384db0 | 165 | #ifdef PRINTDBUG |
scohennm | 4:31207d384db0 | 166 | pc.printf("%s NOK\n\r", rxString); |
scohennm | 4:31207d384db0 | 167 | sprintf(rxString,"%s", NOTOK ); |
scohennm | 4:31207d384db0 | 168 | #endif |
scohennm | 4:31207d384db0 | 169 | } |
scohennm | 2:8196b4cc681b | 170 | charIndex = 0; // start building string from position zero next time around |
scohennm | 2:8196b4cc681b | 171 | } else { |
scohennm | 2:8196b4cc681b | 172 | if(charIndex == 0) clearString(rxString); |
scohennm | 2:8196b4cc681b | 173 | rxString[charIndex] = rxChar; |
scohennm | 4:31207d384db0 | 174 | rxRealString.assign(rxString); |
scohennm | 3:2266158bf72f | 175 | #ifdef PRINTDBUG |
scohennm | 4:31207d384db0 | 176 | pc.printf("%s\n\r", rxString); // This echo's the new char and prevous up to 4 chars |
scohennm | 4:31207d384db0 | 177 | #endif |
scohennm | 4:31207d384db0 | 178 | charIndex = (charIndex + 1)% (MAXCHAR); // Only allow 4 characters then roll over |
scohennm | 2:8196b4cc681b | 179 | } |
scohennm | 2:8196b4cc681b | 180 | } |
scohennm | 2:8196b4cc681b | 181 | Thread::wait(SERIALREADTIME); |
scohennm | 2:8196b4cc681b | 182 | } |
scohennm | 2:8196b4cc681b | 183 | } |
scohennm | 2:8196b4cc681b | 184 | |
scohennm | 2:8196b4cc681b | 185 | int main() |
scohennm | 2:8196b4cc681b | 186 | { |
scohennm | 2:8196b4cc681b | 187 | |
scohennm | 2:8196b4cc681b | 188 | Thread lthread(LCDdis_thread); |
scohennm | 2:8196b4cc681b | 189 | Thread serthread(serial_thread); |
scohennm | 2:8196b4cc681b | 190 | |
scohennm | 2:8196b4cc681b | 191 | sprintf(rxString,"%s",ALL8); // just put something on the LCD to show it's working |
scohennm | 3:2266158bf72f | 192 | |
scohennm | 3:2266158bf72f | 193 | #ifdef PRINTDBUG |
scohennm | 3:2266158bf72f | 194 | pc.printf(PROGNAME); |
scohennm | 3:2266158bf72f | 195 | #endif |
scohennm | 2:8196b4cc681b | 196 | |
scohennm | 2:8196b4cc681b | 197 | while (true) { |
scohennm | 2:8196b4cc681b | 198 | rLed = !rLed; // toggle led |
scohennm | 2:8196b4cc681b | 199 | Thread::wait(LEDBLINKTIME); |
scohennm | 2:8196b4cc681b | 200 | } |
scohennm | 2:8196b4cc681b | 201 | } |