My Billy Bass program, see my notebook for details

Dependencies:   EthernetNetIf mbed

main.cpp

Committer:
tombracer
Date:
2010-08-14
Revision:
0:7613b886e052

File content as of revision 0:7613b886e052:



#include "mbed.h"
#include "SDHCFileSystem.h"
#include "HTTPClient.h"
#include "EthernetNetIf.h"

#define SAMPLE_FREQ 40000
#define BUF_SIZE (SAMPLE_FREQ/10)
#define SLICE_BUF_SIZE 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;

short DAC_fifo[256];
short DAC_wptr;
short DAC_rptr;
short DAC_on;

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

SDFileSystem sd(p5, p6, p7, p13, "sd");

EthernetNetIf eth;
HTTPClient http;

void download_bmf(void);
void load_lipsync(char[]);
void mouth(void);

void dac_out(void);
void dingdong(void);

void body_move(int);
void tail_flap(int);

int dl(char[], char[]);
void surf(char[]);
void pollserver(void);

DigitalOut ruu1(p21); //tail
DigitalOut ruu2(p22); //body
DigitalOut suu1(p23);
DigitalOut suu2(p24);
DigitalOut ena(p25); //enable

Ticker tick;
Ticker polltick;
#define POLLINTERVAL 10 //server polling interval in seconds
bool pollfound = false; //flag goes up if there is something to play

AnalogOut DACout(p18);
DigitalOut relay1(p29);

InterruptIn doorbell(p30);
void dummy(void);

void play_wave(char *, bool);

Ticker movetick; //runs the lipsync function
#define SAYSPEED 0.085 //speed of lipsync in seconds
char lipmoves[300]; //array for lipmove bits
int lippos;

bool doorint = false; //doorbell interrupt flag


int main() {

//setup ethernet connection
printf("Setting up ethernet...\n");
EthernetErr ethErr = eth.setup();
if(ethErr) {
    printf("Error %d in ethernet setup.\n", ethErr);
}//if

printf("Ethernet setup OK\n");

//putting doorbell pin(p30) in pullup mode so it pulls up the voltage
//between interrupts that pull it down
doorbell.mode(PullUp);

//run interrupt function when detecting a falling edge on p30
doorbell.fall(&dummy);
doorbell.fall(&dingdong);

lippos = 0;
suu1 = suu2 = ruu1 = ruu2 = 0;
ena = 1; //enable L293 chip

//starting http server polling ticker (10 second intervals)
polltick.attach(&pollserver, POLLINTERVAL);
    
while(1) {
    //check if polling flag is up
    if(pollfound==true) {
        polltick.detach();
        doorbell.fall(&dummy);
        
        //TODO: dl an effect description file or an sfx sound file
   
        //download lipsync file and load it into the array
        if(dl("http://192.168.1.2/talk/snd.bmf", "/sd/snd.bmf")==0) {
            load_lipsync("/sd/snd.bmf");
        }//inner if

        //flap the tail before playing
        tail_flap(2);
   
         //play downloaded file (new waveplayer code)
         play_wave("/sd/snd.wav", true);
         
         //add event to eventlog (info=type:sender:description)
         surf("http://192.168.1.2/talk/addevent.php?info=info:Billy:Played%20wavefile%20snd.wav");

         //delete played sound file
         surf("http://192.168.1.2/talk/dlok.php?delete=yes");
         
         //add event to eventlog (info=type:sender:description)
         surf("http://192.168.1.2/talk/addevent.php?info=info:Billy:Deleted%20wavefile%20snd.wav%20from%20server.");
         
         //reset pollfound flag
         pollfound = false;
         polltick.attach(&pollserver, POLLINTERVAL);
         doorbell.fall(&dingdong);        
    }//if pollfound

   //check if doorbell flag is raised for doorbell press
   if(doorint==true) {
        printf("Doorbell press detected..\n");
        
        polltick.detach();
               
        play_wave("/sd/ns.wav", false); //doorbell sound, no lipmoves
        
        load_lipsync("/sd/tulossa.bmf");
        
        ruu2 = 1;//raise body
        play_wave("/sd/tulossa.wav", true);
        ruu2 = 0;//lower body
        
        //add event to eventlog (info=type:sender:description)
        surf("http://192.168.1.2/talk/addevent.php?info=info:Billy:Doorbell%20pressed");
        
        //reattach polling ticker
        polltick.attach(&pollserver, POLLINTERVAL);    
         
        //reset doorbell interrupt flag
        doorint = false;        
   }//if doorint
}//while 1

}///////////// main ends //////////////////

