/* * Celestial Fusion * Software for digitized engine data acquisition and processing * * Author: James McCrae */ #include #include #include #define RESOLUTIONX 640 #define RESOLUTIONY 480 #define TACHBUSADDR 0 #define SPEEDBUSADDR 1 #define NUMINPUTSAMPLES 40 #define NUMINPUTSENSORS 2 //Vehicle specific constants #define MAXTACHOMETERRANGE 8000.0 #define TACHOMETERREDLINE 5500.0 /* Class declarations */ class Poll { public: Poll(); void setTimestamp(double timestamp); void setReading(unsigned char reading); double getTimestamp(); unsigned char getReading(); private: double timestamp; unsigned char reading; }; class ParallelPortIO { public: bool IOinit(int portaddress); void setSimulated(bool simulated); bool getSimulated(); Poll *obtainPolls(int busaddress); void resetInputSequence(); void addPoll(int whichsensor, double timestamp, unsigned char reading); private: Poll inputsequence[NUMINPUTSENSORS][NUMINPUTSAMPLES]; int beginindex[NUMINPUTSENSORS]; bool simulated; }; class Simulator { public: Simulator(); void update(ParallelPortIO *ppio); private: int state; float rpm; float speed; int gear; int curpulses; double eventtimestamp; }; class GUI { public: GUI(); void update(ParallelPortIO *ppio); void setCurrentScreen(int screen); private: double lastupdate; int currentscreen; BITMAP *doublebuffer; BITMAP *logo; BITMAP *optionmenu; BITMAP *tachometer; BITMAP *numbers[10]; BITMAP *needle; BITMAP *whiteline; BITMAP *smallredline; BITMAP *bigredline; BITMAP *rpmx1000; void drawTachometer(ParallelPortIO *ppio); }; /* Function declarations */ void alleg_init(); /* Main Method */ int main(int argc, char ** argv) { //set up parallel port IO ParallelPortIO ppio; //set up simulator (used if needed) Simulator sim; //input may be simulated - specified by -S command line parameter if (argc==2) { if (strcmp(argv[1],"-S")==0) { ppio.setSimulated(true); } } else if (argc>2) { exit(-1); } //set up environment alleg_init(); //set up GUI GUI g; do { sim.update(&ppio); g.update(&ppio); rest(50); } while (true); } /* * Sets up keyboard, timer and graphics mode. */ void alleg_init() { if (allegro_init()!=0) { exit(1); } install_keyboard(); set_color_depth(8); set_gfx_mode(GFX_AUTODETECT,RESOLUTIONX,RESOLUTIONY,0,0); } void ParallelPortIO::setSimulated(bool simulated) { this->simulated=simulated; } bool ParallelPortIO::getSimulated() { return simulated; } /* * Note: To be used by Simulator only */ void ParallelPortIO::addPoll(int whichsensor, double timestamp, unsigned char reading) { //set reading and timestamp for poll inputsequence[whichsensor][beginindex[whichsensor]].setReading(reading); inputsequence[whichsensor][beginindex[whichsensor]].setTimestamp(timestamp); //iterate to next poll element in array beginindex[whichsensor]++; beginindex[whichsensor]=beginindex[whichsensor]%NUMINPUTSAMPLES; } Poll *ParallelPortIO::obtainPolls(int busaddress) { return inputsequence[busaddress]; } GUI::GUI() { float numx; float numy; int count=0; int eachnum=0; doublebuffer=create_bitmap(RESOLUTIONX,RESOLUTIONY); logo=load_pcx("images/upperlogo.pcx",NULL); optionmenu=load_pcx("images/optionmenu.pcx",NULL); numbers[0]=load_pcx("images/0.pcx",NULL); numbers[1]=load_pcx("images/1.pcx",NULL); numbers[2]=load_pcx("images/2.pcx",NULL); numbers[3]=load_pcx("images/3.pcx",NULL); numbers[4]=load_pcx("images/4.pcx",NULL); numbers[5]=load_pcx("images/5.pcx",NULL); numbers[6]=load_pcx("images/6.pcx",NULL); numbers[7]=load_pcx("images/7.pcx",NULL); numbers[8]=load_pcx("images/8.pcx",NULL); numbers[9]=load_pcx("images/9.pcx",NULL); needle=load_pcx("images/needle.pcx",NULL); whiteline=load_pcx("images/whiteline.pcx",NULL); smallredline=load_pcx("images/smallredline.pcx",NULL); bigredline=load_pcx("images/bigredline.pcx",NULL); rpmx1000=load_pcx("images/rpmx1000.pcx",NULL); //prepare image of tachometer tachometer=create_bitmap(RESOLUTIONX*3/4,RESOLUTIONY); for (float i=-45.0;i<=225.0;i+=270.0*(200.0/MAXTACHOMETERRANGE)) { count=count%5; if (count==0) { numx=cos((i*256.0/360.0)+128.0)*170.0; numy=sin((i*256.0/360.0)+128.0)*170.0; draw_sprite(tachometer,numbers[eachnum],RESOLUTIONX*3/8+(int)numx-12,RESOLUTIONY/2+(int)numy-12); eachnum++; } if ((i+45.0)/270.0>TACHOMETERREDLINE/MAXTACHOMETERRANGE) pivot_sprite(tachometer,bigredline,RESOLUTIONX*3/8,RESOLUTIONY/2,150,5,ftofix(i*256.0/360.0)); else { if (count==0) { pivot_sprite(tachometer,whiteline,RESOLUTIONX*3/8,RESOLUTIONY/2,150,5,ftofix(i*256.0/360.0)); } else pivot_sprite(tachometer,smallredline,RESOLUTIONX*3/8,RESOLUTIONY/2,150,5,ftofix(i*256.0/360.0)); } count++; } draw_sprite(tachometer,rpmx1000,RESOLUTIONX*3/8-35,RESOLUTIONY/2+100); lastupdate=double(clock()); currentscreen=0; } void GUI::update(ParallelPortIO *ppio) { int keyread; //update only 5 times per second if ((double(clock())-lastupdate)/CLOCKS_PER_SEC<=0.2) return; lastupdate=double(clock()); clear_to_color(doublebuffer,16); draw_sprite(doublebuffer,logo,0,0); //main menu if (currentscreen==0) { draw_sprite(doublebuffer,optionmenu,50,100); } //tachometer else if (currentscreen==1) { drawTachometer(ppio); } draw_sprite(screen,doublebuffer,0,0); //handle keypresses if (keypressed()) { keyread=readkey(); //for debugging if ((keyread&0xff)=='q') exit(0); if (currentscreen==0) { //main menu if ((keyread&0xff)=='1') currentscreen=1; } else //otherwise return to it currentscreen=0; } clear_keybuf(); } void GUI::drawTachometer(ParallelPortIO *ppio) { //trace out tachometer by rotating along an origin //"fixed" is an allegro-specific unit of measure for an angle //a 32-bit data structure that represents a fixed point number //(a complete circle in "fixed" is represented by 256) Poll *currentpolls; int count; float calculatedrpm; float needleangle; draw_sprite(doublebuffer,tachometer,RESOLUTIONX/8,RESOLUTIONY/8); //process polls and calculate the rpm calculatedrpm=0.0; count=0; currentpolls=ppio->obtainPolls(TACHBUSADDR); for (int i=0;ireading=reading; } void Poll::setTimestamp(double timestamp) { this->timestamp=timestamp; } double Poll::getTimestamp() { return timestamp; } unsigned char Poll::getReading() { return reading; } Simulator::Simulator() { state=0; rpm=800; speed=0; gear=1; curpulses=0; eventtimestamp=double(clock()); } void Simulator::update(ParallelPortIO *ppio) { double deltatime=(double(clock())-eventtimestamp)/CLOCKS_PER_SEC; float deltarpm; int newreading; if (state==0) { deltarpm=-1000; } else if (state==1) { deltarpm=1000; } else if (state==2) { deltarpm=800; } else if (state==3) { deltarpm=600; } else if (state==4) { deltarpm=400; } else if (state==5) { deltarpm=200; } rpm+=deltarpm*deltatime; eventtimestamp=double(clock()); //create new poll with eventtimestamp and approximate reading newreading=(unsigned char)(rpm*deltatime/60.0); ppio->addPoll(TACHBUSADDR,eventtimestamp,newreading); //state change if (state!=0) { if (rpm>3500) { rpm=1600; state++; gear=state; } if (state>5) state=0; } else if (state==0) { if (rpm<=800) state=1; } }