Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Advanced C 1992

.pdf
Скачиваний:
96
Добавлен:
17.08.2013
Размер:
4.28 Mб
Скачать

Part II • Managing Data in C

Listing 9.6. continued

{

--nMoneyVertical;

}

break; case 1:

if (--nMoneyVertical < 1)

{

++nMoneyVertical;

}

break; case 2:

if (++nMoneyHorizontal > MAX_WIDTH)

{

--nMoneyHorizontal;

}

break; case 3:

if (--nMoneyHorizontal < 1)

{

++nMoneyHorizontal;

}

break;

default:

break;

}

if (nMoneyHorizontal == nHorizontal && nMoneyVertical == nVertical)

{

--nMoneyHorizontal; --nMoneyVertical;

}

printf(MOVE_CURSOR, nMoneyVertical, nMoneyHorizontal);

printf(“$”); /* Display the money */

printf(MOVE_CURSOR, nVertical, nHorizontal);

}

286

Disk Files and Other I/O

C C C

 

C9C

 

C C C

 

C

}

}

return (0);

}

First the program and the screen are initialized. Standard stream I/O statements are used because they are easy to use. No sense in doing more work than is necessary! Then the screen is cleared, and the target (the dollar sign) is placed at position 10, 10. The chaser (the question mark) is then placed at position 0, 0, and the game begins.

A while loop polls the keyboard. When a key is pressed, kbhit() returns TRUE, allowing the program to read the keypress, as follows:

if (kbhit())