//dummy function for the interruptin 'fix'
void dummy() {}


//this function is attached to polltick, and it polls the server
//every 10 seconds looking for something to download and play
void pollserver() {
   printf("Attempting download..\n");
   led1 = 1;
   
   //if download is successful, raise flag
   if (dl("http://192.168.1.2/talk/snd.wav", "/sd/snd.wav")==0) {
        pollfound = true;
        polltick.detach();
   }//if dl..
   
   led1 = 0;
}//pollserver


//http download function, takes url (http://mbed.org/example.wav)
//and target file (/sd/example.wav) as parameters
//returns 0 on success and 1 on failure
int dl(char url[], char target[]) {
    int result;
    HTTPFile f(target);
    HTTPResult r = http.get(url, &f);

    if(r==HTTP_OK) {
      printf(" HTTP Result OK\n");
      result=0; 
    }
    else {
      printf("HTTP Error %d\n", r);
      result=1;
    }//else 
    
    return result; 
}//dl


//http get function "surfing the web"
void surf(char url[]) {
    HTTPText txt;

    HTTPResult r = http.get(url, &txt);
    if(r==HTTP_OK) {
        printf("Surfing result :\"%s\"\n", txt.gets()); 
    }//if
    else {
        printf("Surfing error %d\n", r);
    }//else
}//surf


//doorbell interrupt code here
//remember not to put any large operations in the interrupt handler
void dingdong() {
   doorint = true;       
}//dingdong


//load lipsync data from bmf file to array in RAM
void load_lipsync(char syncfile[]) {
   printf("Reading lipsync from sd file\n");
   FILE * pFile = fopen (syncfile , "r");
   if (pFile != NULL) {
     fgets (lipmoves , 300 , pFile);
     printf("Lipmoves file is: %s\n", lipmoves);
     fclose (pFile);
   }//if
}//lipsync


//mouth function is attached to movetick ticker
//and it moves billys mouth when activated
void mouth() {
   if(lippos < 300) {
      suu1 = 0;

      char tmpmrk;
      tmpmrk = lipmoves[lippos];
      int num = atoi(&tmpmrk);
      //printf("suu on %d  ", num);
      suu2 = num;
      lippos++;
   }//if
}//mouth


void body_move(int secs) {
    printf("making body move %d",secs);
    ruu2 = 1;
    wait(secs);
    ruu2 = 0;
}


//tail flapping function
void tail_flap(int howmany) {
    for(int i=0;i<howmany;i++) {
      ruu1=1;
      wait(0.2);
      ruu1=ruu2=0;
      wait(0.2);
    }//for
    wait(0.3);
}//tailflap


