MP3-capable chair with sensor-embedded weight scale.

Dependencies:   ACM1602 SDFileSystem VS1053 mbed ClockControl PowerControl

Committer:
kayekss
Date:
Sat Mar 29 16:19:42 2014 +0000
Revision:
2:844bedc9dc63
Parent:
1:ef257d63d970
Child:
3:64f0ba828a2e
Fixed interrupt interval time.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kayekss 0:d9789f57fd9d 1 #include <stdio.h>
kayekss 0:d9789f57fd9d 2 #include "mbed.h"
kayekss 0:d9789f57fd9d 3 #include "defs.h"
kayekss 0:d9789f57fd9d 4 #include "HysteresisIn.h"
kayekss 0:d9789f57fd9d 5 #include "SDFileSystem.h"
kayekss 0:d9789f57fd9d 6 #include "VS1053.h"
kayekss 0:d9789f57fd9d 7 #include "ACM1602.h"
kayekss 1:ef257d63d970 8 #include "ClockControl.h"
kayekss 1:ef257d63d970 9 #include "EthernetPowerControl.h"
kayekss 1:ef257d63d970 10 #include "PowerControl.h"
kayekss 0:d9789f57fd9d 11
kayekss 2:844bedc9dc63 12 // Pin settings for mbed LPC1768
kayekss 1:ef257d63d970 13 SDFileSystem sd(/*MOSI*/ p11, /*MISO*/ p12, /*SCK*/ p13, /*CS*/ p21, /*Mountpoint*/ "sd");
kayekss 1:ef257d63d970 14 VS1053 mp3(/*MOSI*/ p11, /*MISO*/ p12, /*SCK*/ p13,
kayekss 1:ef257d63d970 15 /*CS*/ p22, /*BSYNC*/ p23, /*DREQ*/ p24, /*RST*/ p25, /*SPI freq.*/ 4000000);
kayekss 1:ef257d63d970 16 HysteresisIn sens3(p17, H_TO_L_THRES, L_TO_H_THRES, 1); // Photo sensor #3 (Outer)
kayekss 1:ef257d63d970 17 HysteresisIn sens2(p18, H_TO_L_THRES, L_TO_H_THRES, 1); // Photo sensor #2
kayekss 1:ef257d63d970 18 HysteresisIn sens1(p19, H_TO_L_THRES, L_TO_H_THRES, 1); // Photo sensor #1
kayekss 1:ef257d63d970 19 HysteresisIn sens0(p20, H_TO_L_THRES, L_TO_H_THRES, 1); // Photo sensor #0 (Inner)
kayekss 1:ef257d63d970 20 ACM1602 lcd(/*SDA*/ p9, /*SCL*/ p10, /*Address*/ 0xa0);
kayekss 1:ef257d63d970 21 DigitalOut audioPower(p30);
kayekss 1:ef257d63d970 22 DigitalIn test3(p17);
kayekss 1:ef257d63d970 23 DigitalIn test2(p18);
kayekss 1:ef257d63d970 24 DigitalIn test1(p19);
kayekss 1:ef257d63d970 25 DigitalIn test0(p20);
kayekss 1:ef257d63d970 26 DigitalIn inputSelector(p8);
kayekss 2:844bedc9dc63 27 // Set unused pins to input when using the LPCXpresso board
kayekss 1:ef257d63d970 28 BusIn __dummy(xp21, xp22, xp23, xp24, xp49, xp50, xp51, xp52, xp53);
kayekss 0:d9789f57fd9d 29 Ticker tic;
kayekss 1:ef257d63d970 30 bool inputFrom;
kayekss 1:ef257d63d970 31 size_t totalSizeSent;
kayekss 0:d9789f57fd9d 32
kayekss 0:d9789f57fd9d 33 const char *fileNameList[] = {
kayekss 0:d9789f57fd9d 34 "/sd/Track1.mp3",
kayekss 0:d9789f57fd9d 35 "/sd/Track2.mp3",
kayekss 0:d9789f57fd9d 36 "/sd/Track3.mp3",
kayekss 0:d9789f57fd9d 37 "/sd/Track4.mp3"
kayekss 0:d9789f57fd9d 38 };
kayekss 0:d9789f57fd9d 39
kayekss 0:d9789f57fd9d 40 volatile State state = READY;
kayekss 0:d9789f57fd9d 41 volatile Request request = NONE;
kayekss 0:d9789f57fd9d 42
kayekss 0:d9789f57fd9d 43 /** Setup and initializations */
kayekss 0:d9789f57fd9d 44 void setup(void) {
kayekss 2:844bedc9dc63 45 // Reduce system clock frequency to 48 MHz
kayekss 1:ef257d63d970 46 setSystemFrequency(0x3, 0x1, 6, 1);
kayekss 1:ef257d63d970 47
kayekss 1:ef257d63d970 48 // Power down Ethernet PHY
kayekss 1:ef257d63d970 49 PHY_PowerDown();
kayekss 1:ef257d63d970 50
kayekss 1:ef257d63d970 51 // Set pull-up mode
kayekss 1:ef257d63d970 52 inputSelector.mode(PullUp);
kayekss 1:ef257d63d970 53 test3.mode(PullUp);
kayekss 1:ef257d63d970 54 test2.mode(PullUp);
kayekss 1:ef257d63d970 55 test1.mode(PullUp);
kayekss 1:ef257d63d970 56 test0.mode(PullUp);
kayekss 1:ef257d63d970 57 wait(0.1);
kayekss 1:ef257d63d970 58
kayekss 0:d9789f57fd9d 59 // Initialize VS1053
kayekss 0:d9789f57fd9d 60 mp3.hardwareReset();
kayekss 0:d9789f57fd9d 61 mp3.clockUp();
kayekss 0:d9789f57fd9d 62 wait(0.1);
kayekss 0:d9789f57fd9d 63
kayekss 0:d9789f57fd9d 64 // Initialize power supply for audio amplifier circuit
kayekss 0:d9789f57fd9d 65 audioPower = 0;
kayekss 0:d9789f57fd9d 66
kayekss 0:d9789f57fd9d 67 // Setup LCD
kayekss 0:d9789f57fd9d 68 lcd.init();
kayekss 0:d9789f57fd9d 69
kayekss 1:ef257d63d970 70 // Read input selector
kayekss 1:ef257d63d970 71 inputFrom = inputSelector;
kayekss 0:d9789f57fd9d 72 }
kayekss 0:d9789f57fd9d 73
kayekss 0:d9789f57fd9d 74 /** Read voltages from photo sensor pins and detect weightscale point code */
kayekss 0:d9789f57fd9d 75 int readPhotoSensors(void) {
kayekss 0:d9789f57fd9d 76 uint8_t bitPattern;
kayekss 0:d9789f57fd9d 77
kayekss 0:d9789f57fd9d 78 // Read all photo sensor inputs
kayekss 1:ef257d63d970 79 if (inputFrom) {
kayekss 1:ef257d63d970 80 bitPattern = (test3 << 3)
kayekss 1:ef257d63d970 81 | (test2 << 2)
kayekss 1:ef257d63d970 82 | (test1 << 1)
kayekss 1:ef257d63d970 83 | test0;
kayekss 1:ef257d63d970 84 } else {
kayekss 1:ef257d63d970 85 bitPattern = (sens3.read() << 3)
kayekss 1:ef257d63d970 86 | (sens2.read() << 2)
kayekss 1:ef257d63d970 87 | (sens1.read() << 1)
kayekss 1:ef257d63d970 88 | sens0.read();
kayekss 1:ef257d63d970 89 }
kayekss 0:d9789f57fd9d 90
kayekss 0:d9789f57fd9d 91 switch (bitPattern) {
kayekss 0:d9789f57fd9d 92 // 1 when open, 0 when shut
kayekss 0:d9789f57fd9d 93 // Higher bit is on outer side
kayekss 0:d9789f57fd9d 94 case 0xf: // 1111: no load
kayekss 0:d9789f57fd9d 95 return 0;
kayekss 0:d9789f57fd9d 96 case 0xe: // 1110: slight load
kayekss 0:d9789f57fd9d 97 return 1;
kayekss 0:d9789f57fd9d 98 case 0xc: // 1100
kayekss 0:d9789f57fd9d 99 return 2;
kayekss 0:d9789f57fd9d 100 case 0x8: // 1000
kayekss 0:d9789f57fd9d 101 return 3;
kayekss 0:d9789f57fd9d 102 case 0x0: // 0000: heavy load
kayekss 0:d9789f57fd9d 103 return 4;
kayekss 0:d9789f57fd9d 104 default: // Other than expectation: erroneous pattern
kayekss 0:d9789f57fd9d 105 return -1;
kayekss 0:d9789f57fd9d 106 }
kayekss 0:d9789f57fd9d 107 }
kayekss 0:d9789f57fd9d 108
kayekss 0:d9789f57fd9d 109 /** Poll/sample weightscale inputs and issue requests */
kayekss 0:d9789f57fd9d 110 void pollAndRequest() {
kayekss 0:d9789f57fd9d 111 const char* stateNameList[] = {
kayekss 0:d9789f57fd9d 112 "STOPPING", // -2
kayekss 0:d9789f57fd9d 113 "CANCELING", // -1
kayekss 0:d9789f57fd9d 114 "READY", // 0
kayekss 0:d9789f57fd9d 115 "PLAYING1", // 1
kayekss 0:d9789f57fd9d 116 "PLAYING2", // 2
kayekss 0:d9789f57fd9d 117 "PLAYING3", // 3
kayekss 0:d9789f57fd9d 118 "PLAYING4" // 4
kayekss 0:d9789f57fd9d 119 };
kayekss 0:d9789f57fd9d 120 int code;
kayekss 0:d9789f57fd9d 121 static int codePrev = 0;
kayekss 0:d9789f57fd9d 122 static uint8_t holdTimes = 0;
kayekss 0:d9789f57fd9d 123
kayekss 0:d9789f57fd9d 124 // Get weightscale point code by reading photo sensors
kayekss 0:d9789f57fd9d 125 code = readPhotoSensors();
kayekss 0:d9789f57fd9d 126
kayekss 0:d9789f57fd9d 127 // Count the times that the given code persists
kayekss 0:d9789f57fd9d 128 if (code == codePrev && code != -1) {
kayekss 0:d9789f57fd9d 129 if (holdTimes < 99) {
kayekss 0:d9789f57fd9d 130 holdTimes++;
kayekss 0:d9789f57fd9d 131 }
kayekss 0:d9789f57fd9d 132 } else {
kayekss 0:d9789f57fd9d 133 holdTimes = 0;
kayekss 0:d9789f57fd9d 134 }
kayekss 1:ef257d63d970 135
kayekss 1:ef257d63d970 136 // Print status to LCD:
kayekss 1:ef257d63d970 137 // current state, photo sensor inputs, hold count,
kayekss 1:ef257d63d970 138 // file size sent to VS1053
kayekss 0:d9789f57fd9d 139 lcd.locate(0, 0);
kayekss 1:ef257d63d970 140 lcd.printf("%-9s in=%2d", stateNameList[state + 2], code);
kayekss 0:d9789f57fd9d 141 lcd.locate(0, 1);
kayekss 1:ef257d63d970 142 lcd.printf("x%2d ", holdTimes);
kayekss 1:ef257d63d970 143 switch (state) {
kayekss 1:ef257d63d970 144 case PLAYING1: case PLAYING2: case PLAYING3: case PLAYING4:
kayekss 1:ef257d63d970 145 if (totalSizeSent >= 1000000) {
kayekss 1:ef257d63d970 146 lcd.printf("%9.2f MB", totalSizeSent / 1048576.0);
kayekss 1:ef257d63d970 147 } else if (totalSizeSent >= 1000) {
kayekss 1:ef257d63d970 148 lcd.printf("%9.2f KB", totalSizeSent / 1024.0);
kayekss 1:ef257d63d970 149 } else {
kayekss 1:ef257d63d970 150 lcd.printf("%6d bytes", totalSizeSent);
kayekss 1:ef257d63d970 151 }
kayekss 1:ef257d63d970 152 break;
kayekss 1:ef257d63d970 153 default:
kayekss 1:ef257d63d970 154 lcd.printf(" <No File>");
kayekss 1:ef257d63d970 155 break;
kayekss 1:ef257d63d970 156 }
kayekss 0:d9789f57fd9d 157
kayekss 0:d9789f57fd9d 158 // Once the point is stable enough, make a request
kayekss 0:d9789f57fd9d 159 if (holdTimes == SETTLING_COUNT) {
kayekss 0:d9789f57fd9d 160 if (code == 0) {
kayekss 0:d9789f57fd9d 161 // Stable no load: stop request
kayekss 0:d9789f57fd9d 162 request = STOP_REQUEST;
kayekss 0:d9789f57fd9d 163 } else {
kayekss 0:d9789f57fd9d 164 // Certain stable load: play request 1..4
kayekss 0:d9789f57fd9d 165 // Ignore cases while playing the same track
kayekss 0:d9789f57fd9d 166 if (state != code) {
kayekss 0:d9789f57fd9d 167 request = (Request) code;
kayekss 0:d9789f57fd9d 168 }
kayekss 0:d9789f57fd9d 169 }
kayekss 0:d9789f57fd9d 170 }
kayekss 0:d9789f57fd9d 171
kayekss 0:d9789f57fd9d 172 // Preserve this time's code
kayekss 0:d9789f57fd9d 173 codePrev = code;
kayekss 0:d9789f57fd9d 174 }
kayekss 0:d9789f57fd9d 175
kayekss 0:d9789f57fd9d 176 /** Player control in accordance with requests */
kayekss 0:d9789f57fd9d 177 void controlTrack() {
kayekss 1:ef257d63d970 178 static FILE *fp = NULL;
kayekss 1:ef257d63d970 179 size_t sizeRead = 0;
kayekss 1:ef257d63d970 180 uint8_t buf[BLOCK_SIZE];
kayekss 0:d9789f57fd9d 181
kayekss 0:d9789f57fd9d 182 switch (state) {
kayekss 0:d9789f57fd9d 183 case READY:
kayekss 0:d9789f57fd9d 184 switch (request) {
kayekss 0:d9789f57fd9d 185 case STOP_REQUEST:
kayekss 0:d9789f57fd9d 186 // Clear stop request
kayekss 0:d9789f57fd9d 187 request = NONE;
kayekss 0:d9789f57fd9d 188 break;
kayekss 1:ef257d63d970 189 case PLAY1_REQUEST: case PLAY2_REQUEST: case PLAY3_REQUEST: case PLAY4_REQUEST:
kayekss 0:d9789f57fd9d 190 fp = fopen(fileNameList[request - 1], "rb");
kayekss 0:d9789f57fd9d 191 if (fp) {
kayekss 1:ef257d63d970 192 clearerr(fp);
kayekss 1:ef257d63d970 193
kayekss 0:d9789f57fd9d 194 // Power supply on
kayekss 0:d9789f57fd9d 195 audioPower = 1;
kayekss 0:d9789f57fd9d 196
kayekss 0:d9789f57fd9d 197 totalSizeSent = 0;
kayekss 0:d9789f57fd9d 198 state = (State) request;
kayekss 0:d9789f57fd9d 199 }
kayekss 0:d9789f57fd9d 200 // Clear play request
kayekss 0:d9789f57fd9d 201 request = NONE;
kayekss 0:d9789f57fd9d 202 break;
kayekss 0:d9789f57fd9d 203 default:
kayekss 0:d9789f57fd9d 204 break;
kayekss 0:d9789f57fd9d 205 }
kayekss 0:d9789f57fd9d 206 break;
kayekss 0:d9789f57fd9d 207 case PLAYING1: case PLAYING2: case PLAYING3: case PLAYING4:
kayekss 0:d9789f57fd9d 208 if (request == NONE) {
kayekss 1:ef257d63d970 209 // Continue playback
kayekss 1:ef257d63d970 210 if (feof(fp)) {
kayekss 1:ef257d63d970 211 // Close when the track reaches the end
kayekss 0:d9789f57fd9d 212 fclose(fp);
kayekss 1:ef257d63d970 213 fp = NULL;
kayekss 0:d9789f57fd9d 214
kayekss 0:d9789f57fd9d 215 // Invoke play request again
kayekss 0:d9789f57fd9d 216 request = (Request) state;
kayekss 0:d9789f57fd9d 217 state = READY;
kayekss 1:ef257d63d970 218 } else {
kayekss 1:ef257d63d970 219 sizeRead = fread(buf, sizeof(char), BLOCK_SIZE, fp);
kayekss 1:ef257d63d970 220 totalSizeSent += mp3.sendDataBlock(buf, sizeRead);
kayekss 0:d9789f57fd9d 221 }
kayekss 0:d9789f57fd9d 222 } else {
kayekss 0:d9789f57fd9d 223 // Cancel current track when something's requested
kayekss 0:d9789f57fd9d 224 fclose(fp);
kayekss 1:ef257d63d970 225 fp = NULL;
kayekss 0:d9789f57fd9d 226 state = CANCELING;
kayekss 0:d9789f57fd9d 227 }
kayekss 0:d9789f57fd9d 228 break;
kayekss 0:d9789f57fd9d 229 case CANCELING:
kayekss 0:d9789f57fd9d 230 if (mp3.sendCancel()) {
kayekss 0:d9789f57fd9d 231 state = STOPPING;
kayekss 0:d9789f57fd9d 232 }
kayekss 0:d9789f57fd9d 233 break;
kayekss 0:d9789f57fd9d 234 case STOPPING:
kayekss 0:d9789f57fd9d 235 if (mp3.stop()) {
kayekss 0:d9789f57fd9d 236 state = READY;
kayekss 0:d9789f57fd9d 237 }
kayekss 0:d9789f57fd9d 238 if (request == STOP_REQUEST) {
kayekss 0:d9789f57fd9d 239 // Clear stop request
kayekss 0:d9789f57fd9d 240 request = NONE;
kayekss 0:d9789f57fd9d 241 // Power supply off
kayekss 0:d9789f57fd9d 242 audioPower = 0;
kayekss 0:d9789f57fd9d 243 }
kayekss 0:d9789f57fd9d 244 break;
kayekss 0:d9789f57fd9d 245 default:
kayekss 0:d9789f57fd9d 246 break;
kayekss 0:d9789f57fd9d 247 }
kayekss 0:d9789f57fd9d 248 }
kayekss 0:d9789f57fd9d 249
kayekss 0:d9789f57fd9d 250 /** Print build timestamp (in JST) */
kayekss 0:d9789f57fd9d 251 void printTimestamp() {
kayekss 0:d9789f57fd9d 252 time_t secBuild;
kayekss 0:d9789f57fd9d 253 struct tm *tmBuild;
kayekss 0:d9789f57fd9d 254 char sbuf[11];
kayekss 0:d9789f57fd9d 255
kayekss 0:d9789f57fd9d 256 secBuild = MBED_BUILD_TIMESTAMP + 9 * 60 * 60;
kayekss 0:d9789f57fd9d 257 tmBuild = localtime(&secBuild);
kayekss 0:d9789f57fd9d 258
kayekss 0:d9789f57fd9d 259 strftime(sbuf, 11, "%Y-%m-%d", tmBuild);
kayekss 0:d9789f57fd9d 260 lcd.locate(0, 0);
kayekss 0:d9789f57fd9d 261 lcd.printf("Build %8s", sbuf);
kayekss 0:d9789f57fd9d 262 wait(0.0);
kayekss 0:d9789f57fd9d 263 strftime(sbuf, 11, "%H:%M:%S", tmBuild);
kayekss 0:d9789f57fd9d 264 lcd.locate(0, 1);
kayekss 0:d9789f57fd9d 265 lcd.printf(" T%8s", sbuf);
kayekss 0:d9789f57fd9d 266 wait(2.0);
kayekss 0:d9789f57fd9d 267 }
kayekss 0:d9789f57fd9d 268
kayekss 0:d9789f57fd9d 269 /** Test files in the SD memory card */
kayekss 0:d9789f57fd9d 270 uint8_t testFiles() {
kayekss 0:d9789f57fd9d 271 FILE *fpTest = NULL;
kayekss 0:d9789f57fd9d 272 bool sdTestResult = 0x00;
kayekss 0:d9789f57fd9d 273
kayekss 0:d9789f57fd9d 274 lcd.cls();
kayekss 0:d9789f57fd9d 275 lcd.locate(0, 0);
kayekss 0:d9789f57fd9d 276 lcd.printf("No memory cards ");
kayekss 0:d9789f57fd9d 277 wait(0.0);
kayekss 0:d9789f57fd9d 278 lcd.locate(0, 0);
kayekss 0:d9789f57fd9d 279 lcd.printf("Track / / / Ok");
kayekss 0:d9789f57fd9d 280 for (uint8_t i = 1; i <= 4; i++) {
kayekss 0:d9789f57fd9d 281 fpTest = fopen(fileNameList[i - 1], "rb");
kayekss 0:d9789f57fd9d 282 if (fpTest) {
kayekss 0:d9789f57fd9d 283 lcd.locate(2 * i + 4, 0);
kayekss 0:d9789f57fd9d 284 lcd.printf("%d", i);
kayekss 0:d9789f57fd9d 285 fclose(fpTest);
kayekss 0:d9789f57fd9d 286 } else {
kayekss 0:d9789f57fd9d 287 sdTestResult |= 0x01 << (i - 1);
kayekss 0:d9789f57fd9d 288 }
kayekss 0:d9789f57fd9d 289 }
kayekss 0:d9789f57fd9d 290 lcd.locate(0, 1);
kayekss 0:d9789f57fd9d 291 if (sdTestResult == 0x00) {
kayekss 0:d9789f57fd9d 292 lcd.printf("SD Test Pass ");
kayekss 0:d9789f57fd9d 293 wait(1.0);
kayekss 0:d9789f57fd9d 294 lcd.cls();
kayekss 0:d9789f57fd9d 295 } else {
kayekss 0:d9789f57fd9d 296 lcd.printf("SD Test Fail ");
kayekss 0:d9789f57fd9d 297 }
kayekss 0:d9789f57fd9d 298 return sdTestResult;
kayekss 0:d9789f57fd9d 299 }
kayekss 0:d9789f57fd9d 300
kayekss 0:d9789f57fd9d 301 /** Main routine */
kayekss 0:d9789f57fd9d 302 int main(void) {
kayekss 0:d9789f57fd9d 303 setup();
kayekss 0:d9789f57fd9d 304
kayekss 0:d9789f57fd9d 305 // Print build timestamp
kayekss 0:d9789f57fd9d 306 printTimestamp();
kayekss 0:d9789f57fd9d 307
kayekss 0:d9789f57fd9d 308 // Test files: Enter an infinite loop on failure
kayekss 0:d9789f57fd9d 309 if (testFiles()) {
kayekss 1:ef257d63d970 310 while (1) {}
kayekss 0:d9789f57fd9d 311 }
kayekss 0:d9789f57fd9d 312
kayekss 0:d9789f57fd9d 313 // Set Ticker interrupt routine
kayekss 0:d9789f57fd9d 314 tic.attach(&pollAndRequest, POLL_INTERVAL_SEC);
kayekss 0:d9789f57fd9d 315
kayekss 0:d9789f57fd9d 316 // Main loop
kayekss 0:d9789f57fd9d 317 while (1) {
kayekss 0:d9789f57fd9d 318 controlTrack();
kayekss 0:d9789f57fd9d 319 }
kayekss 0:d9789f57fd9d 320 }