Engineering 15 Project

Aron Dobos

15 December 2005

 

Parallel Port Communication Interface to the ADuC7026 Microcontroller

 

Abstract

 

A parallel port interface between a host PC and the ADuC7026 microcontroller was implemented.  A communication protocol was designed and implemented in C/C++ on both the PC and microcontroller, and the necessary hardware adaptor was built to allow the device to be connected to the standard DB-25 parallel port. With the host operating in standard parallel port (SPP) mode, data transfer rates of 83.3 kbytes/sec were achieved using full software handshaking for concurrency.  The communication interface will be used in a PC-based time domain reflectometer (TDR) instrument next semester.

 

Microcontroller Overview

 

The Analog Devices ADuC7026 is a 32-bit ARM7 microcontroller designed for embedded data acquisition.  It provides 4 built-in 12-bit D/A converters as well as a 12 channel 12-bit A/D converter with 1MS/s capability, as well as general purpose programmable timers, pulse width modulation, a programmable logic array (PLA), RS-232, and of course a few general purpose I/O ports.   Port 3 was designated as the bi-directional data port, and the lower nibble of port 4 was reserved as control lines.  While the serial port could have been used to achieve bidirectional connectivity with the host PC, higher data transfer rates were desired to allow for more waveforms to be transferred per second in the intended TDR instrument application.

 

Host PC Overview

 

The PC parallel port operating in standard mode (SPP) was used.  The parallel port consists of three registers/ports.  The 8-bit data port was originally designed by IBM as output only, but nearly all relatively recent implementations allow the data port to operate in both directions.  The lower nibble of the control port can also be used as input or output, and the upper five bits of the status port are permanently configured as inputs.  Some of the bits in the control and status ports are inverted at the connector, requiring appropriate adjustments in the software to achieve the desired behavior.  The upper nibble of the control port is reserved.  However, writing a ‘1’ to C5 changes the data port to high impedance state, thereby allowing the port to read the value placed on the pins.  It was determined experimentally that the port in the computer used had 2.2k internal pullup resistors.  The pulled up voltage on the data and status ports was measured to be approximately 4.3V.  A diagram of the parallel port connecter is shown below in Figure 1. 

Figure 1. Parallel Port DB-25 Connector

 

Interface Resource Allocation

 

The communication schematic is shown below in Figure 2.

Figure 2. Resource Allocation

 

The 8-bit wide bi-directional data port sends or receives data.  The request (RQ) line is used to initiate a transaction with the microcontroller, and the clock (CLK) line is used to synchronize each byte as it is transferred.  The ready (RDY) and acknowledge (ACK) lines provide status indicators as to the state of the current transaction.

 

Protocol Definition

 

The PC host interface is defined as the master, and the ADuC7026 as the slave.  The master initiates all data transfers, and controls the transfer sequence with the clock signal.  In the current implementation, the transfer length is fixed in the code and must be the same on both the master and slave.  The basic protocol outlined below can easily be upgraded later to allow for variable length transfers.  The direction of the transfer is specified by the state of the CK line at the time that the request (RQ) line is raised to initiate a transfer.  If the CK=’1’, the transfer is from the device to the host, otherwise from the host to the device.  The basic transfer protocol is outlined in detail below.

 

Host-to-Device Transfer

 

  1. Host enables outputs on the data port, CK line is low to indicate direction of transfer.
  2. Host raises the RQ line.
  3. Host waits for RDY line to be asserted by the device.
  4. Host lowers the RQ line.
  5. Data transfer sequence commences
    1. Host writes data to the data port.
    2. Host raises the CK line to signal that the data is ready.
    3. Host waits for the ACK signal to be asserted by the slave, indicating that the data was read.
    4. Host lowers the CK signal.
    5. Host waits for ACK signal to go low, signaling that the byte transaction was completed, and the slave is ready for the next byte. (repeat a-e as necessary)
  6. Host puts the data port back to INPUT mode for reduce the chance of both the parallel port and microcontroller writing at the same time.
  7. Host clears both RQ and CLK lines to return to idle state.

 

Device-to-Host Transfer

 

  1. Host raises the CK line to indicate the direction of transfer.
  2. Host raises the RQ line. (the data port is already in INPUT mode, default state)
  3. Host waits for RDY line to be asserted by the device.
  4. Host lowers the RQ line.
  5. Data transfer sequence commences
    1. Host lowers the CK line to signal that it awaits the data byte.
    2. Host waits for the ACK signal to go high, indicating that the data byte is ready for reading.
    3. Host reads the data.
    4. Host raises the clock to indicate that the data was read.
    5. Host waits for the ACK signal to go low, signaling that the byte transaction was completed, and the slave is ready to transfer the next byte. (repeat a-e as necessary)
  6. Host clears both RQ and CLK lines to return to idle state.

 

Due to the full software handshaking in place, the protocol as outlined is not time sensitive.  However, to prevent either the host or device from locking up in the case of excessively long response times (or no response/error), iteration limitations are used in the wait cycles to impose a timeout on the transfer sequence.  In this way the robustness of the protocol is ensured.  No error checking provisions are made in the basic transfer sequence.  For most applications, this is probably acceptable due to the rarity of bit errors, especially considering that the data being transferred in the intended target application is relatively non-critical.

 

The protocol from the device perspective is analogous to the host side, and can be readily arrived at by considering what sequence is required by the host for a successful data transfer.

 

Software

 

The PC host software was implemented using the DriverLinx DlPortIO generic port driver for Windows 2000/XP.  The driver is freely downloadable from the http://www.driverlinx.com website, and provides direct port access under the aforementioned protected-mode operating systems.  A graphical user interface application was written in C++ using the wxWidgets 2.6 (http://www.wxwidgets.org) toolkit to facilitate easy testing of the communication interface.  The application consists of a scrolled text window in which status messages and output are displayed, as well as a command entry widget into which commands can be typed and executed by pressing ‘Enter’.  The currently available commands in the Commhost application are listed below.  An application screen shot is included below.

 

  1. bidir     Tests the bidirectional functionality of the parallel port.  If the readback does not return 0xFF, the port may not be configured as a Standard Parallel Port (SPP) in the PC BIOS, or may be such an old port that it physically does not support bidirectional data transfer (unlikely).
  2. disp      Displays the values in the data transfer buffer. 
  3. w         Writes the values in the data transfer buffer to the microcontroller.
  4. r                      Reads from the microcontroller and fills in the data transfer buffer with the values.
  5. inc       Increments all of the values in the buffer by 1.
  6. t         Initiates a test sequence. (microcontroller must be running the test_main() code for this to work properly)

 

Figure 3. Commhost Test Application Screenshot.

 

The ADuC7026 software is programmed in C and is compiled with the Keil uVision 3 development studio using the GCC-ARM7 compiler.  These tools were provided on the development kit CDROM. 

 

The code is set up to transfer a 9-byte buffer between the two devices.  The buffer and its length are of course passed as parameters to the read/write functions, so any length data transfer can be achieved.  Higher levels of abstraction may provide the necessary sequencing of low-level read/write functions to achieve variable length data transfers between the host and target device.

 

Hardware Connector

 

An adaptor was built to connect the DB-25 parallel port cable to the ADuC7026 development board, and to facilitate easy debugging.  The adaptor is shown in Figure 4.

 

Figure 4. DB-25 to Development Board Adaptor

 

