/******************************************************************************

  Parallel Port Programming Cable

  DB-25  8-Pin Header  Signal Name
  -----  ------------  -----------
    2       JP1-1      RESET*
    3       JP1-3      SCK
    4       JP1-7      MOSI
   13       JP1-5      MISO
   15       JP1-2      GND
   24       JP1-4      GND
   23       JP1-6      GND
   22       JP1-8      GND
   12         -         \ Loop-back (cable detect)
   14         -         / Loop-back (cable detect)

******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if !defined (__GNUC__)
#include <conio.h>
#include <dos.h>
#else
int inportb(int port)
{
    return 0;
};
void outportb(int port, int value)
{
};
void getch(void)
{
    getchar();
};

#endif

#ifdef NOT_MSC_COMPAT
#define inp inportb
#define outp outportb
#endif

#define RESETHI 0x1
#define RESETLOW  0

static int debug = 0;
static char *program;

static int lpt[3] =
{0x03bc, 0x0378, 0x0278};

static int lpt_data = 0;	// 8 DATA BITS

static int lpt_control = 2;	// X X X IRQ4EN *SEL INIT *AUTOFEED *STROBE (POR XXX01011)

static int lpt_status = 1;	// *BUSY *ACK P.OUT SEL *ERR X X X

static int lptN = -1;
static int lpt_port = 0;

int find_lpt_port(int port)
{
    int x;
    int first_port = 0;
    int last_port = 2;
    int i;
    int data;

#if !defined (__GNUC__)
    if (port >= 0) {
        first_port = port;
        last_port = port;
    }
    for (x = first_port; x <= last_port; x++) {
        data = inp(lpt[x] + lpt_control);
        outp((lpt[x] + lpt_control), (data | 2));
        i = inp(lpt[x] + lpt_status);
        if (debug)
            printf("LPT%d (0x%x): status=0x%02x\n", x, lpt[x], i);
        if ((i & 0x20) != 0)
            goto skip;
        outp((lpt[x] + lpt_control), (data & (~2)));
        i = inp(lpt[x] + lpt_status);
        if (debug)
            printf("\tstatus=0x%02x\n", i);
        if ((i & 0x20) != 0x20)
            goto skip;
        printf("Found LPT%d (I/O base 0x%x)\n", x, lpt[x]);
        return lpt[x];
      skip:
        i = inp(lpt[x] + lpt_status);
        if (debug)
            printf("\tstatus=0x%02x\n", i);
        outp((lpt[x] + lpt_control), data);
    }
    if (port >= 0) {
        fprintf(stderr, "Can't find the AVR program cable on LPT%d!\n", port);
    } else {
        fprintf(stderr, "Can't find the AVR program cable on any LPT port!\n");
    }
    exit(1);
#endif
    return 0;
}

void usage(void)
{
    fprintf(stderr, "usage: %s [options]\n"
    "options:\n"
    "   -d         - set debug mode\n"
    "   -lptx      - look for program cable on parallel port LPTx\n"
    "   -on        - Turn OBD-II connector power ON\n"
    "   -off       - Turn OBD-II connector power OFF\n"
    "   -cycle     - Cycle OBD-II connector power OFF and ON\n"
        , program);
    exit(1);
}

void main(int argc, char **argv)
{
    int n;
    int start, finish, data_val;
    char *p, *opt;
    char filename[256];

    program = *argv;
    --argc;
    ++argv;
    if ((p = strrchr(program, '/')) != NULL)
        program = p + 1;
    if ((p = strrchr(program, '\\')) != NULL)
        program = p + 1;

    while (argc && **argv == '-') {
        opt = *argv;
        --argc;
        ++argv;
        if (!strcmp(opt, "-d")) {
            debug = 1;

        } else if (!strncmp(opt, "-lpt", 4)) {
            lptN = atoi(opt + 4);
            if (lptN < 0 || lptN > 2) {
                fprintf(stderr, "%s: no such LPT port (%s)!  Use -lpt0, -lpt1 or -lpt2.\n", program, *argv);
                exit(1);
            }
            lpt_port = find_lpt_port(lptN);

        } else if (!strcmp(opt, "-on")) {
            if (!lpt_port)
                lpt_port = find_lpt_port(lptN);
            outp(lpt_port, RESETLOW);

        } else if (!strcmp(opt, "-off")) {
            if (!lpt_port)
                lpt_port = find_lpt_port(lptN);
            outp(lpt_port, RESETHI);

        } else if (!strcmp(opt, "-cycle")) {
            if (!lpt_port)
                lpt_port = find_lpt_port(lptN);
            outp(lpt_port, RESETHI);
            sleep(2);
            outp(lpt_port, RESETLOW);

        } else {
            fprintf(stderr, "%s: unknown option (%s)!\n", program, opt);
            usage();
        }
    }

    if (argc)
        usage();

    exit(0);
}
