This program implements the negotiation phase and emulates a printer. It can be plugged on the parallel port of a PC. It\'s a test program

Dependencies:   mbed

main.cpp

Committer:
jpelletier
Date:
2011-05-07
Revision:
0:8133df8bab0f

File content as of revision 0:8133df8bab0f:

#include "mbed.h"


#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PAR_NEGOTIATE_EXTENSIBILITY_LINK        0x80
#define PAR_NEGOTIATE_REQ_EPP_MODE              0x40
#define PAR_NEGOTIATE_REQ_ECP_MODE              0x10
#define PAR_NEGOTIATE_REQ_ECP_RLE_MODE          0x30
#define PAR_NEGOTIATE_REQ_DEV_ID_NIBBLE_MODE    0x04
#define PAR_NEGOTIATE_REQ_DEV_ID_BYTE_MODE      0x05
#define PAR_NEGOTIATE_REQ_DEV_ID_ECP_MODE       0x14
#define PAR_NEGOTIATE_REQ_DEV_ID_ECP_RLE_MODE   0x34
#define PAR_NEGOTIATE_NIBBLE_MODE               0x00
#define PAR_NEGOTIATE_BYTE_MODE                 0x01

/*
15 nError       -> p9
13 Select       -> p10
12 PE           -> p11
11 Busy         -> p12
10 nAck         -> p13

 1 nStrobe      -> p14
14 nAutoFeed    -> p15
16 nInit        -> p16
17 nSelectIn    -> p17
*/

DigitalOut nError(p9);
DigitalOut Select(p10);
DigitalOut PaperOut(p11);
DigitalOut Busy(p12);
DigitalOut nAck(p13);

DigitalIn nStrobe(p14);
DigitalIn nAutoFeed(p15);
DigitalIn nInit(p16);
DigitalIn nSelectIn(p17);

/* 
D0 p30  p0.4
D1 p29  p0.5
D2 p8   p0.6
D3 p7   p0.7
D4 p6   p0.8
D5 p5   p0.9
D6 p28  p0.10
D7 p27  p0.11
*/
BusInOut PtrData(p30,p29,p8,p7,p6,p5,p28,p27);

#define __DOUTBUFSIZE 256
#define __DINBUFSIZE 256
char __outstr[__DOUTBUFSIZE];
char __instr[__DINBUFSIZE];

Serial pc(USBTX, USBRX); // tx, rx
DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
DigitalOut myled4(LED4);

//---------------------------------------------------------------------------------
void printer_side_ecp_mode_write_data(char c)
{
    /* Write data */
    Busy = 1;
    PtrData = c;

    /* Wait HostAck = L (nAutoFd) */
    while (nAutoFeed) {}

    /* Set PeriphClk = L (nAck) */
    nAck = 0;

    /* Wait HostAck = H (nAutoFd) */
    while (!nAutoFeed) {}

    /* Set PeriphClk = H (nAck) */
    nAck = 1;
}

void printer_side_ecp_mode_write_cmd(char c)
{
    /* Wait HostAck = L (nAutoFd) */
    while (nAutoFeed) {}

    /* Write command */
    Busy = 0;
    PtrData = c;

    /* Set PeriphClk = L (nAck) */
    nAck = 0;

    /* Wait HostAck = H (nAutoFd) */
    while (!nAutoFeed) {}

    /* Set PeriphClk = H (nAck) */
    nAck = 1;
}

void printer_side_ecp_sendblock(char *str, int len)
{
    PtrData.output();

    while (len--)
    {
        printer_side_ecp_mode_write_data(*str);
        ++str;
    }

    PtrData.input();
}

void printer_side_ecp_printf(char *str, ...)
{
    va_list args;
    int len;

    va_start(args, str);
    len=vsnprintf(__outstr,__DOUTBUFSIZE,str,args);
    va_end(args);

    printer_side_ecp_sendblock(__outstr,len);
}

