1/* d4lib.c 2 * Copyright (C) 2001 Jean-Jacques Sarton jj.sarton@t-online.de 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 */ 18 19/* this file will be a library, which will allow to use the EPSON 20 * Stylus Scanner and also allow to send commands to the 21 * Stylus Color 480/580. 22 * 23 * At this stage a lot of things are not implemented and the 24 * first goal is to get the Stylus Scanner printing. 25 * This may be reached if this file is compiled with the TEST 26 * option set. 27 * 28 * I don��t own a Stylus Scanner and I am not able to test this 29 * code, as desired. Printing on a Stylus Photo 1290 work fine 30 * with this. 31 * 32 * The best way to get the Stylus Scanner working is to test 33 * this and also correct my possibly errors. 34 * Programming knowledge will be helpfull for this. 35 * 36 */ 37 38 39#include <stdio.h> 40#include <stdlib.h> 41#include <sys/types.h> 42#include <sys/stat.h> 43#include <signal.h> 44#include <fcntl.h> 45#include <sys/time.h> 46#include <unistd.h> 47#include <errno.h> 48#include <string.h> 49#include <ctype.h> 50 51#include "d4lib.h" 52 53 54#ifndef RDTIMEOUT 55#define RDTIMEOUT 10000 56#define WRTIMEOUT 10000 57#define RDDATATIMEOUT 1000 58#define MICROTIMEOUT 1 59#endif 60 61int d4WrTimeout = WRTIMEOUT; 62int d4RdTimeout = RDTIMEOUT; 63int d4RdDataTimeout = RDDATATIMEOUT; 64int d4MicroTimeout = 1; 65int ppid = 0; 66 67int debugD4 = 1; 68 69typedef void (*signalHandler_t)(int); 70static signalHandler_t sig; 71static int timeoutGot = 0; 72static int _readData(int fd, unsigned char *buf, int len); 73 74static int d4Errno = 0; 75 76/* commands for the D4 protocol 77 78Transaction Cmd Reply 79-------------- ---- ----- 80Init 0x00 0x80 81OpenChannel 0x01 0x81 82CloseChannel 0x02 0x82 83Credit 0x03 0x83 84CreditRequest 0x04 0x84 85Exit 0x08 0x88 86GetSocketID 0x09 0x89 87GetServiceName 0x0a 0x8a 88Error 0x7f - 89 90*/ 91 92typedef struct cmdHeader_s 93{ 94 unsigned char psid; 95 unsigned char ssid; 96 unsigned char lengthH; 97 unsigned char lengthL; 98 unsigned char credit; 99 unsigned char control; 100 unsigned char command; 101} cmdHeader_t; 102 103typedef struct replyHeader_s 104{ 105 unsigned char psid; 106 unsigned char ssid; 107 unsigned char lengthH; 108 unsigned char lengthL; 109 unsigned char credit; 110 unsigned char control; 111 unsigned char command; 112 unsigned char result; 113} replyHeader_t; 114 115typedef struct init_s 116{ 117 cmdHeader_t head; 118 unsigned char revision; 119} init_t; 120 121typedef struct initReply_s 122{ 123 replyHeader_t head; 124 unsigned char revision; 125} initReply_t; 126 127typedef struct error_s 128{ 129 replyHeader_t head; 130 unsigned char epsid; 131 unsigned char essid; 132 unsigned char ecode; 133} error_t; 134 135/* results */ 136typedef struct errorMessage_s 137{ 138 unsigned char result; 139 const char *message; 140 int errorClass; 141} errorMessage_t; 142 143#define RECOVERABLE 0 144#define FATAL 1 145 146static errorMessage_t errorMessage[] = 147{ 148 { 0x01, "Unable to begin conversation, try later." ,0 }, 149 { 0x02, "Protocol revision not supported." ,1 }, 150 { 0x03, "Transaction channel can��t be closed." ,0 }, 151 { 0x04, "No sufficient resources available now." ,0 }, 152 { 0x05, "Connection denied." ,1 }, 153 { 0x06, "Channel allready open." ,0 }, 154 { 0x07, "Credit overflow, previous credit remain valid." ,0 }, 155 { 0x08, "Channel is not open." ,1 }, 156 { 0x09, "Service not available on specified socket." ,1 }, 157 { 0x0a, "Service name to socket ID failed." ,1 }, 158 { 0x0b, "Init transaction failed." ,1 }, 159 { 0x0c, "Invalid packet size." ,1 }, 160 { 0x0d, "Requested packed size is 0, no data can be transfered.",0 }, 161 { 0x80, "Malformed packet, ignored." ,1 }, 162 { 0x81, "No credit for received packet, ignored" ,0 }, 163 { 0x82, "Reply don��t match with outstanding command, ignored." ,1 }, 164 { 0x83, "Packet size greater as negotiated size." ,1 }, 165 { 0x84, "Data received for a non opened channel." ,1 }, 166 { 0x85, "Reply with unknown result value received." ,1 }, 167 { 0x86, "Piggybacked credit in data packet cause overflow." ,1 }, 168 { 0x87, "Unknown 1284.4 Reply." ,0 }, 169 { 0x00, NULL ,0 } 170}; 171 172#define RESET_TIMER(ti,oti) { signal(SIGALRM, sig); \ 173 memset((void*)&ti,0,sizeof(ti)); \ 174 memset((void*)&oti,0,sizeof(oti)); \ 175 setitimer( ITIMER_REAL ,&ti, &oti); \ 176 } 177 178#define SET_TIMER(ti,oti,val) { memset((void*)&ti,0,sizeof(ti)); \ 179 memset((void*)&oti,0,sizeof(oti)); \ 180 ti.it_value.tv_sec = val/1000; \ 181 ti.it_value.tv_usec = (val%1000)*1000; \ 182 setitimer( ITIMER_REAL ,&ti, &oti); \ 183 sig = signal(SIGALRM, sigAlarm); \ 184 } 185 186/*******************************************************************/ 187/* Function printHexValues */ 188/* */ 189/* Print hex code contained in the passed buffer */ 190/* */ 191/*******************************************************************/ 192 193static void printHexValues(const char *dir, const unsigned char *buf, int len) 194{ 195 int i, j; 196 int printable_count = 0; 197 int longest_printable_run = 0; 198 int current_printable_run = 0; 199 int print_strings = 0; 200 int blocks = (len + 15) / 16; 201#if 0 202 len = len > 30 ? 30 : len; 203#endif 204 printf("%s\n",dir); 205 for (i = 0; i < len; i++) 206 { 207 if (isprint(buf[i])) 208 { 209 if (!isspace(buf[i])) 210 printable_count++; 211 current_printable_run++; 212 } 213 else 214 { 215 if (current_printable_run > longest_printable_run) 216 longest_printable_run = current_printable_run; 217 } 218 } 219 if (current_printable_run > longest_printable_run) 220 longest_printable_run = current_printable_run; 221 if (longest_printable_run >= 8 || 222 ((float) printable_count / (float) len > .75)) 223 print_strings = 1; 224 if (print_strings) 225 { 226 for (i = 0; i < len; i++) 227 { 228 printf("%c",isprint(buf[i])||isspace(buf[i])?buf[i]:'*'); 229 if (buf[i] == ';' && i < len - 1) 230 printf("\n"); 231 } 232 printf("\n"); 233 } 234 for (j = 0; j < blocks; j++) 235 { 236 int baseidx = j * 16; 237 int count = len; 238 if (count > baseidx + 16) 239 count = baseidx + 16; 240 printf("%4d: ", baseidx); 241 for ( i = baseidx; i < count;i++) 242 { 243 if (i % 4 == 0) 244 printf(" "); 245 printf(" %02x",buf[i]); 246 } 247 if (print_strings) 248 { 249 printf("\n "); 250 for ( i = baseidx; i < count;i++) 251 { 252 if (i % 4 == 0) 253 printf(" "); 254 printf(" %c", 255 isprint(buf[i]) && !isspace(buf[i]) ? buf[i] : ' '); 256 } 257 } 258 printf("\n"); 259 } 260} 261 262int SafeWrite(int fd, const void *data, int len) 263{ 264 int status; 265 int retries=30; 266 if (debugD4) 267 printHexValues("SafeWrite: ", data, len); 268 do 269 { 270 status = write(fd, data, len); 271 if(status < len) 272 usleep(d4WrTimeout); 273 retries--; 274 } 275 while ((status < len) && (retries > 0)); 276 return(status); 277} 278 279/*******************************************************************/ 280/* Function sigAlarm(int code) */ 281/* */ 282/* do nothing, avoid printing of undesired messages and/or */ 283/* other not desirable actions */ 284/* */ 285/*******************************************************************/ 286 287static void sigAlarm(int code) 288{ 289 timeoutGot = -1; 290} 291 292 293/*******************************************************************/ 294/* Function printError() */ 295/* print an error message on stdout */ 296/* */ 297/* Input: unsigned char errorNb the error number */ 298/* */ 299/* Return: fatal = 1 or recoverable = 0 */ 300/* */ 301/*******************************************************************/ 302 303static int printError(unsigned char errorNb) 304{ 305 errorMessage_t *msg = errorMessage; 306 if ( errorNb == 0 ) 307 { 308 return 0; 309 } 310 while ( msg->result ) 311 { 312 if ( msg->result == errorNb ) 313 { 314 if (debugD4) 315 printf("%s\n", msg->message); 316 return msg->errorClass; 317 } 318 msg++; 319 } 320 printf("Unknown IEEE 1284.4 error number %d\n",errorNb); 321 return 0; 322} 323 324 325/*******************************************************************/ 326/* Function printCmdType() */ 327/* print on stdout the command name */ 328/* Input: unsigned char *cmd the data are to be put here */ 329/* */ 330/* Return: - */ 331/* */ 332/*******************************************************************/ 333 334static void printCmdType(unsigned char *cmd) 335{ 336 if (cmd[6] & 0x80) 337 printf(">>>"); 338 if ( cmd[0] == 0 && cmd[1] == 0 ) 339 { 340 switch(cmd[6] & 0x7f) 341 { 342 case 0: printf("--- Init ---\n");break; 343 case 1: printf("--- OpenChannel ---\n");break; 344 case 2: printf("--- CloseChannel ---\n");break; 345 case 3: printf("--- Credit ---\n");break; 346 case 4: printf("--- CreditRequest ---\n");break; 347 case 8: printf("--- Exit ---\n");break; 348 case 9: printf("--- GetSocketID ---\n");break; 349 case 10: printf("--- GetServiceName ---\n");break; 350 case 0x45: printf("--- EnterD4Mode ---\n");break; 351 case 0x7f: printf("--- Error ---\n");break; 352 default: printf("--- ?????????????? ---\n");break; 353 } 354 } 355 else 356 { 357 printf("--- Send Data ---\n"); 358 } 359} 360 361 362/*******************************************************************/ 363/* Function writeCmd() */ 364/* write a commmand */ 365/* Input: int fd file handle */ 366/* char *cmd the data are to be put here */ 367/* int len the number of bytes to read */ 368/* */ 369/* Return: number of bytes write or -1 */ 370/* */ 371/*******************************************************************/ 372 373static int writeCmd(int fd, unsigned char *cmd, int len) 374{ 375 int w; 376 int i = 0; 377 struct itimerval ti, oti; 378 379# if PTIME 380 struct timeval beg, end; 381 long dt; 382# endif 383 if ( debugD4 ) 384 { 385 printCmdType(cmd); 386# if PTIME 387 gettimeofday(&beg, NULL); 388# endif 389 if ( cmd[0] == 0 && cmd[1] == 0 ) 390 { 391 printHexValues("Send: ", cmd, len); 392 } 393 else 394 { 395 printHexValues("Send: ", cmd, 6); 396 } 397 } 398 399 /* according to Glen Steward, this will solve problems */ 400 /* for the cartridge exchange with the Stylus Color 580 */ 401 usleep(d4MicroTimeout); 402 403 timeoutGot = 0; 404 errno = 0; 405 while ( i < len ) 406 { 407 SET_TIMER(ti,oti,d4WrTimeout); 408 w = SafeWrite(fd, cmd+i,len-i); 409 RESET_TIMER(ti,oti); 410 if ( w < 0 ) 411 { 412 if ( debugD4 ) 413 { 414 perror("Write error"); 415 } 416 i= -1; 417 break; 418 } 419 else 420 i += w; 421 } 422 423 if ( debugD4 ) 424 { 425# if PTIME 426 gettimeofday(&end, NULL); 427 dt = (end.tv_sec - beg.tv_sec) * 1000000; 428 dt += end.tv_usec - beg.tv_usec; 429 printf("Write time %5.3f s\n",(double)dt/1000000); 430# endif 431 } 432 433 if ( timeoutGot ) 434 return -1; 435 return i; 436} 437 438/*******************************************************************/ 439/* Function readAnswer() */ 440/* Read the datas returned by the printer */ 441/* Input: int fd file handle */ 442/* char *buf the data are to be put here */ 443/* int len the number of bytes to read */ 444/* */ 445/* Return: number of bytes read. -1 on error */ 446/* */ 447/*******************************************************************/ 448 449int readAnswer(int fd, unsigned char *buf, int len, int allowExtra) 450{ 451 int rd = 0; 452 int total = 0; 453 struct timeval beg, end; 454 struct itimerval ti, oti; 455 long dt; 456 int count = 0; 457 int first_read = 1; 458 int excess = 0; 459 /* wait a little bit before reading an answer */ 460 usleep(d4RdTimeout); 461 462 /* for error handling in case of timeout */ 463 timeoutGot = 0; 464 465 /* set errno to 0 in order to get correct informations */ 466 /* in case of error */ 467 errno = 0; 468 469 gettimeofday(&beg, NULL); 470 471 if (debugD4) 472 printf("length: %i\n", len); 473 while ( total < len ) 474 { 475 SET_TIMER(ti,oti, d4RdTimeout); 476 rd = read(fd, buf+total, len-total); 477 if (debugD4) 478 { 479 if (first_read) 480 { 481 printf("read: "); 482 first_read = 0; 483 } 484 if (rd < 0) 485 { 486 printf("%i %s\n", rd, errno != 0 ?strerror(errno) : ""); 487 first_read = 1; 488 } 489 else 490 printf("%i ", rd); 491 } 492 RESET_TIMER(ti,oti); 493 if ( rd <= 0 ) 494 { 495 gettimeofday(&end, NULL); 496 dt = (end.tv_sec - beg.tv_sec) * 1000; 497 dt += (end.tv_usec - beg.tv_usec) / 1000; 498 if ( dt > d4RdTimeout * 2 ) 499 { 500 if ( debugD4 ) 501 printf("Timeout 1 at readAnswer() rcv %d bytes\n",total); 502 timeoutGot = 1; 503 break; 504 } 505 count++; 506 if ( count >= 100 ) 507 { 508 timeoutGot = 1; 509 if ( rd == 0 ) 510 errno = -1; /* tell that there is an abnormal condition */ 511 break; 512 } 513 errno = 0; 514 } else { 515 total += rd; 516 if ( total > 3 ) 517 { 518 /* the bytes idx 2 and 3 contain the length */ 519 /* in case of errors this may differ from */ 520 /* the expected lenght. Setting len to this */ 521 /* value will avoid waiting for timeout */ 522 int newlen = (buf[2] << 8) + buf[3]; 523 if (len > newlen) 524 { 525 if (debugD4) 526 printf("Changing len from %d to %d\n", len, newlen); 527 len = newlen; 528 } 529 else if (len < newlen) 530 { 531 excess = newlen - len; 532 if (debugD4) 533 printf("Expected %d, getting %d, %sflushing %d\n", 534 len, newlen, allowExtra ? "not " : "", excess); 535 } 536 } 537 } 538 usleep(d4RdTimeout); 539 } 540 if (! allowExtra) 541 { 542 int retry_count = 0; 543 while (excess > 0) 544 { 545 char wastebuf[256]; 546 int bytes = excess > 256 ? 256 : excess; 547 int status = read(fd, wastebuf, bytes); 548 if (status < 0) 549 break; 550 else if (status == 0 && retry_count > 2) 551 break; 552 else if (status == 0) 553 retry_count++; 554 else 555 retry_count = 0; 556 if (status < bytes) 557 usleep(d4RdTimeout); 558 if (debugD4) 559 printHexValues("waste", (const unsigned char *) wastebuf, status); 560 excess -= status; 561 } 562 } 563 564 if ( debugD4 ) 565 { 566 printCmdType(buf); 567# if PTIME 568 gettimeofday(&end, NULL); 569# endif 570 printf("total: %i\n", total); 571 printHexValues("Recv: ",buf,total); 572# if PTIME 573 dt = (end.tv_sec - beg.tv_sec) * 1000000; 574 dt += end.tv_usec - beg.tv_usec; 575 printf("Read time %5.3f s\n",(double)dt/1000000); 576# endif 577 } 578 if ( timeoutGot ) 579 { 580 if ( debugD4 ) 581 printf("Timeout 2 at readAnswer()\n"); 582 return -1; 583 } 584 return total; 585} 586 587static void _flushData(int fd) 588{ 589 int rd = 0; 590 struct itimerval ti, oti; 591 char buf[1024]; 592 int len = 1023; 593 int count = 200; 594 usleep(d4RdTimeout); 595 596 /* for error handling in case of timeout */ 597 timeoutGot = 0; 598 599 /* set errno to 0 in order to get correct informations */ 600 /* in case of error */ 601 errno = 0; 602 603 if (debugD4) 604 printf("flush data: length: %i\n", len); 605 do 606 { 607 usleep(d4RdTimeout); 608 SET_TIMER(ti,oti, d4RdTimeout); 609 rd = read(fd, buf, len); 610 if (debugD4) 611 printf("flush: read: %i %s\n", rd, 612 rd < 0 && errno != 0 ?strerror(errno) : ""); 613 RESET_TIMER(ti,oti); 614 count--; 615 } while ( count > 0 && (rd > 0 || (rd < 0 && errno == EAGAIN))); 616} 617 618/*******************************************************************/ 619/* Function _readData() */ 620/* Read the datas returned by the printer */ 621/* Input: int fd file handle */ 622/* char *buf the data are to be put here */ 623/* int len the number of bytes to read */ 624/* */ 625/* Return: number of bytes read. -1 on error */ 626/* */ 627/*******************************************************************/ 628 629static int _readData(int fd, unsigned char *buf, int len) 630{ 631 int rd = 0; 632 int total = 0; 633 int toGet = 0; 634 unsigned char header[6]; 635 struct timeval beg, end; 636 long dt; 637 struct itimerval ti, oti; 638 639 /* set errno to 0 in order to get correct informations */ 640 /* in case of error */ 641 errno = 0; 642 643 /* read the first 6 bytes */ 644 gettimeofday(&beg, NULL); 645 while ( total < 6 ) 646 { 647 SET_TIMER(ti,oti, d4RdTimeout); 648 rd = read(fd, header+total, 6-total); 649 RESET_TIMER(ti,oti); 650 if ( rd <= 0 ) 651 { 652 gettimeofday(&end, NULL); 653 dt = (end.tv_sec - beg.tv_sec) * 1000; 654 dt += (end.tv_usec - beg.tv_usec) / 1000; 655 if ( dt > d4RdTimeout*3 ) 656 { 657 if ( debugD4 ) 658 printf("Timeout at _readData(), dt = %ld ms\n", dt); 659 return -1; 660 break; 661 } 662 continue; 663 } 664 else 665 { 666 total += rd; 667 } 668 } 669 670 if ( debugD4 ) 671 printHexValues("Recv: ",header,total); 672 673 if ( total == 6 ) 674 { 675 toGet = (header[2] >> 8) + header[3] - 6; 676 if (debugD4) 677 printf("toGet: %i\n", toGet); 678 total = 0; 679 gettimeofday(&beg, NULL); 680 while ( total < toGet ) 681 { 682 SET_TIMER(ti,oti, d4RdTimeout); 683 rd = read(fd, buf+total, toGet-total); 684 RESET_TIMER(ti,oti); 685 if ( rd <= 0 ) 686 { 687 gettimeofday(&end, NULL); 688 dt = (end.tv_sec - beg.tv_sec) * 1000; 689 dt += (end.tv_usec - beg.tv_usec) / 1000; 690 if ( dt > d4RdTimeout*3 ) 691 { 692 if ( debugD4 ) 693 printf("Timeout at _readData(), dt = %ld ms\n",dt); 694 return -1; 695 break; 696 } 697 continue; 698 } 699 else 700 { 701 total += rd; 702 } 703 } 704 if ( debugD4 ) 705 printHexValues("Recv: ",buf,total); 706 return total; 707 } 708 709 return -1; 710} 711 712/*******************************************************************/ 713/* Function sendReceiveCmd() */ 714/* send a command and get the answer. */ 715/* Input: int fd file handle */ 716/* char *buf the data are to be put here */ 717/* int len the number of bytes to read */ 718/* */ 719/* Return: number of bytes read */ 720/* */ 721/*******************************************************************/ 722 723static int sendReceiveCmd(int fd, unsigned char *cmd, int len, unsigned char *answer, int expectedlen, int allowExtra) 724{ 725 int rd; 726 d4Errno = 0; 727 if ( (rd = writeCmd(fd, cmd, len ) ) != len ) 728 { 729 if ( rd < 0 ) return -1; 730 return 0; 731 } 732 rd = readAnswer(fd, answer, expectedlen, allowExtra ); 733 if ( rd == 0 ) 734 { 735 /* no answer from device */ 736 return 0; 737 } 738 else if ( rd < 0 ) 739 { 740 /* interrupted write call */ 741 if ( debugD4 ) 742 printf("interrupt received\n"); 743 return -1; 744 } 745 else 746 { 747 /* check result */ 748 if ( answer[6] == 0x7f ) 749 { 750 printError(answer[9]); 751 d4Errno = answer[9]; 752 return -1; 753 } 754 else if ( answer[7] != 0 ) 755 { 756 d4Errno = answer[7]; 757 if ( printError(answer[7]) ) 758 { 759 return -1; 760 } 761 return 0; 762 } 763 else 764 { 765 return rd; 766 } 767 } 768} 769 770/*******************************************************************/ 771/* Function EnterIEEE() */ 772/* send a command and get the answer. */ 773/* Input: int fd file handle */ 774/* */ 775/* Return: 0 on error 1 if all is OK */ 776/* */ 777/*******************************************************************/ 778 779int EnterIEEE(int fd) 780{ 781 unsigned char buf[200]; 782 unsigned char cmd[] = 783 { 784 0x00, 0x00, 0x00, 0x1b, 0x01, '@', 'E', 'J', 'L', ' ', 785 '1', '2', '8', '4', '.', '4', 0x0a, '@', 'E', 'J', 786 'L', 0x0a, '@', 'E', 'J', 'L', 0x0a 787 }; 788 int rd; 789 memset(buf, 0, sizeof(buf)); 790Loop: 791 if ( writeCmd(fd, cmd, sizeof(cmd) ) != sizeof(cmd) ) 792 { 793 return 0; 794 } 795 rd = readAnswer(fd, buf, 8, 0); 796 if ( rd == 0 ) 797 { 798 /* no answer from device */ 799 if (debugD4) 800 printf(">>>No answer from printer\n"); 801 return 0; 802 } 803 else if ( rd < 0 ) 804 { 805 if (debugD4) 806 printf(">>>Interrupted write\n"); 807 /* interrupted write call */ 808 return 0; 809 } 810 else 811 { 812 int i; 813 /* check result */ 814 for (i=0; i < rd; i++ ) 815 if ( buf[i] != 0 ) 816 break; 817 if ( i == rd ) goto Loop; 818 return 1; 819 } 820} 821 822/*******************************************************************/ 823/* Function Init() */ 824/* handle the init command */ 825/* Input: int fd file handle */ 826/* */ 827/* Return: 0 on error 1 if all is OK */ 828/* */ 829/*******************************************************************/ 830 831int Init(int fd) 832{ 833 unsigned char buf[20]; 834 init_t cmd; 835 int rd; 836 837 cmd.head.psid = 0; 838 cmd.head.ssid = 0; 839 cmd.head.lengthH = 0; 840 cmd.head.lengthL = 8; 841 cmd.head.credit = 1; 842 cmd.head.control = 0; 843 cmd.head.command = 0; 844 cmd.revision = 0x10; 845 846 rd = sendReceiveCmd(fd, (unsigned char*)&cmd, sizeof(cmd), buf, 9, 0 ); 847 return rd == 9 ? 1 : 0; 848} 849 850/*******************************************************************/ 851/* Function Exit() */ 852/* handle the Exit command */ 853/* Input: int fd file handle */ 854/* */ 855/* Return: 0 on error 1 if all is OK */ 856/* */ 857/*******************************************************************/ 858 859int Exit(int fd) 860{ 861 int rd; 862 unsigned char buf[20]; 863 cmdHeader_t cmd; 864 cmd.psid = 0; 865 cmd.ssid = 0; 866 cmd.lengthH = 0; 867 cmd.lengthL = 7; 868 cmd.credit = 1; 869 cmd.control = 0; 870 cmd.command = 8; 871 872 rd = sendReceiveCmd(fd, (unsigned char*)&cmd, sizeof(cmd), buf, 8, 0 ); 873 return rd > 0 ? 1 : rd; 874} 875 876/*******************************************************************/ 877/* Function GetSocketID() */ 878/* handle the GetSocketID command */ 879/* Input: int fd file handle */ 880/* char *serviceName name of wanted service */ 881/* */ 882/* Return: 0 on error else the socket ID */ 883/* */ 884/*******************************************************************/ 885 886int GetSocketID(int fd, const char *serviceName) 887{ 888 /* the service name may not be longer as 40 bytes */ 889 int len = sizeof(cmdHeader_t) + strlen(serviceName); 890 char buf[100]; 891 unsigned char rBuf[100]; 892 int rd; 893 cmdHeader_t *cmd = (cmdHeader_t*)buf; 894 cmd->psid = 0; 895 cmd->ssid = 0; 896 cmd->lengthH = 0; 897 cmd->lengthL = len & 0xff; 898 cmd->credit = 1; 899 cmd->control = 0; 900 cmd->command = 0x09; 901 strcpy(buf + sizeof(cmdHeader_t), serviceName); 902 903 rd = sendReceiveCmd(fd, (unsigned char*)buf, len, rBuf, len + 2, 0); 904 if ( rd > 0 ) 905 { 906 return rBuf[8]; 907 } 908 else 909 { 910 return 0; 911 } 912} 913 914/*******************************************************************/ 915/* Function OpenChannel() */ 916/* handle the OpenChannel command */ 917/* Input: int fd file handle */ 918/* I/O: int *sndSz The size for sendig of datas */ 919/* int *recSz The size for receiving of datas */ 920/* */ 921/* Return: -1 on error or 1 if all is OK */ 922/* */ 923/*******************************************************************/ 924 925int OpenChannel(int fd, unsigned char sockId, int *sndSz, int *rcvSz) 926{ 927 unsigned char cmd[17]; 928 unsigned char buf[20]; 929 int rd; 930 int i; 931 932 for(i = 0; i < 5; i++) /* Retry count */ 933 { 934 cmd[0] = 0; /* transaction sockets */ 935 cmd[1] = 0; 936 cmd[2] = 0; /* len */ 937 cmd[3] = 17; /* len */ 938 cmd[4] = 1; /* credit */ 939 cmd[5] = 0; /* control */ 940 cmd[6] = 1; /* command */ 941 cmd[7] = sockId; /* sockets # */ 942 cmd[8] = sockId; /* sockets # */ 943 cmd[9] = *sndSz >> 8; /* packet size in send dir */ 944 cmd[10] = *sndSz & 0xff; 945 cmd[11] = *rcvSz >> 8; /* packet size in recv dir */ 946 cmd[12] = *rcvSz & 0xff; 947 cmd[13] = 0; /* max outstanding Credit, must be 0 */ 948 cmd[14] = 0; 949 cmd[15] = 0; /* initial credit for us ? */ 950 cmd[16] = 0; 951 952 rd = sendReceiveCmd(fd, cmd, 17, buf, 16, 0); 953 if ( rd == -1 ) 954 { 955 if (debugD4) 956 printf("OpenChannel %d fails, error %d\n", sockId, d4Errno); 957 if (d4Errno == 6) /* channel already open */ 958 { 959 if ( debugD4 ) 960 printf("Channel %d already open, closing\n", sockId); 961 CloseChannel(fd, sockId); 962 continue; 963 } 964 else 965 return -1; 966 } 967 else if ( rd == 16 ) 968 { 969 if ( buf[7] == 4 ) 970 { 971 /* device can��t allocate resources now */ 972 continue; 973 } 974 else if ( buf[7] != 0 ) 975 { 976 if (debugD4) 977 printf("OpenChannel %d fails, hard error\n", sockId); 978 /* hard error */ 979 return -1; 980 } 981 *sndSz = (buf[10]<<8) + buf[11]; 982 *rcvSz = (buf[12]<<8) + buf[13]; 983 break; 984 } 985 else 986 { 987 if (d4Errno == 6) /* channel already open */ 988 { 989 if ( debugD4 ) 990 printf("Channel %d already open, closing\n", sockId); 991 CloseChannel(fd, sockId); 992 continue; 993 } 994 /* at this stage we can only have an error */ 995 if (debugD4) 996 printf("OpenChannel %d fails, wrong count %d\n", sockId, rd); 997 return -1; 998 } 999 } 1000 return 1; 1001} 1002 1003/*******************************************************************/ 1004/* Function CloseChannel() */ 1005/* handle the CloseChannel command */ 1006/* Input: int fd file handle */ 1007/* unsigned char socketID he socket to close */ 1008/* */ 1009/* Return: -1 on error or 1 if all is OK */ 1010/* */ 1011/*******************************************************************/ 1012 1013int CloseChannel(int fd, unsigned char socketID) 1014{ 1015 unsigned char buf[100]; 1016 int rd; 1017 cmdHeader_t *cmd = (cmdHeader_t *)buf; 1018 cmd->psid = 0; 1019 cmd->ssid = 0; 1020 cmd->lengthH = 0; 1021 cmd->lengthL = 10; 1022 cmd->credit = 1; 1023 cmd->control = 0; 1024 cmd->command = 2; 1025 buf[sizeof(cmdHeader_t)+0] = socketID; 1026 buf[sizeof(cmdHeader_t)+1] = socketID; 1027 buf[sizeof(cmdHeader_t)+2] = 0; 1028 rd = sendReceiveCmd(fd, buf,10, buf, 10, 0); 1029 return rd == 10 ? 1 : rd; 1030} 1031 1032/*******************************************************************/ 1033/* Function CreditRequest() */ 1034/* handle the CreditRequest command */ 1035/* Input: int fd file handle */ 1036/* unsigned char socketID he socket to close */ 1037/* */ 1038/* Return: -1 on error else the credit got */ 1039/* */ 1040/*******************************************************************/ 1041 1042int CreditRequest(int fd, unsigned char socketID) 1043{ 1044 int rd; 1045 unsigned char buf[100]; 1046 unsigned char rBuf[100]; 1047 cmdHeader_t *cmd = (cmdHeader_t *)buf; 1048 cmd->psid = 0; 1049 cmd->ssid = 0; 1050 cmd->lengthH = 0; 1051 cmd->lengthL = 13; 1052 cmd->credit = 1; 1053 cmd->control = 0; 1054 cmd->command = 4; 1055 buf[sizeof(cmdHeader_t)+0] = socketID; 1056 buf[sizeof(cmdHeader_t)+1] = socketID; 1057 buf[sizeof(cmdHeader_t)+2] = 0x00; 1058 buf[sizeof(cmdHeader_t)+3] = 0x80; 1059 buf[sizeof(cmdHeader_t)+4] = 0xff; 1060 buf[sizeof(cmdHeader_t)+5] = 0xff; 1061 rd = sendReceiveCmd(fd, buf, 13, rBuf, 12, 0); 1062 if ( rd == 12 ) 1063 { 1064 /* this is the credit */ 1065 return (rBuf[10]*256)+rBuf[11]; 1066 } 1067 else 1068 { 1069 return rd > 0 ? 0 : rd; /* there was an error */ 1070 } 1071} 1072 1073/*******************************************************************/ 1074/* Function Credit() */ 1075/* give credit to the attached device */ 1076/* Input: int fd file handle */ 1077/* unsigned char socketID the socket to close */ 1078/* */ 1079/* Return: -1 on error or 1 if all is OK */ 1080/* */ 1081/*******************************************************************/ 1082 1083/* needed for sending of commands (channel 2) or scanning */ 1084int Credit(int fd, unsigned char socketID, int credit) 1085{ 1086 int rd; 1087 unsigned char buf[100]; 1088 unsigned char rBuf[100]; 1089 cmdHeader_t *cmd = (cmdHeader_t*)buf; 1090 cmd->psid = 0; 1091 cmd->ssid = 0; 1092 cmd->lengthH = 0; 1093 cmd->lengthL = 0x0b; 1094 cmd->credit = 1; 1095 cmd->control = 0; 1096 cmd->command = 0x03; 1097 1098 buf[sizeof(cmdHeader_t)+0] = socketID; 1099 buf[sizeof(cmdHeader_t)+1] = socketID; 1100 buf[sizeof(cmdHeader_t)+2] = credit >> 8; 1101 buf[sizeof(cmdHeader_t)+3] = credit & 0xff; 1102 rd = sendReceiveCmd(fd, buf, 11, rBuf, 10, 0); 1103 if ( rd == 10 ) 1104 { 1105 return 1; 1106 } 1107 else 1108 { 1109 return 0; 1110 } 1111} 1112 1113/*******************************************************************/ 1114/* Function askForCredit() */ 1115/* Convenience function */ 1116/* handle the CreditRequest command */ 1117/* Input: int fd file handle */ 1118/* unsigned char socketID */ 1119/* IN/Out int *sndSize for error handling */ 1120/* IN/Out int *rcvSize for error handling */ 1121/* */ 1122/* Return: credit */ 1123/* */ 1124/* Remark: CreditRequest() will be called in a loop as long as */ 1125/* the returned credit is 0 */ 1126/* */ 1127/*******************************************************************/ 1128#define MAX_CREDIT_REQUEST 2 1129int askForCredit(int fd, unsigned char socketID, int *sndSize, int *rcvSize) 1130{ 1131 int credit = 0; 1132 int count = 0; 1133 int retries = 10; 1134 1135 while (credit == 0 && retries-- >= 0 ) 1136 { 1137 while((credit=CreditRequest(fd,socketID)) == 0 && count < MAX_CREDIT_REQUEST && retries-- >= 0) 1138 usleep(d4RdTimeout); 1139 1140 if ( credit == -1 ) 1141 { 1142 if ( errno == ENODEV || count == MAX_CREDIT_REQUEST ) 1143 { 1144 break; 1145 } 1146 credit = 0; 1147 /* init printer and reopen the printer channel */ 1148 CloseChannel(fd, socketID); 1149 socketID = GetSocketID(fd, "EPSON-CTRL"); 1150 if ( Init(fd) ) 1151 { 1152 if (debugD4) 1153 printf("askForCredit init succeeded, now try to open\n"); 1154 OpenChannel(fd, socketID, sndSize, rcvSize); 1155 } 1156 } 1157 /* if the parent died, live this loop if credit not got */ 1158 if ( credit == 0 && getppid() == ppid ) 1159 return 0; 1160 count++; 1161 } 1162 return credit; 1163} 1164 1165/*******************************************************************/ 1166/* Function writeData() */ 1167/* Convenience function */ 1168/* write the data to the device */ 1169/* Input: int fd file handle */ 1170/* unsigned char socketID the deetination socket */ 1171/* unsigned char *buf the datas to be send */ 1172/* int len how many datas are to we send */ 1173/* int eoj set out of band flag if eoj set */ 1174/* */ 1175/* Return: number of bytes written or -1; */ 1176/* */ 1177/*******************************************************************/ 1178 1179int writeData(int fd, unsigned char socketID, const unsigned char *buf, int len, int eoj) 1180{ 1181 unsigned char cmd[6]; 1182 int wr = 0; 1183 int ret = 0; 1184 struct itimerval ti, oti; 1185 struct timeval beg; 1186 static unsigned char *buffer = NULL; 1187 static int bLen = 0; 1188 if ( debugD4 ) 1189 { 1190 printf("--- Send Data ---\n"); 1191 gettimeofday(&beg, NULL); 1192 } 1193 len += 6; 1194 if ( len > bLen ) 1195 { 1196 if ( buffer == NULL ) 1197 buffer = (unsigned char*)malloc(len); 1198 else 1199 buffer = (unsigned char*)realloc(buffer, len); 1200 if ( buffer == NULL ) 1201 return -1; 1202 bLen = len; 1203 } 1204 cmd[0] = socketID; 1205 cmd[1] = socketID; 1206 cmd[2] = len >> 8; 1207 cmd[3] = len & 0xff; 1208 cmd[4] = 0; 1209 cmd[5] = eoj ? 1 : 0; 1210 1211 memcpy(buffer, cmd, 6); 1212 memcpy(buffer + 6, buf, len - 6 ); 1213 while( ret > -1 && wr != len ) 1214 { 1215 SET_TIMER(ti,oti,d4WrTimeout); 1216 ret = SafeWrite(fd, buffer+wr, len-wr ); 1217 RESET_TIMER(ti,oti); 1218 if ( ret == -1 ) 1219 { 1220 perror("write: "); 1221 } 1222 else 1223 { 1224 wr += ret; 1225 } 1226 } 1227 1228 if ( debugD4 ) 1229 { 1230# if PTIME 1231 gettimeofday(&end, NULL); 1232 dt = (end.tv_sec - beg.tv_sec) * 1000000; 1233 dt += end.tv_usec - beg.tv_usec; 1234# endif 1235 printf("Send: "); 1236 for ( ret = 0; (wr > 0) && (ret < ((wr > 20) ? 20 : wr)) ; ret++ ) 1237 printf("%02x ", buffer[ret]); 1238 printf("\n "); 1239 for ( ret = 0; (wr > 0) && (ret < ((wr > 20) ? 20 : wr)) ; ret++ ) 1240 printf("%c ", isprint(buffer[ret])&&!isspace(buffer[ret])?buffer[ret]:' '); 1241 printf("\n"); 1242# if PTIME 1243 printf("Write time %5.3f s\n",(double)dt/1000000); 1244# endif 1245 } 1246 1247 if ( wr > 6 ) 1248 wr -= 6; 1249 else 1250 wr = -1; 1251 return wr; 1252 1253} 1254 1255/*******************************************************************/ 1256/* Function readData() */ 1257/* Convenience function */ 1258/* give credit and read then the expected datas */ 1259/* Input: int fd file handle */ 1260/* unsigned char socketID the destination socket */ 1261/* unsigned char *buf the datas to be send */ 1262/* int len howmany datas are to we send */ 1263/* */ 1264/* Return: number of bytes read or -1; */ 1265/* */ 1266/*******************************************************************/ 1267 1268int readData(int fd, unsigned char socketID, unsigned char *buf, int len) 1269{ 1270 int ret; 1271 /* give credit */ 1272 if ( Credit(fd, socketID, 1) == 1 ) 1273 { 1274 /* wait a little bit */ 1275 usleep(d4RdDataTimeout); 1276 ret = _readData(fd, buf, len); 1277 return ret; 1278 } 1279 else 1280 { 1281 return -1; 1282 } 1283} 1284 1285/*******************************************************************/ 1286/* Function writeAndReadData() */ 1287/* Convenience function */ 1288/* give credit and read then the expected datas */ 1289/* Input: int fd file handle */ 1290/* unsigned char socketID the destination socket */ 1291/* unsigned char *cmd the datas to be send */ 1292/* int cmd_len howmany datas are to we send */ 1293/* int eoj set out of band flag if eoj set */ 1294/* unsigned char *buf the datas to be send */ 1295/* int *sndSz Send buffer size */ 1296/* int *rcvSz Receive buffer size */ 1297/* int len how many datas are to we send */ 1298/* fptr test function to verify buffer contents */ 1299/* */ 1300/* Return: number of bytes read or -1; */ 1301/* */ 1302/* This allows us to give credit before sending the command. */ 1303/* Sending the command and then giving credit sometimes causes */ 1304/* the actual data to be sent as a reply to the credit command. */ 1305/* */ 1306/*******************************************************************/ 1307 1308int writeAndReadData(int fd, unsigned char socketID, 1309 const unsigned char *cmd, int cmd_len, int eoj, 1310 unsigned char *buf, int len, int *sndSz, int *rcvSz, 1311 int (*test)(const unsigned char *buf)) 1312{ 1313 int ret; 1314 int retry = 5; 1315 int credit = askForCredit(fd, socketID, sndSz, rcvSz); 1316 if (credit < 0) 1317 return -1; 1318 /* give credit */ 1319 if ( Credit(fd, socketID, 1) == 1 ) 1320 { 1321 if (writeData(fd, socketID, cmd, cmd_len, eoj) <= 0) 1322 return -1; 1323 /* wait a little bit */ 1324 do 1325 { 1326 usleep(d4RdDataTimeout); 1327 ret = _readData(fd, buf, len); 1328 if (ret < 0) 1329 return ret; 1330 } while (retry-- >= 0 && (!test || !(*test)(buf))); 1331 return ret; 1332 } 1333 else 1334 return -1; 1335} 1336 1337/*******************************************************************/ 1338/* Function readData() */ 1339/* Convenience function */ 1340/* give credit and read then the expected datas */ 1341/* Input: int fd file handle */ 1342/* unsigned char socketID the destination socket */ 1343/* unsigned char *buf the datas to be send */ 1344/* int len howmany datas are to we send */ 1345/* */ 1346/* Return: number of bytes written or -1; */ 1347/* */ 1348/*******************************************************************/ 1349 1350void flushData(int fd, unsigned char socketID) 1351{ 1352 if (debugD4) 1353 printf("flushData %d\n", socketID); 1354 /* give credit */ 1355 if (socketID != (unsigned char) -1) 1356 { 1357 if ( Credit(fd, socketID, 1) == 1 ) 1358 { 1359 /* wait a little bit */ 1360 usleep(d4RdDataTimeout); 1361 _flushData(fd); 1362 } 1363 } 1364 else 1365 _flushData(fd); 1366} 1367 1368/*******************************************************************/ 1369/* Function clearSndBuf() */ 1370/* Convenience function */ 1371/* */ 1372/* Input: int fd file handle */ 1373/* */ 1374/* */ 1375/*******************************************************************/ 1376 1377static void clearSndBuf(int fd) 1378{ 1379 char buf[256]; 1380 struct itimerval ti, oti; 1381 1382 SET_TIMER(ti,oti, d4RdTimeout); 1383 while ( read(fd, buf, sizeof(buf) ) > 0 ) 1384 SET_TIMER(ti,oti, d4RdTimeout); 1385 RESET_TIMER(ti,oti); 1386} 1387 1388void setDebug(int debug) 1389{ 1390 debugD4 = debug; 1391} 1392 1393#if 0 /* implementation later ? */ 1394int InitReply(int fd) 1395{ 1396 unsigned char buf[20]; 1397 initReply_t cmd; 1398 1399 cmd.head.psid = 0; 1400 cmd.head.ssid = 0; 1401 cmd.head.lengthH = 0; 1402 cmd.head.lengthL = 9; 1403 cmd.head.credit = 1; 1404 cmd.head.control = 0; 1405 cmd.head.command = 0x80; 1406 cmd.head.result = 0; /* put the correct value here, 0,1,2 or 0x0b */ 1407 cmd.revision = 0x10; 1408 1409} 1410 1411int ExitReply(int fd) 1412{ 1413 replyHeader_t cmd; 1414 cmd.psid = 0; 1415 cmd.ssid = 0; 1416 cmd.lengthH = 0; 1417 cmd.lengthL = 7; 1418 cmd.credit = 1; /* always ignored */ 1419 cmd.control = 0; 1420 cmd.command = 0x88; 1421 cmd.result = 0x0; /* put the correct value here always 0 */ 1422} 1423 1424int Error(int fd) 1425{ 1426 char 1427 error_t cmd; 1428 cmd.head.psid = 0; 1429 cmd.head.ssid = 0; 1430 cmd.head.lengthH = 0; 1431 cmd.head.lengthL = 0x0a; 1432 cmd.head.credit = 0; 1433 cmd.head.control = 0; 1434 cmd.head.command = 0x7f; 1435 cmd.epsid = psid; 1436 cmd.essid = ssid; 1437 cmd.ecode = 0x80; /* + 1...7 */ 1438} 1439 1440int GetSocketIDReply(int fd, unsigned char socketID) 1441{ 1442 /* the service name may not be longer as 40 bytes */ 1443 int len = sizeof(replyHeader_t) + 1 + strlen(serviceName); 1444 unsigned char buf[100]; 1445 replyHeader_t *cmd = buf; 1446 cmd->psid = 0; 1447 cmd->ssid = 0; 1448 cmd->lengthH = 0; 1449 cmd->lengthL = len & 0xff; 1450 cmd->credit = 1; 1451 cmd->control = 0; 1452 cmd->command = 0x89; 1453 cmd->result = 0; /* put the correct vale here 0 or 0x0a */ 1454 buf[sizeof(cmdHeader_t)] = socketID; 1455 strcpy(buf+1+sizeof(cmdHeader_t), serviceName); 1456 1457} 1458 1459int GetServiceName(inf fd, unsigned char socketID) 1460{ 1461 int rd; 1462 unsigned char buf[100]; 1463 cmdHeader_t *cmd = buf; 1464 cmd->psid = 0; 1465 cmd->ssid = 0; 1466 cmd->lengthH = 0; 1467 cmd->lengthL = 8; 1468 cmd->credit = 1; 1469 cmd->control = 0; 1470 cmd->command = 0x0a; 1471 buf[sizeof(cmdHeader_t)] = socketID; 1472} 1473 1474/* as GetSocketIDReply but with command 0x8a instead 0f 0x89 */ 1475int GetServiceNameReply(inf fd) 1476{ 1477 /* the service name may not be longer as 40 bytes */ 1478 int len = sizeof(replyHeader_t) + 1 + strlen(serviceName); 1479 unsigned char buf[100]; 1480 replyHeader_t *cmd = buf; 1481 cmd->psid = 0; 1482 cmd->ssid = 0; 1483 cmd->lengthH = 0; 1484 cmd->lengthL = len & 0xff; 1485 cmd->credit = 1; 1486 cmd->control = 0; 1487 cmd->command = 0x8a; 1488 cmd->result = 0; /* put the correct vale here 0 or 0x0a */ 1489 buf[sizeof(replyHeader_t)] = socketID; 1490 strcpy(buf+1+sizeof(replyHeader_t), serviceName); 1491 1492} 1493 1494int CreditReply(int fd, unsigned char socketID, int credit) 1495{ 1496 unsigned char buf[100]; 1497 replyHeader_t *cmd = buf; 1498 cmd->psid = 0; 1499 cmd->ssid = 0; 1500 cmd->lengthH = 0; 1501 cmd->lengthL = 0x0b; 1502 cmd->credit = 1; 1503 cmd->control = 0; 1504 cmd->command = 0x83; 1505 buf[sizeof(replyHeader_t)] = socketID; 1506 buf[sizeof(replyHeader_t)+1] = socketID; 1507} 1508 1509#endif 1510 1511