Twittering Billy Bass plays back samples and looks out for and reads twitters!

Dependencies:   NetServices mbed

Files at this revision

API Documentation at this revision

Comitter:
simon
Date:
Wed Apr 06 15:16:45 2011 +0000
Child:
1:27b1efbf5a46
Commit message:

Changed in this revision

FATFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
MSCFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
NetServices.lib Show annotated file Show diff for this revision Revisions of this file
billy.cpp Show annotated file Show diff for this revision Revisions of this file
billy.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FATFileSystem.lib	Wed Apr 06 15:16:45 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_unsupported/code/fatfilesystem/
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MSCFileSystem.lib	Wed Apr 06 15:16:45 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/chris/code/MSCFileSystem/#3e7d2baed4b4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NetServices.lib	Wed Apr 06 15:16:45 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/segundo/code/NetServices/#4e2468d7d5cb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/billy.cpp	Wed Apr 06 15:16:45 2011 +0000
@@ -0,0 +1,298 @@
+#include "billy.h"
+
+#include "mbed.h"
+
+#define SAMPLE_FREQ 40000
+#define BUF_SIZE (SAMPLE_FREQ/10)
+#define SLICE_BUF_SIZE 1
+#define USE_PUSHBUTTON 1
+
+typedef struct uFMT_STRUCT {
+    short comp_code;
+    short num_channels;
+    unsigned sample_rate;
+    unsigned avg_Bps;
+    short block_align;
+    short sig_bps;
+} FMT_STRUCT;
+
+typedef struct uMOV_STRUCT {
+    long sample;
+    unsigned motor;
+    unsigned duty_cycle;
+    unsigned played;
+} MOV_STRUCT;
+
+// Billy's i/o
+AnalogOut DACout(p18);
+PwmOut body(p21);
+PwmOut mouth(p22);
+PwmOut tail(p23);
+Ticker tick;
+
+// global variables used both by the main program and the ISR
+short DAC_fifo[256];        // FIFO for the DAC
+short DAC_wptr;             // FIFO pointer
+volatile short DAC_rptr;    // FIFO pointer
+long slice;
+unsigned num_movements;
+unsigned current_movement;
+MOV_STRUCT movements[500];
+
+void dac_out(void);
+unsigned process_movement_file (char *mfname, MOV_STRUCT *mv,unsigned samp_rate);
+
+void billy_play(char *wavname, char *movname) {
+    unsigned chunk_id,chunk_size,channel;
+    unsigned data,samp_int,i;
+    short dac_data;
+    char *slice_buf;
+    short *data_sptr;
+    unsigned char *data_bptr;
+    int *data_wptr;
+    FMT_STRUCT wav_format;
+    FILE *wavfile;
+    long num_slices;
+    long long slice_value;
+    int verbosity=0;
+    DAC_wptr=0;
+    DAC_rptr=0;
+    for (i=0;i<256;i+=2) {
+        DAC_fifo[i]=0;
+        DAC_fifo[i+1]=3000;
+    }
+    DAC_wptr=4;
+
+    body.period_us(100);
+    mouth.period_us(100);
+    tail.period_us(100);
+
+    printf("Playing wave file '%s', mov file '%s'\n",wavname, movname);
+
+    wavfile=fopen(wavname,"rb");
+    if (!wavfile) {
+        printf("Unable to open wav file '%s'\n",wavname);
+        return;
+    }
+
+    fread(&chunk_id,4,1,wavfile);
+    fread(&chunk_size,4,1,wavfile);
+    while (!feof(wavfile)) {
+        printf("Read chunk ID 0x%x, size 0x%x\n",chunk_id,chunk_size);
+        switch (chunk_id) {
+            case 0x46464952:
+                fread(&data,4,1,wavfile);
+                printf("RIFF chunk\n");
+                printf("  chunk size %d (0x%x)\n",chunk_size,chunk_size);
+                printf("  RIFF type 0x%x\n",data);
+                break;
+            case 0x20746d66:
+                fread(&wav_format,sizeof(wav_format),1,wavfile);
+                printf("FORMAT chunk\n");
+                printf("  chunk size %d (0x%x)\n",chunk_size,chunk_size);
+                printf("  compression code %d\n",wav_format.comp_code);
+                printf("  %d channels\n",wav_format.num_channels);
+                printf("  %d samples/sec\n",wav_format.sample_rate);
+                printf("  %d bytes/sec\n",wav_format.avg_Bps);
+                printf("  block align %d\n",wav_format.block_align);
+                printf("  %d bits per sample\n",wav_format.sig_bps);
+                if (chunk_size > sizeof(wav_format))
+                    fseek(wavfile,chunk_size-sizeof(wav_format),SEEK_CUR);
+// create a slice buffer large enough to hold multiple slices
+                slice_buf=(char *)malloc(wav_format.block_align*SLICE_BUF_SIZE);
+                if (!slice_buf) {
+                    printf("Unable to malloc slice buffer");
+                    exit(1);
+                }
+// now that the sample rate is known, process the movement file
+                num_movements=process_movement_file(movname,movements,wav_format.sample_rate);
+                break;
+
+            case 0x61746164:
+                slice_buf=(char *)malloc(wav_format.block_align*SLICE_BUF_SIZE);
+                if (!slice_buf) {
+                    printf("Unable to malloc slice buffer");
+                    exit(1);
+                }
+                num_slices=chunk_size/wav_format.block_align;
+                printf("DATA chunk\n");
+                printf("  chunk size %d (0x%x)\n",chunk_size,chunk_size);
+                printf("  %d slices\n",num_slices);
+                printf("  Ideal sample interval=%d\n",(unsigned)(1000000.0/wav_format.sample_rate));
+                samp_int=1000000/(wav_format.sample_rate);
+
+                printf("  programmed interrupt tick interval=%d\n",samp_int);
+
+// starting up ticker to write samples out -- no printfs until tick.detach is called
+                current_movement = 0;
+                tick.attach_us(&dac_out, samp_int);
+                //led2=1;
+                for (slice=0;slice<num_slices;slice+=SLICE_BUF_SIZE) {
+                    fread(slice_buf,wav_format.block_align*SLICE_BUF_SIZE,1,wavfile);
+                    if (feof(wavfile)) {
+                        printf("Oops -- not enough slices in the wave file\n");
+                        exit(1);
+                    }
+                    data_sptr=(short *)slice_buf;
+                    data_bptr=(unsigned char *)slice_buf;
+                    data_wptr=(int *)slice_buf;
+                    slice_value=0;
+                    for (i=0;i<SLICE_BUF_SIZE;i++) {
+                        for (channel=0;channel<wav_format.num_channels;channel++) {
+                            switch (wav_format.sig_bps) {
+                                case 16:
+                                    if (verbosity)
+                                        printf("16 bit channel %d data=%d ",channel,data_sptr[channel]);
+                                    slice_value+=data_sptr[channel];
+                                    break;
+                                case 32:
+                                    if (verbosity)
+                                        printf("32 bit channel %d data=%d ",channel,data_wptr[channel]);
+                                    slice_value+=data_wptr[channel];
+                                    break;
+                                case 8:
+                                    if (verbosity)
+                                        printf("8 bit channel %d data=%d ",channel,(int)data_bptr[channel]);
+                                    slice_value+=data_bptr[channel];
+                                    break;
+                            }
+                        }
+                        slice_value/=wav_format.num_channels;
+
+// slice_value is now averaged.  Next it needs to be scaled to an unsigned 16 bit value
+// with DC offset so it can be written to the DAC.
+                        switch (wav_format.sig_bps) {
+                            case 8:
+                                slice_value<<=8;
+                                break;
+                            case 16:
+                                slice_value+=32768;
+                                break;
+                            case 32:
+                                slice_value>>=16;
+                                slice_value+=32768;
+                                break;
+                        }
+                        dac_data=(short unsigned )slice_value;
+                        if (verbosity)
+                            printf("sample %d wptr %d slice_value %d dac_data %u\n",slice,DAC_wptr,(int)slice_value,dac_data);
+
+// finally stick it in the DAC FIFO.  If the write pointer wraps around and meets the read pointer
+// the wait until the read pointer moves.
+                        DAC_fifo[DAC_wptr]=dac_data;
+                        DAC_wptr=(DAC_wptr+1) & 0xff;
+                        while (DAC_wptr==DAC_rptr) {
+                        }
+                    }
+                }
+
+// wait for ISR to drain FIFO
+                wait_us(300);
+                tick.detach();
+                printf("Ticker detached\n");
+                free(slice_buf);
+                break;
+            case 0x5453494c:
+                printf("INFO chunk, size %d\n",chunk_size);
+                fseek(wavfile,chunk_size,SEEK_CUR);
+                break;
+            default:
+                printf("unknown chunk type 0x%x, size %d\n",chunk_id,chunk_size);
+                data=fseek(wavfile,chunk_size,SEEK_CUR);
+                break;
+        }
+        fread(&chunk_id,4,1,wavfile);
+        fread(&chunk_size,4,1,wavfile);
+    }
+    printf("Done with wave file\n");
+    fclose(wavfile);
+    body.pulsewidth_us(0);
+    mouth.pulsewidth_us(0);
+    tail.pulsewidth_us(0);
+}
+
+void dac_out() {
+    int value;
+    if (!movements[current_movement].played) {
+        if (movements[current_movement].sample<=slice) {
+            if (movements[current_movement].motor==0) body.pulsewidth_us(movements[current_movement].duty_cycle);
+            if (movements[current_movement].motor==1) mouth.pulsewidth_us(movements[current_movement].duty_cycle);
+            if (movements[current_movement].motor==2) tail.pulsewidth_us(movements[current_movement].duty_cycle);
+            movements[current_movement].played=1;
+            current_movement++;
+        }
+    }
+    DACout.write_u16(DAC_fifo[DAC_rptr]);
+    DAC_rptr=(DAC_rptr+1) & 0xff;
+}
+
+unsigned process_movement_file(char *mfname, MOV_STRUCT *mv,unsigned samp_rate) {
+    FILE *movfile;
+    char line[100],*tmp;
+    unsigned num_movements,i,j,x;
+    movfile=fopen(mfname,"rb");
+    if (!movfile) {
+        printf("Unable to open mov file '%s'\n",mfname);
+        return 0;
+    }
+
+    fgets(line,100,movfile);
+    num_movements=0;
+#ifdef VERBOSE
+    printf("Motor report...\n");
+#endif
+    while (!feof(movfile)) {
+        if (line[0]!='#') {
+            tmp=line;
+// first thing on line is time in ms
+            movements[num_movements].sample=(atol(tmp)*samp_rate)/1000;
+// skip digits (non whitespace)
+            tmp=line;
+            while (*tmp!=' ' && *tmp!='\t' && *tmp!=0)
+                tmp++;
+// skip whitespace
+            while ((*tmp==' ' | *tmp=='\t') && *tmp!=0)
+                tmp++;
+            if (strstr(tmp,"body"))
+                movements[num_movements].motor=0;
+            if (strstr(tmp,"mouth"))
+                movements[num_movements].motor=1;
+            if (strstr(tmp,"tail"))
+                movements[num_movements].motor=2;
+// skip letters (non whitespace)
+            while (*tmp!=' ' && *tmp!='\t')
+                tmp++;
+// skip whitespace
+            while (*tmp==' ' | *tmp=='\t')
+                tmp++;
+            if (tmp)
+                movements[num_movements].duty_cycle=atoi(tmp);
+            movements[num_movements].played=0;
+#ifdef VERBOSE
+            printf("  moving motor %d at sample %ld with duty cycle %d\n",movements[num_movements].motor,movements[num_movements].sample,movements[num_movements].duty_cycle);
+#endif
+            num_movements++;
+        }
+        fgets(line,100,movfile);
+    }
+    printf("  %d movements read\n",num_movements);
+    printf("  sorting movements...");
+    for (i=0;i<num_movements;i++) {
+        for (j=i;j<num_movements;j++) {
+            if (movements[j].sample < movements[i].sample) {
+                x=movements[i].sample;
+                movements[i].sample=movements[j].sample;
+                movements[j].sample=x;
+                x=movements[i].motor ;
+                movements[i].motor =movements[j].motor ;
+                movements[j].motor =x;
+                x=movements[i].duty_cycle;
+                movements[i].duty_cycle=movements[j].duty_cycle;
+                movements[j].duty_cycle=x;
+            }
+        }
+    }
+    printf("done\n");
+    fclose(movfile);
+    return num_movements;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/billy.h	Wed Apr 06 15:16:45 2011 +0000
@@ -0,0 +1,7 @@
+#ifndef BILLY_H
+#define BILLY_H
+
+// ask billy to play and move!
+void billy_play(char *wavname, char *movname);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Wed Apr 06 15:16:45 2011 +0000
@@ -0,0 +1,123 @@
+#include "mbed.h"
+
+#include "MSCFileSystem.h"
+#include "billy.h"
+#include "EthernetNetIf.h"
+#include "HTTPClient.h"
+
+EthernetNetIf eth;
+HTTPClient http;
+
+MSCFileSystem usb("usb");
+
+DigitalOut setup_led(LED1);
+DigitalOut waiting_led(LED2);
+DigitalOut downloading_led(LED3);
+DigitalOut button_led(LED4);
+
+int get_file(char *url, char *file) {
+    printf("Getting url to file [%s]...\n", url);
+    HTTPFile f(file);
+    HTTPResult r = http.get(url, &f);
+    if (r != HTTP_OK) {
+        printf("HTTPResult error %d\n", r);
+        return 0;
+    }
+    return 1;
+}
+
+int get_string(char *url, char *str) {
+    printf("Getting url [%s] to string...\n", url);
+    HTTPText t;
+    HTTPResult r = http.get("http://danros.org.uk/billy/billy.py", &t);
+    if (r != HTTP_OK) {
+        printf("HTTPResult error %d\n", r);
+        str[0] = 0;
+        return 0;
+    }
+    strcpy(str, t.gets());
+    return 1;
+}
+
+int billy_get_id(char *id) {
+    return get_string("http://danros.org.uk/billy/billy.py", id);
+}
+
+int billy_get_wav(char *id) {
+    char url[128];
+    sprintf(url, "http://danros.org.uk/billydata/%s.wav", id);
+    return get_file(url, "/usb/download.wav");
+}
+
+int billy_get_mov(char *id) {
+    char url[128];
+    sprintf(url, "http://danros.org.uk/billydata/%s.txt", id);
+    return get_file(url, "/usb/download.txt");
+}
+
+int billy_get_new_message() {
+    static char last[64] = {0};
+    char id[64];
+    billy_get_id(id);
+    if (strcmp(last, id) != 0) { // new message
+        printf("New message found...\n");
+        downloading_led = 1;
+        billy_get_wav(id);
+        billy_get_mov(id);
+        strcpy(last, id);
+        downloading_led = 0;
+        return 1;
+    }
+    return 0;
+}
+
+const char *songs[] = {"baddonut", "belcher", "people", "clinton", "coconut", "bushfool", "ecky", "ni", "looney", "lumber"};
+int nsongs = 10;
+
+int billy_play_next() {
+    static int n = 0;
+    char wavname[64];
+    char cmdname[64];
+    sprintf(wavname, "/usb/%s.wav", songs[n]);
+    sprintf(cmdname, "/usb/%s.txt", songs[n]);
+    n = (n + 1) % nsongs;
+    billy_play(wavname, cmdname);
+}
+
+// Capture button presses
+InterruptIn button(p24);
+void button_press() {
+    if(button) {
+        button_led = 1;
+    }
+}
+
+int main() {
+    printf("Twittering billy...\n");
+
+    printf("Setup network...\n");
+    setup_led = 1;
+    EthernetErr ethErr = eth.setup();
+    if (ethErr) {
+        error("Error %d in setup\n", ethErr);
+    }
+    printf("Network setup OK!\n");
+    setup_led = 0;
+
+    button.rise(&button_press);
+
+    while (1) {
+        if(billy_get_new_message()) {
+            billy_play("/usb/download.wav", "/usb/download.txt");
+        }
+
+        if (button_led) {
+            billy_play_next();
+            button_led = 0;
+        }
+
+        waiting_led = !waiting_led;
+        wait(1);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Apr 06 15:16:45 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912