{/* A key has been pressed, so process it as necessary */ chChar = getch();

if (chChar == (char)NULL)

{

chChar = getch();

If the first call to getch() returns zero, an extended key (probably an arrow key) has been pressed. If the return is nonzero, an ASCII key has been pressed. The only nonextended key that interests us is ESC, which ends the game.

After a key has been pressed, a new location for the chaser is computed. If the chaser has landed on the target’s position, the speaker beeps. Try playing the game— it’s harder than it seems!

If no key has been pressed, the program checks how long it has been since the target moved. Every half second, if no key is pressed, the target moves one square in a random direction. This time period makes the game more playable. (Otherwise, on a fast CPU, the target would be all over the screen, and you could never hit it.)

All moves in ARCADE are kept in the bounds of the screen. In addition, the target cannot move to the same position as the chaser—the game should never lose by its own choice!

287

Part II • Managing Data in C

Direct Port I/O

This section assumes that you are programming on an IBM compatible PC. If you are using another type of computer, some of the discussion in this section may not apply.

Direct port I/O can be dangerous because the program is interacting with the hardware at a basic level. Because there is no error checking, you can seriously damage the information on your hard disk.

! ! ! ! ! ! ! !

! ! ! ! !

! ! ! ! ! ! ! !

! ! ! ! !

! ! ! ! ! ! ! !

! ! !

! !

! ! ! ! ! ! ! ! ! ! ! ! !

! ! ! ! ! ! ! ! ! ! ! ! !

! ! ! ! ! ! ! ! ! ! ! ! !

! ! ! ! ! ! ! ! ! ! ! ! !

If you are writing software that uses direct port I/O, back up your hard disk!

Direct port I/O is system dependent, not only on the type of computer, but also on the computer’s configuration. In this section, the assumption is that you are programming on an IBM compatible PC. If you are using another type of computer, this section may not apply.

The CPU uses the I/O ports to communicate with all the various peripherals, such as the communication ports, the printer ports, and the keyboard. Peripherals are connected to the CPU by interface cards (these may be part of the motherboard). The direct port I/O functions are shown in Table 9.4.

Table 9.4. Direct I/O functions.

I/O function Description

inp()

inpw()

outp()

outpw()

Inputs a byte of data from the specified port

Inputs two bytes of data from the specified port

Outputs a byte of data to the specified port

Outputs two bytes of data to the specified port

288

Disk Files and Other I/O

C C C

 

C9C

 

C C C

 

C

The return type is always type int, so you should use only the first byte in functions that process byte-size data objects. Both output functions return the byte or word that was output. The input functions return the currently input byte or word.

The PC Printer Ports

The PC supports up to three printer ports. The addresses for the printer ports are in the BIOS data area, at segment 0040, as follows: 0040:0008 for LPT1, 0040:000A for LPT2, and 0040:000C for LPT3. Typical addresses for printer ports are 0x0378 or 0x03BC. Although there are standard addresses for the printer I/O, your program could use any I/O address that is defined by the system.

Listing 9.7, PRNPORT.C, prints to the printer a single string, followed by a form-feed character. (The form-feed character forces laser printers to print the page.) The program prints directly, without calling the DOS or the BIOS routines.

Listing 9.7. PRNPORT.C.

/* PRNPORT, written 1992 by Peter D. Hipson

*This program prints directly to the printer’s port.

*The program should be run under DOS on a PC. If your

*computer is not PC-compatible, do not run this program.

*The program should also be compiled with Microsoft C. */

#include <stdio.h>

// Make includes first part of file

#include <conio.h>

// Console I/O functions

#include <string.h>

// For string functions

#include <stdlib.h>

// Standard include items

#include <process.h>

// For exit(), etc.

#include <time.h>

// To seed random numbers

#define

MAKELONG(low, high)

((long)(((unsigned short int)(low)) \

| (((unsigned long

int)((unsigned

short int)(high))) << 16)))

#define

MAKELP(sel,

off)

((void

_far*)MAKELONG((off), (sel)))

/* Printer port definitions

*/

 

continues

289

Part II • Managing Data in C

Listing 9.7. continued

#define BIOS_DATA_PAGE

 

0x0040

#define LPT1

 

0x0008

#define DATA_PORT

(nPort)

#define STATUS_PORT

(nPort + 1)

#define CONTROL_PORT

(nPort + 2)

#define STATUS_NORESP

 

0x01

#define STATUS_UNUSED1

 

0x02

#define STATUS_UNUSED2

 

0x04

#define STATUS_ERROR

 

0x08

#define STATUS_SELECTED

0x10

#define STATUS_NOPAPER

 

0x20

#define STATUS_ACK

 

0x40

#define STATUS_NOTBUSY

 

0x80

#define CONTROL_STROBE

 

0x01

#define CONTROL_AUTOFEED

0x02

#define CONTROL_INIT

 

0x04

#define CONTROL_SELECT

 

0x08

#define CONTROL_IRQ7

 

0x10

#define CONTROL_UNUSED1

0x20

#define CONTROL_UNUSED2

0x40

#define CONTROL_UNUSED3

0x80

/* End printer port definitions. */

int main(

// Define main() and the fact that this

int

argc, // program uses the passed parameters

char

*argv[],

char

*envp[]

);

 

int PrintCharacter(char chChar);

int

PrinterStatus(void);

int

main(

 

 

int

argc,

 

char

*argv[],

290

Disk Files and Other I/O

char

*envp[]

)

 

{

 

char

szNowIsTheTime[] = {

“Now is the time for all good men to come to the aid...\f”};

int

nStatus;

int

i;

if (!PrinterStatus())

{

printf(“There was a printer error!\n”); exit(4);

}

for (i = 0; i < strlen(szNowIsTheTime); i++)

{

if (PrintCharacter(szNowIsTheTime[i]) == 0)

{

printf(“\nCouldn’t print from ‘%s’\n”, &szNowIsTheTime[i]);

 

break;

 

}

}

 

return (0);

}

 

int

PrintCharacter(

char

chChar)

{

 

int _far

*pPrintPort;

int

nPort;

C C C

C9C C

C C C

continues

291

Part II • Managing Data in C

Listing 9.7. continued

int nStatus;

/* The PC’s printer port is at address 0040:0008

*(for LPT1:). If 0 is stored at that address,

*a printer port is not installed.

*/

pPrintPort = MAKELP(BIOS_DATA_PAGE, LPT1);

nPort = *pPrintPort;

if (nPort == 0)

{/* No printer is installed! */

printf(“No printer installed... WHY?\n”); return(0);

}

/* Write the data byte to the printer’s data lines */

outp(DATA_PORT, chChar);

/* Next, check to see if the printer is busy. */

nStatus = inp(STATUS_PORT);

if (!(nStatus & STATUS_NOTBUSY))

{/* The printer is busy. You should wait and try again */ printf(“The printer is busy?\n”);

return(0);

}

/* Set the strobe line */

outp(CONTROL_PORT, CONTROL_STROBE | CONTROL_INIT | CONTROL_SELECT);

/* Clear the strobe line */

outp(CONTROL_PORT, CONTROL_INIT | CONTROL_SELECT);

}

int PrinterStatus()

292

Disk Files and Other I/O

{

 

int _far

*pPrintPort;

int

nPort;

int

nStatus;

/* The PC’s printer port is at address 0040:0008

*(for LPT1:). If 0 is stored at that address,

*a printer port is not installed.

*/

pPrintPort = MAKELP(BIOS_DATA_PAGE, LPT1);

nPort = *pPrintPort;

if (nPort == 0)

{/* No printer is installed! */

printf(“No printer installed... WHY?\n”); return(0);

}

printf(“Printer vector = %lp Printer port %4.4X\n”, pPrintPort,

nPort);

nStatus = inp(DATA_PORT);

printf(“DATA port’s contents %2.2X (last character that was printed).\n”,

nStatus);

nStatus = inp(STATUS_PORT);

if (!(nStatus & STATUS_NORESP))

{

printf(“The printer did not respond. \n”);

}

else

{

C C C

C9C C

C C C

continues

293

Part II • Managing Data in C

Listing 9.7. continued

printf(“The printer is responding. \n”);

}

if (!(nStatus & STATUS_ERROR))

{

printf(“The printer is signaling an error. \n”);

}

else

{

printf(“The printer is signaling no errors. \n”);

}

if (nStatus & STATUS_SELECTED)

{

printf(“The printer is currently selected. \n”);

}

else

{

printf(“The printer is not selected. \n”);

}

if (nStatus & STATUS_NOPAPER)

{

printf(“The printer is out of paper.\n”);

}

else

{

printf(“The printer has paper. \n”);

}

if (nStatus & STATUS_ACK)

{

printf(“The printer ACK line is set.\n”);

}

else

{

printf(“The printer ACK line is cleared.\n”);

}

294

Disk Files and Other I/O

if (nStatus & STATUS_NOTBUSY)

{

printf(“The printer is not busy.\n”);

}

else

{

printf(“The printer is currently busy. \n”);

}

return(1);

}

C C C

C9C C

C C C

The PRNPORT.C program shows how easy it is to print to a printer port using a high-level language such as C. Admittedly, this program cannot be used in its current state—the character print routines require more error checking and recovery. These improvements, however, would not be difficult to implement.

I have written custom printer drivers for the PC in C. Why? In one case, the printer (a special graphics printer with a high-speed interface) needed special timing and control signals, even though it used a Centronics type of connector and the same printer pins as other compatible printers.

A second use of the printer port is one that I think is more interesting than simply printing. In most PCs, the printer port is a bidirectional I/O port (it can both output data and read data) and as such can be used to communicate with all types of external devices.

A third use for custom drivers is for I/O boards that are not intended to be printer ports but have a similar structure. These boards are used for control and for special devices. It is not unusual for a special board to be used for graphic tablets (which might also use a serial port) or most tape drives, all of which need drivers.

You must write the driver in assembler (you can use in-line assembly if your compiler supports it) for the best control and performance. A C language driver is adequate, however, for initial development and for drivers with noncritical timing requirements.

295