Series 180 ohm resistors were placed between the parallel port and the ADI chip to help protect the microcontroller and parallel port from high currents in the event that outputs on both sides were enabled at the same time.  The resistors were used on the control port and the data port, but not on the status port since it cannot ever be driven by the parallel port.  The resistor leads on the top side were left longer to allow oscilloscope probes to be attached with ease for debugging purposes.

 

Testing

 

After some debugging, both the read and write sequences worked correctly.  Correct operation of the bidirectional transfer was readily verified using the Commhost interface application, and further documented using a Tektronix oscilloscope.  The following scope screens show the read and write transfers.

 

Figure 5. 9-byte Read Operation (Device to Host)

 

Figure 6. 9-byte Write Operation (Host to Device)

 

Using the oscilloscope cursors, the data transfer rate is readily determined.

 

This is a reasonably fast transfer rate of about 0.5 MBit/sec, considering that the all of the synchronization is done in software.  It is indeed much faster than RS-232 for bulk data transfer.

 

Conclusions

 

The simple parallel port communication interface provides a straightforward mechanism for interacting with the ADuC7026 microcontroller with reasonably high speed bulk data transfer capabilities.  Using the low level read/write commands outlined in this document, higher level protocols can be easily designed with the intended target application in mind.

 

While the resistive current limiting is sufficient for laboratory testing and product development, a finished product should use bidirectional buffers between the ADI chip and the parallel port to fully protect the microcontroller from erroneous parallel port conditions, even though the device claims to be 5-V logic tolerant.

 

Appendix A – ADuC7026 Microcontroller Code

 

comm.c

 

#include <aduc7026.h>

 

/*

 

  Parallel port             ADuC7026

 

     D0 .. D7   <------>       P3.0 .. P3.7

    

       S4         <--RDY--       P4.0

     S5         <--ACK--       P4.1

    

       C0         ---CK-->       P4.2   (also DIR during request)

       C2         ---RQ-->       P4.3

 

     C1         -INTR-->       P0.4

 

*/

 

typedef unsigned char UINT8;

typedef unsigned long UINT32;

 

#define INPUT 0

#define OUTPUT 1

 

/* ADuC7026 port GPxDAT register

bits

31-24    direction of data ('1':output, '0':input)

23-16    port x data output

15-8     reflect state of port x pins at reset (read only)

7-0      port x data input (read only)

*/

 

// communication config/read/write macros

#define SET_DATA_INPUT  (GP3DAT &= 0x00ffffff)

#define SET_DATA_OUTPUT (GP3DAT |= 0xff000000)

 

#define WRITE_DATA(val) (GP3DAT = (GP3DAT & ~0x00ff0000) | (((UINT32)val) << 16))  // write port 3 data

#define READ_DATA ((UINT8)(GP3DAT & 0x000000ff)) // read port 3 data

 

#define READ_CK ((UINT8)((GP4DAT & 0x00000004)>>2)) // pin 4.2

#define READ_RQ  ((UINT8)((GP4DAT & 0x00000008)>>3)) // pin 4.3

#define READ_INTR  ((UINT8)((GP0DAT & 0x00000010)>>4))  // pin 0.4 (xirq0)

 

#define WRITE_ACK(val) (GP4DAT = (GP4DAT & ~0x00020000) | (((UINT32)val)<<17)) // pin 4.1

#define WRITE_RDY(val) (GP4DAT = (GP4DAT & ~0x00010000) | (((UINT32)val)<<16)) // pin 4.0

 

#define COMM_READ 0

#define COMM_WRITE 1

 

enum { S_IDLE, S_READ_REQUEST, S_WRITE_REQUEST, S_TRANSFERRING };

static int cur_state = S_IDLE;

static int comm_attempts = 1000000;

 

 

int comm_read(UINT8 *buf, int count)

{

      int i, timeout;

 

      cur_state = S_TRANSFERRING;

 

      // set port direction as input

      SET_DATA_INPUT;

 

      // assert ready signal

      WRITE_RDY(1);

 

      /* wait for request line to go low again */

      while ( READ_RQ );

 

      for (i=0;i<count;i++)

      {

            // wait for clock to go high

            timeout = comm_attempts;

            while(timeout>0 && !READ_CK)

                  timeout--;

 

            if (!timeout)

            {

                  WRITE_RDY(0);

                  cur_state = S_IDLE;

                  return -1;

            }

 

            // now the data is available, so read it

            buf[i] = READ_DATA;

 

            // assert ACK to indicate data was read

            WRITE_ACK(1);

 

            // wait for clock to go low

            timeout = comm_attempts;

            while(timeout>0 && READ_CK)

                  timeout--;

 

            if (!timeout)

            {

                  WRITE_RDY(0);

                  cur_state = S_IDLE;

                  return -1;

            }

 

            // lower ACK to indicate byte transfer complete

            WRITE_ACK(0);

      }

 

      // pull ready line low

      WRITE_RDY(0);

     

      cur_state = S_IDLE;     // revert to IDLE state

      return i; // return number of bytes read

}

 

int comm_write(UINT8 *buf, int count)

{

      int i, timeout;

 

      cur_state = S_TRANSFERRING;

 

      // set port direction as output

      SET_DATA_OUTPUT;

 

      // assert ready signal

      WRITE_RDY(1);

 

      /* wait for request line (XIRQ0) to go low again */

      while (READ_RQ);

 

      for(i=0;i<count;i++)

      {

            // wait for the clock to go low

            timeout = comm_attempts;

            while(timeout>0 && READ_CK)

                  timeout--;

 

            if (!timeout)

            {

                  WRITE_RDY(0);

                  cur_state = S_IDLE;

                  return -1;

            }

                                           

            // place data on outputs

            WRITE_DATA( buf[i] );

 

            // assert ACK to indicate data is available

            WRITE_ACK(1);

 

            // wait for clock to go high again

            timeout = comm_attempts;

            while(timeout>0 && !READ_CK)

                  timeout--;

 

            if (!timeout)

            {

                  WRITE_RDY(0);

                  cur_state = S_IDLE;

                  return -1;

            }

            // pull ACK low to indicate byte transfer complete

 

            WRITE_ACK(0);

      }

     

      // pull ready signal low

      WRITE_RDY(0);

 

      cur_state = S_IDLE; // revert to IDLE state

      return i; // return number of bytes written

} 

 

void setup_comm()

{

      // configure ports 3 and 4 as GPIO

      GP3CON = 0x00000000;

      GP4CON = 0x00000000;

     

      // set pin 4.1, 4.0 as output

      // set pin 4.2, 4.3 as input

      GP4DAT = 0x03000000;

 

 

      // set port 0 as input

      GP0DAT = 0x00000000;

                          

      // start with port 3 as input

      SET_DATA_INPUT;

 

}

 

 

int main()                   

{

      // configure gpio ports

      setup_comm();

 

#define BUFLEN 9

      static unsigned char databuf[BUFLEN] = { 254, 128, 64, 32, 16, 8, 4, 2, 0 };

 

      while(1)

      {

            // wait for a communication request

            while (!READ_RQ);

 

            // determine direction of data transfer

            if ( READ_CK )

                  comm_write(databuf, BUFLEN); 

            else

                  comm_read(databuf, BUFLEN);

      }

 

      return 0;

}

 

 

 

 

 

/**************************************

**  single byte read/write commands  **

**************************************/

 

UINT8 readbyte()

{

      UINT8 val = 0;

      SET_DATA_INPUT;

 

      /* wait for request */

      while(!READ_RQ);

 

      val = READ_DATA;

 

      WRITE_ACK(1);

 

      while(READ_RQ);

     

      WRITE_ACK(0);

 

      return val;

}

 

void writebyte(UINT8 val)