void play_wave(char *wavname, bool lipmoves) {

    //enable audio amps via relay 1
    relay1=1;
  
    unsigned chunk_id,chunk_size,channel;
    unsigned data,samp_int,i;
    short dac_data;
    char *slice_buf;
    short *data_sptr;
    FMT_STRUCT wav_format;
    FILE *wavfile;
    long slice,num_slices;
    DAC_wptr=0;
    DAC_rptr=0;

    size_t result;

    for (i=0;i<256;i+=2) {
        DAC_fifo[i]=0;
        DAC_fifo[i+1]=3000;
    }
    DAC_wptr=4;
    DAC_on=0;

    printf("Playing wave file '%s'\r\n",wavname);

    wavfile=fopen(wavname,"rb");
    if (!wavfile) {
        printf("Unable to open wav file '%s'\r\n",wavname);
        exit(1);
    }

    fread(&chunk_id,4,1,wavfile);
    fread(&chunk_size,4,1,wavfile);
    while (!feof(wavfile)) {
        printf("Read chunk ID 0x%x, size 0x%x\r\n",chunk_id,chunk_size);
        switch (chunk_id) {
            case 0x46464952:
                fread(&data,4,1,wavfile);
                printf("RIFF chunk\r\n");
                printf("  chunk size %d (0x%x)\r\n",chunk_size,chunk_size);
                printf("  RIFF type 0x%x\r\n",data);
                break;
            case 0x20746d66:
                fread(&wav_format,sizeof(wav_format),1,wavfile);
                printf("FORMAT chunk\r\n");
                printf("  chunk size %d (0x%x)\r\n",chunk_size,chunk_size);
                printf("  compression code %d\r\n",wav_format.comp_code);
                printf("  %d channels\r\n",wav_format.num_channels);
                printf("  %d samples/sec\r\n",wav_format.sample_rate);
                printf("  %d bytes/sec\r\n",wav_format.avg_Bps);
                printf("  block align %d\r\n",wav_format.block_align);
                printf("  %d bits per sample\r\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);
                }
                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\r\n");
                printf("  chunk size %d (0x%x)\r\n",chunk_size,chunk_size);
                printf("  %d slices\r\n",num_slices);
                printf("  Ideal sample interval=%d\r\n",(unsigned)(1000000.0/wav_format.sample_rate));
                samp_int=1000000/(wav_format.sample_rate);
                printf("  programmed interrupt tick interval=%d\r\n",samp_int);

// starting up ticker to write samples out -- no printfs until tick.detach is called
                if(lipmoves==true) {
                    lippos = 0; //reset lipmoves position counter
                    movetick.attach(&mouth, SAYSPEED);
                }
                tick.attach_us(&dac_out, samp_int);
               
                DAC_on=1;
                for (slice=0;slice<num_slices;slice+=SLICE_BUF_SIZE) {

                    result = fread(slice_buf,wav_format.block_align*SLICE_BUF_SIZE,1,wavfile);
                    if (feof(wavfile)) {
                        printf("Oops -- not enough slices in the wave file\r\n");

                        break;
                    }

                    data_sptr=(short *)slice_buf;
                    for (i=0;i<SLICE_BUF_SIZE;i++) {
                        dac_data=0;

// for a stereo wave file average the two channels.
                        for (channel=0;channel<wav_format.num_channels;channel++) {
                            switch (wav_format.sig_bps) {
                                case 16:
                                    dac_data+=(  ((int)(*data_sptr++)) +32768 );
                                    break;
                                case 8:
                                    dac_data+=(  ((int)(*data_sptr++)) +32768 <<8);
                                    break;
                            }
                        }
                        DAC_fifo[DAC_wptr]=dac_data;
                        DAC_wptr=(DAC_wptr+1) & 0xff;
                        while (DAC_wptr==DAC_rptr) {
                            wait_us(10);
                        }
                    }
                }
                DAC_on=0;
                suu1 = suu2 = 0;
                tick.detach();
                if(lipmoves==true) {
                    movetick.detach();
                }
                printf("Tickers detached\r\n");
                free(slice_buf);
                break;
            case 0x5453494c:
                printf("INFO chunk, size %d\r\n",chunk_size);
                fseek(wavfile,chunk_size,SEEK_CUR);
                break;
            default:
                printf("unknown chunk type 0x%x, size %d\r\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 ++++++++++\r\n");
    fclose(wavfile);
    
    //disable audio amps via relay 1
    relay1=0;
}//play-wave


void dac_out() {
    if (DAC_on) {
        DACout.write_u16(DAC_fifo[DAC_rptr]);
        DAC_rptr=(DAC_rptr+1) & 0xff;
    }//if
}//dac-out