_Real-Time Modleing with MS-DOS_
by David Bowling
[LISTING ONE]
#include <dos.h>
#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 <dos.h>
#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 */
}