{

      while(!READ_RQ);

 

      SET_DATA_OUTPUT;

      WRITE_DATA(val);

     

      WRITE_ACK(1);

 

      while(READ_RQ);

 

      SET_DATA_INPUT;  

      WRITE_ACK(0);

}

 

 

void test_main()

{

 

      UINT8 x = 0;

 

      GP3CON = 0x00000000;

     

      GP4CON = 0x00000000;

      GP4DAT = 0x03000000;

     

      GP0DAT = 0x00000000;

 

      SET_DATA_INPUT;

 

      WRITE_RDY(0);

      WRITE_ACK(0);

 

      while(1)

      {

            x = readbyte();

            writebyte(x+1);

      }

}

 

 

 

Appendix B – PC Commhost Source Code

 

commadi.h

 

#ifndef __commadi_h__

#define __commadi_h__

 

typedef void (*comm_print_func)(const char*, void*);

 

void  comm_set_print( comm_print_func f, void *cbdata);

void  comm_set_timeout(int attempts);

void  comm_test_bidir();

void  comm_test_ports();

int   comm_read_stat();

void  comm_clear();

 

/* these functions return the number of bytes

   written or read

 

   or

  

      -1 for to indicate an error

*/

int   comm_write( unsigned char *buf, int count);

int   comm_read( unsigned char *buf, int count);

 

 

#endif

 

commadi.cpp

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

 

#include <windows.h>

 

#include "dlportio.h"

#include "commadi.h"

 

// unsigned char x = DlPortReadPortUchar(PP_STAT);

// DlPortWritePortUchar(PP_DATA, 33);

 

typedef unsigned char UINT8;

  

#define PP_STAT 0x379

#define PP_CNTL 0x37A

#define PP_DATA 0x378

 

static UINT8 ppdata_val = 0;

static UINT8 ppcntl_val = 0;

 

/*

 

  Parallel port             ADuC7026

 

     D0 .. D7   <------>       P3.0 .. P3.7

    

       S4         <--RDY--       P4.0

     S5         <--ACK--       P4.1

    

       C0         ---CK-->       P4.2   (also DIR during request)

       C2         ---RQ-->       P4.3

 

     C1         -INTR-->       P0.4

 

*/

 

#define RQ_BIT 2

#define INTR_BIT 1

#define CK_BIT 0

 

#define RDY_BIT 4

#define ACK_BIT 5

 

/* xor the status and control ports with the appropriate masks

   to take care of the inverted signals on specific pins */

#define READSTAT  ((UINT8)(DlPortReadPortUchar(PP_STAT) ^ 0x80))

#define READDATA  ((UINT8)DlPortReadPortUchar(PP_DATA))

#define READCNTL  ((UINT8)DlPortReadPortUchar(PP_CNTL)^0x0b)

#define WRITEDATA DlPortWritePortUchar( PP_DATA, (UINT8)ppdata_val )

#define WRITECNTL DlPortWritePortUchar( PP_CNTL, (UINT8)((ppcntl_val ^ 0x0b)&0x3F) )

 

#define WRITE_RQ(x) changebit(&ppcntl_val, RQ_BIT, x); WRITECNTL

#define WRITE_CK(x) changebit(&ppcntl_val, CK_BIT, x); WRITECNTL

#define WRITE_INTR(x) changebit(&ppcntl_val, INTR_BIT, x); WRITECNTL

 

#define INPUT 0

#define OUTPUT 1

 

 

 

 

static comm_print_func print_func = NULL;

static void *print_cbdata = NULL;

 

static int commattempts = 1000000;

 

void  comm_set_timeout(int attempts)

{

      commattempts = attempts;

}

 

void comm_set_print( comm_print_func f, void *cbdata)

{

      print_func = f;

      print_cbdata = cbdata;

}

 

static void commprint(const char *fmt, ...)

{

      static char buf[1024];

      if (print_func != NULL)

      {

            va_list args;                

            va_start(args, fmt);

            _vsnprintf(buf, 1024, fmt, args);

            va_end(args);

 

            (*print_func)(buf, print_cbdata);

      }

}

 

 

static void changebit( UINT8 *data, UINT8 pos, UINT8 value)

{

      if (!data)

            return;

 

      if (value)

      {

            *data |= (0x1 << pos);

      }

      else

      {

            UINT8 mask = (UINT8) ~(0x01 << pos);

            *data &= mask;

      }

}

 

static void set_data_dir(int dir)

{

      if (dir == INPUT)

            changebit(&ppcntl_val, 5, 1);

      else

            changebit(&ppcntl_val, 5, 0);

 

      commprint("set data dir: '%s' (CNTL=0x%x). ", dir==INPUT?"input":"output", ppcntl_val);

      WRITECNTL;

 

      commprint("[read cntl=0x%x]\n", READCNTL&0x3F);

 

}

 

inline void writebyte(UINT8 x)

{

      int timeout;

 

      /* apply the data */

      set_data_dir(OUTPUT);

      ppdata_val = x;

      WRITEDATA;

 

      /* indicate write operation */

      WRITE_CK(0);

 

      /* assert request */

      WRITE_RQ(1);

     

      /* wait for ACK signal to go high*/

      timeout = commattempts;

      while(timeout-- > 0 && !(READSTAT & 0x20));

 

      /* deassert RQ */

 

      WRITE_RQ(0);

 

      /* wait for ACK signal to go low */

      timeout = commattempts;

      while(timeout-- > 0 && (READSTAT & 0x20));

 

      set_data_dir(INPUT);

}

 

inline UINT8 readbyte()

{

      UINT8 val;

      int timeout;

 

      set_data_dir(INPUT);

 

      /* assert request */

      WRITE_RQ(1);

     

      /* wait for ACK signal to go high*/

      timeout=commattempts;

      while(timeout-- > 0 && !(READSTAT & 0x20));

 

      /* read the data */

      val = READDATA;

      commprint("readdata=%d\n", READDATA);

 

      /* deassert RQ */

      WRITE_RQ(0);

 

      /* wait for ACK signal to go low */

      timeout = commattempts;

      while(timeout-- > 0 && (READSTAT & 0x20));

 

      return val;

}

 

void comm_test_ports()

{

      int timeout = 0;

      UINT8 x = 0;

 

      writebyte(35);

      x = readbyte();

     

      commprint("comm port test sequence completed [wrote 35, read %d]\n", x);

}

 

void comm_test_bidir()

{

      int i;

      UINT8 x;

      set_data_dir(OUTPUT);

 

      ppdata_val = 1;

      WRITEDATA;

      ppdata_val = 0;

      WRITEDATA;

 

      commprint("testing bidir...\n");

 

      for (i=0;i<10;i++)

      {

            ppdata_val = 100-i;

            WRITEDATA;

            x = READDATA;

            commprint("\tread(mode:out): 0x%x\n", x);

      }

 

      set_data_dir(INPUT);

      for (i=0;i<10;i++)

      {

            ppdata_val++;

            WRITEDATA;

            x = READDATA;

            commprint("\tread(mode:in): 0x%x\n", x);

      }

 

      ppdata_val = 0;

      WRITEDATA;

}

 

void comm_write0()

{

      ppdata_val = 0;

      ppcntl_val = 0;

      WRITEDATA;

      WRITECNTL;

      set_data_dir(INPUT);

}

 

 

int comm_write( unsigned char *buf, int count)

