_Real-Time Modleing with MS-DOS_ by David Bowling [LISTING ONE] #include #define TRUE -1 #define FALSE 0 void user_defined_background_task(); void set_up_user_background_task(); void set_down_user_background_task(); void set_up_user_real_time_task(); void set_down_user_real_time_task(); void set_up_real_time_task(); void set_down_real_time_task(); int not_done = TRUE; int over_run = FALSE; main(){ set_up_user_real_time_task(); /*initialization section*/ set_up_real_time_task(); set_up_user_background_task(); while( not_done && ! over_run){ /*background task loop*/ user_defined_background_task(); } set_down_real_time_task(); /*termination section*/ set_down_user_background_task(); set_down_user_real_time_task(); if( over_run ) printf("Error exit, frame over run\n"); } [LISTING TWO] void interrupt real_time_task(); void interrupt (*old_clock_func)(); void set_timer(); int user_define_divisor = 1; /*initialize in case user forgets*/ void set_up_real_time_task() { void interrupt (*getvect())(); old_clock_func = getvect( 0x08 );/*save original clock vector*/ setvect( 0x50, old_clock_func );/*store in unused location*/ setvect( 0x08, real_time_task ); /*overwrite with real-time*/ set_timer( user_define_divisor ); /*set system timer*/ } void set_down_real_time_task(){ setvect( 0x08, old_clock_func ); /*restore clock vector*/ set_timer( 1 ); /*reset system timer*/ } [LISTING THREE] int running = FALSE; int inter_count = 0; void interrupt real_time_task(){ enable(); if( !running && !over_run ){ running = TRUE; user_defined_real_time_task(); /*real-time function*/ }else{ over_run = TRUE; }; if( inter_count == user_define_divisor ){ geninterrupt( 0x50 ); /*call system clock*/ inter_count = 0; }else{ outport( 0x20, 0x20 ); /*8259 end of interrupt routine*/ inter_count += 1; }; running = FALSE; } [LISTING FOUR] void set_timer( divisor ) int divisor; { int cnt; int lo, hi; cnt = 65536 / divisor; lo = cnt % 256; hi = cnt / 256; outportb( 0x43, 0x36 ); outportb( 0x40, lo ); /*write tic counter*/ outportb( 0x40, hi ); } [LISTING FIVE] int i = 0; /* DATAPOOL */ user_defined_background_task(){ printf("i = %d\n", i ); } user_defined_real_time_function(){ i += 1; } [LISTING SIX] union{ char coprocessor_state[94]; int control_word; }float_save; /* save coprocessor state */ asm fsave float_save.coprocessor_state asm fldcw float_save.control_word . . . /* restore coprocessor state */ asm frstor float_save.coprocessor_state [LISTING SEVEN] while( not_done && ! over_run ){ /* non real-time debugging*/ user_defined_background_task(); user_defined_real_time_task(); } [LISTING EIGHT] #include #define TRUE -1 #define FALSE 0 void user_defined_background_task(); void set_up_user_background_task(); void set_down_user_background_task(); void set_up_user_real_time_task(); void set_down_user_real_time_task(); void set_up_real_time_task(); void set_down_real_time_task(); int not_done = TRUE; int over_run = FALSE; main(){ set_up_user_real_time_task(); /*initialization section*/ set_up_real_time_task(); set_up_user_background_task(); while( not_done && ! over_run){ /*background task loop*/ user_defined_background_task(); } set_down_real_time_task(); /*termination section*/ set_down_user_background_task(); set_down_user_real_time_task(); if( over_run ) printf("Error exit, frame over run\n"); } /******************************************************/ void interrupt real_time_task(); void interrupt (*old_clock_func)(); void set_timer(); int user_define_divisor = 1; /* initialize in case user forgets */ void set_up_real_time_task() { void interrupt (*getvect())(); old_clock_func = getvect( 0x08 ); /*save original clock vector*/ setvect( 0x50, old_clock_func ); /*store in unused location*/ setvect( 0x08, real_time_task ); /*overwrite with real-time*/ set_timer( user_define_divisor ); /*set system timer*/ } void set_down_real_time_task(){ setvect( 0x08, old_clock_func ); /*restore clock vector*/ set_timer( 1 ); /*reset system timer*/ } /******************************************************/ union{ char coprocessor_state[94]; int control_word; } float_save; int running = FALSE; int inter_count = 0; void interrupt real_time_task(){ /* save coprocessor state */ asm fsave float_save.coprocessor_state asm fldcw float_save.control_word enable(); if( !running && !over_run ){ running = TRUE; user_defined_real_time_task(); /*real-time function*/ }else{ over_run = TRUE; }; if( inter_count == user_define_divisor ){ geninterrupt( 0x50 ); /*call system clock*/ inter_count = 0; }else{ outport( 0x20, 0x20 ); /*8259 end of interrupt routine*/ inter_count += 1; }; running = FALSE; /* restore coprocessor state */ asm frstor float_save.coprocessor_state } /******************************************************/ void set_timer( divisor ) int divisor; { int cnt; int lo, hi; cnt = 65536 / divisor; lo = cnt % 256; hi = cnt / 256; outportb( 0x43, 0x36 ); outportb( 0x40, lo ); /*write tic counter*/ outportb( 0x40, hi ); } /******************************************************/ [LISTING NINE] double x; /* DATAPOOL */ extern int user_define_divisor; #define m 1.0134145 /* define spring-mass constants */ #define k 10.0 #define zeta 0.01 #define x_o 30.0 #define frame_time 0.013725 double t = 0.0; /* real-time */ double c1; /* real-time constants */ double c2; double c3; double c4; void set_up_user_real_time_task(){ double omega; double temp; double sqrt(); user_define_divisor = 4; /* set user divisor counter */ omega = sqrt( k / m ); temp = sqrt( 1.0 - zeta * zeta ); c1 = - zeta * omega; /* compute real-time constants */ c2 = zeta * x_o / temp; c3 = temp * omega; c4 = x_o; } void set_down_user_real_time_task(){ /* no set down necessary */ } void user_defined_real_time_task(){ double cos(); double sin(); double exp(); /* spring-mass model */ x = exp( c1 * t ) * ( c2 * sin( c3 * t ) + c4 * cos( c3 * t ) ); t += frame_time; } [LISTING TEN] #include "graphics.h" #define FALSE 0 #define TRUE -1 extern int not_done; extern double x; /* DATAPOOL */ int x_off = 320; int y_off = 100; stationary[11][4] = { { 0, 0, 0, -5 }, /* base */ { 0, 0, 7, 0 }, { -40, -5, 40, -5 }, { -35, -5, -30, -12 }, { -25, -5, -20, -12 }, { -15, -5, -10, -12 }, { -5, -5, 0, -12 }, { 5, -5, 10, -12 }, { 15, -5, 20, -12 }, { 25, -5, 30, -12 }, { 35, -5, 40, -12 } }; void set_up_user_background_task(){ int i, j; int g_driver = EGA; int g_mode = EGAHI; char d_path[] = {""}; int g_error; if( registerbgidriver( EGAVGA_driver ) < 0 ){ /* EGA driver */ printf("ERROR: can't register ega/vga driver\n"); exit(); }; initgraph( &g_driver, &g_mode, d_path ); g_error = graphresult(); if( g_error < 0 ){ printf("ERROR: %s\n", grapherrormsg(g_error) ); exit( 0 ); }; setcolor( YELLOW ); for( i = 0; i < 2; ++i ){ /* setup spring */ setactivepage( i ); for( j = 0; j < 11; ++j ){ line( stationary[j][0] + x_off, stationary[j][1] + y_off, stationary[j][2] + x_off, stationary[j][3] + y_off); }; }; } void set_down_user_background_task() { closegraph(); } double stretch[12][4] = { { 7.0, 0.0, -7.0, 5.0 }, /* spring */ { -7.0, 5.0, 7.0, 10.0 }, { 7.0, 10.0, -7.0, 15.0 }, { -7.0, 15.0, 7.0, 20.0 }, { 7.0, 20.0, -7.0, 25.0 }, { -7.0, 25.0, 7.0, 30.0 }, { 7.0, 30.0, -7.0, 35.0 }, { -7.0, 35.0, 7.0, 40.0 }, { 7.0, 40.0, -7.0, 45.0 }, { -7.0, 45.0, 7.0, 50.0 }, { 7.0, 50.0, -7.0, 55.0 }, { -7.0, 55.0, 7.0, 60.0 } }; int move[ 6][4] = { { -30, 5, 30, 5 }, /* mass */ { -30, 40, 30, 40 }, { -30, 5, -30, 40 }, { 30, 5, 30, 40 }, { 0, 0, 0, 5 }, { 0, 0, 7, 0 } }; void user_defined_background_task(){ double ratio; int x_spring; int i, j; static int start = 1; static int buff[2][100][4]; static int cnt[2]; static int b = 0; static int p = 0; if( start ){ set_page( p ); p = ( p )? 0: 1; setactivepage( p ); }; if( kbhit() ){ not_done = FALSE; }; x_spring = x + 30.0; ratio = 1.0 + ( (double)x / 60.0 ); cnt[b] = 0; setcolor( RED ); /* draw mass */ for( i = 0, j = cnt[b]; i < 6; ++i, ++j ){ buff[b][j][0] = move[i][0] + x_off; buff[b][j][1] = move[i][1] + y_off + x_spring + 30; buff[b][j][2] = move[i][2] + x_off; buff[b][j][3] = move[i][3] + y_off + x_spring + 30; line( buff[b][j][0], buff[b][j][1], buff[b][j][2], buff[b][j][3] ); }; cnt[b] += 6; setcolor( GREEN ); /* draw spring */ for( i = 0, j = cnt[b]; i < 12; ++i, ++j ){ buff[b][j][0] = stretch[i][0] + x_off; buff[b][j][1] = (int)( stretch[i][1] * ratio ) + y_off; buff[b][j][2] = stretch[i][2] + x_off; buff[b][j][3] = (int)( stretch[i][3] * ratio ) + y_off; line( buff[b][j][0], buff[b][j][1], buff[b][j][2], buff[b][j][3] ); }; cnt[b] += 12; b = ( b )? 0: 1; set_page( p ); p = ( p )? 0: 1; setactivepage( p ); /* switch page */ if( ! start ){ setcolor( BLACK ); /* undraw picture */ for( i = 0; i < cnt[b]; ++i ) line( buff[b][i][0], buff[b][i][1], buff[b][i][2], buff[b][i][3] ); }else{ start = 0; }; } set_page(n) /* set visual page */ int n; { int far *farptr; int addr; setvisualpage( n ); farptr = (int far *)0x00400063; /* status register address */ addr = *(farptr) + 6; while( ( inport( addr ) & 0x08 ) == 0x08 ); /* while in vert retrace */ while( ( inport( addr ) & 0x08 ) != 0x08 ); /* while not in vert retrace */ }