/* d4lib.c
* Copyright (C) 2001 Jean-Jacques Sarton jj.sarton@t-online.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
/* this file will be a library, which will allow to use the EPSON
* Stylus Scanner and also allow to send commands to the
* Stylus Color 480/580.
*
* At this stage a lot of things are not implemented and the
* first goal is to get the Stylus Scanner printing.
* This may be reached if this file is compiled with the TEST
* option set.
*
* I donīt own a Stylus Scanner and I am not able to test this
* code, as desired. Printing on a Stylus Photo 1290 work fine
* with this.
*
* The best way to get the Stylus Scanner working is to test
* this and also correct my possibly errors.
* Programming knowledge will be helpful for this.
*
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "d4lib.h"
#ifndef RDTIMEOUT
#define RDTIMEOUT 10000
#define WRTIMEOUT 10000
#define RDDATATIMEOUT 1000
#define MICROTIMEOUT 1
#endif
int d4WrTimeout = WRTIMEOUT;
int d4RdTimeout = RDTIMEOUT;
int d4RdDataTimeout = RDDATATIMEOUT;
int d4MicroTimeout = 1;
int ppid = 0;
int debugD4 = 1;
typedef void (*signalHandler_t)(int);
static signalHandler_t sig;
static int timeoutGot = 0;
static int _readData(int fd, unsigned char *buf, int len);
static int d4Errno = 0;
/* commands for the D4 protocol
Transaction Cmd Reply
-------------- ---- -----
Init 0x00 0x80
OpenChannel 0x01 0x81
CloseChannel 0x02 0x82
Credit 0x03 0x83
CreditRequest 0x04 0x84
Exit 0x08 0x88
GetSocketID 0x09 0x89
GetServiceName 0x0a 0x8a
Error 0x7f -
*/
typedef struct cmdHeader_s
{
unsigned char psid;
unsigned char ssid;
unsigned char lengthH;
unsigned char lengthL;
unsigned char credit;
unsigned char control;
unsigned char command;
} cmdHeader_t;
typedef struct replyHeader_s
{
unsigned char psid;
unsigned char ssid;
unsigned char lengthH;
unsigned char lengthL;
unsigned char credit;
unsigned char control;
unsigned char command;
unsigned char result;
} replyHeader_t;
typedef struct init_s
{
cmdHeader_t head;
unsigned char revision;
} init_t;
typedef struct initReply_s
{
replyHeader_t head;
unsigned char revision;
} initReply_t;
typedef struct error_s
{
replyHeader_t head;
unsigned char epsid;
unsigned char essid;
unsigned char ecode;
} error_t;
/* results */
typedef struct errorMessage_s
{
unsigned char result;
const char *message;
int errorClass;
} errorMessage_t;
#define RECOVERABLE 0
#define FATAL 1
static errorMessage_t errorMessage[] =
{
{ 0x01, "Unable to begin conversation, try later." ,0 },
{ 0x02, "Protocol revision not supported." ,1 },
{ 0x03, "Transaction channel can't be closed." ,0 },
{ 0x04, "No sufficient resources available now." ,0 },
{ 0x05, "Connection denied." ,1 },
{ 0x06, "Channel already open." ,0 },
{ 0x07, "Credit overflow, previous credit remain valid." ,0 },
{ 0x08, "Channel is not open." ,1 },
{ 0x09, "Service not available on specified socket." ,1 },
{ 0x0a, "Service name to socket ID failed." ,1 },
{ 0x0b, "Init transaction failed." ,1 },
{ 0x0c, "Invalid packet size." ,1 },
{ 0x0d, "Requested packed size is 0, no data can be transferred." ,0 },
{ 0x80, "Malformed packet, ignored." ,1 },
{ 0x81, "No credit for received packet, ignored" ,0 },
{ 0x82, "Reply doesn't match with outstanding command, ignored." ,1 },
{ 0x83, "Packet size greater as negotiated size." ,1 },
{ 0x84, "Data received for a non opened channel." ,1 },
{ 0x85, "Reply with unknown result value received." ,1 },
{ 0x86, "Piggybacked credit in data packet cause overflow." ,1 },
{ 0x87, "Unknown 1284.4 Reply." ,0 },
{ 0x00, NULL ,0 }
};
#define RESET_TIMER(ti,oti) { signal(SIGALRM, sig); \
memset((void*)&ti,0,sizeof(ti)); \
memset((void*)&oti,0,sizeof(oti)); \
setitimer( ITIMER_REAL ,&ti, &oti); \
}
#define SET_TIMER(ti,oti,val) { memset((void*)&ti,0,sizeof(ti)); \
memset((void*)&oti,0,sizeof(oti)); \
ti.it_value.tv_sec = val/1000; \
ti.it_value.tv_usec = (val%1000)*1000; \
setitimer( ITIMER_REAL ,&ti, &oti); \
sig = signal(SIGALRM, sigAlarm); \
}
static int d4USleep(long usec)
{
struct timespec t;
t.tv_sec = 0;
t.tv_nsec = 1000l * usec;
return nanosleep(&t, NULL);
}
/*******************************************************************/
/* Function printHexValues */
/* */
/* Print hex code contained in the passed buffer */
/* */
/*******************************************************************/
static void printHexValues(const char *dir, const unsigned char *buf, int len)
{
int i, j;
int printable_count = 0;
int longest_printable_run = 0;
int current_printable_run = 0;
int print_strings = 0;
int blocks = (len + 15) / 16;
#if 0
len = len > 30 ? 30 : len;
#endif
printf("+++%s\n",dir);
for (i = 0; i < len; i++)
{
if (isprint(buf[i]))
{
if (!isspace(buf[i]))
printable_count++;
current_printable_run++;
}
else
{
if (current_printable_run > longest_printable_run)
longest_printable_run = current_printable_run;
}
}
if (current_printable_run > longest_printable_run)
longest_printable_run = current_printable_run;
if (longest_printable_run >= 8 ||
((float) printable_count / (float) len > .75))
print_strings = 1;
if (print_strings)
{
int print_prefix = 1;
for (i = 0; i < len; i++)
{
printf("%s%c", (print_prefix ? "+++" : ""),
isprint(buf[i])?buf[i]:'*');
print_prefix = 0;
if (buf[i] == ';' && i < len - 1)
{
printf("\n");
print_prefix = 1;
}
}
printf("\n");
}
for (j = 0; j < blocks; j++)
{
int baseidx = j * 16;
int count = len;
if (count > baseidx + 16)
count = baseidx + 16;
printf("+++ %4d: ", baseidx);
for ( i = baseidx; i < count;i++)
{
if (i % 4 == 0)
printf(" ");
printf(" %02x",buf[i]);
}
if (print_strings)
{
printf("\n+++ ");
for ( i = baseidx; i < count;i++)
{
if (i % 4 == 0)
printf(" ");
printf(" %c",
isprint(buf[i]) && !isspace(buf[i]) ? buf[i] : ' ');
}
}
printf("\n");
}
}
int SafeWrite(int fd, const void *data, int len)
{
int status;
int retries=30;
if (debugD4)
printHexValues("SafeWrite: ", data, len);
do
{
status = write(fd, data, len);
if(status < len)
d4USleep(d4WrTimeout);
retries--;
}
while ((status < len) && (retries > 0));
return(status);
}
/*******************************************************************/
/* Function sigAlarm(int code) */
/* */
/* do nothing, avoid printing of undesired messages and/or */
/* other not desirable actions */
/* */
/*******************************************************************/
static void sigAlarm(int code)
{
timeoutGot = -1;
}
/*******************************************************************/
/* Function printError() */
/* print an error message on stdout */
/* */
/* Input: unsigned char errorNb the error number */
/* */
/* Return: fatal = 1 or recoverable = 0 */
/* */
/*******************************************************************/
static int printError(unsigned char errorNb)
{
errorMessage_t *msg = errorMessage;
if ( errorNb == 0 )
{
return 0;
}
while ( msg->result )
{
if ( msg->result == errorNb )
{
if (debugD4)
printf("+++ %s\n", msg->message);
return msg->errorClass;
}
msg++;
}
printf("Unknown IEEE 1284.4 error number %d\n",errorNb);
return 0;
}
/*******************************************************************/
/* Function printCmdType() */
/* print on stdout the command name */
/* Input: unsigned char *cmd the data are to be put here */
/* */
/* Return: - */
/* */
/*******************************************************************/
static void printCmdType(unsigned char *cmd)
{
printf("+++");
if (cmd[6] & 0x80)
printf(">>>");
if ( cmd[0] == 0 && cmd[1] == 0 )
{
switch(cmd[6] & 0x7f)
{
case 0: printf("--- Init ---\n");break;
case 1: printf("--- OpenChannel ---\n");break;
case 2: printf("--- CloseChannel ---\n");break;
case 3: printf("--- Credit ---\n");break;
case 4: printf("--- CreditRequest ---\n");break;
case 8: printf("--- Exit ---\n");break;
case 9: printf("--- GetSocketID ---\n");break;
case 10: printf("--- GetServiceName ---\n");break;
case 0x45: printf("--- EnterD4Mode ---\n");break;
case 0x7f: printf("--- Error ---\n");break;
default: printf("--- ?????????????? ---\n");break;
}
}
else
{
printf("--- Send Data ---\n");
}
}
/*******************************************************************/
/* Function writeCmd() */
/* write a command */
/* Input: int fd file handle */
/* char *cmd the data are to be put here */
/* int len the number of bytes to read */
/* */
/* Return: number of bytes write or -1 */
/* */
/*******************************************************************/
static int writeCmd(int fd, unsigned char *cmd, int len)
{
int w;
int i = 0;
struct itimerval ti, oti;
# if PTIME
struct timeval beg, end;
long dt;
# endif
if ( debugD4 )
{
printCmdType(cmd);
# if PTIME
gettimeofday(&beg, NULL);
# endif
if ( cmd[0] == 0 && cmd[1] == 0 )
{
printHexValues("Send: ", cmd, len);
}
else
{
printHexValues("Send: ", cmd, 6);
}
}
/* according to Glen Steward, this will solve problems */
/* for the cartridge exchange with the Stylus Color 580 */
d4USleep(d4MicroTimeout);
timeoutGot = 0;
errno = 0;
while ( i < len )
{
SET_TIMER(ti,oti,d4WrTimeout);
w = SafeWrite(fd, cmd+i,len-i);
RESET_TIMER(ti,oti);
if ( w < 0 )
{
if ( debugD4 )
{
perror("Write error");
}
i= -1;
break;
}
else
i += w;
}
# if PTIME
if ( debugD4 )
{
gettimeofday(&end, NULL);
dt = (end.tv_sec - beg.tv_sec) * 1000000;
dt += end.tv_usec - beg.tv_usec;
printf("+++Write time %5.3f s\n",(double)dt/1000000);
}
# endif
if ( timeoutGot )
return -1;
return i;
}
/*******************************************************************/
/* Function readAnswer() */
/* Read the datas returned by the printer */
/* Input: int fd file handle */
/* char *buf the data are to be put here */
/* int len the number of bytes to read */
/* */
/* Return: number of bytes read. -1 on error */
/* */
/*******************************************************************/
int readAnswer(int fd, unsigned char *buf, int len, int allowExtra)
{
int rd = 0;
int total = 0;
struct timeval beg, end;
struct itimerval ti, oti;
long dt;
int count = 0;
int first_read = 1;
int excess = 0;
/* wait a little bit before reading an answer */
d4USleep(d4RdTimeout);
/* for error handling in case of timeout */
timeoutGot = 0;
/* set errno to 0 in order to get correct informations */
/* in case of error */
errno = 0;
gettimeofday(&beg, NULL);
if (debugD4)
printf("+++length: %i\n", len);
while ( total < len )
{
SET_TIMER(ti,oti, d4RdTimeout);
rd = read(fd, buf+total, len-total);
if (debugD4)
{
if (first_read)
{
printf("+++read: ");
first_read = 0;
}
if (rd < 0)
{
printf("%i %s\n", rd, errno != 0 ?strerror(errno) : "");
first_read = 1;
}
else
printf("%i ", rd);
}
RESET_TIMER(ti,oti);
if ( rd <= 0 )
{
gettimeofday(&end, NULL);
dt = (end.tv_sec - beg.tv_sec) * 1000;
dt += (end.tv_usec - beg.tv_usec) / 1000;
if ( dt > d4RdTimeout * 2 )
{
if ( debugD4 )
printf("\n+++Timeout 1 at readAnswer() rcv %d bytes",total);
timeoutGot = 1;
break;
}
count++;
if ( count >= 100 )
{
timeoutGot = 1;
if ( rd == 0 )
errno = -1; /* tell that there is an abnormal condition */
break;
}
errno = 0;
} else {
total += rd;
if ( total > 3 )
{
/* the bytes idx 2 and 3 contain the length */
/* in case of errors this may differ from */
/* the expected length. Setting len to this */
/* value will avoid waiting for timeout */
int newlen = (buf[2] << 8) + buf[3];
if (len > newlen)
{
if (debugD4)
printf("\n+++Changing len from %d to %d", len, newlen);
len = newlen;
}
else if (len < newlen)
{
excess = newlen - len;
if (debugD4)
printf("\n+++Expected %d, getting %d, %sflushing %d",
len, newlen, allowExtra ? "not " : "", excess);
}
}
}
d4USleep(d4RdTimeout);
}
if (debugD4)
printf("\n");
if (! allowExtra)
{
int retry_count = 0;
while (excess > 0)
{
char wastebuf[256];
int bytes = excess > 256 ? 256 : excess;
int status = read(fd, wastebuf, bytes);
if (status < 0)
break;
else if (status == 0 && retry_count > 2)
break;
else if (status == 0)
retry_count++;
else
retry_count = 0;
if (status < bytes)
d4USleep(d4RdTimeout);
if (debugD4)
printHexValues("waste", (const unsigned char *) wastebuf, status);
excess -= status;
}
}
if ( debugD4 )
{
printCmdType(buf);
# if PTIME
gettimeofday(&end, NULL);
# endif
printf("+++total: %i\n", total);
printHexValues("Recv: ",buf,total);
# if PTIME
dt = (end.tv_sec - beg.tv_sec) * 1000000;
dt += end.tv_usec - beg.tv_usec;
printf("+++Read time %5.3f s\n",(double)dt/1000000);
# endif
}
if ( timeoutGot )
{
if ( debugD4 )
printf("+++Timeout 2 at readAnswer()\n");
return -1;
}
return total;
}
static void _flushData(int fd)
{
int rd = 0;
struct itimerval ti, oti;
char buf[1024];
int len = 1023;
int count = 200;
d4USleep(d4RdTimeout);
/* for error handling in case of timeout */
timeoutGot = 0;
/* set errno to 0 in order to get correct informations */
/* in case of error */
errno = 0;
if (debugD4)
printf("+++flush data: length: %i\n", len);
do
{
d4USleep(d4RdTimeout);
SET_TIMER(ti,oti, d4RdTimeout);
rd = read(fd, buf, len);
if (debugD4)
printf("+++flush: read: %i %s\n", rd,
rd < 0 && errno != 0 ?strerror(errno) : "");
RESET_TIMER(ti,oti);
count--;
} while ( count > 0 && (rd > 0 || (rd < 0 && errno == EAGAIN)));
}
/*******************************************************************/
/* Function _readData() */
/* Read the datas returned by the printer */
/* Input: int fd file handle */
/* char *buf the data are to be put here */
/* int len the number of bytes to read */
/* */
/* Return: number of bytes read. -1 on error */
/* */
/*******************************************************************/
static int _readData(int fd, unsigned char *buf, int len)
{
int rd = 0;
int total = 0;
int toGet = 0;
unsigned char header[6];
struct timeval beg, end;
long dt;
struct itimerval ti, oti;
/* set errno to 0 in order to get correct informations */
/* in case of error */
errno = 0;
/* read the first 6 bytes */
gettimeofday(&beg, NULL);
while ( total < 6 )
{
SET_TIMER(ti,oti, d4RdTimeout);
rd = read(fd, header+total, 6-total);
RESET_TIMER(ti,oti);
if ( rd <= 0 )
{
gettimeofday(&end, NULL);
dt = (end.tv_sec - beg.tv_sec) * 1000;
dt += (end.tv_usec - beg.tv_usec) / 1000;
if ( dt > d4RdTimeout*3 )
{
if ( debugD4 )
printf("+++Timeout at _readData(), dt = %ld ms\n", dt);
return -1;
break;
}
continue;
}
else
{
total += rd;
}
}
if ( debugD4 )
printHexValues("Recv: ",header,total);
if ( total == 6 )
{
toGet = (header[2] << 8) + header[3] - 6;
if (debugD4)
printf("+++toGet: %i\n", toGet);
total = 0;
gettimeofday(&beg, NULL);
while ( total < toGet )
{
SET_TIMER(ti,oti, d4RdTimeout);
rd = read(fd, buf+total, toGet-total);
RESET_TIMER(ti,oti);
if ( rd <= 0 )
{
gettimeofday(&end, NULL);
dt = (end.tv_sec - beg.tv_sec) * 1000;
dt += (end.tv_usec - beg.tv_usec) / 1000;
if ( dt > d4RdTimeout*3 )
{
if ( debugD4 )
printf("+++Timeout at _readData(), dt = %ld ms\n",dt);
return -1;
break;
}
continue;
}
else
{
total += rd;
}
}
if ( debugD4 )
printHexValues("Recv: ",buf,total);
return total;
}
return -1;
}
/*******************************************************************/
/* Function sendReceiveCmd() */
/* send a command and get the answer. */
/* Input: int fd file handle */
/* char *buf the data are to be put here */
/* int len the number of bytes to read */
/* */
/* Return: number of bytes read */
/* */
/*******************************************************************/
static int sendReceiveCmd(int fd, unsigned char *cmd, int len, unsigned char *answer, int expectedlen, int allowExtra)
{
int rd;
d4Errno = 0;
if ( (rd = writeCmd(fd, cmd, len ) ) != len )
{
if ( rd < 0 ) return -1;
return 0;
}
rd = readAnswer(fd, answer, expectedlen, allowExtra );
if ( rd == 0 )
{
/* no answer from device */
return 0;
}
else if ( rd < 0 )
{
/* interrupted write call */
if ( debugD4 )
printf("+++interrupt received\n");
return -1;
}
else
{
/* check result */
if ( answer[6] == 0x7f )
{
printError(answer[9]);
d4Errno = answer[9];
return -1;
}
else if ( answer[7] != 0 )
{
d4Errno = answer[7];
if ( printError(answer[7]) )
{
return -1;
}
return 0;
}
else
{
return rd;
}
}
}
/*******************************************************************/
/* Function EnterIEEE() */
/* send a command and get the answer. */
/* Input: int fd file handle */
/* */
/* Return: 0 on error 1 if all is OK */
/* */
/*******************************************************************/
int EnterIEEE(int fd)
{
unsigned char buf[200];
unsigned char cmd[] =
{
0x00, 0x00, 0x00, 0x1b, 0x01, '@', 'E', 'J', 'L', ' ',
'1', '2', '8', '4', '.', '4', 0x0a, '@', 'E', 'J',
'L', 0x0a, '@', 'E', 'J', 'L', 0x0a
};
int rd;
memset(buf, 0, sizeof(buf));
Loop:
if ( writeCmd(fd, cmd, sizeof(cmd) ) != sizeof(cmd) )
{
return 0;
}
rd = readAnswer(fd, buf, 8, 0);
if ( rd == 0 )
{
/* no answer from device */
if (debugD4)
printf("+++>>>No answer from printer\n");
return 0;
}
else if ( rd < 0 )
{
if (debugD4)
printf("+++>>>Interrupted write\n");
/* interrupted write call */
return 0;
}
else
{
int i;
/* check result */
for (i=0; i < rd; i++ )
if ( buf[i] != 0 )
break;
if ( i == rd ) goto Loop;
return 1;
}
}
/*******************************************************************/
/* Function Init() */
/* handle the init command */
/* Input: int fd file handle */
/* */
/* Return: 0 on error 1 if all is OK */
/* */
/*******************************************************************/
int Init(int fd)
{
unsigned char buf[20];
init_t cmd;
int rd;
cmd.head.psid = 0;
cmd.head.ssid = 0;
cmd.head.lengthH = 0;
cmd.head.lengthL = 8;
cmd.head.credit = 1;
cmd.head.control = 0;
cmd.head.command = 0;
cmd.revision = 0x10;
rd = sendReceiveCmd(fd, (unsigned char*)&cmd, sizeof(cmd), buf, 9, 0 );
return rd == 9 ? 1 : 0;
}
/*******************************************************************/
/* Function Exit() */
/* handle the Exit command */
/* Input: int fd file handle */
/* */
/* Return: 0 on error 1 if all is OK */
/* */
/*******************************************************************/
int Exit(int fd)
{
int rd;
unsigned char buf[20];
cmdHeader_t cmd;
cmd.psid = 0;
cmd.ssid = 0;
cmd.lengthH = 0;
cmd.lengthL = 7;
cmd.credit = 1;
cmd.control = 0;
cmd.command = 8;
rd = sendReceiveCmd(fd, (unsigned char*)&cmd, sizeof(cmd), buf, 8, 0 );
return rd > 0 ? 1 : rd;
}
/*******************************************************************/
/* Function GetSocketID() */
/* handle the GetSocketID command */
/* Input: int fd file handle */
/* char *serviceName name of wanted service */
/* */
/* Return: 0 on error else the socket ID */
/* */
/*******************************************************************/
int GetSocketID(int fd, const char *serviceName)
{
/* the service name may not be longer as 40 bytes */
int len = sizeof(cmdHeader_t) + strlen(serviceName);
char buf[100];
unsigned char rBuf[100];
int rd;
cmdHeader_t *cmd = (cmdHeader_t*)buf;
cmd->psid = 0;
cmd->ssid = 0;
cmd->lengthH = 0;
cmd->lengthL = len & 0xff;
cmd->credit = 1;
cmd->control = 0;
cmd->command = 0x09;
strcpy(buf + sizeof(cmdHeader_t), serviceName);
rd = sendReceiveCmd(fd, (unsigned char*)buf, len, rBuf, len + 2, 0);
if ( rd > 0 )
{
return rBuf[8];
}
else
{
return 0;
}
}
/*******************************************************************/
/* Function OpenChannel() */
/* handle the OpenChannel command */
/* Input: int fd file handle */
/* I/O: int *sndSz The size for sendig of datas */
/* int *recSz The size for receiving of datas */
/* */
/* Return: -1 on error or 1 if all is OK */
/* */
/*******************************************************************/
int OpenChannel(int fd, unsigned char sockId, int *sndSz, int *rcvSz)
{
unsigned char cmd[17];
unsigned char buf[20];
int rd;
int i;
for(i = 0; i < 5; i++) /* Retry count */
{
cmd[0] = 0; /* transaction sockets */
cmd[1] = 0;
cmd[2] = 0; /* len */
cmd[3] = 17; /* len */
cmd[4] = 1; /* credit */
cmd[5] = 0; /* control */
cmd[6] = 1; /* command */
cmd[7] = sockId; /* sockets # */
cmd[8] = sockId; /* sockets # */
cmd[9] = *sndSz >> 8; /* packet size in send dir */
cmd[10] = *sndSz & 0xff;
cmd[11] = *rcvSz >> 8; /* packet size in recv dir */
cmd[12] = *rcvSz & 0xff;
cmd[13] = 0; /* max outstanding Credit, must be 0 */
cmd[14] = 0;
cmd[15] = 0; /* initial credit for us ? */
cmd[16] = 0;
rd = sendReceiveCmd(fd, cmd, 17, buf, 16, 0);
if ( rd == -1 )
{
if (debugD4)
printf("+++OpenChannel %d fails, error %d\n", sockId, d4Errno);
if (d4Errno == 6) /* channel already open */
{
if ( debugD4 )
printf("+++Channel %d already open, closing\n", sockId);
CloseChannel(fd, sockId);
continue;
}
else
return -1;
}
else if ( rd == 16 )
{
if ( buf[7] == 4 )
{
/* device canīt allocate resources now */
continue;
}
else if ( buf[7] != 0 )
{
if (debugD4)
printf("+++OpenChannel %d fails, hard error\n", sockId);
/* hard error */
return -1;
}
*sndSz = (buf[10]<<8) + buf[11];
*rcvSz = (buf[12]<<8) + buf[13];
break;
}
else
{
if (d4Errno == 6) /* channel already open */
{
if ( debugD4 )
printf("+++Channel %d already open, closing\n", sockId);
CloseChannel(fd, sockId);
continue;
}
/* at this stage we can only have an error */
if (debugD4)
printf("+++OpenChannel %d fails, wrong count %d\n", sockId, rd);
return -1;
}
}
return 1;
}
/*******************************************************************/
/* Function CloseChannel() */
/* handle the CloseChannel command */
/* Input: int fd file handle */
/* unsigned char socketID he socket to close */
/* */
/* Return: -1 on error or 1 if all is OK */
/* */
/*******************************************************************/
int CloseChannel(int fd, unsigned char socketID)
{
unsigned char buf[100];
int rd;
cmdHeader_t *cmd = (cmdHeader_t *)buf;
cmd->psid = 0;
cmd->ssid = 0;
cmd->lengthH = 0;
cmd->lengthL = 10;
cmd->credit = 1;
cmd->control = 0;
cmd->command = 2;
buf[sizeof(cmdHeader_t)+0] = socketID;
buf[sizeof(cmdHeader_t)+1] = socketID;
buf[sizeof(cmdHeader_t)+2] = 0;
rd = sendReceiveCmd(fd, buf,10, buf, 10, 0);
return rd == 10 ? 1 : rd;
}
/*******************************************************************/
/* Function CreditRequest() */
/* handle the CreditRequest command */
/* Input: int fd file handle */
/* unsigned char socketID he socket to close */
/* */
/* Return: -1 on error else the credit got */
/* */
/*******************************************************************/
int CreditRequest(int fd, unsigned char socketID)
{
int rd;
unsigned char buf[100];
unsigned char rBuf[100];
cmdHeader_t *cmd = (cmdHeader_t *)buf;
cmd->psid = 0;
cmd->ssid = 0;
cmd->lengthH = 0;
cmd->lengthL = 13;
cmd->credit = 1;
cmd->control = 0;
cmd->command = 4;
buf[sizeof(cmdHeader_t)+0] = socketID;
buf[sizeof(cmdHeader_t)+1] = socketID;
buf[sizeof(cmdHeader_t)+2] = 0x00;
buf[sizeof(cmdHeader_t)+3] = 0x80;
buf[sizeof(cmdHeader_t)+4] = 0xff;
buf[sizeof(cmdHeader_t)+5] = 0xff;
rd = sendReceiveCmd(fd, buf, 13, rBuf, 12, 0);
if ( rd == 12 )
{
/* this is the credit */
return (rBuf[10]*256)+rBuf[11];
}
else
{
return rd > 0 ? 0 : rd; /* there was an error */
}
}
/*******************************************************************/
/* Function Credit() */
/* give credit to the attached device */
/* Input: int fd file handle */
/* unsigned char socketID the socket to close */
/* */
/* Return: -1 on error or 1 if all is OK */
/* */
/*******************************************************************/
/* needed for sending of commands (channel 2) or scanning */
int Credit(int fd, unsigned char socketID, int credit)
{
int rd;
unsigned char buf[100];
unsigned char rBuf[100];
cmdHeader_t *cmd = (cmdHeader_t*)buf;
cmd->psid = 0;
cmd->ssid = 0;
cmd->lengthH = 0;
cmd->lengthL = 0x0b;
cmd->credit = 1;
cmd->control = 0;
cmd->command = 0x03;
buf[sizeof(cmdHeader_t)+0] = socketID;
buf[sizeof(cmdHeader_t)+1] = socketID;
buf[sizeof(cmdHeader_t)+2] = credit >> 8;
buf[sizeof(cmdHeader_t)+3] = credit & 0xff;
rd = sendReceiveCmd(fd, buf, 11, rBuf, 10, 0);
if ( rd == 10 )
{
return 1;
}
else
{
return 0;
}
}
/*******************************************************************/
/* Function askForCredit() */
/* Convenience function */
/* handle the CreditRequest command */
/* Input: int fd file handle */
/* unsigned char socketID */
/* IN/Out int *sndSize for error handling */
/* IN/Out int *rcvSize for error handling */
/* */
/* Return: credit */
/* */
/* Remark: CreditRequest() will be called in a loop as long as */
/* the returned credit is 0 */
/* */
/*******************************************************************/
#define MAX_CREDIT_REQUEST 2
int askForCredit(int fd, unsigned char socketID, int *sndSize, int *rcvSize)
{
int credit = 0;
int count = 0;
int retries = 10;
while (credit == 0 && retries-- >= 0 )
{
while((credit=CreditRequest(fd,socketID)) == 0 && count < MAX_CREDIT_REQUEST && retries-- >= 0)
d4USleep(d4RdTimeout);
if ( credit == -1 )
{
if ( errno == ENODEV || count == MAX_CREDIT_REQUEST )
{
break;
}
credit = 0;
/* init printer and reopen the printer channel */
CloseChannel(fd, socketID);
socketID = GetSocketID(fd, "EPSON-CTRL");
if ( Init(fd) )
{
if (debugD4)
printf("+++askForCredit init succeeded, now try to open\n");
OpenChannel(fd, socketID, sndSize, rcvSize);
}
}
/* if the parent died, live this loop if credit not got */
if ( credit == 0 && getppid() == ppid )
return 0;
count++;
}
return credit;
}
/*******************************************************************/
/* Function writeData() */
/* Convenience function */
/* write the data to the device */
/* Input: int fd file handle */
/* unsigned char socketID the deetination socket */
/* unsigned char *buf the datas to be send */
/* int len how many datas are to we send */
/* int eoj set out of band flag if eoj set */
/* */
/* Return: number of bytes written or -1; */
/* */
/*******************************************************************/
int writeData(int fd, unsigned char socketID, const unsigned char *buf, int len, int eoj)
{
unsigned char cmd[6];
int wr = 0;
int ret = 0;
struct itimerval ti, oti;
struct timeval beg;
static unsigned char *buffer = NULL;
static int bLen = 0;
if ( debugD4 )
{
printf("+++--- Send Data ---\n");
gettimeofday(&beg, NULL);
}
len += 6;
if ( len > bLen )
{
if ( buffer == NULL )
buffer = (unsigned char*)malloc(len);
else
buffer = (unsigned char*)realloc(buffer, len);
if ( buffer == NULL )
return -1;
bLen = len;
}
cmd[0] = socketID;
cmd[1] = socketID;
cmd[2] = len >> 8;
cmd[3] = len & 0xff;
cmd[4] = 0;
cmd[5] = eoj ? 1 : 0;
memcpy(buffer, cmd, 6);
memcpy(buffer + 6, buf, len - 6 );
while( ret > -1 && wr != len )
{
SET_TIMER(ti,oti,d4WrTimeout);
ret = SafeWrite(fd, buffer+wr, len-wr );
RESET_TIMER(ti,oti);
if ( ret == -1 )
{
perror("write: ");
}
else
{
wr += ret;
}
}
if ( debugD4 )
{
# if PTIME
gettimeofday(&end, NULL);
dt = (end.tv_sec - beg.tv_sec) * 1000000;
dt += end.tv_usec - beg.tv_usec;
# endif
printf("+++Send: ");
for ( ret = 0; (wr > 0) && (ret < ((wr > 20) ? 20 : wr)) ; ret++ )
printf("%02x ", buffer[ret]);
printf("\n+++ ");
for ( ret = 0; (wr > 0) && (ret < ((wr > 20) ? 20 : wr)) ; ret++ )
printf("%c ", isprint(buffer[ret])&&!isspace(buffer[ret])?buffer[ret]:' ');
printf("\n");
# if PTIME
printf("+++Write time %5.3f s\n",(double)dt/1000000);
# endif
}
if ( wr > 6 )
wr -= 6;
else
wr = -1;
return wr;
}
/*******************************************************************/
/* Function readData() */
/* Convenience function */
/* give credit and read then the expected datas */
/* Input: int fd file handle */
/* unsigned char socketID the destination socket */
/* unsigned char *buf the datas to be send */
/* int len howmany datas are to we send */
/* */
/* Return: number of bytes read or -1; */
/* */
/*******************************************************************/
int readData(int fd, unsigned char socketID, unsigned char *buf, int len)
{
int ret;
/* give credit */
if ( Credit(fd, socketID, 1) == 1 )
{
/* wait a little bit */
d4USleep(d4RdDataTimeout);
ret = _readData(fd, buf, len);
return ret;
}
else
{
return -1;
}
}
/*******************************************************************/
/* Function writeAndReadData() */
/* Convenience function */
/* give credit and read then the expected datas */
/* Input: int fd file handle */
/* unsigned char socketID the destination socket */
/* unsigned char *cmd the datas to be send */
/* int cmd_len howmany datas are to we send */
/* int eoj set out of band flag if eoj set */
/* unsigned char *buf the datas to be send */
/* int *sndSz Send buffer size */
/* int *rcvSz Receive buffer size */
/* int len how many datas are to we send */
/* fptr test function to verify buffer contents */
/* */
/* Return: number of bytes read or -1; */
/* */
/* This allows us to give credit before sending the command. */
/* Sending the command and then giving credit sometimes causes */
/* the actual data to be sent as a reply to the credit command. */
/* */
/*******************************************************************/
int writeAndReadData(int fd, unsigned char socketID,
const unsigned char *cmd, int cmd_len, int eoj,
unsigned char *buf, int len, int *sndSz, int *rcvSz,
int (*test)(const unsigned char *buf))
{
int ret;
int retry = 5;
int credit = askForCredit(fd, socketID, sndSz, rcvSz);
if (credit < 0)
return -1;
/* give credit */
if ( Credit(fd, socketID, 1) == 1 )
{
if (writeData(fd, socketID, cmd, cmd_len, eoj) <= 0)
return -1;
/* wait a little bit */
do
{
d4USleep(d4RdDataTimeout);
ret = _readData(fd, buf, len);
if (ret < 0)
return ret;
} while (retry-- >= 0 && (!test || !(*test)(buf)));
return ret;
}
else
return -1;
}
/*******************************************************************/
/* Function readData() */
/* Convenience function */
/* give credit and read then the expected datas */
/* Input: int fd file handle */
/* unsigned char socketID the destination socket */
/* unsigned char *buf the datas to be send */
/* int len howmany datas are to we send */
/* */
/* Return: number of bytes written or -1; */
/* */
/*******************************************************************/
void flushData(int fd, unsigned char socketID)
{
if (debugD4)
printf("+++flushData %d\n", socketID);
/* give credit */
if (socketID != (unsigned char) -1)
{
if ( Credit(fd, socketID, 1) == 1 )
{
/* wait a little bit */
d4USleep(d4RdDataTimeout);
_flushData(fd);
}
}
else
_flushData(fd);
}
/*******************************************************************/
/* Function clearSndBuf() */
/* Convenience function */
/* */
/* Input: int fd file handle */
/* */
/* */
/*******************************************************************/
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
static inline void clearSndBuf(int fd)
{
char buf[256];
struct itimerval ti, oti;
SET_TIMER(ti,oti, d4RdTimeout);
while ( read(fd, buf, sizeof(buf) ) > 0 )
SET_TIMER(ti,oti, d4RdTimeout);
RESET_TIMER(ti,oti);
}
#pragma GCC diagnostic pop
void setDebug(int debug)
{
debugD4 = debug;
}
#if 0 /* implementation later ? */
int InitReply(int fd)
{
unsigned char buf[20];
initReply_t cmd;
cmd.head.psid = 0;
cmd.head.ssid = 0;
cmd.head.lengthH = 0;
cmd.head.lengthL = 9;
cmd.head.credit = 1;
cmd.head.control = 0;
cmd.head.command = 0x80;
cmd.head.result = 0; /* put the correct value here, 0,1,2 or 0x0b */
cmd.revision = 0x10;
}
int ExitReply(int fd)
{
replyHeader_t cmd;
cmd.psid = 0;
cmd.ssid = 0;
cmd.lengthH = 0;
cmd.lengthL = 7;
cmd.credit = 1; /* always ignored */
cmd.control = 0;
cmd.command = 0x88;
cmd.result = 0x0; /* put the correct value here always 0 */
}
int Error(int fd)
{
char
error_t cmd;
cmd.head.psid = 0;
cmd.head.ssid = 0;
cmd.head.lengthH = 0;
cmd.head.lengthL = 0x0a;
cmd.head.credit = 0;
cmd.head.control = 0;
cmd.head.command = 0x7f;
cmd.epsid = psid;
cmd.essid = ssid;
cmd.ecode = 0x80; /* + 1...7 */
}
int GetSocketIDReply(int fd, unsigned char socketID)
{
/* the service name may not be longer as 40 bytes */
int len = sizeof(replyHeader_t) + 1 + strlen(serviceName);
unsigned char buf[100];
replyHeader_t *cmd = buf;
cmd->psid = 0;
cmd->ssid = 0;
cmd->lengthH = 0;
cmd->lengthL = len & 0xff;
cmd->credit = 1;
cmd->control = 0;
cmd->command = 0x89;
cmd->result = 0; /* put the correct vale here 0 or 0x0a */
buf[sizeof(cmdHeader_t)] = socketID;
strcpy(buf+1+sizeof(cmdHeader_t), serviceName);
}
int GetServiceName(inf fd, unsigned char socketID)
{
int rd;
unsigned char buf[100];
cmdHeader_t *cmd = buf;
cmd->psid = 0;
cmd->ssid = 0;
cmd->lengthH = 0;
cmd->lengthL = 8;
cmd->credit = 1;
cmd->control = 0;
cmd->command = 0x0a;
buf[sizeof(cmdHeader_t)] = socketID;
}
/* as GetSocketIDReply but with command 0x8a instead 0f 0x89 */
int GetServiceNameReply(inf fd)
{
/* the service name may not be longer as 40 bytes */
int len = sizeof(replyHeader_t) + 1 + strlen(serviceName);
unsigned char buf[100];
replyHeader_t *cmd = buf;
cmd->psid = 0;
cmd->ssid = 0;
cmd->lengthH = 0;
cmd->lengthL = len & 0xff;
cmd->credit = 1;
cmd->control = 0;
cmd->command = 0x8a;
cmd->result = 0; /* put the correct vale here 0 or 0x0a */
buf[sizeof(replyHeader_t)] = socketID;
strcpy(buf+1+sizeof(replyHeader_t), serviceName);
}
int CreditReply(int fd, unsigned char socketID, int credit)
{
unsigned char buf[100];
replyHeader_t *cmd = buf;
cmd->psid = 0;
cmd->ssid = 0;
cmd->lengthH = 0;
cmd->lengthL = 0x0b;
cmd->credit = 1;
cmd->control = 0;
cmd->command = 0x83;
buf[sizeof(replyHeader_t)] = socketID;
buf[sizeof(replyHeader_t)+1] = socketID;
}
#endif