{

      int i;

      int timeout = 0;

 

      /* start with port as input for safety */

      set_data_dir(OUTPUT);

 

      /* set CK/DIR to 0 to indicate write operation */

      WRITE_CK(0);

 

      /* raise request line */

      WRITE_RQ(1);

 

      /* wait for RDY to go high */

      timeout = commattempts;

      while(timeout > 0 && !(READSTAT & 0x10))

            timeout--;

 

      /* if we got no response, return error */

      if (!timeout)

      {

            commprint("WRITE timed out waiting for RDY to go high ('1')\n");

            return -1;

      }

 

      /* pull request line low again */

      WRITE_RQ(0);

 

 

      for (i=0;i<count;i++)

      {

            /* write the byte to the data port */

            ppdata_val = buf[i];

            WRITEDATA;

 

            /* raise the clock */

            WRITE_CK(1);

 

            /* wait for the ACK signal to go high,

               indicating that the byte was read */

            timeout = commattempts;

            while(timeout > 0 && !(READSTAT & 0x20))

                  timeout--;

 

            if (!timeout)

            {

                  commprint("write timed out waiting for ACK to go high ('1')\n");

                  WRITE_CK(0);

                  WRITE_RQ(0);

                  set_data_dir(INPUT);

                  return -1;

            }

 

            /* lower the clock */

            WRITE_CK(0);

 

 

            /* wait for the ACK signal to go low,

               indicating that the transaction was done */

            timeout = commattempts;

            while(timeout > 0 && (READSTAT & 0x20))

                  timeout--;

 

            if (!timeout)

            {

                  commprint("write timed out waiting for ACK to go low ('0') again\n");

                  WRITE_CK(0);

                  WRITE_RQ(0);

                  set_data_dir(INPUT);

                  return -1;

            }

      }

 

      /* change back to input mode */

      set_data_dir(INPUT);

 

      return i;

 

}

 

int comm_read( unsigned char *buf, int count)

{

      int i;

      int timeout = 0;

 

      set_data_dir(INPUT);

 

      /* set CK/DIR to 1 to indicate read operation */

      WRITE_CK(1);

     

      /* raise request line */

      WRITE_RQ(1);

           

      /* wait for RDY to go high */

      timeout = commattempts;

      while(timeout > 0 && !(READSTAT & 0x10))

            timeout--;

 

 

      /* if we got no response, return error */

      if (!timeout)

      {

            WRITE_CK(0);

            WRITE_RQ(0);

            commprint("READ timed out waiting for RDY to go high ('1')\n");

            return -1;

      }

 

      /* lower request line again */

      WRITE_RQ(0);

 

      for (i=0;i<count;i++)

      {

            /* lower the clock */

            WRITE_CK(0);

           

            /* wait for the ACK signal to go high

               indicating that the data is ready */

            timeout = commattempts;

            while(timeout > 0 && !(READSTAT & 0x20))

                  timeout--;

 

            if (!timeout)

            {

                  WRITE_CK(0);

                  WRITE_RQ(0);

                  commprint("READ timed out waiting for ACK to go high ('1')\n");

                  return -1;

            }

 

            /* read the byte from the data port */

            buf[i] = READDATA;

 

            /* raise the clock */

            WRITE_CK(1);

           

            /* wait for the ACK signal to go low

               indicating that the transaction was done */

            timeout = commattempts;

            while(timeout > 0 && (READSTAT & 0x20))

                  timeout--;

 

            if (!timeout)

            {

                  WRITE_CK(0);

                  WRITE_RQ(0);

                  commprint("READ timed out waiting for ACK to go low ('0') again\n");

                  return -1;

            }

      }

 

      WRITE_CK(0);

      WRITE_RQ(0);

 

 

      return i;

 

}

 

 

int comm_read_stat()

{

      UINT8 val = READSTAT;

      commprint("comm_read_stat: 0x%x\n", val);

      return (int)val;

}

 

afwx.h

 

#ifndef AFWX_H

#define AFWX_H

 

 

extern wxConfig *app_config;

 

 

class AFApp : public wxApp

{

public:

      AFApp();

      bool OnInit();

      int OnExit();

     

};

 

DECLARE_APP(AFApp)

 

#define MAX_RECENT 9

 

class AFView;

class AFHelp;

 

class AFFrame : public wxFrame

{

public:

      AFFrame();

      virtual ~AFFrame();

     

      void New();

      void Load(const wxString &fn);

      void Open();

      void Save();

      void SaveAs();

      bool CloseDocument();

      void ShowHelp();

      void Exit();

     

      void UpdateControlStatus();

      void UpdateTitlebar();

 

      void Append(const wxString &str);

 

private:

      void OnInput(wxCommandEvent &evt);

      void OnDocumentCommand(wxCommandEvent &evt);

     

      void OnEditCommand(wxCommandEvent &evt);

      void OnUpdateEditMenuUI(wxUpdateUIEvent &evt);

 

      void OnPrintCommand(wxCommandEvent &evt);

      void OnRecent(wxCommandEvent &evt);

      void OnExit(wxCommandEvent &evt);

 

      void OnAbout(wxCommandEvent &evt);

      void OnHelp(wxCommandEvent &evt);

     

      void AddRecent(const wxString &fn);

      void RemoveRecent(const wxString &fn);

      void UpdateRecentMenu();

 

      void OnCloseFrame(wxCloseEvent &evt);

     

      wxMenu *mFileMenu, *mRecentMenu;

 

      wxToolBar *mToolBar;

 

      wxString mFilename;

      wxTextCtrl *mOutput, *mInput;

      AFHelp *mHelpView;

     

      int mRecentCount;

      wxString mRecentFiles[MAX_RECENT];

 

      DECLARE_EVENT_TABLE()

};

 

#endif

 

afwx.cpp

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

 

#include <wx/wx.h>

#include <wx/scrolbar.h>

#include <wx/print.h>

#include <wx/printdlg.h>

#include <wx/accel.h>

#include <wx/image.h>

#include <wx/fs_zip.h>

#include <wx/html/htmlwin.h>

#include <wx/config.h>

 

#include "painter.h"

#include "afhelp.h"

#include "afwx.h"

 

#include "commadi.h"

 

#include "stock_new.xpm"

#include "stock_open.xpm"

#include "stock_save.xpm"

#include "stock_save_as.xpm"

#include "stock_trash_full.xpm"

#include "stock_print.xpm"

#include "stock_convert.xpm"

#include "stock_undo.xpm"

#include "stock_redo.xpm"

#include "stock_button_cancel.xpm"

#include "stock_zoom_in.xpm"

#include "stock_zoom_out.xpm"

#include "stock_zoom_fit.xpm"

#include "stock_jump_to.xpm"

#include "stock_refresh.xpm"

#include "stock_index.xpm"

#include "stock_help.xpm"

#include "aficon.xpm"

 

 

/* application global variables */

 

static AFFrame *app_frame = NULL;

 

static wxArrayString app_args;

 

wxConfig *app_config = NULL;

 

/* AFFrame implementation */

 

IMPLEMENT_APP(AFApp)

 

AFApp::AFApp()

{

      /* nothing to do */

}

 

bool AFApp::OnInit()

{

      for (int i=0;i<argc;i++)

            app_args.Add(argv[i]);

 

#ifdef MESSAGES

      printf("AF-WX Application Framework (WX): Starting up...\n");

      printf("Framework by Aron Dobos\n");

      printf("Command line args: %d\n", app_args.Count());

      for (int k=0;k<app_args.Count();k++)

            printf("argv[%d]: '%s'\n", k, app_args[k].c_str());

     

#endif

 

      app_config = new wxConfig("Commhost", "AF_Applications");

 

 

      /* needed for the html help viewer */

    wxImage::AddHandler(new wxPNGHandler);

    wxImage::AddHandler(new wxJPEGHandler);

    wxFileSystem::AddHandler(new wxZipFSHandler);

 

      app_frame = new AFFrame;

      app_frame->Centre(wxBOTH);

      app_frame->Show(true);

 

      SetTopWindow(app_frame);

 

      if ((int)app_args.Count() > 1)

            app_frame->Load(app_args[1]);

     

     

      return true;

}

 