//---------------------------------------------------------------------------------
void printer_side_ecprle_sendblock(char *str, int len)
{
int rle = 0;
char c;

    PtrData.output();

    while (len--)
    {
        c = *str;
        while (*(++str) == c) {++rle;}

        if (rle != 0)
        {
            printer_side_ecp_mode_write_cmd(rle);
            rle = 0;
        }
        printer_side_ecp_mode_write_data(c);
    }

    PtrData.input();
}

void printer_side_ecprle_printf(char *str, ...)
{
    va_list args;
    int len;

    va_start(args, str);
    len=vsnprintf(__outstr,__DOUTBUFSIZE,str,args);
    va_end(args);

    printer_side_ecprle_sendblock(__outstr,len);
}

//---------------------------------------------------------------------------------
void printer_side_byte_mode_write(char c)
{
    /* Wait HostBusy = L (nAutoFd) */
    while (nAutoFeed) {}

    PtrData = c;

    /* Set PtrClk = L (nAck) */
    nAck = 0;

    /* Wait HostBusy = H (nAutoFd) */
    while (!nAutoFeed) {}

    /* Set PtrClk = H (nAck) */
    nAck = 1;

    /* Wait HostClk = L (nStrobe) */
    while (nStrobe) {}

    /* Wait HostClk = H (nStrobe) */
    while (!nStrobe) {}
}

void printer_side_byte_sendblock(char *str, int len)
{
    PtrData.output();

    while (len--)
    {
        printer_side_byte_mode_write(*str);
        ++str;
    }

    PtrData.input();
}

void printer_side_byte_printf(char *str, ...)
{
    va_list args;
    int len;

    va_start(args, str);
    len=vsnprintf(__outstr,__DOUTBUFSIZE,str,args);
    va_end(args);

    printer_side_byte_sendblock(__outstr,len);
}

//---------------------------------------------------------------------------------
/*
Busy, PE,Select,nError   3-0,7-4
*/
void printer_side_write_nibble(char c)
{
    /* Wait HostBusy = L (nAutoFd) */
    while (nAutoFeed) {}

    nError   =  c & 0x01;
    Select   = (c & 0x02) >> 1;
    PaperOut = (c & 0x04) >> 2;
    Busy     = (c & 0x08) >> 3;

    /* Set PtrClk = H (nAck) */
    nAck = 1;

    /* Set PtrClk = L (nAck) */
    nAck = 0;

    /* Wait HostBusy = H (nAutoFd) */
    while (!nAutoFeed) {}

    /* Set PtrClk = H (nAck) */
    nAck = 1;
}

void printer_side_nibble_mode_write(char c)
{
    // data available
    nError = 0;
    printer_side_write_nibble(c);       // Low
    printer_side_write_nibble(c >> 4);  // High

    nError = 0;
}

void printer_side_nibble_sendblock(char *str, int len)
{
    while (len--)
    {
        printer_side_nibble_mode_write(*str);
        ++str;
    }
}

void printer_side_nibble_printf(char *str, ...)
{
    va_list args;
    int len;

    va_start(args, str);
    len=vsnprintf(__outstr,__DOUTBUFSIZE,str,args);
    va_end(args);

    printer_side_nibble_sendblock(__outstr,len);
}

//---------------------------------------------------------------------------------
unsigned char printer_side_read_char(void)
{
unsigned char c;

    /* When Strobe detected, set Busy */
    while (nStrobe) {}

    Busy = 1;

    /* Read data lines */
    c = PtrData;

    /* Send nACK pulse */
    Busy = 0;
    nAck = 0;
    nAck = 1;

    return c;
}

