/***************************************************************************** * This is the root module for the IOD48 board demonstration for * * change of state interrupt programming. * *****************************************************************************/ #include #include #include #include #include unsigned int IOD48; /* starting value for IOD48 port address */ unsigned int IRQ_num; /* user selected irq number */ /* these are the port address offsets for reading and control of the IOD48 */ #define PORT0A 0x0000 #define PORT0B 0x0001 #define PORT0C 0x0002 #define PORT0CONTROL 0x0003 #define PORT1A 0x0004 #define PORT1B 0x0005 #define PORT1C 0x0006 #define PORT1CONTROL 0x0007 #define COSENABLE 0x000B #define CLRCOSINT 0x000F #define SET( value, mask ) value |= mask #define CLR( value, mask ) value &= (~mask) typedef enum {FALSE,TRUE} boolean; unsigned int isr_flag; /* used to indicate an interrupt occurred */ void interrupt far (*oldisr[16])(__CPPARGS); //global to store old handler pointer /***************************************************************************** * FUNCTION: IOD48_cos_enable -- export routine * * * * PURPOSE: To write the enable word passed to it to the IOD48 board. See * * IOD48 board manual for more information. * * * * INPUT: unsigned port: contains the board port address. * * char value: control value to write. * * * * OUTPUT: None. * * * * CALLS: None. * * * *****************************************************************************/ void IOD48_cos_enable(unsigned port,char value) { outportb(port + COSENABLE,value); /* send the byte */ } /* end IOD48_cos_enable */ /***************************************************************************** * FUNCTION: IOD48_clr_cos_int -- export routine * * * * PURPOSE: To write anything to this board address, clears any interrupts * * caused by change of state. * * * * INPUT: unsigned port: contains the board port address. * * * * OUTPUT: None. * * * * CALLS: None. * * * *****************************************************************************/ void IOD48_clr_cos_int(unsigned port) { outportb(port + CLRCOSINT,0); /* send anything */ } /* end IOD48_clr_cos_int */ /***************************************************************************** * FUNCTION: IOD48_read_port -- export routine * * * * PURPOSE: Reads the value contained at one of the 6 ports contained on * * the IOD48 board. * * * * INPUT: unsigned port: contains the board port address. * * unsigned offset: determines which port to read. * * * * OUTPUT: Returns the value read in from the board. * * * * CALLS: None. * * * *****************************************************************************/ unsigned IOD48_read_port(unsigned port,unsigned offset) { unsigned value; value = inportb(port + offset); return(value); } /* end IOD48_read_port */ /***************************************************************************** * FUNCTION: IOD48_port_control -- export routine * * * * PURPOSE: Writes the control word to the PPI indicated by offset. This * * word determines the direction of digital I/O as well mode. * * See IOD48 manual for more information. * * * * INPUT: unsigned port: contains the board port address. * * unsigned offset: determines which PPI to write to. * * char value: control word to write. * * * * OUTPUT: None. * * * * CALLS: None. * * * *****************************************************************************/ void IOD48_port_control(unsigned port,unsigned offset,char value) { outportb(port + offset,value); /* send the byte */ } /* end IOD48_port_control */ /* ****************************************************************************** FUNCTION initirq() RETURNS PARAMETERS PURPOSE ****************************************************************************** */ unsigned char initirq(char IRQnumber,void interrupt (*ISR)()) { unsigned char intmask, oldmask; if (IRQnumber <=7) { oldmask = inportb(0x21); oldisr[IRQnumber] = getvect(IRQnumber + 8); setvect(IRQnumber + 8,ISR); intmask = oldmask & (~(1 << IRQnumber)); outportb(0x21,intmask); } else { oldmask = inportb(0xA1); oldisr[IRQnumber] = getvect(IRQnumber + 0x70 - 8); setvect(IRQnumber - 8 + 0x70, ISR); intmask = oldmask & (~(1 << (IRQnumber - 8))); outportb(0xA1, intmask); } return(oldmask); } // end initirq /* ****************************************************************************** FUNCTION restoreirq() RETURNS PARAMETERS PURPOSE ****************************************************************************** */ void restoreirq(char IRQnumber) { unsigned char intmask; if (IRQnumber <=7 ){ intmask = inportb(0x21); intmask |= (1 << IRQnumber); setvect(IRQnumber + 8,oldisr[IRQnumber]); outportb(0x21, intmask); } else { intmask = inportb(0xA1); intmask |= (1 << (IRQnumber - 8)); setvect(IRQnumber - 8 + 0x70, oldisr[IRQnumber]); outportb(0xA1, intmask); } } // end restoreirq /***************************************************************************** * FUNCTION: signon -- local routine * * PURPOSE: To display an initial sign on message on the screen. * *****************************************************************************/ void signon(void) { clrscr(); gotoxy(6,2); puts(" I O D - 4 8 S I N T E R R U P T D E M O N S T R A T O R"); gotoxy(33,10); puts(" PORT READINGS"); gotoxy(5,12); puts(" PPI #0 PPI #1"); gotoxy(5,12); puts(" PORT A PORT B PORT C PORT A PORT B PORT C"); gotoxy(1,16); puts(" Flashing bits have changed!"); gotoxy(1,17); puts(" PRESS ANY KEY TO EXIT PROGRAM"); } /* end signon */ /***************************************************************************** * FUNCTION: write_port_data -- local routine * * PURPOSE: Displays the current port values on the screen. If a bit has * * changed, the bit is displayed flashing. * *****************************************************************************/ void write_port_data(unsigned current[6],unsigned compare[6]) { unsigned x,index,index1,value; x = 5; /* x coordinate to write value to screen */ for (index = 0;index <= 5;index++) /* for each array member */ { value = current[index]; for (index1 = 0;index1 <= 7;index1++) /* for each bit in array member */ { /* if not 0, then bit has changed, so write bit flashing */ gotoxy(x,14); if (compare[index] % 2) /* has changed, so flashing bit */ { textcolor(WHITE+BLINK); if (value % 2) cprintf("1"); else cprintf("0"); } else /* has not changed, write bit normally */ { textcolor(WHITE); if (value % 2) cprintf("1"); else cprintf("0"); } compare[index] = compare[index] >> 1; /* roll next compare bit */ value = value >> 1; /* roll next display bit */ x++; } x+=4; /* display distance between each port byte */ if (index == 2) x+=5; /* extra display distance between each PPI */ } textcolor(LIGHTGRAY); } /* end write_port_data */ /***************************************************************************** * FUNCTION: compare_ports -- local routine * * PURPOSE: Compares two sets of port readings passed to it. The compare * * array will have a one in each bit position that has changed. * *****************************************************************************/ void compare_ports(unsigned current[6],unsigned new[6],unsigned compare[6]) { unsigned index; for (index = 0;index <= 5;index++) /* for each port */ { /* does an XOR comparision which result will indicate bits that changed */ compare[index] = current[index] ^ new[index]; current[index] = new[index]; /* set new values as current values */ } } /* end compare_ports */ /***************************************************************************** * FUNCTION: setflag -- global routine * * PURPOSE: This is The interrupt service routine. It is called when the * * IOD48 board has detected a status change from the ports. The * * IOD48 asserts the IRQ 3, which is this routine. * *****************************************************************************/ void interrupt setflag() { disable(); /* do not allow further interrupts */ isr_flag = 1; /* indicate an interrupt has occurred */ } /* end setflag */ /***************************************************************************** * FUNCTION: read_all_IOD48_ports - local routine * * PURPOSE: Reads all six IOD48 ports. * *****************************************************************************/ void read_all_IOD48_ports(unsigned current[6],unsigned port) { current[0] = IOD48_read_port(port,PORT0A); current[1] = IOD48_read_port(port,PORT0B); current[2] = IOD48_read_port(port,PORT0C); current[3] = IOD48_read_port(port,PORT1A); current[4] = IOD48_read_port(port,PORT1B); current[5] = IOD48_read_port(port,PORT1C); } /* end read_all_IOD_ports */ /****************************************************************************** Function AskForBaseAddress Purpose: This function allows the user to input the address of the card. *****************************************************************************/ unsigned AskForBaseAddress(unsigned int OldOne) { char msg[7]; int NewOne = 0, Success = 0, Dummy; int AddrInputPosX, AddrInputPosY; puts("\nPlease enter the Base Address for your card (in hex)"); printf("or press ENTER for %X.\n>", OldOne); AddrInputPosX = wherex(); AddrInputPosY = wherey(); do { gotoxy(AddrInputPosX, AddrInputPosY); clreol(); msg[0] = 5; msg[1] = 0; cgets(msg); sscanf(msg + 2, "%x", &NewOne); Success = 1; Dummy = NewOne; if (msg[1] == 0) { gotoxy(AddrInputPosX, AddrInputPosY); printf("%X", OldOne); Success = 1; Dummy = OldOne; } } while(!Success); return (Dummy); } /* end of AskForBaseAddress */ #define IRQ_cursor_posx 1 #define IRQ_cursor_posy 12 #define IRQ_input_posx 2 #define IRQ_input_posy 14 #define addr_cursor_posx 1 #define addr_cursor_posy 7 #define addr_input_posx 2 #define addr_input_posy 9 unsigned AskForIRQ(unsigned int OldOne) { // displays options, collects 2 characters, checks range, loops 'til right // called with the default IRQ, returns the user's input char msg[8]; unsigned int NewOne, success = FALSE, dummy; gotoxy( IRQ_cursor_posx, IRQ_cursor_posy); printf( "Please enter the IRQ number (2-7, 10-12, 14, 15)\n" "or press ENTER for %i.\n>",OldOne); do{ /* input & error check */ gotoxy( IRQ_input_posx, IRQ_input_posy); printf( " \b\b\b\b"); msg[0]=3; msg[1]=0; // collect up to 2 characters cgets(msg); sscanf(msg+2,"%i",&NewOne); if(( NewOne <= 12 && NewOne >= 10) || ( NewOne <= 7 && NewOne >= 2) || ( NewOne == 15)) { success = TRUE; dummy = NewOne; } else if( EOF == sscanf(msg+2,"%i",&dummy)) { gotoxy( addr_input_posx, addr_input_posy); printf( " \b\b\b\b%i", OldOne); success = TRUE; dummy = OldOne; } } while( !success); clrscr(); return( dummy); } /***************************************************************************** * FUNCTION: main -- local routine * * PURPOSE: To perform the program control functions. * *****************************************************************************/ void main() { unsigned port; unsigned char old_mask,int_mask; void (interrupt far *oldisr)(); unsigned current[6],new[6],compare[6]; clrscr(); puts(" SAMPLE 1.C : INTERRUPT PROGRAMMING\n"); puts("This is the root module for the IOD48S board demonstration for"); puts("change of state interrupt programming."); gotoxy(1,7); puts("IOD48S BASE ADDRESS\n"); IOD48 = AskForBaseAddress(0x300); IRQ_num = AskForIRQ(5); clrscr(); printf("\n\n\nBoard Configuration:\n\n"); printf(" -- Base Address is %X hex\n",IOD48); printf(" -- The IRQ%i jumper should be installed (required)\n",IRQ_num); printf(" -- TST/BEN jumper should be in the BEN position (required)\n"); printf(" -- All remaining jumper settings are irrelevant.\n\n\n"); printf("Press a key to continue"); getch(); disable(); /* do notallow hardware interrupts */ signon(); /* print the start up message */ memset(compare,0,sizeof(compare)); port = IOD48; /* default port is 300 hex */ IOD48_cos_enable(port,0xff); /* turn off board interrupts */ isr_flag = 0; initirq(IRQ_num, setflag); IOD48_port_control(port,PORT0CONTROL,0x9b); /* set both PPI's as input */ IOD48_port_control(port,PORT1CONTROL,0x9b); read_all_IOD48_ports(current,port); /* make initial reading */ write_port_data(current,compare); /* display the values */ IOD48_clr_cos_int(port); /* clear any pending interrupt */ IOD48_cos_enable(port,0); /* enable all port for interrupts */ enable(); while(!kbhit()) /* loop until key pressed */ { /* other code can go here while waiting for an interrupt */ if (isr_flag) /* if flag set then interrupt has occurred */ { delay(40); read_all_IOD48_ports(new,port); /* read the new values */ compare_ports(current,new,compare); /* determine what has changed */ write_port_data(current,compare); /* write new data to screen */ isr_flag = 0; enable(); /* allow hardware interrupts */ IOD48_clr_cos_int(port); /* clear pending interrupts */ IOD48_cos_enable(port,0); /* enable all ports for interrupts */ if( IRQ_num < 8) outportb(0x20,0x20); /* clear 8259 interrupt */ else /* ditto */ { outportb( 0x20, 0x20); // non-specific EOI, slave outportb( 0xa0, 0x20); // non_specific EOI, master } } }; disable(); /* disable hardware interrupts */ IOD48_cos_enable(port,0xff); /* disable all board interrupts */ IOD48_clr_cos_int(port); /* clear pending interrupts */ restoreirq(IRQ_num); enable(); /* allow hardware interrupts */ clrscr(); if( !getch()) getch(); } /* end main program */