int AFApp::OnExit()

{    

      // delete the app config

      // (it automatically writes the configuration)

      delete app_config;

     

#ifdef MESSAGES

      printf("AF-WX: Shutdown complete.\n");

#endif

     

      return 0;

}

 

enum{ 

            ID_NEW, ID_OPEN, ID_SAVE, ID_SAVEAS, ID_CLOSEFILE,

            ID_RECENT_FILES, ID_EXIT,

           

            ID_ABOUT,

            ID_HELP,

 

            ID_OUTPUT, ID_INPUT,

           

            // up to 100 recent items can be accommodated

            ID_RECENT = 500,

            ID_RECENT_LAST = 600,

 

};

 

BEGIN_EVENT_TABLE(AFFrame, wxFrame)

      EVT_MENU( ID_NEW,                    AFFrame::OnDocumentCommand )

      EVT_MENU( ID_OPEN,                   AFFrame::OnDocumentCommand )

      EVT_MENU( ID_SAVE,                   AFFrame::OnDocumentCommand )

      EVT_MENU( ID_SAVEAS,                 AFFrame::OnDocumentCommand )

      EVT_MENU( ID_CLOSEFILE,              AFFrame::OnDocumentCommand )

     

      EVT_MENU( ID_EXIT,                   AFFrame::OnExit )

 

      EVT_MENU( ID_ABOUT, AFFrame::OnAbout )

      EVT_MENU( ID_HELP, AFFrame::OnHelp )

     

      EVT_TEXT_ENTER( ID_INPUT, AFFrame::OnInput)

 

      EVT_CLOSE( AFFrame::OnCloseFrame )

 

      // For recent file menu

      EVT_MENU( ID_RECENT+0, AFFrame::OnRecent)

      EVT_MENU( ID_RECENT+1, AFFrame::OnRecent)

      EVT_MENU( ID_RECENT+2, AFFrame::OnRecent)

      EVT_MENU( ID_RECENT+3, AFFrame::OnRecent)

      EVT_MENU( ID_RECENT+4, AFFrame::OnRecent)

      EVT_MENU( ID_RECENT+5, AFFrame::OnRecent)

      EVT_MENU( ID_RECENT+6, AFFrame::OnRecent)

      EVT_MENU( ID_RECENT+7, AFFrame::OnRecent)

      EVT_MENU( ID_RECENT+8, AFFrame::OnRecent)

      EVT_MENU( ID_RECENT+9, AFFrame::OnRecent) // this must go all the way to MAX_RECENT-1

     

END_EVENT_TABLE()

 

void afprint_output(const char *str, void *data)

{

      ((AFFrame*)data)->Append( str );

}

 

AFFrame::AFFrame()

      : wxFrame(NULL, -1, "Commhost", wxDefaultPosition, wxSize(700, 600))

{

      mFilename = "";

     

      mRecentCount = 0;

 

      CreateStatusBar(1);

 

      wxString helpfile = wxPathOnly(app_args[0]) + "/commhosthelp.zip#zip:index.html";

      mHelpView = new AFHelp(helpfile);

 

 

#ifdef __WXMSW__

      SetIcon( wxIcon("aficon") );

#else

      SetIcon( wxIcon( aicon_xpm ) );

#endif

 

      mRecentMenu = new wxMenu;

 

      mFileMenu = new wxMenu;

/*    mFileMenu->Append(ID_NEW, "New\tCtrl-N");

      mFileMenu->AppendSeparator();

      mFileMenu->Append(ID_OPEN, "Open...\tCtrl-O");

      mFileMenu->Append(ID_SAVE, "Save\tCtrl-S");

      mFileMenu->Append(ID_SAVEAS, "Save As...");

      mFileMenu->AppendSeparator();

      mFileMenu->Append(ID_CLOSEFILE, "Close");

      mFileMenu->AppendSeparator();

      mFileMenu->Append(ID_RECENT_FILES, "Recent Files", mRecentMenu);

      mFileMenu->AppendSeparator();*/

      mFileMenu->Append(ID_EXIT, "Exit\tCtrl-W");

 

 

      wxMenu *help_menu = new wxMenu;

      help_menu->Append(ID_ABOUT, "About Commhost");

      help_menu->AppendSeparator();

      help_menu->Append(ID_HELP, "Help Contents\tF1");

     

      wxMenuBar *menubar = new wxMenuBar;

      menubar->Append(mFileMenu, "File");

      menubar->Append(help_menu, "Help");

     

      SetMenuBar( menubar );

     

/*    mToolBar = CreateToolBar();

 

      mToolBar->AddTool( ID_NEW, wxBitmap( stock_new_xpm ), "Create a new document" );

      mToolBar->AddTool( ID_OPEN, wxBitmap( stock_open_xpm ), "Open an existing file" );

      mToolBar->AddTool( ID_SAVE, wxBitmap( stock_save_xpm ), "Save changes");

      mToolBar->AddTool( ID_SAVEAS, wxBitmap( stock_save_as_xpm ), "Save to a different file" );

      mToolBar->AddTool( ID_HELP, wxBitmap( stock_help_xpm ), "Help contents" );

 

    mToolBar->SetToolBitmapSize(wxSize(24, 24));     

      mToolBar->Realize();*/

 

      wxFont font(10, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL,

            wxFONTWEIGHT_NORMAL, false, "courier");

 

      mOutput = new wxTextCtrl(this, ID_OUTPUT, "", wxDefaultPosition, wxDefaultSize,

            wxTE_MULTILINE | wxTE_DONTWRAP | wxHSCROLL | wxVSCROLL);

      mOutput->SetFont(font);

      mOutput->SetEditable(false);

 

      comm_set_print( afprint_output, this );

 

      mInput = new wxTextCtrl(this, ID_INPUT, "", wxDefaultPosition, wxDefaultSize,

            wxTE_PROCESS_ENTER);

      mInput->SetFont(font); 

 

 

      wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);

      SetSizer(sizer);

      sizer->Add(mOutput, 1, wxEXPAND);

      sizer->Add(mInput, 0, wxEXPAND);

 

      sizer->Fit(this);

      sizer->SetSizeHints(this);

           

      SetSize(500, 500);

     

      mInput->SetFocus();

     

     

      long ct = 0;

      if (app_config->Read("RecentCount", &ct))

            mRecentCount = (int)ct;

 

      if (mRecentCount > MAX_RECENT)

            mRecentCount = MAX_RECENT;

 

      for (int i=0;i<mRecentCount;i++)

      {

            wxString key;

            key.Printf("RecentFile_%d", i);

            wxString fn;

            if (app_config->Read(key, &fn))

                  mRecentFiles[i] = fn;

      }

 

      UpdateRecentMenu();    

      UpdateControlStatus();

      UpdateTitlebar();

 

      New();

 

      /* clear the output port */

      comm_clear();

}

 

 

AFFrame::~AFFrame()

