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
Diff: main.cpp
- 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; + } +}