home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-10-12 | 46.8 KB | 1,448 lines |
- 8 PARALLEL DEVICE
-
- 8.1 INTRODUCTION
-
- All Amiga models have a parallel port to which you can connect
- external devices like a printer, a video digitizer or a sound
- sampler. The most common external device for the parallel port
- is undoubtedly a printer, although some printers are connected
- to the serial device.
-
- The parallel port can send and receive eight bits
- simultaneously. This can be compared with the serial port which
- only can send/receive a stream of bits. The parallel port
- is because of this much faster and is therefore often used for
- video digitizers or sound samplers.
-
- The parallel device helps you to work with the printer at a
- very low level, but is still easy to handle. The parallel
- device can as the serial device be locked for exclusive access
- or you can allow other programs to use the device
- simultaneously.
-
- It is important to note that the parallel device should only be
- used when you want to handle the port directly at a low level.
- This can be useful when you want to collect data from a video
- digitizer, or send untranslated printer codes. However, if you
- simply want to use the printer you should use the printer
- device instead. The printer device will automatically take care
- of all printer handling, and is using the preference settings.
- See next chapter (29) "Printer Device".
-
-
-
- 8.2 PARALLEL PORT
-
- A parallel port sends a whole byte each time as explained above,
- and is therefore very fast. Data that is sent to or received
- from the parallel port does not need to be translated in any
- way, it is immediately usable.
-
- The Amiga's parallel (Centronics) port is a 25-pin D-female-
- type connector. (On the old A1000s the parallel port have a
- male connector.) Below is an almost complete list of the pin
- assignment, together with a short description. (See
- illustration "Centronics".)
-
-
- Pin Name Direction Description
- -----------------------------------------------------
- 1 STROBE Out Used to coordinate the events
- 2 Data 0 In/Out Bit 0
- 3 Data 1 In/Out Bit 1
- 4 Data 2 In/Out Bit 2
- 5 Data 3 In/Out Bit 3
- 6 Data 4 In/Out Bit 4
- 7 Data 5 In/Out Bit 5
- 8 Data 6 In/Out Bit 6
- 9 Data 7 In/Out Bit 7
- 10 ACK In Data acknowledge
- 11 BUSY In/Out General Input/Output pin
- 12 POUT In/Out General Input/Output pin
- 13 SEL In/Out General Input/Output pin
- 14 +5V - +5 Volt
- 15 NC In/Out No connection pin
- 16 RESET Out The system resets
- 17 GND - Signal ground
- 18 GND - Signal ground
- 19 GND - Signal ground
- 20 GND - Signal ground
- 21 GND - Signal ground
- 22 GND - Signal ground
- 23 GND - Signal ground
- 24 GND - Signal ground
- 25 GND - Signal ground
-
-
-
- 8.3 PARALLEL DEVICE
-
- The parallel device is very similar to the serial device. It
- can either be used in exclusive mode, or several programs may
- use the port simultaneously, shared access. When you want that
- the parallel device to do something you simply send an already
- initialized request block (struct IOExtPar), and the device
- will send a message to the reply port when the request has been
- done. Exactly as all other devices.
-
-
-
- 8.3.1 THE PARALLEL REQUESTBLOCK
-
- The request block you should use with the parallel device look
- like this: (defined in header file "devices/parallel.h")
-
- struct IOExtPar
- {
- struct IOStdReq IOPar;
- ULONG io_PExtFlags;
- UBYTE io_Status;
- UBYTE io_ParFlags;
- struct IOPArray io_PTermArray;
- };
-
- IOPar: This is the standard request block. The IOStdReq
- structure is defined in header file "exec/io.h",
- and is fully documented in chapter 17 "Devices".
-
- io_PExtFlags: This is currently not used, but will maybe be
- used in the future when more parallel flags are
- needed.
-
- io_Status: The status of the parallel port and parallel
- device. There exist for the moment four
- status flags:
-
- IOPTF_RWDIR If this flag is set the device
- is currently writing to the
- parallel device. On the other
- hand, if the flag is not set
- the device is collecting data
- at the parallel port.
-
- IOPTF_PARSEL Printer selected.
-
- IOPTF_PAPEROUT The printer ran out of paper.
- Inform the user!
-
- IOPTF_PARBUSY The parallel port is currently
- busy.
-
- Use the command "PDCMD_QUERY" before you look at
- these fields to make sure everything is up to
- date.
-
- io_ParFlags: This field contains all special parallel flags.
- There exist only three flags for the moment, and
- one of these is still not usable. Here is the
- complete list:
-
- PARF_SHARED Set this flag if you want to
- share the parallel port with
- other programs. Note that this
- flag should only be altered
- before you have opened the
- parallel device, and should
- NOT be changed later on.
-
- If you want to change status
- you should close the parallel
- device, alter the status and
- then try to open the device
- again.
-
- PARF_RAD_BOOGIE This flag is currently not
- used. It is supposed to be
- set when you want to send/
- receive data at a very high
- speed.
-
- PARF_EOFMODE This is actually the only
- flag you may alter after you
- have opened the device. If
- the flag is set the parallel
- device will immediately
- stop the transmission of data
- when it finds one of the
- specified end-of-file
- characters.
-
- io_PTermArray: This field contains eight characters which will
- be treated as the end-of-file characters if the
- PARF_EOFMODE flag is set.
-
-
-
- 8.3.2 OPEN THE PARALLEL DEVICE
-
- As with all devices you have to open a message port through
- which the parallel device can communicate with you, and
- allocate a request block (a IOExtPar structure), before you
- may open the device itself.
-
- 1. Open a message port: (Since it is only our task and the
- device that will use the message port, we do not need
- to make it "public", hence no name. Priority should as
- usual be set to 0, normal priority.)
-
- struct MsgPort *replymp;
-
- replymp = (struct MsgPort *)
- CreatePort( NULL, 0 );
-
- if( !replymp )
- clean_up( "Could not create the reply port!" );
-
-
- 2. Allocate a request block of type IOExtPar structure.
- (The IOExtPar structure is an extended version of the
- normal request block, and should therefore be allocated
- with help of the CreateExtIO() function with the size
- set to sizeof( struct IOExtPar ).
-
- struct IOExtPar *parallel_req;
-
- parallel_req = (struct IOExtPar *)
- CreateExtIO( replymp, sizeof( struct IOExtPar ) );
-
- if( !parallel_req )
- clean_up( "Not enough memory!" );
-
-
- Once the message port and the request block have successfully
- been created, you need to decide if you want exclusive or
- shared access. If you want shared access, other programs may
- also use the parallel port, should you set the flag
- "PARF_SHARED" in the io_ParFlags" field. If you want exclusive
- access you do not need to set any flags, since it is the
- default mode.
-
- 3. Either set shared or exclusive access, and open the
- device.
-
- UBYTE error;
-
- /* We want shared access: */
- parallel_req->io_ParFlags = PARF_SHARED;
-
- /* Open the parallel device: */
- error = OpenDevice( PARALLELNAME, 0, parallel_req, 0 );
-
- if( error )
- clean_up( "Could not open the Parallel Device!" );
-
-
-
- 8.3.3 SET PARALLEL PARAMETERS
-
- Once you have successfully opened the parallel device you
- may set some parameters that tells the device how it should
- work. Luckily, the parallel device is much simpler than the
- serial device.
-
- For the moment there exist only one parallel flag you may use,
- and that is PARF_EOFMODE. It should be set if you want the
- device to immediately stop the current communication if one of
- the eight specified end-of-file characters appears. To set the
- flag do like this:
-
- /* Look for end-of-file characters: */
- parallel_req->io_ParFlags += PARF_EOFMODE;
-
- Note that we used the sign "+=". This is very useful if you
- want to set one flag (bit), but keep all others unchanged. If
- we simply used the sign "=" the "PARF_SHARED" flag we
- previously had set would be erased. We could of course have
- written it like this:
-
- /* Set both the end-of-file and shared mode: */
- parallel_req->io_ParFlags = PARF_EOFMODE | PARF_SHARED;
-
- This is however not equally good, since it is easy to forget
- one flag, and then it would be erased. So if you want to
- add flags use the command "+=". To erase one flag you only
- have to do the opposite and subtract it ("-=").
-
- If you want to use the end-of-file mode, and have set the
- "PARF_EOFMODE" flag, you must also tell the device which
- characters should be treated as end-of-file characters. The
- list of these characters is stored in the "IOPArra" array
- which is placed at the bottom of the request structure, and
- looks like this:
-
- struct IOPArray
- {
- ULONG PTermArray0;
- ULONG PTermArray1;
- };
-
- Each ULONG data consists of four bytes, and in total you can
- store eight bytes (end-of-file characters) in the array. To
- make the checking routine efficient you must store the
- characters in descending order! To copy the desired
- characters into the array do like this:
-
- /* Here is an array with all EOF characters: */
- /* NOTE! They MUST be in descending order! */
- UBYTE eof_char[8]={ 0x54, 0x32, 0x16, 0x15, 0x12, 0x03, 0x00, 0x00 };
-
- /* Declare a unsigned byte pointer: */
- UBYTE *ptr;
-
- /* Simple loop variable: */
- int loop;
-
- ...
-
- /* Get the address of the IOTArray: */
- ptr = (UBYTE *) &(ioreq->io_PTermArray);
-
- /* Set all eight end of file characters: */
- for( loop=0; loop < 8; loop++ )
- {
- /* Copy character after character: */
- *ptr = eof_chars[ loop ];
-
- /* Step one byte forward: */
- ptr++;
- }
-
-
- Once you have set all desired parameters in the request block
- (IOExtPar structure) you set the IO command to PDCMD_SETPARAMS
- and tell the parallel device to do your request by calling the
- DoIO() function. If something went wrong DoIO() will return
- with an error number, else 0 is returned which means that your
- request have successfully been executed. (See below for a
- complete list of error messages.) Here is an example:
-
- /* We want to set the parallel device's parameters: */
- ioreq->IOPar.io_Command = PDCMD_SETPARAMS;
-
- /* Do our request, and return when done: */
- error = DoIO( ioreq );
-
-
-
- 8.3.4 WRITE DATA
-
- To send data to the parallel device you have to:
-
- 1. Set the command flag "CMD_WRITE" in the "io_Command"
- field.
-
- 2. Tell the parallel device how many bytes you want to send
- by setting the "io_Length" field as desired. If you set it
- to -1 the device will continuously send data and stop
- first when an end-of-file character is found. (The end-of-
- file character will also be sent.) Note that the parallel
- flag "PARF_EOFMODE" must have been set, or the device will
- never stop sending data.
-
- 3. Give the field "io_Data" the address of the first byte of
- data that should be sent.
-
- 4. Finally you send the request to the parallel device. If
- you want to wait for the request to be completed
- (synchronous) you should use the DoIO() function. On the
- other hand, if you want that your program continues to
- work while your request is completed, you should use the
- SendIO() function.
-
- Here is an example on how to write data to the parallel port:
- (In this example the program will be put to sleep while the data
- is sent to the parallel port.)
-
- error: (UBYTE) is a simple unsigned byte variable.
-
- ioreq: (struct IOExtPar *) is a pointer to an IOExtPar
- structure.
-
- data: (BYTE) is a pointer to a block of memory where all
- data you want to send is located.
-
-
- /* We want to send (write) some data: */
- ioreq->IOPar.io_Command = CMD_WRITE;
-
- /* Give the start address of our data buffer: */
- ioreq->IOPar.io_Data = data;
-
- /* We want to send 150 bytes/characters: */
- ioreq->IOPar.io_Length = 150;
-
- /* Do our request: */
- error = DoIO( ioreq );
-
- /* Everything OK? */
- if( error )
- printf( "Problems while writing!\n" );
-
-
- If you do not want to wait for the request to be completed you
- should use the SendIO() function instead. To check later if the
- request have been completed or not you can either use the
- function CheckIO(), or wait for a message to arrive at the
- request block's reply port. (Since other request may also send
- messages to this port, it is usually easiest to use CheckIO().)
-
- Once the request have been completed you can look at the
- io_Error field of the request block to check if everything
- was OK. If the field is zero everything was executed without
- any problems, but if it is non zero the request failed.
-
- Here is an example:
-
- /* Declare a pointer and set it to NULL: */
- struct IOExtPar *ptr = NULL;
-
- ...
-
-
- /* We want to send (write) some data: */
- ioreq->IOPar.io_Command = CMD_WRITE;
-
- /* Give the start address of our data buffer: */
- ioreq->IOPar.io_Data = data;
-
- /* We want to send 280 bytes/characters: */
- ioreq->IOPar.io_Length = 280;
-
- /* Do our request and return immediately: */
- SendIO( ioreq );
-
-
- /* As long as the pointer is not pointing to */
- /* the request we should stay in the loop: */
- while( ptr == NULL )
- {
- ... do something ...
-
-
- /* Check if the request has been completed: (If the */
- /* request has been completed CheckIO() will return */
- /* a pointer to the request, else NULL is returned.) */
- ptr = CheckIO( ioreq );
- }
-
- /* Remove the requst block's message. (The ptr and ioreq */
- /* are in this example identical, so it does not matter */
- /* whichever you will use. The parenthesis around the */
- /* expression is actually unnecessary, but this looks */
- /* better.) */
- Remove( &(ptr->IOPar.io_Message.mn_Node) );
-
- /* Everything OK? Check the io_Error filed: */
- if( ioreq->IOPar.io_Error )
- printf( "Problems while writing!\n" );
-
-
-
- 8.3.5 READ DATA
-
- Although most people use the parallel port to send data to their
- printer, more and more users connect other external devices
- like video digitzers and sound samplers. With these devices
- you do not only need to send data, you also have to collect
- data from the parallel port.
-
- The process of collecting (reading) is very similar to reading.
- Here is what you have to do:
-
- 1. Set the command flag "CMD_READ" in the "io_Command"
- field.
-
- 2. Tell the parallel device how many bytes you want to read
- by setting the "io_Length" field as desired. If you set it
- to -1 the device will continuously read data and stop
- first when an end-of-file character is received. (The end-
- of-file character will also be collected.) Note that the
- parallel flag "PARF_EOFMODE" must have been set, or the
- device will never stop collecting data.
-
- 3. Give the field "io_Data" a pointer to your data buffer
- where all collected data should be placed. Note that the
- buffer must be big enough so all data will fit!
-
- 4. Finally you send the request to the parallel device. If
- you want to wait for the request to be completed
- (synchronous) you should as usual use the DoIO() function.
- On the other hand, if you want that your program
- continues to work while your request is completed, you
- should use the SendIO() function.
-
- Here is an example on how to read data: (Your program will be
- put to sleep while the data is collected.)
-
- error: (UBYTE) is a simple unsigned byte variable.
-
- ioreq: (struct IOExtPar *) is a pointer to an IOExtPar
- structure.
-
- data: (BYTE) is a pointer to a block of memory where all
- data which is collected will be stored. Note that the
- data buffer must be big enough so all data will fit.
-
-
- /* We want to read some data: */
- ioreq->IOPar.io_Command = CMD_READ;
-
- /* Give the start address of our data buffer: */
- ioreq->IOPar.io_Data = data;
-
- /* We want to read 400 bytes/characters: (The buffer must */
- /* then be at least 400 bytes.) */
- ioreq->IOPar.io_Length = 400;
-
- /* Do our request: */
- error = DoIO( ioreq );
-
- /* Everything OK? */
- if( error )
- printf( "Problems while reading!\n" );
-
-
- The program above will go to sleep while the data is collected
- from the parallel port. If you want to do something while the
- data is fetched and not go to sleep you should use the
- asynchronous function SendIO() function as explained above.
- Here is an example:
-
- /* Declare a pointer and set it to NULL: */
- struct IOExtPar *ptr = NULL;
-
- ...
-
-
- /* We want to read some data: */
- ioreq->IOPar.io_Command = CMD_READ;
-
- /* Give the start address of our data buffer: */
- ioreq->IOPar.io_Data = data;
-
- /* We want to read 400 bytes/characters: (The buffer must */
- /* then be at least 400 bytes.) */
- ioreq->IOPar.io_Length = 400;
-
- /* Do our request and return immediately: */
- SendIO( ioreq );
-
-
- /* As long as the pointer is not pointing to */
- /* the request we should stay in the loop: */
- while( ptr == NULL )
- {
- ... do something ...
-
-
- /* Check if the request has been completed: (If the */
- /* request has been completed CheckIO() will return */
- /* a pointer to the request, else NULL is returned.) */
- ptr = CheckIO( ioreq );
- }
-
- /* Remove the requst block's message. (The ptr and ioreq */
- /* are in this example identical, so it does not matter */
- /* whichever you will use. The parenthesis around the */
- /* expression is actually unnecessary, but this looks */
- /* better.) */
- Remove( &(ptr->IOPar.io_Message.mn_Node) );
-
- /* Everything OK? Check the io_Error filed: */
- if( ioreq->IOPar.io_Error )
- printf( "Problems while reading!\n" );
-
-
-
- 8.3.6 HOW TO HANDLE SEVERAL REQUESTS SIMULTANIOUSLY
-
- Since you usually will want to read and write data at the same
- time, you have to use two separate request blocks. If you are
- using shared access mode you simply create two request blocks
- and open the parallel device twice. (Do not forget to close
- both requests later on.) Here is an example:
-
- struct MsgPort *replymp;
- struct IOExtPar *parallel_req_read;
- struct IOExtPar *parallel_req_write;
- UBYTE error;
-
-
- /* We use only one reply message port: */
- replymp = (struct MsgPort *)
- CreatePort( NULL, 0 );
- if( !replymp )
- clean_up( "Could not create the reply port!" );
-
-
- /* Create the request block "read": */
- parallel_req_read = (struct IOExtPar *)
- CreateExtIO( replymp, sizeof( struct IOExtPar ) );
- if( !parallel_req_read )
- clean_up( "Not enough memory!" );
- parallel_req_read->io_ParFlags = PARF_EOFMODE | PARF_SHARED;
-
- /* Create the request block "write": */
- parallel_req_write = (struct IOExtPar *)
- CreateExtIO( replymp, sizeof( struct IOExtPar ) );
- if( !parallel_req_write )
- clean_up( "Not enough memory!" );
- parallel_req_write->io_ParFlags = PARF_EOFMODE | PARF_SHARED;
-
-
- /* Open the parallel device for the read request: */
- error = OpenDevice( PARALLELNAME, 0, parallel_req_read, 0 );
- if( error )
- clean_up( "Could not open the parallel device (Read)!" );
-
- /* Open the parallel device for the write request: */
- error = OpenDevice( PARALLELNAME, 0, parallel_req_write, 0 );
- if( error )
- clean_up( "Could not open the parallel device (Write)!" );
-
-
-
- If you are using exclusive access mode you can of course not
- open the parallel device twice. Instead we have to copy the
- first request block to the other request block, byte for byte.
- Here is an example:
-
- struct MsgPort *replymp;
- struct IOExtPar *parallel_req_read;
- struct IOExtPar *parallel_req_write;
- BYTE *r_ptr;
- BYTE *w_ptr;
- UBYTE error;
- int loop;
-
-
- /* We use only one reply message port: */
- replymp = (struct MsgPort *)
- CreatePort( NULL, 0 );
- if( !replymp )
- clean_up( "Could not create the reply port!" );
-
-
- /* Create the request block "read": */
- parallel_req_read = (struct IOExtPar *)
- CreateExtIO( replymp, sizeof( struct IOExtPar ) );
- if( !parallel_req_read )
- clean_up( "Not enough memory!" );
- parallel_req_read->io_ParFlags = PARF_EOFMODE | PARF_SHARED;
-
- /* Create the request block "write": */
- parallel_req_write = (struct IOExtPar *)
- CreateExtIO( replymp, sizeof( struct IOExtPar ) );
- if( !parallel_req_write )
- clean_up( "Not enough memory!" );
- parallel_req_write->io_ParFlags = PARF_EOFMODE | PARF_SHARED;
-
-
- /* Open the parallel device for the read request: */
- error = OpenDevice( PARALLELNAME, 0, parallel_req_read, 0 );
- if( error )
- clean_up( "Could not open the Parallel Device (Read)!" );
-
-
- /* Since we can not open the parallel device once again */
- /* for the write request, we have to copy the whole */
- /* read request block into the write request block. */
-
- /* Get the start address of both request blocks: */
- r_ptr = (BYTE *) parallel_req_read;
- w_ptr = (BYTE *) parallel_req_write;
-
- /* Copy the request block, byte by byte: */
- for( loop=0; loop < sizeof( struct IOExtPar ); loop++ )
- {
- /* Copy one byte: */
- *w_ptr = *r_ptr;
-
- /* Step one byte forward: */
- w_ptr++;
- r_ptr++;
- }
-
-
- Now we have two request blocks, and can therefore use both
- read and write requests at the same time. If you also want to
- use the special extra functions described further down, you
- may want to create even one more request block (or maybe
- even more...). The procedure is the same as described above.
-
-
-
- 8.3.7 ERRORS
-
- While you are using the parallel device you may sometimes
- encounter an error message. Usually it is easy to guess what
- went wrong, but it is always good to check what really happened.
- There exit for the moment seven different types of parallel
- port errors, all defined in the header file "devices/
- parallel.h".
-
- You will either receive the error message from the function you
- just called (for example, DoIO() returns 0 or an error number),
- or you can check the request block to see if there were any
- problems. (The io_Error filed of the request block either
- contains 0, which means everything is OK, or an error number.)
-
- Here is a complete list of the parallel error messages:
-
- ParErr_DevBusy Some other task/request is already using
- the parallel device.
-
- ParErr_BufTooBig: Buffer too big. Hey, what is this?
-
- ParErr_InvParam: The request block's parameters were not
- properly initialized.
-
- ParErr_LineErr: There were some problems with the
- communication. The parallel cable is
- faulty or the other device is not
- properly initialized or not connected.
- Tell the user to check the cables!
-
- ParErr_NotOpen: The parallel device was not open!
-
- ParErr_PortReset: The parallel device have just been
- resetted. Someone just sent a CMD_Reset
- request. Default parameters are
- set.
-
- ParErr_InitErr: The parallel device could not be
- initialized with your requirements.
- (Probably forgot to clear all unused
- flags.)
-
-
- While you are using the parallel device it may happen that you
- also receive error messages from Exec. (Exec is handling all
- stuff like messages, requests, tasks and so on.) Here is
- a complete list of exec error messages: (defined in the header
- file "exec/errors.h")
-
- IOERR_OPENFAIL The device (unit) could not be opened. (If you
- are denied access to the parallel device you
- should receive the ParErr_DevBusy flag instead
- of this exec message, but internally this flag
- is used.)
-
- IOERR_ABORTED When you abort a previously started request by
- calling the AbortIO() function, the io_Error
- filed of that request is set to IOERR_ABORTED.
- If you find a request block with this flag set,
- you know that it has been aborted.
-
- IOERR_NOCMD You tried to use a command that is not
- supported by the parallel device.
-
- IOERR_BADLENGTH The length of the request was not valid.
-
-
-
- 8.3.8 CLEAN UP
-
- As usual on the Amiga you must remember to close and return
- everything you have opened or allocated. If you do not close
- the parallel device after you, other programs will then not
- be able to use the it. PLEASE be very careful about this!
-
- The routine is very similar to how you close the serial device
- which was described in the previous chapter. However this is
- so important that it can not be said too often.
-
- Here is a list of what you have to do:
-
- 1. All requests you have started with SendIO() or BeginIO()
- (asynchronous commands) must either have been completed
- or aborted before you may close the device. It is a very
- common error to forget this, and it can be hard to find
- this bug. Usually the program will work fine (the command
- was completed in time), but now and then your program will
- crash (the command was completed after the device have
- been closed).
-
- A simple way is to abort all commands that have not
- reported that they have been completed, but this is not
- always good way to do it. (The last commands may be
- important and should therefore not be aborted.)
-
- If you do not want to abort the command, you should
- instead wait for it to be completed. The WaitIO()
- function is simple to use, and will put your program
- to sleep while waiting, so no computer time is wasted.
- If the request has already been completed, the function
- will return immediately. WaitIO() will also remove the
- message from the reply port. It is a very useful and
- simple function to use, but do NOT try to wait for
- a request that has not been started!
-
- Here is an example on how to wait for a request to be
- completed: (If the request already has been completed
- it does not matter, WaitIO() will then simply return
- immediately. Note that we do not have to remove any
- messages from the reply port if we use WaitIO().)
-
- /* Store possible error numbers here: */
- UBYTE error;
-
- /* ... */
-
- /* Wait for the request to be completed: */
- error = WaitIO( ioreq );
-
- /* Everything OK? */
- if( error )
- printf( "Something went wrong!" );
-
- /* Well, successful or not, we may now */
- /* close the device! */
-
-
- To abort a request, simply use the AbortIO() function:
-
- /* Try to abort a previously started request: */
- /* (Do not try to abort a request that has not */
- /* been started.) */
- AbortIO( ioreq );
-
-
- 2. When all requests have been completed or aborted you may
- close the parallel device. (Requests that have been
- executed by calling the DoIO() function have already been
- completed before your program wakes up, and thus you do
- not need to wait for these.)
-
- The parallel device is closed as all other devices, by
- calling the CloseDevice() function. Here is an example:
-
- /* Close the Parallel Device: */
- if( !parallel_dever )
- CloseDevice( ioreq );
-
-
- 3. You should now return all request blocks you have
- allocated. If you allocated a standard sized request block
- by calling the CreateStdIO() function, you should free
- it by calling the DeleteStdIO() function. However, if
- you have allocated an extended request block (like the
- parallel device's request blocks) by calling the
- CreateExtIO() function, you MUST call the DeleteExtIO(),
- and of course remove the same amount of data as you
- allocated.
-
- How to delete a standard request block: (Since it is of
- the standard size, you do not need to specify any size.)
-
- /* Deallocate a standard sized request block: */
- DeleteStdIO( ioreq );
-
- With extended request block you have to specify the size
- as you did when you allocated it:
-
- /* Deallocate an extended request block: */
- /* (The size may vary depending on what */
- /* device it was used for.) */
- DeleteExtIO( ioreq, sizeof( struct IOExtSer ) );
-
- Note that ALL request blocks that have been allocated,
- must be removed!
-
-
- 4. Finally you should close all message ports you have
- previously opened. Simply use the DeletePort() function
- as this example demonstrates:
-
- /* Remove the replyport: */
- DeletePort( replymp);
-
-
- Please be careful with how your program terminates! Your
- program should not only run fine, but it should also allow
- other programs to run after and simultaneously. Remember that
- your program must also be able to quit nice and neatly even if
- it had to terminate too early because of some fatal error. The
- cleaning up should only be done where it is needed, and if you
- have not allocated the memory or opened the device before your
- program quits, you should of course NOT try to free these
- resources! If you do the Amiga will most certainly crash! Too
- many programs contain this very annoying error. Make sure yours
- will not be the same.
-
- The best way to manage this cleaning up routine is to write a
- separate function which checks each thing before it frees it.
- The idea is that you may call this routine at any time, and it
- will still manage to clear everything properly. Here is an
- example: (Note how we check each thing to see if it should be
- removed!)
-
- /* Close and return everything that has been */
- /* opened and allocated before we quit: */
- void clean_up()
- {
- /* 1. Close the Parallel Device: */
- if( !parallel_dever )
- CloseDevice( parallel_req );
-
- /* 2. Deallocate the parallel request block: */
- if( parallel_req )
- DeleteExtIO( parallel_req, sizeof( struct IOExtPar ) );
-
- /* 3. Remove the replyport: */
- if( replymp )
- DeletePort( replymp);
-
- /* 4. Quit: */
- exit( 0 );
- }
-
- Comments: 1. The parallel_dever is a variable that we have
- declared ourself, and is used only to determine
- if the device has been opened or not. (The
- variable is set to TRUE before the program
- starts, and is only changed to FALSE after
- a successful opening of the device. See the
- included examples for more information.) We
- should of course only close the device if
- the parallel_dever is FALSE. ("parallel_dever"
- stands for "parallel device error".)
-
- 2. The parallel_req is a pointer which is either
- pointing to a request block, or NULL if no
- request block has been allocated. We should
- of course only free the request block if there
- exist one.
-
- 3. The replymp is a pointer which is either
- pointing to a message port, or NULL if no message
- port has been opened. And of course, we should
- only close the message port if it has been
- opened.
-
- 4. Finally our program may terminate. The exit()
- function is placed here so we are sure the
- program will quit. (If we did not have this
- exit(), our function would then return the
- control to our program again, and then we would
- be in deep s*#^%.)
-
-
-
- 8.4 A COMPLETE EXAMPLE
-
- Here is a complete example that opens the parallel device, sets
- all necessary parameters, sends some data, collects some data
- (well actually only 0 bytes) and finally cleans up and quits.
- Since we send the read and write requests after each other (the
- first is completed before the other is started) we only need to
- use one request block.
-
-
- #include <exec/types.h>
- #include <devices/parallel.h>
-
-
- /* Declare a pointer to our reply port: */
- struct MsgPort *replymp = NULL;
-
- /* Declare a pointer to our parallel request block: */
- struct IOExtPar *parallel_req = NULL;
-
- /* Store the parallel device error here: */
- UWORD parallel_dever = TRUE;
-
- /* Declare our own data buffer: */
- /* (Last byte is a NULL sign.) */
- BYTE buffer[] = "Anders Bjerin was here...";
-
-
- /* Declare our functions: */
- void main();
- void clean_up( STRPTR text );
-
- void main()
- {
- int loop;
- UBYTE *ptr;
- UBYTE error;
-
- /* The eight end-of-file characters: */
- UBYTE eof_char[8]={ 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00 };
-
-
-
- /* OPEN THE PARALLEL DEVICE: */
-
- /* Get a reply port: (No name, priority 0) */
- replymp = (struct MsgPort *)
- CreatePort( NULL, 0 );
- if( !replymp )
- clean_up( "Could not create the reply port!" );
-
- /* Create a parallel request block: */
- parallel_req = (struct IOExtPar *)
- CreateExtIO( replymp, sizeof( struct IOExtPar ) );
- if( !parallel_req )
- clean_up( "Not enough memory for the parallel request block!" );
-
-
- /* Since we want exclusive access mode, we do not set the */
- /* parallel flag "PARF_SHARED", which otherwise must have */
- /* been set before the device is opened. To make sure the */
- /* field is empty we set it to 0: */
- parallel_req->io_ParFlags = 0;
-
-
- /* Open the Parallel Device: */
- parallel_dever = OpenDevice( PARALLELNAME, 0, parallel_req, 0 );
- if( parallel_dever )
- clean_up( "Could not open the Parallel Device!" );
-
-
-
-
- /* SET THE REST OF THE PARALLEL PARAMETERS (not many): */
-
- /* Check for end-of-file characters: */
- parallel_req->io_ParFlags = PARF_EOFMODE;
-
- /* No additional flags: */
- parallel_req->io_PExtFlags = NULL;
-
- /* Set all eight end of file characters: */
- ptr = (UBYTE *) &(parallel_req->io_PTermArray);
- for( loop=0; loop < 8; loop++ )
- {
- /* Copy character after character: */
- *ptr = eof_char[ loop ];
-
- /* Step one byte forward: */
- ptr++;
- }
-
- /* All values have now been set, lets */
- /* do a PDCMD_SETPARAMS request: */
- parallel_req->IOPar.io_Command = PDCMD_SETPARAMS;
-
- /* Do our request: */
- error = DoIO( parallel_req );
- if( error )
- clean_up( "Could not set the parallel parameters!" );
-
-
-
- /* SEND DATA TO THE PARALLEL PORT: */
-
- /* We want to send (write) some data: */
- parallel_req->IOPar.io_Command = CMD_WRITE;
-
- /* Give the start address of our data: */
- parallel_req->IOPar.io_Data = (APTR) buffer;
-
- /* We want to send data until we find a NULL sign: */
- /* (The NULL sign was specified in the EOF-char.) */
- parallel_req->IOPar.io_Length = -1;
-
- /* Do our request: */
- error = DoIO( parallel_req );
- if( error )
- clean_up( "Could not send data to the parallel port!" );
-
-
-
- /* READ DATA FROM THE PARALLEL DEVICE: */
-
- /* We want to read some data: */
- parallel_req->IOPar.io_Command = CMD_READ;
-
- /* Give the start address of our buffer: */
- parallel_req->IOPar.io_Data = (APTR) buffer;
-
- /* We want to read 0 bytes: */
- /* (Since most of you do not have anything which sends data */
- /* to the parallel device, I do not want to wait for more */
- /* than 0 bytes to arrive.) */
- parallel_req->IOPar.io_Length = 0;
-
- /* Do our request: */
- error = DoIO( parallel_req );
- if( error )
- clean_up( "Could not read data from the parallel port!" );
-
-
-
- /* THE END: */
- clean_up( "The End" );
- }
-
-
- /* Close and return everything that has been */
- /* opened and allocated before we quit: */
- void clean_up( STRPTR text )
- {
- /* Close the Parallel Device: */
- if( !parallel_dever )
- CloseDevice( parallel_req );
-
- /* Deallocate the parallel request block: */
- if( parallel_req )
- DeleteExtIO( parallel_req, sizeof( struct IOExtPar ) );
-
- /* Remove the replyport: */
- if( replymp )
- DeletePort( replymp);
-
- /* Print the message: */
- printf( "\n%s\n", text );
-
- /* Quit: */
- exit( 0 );
- }
-
-
- 8.5 OTHER USEFUL COMMANDS
-
- Although reading and writing are most commonly used commands,
- there exist some other functions that can sometimes be needed.
- Here is a complete list of commands that can be sent with help
- of a request block:
-
- 1. Flush, removes all queued requests.
- 2. Query, get some information from the parallel device.
- 3. Reset, reinitializes the parallel device.
- 4. Start, restarts the parallel communication.
- 5. Stop, temporary stops the parallel communication.
-
-
-
- 8.5.1 FLUSH
-
- If several requests are sent to the parallel device they are
- all queued on a FIFO (First In First Out) basis. The command
- "CMD_FLUSH" can then be used to remove all these queued
- commands. Here is an example:
-
- /* We want to remove all queued requests: */
- ioreq->IOPar.io_Command = CMD_FLUSH;
-
- /* Do our request: */
- error = DoIO( ioreq );
-
- /* OK? */
- if( error )
- printf( "Could not remove the queued requests!\n" );
-
-
-
- 8.5.2 QUERY
-
- The command "PDCMD_QUERY" can be used to get some information
- from the parallel device. It is useful if you want to see if
- the paper is out, printer is busy or if it is currently writing
- or reading. All this can be found in the "io_Status" field of
- the request structure, as this table shows:
-
- Name Bit Hex Active Description
- ------------------------------------------------------------
- IOPTF_PARBUSY 0 0x01 Low Printer is selected
- IOPTF_PAPEROUT 1 0x02 Low Paper out
- IOPTF_PARSEL 2 0x04 Low Printer is busy
- IOPTF_RWDIR 3 0x08 - Reading (0) or Writing (1)
- - 4 0x10 - Reserved
- - 5 0x20 - Reserved
- - 6 0x40 - Reserved
- - 7 0x80 - Reserved
- ------------------------------------------------------------
-
- Here is an example:
-
- /* Check the parallel device: */
- ioreq->IOPar.io_Command = PDCMD_QUERY;
-
- /* Do our request: */
- error = DoIO( ioreq );
-
- /* OK? */
- if( error )
- printf( "Could not get any information from the device!\n" );
- else
- {
- /* Check the "io_Status" field: */
- if( ioreq->io_Status & IOPTF_PARBUSY )
- printf( "Printer is busy.\n" );
-
- if( ioreq->io_Status & IOPTF_PAPEROUT )
- printf( "Paper out!\n" );
-
- if( ioreq->io_Status & IOPTF_PARSEL )
- printf( "Printer selected!\n" );
-
- printf( "Device is %s\n",
- ioreq->io_Status & IOPTF_RWDIR ? "Writing" : "Reading" );
- }
-
-
-
- 8.5.3 RESET
-
- Send the command "CMD_RESET" to reset the parallel device. All
- commands that are queued to the device will be removed, commands
- that are currently executed will be aborted all parallel flags
- are resetted. Here is an example:
-
- /* We want to reset the parallel device: */
- ioreq->IOPar.io_Command = CMD_RESET;
-
- /* Do our request: */
- error = DoIO( ioreq );
-
- /* OK? */
- if( error )
- printf( "Could not reset the parallel device!\n" );
-
-
-
- 8.5.4 START
-
- After you have stopped the parallel communication by sending an
- CMD_STOP command, you may want to start the communication again.
- It is done by sending a CMD_START command. Here is an example:
-
- /* We want to start parallel communication again: */
- ioreq->IOPar.io_Command = CMD_START;
-
- /* Do our request: */
- error = DoIO( ioreq );
-
- /* OK? */
- if( error )
- printf( "Could not start the parallel communication!\n" );
-
-
-
- 8.5.5 STOP
-
- To temporary stop all parallel communication you send a CMD_STOP
- command. The communication will then first start again when a
- CMD_START command is broadcasted. Here is an example:
-
- /* We want to temporary stop all parallel communication: */
- ioreq->IOPar.io_Command = CMD_STOP;
-
- /* Do our request: */
- error = DoIO( ioreq );
-
- /* OK? */
- if( error )
- printf( "Could not stop the parallel communication!\n" );
-
-
-
- 8.6 FUNCTIONS
-
-
- DoIO()
-
- DoIO() is used to send requests to a device, and waits for it
- to be completed. While the program is waiting it is put to
- sleep so it will not waste any computer time. DoIO() will
- return first when the request have been completed or failed,
- and no message is therefore sent to the reply port.
-
- Synopsis: error = DoIO( req );
-
- error: (long) DoIO() will return first when the request has
- been completed or something has failed. If the
- request was successfully completed zero is returned,
- else an error number is returned. What error number
- depends on which device was used.
-
- req: (struct IORequest *) Pointer to the request you
- want to have executed.
-
-
- SendIO()
-
- SendIO() is used to send requests to a device, but will
- return immediately without any delay. To check if the request
- have been completed use the CheckIO() function, or look
- at the request's reply port for any messages. Once the
- request has been completed you must remove the message at
- the reply port. (CheckIO() will not do it.) To remove a
- message use the function Remove(). Note that you may NOT
- close the device before all requests have been completed or
- aborted!
-
- Synopsis: SendIO( req )
-
- req: (struct IORequest *) Pointer to the request you
- want to have executed.
-
-
- CheckIO()
-
- CheckIO() is used to check if a previously started request
- has been completed. Note that this function will not remove
- the message at the reply port. This must be done with the
- Remove() function.
-
- Synopsis: ptr = CheckIO( req );
-
- ptr: (long) CheckIO() will either return NULL if the
- request have not been completed or it will return a
- pointer to the request block.
-
- req: (struct IORequest *) Pointer to the request you
- want to check.
-
-
- WaitIO()
-
- WaitIO() will wait for the request to be completed, and while
- the program is waiting it is put to sleep so no computer time
- is wasted.
-
- Synopsis: error = WaitIO( req );
-
- error: (long) WaitIO() will return first when the request,
- that has previously been sent, has been completed or
- something has failed. If the request was successfully
- completed zero is returned, else an error number is
- returned. What error number depends on which device
- was used.
-
- req: (struct IORequest *) Pointer to the request you
- want to wait for to be completed. Note that the
- request must have already been sent to the device
- by either a SendIO() or BeginIO() function call.
-
-
- BeginIO()
-
- BeginIO() is a low level form of the SendIO() function. The
- advantage with BeginIO() is that no fields of the request
- block will be altered as which is the case with SendIO().
- With the parallel device you should only use SendIO().
-
- Synopsis: BeginIO( req )
-
- req: (struct IORequest *) Pointer to the request you
- want to have executed.
-
-
- AbortIO()
-
- AbortIO() will try to abort a previously started request. This
- function should be used sparsely since it does not look so
- good if you start a request and the try to stop it. (Better
- not start it at all.) However, it is easy, and can sometimes
- be very useful.
-
- A request that is aborted will have its io_Error field set
- to IOERR_ABORTED (defined in header file "exec/errors.h").
-
- Synopsis: AbortIO( req )
-
- req: (struct IORequest *) Pointer to the request you
- want to abort.
-
-
- CloseDevice()
-
- CloseDevice() will (surprise!) close a device. Note that you
- should NOT close the device before all started asynchronous
- requests have either been completed or aborted.
-
- Synopsis: CloseDevice( ioreq );
-
- ioreg: (struct IORequest *) Pointer to the device's
- request block.
-
-
- OpenDevice()
-
- OpenDevice() will try to open the specified device.
-
- Synopsis: error = OpenDevice( name, unit, req, flags );
-
- error: (long) If OpenDevice() managed to open the device
- it returns 0, else an error number is returned.
- If you try to open the parallel device, and there is
- already a program that is using it, the error
- message "ParErr_DevBusy" is returned.
-
- name: (char *) Name of the device you want to open.
- The name of the parallel device is defined as
- PARALLELNAME in header file "devices/parallel.h".
-
- unit: (long) Which unit you want to open. Since there
- exist only one parallel port, this field is ignored.
-
- req: (struct IORequest *) Pointer to a request block.
- For the parallel device it must be a pointer to an
- extender parallel request block (struct IOExtPar).
-
- flags: (long) Any special mode is set here. Ignored by
- the parallel device.
-
-
-
- 8.7 COMMANDS
-
- Here is a complete list of commands you may send to the
- parallel device. For full documentation se examples above.
-
- The special parallel device commands: (Defined in header file
- "devices/parallel.h")
-
- PDCMD_QUERY Check the status of the parallel device.
- PDCMD_SETPARAMS Set the parameters of the parallel device.
-
-
- The rest of the commands you may use are normal exec commands,
- and are defined in header file "exec/io.h".
-
- CMD_RESET Resets all parameters of the parallel device.
- CMD_READ Read data from the parallel port.
- CMD_WRITE Write data to the parallel port.
- CMD_STOP Temporary stops all parallel communication.
- CMD_START Restarts parallel communication.
- CMD_FLUSH Removes all queued requests.
-
-
-
- 8.8 EXAMPLES
-
- Example 1
- This program demonstrates how you can use the Parallel Device.
- It does not do very much since I do not know what you have
- connected to your parallel port, but with small modifications
- you should be able to write your own parallel communication
- packages.
-
- Example 2
- This example is rather similar to Example 1, but this time
- we do not wait for the parallel port to complete our request.
- Instead we do somethings (well not very much) and now and
- then checks if the request has been completed.
-
- Example 3
- This example is rather similar to Example 1, but this time
- we do not wait for the parallel port to complete our request.
- We are also trying to read and write at the same time. To be
- able to do several requests simultaneously we need one request
- block for each command. In this example we use three separate
- request blocks.
-
- Example4
- This example does not do anything, but it consists of
- several useful functions that you can use yourself after
- small modifications. The functions demonstrates all
- commands there exist for the parallel device, so if you
- had problems in understanding how a command was used you
- can look here.
-
-
-