{

      // save the recent file settings

 

      long ct = (long)mRecentCount;

      app_config->Write("RecentCount", ct);

      for (int i=0;i<mRecentCount;i++)

      {

            wxString key;

            key.Printf("RecentFile_%d", i);

            app_config->Write(key, mRecentFiles[i]);

      }

 

      mHelpView->Destroy();

 

#ifdef MESSSAGES

      printf("~AFFrame: destructing the main window...\n");

#endif

}

 

void AFFrame::Append(const wxString &str)

{

      mOutput->AppendText(str);

}

 

void AFFrame::OnInput(wxCommandEvent &evt)

{

      #define BUFLEN 9

      static unsigned char databuf[BUFLEN] = { 0, 2, 4, 8, 16, 32, 64, 128, 255 };

 

      wxString cmd = mInput->GetValue();

      if (cmd == "")

            return;

 

      mOutput->AppendText(">> " + cmd + "\n");

      mInput->SetValue("");

 

      cmd.Lower();

      if (cmd == "bidir")

      {

            comm_test_bidir();

      }

      else if (cmd == "disp")

      {

            Append(wxString::Format("Data buffer (len:%d)\n", BUFLEN));

            for (int i=0;i<BUFLEN;i++)

                  Append( wxString::Format(">> %d: '%d'\n", i, databuf[i]));

      }

      else if (cmd == "w")

      {

            comm_read_stat();

            int ret = comm_write(databuf, BUFLEN);

            if (ret > 0)

            {

                  for (int i=0;i<BUFLEN;i++)

                        Append( wxString::Format("%d: '%d'\n", i, databuf[i]));

                  Append("write succeeded.\n");

            }

            else

                  Append("write failed.\n");

      }

      else if (cmd == "inc")

      {

            for (int i=0;i<BUFLEN;i++)

                  databuf[i]++;

      }

      else if (cmd == "r")

      {

            comm_read_stat();

            int ret = comm_read(databuf, BUFLEN);

            if (ret > 0)

            {

                  Append("read succeeded.\n");

                  for (int i=0;i<BUFLEN;i++)

                        Append( wxString::Format("%d: '%d'\n", i, databuf[i]));

            }

            else

                  Append("read failed.\n");

      }

      else if (cmd == "t")

      {

            comm_test_ports();

      }

      else

      {

            mOutput->AppendText("unknown command!\n");

      }

}

 

void AFFrame::UpdateRecentMenu()

{

      int i;

      for (i=0;i<MAX_RECENT;i++)

      {

            if (mRecentMenu->FindItem(ID_RECENT+i) != NULL)

                  mRecentMenu->Destroy(ID_RECENT+i);

      }

 

      for (i=0;i<mRecentCount;i++)

      {

            wxString name;

            name.Printf("%d  %s", i+1, mRecentFiles[i].c_str());

            mRecentMenu->Append(ID_RECENT+i, name);

      }

}

 

void AFFrame::OnRecent(wxCommandEvent &evt)

{

      int id = evt.GetId() - ID_RECENT;

      if (id < 0 || id >= MAX_RECENT)

            return;

 

      if (!CloseDocument())

            return;

 

      wxString fn = mRecentFiles[id];

      if (fn != "")

      {

            //wxMessageBox("loading recent file " + fn);

            Load(fn);

      }

}

 

void AFFrame::AddRecent(const wxString &fn)

{

      int i;

      int index = -1;

      // find the file in the recent list

      for (i=0;i<mRecentCount;i++)

      {

            if (fn == mRecentFiles[i])

            {

                  index = i;

                  break;

            }

      }

 

      if (index >= 0)

      {

            // bring this file to the front of the

            // recent file list

 

            for (i=index;i>0;i--)

                  mRecentFiles[i] = mRecentFiles[i-1];

      }

      else // not found in recent list

      {

            // add this to the front of the recent list

            // and increment the recent count if its

            // less than MAX_RECENT

 

            for (i=MAX_RECENT-1;i>0;i--)

                  mRecentFiles[i] = mRecentFiles[i-1];

 

            if (mRecentCount < MAX_RECENT)

                  mRecentCount++;

      }

     

      mRecentFiles[0] = fn;

      UpdateRecentMenu();

}

 

void AFFrame::RemoveRecent(const wxString &fn)

{

      int i;

      int index = -1;

      // find the file in the recent list

      for (i=0;i<mRecentCount;i++)

      {

            if (fn == mRecentFiles[i])

            {

                  index = i;

                  break;

            }

      }

 

      if (index >= 0)

      {

            for (i=index;i<MAX_RECENT-1;i++)

                  mRecentFiles[i] = mRecentFiles[i+1];

 

            mRecentCount--;

            UpdateRecentMenu();

      }

}

 

void AFFrame::ShowHelp()

{

      mHelpView->Show();

}

 

void AFFrame::OnCloseFrame( wxCloseEvent &evt )

{

      if (evt.CanVeto() && (!CloseDocument()))

      {

            evt.Veto();

            return;

      }

     

      Destroy();

}

 

 

void AFFrame::New()

{

      if (!CloseDocument())

            return;

 

      // INITIALIZE NEW DOCUMENT HERE

 

      UpdateTitlebar();

      UpdateControlStatus();

}

 

 

void AFFrame::Load(const wxString &fn)

{

      mFilename = fn;

 

      // READ DATA HERE

 

      UpdateTitlebar();

      UpdateControlStatus();

}

 

void AFFrame::Open()

{

      if (!CloseDocument())

            return;

 

      wxString initial_dir = "";

     

      wxFileDialog fdlg(this, "Open File", initial_dir, "", "All Files(*.*)", wxOPEN);

      if (fdlg.ShowModal() == wxID_OK)

            Load( fdlg.GetPath() );

}

 

void AFFrame::Save()

{

      if (mFilename == "")

      {

            SaveAs();

            return;

      }

 

      // WRITE DATA HERE

 

      UpdateTitlebar();

      UpdateControlStatus();

}

 

void AFFrame::SaveAs()

{

      wxString caption;

      caption.Printf("Save As: '%s'", mFilename != "" ? mFilename.c_str() : "untitled");

     

      wxString initial_dir = "";

      if ( mFilename != "" )

            initial_dir = wxPathOnly( mFilename );

 

      wxString FileName;

      wxFileName::SplitPath(mFilename, NULL, &FileName, NULL);

     

      wxFileDialog fdlg(this, caption, initial_dir, FileName  + ".lay",

            "All Files (*.*)", wxSAVE | wxOVERWRITE_PROMPT );

     

      if (fdlg.ShowModal() == wxID_OK)

      {

            if (fdlg.GetPath() != "")

            {

                  mFilename = fdlg.GetPath();

                  Save();

                  return;

            }

            else

            {

                  wxMessageBox("No filename selected", "", wxOK | wxICON_ERROR);

            }

      }

           

}

 

bool AFFrame::CloseDocument()

{

      if ( /* CHECK IF SOMETHING IS MODIFIED */ false )

      {

            int ret = wxMessageBox("Document has been modified. Save it?", "AFedit", wxYES_NO | wxCANCEL | wxICON_EXCLAMATION);

 

            if (ret == wxYES)

            {

                  Save();

                  if ( false /* CHECK AGAIN IF STILL MODIFIED */)

                        return false;

            }

            else if (ret == wxCANCEL)

            {

                  return false;

            }

      }

     

      /* UNLOAD DOCUMENT AND DATA */

 

 

      mFilename = "";

      UpdateTitlebar();

      UpdateControlStatus();

 

      return true;

}

 

void AFFrame::Exit()

{

      Close( false );

}

 

 

void AFFrame::OnDocumentCommand(wxCommandEvent &evt)

