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