MP3-capable chair with sensor-embedded weight scale.

Dependencies:   ACM1602 SDFileSystem VS1053 mbed ClockControl PowerControl

Revision:
0:d9789f57fd9d
Child:
1:ef257d63d970
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Mar 26 19:56:18 2014 +0000
@@ -0,0 +1,294 @@
+#include <stdio.h>
+#include "mbed.h"
+#include "defs.h"
+#include "HysteresisIn.h"
+#include "SDFileSystem.h"
+#include "VS1053.h"
+#include "ACM1602.h"
+
+// Pin settings for LPC1768(LPCXpresso)
+SDFileSystem sd(/*MOSI*/ xp11, /*MISO*/ xp12, /*SCK*/ xp13, /*CS*/ xp53, /*Mountpoint*/ "sd");
+VS1053       mp3(/*MOSI*/ xp11, /*MISO*/ xp12, /*SCK*/ xp13,
+                 /*CS*/ xp52, /*BSYNC*/ xp51, /*DREQ*/ xp50, /*RST*/ xp49, /*SPI freq.*/ 6000000);
+HysteresisIn sens3(p17, HIGH_TO_LOW, LOW_TO_HIGH, 1);  // Photo sensor #3 (Outer)
+HysteresisIn sens2(p18, HIGH_TO_LOW, LOW_TO_HIGH, 1);  // Photo sensor #2
+HysteresisIn sens1(p19, HIGH_TO_LOW, LOW_TO_HIGH, 1);  // Photo sensor #1
+HysteresisIn sens0(p20, HIGH_TO_LOW, LOW_TO_HIGH, 1);  // Photo sensor #0 (Inner)
+ACM1602      lcd(/*SDA*/ xp9, /*SCL*/ xp10, /*Address*/ 0xa0);
+DigitalOut   led(LED0);
+DigitalOut   audioPower(xp38);
+Ticker       tic;
+
+// Pin settings for LPC1114FN28 (SD card accessing does not work)
+// SDFileSystem sd(/*MOSI*/ dp2, /*MISO*/ dp1, /*SCK*/ dp6, /*CS*/ dp4, /*Mountpoint*/ "sd");
+// VS1053       mp3(/*MOSI*/ dp2, /*MISO*/ dp1, /*SCK*/ dp6,
+//                  /*CS*/ dp14, /*BSYNC*/ dp17, /*DREQ*/ dp18, /*RST*/ dp25, /*SPI freq.*/ 4000000);
+// HysteresisIn sens3(dp9,  HIGH_TO_LOW, LOW_TO_HIGH, 1);  // Photo sensor #3 (Outer)
+// HysteresisIn sens2(dp10, HIGH_TO_LOW, LOW_TO_HIGH, 1);  // Photo sensor #2
+// HysteresisIn sens1(dp11, HIGH_TO_LOW, LOW_TO_HIGH, 1);  // Photo sensor #1
+// HysteresisIn sens0(dp13, HIGH_TO_LOW, LOW_TO_HIGH, 1);  // Photo sensor #0 (Inner)
+// ACM1602      lcd(/*SDA*/ dp5, /*SCL*/ dp27, /*Address*/ 0xa0);
+// Ticker       tic;
+
+const char *fileNameList[] = {
+    "/sd/Track1.mp3",
+    "/sd/Track2.mp3",
+    "/sd/Track3.mp3",
+    "/sd/Track4.mp3"
+};
+
+volatile State   state = READY;
+volatile Request request = NONE;
+
+/** Setup and initializations */
+void setup(void) {
+    // Initialize VS1053
+    mp3.hardwareReset();
+    mp3.clockUp();
+    wait(0.1);
+    
+    // Initialize power supply for audio amplifier circuit
+    audioPower = 0;
+    
+    // Setup LCD
+    lcd.init();
+    
+    // Initialize LED
+    led = 0;
+}
+
+/** Read voltages from photo sensor pins and detect weightscale point code */
+int readPhotoSensors(void) {
+    uint8_t bitPattern;
+    
+    // Read all photo sensor inputs
+    bitPattern =   (sens3.read() << 3)
+                 | (sens2.read() << 2)
+                 | (sens1.read() << 1)
+                 |  sens0.read();
+    
+    switch (bitPattern) {
+    // 1 when open, 0 when shut
+    // Higher bit is on outer side
+    case 0xf:      // 1111: no load
+        return 0;
+    case 0xe:      // 1110: slight load
+        return 1;
+    case 0xc:      // 1100
+        return 2;
+    case 0x8:      // 1000
+        return 3;
+    case 0x0:      // 0000: heavy load
+        return 4;
+    default:       // Other than expectation: erroneous pattern
+        return -1;
+    }
+}
+
+/** Poll/sample weightscale inputs and issue requests */
+void pollAndRequest() {
+    const char* stateNameList[] = {
+        "STOPPING",   // -2
+        "CANCELING",  // -1
+        "READY",      //  0
+        "PLAYING1",   //  1
+        "PLAYING2",   //  2
+        "PLAYING3",   //  3
+        "PLAYING4"    //  4
+    };
+    int            code;
+    static int     codePrev = 0;
+    static uint8_t holdTimes = 0;
+    
+    // Get weightscale point code by reading photo sensors
+    code = readPhotoSensors();
+    
+    // Count the times that the given code persists
+    if (code == codePrev && code != -1) {
+        if (holdTimes < 99) {
+            holdTimes++;
+        }
+    } else {
+        holdTimes = 0;
+    }
+    lcd.locate(0, 0);
+    lcd.printf("%-15s", stateNameList[state + 2]);
+    lcd.locate(0, 1);
+    lcd.printf("ps=%2d times=%2d", code, holdTimes);
+    
+    // Once the point is stable enough, make a request
+    if (holdTimes == SETTLING_COUNT) {
+        if (code == 0) {
+            // Stable no load: stop request
+            request = STOP_REQUEST;
+        } else {
+            // Certain stable load: play request 1..4
+            // Ignore cases while playing the same track
+            if (state != code) {
+                request = (Request) code;
+            }
+        }
+    }
+    
+    // Preserve this time's code
+    codePrev = code;
+}
+
+/** Player control in accordance with requests */
+void controlTrack() {
+    static FILE   *fp = NULL;
+    size_t        sizeRead = 0;
+    uint8_t       buf[BLOCK_SIZE];
+    static size_t totalSizeSent = 0;
+    
+    switch (state) {
+    case READY:
+        switch (request) {
+        case STOP_REQUEST:
+            // Clear stop request
+            request = NONE;
+            break;
+        case PLAY1_REQUEST: case PLAY2_REQUEST: case PLAY3_REQUEST: case PLAY4_REQUEST:            
+            fp = fopen(fileNameList[request - 1], "rb");
+            if (fp) {
+                // Power supply on
+                audioPower = 1;
+                led = 1;
+                
+                totalSizeSent = 0;
+                state = (State) request;
+                lcd.locate(15, 0);
+                lcd.printf("*");
+            } else {
+                lcd.locate(0, 1);
+                lcd.printf("File Open Error ");
+            }
+            // Clear play request
+            request = NONE;
+            break;
+        default:
+            break;
+        }
+        break;
+    case PLAYING1: case PLAYING2: case PLAYING3: case PLAYING4:
+        if (request == NONE) {
+            sizeRead = fread(buf, sizeof(uint8_t), BLOCK_SIZE, fp);
+            if (sizeRead) {
+                totalSizeSent += mp3.sendDataBlock(buf, sizeRead);
+            } else {
+                // Close the track
+                fclose(fp);
+                lcd.locate(15, 0);
+                lcd.printf(" ");
+                
+                // Invoke play request again
+                request = (Request) state;
+                state = READY;
+            }
+        } else {
+            // Cancel current track when something's requested
+            fclose(fp);
+            lcd.locate(15, 0);
+            lcd.printf(" ");
+            state = CANCELING;
+        }
+        break;
+    case CANCELING:
+        if (mp3.sendCancel()) {
+            state = STOPPING;
+        }
+        break;
+    case STOPPING:
+        if (mp3.stop()) {
+            state = READY;
+        }
+        if (request == STOP_REQUEST) {
+            // Clear stop request
+            request = NONE;
+            
+            // Power supply off
+            audioPower = 0;
+            led = 0;
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+/** Print build timestamp (in JST) */
+void printTimestamp() {
+    time_t    secBuild;
+    struct tm *tmBuild;
+    char      sbuf[11];
+    
+    secBuild = MBED_BUILD_TIMESTAMP + 9 * 60 * 60;
+    tmBuild = localtime(&secBuild);
+    
+    strftime(sbuf, 11, "%Y-%m-%d", tmBuild);
+    lcd.locate(0, 0);
+    lcd.printf("Build %8s", sbuf);
+    wait(0.0);
+    strftime(sbuf, 11, "%H:%M:%S", tmBuild);
+    lcd.locate(0, 1);
+    lcd.printf("       T%8s", sbuf);
+    wait(2.0);
+}
+
+/** Test files in the SD memory card */
+uint8_t testFiles() {
+    FILE *fpTest = NULL;
+    bool sdTestResult = 0x00;
+    
+    lcd.cls();
+    lcd.locate(0, 0);
+    lcd.printf("No memory cards ");
+    wait(0.0);
+    lcd.locate(0, 0);
+    lcd.printf("Track  / / /  Ok");
+    for (uint8_t i = 1; i <= 4; i++) {
+        fpTest = fopen(fileNameList[i - 1], "rb");
+        if (fpTest) {
+            lcd.locate(2 * i + 4, 0);
+            lcd.printf("%d", i);
+            fclose(fpTest);
+        } else {
+            sdTestResult |= 0x01 << (i - 1);
+        }
+    }
+    lcd.locate(0, 1);
+    if (sdTestResult == 0x00) {
+        lcd.printf("SD Test Pass    ");
+        wait(1.0);
+        lcd.cls();
+    } else {
+        lcd.printf("SD Test Fail    ");
+    }
+    return sdTestResult;
+}
+
+/** Main routine */
+int main(void) {
+    setup();
+    
+    // Print build timestamp
+    printTimestamp();
+    
+    // Test files: Enter an infinite loop on failure
+    if (testFiles()) {
+        while (1) {
+            led = 1;
+            wait(0.5);
+            led = 0;
+            wait(0.5);
+        }
+    }
+    
+    // Set Ticker interrupt routine
+    tic.attach(&pollAndRequest, POLL_INTERVAL_SEC);
+    
+    // Main loop
+    while (1) {
+        controlTrack();
+    }
+}