MP3-capable chair with sensor-embedded weight scale.
Dependencies: HysteresisIn LCD SDFileSystem VS1053 mbed
main.cpp@0:0451ba2f1062, 2013-12-20 (annotated)
- Committer:
- kayekss
- Date:
- Fri Dec 20 21:35:07 2013 +0000
- Revision:
- 0:0451ba2f1062
First commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
kayekss | 0:0451ba2f1062 | 1 | #include <stdio.h> |
kayekss | 0:0451ba2f1062 | 2 | #include "mbed.h" |
kayekss | 0:0451ba2f1062 | 3 | #include "defs.h" |
kayekss | 0:0451ba2f1062 | 4 | #include "pinalias.h" |
kayekss | 0:0451ba2f1062 | 5 | #include "HysteresisIn.h" |
kayekss | 0:0451ba2f1062 | 6 | #include "SDFileSystem.h" |
kayekss | 0:0451ba2f1062 | 7 | #include "VS1053.h" |
kayekss | 0:0451ba2f1062 | 8 | #include "LCD.h" |
kayekss | 0:0451ba2f1062 | 9 | |
kayekss | 0:0451ba2f1062 | 10 | SDFileSystem sd(/*MOSI*/ D11, /*MISO*/ D12, /*SCK*/ D13, /*CS*/ D10, "sd"); |
kayekss | 0:0451ba2f1062 | 11 | VS1053 mp3(/*MOSI*/ D11, /*MISO*/ D12, /*SCK*/ D13, |
kayekss | 0:0451ba2f1062 | 12 | /*CS*/ D9, /*BSYNC*/ D8, /*DREQ*/ D7, /*RST*/ D6, /*SPI freq.*/ 6000000); |
kayekss | 0:0451ba2f1062 | 13 | HysteresisIn sens3(A3, HIGH_TO_LOW, LOW_TO_HIGH, 1); // Photo sensor #3 (Outer) |
kayekss | 0:0451ba2f1062 | 14 | HysteresisIn sens2(A2, HIGH_TO_LOW, LOW_TO_HIGH, 1); // Photo sensor #2 |
kayekss | 0:0451ba2f1062 | 15 | HysteresisIn sens1(A1, HIGH_TO_LOW, LOW_TO_HIGH, 1); // Photo sensor #1 |
kayekss | 0:0451ba2f1062 | 16 | HysteresisIn sens0(A0, HIGH_TO_LOW, LOW_TO_HIGH, 1); // Photo sensor #0 (Inner) |
kayekss | 0:0451ba2f1062 | 17 | LCD lcd(/*SDA*/ D107, /*SCL*/ D106, /*RESET*/ D105, /*Backlight*/ NC, |
kayekss | 0:0451ba2f1062 | 18 | /*Contrast*/ 40); |
kayekss | 0:0451ba2f1062 | 19 | BusOut led(/*Red*/ P3, /*Yellow*/ P4, /*Green*/ P5, /*Blue*/ P6, /*White*/ P7); |
kayekss | 0:0451ba2f1062 | 20 | Ticker tic; |
kayekss | 0:0451ba2f1062 | 21 | |
kayekss | 0:0451ba2f1062 | 22 | const char *fileNameList[] = { |
kayekss | 0:0451ba2f1062 | 23 | "", |
kayekss | 0:0451ba2f1062 | 24 | "/sd/Track1.mp3", |
kayekss | 0:0451ba2f1062 | 25 | "/sd/Track2.mp3", |
kayekss | 0:0451ba2f1062 | 26 | "/sd/Track3.mp3", |
kayekss | 0:0451ba2f1062 | 27 | "/sd/Track4.mp3" |
kayekss | 0:0451ba2f1062 | 28 | }; |
kayekss | 0:0451ba2f1062 | 29 | |
kayekss | 0:0451ba2f1062 | 30 | volatile State state = READY; |
kayekss | 0:0451ba2f1062 | 31 | volatile Request request = NONE; |
kayekss | 0:0451ba2f1062 | 32 | |
kayekss | 0:0451ba2f1062 | 33 | /** Setups and initializations */ |
kayekss | 0:0451ba2f1062 | 34 | void setup(void) { |
kayekss | 0:0451ba2f1062 | 35 | // Initialize VS1053 |
kayekss | 0:0451ba2f1062 | 36 | mp3.hardwareReset(); |
kayekss | 0:0451ba2f1062 | 37 | mp3.clockUp(); |
kayekss | 0:0451ba2f1062 | 38 | wait(0.1); |
kayekss | 0:0451ba2f1062 | 39 | |
kayekss | 0:0451ba2f1062 | 40 | // Setup LCD |
kayekss | 0:0451ba2f1062 | 41 | lcd.reset(); |
kayekss | 0:0451ba2f1062 | 42 | lcd.cls(); |
kayekss | 0:0451ba2f1062 | 43 | |
kayekss | 0:0451ba2f1062 | 44 | // Initialize LCD |
kayekss | 0:0451ba2f1062 | 45 | led = 0x00; |
kayekss | 0:0451ba2f1062 | 46 | } |
kayekss | 0:0451ba2f1062 | 47 | |
kayekss | 0:0451ba2f1062 | 48 | /** Read voltages from photo sensor pins and detect weightscale point code */ |
kayekss | 0:0451ba2f1062 | 49 | int readPhotoSensors(void) { |
kayekss | 0:0451ba2f1062 | 50 | uint8_t bitPattern; |
kayekss | 0:0451ba2f1062 | 51 | |
kayekss | 0:0451ba2f1062 | 52 | // Read all photo sensor inputs |
kayekss | 0:0451ba2f1062 | 53 | bitPattern = sens3.read() << 3 |
kayekss | 0:0451ba2f1062 | 54 | | sens2.read() << 2 |
kayekss | 0:0451ba2f1062 | 55 | | sens1.read() << 1 |
kayekss | 0:0451ba2f1062 | 56 | | sens0.read(); |
kayekss | 0:0451ba2f1062 | 57 | |
kayekss | 0:0451ba2f1062 | 58 | switch (bitPattern) { |
kayekss | 0:0451ba2f1062 | 59 | // 1 when open, 0 when shut |
kayekss | 0:0451ba2f1062 | 60 | // Higher bit is on outer side |
kayekss | 0:0451ba2f1062 | 61 | case 0xf: // 1111: no load |
kayekss | 0:0451ba2f1062 | 62 | return 0; |
kayekss | 0:0451ba2f1062 | 63 | case 0xe: // 1110: slight load |
kayekss | 0:0451ba2f1062 | 64 | return 1; |
kayekss | 0:0451ba2f1062 | 65 | case 0xc: // 1100 |
kayekss | 0:0451ba2f1062 | 66 | return 2; |
kayekss | 0:0451ba2f1062 | 67 | case 0x8: // 1000 |
kayekss | 0:0451ba2f1062 | 68 | return 3; |
kayekss | 0:0451ba2f1062 | 69 | case 0x0: // 0000: heavy load |
kayekss | 0:0451ba2f1062 | 70 | return 4; |
kayekss | 0:0451ba2f1062 | 71 | default: // Other than expectation: erroneous pattern |
kayekss | 0:0451ba2f1062 | 72 | return -1; |
kayekss | 0:0451ba2f1062 | 73 | } |
kayekss | 0:0451ba2f1062 | 74 | } |
kayekss | 0:0451ba2f1062 | 75 | |
kayekss | 0:0451ba2f1062 | 76 | /** Poll/sample weightscale inputs and issue requests */ |
kayekss | 0:0451ba2f1062 | 77 | void pollAndRequest() { |
kayekss | 0:0451ba2f1062 | 78 | const char* stateNameList[] = { |
kayekss | 0:0451ba2f1062 | 79 | "STOPPING", // -2 |
kayekss | 0:0451ba2f1062 | 80 | "CANCELING", // -1 |
kayekss | 0:0451ba2f1062 | 81 | "READY", // 0 |
kayekss | 0:0451ba2f1062 | 82 | "PLAYING1", // 1 |
kayekss | 0:0451ba2f1062 | 83 | "PLAYING2", // 2 |
kayekss | 0:0451ba2f1062 | 84 | "PLAYING3", // 3 |
kayekss | 0:0451ba2f1062 | 85 | "PLAYING4" // 4 |
kayekss | 0:0451ba2f1062 | 86 | }; |
kayekss | 0:0451ba2f1062 | 87 | const uint8_t ledPatternList[] = { |
kayekss | 0:0451ba2f1062 | 88 | 0x10, // -1 STOP_REQUEST W---- |
kayekss | 0:0451ba2f1062 | 89 | 0x00, // 0 NONE ----- |
kayekss | 0:0451ba2f1062 | 90 | 0x01, // 1 PLAY1_REQUEST ----R |
kayekss | 0:0451ba2f1062 | 91 | 0x02, // 2 PLAY2_REQUEST ---Y- |
kayekss | 0:0451ba2f1062 | 92 | 0x04, // 3 PLAY3_REQUEST --G-- |
kayekss | 0:0451ba2f1062 | 93 | 0x08 // 4 PLAY4_REQUEST -B--- |
kayekss | 0:0451ba2f1062 | 94 | }; |
kayekss | 0:0451ba2f1062 | 95 | int code; |
kayekss | 0:0451ba2f1062 | 96 | static int codePrev = 0; |
kayekss | 0:0451ba2f1062 | 97 | static uint8_t holdTimes = 0; |
kayekss | 0:0451ba2f1062 | 98 | |
kayekss | 0:0451ba2f1062 | 99 | // Get weightscale point code by reading photo sensors |
kayekss | 0:0451ba2f1062 | 100 | code = readPhotoSensors(); |
kayekss | 0:0451ba2f1062 | 101 | |
kayekss | 0:0451ba2f1062 | 102 | // Count the times that the given code persists |
kayekss | 0:0451ba2f1062 | 103 | if (code == codePrev && code != -1) { |
kayekss | 0:0451ba2f1062 | 104 | if (holdTimes < 99) { |
kayekss | 0:0451ba2f1062 | 105 | holdTimes++; |
kayekss | 0:0451ba2f1062 | 106 | } |
kayekss | 0:0451ba2f1062 | 107 | } else { |
kayekss | 0:0451ba2f1062 | 108 | holdTimes = 0; |
kayekss | 0:0451ba2f1062 | 109 | } |
kayekss | 0:0451ba2f1062 | 110 | lcd.locate(0, 0); |
kayekss | 0:0451ba2f1062 | 111 | lcd.printf("%-15s", stateNameList[state + 2]); |
kayekss | 0:0451ba2f1062 | 112 | lcd.locate(0, 1); |
kayekss | 0:0451ba2f1062 | 113 | lcd.printf("ps=%2d times=%2d", code, holdTimes); |
kayekss | 0:0451ba2f1062 | 114 | |
kayekss | 0:0451ba2f1062 | 115 | // Once the point is stable enough, make a request |
kayekss | 0:0451ba2f1062 | 116 | if (holdTimes == SETTLING_COUNT) { |
kayekss | 0:0451ba2f1062 | 117 | if (code == 0) { |
kayekss | 0:0451ba2f1062 | 118 | // Stable no load: stop request |
kayekss | 0:0451ba2f1062 | 119 | request = STOP_REQUEST; |
kayekss | 0:0451ba2f1062 | 120 | } else { |
kayekss | 0:0451ba2f1062 | 121 | // Certain stable load: play request 1..4 |
kayekss | 0:0451ba2f1062 | 122 | // Ignore cases while playing the same track |
kayekss | 0:0451ba2f1062 | 123 | if (state != code) { |
kayekss | 0:0451ba2f1062 | 124 | request = (Request) code; |
kayekss | 0:0451ba2f1062 | 125 | } |
kayekss | 0:0451ba2f1062 | 126 | } |
kayekss | 0:0451ba2f1062 | 127 | } |
kayekss | 0:0451ba2f1062 | 128 | |
kayekss | 0:0451ba2f1062 | 129 | // Set LED as the request |
kayekss | 0:0451ba2f1062 | 130 | led = ledPatternList[request + 1]; |
kayekss | 0:0451ba2f1062 | 131 | |
kayekss | 0:0451ba2f1062 | 132 | // Preserve this time's code |
kayekss | 0:0451ba2f1062 | 133 | codePrev = code; |
kayekss | 0:0451ba2f1062 | 134 | } |
kayekss | 0:0451ba2f1062 | 135 | |
kayekss | 0:0451ba2f1062 | 136 | /** Player control in accordance with requests */ |
kayekss | 0:0451ba2f1062 | 137 | void controlTrack() { |
kayekss | 0:0451ba2f1062 | 138 | static FILE *fp = NULL; |
kayekss | 0:0451ba2f1062 | 139 | size_t sizeRead = 0; |
kayekss | 0:0451ba2f1062 | 140 | uint8_t buf[BLOCK_SIZE]; |
kayekss | 0:0451ba2f1062 | 141 | static size_t totalSizeSent = 0; |
kayekss | 0:0451ba2f1062 | 142 | |
kayekss | 0:0451ba2f1062 | 143 | switch (state) { |
kayekss | 0:0451ba2f1062 | 144 | case READY: |
kayekss | 0:0451ba2f1062 | 145 | switch (request) { |
kayekss | 0:0451ba2f1062 | 146 | case STOP_REQUEST: |
kayekss | 0:0451ba2f1062 | 147 | // Clear stop request |
kayekss | 0:0451ba2f1062 | 148 | request = NONE; |
kayekss | 0:0451ba2f1062 | 149 | break; |
kayekss | 0:0451ba2f1062 | 150 | case PLAY1_REQUEST: case PLAY2_REQUEST: case PLAY3_REQUEST: case PLAY4_REQUEST: |
kayekss | 0:0451ba2f1062 | 151 | fp = fopen(fileNameList[request], "rb"); |
kayekss | 0:0451ba2f1062 | 152 | if (fp) { |
kayekss | 0:0451ba2f1062 | 153 | totalSizeSent = 0; |
kayekss | 0:0451ba2f1062 | 154 | state = (State) request; |
kayekss | 0:0451ba2f1062 | 155 | lcd.locate(15, 0); |
kayekss | 0:0451ba2f1062 | 156 | lcd.printf("*"); |
kayekss | 0:0451ba2f1062 | 157 | } |
kayekss | 0:0451ba2f1062 | 158 | // Clear play request |
kayekss | 0:0451ba2f1062 | 159 | request = NONE; |
kayekss | 0:0451ba2f1062 | 160 | break; |
kayekss | 0:0451ba2f1062 | 161 | default: |
kayekss | 0:0451ba2f1062 | 162 | break; |
kayekss | 0:0451ba2f1062 | 163 | } |
kayekss | 0:0451ba2f1062 | 164 | break; |
kayekss | 0:0451ba2f1062 | 165 | case PLAYING1: case PLAYING2: case PLAYING3: case PLAYING4: |
kayekss | 0:0451ba2f1062 | 166 | if (request == NONE) { |
kayekss | 0:0451ba2f1062 | 167 | if (feof(fp)) { |
kayekss | 0:0451ba2f1062 | 168 | // Close the track |
kayekss | 0:0451ba2f1062 | 169 | fclose(fp); |
kayekss | 0:0451ba2f1062 | 170 | lcd.locate(15, 0); |
kayekss | 0:0451ba2f1062 | 171 | lcd.printf(" "); |
kayekss | 0:0451ba2f1062 | 172 | |
kayekss | 0:0451ba2f1062 | 173 | // Invoke play request again |
kayekss | 0:0451ba2f1062 | 174 | request = (Request) state; |
kayekss | 0:0451ba2f1062 | 175 | state = READY; |
kayekss | 0:0451ba2f1062 | 176 | } else { |
kayekss | 0:0451ba2f1062 | 177 | sizeRead = fread(buf, sizeof(char), BLOCK_SIZE, fp); |
kayekss | 0:0451ba2f1062 | 178 | totalSizeSent += mp3.sendDataBlock(buf, sizeRead); |
kayekss | 0:0451ba2f1062 | 179 | } |
kayekss | 0:0451ba2f1062 | 180 | } else { |
kayekss | 0:0451ba2f1062 | 181 | // Cancel current track when something's requested |
kayekss | 0:0451ba2f1062 | 182 | fclose(fp); |
kayekss | 0:0451ba2f1062 | 183 | lcd.locate(15, 0); |
kayekss | 0:0451ba2f1062 | 184 | lcd.printf(" "); |
kayekss | 0:0451ba2f1062 | 185 | state = CANCELING; |
kayekss | 0:0451ba2f1062 | 186 | } |
kayekss | 0:0451ba2f1062 | 187 | break; |
kayekss | 0:0451ba2f1062 | 188 | case CANCELING: |
kayekss | 0:0451ba2f1062 | 189 | if (mp3.sendCancel()) { |
kayekss | 0:0451ba2f1062 | 190 | state = STOPPING; |
kayekss | 0:0451ba2f1062 | 191 | } |
kayekss | 0:0451ba2f1062 | 192 | break; |
kayekss | 0:0451ba2f1062 | 193 | case STOPPING: |
kayekss | 0:0451ba2f1062 | 194 | if (mp3.stop()) { |
kayekss | 0:0451ba2f1062 | 195 | state = READY; |
kayekss | 0:0451ba2f1062 | 196 | } |
kayekss | 0:0451ba2f1062 | 197 | if (request == STOP_REQUEST) { |
kayekss | 0:0451ba2f1062 | 198 | // Clear stop request |
kayekss | 0:0451ba2f1062 | 199 | request = NONE; |
kayekss | 0:0451ba2f1062 | 200 | } |
kayekss | 0:0451ba2f1062 | 201 | break; |
kayekss | 0:0451ba2f1062 | 202 | default: |
kayekss | 0:0451ba2f1062 | 203 | break; |
kayekss | 0:0451ba2f1062 | 204 | } |
kayekss | 0:0451ba2f1062 | 205 | } |
kayekss | 0:0451ba2f1062 | 206 | |
kayekss | 0:0451ba2f1062 | 207 | /** Main routine */ |
kayekss | 0:0451ba2f1062 | 208 | int main(void) { |
kayekss | 0:0451ba2f1062 | 209 | FILE *fpTest = NULL; |
kayekss | 0:0451ba2f1062 | 210 | time_t secBuild; |
kayekss | 0:0451ba2f1062 | 211 | struct tm *tmBuild; |
kayekss | 0:0451ba2f1062 | 212 | char sbuf[10]; |
kayekss | 0:0451ba2f1062 | 213 | bool sdTestResult = 0x00; |
kayekss | 0:0451ba2f1062 | 214 | |
kayekss | 0:0451ba2f1062 | 215 | setup(); |
kayekss | 0:0451ba2f1062 | 216 | |
kayekss | 0:0451ba2f1062 | 217 | // Print build timestamp (in JST) |
kayekss | 0:0451ba2f1062 | 218 | secBuild = MBED_BUILD_TIMESTAMP + 9 * 60 * 60; |
kayekss | 0:0451ba2f1062 | 219 | tmBuild = localtime(&secBuild); |
kayekss | 0:0451ba2f1062 | 220 | |
kayekss | 0:0451ba2f1062 | 221 | strftime(sbuf, 10, "%Y-%m-%d", tmBuild); |
kayekss | 0:0451ba2f1062 | 222 | lcd.locate(0, 0); |
kayekss | 0:0451ba2f1062 | 223 | lcd.printf("Build %8s", sbuf); |
kayekss | 0:0451ba2f1062 | 224 | wait(0.0); |
kayekss | 0:0451ba2f1062 | 225 | strftime(sbuf, 10, "%H:%M:%S", tmBuild); |
kayekss | 0:0451ba2f1062 | 226 | lcd.locate(0, 1); |
kayekss | 0:0451ba2f1062 | 227 | lcd.printf(" T%8s", sbuf); |
kayekss | 0:0451ba2f1062 | 228 | wait(2.0); |
kayekss | 0:0451ba2f1062 | 229 | |
kayekss | 0:0451ba2f1062 | 230 | // SD card test |
kayekss | 0:0451ba2f1062 | 231 | lcd.cls(); |
kayekss | 0:0451ba2f1062 | 232 | lcd.locate(0, 0); |
kayekss | 0:0451ba2f1062 | 233 | lcd.printf("No memory cards "); |
kayekss | 0:0451ba2f1062 | 234 | wait(0.0); |
kayekss | 0:0451ba2f1062 | 235 | lcd.locate(0, 0); |
kayekss | 0:0451ba2f1062 | 236 | lcd.printf("Track / / / Ok"); |
kayekss | 0:0451ba2f1062 | 237 | for (uint8_t i = 1; i <= 4; i++) { |
kayekss | 0:0451ba2f1062 | 238 | fpTest = fopen(fileNameList[i], "rb"); |
kayekss | 0:0451ba2f1062 | 239 | if (fpTest) { |
kayekss | 0:0451ba2f1062 | 240 | lcd.locate(2 * i + 4, 0); |
kayekss | 0:0451ba2f1062 | 241 | lcd.printf("%d", i); |
kayekss | 0:0451ba2f1062 | 242 | fclose(fpTest); |
kayekss | 0:0451ba2f1062 | 243 | } else { |
kayekss | 0:0451ba2f1062 | 244 | sdTestResult |= 0x01 << (i - 1); |
kayekss | 0:0451ba2f1062 | 245 | } |
kayekss | 0:0451ba2f1062 | 246 | } |
kayekss | 0:0451ba2f1062 | 247 | lcd.locate(0, 1); |
kayekss | 0:0451ba2f1062 | 248 | if (sdTestResult == 0x00) { |
kayekss | 0:0451ba2f1062 | 249 | lcd.printf("SD Test Pass "); |
kayekss | 0:0451ba2f1062 | 250 | } else { |
kayekss | 0:0451ba2f1062 | 251 | lcd.printf("SD Test Fail "); |
kayekss | 0:0451ba2f1062 | 252 | while (1) { |
kayekss | 0:0451ba2f1062 | 253 | led = sdTestResult; |
kayekss | 0:0451ba2f1062 | 254 | wait(0.5); |
kayekss | 0:0451ba2f1062 | 255 | led = 0x00; |
kayekss | 0:0451ba2f1062 | 256 | wait(0.5); |
kayekss | 0:0451ba2f1062 | 257 | } |
kayekss | 0:0451ba2f1062 | 258 | } |
kayekss | 0:0451ba2f1062 | 259 | wait(1.0); |
kayekss | 0:0451ba2f1062 | 260 | lcd.cls(); |
kayekss | 0:0451ba2f1062 | 261 | |
kayekss | 0:0451ba2f1062 | 262 | // Set Ticker interrupt routine |
kayekss | 0:0451ba2f1062 | 263 | tic.attach(&pollAndRequest, POLL_INTERVAL_SEC); |
kayekss | 0:0451ba2f1062 | 264 | |
kayekss | 0:0451ba2f1062 | 265 | // Main loop |
kayekss | 0:0451ba2f1062 | 266 | while (1) { |
kayekss | 0:0451ba2f1062 | 267 | controlTrack(); |
kayekss | 0:0451ba2f1062 | 268 | } |
kayekss | 0:0451ba2f1062 | 269 | } |