MP3-capable chair with sensor-embedded weight scale.

Dependencies:   ACM1602 SDFileSystem VS1053 mbed ClockControl PowerControl

Committer:
kayekss
Date:
Sat Mar 29 16:14:11 2014 +0000
Revision:
1:ef257d63d970
Parent:
0:d9789f57fd9d
Child:
2:844bedc9dc63
(1) Changed the target MCU to mbed LPC1768. (2) Added power-saving controls. (3) Changed content to print to display.

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 0:d9789f57fd9d 12 // Pin settings for LPC1768(LPCXpresso)
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 1:ef257d63d970 27 BusIn __dummy(xp21, xp22, xp23, xp24, xp49, xp50, xp51, xp52, xp53);
kayekss 0:d9789f57fd9d 28 Ticker tic;
kayekss 1:ef257d63d970 29 bool inputFrom;
kayekss 1:ef257d63d970 30 size_t totalSizeSent;
kayekss 0:d9789f57fd9d 31
kayekss 0:d9789f57fd9d 32 const char *fileNameList[] = {
kayekss 0:d9789f57fd9d 33 "/sd/Track1.mp3",
kayekss 0:d9789f57fd9d 34 "/sd/Track2.mp3",
kayekss 0:d9789f57fd9d 35 "/sd/Track3.mp3",
kayekss 0:d9789f57fd9d 36 "/sd/Track4.mp3"
kayekss 0:d9789f57fd9d 37 };
kayekss 0:d9789f57fd9d 38
kayekss 0:d9789f57fd9d 39 volatile State state = READY;
kayekss 0:d9789f57fd9d 40 volatile Request request = NONE;
kayekss 0:d9789f57fd9d 41
kayekss 0:d9789f57fd9d 42 /** Setup and initializations */
kayekss 0:d9789f57fd9d 43 void setup(void) {
kayekss 1:ef257d63d970 44 // Reduce system clock frequency
kayekss 1:ef257d63d970 45 setSystemFrequency(0x3, 0x1, 6, 1);
kayekss 1:ef257d63d970 46
kayekss 1:ef257d63d970 47 // Power down Ethernet PHY
kayekss 1:ef257d63d970 48 PHY_PowerDown();
kayekss 1:ef257d63d970 49
kayekss 1:ef257d63d970 50 // Set pull-up mode
kayekss 1:ef257d63d970 51 inputSelector.mode(PullUp);
kayekss 1:ef257d63d970 52 test3.mode(PullUp);
kayekss 1:ef257d63d970 53 test2.mode(PullUp);
kayekss 1:ef257d63d970 54 test1.mode(PullUp);
kayekss 1:ef257d63d970 55 test0.mode(PullUp);
kayekss 1:ef257d63d970 56 wait(0.1);
kayekss 1:ef257d63d970 57
kayekss 0:d9789f57fd9d 58 // Initialize VS1053
kayekss 0:d9789f57fd9d 59 mp3.hardwareReset();
kayekss 0:d9789f57fd9d 60 mp3.clockUp();
kayekss 0:d9789f57fd9d 61 wait(0.1);
kayekss 0:d9789f57fd9d 62
kayekss 0:d9789f57fd9d 63 // Initialize power supply for audio amplifier circuit
kayekss 0:d9789f57fd9d 64 audioPower = 0;
kayekss 0:d9789f57fd9d 65
kayekss 0:d9789f57fd9d 66 // Setup LCD
kayekss 0:d9789f57fd9d 67 lcd.init();
kayekss 0:d9789f57fd9d 68
kayekss 1:ef257d63d970 69 // Read input selector
kayekss 1:ef257d63d970 70 inputFrom = inputSelector;
kayekss 0:d9789f57fd9d 71 }
kayekss 0:d9789f57fd9d 72
kayekss 0:d9789f57fd9d 73 /** Read voltages from photo sensor pins and detect weightscale point code */
kayekss 0:d9789f57fd9d 74 int readPhotoSensors(void) {
kayekss 0:d9789f57fd9d 75 uint8_t bitPattern;
kayekss 0:d9789f57fd9d 76
kayekss 0:d9789f57fd9d 77 // Read all photo sensor inputs
kayekss 1:ef257d63d970 78 if (inputFrom) {
kayekss 1:ef257d63d970 79 bitPattern = (test3 << 3)
kayekss 1:ef257d63d970 80 | (test2 << 2)
kayekss 1:ef257d63d970 81 | (test1 << 1)
kayekss 1:ef257d63d970 82 | test0;
kayekss 1:ef257d63d970 83 } else {
kayekss 1:ef257d63d970 84 bitPattern = (sens3.read() << 3)
kayekss 1:ef257d63d970 85 | (sens2.read() << 2)
kayekss 1:ef257d63d970 86 | (sens1.read() << 1)
kayekss 1:ef257d63d970 87 | sens0.read();
kayekss 1:ef257d63d970 88 }
kayekss 0:d9789f57fd9d 89
kayekss 0:d9789f57fd9d 90 switch (bitPattern) {
kayekss 0:d9789f57fd9d 91 // 1 when open, 0 when shut
kayekss 0:d9789f57fd9d 92 // Higher bit is on outer side
kayekss 0:d9789f57fd9d 93 case 0xf: // 1111: no load
kayekss 0:d9789f57fd9d 94 return 0;
kayekss 0:d9789f57fd9d 95 case 0xe: // 1110: slight load
kayekss 0:d9789f57fd9d 96 return 1;
kayekss 0:d9789f57fd9d 97 case 0xc: // 1100
kayekss 0:d9789f57fd9d 98 return 2;
kayekss 0:d9789f57fd9d 99 case 0x8: // 1000
kayekss 0:d9789f57fd9d 100 return 3;
kayekss 0:d9789f57fd9d 101 case 0x0: // 0000: heavy load
kayekss 0:d9789f57fd9d 102 return 4;
kayekss 0:d9789f57fd9d 103 default: // Other than expectation: erroneous pattern
kayekss 0:d9789f57fd9d 104 return -1;
kayekss 0:d9789f57fd9d 105 }
kayekss 0:d9789f57fd9d 106 }
kayekss 0:d9789f57fd9d 107
kayekss 0:d9789f57fd9d 108 /** Poll/sample weightscale inputs and issue requests */
kayekss 0:d9789f57fd9d 109 void pollAndRequest() {
kayekss 0:d9789f57fd9d 110 const char* stateNameList[] = {
kayekss 0:d9789f57fd9d 111 "STOPPING", // -2
kayekss 0:d9789f57fd9d 112 "CANCELING", // -1
kayekss 0:d9789f57fd9d 113 "READY", // 0
kayekss 0:d9789f57fd9d 114 "PLAYING1", // 1
kayekss 0:d9789f57fd9d 115 "PLAYING2", // 2
kayekss 0:d9789f57fd9d 116 "PLAYING3", // 3
kayekss 0:d9789f57fd9d 117 "PLAYING4" // 4
kayekss 0:d9789f57fd9d 118 };
kayekss 0:d9789f57fd9d 119 int code;
kayekss 0:d9789f57fd9d 120 static int codePrev = 0;
kayekss 0:d9789f57fd9d 121 static uint8_t holdTimes = 0;
kayekss 0:d9789f57fd9d 122
kayekss 0:d9789f57fd9d 123 // Get weightscale point code by reading photo sensors
kayekss 0:d9789f57fd9d 124 code = readPhotoSensors();
kayekss 0:d9789f57fd9d 125
kayekss 0:d9789f57fd9d 126 // Count the times that the given code persists
kayekss 0:d9789f57fd9d 127 if (code == codePrev && code != -1) {
kayekss 0:d9789f57fd9d 128 if (holdTimes < 99) {
kayekss 0:d9789f57fd9d 129 holdTimes++;
kayekss 0:d9789f57fd9d 130 }
kayekss 0:d9789f57fd9d 131 } else {
kayekss 0:d9789f57fd9d 132 holdTimes = 0;
kayekss 0:d9789f57fd9d 133 }
kayekss 1:ef257d63d970 134
kayekss 1:ef257d63d970 135 // Print status to LCD:
kayekss 1:ef257d63d970 136 // current state, photo sensor inputs, hold count,
kayekss 1:ef257d63d970 137 // file size sent to VS1053
kayekss 0:d9789f57fd9d 138 lcd.locate(0, 0);
kayekss 1:ef257d63d970 139 lcd.printf("%-9s in=%2d", stateNameList[state + 2], code);
kayekss 0:d9789f57fd9d 140 lcd.locate(0, 1);
kayekss 1:ef257d63d970 141 lcd.printf("x%2d ", holdTimes);
kayekss 1:ef257d63d970 142 switch (state) {
kayekss 1:ef257d63d970 143 case PLAYING1: case PLAYING2: case PLAYING3: case PLAYING4:
kayekss 1:ef257d63d970 144 if (totalSizeSent >= 1000000) {
kayekss 1:ef257d63d970 145 lcd.printf("%9.2f MB", totalSizeSent / 1048576.0);
kayekss 1:ef257d63d970 146 } else if (totalSizeSent >= 1000) {
kayekss 1:ef257d63d970 147 lcd.printf("%9.2f KB", totalSizeSent / 1024.0);
kayekss 1:ef257d63d970 148 } else {
kayekss 1:ef257d63d970 149 lcd.printf("%6d bytes", totalSizeSent);
kayekss 1:ef257d63d970 150 }
kayekss 1:ef257d63d970 151 break;
kayekss 1:ef257d63d970 152 default:
kayekss 1:ef257d63d970 153 lcd.printf(" <No File>");
kayekss 1:ef257d63d970 154 break;
kayekss 1:ef257d63d970 155 }
kayekss 0:d9789f57fd9d 156
kayekss 0:d9789f57fd9d 157 // Once the point is stable enough, make a request
kayekss 0:d9789f57fd9d 158 if (holdTimes == SETTLING_COUNT) {
kayekss 0:d9789f57fd9d 159 if (code == 0) {
kayekss 0:d9789f57fd9d 160 // Stable no load: stop request
kayekss 0:d9789f57fd9d 161 request = STOP_REQUEST;
kayekss 0:d9789f57fd9d 162 } else {
kayekss 0:d9789f57fd9d 163 // Certain stable load: play request 1..4
kayekss 0:d9789f57fd9d 164 // Ignore cases while playing the same track
kayekss 0:d9789f57fd9d 165 if (state != code) {
kayekss 0:d9789f57fd9d 166 request = (Request) code;
kayekss 0:d9789f57fd9d 167 }
kayekss 0:d9789f57fd9d 168 }
kayekss 0:d9789f57fd9d 169 }
kayekss 0:d9789f57fd9d 170
kayekss 0:d9789f57fd9d 171 // Preserve this time's code
kayekss 0:d9789f57fd9d 172 codePrev = code;
kayekss 0:d9789f57fd9d 173 }
kayekss 0:d9789f57fd9d 174
kayekss 0:d9789f57fd9d 175 /** Player control in accordance with requests */
kayekss 0:d9789f57fd9d 176 void controlTrack() {
kayekss 1:ef257d63d970 177 static FILE *fp = NULL;
kayekss 1:ef257d63d970 178 size_t sizeRead = 0;
kayekss 1:ef257d63d970 179 uint8_t buf[BLOCK_SIZE];
kayekss 0:d9789f57fd9d 180
kayekss 0:d9789f57fd9d 181 switch (state) {
kayekss 0:d9789f57fd9d 182 case READY:
kayekss 0:d9789f57fd9d 183 switch (request) {
kayekss 0:d9789f57fd9d 184 case STOP_REQUEST:
kayekss 0:d9789f57fd9d 185 // Clear stop request
kayekss 0:d9789f57fd9d 186 request = NONE;
kayekss 0:d9789f57fd9d 187 break;
kayekss 1:ef257d63d970 188 case PLAY1_REQUEST: case PLAY2_REQUEST: case PLAY3_REQUEST: case PLAY4_REQUEST:
kayekss 0:d9789f57fd9d 189 fp = fopen(fileNameList[request - 1], "rb");
kayekss 0:d9789f57fd9d 190 if (fp) {
kayekss 1:ef257d63d970 191 clearerr(fp);
kayekss 1:ef257d63d970 192
kayekss 0:d9789f57fd9d 193 // Power supply on
kayekss 0:d9789f57fd9d 194 audioPower = 1;
kayekss 0:d9789f57fd9d 195
kayekss 0:d9789f57fd9d 196 totalSizeSent = 0;
kayekss 0:d9789f57fd9d 197 state = (State) request;
kayekss 0:d9789f57fd9d 198 }
kayekss 0:d9789f57fd9d 199 // Clear play request
kayekss 0:d9789f57fd9d 200 request = NONE;
kayekss 0:d9789f57fd9d 201 break;
kayekss 0:d9789f57fd9d 202 default:
kayekss 0:d9789f57fd9d 203 break;
kayekss 0:d9789f57fd9d 204 }
kayekss 0:d9789f57fd9d 205 break;
kayekss 0:d9789f57fd9d 206 case PLAYING1: case PLAYING2: case PLAYING3: case PLAYING4:
kayekss 0:d9789f57fd9d 207 if (request == NONE) {
kayekss 1:ef257d63d970 208 // Continue playback
kayekss 1:ef257d63d970 209 if (feof(fp)) {
kayekss 1:ef257d63d970 210 // Close when the track reaches the end
kayekss 0:d9789f57fd9d 211 fclose(fp);
kayekss 1:ef257d63d970 212 fp = NULL;
kayekss 0:d9789f57fd9d 213
kayekss 0:d9789f57fd9d 214 // Invoke play request again
kayekss 0:d9789f57fd9d 215 request = (Request) state;
kayekss 0:d9789f57fd9d 216 state = READY;
kayekss 1:ef257d63d970 217 } else {
kayekss 1:ef257d63d970 218 sizeRead = fread(buf, sizeof(char), BLOCK_SIZE, fp);
kayekss 1:ef257d63d970 219 totalSizeSent += mp3.sendDataBlock(buf, sizeRead);
kayekss 0:d9789f57fd9d 220 }
kayekss 0:d9789f57fd9d 221 } else {
kayekss 0:d9789f57fd9d 222 // Cancel current track when something's requested
kayekss 0:d9789f57fd9d 223 fclose(fp);
kayekss 1:ef257d63d970 224 fp = NULL;
kayekss 0:d9789f57fd9d 225 state = CANCELING;
kayekss 0:d9789f57fd9d 226 }
kayekss 0:d9789f57fd9d 227 break;
kayekss 0:d9789f57fd9d 228 case CANCELING:
kayekss 0:d9789f57fd9d 229 if (mp3.sendCancel()) {
kayekss 0:d9789f57fd9d 230 state = STOPPING;
kayekss 0:d9789f57fd9d 231 }
kayekss 0:d9789f57fd9d 232 break;
kayekss 0:d9789f57fd9d 233 case STOPPING:
kayekss 0:d9789f57fd9d 234 if (mp3.stop()) {
kayekss 0:d9789f57fd9d 235 state = READY;
kayekss 0:d9789f57fd9d 236 }
kayekss 0:d9789f57fd9d 237 if (request == STOP_REQUEST) {
kayekss 0:d9789f57fd9d 238 // Clear stop request
kayekss 0:d9789f57fd9d 239 request = NONE;
kayekss 0:d9789f57fd9d 240
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 }