unsigned char printer_side_negotiate(void)
{
unsigned char c;

    /* Reply: Set nAck L, nERROR,PE,   Select H */
    nAck = 0;
    nError = 1;
    PaperOut = 1;
    Select = 1;

    /* Wait for nStrobe = L */
    while (nStrobe) {}

    /* Read extensibility byte */
    c = PtrData;

    /* Wait for nStrobe = H, nAUTOFEED = H */
    while (!(nStrobe & nAutoFeed)) {}

    // pc.printf("Host requested mode: %02X\r\n",c & 0xff);

       /* Reply: PE = L, 
    nError = L if peripheral has reverse channel data available   

    if requested mode is
        Available, Select = H
        Not available, Select = L
    */

    /* EPP not available */
    if (c == PAR_NEGOTIATE_REQ_EPP_MODE)
    {
        Select   = 0;
    }
    else
    {
        Select   = 1;
    }

    nError   = 0;
    PaperOut = 0;
    Busy     = 0;
    nAck     = 0;
    
    wait_us(2);
    
    /* Set nACK = H */
    nAck = 1;

    return c;
}

void compatibility_read(void)
{
unsigned char c;
int i = 0;

    while(nInit)
    {
        c = printer_side_read_char();

        /* Set Busy active so that we can print the received value */
        Busy = 1;

        pc.printf("%02X ",c & 0xff);
        ++i;
        if (i == 10)
        {
            i = 0;
            pc.printf("\r\n");
        }

        /* Set Busy inactive so that we can receive the following bytes */
        Busy = 0;
    }
}