{

      switch(evt.GetId())

      {

      case ID_NEW:

            New();

            break;

      case ID_OPEN:

            Open();

            break;

      case ID_SAVE:

            Save();

            break;

      case ID_SAVEAS:

            SaveAs();

            break;

      case ID_CLOSEFILE:

            CloseDocument();

      default:

            break;

      }

}

 

void AFFrame::OnExit(wxCommandEvent &evt)

{

      Exit();

}

void AFFrame::OnAbout(wxCommandEvent &evt)

{

      wxString msg;

      msg.Printf("Commhost\n"

            "Parallel Port Communication Interface for ADuC7026\n\n"

            "Copyright (c) 2005 Aron Dobos\n");

 

      wxMessageBox(msg,"About Commhost", wxOK | wxICON_INFORMATION);

}

 

void AFFrame::OnHelp(wxCommandEvent &evt)

{

      mHelpView->Show();

}

 

void AFFrame::UpdateControlStatus()

{

      bool DocumentPresent = false;

      bool DocumentDirty = false;

     

      /*

      mFileMenu->Enable(ID_SAVE, DocumentPresent && DocumentDirty);

      mFileMenu->Enable(ID_SAVEAS, DocumentPresent);

      mFileMenu->Enable(ID_CLOSEFILE, DocumentPresent);

 

      mFileMenu->Enable(ID_RECENT_FILES, mRecentCount > 0 );

     

      mToolBar->EnableTool(ID_NEW, mFileMenu->IsEnabled(ID_NEW));

      mToolBar->EnableTool(ID_OPEN, mFileMenu->IsEnabled(ID_OPEN));

      mToolBar->EnableTool(ID_SAVE, mFileMenu->IsEnabled(ID_SAVE));

      mToolBar->EnableTool(ID_SAVEAS, mFileMenu->IsEnabled(ID_SAVEAS));

      */

 

}

 

void AFFrame::UpdateTitlebar()

{

      bool dirty = false; /* CHECK IF DATA IS MODIFIED */

      wxString title;

      title.Printf("%s%s - Commhost", mFilename.length() > 0 ? wxFileNameFromPath(mFilename).c_str() : "Untitled", dirty ? "*":"");

      SetTitle( title );

}

 

afhelp.h

 

#ifndef __afhelp_h

#define __afhelp_h

 

#include <wx/html/htmlwin.h>

 

class AFHelp : public wxFrame

{

public:

      AFHelp(const wxString &zipfile);

      virtual ~AFHelp();

 

      void OnCloseFrame(wxCloseEvent &evt);

      void OnTool(wxCommandEvent &evt);

 

private:

      wxToolBar *mToolBar;

      wxHtmlWindow *mHtml;

      wxString mZipFilePath;

 

DECLARE_EVENT_TABLE();

};

 

#endif

 

afhelp.cpp

 

#include <wx/wx.h>

#include <wx/html/htmlwin.h>

 

#include "afhelp.h"

#include "stock_close.xpm"

#include "stock_left_arrow.xpm"

#include "stock_right_arrow.xpm"

#include "aficon.xpm"

 

enum { AFHELP_CLOSE, AFHELP_BACK, AFHELP_FORWARD };

 

BEGIN_EVENT_TABLE( AFHelp, wxFrame )

      EVT_TOOL( AFHELP_BACK, AFHelp::OnTool )

      EVT_TOOL( AFHELP_FORWARD, AFHelp::OnTool )

      EVT_TOOL( AFHELP_CLOSE, AFHelp::OnTool )

     

      EVT_CLOSE( AFHelp::OnCloseFrame )

END_EVENT_TABLE();

 

AFHelp::AFHelp(const wxString &zipfile)

      : wxFrame(NULL, -1, "Commhost Help", wxDefaultPosition, wxSize(600, 600))

{

 

#ifdef __WXMSW__

      SetIcon( wxIcon("aficon") );

#else

      SetIcon( wxIcon( aficon_xpm ) );

#endif

 

      CreateStatusBar(1);

 

      mZipFilePath = zipfile;

           

      mToolBar = CreateToolBar();

      mToolBar->AddTool( AFHELP_CLOSE, wxBitmap( stock_close_xpm ), "Close Help" );

      mToolBar->AddTool( AFHELP_BACK, wxBitmap( stock_left_arrow_xpm ), "Go Back" );

      mToolBar->AddTool( AFHELP_FORWARD, wxBitmap( stock_right_arrow_xpm ), "Go Forward" );

    mToolBar->SetToolBitmapSize(wxSize(24, 24));     

      mToolBar->Realize();

 

    mHtml = new wxHtmlWindow( this );

    mHtml->SetRelatedFrame(this, "Commhost Help : %s");

    mHtml->SetRelatedStatusBar(0);

    mHtml->LoadPage(mZipFilePath);

}

 

AFHelp::~AFHelp()

{

      /* nothing to do here */

}

 

void AFHelp::OnTool(wxCommandEvent &evt)

{

      switch(evt.GetId())

      {

      case AFHELP_CLOSE:

            Hide();

            break;

      case AFHELP_BACK:

            mHtml->HistoryBack();

            break;

      case AFHELP_FORWARD:

            mHtml->HistoryForward();

      default:

            break;

      }

}

 

void AFHelp::OnCloseFrame(wxCloseEvent &evt)

{

      Hide();

      evt.Veto();

}

 

dlportio.h

 

/****************************************************************************

 *  @doc INTERNAL

 *  @module dlportio.h |

 *

 *  DriverLINX Port I/O Driver Interface

 *  <cp> Copyright 1996-1999 Scientific Software Tools, Inc.<nl>

 *  All Rights Reserved.<nl>

 *  DriverLINX is a registered trademark of Scientific Software Tools, Inc.

 *

 *  Win32 Prototypes for DriverLINX Port I/O

 *

 *  @comm  

 *  Author: RoyF<nl>

 *  Date:   09/26/96 14:08:58

 *

 *  @group Revision History

 *  @comm

 *  $Revision: 2 $

 *  <nl>

 *  $Log: /DLPortIO/API/DLPORTIO.H $

 *

 * 2     3/03/99 5:25p Kevind

 * Removed any reference for customer to call us when encountering bugs,

 * also removed our old address info.

 *

 * 1     9/27/96 2:03p Royf

 * Initial revision.

 *

 ****************************************************************************/

 

#ifndef DLPORTIO_H

  #define DLPORTIO_H

 

#ifdef __cplusplus

extern "C" {

#endif

 

#ifndef IN

  #define IN

#endif

 

#define DLPORT_API _stdcall

 

UCHAR DLPORT_API

DlPortReadPortUchar(

    IN ULONG Port

    );

 

USHORT DLPORT_API

DlPortReadPortUshort(

    IN ULONG Port

    );

 

ULONG DLPORT_API

DlPortReadPortUlong(

    IN ULONG Port

    );

 

VOID DLPORT_API

DlPortReadPortBufferUchar(

    IN ULONG Port,

    IN PUCHAR Buffer,

    IN ULONG  Count

    );

 

VOID DLPORT_API

DlPortReadPortBufferUshort(

    IN ULONG Port,

    IN PUSHORT Buffer,

    IN ULONG Count

    );

 

VOID DLPORT_API

DlPortReadPortBufferUlong(

    IN ULONG Port,

    IN PULONG Buffer,

    IN ULONG Count

    );

 

VOID DLPORT_API

DlPortWritePortUchar(

    IN ULONG Port,

    IN UCHAR Value

    );

 

VOID DLPORT_API

DlPortWritePortUshort(

    IN ULONG Port,

    IN USHORT Value

    );

 

VOID DLPORT_API

DlPortWritePortUlong(

    IN ULONG Port,

    IN ULONG Value

    );

 

VOID DLPORT_API

DlPortWritePortBufferUchar(

    IN ULONG Port,

    IN PUCHAR Buffer,

    IN ULONG  Count

    );

 

VOID DLPORT_API

DlPortWritePortBufferUshort(

    IN ULONG Port,

    IN PUSHORT Buffer,

    IN ULONG Count

    );

 

VOID DLPORT_API

DlPortWritePortBufferUlong(

    IN ULONG Port,

    IN PULONG Buffer,

    IN ULONG Count

    );

 

#ifdef __cplusplus

}

