MP3-capable chair with sensor-embedded weight scale.

Dependencies:   ACM1602 SDFileSystem VS1053 mbed ClockControl PowerControl

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 #include <stdio.h>
00002 #include "mbed.h"
00003 #include "defs.h"
00004 #include "SDFileSystem.h"
00005 #include "VS1053.h"
00006 #include "ACM1602.h"
00007 #include "ClockControl.h"
00008 #include "EthernetPowerControl.h"
00009 #include "PowerControl.h"
00010 
00011 // Pin settings for mbed LPC1768
00012 SDFileSystem sd(/*MOSI*/ p11, /*MISO*/ p12, /*SCK*/ p13, /*CS*/ p21, /*Mountpoint*/ "sd");
00013 VS1053       mp3(/*MOSI*/ p11, /*MISO*/ p12, /*SCK*/ p13,
00014                  /*CS*/ p22, /*BSYNC*/ p23, /*DREQ*/ p24, /*RST*/ p25, /*SPI freq.*/ 4000000);
00015 BusIn        sens(/*Out: 0*/ p20, /*1*/ p19, /*2*/ p18, /*In: 3*/ p17);
00016 BusIn        test(/*Out: 0*/ p26, /*1*/ p27, /*2*/ p28, /*In: 3*/ p29);
00017 ACM1602      lcd(/*SDA*/ p9, /*SCL*/ p10, /*Address*/ 0xa0);
00018 DigitalOut   audioPower(p30);
00019 DigitalIn    test3(p29);
00020 DigitalIn    test2(p28);
00021 DigitalIn    test1(p27);
00022 DigitalIn    test0(p26);
00023 DigitalIn    inputSelector(p8);
00024 // Set unused pins to input when using the LPCXpresso board
00025 BusIn        __dummy(xp21, xp22, xp23, xp24, xp49, xp50, xp51, xp52, xp53);
00026 Ticker       tic;
00027 bool         inputFrom;
00028 size_t       totalSizeSent;
00029 
00030 const char *fileNameList[] = {
00031     "/sd/Track1.mp3",
00032     "/sd/Track2.mp3",
00033     "/sd/Track3.mp3",
00034     "/sd/Track4.mp3"
00035 };
00036 
00037 volatile State   state = READY;
00038 volatile Request request = NONE;
00039 
00040 /** Setup and initializations */
00041 void setup(void) {
00042     // Reduce system clock frequency to 48 MHz
00043     setSystemFrequency(0x03, 0x01, 6, 1);
00044     
00045     // Power down Ethernet PHY
00046     PHY_PowerDown();
00047     
00048     // Set pull-up mode
00049     inputSelector.mode(PullUp);
00050     test3.mode(PullUp);
00051     test2.mode(PullUp);
00052     test1.mode(PullUp);
00053     test0.mode(PullUp);
00054     wait(0.1);
00055     
00056     // Initialize VS1053
00057     mp3.hardwareReset();
00058     mp3.clockUp();
00059     wait(0.1);
00060     
00061     // Initialize power supply for audio amplifier circuit
00062     audioPower = 0;
00063     
00064     // Setup LCD
00065     lcd.init();
00066     
00067     // Read input selector
00068     inputFrom = inputSelector;
00069 }
00070 
00071 /** Read voltages from photo sensor pins and detect weightscale point code */
00072 int readPhotoSensors(void) {
00073     uint8_t bitPattern;
00074     
00075     // Read all photo sensor inputs
00076     if (inputFrom) {
00077         // Read from photo sensors when Input Selector reads high
00078         // (Input is inverted by 74HC14)
00079         bitPattern = ~sens & 0xf;
00080     } else {
00081         // Read from test pins when Input Selector reads low
00082         bitPattern = test;
00083     }
00084     
00085     switch (bitPattern) {
00086     // 1 when open, 0 when shut
00087     // Higher bit is on outer side
00088     case 0xf:      // 1111: no load
00089         return 0;
00090     case 0xe:      // 1110: slight load
00091         return 1;
00092     case 0xc:      // 1100
00093         return 2;
00094     case 0x8:      // 1000
00095         return 3;
00096     case 0x0:      // 0000: heavy load
00097         return 4;
00098     default:       // Other than expectation: erroneous pattern
00099         return -1;
00100     }
00101 }
00102 
00103 /** Poll/sample weightscale inputs and issue requests */
00104 void pollAndRequest() {
00105     const char* stateNameList[] = {
00106         "STOPPING",   // -2
00107         "CANCELING",  // -1
00108         "READY",      //  0
00109         "PLAYING1",   //  1
00110         "PLAYING2",   //  2
00111         "PLAYING3",   //  3
00112         "PLAYING4"    //  4
00113     };
00114     int            code;
00115     static int     codePrev = 0;
00116     static uint8_t holdTimes = 0;
00117     
00118     // Get weightscale point code by reading photo sensors
00119     code = readPhotoSensors();
00120     
00121     // Count the times that the given code persists
00122     if (code == codePrev && code != -1) {
00123         if (holdTimes < 99) {
00124             holdTimes++;
00125         }
00126     } else {
00127         holdTimes = 0;
00128     }
00129     
00130     // Print status to LCD:
00131     // current state, photo sensor inputs, hold count,
00132     // file size sent to VS1053
00133     lcd.locate(0, 0);
00134     lcd.printf("%-9s  in=%2d", stateNameList[state + 2], code);
00135     lcd.locate(0, 1);
00136     lcd.printf("x%2d ", holdTimes);
00137     switch (state) {
00138     case PLAYING1: case PLAYING2: case PLAYING3: case PLAYING4:
00139         if (totalSizeSent >= 1000000) {
00140             lcd.printf("%9.2f MB", totalSizeSent / 1048576.0);
00141         } else if (totalSizeSent >= 1000) {
00142             lcd.printf("%9.2f KB", totalSizeSent / 1024.0);
00143         } else {
00144             lcd.printf("%6d bytes", totalSizeSent);
00145         }
00146         break;
00147     default:
00148         lcd.printf("   <No File>");
00149         break;
00150     }
00151     
00152     // Once the point is stable enough, make a request
00153     if (holdTimes == SETTLING_COUNT) {
00154         if (code == 0) {
00155             // Stable no load: stop request
00156             request = STOP_REQUEST;
00157         } else {
00158             // Certain stable load: play request 1..4
00159             // Ignore cases while playing the same track
00160             if (state != code) {
00161                 request = (Request) code;
00162             }
00163         }
00164     }
00165     
00166     // Preserve this time's code
00167     codePrev = code;
00168 }
00169 
00170 /** Player control in accordance with requests */
00171 void controlTrack() {
00172     static FILE *fp = NULL;
00173     size_t      sizeRead = 0;
00174     uint8_t     buf[BLOCK_SIZE];
00175     
00176     switch (state) {
00177     case READY:
00178         switch (request) {
00179         case STOP_REQUEST:
00180             // Clear stop request
00181             request = NONE;
00182             break;
00183         case PLAY1_REQUEST: case PLAY2_REQUEST: case PLAY3_REQUEST: case PLAY4_REQUEST:
00184             fp = fopen(fileNameList[request - 1], "rb");
00185             if (fp) {
00186                 clearerr(fp);
00187                 
00188                 // Power supply on
00189                 audioPower = 1;
00190                 
00191                 totalSizeSent = 0;
00192                 state = (State) request;
00193             }
00194             // Clear play request
00195             request = NONE;
00196             break;
00197         default:
00198             break;
00199         }
00200         break;
00201     case PLAYING1: case PLAYING2: case PLAYING3: case PLAYING4:
00202         if (request == NONE) {
00203             // Continue playback
00204             if (feof(fp)) {
00205                 // Close when the track reaches the end
00206                 fclose(fp);
00207                 fp = NULL;
00208                 
00209                 // Invoke play request again
00210                 request = (Request) state;
00211                 state = READY;
00212             } else {
00213                 sizeRead = fread(buf, sizeof(char), BLOCK_SIZE, fp);
00214                 totalSizeSent += mp3.sendDataBlock(buf, sizeRead);
00215             }
00216         } else {
00217             // Cancel current track when something's requested
00218             fclose(fp);
00219             fp = NULL;
00220             state = CANCELING;
00221         }
00222         break;
00223     case CANCELING:
00224         if (mp3.sendCancel()) {
00225             state = STOPPING;
00226         }
00227         break;
00228     case STOPPING:
00229         if (mp3.stop()) {
00230             state = READY;
00231         }
00232         if (request == STOP_REQUEST) {
00233             // Clear stop request
00234             request = NONE;
00235             // Power supply off
00236             audioPower = 0;
00237         }
00238         break;
00239     default:
00240         break;
00241     }
00242 }
00243 
00244 /** Print build timestamp (in JST) */
00245 void printTimestamp() {
00246     time_t    secBuild;
00247     struct tm *tmBuild;
00248     char      sbuf[11];
00249     
00250     secBuild = MBED_BUILD_TIMESTAMP + 9 * 60 * 60;
00251     tmBuild = localtime(&secBuild);
00252     
00253     strftime(sbuf, 11, "%Y-%m-%d", tmBuild);
00254     lcd.locate(0, 0);
00255     lcd.printf("Build %8s", sbuf);
00256     wait(0.0);
00257     strftime(sbuf, 11, "%H:%M:%S", tmBuild);
00258     lcd.locate(0, 1);
00259     lcd.printf("       T%8s", sbuf);
00260     wait(2.0);
00261 }
00262 
00263 /** Test files in the SD memory card */
00264 uint8_t testFiles() {
00265     FILE *fpTest = NULL;
00266     bool sdTestResult = 0x00;
00267     
00268     lcd.cls();
00269     lcd.locate(0, 0);
00270     lcd.printf("No memory cards ");
00271     wait(0.0);
00272     lcd.locate(0, 0);
00273     lcd.printf("Track  / / /  Ok");
00274     for (uint8_t i = 1; i <= 4; i++) {
00275         fpTest = fopen(fileNameList[i - 1], "rb");
00276         if (fpTest) {
00277             lcd.locate(2 * i + 4, 0);
00278             lcd.printf("%d", i);
00279             fclose(fpTest);
00280         } else {
00281             sdTestResult |= 0x01 << (i - 1);
00282         }
00283     }
00284     lcd.locate(0, 1);
00285     if (sdTestResult == 0x00) {
00286         lcd.printf("SD Test Pass    ");
00287         wait(1.0);
00288         lcd.cls();
00289     } else {
00290         lcd.printf("SD Test Fail    ");
00291     }
00292     return sdTestResult;
00293 }
00294 
00295 /** Main routine */
00296 int main(void) {
00297     setup();
00298     
00299     // Print build timestamp
00300     printTimestamp();
00301     
00302     // Test files: Enter an infinite loop on failure
00303     if (testFiles()) {
00304         while (1) {}
00305     }
00306     
00307     // Set Ticker interrupt routine
00308     tic.attach(&pollAndRequest, POLL_INTERVAL_SEC);
00309     
00310     // Main loop
00311     while (1) {
00312         controlTrack();
00313     }
00314 }