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

Revision:
0:8133df8bab0f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sat May 07 23:08:51 2011 +0000
@@ -0,0 +1,637 @@
+#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;
+    }
+}