#endif

 

#endif // DLPORTIO_H

 

array.h

 

#ifndef __array_h

#define __array_h

 

#include <assert.h>

#include <stdlib.h>

#include <stdarg.h>

 

#include "vector.h"

 

template <class T>

class Array

{

public:

      Array(int size = 5);

     

      Array &operator= (const Array &array);

      T operator[] (int i) const;

      T &operator[] (int i);

     

      void prepend(const T &s);

      void append(const T &s);

      void insert(const T &s, int index);

     

      int find(const T &s);

     

      void remove(const T &s);

      void remove(int index);

      void clear();

     

     

      void preAlloc(int size);

      int count() const;

      int length() const;

      int capacity() const;

 

      static Array make(int n, ...);

 

      T *data();

     

private:

      Vector<T> items;

      int n_items;

};

     

 

 

////////////////////////////////////////////////////////////

// templated implementation

 

template <class T>

Array<T>::Array(int size)

{

      n_items = 0;

      if (size > 0)

            items.resize(size);

}

 

template <class T>

Array<T> &Array<T>::operator= (const Array &array)

{

      if (this != &array)

      {

            items.resize(array.length());

            n_items = array.length();

           

            for (int i=0;i<items.length();i++)

                  items[i] = array.items[i];

      }

 

      return *this;

}

 

template <class T>

T Array<T>::operator[] (int i) const

{

      assert( i >= 0 && i < n_items );

     

      return items[i];

}

 

template <class T>

T &Array<T>::operator[] (int i)

{

      assert( i >= 0 && i < n_items );

     

      return items[i];

}

 

template <class T>

void Array<T>::prepend(const T &s)

{

      insert(s, 0);

}

 

template <class T>

void Array<T>::append(const T &s)

{

      int last_location = n_items;

     

      if (items.length() < n_items + 1)

            items.resize(items.length() + 10);

     

      items[last_location] = s;

      n_items++;

}

 

template <class T>

void Array<T>::insert(const T &s, int index)

{

      assert( index >=0 && index <= items.length() );

           

      if (items.length() < n_items + 1)

            items.resize(items.length() + 10);

           

      for (int i=n_items; i > index; i--)

            items[i] = items[i-1];

     

      items[index] = s;

      n_items++;

}

 

template <class T>

int Array<T>::find(const T &s)

{

      for (int i=0;i<n_items;i++)

            if (s == items[i])

                  return i;

     

      return -1;

}

 

template <class T>

void Array<T>::remove(const T &s)

{

      int index = find(s);

      if (index >= 0)

            remove(index);

}

 

template <class T>

void Array<T>::remove(int index)

{

      assert(index >= 0 && index < n_items);

     

      for (int i=index;i<n_items-1;i++)

            items[i] = items[i+1];

     

      n_items--;

}

 

template <class T>

void Array<T>::clear()

{

      n_items = 0;

}

 

template <class T>

void Array<T>::preAlloc(int size)

{

      if (size > items.length())

            items.resize(size);

}

 

template <class T>

int Array<T>::length() const

{

      return n_items;

}

 

template <class T>

int Array<T>::count() const

{

      return n_items;

}

 

template <class T>

int Array<T>::capacity() const

{

      return items.length();

}

 

template <class T>

Array<T> Array<T>::make(int n, ...)

{

      char *str;

      Array sa;

      va_list args;

     

      va_start(args, n);

 

      for (int i=0;i<n;i++)

      {

            str = va_arg(args, char*);

            sa.append( str );  

      }

     

      va_end(args);

     

      return sa;

}

 

template <class T>

T *Array<T>::data()

{

      return items.data();

}

 

#endif

 

vector.h

 

#ifndef __vector_h

#define __vector_h

 

#include <assert.h>

 

template <class type>

class Vector

{

public:

      Vector();

      Vector(int size);

      Vector(int size, const type &fill);

      Vector(const Vector &vec);

      ~Vector();

 

      void clear();

           

      const Vector &operator= (const Vector &vec);

      type &operator[] (int i);

      const type &operator[] (int i) const;

     

      type &at(int i);

      const type &at(int i) const;

     

      bool resize(int new_size, bool copy = true);

      int length() const;

      int size() const;

     

      type *data();

     

private:

      int t_size;

      type *t_array;

};

 

 

 

////////////////////////////////////////////////////////////

// templated implementation

 

template <class type>

Vector<type>::Vector()

{

      t_size = 0;

      t_array = NULL;

}

 

template <class type>

Vector<type>::Vector(int size)

{

      t_size = size;

      t_array = new type[t_size];

}

 

template <class type>

Vector<type>::Vector(int size, const type &fill)

{

      t_size = size;

      t_array = new type[t_size];

      for (int i=0; i < t_size; i++)

            t_array[i] = fill;

}

     

template <class type>

Vector<type>::Vector(const Vector &vec)

{

      t_size = vec.length();

      t_array = new type[t_size];

 

      for (int i=0; i < t_size; i++)

            t_array[i] = vec.t_array[i];

}

 

template <class type>

Vector<type>::~Vector()

{

      delete [] t_array;

}

 

template <class type>

void Vector<type>::clear()

{

      if (t_array)

            delete [] t_array;

     

      t_array = NULL;

      t_size = 0;

}

     

template <class type>

const Vector<type> &Vector<type>::operator= (const Vector &vec)

{

      if (this != &vec)

      {

            delete [] t_array;

            t_size = vec.length();

            t_array = new type[t_size];

 

            for (int i=0;i<t_size;i++)

                  t_array[i] = vec.t_array[i];

      }

      return *this;

}

 

template <class type>

type &Vector<type>::operator[] (int i)

{

      assert( i >= 0 && i < t_size);

      return t_array[i];

}

     

template <class type>

const type &Vector<type>::operator[] (int i) const

{

      assert( i >= 0 && i < t_size);

      return t_array[i];

}

 

template <class type>

type &Vector<type>::at (int i)

{

      assert( i >= 0 && i < t_size);

      return t_array[i];

}

     

template <class type>

const type &Vector<type>::at (int i) const

{

      assert( i >= 0 && i < t_size);

      return t_array[i];

}

 

template <class type>

bool Vector<type>::resize(int new_size, bool copy)

{

      int num_to_copy = new_size < t_size ? new_size : t_size;

      type *buf = new type[new_size];

     

      if (copy)

            for (int i=0;i<num_to_copy;i++)

                  buf[i] = t_array[i];

                             

      delete [] t_array;

      t_size = new_size;

      t_array = buf;

     

      return t_array != NULL;

}

           

template <class type>

int Vector<type>::length() const

{

      return t_size;

}

 

template <class type>

int Vector<type>::size() const

{

      return length();

}

 

template <class type>

type *Vector<type>::data()

{

      return t_array;

}

 

 

#endif