Tizen 2.1 base
[platform/upstream/hplip.git] / prnt / hpijs / printer.cpp
1 /*****************************************************************************\
2   printer.cpp : Implimentation for the Printer class
3
4   Copyright (c) 1996 - 2006, Hewlett-Packard Co.
5   All rights reserved.
6
7   Redistribution and use in source and binary forms, with or without
8   modification, are permitted provided that the following conditions
9   are met:
10   1. Redistributions of source code must retain the above copyright
11      notice, this list of conditions and the following disclaimer.
12   2. Redistributions in binary form must reproduce the above copyright
13      notice, this list of conditions and the following disclaimer in the
14      documentation and/or other materials provided with the distribution.
15   3. Neither the name of Hewlett-Packard nor the names of its
16      contributors may be used to endorse or promote products derived
17      from this software without specific prior written permission.
18
19   THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
20   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
22   NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
24   TO, PATENT INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
25   OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26   ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 \*****************************************************************************/
30
31
32 #include "header.h"
33 #include "io_defs.h"
34 #include "resources.h"
35
36
37 //
38 // ** Printer CLASS **
39
40 APDK_BEGIN_NAMESPACE
41 extern BYTE* GetHTBinary();
42 APDK_END_NAMESPACE
43
44 APDK_BEGIN_NAMESPACE
45
46 Printer::Printer
47 (
48     SystemServices* pSys,
49     int numfonts,
50     BOOL proto
51 ) :
52     constructor_error(NO_ERROR),
53     IOMode(pSys->IOMode),
54 #if defined(APDK_FONTS_NEEDED)
55     iNumFonts(numfonts),
56 #else
57     iNumFonts(0),
58 #endif
59     bCheckForCancelButton(FALSE),
60     ulBytesSentSinceCancelCheck(0),
61     ePen(NO_PEN),
62     CMYMap(NULL),
63     pSS(pSys),
64     InSlowPollMode(0),
65     iTotal_SLOW_POLL_Count(0),
66     iMax_SLOW_POLL_Count(DEFAULT_SLOW_POLL_COUNT),
67     ErrorTerminationState(FALSE),
68     iBuffSize(pSys->GetSendBufferSize()),
69     iCurrBuffSize(0),
70     EndJob(FALSE),
71     ModeCount(2),
72     m_bVIPPrinter(FALSE)
73 {
74
75     int i = 0; // counter
76
77 #ifdef  APDK_LINUX
78     m_iNumPages = 0;
79 #endif
80
81     for (i = 0; i < MAX_PRINTMODES; i++)
82     {
83         pMode[i]=NULL;
84     }
85
86     //CompatiblePens[0] = BOTH_PENS;
87     //for (i = 1; i < MAX_COMPATIBLE_PENS; i++)
88     //{
89     //    CompatiblePens[i] = DUMMY_PEN;
90     //}
91
92     if (IOMode.bDevID)
93     {
94        iMax_SLOW_POLL_Count = DEFAULT_SLOW_POLL_BIDI;
95     }
96
97     // Allocate memory for my send buffer
98     pSendBuffer = NULL;
99 #ifdef APDK_BUFFER_SEND
100     pSendBuffer = pSS->AllocMem(iBuffSize+2);
101     CNEWCHECK(pSendBuffer);
102 #endif
103
104 #ifdef APDK_AUTODUPLEX
105     bDuplexCapable = FALSE;
106     m_bRotateBackPage = TRUE;
107 #endif
108
109 /*
110  *  LaserJet printers do not send status via device id string. PJL is used to
111  *  get status.
112  *  REVISIT:    Do the same for Business Inkjets as well.
113  */
114
115     m_bStatusByPJL = FALSE;
116     char    *tmpStr;
117     if ((strstr ((char *) pSS->strDevID, "LaserJet")) &&
118         (tmpStr = strstr ((char *) pSS->strDevID, "CMD:")) &&
119         (tmpStr = strstr (tmpStr+4, "PJL")))
120     {
121         m_bStatusByPJL = TRUE;
122     }
123
124 #if defined(APDK_FONTS_NEEDED)
125     // create dummy font objects to be queried via EnumFont
126     // these fonts used by all except DJ400
127
128     for (i = 0; i<=MAX_PRINTER_FONTS; i++)
129         fontarray[i] = NULL;
130
131
132 #ifdef APDK_COURIER
133     fontarray[COURIER_INDEX] = new Courier();
134     CNEWCHECK(fontarray[COURIER_INDEX]);
135 #endif
136 #ifdef APDK_CGTIMES
137     fontarray[CGTIMES_INDEX] = new CGTimes();
138     CNEWCHECK(fontarray[CGTIMES_INDEX]);
139 #endif
140 #ifdef APDK_LTRGOTHIC
141     fontarray[LETTERGOTHIC_INDEX] = new LetterGothic();
142     CNEWCHECK(fontarray[LETTERGOTHIC_INDEX]);
143 #endif
144 #ifdef APDK_UNIVERS
145     fontarray[UNIVERS_INDEX] = new Univers();
146     CNEWCHECK(fontarray[UNIVERS_INDEX]);
147 #endif
148
149 #endif  //
150 } //Printer
151
152
153 Printer::~Printer()
154 {
155     if (pMode[GRAYMODE_INDEX])
156     {
157         if (pMode[GRAYMODE_INDEX]->dyeCount==3) // only happens when compgray map used
158         {
159             pSS->FreeMem((BYTE*) pMode[GRAYMODE_INDEX]->cmap.ulMap1 );
160         }
161     }
162
163     for (int i = 0; i < MAX_PRINTMODES; i++)
164     {
165         if (pMode[i])
166         {
167             delete pMode[i];
168         }
169     }
170
171 #ifdef APDK_BUFFER_SEND
172     if (pSendBuffer != NULL)
173     {
174         pSS->FreeMem(pSendBuffer);
175     }
176 #endif
177
178 #ifdef APDK_COURIER
179     delete fontarray[COURIER_INDEX];
180 #endif
181 #ifdef APDK_CGTIMES
182     delete fontarray[CGTIMES_INDEX];
183 #endif
184 #ifdef APDK_LTRGOTHIC
185     delete fontarray[LETTERGOTHIC_INDEX];
186 #endif
187 #ifdef APDK_UNIVERS
188     delete fontarray[UNIVERS_INDEX];
189 #endif
190
191 } //~Printer
192
193
194 ////////////////////////////////////////////////////////////////////////////
195 Compressor* Printer::CreateCompressor (unsigned int RasterSize)
196 {
197     return new Mode9 (pSS, RasterSize);   // most printers use mode 9
198 }
199
200 ////////////////////////////////////////////////////////////////////////////
201 Compressor* Printer::CreateBlackPlaneCompressor (unsigned int RasterSize,
202                                                  BOOL bVIPPrinter)
203 {
204     return new Mode9 (pSS, RasterSize, bVIPPrinter);   // most printers use mode 9
205 }
206
207 ////////////////////////////////////////////////////////////////////////////
208 // ** API functions
209 //
210
211
212 DRIVER_ERROR Printer::Flush
213 (
214     int FlushSize       // = MAX_RASTERSIZE
215 )
216 // flush possible leftover garbage --
217 // default call will send one (maximal) raster's worth of zeroes
218 {
219     ASSERT(FlushSize > 0);
220     ASSERT(FlushSize <= MAX_RASTERSIZE);
221
222     DRIVER_ERROR err = NO_ERROR;
223     int iChunkSize = 1000;
224     BYTE *zero = NULL;
225
226     // Try to allocate iChunkSize bytes of memory.  If we fail then cut size
227     // in half and try again.  If we can't allocate even 10 bytes then bail
228     // with a memory allocation error.  Flush is called at the beginning of
229     // the print job - if there is no memory allocate now then we won't be
230     // printing in any case.
231     while (iChunkSize > 10 && zero == NULL)
232     {
233         zero = pSS->AllocMem(iChunkSize);
234         if (zero == NULL)
235         {
236             iChunkSize /= 2;
237         }
238     }
239
240     if (zero == NULL)
241     {
242         return ALLOCMEM_ERROR;
243     }
244
245     memset(zero, 0, iChunkSize);
246     int iChunks = (FlushSize / iChunkSize) + 1;
247
248     for (int i = 0; i < iChunks; i++)
249     {
250         if ((err = Send( zero, iChunkSize)) != NO_ERROR)
251         {
252             break;              // there was an error
253         }
254     }
255     pSS->FreeMem(zero);         //break to here
256     return err;
257 } //Flush
258
259
260 /*
261  *  Function name: ParseError
262  *
263  *  Owner: Darrell Walker
264  *
265  *  Purpose:  To determine what error state the printer is in.
266  *
267  *  Called by: Send()
268  *
269  *  Parameters on entry: status_reg is the contents of the centronics
270  *                      status register (at the time the error was
271  *                      detected)
272  *
273  *  Parameters on exit: unchanged
274  *
275  *  Return Values: The proper DISPLAY_STATUS to reflect the printer
276  *              error state.
277  *
278  */
279
280 DISPLAY_STATUS Printer::ParseError
281 (
282     BYTE status_reg
283 )
284 {
285     DBG1("Printer: parsing error info\n");
286
287     DRIVER_ERROR err = NO_ERROR;
288     BYTE DevIDBuffer[DevIDBuffSize];
289
290     if(IOMode.bDevID)
291     {
292         // If a bi-di cable was plugged in and everything was OK, let's see if it's still
293         // plugged in and everything is OK
294         err = pSS->GetDeviceID(DevIDBuffer, DevIDBuffSize, TRUE);
295         if(err != NO_ERROR)
296         {
297             // job was bi-di but now something's messed up, probably cable unplugged
298             // or printer turned off during print job
299             return DISPLAY_COMM_PROBLEM;
300         }
301     }
302
303     // check for errors we can detect from the status reg
304
305     if (IOMode.bStatus)
306     {
307         if ( DEVICE_IS_OOP(status_reg) )
308         {
309             DBG1("Out Of Paper\n");
310             return DISPLAY_OUT_OF_PAPER;
311         }
312
313                 if (DEVICE_PAPER_JAMMED(status_reg))
314                 {
315                         DBG1("Paper Jammed\n");
316                         return DISPLAY_PAPER_JAMMED;
317                 }
318                 if (DEVICE_IO_TRAP(status_reg))
319         {
320             DBG1("IO Trap\n");
321             return DISPLAY_ERROR_TRAP;
322         }
323     }
324
325     if (IOMode.bDevID)
326     {
327         if ( TopCoverOpen(status_reg) )
328         {
329             DBG1("Top Cover Open\n");
330             return DISPLAY_TOP_COVER_OPEN;
331         }
332
333         // VerifyPenInfo will handle prompting the user
334         //  if this is a problem
335         VerifyPenInfo();
336     }
337
338     // don't know what the problem is-
339     //  Is the PrinterAlive?
340     if (pSS->PrinterIsAlive())  // <- This is only viable if bStatus is TRUE
341     {
342         iTotal_SLOW_POLL_Count += iMax_SLOW_POLL_Count;
343
344         // -Note that iTotal_SLOW_POLL_Count is a multiple of
345         //  iMax_SLOW_POLL_Count allowing us to check this
346         //  on an absolute time limit - not relative to the number
347         //  of times we happen to have entered ParseError.
348         // -Also note that we have different thresholds for uni-di & bi-di.
349
350         // REVISIT these counts - they are relative to the speed through
351         // the send loop aren't they?  They may be too long!
352         if(
353             ((IOMode.bDevID == FALSE) && (iTotal_SLOW_POLL_Count >= 60)) ||
354             ((IOMode.bDevID == TRUE)  && (iTotal_SLOW_POLL_Count >= 120))
355           )
356         {
357             return DISPLAY_BUSY;
358         }
359         else
360         {
361             return DISPLAY_PRINTING;
362         }
363     }
364     else
365     {
366         return DISPLAY_COMM_PROBLEM;
367     }
368 } //ParseError
369
370 DRIVER_ERROR Printer::Encapsulate
371 (
372     const RASTERDATA* InputRaster,
373     BOOL bLastPlane
374 )
375 {
376     DRIVER_ERROR    err;
377     char            scratch[20];
378     int             scratchLen;
379
380     if (bLastPlane)
381     {
382                 if (VIPPrinter())
383                 {
384                         if (InputRaster->rastersize[COLORTYPE_BLACK] != 0)
385                         {
386                                 if (InputRaster->rastersize[COLORTYPE_COLOR] != 0)
387                                 {
388                                         scratchLen = sprintf (scratch, "\033*b%uV", InputRaster->rastersize[COLORTYPE_BLACK]);
389                                         err = Send ((const BYTE*) scratch, scratchLen);
390                                         if (err == NO_ERROR)
391                                         {
392                                                 err = Send (InputRaster->rasterdata[COLORTYPE_BLACK], InputRaster->rastersize[COLORTYPE_BLACK]);
393                                         }
394                                         if (err == NO_ERROR)
395                                         {
396                                                 scratchLen = sprintf (scratch, "\033*b%uW", InputRaster->rastersize[COLORTYPE_COLOR]);
397                                                 err = Send ((const BYTE*) scratch, scratchLen);
398                                                 if (err == NO_ERROR)
399                                                 {
400                                                         err = Send (InputRaster->rasterdata[COLORTYPE_COLOR], InputRaster->rastersize[COLORTYPE_COLOR]);
401                                                 }
402                                         }
403                                 }
404                                 else
405                                 {
406                                         scratchLen = sprintf (scratch, "\033*b%uV", InputRaster->rastersize[COLORTYPE_BLACK]);
407                                         err = Send ((const BYTE*) scratch, scratchLen);
408                                         if (err == NO_ERROR)
409                                         {
410                                                 err = Send (InputRaster->rasterdata[COLORTYPE_BLACK], InputRaster->rastersize[COLORTYPE_BLACK]);
411                                                 if (err == NO_ERROR)
412                                                 {
413                                                         scratchLen = sprintf (scratch, "\033*b%uW", 0);
414                                                         err = Send ((const BYTE*) scratch, scratchLen);
415                                                 }
416                                         }
417                                 }
418                         }
419                         else
420                         {
421                                 scratchLen = sprintf (scratch, "\033*b%uV", 0);
422                                 err = Send ((const BYTE*) scratch, scratchLen);
423                                 if (err == NO_ERROR)
424                                 {
425                                         scratchLen = sprintf (scratch, "\033*b%uW", InputRaster->rastersize[COLORTYPE_COLOR]);
426                                         err = Send ((const BYTE*) scratch, scratchLen);
427                                         if (err == NO_ERROR && InputRaster->rastersize[COLORTYPE_COLOR] != 0)
428                                         {
429                                                 err = Send (InputRaster->rasterdata[COLORTYPE_COLOR], InputRaster->rastersize[COLORTYPE_COLOR]);
430                                         }
431                                 }
432                         }
433                 }
434                 else
435                 {
436                         scratchLen = sprintf (scratch, "\033*b%uW", InputRaster->rastersize[COLORTYPE_COLOR]);
437                         err = Send ((const BYTE*) scratch, scratchLen);
438                         if (err == NO_ERROR)
439                         {
440                                 err = Send (InputRaster->rasterdata[COLORTYPE_COLOR], InputRaster->rastersize[COLORTYPE_COLOR]);
441                         }
442                 }
443     }
444     else
445     {
446         scratchLen = sprintf (scratch, "\033*b%uV", InputRaster->rastersize[COLORTYPE_COLOR]);
447                 err = Send ((const BYTE*) scratch, scratchLen);
448                 if (err == NO_ERROR)
449                 {
450                         err = Send (InputRaster->rasterdata[COLORTYPE_COLOR], InputRaster->rastersize[COLORTYPE_COLOR]);
451                 }
452     }
453     return err;
454 }
455
456
457 DRIVER_ERROR Printer::Send
458 (
459     const BYTE* pWriteBuff
460 )
461 {
462     ASSERT(pWriteBuff);
463     int len = strlen((const char*)pWriteBuff);
464     return Send(pWriteBuff,len);
465 } //Send
466
467
468 /*
469  *  Function name: Printer::Send
470  *
471  *  Owner: Darrell Walker
472  *
473  *  Purpose:  Encapsulate error handling generated by performing I/O
474  *
475  *  Called by:
476  *
477  *  Calls made: WritePort(), GetStatus(), BusyWait(), ParseError(),
478  *              DisplayPrinterStatus(), YieldToSystem()
479  *
480  *  Parameters on entry: pJob is a pointer to the current JOBSTRUCT,
481  *                      pWriteBuff is a pointer to the data the
482  *                      caller wishes to send to the pritner,
483  *                      wWriteCount is the number of bytes of
484  *                      pWriteBuff to send
485  *
486  *  Parameters on exit: Unchanged
487  *
488  *  Side effects: Sends data to the printer, may update print dialog,
489  *              may change pJob->InSlowPollMode,
490  *              pJob->ErrorTerminationState
491  *
492  *  Return Values: NO_ERROR or JOB_CANCELED or IO_ERROR
493  *
494  *  Comments: (TJL) This routine now has functionality to attempt iterating
495  *      through wWriteCount bytes of data (until we hit slow poll mode)
496  *      before sending PCL cleanup code.  This still leaves the possibility of
497  *      prematurely exiting with an incomplete raster, but gives I/O a fighting chance
498  *      of completing the raster while also protecting from a bogged down slow poll phase
499  *      which would prevent a timely exit from CANCEL.  A JobCanceled flag is used
500  *      because JOB_CANCELED cannot be maintained by write_error through the while
501  *      loop since it will be overwritten by next ToDevice.
502  *
503  */
504
505 DRIVER_ERROR Printer::Send
506 (
507     const BYTE* pWriteBuff,
508     DWORD dwWriteCount
509 )
510 {
511     ASSERT(pWriteBuff);
512
513     DRIVER_ERROR    write_error = NO_ERROR;
514     DWORD           residual = 0;
515     const BYTE *    pWritePos = NULL;
516     BOOL            error_displayed = FALSE;
517     BYTE            status_reg = 0;
518     DISPLAY_STATUS  eDisplayStatus = DISPLAY_PRINTING;
519     BOOL            JobCanceled = FALSE;  // see comments in function header
520
521     // these are just an abstraction layer - buffered vs. non-buffered
522     const BYTE *    pBuffer = pWriteBuff;
523     DWORD           dwSendSize = dwWriteCount;
524
525 ////////////////////////////////////////////////////////////////
526 #ifdef NULL_IO
527     // test imaging speed independent of printer I/O, will not
528     // send any data to the device
529     return NO_ERROR;
530 #endif
531 ////////////////////////////////////////////////////////////////
532
533     if (ErrorTerminationState)  // don't try any more IO if we previously
534     {
535         return JOB_CANCELED;    // terminated in an error state
536     }
537
538     if (EndJob == FALSE && dwWriteCount == 0)    // don't bother processing
539     {
540         return NO_ERROR;                         //  an empty Send call
541     }
542
543 #ifdef APDK_BUFFER_SEND
544     DWORD BytesToWrite = dwWriteCount;
545
546     do
547     {
548         // we should bypass the buffering for a large Send, but don't lose what may already be buffered
549         if ( (BytesToWrite >= iBuffSize) && (iCurrBuffSize == 0) )
550         {
551             pBuffer = pWriteBuff+(dwWriteCount-BytesToWrite);
552             dwSendSize = BytesToWrite;
553             BytesToWrite = 0;  // this is checked for at the end of the outer loop
554         }
555         else // we will buffer this data
556         {
557             // if it'll fit then just copy everything to the buffer
558             if (BytesToWrite <= DWORD(iBuffSize-iCurrBuffSize))
559             {
560                 memcpy((void*)(pSendBuffer+iCurrBuffSize),
561                     (void*)(pWriteBuff+(dwWriteCount-BytesToWrite)),BytesToWrite);
562                iCurrBuffSize += BytesToWrite;
563                BytesToWrite = 0;
564             }
565               else // copy what we can into the buffer, we'll get the rest later
566             {
567               memcpy((void*)(pSendBuffer+iCurrBuffSize),
568                 (void*)(pWriteBuff+(dwWriteCount-BytesToWrite)),
569                 iBuffSize-iCurrBuffSize);
570                 BytesToWrite -= (iBuffSize-iCurrBuffSize);
571                 iCurrBuffSize = iBuffSize;
572             }
573
574             // if the buffer is now full (ready-to-send) or if we're at
575             // the end of the job, then send what we have in the buffer.
576             // otherwise just break (the buffer isn't ready to send)
577             if ( (EndJob == FALSE) && (iCurrBuffSize != iBuffSize) )
578             {
579                 break;  // we're not ready to send yet
580             }
581             else // send this buffered data
582             {
583                 pBuffer = pSendBuffer;
584                 dwSendSize = iCurrBuffSize;
585             }
586                 }
587 #endif
588
589     // initialize our 'residual' to the full send size
590     residual = dwSendSize;
591
592     if (bCheckForCancelButton &&
593         (ulBytesSentSinceCancelCheck >= CANCEL_BUTTON_CHECK_THRESHOLD) &&\r
594         (pSS->IOMode.bDevID))
595     {
596         ulBytesSentSinceCancelCheck = 0;
597         char* tmpStr;
598         BYTE DevIDBuffer[DevIDBuffSize];
599         DRIVER_ERROR tmpErr = pSS->GetDeviceID(DevIDBuffer, DevIDBuffSize, TRUE);
600         if(tmpErr)
601             return tmpErr;
602         BOOL cancelcheck=FALSE;
603
604         if((tmpStr = strstr((char*)DevIDBuffer + 2,"CNCL")))
605         {
606             cancelcheck=TRUE;
607         }
608         else
609         {
610             int     iVersion = pSS->GetVIPVersion ();
611
612             if((tmpStr = strstr((char*)DevIDBuffer + 2,";S:")) &&
613                 iVersion < 6)    // DJ990 devID style
614             {
615                 // point to PrinterState
616 /*
617  *                              VIPVersion = DevID Version + 1 - DevID Version no is 2 bytes following ;S:
618  *                              Version 00 and 01 report 12 bytes for status info
619  *                              Version 02 and onwards, report two additional bytes before pen info
620  */
621
622                                 if (iVersion < 3)
623                                 {
624                                         tmpStr += 17;   // 3 for ";S:", 2 for version, 12 for features = 17
625                                 }
626                                 else if (iVersion < 5)
627                                 {
628                                         tmpStr += 19;   // 17 as above plus 1 for MaxPaperSize, 1 reserved = 19
629                                 }
630                 else
631                 {
632                     tmpStr += 23;   // Crystal added 4 more nibbles
633                 }
634
635                 BYTE b1=*tmpStr++;
636                 BYTE b2=*tmpStr++;
637                 if (((b1=='0') && (b2=='5')) && iVersion <= 5)     // 05 = cancel
638                 {
639                     cancelcheck=TRUE;
640                 }
641             }
642         }
643         if (cancelcheck)
644         {
645             // Since the printer is now just throwing data away, we can bail
646             // immediately w/o worrying about finishing the raster so the
647             // end-of-job FF will work.
648             ErrorTerminationState = TRUE;
649             pSS->DisplayPrinterStatus(DISPLAY_PRINTING_CANCELED);
650             return JOB_CANCELED;
651         }
652     }
653
654     // If we have nothing to send, we need to bail to avoid spurious dialogs
655     //  at the end of the ::send function.  I'd prefer a solution where we don't
656     //  bail from a while loop but in practice this shouldn't have any ill effects.
657     if (residual <= 0)
658     {
659         return NO_ERROR;
660     }
661
662     while (residual > 0)    // while still data to send in this request
663     {
664         DWORD prev_residual = residual;     // WritePort overwrites request
665                                             // count, need to save
666
667         pWritePos = (const BYTE *) &(pBuffer[dwSendSize-residual]);
668         write_error = pSS->ToDevice(pWritePos, &residual);
669
670         // The following error handling code is recommended, but is not supported
671         // on several current platforms for this reason:  when the printer buffer
672         // fills and declines more data, the O/S returns a BUSY error in one form
673         // or another.  The real solution is to allow the code below and have the
674         // derived pSS->ToDevice functions catch and ignore any BUSY error - only
675         // returning a real error to ::Send.  The current workaround here is that we
676         // literally ignore all errors returned from the I/O system and ultimately catch
677         // them after we've reached our slow poll limit via the slow poll logic below. -TL
678 //        if(write_error != NO_ERROR)
679 //        {
680 //            DBG1("IO_ERROR returned from ToDevice - ABORT!\n");
681 //            ErrorTerminationState = TRUE;
682 //            return write_error;
683 //        }
684
685         write_error = NO_ERROR;
686         eDisplayStatus = DISPLAY_PRINTING;
687         if (residual == 0) // no more data to send this time
688         {
689             if (m_bStatusByPJL)
690             {
691                 status_reg = (BYTE) DISPLAY_PRINTING;\r
692                 if (IOMode.bStatus)\r
693                     eDisplayStatus = ParseError (status_reg);
694                 if (eDisplayStatus != DISPLAY_PRINTING)
695                     write_error = IO_ERROR;
696             }
697
698             // did we want to transition out of slow poll?
699             if ( (InSlowPollMode != 0) &&
700                 (prev_residual > MIN_XFER_FOR_SLOW_POLL) )
701             {
702                 InSlowPollMode = 0;
703                 iTotal_SLOW_POLL_Count = 0;
704             }
705             if (write_error == NO_ERROR)
706                 break;  // out of while loop
707         }
708
709
710         // if we are here, WritePort() was not able to
711         // send the full request so start looking for errors
712
713         // decide whether we've waited long enough to check for an error
714         if (InSlowPollMode > iMax_SLOW_POLL_Count )
715         {
716             if (JobCanceled == TRUE)
717             // Well, I/O didn't finish in time to meet the CANCEL request and avoid
718             // the SlowPoll threshold.  We have to bail for prompt cancel response.
719             {
720                 DBG1("Send(SlowPoll): Premature return w/ JOB_CANCELED\n");
721                 ErrorTerminationState = TRUE;
722                 return JOB_CANCELED;
723             }
724
725             DBG1("Printer slow poll times exceeded\n");
726             // reset counter so we will not pop it next time
727             InSlowPollMode = 1;
728             write_error = IO_ERROR;
729         }
730         else
731         {
732             write_error = NO_ERROR;
733         }
734
735         // are we in slow poll mode?  If so, track our count
736         if ( (prev_residual - residual) <= MIN_XFER_FOR_SLOW_POLL)
737         {
738             InSlowPollMode++;
739
740 #if defined(DEBUG) && (DBG_MASK & DBG_LVL1)
741             if (InSlowPollMode == 1)
742             {
743                 printf("entering slow poll mode\n");
744             }
745             else
746             {
747                 printf("still in slow poll mode, count = %d\n",
748                                     InSlowPollMode);
749             }
750 #endif
751             // give the printer some time to process
752             if (pSS->BusyWait((DWORD)200) == JOB_CANCELED)
753             {
754                 DBG1("Send: JOB_CANCELED\n");
755                 JobCanceled = TRUE;
756                 pSS->DisplayPrinterStatus(DISPLAY_PRINTING_CANCELED);
757             }
758         }
759         else
760         {
761             // still busy, but taking enough data that
762             // we are not in slow poll mode
763             DBG1("Partial Send but not slow poll mode\n");
764             InSlowPollMode = 0;
765             iTotal_SLOW_POLL_Count = 0;
766         }
767
768
769         if (write_error != NO_ERROR || (m_bStatusByPJL && eDisplayStatus != DISPLAY_PRINTING))
770         // slow poll times exceeded
771         // the printer isn't taking data so let's see what's wrong...
772         {
773             DBG1("Parsing possible error state...\n");
774             error_displayed = TRUE;
775
776             if (m_bStatusByPJL)
777             {
778                 status_reg = (BYTE) eDisplayStatus;
779             }
780             else
781             {
782                 // go get the status of the printer
783                 if (IOMode.bStatus)
784                 {
785                     pSS->GetStatusInfo(&status_reg);
786                 }
787
788                 // determine the error
789                 eDisplayStatus = ParseError(status_reg);
790             }
791
792             switch (eDisplayStatus)
793             {
794                 case DISPLAY_PRINTING_CANCELED:
795
796                         // user canceled in an error state,
797                         // so we don't want to attempt any
798                         // further communication with the printer
799
800                         ErrorTerminationState = TRUE;
801                         pSS->DisplayPrinterStatus(eDisplayStatus);
802                         return JOB_CANCELED;
803
804                 case DISPLAY_ERROR_TRAP:
805                 case DISPLAY_COMM_PROBLEM:
806                         // these are unrecoverable cases
807                         // don't let any more of this job
808                         // be sent to the printer
809
810                         ErrorTerminationState = TRUE;
811                         pSS->DisplayPrinterStatus(eDisplayStatus);
812
813                         // wait for user to cancel the job,
814                         // otherwise they might miss the
815                         // error message
816                         while (pSS->BusyWait(500) != JOB_CANCELED)
817                         {
818                                 // nothing....
819                             ;
820                         }
821                         return IO_ERROR;
822
823                 case DISPLAY_TOP_COVER_OPEN:
824
825                     pSS->DisplayPrinterStatus(DISPLAY_TOP_COVER_OPEN);
826
827                     // wait for top cover to close
828                     while ( eDisplayStatus == DISPLAY_TOP_COVER_OPEN)
829                     {
830                         if (pSS->BusyWait((DWORD)500) == JOB_CANCELED)
831                         // although we'll leave an incomplete job in the printer,
832                         // we really need to bail for proper CANCEL response.
833                         {
834                             ErrorTerminationState = TRUE;
835                             return JOB_CANCELED;
836                         }
837
838                         if (m_bStatusByPJL)
839                         {
840                             status_reg = (BYTE) eDisplayStatus;
841                         }
842                         else
843                         {
844                             if (IOMode.bStatus)
845                             {
846                                 pSS->GetStatusInfo(&status_reg);
847                             }
848                         }
849
850                         eDisplayStatus = ParseError(status_reg);
851                     }
852
853                     pSS->DisplayPrinterStatus(DISPLAY_PRINTING);
854
855                     // Wait for printer to come back online
856                     if (pSS->BusyWait((DWORD)1000) == JOB_CANCELED)
857                     // Since the top_cover error HAS been handled, we have
858                     // the opportunity to finish the raster before we hit
859                     // the next slowpoll threshold.
860                     {
861                         DBG1("Send: JOB_CANCELED\n");
862                         JobCanceled = TRUE;
863                         pSS->DisplayPrinterStatus(DISPLAY_PRINTING_CANCELED);
864                     }
865
866                     break;
867
868                 case DISPLAY_OUT_OF_PAPER:
869                                 case DISPLAY_PHOTOTRAY_MISMATCH:
870                                 {
871                                         DISPLAY_STATUS  tmpStatus = eDisplayStatus;
872                     pSS->DisplayPrinterStatus(eDisplayStatus);
873
874                     // wait for the user to add paper and
875                     // press resume
876                     while ( eDisplayStatus == tmpStatus)
877                     {
878                         if (pSS->BusyWait((DWORD)500) == JOB_CANCELED)
879                         // although we'll leave an incomplete job in the printer,
880                         // we really need to bail for proper CANCEL response.
881                         {
882                             ErrorTerminationState = TRUE;
883                             return JOB_CANCELED;
884                         }
885
886                         if (m_bStatusByPJL)
887                         {
888                             status_reg = (BYTE) eDisplayStatus;
889                         }
890                         else
891                         {
892                             if (IOMode.bStatus)
893                             {
894                                 pSS->GetStatusInfo(&status_reg);
895                             }
896                         }
897
898                         eDisplayStatus = ParseError(status_reg);
899                     }
900
901                     pSS->DisplayPrinterStatus(DISPLAY_PRINTING);
902
903                     break;
904                                 }
905
906                 case DISPLAY_BUSY:
907
908                     if (pSS->BusyWait((DWORD)5000) == JOB_CANCELED)
909                     {
910                         ErrorTerminationState = TRUE;
911                         return JOB_CANCELED;
912                     }
913
914                     pSS->DisplayPrinterStatus(DISPLAY_BUSY);
915
916                     break;
917
918                 // other cases need no special handling, display
919                 // the error and try to continue
920                 default:
921                     pSS->DisplayPrinterStatus(eDisplayStatus);
922                     break;
923             }// switch
924         } // if
925
926         // give printer time to digest the data and check for 'cancel' before
927         // the next iteration of the loop
928         if (pSS->BusyWait((DWORD)100) == JOB_CANCELED)
929         {
930             DBG1("Send: JOB_CANCELED\n");
931             JobCanceled = TRUE;
932             pSS->DisplayPrinterStatus(DISPLAY_PRINTING_CANCELED);
933         }
934
935     }   // while (residual > 0)
936
937     // The above BusyWait's will not be checked if residual gets sent the first time, every time
938     // because we 'break' at that point for efficiency.  However, we want to make sure we check
939     // at least once for a CANCEL event for timely job-cancel response.
940     if (pSS->BusyWait((DWORD)0) == JOB_CANCELED)
941     {
942         JobCanceled = TRUE;
943         pSS->DisplayPrinterStatus(DISPLAY_PRINTING_CANCELED);
944     }
945
946 #ifdef APDK_BUFFER_SEND
947     // Our buffer is now empty: reset the size so concurrent writes start at the beginning
948         iCurrBuffSize = 0;
949
950     } while (BytesToWrite > 0);
951 #endif
952
953     // restore my JOB_CANCELED error
954     if (JobCanceled == TRUE)
955     {
956         DBG1("Send: Clean return w/ JOB_CANCELED\n");
957         // ensure that display still says we're cancelling
958         pSS->DisplayPrinterStatus(DISPLAY_PRINTING_CANCELED);
959         return JOB_CANCELED;
960     }
961     else
962     {
963         // ensure any error message has been cleared
964         pSS->DisplayPrinterStatus(DISPLAY_PRINTING);
965         if (bCheckForCancelButton)
966         {
967             ulBytesSentSinceCancelCheck += dwWriteCount;
968         }
969         return NO_ERROR;
970     }
971 } //Send
972
973
974 BOOL Printer::TopCoverOpen
975 (
976     BYTE /*status_reg*/
977 )
978 {
979     char * pStr;
980     BYTE bDevIDBuff[DevIDBuffSize];
981
982     if(IOMode.bDevID == FALSE)
983     {
984         return FALSE;
985     }
986
987     DRIVER_ERROR err = pSS->GetDeviceID(bDevIDBuff, DevIDBuffSize, TRUE);
988     if (err != NO_ERROR)
989     {
990         return FALSE;
991     }
992
993     if( (pStr=strstr((char*)bDevIDBuff+2,"VSTATUS:")) ) //  find the VSTATUS area
994     {
995         pStr+=8;
996         // now parse VSTATUS parameters
997         // looking for UP for open, DN for closed
998         if (strstr((char*)pStr,"UP"))
999         {
1000             return TRUE;
1001         }
1002         if (strstr((char*)pStr,"DN"))
1003         {
1004             return FALSE;
1005         }
1006
1007         DBG1("didn't find UP or DN!!\n");
1008         return FALSE;
1009     }
1010     else
1011     if (( pStr = strstr ((char*) bDevIDBuff+2, ";S")))
1012     {
1013         if ( (*(pStr+5) == '9') )
1014         {
1015             return TRUE;
1016         }
1017         else
1018         {
1019             return FALSE;
1020         }
1021     }
1022     else
1023     {
1024         return FALSE;  // if we can't find VSTATUS or binary status field, assume top is not open
1025     }
1026 } //TopCoverOpen
1027
1028
1029 DRIVER_ERROR Printer::CleanPen()
1030 {
1031     DBG1("Printer::ClearPen() called\n");
1032
1033     DWORD length=sizeof(PEN_CLEAN_PML);
1034     return pSS->ToDevice(PEN_CLEAN_PML,&length);
1035 } //CleanPen
1036
1037
1038 PrintMode* Printer::GetMode
1039 (
1040     unsigned int index
1041 )
1042 {
1043     if (index >= ModeCount)
1044     {
1045         return NULL;
1046     }
1047
1048     return pMode[index];
1049 } //GetMode
1050
1051
1052 PrintMode::PrintMode
1053 (
1054     uint32_t *map1,
1055     uint32_t *map2
1056 )
1057 {
1058     pmQuality = QUALITY_NORMAL;
1059     pmMediaType = MEDIA_PLAIN;
1060     pmColor = COLOR;
1061     int iCount;
1062
1063     cmap.ulMap1 = map1;
1064     cmap.ulMap2 = map2;
1065     cmap.ulMap3 = NULL;
1066
1067     BaseResX = BaseResY = TextRes = 300;
1068     MixedRes= FALSE;
1069
1070     // default setting
1071     for (iCount = 0; iCount < MAXCOLORPLANES; iCount++)
1072     {
1073         ResolutionX[iCount] = BaseResX;
1074         ResolutionY[iCount] = BaseResY;
1075         ColorDepth[iCount] = 1;
1076     }
1077
1078     medium = mediaPlain;
1079     theQuality = qualityNormal;
1080     dyeCount=4;
1081
1082     Config.bResSynth = TRUE;
1083
1084 #if defined(APDK_VIP_COLORFILTERING)
1085     Config.bErnie = FALSE;
1086 #endif
1087
1088     Config.bPixelReplicate = TRUE;
1089     Config.bColorImage = TRUE;
1090     Config.bCompress = TRUE;
1091     Config.eHT = FED;
1092     BlackFEDTable = GetHTBinary();
1093     ColorFEDTable = GetHTBinary();
1094
1095
1096     // set for most common cases
1097     bFontCapable = TRUE;
1098     CompatiblePens[0] = BOTH_PENS;
1099     for(iCount = 1; iCount < MAX_COMPATIBLE_PENS; iCount++)
1100     {
1101         CompatiblePens[iCount] = DUMMY_PEN;
1102     }
1103
1104 #ifdef APDK_AUTODUPLEX
1105     bDuplexCapable = FALSE;
1106     DuplexMode = DUPLEXMODE_NONE;
1107 #endif
1108
1109 } //PrintMode
1110
1111
1112 GrayMode::GrayMode
1113 (
1114     uint32_t *map
1115 ) :
1116     PrintMode(map)
1117 // grayscale uses econo, 300, 1 bit
1118 {
1119     ColorDepth[K] = 1;
1120     dyeCount = 1;
1121     CompatiblePens[1] = BLACK_PEN;  // accept either black or both
1122     pmColor = GREY_K;
1123 } //GrayMode
1124
1125
1126 CMYGrayMode::CMYGrayMode
1127 (
1128     uint32_t *map
1129 ) :
1130     GrayMode(map)
1131 {
1132     CompatiblePens[1] = COLOR_PEN;  // accept either color or both
1133     dyeCount = 3;
1134     pmColor = GREY_CMY;
1135 } //CMYGrayMode
1136
1137
1138 KCMYGrayMode::KCMYGrayMode
1139 (
1140     uint32_t *map
1141 ) :
1142     GrayMode(map)
1143 {
1144     dyeCount = 4;
1145     pmColor = GREY_CMY;
1146 } //KCMYGrayMode
1147
1148
1149 DRIVER_ERROR Printer::SetPenInfo
1150 (
1151     char*& pStr,
1152     BOOL QueryPrinter
1153 )
1154 {
1155     DRIVER_ERROR err;
1156
1157     if (QueryPrinter)
1158     {
1159         // read the DevID into the stored strDevID
1160         err = pSS->GetDeviceID(pSS->strDevID, DevIDBuffSize, TRUE);
1161         ERRCHECK;
1162
1163         // update the static values of the pens
1164         err = pSS->DR->ParseDevIDString((const char*)(pSS->strDevID),pSS->strModel,&(pSS->VIPVersion),pSS->strPens);
1165         ERRCHECK;
1166
1167         if ((pStr = strstr((char*)pSS->strDevID,"VSTATUS:")))   //  find the VSTATUS area
1168         {
1169             pStr += 8;
1170         }
1171         else if ((pStr = strstr((char*)pSS->strDevID, ";S:00")))  // binary encoded device ID status (version 0)
1172         {
1173             pStr += 19;     // get to the number of pens field - 12 byte feature field
1174         }
1175         else if ((pStr = strstr ((char *) pSS->strDevID, ";S:01")))
1176         {
1177             pStr += 19;     // same as version 00
1178         }
1179         else if ((pStr = strstr((char*)pSS->strDevID, ";S:02")))  // binary encoded device ID status (version 2)
1180         {
1181 //            pStr += 21;     // get to the number of pens field - 14 byte feature field
1182             pStr += 19;     // same as version 00 - see registry.cpp
1183         }
1184         else if ((pStr = strstr((char*)pSS->strDevID, ";S:03")))  // binary encoded device ID status (version 3)
1185         {
1186             pStr += 21;     // get to the number of pens field - 14 byte feature field
1187         }
1188         else if ((pStr = strstr((char*)pSS->strDevID, ";S:04")))  // binary encoded device ID status (version 3)
1189         {
1190             pStr += 25;     // get to the number of pens field - 18 byte feature field
1191         }
1192         else if ((pSS->GetVIPVersion ()) > 5)
1193         {
1194             return NO_ERROR;
1195         }
1196         else
1197         {
1198             TRACE("Printer::SetPenInfo - Unsupported DeviceID %s.\n", pSS->strDevID);
1199 /*            ASSERT (0);  // you must have a printer with a new version that is not supported yet! */
1200             return BAD_DEVICE_ID;  // - code should never reach this point
1201         }
1202     }
1203     else
1204     {
1205         pStr = pSS->strPens;
1206     }
1207     return NO_ERROR;
1208 } //SetPenInfo
1209
1210
1211 BOOL PrintMode::Compatible
1212 (
1213     PEN_TYPE pens
1214 )
1215 {
1216     BOOL res = FALSE;
1217     for (int i=0; i < MAX_COMPATIBLE_PENS; i++)
1218     {
1219         if (CompatiblePens[i] == pens)
1220         {
1221             res = TRUE;
1222         }
1223     }
1224     return res;
1225 } //Compatible
1226
1227
1228
1229 DRIVER_ERROR Printer::SetPens
1230 (
1231     PEN_TYPE eNewPen
1232 )
1233 {
1234     ASSERT(eNewPen <= MAX_PEN_TYPE);
1235     // We are (probably)in unidi.  We have to trust they know what pens are
1236     // in the printer.  We'll let them set any pen set (even if this printer
1237     // doesn't support it.  We'll find out during SelectPrintMode
1238     if (eNewPen <= MAX_PEN_TYPE)
1239     {
1240         ePen = eNewPen;
1241         return NO_ERROR;
1242     }
1243     else
1244     {
1245         return UNSUPPORTED_PEN;
1246     }
1247 } //SetPens
1248
1249 void PrintMode::GetValues
1250 (
1251     QUALITY_MODE& eQuality,
1252     MEDIATYPE& eMedia,
1253     COLORMODE& eColor,
1254     BOOL& bDeviceText
1255 )
1256 {
1257     if (&eQuality != NULL)
1258     {
1259         eQuality = pmQuality;
1260     }
1261
1262     if (&eMedia != NULL)
1263     {
1264         eMedia = pmMediaType;
1265     }
1266
1267     if (&eColor != NULL)
1268     {
1269         eColor = pmColor;
1270     }
1271
1272     if (&bDeviceText != NULL)
1273     {
1274         bDeviceText = bFontCapable;
1275     }
1276 } //GetValues
1277
1278
1279 void Printer::SetPMIndices()
1280 {
1281     for (unsigned int i=0; i < ModeCount; i++)
1282     {
1283         pMode[i]->myIndex = i;
1284     }
1285 } //SetPMIndices
1286
1287 APDK_END_NAMESPACE
1288
1289