//===========================================================================
int main(void)
{
unsigned char c;
char data;
int i = 0;
int rle = 0;

    pc.printf("Printer emulator on mbed\r\n");

    // set the outputs to the host computer
    PtrData.input();

state_init:
    myled1 = 0;
    myled2 = 0;
    myled3 = 0;
    myled4 = 0;

    while (!nInit) {}

    Busy = 0;
    nAck = 1;
    nError = 1;
    PaperOut = 0;
    Select = 0;

    if (!nStrobe)
    {
        /* Read data from PC compatibility mode */
        Busy = 1;

        /* Read data lines */
        pc.printf("%02X ",PtrData & 0xff);
        ++i;
        if (i == 16)
        {
            i = 0;
            pc.printf("\r\n");
        }

        /* Wait for nSTROBE = H */
        while (!nStrobe) {}

        /* Send nACK pulse */
        Busy = 0;
        nAck = 0;
        nAck = 1;
        goto state_init;
    }

    else if (!(nSelectIn & !nAutoFeed))
    {
        goto state_init;
    }

    /* Negotiation phase */
    /* PC: nSelectIn = H, nAUTOFEED = L */
    c = printer_side_negotiate();

    switch(c)
    {
        case PAR_NEGOTIATE_REQ_EPP_MODE: // Not available
            goto state_init;

        case PAR_NEGOTIATE_REQ_DEV_ID_ECP_MODE:
        case PAR_NEGOTIATE_REQ_ECP_MODE:
state_ecp_mode:
            // PARPORT_CMD_ECP_INIT1
            // PARPORT_CMD_ECP_INIT2
            if (!nSelectIn) goto state_init;

            // PARPORT_CMD_ECP_READ
            if (nStrobe)
            {
                // data available
                nError = 0;

                /* Acknowledge the reverse transfer request */
                PaperOut = 0;

                if (c == PAR_NEGOTIATE_REQ_DEV_ID_ECP_MODE)
                    printer_side_ecp_printf("%cSoftware printer emulator",26);
                else
                    printer_side_ecp_printf("Hello world from printer emulator in ecp mode\n");

                // End of data
                nError = 1;

                while (nSelectIn) {}
                goto state_init;
            }

            // PARPORT_CMD_ECP_WR_CMD
            // PARPORT_CMD_ECP_WR_DATA
            if (nInit)
            {
                /* Acknowledge the forward transfer request */
                PaperOut = 1;

                /* Read data from PC ecp mode */
                Busy = 1;

                /* Read data lines */
                pc.printf("%02X ",PtrData & 0xff);
                ++i;
                if (i == 16)
                {
                    i = 0;
                    pc.printf("\r\n");
                }

                Busy = 0;
            }

            goto state_ecp_mode;

        case PAR_NEGOTIATE_REQ_DEV_ID_ECP_RLE_MODE:
        case PAR_NEGOTIATE_REQ_ECP_RLE_MODE:
            rle = 0;
state_ecp_rle_mode:
            // PARPORT_CMD_ECP_INIT1
            // PARPORT_CMD_ECP_INIT2
            if (!nSelectIn) goto state_init;

            // PARPORT_CMD_ECP_READ
            if (nStrobe)
            {
                // data available
                nError = 0;

                /* Acknowledge the reverse transfer request */
                PaperOut = 0;

                if (c == PAR_NEGOTIATE_REQ_DEV_ID_ECP_RLE_MODE)
                    printer_side_ecprle_printf("%cSoftware printer emulator",26);
                else
                    printer_side_ecprle_printf("Hello world from printer emulator in ecp rle mode\n");

                // End of data
                nError = 1;

                while (nSelectIn) {}
                goto state_init;
            }

            // PARPORT_CMD_ECP_WR_CMD
            // PARPORT_CMD_ECP_WR_DATA
            if (nInit)
            {
                // PARPORT_CMD_ECP_WR_DATA
                if (nAutoFeed)
                {
                    /* Acknowledge the forward transfer request */
                    PaperOut = 1;

                    /* Read data from PC ecp mode */
                    Busy = 1;

                    /* Read data lines */
                    data = PtrData;

                    /* if previous byte was an RLE value, replicate the current byte */
                    if (rle != 0)
                    {
                        pc.printf("(%02X *) %02X ",rle & 0xff,data & 0xff);
                        rle = 0;
                        ++i;
                        if (i == 16)
                        {
                            i = 0;
                            pc.printf("\r\n");
                        }
                    }
                    else
                    {
                        pc.printf("%02X ",data & 0xff);
                        ++i;
                        if (i == 16)
                        {
                            i = 0;
                            pc.printf("\r\n");
                        }
                    }

                    Busy = 0;
                }
                else
                {
                    /* Acknowledge the forward transfer request */
                    PaperOut = 1;

                    /* Read data from PC ecp mode */
                    Busy = 1;

                    /* Read data lines */
                    data = PtrData;

                    /* RLE */
                    if ((data & 0x80) == 0)
                        /* RLE command: next byte to be replicated 1 to 127 times (2-128 bytes) */
                        rle = data & 0x7f;
                    else
                    {
                        /* Address */
                        pc.printf("[%02X]",data & 0xff);
                        ++i;
                        if (i == 16)
                        {
                            i = 0;
                            pc.printf("\r\n");
                        }
                    }
                    Busy = 0;
                }
            }

            goto state_ecp_rle_mode;

        case PAR_NEGOTIATE_REQ_DEV_ID_NIBBLE_MODE:
            if (!nInit) goto state_init;
            if (!nSelectIn) goto state_init;

            printer_side_nibble_printf("%cSoftware printer emulator",26);

            // End of nibble data
            nError = 1;

            while (nSelectIn) {}
            goto state_init;

        case PAR_NEGOTIATE_REQ_DEV_ID_BYTE_MODE:
            if (!nInit) goto state_init;
            if (!nSelectIn) goto state_init;

            printer_side_byte_printf("%cSoftware printer emulator",26);

            while (nSelectIn) {}
            goto state_init;

        case PAR_NEGOTIATE_NIBBLE_MODE:
            if (!nInit) goto state_init;
            if (!nSelectIn) goto state_init;

            printer_side_nibble_printf("Hello world from printer emulator in nibble mode\n");

            // End of nibble data
            nError = 1;

            while (nSelectIn) {}
            goto state_init;

        case PAR_NEGOTIATE_BYTE_MODE:
            if (!nInit) goto state_init;
            if (!nSelectIn) goto state_init;

            printer_side_byte_printf("Hello world from printer emulator in byte mode\n");

            while (nSelectIn) {}
            goto state_init;

        default:
            pc.printf("Mode %02X not supported\n",c & 0xff);
            goto state_init;
    }
}